/* 팔레트·디자인 토큰·화면 스타일. 폰 폭 기준으로 먼저 맞춘다.
   색·간격·타이포·radius·측정폭은 :root 에만 정의한다 — 나머지 규칙과 템플릿은 var() 만
   쓴다. 지켜졌는지는 `grep -n '#[0-9a-fA-F]\{3,6\}' app/static/style.css` 로 잰다:
   :root 와 라이트 모드 블록 밖에 걸리는 줄이 있으면 어긴 것이다. */

/* 다크가 기본이다. 라이트는 prefers-color-scheme 로만 갈아탄다 (수동 토글 없음).
   2026-09-06 은수 「paper.design 느낌으로, 어둡고 눈만 편하게」 — 청록 기운을 걷고 **무채색 다크 + 따뜻한 미색 글자**.
   paper.design 실측: 배경은 순 무채 18% 회색, 글자는 미색(순백 아님), 흐린 글자 두 단계, 테두리 흰 8%, 큰 글자는 가늘게(360). */
:root {
  --bg: #171717;
  --surface: #1e1e1e;
  --text: #ecebe3;           /* 순백이 아니라 미색 — 다크에서 눈을 덜 찌른다 */
  --muted: #8f8f8a;
  --muted-2: #5c5c58;        /* 더 흐린 단계 — 셈·구분자·설명 */
  --accent-read: #4ec9b0;    /* 청록 = 읽는 축 (진도·완독·링크). 쓰는 자리를 절반으로 줄였다 — 나머지는 미색 */
  --accent-review: #b9a8e8;  /* 파스텔 보라 = 인용 등 남기는 축 */
  --border: #2b2b2b;         /* ≈ 흰 8% on #171717 */
  /* 채움(진행바)에 쓰는 원색. 다크에선 글자색과 같다. */
  --fill-read: #4ec9b0;
  --link: var(--accent-read);
  color-scheme: dark light;

  /* 코드 하이라이트(Pygments 토큰 클래스) 색. 축을 뜻하는 두 색(청록·보라)과 겹치지
     않게 별도 색상을 쓴다 — 그 둘은 "무슨 축의 일인지"를 뜻하므로 코드 색으로
     재사용하면 그 뜻이 흐려진다. */
  --syn-comment: #7d8f88;
  --syn-keyword: #7aa2f7;
  --syn-string: #e0af68;
  --syn-number: #e8a8c0;
  --syn-name: #e0d070;
  --syn-error: #f7768e;
  --wrong: #f7768e;         /* 오답 표시 — syn-error 와 값은 같지만 뜻이 다르다 */

  /* 형광펜 3색. 색깔이 곧 뜻이다 — 나중에 색으로 걸러 되돌아오기 위한 분류다.
     노랑=중요 / 청록=알겠다 / 빨강=모르겠다. 늘리기 전에 "이 색으로 뭘 할 건가"를
     먼저 답할 것(app/highlights.py COLORS 와 짝이다 — 한쪽만 늘리면 어긋난다). */
  --hl-yellow: #5f5220;
  --hl-teal: #1d5349;
  --hl-red: #63272d;
  --hl-yellow-edge: #b9a04a;
  --hl-teal-edge: #4ec9b0;
  --hl-red-edge: #d06b74;

  /* 그래프 패널 — 옵시디언 그래프뷰 톤. 노드는 거의 흰 점, 선은 거의 안 보일
     만큼 흐리다(중심만 청록으로 도드라진다). */
  /* 관련 항목 무리 색 — 어느 점이 어느 갈래인지 색으로 가른다. 파스텔로 눕혀
     읽는 축(청록)·남기는 축(보라)의 뜻과 부딪히지 않게 한다. */
  --g0: #81e4d2;
  --g1: #e3a0dc;
  --g2: #aed07c;
  --g3: #819fe4;
  --g4: #e3a0a1;
  --g5: #7cd093;
  --g6: #ba81e4;
  --g7: #e3daa0;
  --g8: #7cc3d0;
  --g9: #e481b8;
  --g10: #b2e3a0;
  --g11: #7e7cd0;
  --g12: #e4a181;
  --g13: #a0e3c9;
  --g14: #c87cd0;
  --g15: #d1e481;
  --g16: #a0c3e3;
  --g17: #d07c8e;
  --g18: #81e488;
  --g19: #b9a0e3;
  --g20: #d0b37c;
  --g21: #81e4df;
  --g22: #e3a0d3;
  --g23: #a3d07c;
  --g24: #8192e4;
  --g25: #e3a8a0;
  --g26: #7cd09e;
  --g27: #c681e4;
  --g28: #e3e3a0;
  --g29: #7cb8d0;
  --graph-node: #e8e6dc;
  /* 별 색 규칙(은수 2026-09-09): 노랑 = 열어봄 · 주황 = 다 읽음 · 분홍 = 관심. 한 계열이라 순서가 색으로 읽힌다. */
  --star: #f2db94;             /* 열어봄 */
  --star-read: #f0a63c;        /* 다 읽음 */
  --star-interest: #f29ab8;    /* 관심 — 하트의 빨강과 같은 가족 */
  --heart: #e5636f;            /* 하트 — 켜지면 빨강(은수 2026-09-09 「초록색이 머냐」) */
  --space-deep: #0a0a12;       /* 별자리 뒤 우주 — 판 바탕보다 한 겹 깊고 푸른 검정 */
  --nebula-a: rgba(112, 96, 190, 0.20);   /* 성운 빛 — 보라 */
  --nebula-b: rgba(46, 140, 150, 0.16);   /* 성운 빛 — 청록 */
  --graph-node-missing: #5c5c58;
  --graph-edge: #262626;

  /* 간격 스케일 — 나머지 CSS 는 rem/px 를 직접 쓰지 않고 이걸 참조한다. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  /* 타이포 스케일. step-0 이 UI 기본(16px), step--1 은 메타 정보용 작은 글자. */
  --step--1: 0.8125rem;
  --step-0: 1rem;
  --step-1: 1.25rem;
  --step-2: 1.5rem;
  --step-3: 2rem;            /* 큰 제목 — 가늘게(300) 쓴다 */
  --step-4: 2.5rem;
  /* 리더 본문만 별도 — "18px/1.75" 는 스텝 비율이 아니라 계획서가 못박은 값이다. */
  --reader-font-size: 1.125rem;
  --reader-line-height: 1.75;

  --backdrop: rgb(0 0 0 / 0.5);   /* 드로어 뒤 딤 배경 */
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-pill: 999px;
  --border-width: 1px;
  --focus-width: 2px;

  /* 리더 본문의 측정폭(한 줄 길이). 68ch — 계획서의 타이포그래피 결정. */
  /* 본문 한 줄 폭. 68ch → 78ch → 96ch 로 두 번 넓혔다(2026-08-08, 은수: "난 넓은 게 편하더라").
     타이포그래피 통설(45~75자)보다 넓지만 읽는 사람이 그렇다면 그게 기준이다.
     좁은 화면에서 넘칠 걱정은 없다 — 그리드가 minmax(0, …) 라 필요하면 줄어든다. */
  --measure: 96ch;

  /* Pretendard 자체호스팅(app/static/fonts/) + 시스템 폴백. CDN 링크 금지 — 오프라인
     PWA 라 서비스워커가 캐시할 수 있어야 한다. */
  --font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo",
    "Noto Sans KR", "Malgun Gothic", Segoe UI, Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f7f6f2;
    --surface: #ffffff;
    --text: #1c1c1a;
    --muted: #6b6b66;
    --muted-2: #a0a09a;
    /* 흰 배경에서 #4ec9b0 은 본문 대비 4.5:1 이 안 나온다 — 글자·링크는 진한 쪽을 쓰고
       원색은 채움에만 남긴다(--fill-*). */
    --g0: #1a9e86;
    --g1: #ae299f;
    --g2: #577a24;
    --g3: #1a429e;
    --g4: #ae292a;
    --g5: #247a3c;
    --g6: #651a9e;
    --g7: #ae9b29;
    --g8: #246d7a;
    --g9: #9e1a63;
    --g10: #4bae29;
    --g11: #27247a;
    --g12: #9e441a;
    --g13: #29ae7a;
    --g14: #72247a;
    --g15: #849e1a;
    --g16: #296dae;
    --g17: #7a2437;
    --g18: #1a9e23;
    --g19: #5929ae;
    --g20: #7a5c24;
    --g21: #1a9e97;
    --g22: #ae298e;
    --g23: #4c7a24;
    --g24: #1a319e;
    --g25: #ae3829;
    --g26: #247a47;
    --g27: #761a9e;
    --g28: #aeac29;
    --g29: #24627a;
    --accent-read: #17806b;
    --accent-review: #6d4fb8;
    --border: #e4e3de;

    --syn-comment: #5a6b64;
    --syn-keyword: #2952a3;
    --syn-string: #8a5a00;
    --syn-number: #9a3f72;
    --syn-name: #6b5b00;
    --syn-error: #b3261e;
    --wrong: #b3261e;

    /* 흰 배경에선 형광펜이 진짜 형광펜처럼 — 옅은 채도로 깔고 글자는 --text 를 지킨다. */
    --hl-yellow: #fbeeb0;
    --hl-teal: #b6ebe0;
    --hl-red: #ffd6d9;
    --hl-yellow-edge: #a8871f;
    --hl-teal-edge: #17806b;
    --hl-red-edge: #b3261e;

    /* 라이트에서는 점이 어두운 회색으로 뒤집힌다(다크에서 흰 점이던 것과 대칭). */
    --graph-node: #2a2a28;
    --star: #b08a1f;
    --star-read: #c4651a;
    --star-interest: #c2426f;
    --heart: #c8323f;
    --space-deep: #e9e8f0;
    --nebula-a: rgba(112, 96, 190, 0.14);
    --nebula-b: rgba(46, 140, 150, 0.12);
    --graph-node-missing: #a0a09a;
    --graph-edge: #e9e8e3;
  }
}

@font-face {
  font-family: "Pretendard";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/static/fonts/Pretendard-Light.subset.woff2") format("woff2");
}
@font-face {
  font-family: "Pretendard";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/Pretendard-Regular.subset.woff2") format("woff2");
}

@font-face {
  font-family: "Pretendard";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/Pretendard-SemiBold.subset.woff2") format("woff2");
}

* { box-sizing: border-box; }

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

/* 페이지 자체를 가로로 못 밀리게 잠근다. 노트마다 오버플로 원인(코드블록·인라인
   코드·표)을 하나씩 잡아도, 실기기 폰트 렌더링의 서브픽셀 반올림 차이로 어딘가
   또 1~2px 넘칠 수 있다(2026-07-30: 세로 스크롤 중에도 옆으로 밀리는 리포트 —
   각 노트 콘텐츠는 이미 딱 맞았는데도 실기기에서 재현됨). 개별 원인을 계속
   쫓는 대신 근본을 막는다 — 안에서 overflow-x:auto 로 따로 연 pre.hl·
   .table-wrap 은 이 규칙과 무관하게 각자 정상적으로 가로 스크롤된다.
   NOTE html 에만 건다 — body 에 걸면 CSS 스펙상 overflow-y 가 강제로 auto 로
   바뀌면서 body 가 별도 스크롤 컨테이너가 되고, 그 안의 position:sticky(상단 바)가
   화면이 아니라 body 를 기준 삼아 같이 흘러간다. html 은 원래 뷰포트의 루트
   스크롤러라 여기 걸어도 그 문제가 없다. */
html { overflow-x: hidden; }

body {
  margin: 0;
  padding: 0 1rem 3rem;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
}

a { color: var(--link); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; }
/* 본문 링크는 밑줄을 흐리게 깔아 「누를 수 있다」만 말한다 — 청록 글자만으로는 형광펜과 겹쳐 보인다. */
.prose a { text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--link) 35%, transparent); text-underline-offset: 0.18em; }
.prose a:hover, .prose a:focus-visible { text-decoration-color: var(--link); }

