/* =============================================================
 * SAM4S Design System — Components (Layer 2 + 3)
 * Version: 1.0.0
 * Requires: sam4s-tokens.css (반드시 이 파일보다 먼저 <link>)
 *
 * 구성
 *   Part A  Reset + Base Typography
 *   Part B  Layout Primitives (Stack, Cluster, Grid, Split)
 *   Part C  App Shell (TopNav + Sidebar + Main)
 *   Part D  Atomic Components
 *            - Button   - Input / Field   - Card
 *            - Tabs     - Segmented      - Table
 *            - Status   - Tag / Badge    - Pagination
 *            - Modal    - Toast          - Switch
 *   Part E  Dashboard Specific
 *            - Donut Stat · Ranked List · Chart Card
 *   Part F  Page Patterns
 *            - Page Header · Empty State · Kv List
 *   Part G  Utilities
 *
 * BEM 네이밍 규칙
 *   .block            : 컴포넌트 루트
 *   .block__element   : 구성 요소
 *   .block--modifier  : 변형
 *   .is-active        : 상태
 *   .u-*              : 유틸리티
 * ============================================================= */


/* =============================================================
 *  Part A — Reset + Base Typography
 * ============================================================= */

*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  color-scheme: light dark;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--lh-base);
  color: var(--text);
  background: var(--surface-1);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: var(--fw-semibold);
  line-height: 1.25;
}
h1 { font-size: var(--text-2xl); }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); }

p     { line-height: var(--lh-base); }
small { font-size: var(--text-sm); color: var(--text-muted); }

a {
  color: var(--brand-500);
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-out);
}
a:hover  { text-decoration: underline; }
a:active { color: var(--brand-600); }

:focus-visible {
  outline: 2px solid var(--focus-color);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

img, svg, video, canvas { max-width: 100%; display: block; }

button,
input,
select,
textarea { font: inherit; color: inherit; }

button { cursor: pointer; }


/* =============================================================
 *  Part B — Layout Primitives
 * ============================================================= */

/* Stack : 수직 리듬 */
.stack > * + *        { margin-top: var(--stack-gap, var(--space-4)); }
.stack-2 > * + *      { margin-top: var(--space-2); }
.stack-3 > * + *      { margin-top: var(--space-3); }
.stack-6 > * + *      { margin-top: var(--space-6); }
.stack-8 > * + *      { margin-top: var(--space-8); }

/* Cluster : 가로 그룹 (wrap 가능) */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cluster-gap, var(--space-3));
  align-items: center;
}
.cluster--end    { justify-content: flex-end; }
.cluster--center { justify-content: center; }
.cluster--between{ justify-content: space-between; }

/* Grid : 반응형 카드 그리드 */
.grid {
  display: grid;
  gap: var(--grid-gap, var(--space-4));
  grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 240px), 1fr));
}
.grid-2 {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-3 {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 900px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
}

/* Split-2 : 2-컬럼 비율 레이아웃 (License / Ranking 용) */
.split-2 {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--space-4);
}
@media (max-width: 900px) {
  .split-2 { grid-template-columns: 1fr; }
}

/* Container : 가로 최대폭 */
.container {
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}
.container--narrow { max-width: 720px; }
.container--wide   { max-width: 1440px; }


/* =============================================================
 *  Part C — App Shell (TopNav + Sidebar + Main)
 * ============================================================= */

.app-shell {
  display: grid;
  grid-template-rows: var(--size-topnav) 1fr;
  min-height: 100vh;
}

.app-body {
  display: grid;
  grid-template-columns: var(--size-sidebar) 1fr;
  height: calc(100vh - var(--size-topnav));
  overflow: hidden;
}

