:root {
  --bg-base: #FFFFFF;
  --bg-surface: #FFFFFF;
  --bg-elevated: #F4F4F5;
  --accent-tint: #F3EEFF;
  --text-primary: #0A0A0A;
  --text-soft: #27272A;
  --text-muted: #52525B;
  --text-faint: #65656D;
  --rule: #000000;
  --border-hair: #E4E4E7;
  --edge-light: #71717A;
  --block: #000000;
  --block-text: #FFFFFF;
  --block-muted: #A1A1AA;
  --block-hair: #27272A;
  --accent: #6D28D9;
  --accent-fill: #6D28D9;
  --accent-hover: #5B21B6;
  --on-accent: #FFFFFF;
  --accent-alt: #7C3AED;
  --accent-deep: #4C1D95;
  --accent-on-block: #A78BFA;
  --rail-bg: #000000;
  --rail-text: #FFFFFF;
  --rail-muted: #A1A1AA;
  --rail-hair: #27272A;
  --rail-hover: #18181B;
  --rail-accent: #A78BFA;
  --rail-sel-bg: #FFFFFF;
  --rail-sel-text: #000000;
  --rail-sel-muted: #52525B;
  --on-warn: #000000;
  --state-text-stable: #065F46;
  --state-text-unstable: #991B1B;
  --state-text-offline: #B91C1C;
  --state-text-warn: #92400E;
  --state-text-idle: #52525B;
  --inv-text-stable: #34D399;
  --inv-text-unstable: #F87171;
  --inv-text-offline: #FF8A8A;
  --inv-text-warn: #FBBF24;
  --inv-text-idle: #A1A1AA;
  --rail-state-stable: #34D399;
  --rail-state-unstable: #F87171;
  --rail-state-offline: #FF8A8A;
  --rail-state-warn: #FBBF24;
  --rail-state-idle: #A1A1AA;
  --rail-sel-state-stable: #065F46;
  --rail-sel-state-unstable: #991B1B;
  --rail-sel-state-offline: #B91C1C;
  --rail-sel-state-warn: #92400E;
  --rail-sel-state-idle: #52525B;
  --state-stable: #34D399;
  --state-unstable: #F87171;
  --state-offline: #EF4444;
  --state-warn: #FBBF24;
  --state-idle: #6B7280;
  color-scheme: light;
}
:root[data-theme="dark"] {
  --bg-base: #000000;
  --bg-surface: #000000;
  --bg-elevated: #111113;
  --accent-tint: #1A1030;
  --text-primary: #FAFAFA;
  --text-soft: #D4D4D8;
  --text-muted: #A1A1AA;
  --text-faint: #8B8B94;
  --rule: #FFFFFF;
  --border-hair: #27272A;
  --edge-light: #8B8B94;
  --block: #FFFFFF;
  --block-text: #000000;
  --block-muted: #52525B;
  --block-hair: #E4E4E7;
  --accent: #A78BFA;
  --accent-fill: #7C3AED;
  --accent-hover: #6D28D9;
  --on-accent: #FFFFFF;
  --accent-alt: #C4B5FD;
  --accent-deep: #6D28D9;
  --accent-on-block: #6D28D9;
  --rail-bg: #0B0B0D;
  --rail-text: #FAFAFA;
  --rail-muted: #A1A1AA;
  --rail-hair: #1F1F23;
  --rail-hover: #18181B;
  --rail-accent: #A78BFA;
  --rail-sel-bg: #FFFFFF;
  --rail-sel-text: #000000;
  --rail-sel-muted: #52525B;
  --on-warn: #000000;
  --state-text-stable: #34D399;
  --state-text-unstable: #F87171;
  --state-text-offline: #FF8A8A;
  --state-text-warn: #FBBF24;
  --state-text-idle: #A1A1AA;
  --inv-text-stable: #065F46;
  --inv-text-unstable: #991B1B;
  --inv-text-offline: #B91C1C;
  --inv-text-warn: #92400E;
  --inv-text-idle: #52525B;
  --rail-state-stable: #34D399;
  --rail-state-unstable: #F87171;
  --rail-state-offline: #FF8A8A;
  --rail-state-warn: #FBBF24;
  --rail-state-idle: #A1A1AA;
  --rail-sel-state-stable: #065F46;
  --rail-sel-state-unstable: #991B1B;
  --rail-sel-state-offline: #B91C1C;
  --rail-sel-state-warn: #92400E;
  --rail-sel-state-idle: #52525B;
  color-scheme: dark;
}
:root {
  --chart-0: #22D3EE;
  --chart-1: #8B5CF6;
  --chart-2: #F472B6;
  --chart-3: #38BDF8;
  --chart-4: #A78BFA;
}

/* 관제 콘솔 — 기초: 글꼴 · 치수 · 입력 · 공용 글자 규칙 (A-16-3, 시안 D «볼드 에디토리얼»).
 *
 * ★★색은 여기 적지 않는다. `/console/theme.css` 맨 앞에 `tsc_ui_tokens.console_web` 이
 *   생성한 변수(종이 기본 · 검정)가 붙는다(assets.stylesheet). 색을 두 곳에 적으면 반드시
 *   어긋난다 (A-16-4). 새 색이 필요하면 토큰을 섞어 만든다 — `color-mix(… var(--accent) …)`.
 * ★여기의 변수는 **색이 아닌 치수**(둥글기·높이·굵기)뿐이다.
 * ★파일은 assets.STYLES 순서로 이어 붙는다 — 기초 → 뼈대 → 부품 → 화면별 → 좁은 화면.
 *   뒤 파일이 앞 파일을 이긴다.
 *
 * ★★시안 D 의 규칙 세 가지 — 화면 CSS 를 고칠 때도 지킨다.
 *   1) 구획은 **2px 검은 선**(`--rule`)으로, 표 안쪽은 **가는 선**(`--border-hair`)으로만 나눈다.
 *      표 안에 2px 선을 남발하면 지면이 무거워진다.
 *   2) 큰 숫자는 굵고 크게(850–950), 본문은 가볍게(450). 숫자는 전부 `tabular-nums`.
 *   3) 바이올렛(`--accent*`)은 브랜드·선택·현재 위치에만. 상태는 점·막대 + **글자**로 말한다.
 */

/* ★글꼴은 이 서버가 낸다(assets.FONTS). 가변 굵기 하나로 400–1000 을 다 쓴다.
 *  `swap` — 글꼴이 늦어도 글자는 먼저 보인다(관제 PC 가 느린 회선일 수 있다). */
@font-face {
  font-family: "Wanted Sans";
  src: url("/console/fonts/wanted-sans-v1.woff2") format("woff2");
  font-weight: 400 1000;
  font-style: normal;
  font-display: swap;
}

:root {
  --rail-w: 300px;
  /* 예전 이름. 시안 D 에는 상단바가 없다 — 화면 CSS 의 `calc(100dvh - var(--topbar-h))` 가 그대로 맞게 0 이다. */
  --topbar-h: 0px;
  --sidebar-w: var(--rail-w);
  --r-card: 0px;      /* 시안 D 는 카드가 아니라 선으로 나눈 지면이다 */
  --r-ctl: 6px;       /* 입력칸·버튼 */
  --r-pill: 999px;
  --rule-w: 2px;      /* 구획선 굵기 */
  --shadow-1: none;
  --shadow-2: none;
  --shadow-pop: 0 18px 40px -16px color-mix(in srgb, var(--text-primary) 40%, transparent);
  /* 예전 화면 CSS 가 쓰던 이름. 이제 면을 띄우지 않으므로 종이와 같다. */
  --lift: var(--bg-surface);
  --hover: var(--bg-elevated);
  --font: "Wanted Sans", Pretendard, -apple-system, "Malgun Gothic", sans-serif;
  accent-color: var(--accent-fill);
}

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

/* ★`hidden` 속성이 `display` 지정을 이기게 한다.
 * `.login { display: grid }` 같은 클래스 규칙은 `[hidden]` 의 UA 기본 `display:none` 보다
 * 우선순위가 높다. 그래서 `el.hidden = true` 로 감춘 요소가 **그대로 보인다** — 로그인
 * 화면이 앱 위에 남아 있던 것이 이 때문이었다. 오류도 나지 않아 찾기 어렵다. */
[hidden] { display: none !important; }

html, body { margin: 0; }
body {
  color: var(--text-primary);
  background: var(--bg-base);
  font: 450 13px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  /* ★숫자는 어디서나 고정폭이다 — 자릿수가 바뀔 때 흔들리면 오독이 난다 (A-16-2). */
  font-variant-numeric: tabular-nums;
  /* ★★한국어는 어절이 아니라 글자마다 줄이 바뀐다(«오프|라인»). 어절 단위로만 끊는다 —
   *  `break-word` 는 한 어절이 줄보다 길 때만 쪼갠다. 차량번호·코드처럼 `anywhere` 를 쓰는
   *  자리는 그 규칙이 따로 이긴다. */
  word-break: keep-all;
  overflow-wrap: break-word;
}

h1, h2, h3, h4 { color: var(--text-primary); }
a { color: var(--accent); text-decoration: none; font-weight: 650; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
strong, b { font-weight: 750; }
code {
  display: inline-block; padding: 0 5px; border-radius: 4px; line-height: 17px;
  border: 1.5px solid var(--edge-light); background: none; color: var(--text-muted);
  font: 750 10.5px/17px ui-monospace, SFMono-Regular, Consolas, monospace; letter-spacing: 0.04em;
}
:focus-visible { outline: 2px solid var(--accent-fill); outline-offset: 2px; }

/* ── 입력 ──
 * :where() 는 특정도가 0 이라 아래의 컨테이너 규칙(.form-grid input 등)이 그대로 이긴다. */
:where(input:not([type=checkbox], [type=radio]), select, textarea) {
  font: inherit; font-size: 13px; font-weight: 500; color: var(--text-primary);
  background: var(--bg-base);
  border: 1.5px solid var(--edge-light); border-radius: var(--r-ctl);
  padding: 8px 11px; transition: border-color 0.15s, box-shadow 0.15s;
}
:where(input, select, textarea):hover:not(:disabled) { border-color: var(--rule); }
:where(input, select, textarea):focus-visible {
  outline: none; border-color: var(--accent-fill);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
::placeholder { color: var(--text-faint); }
:where(input, select, textarea):disabled { opacity: 0.55; cursor: not-allowed; background: var(--bg-elevated); }
/* 표 안의 선택칸(접근 정책 모드 등)은 행 높이를 키우지 않게 작게. */
main td select { padding: 5px 8px; font-size: 12px; }

* { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--text-muted) 45%, transparent) transparent; }

/* ── 공용 글자 규칙 ──────────────────────────────────────────────────────── */

/* .muted 는 색과 크기만 준다. 여백은 문단일 때만. */
.muted { color: var(--text-muted); font-size: 12px; }
p.muted, div.muted { margin: 4px 0 12px; }
/* ★표 안의 둘째 줄은 **라벨이 아니라 자료**다(최근 응답 시각·버전). 흐리게 두지 않는다. */
td .muted { color: var(--text-muted); margin: 2px 0 0; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.actions { text-align: right; white-space: nowrap; }
.error, .error-card { color: var(--state-text-offline); font-weight: 650; }
.warn-line {
  color: var(--state-text-warn); font-size: 12.5px; font-weight: 650; margin: 0 0 14px; padding: 10px 14px;
  background: var(--bg-elevated); border-left: 5px solid var(--state-warn);
}
.plain { color: var(--text-muted); font-size: 12px; padding-left: 18px; }
.plain code { color: var(--text-primary); }
.note-cell { max-width: 220px; font-size: 12px; color: var(--text-primary); white-space: pre-wrap; }
.note-body { white-space: pre-wrap; word-break: break-word; }
.id-line { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

/* 상태색은 토큰에서 온다. 여기서 새 색을 만들지 않는다. */
.tone-stable { color: var(--state-text-stable); }
.tone-warn { color: var(--state-text-warn); }
.tone-offline { color: var(--state-text-offline); }
.tone-idle { color: var(--text-primary); }
/* 예정·베타처럼 상태가 아닌 중립 강조. 상태색을 쓰지 않는다. */
.tone-accent { color: var(--accent); }

/* 상태 점. ★단절만 0.5Hz 로 깜빡인다 — 1Hz 이하(A-16-2), 글자가 늘 함께 있다. */
.dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; flex: none; background: var(--state-idle); }
.dot-stable { background: var(--state-stable); }
.dot-offline { background: var(--state-offline); animation: tsc-blink 2s steps(1, end) infinite; }
.dot-warn { background: var(--state-warn); }
.dot-idle { background: var(--state-idle); }
@keyframes tsc-blink { 50% { opacity: 0.25; } }

/* ★표 안의 숫자를 누를 수 있다는 표시. */
.linky {
  background: none; border: 0; padding: 0; cursor: pointer; display: inline; height: auto;
  color: var(--accent); font: inherit; font-weight: 750;
  text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px;
}
.linky:hover { background: none; }

/* 아이콘 기본 크기. 놓인 자리의 글자색을 따른다 (console-icons.js). */
.ic { width: 16px; height: 16px; flex: none; vertical-align: -3px; }

/* 할 일 배지 — 앰버 채움 + 검은 숫자. 사이드바·탭·처리할 일이 같은 것을 쓴다. */
.badge-amber {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--r-pill); background: var(--state-warn); color: var(--on-warn);
  font-size: 11.5px; font-weight: 850; line-height: 1; font-variant-numeric: tabular-nums;
}

/* ★저사양 PC·접근성. 움직임을 강요하지 않는다 (A-16-4, A-23-4). */
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }


/* 관제 콘솔 — 뼈대: 로그인 · 검은 사이드바 · 본문 머리 · 가로 탭 (A-16-3, 시안 D).
 *
 * ★★배치: [검은 사이드바 300px | 본문]. 상단바는 없다. 사이드바의 주인공은 역할에 따라
 *   다르다 — 회사 계정은 **사업장 목록**(console-rail.js), 사업장 범위가 없는 역할은
 *   **메뉴 그룹 목록**(console-sidebar.js). 메뉴 항목은 본문 머리의 **가로 탭**이다.
 * ★사이드바는 두 테마 모두 검정이다. 고른 칸만 흰 블록 + 바이올렛 막대.
 * ★좁은 화면(≤900px)의 위쪽 띠는 console-responsive.css 에 있다.
 */

/* ── 로그인 · 가입 · 재설정 ─────────────────────────────────────────────── */

.login { display: grid; place-items: center; min-height: 100vh; padding: 24px; }
/* ★`.card.` 을 붙인다 — 부품 CSS 의 `.card` 가 뒤에 이어져 선 모양을 덮어쓴다. */
.card.login-card {
  width: min(440px, 100%); margin: 0; padding: 34px 32px 28px;
  border: var(--rule-w) solid var(--rule); border-radius: 0; background: var(--bg-base);
}
.login-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 26px; }
.login-card h1 { font-size: 40px; font-weight: 950; letter-spacing: -0.045em; line-height: 1.05; margin: 0 0 8px; }
.login-card label { display: block; margin: 18px 0 0; font-size: 12px; font-weight: 800; letter-spacing: 0.02em; color: var(--text-muted); }
.login-card input { display: block; width: 100%; margin-top: 7px; padding: 11px 13px; font-size: 14px; border-width: 2px; border-color: var(--rule); }
.login-card button { width: 100%; height: 46px; margin-top: 24px; font-size: 14.5px; }
.login-card .center { text-align: center; margin-top: 18px; }
.login-card .hint { display: block; margin-top: 6px; font-size: 11.5px; font-weight: 450; line-height: 1.55; color: var(--text-muted); }
.login-card .hint code { font-size: 10px; }

/* 브랜드 표 — 로그인과 사이드바가 같은 모양을 쓴다. */
.brand-mark {
  width: 36px; height: 36px; flex: none; border-radius: 8px;
  display: grid; place-items: center; font-weight: 900; font-size: 19px; letter-spacing: -0.02em;
  color: var(--on-accent); background: var(--accent-fill);
}
.brand-name { font-weight: 900; font-size: 21px; letter-spacing: -0.03em; line-height: 1; white-space: nowrap; }
.brand-name small { margin-left: 3px; font-weight: 700; font-size: 12px; letter-spacing: 0; color: var(--text-muted); }

/* ── 앱 뼈대 ─────────────────────────────────────────────────────────────── */

#app { display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); min-height: 100vh; }
#app[hidden] { display: none; }

/* ── 사이드바 ───────────────────────────────────────────────────────────── */

.rail {
  background: var(--rail-bg); color: var(--rail-text);
  border-right: 1px solid var(--rail-hair); min-width: 0; position: relative;
}
/* ★본문이 길어도 사이드바는 늘 보인다. 길면 사이드바 안에서만 스크롤한다. */
.rail-in { position: sticky; top: 0; height: 100vh; overflow-y: auto; display: flex; flex-direction: column; }
.rail-brand { display: flex; align-items: center; gap: 12px; padding: 22px 24px 18px; }
.rail .brand-name small { color: var(--rail-muted); }
.rail-me { display: none; }
.rail-co {
  margin: 0 24px; padding: 12px 0 14px; border-top: 1px solid var(--rail-hair);
  display: flex; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--rail-muted);
}
.rail-co b { color: var(--rail-text); font-weight: 750; }
.rail-co:empty { display: none; }

/* 플랫폼 관리자의 사업장 범위 상자. ★상자가 숨어 있으면 이름표도 함께 숨긴다.
 * ★사이드바 줄과 같은 모양으로 — 굵은 이름, 가는 선, 오른쪽 «▾». 기본 상자 모양은 걷어 낸다.
 *  화살표는 글자다(이미지 아님 — CSP 가 data: 이미지를 막는다). */
.rail-scope { display: block; position: relative; padding: 4px 24px 10px; }
.rail-scope:has(> select[hidden]) { display: none; }
.rail-scope-label { display: block; margin-bottom: 6px; font-size: 11px; font-weight: 800; letter-spacing: 0.08em; color: var(--rail-muted); }
.rail-scope::after {
  content: "▾"; position: absolute; right: 38px; bottom: 23px; font-size: 16px; line-height: 1;
  color: var(--rail-muted); pointer-events: none;
}
.rail .scope-select {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 44px; padding: 0 36px 0 14px; border-radius: 6px;
  color: var(--rail-text); background: transparent; color-scheme: dark;
  border: 1px solid var(--rail-hair); font-size: 15px; font-weight: 800; letter-spacing: -0.02em; cursor: pointer;
}
.rail .scope-select option { color: var(--rail-text); background: var(--rail-bg); font-weight: 650; }
.rail .scope-select:hover { border-color: var(--rail-muted); }
/* ★★한 사업장만 보고 있을 때 바이올렛 테두리 — 필터가 걸린 채로 숫자를 읽는 오독을 막는다.
 *  ★상태색을 쓰지 않는다. «한 곳만 보고 있다» 는 이상 상태가 아니다 (A-16-1). */
.rail .scope-select.is-narrowed { border-color: var(--rail-accent); box-shadow: inset 4px 0 0 var(--accent-fill); }

