/*
 * 우리 화면 규약. INSPINIA 템플릿 CSS(app.css) 뒤에 실려 값만 덮는다.
 *
 * 왜 SCSS(_variables.scss)가 아니라 여기인가 —
 * 서버에 node/npx 가 없어 sass 재빌드를 할 수 없다. app.css 는 템플릿에서 나온
 * 그대로 두고, 우리가 바꾸는 몇 값만 이 파일이 갖는다. 손으로 고칠 수 있고
 * 업로드도 이 파일 하나면 끝난다.
 *
 * 색·간격의 큰 축은 여전히 _variables.scss 다. 여기에는 빌드 없이 못 넘어가는 것만 둔다.
 * 규칙이 늘어나 이 파일이 두꺼워지면 그때 SCSS 로 옮기고 한 번 빌드한다.
 *
 * 주의: 이 빌드의 부트스트랩 CSS 변수 접두사는 --bs- 가 아니라 --theme- 다.
 */

/* ==========================================================================
 * 화면의 인상을 정하는 값들
 *
 * 템플릿에서 나온 그대로 쓰면 '부트스트랩 관리자 템플릿'으로 읽힌다.
 * 마크업(.wrapper · .sidenav-menu · .card)은 그대로 두고 값만 우리 것으로 덮는다.
 * 아래 다섯 덩어리가 그 값이다 — 글자 크기 · 제목 · 표면 · 표 · 강조.
 * ========================================================================== */

/* --------------------------------------------------------------------------
 * 1. 글자 크기 단계
 *
 * 템플릿 기본은 본문 13px 인데, 페이지 제목까지 13px 이라 화면에 크기 단계가
 * 사실상 없었다. 굵기와 회색조로만 구분하면 눈이 층을 못 읽고 전체가 평평해 보인다.
 *
 * 본문을 14px 로 올려 네 단계를 만든다 — 22 / 16 / 14 / 13.
 * 표는 13px 로 남긴다. MES 는 한 화면에 들어가는 줄 수가 곧 쓸모라,
 * 목록까지 키우면 스크롤이 늘어 오히려 일이 느려진다.
 * 보조 설명에 쓰는 fs-13 은 이제 '본문보다 작은 글자'가 되어 제 역할을 한다.
 * -------------------------------------------------------------------------- */
:root {
    --theme-body-font-size: 0.875rem; /* 14px */
}

.table {
    font-size: 0.8125rem; /* 13px — 목록 밀도는 지킨다 */
}

/* --------------------------------------------------------------------------
 * 2. 페이지 제목
 *
 * 템플릿은 .page-main-title 을 font-size-sm(13px) + uppercase 로 그린다.
 * 화면에서 가장 중요한 글자가 본문과 같은 크기였다.
 * uppercase 는 한글에 아무 효과가 없어 '작은 굵은 글씨'만 남는다.
 *
 * 제목을 둘러싼 회색 띠도 걷는다. 층을 나누는 일은 여백이 하고,
 * 띠·테두리가 겹칠수록 '상자 안의 상자'가 되어 템플릿 냄새가 난다.
 * -------------------------------------------------------------------------- */
.page-main-title {
    font-size: 1.375rem !important; /* 22px */
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
    text-transform: none;
}

.page-title-head {
    min-height: 0;
    margin: 0 0 1.25rem;
    padding: 0;
    background-color: transparent;
    border-bottom: 0;
}

/* --------------------------------------------------------------------------
 * 3. 표면 — 카드의 모서리 · 테두리 · 그림자
 *
 * 템플릿은 모든 모서리가 4.8px 하나이고, 카드 그림자가 투명도 3% 라 사실상 안 보인다.
 * 그래서 층 구분을 전부 '선'이 하고 있었다 — 그게 상자 안의 상자로 보이는 이유다.
 *
 * 선을 빼고 그림자로 띄운다. 모서리는 두 단계로 벌린다 —
 * 카드 10px / 버튼·입력·배지 6px. 같은 반경이면 크기 감각이 안 생긴다.
 *
 * 카드의 테두리 '두께'는 남기고 '색'만 지운다. 재고 미달·지연처럼
 * .border-danger 로 강조하는 카드가 있는데, 두께를 0 으로 만들면 그 강조가 사라진다.
 * -------------------------------------------------------------------------- */
:root {
    --theme-border-radius: 0.375rem; /* 6px — 버튼 · 입력 · 배지 */
}

.card {
    --theme-card-border-radius: 0.625rem; /* 10px */
    --theme-card-border-color: transparent;

    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 1px 3px rgba(15, 23, 42, 0.07);
}

/* 어두운 배경에서는 그림자가 안 보인다. 대신 테두리를 아주 옅게 살린다. */
[data-bs-theme="dark"] .card {
    --theme-card-border-color: rgba(148, 163, 184, 0.16);

    box-shadow: none;
}