.app-nav {
  background: var(--nav-bg);
  color: var(--nav-text);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.app-main {
  background: var(--surface-1);
  padding: var(--space-6);
  overflow-y: auto;
}

@media (max-width: 900px) {
  .app-body {
    grid-template-columns: 1fr;
  }
  .app-nav {
    display: none;
  }
  .app-shell[data-nav-open="true"] .app-nav {
    display: flex;
    position: fixed;
    inset: var(--size-topnav) 0 0 0;
    z-index: var(--z-sidebar);
    width: 280px;
    box-shadow: var(--elevation-4);
  }
  .app-main {
    padding: var(--space-4);
  }
}

/* --- TopNav --- */

.topnav {
  display: grid;
  /* 첫 컬럼을 사이드바 폭과 동일하게 고정 → 그 안에서 로고를 중앙 정렬 */
  grid-template-columns: var(--size-sidebar) 1fr auto;
  align-items: center;
  gap: var(--space-4);
  height: var(--size-topnav);
  padding: 0 var(--space-6) 0 0;      /* 좌측 패딩 제거: 브랜드 영역이 자체 중앙 정렬 */
  background: var(--brand-500);
  color: #fff;
  position: sticky;
  top: 0;
  z-index: var(--z-topnav);
}

.topnav__brand {
  display: flex;
  align-items: center;       /* 세로 가운데 */
  justify-content: center;   /* 가로 가운데 — 240px 사이드바 폭 안에서 */
  height: 100%;
  color: #fff;
  font-weight: var(--fw-bold);
  font-size: var(--text-xl);
  letter-spacing: 0.5px;
}
.topnav__brand img {
  display: block;
  height: 40px;              /* sam4sdm.com 참조 — 헤더(64px) 의 62.5% 비율 */
  width: auto;
}

.topnav__menu {
  display: flex;
  gap: var(--space-8);
  align-items: center;
}

.topnav__menu a {
  color: #fff;
  font-size: var(--text-base);
  padding: 0 var(--space-2);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  opacity: 0.95;
  transition: opacity var(--motion-fast) var(--ease-out);
}
.topnav__menu a:hover {
  opacity: 1;
  text-decoration: underline;
}

.topnav__user {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.user-chip,
.lang-chip {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3);
  height: 32px;
  font-size: var(--text-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  transition: background var(--motion-fast) var(--ease-out);
}
.user-chip:hover,
.lang-chip:hover {
  background: rgba(255, 255, 255, 0.16);
}
/* 기본 user-fill.svg 는 어두운 회색(#262626)이라 파랑 topnav 에서 잘 안보임.
   default 아이콘일 때만 흰색으로 invert. 사용자가 업로드한 photo(url) 는 영향 없음. */
.user-chip img[src$="user-fill.svg"] {
  filter: brightness(0) invert(1);
}

/* --- Sidebar Navigation --- */

.nav-header {
  padding: var(--space-5) var(--space-5) var(--space-4);
  color: var(--nav-text-strong);
  font-size: var(--text-lg);
  font-weight: var(--fw-medium);
  border-bottom: 1px solid var(--nav-divider);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-search {
  display: flex;
  padding: var(--space-3) var(--space-4);
  gap: var(--space-2);
}

.nav-search__input {
  flex: 1;
  background: var(--nav-bg-alt);
  color: var(--nav-text);
  border: 1px solid var(--nav-divider);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3);
  height: 36px;
  font-size: var(--text-sm);
}
.nav-search__input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}
.nav-search__input:focus {
  outline: none;
  border-color: var(--brand-400);
}

.tree {
  list-style: none;
  padding: var(--space-2) 0;
  margin: 0;
  flex: 1;
}
.tree ul {
  list-style: none;
  padding-left: var(--space-5);
  margin: 0;
}

.tree-node__label {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: transparent;
  border: none;
  color: var(--nav-text);
  font-size: var(--text-md);       /* 15px */
  font-weight: var(--fw-medium);
  text-align: left;
  cursor: pointer;
  border-left: 3px solid transparent;
  transition: background var(--motion-fast) var(--ease-out),
              color var(--motion-fast) var(--ease-out);
}
.tree-node__label:hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--nav-text-strong);
}
.tree-node--active > .tree-node__label {
  background: var(--nav-active-bg);
  color: var(--nav-accent);
  border-left-color: var(--nav-accent);
}
/* 활성 상태의 텍스트형 아이콘(emoji/font-icon) 만 별도 노란색 적용.
   <img> 아이콘은 raster 라 color 속성 영향을 받지 않으므로 무해하다. */
.tree-node--active > .tree-node__label .tree-node__icon {
  color: var(--nav-icon-active);
}
.tree-node__chevron {
  width: 12px;
  display: inline-block;
  transition: transform var(--motion-fast) var(--ease-out);
  color: var(--text-muted);
}
.tree-node--open > .tree-node__label .tree-node__chevron {
  transform: rotate(90deg);
}
.tree-node__icon {
  width: var(--size-icon-sm);
  flex-shrink: 0;
}

.nav-footer {
  padding: var(--space-3) var(--space-5);
  font-size: var(--text-xs);
  color: rgba(255, 255, 255, 0.35);
  border-top: 1px solid var(--nav-divider);
}


/* =============================================================
 *  Part D — Atomic Components
 * ============================================================= */

/* --- Button --- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--size-control-md);
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-weight: var(--fw-medium);
  font-size: var(--text-sm);
  line-height: 1;
  white-space: nowrap;
  user-select: none;
  cursor: pointer;
  transition:
    background var(--motion-base) var(--ease-out),
    border-color var(--motion-base) var(--ease-out),
    color var(--motion-base) var(--ease-out),
    box-shadow var(--motion-base) var(--ease-out);
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--brand-500);
  color: var(--color-on-primary);
}
.btn-primary:hover  { background: var(--brand-600); }
.btn-primary:active { background: var(--brand-700); }

.btn-secondary {
  background: var(--surface-0);
  border-color: var(--border);
  color: var(--text);
}
.btn-secondary:hover { background: var(--surface-2); }
.btn-secondary:active{ background: var(--surface-3); }

.btn-danger {
  background: var(--color-danger);
  color: #fff;
}
.btn-danger:hover  { filter: brightness(0.92); }
.btn-danger:active { filter: brightness(0.85); }

.btn-success {
  background: var(--color-success);
  color: #fff;
}
.btn-success:hover { filter: brightness(0.92); }

.btn-ghost {
  background: transparent;
  color: var(--brand-500);
  padding-inline: var(--space-2);
}
.btn-ghost:hover { background: var(--brand-050); }

.btn-lg { min-height: var(--size-control-lg); padding-inline: var(--space-5); font-size: var(--text-base); }
.btn-sm { min-height: var(--size-control-sm); padding-inline: var(--space-3); font-size: var(--text-xs); }

.btn-icon {
  width: var(--size-control-md);
  min-height: var(--size-control-md);
  padding: 0;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
}
.btn-icon:hover { background: var(--surface-2); color: var(--text); }
.btn-icon.btn-sm { width: var(--size-control-sm); min-height: var(--size-control-sm); }

.btn-block { width: 100%; }

/* Button group (pill-connected) */
.btn-group {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.btn-group .btn {
  border-radius: 0;
  border: none;
}
.btn-group .btn + .btn {
  border-left: 1px solid var(--border);
}


/* --- Input / Field --- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.field--row {
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
}
.field--row .field__label { width: 140px; flex-shrink: 0; }

.field__label {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}

.input,
.select,
.textarea {
  min-height: var(--size-control-md);
  padding: 0 var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-0);
  color: var(--text);
  font-size: var(--text-sm);
  transition:
    border-color var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out);
}
.input::placeholder,
.textarea::placeholder { color: var(--text-placeholder); }

.input:hover,
.select:hover,
.textarea:hover { border-color: var(--border-strong); }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: var(--focus-ring);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--surface-2);
  color: var(--text-disabled);
  cursor: not-allowed;
}

.input--error,
.input.is-error { border-color: var(--color-danger); }

.textarea {
  padding: var(--space-2) var(--space-3);
  min-height: 80px;
  line-height: var(--lh-base);
  resize: vertical;
}

.field__hint  { font-size: var(--text-xs); color: var(--text-muted); }
.field__error { font-size: var(--text-xs); color: var(--color-danger); }


/* --- Checkbox · Radio · Switch ---
 * v2 — native 라디오/체크박스가 브라우저/OS 에 따라 다르게 렌더링되는 문제
 *      (특히 unchecked 상태가 검은색 원으로 보이는 레거시 환경) 를 해결하기 위해
 *      appearance:none 으로 초기화 후 완전 커스텀 외관을 그린다.
 *      모든 상태(default / hover / focus / checked / disabled) 는 DS 토큰만 참조. */

.check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--text);
  user-select: none;
}
.check input[type="checkbox"],
.check input[type="radio"] {
  /* 브라우저 기본 스타일 완전 제거 */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;

  /* 공통 박스 */
  position: relative;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 0;
  box-sizing: border-box;
  background: var(--surface-0);
  border: 1.5px solid var(--border-strong);
  cursor: pointer;
  transition:
    background var(--motion-fast) var(--ease-out),
    border-color var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out);

  /* 라디오는 원형, 체크박스는 둥근 사각형 */
}
.check input[type="radio"] {
  border-radius: 50%;
}
.check input[type="checkbox"] {
  border-radius: var(--radius-xs);
}

