/* λ Parenthesis — 블로그 스타일시트 */

/* 웹과 Windows 제어판이 같은 로컬 글꼴 파일을 쓴다. */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-Regular.ttf") format("truetype");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-Medium.ttf") format("truetype");
  font-style: normal;
  font-weight: 500;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-SemiBold.ttf") format("truetype");
  font-style: normal;
  font-weight: 600;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-Bold.ttf") format("truetype");
  font-style: normal;
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-Italic.ttf") format("truetype");
  font-style: italic;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("fonts/IBMPlexSans-BoldItalic.ttf") format("truetype");
  font-style: italic;
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Regular.ttf") format("truetype");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Medium.ttf") format("truetype");
  font-style: normal;
  font-weight: 500;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-SemiBold.ttf") format("truetype");
  font-style: normal;
  font-weight: 600;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Bold.ttf") format("truetype");
  font-style: normal;
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-Italic.ttf") format("truetype");
  font-style: italic;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/IBMPlexMono-BoldItalic.ttf") format("truetype");
  font-style: italic;
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans KR";
  src: url("fonts/IBMPlexSansKR-Regular.ttf") format("truetype");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans KR";
  src: url("fonts/IBMPlexSansKR-Medium.ttf") format("truetype");
  font-style: normal;
  font-weight: 500;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans KR";
  src: url("fonts/IBMPlexSansKR-SemiBold.ttf") format("truetype");
  font-style: normal;
  font-weight: 600;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans KR";
  src: url("fonts/IBMPlexSansKR-Bold.ttf") format("truetype");
  font-style: normal;
  font-weight: 700;
  font-display: swap;
}

/* ------------------------------------------------------------- 테마
 *
 * 세 가지다 — 시스템(auto) / 라이트 / 다크. 어느 것인지는 서버가 쿠키를 보고
 * <html data-theme="…"> 로 찍어 준다((blog theme) 참조). 자바스크립트가 없어서
 * (CSP 가 script-src 를 열지 않는다) 여기 CSS 가 그 속성 하나로 갈라진다.
 *
 * 기본은 라이트다. 다크 팔레트는 두 자리에서 켜진다 —
 *   1. 방문자가 다크를 골랐을 때 (data-theme="dark")
 *   2. 아무것도 고르지 않았는데 OS 가 어두울 때 (auto + prefers-color-scheme)
 * 두 번째 선택자는 "light 도 dark 도 아닌 것" 으로 적었다. auto 뿐 아니라
 * data-theme 이 아예 없는 문서(예전에 캐시된 HTML)도 함께 잡으려는 것이다.
 *
 * 색은 전부 여기 변수로 모은다. 무지개 괄호와 오류 빨강까지 포함해서 —
 * 그래야 팔레트를 두 번 적는 자리가 이 블록 하나로 끝난다. */

:root {
  --radius: 10px;
  --mono: "IBM Plex Mono", "IBM Plex Sans KR", monospace;
  --sans: "IBM Plex Sans", "IBM Plex Sans KR", sans-serif;

  /* 라이트 */
  color-scheme: light;
  --bg: #fbfbf9;
  --surface: #ffffff;
  --border: #e6e3dc;
  --text: #23211e;
  --muted: #7b756c;
  --accent: #9a3412;
  --accent-soft: #fdf2ec;
  --code-bg: #f4f2ee;
  --err: #dc2626;
  --rp-0: #b45309;
  --rp-1: #7c3aed;
  --rp-2: #0f766e;
  --rp-3: #be185d;
  --rp-4: #1d4ed8;
  --rp-5: #15803d;
}

/* 다크 — 골라서 켠 경우 */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #16151a;
  --surface: #1e1d23;
  --border: #302e38;
  --text: #e8e6e3;
  --muted: #9c968d;
  --accent: #f0906a;
  --accent-soft: #2a1f1b;
  --code-bg: #26242c;
  --err: #f87171;
  --rp-0: #fbbf24;
  --rp-1: #c4b5fd;
  --rp-2: #5eead4;
  --rp-3: #f9a8d4;
  --rp-4: #93c5fd;
  --rp-5: #86efac;
}

