/*! 왕관유자 디자인 시스템 v3 — crownyuja.co.kr/ds/v3/yuja.css
 *  빌드 2026-10-14 20:30 · 원본 ds/src-v3/ (직접 수정 금지)
 *  규격: 왕관유자_디자인시스템_v4.md (프로젝트 루트)
 */
/* ===== tokens.css ===== */
/* ============================================================
   왕관유자 디자인 시스템 ds/v3 (규격 v4 「햇살 든 유자」) — 토큰
   crownyuja.co.kr/ds/v3/

   규격 정본: 프로젝트 루트 왕관유자_디자인시스템_v4.md §11
   ⚠ 이 파일 밖에서 색·간격·모서리·모션 값을 새로 정의하지 않는다.

   두 겹 바탕(유자 속껍질빛 캔버스 + 미색 카드) · 유자 일곱 단계 · 그림자 4단.
   누를 것 = 유자 300 · 고른 것 = 유자 200 + 600 테두리 · 지금 메뉴 = 유자 100.
   v2·v1 토큰 이름은 별칭으로 남긴다 — 지우지 않는다(가산 전용).
   ============================================================ */

:root {
  /* ── 두 겹 바탕과 먹 ─────────────────────────────── */
  --yj-canvas:      #F3EFE4;   /* 페이지 바탕 — 유자 속껍질빛 */
  --yj-card:        #FFFDF7;   /* 카드·패널·입력·메뉴바 — 미색 종이 */
  --yj-card-hi:     #FFFFFF;   /* 팝오버·모달 — 가장 앞 */
  --yj-line:        #E8E2D3;
  --yj-line-strong: #D7CFBC;
  --yj-ink-deep:    #16181A;   /* 제목 · 유자 위 글자 (캔버스 15.5:1) */
  --yj-ink:         #333333;   /* 본문 (캔버스 11.0:1) */
  --yj-sub:         #66655F;   /* 보조 글자 (캔버스 5.09 · 카드 5.75) */
  --yj-faint:       #A3A29E;   /* 장식·비활성 전용 */
  --yj-on-ink:      #FFFFFF;

  /* ── 유자 일곱 단계 (제품 테마가 덮어쓴다) ─────────────
     50 = 원색 12% · 100 = 22% · 200 = 33% · 300 = 65% (흰색 위) · 600 = 원색에 검정 10% */
  --yj-yuja-50:   #FEF7E0;   /* 안내 상자 · 목록 행 hover */
  --yj-yuja-100:  #FDF1C8;   /* 지금 메뉴 알약 · 유자 배지 · 보조 버튼 */
  --yj-yuja-200:  #FCEAAA;   /* 고른 칩·세그먼트 면 */
  --yj-yuja-300:  #F9D75E;   /* 부드러운 유자 — 주 버튼 · 고른 필터 칩 */
  --yj-yuja-500:  #F5C800;   /* 원색 — 로고 · 진도 막대 · 누름 · 밑줄 표식 */
  --yj-yuja-600:  #DDB400;   /* 테두리 — 고른 것 · 입력 포커스 */
  --yj-yuja-ink:  #7D6500;   /* 유자 틴트 위 글자 */
  --yj-on-action: #16181A;   /* 유자 위 글자 — 다크 모드에서도 먹 */

  /* ── 잎 · 주황 · 숲 ─────────────────────────────── */
  --yj-leaf:         #4CAA48;
  --yj-leaf-press:   #2D7A29;
  --yj-leaf-tint:    rgba(76, 170, 72, .14);
  --yj-leaf-ink:     #2F7A2C;
  --yj-leaf-solid:   #2F7A2C;
  --yj-orange:       #F08C1E;   /* 알림 숫자 · 배움 지면 입력 포커스 */
  --yj-orange-press: #D97A0F;
  --yj-orange-tint:  rgba(240, 140, 30, .15);
  --yj-orange-ink:   #9A5508;
  --yj-forest:       #142814;
  --yj-on-forest:    #FFFFFF;

  --yj-grad:      linear-gradient(135deg, var(--yj-yuja-500) 0%, var(--yj-orange) 100%);
  --yj-grad-soft: linear-gradient(135deg, var(--yj-yuja-50) 0%, var(--yj-yuja-100) 100%);

  /* ── 의미색 ────────────────────────────────────────── */
  --yj-success:      var(--yj-leaf);
  --yj-success-tint: var(--yj-leaf-tint);
  --yj-success-ink:  var(--yj-leaf-ink);
  --yj-warn:         #E67E22;
  --yj-error:        #C82014;
  --yj-error-press:  #A81A10;
  --yj-error-ink:    #C82014;
  --yj-error-tint:   rgba(200, 32, 20, .10);
  --yj-on-danger:    #FFFFFF;
  --yj-book:         #A8452F;
  --yj-book-tint:    #F9EAE4;
  --yj-overlay:      rgba(23, 21, 14, .40);

  /* ── v2(규격 v3) 이름 별칭 ────────────────────────── */
  --yj-paper:            var(--yj-card);
  --yj-paper-sub:        var(--yj-canvas);
  --yj-amber:            var(--yj-yuja-500);
  --yj-amber-press:      var(--yj-yuja-600);
  --yj-amber-tint:       var(--yj-yuja-100);
  --yj-amber-tint-press: var(--yj-yuja-200);
  --yj-amber-ink:        var(--yj-yuja-ink);
  /* ── v1 이름 별칭 (v1 의 --yj-canvas 는 '흰 종이'였다 — v4 에서는 회색 바탕이다) ── */
  --yj-cream:           var(--yj-card);
  --yj-surface:         var(--yj-canvas);
  --yj-surface-2:       var(--yj-line);
  --yj-hairline:        var(--yj-line);
  --yj-hairline-strong: var(--yj-line-strong);
  --yj-slate:           var(--yj-sub);
  --yj-steel:           var(--yj-faint);
  --yj-on-dark:         #FFFFFF;

  /* ── 모서리 · 모션 · 간격 (규격 v3 과 같다) ─────────── */
  --yj-r-xs: 4px;  --yj-r-sm: 8px;  --yj-r-lg: 12px;  --yj-r-full: 9999px;
  --yj-m-fast: 120ms;  --yj-m-mid: 200ms;  --yj-m-slow: 320ms;
  --yj-ease: cubic-bezier(.2, .8, .2, 1);
  --yj-s1:  4px;  --yj-s2:  8px;  --yj-s3: 12px;  --yj-s4: 16px;
  --yj-s5: 24px;  --yj-s6: 32px;  --yj-s7: 48px;  --yj-s8: 64px;

  /* ── 서체 ──────────────────────────────────────────── */
  --yj-font-ui:    "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
                   "Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", sans-serif;
  --yj-font-disp:  "Paperlogy", var(--yj-font-ui);
  --yj-font-serif: "Noto Serif KR", "Nanum Myeongjo", serif;
  --yj-font-hanja: var(--yj-font-serif);
  --yj-font-mono:  ui-monospace, "SF Mono", Consolas, monospace;

  --yj-t-disp:  34px;  --yj-t-hanja: 22px;  --yj-t-h2: 20px;  --yj-t-vocab: 20px;
  --yj-t-body:  17px;  --yj-t-small: 15px;  --yj-t-vch: 14px; --yj-t-cap: 13px;
  --yj-t-label: 12px;  --yj-t-micro: 11px;
  --yj-lh-ui: 1.6;  --yj-lh-read: 2.0;  --yj-measure: 680px;

  /* ── 셸 ────────────────────────────────────────────── */
  --yj-dock-h: 56px;
  --yj-tap:    44px;
  --yj-safe-t: env(safe-area-inset-top, 0px);
  --yj-safe-b: env(safe-area-inset-bottom, 0px);
  --yj-safe-l: env(safe-area-inset-left, 0px);
  --yj-safe-r: env(safe-area-inset-right, 0px);
  --yj-float-gap: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s4));

  /* ── 깊이 4단 — 따뜻한 먹 그림자 ───────────────────── */
  --yj-sh-0: none;
  --yj-sh-1: 0 1px 2px rgba(31, 28, 18, .05), 0 6px 18px -8px rgba(31, 28, 18, .12);
  --yj-sh-2: 0 2px 4px rgba(31, 28, 18, .06), 0 16px 32px -12px rgba(31, 28, 18, .20);
  --yj-sh-3: 0 24px 56px -16px rgba(31, 28, 18, .30);
  /* v2 이름 */
  --yj-sh-card:  var(--yj-sh-1);
  --yj-sh-float: var(--yj-sh-2);
  --yj-sh-modal: var(--yj-sh-3);
  --yj-sh-sheet: 0 -8px 32px rgba(31, 28, 18, .18);
  --yj-sh-toast: var(--yj-sh-2);
}