/* hover — 마우스 올렸을 때 테두리만 강조 */
.check input[type="checkbox"]:not(:disabled):hover,
.check input[type="radio"]:not(:disabled):hover {
  border-color: var(--brand-500);
}

/* focus-visible — 키보드 접근성용 포커스 링 */
.check input[type="checkbox"]:focus-visible,
.check input[type="radio"]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-color: var(--brand-500);
}

/* checked — 라디오 */
.check input[type="radio"]:checked {
  background: var(--brand-500);
  border-color: var(--brand-500);
}
.check input[type="radio"]:checked::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--color-on-primary);
  transform: translate(-50%, -50%);
}

/* checked — 체크박스 */
.check input[type="checkbox"]:checked {
  background: var(--brand-500);
  border-color: var(--brand-500);
}
.check input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  top: 1px; left: 5px;
  width: 5px; height: 10px;
  border: solid var(--color-on-primary);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* indeterminate — 체크박스 일부 선택 상태 (예: 전체선택 헤더) */
.check input[type="checkbox"]:indeterminate {
  background: var(--brand-500);
  border-color: var(--brand-500);
}
.check input[type="checkbox"]:indeterminate::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 10px; height: 2px;
  background: var(--color-on-primary);
  transform: translate(-50%, -50%);
  border: none;
}

/* disabled — 상호작용 불가 시 톤 다운 */
.check input[type="checkbox"]:disabled,
.check input[type="radio"]:disabled {
  background: var(--surface-2);
  border-color: var(--border);
  cursor: not-allowed;
}
.check input[type="checkbox"]:disabled:checked,
.check input[type="radio"]:disabled:checked {
  background: var(--text-disabled);
  border-color: var(--text-disabled);
}
.check:has(input:disabled) {
  color: var(--text-disabled);
  cursor: not-allowed;
}

.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  cursor: pointer;
}
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.switch__slider {
  position: absolute;
  inset: 0;
  background: var(--border-strong);
  border-radius: var(--radius-pill);
  transition: background var(--motion-base) var(--ease-out);
}
.switch__slider::before {
  content: "";
  position: absolute;
  width: 18px; height: 18px;
  left: 2px; top: 2px;
  background: #fff;
  border-radius: 50%;
  box-shadow: var(--elevation-1);
  transition: transform var(--motion-base) var(--ease-out);
}
.switch input:checked + .switch__slider             { background: var(--brand-500); }
.switch input:checked + .switch__slider::before      { transform: translateX(18px); }
.switch input:focus-visible + .switch__slider        { box-shadow: var(--focus-ring); }


/* =========================================================================
 * Time / Date native input — DS 토큰으로 강제 라이트 톤.
 *
 * 브라우저(Chrome/Edge) 는 OS 다크 모드 또는 colorScheme 힌트에 따라
 * <input type="time"> 의 배경/글자색을 검게 그릴 수 있다. SAM4S 포털은
 * light-only 이므로 모든 시각/날짜 입력기를 흰 배경 + 진회색 글자로 고정한다.
 *
 * 특히 "::-webkit-calendar-picker-indicator" 는 피커 트리거 아이콘으로,
 * 어두운 배경 이슈가 여기서도 발생하므로 필터로 색상 보정.
 *
 * v3 — 시각 표기 locale 고정.
 *   OS 가 한국어(ko-KR) 이면 <input type="time"> 이 "오전 12:00" 같은
 *   12시간제 한국어로 렌더된다. SAM4S 포털은 영문 24시간제 표기가 표준이므로
 *   lang 속성 미지정 입력기에도 영어 locale 힌트를 강제한다.
 *   (개별 input 에 lang="en-US" 를 추가하면 우선 적용됨)
 * ========================================================================= */