.rail-label {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 18px 24px 8px; font-size: 11px; font-weight: 800; letter-spacing: 0.08em; color: var(--rail-muted);
}
.rail-rows { list-style: none; margin: 0; padding: 0 12px; display: flex; flex-direction: column; gap: 2px; }
.rail-rows > li { min-width: 0; }
/* 한 줄 = [점·아이콘 | 이름·상태·숫자 줄 | 오늘 건수]. ★전역 `button` 모양을 전부 걷어 낸다. */
.rail-row {
  position: relative; display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; column-gap: 10px;
  align-items: start; width: 100%; height: auto; padding: 12px 12px 12px 14px; margin: 0;
  border: 0; border-radius: 6px; background: transparent; color: var(--rail-text);
  font: inherit; text-align: left; white-space: normal; cursor: pointer;
}
.rail-row:where(:not(.on)):hover { background: var(--rail-hover); }
.rail-row .dot { margin: 6px 0 0; }
.rail-ic { color: var(--rail-muted); padding-top: 1px; }
.rail-ic .ic { width: 16px; height: 16px; }
.rail-main { display: flex; flex-direction: column; min-width: 0; }
.rail-name { font-size: 16px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.3; overflow-wrap: anywhere; }
.rail-code { margin-left: 6px; font-size: 10.5px; font-weight: 800; letter-spacing: 0.06em; color: var(--rail-muted); }
.rail-st { font-size: 12px; font-weight: 750; margin-top: 2px; }
.rail-meta { font-size: 12px; color: var(--rail-muted); margin-top: 1px; }
.rail-count { text-align: right; font-size: 22px; font-weight: 900; letter-spacing: -0.03em; line-height: 1.1; white-space: nowrap; }
.rail-count small { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0; color: var(--rail-muted); }
.rail-all .rail-name { font-size: 15px; }
.rail-st-stable { color: var(--rail-state-stable); }
.rail-st-warn { color: var(--rail-state-warn); }
.rail-st-offline { color: var(--rail-state-offline); }
.rail-st-idle { color: var(--rail-state-idle); }
/* ★고른 칸 = 흰 블록 + 바이올렛 막대. 색만으로 말하지 않게 막대(모양)가 함께 있다. */
.rail-row.on { background: var(--rail-sel-bg); color: var(--rail-sel-text); cursor: default; }
.rail-row.on::before {
  content: ""; position: absolute; left: -12px; top: 8px; bottom: 8px; width: 5px;
  background: var(--accent-fill); border-radius: 0 3px 3px 0;
}
.rail-row.on :is(.rail-meta, .rail-code, .rail-count small, .rail-ic) { color: var(--rail-sel-muted); }
.rail-row.on .rail-st-stable { color: var(--rail-sel-state-stable); }
.rail-row.on .rail-st-warn { color: var(--rail-sel-state-warn); }
.rail-row.on .rail-st-offline { color: var(--rail-sel-state-offline); }
.rail-row.on .rail-st-idle { color: var(--rail-sel-state-idle); }
.rail-row .badge-amber { margin-top: 2px; }
.rail-sep { height: 1px; background: var(--rail-hair); margin: 6px 12px; }
.rail-empty { margin: 4px 24px; font-size: 12px; color: var(--rail-muted); }
.rail-fill { flex: 1; min-height: 16px; }

/* 처리할 일 — 밀린 일만. 0 이면 통째로 숨는다(console-sidebar.js). */
.rail-todo { margin: 0 24px 16px; padding: 14px 0 0; border-top: 1px solid var(--rail-hair); }
.rail-todo h3 { margin: 0 0 6px; font-size: 11px; font-weight: 800; letter-spacing: 0.08em; color: var(--rail-muted); }
.todo-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  height: auto; padding: 7px 0; margin: 0; border: 0; border-radius: 0; background: none;
  color: var(--rail-text); font-size: 13px; font-weight: 650; text-align: left;
}
.todo-row:hover { background: none; text-decoration: underline; text-underline-offset: 3px; }

.rail-foot { padding: 16px 24px 20px; border-top: 1px solid var(--rail-hair); }
.user-chip { display: flex; align-items: center; gap: 10px; min-width: 0; }
.rail .avatar { width: 32px; height: 32px; font-size: 14px; font-weight: 850; border: 0; background: var(--av); color: var(--rail-sel-text); }
.user-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
#whoName { font-weight: 800; font-size: 14px; color: var(--rail-text); }
#whoKind {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0; margin: 0;
  background: none; border: 0; font-size: 11.5px; font-weight: 650; color: var(--rail-accent);
}
#whoKind::before { content: none; }
.rail-btns { display: flex; gap: 6px; margin-top: 12px; }
.rail-btns > button, .theme-toggle {
  flex: 1; height: 32px; padding: 0 8px; border-radius: 6px; font-size: 12px; font-weight: 650;
  background: transparent; color: var(--rail-text); border: 1px solid var(--rail-hair);
}
.rail-btns > button:where(:not(:disabled)):hover, .theme-toggle:hover { background: var(--rail-hover); }
.theme-toggle { display: flex; width: 100%; margin-top: 6px; gap: 8px; justify-content: center; }
/* 반은 흰, 반은 검은 동그라미 — «테마» 를 뜻하는 기호. 글자가 함께 있다. */
.theme-swatch {
  width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid var(--rail-text);
  background: linear-gradient(90deg, var(--rail-text) 50%, transparent 50%);
}
.nav-scrim { display: none; }

/* ── 본문 ───────────────────────────────────────────────────────────────── */

/* ★본문 폭을 제한한다. 24인치 화면에서 표가 통째로 늘어나면 한 줄을 눈으로 따라가지 못한다. */
main { padding: 0 40px 72px; min-width: 0; }
main > * { max-width: 1480px; }
main > .wide { max-width: none; }

/* 머리 — 작은 위치 + 큰 제목 + 기준 시각·새로 고침 + 가로 탭. */
.page-head { margin: 0 0 30px; }
.mast { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 24px; padding-top: 30px; flex-wrap: wrap; }
.mast-l { min-width: 0; }
.page-head .crumb { display: flex; gap: 8px; align-items: center; font-size: 12px; font-weight: 750; letter-spacing: 0.02em; color: var(--text-muted); }
.crumb-group { color: var(--accent); }
.page-head h1 {
  margin: 6px 0 0; font-size: clamp(38px, 4.2vw, 60px); line-height: 1.02;
  font-weight: 950; letter-spacing: -0.045em; overflow-wrap: anywhere;
}
/* 제목 아래 한 줄 — 이 화면이 사이드바에서 고른 사업장을 따르는가(console-rail.js `pageScopeHtml`).
 * ★사각형은 «범위» 표시다(바이올렛 = 선택). 상태색이 아니다. */
.mast-scope { display: flex; align-items: center; gap: 9px; margin: 12px 0 0; font-size: 13.5px; font-weight: 650; color: var(--text-muted); }
.mast-scope::before { content: ""; flex: none; width: 10px; height: 10px; background: var(--accent-fill); }
.mast-scope b { color: var(--text-primary); font-weight: 850; }
.mast-r { display: flex; align-items: center; gap: 12px; padding-bottom: 6px; white-space: nowrap; }
.asof { font-size: 12.5px; color: var(--text-muted); font-weight: 650; }

/* 가로 탭. ★현재 탭은 굵은 글자 + 5px 바이올렛 밑줄 — 색만으로 말하지 않는다. */
.tabbar { margin-top: 24px; }
.tabs-row {
  display: flex; gap: 30px; border-bottom: var(--rule-w) solid var(--rule);
  overflow-x: auto; scrollbar-width: none;
}
.tabs-row::-webkit-scrollbar { display: none; }
.tab {
  position: relative; display: inline-flex; align-items: center; gap: 7px; flex: none;
  height: auto; padding: 14px 0 13px; margin: 0; border: 0; border-radius: 0; background: none;
  font-size: 15.5px; font-weight: 750; letter-spacing: -0.01em; color: var(--text-muted);
}
.tab:where(:not(:disabled)):hover { background: none; color: var(--text-primary); }
.tab.on { color: var(--text-primary); font-weight: 850; }
.tab.on::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 5px; background: var(--accent-fill); }
.tab .nav-count, .subtab .nav-count { margin: 0; }
/* 둘째 줄 — 묶인 그룹(«관리») 안의 화면들. 알약 모양, 고른 것은 검은 블록. */
.subtabs { display: flex; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.subtab {
  height: 34px; padding: 0 15px; border-radius: var(--r-pill); border: 0; background: none;
  font-size: 13.5px; font-weight: 750; color: var(--text-muted);
}
.subtab:where(:not(:disabled)):hover { background: var(--bg-elevated); color: var(--text-primary); }
.subtab.on { background: var(--block); color: var(--block-text); }
.subtab.on:hover { background: var(--block); color: var(--block-text); }
/* 메뉴의 밀린 일 건수 — 앰버 채움. 0 이면 그리지 않는다. */
.nav-count {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--r-pill); font-size: 11.5px; font-weight: 850; line-height: 1;
  background: var(--state-warn); color: var(--on-warn);
}

/* 제목 아래 한 줄 설명 + 오른쪽 주 행동 (console-ui.js `pageIntro`). */
.page-intro {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px 20px; flex-wrap: wrap; margin: 0 0 26px;
}
.page-intro > p { margin: 0; color: var(--text-primary); font-size: 17px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.45; max-width: 760px; }
.page-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-left: auto; }

/* 화면 위 한 줄 알림(showNotice). ★`p.` 를 붙여 특정도를 올린다. */
p.notice-line {
  display: flex; align-items: center; gap: 8px;
  margin: -8px 0 22px; padding: 11px 14px; border-radius: 0;
  font-size: 13px; font-weight: 650; color: var(--text-primary);
  background: var(--accent-tint); border: 0; border-left: 5px solid var(--accent-fill);
}
p.notice-line.is-error { color: var(--state-text-offline); background: var(--bg-elevated); border-left-color: var(--state-offline); }


/* 관제 콘솔 — 부품: 구획(카드) · KPI · 표 · 배지 · 버튼 · 구분 탭 · 검색 · 메뉴 · 모달 · 폼 (시안 D).
 *
 * ★부품의 HTML 은 console-ui.js 가 만든다. 모양을 바꾸려면 이 파일과 그 파일만 본다.
 * ★옛 화면이 직접 적은 HTML(`.card > h2`, `.filter-bar`, `p.empty` …)도 같은 모양으로
 *   서게 이 파일이 함께 받는다 — 화면을 하나씩 고치지 않아도 콘솔 전체가 같은 옷을 입는다.
 * ★★«카드» 는 이제 상자가 아니라 **2px 검은 선으로 시작하는 지면 구획**이다. 클래스 이름
 *   (`.card`)은 화면 코드 수십 곳이 쓰므로 그대로 두고 모양만 바꾼다.
 */

/* ── 구획 (옛 이름 `.card`) ─────────────────────────────────────────────── */

.card {
  background: none; border: 0; border-top: var(--rule-w) solid var(--rule); border-radius: 0;
  padding: 14px 0 0; margin: 0 0 44px; min-width: 0; box-shadow: none;
}
/* 감싸지 않은 표가 화면 전체를 밀어내지 않게 하는 안전망. 표만 구획 안에서 스크롤한다. */
.card:has(> table) { overflow-x: auto; }
.card:empty { display: none; }

/* 구획 머리 — 새 화면(`panel()`)과 옛 화면(`.card > h2`)이 같은 줄에 선다. */
.card-head { display: flex; align-items: flex-end; gap: 12px 16px; flex-wrap: wrap; margin-bottom: 18px; }
.card-title { min-width: 0; flex: 1 1 260px; }
.card-sub { margin: 6px 0 0; font-size: 13px; color: var(--text-muted); line-height: 1.55; }
.card-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.card h2 {
  font-size: 28px; font-weight: 900; letter-spacing: -0.035em; line-height: 1.15; margin: 0 0 16px;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; row-gap: 8px;
}
.card-head h2 { margin: 0; }
/* 옛 구획 머리글: «제목 <span.muted>건수</span> <span.h2-actions>탭·버튼</span>». */
.card h2 > :is(button, .tabs, .h2-actions) { flex: none; max-width: 100%; white-space: nowrap; margin-left: auto; align-self: center; letter-spacing: 0; }
.card h2 > :is(button, .tabs, .h2-actions) ~ :is(button, .tabs, .h2-actions) { margin-left: 0; }
.h2-actions { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 13px; font-weight: 750; letter-spacing: 0; }
.card h2 .muted { margin: 0; font-weight: 650; font-size: 14px; letter-spacing: -0.01em; }
/* 건수 — 제목 옆 바이올렛 숫자. */
.count { font-size: 0.72em; font-weight: 850; letter-spacing: -0.02em; color: var(--accent); }
.card > .table-wrap:last-child, .card > table:last-child { margin-bottom: 0; }
/* 안쪽 작은 구획(stats-grid 등의 h3)도 같은 무게로. */
.card h3 { font-size: 18px; font-weight: 900; letter-spacing: -0.03em; }
/* ★★구획 번호 «01» — **모양은 여기 하나다.** 세는 법은 화면 묶음마다 다르다: 운영 화면은
 *  `secNo()` 가 `.sec-no` 를 넣고, 나머지 묶음(console-scr-*.css)은 CSS 카운터가 `::before` 로
 *  센다. 묶음마다 글자 크기·간격·제목 크기를 따로 적었더니 탭을 옮길 때마다 번호와 제목이
 *  달라 보였다(28px 와 32px). 묶음 파일에는 «무엇을 세는가» 만 남긴다. */
.sec-no,
:is(.scr-admin, .scr-stats, .scr-fleet, .scr-pending, .pf, .sx) .card h2::before {
  margin-right: 2px; font-size: 13px; font-weight: 850; letter-spacing: 0.04em;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.card h2:has(> .sec-no),
:is(.scr-admin, .scr-stats, .scr-fleet, .scr-pending, .pf, .sx) .card:not(.error-card) h2 {
  font-size: 32px; letter-spacing: -0.035em;
}

/* ── KPI ────────────────────────────────────────────────────────────────── */
/* ★★2px 검은 테두리 안에 칸을 붙여 세운다. 칸 사이도 2px 선. `kpi-hero` 는 검은 블록이다
 *  (다크 테마에서는 흰 블록으로 뒤집힌다).
 * ★격자가 아니라 **줄 바꿈 flex** 다. 격자는 두 칸짜리 값이 다음 줄로 넘어가면 앞줄 끝에
 *  빈 칸이 남아 테두리가 계단처럼 깨졌다. flex 는 줄마다 남는 폭을 칸들이 나눠 가져
 *  상자가 늘 네모로 닫힌다. */
.kpis {
  display: flex; flex-wrap: wrap; gap: 0;
  margin: 0 0 32px; border-top: var(--rule-w) solid var(--rule); border-left: var(--rule-w) solid var(--rule);
}
.kpi {
  position: relative; display: flex; flex-direction: column; gap: 0; min-width: 0; min-height: 132px;
  flex: 1 1 196px; padding: 18px 20px 16px; border-radius: 0; overflow: hidden;
  border-right: var(--rule-w) solid var(--rule); border-bottom: var(--rule-w) solid var(--rule);
  background: var(--bg-base); color: inherit; text-decoration: none; box-shadow: none;
}
.kpi-top { display: flex; align-items: center; gap: 6px; min-width: 0; }
.kpi-icon { display: inline-flex; color: var(--text-muted); }
.kpi-icon .ic { width: 15px; height: 15px; }
.kpi-label { font-size: 12px; font-weight: 800; letter-spacing: 0.03em; color: var(--text-muted); }
.kpi-value {
  margin-top: 12px; font-size: 44px; font-weight: 850; line-height: 1; letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text-primary);
}
/* ★숫자는 검정이다. 상태는 칸 위의 막대와 라벨·아이콘 색이 말한다(글자가 함께 있다). */
.kpi .kpi-value[class*="tone-"] { color: var(--text-primary); }
.kpi-unit { font-size: 0.36em; font-weight: 750; letter-spacing: 0; color: var(--text-muted); margin-left: 4px; }
.kpi-sub { margin-top: auto; padding-top: 12px; font-size: 12px; font-weight: 600; color: var(--text-muted); }
.kpi-stable::before, .kpi-warn::before, .kpi-offline::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 5px;
}
.kpi-stable::before { background: var(--state-stable); }
.kpi-warn::before { background: var(--state-warn); }
.kpi-offline::before { background: var(--state-offline); }
.kpi-stable :is(.kpi-label, .kpi-icon) { color: var(--state-text-stable); }
.kpi-warn :is(.kpi-label, .kpi-icon) { color: var(--state-text-warn); }
.kpi-offline :is(.kpi-label, .kpi-icon) { color: var(--state-text-offline); }
/* 히어로 — 검은 블록, 숫자 58px. ★화면이 고른다(`kpiRow` 의 `hero`). */
.kpi.kpi-hero { flex: 2 1 280px; background: var(--block); color: var(--block-text); }
.kpi.kpi-hero .kpi-value { color: var(--block-text); font-size: 58px; letter-spacing: -0.05em; }
.kpi.kpi-hero :is(.kpi-label, .kpi-icon, .kpi-sub, .kpi-unit) { color: var(--block-muted); }
/* 반전 블록 위의 상태 라벨은 블록용 묶음을 쓴다 — 흰 바탕용 짙은 상태 글자는 검정 위에서 안 읽힌다. */
.kpi.kpi-hero.kpi-stable :is(.kpi-label, .kpi-icon) { color: var(--inv-text-stable); }
.kpi.kpi-hero.kpi-warn :is(.kpi-label, .kpi-icon) { color: var(--inv-text-warn); }
.kpi.kpi-hero.kpi-offline :is(.kpi-label, .kpi-icon) { color: var(--inv-text-offline); }
/* 검은 블록 둘이 나란하면 사이 2px 선이 바탕과 같은 색이라 사라진다 — 블록 안의 가는 선으로 가른다. */
.kpis > .kpi.kpi-hero:has(+ .kpi-hero) { border-right-color: var(--block-hair); }
/* 누르면 그 화면으로 가는 KPI (`kpiRow` 의 `go`). 누를 수 있다는 것이 보여야 한다. */
.kpi-link { cursor: pointer; transition: background 0.15s; }
.kpi-link:hover { text-decoration: none; background: var(--bg-elevated); }
.kpi-link.kpi-hero:hover { background: var(--block); }
.kpi-link .kpi-sub::after { content: " →"; font-weight: 850; color: var(--text-primary); }
.kpi-link.kpi-hero .kpi-sub::after { color: var(--block-text); }
/* 10자 이상인 값(kpiRow 가 붙인다)은 두 칸. flex 줄에서는 폭이 두 배, 화면이 KPI 를
 *  격자로 세운 곳에서는 두 칸을 차지한다. 모바일에서는 한 줄 전체가 된다. */
.kpi.kpi-wide { flex: 2 1 392px; }
.kpi.kpi-wide { grid-column: span 2; }
/* 글자 값(상태·이메일·버전·시각)은 큰 숫자 크기로 두면 서너 줄로 쪼개진다. */
.kpis-text .kpi-value {
  font-size: 22px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.3;
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
}

/* ── 표 ─────────────────────────────────────────────────────────────────── */
/* ★머리글 밑만 2px 검은 선, 행 사이는 가는 선. 표 안에 굵은 선을 더 긋지 않는다. */