/* 상단 바 — 리더의 .reader-top 과 같은 글래스. 폭 밖으로 배경이 닿게 body 패딩만큼 음수 마진. */
.top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 3.5rem;
  margin: 0 -1rem;
  padding: 0 var(--space-3);
  border-bottom: var(--border-width) solid color-mix(in srgb, var(--text) 8%, transparent);
}
/* 글래스는 가상 요소에 건다 — backdrop-filter 가 걸린 요소는 position:fixed 자손의 기준 상자가
   되어서, 헤더 안의 드로어 패널(fixed)이 헤더 높이에 갇힌다(2026-09-06 실측: 패널이 80px 상자로 뜸). */
.top::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.top h1 { margin: 0; font-size: var(--step-0); font-weight: 400; letter-spacing: 0.01em; }
.top-meta { margin: 0 0 0 auto; color: var(--muted); font-size: var(--step--1); }

/* 대문 — 검색 + 최근 읽던 문서 */
.home { padding-top: var(--space-5); }
.home-head { display: flex; align-items: baseline; justify-content: space-between; margin: var(--space-6) 0 var(--space-1); }
.home-h2 { margin: 0; color: var(--muted); font-size: var(--step--1); font-weight: 400; letter-spacing: 0.02em; }
/* 대문의 곁 링크는 --muted 다 — 더 흐린 단계는 배경 대비가 2.7:1 이라 읽기 검사에서 떨어진다(2026-09-12). */
.home-more { color: var(--muted); font-size: var(--step--1); }
.home-more:hover, .home-more:focus-visible { color: var(--link); }

/* 문서 한 줄 — 괘선으로 가른다. 줄 전체가 링크라 엄지로 어디를 눌러도 열린다. */
.rows { list-style: none; margin: 0; padding: 0; }
.row { padding: var(--space-3) 0 var(--space-4); border-bottom: var(--border-width) solid var(--border); }
/* 시리즈 버튼 — 제목 링크와 별개의 링크. 눌리는 높이는 엄지 기준, 보이는 건 작은 칩. */
.row-series {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2rem;
  margin-left: calc(var(--space-2) * -1);
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  color: var(--accent-read);
  font-size: var(--step--1);
  font-weight: 600;
}
.row-series:hover, .row-series:focus-visible { background: var(--surface); text-decoration: none; }
.row-series-n { color: var(--muted); font-weight: 400; }
.row-link {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-top: var(--space-1);
  color: var(--text);
}
.row-link:hover, .row-link:focus-visible { text-decoration: none; }
.row-link:hover .row-title, .row-link:focus-visible .row-title { color: var(--text); }
.row-link:hover, .row-link:focus-visible { opacity: 0.85; }
.row-title { font-size: var(--step-1); font-weight: 300; line-height: 1.3; letter-spacing: -0.01em; text-wrap: pretty; word-break: keep-all; overflow-wrap: anywhere; }
.row-progress { display: flex; align-items: center; gap: var(--space-3); }
.row-progress .progress { width: 7.5rem; margin: 0; height: 3px; }
.row-pct { color: var(--muted-2); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.row-read { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--accent-read); font-size: var(--step--1); font-weight: 600; }

main { max-width: 44rem; margin: 0 auto; }

.sec { margin: 1.6rem 0; }

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

.card {
  background: var(--surface);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  padding: 0.7rem 0.85rem;
}

.card-title { display: block; font-size: 1rem; font-weight: 600; line-height: 1.35; }
.card-blurb {
  margin: 0.3rem 0 0;
  color: var(--muted);
  font-size: 0.85rem;
  /* 한 줄 설명이 길다 — 폰에서 카드가 문단이 되지 않게 두 줄로 자른다. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-meta {
  margin: 0.4rem 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.75rem;
  color: var(--muted);
}

.tag {
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.05rem 0.45rem;
  white-space: nowrap;
}

.progress {
  margin: 0.5rem 0 0;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--border);
  overflow: hidden;
}
.progress-fill { display: block; height: 100%; background: var(--fill-read); }

.search {
  position: relative;
  display: flex;
  align-items: center;
  margin: 0;
}
.search-icon { position: absolute; left: var(--space-3); color: var(--muted); pointer-events: none; }
.search input {
  flex: 1;
  min-width: 0;
  min-height: 3rem;
  background: var(--surface);
  color: var(--text);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 var(--space-3) 0 calc(var(--space-3) * 2 + 20px);
  font: inherit;
  font-size: 1rem;   /* 16px 미만이면 iOS 사파리가 화면을 확대한다 */
}
.search input::placeholder { color: var(--muted); }
.search input:focus-visible { outline: var(--focus-width) solid var(--link); outline-offset: var(--border-width); }
.search .htmx-indicator { margin: 0 var(--space-2); }
/* 검색 단추 — 입력칸과 같은 높이의 알약. 스크립트를 끄면 이것이 제출 수단이 된다. */
.search button {
  flex: none;
  min-height: 3rem;
  padding: 0 var(--space-4);
  background: var(--surface);
  color: var(--text);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  cursor: pointer;
}
.search button:hover, .search button:focus-visible { border-color: var(--muted); }

/* htmx 요청 중에만 보이는 점점점. htmx 가 없으면 그냥 안 보인다. */
.htmx-indicator { opacity: 0; transition: opacity 120ms ease-in; color: var(--muted); }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }

.list-head, .empty { color: var(--muted); font-size: 0.85rem; margin: 0.2rem 0 0.6rem; }
.list-head { font-size: var(--step--1); font-weight: 600; letter-spacing: 0.04em; margin: var(--space-5) 0 var(--space-1); }
.home-search { margin-top: var(--space-7); }
.shelf { margin-top: var(--space-7); }

/* 시리즈 칩은 색을 나누지 않는다 — 어느 시리즈든 같은 미색이고, 누를 수 있다는 것만 링크 색으로 말한다. */
.row-series { color: var(--text); }
.row-series:hover, .row-series:focus-visible { color: var(--link); }
/* 그 시리즈 화면 안에서는 몇 번째 편인지만 남는다 — 지금 있는 곳으로 가는 링크는 안 만든다. */
.row-series-here { color: var(--muted); }

/* 히어로 카드 — 최근 읽던 노트 전부. 시리즈는 카드 링크 밖의 제 링크다. */
.heroes { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4) var(--space-4);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.hero:hover, .hero:focus-within { border-color: var(--muted-2); }
.hero { position: relative; }
/* 그리드·플렉스 칸은 기본 최소 폭이 내용 폭이라, 카드 안 글자 한 덩어리(공백 없는 서비스 이름 나열)가
   카드를 늘려 페이지 전체를 옆으로 밀었다(2026-09-28 AWS 08 설명문). 칸이 줄어들 수 있게 한다. */
.hero, .hero-link { min-width: 0; }
/* × — 오른쪽 위 구석, 평소엔 흐리고 카드에 손이 가면 드러난다. 엄지 목표 44px. */
.hero-dismiss {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted-2);
  cursor: pointer;
}
.hero-dismiss:hover, .hero-dismiss:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
.hero-dismiss:disabled { opacity: 0.4; cursor: default; }
.hero-series { padding-right: 2.5rem; }
.hero-series {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  align-self: flex-start;
  min-height: 2rem;
  margin-left: calc(var(--space-2) * -1);
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: var(--step--1);
  font-weight: 400;
}
.hero-series:hover, .hero-series:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); text-decoration: none; }
.hero-series-n { color: var(--muted); font-weight: 400; }
.hero-link { display: flex; flex-direction: column; gap: var(--space-2); color: var(--text); }
.hero-link:hover, .hero-link:focus-visible { text-decoration: none; }
.hero-link:hover .hero-title, .hero-link:focus-visible .hero-title { color: var(--text); }
.hero-title { font-size: var(--step-2); font-weight: 300; line-height: 1.25; letter-spacing: -0.02em; text-wrap: pretty; word-break: keep-all; overflow-wrap: anywhere; }
.hero-blurb { color: var(--muted); font-size: var(--step--1); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.hero-foot { display: flex; align-items: center; gap: var(--space-4); margin-top: var(--space-1); }
.hero-progress { flex: 1; margin: 0; height: 3px; }
.hero-progress .progress-fill { background: var(--fill-read); }
.hero-cta { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--muted); font-size: var(--step--1); font-weight: 400; white-space: nowrap; }
.hero-link:hover .hero-cta, .hero-link:focus-visible .hero-cta { color: var(--text); }
.home-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 3rem;
  margin-top: var(--space-6);
  padding: 0 var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-weight: 600;
}
.home-link:hover, .home-link:focus-visible { border-color: var(--muted); text-decoration: none; }

/* 묶음 화면의 소개 문단 — 목록보다 앞에 서서 「여기가 무엇인가」를 한 번 말한다. */
.lead { max-width: var(--measure); margin: var(--space-5) 0 0; color: var(--muted); line-height: 1.6; }

/* 화면 하나가 내미는 손잡이 줄 — 담기·다음 편처럼 지금 누를 것만 나란히 선다. */
.series-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: var(--space-5) 0 var(--space-4); }
/* 다음으로 넘어가는 단추. 읽는 축이라 청록이다. */
.cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2.75rem;
  padding: 0 var(--space-5);
  border: var(--border-width) solid var(--accent-read);
  border-radius: var(--radius-pill);
  color: var(--accent-read);
  font-weight: 600;
}
.cta:hover, .cta:focus-visible { background: var(--surface); text-decoration: none; }
/* 서재 담기·빼기 — 담긴 상태는 채워서 「이미 내 것」을 말한다. */
.shelf-btn {
  min-height: 2.75rem;
  padding: 0 var(--space-5);
  font: inherit;
  font-weight: 600;
  color: var(--text);
  background: transparent;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.shelf-btn:hover, .shelf-btn:focus-visible { border-color: var(--muted); }
.shelf-btn.is-in-shelf { color: var(--bg); background: var(--text); border-color: var(--text); }
.shelf-btn.is-in-shelf:hover, .shelf-btn.is-in-shelf:focus-visible { opacity: 0.9; }
.row-blurb { color: var(--muted); font-size: var(--step--1); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
.browse-main .all > summary { padding: var(--space-3) 0; font-size: var(--step--1); font-weight: 600; letter-spacing: 0.04em; }
.related-chip .group-count { margin-left: var(--space-1); }
.shelf-link { gap: var(--space-3); }
.shelf-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.shelf-link .progress { width: 100%; margin: 0; height: 3px; }
.results .sec { margin: 0; }

.all > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
  padding: 0.3rem 0;
}

.group-count { color: var(--muted-2); font-size: 0.75rem; font-weight: 400; }

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

/* 폰에서 맞춘 뒤, 넓은 화면에서 여백과 글자만 조금 키운다 (칼럼은 하나로 둔다). */
@media (min-width: 40rem) {
  body { padding: 0 1.5rem 4rem; font-size: 17px; }
  .top { margin: 0 -1.5rem; padding: 0 var(--space-4); }
}

/* ── 리더 화면 (/w/<제목>) ─────────────────────────────────────────── */

.progress-top {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--border);
  /* 상단 바(z 20)보다 위. 바가 sticky 로 올라와도 진행바는 늘 보인다. */
  z-index: 30;
}
.progress-top-fill {
  display: block;
  height: 100%;
  background: var(--fill-read);
  transition: width 200ms ease-out;
}

/* 고정 진행바(위)가 헤더 첫 줄과 겹치지 않게 살짝 띄운다. */
.reader-body { padding-top: var(--space-2); }

/* 상단 바는 따라 내려온다 — 읽는 중엔 숨고, 살짝 위로 올리면 제목과 함께 나온다
   (2026-08-09, 은수: "살짝 스크롤 위로 올리면 제목 보이게"). 스크롤을 내릴 때까지
   붙들고 있으면 본문 위 3rem 을 늘 잡아먹어서, 방향을 보고 감춘다. */
.reader-top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  /* flex-wrap 을 빼야 한 줄 높이가 고정된다 — 줄이 늘면 감췄다 나올 때 본문이 튄다. */
  padding: var(--space-3) 0;
  /* 글래스 — 떠 있는 층(상단 바·형광펜 고르개)에만 쓴다. 본문엔 안 쓴다. */
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-bottom: var(--border-width) solid color-mix(in srgb, var(--text) 8%, transparent);
  transition: transform 180ms ease-out;
}
/* -101% — 1% 는 서브픽셀 반올림으로 아래 테두리 한 줄이 남는 걸 막는 여유다. */
.reader-top.is-hidden { transform: translateY(-101%); }