/* 다크 — 고른 것이 없어 OS 를 따르는 경우 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    color-scheme: dark;
    --bg: #16151a;
    --surface: #1e1d23;
    --border: #302e38;
    --text: #e8e6e3;
    --muted: #9c968d;
    --accent: #f0906a;
    --accent-soft: #2a1f1b;
    --code-bg: #26242c;
    --err: #f87171;
    --rp-0: #fbbf24;
    --rp-1: #c4b5fd;
    --rp-2: #5eead4;
    --rp-3: #f9a8d4;
    --rp-4: #93c5fd;
    --rp-5: #86efac;
  }
}

* { box-sizing: border-box; }

code, pre, kbd, samp { font-family: var(--mono); }

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

/* 화면 너비를 활용하되 작은 화면에서도 가장자리 여백은 유지한다. */
.wrap {
  width: 100%;
  min-width: 0;
  padding-inline: clamp(1rem, 3vw, 3rem);
  margin: 0 auto;
  overflow-wrap: anywhere;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ------------------------------------------------------------- 헤더 */

header.site {
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  padding: 2.2rem 0 1.2rem;
}

.brand {
  display: inline-block;
  font-size: 1.7rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}
.brand:hover { text-decoration: none; color: var(--accent); }

.tagline { margin: 0.2rem 0 1.1rem; color: var(--muted); font-size: 0.9rem; }

header.site nav { display: flex; flex-wrap: wrap; gap: 1.1rem; align-items: center; }
header.site nav a { color: var(--muted); font-size: 0.92rem; }
header.site nav a:hover { color: var(--accent); }

/* 지금 로그인한 사람. 메뉴에 섞여 있지만 누를 수 있는 것이 아니므로
 * 링크와 같은 색을 주지 않는다 — 눌러 보고 아무 일도 없는 편보다 낫다. */
.who { color: var(--text); font-size: 0.92rem; font-weight: 600; }
.who:hover { color: var(--accent); }
.who::before { content: "λ "; color: var(--muted); font-weight: 400; }

form.inline { display: inline; margin: 0; }
button.linkish {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--muted); font: inherit; font-size: 0.92rem;
}
button.linkish:hover { color: var(--accent); text-decoration: underline; }

/* 테마 토글. 메뉴의 마지막 자리에 붙지만 이동이 아니라 설정이라, 테두리를
 * 둘러 링크와 구분한다. 글자는 지금 켜진 테마다 — 다음에 무엇이 되는지는
 * 버튼의 title/aria-label 에 말로 적혀 있다. */
/* nav 는 flex 라 auto 여백이 남은 자리를 전부 먹는다 — 언어·테마 토글을
 * 오른쪽 끝으로 민다. 둘을 나란히 두려고 auto 는 앞선 언어 폼에만 준다
 * (테마 폼에도 주면 둘 사이가 벌어진다). 줄이 접히면(모바일) 남는 자리가
 * 없어 저절로 다음 줄 왼쪽에 선다. */
form.lang-form { margin-left: auto; }
button.theme-toggle, button.lang-toggle {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.15rem 0.65rem;
  border: 1px solid var(--border); border-radius: 999px;
  font-size: 0.82rem; line-height: 1.6;
}
button.theme-toggle:hover, button.lang-toggle:hover { border-color: var(--accent); text-decoration: none; }
button.theme-toggle .glyph { font-size: 0.95em; }

form.search { display: flex; gap: 0.5rem; margin-top: 1rem; align-items: center; }
form.search .prompt { font-size: 0.95rem; }
form.search input {
  min-width: 0;
  flex: 1; padding: 0.5rem 0.75rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--bg); color: var(--text); font: inherit;
  font-size: 0.9rem; font-family: var(--mono);
}
form.search button {
  padding: 0.5rem 0.95rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); color: var(--muted); cursor: pointer; font: inherit; font-size: 0.9rem;
}
form.search button:hover { border-color: var(--accent); color: var(--accent); }

/* ------------------------------------------------------------- 본문 */