table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; }
th {
  text-align: left; font-size: 11px; font-weight: 800; letter-spacing: 0.03em; color: var(--text-muted);
  padding: 12px 12px 10px; border-bottom: var(--rule-w) solid var(--rule); background: none;
  /* ★★머리글은 절대 세로로 쌓지 않는다. 빈 표에서는 머리글이 열의 최소폭을 잡는 유일한 버팀목이다. */
  white-space: nowrap;
}
td { padding: 11px 12px; border-bottom: 1px solid var(--border-hair); vertical-align: middle; }
th:first-child, td:first-child { padding-left: 0; }
th:last-child, td:last-child { padding-right: 0; }
tbody tr { transition: background 0.12s; }
tbody tr:hover > td { background: var(--bg-elevated); }
/* ★★한국어는 어절 경계 없이도 글자마다 줄바꿈된다. `break-word` — `anywhere` 는 keep-all 을 되돌린다. */
td, th { word-break: keep-all; overflow-wrap: break-word; }
td strong { font-weight: 800; }
td.num { font-weight: 650; }

/* ★★열이 많은 표는 가로로 민다 — 표 하나만 스크롤하고 화면 전체는 밀리지 않는다. */
.table-wrap { overflow-x: auto; }
.table-wrap > table { min-width: 900px; }
.table-wrap.narrow > table { min-width: 560px; }
.table-scroll { max-height: 420px; overflow: auto; }
.table-scroll thead th { position: sticky; top: 0; background: var(--bg-base); z-index: 1; }
tr.is-canceled > td:not(.actions) { color: var(--text-muted); }
tr.is-canceled > td:not(.actions) .muted { color: var(--text-muted); }
.row-click { cursor: pointer; }
.row-click:hover td { background: var(--bg-elevated); }
/* 고른 줄 — 바이올렛 옅은 바탕 + 왼쪽 막대. */
tr.is-selected > td { background: var(--accent-tint); }
tr.is-selected > td:first-child { box-shadow: inset 5px 0 0 var(--accent-fill); }

/* ★★막대는 대개 장식이다. 막대가 본문인 표만 `table.bar-chart` 로 옵트인한다. */
.bar-cell { width: 96px; min-width: 80px; }
table.bar-chart .bar-cell { width: 55%; min-width: 0; }
/* 한 가지 색(검정). 막대마다 색을 바꾸면 색이 뜻을 가진 것처럼 읽힌다. */
.bar { display: block; height: 8px; border-radius: 0; min-width: 2px; background: var(--text-primary); }

/* 사람 칸: 동그라미 + 이름 + 둘째 줄 (console-ui.js `avatar`). */
.person { display: flex; align-items: center; gap: 12px; min-width: 0; }
.person-text { min-width: 0; }
.person-name { font-weight: 800; color: var(--text-primary); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.person-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 2px; font-size: 12px; color: var(--text-muted); }
/* ★색은 이름에서 정해진다(차트 팔레트). 상태색이 아니다 — 테두리로만 쓰고 글자는 본문색. */
.avatar {
  --av: var(--accent-fill);
  width: 34px; height: 34px; flex: none; border-radius: 50%;
  display: inline-grid; place-items: center; font-weight: 850; font-size: 13px;
  color: var(--text-primary); background: color-mix(in srgb, var(--av) 20%, var(--bg-base));
  border: 2px solid var(--av);
}
.row-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }

/* ── 배지 · 상태 · 칩 ─────────────────────────────────────────────────────── */

/* ★배지는 «값» 이 아니라 «라벨» 이다. 테두리 꼬리표 — 알약 안에서 글자가 쪼개지지 않게. */
.badge {
  white-space: nowrap; display: inline-flex; align-items: center; gap: 6px;
  padding: 0 6px; border-radius: 4px; border: 1.5px solid currentColor; background: none;
  font-size: 11px; font-weight: 800; letter-spacing: 0.02em; line-height: 18px; color: var(--text-muted);
}
.badge-accent { color: var(--accent); }
.badge-alt { color: var(--accent-alt); }
/* ★상태 배지는 점 + 글자다(테두리 없이). 색만으로 말하지 않는다 (A-16-2). */
.badge:is(.badge-stable, .badge-warn, .badge-offline, .badge-idle) {
  border: 0; padding: 0; font-size: 12.5px; font-weight: 750; letter-spacing: 0;
}
.badge:is(.badge-stable, .badge-warn, .badge-offline, .badge-idle)::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%; flex: none; background: currentColor;
}
.badge-stable { color: var(--state-text-stable); }
.badge.badge-stable::before { background: var(--state-stable); }
.badge-warn { color: var(--state-text-warn); }
.badge.badge-warn::before { background: var(--state-warn); }
.badge-offline { color: var(--state-text-offline); }
.badge.badge-offline::before { background: var(--state-offline); animation: tsc-blink 2s steps(1, end) infinite; }
.badge-idle { color: var(--state-text-idle); }
.badge.badge-idle::before { background: var(--state-idle); }

/* 점 + 글자 상태 (console-ui.js `stateTag`). */
.state { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 750; white-space: nowrap; }
.state > i { width: 9px; height: 9px; border-radius: 50%; flex: none; background: currentColor; }
.state-stable { color: var(--state-text-stable); }
.state-stable > i { background: var(--state-stable); }
.state-warn { color: var(--state-text-warn); }
.state-warn > i { background: var(--state-warn); }
.state-offline { color: var(--state-text-offline); }
.state-offline > i { background: var(--state-offline); animation: tsc-blink 2s steps(1, end) infinite; }
.state-idle { color: var(--state-text-idle); }
.state-idle > i { background: var(--state-idle); }
/* 상태가 아닌 «진행» 표시(합의 완료 등)는 검은 점 + 본문 글자다 — 바이올렛을 상태로 쓰지 않는다. */
.state-accent { color: var(--text-primary); }
.state-accent > i { background: var(--text-primary); }

/* 작은 꼬리표 (권한 등) — 배지보다 조용하게. 상태가 아니라 속성이다. */
.chips { display: flex; flex-wrap: wrap; gap: 4px; }
td .badge + .chips { margin-top: 6px; }
.chip {
  font-size: 11px; font-weight: 700; padding: 0 6px; line-height: 18px; border-radius: 4px; white-space: nowrap;
  color: var(--text-muted); background: none; border: 1px solid var(--border-hair);
}
.chip-on { color: var(--accent); border-color: currentColor; }

/* ── 버튼 ───────────────────────────────────────────────────────────────── */
/* ★기본 = 검은 2px 테두리. 주 행동 = 바이올렛 채움. 상태(hover)는 `:where()` 로 특정도를 낮춘다. */

button {
  font: inherit; font-size: 13px; font-weight: 750; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 38px; padding: 0 16px; border-radius: var(--r-ctl);
  border: var(--rule-w) solid var(--rule); background: transparent; color: var(--text-primary);
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  /* «조/회», «전/체» 처럼 버튼 글자가 쪼개지지 않게 한다. */
  white-space: nowrap;
}
button:where(:not(:disabled)):hover { background: var(--bg-elevated); }
button.primary { background: var(--accent-fill); color: var(--on-accent); border-color: var(--accent-fill); }
button.primary:where(:not(:disabled)):hover { background: var(--accent-hover); border-color: var(--accent-hover); }
button.danger { color: var(--state-text-offline); border-color: currentColor; }
button.danger:where(:not(:disabled)):hover { background: color-mix(in srgb, var(--state-offline) 10%, transparent); }
button.ghost { background: transparent; color: var(--text-primary); border-color: var(--rule); }
button.ghost:where(:not(:disabled)):hover { background: var(--bg-elevated); }
button.sm { height: 30px; padding: 0 11px; font-size: 12px; border-width: 1.5px; }
button .ic { width: 15px; height: 15px; }
/* 누를 수 없는 버튼은 흐리게. 옆에 막힌 이유를 문구로 적는다. */
button:disabled { opacity: 0.4; cursor: not-allowed; }

/* 링크 모양 버튼(내려받기 등). <a> 와 <button> 이 같은 모양이 된다. */
.btn {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px;
  font: inherit; font-size: 12px; font-weight: 750; color: var(--text-primary);
  background: transparent; border: 1.5px solid var(--rule); border-radius: var(--r-ctl);
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
a.btn:hover { text-decoration: none; background: var(--bg-elevated); }

/* ── 구분 탭 ─────────────────────────────────────────────────────────────── */
/* 묶음 하나에 버튼 여럿 — 한 번에 하나만 켜진다. 고른 칸은 검은 블록. */

.tabs {
  display: inline-flex; flex-wrap: wrap; gap: 0; padding: 0; margin-left: auto; overflow: hidden;
  border-radius: var(--r-ctl); border: var(--rule-w) solid var(--rule); background: none;
}
.h2-actions .tabs { margin-left: 0; }
.tabs button {
  flex: none; height: 32px; padding: 0 12px; border: 0; border-radius: 0; background: transparent;
  font-size: 12.5px; font-weight: 750; color: var(--text-primary);
}
.tabs button + button { border-left: 1px solid var(--border-hair); }
.tabs button:where(:not(:disabled)):hover { background: var(--bg-elevated); }
.tabs button.active, .tabs button.active:hover { background: var(--block); color: var(--block-text); }
.seg-count { margin-left: 6px; font-size: 11.5px; font-weight: 750; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.tabs button.active .seg-count { color: var(--block-muted); }

/* ── 검색 · 거르기 줄 ─────────────────────────────────────────────────────── */

.toolbar, .filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 18px; }
.toolbar > label.muted { margin: 0; }
.toolbar-spacer { flex: 1 1 0; }
.search { position: relative; display: flex; align-items: center; flex: 1 1 260px; min-width: 200px; max-width: 440px; }
.search > .ic { position: absolute; left: 12px; color: var(--text-muted); pointer-events: none; }
.search > input { width: 100%; padding-left: 36px; }
/* ★검색칸은 2px 검은 테두리 — 지면에서 «쓸 수 있는 곳» 이 바로 보인다. */
:is(.search, .filter-bar, .toolbar) input[type="search"] { height: 38px; border: var(--rule-w) solid var(--rule); }
.toolbar input:not([type=checkbox]):not([type=radio]), .filter-bar input[type="search"] {
  flex: 1 1 240px; min-width: 200px; margin: 0;
}
.search > input { flex: 1 1 auto !important; min-width: 0 !important; }
.filter-bar .check, .toolbar .check {
  display: inline-flex; align-items: center; gap: 6px; margin: 0;
  font-size: 12.5px; font-weight: 650; color: var(--text-primary); white-space: nowrap; cursor: pointer;
}
.filter-bar .check input, .toolbar .check input { width: auto; margin: 0; }
.filter-bar .tabs { margin-left: 0; }
.inline { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.inline input { flex: 1 1 180px; min-width: 150px; }

/* ── 줄 작업 메뉴 (⋯) ─────────────────────────────────────────────────────── */
/* ★창은 `position: fixed` — 표의 가로 스크롤 상자에 잘리지 않게 (console-ui.js). */

details.menu { position: relative; display: inline-block; }
details.menu > summary {
  list-style: none; cursor: pointer; width: 32px; height: 30px; border-radius: var(--r-ctl);
  display: inline-grid; place-items: center; color: var(--text-primary); border: 1.5px solid var(--border-hair);
}
details.menu > summary::-webkit-details-marker { display: none; }
details.menu > summary .ic { width: 18px; height: 18px; }
details.menu > summary:hover, details.menu[open] > summary { border-color: var(--rule); background: var(--bg-elevated); }
.menu-panel {
  position: fixed; z-index: 70; min-width: 190px; padding: 6px;
  display: flex; flex-direction: column; gap: 1px;
  border-radius: var(--r-ctl); background: var(--bg-base); border: var(--rule-w) solid var(--rule);
  box-shadow: var(--shadow-pop); text-align: left;
}
/* 화면이 원래 그리던 버튼(ghost sm · danger …)이 그대로 들어온다 — 여기서 메뉴 줄로 바꿔 입힌다. */
.menu-panel > button, .menu-panel > a {
  display: flex; width: 100%; height: auto; justify-content: flex-start; margin: 0;
  padding: 9px 10px; border: 0; border-radius: 4px; box-shadow: none;
  background: transparent; color: var(--text-primary); font-size: 13px; font-weight: 700; text-align: left;
}
.menu-panel > button:where(:not(:disabled)):hover, .menu-panel > a:hover { background: var(--bg-elevated); text-decoration: none; }
.menu-panel > button.primary { color: var(--accent); }
.menu-panel > button.danger { color: var(--state-text-offline); }
.menu-panel > button.danger:where(:not(:disabled)):hover { background: color-mix(in srgb, var(--state-offline) 10%, transparent); }
.menu-panel > hr { border: 0; border-top: 1px solid var(--border-hair); margin: 4px 2px; }

/* ── 안내 (접는 설명) ─────────────────────────────────────────────────────── */

details.help { margin: 0 0 20px; border-top: 1px solid var(--border-hair); border-bottom: 1px solid var(--border-hair); }
details.help > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 8px;
  padding: 10px 0; font-size: 13px; font-weight: 750; color: var(--text-primary);
}
details.help > summary::-webkit-details-marker { display: none; }
details.help > summary .ic { color: var(--accent); }
details.help > summary::after {
  content: ""; margin-left: auto; width: 7px; height: 7px; transform: rotate(45deg);
  border-right: 2px solid var(--text-primary); border-bottom: 2px solid var(--text-primary);
  transition: transform 0.15s;
}
details.help[open] > summary::after { transform: rotate(-135deg); }
.help-body { padding: 0 0 14px; font-size: 13px; line-height: 1.7; color: var(--text-soft); }
.help-body p { margin: 0 0 6px; }
.help-body p:last-child { margin: 0; }
.help-body ul { margin: 0; padding-left: 18px; }

/* ── 빈 상태 ─────────────────────────────────────────────────────────────── */

.empty { color: var(--text-muted); padding: 32px 0; text-align: center; margin: 0; font-size: 13px; }
.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 48px 20px; text-align: center; color: var(--text-muted);
}
.empty-state > .ic {
  width: 22px; height: 22px; padding: 12px; box-sizing: content-box; color: var(--text-primary);
  border-radius: 50%; border: var(--rule-w) solid var(--rule);
}
.empty-state p { margin: 0; max-width: 500px; font-size: 14px; font-weight: 600; line-height: 1.65; color: var(--text-soft); }
.empty-actions { display: flex; justify-content: center; gap: 8px; margin: 0 0 8px; }

/* ── 페이지 넘김 ─────────────────────────────────────────────────────────── */
.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-top: 0; padding-top: 14px; border-top: var(--rule-w) solid var(--rule);
}
.pager-nav { display: inline-flex; align-items: center; gap: 6px; }
.pager-now { font-size: 12.5px; font-weight: 750; color: var(--text-primary); padding: 0 8px; }

/* ── 모달 · 폼 ───────────────────────────────────────────────────────────── */

.modal {
  position: fixed; inset: 0; z-index: 50; padding: 24px;
  background: color-mix(in srgb, var(--block) 45%, transparent);
  overflow-y: auto; display: grid; place-items: start center;
}
.card.modal-card {
  width: min(660px, 100%); margin: 48px 0 0; position: relative;
  padding: 28px 28px 24px; border-radius: 0; box-shadow: var(--shadow-pop);
  background: var(--bg-base); border: var(--rule-w) solid var(--rule);
}
.modal-card h2 { font-size: 26px; padding-right: 40px; }
/* 닫기 ✕ — console.js 가 모달을 열 때 카드 맨 앞에 넣는다. */
.modal-x { position: absolute; top: 16px; right: 16px; width: 32px; padding: 0; }
body:has(.modal:not([hidden])) { overflow: hidden; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
.form-grid label, .modal-card > label {
  display: block; font-size: 12px; font-weight: 800; letter-spacing: 0.02em; color: var(--text-muted); margin-top: 10px;
}
.form-grid input, .modal-card select, .modal-card textarea, .form-grid select,
.modal-card > label > input:not([type=checkbox]):not([type=radio]) {
  display: block; width: 100%; margin-top: 7px;
}
.modal-card input[readonly] {
  background: var(--bg-elevated);
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 12px;
}
.modal-card .note-body { margin-top: 6px; font-size: 13px; color: var(--text-primary); }
.form-grid label > .muted, .modal-card > label > .muted { display: block; margin: 3px 0 0; font-size: 11.5px; font-weight: 450; letter-spacing: 0; }
.form-grid > label:has(> textarea) { grid-column: 1 / -1; }
label.check {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px;
  margin: 12px 0 0; font-size: 13px; font-weight: 650; letter-spacing: 0; color: var(--text-primary); cursor: pointer;
}
label.check > input { width: auto; margin: 0; flex: none; }
label.check > .muted { flex-basis: 100%; margin: 0 0 0 21px; font-size: 11.5px; }
.form-grid label.check { align-self: end; padding-bottom: 9px; }
.form-grid label.check input { display: inline-block; width: auto; margin: 0; padding: 0; }
details.sub-form { margin-top: 16px; padding: 12px 0; border-top: 1px solid var(--border-hair); border-bottom: 1px solid var(--border-hair); }
details.sub-form > summary { cursor: pointer; font-size: 13.5px; font-weight: 800; }
details.card > summary { cursor: pointer; font-size: 18px; font-weight: 900; letter-spacing: -0.03em; }
.perms { margin: 16px 0 0; padding: 12px 14px; border: 1.5px solid var(--edge-light); border-radius: var(--r-ctl); }
.perms legend { font-size: 12px; font-weight: 800; color: var(--text-muted); padding: 0 6px; }
.perms .check { display: inline-flex; align-items: center; gap: 6px; margin: 0 16px 0 0; font-size: 13px; color: var(--text-primary); }
.perms .check input { width: auto; margin: 0; }
.form-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 22px; }

