/* =====================================================================
 * 「침묵」 — 05-design-system.md §7 의 토큰과 그 위에 서는 컴포넌트 규칙.
 *
 * 정본은 `documents/poc/theme-pair.html` L1444-1541 이다. 05 §7 의 표에는
 * 28개만 실려 있어 6개(--q-sans --q-mono --q-scheme --q-ad-bg --q-btn-bg
 * --q-code-rule)가 빠져 있다. 표를 보고 옮기면 광고 슬롯·GitHub 버튼·
 * 코드블록 헤드 하단선이 색을 못 찾는다.
 *
 * ## 이 파일의 불변식 두 개 — QuietCssContractTest 가 지킨다
 *
 * 1. **색 리터럴은 아래 토큰 블록 세 개 안에만 있다.** 컴포넌트 규칙은
 *    토큰만 참조한다. 한 곳이라도 리터럴이 새면 다크가 그 자리에서 무너진다.
 * 2. **다크 토큰 두 블록의 선언 집합이 같다.** 「침묵」은 원래
 *    prefers-color-scheme 을 안 쓰지만 F-V5 가 "쿠키 없으면 시스템"을
 *    요구해서 두 경로가 다 필요해졌다. 05 §5.2 가 바로 이 복제를 결함으로
 *    지목했다 — "한 곳만 고치면 OS 다크와 수동 다크가 조용히 갈라진다".
 *    그래서 사람의 기억이 아니라 테스트가 두 블록을 맞춘다.
 *
 * ## 스코프
 *
 * `data-theme` 는 `<html>` 에, `.v-quiet` 는 `<body>` 에 붙는다.
 * 서버가 쿠키를 읽어 첫 페인트부터 맞는 테마로 그리고(F-V5), 쿠키가
 * 없거나 `system` 이면 속성을 아예 붙이지 않아 아래 @media 폴백이 산다.
 * ===================================================================== */

/* --- TOKENS: LIGHT ------------------------------------------------ */
.v-quiet,
[data-theme="light"] .v-quiet {
  /* 🔴 웹폰트 선언은 `fonts.css` 에 있다 (#45). 여기는 **스택만** 적는다.
     스택 맨 앞이 웹폰트, 그 뒤가 폴백이다 — 파일이 못 오면 예전 모습으로 돌아간다.
     `Pretendard Variable` 이 우리가 내는 것이고, 그냥 `Pretendard` 는
     사용자 기기에 설치돼 있는 경우를 받는 자리다. */
  --q-sans: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;
  --q-mono: "IBM Plex Mono", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  /* 렌더링 힌트도 테마 토큰이다 */
  --q-scheme: light;
  --q-smooth: antialiased;
  --q-img-filter: none;

  /* 표면 — 라이트에서 코드 면은 지면보다 한 칸 어둡다(눌린 면) */
  --q-bg: #ffffff;
  --q-code-bg: #f7f7f7;
  --q-code-in: #f1f1f1;
  --q-ad-bg: #fcfcfc;
  --q-btn-bg: #ffffff;

  /* 잉크 계단 */
  --q-ink: #121212;
  --q-ink-dim: #555555;
  --q-mid: #737373;
  --q-soft: #a6a6a6;
  --q-faint: #c6c6c6;
  --q-ghost: #d4d4d4;

  /* 괘선 */
  --q-rule: #ededed;
  --q-rule-strong: #e2e2e2;
  --q-code-edge: #ededed;
  --q-code-rule: #e9e9e9;

  /* 선으로 쓰는 잉크 — 링크는 색이 아니라 밑줄 알파로 구분한다 */
  --q-line-0: rgba(18, 18, 18, 0);
  --q-line-1: rgba(18, 18, 18, 0.14);
  --q-line-2: rgba(18, 18, 18, 0.42);
  --q-link-line: rgba(18, 18, 18, 0.26);
  --q-link-line-on: rgba(18, 18, 18, 0.9);
  --q-sel: rgba(18, 18, 18, 0.12);

  /* 구문 강조 — 전부 --q-code-bg 대비 AA(4.5:1) 이상 */
  --q-kw: #8a2c72;
  --q-str: #2c6a4a;
  --q-com: #5c6672;
  --q-num: #9a4a1c;
  --q-fn: #2c579f;
  --q-type: #1c6567;
  --q-ann: #7a5520;
}

/* --- TOKENS: DARK (수동 선택) -------------------------------------
 * 반전이 아니라 다시 계산한 값이다.
 *   · 코드 면은 지면보다 "밝게" 뜬다 — 라이트에서는 눌렸다. 방향이 뒤집힌다
 *   · 회색 계단은 어두운 쪽을 들어 올렸다 (mid 1.08배 soft 1.25배 faint 1.45배)
 *   · 괘선은 라이트 대비 약 2배로 올려야 같은 두께로 보인다
 *   · --q-ink 는 순백이 아니다. 7,000자를 견디려면 광량을 깎아야 한다
 * ------------------------------------------------------------------ */
[data-theme="dark"] .v-quiet {
  --q-scheme: dark;
  --q-smooth: auto;
  --q-img-filter: brightness(0.86) contrast(1.02);

  --q-bg: #0d0e10;
  --q-code-bg: #16181b;
  --q-code-in: #242628;
  --q-ad-bg: #101214;
  --q-btn-bg: #191b1e;

  --q-ink: #e8e8e7;
  --q-ink-dim: #b3b4b6;
  --q-mid: #8d9095;
  --q-soft: #66686e;
  --q-faint: #4b4d52;
  --q-ghost: #414246;

  --q-rule: #2a2c30;
  --q-rule-strong: #38393d;
  --q-code-edge: #26292e;
  --q-code-rule: #232629;

  --q-line-0: rgba(232, 232, 231, 0);
  --q-line-1: rgba(232, 232, 231, 0.2);
  --q-line-2: rgba(232, 232, 231, 0.52);
  --q-link-line: rgba(232, 232, 231, 0.34);
  --q-link-line-on: rgba(232, 232, 231, 0.92);
  --q-sel: rgba(232, 232, 231, 0.22);

  --q-kw: #d093c0;
  --q-str: #52a57e;
  --q-com: #8996a5;
  --q-num: #c0865a;
  --q-fn: #839ecf;
  --q-type: #53a6a9;
  --q-ann: #b5935a;
}

/* --- TOKENS: DARK (OS 설정, 쿠키가 없을 때) ------------------------
 * 🔴 위 블록과 **선언 집합이 같아야 한다.** QuietCssContractTest 가 두
 *    블록의 이름·값을 대조한다. 한쪽만 고치면 시스템 다크와 수동 다크가
 *    갈린다 — 214편을 운영하는 동안 반드시 일어난다(05 §5.2).
 * ------------------------------------------------------------------ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .v-quiet {
    --q-scheme: dark;
    --q-smooth: auto;
    --q-img-filter: brightness(0.86) contrast(1.02);

    --q-bg: #0d0e10;
    --q-code-bg: #16181b;
    --q-code-in: #242628;
    --q-ad-bg: #101214;
    --q-btn-bg: #191b1e;

    --q-ink: #e8e8e7;
    --q-ink-dim: #b3b4b6;
    --q-mid: #8d9095;
    --q-soft: #66686e;
    --q-faint: #4b4d52;
    --q-ghost: #414246;

    --q-rule: #2a2c30;
    --q-rule-strong: #38393d;
    --q-code-edge: #26292e;
    --q-code-rule: #232629;

    --q-line-0: rgba(232, 232, 231, 0);
    --q-line-1: rgba(232, 232, 231, 0.2);
    --q-line-2: rgba(232, 232, 231, 0.52);
    --q-link-line: rgba(232, 232, 231, 0.34);
    --q-link-line-on: rgba(232, 232, 231, 0.92);
    --q-sel: rgba(232, 232, 231, 0.22);

    --q-kw: #d093c0;
    --q-str: #52a57e;
    --q-com: #8996a5;
    --q-num: #c0865a;
    --q-fn: #839ecf;
    --q-type: #53a6a9;
    --q-ann: #b5935a;
  }
}

/* =====================================================================
 * 여기부터 아래로 색 리터럴이 없다. 컴포넌트는 토큰만 참조한다.
 * ===================================================================== */

/* --- 루트 --------------------------------------------------------- */
/* `html` 에 배경을 주지 않는다. 루트에 배경이 없으면 브라우저가 body 의 배경을
   캔버스로 올려 쓰므로 오버스크롤 영역까지 테마색이 따라온다 — 여기에 리터럴
   폴백을 하나 두는 순간 다크에서 그 영역만 흰색으로 남는다. */
.v-quiet {
  margin: 0;
  color-scheme: var(--q-scheme);
  background: var(--q-bg);
  color: var(--q-ink);
  min-height: 100vh;
  font-family: var(--q-sans);
  font-size: 16px;
  line-height: 1;
  /* 한글 어절을 보존한다. 공통 규칙이라 루트에 둔다.
     🔴 `keep-all` 만 두면 줄 하나에 안 들어가는 영문 단어·URL·식별자가 상자를 뚫는다.
        실측(2026-08-06 · Chrome headless): 제목 `h1.p-title` 이 700px 상자 안에서
        내용 924px, 500px 폭에서는 문서 전체가 794px 로 가로 스크롤이 생겼다.
        `overflow-wrap: break-word` 는 **줄에 못 들어가는 단어만** 끊으므로 한글
        어절 보존은 그대로 살아 있다. 상속되는 속성이라 루트 한 곳으로 끝난다.
        `anywhere` 를 쓰지 않는 이유는 05 §5 시안B 비평과 같다 — 영문 혼용 단어가
        들어갈 자리가 있는데도 임의 지점에서 끊긴다. */
  word-break: keep-all;
  overflow-wrap: break-word;
  -webkit-font-smoothing: var(--q-smooth);
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
  padding: 128px 40px 176px;
  box-sizing: border-box;
}
.v-quiet *,
.v-quiet *::before,
.v-quiet *::after { box-sizing: border-box; }

.v-quiet ::selection {
  background: var(--q-sel);
  color: var(--q-ink);
}

.v-quiet .q-inner {
  width: 1040px;
  max-width: 100%;
  margin: 0 auto;
}

.v-quiet a {
  color: inherit;
  text-decoration: none;
}
.v-quiet a:focus-visible {
  outline: none;
  box-shadow: 0 1px 0 var(--q-ink);
}

/* 스크린리더 전용. 라이트박스 안내문·건너뛰기 링크가 쓴다 */
.v-quiet .q-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 건너뛰기 링크 — 평소에는 `.q-sr` 로 숨어 있다가 **포커스를 받으면만** 나타난다.
   LNB 가 모든 화면 상시 노출(04 §3.2)이라 이것이 없으면 키보드 사용자가 화면마다
   분류 링크 27개를 지나야 본문에 닿는다. 「침묵」이므로 장식 없이 지면색 위 1px 테두리다. */
