/* ============================================================
 * AXE Labs — fonts (소비자 채널 — *자체완결* 필수)
 *
 *  브랜드 display 슬롯: Gate 에서는 Pretendard 로 결정적 폴백 (Clash 미배포)
 *  Pretendard Var.    : 본문 · UI · 라벨          (gate self-host — 단일 가변 woff2)
 *  Sarasa Fixed K     : 코드 · 터미널 · 박스아트   (gate self-host woff2)
 *
 *  ⚠ gate 변환본 (CDN 0) — 이 파일은 axelabs src/lib/tokens/fonts.css 의 gate 전용
 *  self-host 파생물이다. 원본의 jsDelivr Pretendard `@import` 는 아래 self-host
 *  `@font-face` 로 치환됐고, 허용된 모든 url() 은 `fonts/…` 상대경로(= 번들 스타일시트
 *  /gate/assets/axe-ui.css 기준 → /gate/assets/fonts/…, src/web.rs include_bytes!
 *  라우트가 서빙, 듀얼마운트 안전)로 가리킨다. 재벤더 시 원본을 그대로 cp 하지 말고
 *  본 변환(원격 @import 제거 + OFL self-host faces + Clash 제외 + Sarasa url 상대화)을
 *  재적용할 것.
 *  절차 = assets/axe-ui/VERSION.
 *
 *  Next 앱 (axelabs.ai/design.axelabs.ai) 의 폰트 전달 방식은 canonical 저장소가
 *  별도로 소유한다. Gate 는 그 전달 설정을 복제하지 않고, 본 파일의 로컬 허용목록만
 *  유지한다. 자세한 경계와 재벤더 절차 = assets/axe-ui/VERSION.
 *
 *  Sarasa Fixed K subset 재생성: npm run fonts:install
 * ============================================================ */

/* Pretendard Variable — gate self-host 단일 가변 woff2 (CDN 0).
 * 원본의 jsDelivr dynamic-subset(92-slice) @import 를 제거하고 단일 가변 파일
 * 하나만 include_bytes! 로 서빙 (92개를 바이너리에 굽는 비대 회피). 가변 woff2 는
 * weight 축 45..920 을 파일 안에 담아 font-weight 범위 선언만으로 전 굵기 커버.
 * url() = 상대경로 → 번들 스타일시트(/gate/assets/axe-ui.css) 기준으로
 * /gate/assets/fonts/PretendardVariable.woff2 해석 (루트-절대 /fonts/ 는 듀얼마운트
 * 에서 /gate prefix 이탈 → 404, D-layer 진단). 라이선스 = SIL OFL 1.1
 * (github.com/orioncactus/pretendard v1.3.9). */
@font-face {
  font-family: "Pretendard Variable";
  src: url("fonts/PretendardVariable.woff2") format("woff2");
  font-weight: 45 920;
  font-style: normal;
  font-display: swap;
}

/* unicode-range 의도적 미설정 — Sarasa Fixed K 는 ASCII·한글·박스 모두 처리하며,
 * 한글:ASCII 정확히 2:1 너비를 보장하기 위해 영문도 같은 폰트가 그려야 함.
 *
 * 이전엔 unicode-range 명시했으나 CSS minifier 가 `U+1100-11FF` 를 wildcard
 * `u+11??` 로 압축 → Chrome 이 invalid 로 해석 → 전체 @font-face 거부 →
 * 폰트 로딩 실패 → fallback (Menlo) 으로 렌더 → 한글이 1.4× 가변폭 → 박스 깨짐.
 *
 * (이 함정은 dev (next dev, unminified) 에서는 안 보이고 production 빌드에서만
 * 발현되므로 진단 어려움.  unicode-range 없이 두면 모든 글자 매칭 + minifier
 * 가 만질 게 없음.) */
/* Sarasa Fixed K — Regular(400) 만 self-host.
 *
 * Bold(700) 제거 이유:
 *   - 코드/박스/표 의 mono 자리에 bold 거의 안 씀 (decorative 영향 X)
 *   - Cloudflare edge 가 Bold 파일에 transient 503 을 영구 캐시하는 함정 발견
 *     (2026-05-23, docs.axelabs.ai) — Regular 만 200, Bold 만 503 → 페이지
 *     안 `<strong>` 만 fallback (Pretendard Bold) 으로 빠지면서 한글 가변폭
 *     → 박스 안 markdown ** 굵게 라인만 misalign.
 *   - font-weight: 700 시 browser 가 Regular 를 algorithmic-bold 로 그리거나
 *     stack 의 다음 폰트 (Pretendard Bold) 로 fallback — 본문 외 위치라
 *     의미상 무관.
 *
 * unicode-range 도 *의도적 미설정* — minifier 의 wildcard 변환이 Chrome 에서
 * 거부됨 (이전 함정).  Regular 하나만 두면 minifier 가 만질 게 없음.
 *
 * ?v=2 cache-bust — 이 URL 은 carve-out 이전 깨진 응답(HTML/404)이 브라우저에
 * max-age=14400 으로 캐시된 이력이 있음 → FontFace status:error 가 일반
 * 새로고침으로 안 풀림 (2026-06-10 Windows Chrome 실측). 자산 내용이 바뀌면
 * 반드시 v 를 올릴 것 (URL 불변 정책 금지). */