/* 제목은 본문 <h1> 이 화면에서 사라졌을 때만 켠다 — 둘 다 보이면 같은 말이 두 번이다. */
.reader-top-title {
  flex: 1;
  min-width: 0;
  text-align: center;
  color: var(--muted);
  font-size: var(--step--1);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  transition: opacity 150ms ease-out;
}
.reader-top.is-compact .reader-top-title { opacity: 1; }

.back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2.75rem;               /* 엄지 목표 44px */
  color: var(--muted);
  font-size: var(--step--1);
  white-space: nowrap;
}
.back:hover, .back:focus-visible { color: var(--link); text-decoration: none; }
.back-icon { flex: none; }
/* 본문 머리 — 갈래(노트/사전)·시리즈 칩. 상단 바에서 내려왔다. */
.reader-kind { display: flex; gap: var(--space-2); flex-wrap: wrap; max-width: var(--measure); margin: var(--space-5) auto var(--space-3); }

/* 상단바의 목차 버튼 — 제목 오른쪽, 엄지 목표 44px. */
.toc-open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.toc-open:hover, .toc-open:focus-visible, .toc-open[aria-expanded="true"] { color: var(--text); }

/* 상단바의 관심(하트) — 목차 버튼과 같은 크기·같은 자리. 눌린 것만 읽는 축 색으로 산다. */
.interest-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.interest-btn:hover, .interest-btn:focus-visible { color: var(--text); }
.interest-btn.is-interested { color: var(--accent-read); }

/* 목차 목록 — 드로어와 패널 탭이 같은 마크업을 문다. 자리마다의 여백·글자색은 그 자리
   규칙(.toc-drawer-list · .panel-toc)이 뒤에서 덮는다. */
.toc-list { margin: 0; padding: 0; list-style: none; }
.toc-list li { padding: var(--space-1) 0; line-height: 1.45; }
/* 2단은 장, 3단은 절, 4단 아래는 절 안의 묶음이다 — 들여쓰기는 자리마다 다르니 굵기로도 가른다. */
.toc-list li.toc-l2 { font-weight: 500; }
.toc-list a { color: var(--text); }
.toc-list a:hover, .toc-list a:focus-visible { color: var(--link); }

/* 목차 드로어 — 왼쪽에서 슬라이드, 뒤는 살짝 어둡게. 글래스는 다른 드로어와 같은 층. */
.toc-backdrop { position: fixed; inset: 0; z-index: 45; background: var(--backdrop); }
.toc-backdrop[hidden] { display: none; }
.toc-drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: min(82vw, 21rem);
  z-index: 50;
  display: flex;
  flex-direction: column;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);
  border-right: var(--border-width) solid color-mix(in srgb, var(--text) 8%, transparent);
  box-shadow: 12px 0 40px var(--backdrop);
  transform: translateX(-102%);
  transition: transform 220ms ease-out;
  padding-top: env(safe-area-inset-top, 0px);
}
.toc-drawer.is-open { transform: translateX(0); }
.toc-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 3.5rem;
  padding: 0 var(--space-2) 0 var(--space-4);
  border-bottom: var(--border-width) solid var(--border);
}
.toc-drawer-title { color: var(--muted); font-size: var(--step--1); letter-spacing: 0.02em; }
.toc-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.toc-close:hover, .toc-close:focus-visible { color: var(--text); }
.toc-drawer-list { flex: 1; overflow: auto; margin: 0; padding: var(--space-2) var(--space-3) var(--space-8); }
.toc-drawer-list li { padding: 0; font-size: var(--step-0); }
.toc-drawer-list li.toc-l3 { padding-left: var(--space-4); font-size: var(--step--1); }
.toc-drawer-list li.toc-l4 { padding-left: var(--space-5); font-size: var(--step--1); color: var(--muted); }
.toc-drawer-list li.toc-l5 { padding-left: var(--space-6); font-size: var(--step--1); color: var(--muted); }
.toc-drawer-list li.toc-l6 { padding-left: var(--space-7); font-size: var(--step--1); color: var(--muted); }
.toc-drawer-list a {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  line-height: 1.4;
  text-wrap: pretty;
  word-break: keep-all;
}
.toc-drawer-list a:hover, .toc-drawer-list a:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); text-decoration: none; }
.toc-drawer-list a.is-current { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
body.toc-drawer-open { overflow: hidden; }

/* 앵커로 뛰어온 자리가 상단 바에 가리지 않게 — 형광펜 목록·목차가 이 길로 온다. */
.prose [id^="b-"],
.prose [id^="h-"] { scroll-margin-top: 4.5rem; }

.reader-layout {
  display: block;
  max-width: calc(var(--measure) + 18rem);
  margin: 0 auto;
}

/* 제목 묶음은 main 밖(그리드 첫 줄)에 있어서 전역 `main { max-width: 44rem }` 을 안 받는다 —
   같은 폭으로 맞춰야 폰·태블릿에서 제목과 본문의 왼쪽 선이 맞는다. 데스크톱은 칼럼이 정한다. */
.reader-head { max-width: 44rem; margin: 0 auto; }
/* 문서 머리에 서는 것은 사람뿐이다 — 쓴 사람, 그리고 뒤에 손댄 사람들. */
.doc-people {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  max-width: var(--measure);
  margin: calc(var(--space-5) * -1) auto var(--space-5);
  color: var(--muted-2);
  font-size: var(--step--1);
}
.doc-author { color: var(--muted); }
/* 제목은 크고 **가늘게** — 굵기 대신 크기로 선다(paper.design 48px/360). 나머지가 흐려야 이게 산다. */
.reader-title {
  max-width: var(--measure);
  margin: 0 auto var(--space-5);
  font-size: var(--step-3);
  font-weight: 300;
  line-height: 1.22;
  letter-spacing: -0.02em;
  text-wrap: pretty;
  word-break: keep-all;
  /* keep-all 은 공백에서만 끊는다. 「EC2·Lightsail·Beanstalk·CloudShell」처럼 가운뎃점으로 이은
     제목은 공백이 없어 한 덩어리가 되고, 폰에서 화면 폭을 넘겨 페이지 전체를 옆으로 늘린다
     (2026-09-23 AW 01-1). 넘칠 때만 글자 사이에서 끊게 한다.
     break-word 가 아니라 anywhere 다 — break-word 는 최소 폭 계산에 안 들어가서, 그리드·플렉스
     칸(홈 카드)에서는 칸이 제목 한 덩어리만큼 늘어나 페이지가 다시 옆으로 밀렸다(2026-09-28 AWS 08). */
  overflow-wrap: anywhere;
}

/* 렌더된 마크다운 본문. 계획서가 못박은 값: 18px/1.75, 산세리프, 단일 컬럼 --measure. */
.prose {
  max-width: var(--measure);
  margin: 0 auto;
  font-size: var(--reader-font-size);
  line-height: var(--reader-line-height);
  /* 공백 없는 긴 문자열(URL·경로·정규식)이 줄을 못 바꾸면 그 인라인 요소가
     .prose(overflow-x:visible)를 뚫고 올라가 body 전체를 옆으로 늘린다 —
     그러면 페이지 전체가 가로로 흔들린다(2026-07-30 폰 실기기 리포트로 발견,
     Playwright로 재현: euns:x:1000:1000:,,,:/home/euns:/bin/bash 같은 인라인
     코드가 410px 폭을 요구해 361px 컨테이너를 뚫었다). */
  overflow-wrap: break-word;
}
.prose > :first-child { margin-top: 0; }
.prose h2, .prose h3, .prose h4, .prose h5, .prose h6 { line-height: 1.35; scroll-margin-top: var(--space-6); }
/* 제목 크기는 --step-* 고정이 아니라 본문 기준 em 이다. 데스크톱에서 본문만
   1.125 → 1.25rem 으로 커지는데(.reader-layout) 제목이 고정이면 h3(--step-1 = 1.25rem)가
   본문과 크기·굵기가 같아져 제목으로 안 읽힌다. em 이면 본문이 커질 때 같이 커져 층이 지켜진다.
   굵기는 h2 가 제일 크니 가늘게(300) 두고, 작아질수록 굵게 해서 300 → 500 → 600 으로 간다. */
.prose h2 { margin: var(--space-7) 0 var(--space-3); font-size: 1.4em; font-weight: 300; letter-spacing: -0.015em; }
.prose h3 { margin: var(--space-6) 0 var(--space-2); font-size: 1.15em; font-weight: 500; color: var(--text); }
/* 4단은 절 안의 묶음이다 — 본문과 같은 크기에 굵기로만 가른다. h3(--step-1)보다 크게 보이면 층이 뒤집힌다. */
.prose h4 { margin: var(--space-5) 0 var(--space-2); font-size: 1em; font-weight: 600; color: var(--text); }
/* 5·6단은 본문보다 작게 내려 층이 계속 얕아지게 둔다. 6단은 글자색까지 흐리다. */
.prose h5, .prose h6 { margin: var(--space-4) 0 var(--space-2); font-size: 0.9em; font-weight: 600; }
.prose h5 { color: var(--text); }
.prose h6 { color: var(--muted); }
.prose p, .prose ul, .prose ol, .prose .table-wrap { margin: 0 0 var(--space-4); }
.prose ul, .prose ol { padding-left: var(--space-5); }
.prose li + li { margin-top: var(--space-1); }
.prose li > ul, .prose li > ol { margin: var(--space-1) 0 0; }

.prose blockquote {
  margin: 0 0 var(--space-4);
  padding: var(--space-1) var(--space-4);
  border-left: 3px solid var(--accent-review);
  color: var(--muted);
}
.prose blockquote > :last-child { margin-bottom: 0; }

/* 「쉽고 빠른 이해」 상자 — 본문 문단과 확실히 구분되는 접이식 블록. 기본은 접힘,
   상자 자체가 눈에 띄어야 있는 줄 모르고 지나치지 않는다. */
.prose details {
  margin: 0 0 var(--space-4);
  border: var(--border-width) solid var(--accent-read);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent-read) 8%, var(--surface));
  overflow: hidden;
}
.prose details > :last-child { margin-bottom: 0; }
.prose details[open] summary { border-bottom: var(--border-width) solid var(--accent-read); }
.prose details > :not(summary) { padding: 0 var(--space-4); }
.prose details > p:first-of-type { margin-top: var(--space-4); }
/* 목록 번호는 padding-left 안쪽에 그려진다. 위 규칙이 그 값을 1rem 으로 눌러
   버려서 상자 자체의 여백(space-4)만큼 번호가 상자 밖으로 밀려나 overflow:hidden
   에 잘렸다 — 상자 여백에 원래 목록 들여쓰기(space-5)를 더해 준다. */
.prose details > ol, .prose details > ul { padding-left: calc(var(--space-4) + var(--space-5)); }
.prose summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-weight: 650;
  color: var(--accent-read);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.prose summary::-webkit-details-marker { display: none; }
.prose summary::before {
  content: "▸";
  font-size: 0.8em;
  transition: transform 0.15s ease;
}
.prose details[open] > summary::before { transform: rotate(90deg); }
.prose summary:hover, .prose summary:focus-visible { background: color-mix(in srgb, var(--accent-read) 14%, transparent); }

.prose .table-wrap { overflow-x: auto; }
.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}
.prose th, .prose td {
  border: var(--border-width) solid var(--border);
  padding: var(--space-2) var(--space-3);
  text-align: left;
  /* .prose 의 overflow-wrap: break-word 가 칸까지 내려오면 크롬이 칸의 최소 폭을 글자 하나로 잡아,
     폰에서 긴 표의 한 열이 한 글자씩 세로로 쌓였다(2026-09-27 AWS 03-1). 칸 안은 낱말 단위로만
     끊고 최소 폭을 준다. 표가 화면보다 넓어지면 .table-wrap 이 옆으로 밀린다. */
  overflow-wrap: normal;
  word-break: keep-all;
  min-width: 7em;
}
.prose th { background: var(--surface); font-weight: 600; }