input[type="time"],
input[type="date"],
input[type="datetime-local"] {
    /* color-scheme: light — 브라우저에게 라이트 톤 UA 위젯 쓰라고 명시 */
    color-scheme: light;
    background: var(--surface-0);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    font: inherit;
    font-size: var(--text-base);
    line-height: var(--lh-base);
}
/* 별도 lang 속성이 명시되지 않은 time/date input 에 영어 locale 힌트 강제 */
input[type="time"]:not([lang]),
input[type="date"]:not([lang]),
input[type="datetime-local"]:not([lang]) {
    direction: ltr;
    unicode-bidi: isolate;
}
input[type="time"]:focus,
input[type="date"]:focus,
input[type="datetime-local"]:focus {
    outline: none;
    border-color: var(--brand-500);
    box-shadow: var(--focus-ring);
}
input[type="time"]:disabled,
input[type="date"]:disabled,
input[type="datetime-local"]:disabled {
    background: var(--surface-2);
    color: var(--text-disabled);
    cursor: not-allowed;
}
/* 피커 트리거 아이콘이 검게 나오는 경우를 대비해 필터로 어둡게 정규화 */
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
    filter: invert(0.35);
    cursor: pointer;
    opacity: 0.8;
}
input[type="time"]::-webkit-datetime-edit,
input[type="date"]::-webkit-datetime-edit {
    color: var(--text);
}


/* --- Card --- */

.card {
  background: var(--surface-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  box-shadow: var(--elevation-1);
}
.card--compact  { padding: var(--space-4); }
.card--elevated { box-shadow: var(--elevation-2); }
.card--flat     { box-shadow: none; }
.card--hover {
  transition:
    box-shadow var(--motion-base) var(--ease-out),
    transform var(--motion-base) var(--ease-out);
  cursor: pointer;
}
.card--hover:hover {
  box-shadow: var(--elevation-2);
  transform: translateY(-1px);
}

.card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.card__title {
  font-size: var(--text-lg);
  font-weight: var(--fw-semibold);
  color: var(--text);
  margin: 0;
}
.card__subtitle {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin-top: var(--space-1);
}
.card__actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
.card__footer {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}
.card__body {
  display: block;
}


/* =========================================================================
 * AVATAR — 프로필·썸네일 이미지
 * ========================================================================= */
.avatar {
  display: inline-block;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
}
.avatar--xs { width: 24px;  height: 24px;  }   /* topnav 같은 극소 영역 */
.avatar--sm { width: 40px;  height: 40px;  }
.avatar--md { width: 56px;  height: 56px;  }
.avatar--lg { width: 72px;  height: 72px;  }
.avatar--xl { width: 140px; height: 140px; box-shadow: var(--elevation-1); }

/* Initial-based avatar — Gmail 스타일 (고정 brand 그라디언트 + 대문자 이니셜).
   <div class="avatar avatar--xl avatar--initial">S</div> 형태로 사용.
   명시 class 추가 없이도 dsAvatarSetup() 가 자동 부착. */
.avatar.avatar--initial {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--brand-400) 0%, var(--brand-700) 100%);
  color: #FFFFFF;
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  user-select: none;
  line-height: 1;
  overflow: hidden;
}
.avatar.avatar--initial.avatar--xs { font-size: 11px; }
.avatar.avatar--initial.avatar--sm { font-size: 16px; }
.avatar.avatar--initial.avatar--md { font-size: 22px; }
.avatar.avatar--initial.avatar--lg { font-size: 30px; }
.avatar.avatar--initial.avatar--xl { font-size: 60px; }

/* 유저가 커스텀 사진을 업로드한 경우 — background-image 로 표시, 이니셜 글자 숨김 */
.avatar.avatar--has-icon {
  background-image: var(--avatar-img);
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-color: var(--surface-2);
  color: transparent;
}


/* =========================================================================
 * DS-MODAL-FORM — 모달 안 "label + value" 그리드 폼 (Add Device 템플릿)
 * - 좌측 gray-bg 라벨 셀 + 우측 white-bg 값 셀
 * - 필수 표시: .ds-modal-form__required (빨강 *)
 * - 각 row 는 .ds-modal-form 의 직속 자식 2개 (label, value) 로 이루어진다.
 * ========================================================================= */
.ds-modal-form {
  display: grid;
  grid-template-columns: 180px 1fr;
  margin: var(--space-2) var(--space-4) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-0);
}
.ds-modal-form__label {
  padding: var(--space-3) var(--space-4);
  background: var(--surface-2);
  color: var(--text);
  font-weight: var(--fw-semibold);
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 48px;
}
.ds-modal-form__value {
  padding: var(--space-3) var(--space-4);
  background: var(--surface-0);
  color: var(--text);
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  min-width: 0;
  min-height: 48px;
}
/* 마지막 row 의 하단 border 제거 */
.ds-modal-form > :nth-last-child(-n+2) {
  border-bottom: none;
}
.ds-modal-form__required {
  color: var(--color-danger);
  font-weight: var(--fw-bold);
}
/* .modal 범위의 legacy input 패딩을 .ds-modal-form 안에서는 DS 톤으로 덮어쓴다 */
.ds-modal-form__value input[type="text"],
.ds-modal-form__value input[type="password"],
.ds-modal-form__value input[type="number"],
.ds-modal-form__value input[type="email"],
.ds-modal-form__value select,
.ds-modal-form__value textarea {
  width: 100%;
  margin: 0;
  padding: 0 var(--space-3);
  min-height: 36px;
  font-size: var(--text-sm);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-0);
  color: var(--text);
  box-sizing: border-box;
  transition: border-color var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-out);
}
.ds-modal-form__value input:focus,
.ds-modal-form__value select:focus,
.ds-modal-form__value textarea:focus {
  outline: none;
  border-color: var(--brand-500);
  box-shadow: var(--focus-ring);
}

