/* ============================================================
   LITC MES — 웹 전환 목업 공통 디자인 시스템
   ASP.NET Core 8 (Blazor) 전환 시 UI/UX 기준안
   ============================================================ */
:root {
  --sidebar-w: 240px;
  --topbar-h: 56px;

  --c-bg: #f4f6f9;
  --c-surface: #ffffff;
  --c-border: #e3e8ef;
  --c-border-strong: #cdd5df;

  /* 텍스트 3단계 — 램프를 한 단계 내렸다(2026-08-09). 종전 3단계 #94a3b8 은 흰 배경에서 2.6:1,
     그리드 헤더(#f8fafc) 위에서 2.45:1 로 AA(4.5:1)에 크게 못 미쳤는데 하필 빈 상태 메시지·KPI 부제 등
     "정보가 가장 적을 때 유일하게 남는 텍스트"가 이 단계였다.
     흰 배경에서 4.5:1 을 넘으면서 2단계와 구별되는 3번째 회색은 존재하지 않으므로 램프 전체를 옮겼다.
     실측 대비(흰 배경): 1단계 14.6 · 2단계 7.3 · 3단계 4.76 */
  --c-text: #1e293b;
  --c-text-2: #4b5768;
  /* 3단계는 옅은 층 위에서도 통과해야 한다 — #64748b 는 흰 배경 4.76 이지만
     그리드 헤더(#f8fafc) 4.55 · muted(#f1f5f9) 4.34 로 떨어져 행번호·단위 접미사가 미달했다.
     실측: 흰 5.18 · #f8fafc 4.95 · #f1f5f9 4.72 */
  --c-text-3: #5f6e85;
  /* 4단계는 '글자'가 아닌 장식 글리프 전용 — 구분자(›)·caret(▾)·정렬 힌트(▲▼).
     WCAG 상 비활성 장식은 대비 요건 밖이며, 여기에 문장을 넣으면 위 문제가 되풀이된다. */
  --c-text-4: #94a3b8;

  --c-primary: #2563eb;
  --c-primary-hover: #1d4ed8;
  --c-primary-soft: #eff6ff;

  --c-danger: #dc2626;
  --c-danger-soft: #fef2f2;
  --c-success: #16a34a;
  --c-success-soft: #f0fdf4;
  --c-warn: #d97706;
  --c-warn-soft: #fffbeb;

  /* 옅은 배경 위 '글자' 전용 잉크 — 원색을 -soft 배경에 그대로 올리면 12px 칩 글자가 3.1~3.2:1 로
     본문 대비(4.5:1)에 못 미친다. 면(배경·범례 견본·테두리)은 원색을 그대로 쓰고 글자만 한 단계 내린다.
     값은 .note 계열이 이미 쓰고 있던 것을 채택했다 — 같은 의미의 색이 칩과 안내상자에서 갈려 있었다.
     실측(각자의 -soft 배경 기준): info 8.01 · warn 6.84 · ok 6.81 · bad 7.60 · neutral 5.26 */
  --c-primary-ink: #1e40af;
  --c-success-ink: #166534;
  --c-warn-ink: #92400e;
  --c-danger-ink: #991b1b;
  --c-neutral-ink: #5a6778;

  /* -soft 배경과 짝을 이루는 테두리 톤. 면(-soft)·글자(-ink)·선(-line) 3단이 한 세트다 */
  --c-primary-line: #bfdbfe;
  --c-primary-line-strong: #93c5fd;   /* 칩처럼 작은 요소는 카드보다 진한 선이 필요하다 */
  --c-success-line: #bbf7d0;
  --c-warn-line: #fde68a;
  --c-danger-line: #fecaca;
  --c-purple-soft: #f5f3ff;
  --c-purple-ink: #7c3aed;
  --c-purple-line: #ddd6fe;
  --c-border-hover: #b6c0cd;          /* 버튼·입력 hover 테두리 */
  /* 어두운 면 위 시맨틱 색 — 토스트는 다크 패널이라 본문용 원색은 대비가 나오지 않는다.
     같은 의미를 밝은 쪽으로 옮긴 값이며, 밝은 배경에는 쓰지 않는다. */
  --c-success-on-dark: #4ade80;
  --c-danger-on-dark: #f87171;

  --c-sidebar-bg: #1e2532;
  --c-sidebar-text: #9aa4b5;
  --c-sidebar-active: #2563eb;
  /* 사이드바 전용 다크 램프 — 유일한 다크 영역이라 본문 토큰과 별개 체계다.
     배경(#1e2532) 기준으로 패널이 더 어둡고(panel), 호버·입력이 더 밝다(hover). */
  --c-sidebar-panel: #161c27;         /* 즐겨찾기·최근방문 패널 배경 */
  --c-sidebar-hover: #262e3d;         /* 메뉴 hover·활성, 검색 입력 배경 */
  --c-sidebar-line: #2b3342;          /* 구분선·뱃지 배경 */
  --c-sidebar-line-2: #3b4354;        /* 입력 테두리·스크롤바 */
  --c-sidebar-muted: #8894a8;   /* 다크 배경 대비 3.35:1 → 5.01:1 (11px 그룹 제목·placeholder) */         /* placeholder·그룹 제목 */
  --c-sidebar-text-2: #c7d0dd;        /* 즐겨찾기·최근방문 패널 링크 — 일반 메뉴보다 한 단계 밝다 */
  --c-sidebar-ink: #e5e9f0;           /* 검색 입력 글자 */
  --c-sidebar-fav: #fbbf24;           /* 즐겨찾기 표식(별) */
  --c-sidebar-recent: #7dd3fc;        /* 최근 방문 표식(시계·순번) */

  /* 옅은 층 배경 — 그리드 헤더/모달 바닥(#f8fafc), readonly 입력·중지 칩·휴무일(#f1f5f9) */
  --c-grid-header-bg: #f8fafc;
  --c-grid-band-bg: #eef2f7;      /* 2단(밴드) 머리글·탭 배경 — 리터럴 3곳을 토큰으로 통합 */
  /* 밝은 면의 hover 층 — 밴드 머리글과 같은 층이라 값을 공유한다.
     종전에는 #eef2f6 이 따로 쓰여 밴드(#eef2f7)와 1/255 만 다른 무의미한 갈림이 있었다. */
  --c-surface-hover: var(--c-grid-band-bg);
  --c-track: #e9eef4;             /* 진척 바 트랙 — 채워지는 색과 대비를 만들어야 해 한 단계 더 어둡다 */
  /* 덮는 층의 배경 — 모달 오버레이와 좁은 화면 사이드바 오버레이가 같은 값을 공유한다.
     둘 다 "아래 화면을 잠시 가린다"는 같은 의미이므로 값이 갈리면 안 된다. */
  --c-scrim: rgba(15, 23, 42, .45);
  --c-grid-foot-bg: #e8eef8;
  --c-muted-bg: #f1f5f9;
  --c-selected-row: #dbeafe;

  /* 생산계획 간트 일정 셀 3색 (범례와 셀이 반드시 같은 변수를 쓴다) */
  --c-sched-mat: #eaf3ff;
  --c-sched-inh: #ecf9ec;
  --c-sched-out: #fff3e2;

  --radius: 8px;
  --shadow: 0 1px 3px rgba(16, 24, 40, .08);
  --shadow-lift: 0 6px 20px rgba(16, 24, 40, .10);
  /* 가로 스크롤 엣지 — "이 방향에 잘린 내용이 더 있다"는 신호. 그라데이션 금지 규약에 따라 그림자로 낸다 */
  --shadow-edge-l: 8px 0 12px -6px rgba(16, 24, 40, .28);
  --shadow-edge-r: -8px 0 12px -6px rgba(16, 24, 40, .28);
  /* 떠 있는 층 3종 — 값은 기존 구현 그대로이고 이름만 붙였다(리터럴 제거 목적) */
  --shadow-pop: 0 8px 24px rgba(0, 0, 0, .12);      /* 드롭다운·메뉴 */
  --shadow-toast: 0 12px 32px rgba(0, 0, 0, .28);   /* 토스트 */
  --shadow-card-xl: 0 24px 60px rgba(0, 0, 0, .35); /* 로그인 카드·모달 최상위 */
  --font: "Pretendard", "Malgun Gothic", "맑은 고딕", system-ui, sans-serif;

  /* 모션 토큰 — 등장은 감속(--ease-out), 소멸은 그 역커브(--ease-in)로 대칭 */
  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-modal: 260ms;
  --ease-out: cubic-bezier(.2, .8, .3, 1);
  --ease-in: cubic-bezier(.7, .2, .8, 0);
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
/* tabular-nums: 그리드 수치·KPI 자릿수 변동 시 레이아웃이 흔들리지 않게 */
body { font-family: var(--font); font-size: 14px; color: var(--c-text); background: var(--c-bg); font-variant-numeric: tabular-nums; }

/* ── 레이아웃 골격 ─────────────────────────────── */
.app { display: flex; min-height: 100vh; }
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; margin-left: var(--sidebar-w); }
.content { padding: 20px 24px 40px; display: flex; flex-direction: column; gap: 16px; }

/* ── 사이드바 ──────────────────────────────────── */
.sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--sidebar-w);
  background: var(--c-sidebar-bg); color: var(--c-sidebar-text);
  display: flex; flex-direction: column; z-index: 50; overflow-y: auto;
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--c-sidebar-line-2); border-radius: 3px; }
.brand {
  display: flex; align-items: center; gap: 10px; padding: 16px;
  color: #fff; font-size: 17px; font-weight: 700; letter-spacing: .3px;
  border-bottom: 1px solid var(--c-sidebar-line); position: sticky; top: 0; background: var(--c-sidebar-bg);
}
/* 로고 원본(docs/logo_litc.png)은 배경 투명 + 청록 계열 글자 —
   어두운 배경에서는 흰색 라운드 박스 위에 얹어야 식별된다 */
.brand .logo {
  border-radius: 8px; flex: none; background: #fff;
  padding: 5px 8px; display: flex; align-items: center;
}
.brand .logo img { height: 30px; width: auto; display: block; }   /* width:auto — 속성 190×77 비율 유지(Lighthouse image-aspect-ratio) */
.brand small { display: block; font-size: 11px; font-weight: 400; color: var(--c-sidebar-text); }
/* 메뉴 검색 — 36개 메뉴 스크롤 탐색 대체 (Sidebar/Default.cshtml + turbo-boot.js 짝) */
.nav-search { padding: 10px 12px 2px; }
.nav-search input {
  width: 100%; height: 32px; padding: 0 10px; border-radius: 6px;
  border: 1px solid var(--c-sidebar-line-2); background: var(--c-sidebar-hover); color: var(--c-sidebar-ink);
  font-size: 12.5px; font-family: inherit;
}
.nav-search input::placeholder { color: var(--c-sidebar-muted); }
.nav-search input:focus { outline: none; border-color: var(--c-sidebar-active); }
/* 최근 방문 — 사이드바보다 어두운 인셋 카드로 일반 메뉴와 분리(시인성).
   항목(순번 배지 + 링크)은 turbo-boot.js renderRecent()가 생성, 1번(가장 최근)은 .first 로 강조 */