.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface);
  border-radius: var(--radius-sm);
  padding: 0.1em 0.35em;
  /* anywhere — break-word 는 공백이 아예 없으면 여전히 안 끊는다(예: 경로).
     인라인 코드는 그런 문자열이 흔해서 더 세게 끊는다. */
  overflow-wrap: anywhere;
}
.prose pre.hl {
  margin: 0;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  line-height: 1.6;
}
.prose pre.hl code { background: none; padding: 0; border-radius: 0; }
.prose .codeblock {
  margin: 0 0 var(--space-4);
  background: var(--surface);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  /* 언어 딱지가 이 상자를 기준으로 오른쪽 위에 앉는다. */
  position: relative;
}
/* 한 편에 코틀린·자바·터미널이 번갈아 나오면 무엇을 보는 중인지 매번 되짚게 된다.
   코드가 스크롤돼도 딱지는 제자리여야 해서 pre 가 아니라 바깥 상자에 붙인다.
   상자 위 여백에 얹혀 첫 줄 글자를 가리지 않고, pointer-events 를 꺼서 가로 스크롤을 막지 않는다. */
.prose .codeblock-lang {
  position: absolute;
  top: 0;
  right: 0;
  padding: 0.15em 0.6em;
  border-bottom-left-radius: var(--radius-sm);
  border-top-right-radius: var(--radius-md);
  background: var(--border);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.72em;
  line-height: 1.5;
  letter-spacing: 0.02em;
  user-select: none;
  pointer-events: none;
}

/* Pygments 토큰 클래스 → 토큰 색. 값 자체는 :root 의 --syn-* 뿐이라 규율 13 을 지킨다. */
.hl .c, .hl .c1, .hl .cm, .hl .cs, .hl .cp { color: var(--syn-comment); font-style: italic; }
.hl .k, .hl .kc, .hl .kd, .hl .kn, .hl .kp, .hl .kr, .hl .kt, .hl .ow { color: var(--syn-keyword); font-weight: 600; }
.hl .s, .hl .s1, .hl .s2, .hl .sa, .hl .sb, .hl .sc, .hl .sd,
.hl .se, .hl .sh, .hl .si, .hl .sx, .hl .sr, .hl .ss { color: var(--syn-string); }
.hl .m, .hl .mf, .hl .mh, .hl .mi, .hl .mo, .hl .mb, .hl .il { color: var(--syn-number); }
.hl .nf, .hl .nc, .hl .nb, .hl .nd, .hl .ni, .hl .nl, .hl .nn,
.hl .nt, .hl .vc, .hl .vg, .hl .vi { color: var(--syn-name); }
.hl .err { color: var(--syn-error); }

.wikilink { border-bottom: var(--border-width) dotted var(--link); }
.wikilink-missing {
  color: var(--muted);
  border-bottom: var(--border-width) dashed var(--muted);
  cursor: default;
}

.finish {
  max-width: var(--measure);
  margin: var(--space-7) auto var(--space-7);
  padding-top: var(--space-5);
  border-top: var(--border-width) solid var(--border);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
/* 읽음 토글 — 체크박스처럼. 안 눌림 = 테두리만, 눌림 = 청록으로 채움. 한 버튼이 상태다. */
.read-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2.75rem;
  font: inherit;
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--text);
  background: transparent;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0 var(--space-5);
  cursor: pointer;
}
.read-toggle:hover, .read-toggle:focus-visible { border-color: var(--muted); color: var(--text); }
/* 아이콘 둘(○·✓)을 다 실어 두고 상태로 하나만 보인다 — 서버 조각 없이 JS 가 aria-pressed 만 뒤집는다. */
.read-toggle[aria-pressed="false"] .read-toggle-on,
.read-toggle[aria-pressed="true"] .read-toggle-off { display: none; }
.read-toggle:focus-visible { outline: var(--focus-width) solid var(--link); outline-offset: var(--border-width); }
.read-toggle[aria-pressed="true"] { color: var(--bg); background: var(--text); border-color: var(--text); }
.read-toggle[aria-pressed="true"]:hover, .read-toggle[aria-pressed="true"]:focus-visible { color: var(--bg); background: var(--text); opacity: 0.9; }
.finish-pct { color: var(--muted); font-size: var(--step--1); }

/* 관련 항목 — 목록이 아니라 칩. 다음에 열 문서를 엄지로 고른다. */
.related-list { max-width: var(--measure); margin: 0 auto var(--space-8); }
.related-list h2 {
  margin: 0 0 var(--space-3);
  color: var(--muted);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
}
.related-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.related-chip {
  display: inline-flex;
  align-items: center;
  min-height: 2.125rem;
  padding: 0 var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--text);
  font-size: var(--step--1);
}
.related-chip:hover, .related-chip:focus-visible { border-color: var(--muted); text-decoration: none; }


/* 데스크톱 — 제목 묶음과 본문을 한 칼럼으로 세우고 글씨만 키운다. 목차는 화면 폭과
   무관하게 드로어와 패널 탭으로만 연다. */
@media (min-width: 60rem) {
  .reader-layout {
    display: grid;
    /* 칼럼을 1fr(=남는 폭 전부)로 두면 안 된다. 본문은 --measure 로 좁혀지는데 칼럼은
       화면 끝까지 늘어나, 본문이 그 안에서 가운데로 밀려 왼쪽 여백만 커진다.
       칼럼을 본문 폭에 맞추고(minmax 의 0 은 긴 코드블록이 칼럼을 밀어내지 않게 한다),
       그리드 전체를 justify-content 로 가운데 세운다 — 좌우 여백이 대칭이 된다. */
    grid-template-columns: minmax(0, var(--measure));
    grid-template-rows: 1fr;
    justify-content: center;
    gap: var(--space-4) var(--space-6);
    align-items: start;
    max-width: none;
    padding: 0 var(--space-6);
  }
  /* 제목 묶음은 이제 main > article 안이라 그리드 항목이 아니다 — 칼럼 폭을 그대로 쓴다. */
  .reader-head { margin: 0 0 var(--space-4); max-width: none; }
  /* min-width:0 — 그리드 항목은 기본 min-width:auto 라 안에 넓은 것이 있으면 칼럼(960px)을
     뚫고 1152px 로 늘어난다(2026-09-06 실측: 본문·그래프가 화면 오른쪽 밖으로 나갔다). */
  /* margin:0 — 전역 `main { margin: 0 auto }` 의 auto 마진이 그리드 항목을 칼럼(960px)이 아니라
     제 max-content(1152px)로 키운다(2026-09-06 실측: 본문·그래프가 화면 오른쪽 밖으로 나갔다). */
  .reader-layout > main { grid-column: 1; grid-row: 1; min-width: 0; margin: 0; }

  /* 본문 글씨는 데스크톱에서만 키운다(2026-08-08, 은수 요청). 폰(18px)은 이미 잘 읽힌다고
     해서 안 건드린다 — 화면이 멀어지는 데스크톱이 더 커야 하는 쪽이다.
     칼럼 폭은 .reader-layout(17px) 기준 ch 로 정해지므로 폭은 그대로고, 글씨만 커져서
     한 줄 글자수가 줄어든다(실측 55자 → 49자). 넓힌 폭을 깎지 않으면서 밀도만 낮추는 셈. */
  .reader-layout { --reader-font-size: 1.25rem; }

  /* 코드블록은 --step--1(13px) 고정이라 본문만 키우면 격차가 벌어진다 — 본문 20px 에
     코드 13px 는 65% 다(2026-08-08 실측). 인라인 코드는 0.9em 이라 알아서 따라오는데
     블록만 안 따라온다. em 으로 바꿔 본문에 묶는다.
     0.85em ≈ 17px — 등폭 글꼴은 같은 크기에서 더 커 보여서 본문보다 조금 작게 잡는다. */
  .prose pre.hl { font-size: 0.85em; }

  /* 전역 `main { max-width: 44rem }`(=704px)이 데스크톱에서도 본문을 자른다.
     그래서 --measure 를 올려도 폭이 안 늘고 목차와의 간격만 벌어졌다(2026-08-08 실측:
     칼럼 907.6px · prose max-width 961.0px 인데 main 이 704px 로 캡). 여기선 풀고
     폭 결정을 --measure(=그리드 칼럼)에 넘긴다. */
  .reader-layout > main { max-width: none; }


  .reader-title, .doc-people, .prose, .finish, .reader-kind, .related-list { margin-left: 0; }
  .reader-title { font-size: var(--step-4); }
}


/* 드로어 — 헤더의 햄버거 버튼을 탭하면 왼쪽에서 슬라이드해 덮는다. 폰 퍼스트,
   데스크톱도 동일(이 앱은 폰에서 보는 게 기본이다 — 2026-07-30 은수).
   JS 0: details 로 열고 닫는다. 백드롭 = summary::before(fixed 전체 화면)라서
   어두운 배경을 탭하는 것이 곧 summary 탭 = 닫힘이 된다. */
.drawer > summary {
  list-style: none;               /* 삼각형 마커 제거 */
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  user-select: none;
}
.drawer > summary::-webkit-details-marker { display: none; }
.drawer > summary:hover, .drawer > summary:focus-visible { color: var(--link); background: var(--surface); }

.drawer[open] > summary {
  /* 열린 동안 햄버거 자체는 백드롭 뒤로 숨는다 — 패널의 링크가 주인공이다 */
  color: var(--text);
}
.drawer[open] > summary::before {
  content: "";
  position: fixed;
  inset: 0;
  background: var(--backdrop);
  z-index: 40;
}

.drawer-panel {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: min(78vw, 19rem);
  z-index: 50;
  overflow-y: auto;
  /* 글래스 — 뒤 화면이 비친다. 리더 상단바·형광펜 고르개와 같은 층. */
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);
  border-right: var(--border-width) solid color-mix(in srgb, var(--text) 8%, transparent);
  box-shadow: 12px 0 40px var(--backdrop);
  padding: var(--space-5) var(--space-4) var(--space-8);
}

.side-list { margin: 0; padding: 0; list-style: none; }
.side-list li { margin: 0; }
.side-heading {
  margin-top: var(--space-4);
  padding: var(--space-2) var(--space-2) var(--space-1);
  color: var(--muted);
  font-size: var(--step--1);
  font-weight: 600;
}
.side-link {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
  min-height: 2.75rem;
  padding: var(--space-2) var(--space-2);
  box-sizing: border-box;
  border-radius: var(--radius-sm);
  color: var(--text);
}
.side-link:hover, .side-link:focus-visible { background: var(--surface); text-decoration: none; }
.side-link.is-current { background: var(--surface); color: var(--link); font-weight: 600; }
.side-count { color: var(--muted); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.side-empty { padding: var(--space-2); color: var(--muted-2); font-size: var(--step--1); }
/* 로그아웃은 POST 라 버튼이어야 한다 — 옆 링크들과 같은 모양으로 눕힌다. */
.side-link-btn {
  width: 100%;
  font: inherit;
  text-align: left;
  background: transparent;
  border: 0;
  cursor: pointer;
}



/* ── 형광펜 (리더 본문 + /highlights 수집 화면) ───────────────────────────────── */

/* 칠해진 글귀. <mark> 는 브라우저 기본 배경이 세니 우리 색으로 덮어쓴다. */
.prose mark.hl-mark {
  background: var(--hl-yellow);
  color: inherit;
  border-radius: var(--radius-sm);
  padding: 0 var(--space-1);
  box-decoration-break: clone;         /* 줄바꿈을 넘어가도 양끝이 둥글게 */
  -webkit-box-decoration-break: clone;
  cursor: pointer;
}
.prose mark.hl-teal { background: var(--hl-teal); }
.prose mark.hl-red { background: var(--hl-red); }

/* 메모가 달린 형광펜은 밑줄 하나를 더 그어 "여기 뭐라고 적어놨다"를 알린다. */
.prose mark.has-memo { border-bottom: var(--focus-width) solid var(--hl-yellow-edge); }
.prose mark.hl-teal.has-memo { border-bottom-color: var(--hl-teal-edge); }
.prose mark.hl-red.has-memo { border-bottom-color: var(--hl-red-edge); }

/* 글귀를 끌어 놓으면 뜨는 색 고르개. 손가락으로 닿는 크기(44px)를 지킨다. */
.hl-toolbar {
  position: absolute;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1);
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: var(--border-width) solid color-mix(in srgb, var(--text) 10%, transparent);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px var(--backdrop);
}
.hl-toolbar[hidden] { display: none; }
/* 새로 칠하는 중엔 색만 고르면 된다 — 메모·지움은 이미 칠해진 것에만 뜻이 있다. */
.hl-toolbar[data-mode="new"] .hl-action { display: none; }