/* ── 상세 요약 ── ★라벨 위, 값 아래. 값은 굵게. */
.detail-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px; margin: 14px 0 20px;
}
.detail-grid > div { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.detail-grid .muted { font-size: 11px; font-weight: 800; letter-spacing: 0.03em; margin: 0; }
.detail-grid strong { font-size: 16px; font-weight: 850; letter-spacing: -0.01em; overflow-wrap: anywhere; }
.detail-grid strong.value-lg { font-size: 28px; font-weight: 900; letter-spacing: -0.03em; }

/* ── 승인 대기 카드 ── ★한 건씩 읽고 판단하는 일이라 표가 아니라 칸으로. */
.approval-row { border: var(--rule-w) solid var(--rule); border-radius: 0; padding: 18px 20px; margin-bottom: 14px; background: var(--bg-base); }
.approval-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.approval-head strong { font-size: 18px; font-weight: 900; letter-spacing: -0.02em; }
.approval-row .detail-grid { margin: 12px 0 14px; }
.approval-row .form-actions { margin: 0; }


/* 관제 콘솔 — 화면별 모양: 차트 · 지도 · 수수료 트리 · 사업장 · 통계 · 영업 · 정산.
 *
 * ★공용 부품으로 설 수 없는 것만 여기 둔다. 두 화면 이상이 쓰기 시작하면 부품 CSS 로 옮긴다.
 * ★(시안 D) 상자·둥근 모서리·그림자를 걷어 내고 2px 선으로 나눈 지면으로 맞춰 두었다.
 *   화면마다 다듬는 일(분할 보기·히어로 블록)은 각 화면 작업에서 한다.
 */

/* ── 차트 (A-16-3) ──────────────────────────────────────────────────────── */

.chart { width: 100%; height: auto; margin: 4px 0 14px; }
.chart-label { font-size: 11px; fill: var(--text-muted); dominant-baseline: middle; }
.chart-track { fill: var(--bg-elevated); }
/* ★막대는 단일 색(검정)이다. 회사명이 이미 축 라벨이라 색으로 구분할 정보가 없다. */
.chart-bar { fill: var(--text-primary); }
.chart-value { font-size: 11px; fill: var(--text-primary); font-variant-numeric: tabular-nums; }
.chart-grid { stroke: var(--border-hair); stroke-width: 1; }
.chart-tick { font-size: 10px; fill: var(--text-muted); }
.chart-area { fill: color-mix(in srgb, var(--accent) 16%, transparent); stroke: none; }
.chart-line { fill: none; stroke: var(--accent-fill); stroke-width: 2.5; }
.chart-dot { fill: var(--bg-base); stroke: var(--accent-fill); stroke-width: 2; }

/* HTML 가로 막대(이름 | 막대 | 값). SVG 와 달리 글자 크기가 화면 폭을 따라 변하지 않는다. */
.hbar { margin: 4px 0 14px; font-size: 12.5px; }
.hbar-row {
  display: grid; grid-template-columns: minmax(72px, 160px) minmax(0, 1fr) 96px;
  gap: 12px; align-items: center; padding: 4px 0;
}
.hbar-label { color: var(--text-primary); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar-track { height: 8px; border-radius: 0; background: var(--bg-elevated); overflow: hidden; }
.hbar-fill { display: block; height: 100%; border-radius: 0; background: var(--text-primary); }
.hbar-value { text-align: right; font-weight: 850; font-variant-numeric: tabular-nums; }

/* ── 지도 (A-17) ─────────────────────────────────────────────────────────── */

.map {
  position: relative;
  width: 100%; height: 380px; border-radius: 0;
  overflow: hidden; margin-bottom: 14px; background: var(--bg-elevated);
  border: var(--rule-w) solid var(--rule);
}
.map-setup {
  display: grid; place-items: center; height: 100%; padding: 24px;
  color: var(--text-muted); font-size: 12px; text-align: center;
}
/* ★지도는 밝은 배경 위에서 도로·라벨이 읽힌다. filter:invert() 를 쓰지 않는다 (A-17-2) —
 *  핀만 다크 크롬에 맞춘 원형으로 그린다.
 * ★★모양이 종류를, 색이 상태를 말한다 — 계근대는 전자저울, 기사는 트럭.
 *  색만으로 구분하면 색각 이상 사용자와 흑백 캡처에서 둘이 같아 보인다 (A-16-2). */
.map-pin {
  width: 28px; height: 28px; border-radius: 50% 50% 50% 4px;
  transform: rotate(-45deg);
  background: var(--accent);
  border: 2px solid rgba(0, 0, 0, 0.45);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
  display: grid; place-items: center; cursor: pointer;
}
/* 아이콘은 다시 세운다 — 핀만 물방울 모양으로 기울였다. */
.map-pin svg { width: 16px; height: 16px; transform: rotate(45deg); fill: var(--bg-base); pointer-events: none; }
/* 지도 위 한 줄 안내(표시할 위치가 없음 등). 지도 조작을 막지 않는다. */
.map-note {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%); z-index: 2;
  padding: 4px 12px; border-radius: var(--r-pill);
  background: var(--bg-surface); color: var(--text-primary);
  border: 1px solid var(--border-hair); font-size: 12px; pointer-events: none;
  /* left:50% 만 두면 상자가 오른쪽 절반 폭에 갇혀 짧은 문구도 꺾인다. */
  width: max-content; max-width: calc(100% - 24px); text-align: center;
}
#driverMap { height: clamp(360px, calc(100vh - 330px), 680px); }

/* 지도 핀 — 종류별 색. ★툴팁·팝업에 글자가 함께 있어 색만으로 구분하지 않는다. */
.pin-online { background: var(--state-stable); }
.pin-offline { background: var(--state-offline); }
.pin-idle { background: var(--state-warn); }
/* 기사는 상태색을 쓰지 않는다 — 사람의 '상태'를 색으로 판정하지 않는다. */
.pin-driver { background: var(--accent); }
.pin-driver svg { fill: var(--bg-base); }
/* 쓰지 않는 계근대(인증 전·비활성). 목록의 회색 점과 같은 색이다. */
.pin-disabled { background: var(--state-idle); }

/* ★★지도 팝업 — 흰 바탕에 흰 글자가 되는 것을 막는다.
 * MapLibre 팝업은 **자기 배경만 흰색으로 칠하고 글자색은 물려받는다.** 아무 것도 안 하면
 * 흰 상자에 흰 글자가 찍혀 라벨이 통째로 안 보인다. 팝업만 콘솔 카드와 같은 다크 박스로.
 * ★★선택자에 `.map` 을 앞세워 **특정도를 한 단계 올린다.** MapLibre 스타일시트는 지도를
 * 처음 띄울 때 `<head>` **뒤쪽에** 붙는다(console-map.js). 같은 특정도면 나중에 온 쪽이 이긴다. */
.map .maplibregl-popup-content {
  background: var(--bg-surface); color: var(--text-primary);
  border: 1px solid var(--border-hair); border-radius: 10px;
  /* 오른쪽은 닫기(×) 자리를 비워 둔다 — 안 그러면 버튼이 마지막 글자를 덮는다. */
  padding: 8px 26px 8px 12px; font-size: 12px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}
.map .maplibregl-popup-close-button { color: var(--text-muted); font-size: 15px; padding: 0 5px; background: transparent; border: 0; }
.map .maplibregl-popup-close-button:hover { background: transparent; color: var(--text-primary); }
/* 말풍선 꼬리도 같이 칠한다 — 빠뜨리면 흰 삼각형만 덩그러니 남는다. */
.map .maplibregl-popup-anchor-top .maplibregl-popup-tip,
.map .maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.map .maplibregl-popup-anchor-top-right .maplibregl-popup-tip { border-bottom-color: var(--bg-surface); }
.map .maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.map .maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.map .maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip { border-top-color: var(--bg-surface); }
.map .maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--bg-surface); }
.map .maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--bg-surface); }

/* ── 수수료 · 총판 트리 (총판 → 판매사원 → 건별) ──────────────────────────── */

.tree-row.lv0 { cursor: pointer; }
.tree-row.lv0 > td { background: color-mix(in srgb, var(--bg-elevated) 55%, transparent); }
.tree-row.lv1 { cursor: pointer; }
.tree-row.lv1 > td:first-child { padding-left: 34px; }
/* ★들여쓰기로 깊이를 말한다. 색으로만 구분하면 흑백에서 계층이 사라진다. */
.tree-row.lv2 > td:first-child { padding-left: 62px; color: var(--text-primary); }
.tree-row.lv2 { font-size: 12px; }
.tree-row.lv0 > td { font-weight: 750; }
.tree-row.lv0:hover > td, .tree-row.lv1:hover > td { background: var(--accent-tint); }

/* ── 영업 ───────────────────────────────────────────────────────────────── */

/* 판매원 계약 카드 — 한 계약에 붙은 정보를 한 장에서 훑는다. */
.portfolio-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px; margin-top: 4px;
}
.portfolio-grid > div { min-width: 0; }
.portfolio-grid .kpi-label { display: block; margin-bottom: 4px; }

/* ── 다사업장 (사업장 현황 카드) ───────────────────────────────────────────── */
/* ★사업장이 여러 곳인 회사는 «전체» 와 «한 곳만» 을 하루에도 여러 번 오간다.
 *  지금 어느 쪽을 보고 있는지가 화면에 없으면, 한 사업장만 걸러 둔 것을 잊고
 *  «오늘 건수가 반으로 줄었다» 고 읽는다. 선택기와 카드가 그 사실을 계속 말한다. */

/* 사업장 카드 그리드. 280px 이면 «이름 + 상태 배지» 한 줄과 숫자 세 칸이 들어간다. */
.site-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px; margin-bottom: 18px;
}
/* 패딩만 `.card` 보다 줄인다 — 사업장 열 곳이 한 화면에 들어와야 한다 (A-16-3). */
.site-card {
  background: var(--bg-base);
  border: var(--rule-w) solid var(--rule); border-radius: 0;
  padding: 16px 18px 14px 22px; min-width: 0; box-shadow: none;
  /* ★누르면 계근대 표가 펼쳐진다. 누를 수 있다는 사실이 보여야 한다. */
  cursor: pointer; transition: border-color 0.15s;
}
.site-card:hover { background: var(--bg-elevated); }
/* ★키보드로도 펼쳐야 한다(JS 가 `tabindex="0"` 를 붙인다). 이 윤곽선을 지우지 마라. */
.site-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* ★★왼쪽 세로선이 **상태**, 테두리 색이 **선택** 이다. 둘을 같은 자리에 그리면 오프라인
 *  사업장을 고른 순간 상태 표시가 사라진다. ★테두리 대신 inset box-shadow 로 그린다 —
 *  테두리를 3px 로 바꾸면 그 카드만 글자가 2px 밀려 그리드 전체가 어긋나 보인다. */
.site-card.is-bad { box-shadow: inset 5px 0 0 var(--state-offline); }
.site-card.is-warn { box-shadow: inset 5px 0 0 var(--state-warn); }
.site-card.is-selected { border-color: var(--accent-fill); background: var(--accent-tint); }
.site-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.site-card-head strong { font-size: 22px; font-weight: 900; letter-spacing: -0.035em; line-height: 1.2; min-width: 0; }
.site-card-head code { flex: none; }
.site-card-head .badge { margin-left: auto; }
/* 수치줄: 라벨 위, 값 아래 (`.detail-grid` 와 같은 원리지만 카드 안이라 더 좁다). */
.site-card-nums {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
  gap: 8px; margin-top: 12px;
}
.site-card-nums > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.site-card-nums .kpi-label { font-size: 11px; }
.site-card-nums strong { font-size: 22px; font-weight: 850; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
/* ★꼬리의 버튼은 카드 펼침과 다른 일을 한다. JS 에서 `stopPropagation` 을 빠뜨리면
 *  «이 사업장만 보기» 를 누를 때 계근대 표까지 같이 펼쳐진다. */
.site-card-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-hair);
  font-size: 11.5px; color: var(--text-muted);
}
.site-card-foot .actions { margin-left: auto; }
/* 숫자 묶음 (정상 n · 오프라인 n). 카드에도 표 칸에도 한 줄로 붙어 있게 한다. */
.site-nums { display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.site-nums > span { white-space: nowrap; }
/* ★전역 `td` 여백은 카드 안에서 너무 헐렁하다 — 계근대 세 대가 카드 높이를 두 배로 만든다. */
.site-houses { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border-hair); }
.site-houses table { font-size: 11.5px; }
.site-houses th { font-size: 10.5px; padding: 4px 6px; background: none; }
.site-houses td { padding: 5px 6px; }
.site-houses tr:last-child td { border-bottom: 0; }

/* 체크박스 목록 (계정에 사업장 여러 개 배정).
 * ★사업장이 서른 곳인 회사도 있다. 목록이 길어지면 모달이 화면 밖으로 자라 저장 버튼에
 *  손이 닿지 않으므로, 목록 안에서만 스크롤한다. */
.chk-list {
  max-height: 240px; overflow-y: auto; margin-top: 6px;
  background: var(--bg-base); border: 1.5px solid var(--edge-light); border-radius: var(--r-ctl);
}
.chk-list label {
  display: flex; align-items: center; gap: 8px; margin: 0; padding: 7px 10px; cursor: pointer;
  font-size: 13px; color: var(--text-primary);
  /* ★한 항목은 한 줄이다. 그냥 두면 긴 사업장명이 세로로 쌓여 줄 높이가 제각각이 된다. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chk-list label > span { overflow: hidden; text-overflow: ellipsis; }
.chk-list label:hover { background: var(--hover); }
.chk-list input { width: auto; margin: 0; flex: none; }
/* ★★«전 사업장(제한 없음)» 은 켜면 아래 항목을 전부 비활성화한다. 스크롤해서 시야에서
 *  사라지면 회색 체크박스만 보이고 **왜** 그런지가 화면에 없다 — 위에 붙여 둔다. */
.chk-list .all-row {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-elevated); border-bottom: 1px solid var(--border-hair); font-weight: 600;
}

/* 한 줄 알림 (좌표 없는 사업장 안내 등).
 * ★`.muted` 보다 밝게 둔다 — 지도에 안 뜨는 사업장이 몇 곳인지는 «부가 설명» 이 아니라
 *  읽어야 하는 사실이다. */
.site-empty {
  display: block; margin: 0 0 14px; padding: 10px 14px;
  background: var(--bg-elevated); border: 0; border-left: 5px solid var(--text-faint); border-radius: 0;
  font-size: 12.5px; color: var(--text-primary);
}

/* ── 통계 ───────────────────────────────────────────────────────────────── */

/* 조회 조건 줄: 라벨이 위, 입력이 아래. 좁으면 다음 줄로 넘어간다. */
.stats-controls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 12px; margin-bottom: 12px; }
.stats-controls label {
  display: flex; flex-direction: column; gap: 5px; margin: 0;
  font-size: 12px; font-weight: 800; color: var(--text-muted); white-space: nowrap;
}
.stats-controls input:not([type=checkbox]), .stats-controls select { min-width: 120px; font-weight: 400; }
.stats-controls label.check {
  flex-direction: row; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--text-primary); padding-bottom: 9px;
}
.stats-downloads {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 4px; padding-top: 14px; border-top: 1px solid var(--border-hair);
}
/* 분해 카드 격자. 넓으면 두 칸, 좁으면 한 칸. */
.stats-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 520px), 1fr));
  gap: 18px; margin-bottom: 18px; align-items: start;
}
.stats-grid > .card { margin: 0; min-width: 0; }

/* ── 정산 · 수금 (iframe) ─────────────────────────────────────────────────── */
/* 본문 높이를 화면에 맞춰 스크롤을 iframe 안 하나로 만든다. */
.settlement-frame {
  display: block; width: 100%; flex: 1 1 auto; min-height: 420px;
  border: 0; border-radius: 0; background: var(--bg-base);
}
main:has(> .settlement-frame) > .page-head { margin-bottom: 0; }
main:has(> .settlement-frame) {
  display: flex; flex-direction: column;
  height: calc(100dvh - var(--topbar-h)); padding-bottom: 12px;
}

/* ── 계약 카드 (판매원 «내 영업 현황») ─────────────────────────────────────
 * ★표가 아니라 카드다 — 한 계약에 붙은 기간·입금·수수료·메모를 한 장에서 읽고 전화를 건다.
 * ★왼쪽 띠가 **가장 급한 문제**의 색이다(카드의 `is-bad`·`is-warn`). 사업장 카드와 같은 수법이다. */
.contract-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 460px), 1fr));
  gap: 16px; margin-bottom: 18px;
}
details.card > .contract-grid { margin: 14px 0 0; }
.contract-card {
  display: flex; flex-direction: column; gap: 14px; min-width: 0; padding: 18px 20px 18px 24px;
  border-radius: 0; border: var(--rule-w) solid var(--rule); box-shadow: none; background: var(--bg-base);
}
.contract-card.is-bad { box-shadow: inset 5px 0 0 var(--state-offline); }
.contract-card.is-warn { box-shadow: inset 5px 0 0 var(--state-warn); }
.contract-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.contract-title { min-width: 0; flex: 1 1 auto; }
.contract-title h3 { margin: 0; font-size: 20px; font-weight: 900; letter-spacing: -0.03em; }
.contract-title .muted { margin: 2px 0 0; }
.contract-badges { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.contract-foot { display: flex; gap: 8px; justify-content: flex-end; padding-top: 12px; border-top: 1px solid var(--border-hair); }


/* 관제 콘솔 — 좁은 화면 (시안 D). ★맨 끝에 이어 붙는다(assets.STYLES) — 위 규칙을 덮어쓰는 자리다.
 *
 * ★★페이지에 가로 스크롤이 생기면 안 된다. 넘치는 것(사업장 칩·탭)은 **그 줄 안에서만** 민다.
 */

/* ── 가로로 밀리는 줄의 «더 있다» 표시 ──
 * ★탭 줄·사업장 칩·넓은 표는 그 줄 안에서만 민다. 밀 것이 남은 쪽 끝을 흐린다 — 클래스는
 *  console-sidebar.js `markScrollEdges` 가 스크롤 위치를 보고 붙인다(양쪽 다 남으면 둘 다).
 *  ★마스크는 알파만 쓴다 — 색 값은 아무것이나 불투명이면 된다. */
.fade-r { -webkit-mask-image: linear-gradient(90deg, var(--rule) calc(100% - 56px), transparent);
  mask-image: linear-gradient(90deg, var(--rule) calc(100% - 56px), transparent); }
.fade-l { -webkit-mask-image: linear-gradient(90deg, transparent, var(--rule) 56px);
  mask-image: linear-gradient(90deg, transparent, var(--rule) 56px); }
.fade-l.fade-r {
  -webkit-mask-image: linear-gradient(90deg, transparent, var(--rule) 56px, var(--rule) calc(100% - 56px), transparent);
  mask-image: linear-gradient(90deg, transparent, var(--rule) 56px, var(--rule) calc(100% - 56px), transparent);
}

/* ── 1280px 이하: KPI 가 좁아지고 사이드바도 좁힌다 ──
 * ★300px 사이드바는 1440 기준이다. 1280 노트북에서 그대로 두면 본문이 900px 남짓이라
 *  분할 보기(목록 | 상세)가 들어가지 않는다. */
@media (max-width: 1280px) {
  :root { --rail-w: 252px; }
  main { padding: 0 28px 64px; }
  .kpi-value { font-size: 38px; }
  .kpi.kpi-hero .kpi-value { font-size: 48px; }
  .rail-brand { padding: 20px 18px 16px; }
  .rail-co { margin: 0 18px; }
  .rail-label { padding: 16px 18px 8px; }
  .rail-rows { padding: 0 8px; }
  .rail-row { padding: 11px 10px 11px 12px; column-gap: 8px; }
  .rail-row.on::before { left: -8px; }
  .rail-name { font-size: 15px; }
  .rail-count { font-size: 20px; }
  .rail-todo { margin: 0 18px 14px; }
  .rail-foot { padding: 14px 18px 18px; }
}

/* ── 1100px 이하: 탭 일곱 개가 한 줄에 들어가게 좁힌다(넘치면 위의 흐림이 받는다). ── */
@media (max-width: 1100px) {
  .tabs-row { gap: 22px; }
  .tab { font-size: 14.5px; }
}

/* ── 900px 이하: 사이드바 → 위쪽 띠 ──
 * 사업장(또는 메뉴 그룹)을 가로로 넘겨 보는 칩 줄이 된다. 할 일·계정·로그아웃·테마는 띠
 * 오른쪽의 동그라미(내 계정)를 누르면 내려오는 판으로 옮긴다. */
@media (max-width: 900px) {
  /* ★행을 늘이지 않는다 — 안 그러면 짧은 화면에서 띠가 남은 높이를 나눠 갖고 검은 빈칸이 생긴다. */
  #app { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); align-content: start; }
  .rail { border-right: 0; }
  .rail-in { position: static; height: auto; overflow: visible; }
  .rail-brand { padding: 14px 16px; }
  .rail-me {
    display: grid; place-items: center; margin-left: auto; width: 40px; height: 40px; padding: 0;
    border: 0; border-radius: 50%; background: none;
  }
  .rail-me:hover { background: var(--rail-hover); }
  .rail-co, .rail-fill, .rail-sep { display: none; }
  /* 플랫폼의 사업장 범위 — 이름표 없이 한 줄(상자 안 글자가 «전체 사업장» 이라 뜻이 선다). */
  .rail-scope { padding: 0 16px 10px; }
  .rail-scope-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .rail-scope::after { right: 30px; bottom: 23px; }
  .rail .scope-select { height: 38px; font-size: 14px; }
  .rail-label { padding: 2px 16px 8px; }
  .rail-rows { flex-direction: row; overflow-x: auto; padding: 0 16px 14px; gap: 8px; scrollbar-width: none; }
  .rail-rows::-webkit-scrollbar { display: none; }
  .rail-rows > li { flex: 0 0 auto; }
  .rail-row { width: 216px; height: 100%; border: 1px solid var(--rail-hair); }
  /* ★고른 칩은 아래 막대로 — 칩이 가로로 서 있어 왼쪽 막대가 칩 밖으로 나간다. */
  .rail-row.on::before { left: 0; right: 0; top: auto; bottom: -1px; width: auto; height: 4px; border-radius: 0; }

  /* 계정 판 — 동그라미를 누르면 띠 아래로 내려온다. */
  .rail-drawer { display: none; }
  #app.nav-open .rail-drawer {
    display: block; position: absolute; top: 64px; left: 12px; right: 12px; z-index: 40;
    background: var(--rail-bg); border: 1px solid var(--rail-hair); border-radius: 8px; padding-top: 6px;
    box-shadow: var(--shadow-pop);
  }
  #app.nav-open .rail-todo { margin-top: 8px; border-top: 0; }
  #app.nav-open .rail-foot { border-top: 1px solid var(--rail-hair); }
  #app.nav-open .nav-scrim { display: block; position: fixed; inset: 0; z-index: 35; background: transparent; }

  main { padding: 0 16px 48px; }
  .mast { flex-direction: column; align-items: flex-start; gap: 10px; padding-top: 22px; }
  .mast-r { padding-bottom: 0; }
  .page-head h1 { font-size: 40px; }
  .page-head { margin-bottom: 24px; }
  .tabbar { margin-top: 14px; }
  /* 탭은 그 줄 안에서만 민다. 끝의 흐림은 위의 `.fade-l/.fade-r` 가 맡는다. */
  .tabs-row { gap: 22px; }
  .tab { font-size: 14.5px; }
  .subtabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .subtab { flex: none; }
  .kpi-value { font-size: 34px; }
  .kpi.kpi-hero .kpi-value { font-size: 44px; }
  .card h2 { font-size: 24px; }
  /* 번호 단 구획 머리(console-components.css)도 같은 단계로 줄인다. */
  .card h2:has(> .sec-no),
  :is(.scr-admin, .scr-stats, .scr-fleet, .scr-pending, .pf, .sx) .card:not(.error-card) h2 { font-size: 24px; }
}