/* ── 다크 모드 「밤의 숲」 — 페이지가 고를 때만 켠다 ───────
   <html data-yj-dark="auto"> 기기 설정을 따른다 · <html data-theme="dark"> 늘 다크
   배움 지면은 교실 프로젝터 확인 전까지 켜지 않는다. */
@media (prefers-color-scheme: dark) {
  :root[data-yj-dark="auto"]:not([data-theme="light"]) {
    --yj-canvas: #100F0C; --yj-card: #1C1B17; --yj-card-hi: #25241F; --yj-line: #312F28; --yj-line-strong: #423F36;
    --yj-ink-deep: #FFFFFF; --yj-ink: #ECECE8; --yj-sub: #A3A39E; --yj-faint: #5E625E; --yj-on-ink: #121412;
    --yj-yuja-50: rgba(245, 200, 0, .08); --yj-yuja-100: rgba(245, 200, 0, .14); --yj-yuja-200: rgba(245, 200, 0, .22); --yj-yuja-ink: #F5C800;
    --yj-orange-tint: rgba(240, 140, 30, .20); --yj-orange-ink: #F08C1E;
    --yj-leaf-tint: rgba(76, 170, 72, .20); --yj-leaf-ink: #6CC368;
    --yj-forest: #1E3D1E; --yj-error-ink: #FF6B5E; --yj-error-tint: rgba(255, 107, 94, .14);
    --yj-overlay: rgba(0, 0, 0, .60);
    --yj-sh-1: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 18px -8px rgba(0, 0, 0, .6);
    --yj-sh-2: 0 2px 4px rgba(0, 0, 0, .4), 0 16px 32px -12px rgba(0, 0, 0, .7);
    --yj-sh-3: 0 24px 56px -16px rgba(0, 0, 0, .8);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --yj-canvas: #100F0C; --yj-card: #1C1B17; --yj-card-hi: #25241F; --yj-line: #312F28; --yj-line-strong: #423F36;
  --yj-ink-deep: #FFFFFF; --yj-ink: #ECECE8; --yj-sub: #A3A39E; --yj-faint: #5E625E; --yj-on-ink: #121412;
  --yj-yuja-50: rgba(245, 200, 0, .08); --yj-yuja-100: rgba(245, 200, 0, .14); --yj-yuja-200: rgba(245, 200, 0, .22); --yj-yuja-ink: #F5C800;
  --yj-orange-tint: rgba(240, 140, 30, .20); --yj-orange-ink: #F08C1E;
  --yj-leaf-tint: rgba(76, 170, 72, .20); --yj-leaf-ink: #6CC368;
  --yj-forest: #1E3D1E; --yj-error-ink: #FF6B5E; --yj-error-tint: rgba(255, 107, 94, .14);
  --yj-overlay: rgba(0, 0, 0, .60);
  --yj-sh-1: 0 1px 2px rgba(0, 0, 0, .4), 0 6px 18px -8px rgba(0, 0, 0, .6);
  --yj-sh-2: 0 2px 4px rgba(0, 0, 0, .4), 0 16px 32px -12px rgba(0, 0, 0, .7);
  --yj-sh-3: 0 24px 56px -16px rgba(0, 0, 0, .8);
  color-scheme: dark;
}

/* ===== base.css ===== */
/* ============================================================
   기본 — reset · 활자 역할 · 포커스 · 아이콘
   crownyuja.co.kr/ds/v3/  (규격 v4 §5 · §6 · §7-8)
   ============================================================ */

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

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

body {
  margin: 0;
  font-family: var(--yj-font-ui);
  font-size: var(--yj-t-body);
  line-height: var(--yj-lh-ui);
  letter-spacing: -.01em;
  word-break: keep-all;
  overflow-wrap: break-word;
  color: var(--yj-ink);
  background: var(--yj-canvas);           /* v4: 페이지는 캔버스, 내용은 카드 */
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
svg { flex: none; }

button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }

/* 포커스 — 마우스로는 안 보이고 키보드로는 또렷하게. 먹 2px + 2px 간격 */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--yj-yuja-600);
  outline-offset: 2px;
  border-radius: var(--yj-r-xs);
}

/* 모션 민감 사용자 존중 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── 아이콘 — 이모지 대신 단순한 SVG (규격 §7-8) ─────────
   <svg class="yj-ic" aria-hidden="true"><use href="#i-check"/></svg>
   24 격자 · 선 1.6 · currentColor · 채움 없음 */
.yj-ic {
  width: 20px; height: 20px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  flex: none; display: inline-block; vertical-align: -.2em;
}
.yj-ic--24 { width: 24px; height: 24px; }
.yj-ic--28 { width: 28px; height: 28px; }
.yj-ic--16 { width: 16px; height: 16px; }

/* ── 활자 역할 ────────────────────────────────────────
   원칙 ①: 한자는 주인공이 아니다.
   뜻·음(.yj-disp 34px)이 주인공, 한자(.yj-hanja 22px 회색)는 출처 표기. */

.yj-disp {
  margin: 0;
  font-family: var(--yj-font-disp);
  font-size: var(--yj-t-disp);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -.02em;
  color: var(--yj-ink-deep);
}
.yj-hanja {
  margin: 0;
  font-family: var(--yj-font-hanja);
  font-size: var(--yj-t-hanja);
  font-weight: 600;
  line-height: 1.3;
  color: var(--yj-sub);
}
.yj-h2 {
  margin: 0;
  font-family: var(--yj-font-disp);
  font-size: var(--yj-t-h2);
  font-weight: 800;
  line-height: 1.35;
  color: var(--yj-ink-deep);
}
.yj-vocab {
  margin: 0;
  font-size: var(--yj-t-vocab);
  font-weight: 700;
  line-height: 1.3;
  color: var(--yj-ink-deep);
}
.yj-vocab-hanja {
  margin: 0;
  font-family: var(--yj-font-hanja);
  font-size: var(--yj-t-vch);
  font-weight: 500;
  color: var(--yj-sub);
}
.yj-body  { margin: 0; font-size: var(--yj-t-body); line-height: var(--yj-lh-ui); color: var(--yj-ink); }
.yj-small { margin: 0; font-size: var(--yj-t-small); line-height: 1.8; color: var(--yj-sub); }
.yj-cap   { margin: 0; font-size: var(--yj-t-cap); font-weight: 500; color: var(--yj-sub); }
/* 글자 표식 — 회차·요소·분류. 12 · 700 · 유자 황토 */
.yj-label {
  margin: 0;
  font-size: var(--yj-t-label);
  font-weight: 700;
  letter-spacing: .04em;
  line-height: 1.4;
  color: var(--yj-amber-ink);
}

/* 읽기 지면 제목 — 세리프 (해피·교사자료·안내 글) */
.yj-title-xl, .yj-title-l, .yj-title-m, .yj-title-s {
  margin: 0;
  font-family: var(--yj-font-serif);
  font-weight: 600;
  color: var(--yj-ink-deep);
  text-wrap: balance;
}
.yj-title-xl { font-size: clamp(34px, 5.2vw, 52px); line-height: 1.25; letter-spacing: -.04em; }
.yj-title-l  { font-size: clamp(28px, 4.4vw, 40px); line-height: 1.4;  letter-spacing: -.04em; }
.yj-title-m  { font-size: 20px; line-height: 1.45; letter-spacing: -.03em; }
.yj-title-s  { font-size: 17px; line-height: 1.5;  letter-spacing: -.02em; }
@media (max-width: 640px) { .yj-title-m { font-size: 18px; } }
.yj-lead {
  margin: 0;
  font-family: var(--yj-font-serif);
  font-size: 19px;
  font-weight: 500;
  line-height: 1.9;
  color: var(--yj-ink-deep);
}
/* 긴 글 본문 — 17 · 2.0 · 680 */
.yj-prose {
  max-width: var(--yj-measure);
  font-size: var(--yj-t-body);
  line-height: var(--yj-lh-read);
  color: var(--yj-ink);
}
.yj-prose p { margin: 0 0 1.7em; }