/* --------------------------------------------------------------------------
 * 색칠된 행의 hover
 *
 * 지연·미달·불합격 행은 table-danger 로 옅은 분홍을 깐다. 그런데 마우스를 올리면
 * 부트스트랩이 그 색을 검정과 섞어 hover 색을 만들어서, **옅은 분홍이 탁한 중간톤으로
 * 뒤집히고 글자가 흰색으로 바뀐다.**
 *
 *   평상  #fcdada + 어두운 글자 → 13.75:1
 *   hover #91828b + 흰 글자    →  3.64:1   ← 읽기가 더 어려워진다
 *
 * 색조까지 바뀌어(분홍 → 회보라) 같은 행인지도 잠깐 헷갈린다.
 * 마우스를 올리는 이유는 그 줄을 '더 잘 보려고'인데 반대로 가는 셈이다.
 *
 * 그래서 **같은 색조로 한 단계만 진하게** 하고 글자색은 건드리지 않는다.
 * 어느 줄에 있는지는 밝기 차이만으로 충분히 보인다.
 * -------------------------------------------------------------------------- */
.table-danger {
    --theme-table-hover-bg: #f8c9c9;
    --theme-table-hover-color: var(--theme-table-color);
}

.table-warning {
    --theme-table-hover-bg: #fbedc9;
    --theme-table-hover-color: var(--theme-table-color);
}

.table-success {
    --theme-table-hover-bg: #c6e9dd;
    --theme-table-hover-color: var(--theme-table-color);
}

.table-info {
    --theme-table-hover-bg: #c6e2f6;
    --theme-table-hover-color: var(--theme-table-color);
}

.table-primary {
    --theme-table-hover-bg: #ccd9f8;
    --theme-table-hover-color: var(--theme-table-color);
}