/* 짧은 페이지의 남는 높이를 채우고 긴 페이지에서는 자연스럽게 늘어난다. */
main.wrap { flex: 1 0 auto; padding-block: 2.5rem 4rem; }

.page-title { font-size: 1.35rem; margin: 0 0 1.5rem; letter-spacing: -0.01em; }

/* 목록 카드는 어디를 눌러도 그 글로 간다.
 *
 * 카드를 통째로 <a> 로 감쌀 수는 없다 — 안에 태그 링크가 있어서 링크 중첩이
 * 되고, 그건 유효하지 않은 HTML 이라 브라우저가 제멋대로 쪼갠다. 요약문에
 * 링크를 하나 더 다는 방법도 쓰지 않는다. 같은 목적지가 카드마다 두 개가 되어
 * 스크린리더가 같은 글을 두 번 읽고 탭 정지점도 두 배가 된다 (흔한 처방인
 * aria-hidden 은 여기서 못 쓴다 — 요약문 자체가 읽어야 할 내용이다).
 *
 * 그래서 제목 링크의 가상 요소를 카드 전체로 늘린다. DOM 의 링크는 여전히
 * 하나뿐이라 탭 정지점도 하나고 요약문은 평문으로 남지만, 마우스로는 여백까지
 * 포함해 카드 어디를 눌러도 눌린다. 자바스크립트가 필요 없어서 CSP 도 그대로다.
 *
 * 대가: 덮개가 마우스 이벤트를 가로채므로 카드 안의 글자를 드래그로 선택할 수
 * 없다. 목록에서 요약문을 복사하는 일은 드물어서 감수한다.
 */
.card {
  position: relative;
  border-bottom: 1px solid var(--border);
  padding-bottom: 1.6rem;
  margin-bottom: 1.6rem;
}
.card:last-of-type { border-bottom: 0; }
.card h2 { font-size: 1.25rem; margin: 0 0 0.3rem; letter-spacing: -0.01em; }
.card h2 a { color: var(--text); }
.card h2 a:hover { color: var(--accent); text-decoration: none; }

/* 제목 링크를 카드 전체로 늘리는 덮개. 카드가 position: relative 라 그 기준으로
 * 잡힌다. 아래쪽은 카드 사이 경계선 앞에서 끊어 이웃 카드와 헷갈리지 않게 한다. */
.card h2 a::after { content: ""; position: absolute; inset: 0 0 1.6rem 0; }

/* 태그는 덮개 위로 올려 자기 링크를 지킨다 — 안 그러면 덮개에 가려
 * 태그를 눌러도 글로 가버린다. */
.card ul.tags { position: relative; z-index: 1; }

/* 이제 카드 어디에 올려도 눌린다는 것을 제목 색으로 알린다. */
.card:hover h2 a { color: var(--accent); }

.meta { color: var(--muted); font-size: 0.83rem; margin: 0 0 0.6rem; }
.excerpt { margin: 0 0 0.7rem; color: var(--muted); }
.draft { color: var(--accent); font-weight: 600; }
.empty { color: var(--muted); font-style: italic; }
.error { color: var(--err); }
.hint { color: var(--muted); font-size: 0.85rem; }

ul.tags { list-style: none; display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0; margin: 0.5rem 0; }
ul.tags a {
  display: inline-block; font-size: 0.78rem; padding: 0.15rem 0.6rem;
  background: var(--accent-soft); border-radius: 999px; color: var(--accent);
}
ul.tags a:hover { text-decoration: none; filter: brightness(0.95); }

ul.tagcloud { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.6rem; }
ul.tagcloud a {
  display: inline-flex; gap: 0.45rem; align-items: baseline;
  padding: 0.35rem 0.85rem; border: 1px solid var(--border); border-radius: 999px;
}
ul.tagcloud a span { color: var(--muted); font-size: 0.78rem; }

.pager { display: flex; justify-content: space-between; align-items: center; margin-top: 2.5rem; }
.pager .pageno { color: var(--muted); font-size: 0.85rem; }

/* --------------------------------------------------------- 글 본문 */

