/* ── 웹폰트 (self-host · 외부 CDN 요청 0건) ─────────────────
   Pretendard Variable «라틴 조각만» 싣는다. 한글 조각은 뺐다 — 사용자가 넣는 대화는
   임의 음절이라 웹폰트 전송량에 상한이 서지 않고, 일부만 실으면 조각이 없는 글자가
   시스템 폰트로 떨어져 «한 단어 안에서 글꼴이 갈린다»(안 싣는 것보다 나쁘다).
   ⚠️ 한글은 --font 뒤 스택이 그린다. 이 파일에 CDN URL을 넣지 마라.
   ⚠️ 한글 조각을 다시 넣으면 build.mjs 의 assertFontRefsLocal 이 빌드를 죽인다.
   ⚠️ 라틴-1 조각([71])도 뺐다(2026-08-13) — 3툴에서 «쓰는 글자 0개»인데 28KB를 대기시켰고,
      그 조각의 글자 하나가 페이지에 들어오는 순간 전송량 게이트가 깨진다. 담긴 것이
      전부 기호·확장 라틴이라 시스템 폰트로 떨어져도 육안 차이가 없다. */
@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url(/fonts/PretendardVariable.subset.91.woff2) format('woff2');unicode-range:U+20-22, U+27-2a, U+2c-39, U+3a-3b, U+3f, U+41-4e, U+4f-5d, U+61-7b, U+7d, U+a0-a1, U+ab, U+ad-ae, U+b7, U+bb, U+bf, U+2013-2014, U+201c-201d, U+2122;}

/* styles.5555e250.css — 데이터리포트 허브 공통 스타일
   디자인 토큰 → 레이아웃 → 컴포넌트 순.
   아이콘 로딩 없음. 폰트는 «자체 호스팅»이라 외부 오리진 요청은 0건이다
   (2026-08-13 — 그전에는 폰트도 0건이었다. 「요청 0건」이 아니라 「외부 요청 0건」이다).
   360px에서 가로 넘침 0을 기준선으로 잡는다. */

/* ── 디자인 토큰 ─────────────────────────────────────────────
   ⚠️ 라이트 모드만 정의한다. 다크 대응표는 다음 회차 명세를 기다린다 —
      아래 @media (prefers-color-scheme: dark) 블록은 «기존 값 그대로» 두었다.
   ⚠️ 이름을 새로 만들지 않고 «기존 변수의 값을 갱신»하는 것이 규칙이다.
      두 벌이 공존하면 한쪽만 늙고, 늙은 쪽이 어디서 쓰이는지 아무도 모르게 된다.
      새로 «만든» 것은 기존에 대응 이름이 없던 것들뿐이다(--text-faint · --radius-lg ·
      --btn-* · --fs-* · --fw-* · --ls-* · --sp-* · --motion · --touch · --tool-accent · --p1~--p6). */
:root {
  /* 표면 — 페이지와 카드 두 단계다. --surface 가 «카드», --bg 가 «페이지»다. */
  /* ⚠️ 2026-09-14 — 값을 아이폰 «설정»의 묶음 바탕으로 갈았다(⑱ 「모든 페이지들을 아이폰스타일로」). 페이지는 연회색 · 판은 흰색이다.
     그전 값(페이지 #ffffff · 판 #fafaf8)은 두 단계가 거의 갈리지 않아 «판»이 보이지 않았다. 이름은 그대로다(두 벌을 두지 않는다). */
  --bg: #f2f2f7;
  --bg-soft: #e9e9ee;
  --surface: #ffffff;
  --border: #e5e5ea;
  --border-strong: #d1d1d6;
  /* 드롭존 «전용» 경계색. 🟢 2026-09-02 실측으로 갈라낸 토큰이다.
     ⚠️ --border-strong 을 통째로 올리지 않은 이유 — 그 토큰은 시트에서 17곳이 쓰고
        대부분 «1px 실선 경계»(버튼·카드·표·인용)다. 드롭존은 «1.5px 점선 + 큰 빈 면적»이라
        요구되는 대비가 다르고, 토큰을 올리면 17곳의 시각이 함께 바뀌는데 이 회차에 그
        전량을 검증할 수 없다. **검증할 수 있는 만큼만 바꾼다.**
     🟢 대비 실측 — 기존 #e2e2de ↔ --surface #fafaf8 = 1.24:1 로 🟡 비텍스트 권고 하한
        3:1 에 크게 못 미쳤다. #8e8e93 로 올리면 3.12:1 이다.
     ⚠️ 새 색을 만들지 않았다 — 팔레트의 무채색 슬롯(--p6)을 그대로 쓴다. */
  --dropzone-border: #8e8e93;
  --text: #111112;
  --text-muted: #6e6e73;
  --text-faint: #95958e;
  /* 링크·포커스 등 «상호작용» 한 색. 툴 액센트와 다른 축이다(아래 --tool-accent). */
  --accent: #4c4ae0;
  --accent-soft: #f1f1fe;
  --accent-border: #d9d8f8;
  --ok: #1d9e75;
  --ok-soft: #f2f9f6;
  --ok-border: #dcece5;
  /* 경고 — «오류»가 아니라 «잘렸다·범위를 넘었다»를 알리는 색. 오류(빨강)와 구분한다.
     ⚠️ 이 세 값은 이번 개편에서 손대지 않았다 — 의미색이라 팔레트 정렬 대상이 아니다. */
  --warn: #92400e;
  --warn-soft: #fffbeb;
  --warn-border: #fde68a;

  /* 라운드 — 컨트롤 / 카드 / 드롭존 세 단계. */
  --radius-sm: 10px;
  --radius: 12px;
  --radius-lg: 16px;

  --wrap: 60rem;
  --pad: 1rem;

  /* 주 버튼은 잉크 블랙이다. --accent 로 칠하지 않는다 — 링크색과 버튼색은 다른 축이고,
     한 변수로 묶으면 툴별 액센트를 바꿀 때 버튼까지 따라 움직인다. */
  --btn-primary-bg: #111112;
  --btn-primary-fg: #ffffff;

  /* 툴 액센트 — «탭 밑줄 3px 전용»이다. 다른 곳에 쓰지 않는다.
     각 페이지가 body 클래스에서 이 값만 덮어쓴다(아래 .page-* 규칙). */
  --tool-accent: #4c4ae0;

  /* 참여자 램프 — 결과 화면 전용. 5색 + 6번째 회색.
     ⚠️ 값의 SSOT는 여기다. public/kakao-chat.js 의 COLORS 는 이 값을 «따라간다» —
        한쪽만 고치면 범례 점과 막대 색이 갈린다. */
  --p1: #7f77dd;
  --p2: #1d9e75;
  --p3: #d85a30;
  --p4: #378add;
  --p5: #ba7517;
  --p6: #8e8e93;
  /* 🟢 2026-09-02 신설 — 7번째 툴(/image-convert)의 액센트 자리.
     ⚠️ 그전 회차에 «남은 유채색 슬롯이 --p1 하나»라고 적어 두었고 그것을 /image-crop 이
        가져갔다. --p6 은 무채색이라 탭 밑줄로 쓰면 «꺼진 탭»으로 읽히고, 이 회차에
        --dropzone-border 로도 쓰이고 있어 뜻이 겹친다. 그래서 팔레트를 한 칸 늘렸다.
     🟢 대비 실측 — --surface(#fafaf8) 대비 5.55:1(라이트) · 다크 6.48:1. */
  --p7: #b0347a;

  /* 활자 6단. rem 이 아니라 px 로 둔다 — 스케일이 «단»이지 «비율»이 아니다. */
  --fs-1: 38px;
  --fs-2: 20px;
  --fs-3: 17px;
  --fs-4: 15px;
  --fs-5: 14px;
  --fs-6: 13px;

  --fw-400: 400;
  --fw-500: 500;
  --fw-600: 600;
  --fw-700: 700;

  --ls-title: -0.045em;
  --ls-body: -0.02em;

  /* 간격 8단 */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 40px;
  --sp-8: 56px;

  --motion: 160ms;
  --touch: 48px;

  /* ── 아이폰 기준 토큰 (2026-09-13 · 사용자 지시 ⑰ «전체적인 비쥬얼들을 아이폰에 맞춰서») ──
     ⚠️ 이 한 벌이 SSOT 다 — 라우트마다 복제하지 않는다(페이지 <style> 에 사본을 두지 않는다).
     ⚠️ 이름을 새로 만든 것은 «기존에 대응 이름이 없던 것»뿐이다(위 머리말 규칙).
        글꼴은 기존 --font 의 «값»을 고쳤다(아래). 그림자는 --shadow(=none · 층은 헤어라인)를 건드리지
        않고 «떠 있는 그림»에만 쓰는 --shadow-app 을 따로 뒀다 — --shadow 는 표·카드·인쇄 시트가 함께 읽는다. */
  /* 터치 하한 — 🟡 Apple HIG 의 최소 44×44pt. 버튼 표준 --touch(48px)는 그 위에 있다. */
  --touch-min: 44px;
  /* 안전영역 — layout.mjs 의 viewport 메타에 viewport-fit=cover 가 있을 때만 값이 선다.
     ⚠️ 헤드리스에서는 전부 0 이다 — 노치·홈 막대가 있는 기기에서만 값이 생긴다(실기기 몫). */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  /* 앱 아이콘 — 한 줄 네 칸에 맞춘 크기와 모서리(한 변의 23% — 아이폰 홈 화면 아이콘의 둥근 정도). */
  --icon: clamp(52px, 15vw, 64px);
  --icon-radius: 23%;
  /* 젤리 질감 — 위쪽 광택 한 겹(--gloss) + 안쪽 위 밝은 테 · 아래 그늘 + 바닥 그림자(--shadow-app). */
  --gloss: radial-gradient(120% 75% at 50% -8%, rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0.18) 46%, rgba(255, 255, 255, 0) 62%);
  --shadow-app: 0 1px 1.5px rgba(17, 17, 18, 0.08), 0 7px 16px -7px rgba(17, 17, 18, 0.38),
    inset 0 1px 0 rgba(255, 255, 255, 0.55), inset 0 -3px 6px rgba(17, 17, 18, 0.12);
  /* 눌림 — 살짝 튕기는 곡선. 움직임 줄이기를 켠 기기에서는 홈 블록의 reduce 규칙이 끈다. */
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  /* 채움색 — 아이폰 검색칸 · 알약 버튼의 옅은 회색 채움. */
  --fill: rgba(118, 118, 128, 0.12);
  /* 판 그림자 — 흰 판이 연회색 바탕 위에 «떠 있게» 하는 한 겹(2026-09-14 · ⑱ 입체). --shadow(=none)는 표·인쇄가 읽으므로 따로 둔다. */
  --shadow-card: 0 1px 2px rgba(17, 17, 18, 0.05), 0 8px 22px -12px rgba(17, 17, 18, 0.2);

  /* ⚠️ 웹폰트는 «라틴만» 덮는다. 한글은 뒤 스택이 그린다 — 그래서 뒤 스택의 «순서»가
     이 사이트 한글 인상을 정한다. 스택 중간의 'Pretendard' 는 «로컬 설치본»을 잡는
     자리다: 네트워크 요청이 늘지 않고, 설치된 기기에서는 한글까지 Pretendard로 렌더된다. */
  /* ⚠️ 2026-09-13 — 순서를 «아이폰 시스템 글꼴 먼저»로 바꿨다(지시 ⑰). 위 두 문단은 그 시점의 참이라 둔다.
     애플 기기에서는 -apple-system(SF) · Apple SD Gothic Neo 가 그린다. 그 밖 기기에는 앞 셋이 없어
     전과 같은 자리(Pretendard 라틴 조각 → 로컬 Pretendard → 시스템 한글)로 떨어진다.
     ⚠️ 그래서 이 줄이 바꾼 화면은 헤드리스(Windows)에서 보이지 않는다 — 애플 기기의 글꼴 확인은 실기기 몫이다. */
  --font: -apple-system, BlinkMacSystemFont, 'Apple SD Gothic Neo', 'Pretendard Variable',
    'Pretendard', 'Malgun Gothic', 'Noto Sans KR', system-ui, sans-serif;

  /* 그림자는 0이다. 층은 «경계 1px 헤어라인»으로만 만든다. */
  --shadow: none;
}

/* ── 일본어 문서의 글꼴 (2026-09-17 · ⑳ 본 회차) ──────────────────
   🟢 헤드리스(Windows) 첫 캡쳐 — 위 스택이 가나 · 한자를 'Malgun Gothic'(한국어 글꼴)으로 그려 글자 사이가 벌어지고 한자 모양이 한국식이었다.
   그래서 일본어 문서에서만 일본어 시스템 글꼴을 한국어 글꼴 «앞»에 둔다. 웹폰트는 늘리지 않는다(요청 0 · build.mjs 폰트 게이트 그대로).
   ⚠️ :lang(ja) 는 <html lang> 을 따른다 — 런타임 문구는 page-lang 메타를 읽지만(S1), 글꼴은 «지금 화면에 선 글자의 언어»를 따르는 편이 맞다
      (브라우저 번역이 lang 을 바꾸면 번역된 글자에 맞는 글꼴이 선다).
   ⚠️ 자간 — 위 --ls-body(-0.02em) · --ls-title(-0.045em)은 라틴 · 한글 기준으로 조인 값이다. 전각 가나에 같은 값을 주면 글자가 붙는다 → 일본어는 0 · -0.01em.
   ⚠️ 애플 기기에서 -apple-system 이 일본어를 무엇으로 그리는지는 헤드리스가 못 잰다(⚪ · 실기기 몫). */
:root:lang(ja) {
  --font: -apple-system, BlinkMacSystemFont, 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Pretendard Variable',
    'Yu Gothic UI', 'Yu Gothic', 'Meiryo', 'Noto Sans JP', system-ui, sans-serif;
  --ls-body: 0;
  --ls-title: -0.01em;
}

/* 툴별 액센트 — ⚠️ 2026-09-14 에 body 클래스별 값(.page-pdf · .page-image …)을 걷어냈다.
   그 표는 «탭 밑줄 3px 전용»이었고 툴마다 따로 손으로 늘려 왔다(넷째 · 일곱째 툴에서 두 번 빠졌다).
   이제 도구 색의 SSOT 는 파일 끝 「⑱ 아이폰 젤리 판」 블록의 [data-tool] 표 한 곳이고, --tool-accent 도 거기서 난다. */