.v-quiet .q-skip:focus {
  position: fixed;
  top: 16px;
  left: 16px;
  z-index: 80;
  width: auto;
  height: auto;
  margin: 0;
  padding: 12px 16px;
  overflow: visible;
  clip-path: none;
  background: var(--q-bg);
  color: var(--q-ink);
  font-family: var(--q-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.14em;
  box-shadow: 0 0 0 1px var(--q-ink);
}

/* --- 3트랙 그리드 -------------------------------------------------
 * 🔴 `minmax(0, 1fr)` 이 필수다. 암시적 auto 트랙은 긴 코드 줄에 밀려
 *    페이지 전체를 늘린다(05 §9-6). 자식의 `min-width: 0` 도 짝이다.
 *
 * ## 🔴 `--q-cols` 는 **테마 토큰 블록 안에 두면 안 된다** (2026-08-31)
 *
 * 원래 라이트 토큰 블록 안에 있었다. 그 블록의 선택자가
 * `.v-quiet, [data-theme="light"] .v-quiet` 인데, 두 번째 것의 명시도가
 * (0,2,0) 이다. 미디어 쿼리는 명시도를 **안 올리므로**
 * `@media (max-width: 940px) { .v-quiet { --q-cols: ... } }` 는 (0,1,0) 이라
 * 진다.
 *
 * 결과: `<html data-theme="light">` 가 찍힌 페이지에서는 **두 브레이크포인트가
 * 통째로 죽었다.** 390px 실측 — 스탬프 없음/다크는 `--q-cols` 가
 * `minmax(0, 1fr)` 이고 제목 폭 342px 인데, 라이트 스탬프에서는
 * `116px 64px minmax(0, 1fr)` 이 남아 제목이 **116px** 로 눌렸다. 테마를
 * 라이트로 고정한 사람만 폰에서 페이지가 깨져 보였다는 뜻이다.
 *
 * 색이 아니라 **레이아웃** 값이므로 테마와 무관한 자리에 둔다. 그러면
 * 아래 미디어 쿼리들과 명시도가 같아져서 나중에 온 것이 이긴다.
 * 다크 블록에는 원래부터 없었다 — 그래서 다크만 멀쩡했다.
 *
 * 🔴 **쿠키가 없는 기본 상태도 멀쩡했다.** `data-theme` 속성이 아예 안 붙기
 *    때문이다. 그래서 헤드리스 재현이 몇 번이나 「재현 안 됨」으로 끝났다 —
 *    `colorScheme: 'light'` 는 OS 선호일 뿐 속성을 찍지 않는다. 라이트를
 *    **보는** 것과 **고르는** 것이 다르다.
 * ------------------------------------------------------------------ */
.v-quiet { --q-cols: 116px 64px minmax(0, 1fr); }
.v-quiet .q-row {
  display: grid;
  grid-template-columns: var(--q-cols);
}
.v-quiet .q-main { grid-column: 3; min-width: 0; }

/* --- 헤더 — 구분선 없이 여백으로만 분리한다 -----------------------
 *
 * ## ABOUT 은 워드마크 **오른쪽**에 붙는다 (2026-08-31 오너 지시)
 *
 * 한 번 왼쪽 기둥(1번 트랙)에 넣었다가 오른쪽으로 옮겼다. 왼쪽에 두면 아래
 * `분류`·`최근`·날짜와 같은 선에 서서 기둥이 페이지를 관통하는 이점이 있었지만,
 * 그만큼 워드마크에서 64px 떨어져 **따로 노는 한 칸**으로 읽혔다.
 *
 * 🔴 대신 왼쪽 기둥 116px 이 다시 빈다. 로고는 좌측 레일보다 180px 안쪽에서
 *    시작한다(실측 @1280: `.q-inner`·`.p-rail` 은 x=112.5, 워드마크는 292.5).
 *    헤더 띠 하나에 왼쪽 기준선이 둘이라는 것은 그대로 남아 있는 문제다 —
 *    풀려면 `.q-head` 를 `grid-column: 1 / -1` 로 펴서 로고를 지면 왼쪽 끝에
 *    붙여야 하는데, 그건 워드마크를 옮기는 일이라 지시 범위 밖이다.
 *
 * ## 바닥선이 하나다
 *
 * 예전에는 로고 155 · 테마 153 · 검색 152 로 셋이 달랐다. `.q-head` 가
 * `flex-start`, `.q-head-right` 가 `baseline` 이라 기준이 섞였고, 그 어긋남을
 * `.site-logo { margin-top: 1px }` 로 손보정하고 있었다. 기준을 **아래쪽 하나**로
 * 통일하면 손보정이 사라진다 — 검색창 글자 크기를 바꿔도 다시 안 틀어진다.
 * ------------------------------------------------------------------ */
.v-quiet .q-gnb {
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  /* 🔴 항목을 관리 화면에서 넣게 되면서(#88) 대소문자를 사람이 정하게 됐다.
     띠의 어휘는 10px 등폭 대문자 하나뿐이라, 소문자로 적힌 항목 하나가 줄 전체를
     다른 서체처럼 보이게 만든다. 한글 항목에는 아무 일도 안 한다 — 그게 맞다 */
  text-transform: uppercase;
  color: var(--q-faint);
  /* 🔴 `.q-search` 의 아래 패딩과 **같은 값**이라야 ABOUT 과 「검색」의 줄상자
     바닥이 같은 y 에 선다. 한쪽만 고치면 헤더 띠가 글자 한 줄로 안 읽힌다 */
  padding-bottom: 5px;
  white-space: nowrap;
  flex: 0 0 auto;
  /* 🔴 항목이 여럿이면 **가로로 선다** (#88).
   *
   *    예전에는 `a { display: block }` 하나로 끝났다. 항목이 ABOUT 하나뿐이라
   *    세로로 쌓이든 말든 결과가 같았기 때문이다. 둘이 되는 순간 18px 짜리 헤더 띠
   *    안에서 세로로 쌓여 헤더가 깨진다 — 데이터로 빼기 전에 이것부터 고쳐야 했다.
   *
   *    구분자(`·`)를 안 넣는다(오너 컨펌 2026-09-10). 「침묵」의 헤더는 선도 점도
   *    거의 없는 면이고, `letter-spacing: 0.2em` 이 이미 항목을 떼어 놓는다.
   */
  display: flex;
  gap: 18px;
}
.v-quiet .q-gnb a {
  display: block;
  transition: color 200ms ease;
}
.v-quiet .q-gnb a:hover { color: var(--q-ink); }

/* 🔴 `space-between` 이 아니다. 자식이 셋(로고 · ABOUT · 컨트롤)이라
   `space-between` 으로 두면 ABOUT 이 빈칸 한가운데로 밀려가 어디에도 안 붙는다.
   왼쪽부터 쌓고 컨트롤만 `margin-left: auto` 로 오른쪽 끝에 보낸다. */
.v-quiet .q-head {
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  /* 워드마크와 ABOUT 사이. 64(거터)는 왼쪽에 뒀을 때의 값이라 여기서는 너무 멀다 —
     붙어 보이되 워드마크를 밀지 않는 거리로 잡았다 */
  gap: 32px;
}
/* `.q-brand` 는 로고 파일이 오기 전의 글자 워드마크였다. #44 에서 로고로
   바뀌면서 참조가 0 이 됐다 — 남겨 두면 다음 사람이 둘 중 무엇이 산 것인지
   모른다. 되돌릴 일이 있으면 이 커밋을 보면 된다. */
/* --- 워드마크 (#44) ------------------------------------------------
 * 원본 512x97. 22px 로 두면 폭이 정확히 116px — 좌측 트랙과 같은 폭이다.
 * 3배 이상 축소해서 쓰므로 레티나에서도 가장자리가 살아 있다.
 *
 * 🔴 라이트/다크가 **다른 파일**이다. 슬래브 색이 그 테마의 지면색이라
 *    양쪽 모두 슬래브가 배경에 녹고 글자만 남는다. 한 장으로 쓰면 라이트에서
 *    검은 벽돌이 되거나 다크에서 흰 벽돌이 된다.
 *
 * 전환 규칙은 토큰과 **같은 3단**이다 — 기본(라이트) · `prefers-color-scheme`
 * · `data-theme`. 마지막이 이겨야 토글이 양방향으로 동작한다.
 * ------------------------------------------------------------------ */
.v-quiet .site-logo {
  height: 26px;
  width: 137px;
  display: block;
  /* 🔴 예전의 `margin-top: 1px` 은 기준이 섞인 것을 눈으로 맞춰 둔 값이었다.
     `.q-head` 가 `flex-end` 가 된 지금은 넣으면 오히려 1px 어긋난다 */
  background: url("/img/logo-light.png") no-repeat center / contain;
}
@media (prefers-color-scheme: dark) {
  .v-quiet .site-logo { background-image: url("/img/logo-dark.png"); }
}
:root[data-theme="dark"] .v-quiet .site-logo { background-image: url("/img/logo-dark.png"); }
:root[data-theme="light"] .v-quiet .site-logo { background-image: url("/img/logo-light.png"); }
.v-quiet .q-head-right {
  display: flex;
  align-items: flex-end;
  gap: 20px;
  margin-left: auto;
  /* 🔴 자리가 모자라면 이 묶음이 줄어든다 (#88). flex 자식의 기본 `min-width: auto`
     는 「자기 내용보다 작아지지 않는다」라, 이 한 줄이 없으면 검색칸 166px 이
     끝까지 버티고 헤더가 지면을 넘긴다. 자세한 실측은 `.q-search` 주석에 있다 */
  min-width: 0;
}

/* --- 검색 (F-Q2) --------------------------------------------------
 *
 * 예전에는 밑줄이 `--q-line-0`(알파 0)이라 **평상시에 아무 자국이 없었다.**
 * 「검색」이라는 `--q-faint` 글자 하나가 오른쪽 끝에 떠 있을 뿐이고, 그것이
 * 입력칸이라는 것을 알 방법이 없었다. hover 해 봐야 알 수 있는 컨트롤은
 * 조용한 것이 아니라 없는 것이다.
 *
 * 두 가지를 바꾼다. 새 토큰도 새 색도 만들지 않는다.
 *   · 밑줄을 평상시에도 그린다(`--q-line-1`). 1px 괘선은 이 시스템이 이미
 *     링크 밑줄에 쓰는 어휘라 들여오는 장식이 아니다.
 *   · 선의 **왼쪽 끝**에 돋보기를 둔다. 190px 짜리 선이 왜 거기 있는지를
 *     설명하는 것은 오른쪽 끝의 placeholder 가 아니라 이 표식이다.
 *
 * 🔴 밑줄이 `.q-search` 가 아니라 상자에 붙는다. input 에 두면 돋보기 밑에는
 *    선이 없어서 선이 두 동강 난 것처럼 보인다.
 * ------------------------------------------------------------------ */
.v-quiet .q-searchbox {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  /* 상자가 안 줄면 그 안의 입력칸도 못 준다 (#88) */
  min-width: 0;
  box-shadow: 0 1px 0 var(--q-line-1);
  transition: box-shadow 260ms ease;
}
.v-quiet .q-searchbox:hover,
.v-quiet .q-searchbox:focus-within { box-shadow: 0 1px 0 var(--q-line-2); }
.v-quiet .q-searchbox svg {
  display: block;
  flex: 0 0 auto;
  color: var(--q-faint);
  /* 돋보기의 시각 중심을 「검색」 글자에 맞춘다. 줄상자 바닥에 맞추면 떠 보인다 */
  margin-bottom: 4px;
  transition: color 200ms ease;
}
.v-quiet .q-searchbox:focus-within svg { color: var(--q-ink); }
/* 🔴 자리가 모자라면 **검색칸이 먼저 양보한다** (#88).
 *
 * GNB 를 관리 화면에서 편집하게 되면서 헤더 왼쪽 폭이 사람이 정하는 값이 됐다.
 * 오너가 항목을 셋(`ABOUT · PROJECTS · MORE`)으로 늘리자 721~800px 구간에서
 * 헤더가 지면을 넘겨 **가로 스크롤**이 생겼다 — WCAG 1.4.10 Reflow 위반이고,
 * 좁은 화면 서랍(≤720px)이 시작되기 직전 구간이라 아무도 안 보는 자리다.
 *
 * 🔴 브레이크포인트를 안 쓴다. `min-width: auto` 만 풀어 주면 flex 가 **모자랄 때만**
 *    줄인다 — 실측으로 850px 이상에서는 166px 그대로였고 그 아래에서만 양보했다.
 *    폭마다 값을 적어 두면 항목을 하나 더 넣는 날 그 표가 낡는다.
 *
 * 🔴 `min-width: 72px` 이 바닥이다. 「검색」 자리표시가 살아 있어야 그 칸이
 *    입력칸인 줄 안다 — 0 까지 줄면 돋보기만 남고, 그건 고장으로 보인다.
 *
 * 실측 (항목 3개 · `ABOUT PROJECTS MORE`)
 *
 * ```
 *          전               후
 *   850px  넘침 0 · 검색 166   넘침 0 · 검색 166   ← 아무것도 안 바뀐다
 *   800px  넘침 0 · 검색 166   넘침 0 · 검색 137
 *   760px  넘침 29 · 검색 166  넘침 0 · 검색  97
 *   721px  넘침 68 · 검색 166  넘침 0 · 검색  72
 * ```
 */
.v-quiet .q-search {
  /* 바닥값. 「검색」 자리표시가 남아야 입력칸인 줄 안다 (#88) */
  min-width: 72px;
  -webkit-appearance: none;
  appearance: none;
  width: 166px;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--q-sans);
  font-size: 13px;
  line-height: 18px;
  letter-spacing: -0.005em;
  color: var(--q-ink);
  caret-color: var(--q-ink);
  text-align: right;
  padding: 0 0 5px;
}
.v-quiet .q-search::placeholder {
  color: var(--q-faint);
  letter-spacing: 0.06em;
}
.v-quiet .q-search:focus::placeholder { color: transparent; }

/* --- 테마 토글 (F-V5) — 04 §3.3 "헤더에 두되 눈에 띄지 않게" -------
 *
 * ## 글자에서 그림으로 (2026-08-31)
 *
 * 예전에는 모노 3글자(`AUTO`/`LIGHT`/`DARK`)를 `--q-ghost` 로 깔아 뒀다.
 * 다크에서 #414246 을 #0d0e10 위에 얹은 것이라 대비가 **1.3:1** 이었고,
 * 보이더라도 그 세 글자가 눌리는 것인지 알 수 없었다. 라벨이 상태에 따라
 * 폭이 바뀌어서 오른쪽 덩어리가 미세하게 움직이는 문제도 있었다.
 *
 * 원 하나에 **채움만** 바꾼다 — 0% · 50% · 100%.
 *
 *   LIGHT  빈 원      밝게
 *   AUTO   반만 채움   시스템을 따른다
 *   DARK   꽉 찬 원    어둡게
 *
 * 해도 달도 그리지 않는다. 광선과 초승달은 이 시스템에 없는 어휘다. 셋이 같은
 * 원이라 눌러서 도는 동안 크기도 자리도 흔들리지 않는다.
 *
 * 🔴 세 모양이 **모두 DOM 에 있고** `data-state` 가 무엇을 보일지 정한다.
 *    누를 때마다 innerHTML 을 갈아 끼우면 노드가 매번 새로 만들어져서
 *    포커스 링과 전이가 끊긴다.
 *
 * 🔴 글자가 사라지므로 이름은 `aria-label` 이 진다. WCAG 2.5.3(Label in Name)은
 *    **보이는 글자가 있는** 컴포넌트에만 걸리는 조항이라 아이콘 전용 버튼은
 *    대상이 아니다. 대신 4.1.2 가 요구하는 이름이 반드시 있어야 한다.
 *
 * ## 남아 있는 것 — 1.4.11 Non-text Contrast (미해결, 오너 판단 대기)
 *
 * 쉬는 상태의 `--q-faint` 는 지면 대비가 **라이트 1.71:1 · 다크 2.28:1** 이다.
 * `--q-ghost` 였던 예전(1.48 / 1.92)보다는 올라왔지만 1.4.11 이 UI 컴포넌트에
 * 요구하는 3:1 에는 못 미친다. 아이콘이 곧 이 컨트롤의 유일한 표식이라 조항이
 * 걸리는 자리가 맞다.
 *
 *     토큰        라이트   다크
 *     --q-ghost   1.48    1.92    ← 예전
 *     --q-faint   1.71    2.28    ← 지금
 *     --q-soft    2.43    3.47      다크만 통과
 *     --q-mid     4.74    6.03      둘 다 통과
 *
 * 양쪽을 다 넘기는 것은 `--q-mid` 하나뿐인데, 그러면 이 아이콘이 워드마크 다음으로
 * 진한 것이 되어 04 §3.3 "헤더에 두되 눈에 띄지 않게" 와 정면으로 어긋난다.
 * 옆의 `분류`·`최근`·날짜가 전부 `--q-faint` 라 혼자 튀기도 한다.
 *
 * 🔴 그래서 여기서 조용히 정하지 않았다. 지금 값은 「침묵」 쪽을 택한 것이고,
 *    접근성 쪽을 택하려면 이 한 줄(`--q-faint` → `--q-mid`)만 바꾸면 된다.
 *    hover·focus 는 이미 `--q-ink` 라 그쪽은 어느 선택에서도 충분하다.
 * ------------------------------------------------------------------ */
.v-quiet .q-theme {
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: transparent;
  display: block;
  margin: 0;
  padding: 0 0 4px;
  cursor: pointer;
  color: var(--q-faint);
  transition: color 200ms ease;
}
.v-quiet .q-theme svg { display: block; }
.v-quiet .q-theme:hover,
.v-quiet .q-head:hover .q-theme { color: var(--q-ink); }
.v-quiet .q-theme:focus-visible {
  color: var(--q-ink);
  outline: 1px solid var(--q-soft);
  outline-offset: 3px;
}
/* 채움 세 단계. 기본(스크립트 전)은 서버가 쿠키로 정한 값이 이미 붙어 있다 */
.v-quiet .q-theme .q-theme-half,
.v-quiet .q-theme .q-theme-full { display: none; }
.v-quiet .q-theme[data-state="system"] .q-theme-half { display: block; }
.v-quiet .q-theme[data-state="dark"] .q-theme-full { display: block; }
/* JS 가 없으면 누를 수 있는 것처럼 보이면 안 된다 — 스크립트가 켠다 */
.v-quiet .q-theme[hidden] { display: none; }

/* --- 햄버거와 서랍 (2026-08-31 · 오너 지시) ------------------------
 *
 * 넓은 화면에서는 **없는 것과 같다.** 햄버거는 `display: none` 이고 서랍은
 * `display: contents` 라 상자를 만들지 않는다 — ABOUT · 테마 · 검색이 지금까지처럼
 * 헤더 띠에 그대로 늘어선다. 실제 모양은 720px 아래(맨 아래 미디어 블록)에서만
 * 생긴다. 여기 셋은 그 세 줄을 되돌리는 기본값이다.
 *
 * 🔴 항목을 **복제하지 않는다.** 넓은 화면용과 좁은 화면용을 따로 두면
 *    `id="q-theme"` 가 둘이 되고 검색 input 도 둘이 된다. 같은 노드가 CSS 로만
 *    자리를 옮기므로 문서에는 언제나 하나씩이다.
 * ------------------------------------------------------------------ */
.v-quiet .q-menu { display: none; }
.v-quiet .q-drawer { display: contents; }
/* 서랍 안에서만 필요한 글자. 헤더 띠에서는 테마 아이콘이 워드마크·검색과 나란해서
   무엇인지 읽히지만, 판 안에 혼자 놓이면 동그라미 하나가 된다. 「조용한」 것과
   뜻이 안 통하는 것은 다르다.
   🔴 `aria-label` 이 이름을 정하므로 이 글자는 그 안에 **포함**돼야 한다
      (WCAG 2.5.3) — "화면 테마" ⊂ "화면 테마, 눌러서 바꾼다". */
.v-quiet .q-mlabel { display: none; }

/* --- 좌측 트랙에 매달리는 모노 메타 -------------------------------- */
.v-quiet .q-label {
  grid-column: 1;
  text-align: right;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-faint);
  white-space: nowrap;
}
.v-quiet .q-date {
  grid-column: 1;
  text-align: right;
  font-family: var(--q-mono);
  font-size: 11.5px;
  line-height: 28px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
  white-space: nowrap;
}
.v-quiet .q-n {
  font-family: var(--q-mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
  margin-left: 6px;
}
.v-quiet .p-mark {
  display: block;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-faint);
}