/* 제목 위에 놓여 본문을 밀지 않도록 여백을 작게 잡는다. */
.back { margin: 0 0 1.4rem; font-size: 0.88rem; }
.back a { color: var(--muted); }
.back a:hover { color: var(--accent); text-decoration: none; }

.post h1 { font-size: 1.85rem; line-height: 1.35; margin: 0 0 0.4rem; letter-spacing: -0.02em; }
.content { margin-top: 1.8rem; }
.content h2 { font-size: 1.3rem; margin: 2.2rem 0 0.8rem; letter-spacing: -0.01em; }
.content h3 { font-size: 1.1rem; margin: 1.8rem 0 0.6rem; }
.content p { margin: 0 0 1.15rem; }
.content ul, .content ol { margin: 0 0 1.15rem; padding-left: 1.4rem; }
.content li { margin-bottom: 0.35rem; }
.content img { max-width: 100%; border-radius: var(--radius); }
.content hr { border: 0; border-top: 1px solid var(--border); margin: 2.2rem 0; }

.content blockquote {
  margin: 0 0 1.15rem; padding: 0.1rem 1.1rem;
  border-left: 3px solid var(--accent); color: var(--muted);
}
.content blockquote p { margin: 0.8rem 0; }

.content code {
  font-family: var(--mono); font-size: 0.87em;
  background: var(--code-bg); padding: 0.12em 0.4em; border-radius: 5px;
}
.content pre {
  background: var(--code-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1rem 1.1rem; overflow-x: auto; margin: 0 0 1.3rem; line-height: 1.6;
}
.content pre code { background: none; padding: 0; font-size: 0.85rem; }

.owner-actions { margin-top: 2rem; font-size: 0.88rem; }

/* ----------------------------------------------------------- 댓글 */

.comments { margin-top: 3.5rem; border-top: 1px solid var(--border); padding-top: 2rem; }
.comments h3 { font-size: 1.05rem; margin: 0 0 1.2rem; }
.comment {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 0.9rem 1.1rem; margin-bottom: 0.8rem;
}
.comment p:last-child { margin: 0; white-space: pre-wrap; }

/* ------------------------------------------------------------- 폼 */

form.comment-form, form.editor, form.auth {
  display: flex; flex-direction: column; gap: 0.9rem; margin-top: 1.5rem;
}
form label { display: flex; flex-direction: column; gap: 0.35rem; font-size: 0.88rem; color: var(--muted); }
form label small { font-weight: 400; }
form label.check { flex-direction: row; align-items: center; gap: 0.5rem; }

input[type="text"], input[type="password"], input[type="search"], textarea {
  padding: 0.6rem 0.8rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text); font: inherit; font-size: 0.95rem;
}
textarea { font-family: var(--mono); font-size: 0.88rem; line-height: 1.65; resize: vertical; }
input:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent; }

button, .button {
  align-self: flex-start; padding: 0.55rem 1.2rem; border: 0; border-radius: var(--radius);
  background: var(--accent); color: #fff; font: inherit; font-size: 0.9rem;
  font-weight: 600; cursor: pointer;
}
button:hover, .button:hover { filter: brightness(1.08); text-decoration: none; }
button.danger { background: none; color: var(--err); padding: 0 0 0 0.7rem; font-weight: 400; font-size: 0.85rem; }
button.danger:hover { text-decoration: underline; filter: none; }

form.editor .actions { display: flex; align-items: center; gap: 1.2rem; }
form.editor .actions a { color: var(--muted); font-size: 0.88rem; }

/* ----------------------------------------------------------- 관리 */