/* ── 다크 대응표 (2026-08-13 확정) ───────────────────────────
   ⚠️ 직전 회차에 «깨짐 방지»로 임시로 넣었던 4개 값은 이 표로 «대체»됐다 — 병기하지 않는다.
   ⚠️ --warn 계열 복원 (2026-08-13 같은 날 정정). 「의미색이라 팔레트 정렬 대상이 아니다」와
      「다크 대응이 필요 없다」는 다른 명제인데 앞의 것을 근거로 뒤의 것을 했다.
      경고색의 «색상»은 모드가 바뀌어도 노랑이어야 하지만 «배경»은 반드시 뒤집혀야 한다 —
      안 뒤집으면 어두운 페이지 한가운데 크림색 판이 선다.
      🟢 실측(정정 전): 다크에서 .unparsed 배경이 rgb(255,251,235)로 라이트 값 그대로였다. */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000;
    --bg-soft: #2c2c2e;
    --surface: #1c1c1e;
    --border: #2c2c2e;
    --border-strong: #3a3a3c;
    /* 다크에서도 같은 팔레트 슬롯(--p6 다크값)이다. 🟢 대비 6.20:1. */
    --dropzone-border: #9a9aa0;
    --text: #f2f2f0;
    --text-muted: #a0a0a6;
    --text-faint: #78787e;
    --accent: #8f8df5;
    --accent-soft: #1e1e33;
    --accent-border: #35345c;
    --ok: #4ecfa0;
    --ok-soft: #12241d;
    --ok-border: #24463a;
    --warn: #fcd34d;
    --warn-soft: #2a2110;
    --warn-border: #5a4413;
    --btn-primary-bg: #f2f2f0;
    --btn-primary-fg: #111112;
    --p1: #a79ff0;
    --p2: #4ecfa0;
    --p3: #f08a62;
    --p4: #6fb0ea;
    --p5: #e0a94a;
    --p6: #9a9aa0;
    --p7: #e87ab0;
    --shadow: none;
    --fill: rgba(118, 118, 128, 0.24);
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 22px -12px rgba(0, 0, 0, 0.7);
    --shadow-app: 0 1px 1.5px rgba(0, 0, 0, 0.3), 0 7px 16px -7px rgba(0, 0, 0, 0.75),
      inset 0 1px 0 rgba(255, 255, 255, 0.32), inset 0 -3px 6px rgba(0, 0, 0, 0.2);
  }
}

/* ── 리셋 ─────────────────────────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-3);
  font-weight: var(--fw-400);
  letter-spacing: var(--ls-body);
  line-height: 1.7;
  /* 한국어 줄바꿈: 단어 단위로 끊어 가독성 확보 */
  word-break: keep-all;
  overflow-wrap: anywhere;
}

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

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

h1,
h2,
h3 {
  line-height: 1.25;
  letter-spacing: var(--ls-title);
  font-weight: var(--fw-700);
}

/* 본문 강조 — 굵기를 700에서 600으로 내린다. 색은 본문색 그대로다.
   ⚠️ 태그를 제거하지 않는다. 문단당 3~4곳이 700으로 서면 «전부 강조 = 강조 없음»이
      되는데, 그건 마크업이 아니라 «스타일»의 문제다(🟢 2026-08-13 현행 화면 실측). */
strong,
b {
  font-weight: var(--fw-600);
  color: inherit;
}

/* ── 레이아웃 ─────────────────────────────────────────────── */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  /* 안전영역(가로 모드의 노치)보다 좁아지지 않는다. 헤드리스에서는 --safe-* 가 0 이라 전과 같은 --pad 다. */
  padding-inline: max(var(--pad), var(--safe-l)) max(var(--pad), var(--safe-r));
}

main {
  padding-block: 2rem 3rem;
}

main h1 {
  font-size: clamp(26px, 4.6vw, var(--fs-1));
  margin: 0 0 var(--sp-3);
}

.section {
  margin-top: 2.5rem;
}

.section h2 {
  font-size: var(--fs-2);
  margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
}

.lede {
  font-size: var(--fs-3);
  color: var(--text-muted);
  margin: 0;
}

.muted {
  color: var(--text-muted);
  font-size: var(--fs-4);
}

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 0.5rem;
  top: 0.5rem;
  z-index: 20;
  background: var(--surface);
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}

/* ── 헤더 ─────────────────────────────────────────────────────
   높이 56px 한 줄. 로고와 네비를 양끝으로 민다.
   ⚠️ .brand-tagline 은 «손대지 않는다» — 문자열도 남기고 display:none 도 걸지 않는다.
      숨긴 텍스트를 만들면 «화면에 없는 글자»가 HTML에 남아 검색엔진과 화면이 갈린다.
      400px에서 두 줄로 접히던 문제는 «접히지 않게» 푸는 것이 아니라
      로고 블록을 가로로 눕히고(줄 1개) 활자를 내려서 푼다 — 아래 .brand-text 를 본다. */
.site-header {
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  padding-top: var(--safe-t);
}

.site-header-inner {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--sp-3);
  min-height: 56px;
  padding-block: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}

/* 로고 그림 — ⚠️ 2026-09-14 부터 CSS 가 그리지 않는다. 그림은 src/brand.mjs 의 인라인 SVG(파비콘과 같은 소스)이고 여기는 «상자 크기»만 정한다.
   🟢 그전에는 이 자리가 배경 그라데이션(--accent 시작 · 테마를 탐) + 흰 세로 줄 6개였고 파비콘(막대 3개)과 화소 54.6~88.2% 가 갈렸다(⑱). */
.brand-mark {
  flex: none;
  display: block;
  width: 26px;
  height: 26px;
  max-width: none;
}

/* 로고 블록을 «가로»로 눕힌다 — 세로 2줄이던 것을 한 줄로 만들어 56px에 들어간다.
   태그라인은 지우지 않고 이름 옆에 작은 활자로 선다. */
.brand-text {
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
}
.brand-name {
  font-weight: var(--fw-700);
  font-size: var(--fs-3);
  letter-spacing: var(--ls-title);
  white-space: nowrap;
}
/* ⚠️ 2026-09-13 — .brand-tagline 규칙을 걷어냈다. 부제 노드 자체가 layout.mjs 에서 빠졌다
   (지시 ⑰ 「최상단에 '내 데이터 리포트'- 제거해」). 위 머리말의 «손대지 않는다»는 그 시점의 참이다 —
   그때 금지한 것은 «숨기기»였고, 이번은 문자열과 노드를 함께 지운 것이라 클로킹의 자리가 없다. */

/* 🟢 2026-08-21 (7차) 헤더 전환 — 가로 나열에서 «로고 + <details> 하나»로 바뀌었다.
   형태의 SSOT 는 playbook 「tool-spec.md」 절 「헤더 확장 조건」이고 여기 복제하지 않는다.
   🟢 전환 근거 실측 — 400px 에서 툴 4개 나열이 네비 scrollWidth 321 / clientWidth 270 =
      **여유 −51px** 였다. 넘친 부분은 overflow-x 안으로 숨어 «화면에서는 멀쩡해» 보였고,
      그래서 넷째 툴이 들어온 회차에 아무도 이것을 못 봤다. 재현 경로는 tests/nav-measure.mjs.
   ⚠️ overflow-x:auto 를 걷어낸다 — 드롭다운이 그 상자에 잘린다. 넘칠 것이 없어졌으므로
      스크롤 자체가 필요 없다(접힌 폭은 summary 하나다). */
.site-nav {
  margin-left: auto;
  min-width: 0;
}
.nav-fold {
  position: relative;
}
.nav-fold > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 56px;
  padding: 0 var(--sp-1);
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-5);
  font-weight: var(--fw-600);
  color: var(--text);
  white-space: nowrap;
  /* 접힌 상태에서도 «지금 어디에 있는지»가 남아야 한다 — 그 일을 하던 탭 밑줄 3px 을
     여기로 옮긴다. 툴 페이지가 아니면 액센트가 없어 투명으로 떨어진다. */
  border-bottom: 3px solid var(--tool-accent, transparent);
}
.nav-fold > summary::-webkit-details-marker {
  display: none;
}
/* 펼침 표시 — .fold 의 셰브런과 같은 그림이되 크기가 작다. 두 곳이 같은 값을 갖지
   않도록 여기 값을 따로 적는다(이 자리는 56px 헤더 안이고 .fold 는 본문이다). */
.nav-fold > summary::after {
  content: '';
  flex: none;
  width: 0.4rem;
  height: 0.4rem;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: rotate(45deg) translate(-0.12rem, -0.12rem);
  transition: transform var(--motion) ease;
}
.nav-fold[open] > summary::after {
  transform: rotate(225deg) translate(-0.08rem, -0.08rem);
}
/* 열린 목록은 «세로»이고 흐름 위에 뜬다 — 헤더가 밀려 본문이 아래로 내려가지 않게 한다. */
.nav-fold > ul {
  position: absolute;
  right: 0;
  top: calc(100% - 1px);
  z-index: 20;
  min-width: 12rem;
  display: flex;
  flex-direction: column;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: var(--sp-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg);
  box-shadow: 0 8px 24px rgba(17, 17, 18, 0.12);
}
.site-nav a {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch);
  padding: 0 var(--sp-3);
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-size: var(--fs-5);
  font-weight: var(--fw-500);
  color: var(--text-muted);
  white-space: nowrap;
  transition: color var(--motion) ease, background-color var(--motion) ease;
}
.site-nav a:hover {
  color: var(--text);
  background: var(--bg-soft);
}
/* 현재 툴 표시 — 열린 목록 «안»의 표시다. 접힌 상태의 표시는 위 summary 가 맡는다.
   🟢 이제 마크업의 aria-current 로 잡는다 — header() 가 route 를 받게 되어
   CSS 속성 선택자로 우회할 이유가 없어졌다. 그 우회는 툴이 늘 때 갱신이 누락되어
   /image-compress 가 «현재 탭» 표시를 못 받고 있었다(2026-08-21 조회). */
.site-nav a[aria-current='page'] {
  color: var(--text);
  font-weight: var(--fw-600);
  background: var(--bg-soft);
}
.site-nav a[aria-current='page']::before {
  content: '';
  flex: none;
  width: 3px;
  align-self: stretch;
  margin: var(--sp-2) 0;
  border-radius: 2px;
  background: var(--tool-accent, var(--accent));
}

/* ── 현재 툴 · 언어 선택기 (2026-09-12) ───────────────────────
   ⚠️ **현재 툴 항목은 «링크가 아니다»** — 자기 자신을 가리키는 링크를 0으로 두는 규칙
      (layout.mjs 머리말)에 따라 <span class="nav-self"> 로 선다. 그래서 위의
      ``.site-nav a[aria-current]`` 규칙이 닿지 않고, 같은 «현재» 표시를 여기서 다시 세운다.
      🟢 이 규칙이 없으면 열린 목록에서 현재 툴만 서체·여백이 달라 목록이 어긋나 보인다. */
.site-nav .nav-self {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch);
  padding: 0 var(--sp-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-5);
  font-weight: var(--fw-600);
  color: var(--text);
  background: var(--bg-soft);
  white-space: nowrap;
  cursor: default;
}
.site-nav .nav-self::before {
  content: '';
  flex: none;
  width: 3px;
  align-self: stretch;
  margin: var(--sp-2) 0;
  border-radius: 2px;
  background: var(--tool-accent, var(--accent));
}

/* 언어 선택기 — 헤더 오른쪽 끝. «다른 언어로 건너가는» 유일한 링크다.
   ⚠️ 글자 크기를 내비 summary 와 같은 칸(--fs-6)에 두어 헤더 한 줄(56px)을 넘기지 않는다.
   🟢 2026-09-12 실측(nav-measure · 400px): 가장 긴 조합(«KakaoTalk Chat Analyzer» + 한국어)에서도
      헤더 넘침 0 · 문서 넘침 0. */
.lang-switch {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-2);
}
.lang-switch a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  padding: 0 var(--sp-2);
  border-radius: var(--radius-sm);
  font-size: var(--fs-6);
  font-weight: var(--fw-500);
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--motion) ease, background-color var(--motion) ease;
}
.lang-switch a:hover {
  color: var(--text);
  background: var(--bg-soft);
}

/* ── 헤더 «자주 묻는 질문» 기호 · 좁은 폭의 자리 나눔 (2026-09-13 · 지시 ⑰ 집행) ─────────
   🟢 13px 글자 「자주 묻는 질문」(98px)을 끼운 실측 — 여유가 음수인 라우트 360px 17 · 390px 10 · 430px 15(최악 −53px).
   그래서 이 항목은 44px 기호다(이름은 aria-label). 그래도 영어 긴 툴 이름(«KakaoTalk Chat Analyzer»)에서는 모자라므로
   «현재 툴 이름»이 남는 폭까지만 서고 말줄임표로 끝난다 — 이름을 「도구」로 바꾸지 않는다(playbook 「헤더 확장 조건」).
   ⚠️ 로고는 줄지 않는다(flex: none) — 줄어드는 쪽은 현재 툴 이름 하나다. */
