/* ========================================
   매직브러시 — 목록 상주형 편집 화면

   설계 근거: docs/prd-magic-brush.md §5-4-3

   🔴 **이 도구는 화면을 끝에서 끝까지 쓴다.** 도구 페이지 중 유일하다.
      캔버스가 폭이 아니라 **높이에 갇히기** 때문이다 — 상품 사진이 대개 정사각이라
      `표시크기 = min(폭, 높이)` 인데 세로가 항상 먼저 바닥난다.
      그래서 세로 여백 한 줄이 실제 캔버스 크기를 그대로 깎는다.
      (제목 줄 하나를 없애 1366×768 에서 544 → 600px 를 벌었다)

   🔴 목록 400px 은 **공짜에 가깝다** — 폭이 남아돌기 때문이다.
   🔴 사이드바를 접어도(216→60) 캔버스는 안 커진다. 높이가 병목이라서.
   ======================================== */

/* 🔴 `hidden` 속성이 이기게 만든다 — **이 파일에서 제일 먼저 지킬 규칙**이다.
   아래 블록들은 display:flex/grid 를 직접 준다. 그 순간 브라우저 기본값인
   `[hidden]{display:none}` 을 **이겨 버려서**, JS 가 `.hidden = true` 로 감춰도
   화면에 그대로 남는다 — 드롭존이 목록 위에 남고 빈 안내가 캔버스 위에 겹쳤다.
   (소스메이커에서도 같은 함정을 밟은 적이 있다) */
[hidden] {
  display: none !important;
}

:root {
  --mb-list-w: 400px;
  --mb-rail-w: 88px;
  --mb-gap: 12px;
}

/* ────────────── 껍데기 되돌리기 ──────────────
   🔴 tool-main 은 가운데 정렬 + 최대폭 + 넉넉한 상하 패딩을 준다(css/tools.css).
      다른 도구엔 맞지만 여기서는 캔버스를 깎는다 — 이 페이지에서만 되돌린다.
      tool-layout.php 를 고치지 않는 이유: 저 파일은 도구 넷을 공용으로 감싼다. */
.is-app-shell:has(.mb-app) .tool-main {
  max-width: none;
  margin: 0;
  padding: 0;
  /* 사이드바가 fixed 라 tool-shell 의 padding-left 가 자리를 만든다.
     높이는 화면 전체 — 안쪽에서 flex 로 나눈다. */
  height: 100vh;
  height: calc(100dvh - var(--mb-topbar-h, 0px));
  overflow: hidden;

  /* 🔴 **flex 컬럼이어야 한다.** 이 안에는 mb-app 말고도 위에 얹히는 것이 있다 —
     좁은 화면의 오렌지 안내 배너(.mb-unsupported)를 js 가 mb-app **앞에** 꽂는다.
     block 으로 두면 배너 높이만큼 mb-app 이 아래로 밀려 화면 밖으로 나가고,
     **하단 라인이 끝없이 늘어난 것처럼 보인다**(실제로 겪었다).
     🔴 calc 로 배너 높이를 빼는 방식은 쓰지 않는다 — 문구가 두 줄로 접히면
        숫자가 조용히 틀어지고, 증상이 지금과 똑같아 원인을 다시 찾게 된다.
        flex 는 실제 높이를 재므로 그 재발이 없다. */
  display: flex;
  flex-direction: column;
}

/* 배너는 제 높이만 갖고, 남은 자리를 mb-app 이 전부 가져간다.
   🔴 min-height:0 이 없으면 안쪽 목록·캔버스의 스크롤이 안 생긴다. */
.is-app-shell:has(.mb-app) .mb-unsupported { flex: 0 0 auto; }
.is-app-shell:has(.mb-app) .mb-app { flex: 1 1 auto; min-height: 0; }

/* 🔴 제목 줄(page-head)을 이 페이지에서만 감춘다 — **123px 을 되찾는다.**
   tool-layout.php 가 도구마다 제목·설명을 그려 준다(도구가 제 헤더를 그리면
   모양이 갈라지므로 옳은 설계다). 그런데 여기서는 그 123px 이 그대로 캔버스에서
   빠진다 — §5-4-3 이 "편집 영역에 제목 줄을 두지 않는다" 고 못박은 이유이고,
   줄 하나를 없애 1366×768 에서 56px 를 벌었다고 적어 둔 바로 그 자리다.
   이름·설명은 사이드바의 활성 항목과 왼쪽 목록의 선택 표시가 이미 말한다.

   🔴 tool-layout.php 를 고치지 않는다 — 저 파일은 도구 넷을 공용으로 감싼다.
      한 도구의 사정으로 공용 껍데기를 바꾸면 나머지 셋이 조용히 따라 바뀐다. */
.is-app-shell:has(.mb-app) .page-head {
  display: none;
}

/* :has() 를 못 쓰는 브라우저 대비 — 같은 값을 본문 쪽에서 한 번 더 잡는다.
   (부모 패딩까지는 못 지우므로 완벽하진 않지만 화면이 깨지진 않는다) */
.mb-app {
  display: flex;
  gap: var(--mb-gap);
  height: 100%;
  min-height: 0;
  padding: var(--mb-gap);
  box-sizing: border-box;
  background: var(--ink-100);
}

/* ========================================
   좌: 작업목록
   🔴 **접히지 않는다.** 목록이 사라지면 이 도구가 아니게 된다.
   ======================================== */

.mb-list {
  /* 🔴 **고정폭이 아니라 유동이다.** 옛 `flex: 0 0 400px` 은 한 치도 안 물러서서
     좁아지는 몫을 캔버스가 전부 뒤집어썼다 — 그래서 1366px 에서 캔버스가
     714px 로 쪼그라들었고, **창을 넓혔는데 캔버스가 되레 줄어드는**
     역전까지 났다(1280px 레일일 때 940px > 1366px 목록일 때 714px).
     clamp 로 같이 줄어들게 하면 그 역전이 사라진다. */
  flex: 0 1 clamp(240px, 26%, var(--mb-list-w));
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;                 /* 🔴 없으면 안쪽 스크롤이 안 생기고 목록이 화면을 밀어낸다 */
  background: var(--bg-surface);
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-lg, 10px);
  overflow: hidden;
}

.mb-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--ink-200);
}

/* ── 입력 3경로 탭 ── */
.mb-tabs {
  display: flex;
  gap: 2px;
  background: var(--ink-100);
  border-radius: 8px;
  padding: 2px;
}