.yj-num { font-variant-numeric: tabular-nums; }

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

/* ===== shell.css ===== */
/* ============================================================
   앱 셸 — 모바일 안전영역
   crownyuja.co.kr/ds/v3/

   원칙: 페이지는 자기 위치를 정하지 않는다. 셸이 정한다.

   이 프로젝트에서 가장 자주 재발한 문제가 하단바 겹침이었다.
   원인은 100vh 84곳, viewport-fit=cover 49곳 대비 보상 18곳,
   그리고 페이지 고유 선택자를 하드코딩한 600줄짜리 !important 패치였다.
   페이지가 매직넘버로 기기 바를 피해 다니는 한 영원히 재발한다.
   ============================================================ */

/* 필수 meta:
   <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

   골격:
   <body class="yj-shell">
     <header class="yj-shell__bar">…</header>
     <main   class="yj-shell__body">…</main>
     <nav    class="yj-shell__dock">…</nav>
     <div    class="yj-shell__float">…</div>
   </body>                                                        */

.yj-shell {
  /* 부유 요소 기준선 — 이 요소에서 계산해야 --stacked(104px) 를 따라온다.
     :root 에만 두면 56px 로 굳어 2단 도크에서 FAB·토스트가 깔린다. */
  --yj-float-gap: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s4));

  min-height: 100dvh;              /* 100vh 금지 — 모바일에서 기기 바를 포함한다 */
  margin: 0;
  display: flex;
  flex-direction: column;
  /* 규격 v4: 페이지는 캔버스, 내용은 그 위의 미색 카드(base.css body 와 같다).
     v1 의 --yj-cream 을 그대로 두면 상단바·도크(card)와 본문이 같은 미색이 되어 1px 선으로만 갈린다. */
  background: var(--yj-canvas);
  color: var(--yj-ink);
  padding-left: var(--yj-safe-l);
  padding-right: var(--yj-safe-r);
  position: relative;
}
@supports not (min-height: 100dvh) {
  .yj-shell { min-height: 100vh; }  /* 구형 브라우저 폴백 */
}

/* ── 상단바 — 56px + 상단 안전영역 ─────────────────────── */
.yj-shell__bar {
  flex: none;
  height: calc(var(--yj-dock-h) + var(--yj-safe-t));
  padding-top: var(--yj-safe-t);          /* 제목이 노치 아래에 놓인다 */
  padding-left: var(--yj-s2);
  padding-right: var(--yj-s2);
  /* 규격 v4 §7-5: 불투명 미색 card + 1px 선. v1 에서 이 자리는 --yj-canvas(그때는 흰 종이)였다 —
     v4 의 canvas 는 페이지 바탕(#F3EFE4)이라 그대로 두면 상단바가 바탕에 묻힌다(2026-10-14). */
  background: var(--yj-card);
  border-bottom: 1px solid var(--yj-hairline);
  display: flex;
  align-items: center;
  gap: 2px;
  position: sticky;
  top: 0;
  z-index: 12;
}
.yj-shell__title {
  flex: 1;
  min-width: 0;
  padding: 0 var(--yj-s1);
  font-family: var(--yj-font-disp);
  font-size: 18px;
  font-weight: 800;
  color: var(--yj-ink-deep);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── 본문 — 도크에 절대 가리지 않는다 ──────────────────── */
.yj-shell__body {
  flex: 1;
  padding: var(--yj-s4);
  padding-bottom: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s4));
  display: flex;
  flex-direction: column;
  gap: var(--yj-s5);
}
.yj-shell__body--flush { padding-left: 0; padding-right: 0; }
.yj-shell__body--tight { gap: var(--yj-s4); }

/* ── 하단 도크 — 56px + 하단 안전영역 ──────────────────── */
.yj-shell__dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  height: calc(var(--yj-dock-h) + var(--yj-safe-b));
  padding-bottom: var(--yj-safe-b);       /* 탭이 홈 인디케이터 위에 놓인다 */
  padding-left: var(--yj-safe-l);
  padding-right: var(--yj-safe-r);
  /* 불투명이다. 반투명(.96)이면 뒤로 흐르는 목록 글자가 **비쳐 보인다**
     (2026-08-13 실측: serial-order 에서 도크 칸 사이로 "[1권_1]" 이 비쳤다).
     흐림으로 가릴 수도 없다 — backdrop-filter 는 스킬 §6 이 금지한다
     (교실 저사양 크롬북에서 스크롤 프레임이 무너진다).
     가릴 수 없으면 투명하지 않는 것이 답이다.
     규격 v4 §7-5: 불투명 미색 card + 위 1px 선 — canvas(페이지 바탕)로 칠하면 바탕에 묻힌다. */
  background: var(--yj-card);
  border-top: 1px solid var(--yj-hairline);
  display: flex;
  align-items: stretch;
  z-index: 16;
}
.yj-shell__dock a {
  flex: 1;
  min-height: var(--yj-tap);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  font-weight: 700;
  /* 비활성 탭도 읽혀야 한다. --yj-steel(#9B9A97) 은 흰 바탕에서 **2.81:1** 로
     10.5px 라벨에 AA(4.5:1) 미달이었다(2026-08-13 실측).
     --yj-slate 로 한 단 진하게 — 5.0:1. 초등 대상이라 접근성은 요건이다(§1). */
  color: var(--yj-slate);
  text-decoration: none;
  position: relative;
  min-width: 0;                     /* flex 아이템이 라벨 폭에 밀려 넘치지 않게 */
  transition: color var(--yj-m-fast) var(--yj-ease);
}
/* 라벨 — SKILL.md §3-B 실측 기준.
   최장 라벨 '매일학습'(4자)이 320px 기기(칸 53.3px)에서도 잘리지 않는 조합이다.
   6칸을 유지하려면 이 세 값이 한 벌로 움직인다. 하나만 바꾸지 않는다. */
.yj-shell__dock a > span {
  font-size: 10.5px;
  letter-spacing: -.045em;
  transform: scale(.92);
  white-space: nowrap;              /* 두 줄로 접히면 도크 높이가 무너진다 */
  line-height: 1.1;
}
.yj-shell__dock a > svg { flex: none; }
.yj-shell__dock a.is-on { color: var(--yj-ink-deep); }
.yj-shell__dock a.is-on > span { font-weight: 800; }
/* 규격 v4: 지금 칸은 유자 100 알약 면 (칸 안쪽 4px 여백) */
.yj-shell__dock a.is-on { isolation: isolate; }
.yj-shell__dock a.is-on::before {
  content: "";
  position: absolute;
  inset: 4px 6px;
  z-index: -1;
  border-radius: var(--yj-r-lg);
  background: var(--yj-yuja-100);
}

/* ── 도크만 먼저 붙이는 페이지 (이관 전 다리) ─────────────
   W1 에서 탭바를 25페이지에 얹는데, 그중 대부분은 아직 .yj-shell 이 아니다.
   셸 없이 fixed 도크만 넣으면 본문 끝이 도크 뒤로 들어간다.

   그래서 '도크가 먹는 높이만큼의 아래 여백'만 주는 다리를 둔다.
   .yj-shell 을 씌우지 못하는 화면(hanja-detail·search 처럼 데스크톱 폭을
   지켜야 하는 곳)에는 이관이 끝난 뒤에도 이게 정본으로 남는다.

   ⚠ 이건 축소가 아니라 '셸의 값만 빌리는' 형태다 — SKILL.md §4 참조. */
.yj-dock-compat {
  --yj-float-gap: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s4));
  padding-bottom: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s4));
}
/* compat 페이지의 도크는 상단으로 올리지 않는다(아래 .yj-shell 전용 전환 참조) —
   그래서 데스크톱에서도 하단 여백을 그대로 유지한다. 별도 규칙 불필요. */