/* ── 600px 이하: 휴대폰 ──
 * 입력은 16px — iOS 가 입력칸을 누를 때 화면을 확대하지 않게 한다. */
@media (max-width: 600px) {
  .page-head h1 { font-size: 36px; }
  .card { margin-bottom: 36px; }
  .card h2 { font-size: 22px; }
  .card h2:has(> .sec-no),
  :is(.scr-admin, .scr-stats, .scr-fleet, .scr-pending, .pf, .sx) .card:not(.error-card) h2 { font-size: 22px; }
  .page-intro > p { font-size: 15px; }
  .page-actions { width: 100%; }
  .page-actions > button { flex: 1 1 auto; }
  .kpi { min-height: 0; padding: 14px 14px 12px; flex-basis: 140px; }
  .kpi.kpi-wide { flex-basis: 280px; }
  .kpi-value { font-size: 30px; }
  .kpi.kpi-hero { flex-basis: 100%; }
  /* 검은 블록이 위아래로 쌓이면 가로 선이 사라진다 — 블록 안의 가는 선으로 가른다. */
  .kpis > .kpi.kpi-hero:has(+ .kpi-hero) { border-right-color: var(--rule); border-bottom-color: var(--block-hair); }
  .site-card-nums strong { font-size: 18px; }
  .kpi.kpi-hero .kpi-value { font-size: 44px; }
  .kpis-text .kpi-value { font-size: 18px; }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .modal { padding: 12px; }
  .card.modal-card { margin-top: 12px; padding: 22px 16px; }
  .form-actions { flex-wrap: wrap; }
  .inline > input, .inline > button { flex: 1 1 100%; }
  .search { max-width: none; }
  input:not([type=checkbox]):not([type=radio]), select, textarea { font-size: 16px !important; }
  .stats-controls label:not(.check) { flex: 1 1 calc(50% - 6px); min-width: 0; }
  .stats-controls input:not([type=checkbox]), .stats-controls select { width: 100%; min-width: 0; }
  .stats-controls > button { flex: 1 1 100%; }
  .hbar-row { grid-template-columns: minmax(56px, 96px) minmax(0, 1fr) 72px; gap: 8px; }
  .card h2 > :is(button, .tabs, .h2-actions) { margin-left: 0; }
  .tabs { max-width: 100%; overflow-x: auto; flex-wrap: nowrap; }

  /* ★★표 → 이름표 붙은 카드. 머리글은 숨고, 칸마다 머리글 글자(`data-label`, console-ui.js
   *  `labelTables`)가 왼쪽에 붙는다. 첫 칸은 카드 제목처럼 굵게. 가로 스크롤이 없어진다. */
  main :is(.table-wrap, .card) > table, .table-wrap > table { min-width: 0 !important; }
  main table:not(.keep-table) > thead { display: none; }
  main table:not(.keep-table), main table:not(.keep-table) > tbody,
  main table:not(.keep-table) > tbody > tr, main table:not(.keep-table) > tbody > tr > td { display: block; width: auto; }
  main table:not(.keep-table) > tbody > tr { padding: 12px 0; border-bottom: 1px solid var(--border-hair); }
  main table:not(.keep-table) > tbody > tr:last-child { border-bottom: 0; }
  main table:not(.keep-table) > tbody > tr > td {
    position: relative; border: 0; padding: 3px 0 3px 40%; min-height: 22px; text-align: left; white-space: normal;
  }
  main table:not(.keep-table) > tbody > tr > td[data-label]::before {
    content: attr(data-label); position: absolute; left: 0; top: 5px; width: calc(40% - 10px);
    font-size: 11px; font-weight: 800; letter-spacing: 0.02em; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  main table:not(.keep-table) > tbody > tr > td:not([data-label]) { padding-left: 0; }
  main table:not(.keep-table) > tbody > tr > td:first-child { font-size: 14px; font-weight: 750; }
  main table:not(.keep-table) > tbody > tr > td.actions { padding-left: 0; padding-top: 8px; text-align: right; }
  main table:not(.keep-table) > tbody > tr:hover > td { background: none; }
  main table:not(.keep-table) > tbody > tr.is-selected { background: var(--accent-tint); box-shadow: inset 5px 0 0 var(--accent-fill); padding-left: 12px; }
  main table:not(.keep-table) > tbody > tr.is-selected > td { background: none; box-shadow: none; }
}


/* 관제 콘솔 — 관리 화면 (시안 D): 계근 승인 · 접근 정책 · 기사 관리 · 사업장 관리 · 계정 관리와 그 폼.
 *
 * ★공용 부품(구획·KPI·표·버튼·모달)의 모양은 console-components.css 가 정한다. 여기에는 **이 화면들에만**
 *   있는 것만 둔다 — 구획 번호, 차량번호·숫자 크기, 기사 상세의 검은 블록, 배정·권한 고르기.
 * ★화면 본문은 `.scr-admin` 으로 감싸 그린다(각 render 함수). 모달은 `<main>` 밖이라 그 상자가 닿지
 *   않으므로 **그 폼에만 있는 입력칸 id** 로 가린다(`:has(#afLoginId)` 등). 같은 모달 자리
 *   (`#accountForm`)를 다른 화면도 쓰므로 모달 전체에 규칙을 걸지 않는다.
 * ★색은 토큰만 쓴다. 상태는 점·막대에 늘 글자가 함께 있다 (A-16-2).
 */

/* ── 구획 머리: 바이올렛 번호 «01» ── 모양·제목 크기는 console-components.css. 여기는 세기만. */

.scr-admin { counter-reset: adm-sec; }
.scr-admin > .card > h2::before, .scr-admin > .card > .card-head h2::before {
  counter-increment: adm-sec; content: counter(adm-sec, decimal-leading-zero);
}
.scr-admin > .card > p.muted { margin: -6px 0 18px; font-size: 13px; line-height: 1.6; max-width: 880px; }
.scr-admin td.num, .scr-admin .num-time, .scr-admin .coord { font-variant-numeric: tabular-nums; }
/* KPI 띠 — 검은 칸 하나 + 흰 칸 넷이 한 줄에 서게 칸 기본 폭을 줄인다(계정 관리는 다섯 칸이다). */
.scr-admin .kpis > .kpi { flex-basis: 150px; }
.scr-admin .kpis > .kpi.kpi-hero { flex-basis: 260px; }

/* ── 계근 승인 · 접근 정책 ─────────────────────────────────────────────── */

/* 승인 줄 — 차량번호가 이 줄의 얼굴이다. 버튼은 보통 크기(사람이 앞에 서 있는 일이다). */
.appr-table td { padding-top: 16px; padding-bottom: 16px; }
.appr-table .plate {
  font-size: 19px; font-weight: 900; letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.appr-table td.actions { width: 1%; }
.appr-table td.actions button { height: 36px; min-width: 72px; }
.appr-table td.actions button + button { margin-left: 6px; }

.mode-table td:first-child strong { font-size: 15px; font-weight: 850; letter-spacing: -0.01em; }
.mode-table select { min-width: 190px; height: 36px; font-weight: 700; }
.mode-table td:last-child { font-size: 12.5px; line-height: 1.6; max-width: 560px; }
.mode-table .warn-line { margin: 8px 0 0; }

/* ── 기사 관리 ─────────────────────────────────────────────────────────── */

.scr-drivers td:first-child > strong { font-size: 15px; font-weight: 850; }
.scr-drivers td:first-child .muted code { font-size: 11px; }
.scr-drivers td.num { font-size: 18px; font-weight: 850; letter-spacing: -0.02em; }

/* 기사 상세 — 누적 계량을 검은 블록에 크게 (다크에서는 흰 블록으로 뒤집힌다). */
.driver-hero { display: flex; flex-wrap: wrap; margin: 4px 0 6px; background: var(--block); color: var(--block-text); }
.driver-hero > div { display: flex; flex-direction: column; gap: 6px; padding: 18px 22px 16px; min-width: 0; }
.driver-hero > div:first-child { flex: 1 1 220px; }
.driver-hero > div + div { border-left: 1px solid var(--block-hair); flex: 0 1 160px; justify-content: flex-end; }
.driver-hero .muted { color: var(--block-muted); font-size: 11px; font-weight: 800; letter-spacing: 0.03em; }
.driver-hero strong { font-size: 20px; font-weight: 850; letter-spacing: -0.02em; }
.driver-hero > div:first-child strong {
  font-size: 52px; font-weight: 900; line-height: 1; letter-spacing: -0.045em; font-variant-numeric: tabular-nums;
}
.driver-hero small { margin-left: 4px; font-size: 0.34em; font-weight: 750; letter-spacing: 0; color: var(--block-muted); }
.modal-card:has(.driver-hero) h3 {
  margin: 26px 0 4px; padding-top: 12px; border-top: var(--rule-w) solid var(--rule);
  font-size: 18px; font-weight: 900; letter-spacing: -0.03em;
}
.modal-card:has(.driver-hero) h3 .muted { font-size: 12px; font-weight: 650; letter-spacing: 0; margin-left: 6px; }
.modal-card:has(.driver-hero) table td.num { font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }
.modal-card:has(.driver-hero) .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ── 사업장 관리 ───────────────────────────────────────────────────────── */

.site-id { display: flex; align-items: baseline; gap: 4px 8px; flex-wrap: wrap; }
.site-id > strong { font-size: 16px; font-weight: 900; letter-spacing: -0.02em; }
.site-id > code {
  padding: 0 5px; border: 1.5px solid var(--rule); border-radius: 4px;
  font-size: 10.5px; font-weight: 800; line-height: 16px; letter-spacing: 0.04em; color: var(--text-primary);
}
.site-admin-table .coord { color: var(--text-soft); }
.site-admin-table td.big-num { font-size: 22px; font-weight: 850; letter-spacing: -0.03em; }

/* ── 계정 관리 ─────────────────────────────────────────────────────────── */

.account-table .person-name { font-size: 14.5px; }
.scr-accounts .page-intro > p { font-size: 18px; font-weight: 800; }

/* ── 폼: 권한 고르기 (계정 수정) ── 체크 상자를 켜고 끄는 꼬리표로. */

.modal-card:has(#afLoginId) .perms, .modal-card:has(#sfName) .perms {
  margin: 22px 0 0; padding: 12px 0 0; border: 0; border-top: var(--rule-w) solid var(--rule); border-radius: 0;
}
.modal-card:has(#afLoginId) .perms legend, .modal-card:has(#sfName) .perms legend {
  float: left; width: 100%; padding: 0 0 10px; font-size: 13px; font-weight: 900; color: var(--text-primary);
}
.modal-card:has(#afLoginId) .perms legend .muted { font-weight: 600; margin-left: 6px; }
.modal-card:has(#afLoginId) .perms .check {
  margin: 0 6px 6px 0; padding: 7px 13px; border: 1.5px solid var(--border-hair); border-radius: var(--r-pill);
  font-weight: 750;
}
.modal-card:has(#afLoginId) .perms .check:has(input:checked) { border-color: var(--accent-fill); background: var(--accent-tint); }
.modal-card:has(#afLoginId) .perms input, #siteAssignList input { accent-color: var(--accent-fill); }
.modal-card:has(#sfName) .perms .form-grid { clear: both; }
.modal-card:has(#sfName) > p.muted { margin-top: 18px; font-size: 12.5px; line-height: 1.6; }

/* ── 폼: 사업장 배정 ── 한 줄에 한 곳, 가는 선으로 나눈다. «전 사업장» 은 굵은 첫 줄. */

#siteAssignList { display: block; max-height: 360px; overflow-y: auto; margin: 14px 0; padding: 0; border: 0; border-top: var(--rule-w) solid var(--rule); border-radius: 0; }
#siteAssignList label {
  display: flex; align-items: center; gap: 10px; margin: 0; padding: 11px 4px; border-radius: 0;
  border-bottom: 1px solid var(--border-hair); font-size: 14px; font-weight: 700; color: var(--text-primary);
}
#siteAssignList label.all-row { font-weight: 900; background: var(--bg-elevated); }
#siteAssignList input { width: 17px; height: 17px; }
#siteAssignList input:disabled + span { color: var(--text-faint); }

/* ── 폼: 임시 비밀번호 ── 한 번만 보이는 값이라 검은 블록에 크게. */

#pwResult .detail-grid { display: block; margin: 16px 0 10px; }
#pwResult .detail-grid > div { padding: 18px 22px; background: var(--block); color: var(--block-text); }
#pwResult .detail-grid .muted { color: var(--block-muted); }
#pwResult strong.value-lg {
  text-align: left; font-size: 40px; font-weight: 900; letter-spacing: 0.04em; color: var(--block-text);
  font-variant-numeric: tabular-nums slashed-zero; overflow-wrap: anywhere;
}

/* ── 좁은 화면 ─────────────────────────────────────────────────────────── */

@media (max-width: 600px) {
  /* 카드가 된 승인 줄 — 두 버튼이 반씩 나눠 엄지로 누르기 쉽게. */
  main .appr-table > tbody > tr > td.actions { display: flex; gap: 8px; width: auto; }
  .appr-table td.actions button { flex: 1 1 0; height: 42px; }
  .appr-table td.actions button + button { margin-left: 0; }
  .mode-table select { width: 100%; min-width: 0; }
  /* 카드가 된 줄의 첫 칸(이름·차량번호)은 이름표 없이 카드 제목으로 — 왼쪽 40% 를 비우지 않는다. */
  main .scr-admin table:not(.keep-table) > tbody > tr > td:first-child { padding: 0 0 6px; }
  main .scr-admin table:not(.keep-table) > tbody > tr > td:first-child::before { content: none; }
  .mode-table td:last-child { max-width: none; }
  .driver-hero > div:first-child strong { font-size: 42px; }
  .driver-hero > div:first-child { flex-basis: 0; }
  .driver-hero > div + div { flex: none; padding-left: 16px; padding-right: 16px; }
  .modal-card:has(.driver-hero) table { font-size: 12px; }
  .modal-card:has(.driver-hero) .detail-grid strong { font-size: 14px; }
  .modal-card:has(.driver-hero) :is(th, td) { padding-left: 4px; padding-right: 4px; }
  #pwResult strong.value-lg { font-size: 30px; }
}


/* 관제 콘솔 — 플랫폼 관리자 화면 (시안 D): 대시보드 · 회사 승인 · 회사 관리 · 회사 현황 ·
 * 감사 로그 · 업주 관리 · 프로그램 버전 · 앱 버전 · 공지사항 관리 · 발송 설정 · 전표 발송.
 *
 * ★화면마다 바깥을 `.pf`(+ `.pf-<화면>`)로 감싼다. 여기 규칙은 그 안에서만 돈다 —
 *  다른 역할의 화면과 모달(`#accountForm`)은 건드리지 않는다.
 * ★색은 전부 토큰(var)이다. 상태는 점·막대에 글자를 함께 붙인다 — 색만으로 말하지 않는다.
 * ★부품(.card · .kpis · 표)의 모양은 console-components.css 가 정한다. 여기는 «배치» 와
 *  화면 고유의 강조만 둔다.
 */

/* ── 구획 번호 «01» ──────────────────────────────────────────────────────────
 * ★신문 지면처럼 구획마다 바이올렛 번호를 붙인다. 화면 코드는 번호를 세지 않는다 —
 *  CSS 카운터가 그린 순서대로 센다. 오류 상자(`.error-card`)는 구획이 아니라 세지 않는다. */
.pf { counter-reset: pf-sec; }
.pf .card:not(.error-card) > h2::before,
.pf .card:not(.error-card) > .card-head h2::before {
  counter-increment: pf-sec; content: counter(pf-sec, decimal-leading-zero);
  flex: none; align-self: baseline;
}
/* 구획 머리 아래 한 줄 설명은 제목과 붙여 읽힌다. 본문 회색보다 한 단계 진하게. */
.pf .card > h2 + p.muted { margin-top: -6px; color: var(--text-soft); max-width: 880px; line-height: 1.65; }

/* ── KPI 띠 ─────────────────────────────────────────────────────────────────
 * ★★넓은 화면에서는 한 줄로 닫는다. 공용 flex 띠는 칸이 여섯·일곱이면 마지막 한 칸이 다음
 *  줄로 떨어져 혼자 화면 폭을 다 차지했다(«2차 대기 0» 이 거대한 빈 상자가 됐다).
 *  격자의 열을 칸 수만큼 저절로 늘리고(`grid-auto-flow: column`), 히어로와 긴 값은 두 칸.
 * ★좁아지면 공용 flex 띠로 돌아간다 — 줄 바꿈에서도 상자가 네모로 닫힌다. */
@media (min-width: 1200px) {
  .pf-band > .kpis {
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  }
  .pf-band > .kpis > .kpi-hero, .pf-band > .kpis > .kpi-wide { grid-column: span 2; }
  .pf-band > .kpis > .kpi { min-height: 148px; }
}
/* 띠 둘이 이어지면(프로그램 버전) 사이 2px 선이 두 겹이 되지 않게 붙인다. */
.pf-band + .pf-band > .kpis { border-top: 0; margin-top: -32px; }
/* 글자 값 띠의 히어로 — 버전·켜짐/꺼짐은 큰 글자로. 숫자 띠의 히어로(58px)보다 작게. */
.pf-band.kpis-text .kpi.kpi-hero .kpi-value {
  font-size: 40px; font-weight: 900; letter-spacing: -0.035em; line-height: 1.1;
}
.pf .kpi-sub { font-variant-numeric: tabular-nums; }

/* ── 나란히 보기 ────────────────────────────────────────────────────────────
 * ★두 구획을 신문 단처럼 나란히 세운다(넓은 화면만). 각 단은 제 2px 선으로 시작한다.
 * ★★차트가 든 구획은 단에 넣지 않는다 — `chartWidth()` 가 본문 전체 폭으로 그려서, 단에
 *  넣으면 SVG 가 줄어들며 눈금 글자가 6px 로 작아진다(대시보드에서 실제로 그랬다). */
.pf-split { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 0 48px; align-items: start; }
.pf-split > .card { min-width: 0; }
/* 단이 좁아도 표는 단 안에서 접힌다 — 단 하나만 가로로 밀리지 않게 최소폭을 푼다. */
.pf-split .table-wrap.narrow > table { min-width: 0; }

/* 발송 설정: 폼 | 시험 발송. 오른쪽 단은 고정 폭의 «확인» 판이다 — 검은 테두리 상자로
 *  세워 폼과 다른 일(동작 확인)이라는 것이 보이게 한다. 스크롤해도 따라온다. */
.pf-split.pf-split-form { grid-template-columns: minmax(0, 1fr) 380px; }
.pf-split-form > .card + .card {
  position: sticky; top: 24px;
  border: var(--rule-w) solid var(--rule); padding: 20px 22px 18px;
}
.pf-split-form > .card + .card .inline { flex-direction: column; align-items: stretch; }
.pf-split-form > .card + .card .inline > * { flex: none; width: 100%; min-width: 0; }
.pf-split-form .form-grid { gap: 6px 20px; }

@media (max-width: 1199px) {
  .pf-split, .pf-split.pf-split-form { grid-template-columns: minmax(0, 1fr); }
  .pf-split-form > .card + .card { position: static; }
}

/* ── 표: 이름·버전은 굵게, 숫자는 고정폭 ────────────────────────────────────── */
.pf td > strong:first-child { font-size: 14px; font-weight: 850; letter-spacing: -0.01em; }
.pf td.num { font-size: 14px; font-weight: 800; letter-spacing: -0.01em; }
.pf td.nowrap, .pf td .muted { font-variant-numeric: tabular-nums; }
/* 코드 꼬리표 — 회사 코드·희망 코드·해시. 굵은 고정폭 꼬리표로 이름과 구분한다. */
.pf td code {
  display: inline-block; padding: 0 5px; border: 1.5px solid var(--rule); border-radius: 3px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.04em; line-height: 16px; color: var(--text-primary);
}

/* ── 대시보드 ─────────────────────────────────────────────────────────────── */
/* 회사별 막대 아래 표는 막대와 같은 값을 숫자로 준다 — 위에 2px 선을 두지 않고 붙인다. */
.pf-overview .hbar { margin-bottom: 20px; }
.pf-overview .chart { margin-top: 0; }

/* ── 회사 승인: 대기 줄은 «결정을 기다리는 일» 이라 옅은 바이올렛 바탕 + 왼쪽 막대 ── */
.pf-approvals .card:first-child tbody tr > td { background: var(--accent-tint); }
.pf-approvals .card:first-child tbody tr > td:first-child { box-shadow: inset 5px 0 0 var(--accent-fill); padding-left: 16px; }
.pf-approvals .card:first-child th:first-child { padding-left: 16px; }
.pf-approvals .card:first-child tbody tr + tr > td { border-top: 1px solid var(--bg-base); }

/* ── 감사 로그 ───────────────────────────────────────────────────────────────
 * ★날짜 칸은 검색칸처럼 늘이지 않는다. 검사 결과 띠는 상태색 — 앰버(브랜드)를 쓰지 않는다(A-16-1). */
.pf-audit .empty-state { padding: 56px 20px; }
.pf-audit .audit-filter select { width: auto; flex: 0 0 auto; margin: 0; }
.pf-audit .audit-date { display: inline-flex; align-items: center; gap: 6px; margin: 0;
  font-size: 12.5px; font-weight: 650; white-space: nowrap; }
.pf-audit .audit-date input { width: auto; flex: 0 0 auto; min-width: 0; margin: 0; }
.pf-audit .audit-reason { margin-top: 2px; font-size: 12.5px; color: var(--state-text-warn); }
.pf-audit .audit-more { display: flex; justify-content: center; padding: 14px 0 2px; }
.pf-audit .audit-check { margin: 0 0 20px; padding: 14px 18px; border-left: 5px solid var(--state-stable);
  background: var(--bg-surface); line-height: 1.65; }
.pf-audit .audit-check.is-broken { border-left-color: var(--state-offline); }
.pf-audit .audit-check.is-broken > strong { color: var(--state-text-offline); }
.pf-audit .audit-check ul { margin: 6px 0 0; padding-left: 20px; }
.pf-audit .audit-check code { word-break: break-all; }
.audit-payload { max-height: 320px; overflow: auto; margin: 4px 0 0; padding: 12px 14px;
  background: var(--bg-surface); border: 1px solid var(--border-hair); font-size: 12.5px;
  white-space: pre-wrap; word-break: break-word; }

/* ── 릴리스 등록 폼 (프로그램 버전 › 릴리스 등록) ─────────────────────────────────
 * ★모달(`#accountForm`)은 `.pf` 밖에 있다 — 규칙은 폼이 붙인 `rf-` 이름에만 건다.
 * ★진행 막대는 브랜드(accent) 색이고, 끝남·멈춤만 상태색이다. 색만으로 말하지 않는다 —
 *  막대 아래 글줄이 늘 상태를 적는다. */
.rf-mode { margin: 16px 0 2px; }
.rf-mode .tabs { margin-left: 0; }
.modal-card > label > input[type=file] {
  padding: 10px; font-size: 12.5px; color: var(--text-soft); cursor: pointer;
  background: var(--bg-surface); border: 1.5px dashed var(--rule); border-radius: var(--r-ctl);
}
.modal-card > label > input[type=file]::file-selector-button {
  margin-right: 12px; padding: 6px 12px; font: inherit; font-weight: 750; color: var(--text-primary);
  background: transparent; border: 1.5px solid var(--rule); border-radius: var(--r-ctl); cursor: pointer;
}
.rf-upload { margin-top: 14px; }
.rf-bar { height: 10px; overflow: hidden; background: var(--bg-elevated); border: 1.5px solid var(--rule); }
.rf-bar > span { display: block; width: 0; height: 100%; background: var(--accent-fill); transition: width 0.2s linear; }
.rf-upload.is-done .rf-bar > span { background: var(--state-stable); }
.rf-upload.is-failed .rf-bar > span { background: var(--state-offline); }
.rf-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-top: 8px; font-variant-numeric: tabular-nums; }
.rf-line > strong { font-size: 15px; font-weight: 850; }
.rf-line > button { margin-left: auto; }
.rf-line > button + button { margin-left: 0; }
.rf-upload > p.muted { margin: 6px 0 0; color: var(--text-soft); }
.rf-upload.is-failed > p.muted { color: var(--state-text-offline); font-weight: 650; }
.rf-key { margin: 6px 0 0; }
.rf-key code { word-break: break-all; }
.rf-key + .warn-line { margin: 10px 0 0; }
.form-actions > .rf-hint { margin: 0 auto 0 0; align-self: center; }
@media (prefers-reduced-motion: reduce) { .rf-bar > span { transition: none; } }

/* ── 다크 ─────────────────────────────────────────────────────────────────── */
/* 승인 대기 줄 사이의 틈은 캔버스 색이다 — 토큰이라 다크에서도 그대로 맞는다. */

/* ── 폰 (≤600px) ─────────────────────────────────────────────────────────────
 * ★표는 공용 규칙이 이름표 카드로 바꾼다. 여기는 카드 안의 강조만 맞춘다. */
@media (max-width: 600px) {
  .pf .card > h2 + p.muted { margin-top: -4px; font-size: 12.5px; }
  .pf-band.kpis-text .kpi.kpi-hero .kpi-value { font-size: 30px; }
  .pf-approvals .card:first-child tbody tr {
    padding-left: 12px; padding-right: 10px; background: var(--accent-tint); box-shadow: inset 5px 0 0 var(--accent-fill);
  }
  .pf-approvals .card:first-child tbody tr + tr { margin-top: 10px; }
  .pf-approvals .card:first-child tbody tr > td,
  .pf-approvals .card:first-child tbody tr + tr > td { background: none; border-top: 0; }
  /* 사유·비고는 카드 폭을 다 쓴다 — 공용 220px 상한이면 한 줄에 다섯 글자씩 꺾인다. */
  .pf td.note-cell { max-width: none; }
  .pf-approvals .card:first-child tbody tr > td:first-child { box-shadow: none; padding-left: 40%; }
  .pf-split-form > .card + .card { padding: 16px 14px 14px; }
}

/* ── 앱 버전 (시스템 › 앱 버전) ─────────────────────────────────────────────────
 * ★맨 위 띠가 «홈페이지와 같은 자료를 고친다» 또는 «연결 안 됨 + 고칠 것» 을 말한다. 상태색 막대 +
 *  글자 — 앰버(브랜드)를 쓰지 않는다(A-16-1). 앱 한 장 = 왼쪽 사실 · 오른쪽 QR.
 * ★★QR 은 테마와 상관없이 **흰 바탕**이다. 홈페이지의 QR(SVG)은 바탕이 투명한 검은 칸이라, 다크
 *  테마의 검은 바탕 위에서는 보이지도 찍히지도 않는다 — 여기 하나만 토큰이 아닌 색을 쓴다. */
:is(.pf-apps, .pf-legal) .av-sync { display: flex; gap: 12px; align-items: flex-start; margin: 0 0 28px; padding: 14px 18px;
  border-left: 5px solid var(--state-stable); background: var(--bg-elevated); line-height: 1.65; }
:is(.pf-apps, .pf-legal) .av-sync.is-off { border-left-color: var(--state-warn); }
:is(.pf-apps, .pf-legal) .av-sync > .ic { flex: none; width: 18px; height: 18px; margin-top: 3px; }
:is(.pf-apps, .pf-legal) .av-sync p { margin: 4px 0 0; color: var(--text-soft); }
:is(.pf-apps, .pf-legal) .av-sync code { word-break: break-all; }
.pf-apps .av-warn { display: block; margin-top: 4px; color: var(--state-text-warn); font-weight: 650; }
.pf-apps .card h2 .badge { align-self: center; }
.pf-apps .av-body { display: grid; grid-template-columns: minmax(0, 1fr) 184px; gap: 8px 36px; align-items: start; }
.pf-apps .av-body .detail-grid { margin-top: 4px; }
.pf-apps .av-explain { margin: 0 0 16px; padding: 10px 14px; border-left: 3px solid var(--rule);
  background: var(--bg-elevated); line-height: 1.65; max-width: 880px; }
.pf-apps .av-facts { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 10px 16px; margin: 0; }
.pf-apps .av-facts dt { padding-top: 2px; font-size: 11px; font-weight: 800; letter-spacing: 0.03em; color: var(--text-muted); }
.pf-apps .av-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; line-height: 1.6; }
.pf-apps .av-facts code { font-size: 11px; }
.pf-apps .av-qr { margin: 0; text-align: center; font-size: 12px; line-height: 1.7; }
.pf-apps .av-qr img, .pf-apps .av-qr-off {
  display: block; box-sizing: border-box; width: 184px; height: 184px; margin: 0 0 8px; padding: 10px;
  background: #fff; border: 1.5px solid var(--rule);
}
.pf-apps .av-qr-off {
  display: flex; align-items: center; justify-content: center; text-align: center;
  background: var(--bg-elevated); border-style: dashed; color: var(--text-muted); font-weight: 750; line-height: 1.5;
}
.pf-apps .av-qr figcaption code { word-break: break-all; }

/* 개인정보처리방침 (시스템 › 개인정보처리방침). 맨 위 띠는 앱 버전과 같은 모양(위 `:is()`).
 * ★본문 미리보기는 길다 — 카드가 화면을 다 먹지 않게 높이를 묶고 안에서 굴린다. */
.pf-legal .legal-body { max-height: 360px; overflow: auto; padding: 12px 14px; border: 1.5px solid var(--rule);
  background: var(--bg-elevated); line-height: 1.7; }
.pf-legal #lg_body { font-family: inherit; line-height: 1.7; }

/* APK 올리기 창(모달은 `.pf` 밖이다 — `av-` 이름에만 건다). 막대는 브랜드 색, 멈춤만 상태색. */
.av-upload { margin-top: 14px; }
.av-bar { height: 10px; overflow: hidden; background: var(--bg-elevated); border: 1.5px solid var(--rule); }
.av-bar > span { display: block; width: 0; height: 100%; background: var(--accent-fill); transition: width 0.2s linear; }
.av-upload.is-failed .av-bar > span { background: var(--state-offline); }
.av-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-top: 8px; font-variant-numeric: tabular-nums; }
.av-line > strong { font-size: 15px; font-weight: 850; }
.av-line > button { margin-left: auto; }
.av-upload > p.muted { margin: 6px 0 0; color: var(--text-soft); }
.av-upload.is-failed > p.muted { color: var(--state-text-offline); font-weight: 650; }
.form-actions > .av-hint { margin: 0 auto 0 0; align-self: center; }
@media (prefers-reduced-motion: reduce) { .av-bar > span { transition: none; } }

@media (max-width: 760px) {
  .pf-apps .av-body { grid-template-columns: minmax(0, 1fr); }
  .pf-apps .av-qr { display: flex; gap: 14px; align-items: center; text-align: left; }
  .pf-apps .av-qr img, .pf-apps .av-qr-off { flex: none; width: 132px; height: 132px; margin: 0; }
  .pf-apps .av-facts { grid-template-columns: minmax(0, 1fr); gap: 2px 0; }
  .pf-apps .av-facts dd + dt { margin-top: 8px; }
}


/* 관제 콘솔 — 영업 화면 (시안 D): 영업 관리 · 영업 승인 · 총판 · 판매사원 · 계약 현황 · 구독 · 수수료 · 구독 설정.
 *
 * ★화면 파일이 본문 전체를 `.sx .sx-<화면>` 으로 감싼다. 이 파일의 규칙은 전부 그 안에서만
 *  산다 — 다른 화면(사업장·계근·정산)으로 새지 않는다. 모달(`#accountModal`)은 본문 밖이라
 *  여기 규칙을 받지 않는다.
 * ★색은 토큰만 쓴다. 새 색을 만들지 않는다. 상태는 늘 글자와 함께다(A-16-2).
 * ★KPI 줄은 두 가지다.
 *   `.sx-band`  — 그 화면의 머리. 큰 숫자, 검은 블록(`hero`) 한두 칸.
 *   `.sx-strip` — 머리 바로 밑에 붙는 둘째 줄. 숫자를 한 단계 줄이고 칸을 낮춘다.
 *  `.sx-joined` 를 단 머리 밑에 둘째 줄이 오면 두 줄이 2px 선 하나를 나눠 쓰며 한 덩어리가 된다.
 */

/* ── 구획 번호 «01» — 지면의 순서를 말한다 ─────────────────────────────── */

.sx { counter-reset: sx-sec; }
.sx .card > .card-head h2::before,
.sx section.card > h2::before {
  counter-increment: sx-sec; content: counter(sx-sec, decimal-leading-zero);
  align-self: baseline;
}

/* ── KPI 줄 ──────────────────────────────────────────────────────────────── */
/* ★★숫자 크기를 **칸 폭**에 묶는다(`cqi`). 고정 44px 이면 «416,000원» 처럼 단위 붙은 금액이
 *  좁은 칸에서 잘리고(칸이 overflow:hidden), 넓은 칸에서는 쓸데없이 작다.
 *  셋으로 나눈다: 짧은 수(건수) · 단위 붙은 값(금액·일) · 10자 넘는 값(`kpi-wide`). */

.sx .kpis > .kpi { flex: 1 1 150px; container-type: inline-size; }
.sx .kpis > .kpi.kpi-wide { flex: 1.6 1 260px; }
.sx .kpis > .kpi.kpi-hero { flex: 1.5 1 220px; }
.sx .kpis > .kpi.kpi-hero.kpi-wide { flex: 2 1 300px; }

.sx .kpi .kpi-value { font-size: clamp(30px, 30cqi, 46px); }
.sx .kpi .kpi-value:has(> .kpi-unit) { font-size: clamp(24px, 19cqi, 46px); }
.sx .kpi.kpi-wide .kpi-value { font-size: clamp(22px, 14cqi, 46px); }
.sx .kpi.kpi-hero .kpi-value { font-size: clamp(36px, 34cqi, 58px); }
.sx .kpi.kpi-hero .kpi-value:has(> .kpi-unit) { font-size: clamp(28px, 19cqi, 58px); }
.sx .kpi.kpi-hero.kpi-wide .kpi-value { font-size: clamp(26px, 14.5cqi, 58px); }

/* 검은 블록 위의 상태 라벨 · 나란한 검은 블록 사이 선은 공용이다(console-components.css). */

/* 머리 + 둘째 줄을 한 덩어리로. */
.sx .sx-joined > .kpis { margin-bottom: 0; }
.sx .sx-joined + .sx-strip > .kpis { border-top: 0; }

/* 둘째 줄 — 낮은 칸, 한 단계 작은 숫자. */
.sx .sx-strip > .kpis > .kpi { flex: 1 1 130px; min-height: 0; padding: 14px 18px 13px; }
.sx .sx-strip .kpi .kpi-value { margin-top: 8px; font-size: clamp(24px, 26cqi, 34px); }
.sx .sx-strip .kpi .kpi-value:has(> .kpi-unit) { font-size: clamp(20px, 17cqi, 34px); }
.sx .sx-strip .kpi.kpi-wide .kpi-value { font-size: clamp(20px, 13cqi, 34px); }
.sx .sx-strip .kpi-sub { padding-top: 8px; }

/* ── 표 공통 ─────────────────────────────────────────────────────────────── */

/* 이름 밑 한 줄(요율 · 계약 수 …)에 가운뎃점을 넣어 덩어리를 가른다. 간격만으로는 붙어 읽혔다. */
.sx .id-line { gap: 4px 6px; margin-top: 4px; }
.sx .id-line > span::before { content: "·"; margin-right: 6px; color: var(--text-faint); }
.sx .id-line > span.badge::before { content: none; }
.sx td.num { font-weight: 700; }
/* 금액이 본문인 칸은 한 단계 굵게 — 표에서 눈이 먼저 닿아야 하는 숫자다. */
.sx td.num strong, .sx td.num .tone-warn { font-weight: 850; }

/* 트리(총판 → 판매사원 → 건별): 깊이는 들여쓰기와 글자 무게로 말한다. */
.sx .tree-row.lv0 > td { background: var(--bg-elevated); }
.sx .tree-row.lv0 > td:first-child strong { font-size: 16px; font-weight: 900; letter-spacing: -0.02em; }
.sx .tree-row.lv1 > td:first-child { font-weight: 750; }
.sx .tree-row.lv1-add > td { padding-top: 8px; padding-bottom: 12px; }
.sx .caret { margin-right: 4px; }

/* ── 영업 관리 ───────────────────────────────────────────────────────────── */

.sx-home .person-name { font-size: 14px; }

/* ── 영업 승인 — 한 건씩 읽고 판단한다: 왼쪽 내용, 오른쪽 결정 ──────────── */

.sx-appr .approval-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 32px; align-items: center;
  margin: 0; padding: 22px 0 20px; border: 0; border-bottom: 1px solid var(--border-hair); background: none;
}
.sx-appr .approval-row > * { grid-column: 1; }
.sx-appr .approval-row > .form-actions { grid-column: 2; grid-row: 1 / span 3; margin: 0; align-self: center; }
.sx-appr .approval-row > .form-actions > button:not(.sm) { height: 38px; }
.sx-appr .approval-row > .form-actions > button.sm { height: 36px; padding: 0 16px; font-size: 13px; }
.sx-appr .approval-head { gap: 8px 10px; }
.sx-appr .approval-head strong { font-size: 24px; font-weight: 900; letter-spacing: -0.035em; }
/* 며칠째 기다리는가 — 줄 끝에 굵게. 3일을 넘기면 앰버 글자(`tone-warn`)다. */
.sx-appr .approval-head > span:last-child { margin-left: 4px; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; }
.sx-appr .approval-row .detail-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px 24px; margin: 14px 0 0; }
.sx-appr .approval-row .detail-grid strong { font-size: 15px; }
.sx-appr .approval-row > .error:not([hidden]) { margin: 10px 0 0; }

