/* ==========================================================================
   style.css — 공통 + 페이지 스타일
   구획: 1) 리셋·베이스  2) 유틸리티  3) 공통 컴포넌트  4) 페이지(index)
        5) 페이지(Top 20 정산)  6) 반응형 (표 → 카드 전환 등)
   색·폰트·간격 리터럴은 css/tokens.css 에만 존재한다.
   ★ 열 폭 %는 디자이너가 지정한 값(합 100)을 그대로 쓴다. 지정값 자체가
     화면 노출 금지 수치(배분율)와 겹치는 정수들을 의도적으로 피해 만들어졌다 —
     CSS 에 그 값이 들어가면 금지 수치 스캔에 오탐으로 걸리기 때문이다(레이아웃 §3 ④ 주석).
   ========================================================================== */

/* ==========================================================================
   1) 리셋 · 베이스
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-family-base);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
}

h1, h2, h3, h4, p, ul, ol, dl, dd, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }

h1, h2, h3, .u-keep-all {
  word-break: keep-all;
  overflow-wrap: break-word;
  line-height: var(--line-height-tight);
  letter-spacing: var(--letter-spacing-heading);
}

img, svg { max-width: 100%; }
img { height: auto; }

a { color: var(--color-primary); }

button, select, input, textarea { font: inherit; }

/* 스티키 헤더 앵커 보정.
   ★ v2.8 — `--header-h` 의 뜻이 "탭 바 높이 48px"에서 **"헤더 전체 높이"**(124/88/64)로
     바뀌었다. 헤더가 1행 하나뿐이라 이 한 값이 곧 상시 점유 높이이고, 이 식은
     **고칠 필요 없이 자동으로 따라온다** — 여기에 브랜드 바 몫을 더하는 식의 보정을
     추가하지 말 것(이중 보정이 되어 앵커가 과하게 내려간다. 레이아웃 §1). */
[id] { scroll-margin-top: calc(var(--header-h) + var(--space-4)); }

/* 포커스 링 — 모든 인터랙티브 요소 공통 (라이트/네이비 밴드 겸용) */
a:focus-visible,
button:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   2) 유틸리티
   ========================================================================== */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
.container--max    { max-width: calc(var(--container-max)    + var(--container-pad) * 2); }
.container--data   { max-width: calc(var(--container-data)   + var(--container-pad) * 2); }
.container--narrow { max-width: calc(var(--container-narrow) + var(--container-pad) * 2); }

/* 숫자 타이포 (디자인 시스템 §2-4) — 금액·수량·순위·일시·건수 전부 이 계열을 쓴다 */
.num {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: var(--letter-spacing-num);
  line-height: var(--line-height-num);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}
.num--amount { font-size: var(--font-size-body-lg); font-weight: var(--font-weight-bold); }
/* ★★ v2.28 — 소수부 축소 (PPT S5 ④: *"소수점 아래로 글씨 크기 작게"*)
   ★ `em` 을 쓴다 — 부모 값 폰트에 **비례**해야 표(16px)·카드(18px) 어디서든 같은 비율로
     작아진다. `px` 나 토큰 고정값을 쓰면 카드 모드에서 정수부와의 대비가 달라진다.
   ★ 0.78em 은 4px 스케일과 무관한 **비율**이라 스케일 규칙의 대상이 아니다(간격이 아니라
     글자 크기의 상대비). 표 기준 16 × 0.78 = 12.48px 로 캡션 하한(13px)보다 작지만,
     **읽는 단위가 아니라 정밀도 꼬리**라 하한 규칙의 취지(본문 가독)와 성격이 다르다
     → designer 판단 요망(§7 D-17).
   ★ `font-variant-numeric` 을 상속받아 정수부와 **같은 자간·같은 숫자 글리프**를 쓴다 —
     따로 선언하면 소수점 앞뒤가 다른 서체처럼 보인다. */
/* ★★ v2.35 — 소수부 색·굵기 정합 (사용자 직접 지시 2026-08-13 · B1) ★★
   지시 원문: *"표의 소수점 자리 숫자를 검은색으로 표현 (현재 흐린 소수부를 본문
   숫자색과 동일하게)"*
   ★ 진단 — 흐려 보인 원인은 **색이 아니라 굵기·글리프**였다: 이 span 은 `.num`(정수부)의
     **형제**라 `.num` 의 semibold(600)·tabular-nums 를 상속받지 못하고, td 기본
     regular(400)·기본 글리프로 렌더됐다(v2.28 축소 주석의 *"font-variant 를 상속받아"*
     서술은 형제 관계라 실제로 성립하지 않았다 — 실렌더 computed 대조로 확인).
     0.78em 축소(v2.28 지시)와 겹쳐 정수부보다 옅은 회색처럼 읽힌 것이다.
   ★ 처방 — 색은 본문 숫자와 같은 **--color-text 를 명시**(상속 우연에 맡기지 않는다),
     굵기·숫자 글리프를 `.num` 과 같은 토큰으로 맞춘다. **크기 축소(0.78em)는 유지** —
     v2.28 사용자 지시(*"소수점 아래로 글씨 크기 작게"*)는 살아 있고, 이번 지시는 색이지
     크기가 아니다. 두 페이지 공통 규칙이라(랭킹 표는 소수부 없음 — `원` 정수) 건별
     표·현황 타일이 함께 맞는다. */
.num__frac {
  font-size: 0.78em;
  letter-spacing: var(--letter-spacing-num);
  color: var(--color-text);
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* 지표 타일 값. 크기는 타일이 아니라 .stat-strip 컨테이너가 정한다(디자인 시스템 §2-5) */
.num--stat { font-size: var(--font-size-stat); font-weight: var(--font-weight-black); }
/* 히어로 대형 수치 (v2.21 · ranking ② 공동 정산 누적 총액) — 이 사이트에서 **가장 큰 수치**다.
   ★ [토큰 추가 대기] 전용 토큰(`--font-size-display` 류)이 없어 **기존 토큰 파생**으로 뒀다
     (스킬 규약: 임의 리터럴 대신 calc 파생 + notes 추적). designer 가 정식 토큰을 주면
     이 한 줄의 `calc(...)` 를 그 토큰으로 바꾼다 — 다른 곳은 손댈 것이 없다. notes §7 상신.
   ★ 배수 1.2 의 근거는 **좁은 화면의 넘침 한계**다. `--font-size-hero` 는 <768px 에서
     28px 로 줄므로 여기서는 33.6px 이 된다. 360px 뷰포트의 narrow 컨테이너 가용폭에서
     `1,234,567,890원`(13자 + 단위)이 한 줄에 들어가는 가장 큰 배수대가 이 부근이고,
     1.5(=42px)로 올리면 자릿수가 큰 실값에서 가로 넘침이 난다. 값이 `—` 인 지금은
     넘칠 일이 없지만, **넘치는 순간은 실데이터가 들어온 날**이라 그때 고칠 수 없다.
   ★ `.num` 이 이미 `white-space: nowrap` 이라 금액은 절대 두 줄로 쪼개지지 않는다
     (`1,234,567,` / `890원` 같은 낭독 사고 방지). 그래서 폭 여유를 크기로 확보해야 한다. */
.num--hero { font-size: calc(var(--font-size-hero) * 1.2); font-weight: var(--font-weight-black); }
.num__unit {
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-muted);
  margin-left: 2px;
  font-variant-numeric: normal;
}
/* 로마자 단위(`USDT`·`OnTact`)는 텍스트 자체에 공백 1칸을 품는다(v2.9-1 / QA W10-1 —
   common.js `unitNode`). 그 공백이 이 폰트 크기(14px)에서 3.42px 이므로 margin 2px 를
   덜어내 시각 간격 증가를 +1.42px 로 묶는다. 한글 단위(`원`)는 이 클래스가 붙지 않아
   기존 2px 그대로다 — Top 20 정산 화면은 픽셀 단위로 불변.
   nowrap: 공백이 span 안에 있어도 그 자리가 줄바꿈 지점이 되지 않게 한다(§2-4 규칙 9).
   ★★ v2.35 — 간격 확대 (사용자 직접 지시 2026-08-13 · B2) ★★
   지시 원문: *"숫자와 단위 사이 여백 넣기 (예: 372,155.9296USDT 처럼 붙어 보이는 것 해소)"*
   ★ 진단 — 공백 문자는 **정상적으로 렌더되고 있었다**(unitNode 가 span 안쪽에 ' ' 를
     품는 v2.9-1 규약 그대로 · 실렌더 확인). 붙어 보인 원인은 그 공백이 단위 폰트
     14px 기준 **3.42px 뿐**인데 위 규약이 margin 마저 0 으로 죽여 놓아, 굵은 18px
     숫자 뒤에서 시각적으로 소멸한 것이다 — **공백 문자 문제가 아니라 스타일 여백
     문제**라 unitNode 는 손대지 않고(포맷 지점 불변 규약) CSS 만 고친다.
   ★ 처방 — ~~margin-left: 0~~ → **var(--space-1)**(4px). 공백 3.42px 와 합쳐 총
     ≈7.4px — 낭독·복사 문자열은 그대로(공백 1칸)이고 시각 간격만 벌어진다.
     한글 단위(`원`)는 여전히 이 클래스 밖이라 랭킹 정산 화면 불변. */
.num__unit--spaced {
  margin-left: var(--space-1);
  white-space: nowrap;
}

/* 미확정 상태 (디자인 시스템 §5-8) — 값은 `—`, 링크는 pointer-events 차단.
   ※ .is-pending 을 품은 조상에 overflow(hidden/auto/scroll)를 걸면 인라인 테두리
     상자 위쪽이 잘려 "위가 열린 ⊐" 형태가 된다(v1.3 N-03). 조상 overflow 금지. */
.is-pending {
  display: inline;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  color: var(--color-text-muted);
  /* 점선 박스가 "미확정"이라는 상태를 전달하는 시각 단서이므로
     장식선 토큰(--color-border-strong)이 아니라 컨트롤 토큰을 쓴다 (§5-8) */
  border: 1px dashed var(--color-border-control);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-2);
  font-weight: var(--font-weight-regular);
  letter-spacing: normal;
}
.is-pending--block {
  display: block;
  padding: var(--space-4);
  line-height: var(--line-height-body);
}
a.is-pending {
  cursor: not-allowed;
  pointer-events: none;
  text-decoration: none;
}
/* 네이비 밴드 위에서는 muted 대비가 부족하므로 on-dark 토큰으로 교체 */
.on-dark .is-pending {
  color: var(--color-text-muted-on-dark);
  border-color: var(--color-border-on-dark);
}
.on-dark .num__unit { color: var(--color-text-muted-on-dark); }

/* ==========================================================================
   3) 공통 컴포넌트
   ========================================================================== */

/* --- 3-0. 스킵 링크 (두 페이지 공통, 포커스 시에만 노출) --------------- */

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-2);
  z-index: calc(var(--z-header) + 1);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-semibold);
  text-decoration: none;
  /* 포커스 전에는 화면 밖으로 밀어 둔다 (display:none 은 포커스를 못 받는다) */
  transform: translateY(calc(-100% - var(--space-4)));
  transition: transform var(--transition-fast);
}
.skip-link:focus-visible,
.skip-link:focus { transform: translateY(0); }

/* --- 3-1. 헤더 1행 (디자인 시스템 §5-3 / 레이아웃 §1) — ★ v2.8 전면 교체 ----
   2단(브랜드 바 + 사각 탭 바) → **1행**. 좌측 로고 락업(아이콘 + 워드마크), 우측 텍스트 내비 2항목.
   ~~`.brand-bar` · `.brand-bar__inner` · `.logo` · `.tabs-bar` · `.tabs` · `.tab`~~ **전부 삭제**
   (구 규격 원문은 레이아웃 §1-B 와 notes v2.25 에 보존 — 복원 지점은 그 두 곳이다).

   ★ **전 뷰포트 sticky 로 통일했다.** v2.7 이 2단으로 나눈 근거는 *"브랜드 바까지 붙이면
     모바일에서 96px 를 상시 점유해 20행 표 조회를 방해한다"* 였는데, 1행 헤더에서는 그 전제가
     사라진다 — 모바일 헤더 총높이가 **92px(44+48) → 64px** 로 줄기 때문이다. 상시 점유는
     48 → 64px 로 16px 늘지만 **전체 크롬은 28px 줄어든다.**
   ★ 활성 표시는 **색 + 굵기 둘 다**. 구 `.tab` 의 3중 표시(배경·색·상단 바)가 사라졌으므로
     굵기 변화를 생략하면 **색 단독 의존**이 되어 접근성 규칙 위반이다 — 취향이 아니다. */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--color-bg);
  /* ★ 시안(677)에는 이 선이 안 보인다 — 바로 아래가 다크 히어로라 눈에 띄지 않을 뿐이다.
     예시 데이터 배너(§3-2)나 밝은 섹션이 뒤따를 때는 반드시 필요하므로 유지한다. */
  border-bottom: 1px solid var(--color-border);
}
.site-header.is-scrolled { box-shadow: var(--shadow-sm); }

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;   /* 좌 락업은 컨테이너 좌단, 우 내비는 우단 (시안 실측 정렬) */
  height: var(--header-h);
}

/* 아이콘과 워드마크를 함께 감싼 **링크 하나**다. 둘을 별개 링크로 두면 같은 목적지로 가는
   링크가 나란히 둘이 되어 키보드 탐색이 한 번 더 걸린다. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-5);
  min-height: 44px;                 /* 터치 타깃 */
  text-decoration: none;
}
/* ★★ v2.26-1 — **정사각 전제를 걷었다 (리더 지시 7 · 아이콘 원본 수령)** ★★
   ~~width: var(--brandmark-size); height: var(--brandmark-size);~~
   종전 자산은 시안에서 뜯어낸 **정사각 크롭**(64×64)이라 두 축을 같은 값으로 묶어도
   왜곡이 없었다. 수령한 원본은 **167×180(비정방)** 이라 그 규칙을 그대로 두면
   가로가 7.2% 늘어나 **찌그러진 로고**가 나간다.
   → **높이를 기준으로 잡고 가로는 비율대로 따라오게** 한다(리더 지시 *"세로 기준 맞춤·
     가로 자동"*). 토큰(`--brandmark-size` 32/28)의 뜻이 *"정사각 변"* 에서 **"아이콘 높이"**
     로 바뀌었다 — 값은 그대로이고 계단(32/28)도 그대로다. designer 상신(§7 D-12).
   ★ `width: auto` 를 **명시**한다. 생략하면 `<img>` 의 `width` 속성(30)이 CSS 픽셀로
     그대로 먹어서, 모바일(28px 높이)에서 30×28 = **또 다른 비율**이 된다.
   ★ `flex: none` 은 그대로 — 좁은 폭에서 워드마크에 밀려 찌그러지지 않게 하는 장치다. */
.brand__mark {
  height: var(--brandmark-size);
  width: auto;
  flex: none;
}
.brand__word {
  color: var(--color-text);
  font-size: var(--font-size-h2);
  font-weight: var(--font-weight-black);
  letter-spacing: var(--letter-spacing-heading);
  white-space: nowrap;
}

.site-nav { display: flex; align-items: center; gap: var(--space-5); }

.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--color-text-muted);
  font-size: var(--font-size-h3);
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--transition-fast);
}
.site-nav__link:hover { color: var(--color-text); }
.site-nav__link.is-active {
  color: var(--color-text);
  font-weight: var(--font-weight-bold);   /* 색 단독 의존 금지 — 접근성 요건 */
}
/* ★★ v2.38 — 현재 페이지 탭 밑줄 (사용자 직접 지시 2026-08-14 · 항목 4) ★★
   지시 원문: *"OnTact Auto Buyback / 판매자 랭킹 페이지 구분할 수 있도록 아래 밑줄 그어주기"*
   ★ 선택자는 `[aria-current="page"]` — 상태의 원천이 클래스가 아니라 **접근성 계약**이다.
     두 원본 페이지는 마크업이 이 속성을 직접 갖고(활성 상태 JS 판별 금지 규약), 단일 파일
     사본은 뷰 전환 스크립트가 `is-active` 와 함께 이 속성을 토글하므로(생성기 TABS_JS)
     양쪽 다 자동으로 맞는다 — 생성기 상수(TAB_OLD/TAB_NEW) 무변.
   ★ 색은 --color-brand — 토큰 정의가 이 용도(*"탭 활성 상단 바"*)를 이미 지목하고 있고,
     밑줄은 비텍스트 표지라 3:1 기준 대상(흰 배경 3.87:1 ✓ · WCAG 1.4.11)이다.
   ★ 두께 2px 는 전용 토큰이 없어 --space-1 파생(calc ÷2)으로 임시 처리 — §7 「토큰 추가
     대기」 규약 그대로다(notes §7 D-31 · designer 정식 등재 요망).
   ★ 호버(색만 진해짐)와 활성(굵기 + 밑줄)이 서로 다른 신호라 구분된다 — 호버에 밑줄을
     주지 않는 것이 그 구분의 나머지 반이다.
   ★★ v2.45-B — 선언 형태를 **shorthand 한 줄**로 교체 (사양 §5 명시) ★★
     사양 원문: *"밑줄은 shorthand 한 줄에 같이 지정할 것. 상태에 따라 text-decoration
     만 바꾸면 색이 currentColor(검정)로 초기화된다. 프로토타입에서 실제로 만난 버그다."*
     — v2.38 의 longhand 4줄도 그 함정은 피하고 있었으나(부분 속성만 선언), 사양이
     형태 자체를 못박았으므로 따른다. **값은 전부 동일**하다(선·스타일·색·두께·오프셋 —
     사양 §5 의 #2F80ED = --color-brand · 2px = --space-1 파생 · offset 4px):
     ~~text-decoration-line: underline;~~
     ~~text-decoration-color: var(--color-brand);~~
     ~~text-decoration-thickness: calc(var(--space-1) / 2);~~
     활성 글자색 #16202E/700 · 비활성 #5B6980/500(사양 §5)은 기존 `.is-active`(--color-text
     + bold)·기본형(muted + medium) 규칙이 이미 그 값이다 — 재선언 0. */
.site-nav__link[aria-current="page"] {
  text-decoration: underline solid var(--color-brand) calc(var(--space-1) / 2);  /* 사양 §5 — 한 줄 shorthand (2px 토큰 파생) */
  text-underline-offset: var(--space-1);                /* 4px — 글자와 밑줄 사이 */
}

.site-nav__sep { width: 1px; height: 16px; background: var(--color-border); flex: none; }

/* --- 3-1-b. ★★ v2.45-B — KOR/EN 언어 토글 (사용자 지시 2026-09-29 · 사양 §3) --------
   위치·마크업은 두 페이지 헤더 내비 끝(구분선 뒤) — index.html 그 자리 주석 1벌 참조.
   · pill 컨테이너: padding 3 · 1px --color-border · radius 999 · 배경 --color-bg-alt
     (사양 수치·색 그대로 — 3px 는 4px 배수 밖의 사양 확정치라 리터럴 · tokens v2.45-B 주석).
   · 버튼: 데스크톱 높이 32 · padding 0 12(--space-3) · 14px(--font-size-lang)/700.
     모바일(<768)은 §6-0 블록에서 높이 28 · padding 0 7 로 계단(폰트는 토큰이 12px 로
     내려간다 — ⚠ 캡션 하한 충돌 상신은 tokens 주석 1벌).
   · 상태는 `aria-pressed` 하나 — 선택: --color-primary 면 + 흰 글자(5.24:1 ✓) /
     비선택: 투명 + --color-text-muted(--color-bg-alt 위 4.51:1 ✓). 상태 클래스를 따로
     만들지 않는 것은 기간 토글(§3-7)과 같은 규약이다.
   · ⚠ 버튼 높이 32/28 은 터치 타깃 44 미달 — **사양 §3 이 높이를 못박아** 그대로 싣고
     미달 사실은 designer 판정으로 상신(notes §7 D-37 · pill 전체가 실질 타깃이라 완화). */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  padding: 3px;                              /* 사양 §3 확정치 */
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-alt);
  flex: none;
}
.lang-toggle__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;                              /* 사양 §3 데스크톱 — <768 은 §6-0 에서 28 */
  padding: 0 var(--space-3);
  border: 0;
  background: transparent;
  border-radius: var(--radius-full);
  color: var(--color-text-muted);
  font-size: var(--font-size-lang);
  font-weight: var(--font-weight-bold);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.lang-toggle__btn[aria-pressed="true"] {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

/* --- 3-2. 예시 데이터 고지 배너 (디자인 시스템 §5-17 / 레이아웃 §1-A) ------
   ★ v2.8 **복원·정식 등재** (리더 판정 C-5). v2.18 에서 사용자 지시로 걷어냈던 규칙 3벌을
   되살리되, **v2.8 규격으로 갱신**했다 — 구 원문(D142)은 배지(`.badge--pending`, 높이 24px)를
   썼으나 시안 실측 밴드가 **44.4px** 라 배지로는 48px 가 되어 맞지 않는다. §5-17 이 지정한
   대로 **라벨 span + caption 2종 + baseline 정렬**로 재작성한다.

   ★ **베이지를 위한 새 토큰을 만들지 않는다** — `--color-pending` 계열은 이 사이트에서
     "주의·대기"를 뜻하도록 이미 굳어 있고, 예시 데이터는 정확히 그 부류다.
     시안 실측 필 `#FBF0E4` ↔ `--color-pending-bg` `#FDF1E3` (채널당 ≤2 = 스크린샷 필터 오차).
   ★ 전폭이다 — 컨테이너 밖에서 배경이 끝까지 가고, 내부만 `.container--max` 로 잡는다.
   ★ **스티키가 아니다.** 헤더만 sticky 이고 배너는 스크롤과 함께 올라간다 — 상시 점유를
     44px 더 늘리면 20행 표 조회를 방해한다(§1 sticky 예산과 같은 판단). */

.mock-banner {
  background: var(--color-pending-bg);
  border-bottom: 1px solid var(--color-border);
}
/* ★ `[hidden]` 재선언 — §5-6 의 `[hidden]` 무력화 함정. 이 블록이 `display` 를 선언하는
   자식(`__inner` flex)을 갖고, 배너 자체도 JS 가 `hidden` 으로 끄는 요소다. 재선언을
   빠뜨리면 *"필요 없을 때 끈다"* 는 규칙이 조용히 깨져 고지가 영구히 남는다. */
.mock-banner[hidden] { display: none; }

.mock-banner__inner {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  padding-block: var(--space-3);      /* 12px → 밴드 총 약 44px (시안 실측 44.4px) */
}
.mock-banner__label {
  flex: none;
  color: var(--color-pending);        /* tint 위 5.52 ✓ (§1-3 20행) */
  font-size: var(--font-size-caption);
  font-weight: var(--font-weight-bold);
  /* ★ v2.25-1 (QA 20차 W20-2) — 밴드가 **46.44px** 로 명세 44px·시안 실측 44.4px 를 +2.04 넘었다.
     원인은 padding 이 아니라 **이 라벨이 line-height 를 선언하지 않아 본문 기본값(1.65)을
     상속**한 것이다(13 × 1.65 = 21.45). 바로 옆 형제 `__text` 는 `--line-height-snug` 라
     **같은 caption 두 개가 서로 다른 행높이**를 갖고 있었고, 큰 쪽이 밴드 높이를 정했다.
     → 형제와 같은 토큰으로 맞춘다: 13 × 1.4 = 18.2 → 밴드 **43.2px**.
     ★ QA 대안이던 `padding-block: 11px` 는 채택하지 않았다 — 44.44px 로 시안에 더 가깝지만
       **4px 스케일 밖의 리터럴**이라 토큰 규율을 깨고, 형제 간 행높이 불일치도 그대로 남는다.
       ±1px 를 맞추려고 토큰 체계를 깨는 교환은 맞지 않는다(고지 밴드이고 옆에 비교 대상이 없다).
     ⚠ 남은 편차 **−1.2px**(43.2 vs 44)는 스펙 수치 쪽 정정을 designer 에 상신했다(notes §7 D-4). */
  line-height: var(--line-height-snug);
}
.mock-banner__text {
  margin: 0;
  color: var(--color-text);           /* pending-bg 위 대비 여유 큼 */
  font-size: var(--font-size-caption);
  line-height: var(--line-height-snug);
}

/* --- 3-3. 버튼 (디자인 시스템 §5-1) ------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 48px;
  padding-inline: var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

.btn--primary   { background: var(--color-primary); color: var(--color-on-primary); }
.btn--primary:hover { background: var(--color-primary-dark); }

.btn--secondary { background: transparent; color: var(--color-primary); border-color: var(--color-primary); }
.btn--secondary:hover { background: var(--color-primary-tint); }

.btn--on-dark   { background: var(--color-on-primary); color: var(--color-primary); }
.btn--on-dark:hover { background: var(--color-primary-tint); }

.btn--outline-on-dark { background: transparent; color: var(--color-text-on-dark); border-color: var(--color-text-on-dark); }
.btn--outline-on-dark:hover { background: var(--color-surface-on-dark-hover); }

.btn--ghost { background: transparent; color: var(--color-text-muted); border-color: var(--color-border-control); }
.btn--ghost:hover { background: var(--color-bg-alt); color: var(--color-text); }

.btn--sm { height: 40px; padding-inline: var(--space-4); font-size: var(--font-size-small); }
/* 소형 버튼이 단독 터치 타깃일 때 히트 영역 44px 확보 */
.btn--sm.btn--touch { position: relative; }
.btn--sm.btn--touch::after {
  content: "";
  position: absolute;
  inset: -2px 0;
  min-height: 44px;
}

.icon { flex: 0 0 auto; }

/* --- 3-4. 배지 / 칩 / 순위 뱃지 ---------------------------------------
   다크 밴드 위 배지 변형은 참조가 사라져(설명 섹션 4개 이관) 함께 삭제했다.
   칩(.chip--on-dark)은 히어로에서 계속 쓰이므로 남는다. */

.badge {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding-inline: var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--font-size-caption);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--letter-spacing-label);
  line-height: 1;
  white-space: nowrap;
}
.badge--success { background: var(--color-success-bg); color: var(--color-success); }
.badge--pending { background: var(--color-pending-bg); color: var(--color-pending); }
.badge--info    { background: var(--color-info-bg);    color: var(--color-info); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 32px;
  padding: var(--space-1) var(--space-4);
  border-radius: var(--radius-full);
  font-size: var(--font-size-small);
  line-height: var(--line-height-snug);
}
.chip--on-dark { background: var(--color-surface-on-dark); color: var(--color-text-on-dark); }
.chip__label { color: var(--color-text-muted-on-dark); }