/* 다크 모드는 반대로 — 어두운 바탕에서 한 단계 밝게 한다. */
[data-bs-theme="dark"] .table-danger  { --theme-table-hover-bg: #4a2020; }
[data-bs-theme="dark"] .table-warning { --theme-table-hover-bg: #4a3a15; }
[data-bs-theme="dark"] .table-success { --theme-table-hover-bg: #16402f; }
[data-bs-theme="dark"] .table-info    { --theme-table-hover-bg: #16374a; }
[data-bs-theme="dark"] .table-primary { --theme-table-hover-bg: #1e2f52; }

/* --------------------------------------------------------------------------
 * 4. 표 머리 — 템플릿 기본(table-light 회색 면)을 그대로 둔다
 *
 * 한때 회색을 빼고 밑줄 하나로 가르는 안을 넣었다가 되돌렸다.
 * 열이 20~30개인 표(수불부 · 생산일보 · 불량분석)가 많은 화면이라,
 * 머리에 면이 있는 편이 가로로 훑을 때 기준선 노릇을 한다.
 * 다시 빼고 싶어지면 아래 두 규칙을 되살리면 된다 —
 * 셀 배경은 --theme-table-bg 와 inset box-shadow 두 경로로 칠해지므로 둘 다 꺼야 한다.
 *
 *   .table > thead.table-light { --theme-table-bg: transparent;
 *                                --theme-table-accent-bg: transparent; }
 *   .table > thead > tr > th   { border-bottom: 2px solid var(--theme-border-color); }
 * -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
 * 5. 상태 배지
 *
 * 크기 — 부트스트랩 기본값 0.75em 은 부모 글자를 따라간다. 표 안에서 9.75px 까지
 * 내려가 읽히지 않았다. 상태 배지는 어디에 놓이든 같은 크기여야 하므로 rem 으로 못 박는다.
 *
 * 색 — `bg-{색}-subtle text-{색}` 조합의 대비를 재 보면 13px 기준(4.5:1)에 크게 못 미쳤다.
 *   warning 1.91:1 · success 2.19:1 · danger 3.11:1 · primary 4.20:1
 * 원인은 팔레트가 아니라 쓰임이다 — #10b981 · #f59e0b 는 '채우기용 중간톤'이라
 * 글자색으로 쓸 밝기가 아니다. 부트스트랩의 text-*-emphasis 로 바꿔도 여전히 미달이다.
 *
 * 그래서 **배지 글자에만** 한 단계 진한 값을 쓴다. 채우기용 $success · $warning 은
 * 그대로 두므로 팔레트를 건드리지 않는다. 아래 값은 각 subtle 배경 위에서 4.5:1 을 넘긴다.
 * -------------------------------------------------------------------------- */
.badge {
    --theme-badge-font-size: 0.8125rem; /* 13px */
    --theme-badge-padding-x: 0.5em;
}

.badge.text-success { color: #046c4e !important; } /* 5.51:1 */
.badge.text-warning { color: #92400e !important; } /* 6.71:1 */
.badge.text-danger  { color: #b91c1c !important; } /* 5.35:1 */
.badge.text-primary { color: #1d4ed8 !important; } /* 6.31:1 */
.badge.text-info    { color: #0369a1 !important; } /* 5.09:1 */

/* 취소·비활성 배지(text-bg-light text-muted)는 회색 위 회색이라 3.86:1 이었다.
   '지금은 중요하지 않다'는 뜻은 남기되 읽히기는 해야 하므로 한 단계만 내린다. */
.badge.text-bg-light.text-muted {
    color: #475569 !important; /* 6.11:1 */
}

/* 채운 배지·버튼도 같은 이유로 흰 글자 대비가 모자랐다(success 2.54 · warning 2.15 · info 2.77).
   면 색을 한 단계 내려 흰 글자가 읽히게 한다.

   **버튼은 배경을 직접 덮지 않고 변수를 바꾼다.** background-color 를 !important 로 박으면
   hover · active · disabled 가 전부 같은 색으로 굳어 눌리는 느낌이 사라진다.
   테두리 버튼(btn-outline-*)의 hover 배경도 같은 변수를 타므로 함께 잡힌다. */
.btn-success {
    --theme-btn-bg: #047857;
    --theme-btn-border-color: #047857;
    --theme-btn-hover-bg: #036249;
    --theme-btn-hover-border-color: #036249;
    --theme-btn-active-bg: #036249;
    --theme-btn-active-border-color: #036249;
    --theme-btn-disabled-bg: #047857;
    --theme-btn-disabled-border-color: #047857;
}

.btn-outline-success {
    --theme-btn-color: #047857;
    --theme-btn-border-color: #047857;
    --theme-btn-hover-bg: #047857;
    --theme-btn-hover-border-color: #047857;
    --theme-btn-active-bg: #047857;
    --theme-btn-active-border-color: #047857;
}

.btn-warning {
    --theme-btn-color: #fff;
    --theme-btn-bg: #b45309;
    --theme-btn-border-color: #b45309;
    --theme-btn-hover-color: #fff;
    --theme-btn-hover-bg: #96450a;
    --theme-btn-hover-border-color: #96450a;
    --theme-btn-active-color: #fff;
    --theme-btn-active-bg: #96450a;
    --theme-btn-active-border-color: #96450a;
    --theme-btn-disabled-color: #fff;
    --theme-btn-disabled-bg: #b45309;
    --theme-btn-disabled-border-color: #b45309;
}

.btn-outline-warning {
    --theme-btn-color: #b45309;
    --theme-btn-border-color: #b45309;
    --theme-btn-hover-color: #fff;
    --theme-btn-hover-bg: #b45309;
    --theme-btn-hover-border-color: #b45309;
    --theme-btn-active-bg: #b45309;
    --theme-btn-active-border-color: #b45309;
}

.btn-info {
    --theme-btn-bg: #0369a1;
    --theme-btn-border-color: #0369a1;
    --theme-btn-hover-bg: #025683;
    --theme-btn-hover-border-color: #025683;
    --theme-btn-active-bg: #025683;
    --theme-btn-active-border-color: #025683;
    --theme-btn-disabled-bg: #0369a1;
    --theme-btn-disabled-border-color: #0369a1;
}

.btn-danger {
    --theme-btn-bg: #dc2626;
    --theme-btn-border-color: #dc2626;
    --theme-btn-hover-bg: #b91c1c;
    --theme-btn-hover-border-color: #b91c1c;
    --theme-btn-active-bg: #b91c1c;
    --theme-btn-active-border-color: #b91c1c;
    --theme-btn-disabled-bg: #dc2626;
    --theme-btn-disabled-border-color: #dc2626;
}

/* 채운 배지는 상태를 나타낼 뿐 눌리지 않는다. 배경을 그대로 덮어도 잃는 것이 없다. */
.text-bg-success { background-color: #047857 !important; color: #fff !important; }
.text-bg-warning { background-color: #b45309 !important; color: #fff !important; }
.text-bg-info    { background-color: #0369a1 !important; color: #fff !important; }
.text-bg-danger  { background-color: #dc2626 !important; color: #fff !important; }

/* 다크 배경에서는 반대로 밝아야 읽힌다. 진하게 내린 값을 되돌린다. */
[data-bs-theme="dark"] .badge.text-success { color: #34d399 !important; }
[data-bs-theme="dark"] .badge.text-warning { color: #fbbf24 !important; }
[data-bs-theme="dark"] .badge.text-danger  { color: #f87171 !important; }
[data-bs-theme="dark"] .badge.text-primary { color: #60a5fa !important; }
[data-bs-theme="dark"] .badge.text-info    { color: #38bdf8 !important; }

/* --------------------------------------------------------------------------
 * 인쇄
 *
 * 공장에서는 아직 종이가 돈다 — 작업지시를 뽑아 현장에 들고 가고, 수불부를 인쇄해
 * 회계와 대조한다. 그런데 그냥 인쇄하면 사이드바·상단바·버튼이 같이 찍혀
 * 정작 표가 한쪽으로 밀리고 두 장이 된다.
 *
 * 전용 인쇄 화면을 따로 만들지 않는다. 화면마다 인쇄본을 두면 화면이 바뀔 때
 * 인쇄본이 뒤처져 '화면과 다른 종이'가 나온다 — 그게 더 나쁘다.
 * 대신 지금 보고 있는 화면에서 **조작하는 것만 걷어낸다.** 무엇이 찍힐지는
 * 화면에 보이는 그대로다.
 *
 * 브라우저의 인쇄 대화상자에서 '배경 그래픽'을 켜야 배지·표 머리의 색이 나온다.
 * 기본값이 꺼짐이라, 색 없이도 읽히도록 표에 테두리를 준다.
 * -------------------------------------------------------------------------- */
@media print {
    /* 조작하는 것은 종이에서 의미가 없다. */
    .sidenav-menu,
    .app-topbar,
    .page-title-head .btn,
    .card-header .btn,
    .card-header form,
    .btn,
    .pagination,
    .nav-pills,
    .dropdown-menu,
    .alert-dismissible .btn-close,
    #theme-settings-offcanvas,
    .sf-topbar {
        display: none !important;
    }

    /* 사이드바가 빠졌으니 본문이 그 자리를 쓴다. */
    .wrapper,
    .content-page,
    .page-content,
    .content {
        margin: 0 !important;
        padding: 0 !important;
        width: 100% !important;
    }

    /* 종이에는 그림자·둥근 모서리가 인쇄 잉크만 먹는다. */
    .card {
        border: 1px solid #999 !important;
        box-shadow: none !important;
        break-inside: avoid;
    }

    /* 표는 색을 못 써도 줄이 구분돼야 한다. */
    .table > :not(caption) > * > * {
        border-color: #999 !important;
    }

    .table thead {
        /* 여러 장으로 넘어가도 머리글이 따라간다. */
        display: table-header-group;
    }

    .table tr,
    .stat-row > [class*="col-"] {
        break-inside: avoid;
    }

    /* 가로 스크롤 영역은 종이에서 잘린다. 폭에 맞춰 접는다. */
    .table-responsive {
        overflow: visible !important;
    }

    a[href]::after {
        /* 링크 주소를 뒤에 붙이지 않는다 — 표 안의 코드 링크가 전부 URL 로 늘어난다. */
        content: none !important;
    }

    body {
        background: #fff !important;
        font-size: 11pt;
    }

    @page {
        margin: 12mm;
    }
}

/* --------------------------------------------------------------------------
 * 입력 칸의 hover · focus 테두리
 *
 * 템플릿은 두 상태 모두 테두리를 --theme-dark-border-subtle(#334155, slate-700)로 바꾼다.
 * 평소 테두리가 #cbd5e1(slate-300)이라 한 번에 여섯 단계를 건너뛴다 — 검은 선이 그어진 것처럼 보인다.
 *
 * 검색창처럼 input-group 으로 묶인 자리에서는 그게 더 두드러진다.
 *  - 색이 바뀌는 것은 .form-control 뿐이고 앞의 돋보기 칸(.input-group-text)은 연한 채로 남는다.
 *  - 게다가 템플릿이 .input-group > .form-control:focus 에 z-index:5 를 줘서, 입력칸의
 *    진한 테두리가 아이콘 칸의 테두리 위에 그려진다. 한 덩어리여야 할 것의 이음매가 어긋나 보인다.
 *
 * 그래서 두 가지를 함께 고친다.
 *  - **색을 한 단계씩만 옮긴다.** hover 는 gray-400(한 칸 진하게), focus 는 primary(파랑).
 *    focus 가 색상 자체를 바꾸므로 hover 와 구분되고, 어느 쪽도 검게 보이지 않는다.
 *  - **묶음 전체가 같이 반응한다.** 아이콘 칸을 짚어도, 입력칸에 커서가 들어가도
 *    그룹 안의 테두리가 한 색이 된다. 색이 같으면 z-index 로 겹쳐 그려져도 이음매가 안 보인다.
 *
 * **hover 쪽에 :not(:focus) 를 단다.** 커서가 든 칸에 마우스가 올라간 상태가 실제로 흔한데,
 * :not() 이 붙은 hover 선택자가 특이도가 더 높아 그냥 두면 focus 파랑을 회색이 덮어쓴다.
 * 순서로 해결하려 하면 나중에 규칙을 하나 끼울 때 다시 깨진다 — 두 상태를 아예 배타로 둔다.
 * -------------------------------------------------------------------------- */
.form-control:hover:not(:focus):not(:disabled):not([readonly]),
.form-select:hover:not(:focus):not(:disabled),
.input-group:hover:not(:focus-within) > .input-group-text,
.input-group:hover:not(:focus-within) > .form-control,
.input-group:hover:not(:focus-within) > .form-select {
    border-color: var(--theme-gray-400);
}

.form-control:focus,
.form-select:focus,
.input-group:focus-within > .input-group-text,
.input-group:focus-within > .form-control,
.input-group:focus-within > .form-select {
    border-color: var(--theme-primary);
}

/* 검색형 선택 상자(Choices.js)도 같은 필터 바에 나란히 놓인다. 하나만 다르게 반응하면
   그것대로 이질감이 된다. 템플릿은 이 상자의 바깥 테두리에 hover·focus 규칙이 아예 없어
   눌러도 아무 반응이 없었고, 안쪽 검색칸만 dark-border-subtle 로 검게 변했다. */
.choices:hover:not(.is-focused):not(.is-open) .choices__inner,
.choices[data-type*="select-one"] .choices__input:hover {
    border-color: var(--theme-gray-400);
}

.choices.is-focused .choices__inner,
.choices.is-open .choices__inner,
.choices[data-type*="select-one"] .choices__input:focus {
    border-color: var(--theme-primary);
}

/* --------------------------------------------------------------------------
 * 검색형 선택 상자의 높이 (.choices-sm)
 *
 * Choices.js 는 원본 select 을 감추고 자기 마크업(.choices > .choices__inner)을 그린다.
 * 그 마크업은 언제나 기본 크기다 — **원본에 붙은 form-select-sm 이 옮겨지지 않는다.**
 * 필터 바는 전부 -sm(입력칸·선택칸·버튼)인데 검색형 선택 상자만 기본 크기로 그려져
 * 위아래로 5px 쯤 높았고, 한 줄에 나란히 놓인 컨트롤들의 높이가 어긋났다.
 *
 *   .form-select-sm  padding .3125rem / font .788rem  → 약 31px
 *   .choices__inner  padding .4532rem / font 13px     → 약 36px
 *
 * 레이아웃의 Choices 초기화가 원본이 -sm 이면 래퍼에 .choices-sm 을 달아 준다.
 * 여기서는 그 표식에 -sm 의 값을 그대로 준다 — 두 숫자가 갈리면 다시 어긋난다.
 *
 * 기본 크기는 손대지 않는다. .choices__inner 의 padding 이 이미 .form-select 와 같은
 * .4532rem 이라 원래 맞아 있었다. 어긋난 것은 -sm 뿐이다.
 * -------------------------------------------------------------------------- */
.choices-sm .choices__inner {
    padding: 0.3125rem 0.7rem !important; /* .form-select-sm 과 같은 값 */
    font-size: 0.788rem;
    border-radius: var(--theme-border-radius-sm) !important;
}

/* 화살표는 top:18px 로 박혀 있다 — 기본 높이(36px)의 한가운데라는 뜻이다.
   높이가 달라지면 어긋나므로 '가운데'로 바꿔 말한다. 기본 크기에서는 값이 같아 변화가 없다. */
.choices[data-type*="select-one"]:after {
    top: 50%;
}

/* --------------------------------------------------------------------------
 * 상단바 알림 배지 (.topbar-badge)
 *
 * 종 아이콘 위에 얹는 숫자다. 탭 옆의 .badge-count 와 쓰임이 다르다 —
 * 그건 줄 안에 자리를 차지하는 값이고, 이건 아이콘 위에 겹쳐 얹는 표시다.
 *
 * 부트스트랩 예제의 `top-0 start-100 translate-middle` 을 그대로 쓰면
 * **배지의 가운데가 버튼 모서리에 놓여 절반이 버튼 밖으로 나간다.**
 * 옆 아이콘을 덮고, 오른쪽 끝에 있으면 화면을 넘어간다.
 * 그래서 버튼 '안쪽' 모서리에 붙이고, 넘치는 만큼만 살짝 띄운다.
 *
 * .badge-count 의 min-width(24px)도 여기서는 과하다. 한 자리 숫자를 위해
 * 아이콘만 한 원을 그릴 이유가 없다 — 폭은 내용을 따라간다.
 * -------------------------------------------------------------------------- */
.topbar-badge {
    position: absolute;
    top: -0.125rem;
    inset-inline-end: -0.25rem;

    /* **높이와 같은 min-width 로 정원을 만든다.**
       한때 좌우 여백만 주고 폭을 내용에 맡겼는데, line-height 가 만드는 높이(16px)가
       글자 한 자의 폭(14px)보다 커서 '세로로 긴 타원'이 됐다. 숫자 배지에서는
       가로가 세로보다 좁아지는 경우를 아예 없애야 한다.

       탭 옆의 .badge-count 는 라운드 사각형인데 여기만 정원인 이유는 쓰임이 달라서다 —
       그건 줄 안에 자리를 차지하는 값이고, 이건 아이콘 위에 얹는 표시다.
       두 자리를 넘으면 좌우로만 늘어나 알약이 된다. */
    display: inline-flex;
    align-items: center;
    justify-content: center;

    min-width: 1.125rem; /* 18px — height 와 같은 값이 정원의 근거다 */
    height: 1.125rem;
    padding: 0 0.25em;

    font-size: 0.6875rem; /* 11px — 아이콘 위에 얹는 표시라 본문보다 작아도 된다 */
    line-height: 1;
    font-variant-numeric: tabular-nums;
    border-radius: 999px;

    /* 어두운 상단바에서도 숫자가 아이콘에 묻히지 않게 테두리로 띄운다. */
    box-shadow: 0 0 0 2px var(--theme-topbar-bg, var(--theme-secondary-bg));
}

/* 상단바 오른쪽 끝에 여백이 없어 마지막 항목이 화면에 붙는다.
   배지가 아니라도 손이 닿기 어려우므로 조금 띄운다. */
.app-topbar .topbar-menu {
    padding-inline-end: 0.75rem;
}

/* --------------------------------------------------------------------------
 * 건수 배지 (.badge-count)
 *
 * 탭(nav-pill) 옆에 붙는 '전체 128 / 미달 4' 같은 숫자다. 글자가 아니라 수를 세는 칸이다.
 *
 * **원형을 쓰지 않는다.** 전에는 `rounded-pill` 이었는데, 그 클래스는 '높이의 절반'을
 * 반지름으로 잡을 뿐 폭을 정해주지 않아서 폭이 글자 하나의 폭을 그대로 따라갔다.
 * 숫자마다 폭이 달라(1 은 좁고 4·8 은 넓다) 같은 한 자리인데도 어떤 탭은 동그랗고
 * 어떤 탭은 눌린 타원이었다. 높이와 같은 min-width 로 정원을 만들 수도 있었지만,
 * **두 자리를 넘어가면 결국 길쭉한 알약이 되어 한 화면 안에 원과 알약이 섞인다.**
 *
 * 그래서 상태 배지와 **같은 모서리(라운드 사각형)** 를 쓴다. 이 앱의 배지는 원래
 * 전부 라운드 사각형이고 건수만 원형이던 것이 예외였다 — 모양을 하나로 두면
 * 자릿수가 늘어도 같은 배지가 옆으로 넓어질 뿐, 다른 물건으로 보이지 않는다.
 *
 * 그래서 여기서 정하는 것은 두 가지뿐이다.
 *  - min-width — 한 자리 배지가 홀쭉해 보이지 않게 하고, 나란한 탭들의 폭을 맞춘다.
 *  - tabular-nums — 숫자 폭을 고정한다. 같은 자릿수면 11 과 48 의 폭이 갈리지 않는다.
 *
 * 모서리·여백·정렬은 .badge 가 이미 갖고 있으므로 다시 쓰지 않는다.
 * -------------------------------------------------------------------------- */
.badge-count {
    /* 라운드 사각형이다. .badge 가 이미 그 모서리를 갖고 있지만 여기 못 박아 둔다 —
       바깥에서 rounded-pill 이 섞여 들어와도 모양이 흔들리지 않는다. */
    border-radius: var(--theme-border-radius);

    /* 한 자리가 홀쭉해 보이지 않게, 나란한 탭들의 폭도 맞춘다. */
    min-width: 1.5rem;

    /* **flex 안에서 줄어들지 않게 한다.**
       알림 드롭다운처럼 배지가 flex 항목이면 flex-shrink 기본값(1)이
       min-width 를 눌러 버려 폭이 글자보다 좁아진다. 그러면 높이는 그대로인데
       폭만 줄어 '세로로 긴 타원'이 된다 — 숫자가 길어질수록 더 눌린다. */
    flex: 0 0 auto;

    /* 같은 자릿수면 11 과 48 의 폭이 갈리지 않는다. */
    font-variant-numeric: tabular-nums;

    /* 세 자리를 넘어가도 가로로만 늘어난다. 줄바꿈으로 두 줄이 되면 높이가 튄다. */
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
 * 표 밀도
 *
 * 한 화면에 들어가는 줄 수가 곧 쓸모다. 목록 화면이 대부분이라 여백을 좁게 잡는다.
 * .table-sm 은 더 좁게 둬야 구분이 남는다.
 * -------------------------------------------------------------------------- */
.table > :not(caption) > * > * {
    padding: 0.5rem 0.5rem;
}

.table-sm > :not(caption) > * > * {
    padding: 0.35rem 0.4rem;
}

/* --------------------------------------------------------------------------
 * 요약 카드 (.stat-row)
 *
 * 화면 맨 위에 2~4칸으로 깔리는 숫자 카드다. 마크업은
 *   <div class="row g-3 mb-4 stat-row"> … <div class="card h-100"><div class="card-body">
 * 로 고정돼 있고, 그 안은 '작은 라벨 + 큰 숫자 + 작은 보조설명' 세 줄이다.
 *
 * 두 가지가 겹쳐 칸이 내용보다 훨씬 커 보였다.
 *  - 카드 기본 여백이 20px 인데 본문 글자가 13px 이다. 표 밀도를 좁힌 것과 같은 이유로 과하다.
 *  - 숫자를 22px(fs-3 · fs-22)로 키워 뒀는데, 라벨·보조설명이 13px 이라 한 칸 안에서 격차가 크다.
 *
 * h-100 이라 네 칸의 높이는 '가장 내용이 많은 칸'이 정한다. 그래서 그 칸(예: 작업지시
 * 상세의 '지시 수량' — 라벨·숫자·진행바·보조설명 네 줄)을 줄이면 나머지 세 칸의
 * 빈 여백도 같이 줄어든다. 값을 여기 한 곳에서 잡아야 25개 화면이 같이 움직인다.
 *
 * 카드 안의 다른 글자 크기(fs-4 · fs-5 = 16 · 13.5px)는 이미 본문에 가까워 건드리지 않는다.
 * -------------------------------------------------------------------------- */
.stat-row .card-body {
    padding: 0.75rem 0.875rem;
}

.stat-row .fs-3,
.stat-row .fs-22 {
    font-size: 1.125rem !important; /* 22px → 18px. app.css 의 fs-* 가 !important 라 여기도 필요하다 */
}

/* --------------------------------------------------------------------------
 * 인증 화면 (로그인 · 가입 · 강제 비밀번호 변경)
 *
 * **폰이 기준이고 넓어지면 카드가 된다.** 창고 담당자는 관리자가 발급한 계정으로
 * 폰에서 처음 로그인한다. 그 화면이 이 서비스의 첫인상이고, 여기서 막히면
 * 나머지 화면은 볼 일이 없다.
 *
 * 템플릿(app.css)이 이 화면에 맞지 않는 값 넷을 갖고 있다. app.css 는 건드리지
 * 않는다 — 템플릿을 다시 받으면 되돌아갈 수정이다.
 *
 *  1. .auth-box 여백이 사방 50px 다. 360px 폭 폰에서 좌우 100px 가 먼저 빠져
 *     카드가 260px 로 눌린다.
 *  2. min-height 가 100vh 다. 모바일 브라우저의 주소창 높이를 포함해 계산돼
 *     아래가 잘린다.
 *  3. --theme-border-radius 가 4px 다. 목록 화면의 촘촘한 표에는 맞지만,
 *     48px 짜리 입력칸에 4px 각을 두면 높이만 큰 옛날 관리자 폼으로 읽힌다.
 *  4. .form-control:focus 의 box-shadow 가 none 이다. 칸을 눌러도 티가 안 나
 *     폰에서는 지금 어디에 쓰고 있는지 알기 어렵다.
 * -------------------------------------------------------------------------- */
.auth-box {
    padding: 1.25rem;
    /* 주소창이 접혔다 펴져도 높이가 흔들리지 않는다. dvh 를 모르는 브라우저는 app.css 의 100vh 를 쓴다. */
    min-height: 100dvh !important;
    /* 아이폰 홈 인디케이터에 버튼이 가리지 않게. */
    padding-bottom: calc(1.25rem + env(safe-area-inset-bottom));
}

@media (min-width: 576px) {
    .auth-box {
        padding: 2rem;
    }
}

/*
 * **입력 글자를 16px 로 올린다.**
 *
 * 이보다 작은 칸에 포커스하면 iOS 사파리가 페이지를 통째로 확대한다. 확대된 채로
 * 남기 때문에 다음 칸과 로그인 버튼이 화면 밖으로 나가고, 사용자는 손으로 다시
 * 줄여야 한다. 본문 13px 규약의 예외이고, 예외인 이유는 이것 하나다.
 *
 * 확대 자체를 막는 길(maximum-scale=1)도 있지만 인증 화면에서는 쓰지 않는다 —
 * 눈이 나쁜 사람이 회사코드를 확인할 방법까지 같이 없어진다.
 */
.auth-box .form-control,
.auth-box .form-select {
    font-size: 16px;
    min-height: 52px;
    padding: 0.75rem 0.875rem;
    border-radius: 12px;
}

/* 지금 어느 칸에 쓰고 있는지 한눈에. 색만이 아니라 테두리 굵기로도 갈린다. */
.auth-box .form-control:focus,
.auth-box .form-select:focus {
    border-color: var(--theme-primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/*
 * 눈 버튼(비밀번호 보기)은 칸에 붙은 별개의 버튼이 아니라 **칸의 일부**로 보여야 한다.
 * 기본 btn-outline-secondary 는 회색 테두리가 한 겹 더 생겨 두 덩어리로 읽힌다.
 */
.auth-box .input-group > .btn {
    min-height: 52px;
    border-radius: 0 12px 12px 0;
    border: 1px solid var(--theme-border-color);
    border-left: 0;
    background-color: var(--theme-secondary-bg);
    color: var(--theme-secondary-color);
}

.auth-box .input-group > .form-control {
    border-radius: 12px 0 0 12px;
}

/* 포커스 테두리는 칸 전체에 돈다. 절반만 파래지면 어긋나 보인다. */
.auth-box .input-group:focus-within > .btn,
.auth-box .input-group:focus-within > .form-control {
    border-color: var(--theme-primary);
}

.auth-box .input-group:focus-within {
    border-radius: 12px;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* 위 그림자가 칸 전체를 감싸므로 입력칸 자체의 그림자는 뺀다. 두 겹이 되면 번져 보인다. */
.auth-box .input-group > .form-control:focus {
    box-shadow: none;
}

/* 한 손 엄지로 누르는 버튼. 현장 화면(layouts/mobile)의 크기와 맞춘다. */
.auth-box .btn-auth {
    min-height: 52px;
    border-radius: 12px;
    font-size: 1rem;
    font-weight: 600;
}

/*
 * 워드마크.
 *
 * 로그인 화면에는 제목이 없다 — 로고와 '로그인' 버튼이 이미 어디인지 말한다.
 * 그래서 이 로고가 화면의 머리 역할을 대신하고, 그만한 크기와 자리를 갖는다.
 */
.auth-box .auth-brand {
    text-align: center;
    margin-bottom: 2rem;
}

.auth-box .auth-brand-link {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
}

.auth-box .auth-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    font-size: 28px;
    line-height: 1;
    border-radius: 16px;
}

.auth-box .auth-brand-name {
    font-size: 1.875rem;
    line-height: 1;
    letter-spacing: -0.03em;
}

/*
 * 제목을 화면 제목 크기로 올린다. 무슨 화면인지 헷갈릴 수 있는 곳에만 쓴다.
 *
 * 템플릿의 h4 는 16.3px 라 본문 13px 과 거의 같다. 목록 화면 안에서는 그게 맞지만
 * 인증 화면의 제목은 그 하나로 여기가 어디인지 말해야 한다.
 */
.auth-box .auth-headings {
    text-align: center;
    margin-bottom: 2rem;
}

.auth-box .auth-heading {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.auth-box .form-label {
    font-size: 0.8125rem;
    margin-bottom: 0.375rem;
}

/* 기본 체크박스는 13px 이라 폰에서 조준이 안 된다. */
.auth-box .form-check-input {
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.05rem;
}

.auth-box .form-check-label {
    padding-left: 0.35rem;
    font-size: 0.875rem;
    line-height: 1.5;
}

/*
 * 폰에서는 카드 테두리가 정보를 더하지 않는다. 좁은 화면에서 테두리는 안쪽 폭만
 * 깎아먹으므로 장식을 걷고 화면을 꽉 쓴다. 576px 부터 원래 카드로 돌아간다.
 */
@media (max-width: 575.98px) {
    .auth-box .card {
        border: 0;
        box-shadow: none;
        background: transparent;
        margin-bottom: 0;
    }

    .auth-box .card-body {
        padding: 0 !important;
    }
}

@media (min-width: 576px) {
    .auth-box .card {
        border-radius: 16px;
    }
}

/* --------------------------------------------------------------------------
 * 글꼴 — Pretendard 가변폰트 하나
 *
 * 바꾸지 않는다. 한글 UI 에서 지금 가장 무난한 선택이고 이미 로컬에 있다.
 * (CDN 은 쓰지 않는다. `public/assets/fonts/PretendardVariable.woff2` 와
 *  `css/` 의 형제 관계를 깨면 app.css 의 @font-face 가 파일을 못 찾는다.)
 *
 * 대신 **폴백 순서**를 고친다. 템플릿 기본값은
 *   "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
 *   system-ui, "Malgun Gothic", sans-serif
 * 인데, 한글이 그려지는 순간 문제가 둘 있다.
 *
 *  1. `-apple-system`(SF Pro)에는 한글이 없다. 그래서 한글만 다시 아래로 떨어져
 *     라틴과 한글이 서로 다른 글꼴로 섞여 나온다.
 *  2. `Malgun Gothic` 은 윈도우 폰트다. 안드로이드·iOS 에는 없어서 결국
 *     `sans-serif` 까지 내려간다.
 *
 * 각 기기의 한글 기본 글꼴을 이름으로 끼워 넣어, 폰트가 도착하기 전 구간에도
 * 한글이 제 글꼴로 그려지게 한다. 도착 후 바뀌는 폭도 그만큼 작아진다.
 * -------------------------------------------------------------------------- */
:root {
    --theme-font-sans-serif:
        "Pretendard Variable", Pretendard,
        -apple-system, BlinkMacSystemFont, system-ui,
        "Apple SD Gothic Neo",   /* iOS · macOS 의 한글 */
        "Noto Sans KR",          /* 안드로이드의 한글(본고딕) */
        "Malgun Gothic",         /* 윈도우의 한글 */
        sans-serif;
}

/* --------------------------------------------------------------------------
 * 품목 자동완성 (x-item-select)
 *
 * select2 · Choices 같은 라이브러리를 쓰지 않고 직접 그린다. CDN 을 안 쓰는 원칙과
 * 맞고, 무엇보다 **스캐너가 타이핑해 넣는 입력칸**을 라이브러리가 감싸는 순간
 * 그 흐름이 먼저 깨진다. 여기서는 평범한 input 위에 목록만 얹는다 —
 * 스크립트가 죽어도 입력칸은 그대로 동작한다.
 *
 * 목록은 .input-group **밖**, 입력칸만 감싸는 .item-select-field 를 기준으로 연다.
 * 안에 두면 입력칸이 마지막 자식이 아니게 되어 부트스트랩이 오른쪽 모서리를 0 으로
 * 깎는다(`.input-group > :not(:last-child)`). 그 선택자는 6단계라 덮을 수도 없다.
 * -------------------------------------------------------------------------- */
.item-select-field {
    position: relative;
}

.item-suggest {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 1056;   /* 모달(1055) 위에서도 열려야 한다 */
    max-height: 17rem;
    margin: 0;
    padding: 0.25rem;
    overflow-y: auto;
    list-style: none;
    background: var(--theme-secondary-bg);
    border: 1px solid var(--theme-border-color);
    border-radius: 0.625rem;
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08), 0 16px 32px -20px rgba(15, 23, 42, 0.45);
    /* 폰에서 목록을 훑을 때 관성 스크롤이 걸리게 한다. */
    -webkit-overflow-scrolling: touch;
}

.item-suggest-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.625rem;
    border-radius: 0.5rem;
    cursor: pointer;
}

/*
 * 키보드로 고른 줄과 마우스를 올린 줄을 **같은 색**으로 칠한다.
 * 둘이 다르면 화살표로 내려가는 도중 마우스가 놓인 줄이 같이 밝아져
 * 어느 것이 선택된 줄인지 알 수 없게 된다.
 */
.item-suggest-row:hover,
.item-suggest-row.is-active {
    background: var(--theme-primary-bg-subtle, #e7effd);
}

.item-suggest-name {
    font-weight: 600;
    line-height: 1.35;
}

.item-suggest-meta {
    font-size: 0.8125rem;
    color: var(--theme-secondary-color);
    line-height: 1.35;
}

/* 현재고는 오른쪽에 붙여 세로로 줄을 맞춘다. 목록을 훑는 눈이 한 줄로 내려간다. */
.item-suggest-stock {
    flex-shrink: 0;
    font-size: 0.8125rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--theme-secondary-color);
}
