/* 결제 탭·체크아웃/모의결제/영수증 트레이 — DESIGN.md(Framer) 준수. body.shell-v2 스코프
 *   (admin.css·admin-workspace.css 와 같은 규칙). 표면 대부분은 admin-* 프리미티브를 재사용하고, 여긴 이
 *   화면군에만 있는 것만(요금 카드 격자·주문 요약·모의 결제 결과·영수증 인쇄). spec_billing §5. */

/* ── 요금 비교 카드 ── */
/* D-responsive-1(2026-09-27 크리틱, i3) — auto-fit 은 한 행에 다 안 들어가는 폭(예 768px, 3장만 들어감)에서
 *   4번째(Enterprise) 카드가 혼자 다음 행에 남을 때 그 빈 트랙 공간을 그 카드 하나에 몰아준다(실측:
 *   위 3장 230px vs 카드1개 712px). 4장이 한 행에 다 들어가는 폭(≥1100, tray--modal-lg)에서는 auto-fill 과
 *   결과가 같으므로(빈 트랙이 아예 없다) 손해 없이 auto-fill 로 바꿔 좁은 폭의 홀로 남는 카드가 형제와
 *   같은 폭을 유지하게 한다(빈 트랙은 접지 않고 남긴다 — .billing-panel .admin-cards 가 반대로 auto-fit
 *   을 쓰는 것과 대비: 그쪽은 항목이 적어 넓게 퍼지는 게 의도다).
 * D-responsive-1 회귀(2026-09-27, 독립 검증) — floor 200px 는 데스크톱 최대 콘텐츠 폭(1080px, ≥1130px
 *   뷰포트)에서 `5*200+4*12=1048<=1080` 로 5번째 빈 트랙을 만들어 버렸다(카드 206px+우측 여백 218px,
 *   1280px 실측). 고치려면 넓은 폭에서 5번째가 안 생기면서도 좁은 폭(768px, gridWidth 710px)의 3트랙
 *   조건(`3*floor+24<=710`)을 깨지 않아야 한다 — 둘 다 만족하는 floor 는 [207,228]뿐이다(230은
 *   4px 초과로 768px 의 3+1 을 2+2 로 조용히 바꿔 버렸다 — 실측으로 잡음). 220 선택: 5번째 미생성(여유
 *   68) 및 3트랙 유지(여유 26) 둘 다 만족 — 768/1120/1130/1280/1920 다 재측정 확인. */
body.shell-v2 .billing-plan-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
body.shell-v2 .billing-plan-card { display: flex; flex-direction: column; gap: var(--sp-xs); align-items: flex-start; }
body.shell-v2 .billing-plan-card.is-current { outline: 1px solid var(--accent-focus); outline-offset: -1px; }
body.shell-v2 .billing-plan-card .admin-input { width: 100%; margin-top: var(--sp-xxs); }
body.shell-v2 .billing-plan-card .btn { align-self: stretch; justify-content: center; margin-top: var(--sp-xxs); }
/* D4 — 큰 금액 + 작은 접미(VAT·주기) + 작은 USD, 세 줄이라도 촘촘하게(카드 안 다른 정보 줄과 같은 gap 을 쓰면 벌어져 보인다). */
body.shell-v2 .billing-plan-price { display: flex; flex-direction: column; gap: 2px; }
/* D4(리뷰 재지적) — 크기(24px, admin-stat-val)만 플랜명과 같고 굵기가 둘 다 기본값(400)이라 "큰 금액"이
 * 실제로는 도드라지지 않았다. 글자 크기는 그대로 두고(카드 폭에서 Enterprise "₩4,050,000부터"가 두 줄로
 * 안 밀리도록) 이 자리의 admin-stat-val 만 굵게 — 플랜명(위)보다 무게가 위인 게 가격 카드의 정상적인 위계다. */
body.shell-v2 .billing-plan-price .admin-stat-val { font-weight: 700; }
/* D3 — 네 카드의 정보 줄 수·길이가 달라도 CTA(선택 버튼·현재 플랜·Enterprise 문의)는 카드 바닥 한 줄에 선다.
 *   margin-top:auto 가 그 위 정보를 위로 밀어 올리고, 이 래퍼 자신도 flex column 이라야 안의 .btn(위 규칙의
 *   align-self:stretch)이 폭을 꽉 채운다(그렇지 않으면 이 div 는 block 이라 align-self 가 아무 효과가 없다). */