/* 폰에서는 선택 옆이 아니라 화면 아래에 붙인다.
   NOTE 선택 옆에 띄우면 안 보인다 — 폰은 글귀를 잡는 순간 OS 가 "복사·공유·전체 선택"
   메뉴를 그 자리에 먼저 띄우고, 그게 우리 툴바를 덮는다(2026-08-09 은수 실기기
   리포트). OS 메뉴는 선택 근처에만 뜨므로 화면 밑으로 피하면 자리가 겹치지 않는다.
   덤으로 엄지가 닿는 자리다. 데스크톱은 그런 메뉴가 없어 지금처럼 선택 옆에 둔다. */
@media (max-width: 59.99rem) {
  .hl-toolbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    width: 100%;
    justify-content: center;
    padding: var(--space-3);
    /* 홈 인디케이터·제스처 바를 피한다. 미지원 브라우저에선 env() 가 0 이다. */
    padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    border-bottom: 0;
    gap: var(--space-1);
  }
  .hl-toolbar[data-mode="memo"] { width: 100%; }
}

/* 메모를 쓸 땐 툴바가 세로로 펼쳐진다 — 색·지움은 물러나고 입력만 남는다. */
.hl-memo-editor { display: none; }
.hl-toolbar[data-mode="memo"] {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  width: min(22rem, calc(100vw - 2rem));
}
.hl-toolbar[data-mode="memo"] .hl-swatch,
.hl-toolbar[data-mode="memo"] .hl-action-danger,
.hl-toolbar[data-mode="memo"] [data-action="memo"] { display: none; }
.hl-toolbar[data-mode="memo"] .hl-memo-editor { display: block; }

.hl-memo-row { display: flex; gap: var(--space-2); }
.hl-memo-input {
  flex: 1;
  min-width: 0;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  background: var(--bg);
  color: var(--text);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: var(--step--1);
}
.hl-memo-input:focus-visible { outline: var(--focus-width) solid var(--link); outline-offset: -1px; }

/* 색에 이름이 있다(중요·발견·모르겠음) — 점 하나와 이름을 같이 보여준다. */
.hl-swatch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 2.75rem;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
}
.hl-swatch::before {
  content: "";
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 3px;
  background: var(--hl-yellow-edge);
}
.hl-swatch:hover, .hl-swatch:focus-visible { background: color-mix(in srgb, var(--text) 8%, transparent); }
.hl-swatch:focus-visible { outline: var(--focus-width) solid var(--link); outline-offset: 2px; }
/* 고르개는 본문 형광펜 색(--hl-*)이 아니라 **진한 쪽(--hl-*-edge)**으로 채운다.
   본문 색은 글자를 덮어도 읽히라고 어둡게 잡은 것이라, 다크에서 툴바 배경(--surface)
   대비가 1.4~2.1:1 밖에 안 나와 동그라미가 통째로 안 보인다(2026-08-09 은수 실기기
   리포트: "모바일에서는 안 보이네. 노랑초록빨강"). edge 로 바꾸면 4.7~8.0:1 이다. */
.hl-swatch-yellow::before { background: var(--hl-yellow-edge); }
.hl-swatch-teal::before { background: var(--hl-teal-edge); }
.hl-swatch-red::before { background: var(--hl-red-edge); }

.hl-action {
  min-width: 2.75rem;
  height: 2.75rem;
  padding: 0 var(--space-3);
  background: transparent;
  color: var(--muted);
  border: 0;
  border-radius: var(--radius-pill);
  font-size: var(--step--1);
  cursor: pointer;
}
.hl-action:hover, .hl-action:focus-visible { color: var(--text); }
.hl-action-danger:hover, .hl-action-danger:focus-visible { color: var(--wrong); }

/* 형광펜 곁의 한 줄 메모 — 본문 흐름을 끊지 않게 작게 붙인다. */
.hl-memo {
  display: block;
  margin: var(--space-1) 0 0;
  padding-left: var(--space-3);
  border-left: var(--focus-width) solid var(--border);
  color: var(--muted);
  font-size: var(--step--1);
}

/* 수집 화면 */
.hl-filters {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin: 0 0 var(--space-5);
}
.hl-filter {
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: var(--step--1);
}
.hl-filter.is-active { color: var(--text); border-color: var(--link); }
.hl-filter-dot {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  margin-right: var(--space-1);
  vertical-align: baseline;
}
.hl-filter-yellow .hl-filter-dot { background: var(--hl-yellow-edge); }
.hl-filter-teal .hl-filter-dot { background: var(--hl-teal-edge); }
.hl-filter-red .hl-filter-dot { background: var(--hl-red-edge); }

.hl-item {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border-radius: var(--radius-md);
  border-left: 3px solid var(--border);
}
/* 왼쪽 선이 곧 색이다 — 목록을 훑을 때 왜 칠했는지가 줄 시작에서 읽힌다. */
.hl-item-yellow { border-left-color: var(--hl-yellow-edge); }
.hl-item-teal { border-left-color: var(--hl-teal-edge); }
.hl-item-red { border-left-color: var(--hl-red-edge); }

.hl-quote { margin: 0 0 var(--space-2); line-height: var(--reader-line-height); }
.hl-item-memo { margin: 0 0 var(--space-2); color: var(--muted); font-size: var(--step--1); }
.hl-source {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  flex-wrap: wrap;
  font-size: var(--step--1);
  color: var(--muted);
}
.hl-source a { color: var(--link); }

/* ── 머메이드 다이어그램 ────────────────────────────────────────────────────── */

/* 렌더 전에는 설계도 원문이 그대로 보인다 — 순간적으로 코드가 번쩍이는 걸 막는다.
   mermaid 가 SVG 로 갈아 끼우면 data-processed 가 붙으면서 다시 보이게 한다. */
.prose pre.mermaid { visibility: hidden; }
.prose pre.mermaid[data-processed="true"] { visibility: visible; }

.prose pre.mermaid {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  background: var(--surface);
  border-radius: var(--radius-md);
  /* 넓은 그림은 페이지를 밀지 않고 자기 안에서만 가로 스크롤한다(코드블록·표와 같은 처방). */
  overflow-x: auto;
  text-align: center;
  line-height: 1.4;
}
.prose pre.mermaid svg { max-width: 100%; height: auto; }

/* 다이어그램 확대(은수 09-06) — 그림을 누르면 전체 화면 층. 오른쪽 위 작은 버튼이 「누를 수 있다」를 말한다. */
.prose pre.mermaid[data-processed="true"] { position: relative; cursor: zoom-in; }
.mermaid-zoom {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
}
.mermaid-zoom:hover, .mermaid-zoom:focus-visible { color: var(--text); border-color: var(--muted); }

.zoom-layer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}
.zoom-layer[hidden] { display: none; }
body.zoom-open { overflow: hidden; }
.zoom-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 3.25rem;
  padding: 0 var(--space-2) 0 var(--space-4);
  border-bottom: var(--border-width) solid var(--border);
  /* 홈 인디케이터·노치를 피한다. */
  padding-top: env(safe-area-inset-top, 0px);
}
.zoom-hint { flex: 1; color: var(--muted-2); font-size: var(--step--1); }
.zoom-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  height: 2.75rem;
  padding: 0 var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
}
.zoom-btn:hover, .zoom-btn:focus-visible { border-color: var(--muted); }
.zoom-close { padding: 0; border-radius: 50%; }
.zoom-stage {
  position: relative;
  flex: 1;
  overflow: hidden;
  /* 한 손가락 끌기·두 손가락 핀치를 전부 우리가 받는다. */
  touch-action: none;
  cursor: grab;
}
.zoom-stage:active { cursor: grabbing; }
.zoom-canvas { position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform; }
.zoom-canvas svg { display: block; }

/* 스크립트가 죽었거나 문법이 틀리면 원문이라도 읽히게 — 빈 자리로 두지 않는다. */
.prose pre.mermaid:not([data-processed="true"]) {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--muted);
  text-align: left;
  white-space: pre;
}

/* ── 기술사전 (/terms) — type 별 묶음. 학습노트 카드 스타일을 그대로 쓰고 묶음 머리만 더한다 */
.term-group { margin: 0 0 1.6rem; }
.term-group-title {
  margin: 0 0 .5rem;
  font-size: .95rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: .02em;
}
.term-aliases {
  margin: 2rem 0 0;
  padding-top: .8rem;
  border-top: 1px solid var(--border);
  font-size: .85rem;
  color: var(--muted);
}

/* ── 리더 상단 그래프 패널 — 지금 문서 기준 1홉 이웃. graph.js 가 그린다.
   높이는 그림이 뜨기 전에도 38vh 로 고정한다(본문이 밀리지 않게). */