.mb-tab {
  border: 0;
  background: transparent;
  padding: 5px 12px;
  font-size: var(--font-sm, 0.875rem);
  color: var(--ink-500);
  border-radius: 6px;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.mb-tab:hover { color: var(--ink-700); }

.mb-tab.is-active {
  background: var(--bg-surface);
  color: var(--ink-800);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}

/* ── 선택 줄 ── */
.mb-list-sel {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--ink-200);
  font-size: var(--font-xs, 0.75rem);
  color: var(--ink-600);
}

.mb-check-all {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  user-select: none;
}

.mb-sel-count { color: var(--ink-500); }

/* 🔴 [추가]·[비우기] 를 오른쪽 끝으로 민다 */
.mb-linkbtn {
  border: 0;
  background: transparent;
  padding: 2px 4px;
  font-size: var(--font-xs, 0.75rem);
  color: var(--ink-500);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.mb-linkbtn:first-of-type { margin-left: auto; }
.mb-linkbtn:hover { color: var(--ink-800); }
.mb-linkbtn.is-danger:hover { color: var(--error-color); }

/* ── 드롭존 (= 빈 목록) ── */
.mb-drop {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 12px;
  padding: 20px;
  border: 2px dashed var(--ink-300);
  border-radius: 10px;
  text-align: center;
  color: var(--ink-500);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.mb-drop.is-over {
  border-color: var(--brand-500);
  background: var(--brand-50);
}

/* 🔴 **목록이 찬 뒤의 드롭 표시** — 없으면 "추가가 안 된다" 로 읽힌다.
   드롭 핸들러는 바깥 `mbList` 에 걸려 있어 목록이 차도 **정상 동작한다**.
   그런데 강조 스타일이 `.mb-drop`(빈 상태 안내)에만 있었고 그것은 목록이
   차면 숨는다 → **아무 반응이 없어** 사용자가 파일을 놓지 않고 되돌아갔다.
   실제로 안 되던 게 아니라 **된다는 신호가 없던 것**이다(사용자 신고).

   🔴 `outline` + 음수 offset 을 쓴다(border 가 아니라). border 를 주면 400px
      고정폭 목록의 레이아웃이 밀려 행 전체가 흔들린다 — outline 은 자리를
      차지하지 않는다. */
.mb-list.is-over {
  outline: 2px dashed var(--brand-500);
  outline-offset: -4px;
  background: var(--brand-50);
}

/* 안쪽 스크롤 영역까지 같이 물들여야 한 덩어리로 보인다 — 행 배경이
   흰색이라 놔두면 강조가 테두리에만 걸려 약하다. */
.mb-list.is-over .mb-rows {
  background: transparent;
}

/* 드롭존 아이콘은 장식이라 이모지를 그대로 둔다(상태를 나르지 않는다).
   다만 두부가 되면 보기 싫으므로 폰트를 지정해 둔다. */
.mb-drop-icon {
  font-size: 28px;
  line-height: 1;
  font-family: "Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", sans-serif;
}

.mb-drop-text {
  font-size: var(--font-base, 1rem);
  font-weight: 600;
  color: var(--ink-700);
}

.mb-drop-sub { font-size: var(--font-xs, 0.75rem); }
.mb-drop-btn { margin-top: 6px; }


/* ── 그리드·엑셀 준비 안내 ── */
/* ══════════ 그리드 · 엑셀 입력 (4단계 · §5-4) ══════════
   🔴 목록과 **같은 자리**를 쓴다 — 탭이 갈아끼운다. 목록 아래에 쌓으면
      400px 폭에서 둘 다 좁아져 아무것도 제대로 안 보인다. */
.mb-src {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 12px;
  gap: 8px;
  border-bottom: 1px solid var(--ink-200);
}

.mb-src-help {
  margin: 0;
  font-size: var(--font-xs, 0.75rem);
  color: var(--ink-500);
  line-height: 1.5;
}

.mb-src-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
}

.mb-src-note {
  margin: 0;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
  line-height: 1.5;
}

.mb-src-note.is-ok { color: var(--ink-700); }

/* ── 그리드 ── */
/* 🔴 높이를 고정하고 안쪽만 스크롤한다 — 행이 늘어도 패널이 안 늘어난다 */
.mb-grid-wrap {
  max-height: 220px;
  overflow: auto;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
}

.mb-grid {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-xs, 0.75rem);
  table-layout: fixed;
}

.mb-grid th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 6px 8px;
  text-align: left;
  font-weight: 600;
  color: var(--ink-600);
  background: var(--ink-100);
  border-bottom: 1px solid var(--ink-200);
  white-space: nowrap;
}

.mb-grid-opt {
  font-weight: 400;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-400);
}

.mb-grid-no {
  width: 34px;
  text-align: right;
  color: var(--ink-400);
  font-variant-numeric: tabular-nums;
  user-select: none;
}

/* 🔴 URL 은 길다 — 열을 좁히고 잘라낸다. 안 그러면 표가 가로로 밀려
   상품코드가 화면 밖으로 나간다(400px 목록 안이다). */
.mb-grid th:nth-child(4),
.mb-grid td:nth-child(4) { width: 30%; }

.mb-grid td {
  padding: 5px 8px;
  border-bottom: 1px solid var(--ink-100);
  color: var(--ink-800);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mb-grid-cell:focus {
  outline: 2px solid var(--brand-500, #f60);
  outline-offset: -2px;
  background: var(--bg-surface);
}

/* ── 입력 패널 머리줄 (접기) ── */
/* 🔴 접혀도 이 줄은 남는다 — 사라지면 다시 여는 길이 없어진다 */
.mb-src-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-100);
}

.mb-src-toggle {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-700);
}

.mb-src-caret {
  flex: 0 0 auto;
  transition: transform var(--transition-fast);
  color: var(--ink-500);
}

.mb-src-toggle.is-collapsed .mb-src-caret { transform: rotate(-90deg); }

.mb-src-head-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

/* ── 실패 내역 (접힘) ── */
/* 🔴 32건 중 1건 실패인데 목록을 밀어낼 이유가 없다 */
.mb-url-detail {
  margin: 0 12px 8px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
}

.mb-url-detail > summary {
  cursor: pointer;
  color: #c2410c;
  padding: 2px 0;
}

.mb-url-detail .mb-src-note {
  margin: 4px 0 0;
  padding-left: 12px;
  line-height: 1.6;
  word-break: break-all;
}

