/* ================================================================
   팀 Claude CMS — nms-landing 파생 디자인 시스템 (다크/라이트 테마)
   표면·글래스 색을 변수화 → data-theme="dark|light" 로 전환.
   과한 애니메이션 없음(미세 hover/fade만).
   ================================================================ */
@font-face {
  font-family: "Pretendard";
  font-weight: 45 920; font-style: normal; font-display: swap;
  src: url("/fonts/PretendardVariable.woff2") format("woff2-variations");
}

/* ── 공통(테마 무관) ── */
:root {
  --accent-from: #38bdf8;
  --accent-to: #6366f1;
  --accent: #38bdf8;  /* 브랜드 액센트 별칭 — var(--accent, …) 사용처가 외부 폴백색으로 새지 않게 */
  --ok: #10b981;
  --warn: #d97706;
  --err: #e11d48;
  --radius: 22px;
  --font: "Pretendard", system-ui, -apple-system, "Segoe UI", "Malgun Gothic", sans-serif;
  --mono: ui-monospace, "SF Mono", Consolas, "D2Coding", monospace;
  /* 콘텐츠 폭 상한 — 와이드 모니터에서 데이터 밀집 뷰가 남는 폭을 쓰도록 뷰포트에 따라 단계 상향.
     기본 1080(1280~1440 회귀 방지) → ≥1440 1280 → ≥1920 1560. 프로즈(.lead)는 별도 measure로 고정. */
  --view-max: 1080px;
}

/* ── 다크(기본) ── */
:root, :root[data-theme="dark"] {
  color-scheme: dark;
  --background: #05060a; --surface: #0b0e16; --foreground: #e8eaf0; --muted: #98a1b3; --faint: #7b8494;
  --border: rgba(255,255,255,0.10); --border-soft: rgba(255,255,255,0.06);
  --hover: rgba(255,255,255,0.05); --hover-2: rgba(255,255,255,0.09);
  --input-bg: rgba(255,255,255,0.04); --input-bg-focus: rgba(255,255,255,0.06);
  --glass-bg: rgba(255,255,255,0.045); --glass-strong-bg: rgba(12,16,26,0.66);
  --glass-border: rgba(255,255,255,0.10); --glass-strong-border: rgba(255,255,255,0.12);
  --glass-inset: rgba(255,255,255,0.08);
  --glass-shadow: 0 24px 70px -30px rgba(0,0,0,0.75);
  --glass-strong-shadow: 0 20px 50px -24px rgba(0,0,0,0.8);
  --grid: rgba(255,255,255,0.028);
  --code-bg: rgba(0,0,0,0.30); --ta-bg: rgba(0,0,0,0.25); --ta-bg-focus: rgba(0,0,0,0.30);
  --switch-off: rgba(255,255,255,0.12); --scroll-thumb: rgba(255,255,255,0.12);
  --mesh-1: rgba(56,189,248,0.22); --mesh-2: rgba(124,58,237,0.20); --mesh-3: rgba(236,72,153,0.12);
  --ok-bg: rgba(16,185,129,0.12); --warn-bg: rgba(217,119,6,0.14); --err-bg: rgba(225,29,72,0.14);
  --ok-bd: rgba(16,185,129,0.35); --warn-bd: rgba(217,119,6,0.35); --err-bd: rgba(225,29,72,0.35);
}

/* ── 라이트 ── */
:root[data-theme="light"] {
  color-scheme: light;
  --background: #eef1f7; --surface: #ffffff; --foreground: #141a26; --muted: #5b6576; --faint: #737c8e;
  --border: rgba(15,20,35,0.12); --border-soft: rgba(15,20,35,0.07);
  --hover: rgba(15,20,35,0.05); --hover-2: rgba(15,20,35,0.09);
  --input-bg: rgba(15,20,35,0.03); --input-bg-focus: rgba(15,20,35,0.05);
  --glass-bg: rgba(255,255,255,0.62); --glass-strong-bg: rgba(255,255,255,0.84);
  --glass-border: rgba(15,20,35,0.10); --glass-strong-border: rgba(15,20,35,0.12);
  --glass-inset: rgba(255,255,255,0.7);
  --glass-shadow: 0 24px 60px -30px rgba(20,30,60,0.28);
  --glass-strong-shadow: 0 20px 46px -24px rgba(20,30,60,0.22);
  --grid: rgba(15,20,35,0.045);
  --code-bg: rgba(15,20,35,0.05); --ta-bg: rgba(15,20,35,0.035); --ta-bg-focus: rgba(15,20,35,0.05);
  --switch-off: rgba(15,20,35,0.16); --scroll-thumb: rgba(15,20,35,0.20);
  --mesh-1: rgba(56,189,248,0.18); --mesh-2: rgba(124,58,237,0.13); --mesh-3: rgba(236,72,153,0.09);
  --ok-bg: rgba(16,185,129,0.12); --warn-bg: rgba(217,119,6,0.14); --err-bg: rgba(225,29,72,0.12);
  --ok-bd: rgba(16,185,129,0.4); --warn-bd: rgba(217,119,6,0.4); --err-bd: rgba(225,29,72,0.35);
}

* { box-sizing: border-box; border-color: var(--border); }
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
body {
  margin: 0; min-height: 100vh; background: var(--background); color: var(--foreground);
  font-family: var(--font); font-size: 14px; line-height: 1.55; overflow-x: hidden;
  /* 한국어는 기본 word-break 로 **글자 단위**로 끊긴다 — '표준정책' 이 '표준정 / 책' 이 되고
   * '에이전트' 가 '에이전 / 트' 가 된다. 좁은 칸(사이드바·뱃지·카드 제목·탭)에서 항상 나온다.
   * keep-all 은 띄어쓰기 단위로만 끊는다.
   *   종전엔 이 규칙이 `.between > :first-child` 한 곳에만 있었다(아래 주석이 문제를 이미
   *   진단해 놓았다). 원인이 전역인데 처방이 국소라, 고친 자리 밖에서는 그대로 깨져 있었다.
   * break-word 를 함께 두는 이유: keep-all 만 두면 띄어쓰기 없는 긴 토큰(경로·URL·해시)이
   * 칸을 뚫고 나간다. anywhere 가 아니라 break-word 인 것은 의도다 — anywhere 는 min-content
   * 계산까지 바꿔 flex/grid 폭이 예기치 않게 줄어든다. */
  word-break: keep-all; overflow-wrap: break-word;
  transition: background .25s, color .25s;
}

/* 정적 메시 배경 */
.bg { position: fixed; inset: 0; z-index: -10; pointer-events: none; overflow: hidden; background: var(--background); }
.bg::before {
  content: ""; position: absolute; inset: -20%;
  background:
    radial-gradient(38vw 38vw at 12% 8%, var(--mesh-1), transparent 70%),
    radial-gradient(40vw 40vw at 88% 14%, var(--mesh-2), transparent 70%),
    radial-gradient(42vw 42vw at 50% 100%, var(--mesh-3), transparent 70%);
  filter: blur(30px);
}
.bg::after {
  content: ""; position: absolute; inset: 0;
  background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, #000 30%, transparent 100%);
  mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, #000 30%, transparent 100%);
}

/* 글래스 */
.glass {
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(140%);
  box-shadow: inset 0 1px 0 0 var(--glass-inset), var(--glass-shadow); border-radius: var(--radius);
}
.glass-strong {
  background: var(--glass-strong-bg); border: 1px solid var(--glass-strong-border);
  backdrop-filter: blur(28px) saturate(150%); -webkit-backdrop-filter: blur(28px) saturate(150%);
  box-shadow: inset 0 1px 0 0 var(--glass-inset), var(--glass-strong-shadow); border-radius: var(--radius);
}
.text-gradient { background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hairline { height: 1px; background: linear-gradient(90deg, transparent, var(--border), transparent); }

h1,h2,h3 { margin: 0; font-weight: 680; letter-spacing: -0.01em; }
.muted { color: var(--muted); }
.mono { font-family: var(--mono); }

/* ── 버튼 시스템 (통일) ──
   한 가지 규칙만 기억: 색은 여기 정의된 변형(primary·ghost·danger·success·warn)만 쓴다.
   뷰에서 인라인 style 로 버튼 색을 직접 칠하지 말 것 — 색이 제각각이 되는 원인이다.
   기본 = 중립(테두리+은은한 배경) · primary = 강조(그라디언트 채움) · ghost = 최소(투명)
   danger/success/warn = 의미색, 평소 테두리·글자만, hover 시 옅게 채움. */
button, .btn {
  font: inherit; cursor: pointer; border: 1px solid var(--border); background: var(--hover);
  color: var(--foreground); border-radius: 12px; padding: 8px 14px; font-weight: 550;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; line-height: 1.25;
  transition: background .15s, border-color .15s, opacity .15s, color .15s;
}
button:hover, .btn:hover { background: var(--hover-2); }
button.primary, .btn.primary { border: 0; color: #fff; font-weight: 650; background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); box-shadow: 0 10px 30px -12px rgba(99,102,241,0.6); }
button.primary:hover, .btn.primary:hover { opacity: .92; }
button.ghost, .btn.ghost { background: transparent; border-color: var(--border-soft); }
button.ghost:hover, .btn.ghost:hover { background: var(--hover); }
button.danger, .btn.danger { color: var(--err); border-color: var(--err-bd); background: transparent; }
button.danger:hover, .btn.danger:hover { color: var(--err); background: var(--err-bg); border-color: var(--err); }
button.success, .btn.success { color: var(--ok); border-color: var(--ok-bd); background: transparent; }
button.success:hover, .btn.success:hover { color: var(--ok); background: var(--ok-bg); border-color: var(--ok); }
button.warn, .btn.warn { color: var(--warn); border-color: var(--warn-bd); background: transparent; }
button.warn:hover, .btn.warn:hover { color: var(--warn); background: var(--warn-bg); border-color: var(--warn); }
/* 작은 버튼(툴바·표 안) · 아이콘 전용 버튼 — 크기만 다르고 색 규칙은 위와 동일 */
button.sm, .btn.sm { padding: 4px 10px; font-size: 12px; border-radius: 9px; }
button.icon, .btn.icon { padding: 6px 9px; }
button:disabled, .btn:disabled { opacity: .4; cursor: not-allowed; }

input, select, textarea {
  font: inherit; color: var(--foreground); background: var(--input-bg);
  border: 1px solid var(--border); border-radius: 12px; padding: 9px 12px; width: 100%;
  /* width:100% 만으로는 flex/grid 안에서 안 줄어든다 — 폼 요소는 고유 최소폭(size 기본값 ≈180px)을
   * 갖고, flex/grid 아이템의 자동 최소 크기가 그걸 바닥으로 삼기 때문이다. 2열 폼(.wk-form·.si-form)이
   * 좁아지면 입력칸이 칸을 뚫고 나간다. */
  min-width: 0;
  transition: border-color .15s, background .15s;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: rgba(99,102,241,0.7); background: var(--input-bg-focus); }
/* textarea 기본 resize는 both — 가로로 끌면 모달/카드 경계를 뚫고 나간다. 세로만 허용 + 폭 상한. */
textarea { resize: vertical; max-width: 100%; }
/* select는 불투명 배경 강제 — 반투명(--input-bg)을 주면 브라우저가 네이티브 흰 바탕 위에 합성해
   다크 모드에서 셀렉트/드롭다운이 하얗게 떠서 안 보인다. */
select { background-color: var(--surface); }
select option { background: var(--surface); color: var(--foreground); }
label { display: block; font-size: 12px; color: var(--muted); margin: 0 0 6px; }
.field { margin-bottom: 14px; }

/* 포커스 링. input:focus 가 outline:none 을 걸므로 같은 특이도(0,1,1)로 뒤에 와야 이긴다 — 순서 고정. */
:focus-visible { outline: 2px solid var(--accent-from); outline-offset: 2px; }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent-from); outline-offset: 1px; }
/* 뷰가 재렌더될 때 포커스 중이던 버튼이 통째로 사라지면(disable/역할변경 등 성공 후 viewX() 재호출)
   브라우저가 포커스를 랜드마크(main/body)로 떨어뜨린다 — 그 랜드마크는 전체 화면 크기라 화면
   전체를 감싸는 거대한 파란 테두리로 보인다. 랜드마크 자체는 시각 표시 대상이 아니므로 끈다
   (실제 버튼·입력 등 인터랙티브 요소의 링은 위 규칙대로 그대로 유지). */
