/* order-hub.css — 주문허브 v2 · 2열 마스터-디테일
 *
 * 근거: prd-order-hub.md §14-1 · 기준 화면 mockup-order-hub.html · 팔레트/타이포는 common.css 의 :root 가 진실
 *
 * 🔴 하드코딩 색 금지 — 전부 토큰. 마켓 브랜드색만 이 파일의 .oh-app 스코프 토큰이다(도팡 팔레트가 아니라 «식별용 남의 색»).
 * 🔴 모바일 퍼스트 — 기본이 폰(1열 · 홈➔디테일 전환), 넓어지면 2열. 고정 px 폭 금지.
 * 🔴 접힘 기준은 «뷰포트»가 아니라 «.oh-app 의 폭»(컨테이너 쿼리) — 툴 껍데기 사이드바(216px)를
 *    접고 펴면 뷰포트는 그대로인데 본문만 넓어진다. 미디어쿼리는 그걸 구분 못 한다.
 */

/* 🔴 **맨 위에 둔다.** 없으면 아래 display 규칙이 [hidden] 을 이겨서
   숨긴 요소가 그대로 보인다 (세 번 재발한 함정). */
[hidden] { display: none !important; }

.oh-app {
  container-type: inline-size;
  container-name: oh;
  --oh-red: var(--error-color);
  --oh-green: var(--success-color);
  --oh-master-w: 360px;
  /* 🔵 두 번째 액센트(틸) — 2026-09-14 사용자 결정. 뜻은 하나: «집어 갈 값»(주문번호·전화·주소 = 탭하면 복사).
     오렌지는 «지금 보는 것»(활성 단계·옵션명), 빨강은 «급한 숫자». 셋이 겹치는 자리를 만들지 말 것.
     🔵 검증되면 common.css :root 로 올린다 — 그때까지는 이 도구 안에서만. */
  --oh-accent2: #1a8fa6;   /* 2026-09-15 채도 한 단계 ↑ (사용자: 청록이 눈에 안 띈다) */
  --oh-accent2-soft: color-mix(in srgb, var(--oh-accent2) 10%, white);
  /* 홈의 유일한 행동(주문수집) — 브랜드 오렌지 «채움». 겨자·앰버를 거쳐 여기로 왔다(2026-09-15): 팔레트 밖 색은 검정 카드 위에서 남의 버튼처럼 보였다.
     활성 단계 칸도 오렌지지만 그쪽은 «연한 배경+가는 테두리», 이쪽은 «진한 채움+흰 글자» 라 형태로 갈린다. */
  --oh-cta: var(--brand-500);
  /* 마켓 식별색 — 카드·MY SHOP·설정 네 곳이 같은 칩을 쓴다. 팔레트 원칙과 무관한 식별용. */
  --mk-smartstore: #03c75a;
  --mk-coupang:    #e61e2b;
  --mk-esm:        #4a4741;   /* 🔴 지마켓과 같은 파랑이면 계정 칩과 사이트 칩이 구별되지 않는다 */
  --mk-gmarket:    #2b70f6;
  --mk-auction:    #e8632a;
  --mk-elevenst:   #d1233b;
  --mk-lotteon:    #b7202b;
}

/* ── 상단 한 줄 · 카드 상자 · 섹션 제목 ─────────────── */
.oh-topbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
}
.oh-topbar-acts { display: flex; gap: var(--spacing-xs); margin-left: auto; }
.oh-colsw { display: none; gap: 0; }
.oh-colsw .oh-btn { border-radius: 0; }
.oh-colsw .oh-btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.oh-colsw .oh-btn:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
.oh-colsw .oh-btn.is-on { background: var(--ink-900); border-color: var(--ink-900); color: var(--text-inverse); position: relative; z-index: 1; }

.oh-pc-badge {
  display: inline-flex; align-items: center; gap: 0.4em;
  padding: 0.25em 0.7em; border-radius: var(--radius-full);
  font-size: 0.8em; font-weight: 600;
  border: 1px solid var(--ink-300); background: var(--bg-card); color: var(--ink-600);
}
.oh-pc-badge::before { content: ""; width: 0.5em; height: 0.5em; border-radius: 50%; background: var(--ink-400); flex: none; }
.oh-pc-badge.on   { color: var(--oh-green); border-color: color-mix(in srgb, var(--oh-green) 40%, white); background: color-mix(in srgb, var(--oh-green) 10%, white); }
.oh-pc-badge.on::before { background: var(--oh-green); box-shadow: 0 0 5px var(--oh-green); }
.oh-pc-badge.off  { color: var(--warning-color); border-color: color-mix(in srgb, var(--warning-color) 40%, white); background: color-mix(in srgb, var(--warning-color) 10%, white); }
.oh-pc-badge.off::before { background: var(--warning-color); }

.oh-box {
  background: var(--bg-card);
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-lg);
  padding: var(--spacing-md);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--ink-900) 5%, transparent);
}
.oh-sec-title {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 0.8em; font-weight: 800; color: var(--ink-500);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin-bottom: var(--spacing-sm);
}
.oh-muted { color: var(--ink-500); font-size: 0.85em; margin: 0; }
.oh-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--brand-600); font-weight: 600; font-size: 0.85em; text-decoration: none;
}
.oh-link:hover { text-decoration: underline; }
.oh-link-inverse { color: var(--ink-300); }

/* ── 2열 그리드 · 폰 전환 ─────────────────────────────
   기본(1열): is-home 이면 마스터만, is-detail 이면 디테일만. */
/* 🔴 --oh-cols 는 .oh-app 이 아니라 .oh-layout 에 둔다 — 컨테이너 쿼리는 «컨테이너 자신»을 못 고친다(자손만). JS 가 읽는다. */
.oh-layout { display: grid; grid-template-columns: 1fr; gap: var(--spacing-md); align-items: start; --oh-cols: 1; }
.oh-master { display: flex; flex-direction: column; gap: var(--spacing-md); }
.oh-app.is-home   .oh-detail { display: none; }
.oh-app.is-detail .oh-master { display: none; }
.oh-detail { min-height: 60vh; }
/* 🔴 디테일엔 외곽 상자(.oh-box)를 씌우지 않는다(2026-09-18 사용자) — 안의 주문 카드가 이미 상자라 «상자 안의 상자»가 됐고,
   폰에선 테두리+여백이 양쪽 17px 씩 카드 폭을 먹었다. 카드 테두리는 그대로 둔다: 실패(빨강)·선택(검정) 표시가 테두리다.
   PC 선 맞춤: 제목 줄 윗선 = 좌측 첫 상자 윗선 · 우측 끝 = 상단 [1열·2열·설정] 끝. */

/* 🔴 기준은 1024 → **900** (2026-09-16). 1024 는 「노트북 창폭이면 2열」이라는 감각으로 잡았는데
   컨테이너는 창이 아니다 — 도구 껍데기가 **사이드바 216 + tool-main 패딩 40 = 256px** 을 먼저 먹는다.
   창 1262 → 컨테이너 ≈ 991 로 **아직 두 열이 남는데도 1열로 접혔다**(사용자 지적).
   900 의 근거: 마스터 360 + 간격 16 + 디테일 524. 디테일이 524 면 카드(상품|주문정보 1.2:1)가 아직 읽힌다.
   ⛔ 이 값을 창 폭 감각으로 다시 올리지 말 것 — 여기 들어오는 숫자는 «본문 폭»이고 창보다 256 작다. */
@container oh (min-width: 900px) {
  .oh-layout { grid-template-columns: var(--oh-master-w) 1fr; --oh-cols: 2; }
  .oh-app.is-home .oh-detail { display: block; }
  .oh-app.is-detail .oh-master { display: flex; }
  /* 2열에서는 뒤로가기가 필요 없다 — 설정만 [✕ 주문 목록으로] 로 쓴다 */
  .oh-layout .oh-back { display: none; }
  .oh-app.view-settings .oh-layout .oh-back,
  .oh-app.view-sales .oh-layout .oh-back { display: inline-flex; }
  /* 좌측은 화면에 고정하고 «안에서» 스크롤 — 매출·단계는 늘 보이고 MY SHOP 이 길면 패널 안에서 넘긴다.
     우측은 페이지와 함께 스크롤(카드 300장을 가두면 폰 감각과 어긋난다). 바닥 선은 최소 높이로 맞춘다. */
  /* 스크롤바가 카드 «위»에 겹쳐 오른쪽 라운드를 잘랐다(2026-09-15) → 바가 놓일 홈을 카드 바깥에 둔다.
     gutter 를 stable 로 잡아 넘칠 때만 폭이 바뀌는 흔들림도 없앤다. */
  .oh-master { position: sticky; top: var(--spacing-md); max-height: calc(100vh - var(--spacing-md) * 2); overflow-y: auto;
               scrollbar-width: thin; scrollbar-gutter: stable; padding-right: var(--spacing-sm); }
  .oh-detail { min-height: calc(100vh - var(--spacing-md) * 2); }
}

/* ── 카드 «안»을 벌리는 것은 한 단 더 넓을 때부터 ─────────
   🔴 마스터-디테일 2열(900)과 카드 내부 2단은 필요한 폭이 다르다. 900 에서 디테일은 524 이고
   거기서 또 1.2:1 로 쪼개면 285|238 이 되어 주소·옵션명이 줄줄이 접힌다.
   1080 의 근거: 디테일 704 → 카드 내부 383|305, 2열 토글을 켜도 카드당 344. 그리고
   **1366×768 노트북**(흔하다)이 컨테이너 1095 로 여기에 들어온다 — 그 아래로는 토글도 감춘다
   (선택지를 주면서 결과가 좁아지는 것보다, 넓어질 때 나타나는 편이 낫다). */