/* ── 계약 현황 — 계약 한 장 ──────────────────────────────────────────────── */

.sx-port .contract-grid { gap: 18px; }
.sx-port .contract-card { gap: 0; padding: 20px 22px 16px 26px; }
.sx-port .contract-head { flex-direction: column; gap: 10px; }
.sx-port .contract-title h3 { font-size: 24px; letter-spacing: -0.035em; line-height: 1.2; }
.sx-port .contract-title .muted { margin-top: 4px; font-size: 12.5px; }
.sx-port .contract-badges { margin-left: 0; gap: 6px 14px; }
.sx-port .portfolio-grid {
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: 16px 24px;
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-hair);
}
.sx-port .portfolio-grid > div > div:nth-child(2) { font-size: 13.5px; font-weight: 800; color: var(--text-primary); }
.sx-port .portfolio-grid > div > .muted { margin: 3px 0 0; line-height: 1.5; }
.sx-port .contract-foot { margin-top: 16px; }
.sx-port details.card > summary { padding: 4px 0; }

/* ── 구독 설정 — 두 묶음을 나란히 ────────────────────────────────────────── */

.sx-plan > .card { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 48px; align-items: start; }
.sx-plan > .card > :not(fieldset) { grid-column: 1 / -1; }
.sx-plan > .card > p.muted { max-width: 820px; margin-bottom: 8px; font-size: 13px; line-height: 1.6; }
.sx-plan fieldset.perms {
  min-width: 0; margin: 18px 0 0; padding: 14px 0 0; border: 0; border-top: 1px solid var(--border-hair); border-radius: 0;
}
.sx-plan fieldset.perms > legend {
  float: left; width: 100%; padding: 0; margin: 0 0 4px;
  font-size: 18px; font-weight: 900; letter-spacing: -0.03em; color: var(--text-primary);
}
.sx-plan fieldset.perms > legend + * { clear: both; }
.sx-plan .form-grid { grid-template-columns: minmax(0, 1fr); }
.sx-plan .form-grid input { max-width: 360px; }
.sx-plan fieldset .muted { font-size: 12.5px; line-height: 1.65; }
.sx-plan > .card > .form-actions { align-items: center; margin-top: 28px; padding-top: 16px; border-top: var(--rule-w) solid var(--rule); }