/* ── 도크와 겹치는 옛 헤더 항목 ────────────────────────────
   이관 전 페이지들은 자기 상단바에 홈·검색을 이미 갖고 있다.
   도크가 같은 자리를 맡으면 **같은 버튼이 위아래로 둘**이 된다(2026-08-13 실기 확인).

   지우지 않고 감춘다. 마크업을 지우면 JS 결합점과 ds-guard 불변식이 함께 깨진다(규약 1).
   그 페이지가 실제로 .yj-shell 을 입는 단계에서 옛 헤더째 정리된다.

   ⚠ 클래스를 세 번 겹쳐 쓴 이유 (오타가 아니다) —
     app-safe-area.css:81 에 `.header-fixed > nav > * { display: flex !important }` 가 있다.
     둘 다 !important 라 특이도로 갈리는데 그쪽이 (0,2,1), 이쪽이 (0,1,0) 이라 진다.
     실측으로 확인했다: 클래스는 붙었는데 display 가 flex 로 남아 있었다.
     세 번 겹치면 (0,3,0) 이 되어 이긴다.

     이건 그 패치 더미가 사라지면 함께 정리할 임시방편이다.
     SKILL §4 가 app-safe-area.css 를 하단바 겹침의 근본 원인으로 지목하고 있고,
     축소는 27개 페이지 전수 재검증이 필요해 D구간으로 미뤄져 있다. */
.yj-dock-dup.yj-dock-dup.yj-dock-dup { display: none !important; }

/* ── 물러난 옛 상단바 ──────────────────────────────────────
   도크가 항목을 다 가져가서 남은 게 뒤로·앞으로뿐이면, 56px 짜리 바를
   그것만으로 유지할 이유가 없다(2026-08-13 사용자 확정 — 목차 3장).

   뒤로가기를 잃지 않는 근거:
     · 브라우저 — 자체 뒤로가기가 있다
     · 앱(WebView) — MainActivity 가 안드로이드 시스템 뒤로가기를
       webView.canGoBack()/goBack() 으로 받는다 (확인함)
   '앞으로가기'만 사라진다. 시스템 대응이 없지만 학습 동선에서 쓰임이 드물다.

   ⚠ 헤더가 아직 제 역할을 하는 페이지(hanja-detail·search)에는 쓰지 않는다.
      항목이 다 빠진 뒤에만 쓴다. */
.yj-topbar-retired.yj-topbar-retired.yj-topbar-retired { display: none !important; }

/* 상단바를 없앴는데 그 아래 필터바가 여전히 `top: 56px` 로 고정돼 있으면,
   빈 56px 자리가 그대로 남는다(2026-08-14 PC 실측 — 스크롤하면 옛 헤더 자리가 비어 보였다).
   페이지 CSS 를 직접 고치는 대신 여기서 한 번에 끌어올린다 — 상단바 유무와
   필터바 위치가 항상 같이 움직이게, 두 규칙이 따로 놀며 다시 어긋나지 않게.
   :has() 특이도 (0,2,1) 가 페이지의 평범한 클래스 선택자 (0,1,0) 를 자연히 이긴다.
   모바일 기본값이다 — 데스크톱은 바로 아래에서 도크 높이만큼 다시 밀어낸다. */
body:has(.yj-topbar-retired) .filter-container-fixed,
body:has(.yj-topbar-retired) .quiz-type-bar-fixed,
body:has(.yj-topbar-retired) #quiz-type-bar {
  top: 0;
}

/* ── 도크 위치 원칙 — 모바일·앱은 하단, PC는 상단 (2026-08-14 사용자 확정)
   ────────────────────────────────────────────────────────────
   .yj-shell 정식 셸은 이미 이 원칙대로 동작한다(§ 데스크톱 — 도크를 상단으로).
   .yj-dock-compat 페이지는 대개 자기만의 기존 헤더가 있어 도크를 상단에
   못 올린다 — 올리면 헤더가 두 겹이 된다(§ hanja-detail 실측 참조).

   그런데 **옛 헤더를 이미 없앤 페이지**(.yj-topbar-retired)는 다르다.
   부딪힐 상대가 없으니 도크를 상단으로 올려도 안전하다. 그래서 전환 조건을
   ".yj-shell" 이 아니라 "옛 헤더가 없다"로 잡는다 — 앞으로 다른 compat
   페이지가 이관되며 헤더를 retire 시킬 때마다 이 전환을 자동으로 받는다.

   compat 페이지는 셸의 flex-column 구조가 없어 order:-1 트릭이 안 통한다.
   그래서 sticky 가 아니라 **fixed 로 top:0** 를 준다 — 모바일과 똑같이
   fixed 이고 top/bottom 만 바뀐다. 문서 흐름을 안 차지하므로, 도크가 여는
   자리는 아래 세 규칙이 대신 메운다. */
@media (min-width: 768px) {
  body:has(.yj-topbar-retired) .yj-shell__dock {
    position: fixed;
    top: 0; bottom: auto;
    height: var(--yj-dock-h);
    padding-bottom: 0;
    border-top: 0;
    border-bottom: 1px solid var(--yj-hairline);
    justify-content: center;
    gap: var(--yj-s5);
  }
  body:has(.yj-topbar-retired) .yj-shell__dock a {
    flex: none; flex-direction: row; gap: var(--yj-s2); padding: 0 var(--yj-s3);
  }
  body:has(.yj-topbar-retired) .yj-shell__dock a > span {
    font-size: 14px; letter-spacing: normal; transform: none;
  }
  /* 규격 v4 §7-2: 상단 메뉴의 지금 칸 = 유자 100 알약(높이 36).
     칸은 56 - 아래 선 1 = 55 라서 위 10 · 아래 9 로 둔다(선까지 치면 위아래 10 씩).
     v1 의 밑줄 표시(top:auto · bottom:0)를 모바일 알약(inset 4px 6px) 위에 얹으면
     높이가 0 이 되어 PC 에서 표시가 사라졌다(2026-10-14 실측). */
  body:has(.yj-topbar-retired) .yj-shell__dock a.is-on::before {
    top: 10px; bottom: 9px; left: 0; right: 0; border-radius: var(--yj-r-full);
  }

  /* 필터바 — 도크(56px) 아래로. 위 모바일 규칙(top:0)을 여기서 덮는다. */
  body:has(.yj-topbar-retired) .filter-container-fixed,
  body:has(.yj-topbar-retired) .quiz-type-bar-fixed,
  body:has(.yj-topbar-retired) #quiz-type-bar {
    top: var(--yj-dock-h);
  }

  /* 본문 — 도크가 여는 56px 를 body 여백에 더한다.
     JS(updateBodyPadding)가 body.style.paddingTop 을 인라인으로 계산해 넣는데,
     그 계산은 옛 헤더(0)+필터높이+16 뿐이라 도크의 존재를 모른다.
     margin 은 별개 속성이라 인라인 padding 과 부딪히지 않고 그대로 더해진다 —
     margin(56) + padding(필터+16) = 원하는 총 여백이 자동으로 나온다.
     ⚠ !important — 소스 순서상 페이지 자체 body 규칙이 나중에 로드된다. */
  body:has(.yj-topbar-retired) {
    margin-top: var(--yj-dock-h) !important;
  }

  /* 도크가 하단에서 빠졌으니 dock-compat 의 하단 여백(도크 몫)도 필요 없다. */
  body.yj-dock-compat:has(.yj-topbar-retired) {
    padding-bottom: var(--yj-s6) !important;
  }
}

/* ── 몰입 화면의 퇴장 버튼 ────────────────────────────────
   게임 화면은 도크를 달지 않는다(몰입). 대신 **나가는 길이 확실해야** 한다
   (2026-08-14 사용자 확정: "도크 숨김 처리하고 퇴장하는 확실한 버튼만 있으면 된다").

   실측에서 문제가 나왔다 — crossword/game.html 의 퇴장 버튼이 **28×28** 이었다.
   SKILL §1 의 최소 터치 타깃은 44×44 이고, 초등 대상이라 이건 취향이 아니라 요건이다.
   게다가 그 페이지엔 퇴장 버튼이 둘인데 하나는 좁은 화면에서 숨겨져 있어,
   실제로 누를 수 있는 건 그 28px 짜리 하나뿐이었다.

   페이지마다 손대는 대신 여기서 바닥을 깐다. 모양(배경·모서리)은 건드리지 않는다 —
   페이지가 이미 자기 색을 갖고 있고, 여기서 필요한 건 '닿는 크기'뿐이다. */