/* --- 홈 인트로 블록 (관리자 편집형, 비면 서버가 렌더하지 않는다) --- */
.v-quiet .q-hello { margin-top: 104px; }
.v-quiet .q-hello p {
  margin: 0 0 12px;
  font-size: 17px;
  line-height: 34px;
  letter-spacing: -0.012em;
  color: var(--q-mid);
  max-width: 560px;
}
.v-quiet .q-hello p:first-child {
  color: var(--q-ink);
  font-weight: 500;
}
.v-quiet .q-hello p:last-child { margin-bottom: 0; }
.v-quiet .q-hello a {
  box-shadow: inset 0 -1px 0 var(--q-link-line);
  transition: box-shadow 200ms ease;
}
.v-quiet .q-hello a:hover { box-shadow: inset 0 -1px 0 var(--q-link-line-on); }

/* --- 아카이브·검색 헤딩 ------------------------------------------- */
.v-quiet .q-heading { margin-top: 104px; }
.v-quiet .q-heading .q-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--q-rule);
}
.v-quiet .q-heading h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 500;
  line-height: 30px;
  letter-spacing: -0.018em;
  color: var(--q-ink);
}
.v-quiet .q-heading h1 i {
  font-style: normal;
  color: var(--q-faint);
  margin: 0 8px;
}
.v-quiet .q-heading .q-count {
  flex: 0 0 auto;
  font-family: var(--q-mono);
  font-size: 11.5px;
  line-height: 18px;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}

/* --- 오류 화면 (#39) ----------------------------------------------
 * 새 컴포넌트를 만들지 않는다. 헤딩·본문 크기를 목록 화면에서 그대로 가져와
 * **오류도 이 사이트의 한 화면**으로 읽히게 한다. 구분선도 두지 않는다 —
 * 나가는 문 두 개 말고는 아무것도 없는 자리다.
 * ------------------------------------------------------------------ */
.v-quiet .p-err { margin-top: 140px; }
.v-quiet .p-err h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 500;
  line-height: 30px;
  letter-spacing: -0.018em;
  color: var(--q-ink);
}
.v-quiet .p-err p {
  margin: 26px 0 0;
  max-width: 560px;
  font-size: 14px;
  line-height: 28px;
  color: var(--q-mid);
}
.v-quiet .p-err-out {
  margin-top: 40px;
  font-family: var(--q-mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
}
.v-quiet .p-err-out a { color: var(--q-soft); text-decoration: none; }
.v-quiet .p-err-out a:hover { color: var(--q-ink); }
.v-quiet .p-err-out span { color: var(--q-faint); margin: 0 10px; }

.v-quiet .q-note {
  margin: 30px 0 0;
  max-width: 560px;
  font-size: 14px;
  line-height: 28px;
  letter-spacing: -0.01em;
  color: var(--q-mid);
}
.v-quiet .q-note em { font-style: normal; color: var(--q-ink); }

/* --- 목록 --------------------------------------------------------- */
.v-quiet .q-recent { margin-top: 132px; }
.v-quiet .q-list { margin-top: 30px; }
.v-quiet .q-post {
  display: grid;
  grid-template-columns: var(--q-cols);
  align-items: start;
  padding-bottom: 38px;
}
.v-quiet .q-post:last-child { padding-bottom: 0; }
.v-quiet .q-post .q-date {
  padding-top: 1px;
  transition: color 220ms ease;
}
.v-quiet .q-body { grid-column: 3; min-width: 0; }
/* h2 로 나간다(04 §4.1 의 카드 제목이 곧 문서의 소제목이다). 브라우저 기본 여백을 지운다 */
.v-quiet .q-title {
  margin: 0;
  font-size: 19px;
  font-weight: 500;
  line-height: 28px;
  letter-spacing: -0.018em;
  color: var(--q-ink);
  max-width: 620px;
}
/* 검색 하이라이트는 제목에만 — 본문 발췌에는 하지 않는다(「침묵」, 04 §4.4) */
.v-quiet .q-title mark {
  background: var(--q-sel);
  color: var(--q-ink);
}
/* 04 §4.1 — 분류는 **날짜 아래**, 좌측 메타 트랙에 우측정렬. 복수면 줄바꿈이라
   구분점(`·`)을 두지 않고 한 줄에 하나씩 쌓는다 */
.v-quiet .q-cats {
  grid-column: 1;
  text-align: right;
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 18px;
  letter-spacing: 0.005em;
  color: var(--q-faint);
}
.v-quiet .q-cats span { display: block; }
/* 발췌 — **기본은 없고, 카드에 마우스를 올리면 3줄이 펴진다** (#45, 오너 지시 2026-08-07).
 *
 * ## 세 번 뒤집힌 자리다
 *
 * ```
 * ①  max-height: 0 · hover 에서만 편다     초기 시안
 * ②  항상 3줄                              ① 의 비대칭 때문에 바꿨다
 * ③  3줄이 바닥 · hover 에서 전문           오너 지시를 내가 잘못 읽었다
 * ④  없음 · hover 에서 3줄                  ← 지금. ① 로 돌아왔다
 * ```
 *
 * ② 로 바꿀 때의 이유는 **"폰에서 아무것도 못 읽는다"** 였다. 그 이유는 지금도
 * 유효하므로 `@media (hover: none)` 에서 상시 3줄로 편다(아래). 마우스가 없는
 * 기기는 hover 라는 사건 자체가 없으니, 그쪽에는 처음부터 펴 두는 것이 맞다.
 * ① 이 틀렸던 것은 목록의 조용함이 아니라 **폰을 잊은 것**이었다.
 *
 * ## 목록은 제목만으로 선다
 *
 * 214편이 제목·날짜·분류만으로 늘어선다. 발췌는 손이 닿은 카드 하나에만 나타난다 —
 * 「침묵」에서 정보는 요청할 때 온다.
 *
 * 🔴 `margin-top` 도 같이 전이시켜야 한다. 높이만 접으면 12px 이 남아 카드 사이가
 *    들쭉날쭉해진다.
 */
.v-quiet .q-excerpt {
  margin-top: 0;
  max-width: 560px;
  font-size: 13.5px;
  line-height: 26px;
  letter-spacing: -0.006em;
  color: var(--q-mid);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 280ms ease, opacity 220ms ease, margin-top 280ms ease;
}
/* `focus-within` 이 있어야 키보드로도 닿는다 — 카드 안 제목이 링크다 */
.v-quiet .q-post:hover .q-excerpt,
.v-quiet .q-post:focus-within .q-excerpt {
  margin-top: 12px;
  /* 3줄 = 26px × 3. 클램프와 같은 값이어야 마지막 줄이 잘리지 않는다 */
  max-height: 78px;
  opacity: 1;
}
.v-quiet .q-post:hover .q-date { color: var(--q-ink); }
.v-quiet .q-post:hover .q-cats { color: var(--q-soft); }

/* --- 페이지네이션 (F-V8) ------------------------------------------ */
.v-quiet .q-pages { margin-top: 76px; }
.v-quiet .q-pages nav {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 22px;
  font-family: var(--q-mono);
  font-size: 12.5px;
  line-height: 18px;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .q-pages a { transition: color 200ms ease; }
.v-quiet .q-pages a:hover { color: var(--q-ink); }
.v-quiet .q-pages .q-now {
  color: var(--q-ink);
  font-weight: 500;
}
.v-quiet .q-pages .q-gap { color: var(--q-ghost); }

/* --- 푸터 --------------------------------------------------------- */
.v-quiet .q-foot { margin-top: 132px; }
.v-quiet .q-foot p {
  margin: 0;
  font-family: var(--q-mono);
  font-size: 10.5px;
  line-height: 18px;
  letter-spacing: 0.16em;
  color: var(--q-ghost);
}
.v-quiet .q-foot a { transition: color 200ms ease; }
.v-quiet .q-foot a:hover { color: var(--q-mid); }

/* --- 빵부스러기 · 제목 블록 --------------------------------------- */
.v-quiet .p-crumb { margin-top: 104px; }
.v-quiet .p-crumb nav {
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  color: var(--q-soft);
}
.v-quiet .p-crumb a { transition: color 200ms ease; }
.v-quiet .p-crumb a:hover { color: var(--q-ink); }
.v-quiet .p-crumb i {
  font-style: normal;
  color: var(--q-faint);
  margin: 0 8px 0 4px;
}

.v-quiet .p-head { margin-top: 30px; }
.v-quiet .p-head .q-date { padding-top: 13px; }
.v-quiet .p-title {
  margin: 0;
  font-size: 30px;
  font-weight: 500;
  line-height: 46px;
  letter-spacing: -0.028em;
  color: var(--q-ink);
  max-width: 700px;
}
.v-quiet .p-chips {
  margin-top: 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.v-quiet .p-chip {
  display: inline-block;
  border: 1px solid var(--q-rule);
  padding: 6px 12px;
  font-size: 11.5px;
  line-height: 16px;
  letter-spacing: -0.005em;
  color: var(--q-mid);
  transition: border-color 200ms ease, color 200ms ease;
}
.v-quiet .p-chip:hover {
  border-color: var(--q-soft);
  color: var(--q-ink);
}

/* --- 정적 목차 — JS 가 없을 때의 기본값 (F-V1) --------------------- */
.v-quiet .p-toc { margin-top: 88px; }
.v-quiet .p-toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: q-toc;
  max-width: 560px;
}
.v-quiet .p-toc li {
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 6px 0;
}
.v-quiet .p-toc li::before {
  counter-increment: q-toc;
  content: counter(q-toc, decimal-leading-zero);
  flex: 0 0 auto;
  font-family: var(--q-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .p-toc a {
  /* 🔴 `li` 가 flex 라 항목의 기본 `min-width: auto` 가 내용보다 작아지는 것을 막는다.
     루트가 `word-break: keep-all` 이라 「오케스트레이터는」 같은 긴 낱말이 한 덩어리인데,
     줄 자리가 없으면 줄바꿈 대신 **상자를 넓혀** 페이지를 가로로 민다.
     `.p-related span`·`.p-nb` 와 같은 종류다 (2026-08-31 실측). */
  min-width: 0;
  font-size: 14px;
  line-height: 24px;
  letter-spacing: -0.012em;
  color: var(--q-mid);
  transition: color 200ms ease;
}
.v-quiet .p-toc a:hover { color: var(--q-ink); }

/* --- 본문 문서: 레일 + 아티클 -------------------------------------
 * 🔴 `grid-row: 1` 이 둘 다에 있어야 한다. 마크업이 **레일 → 본문** 순서인데
 *    레일은 1트랙, 본문은 3트랙이라 자동 배치가 둘을 다른 행에 놓기 때문이다.
 *    좌우 배치는 그리드가 만든다 — `order` 로 뒤집지 않는다(탭 순서가 어긋난다).
 * ------------------------------------------------------------------ */
.v-quiet .p-doc,
.v-quiet .q-doc {
  display: grid;
  grid-template-columns: var(--q-cols);
}
.v-quiet .p-doc { margin-top: 100px; }
/* 🔴 목록·아카이브·검색에도 같은 상단 여백이 있어야 한다.
 *
 *    예전에는 `.q-doc` 에 여백이 0 이라 sticky 레일이 헤더 띠에 **2px** 간격으로
 *    붙어 있었다(실측 @1280: 워드마크 bottom y=150 · `.p-rail-label` top y=152).
 *    상세에서 같은 값을 재면 766px 이라 두 화면이 아예 다른 규칙을 쓰고 있었다.
 *    「침묵」의 상단 여백은 104px 단위다(`.q-hello`·`.q-heading`·`.p-crumb`).
 *
 *    아래 두 줄이 짝이다 — 첫 블록의 상단 여백을 컨테이너로 올려야 레일과 본문이
 *    **같은 높이에서** 출발한다. 올리지 않으면 여백이 두 번 붙어 본문만 내려간다.
 *    `.q-sr` 은 절대 위치라 자리를 차지하지 않으므로, 감춘 h1 이 먼저 오는 홈에서는
 *    그 다음 블록이 실질적 첫 블록이다(그 경우만 원래 값 132 - 104 = 28 이 남는다). */
.v-quiet .q-doc { margin-top: 104px; }
.v-quiet .q-docmain > .q-hello:first-child,
.v-quiet .q-docmain > .q-heading:first-child { margin-top: 0; }
.v-quiet .q-docmain > .q-sr:first-child + .q-recent { margin-top: 28px; }
.v-quiet .p-main,
.v-quiet .q-docmain {
  grid-column: 3;
  grid-row: 1;
  min-width: 0;
}

/* --- 좌측 레일 (LNB + 레일 목차) ----------------------------------
 * 🔴 조상에 overflow:hidden 이 걸리면 sticky 가 죽는다. 가로 넘침을
 *    막을 일이 있으면 overflow-x: clip 을 쓴다.
 * ------------------------------------------------------------------ */
.v-quiet .p-rail {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
  position: sticky;
  top: 36px;
  text-align: right;
  max-height: calc(100vh - 72px);
  overflow-y: auto;
  /* 🔴 `overscroll-behavior: contain` 을 뺐다 (#43).
     `contain` 은 **스크롤할 것이 없어도** 연쇄를 막는다. 레일이 안 넘치는
     보통 상황에서 레일 위 116px 이 통째로 죽은 구역이 된다 — 휠을 굴려도
     페이지가 안 움직인다. 실측(1280x900): 레일 위에서 휠 10회, y 가 4000 에서
     그대로였다. 레일 끝에서 페이지가 안 밀리는 이점보다 잃는 게 크다. */
  scrollbar-width: thin;
  scrollbar-color: var(--q-faint) transparent;
}
/* 분류 판의 라벨은 `summary`, 목차 판의 라벨은 `span` 이다. 둘이 같아 보여야 한다.
   🔴 `display: block` 이 여닫이 삼각형을 없앤다(브라우저 기본은 `list-item`).
      사파리는 `::-webkit-details-marker` 를 따로 지워야 한다. */
.v-quiet .p-rail-label {
  display: block;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  color: var(--q-faint);
  margin-bottom: 26px;
}
.v-quiet summary.p-rail-label {
  list-style: none;
  cursor: pointer;
  transition: color 200ms ease;
}
.v-quiet summary.p-rail-label::-webkit-details-marker { display: none; }
.v-quiet summary.p-rail-label:hover { color: var(--q-soft); }
.v-quiet summary.p-rail-label:focus-visible {
  color: var(--q-ink);
  outline: 1px solid var(--q-soft);
  outline-offset: 3px;
}
/* 여닫이 표식. 접을 수 있다는 것을 알려주지 않으면 접힌 분류는 그냥 사라진 것으로
   보인다. 폭에 상관없이 낸다 — 넓은 화면에서도 사용자가 접을 수 있는데 표식이
   그때만 없으면 되펼 방법이 안 보인다 */
.v-quiet summary.p-rail-label::after {
  content: "+";
  margin-left: 0.6em;
  font-variant-numeric: tabular-nums;
}
.v-quiet .p-rail-cats[open] > summary.p-rail-label::after { content: "−"; }
.v-quiet .p-branch { margin-bottom: 22px; }
.v-quiet .p-branch:last-child { margin-bottom: 0; }
.v-quiet .p-branch-head {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: -0.012em;
  color: var(--q-ink);
  transition: color 200ms ease;
}
.v-quiet .p-branch-head:hover { color: var(--q-ink-dim); }
.v-quiet .p-branch ul {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}
.v-quiet .p-branch ul a {
  display: block;
  font-size: 11.5px;
  line-height: 20px;
  letter-spacing: -0.008em;
  color: var(--q-soft);
  transition: color 200ms ease;
}
.v-quiet .p-branch ul a:hover { color: var(--q-ink); }
.v-quiet .p-branch a[aria-current] {
  color: var(--q-ink);
  font-weight: 500;
}
.v-quiet .p-branch a[aria-current] .q-n { color: var(--q-soft); }

/* --- F-V1 레일 전환: 분류 ↔ 목차 ---------------------------------
 * 둘 다 항상 DOM 에 있고 표시만 바뀐다. JS 가 없으면 분류가 그대로 남는
 * 것이 기본값이므로, 레일 목차는 `hidden` 을 달고 서버에서 나간다.
 *
 * 🔴 aria-live 를 쓰지 않는다 — 스크롤마다 스크린리더가 읽으면 방해다.
 *
 * 전환 중 컨테이너 높이가 튀지 않도록 두 장을 겹쳐 놓고 opacity 만
 * 바꾼다. 분류 27줄과 목차 5줄은 높이 차가 크다.
 * ------------------------------------------------------------------ */
.v-quiet .p-rail-stack { position: relative; }
.v-quiet .p-rail-pane {
  transition: opacity 200ms ease;
}
.v-quiet .p-rail-pane[hidden] {
  display: block;
  opacity: 0;
  pointer-events: none;
  /* 스크린리더에도 감춘다. hidden 속성의 기본 동작을 display 로 덮었기 때문 */
  visibility: hidden;
  position: absolute;
  inset: 0;
  /* 🔴 이 줄이 없으면 **안 보이는 pane 이 스크롤바를 만든다** (#43).
     `inset: 0` 이 숨은 pane 을 보이는 pane 높이에 가두는데, 내용이 그보다
     길면 넘친 만큼이 레일의 스크롤 영역으로 잡힌다.
     실측(1280x900 · 글 3702): 목차 표시 중 clientHeight 489 인데
     scrollHeight 698 — 숨은 분류 27줄이 만든 209px 이었다.
     보이는 것이 아니라 안 보이는 것 때문에 생기던 스크롤바다. */
  overflow: hidden;
}
.v-quiet .p-rail-toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: q-rail;
}
.v-quiet .p-rail-toc li { margin-bottom: 14px; }
.v-quiet .p-rail-toc li:last-child { margin-bottom: 0; }
.v-quiet .p-rail-toc li::before {
  counter-increment: q-rail;
  content: counter(q-rail, decimal-leading-zero);
  display: block;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.12em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
  margin-bottom: 3px;
}
.v-quiet .p-rail-toc a {
  display: block;
  font-size: 11.5px;
  line-height: 18px;
  letter-spacing: -0.008em;
  color: var(--q-mid);
  transition: color 200ms ease;
}
.v-quiet .p-rail-toc a:hover { color: var(--q-ink); }
.v-quiet .p-rail-toc a.is-cur { color: var(--q-ink); font-weight: 500; }

/* --- 맨 위로 (#43) ------------------------------------------------
 * `분류`·`목차` 와 같은 급의 글자 하나다. 원형 버튼도, 그림자도, 테두리도 없다.
 * 목차가 떠 있을 때만 나타난다 — 신호를 레일 전환과 공유한다.
 * ------------------------------------------------------------------ */
.v-quiet .p-totop {
  display: block;
  margin-top: 34px;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-faint);
  text-decoration: none;
  transition: color 200ms ease;
}
.v-quiet .p-totop[hidden] { display: none; }
.v-quiet .p-totop:hover { color: var(--q-ink); }
.v-quiet .p-totop:focus-visible {
  outline: 1px solid var(--q-soft);
  outline-offset: 4px;
}

/* --- 본문 --------------------------------------------------------- */
.v-quiet .post-body { counter-reset: q-sec; }
.v-quiet .post-body > :first-child { margin-top: 0; }

.v-quiet .post-body h2 {
  margin: 104px 0 26px;
  max-width: 672px;
  font-size: 21px;
  font-weight: 500;
  line-height: 34px;
  letter-spacing: -0.022em;
  color: var(--q-ink);
  scroll-margin-top: 36px;
}
/* 섹션 경계를 색이나 선이 아니라 모노 번호와 여백으로 만든다 */
.v-quiet .post-body h2::before {
  counter-increment: q-sec;
  content: counter(q-sec, decimal-leading-zero);
  display: block;
  margin-bottom: 16px;
  font-family: var(--q-mono);
  font-size: 10px;
  font-weight: 400;
  line-height: 14px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-faint);
}
.v-quiet .post-body h3 {
  margin: 62px 0 18px;
  max-width: 672px;
  font-size: 16px;
  font-weight: 500;
  line-height: 30px;
  letter-spacing: -0.016em;
  color: var(--q-ink);
  scroll-margin-top: 36px;
}
/* 🔴 루트가 line-height:1 이라 개별 규칙이 없는 요소는 줄이 붙는다.
   마크다운 저자가 h4~h6 을 쓰면 즉시 티가 나므로 받아 둔다 */
.v-quiet .post-body h1,
.v-quiet .post-body h4,
.v-quiet .post-body h5,
.v-quiet .post-body h6 {
  margin: 48px 0 16px;
  max-width: 672px;
  font-size: 15px;
  font-weight: 600;
  line-height: 28px;
  letter-spacing: -0.014em;
  color: var(--q-ink);
  scroll-margin-top: 36px;
}
.v-quiet .post-body h1 { font-size: 24px; line-height: 38px; }
.v-quiet .post-body dl,
.v-quiet .post-body dd,
.v-quiet .post-body dt,
.v-quiet .post-body figcaption,
.v-quiet .post-body address {
  font-size: 15px;
  line-height: 30px;
  letter-spacing: -0.01em;
  color: var(--q-mid);
}
.v-quiet .post-body hr {
  margin: 72px 0 0;
  max-width: 672px;
  border: 0;
  border-top: 1px solid var(--q-rule);
}

/* 🔴 문단 리듬 — 05 §5.1 X2.
 *
 *   문단 간격은 **행간보다 커야 한다.** 30px < 34px 이면 문단 경계가 줄바꿈과
 *   구별되지 않아 장문에서 읽던 자리를 놓친다. 40px 로 올린다.
 *
 *   같은 값을 `ul`·`ol`·`blockquote 뒤` 에도 쓴다. 문단과 목록이 서로 다른
 *   리듬을 가지면 「침묵」의 지면이 두 박자로 흔들린다.
 *
 *   줄바꿈은 루트(`.v-quiet`)가 `keep-all` + `overflow-wrap: break-word` 로 잡고
 *   있는데, **본문 문단만 그 상속을 끊는다** (#42, 오너 지시 2026-08-06).
 */
.v-quiet .post-body p {
  margin: 40px 0 0;
  max-width: 672px;
  /* 오너 지시 2026-08-24 — 17px → 16px. 행간은 배수(2.0)를 지켜 34 → 32.
     문단 간격 40px 은 그대로라 「간격 > 행간」(05 §5.1 X2)이 더 넉넉해진다. */
  font-size: 16px;
  line-height: 32px;
  letter-spacing: -0.012em;
  color: var(--q-ink);
  /* 명세상 `word-break: normal` + `overflow-wrap: anywhere` 와 같은 값이다.
     루트의 `keep-all` 이 여기서 풀리므로 **한글이 어절 중간에서도 끊긴다.**
     그것이 이 지시의 내용이다 — 문단이 상자를 뚫는 쪽보다 낫다고 판단했다.
     제목·목록·표는 건드리지 않는다. 루트 상속 그대로 어절을 지킨다. */
  word-break: break-word;
}
.v-quiet .post-body strong {
  font-weight: 600;
  letter-spacing: -0.016em;
}
.v-quiet .post-body em {
  font-style: italic;
  color: var(--q-mid);
}
/* 링크는 색이 아니라 밑줄 알파로 구분한다 — 그레이스케일에서도 살아남는다 */
.v-quiet .post-body p a,
.v-quiet .post-body li a,
.v-quiet .post-body td a {
  color: var(--q-ink);
  box-shadow: inset 0 -1px 0 var(--q-link-line);
  transition: box-shadow 200ms ease;
}
.v-quiet .post-body p a:hover,
.v-quiet .post-body li a:hover,
.v-quiet .post-body td a:hover {
  box-shadow: inset 0 -1px 0 var(--q-link-line-on);
}

.v-quiet .post-body ul,
.v-quiet .post-body ol {
  margin: 40px 0 0;
  padding: 0;
  max-width: 672px;
  list-style: none;
  counter-reset: q-li;
}
/* 🔴 항목 사이에 여백을 두지 않는다 (오너 지시 2026-08-06).
 *
 *   `line-height` 는 문단과 이미 같은 34px 였고, 차이는 항목마다 붙던
 *   `margin-top: 12px` 하나였다 — 항목 사이가 46px 이라 목록만 성기게 떴다.
 *   목록 항목이 **문단 안의 줄들처럼** 34px 간격으로 이어져야 한다.
 *
 *   항목 경계는 여백이 아니라 불릿(`::before`)이 만든다. 실측으로 확인했다 —
 *   여러 줄로 넘어가는 항목에서도 불릿이 각 항목의 첫 줄에만 찍혀 경계가 남는다.
 */
.v-quiet .post-body li {
  position: relative;
  padding-left: 22px;
  /* 🔴 문단과 **같은 값**이어야 한다. 다르면 지면이 두 박자로 흔들린다
         (QuietCssContractTest 가 두 값이 같은지 본다) */
  font-size: 16px;
  line-height: 32px;
  letter-spacing: -0.012em;
  color: var(--q-ink);
}
/* 🔴 중첩 목록은 위 `margin: 40px 0 0` 을 물려받으면 안 된다.
 *
 *    그 40px 은 **문단과 목록 사이** 간격이다. 항목 사이 여백을 0 으로 만든 뒤로는
 *    중첩된 `ul`/`ol` 만 40px 을 그대로 써서 부모 항목에서 뚝 떨어졌다 — 실측
 *    (2026-08-06 · Chrome headless): 부모 항목 글줄과 자식 항목 글줄 사이 74px,
 *    행간 34px 이므로 목록 한가운데 40px 짜리 빈 칸이 생긴다.
 *    중첩 목록은 부모 항목의 다음 줄로 **이어져야** 한다. */
.v-quiet .post-body li > ul,
.v-quiet .post-body li > ol { margin-top: 0; }
.v-quiet .post-body ul > li::before {
  content: "";
  position: absolute;
  left: 3px;
  /* 행간을 따라간다 — 34px 일 때 15px, 32px 일 때 14px, 30px 일 때 13px */
  top: 14px;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--q-soft);
}
.v-quiet .post-body ol > li::before {
  counter-increment: q-li;
  content: counter(q-li);
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--q-mono);
  font-size: 11px;
  line-height: 32px;
  color: var(--q-faint);
  font-variant-numeric: tabular-nums;
}