/* ── 매크로냥 안내 카드 (소스메이커 .sm-ext 와 같은 형식) ── */
/* 🔴 확장이 있으면 js 가 통째로 숨긴다 — 깔린 사람에게 설치 안내는 잡음이다 */
.mb-ext {
  margin: 12px 12px 0;
  padding: 10px 12px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  background: var(--ink-100);
}

.mb-ext-title {
  font-size: var(--font-xs, 0.75rem);
  font-weight: 700;
  color: var(--ink-700);
  margin-bottom: 2px;
}

.mb-ext-desc {
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
  margin-bottom: 8px;
  line-height: 1.5;
}

.mb-ext-cta {
  display: inline-block;
  font-size: var(--font-2xs, 0.6875rem);
  padding: 5px 12px;
}

/* ── URL 수집 (매크로냥) ── */
/* 🔴 URL 이 하나도 없으면 통째로 숨는다(js) — 안 쓰는 사람에게 설치 광고를 띄우지 않는다 */
.mb-url-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 12px 8px;
  padding: 8px 10px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  background: var(--ink-100);
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-600);
}

.mb-url-text {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.4;
}

.mb-url-cta,
.mb-url-retry {
  flex: 0 0 auto;
  padding: 4px 8px;
  border: 1px solid var(--ink-300);
  border-radius: 4px;
  background: var(--bg-surface);
  color: var(--ink-700);
  font-size: var(--font-2xs, 0.6875rem);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}