.yj-exit {
  min-width: var(--yj-tap);
  min-height: var(--yj-tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

/* ── 도크 순환 안내 — 2초 뒤 사라진다 ──────────────────────
   '목차' 한 칸이 연번·한자·어휘를 돌기 때문에, 그걸 모르는 사용자에게
   한 번 알려 준다. **스크립트를 쓰지 않는다** — 규약 2 안에서 끝내려고
   CSS 애니메이션으로만 만들었다(등장 0.32s → 2s 유지 → 사라짐).

   ⚠ 그래서 페이지를 열 때마다 뜬다. '한 번만 보여주기'는 localStorage 가
      필요해 스크립트 없이는 안 된다 — 필요하면 별도 티켓. */
.yj-dock-hint {
  position: fixed;
  left: 50%;
  bottom: calc(var(--yj-dock-h) + var(--yj-safe-b) + var(--yj-s2));
  transform: translateX(-50%);
  z-index: 17;
  max-width: calc(100% - var(--yj-s6));
  padding: 8px 14px;
  border-radius: var(--yj-r-full);
  background: rgba(20, 24, 16, .82);   /* 반투명 회색 — 잠깐 떴다 사라지는 안내다 */
  color: #FFFFFF;
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;                /* 탭을 가로채지 않는다 */
  opacity: 0;
  animation: yj-dock-hint 2.64s var(--yj-ease) forwards;
}
@keyframes yj-dock-hint {
  0%   { opacity: 0; transform: translateX(-50%) translateY(6px); }
  12%  { opacity: 1; transform: translateX(-50%) translateY(0); }
  88%  { opacity: 1; transform: translateX(-50%) translateY(0); }
  100% { opacity: 0; transform: translateX(-50%) translateY(6px); }
}
@media (prefers-reduced-motion: reduce) {
  /* 움직임을 줄여 달라고 한 사용자에게는 뜨고 지는 것만 남긴다 */
  .yj-dock-hint { animation-name: yj-dock-hint-fade; }
  @keyframes yj-dock-hint-fade {
    0%, 100% { opacity: 0; } 12%, 88% { opacity: 1; }
  }
}

/* ── 하단은 도크 자리다 — 페이지 헤더를 상단으로 되돌린다 (W4 · 2026-08-13)
   ────────────────────────────────────────────────────────
   app-safe-area.css 는 **도크가 없던 시절** 모바일에서 페이지 헤더를
   하단으로 보냈다(`.header-fixed`/`#topbar` 를 `bottom:0 !important`).
   엄지 도달을 위한 합리적인 임시방편이었다.

   이제 하단에는 진짜 탭바가 있다. 둘이 **같은 자리에서 정면으로 겹친다** —
   실측(2026-08-13): 헤더 z-20 이 도크 z-16 을 56px 전면으로 덮어
   **5개 페이지에서 도크가 아예 보이지 않았다**
   (search · vocabulary · serial-order · hanja-sound · hanja-detail).
   W1 실기 확인은 헤더가 없는 셸 페이지만 봐서 드러나지 않았다.

   그래서 도크를 받은 compat 페이지에서는 헤더를 제자리(상단)로 돌린다.
   목업의 배치와도 같다 — appbar 위, dock 아래.

   ⚠ app-safe-area.css 에는 규칙을 넣지 않는다(SKILL §4). 그 파일은 27페이지가
     공유하고 사본이 3개로 갈라져 있다. 전환을 소유하는 것은 디자인시스템이다.
   ⚠ 매직넘버를 쓰지 않는다 — 높이·안전영역 모두 토큰이다. */
.yj-dock-compat .header-fixed,
.yj-dock-compat #topbar {
  top: 0 !important;
  bottom: auto !important;
  height: calc(var(--yj-dock-h) + var(--yj-safe-t)) !important;
  padding-top: var(--yj-safe-t) !important;
  padding-bottom: 0 !important;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .12) !important;
}

/* 헤더가 위로 갔으니 본문도 그만큼 위를 비운다.
   app-safe-area 의 padding-top 은 헤더가 아래 있다는 전제로 8px 만 준다.

   ⚠ 선택자가 긴 이유 — app-safe-area 의
       body:has(.header-fixed):not(:has(.filter-container-fixed))
           :not(:has(.quiz-type-bar-fixed)):not(.home-page)
     가 **특이도 0,4,1** 이라 짧게 쓰면 진다(실측: search.html 만 8px 로 남았다).
     그래서 조건을 실제로 다 적어 0,5,1 로 맞춘다. 억지 해킹이 아니라
     "도크와 고정 헤더를 **둘 다** 가진 compat 페이지" 라는 뜻 그대로다. */
body.yj-dock-compat:has(.header-fixed):has(.yj-shell__dock):not(.home-page):not(.slide-page),
body.yj-dock-compat:has(#topbar):has(.yj-shell__dock):not(.home-page):not(.slide-page) {
  padding-top: calc(var(--yj-dock-h) + var(--yj-safe-t)) !important;
}

/* ── 2단 바 (퀴즈 유형 바 등) ───────────────────────────
   페이지가 매직넘버를 계산하지 않는다. 셸이 도크 높이를 2배로 잡는다. */
.yj-shell--stacked { --yj-dock-h: 104px; }

/* ── 전체화면 (게임·슬라이드) ─────────────────────────
   도크를 숨기고 안전영역만 적용한다. */
.yj-shell--immersive .yj-shell__dock { display: none; }
.yj-shell--immersive .yj-shell__body {
  padding: var(--yj-safe-t) var(--yj-safe-r) var(--yj-safe-b) var(--yj-safe-l);
}

/* ── 부유 요소 — 도크 위에 뜨는 것들 ────────────────────
   FAB·토스트는 여기에만 넣는다. bottom 은 --yj-float-gap 하나만 쓴다.
   페이지마다 110px·120px·180px 을 손으로 계산하던 방식을 대체한다. */
.yj-shell__float {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 17;
  pointer-events: none;
}
.yj-shell__float > * {
  position: fixed;
  bottom: var(--yj-float-gap);
  pointer-events: auto;
}

/* ── 데스크톱 — 도크를 상단으로 ────────────────────────
   모바일이 기준이고, 넓은 화면에서 상단 내비로 전환한다. */
@media (min-width: 768px) {
  .yj-shell__body {
    max-width: 720px;
    margin: 0 auto;
    width: 100%;
    padding-bottom: var(--yj-s6);
  }
  /* ⚠ 도크를 상단으로 올리는 전환은 .yj-shell 정식 셸에만 적용한다.
     .yj-dock-compat 페이지(아직 이관 전)는 대개 자기만의 기존 헤더를 이미
     갖고 있다 — hanja-detail 의 #topbar(fixed top·뒤로/앞으로/홈/검색/연번/
     한자/어휘)가 실례다. 그런 페이지에서 도크까지 위로 올리면 헤더가 둘이 되어
     겹친다(2026-08-13 실기 확인). 그 페이지들이 실제로 .yj-shell 을 입는
     이관 단계(W3~W7)에서 기존 헤더를 걷어내며 이 전환도 함께 받는다.
     그때까지 compat 페이지의 도크는 모든 화면 폭에서 하단 고정으로 둔다. */
  .yj-shell .yj-shell__dock {
    position: sticky;
    top: 0; bottom: auto;
    height: var(--yj-dock-h);
    padding-bottom: 0;
    border-top: 0;
    border-bottom: 1px solid var(--yj-hairline);
    order: -1;
    justify-content: center;
    gap: var(--yj-s5);
  }
  /* 상단바는 도크 '아래'에 붙는다.
     둘 다 sticky top:0 이면 스크롤할 때 겹치고, z-index 가 낮은 상단바가
     도크 뒤로 숨는다. 도크가 상단을 차지하는 폭에서만 생기는 문제다. */
  .yj-shell .yj-shell__bar { top: var(--yj-dock-h); }

  /* 제목이 본문 열과 같은 선에서 시작하게 한다.
     바는 배경·경계선을 위해 폭을 다 쓰지만, 글자는 본문(720px)에 맞춘다.
     이걸 안 하면 1920px 화면에서 제목만 왼쪽 끝에 홀로 떨어진다. */
  .yj-shell__bar {
    padding-left:  max(var(--yj-s2), calc((100% - 720px) / 2 + var(--yj-s4)));
    padding-right: max(var(--yj-s2), calc((100% - 720px) / 2 + var(--yj-s4)));
  }
  .yj-shell__title { padding-left: 0; padding-right: 0; }

  .yj-shell .yj-shell__dock a { flex: none; flex-direction: row; gap: var(--yj-s2); padding: 0 var(--yj-s3); }
  /* 넓은 화면에서는 좁힐 이유가 없다 — 모바일용 축소를 되돌린다 */
  .yj-shell .yj-shell__dock a > span { font-size: 14px; letter-spacing: normal; transform: none; }
  /* 지금 칸 — 유자 100 알약(높이 36). 위 compat 전환 주석 참조 */
  .yj-shell .yj-shell__dock a.is-on::before { top: 10px; bottom: 9px; left: 0; right: 0; border-radius: var(--yj-r-full); }
  .yj-shell__float > * { bottom: var(--yj-s5); }
}

