/*
 * 커스텀 색상 유틸리티. lib/layout.php의 tailwind.config(danger/warn)와 반드시 같은 값으로 유지한다.
 * 로그인 화면처럼 그 config 블록이 없는 독립 HTML에서도 text-danger/text-warn이 동작해야 하므로
 * 여기 순수 CSS로도 정의해 둔다.
 */
/*
 * 메인 컬러(brand)와 사이드바 배경(side). lib/layout.php의 tailwind.config에
 * 같은 값이 있다 — 한쪽만 고치면 화면마다 색이 갈린다. 둘 다 고칠 것.
 */
:root {
  --brand: #3366CC;
  --brand-dark: #2A55AA;
  --side: #1E2A3A;
}

.text-danger { color: hsl(0 72% 51%); }
.text-warn   { color: hsl(38 92% 50%); }
.text-brand  { color: var(--brand); }

/*
 * 셀 — 화면을 이루는 흰 판(검색 상자, 목록 상자, 폼 상자, 대시보드 타일).
 * 값은 Z 드라이브 원본의 .dash-card(company/css/common.css)와 같다.
 *
 * 전에는 `bg-bg border border-border rounded` 유틸리티 조합을 화면마다 적어
 * 뒀는데, 모서리 반경과 테두리색을 한 번 바꾸려면 58개 파일을 고쳐야 했다.
 * 클래스 하나로 모아 두면 여기만 고치면 된다.
 *
 * Tailwind의 rounded/border-border를 손대지 않은 이유 — 그 두 유틸리티는 작은
 * 뱃지·알림줄·안쪽 표에도 쓰인다. 전역 값을 12px/#ddd로 바꾸면 높이 20px짜리
 * 뱃지가 알약처럼 보이는 등 셀과 무관한 곳이 같이 끌려간다.
 *
 * Z의 .dash-card에 있는 overflow:hidden은 옮기지 않았다 — 그건 카드 맨 위에
 * 배경색 있는 헤더 띠를 두느라 모서리에서 잘라내야 해서다. 이쪽 셀은 안쪽에
 * padding을 두고 내용을 띄우므로 잘라낼 것이 없고, 넣으면 안에서 넘쳐야 하는
 * 요소(그리드 스크롤 등)까지 잘린다.
 */
