/* 자동 생성: skill/slur-design/scripts/build-css.mjs — 원본을 수정한 뒤 재생성하세요. */

/* SOURCE: ../../slur-guidelines/assets/common.css */
/* COMMON — 재사용 상태 컴포넌트의 기본 노출 규칙. global.css 다음에 로드한다. */

/* 4상태 스위치 — 문법(ux-states.md)이 전제하는 노출 전환. 색·크기 없음, 보인다/숨긴다만.
   블록이 data-state="loading|empty|error|success"를 갖고, 안내문 셋(i_loading/i_empty/i_error)은
   항상 렌더되는 .i_status(role="status") 상자 안에 둔다 — 상자가 미리 있어야 전환이 보조 기술에 읽힌다.
   display:none은 접근성 트리에서도 빠지므로 "지금 상태가 아닌 안내문"을 숨기는 데 맞는 방법이다.
   i_ 요소를 블록 대신 [data-state]로 스코프하는 유일한 예외 — 이 넷은 문법이 전역으로 예약한 이름이다.
   모양(스피너·스켈레톤·빈 상태 패널)은 여기가 아니라 slur-design components/state.css가 담당한다.
   슬롯 안에는 무엇이든 둘 수 있지만(스켈레톤·empty_state), i_loading에는 읽힐 문장을 하나 둔다(a11y_hidden 가능).
     <section class="list_x" data-state="loading">
       <div class="i_status" role="status"> .i_loading / .i_empty / .i_error </div>
       <ul class="i_body">…</ul>
     </section> */
[data-state] > .i_status > .i_loading, [data-state] > .i_status > .i_empty, [data-state] > .i_status > .i_error { display: none; }
[data-state="loading"] > .i_status > .i_loading { display: block; }
[data-state="empty"] > .i_status > .i_empty { display: block; }
[data-state="error"] > .i_status > .i_error { display: block; }
[data-state="loading"] > .i_body, [data-state="empty"] > .i_body, [data-state="error"] > .i_body { display: none; }


/* SOURCE: patterns/app-shell.css */
/* ─────────────────────────────────────────────
   APP SHELL — SLUR Design System × slur-guidelines (patterns 층)
   대시보드 앱 셸 layout_app: l_side(사이드바) / l_head(상단 바) / l_main(본문).
   레이아웃 블록 규칙대로 내부는 l_로 자족한다 — nav_side·btn 같은 공유
   컴포넌트를 셸 안에 직접 두지 않고, 컴포넌트는 l_main 안의 페이지가 조합한다.
   데스크톱(1024+)은 2열 고정, 그 아래에서 l_side는 드로어가 된다 —
   열림은 data-state="open", 배경 inert·Esc·포커스 복귀는 slur.js(drawer).
   현재 페이지의 정본은 aria-current="page". 구조 간격은 px(레이아웃 값).
   이 저작 원본은 common.css에 포함한다. 로드 순서: global.css → common.css → page.css.
   ───────────────────────────────────────────── */

.layout_app { display: grid; min-height: 100vh; grid-template-columns: 240px 1fr; grid-template-rows: auto 1fr; grid-template-areas: "side head" "side main"; background: var(--color-surface-sunken); }

/* 사이드바 — l_side(드로어 껍데기) > l_panel(패널) + l_dim(모바일 딤) */
.layout_app .l_side { height: 100vh; grid-area: side; position: sticky; top: 0; }
.layout_app .l_panel { display: flex; width: 100%; height: 100%; padding: 16px 12px; border-right: 1px solid var(--color-border-subtle); background: var(--color-surface-card); flex-direction: column; gap: 2px; overflow-y: auto; }
.layout_app .l_dim { display: none; }
.layout_app .l_brand { display: flex; align-items: center; gap: var(--space-8); height: 2.5rem; margin-bottom: 12px; padding: 0 var(--space-12); font-weight: var(--weight-bold); color: var(--color-text-primary); text-decoration: none; }
.layout_app .l_brand svg { width: 1.5rem; height: 1.5rem; color: var(--color-brand); flex: none; }
.layout_app .l_group { padding: var(--space-8) var(--space-12) var(--space-4); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-wide); color: var(--color-text-muted); text-transform: uppercase; }
.layout_app .l_nav { display: flex; flex-direction: column; gap: 2px; list-style: none; }
.layout_app .l_item { display: flex; align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); border-radius: var(--radius-8); font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); text-decoration: none; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.layout_app .l_item:hover { background: var(--color-surface-hover); color: var(--color-text-primary); }
.layout_app .l_item[aria-current="page"] { background: var(--color-brand-soft); font-weight: var(--weight-semibold); color: var(--color-text-brand); }
.layout_app .l_item svg { width: 1.125em; height: 1.125em; flex: none; }
.layout_app .l_count { display: inline-flex; align-items: center; justify-content: center; min-width: 1.25rem; height: 1.25rem; margin-left: auto; padding: 0 var(--space-4); border-radius: var(--radius-full); background: var(--color-surface-hover); font-size: var(--text-xs); font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; color: var(--color-text-secondary); }
.layout_app .l_divider { height: 1px; margin: var(--space-8) var(--space-4); background: var(--color-border-subtle); }
.layout_app .l_foot { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--color-border-subtle); }
.layout_app .l_user { display: flex; align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); border-radius: var(--radius-8); font-size: var(--text-sm); color: var(--color-text-primary); text-decoration: none; }
.layout_app .l_user:hover { background: var(--color-surface-hover); }
.layout_app .l_avatar { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: 50%; background: var(--color-brand-soft); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-text-brand); flex: none; }
.layout_app .l_user_meta { display: flex; flex-direction: column; line-height: 1.3; }
.layout_app .l_user_meta small { font-size: var(--text-xs); color: var(--color-text-muted); }
.layout_app .l_close { display: none; }

/* 상단 바 — 제목·브레드크럼 자리(l_title) + 오른쪽 액션(l_actions). 모바일 햄버거(l_menu)는 여기 */
.layout_app .l_head { display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px; border-bottom: 1px solid var(--color-border-subtle); background: var(--color-surface-card); grid-area: head; position: sticky; top: 0; z-index: var(--z-sticky); }
.layout_app .l_title { font-size: var(--text-lg); font-weight: var(--weight-semibold); }
.layout_app .l_actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.layout_app .l_menu { display: none; }

/* 본문 — 페이지(page_*)가 들어온다. min-width:0은 그리드 안 표·차트의 가로 넘침 방지 */
.layout_app .l_main { min-width: 0; padding: 24px 16px; grid-area: main; }

