:root {
  --bg: #fbfaf8;
  --panel: #ffffff;
  --ink: #1c1a17;
  --dim: #6f6a63;
  --line: #e6e1d9;
  --accent: #b4472e;
  /* 「배우는 중」 — 익힘(--accent)과 같은 계열의 옅은 색. 경고색(--warn)을
     쓰지 않는다: 경고색은 화면당 하나다(기획서 2026-08-28_부담없는_페이스_v1).
     한 번 본 카드는 잘못이 아니라 가는 중이다. */
  --accent-soft: #dda897;
  --ok: #2f7d54;
  --warn: #b8892b;
  --radius: 14px;
  /* 터치 표적 (TODO #26). 44px = 손가락 하나. 헤더는 붙박이라 실제로 이만큼
     키우면 모바일에서 학습 영역을 크게 먹으므로, 헤더만 --tap-slim 으로
     보이는 크기를 두고 탭 영역만 --tap 으로 넓힌다. 자세한 근거는 파일 끝. */
  --tap: 44px;
  --tap-slim: 36px;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14130f;
    --panel: #1d1b17;
    --ink: #f0ece4;
    --dim: #9b948a;
    --line: #2e2b25;
    --accent: #e0714f;
    --accent-soft: #8a4c39;
    --ok: #62b98a;
    --warn: #d6a84e;
  }
}

* { box-sizing: border-box; }
/* 저자 스타일의 display 가 [hidden] 의 UA 규칙을 이긴다.
   .answer{flex} · .empty{grid} 등이 숨겨지지 않던 문제 — 전역으로 못박는다. */
[hidden] { display: none !important; }
/* ★ body 는 height 가 아니라 min-height 다. height:100% 면 body 의 높이가
   뷰포트(950px)에 고정되는데, position:sticky 는 「containing block 안에서만」
   붙어 있으므로 붙박이 헤더가 그 950px 을 벗어나는 순간 밀려 올라간다 —
   실측 2026-08-31: 대시보드(페이지 1,943px)에서 889px 넘게 내리면 헤더 y 가
   0 → -61 → -104 로 사라졌다. 아래 header 규칙이 "항상 보여야 한다" 고
   적어 둔 바로 그것이 조용히 깨져 있었다. min-height 면 body 가 내용만큼
   자라 붙박이가 페이지 끝까지 간다.
   기획서 2026-08-31_단어목록_배치정리_v1 §4-7. */
html { height: 100%; }
body { min-height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans KR",
        "Malgun Gothic", system-ui, sans-serif;
  display: flex;
  flex-direction: column;
}

/* ---- login gate ---- */
.gate {
  margin: auto;
  padding: 32px;
  width: min(360px, 90vw);
  text-align: center;
}
.gate h1 { font-size: 30px; letter-spacing: .06em; margin: 0 0 24px; }
.gate form { display: grid; gap: 10px; }
.gate input, .gate button {
  padding: 12px 14px; font-size: 16px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--ink);
}
.gate button { background: var(--accent); color: #fff; border: 0; cursor: pointer; }
.err { color: var(--accent); font-size: 14px; }

/* ---- shell ---- */
/* ★ min-height:100% 가 아니라 flex:1 0 auto. body 가 min-height 로 바뀌어
   높이가 부정형(auto)이 됐고, 부정형 부모에 대한 백분율 min-height 는 0 으로
   풀려 아무 일도 안 한다. 내용이 짧으면 늘어나고(grow) 길면 안 줄어드는
   (shrink 0) 것이 여기서 원하던 동작 그대로다. */
#app { display: flex; flex-direction: column; flex: 1 0 auto; }
header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
  /* ★ 대시보드가 페이지 스크롤을 쓰게 되면서 헤더가 위로 사라진다. 남은 카드
     수와 현황·설정이 항상 보여야 하므로 붙박이로 둔다. 배경을 주지
     않으면 지나가는 내용이 비친다. */
  position: sticky; top: 0; z-index: 5; background: var(--bg);
  /* ★ 버튼과 칩이 한 줄에 다 안 들어가 375px 폭에서 가로로 넘쳤다. 줄바꿈을
     허용한다. nowrap 이면 flex 가 .stat 을 min-content(43px)까지 짜부라뜨려
     "남은 복습 88 · 카드 296" 이 일곱 줄짜리 세로 기둥이 된다. */
  flex-wrap: wrap;
}
.stat { white-space: nowrap; }
/* 브랜드 = 홈(학습 현황). 버튼이지만 생김새는 글자 그대로 둔다 —
   기획서 2026-08-28_헤더_직접선택_v1. */
.brand {
  font-weight: 700; letter-spacing: .06em;
  background: transparent; border: 0; padding: 0;
  font-size: inherit; font-family: inherit; color: inherit; cursor: pointer;
}
.brand:hover { color: var(--accent); }
.spacer { flex: 1; }
.chip, .stat {
  font-size: 13px; color: var(--dim);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px;
}
/* 무엇을 공부 중인지 헤더에서 바로 보이고, 눌러서 바꾼다.
   .pick = 급수 칩(선택창을 연다) · .sel = 카드 종류 콤보박스 */