/* DS-MODAL-FOOTER — Cancel / Submit 등 버튼을 가로로 배열 */
.ds-modal-footer {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-4);
  margin-top: var(--space-2);
  border-top: 1px solid var(--border);
}
.ds-modal-footer .btn { min-width: 110px; }


/* =========================================================================
 * LEGACY modal 버튼 색상 통일 — .custom-btn.btn-2 (보라 gradient) 을 DS primary 로.
 * ModalV109.addSubmit() 이 button.className="custom-btn btn-2" 를 강제하므로
 * legacy 색상이 그대로 보인다. .modal 범위로 스코프하여 외부 영향 없이 덮는다.
 * 다른 btn-N variant(삭제 등) 은 그대로 유지.
 * ========================================================================= */
.modal .custom-btn.btn-2 {
  background: var(--color-primary);
  background-image: none;
  color: #fff;
  border: none;
  box-shadow: var(--elevation-1);
  transition: background var(--motion-fast) var(--ease-out);
}
.modal .custom-btn.btn-2:hover        { background: var(--brand-600); box-shadow: var(--elevation-2); }
.modal .custom-btn.btn-2:active       { background: var(--brand-700); }
.modal .custom-btn.btn-2:focus-visible{ outline: 2px solid var(--brand-300); outline-offset: 2px; }


/* =========================================================================
 * CARD-GRID · CARD--TILE — 아이콘/모델 타일 그리드
 * ========================================================================= */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--space-4);
}
.card.card--tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5);
  cursor: pointer;
  text-align: center;
  background: var(--surface-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--elevation-1);
  transition: transform var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-out),
              border-color var(--motion-fast) var(--ease-out);
}
.card.card--tile:hover {
  transform: translateY(-2px);
  box-shadow: var(--elevation-3);
  border-color: var(--brand-400);
}
.card__media {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-md);
  object-fit: cover;
}
.card__caption {
  font-size: var(--text-lg);
  color: var(--text);
  font-weight: var(--fw-semibold);
  word-break: break-all;
}
.card__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-muted);
}


/* =========================================================================
 * STAT-CARD — ALL / Online / Offline 요약
 * ========================================================================= */
.stat-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--surface-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--elevation-1);
}
.stat-card__gauge {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: conic-gradient(var(--color-primary) calc(var(--pct, 0) * 1%), var(--surface-2) 0);
  display: grid;
  place-items: center;
  position: relative;
  transition: background var(--motion-base) var(--ease-out);
}
.stat-card__gauge::before {
  content: "";
  position: absolute;
  inset: 10px;
  background: var(--surface-0);
  border-radius: 50%;
}
.stat-card__value {
  position: relative;
  font-size: var(--text-2xl);
  font-weight: var(--fw-bold);
  color: var(--text);
}
.stat-card__label {
  font-size: var(--text-md);
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}
.stat-card.stat-card--online  .stat-card__gauge {
  background: conic-gradient(var(--color-success) calc(var(--pct, 0) * 1%), var(--surface-2) 0);
}
.stat-card.stat-card--offline .stat-card__gauge {
  background: conic-gradient(#94A3B8 calc(var(--pct, 0) * 1%), var(--surface-2) 0);
}

/* v3 — 클릭 가능한 stat-card 의 hover / selected 상태 */
.stat-card[onclick]:hover {
  border-color: var(--brand-400);
  box-shadow: var(--elevation-2);
  transform: translateY(-1px);
  transition: transform var(--motion-fast) var(--ease-out),
              border-color var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-out);
}
.stat-card.is-selected {
  border-color: var(--brand-500);
  box-shadow: var(--elevation-2), inset 0 0 0 1px var(--brand-500);
}
.stat-card.is-selected .stat-card__label {
  color: var(--brand-500);
  font-weight: var(--fw-semibold);
}


/* =========================================================================
 * FILTER-BAR — 필터·검색 헤더
 * ========================================================================= */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  align-items: center;
  padding: var(--space-3) var(--space-4);
  background: var(--surface-0);                 /* 밝은 배경 (이전: 어두운 배경 이슈) */
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
}
.filter-bar .field--inline {
  display: flex;
  flex-direction: row;            /* .field 의 기본 column 을 필터바 안에서만 row 로 강제 */
  flex-wrap: nowrap;              /* SID·SN·Version 묶음은 한 줄 유지 */
  align-items: center;
  gap: var(--space-3);
}
.filter-bar .field--inline .check {
  white-space: nowrap;            /* 각 라벨은 개별 줄바꿈 금지 */
}
.filter-bar .field--inline .field__label {
  font-size: var(--text-md);
  font-weight: var(--fw-semibold);
  color: var(--text);
  width: auto;
  flex-shrink: 0;
}
.filter-bar .input {
  height: 36px;
  background: var(--surface-0);
  color: var(--text);
}
.filter-bar .input--search {
  background-image: url(../images/store/search.png);
  background-repeat: no-repeat;
  background-position: left var(--space-3) center;
  background-size: 16px;
  padding-left: 36px;
  min-width: 240px;
}
.filter-bar .check {
  font-size: var(--text-md);                    /* 요청: 테이블 헤더와 동일 크기 */
  font-weight: var(--fw-semibold);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}


/* =========================================================================
 * DATA-TABLE — 대용량 리스트 테이블
 * ========================================================================= */
.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  font-size: var(--text-sm);
}
.data-table thead th {
  background: var(--surface-2);
  color: var(--text);
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-md);
  font-weight: var(--fw-semibold);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: middle;
}
.data-table__th-inner {
  display: inline-flex;                         /* 글자 + 정렬 아이콘 인라인 정렬 */
  align-items: center;
  gap: var(--space-1);
  line-height: 1;
}
.data-table__sort {
  width: 14px;
  height: 14px;
  opacity: 0.5;
  cursor: pointer;
  vertical-align: middle;
}
.data-table__sort--active { opacity: 1; }
.data-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover {
  background: var(--surface-1);
  cursor: pointer;
}


