/* ============================================================================
 *  nx-form.css — 버튼 · 입력 · 셀렉트의 **높이와 모양을 하나로** 맞춘다.
 *
 *  왜 필요한가
 *  ----------
 *  Zynix 기본값을 실제로 재 보면 셋이 전부 다르다:
 *
 *      .ti-btn (Default Button)   35px
 *      .form-control (Input 기본) 30px
 *      .ti-form-select            50px      ← 20px 차이
 *
 *  한 줄에 나란히 놓으면 눈에 띄게 어긋난다(검색줄에서 실제로 그랬다).
 *  Zynix 원본을 고치지 않고 **우리 규칙만 위에 덮는다** — `zynix_import.py` 로
 *  재임포트해도 이 파일은 그대로 남는다.
 *
 *  규칙 (2026-07-30 결정)
 *  --------------------
 *    · 높이는 **Default Button 의 35px** 로 통일
 *    · **평면** — 그림자 없음
 *    · **직각** — 라운드 없음
 *
 *  바꾸려면 `--nx-control-h` 한 줄만 만지면 셋이 함께 움직인다.
 * ========================================================================= */

:root {
  --nx-control-h: 35px;
}

/* --------------------------------------------------------------------------
 * 세로 스크롤바 자리를 **늘 비워 둔다**
 *
 * 스크롤바가 생기거나 사라지는 순간 본문 폭이 15~17px 씩 바뀐다.
 * 눈에 띄는 곳이 둘이었다:
 *
 *   ① 화면이 처음 그려질 때 — 웹폰트가 도착하면 글이 늘어나 페이지가 길어지고,
 *      그때 스크롤바가 생기면서 **글 영역 좌우가 순간 줄어든다**
 *   ② 팝업을 열 때 — `body { overflow:hidden }` 으로 스크롤바가 사라져
 *      본문이 오른쪽으로 밀렸다가, 닫으면 되돌아온다
 *
 * `scrollbar-gutter: stable` 한 줄이면 자리를 항상 잡아 두므로 둘 다 없어진다.
 * 스크롤이 필요 없는 짧은 화면에서는 오른쪽에 그만큼 빈 자리가 생기지만,
 * **화면이 흔들리지 않는 쪽**이 낫다.
 *
 * 이 속성을 모르는 브라우저(사파리 구버전)는 `modal.ts` 의 `lockScroll()` 이
 * `padding-right` 로 대신 메운다 — 거기서 `CSS.supports()` 로 갈린다.
 * ----------------------------------------------------------------------- */
html {
  scrollbar-gutter: stable;
}

/* --------------------------------------------------------------------------
 * 높이 통일
 * `height` 에는 !important 를 쓰지 않는다 — 컴포넌트(트리 툴버튼 등)가
 * 자기 크기를 덮어쓸 수 있어야 한다. 모양(radius/shadow)만 강제한다.
 * ----------------------------------------------------------------------- */
.ti-btn,
.form-control,
.ti-form-select,
select.form-control,
input.form-control,
textarea.form-control {
  box-sizing: border-box;
}

.ti-btn,
.form-control:not(textarea),
.ti-form-select,
select.form-control {
  height: var(--nx-control-h);
  min-height: var(--nx-control-h);
  line-height: 1.2;
}

/* Zynix 는 select 에 위아래 12px 패딩을 준다 — 35px 안에서는 글자가 넘친다.
   input 과 같은 값으로 맞춘다. */
.ti-form-select,
select.form-control {
  padding-top: 0.375rem !important;
  padding-bottom: 0.375rem !important;
}

/* --------------------------------------------------------------------------
 * ★★★★★ 사장님 지시 2026-09-05 — *"앞으로도 전부 통일한다"*.
 *
 * 클래스 없는 맨몸 라디오·체크박스는 **브라우저가 직접 그린다**(appearance:auto).
 * 그래서 우리 CSS 의 색이 하나도 안 먹고 **크롬 기본 파랑**으로 찍힌다 —
 * 실측으로 확인했다(dox_status·dox_hosting 의 라디오가 그랬다). 그 자리를
 * 여는 열쇠는 색 속성이 아니라 `accent-color` 하나뿐이다.
 * 값은 새로 짓지 않고 정본 토큰(`--nx-primary`)을 가리킨다.
 * ----------------------------------------------------------------------- */
input[type="radio"],
input[type="checkbox"],
progress,
input[type="range"] {
  accent-color: var(--nx-primary);
}

/* --------------------------------------------------------------------------
 * 평면 · 직각
 * Zynix 가 `border-radius: .25rem !important` 로 박아 두어 !important 가 필요하다.
 * ----------------------------------------------------------------------- */
.ti-btn,
.form-control,
.ti-form-select,
select.form-control,
input.form-control,
textarea.form-control,
.input-group > *,
.ti-btn-group > .ti-btn {
  border-radius: 0 !important;
  box-shadow: none !important;
}

/* 포커스 링은 남긴다 — 접근성이다. 다만 그림자가 아니라 테두리로. */
.form-control:focus,
.ti-form-select:focus,
select.form-control:focus {
  outline: 2px solid rgb(var(--primary) / 0.35);
  outline-offset: -2px;
  box-shadow: none !important;
}

/* 크기 변형도 같은 규칙을 따른다 */
.form-control-sm,
.ti-btn-sm {
  height: calc(var(--nx-control-h) - 6px);
  min-height: calc(var(--nx-control-h) - 6px);
}

.form-control-lg,
.ti-btn-lg {
  height: calc(var(--nx-control-h) + 8px);
  min-height: calc(var(--nx-control-h) + 8px);
}

/* --------------------------------------------------------------------------
 * 상자도 직각
 *
 * 버튼·입력만 직각이고 그것을 담은 카드가 둥글면 **한 화면에 규칙이 두 개**로
 * 보인다. 화면에 실제로 쓰는 표면(surface)을 전부 직각으로 맞춘다.
 *
 * ★ 아바타(`.avatar`)는 뺀다 — 사람 사진은 원형이 맞다.
 * ★ 스피너(`.ti-spinner`)도 뺀다 — 원이어야 도는 것으로 읽힌다.
 * ----------------------------------------------------------------------- */
.box,
.box-header,
.box-body,
.box-footer,
.card,
.ti-modal-box,
.ti-modal-content,
.alert,
.badge,
.hs-dropdown-menu,
.ti-dropdown-menu,
.ti-pagination,
.page-link,
.ti-tab-list,
.progress,
.progress-bar,
.ribbon {
  border-radius: 0 !important;
}

/* 그림자도 없앤다 — 카드가 떠 보이면 평면 규칙이 깨진다.
   팝업(모달·드롭다운)은 **배경 위에 떠야 읽히므로** 그림자를 남긴다. */
.box,
.card {
  box-shadow: none !important;
}

/* --------------------------------------------------------------------------
 * 사이드바 메뉴
 *
 * **바탕색을 쓰지 않는다.** Zynix 기본은 활성/hover 에 `--primary` 를 통째로
 * 깔았고(파란 알약), 검정으로 바꿔도 마찬가지였다. 색이 칠해진 덩어리가
 * 사이드바에서 가장 무거워 보여 정작 본문보다 먼저 눈에 들어왔다.
 *
 * 지금 어디인지는 **글자색 + 굵기**가 말해 준다. 그거면 충분하다.
 * hover 는 아주 옅은 회색만 깔아 "누를 수 있다" 만 알린다.
 *
 * ★ 예전 주석에는 "왼쪽 세로바" 가 적혀 있었는데 그런 규칙은 없었다.
 *   주석이 화면과 다르면 다음 사람이 "왜 안 보이지" 로 시간을 버린다 —
 *   바를 넣는 대신 **주석을 화면에 맞췄다**(오른쪽 파란 바를 지운 결정과 같은 줄기).
 * ----------------------------------------------------------------------- */
.app-sidebar .side-menu__item {
  border-radius: 0 !important;
}

.app-sidebar .side-menu__item.active,
.app-sidebar .side-menu__item.active:hover {
  background-color: transparent !important;
  color: rgb(var(--primary)) !important;
  font-weight: 600;
}

.app-sidebar .side-menu__item.active .side-menu__label,
.app-sidebar .side-menu__item.active .side-menu__icon,
.app-sidebar .side-menu__item.active .side-menu__angle {
  color: rgb(var(--primary)) !important;
}

.app-sidebar .side-menu__item:hover {
  background-color: rgb(var(--default-text-color) / 0.05) !important;
  color: rgb(var(--primary)) !important;
}

/* ★ 다크에서는 `--primary` 하나만으로는 안 된다.
 *   어두운 사이드바 바탕 위에서 재 보면 대비가 2.8~3.1:1 이다 — 본문 글자
 *   기준 4.5:1 에 한참 못 미친다. 바탕색을 지웠기 때문에 **글자색이 유일한
 *   표시**라 여기서 대비가 모자라면 "지금 어디인지" 가 안 보인다.
 *   흰색을 섞어 밝기만 올린다(색상 자체는 그대로 브랜드색이다).
 *
 *   `color-mix` 를 모르는 브라우저는 이 선언만 통째로 버리고 위의
 *   `rgb(var(--primary))` 를 그대로 쓴다 — 예전 그대로일 뿐 깨지지 않는다. */