.chip.pick, .chip.sel {
  background: transparent; cursor: pointer; font-family: inherit; line-height: 1.4;
}
.chip.pick:hover:not(:disabled), .chip.sel:hover:not(:disabled) {
  color: var(--ink); border-color: var(--ink);
}
.chip.pick:disabled, .chip.sel:disabled { opacity: .5; cursor: default; }
/* ★ appearance 를 지우지 않는다 — 화살표가 있어야 콤보박스로 보인다.
   대신 좌우 여백만 줄여 칩 높이에 맞춘다. */
.chip.sel { padding: 3px 4px 3px 8px; max-width: 46vw; }
.ghost {
  background: none; border: 1px solid var(--line); color: var(--dim);
  border-radius: 999px; padding: 4px 12px; font-size: 13px; cursor: pointer;
}

/* ---- card ---- */
.card {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 14px; padding: 24px 16px; text-align: center;
}
.meta { display: flex; gap: 6px; }
.badge {
  font-size: 12px; padding: 2px 9px; border-radius: 999px;
  background: var(--accent); color: #fff;
}
.badge.dim { background: transparent; color: var(--dim); border: 1px solid var(--line); }
.badge.new { background: var(--warn); color: #17150f; }
.badge.report {
  background: transparent; color: var(--dim); border: 1px solid var(--line);
  cursor: pointer; font-family: inherit; line-height: 1.5;
}
.badge.report:hover { color: var(--ink); border-color: var(--ink); }

.hanzi {
  font-size: clamp(52px, 16vw, 96px); line-height: 1.15; font-weight: 600;
  letter-spacing: .04em;
}
.sub { font-size: 22px; color: var(--dim); letter-spacing: .1em; }
.gloss { font-size: 17px; color: var(--ink); max-width: 34ch; }

.toneForm { display: flex; gap: 8px; margin-top: 8px; }
.toneForm input {
  width: 220px; padding: 12px 14px; font-size: 20px; text-align: center;
  letter-spacing: .16em;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--ink);
}
.toneForm button, .reveal {
  padding: 12px 18px; font-size: 16px; border: 0; border-radius: 10px;
  background: var(--accent); color: #fff; cursor: pointer;
}
.reveal { background: transparent; color: var(--dim); border: 1px solid var(--line); }

/* ---- answer ---- */
.answer {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 18px; width: min(520px, 92vw);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.pinyin-row { display: flex; align-items: center; gap: 10px; }
.pinyin { font-size: 30px; letter-spacing: .04em; }
/* 답 단어와 발음을 크기·색·줄로 가른다.
   ★ 예전에는 「I · aɪ」 처럼 **같은 크기로 한 줄에** 붙어 있었다. 중국어는 한자와
     병음이 글자체로 갈려 티가 안 났지만, 영어는 둘 다 로마자라 한 덩어리로 읽힌다
     (2026-09-02 사장님 지적). 답은 단어고 발음은 곁들이라, 크기로 그렇게 말한다. */
.ansWord { font-weight: 600; }
.ansIpa {
  display: block; margin-top: 2px;
  font-size: 16px; font-weight: 400; color: var(--dim); letter-spacing: .02em;
}
.speak {
  flex: none; width: 38px; height: 38px; padding: 0; font-size: 17px;
  line-height: 1; cursor: pointer; background: transparent; color: var(--ink);
  border: 1px solid var(--line); border-radius: 50%;
}
.speak:hover { border-color: var(--accent); }
.tts-why { margin: 0; text-align: center; }
.pattern { font-size: 20px; letter-spacing: .22em; }
.pattern .hit { color: var(--ok); }
.pattern .miss { color: var(--accent); text-decoration: underline wavy; }
.meanings { margin: 0; padding: 0; list-style: none; color: var(--dim); font-size: 15px; }
.meanings li + li::before { content: "· "; }
.meanings li { display: inline; }

.grades { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
.grades button {
  padding: 10px 14px; font-size: 15px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: transparent; color: var(--ink);
}
.grades .primary, .primary { background: var(--accent); color: #fff; border-color: transparent; }

.empty { flex: 1; display: grid; place-content: center; gap: 14px; text-align: center; }

/* ---- settings ---- */
dialog {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); color: var(--ink); padding: 20px;
  width: min(420px, 92vw);
}
dialog::backdrop { background: rgba(0,0,0,.45); }
dialog h2 { margin: 0 0 14px; font-size: 18px; }
dialog fieldset { border: 1px solid var(--line); border-radius: 10px; margin: 0 0 12px; }
dialog legend { color: var(--dim); font-size: 13px; padding: 0 6px; }
dialog label { display: block; font-size: 15px; margin: 4px 0; }
dialog .chips { display: flex; gap: 12px; flex-wrap: wrap; }
dialog .chips label { display: inline-flex; align-items: center; gap: 4px; margin: 2px 0; }
dialog label.stack { display: flex; flex-direction: column; gap: 6px; }
dialog textarea {
  width: 100%; box-sizing: border-box; resize: vertical; font: inherit;
  padding: 8px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); color: var(--ink);
}
dialog input[type=range] { width: 140px; margin: 0 8px; vertical-align: middle; }
dialog select { margin-left: 8px; padding: 5px 6px; max-width: 60%;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; }
dialog input[type=number] { width: 90px; padding: 6px 8px; margin-left: 8px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--bg); color: var(--ink); }
.levels { display: flex; gap: 10px; flex-wrap: wrap; }
.levels label { display: inline-flex; align-items: center; gap: 4px; }
.hint { font-size: 13px; color: var(--dim); }
dialog menu { display: flex; gap: 8px; justify-content: flex-end; padding: 0; margin: 14px 0 0; }
dialog menu button { padding: 8px 14px; border-radius: 8px; border: 1px solid var(--line);
  background: transparent; color: var(--ink); cursor: pointer; }