#main:focus-visible, #app:focus-visible, body:focus-visible, html:focus-visible { outline: none; }

.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; padding: 2px 9px; border-radius: 999px; border: 1px solid var(--border); }
.badge.ok { color: var(--ok); border-color: var(--ok-bd); background: var(--ok-bg); }
.badge.bad { color: var(--err); border-color: var(--err-bd); background: var(--err-bg); }
.badge.warn { color: var(--warn); border-color: var(--warn-bd); background: var(--warn-bg); }
.badge.role { text-transform: uppercase; letter-spacing: .06em; font-size: 10px; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.ok { background: var(--ok); } .dot.warn { background: var(--warn); } .dot.err { background: var(--err); }

/* 로그인 */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.login { width: 100%; max-width: 380px; padding: 34px 30px; }
.login .brand { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.login .brand .logo { width: 34px; height: 34px; border-radius: 10px; background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); }
.login h1 { font-size: 20px; } .login .sub { color: var(--muted); font-size: 13px; margin: 6px 0 22px; }
.login .err { color: var(--err); font-size: 13px; min-height: 18px; margin-top: 4px; }

/* 셸 */
.shell { display: grid; grid-template-columns: 248px 1fr; grid-template-rows: 58px 1fr; height: 100vh; height: 100dvh; }
.topbar { grid-column: 1 / -1; display: flex; align-items: center; flex-wrap: wrap; gap: 14px; min-height: 58px; padding: 8px 20px; border-bottom: 1px solid var(--border-soft); }
.topbar .logo { width: 26px; height: 26px; border-radius: 8px; background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); }
.topbar h1 { font-size: 15px; } .topbar .spacer { flex: 1; } .topbar .who { font-size: 13px; color: var(--muted); }
.topbar h1 button { font: inherit; color: inherit; background: transparent; border: 0; padding: 0; border-radius: 6px; cursor: pointer; }
.topbar h1 button:hover { background: transparent; opacity: .85; }
/* 넓은 화면에서는 사이드바가 항상 보여 필요 없다 — 좁은 화면 @media 에서만 노출. */
.menuBtn, .sidebar-close { display: none; }
/* 데스크톱 사이드바 레일 접기 토글 — 그룹 목록 위, 나브 항목과 같은 좌우 리듬(전체폭)으로 맞춰
   눈에 띄고 클릭 타깃도 넉넉하게. 테두리는 .ghost의 --border-soft로는 배경 대비 ~1.1~1.15:1로
   거의 안 보인다 — 일반 --border(0.10/0.12 alpha)도 ~1.27~1.28:1로 여전히 약해, foreground를
   섞어(투명 위 50%) 다크 ~4.6:1·라이트 ~3.2:1까지 끌어올린다(WCAG 1.4.11 비텍스트 대비
   권장 3:1 충족, 토큰 기반·하드코딩 색 없음). 과한 실선은 아니고 "또렷한 테두리" 선에서 멈춘다.
   ⚠ 실제 마크업은 class="ghost sidebar-rail-toggle" — 단일 클래스 셀렉터(0,1,0)는
   button.ghost(0,1,1)에 명시도로 밀려 border-color가 전혀 안 먹혔다(이전 시도가 "달라진 게
   없다"고 보였던 원인). button.sidebar-rail-toggle로 명시도를 (0,1,1) 동률까지 올리고,
   button.ghost보다 뒤에 선언해 소스순서로 이긴다. 좁은 화면(드로어)에선 숨긴다(아래 @media). */
button.sidebar-rail-toggle { width: 100%; height: 36px; padding: 0; margin-bottom: 6px;
  border-radius: 12px; font-size: 13px; line-height: 1; color: var(--muted);
  border-color: color-mix(in srgb, var(--foreground) 50%, transparent); }
button.sidebar-rail-toggle:hover { color: var(--foreground); }
.sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 150; background: rgba(0,0,0,.45); opacity: 0; transition: opacity .2s ease; }
.sidebar-backdrop.show { display: block; opacity: 1; }
.sidebar { border-right: 1px solid var(--border-soft); padding: 16px 12px; display: flex; flex-direction: column; gap: 4px; overflow: auto; }
/* .nav 은 <button> — button 규칙의 background/border/padding/justify-content 를 반드시 되돌려야 한다.
   (통일 버튼이 justify-content:center 라, 안 되돌리면 사이드바 항목이 가운데로 몰린다.) */
.nav { display: flex; align-items: center; justify-content: flex-start; gap: 11px; width: 100%; text-align: left; font: inherit; font-weight: 550;
  padding: 10px 12px; border: 0; border-radius: 12px; background: transparent; cursor: pointer; color: var(--muted);
  transition: background .15s, color .15s; }
.nav:hover { background: var(--hover); color: var(--foreground); }
.nav.active { background: var(--hover-2); color: var(--foreground); box-shadow: inset 2px 0 0 0 var(--accent-from); }
.nav .ic { width: 18px; text-align: center; opacity: .85; }
.nav-note { margin-top: auto; font-size: 11px; color: var(--muted); padding: 10px 12px; line-height: 1.5; }
/* 사이드바 업무별 그룹 — 접이식 소제목(버튼) + 그 아래 항목 스택 */
.nav-group { display: flex; flex-direction: column; gap: 4px; }
.nav-group + .nav-group { margin-top: 14px; }
/* .nav-group-title 은 <button> — 통일 버튼 규칙(배경/테두리/정렬/패딩)을 되돌린다. */
.nav-group-title { display: flex; align-items: center; justify-content: flex-start; gap: 6px; width: 100%; text-align: left; font: inherit;
  font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted);
  padding: 2px 12px 3px; border: 0; background: transparent; cursor: pointer; border-radius: 8px; transition: color .15s; }
.nav-group-title:hover { color: var(--foreground); }
.nav-group-title .caret { font-size: 9px; opacity: .8; transition: transform .15s ease; }
.nav-group.collapsed .nav-group-title .caret { transform: rotate(-90deg); }
/* 라이트 테마: --muted(≈5.2:1)가 소제목엔 흐림 — foreground/muted 혼합으로 대비만 상향(≈7.8:1), 다크는 불변 */
:root[data-theme="light"] .nav-group-title { color: color-mix(in srgb, var(--foreground) 35%, var(--muted) 65%); }
.nav-group-items { display: flex; flex-direction: column; gap: 4px; }
.nav-group.collapsed .nav-group-items { display: none; }

/* 데스크톱 아이콘 레일 — 사이드바 전체를 접어 아이콘만 남긴다(그룹 개별 접힘과는 별개 축).
   좁은 화면(오프캔버스 드로어)에는 관여하지 않게 데스크톱 폭에서만 적용. */
@media (min-width: 861px) {
  .shell.rail { grid-template-columns: 64px 1fr; }
  .shell.rail .sidebar { padding: 16px 8px; }
  /* 버튼이 width:100%라 좁아진 사이드바 폭에 자동으로 맞춰진다 — 별도 정렬 규칙 불필요. */
  .shell.rail .nav { justify-content: center; padding: 10px 0; gap: 0; }
  .shell.rail .nav .lbl, .shell.rail .nav-group-title, .shell.rail .nav-note { display: none; }
  /* 레일 모드에선 그룹 개별 접힘 상태와 무관하게 아이콘을 전부 보여준다 — 소제목이 없어 펼 수단이 없다. */
  .shell.rail .nav-group.collapsed .nav-group-items { display: flex; }
}

.main { overflow: auto; padding: 24px 28px; }
.view { animation: fade .18s ease; max-width: var(--view-max); }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.view h2 { font-size: 20px; margin-bottom: 4px; }
/* 프로즈는 뷰가 넓어져도 글줄이 과도하게 길어지지 않게 measure(≈62ch)로 고정 — 데이터 뷰만 넓어진다. */
.view .lead { color: var(--muted); margin-bottom: 20px; max-width: 62ch; }
/* 카드 안 설명 문단도 같은 이유로 measure를 고정 — 표/코드블록(자체 스크롤 컨테이너)은 대상 아님. */
.card p { max-width: 65ch; }

/* ── 와이드 디스플레이 — 콘텐츠 폭 단계 상향 ──
   1280~1440 구간은 손대지 않는다(기본 1080 유지, 회귀 방지). 그 위부터만 상한을 키운다.
   .grid/.stat-row/table 은 유동이라 뷰가 넓어지면 자동으로 폭을 더 쓴다(데이터 밀집 뷰 목적).
   실제 사용 가능한 콘텐츠 폭은 (뷰포트 − 사이드바 248 − .main 패딩 56)이라, 상한이 그보다 크면
   유동으로 채우고 상한이 작으면 상한에서 멈춰 과도한 글줄을 막는다. */
@media (min-width: 1440px) { :root, :root[data-theme="dark"], :root[data-theme="light"] { --view-max: 1280px; } }
@media (min-width: 1920px) { :root, :root[data-theme="dark"], :root[data-theme="light"] { --view-max: 1560px; } }

.grid { display: grid; gap: 16px; }
.grid.cols-3 { grid-template-columns: repeat(3, 1fr); } .grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.card { padding: 18px 20px; } .tile { padding: 18px 20px; }
.tile .k { font-size: 12px; color: var(--muted); }
.tile .v { font-size: 26px; font-weight: 720; margin-top: 6px; letter-spacing: -0.02em; }
.tile .s { font-size: 12px; color: var(--muted); margin-top: 4px; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border-soft); }
th { color: var(--muted); font-weight: 550; font-size: 12px; }
tr:last-child td { border-bottom: 0; }
/* 좁은 열에서 CJK 버튼 라벨("삭제" 등)이 한 글자씩 세로로 꺾이는 것 방지 */
table button { white-space: nowrap; }

/* 차트/표 컨테이너 — charts.js·usageobs 가 "자체 가로 스크롤 컨테이너"로 전제하는 래퍼.
   시계열은 열(날짜·시간 버킷)이 많아 카드보다 넓어질 수 있다. 이 규칙이 없으면 표가
   카드·뷰포트 밖으로 넘쳐 나간다(계열 행이 화면 밖으로 빠지던 원인). 넘칠 때만 이 안에서
   가로 스크롤하고, 안의 표는 짜부되지 않게 자연 폭을 쓰되 최소 카드 폭은 채운다. */
.chart-wrap { max-width: 100%; overflow-x: auto; overflow-y: hidden; }
.chart-wrap > table { width: max-content; min-width: 100%; }

.split { display: grid; grid-template-columns: 300px 1fr; gap: 16px; align-items: start; }
.list { padding: 8px; max-height: calc(100vh - 200px); overflow: auto; }
.list .group { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); padding: 10px 12px 6px; }
/* .item 은 <button> — 내부는 phrasing content(span)만 둘 것. */
.list .item { display: block; width: 100%; text-align: left; font: inherit; color: inherit;
  padding: 9px 12px; border: 0; border-radius: 10px; background: transparent; cursor: pointer; }