.recent-panel {
  margin: 10px 10px 2px; padding: 8px 6px 10px;
  background: var(--c-sidebar-panel); border: 1px solid var(--c-sidebar-line); border-radius: 8px;
}
.recent-panel .rp-title {
  display: flex; align-items: center; gap: 6px;
  padding: 2px 10px 8px; font-size: 11px; font-weight: 700;
  letter-spacing: .8px; text-transform: uppercase; color: var(--c-sidebar-recent);
}
.recent-panel a {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; margin: 1px 2px; border-radius: 6px;
  color: var(--c-sidebar-text-2); font-size: 13px; text-decoration: none;
}
.recent-panel a:hover { background: var(--c-sidebar-hover); color: #fff; }
.recent-panel a .num {
  flex: none; width: 16px; height: 16px; border-radius: 4px;
  background: var(--c-sidebar-line); color: var(--c-sidebar-recent); font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.recent-panel a.first { color: #fff; background: var(--c-sidebar-hover); }
.recent-panel a.first .num { background: var(--c-sidebar-active); color: #fff; }

/* 즐겨찾기 — 최근 방문과 동일 골격의 인셋 카드, 금색 포인트로 구분.
   항목은 서버(Sidebar/Default.cshtml)가 렌더하고, 등록/해제는 메뉴 행의 .fav-star(호버 시 노출)가
   /favorite/toggle 을 호출한 뒤 turbo-boot.js 가 패널을 증분 갱신한다 */
.fav-panel {
  margin: 10px 10px 2px; padding: 8px 6px 10px;
  background: var(--c-sidebar-panel); border: 1px solid var(--c-sidebar-line); border-radius: 8px;
}
.fav-panel + .recent-panel { margin-top: 8px; }
.fav-panel .fp-title {
  display: flex; align-items: center; gap: 6px;
  padding: 2px 10px 8px; font-size: 11px; font-weight: 700;
  letter-spacing: .8px; text-transform: uppercase; color: var(--c-sidebar-fav);
}
.fav-panel a {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; margin: 1px 2px; border-radius: 6px;
  color: var(--c-sidebar-text-2); font-size: 13px; text-decoration: none;
}
.fav-panel a:hover { background: var(--c-sidebar-hover); color: #fff; }
.fav-panel a svg { flex: none; color: var(--c-sidebar-fav); }
.fav-panel a svg path { fill: currentColor; }
/* 메뉴 행 별 버튼 — visibility 토글(레이아웃 흔들림 방지). 등록된 행은 항상 채워진 별 */
.nav a .fav-star {
  margin-left: auto; flex: none; visibility: hidden;
  padding: 2px; line-height: 0; color: var(--c-sidebar-muted); cursor: pointer;
}
.nav a:hover .fav-star { visibility: visible; }
.nav a .fav-star:hover { color: var(--c-sidebar-fav); }
.nav a.fav-on .fav-star { visibility: visible; color: var(--c-sidebar-fav); }
.nav a.fav-on .fav-star svg path { fill: currentColor; }

.nav { padding: 8px 0 24px; }
.nav-group-title {
  padding: 16px 16px 6px; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .8px; color: var(--c-sidebar-muted);
}
.nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 16px 8px 20px; color: var(--c-sidebar-text);
  text-decoration: none; font-size: 13.5px; border-left: 3px solid transparent;
}
.nav a:hover { color: #fff; background: var(--c-sidebar-hover); }
.nav a.active {
  color: #fff; background: var(--c-sidebar-hover); border-left-color: var(--c-sidebar-active); font-weight: 600;
}
.nav a .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; opacity: .5; flex: none; }

/* ── 상단바 ────────────────────────────────────── */
/* 반투명 재질 — 콘텐츠가 아래로 비쳐 흐른다. 경계선·그림자는 스크롤이 생겼을 때만
   나타난다(스크롤 엣지 효과, grid.js 아닌 _Layout 스크립트가 .scrolled 토글). */
.topbar {
  height: var(--topbar-h);
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid transparent;
  display: flex; align-items: center; gap: 16px; padding: 0 24px;
  position: sticky; top: 0; z-index: 40;
  transition: border-color var(--dur-base), box-shadow var(--dur-base);
}
.topbar.scrolled {
  border-bottom-color: rgba(203, 213, 225, .55);
  box-shadow: 0 4px 16px rgba(16, 24, 40, .06);
}
.breadcrumb { display: flex; align-items: center; gap: 8px; color: var(--c-text-2); font-size: 13px; }
.breadcrumb .sep { color: var(--c-text-4); }
.breadcrumb .current { color: var(--c-text); font-weight: 600; font-size: 15px; }
.topbar .spacer { flex: 1; }
.user-chip { position: relative; display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--c-text-2); }
.user-chip .avatar {
  width: 30px; height: 30px; border-radius: 50%; background: var(--c-primary-soft);
  color: var(--c-primary); display: grid; place-items: center; font-weight: 700; font-size: 12px;
}
/* 사용자 메뉴 (비밀번호 변경·로그아웃 드롭다운 — _Layout 과 짝) */
.user-chip-btn { display: flex; align-items: center; gap: 10px; padding: 4px 8px; border: none; background: none;
  font: inherit; color: inherit; cursor: pointer; border-radius: 8px; }
.user-chip-btn:hover { background: var(--c-surface-hover); }
.user-chip-btn .caret { font-size: 10px; color: var(--c-text-4); }
/* 트리거(사용자 칩) 우상단에 앵커된 등장 — 발생원과의 공간 관계 유지 */
.user-menu { position: absolute; right: 0; top: calc(100% + 6px); min-width: 170px;
  background: var(--c-surface); border: 1px solid var(--c-border-strong); border-radius: 8px;
  box-shadow: var(--shadow-pop); z-index: 200; padding: 4px;
  transform-origin: top right; animation: menu-in var(--dur-fast) var(--ease-out); }
@keyframes menu-in {
  from { opacity: 0; transform: scale(.95) translateY(-4px); }
}
.user-menu-item { display: block; width: 100%; padding: 8px 12px; border: none; background: none;
  font-size: 13px; color: var(--c-text); text-align: left; cursor: pointer; border-radius: 6px; }
.user-menu-item:hover { background: var(--c-surface-hover); }

/* ── 페이지 헤더(타이틀 + 액션) ─────────────────── */
.page-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.page-head h1 { font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }
.page-head .desc { color: var(--c-text-2); font-size: 13px; }
.page-head .actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* ── 버튼 ──────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 14px; border-radius: var(--radius);
  border: 1px solid var(--c-border-strong); background: var(--c-surface);
  color: var(--c-text); font-size: 13px; font-weight: 600; font-family: inherit;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast);
}
.btn:hover { background: var(--c-grid-header-bg); border-color: var(--c-border-hover); }
/* press 즉답 — 반응은 pointer-down 에서, 확정은 pointer-up 에서 */
.btn:active { transform: scale(.97); }
.btn.primary { background: var(--c-primary); border-color: var(--c-primary); color: #fff; }
.btn.primary:hover { background: var(--c-primary-hover); }
.btn.danger { color: var(--c-danger); border-color: var(--c-danger-line); }
.btn.danger:hover { background: var(--c-danger-soft); }
.btn.ghost { border-color: transparent; color: var(--c-text-2); }
.btn.ghost:hover { background: var(--c-surface-hover); color: var(--c-text); }
.btn.sm { height: 28px; padding: 0 10px; font-size: 12px; }
/* 권한 없음 등으로 비활성화된 링크형 버튼(a 태그는 disabled 속성이 없다) */
.disabled-link { opacity: .5; pointer-events: none; }
/* 비활성 — 시각적으로도 눌 수 없음을 보인다. .45 는 danger 대비가 1.8:1 까지 떨어져 .55 로 상향 */
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn:disabled:active { transform: none; }
/* 링크형 버튼(a.btn)은 disabled 속성이 없어 클래스로 비활성을 표현한다 — aria-disabled 와 함께 쓴다.
   (전에는 뷰마다 인라인 style 로 흩어져 있어 정의가 CSS 에 없었다 — UX 개선계획 P4-6) */
.btn.disabled-link { opacity: .5; pointer-events: none; }

/* 포커스 링 — 앱 포커스 색으로 통일(브라우저 기본 링은 디자인 토큰과 다른 색).
   :focus-visible 이라 마우스 클릭에는 나타나지 않고 키보드 이동에서만 보인다(UX 개선계획 P4-7). */
.btn:focus-visible, a:focus-visible, .tab:focus-visible, .doc-item:focus-visible,
.pl-stage:focus-visible, .slot-tab:focus-visible, .row-toggle:focus-visible,
.note-x:focus-visible, .user-menu-item:focus-visible {
  outline: 2px solid var(--c-primary); outline-offset: 2px;
}
/* 목록 행의 키보드 포커스 — grid.js 가 tr[data-row] 에 로빙 tabindex 를 준다.
   outline-offset 은 음수로 둔다: 행은 표 안에 꽉 차 있어 바깥 오프셋이면 이웃 행에 잘린다. */
table.grid tbody tr[data-row]:focus-visible {
  outline: 2px solid var(--c-primary); outline-offset: -2px;
}
/* 배너의 오류 메시지 → 해당 칸으로 이동 */
.note.banner.error .v-err { cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.note.banner.error .v-err:focus-visible { outline: 2px solid var(--c-danger); outline-offset: 2px; }

/* 본문 바로가기 — 포커스될 때만 나타난다 */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 400;
  transform: translateY(-200%); transition: transform var(--dur-fast);
  background: var(--c-primary); color: #fff; padding: 9px 14px;
  border-radius: var(--radius); font-size: 13px; font-weight: 600; text-decoration: none;
}
.skip-link:focus { transform: translateY(0); }

/* ── 카드 / 필터바 ─────────────────────────────── */
.card { background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius); box-shadow: var(--shadow); }
.card .card-head {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px;
  border-bottom: 1px solid var(--c-border); font-weight: 700; font-size: 14px;
}
.card .card-head .count { color: var(--c-primary); font-weight: 700; }
.card .card-head .tools { margin-left: auto; display: flex; gap: 6px; }
/* 카드 머리글 보조 줄 — 조작 힌트·범례를 제목 줄에 함께 넣으면 좁은 폭에서 줄바꿈이 깨진다
   (생산계획 범례가 "외 / 주" 로 쪼개지던 문제). 제목 줄은 제목·건수·도구만, 설명은 이 줄이 받는다. */
.card .card-sub {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  padding: 8px 16px; border-bottom: 1px solid var(--c-border);
  background: var(--c-grid-header-bg);
}
.card .card-sub .legend { flex-wrap: wrap; }
.card .card-body { padding: 16px; }

.filter-bar {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
  padding: 14px 16px; background: var(--c-surface);
  border: 1px solid var(--c-border); border-radius: var(--radius); box-shadow: var(--shadow);
}
/* 기간 프리셋 칩 (동작 정본 wwwroot/js/daterange.js) — 필터 폼 안에 주입된다.
   필터바가 flex-wrap 이라 flex-basis:100% 로 두면 같은 카드 안에서 한 줄 아래로 접힌다.
   .content 의 16px gap 밖(형제)으로 빼면 필터와 따로 노는 블록으로 읽혀서 폼 안쪽에 둔다.
   클래스명이 .chip 이 아니라 .range-chip 인 이유: .chip 은 이미 상태 배지(점+색상, 아래 정의)로
   전 화면에서 쓰이고 있다 — 재사용하면 ::before 점이 딸려 들어오고 padding 도 덮인다. */
.filter-bar .range-chips { flex: 0 0 100%; margin-top: 2px; }
/* 칩 줄 자리 예약 — daterange.js(defer) 가 칩을 붙이기 전 첫 페인트에서 같은 높이(28px+2px)를 비워 둔다.
   없으면 주입 순간 필터바 아래 전체가 30px 밀려 데스크톱 CLS 0.10~0.12 가 찍혔다(Lighthouse 루프-02). 칩이 붙으면 :has() 로 사라진다 */
.filter-bar[data-daterange]:not(:has(.range-chips))::after { content: ""; flex: 0 0 100%; height: 28px; margin-top: 2px; }
.range-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.range-chips-label { font-size: 12px; font-weight: 600; color: var(--c-text-2); margin-right: 2px; }
.range-chip {
  height: 28px; padding: 0 12px; border-radius: 14px;
  border: 1px solid var(--c-border-strong); background: var(--c-surface);
  color: var(--c-text-2); font-size: 12px; font-weight: 600; font-family: inherit;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast), border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast);
}
.range-chip:hover { background: var(--c-grid-header-bg); border-color: var(--c-border-hover); color: var(--c-text); }
.range-chip:active { transform: scale(.96); }
.range-chip.on { background: var(--c-primary); border-color: var(--c-primary); color: #fff; }
.range-chip:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 2px; }
/* 좌측 목록 패널(폭 ~280px)용 축약 — 칩이 3줄로 늘어지지 않도록 한 단계 작게 */
.doc-filter .range-chips { gap: 4px; }
.doc-filter .range-chips-label { display: none; }
.doc-filter .range-chip { height: 25px; padding: 0 9px; font-size: 11.5px; }

/* 조건부 노출 유틸 (2026-08-29) — 화면들이 classList.toggle('hidden', …) 로 칸을 여닫는데
   정작 이 규칙이 없어 대상 칸이 늘 보이고 있었다(검사 '연결 수주라인'·실적 '초과 사유'·검사 '재검 대상').
   .field 가 display:flex 를 갖고 있어 !important 로 이긴다 — 유틸리티 클래스의 통상 규약이다. */