@container oh (min-width: 1080px) {
  .oh-colsw { display: inline-flex; }
  .oh-app.cols-2 .oh-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 1열 보기에서는 카드가 넓다 — 좌측(상품 + 하단 송장입력) | 우측(주문·고객정보 전체 활용) */
  .oh-app:not(.cols-2) .oh-ocard-body {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    gap: var(--spacing-xs) var(--spacing-md);
  }
  .oh-app:not(.cols-2) .oh-ocard-main { grid-column: 1; grid-row: 1; order: unset; }
  .oh-app:not(.cols-2) .oh-ocard-body > .oh-ocard-foot {
    grid-column: 1; grid-row: 2; align-self: end; padding-top: var(--spacing-xs); order: unset;
  }
  .oh-app:not(.cols-2) .oh-info {
    grid-column: 2; grid-row: 1 / span 2; order: unset;
    border-top: none; padding-top: 0;
    border-left: 1px solid var(--ink-200); padding-left: var(--spacing-md);
  }
}

/* ── 버튼 (common.css 의 .btn 위계와 같다 — 주 버튼은 검정) ── */
.oh-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.3em;
  padding: 0.55em 1em;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--ink-800);
  font-weight: 600;
  font-size: 0.95em;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.oh-btn:hover:not(:disabled) { border-color: var(--ink-900); background: var(--ink-50); }
.oh-btn:disabled { opacity: 0.5; cursor: default; }
.oh-btn-primary { background: var(--ink-900); border-color: var(--ink-900); color: var(--text-inverse); }
.oh-btn-primary:hover:not(:disabled) { background: var(--ink-700); border-color: var(--ink-700); }
.oh-btn-danger { color: var(--oh-red); border-color: var(--oh-red); }
.oh-btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--oh-red) 8%, white); border-color: var(--oh-red); }
.oh-btn-sm { padding: 0.4em 0.75em; font-size: 0.85em; }
.oh-icon-btn { background: none; border: none; font-size: 1.1em; cursor: pointer; color: var(--ink-600); }

.oh-select, .oh-input {
  padding: 0.5em 0.7em;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--ink-900);
  font-size: 0.95em;
  max-width: 100%;
}
.oh-select:focus, .oh-input:focus, .oh-inq-answer textarea:focus { outline: none; border-color: var(--ink-900); }
.oh-select-sm { padding: 0.35em 0.5em; font-size: 0.85em; }
.oh-input { width: 100%; min-width: 0; }

/* ── 마스터: 매출(다크) ───────────────────────────── */
.oh-sales {
  background: linear-gradient(135deg, var(--ink-800) 0%, var(--ink-900) 100%);
  color: var(--text-inverse); border: none;
}
.oh-sales-head { font-size: 0.8em; color: var(--ink-400); margin-bottom: var(--spacing-xs); display: flex; justify-content: space-between; gap: var(--spacing-sm); }
.oh-sales-more { white-space: nowrap; }
.oh-sales-row { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-sm); margin-bottom: var(--spacing-xs); }
.oh-sales-amt { font-size: 1.6em; font-weight: 800; letter-spacing: -0.02em; }
/* 금액 줄과 같은 높이 안에서 글자·아이콘만 키운다 — 카드가 안 늘어난다 */
.oh-btn-sync { font-size: 1.1em; font-weight: 600; padding: 0.45em 1em; gap: 0.4em; background: var(--oh-cta); color: var(--text-inverse); border-color: var(--oh-cta); }
.oh-btn-sync:hover:not(:disabled) { background: var(--brand-600); border-color: var(--brand-600); }
.oh-sync-ico { width: 1.2em; height: 1.2em; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.oh-sales-sub { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); font-size: 0.8em; color: var(--ink-300); }
.oh-sales-sub > span:first-child { color: var(--brand-400); font-weight: 700; }
.oh-pending {
  display: inline-block;
  padding: 0.25em 0.7em;
  border-radius: var(--radius-full);
  background: var(--brand-100);
  color: var(--brand-700);
  font-size: 0.8em;
  font-weight: 600;
}

/* ── 접기 (미처리 현황 · MY SHOP 사업자 · 설정 사업자) ── */
.oh-chev { display: inline-block; width: 0.55em; height: 0.55em; border-right: 2px solid var(--ink-500); border-bottom: 2px solid var(--ink-500); transform: rotate(45deg); transition: transform 0.15s; margin: 0 0.35em 0.15em 0.1em; flex: none; }
.is-folded > .oh-chev, .is-folded > .oh-fold-head .oh-chev, .oh-fold.is-folded .oh-chev, tr.is-folded .oh-chev { transform: rotate(-45deg); }
.oh-fold-head { width: 100%; background: none; border: none; padding: 0; cursor: pointer; font: inherit; text-align: left; gap: var(--spacing-sm); }
.oh-fold-head > span:first-child { flex: none; }
.oh-fold-sum { display: none; flex: 1; text-transform: none; letter-spacing: 0; font-weight: 600; color: var(--ink-700); }
.oh-fold-sum b { color: var(--oh-red); font-weight: 800; }
.oh-fold.is-folded .oh-fold-sum { display: inline; }
.oh-fold.is-folded .oh-fold-head { margin-bottom: 0; }
.oh-fold.is-folded .oh-fold-body { display: none; }

/* ── 마스터: 단계 6개 ─────────────────────────────── */
.oh-stages { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--spacing-sm); }
/* 🔴 라벨과 숫자를 «한 줄에» 둔다(2026-09-15) — 세로로 쌓으면 6칸이 3줄이 되고 MY SHOP 이 접힘 밖으로
   밀려났다. 가로로 누이면 칸 높이가 4.2em → 2.6em 이라 같은 6칸이 화면 안에 들어온다.
   좁아지면 라벨과 숫자가 붙으므로 그때만 다시 세로(아래 미디어쿼리). */
.oh-stage {
  position: relative; overflow: hidden;
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5em;
  min-height: 2.6em; padding: var(--spacing-sm) var(--spacing-md);
  text-align: left; cursor: pointer;
  background: var(--ink-50); border: 1px solid var(--ink-200); border-radius: var(--radius-md);
  font: inherit;
}
.oh-stage:hover { border-color: var(--ink-400); }
/* 활성 단계 = 오렌지 — «지금 보는 것». 검정 막대는 다른 검정과 섞여 안 보였다(2026-09-14) */
.oh-stage.is-active { background: var(--brand-50); border-color: var(--brand-500); box-shadow: inset 4px 0 0 var(--brand-500); }
.oh-stage-lbl { font-size: 0.8em; font-weight: 600; color: var(--ink-600); }
.oh-stage.is-active .oh-stage-lbl { color: var(--brand-700); font-weight: 700; }
.oh-stage-num { font-size: 1.4em; font-weight: 800; color: var(--ink-400); }
.oh-stage.has .oh-stage-num { color: var(--oh-red); }
.oh-stage.is-active .oh-stage-num { color: var(--brand-600); }
/* 2열 × 가로배치라 폭이 좁다 — 라벨이 길면(「배송완료」) 숫자와 붙는다. 이때만 세로로 되돌린다. */
@media (max-width: 400px) {
  .oh-stage { flex-direction: column; align-items: stretch; justify-content: space-between; gap: 0.2em; min-height: 3.8em; }
}

/* ── 마스터: MY SHOP 표 ───────────────────────────── */
.oh-shop-wrap { overflow-x: auto; }
.oh-shop { width: 100%; border-collapse: collapse; font-size: 0.85em; }
.oh-shop th, .oh-shop td { padding: 0.45em 0.2em; text-align: center; white-space: nowrap; }
.oh-shop th { color: var(--ink-400); font-weight: 600; font-size: 0.9em; border-bottom: 1px solid var(--ink-200); }
.oh-shop td:first-child, .oh-shop th:first-child { text-align: left; }
.oh-shop tbody tr { border-bottom: 1px solid var(--ink-100); }
.oh-shop tbody tr[data-acc]:hover { background: var(--bg-alt); }
.oh-shop .num { color: var(--ink-400); font-weight: 600; cursor: pointer; }
.oh-shop .num.has { color: var(--oh-red); font-weight: 800; }
.oh-shop .num.has:hover { text-decoration: underline; }
.oh-shop tr.is-fail td { color: var(--oh-red); cursor: pointer; }
.oh-shop .oh-shop-biz-row { cursor: pointer; background: var(--ink-50); }
.oh-shop .oh-shop-biz-row td { padding: 0.55em 0.2em; color: var(--ink-800); font-weight: 800; font-size: 0.9em; border-top: 1px solid var(--ink-200); }
.oh-shop .oh-shop-biz-row td:first-child { text-align: left; }
.oh-shop .oh-shop-biz-row .num { color: var(--ink-500); }
.oh-shop .oh-shop-biz-row .num.has { color: var(--oh-red); }
.oh-shop .oh-shop-name { font-weight: 600; color: var(--ink-800); }
/* ESM 처럼 한 계정이 두 사이트를 볼 때, 큰 글씨는 계정 이름이고 이것이 사이트다.
   칩이 이미 사이트를 색으로 갈라 주므로 글자는 물러나 있어도 읽힌다. */