.mb-url-cta:hover,
.mb-url-retry:hover { border-color: var(--brand-500, #f60); color: var(--brand-600, #e55); }

/* ── 엑셀 ── */
/* ── 열 지정 요약 (평소엔 이 한 줄만) ── */
/* 🔴 접혀 있을 때도 무엇을 무엇으로 읽었는지는 보여야 한다 —
   안 보이면 접는 것이 곧 숨기는 것이 된다. */
.mb-map-sum {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-600);
}

.mb-map-sum-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 필수 열을 못 잡았을 때 — 표가 자동으로 펴지고 이 줄이 이유를 말한다 */
.mb-map-sum.is-warn {
  border-color: #f0a020;
  background: rgba(240, 160, 32, .08);
  color: #92400e;
}

.mb-xl-guide {
  margin: 0 0 6px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
}

/* 🔴 엑셀은 열이 20개도 넘는다 — 가로 스크롤을 자기 안에서 받는다.
   패널이 늘어나면 400px 목록 전체가 가로로 밀린다. */
.mb-xl-preview {
  max-height: 200px;
  overflow: auto;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
}

.mb-xl-table {
  border-collapse: collapse;
  font-size: var(--font-2xs, 0.6875rem);
}

.mb-xl-table th,
.mb-xl-table td {
  padding: 4px 6px;
  border: 1px solid var(--ink-100);
  max-width: 120px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mb-xl-head-cell {
  background: var(--ink-100);
  color: var(--ink-600);
  font-weight: 600;
}

.mb-xl-select {
  width: 100%;
  font-size: var(--font-2xs, 0.6875rem);
  padding: 2px;
  border: 1px solid var(--ink-200);
  border-radius: 4px;
  background: var(--bg-surface);
  color: var(--ink-600);
}

/* 지정된 열은 색으로 묶어 준다 — 값과 역할이 한눈에 이어져야 판단이 된다 */
.mb-xl-code { background: rgba(255, 102, 0, .10); color: var(--ink-800); }
.mb-xl-name { background: rgba(0, 122, 255, .08); color: var(--ink-800); }
.mb-xl-url  { background: rgba(16, 160, 90, .10); color: var(--ink-800); }
select.mb-xl-code { border-color: var(--brand-500, #f60); }
select.mb-xl-name { border-color: #2d7ff9; }
select.mb-xl-url  { border-color: #10a05a; }

.mb-xl-more {
  margin: 0;
  padding: 4px 6px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-400);
}

/* ── 목록 본체 ── */
.mb-rows {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* 행 — 🔴 그리드가 아니라 행이다. 상품명이 잘리지 않는 게 이유(§5-4-3) */
.mb-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--ink-100);
  cursor: pointer;
  transition: background var(--transition-fast);
}

.mb-row:hover { background: var(--ink-50); }

.mb-row.is-current {
  background: var(--brand-50);
  box-shadow: inset 3px 0 0 var(--brand-500);
}

.mb-row-check { flex: 0 0 auto; cursor: pointer; }

.mb-row-no {
  flex: 0 0 22px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-400);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.mb-row-thumb {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--ink-100);
  border: 1px solid var(--ink-200);
  /* 🔴 끌어서 옮기는 UI 가 아니다 (순서 바꾸기는 없다). 끌 수 있게 두면
     목록 안에 다시 떨어뜨려 **같은 장이 복제됐다.** JS 의 isFileDrag() 와 짝. */
  user-select: none;
  -webkit-user-drag: none;
}

.mb-row-body {
  flex: 1 1 auto;
  min-width: 0;                  /* 🔴 없으면 긴 상품명이 행을 밀어낸다 */
}

.mb-row-name {
  display: block;
  font-size: var(--font-sm, 0.875rem);
  color: var(--ink-800);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 🔴 상품명은 **같은 줄**에 이어 붙는다 — 줄을 하나 더 쓰면 행이 3줄이 되어
   목록에 보이는 장 수가 줄어든다(비율 배지에서 이미 겪은 함정). 코드가 굵고
   상품명이 흐린 순서라, 무엇으로 저장되는지가 먼저 읽힌다. */
.mb-row-title {
  margin-left: 6px;
  color: var(--ink-500);
  font-weight: 400;
}

/* 이름이 코드로 바뀐 장의 원본 파일명 — 어느 파일이 어느 코드가 됐는지 */
.mb-row-file {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-400);
}

.mb-row-file::before { content: '· '; }

/* 🔴 **한 줄에 크기 + 비율 배지를 나란히.** 배지를 아래에 따로 붙였더니 행이
   3줄이 되어 목록에 보이는 장 수가 줄었다(사용자 신고) — 세로가 아까운 화면에서
   배지 하나가 행 높이를 키울 이유가 없다. */
.mb-row-sub {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-400);
}

/* 크기 글자만 줄어든다 — 배지는 온전히 남는다(아래 flex-shrink:0) */
.mb-row-size {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 비율 다름 ──
   🔴 **흐리게 죽이지 않는다.** 못 쓰는 장이 아니라 **이번 자국으로는** 같이
      지울 수 없는 장이다 — 눌러서 열고 따로 칠하는 것이 정상 동선이다.
      그래서 왼쪽에 띠 하나로 "다른 무리" 라고만 표시한다. */
.mb-row.is-offratio {
  /* 배지와 **같은 붉은색**. 띠와 배지가 다른 색이면 두 가지 일이 일어난 것처럼 보인다.
     🔴 선택 표시(brand-500 오렌지 띠)와도 확실히 갈린다 — 주황이었을 땐 헷갈렸다. */
  box-shadow: inset 3px 0 0 var(--error-color, #c2453c);
}

/* 비율을 글자로 적는다 — 🔴 색만으로는 왜 빠졌는지 알 수 없고,
   색각 이상에서는 아예 안 보인다(§5-6 '색이 아니라 모양'과 같은 이유). */
.mb-row-ratio {
  /* 🔴 **줄이지 않는다.** 크기 글자가 먼저 줄어들고 배지는 온전히 남아야 한다 —
     "3:2" 가 "3…" 이 되면 알려 주려던 것을 못 알려 준다. */
  flex: 0 0 auto;
  padding: 0 5px;
  border-radius: 3px;
  /* 🔴 **붉은 계열이다.** 주황(warning)은 브랜드색(brand-500 오렌지)과 너무 가까워
     이 목록 안에서 "선택됨" 표시와 구분이 안 됐다. 이건 경고가 아니라
     **"이 장은 같이 처리되지 않는다"** 는 사실이라 확실히 튀어야 한다. */
  background: #fdecea;
  color: var(--error-color, #c2453c);
  font-size: var(--font-2xs, 0.6875rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 행에서 빼기 — 평소엔 흐리고 행에 올려야 또렷해진다.
   🔴 자리는 **항상 차지한다**(hover 때만 나타나면 행 폭이 흔들린다). */
.mb-row-del {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-left: 2px;
  border: 0;
  background: transparent;
  color: var(--ink-300);
  font-size: 15px;
  line-height: 1;
  border-radius: 4px;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition-fast), color var(--transition-fast),
              background var(--transition-fast);
}

.mb-row:hover .mb-row-del,
.mb-row-del:focus-visible { opacity: 1; }

.mb-row-del:hover {
  color: var(--error-color);
  background: var(--ink-100);
}

/* 상태 — 대기·처리중·완료·실패. 우측 끝의 점 하나.
   🔴 **이모지를 쓰지 않는다.** 폰트가 없으면 빈 네모(두부)가 되고 OS 마다 그림도
      다르다 — tool-icons.php 가 이모지를 버린 것과 같은 이유다. 여기선 CSS 로 그린다.
   🔴 색만으로 구분하지 않는다: 완료는 채운 원, 실패는 테두리+가운데 막대,
      처리중은 회전. 색각 차이가 있어도 모양이 다르다. */
.mb-row-state {
  flex: 0 0 auto;
  position: relative;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  box-sizing: border-box;
}

/* 대기 — 빈 원 */
.mb-row-state.is-idle {
  border: 1.5px solid var(--ink-300);
}

/* 처리중 — 도는 고리 */
.mb-row-state.is-busy {
  border: 1.5px solid var(--ink-200);
  border-top-color: var(--brand-500);
  animation: mb-spin .7s linear infinite;
}

@keyframes mb-spin { to { transform: rotate(360deg); } }

/* 완료 — 채운 원 + 체크 */
.mb-row-state.is-done {
  background: var(--success-color);
}

.mb-row-state.is-done::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 2px;
  width: 4px;
  height: 7px;
  border: solid #fff;
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

/* 실패 — 채운 원 + 가로 막대 */
.mb-row-state.is-fail {
  background: var(--error-color);
}

.mb-row-state.is-fail::after {
  content: '';
  position: absolute;
  left: 3px;
  top: 6px;
  width: 8px;
  height: 1.5px;
  background: #fff;
}

@media (prefers-reduced-motion: reduce) {
  .mb-row-state.is-busy { animation: none; }
}

/* ── AI 준비 상태 ──
   🔴 목록 하단, [선택한 N장에 적용] 바로 위. 이 버튼을 누르려는 사람 눈에 들어와야 한다. */
.mb-ai-bar {
  flex: 0 0 auto;
  padding: 8px 12px;
  border-top: 1px solid var(--ink-200);
  background: var(--brand-50);
}

.mb-ai-track {
  height: 4px;
  border-radius: 2px;
  background: var(--ink-200);
  overflow: hidden;
}

.mb-ai-fill {
  height: 100%;
  width: 0;
  background: var(--brand-500);
  transition: width .2s ease;
}

.mb-ai-text {
  display: block;
  margin-top: 5px;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-600);
  text-align: center;
}

.mb-ai-retry {
  display: block;
  margin: 6px auto 0;
  padding: 5px 14px;
  border: 1px solid var(--error-color);
  background: transparent;
  color: var(--error-color);
  border-radius: 999px;
  font-size: var(--font-2xs, 0.6875rem);
  font-weight: 600;
  cursor: pointer;
}

.mb-ai-retry:hover { background: var(--error-color); color: #fff; }

.mb-ai-bar.is-failed { background: #fdf0ef; }
.mb-ai-bar.is-failed .mb-ai-text { color: var(--error-color); }
.mb-ai-bar.is-ready .mb-ai-fill { background: var(--success-color); }

/* ── 하단 고정 (🔴 스크롤에 묻히면 안 된다) ── */
.mb-list-foot {
  flex: 0 0 auto;
  padding: 12px;
  border-top: 1px solid var(--ink-200);
  background: var(--bg-surface);
}

/* 🔴 **일괄 방식 선택** (5단계). 버튼 바로 위에 둔다 — 무엇이 일어날지 고른 다음
   누르는 순서라야 맞다. 아래에 두면 누르고 나서 읽게 된다. */
.mb-mode {
  display: flex;
  gap: 4px;
  margin-bottom: 8px;
}

.mb-mode-opt {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 7px 6px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm, 6px);
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
  cursor: pointer;
  text-align: center;
  line-height: 1.25;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.mb-mode-opt:hover { border-color: var(--ink-300); }

/* 🔴 고른 것이 **한눈에** 보여야 한다. 라디오 점만으로는 좁은 목록에서 안 보인다.
   🔴 `:has()` 를 못 쓰는 브라우저에서도 **라디오 점 자체는 그대로 보인다** —
      강조가 빠질 뿐 어느 쪽이 켜졌는지 알 수 없게 되지는 않는다. */
.mb-mode-opt:has(input:checked) {
  border-color: var(--brand-500);
  color: var(--brand-600, var(--brand-500));
  font-weight: 600;
}

.mb-mode-opt input { accent-color: var(--brand-500); margin: 0; flex: 0 0 auto; }

/* 🔴 주력 기능이라 크게. 목록 하단에서 눈에 먼저 들어와야 한다. */
.mb-apply-all {
  width: 100%;
  padding: 12px 10px;
  font-size: var(--font-base, 0.875rem);
  font-weight: 700;
}

.mb-foot-note {
  margin: 6px 0 0;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-400);
  text-align: center;
  line-height: 1.4;
}

/* 🔴 비율이 다른 장이 **선택에 들어 있을 때.** [전체] 가 진짜 전체가 된 뒤로는
   사용자가 일부러 넣을 수 있으므로, 막는 대신 **누르기 전에 눈에 띄게** 알린다.
   (실행할 때 확인창이 한 번 더 뜬다 — applyAll) */
.mb-foot-note.is-warn {
  /* 목록의 비율 배지·띠와 **같은 붉은색** — 같은 사실을 말하고 있으므로 색도 같아야 한다 */
  color: var(--error-color, #c2453c);
  font-weight: 600;
}

/* ========================================
   우: 편집
   🔴 제목 줄이 없다 — 어느 상품인지는 목록의 선택 표시가 이미 말한다.
   ======================================== */

.mb-edit {
  position: relative;            /* 🔴 떠 있는 툴바(absolute)의 기준 */
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-lg, 10px);
  overflow: hidden;
}

.mb-empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 24px;
  text-align: center;
}

.mb-empty-title {
  margin: 0;
  font-size: var(--font-lg, 1.125rem);
  font-weight: 700;
  color: var(--ink-700);
}

.mb-empty-text {
  margin: 0;
  font-size: var(--font-sm, 0.875rem);
  color: var(--ink-500);
  line-height: 1.7;
}

/* ── 캔버스 무대 ──
   🔴 아래쪽 패딩이 큰 이유: 툴바가 떠 있어서 캔버스 바닥을 가린다.
      패딩이 없으면 그림의 아랫부분에 칠할 수 없다. */
.mb-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 🔴 확대하면 그림이 무대보다 커진다 — 넘치는 만큼 여기서 훑는다.
     맨휠은 스크롤, Ctrl+휠이 배율이다(js). */
  overflow: auto;
  /* 🔴 아래 패딩은 **떠 있는 툴바가 가리는 만큼**이다. 고정 바를 없앴으므로
     툴바 높이(42) + 여백만 남긴다 — 그만큼이 그대로 캔버스가 된다. */
  padding: 12px 12px 66px;
  background:
    repeating-conic-gradient(var(--ink-100) 0% 25%, var(--bg-surface) 0% 50%)
    50% / 20px 20px;             /* 투명 영역이 보이도록 체커보드 */
}

/* 🔴 **넘칠 때는 가운데 정렬을 푼다.** flex 의 알려진 함정 — `align-items:center`
   상태에서 자식이 컨테이너보다 크면 **넘치는 쪽이 양방향으로 나가서 위/왼쪽이
   잘리고, 스크롤로도 거기까지 갈 수 없다**(스크롤은 음수 방향으로 못 간다).
   확대해 놓고 그림 윗부분을 영영 못 칠하게 되는 증상이 이것이다.
   그래서 넘치는 축만 시작점 정렬로 바꾼다 — 안 넘칠 때는 가운데 그대로. */
.mb-stage.is-overflow-x { justify-content: flex-start; }
.mb-stage.is-overflow-y { align-items: flex-start; }

/* 두 캔버스를 정확히 겹친다. 크기는 JS 가 원본 비율로 정한다. */
.mb-canvas-wrap {
  position: relative;
  line-height: 0;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .12);
  /* 🔴 **브라우저에 "여기 밖은 안 바뀐다" 고 알린다.** 마스크 캔버스를 칠할 때
     체커보드 배경(repeating-conic-gradient)까지 다시 칠할 이유가 없는데,
     안 막으면 무대 전체가 무효화 대상이 된다. */
  contain: paint;
}

.mb-canvas {
  display: block;
  /* 🔴 max-width/height 를 두지 않는다. JS 가 배율로 정확한 픽셀을 넣는데
     여기서 100% 로 다시 조이면 **확대가 무대 크기에서 멈춘다** — 그러면
     `getBoundingClientRect()` 로 재는 브러시 좌표와 실제 표시가 어긋난다. */
}

.mb-canvas-mask {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* 🔴 커서를 **숨긴다.** 크기를 보여주는 것은 아래 .mb-ring 이고, 그 위에
     화살표까지 겹치면 칠할 지점이 어디인지 오히려 흐려진다.
     (CSS cursor:url() 은 쓰지 않는다 — 브라우저가 거부하거나 128px 에서 잘린다) */
  cursor: none;
  touch-action: none;            /* 🔴 없으면 드래그가 페이지 스크롤로 먹힌다 */

  /* 🔴 **T(문구감지)일 때는 커서를 되살린다.** `cursor:none` 은 브러시 링이
     커서를 대신하기 때문인데, T 는 링을 안 띄우므로 그대로 두면 **커서가
     통째로 사라져** 마우스가 어디 있는지 알 수 없다. */
  /* 🔴 **반투명은 여기서 준다.** 칠하는 색 자체를 반투명으로 하면 획이 겹칠 때마다
     알파가 쌓여 문지를수록 진해지고, 결국 밑그림이 안 보인다(사용자 신고).
     캔버스는 불투명하게 그리고 레이어 전체를 반투명하게 = 농도가 항상 일정하다. */
  opacity: .45;
}

/* 🔴 **T(문구감지)일 때는 커서를 되살린다.** 위 `cursor:none` 은 브러시 링이
   커서를 대신하기 때문인데, T 는 링을 안 띄우므로 그대로 두면 **커서가 통째로
   사라져** 마우스가 어디 있는지 알 수 없다. T 는 칠하지 않으니 평범한 화살표면 된다. */
.mb-app[data-tool="text"] .mb-canvas-mask { cursor: default; }

/* ── 브러시 링 ──
   🔴 흰 테두리 + 검은 테두리를 겹친다. 밝은 사진에서도 어두운 사진에서도 보이게. */
.mb-ring {
  position: absolute;
  z-index: 4;
  /* 🔴 위치는 **JS 가 transform 으로** 준다 (left/top 이 아니다).
     left/top 은 바꿀 때마다 레이아웃을 다시 계산하지만 transform 은 합성만
     하므로 훨씬 싸다 — 이 원은 pointermove 마다 움직여서 그 차이가 크다.
     🔴 인라인 transform 끝에 translate(-50%,-50%) 가 붙어 중심이 유지된다.
        여기 있던 같은 값은 **인라인에 덮이므로** 첫 프레임용 기본값이다. */
  top: 0;
  left: 0;
  transform: translate(-50%, -50%);   /* 포인터가 원의 중심 */
  border-radius: 50%;
  pointer-events: none;               /* 🔴 없으면 이 원이 그리기를 가로챈다 */
  border: 1px solid rgba(0, 0, 0, .85);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .9),
              inset 0 0 0 1px rgba(255, 255, 255, .9);
  will-change: transform;
}

/* ── 떠 있는 툴바 ──
   🔴 position:absolute. 세로가 병목이라 고정 툴바로 40~50px 을 뺏기면 손해가 크다. */
/* 🔴 **크게 만든다 (2026-09-05).** 30px 아이콘·11px 글자는 작아서 보기 불편했다
   (사용자 지적). 세로가 병목이라 아껴 뒀는데, 툴바는 어차피 떠 있어서
   높이를 먹지 않는다 — fitCanvas() 가 실측해 비켜 주므로 캔버스만 그만큼 줄 뿐이고
   40→52px 정도는 캔버스 크기에 거의 영향이 없다. */
.mb-toolbar {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  max-width: calc(100% - 24px);
  /* 🔴 항목이 늘어도 각 칸이 짜부라지지 않게. 좁으면 툴바 안에서 가로로 넘긴다 */
  overflow-x: auto;
  scrollbar-width: none;
  background: rgba(31, 30, 27, .93);
  color: var(--text-inverse);
  border-radius: 999px;
  box-shadow: 0 4px 18px rgba(0, 0, 0, .28);
  backdrop-filter: blur(6px);
  /* 🔴 두 줄로 접히지 않게. 접히면 높이가 두 배가 되어 캔버스를 덮는다
     (fitCanvas 가 실측해 비켜 주기는 하지만, 그만큼 그림이 작아진다). */
  flex-wrap: nowrap;
}

.mb-tools,
.mb-history {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
}

.mb-toolbar::-webkit-scrollbar { display: none; }
.mb-sep, .mb-act, .mb-tool { flex: 0 0 auto; }

.mb-tool {
  border: 0;
  background: transparent;
  color: rgba(255, 255, 255, .82);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

/* 아이콘은 인라인 SVG 다 (이모지 아님 — 위 상태 점과 같은 이유) */
.mb-tool svg {
  width: 21px;
  height: 21px;
  display: block;
  margin: 0 auto;
}

.mb-tool:hover:not(:disabled) { background: rgba(255, 255, 255, .14); color: #fff; }

.mb-tool.is-active {
  background: var(--brand-500);
  color: #fff;
}

.mb-tool:disabled { opacity: .35; cursor: not-allowed; }

/* 🔴 **감지 중 표시** — T 는 누르는 즉시 찾고, 범위를 움직이면 계속 다시 찾는다.
   버튼을 **잠그지 않는다**(잠그면 조절을 못 해 실시간이 성립하지 않는다) —
   대신 깜빡여서 "지금 찾는 중" 만 알린다. 0.2~0.5초짜리라 이 정도면 충분하다. */
.mb-tool.is-busy { animation: mb-tool-pulse 1s ease-in-out infinite; }

@keyframes mb-tool-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}

/* 손떨림 방지 설정을 켠 사용자에게는 깜빡이지 않는다 */
@media (prefers-reduced-motion: reduce) {
  .mb-tool.is-busy { animation: none; opacity: .6; }
}

.mb-sep {
  width: 1px;
  height: 24px;
  background: rgba(255, 255, 255, .2);
}

.mb-size {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--font-xs, 0.75rem);
  flex: 0 0 auto;          /* 🔴 툴바가 좁아지면 이 칸부터 짜부라져 '크 기' 로 줄바꿈됐다 */
}

.mb-size-label {
  color: rgba(255, 255, 255, .6);
  white-space: nowrap;
}

.mb-size input[type="range"] {
  width: 108px;
  height: 18px;            /* 잡기 쉽게 — 얇으면 조준해야 한다 */
  accent-color: var(--brand-500);
  cursor: pointer;
}

.mb-size-val {
  width: 26px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, .82);
}

/* ── 배율 (한 칸 + 메뉴) ──
   🔴 [−][85%][+][맞춤] 네 칸(168px)이었다. 브러시 크기(170px)와 맞먹는 폭을
      배율이 먹는 바람에 툴바가 895px 이 되어 **1366px 노트북에서 42px 이 잘렸다**.
      한 칸(56px)으로 줄여 112px 을 돌려받았다.
   🔴 확대·축소를 없앤 게 아니다 — Ctrl+휠과 `+`/`-` 단축키가 원래 있었고,
      그쪽이 버튼 연타보다 빠르다. 메뉴는 **정확한 값**이 필요할 때만 연다. */
.mb-zoom {
  position: relative;            /* 🔴 메뉴(absolute)의 기준 */
  flex: 0 0 auto;
}

.mb-zoom-val {
  min-width: 52px;
  padding: 5px 8px;
  border: 0;
  border-radius: var(--radius-sm, 6px);
  background: transparent;
  color: rgba(255, 255, 255, .82);
  font-size: var(--font-xs, 0.75rem);
  font-variant-numeric: tabular-nums;   /* 숫자가 바뀔 때 칸이 안 흔들린다 */
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
}

/* 🔴 **강조색을 쓰지 않는다.** 맞춤 상태에 brand-500 을 입혔더니 툴바에서
   혼자 튀어 "뭔가 켜져 있다" 는 인상만 줬다. 이 칸이 할 일은 **몇 %인지 말하는 것**
   뿐이고, 맞춤이냐 아니냐는 사용자가 알아야 할 상태가 아니다 — 누르면 맞춰진다. */
.mb-zoom-val:hover { background: rgba(255, 255, 255, .14); color: #fff; }


/* ── 툴바 안 액션 ([적용] · [원본으로]) ──
   🔴 아이콘 버튼(.mb-tool)과 달리 글자다. 되돌릴 수 없는 동작이라
      모양만 보고 누르는 일이 없어야 한다.
   🔴 **투명 테두리로 뒀더니 눌러도 되는 건지 안 보였다**(사용자 신고).
      쓸 수 있을 때는 **채운 버튼**으로 또렷하게, 못 쓸 때만 흐리게. */
.mb-act {
  border: 1px solid transparent;
  background: var(--brand-500);
  color: #fff;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 999px;
  font-size: var(--font-xs, 0.75rem);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--transition-fast), opacity var(--transition-fast);
}

.mb-act:hover:not(:disabled) { background: var(--brand-400); }

/* 단축키 표시 — 글자보다 한 단계 낮춰서 [적용] 이 주인공으로 남는다 */
.mb-kbd {
  display: inline-block;
  margin-left: 5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(255, 255, 255, .22);
  font-size: var(--font-2xs, 0.6875rem);
  font-weight: 400;
  font-family: inherit;
  line-height: 1.5;
}

/* 잠겨 있으면 단축키도 안 먹는다 — 같이 흐려져야 거짓말이 안 된다 */
.mb-act:disabled .mb-kbd { background: rgba(255, 255, 255, .10); }

/* [원본으로] 는 부수적이라 한 단계 낮춘다 — 주력([적용])과 같은 무게면 헷갈린다 */
#mbRevert {
  background: transparent;
  border-color: rgba(255, 255, 255, .35);
  color: rgba(255, 255, 255, .85);
  font-weight: 400;
}