/* 모바일 — 사이드바는 드로어. l_side는 전체 화면 껍데기(딤 포함), l_panel이 왼쪽에서 들어온다 */
@media (max-width: 1023px) {
  .layout_app { grid-template-columns: 1fr; grid-template-areas: "head" "main"; }
  .layout_app .l_side { display: none; height: auto; position: fixed; inset: 0; z-index: var(--z-modal); transition: display var(--duration-slow) allow-discrete; }
  .layout_app .l_side[data-state="open"] { display: block; }
  .layout_app .l_panel { width: 280px; max-width: 85vw; border-right: none; position: relative; z-index: 1; box-shadow: var(--shadow-lg); transition: transform var(--duration-slow) var(--ease-standard); }
  @starting-style { .layout_app .l_side[data-state="open"] .l_panel { transform: translateX(-100%); } }
  .layout_app .l_dim { display: block; background: var(--color-surface-overlay); position: absolute; inset: 0; }
  .layout_app .l_close { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: none; border-radius: var(--radius-8); background: transparent; color: var(--color-text-muted); position: absolute; top: 20px; right: 12px; cursor: pointer; }
  .layout_app .l_close svg { width: 1.125em; height: 1.125em; }
  .layout_app .l_menu { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; margin-left: -12px; border: none; background: transparent; color: inherit; cursor: pointer; }
  .layout_app .l_menu svg { width: 1.875rem; height: 1.875rem; }
  .layout_app .l_head { padding: 0 16px; }
  .layout_app .l_main { padding: 16px; }
}

/* 브랜드 로고 — assets/brand/logo.svg(라이트) · logo-white.svg(다크)를 img 두 장으로 두고 테마에 따라 하나만 보인다.
   (mask로 칠하면 한 장으로 되지만 CORS 이미지라 file://로 열었을 때 안 그려진다.) 비율 416:109. 이름은 l_logo가 role="img"로 갖는다 */
.layout_app .l_logo { display: inline-flex; height: 22px; }
.layout_app .l_logo img { display: block; height: 100%; width: auto; }
.layout_app .l_logo .l_logo_dark { display: none; }
[data-theme="dark"] .layout_app .l_logo .l_logo_light { display: none; }
[data-theme="dark"] .layout_app .l_logo .l_logo_dark { display: block; }


/* SOURCE: patterns/auth-shell.css */
/* ─────────────────────────────────────────────
   AUTH SHELL — SLUR Design System × slur-guidelines (patterns 층)
   로그인·회원가입·비밀번호 재설정 같은 단일 과업 화면의 틀 layout_auth:
   l_main > l_card(가운데 카드)는 필수, l_brand(상단 로고)와
   l_foot(하단 링크)는 선택 슬롯이다.
   레이아웃 규칙대로 내부는 l_로 자족하고, 폼(field·btn)은 l_card 안의
   page_* 블록이 조합한다. 구조 간격은 px(레이아웃 값).
   이 저작 원본은 common.css에 포함한다. 로드 순서: global.css → common.css → page.css.
   ───────────────────────────────────────────── */

/* 셸이 존재하는 슬롯 전체를 세로 가운데 정렬한다. 높이는 고정하지 않아 콘텐츠가 화면보다 길면 상단부터 자연스럽게 흐른다 */
.layout_auth { display: flex; min-height: 100vh; padding: 24px; background: var(--color-surface-sunken); flex-direction: column; align-items: center; justify-content: center; }
.layout_auth .l_brand { display: flex; align-items: center; margin: 0 0 28px; color: var(--color-text-primary); text-decoration: none; }
.layout_auth .l_main { display: flex; width: 100%; max-width: 400px; flex-direction: column; }
.layout_auth .l_card { padding: 32px; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); box-shadow: var(--shadow-sm); }
.layout_auth .l_foot { display: flex; gap: var(--space-16); margin: 24px 0 0; font-size: var(--text-xs); color: var(--color-text-muted); }
.layout_auth .l_foot a { color: var(--color-text-secondary); text-decoration: none; }
.layout_auth .l_foot a:hover { color: var(--color-text-primary); text-decoration: underline; }

@media (max-width: 639px) {
  .layout_auth { padding: 16px; }
  .layout_auth .l_brand { margin-bottom: 20px; }
  .layout_auth .l_card { padding: 24px 20px; }
}

/* 브랜드 로고 — assets/brand/logo.svg(라이트) · logo-white.svg(다크)를 img 두 장으로 두고 테마에 따라 하나만 보인다.
   (mask로 칠하면 한 장으로 되지만 CORS 이미지라 file://로 열었을 때 안 그려진다.) 비율 416:109. 이름은 l_logo가 role="img"로 갖는다 */
.layout_auth .l_logo { display: inline-flex; height: 28px; }
.layout_auth .l_logo img { display: block; height: 100%; width: auto; }
.layout_auth .l_logo .l_logo_dark { display: none; }
[data-theme="dark"] .layout_auth .l_logo .l_logo_light { display: none; }
[data-theme="dark"] .layout_auth .l_logo .l_logo_dark { display: block; }


/* SOURCE: components/button.css */
/* ─────────────────────────────────────────────
   BUTTON — SLUR Design System × slur-guidelines
   기본형은 보조(중립) 버튼. 변형은 m_, 상태는 data-state.
   높이·패딩은 rem(텍스트와 함께 확대), 값은 시맨틱 토큰만.
   공유 컨트롤 높이: 2/2.5/3rem (32/40/48).
   ───────────────────────────────────────────── */

.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8); height: 2.5rem; padding: 0 var(--space-16); border: 1px solid var(--color-border-default); border-radius: var(--radius-8); background: var(--color-surface-card); text-decoration: none; color: inherit; cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard); }
.btn:hover { background: var(--color-surface-hover); }
.btn:active { background: var(--color-surface-sunken); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn svg { width: 1.125em; height: 1.125em; flex: none; }

/* 색상 변형 */
.btn.m_primary { border-color: transparent; background: var(--color-brand); color: var(--color-on-brand); }
.btn.m_primary:hover { background: var(--color-brand-hover); }
.btn.m_primary:active { background: var(--color-brand-active); }
.btn.m_ghost { border-color: transparent; background: transparent; }
.btn.m_ghost:hover { background: var(--color-surface-hover); }
.btn.m_ghost:active { background: var(--color-surface-sunken); }
.btn.m_danger { border-color: transparent; background: var(--color-danger-solid); color: var(--color-on-danger); }
.btn.m_danger:hover { filter: brightness(0.92); }
.btn.m_danger:active { filter: brightness(0.85); }

/* 크기 변형 — 공유 컨트롤 높이 2/2.5/3rem */
.btn.m_small { gap: var(--space-4); height: 2rem; padding: 0 var(--space-12); font-size: var(--text-xs); }
.btn.m_large { gap: var(--space-12); height: 3rem; padding: 0 var(--space-24); font-size: var(--text-base); }
.btn.m_full { width: 100%; font-weight: var(--weight-semibold); }
/* 아이콘만 있는 정사각 버튼 — 보이는 크기 = 탭 영역. 모바일 단독 탭 타깃이면 m_large(48) */
.btn.m_icon { width: 2.5rem; padding: 0; }
.btn.m_icon.m_small { width: 2rem; }
.btn.m_icon.m_large { width: 3rem; }

/* 햄버거(메뉴) 버튼 — 모바일 내비게이션을 여는 단독 버튼.
   48×48(3rem) 고정: 이 버튼은 보이는 크기 = 실제 탭 영역이라, 모바일 최소
   터치 타깃 권장(Material 48·Apple 44)을 채우려면 48이어야 한다(40은 미달).
   테두리·배경 없이 아이콘만 — 배경 피드백(원형 hover) 없음. */
.btn_menu { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; border: none; background: transparent; color: inherit; cursor: pointer; }
.btn_menu svg { width: 1.875rem; height: 1.875rem; flex: none; }

/* 상태 */
.btn[data-state="loading"] { opacity: 0.6; pointer-events: none; cursor: wait; }


/* SOURCE: components/input.css */
/* ─────────────────────────────────────────────
   INPUT — SLUR Design System × slur-guidelines
   field(래퍼) + input_text(컨트롤). 오류/성공은
   data-state, 크기는 m_. 높이·패딩은 rem(텍스트와
   함께 확대), 공유 컨트롤 높이 2/2.5/3rem.
   ───────────────────────────────────────────── */

/* 필드 래퍼 — 라벨/도움말 포함 */
.field { display: flex; flex-direction: column; gap: var(--space-8); }
.field .i_label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-primary); }
.field .i_help { font-size: var(--text-xs); color: var(--color-text-muted); }
.field[data-state="error"] .i_help { color: var(--color-danger); }
.field[data-state="success"] .i_help { color: var(--color-success); }
.field[data-state="disabled"] .i_label { color: var(--color-text-muted); }