.graph-panel {
  margin: 0 0 var(--space-6);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.graph-panel-head {
  display: flex;
  align-items: center;
  /* 왼쪽 그물/목차 탭, 오른쪽 버튼 묶음. */
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0 var(--space-3);
  border-bottom: var(--border-width) solid var(--border);
}

/* 그물/목차 탭 — 눌린 쪽만 글자색이 살고 밑줄이 붙는다. */
.panel-tabs { display: flex; gap: var(--space-1); }
.panel-tab {
  font: inherit;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-bottom: var(--focus-width) solid transparent;
  padding: var(--space-2) var(--space-2);
  min-height: 2.75rem;
  cursor: pointer;
}
.panel-tab[aria-pressed="true"] { color: var(--text); border-bottom-color: var(--text); }
.panel-tab:hover, .panel-tab:focus-visible { color: var(--text); }

/* 목차 탭 — 그물 자리에 목차를 편다. 그물 버튼(원래대로·고정·크게)은 목차에 뜻이 없어 감춘다. */
.panel-toc { display: none; height: 100%; overflow: auto; padding: var(--space-3) var(--space-4); box-sizing: border-box; }
.panel-toc .toc-list { margin: 0; }
.panel-toc .toc-list li { padding: var(--space-2) 0; font-size: var(--step-0); }
.panel-toc .toc-list li.toc-l3 { padding-left: var(--space-5); font-size: var(--step--1); }
.panel-toc .toc-list li.toc-l4 { padding-left: var(--space-6); font-size: var(--step--1); color: var(--muted); }
.panel-toc .toc-list li.toc-l5 { padding-left: var(--space-7); font-size: var(--step--1); color: var(--muted); }
.panel-toc .toc-list li.toc-l6 { padding-left: var(--space-8); font-size: var(--step--1); color: var(--muted); }
.graph-panel.is-toc .graph-svg,
.graph-panel.is-toc .graph-panel-msg,
.graph-panel.is-toc .graph-panel-actions { display: none; }
.graph-panel.is-toc .panel-toc { display: block; }
.graph-panel.is-toc .graph-panel-body { touch-action: auto; }

/* 접기 버튼 옆에 붙는 묶음 — graph.js 가 리셋 버튼을 여기 끼워 넣는다(줌이 1.0 이
   아닐 때만 보인다). 템플릿에는 없다. */
.graph-panel-actions { display: flex; align-items: center; gap: var(--space-2); }
.graph-panel-reset,
.graph-panel-move,
.graph-panel-full {
  font: inherit;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
}
.graph-panel-reset:hover,
.graph-panel-reset:focus-visible { background: var(--surface); }
.graph-panel-reset[hidden] { display: none; }

.graph-panel-body {
  position: relative;
  height: 48vh;
  /* 빈 곳을 한 손가락으로 끌면 그물이 움직인다(페이지 스크롤이 아니다).
     두 손가락은 확대·축소다. 브라우저 기본 동작을 전부 넘겨받는다. */
  touch-action: none;
}
.graph-panel.is-collapsed .graph-panel-body { display: none; }

/* 전체화면 — 폰에서 그물만 크게 본다. 뒤 본문은 스크롤을 잠근다. */
.graph-panel.is-full {
  position: fixed;
  inset: 0;
  z-index: 60;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
.graph-panel.is-full .graph-panel-body { height: auto; flex: 1; }
body.graph-full-open { overflow: hidden; }

.graph-svg { display: block; width: 100%; height: 100%; }
.graph-svg[hidden] { display: none; }

.graph-panel-msg {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--space-4);
  color: var(--muted);
  font-size: var(--step--1);
  text-align: center;
}
.graph-panel-msg[hidden] { display: none; }

/* 옵시디언 그래프뷰 톤 — 선은 거의 안 보일 만큼 흐리다. */
.graph-edge { stroke: var(--graph-edge); stroke-width: 0.7; }
.graph-edge[hidden] { display: none; }

.graph-label {
  fill: var(--muted);
  font-size: 10px;
  font-family: var(--font-sans);
  pointer-events: none;
}
.graph-label[hidden] { display: none; }

/* 2홉 — 확대해야 보이는 곁가지라 더 흐리게. 점 크기는 graph.js 가 정한다. */
.graph-node-hop2 circle { opacity: 0.55; }
.graph-node-hop2[hidden] { display: none; }

/* 무리 노드(관련 항목 소제목) — 중심과 식구들 사이에 낀 갈래다. 문서가 아니라
   묶음이라 속을 비우고 테두리만 둔다. 이름은 늘 보인다. */
.graph-node-group circle {
  fill: none;
  stroke: var(--accent-read);
  stroke-width: 1.6;
  cursor: grab;
}
/* 한 층 아래 무리 — 곁가지라 선도 가늘고 흐리다. */
.graph-node-subgroup circle:not(.graph-node-hit) { stroke-width: 1; opacity: 0.7; }
/* 탭 판정용 원은 절대 안 보인다 — 색 규칙이 실수로 잡아 큰 링으로 나타난 적이 있다. */
.graph-node-hit { fill: transparent !important; stroke: none !important; }

/* 잎 — 줄기보다 뒤로 물러나야 구조가 먼저 읽힌다. */
.graph-node-leaf circle:not(.graph-node-hit) { opacity: 0.6; }
.graph-node-leaf ~ text, .graph-label.graph-label-leaf { opacity: 0.75; }

/* 무리 색 — 같은 갈래에 속한 점·소제목·선이 같은 색을 쓴다. */
.graph-g0 { --group-color: var(--g0); }
.graph-g1 { --group-color: var(--g1); }
.graph-g2 { --group-color: var(--g2); }
.graph-g3 { --group-color: var(--g3); }
.graph-g4 { --group-color: var(--g4); }
.graph-g5 { --group-color: var(--g5); }
.graph-g6 { --group-color: var(--g6); }
.graph-g7 { --group-color: var(--g7); }
.graph-g8 { --group-color: var(--g8); }
.graph-g9 { --group-color: var(--g9); }
.graph-g10 { --group-color: var(--g10); }
.graph-g11 { --group-color: var(--g11); }
.graph-g12 { --group-color: var(--g12); }
.graph-g13 { --group-color: var(--g13); }
.graph-g14 { --group-color: var(--g14); }
.graph-g15 { --group-color: var(--g15); }
.graph-g16 { --group-color: var(--g16); }
.graph-g17 { --group-color: var(--g17); }
.graph-g18 { --group-color: var(--g18); }
.graph-g19 { --group-color: var(--g19); }
.graph-g20 { --group-color: var(--g20); }
.graph-g21 { --group-color: var(--g21); }
.graph-g22 { --group-color: var(--g22); }
.graph-g23 { --group-color: var(--g23); }
.graph-g24 { --group-color: var(--g24); }
.graph-g25 { --group-color: var(--g25); }
.graph-g26 { --group-color: var(--g26); }
.graph-g27 { --group-color: var(--g27); }
.graph-g28 { --group-color: var(--g28); }
.graph-g29 { --group-color: var(--g29); }
.graph-node.graph-gc a circle:not(.graph-node-hit) { fill: var(--group-color); }
.graph-node-group.graph-gc circle:not(.graph-node-hit) { stroke: var(--group-color); }
.graph-label.graph-gc { fill: var(--group-color); }
.graph-edge.graph-gc { stroke: var(--group-color); opacity: 0.45; }
/* 아직 없는 용어는 무리 색을 쓰되 속을 비워 구분한다. */
.graph-node-missing.graph-gc circle:not(.graph-node-hit) {
  fill: none;
  stroke: var(--group-color);
}
.graph-node-group .graph-node-hit { stroke: none; }
.graph-label-group {
  fill: var(--accent-read);
  font-weight: 600;
  letter-spacing: 0.02em;
}
.graph-label-center { font-size: 11px; font-weight: 700; fill: var(--text); }

/* 용어(중심이 노트여도 모양은 같다) = 속이 찬 점. 옵시디언처럼 테두리 없이
   채움만으로 그린다. */
.graph-node-term a circle:not(.graph-node-hit),
.graph-node-note a circle:not(.graph-node-hit) {
  fill: var(--graph-node);
  stroke: none;
  cursor: pointer;
  touch-action: none;
}
.graph-node-missing circle:not(.graph-node-hit) {
  fill: var(--graph-node-missing);
  stroke: none;
  touch-action: none;
}
/* 중심만 청록으로 채워 "내가 지금 여기 있다"를 보여준다. */
.graph-node-center a circle:not(.graph-node-hit),
.graph-node-center.graph-node-missing circle:not(.graph-node-hit) {
  fill: var(--accent-read);
}

/* 점이 작아진 만큼(반지름 3) 손가락으로 못 짚는다 — 보이는 점 밑에 안 보이는
   히트 원을 더 크게 겹쳐 그린다. fill 이 있어야 SVG 기본 pointer-events
   (visiblePainted) 에서 히트 테스트가 되니 투명 채움 + pointer-events 를 명시한다. */
.graph-node-hit {
  fill: transparent;
  pointer-events: all;
  touch-action: none;
}

/* ==== 서재 · 드로어 · 둘러보기 ==== */

/* 서재 한 줄 — 줄 전체는 그 시리즈로 가고, 발치의 「다음 편」은 이어 읽을 편을 바로 연다.
   두 링크는 겹치지 않는 형제라 엄지로 어디를 눌러도 뜻이 하나다. */
.shelf-row { padding-bottom: var(--space-1); }
.shelf-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-width: 0;
}
/* 읽는 축이라 청록. 눌리는 높이는 엄지 기준(44px), 보이는 것은 작은 줄 하나. */
.shelf-next {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  min-height: 2.75rem;
  margin-left: calc(var(--space-2) * -1);
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  color: var(--accent-read);
  font-size: var(--step--1);
  font-weight: 600;
}
.shelf-next:hover, .shelf-next:focus-visible { background: var(--surface); text-decoration: none; }
.shelf-next-label { flex: 0 0 auto; }
/* 편 제목은 길다 — 한 줄로 자른다. 잘려도 앞의 「다음 편」이 무엇인지 말한다. */
.shelf-next-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  font-weight: 400;
}
/* 순서 없는 시리즈 — 편 번호를 믿지 말라는 표식 하나. */
.shelf-mark {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--muted-2);
  font-size: var(--step--1);
}

/* 드로어의 서재 줄 — 시리즈로 가는 링크 옆에 다음 편 화살표를 형제로 세운다. */
.side-row { display: flex; align-items: center; gap: var(--space-1); }
.side-row .side-link { flex: 1 1 auto; min-width: 0; }
.side-next {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  min-height: 2.75rem;
  border-radius: var(--radius-sm);
  color: var(--accent-read);
}
.side-next:hover, .side-next:focus-visible { background: var(--surface); text-decoration: none; }
/* 「서재」 머리글 자체가 서재 화면으로 가는 링크다 — 담은 시리즈 목록의 주인 자리. */
.side-heading-link {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  margin: calc(var(--space-2) * -1) 0;
  color: inherit;
}
.side-heading-link:hover, .side-heading-link:focus-visible { color: var(--link); text-decoration: none; }
.side-heading-link.is-current { color: var(--link); }

/* 시리즈 화면의 편 목록 — 다음에 읽을 편이 목록 어디쯤인지 그 자리에서 말한다.
   표식 줄과 그 다음 줄이 같은 왼 괘선으로 묶여 한 덩이로 읽힌다. */
.row-next-mark,
.row-next-mark + .row {
  border-left: 2px solid var(--accent-read);
  padding-left: var(--space-3);
}
.row-next-mark {
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  color: var(--accent-read);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* 둘러보기 — 소제목 바로 밑에 붙는 설명 줄은 위 여백을 걷는다. */
.home-head + .list-head { margin-top: 0; }
/* 서재 줄의 시리즈 소개는 한 줄만 — 여기서 고르는 것은 소개가 아니라 다음 편이다. */
.shelf-row .row-blurb { -webkit-line-clamp: 1; }

/* ==== 리더 · 형광펜 · 기술사전 ==== */

/* ── 리더: 시리즈 앞뒤 편 ─────────────────────────────────────────────────────── */

/* 본문을 다 읽은 자리에서 갈 곳. 읽음 토글과 관련 항목 사이에 선다. */
.reader-series-nav {
  max-width: var(--measure);
  margin: var(--space-6) auto;
}
.reader-series-where {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  font-size: var(--step--1);
}
.reader-series-where a { color: var(--muted); }
.reader-series-where a:hover, .reader-series-where a:focus-visible { color: var(--link); }

/* 앞뒤 편은 두 칸이다 — 한쪽만 있으면 그쪽이 제 자리를 지키게 이전은 왼쪽, 다음은 오른쪽. */
.reader-series-steps { display: flex; gap: var(--space-3); }
.reader-series-step {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
  align-items: center;
  gap: var(--space-2);
  min-height: 2.75rem;               /* 엄지 목표 44px */
  padding: var(--space-3);
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
}
.reader-series-step:hover, .reader-series-step:focus-visible {
  border-color: var(--muted);
  text-decoration: none;
}
.reader-series-step.is-next { flex-direction: row-reverse; text-align: right; margin-left: auto; }
.reader-series-step svg { flex: none; color: var(--muted); }
.reader-series-step-label {
  flex: none;
  color: var(--muted-2);
  font-size: var(--step--1);
}
/* 라벨을 위에, 제목을 아래에 둔다 — 두 칸이 폰 폭에 나란히 서도 제목이 두 줄까지 읽힌다. */
.reader-series-step-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.reader-series-step.is-next .reader-series-step-text { align-items: flex-end; }
.reader-series-step-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
  font-size: var(--step--1);
}
/* 앞뒤 편이 둘 다 없을 때(편이 하나뿐)의 길 — 시리즈 화면으로는 언제나 갈 수 있다. */
.reader-series-more { margin: 0; font-size: var(--step--1); }


/* 상단 바의 서재 버튼 — 목록 화면의 큰 버튼과 달리 한 줄 높이 안에 들어가야 한다. */
.reader-top .shelf-btn {
  flex: none;
  padding: 0 var(--space-3);
  font-size: var(--step--1);
  white-space: nowrap;
}
/* 상단바에 버튼이 둘이라 돌아갈 곳 이름은 남는 폭만 쓴다 — 넘치면 말줄임. */
.reader-top .back { min-width: 0; }
.reader-top .back span { overflow: hidden; text-overflow: ellipsis; }

/* ── 형광펜 모아보기 ───────────────────────────────────────────────────────── */