.brand {
  flex: none;
}
.site-nav,
.nav-fold,
.nav-fold > summary {
  min-width: 0;
}
.nav-current {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nav-faq {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  min-width: var(--touch-min);
  min-height: var(--touch);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  -webkit-tap-highlight-color: transparent;
  transition: color var(--motion) ease, background-color var(--motion) ease;
}
.nav-faq-icon {
  width: 22px;
  height: 22px;
  max-width: none;
}
.nav-faq:hover {
  color: var(--text);
  background: var(--bg-soft);
}
.nav-faq[aria-current='page'] {
  color: var(--accent);
  cursor: default;
}
@media (max-width: 26rem) {
  .lang-switch a {
    padding: 0 var(--sp-1);
  }
}

@media (max-width: 26rem) {
  /* 400px — 태그라인을 «이 폭에서만» 접는다.
     ⚠️ display:none 이 미디어쿼리 «안»에 있는 것과 «밖»에 있는 것은 다른 일이다.
        전 폭에 걸면 «HTML에는 있고 화면에는 어디에도 없는 글자»가 되어 클로킹이지만,
        폭에 따라 갈리는 것은 반응형이다 — 넓은 화면에서는 그대로 보인다.
     ⚠️ 문자열도 노드도 지우지 않는다. 접는 것뿐이다.
     🟢 이 줄을 접어야 툴 3개 링크가 400px에서 «전부» 선다(그 전에는 셋째가 가로 스크롤
        안에 숨었다). 태그라인은 어느 페이지에서든 반복되는 글이고, 네비는 이 사이트에서
        다른 툴로 가는 유일한 길이다 — 자리를 양보할 쪽이 정해져 있다. */
  .site-header-inner {
    gap: var(--sp-2);
  }
  /* 로고를 줄여 네비에 폭을 넘긴다 — 판정 조건이 «툴 3개가 잘림 없이 선다»이므로
     양보하는 쪽은 로고다. 잰 값으로 맞췄다: 네비 scrollWidth ≤ clientWidth. */
  .brand {
    gap: var(--sp-1);
  }
  .brand-mark {
    width: 22px;
    height: 22px;
  }
  .brand-name {
    font-size: var(--fs-5);
  }
  /* 🟢 2026-08-21 (7차) — 가로 나열 시절 규칙이었다. 접힌 형태에서는 목록이 세로라
     간격을 줄일 이유가 없고, 줄이면 터치 표적만 작아진다. summary 쪽만 활자를 내린다. */
  .nav-fold > summary {
    font-size: var(--fs-6);
    padding: 0;
  }
}

/* ── 접는 섹션 ────────────────────────────────────────────────
   ⚠️ 자바스크립트 0줄이다. 네이티브 <details>·<summary>만 쓴다 —
      스크립트로 접으면 JS가 죽었을 때 본문이 통째로 사라진다(접힌 채로 남는다).
   ⚠️ 접혀 있어도 HTML에는 있으므로 문장은 한 줄도 지워지지 않는다.
      «지우지 않고 접는다»가 이 블록의 전부다. */
.fold > summary {
  cursor: pointer;
  list-style: none;
  padding-block: var(--sp-2);
}
.fold > summary::-webkit-details-marker {
  display: none;
}
/* 화살표를 직접 그린다 — 기본 마커는 브라우저마다 위치가 달라 제목과 어긋난다. */
.fold > summary::after {
  content: '';
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  margin-left: auto;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: rotate(45deg) translate(-0.15rem, -0.15rem);
  transition: transform var(--motion) ease;
}
.fold[open] > summary::after {
  transform: rotate(225deg) translate(-0.1rem, -0.1rem);
}
.fold > summary > h2 {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: var(--fs-2);
}
/* summary 를 flex 로 두면 h2 와 화살표가 같은 줄에서 양끝으로 선다. */
.fold > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.fold > summary:hover > h2 {
  color: var(--accent);
}
.fold[open] > summary {
  margin-bottom: var(--sp-3);
}
/* 결과 화면 안의 접기 — 제목이 h2 가 아니라 summary 문구 자체다. */
.rs-fold > summary {
  font-size: var(--fs-4);
  font-weight: var(--fw-600);
  color: var(--text-muted);
}
.rs-fold {
  margin-top: var(--sp-3);
}

/* ── 툴 카드 ──────────────────────────────────────────────── */
/* ⚠️ 2026-09-14 (지시 ㉑) — 이 자리의 .tool-grid · .tool-card · .tool-card-title · .tool-card-desc 규칙을 걷어냈다.
   부르는 마크업이 0 이 됐다(홈은 2026-09-13 에 앱 격자로 · 「다른 도구」는 이 회차에 같은 격자로). 🟢 src · public 의 `tool-grid` · `tool-card` 호출부 0. */
/* 🟢 2026-09-04 — .tool-card-meta 를 걷어냈다. 홈 카드의 「입력: …」 부속 줄이 사라졌고
   형식은 카드 «한 문장» 안으로 들어갔다(판정 근거는 playbook.md 「hub-model.md」 절). */

.pill {
  display: inline-block;
  vertical-align: 0.05em;
  margin-left: 0.375rem;
  padding: 0.0625rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
}

.notice {
  margin: 0 0 0.875rem;
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--accent-border);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  color: var(--text-muted);
}

/* ── 홈 — 앱 아이콘 격자 (2026-09-13 · 사용자 지시 ⑰) ─────────────────
   원문: 「카카오톡 줄 바꾸고 대화 분석기 이름느낌으로」 · 「비슷한 툴들끼리 줄로 세우던가 해」 ·
         「가로로 너무 넓게 쓰지마」 · 「아이폰 어플처럼 입체그래픽or젤리 느낌으로」.
   ⚠️ 줄 = group(site.config.mjs TOOLS). 한 줄 네 칸이고, 넓은 화면에서도 격자 폭에 상한(26rem)을 둔다.
   ⚠️ 카드에 설명문이 0줄이다 — 카드끼리 갈리는 것은 아이콘과 이름이다(갈림은 tests/home-faq-probe.mjs 가 화소로 잰다).
   ⚠️ 그림은 src/icons.mjs(모양) · 색은 아래 .app-icon--<slug>(여기 한 곳)다. */
.page-home main h1,
.page-faq main h1 {
  font-size: clamp(28px, 7.4vw, 34px);
  margin: var(--sp-1) 0 var(--sp-5);
}
.apps {
  display: grid;
  gap: var(--sp-5);
  max-width: 26rem;
}
/* ⚠️ 2026-09-13 — 칸을 «아이콘 폭» 네 개로 두고 남는 폭을 칸 사이에 나눈다(space-between). 사용자 피드백
   「아이콘들이랑 무료 온라인 도구 글자가 열이 맞도록 … 위치만 수정」.
   🟢 원인 실측 — 카드 상자(a)의 왼끝은 이미 H1 왼끝과 같았다(차 0). 어긋난 것은 «카드 안에서 가운데로 선 아이콘»이었다:
      (카드 폭 − 아이콘 폭) ÷ 2 = 360px 11.75 · 390px 13.25 · 430px 15.5px. 칸 폭 − 카드 폭의 차(4.5px)는 칸 사이 6px 이지
      가운데 정렬이 아니었다. 그래서 H1 을 옮기지 않고(로고 · 푸터와 같은 왼쪽 기준선) 아이콘 열을 그 기준선에 붙인다.
   ⚠️ 첫 줄 아이콘 왼끝 = H1 왼끝, 마지막 칸 아이콘 오른끝 = 본문 오른끝이다. 이름은 아이폰처럼 아이콘 아래 가운데에 선다(.app-name). */
.app-row {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, var(--icon));
  justify-content: space-between;
  gap: var(--sp-4) 6px;
}
.app > a,
.app-off {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-1) 0;
  border-radius: var(--radius);
  color: var(--text);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
.app > a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.app-icon {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  width: var(--icon);
  height: var(--icon);
  border-radius: var(--icon-radius);
  background: linear-gradient(160deg, var(--t1, #9ca3af), var(--t2, #4b5563));
  color: var(--ic, #fff);
  box-shadow: var(--shadow-app);
  transition: transform 320ms var(--spring);
}
/* 광택 한 겹 — 그림 «위»에 얹지 않고 배경과 그림 사이에 둔다(svg 가 position:relative 로 위에 선다). */
.app-icon::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--gloss);
  pointer-events: none;
}
.app-icon svg {
  position: relative;
  width: 62%;
  height: 62%;
  max-width: none;
}
/* 눌림 — 누르는 순간 줄고, 떼면 --spring 으로 살짝 튕기며 돌아온다(젤리). */
.app > a:active .app-icon {
  transform: scale(0.9);
  transition-duration: 90ms;
  transition-timing-function: ease-out;
}
@media (hover: hover) {
  .app > a:hover .app-icon {
    transform: translateY(-2px) scale(1.03);
  }
}
@media (prefers-reduced-motion: reduce) {
  .app-icon {
    transition: none;
  }
  .app > a:hover .app-icon,
  .app > a:active .app-icon {
    transform: none;
  }
}
/* 이름 두 줄 — 첫 줄은 «무엇의»(카카오톡 · 이미지), 둘째 줄은 «무엇을 하는»(대화 분석기).
   ⚠️ 낱말 중간에서 끊지 않는다 — 본문 기본값(overflow-wrap:anywhere)을 이 칸에서만 끈다. */
/* ⚠️ 2026-09-13 — 카드(a)가 아이콘 폭이 되어 이름 칸을 카드 폭에 묶지 않는다. 이름은 아이콘 + 2rem 까지 서고
   (한 줄 네 칸의 칸 간격보다 좁다 — 옆 이름과 겹치지 않는다 · home-faq-probe B1), 좁은 화면에서는 본문 ÷ 4 에서 멈춘다. */
.app-name {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: max-content;
  max-width: min(calc(var(--icon) + 2rem), calc((100vw - 2 * var(--pad)) / 4));
  text-align: center;
  line-height: 1.22;
  letter-spacing: -0.02em;
  overflow-wrap: normal;
  word-break: keep-all;
}
.app-name-1 {
  font-size: 11px;
  font-weight: var(--fw-500);
  color: var(--text-muted);
}
.app-name-2 {
  font-size: 12px;
  font-weight: var(--fw-600);
  color: var(--text);
}
.app.is-planned .app-icon {
  filter: grayscale(1);
  opacity: 0.55;
}
/* 아이콘 색 — ⚠️ 2026-09-14 에 이 자리의 슬러그별 값(--ia · --ib)을 걷어냈다. 그전에는 카카오톡 셋이 «같은 노랑»이라 말풍선 안 작은 표지로만 갈렸다
   (⑱ 「각각의 블록들이 색상이 동일하니까 직관적으로 어떤거를 사용해야할지 판단하기 어려워」).
   바탕색(--t1 · --t2)의 SSOT 는 파일 끝 [data-tool] 표 한 곳이다. 여기에는 «말풍선 안 표지 색»(--ic)만 남는다. */
.app-icon--kakao-chat {
  --ic: #4c4ae0;
}
.app-icon--kakao-pdf {
  --ic: #d5432c;
}
.app-icon--kakao-excel {
  --ic: #13875a;
}

/* ── /faq/ — 검색 한 칸 + 고정 첫 글 + 묶음 목록 (2026-09-13 · 사용자 지시 ⑰) ──────
   원문: 「자주 묻는 질문 - 따로 페이지 만들어서 … 검색기능 만들어서 알아서 검색해서 찾아보게해」 ·
         「제일 좋은 거는 제거하고 자주 묻는 질문 페이지 고정 첫글로 좋아」.
   ⚠️ 아이폰 «설정» 앱의 묶음 목록 모양이다 — 둥근 한 판 안에 줄이 헤어라인으로 갈린다. */
.faq-search {
  position: relative;
  margin: 0 0 var(--sp-5);
}
.faq-search-icon {
  position: absolute;
  left: 11px;
  top: 50%;
  width: 18px;
  height: 18px;
  margin-top: -9px;
  color: var(--text-faint);
  pointer-events: none;
}
/* ⚠️ 글자 16px 미만 금지 — iOS Safari 는 그보다 작은 입력칸에 초점이 가면 화면을 확대한다
   (overflow-probe 가 «16px 미만 컨트롤»을 센다). */
.faq-search-input {
  display: block;
  width: 100%;
  min-height: var(--touch-min);
  padding: 0 12px 0 38px;
  border: 0;
  border-radius: 10px;
  background: var(--fill);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  line-height: 1.2;
  -webkit-appearance: none;
  appearance: none;
}
.faq-search-input::placeholder {
  color: var(--text-faint);
}
.faq-search-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.faq-search-input::-webkit-search-decoration {
  -webkit-appearance: none;
}
.faq-empty {
  margin: 0 0 var(--sp-5);
  color: var(--text-muted);
  font-size: var(--fs-4);
}
/* 검색이 숨긴 줄 — 줄에 display 를 걸어 두었으므로 hidden 속성이 이기게 이 칸에서만 못박는다. */
.faq-index [data-faq-item][hidden],
.faq-index [data-faq-group][hidden] {
  display: none;
}
.faq-pin {
  margin: 0 0 var(--sp-6);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.faq-pin h2 {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-2);
}
.faq-pin-icon {
  flex: none;
  width: 18px;
  height: 18px;
  margin-top: 4px;
  color: var(--accent);
}
.faq-pin-lede {
  margin: 0 0 var(--sp-3);
  font-weight: var(--fw-500);
}
.faq-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-3);
}
.faq-points li {
  position: relative;
  display: grid;
  gap: 2px;
  padding-left: 30px;
}
/* 확인 표시 — 초록 동그라미 + 꺾인 선. 글자 기호(✓)를 쓰지 않는다 — 글꼴마다 모양이 갈린다. */
.faq-points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ok);
}
.faq-points li::after {
  content: '';
  position: absolute;
  left: 7px;
  top: 7px;
  width: 6px;
  height: 10px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg);
}
.faq-points strong {
  font-weight: var(--fw-600);
}
.faq-points span {
  color: var(--text-muted);
  font-size: var(--fs-4);
  line-height: 1.55;
}
.faq-pin-note {
  margin: var(--sp-3) 0 0;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1.55;
}
.faq-group {
  margin: 0 0 var(--sp-6);
}
.faq-group h2 {
  margin: 0 0 var(--sp-2) var(--sp-4);
  font-size: var(--fs-6);
  font-weight: var(--fw-600);
  letter-spacing: 0;
  color: var(--text-muted);
}
.faq-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.faq-row {
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
}
.faq-row:first-child {
  border-top: 0;
}
.faq-q {
  margin: 0;
  font-size: var(--fs-4);
  font-weight: var(--fw-600);
  line-height: 1.45;
}
.faq-sum,
.faq-a {
  margin: 2px 0 0;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1.55;
}
.faq-go {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-2) 0 0;
}
.faq-tool {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--touch-min);
  padding: 0 14px 0 8px;
  border-radius: 999px;
  background: var(--fill);
  color: var(--text);
  font-size: var(--fs-6);
  font-weight: var(--fw-500);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.faq-tool:active {
  background: var(--border-strong);
}
.faq-tool .app-icon {
  --icon: 26px;
  border-radius: 8px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

/* ── 인식하지 못한 줄 (세 툴 공용) ─────────────────────────── */
/* 결과 «맨 위» 한 줄. 접혀 있다가 펼치면 원문 표본이 나온다.
   실패(.tool-error) 색을 쓰지 않는다 — 나머지 결과는 정상이므로 «주의»지 «실패»가 아니다.
   ⚠️ 이 블록은 화면 전용이다. 인쇄에는 @media print 화이트리스트가 자동으로 뺀다
      (/kakao-pdf의 #unparsed는 .pdf-panel 직속 자식이다). */
/* 상시 형식 제보 — 결과 «하단»의 저강도 진입점.
   ⚠️ .unparsed 와 색을 «일부러» 다르게 둔다. 저쪽은 경고(warn)고 이쪽은 «정상 경로의 되묻기»다.
      미인식 0건에서 뜨므로 경고색을 쓰면 잘 읽힌 파일에도 문제가 있는 것처럼 보인다.
   ⚠️ 결과 카드를 가리거나 밀어내지 않는다 — 흐름 안에 서고 position:fixed 를 쓰지 않는다.
   ⚠️ 인쇄에는 나오지 않는다. /kakao-pdf 의 인쇄 화이트리스트가 .pdf-panel 직속만 남기므로
      이 블록도 #unparsed 와 같은 층에서 자동으로 빠진다. */
.formatcheck {
  margin: 1.25rem 0 0;
  padding: 0.625rem 0.875rem;
  border-top: 1px solid var(--border);
  font-size: 0.875rem;
  color: var(--text-muted);
}
.formatcheck-ask {
  margin: 0;
  line-height: 1.6;
}
.formatcheck-hint {
  display: inline-block;
}
.formatcheck .unparsed-actions {
  margin: 0.5rem 0 0;
}
.formatcheck .unparsed-report {
  margin-top: 0.625rem;
}
.formatcheck .unparsed-ask {
  color: var(--text-muted);
}
@media (max-width: 420px) {
  /* 360px에서 한 줄에 다 못 들어간다 — 힌트를 아랫줄로 내린다.
     inline-block 이라 줄바꿈이 «단어»가 아니라 «구» 단위로 떨어진다. */
  .formatcheck-hint {
    display: block;
  }
  .formatcheck .unparsed-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
  }
}