/* --- .chip--info — **밝은 배경용 칩** (v2.24-1 신설 · designer v2.7 §4 ② 판정 B) -----
   계기: 히어로에 있던 기간 배지 칩 묶음이 **정산 패널(`#top20-list`)로 이관**되면서
   다크 밴드를 떠났다. `.chip--on-dark` 는 네이비 위 전제(`--color-surface-on-dark`
   배경 + 흰 글자)라 흰 패널 위에서는 **칩이 배경에 녹고 글자가 날아간다.**

   ★ **신규 색이 아니다.** `.badge--info` 가 이미 쓰던 검증된 조합(§3-4 바로 위 줄)을
     칩 치수에 그대로 얹었다 — 신규 토큰 0. 두 줄이 같은 토큰 쌍을 쓰므로 색을 고칠 때
     배지와 칩이 함께 움직인다(갈라지지 않는다).
   ★ 대비 실측: 본문 `--color-info` #1155B8 on `--color-info-bg` #E8F0FE = **6.08:1** ✓
                라벨 `--color-text-muted` #5B6980 on 같은 배경    = **4.85:1** ✓
     (둘 다 AA 4.5:1 통과. designer 기재값과 일치.)
   ★ **치수·radius·자수 계약은 §5-6 `.chip` 공용 규격 그대로**다 — 이 변형이 더하는 것은
     색 두 쌍뿐이고 칩의 크기·모양은 한 값도 건드리지 않는다.
   ⚠ `.chip__label` 재정의가 **반드시 따라와야 한다.** 위 공용 `.chip__label` 은
     `--color-text-muted-on-dark`(#A9B6C9)를 물고 있어 이 밝은 틴트 위에서 **1.9:1** 로
     무너진다. 지금은 라벨을 가진 칩 3개가 전부 `hidden`(기간 메타 미도착 · A-9)이라
     **화면에서 보이지 않지만**, 메타가 도착하는 순간 세 칩이 동시에 뜬다 —
     그때 발견되는 대비 결함이라 **지금 함께 넣는다.** 색 규칙을 나중에 붙이면
     "칩은 옮겼는데 라벨만 안 보인다"가 된다. */
.chip--info { background: var(--color-info-bg); color: var(--color-info); }
.chip--info .chip__label { color: var(--color-text-muted); }
/* 정책 서술층(ranking ② ⓐ) — 라벨+값 구조가 아니라 문장 하나다.
   좁은 폭에서 줄바꿈되더라도 칩 밖으로 넘치지 않도록 폭 상한을 건다. */
.chip--policy { max-width: 100%; text-align: center; }

/* ★ .chip / .badge 는 display:inline-flex 라 UA 기본 `[hidden]{display:none}` 을 덮어쓴다.
   이 두 줄이 없으면 "값이 없으면 `—` 대신 요소를 숨긴다"는 규칙(writer §6 #28)과
   "입도 판정 불가 시 칩을 숨긴다"(격차 c)가 **조용히 깨진다**. .slim-link 와 같은 함정이다. */
.chip[hidden]  { display: none; }
.badge[hidden] { display: none; }

/* 순위 뱃지 — 1~3위에 --color-brand 를 쓰지 않는다. brand 면 위 흰 글자는
   Large Text 예외에 기대야만 통과하는 조합이라 순위 뱃지에는 쓰지 않는다(§1-3 22행).
   ★★ v2.26 — **1·2·3 을 서로 다른 3색으로 칠한다** (사용자 직접 지시 ③ · 2026-08-12).
     ~~--color-primary(5.24) / 1위만 --color-primary-dark(6.96) — 같은 hue 의 ordinal
       한 단계다. 1·2·3 을 서로 다른 3색으로 칠하면 그것이 곧 메달 은유다(§5-6).~~
     그 규칙이 금지하던 **메달 은유가 이번 지시의 내용**이다. 위 문장은 무엇이 뒤집혔는지
     남기기 위해 취소선으로 보존한다 — 되돌릴 때 근거를 다시 찾을 필요가 없게.
     대비 실측 3행과 무효 판정 목록은 `css/tokens.css` 메달 토큰 블록에 있다.
   ★ **Large Text 예외에 기대지 않는다는 원칙은 그대로다** — 메달 3색은 전부
     --color-text 기준 4.5:1 을 넘는다(8.80 / 10.38 / 5.22). 원칙이 살아 있으므로
     위 첫 문장(brand 면 배제)도 여전히 유효하다. */
.rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 32px; height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-bg-alt);
  color: var(--color-text);
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-black);
}
/* 1~3위 (v2.2 상향): 40px + 20px 숫자.
   ★ 숫자 크기는 반드시 --font-size-step 을 쓴다. --font-size-h3 참조 금지 —
     h3 는 <768px 에서 18px 로 줄어 Large Text 임계(18.66px)를 0.66px 밑돌고
     그 뷰포트에서만 조용히 대비가 깨진다(QA F-01 과 동일 함정).
     --font-size-step 은 미디어 쿼리 재정의가 없는 고정 토큰이다. */
.rank-badge--top {
  width: 40px; height: 40px;
  /* v2.26 — 면 색은 아래 메달 3종이 각각 정한다. 이 규칙은 **치수만** 소유한다.
     ~~background: var(--color-primary); color: var(--color-on-primary);~~ */
  color: var(--color-text);
  font-size: var(--font-size-step);
}
/* ~~.rank-badge--first~~ **v2.26 폐기** — `1위만 한 단계 진하게` 가 메달 3색으로
   대체됐다. 클래스를 남겨 두지 않는다: 남기면 어느 것이 1위 색인지 두 곳이 말하게 되고,
   `--first` 와 `--gold` 가 동시에 붙은 뱃지에서 나중 규칙이 이기는 조용한 사고가 난다.
   (되살릴 일이 생기면 `background: var(--color-primary-dark)` 한 줄이다.)

   ★ 메달 3색 — 전경은 셋 다 --color-text(위 `.rank-badge--top` 이 소유). 면만 갈린다.
     대비 8.80 / 10.38 / 5.22 — 전부 일반 텍스트 4.5:1 통과(tokens.css 실측 블록).
   ★ 색이 정보를 단독으로 지지 않는다: 뱃지 **안에 순위 숫자가 인쇄**돼 있고 행마다
     sr-only `상위 3위 이내` 가 붙는다(WCAG 1.4.1). */
.rank-badge--gold   { background: var(--color-medal-gold); }
.rank-badge--silver { background: var(--color-medal-silver); }
.rank-badge--bronze { background: var(--color-medal-bronze); }

/* --- 3-5. 카드 / 지표 타일 ------------------------------------------- */

.card {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}

/* ★★★ v2.35 — 스탯 타일 라벨 승격 (사용자 직접 지시 2026-08-13 · A6) ★★★
   지시 원문: *"스탯 타일 라벨(누적 매출·누적 바이백 금액·누적 바이백 수량·평균 매수
   체결가) 텍스트 수정: ① 사이즈 크기 키우기 ② 두껍게 변경 ③ 색 변경(건별 바이백
   내역의 파란색으로 변경)"*
   · ① 크기: ~~--font-size-small(14px)~~ → **--font-size-body(16px)** — 값(24~30px)과의
     위계를 지키는 선에서 한 단계. 18px(body-lg)는 캡션·값 사이에서 라벨이 값과 다투기
     시작해 채택하지 않았다(정도 판단은 builder — designer 검토 상신 notes §7 D-28).
   · ② 굵기: ~~medium(500)~~ → **bold(700)**.
   · ③ 색: *"건별 바이백 내역의 파란색"* = 건별 표 열 머리(`.data-table thead th`)가 쓰는
     **--color-primary** 그대로 재사용 — 신규 리터럴 0. 흰 카드 위 5.24:1 ✓ (§1-3 35행 ·
     16px 일반 텍스트 AA 통과 — Large Text 예외에 기대지 않는다).
   ⚠ 시안 Frame 39827 의 파랑 채움 타일 1개(라벨·값 반전)는 **채택하지 않았다** — 같은
     라벨(`누적 바이백 수량`)이 시안에 두 번 있어 시안 오류로 판단, 상신만(notes §7 D-28). */
.stat__label {
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-bold);
  color: var(--color-primary);
  white-space: nowrap;
}
/* ★★ v2.38 — 강조 타일 라벨 왼쪽 온택트 심볼 (사용자 직접 지시 2026-08-14 · 항목 1) ★★
   사용처는 index ③-a 강조 타일(`.stat--highlight`) 라벨 안 1곳이다. 크기(20×20)는 CSS 가
   아니라 img width/height **속성**이 소유한다(CLS 방지 · CSS 리터럴 최소화) — 여기서는
   줄 맞춤과 간격만 준다. 자산 선택(엠블럼 파생 · 파란 면 시인성 실측)은 index.html 그 자리
   주석과 notes §4-av D255. 20px 는 라벨 줄 상자(16px × 1.65 = 26.4px) 안이라 라벨 행
   높이가 변하지 않는다 — 다른 타일과의 정렬 기선 유지 근거. */
.stat__label-mark {
  vertical-align: middle;               /* 기선 정렬은 아이콘 하단이 들려 보인다 */
  margin-inline-end: var(--space-2);
  /* 20px 아이콘의 마진 상자를 16px 로 줄여 줄 상자 성장을 막는다 — 실렌더에서 강조
     타일 라벨만 1px 크던 것(21 vs 20)을 이 상쇄가 0px 차로 되돌렸다(§4-av D255 실측).
     음수 마진은 시각 크기를 바꾸지 않는다 — 줄 높이 계산에서만 빠진다. */
  margin-block: calc(var(--space-1) / -2);
}
.stat__value {
  margin-top: var(--space-2);
  color: var(--color-text);
  /* overflow 를 걸지 않는다 (visible 유지) — CSS Overflow 3상 한 축에 auto 를 주면
     다른 축의 visible 이 auto 로 계산되어 세로 클리핑을 끌 수 없고,
     인라인인 .is-pending 의 테두리 상자가 줄 상자보다 커서 점선 위 2px 가 잘린다.
     안전망 역할은 QA 단언(계단 적용 후 넘침 0)으로 이관했다(v1.3 N-03). */
  min-width: 0;
}
/* 값 + 단위는 한 요소로 묶어 한 줄을 유지한다 — 단위 `원`만 다음 줄로 떨어지지 않게 */
.stat__figure { display: inline-block; white-space: nowrap; }
/* 미확정 타일(`—`)도 확정 타일과 값 행 높이가 같아야 한다(QA N-01).
   .is-pending 은 .num 계열이 아니라 --line-height-num 을 상속받지 못한다. */
.stat__value .is-pending {
  font-size: var(--font-size-stat);
  line-height: var(--line-height-num);
}
.stat__caption {
  margin-top: var(--space-2);
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
}

/* ★★★ v2.36 — 강조 타일 (사용자 직접 지시 2026-08-13 저녁 · 시안 39827 파랑 타일) ★★★
   지시 원문: *"누적 바이백 수량은 색을 입혀 강조되게(#0059FF)"*
   · 값은 신설 토큰 `--color-stat-highlight` 경유 — 하드코딩 금지. 값 근거(지시 명기 +
     시안 실측 일치)와 흰 텍스트 대비 검산 **5.42:1**(라벨 16px/700 ✓ · 값 ✓ · 캡션
     13px ✓ — 일반 텍스트 4.5:1 기준)은 tokens.css 그 자리 주석에 1벌.
   · 전경은 전부 `--color-on-primary`(#FFF) — "primary/brand 배경 위 텍스트" 토큰의
     용도 그대로다(강조 파랑도 브랜드 계열 채움면). 전용 전경 토큰을 만들지 않은 이유는
     메달색 주석과 같다: 값이 같으면 토큰이 아니다.
   · border 를 배경과 같은 토큰으로 채운다 — .card 의 회색 1px 테두리가 파랑 면 둘레에
     남으면 흰 페이지 배경 위에서 이물선이 된다(시안 타일은 무테두리로 보인다).
   · v2.35 라벨 승격(16px/700)·계단 폰트 스케일(`--font-size-stat` 계열)·`applyStatScale`
     은 **무변경** — 이 블록은 색만 바꾼다. `.is-pending`(—)·`.num__frac`·`.num__unit` 도
     흰 카드용 색이 명시돼 있어 여기서 함께 반전한다(하나라도 빠지면 파랑 위 회색 잔재).
   ⚠ D-28(시안 파랑 타일 미채택 상신)은 이 지시로 **종결** — 채움 변형이 실제 의도였다. */
/* ★ v2.45 — .stat--highlight 도 **사문**(1b 강조 타일은 §3-5-c .stat1b-card--qty 가
   같은 토큰(--color-stat-highlight)으로 승계). 보존 사유는 §3-5-b v2.45 배너와 같다. */
.stat--highlight {
  background: var(--color-stat-highlight);
  border-color: var(--color-stat-highlight);
}
.stat--highlight .stat__label,
.stat--highlight .stat__value,
.stat--highlight .stat__caption,
.stat--highlight .num__frac,
.stat--highlight .num__unit {
  color: var(--color-on-primary);
}
.stat--highlight .stat__value .is-pending {
  color: var(--color-on-primary);
  /* 점선도 흰색 — 파랑 면 위에서 --color-border-control(회청)은 1.9:1 로 가라앉는다 */
  border-color: var(--color-on-primary);
}

/* --- 3-5-b. ★★★ v2.39 — 누적 락업·소각 파생 카드 + 화살표 커넥터 ★★★ ----------
   ★★★ v2.45 — 이 블록 전체 **사문** (현황 1b 재구축 · 사용자 지시 2026-09-29) ★★★
   1b 마크업은 .stat-flow/.stat-derived 를 쓰지 않는다(신 소유자는 §3-5-c 의
   .stat1b-flow/.stat1b-derived — 구 마크업 원문은 notes §4-bd D287). 규칙을 지우지
   않는 이유는 .mock-banner 전례 그대로 — 스트립형 화면 복원이 마크업 되돌리기로
   끝나야 한다. 아래 원문(v2.39~v2.40 실측·유도식 포함)은 그 복원의 정본이다. ------- */
   (사용자 직접 지시 2026-08-14: *"누적 락업과 소각이라는 부분이 새로 생겨 추가로 해주고
   페이지 디자인 파일 첨부하였으니 확인 후 작업"* · 시안 = Frame 39827 갱신본의 파란
   화살표 2갈래 + 카드 시안 Group 40893(소각)/40894(누적 락업) — 셋 다 00_input 보존)

   ── 카드 (.stat-derived) ──────────────────────────────────────────────────
   · **전용 타이포를 만들지 않았다** — ranking 총액 카드(D118)와 같은 판단: 마크업이
     ③-a 지표 타일과 같은 `.card` + `.stat__*` 라 라벨·값·캡션의 크기·색·간격 전부
     §3-5 공용 규칙에서 온다. 카드 시안 대조: 테두리 회색·radius(1800px 폭 66px ≈ 웹
     환산 16~21px = --radius-lg)·값 큰 정수부+작은 소수부·회색 캡션 — 전부 기존 `.card`/
     `.num--stat`/`.num__frac` 표현 그대로라 **이 블록의 신규 선언은 배치(그리드)뿐**이다.
   · ⚠ 라벨 파랑 — 시안 실측 **#0085FF** 는 흰 카드 위 **3.62:1** 로 16px 일반 텍스트
     AA(4.5:1) 미달이라 채택하지 않고, 기존 `.stat__label` 의 --color-primary(5.24:1 ✓ ·
     v2.35 승격분)를 그대로 상속받는다 — "시안의 파란 라벨 스타일"의 재현이면서 검증
     조합이다(값 간극은 designer 상신 · notes §7 D-34).
   · 그리드 — <768: 1열(타일과 같은 스택) / ≥768: 2열 한 행 / ≥1280: ~~**4열 그리드의
     3·4열**에 앵커(시안 배치 — 카드 2장이 전폭이 아니라 강조 타일 축 아래 우측 정렬로
     선다. 실측: 우측 화살표가 강조 타일(4열) 중심 바로 아래, 카드 폭 ≈ 타일 폭).
     타일과 같은 폭이 되므로 값 계단(§2-5)의 폭 전제(≥1280 내부폭 232px)도 그대로 성립.~~
     → ★★ v2.40 — **우측 정렬 2열 · 카드 폭 26.75%**(사용자 직접 지시 2026-08-14 오후:
     *"누적 락업과 소각 부분 디자인 이미지와 동일하게 옆으로 좀 더 넒게 잡아주고"*).
     v2.39 의 "카드 폭 ≈ 타일 폭" 은 **카드 시안이 프레임과 같은 축척임을 확인하기 전의
     근사**였다 — 재실측(카드 시안 Group 40894/40893 큰 0 글리프 114px ↔ 프레임 타일의
     같은 글리프 116px = **동일 축척**)으로 카드 폭 = 1800fpx, 타일 폭 = 1582.5fpx,
     컨테이너 내부 = 6728fpx 가 확정됐다. 1800/6728 = **26.75%**(1200px 컨테이너에서
     321px — 타일 282px 보다 13.7% 넓다). 트랙을 %로 앵커하는 이유: 시안의 원천 치수가
     "컨테이너 대비 비례"라 gutter 파생 4열 트랙으로는 표현할 수 없다(§3-13-b 180px·622px
     와 같은 도형·배치 치수 — 색·폰트·간격 토큰 규칙의 대상이 아니다). 우측 끝 정렬은
     시안 그대로(우측 카드 우변 = 타일 행 우변 = 컨테이너 우변 · justify-content: end).
     카드 사이 간격은 --grid-gutter 유지(시안 실측 ≈27px — 열 중심 오차 3.4px 이내라
     토큰 24px 를 쓴다 · 전용 리터럴을 만들 만큼의 차이가 아니다).
     값 계단(§2-5) 폭 전제는 **더 여유**가 생겼다(내부폭 232px → 271px = 321 − 패딩 48 −
     테두리 2).
   · 값 크기 계단 — 스트립과 **같은 판정을 나눠 받는다**(`js/buyback.js rescaleStats()` 가
     두 컨테이너에 같은 단계를 건다). 별도 판정을 두면 스트립 24px 옆에서 파생 카드만
     30px 로 서는 순간이 생긴다 — 같은 밴드의 수치는 한 계단을 쓴다(§2-5 원칙 그대로).
   · 로딩 — 스트립과 같은 `.is-swapping` 규칙(§4.2 로딩 UX · 값 원천이 같은 구간 응답이라
     디밍 시점도 같아야 한다).

   ── 화살표 커넥터 (.stat-flow) ────────────────────────────────────────────
   · 구조: 강조 타일 중심에서 내려오는 **줄기(stem)** → **가로 분기 바(bar)** → 카드
     2장 중심으로 떨어지는 **화살 2개(drop + ::after 삼각촉)**. 이미지가 아니라 CSS 면
     (background/border)이다 — 색은 --color-stat-highlight **토큰 경유**(시안 화살표
     실측 #0059FF 가 강조 타일 배경 토큰과 **정확히 같은 값** — 신규 토큰 0).
   · 좌표 — 그리드 열 중심은 gutter 때문에 순수 %가 아니다. 4열: 열폭 c=(W-3g)/4,
     4열 중심 = 3.5c+3g = **87.5% + 0.375g** · 3열 중심 = **62.5% + 0.125g**.
     2열(768~1279): 2열 중심 = **75% + 0.25g** · 1열 중심 = **25% − 0.25g**.
     전부 calc + var(--grid-gutter) 파생이라 gutter 토큰이 바뀌어도 따라온다.
   · 치수 리터럴(선 2px · 촉 10×7px · 줄기 20px)은 시안 실측 환산(선 ≈12px/5.6 ≈ 2.1 ·
     촉 ≈60px/5.6 ≈ 10.7)이며 색·폰트·간격 토큰 규칙의 대상이 아닌 **도형 치수**다
     (§3-13-b 180px·622px 와 같은 성격).
   · **반응형 방침(360px)** — <768 은 전부 1열 스택이라 분기 기하가 성립하지 않는다
     (강조 타일 바로 아래 카드가 순서대로 온다). 2갈래를 세로로 흉내내면 소음이라
     **가운데 화살 1개**로 축약한다(줄기·바·좌측 화살 display:none) — "강조 타일에서
     파생된다"는 관계 표시는 유지되고, 어느 카드로 가는지는 캡션 문안(*"OnTact 바이백
     수량 중 …"*)이 텍스트로 이미 진다. designer 검토 상신(notes §7 D-34).
   · 순수 장식 — 마크업에 aria-hidden="true"(관계 서술은 캡션 몫 · 낭독 경로에 화살표
     도형이 낄 이유가 없다). 포커스 대상 아님.
   · ⚠ 비텍스트 3:1 대상이 아니다 — 화살표는 캡션이 이미 지는 관계의 **보조 시각화**라
     색 단독 전달자가 아니다(§1-3 메달색 주석과 같은 판정. 흰 배경 위 5.42:1 이라
     실제로는 여유가 크다). */
.stat-flow { position: relative; height: var(--space-8); }
.stat-flow__stem,
.stat-flow__bar,
.stat-flow__drop--l { display: none; }   /* <768 — 가운데 화살 1개 방침(위 주석) */
.stat-flow__drop {
  position: absolute;
  top: 0;
  bottom: 7px;                            /* 촉(7px)이 설 자리 */
  width: 2px;
  left: 50%;
  margin-left: -1px;
  background: var(--color-stat-highlight);
}
.stat-flow__drop::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 7px solid var(--color-stat-highlight);
}
.stat-derived {
  display: grid;
  grid-template-columns: minmax(0, 1fr);  /* minmax 근거는 .stat-strip 주석과 동일 */
  gap: var(--grid-gutter);
  margin-top: var(--space-4);
  transition: opacity var(--transition-fast);
}
.stat-derived.is-swapping { opacity: .4; }
/* 값 크기 계단 — 스트립(.stat-strip--s2/--s3)과 같은 토큰 치환을 파생 카드 컨테이너에도
   건다. 클래스를 나눈 이유: `.stat-strip--s2` 를 이 ul 에 그대로 붙이면 동작은 하지만
   "다른 블록의 수식어"라 다음 개정에서 스트립 쪽 규칙 정리에 함께 쓸려 나간다(BEM 규약). */
.stat-derived--s2 { --font-size-stat: var(--font-size-stat-2); }
.stat-derived--s3 { --font-size-stat: var(--font-size-stat-3); }
/* ≥768 — 분기 기하 성립 구간. 국소 미디어쿼리인 이유는 §3-13 v2.36 층과 같다:
   줄기·바·화살·카드 열이 한 덩어리의 시안 재현 단위라 §6 블록으로 흩으면 따로 움직인다.
   ★ v2.40 — 폭 확장 지시(≥1280 26.75% · 아래 주석)에서 이 구간(768~1279)은 **무변**이다:
     2열 한 행에서 카드는 이미 컨테이너의 ≈48% = 시안 비례(26.75%)를 **초과**해 "타일보다
     넓게" 취지가 충족돼 있고, 더 넓히면 두 장 한 행이 깨져 분기 커넥터의 기하 자체가
     무너진다(<768 화살 1개 축약과 같은 판단 축 — 이 구간의 시안은 없고 취지 해석이다.
     designer 검토 상신은 D-34 추기에 병합). <768 1열 스택도 같은 이유로 무변. */