.list .item:hover { background: var(--hover); }
.list .item.active { background: var(--hover-2); box-shadow: inset 2px 0 0 0 var(--accent-from); }
.list .item .id { font-weight: 600; display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
/* ⚠ text-overflow 는 **블록 컨테이너의 인라인 콘텐츠**에만 적용된다. display:flex 인 요소에
 * 걸면 아무 일도 일어나지 않는다 — 이름이 길어도 '…' 없이 그냥 잘리고, 안에 있던 뱃지
 * (번들 · 파일수)는 통째로 사라진다. 종전이 그 상태였다.
 * 이름만 별도 블록(.t)으로 감싸 거기에 말줄임을 걸고, 뱃지는 줄어들지 않게 둔다. */
.list .item .id .nm { display: flex; align-items: center; gap: 8px; min-width: 0; }
.list .item .id .nm > .t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list .item .id .badge { flex: none; }
.list .item .id .badge.files { color: var(--muted); font-weight: 500; }

/* 팩 파일 트리(팩 관리 · 발행) — 종전엔 스타일이 **하나도 없어서** 클릭·호버·선택이 화면에
   드러나지 않았다(무엇을 열었는지 알 수 없었다). .list .item 과 같은 언어로 맞춘다. */
.pm-tree { font-size: 13px; }
.pm-row { display: flex; align-items: center; gap: 7px; min-width: 0;
  padding: 5px 8px; border-radius: 8px; line-height: 1.35; }
/* flex 아이템은 기본 min-width:auto 라 콘텐츠 최소폭 아래로 줄지 않는다 —
 * min-width:0 이 없으면 말줄임이 발동하지 못하고 형제 요소를 밀어낸다. */
.pm-row .nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pm-row .tw { flex: none; width: 12px; text-align: center; color: var(--faint); font-size: 10px;
  transition: transform 120ms ease; }
.pm-row .ic { flex: none; width: 14px; text-align: center; color: var(--faint); font-size: 11px; }
.pm-row .sz { flex: none; margin-left: auto; font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }
.pm-row .badge { flex: none; font-size: 10px; padding: 1px 7px; }
/* 디렉터리 = 접기 토글(버튼 역할). 파일 = 열기. 둘 다 커서·호버·포커스가 보여야 한다. */
.pm-row.dir, .pm-row.file { cursor: pointer; }
.pm-row.dir { font-weight: 600; color: var(--foreground); }
.pm-row.dir.open > .tw { transform: rotate(90deg); }
.pm-row.file { color: var(--muted); }
.pm-row.dir:hover, .pm-row.file:hover { background: var(--hover); }
.pm-row.file:hover { color: var(--foreground); }
.pm-row:focus-visible { outline: 2px solid var(--accent-from); outline-offset: -2px; }
/* 지금 열려 있는 파일 — 어느 파일을 편집 중인지가 트리에서 즉시 보인다. */
.pm-row.file.sel { background: var(--hover-2); color: var(--foreground); font-weight: 600;
  box-shadow: inset 2px 0 0 0 var(--accent-from); }
.pm-row.file.sel .sz, .pm-row.file.sel .ic { color: var(--muted); }
/* 엔진(읽기 전용) 디렉터리는 한 번만 표시하고, 그 안의 파일마다 배지를 반복하지 않는다. */
.pm-row.ro { color: var(--faint); }
.pm-tree .empty { padding: 10px 8px; color: var(--muted); font-size: 12px; }

.editor-panel { padding: 0; overflow: hidden; display: flex; flex-direction: column; min-height: 420px; }
.editor-panel .bar { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border-soft); }
.editor-panel .bar .path { font-family: var(--mono); font-size: 12px; color: var(--muted); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.editor-panel .bar button { flex: 0 0 auto; white-space: nowrap; }
.editor-panel textarea { flex: 1; border: 0; border-radius: 0; background: var(--ta-bg); font-family: var(--mono); font-size: 13px; line-height: 1.65; padding: 16px; resize: vertical; min-height: 300px; }
.editor-panel textarea:focus { background: var(--ta-bg-focus); }
.valid { padding: 10px 16px; border-top: 1px solid var(--border-soft); font-size: 12px; }
.valid .err { color: var(--err); } .valid .warn { color: var(--warn); } .valid .good { color: var(--ok); }

.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/*
 * 카드 헤더 — 제목과 액션.
 *
 * 예전엔 제목·배지·버튼을 .row(flex-wrap) 에 형제로 늘어놓았다. 그러면 줄바꿈 지점이 제목
 * 길이에 따라 카드마다 달라져, 어떤 카드는 버튼 4개가 한 줄이고 어떤 카드는 2개만 다음 줄로
 * 떨어진다(실측 스크린샷). 목록에서 그게 나란히 보이면 레이아웃이 깨진 것처럼 읽힌다.
 *
 * 그래서 두 칸 그리드로 고정한다: 제목은 남는 폭을 갖고 자유롭게 줄바꿈하고,
 * 액션 묶음은 통째로 오른쪽에 남는다 — 제목이 아무리 길어도 버튼은 흩어지지 않는다.
 */
.card-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 10px; }
.card-head > .ch-title { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.card-head > .ch-actions { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; justify-self: end; }
/* 좁은 화면에선 한 칸으로 접고 액션을 왼쪽 정렬 — 가로 스크롤을 만들지 않는다. */
@media (max-width: 640px) {
  .card-head { grid-template-columns: minmax(0, 1fr); }
  .card-head > .ch-actions { justify-self: start; flex-wrap: wrap; }
}

.between { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/*
 * .between 의 제목이 글자 중간에서 끊기던 문제.
 *   ① min-width:0 이 없으면 flex 항목이 콘텐츠 최소폭 아래로 줄지 못해 배지를 밀어낸다.
 *   ② 한국어는 기본 word-break 로 어느 글자에서나 끊긴다 — '표준정책 정 / 책' 이 그 결과다.
 *      keep-all 로 띄어쓰기 단위로만 끊는다.
 *   ③ 배지·버튼은 줄어들면 안 된다(내용이 잘린다).
 */
.between > :first-child { min-width: 0; word-break: keep-all; overflow-wrap: anywhere; }
.between > .badge, .between > .help, .between > button, .between > a { flex-shrink: 0; }
.mt { margin-top: 16px; } .mb { margin-bottom: 12px; }
/* .toggle 은 role="switch" <button> — button 의 배경/테두리/hover 를 되돌린다. */
.toggle { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; padding: 3px; border: 0; background: transparent; border-radius: 999px; }
.toggle:hover { background: transparent; }
.toggle:disabled { cursor: default; }
.switch { width: 40px; height: 22px; border-radius: 999px; background: var(--switch-off); position: relative; transition: background .15s; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; transition: left .15s; box-shadow: 0 1px 3px rgba(0,0,0,0.3); }
.switch.on { background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); }
.switch.on::after { left: 20px; }

pre.code { background: var(--code-bg); border: 1px solid var(--border-soft); border-radius: 12px; padding: 14px; overflow: auto; font-family: var(--mono); font-size: 12px; color: var(--foreground); }
/* 저장 전 미리보기는 서버가 만드는 실제 결과가 아니므로 흐리게 — 미저장 배지와 한 쌍으로 쓴다. */
pre.code.stale { opacity: .5; }

/* 스킬 폴더 트리 */
.tree-box { margin: 0 0 10px; border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--code-bg); }
.tree-head { padding: 8px 12px; font-size: 12px; font-weight: 600; border-bottom: 1px solid var(--border); background: var(--hover); }
.tree-body { max-height: 240px; overflow: auto; }
.tree-row { display: flex; justify-content: space-between; gap: 12px; width: 100%; text-align: left; color: inherit;
  padding: 5px 12px; font-family: var(--mono); font-size: 12px; background: transparent;
  border: 0; border-top: 1px solid var(--border-soft); border-radius: 0; }