/* 텍스트 컨트롤 — input/textarea/select 공통 */
.input_text { height: 2.5rem; padding: 0 var(--space-12); border: 1px solid var(--color-border-default); border-radius: var(--radius-8); background: var(--color-surface-card); transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); }
.input_text:hover { border-color: var(--color-border-strong); }
.input_text:focus { border-color: var(--color-border-focus); box-shadow: var(--color-focus-ring); }
.input_text::placeholder { color: var(--color-text-muted); opacity: 1; }
.input_text:disabled { border-color: var(--color-border-subtle); background: var(--color-surface-sunken); color: var(--color-text-muted); cursor: not-allowed; }
.input_text:read-only { border-color: var(--color-border-subtle); background: var(--color-surface-sunken); color: var(--color-text-secondary); }
.input_text[data-state="error"] { border-color: var(--color-danger); box-shadow: 0 0 0 3px var(--color-danger-soft); }
.input_text[data-state="success"] { border-color: var(--color-success); box-shadow: 0 0 0 3px var(--color-success-soft); }

/* 크기 변형 */
.input_text.m_small { height: 2rem; padding: 0 var(--space-8); font-size: var(--text-xs); }
.input_text.m_large { height: 3rem; padding: 0 var(--space-16); font-size: var(--text-base); }

/* 텍스트에리어 변형 */
.input_text.m_textarea { height: auto; padding: var(--space-8) var(--space-12); resize: vertical; }

/* 아이콘 포함 래퍼 */
.input_wrap { display: flex; width: 100%; align-items: center; position: relative; }
.input_wrap .input_text { width: 100%; }
.input_wrap .i_icon { display: inline-flex; color: var(--color-text-muted); position: absolute; left: var(--space-12); pointer-events: none; }
.input_wrap .i_icon svg { width: 1.125em; height: 1.125em; }
.input_wrap .input_text.m_icon_left { padding-left: 2.25rem; }

/* 오른쪽 액션 — 비밀번호 보기·지우기 같은 버튼을 컨트롤 안에. 버튼은 i_action(아이콘 전용, aria-label·aria-pressed 필수) */
.input_wrap .input_text.m_icon_right { padding-right: 2.5rem; }
.input_wrap .i_action { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: none; border-radius: var(--radius-4); background: transparent; color: var(--color-text-muted); position: absolute; right: var(--space-4); cursor: pointer; transition: color var(--duration-fast) var(--ease-standard); }
.input_wrap .i_action:hover { color: var(--color-text-primary); }
.input_wrap .i_action svg { width: 1.125em; height: 1.125em; }


/* SOURCE: components/select.css */
/* ─────────────────────────────────────────────
   SELECT — SLUR Design System × slur-guidelines
   네이티브 select + 화살표 아이콘을 가진 블록.
   컨트롤 스타일은 input_text를 그대로 쓰고,
   select 고유의 것(appearance, 화살표 공간)만 얹는다.
   ───────────────────────────────────────────── */

.select { display: flex; width: 100%; align-items: center; position: relative; }
.select .input_text { width: 100%; padding-right: 2.25rem; cursor: pointer; appearance: none; -webkit-appearance: none; }
.select .i_icon { display: inline-flex; color: var(--color-text-muted); position: absolute; right: var(--space-12); pointer-events: none; }
.select .i_icon svg { width: 1.125em; height: 1.125em; }


/* SOURCE: components/selection.css */
/* ─────────────────────────────────────────────
   SELECTION — SLUR Design System × slur-guidelines
   체크박스·라디오는 네이티브 input에 appearance:none,
   켜짐은 :checked(네이티브 상태). 토글은 JS 상태라
   data-state="on|off". 치수는 rem(텍스트와 함께 확대).
   ───────────────────────────────────────────── */

/* 체크박스 */
.check { display: inline-flex; align-items: center; gap: var(--space-8); font-size: var(--text-sm); cursor: pointer; }
.check .i_input { display: inline-flex; width: 1.125rem; height: 1.125rem; border: 1px solid var(--color-border-default); border-radius: var(--radius-4); background: var(--color-surface-card); cursor: pointer; appearance: none; -webkit-appearance: none; flex: none; transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard); }
.check .i_input:checked { border-color: var(--color-brand); background: var(--color-brand) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / 0.75rem no-repeat; }
.check .i_input:indeterminate { border-color: var(--color-brand); background: var(--color-brand) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M2 12h20'/%3E%3C/svg%3E") center / 0.75rem no-repeat; }
.check .i_input:disabled { border-color: var(--color-border-subtle); background: var(--color-surface-sunken); cursor: not-allowed; }
.check:has(.i_input:disabled) { color: var(--color-text-muted); cursor: not-allowed; }

/* 라디오 */
.radio { display: inline-flex; align-items: center; gap: var(--space-8); font-size: var(--text-sm); cursor: pointer; }
.radio .i_input { display: inline-flex; width: 1.125rem; height: 1.125rem; border: 1px solid var(--color-border-default); border-radius: 50%; background: var(--color-surface-card); cursor: pointer; appearance: none; -webkit-appearance: none; flex: none; transition: border-color var(--duration-fast) var(--ease-standard); }
.radio .i_input:checked { border-color: var(--color-brand); background: radial-gradient(circle, var(--color-brand) 0 0.25rem, transparent 0.3rem); }
.radio .i_input:disabled { border-color: var(--color-border-subtle); background: var(--color-surface-sunken); cursor: not-allowed; }
.radio:has(.i_input:disabled) { color: var(--color-text-muted); cursor: not-allowed; }

/* 토글 스위치 — button[role="switch"]. 켜짐의 정본은 표준 ARIA 상태 aria-checked="true"(data-state="on"도 인정) */
.switch { display: inline-flex; width: 2.5rem; height: 1.5rem; border: none; border-radius: var(--radius-full); background: var(--color-border-strong); cursor: pointer; position: relative; flex: none; transition: background-color var(--duration-base) var(--ease-standard); }
.switch .i_knob { width: 1.25rem; height: 1.25rem; border-radius: 50%; background: var(--color-surface-card); box-shadow: var(--shadow-sm); position: absolute; top: 0.125rem; left: 0.125rem; transition: left var(--duration-base) var(--ease-standard), background-color var(--duration-base) var(--ease-standard); }
.switch[data-state="on"], .switch[aria-checked="true"] { background: var(--color-brand); }
.switch[data-state="on"] .i_knob, .switch[aria-checked="true"] .i_knob { background: var(--color-on-brand); }
.switch[data-state="on"] .i_knob, .switch[aria-checked="true"] .i_knob { left: 1.125rem; }
.switch:disabled { opacity: 0.45; cursor: not-allowed; }


/* SOURCE: components/badge.css */
/* ─────────────────────────────────────────────
   BADGE — SLUR Design System × slur-guidelines
   기본형은 soft·중립. 색은 m_brand/m_success/…,
   스타일은 m_solid/m_outline, 크기는 m_small/m_medium.
   치수는 rem(텍스트와 함께 확대), 4px 그리드로 스냅.
   ───────────────────────────────────────────── */

.badge { display: inline-flex; align-items: center; gap: var(--space-8); height: 1.5rem; padding: 0 var(--space-8); border-radius: var(--radius-full); background: var(--color-surface-hover); font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--color-text-secondary); }
.badge .i_dot { display: inline-block; width: 0.375rem; height: 0.375rem; border-radius: 50%; background: currentColor; }