.v-quiet .post-body blockquote {
  margin: 58px 0 0;
  padding-left: 26px;
  max-width: 672px;
  border-left: 1px solid var(--q-rule);
}
.v-quiet .post-body blockquote p {
  margin: 0;
  /* 본문보다 한 칸 작다는 관계를 지킨다 (본문 17→16 에 맞춰 16→15) */
  font-size: 15px;
  line-height: 30px;
  letter-spacing: -0.01em;
  color: var(--q-mid);
}

/* 인라인 코드 — X3. `break-all` 을 쓰면 Supplier<List<Path>> 가
   Suppli / er<List<Pa / th>> 로 잘린다 */
.v-quiet .post-body p code,
.v-quiet .post-body li code,
.v-quiet .post-body blockquote code,
.v-quiet .post-body td code,
.v-quiet .post-body h3 code {
  font-family: var(--q-mono);
  font-size: 0.855em;
  letter-spacing: 0;
  color: var(--q-ink);
  background: var(--q-code-in);
  padding: 0.1em 0.34em;
  /* 사이트 전체에서 유일한 라운드 값이다 */
  border-radius: 2px;
  /* 🔴 05 §5 X3 의 판정을 뒤집는 값이다 (#42, 오너 지시 2026-08-06).
     X3 은 `break-all` 이 `Supplier<List<Path>>` 를 `Suppli / er<List<Pa / th>>`
     로 자른다며 `overflow-wrap: anywhere` 를 택했다. 그 판단이 뒤집혔다 —
     식별자가 잘리더라도 상자를 뚫지 않는 쪽을 택한다.
     `anywhere` 는 지운다. `break-all` 이 이기므로 남겨 두면 읽는 사람이 헷갈린다.
     코드블록은 `white-space: pre` 라 이 값이 닿아도 줄바꿈이 생기지 않는다. */
  word-break: break-all;
}

/* --- 코드블록 — 이 블로그의 본체(949개 · 글의 71%) -----------------
 *
 * 🔴 코드가 문단보다 넓어서 글이 정돈돼 보이지 않았다 (#43, 오너 지적).
 *    실측: 1440px 이상에서 문단 672px · 코드 860px — 코드가 188px 튀어나온다.
 *
 *    그런데 **넓을 이유가 거의 없다.** 코드블록 951개의 가장 긴 줄을 셌다.
 *
 *      672px(≈86자) 안에 들어감   89.6%
 *      860px(≈110자) 안에 들어감  96.5%
 *      860px 로도 스크롤해야 함     3.5%
 *
 *    89.6% 는 문단 폭에 그냥 들어간다. 열을 맞춰도 잃는 게 없다.
 *    나머지 10.4% 만 넓힐 수 있게 한다 — 할 일이 있는 블록에만 장치가 생긴다.
 *
 * ## 넓혀도 아래가 안 밀린다
 *
 * `white-space: pre` 라 폭이 늘어도 **줄 수가 변하지 않는다.** 높이가 그대로이므로
 * 뒤따르는 문단이 움직이지 않는다. 마우스가 지나갈 때 페이지가 흔들리지 않는
 * 이유가 이것이다 — 이 조건이 깨지면(줄바꿈을 허용하면) 이 규칙도 같이 깨진다.
 * ------------------------------------------------------------------ */
.v-quiet .codeblock {
  margin: 58px 0 0;
  /* 문단과 같은 열에 선다. `.post-body p` 의 값과 **같아야** 한다 */
  max-width: 672px;
  border: 1px solid var(--q-code-edge);
  background: var(--q-code-bg);
  transition: max-width 240ms ease;
}

/* 넘치는 블록만 표시가 붙는다(`quiet.js`). 안 넘치면 컨트롤도 없다.
 *
 * `.is-wide` 는 **클릭으로 고정한 상태**다 (#45, 오너 지시). hover 는 손을 떼면
 * 돌아오지만 이건 남는다 — 긴 코드를 읽는 동안 마우스를 붙들고 있을 수는 없다.
 * 다시 누르면 풀린다. */
.v-quiet .codeblock.is-widenable:has(.codeblock-head:hover),
.v-quiet .codeblock.is-widenable:focus-within,
.v-quiet .codeblock.is-wide {
  max-width: 100%;
}
/* 고정 상태에서는 헤드가 눌린 컨트롤이라는 것을 라벨이 알린다 */
.v-quiet .codeblock.is-widenable .codeblock-lang { cursor: pointer; }
.v-quiet .codeblock.is-widenable .codeblock-lang:hover,
.v-quiet .codeblock.is-wide .codeblock-lang { color: var(--q-ink); }
.v-quiet .codeblock-lang:focus-visible {
  outline: 1px solid var(--q-soft);
  outline-offset: 3px;
}