.unparsed {
  margin: 0 0 1rem;
  padding: 0.625rem 0.875rem;
  border: 1px solid var(--warn-border);
  background: var(--warn-soft);
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  color: var(--warn);
}
.unparsed > summary {
  cursor: pointer;
  font-weight: 600;
}
.unparsed-body {
  margin-top: 0.625rem;
  color: var(--text-muted);
}
.unparsed-body > p {
  margin: 0 0 0.5rem;
}
.unparsed-samples {
  margin: 0 0 0.5rem;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.25rem;
}
.unparsed-samples li {
  /* 원문을 그대로 보여준다 — 줄이 길면 가로로 스크롤한다(자르지 않는다). */
  overflow-x: auto;
  padding: 0.25rem 0.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.unparsed-samples code {
  font-size: 0.8125rem;
  white-space: pre;
  color: var(--text);
}
.unparsed-more,
.unparsed-ask {
  margin: 0 0 0.25rem;
  font-size: 0.875rem;
}
.unparsed-ask code {
  font-size: 0.8125rem;
  padding: 0 2px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 3px;
}
.unparsed-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.625rem 0 0;
}
.unparsed-report {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--warn-border);
}
.unparsed-report-label {
  display: block;
  margin-bottom: 0.375rem;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--text-muted);
}
.unparsed-draft {
  /* 초안은 사용자가 «고쳐서» 보내는 것이 사양이다 — 읽기 전용으로 두지 않는다. */
  width: 100%;
  box-sizing: border-box;
  /* 360px에서 가로로 밀지 않는다 — 긴 줄은 접어서 보여준다(실측은 overflow-probe). */
  max-width: 100%;
  resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  padding: 0.5rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}
.btn-link {
  background: none;
  border: 0;
  padding: 0.375rem 0.25rem;
  text-decoration: underline;
}

/* ── 리스트류 ─────────────────────────────────────────────── */
.reasons,
.steps {
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
}
.reasons {
  list-style: none;
}
.steps {
  padding-left: 1.25rem;
}

.reasons li,
.steps li {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
.reasons li {
  padding: 0.875rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.reasons span,
.steps span {
  color: var(--text-muted);
  font-size: 0.9375rem;
}
/* ⚠️ 여기 있던 `.steps li::marker { color: var(--accent); font-weight: 700 }` 를 걷어냈다
   (2026-08-14). 🟢 실측: 바로 위 `.steps li { display: flex }` 때문에 li 가 list-item 박스가
   아니어서 `::marker` 자체가 생성되지 않는다 — `.steps`·`.steps.numbered` 양쪽 다 죽어 있었다.
   **«걸어 뒀는데 안 먹는 규칙»을 남기지 않는다** — 남기면 다음 사람이 «번호는 스타일돼 있다»고
   읽고 원인을 다른 곳에서 찾는다. 번호가 필요한 목록은 `.steps.numbered` 의 배지로 그린다.
   ⚠️ 홈 `/` 의 「쓰는 순서」 는 2026-08-15 에 `<ol class="steps numbered">` 로 바꿨다 —
   «번호가 필요한» 목록이라 배지로 그린다. 지금 `.steps` 단독은 쓰는 자리가 없다. */

.bullets {
  margin: 0;
  padding-left: 1.25rem;
  color: var(--text-muted);
}
.bullets li {
  margin-bottom: 0.25rem;
}

/* ── FAQ ──────────────────────────────────────────────────── */
.faq {
  margin: 0;
}
.faq dt {
  font-weight: 700;
  margin-top: 1.125rem;
}
.faq dt:first-child {
  margin-top: 0;
}
.faq dd {
  margin: 0.25rem 0 0;
  color: var(--text-muted);
}

/* ── 표 ───────────────────────────────────────────────────── */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}
.data-table th,
.data-table td {
  padding: 0.625rem 0.875rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.data-table tr:last-child th,
.data-table tr:last-child td {
  border-bottom: 0;
}
/* 표 헤더 — 회색 배경을 걷어내고 «하단 1px 경계»만 남긴다. */
.data-table th {
  color: var(--text-muted);
  font-weight: var(--fw-600);
  font-size: var(--fs-6);
  background: transparent;
  border-bottom: 1px solid var(--border-strong);
  /* 라벨 열이 과도하게 눌리면 한글이 단어 중간에서 끊긴다("통신판매/업/신고번호").
     최소 폭을 줘서 띄어쓰기 지점에서만 줄바꿈되게 한다. 360px에서도 넘침 없음(실측). */
  min-width: 8rem;
}

/* 라틴 고유명사는 단어 중간에서 끊지 않는다("Cloudflar/e, Inc." 방지).
   본문 기본값이 overflow-wrap:anywhere라 이 클래스로만 예외를 준다. */
.nobreak-word {
  overflow-wrap: normal;
}

/* ── 광고 슬롯 (활성화 시 CLS 방지용 예약 높이) ───────────── */
.ad-slot {
  display: block;
  margin: 2.5rem 0 0;
  min-height: 100px;
}

/* ── 크로스링크 ───────────────────────────────────────────── */
.crosslinks {
  margin-top: 2.5rem;
}
.crosslinks h2 {
  font-size: 1.15rem;
  margin: 0 0 0.75rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

/* ── 푸터 ─────────────────────────────────────────────────── */
.site-footer {
  margin-top: 3rem;
  border-top: 1px solid var(--border);
  background: var(--bg-soft);
  /* 아래 여백에 홈 막대(안전영역)를 더한다 — 헤드리스에서는 0 이라 전과 같다. */
  padding-block: 1.75rem calc(2.25rem + var(--safe-b));
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* ⚠️ 2026-09-13 — .footer-badge 를 걷어냈다(지시 ⑰). 같은 사실은 /faq/ 고정 첫 글이 적는다. */

.biz-title {
  margin: 0 0 0.5rem;
  font-weight: 700;
  color: var(--text);
}

.biz-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.25rem;
}

@media (min-width: 40rem) {
  .biz-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.25rem 1.5rem;
  }
}

.biz-list li {
  display: flex;
  gap: 0.5rem;
}
.biz-list li > span:first-child {
  flex: none;
  min-width: 7.5rem;
  color: var(--text-muted);
  opacity: 0.85;
}
.biz-list li > span:last-child {
  color: var(--text);
  min-width: 0;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.footer-nav a {
  color: var(--text-muted);
  text-decoration: none;
}
.footer-nav a:hover {
  color: var(--accent);
  text-decoration: underline;
}
/* 현재 페이지 항목 — 링크가 «아니다»(자기 링크 0). 그래서 색만 죽이고 밑줄도 호버도 없다.
   ⚠️ 2026-09-12 — 이 규칙이 없으면 그 항목만 본문 색으로 튀어 «눌러야 하는 것»처럼 보인다. */
.footer-nav .footer-self {
  color: var(--text-faint);
  cursor: default;
}

.copyright {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
}

/* ── 문서형 페이지 ────────────────────────────────────────── */
.page-doc main p {
  margin: 0 0 0.75rem;
}
.page-doc .section {
  margin-top: 2rem;
}

/* ── 도구 페이지 (/kakao-chat) ───────────────────────────────
   차트는 인라인 SVG라 별도 라이브러리 스타일이 없다.
   기준선은 여전히 360px 가로 넘침 0 — 표와 차트는 각자 스크롤 컨테이너를 갖는다. */

.dropzone {
  /* ⚠️ 여기만 --dropzone-border 를 쓴다. 정의부의 사유 주석이 SSOT 다. */
  border: 1.5px dashed var(--dropzone-border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  transition: border-color var(--motion) ease, background var(--motion) ease;
}
.dropzone:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
.dropzone.is-over {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.dropzone.is-busy {
  opacity: 0.7;
}
.drop-main {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-3);
  font-weight: var(--fw-600);
}
.drop-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  justify-content: center;
}
.drop-sub {
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-6);
  color: var(--text-faint);
}

/* 버튼 — 터치 타겟 하한 48px. 보조는 «흰 배경 + 1px 경계», 주는 «잉크 블랙». */
.btn {
  font: inherit;
  font-size: var(--fs-4);
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-body);
  padding: 0 var(--sp-5);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  cursor: pointer;
  min-height: var(--touch);
  transition: border-color var(--motion) ease, background var(--motion) ease,
    opacity var(--motion) ease;
}
.btn:hover:not(:disabled) {
  border-color: var(--text-faint);
}
.btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.btn-primary {
  background: var(--btn-primary-bg);
  border-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}
.btn-primary:hover:not(:disabled) {
  border-color: var(--btn-primary-bg);
  opacity: 0.86;
}

.tool-status {
  margin: 0.9rem 0 0;
  font-size: 0.92rem;
  color: var(--text-muted);
}
.progress {
  margin-top: 0.5rem;
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.progress > i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 0.15s linear;
}

.tool-error {
  margin-top: 1rem;
  border: 1px solid var(--accent-border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  padding: 0.9rem 1rem;
}
.tool-error h3 {
  margin: 0 0 0.4rem;
  font-size: 1.02rem;
}
.tool-error p {
  margin: 0.35rem 0 0;
}
.tool-error .err-code {
  font-size: 0.8rem;
  color: var(--text-muted);
}
/* 페이지 언어를 못 읽은 도구의 한 줄 안내(2026-09-17 · ⑳ 본 회차 S1) — H1 바로 아래에 런타임이 세운다.
   실패가 아니다 — 도구는 영어 칸으로 돈다. 그래서 실패(.tool-error) 색을 쓰지 않는다. */
.lang-note {
  margin: 0 0 var(--sp-3);
  font-size: 0.8rem;
  color: var(--text-muted);
}

.tool-result {
  margin-top: 1.25rem;
}
.detect {
  border: 1px solid var(--ok-border);
  background: var(--ok-soft);
  border-radius: var(--radius-sm);
  padding: 0.7rem 0.9rem;
  font-size: 0.95rem;
}
.detect strong {
  color: var(--ok);
}
.detect-meta {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.82rem;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

/* 핵심 숫자 타일 — 360px에서 2열, 넓으면 3열 이상 */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
.stat-row.small {
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
}

/* 크기 위계 — «앞 3개»를 크게, 나머지를 작게.
   ⚠️ DOM 순서를 건드리지 않고 순전히 CSS로만 만든다. 6열 그리드에서 타일마다 2열씩
      차지하게 하면 앞 3개가 1행, 나머지가 2행에 서고 «순서는 그대로»다.
   ⚠️ 좁은 화면에서는 걸지 않는다 — 2열에서 앞 3개만 키우면 줄이 어긋나 보인다. */
@media (min-width: 40rem) {
  .stat-row {
    grid-template-columns: repeat(6, 1fr);
  }
  .stat-row > .stat {
    grid-column: span 2;
  }
  .stat-row > .stat:nth-child(-n + 3) .stat-value {
    font-size: var(--fs-1);
    line-height: 1.15;
  }
}
/* 지표 카드 — 테두리를 빼고 «배경만» 남긴다. 층은 배경 대비로만 만든다. */
/* ⚠️ 카드 높이를 «내용»이 정하게 두면 2열에서 들쭉날쭉해진다 — 보조 줄이 있는 카드와
   없는 카드가 섞이기 때문이다. 내용은 그대로 두고 «정렬»만 맞춘다:
   그리드가 행 높이를 맞추고(stretch 기본), 카드 안에서 라벨을 위·값을 아래로 민다. */
.stat {
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--sp-3) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  height: 100%;
}
.stat > .stat-value {
  margin-top: auto;
}
.stat-label {
  font-size: var(--fs-6);
  color: var(--text-muted);
}
.stat-value {
  font-size: var(--fs-2);
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-title);
  font-variant-numeric: tabular-nums;
}
/* 단위·보조 글자는 «내린다» — 숫자가 먼저 읽히게 하는 것이 이 카드의 일이다. */
.stat-sub {
  font-size: var(--fs-5);
  color: var(--text-faint);
}

.rs {
  margin-top: 1.6rem;
}
.rs h3 {
  margin: 0 0 0.5rem;
  font-size: 1.05rem;
}
.rs-note {
  margin: 0.5rem 0 0;
  font-size: 0.84rem;
  color: var(--text-muted);
}

/* 참여자 비율 바 — 높이 8px · «양끝만» 라운드.
   ⚠️ 세그먼트 사이 2px 간격은 «걸지 못했다»(2026-08-13 정정). 이 바는 div가 아니라
      SVG(viewBox 0 0 100 12)이고 세그먼트는 x가 맞붙은 <rect>다 — CSS border·gap·margin은
      SVG rect에 렌더되지 않으므로 간격을 CSS로 만들 방법이 없다. 넣으려면 JS가 rect 폭에서
      간격을 빼야 하는데 그건 결과 화면의 «그리는 계산»이라 이 회차 범위 밖이다.
      ⚠️ 「걸어 뒀는데 안 먹는 규칙」을 남기지 않는다 — 다음 세션이 «되어 있다»로 읽는다.
   height 8px 는 먹는다(preserveAspectRatio="none" 이라 viewBox가 눌린다).
   border-radius + overflow:hidden 도 SVG 요소 «자신»에 걸리므로 양끝 라운드는 성립한다. */
.sharebar {
  display: block;
  width: 100%;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  margin: var(--sp-2) 0 var(--sp-3);
  background: var(--border);
}
.legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  font-size: 0.88rem;
}
.legend b {
  font-variant-numeric: tabular-nums;
}
.dot {
  display: inline-block;
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  margin-right: 0.35rem;
  vertical-align: baseline;
}

/* ── 참여자 램프 클래스 ───────────────────────────────────────
   ⚠️ `fill` 과 `background` 를 «둘 다» 건다 — 같은 램프가 SVG <rect>(비율 바)와
      HTML <span>(범례 점) 양쪽에서 쓰이고, 두 요소는 색을 받는 속성이 다르다.
      한쪽만 걸면 한쪽만 칠해지는데 그건 화면에서 «색이 갈린 것»으로만 보인다.
   ⚠️ 이 클래스가 생긴 이유는 «값의 SSOT를 여기 한 곳으로 모으기» 위해서다 —
      전에는 kakao-chat.js 가 색값 사본을 들고 인라인으로 칠해서, 다크 토큰을 바꿔도
      범례·막대만 라이트 값 그대로 나왔다(2026-08-13 실측). 인라인 색 지정으로 되돌리지 마라. */
.p1 {
  fill: var(--p1);
  background: var(--p1);
}
.p2 {
  fill: var(--p2);
  background: var(--p2);
}
.p3 {
  fill: var(--p3);
  background: var(--p3);
}
.p4 {
  fill: var(--p4);
  background: var(--p4);
}
.p5 {
  fill: var(--p5);
  background: var(--p5);
}
.p6 {
  fill: var(--p6);
  background: var(--p6);
}