.hidden { display: none !important; }

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field > label { font-size: 12px; font-weight: 600; color: var(--c-text-2); }
.field > label .req { color: var(--c-danger); margin-left: 2px; }
.field input[type=text], .field input[type=date], .field input[type=month], .field input[type=number],
.field input[type=password], .field input[type=email], .field select, .field textarea {
  height: 34px; padding: 0 10px; border: 1px solid var(--c-border-strong); border-radius: 6px;
  font-size: 13px; font-family: inherit; color: var(--c-text); background: #fff; min-width: 0;
}
.field textarea { height: auto; padding: 8px 10px; resize: vertical; }
.field input, .field select, .field textarea {
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.field input[readonly], .field input:disabled { background: var(--c-muted-bg); color: var(--c-text-2); }
/* 인라인 검증(required/pattern) 실패 필드 — 사용자가 상호작용한 뒤에만 표시(:user-invalid, 로드 직후 오탐 방지) */
.field input:user-invalid, .field select:user-invalid, .field textarea:user-invalid {
  border-color: var(--c-danger);
}
/* 서버 검증(ModelState) 실패 필드 — _ValidationBanner 의 스크립트가 .invalid 를 붙인다.
   배너 메시지·aria-describedby 와 항상 짝으로 동작하므로 색 단독 인코딩이 아니다.
   위 .field input[type=…] 규칙과 특이도가 같아 반드시 그 뒤에 와야 테두리가 실제로 바뀐다. */
.field.invalid > input, .field.invalid > select, .field.invalid > textarea {
  border-color: var(--c-danger); box-shadow: 0 0 0 3px rgba(220, 38, 38, .12);
}
.field.invalid > label { color: var(--c-danger); }
.field.w-sm { width: 120px; } .field.w-md { width: 180px; } .field.w-lg { width: 260px; }
/* 조작법 안내가 전부 .hint 로 쓰이므로 보조색(2.6:1)이 아닌 본문 보조색(4.8:1)을 쓴다 — WCAG AA */
.hint { font-size: 11.5px; color: var(--c-text-2); font-weight: 400; }
.checks { display: flex; gap: 14px; align-items: center; height: 34px; }
.checks label { display: flex; gap: 6px; align-items: center; font-size: 13px; cursor: pointer; }

/* ── .field 밖 입력 컨트롤 ──────────────────────────
   편집 그리드(table.grid 셀 안 input/select)와 페이지 헤더 액션(대시보드 기준일 date 등)은
   목업에 없던 웹 구현 추가분이라 .field 래퍼가 없다 — 시각 규칙은 .field 와 동일하게,
   그리드 셀 안은 행 높이에 맞춰 컴팩트(28px)로 적용한다. */
table.grid td input[type=text], table.grid td input[type=number], table.grid td input[type=date],
table.grid td input[type=time], table.grid td select {
  height: 28px; padding: 0 8px; border: 1px solid var(--c-border-strong); border-radius: 5px;
  font-size: 12.5px; font-family: inherit; color: var(--c-text); background: #fff; min-width: 0;
}
.page-head .actions input[type=date], .page-head .actions select {
  height: 34px; padding: 0 10px; border: 1px solid var(--c-border-strong); border-radius: 6px;
  font-size: 13px; font-family: inherit; color: var(--c-text); background: #fff;
}
.card-head .tools input[type=date], .card-head .tools input[type=search], .card-head .tools select {
  height: 30px; padding: 0 8px; border: 1px solid var(--c-border-strong); border-radius: 6px;
  font-size: 12.5px; font-family: inherit; color: var(--c-text); background: #fff;
}
/* 편집 그리드의 선택지 중 "미배정" 상태 셀 — 값이 있는 셀과 시각적으로 구분해 노이즈를 줄인다 */
table.grid td select.unassigned { color: var(--c-text-3); background: var(--c-grid-header-bg); }
table.grid td input, table.grid td select,
.page-head .actions input, .page-head .actions select,
.card-head .tools input, .card-head .tools select {
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
table.grid td input:focus, table.grid td select:focus,
.page-head .actions input:focus, .page-head .actions select:focus,
.card-head .tools input:focus, .card-head .tools select:focus {
  outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
table.grid td input[readonly], table.grid td input:disabled, table.grid td select:disabled {
  background: var(--c-muted-bg); color: var(--c-text-2);
}
/* 그리드 셀 인라인 편집 input(여유레벨·타임 시간대) — 수치·시각 값이라 가운데 정렬 */
.grid td .cell-input { text-align: center; }

/* ── 데이터 테이블 (XtraGrid 대응) ──────────────── */
.table-wrap { overflow-x: auto; }
/* 세로 스크롤 그리드: .table-wrap 에 함께 지정하면 목록이 고정 높이 안에서 스크롤되고
   thead 는 sticky 로 컨테이너 상단에 고정된다 (검색조건이 화면 밖으로 밀리지 않도록). */
.table-wrap.v-scroll { overflow-y: auto; max-height: calc(100vh - 310px); min-height: 240px; }
/* border-collapse 테이블은 sticky 시 th 테두리가 함께 고정되지 않으므로 그림자로 대체 */
.table-wrap.v-scroll table.grid thead th {
  border-top: 0; border-bottom: 0; z-index: 1;
  box-shadow: inset 0 -2px 0 var(--c-border-strong);
  transition: box-shadow var(--dur-base);
}
/* 스크롤 엣지 — 콘텐츠가 헤더 밑으로 지나갈 때만 부양 그림자 (grid.js 가 .scrolled 토글) */
.table-wrap.v-scroll.scrolled table.grid thead th {
  box-shadow: inset 0 -2px 0 var(--c-border-strong), 0 6px 12px -6px rgba(16, 24, 40, .14);
}

/* ── 가로 오버플로 표시 ──────────────────────────
   표가 컨테이너보다 넓으면 잘린 사실 자체가 화면에 없었다(스크롤바도 상시 노출이 아니다).
   grid.js 가 .table-wrap 을 .table-scroll 로 감싸고 좌/우 잔여 스크롤 여부에 따라 .ovf-l/.ovf-r 를 토글한다.
   신호는 그라데이션이 아니라 그림자다 — 위 thead 스크롤 엣지와 같은 언어를 쓰고,
   DESIGN.md 의 "그라데이션 배경 금지"를 지킨다. */
.table-scroll { position: relative; }
.table-scroll::before,
.table-scroll::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 1px;
  pointer-events: none; opacity: 0; transition: opacity var(--dur-fast); z-index: 4;
}
.table-scroll::before { left: 0; box-shadow: var(--shadow-edge-l); }
.table-scroll::after { right: 0; box-shadow: var(--shadow-edge-r); }
.table-scroll.ovf-l::before, .table-scroll.ovf-r::after { opacity: 1; }

/* 가로 스크롤바 상시 노출 — 오버플로가 있는 표에만 (grid.js 가 .ovf-x 를 준다).
   그림자는 "더 있다"를 알리고, 스크롤바는 "얼마나 더 있는지"와 조작 수단을 준다. */
.table-scroll.ovf-x > .table-wrap { overflow-x: scroll; scrollbar-width: thin; }
.table-scroll.ovf-x > .table-wrap::-webkit-scrollbar { height: 10px; }
.table-scroll.ovf-x > .table-wrap::-webkit-scrollbar-thumb {
  background: var(--c-border-strong); border-radius: 999px;
}
.table-scroll.ovf-x > .table-wrap::-webkit-scrollbar-track { background: var(--c-muted-bg); }

/* ── 식별 컬럼 고정 ──────────────────────────────
   가로로 스크롤하면 "이게 어느 수주/거래처 행이었는지"를 잃는다. 뷰가 table[data-stick="N"] 으로
   선두 N개 열을 지정하면 grid.js 가 누적 left 를 계산해 .stick 을 부여한다.
   border-collapse 표는 sticky 셀의 테두리가 고정되지 않으므로(위 thead 와 같은 제약)
   경계는 inset 그림자로 그린다. 배경은 행 상태별로 다시 칠해야 아래 셀이 비쳐 보이지 않는다. */
table.grid .stick { position: sticky; z-index: 2; background: var(--c-surface); }
table.grid thead th.stick { background: var(--c-grid-header-bg); }
/* 머리글 셀은 전부 세로 sticky 라 z-index 가 같고, 같으면 DOM 순서상 뒤 셀이 위에 그려진다
   — 고정 열 머리글이 뒷 열(품목코드…)에 덮이던 원인. 위 v-scroll 규칙(z-index:1)보다 확실히 위로 올린다. */
.table-wrap table.grid thead th.stick,
.table-wrap.v-scroll table.grid thead th.stick { z-index: 6; }
table.grid thead .band th.stick { background: var(--c-grid-band-bg); }
table.grid tbody tr:hover td.stick { background: var(--c-primary-soft); }
table.grid tbody tr.selected td.stick { background: var(--c-selected-row); }
table.grid tbody tr.row-warn td.stick { background: var(--c-warn-soft); }
table.grid tbody tr.dim td.stick { background: var(--c-grid-header-bg); }
table.grid .stick-last { box-shadow: inset -1px 0 0 var(--c-border-strong); }
/* 좌측으로 스크롤된 동안에만 고정 열이 떠 있음을 표시 */
.table-scroll.ovf-l table.grid .stick-last { box-shadow: inset -1px 0 0 var(--c-border-strong), var(--shadow-edge-l); }
table.grid { width: 100%; border-collapse: collapse; font-size: 13px; }
table.grid thead th {
  position: sticky; top: 0; background: var(--c-grid-header-bg); color: var(--c-text-2);
  font-size: 12px; font-weight: 700; text-align: center; white-space: nowrap;
  padding: 9px 10px; border-bottom: 2px solid var(--c-border-strong); border-top: 1px solid var(--c-border);
}
table.grid thead .band th { background: var(--c-grid-band-bg); border-bottom: 1px solid var(--c-border); }
table.grid tbody td {
  padding: 8px 10px; border-bottom: 1px solid var(--c-border);
  text-align: center; white-space: nowrap; color: var(--c-text);
}
table.grid tbody td.l { text-align: left; } table.grid tbody td.r { text-align: right; }
table.grid tbody tr { transition: background var(--dur-fast); }
table.grid tbody tr:hover { background: var(--c-primary-soft); }
table.grid tbody tr.selected { background: var(--c-selected-row); }
/* 정렬 상태 — grid.js 가 th[aria-sort] 를 지정하고 캐럿은 의사요소로 그린다 */
table.grid thead th[aria-sort] { color: var(--c-primary); }
table.grid thead th[aria-sort]::after { content: "▲"; font-size: 9px; margin-left: 4px; vertical-align: 1px; }
table.grid thead th[aria-sort="descending"]::after { content: "▼"; }
/* 정렬 가능(중립) 표식 — grid.js 가 th[data-sortable] 을 지정한다. 눌러보기 전에 "정렬되는 열"임을 알린다.
   허용 기능 문자 ▲▼(DESIGN.md §아이콘)만 쓰고, 세로 2단 스택이라 방향을 암시하지 않는다. */
table.grid thead th[data-sortable]:not([aria-sort])::after {
  content: "▲\A▼"; white-space: pre; display: inline-block;
  font-size: 6px; line-height: 6px; margin-left: 5px; vertical-align: middle;
  color: var(--c-text-4); opacity: .45;
}
table.grid thead th[data-sortable]:hover::after { opacity: .85; }
/* 정렬 기준 컬럼 틴트 — 무엇을 기준으로 정렬됐는지 은은하게 표시 (hover/선택이 우선) */
table.grid tbody td.sorted { background: rgba(37, 99, 235, .04); }
table.grid tbody tr:hover td.sorted, table.grid tbody tr.selected td.sorted { background: transparent; }
table.grid .rownum { color: var(--c-text-3); font-size: 12px; width: 44px; }
/* 선택 행 틴트(#dbeafe) 위에서는 --c-text-3 이 4.24:1 로 4.5 에 못 미친다(2026-08-21 감사).
   흰 배경만 보고 정한 값이 다른 배경에서 미달하는 전형이라, 선택 행에서만 한 단계 진하게 쓴다. */
table.grid tr.selected .rownum { color: var(--c-text-2); }
/* 행 상태 변형: row-warn = 확인 필요(업로드 미리보기 등), dim = 비활성 성격의 행(라우팅 미설정 등) */
table.grid tbody tr.row-warn { background: var(--c-warn-soft); }
/* 재고 상태 행 표식 — 품절/부족 배지는 판정 근거인 '가용수량' 열에 그대로 두고,
   13열짜리 넓은 그리드를 왼쪽부터 훑을 때 이상 행을 놓치지 않도록 행 자체에 표식을 얹는다.
   (배지를 품목명으로 옮기면 행 단위가 품목×창고×로트인 탓에 "품목이 품절"로 오독된다)
   border-collapse 테이블은 tr 에 border 가 먹지 않으므로 첫 셀 inset 그림자로 왼쪽 띠를 그린다. */
table.grid tbody tr.stock-out { background: var(--c-danger-soft); }
table.grid tbody tr.stock-low { background: var(--c-warn-soft); }
table.grid tbody tr.stock-out > td:first-child { box-shadow: inset 3px 0 0 var(--c-danger); }
table.grid tbody tr.stock-low > td:first-child { box-shadow: inset 3px 0 0 var(--c-warn); }
/* hover·선택·체크는 상태 표식보다 우선 — "지금 무엇을 가리키는가"가 더 급한 정보다.
   (앞선 tr:hover/.selected 규칙과 특정도가 같아 나중 선언인 여기서 되돌려줘야 한다) */
table.grid tbody tr.stock-out:hover, table.grid tbody tr.stock-low:hover { background: var(--c-primary-soft); }
table.grid tbody tr.stock-out.selected, table.grid tbody tr.stock-low.selected,
table.grid tbody tr.stock-out.checked,  table.grid tbody tr.stock-low.checked { background: var(--c-selected-row); }
/* 음수 수치 셀 — 재고조정 차감 등 재고를 줄이는 값의 강조 (입출고이력) */
table.grid tbody td.neg { color: var(--c-danger); font-weight: 700; }
table.grid tbody tr.dim { background: var(--c-grid-header-bg); }
table.grid tbody tr.dim td { color: var(--c-text-3); }
/* 합계 행 — 표의 결론이다. 머리글과 같은 색이면 "데이터 한 줄 더"로 읽혀 그냥 지나친다.
   파란 틴트 + 상단 경계선으로 본문에서 떼어낸다. */
table.grid tfoot td {
  padding: 11px 10px; background: var(--c-grid-foot-bg); font-weight: 700;
  border-top: 2px solid var(--c-primary); text-align: right; color: var(--c-text);
}
/* 합계 라벨(colspan 병합 셀) — 좌측 끝에 두면 값까지 시선이 표 전체를 가로질러야 한다.
   우측 정렬 + 캐럿으로 바로 옆 값을 가리킨다. 허용 기능 문자 ▸(DESIGN.md §아이콘). */
table.grid tfoot td.sum-label {
  text-align: right; color: var(--c-text-2); font-size: 12px; letter-spacing: .4px;
}
table.grid tfoot td.sum-label::after { content: " ▸"; color: var(--c-primary); }
/* 해당 화면의 핵심 합계값 — 값이 1~2개인 화면에서만 지정한다(여러 값에 붙이면 강조가 흐려진다) */
table.grid tfoot td.val { font-size: 14.5px; color: var(--c-primary-ink); }   /* 합계 행 틴트(#e8eef8) 위 4.5:1 — ink 토큰 */
/* 세로 스크롤 표에서는 합계를 바닥에 고정 — 페이지당 200행이라 끝까지 굴려야만 보이던 문제를 없앤다.
   머리글 sticky 와 위아래 대칭(위=열 이름, 아래=합계).
   border-collapse 표는 sticky 셀의 테두리가 함께 고정되지 않으므로 thead 와 같은 방식으로 그림자 대체 */
.table-wrap.v-scroll table.grid tfoot td {
  position: sticky; bottom: 0; z-index: 2; border-top: 0;
  box-shadow: inset 0 2px 0 var(--c-primary), 0 -7px 14px -7px rgba(16, 24, 40, .22);
}

/* ── 상태 칩 (status_text 셀 색상 대응) ─────────── */
/* 변형 없는 기본형 = 중립 상태(대기·미정). 배경이 없으면 알약으로 보이지 않아
   같은 컬럼의 다른 칩과 형태가 어긋난다(UX 개선계획 P4-3). */
.chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px;
  border-radius: 999px; font-size: 12px; font-weight: 600;
  background: var(--c-muted-bg); color: var(--c-neutral-ink);
}
.chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.chip.ok   { background: var(--c-success-soft); color: var(--c-success-ink); }
.chip.stop { background: var(--c-muted-bg); color: var(--c-neutral-ink); }
/* 범례용 납기 색 견본 — 셀(td.due-*)과 같은 토큰을 써서 색이 어긋나지 않게 한다(UX 개선계획 P4-4) */
.legend i.due7  { background: var(--c-danger); }
.legend i.due14 { background: var(--c-warn); }
.chip.warn { background: var(--c-warn-soft); color: var(--c-warn-ink); }
.chip.bad  { background: var(--c-danger-soft); color: var(--c-danger-ink); }
.chip.info { background: var(--c-primary-soft); color: var(--c-primary-ink); }

/* 자재 소요 칩(생산계획, material-requirements) — 칩이 모달을 여는 유일한 진입점이라 클릭 가능함을 커서로 드러낸다.
   모달의 지연 행(수급예정일 > 착수일)은 납기 임박(due-d7)과 같은 danger 계열 좌측선 — 색만으로 끝내지 않고 입력 title 에도 적는다 */
.chip.mat-chip { cursor: pointer; }
.chip.mat-chip:hover { filter: brightness(0.96); }
table.grid tr.mat-late td:first-child { box-shadow: inset 3px 0 0 var(--c-danger); }

/* ── 태그(거래처 역할 플래그 등) ────────────────── */
.tag {
  display: inline-block; padding: 2px 8px; border-radius: 5px;
  font-size: 11.5px; font-weight: 600; margin-right: 3px;
  background: var(--c-grid-band-bg); color: var(--c-text-2); border: 1px solid var(--c-border);
}
.tag.blue { background: var(--c-primary-soft); color: var(--c-primary-ink); border-color: var(--c-primary-line); }
.tag.green { background: var(--c-success-soft); color: var(--c-success-ink); border-color: var(--c-success-line); }
.tag.purple { background: var(--c-purple-soft); color: var(--c-purple-ink); border-color: var(--c-purple-line); }
.tag.red { background: var(--c-danger-soft); color: var(--c-danger-ink); border-color: var(--c-danger-line); }
/* .tag.amber 는 가공비 분석 '판정' 전용이었으나, 판정은 분류가 아니라 상태라 .chip 5종으로 옮겼다(2026-08-09).
   남은 사용처가 없어 제거 — 상태를 .tag 로 표현하는 선례를 남기지 않기 위함이다. */

/* ── 상세 입력 폼 ──────────────────────────────── */
.form-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px 16px; }
.form-grid .span-2 { grid-column: span 2; }
.form-grid .span-4 { grid-column: span 4; }
/* 열 구성 변형 — 뷰의 인라인 grid-template-columns 를 대체한다.
   인라인 선언은 아래 1100px 붕괴 규칙을 미디어쿼리가 이길 수 없어 무력화한다(DESIGN.md 금지 규약).
   새 비율이 필요하면 인라인이 아니라 여기에 변형을 더한다. */