body.shell-v2 .billing-plan-cta { display: flex; flex-direction: column; align-self: stretch; width: 100%; margin-top: auto; }
/* D5(2026-09-27 크리틱 — advisor 재진단으로 근본원인 정정) — 처음엔 draw()를 showModal() 전으로 옮기면
 * 되는 줄 알았으나(레이스가 아니었다) 재현이 그대로였다. 진짜 원인: 카드는 `home-stat` 클래스를 같이 쓰는데
 * components.css 의 그 공용 규칙이 "코스모스 배경 위 유리 카드"용 backdrop-filter+반투명 배경을 준다 — 홈
 * 화면(진짜 배경 위)에서는 맞는 디자인이지만, 이 카드는 이미 블러가 걸린 모달(dialog.tray, 아래
 * liquid-glass-overlays.css) *안*에 있다. "글라스 위에 글라스"(그 파일 헤더가 명시적으로 금지하는 패턴)가
 * 되고, 모달의 진입 전환(scale·opacity, tray.css)이 도는 동안 이 중첩 backdrop-root 위 글자(맨 처음 카드의
 * "Free" 제목)가 첫 프레임에 합성되지 않는 레이스가 생겼다(재현 3/3). 모달 안에서는 배경이 이미 모달
 * 표면이라 카드 자신의 블러가 걸러낼 것이 없다 — 죽여도 잃는 게 없다. background 는 대신 liquid-glass
 * -overlays.css 가 `.tray` 자손에 이미 재정의해 둔 --surface-1(알파 토큰)로 — 새 값을 만들지 않는다. */