table.admin { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
table.admin th {
  text-align: left; color: var(--muted); font-weight: 500; font-size: 0.8rem;
  border-bottom: 1px solid var(--border); padding: 0.5rem 0.4rem;
}
table.admin td { border-bottom: 1px solid var(--border); padding: 0.7rem 0.4rem; vertical-align: middle; }
table.admin td:nth-child(2), table.admin td:nth-child(3) { color: var(--muted); white-space: nowrap; }
.row-actions { text-align: right; white-space: nowrap; font-size: 0.85rem; }

/* ----------------------------------------------------- 계정 설정 */

.account-section {
  border-top: 1px solid var(--border);
  margin-top: 2rem; padding-top: 1.6rem;
}
.account-section h2 { font-size: 1.05rem; margin: 0 0 0.9rem; }
.account-section.danger h2 { color: var(--err); }

.account-info {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.45rem 1.2rem; margin: 0 0 0.9rem; font-size: 0.92rem;
}
.account-info dt { color: var(--muted); }
.account-info dd { margin: 0; color: var(--text); }

.account-field-label { color: var(--muted); font-size: 0.88rem; margin: 0 0 0.6rem; }
/* 테마·본문 형식 선택 — 알약 한 줄. 계정 설정에서는 버튼(누르면 곧 저장),
 * 글쓰기 폼에서는 라디오에 입힌 span(저장할 때 함께 넘어간다). 모양은 하나다. */
.theme-choices, .format-choices { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 0.6rem; }
fieldset.format-choices { border: 0; padding: 0; margin: 0 0 0.6rem; min-width: 0; }
fieldset.format-choices legend { color: var(--muted); font-size: 0.88rem; margin-bottom: 0.35rem; padding: 0; }
.account-section .hint + .account-field-label { margin-top: 1.5rem; }
button.theme-choice, .format-choice {
  align-self: auto; display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.45rem 0.9rem; border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--muted); font-weight: 400; font-size: 0.88rem;
  cursor: pointer;
}
button.theme-choice:hover, .format-choice:hover { border-color: var(--accent); color: var(--accent); filter: none; }
button.theme-choice.current, button.format-choice.current, input:checked + .format-choice {
  border-color: var(--accent); color: var(--accent); background: var(--accent-soft);
}
/* 라디오 자체는 숨기고 알약이 그 자리를 대신한다 — 키보드 포커스는 알약에 그린다. */
form label.format-option { position: relative; flex-direction: row; gap: 0; }
.format-option input {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.format-option input:focus-visible + .format-choice { outline: 2px solid var(--accent); outline-offset: 2px; }

.notice { color: var(--rp-5); font-size: 0.9rem; }

/* --------------------------------------------------------- 푸터 */

footer.site {
  flex-shrink: 0;
  border-top: 1px solid var(--border); background: var(--surface);
  padding: 1.6rem 0; color: var(--muted); font-size: 0.83rem;
}
footer.site p { margin: 0; }
footer.site .footer-links { margin-top: 0.5rem; }
footer.site .footer-links a { color: var(--muted); }
footer.site .footer-links a:hover { color: var(--accent); }

/* --------------------------------------------------- REPL 표면 */

/* λ> 프롬프트 — 검색창과 REPL 출력에 함께 쓴다. */
.prompt { font-family: var(--mono); color: var(--accent); font-weight: 600; }

/* 현재 위치를 나타내는 S-expression 브레드크럼 — (blog (tag "scheme")) */
.crumb {
  font-family: var(--mono); font-size: 0.8rem; color: var(--muted);
  margin: 0 0 1.2rem;
}
.crumb a { color: var(--muted); }
.crumb a:hover { color: var(--accent); text-decoration: none; }

/* REPL 세션 출력 — 질의 에코, 오류(Exception), /stats, 404 */
pre.repl {
  font-family: var(--mono); font-size: 0.88rem; line-height: 1.7;
  background: var(--code-bg); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1rem 1.1rem; margin: 0 0 1.2rem;
  overflow-x: auto; white-space: pre-wrap; word-break: break-word;
}
pre.repl .err { color: var(--err); }

/* 글 하단의 저장 원본(.sexp) 링크 — 주석 문장처럼 그린다 */

/* 본문 목록의 불릿을 λ 로 */
.content ul li::marker { content: "λ "; color: var(--accent); }

/* scheme 코드블록의 실행 폼 — 블록 바로 아래 오른쪽에 붙는다 */
form.run { margin: -0.9rem 0 1.3rem; display: flex; justify-content: flex-end; }
form.run button {
  background: none; border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--muted); font-family: var(--mono); font-size: 0.78rem;
  padding: 0.25rem 0.7rem; font-weight: 400; align-self: auto;
}
form.run button:hover { border-color: var(--accent); color: var(--accent); filter: none; }