.rank-table {
  font-variant-numeric: tabular-nums;
}
/* 8열이라 nowrap을 걸면 데스크톱에서도 마지막 열이 잘린다(🟢 CDP 검수에서 검출).
   숫자 셀만 붙여 쓰고 나머지는 줄바꿈을 허용한다. */
.rank-table td,
.rank-table th {
  white-space: normal;
}
/* 숫자 열은 «우측 정렬 + tabular-nums». 자릿수가 세로로 맞아야 비교가 된다. */
.rank-table .num,
.data-table .num {
  white-space: nowrap;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ⚠️ 헤더에는 .num 이 붙어 있지 않다 — 값만 오른쪽으로 가면 «머리와 몸이 어긋난» 표가 된다.
   순위 표는 6열 고정(순위·참여자·메시지·글자 수·평균 답장·먼저 시작)이므로 열 번호로 잡는다.
   ⚠️ 마크업에 클래스를 새로 붙이지 않는다 — 이 회차는 CSS 층만 바꾼다.
   앞 2열(순위·참여자)은 왼쪽에 둔다. 순위는 한 자리라 오른쪽으로 밀면 참여자에게서 멀어진다. */
.rank-table th:nth-child(-n + 2),
.rank-table td:nth-child(-n + 2) {
  text-align: left;
}
.rank-table th:nth-child(n + 3),
.rank-table td:nth-child(n + 3) {
  text-align: right;
}
.rank-table small {
  display: block;
  font-size: 0.78rem;
  color: var(--text-muted);
}
.rank-table th,
.rank-table td {
  font-size: 0.86rem;
}

.chart {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 0.4rem;
}
.cx-axis {
  stroke: var(--border-strong);
  stroke-width: 1;
}

/* ── 막대 차트의 최댓값 강조 ──────────────────────────────────
   ⚠️ 강조를 «다른 색»으로 하지 않는다. 같은 화면에 참여자 램프가 서 있어서
      램프 3번(--p3)으로 강조하면 그 색이 «최댓값»과 «세 번째 참여자» 두 뜻을 갖는다.
      한 색이 두 뜻을 가지면 범례가 거짓말을 한다 — 그래서 강조는 «농도»로만 한다.
   ⚠️ 새 색 토큰을 늘리지 않는다. 옅은 단계는 --p1 을 배경색과 섞어 만든다.
      color-mix 미지원 브라우저에서는 앞의 fill 이 그대로 남고 opacity 가 같은 일을 한다
      (두 줄이 «중복»이 아니라 «폴백»이다 — 지원 브라우저는 opacity 1 로 덮어쓴다). */
.chart .bar {
  fill: var(--p1);
  opacity: 0.5;
}
.chart .bar-max {
  fill: var(--p1);
  opacity: 1;
}
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .chart .bar {
    fill: color-mix(in srgb, var(--p1) 45%, var(--bg));
    opacity: 1;
  }
}
.cx-lbl {
  font-size: 11px;
  fill: var(--text-muted);
  font-family: var(--font);
}
/* 월별 꺾은선 — 선·점 모두 램프 1번(--p1). 값은 여기 한 곳이고 JS에 사본이 없다. */
.cx-line {
  stroke: var(--p1);
  stroke-width: 2;
}
/* 부분 집계 구간은 «점선»으로만 구분한다 — 색을 바꾸지 않는다(같은 계열의 같은 뜻이다). */
.cx-line-part {
  stroke-dasharray: 5 4;
}
.cx-dot {
  fill: var(--p1);
}
/* 부분 집계 월의 꼭짓점 — 속을 배경색으로 비워 «채운 점»과 구분한다. */
.cx-dot-part {
  fill: var(--bg);
  stroke: var(--p1);
  stroke-width: 2;
}

.wordlist {
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.3rem;
}
.wordlist li {
  display: grid;
  grid-template-columns: minmax(4.5rem, 8rem) 1fr auto;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
}
.wordlist .w {
  overflow-wrap: anywhere;
}
/* ⚠️ .wbar 는 «단어 빈도» 바다 — 참여자 비율 바는 위 .sharebar 이고 둘은 다른 것이다.
   높이 8px·양끝 라운드는 두 바에 같은 값으로 맞춰 리듬을 하나로 둔다. */
.wordlist .wbar {
  display: block;
  height: 8px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.wordlist .wbar > i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--p1);
}
.wordlist .wn {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  font-size: 0.84rem;
}

.quality summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.95rem;
}
.quality[open] summary {
  margin-bottom: 0.5rem;
}

/* 내보내기 가이드 탭 */
.guide-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.8rem;
}
.guide-tab {
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.5rem 0.9rem;
  /* 터치 타깃 하한 44px — 1단계 디자인 시스템의 값이다. */
  min-height: 2.75rem;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
}
/* 선택된 탭은 «채운 알약»이다 — 연한 배경은 400px에서 선택 여부가 잘 안 갈렸다.
   색은 토큰만 쓴다(다크는 --btn-primary-* 가 이미 반전돼 있다). */
.guide-tab[aria-selected='true'] {
  background: var(--btn-primary-bg);
  border-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}

/* 절차 목록 — 번호 배지 + 세로 연결선.
   ⚠️ 왜 ::marker 가 아니라 ::before 인가: `.steps li` 가 `display: flex` 라
   li 가 list-item 박스가 아니게 되어 «::marker 자체가 생성되지 않는다».
   🟢 2026-08-14 실측: 3툴 전부 li display=flex · list-item 아님 · 번호 안 뜸
   (list-style-type 은 decimal 로 «설정»돼 있었다 — 설정과 렌더는 다르다).
   구조와 문장은 한 글자도 바꾸지 않고 CSS로만 세운다. */
.steps.numbered {
  counter-reset: step;
  padding-left: 0;
  /* 연결선이 항목 사이에서 끊기지 않도록 gap 을 li 의 padding-bottom 으로 옮긴다. */
  gap: 0;
}
.steps.numbered li {
  counter-increment: step;
  position: relative;
  padding-left: 2.25rem;
  padding-bottom: 0.75rem;
}
.steps.numbered li:last-child {
  padding-bottom: 0;
}
.steps.numbered li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  font-size: 13px;
  font-weight: 600;
  line-height: 24px;
  text-align: center;
}
/* 배지 아래에서 다음 배지 위까지. gap 0 이므로 bottom: 0 이 곧 다음 배지의 top 이다. */
.steps.numbered li::after {
  content: '';
  position: absolute;
  left: 11.25px;
  top: 26px;
  bottom: 0;
  width: 1.5px;
  background: var(--border-strong);
}
.steps.numbered li:last-child::after {
  content: none;
}

@media (max-width: 26rem) {
  .rank-table th,
  .rank-table td {
    font-size: 0.8rem;
    padding-left: 0.45rem;
    padding-right: 0.45rem;
  }
  .stat-value {
    font-size: 1.1rem;
  }
}

/* ── PDF 변환기 (/kakao-pdf) ─────────────────────────────────
   화면용 미리보기와 인쇄용 레이아웃을 같은 DOM으로 쓴다.
   페이지 번호는 JS가 .sheet 단위로 직접 넣는다 — Chrome은 CSS 페이지 마진 박스를
   지원하지 않아 @bottom-center counter(page)가 동작하지 않기 때문이다. */

.pdf-panel {
  margin-top: 1.25rem;
}
.filters {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  padding: 0.9rem 1rem;
}
.filters h3 {
  margin: 0 0 0.7rem;
  font-size: 1rem;
}
.filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: flex-end;
  margin-bottom: 0.7rem;
}
.filter-actions {
  align-items: center;
  margin-bottom: 0;
}
.fld {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.fld.grow {
  flex: 1 1 12rem;
  min-width: 0;
}
.fld input[type='date'],
.fld input[type='text'] {
  font: inherit;
  font-size: 0.95rem;
  padding: 0.5rem 0.6rem;
  min-height: 2.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  max-width: 100%;
}
.chk-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.25rem;
}
.chk {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.9rem;
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 0.35rem 0.7rem;
  min-height: 2.25rem;
  background: var(--surface);
  cursor: pointer;
}
.chk small {
  color: var(--text-muted);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}
.count-wrap {
  font-size: 0.9rem;
  color: var(--text-muted);
}
.count-wrap b {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.count-wrap b.over {
  color: #c2410c;
}
.print-howto {
  margin: 0.8rem 0 0;
  padding: 0.6rem 0.8rem;
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
}

/* 측정용 컨테이너 — 화면에 보이지 않지만 레이아웃은 실제로 일어나야 한다.
   display:none이면 offsetTop이 0이 되어 페이지 계산이 무너진다.

   ⚠️⚠️ 아래 «인쇄 지표» 블록은 @media print의 .sheet 블록과 **반드시 같아야 한다.**
   측정은 여기서 하고 출력은 거기서 나므로, 둘이 다르면 쪽 계산이 어긋나
   문서에 찍힌 페이지 번호가 거짓이 된다. 한쪽을 고치면 반드시 다른 쪽도 고쳐라.
   (화면 미리보기는 의도적으로 카드 모양을 유지한다 — 측정·인쇄와는 별개다.) */
.measure {
  position: absolute;
  left: -10000px;
  top: 0;
  width: 180mm;
  visibility: hidden;
  pointer-events: none;
}
/* ── 인쇄 지표 (measure 쪽) — @media print .sheet 와 동기 ── */
.measure {
  font-size: 9.2pt;
  line-height: 1.34;
}
.measure .k-msg {
  background: none;
  border: 0;
  border-radius: 0;
  max-width: none;
  margin: 0 0 0.7mm;
  padding: 0;
}
.measure .k-meta {
  display: inline;
  margin: 0;
  font-size: 8.2pt;
}
.measure .k-who::after {
  content: ' ';
}
.measure .k-time::after {
  content: '  ';
}
.measure .k-body {
  display: inline;
  white-space: pre-wrap;
}
.measure .k-day {
  margin: 2.4mm 0 1.2mm;
  padding: 0.6mm 0;
  font-size: 8.6pt;
}

.doc-wrap {
  margin-top: 1rem;
  overflow-x: auto;
}
.doc {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  align-items: flex-start;
}
.sheet {
  width: 210mm;
  min-height: 297mm;
  padding: 15mm;
  background: #fff;
  color: #111;
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  font-size: 10pt;
  line-height: 1.5;
}
.sheet-body {
  flex: 1 1 auto;
}
.sheet-foot {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 8mm;
  padding-top: 2mm;
  border-top: 0.5pt solid #bbb;
  font-size: 8pt;
  color: #555;
  font-variant-numeric: tabular-nums;
}
.sheet-foot span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 70%;
}

.k-day {
  margin: 4mm 0 2mm;
  padding: 1.2mm 0;
  border-top: 0.5pt solid #ccc;
  border-bottom: 0.5pt solid #ccc;
  text-align: center;
  font-size: 9pt;
  font-weight: 700;
  color: #333;
}
.k-day-cont {
  margin-top: 0;
  color: #666;
  font-weight: 600;
}
.k-day-cont span {
  font-weight: 400;
  font-size: 8pt;
}
.k-msg {
  margin: 0 0 2.2mm;
  padding: 1.4mm 2mm;
  border-radius: 2mm;
  max-width: 82%;
  break-inside: avoid;
  page-break-inside: avoid;
}
.k-msg.k-a {
  background: #f1f4fa;
  margin-right: auto;
}
.k-msg.k-b {
  background: #fdf3e8;
  margin-left: auto;
}
.k-meta {
  display: flex;
  gap: 2mm;
  align-items: baseline;
  font-size: 8pt;
  margin-bottom: 0.6mm;
}
.k-who {
  font-weight: 700;
  color: #1f2937;
}
.k-time {
  color: #6b7280;
  font-variant-numeric: tabular-nums;
}
/* 원문 무변형의 렌더 쪽 조건 — 줄바꿈·연속 공백·들여쓰기를 모두 보존한다. */
.k-body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: normal;
}
/* 검색어 하이라이트 — «화면 전용»이다. 인쇄에서는 아래 @media print가 무력화한다.
   ⚠️ <mark>는 요소만 끼우므로 textContent는 변하지 않는다(원문 무변형 유지). */
.k-body mark {
  background: rgb(255, 237, 160);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}