@media (min-width: 768px) {
  .stat-flow { height: var(--space-12); }
  .stat-flow__stem,
  .stat-flow__bar,
  .stat-flow__drop--l { display: block; }
  .stat-flow__stem {
    position: absolute;
    top: 0;
    height: 20px;
    width: 2px;
    left: calc(75% + var(--grid-gutter) * 0.25);      /* 2×2 그리드 — 강조 타일(2행 2열) 중심 */
    margin-left: -1px;
    background: var(--color-stat-highlight);
  }
  .stat-flow__bar {
    position: absolute;
    top: 20px;
    height: 2px;
    left: calc(25% - var(--grid-gutter) * 0.25);      /* 좌측 화살 x 까지 */
    right: calc(25% - var(--grid-gutter) * 0.25);     /* = 100% − 줄기 x */
    background: var(--color-stat-highlight);
  }
  .stat-flow__drop { top: 20px; }                     /* 바 아래에서 시작 */
  .stat-flow__drop--l { left: calc(25% - var(--grid-gutter) * 0.25); }
  .stat-flow__drop--r { left: calc(75% + var(--grid-gutter) * 0.25); }
  .stat-derived { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ≥1280 — 스트립이 4열이 되며 강조 타일이 4열로 이동.
   ★★ v2.40 — 카드는 ~~3·4열 앵커~~ → **우측 정렬 2열 · 폭 26.75%**(시안 재실측 —
   근거·환산은 위 카드 그리드 주석 v2.40 층 1벌).
   ~~.stat-derived { grid-template-columns: repeat(4, minmax(0, 1fr)); }
   .stat-derived > li:nth-child(1) { grid-column: 3; }
   .stat-derived > li:nth-child(2) { grid-column: 4; }~~ (v2.39 원문 — 열 앵커는 트랙이
   2개가 되며 소멸했다. 되살릴 일이 생기면 위 v2.40 층의 취소선 원문이 아니라 **시안을
   다시 실측**할 것 — 이 좌표는 전부 실측 파생이다.)
   ── 커넥터 좌표 재계산 ──
   · 줄기·우측 화살 = 강조 타일(4열) 중심 그대로 **87.5% + 0.375g** (무변 — 시안도
     화살이 카드 중심이 아니라 **타일 축에서 수직 낙하**한다. 프레임 실측: 우측 화살
     7879fpx ↔ 우측 카드 중심 7783fpx = 카드 중심에서 17px(웹) 우측 — 시안 스스로
     오프센터라 카드 중심으로 "고치지" 않는다).
   · 좌측 화살 = **좌측 카드 중심** = 100% − 1.5w − g (w=26.75% → **59.875% − g**).
     1200px 검산: 718.5 − 24 = 694.5px ↔ 프레임 실측 691.1px (오차 3.4px = gutter 를
     시안 ≈27px 대신 토큰 24px 로 쓴 데서 온다 · 위 주석).
   · 바 우변 = 100% − 줄기 x = **12.5% − 0.375g** (무변). */
@media (min-width: 1280px) {
  .stat-flow__stem,
  .stat-flow__drop--r { left: calc(87.5% + var(--grid-gutter) * 0.375); }
  .stat-flow__bar {
    left: calc(59.875% - var(--grid-gutter));
    right: calc(12.5% - var(--grid-gutter) * 0.375);
  }
  .stat-flow__drop--l { left: calc(59.875% - var(--grid-gutter)); }
  .stat-derived {
    grid-template-columns: repeat(2, 26.75%);
    justify-content: end;
  }
}

/* --- 3-5-c. ★★★ v2.45 — 현황 1b 재구축 (사용자 지시 2026-09-29 · 전면 수정안) -----
   지시 원문: *"바이백 페이지 전면 수정안임 확인"* — 사양 정본 handoff-v245 §1(데스크톱
   1b) · §2(모바일 1b-m) · 디자인 토큰 절. 신규 값의 토큰 등재·대비 검산·하한 충돌
   상신은 tokens.css v2.45 블록 1벌이 정본이다(D-36).

   ── 구 화면과의 관계 ──────────────────────────────────────────────────────
   · 위 §3-5-b(.stat-flow/.stat-derived)와 §3-5 의 .stat-strip·.stat--highlight 계열,
     §6-3/§6-5 의 .stat-strip 열 수는 전부 **사문**이 됐다(1b 마크업이 그 클래스를 더는
     쓰지 않는다 — 각 자리 v2.45 주석). 지우지 않는 이유는 .mock-banner 전례 그대로:
     스트립형 화면 복원이 마크업 되돌리기로 끝나야 한다. ⚠ .stat__label/.stat__value/
     .stat__caption(§3-5 기본형)은 사문이 **아니다** — ranking 총액 카드(.settlement-total)
     가 계속 쓴다.
   · .stat__figure/.num--stat/.num__frac/.num__unit 공용 규칙은 1b 도 그대로 소비한다 —
     값 크기만 .stat1b 스코프가 --font-size-stat 를 1b 토큰으로 갈아끼운다(계단 클래스
     무관 · 계단 기구는 js 쪽에서 휴면 — buyback.js UNIT_SCALE_CHARS 배너).

   ── 반응형 설계 (사양 §1·§2 + 768~1279 권장안) ────────────────────────────
   · 기본(≥768) — 그리드 270px + minmax(0,1fr) 두 열, 3열 래퍼(.stat1b__group)는 전폭
     줄바꿈. 사양이 768~1279 디자인을 따로 주지 않아 §2 끝의 권장안(*"1열(270)+2열(290)을
     한 줄, 3열은 아래 전폭"*)을 따르되, 2열을 290 고정이 아니라 1fr 로 편다 — 720px
     내부폭에서 270+290+16=576 뒤에 남는 144px 빈 트랙이 생기지 않게 한 builder 판단
     (사양 문구가 '권장'이라 재량 범위 — 기록은 notes §4-bd).
   · ≥1280 — 사양 §1 원안 `270px 290px minmax(0,1fr)` · gap 16 · align-items stretch.
   · <768 — 1b-m(사양 §2): 1열 스택 gap 12 · 카드 패딩 16 · 값 22px(토큰) · 수량
     그룹은 래퍼가 흰 카드(패딩 8)가 되고 커넥터 미사용 · 속 박스 #EEF4FF.

   ── 커넥터 (사양 §1 ⑤) ──────────────────────────────────────────────────
   높이 34 · 선 2px · 촉 5×6 · 줄기 = 수량 카드 중앙에서 14px 낙하 · 가로선 = 락업
   중앙 → 소각 중앙 · 아래 카드 간격 10. ⚠ 사양 명시대로 **px 절대좌표 금지** — x 는
   전부 %·gap 파생이다: 2열 그리드 열 중앙 = 25% − g/4 · 75% + g/4 (g = --space-4 ·
   §3-5-b v2.39 유도식 재사용). 세로 34px 분해: 줄기 0~14 · 바 14~16 · 낙하선 14~28 ·
   촉 28~34. 순수 장식(마크업 aria-hidden — 관계 서술은 캡션 몫 · v2.39 판단 그대로).
   2px 선·7px 점·10px 세로 패딩 등은 색·폰트·간격 토큰 규칙 대상이 아닌 도형 수치다
   (§3-13-b 전례). ------------------------------------------------------------- */
.stat1b {
  /* .num--stat 재사용 스위치 — 1b 값 크기는 계단이 아니라 토큰 고정(18↔22) */
  --font-size-stat: var(--font-size-stat1b-value);
  display: grid;
  grid-template-columns: 270px minmax(0, 1fr);
  gap: var(--space-4);
  align-items: stretch;
  transition: opacity var(--transition-fast);
}
/* 구간 전환 로딩 — 스트립과 같은 규칙(§4.2 로딩 UX · js setBusy 가 같은 id 를 토글) */
.stat1b.is-swapping { opacity: .4; }
.stat1b__col { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; grid-column: 1 / -1; }
/* ★ v2.50 — 총 바이백 금액 | 미집행 바이백 재원 짝. 같은 구조 2장을 나란히 두고 flex:1 로 남는 높이를 채운다 */
.stat1b__pair { flex: 1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); min-width: 0; }
.stat1b__pair > .stat1b-card { display: flex; flex-direction: column; }
.stat1b__pair .stat1b-card__subs { flex: 1; }
.stat1b__pair .stat1b-sub { flex: 1; }
.stat1b__group { grid-column: 1 / -1; display: flex; flex-direction: column; min-width: 0; }

/* 공통 카드 (사양 §1 공통 카드 스타일 — 배경·1px 테두리·radius 14·18/20 패딩·shadow-sm) */
.stat1b-card {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-stat-card);
  padding: var(--space-stat1b-pad) var(--space-5);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}
/* ★ v2.45-1 (U-24) — 1열이 3장(예상 매출 → 예상 매출 바이백 재원 → 잔여 바이백 재원)이
   되어 flex 배분을 실렌더로 재판정했다: **현행 유지**(잔여 카드 한 장만 flex:1). 1280
   실측에서 세 열 하단 1131/1131/1131px 로 이미 정합이고(§8 v2.45-1), 신설 미러 카드는
   기본형(늘어나지 않음)이 값·설명 간격을 사양 6px 그대로 지킨다. 신설 카드 전용 규칙 0 —
   공통 .stat1b-card 를 그대로 입는다(마크업 U-24 주석이 정본). */
/* ★★ v2.46 (U-25 · 사용자 지시 2026-09-30) — 미러 카드가 **예상 매출 카드 안의 서브
   박스**로 병합돼 1열은 다시 2장이다(마크업 U-25 주석 정본 — 목적 = 1열 높이 축소).
   CSS 변경 0줄: 서브 박스는 총 카드의 .stat1b-card__subs › .stat1b-sub 규칙(아래
   「총액 서브 박스」 블록)을 그대로 입고, flex 배분도 재판정 결과 그대로(잔여 카드만
   flex:1 — 1열이 짧아진 몫은 flex:1 이 흡수해 하단 정합 유지 · 실측 §8 v2.46).
   그 블록 주석의 "서브 박스 2개"는 이제 총 카드 한정 서술이다 — 규칙 자체는 예상 매출
   카드의 서브 박스 1개에도 똑같이 적용된다(선택자가 카드를 가리지 않는다). */
/* ~~.stat1b-card--fund { flex: 1; }~~ — v2.50 짝 레이아웃(.stat1b__pair)이 높이를 맞춘다 */
.stat1b-card__label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-stat1b-label);
  font-weight: var(--font-weight-bold);
  color: var(--color-primary);
  line-height: var(--line-height-tight);
  letter-spacing: var(--letter-spacing-heading);
  white-space: nowrap;
}
.stat1b-card__mark { flex: none; }
/* 뱃지 '변동 가능' — 높이 20 · 0 7px · pill · 경고 틴트(기존 pending 계열 값 일치 재사용) */
.stat1b-card__badge {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 7px;
  border-radius: var(--radius-full);
  background: var(--color-pending-bg);
  color: var(--color-pending);
  font-size: var(--font-size-stat1b-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: normal;
}
.stat1b-card__value {
  margin-top: var(--space-stat1b-text);
  font-size: var(--font-size-stat1b-value);
  line-height: var(--line-height-num);
  letter-spacing: var(--letter-spacing-num);
  color: var(--color-text);
  min-width: 0;
}
/* 미확정(`—`)도 값 행 높이 유지 — §3-5 .stat__value .is-pending 과 같은 장치 */
.stat1b-card__value .is-pending {
  font-size: var(--font-size-stat1b-value);
  line-height: var(--line-height-num);
}
.stat1b-card__desc {
  margin-top: var(--space-stat1b-text);
  font-size: var(--font-size-stat1b-desc);
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
  letter-spacing: var(--letter-spacing-heading);
}
/* 단위 13px(사양: USDT 13px/500 · 간격 4px) — 전역 .num__unit(14px)의 1b 스코프 재정의.
   굵기 500·muted 색·--spaced 의 4px 마진은 전역 값이 이미 사양과 일치라 재선언 0. */
.stat1b .num__unit { font-size: var(--font-size-caption); }

/* 락업·소각 — 텍스트 간격만 14px (사양 ⑥ — 카드가 높아 6px 는 값이 뜬다) */
.stat1b-card--derived .stat1b-card__value,
.stat1b-card--derived .stat1b-card__desc { margin-top: var(--space-stat1b-text-lg); }

/* 강조 타일 (누적 바이백 수량 · 사양 ④ — #0059FF 채움 · 좌 패딩 32 · 전경 전부 흰색) */
.stat1b-card--qty {
  background: var(--color-stat-highlight);
  border-color: var(--color-stat-highlight);
  padding-left: var(--space-8);
}
.stat1b-card--qty .stat1b-card__label,
.stat1b-card--qty .stat1b-card__value,
.stat1b-card--qty .stat1b-card__desc,
.stat1b-card--qty .num__frac,
.stat1b-card--qty .num__unit { color: var(--color-on-primary); }
.stat1b-card--qty .stat1b-card__value .is-pending {
  color: var(--color-on-primary);
  border-color: var(--color-on-primary);   /* 파랑 위 회청 점선 1.9:1 침몰 방지(§3-5 전례) */
}

/* ★★★ v2.46-1 (U-26 ④ · 사용자 확정 추기 2차 2026-09-30) — **미집행 바이백 재원 카드
   커버 색상 = 누적 바이백 수량 강조 카드와 동일.** 지시 원문: *"그 카드의 커버 색상을
   누적 바이백 수량 강조 카드와 동일하게 — 배경·테두리 #0059FF(기존 강조 토큰 재사용) ·
   흰 글자(값·단위·설명 포함)."*
   · 위 `.stat1b-card--qty` 블록의 색 처리 패턴을 **선택자만 바꿔 그대로** 옮겼다 —
     한 그룹 선택자로 합치지 않은 이유: 수량 카드는 `padding-left: 32px`(사양 §1 ④ 좌
     여백)가 색과 한 블록에 있어, 합치면 이 카드까지 좌 패딩이 따라온다(지시 범위 밖).
   · 신규 색 리터럴 0 — 배경·테두리는 --color-stat-highlight(#0059FF), 전경은
     --color-on-primary(#FFFFFF). 흰 글자/#0059FF 대비 5.42:1 — 12.5px 설명까지 AA ✓
     (실측 §8 v2.46-1 · 수량 카드가 이미 같은 조합으로 선례).
   · 라벨은 공통 규칙의 --color-primary(#1668D8) 를 흰색으로 덮는다(수량 카드와 동일).
   · 마크업 변경 0 — `.stat1b-card--fund` 는 이 카드 고유 클래스다(flex:1 규칙과 공존). */
.stat1b-card--fund {
  background: var(--color-stat-highlight);
  border-color: var(--color-stat-highlight);
}
.stat1b-card--fund .stat1b-card__label,
.stat1b-card--fund .stat1b-card__value,
.stat1b-card--fund .stat1b-card__desc,
.stat1b-card--fund .num__frac,
.stat1b-card--fund .num__unit { color: var(--color-on-primary); }
/* 파랑 카드 안 서브 박스 — 흰 박스 · 본문색 글자(총 카드 서브 박스와 같은 읽기) */
.stat1b-card--fund .stat1b-sub { background: var(--color-bg); }
.stat1b-card--fund .stat1b-sub .num__frac { color: inherit; }
.stat1b-card--fund .stat1b-sub .num__unit { color: var(--color-text-muted); }
.stat1b-card--fund .stat1b-card__value .is-pending {
  color: var(--color-on-primary);
  border-color: var(--color-on-primary);   /* 파랑 위 회청 점선 침몰 방지 — 수량 카드와 동일 */
}

/* 총액 서브 박스 2개 (사양 ③ — 12px 아래 · 세로 8px 간격 · 배경 F5F7FA · radius 10) */
.stat1b-card__subs {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.stat1b-sub {
  --font-size-stat: var(--font-size-body);   /* 서브 값 16px — 굵기 700 은 아래 줄 */
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--color-bg-alt);
  border-radius: var(--radius);
  padding: 10px var(--space-3);
  min-width: 0;
}
.stat1b-sub .num--stat { font-weight: var(--font-weight-bold); }
.stat1b-sub__head { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.stat1b-sub__dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--color-primary);          /* 박스 1 — 매출 기반 (사양 ③ 표) */
}
.stat1b-sub--fund .stat1b-sub__dot { background: var(--color-bg-deep); }  /* 박스 2 — 재단 점 #0F1B2D */
.stat1b-sub__label {
  font-size: var(--font-size-caption);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text);
}
.stat1b-sub__ratio {
  margin-left: auto;
  font-size: var(--font-size-stat1b-desc);
  font-weight: var(--font-weight-semibold);
  color: var(--color-primary);
  font-variant-numeric: tabular-nums lining-nums;
}
.stat1b-sub--fund .stat1b-sub__ratio { color: var(--color-text); }
.stat1b-sub__value {
  font-size: var(--font-size-body);
  line-height: var(--line-height-num);
  letter-spacing: var(--letter-spacing-num);
  color: var(--color-text);
  min-width: 0;
}
.stat1b-sub__value .is-pending { font-size: var(--font-size-body); line-height: var(--line-height-num); }
.stat1b-sub__desc {
  font-size: var(--font-size-stat1b-xs);
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
  letter-spacing: var(--letter-spacing-heading);
}

/* 커넥터 — 기하 근거는 블록 배너 1벌 */
.stat1b-flow { position: relative; height: 34px; margin-bottom: 10px; }
.stat1b-flow__stem {
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  height: 14px;
  margin-left: -1px;
  background: var(--color-stat-highlight);
}
.stat1b-flow__bar {
  position: absolute;
  top: 14px;
  height: 2px;
  left: calc(25% - var(--space-4) / 4);
  right: calc(25% - var(--space-4) / 4);
  background: var(--color-stat-highlight);
}
.stat1b-flow__drop {
  position: absolute;
  top: 14px;
  bottom: 6px;
  width: 2px;
  margin-left: -1px;
  background: var(--color-stat-highlight);
}
.stat1b-flow__drop--l { left: calc(25% - var(--space-4) / 4); }
.stat1b-flow__drop--r { left: calc(75% + var(--space-4) / 4); }
.stat1b-flow__drop::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--color-stat-highlight);
}

/* 락업·소각 2열 — flex:1 로 3열 하단 라인 맞춤 (사양 §1 표 3열) */
.stat1b-derived {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  transition: opacity var(--transition-fast);
}
.stat1b-derived.is-swapping { opacity: .4; }

/* ≥1280 — 사양 §1 원안 3열 */
@media (min-width: 1280px) {
  .stat1b { grid-template-columns: 560px minmax(0, 1fr); }
  .stat1b__col { grid-column: auto; }
  .stat1b__group { grid-column: auto; }
}

/* <768 — 1b-m (사양 §2). 국소 미디어쿼리인 이유는 §3-5-b 와 같다 — 그룹 카드·속 박스·
   커넥터 소거가 한 덩어리의 시안 재현 단위라 §6 블록으로 흩으면 따로 움직인다. */
@media (max-width: 767px) {
  .stat1b { display: flex; flex-direction: column; gap: var(--space-3); }
  .stat1b__col { gap: var(--space-3); }
  .stat1b__pair { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
  /* 카드 패딩 16 **전면**(사양 §2 "카드 padding 16" — 세로만이 아니다). 단일 값이
     기본형의 `세로 var(--space-stat1b-pad · <768=16) / 가로 --space-5(20)` 를 덮는다 —
     실렌더에서 가로 20 잔존을 확인하고 고쳤다(§8 v2.45 표). */
  .stat1b-card { padding: var(--space-stat1b-pad); }
  /* 수량 그룹 — 래퍼 자체가 흰 카드(1px 테두리 · radius 14 · 패딩 8)가 된다(사양 §2 4:
     락업·소각이 하나 타일에 속한 것처럼 · 화살표·세로선 미사용). */
  .stat1b__group {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-stat-card);
    padding: var(--space-2);
    box-shadow: var(--shadow-sm);
  }
  .stat1b-flow { display: none; }
  /* 속 ① 하늘 박스 — radius 10 · 14px 12px (좌 32 패딩은 shorthand 가 함께 되돌린다) */
  .stat1b-card--qty {
    border-radius: var(--radius);
    padding: 14px var(--space-3);
    box-shadow: none;
  }
  /* 속 ② 서브 박스 2개 — #EEF4FF · 세로 스택 gap 8 · 패딩 12 · 라벨 13 + 아이콘 높이 14 ·
     값 16/700 · 설명 12 (사양 §2 4 속 ②) */
  .stat1b-derived {
    margin-top: var(--space-2);
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
  }
  .stat1b-derived .stat1b-card {
    --font-size-stat: var(--font-size-body);
    background: var(--color-stat-inner);
    border: 0;
    border-radius: var(--radius);
    padding: var(--space-3);
    box-shadow: none;
  }
  .stat1b-derived .num--stat { font-weight: var(--font-weight-bold); }
  .stat1b-derived .stat1b-card__label {
    font-size: var(--font-size-caption);
    font-weight: var(--font-weight-semibold);
  }
  .stat1b-derived .stat1b-card__mark { height: 14px; width: auto; }
  .stat1b-derived .stat1b-card__value { font-size: var(--font-size-body); }
  .stat1b-derived .stat1b-card__value .is-pending { font-size: var(--font-size-body); }
  .stat1b-derived .stat1b-card__desc { font-size: var(--font-size-stat1b-xs); }
  .stat1b-derived .stat1b-card__value,
  .stat1b-derived .stat1b-card__desc { margin-top: var(--space-stat1b-text); }
}

/* --- 3-6. 섹션 골격 --------------------------------------------------- */

.section { padding-block: var(--section-py); }
.section--alt  { background: var(--color-bg-alt); }
/* v2.3 — 다크 밴드는 히어로와 푸터 둘뿐이다(레이아웃 §0-3).
   C6 으로 설명 섹션 4개가 노션으로 이관되면서 다크 밴드가 담을 콘텐츠 자체가 사라졌고,
   남은 콘텐츠(표·그래프)는 자기 카드와 테두리로 이미 구획되므로 배경 교차를 억지로 유지하지 않는다.
   → 다크 섹션 변형과 그 파생 규칙(제목·리드문 반전, 연속 밴드 여백 병합)은 삭제했다.
     클래스명은 적지 않는다 — 폐기 클래스 스캔의 오탐이 된다(tokens.css 삭제 토큰 주석과 같은 관례). */

/* ★★ v2.29 — 타이틀 블록 가운데 정렬 변형 (사용자 지시 3 · 건별 내역 섹션).
   ⚠⚠ **선택자를 두 클래스로 겹쳐 쓴다** — `.section__head--center` 한 개로는 **진다**.
     `.section__head` 는 §6-3(≥768) 블록에서 `justify-content: space-between` 을 다시
     선언하는데, 미디어 쿼리는 특정도를 올리지 않으므로 **클래스 1개끼리는 나중 선언이
     이긴다**(그 블록이 파일 뒤에 있다). 처음 한 클래스로 썼다가 **1280 에서 제목이
     왼쪽에 그대로 붙어 있는 것을 실렌더 캡처로 확인**했다.
     두 클래스(0,2,0)로 겹치면 **순서와 무관하게** 이긴다 — 규칙을 파일 뒤로 옮기는
     것보다 안전하다(다음 개정에서 블록 순서가 바뀌어도 깨지지 않는다).
   ★ `text-align` 만으로는 부족했다: 안쪽 `<div>` 가 flex 아이템이라 **내용 폭으로
     줄어들어**, 그 안에서 텍스트를 가운데 정렬해도 눈에 보이는 변화가 없다.
     **`justify-content` 가 그 div 자체를 가운데로 보내는** 쪽이 실제 효과를 낸다.
   ★ 범위는 이 블록 안쪽뿐이다 — 아래 이더스캔 링크(우측)·표(좌측)는 그대로다. */
.section__head.section__head--center {
  justify-content: center;
  text-align: center;
}

.section__head {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}
.section__title { font-size: var(--font-size-h2); font-weight: var(--font-weight-bold); }
.section__sub {
  margin-top: var(--space-2);
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
}

/* --- 3-7. 세그먼트 토글 (기간 구분 5종, 디자인 시스템 §5-13) ------------ */

.segmented {
  display: flex;
  border: 1px solid var(--color-border-control);   /* 3.41:1 — 컨트롤 경계 */
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--color-bg);
}
.segmented__btn {
  height: 44px;
  padding-inline: var(--space-4);
  border: 0;
  border-left: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
.segmented__btn:first-child { border-left: 0; }
.segmented__btn:hover { background: var(--color-bg-alt); color: var(--color-text); }
/* 상태를 색만으로 전달하지 않는다 — aria-pressed + 굵기 변화(500→600)를 함께 쓴다
   ★ v2.23 — `aria-selected` 를 **같은 규칙에 합쳤다**(ranking 의 랭킹 구분 탭).
     같은 컴포넌트인데 역할이 둘이다: index 기간 구분은 *눌린 버튼*(toggle · aria-pressed),
     ranking 랭킹 구분은 *고른 탭*(role="tab" · aria-selected). 역할이 다르면 상태 속성도
     다르지만 **보이는 상태는 하나**여야 하므로 값은 한 벌만 둔다 — 두 벌로 나누면
     언젠가 한쪽만 손대서 같은 컴포넌트가 두 가지 활성 색을 갖게 된다. */
.segmented__btn[aria-pressed="true"],
.segmented__btn[aria-selected="true"] {
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: var(--font-weight-semibold);
}
/* 컨테이너가 overflow:hidden 이므로 포커스 링을 안쪽에 그린다 */
.segmented__btn:focus-visible { outline-offset: -3px; border-radius: 0; }

/* --- 3-8. 표 (건별 6열 · Top 20 **3열** 공용 기반, 디자인 시스템 §5-7) ---
   ※ Top 20 은 v2.15 에서 4열 → 3열이 됐다(2026-08-04 사용자 지시로 `판매 실적` 제거).
     이 공용 기반 규칙은 열 수에 의존하지 않아 **한 줄도 바뀌지 않았다.** */

/* 표 상단 고지 노트 — 열·블록 단위로 1회만 두는 미확정 메타 고지.
   표 바깥에 두는 이유: 카드 전환 시 thead 가 sr-only 로 바뀌므로
   th 안에 넣으면 시각 사용자에게 고지가 소실된다. 전 뷰포트 공통 노출. */
.table-note {
  margin-bottom: var(--space-3);
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
}
/* 고지가 2줄일 때(index ④ — 범위 → 단위) 두 줄은 한 덩어리로 붙고,
   표와의 간격만 --space-3 로 남는다. 별개 블록으로 흩어져 보이지 않게 한다. */
.table-note:not(:last-of-type) { margin-bottom: var(--space-1); }

.data-table { width: 100%; border-collapse: collapse; }
.data-table thead th {
  height: 44px;
  padding-inline: var(--space-2);
  background: var(--color-bg);
  /* ★ v2.8 — 시안 주석 ④ *"표 제목 컬러 눈에 띄게 변경"* (구 --color-text-muted).
     "표 제목"이 열 헤더임은 시안이 확정했다 — 함께 온 슬라이스 6종이 index ④ 건별 표의
     열 헤더 6개와 1:1 이고 잉크 높이도 --font-size-small 규격과 일치한다(디자인 시스템 §5-7).
     ★ 시안색 #0085FF 는 **쓰지 않는다** — 14px 텍스트에 흰 3.62 / bg-alt 3.37 로 AA 미달이다.
       의도만 채택하고 값은 --color-primary(흰 5.24 · bg-alt 4.88 — §1-3 35·36행)로 치환했다.
     ★ 선언 1줄이 세 표(index 건별 6열 · ranking 매출 3열 · ranking 정산 3열)를 함께 옮긴다.
       ⚠ 모바일 카드 모드의 `td::before` 라벨은 **--color-text-muted 유지**다(아래 반응형 블록).
         그 라벨은 행마다 반복되므로 파랑으로 올리면 값보다 라벨이 먼저 읽힌다. */
  color: var(--color-primary);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-semibold);
  text-align: left;
  border-bottom: 1px solid var(--color-border-strong);  /* 구조 장식선 — 1.4.11 비대상 */
  /* sticky 제거 (2026-07-28 사용자 확정) — 스크롤 중 헤더가 행 사이에 끼어 보이는 문제.
     헤더는 표와 함께 스크롤한다. */
}
.data-table tbody td {
  height: 56px;
  padding-inline: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}
/* zebra 줄무늬 금지 — 1~3위 강조 행과 경쟁한다 */
@media (hover: hover) and (pointer: fine) {
  .data-table tbody tr:hover { background: var(--color-bg-alt); transition: background var(--transition-fast); }
}
.data-table .is-num { text-align: right; }
/* 카드 전환 시 td::before 라벨과 값이 좌우로 갈리도록 값만 한 겹 감싼다 */
.cell-value { display: inline-flex; align-items: baseline; }

.table-foot { margin-top: var(--space-6); text-align: center; }
/* --- ~~바이백 지갑 주소~~ (index ④-a · v2.19 사용자 지시 2026-08-10) ------------
   ★★ v2.33 — **적용 대상 0개 (의도적 보존)**: ④-a 블록 마크업이 사용자 직접 지시
      (*"지갑 주소 블록 없애주고 바이백 내역 링크 누르는것만 있어도 됨"*)로 DOM 삭제됐다.
      아래 `.wallet-note*` 규칙과 §6 반응형의 `.wallet-note__row` 행은 `.mock-banner` 전례
      (§3-2)대로 **지우지 않고 보존**한다 — A-33(건별 tx 해시) 회신 시 주소 UI 가
      재구성될 수 있고, 그때 이 규칙이 그대로 다시 산다. 신규 마크업이 이 클래스를
      다른 뜻으로 재사용하는 것만 금한다.
   ── 이하 v2.19 설계 근거 (이력) ──
   표 위 고지 줄(①범위 ②단위) 다음의 **③주체** 자리다. 고지가 산문 한 줄인 것과 달리
   이쪽은 **값 + 액션**이라, 카드로 띄우지 않고 얇은 배경 블록으로만 구분한다 —
   표 바로 위에 카드를 두면 표보다 무거워져 시선이 지갑에 먼저 붙는다(주인공은 표다).
   ★ 값이 없으면 `hidden` 이라 이 규칙 전체가 무효가 된다 — 죽은 자리를 만들지 않는다.
   ★ 신규 토큰 0. 색·간격·서체 전부 기존 토큰을 경유한다. */
.wallet-note {
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.wallet-note__label {
  margin-bottom: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--font-size-caption);
  line-height: var(--line-height-snug);
}
/* 모바일 기본은 세로 — 42자 주소와 44px 버튼을 360px 한 줄에 넣으면 반드시 넘친다.
   ≥768 에서 가로로 편다(아래 6-3 블록). */