/* ===== components.css ===== */
/* ============================================================
   컴포넌트 — crownyuja.co.kr/ds/v3/  (규격 v4 §7)

   규격 v4 「햇살 든 유자」: 누를 것 = 유자 300, 고른 것 = 유자 200 + 600 테두리,
   지금 메뉴 = 유자 100 알약, 이룬 것 = 잎. 카드는 미색 + 그림자 1, hover 2.
   버튼은 5종이 전부다. v1·v2 클래스 이름은 모두 남기고 모양만 바꾼다(가산 전용).
   ============================================================ */

/* ── 버튼 5종 ──────────────────────────────────────────── */
.yj-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--yj-s2);
  height: var(--yj-tap);
  min-width: var(--yj-tap);
  padding: 0 20px;                     /* 높이 × 0.45 */
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  border: 0;
  border-radius: var(--yj-r-sm);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background-color var(--yj-m-fast) var(--yj-ease),
              color var(--yj-m-fast) var(--yj-ease),
              border-color var(--yj-m-fast) var(--yj-ease),
              transform var(--yj-m-mid) var(--yj-ease);
}
.yj-btn .yj-ic { width: 18px; height: 18px; }
.yj-btn:disabled, .yj-btn[aria-disabled="true"] {
  opacity: .4; cursor: not-allowed; transform: none;
}

/* 화면당 1개. 지금 눌러야 할 것. 단색 — 그라데이션·빛나는 그림자 없음 */
.yj-btn--primary {
  height: 52px;
  padding: 0 24px;
  font-size: 16px;
  border-radius: var(--yj-r-full);
  background: var(--yj-yuja-300);
  color: var(--yj-on-action);          /* 유자 위 흰 글자는 금지 */
}
.yj-btn--primary:hover:not(:disabled) { background: var(--yj-yuja-500); }
.yj-btn--primary:active:not(:disabled) { background: var(--yj-yuja-500); transform: scale(.97); }

/* 대등한 다른 선택. 테두리가 아니라 틴트 */
.yj-btn--secondary { background: var(--yj-yuja-100); color: var(--yj-yuja-ink); }
.yj-btn--secondary:hover:not(:disabled),
.yj-btn--secondary:active:not(:disabled) { background: var(--yj-yuja-200); }

/* 취소·나중에·이전/다음 글 */
.yj-btn--ghost { background: transparent; color: var(--yj-sub); }
.yj-btn--ghost:hover:not(:disabled) { color: var(--yj-ink-deep); }

/* 되돌릴 수 없는 것 — 확인 모달 필수 */
.yj-btn--danger { background: var(--yj-error); color: var(--yj-on-danger); }
.yj-btn--danger:hover:not(:disabled) { background: var(--yj-error-press); }

/* 아이콘 전용 — aria-label 필수 */
.yj-btn--icon {
  width: var(--yj-tap);
  padding: 0;
  border-radius: var(--yj-r-full);
  background: transparent;
  color: var(--yj-sub);
}
.yj-btn--icon .yj-ic { width: 20px; height: 20px; }
.yj-btn--icon:hover:not(:disabled) { color: var(--yj-ink-deep); }
.yj-btn--icon:active:not(:disabled) { transform: scale(.97); }
.yj-btn--float {
  background: var(--yj-card-hi);
  border: 1px solid var(--yj-line-strong);
  box-shadow: var(--yj-sh-float);
}
.yj-btn--float:hover:not(:disabled) { border-color: var(--yj-ink-deep); }

.yj-btn--sm    { height: 36px; font-size: 14px; padding: 0 16px; }
.yj-btn--md    { height: 44px; font-size: 15px; padding: 0 20px; }
.yj-btn--lg    { height: 52px; font-size: 16px; padding: 0 24px; }
.yj-btn--block { width: 100%; }

/* ── 고르는 부품 — 고른 것은 유자 ───────────────────────── */
.yj-chip {
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  height: 36px; padding: 0 14px;
  border: 1px solid var(--yj-line-strong);
  border-radius: var(--yj-r-full);
  background: var(--yj-paper);
  color: var(--yj-sub);
  font-size: 13px; font-weight: 500;
  white-space: nowrap; text-decoration: none; cursor: pointer;
  transition: border-color var(--yj-m-fast) var(--yj-ease), color var(--yj-m-fast) var(--yj-ease),
              background-color var(--yj-m-fast) var(--yj-ease);
}
.yj-chip::before { content: ""; position: absolute; inset: -4px 0; }  /* 터치 44 */
.yj-chip:hover { border-color: var(--yj-ink-deep); color: var(--yj-ink-deep); }
.yj-chip.is-on, .yj-chip[aria-pressed="true"], .yj-chip[aria-current="true"], .yj-chip[aria-selected="true"] {
  background: var(--yj-yuja-300); border-color: var(--yj-yuja-300); color: var(--yj-on-action);
}

/* 세그먼트 — 같은 데이터를 '어떻게 볼지' 고른다 (연번 / 한자 / 어휘)
   <nav class="yj-seg"><a class="is-on">연번</a><a>한자</a><a>어휘</a></nav> */
.yj-seg {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--yj-line-strong);
  border-radius: var(--yj-r-full);
  background: var(--yj-paper);
}
.yj-seg > * {
  flex: 1;
  min-width: 0;
  height: 34px;
  padding: 0 14px;
  display: flex; align-items: center; justify-content: center;
  font-size: 13.5px; font-weight: 600;
  color: var(--yj-sub);
  text-decoration: none; white-space: nowrap;
  border-radius: var(--yj-r-full);
  transition: color var(--yj-m-fast) var(--yj-ease), background-color var(--yj-m-fast) var(--yj-ease);
}
.yj-seg > *:hover { color: var(--yj-ink-deep); }
.yj-seg > .is-on, .yj-seg > [aria-pressed="true"], .yj-seg > [aria-selected="true"] {
  background: var(--yj-yuja-200);
  color: var(--yj-ink-deep);
  box-shadow: inset 0 0 0 1px var(--yj-yuja-600);
}
/* 색이 있는 바 위의 세그먼트 — 형태만 만들고 색은 페이지 것이 이긴다 (v1 실측 결정 유지) */
.yj-seg--onbar {
  background: transparent;
  border: 1.5px solid rgba(20, 24, 16, .55);
  padding: 2px;
  gap: 0;
}
.yj-seg--onbar > * { color: inherit; }