/* ── 좁은 화면 ───────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .sx-plan > .card { grid-template-columns: minmax(0, 1fr); }
  .sx-appr .approval-row .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 600px) {
  /* 머리의 검은 블록은 한 줄을 다 쓴다. 나머지는 두 칸씩. */
  .sx .kpis > .kpi { flex-basis: 130px; }
  .sx .kpis > .kpi.kpi-hero, .sx .kpis > .kpi.kpi-wide { flex-basis: 100%; }
  .sx .kpi.kpi-hero .kpi-value { font-size: clamp(36px, 15cqi, 52px); }
  .sx .kpi.kpi-hero .kpi-value:has(> .kpi-unit), .sx .kpi.kpi-hero.kpi-wide .kpi-value { font-size: clamp(30px, 11.5cqi, 48px); }
  .sx .kpi.kpi-wide .kpi-value { font-size: clamp(26px, 10cqi, 38px); }
  .sx .sx-strip > .kpis > .kpi { padding: 12px 14px 11px; }
  /* 단위 붙은 짧은 값(«0일») 이 옆 칸의 건수보다 눈에 띄게 작아지지 않게. 폰 칸은 150px 안팎이다. */
  .sx .kpi .kpi-value:has(> .kpi-unit) { font-size: clamp(30px, 19cqi, 46px); }
  /* 막대는 장식이다(같은 줄의 «입금 확인» 숫자가 본문). 카드에서는 이름표 없는 긴 줄이 되어 구분선처럼 읽혔다. */
  .sx td.bar-cell { display: none !important; }
  /* 트리의 빈 칸(작업 자리·합친 칸)은 카드 밑에 빈 줄만 남긴다. */
  .sx table.tree td:empty { display: none !important; }

  /* 승인: 결정 버튼은 내용 밑, 오른쪽. */
  .sx-appr .approval-row { grid-template-columns: minmax(0, 1fr); }
  .sx-appr .approval-row > .form-actions { grid-column: 1; grid-row: auto; margin-top: 14px; justify-content: flex-end; }
  .sx-appr .approval-head strong { font-size: 20px; }

  .sx-port .contract-card { padding: 16px 16px 14px 20px; }
  .sx-port .contract-title h3 { font-size: 20px; }
  .sx-port .portfolio-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .sx-port .contract-foot { flex-wrap: wrap; }

  /* 트리 표도 카드가 된다(console-responsive.css). 깊이는 왼쪽 막대와 들여쓰기로. */
  .sx table.tree > tbody > tr.tree-row > td:first-child { padding-left: 0; font-size: 15px; }
  .sx table.tree > tbody > tr.tree-row > td:first-child::before { content: none; }
  .sx table.tree > tbody > tr.tree-row.lv0 { background: var(--bg-elevated); padding-left: 12px; padding-right: 12px; }
  .sx table.tree > tbody > tr.tree-row.lv0 > td { background: none; }
  .sx table.tree > tbody > tr.tree-row.lv1 { margin-left: 14px; padding-left: 12px; box-shadow: inset 3px 0 0 var(--border-hair); }
  .sx table.tree > tbody > tr.tree-row.lv2 { margin-left: 28px; padding-left: 12px; box-shadow: inset 3px 0 0 var(--border-hair); }
  .sx table.tree > tbody > tr.tree-row.lv1-add > td { padding: 4px 0; text-align: left; }
}


/* 관제 콘솔 — 화면 모양: 계근 통계 · 계근대 · 기사 · 미인증 계근대 (시안 D).
 *
 * ★세 화면은 본문을 `.scr-stats` / `.scr-fleet` / `.scr-pending` 으로 한 번 감싼다
 *  (console-stats.js · console-fleet.js · console-pending.js). 여기 규칙은 **전부 그 아래로만**
 *  걸어서 공용 부품(console-components.css)의 모양을 다른 화면에서 바꾸지 않는다.
 * ★색은 토큰만 쓴다. 원색을 적지 않는다 — 다크 테마가 같은 규칙으로 뒤집힌다.
 * ★표 안쪽은 가는 선만. 2px 선은 구획의 머리와 분할 보기의 테두리에만 긋는다
 *  (밀도 높은 통계 표에 굵은 선을 남발하면 지면이 무거워진다 — 시안 노트 위험 9).
 */

/* ── 공통: 구획 머리 «01 제목» ───────────────────────────────────────────── */

.scr-stats, .scr-fleet, .scr-pending { counter-reset: scr-sec; }
/* ★번호는 장식이 아니라 읽는 순서다. 모양·제목 크기는 console-components.css(묶음 공용). */
:is(.scr-stats, .scr-fleet, .scr-pending) .card > h2::before {
  counter-increment: scr-sec; content: counter(scr-sec, decimal-leading-zero);
}
:is(.scr-stats, .scr-fleet, .scr-pending) .card > p.muted { margin: -6px 0 16px; font-size: 13px; line-height: 1.6; }
:is(.scr-stats, .scr-fleet, .scr-pending) td.num { font-variant-numeric: tabular-nums; }

/* ── 계근 통계 ───────────────────────────────────────────────────────────── */

/* 조회 조건: 첫 줄은 기간(시작 · 종료 · 단위 · 상세 · 조회), 둘째 줄은 거르기 칸을 같은 폭 격자로. */
.scr-stats .stats-controls { gap: 12px 14px; margin-bottom: 16px; }
.scr-stats .stats-controls + .stats-controls {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); align-items: end;
  padding-top: 16px; border-top: 1px solid var(--border-hair);
}
.scr-stats .stats-controls + .stats-controls :is(select, input) { width: 100%; min-width: 0; }
.scr-stats .stats-controls + .stats-controls > button { justify-self: start; }
.scr-stats .stats-controls > button.primary { min-width: 96px; }
.scr-stats .stats-controls :is(select, input:not([type=checkbox])) { height: 40px; }
.scr-stats .stats-controls ~ p.muted { margin: -4px 0 12px; font-size: 12.5px; }
.scr-stats .stats-downloads { gap: 8px 10px; }

/* KPI: 검은 히어로 둘(건수 · 실중량)이 앞에 서고 나머지는 흰 칸. */
.scr-stats .kpis { margin-bottom: 44px; }
.scr-stats .kpi-hero .kpi-sub { font-variant-numeric: tabular-nums; }
/* ★여섯 칸 = 세 칸 두 줄. 줄마다 폭을 따로 나누면 위아래 세로 선이 어긋난다 — 같은 세 칸 틀에 세운다.
 *  좁은 화면(≤900)은 공용 flex 줄 바꿈 그대로다. */
@media (min-width: 901px) {
  .scr-stats .kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* ★긴 값(`kpi-wide`)도 두 칸을 먹지 않는다 — 대신 숫자를 칸 폭에 맞춰 줄인다(`cqi`). */
  .scr-stats .kpis > .kpi.kpi-wide { grid-column: auto; container-type: inline-size; }
  .scr-stats .kpis > .kpi.kpi-wide .kpi-value { font-size: clamp(28px, 13cqi, 58px); }
}

/* 기간별: «막대 | 표» 분할 보기. 2px 테두리 상자 하나, 가운데도 2px 선. */
.stats-split {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  border: var(--rule-w) solid var(--rule); align-items: stretch;
}
.stats-split-chart { padding: 18px 22px 8px; min-width: 0; }
.stats-split-chart .hbar { margin: 0; }
.stats-split-chart .hbar-row { grid-template-columns: minmax(64px, 112px) minmax(0, 1fr) 96px; }
.stats-split > .table-scroll {
  max-height: 480px; border-left: var(--rule-w) solid var(--rule); padding: 0 18px 4px;
}
.stats-split > .table-scroll thead th { background: var(--bg-base); }
.scr-stats .card > .chart + .table-scroll { margin-top: 4px; }

/* 막대: 이름 | 막대 | 값. 막대는 굵고 검게, 값은 굵은 고정폭 숫자. */
.scr-stats .hbar { font-size: 13px; }
.scr-stats .hbar-row { padding: 5px 0; }
.scr-stats .hbar-track { height: 12px; background: var(--border-hair); }
.scr-stats .hbar-fill { background: var(--text-primary); }
.scr-stats .hbar-label { font-weight: 750; }
.scr-stats .hbar-value { font-size: 13.5px; font-weight: 850; letter-spacing: -0.01em; }

/* 분해(사업장별 · 계근대별 · 제품별 · 거래처별 · 차량별): 넓으면 두 단, 단 사이 40px. */
.scr-stats .stats-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 0 40px; margin-bottom: 0;
}
.scr-stats .stats-grid > .card { margin: 0 0 44px; }
.scr-stats .stats-grid > .card > h2 { font-size: 24px; }
/* 홀수 개로 끝나면 마지막 표(대개 차량별)가 한 줄을 다 쓴다 — 오른쪽이 비어 보이지 않게. */
.scr-stats .stats-grid > .card:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* 통계 표는 줄이 많다 — 행 높이를 줄이고, 실중량 열을 굵게(이 화면의 답). */
.scr-stats :is(.stats-grid, .table-scroll, .table-wrap) td { padding-top: 8px; padding-bottom: 8px; }
.scr-stats .table-wrap td:nth-child(8), .scr-stats .table-scroll td:nth-child(3) { font-weight: 850; }
.scr-stats .stats-grid .hbar { padding-bottom: 14px; margin-bottom: 0; border-bottom: 1px solid var(--border-hair); }

/* ── 계근대 · 기사 ───────────────────────────────────────────────────────── */

/* ★KPI 두 줄(현황 · 계약)을 **한 상자**로 붙인다. 첫 줄 여섯 칸이 한 줄에 서게 칸을 좁힌다. */
.scr-fleet > .kpis:first-of-type { margin-bottom: 0; }
.scr-fleet > .kpis + .kpis { border-top: 0; margin-bottom: 48px; }
.scr-fleet > .kpis:first-of-type > .kpi { flex: 1 1 140px; }
.scr-fleet > .kpis:first-of-type > .kpi.kpi-hero { flex: 1.7 1 230px; }
.scr-fleet > .kpis + .kpis > .kpi { min-height: 112px; }
.scr-fleet > .kpis + .kpis .kpi-value { font-size: 36px; }

.scr-fleet .map { height: 440px; }
.scr-fleet .card > .site-empty { margin-bottom: 14px; }
/* 계근대 표: 이름 칸이 줄의 머리다. 코드·Edge 꼬리표는 작게. */
.scr-fleet td strong { font-size: 14px; font-weight: 850; letter-spacing: -0.01em; }
.scr-fleet td code { font-size: 11px; }
.scr-fleet td.num { font-size: 16px; font-weight: 850; }
.scr-fleet .filter-bar { margin-bottom: 8px; }

/* ── 미인증 계근대 ───────────────────────────────────────────────────────── */

/* 인증까지 세 걸음. 2px 선 위에 «01 · 02 · 03» 세 단. */
.pending-steps {
  list-style: none; counter-reset: scr-step; margin: 0 0 48px; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: var(--rule-w) solid var(--rule);
}
.pending-steps > li {
  counter-increment: scr-step; display: flex; flex-direction: column; gap: 6px; min-width: 0;
  padding: 16px 24px 4px 0;
}
.pending-steps > li + li { padding-left: 24px; border-left: 1px solid var(--border-hair); }
.pending-steps > li::before {
  content: counter(scr-step, decimal-leading-zero); font-size: 13px; font-weight: 850;
  letter-spacing: 0.04em; color: var(--accent); font-variant-numeric: tabular-nums;
}
.pending-steps strong { font-size: 20px; font-weight: 900; letter-spacing: -0.03em; line-height: 1.2; }
.pending-steps span { font-size: 13px; line-height: 1.6; color: var(--text-soft); word-break: keep-all; }
/* 구획이 하나뿐이라 번호를 달지 않는다 — 위 세 걸음의 «01» 과 겹쳐 읽힌다. */
.scr-pending .card > h2::before { content: none; }
.scr-pending .card > h2 .badge { font-size: 15px; font-weight: 850; }
/* ★지문이 인증의 열쇠다 — 표에서 가장 먼저 읽히게 굵은 고정폭으로. */
.scr-pending td code {
  font-size: 13.5px; font-weight: 800; letter-spacing: 0.02em; padding: 3px 8px;
  border: 1.5px solid var(--rule); border-radius: 4px; background: none;
}
.scr-pending td:first-child { font-size: 14px; font-weight: 800; }

/* ── 좁은 화면 ───────────────────────────────────────────────────────────── */

@media (max-width: 1100px) {
  .stats-split { grid-template-columns: minmax(0, 1fr); }
  .stats-split > .table-scroll { border-left: 0; border-top: var(--rule-w) solid var(--rule); }
}

@media (max-width: 900px) {
  .scr-stats .stats-grid > .card > h2 { font-size: 22px; }
  .scr-fleet .map { height: 340px; }
  .pending-steps { grid-template-columns: minmax(0, 1fr); }
  .pending-steps > li, .pending-steps > li + li { padding: 14px 0 12px; border-left: 0; }
  .pending-steps > li + li { border-top: 1px solid var(--border-hair); }
}

@media (max-width: 600px) {
  /* 거르기 칸은 두 개씩. 첫 줄(기간)은 공용 규칙대로 반씩 + 조회 버튼 한 줄. */
  .scr-stats .stats-controls + .stats-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .scr-stats .stats-controls + .stats-controls > button { grid-column: 1 / -1; justify-self: stretch; }
  .scr-stats .stats-downloads > .btn { flex: 1 1 auto; justify-content: center; }
  .stats-split-chart { padding: 14px 12px 6px; }
  .stats-split > .table-scroll { padding: 0 12px; max-height: none; }
  .scr-stats .hbar-row { grid-template-columns: minmax(56px, 92px) minmax(0, 1fr) 84px; }
  /* 현황 여섯 칸은 두 칸씩, 히어로는 한 줄 전체. */
  .scr-fleet > .kpis:first-of-type > .kpi { flex-basis: 40%; }
  .scr-fleet > .kpis:first-of-type > .kpi.kpi-hero { flex-basis: 100%; }
  .scr-fleet > .kpis + .kpis .kpi-value { font-size: 30px; }
  .scr-fleet .map { height: 300px; }
  .scr-pending td code { font-size: 12.5px; }
}


/* 관제 콘솔 — 운영 화면 (시안 D): 사업장 현황 · 대시보드 · 계근 데이터 · 회원 승인 · 차량 · 기사 · 실시간 위치.
 *
 * ★화면 HTML 은 console-sites.js · console-pages.js 가 만든다. 이 파일은 그 화면들만의 모양이다
 *   (`ops-` 로 시작하는 클래스, `.site-card`, `.sec-no`). 공용 부품은 console-components.css 가 맡는다.
 * ★★맨 끝(console-responsive.css 뒤)에 이어 붙는다. 그래서 좁은 화면 규칙도 이 파일 안에 함께 둔다 —
 *   여기의 선택자가 더 구체적이라, 공용 좁은 화면 규칙이 이 화면들에는 닿지 않는다.
 * ★색은 토큰만 쓴다. 상태는 늘 점·글자가 함께 있다 (A-16-2). 바이올렛은 상태를 뜻하지 않는다.
 */

/* ── 공통: 구획 번호 · 작은 라벨 ──────────────────────────────────────────── */

/* `.sec-no`(secNo())와 번호 단 제목의 모양·크기는 console-components.css 가 정한다 — 묶음 공용. */
.ops-date { font-size: 14px; font-weight: 650; letter-spacing: 0; color: var(--text-muted); }
.ops-lab { font-size: 11.5px; font-weight: 800; letter-spacing: 0.04em; color: var(--text-muted); }
.ops-note { margin: 0; font-size: 12.5px; color: var(--text-muted); }
.ops-note strong { color: var(--text-primary); }
.card-actions > .filter-bar { margin: 0; flex-wrap: nowrap; }
.card-actions > .filter-bar input[type=search] { width: 260px; }