/* 샌드박스 어휘 밖 블록의 안내 — 버튼 자리에 주석 낯으로 붙는다 */
p.no-run {
  margin: -0.9rem 0 1.3rem; text-align: right;
  font-family: var(--mono); font-size: 0.78rem; color: var(--muted);
}

/* 실행 결과의 값 표시 */
pre.repl .result { color: var(--accent); font-weight: 600; }

/* --------------------------------------------------- 낱말 통계 (/words) */

.word-summary { font-family: var(--mono); font-size: 0.88rem; color: var(--muted); }

/* 순위-빈도 차트 — 인라인 SVG 라 여기 변수 색을 그대로 물려받는다.
 * 테마가 바뀌면 차트도 함께 바뀐다. */
.zipf { margin: 1.2rem 0 1.6rem; }
.zipf svg {
  display: block; width: 100%; height: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.zipf .grid line { stroke: var(--border); stroke-width: 1; }
.zipf .grid text, .zipf .axis {
  fill: var(--muted); font-family: var(--mono); font-size: 11px;
}
.zipf .frame { fill: none; stroke: var(--border); }
.zipf polyline { fill: none; stroke: var(--accent); stroke-width: 1.5; }
.zipf circle { fill: var(--accent); }
.zipf figcaption { margin-top: 0.5rem; font-family: var(--mono); }

/* 상위 낱말 가로 막대 목록 */
ol.freq {
  list-style: none; margin: 0 0 1.2rem; padding: 0;
  display: grid; row-gap: 0.35rem;
}
ol.freq li {
  display: grid; grid-template-columns: 9rem 1fr 3.2rem;
  align-items: center; column-gap: 0.8rem; font-size: 0.9rem;
}
.freq-word { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 막대는 인라인 SVG 다 — CSP(style-src 'self')가 인라인 style 을 막아서
 * 길이를 rect 의 width 속성으로 싣는다. (blog adapter presenter view words) 참조. */
.freq-bar { display: block; width: 100%; height: 0.6rem; background: var(--code-bg); border-radius: 3px; }
.freq-bar rect { fill: var(--accent); opacity: 0.75; }
.freq-count { text-align: right; font-family: var(--mono); font-size: 0.8rem; color: var(--muted); }

/* --------------------------------------------------- 글-글 그래프 (/graph) */

/* /words 의 차트와 같은 규칙 — 인라인 SVG 가 변수 색을 물려받아 테마를 따른다.
 * 굵기·크기는 뷰가 SVG 속성으로 싣는다 (CSP 가 인라인 style 을 막는다). */
.post-graph { margin: 1.2rem 0 1.6rem; }
.post-graph svg {
  display: block; width: 100%; height: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.post-graph .edges line { stroke: var(--accent); opacity: 0.4; }
.post-graph .edges line:hover { opacity: 1; }
.post-graph .nodes circle { fill: var(--accent); }
.post-graph .nodes a.lone circle { fill: var(--muted); opacity: 0.6; }

/* 커뮤니티 색 — label propagation 이 찾은 주제 덩어리마다 하나씩.
 * 코드블록 무지개 괄호와 같은 팔레트라 라이트/다크 모두에서 읽힌다.
 * 일곱째 커뮤니티부터는 색이 돌아 겹친다 (뷰가 mod 6 으로 접는다). */
.post-graph .nodes a.comm-0 circle { fill: var(--rp-0); }
.post-graph .nodes a.comm-1 circle { fill: var(--rp-1); }
.post-graph .nodes a.comm-2 circle { fill: var(--rp-2); }
.post-graph .nodes a.comm-3 circle { fill: var(--rp-3); }
.post-graph .nodes a.comm-4 circle { fill: var(--rp-4); }
.post-graph .nodes a.comm-5 circle { fill: var(--rp-5); }
/* 제목 글자 뒤에 바탕색 테를 둘러 간선 위에서도 읽히게 한다. */
.post-graph .nodes text {
  fill: var(--muted); font-family: var(--mono); font-size: 11px;
  paint-order: stroke; stroke: var(--surface); stroke-width: 3px; stroke-linejoin: round;
}
.post-graph .nodes a:hover circle { stroke: var(--text); stroke-width: 1.5; }
.post-graph .nodes a:hover text { fill: var(--accent); }
.post-graph figcaption { margin-top: 0.5rem; font-family: var(--mono); }

/* 두 그래프 화면(글끼리 / 낱말과 함께)을 오가는 링크 — REPL 낯의 한 줄 */
.graph-switch { font-family: var(--mono); font-size: 0.8rem; margin: -0.8rem 0 1.2rem; }
.graph-switch a { color: var(--muted); }
.graph-switch a:hover { color: var(--accent); }

/* 이분 그래프의 낱말 알약 — 글 점과 낯이 달라야 두 층이 한눈에 갈린다.
 * 알약 글자는 제목 글자의 흰 테(halo)를 물려받으면 얼룩지므로 끈다. */
.post-graph .nodes a.word rect { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1; }
.post-graph .nodes a.word text { fill: var(--accent); stroke: none; }
.post-graph .nodes a.word:hover rect { stroke-width: 2; }

/* ------------------------------------- Scheme 코드블록 무지개 괄호 */
/* 깊이는 (blog markdown) 이 서버에서 센다 — 여기는 색만 입힌다.
 * 밝기가 다른 두 팔레트는 맨 위 테마 블록에 있다. */

.rp-0 { color: var(--rp-0); }
.rp-1 { color: var(--rp-1); }
.rp-2 { color: var(--rp-2); }
.rp-3 { color: var(--rp-3); }
.rp-4 { color: var(--rp-4); }
.rp-5 { color: var(--rp-5); }

/* Body markup editor: matching metrics keep the native caret and color layer aligned. */
.body-editor { position: relative; min-width: 0; background: var(--surface); border-radius: var(--radius); }
.body-editor textarea, .body-editor .body-highlight {
  font-family: var(--mono); font-size: 0.88rem; line-height: 1.65;
  font-weight: 400; font-style: normal; letter-spacing: normal;
  tab-size: 4; white-space: pre-wrap; overflow-wrap: break-word; word-break: normal;
  padding: 0.6rem 0.8rem; margin: 0; text-align: left;
}
.body-editor textarea { display: block; position: relative; width: 100%; min-height: 12rem; }
.body-editor .body-highlight {
  display: none; position: absolute; top: 1px; left: 1px; border: 0;
  border-radius: var(--radius); overflow: hidden; pointer-events: none; color: var(--text);
}
.body-editor.highlight-ready .body-highlight { display: block; }
.body-editor.highlight-ready textarea { color: transparent; caret-color: var(--text); background: transparent; }
.body-editor.highlight-ready textarea::selection { background: var(--accent-soft); color: var(--text); }
/* Org headings deeper than six repeat the same six-color palette. */
.body-highlight .syntax-heading-1 { color: var(--rp-0); }
.body-highlight .syntax-heading-2 { color: var(--rp-1); }
.body-highlight .syntax-heading-3 { color: var(--rp-2); }
.body-highlight .syntax-heading-4 { color: var(--rp-3); }
.body-highlight .syntax-heading-5 { color: var(--rp-4); }
.body-highlight .syntax-heading-6 { color: var(--rp-5); }
.body-highlight .syntax-marker { color: var(--rp-1); }
.body-highlight .syntax-emphasis { color: var(--rp-3); }
.body-highlight .syntax-link { color: var(--rp-4); }
.body-highlight .syntax-code { color: var(--rp-2); }
.body-highlight .syntax-quote { color: var(--rp-5); }
.body-highlight .syntax-comment { color: var(--muted); }
@media (forced-colors: active) {
  .body-editor.highlight-ready textarea { color: CanvasText; caret-color: CanvasText; }
  .body-editor.highlight-ready .body-highlight { visibility: hidden; }
}