#mbRevert:hover:not(:disabled) { background: rgba(255, 255, 255, .16); }

.mb-act:disabled {
  background: rgba(255, 255, 255, .10);
  border-color: transparent;
  color: rgba(255, 255, 255, .40);
  font-weight: 400;
  cursor: not-allowed;
}

/* ── 처리 중 ──
   🔴 추론이 장당 5~7초다. 누르고 조용하면 **안 눌린 줄 알고 또 누른다.**
      줄무늬가 흐르게 해서 "돌고 있다" 를 눈으로 알린다. */
.mb-act.is-busy,
.mb-apply-all.is-busy {
  cursor: progress;
  background-image: linear-gradient(115deg,
      rgba(255, 255, 255, .22) 25%, transparent 25%, transparent 50%,
      rgba(255, 255, 255, .22) 50%, rgba(255, 255, 255, .22) 75%, transparent 75%);
  background-size: 22px 22px;
  animation: mb-stripes .7s linear infinite;
}

.mb-act.is-busy {
  background-color: var(--brand-600);
  color: #fff;
  opacity: 1;
}

.mb-apply-all.is-busy {
  background-color: var(--ink-700);
  color: #fff;
  opacity: 1;
}

@keyframes mb-stripes { to { background-position: 22px 0; } }

@media (prefers-reduced-motion: reduce) {
  .mb-act.is-busy, .mb-apply-all.is-busy { animation: none; }
}