.form-grid.cols-1 { grid-template-columns: 1fr; }
.form-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.form-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.form-grid.cols-5 { grid-template-columns: repeat(5, 1fr); }
.form-grid.c-21 { grid-template-columns: 2fr 1fr; }     /* 넓은 요약 + 좁은 보조 (BOM 업로드 미리보기) */
.form-grid.c-12 { grid-template-columns: 1fr 2fr; }     /* 좁은 코드 + 넓은 명칭 (라우팅·수주 미리보기) */
.form-grid.c-211 { grid-template-columns: 2fr 1fr 1fr; }
.form-grid.c-2112 { grid-template-columns: 2fr 1fr 1fr 2fr; }
@media (max-width: 1100px) {
  .form-grid, .form-grid.cols-3, .form-grid.cols-5,
  .form-grid.c-21, .form-grid.c-12, .form-grid.c-211, .form-grid.c-2112 { grid-template-columns: repeat(2, 1fr); }
  .form-grid .span-4 { grid-column: span 2; }
}

/* ── 마스터-디테일 분할 ─────────────────────────── */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
/* 그리드 아이템은 기본 min-width:auto 라 넓은 표가 있으면 페이지가 옆으로 밀린다
   — 카드가 트랙 폭까지 줄어들게 하고, 넘치는 표는 .table-wrap 내부 스크롤이 받는다 */
.split > * { min-width: 0; }
.split.r-40 { grid-template-columns: 3fr 2fr; }
.split.r-30 { grid-template-columns: 7fr 3fr; }
.split.l-30 { grid-template-columns: 2fr 5fr; }    /* 좌측 좁은 목록 + 우측 넓은 폼 (공정관리) */
.split.l-280 { grid-template-columns: 280px 1fr; } /* 좌측 고정폭 목록 (메뉴권한관리) */
/* minmax(0, …) 필수 — 맨 1fr 은 트랙 최소값이 min-content 라 넓은 표가 뷰포트를 밀어낸다(ship-split:1040 참조) */
@media (max-width: 1200px) { .split, .split.r-40, .split.r-30, .split.l-30, .split.l-280 { grid-template-columns: minmax(0, 1fr); } }

/* ── KPI 통계 타일 ─────────────────────────────── */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.stat {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 14px 16px;
  transition: box-shadow var(--dur-base), transform var(--dur-base);
}
.stat:hover { box-shadow: var(--shadow-lift); transform: translateY(-1px); }
.stat .k { font-size: 12px; color: var(--c-text-2); font-weight: 600; }
.stat .v { font-size: 24px; font-weight: 800; margin-top: 4px; letter-spacing: -0.015em; }
.stat .v small { font-size: 13px; font-weight: 600; color: var(--c-text-3); margin-left: 2px; }
.stat .sub { font-size: 12px; margin-top: 4px; color: var(--c-text-3); }
.stat .sub .up { color: var(--c-success-ink); font-weight: 700; }   /* 12px 굵은 글자 — ink 토큰으로 4.5:1 대비 확보 */
.stat .sub .down { color: var(--c-danger-ink); font-weight: 700; }
/* 경고 타일(진행중 중단 > 0) — 납기 due-d7 과 같은 danger 계열. 값만 빨강, 테두리로 한 번 더 구분. 초록은 쓰지 않는다(대시보드 색 규약) */
.stat.alert { border-color: var(--c-danger-ink); }
.stat.alert .v { color: var(--c-danger-ink); }

/* ── 탭 ────────────────────────────────────────── */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--c-border); padding: 0 4px; }
.tabs .tab {
  padding: 10px 16px; font-size: 13.5px; font-weight: 600; color: var(--c-text-2);
  border-bottom: 2px solid transparent; cursor: pointer; background: none; border-top: 0; border-left: 0; border-right: 0; font-family: inherit;
}
.tabs .tab { transition: color var(--dur-fast), border-color var(--dur-fast), transform var(--dur-fast); }
.tabs .tab.active { color: var(--c-primary); border-bottom-color: var(--c-primary); }
.tabs .tab:hover:not(.active) { color: var(--c-text); }
.tabs .tab:active { transform: scale(.98); }

/* ── 진행률 바 ─────────────────────────────────── */
.progress { height: 8px; background: var(--c-track); border-radius: 999px; overflow: hidden; min-width: 80px; }
.progress > i { display: block; height: 100%; border-radius: 999px; background: var(--c-primary);
  transition: width var(--dur-base) var(--ease-out); }
.progress > i.g { background: var(--c-success); } .progress > i.w { background: var(--c-warn); } .progress > i.d { background: var(--c-danger); }
/* 그리드 셀 안 비중 막대 + 수치 (불량유형별 집계 등 RepositoryItemProgressBar 대응) */
.bar-cell { display: flex; align-items: center; gap: 8px; }
.bar-cell .progress { flex: 1; }
.bar-cell .pct { min-width: 48px; text-align: right; }

/* ── 모달(정적 표현용) ─────────────────────────── */
.modal-demo {
  border: 1px solid var(--c-border); border-radius: 12px; box-shadow: 0 20px 50px rgba(16,24,40,.18);
  background: var(--c-surface); max-width: 720px;
}
.modal-demo .modal-head { display: flex; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--c-border); font-weight: 700; font-size: 15px; }
.modal-demo .modal-head .x { margin-left: auto; color: var(--c-text-3); font-size: 18px; cursor: pointer; }
/* 넓은 모달 변형 — 표·그리드를 담는 모달용. 뷰마다 인라인 max-width 를 쓰지 않도록 변형으로 고정 */
.modal-demo.wide { max-width: 1280px; }
/* 중간 폭 — 폼이 2단으로 들어가는 편집 모달(품목 등록 등). 뷰의 인라인 max-width 를 대체한다 */
.modal-demo.mid { max-width: 860px; }
/* 폼 + 상세표 복합 모달(BOM·라우팅·리드타임 등록) — 인라인 920/960/980px 3종을 하나로 수렴 */
.modal-demo.mid-lg { max-width: 960px; }
/* 소형 입력 모달(비밀번호 변경·납기일 수정) — 인라인 400/420px 수렴. 확인 모달(520px)보다 좁다 */
.modal-demo.narrow { max-width: 420px; }
.modal-demo .modal-body { padding: 18px; }
/* 공용 확인 모달(P6-2) — 네이티브 confirm 대체. 문구가 짧아 720px 은 넓다.
   본문은 기존 confirm 문자열을 그대로 옮기므로 개행(\n)을 살린다. */