/* 색상 변형 — soft(기본) */
.badge.m_brand { background: var(--color-brand-soft); color: var(--color-text-brand); }
.badge.m_success { background: var(--color-success-soft); color: var(--color-success); }
.badge.m_warning { background: var(--color-warning-soft); color: var(--color-warning); }
.badge.m_danger { background: var(--color-danger-soft); color: var(--color-danger); }

/* 스타일 변형 — solid */
.badge.m_solid { background: var(--color-surface-inverse); color: var(--color-text-inverse); }
.badge.m_solid.m_brand { background: var(--color-brand); color: var(--color-on-brand); }
.badge.m_solid.m_success { background: var(--color-success-solid); color: var(--color-on-success); }
.badge.m_solid.m_warning { background: var(--color-warning-solid); color: var(--color-on-warning); }
.badge.m_solid.m_danger { background: var(--color-danger-solid); color: var(--color-on-danger); }

/* 스타일 변형 — outline */
.badge.m_outline { border: 1px solid var(--color-border-default); background: transparent; }
.badge.m_outline.m_brand { border-color: var(--color-brand); background: transparent; }
.badge.m_outline.m_success { border-color: var(--color-success); background: transparent; }
.badge.m_outline.m_danger { border-color: var(--color-danger); background: transparent; }

/* 카운트 변형 */
.badge.m_count { justify-content: center; min-width: 1.25rem; height: 1.25rem; padding: 0 var(--space-4); font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }

/* 크기 변형 */
.badge.m_small { height: 1.25rem; padding: 0 var(--space-8); }
.badge.m_medium { height: 1.75rem; padding: 0 var(--space-12); font-size: var(--text-sm); }

/* 삭제 가능한 칩 */
.chip { display: inline-flex; align-items: center; gap: var(--space-8); height: 1.75rem; padding: 0 var(--space-4) 0 var(--space-12); border: 1px solid var(--color-border-default); border-radius: var(--radius-full); background: var(--color-surface-card); font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-primary); }
.chip .i_close { display: inline-flex; align-items: center; justify-content: center; width: 1.125rem; height: 1.125rem; border: none; border-radius: 50%; background: transparent; color: var(--color-text-muted); cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.chip .i_close:hover { background: var(--color-surface-hover); color: var(--color-text-primary); }
.chip .i_close svg { width: 0.875em; height: 0.875em; }


/* SOURCE: components/card.css */
/* ─────────────────────────────────────────────
   CARD — SLUR Design System × slur-guidelines
   기본형은 1px 테두리 + 은은한 그림자.
   변형은 m_flat / m_elevated / m_link,
   내부 구조는 i_head / i_body / i_foot.
   내부 여백은 rem 토큰(텍스트와 함께 확대).
   ───────────────────────────────────────────── */

.card { display: flex; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); flex-direction: column; overflow: hidden; box-shadow: var(--shadow-sm); }
.card.m_flat { box-shadow: none; }
.card.m_elevated { box-shadow: var(--shadow-md); }

/* 내부 구조 */
.card .i_head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-12); padding: var(--space-20) var(--space-20) 0; }
.card .i_body { padding: var(--space-16) var(--space-20); }
.card .i_foot { display: flex; gap: var(--space-8); padding: var(--space-16) var(--space-20); border-top: 1px solid var(--color-border-subtle); }
.card .i_title { font-size: var(--text-lg); font-weight: var(--weight-semibold); }
.card .i_desc { font-size: var(--text-sm); color: var(--color-text-secondary); }

/* 인터랙티브(링크) 카드 */
.card.m_link { padding: var(--space-16); text-decoration: none; color: var(--color-text-primary); cursor: pointer; transition: box-shadow var(--duration-base) var(--ease-standard), border-color var(--duration-base) var(--ease-standard), transform var(--duration-base) var(--ease-standard); }
.card.m_link:hover { border-color: var(--color-border-default); box-shadow: var(--shadow-md); transform: translateY(-2px); }

/* 통계(KPI) 카드 — 대시보드 숫자 한 개. i_head(라벨+아이콘) / i_value / i_delta.
   증감 표시는 새 규칙 대신 badge(m_success/m_danger)를 i_delta 안에 조합한다 */
.card.m_stat { padding: var(--space-20); gap: var(--space-8); }
.card.m_stat .i_head { padding: 0; }
.card.m_stat .i_label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); }
.card.m_stat .i_icon { display: inline-flex; color: var(--color-text-muted); }
.card.m_stat .i_icon svg { width: 1.125em; height: 1.125em; }
.card.m_stat .i_value { font-size: var(--text-3xl); font-weight: var(--weight-bold); line-height: 1.1; letter-spacing: var(--tracking-tight); font-variant-numeric: tabular-nums; }
.card.m_stat .i_delta { display: flex; align-items: center; gap: var(--space-8); font-size: var(--text-xs); color: var(--color-text-muted); }

/* 리스트 카드 — 행 단위 hover */
.card.m_list { padding: var(--space-4); }
.card .i_row { display: flex; align-items: center; gap: var(--space-12); padding: var(--space-8) var(--space-12); border-radius: var(--radius-8); cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard); }
.card .i_row:hover { background: var(--color-surface-hover); }


/* SOURCE: components/alert.css */
/* ─────────────────────────────────────────────
   ALERT — SLUR Design System × slur-guidelines
   기본형은 정보(brand). 색은 m_success/m_warning/m_danger,
   형태는 m_inline(한 줄) / m_banner(액션 포함).
   여백은 rem 토큰(텍스트와 함께 확대).
   ───────────────────────────────────────────── */