.oh-shop-sub { margin-left: 0.35em; font-size: 0.85em; color: var(--ink-500); font-weight: 400; }
/* 자동 수집이 멈춘 계정 — PC 알약 「꺼짐」과 같은 경고색(왜 ↔ 어디가 가 한 색으로 이어진다) · 판정은 order-hub.js staleOf */
.oh-shop-stale { margin-left: 0.4em; font-size: 0.8em; font-weight: 700; color: var(--warning-color); white-space: nowrap; }
/* 요약 카드(검은 바탕)의 「⚠ 일부 멈춤」 — 누르면 MY SHOP 으로. 줄이 좁아(폰 360px) 글자 크기를 안 키운다 */
.oh-stale {
  margin-left: 0.3em; padding: 0 0.1em; border: 0; background: none; cursor: pointer;
  font: inherit; font-weight: 700; color: var(--warning-color); text-decoration: underline; text-underline-offset: 2px;
}

.oh-shop-note { margin-top: var(--spacing-sm); }

/* 마켓 칩 — 한 글자. 색은 마켓/사이트 토큰(.oh-app), 모르는 마켓은 잉크. */
.oh-mk {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5em; height: 1.5em; padding: 0 0.3em;
  border-radius: var(--radius-sm);
  background: var(--ink-800); color: var(--text-inverse);
  font-size: 0.75em; font-weight: 800; margin-right: 0.4em;
  vertical-align: middle;
}
.oh-mk-smartstore { background: var(--mk-smartstore); }
.oh-mk-coupang    { background: var(--mk-coupang); }
.oh-mk-esm        { background: var(--mk-esm); }
.oh-mk-gmarket    { background: var(--mk-gmarket); }
.oh-mk-auction    { background: var(--mk-auction); }
.oh-mk-elevenst   { background: var(--mk-elevenst); }
.oh-mk-lotteon    { background: var(--mk-lotteon); }
.oh-badge-unverified {
  display: inline-block; margin-left: 0.4em; padding: 0 0.4em;
  border: 1px solid var(--warning-color); color: var(--warning-color);
  border-radius: var(--radius-sm); font-size: 0.75em; vertical-align: middle;
}

/* ── 확장 끊김 안내줄 — showExtStale 만 쓴다 ── */
.oh-extbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md);
  border: 1px solid color-mix(in srgb, var(--warning-color) 40%, white);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--warning-color) 10%, white);
  font-size: 0.9em; color: var(--ink-800);
}

/* ── 미검증 기능 안내 (모달 안) ──
   🔴 결정 18 — 「미검증」을 주석에만 적으면 화면에선 정상 기능으로 보인다.
   실사용 검증이 끝나면 이 띠를 쓰는 쪽에서 지운다(스타일은 남겨도 된다). */
.oh-note {
  padding: var(--spacing-sm) var(--spacing-md);
  margin: var(--spacing-sm) 0;
  border-radius: var(--radius-md);
  font-size: 0.9em; line-height: 1.5; color: var(--ink-800);
}
.oh-note-warn {
  border: 1px solid color-mix(in srgb, var(--warning-color) 40%, white);
  background: color-mix(in srgb, var(--warning-color) 10%, white);
}

/* ── 수집 진행 패널 ─────────────────────────
 *
 * 🔴 **2026-09-15: 「안 읽힌다」를 고쳤다** (사용자 지적 · prd-order-hub.md §19-10-3).
 *    원인은 정보가 많아서가 아니라 **진행 중인 것과 끝난 것이 똑같이 생겨서**였다:
 *    점이 전부 같은 크기·같은 밝기라 9줄이 균일한 벽으로 보였고, 진행 중인데도
 *    **아무것도 움직이지 않아** 멈춘 것처럼 읽혔다.
 *
 * 규칙 셋 — ⛔ 이걸 되돌리면 다시 «벽»이 된다:
 *   ① **움직이는 것 = 지금 도는 것.** 맥동은 `sp-run` 에만 준다.
 *   ② **끝난 줄은 가라앉힌다**(opacity). 눈이 «남은 것»으로 저절로 간다.
 *   ③ **상태마다 모양이 다르다** — 색만으로 가르지 않는다(색각 이상·저대비 화면).
 */
.oh-sync-panel {
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md);
  font-size: 0.85em;
}

/* 머리줄 — 「3/9」 하나로 «얼마나 남았나»가 보인다 */
.oh-sync-panel .sp-head {
  display: flex; align-items: center; gap: 0.5em;
  padding-bottom: 0.4em; margin-bottom: 0.4em;
  border-bottom: 1px solid var(--ink-100);
  font-weight: 600;
}
.oh-sync-panel .sp-count { margin-left: auto; color: var(--ink-500); font-variant-numeric: tabular-nums; }
/* 진행바 — 얇게. 숫자를 보조할 뿐 화면을 먹지 않는다 */
.oh-sync-panel .sp-bar { height: 3px; border-radius: 2px; background: var(--ink-100); overflow: hidden; margin-bottom: 0.5em; }
.oh-sync-panel .sp-bar > i { display: block; height: 100%; width: 0; background: var(--oh-green); transition: width 0.3s ease; }

.oh-sync-panel ul { list-style: none; margin: 0; padding: 0; }
.oh-sync-panel li {
  display: flex; gap: 0.5em; align-items: center; padding: 0.25em 0;
  transition: opacity 0.25s ease;
}

/* ② 끝난 줄은 가라앉는다 — 성공만. 실패는 **끝났어도 봐야 하므로** 흐리지 않는다 */
.oh-sync-panel li.sp-ok { opacity: 0.55; }

/* ③ 상태 표식 — 모양이 다르다(색만으로 가르지 않는다) */
.oh-sync-panel .sp-dot {
  width: 1.1em; flex: none; text-align: center;
  font-size: 0.95em; line-height: 1; color: var(--ink-400);
}
.oh-sync-panel .sp-dot::before { content: '○'; }          /* 대기 */
.oh-sync-panel li.sp-queued .sp-dot { color: var(--info-color); }
.oh-sync-panel li.sp-queued .sp-dot::before { content: '◴'; }
.oh-sync-panel li.sp-run .sp-dot { color: var(--warning-color); }
.oh-sync-panel li.sp-run .sp-dot::before { content: '●'; }
.oh-sync-panel li.sp-ok .sp-dot { color: var(--oh-green); }
.oh-sync-panel li.sp-ok .sp-dot::before { content: '✓'; }
.oh-sync-panel li.sp-fail .sp-dot { color: var(--oh-red); }
.oh-sync-panel li.sp-fail .sp-dot::before { content: '✕'; }

/* ① 진행 중인 줄만 맥동한다 — 정적이면 «멈춘 것»으로 읽힌다 */
.oh-sync-panel li.sp-run .sp-dot { animation: sp-pulse 1.1s ease-in-out infinite; }
@keyframes sp-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
/* 🔴 움직임을 싫어하는 사용자에겐 끄되, **구분은 남긴다**(테두리로 대신한다) */
@media (prefers-reduced-motion: reduce) {
  .oh-sync-panel li.sp-run .sp-dot { animation: none; }
  .oh-sync-panel li.sp-run { box-shadow: inset 2px 0 0 var(--warning-color); padding-left: 0.4em; }
}

/* 진행 중인 마켓 이름은 또렷하게 — 나머지는 평소 굵기 */
.oh-sync-panel li.sp-run .sp-name { font-weight: 600; }
.oh-sync-panel li.sp-fail .sp-name { font-weight: 600; color: var(--oh-red); }

.oh-sync-panel .sp-msg {
  color: var(--ink-500); margin-left: auto; text-align: right;
  /* 🔴 긴 실패 메시지가 줄을 밀어내지 않게 — 넘치면 자르고 title 로 본다 */
  max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.oh-sync-panel li.sp-fail .sp-msg { color: var(--oh-red); }

/* ── 디테일: 머리줄 ───────────────────────── */
.oh-detail-head {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--spacing-sm);
  padding-bottom: var(--spacing-sm); border-bottom: 1px solid var(--ink-200); margin-bottom: var(--spacing-sm);
}
.oh-detail-title-wrap { display: flex; align-items: center; gap: var(--spacing-sm); }
.oh-detail-title { margin: 0; font-size: 1.1em; font-weight: 800; }
.oh-cnt-badge {
  padding: 0.2em 0.6em; border-radius: var(--radius-full);
  font-size: 0.8em; font-weight: 700;
  background: color-mix(in srgb, var(--oh-red) 12%, white); color: var(--oh-red);
}
.oh-quick { display: inline-flex; align-items: center; gap: 0.4em; }
.oh-quick-lbl { font-size: 0.8em; font-weight: 600; color: var(--ink-500); }
.oh-back { background: var(--ink-100); }

/* ── 디테일: 목록 ─────────────────────────── */
.oh-filters { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); margin-bottom: var(--spacing-sm); }
.oh-search { flex: 1 1 12em; }
.oh-filters .oh-select { flex: 0 1 auto; }
/* 폰: 검색 한 줄 + 셀렉트 셋 한 줄. 줄바꿈을 폭에 맡기면 폭이 조금만 바뀌어도 «오래된순» 하나만 아랫줄로 떨어진다
   (2026-09-18 디테일 외곽 박스를 걷자 그랬다) → 줄을 정해 둔다. */