/* =========================================================================
 * BADGE — 상태 뱃지 (online/offline 등)
 * ========================================================================= */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  background: var(--surface-2);
  color: var(--text-muted);
  line-height: 1.4;
}
.badge.badge--dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.8;
}
.badge.badge--online {
  background: var(--color-success-bg);
  color: var(--color-success);
}
.badge.badge--offline {
  background: var(--surface-2);
  color: var(--text-muted);
}


/* =========================================================================
 * PAGINATION — DS 스타일 페이지네이션
 * ========================================================================= */
.pagination {
  display: inline-flex;
  list-style: none;
  padding: 0;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-0);
}
.pagination li { display: inline-flex; }
.pagination li + li { border-left: 1px solid var(--border); }
.pagination a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 36px;
  padding: 0 var(--space-3);
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
  font-size: var(--text-sm);
  transition: background var(--motion-fast) var(--ease-out);
}
.pagination a:hover { background: var(--surface-1); }
.pagination a.active {
  background: var(--color-primary);
  color: #fff;
  cursor: default;
}
.pagination a.active:hover { background: var(--color-primary); }
.pagination a.u-click {
  color: var(--text-disabled, #B8BEC7);
  cursor: default;
}
.pagination a.u-click:hover { background: transparent; }


/* =========================================================================
 * BTN-GHOST-ICON — 아이콘 전용 고스트 버튼 (연필 · 휴지통 등)
 * ========================================================================= */
.btn-ghost-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-muted);
  transition: background var(--motion-fast) var(--ease-out),
              color var(--motion-fast) var(--ease-out);
}
.btn-ghost-icon:hover        { background: var(--brand-050); color: var(--color-primary); }
.btn-ghost-icon:focus-visible{ box-shadow: var(--focus-ring); outline: none; }
.btn-ghost-icon img,
.btn-ghost-icon svg          { width: 18px; height: 18px; }


/* --- Tabs (inline style) --- */

.tabs {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
}
.tab {
  background: transparent;
  border: none;
  padding: var(--space-3) 0;
  font-size: var(--text-lg);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  cursor: pointer;
  position: relative;
  transition: color var(--motion-fast) var(--ease-out);
}
.tab:hover { color: var(--text); }
.tab.is-active,
.tab--active {
  color: var(--text);
}
.tab.is-active::after,
.tab--active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--brand-500);
}
.tab-sep {
  color: var(--border-strong);
  user-select: none;
}

/* 가벼운 inline tabs (이미지의 "Device Property | Hardware Status") */
.tabs--inline {
  border-bottom: none;
  gap: var(--space-2);
}
.tabs--inline .tab {
  padding: 0;
  font-size: var(--text-lg);
}
.tabs--inline .tab.is-active::after,
.tabs--inline .tab--active::after {
  display: none;
}


/* --- Segmented Button (Week/Month/Quarter/Year) --- */

.segmented {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-0);
}
.segmented__item {
  padding: 0 var(--space-4);
  height: var(--size-control-md);
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-sm);
  cursor: pointer;
  transition:
    background var(--motion-fast) var(--ease-out),
    color var(--motion-fast) var(--ease-out);
}
.segmented__item + .segmented__item { border-left: 1px solid var(--border); }
.segmented__item:hover { background: var(--surface-2); }
.segmented__item.is-active,
.segmented__item--active {
  background: var(--brand-050);
  color: var(--brand-500);
  font-weight: var(--fw-medium);
}


/* --- Data Table --- */

.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-sm);
}
.data-table thead th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  color: var(--text-muted);
  font-weight: var(--fw-medium);
  border-bottom: 1px solid var(--border);
  background: var(--surface-0);
  position: sticky;
  top: 0;
  z-index: 1;
}
.data-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr { transition: background var(--motion-fast) var(--ease-out); }
.data-table tbody tr:hover { background: var(--surface-1); }

.data-table--compact thead th,
.data-table--compact tbody td {
  padding: var(--space-2) var(--space-3);
}

.cell-link {
  color: var(--brand-500);
}
.cell-link:hover { text-decoration: underline; }

.cell-muted { color: var(--text-muted); }


/* --- Status text (Offline / Running / …) --- */

.status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
}
.status::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
  display: inline-block;
  flex-shrink: 0;
}
.status--success { color: var(--status-success); }
.status--danger  { color: var(--status-danger); }
.status--warning { color: var(--status-warning); }
.status--muted   { color: var(--status-muted); }


/* --- Tag / Badge --- */

.tag {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  background: var(--surface-2);
  color: var(--text);
  white-space: nowrap;
}
.tag--success { background: var(--color-success-bg); color: var(--status-success); }
.tag--danger  { background: var(--color-danger-bg);  color: var(--status-danger); }
.tag--warning { background: var(--color-warning-bg); color: var(--status-warning); }
.tag--info    { background: var(--color-info-bg);    color: var(--color-info); }

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--color-danger);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
}


/* --- Pagination --- */

.pagination {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-muted);
  flex-wrap: wrap;
}
.pagination__summary strong { color: var(--text); }
.pagination__size {
  margin-left: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-2);
  height: var(--size-control-sm);
  background: var(--surface-0);
}

.pagination__nav {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
}
.pagination__nav button {
  min-width: var(--size-control-sm);
  height: var(--size-control-sm);
  border: 1px solid var(--border);
  background: var(--surface-0);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-out);
}
.pagination__nav button:hover:not(:disabled):not(.is-current) {
  background: var(--surface-2);
}
.pagination__nav button.is-current {
  background: var(--brand-500);
  color: #fff;
  border-color: var(--brand-500);
}
.pagination__nav button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}