footer {
  padding: 14px 16px; border-top: 1px solid var(--line);
  color: var(--dim); font-size: 12px; text-align: center;
}
footer a { color: var(--dim); }

.meanings-en {
  color: var(--dim);
  font-size: 13px;
  opacity: .75;
  max-width: 42ch;
}

/* ---------------------------------------------------------- 객관식 보기 */
/* 성조·뜻·한자 카드가 함께 쓴다. */
/* 2 x 2 고정. 보기 크기가 다르면 그 자체가 힌트로 읽히므로 네 칸을 반드시
   같은 크기로 둔다. flex-wrap 은 3+1 로 접혀서 안 되고, grid-auto-rows:1fr
   이 있어야 4음절 성어(xiāng fǔ xiāng chéng)처럼 한 줄에 안 들어가는 보기가
   섞여도 크기가 어긋나지 않는다. */
/* 보기. 단이 셔이라 6개는 3+3, 5개는 3+2 로 두 줄에 앉는다 (2026-09-04 사장님).
   ★ 뜻 보기는 한국어 문잭이고 최대 35자라(`了`) 세 단에서 접힌다 —
   그래서 폭을 380 → 560px 로 넓히고 글자를 줄이는 규칙을 아래 .choice 에 둔다. */
.choices {
  display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 1fr;
  gap: 8px; width: min(560px, 96vw);
}

.choice {
  padding: 12px 8px; font-size: 17px; min-height: 58px; line-height: 1.3;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--ink); cursor: pointer;
  /* ★ 긴 뜻이 칸을 밀어내지 않게 한다 — 그리드 칸은 min-content 가
     기본이라 이게 없으면 긴 보기 하나가 세 칸의 너비를 무너뜨린다.
     ★ word-break: keep-all 은 **한국어를 낱말 가운데에서 안 끊는다** — 없으면
     「완료를」가 「완료 / 를」로 갈라진다(실렌더로 확인).
     overflow-wrap 은 그래도 칸보다 긴 낱말이 오면 끊으라는 되돌림이다. */
  min-width: 0; word-break: keep-all; overflow-wrap: anywhere;
}
.choice:hover:not(:disabled) { border-color: var(--accent); }
.choice:disabled { cursor: default; opacity: .95; }
.choice.right { border-color: var(--ok); color: var(--ok); font-weight: 600; }
.choice.wrong { border-color: var(--accent); color: var(--accent); text-decoration: line-through; }

/* 뜻→단어 카드에서 같은 뜻을 가진 다른 단어 */
.synonyms { color: var(--dim); font-size: 13px; max-width: 42ch; }

/* 지난 오답 — 답 화면에만 뜬다. ★ 경고색(--warn/--accent)을 쓰지 않는다.
   무부담 원칙: 경고색은 화면당 하나이고, 그 하나는 이미 「답이 틀렸습니다」
   (.hint.warn)가 쓴다. 여기는 꾸짖는 자리가 아니라 알려 주는 자리다.
   기획서 2026-09-05_오답이력_보여주기_v1 §4-1. */
.misses { color: var(--dim); font-size: 13px; max-width: 42ch;
  padding-top: 2px; border-top: 1px solid var(--line); margin-top: 2px; }
.misses b { color: var(--ink); font-weight: 600; }

/* 예문 — 답 화면에만 뜬다. 중국어는 읽기 쉽게 키우고 번역은 한 단 낮춘다.
   기획서 2026-08-29_예문_HSK1_v1. */
/* ★ #answer 가 align-items:center 인 flex 라 그냥 두면 내용 폭(145px)으로
   쪼그라들어 문장이 불필요하게 접힌다. width:100% 로 폭을 채우고 42ch 로 묶는다.
   ★ align-self:stretch 는 쓰지 않는다 — 교차축 margin:auto 와 같이 쓰면 서로
   무효가 된다(실렌더로 확인: 145px 그대로였다). */
.examples { list-style: none; margin: 4px 0 0; padding: 0;
  width: 100%; max-width: 42ch; margin-inline: auto;
  display: flex; flex-direction: column; gap: 8px; text-align: left; }
.examples li { display: flex; flex-direction: column; gap: 2px;
  padding-left: 10px; border-left: 2px solid var(--line); }
/* 문장 + 읽기 버튼을 한 줄로. 버튼이 문장 끝을 따라다니면 줄바꿈마다
   자리가 바뀌므로, 오른쪽에 고정하고 문장이 남는 폭을 먹게 한다. */
.ex-line { display: flex; align-items: flex-start; gap: 8px; }
.ex-line .ex-text { flex: 1; min-width: 0; }
.ex-text { font-size: 17px; line-height: 1.5; }
.ex-ko { color: var(--dim); font-size: 13px; line-height: 1.4; }
/* 본문 크기에 맞춰 작게 두고 탭 영역만 44px 로 넓힌다(헤더와 같은 수법).
   ★ 선택자를 .examples 로 한 단 구체화한 이유: 파일 뒤쪽의
     `.speak { width: var(--tap) }` 이 그냥 `.ex-speak` 를 이긴다. */