.wallet-note__row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}
/* 주소는 **끊어 읽는 값이 아니라 한 덩어리 식별자**라 말줄임(...)을 쓰지 않는다 —
   가려진 주소는 눈으로 대조할 수 없어 표기의 목적 자체가 사라진다. 대신 줄을 접는다.
   `anywhere` 를 쓰는 이유: 주소에는 공백·하이픈이 없어 `break-word` 로는 접히지 않는다. */
.wallet-note__addr {
  min-width: 0;
  font-family: var(--font-family-mono);
  font-size: var(--font-size-small);
  line-height: var(--line-height-body);
  color: var(--color-text);
  overflow-wrap: anywhere;
  word-break: break-all;
}
.wallet-note__copy { flex: none; }
/* ★ v2.27 — 이더스캔 링크 (사용자 지시 4). **새 컴포넌트를 만들지 않았다** —
   내용물이 `.slim-link--external`(이 사이트의 외부 링크 컴포넌트)이고 이 규칙은
   그것을 행 안에서 줄바꿈되지 않게 잡아 두는 **자리 규칙 한 줄**뿐이다. */
/* ~~.wallet-note__link~~ **v2.28-2 폐기** — 이더스캔 링크가 지갑 블록 밖으로 나갔다.
   규칙을 남겨 두지 않는다: 적용 대상이 0이고, 되살릴 때는 자리 자체를 다시 정해야 한다. */

/* ★ v2.28-2 — 이더스캔 링크 자리(표 위 · 상시 노출). 새 컴포넌트를 만들지 않았다 —
   내용물은 `.slim-link--external` 이고 이 규칙은 **바깥 여백 한 줄**뿐이다. */
/* ★ v2.29 — **오른쪽 끝 정렬** (사용자 지시 1). 이 줄은 표 바로 위에 홀로 서는
   보조 링크라, 좌측에 두면 표의 첫 열(`실행 일자`)과 같은 축에 붙어 **표의 일부처럼**
   읽힌다. 우측 끝으로 보내면 표와 분리되고, 표의 마지막 열이 우측 정렬 금액이라
   시각 축도 맞는다.
   ★ 360px 에서도 그대로 우측 정렬이다 — 링크 한 줄이라 좁은 폭에서도 넘치지 않는다
     (실측 확인). 별도 반응형 분기를 두지 않았다. */
.buyback-explorer {
  margin-bottom: var(--space-4);
  text-align: right;
}


/* ══════════════════════════════════════════════════════════════════════════
   ? 도움말 점 — 노션 설명 문서 슬롯 (v2.27 · 사용자 지시 3 + 추가 정정)

   ★ **두 상태가 한 규칙을 공유한다.** 비활성은 `<span>`, 활성은 `<a class="…--link">`
     이고 **모양이 같다** — 눌리는지 여부는 커서와 색으로만 갈린다. 같은 자리에서
     아이콘이 커지거나 움직이면 URL 주입이 레이아웃을 흔든 것처럼 보인다.
   ★ 크기 20px 는 4px 스케일 안이고(--space-5), 제목(30px) 옆에서 위첨자처럼 읽히도록
     `vertical-align` 로 살짝 올린다. 터치 타깃 44px 규칙의 예외인 이유: 이것은 **보조
     설명으로 가는 부가 링크**이지 주 동작이 아니고, 같은 문서로 가는 경로가 아직
     이 자리 하나뿐이라 크기를 키우면 제목 줄을 밀어낸다. → designer 상신(§7 D-14).
   ★ 대비: 비활성 `--color-text-muted`(5.56:1) / 활성 `--color-primary`(5.24:1) — 둘 다
     본문 대비 기준 통과. 면(`--color-bg-alt`)은 비텍스트라 3:1 대상이 아니다. */
.help-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-5);
  height: var(--space-5);
  margin-inline-start: var(--space-2);
  vertical-align: 0.15em;
  border-radius: var(--radius-full);
  background: var(--color-bg-alt);
  color: var(--color-text-muted);
  font-size: var(--font-size-caption);
  font-weight: var(--font-weight-bold);
  line-height: 1;
  /* 비활성 기본 — 링크가 아니므로 손가락 커서를 주지 않는다(누를 수 있다는 거짓 신호) */
  cursor: default;
  text-decoration: none;
  user-select: none;
}
/* 활성(주입됨) — 링크일 때만 브랜드색과 손가락 커서를 준다 */
.help-dot--link {
  background: var(--color-info-bg);
  color: var(--color-primary);
  cursor: pointer;
}
.help-dot--link:hover { background: var(--color-primary-tint-2); }
.help-dot--link:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* ★ v2.40 — 표 아래 「링크 복사」 액션 행 규칙을 삭제했다(사용자 직접 지시 2026-08-14
   오후 — 버튼 폐기 · 유일 사용처가 ranking 표 아래 그 한 곳이었다). 마크업 원문·경위는
   ranking.html 그 자리 취소선 주석 1벌 · notes §4-ax D272. 클래스명은 여기 적지 않는다 —
   폐기 클래스 스캔의 오탐이 된다(§3-6 v2.3 삭제 주석과 같은 관례 · 원문 보존 의무는
   ranking.html 쪽 규약이 진다). */

/* 스켈레톤 (로딩) — 스피너·"로딩 중" 텍스트 없음 */
.skeleton-bar {
  display: block;
  height: 1em;
  border-radius: var(--radius-sm);
  background: var(--color-bg-alt);
}

/* --- 3-9. 상태 블록 / 콜아웃 ------------------------------------------ */

.notice {
  background: var(--color-info-bg);
  border-left: 4px solid var(--color-primary);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-5) var(--space-6);
  line-height: var(--line-height-body);
}
.notice--warn {
  background: var(--color-pending-bg);
  border-left-color: var(--color-pending);
}
.state-block { margin-top: var(--space-6); }
.state-block__actions { margin-top: var(--space-4); }

/* --- 3-10. 슬림 링크 (탭 전환 · 노션 상세 안내 공용 컴포넌트) ------------ */

/* 페이지 끝의 탭 전환 밴드 — 두 페이지 공통으로 bg-alt 를 쓴다.
   설명 섹션이 빠져 배경 교차가 사라진 뒤, 이것이 "여기가 페이지 끝"이라는
   유일한 배경 신호다(레이아웃 §0-3). */
.slim-link-band {
  padding-block: var(--space-12);
  text-align: center;
  background: var(--color-bg-alt);
  border-top: 1px solid var(--color-border);
}
/* index ⑤ 노션 링크 밴드 — 바로 아래 ⑥ 탭 전환 밴드와 배경·경계선으로 구분해
   두 링크가 링크 목록처럼 한 덩어리로 뭉치지 않게 한다(레이아웃 §3 ⑤·⑥). */
.slim-link-band--notion {
  padding-block: var(--space-10) var(--space-6);
  background: var(--color-bg);
  border-top: 0;
}

.slim-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  color: var(--color-primary);
  font-size: var(--font-size-body-lg);
  font-weight: var(--font-weight-semibold);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.slim-link:hover { color: var(--color-primary-dark); }

/* 외부(노션) 상세 안내 링크 — 같은 컴포넌트의 외부 변형.
   화살표가 아니라 **외부 이동 도형** 아이콘을 붙여 "사이트를 떠난다"를 전달한다(레이아웃 §3 ⑤).
   ★ [hidden] 을 여기서 명시적으로 끈다: .slim-link 가 display:inline-flex 라
     UA 기본 `[hidden]{display:none}` 을 덮어써, 이 한 줄이 없으면 "URL 미확정 시
     요소 자체를 렌더하지 않는다"는 규칙(레이아웃 §5 예외 행)이 조용히 깨진다. */
.slim-link--external[hidden] { display: none; }
/* 각주 블록 안 축소형(ranking ④ⓓ) — 크기만 낮추고 터치 타깃 44px 는 유지한다 */
.slim-link--sm { font-size: var(--font-size-small); }
/* ★ v2.28-2 — 비활성(주소 미주입). 노션 `?` 비활성과 **같은 판단**: 링크가 아니므로
   브랜드색도 손가락 커서도 주지 않는다(누를 수 있다는 거짓 신호).
   ⚠ **반드시 `.slim-link` 정의보다 뒤에 있어야 한다** — 특정도가 같아(클래스 1개)
     순서로 승부가 갈린다. 앞에 두었더니 `.slim-link` 의 `--color-primary` 가 이겨
     비활성인데 **파랗게** 떴다(실렌더로 잡았다).
   ★ 밑줄은 **남긴다** — 주소가 들어오면 같은 자리에 같은 모양의 링크가 서야 하고,
     밑줄까지 빼면 활성 전환이 "없던 것이 생긴" 것처럼 보여 자리가 흔들린다.
     대신 **점선**으로 바꿔 "지금은 눌리지 않는다"를 형태로도 말한다.
   ★ 대비 `--color-text-muted` 5.56:1 ✓ (활성 `--color-primary` 5.24:1). */
.slim-link--disabled {
  color: var(--color-text-muted);
  cursor: default;
  text-decoration-style: dashed;
}

/* --- 3-11. 푸터 — ★★ 이 블록의 규칙은 **전부 무효다 (v2.21)** ★★ ----------
   사용자 직접 지시(2026-08-11): *"하단에 색이 다른 전체 부분을 다 제거."*
   → `<footer class="site-footer">` 가 **index·ranking 두 페이지 마크업에서 통째로
     사라졌다.** 아래 규칙들이 꾸밀 요소가 하나도 없다.

   ★ **그런데도 지우지 않는다** — `.stat--wide`(D87)·`.site-footer__bottom`(v2.19)과
     **같은 규약**이다: 되살릴 때 **마크업만 되돌리면 끝나게** 하기 위함이다. 특히 이번
     제거는 법적 고지·거래소 링크가 함께 사라져 **리더 → 사용자 확인이 걸려 있는**
     상태라(index.html 푸터 자리 주석 R-a·R-b · notes §4-ab), 되살릴 여지가 v2.19 보다
     오히려 크다. CSS 를 지우면 그때 스타일 복원까지 딸려 온다.
   ★ 되살릴 때 **먼저 볼 것**: 아래 v2.19 `padding-bottom` 주석은 *하단 바만 없던
     상태*를 전제로 쓰였다. 푸터 전체를 원상 복구하는 것이라면 하단 바도 함께 돌아오므로
     그 한 줄(`padding-bottom`)은 **지워야** 여백이 두 겹이 되지 않는다.
   ★ 산출물 생성기에도 잔존 감지 게이트가 있다 — 마크업만 되돌리면 빌드가 멈춘다.
     `_workspace/build-share-snapshot.py` 의 푸터 게이트 2개를 함께 걷을 것.
   ── 이하 v2.19 시점의 주석 원문 (맥락 보존) ───────────────────────────── */

/* ★ v2.19 — `padding-bottom` 신설. 최하단 바(`.site-footer__bottom`)를 사용자 지시로
     제거하면서(2026-08-10 · index/ranking 마크업 주석 참조) 그 바가 갖고 있던 아래 여백이
     함께 사라져, 푸터가 법적 고지 문장 **32px 아래에서 뚝 끊겼다**(위 패딩은 64px 인데
     아래만 32px 이라 눈에 띄게 아래가 눌린 모양이 된다).
     종전 실제 여백: 법적 고지 `margin-bottom` 32 + 바 `padding-block` 24+24 ≒ 103px.
     복원값으로 **32px(`--space-8`)** 를 더해 총 **64px** 로 맞췄다 — `.site-footer__grid` 의
     `padding-top: var(--space-16)`(64px)과 **위아래 대칭**이 되는 값이라, 임의 수치가 아니라
     이미 이 푸터가 쓰던 상하 리듬을 그대로 따른 것이다. 신규 토큰 0.
     ★ 바를 되살리면 이 한 줄을 지운다 — 안 지우면 아래 여백이 두 겹이 된다. */
.site-footer {
  background: var(--color-bg-deep);
  color: var(--color-text-on-dark);
  padding-bottom: var(--space-8);
}
.site-footer__grid {
  display: grid;
  gap: var(--space-8);
  padding-block: var(--space-16) var(--space-8);
}
.site-footer__about {
  margin-top: var(--space-4);
  color: var(--color-text-muted-on-dark);
  font-size: var(--font-size-small);
  line-height: var(--line-height-body);
}
.site-footer__list { display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer a {
  color: var(--color-text-on-dark);   /* 푸터에서 primary·brand 사용 금지 (대비 부족) */
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--font-size-small);
}
.site-footer a:hover { text-decoration: underline; }
/* ★ v2.19 — 이 규칙이 꾸미던 요소(`.site-footer__bottom` 하단 바)는 **마크업에서 제거됐다**
     (사용자 지시 2026-08-10 · index/ranking 푸터 주석에 원문·사유 보존). 지금은 **해당 요소가
     없는 무효 규칙**이다. 그런데도 지우지 않은 이유는 이더스캔 `.stat--wide`(D87)·계단
     기구(§2-5)와 **같은 규약**이다 — 되살릴 때 **마크업만 되돌리면 끝나게** 하기 위함이고,
     이 바는 *"실데이터 투입을 전제로 한 종료"*(D142 배너)와 달리 **되살릴 여지가 열려 있다**
     (함께 사라진 `데이터 기준 시점` 고지가 리더 → 사용자 확인 대기 중이다 — notes §4-aa).
     ※ 아래 `.site-footer__stamp`·`.site-footer__copyright`·6-3 의 `flex-direction: row` 규칙도
       같은 이유로 남겼다. 셋 다 현재 무효다. */
.site-footer__bottom {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  border-top: 1px solid var(--color-border-on-dark);
  padding-block: var(--space-6);
  color: var(--color-text-muted-on-dark);
  font-size: var(--font-size-caption);
}
/* 법적 고지 전문 (v2.5 — 레이아웃 §2 v2.3.2). 3열 그리드 **아래 본문 블록**이다.
   ★ 위 여백은 `.site-footer__grid` 의 padding-bottom(--space-8)이 이미 만든다 — 겹쳐 주지 않는다.
   ★ 소제목·구분선을 두지 않는다: 하단 바 위 1px 헤어라인이 이미 경계를 만들고,
     제목을 달면 푸터에 없던 위계가 하나 더 생긴다.
   ★ 폭을 --container-narrow 로 묶어 한 줄을 40~50자로 잡는다 — 1200px 전폭으로 흘리면
     106자가 두 줄이 되면서 줄 끝에서 눈이 길을 잃는다. */
.site-footer__legal-notice {
  max-width: var(--container-narrow);
  margin-bottom: var(--space-8);
  color: var(--color-text-muted-on-dark);   /* 네이비 위 8.41:1 ✓ */
  font-size: var(--font-size-small);        /* 서비스 소개(16px)보다 한 단계 아래, 잔글씨는 아님 */
  line-height: var(--line-height-body);
}
/* 기준 시점 줄은 폭이 모자라면 **2줄로 접힌다** — 자르거나 말줄임하지 않는다(레이아웃 §2).
   `· 일 1회 갱신`이 잘리면 갱신 주기 고지가 사라지기 때문이다. */
.site-footer__stamp { font-size: var(--font-size-small); }
.site-footer__copyright { font-size: var(--font-size-caption); }

/* --- 3-12. 토스트 ----------------------------------------------------- */

.toast {
  position: fixed;
  bottom: var(--space-8);
  left: 50%;
  z-index: var(--z-toast);
  transform: translateX(-50%) translateY(var(--space-4));
  background: var(--color-bg-deep);
  color: var(--color-text-on-dark);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-lg);
  font-size: var(--font-size-small);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
}
.toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* --- 3-13. 히어로 (두 페이지 공용 골격) -------------------------------- */

/* ★ v2.8 ⓐ — 라디얼 워시 (디자인 시스템 §5-16 ⓐ · 시안 `image 677`).
   두 페이지 공통이다 — 히어로가 이 사이트의 **유일한 다크 밴드**이므로 워시도 한 곳뿐이다.
   ★ **`--color-bg-deep` 을 대체하지 않고 그 위에 얹는다.** 두 번째 레이어의 불투명 배경색을
     반드시 남길 것 — 그라디언트만 두면 알파 구간이 페이지 배경(흰색)을 통과시킨다.
   ★ 알파 상한 0.08 (`--color-brand-wash` 정의 주석 참조). 정적 그라디언트라
     `prefers-reduced-motion` 과 무관하고, 애니메이션은 붙이지 않는다. */
.hero {
  background:
    radial-gradient(58% 72% at 50% 46%,
                    var(--color-brand-wash) 0%,
                    rgba(47, 128, 237, 0) 72%),
    var(--color-bg-deep);
  color: var(--color-text-on-dark);
  text-align: center;
  /* ★ v2.8 ⓒ — 하단 여백만 96 → 64px 로 줄인다 (시안 주석 ③ · 리더 판정 C-2 기본안).
     **상단 96px 는 그대로다** — 위는 헤더(124px)와의 분리, 아래는 다음 섹션과의 분리라
     역할이 다르고, 함께 줄이면 밴드의 시작이 헤더에 먹힌다.
     ⚠ 전역 `--section-py` 를 건드리지 않고 `.hero` 전용 선언으로만 조정한다(판정 C 경로표).
     ⚠ C-2 대안(= 헤더를 낮춘다)과 **동시에 적용하지 말 것** — 합치면 히어로가 과하게 얕아진다. */
  padding-block: var(--section-py) var(--space-16);   /* 96 → 64 (≥1024) */
}
/* ★ v2.36 — `.hero__overline`·`.hero__sub` 는 **참조 0** 이 됐다(index 칩·양 페이지 서브
   DOM 제거 — 시안 39827/39828 완전 일치 지시). 규칙은 보존한다(.hero__cta 전례 — 복원이
   마크업 한 줄로 끝나게). `.hero__title` 기본 규칙은 index 가 계속 쓴다 — 색·배치는
   §3-13 v2.36 층(.hero--index .hero__title)이 덮는다. */
.hero__overline { display: inline-flex; }
.hero__title {
  margin-top: var(--space-5);
  font-size: var(--font-size-hero);
  font-weight: var(--font-weight-black);
  color: var(--color-text-on-dark);
}
.hero__sub {
  max-width: 640px;
  margin: var(--space-4) auto 0;
  font-size: var(--font-size-body-lg);
  color: var(--color-text-muted-on-dark);
  line-height: var(--line-height-snug);
}
/* ★ v2.8 — 제목 앞 장식 아이콘(현재 사용처: ranking h1 트로피 🏆 · 디자인 시스템 §6-1 ⓒ).
   `font-size: 1em` 이라 제목 크기를 따라 스케일한다 — 뷰포트별 재정의가 필요 없는 이유다.
   ⚠ 플랫폼별 글리프가 다르다(Segoe UI Emoji / Apple / Noto). 장식이므로 허용 범위이나,
     픽셀 동일 렌더가 요구되면 슬라이스에서 트로피만 잘라 20×20 이미지로 두는 것이 대안이다. */
.h-icon { margin-right: var(--space-2); font-size: 1em; line-height: 1; }

.hero__cta {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-8);
}
.hero__cta .btn { width: 100%; }

/* ★ v2.8 ⓑ — 히어로 3D 오브제 2점 (디자인 시스템 §5-16 ⓑ · 시안 `image 677`).
   **index 히어로 전용**이다. ranking 에는 두지 않는다 — 시안이 index 에만 그렸고, 두 히어로의
   성격이 다르다: index 는 서비스를 소개하는 자리라 상징물이 맞지만, ranking 은 개인별 정산
   금액을 공개하기 직전의 **고지 화면**이다. 그 앞에 코인 더미를 놓으면 톤이 "정산 공개"에서
   "수익 자랑"으로 이동한다(§0 원칙 2 · 메달색 폐기와 같은 판단).

   ⚠ `overflow: hidden` 부작용 — `.is-pending` 을 품은 조상에 overflow 를 걸면 점선 테두리가
     잘린다(§5-8, N-03 의 원인). **index 히어로에는 현재 `.is-pending` 이 0건이라 안전**하다.
     ranking 히어로에는 총액 블록이 값과 함께 돌아올 때 `—`+`.is-pending` 이 들어올 수 있는데,
     **ranking 에는 오브제를 두지 않으므로 overflow 도 걸지 않는다** — 두 결정이 서로를 보호한다.
     ★ 그러므로 이 두 선언을 `.hero` 로 올리지 말 것. */
.hero--index { position: relative; overflow: hidden; }

/* ★★★ v2.36 — index 히어로 = 시안 39827 「완전 동일」 재현 ★★★
   지시 원문: *"배너들은 이미지와 완전히 동일하게 디자인(동영상 움직이는 것까지 넣어서)"*
   (2026-08-13 저녁 · v2.35 라이트 변형(전면 cover 영상 + 흰 스크림)을 대체 — 경위·시안
   실측 수치는 index.html 히어로 주석 1벌 · notes §4-at).

   구조: 밝은 밴드(base) > `.hero__stage`(시안 일러스트 상자 622px) > 영상(contain·in-flow)
         + 제목(스테이지 좌하단 절대 배치).
   ★ 밴드 배경은 신설 토큰 `--color-hero-band`(#ECF0F6 — 시안 밴드 실측 = 영상 자체 배경
     동계열 · 검산 주석은 tokens.css). 영상 상자 경계가 밴드에 녹아 시안처럼 한 장의
     밝은 밴드로 보인다 — 스크림·오브제·컨테이너 승격이 전부 불필요해진 근거.
   ★ 선택자를 `.hero.hero--index`(0,2,0)로 겹친다 — §6 반응형 블록이 `.hero` 의
     padding-block 을 파일 뒤에서 재선언하므로 클래스 1개로는 진다(§3-13-b `.hero.hero--top20`
     이 실렌더로 확인한 함정 그대로). */
.hero.hero--index {
  background: var(--color-hero-band);   /* 라디얼 워시(.hero)도 함께 걷힌다 — 시안은 평탄 단색 */
  color: var(--color-text);
  text-align: left;
  padding-block: 0;                     /* 밴드 높이는 아래 스테이지가 소유한다 */
}
/* 스테이지 — 시안 일러스트 상자(604×338 @1920)의 재현 단위.
   · 622px = 영상 표시 폭 실측: 영상 프레임(1278×720) 안 일러스트가 약 97% 폭을 차지해
     622 × 0.97 ≈ 604(시안 일러스트 실측 폭). 색·폰트·간격이 아닌 **레이아웃 치수
     리터럴**이라 하드코딩 금지 규칙 대상이 아니다(§3-13-b 180px 와 같은 성격).
   · padding-block --space-8(32px) ≈ 시안 상하 여백 실측 40/38px 의 토큰 근사 —
     밴드 총높이 414px vs 시안 416px (오차 <1%).
   · min-height 416px — 영상 미주입(JS 죽음·URL 공백) 상태에서도 밴드가 시안 높이를
     유지하고 제목이 좌하단에 남는다(빈 밝은 밴드 + 문구 = 열화 허용 상태). */
.hero__stage {
  position: relative;
  width: min(100%, 622px);
  margin-inline: auto;
  padding-block: var(--space-5);
  min-height: 240px;
}
/* 제목 — 시안 실측: 좌 오프셋 ≈32px(--space-8) · 밴드 하단 여백 ≈41px(--space-10 근사) ·
   폰트 ≈36px = 히어로 토큰 40px 의 0.9 배.
   ★ [토큰 추가 대기] 36px 전용 토큰이 없어 **기존 토큰 파생**(calc)으로 뒀다(.num--hero
     전례 · 스킬 규약). designer 정식 토큰 시 calc 한 줄만 치환.
   ★ 색 — 다크부는 --color-text(시안 실측은 #001B50 계열 네이비 — 팔레트에 없는 값이라
     본문 토큰으로 근사 · 상신 D-29), 브랜드부는 --color-primary(#1668D8 — 시안 실측
     그라디언트 종점 #0769D2 과 근접 · 리더 명세 "파랑" 단색 채택 · 그라디언트 간극은
     상신 D-29). 대비는 밴드 위 14.3:1 / 4.58:1, 영상 최암 화소 위 13.7:1 / 4.37:1
     (36px/800 대형 텍스트 AA 3:1 ✓ — 실측 경위는 index.html 히어로 주석). */
.hero--index .hero__title {
  position: absolute;
  left: var(--space-4);                 /* <768 축소 오프셋 — 시안 비례는 ≥768 블록이 잡는다 */
  bottom: var(--space-5);
  margin: 0;
  font-size: calc(var(--font-size-hero) * 0.9);
  line-height: var(--line-height-tight);
  color: var(--color-text);
}
/* ★★★ v2.39 — 워드마크 **초록→파랑 텍스트 그라디언트** (사용자 회신 2026-08-14 · D-29 종결) ★★★
   회신 원문: *"배너에서 '상품 판매 시 OnTact Auto BuyBack 으로' 의 문구에 그라데이션
   넣어놨는데 왜 적용이 안됐는지"* — v2.36 이 리더 명세("파랑")를 따르며 상신했던 D-29
   (시안 실측은 그라디언트)가 이 회신으로 뒤집혔다. 시안이 옳았다 — 적용한다.
   · 색 2종은 신설 토큰 경유(--color-hero-grad-start #26AB11 → --color-hero-grad-end
     #0666DA · 시안 문구 자산 끝단 코어 화소 실측 — 근거·대비 검산은 tokens.css 그 자리
     주석 1벌 · designer 등재 상신 D-33). 방향 90deg — 시안의 축은 수평이다('OnTact' 쪽
     초록 → 'BuyBack' 쪽 파랑). 그라디언트 상자는 이 span 하나라 두 줄 h1 에서도 첫 줄
     다크부와 섞이지 않는다.
   · **폴백이 기본 선언이다** — 아래 `color: var(--color-primary)` 가 먼저 서고,
     `background-clip: text` 미지원 브라우저는 @supports 블록 전체를 건너뛰어 v2.36
     상태(파랑 단색 · 밴드 위 4.58:1 ✓)로 열화한다. 지원 브라우저는 @supports 안에서
     텍스트 채움을 투명으로 바꾸고 배경 그라디언트를 글자 모양으로 오린다.
   · `-webkit-text-fill-color` 를 `color: transparent` 대신 쓴다 — color 는 상속·선택
     하이라이트 등 다른 계약을 지고 있어 투명화하면 ::selection 계열에서 글자가 통째로
     사라지는 엔진이 있다. fill-color 는 채움만 바꾼다(프리픽스 포함 전 주류 엔진 지원).
   ⚠ 대비 — 끝 파랑 4.68:1 ✓ / **시작 초록 2.66:1 ✗ (밴드 위 Large Text 3:1 미달)**.
     시안 실측값 그대로이며(사용자 확정 디자인) 임의 하향 보정하지 않았다 — 미달 판정과
     시작색 조정 여부는 designer 상신 D-33(tokens.css 주석 · notes §7). */