/* 거르개는 엄지로 누른다 — 알약 안쪽 여백만으로는 44px 이 안 나온다. */
.hl-filters .hl-filter {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/* 잇달아 같은 문서에서 나온 것들의 머리. 제목은 한 번만 서고 아래가 그 문서의 형광펜이다. */
.hl-doc { margin: 0 0 var(--space-6); }
.hl-doc-title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  font-size: var(--step-0);
  font-weight: 600;
}
.hl-doc-title a { color: var(--link); }

/* 앞 글자는 문맥일 뿐이라 흐리게 — 눈은 칠한 글귀에 먼저 닿아야 한다. */
.hl-prefix { color: var(--muted-2); }
/* 칠한 색은 왼쪽 선이 이미 말한다 — 여기서는 배경 없이 또렷한 글자색만으로 세운다
   (브라우저 기본 mark 는 노란 배경이라 다크에서 눈이 아프다). */
.hl-exact { background: transparent; color: var(--text); }

/* ── 기술사전 ─────────────────────────────────────────────────────────────── */

/* 분량은 고르는 데 쓰는 곁가지다 — 갈래보다 한 단 더 흐리게. */
.term-size { margin-left: var(--space-2); color: var(--muted-2); }


/* ==== 드로어 닫기 과녁 · 리더 시리즈 이동 ==== */

/* 드로어를 연 동안 햄버거 자리는 패널(z-index 50)에 덮여 있었다 — 그 자리를 탭하면
   패널 첫 링크가 눌려 대문으로 갔다. 여는 자리가 곧 닫는 자리여야 하므로 summary 의
   과녁만 패널 위로 올린다. summary 자체에 z-index 를 주면 쌓임 맥락이 생겨 백드롭
   (::before, z-index 40)까지 딸려 올라와 패널을 덮으므로, 위치만 잡고 z-index 는
   과녁(::after)에만 준다. */
.drawer[open] > summary { position: relative; }
.drawer[open] > summary::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 60;
}
/* 과녁 아래에 첫 링크가 깔리지 않게 패널 머리를 그만큼 비운다. */
.drawer[open] .drawer-panel { padding-top: calc(2.75rem + var(--space-3)); }

/* 시리즈 이름과 「이 시리즈의 다른 편」은 글줄 높이(각각 21px·15px)뿐이라 엄지로 못 짚는다.
   보이는 것은 그대로 한 줄, 눌리는 높이만 44px 로 연다. */
.reader-series-where a,
.reader-series-more a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 var(--space-2);
  margin: 0 calc(var(--space-2) * -1);
  border-radius: var(--radius-sm);
}
.reader-series-where a:hover,
.reader-series-where a:focus-visible,
.reader-series-more a:hover,
.reader-series-more a:focus-visible { background: var(--surface); text-decoration: none; }
/* 앞뒤 편 칸도 같은 높이 — 값이 와서 켜질 때 이미 44px 이어야 한다. */
.reader-series-step { min-height: 2.75rem; }

/* 상단 바의 돌아갈 곳은 시리즈 이름을 문다 — 긴 이름이 제목과 관심 버튼을 밀어내지 않게
   화면 폭의 절반 아래로 묶고 넘치면 말줄임한다. */
.reader-top .back { max-width: 45vw; }
.reader-top .back span { min-width: 0; white-space: nowrap; }

/* ==== 별자리 · 마이페이지 ==== */