.tree-row:first-child { border-top: 0; }
.tree-row.md { cursor: pointer; }
.tree-row.md:hover { background: var(--hover); }
.tree-row .tf { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-row .ts { color: var(--muted); white-space: nowrap; }

/* 페이지네이션 (감사 로그 · 버전 태그 공용) */
.pager { display: flex; justify-content: center; align-items: center; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.pager button { padding: 4px 10px; font-size: 12px; }

#toast { position: fixed; right: 20px; bottom: 20px; max-width: 440px; padding: 12px 16px; font-size: 13px; opacity: 0; transform: translateY(8px); transition: .2s; pointer-events: none; z-index: 100; }
#toast.show { opacity: 1; transform: none; }
#toast.ok { border-color: var(--ok-bd); } #toast.err { border-color: var(--err-bd); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 999px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

.hidden { display: none !important; }

/* ── 모달(중앙 팝업) ── */
.modal-overlay { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(0,0,0,0.5); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); opacity: 0; transition: opacity .15s ease; }
.modal-overlay.show { opacity: 1; }
/* 모달 높이 — 내용이 길면 뷰포트를 넘어 **위아래가 잘려나갔고 스크롤이 없어 읽을 방법이 없었다**.
   오버레이가 align-items:center 라 넘치는 만큼 위아래로 균등하게 사라진다 — 아래로만 넘치는 것보다
   나쁘다(스크롤로도 [닫기]에 닿을 수 없다).
   실측: 2026-08-03 세션 이어받기 노트 모달 3008px, 2026-08-04 같은 화면 2987px — 요약·다음단계·
   열린질문이 다 들어가는 화면이라 길어지는 게 정상이고, 그러니 화면 쪽이 아니라 여기서 접어야 한다.

   ⚠ 이 문제는 이미 한 번 국소 해결됐다: .tr-modal/.tr-modal-body(학습 과정)가 자기 접두 클래스로
   같은 것을 고쳤다. 공용 .modal 에는 없어서 generic 모달(core.js showModal/confirmDialog)을 쓰는
   화면마다 재발했다. 같은 증상을 화면마다 다시 고치지 않도록 **공용 자리에서** 막는다.

   상한은 오버레이 padding 20px×2 와 정확히 맞춘다. 100dvh 를 쓰는 이유는 모바일에서 주소창이
   접혔다 펴질 때 100vh 가 실제로 보이는 높이보다 커져 다시 잘리기 때문 — 미지원 브라우저용으로
   100vh 를 먼저 선언해 폴백으로 남긴다(순서가 곧 폴백이다).

   display:flex 는 **조건 없이** 건다(:has() 로 감싸지 않는다). 아래 `.modal > .modal-body` 의
   flex:1 1 auto / min-height:0 은 부모가 flex 일 때만 발동하므로, :has() 미지원 환경에서 본문
   스크롤이 통째로 죽는 일이 없어야 한다.
   .modal 자신의 overflow-y:auto 는 **본문 래퍼(.modal-body/.modal-sub)가 없는 모달**을 위한
   안전망이다. 래퍼가 있으면 자식이 flex 로 줄어들어 .modal 은 상한 안에 들어오므로 이 스크롤바는
   뜨지 않고(스크롤은 자식이 가져간다), 래퍼가 없으면 자식이 내용 높이로 버텨 넘치므로 여기서
   잡힌다 — 두 스크롤이 동시에 생기지 않는다. */
.modal { width: 100%; max-width: 460px; padding: 24px; transform: translateY(10px) scale(.985); transition: transform .15s ease;
  display: flex; flex-direction: column; max-height: calc(100vh - 40px); max-height: calc(100dvh - 40px); overflow-y: auto; }
.modal-overlay.show .modal { transform: none; }
/* min-height:0 이 없으면 flex 자식이 내용 높이로 버텨 overflow 가 발동하지 않는다.
   .modal-sub 도 함께 잡는다 — confirmDialog 는 본문 컨테이너 이름이 그쪽이다(core.js). */
.modal > .modal-body,
.modal > .modal-sub { overflow-y: auto; overflow-x: hidden; min-height: 0; flex: 1 1 auto; }
/* 버튼 줄은 접히지 않는다 — flex 기본값(shrink:1)이면 좁은 화면에서 눌린다.
   여백은 아래 `.modal .actions` 의 margin-top 이 이미 갖고 있다(중복 금지). */
.modal > .actions { flex: 0 0 auto; }
.modal h3 { margin: 0 0 4px; font-size: 18px; }
.modal .modal-sub { color: var(--muted); font-size: 13px; margin-bottom: 4px; }
.modal label { display: block; font-size: 12px; color: var(--muted); margin: 14px 0 6px; }
.modal .file-row { display: flex; align-items: center; gap: 10px; }
.modal .file-row button { flex: 0 0 auto; }
.modal .file-name { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.modal .note { font-size: 11.5px; color: var(--faint); margin-top: 12px; line-height: 1.55; }
.modal .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; }

/* 조직 학습 허브의 신호 필터 줄 —
   input/select 는 전역에서 width:100% 라 한 줄에 나란히 두려면 내용 폭으로 되돌린다. */
.lrn-filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.lrn-filters input, .lrn-filters select { width: auto; min-width: 150px; padding: 7px 10px; font-size: 13px; }

@media (max-width: 860px) {
  /* topbar 는 wrap 하므로 행 높이를 고정하면 잘린다 — auto 로 둘 것. 사이드바는 그리드 밖으로 빼서
     오프캔버스 드로어로 띄운다(고정 위치라 그리드 행을 차지하지 않음). */
  .shell { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .menuBtn { display: inline-flex; }
  /* 레일 접기는 데스크톱 전용 개념 — 드로어엔 이미 자체 닫기 버튼이 있다. */
  .sidebar-rail-toggle { display: none; }
  /* 그룹·항목은 데스크톱과 똑같이 세로 목록 그대로 — 좁은 화면에서만 열고 닫는 방식이 다를 뿐,
     "가로로 흘려서 잘라먹기"를 하지 않는다(이게 이전 버전의 문제였다). */
  .sidebar {
    position: fixed; inset: 0; z-index: 160; width: min(280px, 82vw);
    overflow-x: hidden; overflow-y: auto; background: var(--surface);
    box-shadow: 2px 0 24px rgba(0,0,0,.3); transform: translateX(-100%); transition: transform .2s ease;
  }
  .sidebar.open { transform: none; }
  .sidebar-close { display: flex; margin-bottom: 6px; }
  .split { grid-template-columns: 1fr; } .grid.cols-3, .grid.cols-2 { grid-template-columns: 1fr; }
  /* 스택 레이아웃에선 목록이 에디터를 화면 밖으로 밀어낸다. */
  .list { max-height: 46vh; }
  /* 좁은 화면: 필터는 한 줄에 하나씩, 구조도는 낮게. */
  .lrn-filters { width: 100%; }
  .lrn-filters input, .lrn-filters select { width: 100%; flex: 1 1 100%; }
}
/* ── SI 프로젝트 ──
   8단계 보드·타임라인은 신규 의존성 없이 CSS 로만 그린다(차트 라이브러리 없음).
   상태는 색만으로 구분하지 않는다 — 완료 ✓ · 진행 ▶ · 게이트 대기 ⚑ · 게이트 단계 ⚐.
   좁은화면 규칙은 이 섹션 끝의 @media 에 함께 둔다. */
.si-panel { text-align: center; padding: 36px 20px; }
.si-panel .ic { font-size: 30px; line-height: 1; }
.si-panel h3 { margin: 12px 0 6px; font-size: 16px; }
.si-panel p { color: var(--muted); font-size: 13px; margin: 0 auto; max-width: 580px; }

.si-summary { color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer; }
.si-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.si-proposal { min-height: 120px; font-family: var(--mono); font-size: 12.5px; line-height: 1.6; resize: vertical; }
.si-title { display: inline; font-size: 16px; }
.si-meta { font-size: 12px; white-space: nowrap; }

/* .si-link 는 <button> — button 규칙의 배경/테두리/패딩을 되돌린다(표 안의 링크처럼 보이게). */
.si-link { background: transparent; border: 0; padding: 0; font: inherit; font-weight: 650; color: var(--foreground);
  text-align: left; cursor: pointer; border-radius: 4px; }
.si-link:hover { background: transparent; color: var(--accent-from); text-decoration: underline; }
.si-card-pending { border-color: var(--warn-bd); }
.si-pend { color: var(--warn); }

/* 단계 보드 — .pending 은 .done/.cur 뒤에 와야 이긴다(승인 대기가 최우선 신호). */
.si-board { display: flex; gap: 6px; list-style: none; margin: 14px 0 0; padding: 0; }
.si-step { flex: 1 1 0; min-width: 0; }
.si-step .si-seg { display: block; height: 6px; border-radius: 999px; background: var(--switch-off); transition: background .15s; }
.si-step .si-name { display: block; margin-top: 6px; font-size: 10.5px; color: var(--faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.si-step.done .si-seg { background: var(--ok); }
.si-step.done .si-name { color: var(--muted); }
.si-step.cur .si-seg { background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); }
.si-step.cur .si-name { color: var(--foreground); font-weight: 600; }
.si-step.pending .si-seg { background: var(--warn); }
.si-step.pending .si-name { color: var(--warn); font-weight: 600; }
.si-pos { font-size: 12px; margin-top: 6px; }

/* 단계 타임라인 */
.si-timeline { list-style: none; margin: 0; padding: 0; }
.si-tl { position: relative; padding: 0 0 20px 26px; border-left: 2px solid var(--border-soft); }
.si-tl:last-child { border-left-color: transparent; padding-bottom: 0; }
.si-tl::before { content: ""; position: absolute; left: -8px; top: 3px; width: 14px; height: 14px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--border); }
.si-tl.done::before { background: var(--ok); border-color: var(--ok); }
.si-tl.cur::before { background: var(--accent-from); border-color: var(--accent-from); box-shadow: 0 0 0 4px var(--hover-2); }
.si-tl.todo { opacity: .72; }
.si-tl-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.si-key { font-size: 11.5px; }
.si-none { font-size: 12.5px; }

/* 산출물 · 지식 본문 — 서버 원문은 pre-wrap 으로 보이되 카드가 무한히 길어지지 않게 스크롤한다. */
.si-art { background: var(--code-bg); border: 1px solid var(--border-soft); border-radius: 12px; padding: 10px 12px; margin-bottom: 8px; }
.si-art:last-child { margin-bottom: 0; }
.si-art-head { margin-bottom: 6px; }
.si-body { white-space: pre-wrap; word-break: break-word; font-size: 13px; line-height: 1.6; max-height: 260px; overflow: auto; }
.si-know { list-style: none; margin: 0; padding: 0; }
.si-know-item { padding: 12px 0; border-top: 1px solid var(--border-soft); }
.si-know-item:first-child { border-top: 0; padding-top: 0; }

/* 승인 게이트 */
.si-gate { border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; margin-bottom: 8px; }
.si-gate.pending { border-color: var(--warn-bd); background: var(--warn-bg); }
.si-gate.approved { border-color: var(--ok-bd); background: var(--ok-bg); }
.si-gate.rejected { border-color: var(--err-bd); background: var(--err-bg); }
.si-gate.changes_requested { border-color: var(--err-bd); background: var(--err-bg); }
/* 피드백 반려 컨트롤(단계 선택 + 버튼) */
.si-fb { display: inline-flex; gap: 6px; align-items: center; flex: 0 0 auto; }
.si-fb-stage { font: inherit; font-size: 13px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--ta-bg); color: inherit; }
/* 재검토 중 — 빨간 강조 */
.si-card-rework { border-color: var(--err-bd); box-shadow: inset 3px 0 0 0 var(--err); }
.si-rework-banner { border: 1px solid var(--err-bd); background: var(--err-bg); color: var(--err); border-radius: 10px; padding: 9px 12px; font-size: 13px; }
/* 프로젝트 첨부(기획서·제안서) */
.si-files { font: inherit; font-size: 13px; }
.si-attach { border-top: 1px solid var(--border); margin-top: 12px; padding-top: 10px; }
.si-attach-head { font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.si-attach-list { display: flex; flex-direction: column; gap: 4px; }
.si-attach-item { display: flex; align-items: center; gap: 8px; padding: 5px 9px; border-radius: 8px; background: var(--hover); }
.si-attach-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--foreground); text-decoration: none; font-size: 13px; }
.si-attach-name:hover { text-decoration: underline; }
.si-attach-size { flex: none; font-size: 12px; }
.si-attach-del { flex: none; border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 13px; line-height: 1; padding: 3px 7px; border-radius: 6px; }
.si-attach-del:hover { color: var(--err); background: var(--err-bg); }
.si-attach-add { display: inline-flex; align-items: center; gap: 6px; margin-top: 9px; font-size: 13px; cursor: pointer; color: var(--accent-from); }
.si-attach-add:hover { text-decoration: underline; }
/* SI 지식 유형 배지 */
.si-kind { font-size: 10.5px; font-weight: 600; letter-spacing: .02em; vertical-align: middle; }
.si-kind-design_decision { color: var(--accent-from); border-color: var(--accent-from); }
.si-kind-retrospective { color: var(--warn); border-color: var(--warn-bd); background: var(--warn-bg); }
.si-kind-reusable_asset { color: var(--ok); border-color: var(--ok-bd); background: var(--ok-bg); }
.si-know-form { border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-bottom: 12px; background: var(--hover); }
.si-know-form .field { margin-bottom: 9px; }
.si-kf-kind { font: inherit; }
.si-know-meta { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.si-know-del { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 12px; line-height: 1; padding: 2px 6px; border-radius: 6px; }
.si-know-del:hover { color: var(--err); background: var(--err-bg); }
.si-delivery { border-top: 1px solid var(--border); margin-top: 12px; padding-top: 10px; }
.si-dl-head { font-size: 13px; font-weight: 600; }
.si-dl-body { margin-top: 6px; display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.si-dl-row { overflow-wrap: anywhere; }
.si-dl-k { display: inline-block; min-width: 64px; color: var(--muted); font-size: 12px; }
.si-dl-deploy { white-space: pre-wrap; }
.si-dl-form { border: 1px solid var(--border); border-radius: 10px; padding: 12px; margin-top: 10px; background: var(--hover); }
.si-dl-form .field { margin-bottom: 9px; }
.si-gate-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* input 은 전역에서 width:100% — 버튼과 한 줄에 두려면 되돌린다(.lrn-filters 와 같은 이유). */
.si-gate-actions .si-note { width: auto; flex: 1 1 200px; min-width: 160px; padding: 7px 10px; font-size: 13px; }
.si-gate-actions button { flex: 0 0 auto; white-space: nowrap; }

@media (max-width: 860px) {
  .si-form { grid-template-columns: 1fr; }
  .si-board { gap: 4px; }
  /* 라벨 8개는 좁은 화면에서 못 읽는다 — 세그먼트만 남기고 진행 위치는 .si-pos 텍스트로 읽는다. */
  .si-step .si-name { display: none; }
  .si-meta { font-size: 11px; white-space: normal; }
  .si-body { max-height: 200px; }
  .si-gate-actions .si-note { flex: 1 1 100%; width: 100%; }
}

@media (prefers-reduced-motion: reduce) { .view { animation: none; } * { transition: none !important; } }

/* SI 프로젝트 액션 버튼 행 */
.si-actions{display:flex;gap:8px;flex-wrap:wrap}

/* 표준배포: 검색·필터 툴바 + 업무별 접이식 그룹 */
.cat-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; }
.cat-search {
  flex: 1 1 240px; min-width: 180px; font: inherit; color: inherit;
  padding: 9px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--ta-bg);
}
.cat-search:focus { outline: none; border-color: var(--accent-from); background: var(--ta-bg-focus); }
.cat-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.cat-chip {
  font: inherit; font-size: 12px; color: var(--muted); cursor: pointer;
  padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px; background: transparent;
}
.cat-chip:hover { background: var(--hover); }
.cat-chip.on { color: var(--foreground); border-color: var(--accent-from); background: var(--hover-2); font-weight: 600; }
/* 그룹 헤더 — 클릭 시 접힘. .list .group(uppercase 라벨)을 대체한다. */
.cat-list .cat-group-head {
  display: flex; align-items: center; justify-content: flex-start; gap: 8px; width: 100%; text-align: left; font: inherit; color: inherit;
  padding: 11px 12px 7px; border: 0; background: transparent; cursor: pointer;
}
.cat-list .cat-group-head:hover { color: var(--foreground); }
.cat-group-head .caret { font-size: 10px; color: var(--muted); transition: transform .15s ease; }
.cat-group-head.collapsed .caret { transform: rotate(-90deg); }
.cat-group-label { font-weight: 700; font-size: 13px; }
.cat-group-count { font-size: 11px; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px; }
.cat-empty { padding: 22px 12px; text-align: center; color: var(--muted); font-size: 13px; }