.hero__title-brand { color: var(--color-primary); }
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .hero__title-brand {
    background: linear-gradient(90deg,
      var(--color-hero-grad-start), var(--color-hero-grad-end));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
/* ≥768 — 시안 실측 비례로 승격. 국소 미디어쿼리인 이유: 스테이지·제목·여백 세 값이
   한 덩어리의 시안 재현 단위라 §6 블록으로 흩으면 다음 개정에서 따로 움직인다
   (§3-13-b <768 배너 아트 디렉션과 같은 판단). */
@media (min-width: 768px) {
  .hero__stage { padding-block: var(--space-8); min-height: 416px; }
  .hero--index .hero__title { left: var(--space-8); bottom: var(--space-10); }
}

/* ~~v2.8 ⓑ 3D 오브제 좌표~~ — ★ v2.36 참조 0 사문 보존: 마크업 2점이 DOM 제거됐다
   (밝은 밴드 위에 네이비 평탄화 크롭본을 놓을 수 없다 — index.html 취소선 주석 1벌).
   규칙·자산은 원본(투명 배경 · R5-2) 수령 경로가 살아 있어 지우지 않는다. */
.hero__art {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  user-select: none;
  /* 기본은 숨김 — 노출은 ≥1280px 구간에서만 켠다(§6-5). 아래 참조 */
  display: none;
}
/* ★ 좌표는 **뷰포트 중앙 기준 오프셋**이다 — 1904px 실측 좌표를 그대로 박으면 다른 뷰포트에서
   어긋난다. 컨테이너(1200px) 기준이 아닌 이유: 우측 오브제의 우단이 컨테이너 우단을 57px
   넘으므로, 컨테이너에 앵커하면 그 값이 `--container-max` 에 종속돼 컨테이너를 건드리는 순간
   일러스트가 따라 움직인다. 히어로 텍스트가 뷰포트 중앙 정렬이므로 장식도 같은 기준을 쓴다.
   ★ 좌우 비대칭(좌 −592 / 우 +486, 우측만 24px 아래)은 **실수가 아니라 균형 조정**이다 —
     카트는 아래가, 계산기는 위가 무거워 억지로 맞추면 오히려 기울어 보인다. 실측 그대로 쓴다. */
.hero__art--l { left: calc(50% - 592px); width: 144px; }
.hero__art--r {
  left: calc(50% + 486px);
  width: 172px;
  /* 시안 실측 세로 중심 353 = 히어로 중심(329)보다 **24px 아래**. 위 비대칭 근거 참조. */
  transform: translateY(calc(-50% + 24px));
}

/* ★★★ v2.32 — 히어로 배경 영상 레이어 (사용자 직접 지시 2026-08-13) ★★★
   지시 원문: "배너에 영상이 들어갈 수 있게 미리 만들어줘. 영상은 뒷 배경으로 나오고
   위로 텍스트가 나올 것임"

   ★ **영상 파일은 아직 없다** — 스위치는 `.hero--has-video` 클래스 하나이고, 그것을
     켜는 곳은 `js/buyback.js initHeroVideo()` 뿐이다(config `HERO_VIDEO_URL` 주입 시).
     클래스가 없는 동안 아래 has-video 규칙은 전부 무효라 **현행 히어로는 픽셀 하나
     변하지 않는다** — 빈 값 → 미노출 규약(BUYBACK_WALLET_ADDRESS)의 CSS 쪽 절반이다.

   ★ 레이어 설계(아래→위): 밴드 배경(네이비+워시) → 영상 → 스크림 → 텍스트 컨테이너.
     · `isolation: isolate` — 히어로를 스태킹 컨텍스트로 만들어 내부 z-index 가 밖
       (스티키 헤더 --z-header 등)과 셈을 섞지 않게 가둔다. has-video 일 때만 건다.
     · 영상·스크림은 z-index 0 — 같은 층에서는 DOM 순서가 위아래를 정하므로
       (스크림이 영상 다음 형제) 스크림이 영상 위에 얹힌다.
     · 텍스트 컨테이너만 z-index 1 로 승격 — 역시 **has-video 일 때만** 건드린다.
       평시 컨테이너는 비위치 요소 그대로다(수정 범위 밖 불변).
   ★ **음수 z-index 를 쓰지 않는다** — `.hero--index` 는 z-index 없는 relative 라
     스태킹 컨텍스트가 아니었고, 음수 층은 그런 조상 밑으로 가라앉아 **불투명한 밴드
     배경 뒤로 사라진다**(영상이 조용히 안 보이는 사고). isolate + 0/1 승격이 그 함정을
     구조적으로 피한다.
   ★ z-index 0·1 은 `--z-*` 토큰을 쓰지 않는다 — 그 토큰들은 **페이지 전역 층**
     (헤더 100 · 토스트 200)의 자리이고, 이 0·1 은 isolate 로 격리된 히어로 **안에서만**
     뜻을 갖는 국소 순번이라 전역 층과 셈이 섞일 수 없다. 토큰화하면 간접 참조만 늘고
     값의 소유자가 흐려진다(tokens.css 메달색 주석의 *"사용처가 아니라 값이 달라야
     토큰"* 과 같은 판단). */
/* ★★★ v2.36 — 영상을 「전면 배경」에서 「시안의 일러스트 자리」로 옮겼다 ★★★
   (사용자 직접 지시 2026-08-13 저녁 *"배너들은 이미지와 완전히 동일하게"* — 시안 39827
   은 영상=일러스트가 중앙 상자에 서고 그 둘레가 평탄한 밝은 밴드다. 위 v2.32 레이어
   설계(absolute inset + cover + z-index 0/1 + 스크림)는 "전면 배경 영상" 전제였고 그
   전제가 지시로 대체됐다 — 서술은 이력으로 보존하되 아래가 현행이다.)
   폐기 선언 원문 (취소선 보존):
   ~~position: absolute; inset: 0; width/height 100%; object-fit: cover; z-index: 0;~~
   · in-flow block — 스테이지가 상자 크기를 소유하고 영상은 폭을 따른다(aspect 유지).
   · cover → 기본 배율 — 밴드(416px)에 cover 로 채우면 1278×720 영상의 상하가 잘려
     일러스트가 뭉개진다(시안과 정반대). contain 성 배치는 width 100% + height auto 로 충분.
   · pointer-events·aria-hidden 판단은 v2.32 그대로 유효하다. */
.hero__video {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;   /* 순수 장식 — 클릭·포커스 대상이 아니다(v2.32 판단 유지) */
}
/* §5-6 `[hidden]` 무력화 함정 — 지금은 이 블록에 display 선언이 없어 UA 기본으로도
   숨지만, 다음 개정에서 display 를 선언하는 순간 조용히 깨진다. `.hero-figure[hidden]`
   과 같은 규약으로 방어를 미리 박는다(값 주입 전까지 이 요소는 **상시 hidden** 이다). */
.hero__video[hidden] { display: none; }

/* ★★ v2.36 — 아래 `.hero--has-video` 묶음 전체가 **휴면**이다 (참조 0 또는 무해 중복) ★★
   스크림 div·오버라인 칩·서브카피·컨테이너·3D 오브제 2점이 v2.36 시안 재현으로 DOM 에서
   빠졌다(취소선 원문은 index.html 히어로 주석). 클래스 자체는 JS(`initHeroVideo()`)가
   계속 부여하므로 스위치 회로는 살아 있다 — 다크 원형·스크림 복원은 마크업 되돌리기만으로
   끝난다(.mock-banner 전례). `.hero--has-video .hero__title` 색 재정의는 새 base 와 같은
   토큰이라 무해 중복이다. **지우지 말 것** — 이 묶음은 사문이 아니라 대기다.
   ── 이하 v2.32~v2.35 서술 원문 (이력 보존) ──────────────────────────────
   스크림 — 영상 위·텍스트 아래의 오버레이(텍스트 대비 확보용).
   ★ 노출 스위치는 `.hero--has-video` **뿐**이다 — 자체 hidden 속성을 두지 않아 영상과
     스크림의 상태가 갈라질 수 없다(스위치가 하나면 어긋날 방법이 없다). 기본은 미노출 —
     JS 가 죽어도(클래스 미부여) 화면은 현행 히어로 그대로다.
   ~~★ 색은 `--color-bg-deep`(밴드 배경과 같은 네이비) 재사용 · 농도 .55 잠정~~
   ★★★ v2.35 — **라이트 변형으로 전환 (사용자 직접 지시 2026-08-13 · A5 영상 도착)** ★★★
     지시 원문: *"'배너 이미지 수정 (영상 작업중)' → 영상 도착: 히어로 배경 영상으로 반영"*
     — 실물 영상(assets 의 banner-video.mp4 · 1278×720 · 5.0s)을 Playwright 실렌더로
     확인한 결과 **밝은 배경**(연회색 #E8~#F0 계열 · 3D 공장/거래소 일러스트)이고, 시안
     Frame 39827 히어로도 같은 밝은 배경이다. v2.32 의 다크 스크림(.55 네이비)을 그 위에
     얹으면 탁한 회색 화면이 된다 — **시안대로 라이트 변형**을 택했다.
     · 스크림: ~~--color-bg-deep .55~~ → **--color-bg(흰) .6** — 새 색 리터럴 0.
     · 텍스트: 흰(on-dark) → **--color-text 계열** (아래 재정의 3줄).
     ── 대비 실측 (§1-3 방식 · 최악 화소 기준) ─────────────────────────────
       흰 .6 스크림 위 최악 화소(영상 내 순검정 #000 가정) 합성 = #999999 근방
       · --color-text  #16202E / 합성 #999999 = **5.77:1** ✓ (h1 · 서브)
       · 실측 대부분 영역은 연회색(#E8EAF0)이라 합성 후 12:1 이상.
       · 칩은 자체 불투명 배경(--color-info-bg) 위 --color-info = **6.08:1** ✓ (기지 조합)
     ⚠ 이 재정의는 **"이 영상(밝음)" 전제**다 — 어두운 영상으로 교체되면 스크림·텍스트를
       다시 판정해야 한다. designer 스펙 동기화 상신(D-25 갱신 → notes §7 D-26).
     opacity 리터럴은 색이 아니라 상태 계수라 토큰 대상이 아니다(v2.32 판단 유지). */
.hero__scrim { display: none; }
.hero--has-video { isolation: isolate; }
.hero--has-video .hero__scrim {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--color-bg);
  opacity: .6;
}
.hero--has-video .container { position: relative; z-index: 1; }
/* ★ v2.35 — 라이트 변형의 텍스트 재정의. 특정도 (0,2,0)·(0,3,0)이라 기본 on-dark 색
   ((0,1,0)·(0,2,0))을 선언 위치와 무관하게 이긴다. 스위치는 여전히 `.hero--has-video`
   하나 — 영상이 빠지면(클래스 미부여) 다크 히어로 원형으로 자동 복귀한다.
   ★ 서브도 muted 가 아니라 --color-text 다 — muted(#5B6980)는 흰 .6 스크림 위 최악
     합성(#999999)에서 2.1:1 로 무너진다. 위계는 크기(40/18px)와 굵기가 이미 가른다. */
.hero--has-video .hero__title { color: var(--color-text); }
.hero--has-video .hero__sub { color: var(--color-text); }
/* 칩 — 다크 칩(반투명 흰 면 + 흰 글자)은 밝은 영상 위에서 녹는다.
   `.chip--info` 의 검증 조합(--color-info-bg / --color-info · 6.08:1)을 재정의로 얹는다 —
   마크업의 클래스는 그대로 두고(원형 복귀 자동) 색만 상태 스위치를 따라간다. */
.hero--has-video .chip--on-dark {
  background: var(--color-info-bg);
  color: var(--color-info);
}
/* ★ 영상 활성 시 3D 오브제 2점은 숨긴다 — §5-16 ⓑ 자산이 **네이비로 평탄화**돼 있어
   (투명 아님 — 위 hero__art 주석 "다른 배경 위에 재사용하면 안 된다") 영상 위에 얹으면
   네이비 사각형으로 뜬다. 자산 자신의 규약이 근거이며, 원본(투명 배경 · R5-2)이 오면
   이 방침을 재검토한다 — designer 상신 notes v2.32 §7 D-25.
   ⚠ ≥1280px 의 `display: block`(§6-5)보다 **특정도(0,2,0 > 0,1,0)로 이긴다** — 선언
     위치·순서와 무관하게 성립한다(v2.29 D222·v2.30 D226 특정도 사고의 교훈 그대로). */
.hero--has-video .hero__art { display: none; }

/* --- 3-13-b. ranking 히어로 배너 일러스트 (v2.35 · 사용자 직접 지시 2026-08-13 · C1) ----
   지시 원문: *"히어로 CTA 버튼 '정산 대상 확인' — 제거 및 배너 변경"* + 시안 Frame 39828.
   자산·배치·alt 판단은 ranking.html 그 자리 주석에 1벌(공용 서술 금지 규약).

   ★ 전폭 블록 — 컨테이너 밖이라 좌우 이음새가 없다. 남는 이음새는 **윗변 하나**:
     크롭본의 배경(#001334 계열 — 시안이 구운 색)과 밴드 토큰(--color-bg-deep #0F1B2D)이
     달라 경계선이 보인다. ::before 그라디언트가 밴드색 → 투명으로 48px 를 섞는다.
     새 색 리터럴 0 — 그라디언트 시작색은 밴드 토큰 그대로이고, 끝은 transparent
     (모던 브라우저는 premultiplied 보간이라 회색 띠가 생기지 않는다).
   ★ 히어로 하단 여백과의 관계 — `.hero` 의 padding-bottom(--space-16)을 이 변형에서
     **0 으로 걷는다**(아래 첫 줄). 배너 하단이 곧 밴드 하단이어야 하는데(시안), 패딩이
     남으면 배너 아래 네이비 띠가 생긴다. 걷어낸 --space-16 은 **wrap 의 margin-top 으로
     자리를 옮겼다**(텍스트 ↔ 배너 간격) — 총 여백량은 보존되고 위치만 바뀐다.
   ⚠ `.hero--top20 { min-height: 340px }`(§6-4)는 이 배너로 실렌더가 훨씬 넘으므로
     **완전 사문**이 됐다 — 삭제는 designer 판단으로 미룬다(notes §7 D-27). */
/* ⚠⚠ 선택자를 **두 클래스로 겹쳐** 쓴다 — `.hero--top20` 한 개로는 진다. `.hero` 가
   §6 반응형 블록(768~1023 · <768)에서 `padding-block` 을 **다시 선언**하고 그 블록들이
   파일 뒤에 있어, 클래스 1개끼리는 나중 선언이 이긴다(`.section__head--center` 가 v2.29 에
   실렌더로 확인한 것과 같은 함정). (0,2,0)은 순서·구간과 무관하게 이긴다. */
/* ★★★ v2.36 — 밴드 = 배너 단독 (사용자 직접 지시 2026-08-13 저녁 · 시안 39828 완전 일치) ★★★
   h1 sr-only·서브 DOM 제거로(경위는 ranking.html 주석) 밴드에 배너 말고는 높이를 가진
   요소가 없다 — **배너의 4변이 곧 밴드의 4변**이다. 그래서:
   · padding-bottom 0 → **padding-block 0** (상단 패딩까지 걷는다 — 남으면 배너 위 네이비 띠).
   · wrap margin-top ~~var(--space-16)~~ → **0** — "서브카피 ↔ 배너 간격"의 서브카피가 없다.
   · ~~::before 상단 블렌드(밴드색 → 투명 48px)~~ → **규칙 제거** — 배너 위 밴드 노출면이
     사라져 이음새 자체가 없고, 남겨 두면 배너 윗변 48px 를 어둡게 물들여 시안을 왜곡한다.
     폐기 선언 원문 (취소선 보존 · 복원 시 wrap 이 position: relative 를 이미 갖고 있다):
     ~~content:"" · position:absolute · inset: 0 0 auto 0 · height: var(--space-12) ·
       background: linear-gradient(180deg, var(--color-bg-deep), transparent) · pointer-events:none~~ */
.hero.hero--top20 { padding-block: 0; }   /* 배너가 밴드 전체를 마감한다 (v2.36) */
.hero__banner-wrap {
  position: relative;                 /* 복원 대비 보존 — 현재 자손 absolute 없음 */
  margin-top: 0;                      /* v2.36 — 위 주석 참조 */
}
.hero__banner {
  display: block;
  width: 100%;
  height: auto;
}
/* <768px — 원본 비율(4.63:1)대로면 360px 에서 78px 스트립이 되어 일러스트가 뭉개진다.
   높이를 고정하고 cover 로 중앙(트로피 포디움)을 살린다 — 좌우가 잘리는 아트 디렉션이며
   잘리는 것은 여백·다이어그램 일부다(정보 손실은 alt 가 보완 · notes §7 D-27 상신).
   ★ 180px 는 색·폰트·간격이 아니라 **레이아웃 치수**다 — `.hero--top20 min-height: 340px`
     (§6-4)와 같은 성격의 리터럴이라 하드코딩 금지 규칙의 대상이 아니다. */
@media (max-width: 767px) {
  .hero__banner {
    height: 180px;
    object-fit: cover;
    object-position: center;
  }
}

/* ==========================================================================
   4) 페이지 — index.html (OnTact Buyback)
   ========================================================================== */

/* ③ 누적 결과 — 기간 구분 토글 + 표시 항목 5종 (레이아웃 §3 ③)
   숫자를 담는 트랙은 예외 없이 minmax(0, …) — `1fr` 은 최소폭이 min-content 라
   줄바꿈 불가한 긴 수치가 트랙을 밀어내 "타일 동일 크기"를 조용히 깨뜨린다. */
/* ★★★ v2.45 — .stat-strip 계열(--s2/--s3 계단 포함) **사문** (현황 1b 재구축) ★★★
   #result-grid 는 이제 .stat1b(§3-5-c)다 — 계단 기구도 js 쪽에서 휴면(buyback.js
   UNIT_SCALE_CHARS 배너). §6-3(2열)·§6-5(4열)의 열 수 규칙도 함께 사문이다(각 자리
   주석). 보존 사유는 §3-5-b v2.45 배너와 같다. */
.stat-strip {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--grid-gutter);
  transition: opacity var(--transition-fast);
}
/* 구간 전환 로딩 — 스켈레톤을 쓰지 않는다. 이전 렌더를 낮은 불투명도로 유지하고 교체하면
   레이아웃이 점프하지 않는다(기획서 §4.2 로딩 UX. 차트의 .is-swapping 과 같은 규칙). */
.stat-strip.is-swapping { opacity: .4; }
/* 값 크기 계단 — 수치 타일 중 **유효 자수가 가장 큰 하나**가 스트립 전체 크기를 정한다.
   컨테이너에서 토큰 자체를 갈아끼우므로 계산 지점은 1곳뿐이다(§2-5).
   ★ v2.19 — 수치 타일이 **1개 → 3개**(`매출`·`바이백 수량`·`평균 매수 체결가`)로 돌아왔다
     (사용자 재지시 2026-08-10). **§2-5 의 원래 전제가 그대로 복귀했다** — 세 값이 한 줄을
     나눠 가지며 *"유효 자수가 가장 큰 하나가 스트립 전체 크기를 정한다"* 는 경쟁 관계가
     다시 성립한다. ≥1280 타일 내부폭도 588px → **234px 실측**(문서 기록값 232.00px 대비
     +2px · 6-5 블록 주석 참조)으로 돌아와, 경계표(12·15자)와 환산 실측이 세워진 조건과
     사실상 일치한다. **경계값·CSS·환산 상수는 v2.13 이래 불변**이고
     이번에도 손대지 않았다 — 바뀐 것은 호출부가 넘기는 원소 수(1 → 3)뿐이다.
   ~~v2.18 — 수치 타일이 3개 → 1개가 되며 이 장치가 "그 한 타일의 자기 폭 방어"로만 남았다.~~
     → 취소선 보존. 그때 **기구를 지우지 않고 남긴 판단** 덕분에 이번 복원이 호출부
       원소 3개로 끝났다(CSS·경계값 무변경).
   ★ v2.13(D111) — 판정 입력이 *최장 값 문자열* 에서 **유효 자수 = 값 자수 + 단위 환산 자수** 로
     바뀌었다. 단위 폭이 타일마다 다르고(` USDT` 39.89px / ` OnTact` 48.84px) **계단을 내려도
     줄지 않으므로**, 값 문자열만으로는 넘침을 예측할 수 없다(실측 근거·환산 상수는
     `js/buyback.js UNIT_SCALE_CHARS`). 아래 경계 자수는 불변이다. */
.stat-strip--s2 { --font-size-stat: var(--font-size-stat-2); }  /* 유효 12~14자 */
.stat-strip--s3 { --font-size-stat: var(--font-size-stat-3); }  /* 유효 15자 이상 */

/* 거래소 타일 — 문자열이므로 .num 미적용 */
.exchange-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: var(--font-size-h3);
  font-weight: var(--font-weight-semibold);
}
/* 이더스캔 타일 — 주소 문자열 + 외부 링크 버튼.
   ※ v2.9 — 이 두 규칙을 쓰는 마크업은 **현재 없다**(타일 잠정 제외, D87).
     삭제하지 않고 남긴다: 재도입이 마크업 복원 한 단계로 끝나야 한다.
     사용처가 다시 생기기 전까지 값을 바꾸지 말 것(바꿔도 화면에 나타나지 않는다). */
.addr {
  margin-top: var(--space-2);
  font-family: var(--font-family-mono);
  font-size: var(--font-size-small);
  word-break: break-all;
}
.addr-action { margin-top: var(--space-4); }

/* ③-b 추이 그래프 (누적 바이백 금액 영역 차트)
   ★ 카드에 height 를 고정하지 않는다 — SVG 높이에 x축 라벨 밴드가 이미 포함돼 있고,
     고정 높이는 축 라벨을 배제해 카드 안에 세로 스크롤을 만든다.
   ★ 색은 전부 차트 토큰 경유. 축·눈금·툴팁 텍스트에 시리즈 색을 쓰지 않는다. */
.chart-card { margin-top: var(--space-6); }
.chart-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.chart-card__title { font-size: var(--font-size-h3); font-weight: var(--font-weight-bold); }
.chart-card__sub {
  margin-top: var(--space-2);
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
}
.chart-card__unit {
  margin-bottom: var(--space-2);
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);
}
.chart-plot {
  position: relative;   /* 툴팁 기준 상자 */
  width: 100%;
  transition: opacity var(--transition-fast);
}
/* 재렌더 시 스켈레톤을 쓰지 않는다 — 이전 렌더를 낮은 불투명도로 유지하고 교체한다 */
.chart-plot.is-swapping { opacity: .4; }
.trend__svg { display: block; }

.trend__grid      { stroke: var(--color-chart-grid); stroke-width: 1; }
.trend__axis      { stroke: var(--color-chart-axis); stroke-width: 1; }
.trend__area      { fill: var(--color-chart-area); }
.trend__line      { fill: none; stroke: var(--color-chart-series); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.trend__dot       { fill: var(--color-chart-series); stroke: var(--color-bg); stroke-width: 2; }
.trend__crosshair { stroke: var(--color-chart-crosshair); stroke-width: 1; }
.trend__hit       { fill: transparent; }
/* 축 눈금 — 시리즈 색이 아니라 텍스트 토큰을 쓴다 */
.trend__tick {
  fill: var(--color-text-muted);
  font-size: var(--font-size-caption);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}
.trend__tick-bg { fill: var(--color-bg); }

.chart-tip {
  position: absolute;
  z-index: var(--z-toast);
  max-width: 240px;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  background: var(--color-bg-deep);
  color: var(--color-text-on-dark);
  box-shadow: var(--shadow-lg);
  pointer-events: none;
}
/* 값이 먼저, 라벨은 뒤 — 독자는 이미 시리즈를 알고 숫자를 원한다 */
.chart-tip__value {
  font-size: var(--font-size-body-lg);
  font-weight: var(--font-weight-bold);
  white-space: nowrap;
}
.chart-tip__value .num__unit { color: var(--color-text-muted-on-dark); }
.chart-tip__meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-1);
  font-size: var(--font-size-caption);
  color: var(--color-text-muted-on-dark);
  white-space: nowrap;
}
.chart-tip__key {
  flex: 0 0 12px;
  width: 12px; height: 2px;
  border-radius: 1px;
  background: var(--color-chart-series);
}

/* 폴백 안내 — 오류 박스가 아니라 상태 설명 1줄 */
.chart-fallback {
  margin-bottom: var(--space-4);
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
}

/* 거래소 셀 — 데스크톱은 문자열(.num 미적용), 카드 전환 시 CSS로 칩이 된다 */
.exchange-name { font-weight: var(--font-weight-medium); }

/* ④ 건별 6열 표 열 폭 (데스크톱 ≥1024px) — 합 100
   선언 순서 = 화면 열 순서(실행 일자 · 거래소 · 체결 가격 · 매수 수량 · 구매금액 · 누적 금액).
   폭 자체는 열이 이동해도 그대로다 — 폭은 값의 자릿수에 맞춘 것이지 위치에 맞춘 것이 아니다.

   ★ `.col-sale` 은 이름과 화면 라벨이 **일부러 다르다.** 한 짝으로 읽을 것:
       클래스 `.col-sale`  ↔  API 필드 `sales`  ↔  내부 키 `item.saleAmount`  ↔  **화면 라벨 `구매금액`**
     라벨만 2026-07-30 사용자 지시로 `판매금액` → `구매금액` 이 됐고 **클래스·필드는 유지**한다 —
     라벨을 따라 클래스를 고치면 서버 규격과의 대응이 끊긴다. **유지가 정답**이며 결함이 아니다
     (notes D69 · designer 레이아웃 §3 ④ v2.4 승인 · QA 12차 판정).
     같은 짝 설명이 `index.html` thead 와 `js/buyback.js rowNode()` 에도 있다 — 세 곳을 함께 고칠 것.
     ※ 카드 모드의 `::before` 라벨은 6-1 블록에 따로 있다(같은 문자열이어야 표↔카드가 같은 표다). */
/* ★ v2.28 — `누적 금액` 열 제거(PPT S5)로 **6열 → 5열**. 빠진 21% 를 한 열이 통째로
   흡수하지 않고 **수치 3열에 나눠** 실었다: 셋 다 단위 span 이 새로 붙어(지시 ④)
   종전 폭으로는 값+단위가 한 줄에 안 들어간다. 합 100% = 24+13+21+21+21. */