@container oh (max-width: 560px) {
  .oh-search { flex-basis: 100%; }
  .oh-filters .oh-select { flex: 1 1 0; min-width: 0; }
}
.oh-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-xs);
  padding: var(--spacing-sm);
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-md);
  background: var(--bg-alt);
  margin-bottom: var(--spacing-sm);
  position: sticky; top: 0; z-index: 2;
}
.oh-allsel { display: inline-flex; align-items: center; gap: 0.4em; font-size: 0.85em; color: var(--ink-600); margin-right: var(--spacing-xs); cursor: pointer; }
/* 🔴 기본 체크박스를 CSS 로 키우면 윈도 크롬에서 비트맵처럼 뭉개진다 — appearance:none 으로 끄고 직접 그린다 */
.oh-allsel input, .oh-ocard-chk input {
  appearance: none; -webkit-appearance: none;
  width: 1.3rem; height: 1.3rem; margin: 0; flex: none; cursor: pointer;
  border: 1.5px solid var(--ink-400); border-radius: var(--radius-sm); background: var(--bg-card);
  display: inline-grid; place-content: center; transition: background 0.1s, border-color 0.1s;
}
.oh-allsel input:hover, .oh-ocard-chk input:hover { border-color: var(--ink-900); }
.oh-allsel input:checked, .oh-ocard-chk input:checked { background: var(--ink-900); border-color: var(--ink-900); }
.oh-allsel input:checked::before, .oh-ocard-chk input:checked::before {
  content: ""; width: 0.32rem; height: 0.6rem; margin-top: -0.12rem;
  border: solid var(--text-inverse); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.oh-allsel input:focus-visible, .oh-ocard-chk input:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.oh-act { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); }

/* 카드 피드 — 기본 1열. 2열은 넓은 화면에서 토글(cols-2)로만 켠다(자동 채움으로 두면 1열 보기가 «조용히» 2열이 된다). */
.oh-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--spacing-sm); }
.oh-empty { grid-column: 1 / -1; text-align: center; color: var(--ink-500); padding: var(--spacing-xl) 0; }

/* 카드 — 한 주문에 상품이 N 개면 카드 N 장(발송 단위가 상품이다) */
.oh-ocard {
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  background: var(--bg-card);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--spacing-sm) var(--spacing-sm);
  font-size: 1em;
  line-height: 1.45;
  align-content: start;
}
.oh-ocard:hover { border-color: var(--ink-400); }
.oh-ocard.is-sel { border-color: var(--ink-900); }
.oh-ocard.is-fail { border-color: var(--oh-red); }

/* [처리중] 표시 — 🔴 **가리는 것이 아니라 가라앉히는 것**(prd-order-hub.md 결정 19).
   ⛔ `display:none` 도, 접기도 아니다 — 마켓에서 실제로 안 끝난 건이 눈에서 사라지면 조용히 방치된다.
   0.55 는 «훑을 때 갈리되 글자는 다 읽히는» 선이다(더 내리면 매번 눌러 확인하게 된다).
   ⛔ **:hover·:focus-within 에서 되살리지 말 것**(2026-09-18 사용자) — 마우스를 올릴 때마다 선명해져 «풀렸나?»로 헷갈렸고,
      폰은 탭 한 번이면 hover 가 눌러붙어 선명한 채 남았다. 눈을 대는 반응은 **테두리**(일반 카드의 `:hover`)만 한다.
   🔴 **카드째 옅게 하지 않는다 — 스위치만 빼고 옅게 한다.** 카드에 opacity 를 걸면 자식은 벗어날 수 없어서,
      «켜져 있다»를 알려 줄 유일한 것(스위치)까지 같이 흐려졌다(2026-09-18 화면). */
.oh-ocard.is-marked .oh-ocard-main,
.oh-ocard.is-marked .oh-info,
.oh-ocard.is-marked .oh-ocard-foot > :not(.oh-ocard-actions),
.oh-ocard.is-marked .oh-ocard-actions > :not(.oh-mark) { opacity: 0.55; transition: opacity 0.15s; }
/* 스위치 — ⛔ 체크박스로 바꾸지 말 것(다른 화면에서 «일괄 선택»이다) · 근거는 order-hub.js markBtn 주석.
   **가장 조용하게** — 옆의 [승인] 은 빨강이고 되돌릴 수 없다. 무게가 같으면 손이 헷갈린다. */
.oh-mark {
  display: inline-flex; align-items: center; gap: 0.45em;
  margin-right: auto;                 /* 버튼 줄의 맨 왼쪽에 떨어져 앉는다 — 처리 버튼들과 한 덩어리로 안 보이게 */
  padding: 0.3em 0.2em; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 0.85em; font-weight: 600; color: var(--ink-500);
}
.oh-mark-track {
  position: relative; width: 2.1em; height: 1.2em; flex: none;
  border-radius: var(--radius-full); background: var(--ink-200);
  transition: background 0.15s;
}
.oh-mark-track::after {
  content: ''; position: absolute; top: 0.15em; left: 0.15em;
  width: 0.9em; height: 0.9em; border-radius: 50%; background: white;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.2); transition: transform 0.15s;
}
/* 켜짐 = **파랑(`--info-color`)**. 빨강은 «미처리·위험», 초록은 «완료»(✓ 승인 보냄), 주황은 «지금 누를 것»(주문수집)이라
   셋 다 뜻이 겹친다 — 초록이면 끝난 줄 알고, 주황이면 옅게 가라앉힌 카드가 오히려 튄다. 파랑만 비어 있다.
   ⛔ 깜박임 금지 — 가라앉히려는 카드에 움직임을 주면 거꾸로 눈을 끈다. 처리중 20장이 깜박이면 화면이 못 쓴다. */
.oh-mark[aria-checked="true"] { color: var(--info-color); }
.oh-mark[aria-checked="true"] .oh-mark-track { background: var(--info-color); }
.oh-mark[aria-checked="true"] .oh-mark-track::after { transform: translateX(0.9em); }
.oh-mark:disabled { opacity: 0.5; cursor: wait; }
.oh-mark:focus-visible { outline: 2px solid var(--ink-900); outline-offset: 2px; border-radius: var(--radius-sm); }
.oh-mark-sum { font-size: 0.8em; font-weight: 600; color: var(--info-color); }   /* 스위치 켜짐과 같은 색 — «이 숫자가 저 스위치들»이다 */
.oh-ocard-chk { align-self: start; margin-top: 0.15em; }
.oh-ocard-body { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.oh-ocard-main { display: flex; flex-direction: column; gap: 0.3em; min-width: 0; order: 1; }
.oh-info { order: 2; }
.oh-ocard-foot { grid-column: 2; display: flex; flex-direction: column; gap: var(--spacing-xs); order: 3; }
.oh-ocard-body > .oh-ocard-foot { order: 3; }
.oh-ocard-price { display: flex; align-items: baseline; gap: 0.5em; color: var(--ink-500); font-size: 0.95em; margin-top: 0.2em; }
.oh-ocard-price b { font-size: 1.3em; font-weight: 800; color: var(--ink-900); letter-spacing: -0.02em; }
/* 🔴 착불 — «기사에게 돈을 받아야 한다»는 행동이 걸린 값이라 빨강으로 눈에 띈다.
   선불·무료는 배지를 만들지 않는다(정상은 말하지 않는다 — 전부 배지면 아무것도 안 보인다). */
.oh-cod { color: var(--oh-red); font-weight: 800; font-size: 0.9em; }
/* 관리코드(셀러) — 주문번호 옆. 마켓 번호와 «다른 것»이라 검정으로 구분되어야 한다. */
.oh-sep { color: var(--ink-300); }
.oh-itemcode { color: var(--ink-900); font-weight: 700; }
.oh-ocard-time { margin-left: auto; color: var(--ink-400); font-size: 0.85em; white-space: nowrap; }
/* 정보 박스 — 라벨(회색·고정폭) | 값(진하게). 목업의 card-customer-grid */
/* 정보 — 상자가 아니라 «구분선 하나». 쌓일 때(폰·2열)는 위에 가는 선, 나란히 설 때(1열 넓은 화면)는 왼쪽 세로선 */
.oh-info {
  margin: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 0.35em 0.9em; align-content: start;
  padding-top: var(--spacing-sm); border-top: 1px solid var(--ink-200);
  font-size: 0.92em;
}
.oh-info dt { color: var(--ink-400); font-weight: 600; font-size: 0.85em; padding-top: 0.15em; letter-spacing: 0.02em; }
.oh-info dd { margin: 0; color: var(--ink-900); font-weight: 700; overflow-wrap: anywhere; }
.oh-info dd .oh-copy { font-weight: inherit; }
.oh-info dd.is-key { font-size: 1.05em; font-weight: 800; }
.oh-info dd.is-soft { font-weight: 500; color: var(--ink-700); }
.oh-info dd.is-soft .oh-copy { color: var(--oh-accent2); }
.oh-ocard-top { display: flex; align-items: center; gap: 0.3em; flex-wrap: wrap; }
.oh-ocard-shop { font-weight: 700; color: var(--ink-800); }
.oh-ocard-biz {
  color: var(--ink-700); font-size: 0.75em; font-weight: 700;
  padding: 0 0.4em; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); background: var(--ink-100);
}
.oh-ocard-name { font-weight: 800; font-size: 1.02em; color: var(--ink-900); overflow-wrap: anywhere; line-height: 1.35; letter-spacing: -0.01em; }
.oh-ocard-name a { color: inherit; }
/* 카드 상단 우측 주문취소 미니 ✕ 아이콘 — 평소엔 은은하게, 호버 시 명확하게 */
.oh-ocard-cancel {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.35rem; height: 1.35rem; margin-left: 0.35rem;
  border: 1px solid color-mix(in srgb, var(--oh-red) 30%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--oh-red) 5%, transparent);
  color: var(--oh-red);
  font-size: 0.75rem; font-weight: 700; line-height: 1;
  cursor: pointer; opacity: 0.7;
  transition: opacity 0.12s ease, background 0.12s ease, border-color 0.12s ease;
  flex: none;
}
.oh-ocard-cancel:hover {
  opacity: 1;
  background: color-mix(in srgb, var(--oh-red) 14%, white);
  border-color: var(--oh-red);
}
.oh-ocard-opt { color: var(--brand-600); font-weight: 600; font-size: 0.9em; }
.oh-ocard-memo {
  display: inline-block;
  padding: 0.1em 0.5em; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--warning-color) 12%, white); color: var(--warning-color);
  border: 1px solid color-mix(in srgb, var(--warning-color) 40%, white);
  font-size: 0.85em; font-weight: 700;
}
.oh-ocard-claim { color: var(--oh-red); font-size: 0.9em; }
/* 복사 가능한 값 — 틸. 「탭하면 복사」를 색 하나로 말한다 */
.oh-copy { cursor: pointer; color: var(--oh-accent2); }
/* 이름과 번호 사이 여백 — 붙어 있어 한 덩어리로 읽혔다(2026-09-15 사용자).
   dd 가 «이름 번호」일 때만(구매자·수령자) — 번호만 든 dd(주문번호·주소)는 :first-child 라 안 밀린다 */