/* `:has` 가 없는 브라우저를 위한 폴백 — 블록 어디든 올리면 넓어진다 */
@supports not selector(:has(*)) {
  .v-quiet .codeblock.is-widenable:hover { max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .v-quiet .codeblock { transition: none; }
}
.v-quiet .codeblock-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 16px 10px 20px;
  border-bottom: 1px solid var(--q-code-rule);
}
.v-quiet .codeblock-lang {
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 16px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
  color: var(--q-soft);
}
/* 언어 미지정 블록 15.3%(145개) — 빈 라벨을 그대로 두지 않는다 */
.v-quiet .codeblock-lang:empty::before {
  content: "PLAIN";
  color: var(--q-faint);
}
.v-quiet .btn-copy {
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 16px;
  letter-spacing: 0.16em;
  color: var(--q-soft);
  cursor: pointer;
  opacity: 0;
  transition: opacity 220ms ease, color 200ms ease;
}
/* focus-within 이 있어야 키보드만으로 도달할 수 있다(N-X2) */
.v-quiet .codeblock:hover .btn-copy,
.v-quiet .codeblock:focus-within .btn-copy { opacity: 1; }
.v-quiet .btn-copy:hover { color: var(--q-ink); }
.v-quiet .btn-copy:focus-visible {
  opacity: 1;
  outline: 1px solid var(--q-soft);
  outline-offset: 3px;
}

/* 🔴 가로 스크롤이 블록 내부에 갇힌다. 페이지가 밀리면 실패다(D5) */
.v-quiet .codeblock pre {
  margin: 0;
  padding: 22px 20px 24px;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  background: transparent;
  scrollbar-width: thin;
  scrollbar-color: var(--q-faint) transparent;
}
.v-quiet .codeblock code {
  display: block;
  font-family: var(--q-mono);
  font-size: 13px;
  line-height: 24px;
  letter-spacing: 0;
  color: var(--q-ink);
  word-break: normal;
  white-space: pre;
  tab-size: 4;
  background: none;
  padding: 0;
}

/* 구문 토큰. 지금은 이 클래스를 만드는 쪽이 없다 — 서버 하이라이터를
   붙이는 날 이 규칙 위에 그대로 얹힌다(05 §7.5) */
.v-quiet .tok-kw   { color: var(--q-kw); }
.v-quiet .tok-str  { color: var(--q-str); }
.v-quiet .tok-com  { color: var(--q-com); }
.v-quiet .tok-num  { color: var(--q-num); }
.v-quiet .tok-fn   { color: var(--q-fn); }
.v-quiet .tok-type { color: var(--q-type); }
.v-quiet .tok-ann  { color: var(--q-ann); }
/* 로그의 [main] 같은 대괄호 태그가 링크로 오독되지 않도록 (R5) */
.v-quiet .codeblock code span {
  text-decoration: none;
  box-shadow: none;
}

/* --- 표 — max-width 가 빠지면 넓은 표가 페이지 전체를 민다 --------- */
.v-quiet .post-body table {
  display: block;
  width: max-content;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  margin: 58px 0 0;
}
.v-quiet .post-body th,
.v-quiet .post-body td {
  text-align: left;
  white-space: nowrap;
  padding: 13px 26px 13px 0;
  border-bottom: 1px solid var(--q-rule);
}
.v-quiet .post-body th {
  font-family: var(--q-mono);
  font-size: 10px;
  font-weight: 400;
  line-height: 18px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--q-soft);
  border-bottom-color: var(--q-rule-strong);
  padding-bottom: 11px;
}
.v-quiet .post-body td {
  font-size: 13.5px;
  line-height: 24px;
  letter-spacing: -0.008em;
  color: var(--q-mid);
}
.v-quiet .post-body td:first-child { color: var(--q-ink); }
.v-quiet .post-body tbody tr:last-child td { border-bottom: 0; }

/* --- 이미지 ------------------------------------------------------- */
.v-quiet .post-body p > img,
.v-quiet .post-image img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  margin: 62px 0 0;
  /* 다크에서 흰 여백 많은 도식이 발광하지 않게. 값은 토큰에서만 온다 */
  filter: var(--q-img-filter);
  cursor: zoom-in;
}
.v-quiet .post-image { margin: 62px 0 0; max-width: 100%; }

/* --- 다이어그램 (#79) -----------------------------------------------
   본문의 ```mermaid · ```svg 펜스가 구워져 <img> 로 나온 자리다.

   🔴 인라인 SVG 가 아니라 이미지인 이유는 CSP 다. 실측(2026-08-10) — 우리
      style-src 'self' 아래에서 내부 <style> 을 가진 인라인 SVG 는 새까맣게 나온다.
      <img> 안의 SVG 는 자기 문서라 그 제약을 안 받는다.

   그래서 여기서도 **다른 이미지와 같은 대접**을 한다 — 다크에서 발광하지 않게
   같은 토큰을 쓴다. 도표만 따로 취급하면 한 지면에 두 가지 이미지 규칙이 생긴다. */
.v-quiet .post-body .diagram {
  margin: 44px 0;
  max-width: 100%;
  /* 도표는 대개 글보다 좁다. 가운데로 몰면 글줄과 축이 어긋나 보여서 왼쪽에 맞춘다 */
  text-align: left;
  /* 넓은 도표가 지면을 밀지 않게. 넘치면 이 안에서만 가로로 민다 */
  overflow-x: auto;
}
.v-quiet .post-body .diagram img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  margin: 0;
}
/* 🔴 mermaid 로 구운 것은 **라이트 테마로만** 굳어 있다. 다크에서 발광하지 않게
      다른 이미지와 같은 토큰을 건다. */
.v-quiet .post-body .diagram.is-mermaid img { filter: var(--q-img-filter); }
/* 🔴 손으로 쓴 SVG 는 자기 안에서 @media (prefers-color-scheme: dark) 로 테마를
      바꿀 수 있다(별도 문서로 서빙되므로 동작한다 — 실측 2026-08-10).
      거기에 필터까지 걸면 이미 어두워진 그림을 한 번 더 눌러 탁해진다. */
.v-quiet .post-body .diagram.is-svg img { filter: none; }
.v-quiet .post-image img { margin: 0; }
.v-quiet .post-image figcaption {
  margin-top: 14px;
  max-width: 620px;
  font-size: 12.5px;
  line-height: 24px;
  letter-spacing: -0.008em;
  color: var(--q-mid);
}

/* --- 라이트박스 (F-V3) --------------------------------------------
 * 문서에 시각 사양이 없어 구현자가 정했다 — 「침묵」이므로 지면색을
 * 거의 불투명하게 덮고 장식을 두지 않는다.
 * 확대 이미지에는 --q-img-filter 를 걸지 않는다. 원본을 보러 연 것이다.
 * ------------------------------------------------------------------ */
.v-quiet .q-lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 72px 40px;
  background: var(--q-bg);
  opacity: 0.98;
  transition: opacity 200ms ease;
}
.v-quiet .q-lightbox[hidden] { display: none; }
.v-quiet .q-lightbox img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: none;
  cursor: zoom-out;
}
.v-quiet .q-lightbox-close {
  position: absolute;
  top: 26px;
  right: 32px;
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: transparent;
  padding: 6px;
  cursor: pointer;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 16px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
  color: var(--q-soft);
  transition: color 200ms ease;
}
.v-quiet .q-lightbox-close:hover { color: var(--q-ink); }
.v-quiet .q-lightbox-close:focus-visible {
  color: var(--q-ink);
  outline: 1px solid var(--q-soft);
  outline-offset: 3px;
}

/* --- 광고 슬롯 (F-V9) --------------------------------------------
 * ① 비활성이면 서버가 DOM 에 아예 넣지 않는다 — CLS 0
 * ② 활성·미충전이면 collapse. :has() 를 모르는 브라우저에서는 예약
 *    높이가 그대로 남는다 — 빈 상자가 남는 쪽이 지면이 튀는 쪽보다 낫다
 * ③ 활성·충전이면 예약 높이 안에 렌더 — CLS 0
 * ------------------------------------------------------------------ */
.v-quiet .ad-slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 92px 0 0;
  min-height: 280px;
  max-width: 100%;
  border: 1px solid var(--q-rule);
  background: var(--q-ad-bg);
  overflow: hidden;
}
.v-quiet .ad-slot-label {
  position: absolute;
  top: 12px;
  left: 14px;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-soft);
}
.v-quiet .ad-slot ins[data-ad-status="unfilled"] { display: none; }
/* 🔴 판정을 뒤집었다 (2026-08-06).
 *
 *   예전 규칙은 `:not(:has(ins[data-ad-status="ad"]))` 였다. 그런데 마크업
 *   (`parts.html :: adSlot` · `MarkdownRenderer.AD_SLOT_HTML`)에 `ins` 가 **아예 없다** —
 *   AdSense 스크립트를 아직 붙이지 않았기 때문이다. 그래서 조건이 늘 참이 되어
 *   `ads.enabled=true` 인데도 슬롯이 **높이 2px**(테두리 두 줄)로 무너졌다.
 *   실측 2026-08-06: 높이 2px · min-height 0px · 라벨은 overflow 에 잘려 안 보임.
 *
 *   접는 판정은 **AdSense 가 미충전을 알려 왔을 때만** 한다. `ins` 가 없는 상태는
 *   04 §3.5 가 말한 "개발 중 자리 확인용 placeholder" 이고, 그때는 예약 높이가
 *   그대로 서 있어야 자리를 확인할 수 있다.
 *
 *   접을 때는 테두리와 바깥 여백까지 같이 없앤다. 2px 짜리 줄 하나가 지면에
 *   남으면 그것은 collapse 가 아니라 「침묵」이 깨진 자국이다.
 */
.v-quiet .ad-slot:has(ins[data-ad-status="unfilled"]) {
  min-height: 0;
  margin: 0;
  border: 0;
}
.v-quiet .ad-slot:has(ins[data-ad-status="unfilled"]) .ad-slot-label { display: none; }

/* --- 태그 --------------------------------------------------------- */
.v-quiet .p-tags { margin-top: 100px; }
.v-quiet .p-taglist {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  margin-top: 22px;
}
.v-quiet .p-tag {
  font-size: 12.5px;
  line-height: 20px;
  letter-spacing: -0.005em;
  color: var(--q-soft);
  transition: color 200ms ease;
}
.v-quiet .p-tag::before {
  content: "#";
  color: var(--q-faint);
  margin-right: 2px;
}
.v-quiet .p-tag:hover { color: var(--q-ink); }

/* --- 관련 글 (F-V4) — 작게. 제목 + 날짜만 ------------------------- */
/* --- 댓글 (#48) ---------------------------------------------------
 * 관련 글과 같은 리듬을 쓴다. 「침묵」에서 글 아래 딸린 것들은 한 박자로 선다 —
 * 카드도 테두리도 없고, 라벨과 여백만으로 구역을 가른다.
 * ------------------------------------------------------------------ */