/* ── 스코프(설치 위치) 시각 언어 — 표준배포·표준정책·학습이 공유한다 ───────────────────
   색은 영역 칩(.chip.dom-*)과 같은 검증된 4색 계열에서 가져온다. 상태색(--ok/--warn/--err)은
   쓰지 않는다 — 상태 전용이라 재사용하면 완료·실패로 오독된다. 색은 항상 라벨과 함께 간다. */
:root, :root[data-theme="dark"] {
  --sc-user: #3987e5; --sc-project: #9085e9; --sc-both: #1098ad; --sc-server: var(--faint);
}
:root[data-theme="light"] {
  --sc-user: #2a78d6; --sc-project: #4a3aa7; --sc-both: #0891b2; --sc-server: var(--faint);
}
.sc-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--sc-c, var(--muted)); flex: none;
}
[data-scope="user"] { --sc-c: var(--sc-user); }
[data-scope="project"] { --sc-c: var(--sc-project); }
[data-scope="both"] { --sc-c: var(--sc-both); }
[data-scope="server"] { --sc-c: var(--sc-server); }

/* 분포 바 — 이 화면의 시그니처 하나. "지금 어디에 얼마나 깔려 있나"를 한 줄로 보여준다.
   숫자 라벨이 항상 따라붙으므로 색만으로 정보를 전달하지 않는다. */
.sc-bar { display: flex; height: 8px; border-radius: 999px; overflow: hidden; background: var(--border-soft); }
.sc-bar > span { background: var(--sc-c, var(--muted)); min-width: 2px; }
.sc-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; font-size: 12px; }
.sc-legend > span { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
.sc-legend b { color: var(--foreground); font-weight: 600; font-variant-numeric: tabular-nums; }

/* 스코프 머리글 — 세트 그룹보다 한 단계 위. 유저/프로젝트가 배달 축이라 최상위에 둔다.
   접기 버튼을 겸한다: 53개 항목을 한 번에 펼쳐 두면 무엇을 고르는 중인지 놓친다. */
.sc-head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-start;
  gap: 4px 10px; width: 100%;
  padding: 14px 0 8px; border-top: 1px solid var(--border-soft); margin-top: 8px;
  border-left: 0; border-right: 0; border-bottom: 0; background: transparent;
  font: inherit; color: inherit; text-align: left;
}
button.sc-head { cursor: pointer; }
button.sc-head:hover .t { color: var(--accent); }
.sc-head:first-child, .cat-list > .sc-head:first-child { border-top: 0; margin-top: 0; padding-top: 4px; }
.sc-head .t { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; }
.sc-head .caret { font-size: 10px; color: var(--muted); transition: transform .15s ease; }
.sc-head.collapsed .caret { transform: rotate(-90deg); }
.sc-head .hint { font-size: 12px; color: var(--muted); flex: 1 1 200px; min-width: 0; }
.cat-list .sc-head { padding-left: 12px; padding-right: 12px; }
.cat-list .cat-group-head { padding-left: 22px; }
@media (prefers-reduced-motion: reduce) { .sc-head .caret { transition: none; } }

/* 세트 소제목 — 조용한 대문자 라벨. 위계는 크기·굵기·색으로만 만든다(테두리로 때우지 않는다). */
.sc-set-label {
  font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--faint); margin: 12px 0 2px;
}

/* 이름↔설정 짝 목록은 데이터 표가 아니다 — 한 줄을 끝까지 늘리면 이름과 드롭다운 사이가
   800px 넘게 벌어져 눈이 짝을 잃는다. 그래서 **한 줄의 폭**을 묶는다(규율 4조). */
.sc-list { max-width: 980px; }

/* 다만 "줄 폭을 묶는 것"과 "목록을 좁게 두는 것"은 다르다. 760px 로 묶어만 두면 와이드에서
   오른쪽이 통째로 죽는다(실측: 1720px 38% · 2400px 50% 유휴 — 화면이 잘린 것처럼 보였다).
   넓어지면 열을 늘려 공간을 쓰되 각 줄은 여전히 짧게 유지한다.
   머리글·세트 라벨은 열을 가로질러 그룹 경계가 무너지지 않게 한다.
   열 수는 auto-fill 이 남는 폭에서 스스로 정한다 — 브레이크포인트를 손으로 찍으면 카드 폭이
   단계적으로 바뀌는(--view-max 1080→1280→1560) 이 레이아웃에서 반드시 어긋난 구간이 생긴다. */
@media (min-width: 1400px) {
  .sc-list { max-width: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); column-gap: 36px; align-content: start; }
  .sc-list > .sc-head, .sc-list > .sc-set-label, .sc-list > .sc-group, .sc-list > .cat-empty { grid-column: 1 / -1; }
  .sc-group { display: grid; grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); column-gap: 36px; }
  .sc-group > .sc-set-label { grid-column: 1 / -1; }
}

/* 항목 행 — **한 줄**. 이름은 남는 폭을 쓰고 스코프 선택은 오른쪽에 고정 폭으로 붙는다.
   설명은 넣지 않는다(title 로만): 53행에서 설명은 읽히지 않으면서 폭을 다 먹고, 좁은 화면에선
   컨테이너 밖으로 넘쳐 가로 스크롤을 만든다. */
/* 좁아지면 이름을 줄이는 게 아니라 드롭다운을 아래 줄로 내린다 — 항목의 정체(이름)는 어떤 폭에서도
   온전히 보여야 한다. 이름에 말줄임을 걸면 si-requirements-curator 류가 구분되지 않는다. */
.sc-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  min-height: 40px; padding: 3px 0; border-top: 1px solid var(--border-soft);
  border-radius: 8px;
}
/* 호버 — 긴 목록에서 지금 어느 줄을 보고 있는지 잃지 않게. 여백만 살짝 넓힌다(색 이동 없음). */
.sc-list .sc-row:hover { background: var(--hover); box-shadow: 0 0 0 8px var(--hover); }
.sc-row:first-of-type { border-top: 0; }
.sc-row .nm {
  display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 14px;
  flex: 1 1 auto; min-width: fit-content;  /* 텍스트보다 좁아지지 않는다 = 말줄임이 생기지 않는다 */
}
.sc-row .nm > span { white-space: nowrap; }
.sc-row select { flex: 0 0 auto; width: 138px; margin-left: auto; }
.sc-row .badge { flex: 0 0 auto; }
.sc-row .why { font-size: 12px; color: var(--muted); }
/* 기본값에서 옮긴 행 — 저장 전에도 무엇을 건드렸는지 보이게. 색이 아니라 위치(왼쪽 표시)로도 알린다. */
.sc-row.moved { box-shadow: inset 2px 0 0 var(--sc-c, var(--accent)); padding-left: 8px; }
@media (max-width: 560px) { .sc-row select { width: 116px; } }

/* 배달 모드 — 세그먼티드 컨트롤. 3개 큰 상자가 목록과 시선을 다투던 것을 한 줄로 접는다. */
.sc-seg { display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 4px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--input-bg); }
.sc-seg label { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px;
  border-radius: 9px; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--muted); }
.sc-seg label:hover { background: var(--hover); color: var(--foreground); }
.sc-seg label.on { background: var(--surface); color: var(--foreground); box-shadow: 0 1px 2px rgba(0,0,0,.12); }
.sc-seg input { position: absolute; opacity: 0; width: 0; height: 0; }
.sc-seg label:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.sc-mode-hint { font-size: 12px; color: var(--muted); margin-top: 8px; max-width: 65ch; }

/* 배달 모드 배너(표준배포 목록 위) — "아래 스코프 구분이 아직 배달에 반영되지 않았다".
 * 경고(warn) 계열을 쓴다: 고장이 아니라 이행기 상태라서 err 를 쓰면 과장이 되고, 정보(ok)로
 * 두면 목록 위에서 그냥 지나쳐진다. 배달 모드가 '프로젝트 단위로' 면 이 요소는 뜨지 않는다
 * (평소 늘 떠 있는 경고를 만들지 않는다 — deploy.js deliveryNotice 주석).
 * 프로즈라서 measure 로 묶는다(.sc-note 와 같은 규약). */

/* 프로즈는 measure 로 묶는다 — 데이터 목록과 달리 눈이 줄을 놓치지 않게. */
.sc-note { font-size: 12px; color: var(--muted); max-width: 65ch; }

/* ── 학습 추적 — 수집→증류→개선안→검증→발행 ────────────────────────────────────
   파이프라인을 화면 구조로 보여준다: 스트립이 순서를, 아래 절이 각 단계의 실제 데이터를 맡는다. */
/* 과정은 모달로 띄운다 — 한 번에 하나만 보는 것이라 페이지에 눌러 붙이지 않는다.
   기본 .modal(460px)보다 넓게: 5단계 스트립과 신호 원문이 들어가야 한다. */