.examples .ex-speak { position: relative; flex: none;
  width: 30px; height: 30px; font-size: 14px; margin-top: 2px; }
.examples .ex-speak::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%); width: var(--tap); height: var(--tap);
}

/* ---- dashboard ---- */
/* 기획서 2026-08-27_대시보드_v1.
   ★ 차트 칠은 여기에만 있다. SVG 는 fill, 범례 칩은 background 를 쓰는데
   한 규칙에 둘 다 적어 두면 같은 클래스로 양쪽이 칠해진다 (HTML 은 fill 을,
   SVG rect 는 background 를 무시한다). */
/* ★ 자체 스크롤을 두지 않는다. flex:1 + overflow-y:auto 로 두면 페이지
   스크롤바와 별개로 안쪽 스크롤바가 하나 더 생겨 「학습 시작」 옆에 붙는다.
   ★ overflow-x:hidden 만 남겨도 안 된다 — 한 축이 visible 이 아니면 CSS 가
   다른 축을 auto 로 계산해 세로 스크롤바가 그대로 되살아난다. */
.dash {
  padding: 16px; display: flex; flex-direction: column; gap: 14px;
  width: min(760px, 100%); margin: 0 auto;
}
.dashHead { display: flex; align-items: center; gap: 10px; }
.dashHead h2 { margin: 0; font-size: 20px; }
.dashHead .primary {
  padding: 10px 20px; font-size: 15px; border: 0; border-radius: 10px;
  background: var(--accent); color: #fff; cursor: pointer;
}

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; }
.tile {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 2px;
}
.tile b { font-size: 24px; font-weight: 600; line-height: 1.2; }
.tile span { font-size: 12px; color: var(--dim); }

.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px;
}
.panel h3 { margin: 0 0 10px; font-size: 14px; color: var(--dim); font-weight: 600; }

/* ── 패널 접기 ────────────────────────────────────────────────────────
   ★ hidden 속성이 아니라 **클래스**로 접는다. 전역 [hidden]{display:none!important}
     과 겹치면 「어떻게 틀리시나」 패널의 자기 숨김(데이터 없을 때)과 뒤엉킨다.
     접힘 = 클래스 · 데이터 없어서 안 보임 = hidden 으로 갈라 둔다.
   기획서 2026-09-05_학습현황_접기_v1 §3-1. */
.panel.collapsed > *:not(.panelHead) { display: none; }
.panel.collapsed .panelHead { margin-bottom: 0; }

.panelHead { margin: 0 0 10px; }
.panelHead button {
  /* 제목이 곧 단추다. 생김새는 h3 그대로 두고 눌리는 것만 더한다. */
  all: unset; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center; gap: 6px;
  width: 100%; min-height: var(--tap-slim);
  font: inherit; color: inherit;
}
.panelHead button::before {
  /* 펴짐 ▾ · 접힘 ▸. 글자라 색·크기가 제목을 따라간다. */
  content: '▾'; font-size: 10px; line-height: 1; opacity: 0.7;
}
.panel.collapsed .panelHead button::before { content: '▸'; }
.panelHead button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.panel p { margin: 0 0 6px; font-size: 14px; }
.panel p:last-child { margin-bottom: 0; }
.panel .hint { font-size: 12px; color: var(--dim); margin-top: 10px; }
.panel .hint.warn { color: var(--warn); }
/* 시스템이 알아서 한 일 한 줄. 경고가 아니라 통지다 — 색은 성취 쪽(--ok)을
   쓰되 왼쪽 선으로 「내가 안 한 일」임을 구분한다.
   기획서 2026-08-28_자동조절_v1. */
.panel .auto {
  margin: 0 0 10px; padding: 6px 10px; font-size: 13px;
  color: var(--ok); border-left: 3px solid var(--ok);
  background: color-mix(in srgb, var(--ok) 8%, transparent);
  border-radius: 0 8px 8px 0;
}

/* 라벨-값 줄. 문장 대신 이걸 쓴다 — 대시보드는 읽는 곳이 아니라 보는 곳이다. */
.rows { display: grid; grid-template-columns: 1fr auto; gap: 7px 14px; align-items: baseline; }
.rows .k { font-size: 14px; color: var(--dim); }
.rows .v { font-size: 15px; text-align: right; font-variant-numeric: tabular-nums; }
.rows .v.big { font-size: 19px; font-weight: 600; color: var(--ink); }
.rows .sub { grid-column: 1 / -1; margin-top: -5px; font-size: 12px; color: var(--dim); }

/* 급수별 진도 — 이름 / 막대 / 숫자 */
.lvRow { display: grid; grid-template-columns: 4.2rem 1fr 5.4rem; align-items: center;
  gap: 8px; margin-bottom: 5px; }
.lvRow:last-child { margin-bottom: 0; }
.lvName { font-size: 13px; }
/* 꺼 둔 급수도 보여 준다 — 안 보이면 "왜 안 나오지" 가 된다. */
.lvRow.off { opacity: .5; }
.lvNum { font-size: 12px; color: var(--dim); text-align: right;
  font-variant-numeric: tabular-nums; }

/* 급수 줄을 눌러 종류별 진도를 펼친다. button 이라 기본 칠·테두리를 지운다.
   ★ 터치 표적(TODO #26): 급수 줄은 헤더와 같은 --tap-slim 으로 둔다. 잘못 눌러도
     펼쳐지고 접힐 뿐이다. 종류 줄에는 더 이상 체크박스가 없으므로(단어 목록으로
     옮겼다) 표적이 겹칠 일도 없다. */
