/* ══════════════════════════════════════════════════════════════════════════
   DECK — ui.css · 레이아웃 프리미티브 + 부품
   tokens.css 뒤에 읽는다. 여기 어떤 규칙도 --p-* 를 직접 쓰지 않는다.

   구성
     A. 기반(reset·타이포·접근성)
     B. 레이아웃 프리미티브 — stack / cluster / grid-auto / split / shell
     C. 부품 — panel · btn · field · pill · kpi · table · toast · nav · modal
   도메인 부품(정산 원장·번호판 카드 등)은 여기 없다 — 프로젝트 층 CSS 가 담당한다.
   이 파일은 어떤 업무도 알지 못한다: 새 프로젝트는 이 파일을 그대로 복사한다.

   반응형 원칙: **화면 폭이 아니라 자기 칸의 폭**으로 판단한다(컨테이너 쿼리).
   부품은 어디에 놓이든 스스로 맞춘다 — 페이지가 부품 사정을 알 필요가 없다.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── A. 기반 ─────────────────────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--c-canvas);color:var(--c-text);
  font:var(--fs-base)/var(--lh) var(--p-ff-sans);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  /* 한글은 낱글자 사이 어디서나 줄이 바뀌어 "프로젝\n트"처럼 단어가 쪼개진다.
     keep-all 로 어절 단위로 끊는다(2026-08-01 실측 — 모바일에서 특히 심했다).
     영문 URL·긴 식별자는 대신 안 넘치도록 overflow-wrap 을 함께 준다. */
  word-break:keep-all;
  overflow-wrap:anywhere;
}
/* 코드·표는 어절 규칙을 적용하지 않는다 — 원문 그대로 보여야 한다 */
code,kbd,pre,.mono,.num,.tbl{word-break:normal;overflow-wrap:normal}
h1,h2,h3,h4{margin:0;text-wrap:balance;line-height:1.2;font-weight:var(--p-fw-bold)}
h1{font-size:var(--fs-2xl);letter-spacing:-.02em}
h2{font-size:var(--fs-xl);letter-spacing:-.015em}
h3{font-size:var(--fs-lg)}
p{margin:0}
a{color:var(--c-accent);text-underline-offset:3px}
:where(button,input,select,textarea){font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--c-focus);outline-offset:2px;border-radius:var(--r-1)}
.mono,code,kbd{font-family:var(--p-ff-mono);font-variant-numeric:tabular-nums}
.num{font-family:var(--p-ff-mono);font-variant-numeric:tabular-nums}
/* 화면에 안 보이되 스크린리더는 읽는 라벨 */
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
                       transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* ── B. 레이아웃 프리미티브 ──────────────────────────────────────────────
   이름이 곧 의도다. margin 을 쓰지 않고 gap 으로만 띄운다(상쇄·중복 방지).
   ────────────────────────────────────────────────────────────────────────── */
.stack{display:flex;flex-direction:column;gap:var(--gap,var(--sp-4));min-width:0}
.cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--gap,var(--sp-3));min-width:0}
.split{display:flex;align-items:center;gap:var(--gap,var(--sp-3));min-width:0}
.split > .grow{flex:1;min-width:0}
.push{margin-left:auto}
/* 칸 최소폭만 정하면 열 수는 스스로 정한다. 하나뿐이면 폭을 채운다(auto-fit). */
.grid-auto{display:grid;gap:var(--gap,var(--sp-4));
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--col,260px)),1fr))}
.center{margin-inline:auto;width:100%;max-width:var(--max,1180px);padding-inline:var(--sp-5)}
.scroll-x{overflow-x:auto;overscroll-behavior-x:contain}
.fill{flex:1;min-width:0}