.oh-info dd .oh-copy:not(:first-child) { margin-left: 0.5em; }
.oh-copy:hover { background: var(--oh-accent2-soft); border-radius: 2px; }
.oh-ocard-inv { display: flex; flex-wrap: nowrap; gap: var(--spacing-xs); align-items: center; }
/* 셀렉트·입력·버튼이 한 줄에 서면 높이를 같게 — 크기 클래스가 달라 들쭉날쭉했다 */
.oh-ocard-inv > .oh-select, .oh-ocard-inv > .oh-input, .oh-ocard-inv > .oh-btn,
.oh-actions .oh-select, .oh-actions .oh-btn, .oh-form-inline > .oh-select, .oh-form-inline > .oh-input, .oh-form-inline > .oh-btn { height: 2rem; padding-top: 0; padding-bottom: 0; font-size: 0.9em; }
/* 송장 줄은 살짝 낮추고(2rem) 그만큼 위 여백을 준다 — 카드 높이는 그대로, 균형만 옮긴다(2026-09-15) */
.oh-ocard-foot { padding-top: var(--spacing-xs); }
/* 9.5em — «CU편의점택배»가 끝까지 보이는 폭(7.2em 은 «CU편의점택»에서 잘렸다 · 2026-09-18 사용자). 폰에서도 송장칸이 13자리를 담는다 */
.oh-ocard-inv .oh-select { flex: 0 0 9.5em; min-width: 0; }
.oh-ocard-inv .oh-input { flex: 1 1 auto; min-width: 0; }
.oh-ocard-inv > .oh-btn { flex: none; }
.oh-inv-sent { color: var(--oh-green); font-weight: 600; font-size: 0.9em; }
.oh-qbadge {
  display: inline-block; padding: 0.15em 0.5em; border-radius: var(--radius-full);
  font-size: 0.8em; font-weight: 600;
}
.oh-qbadge.pending { background: var(--brand-100); color: var(--brand-700); }
/* 🔴 「담당 PC 없음/꺼짐」은 실패가 아니라 **기다림의 이유**다 — 빨강으로 그리면 사용자가
   마켓 전송이 깨진 줄 안다. 파랑(대기)과도 갈라야 한다. 기다리면 되는 것과 손을 써야
   하는 것이 같은 색이면 안 된다 (§14-3). */
.oh-qbadge.warn { background: var(--warning-color); color: var(--text-inverse); }
.oh-qbadge.failed { background: var(--oh-red); color: var(--text-inverse); }
.oh-qresult { color: var(--oh-red); font-size: 0.85em; overflow-wrap: anywhere; }
.oh-ocard-actions { display: flex; gap: var(--spacing-xs); flex-wrap: wrap; justify-content: flex-end; }

/* 문자 — 카드의 작은 버튼 · 보내기 패널 · 템플릿 편집 */
.oh-mini { margin-left: 0.4em; padding: 0.05em 0.5em; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); background: var(--bg-card); color: var(--ink-700); font: inherit; font-size: 0.8em; font-weight: 700; cursor: pointer; vertical-align: middle; }
.oh-mini:hover { border-color: var(--ink-900); background: var(--ink-50); }
.oh-sms { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.oh-sms-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm); }
/* 주문취소 모달 — 문자 모달과 같은 줄 구조를 쓴다 */
.oh-cancel { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.oh-cancel textarea { width: 100%; font: inherit; padding: 0.5em; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); }
.oh-modal-actions { display: flex; justify-content: flex-end; gap: var(--spacing-xs); }
/* 전송 중 — 글자 앞에 도는 점. 비활성이어도 흐려지지 않게(«눌리지 않는» 게 아니라 «일하는 중»이다) */
.oh-btn.is-busy { opacity: 1; cursor: progress; }
.oh-btn.is-busy::before { content: ''; width: 0.9em; height: 0.9em; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: oh-spin 0.8s linear infinite; }
@keyframes oh-spin { to { transform: rotate(360deg); } }
.oh-cancel-list { margin: 0; padding-left: 1.2em; font-size: 0.85em; color: var(--ink-600); max-height: 30vh; overflow-y: auto; }
.oh-sms-lbl { color: var(--ink-400); font-size: 0.85em; font-weight: 600; min-width: 4.5em; }
.oh-sms textarea { width: 100%; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); padding: 0.6em; font: inherit; line-height: 1.5; }
.oh-tpl { display: flex; flex-direction: column; gap: var(--spacing-xs); padding-bottom: var(--spacing-sm); border-bottom: 1px dashed var(--ink-200); }
.oh-tpl-body { width: 100%; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); padding: 0.5em; font: inherit; line-height: 1.5; }
.oh-form-note code { background: var(--ink-100); padding: 0 0.3em; border-radius: 3px; font-size: 0.95em; }

/* 문의 카드 */
.oh-inq-body { white-space: pre-wrap; color: var(--ink-700); font-size: 0.9em; max-height: 6.5em; overflow: hidden; }
.oh-ocard.is-open .oh-inq-body { max-height: none; }
/* 접기·펼치기 — 본문과 떨어진 **별도 버튼**(본문 클릭 토글은 복사를 방해했다 · renderInqCard 주석) */
.oh-inq-more { align-self: flex-start; padding: 3px 12px; border: 1px solid var(--ink-300); border-radius: var(--radius-full); background: var(--bg-surface); color: var(--ink-600); font-size: 0.8em; font-weight: 600; cursor: pointer; }
.oh-inq-more:hover { background: var(--ink-100); color: var(--ink-900); }
.oh-inq-answer { display: flex; flex-direction: column; gap: var(--spacing-xs); }
.oh-inq-answer textarea { width: 100%; min-height: 5em; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); padding: 0.5em; font: inherit; }

