* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Pretendard',
               'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
  background: #f4f5f7;
  color: #1f2540;
  font-size: 13px;
}

/* ── 접근 게이트 ─────────────────────────── */
.auth-gate {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, #152033 0%, #0c1322 100%);
  color: #e6ecff;
  z-index: 9999;
}
.auth-msg { text-align: center; padding: 32px; max-width: 420px; }
.auth-msg h2 { margin: 0 0 8px; font-size: 22px; }
.auth-msg p  { color: #9aa3c0; margin: 0 0 16px; }
.auth-msg code {
  display: inline-block;
  background: rgba(255,255,255,0.08);
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 12px;
  color: #cfd6f0;
}

/* ── 상단 바 ─────────────────────────────── */
.topbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 12px 20px;
  background: #152033;
  color: #fff;
  border-bottom: 3px solid #2b3b66;
}
.topbar .brand h1 { margin: 0; font-size: 18px; line-height: 1.2; display:flex; align-items:center; gap:8px; }
.env-badge {
  display: inline-block;
  padding: 2px 10px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 999px;
  background: #6b7299;
  color: #fff;
  letter-spacing: 0.5px;
}
.env-badge.env-prod { background: #1e7a4f; }
.env-badge.env-dev  { background: #c87a1c; }
.topbar .brand .muted { color: #9aa3c0; font-size: 12px; margin: 2px 0 0; }
.topbar .toolbar { display: flex; gap: 8px; margin-left: 16px; }
.topbar .status { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* 버튼 (#105) — .btn.ghost 의 기본값은 「밝은 패널 위」다.
   종전 기본값(투명 배경 + .btn 에서 상속한 흰 글자)은 어두운 topbar 에서만 읽혔고
   흰 패널(.cl-wrap 마감/자재)에서는 글자가 배경과 같은 색이라 빈 상자로 보였다.
   화면 수는 흰 패널 쪽이 훨씬 많으므로 기본을 밝은 쪽으로 두고
   어두운 곳(.topbar)만 아래에서 되돌린다. */
.btn {
  background: #2b3b66;
  color: #fff;
  border: 1px solid transparent;
  padding: 7px 14px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn:hover:not(:disabled) { background: #3a4d80; }
.btn:active:not(:disabled) { background: #24325a; }
.btn:focus-visible { outline: 2px solid #3a7bd5; outline-offset: 2px; }

.btn.ghost { background: #f4f5f7; color: #2b3b66; border-color: #c9d5e7; }
.btn.ghost:hover:not(:disabled) { background: #e5ebf5; border-color: #a9bcd8; }
.btn.ghost:active:not(:disabled) { background: #d9e2f0; }

/* 어두운 상단바 — 여기서만 종전의 투명/흰 글자 조합으로 되돌린다. */
.topbar .btn.ghost { background: transparent; color: #fff; border-color: #3a4d80; }
.topbar .btn.ghost:hover:not(:disabled) { background: rgba(255,255,255,0.10); border-color: #5a6da0; }

.btn.danger { background: #a53737; color: #fff; border-color: transparent; }
.btn.danger:hover:not(:disabled) { background: #c44141; }

/* 비활성은 투명도가 아니라 색으로 — opacity 는 배경까지 비쳐 글자를 다시 흐리게 만든다. */
.btn:disabled { cursor: not-allowed; background: #eef1f6; color: #97a1b5; border-color: #e2e8f0; }
.topbar .btn:disabled { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.45); border-color: transparent; }

.pill {
  display: inline-block;
  padding: 5px 12px;
  background: rgba(255,255,255,0.08);
  border-radius: 999px;
  font-size: 12px;
  white-space: nowrap;
}
.pill.ok  { background: #1e7a4f; }
.pill.err { background: #a53737; }
.pill.warn{ background: #c87a1c; }
.pill.user{ background: #3a4d80; }

/* ── 조회기간 바 (2026-07-13) — period-filter.js 렌더 ── */
.period-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 20px;
  background: #eef2f7; border-bottom: 1px solid #d8dee8;
  font-size: 13px; color: #2b3b66;
}
.period-bar .pf-title { font-weight: 600; }
.period-bar select,
.period-bar input[type="date"] {
  padding: 6px 8px; border: 1px solid #c9d5e7; border-radius: 6px;
  font: inherit; background: #fff; color: #1f2937;
}
.period-bar .pf-sep   { color: #8a94a6; }
.period-bar .pf-label { color: #1e7a4f; font-size: 12px; font-weight: 600; }
.period-bar .pf-hint  { color: #8a94a6; font-size: 12px; margin-left: auto; }
.period-bar .btn.pf-dirty { background: #c87a1c; }   /* 미적용 변경 있음 — 「적용」 강조 */

/* ── 선택 합계 패널 ─────────────────────────── */
.selection-panel {
  display: flex; align-items: center; gap: 16px;
  padding: 8px 20px;
  background: #fff;
  border-bottom: 1px solid #e3e7f0;
  flex-wrap: wrap;
}
.selection-panel .sp-left {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px;
  color: #2b3b66;
  min-width: 90px;
}
.selection-panel .sp-left strong {
  font-size: 16px;
  color: #1e7a4f;
  min-width: 28px;
  text-align: right;
}
.selection-panel .sp-sums {
  display: flex; gap: 6px; flex-wrap: wrap;
  align-items: center;
  flex: 1 1 auto;
}
.sum-chip {
  display: inline-block;
  padding: 3px 10px;
  background: #eef3ff;
  border: 1px solid #d6deef;
  border-radius: 999px;
  font-size: 12px;
  color: #1f2540;
}
.sum-chip b {
  font-weight: 700;
  color: #2b3b66;
  margin-right: 4px;
}

/* ── 모달 ────────────────────────────────── */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(20, 30, 60, 0.55);
  display: none;
  align-items: center; justify-content: center;
  z-index: 10000;
}
.modal-overlay.open { display: flex; }
.modal-card {
  background: #fff;
  border-radius: 12px;
  padding: 22px 26px;
  width: min(480px, 92vw);
  box-shadow: 0 24px 64px rgba(20, 30, 60, 0.32);
  color: #1f2540;
}
.modal-card h3 {
  margin: 0 0 6px;
  font-size: 18px;
  color: #2b3b66;
}
.modal-card h3.danger-title { color: #a53737; }
.modal-card .modal-form {
  display: flex; flex-direction: column; gap: 10px;
  margin: 14px 0;
}
.modal-card .modal-form label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: #627188;
}
.modal-card .modal-form input {
  padding: 8px 10px;
  border: 1px solid #c9d5e7;
  border-radius: 6px;
  font-size: 14px;
}
.modal-card .modal-form input:focus {
  outline: 2px solid #2b6cb0;
  border-color: #2b6cb0;
}
.modal-card .modal-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 14px;
}
/* 모달 전용 버튼 재정의는 없앴다 (#105) — 여기 있던 값이 그대로 .btn 기본값이 됐다.
   사본을 남겨 두면 기본값을 고칠 때 모달만 옛 값에 남는다. */
.modal-card .confirm-label {
  display: block;
  margin-top: 14px;
  font-size: 13px;
  color: #627188;
}
.modal-card .confirm-label input {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 8px 10px;
  border: 1.5px solid #a53737;
  border-radius: 6px;
  font-size: 14px;
}
/* ── 컬럼 설정 팝업 (컬럼 사용자화) ─────────── */
.modal-card.colpref-card {
  width: min(460px, 94vw);
  max-height: 82vh;
  display: flex; flex-direction: column;
}
.colpref-hint {
  margin: 4px 0 10px;
  font-size: 12px;
  color: #627188;
  line-height: 1.5;
}
.colpref-hint b { color: #2b3b66; }
.colpref-count {
  font-size: 12px;
  color: #1e7a4f;
  font-weight: 600;
  margin-bottom: 8px;
}
.colpref-list {
  flex: 1 1 auto;
  overflow-y: auto;
  border: 1px solid #e3e7f0;
  border-radius: 8px;
  padding: 4px;
  background: #fafbfd;
}
.colpref-row {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
}
.colpref-row:hover { background: #eef3ff; }
.colpref-row .colpref-chk {
  width: 16px; height: 16px; margin: 0;
  accent-color: #2b6cb0;
  cursor: pointer;
  flex: 0 0 auto;
}
.colpref-row .colpref-name {
  flex: 1 1 auto;
  color: #1f2540;
  font-weight: 500;
}
.colpref-row .colpref-field {
  flex: 0 0 auto;
  font-size: 11px;
  color: #94a3b8;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.colpref-actions { justify-content: flex-start; }
.colpref-actions #colPrefClose { margin-left: auto; }
.colpref-actions #groupPrefClose { margin-left: auto; }

/* ── 그룹 소계·컬럼 고정 ──────────────────── */
/* 그룹 헤더 행 (groupHeader formatter HTML) */
.tabulator .tabulator-group {
  background: #eef3ff;
  border-bottom: 1px solid #d6deef;
  font-weight: 500;
  padding: 6px 10px;
}
.tabulator .tabulator-group .grp-key   { color: #2b3b66; }
.tabulator .tabulator-group .grp-key b  { color: #1a4d8f; }
.tabulator .tabulator-group .grp-sub {
  margin-left: 14px;
  color: #627188;
  font-size: 12px;
  font-weight: 400;
}
/* 그룹·고정 팝업 — 그룹 기준 select */
.grouppref-sel {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: #2b3b66; font-weight: 500;
  margin: 8px 0 12px;
}
.grouppref-sel select {
  flex: 1 1 auto;
  padding: 7px 10px;
  border: 1px solid #c9d5e7;
  border-radius: 6px;
  font: inherit;
  background: #fff;
}

/* ── 내부 탭 바 ───────────────────────────── */
.erp-tab-bar {
  display: flex; gap: 4px; align-items: flex-end;
  padding: 4px 16px 0;
  background: #eef2f7;
  border-bottom: 1px solid #d8dee8;
  overflow-x: auto;
}
.erp-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 8px 5px 12px;
  font-size: 13px; font-weight: 500;
  color: #2b3a5e;
  background: #fff;
  border: 1px solid #cbd5e1;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  cursor: pointer;
  white-space: nowrap;
}
.erp-tab:hover { background: #f1f5f9; }
.erp-tab.active {
  background: #1a4d8f;
  color: #fff;
  border-color: #1a4d8f;
}
.erp-tab .erp-tab-label { pointer-events: none; }
.erp-tab-close {
  border: 0; background: transparent;
  color: #94a3b8; font-size: 15px; line-height: 1;
  cursor: pointer; padding: 0 3px; border-radius: 3px;
}
.erp-tab.active .erp-tab-close { color: #cfe0f5; }
.erp-tab-close:hover { background: rgba(0,0,0,0.14); color: #e11d48; }

/* ── 즐겨찾기 필터 팝업 ──────────────────────── */
.fav-cur {
  font-size: 12px; color: #627188;
  margin: 6px 0 10px;
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
}
.fav-chip {
  background: #eef3ff; border: 1px solid #dbe4f7; border-radius: 10px;
  padding: 2px 8px; font-size: 11px; color: #2b3b66;
}
.fav-form { display: flex; gap: 8px; align-items: flex-end; }
.fav-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 6px;
}
.fav-row:hover { background: #eef3ff; }
.fav-apply { flex: 0 0 auto; }
.fav-summ {
  flex: 1 1 auto; min-width: 0;
  font-size: 11px; color: #94a3b8;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fav-list { margin-top: 4px; }

/* ── 탭 배지 (정합성 검사 등 걸린건수) ─────── */
.erp-tab-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; margin-left: 4px; padding: 0 4px;
  border-radius: 8px; background: #a53737; color: #fff;
  font-size: 10px; font-weight: 700; line-height: 1;
}
.erp-tab.active .erp-tab-badge { background: #fff; color: #a53737; }

/* ── 정합성 검사 ────────────────────────────── */
.ic-filterbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; background: #eef2f7; border-bottom: 1px solid #d8dee8;
}
.ic-field { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #2b3b66; }
.ic-field select { padding: 6px 8px; border: 1px solid #c9d5e7; border-radius: 6px; font: inherit; background: #fff; }
.ic-cards { display: flex; gap: 12px; padding: 12px 16px; flex-wrap: wrap; }
.ic-card {
  flex: 1 1 200px; background: #fff; border: 1px solid #d8dee8;
  border-left: 4px solid #cbd5e1; border-radius: 8px; padding: 12px 16px;
}
.ic-card .ic-title { font-size: 13px; color: #2b3b66; font-weight: 600; }
.ic-card .ic-count { font-size: 28px; font-weight: 800; color: #1f2540; margin: 2px 0; }
.ic-card.warn { border-left-color: #c87a1c; }
.ic-card.warn .ic-count { color: #c87a1c; }
.ic-card.ok { border-left-color: #1e7a4f; }
.ic-card.ok .ic-count { color: #1e7a4f; }
#ic-findings { padding: 0 16px 16px; }
.ic-tag { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; }
.ic-tag.ic-warn { background: #fdf0dd; color: #9a5b12; }
.ic-tag.ic-err  { background: #fbe3e3; color: #a53737; }
.ic-tag.ic-info { background: #e6effb; color: #2b6cb0; }
.ic-open-btn { padding: 4px 10px; font-size: 12px; }
.ic-proc { display: inline-block; padding: 2px 8px; border-radius: 6px; background: #eef3ff; color: #2b3b66; font-weight: 600; font-size: 12px; white-space: nowrap; }
.tabulator-row.ic-row-hl { animation: ic-flash 2.2s ease-out; }
@keyframes ic-flash { from { background: #fff3cd; } to { background: transparent; } }

/* ── 행 딥링크 (row-link.js · #42) ───────────── */
/* 지목한 행 — 필터를 풀 때까지 유지되는 강조. 품번·구역이 빈 행은 그 칸을 검색 조건으로
   걸 수 없어 같은 조건의 동행이 여럿 남는다. 그중 어느 것인지는 이 표시만이 말한다.
   ⚠ background 에 !important — 뒤에 오는 `.tabulator-row-even`(같은 특정도)에 밀린다.
      hover 는 그 뒤에서 !important 로 다시 덮으므로 마우스 반응은 그대로다. */
.tabulator .tabulator-row.rl-row-pin { background: #fff3cd !important; box-shadow: inset 3px 0 0 #c87a1c; }

.rl-banner {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 20px;
  background: #fff8e6; border-bottom: 1px solid #e6d3a3;
  font-size: 13px; color: #7a5312;
}
.rl-banner[hidden] { display: none; }
.rl-banner .rl-what  { font-weight: 600; }
.rl-banner .rl-cond  { color: #9a7434; font-size: 12px; }
.rl-banner .rl-clear { margin-left: auto; padding: 4px 12px; font-size: 12px; }

/* ── 마감 / 넷스윗 ──────────────────────────── */
.cl-wrap { display: flex; flex-direction: column; }
.cl-filters { padding: 12px 16px; background: #fff; border-bottom: 1px solid #e3e7f0; }
.cl-frow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.cl-frow:last-child { margin-bottom: 0; }
/* .cl-frow 는 display:flex 라 UA 의 [hidden]{display:none} 을 이겨 버린다 —
   hidden 을 세워도 줄이 그대로 보인다(#104 반완칼 하위줄). 여기서 되돌린다. */
.cl-frow[hidden] { display: none; }
.cl-field { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #2b3b66; }
.cl-field input[type=date], .cl-field select { padding: 6px 8px; border: 1px solid #c9d5e7; border-radius: 6px; font: inherit; }
.cl-tilde { color: #94a3b8; }
.cl-lbl { font-size: 13px; color: #2b3b66; font-weight: 600; min-width: 56px; }
.cl-checks { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.cl-chk { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: #384364; }
/* 공정 필터 — 정본 외 코드값(폐기값·오타)은 색으로 구분하되 반드시 선택 가능하게 둔다.
   목록에서 빼면 그 행의 수량이 마감 집계에서 조용히 누락된다 (2026-07-29 #14) */
.cl-chk-extra { color: #a15c00; }
.cl-sep { color: #c9d5e7; margin: 0 2px; }
.cl-mini { padding: 3px 9px !important; font-size: 11px !important; }
/* 반완칼 하위 필터 (#104) — 공정 줄에 딸린 한 단계 아래 줄임을 왼쪽 선으로 보인다. */
.cl-subrow { margin-left: 2px; padding-left: 10px; border-left: 2px solid #dbe3ef; }
.cl-lbl-sub { color: #5b6784; font-weight: 600; min-width: 78px; }
.cl-actions { margin-top: 4px; }
#closing-result { padding: 12px 16px 0; }
/* 자재 사용량 (#23) — 두 영역(자재별/지시서별) 세로 배치 + 영역별 다운로드 툴바 */
.mat-section { padding: 8px 16px 0; }
.mat-sec-hd { display: flex; align-items: center; gap: 8px; padding: 6px 2px; font-size: 14px; color: #2b3b66; }
.mat-sec-hd .mat-dl { margin-left: auto; display: flex; gap: 6px; }
#mat-material, #mat-detail { border: 1px solid #e3e7f0; border-radius: 8px; }
.cl-log-wrap { padding: 12px 16px 24px; }
.cl-log-title { margin: 8px 0; font-size: 14px; color: #2b3b66; }
.cl-log { border: 1px solid #e3e7f0; border-radius: 8px; background: #fafbfd; max-height: 240px; overflow-y: auto; }
.cl-log-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid #eef1f6; }
.cl-log-row:last-child { border-bottom: 0; }
.cl-log-main { flex: 1 1 auto; min-width: 0; }
.cl-log-l1 { font-size: 13px; color: #1f2540; }
.cl-log-actions { display: flex; gap: 6px; flex: 0 0 auto; }
.cl-log-actions .btn { padding: 4px 8px; font-size: 11px; }
.cl-reg { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 11px; font-weight: 700; margin-right: 4px; }
.cl-reg-on  { background: #e3f4ea; color: #1e7a4f; }
.cl-reg-off { background: #fdf0dd; color: #9a5b12; }
.cl-warn { color: #a53737 !important; font-weight: 600; }

/* ── 커스텀 체크박스 컬럼 ──────────────────── */
.tabulator .tabulator-cell.col-selector,
.tabulator .tabulator-col.col-selector .tabulator-col-content {
  padding: 0;
}
.tabulator .erp-row-check,
.tabulator .erp-check-all {
  cursor: pointer;
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: #2b6cb0;
}
.tabulator .tabulator-row.tabulator-selected {
  background-color: #e3f0ff !important;
}
.tabulator .tabulator-row.tabulator-selected:hover {
  background-color: #d4e6ff !important;
}

/* ── 커스텀 우클릭 컨텍스트 메뉴 ──────────────── */
.erp-ctx-menu {
  position: fixed;
  z-index: 99999;
  background: #fff;
  border: 1px solid #c9d5e7;
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(20,30,60,0.22);
  padding: 6px 0;
  min-width: 220px;
  font-size: 13px;
  color: #1f2540;
  user-select: none;
}
.erp-ctx-menu.hidden { display: none; }
.erp-ctx-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 16px;
  border: 0;
  background: transparent;
  font-size: 13px;
  cursor: pointer;
  color: #1f2540;
  font-family: inherit;
}
.erp-ctx-menu button:hover {
  background: #eef3ff;
  color: #1d4ed8;
}
.erp-ctx-menu .erp-ctx-sep {
  height: 1px;
  background: #e3e7f0;
  margin: 4px 0;
}

/* 수정자 pill — 미확인 시 클릭 가능 표시 */
.pill.warn { background: #c87a1c; }
.pill.warn u { text-decoration: underline; }

/* ── 신규 행 입력 모달 — 그리드 레이아웃 ───────── */
.modal-card.insert-card {
  width: min(820px, 95vw);
  max-height: 85vh;
  display: flex; flex-direction: column;
}
.insert-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 18px;
  margin: 14px 0;
  overflow-y: auto;
  padding-right: 6px;
  flex: 1 1 auto;
}
@media (max-width: 640px) { .insert-grid { grid-template-columns: 1fr; } }
.ins-row {
  display: grid;
  grid-template-columns: 90px 1fr;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: #2b3b66;
}
.ins-lbl { font-weight: 600; color: #2b3b66; }
.ins-fld {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid #c9d5e7;
  border-radius: 6px;
  font-size: 13px;
  background: #fff;
  color: #1f2540;
  font-family: inherit;
}
.ins-fld:focus { outline: 2px solid #2b6cb0; border-color: #2b6cb0; }

.delete-preview {
  background: #fbf2f2;
  border: 1px solid #f2c7c7;
  border-radius: 6px;
  padding: 10px 12px;
  margin: 10px 0 0;
  font-size: 12px;
  color: #6b2222;
  max-height: 180px;
  overflow: auto;
  white-space: pre-wrap;
  font-family: -apple-system, 'Segoe UI', 'Pretendard', sans-serif;
}

/* ── 본문 ─────────────────────────────── */
main {
  padding: 12px 20px;
}
#grid {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(20,30,60,0.08);
  overflow: hidden;
}

/* Tabulator 한국어 친화 미세조정 */
.tabulator { font-size: 12.5px; }
.tabulator .tabulator-header .tabulator-col {
  background: #f0f2f7;
  border-right: 1px solid #e3e7f0;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-title {
  font-weight: 600; color: #2b3b66;
}
.tabulator .tabulator-row.tabulator-row-even { background: #fafbfd; }
.tabulator .tabulator-row:hover { background: #eef3ff !important; }

/* ── 편집 셀 ─────────────────────────────── */
.tabulator .tabulator-cell.cell-editable {
  cursor: cell;
  background-image: linear-gradient(135deg, transparent 0 calc(100% - 6px), #cfd6f0 calc(100% - 6px) 100%);
}
.tabulator .tabulator-cell.cell-editable:hover {
  background-color: #fffbe8;
}
.tabulator .tabulator-cell.tabulator-editing {
  outline: 2px solid #2b6cb0;
  background: #fff !important;
}

/* 저장 상태 — 짧게 깜빡 */
.tabulator .tabulator-cell.cell-saving {
  background-color: #fff5cc !important;
  transition: background-color 0.2s;
}
.tabulator .tabulator-cell.cell-saved {
  background-color: #d6f5e3 !important;
  transition: background-color 1.2s;
}
.tabulator .tabulator-cell.cell-error {
  background-color: #fbd6d6 !important;
  transition: background-color 2.2s;
}

/* ── 푸터 ─────────────────────────────── */
.footer {
  display: flex; gap: 16px; justify-content: space-between;
  padding: 10px 20px;
  color: #6b7299;
  font-size: 12px;
}


/* ── 상단 메뉴바 (2026-05-26 추가) ─────── */
.menu-bar {
  display: flex; gap: 6px;
  margin: 0 16px;
  padding: 0;
  align-items: center;
}
.menu-bar .menu-btn {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 8px 16px;
  font-size: 14px;
  font-weight: 500;
  color: #5a6a8a;
  cursor: pointer;
  transition: all 0.15s;
}
.menu-bar .menu-btn:hover {
  background: #f0f3fa;
  color: #2b3a5e;
}
.menu-bar .menu-btn.active {
  background: #2b6cb0;
  color: white;
  border-color: #2b6cb0;
  box-shadow: 0 1px 3px rgba(43, 108, 176, 0.3);
}

/* ── 메뉴별 뷰 영역 ── */
.menu-view {
  /* hidden 속성으로 토글, 기본 표시 */
}
.menu-view[hidden] {
  display: none !important;
}

/* ── 좌측 사이드바 네비게이션 (2026-06-15) ──────────── */
.sidebar-toggle {
  flex: 0 0 auto;
  width: 38px; height: 34px;
  background: transparent;
  border: 1px solid #3a4d80;
  color: #fff;
  border-radius: 6px;
  font-size: 17px; line-height: 1;
  cursor: pointer;
}
.sidebar-toggle:hover { background: rgba(255,255,255,0.08); }

/* position: relative 는 제조 AI 패널이 이 칸을 기준으로 서기 위한 것이다.
   여기 말고는 영향이 없다 — 안쪽의 absolute 두 곳(.menu-bar-l2 · .ts-more-body)은
   각자 relative 부모를 이미 갖고 있다. */
.app-body { display: flex; align-items: stretch; position: relative; }
.content-area { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.sidebar {
  flex: 0 0 auto;
  width: 230px;
  min-height: 0;
  background: #fff;
  border-right: 1px solid #d8dee8;
  overflow-y: auto;
  overflow-x: hidden;
  transition: width 0.15s ease;
}
body.sidebar-collapsed .sidebar { width: 0; border-right: 0; }
.sidebar-nav { padding: 8px 8px 24px; min-width: 214px; }

.sb-group { margin-bottom: 1px; }
.sb-group-hd {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: transparent; border: 0; cursor: pointer;
  padding: 9px 8px; border-radius: 6px;
  font-size: 13px; font-weight: 600; color: #1f2540; text-align: left;
}
.sb-group-hd:hover { background: #f0f3fa; }
.sb-chev {
  flex: 0 0 auto; width: 12px;
  font-size: 10px; color: #94a3b8;
  transition: transform 0.12s ease;
}
.sb-group.open > .sb-group-hd .sb-chev { transform: rotate(90deg); }
.sb-ico { flex: 0 0 auto; font-size: 14px; }
.sb-grp-label { flex: 1 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.sb-items { display: none; padding: 1px 0 6px; }
.sb-group.open > .sb-items { display: block; }
.sb-item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: 0; cursor: pointer;
  padding: 8px 10px 8px 32px;
  border-radius: 6px;
  font-size: 13px; color: #384364;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-item:hover { background: #f0f3fa; color: #1a4d8f; }
.sb-item.active { background: #2b6cb0; color: #fff; font-weight: 500; }

/* ── 메뉴바 (2026-05-27 드롭다운 형식) ─────── */
/* L1 = 항상 보이는 카테고리 버튼 가로 줄 (헤더와 본문 경계에 위치) */
.menu-bar-l1 {
  position: relative;            /* L2 absolute 기준 */
  display: flex;
  gap: 2px;
  align-items: center;
  background: linear-gradient(180deg, #f7f9fc 0%, #eef2f7 100%);
  border-top: 1px solid #d8dee8;
  border-bottom: 1px solid #d8dee8;
  padding: 0 16px;
  min-height: 32px;
}
.menu-bar-l1 .menu-btn {
  font-size: 13px;
  font-weight: 500;
  padding: 5px 12px;
  border: 1px solid transparent;
  background: transparent;
  color: #2b3a5e;
  border-radius: 4px;
  cursor: pointer;
  position: relative;
  transition: background 0.12s;
}
.menu-bar-l1 .menu-btn::after {
  content: '▾';
  font-size: 10px;
  margin-left: 6px;
  color: #94a3b8;
}
.menu-bar-l1 .menu-btn:hover {
  background: #e2e8f0;
}
.menu-bar-l1 .menu-btn.active {
  background: #1a4d8f;
  color: white;
}
.menu-bar-l1 .menu-btn.active::after { color: white; }

/* L2 = 드롭다운 패널 (L1 버튼 아래 absolute) */
.menu-bar-l2 {
  position: absolute;
  display: none;
  top: 100%;
  left: 0;
  margin-top: 1px;
  background: white;
  border: 1px solid #cbd5e1;
  border-radius: 6px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
  padding: 4px;
  min-width: 220px;
  z-index: 150;
}
.menu-bar-l2.open {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.menu-bar-l2 .menu-btn {
  font-size: 13px;
  padding: 8px 14px;
  text-align: left;
  background: transparent;
  border: none;
  color: #1f2937;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  width: 100%;
  display: block;
  transition: background 0.1s;
}
.menu-bar-l2 .menu-btn:hover {
  background: #f1f5f9;
}
.menu-bar-l2 .menu-btn.active {
  background: #dbeafe;
  color: #1a4d8f;
  font-weight: 600;
}
.menu-bar-l2 .menu-empty {
  color: #94a3b8;
  font-size: 12px;
  padding: 8px 14px;
  font-style: italic;
}

/* ── 타임별 생산실적(신설) — 묻는 순서대로 세운 화면 ─────────── */
/*  이 화면의 버튼은 .ts-btn(테두리형)이다 — 단계 안내와 폭을 맞춰 따로 둔다.
      ⚠ 종전의 「.btn.ghost 를 쓰지 말라」는 사유(흰 배경 위 흰 글자)는
      #105 에서 기본값을 뒤집어 없어졌다. 새 화면은 .btn.ghost 를 그냥 써도 된다. */
.ts-wrap { display: flex; flex-direction: column; }

/* ① 고르기 — 단계마다 번호를 달고 질문을 그대로 적는다. */
.ts-bar { padding: 10px 16px 8px; background: #fff; border-bottom: 1px solid #e3e7f0; }
.ts-step { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.ts-step:last-child { margin-bottom: 0; }
.ts-num {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  background: #2b3b66; color: #fff; font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.ts-q { font-size: 14px; font-weight: 600; color: #1f2540; margin-right: 4px; }

/* 타임 — 이 화면의 유일한 체크박스. 라벨 전체가 누를 자리다. */
.ts-chips { display: contents; }
.ts-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 12px; border: 1px solid #c9d5e7; border-radius: 999px;
  background: #fff; color: #384364; font-size: 13px;
  cursor: pointer; user-select: none;
}
.ts-chip:hover { background: #eef2f7; }
.ts-chip.on { background: #2b3b66; border-color: #2b3b66; color: #fff; }
.ts-chip input { margin: 0; accent-color: #2b3b66; }
.ts-chip.on input { accent-color: #fff; }
.ts-all { font-weight: 600; }

/* 공정·세부·도수 — 드롭다운. 고른 것이 있으면 색으로 표가 난다. */
.ts-sel {
  padding: 6px 10px; border: 1px solid #c9d5e7; border-radius: 6px;
  background: #fff; color: #1f2540; font: inherit; font-size: 13px; max-width: 280px;
}
.ts-sel:focus { outline: 2px solid #3a4d80; outline-offset: 1px; }
.ts-sel.on { border-color: #2b3b66; background: #eef3ff; font-weight: 600; }
.ts-sub { display: inline-flex; align-items: center; gap: 8px; }
.ts-arrow { color: #94a3b8; font-size: 15px; }

/* ② 결과 — 「몇 건 보이나」가 이 화면에서 가장 큰 글자다. */
.ts-result {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 8px 16px; background: #fafbfd; border-bottom: 1px solid #e3e7f0;
}
.ts-big { font-size: 20px; font-weight: 700; color: #1e7a4f; }
.ts-big.warn { color: #c87a1c; }
.ts-note { font-size: 12px; color: #8a94a6; }
.ts-gap { flex: 1 1 auto; }

/* ③ 안내 — 본문(고르기·결과) 아래로 내린다. */
.ts-tips {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 7px 16px; background: #fff; border-bottom: 1px solid #e3e7f0;
  font-size: 12px; color: #627188;
}
.ts-ask { color: #384364; }

.ts-btn {
  padding: 5px 11px; border: 1px solid #c9d5e7; border-radius: 6px;
  background: #fff; color: #2b3b66; font: inherit; font-size: 12px;
  cursor: pointer; white-space: nowrap;
}
.ts-btn:hover { background: #eef2f7; border-color: #2b3b66; }

/* 드문 설정은 접어 둔다 — 늘 보이면 자주 쓰는 것과 무게가 같아진다. */
.ts-more { position: relative; }
.ts-more > summary {
  list-style: none; cursor: pointer;
  padding: 5px 11px; border: 1px solid #c9d5e7; border-radius: 6px;
  background: #fff; color: #2b3b66; font-size: 12px;
}
.ts-more > summary::-webkit-details-marker { display: none; }
.ts-more[open] > summary { background: #eef3ff; border-color: #2b3b66; }
.ts-more-body {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  display: flex; flex-direction: column; gap: 8px;
  min-width: 240px; padding: 10px 12px;
  background: #fff; border: 1px solid #c9d5e7; border-radius: 8px;
  box-shadow: 0 6px 18px rgba(31, 37, 64, 0.14);
}
.ts-opt { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #384364; cursor: pointer; }
/* 0건 항목은 잠근다 — 고를 수 있게 두면 무엇을 골라도 0건인 막다른 길이 된다(PR #61 규약). */
.ts-opt.off { color: #b6bdca; cursor: not-allowed; }
/* 도수 패널 — 껍데기는 ⚙ 고급과 같고 여는 방향만 왼쪽이다(필터바 왼쪽이라 오른쪽 정렬이면
   화면 밖으로 밀린다). 항목이 열 줄까지 늘어나므로 패널 안에서만 스크롤한다. */
.ts-more-left > .ts-more-body { right: auto; left: 0; max-height: 60vh; overflow-y: auto; gap: 6px; }
/* 고른 것이 있으면 옆 드롭다운(.ts-sel.on)과 같은 표시를 준다 — 나란히 서 있는 컨트롤이다. */
.ts-more > summary.on { border-color: #2b3b66; background: #eef3ff; font-weight: 600; }
/* 「전체」는 값이 아니라 동작이라 체크박스로 두지 않는다 — 켜고 끄는 것이 아니라 모두 해제다. */
.ts-optall {
  padding: 0 0 6px; border: 0; border-bottom: 1px solid #e3e7f0;
  background: transparent; color: #2b3b66;
  font: inherit; font-size: 12px; font-weight: 600; text-align: left; cursor: pointer;
}
.ts-optall:hover { text-decoration: underline; }

.ts-banner {
  padding: 8px 16px; background: #fff8ec;
  border-bottom: 1px solid #e8d3ad; color: #8a5210; font-size: 13px;
}
.ts-banner.err { background: #fdecec; border-bottom-color: #e8b4b4; color: #a53737; font-weight: 600; }
.ts-grid { padding: 10px 16px 0; }

/* 그룹헤더 — 왼쪽 「무엇을 만들었나」, 오른쪽 「얼마나」. 곁다리 표시는 조용하게. */
.tabulator .tabulator-group .ts-tag {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  border: 1px solid #c9d5e7; border-radius: 999px;
  color: #627188; font-size: 11px; font-weight: 400;
}
.tabulator .tabulator-group .ts-tag.warn { border-color: #c87a1c; color: #8a5210; }
/* 모든 그룹에 붙는 버튼이라 눈에 띄면 경고가 뜻을 잃는다 — 평소엔 조용하고 hover 에 드러난다. */
.tabulator .tabulator-group .ts-gz {
  margin-left: 12px; padding: 1px 9px;
  border: 1px solid #d8dee8; border-radius: 999px;
  background: transparent; color: #8a94a6;
  font: inherit; font-size: 11px; cursor: pointer;
}
.tabulator .tabulator-group:hover .ts-gz { color: #8a5210; border-color: #c9b28a; }
.tabulator .tabulator-group .ts-gz:hover { background: #fff8ec; color: #8a5210; border-color: #c87a1c; }

/* ⚠ hidden 이 안 듣는 자리 — [hidden]{display:none} 은 브라우저 기본 스타일이라
   작성자가 쓴 display 에 **특정도와 무관하게** 진다. .ts-sub 가 inline-flex 라
   「고를 것이 있을 때만 나타낸다」는 규칙이 안 지켜졌고 세부·도수 콤보가 빈 상자로
   남았다. 한 줄로 못박아 다음 .ts-* 에서 되풀이되지 않게 한다. */
[class^="ts-"][hidden], [class*=" ts-"][hidden] { display: none; }

/* ── 부모 수량 자동 반영 안내 배너 (parent-qty-sync · #71) ──────────
   대상 메뉴는 「자동 갱신된다」를, 제외 메뉴는 「왜 안 되는지」를 그리드 위에 띄운다.
   JS(js/parent-qty-sync.js mountPsyncNotes)가 view-<메뉴키> 섹션 맨 앞에 삽입. */
.psync-note {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  margin: 0 0 10px;
  padding: 9px 12px;
  border: 1px solid #f0d69a;
  border-radius: 8px;
  background: #fdf7e7;
  color: #7a5a12;
  font-size: 12.5px;
  line-height: 1.55;
}
.psync-note-ico { flex: 0 0 auto; font-weight: 700; }

/* ── 공정 인수표 (2026-08-28) ─────────────────────────────────────
   품번 × 타입 행 · 공정 열. Tabulator 를 쓰지 않는 순수 HTML 표다 —
   칸 안에 숫자·불량·근거를 겹쳐 넣어야 해서 그리드보다 표가 짧다.
   ⚠ 가로가 길어 표만 스크롤한다(.hf-table). 페이지 자체는 가로 스크롤되지 않게. */
.hf-wrap { display: flex; flex-direction: column; }
.hf-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; background: #fff; border-bottom: 1px solid #e3e7f0; }
.hf-field { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #2b3b66; }
.hf-field input[type=date] { padding: 6px 8px; border: 1px solid #c9d5e7; border-radius: 6px; font: inherit; }
.hf-tilde { color: #94a3b8; }
.hf-brands { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-left: 8px; }
.hf-brand { padding: 3px 10px; border: 1px solid #c9d5e7; border-radius: 999px;
  background: #fff; color: #384364; font-size: 12px; cursor: pointer; }
.hf-brand:hover { background: #eef2f7; }
.hf-brand.on { background: #2b3b66; border-color: #2b3b66; color: #fff; }
#hf-summary { margin-left: auto; }

.hf-table { padding: 0; }
.hf-grid { border-collapse: collapse; width: 100%; font-size: 12.5px; }
/* ── 촘촘하게 ────────────────────────────────────────────────
   업무표를 최대한 많이 보이게 한다. 우측에 제조 AI 패널이 서면 가로가
   400px 줄어드는데, 공정 열이 넉넉하면 그만큼 열이 화면 밖으로 나간다.
   ⚠ 숫자는 안 줄인다. 좁히는 것은 여백이지 값이 아니다. */
/* ★ 격자 (2026-09-05 · 1안) — 종전에는 가로선 하나뿐이었다. 세로선이 없으니 어느 숫자가
   어느 공정 칸인지 눈이 스스로 맞춰야 했고, 값이 드문 표라 숫자가 허공에 떠 보였다.
   이 화면을 쓰는 분들이 보던 것은 엑셀 시트다 — 칸을 칸으로 보이게 되돌린다. */
.hf-grid th, .hf-grid td {
  border-right: 1px solid #d6dce6; border-bottom: 1px solid #d6dce6; padding: 5px 5px;
}
.hf-grid th:last-child, .hf-grid td:last-child { border-right: 0; }
/* ⚠ z-index 는 왼쪽 고정 칸(.hf-part·.hf-verdict = 1)보다 위여야 한다 — 낮으면 머리줄 밑으로
   지나가는 행의 품번·부제가 글자 사이로 비친다(2026-09-05 스테이징 실측). */
/* ★ 틀 고정선은 border 가 아니라 «칸 안쪽 그림자» 다 (2026-09-05 스테이징 실측).
   이 표는 `border-collapse: collapse` 라 **접힌 테두리를 「칸」이 아니라 「표」가 그린다.**
   그래서 sticky 로 떠 있는 머리칸에 `border-bottom` 을 줘도 선은 머리칸을 따라오지 않고
   내용과 함께 굴러간다 — 아래로 조금만 스크롤하면 **머리줄과 행 사이에 선이 사라져**
   숫자가 머리줄에 그대로 이어 붙는다. `inset` 그림자는 칸 안쪽에 그려지므로 칸을 따라온다.
   ⚠ 같은 이유로 아래 왼쪽 고정 칸들의 «오른쪽» 선도 border 가 아니라 inset 그림자다.
      border 로 두면 가로로 구를 때 그 선만 왼쪽으로 밀려 사라진다.
   ⚠ 그림자로 바꾼 칸은 `border-*: 0` 을 같이 준다 — 안 주면 위 격자선 1px 이 남아 겹친다. */
.hf-grid thead th { position: sticky; top: 0; z-index: 4; background: #eef1f6;
  border-bottom: 0; box-shadow: inset 0 -2px 0 #aeb9cb;
  color: #1f2540; font-weight: 600; text-align: right; white-space: nowrap; }
/* ⚠ 머리칸도 왼쪽 고정이다 — 아래 .hf-part 는 고정인데 여기만 빠져 있어 가로로 구르면
   머리칸만 따라 밀렸다(2026-09-05). position 은 위 thead th 가 이미 준다. */
/* ⚠ 선택자에 th/td 를 붙여 두는 이유 — 위 `.hf-grid th, .hf-grid td` 가 (0,1,1) 이라
   클래스 하나짜리(0,1,0)로 쓰면 격자선 1px 이 이겨 `border-right: 0` 이 먹지 않고,
   `.hf-grid thead th` 의 z-index 4 도 못 이겨 **가로로 구르면 공정 머리칸이 이 두 칸을 덮는다**
   (머리줄에서 품번·판정이 통째로 사라진다). 2026-09-05 스테이징 실측으로 잡았다. */
.hf-grid th.hf-th-part { text-align: left !important; min-width: 176px; width: 176px;
  left: 0; z-index: 5; border-right: 0;
  box-shadow: inset -2px 0 0 #aeb9cb, inset 0 -2px 0 #aeb9cb; }
/* 공정 열은 네 자리 수 + 아래 보조 두 줄이 들어갈 만큼만. */
.hf-th-proc { min-width: 84px; }
.hf-th-sub { display: block; font-size: 10.5px; color: #94a3b8; font-weight: 500; }

/* 품번 칸만 왼쪽에 고정 — 공정이 늘어도 「어느 품번 줄인지」를 잃지 않는다.
   ⚠ 고정 칸에는 반드시 배경색이 있어야 한다. 투명하면 스크롤되는 숫자가 밑으로 비쳐 지나간다. */
/* 고정 칸 오른쪽은 굵게 — 엑셀 틀 고정의 그 선이다. 여기부터 오른쪽이 구른다. */
.hf-grid td.hf-part { position: sticky; left: 0; z-index: 1; background: #fff;
  text-align: left; border-right: 0; box-shadow: inset -2px 0 0 #aeb9cb; }
.hf-grid tbody tr:hover .hf-part { background: #f5f8ff; }
.hf-part b { color: #1f2540; }
.hf-part-sub { display: block; font-size: 10.5px; color: #94a3b8; margin-top: 1px; }
.hf-sub { display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 9px;
  background: #eef2f7; color: #2b3b66; font-size: 10.5px; font-weight: 700; }

.hf-cell { text-align: right; white-space: nowrap; }
.hf-grid tbody tr:hover td { background: #f5f8ff; }
.hf-none { color: #cbd5e1; }
/* 여백을 줄인 만큼 숫자는 오히려 또렷하게. 이 표에서 읽는 것은 이 값이다. */
/* 칸 윗줄 — 왼쪽 기준 → 오른쪽 결과. 기준이 없으면 왼쪽이 비고 결과만 오른쪽에 붙는다
   (.hf-q 의 margin-left:auto 가 그 일을 한다 — 빈 자리를 채우는 요소를 따로 두지 않는다). */
.hf-line { display: flex; align-items: baseline; gap: 4px; }
.hf-base { font-size: 13px; color: #6b7891; font-variant-numeric: tabular-nums; }
.hf-arrow { font-size: 10px; color: #c3cad6; }
.hf-q { margin-left: auto; font-variant-numeric: tabular-nums; color: #1f2540;
  font-size: 13px; font-weight: 600; }
/* 아랫줄 — 환산 근거 · 차이 · 불량을 한 줄로. 종전 3줄이 여기로 접혔다. */
.hf-cellsub { text-align: right; font-size: 10.5px; color: #8a93a6;
  font-variant-numeric: tabular-nums; margin-top: 1px; }
.hf-dv { font-weight: 700; color: #6b7891; }
.hf-dv-ok { font-weight: 500; color: #b6c0d0; }
.hf-mute { color: #c3cad6; font-style: italic; }
/* GP합지 층 분해(2026-09-07) — 「배열 미상」같은 결손 표시가 아니라 근거라서,
   hf-mute(아주 옅음·기울임)가 아니라 보조줄 기본색보다 살짝 진하게 둔다.
   ⚠ .hf-cell 이 white-space:nowrap 이고 표는 table-layout:auto 라, 층 문자열
   (「2P+2U 123 · A3U 123 · ACR 123 · PCA 120+불량3」 ≈ 250px)이 그대로 서면
   합지 열만 3배로 벌어져 표 전체가 가로로 길어진다. 「5층까지만」이라는 상한은
   글자 수를 안 묶으므로 너비를 여기서 묶는다 — 넘치면 «…» 로 줄이고 전문은 툴팁에 있다. */
.hf-layers { color: #6b7891; display: inline-block; max-width: 220px;
             overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.hf-bad { color: #a53737; }
.hf-wip { color: #2b7a8f; }   /* 재고보관·재고사용(2026-09-03) — 불량(빨강)과 구분되는 정보성 색 */
/* 칸 전체가 링크다 — 숫자만 링크면 누를 자리가 너무 좁다. 밑줄은 hover 에서만. */
/* 2026-09-05 복원 — 아래 두 줄은 신설(b2c97ca)에 있었는데 칸 클릭 이동을 뺀 bdfb42e 가
   함께 지웠다(그때는 <a> 가 아니어서 티가 안 났다). 09-02 에 이동만 되살아나고(cellHref)
   CSS 는 안 돌아와, 이 레포에 전역 a 리셋이 없는 탓에 값 있는 칸마다 UA 기본 밑줄이 상시로 깔렸다.
   ⚠ 전역 a { text-decoration:none } 으로 고치지 않는다 — 다른 화면 링크까지 바뀐다.
   ⚠ hover 밑줄은 결과 숫자(.hf-q)에만 긋는다 — 칸 전체에 그으면 환산 근거·불량 보조줄까지
     따라와 칸이 두 줄로 어지러워진다. */
.hf-go { display: block; color: inherit; text-decoration: none; }
.hf-go:hover .hf-q { text-decoration: underline; color: #2b3b66; }

.hf-grp td { background: #f7f9fc; color: #2b3b66; font-weight: 700; font-size: 12px; }
.hf-empty { padding: 28px 16px; color: #94a3b8; font-size: 13px; }
.hf-legend { padding: 10px 16px 24px; color: #7a8699; font-size: 11.5px; line-height: 1.6; }
/* 반·완칼 칸 — 팀 완칼(위) / 구역 완칼(아래). 둘이 어긋나면 아래 줄을 붉게.
   어긋남 = 작업자가 반칼/완칼 버튼으로 등록 구역과 다르게 고른 행이 있다는 뜻이다. */
.hf-zone { display: block; font-size: 10.5px; color: #94a3b8; }
.hf-zone.hf-gap { color: #a53737; font-weight: 700; }
/* 공정 인수표 — 검색창 / 앞·뒤 차이 / 판정 (2026-08-28) */
.hf-find { padding: 6px 8px; border: 1px solid #c9d5e7; border-radius: 6px; font: inherit;
  font-size: 12.5px; width: 120px; }
.hf-find:focus { outline: none; border-color: #2b3b66; }

/* 공정 필터 (2026-09-05) — 열을 숨기지 않고 행만 좁힌다. 켜져 있으면 띠로 알린다.
   손잡이는 머리칸이다(오후 · 드롭다운 대체). 머리칸이 버튼이라 th 안의 button 을 th 처럼 보이게
   되돌린다 — 배경·테두리·글꼴을 물려받고 칸을 꽉 채운다(누를 수 있는 넓이가 곧 머리칸 넓이). */
/* ⚠ 여백은 th 가 아니라 button 이 가진다 — th 에 남겨 두면 그 5px 가장자리는 눌러도 반응이 없다. */
.hf-grid th.hf-th-proc { padding: 0; }
.hf-th-btn { display: block; width: 100%; padding: 5px 5px; margin: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: inherit; cursor: pointer; }
.hf-th-btn:hover .hf-th-l { text-decoration: underline; }
.hf-th-btn:focus-visible { outline: 2px solid #2b3b66; outline-offset: -2px; }
/* 오류 배지 — 「이 공정에 몇 건」. 붉은 계열 하나로 통일한다(덜받음·더받음을 합친 수라 어느 한쪽
   색을 쓰면 그쪽으로 읽힌다). 0 이면 안 그린다 — 열 열 개에 「0」이 줄지어 서면 소음이다. */
.hf-th-badge { display: inline-block; margin-left: 5px; min-width: 18px; padding: 0 5px;
  border-radius: 999px; background: #b3261e; color: #fff; font-size: 10.5px; font-weight: 700;
  line-height: 16px; text-align: center; vertical-align: 1px; }
/* 잘린 조회 — 숫자를 단정할 수 없다. 띠(.hf-banner-warn)와 같은 주황으로 「N+」. */
.hf-th-badge-trunc { background: #b06a12; }
/* 켜진 머리칸 — 이 공정으로 좁혀 보는 중. 아래 굵은 밑줄이 「여기」다.
   ⚠ th 배경은 위 `.hf-grid thead th` 가 sticky 와 함께 준다 — 선택자에 thead th 를 붙여야 이긴다. */
.hf-grid thead th.hf-th-on { background: #dbe4f5;
  box-shadow: inset 0 -3px 0 #2b3b66; }
/* 0건 안내를 표 본문 자리에 넣는다 — 머리줄(배지)이 남아 다른 공정으로 건너갈 수 있다. */
/* 오류 0 인 머리칸을 눌렀을 때 — 「없다」가 답이라 회색이 아니라 초록으로. 빈 화면이 고장이 아니라
   확인 결과로 읽혀야 한다. */
.hf-empty.hf-empty-ok { color: #1f6b3a; }
.hf-grid td.hf-empty-cell { padding: 0; border-right: 0; }
/* ⚠ inline-block 이어야 sticky 가 선다 — block 이면 안내가 표 너비만큼 넓어 붙을 자리가 없고,
   가로로 굴리면 글이 왼쪽으로 빠져나간다(범례 .hf-legend 와 같은 이유). */
.hf-grid td.hf-empty-cell .hf-empty { position: sticky; left: 0; display: inline-block; max-width: 100%; }
/* ⚠ display:flex 는 브라우저 기본 [hidden]{display:none} 을 이긴다 — 이 한 줄이 없으면
   필터를 안 건 «기본 상태»에서 빈 파란 띠가 늘 보이고, flex:0 0 auto 라 표 높이까지 먹는다.
   이 레포에서 되풀이된 함정이다: .rl-banner[hidden](:424) · .cl-frow[hidden](:436) ·
   [class^="ts-"][hidden](:957) · .ow-bar[hidden](:1404) 가 전부 같은 이유로 있다. */
.hf-banner[hidden] { display: none; }
.hf-banner { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 10px 16px 0; padding: 7px 12px; border: 1px solid #b9cdf0; border-left: 4px solid #2b3b66;
  border-radius: 6px; background: #eef3fc; font-size: 12.5px; }
.hf-banner-t { font-weight: 600; color: #21325c; }
.hf-banner .btn { margin-left: auto; padding: 4px 10px; font-size: 12px; }
/* 조회가 상한에 걸린 채로 걸린 필터 — 숨긴 행이 「없는 것」인지 「안 온 것」인지 가를 수 없다. */
.hf-banner-warn { border-color: #e6b98a; border-left-color: #b06a12; background: #fdf5ea; }
.hf-banner-warn .hf-banner-t { color: #7a4708; }

/* §RUN_SCOPE 차수 전체 집계 (2026-09-06) */
/* 툴바 손잡이 — 조회 조건이라 조회 버튼 옆에 선다. 체크박스와 일수가 한 덩어리로 읽혀야
   「켜져 있고 ±14일」이 한 눈에 들어온다(둘이 떨어져 있으면 일수만 보고 켜진 줄 안다). */
.hf-runscope { gap: 4px; padding: 4px 8px; border: 1px solid #c9d5e7; border-radius: 6px;
  background: #f7faff; white-space: nowrap; cursor: pointer; }
.hf-runscope select { padding: 3px 4px; border: 1px solid #c9d5e7; border-radius: 5px;
  font: inherit; font-size: 12px; background: #fff; }
/* 차수가 갈려 뺀 프로젝트명 — 남은 것과 비슷한 이름인지 **눈으로 대보라고** 내는 값이라
   줄임표로 자르지 않는다. 자르면 「매니코 26-4…」가 되어 비교 자체가 안 된다. */
.hf-run-drop { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px;
  color: #5b6b8c; word-break: break-all; }
/* 띠가 둘 연달아 설 수 있다(차수 → 공정). 붙어 있으면 한 덩어리로 읽혀 두 사실이 섞인다. */
.hf-banner + .hf-banner { margin-top: 6px; }

/* 칸 아래 작은 델타. 색은 칸 배경(.hf-more/.hf-less)이 지고 글자는 톤만 맞춘다 —
   숫자 두 개가 모두 강한 색이면 어느 쪽을 읽어야 할지 눈이 갈 곳을 잃는다. */
/* 앞 공정보다 적다 — 공정 손실은 정상이라 옅게. 많다 — 앞에서 준 것보다 많을 수 없으니 진하게. */
.hf-cell.hf-less { background: #fdf3f3; }
.hf-cell.hf-less .hf-dv { color: #a53737; }
.hf-cell.hf-more { background: #fbeef7; }
.hf-cell.hf-more .hf-dv { color: #9c2b7a; font-weight: 700; }
.hf-grid tbody tr:hover td.hf-less { background: #fbe9e9; }
.hf-grid tbody tr:hover td.hf-more { background: #f6e2ef; }

.hf-th-verdict { text-align: center !important; width: 72px; min-width: 72px; }
.hf-verdict { text-align: center; font-size: 11px; color: #94a3b8; white-space: nowrap; }
/* 판정은 칩이다 — 글자만 두면 공정 열의 숫자와 무게가 같아 눈이 멈추지 않는다. */
.hf-vb {
  display: inline-block; padding: 1px 6px; border-radius: 999px;
  font-size: 10.5px; line-height: 1.5; letter-spacing: -0.01em;
  border: 1px solid currentColor; background: #fff;
}
.hf-v-ok   .hf-vb { background: #eef8f2; }
.hf-v-less .hf-vb { background: #fdf1f1; }
.hf-v-more .hf-vb { background: #fbeaf5; }
.hf-v-noarr .hf-vb { background: #f5f6f8; }
.hf-v-ok   { color: #1e7a4f; }
.hf-v-less { color: #a53737; }
.hf-v-more { color: #9c2b7a; font-weight: 700; }
/* 범례의 색 견본 — 표의 칸과 같은 배경을 써야 「이 색이 저 색」이라고 읽힌다. */
.hf-lg { display: inline-block; padding: 0 6px; border-radius: 4px; }
/* 공정 인수표 — EA 환산 근거 / 판정 필터 / 배열 미상 (2026-08-28) */
/* 배열을 못 찾은 칸 — 경고색을 쓰지 않는다. 틀린 게 아니라 «모르는» 것이라 회색이 맞다. */
.hf-cell.hf-noarr { background: #f7f8fa; }
.hf-v-noarr { color: #8a93a6; }
/* 판정 칩(.hf-vchip)은 요약 카드로 승격돼 없어졌다 (2026-08-31). 아래가 그 자리다. */

/* ── 기간 프리셋 ── */
.hf-presets { display: inline-flex; border: 1px solid #c9d5e7; border-radius: 6px; overflow: hidden; }
.hf-preset { padding: 6px 12px; border: 0; border-right: 1px solid #dde3ee;
  background: #fff; color: #384364; font-size: 12.5px; cursor: pointer; }
.hf-preset:last-child { border-right: 0; }
.hf-preset:hover { background: #eef2f7; }
.hf-preset.on { background: #2b3b66; color: #fff; }

/* ── 요약 카드 — 판정별 행 수 + 그 판정으로 좁히는 버튼 ── */
.hf-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 8px; padding: 12px 16px 0; }
.hf-stat { display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 10px 14px; border: 1px solid #e3e7f0; border-radius: 8px;
  background: #fff; cursor: pointer; text-align: left; }
.hf-stat:hover { background: #f5f8ff; border-color: #c9d5e7; }
.hf-stat-n { font-size: 22px; font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums; color: #1f2540; }
.hf-stat-l { font-size: 11.5px; color: #7a8699; }
/* 켜진 카드는 **테두리**로 표시한다 — 배경을 채우면 숫자 색(판정색)이 죽는다. */
.hf-stat.on { border-color: #2b3b66; box-shadow: inset 0 0 0 1px #2b3b66; background: #f5f8ff; }
/* 0 건인 판정 — 숨기지 않는다. 「없다」는 것도 정보다. 누를 수만 없게 한다. */
.hf-stat-0 { opacity: .45; cursor: default; }
.hf-stat-0:hover { background: #fff; border-color: #e3e7f0; }
.hf-s-ok    .hf-stat-n { color: #1e7a4f; }
.hf-s-less  .hf-stat-n { color: #a53737; }
.hf-s-more  .hf-stat-n { color: #9c2b7a; }
.hf-s-noarr .hf-stat-n { color: #8a93a6; }
/* 판정 열은 품번 바로 옆 — 품번 칸과 함께 왼쪽에 붙여 둔다(가로 스크롤해도 보이게).
   ⚠ left 값은 .hf-th-part 의 width 와 맞춰야 한다. 어긋나면 두 칸이 겹친다. */
.hf-grid th.hf-th-verdict, .hf-grid td.hf-verdict { position: sticky; left: 176px; z-index: 1;
  background: #fff; border-right: 0; box-shadow: inset -2px 0 0 #aeb9cb; }
.hf-grid th.hf-th-verdict { z-index: 5; background: #eef1f6;
  box-shadow: inset -2px 0 0 #aeb9cb, inset 0 -2px 0 #aeb9cb; }
.hf-grid tbody tr:hover .hf-verdict { background: #f5f8ff; }

/* ── 머리줄 고정 (2026-09-05) ────────────────────────────────────────

   ■ 왜 안 붙어 있었나
     `thead th` 는 처음부터 `position: sticky; top: 0` 였다. 안 붙은 이유는 규칙이 아니라
     **붙을 상대가 없었기 때문**이다. sticky 는 「가장 가까운 스크롤 상자」를 기준으로 서는데,
     `.hf-table` 이 `overflow-x: auto` 라 (한 축이 auto 면 다른 축도 auto 가 된다) 그 상자가
     됐고, 그 상자는 키가 내용만큼 늘어나 **자기가 통째로 페이지와 함께 굴러갔다.**
     머리줄은 「자기 상자의 맨 위」에 잘 붙어 있었고, 그 상자가 화면 밖으로 나갔을 뿐이다.

   ■ 그래서 키를 가둔다
     이 화면일 때만 상단바→표까지 세로 flex 로 잇고, 표가 남는 높이를 가져간다.
     페이지는 더 이상 구르지 않고 **표만 구른다.**
     ⚠ 다른 화면은 손대지 않는다 — `:has()` 로 이 뷰가 열려 있을 때만 걸린다.
       `:has()` 를 모르는 브라우저에서는 규칙 전체가 무시되고 종전대로 페이지가 구른다
       (머리줄만 안 붙을 뿐 아무것도 깨지지 않는다).
     ⚠ `#app` 의 인라인 `display` 는 js/auth.js 가 넣는다. 거기서 'block' 을 박으면
       이 규칙이 진다 — 그래서 통과 시 '' 를 넣도록 함께 고쳤다(auth.js 주석 참조).
     ⚠ 표 말고는 아무도 줄어들면 안 된다. flex 기본 `shrink:1` 을 그대로 두면
       **탭바가 눌려 납작해진다**(실측 35px → 8px).

   ■ 스크롤 상자 안에는 여백을 두지 않는다
     `.hf-table` 이 갖고 있던 `padding: 10px 12px 0` 을 그대로 두면, 고정된 머리줄·품번 칸이
     그 여백만큼 안쪽에 서고 **그 바깥 띠로 지나가는 행이 비친다.** 바깥 여백은
     `.hf-scroll` 의 margin 이 진다.                                                    */
#app:has(#view-handoff:not([hidden])) { display: flex; flex-direction: column; height: 100dvh; }
#app:has(#view-handoff:not([hidden])) .app-body { flex: 1 1 auto; min-height: 0; }
#app:has(#view-handoff:not([hidden])) .content-area { min-height: 0; }
#app:has(#view-handoff:not([hidden])) .content-area > *:not(main) { flex: 0 0 auto; }
#app:has(#view-handoff:not([hidden])) main {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
}
#app:has(#view-handoff:not([hidden])) #view-handoff {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
}
.hf-wrap { flex: 1 1 auto; min-height: 0; }
.hf-bar, .hf-stats, .hf-banner { flex: 0 0 auto; }
/* ⚠ .hf-banner 를 빠뜨리면 flex 기본값(0 1 auto)이라 창이 낮을 때 눌려 글자가 넘친다 —
   .hf-scroll 만 줄어야 하고 알림 줄은 제 키를 지켜야 한다(PR #160 §키를 가둔 레이아웃). */
/* 구르는 상자 — 표와 범례가 함께 들어 있다(js/handoff.js). 범례를 밖에 두면 화면 아래에
   붙박여 표 높이를 144px 먹는다. 종전처럼 「표 끝까지 내리면 범례」가 되게 둘을 묶는다. */
/* ⚠ 바닥(min-height)이 있어야 한다. 키를 가둔 뒤로는 툴바·요약 카드가 줄바꿈으로 커질 때
   표 칸이 그만큼 눌리는데, 바닥이 없으면 **0px 까지 눌려 표가 통째로 사라진다**
   (실측: 앱 높이 300px → 0px · 420px → 96px). 바닥에 닿으면 넘친 만큼 페이지가 굴러
   종전 동작으로 돌아간다 — 잃는 것 없이 표가 사라지는 것만 막는다. */
.hf-scroll { flex: 1 1 auto; min-height: 200px; overflow: auto; margin: 10px 12px 0; }
/* 범례는 가로로 따라가지 않는다 — 상자를 오른쪽 끝까지 밀면 범례가 왼쪽으로 빠져나간다
   (실측 left −146px). 표만 구르고 설명은 제자리에 있어야 한다. */
.hf-legend { position: sticky; left: 0; }

/* ⚠ 제조 AI 패널의 바닥을 되살린다. 아래 `.app-body.with-agent { min-height: 520px }` 는
   「표가 몇 줄뿐인 날에도 대화창이 쓸 만한 키는 남는다」는 기록된 결정인데, 위
   `.app-body { min-height: 0 }` 이 특정도로 이겨 무력화된다(실측: 앱 높이 520px →
   .app-body 452px, 420px → 352px — 패널이 같이 줄어든다). 이 화면은 그 패널을 다는
   두 화면 중 하나다. */
#app:has(#view-handoff:not([hidden])) .app-body.with-agent { min-height: 520px; }

/* ── 제조 AI 사이드 채팅 (검수 불량유형 · 공정 인수표) ──────────────────

   ■ 두 겹인 이유
     바깥(.erp-agent-side)은 그리드 칸 안에 절대배치로 서서 **그리드보다
     커질 수 없다**. 안쪽(.agent-side-shell)은 그 안에서 화면에 달라붙어
     **화면보다 커지지 않는다**. 둘 다 필요하다.

     한 겹이었을 때 무슨 일이 있었나(2026-08-28 실측):
       · 그냥 flex 아이템 → 대화가 쌓이면 상자가 늘고, 형제인 본문이 그 키를
         따라가 페이지가 2,759px 이 됐다. 표는 1,045px 인데.
       · align-self:flex-start + height:100dvh → 페이지는 안 늘었지만, 패널이
         상단바(68px) 아래에서 시작하는데 키는 화면 전체라 아래가 넘쳤다.
         입력줄이 화면 밖으로 11px 잘려서, 전송하려면 스크롤을 해야 했다.

   ■ 화면마다 파일은 다르지만 생김새는 하나다
     js/agent-side-chat.js(검수)와 js/agent-handoff-chat.js(인수표)는 보내는
     것이 아예 달라 따로 두었다. 그래도 보이는 모양까지 갈라 두면 한쪽만
     고쳐지는 날이 온다 — 그래서 .erp-agent-side 하나로 묶는다.

   ■ 절대배치라 흐름에서 빠진다
     그래서 대화가 아무리 길어도 본문 키를 못 건드린다. 자리는
     .content-area 의 padding-right 로 비운다 — 덮지 않고 옆에 선다. */
.erp-agent-side {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 400px;
  z-index: 5;
  background: #1e293b;
  border-left: 1px solid #334155;
  color: #e2e8f0;
}
/* 접었을 때. .erp-agent-side 이 display 를 정하므로 [hidden] 기본값이
   먹지 않는다 — 여기서 직접 끈다. 지우는 게 아니라 감추는 것이라 필요하다. */
.erp-agent-side[hidden] { display: none; }

/* ── 접었을 때 다시 펼 손잡이 ──────────────────────────────────────

   ■ 왜 필요한가
     ✕ 로 접으면 다시 여는 길이 「메뉴를 나갔다 들어오기」뿐이었다.
     접는 버튼은 있는데 펴는 버튼이 없으면, 한 번 접은 사람은 그 화면에서
     제조 AI 를 잃는다.

   ■ position: fixed 인 이유
     이 파일 위쪽에 적힌 사고를 되풀이하지 않으려는 것이다 — 흐름에 있는
     상자는 형제의 키를 밀어 페이지를 2,759px 로 만든 적이 있다.
     손잡이는 흐름에서 완전히 빠져 있어야 표를 한 픽셀도 못 건드린다.

   ■ 화면을 떠날 때는 이것도 함께 사라진다
     접기(collapse)와 화면을 떠나기(close)는 다른 일이다. 떠난 화면의
     손잡이가 남아 있으면, 상관없는 화면에서 남의 대화창이 열린다. */
.erp-agent-reopen {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 99001;
  display: flex;
  align-items: center;
  gap: 6px;
  writing-mode: vertical-rl;      /* 세로로 세운다 — 표를 가리는 폭을 줄인다 */
  padding: 14px 6px;
  border: 1px solid #334155;
  border-right: none;
  border-radius: 8px 0 0 8px;
  background: #1e293b;
  color: #e2e8f0;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  box-shadow: -4px 0 14px rgba(0, 0, 0, 0.3);
}
.erp-agent-reopen:hover { background: #334155; color: #fff; }
.erp-agent-reopen[hidden] { display: none; }

/* 패널이 서 있는 동안만 자리를 비운다. 다른 화면에는 이 클래스가 없다. */
.app-body.with-agent .content-area { padding-right: 400px; }
/* 표가 몇 줄뿐인 날에도 대화창이 쓸 만한 키는 남는다. */
.app-body.with-agent { min-height: 520px; }

.erp-agent-side .agent-side-shell {
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;                    /* 긴 표를 내려도 따라온다 */
  /* --agent-top 은 패널 위끝이 화면 위끝에서 떨어진 거리다.
     js/agent-side-chat.js 가 스크롤마다 재어 넣는다. CSS 혼자서는 못 읽는다. */
  height: calc(100vh - var(--agent-top, 0px));
  height: calc(100dvh - var(--agent-top, 0px));   /* 모바일 주소창이 접혀도 안 튄다 */
  max-height: 100%;          /* 그리드를 넘지 않는다 — 바깥 상자가 그리드 키다 */
  background: #1e293b;
}
.erp-agent-side .agent-side-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid #334155;
  font-size: 0.95rem; color: #fff;
}
.erp-agent-side .agent-side-head button {
  background: transparent; border: none; color: #94a3b8;
  font-size: 1rem; cursor: pointer; padding: 2px 6px; border-radius: 6px;
}
.erp-agent-side .agent-side-head button:hover { background: #334155; color: #fff; }
.erp-agent-side .agent-side-log {
  flex: 1 1 auto;
  /* ⚠ min-height 를 빼지 마라. flex 아이템의 기본값은 auto 라 내용보다
     작아지지 않는다 — overflow-y 를 걸어 놔도 영영 스크롤이 안 생긴다.
     2026-08-28 에 실제로 그랬다: overflow-y:auto 인데 scrollHeight 와
     clientHeight 가 늘 같아서 스크롤바가 한 번도 안 나왔다. */
  min-height: 0;
  overflow-y: auto;
  /* 로그 끝에서 페이지가 딸려 스크롤되지 않게. */
  overscroll-behavior: contain;
  padding: 14px;
}
/* 머리말·입력줄·안내는 줄지 않는다 — 줄어드는 것은 대화 영역뿐이다. */
.erp-agent-side .agent-side-head,
.erp-agent-side .agent-side-foot,
.erp-agent-side .agent-side-note { flex: none; }
.erp-agent-side .agent-side-foot {
  display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid #334155;
}
/* 입력줄은 한 줄에서 시작해 쓴 만큼 자란다.
   ⚠ 전에는 <input> 이라 길게 쓰면 가로로 밀려 끝만 보였다 — 내가 뭘 썼는지
     확인하려면 커서를 움직여야 했다.
   ⚠ resize: none — 손잡이로 늘리면 패널 높이 계산과 어긋난다. 높이는
     js/agent-input.js 가 내용에 맞춰 정한다.
   ⚠ 아래쪽 버튼과 밑선을 맞춘다(align-items: flex-end). 안 맞추면 입력줄이
     자랄 때 전송 단추가 가운데로 떠 보인다. */
.erp-agent-side .agent-side-foot { align-items: flex-end; }
.erp-agent-side .agent-side-foot textarea {
  flex: 1 1 auto; min-width: 0; padding: 8px 10px; border-radius: 7px;
  border: 1px solid #475569; background: #0f172a; color: #e2e8f0; font-size: 0.86rem;
  font-family: inherit; line-height: 1.5; resize: none; overflow-y: hidden;
}
.erp-agent-side .agent-side-foot textarea:focus { outline: none; border-color: #2563eb; }
.erp-agent-side .agent-side-foot textarea::placeholder { color: #64748b; }
.erp-agent-side .agent-side-foot button {
  flex: 0 0 auto; padding: 8px 14px; border-radius: 7px;
  border: 1px solid #2563eb; background: #2563eb; color: #fff;
  font-size: 0.84rem; cursor: pointer;
}
.erp-agent-side .agent-side-note {
  margin: 0; padding: 0 12px 10px; font-size: 0.72rem; color: #64748b;
}
/* 좁은 화면에서는 그리드를 밀어내지 않고 겹쳐 띄운다 — 표가 먼저다. */
@media (max-width: 1100px) {
  .app-body.with-agent .content-area { padding-right: 0; }
  .erp-agent-side {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 99000;
    box-shadow: -8px 0 28px rgba(0, 0, 0, 0.45);
  }
  /* 겹쳐 띄울 때는 바깥이 이미 화면에 고정이라 안쪽은 그냥 채우면 된다. */
  .erp-agent-side .agent-side-shell {
    position: static; height: 100%; max-height: none;
  }
}
/* 앞 공정이 넘긴 양품 수량 — 차이 바로 앞에 둔다. 차이보다 옅게 해서
   「무엇을 견줬나(옅게) → 얼마나 어긋났나(진하게)」 순으로 읽히게 한다. */

/* ── 더받음 표시 (2026-09-01) ─────────────────────────────────────────
   ⚠ 행이 아니라 **양품 칸 하나만** 칠한다. 행 전체를 칠하면 그 행의 모든 값이
     잘못됐다는 뜻이 되는데, 여기서 잘못된 것은 수량뿐이다.
   ⚠ background 는 !important — 같은 특정도의 .tabulator-row-even 이 뒤에 와서
     밀린다(.rl-row-pin 과 같은 사정).
   ⚠ 색만으로 갈리면 색약 사용자가 못 읽으므로 왼쪽 굵은 띠를 함께 둔다. */
.tabulator .tabulator-cell.ow-over {
  background: #fde8e8 !important;
  color: #a01b1b;
  font-weight: 700;
  border-left: 3px solid #d64545;
  cursor: help;
}
.tabulator .tabulator-row.tabulator-row-even .tabulator-cell.ow-over {
  background: #fbdede !important;
}

/* 더받음 검사 바 — 조회기간 바로 아래. 조회 조건에 딸린 표시라 툴바가 아니라 여기 둔다. */
.ow-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 6px 14px;
  border-bottom: 1px solid #e6e9f0;
  background: #fafbfd;
}
.ow-bar[hidden] { display: none; }
.ow-only { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #384364; cursor: pointer; }
/* 검사 전·문제행 0건이면 켤 수 없다 — 눌러도 안 되는 이유가 보이게 흐리게 둔다 */
.ow-only.off { color: #b6bdca; cursor: not-allowed; }
.ow-legend { font-size: 12px; color: #8a94a6; }
.ow-bar .pill { margin-left: auto; }

/* ── 검수 불량 현황 (2026-09-03) — 품질 그룹, 불량유형 피벗 ────────────────
   docs/검수불량현황_설계.md · 읽기 전용. cl-* (마감/자재) 규약을 그대로 쓰고
   이 화면에만 필요한 것만 여기 둔다. */
.ds-wrap { display: flex; flex-direction: column; }
.ds-bar .cl-frow { margin-bottom: 6px; }
.ds-grid { padding: 0 16px 12px; }
.ds-grid .tabulator { border: 1px solid #e3e7f0; border-radius: 8px; }

/* 집계 단위 — 두 상태 중 하나가 반드시 켜져 있다(토글이 아니라 선택). */
.ds-seg { display: inline-flex; gap: 0; }
.ds-seg .ds-mode { border-radius: 0; margin-left: -1px; }
.ds-seg .ds-mode:first-child { border-radius: 6px 0 0 6px; margin-left: 0; }
.ds-seg .ds-mode:last-child  { border-radius: 0 6px 6px 0; }
.ds-seg .ds-mode[aria-pressed="true"] {
  background: #2b3b66; color: #fff; border-color: #2b3b66; position: relative; z-index: 1;
}
.ds-chk { cursor: pointer; }

/* 안내줄 — 단위·목록 외·잘림을 여기서만 말한다. 표 안에 섞으면 숫자가 안 읽힌다. */
.ds-note { display: flex; flex-direction: column; gap: 3px; }
.ds-note-line { font-size: 12px; color: #5b6784; line-height: 1.45; }
.ds-note-line b { color: #2b3b66; }
.ds-warn { color: #a53737; font-weight: 600; }
/* 검수 불량 현황 — 특수공정 진행 열 (ADR-0003) */
.ds-sp-yes { font-weight:700; color:#1f6f43; }
.ds-sp-unk { font-weight:700; color:#8a6100; }
/* 검수 불량 현황 — B·P 통합 입력을 반으로 나눈 줄 (ADR-0004) */
.ds-half { display:inline-block; padding:0 4px; margin-left:2px; border-radius:3px;
  font-size:11px; line-height:15px; background:#fff3cd; color:#8a6100; border:1px solid #f0d58a; }
.ds-mismatch-dot { color: #b4232a; font-weight: 700; }

/* 열 제목의 단위 — 2공장은 불량수량(EA)과 유형합(g)이 다른 물리량이라
   제목에 박아 두지 않으면 「합이 왜 안 맞나」로 읽힌다 (ADR-0002). */
.tabulator .ds-unit {
  display: block; font-size: 9.5px; font-weight: 600; color: #8a94a6;
  letter-spacing: .04em; line-height: 1.1;
}

/* 0인 칸 — 열은 남기되 눈에서는 물러난다(마스터 고정 열이라 0이 많다). */
.ds-zero-cell { color: #c3c9d6; }
.tabulator .tabulator-cell.ds-d { color: #384364; }
/* 유형 열 제목은 띄어쓰기에서만 접는다 — 한글은 기본이 글자 단위라 「퀄리 / 티」로 끊긴다. */
.tabulator .tabulator-col.ds-d .tabulator-col-title { word-break: keep-all; }
/* 마스터에 없는 유형 — 정상값처럼 보이지 않게, 그러나 숨기지도 않게. */
.tabulator .tabulator-cell.ds-extra { background: #fff6e6; }
/* 히트 음영 — 표 전체 유형 칸의 최댓값 대비 4단계(defect-summary heatClass).
   ⚠ .ds-extra(목록 외 열의 살구색)보다 뒤에 와야 같은 특정도에서 음영이 이긴다.
   ⚠ 선택/짝수 행 배경을 덮어야 하므로 !important — Tabulator 의 row 규칙이 셀보다 뒤에 온다. */
.tabulator .tabulator-cell.ds-h1 { background: #fdf0f0 !important; }
.tabulator .tabulator-cell.ds-h2 { background: #fadede !important; }
.tabulator .tabulator-cell.ds-h3 { background: #f4c4c4 !important; }
.tabulator .tabulator-cell.ds-h4 { background: #eda2a2 !important; font-weight: 600; }
.tabulator .tabulator-col.ds-extra .tabulator-col-content { color: #a15c00; }
.tabulator .tabulator-cell.ds-bad { font-weight: 600; }
/* 불량수량 ≠ 유형합. 뜻은 한 가지가 아니라 툴팁에서 말한다 — 색은 「다르다」까지만. */
.tabulator .tabulator-cell.ds-mismatch { color: #b4232a; font-weight: 700; }
.tabulator .tabulator-cell.ds-mismatch::after {
  content: "●"; font-size: 7px; vertical-align: 3px; margin-left: 3px;
}

/* WIP inventory: internal tabs and source-lot ledger. */
.wip-view { --wip-border:#e3e7f0; --wip-muted:#6b7891; padding:20px 16px; width:100%; min-width:0; line-height:1.5; }
.wip-heading h2 { font-size:20px; letter-spacing:-.03em; margin:0 0 6px; }
.wip-heading p { margin:0; color:var(--wip-muted); font-size:12px; }
.wip-tabs { display:flex; gap:4px; margin:20px 0 0; border-bottom:1px solid #c9d5e7; }
.wip-tabs .btn { padding:11px 18px; border:0; border-bottom:3px solid transparent; border-radius:6px 6px 0 0; background:transparent; color:var(--wip-muted); }
.wip-tabs .btn:hover:not(:disabled) { background:#e5ebf5; }
.wip-tabs .btn[aria-pressed="true"] { color:#2b3b66; background:#fff; border-bottom-color:#2b3b66; }
#wipBadge { display:inline-block; margin-left:4px; padding:0 6px; border-radius:9px; background:#eef1f6; color:#2b3b66; font-size:11px; }
.wip-controls { display:flex; flex-wrap:wrap; gap:12px; align-items:end; }
#wipFilters { padding:16px; margin:0; background:#fff; border:1px solid var(--wip-border); border-top:0; border-radius:0 0 6px 6px; }
.wip-controls label { display:flex; flex-direction:column; gap:6px; min-width:0; color:#384364; font-size:12px; font-weight:500; }
#wipFilters label { flex:1 1 130px; }
#wipFilters label:first-child { flex:0 0 80px; }
.wip-controls input,.wip-controls select { width:100%; min-height:34px; padding:6px 9px; border:1px solid #c9d5e7; border-radius:6px; background:#fff; color:#1f2540; font:inherit; font-weight:400; }
.wip-controls input:focus-visible,.wip-controls select:focus-visible { outline:2px solid #3a7bd5; outline-offset:1px; }
.wip-controls input[type=checkbox] { width:16px; min-height:16px; height:16px; margin:0; accent-color:#2b3b66; }
.wip-controls label:has(input[type=checkbox]) { flex-direction:row; align-items:center; align-self:center; }
#wipMessage { margin:12px 2px; font-size:12px; color:var(--wip-muted); }
.wip-panel { margin-top:16px; border:1px solid var(--wip-border); border-radius:6px; background:#fff; min-width:0; overflow:hidden; }
.wip-panel:empty { display:none; }
.wip-panel h3 { font-size:13px; color:#2b3b66; margin:0; font-weight:650; }
.wip-section-heading { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 16px; }
.wip-section-heading span { color:var(--wip-muted); font-size:11px; }
#wipSummary>h3,#wipRuns>h3 { padding:12px 16px 0; }
#wipSummary>p,#wipRuns>p { margin:4px 16px 12px; color:var(--wip-muted); font-size:11px; }
.wip-table { overflow:auto; }
.wip-table table { border-collapse:collapse; width:100%; font-size:12.5px; }
.wip-table th,.wip-table td { border-bottom:1px solid var(--wip-border); padding:10px 16px; text-align:left; white-space:nowrap; }
.wip-table th { background:#eef1f6; color:#384364; font-size:11px; font-weight:600; }
.wip-table tbody tr:last-child td { border-bottom:0; }
.wip-table tbody tr:hover { background:#f5f8ff; }
.wip-table td:nth-child(3),.wip-table th:nth-child(3),#wipSummary td:last-child,#wipSummary th:last-child { text-align:right; font-variant-numeric:tabular-nums; }
.wip-table td:nth-child(3) { font-weight:650; }
.wip-table .btn { padding:5px 10px; font-size:12px; }
.wip-state { display:inline-block; padding:2px 7px; border-radius:4px; font-size:11px; font-weight:500; background:#eef1f6; color:#52617b; }
.wip-state-completed { background:#eaf5ef; color:#216344; }
.wip-state-needs_print { background:#edf2fb; color:#2b4d80; }
.wip-state-unknown { background:#fff4e3; color:#8b5d19; }
.wip-mapping { margin-left:8px; color:var(--wip-muted); font-size:11px; }
.wip-pagination { justify-content:flex-end; align-items:center; gap:12px; padding:10px 16px; border-top:1px solid var(--wip-border); color:var(--wip-muted); font-size:12px; }
#wipDetail { padding:0 16px 16px; }
#wipDetail>.wip-section-heading { margin:0 -16px 16px; border-bottom:1px solid var(--wip-border); }
.wip-fields { display:grid; grid-template-columns:140px minmax(0,1fr) 140px minmax(0,1fr); gap:0 16px; margin:0 0 16px; }
.wip-fields dt,.wip-fields dd { margin:0; padding:8px 0; border-bottom:1px solid #f0f2f6; overflow-wrap:anywhere; }
.wip-fields dt { color:var(--wip-muted); font-size:12px; }
#wipDetail>h3 { margin-top:20px; padding-top:16px; border-top:1px solid var(--wip-border); }
#wipCommand { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); margin-top:12px; padding:16px; background:#f7f9fc; border-radius:6px; }
#wipCommand label:has([name=reason]) { grid-column:span 2; }
#wipCommand>button { justify-self:start; }
#wipReview { grid-column:1/-1; margin:0; color:#2b3b66; font-size:12px; }
#wipReview:empty { display:none; }
#wipDetail>form.wip-controls:not(#wipCommand) { margin-top:16px; padding-top:16px; border-top:1px solid var(--wip-border); }
#wipDetail>form.wip-controls>h3,#wipDetail>form.wip-controls>p { flex-basis:100%; margin:0; }
.wip-panel details { padding:12px 16px; border-top:1px solid var(--wip-border); }
.wip-panel summary { cursor:pointer; color:#2b3b66; font-weight:500; }
.wip-panel details[open]>summary { margin-bottom:12px; }
@media(max-width:1000px) {
  #wipCommand { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .wip-fields { grid-template-columns:130px minmax(0,1fr); }
}
@media(max-width:600px) {
  .wip-view { padding:12px 8px; }
  .wip-heading h2 { font-size:18px; }
  .wip-tabs .btn { padding:10px 12px; }
  #wipFilters label,#wipFilters label:first-child { flex:1 1 120px; }
  .wip-section-heading span { display:none; }
  #wipCommand { grid-template-columns:minmax(0,1fr); }
  #wipCommand label:has([name=reason]) { grid-column:auto; }
  .wip-fields { grid-template-columns:100px minmax(0,1fr); gap:0 12px; }
}

/* WIP inventory table and responsive detail drawer */
/* Reuse the application's typography, period bar, buttons, and Tabulator rules. */
body:has(.mesp-root) #selectionPanel { display:none; }
body:has(.mesp-root) #rowCount { display:none; }
#mespGrid { background:#fff;border-radius:8px;box-shadow:0 1px 3px rgba(20,30,60,0.08);overflow:hidden; }
body:has(.mesp-root) .content-area>main { padding:0; }
.mesp-viewbar { display:flex;align-items:center;gap:18px;padding:8px 20px;border-bottom:1px solid #d8dee8;background:#fff;font-size:13px;color:#2b3b66; }
.mesp-viewbar>div { display:flex;gap:6px; }
.mesp-viewbar .btn[aria-pressed="true"] { background:#2b3b66;color:white; }
.mesp-viewbar>.muted { margin-left:auto; }
.mesp-grid-area { padding:12px 20px; }
.mesp-footnote { display:flex;justify-content:space-between;gap:15px;padding:8px 0;color:#526079;font-size:12px; }
.mesp-open { font:inherit;padding:2px 7px;background:#fff;border:1px solid #c9d5e7;border-radius:3px;color:#2b3b66;cursor:pointer; }
#mespDetail { border:1px solid #d8dee8;background:white;margin-top:8px;padding:12px; }
.mesp-detail-title { display:flex;align-items:center;justify-content:space-between; }
#mespDetail dl { display:grid;grid-template-columns:110px 1fr 110px 1fr;gap:8px;font-size:13px; }
#mespDetail dd { margin:0;overflow-wrap:anywhere; }
@media(max-width:800px){.mesp-viewbar{flex-wrap:wrap}.mesp-viewbar>.muted{margin-left:0}.mesp-footnote{flex-wrap:wrap}#mespDetail dl{grid-template-columns:110px 1fr}}
.mesp-drawer { position:fixed;inset:0 0 0 auto;margin:0;width:min(520px,100vw);height:100dvh;max-width:100vw;max-height:100dvh;padding:0;border:0;border-left:1px solid #c9d5e7;background:#fff;color:#263752;box-shadow:-8px 0 28px rgba(20,30,60,.18); }
.mesp-drawer[open] { display:flex;flex-direction:column;animation:mesp-drawer-in .18s ease-out; }
.mesp-drawer::backdrop { background:rgba(20,30,50,.24); }
.mesp-drawer-header { display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 20px;background:#eef2f7;border-bottom:1px solid #d8dee8;font-size:16px; }
.mesp-drawer-body { flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;padding:20px; }
.mesp-drawer-summary { padding-bottom:20px;border-bottom:1px solid #d8dee8; }
.mesp-drawer h2 { margin:0 0 10px;font-size:23px;overflow-wrap:anywhere; }
.mesp-drawer-state { display:inline-block;padding:4px 8px;border:1px solid #c9d5e7;border-radius:4px;background:#f0f2f7;font-size:13px; }
.mesp-drawer-summary p { margin:20px 0 5px;font-size:13px;color:#526079; }
.mesp-drawer-quantity { font-size:30px;font-weight:700;font-variant-numeric:tabular-nums; }
.mesp-drawer-quantity small { font-size:14px;font-weight:400; }
.mesp-drawer h3 { font-size:15px;margin:22px 0 12px; }
.mesp-drawer h3 small { font-size:13px;font-weight:400; }
.mesp-drawer dl { display:grid;grid-template-columns:100px minmax(0,1fr);margin:0;font-size:14px;line-height:1.6; }
.mesp-drawer dt,.mesp-drawer dd { margin:0;padding:10px 0;border-bottom:1px solid #e3e7f0;overflow-wrap:anywhere; }
.mesp-drawer dt { color:#526079; }
.mesp-drawer-history { overflow:auto; }
.mesp-drawer table { width:100%;border-collapse:collapse;font-size:12.5px; }
.mesp-drawer th { background:#f0f2f7;text-align:left; }
.mesp-drawer th,.mesp-drawer td { padding:9px 8px;border:1px solid #e3e7f0; }
.mesp-drawer th:last-child,.mesp-drawer td:last-child { text-align:right;white-space:nowrap; }
.mesp-drawer-footer { padding:12px 20px;border-top:1px solid #d8dee8;font-size:12px;color:#526079; }
#mespGrid .tabulator-row.mesp-detail-selected { background:#e0eaff!important;box-shadow:inset 3px 0 #2b5e9b; }
@keyframes mesp-drawer-in { from { transform:translateX(100%); } to { transform:translateX(0); } }
@media(max-width:700px){.mesp-drawer { inset:auto 0 0;width:100vw;height:85dvh;border-left:0;border-top:1px solid #c9d5e7;border-radius:12px 12px 0 0; }.mesp-drawer[open]{animation-name:mesp-sheet-in}.mesp-drawer-body{padding:16px}.mesp-drawer-footer{padding-bottom:max(12px,env(safe-area-inset-bottom))}}
@keyframes mesp-sheet-in { from { transform:translateY(100%); } to { transform:translateY(0); } }
@media(prefers-reduced-motion:reduce){.mesp-drawer[open]{animation:none}}
.mesp-admin-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.mesp-drawer-footer .mesp-admin-actions{margin-bottom:10px}.mesp-admin-form{display:grid;gap:16px}.mesp-admin-form label{display:grid;gap:7px;font-size:14px;font-weight:600}.mesp-admin-form input,.mesp-admin-form select,.mesp-admin-form textarea{font:inherit;width:100%;box-sizing:border-box;padding:9px;border:1px solid #c9d5e7;border-radius:5px;color:#263752;background:white}.mesp-notice{background:#eef2f7;border:1px solid #d8dee8;padding:12px;font-size:13px;line-height:1.6}.mesp-viewbar{flex-wrap:wrap}#adminReview:not(:empty){border-top:1px solid #c9d5e7;padding-top:12px}
.mesp-inline{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px}.mesp-inline .btn{white-space:nowrap}.mesp-admin-form textarea{resize:vertical}.mesp-drawer .danger{background:#b42318;color:#fff;border-color:#b42318}