.alert { display: flex; gap: var(--space-12); padding: var(--space-12) var(--space-16); border: 1px solid var(--color-brand); border-radius: var(--radius-8); background: var(--color-brand-soft); }
.alert .i_icon { display: inline-flex; margin-top: 1px; color: var(--color-text-brand); flex: none; }
.alert .i_icon svg { width: 1.25em; height: 1.25em; }
.alert .i_close svg { width: 1.125em; height: 1.125em; }
.alert .i_body { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.alert .i_title { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.alert .i_text { font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--color-text-secondary); }
.alert .i_close { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: none; border-radius: var(--radius-8); background: transparent; color: var(--color-text-muted); cursor: pointer; flex: none; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.alert .i_close:hover { background: var(--color-surface-hover); color: var(--color-text-primary); }

/* 색상 변형 */
.alert.m_success { border-color: var(--color-success); background: var(--color-success-soft); }
.alert.m_success .i_icon { color: var(--color-success); }
.alert.m_warning { border-color: var(--color-warning); background: var(--color-warning-soft); }
.alert.m_warning .i_icon { color: var(--color-warning); }
.alert.m_danger { border-color: var(--color-danger); background: var(--color-danger-soft); }
.alert.m_danger .i_icon { color: var(--color-danger); }

/* 인라인 — 한 줄, 테두리 없음 */
.alert.m_inline { align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); border: none; font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-brand); }
.alert.m_inline.m_success { color: var(--color-success); }
.alert.m_inline.m_warning { color: var(--color-warning); }
.alert.m_inline.m_danger { color: var(--color-danger); }
.alert.m_inline .i_icon { margin-top: 0; color: currentColor; }

/* 배너 — 가로 정렬 + 액션 버튼 */
.alert.m_banner { align-items: center; gap: var(--space-12); }
.alert.m_banner .i_icon { margin-top: 0; }
.alert.m_banner .btn { height: 2rem; padding: 0 var(--space-12); flex: none; }


/* SOURCE: components/navigation.css */
/* ─────────────────────────────────────────────
   NAVIGATION — SLUR Design System × slur-guidelines
   탭(tab_menu), 사이드바(nav_side), 브레드크럼(breadcrumb).
   활성은 data-state="active", 필 탭은 m_pill.
   탭은 i_list(role=tablist) > i_tab(role=tab) + i_panel(role=tabpanel)이 한 세트 —
   방향키 이동(roving tabindex)은 slur.js(tabs). 현재 페이지 링크는
   aria-current="page"(표준 속성)도 정본으로 인정한다.
   여백은 rem 토큰(텍스트와 함께 확대).
   ───────────────────────────────────────────── */

/* 탭 — 밑줄(기본) */
.tab_menu .i_list { display: flex; gap: var(--space-4); border-bottom: 1px solid var(--color-border-subtle); list-style: none; }
.tab_menu .i_tab { margin-bottom: -1px; padding: var(--space-8) var(--space-12); border: none; border-bottom: 2px solid transparent; background: none; color: var(--color-text-secondary); cursor: pointer; transition: color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard); }
.tab_menu .i_tab:hover { color: var(--color-text-primary); }
.tab_menu .i_tab[data-state="active"] { border-bottom-color: var(--color-brand); font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.tab_menu .i_panel { display: none; padding-top: var(--space-16); }
.tab_menu .i_panel[data-state="active"] { display: block; }

/* 탭 — 필 변형 */
.tab_menu.m_pill .i_list { display: inline-flex; padding: var(--space-4); border-bottom: none; border-radius: var(--radius-full); background: var(--color-surface-hover); }
.tab_menu.m_pill .i_tab { margin-bottom: 0; padding: var(--space-4) var(--space-16); border-bottom: none; border-radius: var(--radius-full); transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.tab_menu.m_pill .i_tab[data-state="active"] { background: var(--color-surface-card); font-weight: var(--weight-medium); color: var(--color-text-primary); box-shadow: var(--shadow-xs); }

/* 사이드바 */
.nav_side { display: flex; padding: var(--space-8); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); flex-direction: column; gap: 2px; box-shadow: var(--shadow-sm); }
.nav_side .i_group { padding: var(--space-8) var(--space-12) var(--space-4); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-wide); color: var(--color-text-muted); text-transform: uppercase; }
.nav_side .i_item { display: flex; align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); border-radius: var(--radius-8); font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--color-text-secondary); text-decoration: none; cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.nav_side .i_item:hover { background: var(--color-surface-hover); }
.nav_side .i_item[data-state="active"], .nav_side .i_item[aria-current="page"] { background: var(--color-brand-soft); font-weight: var(--weight-semibold); color: var(--color-text-brand); }
.nav_side .i_item .i_label { flex: 1; }
.nav_side .i_divider { height: 1px; margin: var(--space-8) var(--space-4); background: var(--color-border-subtle); }

/* 브레드크럼 */
.breadcrumb { display: flex; align-items: center; gap: var(--space-8); font-size: var(--text-sm); color: var(--color-text-secondary); }
.breadcrumb .i_link { color: var(--color-text-secondary); text-decoration: none; transition: color var(--duration-fast) var(--ease-standard); }
.breadcrumb .i_link:hover { color: var(--color-text-primary); }
.breadcrumb .i_sep { color: var(--color-text-muted); }
.breadcrumb .i_current { font-weight: var(--weight-medium); color: var(--color-text-primary); }


/* SOURCE: components/table.css */
/* ─────────────────────────────────────────────
   TABLE — SLUR Design System × slur-guidelines
   table_wrap(카드형 래퍼) + table_data(테이블).
   숫자 열은 m_num(tabular-nums), 정렬 헤더는 m_sort(안에 i_sort 버튼).
   정렬 상태의 정본은 th의 aria-sort="ascending|descending"(표준 속성) —
   data-state를 붙이지 않는다. 정렬 로직은 프로젝트(또는 TanStack Table 등)가
   하고, 표현은 aria-sort를 읽는 CSS가 한다. 페이지네이션은 pagination.css.
   셀 여백은 rem 토큰(텍스트와 함께 확대).
   ───────────────────────────────────────────── */

.table_wrap { border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); overflow: hidden; position: relative; box-shadow: var(--shadow-sm); }   /* position: relative — 표 안 a11y_hidden(absolute) 같은 절대 배치 자손을 래퍼 안에 가둔다(없으면 모바일에서 문서가 가로로 밀린다) */
/* 좁은 화면 — 표 자체를 줄이지 않고 가로 스크롤. 열을 숨기는 선택은 페이지가 한다 */
.table_wrap .i_scroll, .table_wrap .i_body { overflow-x: auto; }
.table_wrap .i_foot { display: flex; align-items: center; justify-content: space-between; padding: var(--space-12) var(--space-16); border-top: 1px solid var(--color-border-subtle); }
.table_wrap .i_count { font-size: var(--text-xs); color: var(--color-text-muted); }
.table_wrap .i_btn_wrap { display: flex; gap: var(--space-4); }