/* ========================================
   반응형
   🔴 목록을 **레일로 접는다.** 숨기지 않는다 —
      목록이 사라지면 이 도구가 아니게 된다(§5-4-3).

   🔴 **경계를 1280 → 900 으로 내렸다 (2026-09-07).** 1280 은 너무 일렀다 —
      1250px 짜리 흔한 창에서 이미 88px 레일이 떠서, 목록을 멀쩡히 놓을 수
      있는 폭인데도 썸네일 1열로 쪼그라들었다(실사용 신고).
      이제 목록이 clamp 로 같이 줄어드니 1024px 에서도 266px 을 쥔다 —
      레일은 그 하한(240px)마저 캔버스를 깎기 시작하는 900px 아래에서만 쓴다.
   ======================================== */

@media (max-width: 900px) {
  /* 레일은 고정폭이다 — 여기서는 더 줄일 여지가 없다 */
  .mb-list { flex: 0 0 var(--mb-rail-w); }

  /* 레일에서는 썸네일 1열만 남는다 */
  .mb-list-head,
  .mb-list-sel .mb-check-all span,
  .mb-list-sel .mb-sel-count,
  .mb-row-no,
  .mb-row-sub,
  .mb-foot-note { display: none; }

  .mb-row {
    flex-wrap: wrap;
    justify-content: center;
    padding: 6px 4px;
  }

  .mb-row-name { font-size: var(--font-2xs, 0.6875rem); text-align: center; }
  .mb-row-thumb { flex-basis: 56px; width: 56px; height: 56px; }

  .mb-drop-text,
  .mb-drop-sub,
  /* 🔴 레일(88px)에는 표를 그릴 수 없다 — 그리드·엑셀은 통째로 접는다.
     탭 자체는 남으므로 창을 넓히면 그대로 돌아온다. */
  .mb-src,
  .mb-url-bar,
  .mb-url-detail,
  .mb-src-head,
  .mb-ext { display: none; }

  .mb-drop { margin: 8px; padding: 8px; }

  /* 버튼 글자는 줄이되 없애지 않는다 — 여기가 주력 기능이다 */
  .mb-apply-all { font-size: var(--font-2xs, 0.6875rem); padding: 8px 4px; }

  /* 🔴 레일(88px)에서는 큐도 줄여야 한다. 진행률과 [중단] 은 **남긴다** —
     좁다고 멈추는 길을 없애면 6분짜리를 통째로 기다려야 한다.
     남은 시간·파일명은 자리가 없어 접는다(진행 숫자가 대신 말한다). */
  .mb-queue-note,
  /* 🔴 완료 개수는 **좁아도 남긴다** — 탭 줄로 옮겨서 더 이상 접히지 않는다.
     (옛 자리에서는 [ZIP] 줄을 밀어내서 숨겼던 것이다) */

  .mb-queue-top { flex-direction: column; gap: 4px; }
  .mb-queue-count { font-size: var(--font-2xs, 0.6875rem); }
  .mb-queue-stop { padding: 3px 6px; font-size: var(--font-2xs, 0.6875rem); }
  .mb-done-bar { justify-content: center; flex-wrap: wrap; gap: 4px; }
  .mb-zip { padding: 6px 6px; font-size: var(--font-2xs, 0.6875rem); }

  /* 🔴 글자만 접고 **선택칸은 남긴다** — 좁다고 품질을 못 고르게 하면
     크게 지운 사람이 85 로 받아 잡티를 보게 된다 */
  .mb-quality-label { display: none; }

  /* 🔴 다만 가로칸은 **'가로' 두 글자를 남긴다** — 숫자만 덩그러니 있으면
     1000 이 폭인지 품질인지 알 수 없다(바로 옆이 품질 선택칸이다).
     대신 뒤쪽 'px' 는 접는다. */
  .mb-minw .mb-quality-label:first-of-type { display: inline; }
  .mb-minw input[type="number"] { width: 48px; }
}

