﻿/* ⛔ 템플릿 기본 폰트를 «지우지 말고 덮는다» — MudBlazor 테마 변수를 그대로 쓴다.
   실측(2026-08-29): 이 규칙 때문에 body 만 Helvetica Neue 로 떨어지고
   h1·MudBlazor 컴포넌트만 IBM Plex 스택이라 화면 안에서 폰트가 갈렸다. */
html, body {
    font-family: var(--mud-typography-default-family, 'IBM Plex Sans KR', sans-serif);
}

/* ⛔⛔ 이 값은 Blazor «프로젝트 템플릿»의 잔재였다 — 정본과 링크색이 달랐다.
   실측 2026-08-31 (같은 호스트 5100 에서 나란히 측정):
     Blazor /dms          → rgb(0,107,183)  = #006bb7   ← 템플릿 기본값
     Svelte 정본 /m/approvals → rgb(26,111,196) = #1a6fc4  = var(--vz-link-color)
   ⛔ 규칙 자체를 «지우면» 안 된다 — MudBlazor 가 `a{color:var(--mud-palette-text-primary)}` 를
      깔고 그게 global.css 보다 뒤라 링크가 본문색(#1f2f3e)으로 죽는다. 토큰으로 «덮는» 것이 답이다. */
a, .btn-link {
    color: var(--vz-link-color, #1a6fc4);
}

/* ⛔⛔ MudBlazor 의 전역 `body` 규칙이 정본 타이포를 덮는다 — 특이도가 (0,0,1) 로 «동률»이고
   App.razor 에서 MudBlazor.min.css 가 global.css «뒤»에 오기 때문이다.
   실측 2026-08-31 — body: 정본 line-height 1.5 / letter-spacing normal
                     ↔ Blazor 1.43 / 0.139px (둘 다 MudBlazor 기본값)
   ⛔⛔ font-size 는 «건드리지 않는다». 정본은 14.4px 이지만 JK 디자인 표준(2026-08-07 확정)이
      «본문 13px, 14.4px 아님» 이라 **Blazor 쪽이 맞고 정본이 낡은 것**이다.
      여기서 되돌리는 것은 «아무도 고르지 않은» 두 값뿐이다.
   ⛔ `--mud-typography-*` 변수를 바꾸지 마라 — MudBlazor 컴포넌트 내부 치수까지 흔든다. body 만 덮는다. */
body {
    line-height: var(--vz-body-line-height, 1.5);
    letter-spacing: normal;
}

/* ⛔⛔ .fs-11 · .fs-12 · .fs-13 · .fs-14 가 화면에서 «전부 14.4px» 으로 나오고 있었다.
   정본 테마 SCSS(JK.AI.Front/src/assets/scss/theme/_default.scss 12~20행)가 --vz-font-10~14 를
   전부 0.9rem 으로 눌러 놓았기 때문이다. 그 파일 주석은 "base: 0.9rem //13px" 라고 적혀 있지만
   루트(html)가 16px 라 0.9rem 은 13px 가 아니라 14.4px 다 — 오기다.
   결과: 이름은 다 다른데 크기는 하나고, 그것도 본문(.page-content = 13px)보다 한 단 크다.
   마크업 619곳이 이 클래스를 쓴다 — 「페이지마다 글자가 크다/작다」의 가장 큰 원인이었고,
   2026-09-01 브라우저로 직접 재서 확인했다(fs-11/12/13/14 전부 14.4px).
   ⛔ 15px 이상(--vz-font-15~48)은 원래 이름값과 맞아서 건드리지 않는다.
   ⛔ --vz-font-base 도 건드리지 않는다 — 본문은 global.css 의 .page-content 가 진다. */
:root,
:root[data-theme] {
    --vz-font-10: 10px;
    --vz-font-11: 11px;
    --vz-font-12: 12px;
    --vz-font-13: 13px;
    --vz-font-14: 14px;
    --vz-font-23: 23px;
}

/* ══ 글자 크기 스케일 — 앱 전체 공통 (2026-09-01 지시 「통일시켜줘」) ══════════════
   본문은 global.css 의 .page-content { font-size: 13px } 이다. 여기서 갈라지면 «페이지마다 글자가 다른» 화면이 된다.

     11px  미세 라벨(그룹명·카운트·아바타 이니셜)
     12px  보조 · 칩 · 뭇지 · 표 헤더(th)
     13px  ⭐ 본문 — 표 셀·입력칸·라벨·리스트항목이 전부 이 값이다
     14px  본문 한 단 위(소제목)
     15px  카드 헤더
     16 / 18 / 20 / 22px  제목

   ⛔⛔ 스코프 CSS·인라인 style 에 rem 으로 적지 마라. rem 은 html(16px) 기준이라
      0.9rem = 14.4px 가 되고, 그것은 본문(13px)보다 한 단 크다. 정본(Svelte)은 본문이 14.4px
      이던 시절의 값을 그대로 들고 왔고, 그 탓에 /dms 는 14.4px 306개 · 13px 57개 였다(실측).
   ⛔⛔ 전역 유틸 .fs-11 / .fs-12 / .fs-13 을 화면별 CSS 에서 다시 정의하지 마라.
      스코프 CSS 는 [b-xxxxx] 가 붙어 특이도가 높아서 전역을 이긴다 — 같은 fs-12 가 화면마다
      다른 크기가 된다(실제로 16개 파일에서 그러고 있었고 전부 제거했다).
   감사: node tools/parity/dom/font_audit.mjs — 페이지별 computed font-size 히스토그램. */

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ⛔ JK 표준 — 표 셀·라벨은 13px 이다(기존 프론트 .table td / .form-label 실측).
   MudDataGrid 는 Dense 에서 body2(12px)를 써서 기존 화면보다 한 단계 작게 나온다.
   ⛔ 테마 Typography 를 13px 로 올리면 «다른 곳»까지 커진다 — 표에만 좁혀서 맞춘다. */
.mud-table-cell,
.mud-table-cell.mud-table-cell-dense,
.mud-input-label,
.mud-form-control .mud-input-label {
    font-size: 13px;
}

/* ============================================================================
   공용 부품 (2026-08-31) — 리치 에디터 / 편집 그리드 / 조직도 피커
   ⛔⛔ 여기에 둔 이유: Blazor 스코프 CSS(.razor.css)는 «렌더 트리가 만든 요소»에만
      scope 속성을 붙인다. 에디터 본문은 JS 가, JkRichText 는 MarkupString 이 만들어서
      스코프 CSS 가 «조용히» 안 먹는다. 전역이 맞다.
   ============================================================================ */

/* ⭐ QA시트 #68·#77 — 「설명」·「승인/반려 의견」이 입력칸으로 안 보였다.
   원인은 여기 하나다: 리치 에디터가 «--vz-border-color»(#e9ebec)를 쓰는데 같은 화면의
   .form-control 은 «--vz-input-border-custom»(#ced4da)이라 두 배 진했다.
   ⛔ 새 색을 고르지 않는다 — .form-control 이 쓰는 «그 토큰»으로 맞추기만 한다.
   ⛔⛔ 2026-09-04 — 화면 CSS 두 벌(ApprovalRequestForm·ApprovalInbox 의 `::deep .jk-rte`)에
      같은 수정을 사본으로 넣었던 것을 여기로 올리고 «지웠다». 리치 에디터를 쓰는 화면은
      그 둘만이 아니다 — 화면마다 덧대면 한쪽만 늙는다.
   ⛔ 안쪽 구분선(.jk-rte-tools · .jk-rte-sep)은 «테두리»가 아니다 — --vz-border-color 유지. */
.jk-rte { border: 1px solid var(--vz-input-border-custom, #ced4da); border-radius: 4px; background: #fff; font-size: 13px; }
/* 포커스도 같은 규칙 — .form-control:focus 와 같은 토큰이다. */
.jk-rte:focus-within { border-color: var(--vz-primary-border-subtle); }
.jk-rte.is-disabled { background: #f3f6f9; }
.jk-rte-tools { display: flex; align-items: center; gap: 2px; padding: 4px 6px; border-bottom: 1px solid var(--vz-border-color, #e9ebec); flex-wrap: wrap; }
.jk-rte-btn { border: 0; background: transparent; border-radius: 3px; width: 26px; height: 26px; line-height: 1; color: #495057; cursor: pointer; font-size: 14px; }
.jk-rte-btn:hover:not(:disabled) { background: #eff2f7; }
.jk-rte-btn:disabled { color: #ced4da; cursor: default; }
.jk-rte-sep { width: 1px; height: 16px; margin: 0 4px; background: var(--vz-border-color, #e9ebec); }
.jk-rte-body { padding: 8px 10px; outline: none; line-height: 1.6; word-break: break-word; }
/* :empty 로는 안 된다 - 브라우저가 <br> 를 남긴다. JS 가 is-empty 를 붙인다. */
.jk-rte-body.is-empty::before { content: attr(data-placeholder); color: #adb5bd; pointer-events: none; }

.jk-rte-body p, .jk-rt p { margin: 0 0 .5em; }
.jk-rte-body p:last-child, .jk-rt p:last-child { margin-bottom: 0; }
.jk-rte-body h3, .jk-rt h3 { font-size: 15px; font-weight: 500; margin: .6em 0 .3em; }
.jk-rte-body blockquote, .jk-rt blockquote { margin: .5em 0; padding-left: 10px; border-left: 3px solid #e9ebec; color: #6c757d; }
.jk-rte-body ul, .jk-rte-body ol, .jk-rt ul, .jk-rt ol { margin: 0 0 .5em; padding-left: 1.4em; }
.jk-rte-body a, .jk-rt a { color: #1f6feb; }
.jk-rt { font-size: 13px; line-height: 1.6; word-break: break-word; }
.jk-rt-empty { font-size: 13px; color: #adb5bd; }

/* ⛔⛔ MudBlazor 의 «전역 button 리셋» 무력화 — 정본에 없던 규칙이라 화면이 어긋난다.
   경위(2026-08-31 실측): MudBlazor.min.css 가 요소 선택자 `button { justify-content: center }`
   를 깐다. 정본(SvelteKit)에는 MudBlazor 가 없어 이 규칙 자체가 존재하지 않는다.
   그래서 «display:flex 인 우리 버튼»들이 전부 가운데로 밀렸다 — /dms 한 화면에서만 13곳:
     segtabs-item 5(서브탭 활성 모양) · sidebar-section-header 4(핀 고정 등) ·
     filter-chip 2 · jkia-who · jkia-search-go
   ⛔ 배지(`ms-auto`)가 붙은 헤더는 margin:auto 가 여유공간을 먹어 «우연히» 정상으로 보였다.
      그래서 핀 0건일 때만 틀려 보이는 «데이터 의존» 증상이 됐다 — 재현이 들쭉날쭉했던 이유다.
   ⛔ 스코프 CSS 로 하나씩 막지 마라(두더지잡기). 정본에 없던 규칙을 걷어내는 것이 옳은 축이다.
   ⛔ MudBlazor 자기 컴포넌트는 건드리지 않는다 — `[class*="mud-"]` 로 제외한다.
   ⛔ 순서 의존: App.razor 에서 app.css 가 MudBlazor.min.css «뒤»에 온다. 그 순서를 바꾸면 죽는다. */
button:not([class*="mud-"]) {
    justify-content: normal;
}

/* ══ 정본 스타일 이식 — 그리드 영역 ═══════════════════════════════════════════
   출처: JK.AI.Front/src/lib/components/grid/CustomerGrid.svelte <style>(683~686행).
   ⛔⛔ 정본에서 Svelte «스코프» 안이라 global.css 에 «0건»이다. 그리드를 쓰는 화면이
      여럿이라 화면마다 베끼지 않고 여기 한 번만 둔다(실패 오버레이가 걸 자리이기도 하다). */
.grid-area {
    position: relative;
    width: 100%;
}

/* 빈 상태 오버레이 — 출처 정본 PartGrid.svelte <style> :1207~1216 (Svelte 스코프라 global.css 에 없다).
   ⛔⛔ 2026-09-07 PLM-20260907-11 — 부품 그리드는 «맨 위 임시 등록행»이 상시 1줄 있어서
      AG Grid 의 No-Rows 오버레이가 «한 번도» 뜨지 않는다. 그래서 「총 0 건」인데 화면엔 1행이 보였다.
      행을 지우는 대신 덮는 것이 정본의 길이다 — 등록 입구를 없애지 않으면서 결과가 0임을 말한다.
   ⛔ pointer-events:none — 오버레이 «아래»의 임시 행은 그대로 클릭·F2 로 쓸 수 있어야 한다.
   ⛔ top 은 헤더+임시행 높이만큼 띄운 값이다. 0 으로 바꾸면 헤더를 덮는다. */
.parts-empty {
    position: absolute;
    left: 0;
    right: 0;
    top: 96px;
    z-index: 2;
    padding: 24px 16px;
    text-align: center;
    pointer-events: none;
}

/* ══ 정본 스타일 이식 — AG Grid 테마 ═══════════════════════════════════════════
   출처: JK.AI.Front/src/lib/components/grid/CustomerGrid.svelte <style>(697~730행).
   ⛔⛔ 정본에서 Svelte 스코프 안이라 global.css 에 «0건»이다 — 이게 없으면 그리드가
      AG Grid «기본 테마»(14px)로 나와 앱의 다른 표(13px)와 크기가 어긋난다.
      2026-08-31 실측: Blazor 에 --ag-* 변수가 하나도 없었다. */
/* ⛔⛔ 선택자를 두 번 적는다 — app.css 가 ag-theme-alpine.min.css «앞»에 오므로 같은 특이도면 진다.
   실측(2026-08-31): 변수 블록이 밀려서 헤더 배경이 AG 기본값(#f8f8f8)으로 나왔다. */
/* ⛔⛔ 2026-09-01 지시 — 「헤더와 아래 ROW 배경이 같아 구분이 안 된다」.
     원인은 «줄무늬»였다: 홀수 행이 tertiary(#edf1f5) 인데 헤더도 tertiary 라 첫 행과 머리가 한 덩어리로 보였다.
     고침 두 가지 — ① 헤더를 한 단계 진한 회색(gray-300)으로 내리고 ② 줄무늬를 끈다.
     ⛔ 줄무늬를 되살리려면 헤더를 «그보다 더» 진하게 함께 올려라. 둘이 같은 톤이면 이 지적이 그대로 돌아온다.
     ⛔ 색은 Velzon 토큰에서만 고른다(새 색 정의 금지 — 디자인 표준). */
.ag-theme-alpine.ag-theme-alpine {
    /* ⛔ 2026-09-01 2차 지시 — 「좀 더 다른 색으로」. 중립 회색(gray-300)에서 «앱 주색 계열의 옅은 톤»으로 바꿨다.
       이 색은 이 파일이 이미 쓰던 계열이다(hover 0.06 · selected 0.10) — 새 색을 정의한 것이 아니다.
       ⛔ 0.14 인 이유: 선택 행(0.10)보다 «진해야» 머리줄과 선택 행이 안 헷갈린다. 내리지 마라. */
    --ag-header-background-color: rgba(64, 81, 137, 0.14);
    --ag-header-foreground-color: var(--vz-body-color);
    --ag-odd-row-background-color: transparent;
    --ag-row-hover-color: rgba(64, 81, 137, 0.06);
    --ag-selected-row-background-color: rgba(64, 81, 137, 0.1);
    /* ⛔⛔ 앱 표준을 따른다(2026-08-20 지시 "다른 페이지와 폰트 크기를 맞춰줘").
       기준은 _ia-typography.scss — 본문/.table td 13px · .table th 12px.
       ⛔ rem 로 적지 마라 — root 가 16px 이라 0.95rem 은 15.2px 다. */
    --ag-font-size: 13px;
    --ag-font-family: inherit;
    --ag-border-color: var(--vz-border-color);
    --ag-row-border-color: var(--vz-border-color);
}

/* ⛔⛔ AG Grid 테마가 행 폰트를 calc(var(--ag-font-size) + 1px) 로 건다.
   그래서 --ag-font-size 만 13px 로 낮춰도 셀은 14px 로 나온다(정본이 실측으로 밟은 함정).
   ⛔ --ag-font-size 를 12px 로 내려서 맞추지 마라 — 헤더·에디터까지 같이 줄어든다. */
/* ⛔⛔ 선택자를 «두 번» 적은 이유: App.razor 에서 app.css 가 ag-theme-alpine.min.css «앞»에 온다.
   같은 특이도(0,2,0)면 뒤에 온 AG 규칙이 이긴다 — 실측에서 행 폰트가 14px 로 나왔다.
   ⛔ 링크 순서를 바꿔서 해결하지 마라: 그러면 이 파일의 다른 재정의들이 AG 밑으로 깔린다. */
.ag-theme-alpine.ag-theme-alpine .ag-row { font-size: 13px; }

/* 머리와 몸통 사이 «선» — 색만으로 나누지 않는다(2026-09-01 지시).
   ⛔ AG 기본 --ag-border-color 는 행 구분선과 같은 연한 색이라 머리줄이 행 하나처럼 보인다. */
.ag-theme-alpine.ag-theme-alpine .ag-header {
    border-bottom: 1px solid var(--vz-gray-400, #ced4da);
}

.ag-theme-alpine.ag-theme-alpine .ag-header-cell-label {
    font-weight: 500;
    font-size: 12px;   /* = .table th (앱 표준) */
}

.ag-theme-alpine.ag-theme-alpine .ag-cell { line-height: 38px; }

/* 유효성 위반 셀 — 정본 validationCellClassRules 가 붙이는 클래스. */
.ag-theme-alpine.ag-theme-alpine .cell-invalid {
    border: 2px solid var(--vz-danger) !important;
    background: rgba(240, 101, 72, 0.05) !important;
}

/* ⛔ 2026-09-01 — 헤더 배경 재정의를 뺐다(위 공통 블록이 정한다). 크기만 남긴다. */
.quote-grid.quote-grid {
    width: 100%;
    height: 100%;
    min-height: 260px;
}

/* 견적 «목록» 그리드 — 정본 QuoteGrid.svelte <style>:979~984. 헤더 배경이 다른 그리드와 다르다. */
/* ⛔ 2026-09-01 — 헤더·줄무늬 재정의를 뺐다. 표는 앱 전체가 «한 모양»이어야 한다. */
.quote-list-grid.quote-list-grid {
    --ag-selected-row-background-color: rgba(64, 81, 137, 0.1);
}

/* ══ 정본 스타일 이식 — 유사 도면 «모달» 껍데기 ═══════════════════════════════
   출처: JK.AI.Front/src/lib/components/shared/SimilarDrawingsModal.svelte <style>(767~805행).
   ⛔⛔ 정본에서 Svelte 스코프 안이라 global.css 에 «0건»이다.
   ⛔ 여기(전역)에 두는 이유: 이 껍데기를 «두 곳»이 쓴다 —
      DMS 카드 우클릭 모달(JkDmsCardContextMenu)과 /dms/similar 라우트(Shell 전용창).
      화면 스코프 CSS 에 두면 한쪽에 한 줄도 안 걸린다.
   ⛔ 값(폭·그림자)을 바꾸지 마라.
   ⛔⛔ z-index 만은 정본 값(1095)을 못 쓴다 — 이 셸의 모달 층이 정본과 다르다(아래 「겹침 순서」).
      이 모달을 여는 진입로가 «모달 안의 우클릭 메뉴»(파일 선택 모달 → 카드 우클릭 → 유사 도면 검색)라
      1095 면 표준 모달(JkModal 2000) «뒤»로 깔린다(2026-09-03 QA #21: 「결재모달창에 숨겨져 나옴」).
      그래서 «메뉴가 여는 대화상자» 층(2200)에 둔다 — JkDialog·context-submenu 와 같은 칸이다. */
.sim-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 2200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}

.sim-dialog {
    background: var(--vz-card-bg, #fff);
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
    width: min(1100px, 94vw);
    max-height: 92vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Shell 전용창(/dms/similar) — 정본 794~805행. 화면을 꽉 채우고 모서리·그림자를 없앤다. */
.sim-backdrop.fullscreen {
    padding: 0;
    background: var(--vz-body-bg);
}

.sim-dialog.fullscreen {
    width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
    box-shadow: none;
}

/* ══════════════════════════════════════════════════════════════════════════
   화면 좌우 여백을 «한 벌»로 — 2026-09-01 사용자 지시
   ══════════════════════════════════════════════════════════════════════════
   실측: `page-content` 를 쓰는 109화면 중 65개가 그 아래에 `container-fluid` 를 한 겹 더 둔다.
   부트스트랩이 거기에 좌우 12px 를 넣어, 같은 셸인데 화면마다 내용 시작 위치가
   116px / 128px 로 갈렸다(휴지통·결재 전 화면·품목 카탈로그 등).

   ⛔ 65개 파일에서 래퍼를 걷어내지 않는다 — 그 편집은 본문 전체를 dedent 해야 해서
      되레 사고가 난다(2026-09-01 실제로 두 파일을 망가뜨렸다). 여백만 여기서 0 으로 맞춘다.
   ⛔ `.container-fluid` 자체를 건드리지 마라 — 모달·카드 안에서도 쓰는 클래스다.
      반드시 `page-content` «직속»일 때만이다.
   ⭐ 특이도 (0,2,0) 이라 로드 순서와 무관하게 부트스트랩을 이긴다. */
.page-content > .container-fluid {
    padding-left: 0;
    padding-right: 0;
}

/* 화면 제목 줄 오른쪽 액션(JkBreadCrumb Actions) — 버튼 하나 때문에 본문이 내려가지 않게 한다. */
.page-title-actions {
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* ══════════════════════════════════════════════════════════════════════════
   BOM 그리드 — 정본 BomGrid.svelte <style>(2197~2255) 이식
   ══════════════════════════════════════════════════════════════════════════
   ⛔⛔ 정본에서 Svelte <style> 스코프 안이라 global.css 에 «0건»이다.
      클래스 이름만 맞춰서는 모양이 안 나온다(2026-08-31 감사가 잡은 그 부류).
   ⛔ 헤더 배경이 다른 그리드와 «다르다» — 기본(흰색)이 아니라 tertiary 다.
      이 한 줄이 없어서 「헤더 색상이 빠졌다」는 지적이 나왔다(2026-09-01).
   ⛔ 선택자를 두 번 적는다 — app.css 가 ag-theme-alpine.min.css «앞»에 오기 때문. */
/* ⛔⛔ 2026-09-01 지시로 «헤더·줄무늬 재정의를 뺐다» — 그 둘이 같은 tertiary 라
   머리와 첫 행이 한 덩어리로 보였다. 이제 위 공통 블록 하나가 정한다(gray-300 머리 + 줄무늬 없음).
   ⛔ 여기에 --ag-header-background-color 를 다시 넣지 마라. 그 순간 이 그리드만 다시 흐려진다. */
.bom-grid.bom-grid {
    --ag-selected-row-background-color: rgba(64, 81, 137, 0.08);
}

/* 정본 2249~2255 — 가운데/오른쪽 정렬은 «셀이 flex 라» text-align 만으로 안 먹는다. */
.ag-theme-alpine.ag-theme-alpine .ag-cell.bom-cell-center,
.ag-theme-alpine.ag-theme-alpine .ag-cell.bom-cell-center .ag-cell-value {
    justify-content: center;
    text-align: center;
}

.ag-theme-alpine.ag-theme-alpine .ag-cell.bom-cell-right,
.ag-theme-alpine.ag-theme-alpine .ag-cell.bom-cell-right .ag-cell-value {
    justify-content: flex-end;
    text-align: right;
}

.ag-theme-alpine.ag-theme-alpine .ag-header-cell.bom-header-center .ag-header-cell-label { justify-content: center; }
.ag-theme-alpine.ag-theme-alpine .ag-header-cell.bom-header-right .ag-header-cell-label { justify-content: flex-end; }

/* ── BOM 툴바 / 상태바 — 정본 BomGrid.svelte(1889~1941) 크롬 ────────────────── */
.bom-toolbar {
    display: flex;
    align-items: center;
    /* ⛔ 2026-09-01 — 리비전·스냅샷·비교·엑셀이 이 한 줄로 들어왔다. wrap 이 없으면
       좁은 폭에서 「실행취소」가 툴바 밖으로 밀려 나간다. 줄바꿈을 빼지 마라. */
    flex-wrap: wrap;
    row-gap: .375rem;
    gap: .5rem;
    padding: .375rem .5rem;
    border: 1px solid var(--vz-border-color);
    border-bottom: 0;
    border-radius: 4px 4px 0 0;
    background: var(--vz-card-bg, #fff);
}

.bom-quick-filter {
    border: 1px solid var(--vz-border-color);
    border-radius: 4px;
    padding: 2px 8px;
    font-size: 13px;
    min-width: 240px;
    background: var(--vz-card-bg, #fff);
    color: var(--vz-body-color);
}

.bom-hint-bar,
.bom-statusbar {
    display: flex;
    align-items: center;
    font-size: 13px;
    background: var(--vz-tertiary-bg);
    color: var(--vz-secondary-color);
    padding: 2px 12px;
    border: 1px solid var(--vz-border-color);
    border-top: 0;
}

.bom-statusbar { border-radius: 0 0 4px 4px; }
.bom-statusbar i, .bom-hint-bar i { font-size: 13px; }

/* ── 그리드 우클릭 메뉴 (BOM) — 정본 BomGrid.svelte .ctx-menu ─────────────────
   ⛔ 정본에서 Svelte 스코프 안이라 global.css 에 0건이다. 이름만 맞춰선 안 나온다. */
.jk-ctx-backdrop { position: fixed; inset: 0; z-index: 2090; }

.jk-ctx-menu {
    position: fixed;
    z-index: 2091;
    min-width: 200px;
    padding: 4px 0;
    background: var(--vz-card-bg, #fff);
    border: 1px solid var(--vz-border-color);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, .16);
}

.jk-ctx-item {
    display: flex;
    align-items: center;
    width: 100%;
    border: 0;
    background: none;
    text-align: left;
    padding: 6px 12px;
    font-size: 13px;
    color: var(--vz-body-color);
}

.jk-ctx-item:hover { background: var(--vz-tertiary-bg); }
.jk-ctx-item.jk-ctx-danger { color: var(--vz-danger); }
.jk-ctx-divider { height: 1px; margin: 4px 0; background: var(--vz-border-color); }
.jk-ctx-hint { margin-left: auto; font-size: 12px; color: var(--vz-secondary-color); }

/* ── 부품 자동완성 에디터 — 정본 BomGrid.svelte <style>(2310~2340) 그대로 ─────────
   ⛔ 정본에서 :global 이지만 «컴포넌트 스코프 안»이라 global.css 에는 0건이다.
   ⛔⛔ 강조색을 «내가 고르지 마라». 처음에 --vz-tertiary-bg(연한 회색)로 넣었더니
      ↑↓ 로 이동은 하는데 «눈에 안 보였다»(2026-09-01 사용자 지적: 「위아래 이동이 안 된다」).
      정본은 파란 틴트 rgba(64,81,137,0.12) 다. */
.part-ac-editor {
    /* ⛔ 정본은 360px 인데 «좁다»는 지적(2026-09-01)으로 넓혔다 — 품번+품명이 한 줄에 들어가야 한다.
       ⛔ 고정폭으로 두는 이유: AG Grid 팝업이라 셀 폭을 따라가지 않는다. 화면이 좁으면 min() 이 줄인다. */
    width: min(560px, 90vw);
    background: var(--vz-secondary-bg);
    border: 1px solid #c4c8cf;
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
    padding: 6px;
}

.part-ac-input { width: 100%; margin-bottom: 4px; }
.part-ac-dropdown { max-height: 260px; overflow-y: auto; }

.part-ac-item {
    padding: 6px 10px;
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
}

.part-ac-item[data-highlighted="true"] { background: rgba(64, 81, 137, 0.12); }
.part-ac-item code { color: var(--vz-primary); font-family: monospace; font-size: 13px; }
.part-ac-item strong { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
/* 품번은 줄바꿈 없이 — 넓어진 폭을 품명이 쓰게 한다. */
.part-ac-item code { white-space: nowrap; flex-shrink: 0; }
.part-ac-price { color: var(--vz-success); font-size: 13px; margin-left: auto; }
.part-ac-empty { padding: 10px; color: var(--vz-secondary-color); font-size: 13px; text-align: center; }
.part-ac-hint { padding: 6px 10px; font-size: 12px; color: var(--vz-tertiary-color); }

/* 넣을 수 없는 후보 — ⛔ 지우지 않고 흐리게 남긴다. 사라지면 「왜 안 뜨지」로 헤맨다. */
.part-ac-item.is-disabled { cursor: not-allowed; opacity: .55; }
.part-ac-item.is-disabled[data-highlighted="true"] { background: none; }
.part-ac-item.is-disabled code { color: var(--vz-secondary-color); }

.part-ac-reason {
    margin-left: auto;
    font-size: 12px;
    color: var(--vz-danger);
    background: rgba(240, 101, 72, .10);
    border-radius: 3px;
    padding: 1px 5px;
    white-space: nowrap;
}


/* ══════════════════════════════════════════════════════════════════════════
   2026-09-01 사용자 지시 — ① 눌렀을 때 생기는 파란 테두리 ② BOM 셀 글자 선택
   ══════════════════════════════════════════════════════════════════════════ */

/* ① 마우스로 «누른» 것에는 포커스 테두리를 그리지 않는다.
   ⛔⛔ :focus 를 통째로 지우지 마라 — 키보드 사용자가 지금 어디 있는지 못 본다.
      :focus-visible 은 «키보드로 들어온 포커스»에만 참이라, 이 규칙은 클릭한 경우만 지운다.
   ⛔ Bootstrap 은 테두리를 outline 이 아니라 box-shadow 로 그린다(.btn:focus·.nav-link:focus·
      .form-select:focus). 둘 다 꺼야 파란 링이 사라진다. */
:focus:not(:focus-visible) {
    outline: 0 !important;
    box-shadow: none !important;
}

/* ⛔⛔ 위 리셋은 «포커스 링»만 지우려던 것인데 box-shadow 를 통째로 끈다 —
   선택 표시(.jk-sel)의 왼쪽 3px 강조 막대도 box-shadow(inset)라 같이 지워졌다(2026-09-04 지적).
   증상: 목록에서 한 건을 누르면 그 건의 막대가 «안 보이고», 다른 건을 누르는 순간
        앞 건이 포커스를 잃으며 막대가 «잠깐 나타났다가» 재렌더로 사라진다.
   ⛔ .jk-sel 쪽에 !important 를 더해도 소용없다 — 리셋(0,2,0)이 .jk-sel(0,1,0)보다 세다.
      그래서 «같은 조건 + 클래스»(0,3,0)로 되돌린다. 값은 _ia-typography.scss 의 정본과 같다.
   ⛔ 선택과 포커스는 다른 축이다. 포커스 링을 끄는 규칙이 선택 표시를 끄면 안 된다. */
.jk-sel:focus:not(:focus-visible) {
    box-shadow: inset 3px 0 0 var(--vz-primary, #1a6fc4) !important;
}

/* 탭·버튼은 클릭 직후 :focus 가 남아 파란 링이 «계속» 보인다 — 위 규칙이 그 자리를 덮는다.
   .nav-link 는 Bootstrap 이 :focus 에 border-color 까지 바꾸므로 되돌려 준다. */
.nav-link:focus:not(:focus-visible),
.nav-tabs .nav-link:focus:not(:focus-visible) {
    border-color: transparent;
}

.nav-tabs .nav-link.active:focus:not(:focus-visible) {
    border-color: var(--vz-border-color) var(--vz-border-color) var(--vz-card-bg);
}

/* ② BOM 그리드 — 셀을 클릭·드래그해도 글자가 «선택»되지 않는다.
   ⛔ 편집 중인 셀은 빼야 한다(.ag-cell-inline-editing) — 안 그러면 입력칸에서
      드래그 선택·더블클릭 단어 선택이 죽어 값을 고치기가 어려워진다. */
.bom-grid .ag-cell:not(.ag-cell-inline-editing),
.bom-grid .ag-header-cell {
    user-select: none;
    -webkit-user-select: none;
}

.bom-grid .ag-cell-inline-editing,
.bom-grid .ag-cell-inline-editing * {
    user-select: text;
    -webkit-user-select: text;
}


/* ══ BOM 편집기 높이 — 2026-09-01 지시 ══════════════════════════════════════
   「BOM 편집기 창에 스크롤이 생기지 않게 하고, 부품이 많아지면 그때부터 AG Grid 안에서만
     스크롤이 생기게. 기준은 브라우저 사이즈」

   ⛔⛔ 고정 520px 이었다. 그래서 창이 커도 표는 그대로고, 행이 조금만 넘쳐도
      «페이지»가 같이 스크롤됐다(그리드 스크롤 + 페이지 스크롤 두 겹).
   ⛔ 빼는 값 320px 의 근거(1600×1000 실측): 그리드 위 207 + 힌트바 27 + 상태바 27 + 카드/본문 여백.
      300 으로 뒀더니 문서가 1,016px 이 돼 «페이지 스크롤이 16px» 남았다 — 그래서 320 이다.
      화면 위쪽 구성을 바꾸면 이 값도 같이 재야 한다 — 짐작으로 고치지 마라.
   ⛔ min-height 를 빼지 마라. 낮은 창에서 표가 헤더만 남는다.
   ⛔ 내 작업(MyWorkBoard)의 BOM 그리드는 «그대로 520px» 이다 — 위 구성이 달라 같은 값을 쓸 수 없다. */
.grid-area.bom-grid-fill {
    /* 화면마다 그리드 «위»에 쌓인 높이가 다르다 — 그 값만 변수로 받는다.
       ⛔ 기본값 320px 은 «부품 상세» 기준이다. 다른 화면은 style="--jk-bom-offset:…" 로 준다. */
    height: calc(100vh - var(--jk-bom-offset, 320px));
    min-height: 320px;
}

/* ══ 문서 고르기 모달 — 정본 DmsDocPicker.svelte <style>(:627~719) «그대로» 이식 ═══════
   ⛔⛔ 정본에서 Svelte 스코프 안이라 global.css 에 «0건»이다. 그래서 부트스트랩 모달로
      흉내 내면 크기·비율·여백이 전부 달라진다(2026-09-01 지적). 선택자 이름만 jk- 를 붙였다.
   ⛔ 값을 «고르지» 마라 — 아래 숫자는 정본 값 그대로다(920×620 · 트리 180px · z-index 2000). */
.jk-doc-picker-backdrop {
    position: fixed; inset: 0; z-index: 2000;
    background: rgba(0, 0, 0, 0.45);
    display: flex; align-items: center; justify-content: center;
    overscroll-behavior: contain;
}

.jk-doc-picker-modal {
    background: var(--vz-card-bg, #fff);
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
    width: 920px; max-width: 94vw;
    height: 620px; max-height: 88vh;
    display: flex; flex-direction: column;
    overflow: hidden;
    position: relative;
}

.jk-doc-picker-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--vz-border-color);
}

.jk-doc-picker-search {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 16px;
    border-bottom: 1px solid var(--vz-border-color);
    color: var(--vz-secondary-color); font-size: 0.9rem;
}

.jk-doc-picker-search input { font-size: 0.9rem; min-width: 0; }
.jk-doc-picker-search .upload-btn { flex-shrink: 0; white-space: nowrap; padding: 4px 12px; }

.jk-doc-picker-drop-hint {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    padding: 10px; font-size: 0.9rem; color: var(--vz-primary);
    background: var(--vz-primary-bg-subtle, #dff0fa);
    border-bottom: 1px dashed var(--vz-primary);
}

.jk-doc-picker-body { flex: 1; display: flex; overflow: hidden; }

.jk-doc-picker-tree {
    width: 180px; min-width: 160px;
    border-right: 1px solid var(--vz-border-color);
    overflow-y: auto; padding: 6px 0;
    overscroll-behavior: contain;
}

.jk-picker-tree-node {
    display: flex; align-items: center; gap: 4px;
    padding: 5px 10px; font-size: 0.9rem;
    cursor: pointer; user-select: none; border-radius: 4px; margin: 1px 4px;
}

.jk-picker-tree-node:hover { background: var(--vz-light); }

.jk-picker-tree-node.active {
    background: var(--vz-primary-bg-subtle, #dff0fa);
    color: var(--vz-primary); font-weight: 500;
}

.jk-picker-tree-toggle-ph { width: 14px; flex-shrink: 0; }

.jk-picker-tree-toggle {
    width: 14px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    cursor: pointer; color: var(--vz-secondary-color);
}

.jk-picker-tree-toggle:hover { color: var(--vz-primary); }

.jk-picker-tree-count {
    font-size: 0.9rem; color: var(--vz-secondary-color); background: var(--vz-tertiary-bg);
    padding: 0 4px; border-radius: 8px; flex-shrink: 0;
}

.jk-doc-picker-list { flex: 1; display: flex; flex-direction: column; overflow: hidden; }

.jk-doc-picker-list-header {
    padding: 6px 12px;
    border-bottom: 1px solid var(--vz-border-color);
    background: var(--vz-light);
}

.jk-doc-picker-list-body {
    flex: 1; overflow-y: auto; padding: 4px 0;
    overscroll-behavior: contain;
}

.jk-doc-picker-item {
    display: flex; align-items: center; gap: 8px;
    padding: 5px 12px; cursor: pointer;
    border-bottom: 1px solid var(--vz-border-color);
    transition: background 0.1s;
}

.jk-doc-picker-item:hover { background: var(--vz-light); }
.jk-doc-picker-item.selected { background: rgba(64, 81, 137, 0.06); }

.jk-doc-picker-footer {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 16px;
    border-top: 1px solid var(--vz-border-color);
}

/* ══ 겹침 순서(z-index) — 2026-09-01 ═══════════════════════════════════════════
   ⛔⛔ 우클릭 메뉴가 «모달 안»에서도 떠야 한다. 표준 모달(JkModal)이 2000 인데
      정본에서 옮겨 온 우클릭 메뉴는 1060/1061 이라 모달 뒤로 깔렸다
      (2026-09-01 실측: 파일 선택 모달에서 메뉴가 판 아래로 잘려 나왔다).
   ⛔ 모달 z-index 를 내려서 맞추지 마라 — 그러면 모달이 셸(레일·상단바) 아래로 간다.
   ⛔ jk-shell.css 를 직접 고치지 마라 — 그 파일은 생성물이다(scripts/gen-blazor-shell-css.py).
      여기서 «덮는다». app.css 가 그 뒤에 오므로 같은 특이도로 이긴다.
   층: 셸 < 모달(2000) < 상세 오버레이(2050 .detail-overlay — jk-shell.css:346)
       < 우클릭 메뉴(2100) < 메뉴가 여는 작은 대화상자(2200 — JkDialog · 유사도면 .sim-backdrop)
       < 확인창(2210 JkConfirmHost) < «모달 위의 모달»(2300 — 조직도 피커 JkOrgPicker 등)
       < 토스트(2400 — 언제나 맨 위. 값은 Components/Shared/Toast/JkToastHost.razor.css 에 있다)
   ⛔ 새 겹침 층을 만들 때 이 목록에 «적어라». 숫자를 각자 고르기 시작하면 다시 뒤로 숨는 것이 생긴다. */
.context-menu-backdrop { z-index: 2100; }
.context-menu { z-index: 2101; }
.context-submenu { z-index: 2102; }


/* ══ 경고 버튼 글자색 — 2026-09-01 지시 ═══════════════════════════════════════
   Velzon 의 --vz-warning(#f7b84b) 위에 부트스트랩 기본 대비 계산이 «검은 글자»를 얹는데,
   그 조합은 화면에서 잘 안 읽힌다(사용자 지적). 흰 글자로 고정한다.
   ⛔ soft/outline 변형(.btn-soft-warning · .btn-outline-warning)은 «배경이 연해서» 흰 글자면 사라진다 —
      여기서 건드리는 것은 «꽉 찬» .btn-warning 하나뿐이다.
   ⛔ --vz-warning 색 자체를 바꾸지 마라(뱃지·알림·아이콘이 같은 토큰을 쓴다). */
.btn-warning,
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active,
.btn-warning:disabled,
.btn-warning.disabled,
.btn-check:checked + .btn-warning,
.btn-check:active + .btn-warning,
.btn-warning.show {
    color: var(--vz-white, #fff);
}


/* ══ 모달 뒷배경(딤) — 2026-09-02 지시 ════════════════════════════════════════
   ⛔⛔ `.modal-backdrop-custom` 은 정본(Svelte)에서 «화면마다» <style> 안에 있던 클래스다.
      Blazor 로 옮기면서 화면별 scoped CSS 로 흩어졌고, 옮기다 빠진 화면(영업 견적·고객)에서는
      마크업은 있는데 «규칙이 없어» 딤이 아예 안 보였다(2026-09-02 실측: position:static).
   ⛔ 여기 있는 것은 «바닥값»이다. 화면 scoped CSS 가 같은 이름으로 z-index 를 달리 주면
      (모달 위의 모달 등) 그쪽이 이긴다 — scoped 선택자에 속성 한 개가 더 붙기 때문이다.
   ⛔ 값(rgba .45)을 새로 고르지 마라 — 모달 표준 껍데기(JkModal .jk-modal-backdrop)와 같은 값이다. */
.modal-backdrop-custom {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1050;
}

/* ══ 경고 배지 글자 대비 — 2026-09-04 PLM-20260903-19 ═════════════════════════
   측정: `.badge.bg-soft-warning.text-warning` 글자 #cf8a2b / 배경 #fdf1db = «2.56»,
         `.badge.bg-subtle-warning.text-warning` 흰 바탕 위 = 2.87,
         `.badge.bg-warning` 흰 글자 / 배경 #cf8a2b = 2.87. 셋 다 3.0 미만이라 «안 읽힌다».
   고침: 글자를 짙은 앰버 #8a5a0b 로 내린다 → 5.29 · 5.92 (WCAG AA 4.5 통과).
         꽉 찬 `.bg-warning` 은 «글자가 흰색»이라 글자를 어둡게 할 수 없다 —
         배경을 같은 짙은 앰버로 내려 흰 글자 대비를 5.92 로 만든다.
   ⛔ `--vz-warning` 토큰 자체를 바꾸지 마라 — 아이콘·차트·테두리가 같은 값을 쓴다.
      여기서 «배지에만» 건다(.badge 를 붙여 특이도를 올렸다).
   ⛔ 다른 색(success/danger/info)은 건드리지 않는다 — 신고된 세 화면에서 4.5 미만인 배지는 warning 계열뿐이었다(같은 프로브 실측).
   ⛔ `!important` 는 부트스트랩 유틸(.text-warning{color:…!important})을 이기기 위한 것이다.
      선택자 특이도가 더 높아 이쪽이 이긴다. */
.badge.bg-soft-warning,
.badge.bg-soft-warning.text-warning,
.badge.bg-subtle-warning,
.badge.bg-subtle-warning.text-warning,
/* ⛔ 2026-09-04 후속 — 이 리포의 «지배적» 클래스는 부트스트랩 표기인 `bg-warning-subtle` 다.
   위 두 개(bg-soft-warning · bg-subtle-warning)만 걸면 실제 배지 대부분이 그대로 저대비로 남는다.
   `bg-warning-subtle` 포함 — 실측 88곳(JK.AI.Blazor .razor/.cs 52파일, 그중 .badge 동반 55곳).
   ⛔ 글자색만 내린다 — 배경(bg-warning-subtle 의 옅은 앰버)은 건드리지 않는다. */
.badge.bg-warning-subtle,
.badge.bg-warning-subtle.text-warning,
/* ⛔ PLM-20260903-44 (2026-09-07) — 결재 모니터링의 «타입» 배지는 채움이 아니라 테두리형이다
   (ApprovalAdminLabels.RequestTypeBadgeClass). 배경이 흰색이라 부트스트랩 기본 text-warning-emphasis
   (#997404)는 대비 4.0 으로 AA(4.5) 미만이다 — 같은 짙은 앰버로 내린다. */
.badge.border-warning {
    color: #8a5a0b !important;
}

.badge.bg-warning {
    background-color: #8a5a0b !important;
    color: var(--vz-white, #fff) !important;
}

/* ══════════════════════════════════════════════════════════════════════════
   카드 표면 — MES(`/master`) 규격을 «공용»으로 (2026-09-04 지시)

   왜: 두 제품이 카드를 다르게 그리고 있었다. 값의 출처는 MES 정본 한 곳이다
       (JK.AI.MES/src/JK.AI.MES.Api/wwwroot/app.css 403~412행):
         .card { background:#fff; border:1px solid #edf1f5; border-radius:10px; padding:20px }
         .card h3 { font-size:18px; font-weight:400 }
       MES 는 카드를 «한 면»으로 본다 — 머리와 몸 사이에 구분선이 없고 여백을 카드가 정한다.
       PLM(Velzon/Bootstrap)은 .card-header 가 아래 테두리를 긋고 그림자를 얹는다.

   범위: 이 파일은 Velzon 뒤에 로드되므로 앱 «전체»에 적용된다.
       실측(2026-09-04): .card 를 쓰는 화면 파일 114개 · card-header 196곳 · card-body 381곳.
   ⛔ 화면별 scoped CSS 에서 .card 를 다시 정의한 곳이 8개 있다 — 그쪽이 이 값을 덮는다(의도).
      새로 덮지 마라. 카드 모양을 바꿀 일이 생기면 «여기»를 고친다.

   ⛔⛔ 부트스트랩 여백 유틸리티(`py-2`·`p-0` 등)는 `!important` 라 이 규칙을 이긴다.
      실측: card-header 196곳 중 43곳이 py-/pt-/pb- 를 달고 있어 «세로 여백만» 옛 값으로 남는다.
      그건 CSS 로 이길 대상이 아니라 마크업에서 «지울» 대상이다(결재함에서 그렇게 했다).
      ⛔ 여기서 `!important` 로 맞불을 놓지 마라 — p-0 로 «일부러» 여백을 없앤 66곳이 같이 깨진다.
   ══════════════════════════════════════════════════════════════════════════ */
.card {
    border: 1px solid #edf1f5;
    border-radius: 10px;
    box-shadow: none;
}

.card-header {
    background: transparent;
    border-bottom: 0;
    padding: 20px 20px 14px;
}

.card-body {
    padding: 20px;
}

.card-footer {
    background: transparent;
    border-top: 1px solid #f2f5f8;
}

/* 카드 «안»의 제목 — MES 규격 18px/400. ⛔ 화면 제목(h1·페이지 헤더)은 건드리지 않는다. */
.card h3,
.card .card-title {
    font-size: 18px;
    font-weight: 400;
}

/* ══════════════════════════════════════════════════════════════════════════
   Blazor 회로 오류 배너 (#blazor-error-ui) — «전역» 정의. 2026-09-05 (PLM-20260905-01)

   ⛔⛔ 이 규칙은 스코프 CSS 로 두면 안 된다. 마크업이 «레이아웃마다 하나씩» 있어서다:
        Layout/MainLayout.razor:310 · Pages/AccountDesk/AuthPageLayout.razor:20 ·
        Pages/MiscDesk/PublicQuoteLayout.razor:30.
      스코프 CSS 는 `#blazor-error-ui[b-xxxxx]` 로 컴파일돼 «자기 컴포넌트가 그린 것»에만 붙는다.
      그래서 규칙을 가진 MainLayout 밖(로그인 화면)에서는 아무 규칙도 안 걸려
      div 기본값(display:block · position:static)으로 «오류가 없는데도» 문서 흐름에 남았다
      (실측 2026-09-05 /login: display:block · position:static · rect.y=768 · docScrollH 790).
      같은 결함을 견적 출력 화면에서 2026-09-03 에 한 번 고쳤는데(PublicQuoteLayout.razor.css)
      그때는 «그 화면만» 덮었다 — 그래서 로그인에서 다시 나왔다. 이번엔 정의를 한 곳으로 올린다.
   ⛔ 마크업을 지워서 풀지 마라 — 회로가 끊겼을 때 사용자에게 아무 말도 못 하게 된다.
   ⛔ 값은 Blazor 템플릿 원본과 같다(MainLayout.razor.css:79~98 과 동일). 새로 고르지 않는다.
   ⛔ display:none 이 기본이고, 오류가 나면 blazor.web.js 가 «인라인» display:block 을 넣는다 —
      인라인이 이 규칙을 이기므로 그때만 보이고, position:fixed 라 하단 고정 배너가 된다.
      여기에 !important 를 붙이면 «진짜 오류가 나도 안 보이는» 배너가 된다. 붙이지 마라.
   ⛔ 각 레이아웃의 스코프 사본은 남겨 둔다(같은 값이라 충돌하지 않는다) —
      한 벌로 줄이는 정리는 이 결함의 범위가 아니다.
   ══════════════════════════════════════════════════════════════════════════ */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

/* 인쇄물(견적서 등)에는 배너가 찍히지 않는다 — PublicQuoteLayout.razor.css 가 자기 화면에서
   같은 규칙을 갖고 있었다. 전역으로 올려 «모든» 인쇄 경로에서 같게 만든다. */
@media print {
    #blazor-error-ui {
        display: none !important;
    }
}

/* ⛔⛔ 2026-09-05 PLM-20260905-04 — 「사용자 디렉터리에서 못 푼 ID」 표시.
   등록자·담당자 칸에 사람 이름(데모관리자1)과 시드 표식(demo-seed)이 «같은 글씨로» 섞여
   둘 다 이름처럼 읽혔다. 값을 지우거나 「시스템」으로 바꾸지 않는다 — 그건 추측이다.
   원본 값은 그대로 두고 글씨만 흐리게 해서 «이름이 아님»을 보인다.
   ⛔ 색은 새로 고르지 않는다 — 화면 전역이 쓰는 --vz-secondary-color 그대로다. */
/* ⛔⛔ 선택자를 `.ag-cell.jk-user-raw` 로 «올려» 쓴다 — AG Grid 스타일시트가 app.css «뒤»에
   로드돼 같은 특정도(.ag-cell)면 그쪽이 이긴다. 실측: color 가 #646a72 로 안 바뀌고
   rgb(73,80,87) 그대로였다(2026-09-05 실물 확인에서 잡음).
   ⛔ font-style:italic 을 쓰지 않는다 — 빈 칸의 「-」이 이미 기울임이라 «빈 칸과 구분이 안 된다».
   ⛔ 색은 여기서 주지 않는다 — 열 정의의 cellStyle 이 인라인으로 박혀 CSS 가 진다.
      색은 JkAgGrid.razor.js 의 user 포매터가 cellStyle 로 얹는다. 여기는 «글꼴»만 맡는다. */
.ag-cell.jk-user-raw {
    font-family: var(--bs-font-monospace, ui-monospace, SFMono-Regular, Menlo, monospace);
}