@font-face {
  font-family: "Sarasa Fixed K";
  src: url("fonts/SarasaFixedK-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---- zero-CLS: metric-matched 시스템 폴백 ----
 * Pretendard 도착 전 폴백이 같은 줄높이/폭으로 그려져 swap 시 reflow 최소화.
 * Pretendard 는 Apple SD Gothic Neo metrics-호환 설계 (공식 README) —
 * size-adjust 100% + Pretendard 수직 메트릭 (ascent 1060/descent 300/UPM 1000)
 * override 로 사실상 무이동. Malgun (Windows) 은 폭이 살짝 넓어 98% 보정. */
@font-face {
  font-family: "Pretendard Fallback";
  src: local("Apple SD Gothic Neo");
  size-adjust: 100%;
  ascent-override: 106%;
  descent-override: 30%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Pretendard Fallback MG";
  src: local("Malgun Gothic");
  size-adjust: 98%;
  ascent-override: 108%;
  descent-override: 30.5%;
  line-gap-override: 0%;
}

:root {
  /* 본문 / UI / 디스플레이 *공통* sans 스택 — Pretendard 1순위.
   * default 헤딩 페이스도 이걸로 받음.
   * Fallback 페이스 2종은 metric-matched (위 @font-face) — CLS 억제. */
  --font-sans:
    "Pretendard Variable", Pretendard, "Pretendard Fallback",
    "Pretendard Fallback MG", -apple-system, BlinkMacSystemFont,
    "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  /* --font-display = 디스플레이 자리 (h1·h2·card title·logo 등) 의 의미적 슬롯.
   * 현재 sans 와 동일 — 즉 default 는 Pretendard. */
  --font-display: var(--font-sans);

  /* 공개 CSS 계약의 --font-clash 이름은 호환성을 위해 남긴다. Gate 는 ITF FFL상
   * 사전 서면동의 없는 공개 서버 재배포/font serving 을 하지 않으며 외부 API도
   * 로드하지 않는다. 따라서 브랜드 슬롯은 로컬 Pretendard 스택으로 결정적 폴백. */
  --font-clash: var(--font-sans);

  /* Sarasa Fixed K — 한글이 ASCII 의 정확히 2× 너비. 박스 정렬에 결정적.
   * (구 D2Coding CDN 폴백은 family 명 불일치 'D2 coding' 로 한 번도 매칭된
   *  적 없는 dead code 였음 — 2026-06-10 제거.) */
  --font-mono:
    "Sarasa Fixed K", "JetBrains Mono", "SF Mono", Menlo, Consolas,
    monospace;
}
/* ============================================================
 * AXE Labs — colors
 *
 *  - Light: warm Sand-tinted 12-step (Radix Sand inspired)
 *  - Dark : wine-tinted, brand navy(#1A0610) 를 gray-1 로 앵커
 *  - Accent: #E3FF66 (dark) / #7A8F1F (light, AA contrast)
 *
 *  Step 의미 (Radix scale 패턴 동일):
 *    1  App background          7  UI element border
 *    2  Subtle / elevated bg    8  Hover border / focus
 *    3  UI element bg           9  Solid bg (disabled, placeholder dot)
 *    4  Hover UI bg            10  Hover solid
 *    5  Active UI bg           11  Low-contrast text  (caption)
 *    6  Subtle border, divider 12  High-contrast text (body)
 *
 *  ── 다크 팔레트 = light-dark() 단일 선언 (2026-07 Astryx 채굴 리팩터) ──
 *  이전엔 다크 값이 세 곳([data-theme=dark]/.dark 블록 + prefers-color-scheme
 *  미디어 블록)에 byte-identical 로 중복 선언돼 있었고, 그 수동 동기화가
 *  2026-06-10 gray-8/9/10 drift 사고(두 블록 값 불일치 + ramp 단조성 붕괴)를
 *  낳았다. 이제 토큰당 `light-dark(<라이트>, <다크>)` 한 줄로 접어 중복 자체를
 *  제거 — 두 값이 물리적으로 한 곳에 있어 drift 가 불가능하다.
 *
 *  모드 전환은 CSS `color-scheme` 로 한다 (light-dark() 는 요소의 계산된
 *  color-scheme 에 따라 라이트/다크 인자를 고른다):
 *    :root                         → color-scheme: light dark  (OS 기본 따라감)
 *    [data-theme=dark] / .dark     → color-scheme: dark        (명시 다크)
 *    [data-theme=light] / .light   → color-scheme: light       (명시 라이트)
 *  data-theme 토글·.light/.dark 클래스(next-themes)·prefers-color-scheme
 *  자동 — 세 경로 모두 리팩터 전과 각 토큰 해석값이 완전 동일하다
 *  (resolve_tokens.py 4-state 등가 증명).
 *
 *  ⚠ 브라우저 지원: light-dark() (color) = Baseline 2024-05 — Chrome/Edge 123+,
 *  Safari 17.5+, Firefox 120+ (2026-07-10 정정: 종전 'Chrome/Edge 110+' 는 오기).
 *  미지원 브라우저는 전 색 토큰이 invalid-at-computed-value → 무브랜드 렌더.
 *  '내부 도구 대상' 전제는 소비자에 따라 성립하지 않는다(layer viewer/gate 는
 *  외부 수신자 표면) — 외부 서빙 소비자는 폴백 필수. layer 는 번들 시
 *  @supports not (color: light-dark(#000,#fff)) 라이트 정적값 블록을 자동
 *  생성한다(assets/axe-ui/build_bundle.py). light-dark() 미지원 표면(구형
 *  이메일 클라이언트 등)에는 이 토큰을 직접 흘리지 말 것 — 값을 인라인/구운다.
 * ============================================================ */

/* -------- 모드 스위치 (color-scheme) --------
 * 두 토글 전략 모두 지원:
 *   - data-theme="light|dark"  (axelabs 메인 앱 + 직접 토글)
 *   - .light / .dark           (next-themes class 기본값 — Nextra docs 등)
 * :root 에 `light dark` 를 둬 명시 선택이 없으면 prefers-color-scheme 를
 * 따르게 하고, 명시 선택 시 단일 스킴으로 좁힌다. */
:root {
  color-scheme: light dark;
}
[data-theme="dark"],
.dark {
  color-scheme: dark;
}
[data-theme="light"],
.light {
  color-scheme: light;
}

/* -------- 토큰 (light-dark(<라이트>, <다크>)) --------
 * 라이트 = warm cream paper (순백 회피, 모니터 직사광 부담 감소 — Anthropic
 *          #FAF9F5, Toss off-white, Linear light-mode 노선 참고).
 * 다크   = wine-tinted, brand noir(#1A0610) 를 gray-1 로 앵커. */
:root {
  /* 브랜드 fixed colors — 모드 무관 동일 값 (light-dark 불요).
   *   noir   : 다크 모드 배경의 와인-블랙 (Pinot Noir 톤). 거의 검정에 와인 hue.
   *   claret : 라이트 모드 의 brand + accent. AXE 시그니처 와인색.
   *   neon   : 다크 모드 의 brand + accent. 에너지 컬러.
   *
   * 시멘틱 `--accent` 가 모드 따라 둘 중 하나로 자동 매핑되므로
   * Logo 와 CTA 버튼이 같은 브랜드 색을 공유. */
  --brand-noir: #1a0610;
  --brand-claret: #821f3b;
  --brand-neon: #e3ff66;

  /* gray ramp — 라이트=warm sand, 다크=wine-tint.
   * 4-7(라이트) 보더 자리는 종이 톤에 가깝게(이전 진한 값이 카드·표·구분선을
   * 와이어프레임처럼 그리던 원인 — Radix Sand 6 수준으로 완화, 8-12 텍스트
   * 계조는 그대로라 대비 영향 없음). */
  --gray-1: light-dark(#f5f1e8, #1a0610);   /* App bg — warm cream / noir */
  --gray-2: light-dark(#efeadf, #220b17);   /* Subtle / elevated bg */
  --gray-3: light-dark(#e8e2d4, #2c1320);
  --gray-4: light-dark(#e3dccd, #371b2a);
  --gray-5: light-dark(#dad2c0, #432435);
  --gray-6: light-dark(#cfc6b2, #532e42);
  --gray-7: light-dark(#bdb29a, #6b4055);
  --gray-8: light-dark(#978b71, #7e4f66);
  --gray-9: light-dark(#756a52, #8e6477);
  --gray-10: light-dark(#5d5440, #ab8499);  /* text-tertiary — dark 는 bg 대비 ≥5:1 (AA) */
  --gray-11: light-dark(#423a2b, #b8a8b2);
  --gray-12: light-dark(#1f1a13, #f2e8ee);

  --bg-base: var(--gray-1);
  --bg-subtle: var(--gray-2);
  /* bg-elevated: 라이트는 bg-base 보다 살짝 밝지만 순백 절대 X; 다크는 gray-3. */
  --bg-elevated: light-dark(#faf6ec, var(--gray-3));
  --bg-overlay: light-dark(rgb(31 26 19 / 0.55), rgb(0 0 0 / 0.65));

  --text-primary: var(--gray-12);
  --text-secondary: var(--gray-11);
  --text-tertiary: var(--gray-10);
  --text-muted: var(--gray-9);
  --text-inverse: var(--gray-1);

  /* 보더 — 알파 기반 색조 잉크 (2026-07 Astryx 채굴):
   * 이전엔 솔리드 gray step(라이트 gray-6/7/8, 다크 gray-6/7/8) 이었다. 목표는
   * zebra·hover·카드 등 어떤 표면 위에서도 보더가 자연 합성되게 하는 것(Astryx
   * 7테마 공통 규칙). 단 AXE 팔레트의 보더는 무채색이 아니라 채도가 있는 색
   * (라이트=웜 샌드, 다크=와인) 이라, Astryx 의 순백/중립 알파(#FFFFFF1A)를
   * 그대로 쓰면 종전 대비 ΔE 11~17 의 급격한 대비 변화가 난다(흰-알파 저채도가
   * 종전 채색 보더를 재현 못 함). 그래서 **시각 등가 우선** 원칙에 따라 잉크를
   * 보더 자신의 hue 를 실은 색으로 두고, 알파는 bg-base 위 합성이 종전 솔리드와
   * 지각적으로 동등하도록 solve 했다:
   *   라이트 잉크 = rgb(143 126 90)  (웜 샌드-잉크, ≈#8f7e5a)
   *   다크   잉크 = rgb(173 111 141) (와인-잉크, ≈#ad6f8d)
   * 검증(sRGB→Lab, before=솔리드 vs after=알파합성 — 2026-07-10 실측 정정):
   *   default 티어만 bg-base 위 CIE76 ≈ 0.1 로 사실상 동일. subtle/strong 은
   *   CIE76 최대 4.0(bg-base: 라이트 strong 3.96 · 다크 subtle 2.67), elevated
   *   위 최대 4.2 — CIEDE2000 기준 ≤ 2.6. 즉 '전 티어 ΔE ≤ 1.5' 가 아니라
   *   근사(종전 주석의 과대 주장 정정 — 1px 보더라 지각 위험은 낮음). 솔리드
   *   보더는 표면마다 튀지만 이 알파 잉크는 세 표면 모두 종전 값에 근사.
   *   알파 3단(subtle<default<strong)이 종전 gray-6/7/8 계조를 대체. */
  --border-subtle: light-dark(rgb(143 126 90 / 0.38), rgb(173 111 141 / 0.35));
  --border-default: light-dark(rgb(143 126 90 / 0.55), rgb(173 111 141 / 0.55));
  --border-strong: light-dark(rgb(143 126 90 / 0.85), rgb(173 111 141 / 0.68));

  /* accent = 브랜드 강조색 (claret/neon). 다음 자리에 사용:
   *   - Logo · Prose 링크 · Input/ChatInput focus border(+accent-soft 링)
   *   - Card 인터랙티브 hover 보더 · Badge "accent" · Callout 좌보더
   *   - ToolCall 이름 색 · ::selection 배경 · :focus-visible outline
   * Primary CTA 는 별도 --cta (행동 자리는 의미 부담 없는 ink). */
  --accent: light-dark(var(--brand-claret), var(--brand-neon));
  --accent-hover: light-dark(#6b1830, #eeff94);
  --accent-fg: light-dark(#ffffff, var(--brand-noir));
  --accent-soft: light-dark(rgb(130 31 59 / 0.10), rgb(227 255 102 / 0.10));

  /* cta = Primary 버튼 등 행동 자리. 모드 따라 ink 인버전 (Vercel · Linear ·
   * Anthropic 의 black/cream CTA 패턴). 양 모드 모두 gray-12/11/1 참조라
   * 선언은 동일하지만, 밑단 gray 가 light-dark 라 자동 flip. */
  --cta: var(--gray-12);
  --cta-hover: var(--gray-11);
  --cta-fg: var(--gray-1);

  --success: light-dark(#2b7a3f, #58d17a);
  --warning: light-dark(#b8651a, #f0a961);
  --danger: light-dark(#c4321f, #f26a55);
  --info: light-dark(#2860b8, #6ba8ff);

  /* 상태 soft 배경 — 라이트는 파스텔 솔리드, 다크는 원색 10% 알파. */
  --success-soft: light-dark(#e9f6ec, rgb(88 209 122 / 0.10));
  --warning-soft: light-dark(#fbf0e0, rgb(240 169 97 / 0.10));
  --danger-soft: light-dark(#fbe7e2, rgb(242 106 85 / 0.10));
  --info-soft: light-dark(#e6eefb, rgb(107 168 255 / 0.10));

  /* elevation (라이트) — 2-layer 레시피 (key light + ambient), 따뜻한 잉크
   * rgb(31 26 19) 베이스로 종이 위 실제 그림자처럼. 라이트 값은 리팩터 전과 무변.
   *
   * ⚠ shadow 는 <color> 가 아니라 shadow-list(콤마 포함) 라 light-dark() 로 접을
   *   수 없다 (light-dark 는 <color>|<image> 전용, CSS Color L5). 따라서 다크
   *   그림자는 아래 별도 블록에서 **한 번만** 선언한다 — 명시 [data-theme=dark]/
   *   .dark 와 OS prefers-dark 를 하나의 selector-list 로 묶어, 종전의
   *   byte-identical 이중 선언(drift 원인) 을 제거했다. */
  --shadow-xs: 0 1px 2px rgb(31 26 19 / 0.05);
  --shadow-sm: 0 1px 2px rgb(31 26 19 / 0.05), 0 2px 6px -1px rgb(31 26 19 / 0.05);
  --shadow-md: 0 2px 4px rgb(31 26 19 / 0.04), 0 8px 20px -6px rgb(31 26 19 / 0.10);
  --shadow-lg: 0 4px 8px rgb(31 26 19 / 0.05), 0 20px 48px -12px rgb(31 26 19 / 0.16);
  --shadow-xl: 0 8px 16px rgb(31 26 19 / 0.06), 0 32px 80px -16px rgb(31 26 19 / 0.22);

  /* focus ring — 손글씨로 8곳+ 중복되던 0 0 0 3px accent-soft 의 SSOT.
   * accent-soft/danger-soft 가 light-dark 라 링도 모드 자동 flip. */
  --ring: 0 0 0 3px var(--accent-soft);
  --ring-danger: 0 0 0 3px var(--danger-soft);
}

/* -------- elevation (다크) --------
 * 순검정 드롭 섀도에 흰 inset 림 한 겹(inset 0 0 0 1px rgb(255 255 255 / 0.08))
 * 을 추가 (2026-07 Astryx/Figma bezel 기법): 다크 기본 표면에서 카드·드로어·
 * 모달의 엣지를 살짝 띄워 리프팅을 강화. 드롭 섀도 geometry/알파는 리팩터 전과
 * 동일 — inset 림만 신규.
 *
 * ⚠ shadow 는 <color> 가 아니라 shadow-list(콤마 포함) 라 light-dark() 로 접을
 *   수 없다 (light-dark = <color>|<image> 전용, CSS Color L5). 색 팔레트와 달리
 *   다크 그림자는 아래 두 컨텍스트(명시 .dark/[data-theme=dark] + OS prefers-dark)
 *   에 동일 값이 반복될 수밖에 없다 — 순수 CSS 로는 at-rule 을 selector-list 에
 *   넣지 못하기 때문. 두 블록 값은 반드시 동일하게 유지(색 토큰과 달리 shadow
 *   drift 는 지각 영향이 작지만, 바꿀 땐 두 곳을 함께 바꿀 것).
 *   `--shadow-inset-rim` 를 한 곳에서 정의해 두 블록이 그 변수를 공유 → inset 림
 *   값만큼은 SoT 를 단일화(림 두께/알파 변경 시 한 줄만 수정). */
:root {
  --shadow-inset-rim: inset 0 0 0 1px rgb(255 255 255 / 0.08);
}
[data-theme="dark"],
.dark {
  --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.40), var(--shadow-inset-rim);
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 8px -2px rgb(0 0 0 / 0.50), var(--shadow-inset-rim);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 0.40), 0 10px 24px -6px rgb(0 0 0 / 0.55), var(--shadow-inset-rim);
  --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 24px 56px -12px rgb(0 0 0 / 0.65), var(--shadow-inset-rim);
  --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.50), 0 40px 96px -16px rgb(0 0 0 / 0.70), var(--shadow-inset-rim);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.light) {
    --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.40), var(--shadow-inset-rim);
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 8px -2px rgb(0 0 0 / 0.50), var(--shadow-inset-rim);
    --shadow-md: 0 2px 4px rgb(0 0 0 / 0.40), 0 10px 24px -6px rgb(0 0 0 / 0.55), var(--shadow-inset-rim);
    --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 24px 56px -12px rgb(0 0 0 / 0.65), var(--shadow-inset-rim);
    --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.50), 0 40px 96px -16px rgb(0 0 0 / 0.70), var(--shadow-inset-rim);
  }
}
/* light-dark() 미지원 브라우저 폴백 — scripts/gen_colors_fallback.py 자동 생성물 (D-layer-46).
 * 수동 편집 금지: 원천은 tokens/colors.css 의 light-dark() 단일 선언.
 * gate 번들(src/web.rs concat!)에서 colors.css 다음 순서로 include_str! 되어야
 * 미지원 브라우저 캐스케이드에서 이 재선언이 이긴다.
 * 미지원 브라우저(Chrome/Edge <123, Safari <17.5, FF <120)에만 적용 —
 * 라이트 arm 정적값 + color-scheme:light (라이트 단일 모드 강등). */
@supports not (color: light-dark(#000, #fff)) {
  :root {
    color-scheme: light;
    --gray-1: #f5f1e8;
    --gray-2: #efeadf;
    --gray-3: #e8e2d4;
    --gray-4: #e3dccd;
    --gray-5: #dad2c0;
    --gray-6: #cfc6b2;
    --gray-7: #bdb29a;
    --gray-8: #978b71;
    --gray-9: #756a52;
    --gray-10: #5d5440;
    --gray-11: #423a2b;
    --gray-12: #1f1a13;
    --bg-elevated: #faf6ec;
    --bg-overlay: rgb(31 26 19 / 0.55);
    --border-subtle: rgb(143 126 90 / 0.38);
    --border-default: rgb(143 126 90 / 0.55);
    --border-strong: rgb(143 126 90 / 0.85);
    --accent: var(--brand-claret);
    --accent-hover: #6b1830;
    --accent-fg: #ffffff;
    --accent-soft: rgb(130 31 59 / 0.10);
    --success: #2b7a3f;
    --warning: #b8651a;
    --danger: #c4321f;
    --info: #2860b8;
    --success-soft: #e9f6ec;
    --warning-soft: #fbf0e0;
    --danger-soft: #fbe7e2;
    --info-soft: #e6eefb;
  }
}
/* ============================================================
 * AXE Labs — typography
 *
 *  스케일 — 16 px base, ±10% 컴파운딩 (ratio 1.1 / 0.9).
 *  큰 헤딩 (3xl/4xl/5xl) 만 `clamp()` 로 모바일 자동 축소 —
 *  본문은 16 px 변동 없음 (한글 가독성 표준).
 *
 *    text-xs    12.96 px   (16 × 0.9²)        고정
 *    text-sm    14.4  px   (16 × 0.9)         고정
 *    text-base  16    px                       고정  <-- 본문
 *    text-lg    17.6  px   (16 × 1.1)         고정
 *    text-xl    19.36 px   (16 × 1.1²)        고정
 *    text-2xl   21.30 px   (16 × 1.1³)        고정
 *    text-3xl   19.36~23.43 px (mobile~desktop)   <-- clamp
 *    text-4xl   21.30~25.77 px (mobile~desktop)   <-- clamp
 *    text-5xl   23.43~28.34 px (mobile~desktop)   <-- clamp  <-- Hero
 *
 *  Clamp 공식: 모바일 (375vw) 에서 한 단계 아래 토큰값까지 내려가고,
 *  데스크탑 (1280vw) 에서 현행 유지. 그 사이는 선형 보간.
 *
 *  자간 (letter-spacing)
 *    본문      0
 *    UI label  0
 *    헤딩     -0.015em      (한·영 모두 안전)
 *    숫자(tabular) 0  + variant-numeric: tabular-nums
 *
 *  줄높이 (line-height)
 *    본문      1.6           (한글 받침 여유)
 *    UI dense  1.5
 *    헤딩 (h3+)1.3
 *    h1/h2     1.15          (display)
 *    code      1.55
 *
 *  Prose 폭 — 680 px (Linear 624 ~ Anthropic 728 의 중간)
 * ============================================================ */

:root {
  /* 본문 인근 — 고정 (모바일/데스크탑 동일). */
  --text-xs: 0.81rem; /*    12.96 px  (16 × 0.9²) */
  --text-sm: 0.9rem; /*     14.4  px  (16 × 0.9) */
  --text-base: 1rem; /*     16    px  <-- 본문 (고정) */
  --text-lg: 1.1rem; /*     17.6  px  (16 × 1.1) */
  --text-xl: 1.21rem; /*    19.36 px  (16 × 1.1²) */
  --text-2xl: 1.331rem; /*  21.30 px  (16 × 1.1³) */

  /* 큰 헤딩 — fluid clamp(min, preferred, max).
   * 모바일 (≤ 375 px) 에선 min 으로 클램프되어 한 단계 아래 토큰값까지 down,
   * 데스크탑 (≥ 1280 px) 에선 max 로 클램프되어 현행 사이즈 유지. */
  --text-3xl: clamp(1.21rem,   1.104rem + 0.45vw,   1.4641rem); /* 19.36 ~ 23.43 px */
  --text-4xl: clamp(1.331rem,  1.216rem + 0.49vw,   1.6105rem); /* 21.30 ~ 25.77 px */
  --text-5xl: clamp(1.4641rem, 1.337rem + 0.5425vw, 1.7716rem); /* 23.43 ~ 28.34 px  <-- Hero */

  /* display 티어 — hero·랜딩 전용, 본문 스케일과 분리 (additive, 기존 --text-* 불변).
   * ±10% 컴파운딩 스케일은 문서·UI 밀도용이라 28px 에서 끝남 — 랜딩 hero 는
   * 별도 등급 필요 (Linear ~64px, Stripe ~90px 급 디스플레이 타입). */
  --text-display-sm: clamp(2rem, 1.55rem + 1.9vw, 3rem);   /* 32 ~ 48 px */
  --text-display-md: clamp(2.5rem, 1.84rem + 2.8vw, 4rem); /* 40 ~ 64 px */
  --text-display-lg: clamp(3rem, 2.06rem + 4vw, 5rem);     /* 48 ~ 80 px */
  --tracking-display: -0.03em; /* display 사이즈 전용 — 한글 혼용 안전 범위 */
  --leading-display: 1.05;

  /* 줄높이 */
  --leading-tight: 1.15;
  --leading-heading: 1.3;
  --leading-normal: 1.5;
  --leading-body: 1.6;
  --leading-code: 1.55;
  --leading-relaxed: 1.75;

  /* 자간 */
  --tracking-tighter: -0.025em;
  --tracking-heading: -0.015em;
  --tracking-normal: 0;
  --tracking-wide: 0.02em;
  --tracking-widest: 0.08em;

  /* 두께 (variable font axis) */
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  /* 폭 */
  --prose-max: 42.5rem; /* 680 px */
  --content-max: 75rem; /* 1200 px */
}

/* 기본 본문 — 어떤 페이지에서도 보장되는 baseline */
html {
  font-size: 16px;
  /* 한국어 본문의 어절 단위 줄바꿈 — Toss/Daangn 패턴 */
  word-break: keep-all;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-normal);
  color: var(--text-primary);
  background: var(--bg-base);
  font-weight: var(--weight-regular);
}

/* 표 / 숫자 행렬 — 등폭 숫자 + 마이너스 표시 정렬 */
table,
.tabular-nums {
  font-variant-numeric: tabular-nums;
}
/* ============================================================
 * AXE Labs — spacing / radius / motion
 *
 *  4-grid (Linear, Vercel 표준) — 8 단계
 * ============================================================ */

:root {
  /* spacing */
  --space-0: 0;
  --space-1: 0.25rem; /*  4 px */
  --space-2: 0.5rem; /*   8 px */
  --space-3: 0.75rem; /* 12 px */
  --space-4: 1rem; /*    16 px */
  --space-5: 1.5rem; /*  24 px */
  --space-6: 2rem; /*    32 px */
  --space-7: 3rem; /*    48 px */
  --space-8: 4rem; /*    64 px */
  --space-9: 6rem; /*    96 px */
  --space-10: 8rem; /*  128 px */

  /* radius */
  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-xl: 16px;
  --radius-2xl: 24px;
  --radius-full: 9999px;

  /* motion */
  --duration-fast: 120ms;
  --duration-base: 180ms;
  --duration-slow: 280ms;
  --duration-slower: 480ms; /* 진입 reveal · 큰 표면 전환 전용 */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  /* spring — 살짝 overshoot 하는 스냅 (segmented control thumb, 토글,
   * hover lift 류 마이크로 인터랙션). transform 전용으로 쓸 것. */
  --ease-spring: cubic-bezier(0.22, 1.36, 0.36, 1);

  /* z-index */
  --z-base: 1;
  --z-sticky: 100;
  --z-overlay: 1000;
  --z-modal: 1100;
  --z-toast: 1200;
}
/* ============================================================
 * AXE Labs — minimal reset
 *
 * 토큰 파일이 html/body 의 폰트·컬러·줄높이를 이미 잡으므로,
 * 이 파일은 여백·박스모델·기본 element 정상화만.
 * ============================================================ */

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

html,
body {
  margin: 0;
  padding: 0;
}

/* anchor 네비 부드럽게 — reduced-motion 환경은 아래 media query 가 auto 로 되돌림 */
html {
  scroll-behavior: smooth;
}

/* 헤딩 / 단락 / 리스트 / blockquote 의 기본 여백 제거.
 * 컴포넌트 / Prose 가 명시적으로 spacing 을 부여. */
h1,
h2,
h3,
h4,
h5,
h6,
p,
ul,
ol,
dl,
figure,
blockquote,
pre,
hr {
  margin: 0;
}

/* 리스트 기본 padding 제거 */
ul,
ol {
  padding: 0;
}

/* 이미지 / 미디어 — block, 부모 폭에 맞춤 */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* form element — 폰트 / 컬러 상속 */
input,
textarea,
select,
button {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

/* [hidden] 강제 — 컴포넌트 CSS 의 display:flex/grid 가 UA 의 [hidden]
 * display:none 을 덮어쓰면 hidden 토글이 시각적으로 무력화됨
 * (실례: .axe-sidebar__group-list 가 flex 라 그룹 접기가 안 먹던 버그,
 * 2026-06-10). until-found 는 검색 가시성 시맨틱이라 제외. */
[hidden]:not([hidden="until-found"]) {
  display: none !important;
}

/* 표 — collapse 기본 + 헤더 정렬 명시 */
table {
  border-collapse: collapse;
  width: 100%;
}

th {
  text-align: left;
  font-weight: var(--weight-semibold, 600);
}

/* 강조 인라인 — italic 의 한글 폴백 정상화 */
i,
em {
  font-style: italic;
  font-feature-settings: "kern";
}

/* 모션 줄이기 환경 — 자동 disable */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* focus 가시성 — 키보드만 (마우스 클릭 시는 끔).
 * border-radius 미지정: outline 은 element 자체 radius 를 따른다 (Chrome 94+).
 * 이전의 border-radius:var(--radius-sm) 은 outline 이 아니라 *element* 의
 * radius 를 덮어써 원형 컨트롤이 Tab 포커스 순간 4px 모서리로 깨지던 버그. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* selection 색 */
::selection {
  background: var(--accent);
  color: var(--accent-fg);
}
/* ============================================================
 * @axe/ui — Layout / Nav components (Phase 3)
 *
 * Owns: .axe-tabs__*, .axe-sidebar__*, .axe-breadcrumb__*, .axe-sheet__*
 * 토큰: --bg-*, --text-*, --border-*, --accent*, --space-*, --radius-*,
 *       --shadow-*, --duration-*, --ease-*, --font-* (모두 src/lib/tokens 정의).
 * 다크/라이트 자동 — CSS var 만 참조.
 * ============================================================ */

/* ============================================================
 *  Tabs — Radix Tabs 위 styling
 *
 *  horizontal: underline 활성 indicator + bottom border rail
 *  vertical:   좌측 indicator + 우측 컨텐츠
 * ============================================================ */
.axe-tabs {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.axe-tabs--vertical {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-6);
}

.axe-tabs__list {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
  /* Radix 가 자동으로 role="tablist" 부여, 키보드 nav 도 처리 */
}
.axe-tabs--vertical .axe-tabs__list {
  flex-direction: column;
  align-items: stretch;
  border-bottom: none;
  border-right: 1px solid var(--border-subtle);
  min-width: 12rem;
  padding-right: var(--space-2);
}

.axe-tabs__trigger {
  position: relative;
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium, 500);
  line-height: 1.4;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-tabs__trigger:hover {
  color: var(--text-primary);
}
.axe-tabs__trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.axe-tabs__trigger[data-state="active"] {
  color: var(--text-primary);
}
.axe-tabs__trigger[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* horizontal indicator (bottom underline) */
.axe-tabs--horizontal .axe-tabs__trigger::after {
  content: "";
  position: absolute;
  left: var(--space-3);
  right: var(--space-3);
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-tabs--horizontal .axe-tabs__trigger[data-state="active"]::after {
  transform: scaleX(1);
}

/* vertical indicator (left bar) */
.axe-tabs--vertical .axe-tabs__trigger {
  text-align: left;
  border-radius: var(--radius-sm);
}
.axe-tabs--vertical .axe-tabs__trigger::before {
  content: "";
  position: absolute;
  left: -1px;
  top: var(--space-2);
  bottom: var(--space-2);
  width: 2px;
  background: var(--accent);
  border-radius: 0 2px 2px 0;
  transform: scaleY(0);
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-tabs--vertical .axe-tabs__trigger[data-state="active"]::before {
  transform: scaleY(1);
}
.axe-tabs--vertical .axe-tabs__trigger[data-state="active"] {
  background: var(--bg-subtle);
}

.axe-tabs__content {
  outline: none;
  min-width: 0;
  flex: 1 1 auto;
}
.axe-tabs__content[data-state="inactive"] {
  display: none;
}

/* ============================================================
 *  Sidebar — 자체 구현 (semantic <nav><ul><li>)
 *
 *  Group 은 collapsible 시 <button aria-expanded> + 패널 [hidden].
 *  활성 항목: aria-current="page" + .axe-sidebar__item--active.
 * ============================================================ */
.axe-sidebar {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 14rem;
  padding: var(--space-3);
  background: var(--bg-base);
  color: var(--text-primary);
  border-right: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
}

.axe-sidebar__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.axe-sidebar__item {
  list-style: none;
}

/* 링크 — TOC(.axe-app-shell__toc-link) 와 같은 시각 언어 (2026-06-10 운영자
 * 피드백: 필 배경보다 레일+바가 좋다). 좌측 2px 보더가 group-list 의 1px
 * 레일에 -1px 로 겹치고, 활성이면 accent 바가 된다. 배경 필 없음. */
.axe-sidebar__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  text-align: left;
  appearance: none;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  margin-left: -1px;
  color: var(--text-secondary);
  font: inherit;
  line-height: 1.4;
  padding: var(--space-1) var(--space-3);
  cursor: pointer;
  text-decoration: none;
  transition:
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__link:hover {
  color: var(--text-primary);
}
.axe-sidebar__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}
.axe-sidebar__item--active > .axe-sidebar__link {
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-sidebar__item--disabled > .axe-sidebar__link {
  opacity: 0.5;
  cursor: not-allowed;
}

.axe-sidebar__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  color: var(--text-tertiary);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__item--active > .axe-sidebar__link .axe-sidebar__icon {
  color: var(--accent);
}

.axe-sidebar__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Group */
.axe-sidebar__group {
  list-style: none;
  margin-top: var(--space-4);
}
.axe-sidebar__group:first-child {
  margin-top: 0;
}

/* 그룹 헤더 — TOC 타이틀과 같은 조용한 캡션. hover 는 색만 (배경 필 X). */
.axe-sidebar__group-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  text-align: left;
  appearance: none;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: var(--weight-semibold, 600);
  color: var(--text-tertiary);
  padding: var(--space-2) var(--space-3) var(--space-1) 0;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__group-header:hover {
  color: var(--text-secondary);
}
.axe-sidebar__group-header--static {
  cursor: default;
}
.axe-sidebar__group-header--static:hover {
  color: var(--text-tertiary);
}
.axe-sidebar__group-header:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-sidebar__group-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-sidebar__chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}

/* 그룹 패널 — TOC 리스트와 동일한 1px 레일. 링크의 -1px 2px 보더가 위에
 * 겹친다. 들여쓰기 없이 레일 자체가 계층을 표현. */
.axe-sidebar__group-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--border-subtle);
}
/* belt-and-braces — 위 display:flex 가 UA [hidden] 을 이기므로 컴포넌트
 * 스코프에서도 접기를 보장. reset.css 의 글로벌 [hidden] 가드는 별도
 * entry(./reset)라 components.css 단독 소비자에게는 안 깔린다 (어드버서리얼
 * 리뷰 2026-06-10). */
.axe-sidebar__group-list[hidden] {
  display: none;
}

/* ============================================================
 *  Breadcrumb
 * ============================================================ */
.axe-breadcrumb {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.axe-breadcrumb__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}

.axe-breadcrumb__item {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}

.axe-breadcrumb__link {
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-breadcrumb__link:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-breadcrumb__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-breadcrumb__current {
  padding: var(--space-1) var(--space-2);
  color: var(--text-primary);
  font-weight: var(--weight-medium, 500);
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-breadcrumb__separator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 1em;
  padding: 0 var(--space-1);
  user-select: none;
}

/* ============================================================
 *  Sheet (Drawer) — Radix Dialog 위 styling
 *
 *  side variant: left / right / top / bottom
 *  data-state="open|closed" → 슬라이드 in/out 애니메이션.
 * ============================================================ */
.axe-sheet__overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay);
  backdrop-filter: blur(2px);
  z-index: 60;
  animation: axe-sheet-overlay-in 180ms ease-out;
}
.axe-sheet__overlay[data-state="closed"] {
  animation: axe-sheet-overlay-out 140ms ease-in forwards;
}

.axe-sheet__content {
  position: fixed;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  z-index: 61;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  overflow: auto;
}
.axe-sheet__content:focus { outline: none; }

/* right (default) */
.axe-sheet__content--right {
  top: 0;
  right: 0;
  bottom: 0;
  width: min(28rem, 92vw);
  max-width: 100vw;
  border-right: 0;
  border-top: 0;
  border-bottom: 0;
  border-top-left-radius: var(--radius-xl);
  border-bottom-left-radius: var(--radius-xl);
  animation: axe-sheet-in-right var(--duration-base) var(--ease-out);
}
.axe-sheet__content--right[data-state="closed"] {
  animation: axe-sheet-out-right var(--duration-fast) ease-in forwards;
}

/* left */
.axe-sheet__content--left {
  top: 0;
  left: 0;
  bottom: 0;
  width: min(20rem, 92vw);
  max-width: 100vw;
  border-left: 0;
  border-top: 0;
  border-bottom: 0;
  border-top-right-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xl);
  animation: axe-sheet-in-left var(--duration-base) var(--ease-out);
}
.axe-sheet__content--left[data-state="closed"] {
  animation: axe-sheet-out-left var(--duration-fast) ease-in forwards;
}

/* top */
.axe-sheet__content--top {
  top: 0;
  left: 0;
  right: 0;
  width: 100vw;
  max-height: min(80vh, 80dvh);
  border-top: 0;
  border-left: 0;
  border-right: 0;
  border-bottom-left-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xl);
  animation: axe-sheet-in-top var(--duration-base) var(--ease-out);
}
.axe-sheet__content--top[data-state="closed"] {
  animation: axe-sheet-out-top var(--duration-fast) ease-in forwards;
}

/* bottom */
.axe-sheet__content--bottom {
  bottom: 0;
  left: 0;
  right: 0;
  width: 100vw;
  max-height: min(80vh, 80dvh);
  border-bottom: 0;
  border-left: 0;
  border-right: 0;
  border-top-left-radius: var(--radius-xl);
  border-top-right-radius: var(--radius-xl);
  animation: axe-sheet-in-bottom var(--duration-base) var(--ease-out);
  /* safe-area for iOS PWA */
  padding-bottom: max(var(--space-6), env(safe-area-inset-bottom));
}
.axe-sheet__content--bottom[data-state="closed"] {
  animation: axe-sheet-out-bottom var(--duration-fast) ease-in forwards;
}

.axe-sheet__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-right: var(--space-8); /* close X 자리 */
}

.axe-sheet__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold, 600);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.axe-sheet__description {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
}

.axe-sheet__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

/* keyframes — side 별 슬라이드 */
@keyframes axe-sheet-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes axe-sheet-overlay-out {
  to { opacity: 0; }
}

@keyframes axe-sheet-in-right {
  from { transform: translate3d(100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-right {
  to { transform: translate3d(100%, 0, 0); }
}
@keyframes axe-sheet-in-left {
  from { transform: translate3d(-100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-left {
  to { transform: translate3d(-100%, 0, 0); }
}
@keyframes axe-sheet-in-top {
  from { transform: translate3d(0, -100%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-top {
  to { transform: translate3d(0, -100%, 0); }
}
@keyframes axe-sheet-in-bottom {
  from { transform: translate3d(0, 100%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-bottom {
  to { transform: translate3d(0, 100%, 0); }
}

/* ============================================================
 *  prefers-reduced-motion — 모든 transition/animation 비활성화
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .axe-tabs__trigger,
  .axe-tabs--horizontal .axe-tabs__trigger::after,
  .axe-tabs--vertical .axe-tabs__trigger::before,
  .axe-sidebar__link,
  .axe-sidebar__group-header,
  .axe-sidebar__chevron svg,
  .axe-breadcrumb__link,
  .axe-sheet__overlay,
  .axe-sheet__content {
    transition: none !important;
    animation: none !important;
  }
}

/* ============================================================
 *  AppShell — 통합 layout chrome (Phase 15)
 *
 *  variant (data-shell attribute):
 *    docs       — TopNav + Sidebar + Content + TOC + Footer (3단)
 *    dashboard  — TopNav + Sidebar + Content + Footer (2단)
 *    landing    — TopNav + Content + Footer (단일단, hero-friendly)
 *
 *  CSS-only — React / Rust(maud) / Python(jinja) 모두 동일 markup 으로 사용 가능.
 *  React wrapper (src/lib/components/app-shell/) 는 슬롯 합성 + 행동만 추가.
 *
 *  CSS variables (override 가능):
 *    --app-shell-sidebar-w   (기본 240px)
 *    --app-shell-toc-w       (기본 220px)
 *    --app-shell-content-max (기본 80ch — docs / 1280px — dashboard / 100% — landing)
 *    --app-shell-gutter      (기본 var(--space-6))
 *    --app-shell-topbar-h    (기본 56px — .axe-topnav 와 동일. ≤767.98px 도 56px — v0.6 단일행 topnav)
 *    --app-shell-subnav-h    (기본 44px — ≤1023px subnav disclosure bar. anchor 보정용 공개 토큰)
 *
 *  HTML 표준 markup (React = maud = jinja 공통 — v0.5):
 *    <div class="axe-app-shell" data-shell="docs">
 *      <a href="#main" class="axe-skip-link">본문으로 건너뛰기</a>
 *
 *      <div class="axe-app-shell__topbar">
 *        <!-- ① TopNav — items 는 nav 직계 3-슬롯 (components.css 헤더 참조) -->
 *        <nav class="axe-topnav" aria-label="Main navigation">
 *          <div class="axe-topnav__left"><a class="axe-logo" href="/">AXE Labs</a></div>
 *          <div class="axe-topnav__items"><!-- data-fade = JS enhancement -->
 *            <a class="axe-topnav__item" aria-current="page" href="#principles">원칙</a>
 *            <a class="axe-topnav__item" href="#colors">Tokens</a>
 *          </div>
 *          <div class="axe-topnav__right"><!-- ThemeToggle 등 --></div>
 *        </nav>
 *
 *        <!-- ② subnav disclosure — topbar sticky wrapper *안* (top 오프셋
 *             var 동기화 불요). ≥1024px display:none. sidebar 있는 variant 만. -->
 *        <details class="axe-app-shell__subnav">
 *          <summary class="axe-app-shell__subnav-summary">
 *            <svg class="axe-app-shell__subnav-chevron" aria-hidden="true" width="12" height="12"
 *                 viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
 *                 stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>
 *            <span class="axe-app-shell__subnav-label">메뉴</span>
 *          </summary>
 *          <div class="axe-app-shell__subnav-panel">
 *            <nav class="axe-sidebar" aria-label="Primary"><!-- 데스크톱 column 과 동일 markup --></nav>
 *            <div class="axe-app-shell__subnav-toc"><!-- docs variant + toc 있을 때만 --></div>
 *          </div>
 *        </details>
 *      </div>
 *
 *      <div class="axe-app-shell__main">
 *        <aside class="axe-app-shell__sidebar" aria-label="Primary">…</aside>
 *        <main id="main" class="axe-app-shell__content">…</main>
 *        <aside class="axe-app-shell__toc" aria-label="On this page">…</aside>
 *      </div>
 *      <div class="axe-app-shell__footer"><footer class="axe-footer">…</footer></div>
 *    </div>
 * ============================================================ */
:root {
  --app-shell-sidebar-w: 240px;
  --app-shell-toc-w: 220px;
  --app-shell-gutter: var(--space-6);
  --app-shell-topbar-h: 56px;
  /* 공개 토큰 — 커스텀 anchor 보정용 (≤1023px subnav bar 높이) */
  --app-shell-subnav-h: 44px;
}

.axe-app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--bg-base);
  color: var(--text-primary);
}

/* topbar slot — .axe-topnav 가 자체 sticky/blur. slot 은 stacking 만. */
.axe-app-shell__topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky, 100);
}

/* main — sidebar / content / toc 의 grid 컨테이너 */
.axe-app-shell__main {
  flex: 1 1 auto;
  display: grid;
  width: 100%;
  min-width: 0;
  grid-template-columns: minmax(0, 1fr); /* default (landing) = single column */
}

/* variant: docs — Sidebar | Content | TOC */
.axe-app-shell[data-shell="docs"] .axe-app-shell__main {
  grid-template-columns: var(--app-shell-sidebar-w) minmax(0, 1fr) var(--app-shell-toc-w);
}
/* variant: dashboard — Sidebar | Content */
.axe-app-shell[data-shell="dashboard"] .axe-app-shell__main {
  grid-template-columns: var(--app-shell-sidebar-w) minmax(0, 1fr);
}

/* sidebar slot — .axe-sidebar 가 내부 styling, slot 은 sticky/scroll 만. */
.axe-app-shell__sidebar {
  grid-column: 1;
  position: sticky;
  top: var(--app-shell-topbar-h);
  align-self: start;
  max-height: calc(100vh - var(--app-shell-topbar-h));
  max-height: calc(100dvh - var(--app-shell-topbar-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--bg-base);
  border-right: 1px solid var(--border-subtle);
}

/* content slot — variant 별 max-width / padding */
.axe-app-shell__content {
  min-width: 0;
  padding: var(--app-shell-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.axe-app-shell[data-shell="docs"] .axe-app-shell__content {
  max-width: var(--app-shell-content-max, 80ch);
  margin-inline: auto;
  width: 100%;
}
.axe-app-shell[data-shell="dashboard"] .axe-app-shell__content {
  max-width: var(--app-shell-content-max, 1280px);
  width: 100%;
  margin-inline: auto;
}
.axe-app-shell[data-shell="landing"] .axe-app-shell__content {
  /* full width — Hero/Section composites 가 자체 max-width 결정 */
  padding: 0;
  gap: 0;
}

/* TOC slot */
.axe-app-shell__toc {
  grid-column: 3;
  position: sticky;
  top: var(--app-shell-topbar-h);
  align-self: start;
  max-height: calc(100vh - var(--app-shell-topbar-h));
  max-height: calc(100dvh - var(--app-shell-topbar-h));
  overflow-y: auto;
  padding: var(--space-5) var(--space-4);
  border-left: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
  background: var(--bg-base);
}
.axe-app-shell__toc-title {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
  margin-bottom: var(--space-3);
  font-weight: var(--weight-semibold, 600);
}
.axe-app-shell__toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--border-subtle);
}
.axe-app-shell__toc-link {
  position: relative;
  display: block;
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--space-1) var(--space-3);
  margin-left: -1px;
  border-left: 2px solid transparent;
  font-size: var(--text-sm);
  line-height: 1.4;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-app-shell__toc-link:hover {
  color: var(--text-primary);
}
.axe-app-shell__toc-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}
.axe-app-shell__toc-link[aria-current="location"] {
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-app-shell__toc-link--h3 {
  padding-left: calc(var(--space-3) + var(--space-3));
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

/* footer slot — .axe-footer 가 내부 styling. slot 은 spacing 만. */
.axe-app-shell__footer {
  padding: 0 var(--app-shell-gutter);
}
.axe-app-shell[data-shell="landing"] .axe-app-shell__footer {
  background: var(--bg-subtle);
  border-top: 1px solid var(--border-subtle);
}

/* tablet & mobile (≤1023px) — 3-column 무너뜨림, sidebar/toc 숨김.
 * sidebar 내용은 아래 subnav disclosure 로 이동, toc 는 subnav 패널 하단. */
@media (max-width: 1023.98px) {
  .axe-app-shell[data-shell="docs"] .axe-app-shell__main,
  .axe-app-shell[data-shell="dashboard"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }
  .axe-app-shell__sidebar,
  .axe-app-shell__toc {
    display: none;
  }
}

/* ============================================================
 *  AppShell subnav — ≤1023px sticky disclosure (v0.5)
 *
 *  데스크톱 sidebar column 이 접히는 폭에서 같은 네비를 topbar 안의
 *  <details> bar 로 노출. topbar sticky wrapper *안* 에 중첩이라
 *  top 오프셋 var 동기화 문제 자체가 없음. 비모달 disclosure —
 *  scrim/focus trap/scroll lock 의도적 부재 (WAI-ARIA 패턴 준수).
 * ============================================================ */
.axe-app-shell__subnav {
  display: none;                   /* 데스크톱 부재 — [open] 잔존해도 무해 */
}

@media (max-width: 1023.98px) {
  .axe-app-shell__subnav {
    display: block;
    /* 패널 absolute 의 containing block — topbar sticky 직접 의존 대신
     * details 자체에 relative (iOS Safari sticky 모서리 회피) */
    position: relative;
    /* blur 비사용 — topnav 와 2중 backdrop-filter 비용 회피
     * (components.css 의 blur 커널 축소 결정과 정합) */
    background: var(--bg-base);
    border-bottom: 1px solid var(--border-subtle);
  }
  .axe-app-shell__subnav-summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--app-shell-subnav-h);
    padding: 0 var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium, 500);
    color: var(--text-secondary);
    cursor: pointer;
    user-select: none;
    list-style: none;
  }
  .axe-app-shell__subnav-summary::-webkit-details-marker {
    display: none;
  }
  .axe-app-shell__subnav-summary:hover {
    color: var(--text-primary);
  }
  .axe-app-shell__subnav-summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
  }
  .axe-app-shell__subnav[open] .axe-app-shell__subnav-summary {
    color: var(--text-primary);
  }
  .axe-app-shell__subnav-chevron {
    display: inline-flex;
    color: var(--text-muted);
    /* Sidebar Chevron(right→90°) 과 동일 언어 */
    transition: transform var(--duration-fast) var(--ease-out);
  }
  .axe-app-shell__subnav[open] .axe-app-shell__subnav-chevron {
    transform: rotate(90deg);
  }

  /* 패널 — absolute overlay: 본문 layout shift 0 (in-flow push 거부 — CLS) */
  .axe-app-shell__subnav-panel {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    max-height: calc(100dvh - var(--app-shell-topbar-h) - var(--app-shell-subnav-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    background: var(--bg-base);
    border-bottom: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    padding: var(--space-2) var(--space-2) var(--space-5);
  }
  .axe-app-shell__subnav-panel .axe-sidebar {
    border-right: 0;
    min-width: 0;
  }
  .axe-app-shell__subnav-toc {
    margin-top: var(--space-4);
    padding: var(--space-4) var(--space-3) 0;
    border-top: 1px solid var(--border-subtle);
  }

  /* anchor 착지 보정 — 범용 [id]. 근사 generous 값: 작아서 가리는 것만 금지
   * (과보정은 착지가 약간 내려올 뿐 가림 없음). */
  .axe-app-shell {
    --app-shell-topbar-h: 56px;
  }
  .axe-app-shell__content [id] {
    scroll-margin-top: calc(var(--app-shell-topbar-h) + var(--app-shell-subnav-h, 0px) + var(--space-3));
  }
}

/* small mobile — content gutter 축소 */
@media (max-width: 767.98px) {
  .axe-app-shell {
    --app-shell-gutter: var(--space-4);
    /* v0.6 (2026-06-17): 모바일 topnav = 단일 행 56px (종전 2행 92px 폐지,
     * components.css). 드로어가 인라인 items/right 를 대체하므로 topbar 높이
     * 계약은 56px 단일행. */
    --app-shell-topbar-h: 56px;
  }
}

/* 인쇄 — chrome 전부 숨김 + single column. .axe-doc(document.css) 경로와 무교차. */
@media print {
  .axe-app-shell__topbar,
  .axe-app-shell__subnav,
  .axe-app-shell__sidebar,
  .axe-app-shell__toc,
  .axe-app-shell__footer,
  .axe-skip-link {
    display: none !important;
  }
  .axe-app-shell[data-shell] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* prefers-reduced-motion — AppShell transition 비활성화 */
@media (prefers-reduced-motion: reduce) {
  .axe-app-shell__toc-link,
  .axe-app-shell__subnav-chevron {
    transition: none !important;
  }
}

/* ============================================================
 *  Layout primitives — Stack / Cluster / Grid / Container (Phase 16)
 *
 *  CSS-only.  React wrapper (src/lib/components/layout/) 는 prop → class
 *  매핑만 한다.  matrix / cortex 처럼 inline col()/grid()/max-width 를
 *  재발명하던 비-Tailwind 소비자가 동일 markup 으로 채택 가능
 *  (Tailwind 0 원칙 — SSOT 가 spacing/layout utility 를 직접 제공).
 *
 *    Stack     — 세로 flex + gap            (구 col())
 *    Cluster   — 가로 flex + wrap + gap      (toolbar / inline row / header)
 *    Grid      — 반응형 grid                 (구 grid(N)) — cols 1~6 또는 auto-fill
 *    Container — max-width 중앙 정렬 + gutter (구 <main style={{maxWidth}}>)
 *
 *  gap modifier 는 spacing scale (--space-N) 0~8 단계와 1:1 (default 는
 *  Stack/ Grid = --space-4, Cluster = --space-3).
 * ============================================================ */

/* --- Stack (vertical) --- */
.axe-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
.axe-stack--gap-0 { gap: 0; }
.axe-stack--gap-1 { gap: var(--space-1); }
.axe-stack--gap-2 { gap: var(--space-2); }
.axe-stack--gap-3 { gap: var(--space-3); }
.axe-stack--gap-4 { gap: var(--space-4); }
.axe-stack--gap-5 { gap: var(--space-5); }
.axe-stack--gap-6 { gap: var(--space-6); }
.axe-stack--gap-7 { gap: var(--space-7); }
.axe-stack--gap-8 { gap: var(--space-8); }
.axe-stack--gap-9 { gap: var(--space-9); }
.axe-stack--gap-10 { gap: var(--space-10); }
.axe-stack--align-start { align-items: flex-start; }
.axe-stack--align-center { align-items: center; }
.axe-stack--align-end { align-items: flex-end; }
.axe-stack--align-stretch { align-items: stretch; }

/* --- Cluster (horizontal, wraps) --- */
.axe-cluster {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.axe-cluster--gap-0 { gap: 0; }
.axe-cluster--gap-1 { gap: var(--space-1); }
.axe-cluster--gap-2 { gap: var(--space-2); }
.axe-cluster--gap-3 { gap: var(--space-3); }
.axe-cluster--gap-4 { gap: var(--space-4); }
.axe-cluster--gap-5 { gap: var(--space-5); }
.axe-cluster--gap-6 { gap: var(--space-6); }
.axe-cluster--gap-7 { gap: var(--space-7); }
.axe-cluster--gap-8 { gap: var(--space-8); }
.axe-cluster--gap-9 { gap: var(--space-9); }
.axe-cluster--gap-10 { gap: var(--space-10); }
.axe-cluster--nowrap { flex-wrap: nowrap; }
.axe-cluster--align-start { align-items: flex-start; }
.axe-cluster--align-center { align-items: center; }
.axe-cluster--align-end { align-items: flex-end; }
.axe-cluster--align-baseline { align-items: baseline; }
.axe-cluster--align-stretch { align-items: stretch; }
.axe-cluster--justify-start { justify-content: flex-start; }
.axe-cluster--justify-center { justify-content: center; }
.axe-cluster--justify-end { justify-content: flex-end; }
.axe-cluster--justify-between { justify-content: space-between; }

/* --- Grid --- */
.axe-grid {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}
.axe-grid--gap-0 { gap: 0; }
.axe-grid--gap-1 { gap: var(--space-1); }
.axe-grid--gap-2 { gap: var(--space-2); }
.axe-grid--gap-3 { gap: var(--space-3); }
.axe-grid--gap-4 { gap: var(--space-4); }
.axe-grid--gap-5 { gap: var(--space-5); }
.axe-grid--gap-6 { gap: var(--space-6); }
.axe-grid--cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.axe-grid--cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.axe-grid--cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.axe-grid--cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.axe-grid--cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.axe-grid--cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
/* auto-fill: 카드가 --axe-grid-min 폭 이하로 줄지 않게 자동 wrap (cortex .cortex-metric-grid 대체) */
.axe-grid--auto {
  grid-template-columns: repeat(auto-fill, minmax(var(--axe-grid-min, 15rem), 1fr));
}

/* responsive — cols-N 을 작은 화면에서 단계적으로 접음.
   inline var 가 아니라 modifier class 라 media query 가 specificity 로 override 가능. */
@media (max-width: 1023.98px) {
  .axe-grid--responsive.axe-grid--cols-3,
  .axe-grid--responsive.axe-grid--cols-4,
  .axe-grid--responsive.axe-grid--cols-5,
  .axe-grid--responsive.axe-grid--cols-6 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 639.98px) {
  .axe-grid--responsive.axe-grid--cols-2,
  .axe-grid--responsive.axe-grid--cols-3,
  .axe-grid--responsive.axe-grid--cols-4,
  .axe-grid--responsive.axe-grid--cols-5,
  .axe-grid--responsive.axe-grid--cols-6 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --- Container (max-width centered + gutter) --- */
.axe-container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--space-4);
  max-width: var(--axe-container-max, 72rem);
}
.axe-container--sm { --axe-container-max: 40rem; }
.axe-container--md { --axe-container-max: 56rem; }
.axe-container--lg { --axe-container-max: 72rem; }
.axe-container--xl { --axe-container-max: 80rem; }
.axe-container--full { --axe-container-max: 100%; }

/* ============================================================
 *  ThemeToggle — light / system / dark control (Phase 16)
 *
 *  useTheme 위 thin control.  segment(3-버튼) / cycle(단일 순환) 두 형태.
 *  matrix·blueprint·design 페이지가 각자 재발명하던 토글을 SSOT 로 흡수.
 *  내부 버튼은 .axe-btn 재사용 — 별도 색 정의 없음 (segment wrap 만 정의).
 * ============================================================ */
.axe-theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.axe-theme-toggle__icon {
  display: inline-flex;
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
}
.axe-theme-toggle__icon svg {
  width: 100%;
  height: 100%;
}
/* ============================================================
 * AXE Labs — component styles
 *
 * 모든 컴포넌트는 .axe- prefix.  Tailwind 의존 0.
 * CSS 변수로만 컬러·폰트·간격 참조 → light/dark 자동 전환.
 *
 * 그룹별 CSS 는 별도 파일 → 본 파일에서 @import.
 * 소비자는 components.css 만 import 해도 전 그룹 다 로드.
 * ============================================================ */

/* v2 component groups (Phase 1-14) — 그룹별 격리 + 한 곳 통합 */
@import "./overlays.css";      /* Toast / Popover / Tooltip */
@import "./form.css";          /* Select / Checkbox / Radio / Switch / FormField / Label */
@import "./layout.css";        /* Tabs / Sidebar / Breadcrumb / Sheet */
@import "./indicators.css";    /* Skeleton / Spinner / Avatar / Progress */
@import "./dashboard.css";     /* StatusLight / MetricCard / PipelineTable */
@import "./mobile.css";        /* safe-area / tap highlight / .axe-tabular-nums / .axe-sticky-blur */
@import "./agent.css";         /* AgentExecutor / StreamingTable / MultiModalChatInput */
/* Phase 14 — gap fill */
@import "./data-display.css";  /* DataTable / Pagination / Chart */
@import "./menus.css";         /* AlertDialog / Accordion / DropdownMenu */
@import "./feedback.css";      /* EmptyState / ErrorBoundary */
@import "./data-views.css";    /* Tree / Timeline / MasterDetailLayout */
@import "./chat-ext.css";      /* MessageWithSources / TypingIndicator / StatusBanner / ResponsiveTabs */
@import "./composites.css";    /* Code / Section / Hero / Footer / Splitter / Callout left-bar modifier */
/* Phase 17 (D-ui-3 Phase 2) — 문서/인쇄 템플릿 */
@import "./document.css";      /* .axe-doc IC Memo · LP letter (가로/세로, A4 @page, @media print) */
@import "./code-theme.css";     /* shiki ServerCodeBlock 팔레트 (--shiki-* → 디자인 토큰) */
/* NOTE: tailwind-bridge.css 는 *opt-in* — 소비자가 Tailwind 쓸 때만 명시 import. */

/* ------- Logo ------- */
.axe-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: var(--weight-medium);
  letter-spacing: 0.02em;
  color: var(--accent);
  text-decoration: none;
  font-size: var(--text-lg);
  line-height: 1;
  white-space: nowrap;
}

.axe-logo--sm {
  font-size: var(--text-base);
}
.axe-logo--lg {
  font-size: var(--text-2xl);
}

/* ------- TopNav -------
 * v0.5 canonical markup — items 가 nav 직계 3-슬롯 (React = maud = jinja 공통):
 *   <nav class="axe-topnav" aria-label="Main navigation">
 *     <div class="axe-topnav__left"><a class="axe-logo" href="/">AXE Labs</a></div>
 *     <div class="axe-topnav__items"><!-- data-fade="left|right|both" = JS enhancement -->
 *       <a class="axe-topnav__item" aria-current="page" href="#principles">원칙</a>
 *       <a class="axe-topnav__item" href="#colors">Tokens</a>
 *     </div>
 *     <div class="axe-topnav__right"><!-- ThemeToggle 등 --></div>
 *   </nav>
 * 종전(v0.4)에는 items 가 __left 내부였음 — nav 직계 3-슬롯으로 평탄화.
 * 데스크톱 시각은 margin-left 보정으로 동일.
 * 모바일(≤767.98px, v0.6)에서는 같은 __items/__right 요소를 CSS 로 좌·우
 * 슬라이드 드로어로 재배치하고 ☰/⋯ 버튼이 토글한다 (아래 @media 블록 참조). */
.axe-topnav {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-5);
  /* blur 커널 20px → 12px + 불투명도 92→95%: sticky 스크롤 경로에서 매 프레임
   * 재필터되는 비용을 줄임 (저사양 GPU 스크롤 jank 원인). 95% 불투명이라
   * 시각 차이는 거의 없음. */
  background: color-mix(in oklch, var(--bg-base) 95%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--border-subtle);
  /* 모바일 nav 가 참조 — 768px 미만에서 navbar 바로 아래에 fixed 로 펼침. */
  --axe-topnav-height: 56px;
  /* 바 높이를 토큰에 고정한다. 드로어(.axe-topnav__items/__right)·scrim·sub-nav
   * 가 모두 top:var(--axe-topnav-height) 로 anchor 하는데, 바의 자연 높이(컨텐츠
   * +패딩)가 토큰보다 작으면 그 차이가 바 아래·드로어 위 사이 여백으로 보인다
   * (모바일 ≈52px<56px → ~4px 띠, 2026-06-17 운영자 보고). min-height 로 바를
   * 정확히 토큰 높이로 맞춰 anchor 와 flush 하게 한다 (align-items:center 가
   * 컨텐츠 수직 중앙정렬 유지 — 데스크톱 바는 이미 ≈56px 라 시각 변화 없음). */
  min-height: var(--axe-topnav-height);
}
/* 로고 전용 슬롯 — 종전 flex:1 1 auto + overflow:hidden + gap space-6 삭제.
 * items 가 nav 직계로 빠지면서 left 는 더 이상 늘어나지 않는다. */
.axe-topnav__left {
  display: flex;
  align-items: center;
  min-width: 0;
  flex: 0 0 auto;
}
.axe-topnav__items {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  /* nav 직계 가변 슬롯 — right (테마 토글 등) 절대 가리지 않음 */
  flex: 1 1 0;
  min-width: 0;
  /* nav gap 24px(space-5) + 8px(space-2) = 32px — 종전 __left 내부 gap
   * space-6(32px) 보존 (데스크톱 시각 변화 0). */
  margin-left: var(--space-2);
  /* Tab focus 시 fade 영역 밖에 착지 */
  scroll-padding-inline: var(--space-6);
  /* items 많으면 가로 스크롤 */
  overflow-x: auto;
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* IE/old Edge */
}
.axe-topnav__items::-webkit-scrollbar {
  display: none;               /* Chrome/Safari */
}
/* fade gradient = "더 있다" 시각 힌트 — 실제 가려진 쪽에만.
 * data-fade 는 TopNavItems(client) 가 scroll/resize 마다 토글.
 * 무조건 mask 를 걸면 오버플로우 없는 데스크톱에서 마지막 항목
 * 끝 글자가 깎인다 (2026-06-10 회귀 — 재발 금지). */
.axe-topnav__items[data-fade="right"] {
  mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
}
.axe-topnav__items[data-fade="left"] {
  mask-image: linear-gradient(to left, black calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to left, black calc(100% - 24px), transparent 100%);
}
.axe-topnav__items[data-fade="both"] {
  mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
}
.axe-topnav__item {
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-md);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  letter-spacing: 0.005em;
  color: var(--text-secondary);
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__item:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-topnav__item[aria-current="page"],
.axe-topnav__item--active {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}
.axe-topnav__right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 0 0 auto;     /* 우선순위 — 절대 줄지 않음 */
  margin-left: var(--space-4);
}

/* ------- TopNav menu (NavMenu) -------
 * entity-selector + user-menu 통일 드롭다운. trigger(pill) + popover(absolute).
 * 같은 클래스로 두 용도가 픽셀 단위로 동일하게 보이게 한다. JS(NavMenu.tsx)는
 * open 토글 + click-outside + ↑↓/Esc 만; 표시는 100% CSS. */
.axe-topnav__menu {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}
.axe-topnav__menu-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 220px;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-base);
  color: var(--text-secondary);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-trigger:hover {
  color: var(--text-primary);
  border-color: var(--accent);
  background: var(--bg-subtle);
}
.axe-topnav__menu-trigger[data-state="open"] {
  color: var(--text-primary);
  border-color: var(--accent);
}
.axe-topnav__menu-trigger:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-topnav__menu-trigger[data-accent] {
  border-color: var(--accent);
  color: var(--text-primary);
}
.axe-topnav__menu-trigger-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.axe-topnav__menu-chevron {
  flex: 0 0 auto;
  color: var(--text-muted);
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-topnav__menu-trigger[data-state="open"] .axe-topnav__menu-chevron {
  transform: rotate(180deg);
}

.axe-topnav__menu-popover {
  position: absolute;
  top: calc(100% + var(--space-2));
  /* 자동폭: trigger 폭 이상에서 시작해 내용에 맞춰 늘되 320px 상한. 종전 고정
   * min-width 200px 가 짧은 메뉴(계정 전환 등)에서 과하게 넓었음 (운영자 2026-06-17). */
  min-width: 100%;
  width: max-content;
  max-width: 320px;
  padding: var(--space-1);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  z-index: var(--z-overlay);
  animation: axe-topnav-menu-in var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-popover[data-align="right"] { right: 0; }
.axe-topnav__menu-popover[data-align="left"]  { left: 0; }

.axe-topnav__menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-item:hover,
.axe-topnav__menu-item:focus-visible {
  outline: none;
  background: var(--bg-subtle);
  color: var(--text-primary);
}
.axe-topnav__menu-item--active {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  background: var(--accent-soft);
}
.axe-topnav__menu-item-label {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.axe-topnav__menu-item-meta {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.axe-topnav__menu-empty {
  padding: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-align: center;
}
.axe-topnav__menu-header {
  margin-bottom: var(--space-1);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}
.axe-topnav__menu-header-label {
  display: block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  white-space: nowrap;
}
.axe-topnav__menu-footer {
  margin-top: var(--space-1);
  padding-top: var(--space-1);
  border-top: 1px solid var(--border-subtle);
}
.axe-topnav__menu-item--danger {
  color: var(--danger);
}
.axe-topnav__menu-item--danger:hover,
.axe-topnav__menu-item--danger:focus-visible {
  background: var(--danger-soft);
  color: var(--danger);
}

@keyframes axe-topnav-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .axe-topnav__menu-popover { animation: none; }
  .axe-topnav__menu-chevron { transition: none; }
}

/* ------- TopNav brand (home/brand 링크) -------
 * Logo 와 별개로 .axe-topnav__brand 만 붙여도 brand 식자(Clash) 로 렌더 가능.
 * Latin=Clash Display, 한글=Pretendard 폴백 (의도). */
.axe-topnav__brand {
  font-family: var(--font-clash);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}
.axe-topnav__brand:hover {
  color: var(--accent-hover);
}
.axe-topnav__brand:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ------- Hamburger · Kebab 버튼 (모바일 전용 — 데스크톱 display:none) -------
 * v0.6: 모바일 2-드로어가 새 기본. 햄버거(좌)=items 드로어 토글,
 * kebab(우, 원형)=right 슬롯 드로어 토글. 둘 다 nav 바에 상주(드로어 밖)이라
 * 드로어가 슬라이드해도 토글 가능. 데스크톱에서는 @media 밖 display:none. */
.axe-topnav__hamburger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  color: var(--text-primary);
  background: transparent;
  transition: background var(--duration-fast) var(--ease-out);
}
/* hover 는 실제 포인터에서만 — 모바일 터치 탭이 :hover 를 sticky 하게 남겨
 * 열고/닫은 뒤에도 배경이 밝게 유지되던 것 차단 (운영자 2026-06-18). */
@media (hover: hover) {
  .axe-topnav__hamburger:hover {
    background: var(--bg-subtle);
  }
}
.axe-topnav__hamburger:focus-visible {
  /* 포커스·활성 시 배경 변화 없음 — 열고/닫을 때 brighten 방지(운영자 2026-06-18,
   * 종전 bg-subtle 제거). 네온 outline 도 제거됨(이전 라운드). 키보드 포커스 표식은
   * 아이콘 상태(☰↔X)+드로어 슬라이드로 대체. */
  outline: none;
}
/* kebab — 햄버거와 동일한 plain 아이콘 버튼(좌우 대칭). 원형/테두리 제거
 * (운영자 2026-06-17: 우측 버튼 사이즈·디자인이 좌측 햄버거와 안 맞던 것 통일). */
.axe-topnav__kebab {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  color: var(--text-primary);
  background: transparent;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
/* hover = 실제 포인터만. data-open(드로어 열림) 활성 bg 제거 — kebab 이 드로어
 * 열린 동안 밝게 유지되던 "활성화" 차단 (운영자 2026-06-18). */
@media (hover: hover) {
  .axe-topnav__kebab:hover {
    background: var(--bg-subtle);
  }
}
.axe-topnav__kebab:focus-visible {
  /* 햄버거와 동일 — 배경/링 변화 없음 (2026-06-18). */
  outline: none;
}
.axe-topnav__kebab-icon {
  flex: 0 0 auto;
}

/* scrim — 양 드로어 공통 반투명 배경. nav 의 형제. 데스크톱 display:none. */
.axe-mobile-scrim {
  display: none;
}

/* 햄버거 line — open 시 X 로 변형. transform 만 애니메이션 → GPU. */
.axe-hamburger-line {
  transform-origin: center;
  transition:
    transform var(--duration-base) var(--ease-out),
    opacity var(--duration-fast) var(--ease-out);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--top {
  transform: translateY(6px) rotate(45deg);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--mid {
  opacity: 0;
  transform: scaleX(0);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--bot {
  transform: translateY(-6px) rotate(-45deg);
}

/* ------- 모바일 2-드로어 (≤767.98px) — v0.6 새 기본 (2026-06-17) -------
 * 단일 행 바 = [☰ 햄버거(좌)] [브랜드] [⋯ kebab(우, 원형)]. 인라인 items 와
 * 인라인 right 슬롯은 같은 요소를 CSS 로 고정 슬라이드 드로어로 재배치(중복
 * 렌더 없음). data-open="true" = 열림. 종전 2행 grid + .axe-mobile-nav 풀스크린
 * 오버레이 + .axe-topnav--drawer opt-in 은 폐지.
 *
 * 데스크톱(≥768px) inline 규칙은 이 @media 밖에 그대로 — 드로어 규칙은 모바일
 * 한정. 브레이크포인트 768px = docs.axelabs.ai (Nextra md) 와 동일. */
@media (max-width: 767.98px) {
  .axe-topnav {
    /* 단일 행 3-칼럼: [☰ 좌][브랜드 가운데][⋯ 우]. brand 를 뷰포트 가운데 고정
     * (drawer 는 position:fixed 라 grid flow 에서 빠짐 → 3 in-flow 항목만 칼럼 차지). */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    /* 드로어 top = 단일 행 높이. (종전 92px 2행 폐지.) */
    --axe-topnav-height: 56px;
    /* ⚠️ backdrop-filter 는 position:fixed 자손의 containing block 을 만든다
     * (spec). 드로어(.axe-topnav__items/.axe-topnav__right) 가 nav 의 자식
     * 이므로, blur 를 켜두면 fixed 드로어가 viewport 가 아닌 56px nav 박스에
     * 갇혀 height 가 붕괴한다. 모바일에선 blur 제거 + 불투명 배경으로 같은
     * 시각을 유지하면서 containment trap 을 푼다. */
    background: var(--bg-base);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .axe-topnav__hamburger {
    display: inline-flex;
    grid-column: 1;
    justify-self: start;
  }
  .axe-topnav__kebab {
    display: inline-flex;
    grid-column: 3;
    justify-self: end;
  }
  /* 브랜드 슬롯 — 가운데 칼럼 = 뷰포트 중앙. */
  .axe-topnav__left {
    grid-column: 2;
    justify-self: center;
    margin-left: 0;
  }

  /* 좌 드로어 = nav items. 좌측 고정, translateX(-100%)→0 슬라이드. */
  .axe-topnav__items {
    position: fixed;
    top: var(--axe-topnav-height);
    left: 0;
    bottom: 0;
    width: min(280px, 80vw);
    margin: 0;
    padding: var(--space-3);
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);
    overflow-y: auto;
    overflow-x: hidden;             /* 세로 리스트 — 가로 fade 미적용 */
    overscroll-behavior: contain;
    background: var(--bg-base);
    border-right: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-overlay);
    /* translate3d 로 GPU layer 강제 → 60fps (docs.axelabs.ai 패턴). */
    transform: translate3d(-100%, 0, 0);
    /* 닫힘 시 슬라이드아웃 완료 후 visibility:hidden → 키보드 tab·스크린리더에서
     * 제거 (transform 만으론 오프스크린 항목이 포커스·AT 에 남는 회귀). */
    visibility: hidden;
    transition:
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear var(--duration-base);
    /* 세로 드로어엔 가로 오버플로우 없음 → data-fade mask 미적용. 안전상 명시 해제. */
    mask-image: none;
    -webkit-mask-image: none;
  }
  .axe-topnav__items[data-open="true"] {
    transform: translate3d(0, 0, 0);
    visibility: visible;
    transition: transform var(--duration-base) var(--ease-out);
  }
  /* 모바일 항목 = 세로 리스트. 탭타깃은 패딩(space-3 space-4 ≈ 44px 행)이 확보.
   * font-size 는 text-sm — 우 드로어(entity·계정 리스트 = text-sm)와 동일 스케일로
   * 통일 (종전 text-base 는 좌 드로어만 16px 라 우 드로어 14.4px 대비 떠 보였다,
   * 2026-06-17 운영자 보고). 드로어 타입 스케일: 헤더 text-xs / 항목 text-sm. */
  .axe-topnav__item {
    display: block;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    white-space: normal;
  }

  /* 우 드로어 = right 슬롯(entity+user NavMenu). 우측 고정, translateX(100%)→0. */
  .axe-topnav__right {
    position: fixed;
    top: var(--axe-topnav-height);
    right: 0;
    bottom: 0;
    width: min(300px, 85vw);
    margin: 0;
    padding: var(--space-4);
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg-base);
    border-left: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-overlay);
    transform: translate3d(100%, 0, 0);
    visibility: hidden;
    transition:
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear var(--duration-base);
  }
  .axe-topnav__right[data-open="true"] {
    transform: translate3d(0, 0, 0);
    visibility: visible;
    transition: transform var(--duration-base) var(--ease-out);
  }
  /* 우 드로어 안 NavMenu — 폭 채우고 trigger 도 full-width. popover 는
   * 드로어 스크롤 내 표시 (z-index 동일, 드로어보다 위 stacking). */
  .axe-topnav__right .axe-topnav__menu {
    display: flex;
    width: 100%;
  }
  .axe-topnav__right .axe-topnav__menu-trigger {
    width: 100%;
    max-width: none;
    justify-content: space-between;
  }
  .axe-topnav__right .axe-topnav__menu-popover {
    /* 드로어 안에서는 absolute float 대신 inline 펼침 — 스크롤 컨테이너
     * 클리핑·viewport 초과 점프 방지. */
    position: static;
    max-width: none;
    box-shadow: none;
    animation: none;
    margin-top: var(--space-1);
  }

  /* scrim — 양 드로어 공통. 바 아래(top) 전체 덮음. 패널보다 한 단계 아래. */
  .axe-mobile-scrim {
    display: block;
    position: fixed;
    inset: 0;
    /* scrim 은 nav 형제라 .axe-topnav 의 --axe-topnav-height 를 상속 못 함 → fallback 필수 */
    top: var(--axe-topnav-height, 56px);
    background: var(--bg-overlay);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-out);
    z-index: calc(var(--z-overlay) - 1);
  }
  .axe-mobile-scrim[data-open="true"] {
    opacity: 1;
    pointer-events: auto;
  }
}

@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
  .axe-topnav__items,
  .axe-topnav__right,
  .axe-mobile-scrim,
  .axe-hamburger-line,
  .axe-topnav__kebab {
    transition: none;
  }
}

/* ------- Button ------- */
.axe-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: 36px;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: 0;
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
  white-space: nowrap;
  user-select: none;
  border: 1px solid transparent;
}
.axe-btn:disabled,
.axe-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}
.axe-btn:active:not(:disabled) {
  transform: scale(0.98);
}

.axe-btn--sm {
  height: 28px;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}
.axe-btn--lg {
  height: 44px;
  padding: 0 var(--space-5);
  font-size: var(--text-base);
}

.axe-btn--primary {
  background: var(--cta);
  color: var(--cta-fg);
  font-weight: var(--weight-semibold);
}
.axe-btn--primary:hover:not(:disabled) {
  background: var(--cta-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.axe-btn--primary:active:not(:disabled) {
  transform: scale(0.98); /* hover lift 보다 우선 — 누름 피드백 */
  box-shadow: none;
}

.axe-btn--secondary {
  background: var(--bg-elevated);
  border-color: var(--border-default);
  color: var(--text-primary);
}
.axe-btn--secondary:hover:not(:disabled) {
  border-color: var(--border-strong);
  background: var(--bg-subtle);
}

.axe-btn--ghost {
  background: transparent;
  color: var(--text-secondary);
}
.axe-btn--ghost:hover:not(:disabled) {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-btn--danger {
  background: var(--danger);
  color: #fff;
}
.axe-btn--danger:hover:not(:disabled) {
  filter: brightness(0.95);
}

/* loading 상태 (Button loading prop) — spinner 가 children 앞에 렌더됨 */
.axe-btn--loading {
  pointer-events: none;
}
.axe-btn__icon {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

/* ------- Seg (segmented control) -------
 * VariantSwitcher · DocSeg 등이 inline style 로 2번 재발명하던 패턴의 SSOT.
 * React <Seg> + CSS-only (maud/jinja) 양쪽에서 동일 markup:
 *   <div class="axe-seg" role="group" aria-label="...">
 *     <button class="axe-seg__btn" aria-pressed="true">A</button>
 *     <button class="axe-seg__btn">B</button>
 *   </div>
 */
.axe-seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.axe-seg__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  /* spring snap — transform/색만 변경 (compositor-safe) */
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-seg__btn:hover:not([aria-pressed="true"]) {
  color: var(--text-primary);
}
.axe-seg__btn:active {
  transform: scale(0.96);
}
.axe-seg__btn[aria-pressed="true"],
.axe-seg__btn--active {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-subtle);
  box-shadow: var(--shadow-xs);
}
.axe-seg--sm .axe-seg__btn {
  height: 24px;
  padding: 0 var(--space-2);
}

/* ------- ToggleGroup (axe-toggle-group__*) -------
 * Seg 와 같은 시각 family(pill 묶음)이나 의미가 다르다: Seg = 단일 필수 선택
 * (항상 1개 pressed), ToggleGroup = 다중 토글 또는 해제 가능한 단일 (0~N개
 * pressed) — 정렬/서식 툴바·필터 칩. React <ToggleGroup> + CSS-only
 * (maud/jinja) 양쪽 동일 markup:
 *   <div class="axe-toggle-group" role="group" aria-label="...">
 *     <button class="axe-toggle-group__btn" aria-pressed="true">B</button>
 *     <button class="axe-toggle-group__btn">I</button>
 *   </div>
 */
.axe-toggle-group {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.axe-toggle-group__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-toggle-group__btn:hover:not([aria-pressed="true"]):not(:disabled) {
  color: var(--text-primary);
}
.axe-toggle-group__btn:active:not(:disabled) {
  transform: scale(0.96);
}
.axe-toggle-group__btn[aria-pressed="true"] {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-subtle);
  box-shadow: var(--shadow-xs);
}
.axe-toggle-group__btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-toggle-group--sm .axe-toggle-group__btn {
  height: 24px;
  min-width: 24px;
  padding: 0 var(--space-2);
}

/* ------- Toggle (axe-toggle) — standalone 단일 두-상태 누름 -------
 * .axe-toggle-group__btn 의 standalone 변형 — 묶음 컨테이너가 없으니
 * 자체 border/bg 를 들고 다닌다. pressed = aria-pressed="true". 동일 motion.
 *   <button class="axe-toggle" aria-pressed="true">★</button> */
.axe-toggle {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-toggle:hover:not([aria-pressed="true"]):not(:disabled) {
  color: var(--text-primary);
}
.axe-toggle:active:not(:disabled) {
  transform: scale(0.96);
}
.axe-toggle[aria-pressed="true"] {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-default);
  box-shadow: var(--shadow-xs);
}
.axe-toggle:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-toggle--sm {
  height: 24px;
  min-width: 24px;
  padding: 0 var(--space-2);
}

/* ------- Skip link (AppShell 첫 child) -------
 * 평소 화면 밖 — 키보드 포커스 시에만 표시. */
.axe-skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: calc(var(--z-toast) + 1);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--cta);
  color: var(--cta-fg);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-lg);
  transform: translateY(calc(-100% - var(--space-5)));
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-skip-link:focus-visible {
  transform: translateY(0);
}

/* ------- Input ------- */
.axe-input {
  display: inline-flex;
  align-items: center;
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-default);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-input::placeholder {
  color: var(--text-muted);
}
.axe-input:hover {
  border-color: var(--border-strong);
}
.axe-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}

.axe-input--lg {
  height: 44px;
  font-size: var(--text-base);
}
.axe-input--textarea {
  height: auto;
  min-height: 80px;
  padding: var(--space-3);
  line-height: var(--leading-body);
  resize: vertical;
}

/* ------- Card ------- */
.axe-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
  transition:
    border-color var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}
.axe-card--interactive {
  cursor: pointer;
}
/* hover = lift (이전의 full-accent 보더 스냅 대체 — transform/shadow 만
 * 변경이라 compositor-only, 레이아웃 무영향) */
.axe-card--interactive:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.axe-card__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-heading);
  color: var(--text-primary);
  margin-bottom: var(--space-2);
}
.axe-card__body {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
}

/* ------- Callout ------- */
.axe-callout {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid;
  font-size: var(--text-sm);
  line-height: var(--leading-body);
}
.axe-callout__icon {
  flex-shrink: 0;
  font-size: var(--text-base);
  line-height: var(--leading-body);
}
.axe-callout__content {
  flex: 1;
  min-width: 0;
}
.axe-callout__title {
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-1);
}

.axe-callout--info {
  background: var(--info-soft);
  border-color: var(--info);
  color: var(--text-primary);
}
.axe-callout--info .axe-callout__icon {
  color: var(--info);
}

.axe-callout--success {
  background: var(--success-soft);
  border-color: var(--success);
  color: var(--text-primary);
}
.axe-callout--success .axe-callout__icon {
  color: var(--success);
}

.axe-callout--warning {
  background: var(--warning-soft);
  border-color: var(--warning);
  color: var(--text-primary);
}
.axe-callout--warning .axe-callout__icon {
  color: var(--warning);
}

.axe-callout--danger {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--text-primary);
}
.axe-callout--danger .axe-callout__icon {
  color: var(--danger);
}

.axe-callout--note {
  background: var(--bg-subtle);
  border-color: var(--border-subtle);
  color: var(--text-secondary);
}
.axe-callout--note .axe-callout__icon {
  color: var(--text-tertiary);
}

/* ------- Badge ------- */
.axe-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  line-height: 1.4;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}
.axe-badge--accent {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: transparent;
}
.axe-badge--success {
  background: var(--success-soft);
  color: var(--success);
  border-color: transparent;
}
.axe-badge--warning {
  background: var(--warning-soft);
  color: var(--warning);
  border-color: transparent;
}
.axe-badge--danger {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: transparent;
}
.axe-badge--info {
  background: var(--info-soft);
  color: var(--info);
  border-color: transparent;
}

/* ------- CodeBlock ------- */
.axe-codeblock {
  position: relative;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.axe-codeblock__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background: color-mix(in oklch, var(--bg-subtle) 80%, var(--bg-base));
  border-bottom: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.axe-codeblock__lang {
  text-transform: lowercase;
  letter-spacing: 0.04em;
}
.axe-codeblock__copy {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-codeblock__copy:hover {
  color: var(--text-primary);
  background: var(--bg-base);
}
.axe-codeblock__pre {
  margin: 0;
  padding: var(--space-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  color: var(--text-primary);
  /* 한글·ASCII 박스 정렬 핵심:
   * 1) Sarasa Term K / D2Coding 이 한글을 정확히 2× 너비로 렌더
   * 2) keep-all 해제 — 코드는 그대로 보여줌 */
  word-break: normal;
  white-space: pre;
  tab-size: 4;
  font-variant-ligatures: contextual;
  font-feature-settings: "calt" 1;
}
.axe-codeblock__pre code {
  font-family: inherit;
  font-size: inherit;
}

/* 인라인 code */
.axe-code-inline,
:not(pre) > code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 0.125em 0.4em;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  word-break: break-all;
}

/* ------- Table ------- */
.axe-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}
.axe-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  font-variant-numeric: tabular-nums;
}
.axe-table thead th {
  text-align: left;
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.axe-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-primary);
  vertical-align: top;
}
.axe-table tbody tr:last-child td {
  border-bottom: 0;
}
.axe-table tbody tr:hover td {
  background: var(--bg-subtle);
}

/* ------- Prose (마크다운 본문 래퍼) -------
 * 단일 클래스로 임의 마크다운 트리에 prose 스타일 부여.
 * docs.axelabs.ai 처럼 정보 밀도 높은 페이지에 .axe-prose 한 줄로. */
.axe-prose {
  max-width: var(--prose-max);
  color: var(--text-primary);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}

.axe-prose > * + * {
  margin-top: var(--space-4);
}
.axe-prose > h1 + *,
.axe-prose > h2 + *,
.axe-prose > h3 + * {
  margin-top: var(--space-3);
}
.axe-prose > * + h2 {
  margin-top: var(--space-7);
}
.axe-prose > * + h3 {
  margin-top: var(--space-6);
}

.axe-prose h1,
.axe-prose h2,
.axe-prose h3,
.axe-prose h4,
.axe-prose h5,
.axe-prose h6 {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  color: var(--text-primary);
}
.axe-prose h1 {
  font-size: var(--text-4xl);
  line-height: var(--leading-tight);
}
.axe-prose h2 {
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-subtle);
}
.axe-prose h3 {
  font-size: var(--text-xl);
  line-height: var(--leading-heading);
}
.axe-prose h4 {
  font-size: var(--text-lg);
  line-height: var(--leading-heading);
}
.axe-prose h5,
.axe-prose h6 {
  font-size: var(--text-base);
  line-height: var(--leading-heading);
}

.axe-prose p {
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: 0;
  color: var(--text-primary);
}

.axe-prose a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-prose a:hover {
  color: var(--accent-hover);
}

.axe-prose ul,
.axe-prose ol {
  padding-left: var(--space-5);
  line-height: var(--leading-body);
}
.axe-prose ul {
  list-style: disc;
}
.axe-prose ol {
  list-style: decimal;
}
.axe-prose li::marker {
  color: var(--text-tertiary);
}
.axe-prose li + li {
  margin-top: var(--space-1);
}
.axe-prose li p {
  margin-top: 0;
}
.axe-prose li > ul,
.axe-prose li > ol {
  margin-top: var(--space-1);
}

.axe-prose blockquote {
  border-left: 3px solid var(--border-strong);
  padding: var(--space-2) var(--space-4);
  color: var(--text-secondary);
  font-style: italic;
}

.axe-prose hr {
  border: 0;
  height: 1px;
  background: var(--border-subtle);
  margin: var(--space-6) 0;
}

.axe-prose strong {
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.axe-prose img {
  border-radius: var(--radius-md);
  border: 1px solid var(--border-subtle);
}

/* prose 안의 표·코드블록은 위에서 정의한 클래스 스타일을 그대로 받도록
 * 동일 셀렉터 사용 */
.axe-prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.axe-prose table thead th {
  text-align: left;
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.axe-prose table tbody td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: top;
}
.axe-prose table tbody tr:last-child td {
  border-bottom: 0;
}

.axe-prose pre {
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  word-break: normal;
  white-space: pre;
  tab-size: 4;
}
.axe-prose pre code {
  background: transparent;
  border: 0;
  padding: 0;
  font-size: inherit;
}

/* ------- Chat — AI-first ------- */
.axe-chat-input {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-chat-input:focus-within {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-chat-input__textarea {
  width: 100%;
  border: 0;
  background: transparent;
  resize: none;
  outline: none;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  min-height: 1.5em;
  max-height: 12em;
}
.axe-chat-input__textarea::placeholder {
  color: var(--text-muted);
}
.axe-chat-input__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.axe-chat-input__hint {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
}

/* MessageBubble */
.axe-message {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) 0;
}
.axe-message__avatar {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  /* gray-9 = Radix scale 의 "solid bg" tier. avatar 같은 UI 마크용. */
  background: var(--gray-9);
  color: var(--bg-base);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}
.axe-message--user .axe-message__avatar {
  background: var(--accent);
  color: var(--accent-fg);
}
.axe-message__body {
  flex: 1;
  min-width: 0;
  color: var(--text-primary);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}
.axe-message__role {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  margin-bottom: var(--space-1);
}
.axe-message__content > * + * {
  margin-top: var(--space-3);
}

/* StreamingMarkdown — pulse cursor */
.axe-stream-cursor {
  display: inline-block;
  width: 0.5em;
  height: 1em;
  background: var(--accent);
  margin-left: 2px;
  vertical-align: text-bottom;
  animation: axe-blink 1s steps(2, end) infinite;
}
@keyframes axe-blink {
  0%, 50% {
    opacity: 1;
  }
  50.01%, 100% {
    opacity: 0;
  }
}

/* ToolCallCard */
.axe-toolcall {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  overflow: hidden;
}
.axe-toolcall__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  user-select: none;
  background: color-mix(in oklch, var(--bg-subtle) 80%, var(--bg-base));
  border-bottom: 1px solid transparent;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-toolcall__header:hover {
  background: color-mix(in oklch, var(--bg-subtle) 60%, var(--bg-base));
}
.axe-toolcall[data-open="true"] .axe-toolcall__header {
  border-bottom-color: var(--border-subtle);
}
.axe-toolcall__name {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.axe-toolcall__status {
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}
.axe-toolcall__chevron {
  color: var(--text-tertiary);
  transition: transform var(--duration-fast) var(--ease-out);
}
.axe-toolcall[data-open="true"] .axe-toolcall__chevron {
  transform: rotate(90deg);
}
.axe-toolcall__body {
  padding: var(--space-3);
  color: var(--text-primary);
  white-space: pre-wrap;
  word-break: normal;
  overflow-x: auto;
}

/* CommandPalette (⌘K) */
.axe-cmdk-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--bg-overlay);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}
.axe-cmdk {
  width: min(560px, 92vw);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xl); /* 큰 floating surface = 16px (radius 위계) */
  box-shadow: var(--shadow-xl);
  overflow: hidden;
}
.axe-cmdk__input {
  width: 100%;
  padding: var(--space-4);
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  border-bottom: 1px solid var(--border-subtle);
}
.axe-cmdk__input::placeholder {
  color: var(--text-muted);
}
.axe-cmdk__list {
  max-height: 400px;
  overflow-y: auto;
  padding: var(--space-2);
}
.axe-cmdk__group {
  margin-bottom: var(--space-2);
}
.axe-cmdk__group-label {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--text-tertiary);
  padding: var(--space-2) var(--space-3);
}
.axe-cmdk__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-cmdk__item[aria-selected="true"],
.axe-cmdk__item:hover {
  background: var(--bg-subtle);
}
.axe-cmdk__item-meta {
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.axe-cmdk__empty {
  padding: var(--space-6);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* kbd 키 표기 */
.axe-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5em;
  padding: 0 0.4em;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-bottom-width: 2px;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.6;
}

/* ============================================================
 * Dialog (Modal) — Radix Dialog 위 styling
 *
 *  size variant: sm 440 / md 560 / lg 720 / xl 960 / full 100vw
 *  data-state="open|closed" 으로 Radix 가 트랜지션 트리거.
 *  prefers-reduced-motion 존중.
 * ============================================================ */
.axe-dialog__overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay);
  backdrop-filter: blur(2px);
  z-index: 50;
  animation: axe-dialog-overlay-in 160ms ease-out;
}
.axe-dialog__overlay[data-state="closed"] {
  animation: axe-dialog-overlay-out 120ms ease-in forwards;
}

.axe-dialog__content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100vw - 2 * var(--space-4));
  max-height: calc(100vh - 2 * var(--space-4));
  max-height: calc(100dvh - 2 * var(--space-4));
  overflow: auto;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl); /* 큰 floating surface = 16px (radius 위계) */
  box-shadow: var(--shadow-xl);
  padding: var(--space-6);
  z-index: 51;
  animation: axe-dialog-content-in 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
.axe-dialog__content[data-state="closed"] {
  animation: axe-dialog-content-out 140ms ease-in forwards;
}
.axe-dialog__content:focus { outline: none; }

.axe-dialog__content--sm   { max-width: 440px; }
.axe-dialog__content--md   { max-width: 560px; }
.axe-dialog__content--lg   { max-width: 720px; }
.axe-dialog__content--xl   { max-width: 960px; }
.axe-dialog__content--full {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-height: 100dvh;
  top: 0;
  left: 0;
  transform: none;
  border-radius: 0;
}

.axe-dialog__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
  padding-right: var(--space-8); /* close X 자리 */
}

.axe-dialog__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.axe-dialog__description {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
}

.axe-dialog__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

@keyframes axe-dialog-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes axe-dialog-overlay-out {
  to { opacity: 0; }
}
@keyframes axe-dialog-content-in {
  from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes axe-dialog-content-out {
  to { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-dialog__overlay,
  .axe-dialog__content,
  .axe-dialog__overlay[data-state="closed"],
  .axe-dialog__content[data-state="closed"] {
    animation: none;
  }
}
/* ============================================================
 * Form group — Select / Checkbox / Radio / Switch / Label / FormField
 *
 * Convention:
 *   - 모든 sizing 은 토큰 (var(--space-*), var(--text-*)).
 *   - focus ring = var(--ring) 토큰 (3px var(--accent-soft)) + border var(--accent)
 *     (Input 과 동일).  ::focus-visible 만 — 마우스 클릭에 ring 안 뜸.
 *   - error 상태 = border var(--danger) + ring var(--ring-danger).
 *   - 다크/라이트 자동 — CSS var 만 사용.
 *   - prefers-reduced-motion 존중.
 * ============================================================ */

/* ------- Label (axe-label) — Radix Label wrap ------- */
.axe-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium, 500);
  line-height: 1.4;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
}

/* ============================================================
 * Select (axe-select__*) — Radix Select
 * ============================================================ */
.axe-select__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-default);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-select__trigger:hover:not([data-disabled]) {
  border-color: var(--border-strong);
}
.axe-select__trigger:focus-visible,
.axe-select__trigger[data-state="open"] {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-select__trigger[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-select__trigger[data-placeholder] {
  color: var(--text-muted);
}
.axe-select__trigger--lg {
  height: 44px;
  font-size: var(--text-base);
}

/* error wiring — 부모 FormField--error 안 trigger 도 적용 */
.axe-form-field--error .axe-select__trigger {
  border-color: var(--danger);
}
.axe-form-field--error .axe-select__trigger:focus-visible,
.axe-form-field--error .axe-select__trigger[data-state="open"] {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

.axe-select__content {
  min-width: var(--radix-select-trigger-width);
  max-height: var(--radix-select-content-available-height);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  z-index: 60;
  animation: axe-select-in 140ms var(--ease-out, ease-out);
}
.axe-select__content[data-state="closed"] {
  animation: axe-select-out 100ms ease-in forwards;
}
.axe-select__viewport {
  padding: var(--space-1);
}
.axe-select__label {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--text-tertiary);
}
.axe-select__item {
  position: relative;
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-7);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: 1.4;
  cursor: pointer;
  user-select: none;
  outline: none;
}
.axe-select__item[data-highlighted] {
  background: var(--bg-subtle);
}
.axe-select__item[data-state="checked"] {
  color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-select__item[data-disabled] {
  color: var(--text-muted);
  pointer-events: none;
}
.axe-select__indicator {
  position: absolute;
  left: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}
.axe-select__separator {
  height: 1px;
  margin: var(--space-1) 0;
  background: var(--border-subtle);
}

@keyframes axe-select-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes axe-select-out {
  to { opacity: 0; transform: translateY(-4px); }
}

/* ============================================================
 * Checkbox (axe-checkbox) — Radix Checkbox  +  indeterminate
 * ============================================================ */
.axe-checkbox {
  --size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--size);
  height: var(--size);
  flex: 0 0 var(--size);
  padding: 0;
  margin: 0;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border-strong);
  background: var(--bg-elevated);
  color: var(--accent-fg);
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-checkbox:hover:not([data-disabled]) {
  border-color: var(--accent);
}
.axe-checkbox:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-color: var(--accent);
}
.axe-checkbox[data-state="checked"],
.axe-checkbox[data-state="indeterminate"] {
  background: var(--accent);
  border-color: var(--accent);
}
.axe-checkbox[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* indicator + 두 icon (check / dash) — data-state 로 표시 분기 */
.axe-checkbox__indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.axe-checkbox__icon {
  display: none;
  color: var(--accent-fg);
}
.axe-checkbox[data-state="checked"] .axe-checkbox__icon--check {
  display: block;
}
.axe-checkbox[data-state="indeterminate"] .axe-checkbox__icon--dash {
  display: block;
}

/* error wiring */
.axe-form-field--error .axe-checkbox {
  border-color: var(--danger);
}
.axe-form-field--error .axe-checkbox:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-checkbox[data-state="checked"],
.axe-form-field--error .axe-checkbox[data-state="indeterminate"] {
  background: var(--danger);
  border-color: var(--danger);
}

/* ============================================================
 * Radio (axe-radio__*) — Radix RadioGroup
 * ============================================================ */
.axe-radio__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-radio__item {
  --size: 18px;
  width: var(--size);
  height: var(--size);
  flex: 0 0 var(--size);
  padding: 0;
  margin: 0;
  border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  background: var(--bg-elevated);
  cursor: pointer;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-radio__item:hover:not([data-disabled]) {
  border-color: var(--accent);
}
.axe-radio__item:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-color: var(--accent);
}
.axe-radio__item[data-state="checked"] {
  border-color: var(--accent);
}
.axe-radio__item[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-radio__indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  position: relative;
}
.axe-radio__indicator::after {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* error wiring */
.axe-form-field--error .axe-radio__item {
  border-color: var(--danger);
}
.axe-form-field--error .axe-radio__item:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-radio__item[data-state="checked"] {
  border-color: var(--danger);
}
.axe-form-field--error .axe-radio__indicator::after {
  background: var(--danger);
}

/* ============================================================
 * Switch (axe-switch) — Radix Switch
 * ============================================================ */
.axe-switch {
  --track-w: 36px;
  --track-h: 20px;
  --thumb: 16px;

  position: relative;
  width: var(--track-w);
  height: var(--track-h);
  flex: 0 0 var(--track-w);
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 999px;
  background: var(--border-default);
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-switch:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.axe-switch[data-state="checked"] {
  background: var(--accent);
}
.axe-switch[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-switch__thumb {
  display: block;
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transform: translateX(2px);
  transition: transform var(--duration-fast) var(--ease-out);
  will-change: transform;
}
.axe-switch[data-state="checked"] .axe-switch__thumb {
  transform: translateX(calc(var(--track-w) - var(--thumb) - 2px));
}

/* error wiring */
.axe-form-field--error .axe-switch:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-switch[data-state="checked"] {
  background: var(--danger);
}

/* ============================================================
 * FormField (axe-form-field) — wrapper layout
 * ============================================================ */
.axe-form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-form-field__label {
  /* axe-label 상속 — 추가 spacing 만 */
}
.axe-form-field__required {
  color: var(--danger);
  font-weight: var(--weight-medium, 500);
  margin-left: 2px;
}
.axe-form-field__control {
  /* control wrapper — Input/Select/Checkbox 등이 들어옴 */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-form-field__hint {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--text-tertiary);
}
.axe-form-field__error {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--danger);
}
/* error 상태일 때 wrap 안 Input 도 자동 적용 — aria-invalid 가 더 정석이지만
   FormField 의 명시적 error prop 만으로도 시각 동기화 */
.axe-form-field--error .axe-input,
.axe-input[aria-invalid="true"] {
  border-color: var(--danger);
}
.axe-form-field--error .axe-input:focus,
.axe-input[aria-invalid="true"]:focus {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

/* ============================================================
 * Combobox (axe-combobox__*) — 인라인 자동완성 (Popover anchor + listbox)
 *   input = axe-select__trigger 와 동일 sizing/border/ring 토큰,
 *   list/item = axe-cmdk 팝업 토큰 재사용.
 * ============================================================ */
.axe-combobox {
  display: block;
  width: 100%;
}
.axe-combobox__input {
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-default);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-combobox__input::placeholder {
  color: var(--text-muted);
}
.axe-combobox__input:hover:not(:disabled) {
  border-color: var(--border-strong);
}
.axe-combobox__input:focus-visible,
.axe-combobox__input[aria-expanded="true"] {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-combobox__input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-form-field--error .axe-combobox__input {
  border-color: var(--danger);
}
.axe-form-field--error .axe-combobox__input:focus-visible,
.axe-form-field--error .axe-combobox__input[aria-expanded="true"] {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

.axe-combobox__content {
  min-width: var(--radix-popover-trigger-width);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  z-index: 60;
}
.axe-combobox__list {
  max-height: 320px;
  overflow-y: auto;
  padding: var(--space-2);
}
.axe-combobox__item {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-combobox__item[aria-selected="true"],
.axe-combobox__item:hover {
  background: var(--bg-subtle);
}
.axe-combobox__empty {
  padding: var(--space-6);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* ============================================================
 * Slider (axe-slider__*) — 네이티브 range input + 토큰 채움/thumb.
 *   채움은 --axe-slider-pct(0~100, 컴포넌트가 인라인 주입) → accent 그라데이션.
 *   thumb/track 토큰 = axe-switch/axe-btn 와 동일 accent·ring·border 어휘.
 *   WebKit(::-webkit-slider-*) + Firefox(::-moz-range-*) 양쪽 모두 스타일.
 * ============================================================ */
.axe-slider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}
.axe-slider__input {
  --axe-slider-pct: 0;
  flex: 1 1 auto;
  min-width: 0;
  height: 20px;
  margin: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.axe-slider__input:focus-visible {
  outline: none;
}
/* track — 채운 구간(accent) + 빈 구간(border) 을 한 그라데이션으로 */
.axe-slider__input::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: var(--radius-full);
  background: linear-gradient(
    to right,
    var(--accent) 0%,
    var(--accent) calc(var(--axe-slider-pct) * 1%),
    var(--bg-subtle) calc(var(--axe-slider-pct) * 1%),
    var(--bg-subtle) 100%
  );
}
.axe-slider__input::-moz-range-track {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
}
.axe-slider__input::-moz-range-progress {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--accent);
}
/* thumb */
.axe-slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px; /* (16 - 6) / 2 로 track 중앙 정렬 */
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.axe-slider__input::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.axe-slider__input:focus-visible::-webkit-slider-thumb {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-slider__input:focus-visible::-moz-range-thumb {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-slider--disabled {
  opacity: 0.5;
}
.axe-slider--disabled .axe-slider__input {
  cursor: not-allowed;
}
.axe-slider__value {
  flex: 0 0 auto;
  min-width: 3ch;
  text-align: right;
  font-family: var(--font-mono, var(--font-sans));
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

/* ============================================================
 * Calendar (axe-calendar__*) — 단일 날짜 선택 그리드 (dep 0, 순수 CSS).
 *   토큰 어휘 = axe-slider/axe-switch 와 동일 accent·accent-fg·ring·border.
 *   markup 은 role=grid/row/gridcell + 셀별 aria-selected → 서버 렌더(maud/jinja)도
 *   같은 클래스에 aria-selected 만 계산해 넣으면 동일 모양.
 * ============================================================ */
.axe-calendar {
  display: inline-block;
  padding: var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: var(--text-sm);
}
.axe-calendar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.axe-calendar__title {
  flex: 1 1 auto;
  text-align: center;
  font-weight: 600;
  color: var(--text-primary);
}
.axe-calendar__nav {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-base);
  color: var(--text-secondary);
  font-size: var(--text-base);
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
.axe-calendar__nav:hover:not(:disabled) {
  background: var(--bg-subtle);
  border-color: var(--border-strong);
}
.axe-calendar__nav:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-calendar__nav:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-calendar__grid {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.axe-calendar__weekdays,
.axe-calendar__week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.axe-calendar__weekday {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-muted);
}
.axe-calendar__day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-calendar__day:hover:not(:disabled):not(.axe-calendar__day--selected) {
  background: var(--bg-subtle);
}
.axe-calendar__day:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-calendar__day--today:not(.axe-calendar__day--selected) {
  border-color: var(--border-strong);
  font-weight: 600;
}
.axe-calendar__day--selected {
  background: var(--accent);
  color: var(--accent-fg);
  font-weight: 600;
}
.axe-calendar__day--selected:hover:not(:disabled) {
  background: var(--accent-hover);
}
.axe-calendar__day:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* 이전/다음 달 빈칸 — 클릭 불가 placeholder */
.axe-calendar__day--outside {
  cursor: default;
  pointer-events: none;
}
.axe-calendar--disabled {
  opacity: 0.5;
  pointer-events: none;
}

/* ============================================================
 * Reduced motion
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .axe-select__content,
  .axe-select__content[data-state="closed"],
  .axe-switch__thumb,
  .axe-slider__input::-webkit-slider-thumb,
  .axe-slider__input::-moz-range-thumb,
  .axe-calendar__nav,
  .axe-calendar__day {
    animation: none;
    transition: none;
  }
}
/* ============================================================
 * Data display (Phase 14 Wave 5)
 *   DataTable · Pagination · Chart (recharts wrap)
 *
 *   Phase 7 dashboard.css 와 별도 — Pipeline 은 운영자 status row,
 *   DataTable 은 일반 데이터 + 정렬/페이징.  스타일 분리해서 tree-shake
 *   가능, showcase page 에서 본 파일만 import.
 *
 *   원칙
 *     · token-only — Tailwind 0, hard-coded color 0.
 *     · CSS-only animation (hover transition, skeleton shimmer).
 *     · prefers-reduced-motion: reduce 시 모든 motion 정지/완화.
 *     · light/dark 자동 — CSS var 만 사용.
 * ============================================================ */

/* ============================================================
 * DataTable — sortable, paginatable generic data table.
 *   wrap > scroll > table.  PipelineTable 과 마크업 유사하지만
 *   sortable header 가 <button> 으로 들어가는 차이.
 * ============================================================ */
.axe-data-table {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden; /* radius clip */
}

.axe-data-table__scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.axe-data-table--sticky .axe-data-table__scroll {
  max-height: 480px;
  overflow-y: auto;
}

.axe-data-table__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  min-width: 600px;
}

.axe-data-table__thead {
  background: var(--bg-subtle);
}

.axe-data-table--sticky .axe-data-table__thead {
  position: sticky;
  top: 0;
  z-index: 1;
}

.axe-data-table__th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.axe-data-table__th--right  { text-align: right; }
.axe-data-table__th--center { text-align: center; }

.axe-data-table__th--active {
  color: var(--text-primary);
}

.axe-data-table__th--sortable {
  padding: 0; /* button 이 padding 보유 */
}

.axe-data-table__sort-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  background: transparent;
  border: 0;
  padding: var(--space-3) var(--space-4);
  font-size: inherit;
  font-weight: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  cursor: pointer;
  font-family: inherit;
  transition: color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-data-table__th--right .axe-data-table__sort-btn  { justify-content: flex-end; }
.axe-data-table__th--center .axe-data-table__sort-btn { justify-content: center; }

.axe-data-table__sort-btn:hover {
  color: var(--text-primary);
}

.axe-data-table__sort-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}

.axe-data-table__sort-arrow {
  font-size: 0.8em;
  color: var(--text-muted);
  line-height: 1;
}

.axe-data-table__th--active .axe-data-table__sort-arrow {
  color: var(--accent);
}

.axe-data-table__tr {
  border-bottom: 1px solid var(--border-subtle);
  transition: background-color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-data-table__tr:last-child {
  border-bottom: 0;
}

.axe-data-table__tr:hover {
  background: color-mix(in oklch, var(--accent) 4%, transparent);
}

.axe-data-table__tr--clickable {
  cursor: pointer;
}

.axe-data-table__tr--clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.axe-data-table__td {
  padding: var(--space-3) var(--space-4);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

.axe-data-table__td--right  { text-align: right; }
.axe-data-table__td--center { text-align: center; }

/* empty state */
.axe-data-table__tr--empty:hover { background: transparent; }
.axe-data-table__empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* skeleton rows */
.axe-data-table__tr--skeleton:hover { background: transparent; }

/* shimmer = indicators.css 의 axe-shimmer keyframes 공유 (transform sweep). */
.axe-data-table__skel {
  display: inline-block;
  width: 70%;
  height: 12px;
  position: relative;
  overflow: hidden; /* radius clip */
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
}

.axe-data-table__skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .axe-data-table__tr,
  .axe-data-table__sort-btn {
    transition: none;
  }
  .axe-data-table__skel::after {
    content: none;
  }
}

@media (max-width: 480px) {
  .axe-data-table__th,
  .axe-data-table__td,
  .axe-data-table__sort-btn {
    padding: var(--space-2) var(--space-3);
  }
  .axe-data-table__table {
    font-size: var(--text-xs);
  }
}

/* ============================================================
 * Pagination — page nav.
 *   info | list (이전 + page btns + 다음).
 *   compact 시 list 안의 페이지 버튼이 "current / total" 텍스트로 치환.
 * ============================================================ */
.axe-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-variant-numeric: tabular-nums;
}

.axe-pagination__info {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.axe-pagination__info-range {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

.axe-pagination__info-sep {
  color: var(--text-muted);
}

.axe-pagination__info-total {
  color: var(--text-secondary);
}

.axe-pagination__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.axe-pagination__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition:
    background-color var(--duration-fast, 120ms) var(--ease-out, ease-out),
    color var(--duration-fast, 120ms) var(--ease-out, ease-out),
    border-color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-pagination__btn:hover:not(:disabled):not(.axe-pagination__btn--active) {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-pagination__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-pagination__btn:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.axe-pagination__btn--active {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
  cursor: default;
}

.axe-pagination__btn--nav {
  font-size: var(--text-lg);
  line-height: 1;
}

.axe-pagination__ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 32px;
  color: var(--text-muted);
  font-size: var(--text-sm);
  user-select: none;
}

/* size sm */
.axe-pagination--size-sm .axe-pagination__btn {
  min-width: 28px;
  height: 28px;
  font-size: var(--text-xs);
}
.axe-pagination--size-sm .axe-pagination__btn--nav {
  font-size: var(--text-base);
}
.axe-pagination--size-sm .axe-pagination__ellipsis {
  height: 28px;
  font-size: var(--text-xs);
}

/* compact 모바일 */
.axe-pagination--compact {
  justify-content: center;
}
.axe-pagination__compact-label {
  display: inline-flex;
  align-items: baseline;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.axe-pagination__compact-current {
  font-weight: var(--weight-semibold);
}
.axe-pagination__compact-sep {
  color: var(--text-muted);
  padding: 0 var(--space-1);
}
.axe-pagination__compact-total {
  color: var(--text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .axe-pagination__btn {
    transition: none;
  }
}

/* ============================================================
 * Chart — recharts wrap container.
 *   recharts SVG 가 컨테이너 100% 차지 → axe-chart 가 height 지정자.
 *   tooltip 은 portal 아닌 inline div — axe-chart__tooltip 으로 자체 styling.
 *
 *   색 매핑 (Chart.tsx 와 동기화):
 *     · series color: --accent → --success → --warning → --danger → --info 순환
 *     · axis tick:    --text-secondary
 *     · grid line:    --border-subtle  (strokeDasharray 3 3)
 *     · tooltip bg:   --bg-elevated  border: --border-subtle
 *     · dashed line:  strokeDasharray 5 4  — series.dashed=true 시
 *     · gradient area: 0%→35% / 100%→2% (의미: 최근일수록 진함)
 * ============================================================ */
.axe-chart {
  width: 100%;
  color: var(--text-primary);
}

/* tooltip — recharts content 안에서 사용 */
.axe-chart__tooltip {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, var(--shadow-sm, 0 2px 8px rgb(0 0 0 / 0.1)));
  padding: var(--space-2) var(--space-3);
  min-width: 120px;
  font-size: var(--text-xs);
  color: var(--text-primary);
  pointer-events: none;
}

.axe-chart__tooltip-label {
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  margin-bottom: var(--space-1);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}

.axe-chart__tooltip-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.axe-chart__tooltip-row {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  align-items: center;
  gap: var(--space-2);
}

.axe-chart__tooltip-swatch {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-sm);
  display: inline-block;
}

.axe-chart__tooltip-name {
  color: var(--text-secondary);
}

.axe-chart__tooltip-value {
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* recharts text default 가 SVG fill — focus ring 은 SVG 가 자체 처리.
   reduced-motion 은 컴포넌트 prop 으로 animation false (Chart.tsx).  */

/* axe-shimmer keyframes — indicators.css 와 동일 정의 (cortex 등 선택적 번들이
 * indicators 없이 본 파일만 포함해도 동작. 동명 중복 정의는 무해 — 후승). */
@keyframes axe-shimmer {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}
/* ============================================================
 * Phase 14 Wave 5 — Feedback group  (EmptyState · ErrorBoundary)
 *
 *  - 본 파일은 components.css 가 import 하지 않음 (owner 가 통합).
 *    showcase 와 통합 전 까지는 page 가 직접 side-effect import.
 *  - 표면은 transparent 또는 elevated.  semantic 색은 icon/border 만.
 *  - reduced-motion 존중, dark/light CSS var 자동.
 * ============================================================ */

/* ────────────────────────────────────────────────────────────
 * EmptyState
 *   - center-aligned column.  background: transparent → Card 안/밖 모두 자연.
 *   - icon → title → description → actions 순서.
 *   - size 가 padding + icon box + 폰트 크기 비례.
 *   - tone 이 icon 색 + (subtle) border accent 결정.
 * ──────────────────────────────────────────────────────────── */
.axe-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  background: transparent;
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
  color: var(--text-primary);
}

.axe-empty-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-size: 24px;
  line-height: 1;
}

.axe-empty-state__title {
  font-family: var(--font-display, var(--font-sans));
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
}

.axe-empty-state__description {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.5;
  max-width: 48ch;
}

.axe-empty-state__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* ── size variants ── */
.axe-empty-state--size-sm {
  padding: var(--space-5) var(--space-4);
  gap: var(--space-2);
}
.axe-empty-state--size-sm .axe-empty-state__icon {
  width: 36px;
  height: 36px;
  font-size: 18px;
}
.axe-empty-state--size-sm .axe-empty-state__title {
  font-size: var(--text-base);
}
.axe-empty-state--size-sm .axe-empty-state__description {
  font-size: var(--text-xs);
}

.axe-empty-state--size-lg {
  padding: var(--space-8) var(--space-6);
  gap: var(--space-4);
}
.axe-empty-state--size-lg .axe-empty-state__icon {
  width: 64px;
  height: 64px;
  font-size: 32px;
}
.axe-empty-state--size-lg .axe-empty-state__title {
  font-size: var(--text-xl);
}

/* ── tone variants — icon tint + border accent (subtle) ── */
.axe-empty-state--tone-success {
  border-color: color-mix(in srgb, var(--success) 35%, var(--border-subtle));
}
.axe-empty-state--tone-success .axe-empty-state__icon {
  background: var(--success-soft);
  color: var(--success);
}

.axe-empty-state--tone-warning {
  border-color: color-mix(in srgb, var(--warning) 35%, var(--border-subtle));
}
.axe-empty-state--tone-warning .axe-empty-state__icon {
  background: var(--warning-soft);
  color: var(--warning);
}

.axe-empty-state--tone-danger {
  border-color: color-mix(in srgb, var(--danger) 35%, var(--border-subtle));
}
.axe-empty-state--tone-danger .axe-empty-state__icon {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ────────────────────────────────────────────────────────────
 * ErrorBoundary — default fallback 의 wrapper.
 *   - Callout(variant="danger") 가 본체.  여기서는 spacing + 액션 row 만.
 *   - custom fallback 을 쓰면 caller 책임.
 * ──────────────────────────────────────────────────────────── */
.axe-error-boundary {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.axe-error-boundary__detail {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.5;
}

.axe-error-boundary__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
/* ============================================================
 * Indicators (Phase 4) — Skeleton / Spinner / Avatar / Progress
 *
 *   본 파일은 components.css 에 통합되기 전 Phase 4 격리 CSS.
 *   소비자는 globals.css 또는 showcase page 에서 직접 import.
 *
 *   모든 애니메이션 prefers-reduced-motion: reduce 존중.
 *   CSS-only — JS 의존 0.  성능 budget < 1KB gz / 컴포넌트.
 * ============================================================ */

/* ---------- sr-only (a11y 유틸; Spinner 가 의존) ---------- */
.axe-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;
}

/* ============================================================
 * Skeleton — content placeholder.
 *   shimmer = ::after overlay 의 transform sweep — compositor-only
 *   (background-position 애니메이션은 paint-bound → transform 으로 통일).
 *   variant: text(line) / circle / rect(default).
 * ============================================================ */
.axe-skeleton {
  display: block;
  position: relative;
  overflow: hidden; /* radius clip — sweep 가 모서리 밖으로 안 새게. */
  background: var(--bg-subtle);
  border-radius: var(--radius-md);
}

.axe-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

.axe-skeleton--text {
  height: 1em;
  border-radius: var(--radius-sm);
  /* text line 은 1em 기본; 사용자가 height 로 덮어쓰면 그게 우선. */
}

.axe-skeleton--circle {
  border-radius: 9999px;
  aspect-ratio: 1 / 1;
}

.axe-skeleton--rect {
  /* rect 기본; 사용자가 width/height 명시. */
}

/* 공유 shimmer keyframes — dashboard.css (MetricCard/PipelineTable skel) 와
 * data-display.css (DataTable skel) 도 본 keyframes 를 사용.
 * components.css import 순서상 indicators 가 가장 먼저 로드됨. */
@keyframes axe-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* ============================================================
 * Spinner — indeterminate.
 *   svg + circle stroke-dasharray rotation.
 *   prefers-reduced-motion 시 dot 만 깜박임.
 * ============================================================ */
.axe-spinner {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  vertical-align: middle;
  color: var(--accent);
  line-height: 1;
}

.axe-spinner__svg {
  display: block;
  animation: axe-spinner-rotate 0.9s linear infinite;
}

.axe-spinner__track {
  stroke: color-mix(in oklch, currentColor 18%, transparent);
}

.axe-spinner__head {
  stroke: currentColor;
  /* circumference = 2 * PI * 10 ≈ 62.83.  1/4 가시 (15.7), 3/4 갭. */
  stroke-dasharray: 15.7 62.83;
  transform-origin: center;
}

/* reduced-motion 대체: dot pulse */
.axe-spinner__dot {
  display: none;
  width: 0.5em;
  height: 0.5em;
  border-radius: 9999px;
  background: currentColor;
}

.axe-spinner__label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

@keyframes axe-spinner-rotate {
  to { transform: rotate(360deg); }
}

@keyframes axe-spinner-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .axe-spinner__svg { display: none; }
  .axe-spinner__dot {
    display: inline-block;
    animation: axe-spinner-pulse 1.4s ease-in-out infinite;
  }
}

/* ============================================================
 * Avatar — Radix Avatar 위 styling.
 *   size sm 24 / md 32 / lg 48.  fallback initials 자동 layout.
 * ============================================================ */
.axe-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 9999px;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-family: var(--font-display, inherit);
  font-weight: var(--weight-medium);
  user-select: none;
  vertical-align: middle;
  flex-shrink: 0;
}

.axe-avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.axe-avatar--md { width: 32px; height: 32px; font-size: 12px; }
.axe-avatar--lg { width: 48px; height: 48px; font-size: 18px; }

.axe-avatar__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

.axe-avatar__fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  background: var(--bg-subtle);
}

/* ============================================================
 * Progress — Radix Progress 위 styling.
 *   determinate: transform translateX 로 indicator 이동.
 *   indeterminate: sweep keyframes.
 *   variant: default(accent) / success / danger.
 * ============================================================ */
.axe-progress {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 6px;
  background: var(--bg-subtle);
  border-radius: 9999px;
  /* Radix 가 max/value 를 aria 로 설정 — 추가 처리 불필요. */
  /* iOS Safari 의 transform overflow bug 방어. */
  transform: translateZ(0);
}

.axe-progress__indicator {
  width: 100%;
  height: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: transform var(--duration-base, 200ms) var(--ease-out, ease-out);
}

.axe-progress--success .axe-progress__indicator { background: var(--success); }
.axe-progress--danger  .axe-progress__indicator { background: var(--danger); }

/* Indeterminate — indicator 를 1/3 폭의 sweep 으로 변환. */
.axe-progress--indeterminate .axe-progress__indicator {
  width: 33%;
  transform: translateX(-100%);
  animation: axe-progress-sweep 1.4s ease-in-out infinite;
  transition: none;
}

@keyframes axe-progress-sweep {
  0%   { transform: translateX(-100%); }
  50%  { transform: translateX(150%); }
  100% { transform: translateX(300%); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-skeleton::after {
    content: none;
  }
  .axe-progress__indicator {
    transition: none;
  }
  .axe-progress--indeterminate .axe-progress__indicator {
    animation: none;
    width: 100%;
    transform: translateX(0);
    opacity: 0.6;
  }
}
/* ============================================================
 * @axe/ui — Document / print templates (Phase 17, D-ui-3 Phase 2)
 *
 * AXE 발신 문서 (IC Memo · LP letter 등) 를 가로(landscape)·세로(portrait)
 * 모두 지원하는 CSS-class HTML 템플릿. "Tailwind 0" — 100% `.axe-doc*`
 * 클래스 + CSS var → React 없이 Python(jinja)/Rust(maud) 가 동일 markup 재사용.
 *
 * Owns: .axe-doc-stage, .axe-doc, .axe-doc__* (masthead/title/meta/section/
 *       kpi/callout/table/signoff/footer), 인쇄 유틸 (.axe-doc__pagebreak 등),
 *       표 variants (.axe-doc__table--financial/--compact/--keep/--compare,
 *       .axe-doc__row--*, 셀 유틸 .axe-doc__ctr/__neg/__pos/__fn/__cellbar),
 *       데이터 비주얼 (.axe-doc-viz*, .axe-doc-diagram* — Phase 18 Track B).
 *
 * 설계 원칙:
 *  1. 테마 독립 — 문서는 light/dark 와 무관하게 동일 (흰 종이·먹 잉크).
 *     `.axe-doc` 가 자체 `--doc-*` 팔레트를 깔아 전역 테마 토큰을 덮음.
 *     accent 만 브랜드 `--brand-claret` 추종 (rebrand 시 자동 반영).
 *  2. 스코프 @page — named page (`page:` property) 로만 size/margin 지정 →
 *     `.axe-doc` 없는 일반 페이지 인쇄에는 영향 0 (전역 bare @page 금지).
 *  3. pt 단위 본문 — 인쇄 충실도. 화면에서도 mm 종이 위 pt 글자로 동일 비율.
 *  4. 화면 미리보기 = 회색 backdrop 위 mm 폭 종이 + 그림자. @media print 에서
 *     backdrop/그림자 제거하고 @page margin 이 여백을 인계.
 *
 * 토큰: --font-sans, --font-display, --brand-claret, --space-*, --radius-*
 *       (src/lib/tokens). 색은 --doc-* 로 재정의 (테마 무관 고정).
 * 렌더: 브라우저 "인쇄→PDF" (named @page size 인식) + md-to-pdf 파이프라인
 *       (Puppeteer landscape 옵션을 orientation 에 맞춰 셋 — 렌더 측 책임).
 * ============================================================ */

/* ------------------------------------------------------------
 *  Named @page — 스코프됨 (page: property 로 선택, 전역 미적용)
 *  A4 = 210 × 297 mm. 여백: 세로 22/20, 가로 16/22 (mm, T/B · L/R).
 * ------------------------------------------------------------ */
@page axe-doc-portrait {
  size: A4 portrait;
  margin: 22mm 20mm;
}
@page axe-doc-landscape {
  size: A4 landscape;
  margin: 16mm 22mm;
}

/* ------------------------------------------------------------
 *  Stage — 화면 전용 회색 backdrop (showcase/preview 환경).
 *  종이를 가운데 띄우고 스크롤. 인쇄 시 사라짐.
 * ------------------------------------------------------------ */
.axe-doc-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-7) var(--space-5);
  background: var(--gray-3, #e8e2d4);
  min-height: 100%;
}

/* ------------------------------------------------------------
 *  .axe-doc — 종이 (root). 테마 독립 팔레트를 자체 정의.
 * ------------------------------------------------------------ */
.axe-doc {
  /* 문서 전용 색 — 테마 무관 고정 (accent 만 브랜드 추종) */
  --doc-paper: #ffffff;
  --doc-ink: #16130f; /* 본문 — 따뜻한 먹색 */
  --doc-ink-2: #423a2b; /* 보조 텍스트 */
  --doc-muted: #756a52; /* 라벨 · 캡션 */
  --doc-rule: #ddd6c5; /* 헤어라인 */
  --doc-rule-strong: #b1a78f; /* 강조 구분선 */
  --doc-band: #f6f3ec; /* 옅은 띠 배경 (meta/kpi) */
  --doc-accent: var(--brand-claret, #821f3b); /* AXE 와인 시그니처 */
  --doc-accent-ink: #6b1830;
  --doc-accent-soft: rgb(130 31 59 / 0.06);

  /* 인쇄/화면 공통 본문 타이포 — pt 기준 */
  font-family: var(--font-sans);
  font-size: 10.5pt;
  line-height: 1.55;
  color: var(--doc-ink);
  background: var(--doc-paper);
  text-align: left;
  word-break: keep-all;
  overflow-wrap: break-word;

  /* 화면 종이 geometry (세로 기본) — mm 폭 + 그림자 */
  box-sizing: border-box;
  width: 210mm;
  min-height: 297mm;
  padding: 22mm 20mm;
  margin-inline: auto;
  box-shadow: 0 6px 28px rgb(31 26 19 / 0.18);

  /* 기본 페이지 = 세로 (landscape modifier 가 override) */
  page: axe-doc-portrait;
}

/* 가로 modifier — 화면 geometry + named page 교체 */
.axe-doc--landscape {
  width: 297mm;
  min-height: 210mm;
  padding: 16mm 22mm;
  page: axe-doc-landscape;
}
/* 세로 modifier (명시) — 기본과 동일하나 markup 가독성용 */
.axe-doc--portrait {
  width: 210mm;
  min-height: 297mm;
  padding: 22mm 20mm;
  page: axe-doc-portrait;
}

/* ------------------------------------------------------------
 *  Masthead / letterhead — 상단 브랜드 밴드
 * ------------------------------------------------------------ */
.axe-doc__masthead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: 8pt;
  border-bottom: 1.5pt solid var(--doc-accent);
  margin-bottom: 16pt;
}
.axe-doc__wordmark {
  /* 브랜드 워드마크 = Clash Display (display 페이스). 클래스에 직접 박는다 —
   * 문서별 인라인 style(var(--font-clash)) 은 layer 뷰어의 opaque sandbox iframe
   * 에서 적용되지 않아(클래스 규칙만 먹음) Pretendard 로 폴백했었다. */
  font-family: var(--font-clash);
  font-size: 13pt;
  /* 두께·트래킹은 .axe-topnav__brand(앱 nav 워드마크) 와 동일 톤 — medium + 살짝
   * 타이트. 과거 700 + 0.14em(넓은 letterhead 트래킹)은 nav 워드마크와 안 맞았음. */
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
  /* 워드마크는 작성된 케이스 그대로 렌더 (예: "AXE·Corporation").
   * 과거 letterhead 전체 대문자화는 mixed-case 브랜드명을 강제 변형했음. */
  text-transform: none;
  /* 워드마크 = AXE 와인(버건디) 시그니처 — 마스트헤드 보더·confidential 과 동일 강조색. */
  color: var(--doc-accent);
  line-height: 1;
}
.axe-doc__wordmark-accent {
  color: var(--doc-accent);
}
.axe-doc__doctype {
  font-size: 8pt;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--doc-muted);
  text-align: right;
}

/* Confidential 태그 — masthead 우측 또는 단독 */
.axe-doc__confidential {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Title block
 * ------------------------------------------------------------ */
.axe-doc__title {
  font-family: var(--font-display);
  font-size: 22pt;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--doc-ink);
  margin: 0 0 4pt;
}
.axe-doc__subtitle {
  font-size: 12pt;
  font-weight: 400;
  line-height: 1.35;
  color: var(--doc-ink-2);
  margin: 0 0 14pt;
}

/* Meta grid — Date / Author / Recipient 등 라벨·값 쌍 */
.axe-doc__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5pt 18pt;
  padding: 9pt 12pt;
  background: var(--doc-band);
  border: 0.75pt solid var(--doc-rule);
  border-radius: var(--radius-sm);
  margin-bottom: 16pt;
}
.axe-doc__meta--3col {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.axe-doc__meta-item {
  display: flex;
  flex-direction: column;
  gap: 1pt;
}
.axe-doc__meta-label {
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--doc-muted);
}
.axe-doc__meta-value {
  font-size: 9.5pt;
  color: var(--doc-ink);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 *  Section
 * ------------------------------------------------------------ */
.axe-doc__section {
  margin-top: 16pt;
}
.axe-doc__section-title {
  font-family: var(--font-display);
  font-size: 12.5pt;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--doc-ink);
  padding-bottom: 3pt;
  margin: 0 0 8pt;
  border-bottom: 0.75pt solid var(--doc-rule-strong);
  break-after: avoid;
}
.axe-doc__section-title--accent {
  color: var(--doc-accent);
  border-bottom-color: var(--doc-accent);
}
/* 번호 매기는 섹션 (CSS counter) — .axe-doc__body 에 .axe-doc__body--numbered */
.axe-doc__body--numbered {
  counter-reset: axe-doc-sec;
}
.axe-doc__body--numbered .axe-doc__section-title::before {
  counter-increment: axe-doc-sec;
  content: counter(axe-doc-sec) ". ";
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Body prose — h/p/list/quote/link (jinja 본문이 그대로 흘리는 태그)
 * ------------------------------------------------------------ */
.axe-doc__body {
  font-size: 10.5pt;
  line-height: 1.55;
  color: var(--doc-ink);
}
.axe-doc__body > :first-child {
  margin-top: 0;
}
.axe-doc__body h2 {
  font-family: var(--font-display);
  font-size: 12.5pt;
  font-weight: 700;
  margin: 16pt 0 7pt;
  break-after: avoid;
}
.axe-doc__body h3 {
  font-size: 11pt;
  font-weight: 700;
  color: var(--doc-ink);
  margin: 12pt 0 5pt;
  break-after: avoid;
}
.axe-doc__body h4 {
  font-size: 10pt;
  font-weight: 700;
  color: var(--doc-ink-2);
  letter-spacing: 0.01em;
  margin: 10pt 0 4pt;
  break-after: avoid;
}
.axe-doc__body p {
  margin: 0 0 7pt;
}
.axe-doc__body ul,
.axe-doc__body ol {
  margin: 0 0 7pt;
  padding-left: 16pt;
}
.axe-doc__body li {
  margin-bottom: 2.5pt;
}
.axe-doc__body li::marker {
  color: var(--doc-muted);
}
/* 본문·콜아웃 링크 — AXE 와인색 + 분명한(은은) 밑줄로 "링크임"을 명확히.
 * 과거 0.06 알파 보더는 사실상 안 보여 링크 식별 불가였음(시퍼런 파랑은 지양). */
.axe-doc__body a,
.axe-doc__callout-body a {
  color: var(--doc-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  text-decoration-color: rgb(130 31 59 / 0.5);
  text-decoration-skip-ink: auto;
}
.axe-doc__body a:hover,
.axe-doc__callout-body a:hover {
  color: var(--doc-accent-ink);
  text-decoration-color: var(--doc-accent);
}
.axe-doc__body strong {
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__body blockquote {
  margin: 8pt 0;
  padding: 4pt 0 4pt 12pt;
  border-left: 2pt solid var(--doc-rule-strong);
  color: var(--doc-ink-2);
  font-style: italic;
}
.axe-doc__body code {
  font-family: var(--font-mono);
  font-size: 9pt;
  background: var(--doc-band);
  padding: 0.5pt 3pt;
  border-radius: var(--radius-xs);
}
.axe-doc__rule {
  border: none;
  border-top: 0.75pt solid var(--doc-rule);
  margin: 12pt 0;
}

/* ------------------------------------------------------------
 *  KPI tiles — Pre/Post money, IRR, ownership 등 수치 강조
 * ------------------------------------------------------------ */
.axe-doc__kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110pt, 1fr));
  gap: 8pt;
  margin: 12pt 0;
}
.axe-doc__kpi {
  padding: 8pt 10pt;
  background: var(--doc-band);
  border: 0.75pt solid var(--doc-rule);
  border-radius: var(--radius-sm);
  break-inside: avoid;
}
.axe-doc__kpi-label {
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 3pt;
}
.axe-doc__kpi-value {
  font-size: 15pt;
  font-weight: 700;
  line-height: 1.05;
  color: var(--doc-ink);
  font-variant-numeric: tabular-nums;
}
.axe-doc__kpi-sub {
  font-size: 8pt;
  color: var(--doc-muted);
  margin-top: 2pt;
}
.axe-doc__kpi--accent {
  border-color: var(--doc-accent);
}
.axe-doc__kpi--accent .axe-doc__kpi-value {
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Callout / Recommendation box — Go / Conditional / Pass
 * ------------------------------------------------------------ */
.axe-doc__callout {
  display: flex;
  flex-direction: column;
  gap: 3pt;
  padding: 9pt 12pt 9pt 14pt;
  background: var(--doc-accent-soft);
  border-left: 3pt solid var(--doc-accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin: 12pt 0;
  break-inside: avoid;
}
.axe-doc__callout-label {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--doc-accent);
}
.axe-doc__callout-title {
  font-size: 12pt;
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__callout-body {
  font-size: 9.5pt;
  color: var(--doc-ink-2);
}
/* 의미 variant — 인쇄 시 배경 보장 (print-color-adjust 아래) */
.axe-doc__callout--go {
  background: #e9f6ec;
  border-left-color: #2b7a3f;
}
.axe-doc__callout--go .axe-doc__callout-label {
  color: #2b7a3f;
}
.axe-doc__callout--conditional {
  background: #fbf0e0;
  border-left-color: #b8651a;
}
.axe-doc__callout--conditional .axe-doc__callout-label {
  color: #b8651a;
}
.axe-doc__callout--pass {
  background: #fbe7e2;
  border-left-color: #c4321f;
}
.axe-doc__callout--pass .axe-doc__callout-label {
  color: #c4321f;
}

/* ------------------------------------------------------------
 *  Table — formal
 * ------------------------------------------------------------ */
.axe-doc__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 9pt;
  margin: 10pt 0;
  font-variant-numeric: tabular-nums;
}
.axe-doc__table caption {
  caption-side: top;
  text-align: left;
  font-size: 8pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 4pt;
}
.axe-doc__table th {
  text-align: left;
  font-weight: 700;
  color: var(--doc-ink);
  padding: 5pt 8pt;
  border-bottom: 1pt solid var(--doc-rule-strong);
  vertical-align: bottom;
}
.axe-doc__table td {
  padding: 5pt 8pt;
  border-bottom: 0.5pt solid var(--doc-rule);
  color: var(--doc-ink-2);
  vertical-align: top;
}
.axe-doc__table tr {
  break-inside: avoid;
}
.axe-doc__table--zebra tbody tr:nth-child(even) {
  background: var(--doc-band);
}
.axe-doc__table .axe-doc__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 *  Signature / sign-off block
 * ------------------------------------------------------------ */
.axe-doc__signoff {
  margin-top: 24pt;
  display: flex;
  flex-wrap: wrap;
  gap: 24pt;
  break-inside: avoid;
}
.axe-doc__sign {
  min-width: 150pt;
}
.axe-doc__sign-line {
  border-top: 0.75pt solid var(--doc-ink);
  padding-top: 4pt;
  margin-top: 28pt;
}
.axe-doc__sign-name {
  font-size: 10pt;
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__sign-title {
  font-size: 8.5pt;
  color: var(--doc-muted);
}

/* ------------------------------------------------------------
 *  Footer — top hairline + confidential · page indicator
 * ------------------------------------------------------------ */
.axe-doc__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: 22pt;
  padding-top: 6pt;
  border-top: 0.75pt solid var(--doc-rule);
  font-size: 7.5pt;
  color: var(--doc-muted);
}
.axe-doc__footer-page::after {
  /* 화면에서는 정적, 인쇄 시 @page counter 가 별도 처리 */
  content: attr(data-page);
}

/* ------------------------------------------------------------
 *  Layout helpers — 가로 문서 2-단, 페이지 나눔
 * ------------------------------------------------------------ */
.axe-doc__cols {
  column-count: 2;
  column-gap: 20pt;
  column-rule: 0.5pt solid var(--doc-rule);
}
.axe-doc__cols-3 {
  column-count: 3;
  column-gap: 16pt;
}
.axe-doc__pagebreak {
  break-after: page;
}
.axe-doc__pagebreak-before {
  break-before: page;
}
.axe-doc__nobreak {
  break-inside: avoid;
}
.axe-doc__spacer {
  height: 12pt;
}

/* ------------------------------------------------------------
 *  Print — backdrop/그림자 제거, @page margin 인계, 색 강제
 * ------------------------------------------------------------ */
@media print {
  html,
  body {
    background: #ffffff !important;
  }
  /* showcase chrome 숨김 */
  .axe-doc-toolbar,
  [data-print-hide] {
    display: none !important;
  }
  .axe-doc-stage {
    display: block;
    padding: 0;
    background: none;
    min-height: 0;
    gap: 0;
  }
  .axe-doc {
    /* 종이 시뮬레이션 해제 — @page 가 size/margin 인계 */
    width: auto;
    min-height: 0;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border-radius: 0;
  }
  /* 밴드/배경/보더 색을 인쇄에 강제 (회색조 변환 방지) */
  .axe-doc,
  .axe-doc * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* 한 문서 = 한 orientation. 인쇄될 종이만 표시. */
  .axe-doc + .axe-doc {
    break-before: page;
  }
}

/* ============================================================
 * Phase 18 — Document data visuals (Track B)
 *
 * Resolved-spec 경계: 렌더러(React doc-viz 컴포넌트 · jinja _viz 매크로)는
 * 산술만 한다 — 선형 보간, 누적합, grid 곱셈. 축 tick 배열 · yMax · 표시
 * 문자열("₩60억", "15.8%")은 전부 호출자 책임 (ic-memo 의 기존 "str 표시값"
 * 규약의 연장). 함수 prop 금지.
 *
 * SVG geometry 계약: viewBox `0 0 482 H`(portrait 본문폭 170mm≈482pt,
 * 1 user unit ≡ 1pt) · 반폭 2-up 은 `0 0 231 H` · plot 마진
 * {l:36, r:8, t:8(valueLabels 시 16), b:18} · 좌표 소수 2자리 고정
 * (toFixed(2) / '%.2f'|format) · 색은 attribute 금지 — CSS 클래스/currentColor.
 * 기하 변경 = TS(doc-viz) · jinja(_viz) · golden(__fixtures__) 3점 동시 commit
 * (검증: scripts/doc-viz-parity/{gen-golden.mts,check_jinja.py}).
 *
 * 화면 대시보드 차트는 chart/Chart.tsx(recharts) — 본 섹션은 인쇄 문서 전용.
 * `.axe-doc` 내부 반응형 무대상 (by design — mm 고정 종이).
 * ============================================================ */

/* ------------------------------------------------------------
 *  신규 토큰 — 기존 .axe-doc 블록(상단) 무수정 원칙에 따라 append
 *  블록으로 추가 (cascade 가 동일 selector 의 변수 선언을 병합).
 *  카테고리 6색 = 휘도 분산 (실측 L* 29~63, 인접 시리즈 최소 ΔL*≈7,
 *  donut wrap 6↔1≈4.6) — 색 단독으로 흑백 복사 생존 불가. 그래서
 *  2-series bar 는 valueLabels 병기, donut 은 범례 표시값 병기가 규약
 *  (데모가 그 패턴). viz-1 은 --doc-accent(브랜드) 추종이라 rebrand 시
 *  사다리가 조용히 움직임 — 완전한 ≥12 사다리 재설계는
 *  B-ui-doc-viz-grayscale-ladder. (어드버서리얼 리뷰 2026-06-10)
 * ------------------------------------------------------------ */
.axe-doc {
  --doc-positive: #2b7a3f; /* callout --go 와 동일 (의미색 재사용) */
  --doc-negative: #c4321f; /* callout --pass 와 동일 */
  --doc-viz-1: var(--doc-accent); /* 1순위 = 브랜드 claret 추종 */
  --doc-viz-2: #31597f; /* 진청 */
  --doc-viz-3: #8a7f63; /* 모래 */
  --doc-viz-4: #c2913a; /* 황토 */
  --doc-viz-5: #4a7a55; /* 회록 */
  --doc-viz-6: #594a6b; /* 회보라 */
}

/* ------------------------------------------------------------
 *  표 variants
 * ------------------------------------------------------------ */
/* 재무표 — 첫 열 외 우정렬. :not() 형이라 jinja 루프에서 셀 클래스 불요. */
.axe-doc__table--financial th:not(:first-child),
.axe-doc__table--financial td:not(:first-child) {
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
}
.axe-doc__table--compact {
  font-size: 8pt;
}
.axe-doc__table--compact th,
.axe-doc__table--compact td {
  padding: 3pt 6pt;
}
/* 인쇄 페이지마다 thead 반복 — 기본 동작이지만 명시 (긴 표 분할 대비) */
.axe-doc__table thead {
  display: table-header-group;
}
/* 짧은 표 opt-in — 표 전체를 한 페이지에 응집 */
.axe-doc__table--keep {
  break-inside: avoid;
}

/* 행 역할 — 회계 괘선 관례: 합계 = 위 단선 + 아래 이중선 */
.axe-doc__row--group th,
.axe-doc__row--group td {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  background: var(--doc-band);
  border-bottom-color: var(--doc-rule-strong);
}
.axe-doc__row--group {
  break-after: avoid; /* 그룹 헤더가 페이지 끝에 고아로 남지 않게 */
}
.axe-doc__row--subtotal td,
.axe-doc__row--subtotal th {
  font-weight: 600;
  color: var(--doc-ink);
  border-top: 0.75pt solid var(--doc-rule-strong);
}
.axe-doc__row--total td,
.axe-doc__row--total th {
  font-weight: 700;
  color: var(--doc-ink);
  border-top: 1pt solid var(--doc-ink);
  border-bottom: 2.25pt double var(--doc-ink);
}
.axe-doc__row--subtotal,
.axe-doc__row--total {
  break-before: avoid; /* Chromium best-effort — 실패해도 데이터 무손실 */
}
.axe-doc__row--indent td:first-child,
.axe-doc__row--indent th:first-child {
  padding-left: 18pt;
}
.axe-doc__row--indent-2 td:first-child,
.axe-doc__row--indent-2 th:first-child {
  padding-left: 30pt;
}
/* 그룹+소계 응집 (opt-in) — cap table 의 다중 tbody 단위 페이지 나눔 */
tbody.axe-doc__rowgroup {
  break-inside: avoid;
}

/* 셀 유틸 */
.axe-doc__ctr {
  text-align: center;
}
/* 음수 — 괄호 (1,234) 는 표시 문자열 책임. 색+괄호 = 흑백 복사 이중 부호. */
.axe-doc__neg {
  color: var(--doc-negative);
}
.axe-doc__pos {
  color: var(--doc-positive);
}
.axe-doc__fn {
  font-size: 0.7em;
  vertical-align: super;
  color: var(--doc-accent-ink);
}
/* 지분 미니바 — inline 은 `--w` 데이터만 주입, 기존 print-color-adjust
 * (.axe-doc * exact) 가 gradient 인쇄를 보장. */
.axe-doc__cellbar {
  display: inline-block;
  vertical-align: -1pt;
  width: 36pt;
  height: 5pt;
  margin-right: 4pt;
  background: linear-gradient(
    to right,
    var(--doc-accent) var(--w, 0%),
    var(--doc-band) var(--w, 0%)
  );
  border: 0.5pt solid var(--doc-rule);
  border-radius: 1pt;
}

/* 비교표 — 열 사이 수직 헤어라인 + 제안 열 하이라이트 */
.axe-doc__table--compare th:not(:first-child) {
  text-align: center;
}
.axe-doc__table--compare td:not(:first-child),
.axe-doc__table--compare th:not(:first-child) {
  border-left: 0.5pt solid var(--doc-rule);
}
.axe-doc__table--compare th:first-child,
.axe-doc__table--compare td:first-child {
  color: var(--doc-muted);
  width: 24%;
}
/* colgroup 하이라이트 — col 은 배경만 가능 (보더 불가, CSS 2.1 제약) */
col.axe-doc__col--hl {
  background: var(--doc-accent-soft);
}
.axe-doc__table--compare thead th.axe-doc__th--hl {
  border-bottom: 1.5pt solid var(--doc-accent);
  color: var(--doc-accent-ink);
}

/* 표 단위 — caption 우측 float. 각주는 표 *밖* 형제 ul (__tnotes).
 * tfoot 금지: Chromium 인쇄에서 매 페이지 반복 — 합계/각주가 중복 출력됨. */
.axe-doc__table caption .axe-doc__table-unit {
  float: right;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
.axe-doc__tnotes {
  margin: -6pt 0 10pt;
  padding: 0;
  list-style: none;
  font-size: 7.5pt;
  color: var(--doc-muted);
}
.axe-doc__tnotes li {
  margin-bottom: 1pt;
}

/* sr 유틸 — document.css 로컬 정의. jinja axe_css 채널 = tokens+document.css
 * 인라인 계약이라 indicators.css 의 .axe-sr-only 를 못 쓴다 (부재 검증됨). */
.axe-doc__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------
 *  .axe-doc-viz — 서버 SVG 차트 (bar / line / donut)
 *  색 = series/key 클래스의 currentColor 단일 채널.
 * ------------------------------------------------------------ */
.axe-doc-viz {
  margin: 10pt 0;
  break-inside: avoid; /* figure = 원자 단위 (차트 H 200u ≈ 70mm — 항상 1페이지 내) */
}
.axe-doc-viz--wide {
  column-span: all; /* landscape 2-col 탈출 */
}
.axe-doc__figrow {
  display: flex;
  gap: 12pt; /* 2-up — 각 child flex:1, 반폭 viewBox 231 사용 */
}
.axe-doc__figrow > * {
  flex: 1;
  min-width: 0;
}
.axe-doc-viz__caption {
  font-size: 8pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 4pt;
}
.axe-doc-viz__svg {
  display: block;
  width: 100%;
  height: auto;
}
.axe-doc-viz__grid line {
  stroke: var(--doc-rule);
  stroke-width: 0.5px;
  shape-rendering: crispEdges;
}
.axe-doc-viz__axis line {
  stroke: var(--doc-rule-strong);
  stroke-width: 0.75px;
  shape-rendering: crispEdges;
}
.axe-doc-viz__tick,
.axe-doc-viz__xlabel {
  fill: var(--doc-muted);
  font-size: 7px;
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.axe-doc-viz__value {
  fill: var(--doc-ink-2);
  font-size: 7px;
  font-variant-numeric: tabular-nums;
}
/* 카테고리 색 — series(SVG)·key(범례) 공용 currentColor 채널 */
.axe-doc-viz__series--1, .axe-doc-viz__key--1 { color: var(--doc-viz-1); }
.axe-doc-viz__series--2, .axe-doc-viz__key--2 { color: var(--doc-viz-2); }
.axe-doc-viz__series--3, .axe-doc-viz__key--3 { color: var(--doc-viz-3); }
.axe-doc-viz__series--4, .axe-doc-viz__key--4 { color: var(--doc-viz-4); }
.axe-doc-viz__series--5, .axe-doc-viz__key--5 { color: var(--doc-viz-5); }
.axe-doc-viz__series--6, .axe-doc-viz__key--6 { color: var(--doc-viz-6); }
.axe-doc-viz--bar .axe-doc-viz__series rect {
  fill: currentColor;
  shape-rendering: crispEdges;
}
.axe-doc-viz--line .axe-doc-viz__series polyline {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6px;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* 예측/2nd 시리즈 — dashed = 흑백 복사 redundant encoding */
.axe-doc-viz--line .axe-doc-viz__series--dashed polyline {
  stroke-dasharray: 4 2.5;
}
.axe-doc-viz--line .axe-doc-viz__series circle {
  fill: var(--doc-paper);
  stroke: currentColor;
  stroke-width: 1.2px;
}
/* donut — pathLength=100 기법: 슬라이스 = stroke-dasharray 백분율 산술만
 * (π·trig·rotate 전부 불요 — jinja 패리티 면적 최소화). */
.axe-doc-viz--donut .axe-doc-viz__slice {
  fill: none;
  stroke: currentColor;
  stroke-width: 26px;
}
.axe-doc-viz__donut-value {
  fill: var(--doc-ink);
  font-size: 15px;
  font-weight: 700;
  text-anchor: middle;
  font-variant-numeric: tabular-nums;
}
.axe-doc-viz__donut-label {
  fill: var(--doc-muted);
  font-size: 7px;
  text-anchor: middle;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* 범례 = SVG 밖 HTML ul — 스크린리더 · 한글 줄바꿈 · 타이포 일관 */
.axe-doc-viz__legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4pt 12pt;
  margin: 4pt 0 0;
  padding: 0;
  font-size: 7.5pt;
  color: var(--doc-ink-2);
}
.axe-doc-viz__key::before {
  content: "";
  display: inline-block;
  width: 7pt;
  height: 7pt;
  margin-right: 3pt;
  vertical-align: -0.5pt;
  background: currentColor;
  border-radius: 1pt;
}

/* ------------------------------------------------------------
 *  .axe-doc-diagram — 투자 구조 다이어그램 (grid 배치, 수동 레이아웃)
 *  노드 kind = 색 아닌 테두리 *형태* 구분 (흑백 복사 의미 보존).
 *  신주/구주 = accent/파선 이중 부호.
 * ------------------------------------------------------------ */
.axe-doc-diagram__node rect {
  fill: var(--doc-paper);
  stroke: var(--doc-rule-strong);
  stroke-width: 0.9px;
}
.axe-doc-diagram__node--fund rect {
  fill: var(--doc-band);
  stroke: var(--doc-accent);
  stroke-width: 1.2px;
}
.axe-doc-diagram__node--spc rect {
  stroke-dasharray: 3 2;
}
.axe-doc-diagram__node--person rect {
  rx: 22px;
}
.axe-doc-diagram__node--target rect {
  stroke: var(--doc-ink);
  stroke-width: 1.4px;
}
.axe-doc-diagram__node-label {
  fill: var(--doc-ink);
  font-size: 8.5px;
  font-weight: 700;
  text-anchor: middle;
}
.axe-doc-diagram__node-sub {
  fill: var(--doc-muted);
  font-size: 7px;
  text-anchor: middle;
}
.axe-doc-diagram__edge path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1px;
}
.axe-doc-diagram__edge {
  color: var(--doc-ink-2); /* equity 기본 */
}
.axe-doc-diagram__edge--new {
  color: var(--doc-accent); /* 신주 = accent 실선 */
}
.axe-doc-diagram__edge--old path {
  stroke-dasharray: 3.5 2.5; /* 구주 = 파선 */
}
.axe-doc-diagram__edge--flow {
  color: var(--doc-muted);
}
.axe-doc-diagram__edge--flow path {
  stroke-dasharray: 1.5 2.5; /* 출자/자금 = 점선 */
}
/* 화살촉 — marker 내용은 참조 엣지의 color 를 상속받지 못함 (context-fill
 * 미지원). marker 자체에 edge 클래스를 부여하고 본 규칙이 fill 을 채움.
 * specificity (0,2,1) — 위 `.axe-doc-diagram__edge path` 의 fill:none 을 이김. */
.axe-doc-diagram__edge path.axe-doc-diagram__edge-arrow {
  fill: currentColor;
  stroke: none;
}
/* 엣지 라벨 halo — 선 위 가독, 인쇄 안전 (paint-order 는 PDF 변환 시 보존) */
.axe-doc-diagram__edge-label,
.axe-doc-diagram__edge-sub {
  fill: currentColor;
  font-size: 7px;
  paint-order: stroke;
  stroke: var(--doc-paper);
  stroke-width: 2.5px;
}

/* ------------------------------------------------------------
 *  Print — sr 표는 인쇄물에서 제외 (HTML 소비자 전용 fallback)
 * ------------------------------------------------------------ */
@media print {
  .axe-doc__sr {
    display: none;
  }
}

/* ============================================================
   계약서 variant — .axe-doc--contract (2026-06)
   메모·서한의 chrome(masthead·meta 밴드·accent 색)을 걷어내고 법률문서 톤으로:
   가운데 제목 + 당사자 식별 + 번호 조항(장 가운데/조 굵게/항·호) + 서명·날인 + 페이지번호.
   .axe-doc 의 A4 종이·토큰·본문 prose·표 는 그대로 재활용 (양식 다 빼고 "문서").
   ============================================================ */
.axe-doc--contract { position: relative; padding-bottom: 24mm; }
.axe-doc--contract .axe-doc__masthead { display: none; }
.axe-doc--contract .axe-doc__title {
  text-align: center; letter-spacing: 0.36em; font-size: 16pt; font-weight: 700;
  color: var(--doc-ink); margin: 4mm 0 1.5mm; border: 0;
}
.axe-doc--contract .axe-doc__subtitle { text-align: center; color: var(--doc-muted); margin: 0 0 2mm; }
.axe-doc--contract .axe-doc__contract-rule { border: 0; border-top: 0.6pt solid var(--doc-rule-strong); margin: 4mm 0 5mm; }
.axe-doc--contract .axe-doc__parties { margin: 0 0 4mm; }
.axe-doc--contract .axe-doc__party { font-size: 10.5pt; line-height: 1.55; margin: 1.5mm 0; }
.axe-doc--contract .axe-doc__party-role { font-weight: 800; color: var(--doc-ink); }
/* 장 — 가운데, 액센트/괘선/카운터 제거 */
.axe-doc--contract .axe-doc__section-title,
.axe-doc--contract .axe-doc__section-title--accent {
  text-align: center; border: 0; background: none; color: var(--doc-ink);
  font-size: 12pt; font-weight: 800; letter-spacing: 0.04em; margin: 9mm 0 3.5mm; padding: 0;
}
.axe-doc--contract .axe-doc__section-title::before { content: none; }
/* 조 + 본문 */
.axe-doc--contract .axe-doc__body { font-size: 11pt; line-height: 1.7; color: var(--doc-ink); }
.axe-doc--contract .axe-doc__body h3 { font-size: 11pt; font-weight: 800; color: var(--doc-ink); margin: 5mm 0 1.5mm; }
.axe-doc--contract .axe-doc__body p { text-align: justify; margin: 1.5mm 0; }
.axe-doc--contract .axe-doc__body ol { padding-left: 8mm; }
.axe-doc--contract .axe-doc__body li { text-align: justify; margin: 1.2mm 0; }
/* 표 — 단순 검은색 1px 테두리(상하좌우 풀 그리드) + table-layout:fixed.
   컬럼 너비(%)는 표 내용을 LLM 이 판단해 <colgroup><col style="width:N%"> 로 주입한다
   (가변 콘텐츠를 가독성 좋게 정렬 — 주소·설명 넓게, 숫자·코드 좁게). */
.axe-doc--contract .axe-doc__table { table-layout: fixed; }
.axe-doc--contract .axe-doc__table th,
.axe-doc--contract .axe-doc__table td { border: 1px solid #1a1a1a; background: none; padding: 4pt 6pt;
  vertical-align: top; word-break: keep-all; overflow-wrap: break-word; }
.axe-doc--contract .axe-doc__table thead th { font-weight: 700; }
.axe-doc--contract .axe-doc__table caption { text-align: left; }
/* 서명·날인 — 통상 계약서식: 당사자별 세로 블록(회사명·주소·법인등록번호·대표이사명 (인)) */
.axe-doc--contract .axe-doc__signoff { display: block; border: 0; padding: 0; margin: 10mm 0 0; }
.axe-doc--contract .axe-doc__sign-intro { font-size: 10.5pt; margin: 0 0 4mm; }
.axe-doc--contract .axe-doc__sign { font-size: 10pt; line-height: 1.65; margin: 7mm 0; }
.axe-doc--contract .axe-doc__sign .role { font-weight: 800; }
.axe-doc--contract .axe-doc__sign .seal { float: right; color: var(--doc-muted); }
.axe-doc--contract .axe-doc__sign .addr { color: var(--doc-ink-2); }
/* 페이지번호 */
.axe-doc--contract .axe-doc__pagenum {
  position: absolute; left: 0; right: 0; bottom: 9mm; text-align: center;
  font-size: 9pt; color: var(--doc-muted); letter-spacing: 0.12em;
}
@media print { .axe-doc--contract .axe-doc__pagenum { display: none; } }