/* 🔴 세로 768px 이하가 진짜 문제다 — 캔버스가 544px 로 떨어진다.
   가로 여백을 걷어내 조금이라도 돌려준다. */
@media (max-height: 768px) {
  .mb-stage { padding: 6px 6px 58px; }
  .mb-app { padding: 8px; gap: 8px; }
  .mb-toolbar { bottom: 8px; }
}

/* ≤1024px 은 미지원 — 208MB 모델 + 215MB 힙은 모바일 탭을 죽인다(§4).
   🔴 화면을 잠그는 게 아니라 **알린다**. 1단계는 AI 가 없어 실제로는 돌아간다. */
.mb-unsupported {
  display: none;
  padding: 10px 14px;
  background: var(--warning-color);
  color: #fff;
  font-size: var(--font-sm, 0.875rem);
  text-align: center;
}

@media (max-width: 1024px) {
  .mb-unsupported { display: block; }
}

/* 🔴 ≤820px 에서는 껍데기가 상단 바(.tool-topbar, 52px)를 **밖에** 세운다
   (css/tools.css). 그것은 tool-main 의 형제라 flex 로는 못 잡는다 —
   화면 높이에서 빼 주지 않으면 그만큼 아래로 넘쳐 **하단 라인이 늘어난다.**
   🔴 여기 상수는 tools.css 의 .tool-topbar height 와 **같이 움직여야 한다.** */