.v-quiet .p-comments { margin-top: 100px; }
.v-quiet .p-comments .p-mark i {
  font-style: normal;
  margin-left: 8px;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .p-cmt-list,
.v-quiet .p-cmt-replies {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
  max-width: 672px;
}
.v-quiet .p-cmt-list > li { margin-top: 38px; }
.v-quiet .p-cmt-list > li:first-child { margin-top: 0; }
/* 답글은 1단뿐이라 들여쓰기도 한 번뿐이다 (F-C2) */
.v-quiet .p-cmt-replies { margin: 26px 0 0 26px; }
.v-quiet .p-cmt-replies > li { margin-top: 26px; }
.v-quiet .p-cmt-replies > li:first-child { margin-top: 0; }

.v-quiet .p-cmt-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.v-quiet .p-cmt-avatar {
  /* 크기를 마크업에 박아 두고 여기서도 고정한다 — GitHub 이 주는 주소라
     우리가 원본 크기를 모른다. 안 잡으면 이미지가 뜰 때 지면이 튄다 */
  width: 20px;
  height: 20px;
  border-radius: 50%;
  flex: 0 0 auto;
  filter: var(--q-img-filter);
}
.v-quiet .p-cmt-who {
  font-family: var(--q-mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--q-mid);
  text-decoration: none;
}
.v-quiet .p-cmt-who:hover { color: var(--q-ink); }
.v-quiet .p-cmt-when {
  font-family: var(--q-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .p-cmt-body {
  margin-top: 12px;
  font-size: 14px;
  line-height: 28px;
  color: var(--q-mid);
}
.v-quiet .p-cmt-body > :first-child { margin-top: 0; }
.v-quiet .p-cmt-body p { margin: 16px 0 0; }
.v-quiet .p-cmt-body a { color: var(--q-ink); }
.v-quiet .p-cmt-body code {
  font-family: var(--q-mono);
  font-size: 0.855em;
  background: var(--q-code-in);
  padding: 0.1em 0.34em;
  border-radius: 2px;
  word-break: break-all;
}
.v-quiet .p-cmt-body pre {
  margin: 16px 0 0;
  padding: 16px 18px;
  background: var(--q-code-bg);
  border: 1px solid var(--q-code-edge);
  overflow-x: auto;
}
.v-quiet .p-cmt-body pre code {
  background: none;
  padding: 0;
  font-size: 12.5px;
  line-height: 22px;
  white-space: pre;
  word-break: normal;
}
.v-quiet .p-cmt-body blockquote {
  margin: 16px 0 0;
  padding-left: 16px;
  border-left: 1px solid var(--q-rule);
  color: var(--q-soft);
}

/* --- 댓글 쓰기 (#53) ------------------------------------------------
 * 「침묵」에 입력 요소가 처음 들어온다. 규칙은 그대로다 — 장식 0, 위계는 여백과
 * 타이포로만. 테두리는 한 겹의 실선이고 채움색이 없다.
 *
 * 🔴 폼도 본문과 같은 672px 열에 선다. 더 넓으면 읽던 리듬이 거기서 끊긴다.
 * ------------------------------------------------------------------ */
.v-quiet .p-cmt-form,
.v-quiet .p-cmt-signin,
.v-quiet .p-cmt-note { max-width: 672px; }

.v-quiet .p-cmt-form { margin-top: 32px; }
.v-quiet .p-cmt-me {
  margin: 0 0 8px;
  font-size: 12px;
  line-height: 18px;
  letter-spacing: 0.02em;
  color: var(--q-faint);
}
.v-quiet .p-cmt-me span { color: var(--q-soft); }

.v-quiet .p-comments textarea {
  display: block;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--q-rule);
  border-radius: 2px;
  background: transparent;
  color: var(--q-ink);
  font-family: var(--q-sans);
  font-size: 14px;
  line-height: 24px;
  resize: vertical;
}
.v-quiet .p-comments textarea:focus {
  outline: none;
  border-color: var(--q-ink);
}
.v-quiet .p-comments textarea::placeholder { color: var(--q-faint); }

.v-quiet .p-comments button {
  margin-top: 10px;
  padding: 8px 18px;
  border: 1px solid var(--q-rule);
  border-radius: 2px;
  background: transparent;
  color: var(--q-soft);
  font: inherit;
  font-size: 13px;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}
.v-quiet .p-comments button:hover { color: var(--q-ink); border-color: var(--q-ink); }

/* 답글 폼. JS 없이 접힌다 — 댓글 10개에 폼 10개가 펼쳐져 있으면 못 읽는다 */
.v-quiet .p-cmt-reply { margin: 10px 0 0 var(--q-cmt-indent, 0); }
.v-quiet .p-cmt-reply summary {
  display: inline-block;
  font-size: 12px;
  line-height: 18px;
  letter-spacing: 0.02em;
  color: var(--q-faint);
  cursor: pointer;
  list-style: none;
}
.v-quiet .p-cmt-reply summary::-webkit-details-marker { display: none; }
.v-quiet .p-cmt-reply summary:hover { color: var(--q-soft); }
.v-quiet .p-cmt-reply[open] summary { margin-bottom: 8px; }

.v-quiet .p-cmt-signin,
.v-quiet .p-cmt-note {
  margin-top: 32px;
  font-size: 13px;
  line-height: 22px;
  color: var(--q-soft);
}
.v-quiet .p-cmt-signin a {
  color: var(--q-ink);
  border-bottom: 1px solid var(--q-rule);
}
.v-quiet .p-cmt-signin a:hover { border-bottom-color: var(--q-ink); }

/* 🔴 거절은 색만으로 말하지 않는다 — 문장 자체가 이유를 담는다.
   「침묵」에 빨강은 없으므로 잉크색 + 좌측 표식으로 무게를 준다 */
.v-quiet .p-cmt-note {
  margin-top: 16px;
  padding-left: 12px;
  border-left: 2px solid var(--q-rule);
  color: var(--q-soft);
}
.v-quiet .p-cmt-note.is-bad { border-left-color: var(--q-ink); color: var(--q-ink); }

/* 본인 댓글의 고치기·지우기 (F-C3 · #55).
   평소에는 거의 안 보인다 — 남의 댓글을 읽는 동안 눈에 걸릴 이유가 없다.
   내 댓글 위에 마우스를 올리거나 키보드 초점이 오면 잉크색으로 올라온다 */
.v-quiet .p-cmt-own {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-top: 10px;
}
.v-quiet .p-cmt-own form { margin: 0; }
/* 🔴 `.p-comments button` 이 테두리와 패딩을 준다. 그 셀렉터가 이것보다 특이도가
   높아서(클래스 둘 + 타입 하나) 「지우기」만 박스로 그려졌다 — 「고치기」는 summary 라
   안 걸렸고, 그래서 둘이 다르게 보였다. 같은 자리에 두 규칙을 겹치지 않도록
   여기서도 `.p-comments` 를 붙여 이긴다. */
.v-quiet .p-comments .p-cmt-edit summary,
.v-quiet .p-comments .p-cmt-drop {
  margin-top: 0;
  font-size: 12px;
  line-height: 18px;
  letter-spacing: 0.02em;
  color: var(--q-faint);
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  list-style: none;
  transition: color 200ms ease;
}
.v-quiet .p-comments .p-cmt-edit summary::-webkit-details-marker { display: none; }
.v-quiet .p-cmt:hover .p-comments .p-cmt-edit summary,
.v-quiet .p-comments .p-cmt:hover .p-cmt-edit summary,
.v-quiet .p-comments .p-cmt:hover .p-cmt-drop,
.v-quiet .p-comments .p-cmt-own :focus-visible { color: var(--q-soft); }
.v-quiet .p-comments .p-cmt-edit summary:hover,
.v-quiet .p-comments .p-cmt-drop:hover { color: var(--q-ink); }
.v-quiet .p-cmt-edit[open] { flex: 1; }
.v-quiet .p-cmt-edit[open] summary { margin-bottom: 8px; }

/* 고쳤다는 사실은 감출 것이 아니다. 이력 자체는 공개하지 않는다(오너 결정) —
   화면은 이 표시 하나이고, 기록은 comment_revision 에 남는다.

   🔴 날짜와 같은 타이포다. 시각 정보의 일부로 읽혀야 하므로 크기·색을 맞추고
      앞에 여백만 준다 — 다르게 그리면 그것대로 눈에 걸린다 */
.v-quiet .p-cmt-edited {
  margin-left: 6px;
  font-family: var(--q-mono);
  font-size: 11.5px;
  line-height: 18px;
  letter-spacing: 0.06em;
  color: var(--q-faint);
}

/* F-C4 — 이관된 giscus 댓글도 소유자가 같으면 여기 걸린다 */
.v-quiet .p-cmt-mine {
  font-family: var(--q-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--q-faint);
  border: 1px solid var(--q-rule);
  border-radius: 2px;
  padding: 1px 5px;
}

.v-quiet .p-related { margin-top: 100px; }
.v-quiet .p-related ul {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
  max-width: 672px;
}
.v-quiet .p-related li { margin-top: 14px; }
.v-quiet .p-related li:first-child { margin-top: 0; }
.v-quiet .p-related a {
  display: flex;
  align-items: baseline;
  gap: 18px;
  transition: color 200ms ease;
}
.v-quiet .p-related time {
  flex: 0 0 auto;
  font-family: var(--q-mono);
  font-size: 10.5px;
  line-height: 24px;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .p-related span {
  /* 🔴 flex 항목의 기본 `min-width: auto` 는 **내용보다 작아지지 않는다.**
     그래서 긴 제목이 상자를 뚫고 페이지를 가로로 밀었다 — 실측(2026-08-25 ·
     유효 폭 156px): 「오브젝트; 동적 메서드 탐색과 다형성」이 109..169.
     `width` 를 안 줘도 이 한 줄이 있어야 줄바꿈이 일어난다. */
  min-width: 0;
  font-size: 14px;
  line-height: 24px;
  letter-spacing: -0.012em;
  color: var(--q-mid);
  transition: color 200ms ease;
}
.v-quiet .p-related a:hover span { color: var(--q-ink); }

/* --- 이전·다음 글 (#64) ---------------------------------------------
 *
 * 오너 결정(2026-08-07) — "이전/다음 : 넣기".
 *
 * ## 관련 글과 왜 모양이 다른가
 *
 * 관련 글은 **목록**이다 — 날짜와 제목이 줄줄이 선다. 이건 **두 방향**이다.
 * 같은 모양으로 그리면 「관련 5편」처럼 보이고, 앞뒤라는 뜻이 사라진다.
 *
 * 그래서 방향 라벨을 제목 위에 얹고 둘을 나란히 둔다. 화살표 문자는 쓰지 않는다 —
 * 「침묵」에 장식 문자가 없고, `이전`·`다음` 이라는 낱말이 이미 방향이다.
 *
 * ## 🔴 한쪽만 있어도 자리가 안 무너진다
 *
 * 첫 글에는 이전이, 마지막 글에는 다음이 없다. `grid` 로 두 칸을 고정하면 없는 쪽에
 * 빈 칸이 남고, 그 빈 칸이 무엇인지 아무도 모른다. `flex` + `margin-left:auto` 로
 * **다음 글만 오른쪽에 붙인다** — 혼자 있어도 자기 자리에 선다.
 * ------------------------------------------------------------------ */
.v-quiet .p-neighbours { margin-top: 72px; }
.v-quiet .p-nb-list {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 32px;
  margin-top: 22px;
  max-width: 672px;
}
.v-quiet .p-nb {
  display: block;
  max-width: 320px;
  /* 🔴 `.p-nb-list` 가 flex 라 항목의 기본 `min-width: auto` 가 내용보다 작아지는 것을
     막는다. 그러면 「오케스트레이터는」 같은 긴 낱말 하나가 페이지를 가로로 민다 —
     `.p-related span` 과 같은 종류의 버그다 (2026-08-31 실측 · 130px 에서 +22px). */
  min-width: 0;
  transition: color 200ms ease;
}
/* 🔴 다음 글은 오른쪽 끝에 붙는다. 이전이 없어도 이 규칙이 자리를 지킨다 */
.v-quiet .p-nb.is-next { margin-left: auto; text-align: right; }
.v-quiet .p-nb-dir {
  display: block;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 18px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: var(--q-faint);
}
.v-quiet .p-nb-title {
  display: block;
  margin-top: 4px;
  font-size: 14px;
  line-height: 24px;
  letter-spacing: -0.012em;
  color: var(--q-mid);
  transition: color 200ms ease;
}
.v-quiet .p-nb:hover .p-nb-title { color: var(--q-ink); }

/* 좁은 화면에서는 두 칸이 320px 씩 못 서고 겹쳐 보인다. 한 줄에 하나씩 눕히고
   오른쪽 정렬도 푼다 — 화면 폭이 좁으면 오른쪽 끝이 어디인지가 안 읽힌다 */
@media (max-width: 620px) {
  .v-quiet .p-nb { max-width: none; }
  .v-quiet .p-nb.is-next { margin-left: 0; text-align: left; }
}

/* --- 댓글 (마일스톤 7 에서 채운다. 자리와 값만 잡아 둔다) ---------- */
.v-quiet .p-talk { margin-top: 104px; }
.v-quiet .p-cmts {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  max-width: 672px;
}
.v-quiet .p-cmt { margin-top: 34px; }
.v-quiet .p-cmt:first-child { margin-top: 0; }
.v-quiet .p-cmt-meta {
  display: flex;
  align-items: baseline;
  gap: 12px;
}
.v-quiet .p-cmt-who {
  font-size: 13px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: -0.01em;
  color: var(--q-ink);
}
.v-quiet .p-cmt-at {
  font-family: var(--q-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--q-faint);
}
.v-quiet .p-cmt-body {
  margin: 10px 0 0;
  font-size: 14.5px;
  line-height: 28px;
  letter-spacing: -0.01em;
  color: var(--q-mid);
}
.v-quiet .p-cmt-re {
  list-style: none;
  margin: 26px 0 0;
  padding: 0 0 0 26px;
  border-left: 1px solid var(--q-rule);
}
.v-quiet .p-login {
  margin-top: 52px;
  padding-top: 34px;
  border-top: 1px solid var(--q-rule);
  max-width: 672px;
}
.v-quiet .p-login p {
  margin: 0 0 18px;
  font-size: 13.5px;
  line-height: 24px;
  letter-spacing: -0.008em;
  color: var(--q-mid);
}
.v-quiet .p-gh {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  border: 1px solid var(--q-rule-strong);
  background: var(--q-btn-bg);
  padding: 11px 18px;
  font-family: var(--q-sans);
  font-size: 13px;
  line-height: 18px;
  letter-spacing: -0.008em;
  color: var(--q-ink);
  cursor: pointer;
  transition: border-color 200ms ease;
}
.v-quiet .p-gh:hover { border-color: var(--q-ink); }
.v-quiet .p-gh:focus-visible { outline: 1px solid var(--q-ink); outline-offset: 2px; }
.v-quiet .p-gh svg {
  width: 15px;
  height: 15px;
  fill: currentColor;
  display: block;
}

/* --- 이전 / 다음 --------------------------------------------------- */
.v-quiet .p-adjacent {
  margin-top: 104px;
  border-top: 1px solid var(--q-rule);
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.v-quiet .p-adj {
  display: block;
  padding: 32px 0 0;
}
.v-quiet .p-adj-prev { padding-right: 32px; }
.v-quiet .p-adj-next { padding-left: 32px; text-align: right; }
.v-quiet .p-adj-k {
  display: block;
  font-family: var(--q-mono);
  font-size: 10px;
  line-height: 14px;
  letter-spacing: 0.2em;
  color: var(--q-faint);
  margin-bottom: 13px;
}
.v-quiet .p-adj-t {
  display: block;
  font-size: 15px;
  line-height: 26px;
  letter-spacing: -0.016em;
  color: var(--q-mid);
  max-width: 300px;
  transition: color 200ms ease;
}
.v-quiet .p-adj-next .p-adj-t { margin-left: auto; }
.v-quiet .p-adj:hover .p-adj-t { color: var(--q-ink); }

/* =====================================================================
 * 반응형 — 04 §6 은 820px 단일이라고 적었지만 실제로 검증된 것은
 * PoC 의 3단(1180 / 940 / 720)이다. 940px 에서 레일을 본문 아래로
 * 내리지 않으면 820~940 구간에서 7,000자 본문이 116px 트랙에 눌린다.
 * ===================================================================== */
@media (max-width: 1180px) {
  .v-quiet { padding: 104px 40px 144px; }
  .v-quiet .q-inner { width: 880px; }
}

@media (max-width: 940px) {
  .v-quiet { --q-cols: 92px 40px minmax(0, 1fr); }
  .v-quiet .q-inner { width: 100%; }
  /* 116px 트랙에 7,000자 본문을 눌러 담지 않는다 — 그리드를 세로 흐름으로 푼다.
     🔴 `order` 로 뒤집지 않는다. 시각 순서만 바뀌고 **탭 순서는 DOM 순서**라
        시각 순서와 포커스 순서가 어긋난다(WCAG 2.4.3 Focus Order). 마크업이
        이미 레일 → 본문 순서이므로 세로로 풀면 그대로 읽는 순서가 된다.
        분류 링크 27개가 본문을 밀어내는 문제는 `quiet.js` 가 `details` 를
        접어서 한 줄로 만든다 — 순서를 뒤집어서 풀 문제가 아니다 */
  .v-quiet .p-doc,
  .v-quiet .q-doc {
    display: flex;
    flex-direction: column;
  }
  .v-quiet .p-rail {
    position: static;
    max-height: none;
    overflow: visible;
    text-align: left;
    /* 🔴 세로 flex 에서 `align-self` 는 **가로축**이다. 위에서 상속되는 `start` 를
          그대로 두면 레일이 내용 폭으로 쪼그라든다 — 실측 900px 폭에서 389/820
          (47%), 500px 폭에서 251/452(56%). 아래 구분선도 같이 반쪽이 된다.
          예전 `lnbBlock` 이 전폭 `.q-row` 였던 것과 같은 폭으로 되돌린다 */
    align-self: stretch;
    padding-bottom: 26px;
    margin-bottom: 56px;
    border-bottom: 1px solid var(--q-rule);
  }
  /* 좁은 화면에서 레일은 **접힌 한 줄**이다(04 §6 "LNB는 접힘(햄버거)").
     넓은 화면의 104px 리듬을 그대로 쓰면 그 한 줄 때문에 본문이 그만큼 더 밀린다 —
     헤더와 구분될 만큼만 띄운다 */
  .v-quiet .q-doc { margin-top: 64px; }
  /* 접혀 있으면 라벨 아래 26px 은 아무것도 없는 빈칸이다 */
  .v-quiet .p-rail-cats:not([open]) > .p-rail-label { margin-bottom: 0; }
  /* 레일이 본문 아래로 내려가면 목차로 바뀔 이유가 없다 — 분류만 남긴다.
     🔴 `[hidden]` 짝이 있어야 한다. 아래 `.p-rail-pane[hidden]` 이 `display: block`
        으로 덮고 있어서, 이 줄만으로는 스크립트가 목차를 켠 순간 분류와 목차가
        **둘 다** 보인다 */
  .v-quiet .p-rail-toc,
  .v-quiet .p-rail-toc[hidden] { display: none; }

  /* 🔴 레일이 본문 **위**에 눕는 폭이다. 레일 안에 둔 `위로` 는 화면 맨 처음에
        박혀 있어 정작 필요한 순간에 화면 밖이다. 화면 오른쪽 아래로 고정한다.
        여기서도 원형 버튼을 만들지 않는다 — 같은 글자, 위치만 바뀐다.
        바탕을 깔지 않으면 본문 글자 위에 겹쳐 읽히지 않으므로 지면색을 깐다. */
  .v-quiet .p-totop {
    position: fixed;
    right: 20px;
    bottom: 18px;
    margin-top: 0;
    z-index: 20;
    padding: 10px 12px;
    background: var(--q-bg);
    color: var(--q-soft);
  }
  .v-quiet .p-rail-cats[hidden] {
    display: block;
    opacity: 1;
    visibility: visible;
    position: static;
    pointer-events: auto;
  }
  .v-quiet .p-nav {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 24px;
    row-gap: 32px;
  }
  .v-quiet .p-branch { margin-bottom: 0; }
}

@media (max-width: 720px) {
  .v-quiet { --q-cols: minmax(0, 1fr); padding: 72px 24px 112px; }
  /* 🔴 --q-cols 가 1트랙이 되므로 grid-column:3 을 전부 되돌린다.
     짝을 빠뜨리면 모바일에서 요소가 사라진 것처럼 보인다 */
  .v-quiet .q-main,
  .v-quiet .q-body,
  .v-quiet .q-docmain,
  .v-quiet .p-main { grid-column: 1; }
  .v-quiet .q-label,
  .v-quiet .q-date,
  .v-quiet .q-cats { grid-column: 1; text-align: left; text-indent: 0; }
  /* ## 좁은 화면에서는 헤더가 **로고와 햄버거 둘**이다 (2026-08-31 · 오너 지시)
   *
   * ### 무엇을 되돌렸나
   *
   * 바로 앞 판은 넷을 두 줄로 폈다 — 1줄 `ABOUT [로고] ◐`, 2줄 `⌕ ──── 검색`.
   * 폭이 좁을수록 그 두 줄이 헤더의 높이를 키워서, 본문 첫 글자에 닿기 전에
   * 컨트롤 넷을 지나야 했다. 셋을 서랍에 넣고 띠를 한 줄로 되돌린다.
   *
   *   닫힘   [로고] ....................... ☰
   *   열림   [로고] ............ ✕  │ ABOUT
   *                                │ ◐ 화면 테마
   *                                │ ⌕ ──────── 검색
   *
   * ### 세 가지가 이 구조를 정했다
   *
   * 🔴 **항목을 복제하지 않는다.** 넓은 화면용 한 벌 · 좁은 화면용 한 벌로 두면
   *    `id="q-theme"` 가 둘이 되고 검색 input 도 둘이 된다 — 폼 제출과 스크립트가
   *    어느 쪽을 잡을지 알 수 없어진다. 같은 노드가 CSS 로만 자리를 옮긴다.
   *
   * 🔴 **스크립트가 없어도 열린다.** `details` 를 쓰는 이유가 그것이다. 테마 토글은
   *    JS 가 없으면 눌러도 아무 일이 없어서 `hidden` 으로 빠지지만, ABOUT 과 검색은
   *    그 자체로 동작한다 — `button` + JS 로 만들었다면 스크립트가 죽는 순간
   *    좁은 화면에서 그 둘에 닿을 방법이 아예 없어진다.
   *
   * 🔴 **닫는 것도 스크립트가 없어도 된다.** 햄버거를 판보다 위(z 54 > 52)에 띄워
   *    열린 상태에서도 자리에 남긴다. 다시 누르면 닫힌다. `quiet.js` 의 ESC ·
   *    바깥 누르기 · 폭 복귀는 그 위에 얹는 편의지 여는 수단이 아니다.
   *
   * ### 층
   *
   *   54 햄버거   ·   52 판   ·   (-1) 지면색 막   ·   20 위로
   *
   * 라이트박스(60)와 건너뛰기 링크(80) 아래다. 서랍이 열린 채로 본문 이미지를
   * 누를 일은 없고, 건너뛰기는 언제나 맨 위여야 한다.
   */
  .v-quiet .q-head { gap: 24px; }
  .v-quiet .q-head > a { min-width: 0; max-width: 100%; }
  /* 🔴 로고가 `width: 137px` 고정이라 혼자서 화면을 넘겼다(실측 156px 에서
        24..161). `contain` 이라 상자를 줄여도 비율은 지켜진다 — 찌그러지지 않고
        가로에 맞춰 작아진다. */
  .v-quiet .site-logo { max-width: 100%; }

  /* --- 햄버거 -------------------------------------------------------- */
  .v-quiet .q-menu {
    display: block;
    /* 오른쪽 끝. `.q-head` 는 `flex-start` 라 이 한 줄이 위치를 정한다 */
    margin-left: auto;
    position: relative;
    z-index: 54;
  }
  /* 기본 삼각형 마커를 지운다. 🔴 두 줄이 다 필요하다 — 사파리는 아직
     `::-webkit-details-marker` 쪽만 보고, 그쪽만 쓰면 파이어폭스에 삼각형이 남는다 */
  .v-quiet .q-burger { list-style: none; }
  .v-quiet .q-burger::-webkit-details-marker { display: none; }
  .v-quiet .q-burger {
    display: block;
    cursor: pointer;
    color: var(--q-mid);
    /* 아이콘은 17px 이지만 누르는 자리는 39px 이다(WCAG 2.5.8 최소 24px).
       음수 마진으로 상자만 넓히고 **띠의 높이는 안 건드린다** — 안 그러면
       헤더가 아이콘 하나 때문에 22px 두꺼워진다 */
    padding: 11px;
    margin: -11px -11px -11px 0;
    transition: color 200ms ease;
  }
  .v-quiet .q-burger:hover { color: var(--q-ink); }
  .v-quiet .q-burger:focus-visible {
    outline: 1px solid var(--q-line-2);
    outline-offset: 1px;
  }
  .v-quiet .q-burger svg { display: block; }
  /* 상태에 따라 도형을 갈아 끼운다 — `.q-theme` 이 쓰는 어휘와 같다 */
  .v-quiet .q-burger .q-burger-x { display: none; }
  .v-quiet .q-menu[open] .q-burger .q-burger-bars { display: none; }
  .v-quiet .q-menu[open] .q-burger .q-burger-x { display: block; }

  /* --- 서랍 ---------------------------------------------------------- */
  .v-quiet .q-drawer {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 28px;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 52;
    width: min(292px, 78vw);
    box-sizing: border-box;
    /* 위를 76px 비운다 — 열려 있는 동안 햄버거가 판 위에 그대로 보이는 자리다 */
    padding: 76px 24px 40px;
    background: var(--q-bg);
    /* 🔴 `--q-rule`(#ededed) 로는 **판이 안 보인다.** 막이 지면색이라 판과 배경이
       같은 색이 되고, 남는 표식이 이 선 하나뿐인데 그게 흰 바탕에 묻는다
       (실측 2026-09-01 · 라이트에서 경계가 완전히 사라졌다).
       🔴 `--q-line-2` 도 부족했다. 보이기는 하는데 라이트에서 **2.78:1** 이라
       WCAG 1.4.11(3:1)에 걸린다. 이 블로그에는 이미 같은 조항의 미해결 항목이
       하나 있다(테마 아이콘) — 두 번째를 만들지 않는다.
       `--q-mid` 는 새 색이 아니다. 햄버거 아이콘과 「위로」가 쓰는 바로 그 값이고,
       라이트 4.74:1 · 다크 6.03:1 로 여유 있게 넘는다. */
    border-left: 1px solid var(--q-mid);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(100%);
    /* 🔴 `transform` 만으로는 닫힌 판이 화면 밖에 **남아 있다** — 초점이 그리로
       들어가고 스크린리더도 읽는다. `visibility` 로 트리에서 뺀다. 닫힐 때만
       260ms 늦춰서 미끄러지는 동안은 보이게 둔다 */
    visibility: hidden;
    /* 🔴 전이는 여기 없다. 아래 `.is-ready` 절을 보라 (#121) */
  }
  .v-quiet .q-menu[open] ~ .q-drawer {
    transform: none;
    visibility: visible;
  }

  /* ── 🔴 전이는 **첫 페인트 뒤에만** 붙인다 (#121) ──────────────────
   *
   * 예전에는 위의 **닫힌 상태**에 `transition` 이 달려 있었다. 표준대로면 첫 스타일
   * 계산에는 「바뀐 값」이 없으니 전이가 안 돌아야 한다. 그런데 **WebKit 은 그 계산을
   * 변화로 취급하는 버릇**이 있어서, 기본값(`transform: none` · 보임)에서 닫힌
   * 상태로 260ms 동안 미끄러뜨린다 — 누르지도 않은 판이 **오른쪽으로 사라지는**
   * 장면이 페이지마다 한 번씩 보인다(오너 신고, iOS 사파리).
   *
   * 🔴 Chromium 에서는 재현되지 않는다. 넓은 화면에서 서랍은 `display: contents` 라
   *    박스가 없고, 좁아질 때 박스가 새로 생긴다 — 새 박스에는 전이가 안 걸린다.
   *    ego-browser 로 세 번(모바일 폭 진입 · 폭 넘기 · 스크립트 개입) 재서 전부
   *    `transitionrun` **0건**이었다. 엔진 차이라 기기 없이는 안 보인다.
   *
   * 전이를 닫힌 상태에서 떼면 진입 순간에 **애니메이션할 거리가 아예 없다.**
   * `is-ready` 는 `quiet.js` 가 프레임 두 번 뒤에 붙인다.
   *
   * 🔴 대가 — JS 가 죽으면 애니메이션이 없다. **서랍은 그대로 열리고 닫힌다**
   *    (`<details>` 가 하는 일이다). 기능이 아니라 장식만 JS 에 걸린다.
   * ---------------------------------------------------------------- */
  .v-quiet.is-ready .q-drawer {
    transition: transform 260ms ease, visibility 0s linear 260ms;
  }
  .v-quiet.is-ready .q-menu[open] ~ .q-drawer {
    transition: transform 260ms ease, visibility 0s;
  }
  /* 판 왼쪽을 덮는 막. 🔴 반투명 **검은** 막은 이 시스템의 어휘가 아니다 —
     라이트박스(F-V3)와 같이 **지면색**을 거의 불투명하게 덮는다.
     `z-index: -1` 은 판이 만든 쌓임 맥락 안이라 판의 배경 뒤로만 간다 */
  .v-quiet .q-drawer::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background: var(--q-bg);
    opacity: 0;
    /* 판과 같은 이유로 전이가 여기 없다 (#121) — 막도 진입 때 함께 흐려졌다 */
  }
  .v-quiet.is-ready .q-drawer::before { transition: opacity 260ms ease; }
  .v-quiet .q-menu[open] ~ .q-drawer::before { opacity: 0.92; }

  /* 판 안에서는 셋이 세로로 쌓인다. 헤더 띠의 `flex-end` 바닥맞춤과
     `margin-left: auto` 는 가로로 늘어설 때의 규칙이라 여기서 되돌린다 */
  .v-quiet .q-drawer .q-head-right {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 28px;
    margin-left: 0;
  }
  /* 🔴 이 줄이 없으면 스크립트가 없을 때 테마 버튼이 판에 나타난다. 바로 위
     `.q-drawer .q-head-right` 와 `.q-theme[hidden]` 이 명시도 (0,3,0) 로 같아서,
     뒤에 오는 쪽이 이긴다 — 여기서 다시 못 박는다 */
  .v-quiet .q-drawer .q-theme[hidden] { display: none; }
  /* 띠에서는 10px 이 「조용한 표지」지만 판에서는 항목이다. 한 칸 키우고
     누르는 자리를 세로로 벌린다 */
  .v-quiet .q-drawer .q-gnb {
    font-size: 11px;
    line-height: 20px;
    padding-bottom: 0;
    /* 🔴 넓은 화면에서 가로 한 줄이 되었으므로(#88) 판에서는 **되돌려야** 한다.
       안 되돌리면 항목이 292px 짜리 서랍 안에서도 옆으로 늘어서서 넘친다.
       명시도는 (0,3,0) 대 (0,2,0) 이라 이쪽이 이긴다 — 미디어 쿼리는 명시도를
       올려 주지 않으므로 선택자 자체로 이겨야 한다 */
    flex-direction: column;
    gap: 0;
  }
  .v-quiet .q-drawer .q-gnb a { padding: 6px 0; }
  .v-quiet .q-drawer .q-theme {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 0;
  }
  .v-quiet .q-drawer .q-mlabel {
    display: block;
    font-family: var(--q-mono);
    font-size: 11px;
    line-height: 20px;
    letter-spacing: 0.2em;
    text-indent: 0.2em;
    color: var(--q-faint);
  }
  .v-quiet .q-drawer .q-theme:hover .q-mlabel { color: var(--q-ink); }
  .v-quiet .q-drawer .q-searchbox { width: 100%; }
  /* 🔴 `text-align: right` 는 검색이 띠의 **오른쪽 끝에 붙어 있을 때**의 어휘다.
        왼쪽 맞춤 판 안에서 그대로 두면 글자가 혼자 반대쪽에서 자란다 */
  .v-quiet .q-drawer .q-search {
    width: auto;
    max-width: 100%;
    flex: 1 1 auto;
    min-width: 0;
    text-align: left;
  }

  /* 1트랙에서는 날짜 · 분류가 제목 위에 한 줄로 눕는다 */
  .v-quiet .q-post .q-date { line-height: 20px; }
  .v-quiet .q-post .q-cats { margin: 2px 0 8px; }
  .v-quiet .q-cats span { display: inline; }
  .v-quiet .q-cats span + span::before { content: " · "; color: var(--q-ghost); }
  /* 🔴 두 마커가 **짝**이다. 한쪽만 고치면 다른 쪽이 어긋난다.
     불릿은 줄 높이의 한가운데다 — 32px 줄에서는 15px 이 아니라 14px.
     번호는 `top: 0` 에서 자기 `line-height` 로 첫 줄에 맞추므로 li 와 같은 값을
     써야 한다. 34px 을 그대로 두면 li 의 32px 과 2px 어긋난다(실측 확인) */
  .v-quiet .post-body ul > li::before { top: 13px; }
  .v-quiet .post-body ol > li::before { line-height: 30px; }
  .v-quiet .q-heading .q-main { flex-wrap: wrap; }

  .v-quiet .p-crumb { margin-top: 72px; }
  .v-quiet .p-head { margin-top: 22px; }
  .v-quiet .p-head .q-date {
    padding-top: 0;
    line-height: 18px;
    margin-bottom: 12px;
  }
  .v-quiet .p-title { font-size: 25px; line-height: 40px; }
  .v-quiet .p-toc { margin-top: 64px; }
  .v-quiet .p-toc .q-label { margin-bottom: 16px; }
  .v-quiet .p-doc { margin-top: 64px; }
  .v-quiet .p-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .v-quiet .post-body p,
  /* 🔴 문단도 같이 줄인다. 예전에는 `li` 만 줄어서 좁은 화면에서 목록이
        문단보다 작았다 — 같은 지면인데 두 크기가 섞여 있었다 */
  .v-quiet .post-body p { font-size: 15.5px; line-height: 30px; }
  .v-quiet .post-body li { font-size: 15.5px; line-height: 30px; }
  .v-quiet .post-body h2 { margin-top: 80px; font-size: 20px; line-height: 32px; }
  .v-quiet .post-body h3 { margin-top: 52px; }

  /* 코드는 화면 끝까지 — 가로 스크롤 양을 줄이는 게 곧 가독성.
     🔴 이 -24px 은 루트 padding 24px 과 하드 커플링이다. 한쪽만 바꾸면
        코드블록이 화면 밖으로 나가거나 어정쩡하게 뜬다 */
  .v-quiet .codeblock {
    margin-left: -24px;
    margin-right: -24px;
    max-width: calc(100% + 48px);
    border-left: 0;
    border-right: 0;
  }
  /* 🔴 넓히기는 이 폭에서 **동작하지 않는다** (#46, 오너 지적 2026-08-07).
   *
   *    여기서 코드는 이미 화면 끝까지 차 있다(좌우 -24px 풀블리드). 넓힐 여지가
   *    없는데 `.is-wide` 의 `max-width: 100%` 가 위 `calc(100% + 48px)` 를 덮으면
   *    **오히려 48px 좁아지고** 왼쪽 음수 마진만 남아 블록이 어긋난다.
   *
   *    실측(iPhone 14 Pro · 393px): 기본 폭 393 → `is-wide` 적용 시 345.
   *
   *    `quiet.js` 도 이 폭에서는 표시를 붙이지 않는다. 여기 규칙은 그 짝이다 —
   *    스크립트가 없거나 늦게 와도 폭이 어긋나지 않는다. */
  .v-quiet .codeblock.is-wide,
  .v-quiet .codeblock.is-widenable:has(.codeblock-head:hover),
  .v-quiet .codeblock.is-widenable:focus-within {
    max-width: calc(100% + 48px);
  }
  .v-quiet .codeblock-lang { cursor: default; }

  .v-quiet .codeblock pre { padding: 18px 16px 20px; }
  .v-quiet .codeblock code { font-size: 12.5px; line-height: 22px; }
  .v-quiet .ad-slot { min-height: 260px; }
  .v-quiet .q-lightbox { padding: 56px 16px; }

  .v-quiet .p-adjacent { grid-template-columns: minmax(0, 1fr); }
  .v-quiet .p-adj-prev { padding-right: 0; }
  .v-quiet .p-adj-next {
    padding-left: 0;
    text-align: left;
    border-top: 1px solid var(--q-rule);
  }
  .v-quiet .p-adj-next .p-adj-t { margin-left: 0; }
  .v-quiet .p-adj-t { max-width: none; }
}

/* 터치 기기에서 hover 로만 보이는 UI 를 상시 노출한다.
   🔴 발췌는 여기 없다. 예전에는 있었고 그래서 **폰에서는 보이고 데스크톱에서는
      안 보이는** 비대칭이 생겼다. 지금은 어느 기기에서도 상시 노출이다(04 §4.1) */
@media (hover: none) {
  .v-quiet .btn-copy { opacity: 1; }
  .v-quiet .q-theme { color: var(--q-mid); }
  /* 🔴 발췌는 hover 로만 나온다(#45). 마우스가 없는 기기에는 **hover 라는 사건이
        없으므로** 여기서 펴 둔다. 이것이 없으면 폰에서 발췌를 영영 못 읽는다 —
        예전에 ② 로 바꾼 이유가 정확히 그것이었다. */
  .v-quiet .q-excerpt {
    margin-top: 12px;
    max-height: 78px;
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .v-quiet * { transition-duration: 1ms !important; }
}

/* --- 아주 좁은 화면 · 확대(zoom) 구간 --------------------------------
 *
 * 🔴 720px 아래로는 **더 줄이는 구간이 없었다.** 그래서 확대를 걸어 유효 폭이
 *    168px 이 되어도 제목이 25px 그대로 남고, 「하네스 엔지니어링 with 클로드
 *    코드 - 책 소개」가 **다섯 줄**이 된다(2026-08-31 실측 · 오너 신고).
 *
 *    폭이 반으로 줄면 글자도 같이 줄어야 한다. 안 그러면 한 줄에 두세 어절만
 *    들어가고, 그건 읽는 것이 아니라 세로로 흐르는 낱말 목록이 된다.
 *
 * 🔴 경계를 **320px 아래**에 둔다. 360·375·390 은 실제 기기 폭이라 그대로 두어야
 *    한다 — 확대 때문에 보통 폰의 모양을 바꾸면 대가를 엉뚱한 사람이 치른다.
 * ------------------------------------------------------------------ */
@media (max-width: 320px) {
  .v-quiet .p-title { font-size: 21px; line-height: 32px; }
  .v-quiet .q-title { font-size: 17px; line-height: 26px; }
  .v-quiet .post-body h2 { font-size: 18px; line-height: 28px; }
}

@media (max-width: 240px) {
  /* 🔴 여백을 줄여 본문 폭을 되찾는다. 칸이 120px 일 때 좌우 24px 은 전체의 40% 다 */
  .v-quiet { padding: 56px 16px 88px; }
  .v-quiet .p-title { font-size: 18px; line-height: 28px; }
  .v-quiet .q-title { font-size: 16px; line-height: 24px; }
  .v-quiet .post-body h2 { font-size: 17px; line-height: 26px; }
  .v-quiet .post-body p,
  .v-quiet .post-body li { font-size: 15px; line-height: 28px; }
  .v-quiet .post-body ol > li::before { line-height: 28px; }
  .v-quiet .post-body ul > li::before { top: 12px; }
  /* 🔴 코드블록은 본문 여백만큼 **밖으로 삐져나온다**(≤720px 에서 -24px).
        여백을 16px 로 줄였으면 이 값도 같이 줄여야 한다 — 안 그러면 8px 씩
        넘쳐서 페이지가 가로로 밀린다. 실측으로 잡았다(2026-08-31). */
  .v-quiet .codeblock {
    margin-left: -16px;
    margin-right: -16px;
    max-width: calc(100% + 32px);
  }
  .v-quiet .codeblock.is-widenable:focus-within { max-width: calc(100% + 32px); }
}

/* --- 시리즈 블록 (#112) ---------------------------------------------
 *
 * 시안 A4 확정. `/tmp/static112/series-a4.html` + 그 css 에서 **A4 가 켜는 선언만**
 * 추린 것이다 — A1·A2·A3·A5 는 검토용이라 싣지 않는다. 안 쓰는 바리에이션 넷을 남겨
 * 두면 다음 사람이 `is-a2` 를 마크업에 써 보고, 그때부터 이 블록에 모양이 둘이 된다.
 *
 * 🔴 `--q-line` 은 이 저장소에 **없는 이름**이다(시안 메모의 경고). 선은 `--q-rule`,
 *    면은 `--q-code-bg`(코드블록)다. 여기 쓰는 토큰 여덟은 전부 실재한다.
 *
 * 🔴 여백은 이 페이지의 계단을 쓴다 — `.p-toc` 88 · `.p-tags`/`.p-related`/
 *    `.p-comments` 100 · `.p-crumb` 104. 24px 은 `.p-chips` 의 「같은 묶음 안」
 *    값이라 여기 쓰면 블록이 분류 칩에 붙는다.
 *
 * 🔴 전환은 `prefers-reduced-motion` 아래에서 이미 1ms 로 눌린다(위 전역 규칙).
 *    여기서 또 처리하지 않는다.
 * ------------------------------------------------------------------ */
.v-quiet .p-series { margin-top: 88px; }
/* 본문 뒤쪽 블록은 태그·관련과 같은 100 으로 선다 */
.v-quiet .p-main .p-series { margin-top: 100px; }

.v-quiet .p-series-pane {
  background: var(--q-code-bg);
  border: 1px solid var(--q-code-edge);
  border-radius: 3px;
}
.v-quiet .p-series-pane:hover { border-color: var(--q-rule-strong); }

.v-quiet .p-series-pane summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 11px 14px;
  cursor: pointer;
  list-style: none;
}
.v-quiet .p-series-pane summary::-webkit-details-marker { display: none; }
/* 🔴 여닫이에 포커스 링이 있어야 한다. 시안에는 없었다 — `summary` 는 키보드로 닿는
      컨트롤이고, `.v-quiet a:focus-visible` 은 `a` 에만 걸린다. `outline-offset` 이
      **음수**인 것은 판에 테두리가 있어서다. 양수면 링이 판 밖으로 나가 위아래 블록과
      겹친다 (`summary.p-rail-label` 과 다른 점). */
.v-quiet .p-series-pane summary:focus-visible {
  outline: 1px solid var(--q-soft);
  outline-offset: -3px;
}

.v-quiet .p-series-lead { font-size: 13px; line-height: 20px; color: var(--q-ink-dim); }
.v-quiet .p-series-lead b { font-weight: 500; color: var(--q-ink); }
/* 셰브론 — 글자 하나다. 아이콘 파일도 JS 도 안 쓴다. 열리면 90° 돈다 */
.v-quiet .p-series-lead::before {
  content: "›";
  display: inline-block;
  margin-right: 8px;
  color: var(--q-faint);
  transition: transform 140ms ease;
}
.v-quiet .p-series-pane[open] .p-series-lead::before { transform: rotate(90deg); }
.v-quiet .p-series-pane summary:hover .p-series-lead { color: var(--q-ink); }

.v-quiet .p-series-pos {
  margin-left: auto;
  font-family: var(--q-mono);
  font-size: 11px;
  color: var(--q-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.v-quiet .p-series-list { list-style: none; margin: 2px 0 0; padding: 0 14px 12px; }
.v-quiet .p-series-list li { margin: 0 0 7px; }
.v-quiet .p-series-list a,
.v-quiet .p-series-now { display: flex; gap: 14px; align-items: baseline; text-decoration: none; }
.v-quiet .p-series-list time {
  font-family: var(--q-mono);
  font-size: 11px;
  color: var(--q-faint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* 🔴 `min-width: 0` 은 시안에 없던 한 줄이다. flex 항목의 기본 `min-width: auto` 는
      **내용보다 작아지지 않는다** — 루트가 `word-break: keep-all` 이라 긴 한글 제목의
      최소 폭이 그대로 남고, 그 한 줄이 없으면 제목이 판을 뚫고 페이지를 가로로 민다.
      `.p-related span` 이 2026-08-25 실측으로 같은 자리에서 잡힌 그 병이다. 자리가
      넉넉할 때는 아무것도 안 바꾼다 — 모자랄 때만 줄바꿈이 일어난다. */
.v-quiet .p-series-list a span { min-width: 0; font-size: 14px; color: var(--q-ink-dim); }
.v-quiet .p-series-list a:hover span { color: var(--q-ink); }
/* 🔴 지금 보는 글 — 링크가 아니고, **색만이 아니라 글자로도** 구별된다 (WCAG 1.4.1) */
.v-quiet .p-series-now span { min-width: 0; font-size: 14px; color: var(--q-ink); font-weight: 500; }
.v-quiet .p-series-now::after {
  content: "지금";
  margin-left: 6px;
  font-family: var(--q-mono);
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--q-faint);
}

/* --- `/series` · `/series/{slug}` 전용 (블록 밖) --------------------
 *
 * 같은 목록 모양을 판 없이 쓴다. 새 시각 언어를 만들지 않는다.
 *
 * 🔴 **면이 둘이라 값도 둘이다.** 같은 목록 조각이 두 면 위에 놓인다 — 글 상세의 접힌 판은
 *    `--q-code-bg` 이고, 이 두 지면은 흰 지면(`--q-bg`)이다. 토큰 하나로 통일하면 한쪽이 반드시 틀린다:
 *
 *    | | 판 안쪽 (#f7f7f7 / #16181b) | 이 두 지면 (#ffffff / #0d0e10) |
 *    |---|---|---|
 *    | `--q-mid` | 🔴 4.43 · 5.55 — **AA 4.5 미달** | 4.74 · 6.03 — 목차·관련 글과 같음 |
 *    | `--q-ink-dim` | 6.96 · 8.57 | 🔴 7.46 · 9.31 — 목록만 혼자 진해져 튄다 |
 *
 *    그래서 판 안쪽은 `--q-ink-dim`, 여기는 `--q-mid` 다(오너 컨펌 2026-09-15 · #112).
 *    판 안쪽 값은 이 파일 70행이 이미 못 박은 규칙 — 「구문 강조 — 전부 --q-code-bg 대비 AA 이상」 —
 *    을 따른 것이고, 실제 구문 강조 색 일곱은 그 면 위에서 5.45~7.30 에 선다. 6.96 은 그 밴드 안이다.
 *
 *    🔴 두 자리가 조용히 갈라지지 않는다. `QuietCssContractTest` 가 **두 면을 따로 잰다** —
 *    판은 `--q-code-bg` 위에서, 이 지면은 `--q-bg` 위에서. 한쪽만 고치면 그 자리가 빨개진다.
 *
 * 🔴 「지금」 글은 대비를 올려도 색에만 기대지 않는다 — `--q-ink` + 굵기 + 「지금」 라벨이다(WCAG 1.4.1).
 *    대비를 올릴수록 색 차이가 줄어서 그 라벨이 더 중요해졌다. 같은 테스트가 라벨이 비지 않았는지도 본다.
 *
 * 🔴 날짜와 편수는 `--q-faint` 로 남긴다. 11px 메타라 `.p-related time`(10.5px · 1.71:1)과 같은 짝이고,
 *    대비 규칙의 대상이 아니다.
 *
 * 🔴 목록의 위 여백은 `.q-list`(글 목록)와 같은 30 이다. 헤딩의 밑줄에 붙이지 않는다.
 * ------------------------------------------------------------------ */
/* 🔴 게이트 안내 안의 링크는 **링크로 보여야 한다.** `.v-quiet a` 는 색도 밑줄도 안
      주고(색으로 구분하지 않는 것이 이 지면의 규칙이다), 밑줄을 주는 것은 본문
      (`.post-body p a`)과 홈 인트로(`.q-hello a`)뿐이다. 이 문단은 그 어느 쪽도 아니라서
      그냥 두면 「지금 열기」로 가는 유일한 문이 본문 글자와 구별되지 않는다.
      같은 토큰·같은 밑줄을 쓴다 — 그레이스케일에서도 살아남는 구분이다. */
.v-quiet .p-series-gate a {
  color: var(--q-ink);
  box-shadow: inset 0 -1px 0 var(--q-link-line);
  transition: box-shadow 200ms ease;
}
.v-quiet .p-series-gate a:hover { box-shadow: inset 0 -1px 0 var(--q-link-line-on); }

.v-quiet .p-series-page { margin-top: 30px; }
.v-quiet .p-series-page .p-series-list { margin: 0; padding: 0; }
.v-quiet .p-series-page .p-series-list li { margin: 0 0 10px; }
/* 🔴 지면 위로 나오면 한 단계 밝힌다. 판 안쪽은 --q-ink-dim 이지만 여기는 흰 지면이라
      같은 값이면 이 지면의 목록만 목차·관련 글보다 진해져 혼자 튄다. 면이 다르면 값도 다르다 */
.v-quiet .p-series-page .p-series-list a span { color: var(--q-mid); }
/* 🔴 **이 줄이 있어야 한다.** 위 한 줄과 기본 hover 는 명시도가 **같다** —
      `.v-quiet .p-series-page .p-series-list a span`  (0,3,2)
      `.v-quiet .p-series-list a:hover span`           (0,3,2)  ← `:hover` 도 클래스로 센다
      동률이면 나중 것이 이기고 위 한 줄이 더 뒤에 있다. 그래서 이 줄을 지우면 쉬는 색이
      hover 를 덮어 **이 지면에서만 hover 가 조용히 죽는다**. (순서는 상관없다 — 이 줄은
      `:hover` 가 하나 더 붙어 (0,4,2) 라 위 한 줄을 명시도로 이긴다.)
      `QuietCssContractTest` 의 `series list hover survives the cascade` 가 지킨다 */
.v-quiet .p-series-page .p-series-list a:hover span { color: var(--q-ink); }

.v-quiet .p-series-index { list-style: none; margin: 30px 0 0; padding: 0; }
.v-quiet .p-series-index li { margin: 0 0 14px; }
.v-quiet .p-series-index a { display: flex; gap: 14px; align-items: baseline; text-decoration: none; }
.v-quiet .p-series-index a span { min-width: 0; font-size: 15px; color: var(--q-mid); }
.v-quiet .p-series-index a:hover span { color: var(--q-ink); }
.v-quiet .p-series-index em {
  font-family: var(--q-mono);
  font-size: 11px;
  font-style: normal;
  color: var(--q-faint);
  font-variant-numeric: tabular-nums;
  margin-left: auto;
  white-space: nowrap;
}