/* ★★ v2.30 — **건별 표 열 제목만 가운데 정렬** (사용자 정정 2026-08-12).
   ★ 범위가 `thead` 안으로 한정된다 — **셀 값 정렬은 그대로다**(날짜·거래소 좌측 /
     금액·가격·수량 우측).
   ⚠⚠ **`thead th` 로는 이기지 못한다 — 실렌더로 확인했다.** 아래 `.col-price` 등은
     **클래스 2개**(0,2,0)인데 `thead th` 는 클래스 1 + 타입 2(0,1,2)라 **특정도에서 진다**
     (뒤에 와도 소용없다). 처음 그렇게 썼더니 금액·가격·수량 세 열의 헤더가 **우측 정렬
     그대로**였고, 좌측 두 열만 가운데로 갔다. → **같은 클래스 수(0,2,1)로 맞춰** 이긴다.
   ⚠⚠ **헤더와 값의 정렬이 갈린다는 것을 알고 넣는다.** 표 관례는 *"숫자 열은 헤더도
     우측"* 이고, 가운데 헤더 아래 우측 정렬 숫자가 오면 둘의 시각 축이 어긋난다.
     실렌더로 확인한 결과 **열 폭이 넓어(21%씩) 헤더가 값 위에 뜬 것처럼 보이는 구간이
     생긴다** — 특히 `매수 수량`(마지막 열)에서 두드러진다. 그럼에도 **사용자 지시가
     우선**이므로 반영하고, 시각 정합 판단은 designer 에 상신했다(notes §7 D-22).
   ★ **랭킹 2종 표에는 적용하지 않았다.** 지시가 건별 표를 지목했고, 랭킹 표는 구조가
     다르다(순위 뱃지 열 + 4열/3열). 확신 없이 함께 바꾸면 **요청되지 않은 변경**이
     두 표에 더 생긴다 — 일관성 판단은 상신으로 올린다(리더 지침: *"확신 없으면 건별만"*). */
.data-table--buyback thead .col-date,
.data-table--buyback thead .col-exchange,
.data-table--buyback thead .col-sale,
.data-table--buyback thead .col-price,
.data-table--buyback thead .col-qty { text-align: center; }

/* ★ v2.28-1 — 선언 순서를 **화면 열 순서와 맞춘다**(실행 일자 · 거래소 · 집행 금액 ·
   체결 가격 · 매수 수량). CSS 는 선언 순서로 열을 정하지 않지만, 이 목록이 곧 다음
   사람이 열 순서를 확인하는 자리라 **읽는 순서가 화면과 같아야** 한다.
   폭은 무변경(합 100% = 24+13+21+21+21). */
.data-table--buyback .col-date     { width: 24%; }
.data-table--buyback .col-exchange { width: 13%; }
.data-table--buyback .col-sale     { width: 21%; text-align: right; }
.data-table--buyback .col-price    { width: 21%; text-align: right; }
.data-table--buyback .col-qty      { width: 21%; text-align: right; }

/* ⑤ 상세 안내 링크(노션)는 §3-10 슬림 링크 컴포넌트를 그대로 쓴다 — 전용 CSS 없음.
   구 ⑤ 규칙 5카드 · 구 ⑥ 4단계 흐름의 CSS(카드 그리드·단계 카드·화살표·예시 블록)는
   C6 노션 이관으로 참조가 사라져 전부 삭제했다(주석 보존 금지 — 되살아난다). */

/* ==========================================================================
   5) 페이지 — ranking.html (탭: Top 20 정산 / 정식: TOP 20 추가 정산)

   ★★★ v2.45-B — 이 구획(5~5-d)의 랭킹 패널 계열 규칙은 **전부 사문(적용 대상 0)** ★★★
   ranking.html 본문이 Coming Soon 블록으로 교체됐다(사용자 지시 2026-09-29 · 사양 §4 ·
   원문 보존 notes §4-be D291). 사양의 처분이 *"삭제하지 말고 휴면 처리"* 라 규칙을
   지우지 않는다 — `.mock-banner`(v2.26)·`.site-footer`(v2.21) 전례 그대로, 복원이
   마크업 복구 하나로 끝나게 두는 보존이다. 대상: 히어로 총액(.hero-figure — 마크업은
   히어로에 남아 있으나 hidden 상시)·랭킹 표 2종·포디움(5-d)·게이트 패널(5-c)·세그먼트
   탭 변형·패널 설명(5-d)·§6-2 카드 전환·메달 토큰 계열. 생성기 게이트도 "CSS 존치"를
   전제로 재작업됐다(생성기 v2.45-B 블록 — CSS 부재가 아니라 마크업 부재를 검사).
   ⚠ 신규 Coming Soon 규칙은 아래 **5-e** 블록이다 — 이 사문 배너의 대상이 아니다.
   ========================================================================== */

/* ⚠⚠ v2.24-1 — **이 규칙은 현재 참조가 0이다.** 기간 배지 칩 묶음이 히어로를 떠나
   정산 패널로 이관되면서(designer v2.7 §4 ② 판정 B) 두 HTML 어디에도 `hero__chips`
   가 없다(실측). index 히어로가 쓰는 것은 `.hero__overline`(별개 규칙)이다.
   ★ **삭제하지 않고 남긴 이유**: 판정 B 는 *"자리와 색만 바꾼다"* 는 이관이지 히어로
     칩 슬롯의 폐지가 아니고, 이 사이트는 총액 블록 마크업·`min-height` 선언을 같은
     이유로 존치해 왔다. **다만 여기에 표시가 없으면 다음 사람이 살아 있는 규칙으로
     읽는다** — 삭제 여부는 designer 판단이다(notes §7 경미 상신).
   ⚠ 되살릴 일이 생기면 **`justify-content: center` 가 히어로 전용 전제**임을 볼 것 —
     패널 쪽 이관분은 좌측 정렬이라 `.rank-panel__chips` 로 따로 잡았다(§5-d). */
.hero__chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-6);
}

/* ② 히어로 대형 수치 — 공동 정산 누적 총액 (v2.21 신설 · 2026-08-11 사용자 직접 지시)
   *"현재 top 20 추가 정산의 자리에 올리고 크게 보였으면 함."* / *"자리만 크게, 값은 `—`."*

   ★ **지표 히어로의 표준 3단**이다: 라벨(작게) → 값(가장 크게) → 캡션(작게).
     종전 ③-a 카드가 쓰던 `.stat__label`/`.stat__value`/`.stat__caption` 을 **그대로 쓰지
     않은 이유**는 그 세 규칙이 전부 **밝은 카드 위 전제**이기 때문이다 —
     `.stat__label`·`.stat__caption` 은 `--color-text-muted`(밝은 배경용)를 직접 물고
     있어 네이비 밴드 위에서 대비가 무너진다. `.on-dark` 하위 재정의를 새로 6줄 쓰느니
     **다크 밴드 전용 3줄**을 쓰는 편이 짧고, 카드 규칙을 건드리지 않아 index 가 안전하다.
   ★ 새 토큰 0개. 크기는 `.num--hero`(§2-4 파생) 하나뿐이고 나머지는 기존 토큰 조합이다.
   ★ 값 자리는 **값이 없어도 줄어들지 않는다**(사용자 확정). `—` 는 `.is-pending` 점선
     표기이며, 값 행 높이를 `.num--hero` 와 맞춰 값이 도착해도 세로 점프가 없다
     (index 타일의 `.stat__value .is-pending` 과 같은 장치·같은 사유). */
.hero-figure { margin-top: var(--space-6); }
/* ★★ v2.23-1 — **값이 없으면 블록 통째로 사라진다**(사용자 피드백 2026-08-11:
     *"추후에 다시 넣는 것으로 변경"*). `hidden` 은 `js/ranking.js` 가 값이 있을 때만 푼다.
     규칙을 명시하는 이유: 이 블록에 `display` 를 선언할 일이 생기면 브라우저 기본
     `[hidden]` 이 곧바로 무력해진다(`.gate-panel[hidden]`·`.table-footnote__link[hidden]`
     과 같은 방어). ⚠ 아래 크기 규칙들의 *"자리만 크게"* 사유는 **v2.21 것이고 지금은
     값이 있을 때만 적용된다** — 빈 자리를 크게 남기는 규약은 이 지시로 폐기됐다. */
.hero-figure[hidden] { display: none; }
.hero-figure__label {
  font-size: var(--font-size-body-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-muted-on-dark);
}
/* ★ 크기를 **값이 아니라 자리(컨테이너)** 에 건다. 이유가 이번 지시에 그대로 들어 있다 —
     *"자리만 크게, 값은 `—`."* 크기를 `.num--hero`(값 노드)에만 걸면 값이 있을 때만
     자리가 커지고, `—` 인 지금은 자리가 쪼그라들어 **지시와 정반대**가 된다.
     컨테이너가 크기를 소유하면 `—` 든 `1,250,000,000원` 이든 **같은 크기의 같은 자리**를
     차지하고, 값이 도착해도 세로 점프가 없다(index 타일의 N-01 장치와 같은 목적). */
.hero-figure__value {
  margin-top: var(--space-3);
  color: var(--color-text-on-dark);
  font-size: calc(var(--font-size-hero) * 1.2);   /* `.num--hero` 와 같은 식 — §2-4 주석에 근거 */
  line-height: var(--line-height-num);
  /* overflow 를 걸지 않는다(visible 유지) — `.is-pending` 점선 상자 위쪽이 잘린다
     (§3-5 `.stat__value` 와 같은 사유 · v1.3 N-03). 넘침 방지는 크기로 푼다. */
  min-width: 0;
}
/* 대기 표기도 **값과 같은 크기**로 둔다(축소 금지 — 위 주석의 `자리만 크게`).
   `.on-dark .is-pending` 이 색·테두리를 이미 다크 밴드용으로 바꿔 놓았다. */
.hero-figure__value .is-pending { font-size: inherit; line-height: inherit; }
.hero-figure__caption {
  margin-top: var(--space-3);
  font-size: var(--font-size-small);
  color: var(--color-text-muted-on-dark);
  line-height: var(--line-height-snug);
}

/* ③-a 공동 정산 누적 총액 (v2.15 신설 — 2026-08-04 사용자 지시)
   ★ **전용 타이포를 만들지 않았다.** 마크업이 index ③-a 지표 타일과 같은
     `.card` + `.stat__label`/`.stat__value`/`.stat__caption` 이라 라벨·값·캡션의
     크기·색·간격이 전부 §3-5 공용 규칙에서 온다. 이 블록이 더하는 것은
     **폭(전폭 1장)과 표와의 간격**뿐이다 — 새 토큰 0개.
   ★ `.stat-strip` 의 계단(`--font-size-stat-2/-3`)은 쓰지 않는다. 그 장치는 타일 3개가
     한 줄을 나눠 가질 때 **가장 긴 값 하나가 전체를 낮추는** 문제를 푸는 것이고,
     여기는 전폭 1장이라 값이 경쟁할 상대가 없다. 360px·24px 기준으로도 15자
     (`420,000,000원` 수준의 2배)까지 들어간다 — 계단을 끌어오면 근거 없는 축소가 된다. */
.settlement-total { margin-bottom: var(--space-6); }
/* 로딩 표시는 **스켈레톤**이다 — 이 페이지의 로딩 언어는 표의 스켈레톤 행이고
   `—` 대기 표시는 한 곳도 없다(index 타일과 다른 점. 그쪽은 `—` 가 기본값이다).
   높이를 값의 실제 행 높이(폰트 × --line-height-num)로 맞춰 값이 도착해도 세로 점프가 없다. */
.settlement-total .stat__value .skeleton-bar {
  height: calc(var(--font-size-stat) * var(--line-height-num));
  max-width: 12ch;
}

/* ③ Top 20 표 열 폭 (≥768px) — **3열, 합 100%**
   ★ v2.15 — `판매 실적`(`.col-sales` 31%) 열이 빠졌다(2026-08-04 사용자 지시).
     비는 31% 를 판매자 열이 통째로 흡수하게 두지 않고 **재배치**했다: 그러면 판매자 값
     (`김*옥` 4자)과 우측 정렬된 금액 사이가 화면 절반 넘게 비어 두 값이 한 행으로
     읽히지 않는다. 대신 남은 금액 열을 31% → **38%** 로 올렸다 — 이 페이지의 주제이자
     이제 **유일한** 금액 열이고, 1~3위에서 `--font-size-h3`/900 으로 커지는 열이라
     제 폭을 갖는 편이 맞다.
   ★ 판매자 열만 width:auto 인 것은 그대로다 — 식별 방식에 따라 값 길이가 크게 다르므로
     (`김*옥` 3자 / `U-10482` 7자 / `김*옥(…1234)` 11자) 폭을 고정하면 어느 한 방식에서
     반드시 어긋난다(C7·레이아웃 §4 ③).
   ★ **합 100%** = 12(순위) + 50(판매자 — 잔여, 명시하지 않는다) + 38(추가 정산 금액). */
/* ★ v2.28 — `누적 정산 실적` 열 신설(PPT S4)로 **3열 → 4열**. 금액 38% 를 두 금액 열이
   나눠 갖는다(28+28) — 둘 다 우측 정렬 금액이라 같은 폭이어야 자릿수가 세로로 맞는다.
   합 100% = 12(순위) + 32(판매자 · 잔여) + 28 + 28. */
.data-table--top20 .col-rank  { width: 12%; min-width: 88px; }
.data-table--top20 .col-name  { width: auto; min-width: 120px; }   /* 잔여 32% */
.data-table--top20 .col-perf  { width: 28%; min-width: 150px; text-align: right; }
.data-table--top20 .col-extra { width: 28%; min-width: 150px; text-align: right; }

/* 식별 표기(displayId) — 서버가 완성해 내려준 문자열을 그대로 렌더한다.
   ★ 말줄임(text-overflow: ellipsis) 폐기: 식별자를 자르면(`U-104…`) 다른 사람으로
     오독될 수 있다 — 절삭은 사실 왜곡이라는 원칙이 여기에도 그대로 적용된다.
     길면 줄바꿈해 행 높이가 늘어나는 편이 낫다. */
.display-id {
  display: inline-block;
  max-width: 100%;
  vertical-align: middle;
  overflow-wrap: anywhere;
}

/* 1~3위 강조 (v2.2 상향) — 강조를 **색이 아니라 크기·굵기·마커**로 만든다.
   금·은·동 메타포는 여전히 쓰지 않는다(이 페이지는 시상이 아니라 정산 공개다).
   대신 상위 3행을 한 덩어리로 크게 만들어, 색을 못 보는 사용자에게도
   물리적 크기로 먼저 읽히게 한다(레이아웃 §4 ③). */
/* ★★ v2.26 — **매출 랭킹 표에도 같은 강조를 건다** (사용자 직접 지시 ② · 2026-08-12).
     지시 원문: *"매출 랭킹도 1~3위 효과 적용."*
   ⚠⚠ **designer v2.7 §4 ②-b 「판정 D」(매출 표 강조 없음)를 사용자가 대체했다.**
     판정 D 의 근거는 *"강조의 근거는 값의 확정성이다 — 예상 1위를 굳혀 놓으면 다음
     집계에 내려간 사람에게 「떨어졌다」는 서사가 생긴다"* 였고, 그 서사 위험은
     **사라지지 않았다.** 사용자가 그 위험을 알고도 대칭을 택한 것으로 처리한다
     (지시가 판정보다 위다). designer 상신 — notes v2.26 §7 **D-9**.
   ★ 판정 D 의 **전제 A 는 계속 지킨다** — 매출 패널 각주 ⓐⓑ(*"예상 순위"*·*"집계
     시점에 따라 달라집니다"*)를 **그대로 둔다.** 강조가 들어올수록 그 두 줄이 더
     필요해진다: 화면이 순위를 무겁게 그릴수록 *"확정이 아니다"* 를 말하는 자리가
     사라지면 안 된다(writer §6 #51 — 금액이 걸린 화면의 고지는 재량으로 덜지 않는다).
   ★ **비대칭이 의도라던 종전 규약은 무효다** — QA 는 이제 두 표 모두에서
     `tr.is-top` **각 3건**을 기대해야 한다(종전: 매출 0건이 정상). §5-b 배너도 갱신했다.
   ★ 선택자를 **묶어서** 쓴다. 두 표가 같은 규격이어야 하는데 블록을 복제하면
     다음 개정에서 한쪽만 바뀐다(§5-b 가 열 폭을 맞춰 둔 것과 같은 이유).
     금액 열만 이름이 다르다(`.col-extra` / `.col-revenue`). */
.data-table--top20 tbody tr.is-top,
.data-table--sales-rank tbody tr.is-top {
  background: var(--color-primary-tint);
}
/* 좌측 4px 인셋 마커 — brand / primary-tint = 3.37:1 (비텍스트 3:1 충족, §1-3 34행).
   세 행이 하나의 블록으로 묶여 읽히게 하는 장치다.
   ★ tr 에 건 box-shadow 는 border-collapse: collapse 인 표에서 페인트되지 않는다.
     첫 셀에 걸면 셀 좌변 = 행 좌변이라 렌더 결과가 스펙과 동일하다(카드 모드는 tr 이
     display:grid 라 아래 6-2 에서 tr 자신에게 건다). */
/* ★ v2.26 — 인셋 마커는 **--color-brand 그대로**다. 메달색으로 바꾸지 않았다:
     이 마커는 §1-3 34행에 `brand / primary-tint = 3.37` 로 등재된 **비텍스트 3:1
     대상**인데, 메달 3색은 틴트 위에서 1.38~2.74 라 전부 미달한다. 메달색은
     **자기 위에 순위 숫자가 얹히는 자리에만** 쓴다(tokens.css 실측 블록의 경계). */
.data-table--top20 tbody tr.is-top > td:first-child,
.data-table--sales-rank tbody tr.is-top > td:first-child {
  box-shadow: inset 4px 0 0 var(--color-brand);
}
/* 가장 강한 신호 — 스캔 중 크기 차이가 색보다 먼저 잡힌다 (일반 행 56px) */
.data-table--top20 tbody tr.is-top td,
.data-table--sales-rank tbody tr.is-top td { height: 72px; }
.data-table--top20 tbody tr.is-top .col-name,
.data-table--sales-rank tbody tr.is-top .col-name {
  font-size: var(--font-size-body-lg);
  font-weight: var(--font-weight-bold);
}
/* 추가 정산 금액을 키운다 — 이 페이지의 주제다.
   ※ v2.15 이전에는 이 규칙에 *"판매 실적은 일반 규격 유지 — 두 금액을 동시에 키우면
     초점이 흩어진다"* 는 단서가 붙어 있었다. 금액 열이 하나만 남아 **단서가 소멸**했고
     규칙 자체는 그대로다(선택자·값 무변경).
   (카드 모드의 body-lg/700 선언보다 특정도가 높아 두 모드에 모두 적용된다) */
.data-table--top20 tbody tr.is-top .col-extra .num--amount,
.data-table--sales-rank tbody tr.is-top .col-revenue .num--amount {
  font-size: var(--font-size-h3);
  font-weight: var(--font-weight-black);
}
@media (hover: hover) and (pointer: fine) {
  .data-table--top20 tbody tr.is-top:hover,
  .data-table--sales-rank tbody tr.is-top:hover { background: var(--color-primary-tint); }
}

/* ④ 공개 고지 (표 각주) — C6 잔존분.
   ★ `.table-note`(표 **위** 1줄 + aria-describedby 연결용)를 재사용하지 않는다.
     여기는 표 **아래** 3줄 + 링크이고 성격이 각주다 — 한 클래스로 묶으면 조건 분기가 생긴다.
     다만 타이포 규격(caption / muted)은 동일하게 맞춰 두 고지가 같은 위계로 읽히게 한다.
   섹션이 아니라 표에 딸린 각주이므로 ③ 표와 같은 밴드·같은 컨테이너(--container-data) 안에 둔다. */
.table-footnote {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-4);
  list-style: none;
  font-size: var(--font-size-caption);
  color: var(--color-text-muted);          /* 5.56:1 ✓ AA */
  line-height: var(--line-height-snug);
}
/* ⓒ만 한 단계 올린다(16.4:1). 크기는 caption 그대로 두어 각주 위계는 지킨다 —
   개인 식별 정보를 공개하는 화면에서 그 근거·범위를 말하는 줄이 가장 읽기 쉬워야 한다(R2·R18). */
.table-footnote__scope { color: var(--color-text); }
/* ⓓ 링크 줄은 고지 3줄에서 한 단계 떼어 놓는다(gap --space-2 + 이 여백 = --space-3) */
.table-footnote__link { margin-top: var(--space-1); }
.table-footnote__link[hidden] { display: none; }

/* ==========================================================================
   5-b) ②-b 매출 랭킹(예상) 표 — v2.22 신설 (사용자 직접 지시 2026-08-11)

   ★ **새 컴포넌트를 만들지 않았다.** `.data-table` · `.table-wrap` · `.table-footnote` ·
     `.state-block`/`.notice` 를 그대로 쓰고, 이 블록이 더하는 것은 **열 폭 3줄과
     카드 모드 3줄**뿐이다. 두 표가 같은 컨테이너(--container-data)에서 같은 위계로
     읽혀야 하므로 타이포·경계선·행 높이를 따로 만들 이유가 없다.
   ★ 열 폭은 Top 20 과 **같은 값**(12 / 잔여 50 / 38)이다. 우연이 아니라 맞춘 것이다 —
     세 열의 성격이 같고(순위 · 식별 표기 · 우측 정렬 금액) 두 표가 같은 페이지에서
     위아래로 붙어 있어, 폭이 어긋나면 **같은 열이 어긋난 위치에서 시작**한다.
   ★★ v2.26 — **강조 규칙이 뒤집혔다. 이 표도 정산 표와 같은 규격이다.** ★★
     ~~1~3위 강조(`.is-top`)를 이 표에는 **걸지 않는다.** 예상치라 순위가 새로고침마다
       흔들릴 수 있는데 시상대처럼 강조하면 그 흔들림이 오해를 키운다.~~
     ~~→ `designer v2.7 §4 ②-b 판정 D 승인` (2026-08-11 · builder D-1 종결) — 위 사유가
        그대로 승인됐고 세 선택지 중 ⓐ(유지)로 확정됐다.~~
     ~~⚠ 비대칭이 의도임을 QA 가 알아야 한다 — 이 표에 `tr.is-top` **0건**·상위권
        sr-only 문구 **0건**이 정상이다.~~
     → **2026-08-12 사용자 직접 지시 ②(*"매출 랭킹도 1~3위 효과 적용"*)가 판정 D 를
       대체했다.** 규칙 본문은 §3-5 `.is-top` 블록이 **두 표 공용 선택자**로 소유한다.
     ⚠⚠ **QA 기대값이 정반대로 바뀌었다** — 이제 **두 표 모두** `tr.is-top` **각 3건** ·
       상위권 sr-only **각 3건**이 정상이다. 종전 기준(매출 0건)으로 검사하면
       정상 산출물이 FAIL 로 잡힌다. 「검사 방향 반전」 사고를 되풀이하지 않기 위해
       생성기 게이트도 같은 라운드에 함께 뒤집었다(build-share-snapshot.py §랭킹 ⑨).
     ★ 판정 D 의 **전제 A 는 계속 유효하고 계속 지킨다** — 매출 패널에 *"예상치"* 성격
       서술이 화면에 최소 1줄(현재 각주 ⓐⓑ 2줄) 남아 있어야 한다. 강조가 들어온
       지금은 그 요구가 **더 강해졌다.** 각주를 지우지 말 것.
     ★ 열 폭 3줄은 **무변경**이다 — 두 표가 같은 규격이라는 이 블록의 원래 취지가
       강조까지 확장됐을 뿐이다.
   ========================================================================== */
.data-table--sales-rank .col-rank    { width: 12%; min-width: 88px; }
.data-table--sales-rank .col-name    { width: auto; min-width: 160px; }   /* 잔여 50% */
.data-table--sales-rank .col-revenue { width: 38%; min-width: 200px; text-align: right; }

/* ==========================================================================
   5-d) 상위 3위 포디움 — ★★ v2.26 신설 (사용자 직접 지시 ③ · 2026-08-12) ★★

   지시 원문: *"1~3위를 포디움(시상대) 스타일로 표시하고 금(1위)·은(2위)·동(3위) 색을
   랭크 뱃지·강조에 적용."* 권장 형태까지 지시에 포함됐다 — *"표 위에 상위 3인 포디움
   블록(2위-1위-3위 배치, 메달 색 뱃지+이름+금액, 1위 중앙·가장 높게)."*

   ★ **두 랭킹 패널이 같은 컴포넌트 1벌을 쓴다.** 매출·정산 어느 표 위에도 같은 마크업이
     들어가고, 다른 것은 금액 값의 출처뿐이다(JS 가 주입). 두 벌을 만들면 §5-b 가 열 폭에서
     겪은 갈라짐이 여기서도 일어난다.
   ★ **새 토큰은 메달 3색뿐**이다(tokens.css). 치수·간격·모서리·글꼴은 전부 기존 토큰이고
     4px 스케일 밖 리터럴은 **0개**다 — 단 높이 64/48/32px 는 --space-16/12/8 이다.
     예외는 모바일의 `44px`(터치 타깃 규격 · 기존 카드 모드 grid 트랙과 같은 값)뿐이다.

   ── 왜 `aria-hidden="true"` 인가 (a11y 판단의 핵심) ─────────────────────────
     이 블록은 **바로 아래 표의 상위 3행을 시각적으로 다시 그린 것**이다. 표는 같은 3인을
     순위·판매자·금액 3열로 **완전한 형태**로 이미 낭독하고, 그 세 행에는 sr-only
     `상위 3위 이내` 가 붙어 있다(writer §8 #41). 즉 포디움이 낭독에 **더하는 정보가 0** 이고,
     읽히게 두면 같은 사람 셋을 연달아 두 번 듣게 된다.
     ★ 포커스 가능한 요소가 하나도 없어(링크·버튼 0개) `aria-hidden` 이 포커스를 가두는
       사고도 일어나지 않는다.
     ⚠⚠ **이 판단이 성립하는 전제: 표가 같은 패널에 함께 있다.** 표를 감추고 포디움만
       남기는 변형을 만들면 **그 순간 데이터가 보조기술에서 사라진다.** 그래서 JS 는
       포디움을 **표 행을 그리는 바로 그 함수 안에서** 만든다 — 둘이 갈라질 수 없게
       코드 경로를 하나로 묶었다(`ranking.js renderPodium()` 호출 지점 주석).

   ── 배치 ─────────────────────────────────────────────────────────────────
     DOM 순서는 **1위 → 2위 → 3위**(의미 순서)이고, 화면의 2-1-3 은 `order` 로만 만든다.
     ★ 순서 뒤바꿈이 안전한 이유: 각 단에 **순위 숫자가 인쇄**돼 있어 어느 칸이 몇 위인지
       위치에 의존하지 않는다(WCAG 1.3.2 의 의미 순서는 DOM 이 지킨다).
   ── 색 ───────────────────────────────────────────────────────────────────
     메달 3색은 **자기 위에 순위 숫자를 얹은 채로만** 나타난다(단 + 표 뱃지). 대비는
     --color-text 기준 8.80 / 10.38 / 5.22 로 전부 4.5:1 통과 — 실측·근거는 tokens.css.
   ========================================================================== */