.k-s0 .k-who { color: #1d4ed8; }
.k-s1 .k-who { color: #c2410c; }
.k-s2 .k-who { color: #0f766e; }
.k-s3 .k-who { color: #6d28d9; }
.k-s4 .k-who { color: #a16207; }
.k-s5 .k-who { color: #be123c; }

.cover .sheet-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.cover-title {
  font-size: 20pt;
  margin: 0 0 10mm;
  text-align: center;
}
.cover-dl {
  display: grid;
  grid-template-columns: 30mm 1fr;
  gap: 2.5mm 4mm;
  margin: 0;
  font-size: 10pt;
}
.cover-dl dt {
  color: #555;
}
.cover-dl dd {
  margin: 0;
  overflow-wrap: anywhere;
}
.cover-dl dd.cover-hash {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 8.5pt;
  letter-spacing: 0.02em;
}
.cover-note {
  margin-top: 12mm;
  font-size: 8.5pt;
  color: #666;
  text-align: center;
}
/* 증거 표기 문단 — 표지 안에서 «사실 진술»로 읽히도록 좌측 정렬하고 위 여백을 줄인다.
   .cover-note와 나란히 서므로 12mm를 또 주면 표지가 밀린다. */
.cover-evidence {
  margin-top: 6mm;
  padding-top: 3mm;
  border-top: 0.3mm solid #ddd;
  font-size: 8.5pt;
  line-height: 1.6;
  color: #444;
}

/* 화면이 좁으면 A4 시트를 축소해 가로 넘침을 막는다(인쇄에는 영향 없음). */
@media (max-width: 60rem) {
  .doc {
    align-items: stretch;
  }
  .sheet {
    width: 100%;
    min-height: 0;
    padding: 6mm;
    font-size: 9pt;
  }
  .cover-dl {
    grid-template-columns: 24mm 1fr;
  }
}

/* ── 인쇄 ──────────────────────────────────────────────────── */
@page {
  size: A4 portrait;
  margin: 15mm;
}
@media print {
  /* 화이트리스트 방식 — 인쇄에는 «문서(.doc)»만 남긴다.
     블랙리스트로 개별 요소를 숨기면 .lede처럼 섹션 밖에 있는 요소를 놓치고,
     그게 첫 쪽을 먹어 페이지 번호 총계가 어긋난다(🟢 26시트 vs 27쪽으로 검출).
     새 요소를 페이지에 추가해도 인쇄에는 자동으로 안 나오는 쪽이 안전하다. */
  .site-header,
  .site-footer,
  .skip {
    display: none !important;
  }
  main > .wrap > * {
    display: none !important;
  }
  main > .wrap > .section.tool {
    display: block !important;
  }
  .section.tool > * {
    display: none !important;
  }
  .section.tool > .pdf-panel {
    display: block !important;
  }
  .pdf-panel > * {
    display: none !important;
  }
  .pdf-panel > .doc-wrap {
    display: block !important;
  }

  html,
  body {
    background: #fff;
  }
  body,
  main,
  .wrap,
  .section.tool,
  .pdf-panel,
  .doc-wrap,
  .doc {
    margin: 0 !important;
    padding: 0 !important;
    max-width: none !important;
    overflow: visible !important;
  }
  .doc {
    display: block !important;
  }
  .sheet {
    width: auto;
    padding: 0;
    border: 0;
    box-shadow: none;
    break-after: page;
    page-break-after: always;
    display: flex;
    flex-direction: column;
    /* @page margin이 이미 15mm를 잡으므로 시트 안쪽 여백은 0이다.
       인쇄 가능 높이(267mm)와 같은 값을 주면 반올림으로 흘러넘치므로 여유를 둔다. */
    min-height: 262mm;
    font-size: 10pt;
  }
  /* 마지막 시트 뒤에 강제 개행을 남기면 빈 쪽 1장이 더 생긴다. */
  .sheet:last-child,
  .sheet:last-of-type {
    break-after: auto !important;
    page-break-after: auto !important;
  }
  /* ── 인쇄 밀도 ──────────────────────────────────────────────
     화면용 «말풍선 카드»를 인쇄에 그대로 들고 가면 종이가 배로 든다.
     🟢 실물 5,224건이 1,842쪽(2.84건/쪽)이었고 같은 파일을 경쟁 서비스는 939쪽에 담는다.
     인쇄에서는 카드를 걷어내고 «한 줄 기록»으로 바꾼다 — 배경·테두리·라운드를 없애고
     발신자·시각·본문 첫 줄을 같은 줄에서 시작시킨다.
     ⚠️ 이건 레이아웃이지 문자열이 아니다. 원문 무변형(3자 동일성)과 무관하다.
     화면 표시는 카드 그대로 둔다. */
  .sheet {
    font-size: 9.2pt;
    line-height: 1.34;
  }
  .k-msg,
  .k-msg.k-a,
  .k-msg.k-b {
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    max-width: none !important;
    margin: 0 0 0.7mm !important;
    padding: 0 !important;
  }
  /* 발신자·시각을 본문과 같은 줄에 흘린다. 블록으로 두면 메시지마다 한 줄이 더 든다. */
  .k-meta {
    display: inline !important;
    margin: 0 !important;
    font-size: 8.2pt;
  }
  .k-who {
    font-weight: 700;
  }
  .k-who::after {
    content: ' ';
  }
  .k-time::after {
    content: '  ';
  }
  .k-body {
    display: inline !important;
    white-space: pre-wrap;
  }
  /* 검색어 하이라이트는 «화면 전용»이다 — 종이·PDF에는 나오지 않는다.
     ⚠️ 요소를 지우지 않고 «표시»만 지운다: <mark>를 없애면 textContent를 건드리게 되고
     그러면 원문 무변형 대조가 흔들린다. 글자는 그대로 두고 배경·강조만 무력화한다. */
  .k-body mark {
    background: none !important;
    background-color: transparent !important;
    color: inherit !important;
    border-radius: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
    font-weight: inherit !important;
  }
  .k-day {
    margin: 2.4mm 0 1.2mm !important;
    padding: 0.6mm 0 !important;
    font-size: 8.6pt;
  }
  .k-day-cont {
    margin-top: 0 !important;
  }
}

/* ── 엑셀(CSV) 변환기 ─────────────────────────────────────── */
/* 잘림·상한 초과 안내. 실패(.tool-error)와 색을 구분한다 —
   여기서는 파일이 «정상적으로 나온다». 오류 색을 쓰면 실패로 오해된다. */
.notice-warn {
  border-color: var(--warn-border);
  background: var(--warn-soft);
  color: var(--warn);
}
.notice-warn strong {
  color: var(--warn);
}

.csv-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}
.csv-actions .btn {
  flex: 0 1 auto;
}

/* 6열 미리보기. .table-wrap이 가로 스크롤을 갖고 있으므로 여기서는
   셀이 «찌그러지지 않게» 최소 폭만 준다. 표를 페이지 폭에 억지로 맞추면
   내용 열이 한 글자씩 접혀 읽을 수 없게 된다. */
.csv-table {
  min-width: 44rem;
  font-variant-numeric: tabular-nums;
}
.csv-table th,
.csv-table td {
  font-size: 0.84rem;
  white-space: nowrap;
}
.csv-table .csv-text {
  white-space: normal;
  min-width: 18rem;
  overflow-wrap: anywhere;
}
.csv-table tbody tr:nth-child(even) {
  background: var(--bg-soft);
}

@media (max-width: 30rem) {
  .csv-actions .btn {
    flex: 1 1 100%;
  }
  .csv-table {
    min-width: 38rem;
  }
  .csv-table .csv-text {
    min-width: 14rem;
  }
}

/* ── /image-compress 전용 소량 추가 (2026-08-20) ─────────────────────────
   ⚠️ 새 디자인이 아니다. 기존 토큰(--sp-*, --fs-*, --border, --radius-*, --touch)만 쓰고
   색·타이포·간격 스케일을 새로 만들지 않는다. 여기 있는 것은 이 페이지에만 있는
   «배치» 세 가지(컨트롤 줄 · 결과 목록 행 · 작은 버튼)뿐이다. */
/* 🟢 2026-08-21 실기기 결함 — 360px 에서 「저장 형식」 라벨이 «세로로 한 글자씩» 쪼개지고
   셀렉트가 화면 오른쪽으로 이탈했다. 원인은 라벨과 컨트롤을 «한 줄»에 둔 것이다:
   select 의 최소 폭은 가장 긴 option 이 정하는데 그 폭이 줄지 않으니 라벨 쪽이 0 에 가깝게
   눌렸다. ⚠️ 폰트를 줄여 우겨넣지 않는다 — 좁은 폭에서는 라벨을 «위»로 올린다. */
.img-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin-top: var(--sp-4);
}
.img-controls .ctl {
  display: flex;
  /* 라벨이 위, 컨트롤이 아래. 한 줄에 욱여넣지 않으므로 좁은 폭에서 눌릴 자리가 없다. */
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  font-size: var(--fs-4);
  color: var(--text-muted);
  /* min-width:0 이 없으면 flex 자식이 콘텐츠 최소 폭 아래로 못 줄어 컨테이너를 넘는다. */
  flex: 1 1 14rem;
  min-width: 0;
}
/* ⚠️ [hidden] 은 UA 스타일이라 위의 display:flex 가 이긴다 —
   그래서 「목표 용량」 칸이 프리셋과 무관하게 상시 노출됐다(2026-08-21 실기기 결함).
   author 규칙으로 다시 눌러야 hidden 이 실제로 숨긴다. */
.img-controls .ctl[hidden] {
  display: none;
}
.img-controls .ctl-line {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}
.img-controls .ctl-line > input {
  flex: 1 1 auto;
  min-width: 0;
}
/* 🟢 2026-08-21 실측: range 옆의 출력값 「80%」이 2줄로 쪼개졌다(줄당 1.5자).
   suffix 는 줄지 않아야 한다 — 줄어드는 쪽은 range 이고 이쪽은 제 폭을 지킨다. */
.img-controls .ctl-line > output,
.img-controls .ctl-line > span {
  flex: 0 0 auto;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.img-controls .ctl select,
.img-controls .ctl input {
  font: inherit;
  min-height: var(--touch);
  /* 컨테이너 밖으로 나가지 않게 폭을 묶는다. box-sizing 이 없으면 패딩만큼 또 넘친다. */
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}
.img-controls .ctl select {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text);
  padding: 0 var(--sp-3);
}
.img-controls .ctl input[type='number'] {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text);
  padding: 0 var(--sp-3);
}
/* 체크박스 한 칸 — .img-controls .ctl input 의 width:100% 가 체크박스까지 늘여
   버리므로 그 자리만 되돌린다. 새 배치를 만드는 것이 아니라 상속을 끊는 한 줄이다.
   (2026-08-21 (7차) — /image-resize 의 「비율 잠금」) */
.img-controls .ctl-check .ctl-line > input[type='checkbox'] {
  flex: 0 0 auto;
  width: 1.15rem;
  min-height: 1.15rem;
  height: 1.15rem;
  accent-color: var(--accent);
}
/* 체크박스 옆 설명은 한 줄 문장이라 줄어들 쪽이 이쪽이다 — nowrap 을 걸지 않는다. */
.img-controls .ctl-check .ctl-line > span {
  flex: 1 1 auto;
  white-space: normal;
}
.img-controls .ctl-check {
  justify-content: center;
}
.meta-note {
  margin-top: var(--sp-3);
}
.img-list {
  list-style: none;
  margin: var(--sp-4) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.img-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.img-row .img-name {
  font-weight: var(--fw-600);
  word-break: break-all;
  flex: 1 1 12rem;
}
.img-row .img-meta {
  font-size: var(--fs-5);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.img-row.is-fail .img-meta {
  color: var(--danger, var(--text-muted));
}
.btn-small {
  min-height: auto;
  padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-5);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

/* ── 결과 행 썸네일 · 큰 화면 비교 (2026-08-21) ─────────────────────────
   🟢 사용자 지시: 「어떤 사진을 넣었는지 보여주고 변환된 사진도 어떻게 변환되었는지
   보여주는 갤러리 형식」. 결과 목록이 이름과 숫자뿐이라 «내가 받는 게 어느 사진인지»가
   화면에 없었다.
   ⚠️ 새 디자인 언어를 만들지 않는다 — 여기 있는 값은 전부 기존 토큰(--sp-* · --fs-* ·
      --radius-* · --border · --bg-soft · --text-muted · --touch)이고 새 색·새 스케일이 없다.
   ⚠️ 썸네일 상자는 «고정 크기»다 — 그림이 늦게 붙어도 행 높이가 흔들리지 않는다. */
.img-thumbs {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 0 0 auto;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.img-thumbs:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.img-thumb-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
}
.img-thumb {
  display: block;
  width: 52px;
  height: 52px;
  object-fit: cover;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
}
.img-thumb.is-missing {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: var(--fs-4);
}
/* 캡션은 «원본»·«결과» 두 글자다 — 줄바꿈이 걸리면 세로로 쪼개져 게이트 2에 걸린다. */
.img-thumb-cap {
  font-size: var(--fs-6);
  color: var(--text-muted);
  white-space: nowrap;
}
.img-thumb-arrow {
  color: var(--text-faint);
  font-size: var(--fs-5);
  flex: 0 0 auto;
}
/* 썸네일이 붙으면서 이름 칸의 기본 폭을 줄인다 — 360px 에서 이름이 눌리지 않게 한다. */
.img-row .img-thumbs + .img-name {
  flex: 1 1 8rem;
}

.img-viewer {
  width: min(92vw, 56rem);
  max-width: 92vw;
  max-height: 88vh;
  padding: var(--sp-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  overflow: auto;
}
.img-viewer::backdrop {
  background: rgba(17, 17, 18, 0.6);
}
.img-viewer-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}
.img-viewer-title {
  margin: 0;
  font-size: var(--fs-4);
  font-weight: var(--fw-600);
  word-break: break-all;
  min-width: 0;
}
.img-viewer-body {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
}
.img-viewer-pane {
  margin: 0;
  /* 좁은 화면에서는 위아래로 쌓이고 넓어지면 나란히 선다 — 비교가 목적이므로 같은 폭이다. */
  flex: 1 1 16rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.img-viewer-pane figcaption {
  font-size: var(--fs-5);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.img-view {
  display: block;
  width: 100%;
  max-height: 52vh;
  object-fit: contain;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
}
.img-view.is-missing {
  min-height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
}

/* ── 크롭 상자 (2026-09-01 신설 — /image-crop) ──────────────────────
   ⚠️ 새 디자인 언어를 만들지 않는다 — 색·간격·모서리는 전부 기존 토큰이다.
   ⚠️ 이 블록의 요소는 «문구 없이도» 무엇을 하는 자리인지 보여야 한다
      (insights 2026-09-01 「언어 제거 조작 가능성」 후보 조항). 그래서 바깥을 어둡게
      깔고 네 모서리에 손잡이를 둔다 — 설명 문장이 아니라 형태가 말한다. */
.crop-stage {
  margin-top: var(--sp-4);
}
/* 프레임은 «그림에 딱 맞는» 상자여야 한다 — 상자 위치를 백분율로 잡기 때문에
   프레임이 그림보다 크면 그 차이만큼 어긋난다. */
.crop-frame {
  position: relative;
  display: block;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  line-height: 0;
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  /* 상자를 끌 때 페이지가 함께 스크롤되지 않게 한다 — 손가락 조작의 전제다. */
  touch-action: none;
}
.crop-preview {
  display: block;
  max-width: 100%;
  max-height: 60vh;
  width: auto;
  height: auto;
}
.crop-box {
  position: absolute;
  box-sizing: border-box;
  border: 2px solid #ffffff;
  outline: 1px solid rgba(0, 0, 0, 0.55);
  /* 바깥을 어둡게 — 남길 부분이 도드라진다. 프레임의 overflow:hidden 이 잘라 준다. */
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.42);
  cursor: move;
  touch-action: none;
}
/* 손잡이는 «상자 안쪽»에 붙인다 — 바깥으로 내밀면 그림 가장자리에서 프레임에 잘려
   누를 수 없는 자리가 생긴다. */
.crop-handle {
  position: absolute;
  width: 28px;
  height: 28px;
  box-sizing: border-box;
  background: #ffffff;
  border: 1px solid rgba(0, 0, 0, 0.5);
  border-radius: 3px;
  touch-action: none;
}
.crop-handle[data-handle='nw'] { left: 0; top: 0; cursor: nwse-resize; }
.crop-handle[data-handle='ne'] { right: 0; top: 0; cursor: nesw-resize; }
.crop-handle[data-handle='sw'] { left: 0; bottom: 0; cursor: nesw-resize; }
.crop-handle[data-handle='se'] { right: 0; bottom: 0; cursor: nwse-resize; }

/* 자르기의 «비율 버튼»과 크기 조절의 «크기 프리셋»은 같은 형태다 —
   새 디자인을 만들지 않고 같은 규칙을 공유한다. */
.crop-ratios,
.size-presets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}
/* 🟢 2026-09-04 — .save-note 3규칙을 걷어냈다. 그 블록이 화면에서 사라졌다. */

/* 결과 행의 판정 표기 — 통과/미달이 «색»만으로 갈리지 않게 글자로도 갈린다. */
.verdict {
  white-space: nowrap;
  font-weight: 600;
}
.verdict.is-ok { color: var(--ok); }
.verdict.is-bad { color: var(--warn); }
/* 🟢 2026-09-04 실기기 결함 — 「전체 화면·발표1920×1080」처럼 이름과 치수가 붙어 나왔다.
   원인: .btn-small 이 `display: inline-flex` 라 소스에 있던 «공백 텍스트 노드»가
   익명 플렉스 아이템으로 잘려 화면에서 사라진다. 마크업에 공백이 «있는데» 안 보이는 자리다.
   ⚠️ 그래서 처방은 &nbsp; 가 아니라 gap 이다 — 공백 문자는 다음에도 같은 방식으로 먹힌다.
   ⚠️ 두 조각을 각각 «요소»로 세운다(.size-preset-name · .size-preset-px). 텍스트 노드는
      좌표가 없어 스위트가 «갈렸는가»를 잴 수 없다 — 재려면 잴 것이 요소여야 한다. */
.size-preset {
  column-gap: var(--sp-2);
}
.size-preset-px {
  opacity: 0.72;
  font-variant-numeric: tabular-nums;
}
.crop-ratio.is-on,
.size-preset.is-on {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

/* ── iOS Safari 가 화면을 당기지 않게 한다 (2026-09-04) ──────────────
   🟢 실기기 보고: 「사이트에 들어가면 화면이 확대된 상태로 뜬다. 줌아웃하면 정상화면으로
      돼. 계속 그랬어」(iOS Safari · 프로덕션).
   🟢 헤드리스 실측으로 세 방향을 갈랐다(360×640 · 400×667 · 9라우트 전량 = 18화면).
     ① viewport 메타 — 18/18 이 「width=device-width, initial-scale=1」이고
        maximum-scale·user-scalable 은 0건이었다. → 원인 아님.
     ③ 문서 폭 — documentElement.scrollWidth − clientWidth 가 18/18 에서 0 이었다.
        → 원인 아님(넘치는 표는 .table-wrap 안에서 스스로 스크롤한다).
     ② 입력 칸 글자 크기 — 16px 미만인 폼 컨트롤이 7라우트에 서 있었다.
        15px(.img-controls .ctl 계열) · 15.2px(.fld 계열) · 13.333px(파일·체크박스·일부 select).
        → 남은 원인은 이것 하나다. iOS Safari 는 16px 미만 입력 칸에 포커스가 가면 화면을
        당기고, 그 배율이 사이트에 남아 다음 방문에 «확대된 채로» 뜬다.
   ⚠️ user-scalable=no·maximum-scale 로 막지 않는다 — 그것은 확대를 «못 하게» 만드는 것이라
      접근성을 깨고, 원인을 고치는 것이 아니다. 고치는 것은 «당길 이유»다.
   ⚠️ 16px «이상»이어야 한다. 15.99px 도 당긴다. 그래서 max(16px, …) 로 바닥을 둔다.
   ⚠️ 셀렉터를 나열하는 이유 — .img-controls .ctl input 등은 이 파일 앞쪽에서 특이도 (0,2,1)
      로 font 를 잡는다. 태그 셀렉터 하나만 두면 그 규칙이 이겨 값이 안 선다.
   ⚠️ 이 규칙이 도는지는 overflow-probe 의 「초기 배율」 패스가 잰다. 지우면 그 패스가 죽는다. */
input,
select,
textarea,
.img-controls .ctl input,
.img-controls .ctl select,
.fld input[type='date'],
.fld input[type='text'] {
  font-size: max(16px, 1em);
}

/* ── 도구 페이지 공통 골격 — 아이폰 기준 (2026-09-13 · 사용자 지시 ⑰ 집행 · 「이제 각각의 내부 페이지들도」) ──────
   대상 7종: 드롭존 · 주 버튼 · 보조 버튼 · 입력칸/셀렉트 · 접힌 설명 상자 · 「다른 도구」 카드 · 결과 목록 항목.
   ⚠️ 새 토큰 0 — :root 의 아이폰 한 벌(--touch-min · --icon-radius · --gloss · --shadow-app · --spring · --fill · --safe-*)과
      기존 활자·간격·모서리 단만 읽는다. 홈과 툴이 같은 값을 읽어야 둘이 갈리지 않는다.
   ⚠️ 이 블록이 파일 «끝»에 서는 이유 — 바로 위 블록(font-size: max(16px, 1em))보다 뒤라야 입력칸 17px 이 선다.
      그 블록의 바닥 16px 은 여기 값이 넘으므로 그대로 산다(지우지 않았다).
   ⚠️ 하한 둘 — 골격 안 글자 16px · 누를 자리 44px. 재는 곳은 tests/tool-skeleton-probe.mjs(툴 18라우트 × 360·390·430).
   ⚠️ 라우트 고유 UI(프리셋 .size-preset · 비율 .crop-ratio · 필터 칩 .chk · .sp-chip · .uuid-chip · 출력칸)는 건드리지 않는다 —
      그래서 버튼 규칙이 .btn-small 을 비켜 간다(결과 행 · 비교 창의 작은 버튼만 아래에서 따로 잡는다).
   ⚠️ /spell-check-pdf · /uuid-generator 는 자기 <style> 에서 «겉모양»을 걷어내고 배치만 남겼다 — 겉모양은 여기 한 곳이다. */

/* 드롭존 — 둥근 판 하나. 점선 경계는 --dropzone-border(대비 3.12:1 실측 토큰) 그대로다. */
.dropzone,
.sp-drop {
  border: 1.5px dashed var(--dropzone-border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  transition: border-color var(--motion) ease, background-color var(--motion) ease;
}
.dropzone.is-over,
.sp-drop.is-over {
  border-color: var(--accent);
  background: var(--accent-soft);
}
/* 안내 글자 — 13px → 16px(아이폰 «Callout» 단). 크기를 올린 대신 색을 한 단 내려 위계는 색이 맡는다. */
.drop-sub,
.sp-drop span {
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-muted);
}
/* 드롭존 안 버튼 — 좁은 화면에서는 줄을 채워 엄지 자리를 넓히고, 넓은 화면에서는 18rem 에서 멈춘다. */
.drop-actions .btn {
  flex: 1 1 9rem;
  max-width: 18rem;
}

/* 버튼 — 주 버튼은 잉크 채움, 보조 버튼은 옅은 회색 채움(--fill). 경계선이 없다. 누르면 줄었다가 --spring 으로 돌아온다(홈 아이콘과 같은 곡선). */
.btn:not(.btn-small),
.sp-dl,
.uuid-dl,
.uuid-copy,
.uuid-go {
  font: inherit;
  font-size: var(--fs-3);
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-body);
  min-height: var(--touch);
  padding: 0 var(--sp-5);
  border: 0;
  border-radius: var(--radius);
  background: var(--fill);
  color: var(--text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform 320ms var(--spring), opacity var(--motion) ease, background-color var(--motion) ease;
}
.btn.btn-primary:not(.btn-small),
.uuid-go {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}
.btn:not(.btn-small):active:not(:disabled),
.sp-dl:active:not(:disabled),
.uuid-dl:active,
.uuid-copy:active,
.uuid-go:active {
  transform: scale(0.96);
  transition-duration: 90ms;
  transition-timing-function: ease-out;
}
@media (hover: hover) {
  .btn:not(.btn-small):not(.btn-primary):hover:not(:disabled),
  .sp-dl:hover:not(:disabled),
  .uuid-dl:hover,
  .uuid-copy:hover {
    background: var(--border-strong);
  }
}

/* 입력칸 · 셀렉트 — 아이폰 검색칸과 같은 옅은 채움 + 둥근 모서리. 경계선 대신 채움이 칸을 만든다. */
.img-controls .ctl select,
.img-controls .ctl input[type='number'],
.fld select,
.fld input[type='date'],
.fld input[type='text'],
.uuid-num,
.uuid-text,
.uuid-select {
  font: inherit;
  font-size: var(--fs-3);
  min-height: var(--touch);
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--fill);
  color: var(--text);
}
.img-controls .ctl select:focus-visible,
.img-controls .ctl input[type='number']:focus-visible,
.fld select:focus-visible,
.fld input:focus-visible,
.uuid-num:focus-visible,
.uuid-text:focus-visible,
.uuid-select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* 접힌 설명 — «행 하나 + 펼치면 그 행 아래로 겹쳐 뜨는 판».
   🟢 왜 겹쳐 뜨는가 — RUM(CF Web Analytics) CLS 디버그가 `section.section > details.fold > p` 를 지목했고, 헤드리스 실측에서
      «입력 없이 열린» 접힘(찾기 · 검색 결과의 글자 조각 링크가 여는 모양)이 CLS 0.15~0.53 을 냈다. 손가락으로 연 접힘은
      hadRecentInput 이라 CLS 에 들지 않는다. 판이 흐름 «밖»에 서면 열어도 아래 행이 한 픽셀도 움직이지 않는다.
   ⚠️ 펼쳐 두는 것으로 고치지 않았다(지시 ⑦⑨). 기본 펼침 8개(언어당)도 닫았다 — 흐름 밖 판이 처음부터 열려 있으면 페이지를 덮는다.
   ⚠️ 한 페이지의 설명 상자는 `name="info"` 한 무리다 — 하나를 열면 다른 것이 닫혀 판끼리 겹치지 않는다(자바스크립트 0줄). */
.section.tool ~ .section:not(.tool) {
  margin-top: var(--sp-2);
}
.section.tool + .section:not(.tool) {
  margin-top: var(--sp-6);
}
.section:not(.tool) > .fold {
  position: relative;
}
.section:not(.tool) > .fold > summary {
  min-height: calc(var(--touch-min) + var(--sp-2));
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--motion) ease;
}
.section:not(.tool) > .fold > summary:active {
  background: var(--fill);
}
.section:not(.tool) > .fold > summary > h2 {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-3);
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-body);
  line-height: 1.35;
}
.section:not(.tool) > .fold[open] > summary {
  margin-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
}
.section:not(.tool) > .fold > .fold-body {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 15;
  padding: var(--sp-3) var(--sp-4) var(--sp-5);
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--surface);
  box-shadow: 0 22px 40px -18px rgba(17, 17, 18, 0.32);
  transform-origin: top center;
}
.section:not(.tool) > .fold[open] > .fold-body {
  animation: fold-drop 260ms var(--spring);
}
@keyframes fold-drop {
  from {
    opacity: 0;
    transform: translateY(-6px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.fold-body > :first-child {
  margin-top: 0;
}
.fold-body > :last-child {
  margin-bottom: 0;
}
/* 도구 칸 안의 접힘(고급 설정)은 «조작 칸»이라 흐름 안에서 편다 — 여는 것이 늘 손가락 입력이다. 행 높이만 44px 로 맞춘다. */
.section.tool > .fold.img-advanced {
  margin-top: var(--sp-4);
}
.section.tool > .fold.img-advanced > summary {
  min-height: var(--touch-min);
  font-size: var(--fs-3);
  font-weight: var(--fw-600);
  -webkit-tap-highlight-color: transparent;
}

/* 「다른 도구」 제목 — ⚠️ 2026-09-14 (지시 ㉑) 이 자리의 카드 규칙(.tool-grid · .tool-card · 44px 아이콘 · 한 문장 두 줄)을 걷어냈다.
   목록은 홈과 같은 아이콘 격자이고 규칙은 파일 앞 「홈 — 앱 아이콘 격자」 블록 한 곳이다. 여기에는 제목 한 줄만 남는다. */
.crosslinks h2 {
  margin: 0 0 var(--sp-3);
  padding: 0;
  border: 0;
  font-size: var(--fs-3);
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-body);
  color: var(--text-muted);
}

/* 결과 목록 항목 — 둥근 판 + 16px 글자 + 44px 알약 버튼. 판정 표기·썸네일 크기(52px)는 그대로다. */
.img-row {
  border-radius: var(--radius);
  background: var(--surface);
}
.img-row .img-meta,
.img-thumb-cap,
.img-thumb-arrow {
  font-size: 16px;
}
.img-row .btn-small,
.img-viewer .btn-small {
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  border: 0;
  border-radius: 999px;
  background: var(--fill);
  color: var(--text);
  font-size: 16px;
  font-weight: var(--fw-600);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform 320ms var(--spring);
}
.img-row .btn-small:active,
.img-viewer .btn-small:active {
  transform: scale(0.95);
  transition-duration: 90ms;
}

@media (prefers-reduced-motion: reduce) {
  .btn:not(.btn-small),
  .sp-dl,
  .uuid-dl,
  .uuid-copy,
  .uuid-go,
  .img-row .btn-small,
  .img-viewer .btn-small {
    transition: none;
  }
  .btn:not(.btn-small):active:not(:disabled),
  .sp-dl:active:not(:disabled),
  .uuid-dl:active,
  .uuid-copy:active,
  .uuid-go:active,
  .img-row .btn-small:active,
  .img-viewer .btn-small:active {
    transform: none;
  }
  .section:not(.tool) > .fold[open] > .fold-body {
    animation: none;
  }
}


/* ── ⑱ 아이폰 젤리 판 — 전 페이지 (2026-09-14 · 사용자 지시 ⑱) ─────────────────────────────
   원문: 「툴들 페이지들도 아이폰스타일로 입체그래픽,젤리 느낌으로 다 수정해」 · 「그냥 이 웹사이트의 모든 페이지들을 아이폰스타일로 입체그래픽,젤리 느낌으로 다 수정해」 ·
         「그리고 각각의 블록들이 색상이 동일하니까 직관적으로 어떤거를 사용해야할지 판단하기 어려워」.
   무엇을 바꿨나 — 한 줄씩:
   ① 바탕 — 연회색 페이지 + 흰 판(:root 토큰 값을 갈았다 · 두 벌을 두지 않는다).
   ② 도구 색 — 도구마다 한 색이다. SSOT 는 아래 [data-tool] 표 한 곳이고, 홈 아이콘 · 「다른 도구」 줄 · /faq/ 도구 칩 · 도구 페이지
      (헤더 밑줄 · 드롭존 · 주 버튼 · 예시 보기)가 같은 값을 읽는다. 기준(측정 «전»에 적었다): 아이콘 바탕색 쌍별 ΔE76 ≥ 20 — tests/tool-copy-probe.mjs.
   ③ 젤리 — 판마다 위쪽 밝은 테 + 부드러운 바닥 그림자, 누르면 줄었다가 --spring 으로 돌아온다(움직임 줄이기에서는 끈다).
   ④ «예시 보기» — 알약 한 개. 펼친 동안 결과판을 드롭존 위로 세운다 — DOM 을 옮기지 않고 order 로 세운다(kakao-pdf 인쇄 화이트리스트 보존).
   ⚠️ 하한은 그대로다 — 골격 안 글자 16px · 누를 자리 44px(tool-skeleton-probe) · 설명 판은 흐름 밖(S4 · S5).
   ⚠️ 흰 글자를 올리는 주 버튼의 아래 끝 색(--tb2)은 흰색 대비 4.5:1 이상으로 골랐다(계산값 4.7~8.7). 카카오톡 대화 분석기만 노랑 바탕 + 짙은 글자다. */

/* 도구 색 표 — t1·t2 = 아이콘 바탕 그라데이션 · tc = 흰 판 위 글자/테두리 색(대비 4.5:1 이상) · tb1·tb2 = 주 버튼 · ton = 주 버튼 글자 */
[data-tool='kakao-chat'],
.app-icon--kakao-chat {
  --t1: #ffe45e;
  --tdz: #91784a;
  --t2: #f5b400;
  --tc: #946200;
  --tb1: #ffe66e;
  --tb2: #f5b400;
  --ton: #3a2a00;
}
[data-tool='kakao-pdf'],
.app-icon--kakao-pdf {
  --t1: #ff9b7d;
  --tdz: #a96961;
  --t2: #e5533d;
  --tc: #c4432e;
  --tb1: #e0654f;
  --tb2: #c4432e;
  --ton: #ffffff;
}
[data-tool='kakao-excel'],
.app-icon--kakao-excel {
  --t1: #6ee0a8;
  --tdz: #508473;
  --t2: #189a66;
  --tc: #127a52;
  --tb1: #22946a;
  --tb2: #127a52;
  --ton: #ffffff;
}
[data-tool='image-compress'],
.app-icon--image-compress {
  --t1: #6fd0ff;
  --tdz: #517fa8;
  --t2: #1b86dd;
  --tc: #146fbd;
  --tb1: #2a86d6;
  --tb2: #146fbd;
  --ton: #ffffff;
}
[data-tool='image-resize'],
.app-icon--image-resize {
  --t1: #ffbd66;
  --tdz: #a0764a;
  --t2: #e2780f;
  --tc: #b25e00;
  --tb1: #c9730f;
  --tb2: #b25e00;
  --ton: #ffffff;
}
[data-tool='image-crop'],
.app-icon--image-crop {
  --t1: #b8adff;
  --tdz: #736bb1;
  --t2: #6a5bdb;
  --tc: #5747cf;
  --tb1: #6b5de0;
  --tb2: #5747cf;
  --ton: #ffffff;
}
[data-tool='image-convert'],
.app-icon--image-convert {
  --t1: #f58ac8;
  --tdz: #995d82;
  --t2: #b3307b;
  --tc: #a42c70;
  --tb1: #bd3a86;
  --tb2: #a42c70;
  --ton: #ffffff;
}
[data-tool='uuid-generator'],
.app-icon--uuid-generator {
  --t1: #7d869b;
  --tdz: #6a6e7d;
  --t2: #2b3142;
  --tc: #454e66;
  --tb1: #58627d;
  --tb2: #3b4359;
  --ton: #ffffff;
}
/* ⚠️ 2026-09-14 — 첫 값(청록 #4fded0 → #0c8779)은 카카오톡 대화 엑셀 변환기(초록)와 ΔE76 19.8 로 기준 20 에 못 미쳤다(tool-copy-probe T6 첫 판).
   기준은 그대로 두고 색을 옮겼다 — 청록에서 «바다색(petrol)» 쪽으로. 흰 글자 대비 --tc 5.7:1(계산). */
[data-tool='spell-check-pdf'],
.app-icon--spell-check-pdf {
  --t1: #56d8ea;
  --tdz: #4c7f8c;
  --t2: #0e7f97;
  --tc: #0a6f84;
  --tb1: #1a8aa2;
  --tb2: #0a6f84;
  --ton: #ffffff;
}
@media (prefers-color-scheme: dark) {
  [data-tool='kakao-chat'] { --tc: #ffd34d; --tdz: #cdb777; }
  [data-tool='kakao-pdf'] { --tc: #ff8f75; --tdz: #cd958b; }
  [data-tool='kakao-excel'] { --tc: #5cd69c; --tdz: #7bb89e; }
  [data-tool='image-compress'] { --tc: #72bfff; --tdz: #86add0; }
  [data-tool='image-resize'] { --tc: #ffb45e; --tdz: #cda77f; }
  [data-tool='image-crop'] { --tc: #b3a8ff; --tdz: #a7a1d0; }
  [data-tool='image-convert'] { --tc: #f28bc3; --tdz: #c693b2; }
  [data-tool='uuid-generator'] { --tc: #aab3c7; --tdz: #a2a7b4; }
  [data-tool='spell-check-pdf'] { --tc: #5ad2e6; --tdz: #7ab6c3; }
}
/* 헤더 밑줄(«지금 어디에 있는지»)도 같은 표에서 난다. 도구가 아닌 페이지에는 밑줄이 없다. */
[data-tool] {
  --tool-accent: var(--tc);
}
.nav-fold > summary {
  border-bottom-color: var(--tc, transparent);
}

/* 바탕 · 헤더 — 헤더는 반투명 판 + 흐림(아이폰 탐색 막대)이고 스크롤해도 위에 붙는다. */
html {
  scroll-padding-top: 72px;
}
body {
  background: var(--bg);
}
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 0.5px solid var(--border-strong);
}
.nav-fold > ul {
  border: 0;
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 12px 32px -8px rgba(17, 17, 18, 0.28), 0 0 0 0.5px var(--border-strong);
}

/* 도구 페이지 머리 — 제목 바로 아래가 «예시 보기» 또는 드롭존이다. */
main .wrap > h1 + .section.tool {
  margin-top: 0;
}
.page-tool main h1 {
  margin-bottom: var(--sp-4);
}

/* «예시 보기» — 명세 playbook 「페이지 문구 규칙」 8항. 하단 설명 상자(판)와 다른 모양 — 도구 색 알약 한 개. */
.section.tool.has-demo {
  display: flex;
  flex-direction: column;
}
.section.tool.has-demo > .demo-toggle {
  order: -2;
  align-self: flex-start;
}
.section.tool.has-demo.is-demo > [data-demo-panel] {
  order: -1;
  margin: 0 0 var(--sp-4);
  animation: demo-drop 300ms var(--spring);
}
/* 2026-09-15 (⑲) — 맞춤법 검사기의 도구 칸(.sp-tool)은 격자(grid · 간격 0.75rem)라 flex 로 바꾸지 않는다. 격자 항목에도 order 가 서므로 같은 order 만 주고 간격은 격자 gap 이 든다.
   결과판이 셋(상태 줄 · 내려받기 단추 · 목록)이라 셋 다 data-demo-panel 이다 — 같은 order 끼리는 DOM 순서가 그대로다. */
.sp-tool.has-demo > .demo-toggle {
  order: -2;
  justify-self: start;
  margin-bottom: 0;
}
.sp-tool.has-demo.is-demo > [data-demo-panel] {
  order: -1;
  animation: demo-drop 300ms var(--spring);
}
@keyframes demo-drop {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.demo-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--touch-min);
  margin: 0 0 var(--sp-3);
  padding: 0 12px 0 18px;
  border: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--tc, var(--accent)) 13%, var(--surface));
  color: var(--tc, var(--accent));
  font: inherit;
  font-size: 16px;
  font-weight: var(--fw-600);
  letter-spacing: var(--ls-body);
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), 0 1px 2px rgba(17, 17, 18, 0.06),
    0 0 0 0.5px color-mix(in srgb, var(--tc, var(--accent)) 22%, transparent);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform 320ms var(--spring), background-color var(--motion) ease;
}
.demo-toggle:active:not(:disabled) {
  transform: scale(0.95);
  transition-duration: 90ms;
  transition-timing-function: ease-out;
}
.demo-toggle:focus-visible {
  outline: 2px solid var(--tc, var(--accent));
  outline-offset: 2px;
}
.demo-toggle:disabled {
  opacity: 0.6;
  cursor: default;
}
.demo-chev {
  flex: none;
  width: 18px;
  height: 18px;
  max-width: none;
  transition: transform 300ms var(--spring);
}
.demo-toggle[aria-expanded='true'] .demo-chev {
  transform: rotate(180deg);
}

/* 드롭존 — 도구 색이 옅게 번진 흰 판 + 점선. 머리에 그 도구의 앱 아이콘이 선다(홈과 같은 그림 · 같은 색). */
.dropzone,
.sp-drop {
  /* 테두리는 «실측 대비»가 선 단색 토큰(--tdz)이다 — color-mix 로 섞으면 계산값이 color(srgb …) 가 되어 tests/image-probe.mjs 의
     대비 판정(3:1)이 값을 못 읽는다(🟢 2026-09-14 전량 회귀 첫 판 8 FAIL · null). 값은 도구 색 50% + --dropzone-border 50% 를 미리 계산했고
     흰 판 대비 4.05~5.08:1 · 위쪽 옅은 도구 색 대비 3.70~4.31:1(다크: 판 6.63~8.57 · 옅은 색 4.66~5.52). 바탕색은 흰 판 단색 + 그 위 옅은 도구 색 번짐이다. */
  border: 1.5px dashed var(--tdz, var(--dropzone-border));
  border-radius: 22px;
  background-color: var(--surface);
  background-image: linear-gradient(180deg, color-mix(in srgb, var(--t1, var(--surface)) 18%, var(--surface)) 0%, var(--surface) 75%);
  box-shadow: var(--shadow-card);
}
.dropzone.is-over,
.sp-drop.is-over {
  border-color: var(--tc, var(--accent));
  background: color-mix(in srgb, var(--t1, var(--accent-soft)) 28%, var(--surface));
}
.dropzone {
  padding: var(--sp-5) var(--sp-4);
}
.drop-icon {
  --icon: 60px;
  margin: 0 auto var(--sp-3);
}
.sp-drop .drop-icon {
  margin: 0 auto var(--sp-1);
}
.drop-main {
  margin-bottom: var(--sp-3);
}

/* 버튼 — 주 버튼은 도구 색 젤리(위 밝은 테 · 아래 그늘 · 바닥 그림자), 보조는 옅은 채움에 밝은 테. */
.btn:not(.btn-small),
.sp-dl,
.uuid-dl,
.uuid-copy,
.uuid-go {
  border-radius: 14px;
}
.btn.btn-primary:not(.btn-small),
.uuid-go {
  background: linear-gradient(180deg, var(--tb1, var(--btn-primary-bg)), var(--tb2, var(--btn-primary-bg)));
  color: var(--ton, var(--btn-primary-fg));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.38), inset 0 -2px 4px rgba(0, 0, 0, 0.12),
    0 6px 14px -8px rgba(17, 17, 18, 0.5);
}
.btn:not(.btn-small):not(.btn-primary),
.sp-dl,
.uuid-dl,
.uuid-copy {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

/* 결과판 · 조작 칸 — 흰 판에 담는다. 판 안의 작은 판(숫자 타일 · 결과 행)은 바탕색으로 한 단 내린다. */
.section.tool > .tool-result,
.section.tool > .pdf-panel {
  padding: var(--sp-4);
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.section.tool > .tool-result .stat,
.section.tool > .pdf-panel .stat,
.section.tool > .tool-result .img-row {
  background: var(--bg);
}
.section.tool > .img-controls {
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: 18px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.uuid-tool {
  padding: var(--sp-4);
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* 설명 상자 — 흰 판 한 줄씩, 떠 있는 그림자. 판(흐름 밖)은 그대로다. */
.section:not(.tool) > .fold > summary {
  border: 0;
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.section:not(.tool) > .fold[open] > summary {
  border-radius: 16px 16px 0 0;
  box-shadow: none;
}
.section:not(.tool) > .fold > .fold-body {
  border: 0;
  border-radius: 0 0 16px 16px;
  box-shadow: inset 0 0.5px 0 var(--border-strong), 0 26px 44px -18px rgba(17, 17, 18, 0.34);
}
.section:not(.tool) > .fold[open] > summary::after {
  border-color: var(--tc, var(--text-faint));
}
/* 기기별 안내 탭 — 아이폰 분할 선택기(옅은 채움 위 흰 조각). */
.guide-tabs {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  border-radius: 12px;
  background: var(--fill);
}
.guide-tab {
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--text);
  font-size: 15px;
}
.guide-tab[aria-selected='true'] {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 3px rgba(17, 17, 18, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
@media (prefers-color-scheme: dark) {
  .guide-tab[aria-selected='true'] {
    background: #48484a;
  }
}

/* 「다른 도구」 — ⚠️ 2026-09-14 (지시 ㉑) 이 자리의 «설정 목록» 규칙(흰 판 · 헤어라인 · 꺾쇠 · 38px 아이콘)을 걷어냈다.
   이제 홈과 같은 아이콘 격자이고, 규칙은 파일 앞 「홈 — 앱 아이콘 격자」 블록(.apps · .app-row · .app · .app-icon · .app-name) 한 곳이다 —
   두 벌을 두지 않는다(playbook 「페이지 문구 규칙」 14항 · 단정 tests/home-faq-probe.mjs A10 · B6). 제목(h2) 규칙만 이 파일 앞 ⑰ 블록에 남는다. */

/* /faq/ — 판에 그림자, 도구 칩은 그 도구의 색. */
.faq-list {
  border: 0;
  border-radius: 16px;
  box-shadow: var(--shadow-card);
}
.faq-pin {
  border: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ok) 9%, var(--surface)) 0%, var(--surface) 55%);
  box-shadow: var(--shadow-card);
}
.faq-points .faq-point-h {
  color: var(--text);
  font-size: var(--fs-4);
  font-weight: var(--fw-600);
}
.faq-tool[data-tool] {
  background: color-mix(in srgb, var(--tc) 12%, var(--surface));
  color: var(--tc);
  font-weight: var(--fw-600);
}
.faq-moved .faq-a {
  color: var(--text);
}

/* 개인정보처리방침 — 절마다 흰 판. */
.page-doc main .section {
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}
.page-doc main .section h2 {
  padding-bottom: 0;
  border-bottom: 0;
  font-size: var(--fs-3);
}

/* 푸터 — 바탕 위에 헤어라인 한 줄. */
.site-footer {
  background: transparent;
  border-top: 0.5px solid var(--border-strong);
}

@media (prefers-reduced-motion: reduce) {
  .demo-toggle,
  .demo-chev {
    transition: none;
  }
  .demo-toggle:active:not(:disabled) {
    transform: none;
  }
  .section.tool.has-demo.is-demo > [data-demo-panel],
  .sp-tool.has-demo.is-demo > [data-demo-panel] {
    animation: none;
  }
}
@media print {
  /* 결과판의 흰 판 · 그림자는 화면 전용이다 — 인쇄 문서(.doc)에 번지지 않게 끈다. */
  .section.tool > .pdf-panel {
    background: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
  }
}
/* 인식한 형식 이름 — 강조 태그(<strong>) 대신 이 한 칸이 색만 준다(2026-09-14 · ⑱ 「쓸데없이 강조 표시 넣지말고」). */
.detect .detect-name {
  color: var(--ok);
  font-weight: var(--fw-600);
}
/* 결과 행의 «값» 칸(잘라낸 크기 · 형식 변화 · 결과 해상도) — <strong> 대신 이 칸이 굵기만 준다(2026-09-14 · ⑱). tests/image-probe.mjs 가 이 표지로 값을 읽는다. */
.img-meta .img-meta-v {
  color: var(--text);
  font-weight: var(--fw-600);
}
/* 비교 창 그림 제목(원본 · 결과) — <strong> 대신 이 칸이 굵기만 준다(2026-09-14 · ⑱). */
.img-pane-label {
  color: var(--text);
  font-weight: var(--fw-600);
}