/* --- Modal (기존 ModalV109 대체) --- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(17, 24, 39, 0.48);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: center;
  z-index: var(--z-modal);
  animation: sam4s-fade-in var(--motion-base) var(--ease-out);
}

.modal-dialog {
  background: var(--surface-0);
  border-radius: var(--radius-lg);
  box-shadow: var(--elevation-4);
  width: min(560px, calc(100% - var(--space-8)));
  max-height: calc(100vh - var(--space-8));
  overflow: auto;
  animation: sam4s-scale-in var(--motion-base) var(--ease-out);
}

.modal-dialog--sm { width: min(420px, calc(100% - var(--space-8))); }
.modal-dialog--lg { width: min(720px, calc(100% - var(--space-8))); }

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-5) var(--space-5) var(--space-3);
}
.modal__title {
  font-size: var(--text-lg);
  font-weight: var(--fw-semibold);
}
.modal__close {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: var(--space-1);
}
.modal__close:hover { color: var(--text); }

.modal__body {
  padding: var(--space-3) var(--space-5);
}
.modal__footer {
  padding: var(--space-3) var(--space-5) var(--space-5);
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}

@keyframes sam4s-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes sam4s-scale-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}


/* --- Toast --- */

.toast-stack {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  z-index: var(--z-toast);
  pointer-events: none;
}

.toast {
  background: var(--surface-0);
  border: 1px solid var(--border);
  border-left: 4px solid var(--color-info);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
  box-shadow: var(--elevation-3);
  max-width: 360px;
  font-size: var(--text-sm);
  color: var(--text);
  pointer-events: auto;
  animation: sam4s-slide-in var(--motion-base) var(--ease-out);
}
.toast--success { border-left-color: var(--color-success); }
.toast--danger  { border-left-color: var(--color-danger); }
.toast--warning { border-left-color: var(--color-warning); }

@keyframes sam4s-slide-in {
  from { opacity: 0; transform: translateX(16px); }
  to   { opacity: 1; transform: translateX(0); }
}


/* =============================================================
 *  Part E — Dashboard Specific
 * ============================================================= */

/* --- Donut Stat (이미지의 11124 All 등) --- */

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-6);
  padding-top: var(--space-2);
}

.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.stat__donut {
  --ring-size: 160px;
  --ring-value: 100;
  --ring-color: var(--stat-purple);
  width: var(--ring-size);
  height: var(--ring-size);
  border-radius: 50%;
  background:
    conic-gradient(var(--ring-color) calc(var(--ring-value) * 1%),
                   var(--surface-2) 0);
  display: grid;
  place-items: center;
  position: relative;
}
.stat__donut::before {
  content: "";
  position: absolute;
  inset: 12px;
  border-radius: 50%;
  background: var(--surface-0);
}

.stat__value {
  position: relative;
  z-index: 1;
  font-size: var(--text-stat);
  line-height: 1;
  font-weight: var(--fw-bold);
  color: var(--text);
}

.stat__label {
  font-size: var(--text-base);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}


/* --- Ranked List (Top Dealer Ranking) --- */

.ranked-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.ranked-list > li {
  display: grid;
  grid-template-columns: 32px 1fr auto;
  align-items: center;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-base);
}
.ranked-list > li:last-child { border-bottom: none; }

.rank {
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}
.rank-name {
  color: var(--text);
}
.rank-value {
  color: var(--brand-500);
  font-weight: var(--fw-medium);
}


/* --- Chart card wrapper --- */

.chart-card__legend {
  display: flex;
  gap: var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}
.chart-card__legend .dot {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 2px;
  margin-right: var(--space-2);
  vertical-align: middle;
}
.chart-card__legend .dot--bar  { background: var(--chart-bar); }
.chart-card__legend .dot--line { background: var(--chart-line); }


/* =============================================================
 *  Part F — Page Patterns
 * ============================================================= */

/* --- Page Header --- */

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  margin-bottom: var(--space-5);
  border-bottom: 1px solid var(--border);
  /* 스크롤 시 .app-main 의 최상단에 고정 — 타이틀 + Save All / Delete 가 항상 보임 */
  position: -webkit-sticky;
  position: sticky;
  top: 0;                           /* .app-main 의 visible area 상단에 sticky (topnav 바로 밑) */
  z-index: var(--z-sidebar);
  background: var(--surface-1);     /* 스크롤되는 콘텐츠가 배경에 보이지 않도록 page bg 와 동일 */
}

/* sticky page-header 위쪽 갭(.app-main padding-top + .container padding-block-start ≈ 44px)
   영역에서 스크롤되는 카드가 비치지 않도록 pseudo-element 로 page bg 를 위쪽으로 200px 확장.
   - .page-header 가 position: sticky 라 자체가 absolute 의 containing block 이 되어
     스크롤 시 ::before 도 함께 따라온다.
   - 화면을 벗어난 영역은 어차피 topnav (z-index 20 > z-sidebar 10) 가 가리므로 안전. */
.page-header::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 200px;
  background: var(--surface-1);
  pointer-events: none;
}

.page-header__title {
  font-size: var(--text-xl);
  font-weight: var(--fw-semibold);
  margin: 0;
}
.page-header__breadcrumb {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin-top: var(--space-1);
}
.page-header__actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
/* Save All / Delete 등 page-header 액션 버튼은 1.5배 크기
   — 기본 .btn 의 height(40), padding(0 16), font-size(13) 를 그대로 1.5배.
   - 좌우 길이 동일: 더 긴 라벨(Save All) 기준 min-width 고정.
   - 평상시: 투명 배경 + 컬러 글씨/굵은 테두리(outline 스타일).
   - hover : 컬러 배경 + 흰 글씨로 채움(filled). */