.podium {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));   /* 금액 트랙 — minmax(0,·) 전역 규칙 */
  align-items: end;                 /* 바닥을 맞춰야 1위가 가장 높이 선다 */
  gap: var(--grid-gutter);
  margin: 0 0 var(--space-8);
  padding: 0;
  list-style: none;
}
/* §5-6 `[hidden]` 무력화 함정 — `display: grid` 를 선언했으므로 반드시 따라온다.
   포디움은 상위 3행이 없을 때(0건·로드 실패) JS 가 `hidden` 으로 끈다. */
.podium[hidden] { display: none; }

.podium__item {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* 시각 배치 2-1-3 (지시 원문). DOM 은 1,2,3 그대로다. */
.podium__item--r1 { order: 2; }
.podium__item--r2 { order: 1; }
.podium__item--r3 { order: 3; }

/* 카드 — 단 위에 얹히므로 아래 모서리·아래 테두리를 없애 한 덩어리로 보이게 한다 */
.podium__card {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: var(--space-4);
  text-align: center;
  min-width: 0;
}
/* 1위만 카드도 한 단계 두껍게 — 높이 차이를 단(壇)에만 맡기지 않는다 */
.podium__item--r1 .podium__card { padding-block: var(--space-6); }

.podium__name {
  display: block;
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
  line-height: var(--line-height-snug);
  /* 식별 표기는 길이가 방식마다 다르다 — 자르지 않고 줄바꿈한다(`.display-id` 와 같은 규약) */
  overflow-wrap: anywhere;
}
.podium__value {
  display: block;
  margin-top: var(--space-2);
  min-width: 0;
}
.podium__item--r1 .podium__value .num--amount {
  font-size: var(--font-size-body-lg);
  font-weight: var(--font-weight-black);
}

/* 단(壇) — 메달 면 + 순위 숫자. 색이 정보를 단독으로 지지 않게 숫자를 얹는다. */
.podium__base {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  color: var(--color-text);
  font-size: var(--font-size-step);      /* 20px 고정 — 미디어 쿼리 재정의 없는 토큰 */
  font-weight: var(--font-weight-black);
  line-height: var(--line-height-num);
}
.podium__item--r1 .podium__base { height: var(--space-16); background: var(--color-medal-gold); }
.podium__item--r2 .podium__base { height: var(--space-12); background: var(--color-medal-silver); }
.podium__item--r3 .podium__base { height: var(--space-8);  background: var(--color-medal-bronze); }

/* ==========================================================================
   5-c) 버튼 게이트 + 모자이크 패널 — v2.22 신설 (사용자 직접 지시 2026-08-11)
        *"버튼 형식으로 해서 누르면 데이터 수집 중이라는 문구와 함께 뒤의 내용은 모자이크"*

   ★ **블러는 시각 효과일 뿐이다** — DOM 을 가리지 못한다(복사·소스 보기·CSS 해제로
     원문이 그대로 나온다). 그래서 이 패널 뒤에는 **실데이터를 두지 않는다**(스켈레톤 바).
     이 CSS 는 *"가림"* 을 구현하는 것이 아니라 *"수집 중임을 보여 주는"* 연출이다.
     보안 경계는 마크업·JS 쪽에 있다(`ranking.html` ③-b 주석 · `TOP20_TABLE_LOCKED`).
   ========================================================================== */

/* 게이트 버튼 줄 — 표가 있던 자리를 대신하므로 표와 같은 간격(--space-6)을 둔다.
   가운데 정렬: 눌러야 다음이 열리는 유일한 장치라, 좌측에 붙이면 섹션 부제의
   연장선처럼 읽혀 버튼임이 약해진다.
   ★★ v2.23 — **마크업에서 이 클래스가 사라졌다**(「보기」 버튼 게이트를 탭이 대체).
     규칙은 `.settlement-total`(v2.21)·`.site-footer`(v2.21)와 **같은 규약으로 남겨 둔다** —
     되살릴 때 마크업만 되돌리면 되도록. 적용 대상이 없으므로 아무것도 꾸미지 않는다.
     ※ 아래 `.gate-panel*` 는 **살아 있는 규칙**이다(모자이크는 그대로 쓴다). */
.gate-actions {
  display: flex;
  justify-content: center;
  margin-top: var(--space-6);
}

.gate-panel { margin-top: var(--space-6); }
.gate-panel[hidden] { display: none; }

/* 블러 덩어리와 오버레이를 같은 자리에 겹친다 */
.gate-panel__stack { position: relative; }

/* 모자이크 본체.
   ★ `filter: blur()` 는 **자기 자식만** 흐리게 한다 — 오버레이를 이 안에 두면 문구까지
     함께 뭉개지므로 형제로 뺐다(그래서 __stack 이 필요하다).
   ★ `pointer-events: none` + `user-select: none` 은 보안 장치가 **아니다**(위 배너 참조).
     흐린 글자를 선택·클릭하려는 헛시도를 막는 UX 장치일 뿐이다. */
.gate-panel__blur {
  filter: blur(5px);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

/* 「데이터 수집 중」 — 흐린 표 위에 얹히는 실제 텍스트.
   ★ 배경 판을 깔지 않으면 블러 위에서 대비가 무너진다. 판은 --color-bg 불투명이라
     본문 대비(16.4:1)가 그대로 유지된다 — 반투명으로 두면 뒤 스켈레톤 명도에 따라
     대비가 흔들려 AA 를 보증할 수 없다.
   ★ 크기는 h3(20px / <768px 18px). 히어로 수치와 경쟁하지 않으면서 표 위에서
     제일 먼저 읽힐 만큼은 크다. */
.gate-panel__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: var(--space-4);
  text-align: center;
}
/* ★★ v2.25 결함 수정 — `[hidden]` 재선언 누락 (디자인 시스템 §5-6 무력화 함정) ★★
   이 규칙의 `display: flex` 가 UA 기본 `[hidden] { display: none }` 을 **덮어써서**,
   `js/ranking.js unmask()` 가 `dom.collecting.hidden = true` 로 오버레이를 꺼도
   **화면에서는 꺼지지 않았다.** 그 결과 잠금이 풀린 실표 위에 「데이터 수집 중」 카드가
   그대로 떠 있었다 — `unmask()` 주석이 *"오버레이만 남으면 실데이터 위에 「데이터 수집 중」이
   덮여 **거짓말**을 한다"* 고 경고한 바로 그 상태다. **JS 는 옳았고 CSS 가 그것을 무력화했다.**
   ⚠ 발견 경위: v2.25 live 전환 후 실렌더 검증. 표 중앙(약 y+600)에 떠서 **첫 화면 캡처에
     잡히지 않았고**, 스크롤해 히트 테스트(`elementFromPoint`)로야 드러났다. 위쪽만 보는
     검증으로는 못 잡는 종류라 검증 스크립트에도 그 지점을 남겼다.
   ※ v2.23~v2.24(demo)에서도 같은 상태였을 것이다 — 이번 라운드가 만든 결함이 아니라
     이번 라운드가 **드러낸** 결함이다. §5-6 이 `.gate-panel` 에는 재선언을 달게 했으면서
     `__overlay` 를 빠뜨린 것이 원인이다. */
.gate-panel__overlay[hidden] { display: none; }
.gate-panel__overlay > span {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: var(--space-4) var(--space-6);
  font-size: var(--font-size-h3);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-snug);
  color: var(--color-text);
  max-width: 100%;
}

/* ==========================================================================
   5-d) 랭킹 세그먼트 탭 + 패널 — v2.23 신설 (사용자 직접 지시 2026-08-11 · 와이어프레임)
        *[매출 랭킹(예상)] [정산 랭킹] 두 버튼이 나란히 → 그 아래 한 콘텐츠 영역*

   ★ **새 컴포넌트를 만들지 않았다.** 버튼 줄은 기존 세그먼트 토글(§3-7 · 디자인 시스템
     §5-13)을 그대로 쓰고, 이 블록이 더하는 것은 **전폭 2등분 변형 + 패널 여백/설명문**
     뿐이다. 활성 상태 색·굵기는 §3-7 의 한 규칙이 `aria-pressed`·`aria-selected` 를
     함께 받는다 — 두 곳에 같은 색을 적어 두면 언젠가 갈라진다.
   ★ 전폭 2등분인 이유: 와이어프레임이 두 버튼을 **나란히 같은 크기**로 그렸다. 내용
     길이에 따라 폭이 달라지면(`매출 랭킹(예상)` 이 `정산 랭킹` 보다 길다) 둘 중 하나가
     기본값처럼 커 보인다 — 동등한 선택지는 동등한 면적으로 보여야 한다.
   ========================================================================== */

.segmented--tabs { width: 100%; }
/* 두 칸을 정확히 반씩 — `flex: 1 1 0` 은 내용 길이를 무시하고 남은 폭을 균등 분배한다
   (`1 1 auto` 로 두면 긴 라벨 쪽이 넓어진다). 모바일 규칙(§6-2)과 **같은 값**이라
   전 뷰포트에서 폭이 흔들리지 않는다.
   ★★ v2.35 — 탭 타이포 승격 (사용자 직접 지시 2026-08-13 · C2) ★★
   지시 원문: *"랭킹 세그먼트 탭(판매 실적 순위/정산금 순위): 글씨 크기 키우기, 색 잘
   보이게"*
   · 크기: ~~--font-size-small(14px)~~ → **--font-size-body(16px)**. (0,2,0)이라 §6-2 의
     모바일 축소(`--font-size-caption` · (0,1,0))도 순서와 무관하게 이긴다 — 이 탭은
     360px 에서도 16px 다(두 라벨 실측으로 넘침 없음 확인 · 검증 §8).
   · 비선택 색: ~~--color-text-muted(4.83:1)~~ → **--color-text(14.7:1)** + semibold —
     선택(파랑 면+흰 글자)과의 대비 축이 "색 vs 무채"로 더 벌어진다. 선택 상태 규칙은
     공용 한 벌(§3-7) 그대로 — index 기간 토글은 이 변형 밖이라 **무변**(지시가 지목한
     것은 랭킹 세그먼트 탭뿐이다).
   ⚠⚠ color 는 **:not([aria-selected="true"]) 로 한정**한다 — 이 규칙(0,2,0)이 §3-7 의
     선택 상태 규칙(0,2,0)보다 **파일 뒤에 있어**, color 를 무조건 선언하면 특정도 동률
     후순위 승리로 **선택 탭의 흰 글자를 어두운 글자로 덮어쓴다**(파랑 면 위 2.8:1 사고 —
     v2.29 D222 특정도 사고와 같은 계열이라 선례대로 선택자에서 원천 차단). */
.segmented--tabs .segmented__btn {
  flex: 1 1 0;
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-semibold);
}
.segmented--tabs .segmented__btn:not([aria-selected="true"]) {
  color: var(--color-text);
}

/* 패널 — 탭 줄과의 간격은 표·상태 블록이 쓰는 --space-6 과 같게 둔다.
   ★ `tabindex="0"` 을 준 컨테이너라 포커스 링이 필요하다. 기본 상태에서 매출 패널에는
     포커스 받을 요소가 하나도 없어(안내문 한 줄), 이 링이 없으면 키보드 사용자가
     "지금 어디에 있는지"를 알 수 없다. 안쪽에 그린다 — 패널이 컨테이너 폭을 꽉 채워
     바깥 오프셋은 잘려 보인다.
   ※ 색·굵기는 §1 의 공통 포커스 링(`[tabindex]:focus-visible` — 3px)이 이미 준다.
     여기서는 **오프셋만** 뒤집는다(`.segmented__btn:focus-visible` 와 같은 방식 · 리터럴
     -3px 도 그 줄과 같은 값이다). 토큰을 새로 지어내지 않는다 — 포커스 링 굵기는 토큰이
     없고 §1 이 리터럴로 정의한 값이라, 여기서만 토큰을 만들면 두 값이 갈라진다. */
.rank-panel { margin-top: var(--space-6); }
.rank-panel[hidden] { display: none; }
.rank-panel:focus-visible { outline-offset: -3px; }

/* 패널 설명문 — 종전 `.section__sub`(제목 아래 부제)와 **같은 타이포**다. 클래스를 새로
   판 이유: 이제 이 줄 위에 제목이 없다(제목은 탭 라벨이고 h2 는 sr-only). `.section__sub`
   는 `margin-top: --space-2` 로 제목에 붙는 것이 전제라, 패널 첫 줄에 쓰면 위쪽이 어중간하게
   벌어진다. 값(크기·색)은 같은 토큰을 쓰므로 두 줄이 화면에서 같은 위계로 읽힌다. */
.rank-panel__desc {
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
}

/* ★★ v2.29 — 정산금 순위 **설명 4줄** (사용자 지시 5·6) ─────────────────────
   ★ 지시 6: **크기를 판매 실적 순위 설명과 같게.** 위 `.rank-panel__desc` 와 같은
     토큰(`--font-size-small`)을 쓴다 — 값을 베끼지 않고 같은 토큰을 가리켜, 한쪽이
     바뀌면 다른 쪽도 따라오게 한다(두 패널이 같은 위계로 읽혀야 한다는 것이 지시의 요지).
   ★ 색은 **줄마다 다르다**(지시 5): 리드 1줄만 muted, 나머지 3줄은 본문색.
     리드는 *"이 표가 무엇인가"*, 나머지는 **산정·지급 규칙**이라 위계가 다르다.
   ★ `list-style: none` — 번호·불릿을 붙이지 않는다. 네 문장은 순서가 있는 절차가
     아니라 **병렬 서술**이고, 불릿이 붙으면 각주(`.table-footnote`)와 위계가 섞인다. */
.rank-panel__desc-list {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--font-size-small);
  color: var(--color-text);
  line-height: var(--line-height-snug);
}
/* 리드 1줄만 옅게 — 대비 5.56:1 ✓ AA (옅어져도 규격 안이다) */
.rank-panel__desc-lead { color: var(--color-text-muted); }
/* 집계 기간 줄 — ★ v2.30: **다시 칩이다**(사용자 정정). `<li>` 자신이 `.chip.chip--info`
   이므로 색·테두리·치수는 §3-4 공용 칩 규격이 그대로 준다. 여기서 더하는 것은
   **그리드 안에서의 자리 두 줄**뿐이다.
   ★ `justify-self: start` — 부모가 `display: grid` 라 아이템이 **전폭으로 늘어난다.**
     칩은 내용 폭이어야 하므로 시작 쪽으로 붙인다(없으면 화면 폭만큼 늘어난 칩이 된다).
   ★ 위아래 여백을 조금 더 준다 — 칩은 텍스트 줄보다 시각 무게가 커서 목록의 기본
     `gap`(--space-1)만으로는 앞뒤 문장에 끼인 듯 보인다.
   ⚠ `[hidden]` 재선언은 §3-4 의 `.chip[hidden] { display: none }` 이 이미 갖고 있다
     (칩이 `inline-flex` 라 필요한 그 규칙) — 여기서 다시 선언하지 않는다. */
.rank-panel__desc-period {
  justify-self: start;
  margin-block: var(--space-1);
}
/* ★★ v2.38 — 규칙 3줄 불릿 (사용자 직접 지시 2026-08-14 · 항목 6) ★★
   지시 원문: *"정산금 순위에서 아래 내용 앞에 점 하나 넣어서 구분감 있게 해줘"*
   ★ 위 v2.29 배너의 `list-style: none` 근거(*"병렬 서술이라 불릿 없음 · 각주와 위계 혼동"*)는
     이 지시로 **지목된 세 줄에 한해 대체**됐다 — 목록 전체가 아니라 규칙 3줄
     (`.rank-panel__desc-rule`)에만 마커를 되살린다. 리드·집계 기간 칩 줄은 종전 그대로다.
   ★ `display: list-item` + `disc` — ul/li 시맨틱이 이미 있으므로 ::before 가짜 점이 아니라
     **진짜 리스트 마커**를 쓴다. 낭독은 li 그대로라 무변이고 시각만 바뀐다.
   ★ 들여쓰기 --space-4 는 outside 마커가 패널 좌변 밖으로 나가지 않게 하는 자리다.
     줄바꿈 시 둘째 줄이 마커 뒤 본문 기선에 맞는 행잉 형태 — 360px 실렌더 확인(§4-av D259).
   ★ 마커 색은 본문과 같은 --color-text — 세 줄의 글자색과 같은 토큰이라 별도 대비 논점이
     없다(점은 글자의 연장이지 독립 신호가 아니다). */
.rank-panel__desc-rule {
  display: list-item;
  list-style: disc outside;
  margin-inline-start: var(--space-4);
}
.rank-panel__desc-rule::marker { color: var(--color-text); }

/* 패널 안 칩 줄 — v2.24-1 신설 (designer v2.7 §4 ② 판정 B 이관 규격)
   designer 가 지정한 배치: *"패널 B 안, `.rank-panel__desc` 아래 · ③-a 총액 블록 위 /
   위 --space-4 · 아래 --space-6"*.
   ⚠ **`.hero__chips` 를 재사용할 수 없어 규칙을 따로 잡았다** — 그쪽은 히어로 전제라
     ① `margin-top: --space-6`(스펙은 --space-4) ② `margin-bottom` 없음(스펙은 --space-6)
     ③ `justify-content: center` 로 **세 값이 전부 어긋난다.** 특히 ③ 은 왼쪽 정렬인
     패널에서 칩만 가운데 뜨게 만든다(바로 위 설명문·아래 표가 전부 좌측 정렬이다).
   ★ **신규 컴포넌트가 아니다** — 칩 자체는 §3-4 공용 규격 그대로이고 이 규칙이 더하는
     것은 **줄 배치 3값**뿐이다. 신규 토큰 0.
   ★ ③-a 총액 블록은 v2.21 에 히어로로 올라가 지금 이 패널에 없다 — 그래서 아래 여백은
     실제로는 `.gate-panel`(표·모자이크) 과의 사이가 된다. **총액이 패널로 돌아오면
     그 사이에 들어가고 이 규칙은 그대로 맞는다**(designer 가 적은 순서 그대로다). */
.rank-panel__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
  margin-bottom: var(--space-6);
}

/* ==========================================================================
   5-e) ★★★ v2.45-B — 판매자 랭킹 Coming Soon (사용자 지시 2026-09-29 · 사양 §4) ★★★

   ★★ v2.46-1 (U-26 ⑤ · 2026-09-30) — **사문.** 판매자 랭킹 페이지 자체가 제거돼
   (ranking.html = 리다이렉트 스텁 · 구 본문 원문은 notes §4-bf D295) 이 블록의 적용
   대상이 0 이 됐다. §5 랭킹 패널 계열과 같은 사문 보존이다 — Coming Soon 화면을
   되살릴 일이 생기면 notes D295 원문 복구 + 이 블록이 그대로 다시 선다(규칙 무변).

   ranking.html 히어로 아래 본문 전체를 대체하는 단일 블록. 수치·색은 전부 사양 §4
   확정치다(High-fidelity — 배경 #ECF0F6 · min-height 720/520 · gap 16/12 · 칩 30 ·
   제목 40/26·800 · 본문 17/14 · 버튼 48/44 · padding 0 22 · radius 10 · 15px/700).
   · 색은 신규 0 — 전부 기존 토큰 값 일치 재사용(tokens v2.45-B 주석의 대비 검산 1벌:
     ⚠ 본문 muted/#ECF0F6 4.44:1 — 17px 일반 텍스트 4.5:1 에 0.06 미달 · 사양 색
     그대로 실음 · designer 상신 D-37).
   · 세로 중앙 + 내부 column flex — 사양 *"가운데 정렬 · 세로 gap 16(모바일 12)"*.
     min-height 는 사양 확정치 리터럴(720/520 — 뷰포트 파생이 아니라 고정값이 사양이다).
   · 버튼은 기존 `.btn` 을 쓰지 않는다 — 치수 3종(높이 48 · padding 0 22 · 15px)이
     전부 `.btn` 스케일(--space 배수·small/body) 밖의 사양 확정치라, 수식 클래스로
     덮으면 `.btn` 개정이 이 버튼을 조용히 끌고 간다(D88 상수 분리와 같은 판단).
     포커스 링·터치 타깃(48≥44 ✓)은 전역 규칙이 그대로 준다.
   · `[hidden]` 재선언이 없다 — 이 블록은 display 를 선언하지만 hidden 토글 대상이
     아니다(정적 상시 블록 · §5-6 함정 목록의 등재 조건 미해당 — 생성기 _sel 루프 밖). */

.coming-soon {
  display: flex;
  align-items: center;
  background: var(--color-hero-band);       /* 사양 #ECF0F6 — v2.36 등재 토큰 값 일치 */
  min-height: 720px;                        /* 사양 §4 — <768 은 520 (아래 미디어) */
  padding-block: var(--space-12);           /* 낮은 뷰포트에서 내용이 변에 붙지 않게 */
}
.coming-soon__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);                      /* 사양 16 — <768 은 12 */
}
.coming-soon__chip {
  display: inline-flex;
  align-items: center;
  height: 30px;                             /* 사양 §4 확정치 */
  padding: 0 14px;                          /* 사양 확정치(4px 배수 밖 — 22px 와 같은 층위) */
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg);
  color: var(--color-primary);
  font-size: var(--font-size-caption);      /* 13px */
  font-weight: var(--font-weight-bold);
  letter-spacing: 0.08em;                   /* 사양 확정치 — 자간 토큰 스케일 밖 */
}
.coming-soon__title {
  font-size: var(--font-size-coming-title); /* 40 → 26 (tokens 계단) */
  font-weight: var(--font-weight-black);
  color: var(--color-text);
}
.coming-soon__body {
  font-size: var(--font-size-coming-body);  /* 17 → 14 (tokens 계단) */
  color: var(--color-text-muted);
  line-height: var(--line-height-snug);
}
.coming-soon__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 48px;                             /* 사양 §4 — <768 은 44 */
  padding: 0 22px;                          /* 사양 확정치(4px 배수 밖) */
  border-radius: var(--radius);
  background: var(--color-primary);
  color: var(--color-on-primary);
  font-size: var(--font-size-coming-cta);   /* 15px/700 */
  font-weight: var(--font-weight-bold);
  text-decoration: none;
  margin-top: var(--space-2);               /* 본문과 버튼 사이 — gap 16 + 8 (시각 위계) */
  transition: background var(--transition-fast);
}
.coming-soon__cta:hover { background: var(--color-primary-dark); }

@media (max-width: 767px) {
  .coming-soon { min-height: 520px; }
  .coming-soon__inner { gap: var(--space-3); }   /* 사양 모바일 12 */
  .coming-soon__cta { height: 44px; }            /* 사양 모바일 — 터치 타깃 44 유지 ✓ */
}

/* ==========================================================================
   6) 반응형 — mobile-first 기본 스타일 위에 min-width 로 확장
      표 → 카드 전환만 max-width 로 내려 잡는다. 두 표의 임계가 다르다:
      건별 6열 = 1024px / Top 20 3열 = 768px (레이아웃 §0-4, 의도된 차이)
      ※ Top 20 은 v2.15 에서 4열 → 3열. **임계는 그대로 768px** 이다 — 열이 하나 줄어
        더 좁은 폭까지 표로 버틸 수는 있지만, 임계를 내리면 카드 전환 검증(360·375·767)이
        전부 다시 돌아야 하고 얻는 것은 없다. 근거 없는 변경을 얹지 않는다.
   ========================================================================== */

/* --- 6-0. 헤더 반응형 3구간 (★ v2.8 — 디자인 시스템 §5-3 표) --------------
   높이·아이콘은 토큰이 계단을 만든다(`--header-h` 124/88/64 · `--brandmark-size` 32/28).
   여기서는 **글자 크기 2건 + 모바일 워드마크 처리**만 한다.
   ⚠ 시안에는 모바일 뷰가 없다 — 아래 두 구간은 designer 설계이며 실측이 아니다. */

/* ★★ v2.25-2 — 이 블록에 **`min-width: 768px` 하한을 넣었다** (designer v2.8.1 조건부 판정) ★★
   ~~`@media (max-width: 1023px)`~~ → `@media (min-width: 768px) and (max-width: 1023px)`

   **왜 하한이 필수인가 — 파생 토큰이 두 번 접히는 사고.**
   `calc(var(--font-size-h2) * 0.8)` 은 *"이 구간의 h2 는 30px 이다"* 를 전제로 24px 를 만든다.
   그런데 `--font-size-h2` 는 **<768px 에서 24px 로 재정의**되므로(tokens.css), 하한이 없으면
   그 구간에서 `24 × 0.8 = **19.2px**` 가 되어 **규격에 없는 값**이 나온다.
   ⚠⚠ **이 결함은 실렌더 검사로 잡히지 않는다** — <768px 에서 워드마크는 `.sr-only` 라
   화면에 안 보이고, 넘침·대비·스크린샷 어디에도 흔적이 남지 않는다. **선언문을 직접 읽거나
   `getComputedStyle` 로 값을 캐물어야** 드러난다(실측으로 확인: 360/390/767 세 폭 전부 19.2px).
   → 지금은 시각적으로 무해하지만, **`.sr-only` 를 걷는 순간(또는 모바일에 워드마크를 되살리는
     순간) 깨진 크기가 그대로 화면에 나온다.** 잠복한 사고라 값이 옳을 때 막아 둔다.
   ★ 하한을 넣으면 <768px 에서는 기본 선언 `font-size: var(--font-size-h2)` 가 그대로 살아
     **24px**(그 구간의 h2)로 떨어진다 — 세 구간이 30 / 24 / 24 로 연속된다.
   ★ **규칙 (파생 토큰을 쓸 때):** 참조하는 토큰이 미디어 쿼리에서 재정의되는지 먼저 보고,
     재정의된다면 **그 파생이 자기 구간 밖으로 새지 않게 하한/상한을 건다.**
     (§1-3 브레이크포인트 규칙이 `--color-brand` 면 위 폰트에 대해 세운 것과 **같은 종류**다.)
     ── **v2.25-2 전수 점검 결과: 이 선언 하나뿐이었다.** 나머지 `calc` 파생 4건은 전부
        **전역 규칙**이고 토큰의 반응형 값을 **따라가는 것이 의도**라 정상이다:
          · `[id] scroll-margin-top` ← `--header-h`(124/88/64) — 앵커가 헤더를 따라야 한다
          · `.num--hero` · 총액 블록 `× 1.2` ← `--font-size-hero`(40/28) — 48/33.6px 설계값(D160)
          · `.gate-panel` 높이 ← `--font-size-stat`(30/24) — 스켈레톤이 값 크기를 따라야 한다
        **구간에 갇혀야 하는 파생**과 **따라가야 하는 파생**의 차이가 이 점검의 판정 기준이다. */