/* 송장 붙여넣기 표 — 소스메이커 직접입력과 같은 contenteditable 셀 */
.oh-paste-wrap { max-height: 40vh; overflow: auto; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); margin: var(--spacing-sm) 0; }
.oh-paste { width: 100%; border-collapse: collapse; font-size: 0.9em; font-variant-numeric: tabular-nums; }
.oh-paste th { position: sticky; top: 0; background: var(--ink-100); color: var(--ink-600); font-weight: 700; padding: 0.4em 0.6em; text-align: left; border-bottom: 1px solid var(--ink-300); }
.oh-paste td { padding: 0.3em 0.6em; border-bottom: 1px solid var(--ink-100); border-right: 1px solid var(--ink-100); min-height: 1.6em; }
.oh-paste td[contenteditable]:focus { outline: 2px solid var(--ink-900); outline-offset: -2px; background: var(--bg-card); }
.oh-paste td:empty::before { content: "\00a0"; }
.oh-paste-who { width: 5.5em; color: var(--ink-600); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.oh-paste-st { width: 7em; font-size: 0.85em; color: var(--ink-400); white-space: nowrap; }
.oh-paste-st.ok { color: var(--oh-green); font-weight: 700; }
.oh-paste-st.fail { color: var(--oh-red); }

/* ── 송장 입력 모달 ──
   🔴 **송장번호는 «눈으로 대조하는 숫자»다** — 작으면 확인 자체가 안 된다.
      표 글자를 본문보다 키우고 tabular-nums 로 자릿수를 맞춘다(위 .oh-paste 와 함께).
   🔴 컨트롤은 «한 줄». 예전엔 [파일][양식] 한 줄 + [택배사][비우기] 한 줄로 갈려 있어
      서로 붙어 보였다. 되돌리는 🗑 은 오른쪽 끝으로 떼어 놓는다(실수 방지). */
.oh-paste { font-size: 1em; }
.oh-paste td[contenteditable] { font-weight: 700; color: var(--ink-900); }
.oh-inv-bar { display: flex; align-items: center; gap: var(--spacing-xs); flex-wrap: wrap; margin: var(--spacing-sm) 0; }
.oh-inv-bar .oh-select { width: auto; flex: 0 1 auto; }
.oh-inv-reset { margin-left: auto; }         /* 파괴적 동작은 다른 버튼과 거리를 둔다 */
.oh-btn-icon { padding-left: 0.6em; padding-right: 0.6em; line-height: 1; }
.oh-btn-lg { padding: 0.7em 1.6em; font-size: 1em; font-weight: 700; }
/* 🔴 검정 버튼은 `opacity:.5` 로는 «꺼진 것»으로 안 보인다 — 여전히 눌릴 것처럼 읽힌다.
   회색으로 확실히 내린다(2026-09-20 화면 확인). */
.oh-btn-primary:disabled { background: var(--ink-200); border-color: var(--ink-200); color: var(--ink-500); opacity: 1; }
/* 빈 송장번호 칸에 «여기를 누르세요»를 대신하는 자리 — 채우면 사라진다. */
.oh-paste td[data-c="1"]:empty::before { content: "송장번호"; color: var(--ink-400); font-weight: 400; }
.oh-paste td[data-c="1"]:focus::before { content: ""; }
.oh-note-sm { padding: 0.5em 0.8em; font-size: 0.85em; }
.oh-inv-foot { align-items: center; margin-top: var(--spacing-sm); }

/* 📱 폰 — 터치 타깃 44px · 컨트롤은 한 줄에 다 못 들어가므로 늘어나게 둔다.
   🔴 표를 숨기지는 않는다: 미리 채워져 있어 «송장번호 칸만» 두드리면 되기 때문이다
      (빈 표였을 때와 달리 폰에서도 쓸 수 있다 — 2026-09-20). */
@media (max-width: 639px) {
  .oh-inv-bar .oh-btn, .oh-inv-bar .oh-select { min-height: 44px; }
  .oh-inv-bar .oh-btn:not(.oh-btn-icon) { flex: 1 1 8em; }
  .oh-inv-foot .oh-btn-lg { flex: 1 1 100%; min-height: 48px; }
  .oh-paste-who { display: none; }           /* 폰에선 세 열이 한계 — 받는분은 카드에서 본다 */
  .oh-paste-wrap { max-height: 50vh; }
  .oh-paste td, .oh-paste th { padding: 0.55em 0.5em; }
}

/* ── 디테일: 설정 › 자동 수집 (간격 라디오 · 방해금지) ── */
.oh-radios { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); }
.oh-radio { display: inline-flex; align-items: center; gap: 0.35em; padding: 0.4em 0.8em; border: 1px solid var(--ink-300); border-radius: var(--radius-full); font-weight: 700; color: var(--ink-700); cursor: pointer; user-select: none; }
.oh-radio.is-on { border-color: var(--ink-900); background: var(--ink-900); color: var(--text-inverse); }
.oh-radio input { margin: 0; }
/* 🔴 `.oh-form label` 이 column flex 라 체크박스·글·시각이 세로로 흩어졌다(2026-09-16 실측) — 여기서 row 로 되돌린다.
   🔴 **`.oh-radio` 도 같은 병이었다**(2026-09-16 사용자 지적). `.oh-radio` 는 `inline-flex` 지만
   `flex-direction` 을 안 줘서, 명시도가 높은 `.oh-form label`(0,1,1 > 0,1,0)의 `column` 이 이겼다 —
   칩 안에서 동그라미가 글자 «위»로 올라간다. 짧은 라벨(10분)일 땐 어색한 정도로 넘어갔는데,
   알림 종류처럼 긴 라벨이 들어오자 대놓고 깨졌다. ⛔ `.oh-radio` 에서 이 줄을 빼지 말 것. */
.oh-form label.oh-radio { flex-direction: row; }
.oh-form label.oh-quiet { flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--spacing-xs); font-weight: 700; color: var(--ink-700); }
/* 🔵 알림 종류 — **칩이 아니라 평범한 체크박스**다. 칩(`.oh-radio`)은 「여럿 중 하나」를 고르는
   모양이라, 여러 개를 켤 수 있는 자리에 쓰면 «선택된 하나»처럼 읽힌다(검게 칠해지므로 더 그렇다).
   방해금지 줄과 같은 생김새로 두어 「켜고 끄는 것」임이 한눈에 보이게 한다. */
/* 🔴 **칩의 간격(`--spacing-xs`)을 그대로 쓰면 안 된다** — 칩은 자체 padding 이 있어 4px 로도
   떨어져 보이지만, 체크박스는 테두리가 없어 **글자끼리 붙어 한 덩어리로 읽힌다**(2026-09-16 사용자 지적).
   가로는 넉넉히, 세로(줄바꿈 시)는 좁게 — 폰에서 세 줄이 되면 줄 간격까지 넓을 이유는 없다. */
.oh-checks { display: flex; flex-wrap: wrap; column-gap: var(--spacing-lg); row-gap: var(--spacing-sm); }
.oh-form label.oh-check { flex-direction: row; align-items: center; gap: 0.4em; font-weight: 700; color: var(--ink-700); cursor: pointer; user-select: none; }
.oh-form label.oh-check input { margin: 0; flex: 0 0 auto; }
.oh-form .oh-quiet .oh-time { width: auto; flex: 0 0 auto; padding: 0.3em 0.5em; }

/* ── 디테일: 설정 탭 (마켓 연동 | 자동 수집 | 문자 템플릿) ── */
.oh-tabs { display: flex; gap: var(--spacing-xs); border-bottom: 1px solid var(--ink-200); margin-bottom: var(--spacing-md); }
.oh-tab { padding: 0.5em 0.9em; margin-bottom: -1px; color: var(--ink-500); font-weight: 700; text-decoration: none; border-bottom: 2px solid transparent; }
.oh-tab:hover { color: var(--ink-900); }
.oh-tab.is-on { color: var(--ink-900); border-bottom-color: var(--brand-500); }

/* ── 디테일: 설정 (사업자 카드 → 마켓 행 → 상태 알약) ── */
.oh-settings { display: flex; flex-direction: column; gap: var(--spacing-md); }
.oh-biz { border: 1px solid var(--ink-200); border-radius: var(--radius-md); }
.oh-biz-head {
  display: flex; align-items: center; gap: var(--spacing-sm); flex-wrap: wrap;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--ink-100); border-radius: var(--radius-md) var(--radius-md) 0 0;
  /* 🔴 **머리줄을 줄이면 그 안의 것이 «곱해져» 작아진다.** 0.85em 이던 때 [+ 마켓] 과
     드롭다운 항목이 0.85 × 0.85 ≈ 0.72em 까지 내려가 «고르는 일»이 부수적으로 보였다.
     🔴 위계도 뒤집혀 있었다 — 마켓 줄 이름(0.92em)이 사업자 이름(0.85×1.05≈0.89em)보다
     컸다. 사업자가 마켓을 담는 그릇이니 사업자가 더 커야 한다(2026-09-16). */
  font-size: 0.95em; font-weight: 800; color: var(--ink-700);
}
.oh-biz-head[data-foldbiz] { cursor: pointer; user-select: none; }
.oh-biz-name { flex: 1; font-size: 1.1em; color: var(--ink-900); }
.oh-biz-chips { display: none; gap: 0.2em; }
.oh-biz-card.is-folded .oh-biz-chips { display: inline-flex; }
.oh-biz-card.is-folded .oh-biz-rows { display: none; }
.oh-biz-card.is-folded .oh-biz-head { border-radius: var(--radius-md); }
.oh-drag { cursor: grab; color: var(--ink-400); font-size: 1.1em; padding: 0 0.2em; user-select: none; }
.oh-drag:hover { color: var(--ink-900); }
.oh-biz-card.is-dragging { opacity: 0.4; }
.oh-biz-card.is-over { outline: 2px dashed var(--ink-900); outline-offset: 2px; }
.oh-biz-acts { display: flex; gap: var(--spacing-xs); align-items: center; }
/* ⋯ 메뉴 — 순서·이름·삭제를 접는다(머리줄이 시끄럽지 않게) */
.oh-more { position: relative; }
.oh-more > summary { list-style: none; cursor: pointer; }
/* 🔴 **머리줄 버튼은 한 줄에 나란히 선다 — 크기를 따로 주면 높이가 어긋난다.**
   [+ 마켓] 만 키웠다가 옆의 ⋯ 와 높이가 달라졌다(2026-09-16). 둘을 같이 잡는다. */
.oh-biz-acts > .oh-more > summary,
.oh-biz-acts > .oh-btn { font-size: 0.95em; }
.oh-more > summary::-webkit-details-marker { display: none; }
.oh-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  display: flex; flex-direction: column; gap: 2px; min-width: 9em;
  padding: var(--spacing-xs); background: var(--bg-card);
  border: 1px solid var(--ink-300); border-radius: var(--radius-md);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink-900) 12%, transparent);
}
/* 🔴 메뉴 항목은 «선택지»다 — 버튼 크기를 그대로 물려받으면 본문보다 작아진다.
   목록 안에서는 한 단계 키우고 세로 패딩도 늘려 손가락이 닿게 한다. */