.tr-modal { max-width: 900px; display: flex; flex-direction: column; max-height: min(86vh, 900px); }
.tr-modal-body { overflow-y: auto; overflow-x: hidden; padding-right: 4px; }
.tr-modal-body pre.code { max-height: none; }
.tr-strip { display: flex; align-items: stretch; gap: 6px; overflow-x: auto; padding-bottom: 6px; }
.tr-stage { flex: 1 1 0; min-width: 132px; padding: 10px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--surface); }
.tr-stage .tr-n { font-size: 11px; color: var(--faint); }
.tr-stage .tr-l { font-weight: 700; font-size: 13px; }
.tr-stage .tr-v { font-size: 13px; color: var(--accent); font-weight: 600; margin-top: 2px; }
.tr-stage .tr-d { font-size: 11px; color: var(--muted); margin-top: 4px; line-height: 1.4; }
.tr-arrow { align-self: center; color: var(--faint); flex: 0 0 auto; }
.tr-sec { margin-top: 14px; }
.tr-sec-h { font-size: 13px; margin-bottom: 6px; }
.tr-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; padding: 5px 0; border-top: 1px solid var(--border-soft); }
.tr-row:first-of-type { border-top: 0; }
.tr-row .tr-ev { flex: 1 1 260px; min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
.tr-row .badge { flex: 0 0 auto; }
.tr-drop { opacity: .72; }
@media (max-width: 640px) { .tr-stage { min-width: 116px; } .tr-arrow { display: none; } }

/* 학습 신호 행 — 사유가 있는 행만 두 줄이 되어 목록의 리듬이 유지된다. */
.ln-item { border-top: 1px solid var(--border-soft); }
.ln-item:first-of-type { border-top: 0; }
.ln-item .sc-row { border-top: 0; }
.ln-item .why { font-size: 12px; color: var(--muted); padding: 0 0 8px 15px; max-width: 65ch; }
.ln-item .sc-row button { flex: 0 0 auto; }

/* 스코프 그룹 본문 래퍼는 `.ln-group` 이다 — `.sc-group` 을 재사용하지 않는다(클래스가 둘인 이유).
   1400px 이상에서 `.sc-group` 은 (스코프가 아닌 전역 선택자로) 420px 2열 그리드가 되는데, 학습
   신호 행은 사유(why) 두 번째 줄을 달고 있어 열로 쪼개면 행과 그 사유의 짝이 어긋난다.
   `.ln-group` 자체는 기본 display:block 이면 충분하므로 규칙을 두지 않는다 — 아래 한 줄은
   '조용한 N건 보기' 토글이 액션 행과 서랍 사이에서 숨을 쉬게 하는 여백뿐이다. */
.ln-quiet-toggle { margin: 10px 0 2px; }

/* 인테이크(도착 대비 학습 기여) — 도착 수와 교훈 수는 두 자리 수까지 벌어지는데, 숫자만
   나란히 적으면 그 격차가 읽히지 않는다. 폭 고정 막대라 표의 열이 행마다 흔들리지 않고,
   저조 상태는 상태 토큰(--warn)을 그대로 쓴다. 막대는 aria-hidden 이고 옆 칸에 비율 숫자를
   함께 적는다 — 색만으로 상태를 구분하게 두지 않는다(색각 이상·흑백 인쇄). */
.ln-meter { display: inline-block; width: 56px; height: 6px; border-radius: 3px;
  background: var(--border); overflow: hidden; vertical-align: middle; margin-right: 6px; }
.ln-meter > i { display: block; height: 100%; background: var(--ok); }
.ln-meter.low > i { background: var(--warn); }
/* 사유 줄은 앞 행에 붙은 **두 번째 줄**이다 — 위 테두리를 지워 두 <tr> 이 한 행으로 읽히게 한다.
   경고가 있는 행에만 생기므로 정상 상태의 표는 한 행 = 한 줄 그대로다. */
/* tr.ln-note(행별 사유 줄) 규칙은 지웠다 — 그 줄 자체를 없앴다(2026-08-05, 표를 표로 읽히게). */

/* 표준배포: 전체폭 리스트 + 우측 슬라이드 편집 드로어 */
.cat-list { max-height: none; }
.cat-drawer-ov { position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 60; }
.cat-drawer {
  position: fixed; top: 0; right: 0; height: 100vh; width: min(760px, 94vw);
  transform: translateX(100%); visibility: hidden;
  transition: transform .24s ease, visibility 0s linear .24s; z-index: 61;
  display: flex; flex-direction: column; border-left: 1px solid var(--border); border-radius: 0;
}
/* 닫힘 상태는 visibility:hidden 로 절대 페인트되지 않는다 → 마운트 시 transform 재생과 무관하게 flash 0.
   닫을 때는 visibility 전환을 .24s 지연시켜 슬라이드아웃이 끝까지 보이도록, 열 때는 즉시 보이게 한다. */
.cat-drawer.open {
  transform: translateX(0); visibility: visible;
  transition: transform .24s ease, visibility 0s linear 0s;
  box-shadow: -18px 0 55px rgba(0,0,0,.4);
}
.cat-drawer .editor-panel { flex: 1; min-height: 0; border-radius: 0; background: transparent; }
.cat-drawer .editor-panel textarea { min-height: 0; }
.cat-drawer .cat-close { flex: 0 0 auto; font-size: 15px; line-height: 1; padding: 6px 10px; }
@media (prefers-reduced-motion: reduce) { .cat-drawer { transition: none; } }

/* ── 작업 배정(work_items) ──
   목록 + 등록 폼 + 우측 상세 드로어(.cat-drawer 재사용). 색은 전부 CSS 변수 — 테마 전환이 따라온다.
   상태는 색만으로 구분하지 않는다 — 배지 텍스트가 항상 함께 간다. */

/* input/select 는 전역에서 width:100% — 필터 줄에선 내용 폭으로 되돌린다(.lrn-filters 와 같은 이유). */
.wk-filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.wk-filters select { width: auto; min-width: 140px; padding: 7px 10px; font-size: 13px; }
.wk-check { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: 13px; color: var(--muted); cursor: pointer; }
.wk-check input { width: auto; margin: 0; }

/* 넓은 표는 카드 안에서만 가로 스크롤 — 본문이 통째로 밀리지 않게.
   목록이 많이 쌓여도 세로로 무한 확장하지 않도록 높이 상한을 두고 컨테이너 안에서 스크롤한다. */
.wk-scroll { overflow-x: auto; overflow-y: auto; max-height: 62vh; }
/* 세로만 스크롤하는 목록 컨테이너(가로 스크롤 없는 카드/큐용) — 무한 세로 확장 방지. */
.list-scroll { overflow-y: auto; max-height: 62vh; }

/* 등록 폼 */
.wk-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.wk-form .wk-span { grid-column: 1 / -1; }
.wk-ta { min-height: 84px; font-size: 13px; line-height: 1.6; resize: vertical; }
.wk-ta-lg { min-height: 150px; font-size: 12.5px; }
.wk-tok-label { width: auto; flex: 1 1 240px; min-width: 180px; }

/* 추천 미리보기 */
.wk-route { margin-top: 4px; }
.wk-route-box { border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; background: var(--code-bg); }
.wk-route-box.bad { border-color: var(--err-bd); background: var(--err-bg); }
.wk-conf { height: 6px; border-radius: 999px; background: var(--switch-off); margin-top: 8px; overflow: hidden; }
.wk-conf span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(120deg, var(--accent-from), var(--accent-to)); }
.wk-alts { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.wk-alt { padding: 3px 10px; font-size: 12px; font-family: var(--mono); }

/* 상세 드로어 — .cat-drawer(우측 슬라이드)를 그대로 쓰고 내부만 정의한다. */
.wk-drawer-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border-soft); flex: 0 0 auto; }
.wk-drawer-title { flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wk-drawer-body { flex: 1; min-height: 0; overflow: auto; padding: 18px 20px 40px; }
.wk-det-head h3 { font-size: 17px; }
.wk-sec { margin-top: 22px; }
.wk-sec h4 { margin: 0 0 8px; font-size: 13px; font-weight: 650; letter-spacing: .01em; }
.wk-kv { display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: 4px 12px; font-size: 13px; }
.wk-kv > div:nth-child(odd) { color: var(--muted); }
.wk-lease-out { color: var(--warn); }

/* 결과 · 발견사항 */
.wk-result { background: var(--code-bg); border: 1px solid var(--border-soft); border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; }
.wk-result:last-child { margin-bottom: 0; }
.wk-sub { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin: 10px 0 4px; }
.wk-findings { list-style: none; margin: 0; padding: 0; }
.wk-finding { border-top: 1px solid var(--border-soft); padding: 10px 0; }
.wk-finding:first-child { border-top: 0; padding-top: 0; }
.wk-finding-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wk-fk { font-size: 11px; color: var(--muted); margin: 6px 0 2px; }

/* 감사 이력 */
.wk-events { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.wk-events li { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 7px 0; border-top: 1px solid var(--border-soft); }
.wk-events li:first-child { border-top: 0; }

/* 발급 직후 1회 노출되는 원문 토큰 — 눈에 띄게, 그리고 선택해서 복사할 수 있게. */
.wk-token-new { border: 1px solid var(--warn-bd); background: var(--warn-bg); border-radius: 12px; padding: 12px 14px; margin-bottom: 14px; }
.wk-token-raw { user-select: all; word-break: break-all; font-size: 12.5px; padding: 10px 12px; border-radius: 10px;
  background: var(--code-bg); border: 1px solid var(--border); }

@media (max-width: 860px) {
  .wk-form { grid-template-columns: 1fr; }
  .wk-filters select { width: 100%; flex: 1 1 100%; }
  .wk-kv { grid-template-columns: 1fr; gap: 2px; }
  .wk-kv > div:nth-child(odd) { margin-top: 6px; }
  .wk-drawer-body { padding: 14px 14px 32px; }
  /* 좁은 화면에선 목록이 너무 눌리지 않게 상한을 살짝 키운다. */
  .wk-scroll { max-height: 72vh; }
  .list-scroll { max-height: 72vh; }
}

/* ================================================================
   공용 컴포넌트 · 레이아웃 유틸 (통일 · 반응형)
   뷰들이 인라인 style 로 제각각 그리던 패턴(탭·툴바·섹션제목·간격·표 스크롤)을
   여기 클래스로 모은다. 새 뷰는 인라인 대신 이 클래스를 쓸 것.
   ================================================================ */

/* 탭 바 — 화면 안 하위 전환(에이전트 플랫폼 구성·설치/학습 등). 알약형 세그먼트. */
.tabs { display: inline-flex; gap: 4px; padding: 4px; margin: 0 0 18px;
  border: 1px solid var(--border-soft); border-radius: 999px; background: var(--hover); }
.tabs .tab { font: inherit; font-weight: 600; font-size: 13px; cursor: pointer; color: var(--muted);
  padding: 7px 16px; border: 0; border-radius: 999px; background: transparent; white-space: nowrap;
  transition: background .15s, color .15s; }
.tabs .tab:hover { background: transparent; color: var(--foreground); }
.tabs .tab.active { color: #fff; background: linear-gradient(120deg, var(--accent-from), var(--accent-to));
  box-shadow: 0 8px 22px -12px rgba(99,102,241,0.6); }

/* 툴바 — 제목 + 오른쪽 액션 버튼들. 좁아지면 자동 줄바꿈. */
.toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 0 14px; }
.toolbar .grow { flex: 1 1 auto; }

/* 카드 안 소제목 — h3 를 반복해서 인라인으로 꾸미던 것을 대체. */
.section-title { font-size: 13px; font-weight: 650; letter-spacing: .01em; color: var(--foreground); margin: 0 0 10px; }
.section-title.sub { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.help { color: var(--muted); font-size: 12.5px; line-height: 1.55; }
.help.tight { font-size: 12px; }

/* 굵기 · 상태색 텍스트 유틸 — 라벨/상태 문구 색·굵기를 인라인으로 칠하지 않게. */
.fw-600 { font-weight: 600; } .fw-700 { font-weight: 700; }
.count { font-weight: 400; font-size: 13px; color: var(--muted); }  /* 굵은 제목 안의 "· N개" 카운트 */
.txt-ok { color: var(--ok); } .txt-warn { color: var(--warn); } .txt-err { color: var(--err); }
.txt-muted { color: var(--muted); } .txt-fg { color: var(--foreground); }

/* 세로 스택 · 간격 유틸 — 인라인 margin/gap 남발을 줄인다. */
.stack { display: flex; flex-direction: column; gap: 12px; }
.stack.sm { gap: 8px; } .stack.lg { gap: 18px; }
.mt-sm { margin-top: 8px; } .mt-lg { margin-top: 24px; }
.mb-sm { margin-bottom: 8px; } .mb-0 { margin-bottom: 0; }
.gap-sm { gap: 6px; } .wrap { flex-wrap: wrap; }

/* 카드 간 세로 간격 — .card 를 연달아 둘 때 통일된 리듬. */
.cards { display: flex; flex-direction: column; gap: 16px; }

/* 넓은 표는 반드시 이 래퍼로 감싼다 — 좁은 화면에서 본문을 밀지 않고 카드 안에서만 가로 스크롤. */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-wrap table { min-width: 520px; }

/* 상태 요약 타일 행(대시보드 등) — 자동 채움 그리드. */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; }

/* 소형 카드 그리드(개선안 큐 등) — auto-fill로 넓은 화면=여러 열, 좁으면 자동 1열.
   와이드 반응형과 자연 조화. .list-scroll 안에 두면 카드가 많아도 컨테이너 안에서만 스크롤. */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }

/* 프로젝트 지식베이스 — 카드 그리드. 종전엔 세로 한 줄로만 쌓여 와이드에서 오른쪽이 통째로 비고
   스크롤만 길어졌다. 지식 카드는 제목+태그+발췌라 260px 는 좁다 — 읽을 수 있는 최소를 340px 로 둔다.
   카드 높이는 내용에 맞춘다(start) — 한 줄에서 가장 긴 카드에 맞춰 늘어나면 여백이 커진다. */
/* 지식 카드 격자 — **한 줄 안의 카드 높이를 맞춘다.**
   종전엔 align-items:start 라 카드가 각자 내용 길이대로 섰다. 정형 지식은 종류마다 필드 수가
   다르고(회고 3칸 · 설계 결정 6칸) 값 길이도 제각각이라, 같은 줄에서 높이가 크게 어긋나
   [프로젝트 열기] 버튼이 계단처럼 흩어졌다(2026-08-05 사용자 지적).
   grid 기본값 stretch 로 두면 한 줄의 카드가 그 줄 최고 높이에 맞춰진다. */