/* 앱 셸 — 3단 적응 네비 (§105 v4 결정본, 2026-08-03 2단 720 → 3단 600·1008).
   같은 마크업(.nav a = 아이콘+라벨)이 폭에 따라 형태만 바꾼다:
     ≥1008px   확장 레일 240px — WinUI Expanded(1008) · M3 expanded rail 220~360dp
               · 실무 폭 군집 200~320px(Ant 200·Carbon 256·Atlassian 320)
     600~1007  아이콘 레일 72px — M3 collapsed rail · WinUI LeftCompact(641~1007)
     <600px    하단 바 — M3 "Compact 는 항상 navigation bar" (3~5 항목)
   셸이 분할 화면·시뮬레이터처럼 **한 칸 안에** 들어가면 부모에 `.shell-box` 를
   준다 — 같은 경계를 칸 폭으로 판정한다(뷰포트·칸 중 좁은 쪽이 이긴다).
   ⚠ 컨테이너 쿼리는 content-box 기준 — .shell-box 요소 자신에 border/padding 을
   주면 경계가 그만큼 민다(§105 실측: border 1px 로 1008 경계가 1006 이 됐다). */
.shell{display:grid;min-height:100%;grid-template-columns:auto 1fr;grid-template-areas:"nav main"}
.shell > .nav{grid-area:nav}
.shell > .main{grid-area:main;min-width:0;display:flex;flex-direction:column}
.shell-box{container-type:inline-size}
@media (max-width:599px){
  .shell{grid-template-columns:1fr;grid-template-rows:1fr auto;
         grid-template-areas:"main" "nav"}
}
@container (max-width:599px){
  .shell{grid-template-columns:1fr;grid-template-rows:1fr auto;
         grid-template-areas:"main" "nav"}
}

/* ── C. 부품 ─────────────────────────────────────────────────────────────── */

/* 패널 — 제목 바 + 내용. 모든 정보 블록의 기본 단위 */
.panel{background:var(--c-surface);border:1px solid var(--c-line);border-radius:var(--r-3);
       display:flex;flex-direction:column;min-width:0;container-type:inline-size}
.panel > header{display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-3) var(--panel-pad);border-bottom:1px solid var(--c-line)}
.panel > header::before{content:"";width:3px;height:12px;border-radius:2px;
  background:var(--tone,var(--c-accent));flex:none}
.panel > header h3{font-size:var(--fs-sm);font-weight:var(--p-fw-bold);
  color:var(--tone,var(--c-accent));letter-spacing:.02em}
.panel > .body{padding:var(--panel-pad);display:flex;flex-direction:column;
  gap:var(--sp-3);min-width:0}
.panel[data-tone="ok"]{--tone:var(--c-ok)} .panel[data-tone="warn"]{--tone:var(--c-warn)}
.panel[data-tone="crit"]{--tone:var(--c-crit)} .panel[data-tone="info"]{--tone:var(--c-info)}
/* 도메인 톤(device/server 등)은 프로젝트 층이 같은 방식으로 덧붙인다 */

/* 라벨 — 작은 대문자 표식 */
.label{font:var(--p-fw-medium) var(--fs-micro)/1 var(--p-ff-mono);color:var(--c-text-3);
  letter-spacing:.09em;text-transform:uppercase}

/* 버튼 — variant는 data-속성으로(클래스 폭발 방지) */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-2);
  height:var(--ctl-h);padding-inline:var(--ctl-px);border-radius:var(--r-2);
  border:1px solid var(--c-line-strong);background:var(--c-surface-2);color:var(--c-text);
  font-size:var(--fs-sm);font-weight:var(--p-fw-medium);cursor:pointer;white-space:nowrap;
  transition:background var(--p-dur-1) var(--p-ease),border-color var(--p-dur-1) var(--p-ease)}