.oh-menu .oh-btn { border: none; justify-content: flex-start; font-weight: 600; font-size: 0.95em; padding: 0.5em 0.7em; }
.oh-menu .oh-btn:hover:not(:disabled) { background: var(--ink-100); }

.oh-mkt-row {
  /* 🔴 **2열 유지**(이름+상태 / 버튼). ⛔ 3열(이름|상태|버튼)로 벌리지 말 것 —
     2026-09-16 에 해 봤다가 되돌렸다: 상태 칸이 늘 비어 있는 사업자가 많아 **가로 공간 낭비**가 크다. */
  display: grid; grid-template-columns: 1fr auto;
  gap: var(--spacing-xs) var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  border-top: 1px solid var(--ink-100);
  align-items: center;
  font-size: 0.92em;
}
/* 줄 버튼도 0.85em × 0.92em 로 곱해져 작았다 — 줄 안에서는 한 단계 되돌린다. */
.oh-mkt-acts .oh-btn { font-size: 0.92em; }
.oh-mkt-name { font-weight: 700; color: var(--ink-900); display: flex; align-items: center; flex-wrap: wrap; gap: 0.3em; }
.oh-mkt-extlink {
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink-400); margin-left: 0.2rem;
  padding: 2px 4px; border-radius: var(--radius-sm);
  transition: color 0.12s ease, background 0.12s ease, transform 0.12s ease;
  text-decoration: none;
}
.oh-mkt-extlink:hover {
  color: var(--ink-700);
  background: var(--ink-100);
  transform: translateY(-1px);
}
/* ── API 마켓 IP 안내 (plan §23-4) ──────────────────
   🔴 IP 한 줄이 **눈에 띄어야 한다** — 이게 안 보이면 「IP 를 등록하세요」가 실행 불가능한 안내가 된다.
   가이드는 접어 둔다: 처음 한 번만 필요한데 늘 펼쳐 두면 설정 화면이 길어 보여 거기서 이탈한다. */
.oh-ipbox {
  border: 1px solid var(--brand-500); border-radius: var(--radius-md);
  background: var(--brand-50); padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md); font-size: 0.9em;
}
.oh-ipbox-head { color: var(--ink-800); }
/* 🔴 IP 두 개를 **나란히** — 좁아지면 접힌다. 라벨을 붙여야 «무엇의 IP»인지 알 수 있다. */
.oh-iprows { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); margin-top: 0.5em; }
.oh-iprow { display: flex; align-items: center; gap: 0.4em; }
.oh-iprow-label { font-size: 0.9em; color: var(--ink-600); font-weight: 600; }
.oh-ip {
  display: inline-block; padding: 0.1em 0.5em; border-radius: var(--radius-sm);
  background: var(--bg-card); border: 1px solid var(--ink-300);
  font-variant-numeric: tabular-nums; cursor: pointer;
}
.oh-ip:hover { border-color: var(--brand-500); }
.oh-ipguide { padding: var(--spacing-sm) var(--spacing-md); font-size: 0.95em; line-height: 1.6; }
.oh-ipguide p { margin: 0 0 0.5em; }
.oh-ipguide p:last-child { margin-bottom: 0; }

/* 마켓이 하나도 없는 사업자 — 빈 칸으로 두면 «고장»처럼 보인다. 할 일을 말해 준다. */
.oh-mkt-empty { margin: 0; padding: var(--spacing-md); border-top: 1px solid var(--ink-100); color: var(--ink-500); font-size: 0.9em; }
.oh-mkt-acts { display: flex; gap: var(--spacing-xs); flex-wrap: wrap; justify-content: flex-end; }
/* 상태 줄 — 이름 아래에 붙는다(버튼 칸은 넘지 않는다).
   🔴 이름과 **세로로 맞춘다**: 예전엔 왼쪽 여백이 0 이라 마켓 이름과 상태가 같은 선에서 시작해
   무엇이 제목이고 무엇이 설명인지 눈으로 갈리지 않았다(「안 읽힌다」의 실체). */
.oh-mkt-state {
  grid-column: 1 / 2; display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.4em; margin-top: 0.15em; font-size: 0.85em; color: var(--ink-600);
  overflow-wrap: anywhere; min-width: 0;
}
.oh-pill {
  display: inline-flex; align-items: center; gap: 0.35em; flex: none;
  padding: 0.15em 0.6em; border-radius: var(--radius-full);
  font-size: 0.9em; font-weight: 700;
  border: 1px solid var(--ink-300); color: var(--ink-600); background: var(--bg-card);
}
.oh-pill::before { content: ""; width: 0.5em; height: 0.5em; border-radius: 50%; background: var(--ink-400); }
.oh-pill.ok   { color: var(--oh-green); border-color: color-mix(in srgb, var(--oh-green) 40%, white); background: color-mix(in srgb, var(--oh-green) 10%, white); }
.oh-pill.ok::before { background: var(--oh-green); }
.oh-pill.warn { color: var(--warning-color); border-color: color-mix(in srgb, var(--warning-color) 40%, white); background: color-mix(in srgb, var(--warning-color) 10%, white); }
.oh-pill.warn::before { background: var(--warning-color); }
.oh-pill.fail { color: var(--oh-red); border-color: color-mix(in srgb, var(--oh-red) 40%, white); background: color-mix(in srgb, var(--oh-red) 10%, white); }
.oh-pill.fail::before { background: var(--oh-red); }

/* 기기 카드 — 마켓 비번을 받아갈 수 있는 PC (prd-order-hub.md §19-3).
   🔴 마켓 줄(.oh-mkt-row)과 **같은 틀**을 쓴다. 전용 레이아웃을 만들면 한쪽만 손보게 된다. */
#ohDevices > .oh-biz-rows > p,
#ohDevices > .oh-biz-rows > .oh-mkt-state,
#ohDevices > .oh-biz-rows > #ohPinRow { padding: var(--spacing-sm) var(--spacing-md); margin: 0; }
#ohDevices #ohPinInput { flex: 0 1 10em; }
.oh-more-log { border-top: 1px solid var(--ink-100); }
.oh-more-log > summary { padding: var(--spacing-sm) var(--spacing-md); cursor: pointer; font-size: 0.85em; }

.oh-form { display: flex; flex-direction: column; gap: var(--spacing-sm); padding: var(--spacing-md); }
.oh-form label { display: flex; flex-direction: column; gap: 0.25em; font-size: 0.9em; color: var(--ink-700); }
.oh-form .hint { font-size: 0.8em; color: var(--ink-500); }
.oh-form-actions { display: flex; gap: var(--spacing-xs); flex-wrap: wrap; }
.oh-form-inline { display: flex; flex-direction: row; gap: var(--spacing-xs); align-items: center; flex-wrap: wrap; }
.oh-form-inline .oh-input { flex: 1 1 12em; width: auto; }
/* 자동 수집을 켤 때의 연결 확인 결과 — 🔴 «읽고 넘어갈 안내»가 아니라 «저장을 한 번 막은 이유»라
   빨간 테두리로 세운다(.oh-form-note 와 같은 회색이면 사람이 그냥 다시 누른다). */
.oh-gate {
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--oh-red); border-left-width: 3px;
  background: var(--ink-50);
  font-size: 0.85em; color: var(--ink-700);
  border-radius: var(--radius-sm);
}
.oh-gate code { background: var(--ink-100); padding: 0 4px; border-radius: 3px; }
.oh-form-note {
  padding: var(--spacing-sm) var(--spacing-md);
  border-left: 3px solid var(--ink-300);
  background: var(--ink-50);
  font-size: 0.85em; color: var(--ink-700);
  border-radius: var(--radius-sm);
}
/* 키 발급 안내 — 링크는 셀러센터 «홈»까지만 데려다준다(딥링크는 로그인에서 튕긴다).
   그래서 링크 아래에 **메뉴 경로를 글자로** 둔다. 링크가 주인공이라 한 줄 띄워 구분한다. */
/* 마켓 줄의 보조 이름 — 계정 이름이 주인공이고 이것은 «무슨 마켓인지» 확인용이다.
   칩이 이미 마켓을 말하므로 더 물러나 있어도 된다. */
.oh-mkt-sub { margin-left: 6px; font-size: 0.85em; color: var(--ink-500); font-weight: 400; }

.oh-cred-guide { display: flex; flex-direction: column; gap: 4px; }
.oh-cred-guide a { font-weight: 600; text-decoration: none; }
.oh-cred-guide a:hover { text-decoration: underline; }
.oh-cred-path { color: var(--ink-600); }

.oh-secret { -webkit-text-security: disc; }
.oh-secret.is-shown { -webkit-text-security: none; }