@media (max-width: 820px) {
  .is-app-shell:has(.mb-app) { --mb-topbar-h: 52px; }
}

/* ════════════════════════════════════════
   일괄 큐 · 결과 (3단계)
   🔴 [선택한 N장에 적용] **자리를 대신한다**(js 가 버튼을 hidden 으로). 아래에 덧붙이면
      목록 하단이 두 배로 부풀어 50행짜리 목록에서 그만큼 행이 덜 보인다.
   ════════════════════════════════════════ */

.mb-queue {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.mb-queue-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.mb-queue-count {
  font-size: var(--font-sm, 0.875rem);
  font-weight: 700;
  color: var(--ink-800);
  font-variant-numeric: tabular-nums;   /* 숫자가 바뀔 때 글자가 안 흔들린다 */
}

/* 🔴 [중단] 은 **처음부터 보인다.** 위험한 버튼이 아니다 — 지운 것은 남고
   아직 안 한 장만 건너뛴다. 그래서 빨갛게 겁주지 않는다. */
.mb-queue-stop {
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
  padding: 4px 10px;
  font-size: var(--font-xs, 0.75rem);
  color: var(--ink-600);
  cursor: pointer;
}

.mb-queue-stop:hover:not(:disabled) {
  border-color: var(--error-color);
  color: var(--error-color);
}

.mb-queue-stop:disabled { opacity: .5; cursor: default; }

.mb-queue-track {
  height: 6px;
  border-radius: 3px;
  background: var(--ink-200);
  overflow: hidden;
}

.mb-queue-fill {
  height: 100%;
  width: 0;
  background: var(--brand-500);
  transition: width .2s ease;
}

.mb-queue-note {
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
  text-align: center;
  /* 🔴 긴 파일명이 목록 폭을 밀어내지 않게 — 한 줄로 자른다 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 결과 줄 ── */
.mb-done-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--ink-200);
}

/* 🔴 **탭 줄 오른쪽에 붙는다** (2026-09-07). [ZIP] 줄에 있을 때는
   가로·품질·ZIP 에 밀려 폭이 한 글자로 눌리고 **세 줄로 접혔다**(1/장/완료).
   `.mb-list-head` 가 `space-between` 이라 여기서는 저절로 오른쪽으로 간다.
   🔴 `flex` 를 주지 말 것 — 늘리면 탭과 사이가 벌어지고, 줄이면 도로 접힌다.
      `white-space:nowrap` 이 접힘을 막는다. */
.mb-done-count {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: var(--font-xs, 0.75rem);
  color: var(--ink-500);
  font-variant-numeric: tabular-nums;   /* 숫자가 늘어도 자리가 안 흔들린다 */
}

/* 실패가 있으면 눈에 걸리게 — 완료만 있을 때는 조용한 회색이다.
   🔴 색 이름은 이 파일이 이미 쓰는 `--error-color` 다(위 .mb-ai-bar 와 같은 것) */
.mb-done-count.has-fail { color: var(--error-color); font-weight: 600; }

/* ── JPEG 품질 ──
   🔴 [ZIP] **왼쪽**에 둔다. 누르기 전에 눈에 들어와야 고를 수 있다 —
      오른쪽에 두면 이미 받고 나서 "아 품질이 있었네" 가 된다. */
.mb-quality {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  font-size: var(--font-2xs, 0.6875rem);
  color: var(--ink-500);
}

.mb-quality select {
  padding: 5px 4px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
  color: var(--ink-700);
  font-size: var(--font-2xs, 0.6875rem);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

/* 가로 크기 보정 — 품질 왼쪽. 체크박스로 켜고 끈다. */
.mb-minw input[type="number"] {
  width: 56px;
  padding: 5px 4px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-surface);
  color: var(--ink-700);
  font-size: var(--font-2xs, 0.6875rem);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.mb-minw input[type="checkbox"] { cursor: pointer; }

/* 🔴 꺼져 있으면 숫자칸을 흐린다 — 값이 남아 있어 **켜져 있는 것처럼 읽힌다**.
   `disabled` 를 쓰지 않는 이유: 끈 상태에서도 다음에 쓸 값을 미리 고쳐 둘 수 있다. */
.mb-minw:has(input[type="checkbox"]:not(:checked)) .mb-quality-label,
.mb-minw:has(input[type="checkbox"]:not(:checked)) input[type="number"] {
  opacity: .45;
}

.mb-zip {
  flex: 0 0 auto;
  padding: 7px 12px;
  font-size: var(--font-xs, 0.75rem);
  font-weight: 700;
}

.mb-zip:disabled { opacity: .5; cursor: not-allowed; }