.btn:hover:not(:disabled){background:var(--c-surface-3)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn[data-variant="primary"]{background:var(--c-accent-bg);border-color:var(--c-accent-line);
  color:var(--c-accent)}
.btn[data-variant="danger"]{background:transparent;border-color:var(--c-crit);color:var(--c-crit)}
.btn[data-variant="ghost"]{background:transparent;border-color:transparent;color:var(--c-text-2)}
.btn[data-variant="ghost"]:hover:not(:disabled){background:var(--c-surface-2);color:var(--c-text)}
.btn .ic{width:1.05em;height:1.05em;fill:currentColor;flex:none}

/* 입력 */
.field{display:flex;flex-direction:column;gap:var(--sp-2);min-width:0}
.field > span{font-size:var(--fs-micro);color:var(--c-text-3)}
.field :where(input,select,textarea){height:var(--ctl-h);padding-inline:var(--sp-3);
  background:var(--c-surface-2);border:1px solid var(--c-line-strong);border-radius:var(--r-2);
  color:var(--c-text);min-width:0;width:100%}
.field textarea{height:auto;padding-block:var(--sp-3);resize:vertical}
.field[data-invalid] :where(input,select,textarea){border-color:var(--c-crit)}
.field .hint{font-size:var(--fs-micro);color:var(--c-text-3)}
.field[data-invalid] .hint{color:var(--c-crit)}

/* 상태 알약 — 색만으로 구분하지 않고 점·글자를 함께 (색각·저조도 대비) */
.pill{display:inline-flex;align-items:center;gap:var(--sp-2);
  padding:2px var(--sp-3);border-radius:var(--r-full);
  border:1px solid currentColor;background:var(--tone-bg,transparent);
  font:var(--p-fw-bold) var(--fs-micro)/1.6 var(--p-ff-mono);white-space:nowrap}
.pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
.pill[data-tone="ok"]{color:var(--c-ok);--tone-bg:var(--c-ok-bg)}
.pill[data-tone="warn"]{color:var(--c-warn);--tone-bg:var(--c-warn-bg)}
.pill[data-tone="crit"]{color:var(--c-crit);--tone-bg:var(--c-crit-bg)}
.pill[data-tone="info"]{color:var(--c-info);--tone-bg:var(--c-info-bg)}
.pill[data-tone="idle"]{color:var(--c-text-3)}

/* KPI 타일 — 값이 주인공, 라벨은 보조, 추세는 배경 */
.kpi{position:relative;display:flex;flex-direction:column;gap:1px;justify-content:center;
  padding:var(--sp-3) var(--sp-4);background:var(--c-surface);border:1px solid var(--c-line);
  border-radius:var(--r-2);min-width:0;overflow:hidden}
.kpi::before{content:"";position:absolute;inset:0 0 auto;height:2px;
  background:var(--tone,var(--c-accent));opacity:.8}
.kpi .label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.kpi b{font:var(--p-fw-bold) var(--fs-num)/1.15 var(--p-ff-mono);
  font-variant-numeric:tabular-nums}
.kpi[data-tone="warn"]{--tone:var(--c-warn)} .kpi[data-tone="crit"]{--tone:var(--c-crit)}
.kpi[data-tone="ok"]{--tone:var(--c-ok)}     .kpi[data-tone="info"]{--tone:var(--c-info)}
.kpi[data-state="alarm"] b{color:var(--c-crit)}
.kpi .spark{position:absolute;inset:auto 0 0;height:38%;opacity:.5;pointer-events:none}

/* 표 — 가로 스크롤은 표만, 페이지는 절대 안 밀린다 */
.table-wrap{overflow-x:auto;border:1px solid var(--c-line);border-radius:var(--r-3)}
table.tbl{border-collapse:collapse;width:100%;min-width:480px;font-size:var(--fs-sm)}
.tbl th,.tbl td{text-align:left;padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--c-line);vertical-align:top}
.tbl thead th{position:sticky;top:0;background:var(--c-surface-2);z-index:1;
  font:var(--p-fw-medium) var(--fs-micro)/1.4 var(--p-ff-mono);
  letter-spacing:.06em;text-transform:uppercase;color:var(--c-text-3)}
.tbl tbody tr:last-child td{border-bottom:0}
.tbl tbody tr:hover{background:var(--c-surface-2)}
.tbl .n{text-align:right;font-family:var(--p-ff-mono);font-variant-numeric:tabular-nums}