.lvGroup { margin-bottom: 6px; }
.lvGroup:last-child { margin-bottom: 0; }
button.lvHead {
  width: 100%; background: none; border: 0; padding: 4px 0; margin: 0;
  min-height: var(--tap-slim);
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
button.lvHead .lvName { font-weight: 600; }
/* 종류별 진도 — 이름 / 막대 / 숫자. 읽기 전용이다: 「안다」 체크는 단어
   목록으로 옮겼다(기획서 2026-08-31_단어별_안다와_정직한진도_v1 §5). */
.lvTypes { padding: 0 0 4px 0.6rem; }
.tyProg {
  display: grid; grid-template-columns: 5.6rem 1fr 5.4rem;
  align-items: center; gap: 8px; min-height: 30px;
}
.tyProg .tyName {
  font-size: 12.5px; color: var(--dim);
  display: flex; flex-direction: column; line-height: 1.25;
}
/* 꺼 둔 종류도 보여 준다 — 진도는 종류를 켰는지와 무관하기 때문이다. 다만
   왜 안 줄어드는지 화면이 스스로 답해야 한다. */
.tyProg.off .tyName { opacity: .75; }
.tyOff { font-size: 10.5px; color: var(--warn); }
/* 단어 목록으로 가는 문. 종류 줄 아래에 한 줄로 둔다. */
.wordsLink { margin-top: 6px; width: 100%; }

/* ★ 대시보드 막대. 요소를 붙여 둔다 — 신고창의 <label class="stack"> 과
   이름이 같아서, 이 규칙의 height:14px·overflow:hidden 이 신고 입력란을
   한 줄로 찌그러뜨리고 있었다(실측: textarea 4행이 14px). */
svg.stack { display: block; width: 100%; height: 14px; border-radius: 999px; overflow: hidden; }
.lvBar .stack { height: 10px; }
.bars { display: block; width: 100%; height: 90px; }

/* ---------------------------------------------------------------- 단어 목록
   「안다」를 단어마다 눈으로 보고 체크하는 화면.
   기획서 2026-08-31_단어별_안다와_정직한진도_v1 §4-5. */
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* ★ .dash 와 같은 방식으로 폭을 묶는다. 이 화면만 상한이 없어서 1900px
   모니터에서 패널이 1,885px 이 되고, 단어 칸(1fr)이 1,692px 을 먹었다 —
   실제 글자는 최대 316px 이라 오른쪽으로 1,376px 이 비어 있었고, 단어에서
   그 체크박스까지 눈이 1,400px 를 건너야 했다(실측 2026-08-31).
   ★ 2026-09-01 — 한 줄에 한 단어로 되돌리면서 상한도 .dash 와 같은 760px
   으로 내렸다. 다열일 때는 「여러 벌 늘어놓는 표」라 1500px 이 맞았지만, 한
   열이면 그 폭이 그대로 단어에서 체크박스까지의 빈 거리가 된다. 앱의 읽는
   화면이 전부 760px 이라 폭도 하나로 통일된다.
   기획서 2026-08-31_단어목록_배치정리_v1 §4-1. */
.words { padding: 16px; width: min(760px, 100%); margin: 0 auto; }
.words .dashHead h2 { margin: 0; }
.wordTools { display: flex; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.wordSearch { flex: 1 1 12rem; min-width: 0; }
.wordSearch input {
  width: 100%; min-height: var(--tap); padding: 6px 10px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg); color: var(--ink); font: inherit;
}
.wordFilter select {
  min-height: var(--tap); padding: 6px 10px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg); color: var(--ink); font: inherit;
}
/* 한 줄 = 단어 하나 · 종류 셋. 종류 칸은 손가락 하나(--tap)를 보장한다.
   ★ 밑줄은 마지막 줄에도 긋는다. 목록과 쪽 이동 단추 사이의 경계선 노릇을
   한다. */
.wRow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--tap) var(--tap) var(--tap);
  align-items: center; gap: 4px;
  border-bottom: 1px solid var(--line);
}
/* ★ 붙박이는 머리줄 「칸」이 아니라 머리줄 「격자」(.wordHead)가 진다 —
   아래 .wordHead 참조. 여기 있던 position:sticky 는 스크롤 상자 밖이라
   아무 일도 안 하고 있었다. */
.wHead {
  border-bottom: 1px solid var(--line); padding-bottom: 4px;
  font-size: 12px; color: var(--dim);
}
.wHead .wCk { flex-direction: column; gap: 2px; padding: 4px 0; }
/* 두 줄짜리 제목(한자 / →뜻). 줄 간격을 좁혀야 44px 칸에 체크박스와 함께 든다.
   ★ min-height 로 셋의 높이를 맞춘다 — 「성조」만 한 줄이라 셀이 44px,
   나머지는 52px 이 되어 성조 체크박스만 6px 위로 떠 있었다
   (실측 y 190 / 196 / 196). 기획서 §4-6. */
.wHead b {
  font-weight: 600; font-size: 10.5px; line-height: 1.15; text-align: center;
  display: block; min-height: 2.3em;
}
/* ★ 한자와 병음을 한 줄에 둔다(.wTop). 셋을 각각 한 줄로 두어 한 줄이
   77px 이었는데 터치 표적은 44px 이라 33px 이 순수한 낭비였다. 기획서 §4-4. */