/* ── KPI 밴드: 검은 히어로 두 칸 + 흰 칸 넷이 한 줄 ─────────────────────────
 * ★폭이 모자라면 줄을 바꾼다(공용 `.kpis` 는 줄 바꿈 flex 라 상자가 늘 네모로 닫힌다).
 *  히어로 숫자가 칸 밖으로 잘리지 않게 히어로의 기본 폭을 값 길이에 맞춰 둔다. */
.ops-band .kpi { flex: 0.4 1 112px; min-height: 150px; padding: 18px 16px 16px; }
.ops-band .kpi .kpi-value { font-size: 40px; }
.ops-band .kpi.kpi-hero { flex: 1 1 220px; padding: 20px 24px; }
.ops-band .kpi.kpi-hero.kpi-wide { flex: 1.6 1 380px; }
.ops-band .kpi.kpi-hero .kpi-value { font-size: 58px; }
.kpi-frac { color: var(--text-faint); font-weight: 750; }
/* 사업장 현황의 정상 · 오프라인 칸 — 라벨은 검정, 상태는 설명 줄의 «점 + 글자» 가 말한다(시안 D). */
.ops-band-sites .kpi:is(.kpi-stable, .kpi-offline)::before { content: none; }
.ops-band-sites .kpi:is(.kpi-stable, .kpi-offline) .kpi-label { color: var(--text-primary); }
.ops-band-sites .kpi-sub { display: flex; align-items: center; }

/* ── 분할 보기: 목록 | 상세 ──────────────────────────────────────────────── */

.ops-split {
  display: grid; grid-template-columns: minmax(0, 1fr) 470px;
  border: var(--rule-w) solid var(--rule); background: var(--bg-base);
}
.ops-split > .ops-detail { border-left: var(--rule-w) solid var(--rule); min-width: 0; }
.ops-detail-empty { margin: 0; padding: 28px 22px; color: var(--text-muted); font-size: 13px; }

/* 사업장 목록 — 카드가 아니라 줄이다(사이 가는 선). 왼쪽 5px 막대가 상태, 바이올렛 테두리가 펼침. */
.ops-list .site-card {
  position: relative; border: 0; border-bottom: 1px solid var(--border-hair);
  padding: 18px 20px 16px 26px; background: none;
}
.ops-list .site-card:last-child { border-bottom: 0; }
.ops-list .site-card:hover { background: var(--bg-elevated); }
.ops-list .site-card.is-open { background: var(--accent-tint); box-shadow: inset 0 0 0 2px var(--accent-fill); }
.ops-list .site-card.is-open.is-warn { box-shadow: inset 5px 0 0 var(--state-warn), inset 0 0 0 2px var(--accent-fill); }
.ops-list .site-card.is-open.is-bad { box-shadow: inset 5px 0 0 var(--state-offline), inset 0 0 0 2px var(--accent-fill); }
.ops-list .site-card:focus-visible { outline-offset: -4px; }
/* 고른 사업장(전역 선택기)은 글자로 말한다 — 펼침과 같은 바이올렛 테두리를 또 쓰면 둘이 섞인다. */
.ops-list .site-card.is-selected .site-card-head strong::after {
  content: "고른 사업장"; margin-left: 10px; padding: 0 6px; border: 1.5px solid currentColor; border-radius: 4px;
  font-size: 11px; font-weight: 800; letter-spacing: 0.02em; line-height: 18px; vertical-align: 4px; color: var(--accent);
}
.site-card-head strong { font-size: 24px; }
.site-card-nums { grid-template-columns: 80px 120px minmax(0, 1fr); gap: 16px; }
.site-card-nums strong { font-size: 22px; white-space: nowrap; }
.site-card-nums .u, .ops-lane-n .u, .ops-net-v .u, .ops-wdet-flow .u {
  font-size: 12px; font-weight: 700; letter-spacing: 0; margin-left: 2px; color: var(--text-muted);
}
.site-card-foot { border-top: 0; padding-top: 0; gap: 8px 16px; }
.site-card-foot .site-nums { margin: 0; color: var(--text-primary); }
.site-card-foot .site-nums .dot { width: 8px; height: 8px; margin-right: 5px; }
/* ★좁은 화면에서만 카드 안에 계근대 판이 펼쳐진다. 넓은 화면에서는 오른쪽 판이 같은 일을 한다. */
.ops-inline { display: none; }

/* 펼친 사업장 — 머리 + 계근대 판(2열). 큰 숫자는 오늘 계량 건수. */
.ops-detail-site + .ops-detail-site { border-top: var(--rule-w) solid var(--rule); }
.ops-detail-h { display: flex; align-items: flex-start; gap: 12px; padding: 18px 22px 14px; border-bottom: 1px solid var(--border-hair); }
.ops-detail-h > div { min-width: 0; flex: 1; }
.ops-detail-h .ops-lab { color: var(--accent); }
.ops-detail-h h3 { margin: 6px 0 0; font-size: 30px; font-weight: 900; letter-spacing: -0.04em; line-height: 1.1; }
.ops-detail-h p { margin: 6px 0 0; color: var(--text-muted); font-size: 12.5px; }
.ops-lanes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ops-lane { padding: 16px 20px; border-bottom: 1px solid var(--border-hair); min-width: 0; }
.ops-lane:nth-child(odd) { border-right: 1px solid var(--border-hair); }
/* ★홀수 개면 마지막 한 장이 두 칸을 다 쓴다 — 반쪽짜리 칸이 사업장 줄 사이에 떠 보이지 않게. */
.ops-lane:last-child:nth-child(odd) { grid-column: 1 / -1; border-right: 0; }
.ops-lane.is-offline {
  background: repeating-linear-gradient(135deg, transparent 0 9px,
    color-mix(in srgb, var(--state-offline) 7%, transparent) 9px 18px);
}
.ops-lane-h { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.ops-lane-h b { font-size: 14.5px; font-weight: 850; letter-spacing: -0.02em; min-width: 0; }
.ops-lane-st { margin: 8px 0 12px; font-size: 12.5px; font-weight: 750; display: flex; align-items: center; }
.ops-lane.is-stable .ops-lane-st { color: var(--state-text-stable); }
.ops-lane.is-warn .ops-lane-st { color: var(--state-text-warn); }
.ops-lane.is-offline .ops-lane-st { color: var(--state-text-offline); }
.ops-lane.is-idle .ops-lane-st { color: var(--state-text-idle); }
.ops-lane-n { margin-top: 8px; font-size: 40px; font-weight: 900; letter-spacing: -0.045em; line-height: 1; font-variant-numeric: tabular-nums; }
.ops-lane-n .u { font-size: 15px; font-weight: 750; }
.ops-lane-m { margin-top: 12px; font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ops-lanes-empty { margin: 0; padding: 18px 22px; }

/* ── 지도 | 막대 ─────────────────────────────────────────────────────────── */

.ops-mapgrid { display: grid; grid-template-columns: minmax(0, 1fr) 380px; border: var(--rule-w) solid var(--rule); }
.ops-mapgrid > .map { border: 0; margin: 0; min-height: 420px; height: 100%; }
.ops-bars { border-left: var(--rule-w) solid var(--rule); padding: 18px 20px; min-width: 0; }
.ops-bars h3 { margin: 0 0 4px; font-size: 18px; font-weight: 900; letter-spacing: -0.03em; }
.ops-bars > .ops-lab { margin-bottom: 14px; }
.ops-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; margin-bottom: 11px; }
.ops-bar-n { font-size: 12.5px; font-weight: 750; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ops-bar-n small { color: var(--text-muted); font-weight: 600; font-size: 12px; }
.ops-bar-c { font-size: 14px; font-weight: 850; text-align: right; font-variant-numeric: tabular-nums; }
.ops-bar-t { grid-column: 1 / -1; height: 8px; background: var(--bg-elevated); }
.ops-bar-t > i { display: block; height: 100%; min-width: 2px; background: var(--text-primary); }
/* 1등만 바이올렛 — 순위를 말할 뿐 상태가 아니다. */
.ops-bar.is-top .ops-bar-t > i { background: var(--accent-fill); }
#driverMap { height: auto; min-height: clamp(360px, calc(100vh - 380px), 640px); }

/* 실시간 위치 — 오른쪽 기사 목록은 표가 아니라 두 줄짜리 줄이다(차량·시각 / 위도·경도). */
.ops-drivers thead { display: none; }
.ops-drivers, .ops-drivers tbody { display: block; }
.ops-drivers tr {
  display: grid; grid-template-columns: auto auto minmax(0, 1fr); gap: 2px 14px;
  padding: 10px 0; border-bottom: 1px solid var(--border-hair);
}
.ops-drivers tr:last-child { border-bottom: 0; }
.ops-drivers td { display: block; border: 0; padding: 0; background: none !important; }
.ops-drivers td:nth-child(1) { grid-column: 1 / 3; grid-row: 1; font-size: 14px; }
.ops-drivers td:nth-child(4) { grid-column: 3; grid-row: 1; justify-self: end; font-size: 12px; }
.ops-drivers td:nth-child(2), .ops-drivers td:nth-child(3) { grid-row: 2; text-align: left; font-size: 12px; color: var(--text-muted); font-weight: 650; }
.ops-drivers td:nth-child(2)::before { content: "위도 "; }
.ops-drivers td:nth-child(3)::before { content: "경도 "; }

/* ── 대시보드 ────────────────────────────────────────────────────────────── */

.ops-rollup td.ops-big { font-size: 18px; font-weight: 850; letter-spacing: -0.02em; }
.ops-rollup td strong { font-size: 15px; }

/* ── 계근 데이터: 최근 계량 표 | 고른 계량 ───────────────────────────────── */

.ops-split-data { grid-template-columns: minmax(0, 1fr) 340px; }
/* ★상세 판이 길게 늘어난 표를 따라 내려오게 붙여 둔다. 세로 선은 표 쪽이 긋는다. */
.ops-split-data > .ops-detail { border-left: 0; align-self: start; position: sticky; top: 12px; }
.ops-split-data > .table-wrap { border-right: var(--rule-w) solid var(--rule); }
.ops-split-data .table-wrap > table.ops-wtable { min-width: 680px; }
.ops-wtable th:first-child, .ops-wtable td:first-child { padding-left: 14px; }
.ops-wtable td { padding: 12px 10px; }
.ops-wtable th { padding: 12px 10px 10px; }
.ops-wtable .ops-where { font-size: 12px; line-height: 1.4; }
.ops-wtable .ops-meta { display: none; }
.ops-wtable .ops-car strong { font-size: 14px; font-weight: 850; letter-spacing: -0.01em; white-space: nowrap; }
.ops-wtable .ops-net { font-size: 14px; font-weight: 850; }
.ops-wtable tr.is-selected:hover > td { background: var(--accent-tint); }
.ops-foot { margin: 0; padding: 14px 16px; border-top: var(--rule-w) solid var(--rule); font-size: 12.5px; }

.ops-wdet-h { padding: 20px 22px 18px; background: var(--block); color: var(--block-text); }
.ops-wdet-h .ops-lab { color: var(--block-muted); }
.ops-plate { margin: 8px 0 10px; font-size: 34px; font-weight: 950; letter-spacing: -0.04em; line-height: 1.1; overflow-wrap: anywhere; }
/* 반전 블록 위의 상태 글자는 블록용 묶음을 쓴다 — 캔버스용 짙은 녹색은 검정 위에서 안 읽힌다. */
.ops-wdet-h .badge-stable { color: var(--inv-text-stable); }
.ops-wdet-h .badge-warn { color: var(--inv-text-warn); }
.ops-wdet-h .badge-offline { color: var(--inv-text-offline); }
.ops-wdet-h .badge-idle { color: var(--inv-text-idle); }
.ops-wdet-net { padding: 20px 22px; border-bottom: 1px solid var(--border-hair); }
.ops-net-v { margin-top: 10px; font-size: 56px; font-weight: 850; letter-spacing: -0.045em; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ops-net-v .u { font-size: 20px; }
.ops-wdet-net p { margin: 10px 0 0; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ops-wdet-flow { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-bottom: 1px solid var(--border-hair); }
.ops-wdet-flow > div { padding: 16px 22px; min-width: 0; }
.ops-wdet-flow > div + div { border-left: 1px solid var(--border-hair); }
.ops-wdet-flow .v { margin-top: 6px; font-size: 26px; font-weight: 850; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ops-wdet-flow .ops-lab.t { margin-top: 6px; font-weight: 650; letter-spacing: 0; }
dl.ops-kv { margin: 0; padding: 6px 22px 12px; font-size: 13px; }
.ops-kv > div { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border-hair); }
.ops-kv > div:last-child { border-bottom: 0; }
.ops-kv dt { color: var(--text-muted); font-weight: 650; flex: none; }
.ops-kv dd { margin: 0; font-weight: 750; text-align: right; font-variant-numeric: tabular-nums; min-width: 0; }

/* ── 회원 승인 · 차량 · 기사 ──────────────────────────────────────────────── */

.ops-members .person, .ops-fleet .person { gap: 10px; }
.ops-members h2 .badge { font-size: 15px; vertical-align: middle; }
.ops-members td strong, .ops-fleet td strong { font-size: 14px; font-weight: 850; }
.ops-fleet form.inline { padding: 14px 0 4px; }

/* ── 1280px 이하: 분할 보기의 오른쪽 판을 좁힌다 ──
 * ★1280 노트북은 가장 흔한 폭이다. 여기서 분할 보기(시안 D 의 얼굴)를 접으면 계근 데이터에서
 *  줄을 눌러도 상세가 안 나온다. 사이드바를 좁히고(console-responsive.css) 판도 좁혀 지킨다. */
@media (max-width: 1280px) {
  .ops-split { grid-template-columns: minmax(0, 1fr) 380px; }
  .ops-split-data { grid-template-columns: minmax(0, 1fr) 300px; }
  .ops-split-data .table-wrap > table.ops-wtable { min-width: 560px; }
  /* 칸 사이를 좁혀 상태 칸까지 한눈에 들게 한다(1200 안팎에서 «실중량» 앞이 잘렸다). */
  .ops-wtable td, .ops-wtable th { padding-left: 6px; padding-right: 6px; }
  .ops-wtable th:first-child, .ops-wtable td:first-child { padding-left: 12px; }
  .ops-net-v { font-size: 46px; }
  .ops-plate { font-size: 30px; }
}

/* ── 1180px 이하: 분할 보기를 접는다 ──
 * 사업장: 오른쪽 판 대신 카드 안에 계근대가 펼쳐진다. 계근 데이터: 표만 남는다(표에 같은 값이 다 있다).
 * 지도 | 막대는 위아래로 쌓는다. */
@media (max-width: 1180px) {
  .ops-split, .ops-split-data { grid-template-columns: minmax(0, 1fr); }
  .ops-split > .ops-detail { display: none; }
  .ops-split-data > .table-wrap { border-right: 0; }
  .ops-inline { display: block; margin: 14px -20px -16px -26px; border-top: 1px solid var(--border-hair); background: var(--bg-base); }
  .ops-inline-h { margin: 0; padding: 12px 20px 10px 26px; border-bottom: 1px solid var(--border-hair); color: var(--accent); }
  .ops-mapgrid { grid-template-columns: minmax(0, 1fr); }
  .ops-mapgrid > .map { height: 380px; min-height: 0; }
  #driverMap { height: clamp(360px, calc(100vh - 380px), 640px); min-height: 0; }
  .ops-bars { border-left: 0; border-top: var(--rule-w) solid var(--rule); }
  .ops-band .kpi.kpi-hero { flex-basis: 34%; }
  .ops-band .kpi.kpi-hero.kpi-wide { flex-basis: 52%; }
  .ops-band .kpi:not(.kpi-hero) { flex-basis: 20%; }
  .ops-band .kpi.kpi-hero .kpi-value { font-size: 48px; }
}

@media (max-width: 900px) {
  .card-actions > .filter-bar { flex-wrap: wrap; width: 100%; }
  .card-actions > .filter-bar input[type=search] { width: 100%; flex: 1 1 200px; }
  .card-actions:has(> .filter-bar) { width: 100%; margin-left: 0; }
}

/* ── 600px 이하: 휴대폰 ── */
@media (max-width: 600px) {
  .ops-band .kpi, .ops-band .kpi:not(.kpi-hero) { flex-basis: 140px; min-height: 0; padding: 14px; }
  .ops-band .kpi.kpi-hero, .ops-band .kpi.kpi-hero.kpi-wide { flex-basis: 100%; padding: 16px 18px; }
  .ops-band .kpi .kpi-value { font-size: 32px; }
  .ops-band .kpi.kpi-hero .kpi-value { font-size: 44px; }
  .ops-list .site-card { padding: 16px 16px 14px 20px; }
  .site-card-head strong { font-size: 21px; }
  .site-card-head .badge { margin-left: 0; width: 100%; }
  .site-card-nums { grid-template-columns: 54px minmax(0, 1fr) minmax(0, 1.4fr); gap: 10px; }
  .site-card-nums strong { font-size: 18px; }
  .site-card-foot .actions { margin-left: 0; }
  .ops-inline { margin: 14px -16px -14px -20px; }
  .ops-inline-h { padding: 10px 16px 8px 20px; }
  .ops-lane { padding: 14px; }
  .ops-lane-n { font-size: 28px; }
  .ops-lane-n .u { font-size: 12px; }
  .ops-lane-h { flex-direction: column; gap: 4px; }
  .ops-mapgrid > .map { height: 300px; }
  #driverMap { height: 320px; }

  /* 계근 데이터 — 차량번호가 제목인 카드: «차량 | 상태» / 사업장·시각·순번 / 1차 · 2차 · 실중량. */
  .ops-split-data .table-wrap > table.ops-wtable { min-width: 0; }
  .ops-wtable thead { display: none; }
  .ops-wtable, .ops-wtable tbody { display: block; }
  .ops-wtable tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 10px;
    grid-template-areas: "car car st" "where where where" "w1 w2 net";
    padding: 14px 12px; border-bottom: 1px solid var(--border-hair);
  }
  .ops-wtable tr:last-child { border-bottom: 0; }
  .ops-wtable td, .ops-wtable td:first-child { display: block; border: 0; padding: 0; background: none !important; box-shadow: none !important; text-align: left; }
  .ops-wtable tr.is-selected { background: var(--accent-tint); box-shadow: inset 5px 0 0 var(--accent-fill); }
  .ops-wtable .ops-car { grid-area: car; }
  .ops-wtable .ops-car strong { font-size: 17px; }
  .ops-wtable .ops-st { grid-area: st; justify-self: end; }
  .ops-wtable .ops-where { grid-area: where; }
  .ops-wtable .ops-meta { display: inline; }
  .ops-wtable .ops-seq, .ops-wtable .ops-at { display: none; }
  .ops-wtable .ops-w1 { grid-area: w1; }
  .ops-wtable .ops-w2 { grid-area: w2; }
  .ops-wtable .ops-net { grid-area: net; }
  .ops-wtable :is(.ops-w1, .ops-w2, .ops-net) { font-size: 15px; }
  .ops-wtable :is(.ops-w1, .ops-w2, .ops-net)[data-label]::before {
    content: attr(data-label); display: block; margin-bottom: 2px;
    font-size: 11px; font-weight: 800; letter-spacing: 0.02em; color: var(--text-muted);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ops-lane .dot-offline { animation: none; }
}