/* 알림(토스트) — 화면 우하단에 쌓인다 */
.toast-host{position:fixed;right:var(--sp-5);bottom:var(--sp-5);z-index:60;
  display:flex;flex-direction:column;gap:var(--sp-3);max-width:min(460px,88vw)}
.toast{display:flex;gap:var(--sp-3);align-items:flex-start;padding:var(--sp-4) var(--sp-5);
  background:var(--c-surface-2);border:1px solid var(--c-line-strong);
  border-left:4px solid var(--tone,var(--c-info));border-radius:var(--r-2);
  box-shadow:var(--c-shadow);animation:toast-in var(--p-dur-2) var(--p-ease)}
.toast[data-tone="ok"]{--tone:var(--c-ok)} .toast[data-tone="warn"]{--tone:var(--c-warn)}
.toast[data-tone="crit"]{--tone:var(--c-crit)}
.toast b{display:block;font-size:var(--fs-sm)}
.toast span{color:var(--c-text-2);font-size:var(--fs-sm)}
@keyframes toast-in{from{transform:translateY(8px);opacity:0}to{transform:none;opacity:1}}

/* 네비게이션 — 3단 (셸 주석 참조). 기본 = 확장 레일(아이콘+라벨 가로) */
.nav{background:var(--c-surface);border-right:1px solid var(--c-line);
  display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-3);width:240px}
.nav a{display:flex;align-items:center;gap:var(--sp-3);min-width:0;
  padding:var(--sp-3);border-radius:var(--r-2);text-decoration:none;
  color:var(--c-text-3);font:var(--p-fw-medium) var(--fs-sm)/1.2 var(--p-ff-sans);
  white-space:nowrap;overflow:hidden}
.nav a .ic{width:18px;height:18px;fill:currentColor;flex:none}
.nav a:hover{background:var(--c-surface-2);color:var(--c-text)}
.nav a[aria-current="page"]{background:var(--c-accent-bg);color:var(--c-accent)}
/* 600~1007px: 아이콘 레일 — 아이콘 위·작은 라벨 아래 (M3 collapsed rail 도 라벨 동반) */
@media (max-width:1007px){
  .nav{width:72px}
  .nav a{flex-direction:column;align-items:center;gap:3px;padding:var(--sp-3) 2px;
    font:var(--p-fw-medium) var(--fs-micro)/1 var(--p-ff-mono)}
}
@container (max-width:1007px){
  .nav{width:72px}
  .nav a{flex-direction:column;align-items:center;gap:3px;padding:var(--sp-3) 2px;
    font:var(--p-fw-medium) var(--fs-micro)/1 var(--p-ff-mono)}
}
/* 접기 버튼 — 레일 **세로 중앙의 작은 원형 버튼**(2026-08-03 사용자 지정).
   메뉴 항목 사이에 끼우지 않고 레일 가장자리에 띄워 "메뉴가 아니라 손잡이"로 읽히게 한다.
   아이콘 레일·하단 바에서는 의미가 없어 감춘다(그 폭에서는 이미 최소 형태다). */
.nav{position:relative}
.nav .navtoggle{position:absolute;top:50%;right:-11px;translate:0 -50%;
  width:22px;height:22px;padding:0;border-radius:50%;
  border:1px solid var(--c-line-strong);background:var(--c-surface-2);
  color:var(--c-text-3);cursor:pointer;display:flex;align-items:center;
  justify-content:center;z-index:5;box-shadow:var(--c-shadow-sm)}
.nav .navtoggle > span{position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap}      /* 라벨은 보조기기 전용 */
.nav .navtoggle:hover{background:var(--c-surface-3);color:var(--c-text);
  border-color:var(--c-accent-line)}
.nav .navtoggle .ic{width:16px;height:16px;fill:currentColor;flex:none;
  transition:transform var(--p-dur-2) var(--p-ease)}