.constellation { margin-top: var(--space-4); }
.constellation-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin: var(--space-6) 0 var(--space-2);
}
/* 상단바의 되돌리기 — 목차 버튼과 같은 44px 아이콘 자리. */
.constellation-refresh {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  margin-right: -0.5rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.constellation-refresh:hover,
.constellation-refresh:focus-visible { color: var(--text); background: var(--surface); }

/* 판이 아니라 하늘이다 — 테두리도 바탕색도 더하지 않는다.
   빈 곳을 한 손가락으로 끌면 별자리가 움직이고 두 손가락은 확대·축소다. */
.constellation-body {
  position: relative;
  height: 38vh;
  min-height: 17rem;
  touch-action: none;
}
.constellation-svg { display: block; width: 100%; height: 100%; }
/* 가장자리로 갈수록 흐려진다 — 타원이 상자 안에서 끝나므로 네 변 어디서도 별이 잘린 채
   드러나지 않는다(은수 2026-09-09 「가장자리 별이 잘려 이질감」). 반지름이 상자 절반이라
   위·아래 한가운데도 0 에 닿는다. */
.constellation-svg {
  -webkit-mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, #000 58%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
  mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, #000 58%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
}
/* 별마다 제 박자로 깜빡인다 — 주기·시작점은 JS 가 별 그룹에 변수로 준다. */
@keyframes constellation-twinkle {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.constellation-star .constellation-star-dot {
  animation: constellation-twinkle var(--twinkle-dur, 3s) ease-in-out infinite;
  animation-delay: var(--twinkle-delay, 0s);
}
@media (prefers-reduced-motion: reduce) {
  .constellation-star .constellation-star-dot { animation: none; }
}

/* 장식 알갱이 — 데이터가 아니라 하늘의 결이라 눌리지 않는다. */
.constellation-dust { pointer-events: none; }
.constellation-star-dust { fill: var(--graph-node); }
/* 먼지 몇은 아주 느리게 숨 쉰다 — 별의 깜빡임과 같은 keyframes, 주기만 길다. */
.constellation-star-dust-twinkle {
  animation: constellation-twinkle var(--twinkle-dur, 8s) ease-in-out infinite;
  animation-delay: var(--twinkle-delay, 0s);
}
@media (prefers-reduced-motion: reduce) { .constellation-star-dust-twinkle { animation: none; } }
.constellation-dust-stop { stop-color: var(--graph-node); }
/* 깜빡이지 않는 별(용어) 과 ?sky=still — 자리·색은 그대로, 움직임만 없다. */
.constellation-star-still .constellation-star-dot, .sky-still .constellation-star-dot, .sky-still .constellation-star-dust-twinkle { animation: none; }
.constellation-svg.sky-nomask { -webkit-mask-image: none; mask-image: none; }
/* 하늘이 화면 밖이면(JS 가 is-offscreen 을 단다) 반짝임을 멈춘다 — 자리는 그대로, 다시 보이면 이어서 깜빡인다. */
.is-offscreen .constellation-star-dot, .is-offscreen .constellation-star-dust-twinkle { animation-play-state: paused; }

/* 선은 별보다 조용하다. */
.constellation-edge { stroke: var(--graph-node); stroke-width: 0.6; opacity: 0.07; }

/* 밝기 셋 — 열어만 봤다(작고 흐린 원) · 다 읽었다(찬 원) · 관심(큰 원 + 빛무리). 모두 찬 원이고 색은 노랑 하나다.
   원의 채움은 defs 의 방사 그러데이션(JS 가 fill 속성으로 건다)이라 여기서 fill 을 주면 안 된다 —
   CSS 가 프리젠테이션 속성을 이겨서 다시 딱딱한 도장이 된다. 색만 stop 에 준다. */
/* 그린 원은 판정에 안 낀다 — 바깥 투명 띠까지 눌리면 판정이 두 배로 넓어진다. */
.constellation-star-dot { pointer-events: none; }
.constellation-star-stop { stop-color: var(--star); }
.constellation-star-stop-read { stop-color: var(--star-read); }
.constellation-star-stop-interest { stop-color: var(--star-interest); }
.constellation-star-dot { stroke: none; cursor: pointer; touch-action: none; }
/* 노트는 밝고, 용어는 한 단계 흐리다 — 같은 밝기 단계라도 갈래로 한 번 더 갈린다. */
.constellation-star-opened .constellation-star-dot { opacity: 0.6; }
.constellation-star-read .constellation-star-dot { opacity: 1; }
.constellation-star-term.constellation-star-opened .constellation-star-dot { opacity: 0.38; }
.constellation-star-term.constellation-star-read .constellation-star-dot { opacity: 0.7; }


.constellation-label {
  fill: var(--muted);
  font-size: 10px;
  font-family: var(--font-sans);
  pointer-events: none;
}
.constellation-label[hidden] { display: none; }
.constellation-label-number { fill: var(--star); font-weight: 600; }   /* 두 줄일 때 위 줄의 번호 — 별 색으로 */


/* ==== 별자리 = 문서 배경 ==== */
/* 별자리 SVG 자체가 문서 위쪽 배경이다(은수 2026-09-09 「svg 자체를 배경으로」). 상자
   (.constellation-body)는 본문에서 자리만 잡고, SVG 는 body 기준 절대 위치로 맨 위에서
   --sky-height 까지 깔린다. 별·성운·하늘이 한 층이라 당기고 끌 때 같이 움직인다. */
body.has-sky { position: relative; }
body.has-sky .constellation-body { position: static; }   /* SVG 의 기준을 상자가 아니라 body 로 */
body.has-sky .constellation-svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--sky-height, 82vh);
  z-index: -1;
  background:
    radial-gradient(ellipse 60% 45% at 22% 22%, var(--nebula-a), transparent 70%),
    radial-gradient(ellipse 55% 42% at 80% 60%, var(--nebula-b), transparent 70%),
    radial-gradient(ellipse 40% 30% at 60% 36%, var(--nebula-a), transparent 75%),
    var(--space-deep);
  /* 아래로 갈수록 판 바탕에 녹는다. 좌우·위는 화면 끝이라 자르지 않는다 — 하늘이 잘리는 건 자연스럽다. */
  -webkit-mask-image: linear-gradient(#000 55%, transparent 100%);
  mask-image: linear-gradient(#000 55%, transparent 100%);
}
body.has-sky .constellation-svg.sky-nomask { -webkit-mask-image: none; mask-image: none; }
/* 손은 상자(.constellation-body)만 받는다 — 문서 배경으로 뻗은 SVG 는 손을 안 받아 상자 밖에서는
   페이지가 평소처럼 스크롤된다. 상자 밖에 걸린 별은 제 히트 원이 직접 받는다(pointer-events: all). */
body.has-sky .constellation-svg { pointer-events: none; }
body.has-sky .constellation-body { pointer-events: auto; touch-action: none; }

/* ==== 서재 카드 · 빼기 ==== */
/* 서재 줄의 × — 오른쪽 위 44px. 줄 링크와 겹치지 않게 줄 오른쪽에 그만큼 여백을 둔다. */
.shelf-row { position: relative; padding-right: 2.75rem; }
.shelf-remove {
  position: absolute;
  top: var(--space-2);
  right: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.shelf-remove:hover, .shelf-remove:focus-visible { color: var(--text); background: var(--surface); }

/* ==== 둘러보기 — 시리즈 카드 · 작은 별자리 ==== */
/* 발견하는 자리라 소개가 앞서고 진도는 별자리가 말한다. 카드는 괘선으로 가르고 오른쪽 위에
   시리즈마다 다른 성운 빛을 아주 흐리게 깐다. */
.browse-search { margin-top: var(--space-4); }
.series-cards { list-style: none; margin: 0; padding: 0; }
.series-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4) var(--space-2);
  margin: 0 calc(-1 * var(--space-4));
  border-bottom: var(--border-width) solid var(--border);
  overflow: hidden;
}
.series-card:nth-child(9n+1) { --card-glow: var(--g0); }
.series-card:nth-child(9n+2) { --card-glow: var(--g3); }
.series-card:nth-child(9n+3) { --card-glow: var(--g6); }
.series-card:nth-child(9n+4) { --card-glow: var(--g9); }
.series-card:nth-child(9n+5) { --card-glow: var(--g12); }
.series-card:nth-child(9n+6) { --card-glow: var(--g15); }
.series-card:nth-child(9n+7) { --card-glow: var(--g18); }
.series-card:nth-child(9n+8) { --card-glow: var(--g21); }
.series-card:nth-child(9n+9) { --card-glow: var(--g24); }
.series-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 70% 90% at 100% 0%, color-mix(in srgb, var(--card-glow, var(--accent-read)) 12%, transparent), transparent 70%);
  pointer-events: none;
}
.series-card > * { position: relative; }
.series-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.series-card-name { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.series-card-title { font-size: var(--step-2); font-weight: 300; line-height: 1.3; letter-spacing: -0.01em; color: var(--text); word-break: keep-all; overflow-wrap: anywhere; }
.series-card-title:hover, .series-card-title:focus-visible { color: var(--text); text-decoration: none; opacity: 0.85; }
.series-card-meta { color: var(--muted-2); font-size: var(--step--1); font-variant-numeric: tabular-nums; }
.series-stars { flex: none; }
/* 안 읽은 별은 회색 흐림, 읽은 별은 노랑 알맹이 + 빛무리. 색은 그러데이션 stop 이 변수에서 받는다. */
.series-star-stop-dim { stop-color: var(--muted); }
.series-star-stop-glow { stop-color: var(--star-read); }
.series-star-core { fill: var(--star-read); }
.series-star-next { fill: var(--star); fill-opacity: 0.16; }   /* 다음 편 — 아직 열어보기 전이라 노랑 */
.series-star-line { stroke: var(--card-glow, var(--muted)); stroke-opacity: 0.22; stroke-width: 1; }
.series-star-line.is-read { stroke-opacity: 0.55; }
/* 소개는 투영이 준다. 빌려 온 조각(편 목록·원래 단추)은 별자리·손잡이의 재료라 감춘다. */
.shelf-borrow:empty { display: none; }
.series-card-desc, .shelf-borrow .lead {
  margin: 0;
  color: color-mix(in srgb, var(--text) 82%, var(--muted));
  font-size: var(--step-0);
  line-height: 1.55;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  word-break: keep-all;
}
.shelf-borrow .rows, .shelf-borrow .cta { display: none; }
.series-card-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.series-card-entry { display: flex; align-items: center; min-height: 2.75rem; }
.series-card-entry .shelf-next { margin-left: calc(-1 * var(--space-2)); }
.series-shelf-btn { min-height: 2.5rem; padding: 0 var(--space-4); font-size: var(--step--1); }
/* 시리즈 화면의 큰 별자리 — 카드 것과 같은 규칙, 폭만 가득(도면 360×170). 별을 누르면 그 편으로 간다. */
.series-stars-big { display: block; width: 100%; height: auto; margin: var(--space-4) 0 0; }
.series-stars-big .series-star { cursor: pointer; }
/* 서재 줄의 작은 별자리 — 제목 오른쪽, 편 수 위. 빌려 온 편 목록은 감춘다. */
.shelf-head-side { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex: none; }
.shelf-stars { display: block; }
.shelf-row .shelf-borrow { display: none; }
/* 하트는 켜지면 빨강 — 읽는 축(청록)과 갈래가 다르다. 기존 규칙은 두고 여기서 덮는다. */
.reader-top .interest-btn.is-interested, .interest-btn.is-interested { color: var(--heart); }
/* 마이페이지 관심 문서 줄 — 진도바 없이 읽음 표식만, 오른쪽에 관심 끄기 ×. */
.interest-row { position: relative; padding-right: 2.75rem; }
.interest-off {
  position: absolute;
  top: var(--space-2);
  right: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.interest-off { color: var(--heart); }   /* 켜진 하트 — 리더의 하트와 같은 빨강 */
.interest-off:hover, .interest-off:focus-visible { color: var(--text); background: var(--surface); }
/* 쪽 넘기기 — 알약 단추 한 줄. 지금 쪽은 채운다. */
.pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-2); margin: var(--space-4) 0 0; }
.pager-btn {
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0 var(--space-3);
  font: inherit;
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  background: transparent;
  border: var(--border-width) solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.pager-btn[aria-current="page"] { color: var(--bg); background: var(--text); border-color: var(--text); }
.pager-btn:disabled { opacity: 0.35; cursor: default; }
.pager-btn:not(:disabled):not([aria-current]):hover { color: var(--text); background: var(--surface); }

/* ==== 리더 그물 — 별자리 결 ==== */
/* 그물을 마이페이지 별자리와 같은 하늘로 — 테두리 없이 크게, 깊은 바탕에 성운 빛, 둘레는 어둠에
   잠기고, 노드는 빛점이다. 배치와 이름표는 그물의 것을 지킨다(은수 2026-09-09). */
.graph-panel { border: 0; border-radius: 0; margin-left: calc(-1 * var(--space-4)); margin-right: calc(-1 * var(--space-4)); overflow: visible; }
.graph-panel-head { border-bottom: 0; padding: 0 var(--space-4); }
.graph-panel-name { color: var(--muted); font-size: var(--step--1); font-weight: 600; letter-spacing: 0.04em; }
.graph-panel-body {
  height: 62vh;
  min-height: 18rem;
  background:
    radial-gradient(ellipse 60% 45% at 22% 22%, var(--nebula-a), transparent 70%),
    radial-gradient(ellipse 55% 42% at 80% 60%, var(--nebula-b), transparent 70%),
    radial-gradient(ellipse 70% 66% at 50% 50%, var(--space-deep) 0%, var(--space-deep) 40%, transparent 100%);
}
.graph-panel.is-full .graph-panel-body { height: auto; }
.graph-panel.is-full { background: var(--space-deep); }
/* 둘레 흐림 — 타원이 상자 안에서 끝나 어느 변에서도 별이 잘린 채 드러나지 않는다. */
.graph-svg {
  -webkit-mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, #000 58%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
  mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, #000 58%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
}
/* 노드는 빛점 — 채움은 graph.js 가 준 그러데이션이고 색은 여기서. 무리 색은 이름표·선에만 남는다. */
.graph-star-stop-center { stop-color: var(--star-read); }
.graph-star-stop-near { stop-color: var(--star); }
.graph-star-stop-dim { stop-color: var(--muted); }
.graph-node a circle.graph-star, .graph-node-missing circle.graph-star { stroke: none; }
.graph-node-hop2 circle.graph-star { opacity: 0.7; }
.graph-star-glow { pointer-events: none; }
.graph-node a circle.graph-star {
  animation: constellation-twinkle var(--twinkle-dur, 3s) ease-in-out infinite;
  animation-delay: var(--twinkle-delay, 0s);
}
@media (prefers-reduced-motion: reduce) { .graph-node a circle.graph-star { animation: none; } }
.graph-svg.is-offscreen .graph-node a circle.graph-star { animation-play-state: paused; }
/* 선은 별보다 조용하되 읽혀야 한다 — 이 그물은 「무엇이 무엇에 닿나」가 내용이라 별자리보다 짙다(은수 2026-09-09). */
.graph-edge { stroke: var(--graph-node); stroke-opacity: 0.55; }
.graph-edge.graph-gc { stroke: var(--group-color); opacity: 0.7; }
/* 무리 노드(관련 항목 묶음)의 고리는 흐리게 — 갈래 표시만 남긴다. */
.graph-node-group circle:not(.graph-node-hit) { stroke-width: 1.2; opacity: 0.8; }

/* ==== 리더 그물 = 문서 배경 ==== */
/* 마이페이지 별자리와 같은 자리 — SVG 가 body 기준으로 문서 맨 위(상단바 뒤)부터 --sky-height 까지
   깔리고 아래로 갈수록 판 바탕에 녹는다. 상자(.graph-panel-body)는 자리만 잡고 손을 받는다. */
/* 하늘은 본문(main) 머리부터 — 제목·쓴 사람 위로는 안 올라간다(은수 2026-09-09 「제목과 겹친다, 팍 줄여」). */
/* 그물 배경(SVG)의 기준 상자는 그물 패널이다 — 제목 묶음이 main 안에 들어와 main 을 기준으로
   두면 하늘이 제목 위까지 올라간다(2026-09-12 article 로 묶으며). */
body.reader-sky .graph-panel { position: relative; }
body.reader-sky .graph-panel { overflow: visible; margin-top: 0; }
body.reader-sky .graph-panel-body { position: static; height: 30vh; min-height: 12rem; background: none; }
body.reader-sky .graph-svg {
  position: absolute;
  /* 양옆은 화면 벽까지 — 본문 폭(44rem·여백 1rem)에 갇히지 않게 화면 폭으로 펼친다(은수 2026-09-09). */
  left: calc(50% - 50vw);
  width: 100vw;
  /* 위아래로 20px 씩 더 — 머리 줄 위와 본문 첫 줄 뒤까지 살짝 물린다. */
  top: -20px;
  height: calc(var(--sky-height, 44vh) + 40px);
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 45% at 22% 22%, var(--nebula-a), transparent 70%),
    radial-gradient(ellipse 55% 42% at 80% 60%, var(--nebula-b), transparent 70%),
    var(--space-deep);
  /* 위아래 모두 판 바탕에 넓게 번지며 녹는다 — 경계가 보이지 않게 띠를 길게 잡는다. */
  -webkit-mask-image: linear-gradient(transparent 0%, #000 26%, #000 56%, transparent 100%);
  mask-image: linear-gradient(transparent 0%, #000 26%, #000 56%, transparent 100%);
}
body.reader-sky .graph-panel-msg { position: relative; inset: auto; min-height: 6rem; }
/* 「크게」 — 패널이 화면을 다 쓰는 동안은 SVG 가 도로 상자 안을 채운다. */
body.reader-sky .graph-panel.is-full .graph-panel-body { position: relative; height: auto; }
body.reader-sky .graph-panel.is-full .graph-svg {
  position: static;
  height: 100%;
  z-index: auto;
  -webkit-mask-image: none;
  mask-image: none;
}

/* ── 리더 하단바(폰) — 엄지 자리의 읽음 체크와 시리즈 앞뒤 편. reader.html 의 스크롤
   스크립트가 is-shown 을 단다: 올리면 나오고 내리면 숨고 끝에 닿으면 나온다. 상단바와 같은 글래스. */
.reader-bottom {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-top: var(--border-width) solid color-mix(in srgb, var(--text) 8%, transparent);
  transform: translateY(110%);
  transition: transform 0.22s ease;
}
.reader-bottom.is-shown { transform: none; }
@media (prefers-reduced-motion: reduce) { .reader-bottom { transition: none; } }
/* 하단바의 읽음 토글 — 본문 끝의 것과 같은 버튼이되 구획 선·여백 없이 한 줄 높이에 앉는다. */
.finish-compact { margin: 0; padding: 0; border: 0; max-width: none; }
.reader-bottom-spacer { flex: 1 1 auto; }
.reader-bottom-step {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-md);
  color: var(--text);
}
.reader-bottom-step:hover, .reader-bottom-step:focus-visible { color: var(--link); text-decoration: none; }
/* 하단바의 버튼들은 테두리 없이 선다(은수 2026-09-09) — 글래스 바 위에 상자까지 서면 겹이 두 개다. */
.reader-bottom .read-toggle, .reader-bottom .interest-btn { border: 0; }
/* 폰에서는 하트가 하단바로 내려간다 — 상단바에는 돌아갈 곳·제목·목차만 남긴다(은수 2026-09-09). */
@media (max-width: 59.99rem) { .reader-top .interest-slot { display: none; } }
/* 첫 편의 이전·마지막 편의 다음 — 자리는 지키되 눌리지 않는다. */
.reader-bottom-step.is-off { color: var(--muted-2); opacity: 0.45; pointer-events: none; }
/* 하단바가 올라와도 본문 끝(다 읽었다 버튼)이 가려지지 않게 그만큼 비운다. */
.reader-body #js-reader-main { padding-bottom: calc(3.75rem + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 60rem) {
  .reader-bottom { display: none; }
  .reader-body #js-reader-main { padding-bottom: 0; }
}

/* 하늘(별자리·그물 배경)이 있는 화면에서는 손으로 만지는 기기에서 떠 있는 바의 배경 흐림을 끈다 —
   깜빡이는 하늘 위에서 backdrop-filter 는 매 프레임 다시 흐려 폰이 끊긴다(은수 2026-09-09 실기기 비교).
   흐림 대신 거의 불투명한 바탕을 깐다. 마우스 기기는 글래스를 그대로 둔다. ?sky=noglass 는 어디서든 끈다. */
@media (pointer: coarse) {
  body.has-sky .top::before, body.reader-sky .reader-top, body.reader-sky .reader-bottom {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: color-mix(in srgb, var(--bg) 94%, transparent);
  }
}
body.sky-noglass .top::before { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--bg); }