.dark .app-sidebar .side-menu__item.active,
.dark .app-sidebar .side-menu__item.active:hover,
.dark .app-sidebar .side-menu__item.active .side-menu__label,
.dark .app-sidebar .side-menu__item.active .side-menu__icon,
.dark .app-sidebar .side-menu__item.active .side-menu__angle {
  color: color-mix(in srgb, rgb(var(--primary)) 40%, #fff) !important;
}

.dark .app-sidebar .side-menu__item:hover {
  color: color-mix(in srgb, rgb(var(--primary)) 40%, #fff) !important;
}

/* --------------------------------------------------------------------------
 * 사이드바 토글 아이콘 (☰ ↔ ✕)
 *
 * 마크업에는 아이콘이 **둘 다** 들어 있고(`_zx_header.html` 의 `.menu-btn` /
 * `.menu-btn-close`), 어느 쪽을 보일지는 `<html data-toggled>` 값이 정한다.
 * 그런데 Zynix 원본 규칙은 **뒤집혀 있다** —
 *
 *     펼쳐진 상태(data-toggled="close")  → ☰   ← 이미 열려 있는데 "여세요"
 *     접힌 상태(…-close / …-closed)      → ✕   ← 이미 닫혀 있는데 "닫으세요"
 *
 * 게다가 모바일 서랍이 나왔을 때(`data-toggled="open"`)는 원본 목록에 그 값이
 * 아예 없어서 **열려 있어도 계속 ☰** 였다.
 *
 * 버튼은 **지금 상태**가 아니라 **누르면 일어날 일**을 보여야 한다:
 *   보이는 중 → ✕(닫기),  숨은 중 → ☰(열기).
 *
 * `data-toggled` 의 의미가 화면 폭에 따라 다르므로 미디어쿼리로 나눈다 —
 * 데스크톱에서 `close` 는 "펼쳐짐", 모바일에서 `close` 는 "서랍 숨음" 이다.
 * (이 파일은 `styles.css` 뒤에 실리므로 같은 특이도로 이긴다)
 * ----------------------------------------------------------------------- */
/* ★★ F434b(사장님 재지시 2026-08-13): 셸은 **1025px**, 목록 표는 **1024px** —
   일부러 1px 다르다. 1024px 화면에서는 사이드바가 **접힌 채로** 표를 본다
   («사이드바가 1024 에서 들어가야 한다» + «리스트는 1024 에서 표»).
   셸 값의 정본은 `scripts/zynix_import.py` 의 SHELL_BREAKPOINT 다. */
@media (min-width: 1025px) {
  /* 기본 = 사이드바가 펼쳐져 있다 → 닫기(✕) */
  .menu-btn {
    display: none;
  }

  .menu-btn-close {
    display: block;
  }

  /* Zynix 가 붙이는 "접힘" 값들은 전부 `-close` 또는 `-closed` 로 끝난다
     (icon-overlay-close · icon-text-close · menu-click-closed …).
     `double-menu-open` 처럼 `-open` 으로 끝나는 값은 펼쳐진 상태라 안 걸린다. */
  [data-toggled$="-close"] .menu-btn,
  [data-toggled$="-closed"] .menu-btn {
    display: block;
  }

  [data-toggled$="-close"] .menu-btn-close,
  [data-toggled$="-closed"] .menu-btn-close {
    display: none;
  }
}

@media (max-width: 1024.98px) {
  /* 모바일 기본 = 서랍이 숨어 있다 → 열기(☰) */
  .menu-btn {
    display: block;
  }

  .menu-btn-close {
    display: none;
  }

  [data-toggled="open"] .menu-btn {
    display: none;
  }

  [data-toggled="open"] .menu-btn-close {
    display: block;
  }
}

/* SimpleBar(오버레이 스크롤바)도 직각으로. 기본은 알약(radius 7px)이다. */
.simplebar-scrollbar::before {
  border-radius: 0 !important;
}

/* --------------------------------------------------------------------------
 * 비밀번호 보기 버튼 (`.show-password-button`)
 *
 * Zynix 원본은 `top: 5px` 로 **위에서부터** 붙이고 padding 으로 크기를 만든다.
 * 그 값은 Zynix 의 큰 입력칸(`form-control-lg`, 약 48px) 기준이다.
 * 우리는 `--nx-control-h`(35px)로 모든 컨트롤 높이를 통일했으므로,
 * 그대로 두면 버튼이 **입력칸보다 커서 위·오른쪽으로 삐져나와** 보인다
 * (화면에서 "간격이 있다" 로 보이던 것이 이것이다).
 *
 * 위에서 재지 않고 **세로 가운데**에 놓는다 — 입력칸 높이가 바뀌어도 따라온다.
 * 모서리는 직각으로(이 파일의 평면 규칙).
 * ----------------------------------------------------------------------- */
.show-password-button {
  top: 50%;
  bottom: auto;
  transform: translateY(-50%);
  inset-inline-end: 4px;
  height: calc(var(--nx-control-h) - 8px);
  min-height: 0;
  padding: 0 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 0;
  line-height: 1;
}

.show-password-button i {
  line-height: 1;
}

/* --------------------------------------------------------------------------
 * 경량 셸(shell.html) 기본값 — Zynix 없는 화면의 입력 부품 (9-130, A-1)
 *
 * 공개 뷰 비밀번호 게이트(dox_view_gate)의 .form-control 이 **브라우저
 * 기본**(2px 회색 테두리)으로 그려졌다(크로미움 실측). Zynix styles.css 가
 * 없는 셸에서도 입력이 우리 모양(1px·직각)으로 나오게 최소 기본값을 깐다.
 * ★ .nx-shell-plain 은 shell.html 의 <body> 에만 있다 — Zynix 화면(앱 셸·
 *   auth·bare)에는 이 규칙이 닿지 않는다. 버튼 짝은 .nx-btn-brand 다.
 * -------------------------------------------------------------------------- */
.nx-shell-plain .form-control {
  appearance: none;
  border: 1px solid var(--nx-plain-line, #d5dae3);
  background: var(--nx-plain-field-bg, #fff);
  color: inherit;
  padding: 0 0.75rem;
  font-size: 0.875rem;
}

.dark .nx-shell-plain .form-control {
  --nx-plain-line: #3a4150;
  --nx-plain-field-bg: rgba(255, 255, 255, 0.04);
}

/* (지운 것) .nx-btn-icon — 사용처 0 인 죽은 규칙이었다(9-130 에서 삭제.
 * 템플릿·TS·빌드 산출물 전부 grep 0. 검색줄 정사각 버튼의 정본은 아래
 * .nx-sbtn 이다). */


/* --------------------------------------------------------------------------
 * 검색줄 아이콘 버튼 — **모든 목록·트리 공통** (F159, 사장님 지시 2026-08-04)
 *
 * "앞으로 모든 리스트는 이 모양을 기본으로 한다" — 목차 트리의 검색줄
 * (.nx-tree-sbtn)이 먼저 이 모양이었고, MY DOX 목록도 같게 맞췄다.
 * 모양: 컨트롤 높이(35px) 정사각 · 테두리 1px · 직각 · 배경 없음 ·
 *       hover 는 주색. 해제 버튼만 주황(경고색)으로 눈에 띄게 한다.
 *
 * ★ 정의는 **여기 한 곳**이다. nx-tree.css 는 이 규칙을 다시 쓰지 않는다 —
 *   두 벌로 갈리면 한쪽만 고쳐도 눈치채지 못한다(9-12 실증 유형).
 * ----------------------------------------------------------------------- */
.nx-sbtn,
.nx-tree-search .nx-tree-sbtn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--nx-control-h, 35px);
  height: var(--nx-control-h, 35px);
  min-height: var(--nx-control-h, 35px);
  padding: 0;
  border: 1px solid rgb(var(--default-border));
  border-radius: 0;
  margin: 0;
  background: none;
  color: rgb(var(--secondary, 141 145 160));
  font-size: 16px;
}

.nx-sbtn:hover,
.nx-tree-search .nx-tree-sbtn:hover {
  color: rgb(var(--primary));
  border-color: rgb(var(--primary));
}

.nx-sbtn[hidden],
.nx-tree-search .nx-tree-sbtn[hidden] {
  display: none;
}

/* --------------------------------------------------------------------------
 * F195 (B안, 사장님 확정 2026-08-06): 지우기 X 는 **입력칸 안** 오른쪽에
 * 하나만 산다 — 지우기+리셋 겸용. 별도 리셋(🔄) 버튼은 폐지(.is-reset 도
 * 같이 지웠다). 노출 규칙: 검색어가 있거나 검색이 걸려 있으면 **항상**
 * 표시(호버 조건 없음 — 터치에는 호버가 없다). 모든 리스트 검색줄의
 * 기본형: [범위 ▾][입력(안에 X)][찾기]
 * 정의는 여기 한 곳 — 목록·트리 검색줄이 함께 쓴다(뷰어는 다크 자체 CSS).
 * ----------------------------------------------------------------------- */
.nx-in-wrap {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
}
.nx-in-wrap > input {
  width: 100%;
  min-width: 0;
  padding-right: 32px; /* X(24) + 틈 — 글자가 X 밑에 안 깔린다 */
}
.nx-in-x {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  min-height: 24px;
  padding: 0;
  border: 0;
  border-radius: 0;
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  color: rgb(var(--secondary, 141 145 160));
  font-size: 14px;
}
.nx-in-x:hover {
  color: rgb(var(--primary));
}
.nx-in-x[hidden] {
  display: none;
}
/* 브라우저 네이티브 ✕(type=search)와 겹치면 X 가 두 개다 — 끈다. */
.nx-in-wrap > input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  display: none;
}

/* 검색줄 한 벌 — 컨트롤이 서로 붙어 하나의 막대로 보인다. */
.nx-search-row {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* F272: 기어 팝업(상태 전환)의 라디오 행 — 모달 폼 공용 부품
   F356(사장님 실기동 2026-08-10): 내용이 넘치면 **줄을 바꾼다**(wrap) —
   설명 글이 세로로 짜부라지던(글자 한 자 폭) 사고의 뿌리 제거.
   min-width 는 설명이 쪼그라드는 대신 줄바꿈을 택하게 하는 버팀목이다. */
.nx-pick-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--nx-border, #e3e8ef);
  cursor: pointer;
}
.nx-pick-row:hover {
  background: var(--nx-menu-hover-bg, #f4f6fa);
}
.nx-pick-hint {
  font-size: 12.5px;
  color: var(--nx-menu-icon-color, #7b8698);
  min-width: 12rem;
}

/* F355(사장님 2026-08-10 "아주 많을 수도 있다"): 다운로드 확인 판 —
   언어 목록은 세로 + 내부 스크롤(nx-tr-list 재사용), 판은 전체 폭. */
.nx-pick-row form[data-nx-dl-armed] {
  flex: 1 1 100%;
  min-width: 0;
}
.nx-dl-langlist {
  border: 1px solid var(--nx-border, #e3e8ef);
  padding: 6px 10px;
  max-height: 16rem;
}
/* 목록 줄 구조는 이 부품 CSS 가 책임진다 — 유틸 클래스에 안 기댄다
   (모달 조각은 셸 밖에서도 쓰인다). */
.nx-dl-langlist label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 3px 0;
  cursor: pointer;
}
/* F356: ready 묶음(배지·남은 횟수·받기·새로 만들기)은 **둘째 줄 전체 폭**
   — 설명 글과 한 줄에 우겨 넣으면 설명이 세로로 짜부라졌다(실측). */
.nx-dl-ready {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* 각 행 번갈아 연한 배경(사장님 2026-08-08) — 행 구분. 넓은 표 모드. */
.nx-rtable tbody tr:nth-child(even) > td { background-color: rgba(100, 116, 139, 0.05); }
.dark .nx-rtable tbody tr:nth-child(even) > td { background-color: rgba(255, 255, 255, 0.03); }

/* ==========================================================================
 * F278(9-136, 사장님 확정): 반응형 표 — **전체 기본** (ui.table 창구의 .nx-rtable)
 *
 * 넓은 화면(≥1024px)은 보통 표. 좁아지면 각 행이 **카드**가 되어 모든 열이
 * 보인다 — 전에는 table-responsive 가로 스크롤에 열이 숨었다(사장님 F278).
 *   · PAD(640~1023px): 카드 안에서 「열 이름 : 값」 한 줄씩(플렉스 2열)
 *   · 모바일(<640px): 열 이름 위 · 값 아래(블록)
 * 라벨은 rtable.ts 가 thead 에서 td[data-th] 로 복사한다.
 * ========================================================================== */
@media (max-width: 1023.98px) {
  .nx-rtable thead { display: none; }
  .nx-rtable, .nx-rtable tbody { display: block; width: 100%; }
  .nx-rtable tbody tr {
    display: block;
    border: 1px solid var(--nx-plain-line, #d5dae3);
    background: var(--nx-plain-field-bg, #fff);
    margin-bottom: 12px;
    padding: 6px 2px;
  }
  /* ★ 사장님 피드백(2026-08-08): 칸 안에 배지+기어처럼 **여러 조각**이 있다 —
     space-between 으로 흩뿌리면 배지 따로 기어 따로가 된다. 라벨만 왼쪽에
     두고(auto 마진), 값 조각들은 **오른쪽에 서로 붙여** 정렬한다. */
  .nx-rtable tbody td {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    border: 0 !important;
    padding: 6px 12px !important;
    white-space: normal;
  }
  .nx-rtable tbody td::before {
    content: attr(data-th);
    flex: 0 0 38%;
    margin-right: auto;          /* 라벨 뒤 공간을 밀어 값 묶음을 우측으로 */
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--nx-menu-icon-color, #7b8698);
  }
  /* 라벨 없는 칸(라벨이 빈 열)은 값만 오른쪽 정렬로 */
  .nx-rtable tbody td:not([data-th])::before,
  .nx-rtable tbody td[data-th=""]::before { content: none; }
  /* 카드도 번갈아 연한 배경 — 행(카드) 구분(사장님 2026-08-08) */
  .nx-rtable tbody tr:nth-child(even) { --nx-plain-field-bg: #f3f5f8; }
  .nx-rtable tbody tr:nth-child(even) > td { background-color: transparent; }
  .dark .nx-rtable tbody tr {
    --nx-plain-line: #3a4150;
    --nx-plain-field-bg: rgba(255, 255, 255, 0.03);
  }
  .dark .nx-rtable tbody tr:nth-child(even) { --nx-plain-field-bg: rgba(255, 255, 255, 0.07); }
}

/* ★ 모바일도 PAD 형식 그대로(사장님 확정 2026-08-08) — 별도 세로 모드 없음.
   좁으면 라벨 몫만 줄인다(값 묶음이 먼저다). */
@media (max-width: 479.98px) {
  .nx-rtable tbody td::before { flex-basis: 30%; }
}

/* ---------------------------------------------------------------------------
   F333(사장님 지시 2026-08-09, 스크린샷): 리스트 **실행 버튼** — 소프트블루
   테두리. 회색 ti-btn-light 만으로는 "누르는 것"이 안 보인다는 지적.
   색은 뷰어 주석 소프트블루 정본과 같은 값(#6b9bd2 · 다크 #7fa9d9 —
   dox_viewer.html 의 --pd-an-blue). 앱 셸에는 그 변수가 없어 값으로 적는다
   — 바꿀 때 두 곳을 같이 바꾼다.
   ★ 특이도 (0,2,0) — 벤더 .ti-btn-light(0,1,0)를 문서 순서가 아니라
   특이도로 이긴다(새채팅_컨텍스트 함정 7 — F258 의 교훈). 라운드 0 은
   통짜 규칙이 지킨다. */
.ti-btn.nx-act { border: 1px solid var(--nx-primary-soft-bd); }
/* ★ F522 — 다크 값은 **정본 변수**가 뒤집었다. 2026-09-05 부터 그 정본이
   `rgb(var(--primary) / .30)` 이라 **다크에서도 저절로 맞는다** — 뒤집을
   값이 없으므로 이 규칙은 걷었다(쓰는 곳 0 인 규칙을 남기지 않는다 · 0-0). */
/* ★ D008(«상세보기 배경을 소프트블루로»)의 `.nx-act--fill` 규칙은 **걷었다.**
   사장님이 곧바로 F603-2 로 *"화살표2의 버튼과 같은 색상"*(= [PDF 업로드] =
   벤더 `ti-btn-primary`)으로 바꾸셨기 때문이다. 쓰는 곳이 0 인 규칙을 남기면
   다음 사람이 «어느 것이 정본인가» 를 화면에서 찾게 된다(0-0).
   ★ 되살릴 일이 생기면 이 자리다 — 값은 페이지네이션 활성 칸과 같은 짝
     (배경 Light primary · 글자 #fff / 다크 #1a2234)이었다. */
/* F345①(사장님 실기동 2026-08-10, 스크린샷): [AI 검수 실행](button)만 같은
   줄 실행 버튼(a.ti-btn — 번역·기어)보다 2px 위로 떠 보였다(356.2 vs
   358.2). 실측 원인: a.ti-btn 에는 margin-top 4px 이 붙고 button 에는
   0 이었다(computed diff). 실행 버튼 전부 4px 로 통일한다 — vertical-align
   가설(baseline/middle/top)은 셋 다 실측에서 효과 없음이 확인됐다. */
.ti-btn.nx-act { margin-top: 4px !important; }
/* F349(같은 날): 배지 줄(두 번째 줄)이 생긴 행에서 middle 정렬은 한 줄
   셀의 버튼을 가운데로 내려 **줄이 어긋난다**(370.2 vs 358.2 실측) —
   첫 줄이 모든 칸에서 같은 y 에서 시작하게 top 정렬(MY DOX 표에만). */
.nx-rows-top tbody td { vertical-align: top; }
/* F351(같은 날, 스크린샷 화살표): 열 **간격 좁히기** — 칸 좌우 여백이
   18.4px 씩(실측)이라 폭 고정 열(비밀번호·URL·QR·상태)마다 틈이 컸고
   표 끝(삭제)이 잘렸다. MY DOX 표만 10px 로. (좁은 폭 카드 모드는
   nx-rtable 규칙이 자기 여백을 따로 가진다 — 안 겹친다.) */
.nx-rows-top thead th, .nx-rows-top tbody td {
  padding-left: 10px;
  padding-right: 10px;
}

/* ---------------------------------------------------------------------------
   ★★ F412(사장님 실기동 2026-08-12): **긴 제목 하나가 표 전체를 밀어냈다.**

   재현(tests/harness_dox_list.py · 크로미움 실측): 제목 90자짜리 문서가
   한 건 있으면 1600px 화면에서 표가 **2298px**(칸은 1265px)이 되고 삭제
   칸의 오른쪽 끝이 x=2578 — 화면 밖이다. 1024·1280·1440·1600·1920px,
   ko·en **10개 조합 전부** 같았다.

   왜 그런가 — `ui.table` 매크로가 표에 `whitespace-nowrap` 을 건다(모든
   표의 공통 규칙이라 여기서 걷지 않는다). 제목 칸에는 폭 상한이 없어서
   `table-layout:auto` 가 **가장 긴 제목 한 줄**에 맞춰 표를 늘린다.

   `.table-responsive{overflow-x:auto}` 가 있어 가로 스크롤 자체는 된다.
   그런데 그 스크롤바는 **표 바닥**에 있다 — 20줄 목록에서는 화면 아래라
   손이 안 닿는다. 사용자에게는 없는 것이다. 그래서 스크롤에 기대지 않고
   **제목 칸을 잘라** 표가 카드를 안 넘게 만든다.

   ★ 자르는 것은 **넓은 화면(표 모드)에서만**. 좁은 폭은 nx-rtable 카드
     모드라 칸이 세로로 펼쳐진다 — 거기서 자르면 제목만 더 안 보인다.
   ★ 전체 제목은 `title=` 로 남는다(마우스를 올리면 보인다).
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  /* ★ `width:100%` 를 표에 더 주는 안은 **실측에서 효과 0** 이었다
     (1411px 그대로 — auto 배치는 칸 폭보다 내용 max-content 를 우선한다).
     효과 없는 규칙은 남기지 않는다. 상한은 칸에 직접 건다. */
  .nx-rtable td.nx-cell-name { max-width: 22rem; }
  /* ★ 자르는 주체는 **칸 안의 인라인 블록**이다 — td 에 overflow 만 걸면
     table-layout:auto 가 칸의 최소 폭을 내용에 맞춰 잡아 안 줄어든다. */
  .nx-rtable td.nx-cell-name > .nx-name {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* ★ F432: `bottom` 이었다 — 기둥(td::before)이 생기면서 제목만 5px
       아래로 처졌다(실측 370.3 vs 365.3). 같은 줄의 다른 조각과 같은
       규칙으로 세운다. */
    vertical-align: middle;
  }
}

/* ---------------------------------------------------------------------------
   ★★ F432(사장님 스크린샷 2026-08-13): **한 행의 상하 높이가 안 맞는다.**

   실측(1700px, 첫 행 · 각 칸의 첫 조각 세로 중심):

       제목 360.4 · SOURCE 배지 361.3 · 실행 버튼들 369.3 ·
       상태 배지 370.2 · 비밀번호 글자 368.7

   세 무리로 갈려 있었다. 원인 둘:
     ⑴ 실행 버튼에는 `margin-top:4px`(F345①)가 있고 글자·배지에는 없다.
     ⑵ 글자·배지는 **baseline** 을 타는데 같은 줄의 버튼은 29px 짜리라,
        줄 상자가 커지면서 글자가 아래로 밀린다(상태·비밀번호 칸).

   고침 — 첫 줄에 **보이지 않는 기둥**을 세운다. 높이는 실행 버튼과 같고,
   그 줄의 모든 조각을 기둥 **가운데**에 세운다. 글자 크기가 달라도 중심이
   같아진다. 기둥은 **첫 줄에만** 선다(둘째 줄 배지는 블록이라 안 걸린다).

   ★ 높이를 숫자로 베끼지 않는다 — `.ti-btn-sm` 의 정본 계산식을 그대로 쓴다.
   ★ F345① 의 4px 은 **이 표에서만** 걷는다. 그 고침의 목적은 «버튼끼리 같은
     줄»이었고, 기둥이 그것까지 함께 지킨다(둘 다 0 이면 서로 같다).
   ★ 좁은 폭은 카드 모드다 — 거기서는 `td::before` 가 **열 이름 라벨**이라
     이 규칙을 걸면 안 된다(그래서 1024px 이상에서만).
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .nx-rows-top tbody td::before {
    content: "";
    display: inline-block;
    width: 0;
    height: calc(var(--nx-control-h) - 6px);   /* = .ti-btn-sm 높이 */
    vertical-align: middle;
  }
  .nx-rows-top tbody td > * { vertical-align: middle; }
  /* ★ 실행 버튼 **전부**다 — `nx-act` 만 잡았더니 [삭제](ti-btn-danger)가
     4px 아래에 홀로 남았다(실측 369.3 vs 365.3). 세는 자리를 좁게 잡으면
     꼭 하나가 빠진다(0-3 ②). */
  .nx-rows-top tbody .ti-btn { margin-top: 0 !important; }
}

/* ---------------------------------------------------------------------------
   ★★ F435(사장님 지시 2026-08-13): **표가 넓어 제목과 버튼 사이가 너무 벌어진다.**

   `ui.table` 은 표에 `min-w-full`(= min-width:100%)을 준다. 그래서 넓은
   화면에서 표가 카드를 꽉 채우고, `table-layout:auto` 는 남는 폭을 **가장
   늘어날 수 있는 칸**(제목)에 몰아준다 — 제목 끝과 첫 버튼 사이가 휑해진다.

   사장님 지시: *"중간으로 모이도록. 중간으로 모이되 보기좋게."*
   → 표를 **내용 폭**으로 줄이고 카드 **가운데**에 놓는다. 남는 폭은 좌우로
     똑같이 나뉜다.

   ★ 표가 카드보다 넓어지면(좁은 화면) 자동 여백은 0 이 되고 예전처럼 가로
     스크롤이 받는다 — 실행 열 고정(F430)도 그대로 듣는다.
   ★ `!important` 를 쓰는 이유: 상대가 유틸리티 클래스(`min-w-full`)라
     특이도가 같아 **어느 파일이 나중에 실리는가**에 결과가 달린다.
     그런 것을 운에 맡기지 않는다(F258 의 교훈).
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .nx-rows-top {
    min-width: 0 !important;
    width: auto;
    margin-inline: auto;
  }
}

/* ---------------------------------------------------------------------------
   ★★ F430(사장님 확정 2026-08-13): **실행 열을 오른쪽에 고정한다.**

   F412 는 «긴 제목» 을 고쳤고 그건 듣는다. 그런데 사장님 증상 *"끝이 안 보여
   삭제를 못 누른다"* 는 **남아 있었다** — 열이 11개라 **짧은 제목만 있어도**
   표가 1,153~1,249px 를 요구하고, 1440·1280px 화면의 카드는 그보다 좁다
   (harness_dox_list 실측). 가로 스크롤은 되지만 그 스크롤바는 **표 바닥**에
   있어 20줄 목록에서는 화면 밖이다 — 사용자에게는 없는 것이다.

   사장님이 고른 답: **열을 줄이지 않고**(정보 손실 0) 실행 칸을 오른쪽에
   붙인다. 가로로 아무리 밀려도 [삭제]는 늘 같은 자리에 있다.

   ★ 배경은 **반드시 불투명**이어야 한다. 표 칸의 기본 배경은 투명이고
     (크로미움 실측 `rgba(0,0,0,0)`), 그대로 고정하면 밑을 지나가는 글자가
     **비쳐 보인다.** 카드의 실제 색을 쓴다 — `.box` 가 `rgb(255,255,255)` /
     다크 `rgb(35,34,38)` 이고 그것이 `--custom-white` 다(값을 베끼지 않고
     변수를 쓴다. 어느 변수인지는 재서 골랐다).
   ★ 줄 번갈이 색·머리 배경은 **그림 층으로 덧칠한다** — 배경색 자리는 하나뿐이라
     불투명 바탕이 가져갔다.
   ★ 좁은 폭(<1024px)은 카드 모드다(td 가 block) — 거기서 고정하면 카드가
     망가진다. 그래서 이 규칙은 표 모드에만 건다.
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  /* ★ 특이도 — 줄 번갈이 규칙 `.nx-rtable tbody tr:nth-child(even) > td`
     (0,2,3)을 **이겨야** 한다. 처음엔 `.nx-stick-end tbody td:last-child`
     (0,2,2)로 적었다가 배경이 그 반투명 색으로 남았고, 하네스가
     «배경이 투명하다» 로 잡았다(0-1b ② — 이기는지는 브라우저가 안다). */
  .nx-rtable.nx-stick-end thead tr > th:last-child,
  .nx-rtable.nx-stick-end tbody tr > td:last-child {
    position: sticky;
    /* 논리 속성 — RTL 이 오면 반대쪽에 붙는다(앱 UI 는 아직 LTR 뿐이다). */
    inset-inline-end: 0;
    /* 불투명 바탕. 이것이 없으면 밑의 글자가 비친다. */
    background-color: rgb(var(--custom-white, 255 255 255));
    /* 고정 칸임을 알리는 경계선 한 줄(그림자는 스크롤이 없을 때도 떠서 안 쓴다).
       ★ 색이 **불투명**이어야 한다 — 반투명으로 두면 그 1px 이 «뒤에 지나가는
         것» 과 섞여 밀 때마다 색이 변한다. 하네스가 정확히 그 1px 줄에서
         57픽셀이 달라진다고 잡았다(영어 판에서만 — 한국어 판은 우연히 뒤가
         같은 색이었다. 0-1b: 하나만 재면 반드시 놓친다).
         값은 «카드색 위에 rgba(100,116,139,.22)» 를 미리 합성한 것이다. */
    border-inline-start: 1px solid #dde0e6;
  }
  .nx-rtable.nx-stick-end tbody tr > td:last-child { z-index: 1; }
  /* 머리 칸이 몸통 위에 온다(가로로 밀 때 겹치는 순서). */
  /* 머리 배경(`ui.table` 의 `bg-primary/10`)을 색조 층으로 되살린다. */
  .nx-rtable.nx-stick-end thead tr > th:last-child {
    z-index: 2;
    background-image: linear-gradient(rgba(var(--primary-rgb, 37, 99, 235), 0.1),
                                      rgba(var(--primary-rgb, 37, 99, 235), 0.1));
  }
  /* 줄 번갈이(짝수 행)도 같은 방식으로. 값은 위 `nth-child(even)` 규칙과
     **같은 것**이다 — 바꿀 때 둘을 같이 바꾼다(배경색 자리를 못 써서 생긴
     두 벌이라, 검사가 두 값이 같은지 본다). */
  .nx-rtable.nx-stick-end tbody tr:nth-child(even) > td:last-child {
    background-image: linear-gradient(rgba(100, 116, 139, 0.05),
                                      rgba(100, 116, 139, 0.05));
  }
  .dark .nx-rtable.nx-stick-end tbody tr:nth-child(even) > td:last-child {
    background-image: linear-gradient(rgba(255, 255, 255, 0.03),
                                      rgba(255, 255, 255, 0.03));
  }
  .dark .nx-rtable.nx-stick-end thead tr > th:last-child,
  .dark .nx-rtable.nx-stick-end tbody tr > td:last-child {
    /* 다크 카드색 rgb(35,34,38) 위에 rgba(255,255,255,.16) 을 미리 합성한 값. */
    border-inline-start-color: #464549;
  }
}

/* ---------------------------------------------------------------------------
   F348(사장님 실기동 2026-08-10, 스크린샷): 페이지네이션 — 숫자·글자가
   본문보다 커 보였다. 작은 글씨 + 볼드, 현재 쪽 배경은 실행 버튼과 같은
   소프트블루(#6b9bd2 · 다크 #7fa9d9 — F333 정본과 같은 값). */
/* ★ 벤더가 `.ti-pagination li .page-link.active`(0,3,1)에 !important 로
   --primary 배경을 박는다 — 같은 모양 + !important 로, 뒤 순서로 이긴다
   (F258 교훈: 특이도를 벤더 실물에 맞춘다. 실측은 harness_f333). */
.ti-pagination li .page-link {
  font-size: 12px !important;
  font-weight: 700 !important;
}
.ti-pagination li .page-link.active {
  background-color: #6b9bd2 !important;
  border-color: #6b9bd2 !important;
  color: #fff !important;
}
.dark .ti-pagination li .page-link.active {
  background-color: #7fa9d9 !important;
  border-color: #7fa9d9 !important;
  color: #1a2234 !important;
}
/* F350(사장님 실기동 2026-08-10, 스크린샷): 활성 네모 **오른쪽에 선** —
   실측: 다음 칸의 왼쪽 테두리(연회색 rgb 243,242,249)가 활성 파랑에 붙어
   보였다. 다음 칸의 시작 테두리를 활성 배경색으로 물들여 지운다
   (:has — 크롬·엣지·사파리 최신 전부 지원, 모르는 브라우저는 이 규칙만
   버려 종전 그대로다). */
.ti-pagination li:has(.page-link.active) + li .page-link {
  border-inline-start-color: #6b9bd2 !important;
}
.dark .ti-pagination li:has(.page-link.active) + li .page-link {
  border-inline-start-color: #7fa9d9 !important;
}

/* ---------------------------------------------------------------------------
   번역 팝업 (F334~F336, 사장님 실기동 2026-08-09~10)
   · F336: 언어 목록 내부 스크롤 — 언어 수가 늘어도 팝업이 세로로 안 자란다.
     22rem ≈ 6~7줄. 스크롤은 목록 안에서만 구른다.
   · F334: 확인 줄 정렬 — 문구·[확인]·[취소]가 한 축(가운데)으로.
     ★ `.nx-tr-confirm{display:flex}` 로 적으면 hidden 속성이 display 에
     져서 확인 줄이 늘 보인다(F314b/F319 실증 함정) — :not([hidden]) 로만
     플렉스를 준다.
   · F335: 진행바 폭 — 줄 안에서 % 글자와 나란히. */
.nx-tr-list { max-height: 22rem; overflow-y: auto; padding-right: 2px; }
.nx-tr-confirm:not([hidden]) {
  display: inline-flex; align-items: center; gap: 8px;
}
.nx-tr-list .nx-tr-bar { width: 9rem; flex: 0 0 auto; }
/* D011: 막대가 핀과 한 줄로 묶였다(`.nx-pgrow`). 줄 안에서 늘어나면 안 된다 —
   폭은 위의 `.nx-tr-bar` 9rem 이 정한다. */
.nx-tr-list .nx-pgrow { flex: 0 0 auto; }
.nx-tr-list .nx-pgrow__bar { flex: 0 0 auto; }

/* ---------------------------------------------------------------------------
   ★★ F421(사장님 지시 2026-08-14) — MY DOX: **표 하나가 DOX 하나다.**

   *"맨 윗행은 좌측정렬 문서제목과 우측정렬 삭제버튼. 그 아래부터는 4열로
     컬럼제목 좌측정렬 / 실행버튼 우측정렬 ×2. 폭 800px 에서 4열이 2열로.
     행과 열은 표처럼 라인 넣는다. 1개의 표가 1개의 DOX 정보이다."*

   왜 격자인가 — `<table>` 은 쓸 수 없다(test_ui_offline 이 맨 table 을
   막는다). 그리고 표로 만들면 «800px 에서 4열→2열» 을 셀 병합 없이는 못
   한다. 격자는 열 정의 한 줄만 바꾸면 된다.

   ★ 경계(800px)의 정본은 **이 파일의 이 한 곳**이다. 셸 분기점
     (SHELL_BREAKPOINT = 1025)·목록 표 분기점(1024)과는 **다른 물건**이라
     일부러 안 묶었다 — 이건 카드 **안쪽**이 두 쌍을 담을 수 있는가이고,
     그 셋은 사이드바가 접히는가다. 묶으면 사이드바를 건드릴 때 카드가
     같이 움직인다.
   --------------------------------------------------------------------------- */
.nx-doxlist {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* 한 장 = 문서 하나. 바깥 테두리가 «표» 의 바깥선이다. */
.nx-doxcard {
  /* ★ 불투명색으로 둔다 — 반투명 1px 은 뒤와 섞여 화면마다 색이 변한다
     (F430 에서 실측으로 겪었다). */
  /* ★ 라운드 0 — 사장님 확정(전 화면 규칙). 처음에 0.35rem 을 넣었다가
     test_ui_offline 이 잡았다. 규칙이 살아 있다는 증거다. */
  /* ★★★★ F478①(사장님 2026-08-16): *"DOX 하나의 외곽 테두리를 가는 선 +
     약간 진하게 — 하나의 정보란으로 읽히게."*
     안쪽 격자선(`--default-border` = 243 242 249, 거의 흰색)은 **그대로** 두고
     **바깥선만** 진하게 한다 — 그래야 «한 덩이» 가 눈에 먼저 잡힌다.
     굵기는 그대로 1px(가는 선)이다.
     ★ 위 주석대로 **불투명색**을 쓴다 — 반투명 1px 은 뒤와 섞여 화면마다
       색이 변한다(F430 실측). */
  /* ★★★★ F486⑦(사장님 2026-08-17 화살표10): *"제목행 밑라인, 표 외곽라인과
     같은 라인을 줘."*  두 자리에 같은 숫자를 **두 번 적지 않는다** — 여기
     한 곳에서 온다. 적어 두면 한쪽만 바뀌어 조용히 갈린다. */
  --nx-dc-line: 163 170 184;
  border: 1px solid rgb(var(--nx-dc-line));
  overflow: hidden;               /* 셀 배경이 테두리 밖으로 새지 않게 */
  background-color: rgb(var(--custom-white));
}

/* ── 맨 윗행: 제목(좌) · 삭제(우) ─────────────────────────────────────── */
.nx-doxcard__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  /* ★★★★ F501(사장님 2026-08-17 화살표3) — *"제목행 아래만 화살표1 같은
     라인 넣는다."*  이 줄과 컬럼 제목 줄 사이가 선 없이 붙어 있으면 두 줄이
     한 덩이로 읽힌다.
     ★★★★ F523 화살표2 → **F532 로 되돌렸다**(사장님 2026-08-17):
       *"제목행 밑에 외곽 테두리와 같은 라인 없애 줘."*  하루 안에 옅은 선 →
       진한 선 → **선 없음** 으로 갔다. 화면을 보시고 정하시는 자리라 그렇다 —
       검사를 지우지 않고 **뜻만 그때그때 옮긴다**(0-1).
     ★ 카드 바깥선은 그대로다. 제목줄과 컬럼제목줄 사이는 **선 없이** 두고,
       컬럼제목 줄의 배경이 그 경계를 말한다. */
  /* ★★★★ F478②(사장님 2026-08-16): *"컬럼제목이 아닌 칸에 배경색이 들어가
     있다 → 제거."*  이 줄은 제목·[삭제] 줄이지 **컬럼제목이 아니다.**
     배경을 깔면 «여기도 머리줄인가» 로 읽혀 진짜 컬럼제목(.nx-dc-k)과
     경쟁한다. 배경은 **컬럼제목 한 곳에만** 둔다. */
}

/* ★★★★★★ F692(사장님 지시 2026-09-02): *"리스트에서도 구분해 줘."*
   제목 **앞**에 갈래 배지. 열을 새로 만들지 않는다 — 여섯 열이 일곱이 되면
   F691 에서 방금 재서 맞춘 최소 너비(1200px)가 그 자리에서 다시 깨진다.
   ★ `flex: 0 0 auto` — 제목이 아무리 길어도 배지는 안 찌그러진다(제목 쪽이
     `flex: 1 1 auto` 라 줄어드는 몫을 가져간다).
   ★ 라운드 0(F210) — 배지도 모서리를 안 굴린다. 알약 모양 금지.
   ★ 색은 있는 토큰에서 가져온다: 매뉴얼은 primary(`--nx-primary` — F687 이
     들여온 그것), FAQ 는 정보색. 새 색을 만들지 않는다. */
.nx-doxkind {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 6px;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #fff;
  background: var(--nx-primary);
  border-radius: 0;
}
/* 갈래별 색 — 기본(위)이 매뉴얼, FAQ 만 갈아 끼운다. `--manual` 을 따로
   안 적는 이유: 규칙이 둘이면 «둘 다 고쳐야 하는데 하나만 고친» 날이 온다. */
.nx-doxkind--faq { background: rgb(var(--info, 14 165 233)); }
/* F703: 북 — 세 번째 색을 새로 만들지 않는다. 이미 있는 무리(secondary)를 쓴다. */
.nx-doxkind--book { background: rgb(var(--secondary, 139 92 246)); }

.nx-doxcard__name {
  /* ★ 제목이 아무리 길어도 **삭제 버튼을 밀어내지 못한다.** 옛 표에서
     정확히 이것이 안 되어 [삭제]가 화면 밖으로 나갔다(F412·F430).
     `min-width: 0` 이 없으면 flex 칸의 최소 폭이 min-content 라 안 줄어든다. */
  min-width: 0;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 0.15rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-doxcard__name > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nx-doxcard__name:hover { color: rgb(var(--primary)); }

/* ★★ 사장님 캡처 2026-08-14: **`Delete` 가 `Delet / e` 로 쪼개진다.**
   제목 쪽은 `min-width:0; flex:1 1 auto` 로 «줄어들어라» 가 돼 있는데,
   그 옆의 [삭제] 버튼에는 아무 규칙이 없었다. 플렉스 항목의 기본값은
   `flex-shrink: 1` 이라 **버튼도 같이 줄어들고**, 줄어든 폭 안에서 글자가
   줄바꿈된다. 버튼은 «글자 길이만큼만 차지하고 줄지 않는다» 여야 한다.
   ★ 독일어 `Löschen`·`AI-Prüfung starten` 은 더 길다 — 여유가 더 필요하다. */
/* ★★★★ F500(사장님 2026-08-17) — *"삭제 버튼 글 줄바꿈 안 되게."*
   좁은 창에서 「삭 / 제」로 쪼개졌다(실측 캡처). 단추 글자는 **한 줄**이고,
   좁으면 줄이는 것은 글자가 아니라 **제목** 쪽이다. */
.nx-doxcard__top > .ti-btn,
.nx-doxcard__top > a.ti-btn {
  white-space: nowrap;
  flex: 0 0 auto;
  flex: 0 0 auto;          /* ① 버튼이 **먼저** 자리를 잡는다(안 줄어든다) */
  white-space: nowrap;     /* ② 글자를 쪼개지 않는다 */
}
/* ★ 2026-08-14: 여기에 `max-width: calc(100% - 10rem)` 를 넣었다가 **뺐다.**
   제목 칸이 억지로 좁아져 첫 줄이 «좁은 상자 + 휑한 회색» 으로 망가졌다
   (사장님 캡처). 제목은 원래대로 **남는 폭을 다 쓰고** 넘칠 때만 잘린다 —
   위 ①② 만으로 버튼은 이미 안 줄고 안 쪼개진다. 건드릴 이유가 없었다. */
/* 격자 안의 버튼·배지도 같은 규칙 — 값 칸이 좁아져도 글자를 안 쪼갠다. */
.nx-dc-v .ti-btn,
.nx-dc-v .badge { white-space: nowrap; }

/* ── 4열 격자 ─────────────────────────────────────────────────────────
   auto = 라벨(내용 폭) · 1fr = 값(남는 폭을 반씩). 두 쌍이 같은 폭을
   갖도록 1fr 을 둘 다 쓴다. */
/* ★★ F421b(사장님 재지시 2026-08-14) — **지그재그를 없앤다.**
   *"표순서를 지그재그로 하지 말고 좌측 …, 우측 … 이렇게 하고, 1열일 때는
     좌측 아래 우측이 오게 할 수 있는가?"*  → 할 수 있다.

   행 우선(4열 한 판)으로 채우면 왼쪽·오른쪽이 번갈아 읽힌다. 그래서 **줄을
   두 덩이로 나눈다** — 왼쪽 6쌍 · 오른쪽 6쌍. DOM 순서가 그대로 «왼쪽 전부
   → 오른쪽 전부» 라, 좁아져 한 줄이 되면 **왼쪽 아래에 오른쪽이 온다.**
   CSS 를 바꿀 필요조차 없다(그게 이 구조를 고른 이유다). */
/* ★★★★ 2026-08-15 사장님 지시 — **가로 표**로 압축한다.
   *"위 제목라인 바로 아래 컬럼 6개를 가로로 넣고 컬럼이름을 굵은체로 강조,
     그 아래 행에 각 컬럼에 해당하는 설명과 버튼 … 목적은 하나의 DOX 리스트의
     높이를 최대한 줄이는 것. 768 이하는 가로 컬럼 4개씩 총 6행."*

   markup 은 **한 벌**이다(칸 24개가 순서대로 흐른다) — 두 벌로 만들면
   폴러·팝업 배선이 두 번 붙는다. 어느 칸이 몇 행 몇 열인지는 **여기서**
   정한다. 768 위: 6열 × 4행 · 768 아래: 4열 × 6행. */
/* ★★★★★ F486(사장님 지시 2026-08-17) — **열 최소 너비 + 가로 스크롤.**
   *"브라우저 너비에 따른 CSS 는 다 지우고 각 컬럼 최소 너비 180·100·210·
     160·120·280 … 1050px 이하로 줄어들면 맨 위 제목 행은 그냥 두고 나머지는
     맨 아래에 손으로 터치할 수 있을 정도 두께의 가로 스크롤이 생겨 …"*

   ★ 왜 껍데기(`__scroll`)가 따로 필요한가 — 스크롤을 **격자 자신**에게 주면
     제목 줄까지 같이 밀린다. 사장님 지시는 «제목 행은 그냥 두고» 다.
   ★ `fr` 값을 최소 너비와 **같은 비율**로 둔다(180fr·100fr…). 넓어질 때
     여섯 열이 제 몫만큼만 늘어나 «어떤 칸만 휑한» 것이 안 생긴다.
   ★ 반응형(4열×6행) 규칙은 **걷었다** — 지시가 «다 지운다» 였다.
     그 자리를 지키던 검사는 지우지 않고 **뜻을 뒤집어** 남겼다(0-1). */
.nx-doxcard__scroll {
  overflow-x: auto;
  overflow-y: hidden;
  /* ★ `scrollbar-width` 를 쓰지 않는다 — 그 값을 주면 크롬이
     `::-webkit-scrollbar` 를 **통째로 무시**해서 막대가 겹쳐 뜨는
     얇은 것(두께 0)으로 남는다. 실측으로 잡았다(F486). */
}
.nx-doxcard__scroll::-webkit-scrollbar { height: 14px; }
.nx-doxcard__scroll::-webkit-scrollbar-track {
  background: rgb(var(--light) / 0.5);
}
.nx-doxcard__scroll::-webkit-scrollbar-thumb {
  background: rgb(var(--nx-dc-line));
  border-radius: 0;               /* 라운드 0 — 전 화면 규칙 */
}

.nx-doxcard__grid {
  display: grid;
  /* ★★★★★ F649(사장님 지시 2026-08-23): 장·쪽 칸에 [리포트]+[그림 글자]와
     이미지 변환 **진행 배지·막대**까지 들어온다 — 100px 로는 옆 칸과 겹친다.
     칸을 220px 로 넓히고 전체 최소 너비를 그만큼 키워 **겹치기 전에 가로
     스크롤이 먼저** 생기게 한다(스크롤은 .nx-doxcard__scroll 이 이미 담당). */
  /* ★★★★★★ F689(사장님 지시 2026-09-01): *"단추 너비가 두 개니까 리스트의
     너비를 더 넓혀서 기본 너비에서 깨지지 않게 해줘."* — 검수 칸(3열)에
     [변환 정밀검수]·[번역 정밀검수] 두 단추와 설명 아이콘이 들어온다.
     210px 로는 단추가 줄바꿈되며 옆 칸과 붙는다. 전체 최소 너비를 그만큼
     키워 **겹치기 전에 가로 스크롤이 먼저** 생기게 한다(스크롤은
     `.nx-doxcard__scroll` 이 이미 담당 — F649 와 같은 처방).
     ★ **420px 은 재서 나온 값이다**(재현대 k25_rvwidth): 실제 CSS·실제 5언어
       글자로 그려 «한 줄에 들어가는가» 를 쟀다 — 340px 은 en·de 가 접히고,
       380px 은 de 가 접힌다. **가장 긴 것은 독일어**다. 짐작으로 정하지
       않았다(0-9). 문구가 길어지면 그 자를 다시 돌린다.
     ★★★★★★ F691(2026-09-01) — 검수 칸이 **두 줄**이 되면서 420px 이 필요
       없어졌다. 한 줄일 때는 «단추 둘 + 아이콘의 합» 이 필요폭이었지만, 두
       줄이면 **가장 넓은 한 줄**이면 된다.
       재현대 `harness_f691` 실측(다섯 언어 · 안여백 포함한 «필요 최소»):
           SOURCE  ko 104 · zh-TW 117 · ja 112 · de 143 · **en 150**
           장·쪽   ko 132 · zh-TW 129 · ja 140 · de 177 · **en 183**
           검수    ko 171 · zh-TW 169 · ja 163 · en 212 · **de 234**
       ⇒ 검수 칸을 **240px**(잰 값 234 + 여유 6)으로 되돌린다. 앞 두 칸은
         180·220 그대로 둔다 — 이미 필요폭 위이고, 좁히라는 말씀은 없었다.
       ⇒ 표 전체 최소 너비가 1380 → **1200px**. 사장님이 F689 에서 걱정하신
         «기본 너비에서 깨진다» 가 오히려 더 멀어진다(가로 스크롤이 늦게
         생긴다). */
  min-width: 1200px;              /* = 180+220+240+160+120+280 */
  grid-template-columns:
    minmax(180px, 180fr) minmax(220px, 220fr) minmax(240px, 240fr)
    minmax(160px, 160fr) minmax(120px, 120fr) minmax(280px, 280fr);
}

/* ★★★★★★ F689 — 검수 단추 둘 + 설명 아이콘을 한 줄로. 좁아지면 접힌다
   (접히는 것이 옆 칸을 밀고 들어가는 것보다 낫다). */
.nx-rvbtns {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.nx-dc-k,
.nx-dc-v {
  padding: 0.3rem 0.55rem;
  border-bottom: 1px solid rgb(var(--default-border));
  border-right: 1px solid rgb(var(--default-border));
  min-height: 2.1rem;
  display: flex;
  align-items: center;
  min-width: 0;
}

/* 컬럼 이름 = **굵은체로 강조**(사장님 지시). 값줄과 확실히 갈린다. */
.nx-dc-k {
  justify-content: flex-start;
  font-size: 0.78rem;
  font-weight: 700;
  /* ★★★★ F478③(사장님 2026-08-16): *"컬럼제목을 #000 볼드."*
     `--text-muted` 는 흐린 회색이라 «굵은체로 강조» 가 무색이었다.
     사장님이 값을 **직접 지정**하셨으므로 그대로 못 박는다.
     ★ 다크에서는 #000 이 안 보인다 — 아래 `.dark` 에서 되돌린다. */
  color: #000;
  /* ★ 사장님 지시 2026-08-17: 반투명(0.5)을 **불투명(1)** 으로. 0.5 는
     아래 배경이 비쳐 폭·다크에 따라 색이 달라 보였다 — 값 하나로 못 박는다. */
  background-color: rgb(var(--light) / 1);
  white-space: nowrap;
  /* ★★★★ F501(사장님 2026-08-17 화살표1·2) — *"이전대로 옅은 것."*
     하루 전 F486⑦ 로 이 줄을 **바깥선과 같은 진한 선**으로 바꿨는데, 사장님이
     화면을 보시고 **되돌리기로 정하셨다.** 안쪽 격자선은 전부 옅은 한 종류다
     — 진한 선은 «한 덩이» 를 나타내는 바깥선에만 쓴다.
     ★ 검사를 지우지 않고 **뜻을 뒤집었다**(0-1): 이제 «안쪽 선은 옅다» 를
       못 박는다. 지웠으면 다음 사람이 다시 진하게 해도 아무도 안 막는다. */
}

.nx-dc-v {
  justify-content: flex-start;
  gap: 0.3rem;
  flex-wrap: wrap;
  font-size: 0.86rem;
  /* ★★★★ F523 화살표3·4(사장님 2026-08-17): *"제목 컬럼이 아닌 이 행들은
     높이를 **6px 높이고** 버튼이나 설명을 세로 **중간에** 배치해서 상하
     여백을 늘려 줘."*
     ★ 컬럼제목 줄(`.nx-dc-k`)은 **그대로 둔다** — 사장님이 «제목 컬럼이
       아닌» 이라고 못 박으셨다.
     ★ 숫자를 새로 짓지 않는다: 위 공통 규칙의 2.1rem 에서 **6px 만** 더한다.
       공통값이 바뀌면 이 줄도 따라온다.
     ★ 가운데 배치는 위 공통 규칙(`align-items: center`)이 이미 한다 —
       두 벌로 적지 않는다. 높이만 늘리면 그만큼 위아래가 함께 벌어진다. */
  /* ★ F532(사장님 2026-08-17): 6px 으로는 부족하다 하셔서 **주신 값 그대로**
     25px 로 올린다. 숫자를 지어내지 않는다 — 화면을 보시고 정한 값이다. */
  min-height: calc(2.1rem + 25px);
}

/* ★★★★★ F634-1-2(사장님 지시 2026-08-22 · 화살표2): *"리포트 버튼이 장.쪽
   옆으로 줄바꿈하지 말고 붙어있게 해줘"*

   이 칸은 위 `.nx-dc-v` 의 `flex-wrap: wrap` 을 물려받아, 칸이 조금만 좁아도
   「1 · 24」와 [리포트] 가 **두 줄로 갈렸다**(사장님 화면).
   ⇒ **이 칸만** 줄바꿈을 끈다. `wrap` 은 다른 칸의 «둘째 줄 배지»
     (`.nx-dc-line2`)가 쓰는 것이라 공통 규칙에서 걷으면 그쪽이 깨진다.
   ★ 숫자와 버튼 둘 다 이미 `whitespace-nowrap` 이라 글자 안에서도 안 쪼개진다.
   ★ 아주 좁은 화면에서 넘치지 않게 `min-width:0` 은 공통 규칙에 이미 있다. */
.nx-dc-v[data-nx-cell="chapters"] { flex-wrap: nowrap; }

/* ★★★★★★ F691(사장님 지시 2026-09-01 · 화살표 다섯): *"화살표 컬럼을 항시
   2줄로 하여 최소의 경우도 컬럼끼리 겹침이 없도록 해 줘."*

   무엇이 잘못돼 있었나 — **한 줄에 다 넣으려 했다.** 그러면 그 칸의 최소
   너비는 «속엣것의 합» 이어야 하는데, 단추마다 `whitespace-nowrap` 이라
   글자로도 안 접히고, 장·쪽 칸은 바로 위 F634-1-2 가 `flex-wrap: nowrap`
   까지 못 박아 두었다. ⇒ 좁아지면 접히는 대신 **옆 칸 위로 흘러넘쳤다.**
   (재현대 harness_f691 실측: 장·쪽 칸이 ko 29 · zh-TW 26 · ja 44 · de 88 ·
    **en 93px** 넘쳤다. 사장님 화면의 [그림글자 번역] 이 [변환 정밀검수] 를
    덮은 그것이다.)

   두 줄로 세우면 필요한 최소 너비가 «합» 에서 **«가장 넓은 하나»** 로 떨어
   진다 — 그래서 「최소의 경우도 안 겹친다」가 성립한다.

   ★ 왜 flex 가 아니라 grid 인가: flex 로 줄을 가르려면 `flex: 0 0 100%` 를
     줘야 하는데 그러면 단추가 **칸 너비만큼 늘어난다**(가로로 긴 막대). grid
     는 «제 줄을 차지하되 제 너비로 선다» 를 그대로 말할 수 있다
     (`grid-column: 1 / -1` + `justify-items: start`).
   ★ F634-1-2 의 약속은 **그대로 지킨다** — 「장·쪽」과 [리포트] 는 첫 줄에
     나란히 선다(격자의 1행 · 하네스 ⑤ 가 그것을 잰다). 위의 `flex-wrap`
     줄은 display 가 grid 로 바뀌어 힘을 잃지만 **지우지 않는다**(0-7):
     되돌릴 일이 생기면 이 블록만 걷으면 옛 모양이 그대로 살아난다. */
.nx-dc-v[data-nx-cell="source"],
.nx-dc-v[data-nx-cell="chapters"] {
  display: grid;
  justify-content: start;
  justify-items: start;
  align-content: center;
  gap: 0.3rem;
}
/* SOURCE — 배지 하나, 단추 하나. **한 칸짜리 격자**라 저절로 두 줄이 된다. */
.nx-dc-v[data-nx-cell="source"] { grid-template-columns: minmax(0, auto); }
/* ★★★★★★ F782(사장님 실기동 2026-09-07: *"리스트에 진행바가 아예 안
   나타난다"*) — **여기가 빠져 있었다.**

   F691 이 이 칸을 `display: grid; justify-items: start` 로 바꾸면서 격자
   자식은 **제 내용만큼**만 넓어졌다. 변환 진행바의 바깥 상자
   (`[data-nx-cv-bar]`)가 그 자식이라, 안의 막대는 `flex: 1 1 auto` +
   `min-width: 0`(F612-6) 이라 **0 까지 줄어든다.** ⇒ 핀만 돌고 막대는 폭 0.
   브라우저에 물어서 잡았다(0-1b 실측 2026-09-07): 칸 22px · 막대 **0px**.

   ★★★ **바로 아래 「장·쪽」 칸에는 이 줄이 이미 있었다**(`[data-nx-fx-bar]`).
     그래서 그림글자 진행바는 보이고 **변환 진행바만** 안 보였다 — 같은
     결함을 한쪽에만 고쳐 둔 자리다(0-3: 그 줄이 아니라 **부류**를 막는다).
   ★ 최소 폭을 함께 준다 — 이 칸의 열 너비는 «가장 넓은 자식» 이라, 배지가
     짧은 언어(대기 중 「대기 3번째」 등)에서는 늘여도 여전히 짧다. */
.nx-dc-v[data-nx-cell="source"] > [data-nx-cv-bar] {
  justify-self: stretch;
  min-width: 11rem;
}
/* 장·쪽 — 1행은 「장·쪽」+[리포트], 그 뒤(그림글자 단추·진행 배지·막대)는
   **제 줄을 통째로** 쓴다. */
.nx-dc-v[data-nx-cell="chapters"] { grid-template-columns: auto auto; }
.nx-dc-v[data-nx-cell="chapters"] > :nth-child(n + 3) { grid-column: 1 / -1; }
/* 진행 막대는 줄을 꽉 채워야 보인다(폭이 0 이면 안 보이는 것과 같다). */
.nx-dc-v[data-nx-cell="chapters"] > [data-nx-fx-bar] { justify-self: stretch; }

/* 검수 칸 — 1행 [변환 정밀검수] · 2행 [번역 정밀검수] + (안내 아이콘).
   ★ 아이콘은 **2행에 붙인다** — 번역 검수 옆이 아니라 칸 전체의 설명이지만,
     제 줄을 따로 쓰면 세 줄이 된다(사장님은 «항시 2줄» 이라 하셨다).
   ★★ 선택자가 `.nx-rvbtns` 만으로는 **안 먹는다.** 아래 F349 의
      `.nx-dc-v > div { display: flex }` 가 더 좁아서(0,1,1 > 0,1,0) 이긴다 —
      `grid-template-columns` 만 들어가고 `display` 는 flex 로 남아 한 줄이
      그대로였다. 짐작이 아니라 **브라우저에게 물어서** 알아냈다(CDP
      `CSS.getMatchedStylesForNode` 가 이긴 규칙과 줄 번호를 그대로 알려
      준다 · 0-1b). ⇒ 앞에 `.nx-dc-v >` 를 붙여 같은 자리에서 이긴다. */
.nx-dc-v > .nx-rvbtns {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  justify-items: start;
  align-items: center;
}
.nx-dc-v > .nx-rvbtns > :first-child { grid-column: 1 / -1; }

/* ★★★★ F523 화살표5(사장님 2026-08-17): *"좌측 배치로, 위 버튼과 좌측 여백이
   같게 해 줘."*  둘째 줄(배지 줄)이 첫 줄 뒤에 이어 붙어 오른쪽으로 밀려
   있었다. **자기 줄을 통째로** 차지하게 하면 칸의 왼쪽 끝에서 시작한다 —
   위 버튼과 **같은 자리**다(둘 다 칸의 안여백에서 시작한다). */
.nx-dc-v > .nx-dc-line2 {
  flex: 0 0 100%;
  margin-inline-start: 0;
  /* ★ 줄을 통째로 차지하게 한 것만으로는 부족했다 — **글자 정렬이 가운데로
     상속**되고 있어 배지가 줄 안에서 가운데에 섰다(실측: 줄 폭 174px ·
     배지 106px · 어긋남 34px = 차이의 정확히 절반. 그 숫자가 원인을 말해
     주었다). 위 버튼은 flex 항목이라 이 상속을 안 타서 혼자 왼쪽에 있었다. */
  text-align: start;
  /* ★ 이 줄은 **flex 상자**로 서 있었고(어디선가 그렇게 정해진다) 그 정렬이
     오른쪽이었다 — 실측: 줄 174px · 배지 140px · 왼쪽에 남은 34px. 글자 정렬만
     고쳐서는 안 움직인 이유다. 정렬을 **여기서 못 박는다**(짐작하지 않고
     재서 정했다 — 0-1b). */
  display: flex;
  justify-content: flex-start;
  gap: 0.3rem;
}

.nx-dc-num { font-variant-numeric: tabular-nums; }

.nx-dc-x { color: rgb(var(--text-muted)); font-weight: 600; cursor: help; }

.dark .nx-dc-k {
  background-color: rgba(255, 255, 255, 0.03);
  /* F478③ — 다크에서는 #000 이 바탕에 묻힌다. 밝은 쪽 «#000 볼드» 와 **같은
     뜻**(가장 또렷한 글자색)을 다크에서 지키는 값이다. */
  color: #f3f5f8;
}
/* ★ F478② — 다크에도 같은 규칙: 제목줄에는 배경을 안 깐다.
   (여기만 지우면 밝은 화면에서만 사라져 두 화면이 갈린다.) */
/* F478① — 바깥선은 다크에서도 «약간 진하게». 불투명색으로 둔다. */
.dark .nx-doxcard { --nx-dc-line: 75 85 101; }

/* ── 6열 × 4행 — **폭과 무관하다**(F486: 반응형 규칙을 걷었다) ──
   ★ 열 정의는 위 `.nx-doxcard__grid` 한 곳뿐이다. 여기에 또 적으면
     **뒤에 있는 것이 이긴다** — 실제로 그렇게 덮고 있었다(F486 실측). */
.nx-doxcard__grid > :nth-child(1) { grid-column: 1; grid-row: 1; }
.nx-doxcard__grid > :nth-child(2) { grid-column: 1; grid-row: 2; }
.nx-doxcard__grid > :nth-child(3) { grid-column: 2; grid-row: 1; }
.nx-doxcard__grid > :nth-child(4) { grid-column: 2; grid-row: 2; }
.nx-doxcard__grid > :nth-child(5) { grid-column: 3; grid-row: 1; }
.nx-doxcard__grid > :nth-child(6) { grid-column: 3; grid-row: 2; }
.nx-doxcard__grid > :nth-child(7) { grid-column: 4; grid-row: 1; }
.nx-doxcard__grid > :nth-child(8) { grid-column: 4; grid-row: 2; }
.nx-doxcard__grid > :nth-child(9) { grid-column: 5; grid-row: 1; }
.nx-doxcard__grid > :nth-child(10) { grid-column: 5; grid-row: 2; }
.nx-doxcard__grid > :nth-child(11) { grid-column: 6; grid-row: 1; }
.nx-doxcard__grid > :nth-child(12) { grid-column: 6; grid-row: 2; }
.nx-doxcard__grid > :nth-child(13) { grid-column: 1; grid-row: 3; }
.nx-doxcard__grid > :nth-child(14) { grid-column: 1; grid-row: 4; }
.nx-doxcard__grid > :nth-child(15) { grid-column: 2; grid-row: 3; }
.nx-doxcard__grid > :nth-child(16) { grid-column: 2; grid-row: 4; }
.nx-doxcard__grid > :nth-child(17) { grid-column: 3; grid-row: 3; }
.nx-doxcard__grid > :nth-child(18) { grid-column: 3; grid-row: 4; }
.nx-doxcard__grid > :nth-child(19) { grid-column: 4; grid-row: 3; }
.nx-doxcard__grid > :nth-child(20) { grid-column: 4; grid-row: 4; }
.nx-doxcard__grid > :nth-child(21) { grid-column: 5; grid-row: 3; }
.nx-doxcard__grid > :nth-child(22) { grid-column: 5; grid-row: 4; }
.nx-doxcard__grid > :nth-child(23) { grid-column: 6; grid-row: 3; }
.nx-doxcard__grid > :nth-child(24) { grid-column: 6; grid-row: 4; }
.nx-doxcard__grid > :nth-child(11),
.nx-doxcard__grid > :nth-child(12) { border-right: 0; }
.nx-doxcard__grid > :nth-child(23),
.nx-doxcard__grid > :nth-child(24) { border-right: 0; }
.nx-doxcard__grid > :nth-child(14) { border-bottom: 0; }
.nx-doxcard__grid > :nth-child(16) { border-bottom: 0; }
.nx-doxcard__grid > :nth-child(18) { border-bottom: 0; }
.nx-doxcard__grid > :nth-child(20) { border-bottom: 0; }
.nx-doxcard__grid > :nth-child(22) { border-bottom: 0; }
.nx-doxcard__grid > :nth-child(24) { border-bottom: 0; }


/* F422: 검수 확인 팝업의 «몇 쪽 · 몇 크레딧» — 카드 격자와 같은 말투로. */
.nx-rv-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  border: 1px solid rgb(var(--default-border));
}

.nx-rv-k,
.nx-rv-v {
  padding: 0.45rem 0.7rem;
  border-bottom: 1px solid rgb(var(--default-border));
  display: flex;
  align-items: center;
}

.nx-rv-k {
  font-size: 0.8125rem;
  color: rgb(var(--text-muted));
  background-color: rgb(var(--light) / 0.5);
  white-space: nowrap;
  border-right: 1px solid rgb(var(--default-border));
}

.nx-rv-v { justify-content: flex-end; }
.nx-rv-facts > :nth-last-child(-n + 2) { border-bottom: 0; }
.dark .nx-rv-k { background-color: rgba(255, 255, 255, 0.03); }

/* ★ F349(사장님 2026-08-10) 를 카드에서도 지킨다 — «기본(버튼)에 추가되는
   상황설명은 **줄을 바꾼다**». 값 칸은 flex-wrap 이라 폭이 남으면 배지 줄이
   버튼 **옆에** 붙는다(1700px 실측). 100% 를 줘서 늘 제 줄을 갖게 한다. */
.nx-dc-v > div { flex: 0 0 100%; display: flex; justify-content: flex-end; }

/* ---------------------------------------------------------------------------
   ★★ 상태 강조 (사장님 지시 2026-08-14)

   원본은 상태 배지가 `bg-success/10`(농도 10%)이라 같은 카드의 다른 배지들
   — 무료·유료·무기한 — 과 **크기도 굵기도 똑같았다.** 「이 문서가 지금
   열려 있나」는 이 표에서 **가장 먼저** 보여야 하는 정보인데 묻혀 있었다.

   ★ 색은 상태에서 온다(`data-nx-status`) — 화면이 클래스를 골라 붙이지
     않는다. 상태가 늘면 여기 한 줄만 는다.
   --------------------------------------------------------------------------- */

/* ① 물들이는 것은 **컬럼제목 칸 하나**다.
   ★★★★ F524(사장님 실기동 2026-08-17): *"STATUS 컬럼만 컬럼제목이 아닌데도
     셀 배경색이 들어갔다. 제거해 줘."*
     맞는 지적이다. `.nx-dc-status` 는 **제목 칸과 값 칸 둘 다**에 붙어 있어
     이 규칙이 값 칸까지 물들이고 있었다 — 상태 칸 하나만 다른 값 칸들과
     달라 보였다. F478② 에서 사장님이 정하신 규칙은 «배경은 컬럼제목 한
     곳에만» 이다. 그 규칙이 여기서만 새고 있었다.
   ★ 선택자를 `.nx-dc-k` 로 좁힌다 — 색을 지우는 것이 아니라 **닿는 자리**를
     바로잡는 것이다(값 칸에 흰색을 덧칠해 덮지 않는다 — 그건 편법이다). */
.nx-dc-k.nx-dc-status[data-nx-status="publishing"] {
  background-color: rgb(var(--success) / 0.12);
}

.nx-dc-k.nx-dc-status:not([data-nx-status="publishing"]) {
  /* ★ 사장님 지시 2026-08-17: 0.7 → **불투명(1)**. 컬럼제목 배경(`.nx-dc-k`)
     과 **같은 값**이라, 상태 칸만 살짝 다르게 보이던 것이 사라진다. */
  background-color: rgb(var(--light) / 1);
}

/* ② 배지는 **꽉 찬 색 + 흰 글씨**로 (10% → 100%). */
.nx-status-badge {
  font-weight: 600;
  font-size: 0.8125rem;
  padding: 0.3rem 0.65rem;
  letter-spacing: 0.01em;
  color: #fff;
  background-color: rgb(var(--secondary));
}

.nx-dc-status[data-nx-status="publishing"] .nx-status-badge {
  background-color: rgb(var(--success));
}

/* 파이프라인 상태(변환·번역 중)는 «지금 뭔가 돌고 있다» 라 따로 본다. */
.nx-dc-status[data-nx-status="converting"] .nx-status-badge,
.nx-dc-status[data-nx-status="translating"] .nx-status-badge {
  background-color: rgb(var(--warning));
}

.nx-dc-status[data-nx-status="failed"] .nx-status-badge {
  background-color: rgb(var(--danger));
}

.dark .nx-dc-k.nx-dc-status:not([data-nx-status="publishing"]) {
  background-color: rgba(255, 255, 255, 0.05);
}

/* --------------------------------------------------------------------------
 * 로딩핀 + 진행바 한 줄 — `.nx-pgrow`  (D011, 사장님 지시 2026-08-20)
 *
 * 사장님: *"리스트 진행바 앞에도 로딩핀 붙여줘. 각 페이지·팝업의 진행바 앞
 * 로딩핀은 F578-1 의 로딩핀이 아니라 CSS 에 있는 F578-2 의 로딩핀이어야 한다."*
 *
 * 마크업의 정본은 `ui/_ui.html` 의 `progress_pin()` 매크로 하나다 — 화면에서
 * 이 클래스를 손으로 짜지 마라(F221: 두 벌이면 한쪽만 고쳐진다).
 *
 * ★★★★★★ 핀 모양은 **사장님이 고르셨다**(2026-08-21): 상세보기에서 돌던
 *   **원호**(`ri-loader-4-line`). 내가 이름표를 거꾸로 달아 «F578-2 = 별표»
 *   로 적어 두었던 것을 바로잡는다.
 * ★ 옛 F578-1 의 잘못은 «원호» 가 아니라 **화면마다 `@keyframes` 를 따로
 *   둔 것**이었다(팝업·상세·검수가 제각각). 그래서 도는 규칙은 **여기 한
 *   곳**에만 둔다 — tailwind `animate-spin` 에도 기대지 않는다(뷰어는 그
 *   유틸리티를 안 싣는 독립 문서다).
 * ★ 원형은 남긴다 — 「전부 라운드 0」 규칙의 예외다(위 «스피너는 뺀다» 참조).
 *   각진 것이 돌면 도는 것으로 안 읽힌다.
 * ----------------------------------------------------------------------- */
.nx-pgrow {
  display: flex;
  align-items: center;
  gap: 8px;
  /* ★★★★★ F612-6(사장님 2026-08-21: *"진행막대가 없어졌다"*) — **여기였다.**
   *
   * MY DOX 목록의 SOURCE 칸은 **자기도 flex** 다. 그래서 이 줄이 그 칸의
   * flex 자식이 되는데, flex 자식의 기본 폭은 «내용만큼» 이다. 안쪽 막대는
   * `min-width:0`(바로 아래) 이라 0 까지 줄어들 수 있으므로 이 줄이
   * **핀 하나 폭** 으로 쪼그라들고 막대는 **폭 0** 이 된다.
   * 브라우저에 물어서 잡았다(0-1b 실측): 줄 22px · 막대 **0px** · 핀만 남았다.
   * 사장님 화면에서 «핀만 돌고 막대가 없다» 로 보인 것이 정확히 이것이다.
   *
   * ⇒ 부모가 flex 든 block 이든 **이 줄은 제 줄 폭을 다 쓴다.**
   * ★ 예외는 번역 목록 하나뿐이다 — 거기서는 폭을 9rem 으로 못 박는다
   *   (`.nx-tr-list .nx-pgrow`, 위 F335 절). 그 규칙이 특이도로 이긴다. */
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
}

/* 막대가 줄의 남는 폭을 다 먹는다. `min-width:0` 이 없으면 좁은 칸(목록의
   SOURCE 칸)에서 핀이 밀려 나간다 — flex 자식의 기본 최소폭 때문이다. */
.nx-pgrow__bar {
  flex: 1 1 auto;
  min-width: 0;
}

/* ★ 핀에 **제 크기**를 준다(F591 에서 배운 것). 아이콘 글꼴이 늦게 오거나
   없으면 빈 글자라 폭이 0 이 되어, 막대만 덩그러니 남고 줄 자리가 흔들린다. */
/* ★★★★★★ F651(2026-08-22) — **도는 규칙은 `nx-shell-parts.css` 로 옮겼다.**
   여기 있으면 뷰어·나란히 보기에서 **안 돈다**: 그 문서들은 `head_css(parts=true)`
   로 부품 CSS 만 싣고 이 파일은 안 싣는다(실측). F578-1 이 «화면마다 keyframes
   를 따로 둬서 안 돌던» 그 사고와 같은 자리다 — 그래서 옮겼지, 두 벌로 만들지
   않았다(0-0). 선언은 지금도 **한 곳**이다. */

.nx-pgrow__pin {
  animation: nx-pgrow-spin 1s linear infinite;
  flex: none;
  display: inline-block;
  width: 14px;
  height: 14px;
  font-size: 14px;
  line-height: 14px;
  text-align: center;
  color: rgb(var(--primary));
}

/* 진행바가 담긴 줄에서는 막대의 아래 여백을 없앤다(핀과 높이를 맞춘다). */
.nx-pgrow__bar .progress {
  margin-bottom: 0;
}