.modal-demo.confirm-modal { max-width: 520px; }
.confirm-body { font-size: 14px; line-height: 1.75; color: var(--c-text); white-space: pre-line; }
.confirm-note { margin-top: 12px; }
.modal-demo .modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--c-border); background: var(--c-grid-header-bg); border-radius: 0 0 12px 12px; }

/* ── 빈 상태 / 안내 ────────────────────────────── */
.empty { text-align: center; color: var(--c-text-3); padding: 40px 0; font-size: 13px; }
.note {
  padding: 10px 14px; border-radius: var(--radius); font-size: 12.5px;
  background: var(--c-primary-soft); color: var(--c-primary-ink); border: 1px solid var(--c-primary-line);
  animation: note-in var(--dur-base) var(--ease-out);
}
.note.warn { background: var(--c-warn-soft); color: var(--c-warn-ink); border-color: var(--c-warn-line); }
/* 결과 안내 색 위계 (UX 개선계획 P4-1) — 실패=빨강.
   성공은 배너가 아니라 상단 중앙 토스트(.app-toast.success)로 나간다 — 확인만 하면 끝나는
   소식이라 본문을 밀어내며 남을 이유가 없다. .note.success 는 뷰가 직접 쓰는 정적 안내용으로 남긴다.
   기본 .note(파랑)=정보, .note.warn(주황)=주의 역시 뷰의 정적 안내용이다. */
.note.success { background: var(--c-success-soft); color: var(--c-success-ink); border-color: var(--c-success-line); }
.note.error   { background: var(--c-danger-soft);  color: var(--c-danger-ink); border-color: var(--c-danger-line); }
/* 결과 배너(.banner) = 방금 내 동작의 결과. 뷰의 상시 안내와 구분되도록 왼쪽 강조선 + 상태 아이콘을 붙인다.
   아이콘은 색만으로 구분하지 못하는 사용자를 위한 이중 단서다(색 단독 인코딩 금지). */
.note.banner { border-left-width: 4px; font-weight: 600; }
.note.banner::before { margin-right: 6px; font-weight: 700; }
.note.banner.success::before { content: "\2713"; }   /* ✓ */
.note.banner.error::before   { content: "\26A0"; }   /* ⚠ */
.note.banner.warn::before    { content: "\26A0"; }
/* 전역 배너(TempData) 닫기 버튼 — _Layout 이 배너에만 붙인다(뷰 정적 안내 .note 는 없음) */
.note .note-x {
  float: right; margin: -2px -6px 0 8px; padding: 2px 6px;
  background: none; border: 0; cursor: pointer; font-size: 13px;
  color: inherit; opacity: .55; line-height: 1;
}
.note .note-x:hover { opacity: 1; }
@keyframes note-in {
  from { opacity: 0; transform: translateY(-6px); }
}

/* ── 하단 상태바 (ShowBottomMessage 대응) ───────── */
.statusbar {
  position: fixed; left: var(--sidebar-w); right: 0; bottom: 0; height: 30px;
  background: rgba(255, 255, 255, .8);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-top: 1px solid var(--c-border);
  display: flex; align-items: center; gap: 16px; padding: 0 20px;
  font-size: 12px; color: var(--c-text-2); z-index: 30;
}

/* ── 캘린더(공휴일관리용) ───────────────────────── */
.calendar { display: grid; grid-template-columns: repeat(7, 1fr); border-left: 1px solid var(--c-border); border-top: 1px solid var(--c-border); }
.calendar .dow, .calendar .day { border-right: 1px solid var(--c-border); border-bottom: 1px solid var(--c-border); }
.calendar .dow { padding: 8px; text-align: center; font-size: 12px; font-weight: 700; color: var(--c-text-2); background: var(--c-grid-header-bg); }
.calendar .dow.sun, .calendar .day .d.sun { color: var(--c-danger-ink); }   /* 공휴일 칸(danger-soft) 위 4.5:1 — ink 토큰 */
.calendar .dow.sat, .calendar .day .d.sat { color: var(--c-primary); }
.calendar .day { min-height: 84px; padding: 6px 8px; font-size: 12px; background: #fff; }
.calendar .day.dim { background: var(--c-grid-header-bg); color: var(--c-text-3); }
.calendar .day.holiday { background: var(--c-danger-soft); }
/* 휴무 유형별 셀 배경: off=주말 등 기타 휴무, special=특정일 (원본 CustomDrawCell 색 규칙) */
.calendar .day.off { background: var(--c-muted-bg); }
.calendar .day.special { background: var(--c-primary-soft); }
.calendar .day.in { cursor: pointer; transition: filter var(--dur-fast); }
.calendar .day.in:hover { filter: brightness(.97); }
.calendar .day.sel { outline: 2px solid var(--c-primary); outline-offset: -2px; }
.calendar .day .d { font-weight: 700; }
.calendar .day .ev { margin-top: 4px; padding: 2px 6px; border-radius: 4px; background: var(--c-danger-soft); color: var(--c-danger-ink); font-size: 11px; font-weight: 600; display: inline-block; }
.calendar .day .ev.special { background: var(--c-selected-row); color: var(--c-primary-ink); }
.calendar .day .ev.off { background: var(--c-muted-bg); color: var(--c-text-2); }
/* 비고 존재 표시 점 — 캘린더 셀 우측 상단·범례 공용 */
/* 달력 셀에서 홀로 '비고 있음'을 나르는 정보라 장식 대비로는 부족하다.
   면 색(--c-success #16a34a)은 선택 행 틴트(#eff6ff) 위에서 3.03:1 이었다 — 잉크 단계로 올린다(2026-08-21 감사). */
.remark-dot { color: var(--c-success-ink); font-weight: 700; }
.calendar .day .remark-dot { float: right; }

/* ── 로그인 페이지 전용 ─────────────────────────── */
/* 그라데이션 금지(DESIGN.md) — 사이드바와 같은 단색 다크 배경으로 통일 */
body.login-page { display: grid; place-items: center; background: var(--c-sidebar-bg); }
.login-card { width: 400px; background: var(--c-surface); border-radius: 16px; box-shadow: var(--shadow-card-xl); padding: 36px;
  animation: modal-in var(--dur-modal) var(--ease-out); }
/* 입력·버튼 44px — 업무 화면 입력(34px)과 다른 이유가 있다.
   현장 관리자가 태블릿에서 /floor/confirm 에 직접 접근하면 반드시 이 화면을 거치므로,
   현장 표면(floor.css)과 같은 터치 하한을 지킨다. 종전 42px 은 2px 모자랐다. */
.login-card .field input { height: 44px; }
.login-card .btn.primary { height: 44px; font-size: 15px; justify-content: center; }
.login-card .brand-block { display: flex; flex-direction: column; gap: 16px; margin-bottom: 28px; }
.login-card .brand-block img { height: 52px; width: auto; align-self: flex-start; }
.login-card .brand-block .t { font-size: 20px; font-weight: 800; }
.login-card .brand-block .s { font-size: 12.5px; color: var(--c-text-2); }
.login-card form { display: flex; flex-direction: column; gap: 14px; }
.login-card .note { text-align: center; }
.login-card .ver { margin-top: 24px; text-align: center; font-size: 11.5px; color: var(--c-text-3); }

/* ── 인쇄 ──────────────────────────────────────── */
@media print { .sidebar, .topbar, .statusbar, .page-head .actions, .action-bar, .doc-panel, .app-toast-stack { display: none; } .main { margin-left: 0; } .doc-split { grid-template-columns: 1fr; } }

/* ── 모달 오버레이 (Phase 3 팝업 화면 공용 — frm*_P 대응) ──
   materialize 등장: 스크림 페이드 + 본체 scale/translate. display:none→flex 토글마다
   애니메이션이 재생되므로 서버 렌더링 모달(로드와 함께 표시)과 JS 토글 모달 모두 동작. */
.modal-overlay { position: fixed; inset: 0; z-index: 200; display: flex; align-items: flex-start; justify-content: center; padding: 48px 16px; background: var(--c-scrim); overflow-y: auto;
  animation: overlay-in var(--dur-base) var(--ease-out); }
.modal-overlay .modal-demo { margin: 0 auto; width: 100%; box-shadow: var(--shadow-card-xl);
  transform-origin: top center; animation: modal-in var(--dur-modal) var(--ease-out); }
@keyframes overlay-in { from { background-color: rgba(15, 23, 42, 0); } }
@keyframes modal-in { from { opacity: 0; transform: scale(.96) translateY(8px); } }
/* 소멸 — 등장과 같은 경로의 역커브(공간 일관성). JS 가 .closing 부여 후 animationend 에 숨긴다 */
.modal-overlay.closing { animation: overlay-out var(--dur-base) var(--ease-in) forwards; }
.modal-overlay.closing .modal-demo { animation: modal-out var(--dur-base) var(--ease-in) forwards; }
@keyframes overlay-out { to { background-color: rgba(15, 23, 42, 0); } }
@keyframes modal-out { to { opacity: 0; transform: scale(.96) translateY(8px); } }

/* ── 라인 일정 셀 (생산계획 udcOrderPlan 대응 — 밴드 헤더 룰은 데이터 테이블 절에 정의) ── */
table.grid td.sched { font-size: 11px; line-height: 1.5; text-align: center; cursor: pointer; min-width: 76px;
  transition: filter var(--dur-fast); }
/* hover 배경 심화 — 3색 변형(mat/inh/out)을 각각 정의하지 않고 filter 로 공통 처리 */
table.grid td.sched:hover { filter: brightness(.96); }
table.grid td.sched.mat { background: var(--c-sched-mat); }
table.grid td.sched.inh { background: var(--c-sched-inh); }
table.grid td.sched.out { background: var(--c-sched-out); }
/* 생산계획 그리드 — 납기일 더블클릭 편집 셀, 생산요청 입력, 제안지시(클릭=적용) 셀 */
.grid td.duedt { cursor: pointer; }
.grid td .qty-input { width: 72px; text-align: right; }
.grid td.suggest { cursor: pointer; color: var(--c-primary); font-weight: 600; }
.grid td.suggest:hover { background: var(--c-primary-soft); }
.legend { display: flex; gap: 12px; font-size: 12px; color: var(--c-text-2); align-items: center; }
.legend i { display: inline-block; width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--c-border); margin-right: 4px; vertical-align: -1px; }
/* 범례 색 견본 — 반드시 셀과 같은 변수를 공유한다 (범례-셀 색 불일치 방지) */
.legend i.mat { background: var(--c-sched-mat); }
.legend i.inh { background: var(--c-sched-inh); }
.legend i.out { background: var(--c-sched-out); }

/* ── 담당자 알림 (Phase 7A-3 — _Layout 배지/패널/토스트, notice.js 와 짝) ──
   표현 계층은 Apple 유동적 인터페이스 원칙 적용 — 패널은 불투명 표면, 토스트만 반투명 재질.
   스프링 모션은 notice.js 가 rAF 로 구동한다 (CSS transition 은 제스처와 충돌하므로 두지 않는다). */
.notice-bell { position: relative; margin-right: 10px; }
.notice-bell .btn svg { display: block; }
.notice-badge { position: absolute; top: -6px; right: -6px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--c-danger); color: #fff; font-size: 11px; line-height: 17px; text-align: center;
  font-variant-numeric: tabular-nums; will-change: transform; }
/* 패널 — 불투명 표면. transform-origin 을 트리거(우상단) 쪽에 고정해
   버튼과의 공간 관계가 드러난다. opacity/scale 은 notice.js 스프링이 구동. */
.notice-panel { position: absolute; right: 0; top: calc(100% + 8px); width: 360px; max-height: 420px; overflow-y: auto;
  background: var(--c-surface);
  border: 1px solid var(--c-border-strong); border-radius: 14px;
  box-shadow: 0 16px 48px rgba(16, 24, 40, .18), 0 2px 8px rgba(16, 24, 40, .08);
  z-index: 200; transform-origin: top right; will-change: transform, opacity; }