.table_data { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.table_data th { padding: var(--space-12) var(--space-16); font-weight: var(--weight-semibold); color: var(--color-text-secondary); text-align: left; }
.table_data td { padding: var(--space-12) var(--space-16); }
.table_data thead tr { border-bottom: 1px solid var(--color-border-subtle); }
.table_data tbody tr { border-bottom: 1px solid var(--color-border-subtle); transition: background-color var(--duration-fast) var(--ease-standard); }
.table_data tbody tr:hover { background: var(--color-surface-hover); }
.table_data tbody tr:last-child { border-bottom: none; }

/* 열 변형 */
.table_data .m_num { font-variant-numeric: tabular-nums; text-align: right; }
.table_data td.m_muted { color: var(--color-text-muted); }

/* 정렬 헤더 — th 여백을 버튼이 대신 채워 헤더 전체가 클릭 영역 */
.table_data th.m_sort { padding: 0; }
.table_data .i_sort { display: inline-flex; align-items: center; gap: var(--space-4); width: 100%; padding: var(--space-12) var(--space-16); border: none; background: transparent; font: inherit; color: inherit; text-align: inherit; cursor: pointer; user-select: none; transition: color var(--duration-fast) var(--ease-standard); }
.table_data .i_sort:hover { color: var(--color-text-primary); }
.table_data .i_sort svg { width: 1em; height: 1em; flex: none; opacity: 0.4; transition: opacity var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-standard); }
.table_data th[aria-sort] .i_sort { color: var(--color-text-primary); }
.table_data th[aria-sort] .i_sort svg { opacity: 1; }
.table_data th[aria-sort="descending"] .i_sort svg { transform: rotate(180deg); }
.table_data th.m_num .i_sort { justify-content: flex-end; }

/* 셀 내부 요소 */
.table_data .i_user { display: flex; align-items: center; gap: var(--space-8); font-weight: var(--weight-medium); color: var(--color-text-primary); }
.table_data .i_avatar { display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; border-radius: 50%; background: var(--color-brand-soft); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-text-brand); flex: none; }


/* SOURCE: components/modal.css */
/* ─────────────────────────────────────────────
   MODAL — SLUR Design System × slur-guidelines
   블록은 modal_dialog. 1순위는 네이티브 <dialog class="modal_dialog"> +
   showModal() — 배경 inert·Esc·포커스 복귀·최상위 레이어를 브라우저가 준다.
   상태 정본은 [open](네이티브) — data-state를 붙이지 않는다. 배경 딤은
   ::backdrop. 열림 모션은 @starting-style + allow-discrete(Safari 17.4+,
   미지원이면 모션만 생략). <dialog>를 못 쓰는 커스텀 오버레이는
   div.modal_dialog + data-state="open|close"(대안, 아래)로 유지한다.
   <dialog>는 자신이 블록이자 카드라 i_wrap 없이 i_head/i_body/i_foot을 직접 둔다.
   모달이 열려 있는 동안 토스트는 띄우지 않는다(ux-states.md — dialog 바깥은 inert).
   내부 여백은 rem 토큰. 다이얼로그 폭은 레이아웃 값(px).
   ───────────────────────────────────────────── */

/* 1순위 — 네이티브 dialog. UA 기본(가운데 정렬·최상위 레이어)을 그대로 쓰고 룩만 입힌다.
   가운데 정렬의 근거인 margin:auto는 전체 리셋이 지우므로 global.css가 dialog { margin: auto }로 복원한다 */
dialog.modal_dialog { width: calc(100% - 48px); max-width: 420px; padding: 0; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); color: inherit; box-shadow: var(--shadow-lg); opacity: 0; transform: scale(0.96) translateY(8px); transition: opacity var(--duration-base) var(--ease-standard), transform var(--duration-base) var(--ease-spring), display var(--duration-base) allow-discrete, overlay var(--duration-base) allow-discrete; }
dialog.modal_dialog[open] { opacity: 1; transform: none; }
dialog.modal_dialog::backdrop { background: var(--color-surface-overlay); opacity: 0; transition: opacity var(--duration-base) var(--ease-standard), display var(--duration-base) allow-discrete, overlay var(--duration-base) allow-discrete; }
dialog.modal_dialog[open]::backdrop { opacity: 1; }
@starting-style { dialog.modal_dialog[open] { opacity: 0; transform: scale(0.96) translateY(8px); } dialog.modal_dialog[open]::backdrop { opacity: 0; } }

/* 대안 — 커스텀 오버레이(div). 열림/닫힘은 data-state, 배경 inert·Tab 순환·포커스 복귀는 JS가 직접 */
div.modal_dialog { display: flex; align-items: center; justify-content: center; padding: var(--space-24); background: var(--color-surface-overlay); position: fixed; inset: 0; z-index: var(--z-overlay); opacity: 0; pointer-events: none; transition: opacity var(--duration-base) var(--ease-standard); }
div.modal_dialog[data-state="open"] { opacity: 1; pointer-events: auto; }
div.modal_dialog .i_wrap { width: 100%; max-width: 420px; border: 1px solid var(--color-border-subtle); border-radius: var(--radius-12); background: var(--color-surface-card); box-shadow: var(--shadow-lg); opacity: 0; transform: scale(0.96) translateY(8px); transition: transform var(--duration-base) var(--ease-spring), opacity var(--duration-base) var(--ease-standard); }
div.modal_dialog[data-state="open"] .i_wrap { opacity: 1; transform: scale(1) translateY(0); }