/* 밑줄 탭 — 같은 화면 안의 다른 내용 (뜻 / 문장 / 동음) */
.yj-tabs {
  display: flex;
  gap: 28px;
  border-bottom: 1px solid var(--yj-line);
  padding: 0 var(--yj-s4);
  background: var(--yj-paper);
  overflow-x: auto;
  scrollbar-width: none;
}
.yj-tabs::-webkit-scrollbar { display: none; }
.yj-tabs > * {
  flex: none;
  height: 48px;
  padding: 0;
  margin-bottom: -1px;
  display: flex; align-items: center;
  font-size: 15px; font-weight: 500;
  color: var(--yj-sub);
  border-bottom: 2px solid transparent;
  position: relative;
  white-space: nowrap;
  text-decoration: none;
  transition: color var(--yj-m-fast) var(--yj-ease), border-color var(--yj-m-fast) var(--yj-ease);
}
.yj-tabs > *:hover { color: var(--yj-ink-deep); }
.yj-tabs > .is-on, .yj-tabs > [aria-selected="true"] {
  color: var(--yj-ink-deep); font-weight: 700; border-bottom-color: var(--yj-yuja-500);
}

/* 상단 글자 메뉴 — 지금 메뉴는 유자 100 알약 (규격 v4 §7-2 · §7-5)
   <nav class="yj-menu"><a class="is-on">급수</a><a>목차</a></nav> */
.yj-menu { display: flex; align-items: center; gap: 2px; }
.yj-menu > * {
  display: inline-flex; align-items: center; height: 36px; padding: 0 14px;
  border-radius: var(--yj-r-full); color: var(--yj-sub); font-size: 15px; font-weight: 600;
  text-decoration: none; white-space: nowrap;
  transition: color var(--yj-m-fast) var(--yj-ease), background-color var(--yj-m-fast) var(--yj-ease);
}
.yj-menu > *:hover { color: var(--yj-ink-deep); }
.yj-menu > .is-on, .yj-menu > [aria-current="page"] { background: var(--yj-yuja-100); color: var(--yj-ink-deep); font-weight: 700; }

/* 페이지 번호 */
.yj-pager { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.yj-pager > a, .yj-pager > button {
  position: relative;
  min-width: 32px; height: 32px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--yj-r-full);
  color: var(--yj-sub); font-size: 14px; font-weight: 500; text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.yj-pager > a::before, .yj-pager > button::before { content: ""; position: absolute; inset: -6px; }
.yj-pager > :hover { color: var(--yj-ink-deep); }
.yj-pager > .is-on, .yj-pager > [aria-current="page"] { background: var(--yj-yuja-200); color: var(--yj-ink-deep); }

/* ── 카드 — 미색 · 1px 선 · 12 · 그림자 1 (hover 2 + 2px 올림) ── */
.yj-card {
  background: var(--yj-card);
  border: 1px solid var(--yj-line);
  border-radius: var(--yj-r-lg);
  padding: var(--yj-s5);
  box-shadow: var(--yj-sh-1);
}
a.yj-card { color: inherit; text-decoration: none; transition: box-shadow var(--yj-m-mid) var(--yj-ease), transform var(--yj-m-mid) var(--yj-ease); }
a.yj-card:hover { box-shadow: var(--yj-sh-2); transform: translateY(-2px); }
a.yj-card:active { transform: scale(.98); }
.yj-card--tight { padding: var(--yj-s4); }
.yj-card--dark  { background: var(--yj-forest); border-color: var(--yj-forest); color: var(--yj-on-forest); }
.yj-card--dark .yj-cap { color: rgba(255, 255, 255, .72); }
.yj-card--sub   { background: var(--yj-yuja-50); box-shadow: none; }
.yj-card--leaf  { background: var(--yj-leaf-tint);  border-color: transparent; }
.yj-card--amber { background: var(--yj-amber-tint); border-color: transparent; }

/* ── 목록 — 상자 대신 선 ─────────────────────────────────
   카드가 10장 쌓이면 벽지다. 한 덩어리로 묶고 행 사이에 1px 선. */
.yj-list {
  background: var(--yj-card);
  border: 1px solid var(--yj-line);
  border-radius: var(--yj-r-lg);
  overflow: hidden;
  box-shadow: var(--yj-sh-1);
}
.yj-list--bare { border: 0; border-radius: 0; overflow: visible; }
.yj-list__item {
  display: flex;
  align-items: center;
  gap: var(--yj-s3);
  min-height: 56px;
  padding: var(--yj-s3) var(--yj-s4);
  position: relative;
  color: inherit;
  text-decoration: none;
  transition: background-color var(--yj-m-fast) var(--yj-ease);
}
a.yj-list__item:hover { background: var(--yj-yuja-50); }
.yj-list__item + .yj-list__item::before {
  content: "";
  position: absolute;
  top: 0; left: var(--yj-s4); right: 0;
  height: 1px;
  background: var(--yj-line);
}
.yj-list__grow { flex: 1; min-width: 0; }
.yj-list__chev { color: var(--yj-faint); flex: none; }

/* 역할색 아이콘 상자 — 틴트 면 + 글자색 아이콘 */
.yj-icon-role {
  width: 34px; height: 34px;
  border-radius: var(--yj-r-sm);
  flex: none;
  display: flex; align-items: center; justify-content: center;
}
.yj-icon-role--amber  { background: var(--yj-amber-tint);  color: var(--yj-amber-ink); }
.yj-icon-role--orange { background: var(--yj-orange-tint); color: var(--yj-orange-ink); }
.yj-icon-role--leaf   { background: var(--yj-leaf-tint);   color: var(--yj-leaf-ink); }
.yj-icon-role--ink    { background: var(--yj-paper-sub);   color: var(--yj-sub); }

/* 목록 머리 — 세리프 + 아래 먹 선 (읽기 지면) */
.yj-list-head {
  padding: 4px 0 20px;
  border-bottom: 1px solid var(--yj-ink-deep);
  font-family: var(--yj-font-serif);
  font-size: 14px; font-weight: 500;
  color: var(--yj-sub);
}
/* 글 한 줄 — 위아래 28 · 아래 1px 선 · 제목 hover 밑줄 */
.yj-post { display: block; padding: 28px 2px; border-bottom: 1px solid var(--yj-line); color: inherit; text-decoration: none; }
.yj-post:hover .yj-title-m { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }
@media (max-width: 640px) { .yj-post { padding: 24px 0; } }

/* ── 상자 3종 (지식 · 왕관유자로 읽기 · 체크리스트) ────── */
.yj-kbox { padding: 28px; border: 1px solid var(--yj-line); border-radius: var(--yj-r-lg); background: var(--yj-card); box-shadow: var(--yj-sh-1); }
/* 안내 상자 — 유자 50 면 + 왼쪽 2px 유자 500 (규격 v4 §7-5) */
.yj-callout { padding: 14px 18px; border-radius: var(--yj-r-lg); background: var(--yj-yuja-50); border-left: 2px solid var(--yj-yuja-500); color: var(--yj-ink); }
.yj-wbox { padding: 16px 20px; border-radius: var(--yj-r-lg); background: var(--yj-amber-tint); }
.yj-cbox { padding: 16px 20px; border-radius: var(--yj-r-lg); border: 1px solid var(--yj-line-strong); }
@media (max-width: 640px) { .yj-kbox { padding: 20px; } }

/* ── 입력 ─────────────────────────────────────────────
   기본은 종이 + 테두리. 배움 지면 검색창은 주황 틴트로 "여기서 시작하세요". */
.yj-input {
  display: flex;
  align-items: center;
  gap: var(--yj-s2);
  width: 100%;
  height: var(--yj-tap);
  padding: 0 16px;
  border-radius: var(--yj-r-xs);
  background: var(--yj-card);
  border: 1px solid var(--yj-line-strong);
  color: var(--yj-ink-deep);
  font-size: 17px;                      /* 16px 미만이면 iOS가 확대한다 */
  font-weight: 400;
  transition: border-color var(--yj-m-fast) var(--yj-ease), box-shadow var(--yj-m-fast) var(--yj-ease);
}
.yj-input::placeholder { color: var(--yj-sub); }
.yj-input:focus, .yj-input:focus-within { outline: none; border-color: var(--yj-yuja-600); box-shadow: 0 0 0 1px var(--yj-yuja-600); }
.yj-input__icon { color: var(--yj-orange-ink); flex: none; }
.yj-input--learn {
  background: var(--yj-yuja-50);
  border-color: var(--yj-line-strong);
}
.yj-input--learn:focus, .yj-input--learn:focus-within { border-color: var(--yj-orange); box-shadow: 0 0 0 1px var(--yj-orange); }
.yj-input--plain { background: var(--yj-paper-sub); border-color: transparent; color: var(--yj-ink); }
.yj-input--error { border-color: var(--yj-error-ink); }
.yj-input:disabled { opacity: .4; cursor: not-allowed; }

/* ── 태그·배지 — 세 가지만 ───────────────────────────────
   글자 표식(.yj-label) · 외곽선 칩(.yj-tag) · 틴트 알약(.yj-pill--*)
   원색으로 채운 배지는 쓰지 않는다. */
.yj-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 10px;
  border: 1px solid var(--yj-line-strong);
  border-radius: var(--yj-r-full);
  font-size: 12px;
  font-weight: 500;
  background: transparent;
  color: var(--yj-sub);
  white-space: nowrap;
}
.yj-tag--amber  { background: var(--yj-amber-tint);  border-color: transparent; color: var(--yj-amber-ink); font-weight: 600; }
.yj-tag--orange { background: var(--yj-orange-tint); border-color: transparent; color: var(--yj-orange-ink); font-weight: 600; }
.yj-tag--leaf   { background: var(--yj-leaf-tint);   border-color: transparent; color: var(--yj-leaf-ink); font-weight: 600; }
.yj-tag--book   { background: var(--yj-book-tint);   border-color: transparent; color: var(--yj-book); font-weight: 600; }
.yj-pill {
  display: inline-flex; align-items: center; gap: 4px;
  height: 24px; padding: 0 10px;
  border-radius: var(--yj-r-full);
  font-size: 12px; font-weight: 600; white-space: nowrap;
}
.yj-pill .yj-ic { width: 14px; height: 14px; stroke-width: 2; }
.yj-pill--leaf   { background: var(--yj-leaf-tint);   color: var(--yj-leaf-ink); }
.yj-pill--amber  { background: var(--yj-amber-tint);  color: var(--yj-amber-ink); }
.yj-pill--orange { background: var(--yj-orange-tint); color: var(--yj-orange-ink); }
.yj-pill--error  { background: var(--yj-error-tint);  color: var(--yj-error-ink); }