.wZh { min-width: 0; padding: 4px 0; display: flex; flex-direction: column; }
.wTop { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.wZh b { font-size: 17px; font-weight: 600; line-height: 1.25; }
.wPy { font-size: 12px; color: var(--dim); white-space: nowrap; }
/* 뜻은 길면 자른다 — 줄이 늘어나면 100줄이 한눈에 안 들어온다. */
.wKo {
  font-size: 12px; color: var(--dim); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 맞은/틀린 횟수. 종류 칸이 44px 고정이라 왼쪽 단어 칸의 셋째 줄로 간다.
   ★ 경고색을 쓰지 않는다 — 목록 화면의 경고색은 진도 막대가 이미 쓴다.
   기획서 2026-09-03_정오횟수와_전종류_4지선다_v1 §4-3. */
.wScRow {
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  font-size: 11px; color: var(--dim); line-height: 1.3;
}
.wSc { white-space: nowrap; }

.wCk {
  display: flex; align-items: center; justify-content: center;
  min-height: var(--tap); position: relative;
}
.wCk.none { color: var(--dim); opacity: .5; }
.wCk input { width: 18px; height: 18px; margin: 0; cursor: pointer; }
.wCk input:disabled { cursor: default; }
/* 지금 상태를 점으로. 이미 익힌 것을 또 체크하지 않도록.
   ★ 체크박스와 나란히 두면 [18 + gap 3 + 점 6 = 27px] 이 44px 칸에 가운데
   정렬돼 체크박스가 칸 중심에서 4.5px 왼쪽으로 밀렸다. 머리줄에는 점이 없어
   정중앙이라, 머리와 본문의 체크 열이 어긋나 보였다. 겹쳐 띄워 체크박스를
   칸 정중앙으로 되돌린다 — 칸 중심에서 점 끝까지 13px < 22px 이라 옆 칸을
   침범하지 않는다. 기획서 §4-5. */
.dot {
  position: absolute; top: 50%; left: 50%;
  transform: translate(7px, -11px);
  width: 6px; height: 6px; border-radius: 50%;
  background: transparent; pointer-events: none;
}
.st-review   { background: var(--ok); }
.st-learning { background: var(--accent-soft); }
.st-new      { background: var(--line); }
/* ★ 2026-09-01 — 다열 격자를 걷어냈다. 한 열이므로 줄이 그냥 쌓이면 된다.
   머리줄 복제와 열 수 계산(app.js 의 wordCols)도 함께 없앴다. */
/* ★ 자체 스크롤을 없앤다. 머리줄만 스크롤 상자 밖이라 본문보다 스크롤바
   폭(15px)만큼 넓었고, 체크 열이 통째로 어긋나 보였다(실측 1,851 / 1,836).
   .dash 가 이미 같은 이유로 자체 스크롤을 버렸다 — 위 「자체 스크롤을 두지
   않는다」 참조. 기획서 §2-1. */
.wordRows { max-height: none; overflow: visible; }
/* 붙박이 머리줄. ★ top 은 앱 헤더 높이다 — header 에 flex-wrap 이 있어
   375px 에서 두 줄이 되므로 고정값을 못 쓴다. JS 가 --headH 를 잰다.
   z-index 는 앱 헤더(5)보다 낮게 둔다. */
.wordHead {
  position: sticky; top: var(--headH, 0px); z-index: 2;
  background: var(--panel);
}
.wordPager {
  display: flex; align-items: center; gap: 10px; margin-top: 10px;
}
.wordRange {
  flex: 1; text-align: center; font-size: 12.5px; color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.wordPager button { min-height: var(--tap); }

/* 범례 */
/* ── 「어떻게 틀리시나」 패널 ─────────────────────────────────────────
   기획서 2026-09-05_오답이력_보여주기_v1 §4-2.
   ★ 막대 길이는 100% 가 아니라 **가장 못 하는 성조**를 기준으로 늘린다(app.js).
     절대값으로 그리면 전부 짧아져 이 표의 목적(비교)이 사라진다. */
.missHead { font-size: 13px; color: var(--dim); font-weight: 600;
  margin: 14px 0 6px; }
.missHead:first-child { margin-top: 0; }

.missBar { display: flex; align-items: center; gap: 8px; margin: 3px 0; }
.missBarName { flex: none; width: 4.5em; font-size: 13px; }
.missBarTrack { flex: 1; height: 10px; border-radius: 5px;
  background: var(--line); overflow: hidden; }
.missBarTrack i { display: block; height: 100%; background: var(--accent-soft); }
.missBarVal { flex: none; font-size: 13px; font-variant-numeric: tabular-nums; }
.missBarVal small { color: var(--dim); font-size: 11px; }

.missPairs { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px; font-size: 13px; }

.missWords { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 2px; }
.missWordRow { display: flex; align-items: baseline; gap: 8px;
  font-size: 13px; padding: 3px 0; border-bottom: 1px solid var(--line); }
.missWordRow:last-child { border-bottom: 0; }
.missWord { flex: none; min-width: 3.5em; font-size: 16px; }
.missSaid { flex: 1; color: var(--dim); }
.missSaid b { color: var(--ink); }
/* 한 번도 다른 답을 고르신 적이 없는 것 — 여기가 「틀리게 외우신 것」이다. */
.missWordRow.always .missSaid b { color: var(--accent); }
.missN { flex: none; color: var(--dim); font-variant-numeric: tabular-nums; }

/* 「내가 틀린 것 전부 보기」 — 요약이 못 보여주는 것을 여는 단추. */
.ghost.wide { display: block; width: 100%; margin-top: 12px; text-align: center; }

/* ★ 이 창만 폭을 따로 준다 — 공용 `dialog` 는 min(420px, 92vw) 이고 설정 창에는
   그게 맞지만, 여기는 한 줄에 네 칸(단어 · 정답 · 고르신 답 여럿 · 횟수)이 들어간다.
   실측(1280×900 · 실데이터 68줄): 420px 이면 글 칸이 245px 뿐이라 **21줄이 접히고**
   제일 긴 줄이 70px(4줄)였다. 880px 에서 **접힌 줄 0** · 전부 32px 한 줄이다.
   폭을 560·680·760·880 으로 재 보니 한국어 뜻이 긴 줄까지 한 줄에 들어가는 지점이
   880px 이었다(760 에서는 아직 2줄). 그 위로는 더 넓혀도 이득이 없다.
   ★ 폰에서는 폭이 안 변한다 — UA 기본 `dialog{max-width:calc(100% - 2em - 6px)}` 가
   먼저 걸려 375px 에서는 요청 폭과 무관하게 337px 다(92vw 였을 때와 같은 값).
   좁은 창에서 실제로 폭을 정하는 것은 대개 이 UA 상한이고(실측 768px → 715px),
   `94vw` 는 그 사이 구간에서 창이 화면 끝에 닿지 않게 하는 보험이다.
   ID 선택자라 위치와 무관하게 요소 선택자 `dialog` 를 이긴다. */
#mistakeAll { width: min(880px, 94vw); }

/* 자세히 보기 다이얼로그. 세 묶음이 세로로 이어지므로 스스로 스크롤한다.
   ★ 70vh 다 — 폭을 넓혀 줄이 짧아진 만큼 한 화면에 더 담는다(900px 기준 540 → 630px,
   약 3줄). 100vh 로 두지 않는 이유는 제목·설명·「닫기」가 이 밖에 있어서다. */
.mistakeAll { max-height: 70vh; overflow-y: auto; margin: 4px 0 10px; }
.mistakeAll .missHead:first-child { margin-top: 0; }
.mistakeAll .hint { margin: 0 0 6px; }
.missCount { color: var(--dim); font-weight: 400; }

.legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 8px; }
.key { font-size: 12px; color: var(--dim); display: inline-flex; align-items: center; gap: 5px; }
.key i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* 칠 — SVG(fill) 와 범례 칩(background) 을 한 규칙으로 함께 준다 */
.seg-done    { fill: var(--accent); background: var(--accent); }
/* 한 번은 봤지만 아직 안 굳은 것. 익힘과 같은 계열이라 「가는 중」으로 읽힌다. */
.seg-doing   { fill: var(--accent-soft); background: var(--accent-soft); }
.seg-rest    { fill: var(--line);   background: var(--line); }
.seg-new     { fill: var(--warn);   background: var(--warn); }
.seg-learn   { fill: var(--accent); background: var(--accent); }
.seg-relearn { fill: var(--dim);    background: var(--dim); }
.seg-review  { fill: var(--ok);     background: var(--ok); }
/* 「안다」로 체크한 (단어 × 종류). 경고가 아니라 성취 쪽이다 —
   경고색은 화면당 하나(기획서 2026-08-28_부담없는_페이스_v1). */
.seg-known   { fill: var(--ok);     background: var(--ok); }
.bar         { fill: var(--accent); }
.bar.today   { fill: var(--ok); }
.bar.over    { fill: var(--dim); }

/* 종류별 줄 — 기획서 2026-08-27_밀린카드_표시와_급수전환_v1.
   ★ 「카드 상태」만 전체 카드를 세고 나머지 패널은 현재 모드만 센다. 그
   차이를 화면이 스스로 말하게 하는 자리다. */
.tyList { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 10px; }
/* ★ 4열이다 — 「안 꺼냄」 칸을 더하면서 3열로 두면 넷째 자식이 암묵 행으로
   내려가 줄 높이가 두 배가 된다(375px 실렌더에서 확인). 간격은 12→10 으로
   줄여 좁은 화면에서 이름 칸이 눌리지 않게 한다. */
/* ★ 두 칸이다 — 이름과 장수. 예전에는 「기다림 45 안 꺼냄 53」까지 네 칸이었는데,
   조사도 서술어도 없는 나열이라 읽히지 않았다(2026-08-28 사장님 지적).
   상태별 숫자는 바로 위 막대가 이미 말한다. */
.tyRow {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 10px;
  align-items: baseline; font-size: 14px; padding: 3px 0;
}
.tyRow.off { opacity: .55; }
.tyRow .n {
  color: var(--dim); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* 힌트 + 동작 버튼 한 줄. 힌트는 패널당 하나라는 규칙을 유지한다. */
.actRow {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px;
}
.actRow .hint { margin: 0; }
.act {
  padding: 6px 12px; font-size: 13px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--accent); background: transparent; color: var(--accent);
  font-family: inherit; white-space: nowrap;
}
.act:disabled { opacity: .5; cursor: default; }


/* 오늘 아직 복습을 안 해 연속이 끊길 참이라는 표시.
   기획서 2026-08-28_밀림우선_연습기록_v1. */
/* 오늘 목표를 채운 타일. ★ 경고(--warn)가 아니라 성취(--ok) 쪽 색이다 —
   이 화면에서 색을 쓰는 유일한 자리가 「하셨습니다」여야 한다. */
.tile.done { border-color: var(--ok); }
.tile.done b, .tile.done span { color: var(--ok); }

/* ================= 터치 표적 (TODO #26) =================
   실측(375px): 헤더 21~29px · 설정 체크박스 13px · 빈 화면 25px.
   권장은 44px 인데 전부 미달이었다. 사장님이 폰으로 쓰신다.

   두 가지를 나눠 쓴다 —
     · 헤더 = 보이는 크기 36px + ::after 로 탭 영역만 44px. 헤더는 sticky 라
       실제로 44px 로 키우면 375px 에서 두 줄 × 44px 이 화면에 붙박인다
     · 그 밖(대화상자·빈 화면·카드) = 진짜 44px. 세로 공간이 넉넉하다

   ★ ::after 는 위아래로 (44-36)/2 = 4px 씩 삐져나온다. 헤더가 줄바꿈되므로
     row-gap 을 14px 로 올려 위 줄의 탭 영역이 아래 줄을 가로채지 않게 한다
     (남는 간격 14-4-4 = 6px). gap 을 줄이면 이 계산이 깨진다.
   ★ <select> 에는 ::after 가 안 붙는다(대체 요소). 그래서 종류 콤보박스만
     실제 높이를 36px 로 둔다 — 네이티브 콤보라 탭 허용 오차가 크다. */

header { gap: 14px 10px; }

.brand, .chip.pick, .ghost, .badge.report {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap-slim);
}
/* 배치는 그대로 두고 탭 영역만 넓힌다. */
.brand::after, .chip.pick::after, .ghost::after, .badge.report::after {
  content: ''; position: absolute; left: 0; right: 0;
  top: 50%; transform: translateY(-50%); height: var(--tap);
}
.chip.sel { min-height: var(--tap-slim); }

/* 헤더 밖은 진짜로 키운다. */
#empty .primary, #empty .ghost, .act,
.dashHead .primary,
dialog menu button {
  min-height: var(--tap); padding-left: 18px; padding-right: 18px;
}
/* 위에서 .ghost 에 준 ::after 가 여기서는 필요 없다 — 이미 44px 이다.
   남겨 두면 44px 짜리가 44px 을 덮을 뿐이라 무해하지만, 인접 컨트롤과
   겹칠 여지를 없애기 위해 끈다. */
#empty .ghost::after { content: none; }

.grades button { min-height: var(--tap); }
.speak { width: var(--tap); height: var(--tap); font-size: 19px; }

/* 설정 — 여기가 가장 나빴다(체크박스 13px). 라벨이 입력을 감싸므로
   라벨을 키우면 탭 표적이 그대로 커진다. */
dialog label { min-height: var(--tap); display: flex; align-items: center; }
dialog label.stack { display: flex; align-items: stretch; }
dialog .chips label, .levels label { min-height: var(--tap); }
dialog input[type=checkbox], dialog input[type=radio] {
  width: 20px; height: 20px; margin-right: 4px; flex: none;
}
dialog select, dialog input[type=number] { min-height: var(--tap); }
/* 슬라이더는 트랙이 16px 이라 손가락으로 잡기 어렵다. 상자 높이만 키우면
   네이티브 트랙이 가운데 정렬되면서 위아래 여백까지 잡히는 영역이 된다.
   ★ 손잡이(::-webkit-slider-thumb)는 건드리지 않는다 — 그걸 스타일하려면
     appearance:none 이 필요하고, 그 순간 트랙까지 직접 그려야 한다. */
dialog input[type=range] { height: var(--tap); }

/* 각주 링크는 문장 안의 인라인 링크라 여기서 제외한다 — 세로로 키우면
   줄 간격이 무너지고, 접근성 기준도 인라인 링크는 예외로 둔다. */

/* ★ 라벨을 44px 로 키우자 설정창이 774px(뷰포트 812px)이 되어 「저장」이
   스크롤 밖으로 밀렸다 — 실측으로 잡은 자기 회귀다. 버튼 줄을 바닥에
   붙여 창이 아무리 길어져도 항상 닿게 한다. */
dialog menu {
  position: sticky; bottom: -20px; z-index: 1;
  background: var(--panel); margin-bottom: -20px;
  padding: 10px 0 20px; border-top: 1px solid var(--line);
}

/* ★ 손가락으로 쓰는 기기에서는 헤더도 진짜 44px 로 올린다.
   `::after` 확장은 <select> 에 안 붙어서 카드 종류 콤보박스만 36px 로 남았다.
   --tap-slim 을 --tap 과 같게 만들면 콤보박스까지 44px 이 되고, 확장이
   요소와 같은 크기가 되어 이웃을 가로챌 여지도 사라진다.
   실측(375×812): 헤더 111 → 127px · 학습 영역 701 → 685px(-2.3%) · 넘침 0.
   마우스(pointer: fine)에서는 그대로 36px — 커서는 정확해서 넓힐 이유가 없다. */
@media (pointer: coarse) {
  :root { --tap-slim: var(--tap); }
}