/* 내부 구조 — 두 방식 공통 */
.modal_dialog .i_head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-12); padding: var(--space-20) var(--space-20) 0; }
.modal_dialog .i_title { font-size: var(--text-lg); font-weight: var(--weight-semibold); }
.modal_dialog .i_text { font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--color-text-secondary); }
.modal_dialog .i_body { padding: var(--space-16) var(--space-20) 0; }
.modal_dialog .i_close { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border: none; border-radius: var(--radius-8); background: transparent; color: var(--color-text-muted); cursor: pointer; flex: none; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.modal_dialog .i_close:hover { background: var(--color-surface-hover); color: var(--color-text-primary); }
.modal_dialog .i_close svg { width: 1.125em; height: 1.125em; }
.modal_dialog .i_foot { display: flex; justify-content: flex-end; gap: var(--space-8); margin-top: var(--space-8); padding: var(--space-20); }


/* SOURCE: components/toast.css */
/* ─────────────────────────────────────────────
   TOAST — SLUR Design System × slur-guidelines
   블록은 toast_message, 노출은 data-state="show|close".
   컨테이너는 페이지 블록 밖(body 직계)에 미리 두고(라이브 영역 선존재) 텍스트만 바꾼다 —
   role="status"(기본, 자동 소멸) / role="alert"(긴급, 수동 닫기)는 각각 별도 컨테이너.
   숨김은 display:none이 아니라 opacity·transform·pointer-events — 컨테이너가 항상
   렌더돼 있어야 다음 알림이 보조 기술에 읽힌다. 안의 글·버튼은 show일 때만 노출한다
   (visibility — 보이지 않는 닫기 버튼에 Tab이 닿지 않게).
   위치는 화면 하단 중앙 한 곳 — status/alert 모두 같은 자리(강도 차이는 role과 자동 소멸 여부뿐,
   위치를 강도에 묶지 않는다: 알림 자리가 한 곳이어야 찾는다 — WCAG 3.2.4 일관된 식별).
   m_top은 레이아웃 사유 전용 — 하단에 고정 탭바·푸터·FAB가 있어 토스트가 포커스된 요소를
   가릴 때(WCAG 2.4.11) status/alert 컨테이너를 함께 위로 옮긴다. z-index는 토큰(toast 600).
   큐·자동 소멸·닫기·모달 중 대기는 slur.js(toast)가 담당한다.
   모달이 열려 있는 동안에는 띄우지 않는다(ux-states.md 토스트 절).
   색 변형 m_success / m_warning / m_danger — 이름은 alert와 같다.
   ───────────────────────────────────────────── */

.toast_message { display: flex; align-items: center; gap: var(--space-12); width: max-content; max-width: min(420px, calc(100vw - 32px)); padding: var(--space-12) var(--space-16); border-radius: var(--radius-8); background: var(--color-surface-inverse); font-size: var(--text-sm); color: var(--color-text-inverse); position: fixed; bottom: 24px; left: 50%; z-index: var(--z-toast); box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none; transform: translate(-50%, 8px); transition: opacity var(--duration-base) var(--ease-standard), transform var(--duration-base) var(--ease-standard); }
.toast_message[data-state="show"] { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }

/* 내용 — show가 아닐 때는 접근성 트리에서도 숨긴다. 사라질 때는 페이드가 끝난 뒤 숨긴다 */
.toast_message .i_icon, .toast_message .i_text, .toast_message .i_close { visibility: hidden; transition: visibility 0s linear var(--duration-base); }
.toast_message[data-state="show"] .i_icon, .toast_message[data-state="show"] .i_text, .toast_message[data-state="show"] .i_close { visibility: visible; transition-delay: 0s; }

.toast_message .i_icon { display: inline-flex; flex: none; }
.toast_message .i_icon svg { width: 1.125em; height: 1.125em; }
.toast_message .i_text { flex: 1; line-height: var(--leading-normal); }
.toast_message .i_close { display: inline-flex; align-items: center; justify-content: center; width: 1.75rem; height: 1.75rem; margin: -0.25rem -0.5rem -0.25rem 0; border: none; border-radius: var(--radius-4); background: transparent; color: inherit; cursor: pointer; flex: none; opacity: 0.7; transition: visibility 0s linear var(--duration-base), opacity var(--duration-fast) var(--ease-standard); }
.toast_message[data-state="show"] .i_close { transition-delay: 0s; }
.toast_message .i_close:hover { opacity: 1; }
.toast_message .i_close svg { width: 1em; height: 1em; }

/* 강도·의미 — 긴급(alert) 컨테이너는 위험색 아이콘, 정적 변형은 m_ */
.toast_message[role="alert"] .i_icon { color: var(--color-danger-on-inverse); }
.toast_message.m_success .i_icon { color: var(--color-success-on-inverse); }
.toast_message.m_warning .i_icon { color: var(--color-warning-on-inverse); }
.toast_message.m_danger .i_icon { color: var(--color-danger-on-inverse); }

/* 위치 변형 — 상단(레이아웃 사유 전용: 하단이 탭바·푸터·FAB로 막힐 때, 두 컨테이너 모두에) */
.toast_message.m_top { top: 24px; bottom: auto; transform: translate(-50%, -8px); }
.toast_message.m_top[data-state="show"] { transform: translate(-50%, 0); }


/* SOURCE: components/state.css */
/* ─────────────────────────────────────────────
   STATE — SLUR Design System × slur-guidelines
   4상태(loading / empty / error / success)의 "룩"을 담당한다.
   "언제 보이나"(노출 전환)는 common.css의 4상태 스위치가 블록의 data-state를
   읽어 처리하고, 여기는 "어떻게 보이나"만. 안내문 셋은 항상 렌더되는
   i_status(role="status") 상자 안에 있다 — 상자 자체에는 스타일 없음.
   · 슬롯 기본형 — 문장만 넣은 i_loading/i_empty/i_error의 여백·색 (global.css와 같은 [data-state] 예외)
   · empty_state — 빈/에러 안내 패널(i_empty·i_error 슬롯 안에, 아이콘+제목+설명+행동)
   · spinner     — 진행 중 표시. i_loading 기본형은 「spinner + 불러오는 중…」(문장 옆) · 버튼 안 · 단독
   · skeleton    — 로딩 자리표시의 선택지(표·카드 목록처럼 모양이 정해진 넓은 영역; 뼈대 행은 페이지 CSS가 짠다)
   i_loading에는 읽힐 문장을 하나 둔다(스켈레톤만이면 보조 기술에 읽히지 않음 — a11y_hidden 가능).
   치수는 rem/em(텍스트와 함께 확대), 값은 시맨틱 토큰만.
   ───────────────────────────────────────────── */

/* 슬롯 기본형 — 문장만 넣었을 때의 모양(여백·글자). 내용물의 배치는 강제하지 않는다 —
   스켈레톤 줄·empty_state 패널을 넣으면 그대로 블록으로 쌓인다. 문장 옆 스피너는 인라인(.spinner). */
[data-state] > .i_status > .i_loading, [data-state] > .i_status > .i_empty, [data-state] > .i_status > .i_error { padding: var(--space-16); font-size: var(--text-sm); line-height: var(--leading-normal); text-align: center; color: var(--color-text-secondary); }
[data-state] > .i_status > .i_error { color: var(--color-danger); }

/* 빈 상태 패널 — 아이콘 + 제목 + 설명 + 행동(선택). 에러는 m_error */
.empty_state { display: flex; max-width: 360px; margin: 0 auto; padding: var(--space-24) var(--space-16); flex-direction: column; align-items: center; gap: var(--space-8); text-align: center; }
.empty_state .i_icon { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; margin-bottom: var(--space-8); border-radius: var(--radius-full); background: var(--color-surface-sunken); color: var(--color-text-muted); }
.empty_state .i_icon svg { width: 1.5rem; height: 1.5rem; }
.empty_state .i_title { font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--color-text-primary); }
.empty_state .i_text { font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--color-text-secondary); }
.empty_state .i_action { display: flex; gap: var(--space-8); margin-top: var(--space-12); flex-wrap: wrap; justify-content: center; }
.empty_state.m_error .i_icon { background: var(--color-danger-soft); color: var(--color-danger); }
.empty_state.m_compact { padding: var(--space-16); }
.empty_state.m_compact .i_icon { width: 2.5rem; height: 2.5rem; margin-bottom: 0; }

/* 스켈레톤 — 한 줄이 기본(텍스트 한 줄 높이). 형태는 m_, 너비는 자리에 맞춰 페이지가 정한다.
   모션은 이동하는 반짝임이 아니라 숨 쉬듯 느린 펄스(투명도) — 산만하지 않고, 무한 반복에 가감속 곡선을 걸어 생기는 멈칫거림이 없다 */