.kb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; }
.kb-grid > .flat-box { min-width: 0; }
.kb-grid .between { gap: 8px; }
.kb-grid pre { max-height: 220px; }
/* 높이를 맞추면 짧은 카드에 아래 여백이 생긴다 — 그 여백을 버튼 **위**에 몰아 버튼 줄을 바닥에
   붙인다. 그래야 카드마다 같은 자리에서 같은 동작을 찾을 수 있다(눈이 줄을 따라간다). */
.kb-grid > .flat-box > .row:last-child { margin-top: auto; }
/* 필드가 아주 많거나 값이 긴 카드 하나가 그 줄 전체를 밀어 올리는 것을 막는다.
   전문은 같은 카드의 '내용 보기'와 프로젝트 화면에 있으므로 여기서 잘라도 잃는 것이 없다. */
.kb-grid .kb-fields { max-height: 300px; overflow-y: auto; overflow-x: hidden; }

/* 프로젝트 지식베이스 — 두 축(기획 확정 요지=자동 / 정형 지식=사람이 벼려 낸 것) 섹션.
   왜 섹션인가: 종전엔 배지 문자열만 달랐고, 그러면 두 종류가 같은 무게로 나란히 서서 사용자가
   앞의 것(자동 요지)을 "지식"으로 읽었다. 왼쪽 굵은 선으로 덩어리를 갈라 눈에 먼저 띄게 하고,
   머리에 "무엇이 다른가"를 한 줄로 적는다. 색은 보조 신호다 — 축 이름이 이미 글자로 말한다.
   (축 이름을 '실행 후=경험' 으로 잡았다가 정정했다 — 인계 이후 구현은 외부라 결과가 오지 않는다.) */
.kb-sec + .kb-sec { margin-top: 24px; }
.kb-sec-head { padding: 0 0 8px 10px; margin: 0 0 10px; border-left: 3px solid var(--border); }
.kb-sec.plan .kb-sec-head { border-left-color: var(--accent-from); }
.kb-sec.done .kb-sec-head { border-left-color: var(--ok); }
.kb-sec-head h4 { margin: 0 0 4px; font-size: 14px; }
.kb-sec-head .help { max-width: 80ch; }
/* 0건 안내 — 경고가 아니다(정상 경로다). 그래서 색은 안 쓰고 점선으로만 "여기는 아직 빈 자리"를
   말한다. 빨간·노란 테두리를 주면 늘 켜진 경고가 되고, 아무 테두리도 없으면 그냥 빈 칸으로 읽힌다. */
.kb-empty { border-style: dashed; }
/* 축 배지 — 카드 안에서도 어느 축인지 읽히게. */
.badge.kb-ax.plan { color: var(--accent-from); border-color: rgba(56,189,248,0.35); background: rgba(56,189,248,0.10); }
.badge.kb-ax.done { color: var(--ok); border-color: var(--ok-bd); background: var(--ok-bg); }

/* 정형 필드(kind·fields) — 라벨 붙은 정의 목록. 라벨·순서는 **서버가 준다**(화면이 복제하지 않는다:
   두 곳에 두면 갈린다). 라벨 열은 내용에 맞추고 값 열이 남는 폭을 먹는다. 값에 긴 URL·경로가
   들어와도 카드를 뚫지 않게 anywhere 로 끊는다(카드 폭이 340px 라 여기가 실제로 터진다). */