body.shell-v2 dialog.tray .billing-plan-card {
  background: var(--surface-1);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* ── 체크아웃 ── */
body.shell-v2 .billing-checkout-body { display: flex; flex-direction: column; gap: var(--sp-md); }
body.shell-v2 .billing-terms-row { flex-direction: row; align-items: flex-start; gap: var(--sp-xs); }
body.shell-v2 .billing-terms-row a { color: var(--accent-focus); }

/* ── 모의 결제창 ── */
body.shell-v2 .billing-mock-pay { display: flex; flex-direction: column; gap: var(--sp-sm); }
body.shell-v2 .billing-test-banner { text-align: center; font-weight: 600; }
body.shell-v2 .billing-payment-result { display: flex; flex-direction: column; gap: var(--sp-sm); align-items: center; text-align: center; padding: var(--sp-lg) 0; }
body.shell-v2 .billing-payment-result.is-ok h3 { color: var(--positive); }
body.shell-v2 .billing-payment-result.is-fail h3 { color: var(--danger); }
/* 테스트 카드 3종 — 공용 세그먼트(segmented.js)를 트레이 폭에 맞춰 고르게 펼친다(기본은 내용 폭 알약) */
body.shell-v2 .billing-mock-pay .seg { display: flex; width: 100%; }
body.shell-v2 .billing-mock-pay .seg-opt { flex: 1 1 0; }
/* 결제 완료 — [영수증](보조) + [확인](주) 한 줄 */
body.shell-v2 .billing-payment-actions { display: flex; gap: var(--sp-xs); flex-wrap: wrap; justify-content: center; }

/* ── 결제 탭 본문(.billing-panel — adminBillingTab.js) ── */
/* D6 — section()의 head→본문 간격이 admin-section 의 gap(12px, 다른 정보 줄 사이 간격과 같다)뿐이라
 *   "제목이 그 아래 내용을 소유한다"는 위계가 안 읽혔다. 결제 탭 섹션에서만 head 아래에 margin 을 더해
 *   (gap 위에 더해진다) 제목→본문 간격을 본문 내부 간격보다 넓힌다 — admin.css(공용) 는 안 건드린다. */
body.shell-v2 .billing-panel .admin-section-head { margin-bottom: var(--sp-xs); }
/* D6(리뷰 재지적) — 공용 --row 변형은 space-between(제목 왼쪽·배지 맨 오른쪽)이라 "제목 옆"보다는
 *   "제목과 같은 줄의 반대쪽 끝"으로 보였다. 결제 탭 요금제 헤드에서만 배지를 제목 바로 옆으로 붙인다. */
body.shell-v2 .billing-panel .admin-section-head.admin-section-head--row { justify-content: flex-start; gap: var(--sp-xs); }
/* 통계 값 — 두 칸 카드에서 날짜·플랜명이 어절 중간에서 끊겼다 */
body.shell-v2 .billing-panel .admin-stat-val { word-break: keep-all; }
/* 섹션 동작 줄(요금제 변경·해지 · 충전팩)은 카드 바로 아래 왼쪽. 구조 파일의 margin-left:auto 는 행 안 동작용이라
 *   섹션 직계 자식에만 푼다 — 결제 내역 행(.admin-row) 안 [영수증]·[환불 요청]은 그대로 오른쪽이다. */
body.shell-v2 .billing-panel .admin-section > .admin-row-actions { margin-left: 0; align-self: flex-start; }
/* 표 — 날짜 칸은 한 줄(버킷 표는 마지막 칸 '만료', 사용 추이는 첫 칸 '날짜'). 버킷 출처('매달 지급')도 한 줄 — 390 에서 접혀 행이 두 줄이 됐다.
 *   넘치면 .admin-table-wrap(admin.css)이 가로로 민다 */
body.shell-v2 .billing-buckets .admin-table td:last-child,
body.shell-v2 .billing-buckets .admin-table td:first-child,
body.shell-v2 .billing-usage .admin-table td:first-child { white-space: nowrap; }
/* 결제수단 — 요약 줄 + [변경] */
body.shell-v2 .billing-summary-row { display: flex; align-items: center; gap: var(--sp-sm); flex-wrap: wrap; }
body.shell-v2 .billing-summary-row .admin-sub { margin: 0; }
/* 상태 배지 — 결제 실패도 다른 상태 배지(admin-role)와 같은 크기, 색만 오류 */
body.shell-v2 .admin-role.billing-role-err { color: var(--danger); background: var(--danger-soft); }
/* 세금계산서 발행 요청 — 체크박스와 라벨 한 줄(약관 동의 줄 .billing-terms-row 와 같은 모양). 구조 파일의 .admin-field 는
 *   '라벨 위 입력' 세로라 체크박스가 라벨 위에 홀로 섰다. billingInfoSection.js 는 이 라운드 편집 밖이라 구조로 고른다. */
body.shell-v2 .billing-panel .admin-form > .admin-field:has(> input[type='checkbox']) { flex-direction: row; align-items: center; gap: var(--sp-xs); min-height: 40px; } /* 40 = 옆 입력칸 높이 — 같은 줄에서 가운데가 맞는다 */

/* ── 영수증 ── */
body.shell-v2 .receipt-doc { display: flex; flex-direction: column; gap: var(--sp-md); }
body.shell-v2 .receipt-parties { display: flex; gap: var(--sp-lg); flex-wrap: wrap; }
body.shell-v2 .receipt-party { flex: 1 1 200px; }
body.shell-v2 .receipt-party p { margin: 2px 0; color: var(--ink-80); font-size: var(--fs-caption); }
body.shell-v2 .receipt-items .is-num { text-align: right; }
body.shell-v2 .receipt-totals { align-self: flex-end; text-align: right; }
body.shell-v2 .receipt-totals p { margin: 2px 0; }
body.shell-v2 .receipt-total-line { font-weight: 700; font-size: var(--fs-tagline); color: var(--ink); }

/* 인쇄 — 트레이(top-layer dialog) 밖 전부를 지우고 영수증 문서만 남긴다(advisor 조언: CSP 상 window.open 대신). */
@media print {
  /* D2(2026-09-27 크리틱, 실제 Chrome printToPDF 대조) — 위 규칙은 dialog 밖만 지운다. dialog 자신과
   *   그 자식은 그대로 어두운 배경·글자색을 쓰므로, body 배경과 영수증 카드 배경·반경을 안 지우면
   *   인쇄 결과가 검은 종이 위에 어두운 카드가 뜬 모양이 된다(실측). 아래 세 줄이 흰 종이로 되돌린다. */
  /* D-print-3(2026-09-27 크리틱, i3 — advisor 재진단) — 위 body 규칙만으로는 실제 Chrome 인쇄/PDF 에서
   *   페이지 네 귀퉁이가 rgb(18,18,18) 어두운 테두리로 남는다(화면 스크린샷엔 안 보이고 인쇄 결과물에만
   *   보여 두 차례의 '해결됨' 검증을 통과했었다). 원인: Chromium 은 인쇄 캔버스의 기본 배경을 body 가 아니라
   *   루트(:root/html)의 color-scheme 으로 정하는데, tokens.css 의 `:root{color-scheme:dark}` 는 이 print
   *   블록에서 한 번도 되돌려진 적이 없었다(body 스코프 선택자라 :root 엔 안 닿는다). 루트도 같이 되돌린다. */
  html, :root { background: #fff !important; color-scheme: light !important; }
  body.shell-v2 { background: #fff !important; color-scheme: light !important; }
  body.shell-v2 > *:not(dialog.receipt-tray) { display: none !important; }
  /* D-print-1(2026-09-27 3차 — advisor 자문 뒤 getComputedStyle 로 관여 규칙을 직접 나열해 확정한 진짜 원인).
   *   D2·재크리틱 두 판 모두 liquid-glass-overlays.css 의 `dialog.tray` 재질 규칙(카드 자체의 반경·그림자·
   *   backdrop-filter)을 범인으로 지목했으나, 다이얼로그 배경을 라임으로 강제해 실측한 결과 카드 자신은
   *   정확히 카드 영역만 칠해졌고 — 검은 면은 카드 위·아래로 그보다 훨씬 넓게, 페이지 대부분을 덮고 있었다.
   *   backdrop 를 display:none 으로 꺼도, 우주 배경 캔버스(cosmos-gl)를 통째로 지워도 검은 면은 그대로였다.
   *   실제 범인은 `body.intro-pending::after`(web/ui/intro.css) — 로그인 뒤 홈 적재 동안 사이드바·홈을
   *   가리는 전체화면 검정 스플래시 가림막(position:fixed, inset:0, z-index:4999, background:#000)이다.
   *   이 클래스는 app.js 가드(1.4초)로 정상적으로는 곧 떨어지지만, 인쇄 시점에 아직 안 떨어져 있으면
   *   다이얼로그·백드롭 어느 쪽도 아닌 이 가림막이 그대로 인쇄돼 페이지 전체가 검게 찍힌다 — dialog 밖을
   *   지우는 위 규칙은 body 의 '자식'만 겨냥해 body 자신의 ::after 는 건드리지 못했다(`::before`/`::after` 는
   *   자식이 아니라 그 요소 자신에 붙는다). 카드 반경·그림자·backdrop-filter 를 !important 로 굳힌 것 자체는
   *   무해하고(둥근 모서리·그림자가 새던 것도 실제로 고쳤다) 그대로 둔다 — 다만 검은 페이지의 진짜 원인은
   *   아래 두 줄이다. */
  body.shell-v2::after { display: none !important; content: none !important; }
  body.shell-v2 dialog.receipt-tray {
    position: static !important; inset: auto !important; margin: 0 !important; width: auto !important; height: auto !important;
    box-shadow: none !important; max-width: none !important; max-height: none !important; overflow: visible !important;
    background: none !important; border-radius: 0 !important; color: #000 !important;
    -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
  }
  /* ::backdrop 은 display:none 만으로 실사용 중 확인됐지만(red 테스트로 되살려서 확인), 인쇄 파이프라인의
   *   또 다른 변주를 대비해 background 도 함께 지운다 — 어느 한쪽만 걸어도 다른 쪽이 방어한다. */
  body.shell-v2 dialog.receipt-tray::backdrop { display: none !important; background: transparent !important; }
  /* 카드 안 모든 글자·테두리를 검은색으로, 배경은 없앤다 — 토큰(--ink-80 등)이 여전히 어두운 테마 값을
   *   가리키므로 하나씩 고치는 대신 한 번에 덮는다(영수증은 사람이 읽어야 하는 문서라 안전한 쪽으로
   *   정한다). ⚠️ background 도 함께 지운다 — 상태 안내(statusNote·refundNote, .admin-note[.is-err])가
   *   각자 어두운/색 배경(admin.css)을 갖고 있어, 글자만 검게 하면 "흰 종이 위 검은 상자 안 검은 글자"로
   *   안 보이는 문서가 된다(실측 대조 후 추가). */
  body.shell-v2 dialog.receipt-tray * { color: #000 !important; border-color: #000 !important; background: none !important; }
  body.shell-v2 dialog.receipt-tray .tray-grip,
  body.shell-v2 dialog.receipt-tray .tray-close,
  body.shell-v2 dialog.receipt-tray .btn { display: none !important; }
  body.shell-v2 dialog.receipt-tray .tray-body { overflow: visible !important; max-height: none !important; }
}

/* ── Enterprise exempt 안내 ── */
body.shell-v2 .billing-exempt-row { display: flex; align-items: center; gap: var(--sp-xs); font-weight: 600; }

/* 좌석 초과 안내(B16) — 안내 문구 + [요금제 변경] 버튼을 한 줄에 놓는다(admin-note 기본은 텍스트만 전제하는 블록). */
body.shell-v2 .billing-seats-over { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-sm); flex-wrap: wrap; }

/* ── 크레딧 소진 전역 배너 — showToast 와 달리 버튼 슬롯이 있다(toast.js 계약 밖이라 별도 DOM). ──
 *   떠 있는 알림 = 오버레이 층 글라스(토스트와 같은 재질 토큰). liquid-glass-overlays.css 의 대상 목록은 공용이라
 *   거기 더하지 않고 같은 토큰을 여기서 쓴다. 투명도 감소·대비 증가 폴백은 토큰 쪽이 이미 갖고 있다. */
body.shell-v2 .billing-blocked-banner {
  /* D7(2026-09-27 크리틱) — --top-h(56px, 전 폭에서 늘 떠 있는 상단바)를 안 뺀 top:var(--sp-md) 라 데스크톱에서
   *   배너가 상단바 바로 그 높이에 떠, Finder 같은 화면의 자체 툴바(빵부스러기·검색·새 프로젝트)와 한 줄에
   *   겹쳐 보였다. .lib-inspector(framer.css)가 이미 top: calc(var(--top-h) + 8px) 로 쓰는 것과 같은 공식 —
   *   ≤810 규칙은 전부터 이미 이 공식이었다(중복이라 아래에서 지운다). */
  position: fixed; top: calc(var(--top-h) + var(--sp-sm)); left: 50%; transform: translateX(-50%); z-index: 2000;
  display: flex; align-items: center; gap: var(--sp-sm); max-width: min(480px, calc(100% - 32px));
  padding: var(--sp-sm) var(--sp-md); border-radius: var(--r-lg);
  background: var(--lg-sheen), var(--lg-tint-thick);
  -webkit-backdrop-filter: var(--lg-filter); backdrop-filter: var(--lg-filter);
  box-shadow: var(--lg-specular), var(--lg-rim-hover), var(--shadow-product);
  --ink-48: var(--lg-ink-48);
}
/* 글라스 위 불투명 표면은 가장자리를 덮는다 — 안쪽 표면 단은 알파로(liquid-glass-overlays.css 와 같은 치환) */
body.shell-v2 .billing-blocked-banner * {
  --surface-1: var(--lg-fill-1); --surface-2: var(--lg-fill-2); --surface-3: var(--lg-fill-3);
  --hairline: var(--lg-divider); --hairline-soft: var(--lg-divider-soft);
}
body.shell-v2 .billing-blocked-text { flex: 1 1 auto; font-size: var(--fs-caption); color: var(--ink); word-break: keep-all; } /* 390 에서 '썼습니다.' 의 '다.' 만 줄을 넘던 것 */
body.shell-v2 .billing-blocked-hint { font-size: var(--fs-fine); color: var(--ink-48); }

/* 사이드바가 있는 허브 셸에서는 콘텐츠 영역 가운데(토스트 components.css 와 같은 보정). shell-chrome 으로 묶는 것이 중요하다:
 *   tokens.css 가 :root 에 --sidebar-w: 240px 를 주므로 사이드바 없는 화면(로그인 등)에서도 240 이 잡힌다.
 *   허브는 88px(sidebar-dock.css) · 프로젝트 셸은 0(shell2.css pshell-open). ≤810 은 아래에서 좌우 16px 로 박는다. */
@media (min-width: 811px) {
  body.shell-v2.shell-chrome .billing-blocked-banner { left: calc(50% + var(--sidebar-w) / 2); }
}

@media (max-width: 810px) {
  /* top 은 이제 기본 규칙과 같은 공식(D7) — 여기선 좌우만 화면 폭으로 넓힌다 */
  body.shell-v2 .billing-blocked-banner { left: 16px; right: 16px; transform: none; max-width: none; }
  body.shell-v2 .billing-blocked-banner .btn { min-height: 44px; }
  body.shell-v2 .billing-blocked-banner .btn--icon-only { min-width: 44px; }
  /* 터치 44px — 결제 탭 · 요금 비교 · 체크아웃 · 모의 결제 · 영수증 트레이의 버튼과 카드 세그먼트(admin.css ≤810 관례).
   *   체크아웃·요금 비교는 JS 파일을 안 건드리고 트레이 cls 로만 잡는다. */
  body.shell-v2 :is(.billing-panel, .billing-pricing-tray, .billing-checkout-tray, .mock-payment-tray, .receipt-tray) :is(.btn, .seg-opt) { min-height: 44px; }
}

/* 2차 적대 리뷰 major(ux) — 충전팩 3개는 라벨이 길어(금액·크레딧·USD 병기) admin-row-actions
 * 기본(줄바꿈 없음)에서 390px 를 넘긴다. 전역 규칙은 안 건드리고 이 줄만 줄바꿈한다.
 * (운영자 결제 조작 줄은 2026-09-26 관리자 탭 '플랫폼'과 함께 백오피스로 옮겼다 — spec_backoffice §8-2.) */
body.shell-v2 .billing-credit-packs { flex-wrap: wrap; }

/* P1-1: 구조 파일(admin.css)의 .admin-cards 는 auto-fill 이다. 카드가 한두 개뿐인 좌석·크레딧 섹션에서는
 *   빈 트랙을 접지 않고 남겨 화면 폭의 상당 부분이 비어 보였다. 결제 탭에서만 auto-fit 으로 바꾼다. */
body.shell-v2 .billing-panel .admin-cards { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* P2-2: 결제 내역 행의 금액은 admin-sub 클래스라 같은 탭의 admin-stat-val, is-num 과 달리 tabular-nums 가 없다. */
body.shell-v2 .billing-invoice-amount { font-variant-numeric: tabular-nums; }

/* P3-1(재수정 2026-09-27) — 전판(각 .admin-row 가 자기만의 그리드)은 빈 액션 칸이 있는 행(결제실패 — 영수증
 *   버튼이 없다)에서 1fr 칼럼이 늘어나 다른 행과 배지·버튼이 어긋났다. 목록(.billing-invoices-list)을
 *   그리드 컨테이너로 두고 각 행은 subgrid 로 그 트랙을 공유한다 — 폭은 모든 행을 합쳐 한 번만 계산되므로
 *   빈 칸이 있어도 어긋나지 않는다. 날짜 칸도 max-content 로 넓혀 "YYYY년 M월 D일"이 두 줄로 안 접힌다
 *   (전엔 96px 고정이라 접혔다 — billing-invoice-date 클래스가 담당한다). 좁은 화면(≤810)은 다시 구조 파일 기본(flex)로. */
body.shell-v2 .billing-invoices-list {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(120px, max-content) minmax(90px, auto) 84px auto;
  row-gap: var(--sp-xs);
  column-gap: var(--sp-sm);
}
body.shell-v2 .billing-invoices-list > .admin-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  column-gap: var(--sp-sm);
}
body.shell-v2 .billing-invoice-date { white-space: nowrap; } /* max-content 뒷받침(위 주석) — 줄바꿈 자체를 막아 안전하게 */
@media (max-width: 810px) {
  /* 좁은 화면에서는 고정 칼럼이 자릿수를 못 견딘다. 구조 파일 기본값(flex-wrap)으로 되돌린다. */
  body.shell-v2 .billing-invoices-list { display: flex; flex-direction: column; gap: var(--sp-xs); }
  body.shell-v2 .billing-invoices-list > .admin-row { display: flex; flex-wrap: wrap; }
}

/* Integrator P1(2026-09-27) — .admin-pane은 결제 흐름이 끝난 뒤 초점이 돌아갈 곳이 없을 때만 쓰는
   프로그램적 초점 폴백 자리(위 renderBillingPanel의 tabIndex=-1)이지, 사람이 키보드로 찾아가는
   진짜 컨트롤이 아니다. chrome-base.css의 전역 [tabindex]:focus-visible 규칙을 그대로 받으면
   결제 성공/실패 결과창을 마우스 클릭으로 닫을 때마다 결제 패널 전체를 감싸는 파란 포커스 링이 떴다
   (요금제변경→체크아웃→모의결제→영수증 체인에서 매번 재현). 현재 pane에 tabIndex를 주는 건 결제 탭뿐
   (사용자/설정 등 다른 탭은 pane에 tabIndex를 안 준다) — 넓게 매칭해도 다른 탭의 포커스 링을 지우지 않는다. */
body.shell-v2 .admin-pane:focus-visible { outline: none; box-shadow: none; }