/* 아이콘 레일·하단 바에는 접기 버튼이 없다. ⚠ 이 규칙은 위 기본 규칙보다
   **뒤에** 있어야 한다 — 같은 특이도(0,2,0)라 순서가 승자를 정한다. */
@media (max-width:1007px){ .nav .navtoggle{display:none} }
@container (max-width:1007px){ .nav .navtoggle{display:none} }
/* 접힘 상태 — 확장 레일 폭에서만 유효(600px 아래는 형태 자체가 다르다).
   ⚠ 미디어 가드 없이 쓰면 특이도가 높아 하단 바까지 72px 로 찌그러뜨린다
     (ui-system.md 함정: "형태를 바꾸는 분기에서는 이전 치수도 되돌린다"). */
@media (min-width:600px){
  :root[data-nav="mini"] .shell > .nav{width:72px}
  :root[data-nav="mini"] .shell > .nav a{
    flex-direction:column;align-items:center;gap:3px;padding:var(--sp-3) 2px;
    font:var(--p-fw-medium) var(--fs-micro)/1 var(--p-ff-mono)}
  /* 접힌 상태에서는 화살표가 반대(펼치기)를 가리킨다 */
  :root[data-nav="mini"] .shell > .nav .navtoggle .ic{transform:rotate(180deg)}
}
/* <600px: 하단 바 — 항상 보이게 화면 하단 고정(엄지 도달 범위) */
@media (max-width:599px){
  .nav{flex-direction:row;width:auto;border-right:0;border-top:1px solid var(--c-line);
       padding:var(--sp-2);gap:2px;position:sticky;bottom:0;z-index:30}
  .nav a{flex:1;padding:var(--sp-2) 0}
}
@container (max-width:599px){   /* .shell-box 안에 있을 때 — 위와 같은 결과 */
  .nav{flex-direction:row;width:auto;border-right:0;border-top:1px solid var(--c-line);
       padding:var(--sp-2);gap:2px;position:sticky;bottom:0;z-index:30}
  .nav a{flex:1;padding:var(--sp-2) 0}
}

/* 탭 — 국소 전환(패널 안에서만) */
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--c-line)}
.tabs button{background:none;border:0;border-bottom:2px solid transparent;cursor:pointer;
  padding:var(--sp-2) var(--sp-4);color:var(--c-text-3);
  font:var(--p-fw-medium) var(--fs-sm)/1.6 var(--p-ff-sans)}
.tabs button[aria-selected="true"]{color:var(--c-accent);border-bottom-color:var(--c-accent)}

/* 모달 — 되돌릴 수 없는 작업 앞에 선다 */
.modal{position:fixed;inset:0;z-index:70;display:none;align-items:center;justify-content:center;
  background:var(--c-overlay);padding:var(--sp-5)}
.modal[open]{display:flex}
.modal > .box{background:var(--c-surface);border:1px solid var(--c-line-strong);
  border-radius:var(--r-4);box-shadow:var(--c-shadow);max-width:min(520px,94vw);
  padding:var(--sp-6);display:flex;flex-direction:column;gap:var(--sp-4)}

/* 빈 상태 — "없음"도 설계 대상 */
.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--sp-2);padding:var(--sp-6);color:var(--c-text-3);text-align:center;
  font-size:var(--fs-sm)}

/* 값 묶음 — 라벨/값 쌍. 칸이 넓으면 2열, 좁으면 1열 (컨테이너 기준) */
.facts{display:grid;gap:var(--sp-2) var(--sp-5);grid-template-columns:1fr}
.facts > div{display:flex;gap:var(--sp-3);font-size:var(--fs-sm);min-width:0}
.facts > div > span:first-child{color:var(--c-text-3);flex:0 0 5.5em}
.facts > div > span:last-child{font-family:var(--p-ff-mono);min-width:0;
  overflow:hidden;text-overflow:ellipsis}
.facts .wide{grid-column:1/-1}
@container (min-width:420px){ .facts{grid-template-columns:1fr 1fr} }