/* ── 모달 · 토스트 ─────────────────────────── */
.oh-modal {
  position: fixed; inset: 0; z-index: 1000;
  background: color-mix(in srgb, var(--ink-900) 45%, transparent);
  display: flex; align-items: flex-end; justify-content: center;
  padding: var(--spacing-md);
}
.oh-modal-box {
  background: var(--bg-card);
  border-radius: var(--radius-lg);
  width: 100%; max-width: 560px; max-height: 80vh;
  display: flex; flex-direction: column;
}
.oh-modal-head { display: flex; align-items: center; justify-content: space-between; padding: var(--spacing-sm) var(--spacing-md); border-bottom: 1px solid var(--ink-200); }
.oh-modal-body { padding: var(--spacing-md); overflow: auto; font-size: 0.92em; }
.oh-result-row { padding: 0.3em 0; border-bottom: 1px solid var(--ink-100); overflow-wrap: anywhere; }
.oh-result-row.ok { color: var(--ink-700); }
.oh-result-row.fail { color: var(--oh-red); }
.oh-result-row.queued { color: var(--brand-700); }
.oh-modal-body textarea { width: 100%; min-height: 8em; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); padding: 0.5em; font: inherit; }

.oh-toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
  background: color-mix(in srgb, var(--ink-900) 92%, transparent); color: var(--text-inverse);
  padding: 0.7em 1.4em; border-radius: var(--radius-full);
  font-size: 0.9em; font-weight: 600; z-index: 1100; max-width: calc(100% - 2rem);
  box-shadow: 0 12px 28px color-mix(in srgb, var(--ink-900) 12%, transparent);
}
.oh-toast.err { background: var(--oh-red); }

@media (min-width: 640px) {
  .oh-modal { align-items: center; }
  .oh-ocard { font-size: 0.95em; }
}

/* ── 디테일: 매출관리 (§20-3) ──
   🔴 색은 늘 쓰던 토큰만 — 매출은 검정(제일 큰 글자), 취소·클레임만 빨강.
      오렌지(--brand-500)는 탭 밑줄 하나뿐이다(common.css 원칙 ①: 오렌지는 화면에 하나). */
.oh-sales-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
}
.oh-seg { display: inline-flex; }   /* 칸막이는 margin -1px 로 겹친다 (gap 은 음수가 안 된다) */
.oh-seg .oh-btn + .oh-btn { margin-left: -1px; }
.oh-seg .oh-btn.is-on { background: var(--ink-900); border-color: var(--ink-900); color: var(--text-inverse); position: relative; z-index: 1; }
.oh-sales-range { display: inline-flex; align-items: center; gap: var(--spacing-xs); }
/* 🔴 날짜칸은 폭을 내용에 맞춘다 — `.oh-input { width: 100% }` 를 그대로 물려받으면
   줄을 통째로 먹어 사업자 셀렉트가 다음 줄로 밀린다(폰에서 3줄이 된다). */
.oh-sales-range .oh-input { width: auto; min-width: 8.5em; }
.oh-input-sm { padding: 0.35em 0.5em; font-size: 0.85em; }

.oh-sales-total { margin-bottom: var(--spacing-md); }
.oh-sales-total-amt { font-size: 1.8em; font-weight: 800; letter-spacing: -0.02em; }
.oh-sales-cancel { color: var(--oh-red); font-weight: 700; }

.oh-sales-table td, .oh-sales-table th { text-align: right; }
.oh-sales-table td:first-child, .oh-sales-table th:first-child { text-align: left; }
.oh-sales-table td:last-child, .oh-sales-table th:last-child { text-align: center; }
.oh-sales-amt-cell { font-weight: 800; color: var(--ink-900); }
.oh-sales-table .oh-icon-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.oh-sales-note { margin-top: var(--spacing-md); font-size: 0.8em; line-height: 1.6; }

/* ── 설정 › 📱 폰 알림 (order-hub-phone.js) ── */
.oh-phone-qr { display: flex; gap: var(--spacing-md); align-items: flex-start; flex-wrap: wrap; }
.oh-phone-qrimg { width: 168px; height: 168px; flex: none; background: #fff; border: 1px solid var(--ink-300); border-radius: var(--radius-sm); }
.oh-phone-qrimg svg { width: 100%; height: 100%; display: block; }
.oh-phone-qr > div:last-child { flex: 1 1 220px; min-width: 0; }
.oh-phone-steps { margin: var(--spacing-xs) 0 0; padding-left: 1.4em; line-height: 1.9; }
.oh-phone-devs { margin-top: var(--spacing-md); display: flex; flex-direction: column; gap: var(--spacing-xs); }
.oh-phone-dev { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-sm); flex-wrap: wrap;
  padding: var(--spacing-xs) 0; border-top: 1px solid var(--ink-200); }
.oh-phone-dev > span:last-child { white-space: nowrap; }
.oh-phone-err { color: var(--oh-red); font-weight: 700; cursor: help; }

/* ── 폰: 페이지 제목·설명 줄을 감춘다 — 첫 화면이 «담당 PC» 줄부터 보이게(2026-09-18 사용자) ──
   주문허브는 폰에서 앱처럼 매일 여는 화면이라 «주문허브 / 주요마켓 주문을 한눈에…» 두 줄이 매번 첫 화면을 먹는다.
   🔴 `display:none` 이 아니라 «눈에만» 감춘다 — `<h1>` 은 문서에 남는다(prd-seo.md: 숨기던 것이 h1 이었다).
   🔴 검색 노출 영향 없음: 로그아웃(로봇) 화면은 잠금 화면이 자기 제목을 따로 낸다 — 이 줄은 로그인한 사람에게만 나온다.
   🔴 이 파일은 주문허브에서만 실린다 — 다른 도구의 제목 줄은 그대로다. */
@media (max-width: 640px) {
  .page-head {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
}

/* ═══ 검증 장치 ① 플로팅 · ② 말풍선 (plan-order-hub-roadmap.md §4) ═══
   🔴 z-index 는 토스트(1100)보다 «아래», 모달(1000)보다 «위». 토스트는 결과를 말하는
      한 줄이라 늘 보여야 하고, 모달이 떠 있을 때 뒤에서 질문이 올라오면 안 된다. */

/* ── ① 플로팅 — 🔴 PC 에서만 뜬다(JS 가 막는다 · §4-2 ②). 폰은 급한 일을 하는 자리다 ── */
.oh-verify {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 1050;
  width: min(22rem, calc(100vw - 2.5rem));
  background: var(--surface-color, #fff);
  border: 1px solid var(--ink-200); border-left: 3px solid var(--oh-accent2);
  border-radius: var(--radius-md); padding: var(--spacing-md);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--ink-900) 16%, transparent);
  animation: oh-verify-in 0.18s ease-out;
}
@keyframes oh-verify-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .oh-verify, .oh-report { animation: none; } }

.oh-verify-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5em; margin-bottom: 0.4em; }
.oh-verify-head strong { font-size: 0.95em; }
.oh-verify-q { margin: 0 0 0.8em; font-size: 0.88em; color: var(--ink-600); line-height: 1.5; }
.oh-verify-acts { display: flex; flex-wrap: wrap; gap: 0.4em; }
.oh-verify-bad { margin-top: 0.7em; display: flex; flex-direction: column; gap: 0.5em; }
.oh-verify-note, .oh-report-body { width: 100%; resize: vertical; font-family: inherit; font-size: 0.9em; }

/* 설정 › 「확인한 것」 — 되돌리기 목록 */
.oh-verify-list { list-style: none; margin: 0.8em 0; padding: 0; display: flex; flex-direction: column; gap: 0.4em; }
.oh-verify-list li {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6em;
  padding: 0.5em 0.7em; border: 1px solid var(--ink-200); border-radius: var(--radius-sm);
  font-size: 0.9em;
}

/* ── ② 말풍선 — 🔵 폰에도 둔다. 사용자가 «먼저 누르는» 것이라 일을 안 끊는다 ── */
.oh-bubble {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 1040;
  width: 2.9rem; height: 2.9rem; border-radius: var(--radius-full);
  border: 1px solid var(--ink-200); background: var(--surface-color, #fff);
  font-size: 1.15rem; line-height: 1; cursor: pointer;
  box-shadow: 0 8px 20px color-mix(in srgb, var(--ink-900) 14%, transparent);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.oh-bubble:hover { transform: translateY(-2px); box-shadow: 0 12px 26px color-mix(in srgb, var(--ink-900) 18%, transparent); }
/* 🔴 ①이 떠 있으면 말풍선을 위로 밀어 겹치지 않게 한다 — 둘 다 오른쪽 아래가 자리다. */
.oh-verify ~ .oh-bubble { bottom: auto; top: 1.25rem; }

.oh-report {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 1050;
  width: min(24rem, calc(100vw - 2.5rem));
  background: var(--surface-color, #fff);
  border: 1px solid var(--ink-200); border-left: 3px solid var(--brand-500);
  border-radius: var(--radius-md); padding: var(--spacing-md);
  box-shadow: 0 16px 40px color-mix(in srgb, var(--ink-900) 16%, transparent);
  animation: oh-verify-in 0.18s ease-out;
}
/* 🔴 «무엇을 같이 보내는지» 보여준다 — 모르는 사이에 뭔가 간다고 느끼면 안 쓴다(§4-2 ②) */
.oh-report-ctx { margin: 0.5em 0 0.8em; font-size: 0.78em; color: var(--ink-500); line-height: 1.5; }

/* 폰 — 좌우로 꽉 채운다(좁은 화면에서 오른쪽에 몰리면 손가락이 닿기 어렵다) */
@media (max-width: 480px) {
  .oh-report { left: 0.75rem; right: 0.75rem; width: auto; bottom: 0.75rem; }
  .oh-bubble { right: 0.9rem; bottom: 0.9rem; }
}