.notice-panel-head { padding: 11px 14px; font-weight: 700; border-bottom: 1px solid var(--c-border);
  position: sticky; top: 0; z-index: 1; background: var(--c-surface); }
.notice-panel-head .hint { font-weight: 400; font-size: 11px; color: var(--c-text-2); }
.notice-item { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--c-border); overflow: hidden; }
.notice-item .notice-msg { grid-column: 1 / -1; font-size: 13px; line-height: 1.5; letter-spacing: .005em; }
.notice-item .notice-msg:hover[style*="cursor"] { color: var(--c-primary); }
.notice-item .notice-meta { font-size: 11px; color: var(--c-text-2); align-self: center; }
.notice-item .btn { justify-self: end; }
.notice-empty { padding: 20px 12px; font-size: 12px; color: var(--c-text-2); text-align: center; }
/* ── 공용 토스트 (마크업·모션 정본은 wwwroot/js/toast.js) ──────────────
   두 스택이 성격을 나눈다: 상단 중앙 = 방금 '내가 한' 동작의 결과(저장·삭제·업로드 성공),
   우하단 = 담당자 알림. 스택 컨테이너에 쌓아 겹침을 막고, 스와이프로 치울 수 있다.
   transform/opacity 는 스프링(motion.js)이 구동 — 여기에 transition 을 두면 1:1 트래킹이 깨진다.

   스택은 pointer-events:none, 토스트만 auto — 상단 스택은 페이지 헤드·버튼 위를 지나므로
   비어 있을 때 보이지 않는 클릭 벽이 되면 안 된다. */
.app-toast-stack { position: fixed; z-index: 300; pointer-events: none;
  display: flex; flex-direction: column; gap: 10px; }
/* 뷰포트가 아니라 '콘텐츠' 중앙 — 사이드바(240px 고정)를 빼지 않으면 왼쪽으로 치우쳐 보인다 */
.app-toast-stack.top { top: 16px; left: calc(50% + var(--sidebar-w) / 2); transform: translateX(-50%);
  align-items: center; }
.app-toast-stack.bottom { right: 20px; bottom: 48px; align-items: flex-end; }
.app-toast { pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px; max-width: 380px; padding: 12px 14px;
  background: rgba(30, 37, 50, 0.92); color: #fff;
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, .08); border-radius: 12px;
  font-size: 13px; line-height: 1.5;
  box-shadow: var(--shadow-toast);
  cursor: grab; touch-action: pan-y; user-select: none; -webkit-user-select: none;
  will-change: transform, opacity; }
.app-toast:active { cursor: grabbing; }
.app-toast svg { flex: none; margin-top: 2px; opacity: .8; }
/* 줄바꿈 보존 — 검증 안내는 '무엇이 막혔나 / 어떻게 푸나'를 두 줄로 나눠 쓴다(구 alert 의 \n 을 그대로 승계).
   pre-line 이라 연속 공백·들여쓰기는 접히고 개행만 산다 — 소스 정렬이 화면에 새지 않는다. */