/* ── 진도 막대 — 유자가 익어가는 방향 (그라데이션은 여기에만) ── */
.yj-bar {
  height: 8px;
  border-radius: var(--yj-r-full);
  background: var(--yj-line);
  overflow: hidden;
}
.yj-bar > i {
  display: block;
  height: 100%;
  border-radius: var(--yj-r-full);
  background: var(--yj-grad);
  transition: width var(--yj-m-slow) var(--yj-ease);
}
.yj-bar--on-dark { background: rgba(255, 255, 255, .18); }
.yj-bar--leaf > i { background: var(--yj-leaf); }

/* ── 정답 · 주의 · 빈 화면 ─────────────────────────────── */
.yj-answer {
  display: flex; align-items: center; gap: var(--yj-s3);
  padding: var(--yj-s3) var(--yj-s4);
  border-radius: var(--yj-r-sm);
  background: var(--yj-leaf-tint);
  color: var(--yj-leaf-ink); font-weight: 600;
}
.yj-answer--wrong { background: var(--yj-error-tint); color: var(--yj-error-ink); }
.yj-answer__dot {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--yj-r-full);
  background: var(--yj-leaf-solid); color: #FFFFFF;
}
.yj-answer--wrong .yj-answer__dot { background: var(--yj-error); }
.yj-answer__dot .yj-ic { width: 16px; height: 16px; stroke-width: 2.2; }
.yj-notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: var(--yj-s3) var(--yj-s4);
  border-radius: var(--yj-r-sm);
  background: var(--yj-orange-tint);
  color: var(--yj-ink); font-size: 15px; line-height: 1.6;
}
.yj-notice > .yj-ic { color: var(--yj-orange-ink); margin-top: 2px; }
.yj-empty { display: grid; justify-items: center; gap: var(--yj-s2); padding: var(--yj-s6) var(--yj-s4); text-align: center; color: var(--yj-sub); }
.yj-empty > .yj-ic { width: 28px; height: 28px; color: var(--yj-faint); }

/* ── 읽기 부품 — 인용 · 결론 · 대사 말풍선 ──────────────── */
.yj-quote {
  margin: var(--yj-s7) 0;
  padding: 2px 0 2px 22px;
  border-left: 2px solid var(--yj-ink-deep);
  font-family: var(--yj-font-serif);
  font-size: 19px; font-weight: 500; line-height: 1.85;
  color: var(--yj-ink-deep);
}
.yj-conclusion { margin-top: var(--yj-s7); padding-top: 28px; border-top: 1px solid var(--yj-line); font-size: 15px; line-height: 1.8; color: var(--yj-sub); }
.yj-say { display: flex; align-items: flex-start; gap: var(--yj-s3); margin: .7em 0; }
.yj-say.is-right { flex-direction: row-reverse; }
.yj-say__who { flex: 0 0 44px; display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: 11px; color: var(--yj-sub); }
.yj-say__ava { width: 34px; height: 34px; border-radius: var(--yj-r-full); background: var(--yj-paper-sub); border: 1px solid var(--yj-line); object-fit: cover; }
.yj-say__bub { max-width: 78%; padding: 7px 14px; border-radius: var(--yj-r-lg); background: var(--yj-paper-sub); line-height: 1.75; color: var(--yj-ink-deep); font-weight: 500; }
.yj-say.is-me .yj-say__bub { background: var(--yj-amber-tint); }

/* ── 시트 · 모달 ───────────────────────────────────────── */
.yj-scrim {
  position: fixed; inset: 0; z-index: 18;
  background: var(--yj-overlay);
}
.yj-sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 19;
  background: var(--yj-card-hi);
  border-radius: var(--yj-r-lg) var(--yj-r-lg) 0 0;
  padding: var(--yj-s2) var(--yj-s4) calc(var(--yj-safe-b) + var(--yj-s3));
  box-shadow: var(--yj-sh-sheet);
}
.yj-sheet__grab {
  width: 36px; height: 4px;
  border-radius: var(--yj-r-full);
  background: var(--yj-line-strong);
  margin: var(--yj-s2) auto var(--yj-s3);
}
.yj-modal {
  width: 100%; max-width: 400px;
  padding: 28px 24px 20px;
  border-radius: var(--yj-r-lg);
  background: var(--yj-card-hi);
  box-shadow: var(--yj-sh-3);
}

/* ── 토스트 · FAB (반드시 .yj-shell__float 안에) ────────── */
.yj-toast {
  left: var(--yj-s4); right: var(--yj-s4);
  display: flex;
  align-items: center;
  gap: var(--yj-s2);
  padding: var(--yj-s3) var(--yj-s4);
  border-radius: var(--yj-r-lg);
  background: var(--yj-forest);
  color: var(--yj-on-forest);
  font-size: 15px;
  font-weight: 600;
  box-shadow: var(--yj-sh-toast);
}
.yj-toast .yj-ic { color: var(--yj-amber); }
.yj-toast--light {
  background: var(--yj-card-hi);
  color: var(--yj-ink);
  border: 1px solid var(--yj-line);
}
.yj-fab {
  right: var(--yj-s4);
  width: 44px; height: 44px;
  border-radius: var(--yj-r-full);
  background: var(--yj-card-hi);
  border: 1px solid var(--yj-line-strong);
  color: var(--yj-sub);
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--yj-sh-float);
}

/* ── 도서 전용 안내 (보류 중 기능 — 2026-09-11 완전 오픈) ── */
.yj-book-note {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--yj-s2);
  padding: var(--yj-s4);
  border-radius: var(--yj-r-lg);
  background: var(--yj-book-tint);
  text-align: center;
}
.yj-book-note__title { font-size: 15px; font-weight: 800; color: var(--yj-book); line-height: 1.45; }
.yj-book-note__sub   { font-size: 13px; color: var(--yj-book); }

/* ── 유틸 (최소한만) ───────────────────────────────────── */
.yj-row   { display: flex; align-items: center; gap: var(--yj-s3); }
.yj-col   { display: flex; flex-direction: column; gap: var(--yj-s2); }
.yj-between { justify-content: space-between; }
.yj-grow  { flex: 1; min-width: 0; }