.kb-fields { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 3px 10px; margin: 2px 0 0; font-size: 12px; }
.kb-fields dt { color: var(--muted); font-weight: 600; white-space: nowrap; }
.kb-fields dd { margin: 0; min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.kb-fields dd.kind { font-weight: 650; color: var(--foreground); }
/* 라벨이 없는 필드(body) — 빈 라벨 칸을 남기지 않고 값이 두 칸을 통째로 쓴다. */
.kb-fields dd.full { grid-column: 1 / -1; }
/* 아주 좁은 화면에서는 라벨 열이 값을 짜부순다 — 한 열로 접고 라벨을 값 위에 올린다. */
@media (max-width: 520px) {
  .kb-fields { grid-template-columns: minmax(0, 1fr); gap: 0 0; }
  .kb-fields dt { margin-top: 6px; }
}

/* 태그 칩 — 분류 라벨(협업 에이전트·스킬·태그 등). 상태 배지(.badge)와 구분: 칩=분류, 배지=상태.
   색은 인라인으로 칠하지 말고 co/skill 변형을 쓴다. */
.chip { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 550;
  padding: 2px 9px; margin: 2px 4px 2px 0; border-radius: 8px; white-space: nowrap; color: var(--muted);
  border: 1px solid var(--border); background: var(--hover); }
.chip.co { color: var(--accent-from); border-color: rgba(56,189,248,0.35); background: rgba(56,189,248,0.10); }
.chip.skill { color: var(--accent-to); border-color: rgba(99,102,241,0.35); background: rgba(99,102,241,0.12); }

/* 선택 목록(에이전트 플랫폼 스킬 고르기 등) — 체크박스 + 이름 + 2줄 클램프 설명.
   긴 설명(수백 자)을 통째 흘려 목록이 글자 벽이 되던 문제를 클램프로 막는다(전체는 title 툴팁). */
.pick-list { display: flex; flex-direction: column; gap: 2px; max-height: 300px; overflow: auto; padding: 2px; }
.pick-row { display: flex; align-items: flex-start; gap: 10px; padding: 9px 11px; border-radius: 10px;
  cursor: pointer; border: 1px solid transparent; transition: background .12s, border-color .12s; }
.pick-row:hover { background: var(--hover); }
.pick-row input[type="checkbox"] { width: auto; margin: 2px 0 0; flex: 0 0 auto; }
.pick-row .pick-body { min-width: 0; }
.pick-row .pick-name { font-weight: 600; }
.pick-row .pick-desc { color: var(--muted); font-size: 12px; line-height: 1.45; margin-top: 2px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pick-row.on { background: var(--hover-2); border-color: rgba(99,102,241,0.35); }

/* 프로젝트 파이프라인 스텝퍼(projects.js) — 색은 토큰만 써서 라이트/다크 모두 정합.
   인라인 하드코딩색(rgba(255,255,255,…) 등)을 이 클래스로 대체한다. */
.pj-step { display: flex; gap: 12px; }
.pj-rail { display: flex; flex-direction: column; align-items: center; }
.pj-dot { width: 28px; height: 28px; flex: 0 0 28px; border-radius: 50%; border: 2px solid var(--faint);
  display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; }
.pj-dot.done { border-color: var(--ok); }
.pj-dot.active { border-color: var(--warn); box-shadow: 0 0 0 4px var(--warn-bg); }
.pj-line { flex: 1; width: 2px; background: var(--border); min-height: 26px; }
.pj-line.done { background: var(--ok); }
.pj-card { flex: 1; margin: 0 0 10px; }
.pj-card.active { border-color: var(--warn-bd); }
.pj-rationale { border-left: 3px solid var(--accent-from); padding-left: 10px; color: var(--muted); font-size: 13px; }

/* 접이식 요약 헤더 — kb/intake/projects 등의 <summary> 공용(커서+굵기 통일, .si-summary와 동일). */
.summary { cursor: pointer; font-weight: 600; }
/* 플랫 박스 — 카드 안의 하위 블록(카드-속-카드 소음 방지). .card.glass 중첩 대신 이걸 쓴다. */
.flat-box { background: var(--code-bg); border: 1px solid var(--border-soft); border-radius: 12px; padding: 12px 14px; }

/* ── 모바일 정밀화(≤560px) — 기존 860px 규칙 위에 한 겹 더 ── */
@media (max-width: 640px) {
  .main { padding: 16px 14px; }
  .view h2 { font-size: 18px; }
  .view { max-width: 100%; }
  .card, .tile { padding: 14px 15px; }
  /* 제목+액션이 한 줄에 안 들어가면 세로로 쌓고 액션을 왼쪽 정렬. */
  .between { flex-direction: column; align-items: stretch; }
  .between > .row, .toolbar { justify-content: flex-start; }
  /* 폭 좁은 화면에서 표는 항상 스크롤 가능하게(래퍼 없어도 최소 방어). */
  .card table, .glass table { display: block; overflow-x: auto; white-space: nowrap; }
  /* 단 .table-wrap 안의 표는 래퍼가 이미 스크롤을 맡는다. 여기에 위 규칙이 겹치면 스크롤
   * 컨테이너가 이중이 되고, display:block 이 표 레이아웃을 깨 열 너비가 내용폭으로 무너진다. */
  .card .table-wrap table, .glass .table-wrap table { display: table; white-space: normal; overflow-x: visible; }
  /* 탭 라벨은 nowrap 이다. flex:1 1 0 으로 두면 basis 0 에서 더 줄어들어 **박스보다 글자가 길어져**
   * 탭끼리 겹쳐 보인다(한국어 탭 3개 이상이면 항상). 줄이지 말고 넘치면 가로로 굴린다. */
  .tabs { display: flex; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tabs .tab { flex: 1 0 auto; text-align: center; }
  .stat-row { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 400px) {
  .stat-row { grid-template-columns: 1fr; }
}

/* 위시캣 필터 바 */
.wk-filter-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wk-filter-bar .cat-search { flex: 1 1 200px; min-width: 160px; padding: 7px 11px; font-size: 13px; }
.wk-label { font-size: 12px; color: var(--muted); }
.wk-select {
  font: inherit; font-size: 12px; color: inherit; width: auto; cursor: pointer;
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--ta-bg);
}
.wk-select:focus { outline: none; border-color: var(--accent-from); background: var(--ta-bg-focus); }

/* 위시캣 리드 카드 — 추천사유(💬)를 2줄로 클램프해 카드가 세로로 폭주하지 않게. 전체 내용은 상세에서 본다. */
.wk-reason-clamp {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ─────────────────────────────────────────────────────────────
   커스텀 드롭다운(select-enhance.js) — 네이티브 <select> 전역 향상.
   닫힌 select 박스(139~150행)와 규격을 맞추고, 열린 목록도 토큰 기반
   다크/라이트로 렌더한다. 새 색 하드코딩 0 · 기존 토큰만 사용.
   ───────────────────────────────────────────────────────────── */

/* 네이티브 select 는 값 저장소로만 남기고 화면에서 숨긴다.
   display:none → 손수 만든 포커스 트랩(offsetParent!==null 필터)이 자연히 건너뛴다. */
.sel-native { display: none !important; }

/* 트리거 — 닫힌 select 박스와 동일 느낌(radius·padding·border·--surface). 기본 폭 100%(폼 필드). */
.sel-trigger {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; font: inherit; text-align: left; cursor: pointer; line-height: 1.25;
  color: var(--foreground); background: var(--surface);
  border: 1px solid var(--border); border-radius: 12px; padding: 9px 12px;
  transition: border-color .15s, background .15s;
}
.sel-trigger:hover:not(:disabled) { background: var(--hover); }
.sel-trigger:disabled { opacity: .4; cursor: not-allowed; }
.sel-trigger[aria-expanded="true"] { border-color: var(--accent); background: var(--input-bg-focus); }
.sel-trigger:focus-visible { outline: 2px solid var(--accent-from); outline-offset: 1px; }
.sel-trigger .sel-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sel-trigger.sel-placeholder .sel-label { color: var(--muted); }
.sel-trigger .sel-chev { flex: 0 0 auto; color: var(--muted); font-size: 11px; transition: transform .15s ease; }
.sel-trigger[aria-expanded="true"] .sel-chev { transform: rotate(180deg); }

/* 필터 바 안에서는 원 select 처럼 내용 폭(auto) — 기존 컨테이너 규칙 미러. */
.wk-filters .sel-trigger, .lrn-filters .sel-trigger,
.wk-filter-bar .sel-trigger { width: auto; min-width: 140px; padding: 7px 10px; font-size: 13px; }
.lrn-filters .sel-trigger { min-width: 150px; }

/* 팝업 목록 — --surface 배경 · --border 테두리 · 카드 그림자 토큰 재사용. */
.sel-list {
  position: fixed; z-index: 300; margin: 0; padding: 5px; list-style: none;
  min-width: 8rem; max-height: 320px; overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--glass-shadow);
}
.sel-list[hidden] { display: none; }
.sel-list li {
  padding: 7px 10px; border-radius: 8px; font-size: 13px; color: var(--foreground);
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sel-list li.sel-active { background: var(--hover); }
.sel-list li[aria-selected="true"] { background: var(--hover-2); color: var(--accent); font-weight: 600; }
.sel-list li[aria-selected="true"].sel-active { background: var(--hover-2); }
.sel-list li.sel-opt-dis { opacity: .4; cursor: not-allowed; }

@media (prefers-reduced-motion: reduce) {
  .sel-trigger, .sel-trigger .sel-chev { transition: none; }
}

/* ── 기획안 파이프라인 (대시보드 메인) ──
   수집 → 기획(W0~W3) → 인계 → 클릭아이 구현을 노드-엣지 플로우 캔버스로 그린다(views/flow.js).
   SVG 는 클래스만 들고 오고 색은 전부 여기서 토큰으로 칠한다 — 그래야 다크/라이트가 따라온다.

   상태를 색만으로 말하지 않는다: 노드 채움(완료)·링+펄스(진행)·빈칸(대기)·굵은 테두리(실패)로
   모양이 함께 바뀌고, flow.js 가 노드마다 aria-label/<title> 로 상태를 글로 남긴다. */
.pipes { display: flex; flex-direction: column; gap: 12px; }

.pipe-row { padding: 10px 12px 6px; border: 1px solid var(--border-soft); border-radius: 14px; background: var(--hover); }
.pipe-row:hover { border-color: var(--border); }

.pipe-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.pipe-name { font-size: 14px; font-weight: 600; color: var(--foreground); }
.pipe-now { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }

/* 캔버스 — 노드가 많으면(기획 4 + 구현 N, 팬아웃 시 더) 넘친다. 컨테이너 안에서만 가로 스크롤한다. */
.fl-canvas { overflow-x: auto; overflow-y: hidden; padding: 2px 0 8px; }
.fl-svg { display: block; max-width: none; }

/* ── 간선 ── 기본은 무채색. 출발 노드가 완료면 초록으로 이어지고, 진행 노드로 들어오는 간선에서
   흐름이 움직인다(흐르는 점선). */
.fl-edge { fill: none; stroke: var(--border); stroke-width: 2; }
.fl-edge.is-flowed { stroke: var(--ok); }
.fl-edge.is-running {
  stroke: var(--warn); stroke-dasharray: 7 6; stroke-linecap: round;
  animation: fl-flow .9s linear infinite;
}
@keyframes fl-flow { from { stroke-dashoffset: 26; } to { stroke-dashoffset: 0; } }

/* ── 노드 ── */
.fl-node .fl-box { fill: var(--surface); stroke: var(--border); stroke-width: 1.5; }
.fl-node .fl-pip { fill: var(--border); }
.fl-node .fl-label { font-size: 11px; font-weight: 600; fill: var(--foreground); }
.fl-node .fl-detail { font-size: 9px; fill: var(--faint); }
.fl-node .fl-caret { font-size: 9px; fill: var(--muted); }

.fl-node.is-done .fl-box { fill: var(--ok-bg); stroke: var(--ok-bd); }
.fl-node.is-done .fl-pip { fill: var(--ok); }
.fl-node.is-done .fl-label { fill: var(--muted); }

.fl-node.is-active .fl-box { fill: var(--warn-bg); stroke: var(--warn); }
.fl-node.is-active .fl-pip { fill: var(--warn); animation: fl-pulse 1.6s ease-in-out infinite; }
.fl-node.is-active .fl-label { fill: var(--warn); }
@keyframes fl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

.fl-node.is-failed .fl-box { fill: var(--err-bg); stroke: var(--err); stroke-width: 2.5; }
.fl-node.is-failed .fl-pip { fill: var(--err); }
.fl-node.is-failed .fl-label { fill: var(--err); }

/* 펼칠 수 있는 웨이브 노드 — 클릭 대상임을 커서와 호버로 알린다. */
.fl-node.is-expandable { cursor: pointer; }
.fl-node.is-expandable:hover .fl-box { stroke: var(--accent); }
.fl-node.is-expandable:focus-visible { outline: none; }
.fl-node.is-expandable:focus-visible .fl-box { stroke: var(--accent); stroke-width: 2.5; }

/* 자동 갱신 표시 — 조용히. 이 화면이 스스로 갱신된다는 사실만 알린다. */
.pipe-live { display: inline-flex; align-items: center; gap: 5px; }
.pipe-live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); animation: pipe-live 2.4s ease-in-out infinite; }
@keyframes pipe-live { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

.dot.idle { background: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  /* 560행의 전역 블록은 transition 만 끈다 — 반복 애니메이션은 여기서 명시적으로 멈춘다.
     흐르는 간선은 정지 상태에서도 주황 점선으로 "여기가 진행 중"임을 유지한다. */
  .fl-edge.is-running, .fl-node.is-active .fl-pip, .pipe-live-dot { animation: none; }
}

/* ── 대시보드 칩 색분류 ──
   전부 같은 회색이면 무엇이 단계고 무엇이 영역인지 구분되지 않는다(칙칙함의 원인).
   종류마다 다른 인코딩을 준다: 단계=순차 농도 · 영역=계열 색 · 메타=무채색.

   ⚠ 글자는 항상 텍스트 토큰을 쓴다 — 칩 색을 글자에 입히면 대비가 무너진다.
      색은 배경·테두리·점이 들고, 라벨 텍스트가 항상 함께 가므로 색만으로 구분하지 않는다. */

/* 단계 칩 — 수집→기획→인계→구현. 한 색조(액센트)의 4단계 농도 = 순차 인코딩.
   알파로 얹어서 라이트/다크 어느 표면에서도 같은 진행감이 나온다. */
.chip.ph { color: var(--foreground); border-color: rgba(56, 189, 248, 0.38); }
.chip.ph-1 { background: rgba(56, 189, 248, 0.10); }
.chip.ph-2 { background: rgba(56, 189, 248, 0.18); }
.chip.ph-3 { background: rgba(56, 189, 248, 0.26); }
.chip.ph-4 { background: rgba(56, 189, 248, 0.34); }

/* 영역 칩 — 계열 4색(nav.js DOMAIN_FAMILY). 좌측 점이 색을 들고 글자는 토큰 유지.
   상태색(--ok/--warn/--err)은 쓰지 않는다 — 상태 전용이라 재사용하면 완료·실패로 오독된다. */
.chip.dom { position: relative; padding-left: 20px; color: var(--foreground); }
.chip.dom::before {
  content: ''; position: absolute; left: 8px; top: 50%; transform: translateY(-50%);
  width: 7px; height: 7px; border-radius: 50%; background: var(--dom-c);
}
.chip.dom-tech   { --dom-c: #2a78d6; border-color: rgba(42, 120, 214, 0.40); background: rgba(42, 120, 214, 0.10); }
.chip.dom-market { --dom-c: #d55181; border-color: rgba(213, 81, 129, 0.40); background: rgba(213, 81, 129, 0.10); }
.chip.dom-ind    { --dom-c: #4a3aa7; border-color: rgba(74, 58, 167, 0.40);  background: rgba(74, 58, 167, 0.12); }
.chip.dom-inst   { --dom-c: #0891b2; border-color: rgba(8, 145, 178, 0.40);  background: rgba(8, 145, 178, 0.10); }
.chip.dom-etc    { --dom-c: var(--muted); }

/* 다크는 뒤집은 게 아니라 같은 색상을 다크 표면용으로 다시 고른 값이다(검증기 통과). */
:root, :root[data-theme="dark"] {
  --dom-tech-d: #3987e5; --dom-market-d: #d55181; --dom-ind-d: #9085e9; --dom-inst-d: #1098ad;
}
:root:not([data-theme="light"]) .chip.dom-tech   { --dom-c: var(--dom-tech-d); }
:root:not([data-theme="light"]) .chip.dom-market { --dom-c: var(--dom-market-d); }
:root:not([data-theme="light"]) .chip.dom-ind    { --dom-c: var(--dom-ind-d); border-color: rgba(144, 133, 233, 0.42); background: rgba(144, 133, 233, 0.14); }
:root:not([data-theme="light"]) .chip.dom-inst   { --dom-c: var(--dom-inst-d); }

/* 메타 칩 — 버전처럼 분류가 아닌 값. 조용히 둔다(색 경쟁에서 빼낸다). */
.chip.meta { color: var(--muted); border-color: var(--border-soft); background: transparent; }

/* ── 팩 제작(make) ──
   좌: 목록 · 우: 작성 패널. 표준배포의 드로어(우측 슬라이드)와 달리 상시 2단이다 —
   작성은 목록을 보며 오래 머무는 작업이라 열고 닫는 동작이 방해가 된다. */
.mk-wrap { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 16px; align-items: start; }
.mk-side, .mk-main { min-width: 0; }
.mk-list { max-height: calc(100vh - 340px); }
.mk-empty { padding: 44px 20px; text-align: center; }
.mk-path { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--muted); }
/* 라벨 위·입력 아래로 쌓는 단일 열 폼. 필드가 넷뿐이라 2열로 나누면 오히려 눈이 갈린다. */
.mk-form { display: grid; gap: 0; }
.mk-form label { font-size: 12px; color: var(--muted); margin-top: 10px; margin-bottom: 4px; }
.mk-form label:first-child { margin-top: 0; }
.mk-form input, .mk-form textarea { width: 100%; }
.mk-editor > label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.mk-body { width: 100%; min-height: 300px; resize: vertical; }
.mk-note { font-size: 12.5px; color: var(--muted); line-height: 1.65; }
.mk-note b { color: var(--foreground); }

@media (max-width: 900px) {
  .mk-wrap { grid-template-columns: minmax(0, 1fr); }
  .mk-list { max-height: 320px; }
}

/* ── 사용 추적(views/usage.js) ──
   외부 차트 라이브러리 없이 div 폭·높이로 그린다(무의존성 원칙). 색은 액센트 하나만 쓰고
   나머지는 뉴트럴로 둔다 — 축이 일곱 개라 축마다 색을 주면 화면이 알록달록해지고 비교가 안 된다. */
.ubars { display: flex; flex-direction: column; gap: 6px; }
.ubar-row { display: grid; grid-template-columns: minmax(90px, 190px) 1fr auto auto; gap: 10px; align-items: center; }
/* min-width:0 이 필수다 — 그리드 아이템의 자동 최소 크기는 콘텐츠 최소폭이라, 없으면 긴 키가
   줄지 못하고 말줄임 대신 막대와 숫자를 화면 밖으로 밀어낸다(test/ui-truncation.test.js 가 잡는다). */
.ubar-k { font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ubar-track { height: 8px; border-radius: 999px; background: var(--hover); overflow: hidden; }
.ubar-fill { height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-from), var(--accent-to)); }
.ubar-v { font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 600; min-width: 4ch; text-align: right; }
.ubar-s { font-size: 12px; white-space: nowrap; }

/* 일별 추이 — 막대 하나가 하루. 가로 스크롤로 흘려 본문 폭을 밀지 않게 한다. */
.udays { display: flex; align-items: flex-end; gap: 4px; height: 120px; overflow-x: auto; padding-bottom: 2px; }
.uday { display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  height: 100%; min-width: 26px; gap: 4px; }
.uday-bar { width: 14px; border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--accent-from), var(--accent-to)); }
.uday-l { font-size: 10px; color: var(--faint); font-variant-numeric: tabular-nums; white-space: nowrap; }

@media (max-width: 720px) {
  .ubar-row { grid-template-columns: minmax(70px, 120px) 1fr auto; }
  .ubar-s { display: none; }
}