.skeleton { display: block; width: 100%; height: 1em; border-radius: var(--radius-4); background: var(--color-border-subtle); animation: skeleton_pulse 1.8s ease-in-out infinite; }
.skeleton.m_title { height: 1.5em; }
.skeleton.m_circle { width: 2.5rem; height: 2.5rem; border-radius: 50%; flex: none; }
.skeleton.m_rect { height: 8rem; border-radius: var(--radius-8); }
.skeleton.m_inline { display: inline-block; width: 6em; vertical-align: middle; }
@keyframes skeleton_pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* 스피너 — 텍스트 옆이면 em(글자 크기 따라감), 단독 큰 표시는 m_large. 장식이면 aria-hidden */
.spinner { display: inline-block; width: 1.25em; height: 1.25em; border: 2px solid var(--color-border-subtle); border-top-color: var(--color-brand); border-radius: 50%; vertical-align: -0.3em; flex: none; animation: spinner_spin 0.8s linear infinite; }
.spinner.m_large { width: 2.5rem; height: 2.5rem; border-width: 3px; }
@keyframes spinner_spin { to { transform: rotate(360deg); } }

/* 조합 — 버튼 로딩 중에는 현재 글자색으로 도는 작은 스피너(button.css의 opacity·pointer-events와 함께) */
.btn .spinner { width: 1em; height: 1em; border-color: transparent; border-top-color: currentColor; }

/* prefers-reduced-motion은 global.css가 animation을 끈다 — 스피너·스켈레톤은 정지된 모양으로 남는다. */


/* SOURCE: components/menu.css */
/* ─────────────────────────────────────────────
   MENU — SLUR Design System × slur-guidelines
   menu_action: 행 액션(⋯)·더보기 같은 앱 동작 메뉴(role="menu").
   열고 닫기·Esc·바깥 클릭·최상위 레이어는 네이티브 popover="auto"가
   담당하므로 JS가 없다. 상태 정본은 :popover-open(네이티브) —
   data-state를 붙이지 않는다. 트리거 기준 위치 계산과 방향키 이동은
   slur.js(menu). 사이트 내비게이션에는 쓰지 않는다(role="menu" 금지).
   ───────────────────────────────────────────── */

/* display는 :popover-open에만 — 기본 규칙에 두면 UA의 [popover]:not(:popover-open) { display: none }을 덮어써
   닫힌 메뉴가 투명한 채 남아 그 자리의 클릭을 가로챈다(Safari는 포커스도 숨은 항목에 남는다) */
.menu_action { min-width: 180px; margin: 0; padding: var(--space-4); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-8); background: var(--color-surface-card); position: fixed; inset: auto; flex-direction: column; box-shadow: var(--shadow-md); opacity: 0; transform: translateY(-4px); transition: opacity var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-standard), display var(--duration-fast) allow-discrete, overlay var(--duration-fast) allow-discrete; }
.menu_action:popover-open { display: flex; opacity: 1; transform: none; }
@starting-style { .menu_action:popover-open { opacity: 0; transform: translateY(-4px); } }

.menu_action .i_item { display: flex; align-items: center; gap: var(--space-8); width: 100%; padding: var(--space-8) var(--space-12); border: none; border-radius: var(--radius-4); background: transparent; font-size: var(--text-sm); font-weight: normal; line-height: var(--leading-normal); color: var(--color-text-primary); text-align: left; text-decoration: none; cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard); }
.menu_action .i_item:hover, .menu_action .i_item:focus-visible { background: var(--color-surface-hover); }
.menu_action .i_item:disabled, .menu_action .i_item[aria-disabled="true"] { color: var(--color-text-muted); cursor: not-allowed; }
.menu_action .i_item svg { width: 1.125em; height: 1.125em; color: var(--color-text-muted); flex: none; }
.menu_action .i_item.m_danger { color: var(--color-danger); }
.menu_action .i_item.m_danger svg { color: inherit; }
.menu_action .i_shortcut { margin-left: auto; padding-left: var(--space-12); font-size: var(--text-xs); color: var(--color-text-muted); }
.menu_action .i_group { padding: var(--space-8) var(--space-12) var(--space-4); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: var(--color-text-muted); }
.menu_action .i_divider { height: 1px; margin: var(--space-4) 0; background: var(--color-border-subtle); }


/* SOURCE: components/tooltip.css */
/* ─────────────────────────────────────────────
   TOOLTIP — SLUR Design System × slur-guidelines
   tooltip_help: 보조 설명 한 줄(role="tooltip"). 트리거와
   aria-describedby로 연결하고 popover="manual"로 최상위 레이어에 띄운다
   (popover="hint"는 WebKit 26.5에서야 지원 — 이전 Safari를 위해 manual 유지). 상태 정본은
   :popover-open — data-state 없음. 호버·포커스·Esc·위치는 slur.js(tooltip).
   안에 버튼·링크를 넣지 않는다 — 그건 팝오버/다이얼로그다.
   ───────────────────────────────────────────── */

/* display는 :popover-open에만(menu.css와 같은 이유) */
.tooltip_help { max-width: 240px; margin: 0; padding: var(--space-4) var(--space-8); border: none; border-radius: var(--radius-4); background: var(--color-surface-inverse); font-size: var(--text-xs); line-height: var(--leading-normal); color: var(--color-text-inverse); position: fixed; inset: auto; overflow: visible; opacity: 0; pointer-events: none; transition: opacity var(--duration-fast) var(--ease-standard), display var(--duration-fast) allow-discrete, overlay var(--duration-fast) allow-discrete; }
.tooltip_help:popover-open { display: block; opacity: 1; pointer-events: auto; }
@starting-style { .tooltip_help:popover-open { opacity: 0; } }


/* SOURCE: components/pagination.css */
/* ─────────────────────────────────────────────
   PAGINATION — SLUR Design System × slur-guidelines
   pagination: 이전/다음 + 페이지 목록. 현재 페이지의 정본은
   aria-current="page"(표준 속성) — data-state를 붙이지 않는다.
   페이지가 URL이면 a, 상태 전환이면 button — 둘 다 같은 룩.
   테이블 하단(table_wrap .i_foot)이나 목록 아래에 둔다.
   ───────────────────────────────────────────── */

.pagination { display: flex; align-items: center; gap: var(--space-4); }
.pagination .i_list { display: flex; gap: var(--space-4); list-style: none; }
.pagination .i_page, .pagination .i_prev, .pagination .i_next { display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; padding: 0 var(--space-8); border: 1px solid transparent; border-radius: var(--radius-8); background: transparent; font-size: var(--text-sm); font-variant-numeric: tabular-nums; color: var(--color-text-secondary); text-decoration: none; cursor: pointer; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
.pagination .i_page:hover, .pagination .i_prev:hover, .pagination .i_next:hover { background: var(--color-surface-hover); color: var(--color-text-primary); }
.pagination .i_page[aria-current="page"] { border-color: var(--color-border-default); background: var(--color-surface-card); font-weight: var(--weight-semibold); color: var(--color-text-primary); box-shadow: var(--shadow-xs); }
.pagination .i_prev:disabled, .pagination .i_next:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.pagination .i_prev svg, .pagination .i_next svg { width: 1.125em; height: 1.125em; }
.pagination .i_ellipsis { display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; color: var(--color-text-muted); }