.card { background:#fff; border:1px solid #ddd; border-radius:12px; }

/*
 * 검색 조건 셀 — 값을 읽는 곳(흰 표)과 값을 넣는 곳이 한눈에 갈리도록 바탕을
 * 깐다.
 *
 * 색은 사용자 지시로 표 머리띠와 맞바꾼 값이다 — 검색이 파랑(#E0EAF7),
 * 표 머리띠·항목명이 서브헤더와 같은 회색(#e5e7eb)을 갖는다. 파랑을 조작하는
 * 쪽에 줘서 눈이 먼저 검색으로 가고, 표는 회색 머리에 흰 본문으로 가라앉는다.
 * 두 값은 짝이므로 한쪽만 바꾸면 검색과 표가 같은 색이 되어 구분이 사라진다
 * (아래 .card-table-head와 app.css의 표 머리줄 규칙).
 *
 * 안쪽 입력칸은 흰색이라 이 바탕 위에서 또렷하게 떠오른다.
 */
.card-search { background:#E0EAF7; border-color:#c5d5f0; }

/*
 * 목록 표 — Z 드라이브 원본의 표 디자인을 옮긴 것이다.
 * 값의 출처는 company/css/common.css의 .ag-theme-alpine 블록:
 *   머리글 띠 #e8eef8 / 글자 #000 / 굵기 500 / 14px
 *   본문 글자 #333 / 400 / 14px, 가로선 #d0d7e3, 세로 구분선 없음
 *   줄 높이 40px, 좌우 여백 16px, 줄에 마우스 올리면 hsl(210 40% 96.1% / .5)
 *
 * Z는 AG Grid, 이쪽은 TOAST UI Grid다. 두 라이브러리는 클래스 이름만 다를 뿐
 * 같은 그림을 그릴 수 있어 수치를 그대로 옮겼다.
 *
 * 색은 여기가 아니라 lib/layout.php의 tui.Grid.applyTheme()에 있다 — TOAST는
 * 인스턴스를 만들 때 테마 CSS를 <head> 끝에 실행 중 주입하는데, 그게 이 파일보다
 * 뒤에 놓이는 데다 선택자도 한 단계 길어(.tui-grid-container .tui-grid-cell)
 * 여기서 색을 적으면 진다. 라이브러리가 주는 API로 넣어야 이긴다.
 * 이 블록에는 테마가 다루지 않는 글꼴·여백·마우스오버만 남긴다.
 */
.tui-grid-container { font-family: 'Pretendard Variable', Pretendard, system-ui, sans-serif; font-size: 14px; }

/* 머리글 — Z의 .ag-header-cell(500 / 14px / #000). 좌우 여백만 16px로 맞춘다. */
.tui-grid-cell-header { font-weight: 500; font-size: 14px; padding: 4px 16px; }

/* 정렬 화살표는 TOAST 기본값(PNG 스프라이트) 그대로다. 잠깐 SVG로 갈아 끼워
   위아래 화살표 사이를 좁혀 봤지만 사용자 지시로 되돌렸다 — 여기에 규칙을
   두지 않는다. */

/*
 * 본문 셀 — 좌우는 Z의 16px, 세로 여백은 0이다.
 *
 * TOAST 기본값은 padding:12px 12px 11px으로, 그 합이 줄 높이 40px을 만들어
 * 글자가 가운데에 놓이는 구조였다. 문제는 칸 안에 글자보다 큰 것(목록의 '수정'
 * 같은 24px 버튼)이 들어올 때다 — 내용 상자가 17px뿐이라 위아래가 잘린다.
 *
 * 세로 여백을 0으로 두면 내용 상자가 내용물 크기를 그대로 갖고, 그것을
 * <td>의 기본 vertical-align:middle이 줄 한가운데에 놓는다. 글자든 버튼이든
 * 같은 규칙으로 가운데에 오고 잘릴 일이 없다.
 */
.tui-grid-cell .tui-grid-cell-content { padding: 0 16px; font-size: 14px; }

/*
 * 줄에 마우스를 올렸을 때. 테마가 칠한 셀 배경을 덮어야 해서 선택자를
 * 한 단계 더 길게 잡는다(테마는 .tui-grid-container .tui-grid-cell).
 * Z처럼 줄 전체가 눌리는 대상임을 커서로도 알린다.
 */
/*
 * 표 안에서는 기본 커서를 쓴다(사용자 지시). 줄이나 항목명 위에서 손 모양이
 * 나오면 "누르면 뭔가 열린다"는 뜻이 되는데, 줄 자체는 누를 곳이 아니고 칸은
 * 골라서 값을 보거나 복사하는 자리다 — 글자를 고르는 자리라는 뜻의 기본 커서가 맞다.
 *
 * 손 모양은 실제로 눌러야 하는 것에만 남는다: 칸 안의 버튼(.cell-btn)·링크(<a>)와
 * 체크박스. 그 셋은 각자 자기 규칙에서 cursor:pointer를 갖고 있어 여기서 끄는
 * 것과 무관하다. 정렬 화살표가 있는 머리줄도 기본 커서로 되돌린다.
 */
.tui-grid-body-area tr,
.tui-grid-header-area .tui-grid-cell,
.tui-grid-header-area .tui-grid-cell-header,
.tui-grid-cell,
.tui-grid-cell-content { cursor: default; }
/* 위에서 한 번에 끈 것을 실제 누를 것들에만 되돌린다. */
.tui-grid-container a,
.tui-grid-container .cell-btn,
.tui-grid-container input[type="checkbox"],
.tui-grid-container label { cursor: pointer; }

/*
 * 드래그로 여러 칸 고르기 — 기능은 라이브러리 기본으로 켜져 있는데 화면에
 * 안 보였다. 원인은 라이브러리가 선택 레이어에 걸어 둔 opacity:0.1이다
 * (tui-grid.css의 .tui-grid-layer-selection). 테마에서 색을 아무리 진하게 줘도
 * 10%로 눌려 흰 바탕과 구분이 안 된다.
 *
 * opacity를 1로 되돌리고, 대신 색 자체를 반투명(alpha .18)으로 둔다 — 밑의
 * 글자가 그대로 읽히면서 고른 범위는 또렷하다. 색은 lib/layout.php의
 * applyTheme(selection)와 같은 계열이고, 여기서 정한 값이 최종이다.
 *
 * 테두리는 범위의 가장자리를 알려 준다. 한 칸만 눌렀을 때 생기는 초점 테두리
 * (applyTheme의 cell.focused)와 같은 색이라 둘이 이어져 읽힌다.
 */
.tui-grid-layer-selection {
  opacity: 1 !important;
  background-color: rgba(51,102,204,.18) !important;
  border-color: var(--brand) !important;
}

/*
 * 줄에 마우스를 올렸을 때 — 체크박스·No 칸까지 줄 전체가 함께 밝아진다.
 *
 * :hover를 쓰지 않는다. TOAST가 왼쪽 고정칸(체크박스·No)을 데이터 칸과 다른
 * <table>에 그려서, :hover로는 마우스가 올라간 쪽 절반만 반응한다. 두 표의 같은
 * 줄을 이어 주는 일은 CSS가 못 하므로 lib/layout.php의 gridRowHover()가 양쪽에
 * 이 클래스를 건다.
 *
 * 칸(td.row-hover)과 줄(tr.row-hover)을 다 받는 이유 — 짝을 찾는 방법이 둘이다
 * (data-row-key / 줄 번호). 어느 쪽으로 잡히든 같은 색이 나오게 둘 다 적는다.
 *
 * 색 #d0e2f7 — 사용자 지시로 진한 파랑 계열이다. 앞서 쓰던
 * hsl(210 40% 96.1% / .5)은 거의 흰색이라 어느 줄에 있는지 눈에 안 들어왔다.
 * 표 머리줄(#e5e7eb)·검색 셀(#E0EAF7)과 겹치지 않으면서 한 단계 진하다.
 *
 * !important인 이유 — 위쪽에서 순번 칸 배경을 흰색으로 고정해 두었는데(테마가
 * 주는 색을 되돌리려고), 그 규칙을 이겨야 이 칸도 같이 밝아진다.
 */
.tui-grid-body-area tr.row-hover > .tui-grid-cell,
.tui-grid-body-area tr.row-hover > .tui-grid-cell-row-header,
.tui-grid-body-area .tui-grid-cell.row-hover { background-color: #d0e2f7 !important; }

/*
 * 마우스가 올라간 줄에서는 세로 구분선도 한 단계 진하게 바꾼다.
 *
 * 평소 구분선(#e5e7eb)은 흰 바탕보다 어두워 선으로 보이지만, 마우스오버 색
 * (#d0e2f7)보다는 밝다. 그대로 두면 색이 깔린 줄에서 선만 밝게 남아 흰 줄처럼
 * 보인다 — "1과 수정 칸 사이 흰 선"이 이것이다. 바탕보다 어두운 값으로 바꾸면
 * 다른 줄과 같은 뜻의 선으로 읽힌다.
 *
 * 순번 칸 오른쪽(고정영역과 데이터영역 경계)은 테두리가 아니라 inset 그림자로
 * 그려 두었으므로(위 border-collapse 주석 참고) 그쪽도 같이 바꾼다.
 */
.tui-grid-body-area tr.row-hover > .tui-grid-cell,
.tui-grid-body-area .tui-grid-cell.row-hover { border-right-color: #b3cbe9 !important; }
/* 순번 칸 오른쪽 경계는 테두리가 아니라 그 칸 안쪽 그림자로 그려 둔 자리다
   (위 .tui-grid-lside-area 규칙). 색만 같이 바꾼다 — 위치는 건드리지 않는다. */
.card-table .tui-grid-lside-area .tui-grid-body-area tr.row-hover > *:last-child,
.card-table .tui-grid-lside-area .tui-grid-body-area .row-hover:last-child { box-shadow: inset -1px 0 0 #b3cbe9 !important; }

/*
 * ── 표 한 판으로 된 셀 (.card .card-table) ─────────────────────────────
 *
 * 셀 안쪽 여백 없이 표가 가장자리까지 꽉 차는 형태. W 드라이브의
 * /adm/export1/ 리스트와 같은 규격이다(출처: adm/css/common.css의
 * #receiptGrid 블록 + adm/export1/index.php의 .dash-card 마크업).
 *
 * 쓰는 법 — .card와 함께 건다:
 *   <div class="card card-table">
 *     <div class="card-table-head">…제목·건수·버튼…</div>
 *     <div id="grid"></div>
 *   </div>
 * 테두리와 둥근 모서리는 .card가, 안쪽 구조는 이 클래스가 맡는다.
 * overflow:hidden이 있어야 표의 네 귀퉁이가 .card의 12px 곡선에 맞춰 잘린다.
 * 표를 붙이는 화면에서 그리드 옵션도 같이 맞출 것 — rowHeight:34,
 * header:{height:33}. 줄 높이는 CSS가 아니라 그 옵션이 정한다.
 *
 * 아래 규칙에 !important가 붙은 이유 — TOAST는 그리드를 만들 때 자기 테마
 * CSS를 <head> 끝에 실행 중 주입한다(lib/layout.php의 applyTheme). 이 파일은
 * <link>라 항상 그보다 앞에 놓여, 명시도가 같으면 나중에 온 테마가 이긴다.
 * W 드라이브 원본도 같은 이유로 같은 방법을 쓴다. 위 기본 표(.tui-grid-*)와
 * 값이 다른 항목만 적는다 — 흰 본문·마우스오버는 그대로 물려받는다.
 */
.card-table { display:flex; flex-direction:column; overflow:hidden; }

/* 표 위 머리띠 — 아래 표 머리줄과 같은 색이라 둘이 한 덩어리로 읽힌다.
   #e5e7eb는 서브헤더와 같은 회색이다(사용자 지시로 검색 셀의 파랑과 맞바꿨다).
   바꿀 때는 머리줄(.tui-grid-header-area) 쪽도 같이 바꿀 것 — 두 값이 갈리면
   띠가 두 층으로 쪼개져 보인다. */
.card-table-head {
  display:flex; align-items:center; justify-content:space-between;
  /* 높이 44px — W 원본과 같은 값이다(중간에 사용자 지시로 42까지 내렸다가 다시
     2px 올렸다). 안에 들어가는 가장 높은 것이 등록 버튼(.btn 33px)이다.
     이 띠가 줄면 아래 표가 그만큼 더 갖는다 — 셀 높이는 flex로 나뉘므로 따로
     손댈 것이 없다. 오른쪽 상세 패널의 머리띠도 이 클래스를 그대로 쓰므로
     여기 한 곳만 고치면 둘 다 따라온다. */
  /*
   * flex를 고정하는 이유 — 이 띠는 세로 flex 상자(.card-table / .pnl-right)의
   * 자식이라, height만 주면 안에 든 것과 남은 공간에 따라 늘거나 줄 수 있다.
   * 왼쪽은 버튼 하나, 오른쪽은 저장·닫기 둘이라 그 차이로 두 띠의 실제 높이가
   * 몇 px 갈렸다(사용자 확인). 0 0 44px은 "늘지도 줄지도 말고 44px"이라는 뜻이라
   * 안에 무엇이 들어가든 같은 높이가 된다.
   */
  /* 41px — 사용자 지시로 44 → 43 → 41px. 왼쪽 '상품목록'과 오른쪽 '상품정보'가
     이 한 규칙을 공유하므로 둘이 함께 낮아진다. 안에 든 버튼(29px)에는 위아래
     6px씩 남아 여전히 여유가 있다 — 더 줄이려면 버튼부터 낮춰야 한다. */
  flex:0 0 41px; height:41px; padding:3px 16px;
  background:#e5e7eb; border-bottom:1px solid #d1d5db;
}
.card-table-title { font-size:15px; font-weight:500; color:#333; }
.card-table-count { font-size:14px; font-weight:600; color:var(--brand); }

/*
 * 머리띠 안의 버튼(목록의 '상품 등록', 상세 패널의 '저장'·'닫기')은 29px —
 * 기본 .btn 33px보다 4px 낮다(사용자 지시로 33 → 31 → 29px). 43px 띠 안에서
 * 위아래 7px씩 남아 버튼이 띠에 꽉 끼지 않는다.
 *
 * .btn 자체를 낮추지 않는 이유 — 그 클래스는 상세 폼 아래 버튼줄, 모달 발치 등
 * 띠 밖의 넓은 자리에도 쓰인다. 그쪽은 좁힐 이유가 없다.
 *
 * 세 버튼이 한 규칙에서 나오므로 왼쪽 등록 버튼과 오른쪽 저장·닫기가 항상 같은
 * 높이다 — 나란히 보이는 자리라 어긋나면 바로 눈에 띈다.
 */
.card-table-head .btn { height:30px; }

/* 글자는 한 단계 작게(13px), 줄 높이 32px에 맞춰 세로 여백을 걷어낸다.
   <td>의 기본 vertical-align:middle이 가운데 정렬을 대신한다. */
.card-table .tui-grid-cell,
.card-table .tui-grid-cell-header,
.card-table .tui-grid-cell-content { font-size:13px !important; }
.card-table .tui-grid-cell .tui-grid-cell-content { padding:0 12px !important; }
.card-table .tui-grid-cell-header { padding:0 12px !important; }

/*
 * renderer로 그리는 칸(상품명 링크, '수정'·'이력' 버튼 …)의 좌우 여백.
 *
 * TOAST는 그런 칸에 .tui-grid-cell-content 래퍼를 만들지 않고 renderer가 돌려준
 * 요소를 <td> 안에 그대로 넣는다. 그래서 바로 위 규칙(12px)이 걸릴 자리가 없어
 * 글자가 칸 왼쪽 끝에 딱 붙는다 — 왼쪽 정렬 링크에서 특히 눈에 띈다(사용자 보고:
 * 상품 목록의 상품명 링크). 래퍼가 없는 칸에는 <td>에 같은 값을 직접 준다.
 *
 * 래퍼 유무를 :has()로 가린다 — 이 화면들은 크롬/엣지 전용이고, lib/layout.php의
 * .app-main:has(.card-fill)에서 이미 쓰고 있는 방식이다.
 *
 * 순번·체크박스 칸(.tui-grid-cell-row-header)은 반드시 제외한다 — 그쪽은 아래에서
 * 일부러 padding:0 + flex 가운데 정렬로 맞춰 놨고, 여백이 들어가면 체크박스가
 * 가운데에서 밀린다.
 *
 * 칸 너비는 라이브러리가 고정하므로 여백을 넣어도 열 폭은 그대로다(실측 확인).
 */
.card-table .tui-grid-body-area .tui-grid-cell:not(.tui-grid-cell-row-header):not(:has(.tui-grid-cell-content)) {
  padding:0 12px !important;
}

/* 머리줄(항목명) — 위 .card-table-head와 같은 #e5e7eb, 글자는 한 톤 가볍게.
   두 값은 한 쌍이다. 한쪽만 고치면 머리띠와 항목명 줄이 두 층으로 갈라진다. */
.card-table .tui-grid-header-area,
.card-table .tui-grid-header-area .tui-grid-cell,
.card-table .tui-grid-header-area .tui-grid-cell-header,
.card-table .tui-grid-header-area .tui-grid-cell-row-header { background:#e5e7eb !important; }
/* 항목명 글자 — 13px / 450 / #222.
   #222는 TOAST 기본 테마 프리셋의 cell.header.text 값이다. W 드라이브는 머리글
   색을 따로 지정하지 않아 그 기본값이 그대로 보이는데, 이쪽은 layout.php의
   applyTheme가 #000으로 덮어써 두었으므로 여기서 되돌려야 W와 같아진다. */
.card-table .tui-grid-header-area .tui-grid-cell,
.card-table .tui-grid-header-area .tui-grid-cell-header { font-weight:450 !important; color:#222 !important; }
.card-table .tui-grid-header-area { border-bottom:1px solid #ddd !important; }

/*
 * 세로 구분선. 기본 표는 가로선만 쓰지만 이 형태는 W처럼 세로선도 넣는다.
 * 본문은 흰 바탕이라 옅은 #e5e7eb로 충분하다.
 *
 * 머리줄은 색을 따로 준다 — 바탕이 흰색이 아니어서 본문과 같은 색을 쓰면
 * 선이 묻혀 항목명 사이가 안 나뉜 것처럼 보인다(그렇게 그리고 있었다).
 * 한 단계 진한 #d1d5db는 셀 머리띠 아랫선과 같은 값이라 팔레트에서 벗어나지 않는다.
 */
.card-table .tui-grid-cell { border-right:1px solid #e5e7eb !important; border-left-width:0 !important; }
.card-table .tui-grid-header-area .tui-grid-cell,
.card-table .tui-grid-header-area .tui-grid-cell-header { border-right:1px solid #d1d5db !important; border-left-width:0 !important; }

/*
 * 순번(No) 칸 — TOAST가 이 칸을 rowHeader로 따로 다루고 테마가 별도 배경색을
 * 준다. 본문에서는 다른 칸과 같은 흰 바탕이어야 하므로 되돌린다. 머리줄 쪽은
 * 위 규칙이 이미 #e5e7eb로 칠하고 있다.
 */
.card-table .tui-grid-body-area .tui-grid-cell-row-header { background:#fff !important; }

/*
 * No 칸과 그 오른쪽(상세보기) 칸 사이의 선.
 *
 * 이 자리만 border로는 그려지지 않는다. TOAST의 표는 border-collapse:collapse인데
 * <table>에 `border: 1px hidden transparent`가 걸려 있고, 겹친 테두리를 정하는
 * 규칙에서 hidden은 다른 무엇보다 세다. 그래서 각 줄의 맨 오른쪽 칸은 오른쪽
 * 테두리를 항상 빼앗긴다 — 순번 칸이 왼쪽 고정영역(lside)의 마지막 칸이라
 * 정확히 여기에 걸린다. 앞선 시도가 안 보였던 것도 이 때문이다.
 *
 * 고정영역 상자에 한 번에 긋는 방법(inset 그림자나 ::after)은 쓰지 않는다.
 * 그 상자는 표 바닥까지 이어져 있어서, 줄이 없는 아래쪽 빈 구간까지 선이
 * 내려가 버린다 — 다른 열의 구분선은 마지막 줄에서 끝나므로 혼자 튄다.
 * (inset 그림자는 자식 칸의 불투명한 배경에 덮여 아예 안 보이기도 한다.)
 *
 * 그래서 다른 열과 똑같이 칸마다 그린다. 다만 border 대신 inset 그림자를 쓴다 —
 * 위에 적은 border-collapse 문제 때문이다. 색도 다른 열의 구분선과 같은 값을
 * 써서 이 선만 달라 보이지 않게 한다(머리줄 #d1d5db / 본문 #e5e7eb).
 *
 * 마지막 줄은 겹선 방지 — 칸에 테두리가 같이 그려지면 2px로 보인다.
 */
/*
 * 머리줄 쪽 선. 칸 안쪽 그림자(inset)가 아니라 ::after로 그린다 — 라이브러리가
 * 머리줄 칸을 본문 칸보다 정확히 1px 넓게 잡기 때문이다(실측: 머리줄 No 칸
 * 오른쪽 끝이 본문보다 1px 오른쪽). 양쪽 다 inset으로 그리면 머리줄 선만 1px
 * 오른쪽에 놓여 위아래가 어긋나 보인다(사용자 보고).
 *
 * right:1px이 그 1px을 되돌려, 본문 선과 정확히 같은 픽셀에 떨어진다.
 * 칸 안쪽이라 overflow:hidden에 잘리지도 않는다.
 */
.card-table .tui-grid-lside-area .tui-grid-header-area tr > *:last-child {
  position: relative; box-shadow: none !important;
}
.card-table .tui-grid-lside-area .tui-grid-header-area tr > *:last-child::after {
  content: ''; position: absolute; top: 0; bottom: 0; right: 1px; width: 1px;
  background: #d1d5db; pointer-events: none;
}
/*
 * 본문도 머리줄과 **같은 자리**(고정영역 마지막 칸의 안쪽 오른편)에 그린다.
 *
 * 전에는 이 선만 오른쪽 영역(rside) 첫 칸의 안쪽 왼편에 그렸다 — 머리줄 선과
 * 딱 1px 어긋나는 것을 피하려던 것인데, 그 자리는 두 가지 이유로 실제 화면에
 * 선이 안 나온다(사용자 보고: "모든 페이지에서 No 칸 오른쪽 선만 안 보인다"):
 *
 *   1. rside는 가로 스크롤되는 영역이다. 조금만 옆으로 밀면 그 '첫 칸'이 고정
 *      경계에서 벗어나 선이 통째로 딸려 간다 — 경계선은 스크롤되면 안 된다.
 *   2. 그 자리는 고정영역과 스크롤영역이 맞닿는 이음매라, 라이브러리가 겹쳐
 *      놓는 상자들에 1px이 가려지기 쉽다.
 *
 * 그래서 본문도 고정영역 칸 자기 안쪽(inset)에 그린다. 색은 다른 열의 본문
 * 구분선과 같은 #e5e7eb다.
 *
 * 칸 **바깥쪽** 1px(고정영역과 스크롤영역의 이음매)에 그리는 것은 시도했다가
 * 되돌렸다 — 그 픽셀은 라이브러리가 겹쳐 놓는 상자에 가려 화면에 안 나온다
 * (실측 후 사용자 확인). 옛 코드가 이 선을 오른쪽 영역 첫 칸에 그렸다가
 * 안 보였던 것도 결국 같은 자리였기 때문이다. 이 자리는 건드리지 말 것.
 */
.card-table .tui-grid-lside-area .tui-grid-body-area tr > *:last-child { box-shadow: inset -1px 0 0 #e5e7eb !important; }
/* 겹선 방지는 마지막 칸에만 건다 — 고정영역 안쪽 칸끼리(체크박스↔No)는 표
   안쪽이라 보통 테두리가 정상적으로 그려지므로 그대로 둬야 한다. */
.card-table .tui-grid-lside-area tr > *:last-child { border-right-width:0 !important; }

/*
 * 체크박스 — TOAST 기본은 이미지 스프라이트를 얹은 라벨이라 이 화면의 다른
 * 컨트롤과 톤이 맞지 않는다. W 드라이브(/adm/css/common.css의 #receiptGrid
 * 체크박스 블록)처럼 상자 하나에 메인 컬러만 입혀 쓴다.
 * 라벨·내용 상자의 여백을 걷어내야 32px 줄 한가운데에 놓인다.
 *
 * appearance:none으로 상자를 직접 그린다. accent-color만 주던 옛 코드는 상자를
 * 브라우저가 그려서, 마우스오버로 줄이 파래져도 체크박스 안쪽만 흰 사각형으로
 * 남았다("체크박스 부분만 색이 안 변한다"). 크롬은 기본 모습(appearance:auto)인
 * 체크박스의 background-color를 무시하므로 — !important를 붙여도 그렇다(실측) —
 * 상자를 직접 그리는 것 말고는 그 흰색을 없앨 방법이 없다.
 *
 * 아래 값은 크롬 기본 체크박스와 6배로 나란히 놓고 맞춘 것이다. 평소 모습은
 * 전과 같고(흰 바탕 + #767676 테두리), 달라지는 것은 마우스오버 줄뿐이다.
 * 크기 19px과 --brand(#3366CC)는 W 원본 값 그대로다.
 */
.card-table input[type="checkbox"] {
  -webkit-appearance:none; appearance:none; box-sizing:border-box;
  width:19px; height:19px; margin:0; cursor:pointer;
  border:1px solid #767676; border-radius:3px; background-color:#fff;
  vertical-align:middle; position:relative; display:inline-block;
}
/* 마우스가 올라간 줄에서만 바탕을 비운다 — 줄 색(#d0e2f7)이 그대로 비쳐
   체크박스가 줄에 묻는다. 체크된 것은 파란 상자라 그대로 둔다.
   선택자 둘은 위 마우스오버 규칙과 짝이다(줄 tr.row-hover / 칸 td.row-hover). */
.card-table .tui-grid-body-area tr.row-hover input[type="checkbox"]:not(:checked),
.card-table .tui-grid-body-area .row-hover input[type="checkbox"]:not(:checked) {
  background-color:transparent;
}
/* 체크 표시는 흰 갈고리다 — 상자를 파랗게 칠하고 그 위에 ::after로 그린다. */
.card-table input[type="checkbox"]:checked {
  background-color:var(--brand); border-color:var(--brand);
}
.card-table input[type="checkbox"]:checked::after {
  content:''; position:absolute; left:5.5px; top:1.5px; width:4.5px; height:10px;
  border:solid #fff; border-width:0 2.5px 2.5px 0; transform:rotate(45deg);
}
.card-table .tui-grid-row-header-checkbox,
.card-table .tui-grid-cell-row-header { text-align:center !important; padding:0 !important; }
.card-table .tui-grid-row-header-checkbox .tui-grid-cell-content,
.card-table .tui-grid-cell-row-header .tui-grid-cell-content {
  display:flex !important; align-items:center !important; justify-content:center !important;
  padding:0 !important; height:100% !important;
}
.card-table .tui-grid-row-header-checkbox label,
.card-table .tui-grid-cell-row-header label {
  display:inline-flex !important; align-items:center !important; justify-content:center !important;
  width:auto !important; height:auto !important; margin:0 !important; padding:0 !important;
  line-height:1 !important;
}
/* 라이브러리가 같은 자리에 자기 선을 그리는 경우 겹치지 않게 끈다. */
.card-table .tui-grid-frozen-border,
.card-table .tui-grid-frozen-border-top,
.card-table .tui-grid-frozen-border-bottom { display:none !important; }

/* 표 본문 자리 — .card-fill과 짝이다. 셀에서 머리띠를 뺀 나머지 높이를 갖고,
   그 안쪽 높이는 화면 스크립트의 fitGridHeight()가 표에 넣는다.
   min-height:0이 없으면 flex 항목이 내용 높이 밑으로 줄지 않아 셀을 넘친다. */
.card-table-body { flex:1; min-height:0; overflow:hidden; }

/* 바깥 테두리는 .card가 그린다 — 그리드가 자기 테두리를 겹쳐 그리지 않게 지운다. */
.card-table .tui-grid-container,
.card-table .tui-grid-header-area,
.card-table .tui-grid-header-area .tui-grid-table,
.card-table .tui-grid-body-area,
.card-table .tui-grid-body-container,
.card-table .tui-grid-content-area,
.card-table .tui-grid-rside-area,
.card-table .tui-grid-lside-area { border-top-width:0 !important; box-shadow:none !important; }
.card-table .tui-grid-header-area .tui-grid-cell,
.card-table .tui-grid-header-area .tui-grid-cell-header { border-top-width:0 !important; border-bottom-width:0 !important; }
.card-table .tui-grid-body-area tr:first-child .tui-grid-cell { border-top-width:0 !important; }
.card-table .tui-grid-border-line-top,
.card-table .tui-grid-border-line-bottom,
.card-table .tui-grid-border-line-left,
.card-table .tui-grid-border-line-right { display:none !important; }

/* 페이지 번호줄 — 표 본문과 이 줄을 가르는 선이 border-top이다(W의 #ddd로,
   셀 테두리와 같은 색이라 셀 안에서 한 단계 나뉜 칸처럼 읽힌다).
   바깥 여백은 걷어내되 버튼 크기·글꼴은 건드리지 않는다. line-height:0은
   컨테이너의 빈 줄 높이를 없애는 것으로, 버튼은 자기 값을 그대로 쓴다. */
.card-table .tui-grid-pagination {
  border-top:1px solid #ddd !important; background:#fff !important; text-align:center;
  height:auto !important; padding:6px 0 8px !important; margin:0 !important;
  box-sizing:border-box !important; line-height:0 !important;
}
.card-table .tui-grid-pagination .tui-pagination { margin:0 !important; }

/*
 * 페이지 번호 — 선택된 쪽을 메인 컬러로 칠한다. tui-pagination 기본값은
 * #4b96e6(라이브러리 고유의 하늘색 계열)이라 이 서비스의 파랑과 미묘하게 어긋난다.
 *
 * !important가 없는 이유 — lib/layout.php가 tui-pagination.css를 app.css보다
 * 먼저 <link>하므로, 명시도가 같으면 나중에 오는 이 파일이 이긴다.
 * 네 줄로 나뉜 이유는 원본이 모서리 칸의 좌·우 테두리를 따로 칠하기 때문이다 —
 * 하나라도 빠지면 첫/끝 번호에 옛 색 테두리가 한 변만 남는다.
 *
 * .card-table 안으로 한정하지 않는다. 표 형태와 무관하게 브랜드 색을 맞추는
 * 일이라 페이저가 있는 모든 화면에 같이 적용되는 게 맞다.
 */
.tui-pagination .tui-is-selected,
.tui-pagination strong { background:var(--brand); border-color:var(--brand); color:#fff; }
.tui-pagination .tui-is-selected:hover { background-color:var(--brand); }
.tui-pagination .tui-first-child.tui-is-selected { border-left-color:var(--brand); }
.tui-pagination .tui-last-child.tui-is-selected { border-right-color:var(--brand); }
/* 선택되지 않은 번호에 마우스를 올렸을 때도 같은 파랑으로 — W와 같다. */
.tui-pagination .tui-page-btn:not(.tui-is-selected):hover { color:var(--brand); }
/* 페이지 직접입력 칸의 현재 쪽 숫자(쓰는 화면이 아직 없지만 색은 같이 맞춘다). */
.tui-page-inputs .tui-page-current { color:var(--brand); }

/* 폼 공통 */
/* 칸 이름표. 굵기를 주지 않으면 작은 한글이 획이 가늘어 흐릿하게 읽힌다 —
   600으로 올리고 색도 한 단계 진하게 해서 값(13px/500 #4b5563)과 무게를 맞춘다.
   크기는 사용자 지시로 12 → 12.5px. */
.f-label { display:block; font-size:12.5px; font-weight:600; color:#4b5563; margin-bottom:4px; }
/*
 * 필수 항목 이름표에 긋는 형광펜 자국(사용자 지시). 붉은 별(*)을 대신하는
 * 표시다 — 별은 지웠고, 이 자국 하나가 "여기는 반드시"를 뜻한다.
 * 색은 노랑 → 초록으로 갔다가 사용자 지시로 노랑으로 되돌렸다.
 *
 * 이름표(.f-row > .f-label)가 아니라 그 안의 <span>에 거는 이유 — 이름표는 폭
 * 118px로 못박힌 칸이라, 거기에 배경을 깔면 글자가 끝난 뒤 빈 자리까지 칠해져
 * 형광펜이 아니라 색칠한 띠가 된다. 글자를 감싼 인라인 요소여야 글자 길이만큼만
 * 그어진다.
 *
 * 배경으로 긋는 이유 — border-bottom이나 text-decoration은 글자 아래 "선"이지
 * "칠한 자국"이 아니다. 글자 아랫동아리에 걸치는 두께의 띠를 깔아야 지나간
 * 형광펜처럼 보인다. 0.85는 잉크가 비치는 느낌을 남기는 값이다.
 *
 * 두께는 글자를 다 덮는다(사용자 지시로 6 → 7 → 8px → 글자 전체). 그래서 px이
 * 아니라 100%다 — 글자 크기가 바뀌어도 덮는 범위가 따라간다. 인라인 요소의
 * 배경 상자는 글꼴의 위아래 끝(ascent+descent)까지라, 100%면 받침과 꼬리까지
 * 들어온다.
 *
 * 다시 "글자 아랫동아리만 지나간" 모양으로 돌리려면 background-size의 세로를
 * px으로 주고(예: 100% 8px) background-position을 0 96%로 두면 된다 — 그 값이
 * 여기 있던 직전 모양이다. px이면 "1px만 더" 같은 말도 그대로 옮길 수 있다.
 *
 * 여백을 주지 않는다 — 인라인 요소라 좌우로 padding을 주면 글자가 그만큼 밀려
 * 다른 줄의 이름표와 왼쪽 끝이 어긋난다. 자국이 글자에 딱 붙는 대신 줄이 안 흔들린다.
 */
/*
 * ↑ 형광펜 자국은 걷었다(사용자 지시 2026-10-05). 지금 필수 표시는 이름 오른쪽의 노란
 * '필수' 딱지다 — 상품관리·입고 등록에서 먼저 바꾼 모양을 창고/로케이션 관리까지 맞추며
 * 여기 공용 규칙으로 올렸다. 되돌리려면 아래 ::after를 지우고 background-image를
 * linear-gradient(rgba(250,204,21,.85), rgba(250,204,21,.85)) / no-repeat / 100% 100%로.
 */
.f-req::after {
  content:'필수'; display:inline-block; margin-left:5px; padding:0 5px;
  font-size:10.5px; font-weight:600; line-height:16px; vertical-align:1px;
  color:#fff; background:#dc2626; border-radius:3px;   /* 진한 빨강 바탕 + 흰 글자(사용자 지시 2026-10-07) */
}
/*
 * 그 줄의 입력칸에도 같은 형광펜 색을 옅게 깐다(사용자 지시). 이름표만 칠하면
 * 눈이 왼쪽 열에서만 머무는데, 적어야 할 자리는 오른쪽이다 — 이름표와 칸이 한
 * 짝으로 묶여 보여야 "여기를 채워라"가 된다.
 *
 * 같은 색(250,204,21)을 알파만 낮춰 쓴다. 다른 노랑을 고르면 두 자국이 서로
 * 다른 표시처럼 읽힌다. 0.16은 글자(12.5px)가 그대로 읽히는 선에서 잡은 값이다.
 *
 * 이름표를 고른 뒤 :has()로 그 줄을 되짚는다 — 칸마다 클래스를 따로 붙이면
 * 이름표에는 긋고 칸에는 안 깔린 줄이 생긴다. 마크업은 한 곳(.f-req)만 손대고
 * 나머지는 CSS가 따라가게 둔다. (:has()는 이 파일이 이미 쓰고 있다.)
 *
 * :disabled는 뺀다 — 고객사는 등록 후 못 고치는 칸이라 회색(.bg-muted)으로
 * 잠가 두었다. 거기에 색을 깔면 "적어야 하는 칸"으로 잘못 읽힌다.
 */
/* 칸 바탕은 옅은 노랑(.16)에서 쨍한 #fff176으로 바꿨다(사용자 지시 2026-10-05 — 필수 칸만
   노랑, 나머지는 흰 바탕. 상품관리·입고 등록과 같은 값). 잠긴 칸(readonly·.bg-muted)도 뺀다. */
.f-row:has(.f-req) .f-input:not(:disabled):not([readonly]):not(.bg-muted) { background-color: #fff176; }
/* .f-row 없이 이름표와 칸을 한 상자에 세로로 쌓은 폼(창고 등록 — manager/location/
   write.php)에도 같은 색을 깐다. 이름표와 칸이 그 상자의 바로 아래 자식일 때만
   걸리게 '>'로 좁혔다 — 넓게 잡으면 필수 칸 하나가 옆 칸들까지 물들인다. */
:has(> .f-label .f-req) > .f-input:not(:disabled):not([readonly]):not(.bg-muted) { background-color: #fff176; }
/*
 * 필수 이름표에도 말풍선(.f-tip)을 달았지만(마우스를 올리면 "필수 입력 항목입니다"),
 * 물음표 커서는 끈다(사용자 지시). .f-tip의 cursor:help는 "설명이 더 있다"는
 * 신호라 카톤수량·안전재고처럼 물음표(.f-tip-q)를 단 칸에 맞는 것이고, 여기는
 * 형광펜 자국이 이미 뜻을 다 말하고 있어 커서까지 물음표가 되면 읽을 것이 더
 * 있는 것처럼 보인다.
 */
.f-tip:has(.f-req) { cursor: default; }
/*
 * 필수 말풍선은 이름표에 더 붙여 띄운다(사용자 지시 — 마우스와 너무 멀었다).
 * 기본 .f-tip은 이름표 위 7px인데, 이름표가 padding-top:7px를 갖고 있어 글자
 * 기준으로는 14px이 떠 버린다. 마우스는 글자 위에 있으므로 그만큼 멀게 느껴진다.
 * 5px씩 내려 글자에서 9px로 좁혔다. 꼬리(::before)도 같은 값만큼 함께 내려야
 * 말풍선과 꼬리가 떨어지지 않는다 — 한쪽만 고치면 꼬리가 공중에 뜬다.
 *
 * 카톤수량·안전재고 쪽 말풍선은 건드리지 않는다. 그쪽은 물음표(.f-tip-q)를
 * 겨냥해 올리는 거리라 이미 맞춰 둔 값이다.
 */
.f-tip:has(.f-req)::after  { bottom: calc(100% + 2px); }
.f-tip:has(.f-req)::before { bottom: calc(100% - 3px); }
/* 흰 바탕을 못박는다 — 폼 구획(.f-sec)이 하늘색이라 입력칸이 투명하면 바탕이
   비쳐 어디가 적는 자리인지 흐려진다. 검색 셀의 입력칸과 같은 짝이다.
   (비활성 칸의 .bg-muted는 Tailwind가 뒤에 실려 그대로 회색으로 남는다.) */
/*
 * 글자 12.5px — 이름표(.f-label)와 같은 크기다(사용자 지시로 13 → 12.5px).
 * 이제 이름표와 값은 굵기(500 vs 400)와 색으로만 갈린다.
 *
 * 높이는 29.75px로 함께 줄어든다: 여백 4.5×2 + 글자줄 18.75(12.5 × 1.5) +
 * 테두리 2. 옆에 나란히 서는 .f-switch / .f-radio-group / .f-val > .btn의
 * 높이(30.5px)와 0.75px 차이인데, 그 셋은 세로 가운데 정렬이라 눈에 띄지 않는다.
 * 더 정확히 맞추려면 그 셋도 29.75px로 내리면 된다.
 *
 * height를 직접 박지 않는 이유 — 이 클래스는 <textarea>에도 쓰여서(다른 화면),
 * 높이를 고정하면 여러 줄 입력이 한 줄로 눌린다.
 *
 * 이 값을 바꾸면 같은 줄에서 가운데를 맞추고 있는 셋을 함께 고쳐야 한다:
 * 이름표의 padding-top, .f-switch와 .f-radio-group의 min-height.
 *
 * 테두리 #d0d7e3 — 검색바의 입력칸(.sh-input / .filter-select, lib/layout.php)과
 * 같은 값이다. 전에 쓰던 hsl(214 32% 91%)(≈#e2e7ee)은 흰 바탕에서 거의 안 보여
 * 칸의 경계가 흐렸다(사용자 지시로 진하게).
 */
.f-input { width:100%; background-color:#fff; border:1px solid #d0d7e3; border-radius:6px; padding:4.5px 10px; font-size:12.5px; }

/* 숫자칸의 위아래 화살표(스피너)를 끈다(사용자 지시) — 검색바(.sh-input)에서
   이미 끈 것을 폼에도 똑같이 적용한다. 안전재고·유통기한 알림·치수·수량처럼
   자릿수가 있는 값은 한 칸씩 눌러 맞추지 않고, 화살표는 마우스를 올릴 때만
   나타났다 사라져 칸 안이 흔들려 보인다.
   두 줄이 필요한 이유: 크롬 계열은 스피너가 별도 가상요소라 그것을 없애야 하고,
   파이어폭스는 칸 자체를 textfield로 돌려야 안 나온다. */
.f-input[type=number] { -moz-appearance:textfield; appearance:textfield; }
.f-input[type=number]::-webkit-outer-spin-button,
.f-input[type=number]::-webkit-inner-spin-button { -webkit-appearance:none; margin:0; }

/*
 * 폼 안의 셀렉트 화살표 — 검색바(.filter-select, lib/layout.php)와 같은 SVG를
 * 쓴다(사용자 지시). 브라우저 기본 화살표는 OS·브라우저마다 모양과 크기가
 * 달라서, 한 화면에 검색바의 화살표와 나란히 놓이면 둘이 다른 물건처럼 보인다.
 *
 * appearance:none을 먼저 끄지 않으면 기본 화살표 위에 SVG가 겹쳐 둘로 보인다.
 * 오른쪽 padding 32px은 그 SVG가 앉을 자리다 — 글자가 화살표 밑으로 들어가지
 * 않게 비워 둔다.
 *
 * background-color(#fff)는 위 .f-input이 이미 갖고 있다. shorthand(background)가
 * 아니라 background-image로 따로 얹어야 그 흰 바탕이 지워지지 않는다.
 */
select.f-input {
  -webkit-appearance:none; -moz-appearance:none; appearance:none;
  padding-right:32px; cursor:pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234b5563' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center;
}
/* 포커스 링도 메인 컬러(#3366CC)를 옅게 깐 것이다 — 예전엔 Tailwind blue-600
   계열(rgb(37 99 235))이라 테두리색(--brand)과 미묘하게 갈렸다. */
.f-input:focus { outline:2px solid rgb(51 102 204 / .18); border-color:var(--brand); }

/*
 * 폼 구획 — 제목은 위쪽에 하늘색 띠로 따로 떼고, 칸들은 그 아래 흰 바닥에
 * 놓는다(사용자 지시).
 *
 * 앞서 상자 전체를 하늘색으로 칠했더니 흰 입력칸이 파란 바탕 다섯 덩어리 위에
 * 떠서, 정작 적는 자리보다 바탕이 먼저 보였다. 색을 띠에만 남기면 "여기부터
 * 이 묶음"이라는 표시 역할만 하고, 눈은 흰 바닥의 칸으로 간다.
 *
 * 색은 검색 셀(.card-search)과 같은 #E0EAF7 / #c5d5f0이다.
 */
/* 상자를 만들지 않는다(사용자 지시) — 테두리도 모서리도 없다. 묶음을 가르는
   일은 아래 제목 띠와 줄 사이 가로선이 대신한다. 좁은 패널에서 상자가 겹겹이
   쌓이면 테두리만 여러 겹으로 보인다. */
.f-sec { background:transparent; border:0; }

/*
 * 제목 띠 오른쪽 끝에 붙는 작은 버튼 — 지금은 '기타' 묶음의 [수정이력 보기]
 * 하나다(사용자 지시로 폼 안의 한 줄에서 띠로 올렸다).
 *
 * 높이 24px — 띠가 32px이라 기본 .btn(33px)은 애초에 안 들어간다. 위아래로 4px씩
 * 남겨 띠에 꽉 끼지 않게 한 값이다.
 *
 * 오른쪽으로 미는 것은 margin-left:auto다. .f-sec-title에 justify-content를 주는
 * 방법도 있지만, 그러면 제목만 있는 나머지 세 띠(기본정보·부피/중량정보·알림)의
 * 규칙까지 바뀐다 — 지금은 티가 안 나도 그쪽에 뭔가 하나 더 붙는 날 갈린다.
 */
.f-sec-btn {
  margin-left:auto; height:24px; padding:0 10px; border-radius:5px;
  font-size:12px; font-weight:600; line-height:1; cursor:pointer;
  border:1px solid var(--brand); background:#fff; color:var(--brand);
  white-space:nowrap;
}
.f-sec-btn:hover { background:#E0EAF7; }

/* 제목 띠 — 하늘색 바탕에 위아래 선. 왼쪽 세로 막대는 뺐다(사용자 지시).
   띠 자체가 이미 층을 만들고 있어 막대가 하는 일이 겹친다. */
.f-sec-title {
  display:flex; align-items:center;
  /* 띠 높이 32px, 글자 12.5px(사용자 지시로 34 → 32, 13.5 → 12.5).
     묶음이 넷이라 띠 하나가 2px씩만 줄어도 폼 전체에서 8px이 줄고, 그만큼
     칸이 더 보인다. 글자를 같이 줄인 것은 띠가 얇아진 만큼 위아래 여백도
     좁아져, 크기를 그대로 두면 글자가 띠에 꽉 차 보이기 때문이다. */
  height:32px; padding:0 12px;
  background:#E0EAF7;
  border-top:1px solid #c5d5f0; border-bottom:1px solid #c5d5f0;
  /* 굵기 500(사용자 지시로 700 → 600 → 500). 하늘색 띠와 짙은 파란 글자가 이미
     "제목"이라고 말하고 있어서 굵기까지 보탤 일이 없다.
     아래 이름표(.f-label 12.5px/600)보다 오히려 얇지만, 글자가 1px 크고 색과
     띠가 달라 층은 그대로 남는다 — 여기서 층을 만드는 것은 굵기가 아니다. */
  /* 13px / 600 — 이름표(.f-row > .f-label)가 12.5px/500이라 한때 글꼴이 완전히
     겹쳤다(사용자 확인). 크기와 굵기를 함께 올려 층을 만든다. 0.5px 차이는
     작아 보이지만 굵기와 겹쳐 작동하고, 띠 높이(32px) 안에도 그대로 들어간다.
     색(--brand-dark)과 하늘색 띠는 그대로다. */
  font-size:13px; font-weight:600; color:var(--brand-dark);
}
/* 맨 위 묶음은 위쪽 선을 뺀다 — 팝업 머리 바로 아래라 선이 두 줄로 겹친다. */
.f-sec:first-child .f-sec-title { border-top:0; }
/*
 * 칸을 두 열로 늘어놓는다(사용자 지시). 한 열일 때는 열다섯 칸이 세로로 길게
 * 늘어져 아래쪽 묶음을 보려면 늘 스크롤해야 했다.
 *
 * column-gap만 주고 row-gap은 주지 않는다 — 줄 사이 간격은 .f-row의 위아래
 * padding이 이미 만들고 있어, 여기서 또 주면 두 번 벌어진다.
 */
.f-sec-body {
  /* 위아래 여백을 같게 둔다(사용자 지시) — 아래가 10px일 때는 마지막 줄
     (바코드·카톤수량) 밑만 넓어 묶음이 아래로 처져 보였다.
     3px(사용자 지시로 2 → 3px). 실제 간격은 여기 3px에 .f-row의 세로 padding
     3px이 더해져, 첫 줄 위와 마지막 줄 아래가 모두 6px이다. */
  padding:3px 12px;
  display:grid; grid-template-columns:1fr 1fr; column-gap:18px;
}
/* 한 칸이 두 열을 다 쓰는 경우 — 안에 입력칸이 여럿이거나(규격 가로·세로·높이)
   값이 긴 것(이미지 경로)이다. 반 폭에 넣으면 글자가 다 안 보인다. */
.f-row-wide { grid-column:1 / -1; }

/*
 * 한 줄 = 이름표(왼쪽) + 값(오른쪽). 이름표를 값 위에 얹던 배치에서 바꿨다
 * (사용자 지시).
 *
 * 이름표 폭을 고정하는 것이 요점이다 — 폭이 글자 수를 따라가면 값의 왼쪽 끝이
 * 줄마다 어긋나 세로선이 안 선다. 92px은 '유통기한 임박알림(일)'처럼 긴 이름이
 * 두 줄로 접히는 것을 감안한 값이다(그래서 align-items도 flex-start다).
 */
/* 한 묶음 안의 칸들 사이에는 가로선을 두지 않는다(사용자 지시) — 그 칸들은
   이미 같은 편이라 갈라 놓을 이유가 없다. 선은 묶음을 가르는 일만 하고,
   그 일은 제목 띠(.f-sec-title)의 위아래 선이 맡는다. 안에서까지 선을 그으면
   층이 두 겹으로 겹쳐 무엇이 한 묶음인지가 흐려진다.
   줄 간격은 위아래 4px씩(사용자 지시로 6 → 4px). 선이 없어진 뒤 잠깐 6px까지
   벌렸는데, 두 열로 나뉘면서 한 열의 줄 수가 절반이 되어 그만큼 벌릴 이유가
   없어졌다. 8px(4+4)은 칸이 붙어 보이지 않을 만큼은 되는 최소치다. */
/* gap 5px — 이름표와 입력칸 사이(사용자 지시로 10 → 7 → 5px). 이름표 폭이
   118px로 고정이라 짧은 이름('고객사')에서는 글자 끝과 칸 사이가 이미 벌어져
   있는데, gap까지 넓으면 둘이 한 짝으로 안 읽힌다. 줄인 만큼 입력칸이 가져간다.
   더 줄이려면 gap이 아니라 이름표 폭(118px)을 손대야 한다 — 남은 5px은 글자와
   칸 테두리가 붙어 보이지 않게 하는 최소치다. */
.f-row { display:flex; align-items:flex-start; gap:5px; padding:3px 0; }
/*
 * 굵기 500(사용자 지시). .f-label 자체를 낮추지 않고 이 줄 안에서만 낮춘다 —
 * 같은 클래스를 검색바의 항목명(고객사·창고·로케이션·검색어)도 쓰는데, 그쪽은
 * "선이 너무 얇다"는 지적으로 600까지 올린 자리다. 전역으로 내리면 그 지적을
 * 되돌리는 셈이 된다.
 */
/* padding-top 7px — 입력칸(30.5px)의 가운데에 이름표 글자의 가운데를 맞춘 값이다.
   입력칸 중심 15.25px = 7 + (12.5×1.35)/2. 입력칸 높이를 바꾸면 여기도 같이.

   폭 118px — 104px일 때도 '상품사이즈 (mm)'·'카톤무게 (kg)' 같은 이름에서 단위만
   다음 줄로 넘어갔다(사용자 지적). 단위는 이름의 일부라 떨어지면 안 읽힌다.
   가장 긴 이름이 들어갈 만큼만 넓혔다 — 더 넓히면 입력칸이 그만큼 좁아진다. */
/*
 * white-space:nowrap — 이름표는 <br>을 적어 둔 자리에서만 줄을 바꾼다.
 *
 * 그냥 두면 브라우저가 폭이 빠듯할 때 알아서 끊는데, 한글은 글자 사이 어디서나
 * 끊을 수 있어서 '알림(수량)' 뒤의 물음표가 혼자 다음 줄로 떨어졌다(사용자
 * 지적 — 물음표는 닫는 괄호 바로 오른쪽에 붙어 있어야 한다).
 *
 * 넘칠 걱정은 없다 — 지금 가장 긴 이름('소비자가 (VAT포함)')도 118px 안에
 * 들어가고, 두 줄이 필요한 둘은 <br>로 직접 끊어 두었다.
 */
.f-row > .f-label { flex:0 0 118px; margin:0; padding-top:7px; line-height:1.35; font-weight:500; white-space:nowrap; }
.f-val { flex:1 1 auto; min-width:0; }

/*
 * 이름이 두 줄인 줄에서 입력칸을 세로 가운데로(사용자 지시).
 *
 * 기본 .f-row는 위쪽 정렬이다 — 한 줄짜리 이름과 입력칸을 맞추는 데는 그게
 * 맞고, 값 아래에 도움말이 붙어 길어져도 이름은 맨 위에 남아야 한다.
 * 하지만 이름이 두 줄로 접히면 이름 덩어리가 입력칸보다 커져서, 위쪽 정렬로는
 * 입력칸이 이름의 첫 줄 옆에 매달린 것처럼 보인다.
 *
 * padding-top을 0으로 되돌리는 것이 짝이다 — 그 7px은 "위쪽 정렬일 때 글자를
 * 입력칸 가운데에 맞추려던" 값이라, 가운데 정렬에서는 아래로 밀기만 한다.
 */
.f-row-mid { align-items:center; }
.f-row-mid > .f-label { padding-top:0; }

/*
 * 값 칸에 들어가는 버튼(이력 보기 등)은 옆·아래 입력칸과 같은 결로 맞춘다
 * (사용자 지시) — 테두리 #d0d7e3, 높이 30.5px, 글자 13px.
 *
 * .btn 기본값(테두리 #e2e8f0, 높이 33px)을 그대로 쓰면 같은 줄에 선 입력칸보다
 * 2.5px 크고 테두리는 옅어, 폼 안에서 혼자 다른 부품처럼 보인다. 여기서는
 * 값을 넣는 칸과 나란히 서는 자리라 그 규격을 따르는 편이 맞다.
 */
/* 글자 12px(사용자 지시로 13 → 12.5 → 12px), 높이 29.75px는 옆·아래
   입력칸(.f-input)과 같은 값이다. 이제 값(12.5px)보다 한 단계 작다 — 버튼은
   읽는 자리가 아니라 누르는 자리라, 값보다 앞설 이유가 없다.
   굵기는 .btn의 500을 그대로 둔다 — 작아진 만큼 무게로 또렷함을 지킨다.
   좌우 여백도 12px로 좁혀 글자가 작아진 만큼 버튼이 헐렁해 보이지 않게 한다. */
.f-val > .btn { height:29.75px; padding:0 12px; border-color:#d0d7e3; font-size:12px; }
/* 칸 아래 딸리는 설명. 값 칸 안에 들어가므로 이름표 폭만큼 자동으로 들여쓰인다. */
.f-help { font-size:11.5px; color:#9ca3af; line-height:1.45; margin-top:4px; }

/* 가로 x 세로 x 높이 사이의 곱셈 기호. 값이 아니라 칸 사이의 관계를 나타내는
   글자라 옅게 두고, flex가 줄이지 못하게 막는다(flex-shrink:0). */
.f-x { flex:0 0 auto; font-size:12px; color:#9ca3af; }

/* 가로 x 세로 x 높이처럼 좁은 칸이 나란히 설 때는 값을 가운데 둔다(사용자 지시).
   왼쪽 정렬이면 숫자가 x 기호에서 멀어져 어느 칸의 값인지 한눈에 안 잡히고,
   placeholder(가로/세로/높이)도 칸 왼쪽에 몰려 세 칸의 리듬이 깨진다. */
.f-input-c { text-align:center; }

/*
 * 여러 줄 입력칸(메모)은 block으로 둔다. textarea는 기본이 inline-block이라
 * 글자의 내려긋는 자리(descender)만큼 아래에 3~4px 틈이 생기는데, 그것이
 * 폼 맨 아래 여백으로 그대로 남는다(사용자 지시로 최소화).
 * resize:vertical — 가로로 늘이면 두 열 배치가 어그러진다. 세로만 허용한다.
 */
/* min-height 29.75px — 한 줄짜리 입력칸(.f-input)과 같은 높이다(사용자 지시).
   메모는 대개 비어 있거나 한 줄이라, 기본에서 세 줄을 잡고 있으면 그만큼이
   늘 빈 회색 상자로 남는다.
   resize:vertical은 그대로 둔다 — 길게 적을 때는 사용자가 끌어 늘리면 된다.
   가로는 막는다(두 열 배치가 어그러진다). */
textarea.f-input { display:block; resize:vertical; min-height:29.75px; }

/*
 * 오류 문구 — 글이 있을 때만 자리를 갖는다. 비어 있을 때 위 여백까지 0으로
 * 두지 않으면, 아무 일도 없는데 폼 아래가 그만큼 벌어져 보인다.
 */
#msg:empty { margin:0; }
#msg:not(:empty) { margin-top:10px; }

/*
 * 이름표 말풍선 — 설명이 필요한 칸에만 붙인다(사용자 지시).
 *
 *   <label class="f-label f-tip" data-tip="설명">파레트수량<i class="f-tip-q">?</i></label>
 *
 * 칸 아래 도움말(.f-help) 대신 이것을 쓰는 이유 — 도움말은 늘 자리를 차지해
 * 칸마다 붙이면 폼이 두 배로 길어진다. 설명이 필요한 사람만 잠깐 꺼내 보는
 * 쪽이 낫다.
 *
 * 브라우저 기본 title= 대신 직접 그리는 이유 — title은 뜨기까지 1~2초가
 * 걸리고 생김새를 못 정한다. 여기서는 곧바로 뜨고 폼과 같은 결로 보인다.
 *
 * JS 없이 CSS만으로 만든 것이라, ajax로 실려 온 폼에서도 따로 붙일 것이 없다.
 * 물음표(.f-tip-q)를 함께 두는 것이 요점이다 — 표시가 없으면 설명이 있는 줄을
 * 모르니 마우스를 올려 볼 이유도 없다.
 */
/*
 * 물음표는 이름 글자 바로 뒤에 붙인다(사용자 지시로 되돌렸다).
 *
 * 잠깐 이름표 오른쪽 끝에 고정(absolute)해 봤지만, 그러면 짧은 이름에서
 * 글자와 물음표 사이가 멀어져 무엇에 딸린 표시인지가 흐려졌다. 글자 흐름에
 * 얹어 두면 이름이 두 줄로 접힐 때 둘째 줄 끝을 따라가지만, 어차피 그 줄이
 * 이름의 끝이라 딸린 자리로는 그쪽이 맞다.
 *
 * vertical-align:1px — 글자의 밑선보다 살짝 올려 한글의 가운데에 맞춘다.
 */
.f-tip { position:relative; cursor:help; }
.f-tip-q {
  display:inline-flex; align-items:center; justify-content:center;
  width:13px; height:13px; margin-left:3px; vertical-align:1px;
  border-radius:50%; background:#cbd5e1; color:#fff;
  font-size:9.5px; font-weight:700; font-style:normal; line-height:1;
  /*
   * 물음표가 원 안에서 살짝 위로 뜬다(사용자 지적). align-items:center는 글자
   * 상자를 가운데 두는데, '?'는 밑선 위에만 그려지고 그 아래 내려긋는 자리
   * (descender)는 비어 있어서 — 상자는 가운데여도 잉크는 위로 몰린다.
   *
   * box-sizing:border-box + padding-top으로 글자 상자를 그만큼 내린다. 원의
   * 크기는 13px 그대로다(border-box라 padding이 안쪽을 먹는다).
   */
  box-sizing:border-box; padding-top:1px;
}
.f-tip:hover .f-tip-q { background:#3B82F6; }
.f-tip::after {
  content:attr(data-tip);
  position:absolute; left:0; bottom:calc(100% + 7px); z-index:5;
  width:max-content; max-width:210px;
  padding:7px 9px; border-radius:6px;
  background:#1f2937; color:#fff;
  font-size:11.5px; font-weight:400; line-height:1.5; white-space:normal;
  box-shadow:0 4px 12px rgba(0,0,0,.2);
  opacity:0; visibility:hidden; transition:opacity .12s;
  pointer-events:none;   /* 말풍선 위로 마우스가 지나가도 깜빡이지 않게 */
}
/* 말풍선 꼬리 — 이름표를 가리키게 아래쪽에 붙인다. */
.f-tip::before {
  content:''; position:absolute; left:11px; bottom:calc(100% + 2px); z-index:5;
  border:5px solid transparent; border-top-color:#1f2937;
  opacity:0; visibility:hidden; transition:opacity .12s;
  pointer-events:none;
}
.f-tip:hover::after, .f-tip:hover::before { opacity:1; visibility:visible; }

/*
 * 수정이력 팝업의 표 — 일시 / 작업 / 작업자 / 변경 내용.
 *
 * 한 번의 저장에서 여러 칸이 함께 바뀌는 것이 흔한데, 그것을 줄마다 나누면
 * 같은 시각·같은 사람이 칸 수만큼 반복된다. 그래서 한 저장 = 한 줄로 두고,
 * 바뀐 칸들은 마지막 칸 안에 목록으로 쌓는다.
 *
 * 껍데기(w-full/border/bg-muted)는 재고실사 팝업의 표와 같은 클래스다 — 여기서는
 * 그 표가 다루지 않는 것(세로 정렬·줄 사이 선·값의 강약)만 정한다.
 */
.ph-table { border-collapse:collapse; }
.ph-table th { font-weight:600; font-size:12.5px; color:#374151; }
.ph-table td { font-size:12.5px; color:#4b5563; border-top:1px solid #eef1f5; }
.ph-row:first-child td { border-top:0; }

/* 작업 구분(등록/수정) — 글자만 두면 옆 칸 값들과 섞여 읽힌다. 옅은 판을 깔아
   한 덩어리로 보이게 한다. 색은 검색 셀과 같은 계열이라 새 색이 늘지 않는다. */
.ph-act { display:inline-block; padding:1px 7px; border-radius:4px;
          background:#E0EAF7; color:var(--brand-dark); font-size:11px; font-weight:600; }

.ph-changes { margin:0; padding-left:0; list-style:none; }
.ph-changes li { padding:1px 0; line-height:1.55; }
.ph-changes b { font-weight:600; color:#374151; }
/* 옛값은 물러나고 새값이 앞으로 — 취소선까지 긋지는 않는다. 값 자체에 하이픈이
   섞이는 경우가 많아(코드·치수) 글자와 선이 엉킨다. */
.ph-old { color:#9ca3af; }
.ph-new { color:var(--brand-dark); font-weight:600; }
/* 등록 줄처럼 견줄 이전 값이 없는 경우. */
.ph-none { color:#9ca3af; }

/*
 * 라디오 버튼 — 셋 중 하나를 고르는 값(구분: 상품/세트상품/부자재).
 *
 * 브라우저가 그리는 동그라미를 그대로 쓰고 accent-color로 색만 브랜드 색에
 * 맞춘다. 직접 그리지 않는 이유 — 동그라미·점·포커스 링·읽기 전용 상태를 다시
 * 만들어야 하는데, 그렇게 얻는 것이 색 하나뿐이다.
 *
 * min-height 33px은 .f-switch와 같은 이유다: 줄이 위쪽 정렬이라, 입력칸과 같은
 * 높이를 줘야 옆 이름표와 가운데가 맞는다.
 */
/* flex-wrap을 쓰지 않는다(사용자 지시) — 두 열 배치에서 폭이 빠듯해지면
   '부자재'만 다음 줄로 떨어져 셋이 한 묶음으로 안 읽힌다. 간격을 16 → 13px로
   좁혀 셋이 한 줄에 들어가게 하고, 각 항목은 자기 글자만큼만 차지하게 둔다
   (flex:0 0 auto + nowrap). */
.f-radio-group { display:flex; align-items:center; gap:13px; min-height:30.5px; flex-wrap:nowrap; }
.f-radio { flex:0 0 auto; display:inline-flex; align-items:center; gap:5px; cursor:pointer; font-size:13px; color:#4b5563; white-space:nowrap; }
/* 색은 토글 스위치(.sw-track)와 같은 #3B82F6이다(사용자 지시). 같은 폼 안에서
   "고른 것"을 나타내는 표시가 둘(라디오·스위치)인데 색이 다르면 서로 다른
   뜻처럼 보인다. 이 값을 바꿀 때는 .f-switch 쪽도 같이. */
.f-radio input[type=radio] { width:15px; height:15px; margin:0; accent-color:#3B82F6; cursor:pointer; }

/*
 * 큰 라디오 — .f-radio-group에 .f-radio-lg를 더하면 동그라미 15 → 18px, 글자 13 → 14px로
 * 한 단계 키운다(사용자 지시 — 15px은 누르기 힘들다. 붙은 단추 모양은 써 보고 되돌렸다).
 * 글자까지 <label> 안이라 글자를 눌러도 골라진다. 지금은 입고 화면(manager/request)만 쓴다.
 */
.f-radio-group.f-radio-lg { gap:16px; }
.f-radio-lg .f-radio { gap:6px; font-size:14px; }
.f-radio-lg .f-radio input[type=radio] { width:18px; height:18px; }

/*
 * 토글 스위치 — 켜짐/꺼짐 둘뿐인 값에 쓴다(사용여부 등, 사용자 지시).
 *
 * 실제 값은 안에 숨은 <input type=checkbox>가 나른다. 보이는 것은 그 옆의
 * <span class="sw-track">이고, :checked 상태를 형제 선택자(~)로 받아 색과
 * 손잡이 위치를 바꾼다. 그림을 위해 checkbox를 없애지 않는 이유 — 키보드
 * 포커스·스페이스바 토글·폼 전송이 전부 공짜로 따라온다.
 *
 * 폼 전송 규칙에 주의: 체크가 풀린 checkbox는 아무것도 보내지 않는다. 그래서
 * 쓰는 쪽에서 같은 name의 hidden(value=0)을 앞에 두어 "꺼짐"도 값으로 가게
 * 한다 — 뒤에 오는 값이 이기므로 켜면 1, 끄면 0이 된다.
 */
/*
 * min-height 33px — 옆 이름표와 높이를 맞추기 위한 것이다(사용자 지시).
 *
 * 이 줄(.f-row)은 위쪽 정렬(align-items:flex-start)이고, 이름표는 입력칸
 * 글자에 맞추려고 padding-top:8px를 갖는다. 스위치는 22px밖에 안 돼서 그냥
 * 두면 이름표보다 위로 올라간다. 입력칸과 같은 33px 높이를 주면 안에서 가운데
 * 정렬(align-items:center)되어, 이름표 글자의 중심(8 + 12.5×1.35/2 ≈ 16.4px)과
 * 스위치 중심(33/2 = 16.5px)이 같은 자리에 온다.
 */
.f-switch { display:inline-flex; align-items:center; gap:9px; min-height:30.5px; cursor:pointer; user-select:none; }
.f-switch input { position:absolute; opacity:0; width:0; height:0; }
/*
 * 크기 35×19(40×22 → 34×19 → 35×20 → 36×20 → 지금. 사용자 지시로 가로·세로 1px씩).
 * 네 값이 한 묶음이라 따로 못 고친다:
 *   손잡이 = 높이 − 여백×2         → 19 − 4 = 15
 *   움직임 = 너비 − 손잡이 − 여백×2 → 35 − 15 − 4 = 16
 * 하나만 바꾸면 손잡이가 트랙 밖으로 나가거나 끝까지 안 간다.
 */
.sw-track {
  position:relative; flex:0 0 auto; width:35px; height:19px;
  background:#cbd5e1; border-radius:999px; transition:background .15s;
}
.sw-track::after {
  content:''; position:absolute; top:2px; left:2px; width:15px; height:15px;
  background:#fff; border-radius:50%; box-shadow:0 1px 2px rgba(0,0,0,.25);
  transition:transform .15s;
}
/* 켜짐 색 #3B82F6(사용자 지정). 이 서비스의 --brand(#3366CC)보다 한 톤 밝고
   푸른 쪽이다 — 스위치는 작아서 진한 색이면 덩어리로만 보인다.
   아래 포커스 링도 같은 색의 옅은 판이라 함께 맞춘다(rgb 59,130,246). */
.f-switch input:checked ~ .sw-track { background:#3B82F6; }
.f-switch input:checked ~ .sw-track::after { transform:translateX(16px); }
/* 키보드로 옮겨왔을 때 어디에 있는지 보이게 한다 — 마우스로 누를 때는 안 뜬다. */
.f-switch input:focus-visible ~ .sw-track { box-shadow:0 0 0 3px rgba(59,130,246,.25); }
.sw-label { font-size:13px; color:#4b5563; }
/*
 * 버튼 — 크기는 W 드라이브의 .btn-primary(adm/css/common.css)와 같다:
 * 높이 33px, 좌우 16px, 모서리 8px, 13px/500, line-height 1.
 *
 * height를 명시하는 것이 요점이다. 전에는 세로 padding(8px)으로 높이를 만들었는데
 * 그러면 글꼴의 줄 높이에 따라 실제 높이가 달라지고, <a>는 기본이 inline이라
 * 세로 padding이 줄 높이에 반영되지도 않는다. inline-flex + height로 고정하면
 * <a>든 <button>이든 같은 크기가 된다.
 *
 * gap은 "+ 상품 등록"처럼 아이콘·기호와 글자를 함께 넣을 때를 위한 것이다.
 */
.btn {
  display:inline-flex; align-items:center; justify-content:center;
  /* box-sizing을 못박는 이유 — 테두리가 있는 버튼(.btn-ghost)과 없는 버튼
     (.btn-primary)이 나란히 서는데, content-box면 테두리 1px이 위아래로 더해져
     같은 height를 줘도 2px 더 큰 버튼이 된다. 실제로 그 2px 때문에 '상품 등록'과
     '저장·닫기'가 계속 달라 보였다. border-box면 테두리가 height 안에 들어간다. */
  box-sizing:border-box;
  height:33px; padding:0 16px; border-radius:8px;
  font-size:13px; font-weight:500; line-height:1;
  gap:4px; white-space:nowrap; cursor:pointer;
}
.btn-primary { background:var(--brand); color:#fff; }
.btn-primary:hover { background:var(--brand-dark); }
.btn-ghost { background:#fff; border:1px solid hsl(214 32% 91%); }
.btn-ghost:hover { background:hsl(210 40% 96%); }

/*
 * 닫기처럼 "지금 하던 것을 그만두는" 버튼. 평소에는 .btn-ghost 그대로 조용히
 * 있다가 마우스를 올렸을 때만 붉은 계열로 바뀐다 — 누르면 되돌릴 수 없는 쪽
 * (입력하던 내용을 버리고 닫는다)이라는 신호다.
 *
 * .btn-ghost의 hover를 직접 바꾸지 않는 이유 — 그 클래스는 회수현황·택배사 설정·
 * 행 추가처럼 그만두는 것과 무관한 버튼들도 쓴다. 별도 클래스로 붙여 쓴다:
 *   <button class="btn btn-ghost btn-close">닫기</button>
 *
 * 색은 이 프로젝트의 danger(hsl(0 72% 51%))와 같은 색상환이다 — 새 빨강을
 * 들이지 않고 명도만 나눠 바탕·글자·테두리로 쓴다.
 */
.btn-close:hover {
  background:hsl(0 86% 97%); color:hsl(0 72% 51%); border-color:hsl(0 72% 75%);
}

/* 되돌릴 수 없는 동작(고친 내용 버리기 등). 위 .btn-close와 같은 danger 색을
   이번엔 바탕으로 채운다 — 확인창에서 이 버튼이 주 동작이지만, 붉으면 무심코
   누르기 어렵다. */
.btn-danger { background:hsl(0 72% 51%); color:#fff; }
.btn-danger:hover { background:hsl(0 72% 43%); }

/*
 * 표 안의 칸에 들어가는 작은 버튼(목록의 '수정'·'설정' 등).
 *
 * W 드라이브 /adm/export1/의 상세보기 칸 버튼과 같은 규격이다 — 그쪽 마크업이
 * `cell-btn inquiry-btn inquiring`이라 세 클래스에 흩어져 있는 값을 한데 모았다:
 *   .cell-btn           높이 24px · 좌우 10px · 모서리 6px · 13px/500
 *   .cell-btn.inquiry-btn  높이만 26px로 덮어씀
 *   .cell-btn.inquiring    배경 #fff9e6 · 글자 #c2410c · 테두리 #eab308
 *                          (hover: 배경 #F9E29C · 테두리 #c2410c)
 *
 * 원본의 `position:relative; top:1px`은 옮기지 않았다. 그건 그쪽 표에서 눈으로
 * 맞춘 보정값인데, 이 표는 칸 안쪽 세로 여백이 0이고 <td>의 vertical-align이
 * 가운데 정렬을 하므로 그대로 두면 오히려 1px 내려간다.
 *
 * .btn을 쓰지 않는 이유 — 위에서 .btn 높이를 33px로 고정했는데 표의 줄 높이는
 * 32px(.card-table)이라 칸 밖으로 삐져나온다. 전에는 .btn에 인라인 padding을
 * 덮어써서 줄였지만, 높이가 고정된 지금은 그 방법이 통하지 않는다.
 */
.cell-btn {
  display:inline-flex; align-items:center; justify-content:center;
  height:26px; padding:0 10px; border-radius:6px;
  font-size:13px; font-weight:500; line-height:1;
  white-space:nowrap; cursor:pointer;
  background:#fff9e6; color:#c2410c; border:1px solid #eab308;
}
.cell-btn:hover { background:#F9E29C; border-color:#c2410c; }

/*
 * 상품 검색 모달 — assets/js/product-picker.js가 <body> 끝에 만들어 넣는 마크업의
 * 스타일이다. 여러 화면이 공용으로 쓰므로 화면 쪽에 흩어 두지 않고 여기 모은다.
 *
 * Tailwind 유틸리티를 쓰지 않는 이유 — Play CDN은 나중에 주입된 마크업의 클래스를
 * MutationObserver로 뒤늦게 훑는다. 첫 표시에 스타일 없는 상태가 한 번 스친다.
 *
 * z-index 60은 사이드바(lib/layout.php의 .app-side, 50)보다 위여야 한다는 뜻이다 —
 * 낮추면 모달 위로 메뉴가 덮인다.
 */
.pp-wrap  { position:fixed; inset:0; z-index:60; }
.pp-dim   { position:absolute; inset:0; background:rgba(0,0,0,.4); }
.pp-panel {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  display:flex; flex-direction:column; max-height:86vh;
  width:min(880px, 94vw);   /* 680 → 880px — 목록이 표가 되며 칸이 여섯(사용자 지시 2026-10-05) */
  background:#fff; border:1px solid #ddd; border-radius:12px; overflow:hidden;
  box-shadow:0 12px 32px rgba(0,0,0,.22);
}
.pp-head {
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:12px 16px; border-bottom:1px solid hsl(214 32% 91%);
}
.pp-title { font-size:15px; font-weight:600; color:#111827; }
.pp-x     { border:0; background:none; padding:0 4px; font-size:22px; line-height:1; color:#6b7280; cursor:pointer; }
.pp-x:hover { color:#111827; }

/* min-height:0 — flex 자식이 내용만큼 부풀어 .pp-list의 스크롤이 안 생기는 것을 막는다. */
.pp-body { display:flex; flex-direction:column; min-height:0; padding:16px; }
.pp-meta {
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-top:8px; font-size:12px; color:#6b7280;
}
.pp-list {
  margin-top:8px; max-height:46vh; overflow-y:auto;
  border:1px solid hsl(214 32% 91%); border-radius:6px;
}
.pp-row {
  display:flex; align-items:center; gap:12px;
  padding:8px 12px; border-bottom:1px solid hsl(214 32% 91%); cursor:pointer;
}
.pp-row:last-child { border-bottom:0; }
.pp-row:hover      { background:hsl(210 40% 96%); }
.pp-row-main { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pp-code  { color:#6b7280; }
.pp-lot   { font-size:11px; color:var(--brand); }
.pp-badge { flex-shrink:0; font-size:12px; color:var(--brand); }
/* 줄 전체가 클릭 대상이라 이건 버튼이 아니라 '여기를 누르면 담긴다'는 표시다 —
   그래서 <button>이 아니고, 줄에 마우스를 올리면 같이 색이 찬다. */
.pp-add {
  flex-shrink:0; display:inline-flex; align-items:center; justify-content:center;
  height:26px; padding:0 10px; border-radius:6px;
  font-size:13px; font-weight:500; line-height:1; white-space:nowrap;
  background:#fff; border:1px solid hsl(214 32% 91%); color:#4b5563;
}
.pp-row:hover .pp-add { background:var(--brand); border-color:var(--brand); color:#fff; }
.pp-empty { padding:24px 12px; text-align:center; color:#6b7280; }
/* 목록 표(사용자 지시 2026-10-05) — 입고 상세 표(.rv-table)와 같은 결: 하늘색 머리줄, 칸 선.
   머리줄은 목록이 스크롤돼도 위에 붙어 있다(sticky). 줄 전체가 클릭 대상이라 .pp-row는 tr이다. */
.pp-table { width:100%; border-collapse:collapse; table-layout:fixed; font-size:12.5px; }
.pp-table th { position:sticky; top:0; z-index:1; background:#e8eef8; color:#111; font-weight:500;
               height:30px; border-bottom:1px solid #d0d7e3; border-right:1px solid #d0d7e3; padding:0 6px; }
.pp-table td { height:34px; border-bottom:1px solid hsl(214 32% 91%); border-right:1px solid hsl(214 32% 91%);
               padding:0 8px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pp-table th:last-child, .pp-table td:last-child { border-right:0; }
.pp-table tr.pp-row { display:table-row; cursor:pointer; }
.pp-table .pp-c { text-align:center; }
.pp-table .pp-r { text-align:right; font-variant-numeric:tabular-nums; }
.pp-table .pp-name .pp-badge { margin-left:4px; font-size:11.5px; }
.pp-table .pp-add { height:24px; padding:0 9px; font-size:12px; }
.pp-foot  { display:flex; justify-content:flex-end; padding:12px 16px; border-top:1px solid hsl(214 32% 91%); background:hsl(210 40% 96%); }

/*
 * 일반 모달 — 화면 위에 띄우는 작은 대화상자(재고실사 입력 등).
 *
 * 상품 검색 모달(.pp-*)과 겹쳐 보이지만 그쪽은 "검색해서 고르는" 전용 컴포넌트고
 * (assets/js/product-picker.js가 마크업까지 만든다), 이쪽은 화면이 자기 마크업을
 * 적어 넣고 껍데기만 빌려 쓰는 자리다. 둘을 하나로 합치지 않은 이유가 그것이다.
 *
 * z-index 60은 사이드바(lib/layout.php의 .app-side, 50)보다 위여야 한다는 뜻이다.
 */
/*
 * 2단 배치 — 왼쪽 목록, 오른쪽 상세. 목록을 보면서 한 줄씩 눌러 내용을 확인하는
 * 형태다. Z 드라이브의 .panel-container/.panel-left/.panel-right와 같은 생각이고,
 * 껍데기만 이 프로젝트의 .card(12px 모서리·#ddd 테두리)로 바꿔 썼다.
 *
 * .pnl-row가 .app-main(세로 flex)의 남은 높이를 전부 받고, 그 안에서 좌우로
 * 나눈다. 왼쪽은 남는 폭을 갖고(min-width:0이 없으면 표가 줄지 않아 넘친다),
 * 오른쪽은 폭이 고정이다 — 폼이 두 칸(grid-cols-2)이라 좁으면 글자가 눌린다.
 *
 * 오른쪽 패널이 열리고 닫히면 표의 폭이 바뀐다. 화면 쪽에서 그때마다
 * grid.refreshLayout()을 불러 열 너비를 다시 잡아야 한다.
 */
.pnl-row   { display:flex; gap:12px; flex:1 1 auto; min-height:0; }
.pnl-left  { flex:1 1 auto; min-width:0; }
/* 폭 700px — 두 열로 늘어놓기로 하면서 560에서 760까지 넓혔다가, 사용자 지시로
   조금 되돌렸다. 한 열에 이름표 92px + 입력칸이 들어가야 두 열로 나눈 뜻이
   서는데(입력칸이 이름표만 해지면 나눈 보람이 없다), 700이면 한 열에 약 300px가
   남아 그 선은 지킨다. 왼쪽 목록은 그만큼 넓어진다. */
.pnl-right { flex:0 0 700px; display:flex; flex-direction:column; overflow:hidden; }
/*
 * 상세 폼이 실리는 본문 — 좌우 여백을 두지 않는다(사용자 지시). 제목 띠
 * (.f-sec-title)가 패널 폭을 가득 채워야 묶음의 경계로 읽힌다. 여백이 있으면
 * 띠가 가운데 뜬 상자처럼 보인다.
 *
 * 위쪽도 0이다 — 첫 띠가 패널 머리에 바로 붙어야 그 사이에 흰 틈이 안 생긴다
 * (그래서 .f-sec:first-child .f-sec-title은 위쪽 선을 뺀다 — 머리의 아래선과
 *  겹치기 때문이다).
 *
 * 아래 4px만 남긴다(사용자 지시로 16 → 8 → 4px — 처음 열 때 세로 스크롤이
 * 안 생기게 하려고 마지막까지 줄였다). 마지막 칸이 패널 바닥에 닿아 붙어
 * 보이지 않을 만큼만이다. 좌우 여백은 안쪽(.f-sec-title / .f-sec-body)이
 * 각자 갖는다.
 *
 * 스크롤이 뜨고 안 뜨고는 결국 창 높이에 달렸다 — 폼이 고정 길이라, 화면이
 * 낮으면 어떤 여백값으로도 넘친다. overflow-y:auto는 그대로 두는 이유가
 * 그것이다(내용이 넘칠 때만 스크롤이 생긴다).
 */
.pnl-right .mdl-body { flex:1 1 auto; padding:0 0 4px; }

/*
 * 상세 패널의 머리띠는 왼쪽 목록과 같은 클래스(.card-table-head)를 그대로 쓴다 —
 * 여기에 따로 규칙을 두지 않는다.
 *
 * 전에는 모달용 .mdl-head에 같은 값을 베껴 적어 맞췄는데, 규칙이 둘이면 한쪽만
 * 고쳐져 높이가 어긋난다(실제로 그렇게 어긋났다). 두 머리띠는 나란히 서 있어서
 * 1~2px만 달라도 눈에 띈다 — 값을 맞추는 대신 규칙을 하나로 합쳐 벌어질 수
 * 없게 했다. 높이를 바꾸려면 .card-table-head 한 곳만 고치면 둘 다 따라온다.
 *
 * 다만 .card-table-head는 자기 자식을 양끝으로 벌리므로(justify-content),
 * 패널에서도 제목과 버튼 묶음이 각각 한 덩어리여야 한다.
 */

/*
 * 바탕색만 왼쪽과 다르게 — 오른쪽은 "지금 손대고 있는 곳"이라 눈이 먼저 가야 한다.
 * 브랜드색(--brand)을 그대로 채운다. 새 파랑을 만들지 않고 이미 있는 것을 쓴다.
 *
 * 여기서 바꾸는 것은 색뿐이다 — 높이(flex:0 0 44px)는 공유 규칙에서 그대로
 * 내려오므로 두 머리띠가 어긋날 일은 없다.
 */
.pnl-right .card-table-head  { background:var(--brand); border-bottom-color:var(--brand-dark); }
.pnl-right .card-table-title { color:#fff; }

/*
 * 파란 띠 위의 두 버튼 — 앞의 '파랑 위에 파랑'은 서로 묻혀서, 띠에서 확실히
 * 떨어져 나오는 쪽으로 바꿨다.
 *
 *   저장 = 흰 바탕 + 짙은 파란 글자. 띠와 가장 크게 갈리는 색이라 주 동작이 된다.
 *   닫기 = 띠를 살짝 밝힌 반투명 흰색 + 흰 테두리. 있는 줄은 알되 저장에 밀린다.
 *
 * 높이는 여기서 정하지 않는다 — 저장·닫기도 왼쪽 '상품 등록'과 같은
 * .card-table-head .btn(31px)을 그대로 쓴다. 나란히 보이는 자리라 예외를 두면
 * 곧바로 어긋나 보인다. 테두리를 넣어도 위 .btn의 box-sizing:border-box가
 * 높이를 지켜 준다.
 */
.pnl-right .card-table-head .btn-primary {
  background:#fff; color:var(--brand-dark); font-weight:600; border:0;
}
.pnl-right .card-table-head .btn-primary:hover { background:#E0EAF7; }
.pnl-right .card-table-head .btn-ghost {
  background:rgba(255,255,255,.14); color:#fff; border-color:rgba(255,255,255,.5);
}
/* 닫기의 붉은 hover는 그대로 살린다. 위 .btn-ghost 규칙이 클래스 셋(0,3,0)이라
   .btn-close:hover(0,2,0)를 눌러버리므로, 같은 깊이로 다시 적어 되살린다. */
.pnl-right .card-table-head .btn-close:hover {
  background:hsl(0 86% 97%); color:hsl(0 72% 51%); border-color:hsl(0 72% 75%);
}

/* 화면이 좁으면 상세를 줄여 목록이 먼저 자리를 갖게 한다. 여기서는 두 열을
   유지할 폭이 안 나오므로 한 열로 되돌린다 — 반 폭 입력칸이 이름표만 해지는
   것보다, 세로로 길어도 읽히는 편이 낫다. */
@media (max-width: 1439px) {
  .pnl-right { flex-basis:520px; }
  .f-sec-body { grid-template-columns:1fr; }
}

.mdl-wrap  { position:fixed; inset:0; z-index:60; }
.mdl-dim   { position:absolute; inset:0; background:rgba(0,0,0,.4); }
/* 확인창처럼 글 한 줄과 버튼 둘뿐인 모달용. 기본 980px는 물음 하나를 담기엔
   너무 넓어, 시선이 좌우로 흩어지고 버튼이 화면 끝에 가서 붙는다. */
.mdl-panel-sm { width:min(420px, 92vw) !important; }
/*
 * 아래 규격은 W 드라이브 /admin/leave/의 연차부여 설정 팝업(.lv-day-pop-*)을
 * 그대로 옮긴 것이다(사용자 지시).
 *
 * 가운데 세우는 방법만 원본과 다르게 남겨 둔다. W는 껍데기를 flex로 가운데
 * 정렬하는데, 우리 팝업은 jQuery .show()/.hide()로 여닫는다 — .show()가
 * display를 block으로 되돌려 flex 정렬이 풀린다. 그래서 지금처럼 absolute +
 * translate로 세운다. 눈에 보이는 결과는 같다.
 */
.mdl-panel {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  display:flex; flex-direction:column; max-height:88vh;
  width:min(980px, 94vw);
  /* 테두리를 뺀 것도 원본을 따른 것이다 — 그림자가 깊어져(0 20px 50px/.35)
     테두리까지 있으면 가장자리가 두 겹으로 보인다. */
  background:#fff; border-radius:12px; overflow:hidden;
  box-shadow:0 20px 50px rgba(0,0,0,.35);
}
/*
 * 머리와 발치는 같은 높이다(사용자 지시) — 한 규칙에서 함께 내려받는다.
 * 값을 두 곳에 따로 적으면 한쪽만 고쳐져 어긋난다(상세 패널 머리띠에서 실제로
 * 그랬다).
 *
 * 세로 여백을 padding으로 만들지 않는 것이 요점이다. padding으로 높이를 만들면
 * 안에 든 것에 따라 실제 높이가 갈린다 — 머리의 X는 30px, 발치의 버튼은 33px,
 * 확인창처럼 X가 없는 팝업의 머리는 글자 높이(24px)뿐이라 더 낮아진다.
 * 높이를 못박고 가운데 정렬(align-items:center)에 맡기면 안에 무엇이 들어가든
 * 같은 높이가 된다.
 *
 * flex를 고정하는 이유는 .card-table-head와 같다 — .mdl-panel이 세로 flex라
 * height만 주면 남은 자리에 따라 늘거나 줄 수 있다.
 */
.mdl-head, .mdl-foot { box-sizing:border-box; flex:0 0 56px; height:56px; padding:0 16px; }
.mdl-head {
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  border-bottom:1px solid #e5e7eb;
}
.mdl-title { font-size:16px; font-weight:700; color:#1f2937; }
/*
 * 닫기 X — W /admin/leave/의 .lv-day-pop-close 규격이다(30×30, 6px 모서리,
 * SVG 20px). 정사각 자리에 십자를 놓고 마우스를 올리면 회색 판이 깔린다.
 * 글리프(&times;)가 아니라 SVG를 쓰는 이유 — 글꼴마다 크기와 세로 위치가 달라
 * 가운데가 맞지 않는다.
 */
.mdl-x {
  height:30px; width:30px; border-radius:6px;
  display:inline-flex; align-items:center; justify-content:center;
  padding:0; border:0; background:none; color:#9ca3af; cursor:pointer;
  transition:background .15s, color .15s;
}
.mdl-x:hover { background:#f3f4f6; color:#6b7280; }
.mdl-x svg { width:20px; height:20px; }
/* 본문 — W의 .lv-day-pop-body(위 12 / 좌우 16 / 아래 16, 줄 사이 8px).
   min-height:0은 우리 쪽에서 더한 것이다: flex 자식이 내용만큼 부풀어
   안쪽 스크롤이 안 생기는 것을 막는다. */
.mdl-body  {
  display:flex; flex-direction:column; gap:8px; min-height:0;
  padding:12px 16px 16px; overflow-y:auto;
}
/* 발치 — 원본은 바탕이 흰색이다. 전에 깔아 두었던 옅은 파란 띠를 걷어낸다.
   높이·좌우 여백은 위 머리와 함께 쓰는 규칙에서 온다. */
.mdl-foot  {
  display:flex; align-items:center; justify-content:flex-end; gap:8px;
  border-top:1px solid #e5e7eb; background:#fff;
}
/*
 * 발치 버튼 — W의 .lv-btn 규격(33px, 좌우 12px, 모서리 7px, 13px/600).
 * 목록·머리띠에서 쓰는 .btn(좌우 16px, 8px, 500)보다 조금 작고 단단하다.
 *
 * 주 버튼의 파랑은 원본(#1565c0)이 아니라 우리 --brand를 그대로 쓴다 —
 * 가져온 것은 폼의 짜임이지 이 서비스의 색이 아니다.
 */
.mdl-foot .btn { padding:0 12px; border-radius:7px; font-weight:600; }
/* 보조 버튼의 테두리·글자색도 원본 값(#d1d5db / #4b5563)으로 맞춘다. */
.mdl-foot .btn-ghost { border-color:#d1d5db; color:#4b5563; }
.mdl-foot .btn-ghost:hover { background:#f9fafb; }

/* ═══════════════════════════════════════════════════════════════════════════
 * 리스트 카드 (.rjp-card / .rjp-grid)
 *
 * 출처는 express(Z 드라이브) /company/receipt_jp.php 와 /company/css/common.css 다.
 * 값은 원본 그대로고 선택자만 두 가지로 바꿨다.
 *   .rjp-card  카드 껍데기 — 테두리·머리띠·버튼·드롭다운·pill
 *   .rjp-grid  표 자체 — 글자·머리줄·체크박스·칸 테두리·페이지 번호줄
 *
 * 쓰는 화면은 지금 둘이다 — manager/product/list.php 의 상품목록과
 * manager/sample/list.php 의 참고용 샘플. 한 규칙에서 둘이 나와야 한쪽만
 * 고쳐져 갈리지 않으므로 화면이 아니라 여기에 둔다.
 *
 * 위 .card-table 묶음과는 별개의 껍데기다. 두 벌을 한 요소에 같이 입히지 말 것 —
 * 같은 값을 다른 명시도로 두 번 선언하게 되어, 어느 쪽이 이기는지가 선언 순서에
 * 달린다. .rjp-card 를 쓰는 화면은 .card / .card-table 을 떼고 쓴다.
 *
 * 다른 화면에는 영향이 없다 — 모든 규칙이 이 두 클래스 안으로 한정돼 있고,
 * 두 이름은 위 화면 둘 말고는 어디에도 붙지 않는다.
 * ═══════════════════════════════════════════════════════════════════════════ */
/* 원본은 :root 에 있던 값이다. WMS 에는 없는 이름이라 이 블록에만 세워 둔다. */
.rjp-card { --color-primary:#3366cc; --color-primary-light:#eef3ff; }

/* ── 리스트 카드 (dash-card 보강) ── */
.rjp-card .dash-card { border:1px solid #ddd; border-radius:12px; overflow:hidden; background:#fff; }
.rjp-card .dash-card-header { padding:3px 16px; min-height:44px; height:44px; display:flex; align-items:center; justify-content:space-between; border-bottom:1px solid #d1d5db; background:#e5e7eb; }
.rjp-card .dash-card-body { padding:16px; }

/* ── 버튼 ── */
.rjp-card .btn-primary {
  display: inline-flex; align-items: center; justify-content: center;
  height: 33px; padding: 0 16px; border-radius: 8px;
  font-size: 13px; font-weight: 500; line-height: 1; color: #fff;
  background: var(--color-primary); border: none; cursor: pointer;
  gap: 4px; transition: opacity 0.15s; white-space: nowrap;
}
.rjp-card .btn-primary:hover { opacity: 0.9; }

.rjp-card .btn-outline {
  display: inline-flex; align-items: center; justify-content: center;
  height: 33px; padding: 0 16px; border-radius: 8px;
  font-size: 13px; font-weight: 500; line-height: 1;
  color: var(--color-primary); background: #fff;
  border: 1.5px solid var(--color-primary); cursor: pointer;
  gap: 4px; transition: background 0.15s; white-space: nowrap;
}
.rjp-card .btn-outline:hover { background: var(--color-primary-light); }

/* ── btn-outline 빨간 테두리 오버라이드 ── */
.rjp-card .btn-outline { color:#BA0000 !important; border-color:#BA0000 !important; }
.rjp-card .btn-outline:hover { background:#fef2f2 !important; }
.rjp-card .btn-outline.keep-blue { color:#3366cc !important; border-color:#3366cc !important; }
.rjp-card .btn-outline.keep-blue:hover { background:#eef3ff !important; }
.rjp-card .dash-card-header .btn-outline { padding: 0 14px !important; }

/* ── 드롭다운 메뉴 (excel-menu) ── */
.rjp-card .excel-dropdown .btn-outline { display:inline-flex; align-items:center; gap:2px; }
@keyframes excelMenuIn { from { opacity:0; transform:translateY(-4px);} to { opacity:1; transform:translateY(0);} }
.rjp-card .excel-menu { position:absolute; top:calc(100% + 6px); right:0; z-index:50; min-width:260px; background:#fff; border:1px solid #d1d5db; border-radius:10px; box-shadow:0 8px 24px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06); padding:6px; animation:excelMenuIn 0.12s ease-out; }
.rjp-card .excel-menu-item { display:flex; align-items:center; gap:10px; width:100%; padding:10px 12px; border:0; background:transparent; border-radius:8px; cursor:pointer; text-align:left; transition:background 0.12s; }
.rjp-card .excel-menu-item:hover { background:#E0EAF7; }
.rjp-card .excel-menu-ico { display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; border-radius:9px; flex-shrink:0; }
.rjp-card .excel-menu-text { display:flex; flex-direction:column; gap:2px; line-height:1.2; }
.rjp-card .excel-menu-title { font-size:13px; font-weight:600; color:#1f2937; }
.rjp-card .excel-menu-desc { font-size:11px; color:#6b7280; }
.rjp-card .excel-menu-sep { height:1px; background:#f3f4f6; margin:2px 4px; }

/* 드롭다운 상단 안내(사은품/이벤트는 상품관리에서 설정 — receipt_jp 전용) */
.rjp-card .excel-menu-notice { display:flex; align-items:center; gap:10px; padding:10px 6px 10px 12px; margin:-2px 0 4px; background:#ffe6cc; border:1px solid #ffbd91; border-radius:8px; }
.rjp-card .excel-menu-notice .notice-ico { width:24px; height:24px; flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; border-radius:50%; background:#fb7d2f; color:#fff; }
.rjp-card .excel-menu-notice .notice-text { font-size:12px; color:#5c1f08; line-height:1.35; }
.rjp-card .excel-menu-notice .notice-text b { color:#9a3412; font-weight:700; }
.rjp-card .excel-menu-notice .notice-link { flex-shrink:0; height:26px; padding:0 10px; display:inline-flex; align-items:center; gap:4px; background:#fb7d2f; color:#fff; border:1px solid #c2410c; border-radius:6px; font-size:12px; font-weight:600; text-decoration:none; white-space:nowrap; cursor:pointer; transition:background 0.12s; }
.rjp-card .excel-menu-notice .notice-link:hover { background:#c2410c; }

/* 커스텀 툴팁 (page-specific) */
.rjp-card .has-tooltip { position:relative; display:inline-block; }
.rjp-card .custom-tooltip { position:fixed; background:#1f2937; color:#fff; font-size:12px; font-weight:500; line-height:1.5; padding:8px 12px; border-radius:6px; white-space:nowrap; box-shadow:0 6px 16px rgba(0,0,0,0.2), 0 2px 4px rgba(0,0,0,0.1); opacity:0; visibility:hidden; transition:opacity 0.1s, visibility 0.1s; pointer-events:none; z-index:9999; letter-spacing:-0.2px; }
.rjp-card .custom-tooltip::after { content:''; position:absolute; top:100%; left:50%; transform:translateX(-50%); border:6px solid transparent; border-top-color:#1f2937; }
.rjp-card .has-tooltip:hover .custom-tooltip { opacity:1; visibility:visible; }

/* ── 상태 pill / cell-btn ── */
/* .status-pill 만 .rjp-card 밖으로 빼 전역으로 둔다 — 고객사 알약 라벨을
   상품관리(.rjp-grid)와 재고관리(.card-table)가 같이 쓰기 때문이다(사용자 지시).
   한쪽 안에 가둬 두면 다른 표에서는 클래스만 붙고 모양이 안 나온다.
   값은 express 원본 그대로다. */
.status-pill { display:inline-flex; align-items:center; justify-content:center; min-width:0; height:22px; padding:0 14px; border-radius:11px; font-size:13px; font-weight:500; border:1px solid; opacity:1; white-space:nowrap; letter-spacing:-0.2px; }
/* 사용여부 라벨(lib/layout.php gridUsePill) — 70px 칸에 들게 작게(사용자 지시 2026-10-05).
   vertical-align:middle — 칸 가운데에 서게. */
.status-pill.use-pill { height:18px; padding:0 7px; border-radius:9px; font-size:11.5px; vertical-align:middle; }
.rjp-card .cell-btn { display:inline-flex; align-items:center; justify-content:center; height:24px; padding:0 10px; border-radius:6px; font-size:13px; font-weight:500; line-height:1; cursor:pointer; transition:none; border:1px solid #b2dcc3; background:#e0f2e9; color:#1b7a3d; white-space:nowrap; }
.rjp-card .cell-btn:hover { background:#c9e8d6; border-color:#1b7a3d; }
.rjp-card .cell-btn.primary { background:#f3f4f6; color:#374151; border-color:#d1d5db; }
.rjp-card .cell-btn.primary:hover { background:#d1d5db; color:#111; border-color:#6b7280; }
.rjp-card .cell-btn.inquiring { background:#fff9e6; color:#c2410c; border-color:#eab308; font-weight:500; }
.rjp-card .cell-btn.inquiring:hover { background:#F9E29C; border-color:#c2410c; }
/* 진행중 — 상세/문의(.inquiring 노랑)와 구분되도록 파랑. 이 앱의 진행형 상태(입고완료·운송중 등) 팔레트와 동일. */
.rjp-card .cell-btn.pending { background:#e3f0fd; color:#1565c0; border-color:#b8d7f4; font-weight:500; }
.rjp-card .cell-btn.pending:hover { background:#c9e2fa; border-color:#1565c0; }
.rjp-card .cell-btn.done { background:#e0f2e9; color:#1b7a3d; border-color:#b2dcc3; font-weight:500; }
.rjp-card .cell-btn.done:hover { background:#c9e8d6; border-color:#1b7a3d; }
.rjp-card .cell-btn.view { background:#fef3c7; color:#b45309; border-color:#facc15; font-weight:500; }
.rjp-card .cell-btn.view:hover { background:#fde68a; color:#92400e; border-color:#eab308; }

/* ── TUI Grid (.rjp-grid) ── */
.rjp-grid, .rjp-grid * {
  font-family:'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, sans-serif !important;
}
.rjp-grid .tui-grid-cell,
.rjp-grid .tui-grid-cell-header,
.rjp-grid .tui-grid-cell-content { font-size:13px !important; }
.rjp-grid .tui-grid-header-area .tui-grid-cell,
.rjp-grid .tui-grid-header-area .tui-grid-cell-header { font-weight:450 !important; }

/* 25px — 원본(express)은 19px인데 사용자 지시로 2px씩 세 번 키웠다. 줄 높이가
   34px(list.php의 rowHeight)이라 위아래로 4.5px씩 남는다 — 더 키우려면 줄부터.
   다른 목록 화면 33곳은 .card-table 쪽 체크박스(19px)를 그대로 쓴다 — 이 규칙은
   .rjp-grid를 쓰는 두 화면(상품관리·샘플)에만 걸린다. 전부 맞추려면 그쪽도 같이. */
.rjp-grid input[type="checkbox"] { width:25px; height:25px; cursor:pointer; accent-color:#3366CC; margin:0; vertical-align:middle; }
.rjp-grid .tui-grid-row-header-checkbox,
.rjp-grid .tui-grid-cell-row-header { text-align:center !important; padding:0 !important; }
.rjp-grid .tui-grid-row-header-checkbox .tui-grid-cell-content,
.rjp-grid .tui-grid-cell-row-header .tui-grid-cell-content { display:flex !important; align-items:center !important; justify-content:center !important; padding:0 !important; height:100% !important; }
.rjp-grid .tui-grid-row-header-checkbox label,
.rjp-grid .tui-grid-cell-row-header label { display:inline-flex !important; align-items:center !important; justify-content:center !important; width:auto !important; height:auto !important; margin:0 !important; padding:0 !important; line-height:1 !important; }

.rjp-grid .tui-grid-container,
.rjp-grid .tui-grid-header-area,
.rjp-grid .tui-grid-content-area { border-top:none !important; }

.rjp-grid,
.rjp-grid .tui-grid-container,
.rjp-grid .tui-grid-header-area,
.rjp-grid .tui-grid-header-area .tui-grid-cell,
.rjp-grid .tui-grid-header-area .tui-grid-cell-header,
.rjp-grid .tui-grid-body-area,
.rjp-grid .tui-grid-body-container,
.rjp-grid .tui-grid-content-area,
.rjp-grid .tui-grid-rside-area,
.rjp-grid .tui-grid-lside-area,
.rjp-grid .tui-grid-table,
.rjp-grid .tui-grid-row,
.rjp-grid .tui-grid-cell,
.rjp-grid .tui-grid-cell-row-header,
.rjp-grid .tui-grid-cell-dummy,
.rjp-grid .tui-grid-summary-area { background:#fff !important; background-color:#fff !important; }

.rjp-grid .tui-grid-header-area,
.rjp-grid .tui-grid-header-area .tui-grid-cell,
.rjp-grid .tui-grid-header-area .tui-grid-cell-header,
.rjp-grid .tui-grid-header-area .tui-grid-cell-row-header { background:#e5e7eb !important; background-color:#e5e7eb !important; }

.rjp-grid .tui-grid-header-area .tui-grid-cell,
.rjp-grid .tui-grid-header-area .tui-grid-cell-header,
.rjp-grid .tui-grid-header-area .tui-grid-cell-row-header { border-top-width:0 !important; border-bottom-width:0 !important; }
.rjp-grid .tui-grid-body-area tr:first-child .tui-grid-cell { border-top-width:0 !important; }
.rjp-grid .tui-grid-header-area,
.rjp-grid .tui-grid-header-area .tui-grid-table,
.rjp-grid .tui-grid-body-area,
.rjp-grid .tui-grid-body-container,
.rjp-grid .tui-grid-rside-area,
.rjp-grid .tui-grid-lside-area { border-top-width:0 !important; border-bottom-width:0 !important; box-shadow:none !important; }
.rjp-grid .tui-grid-header-area::after,
.rjp-grid .tui-grid-header-area::before,
.rjp-grid .tui-grid-body-area::before,
.rjp-grid .tui-grid-body-area::after { display:none !important; content:none !important; }
.rjp-grid .tui-grid-header-area { border-bottom:1px solid #ddd !important; }
.rjp-grid .tui-grid-cell { border-right:1px solid #e5e7eb !important; border-left-width:0 !important; }
/* 항목명 칸 사이 경계선 — 본문 칸과 달리 #d1d5db 다(사용자 지시).
   원본(express)은 여기도 본문과 같은 #e5e7eb 인데, 머리줄 바탕이 바로 그 #e5e7eb 라
   선이 바탕에 묻혀 항목명이 한 칸으로 이어져 보인다. 본문은 바탕이 흰색이라
   같은 색이어도 선이 드러난다 — 그래서 값은 같은데 한쪽만 안 보였다.
   #d1d5db 는 머리띠(.dash-card-header)의 아래 선과 같은 색이라 따로 노는 값이 아니다. */
.rjp-grid .tui-grid-header-area .tui-grid-cell-header { border-right:1px solid #d1d5db !important; }

/* 헤더 셀 높이 통일 (소팅/필터 아이콘 유무 영향 제거) */
.rjp-grid .tui-grid-header-area .tui-grid-cell-content { display:inline-flex !important; align-items:center !important; justify-content:center !important; height:100% !important; line-height:1 !important; }
.rjp-grid .tui-grid-btn-sorting,
.rjp-grid .tui-grid-btn-filter { vertical-align:middle !important; line-height:1 !important; }

/* 행 배경 (단건/엑셀/API수집) */
.rjp-grid .row-method-single .tui-grid-cell { background:#FFEAEA !important; }
.rjp-grid .row-method-excel  .tui-grid-cell { background:#e0f2e9 !important; }
.rjp-grid .row-method-api    .tui-grid-cell { background:#FFF9B6 !important; }

/* ── 고른 줄 (원본에 없는 규칙 — 사용자 지시) ────────────────────────────────
 *
 * 칸 하나를 눌러도 그 줄 전체가 밝아진다. 클래스는 아래 스크립트가 그리드의
 * addRowClassName 으로 넣는다.
 *
 * 선택자가 <tr> 이 아니라 칸(td)인 이유 — TOAST 는 "행 클래스"를 <tr> 이 아니라
 * 그 줄의 칸 하나하나에 붙인다(실측). 고정칸(frozenCount:10)이 다른 <table> 로
 * 갈라져 있어도 한 규칙으로 양쪽이 다 밝아지는 것이 그 덕이다. 바로 위
 * .row-method-* 규칙이 ".row-method-single .tui-grid-cell" 로 적혀 있는데,
 * 그건 이 구조에서는 맞지 않아 원본에서도 걸리지 않는다 — 따라 적지 않았다.
 *
 * 선택자를 이렇게 길게 쓰는 이유 — 바로 위 ".rjp-grid … .tui-grid-cell 는
 * 흰색"이 !important 라, 같은 무게로는 못 이긴다. !important 끼리는 선택자가
 * 좁은 쪽이 이기므로 한 단계를 더 얹었다.
 *
 * 체크박스·순번 칸(.tui-grid-cell-row-header)도 .tui-grid-cell 을 같이 달고
 * 있어서 한 규칙에 들어온다 — 그래야 "해당 라인 전체"가 된다.
 *
 * 색은 앱의 마우스오버(#d0e2f7)보다 한 톤 진하다 — 둘이 겹쳐도 지금 고른 줄이
 * 어느 것인지 구분된다.
 */
.rjp-grid .tui-grid-body-area .tui-grid-cell.row-sel { background:#b6d2f2 !important; background-color:#b6d2f2 !important; border-right-color:#8fb4e0 !important; }
/*
 * 등록 중인 새 줄(사용자 지시 — 보라색 #E3C0F3). '상품 등록'·'창고 등록'을 누르면
 * 표 맨 위에 끼우는 줄이다(lib/layout.php의 gridNewRowAdd가 이 클래스를 붙인다).
 * 아직 저장 전인 줄이라 "고른 줄"의 파랑과 색을 갈랐다.
 *
 * 그 줄은 고른 줄(.row-sel)이기도 하다 — 선택자 무게를 .row-sel과 같게 두고 뒤에
 * 적어서 둘이 겹치면 이쪽이 이긴다. 순서를 바꾸면 파랗게 덮인다.
 */
.rjp-grid .tui-grid-body-area .tui-grid-cell.row-new { background:#E3C0F3 !important; background-color:#E3C0F3 !important; border-right-color:#c99ae0 !important; }

/* TUI Grid 상단 border-line 숨김 */
.rjp-grid .tui-grid-border-line-top,
.rjp-grid .tui-grid-border-line-bottom,
.rjp-grid .tui-grid-frozen-border-top,
.rjp-grid .tui-grid-frozen-border-bottom { background:transparent !important; border:0 !important; display:none !important; }
.rjp-grid .tui-grid-frozen-border { background:#dbdee3 !important; width:2px !important; border:0 !important; }

/* TUI 페이지네이션 */
.rjp-grid .tui-grid-pagination { border-top:1px solid #ddd !important; padding:5px 0 !important; background:#fff !important; text-align:center; margin:0 !important; }
.rjp-grid .tui-pagination .tui-page-btn.tui-is-selected { background-color:#3366CC !important; border-color:#3366CC !important; color:#fff !important; }
.rjp-grid .tui-pagination .tui-page-btn:not(.tui-is-selected):hover { color:#3366CC !important; }

/* 빈 리스트 문구의 줄바꿈 — TUI Grid 는 문구를 <p> 의 텍스트로 넣어 <br> 이 안 먹으므로,
   문자열의 개행을 pre-line 으로 살린다. (setGridEmptyMessage 참고)
   원본은 페이지 전체에 걸었지만, 위 상품목록 표까지 번지지 않게 .rjp-grid 안으로 좁혔다. */
.rjp-grid .tui-grid-layer-state-content p { white-space:pre-line; color:#6b7280; }

/* ── 그리드 로딩 레이어 ("Loading data." + 프로그레스바) ──
   기본값은 <p>만 position:absolute 로 레이어 정중앙에 고정되고 바는 상단(padding-top:50px)에 남아
   그리드가 높을수록 둘 사이가 크게 벌어진다. content 를 세로 중앙 정렬한 뒤
   column-reverse 로 바를 문구 바로 위에 붙인다. (DOM 순서: <p> → 바) */
.rjp-grid .tui-grid-layer-state-content {
  position:absolute !important;
  top:50% !important;
  left:0 !important;
  right:0 !important;
  transform:translateY(-50%) !important;
  padding-top:0 !important;
  display:flex !important;
  flex-direction:column-reverse !important;
  align-items:center !important;
  gap:6px !important;
}
.rjp-grid .tui-grid-layer-state p { position:static !important; margin-top:0 !important; }
.rjp-grid .tui-grid-layer-state-loading { margin:0 !important; }

/* 바깥(.rjp-card)이 세로 flex, 안쪽 .dash-card 가 남은 높이를 다 갖는다.
   아래 복사본은 카드가 제 높이(600px)를 들고 있어 이 규칙이 필요 없지만,
   위 카드는 .card-fill 로 화면 아래까지 늘어나야 해서 높이를 흘려보내야 한다. */
.rjp-card.card-fill { display:flex; flex-direction:column; }
/* 안쪽 카드도 세로 flex 여야 한다 — 그래야 머리띠를 뺀 나머지가 표(.card-table-body)
   로 내려간다. 아래 복사본은 마크업에 같은 값이 인라인으로 붙어 있다. */
.rjp-card.card-fill > .dash-card { flex:1; min-height:0; display:flex; flex-direction:column; overflow:hidden; }

/* ── 순번(No) 칸과 첫 데이터 열 사이의 경계선 ────────────────────────────────
 *
 * 이 자리만 border 로는 그려지지 않는다. TOAST 의 표는 border-collapse:collapse
 * 인데 <table> 에 `border: 1px hidden transparent` 가 걸려 있고, 겹친 테두리를
 * 정하는 규칙에서 hidden 은 다른 무엇보다 세다. 그래서 각 줄의 맨 오른쪽 칸은
 * 오른쪽 테두리를 항상 빼앗긴다 — 체크박스·순번은 왼쪽 고정영역(lside)이라는
 * 별도의 <table> 에 담기므로, 순번 칸이 정확히 여기에 걸린다.
 * (assets/css/app.css 의 .card-table 쪽에 같은 처리가 있다. 위 카드에서
 *  .card-table 을 떼면서 같이 빠져 이 선만 사라졌다 — 사용자 보고.)
 *
 * 고정영역 상자에 한 번에 긋는 방법(inset 그림자나 ::after)은 쓰지 않는다.
 * 그 상자는 표 바닥까지 이어져 있어서, 줄이 없는 아래쪽 빈 구간까지 선이
 * 내려간다 — 다른 열의 구분선은 마지막 줄에서 끝나므로 혼자 튄다.
 *
 * 고정칸을 쓰는 표(아래 접수 리스트는 frozenCount:10)는 그 이음매에 라이브러리가
 * .tui-grid-frozen-border(2px #dbdee3)를 따로 그린다. 거기에 또 그으면 선이
 * 겹치므로 :not(:has(…)) 로 비켜 간다 — 고정칸이 없는 표에만 걸린다.
 */
/* 머리줄 쪽. 칸 안쪽 그림자가 아니라 ::after 로 그린다 — 라이브러리가 머리줄
   칸을 본문 칸보다 정확히 1px 넓게 잡아서(실측), 양쪽 다 inset 으로 그리면
   머리줄 선만 1px 오른쪽에 놓여 위아래가 어긋난다. right:1px 이 그 1px 을
   되돌려 본문 선과 같은 픽셀에 떨어진다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-header-area tr > *:last-child {
  position:relative; box-shadow:none !important;
}
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-header-area tr > *:last-child::after {
  content:''; position:absolute; top:0; bottom:0; right:1px; width:1px;
  background:#d1d5db; pointer-events:none;
}
/* 본문도 같은 자리(고정영역 마지막 칸의 안쪽 오른편)에 그린다. 오른쪽 영역(rside)
   첫 칸에 그리면 가로 스크롤 때 선이 딸려 가고, 두 영역이 맞닿는 이음매 1px 은
   라이브러리가 겹쳐 놓는 상자에 가려 화면에 나오지 않는다(app.css 주석·실측).
   색은 다른 열의 본문 구분선과 같은 #e5e7eb 다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-body-area tr > *:last-child {
  box-shadow: inset -1px 0 0 #e5e7eb !important;
}
/*
 * 고정영역 상자의 마지막 1px — 여기가 줄 색을 끊어 먹는 자리다(사용자 보고:
 * 고른 줄에 흰 선이 보인다).
 *
 * 실측: 고정영역(.tui-grid-lside-area)은 261~362 인데 그 안의 <table> 은 261~361
 * 이다. 라이브러리가 고정칸 경계선 자리로 1px 을 남겨 두기 때문이다. 고정영역은
 * z-index:5 라 오른쪽 영역보다 위에 그려지므로, 남은 1px 에 깔린 흰 바탕이
 * 그 아래 첫 데이터 칸(361부터)을 가린다. 줄이 흰색일 때는 티가 안 나지만
 * 고른 줄(파랑)에서는 줄이 한 번 끊긴 것처럼 보인다.
 *
 * 그래서 그 상자의 바탕을 지운다 — 칸들은 저마다 불투명한 배경을 갖고 있어
 * 안쪽은 달라지지 않고, 남는 1px 만 아래의 오른쪽 영역(=그 줄의 첫 칸)이
 * 비쳐 보인다. 고른 줄이면 파랑, 아니면 흰색 — 줄 색이 알아서 따라온다.
 *
 * 고정칸을 쓰는 표는 그 1px 이 .tui-grid-frozen-border 자리라 건드리지 않는다.
 */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area,
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-body-area {
  background:transparent !important; background-color:transparent !important;
}

/* 고른 줄(.row-sel)에서는 이 선도 같이 진해져야 한다. 다른 칸의 경계선은 위
   .row-sel 규칙이 border-right-color 를 #8fb4e0 으로 바꾸는데, 이 자리만 border 가
   아니라 그림자라 거기에 안 걸린다 — 그래서 파란 줄 위에 이 한 자리만 밝게 남아
   흰 줄처럼 도드라졌다(사용자 보고). 색은 다른 칸 경계선과 같은 값이다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-body-area tr > *:last-child.row-sel {
  box-shadow: inset -1px 0 0 #8fb4e0 !important;
}
/* 등록 중인 새 줄(.row-new)도 같은 이유로 — 색은 그 줄의 칸 경계선과 같다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-body-area tr > *:last-child.row-new {
  box-shadow: inset -1px 0 0 #c99ae0 !important;
}
/* 겹선 방지는 마지막 칸에만 — 고정영역 안쪽 칸끼리(체크박스↔순번)는 표 안쪽이라
   테두리가 정상적으로 그려지므로 그대로 둔다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area tr > *:last-child {
  border-right-width:0 !important;
}   /* 이 닫는 괄호가 빠져 있었다 — 파일 끝이라 브라우저가 알아서 닫아 줘서 드러나지 않다가, 뒤에 규칙을 붙이자 그 규칙들이 이 블록 안에 갇혀 무시됐다(2026-10-07) */

/*
 * 검색바의 고객사 강조(.stk-comp) — 재고관리(manager/stock/list.php)에서 쓰던 규칙을 상품관리·입고관리도 같이
 * 쓰도록 여기로 옮겨 왔다(사용자 지시 2026-10-07). 고른 상태(.on)는 lib/layout.php의 공용 스크립트가 붙인다.
 * 재고관리 list.php의 <style>에도 같은 값이 남아 있다 — 바꿀 때는 이쪽을 고치면 세 화면이 함께 바뀐다.
 * 고른 상태에서도 글자는 흰색으로 뒤집지 않는다 — 크롬은 펼친 목록 항목에 셀렉트의 글자색을 물려줘 흰 바탕
 * 목록이 안 보이게 된다.
 */
.stk-comp .f-label { color: var(--brand-dark); font-weight: 700; }
.stk-comp select.filter-select {
  border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand);
  background-color: #EEF3FC; color: var(--brand-dark); font-weight: 600;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%232A55AA' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
.stk-comp select.filter-select.on { background-color: #D6E3F8; }
/*
 * 고객사를 안 골랐으면(전체 — .on이 없으면) 칸이 계속 은은하게 깜빡인다(사용자 지시).
 * 둘레에 파란 빛이 4px 번졌다 걷히고 바탕도 같이 한 톤 오르내린다 — 1.6초에 한 번,
 * 멈추지 않는다. 번쩍이지 않고 숨 쉬듯 바뀌게 ease-in-out으로 둔다(글자는 그대로라
 * 읽는 데 방해되지 않는다). 고르면(.on) 멈추고, 칸을 누르고 있는 동안(:focus)도 멈춘다 —
 * 목록을 펼친 채 칸이 깜빡이면 거슬린다. 운영체제에서 "동작 줄이기"를 켠 사람에게는
 * 깜빡이지 않는다(조회 기준 단추의 stkBlink와 같은 처리).
 */
@keyframes stkCompPulse {
  0%, 100% { box-shadow: 0 0 0 1px var(--brand); background-color: #EEF3FC; }
  50%      { box-shadow: 0 0 0 1px var(--brand), 0 0 0 4px rgba(51,102,204,.3); background-color: #DCE7FA; }
}
.stk-comp select.filter-select:not(.on) { animation: stkCompPulse 1.6s ease-in-out infinite; }
.stk-comp select.filter-select:focus { animation: none; box-shadow: 0 0 0 1px var(--brand), 0 0 0 4px rgba(51,102,204,.15); }
@media (prefers-reduced-motion: reduce) { .stk-comp select.filter-select:not(.on) { animation: none; } }
.stk-comp select.filter-select option { color: #111; font-weight: 400; }

/* 필수 딱지 깜빡임은 넣었다가 뺐다(사용자 지시 2026-10-07 — 깜빡이지 않고 진한 빨강으로). */
/* 라디오 동그라미만 크게(18px) — 글자 크기·간격은 그대로(사용자 지시 2026-10-07). .f-radio-lg는 글자까지 키운다. */
.f-radio-big .f-radio input[type=radio] { width:18px; height:18px; }

/* 불러오는 중 — 글자 대신 도는 고리(사용자 지시 2026-10-07). 상세 패널·이력 창이 읽는 동안 가운데에 보인다.
   마크업: <div class="ld-wrap"><span class="ld-spin" role="status" aria-label="불러오는 중"></span></div> */
.ld-wrap { display:flex; align-items:center; justify-content:center; height:100%; min-height:160px; }   /* 칸 한가운데(가로·세로, 사용자 지시 2026-10-07) */
.ld-spin { width:28px; height:28px; border-radius:50%; border:3px solid #dbe4f3; border-top-color:var(--brand, #3366cc);
           animation: ldSpin .8s linear infinite; }
@keyframes ldSpin { to { transform: rotate(360deg); } }
/* 불러오기 실패 — 스피너 아래에 실패 문구(사용자 지시 2026-10-07). 고리는 멈추고 옅게(더 기다릴 것이 없다). */
.ld-wrap.ld-fail { flex-direction:column; gap:12px; }
.ld-fail .ld-spin { animation:none; opacity:.45; }
.ld-msg { margin:0; font-size:13px; color:#dc2626; font-weight:600; }
@media (prefers-reduced-motion: reduce) { .ld-spin { animation-duration: 2s; } }

/* 목록 표의 체크박스·No 칸에도 세로 칸선 — 다른 칸과 같은 색 #d0d7e3(사용자 지시 2026-10-07).
   TOAST가 순번 칸(rowHeader 마지막) 오른쪽 선을 0으로 그려 체크박스·No·첫 열 사이에 선이 없었다.
   입고관리·상품관리·재고관리 목록(#grid)에 함께 걸린다. 고른 줄(.row-sel)의 파란 선은 그대로 둔다. */
#grid .tui-grid-cell-row-header { border-right:1px solid #d0d7e3 !important; border-left:0 !important; }
#grid .tui-grid-body-area tr.row-sel > .tui-grid-cell-row-header { border-right-color:#8fb4e0 !important; }

/* 체크한 줄 수 라벨 — 목록 건수 옆 'N개 선택'(lib/layout.php gridSelBadge, 사용자 지시 2026-10-08).
   국내출고 고객사 건수 라벨과 같은 보라 사각형. */
.grid-sel { display:inline-flex; align-items:center; height:22px; padding:0 9px; border-radius:4px; background:#7c3aed; color:#fff;
            font-size:12px; font-weight:700; line-height:1; white-space:nowrap; }

/* 체크박스·No 칸 세로선 맞춤(사용자 지시 2026-10-08 — 국내출고에서 먼저 고쳤다) — TOAST가 왼쪽 고정 영역 폭을 칸 합 + 1px(81px)로
   잡는데 본문 표는 칸 합(80px)이라, 머리줄 표만 늘어나 체크박스 칸 0.5px·No 칸 1px씩 머리줄 세로선이 본문보다 오른쪽에 섰다(실측).
   머리줄 표를 본문과 같은 폭으로. 고정 열 테두리(frozen-border)가 있는 표는 그 1px가 테두리 몫이라 뺀다. */
.rjp-grid:not(:has(.tui-grid-frozen-border)) .tui-grid-lside-area .tui-grid-header-area .tui-grid-table { width:calc(100% - 1px) !important; }