@media (min-width: 768px) and (max-width: 1023px) {
  /* ★ v2.8 ⓒ — 히어로 하단 여백 80 → 48px (`--section-py` 가 이 구간에서 80px 다).
     ※ <768px 는 아래 블록이 `var(--section-py)` 상하(56/56)로 따로 지정한다 — 하한이 생겨도
       그 구간이 비지 않는다(원래도 아래 블록이 이 값을 덮어쓰고 있었다). */
  .hero { padding-block: var(--section-py) var(--space-12); }

  /* 워드마크 30 → 24px. 24px 는 이름 있는 타이포 토큰이 아니라(`--font-size-h2` 는 이 구간에서
     아직 30px 다) **기존 토큰 파생**으로 임시 처리했다 — 임의 리터럴을 심지 않기 위해서다.
     ★ designer 에 정식 토큰 추가를 상신했다(notes §7 D-1 「토큰 추가 대기」).
     ⚠ 위 하한 주석을 반드시 함께 읽을 것 — 이 파생이 하한 없이는 <768 에서 19.2px 가 된다. */
  .brand__word { font-size: calc(var(--font-size-h2) * 0.8); }
  /* 내비 20 → 16px = `--font-size-body` 정확히 일치(파생 불요).
     ※ <768px 는 아래 블록이 `--font-size-small`(14px)로 따로 지정한다. */
  .site-nav__link { font-size: var(--font-size-body); }
}

@media (max-width: 767px) {
  /* ★ v2.8 ⓒ — 이 구간은 **무변경**이다(`--section-py` 56px 상하). 이미 얕아 더 줄이면
     다크 밴드가 "띠"로 보이는 하한(--space-14 56px)에 닿는다. 위 두 구간의 하단 축소를
     여기서 **되돌리는** 선언이라 생략하면 안 된다(상속되면 48px 로 남는다). */
  .hero { padding-block: var(--section-py); }

  /* ★ 워드마크를 `display: none` 하지 **않는다** — `.sr-only` 규격으로 전환한다.
     `.brand` 링크의 접근 이름이 이 텍스트 하나뿐이고(`.brand__mark` 는 alt="" 장식),
     `display:none` 이면 **링크에 이름이 없어진다**(스크린리더가 `"링크"` 로만 읽는다).
     ※ §77 `.sr-only` 와 같은 선언이다. 클래스 교체를 JS 로 하지 않는 이유: 뷰포트에
       따른 시각 표현이므로 CSS 의 일이고, JS 가 죽어도 접근 이름은 남아야 한다. */
  .brand__word {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  /* ~~내비 16 → 14px = `--font-size-small`. 360px 검산: 아이콘 28 + 내비 약 223 = 251 < 328 ✓~~
     ★★ v2.45-B — 사양 §3 모바일 계단으로 교체: **메뉴 13px(--font-size-caption) ·
     내비 gap 8(--space-2)** (사양 원문: *"nav gap 8, 메뉴 글자 13px — 390px 폭에서
     넘치지 않게"*). 토글(pill + 버튼 2)이 내비에 더해져 종전 14px/16px 로는 390 에서
     줄이 넘친다 — 390 실측 검증은 notes §8 v2.45-B 표. */
  .site-nav__link { font-size: var(--font-size-caption); }
  .site-nav { gap: var(--space-2); }
  /* v2.45-B — 토글 모바일 계단 (사양 §3: 높이 28 · padding 0 7 · 12px/700 — 폰트는
     tokens 의 --font-size-lang 이 이 구간에서 12px 로 내려간다 · 7px 는 사양 확정치 리터럴) */
  .lang-toggle__btn { height: 28px; padding: 0 7px; }
}

/* --- 6-1. 건별 6열 표 → 카드 (<1024px) -------------------------------- */

@media (max-width: 1023px) {
  .data-table--buyback,
  .data-table--buyback tbody,
  .data-table--buyback tr,
  .data-table--buyback td { display: block; }

  /* thead 는 스크린리더용으로 남긴다 (마크업 제거 아님) */
  .data-table--buyback thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .data-table--buyback tbody td {
    height: auto;
    padding: 0;
    border-bottom: 0;
  }
  /* 데스크톱 열 폭(%)을 카드 모드에서 확실히 해제한다.
     `.data-table--buyback tbody td`(클래스1+타입2)는 `.data-table--buyback .col-*`(클래스2)보다
     특정도가 낮아 width 를 되돌리지 못한다 — 같은 형태의 선택자로 덮어야 한다. */
  /* ⚠⚠ v2.28 사고 기록 — **이 목록의 마지막 줄이 선언 블록을 이고 있다.**
     `누적 금액` 열을 지우면서 종전 마지막 줄(`… .col-total { width: auto; min-width: 0; }`)을
     통째로 지웠더니, 남은 다섯 선택자가 **선언을 잃고 바로 아래 `tbody tr` 규칙에 흡수**됐다.
     결과: 모든 `td` 가 `display: grid` 가 되고 열 폭 해제가 사라져 **360px 에서 문서 가로
     스크롤**이 생겼다(실측 378 > 360). CSS 는 문법 오류를 내지 않고 조용히 다른 뜻이 된다 —
     **그룹 선택자에서 줄을 뺄 때는 그 줄이 `{ }` 를 이고 있는지 먼저 볼 것.** */
  .data-table--buyback .col-date,
  .data-table--buyback .col-exchange,
  .data-table--buyback .col-sale,
  .data-table--buyback .col-price,
  .data-table--buyback .col-qty { width: auto; min-width: 0; }

  .data-table--buyback tbody tr {
    display: grid;
    /* 두 트랙 모두 minmax(0, …) — 레이아웃 §0-2 전역 규칙.
       `auto` 트랙을 쓰면 1/-1 로 스팬하는 2~5행(라벨+값, 둘 다 nowrap)의
       min-content 기여가 전부 auto 트랙으로 쏠려 트랙이 카드 밖까지 밀린다
       (실측: 360px 에서 거래소 칩이 23px 넘침). 2fr:1fr 로 나누면
       실행 일자(≈100px)와 거래소 칩(≈74px)이 360px 에서도 각 트랙에 들어간다.
       (v2.4: 값에서 시각이 빠져 필요 폭이 오히려 줄었다 — 트랙 비율은 그대로 안전하다.) */
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    row-gap: var(--space-2);
    column-gap: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--color-bg);
  }
  @media (hover: hover) and (pointer: fine) {
    .data-table--buyback tbody tr:hover { background: var(--color-bg); }
  }

  /* 1행: 실행 일자 | 거래소 */
  .data-table--buyback .col-date {
    grid-column: 1;
    font-weight: var(--font-weight-semibold);
    text-align: left;
  }
  .data-table--buyback .col-exchange { grid-column: 2; justify-self: end; }
  .data-table--buyback .exchange-name {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding-inline: var(--space-2);
    border-radius: var(--radius-full);
    background: var(--color-info-bg);
    color: var(--color-info);
    font-size: var(--font-size-caption);
    font-weight: var(--font-weight-semibold);
    letter-spacing: var(--letter-spacing-label);
    white-space: nowrap;
  }

  /* 2~5행: 라벨(td::before) | 값 — **행 순서는 마크업 순서가 정한다**(자동 배치).
     열 순서 변경(2026-07-30 사용자 지시)으로 카드 행도 체결 가격 → 매수 수량 → 구매금액 → 누적 금액
     순이 된다. 여기서 `order` 로 되돌리지 않는다 — 시각 순서와 DOM(스크린리더) 순서가 갈리면
     같은 표가 두 가지 순서로 읽힌다. */
  /* v2.28-1 — 카드에서도 집행 금액이 먼저 온다. **DOM 순서가 그대로 시각 순서**이므로
     여기서 `order` 를 쓰지 않는다(시각 순서와 낭독 순서가 갈리면 같은 표가 두 가지
     순서로 읽힌다 — 이 블록의 원래 규약 그대로다). */
  .data-table--buyback .col-sale,
  .data-table--buyback .col-price,
  .data-table--buyback .col-qty {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: right;
  }
  /* 카드 라벨 = thead 라벨과 **같은 문자열**이다(표 ↔ 카드가 같은 표라는 보장).
     `.col-sale` 의 라벨만 `판매금액` → `구매금액`(2026-07-30 사용자 지시) — 클래스명은 유지. */
  .data-table--buyback .col-price::before { content: "체결 가격"; }
  .data-table--buyback .col-qty::before   { content: "매수 수량"; }
  /* ※ `.col-sale::before` 는 아래 v2.28 줄에 있다(라벨 `집행 금액`). */
  /* v2.28 — ~~`구매금액`~~ → `집행 금액`(PPT S5 ③) · ~~`누적 금액` 라벨~~ 제거(열 삭제) */
  .data-table--buyback .col-sale::before  { content: "집행 금액"; }
  .data-table--buyback .col-price::before,
  .data-table--buyback .col-qty::before,
  .data-table--buyback .col-sale::before {
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
    white-space: nowrap;
  }
  /* ★★ v2.28 — **단위가 셀로 들어오며 카드가 넘쳤다** (360px 실측: 문서 378 > 뷰포트 360).
     카드 행은 `[라벨 ─────── 값]` 플렉스인데, 값 문자열이 `604,420.0000 USDT` 처럼
     길어지자 **줄어들지 못하고 카드 폭을 밀어** 문서에 가로 스크롤이 생겼다.
     ★ `.cell-value` 가 `inline-flex` 라 기본 `min-width: auto` 로 **min-content 아래로
       줄지 않는 것**이 원인이다 — 플렉스 자식의 고전적 함정이며, 이 파일이 표 트랙에
       `minmax(0, 1fr)` 을 쓰는 것과 **같은 이유·같은 처방**이다.
     ★ 라벨은 `flex: none` 으로 고정한다 — 줄어들 쪽은 값이지 라벨이 아니다
       (라벨이 접히면 `집행 금액` 이 두 줄이 되어 행 높이가 들쭉날쭉해진다). */
  .data-table--buyback .col-price::before,
  .data-table--buyback .col-qty::before,
  .data-table--buyback .col-sale::before { flex: none; }
  .data-table--buyback .col-price .cell-value,
  .data-table--buyback .col-qty .cell-value,
  .data-table--buyback .col-sale .cell-value {
    min-width: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
    text-align: right;
  }

  /* v2.28 — 누적 금액 열이 사라져 **집행 금액**이 카드 내 시각 최상위가 된다 */
  .data-table--buyback .col-sale .num--amount {
    font-size: var(--font-size-body-lg);
    font-weight: var(--font-weight-bold);
  }
}

/* --- 6-2. Top 20 3열 표 → 카드 (<768px) ------------------------------- */

@media (max-width: 767px) {
  .data-table--top20,
  .data-table--top20 tbody,
  .data-table--top20 tr,
  .data-table--top20 td { display: block; }

  .data-table--top20 thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .data-table--top20 tbody td {
    height: auto;
    padding: 0;
    border-bottom: 0;
  }
  /* 위와 같은 이유 — 데스크톱 열 폭(%)·min-width 를 카드 모드에서 해제한다.
     특히 .col-rank 의 min-width:88px 은 44px 트랙을 밀어 판매자 열과 겹친다. */
  .data-table--top20 .col-rank,
  .data-table--top20 .col-name,
  .data-table--top20 .col-perf,
  .data-table--top20 .col-extra { width: auto; min-width: 0; }

  .data-table--top20 tbody tr {
    display: grid;
    /* 금액을 담는 트랙이므로 minmax(0, …) — 레이아웃 §0-2 전역 규칙 */
    grid-template-columns: 44px minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-3);
    row-gap: var(--space-2);
    min-height: 96px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--color-bg);
  }
  @media (hover: hover) and (pointer: fine) {
    .data-table--top20 tbody tr:hover { background: var(--color-bg); }
  }

  .data-table--top20 .col-rank {
    grid-column: 1;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .data-table--top20 .rank-badge { width: 36px; height: 36px; }
  .data-table--top20 .col-name {
    grid-column: 2;
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-semibold);
  }
  /* 금액 줄 — 카드 안에서 전폭 1줄(라벨 좌 · 값 우).
     ★ v2.15 — `.col-sales` 와 그 `::before` 라벨(`판매 실적`)을 **제거**했다
       (2026-08-04 사용자 지시). 카드 모드에서 열 라벨은 thead 가 sr-only 라
       **이 `::before` 가 유일한 시각 라벨**이므로, 지우지 않으면 표에 없는 열의
       이름이 모바일에서만 계속 보인다. 표↔카드가 같은 표여야 한다. */
  /* v2.28 — 새 금액 열도 카드에서 같은 문법(라벨 좌 · 값 우 전폭 1줄)을 쓴다 */
  .data-table--top20 .col-perf,
  .data-table--top20 .col-extra {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: right;
  }
  .data-table--top20 .col-perf::before {
    content: "누적 정산 실적";
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
    white-space: nowrap;
  }
  /* v2.28 — ~~`추가 정산 금액`~~ → `보너스 정산 금액`(PPT S4). thead 라벨과 같은 문자열. */
  .data-table--top20 .col-extra::before {
    content: "보너스 정산 금액";
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
    white-space: nowrap;
  }
  .data-table--top20 .col-extra .num--amount {
    font-size: var(--font-size-body-lg);
    font-weight: var(--font-weight-bold);
  }
  /* 1~3위 카드 (v2.2 상향) — 모바일에서도 카드 크기 자체가 달라 강조가 살아남는다.
     데스크톱과 같은 좌측 인셋 마커를 쓰되, 카드 모드의 tr 은 display:grid 라
     tr 자신에게 box-shadow 를 걸 수 있다(표 모드에서는 첫 셀에 건다). */
  /* ★ v2.26 — 매출 표도 **같은 카드 강조**를 받는다(사용자 지시 ②). 데스크톱 블록과
     같은 이유로 선택자를 묶는다 — 두 벌을 두면 한쪽만 바뀐다. */
  .data-table--top20 tbody tr.is-top,
  .data-table--sales-rank tbody tr.is-top {
    border: 2px solid var(--color-primary);
    box-shadow: inset 4px 0 0 var(--color-brand);
    min-height: 120px;                                   /* 일반 카드 96px */
  }
  /* 데스크톱 행 높이(72px)를 카드 모드에서 해제한다 — 같은 형태의 선택자로 덮어야
     특정도가 밀리지 않는다(D7 과 같은 이유). 인셋은 위에서 tr 이 대신 그린다. */
  .data-table--top20 tbody tr.is-top td,
  .data-table--sales-rank tbody tr.is-top td { height: auto; }
  .data-table--top20 tbody tr.is-top > td:first-child,
  .data-table--sales-rank tbody tr.is-top > td:first-child { box-shadow: none; }
  .data-table--top20 tbody tr.is-top .rank-badge,
  .data-table--sales-rank tbody tr.is-top .rank-badge { width: 44px; height: 44px; }

  /* --- 매출 랭킹(예상) 표 → 카드 (v2.22) -------------------------------
     ★ Top 20 과 **같은 임계(768px)·같은 카드 문법**이다. 두 표가 같은 페이지에
       위아래로 붙어 있어 임계가 다르면 어느 폭에서는 한쪽만 카드가 되어
       같은 자료가 두 형태로 보인다.
     ★ v2.26 — 다른 점이 **하나로 줄었다**: `::before` 라벨이 `매출액` 인 것뿐이다.
       ~~② 1~3위 강조 규칙이 없다(예상치라 강조하지 않는다 — §5-b 배너)~~ →
       사용자 지시 ②로 **두 표가 같은 강조 규격**이 됐다(위 `.is-top` 묶음 선택자). */
  .data-table--sales-rank,
  .data-table--sales-rank tbody,
  .data-table--sales-rank tr,
  .data-table--sales-rank td { display: block; }

  .data-table--sales-rank thead {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .data-table--sales-rank tbody td {
    height: auto;
    padding: 0;
    border-bottom: 0;
  }
  .data-table--sales-rank .col-rank,
  .data-table--sales-rank .col-name,
  .data-table--sales-rank .col-revenue { width: auto; min-width: 0; }

  .data-table--sales-rank tbody tr {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-3);
    row-gap: var(--space-2);
    min-height: 96px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--color-bg);
  }
  @media (hover: hover) and (pointer: fine) {
    .data-table--sales-rank tbody tr:hover { background: var(--color-bg); }
  }

  .data-table--sales-rank .col-rank {
    grid-column: 1;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .data-table--sales-rank .rank-badge { width: 36px; height: 36px; }
  .data-table--sales-rank .col-name {
    grid-column: 2;
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-semibold);
  }
  .data-table--sales-rank .col-revenue {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: right;
  }
  /* 카드 모드에서 thead 가 sr-only 라 **이것이 유일한 시각 라벨**이다 — 열 이름을
     바꾸면 여기도 함께 고쳐야 한다(v2.15 가 `판매 실적` 에서 겪은 그 자리다). */
  /* ★★ v2.38 — ~~매출액~~ → **`누적 판매 금액`** (사용자 직접 지시 2026-08-14 · 항목 9).
     thead 가 `누적 판매 금액` 이 되면서(ranking.html 그 자리 주석) 카드 라벨을 **열 제목과
     같은 문자열**로 통일한다 — 정산 표 카드 라벨(`보너스 정산 금액` = thead)이 이미 그
     규약이고, 바로 위 배너(*"열 이름을 바꾸면 여기도 함께 고쳐야 한다"*)가 예고한 자리다.
     ⚠ 종전 `매출액` 은 v2.22 신설 당시 문자열로, v2.28 이 thead 만 `누적 매출` 로 바꾼 뒤에도
       남아 **이미 갈라져 있었다**(이번에 발견). 통일은 builder 판단이라 writer 확인 요망
       (notes §7 W-23 ⑤ — 지시 원문이 지목한 것은 열 제목이고 카드 라벨은 그 파생이다). */
  .data-table--sales-rank .col-revenue::before {
    content: "누적 판매 금액";
    font-size: var(--font-size-caption);
    color: var(--color-text-muted);
    white-space: nowrap;
  }
  .data-table--sales-rank .col-revenue .num--amount {
    font-size: var(--font-size-body-lg);
    font-weight: var(--font-weight-bold);
  }

  /* --- 상위 3위 포디움 → 세로 카드 3장 (v2.26) --------------------------
     ★ **높이로 순위를 말하는 은유를 모바일에서는 버린다.** 360px 에서 3열을 유지하면
       칸당 실폭이 약 101px 인데(360 − 좌우 16×2 − gap 16×2), 금액 `5,500,000원`
       한 줄이 그 폭을 넘어 **넘침 아니면 3줄 접힘**이 된다. 세로로 세우면 단 높이
       차이(64/48/32px)가 **위아래로 늘어서 아무 의미도 만들지 못하므로**, 은유를
       억지로 유지하는 대신 **표 카드 모드와 같은 문법**으로 바꾼다.
     ★ 그래서 이 구간의 포디움은 **위 표 카드와 같은 골격**이다 —
       `44px minmax(0, 1fr)` 그리드 + 같은 테두리·모서리·패딩. 같은 화면에서 두 블록이
       다른 문법으로 보이지 않게 하는 것이 목적이다. `44px` 은 터치 타깃 규격 값이고
       표 카드 모드가 이미 쓰는 트랙 폭이다(4px 스케일 예외가 아니라 **같은 기존 값**).
     ★ 순서는 **1 → 2 → 3** 으로 되돌린다(`order: 0`). 세로 배치에서 2-1-3 은
       포디움으로 읽히지 않고 그냥 순서가 틀린 목록으로 읽힌다. DOM 이 이미
       1,2,3 이므로 되돌리는 것이 곧 DOM 순서와의 일치이기도 하다. */
  .podium {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
  }
  .podium__item {
    order: 0;
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    align-items: center;
    column-gap: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg);
    padding: var(--space-4);
  }
  /* 단이 **왼쪽 원형 뱃지**가 된다 — 표 카드 모드의 순위 뱃지와 같은 자리·같은 지름.
     DOM 은 카드 → 단 순서라 `order: -1` 로 앞으로 당긴다(포커스 대상 0개라 안전). */
  .podium__base,
  .podium__item--r1 .podium__base,
  .podium__item--r2 .podium__base,
  .podium__item--r3 .podium__base {
    order: -1;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
  }
  .podium__card,
  .podium__item--r1 .podium__card {
    border: 0;
    border-radius: 0;
    background: transparent;
    padding: 0;
    text-align: left;
  }
  .podium__item--r1 .podium__value .num--amount { font-size: var(--font-size-body); }

  /* 게이트 버튼 — 좁은 화면에서는 전폭(히어로 CTA 와 같은 규칙) */
  .gate-actions .btn { width: 100%; }

  .table-foot { margin-top: var(--space-4); }
  .table-foot .btn { width: 100%; }

  .card { padding: var(--space-4); }

  /* ~~`.logo` · `.tab` 모바일 재정의~~ **v2.8 삭제** — 두 컴포넌트가 폐기됐다.
     1행 헤더의 반응형은 위 §6-0 블록이 소유한다(같은 767 구간에 두 벌을 두지 않는다). */

  /* 세그먼트 5등분 */
  .segmented { width: 100%; }
  .segmented__btn { flex: 1 1 0; padding-inline: var(--space-2); font-size: var(--font-size-caption); }

  .notice { padding: var(--space-4); }
}

/* --- 6-3. 태블릿 이상 (≥768px) ---------------------------------------- */

@media (min-width: 768px) {
  .hero__cta { flex-direction: row; justify-content: center; }
  .hero__cta .btn { width: auto; }

  .section__head { flex-direction: row; align-items: flex-end; justify-content: space-between; }

  /* 지갑 주소 — 폭이 생기면 주소와 복사 버튼을 한 줄에 편다(v2.19).
     `align-items: center` 로 버튼을 주소 줄 높이에 맞춘다. 주소가 두 줄로 접히더라도
     버튼은 가운데 정렬돼 어긋나 보이지 않는다. */
  .wallet-note__row { flex-direction: row; align-items: center; justify-content: space-between; }

  /* v2.45 — .stat-strip 사문(1b 재구축 · §3-5 그 자리 배너). 1b 의 이 구간 반응형은
     §3-5-c 가 소유한다(기본 그리드 270+1fr · 그룹 전폭 — 권장안). */
  .stat-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* v2.9 — 현재 `.stat--wide` 를 가진 요소는 없다(이더스캔 타일 잠정 제외, D87).
     규칙을 지우지 않고 남긴다 — 재도입 시 마크업만 되돌리면 되도록. */
  .stat-strip .stat--wide { grid-column: span 2; }

  .site-footer__grid { grid-template-columns: 2fr 1fr 1fr; gap: var(--space-12); }
  .site-footer__bottom { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* --- 6-4. 데스크톱 (≥1024px) ------------------------------------------ */

@media (min-width: 1024px) {
  .hero--index { min-height: 380px; }  /* v2.36 — 사문(스테이지 min-height 416 이 항상 이긴다) · 무해 보존 */
  /* ~~.hero--top20 { min-height: 340px; }~~
     ★ v2.36 제거 — v2.35 까지는 사문(실렌더가 항상 초과)이었지만, 밴드=배너 단독이 된
       지금은 1024~1279px 에서 배너 실높이(221~277px)가 340 에 못 미쳐 **배너 아래 네이비
       띠를 만드는 유해 규칙**으로 바뀌었다(시안 39828 왜곡). 사문 삭제 판단은 designer
       상신(D-27)에 걸어 두었으나 유해 전환은 판정을 기다릴 수 없어 builder 가 먼저
       걷었다(사후 승인 대상) — 경위는 notes §4-at·§7 D-27 승격 기록. */
}

/* --- 6-5. 와이드 (≥1280px) --------------------------------------------
   누적 결과 타일만 다열로 승격한다 (레이아웃 §0-4).

   ★ v2.19 — `매출`·`바이백 수량` 복원으로 타일이 **2 → 4개**가 됐다(사용자 재지시 2026-08-10).
     열 수를 **`repeat(4, …)` 로 원복**했다 — 4타일이 한 행에 정확히 떨어지고, 타일 내부폭이
     588px 에서 **234px**(트랙 282px − 좌우 패딩 24px×2)로 돌아온다. §2-5 계단 경계표와
     `js/buyback.js UNIT_SCALE_CHARS` 환산 실측(` USDT` 39.89px · ` OnTact` 48.84px)이
     전제로 삼은 조건이 이 4열 폭이므로, 열 수를 되돌리는 것으로 계단 기구의 전제도 함께
     원위치한다(아래 §2-5 블록 주석 참조).
     ※ v2.19 실측 메모 — 그 전제값이 여러 문서에 **232.00px** 로 적혀 있는데, 2026-08-10
       실측(1280·1440 양쪽)은 **234px** 다. 2px 차이이고 **여유가 더 생기는 방향**이라
       경계표·환산 상수를 고칠 사유는 없다. 다만 다음 사람이 대조하다 혼동하지 않도록
       실측치를 여기 남긴다(수치를 조용히 덮어쓰지 않는다).
     ≥768px 는 `repeat(2, …)` 그대로다 — 4개면 2행 × 2열로 떨어져 고아 칸이 없다.
     <768px 1열은 4행으로 쌓인다. 즉 **조정 지점은 여기 한 곳뿐**이고, 전 구간 고아 칸 0이다.

   ~~v2.18 — 타일 4 → 2 로 줄며 `repeat(2, …)` 로 내렸다(고아 칸 2개 방지).~~
     → 취소선 보존. v2.19 재지시로 되돌렸다.

   ★★ 타일 수가 또 바뀌면 이 숫자 하나를 고친다 ★★
      · 매출·바이백 수량 제거(2타일) → `repeat(2, …)`   (v2.18~v2.18-1 상태)
      · 이더스캔까지 복원(5타일)     → `repeat(3, …)`   (1행 3개 / 2행 거래소 + 이더스캔 span 2)
      `.stat-strip .stat--wide` 의 span 2 규칙은 6-3 블록에 **그대로 남겨 뒀다** — 복원을
      마크업 되돌리기 + 이 숫자 하나로 끝내기 위한 것이다. 지금은 해당 요소가 없어 무효 규칙이다. */
@media (min-width: 1280px) {
  /* v2.45 — .stat-strip 사문(1b 재구축). ≥1280 의 1b 3열(270/290/1fr)은 §3-5-c 소유. */
  .stat-strip { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* ★ v2.8 — 히어로 3D 오브제는 **≥1280px 에서만** 노출한다(디자인 시스템 §5-16 ⓑ).
     1024~1279px 에서는 컨테이너가 좁아지며 h1 이 2줄로 접히기 시작해 텍스트와의 여유
     (≥1280 기준 좌 120px · 우 157px)가 급격히 사라진다.
     ★ **크기를 줄여 살리지 않는다** — 3D 렌더는 작아지면 형태가 뭉개져 "흐릿한 얼룩"이
       되고, 그건 장식이 아니라 노이즈다(§0 원칙 2 의 반대 방향 실패).
     ⚠ 이 구간 판정은 시안에 근거가 없다(모바일·태블릿 뷰 미제공) — designer 설계다. */
  .hero__art { display: block; }
}