.app-toast span { white-space: pre-line; }
/* 종류 구분은 왼쪽 강조선 + 아이콘 색 이중 단서 — 색 단독 인코딩 금지(배너 .note.banner 와 같은 원칙) */
.app-toast.success { border-left: 3px solid var(--c-success-on-dark); }
.app-toast.success svg { color: var(--c-success-on-dark); opacity: 1; }
.app-toast.error { border-left: 3px solid var(--c-danger-on-dark); }
.app-toast.error svg { color: var(--c-danger-on-dark); opacity: 1; }
/* 접근성 — 투명도 줄이기: 토스트 재질을 불투명으로 (패널은 항상 불투명, 모션 감소는 motion.js 스프링이 자체 처리) */
@media (prefers-reduced-transparency: reduce) {
  .app-toast { background: var(--c-sidebar-bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/* 토스트 seed — 서버가 심고 toast.js 가 읽어가는 데이터일 뿐, 화면에는 그리지 않는다 */
.toast-seed { display: none; }

/* ── 수주 단계 진행 바 (Phase 7A-3 — 제품출하 화면, 7단계 세그먼트) ── */
.stage-bar { display: inline-flex; gap: 2px; }
.stage-bar i { display: inline-block; width: 14px; height: 10px; border-radius: 2px; background: var(--c-muted-bg);
  border: 1px solid var(--c-border); }
.stage-bar i.on { background: var(--c-success); border-color: var(--c-success); }
.stage-bar i.cur { background: var(--c-primary); border-color: var(--c-primary); }

/* ── 생산실적 (udcProductResult) — 단계 플로우·타임 탭·진척 패널·근무 도우미 ── */
/* 작성 → 확정 → 재고입고 단계 칩 (카드 헤더용) */
.stage-flow { display: inline-flex; align-items: center; gap: 5px; margin-left: 6px; font-weight: 400; }
.stage-flow .arr { color: var(--c-text-3); font-size: 11px; }
/* 타임(1~4) 선택 탭 — 상태(미작성/작업중/완료)와 실적합을 함께 표시 */
.slot-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.slot-tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-width: 96px; padding: 7px 12px; border: 1px solid var(--c-border-strong); border-radius: 8px;
  background: var(--c-surface); font-family: inherit; font-size: 13px; cursor: pointer;
  transition: border-color var(--dur-fast), background var(--dur-fast), box-shadow var(--dur-fast), transform var(--dur-fast);
}
.slot-tab:hover { border-color: var(--c-primary); background: var(--c-grid-header-bg); }
.slot-tab:active { transform: scale(.98); }
.slot-tab.active { border-color: var(--c-primary); background: var(--c-primary-soft); box-shadow: inset 0 0 0 1px var(--c-primary); }
.slot-tab .nm { font-weight: 700; }
.slot-tab.active .nm { color: var(--c-primary); }
.slot-tab .st { font-size: 11px; color: var(--c-text-3); }
.slot-tab .st.working { color: var(--c-primary); font-weight: 600; }
.slot-tab .st.done { color: var(--c-success); font-weight: 600; }
/* 진척 패널 — 연계 생산계획 기준 누적/잔량을 진행률 바로 시각화 */
.pg-panel {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 12px;
  padding: 10px 14px; background: var(--c-primary-soft); border: 1px solid var(--c-primary-line);
  border-radius: var(--radius); font-size: 12.5px; color: var(--c-primary-ink);
}
.pg-panel .progress { width: 180px; background: var(--c-selected-row); }
.pg-panel b { font-size: 13px; }
.pg-panel input[type=number] {
  height: 26px; padding: 0 6px; border: 1px solid var(--c-primary-line-strong); border-radius: 5px;
  font-family: inherit; font-size: 12.5px; text-align: right; color: inherit;
}
/* 구분자 글리프는 장식 전용 토큰을 쓴다 — 테두리색(--c-border-strong)을 글자에 쓰면 1.35:1 이라
   장식이라는 의도가 값에 드러나지 않는다(breadcrumb .sep 와 같은 규약) */
.pg-panel .sep, .workcalc .sep { color: var(--c-text-4); }
/* 실근무·가공비 도우미 바 (Phase 7B-2) */
.workcalc {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 8px;
  padding: 8px 12px; background: var(--c-grid-header-bg); border: 1px solid var(--c-border);
  border-radius: var(--radius); font-size: 12.5px;
}
.workcalc input {
  height: 26px; padding: 0 6px; border: 1px solid var(--c-border-strong); border-radius: 5px;
  font-family: inherit; font-size: 12.5px;
}
/* 상세 폼 안 섹션 구분 헤더 — form-grid 전체 폭 */
.form-grid .form-sec {
  grid-column: 1 / -1; margin-top: 4px; padding-bottom: 5px;
  border-bottom: 1px solid var(--c-border);
  font-size: 12px; font-weight: 700; color: var(--c-text-2); letter-spacing: .3px;
}
.form-grid .form-sec:first-child { margin-top: 0; }
.form-grid .form-sec .hint { font-weight: 400; margin-left: 6px; }
/* 통합본 — 현재 편집 중인 타임 열 강조 */
table.grid thead th.cur { color: var(--c-primary); background: var(--c-primary-soft); }
table.grid tbody td.cur, table.grid tfoot td.cur { color: var(--c-primary); font-weight: 700; background: var(--c-primary-soft); }

/* ── 문서형 화면 공용 레이아웃 (마스터-디테일 + 단계 섹션 + 하단 액션바) ──
   생산실적·구매발주처럼 "문서를 골라 이어 쓰는" 업무 공용 — Mail형 배치로
   작성영역이 항상 첫 화면에 보이고, 업무 순서가 곧 화면 순서(단계 섹션)다. */
.doc-split { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 1200px) { .doc-split { grid-template-columns: minmax(0, 1fr); } }
/* 읽기 폭 상한 변형 — 넓은 모니터에서 작업영역(폼 4열·명세표)이 화면 폭만큼 늘어나면 라벨↔값, 수량↔금액 거리가 벌어져
   읽기 어렵다(2026-08-21 필드테스트 지적, 구매발주). 좌 목록 320 + 간격 16 + 작업영역 1040 = 1376.
   1200px 이하 1컬럼 붕괴 구간에서는 상한이 닿지 않아 영향 없음.
   page-head 에도 같은 상한 — 우상단 액션이 작업영역 오른쪽 끝에 정렬되어야 한다(실측 1920px: 미적용 시 버튼이 작업영역 밖 +280px 에 뜸). */
.page-head.w-cap, .doc-split.w-cap { max-width: 1376px; }

/* 좌측: 일보 리스트 패널 — 필터 내장, 독립 스크롤, 화면에 sticky */
.doc-panel {
  position: sticky; top: calc(var(--topbar-h) + 16px);
  display: flex; flex-direction: column; overflow: hidden;
  max-height: calc(100vh - var(--topbar-h) - 76px);
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
@media (max-width: 1200px) { .doc-panel { position: static; max-height: 340px; } }
.doc-panel .panel-head {
  display: flex; align-items: center; gap: 8px; padding: 12px 14px 10px;
  font-weight: 700; font-size: 14px;
}
.doc-panel .panel-head .count { color: var(--c-primary); }
.doc-panel .panel-head .btn { margin-left: auto; }
.doc-filter { display: flex; flex-direction: column; gap: 8px; padding: 0 14px 12px; border-bottom: 1px solid var(--c-border); }
.doc-filter .row { display: flex; gap: 6px; }
.doc-filter input, .doc-filter select {
  width: 100%; min-width: 0; height: 30px; padding: 0 8px; font-family: inherit; font-size: 12.5px;
  border: 1px solid var(--c-border-strong); border-radius: 6px; background: #fff; color: var(--c-text);
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.doc-filter input:focus, .doc-filter select:focus {
  outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.doc-filter .btn { height: 30px; flex: none; }
.doc-items { flex: 1; overflow-y: auto; }
/* 일보 카드 — 1행: 작업일·일보번호·실적합 / 2행: 품목 / 3행: 상태 칩 + 성과율 미니바 */
.doc-item {
  display: block; width: 100%; text-align: left; border: 0; background: none; font: inherit;
  padding: 10px 14px; cursor: pointer; border-bottom: 1px solid var(--c-border);
  border-left: 3px solid transparent;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.doc-item:hover { background: var(--c-grid-header-bg); }
.doc-item:active { background: var(--c-primary-soft); }
.doc-item.selected { background: var(--c-primary-soft); border-left-color: var(--c-primary); }
.doc-item .l1, .doc-item .l2, .doc-item .l3 { display: flex; align-items: center; gap: 7px; }
.doc-item .l1 .date { font-weight: 700; font-size: 13px; }
.doc-item .l1 .no { font-size: 11.5px; color: var(--c-text-3); }
.doc-item .l1 .sum { margin-left: auto; font-size: 13px; font-weight: 700; }
.doc-item .l2 { margin-top: 2px; font-size: 12.5px; color: var(--c-text-2); }
.doc-item .l2 span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-item .l3 { margin-top: 6px; }
.doc-item .l3 .chip { padding: 2px 8px; font-size: 11px; }
.doc-item .l3 .mini-bar { margin-left: auto; width: 60px; }
.doc-item .l3 .mini-bar.progress { height: 5px; min-width: 60px; }
.doc-item .l3 .pct { font-size: 11.5px; color: var(--c-text-2); font-weight: 700; min-width: 34px; text-align: right; }
.doc-empty { padding: 28px 14px; text-align: center; color: var(--c-text-3); font-size: 12.5px; }

/* 우측: 작업영역 — 하단 고정 액션바(높이+부양 간격)만큼 바닥 여백 확보 */
.work-col { min-width: 0; display: flex; flex-direction: column; gap: 14px; padding-bottom: 110px; }
/* 액션바 없는 변형 — 주 액션을 공통 위치(.page-head .actions)로 올린 화면(구매발주, 2026-08-21). 바닥 여백 불필요 */
.work-col.no-bar { padding-bottom: 0; }
/* 작업영역 헤더 — 어떤 문서를 어떤 단계까지 진행했는지(wayfinding) */
.work-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 13px 18px;
}
.work-head h2 { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
.work-head .doc-no { font-size: 13px; color: var(--c-text-3); font-weight: 600; }
/* 미저장 표시 — 액션바의 .dirty 와 같은 색·굵기(액션바 없는 화면은 헤더가 그 자리) */
.work-head .dirty { font-size: 12.5px; color: var(--c-warn); font-weight: 700; }
.work-head .stage-flow { margin-left: auto; }
/* 단계 섹션 카드 — 번호 뱃지로 업무 순서를 화면 구조에 새긴다 */
.step { background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius); box-shadow: var(--shadow); }
.step .step-head {
  display: flex; align-items: center; gap: 10px; padding: 12px 18px;
  border-bottom: 1px solid var(--c-border); font-weight: 700; font-size: 14px;
}
.step .step-head .n {
  width: 22px; height: 22px; border-radius: 50%; background: var(--c-primary-soft); color: var(--c-primary);
  display: grid; place-items: center; font-size: 12px; font-weight: 800; flex: none;
}
.step .step-head .tools { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.step .step-body { padding: 16px 18px; }
/* 진척 패널이 form-grid 안(생산계획 연계 필드 바로 아래)에 들어갈 때 전체 폭 차지 */
.form-grid .pg-panel { grid-column: 1 / -1; margin-top: 0; }
/* 작성자(자동 채움)·비고 — 필드 섹션 대신 컴팩트 한 줄 */
.meta-line {
  margin-top: 14px; padding: 8px 12px; border-radius: var(--radius); background: var(--c-muted-bg);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12.5px; color: var(--c-text-2);
}
.meta-line label { font-weight: 600; font-size: 12px; }
.meta-line input {
  height: 28px; padding: 0 8px; font-family: inherit; font-size: 12.5px;
  border: 1px solid var(--c-border-strong); border-radius: 6px; background: #fff; color: var(--c-text);
  transition: border-color var(--dur-fast), box-shadow var(--dur-fast);
}
.meta-line input:focus { outline: none; border-color: var(--c-primary); box-shadow: 0 0 0 3px rgba(37, 99, 235, .12); }
.meta-line input[readonly] { background: var(--c-muted-bg); color: var(--c-text-2); }
.meta-line .grow { flex: 1; min-width: 200px; }
.meta-line .sep { color: var(--c-text-4); }
/* 확정·입고 — 최종 단계 필드와 [확정] 버튼이 한 곳에 (제어는 대상 곁에) */
.confirm-zone { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; }
.confirm-zone .field { width: 240px; }
.confirm-zone .btn.confirm-btn { height: 38px; padding: 0 20px; font-size: 14px; }
.confirm-note { margin-top: 10px; font-size: 12.5px; color: var(--c-text-2); line-height: 1.7; }
/* 흰 배경 위 강조 텍스트 — 원색 주황은 3.19:1 이라 잉크 단계를 쓴다(면·테두리와 다른 값) */
.confirm-note b { color: var(--c-warn-ink); }
/* 되돌릴 수 있는 상태 전이(발주 취소·재개 등) — 확정과 시각적으로 분리된 보조 영역 */
.cancel-zone {
  margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--c-border);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.cancel-zone .hint { max-width: 520px; }
/* 납기 임박 색상 정본 — D-7 빨강 / D-14 주황, 3개 화면 공용(구 인라인 정의 통합: 대시보드·생산계획·생산계획상세) */
table.grid td.due-d7  { color: var(--c-danger-ink); font-weight: 700; background: var(--c-danger-soft); }
table.grid td.due-d14 { color: var(--c-warn-ink); font-weight: 700; background: var(--c-warn-soft); }
/* 납기 임박 뱃지 — 목록 셀 색상 규칙(due-d7/d14)을 카드·헤더용 뱃지로 승격 */
.due-badge {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px;
  border-radius: 5px; font-size: 11px; font-weight: 700; white-space: nowrap;
}
.due-badge.d7  { background: var(--c-danger-soft); color: var(--c-danger); }
.due-badge.d14 { background: var(--c-warn-soft); color: var(--c-warn); }

/* ── 일괄 처리형 화면 레이아웃 (제품출하) — 좌 그리드 + 우 sticky 선택 작업 패널 ──
   문서형(.doc-split)과 달리 "여러 행을 체크해 한 번에 처리"하는 업무 —
   체크한 행에 하는 모든 일(요약·단계 처리·확정)이 우측 패널 한 곳에 모인다. */
.ship-split { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }
/* 붕괴 시에도 minmax(0, …) 를 유지해야 한다 — 맨 1fr 은 minmax(auto, 1fr) 이고 auto 의 최소값이
   min-content 라, 넓은 표가 트랙을 밀어 카드가 뷰포트를 넘어선다(실측: 1024px 에서 +469px).
   자식의 overflow-x:auto 는 부모가 이미 커진 뒤라 소용이 없다. */
@media (max-width: 1200px) { .ship-split { grid-template-columns: minmax(0, 1fr); } }
/* 단계 파이프라인 요약 — stage-bar 7칸의 범례 + 단계별 대기 건수 + 클릭 필터 */
.stage-pipeline {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 12px 16px;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.stage-pipeline .pl-title { font-size: 13px; font-weight: 700; margin-right: 8px; }
.stage-pipeline .pl-arr { color: var(--c-text-3); font-size: 11px; flex: none; }
.stage-pipeline .hint { width: 100%; margin-top: 2px; }
.pl-stage {
  flex: 1; min-width: 84px; text-align: center; padding: 8px 6px;
  border: 1px solid var(--c-border); border-radius: 8px; background: var(--c-muted-bg);
  cursor: pointer; font-family: inherit; text-decoration: none; display: block;
  transition: border-color var(--dur-fast), background var(--dur-fast), transform var(--dur-fast);
}
.pl-stage:hover { border-color: var(--c-border-hover); }
.pl-stage:active { transform: scale(.98); }
.pl-stage.has { background: var(--c-primary-soft); border-color: var(--c-primary-line); }
.pl-stage.on { border-color: var(--c-primary); box-shadow: 0 0 0 1px var(--c-primary) inset; }
.pl-stage .pl-count { display: block; font-size: 20px; font-weight: 700; color: var(--c-text-3); letter-spacing: -0.01em; }
.pl-stage .pl-count small { font-size: 11px; font-weight: 400; margin-left: 1px; }
.pl-stage.has .pl-count { color: var(--c-primary); }
.pl-stage .pl-name { display: block; font-size: 11.5px; color: var(--c-text-2); margin-top: 1px; }
/* bare 변형 — 카드 내부에 넣을 때 자체 카드 배경·테두리를 제거(대시보드 수주 파이프라인) */
.stage-pipeline.bare { background: none; border: 0; box-shadow: none; padding: 0; }
/* fixed 변형 — 단계 수가 적을 때(생산계획 3칸) flex:1 균등 분배가 카드를 화면 폭만큼 늘려버린다.
   대시보드 '수주 단계별 대기 현황' 카드와 같은 폭으로 고정한다. */
.stage-pipeline.fixed .pl-stage { flex: 0 0 125px; width: 125px; }

/* ── 대시보드 드릴다운 링크 ─────────────────────── */
/* 스탯 카드·표 셀이 링크여도 본문 텍스트 색을 유지한다 */
a.stat { color: inherit; text-decoration: none; display: block; }
.grid td a.drill { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* ── 구매발주: 관련 수주 연결(칩 목록 + 검색 룩업) ── */
.so-links { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 30px; }
.so-links .hint { font-size: 12px; color: var(--c-text-3); }
.so-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px;
           border: 1px solid var(--c-border); border-radius: 14px; font-size: 12px;
           background: var(--c-primary-soft); }
.so-chip .m { color: var(--c-text-3); }
.so-chip .x { border: 0; background: none; cursor: pointer; color: var(--c-text-3); padding: 0 2px; }
.so-chip .x:hover { color: var(--c-danger); }
.so-search { position: relative; display: flex; gap: 6px; margin-top: 6px; }
.so-search input { flex: 1; }
.so-results { position: absolute; top: 100%; left: 0; right: 0; z-index: 30; margin-top: 2px;
              border: 1px solid var(--c-border); border-radius: 6px; background: var(--c-surface);
              box-shadow: var(--shadow-lift); max-height: 240px; overflow-y: auto; }
.so-results button { display: block; width: 100%; text-align: left; border: 0; background: none;
                     padding: 7px 10px; font-size: 13px; cursor: pointer; }
.so-results button:hover { background: var(--c-primary-soft); }
.so-results .none { padding: 7px 10px; font-size: 13px; color: var(--c-text-3); }
/* 선택 작업 패널 — 요약(연속 피드백) → 단계 처리 → 확정, 위→아래가 업무 순서 */
.action-panel {
  position: sticky; top: calc(var(--topbar-h) + 16px);
  display: flex; flex-direction: column;
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
@media (max-width: 1200px) { .action-panel { position: static; } }
.sel-summary { padding: 14px 16px; border-bottom: 1px solid var(--c-border); }
.sel-summary .k { font-size: 12px; font-weight: 600; color: var(--c-text-2); }
.sel-summary .v { font-size: 24px; font-weight: 800; letter-spacing: -0.015em; margin-top: 2px; }
.sel-summary .v small { font-size: 13px; font-weight: 600; color: var(--c-text-3); margin-left: 2px; }
.sel-summary .sub { font-size: 12.5px; color: var(--c-text-2); margin-top: 4px; }
.sel-summary .sub b { color: var(--c-text); }
.sel-summary.empty-state .v { color: var(--c-text-3); }
.panel-sec { padding: 14px 16px; border-bottom: 1px solid var(--c-border); }
.panel-sec:last-child { border-bottom: 0; }
.panel-sec .sec-title { font-size: 12px; font-weight: 700; color: var(--c-text-2); letter-spacing: .3px; margin-bottom: 10px; }
.panel-sec .btn-row { display: flex; gap: 8px; }
.panel-sec .btn-row .btn { flex: 1; }
.panel-sec .field { margin-bottom: 10px; }
.panel-sec .btn.confirm-btn { width: 100%; height: 40px; font-size: 14px; justify-content: center; }
.panel-note { margin-top: 10px; font-size: 12px; color: var(--c-text-2); line-height: 1.7; }
/* 흰 배경 위 강조 — 원색 주황은 3.19:1 (confirm-note b 와 같은 규약) */
.panel-note b { color: var(--c-warn-ink); }
/* 체크 선택 행 하이라이트 + 체크박스 히트·색 */
table.grid tbody tr.checked { background: var(--c-selected-row); }
table.grid input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--c-primary); cursor: pointer; }
/* 하단 고정 액션바 — 저장·삭제가 스크롤 위치와 무관하게 항상 손 닿는 곳에.
   위치·폭은 화면 스크립트가 작업영역(.work-col)에 정렬한다(사이드바·리스트 폭 대응). */
.action-bar {
  position: fixed; bottom: 38px; z-index: 60;
  display: flex; align-items: center; gap: 8px; padding: 10px 16px;
  background: rgba(255, 255, 255, .78);
  -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid var(--c-border-strong); border-radius: 12px; box-shadow: var(--shadow-lift);
}
.action-bar .bar-status {
  margin-right: auto; min-width: 0; font-size: 12.5px; color: var(--c-text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.action-bar .bar-status b { color: var(--c-text); }
.action-bar .bar-status .dirty { color: var(--c-warn); font-weight: 700; }
/* 명세 원인·조치 확장 보조행 — 불량 입력 시 자동 노출, 평소엔 접힘(가로 스크롤 제거) */
.row-toggle {
  width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--c-border-strong);
  background: var(--c-surface); cursor: pointer; font-size: 11px; color: var(--c-text-2); font-family: inherit;
  transition: transform var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast), background var(--dur-fast);
}
.row-toggle:hover { background: var(--c-grid-header-bg); }
.row-toggle.open { transform: rotate(90deg); color: var(--c-primary); border-color: var(--c-primary); }
table.grid tbody tr.cause-row, table.grid tbody tr.cause-row:hover { background: var(--c-warn-soft); }
table.grid tbody tr.cause-row.hidden { display: none; }
table.grid tbody tr.cause-row td { text-align: left; padding: 8px 12px; }
.cause-grid { display: flex; gap: 8px 12px; flex-wrap: wrap; align-items: center; font-size: 12.5px; }
.cause-grid label { font-weight: 600; color: var(--c-text-2); font-size: 12px; }
/* 통합본 접이식 — 출력 정본이라 기본 펼침, 명세 작성 중에는 접어둘 수 있다 */
details.integrated { margin-top: 14px; }
details.integrated summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 700; padding: 4px 0;
}
details.integrated summary::-webkit-details-marker { display: none; }
details.integrated summary::before { content: "▸"; font-size: 11px; color: var(--c-text-3); transition: transform var(--dur-fast); }
details.integrated[open] summary::before { transform: rotate(90deg); }

/* ── 행 선택 → 상세 폼 연결 플래시 (grid.js 가 tr[data-row] 클릭 시 #saveForm 에 부여) ──
   "클릭이 이 폼으로 흘러갔다"는 공간 연결 단서 — 링이 번졌다 사라진다. */
.flash-select { animation: flash-select 600ms var(--ease-out); }
@keyframes flash-select {
  0% { box-shadow: var(--shadow), 0 0 0 3px rgba(37, 99, 235, .28); }
  100% { box-shadow: var(--shadow), 0 0 0 3px rgba(37, 99, 235, 0); }
}

/* ── 그리드 페이저 (grid.js 생성 — 인라인 스타일 대신 클래스) ── */
.grid-pager { display: flex; gap: 4px; align-items: center; justify-content: flex-end; padding: 8px 12px; flex-wrap: wrap; }
.grid-pager .info { font-size: 12px; color: var(--c-text-3); margin-right: 8px; }

/* ── 전역 로딩 오버레이 (loading.js 제어 — 변경 POST 제출 시 표시) ──
   z-index 400: 모달(200)·토스트(300) 위. 화면 전체를 잠가 처리 중 중복 제출을 차단한다 */
.loading-overlay {
  position: fixed; inset: 0; z-index: 400;
  background: rgba(30, 41, 59, .35);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
}
.loading-overlay.active {
  opacity: 1; visibility: visible;
  transition: opacity var(--dur-base) var(--ease-out);
}
.loading-box {
  background: var(--c-surface); border-radius: var(--radius); box-shadow: var(--shadow-lift);
  padding: 22px 32px; min-width: 220px;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  transform: translateY(6px); transition: transform var(--dur-base) var(--ease-out);
}
.loading-overlay.active .loading-box { transform: translateY(0); }
.loading-box .loading-msg { font-size: 13.5px; font-weight: 600; }
.loading-box .loading-sub { font-size: 12px; color: var(--c-text-3); margin-top: -6px; }
.loading-box .loading-sub:empty { display: none; }
.loading-spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--c-primary-soft); border-top-color: var(--c-primary);
  animation: loading-spin .7s linear infinite;
}
@keyframes loading-spin { to { transform: rotate(360deg); } }

/* ── 접근성 감손 대응 ────────────────────────────
   모션 감소: 이동·크기 변화를 제거하되 이해를 돕는 페이드는 짧게 유지.
   (notice.js 스프링은 자체적으로 prefers-reduced-motion 을 감지해 즉시 완료값 처리) */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
  .note, .modal-overlay, .modal-overlay .modal-demo { animation-duration: 150ms !important; }
  @keyframes modal-in { from { opacity: 0; transform: none; } }
  @keyframes note-in { from { opacity: 0; transform: none; } }
  .btn:active, .tabs .tab:active, .slot-tab:active { transform: none; }
  .stat:hover { transform: none; }
  /* 스피너는 정지시키지 않고 감속 회전 유지 — "진행 중" 전달 자체가 목적인 요소 */
  .loading-spinner { animation-duration: 1600ms !important; }
}
/* 투명도 줄이기: 반투명 재질을 불투명으로 (알림 패널·토스트는 알림 절에서 자체 처리) */
@media (prefers-reduced-transparency: reduce) {
  .topbar { background: #fff; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .statusbar { background: var(--c-surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .action-bar { background: var(--c-surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/* 고대비: 면 경계를 뚜렷한 보더로 */
@media (prefers-contrast: more) {
  .card, .filter-bar, .stat { border-color: var(--c-border-strong); }
  .topbar { border-bottom-color: var(--c-border-strong); }
}

/* ── 터치 기기(태블릿) — 최소 터치 타깃 승격 ─────────
   Floor 2화면은 자체 CSS(44~62px)로 이미 대응 — 여기서는 일반 웹 화면의 격차를 줄인다.
   레이아웃 폭은 그대로 두고 높이·히트 영역만 키운다(데스크톱 마우스 환경은 변화 없음). */
/* ── 좁은 화면(≤768px) — 사이드바 오버레이 (UX 개선계획 P6-5) ──────────────
   240px 고정 사이드바는 414px 뷰포트에서 화면의 58%를 차지해 본문에 174px 만 남겼다(실측).
   이 폭부터는 사이드바를 화면 밖으로 밀어 두고 상단바의 [메뉴] 로 불러낸다.
   토글을 아이콘이 아니라 텍스트로 둔 이유: 아이콘 화이트리스트는 3종 고정이며(DESIGN.md §아이콘)
   개정 없이 규약을 지키는 편이 낫다 — 한국어 [메뉴] 는 그 자체로 충분히 명확하다. */
.nav-toggle { display: none; }
.nav-scrim { display: none; }
@media (max-width: 768px) {
  .main { margin-left: 0; }
  .sidebar {
    transform: translateX(-100%);
    transition: transform var(--dur-base);
    box-shadow: var(--shadow-lift);
  }
  .app.nav-open .sidebar { transform: translateX(0); }
  .app.nav-open .nav-scrim { display: block; position: fixed; inset: 0; background: var(--c-scrim); z-index: 40; }
  .nav-toggle { display: inline-flex; align-items: center; }
  /* 좁은 폭에서는 여백이 곧 본문 폭이다 */
  .content { padding: 16px 14px 32px; }
  .topbar { padding: 0 14px; gap: 10px; }
  .page-head .actions { flex-wrap: wrap; }
}
/* 사이드바 슬라이드는 화면 전체가 움직이는 큰 모션이라 감손 설정을 반드시 존중한다 */
@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn.sm { min-height: 44px; }              /* 38px 이었다 — 작은 버튼도 손가락 크기는 같다 */
  .field input[type=text], .field input[type=date], .field input[type=month], .field input[type=number],
  .field input[type=password], .field input[type=email], .field select { height: 44px; }
  .checks { height: auto; min-height: 44px; }
  /* 패딩 산술 대신 min-height 로 잠근다 — 종전 padding:13px 은 폰트 메트릭에 흔들려
     실측이 39~43px 로 갈렸다(2026-08-21 감사). 높이는 계산에 의존하지 않는 값으로 둔다. */
  .nav a { padding: 10px 16px 10px 20px; min-height: 44px; box-sizing: border-box; }
  .nav a .fav-star { visibility: visible; }   /* 호버가 없는 터치 환경은 별 상시 노출 */
  /* 즐겨찾기 별 — 상시 노출로 바꿔 놓고 크기는 17x17 그대로였다.
     아이콘 자체는 키우지 않고 히트 영역만 넓힌다(메뉴명과 별이 서로를 밀어내지 않도록). */
  .nav a .fav-star { min-width: 44px; min-height: 44px; display: inline-flex;
    align-items: center; justify-content: center; padding: 0; margin-right: -12px; }
  .recent-panel a { padding: 12px 10px; }
  .fav-panel a { padding: 12px 10px; }
  /* 목표 크기의 기준선은 WCAG 2.2 AA(2.5.8) 의 24x24 다. 44x44 는 AAA(2.5.5) 이며,
     밀도가 업무 가치인 데이터 그리드에 그 값을 강제하면 한 화면에 보이는 행 수가 줄어
     정작 이 사용자가 잃는 것이 더 크다. 주 조작면(버튼·메뉴·칩)만 44 로 올리고
     그리드 내부 요소는 AA 선(24)을 확보한다. */
  table.grid input[type=checkbox] { width: 24px; height: 24px; }
  /* 기간 프리셋 칩 — 위 주석대로 '주 조작면(버튼·메뉴·칩)' 에 포함된다.
     종전 36/32px 은 주석과 어긋난 값이었다(2026-08-21 감사). 칩은 필터바에서 줄바꿈되므로
     세로 8px 증가가 표를 밀지언정 가로 밀도는 그대로다. */
  .range-chip { height: 44px; padding: 0 16px; }
  .doc-filter .range-chip { height: 44px; padding: 0 13px; }   /* 좁은 좌측 패널 — 높이는 같게, 좌우만 축약 */
  /* 상단바 사용자 칩·탭 — 목록에서 빠져 있던 주 조작면 */
  .user-chip-btn { min-height: 44px; }
  .tabs .tab { min-height: 44px; display: inline-flex; align-items: center; box-sizing: border-box; }
  /* 사이드바 — 메뉴 검색·즐겨찾기·최근방문. 세로로 스크롤되는 영역이라
     높이 증가가 데이터 밀도를 해치지 않는다. */
  .nav-search input { height: 44px; }
  .fav-panel a, .recent-panel a { min-height: 44px; box-sizing: border-box; }
  /* 알림 벨 — 버튼 폭이 38px 이라 높이만 44 였다 */
  .notice-bell .btn { min-width: 44px; }
  /* 본문 바로가기 — 포커스될 때만 나타나지만 그때는 조작 대상이다 */
  .skip-link { min-height: 44px; display: inline-flex; align-items: center; box-sizing: border-box; }
  /* 체크·라디오 — 종전 규칙이 [type=checkbox] 만 잡아 라디오가 13x13 으로 남았다.
     min-width 를 함께 준다: 기본 appearance 의 라디오는 width 만 주면 종횡비 보정으로 23.1px 가 된다. */
  .checks input[type=checkbox], .checks input[type=radio],
  table.grid input[type=radio] { width: 24px; height: 24px; min-width: 24px; min-height: 24px; }
  /* 문서 좌측 패널 필터 — .filter-bar 가 아니라 .doc-filter 라 승격 대상에서 빠져 있었다 */
  .doc-filter input, .doc-filter select { height: 44px; }
  /* 생산실적 작성 폼의 인라인 입력(부서·작성자·특이사항·근무시간·시급·인원).
     한 줄에 여러 값을 늘어놓는 자리라 폭은 그대로 두고 높이만 확보한다. */
  .meta-line input, .meta-line select,
  .workcalc input, .workcalc select { height: 44px; }
  /* 페이지 머리 액션 영역의 입력(대시보드 기준일 등).
     [type=date] 를 함께 적는다 — 위 .page-head .actions input[type=date] 규칙(34px)이
     속성 선택자만큼 더 구체적이라, 타입 없는 선택자로는 이기지 못한다. */
  .page-head .actions input, .page-head .actions select,
  .page-head .actions input[type=date], .page-head .actions input[type=month] { height: 44px; }
  /* 짧은 라벨의 작은 버튼(조회·신규·양식)은 높이만 44 였고 폭이 43px 로 남았다.
     2.5.8 은 두 변 모두를 보므로 최소 폭도 함께 잠근다. */
  .btn.sm { min-width: 44px; }
  /* 안내문(.note) 안의 링크는 44 로 올리지 않는다 — 문장 중간에 박힌 인라인 링크라
     높이를 키우면 문단 줄 간격이 깨진다. 위쪽 .note a 규칙의 24px(WCAG 2.2 AA)이 여기서는 정답이다. */
  .card .card-head .tools input, .card .card-head .tools select { height: 44px; }
  /* 링크형 컨트롤에 히트 영역 부여 — 텍스트 높이만큼만 눌리던 것들 */
  .user-menu-item, .doc-item { min-height: 44px; }
  .note.banner .note-x { min-width: 44px; min-height: 44px; }
  .checks input[type=checkbox] { width: 24px; height: 24px; }
  /* 본문 안내 안의 텍스트 링크 — 글자 높이만큼만 눌리던 것들(실측 14~15px).
     .note 뿐 아니라 패널 안내(.panel-note)·설명(.desc)·힌트에도 링크가 들어간다. */
  .drill, .stage-flow a,
  .note a, .panel-note a, .desc a, .hint a, .empty a, .doc-empty a {
    min-height: 24px; display: inline-flex; align-items: center;
  }
}