.page-header__actions .btn {
  min-height: calc(var(--size-control-md) * 1.5);   /* 60px */
  padding: 0 calc(var(--space-4) * 1.5);            /* 0 24px */
  font-size: calc(var(--text-sm) * 1.85);           /* ≈ 24px — 버튼 프레임은 그대로, 글씨만 더 크게 */
  border-radius: var(--radius-md);                  /* 큰 버튼은 살짝 더 둥글게 */
  width: 160px;                                     /* Save All / Delete 좌우 길이 정확히 동일 (이전 사이즈 유지) */
  font-weight: var(--fw-bold);                      /* 글씨 bold */
  border-width: 3px;                                /* 테두리 두껍게 */
  border-style: solid;
  transition:
    background var(--motion-base) var(--ease-out),
    color var(--motion-base) var(--ease-out),
    border-color var(--motion-base) var(--ease-out);
}

/* Save All — 평상시: 투명 배경 / 파란 글씨 / 파란 테두리. Hover: 파란 배경 + 흰 글씨. */
.page-header__actions .btn-primary {
  background: transparent;
  color: var(--brand-500);
  border-color: var(--brand-500);
}
.page-header__actions .btn-primary:hover {
  background: var(--brand-500);
  color: var(--color-on-primary);
  border-color: var(--brand-500);
}
.page-header__actions .btn-primary:active {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: var(--color-on-primary);
}

/* Delete — 평상시: 투명 배경 / 빨간 글씨 / 빨간 테두리. Hover: 빨간 배경 + 흰 글씨. */
.page-header__actions .btn-danger {
  background: transparent;
  color: var(--color-danger);
  border-color: var(--color-danger);
}
.page-header__actions .btn-danger:hover {
  background: var(--color-danger);
  color: #fff;
  border-color: var(--color-danger);
  filter: none;                                     /* 기본 .btn-danger:hover 의 brightness 필터 무력화 */
}
.page-header__actions .btn-danger:active {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: #fff;
  filter: brightness(0.9);
}


/* --- Empty / Loading / Error State --- */

.state-block {
  padding: var(--space-12) var(--space-6);
  text-align: center;
  color: var(--text-muted);
}
.state-block__icon {
  font-size: 48px;
  margin-bottom: var(--space-3);
  opacity: 0.5;
}
.state-block__title {
  font-size: var(--text-lg);
  color: var(--text);
  font-weight: var(--fw-medium);
}
.state-block__message {
  margin-top: var(--space-2);
  margin-bottom: var(--space-4);
}


/* --- Key-Value List --- */

.kv-list {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3) var(--space-4);
  margin: 0;
}
.kv-list > div {
  display: contents;
}
.kv-list dt {
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
}
.kv-list dd {
  color: var(--text);
  font-size: var(--text-sm);
  margin: 0;
  min-width: 0;
}


/* =============================================================
 *  Info Row — 라벨(넓음) + 값(+액션) 의 프로필형 정보 행
 *  .kv-list 는 CSS Grid + display:contents 로 구성돼
 *  값 영역에 flex wrapper 를 쓰면 자동배치가 깨진다.
 *  그래서 profile/account 화면은 단순 flex 기반 .info-row 를 쓴다.
 * ============================================================= */
.info-list {
  display: flex;
  flex-direction: column;
}
.info-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-muted, var(--border));
}
.info-row:last-child { border-bottom: none; }
.info-row__label {
  width: 240px;
  flex-shrink: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
}
.info-row__value {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-width: 0;
  color: var(--text);
  font-size: var(--text-sm);
}
@media (max-width: 640px) {
  .info-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    padding: var(--space-2) 0;
  }
  .info-row__label { width: auto; }
}


/* =============================================================
 *  Part G — Utilities
 * ============================================================= */

/* Text */
.u-text-left   { text-align: left; }
.u-text-center { text-align: center; }
.u-text-right  { text-align: right; }
.u-text-muted  { color: var(--text-muted); }
.u-text-danger { color: var(--color-danger); }
.u-text-success{ color: var(--color-success); }
.u-text-nowrap { white-space: nowrap; }
.u-text-xs     { font-size: var(--text-xs); }
.u-text-sm     { font-size: var(--text-sm); }
.u-text-lg     { font-size: var(--text-lg); }
.u-fw-bold     { font-weight: var(--fw-bold); }
.u-fw-medium   { font-weight: var(--fw-medium); }

/* Margin / Padding (자주 쓰는 것만) */
.u-mt-0 { margin-top: 0; }
.u-mt-2 { margin-top: var(--space-2); }
.u-mt-4 { margin-top: var(--space-4); }
.u-mt-6 { margin-top: var(--space-6); }
.u-mb-0 { margin-bottom: 0; }
.u-mb-2 { margin-bottom: var(--space-2); }
.u-mb-4 { margin-bottom: var(--space-4); }
.u-mb-6 { margin-bottom: var(--space-6); }

/* Display */
.u-hidden      { display: none !important; }
.u-flex        { display: flex; }
.u-inline-flex { display: inline-flex; }
.u-grid        { display: grid; }
.u-block       { display: block; }

/* Flex helpers */
.u-items-center  { align-items: center; }
.u-justify-between { justify-content: space-between; }
.u-justify-end   { justify-content: flex-end; }
.u-gap-2 { gap: var(--space-2); }
.u-gap-3 { gap: var(--space-3); }
.u-gap-4 { gap: var(--space-4); }

/* Width */
.u-w-full { width: 100%; }
.u-w-auto { width: auto; }

/* Screen reader only */
.u-sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
