/* Components and layout — 02-design-system.md §3 (layout), §4 (components), §6 (mobile),
   §8 (photographs). Requires tokens.css. No border-radius and no box-shadow appear in this
   file: §1 rules both out, and every division is a 1px --line or whitespace. */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: var(--w-text) var(--fs-body)/2.2 var(--sans);
  -webkit-font-smoothing: antialiased;
  /* Korean breaks mid-word by default, which strands single syllables at the end of a
     heading. Break at spaces instead, and fall back only for a token wider than its column. */
  word-break: keep-all;
  overflow-wrap: break-word;
}

/* Contains the section margins below so they do not collapse out through <main>. */
main { display: flow-root; }

h1, h2, h3, h4, p, dl, dd, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; height: auto; }

a { color: inherit; text-decoration: none; }

/* §14.22 — 손가락으로 누르면 브라우저가 기본으로 하늘색 사각형을 덮는다. 이 팔레트에
   없는 색이고 글자보다 크게 번져 한지 면을 깬다. 지우는 대신 되먹임은 남긴다 —
   누르는 동안 옅어지는 것으로, 누른 것이 무엇인지는 그대로 보이게. */
a, button, summary, [role="button"] { -webkit-tap-highlight-color: transparent; }

@media (hover: none) {
  a:active,
  button:active { opacity: 0.55; }
}

:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* §14.15 — 탭 사이 이동은 문서를 새로 받아오는 일이라 기본이 '툭' 끊기는 전환이다.
   갈래 안에서는 화면 절반이 그대로인데 전부 다시 그려지니 어지럽다. 브라우저가
   지원하면 두 문서를 겹쳐 넘긴다. 자바스크립트 없음. */
@view-transition { navigation: auto; }

/* 먹지 면과 띠에 이름을 주어 제자리에 붙드는 방법도 있지만 쓰지 않는다: 이름이
   붙은 요소는 위치 차이를 '움직임'으로 갚는데, 화면 맨 위에서 탭을 누르면 그
   차이가 1,000px이라 겹쳐 넘기는 것보다 어지럽다. 화면 전체를 겹쳐 넘긴다. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 260ms;
  animation-timing-function: ease;
}

.nobr { white-space: nowrap; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  top: 0;
  left: var(--gutter);
  z-index: 40;
  transform: translateY(-120%);
  background: var(--accent-text);
  color: #fff;
  font: var(--w-text) 15.5px/1 var(--sans);
  letter-spacing: 0.1em;
  padding: 16px 24px;
}

.skip-link:focus {
  transform: translateY(0);
}

/* §3.1 — margin-inline only: a `margin: 0 auto` shorthand here outranks the section
   rhythm below (a class beats `main > *`) and silently flattens every 200px gap. */
.container {
  max-width: var(--max-w);
  margin-inline: auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

/* §3.3 — one step between screens. The hero keeps its own 210/230 exception. */
main > * { margin-top: var(--sp-section); }
main > :last-child { margin-bottom: var(--sp-section); }
.hero { margin-top: var(--sp-section-hero); }
.hero + * { margin-top: var(--sp-section-hero-end); }

/* §10.8 — a screen that ends on the 먹지 quotation keeps its full section gap:
   the 한지 band is what separates that dark field from the dark footer. */

/* §11.1 — 생애 and 이안실 open straight onto the 먹지; its own padding is the spacing. */
main > .gate-intro:first-child { margin-top: 0; }

/* §3.2 반반형 */
.grid-halves {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-6);
}

/* ── SiteHeader §4.1 ─────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--dark-bg);
  border-top: 4px solid var(--accent);
}


.site-header .inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  padding-top: 11px;
  padding-bottom: 11px;
}

.site-header .wordmark {
  display: inline-block;
  font: 800 19px/1 var(--serif);
  letter-spacing: 0.12em;
  color: #f5f1e8;
  padding: 15px 0;
}

.site-nav {
  display: flex;
  gap: 38px;
}

/* inline-block so the 15px padding is a real 44px touch target, not just painted area. */
.site-nav a {
  display: inline-block;
  font: var(--w-text) var(--fs-nav)/1 var(--sans);
  letter-spacing: 0.08em;
  color: var(--dark-body);
  padding: 15px 0;
}

.site-nav a:hover { color: #fff; }

.site-nav a[aria-current="page"] {
  color: #fff;
  font-weight: 400;
}

/* §4.1's underline emphasis, now in the accent: a filled pill crowded the
   mobile masthead and sat as a box on the band. Colour + rule, no box. */
.site-nav .donate {
  position: relative;
  color: var(--accent-dark);
}

.site-nav .donate::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 11px;
  border-bottom: 1px solid currentColor;
}

.site-nav .donate:hover { color: #fff; }

/* ── SectionLabel §4.2 ───────────────────────────────────── */

.section-label {
  font: var(--w-text) var(--fs-label)/1 var(--sans);
  letter-spacing: 0.3em;
  color: var(--label);
  margin: 0 0 var(--sp-5);
}

/* Letter-spacing leaves a trailing gap after the last glyph. */
.section-label.center {
  text-align: center;
  margin-right: -0.3em;
}

.hero .section-label { margin-bottom: 56px; }

.gate-intro .section-label { color: var(--label); }

/* ── Headings ────────────────────────────────────────────── */

.display-title {
  font: 700 var(--fs-display)/1.5 var(--serif);
  letter-spacing: 0.01em;
  margin: 0 0 var(--sp-4);
}

.screen-title {
  font: 400 var(--fs-h2)/1.6 var(--serif);
  letter-spacing: 0.01em;
  margin: 0;
}

/* §5.3 — one step above the 34px screen title, because it names a chapter. */
.era-title {
  font: 400 44px/1.5 var(--serif);
  letter-spacing: 0.01em;
  margin: 0;
}

.lead {
  font: 400 var(--fs-lead)/1.8 var(--serif);
  letter-spacing: 0.01em;
  margin: 0 0 40px;
}

.body-text {
  font: var(--w-text) var(--fs-body)/2.2 var(--sans);
  color: var(--body);
  max-width: var(--measure-body);
  margin: 0;
}

.body-text-s {
  font: var(--w-text) var(--fs-body-s)/2.15 var(--sans);
  color: var(--body);
  max-width: var(--measure-body);
  margin: 0;
}

/* ── TimelineRow §4.3 ────────────────────────────────────── */

.timeline {
  border-bottom: 1px solid var(--line);
}

/* §10.6 — 44px, not 64: the row carries its section preview now, so the height
   comes from what is in it rather than from the space around it. */
.timeline-row {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 80px;
  padding: var(--sp-3) 0;
  border-top: 1px solid var(--line);
  align-items: baseline;
}

.timeline-row .year {
  font: 700 var(--fs-year)/1 var(--serif);
  letter-spacing: 0.06em;
  color: var(--accent);        /* 22px·700 — 큰 활자라 주홍을 그대로 쓴다 */
  margin: 0;
}

/* §10.6 — one step under the screen title (34px), which the row was level with. */
.timeline-row .title {
  font: 400 var(--fs-card)/1.6 var(--serif);
  letter-spacing: 0.01em;
  margin: 0 0 var(--sp-1);
}

/* §10.5 — the numbered section titles of the text, or the era's summary once it
   is written: what tells the visitor there is something to read behind the row. */
.timeline-row .sections {
  font: var(--w-text) var(--fs-body-s)/1.9 var(--sans);
  color: var(--body);
  max-width: var(--measure-body);
  margin: 0;
}

/* Qualified by the tag: a row with no manuscript is a <div>, and it must not
   answer to the pointer at all (§10.5). */
a.timeline-row:hover .title { color: var(--link-hover); }

.timeline-row.pending .title,
.timeline-row.pending .sections { color: var(--label); }

/* ── GateIntro §11.2 (succeeds QuoteBlock §4.4) ──────────── */

/* 먹지 is now the shared face of the two 갈래 that remember the man: it says
   "여기부터 선생의 말" and the 열람·사무 갈래 open on 한지 instead (§11.3.1). */
.gate-intro {
  background: var(--paper);
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  /* §14.10 — 먹지 면은 내용 길이와 무관하게 한 판이다. 생애는 한문 행과 두 행짜리
     시구를 더 갖는데, 그 차이가 면의 크기를 정하면 갈래를 옮길 때마다 화면이
     출렁인다. 높이는 화면 하나로 못 박고 내용은 그 안에서 가운데 선다. */
  display: grid;
  align-content: center;
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100svh - var(--header-h));
}

.gate-intro .inner {
  max-width: var(--max-w);
  /* 격자 안에서도 화면 가운데를 지킨다 — 이 한 줄이 없으면 최대 폭에 걸린 순간
     내용이 왼쪽 끝에 붙는다(1512px에서 136px 치우쳤다). */
  margin-inline: auto;
  /* 위아래 값은 리듬이 아니라 최소 숨통이다 — 면의 높이는 위에서 정해졌다. */
  padding: var(--sp-5) var(--gutter);
  text-align: center;
}

/* §11.2 rule 1 — the original stands as evidence one step down, and the
   translation below it speaks. 한자 is dense, so the tracking is wide. */
.gate-intro .hanmun {
  font: 400 var(--fs-year)/1 var(--serif);
  letter-spacing: 0.12em;
  color: var(--accent-text);
  margin: 0 0 40px;
}

/* balance is for the 이안실 표제, which soft-wraps: measured plain, it leaves
   '공간' alone on the second line from 430px to 800px. The verse is unaffected —
   its breaks are <br>, and a forced break is not a wrapping decision. */
.gate-intro .display {
  font: 400 var(--fs-quote)/1.85 var(--serif);
  letter-spacing: 0.02em;
  text-wrap: balance;
  margin: 0 0 72px;
}

/* 시는 행갈이가 곧 내용이라 좁은 화면의 접힘을 자연 개행에 맡기지 않는다 —
   같은 시구를 구 단위로 다시 접은 벌이 <720px에서 선다 (§11.3.1). */
.gate-intro .display.narrow { display: none; }

/* §14.12 — 부기와 시구를 가르는 것은 정렬이 아니라 행의 길이다. 짧은 행으로
   쌓을 때 시처럼 읽혔으니 폭을 넓혀 흘리되(6행 → 3행), 정렬은 표제와 같은
   가운데로 되돌린다 — 가운데 표제 아래 왼쪽 덩어리는 서로 따로 논다. */
.gate-intro .note {
  font: var(--w-text) 16.5px/2.1 var(--sans);
  color: var(--body);
  max-width: 34em;
  margin-inline: auto;
  text-wrap: pretty;
  word-break: keep-all;
}

.gate-intro .after-note { margin: var(--sp-3) 0 0; }

/* The underline lives on the inner <span> (§4.9), so the 먹지 variant tints the
   two separately: the words take --dark-ink, the rule takes --line-dark. */
.gate-intro .text-link.dark { color: var(--ink); }

.gate-intro .text-link.dark > span { border-color: var(--line-strong); }

.gate-intro .text-link.dark:hover { color: var(--link-hover); }

.gate-intro .text-link.dark:hover > span { border-color: currentColor; }

/* ── CategoryStrip §9.3.1 ────────────────────────────────── */

/* Deliberately not sticky: the header already floats, and two floating layers
   would make the top of every list screen heavy (§9.3.1). */
.category-strip {
  display: flex;
  gap: 28px;
  margin-top: var(--sp-2);
  overflow-x: auto;
  scrollbar-width: none;
  /* §14.9 — under a 여는 글 the strip is a tab bar and its links point at it, so
     the landing must clear the header floating over it rather than sit beneath.
     §14.25 — derived from the header rather than written out, because the header
     now grows with the wordmark and differs between desktop and mobile. */
  scroll-margin-top: calc(var(--header-h) + 24px);
}

.category-strip::-webkit-scrollbar { display: none; }

/* 15px rather than the specified 14px: with a 14px line box that is what makes
   the touch target a full 44px (§9.3.1's own requirement). */
.category-strip a {
  flex: none;
  font: var(--w-text) 15.5px/1 var(--sans);
  letter-spacing: 0.06em;
  color: var(--nav);
  padding: 15px 0;
}

.category-strip a:hover { color: var(--link-hover); }

.category-strip a[aria-current="page"] {
  color: var(--ink);
  font-weight: 400;
  border-bottom: 1px solid var(--line-strong);
}

/* ── MediaListRow §9.3.2 ─────────────────────────────────── */

/* §10.1 — a list is an index, so every photograph is cropped into one 240×180
   frame and the rows come out the same height. The exhibit is the detail screen,
   where §8.1 still forbids so much as an enlargement. */
.media-row {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 60px;
  align-items: start;
  padding: 32px 0;
  border-top: 1px solid var(--line);
}

.media-row:last-child { border-bottom: 1px solid var(--line); }

.media-row .photo {
  width: 240px;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.media-row .photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A page is taller than it is wide: cropping from the top keeps the first line
   of a letter and the heading of a document. */
.media-row .photo.doc img { object-position: center top; }

/* Smaller than the frame — centred at its own size rather than blown up, and
   what is left over stays 한지 (§8.2 forbids a mat or a border). */
.media-row .photo.undersize img {
  object-fit: none;
  object-position: center;
}

/* §9.3.2 — a piece without a photograph takes the full row rather than
   standing beside an empty well. */
.media-row.no-photo { grid-template-columns: 1fr; }

.media-row .cat {
  font: var(--w-text) var(--fs-small)/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--label);
  margin: 0 0 10px;
}

.media-row .title {
  font: 400 21px/1.7 var(--serif);
  margin: 0 0 12px;
}

.media-row .date {
  font: var(--w-text) var(--fs-small)/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--faded);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.media-row:hover .title { color: var(--link-hover); }

/* ── Pager §9.3.3 ────────────────────────────────────────── */

.pager {
  display: flex;
  gap: 8px;
  margin-top: var(--sp-3);
}

/* lh 1.1 rather than 1: with 15px above and below it is 13.5px of type that
   makes the touch target a full 44px, and the underline stays under the words. */
.pager a {
  font: var(--w-text) 15.5px/1.1 var(--sans);
  letter-spacing: 0.06em;
  color: var(--nav);
  padding: 15px 10px;
  font-variant-numeric: tabular-nums;
}

.pager a:hover { color: var(--link-hover); }

.pager [aria-current="page"] {
  color: var(--ink);
  font-weight: 400;
  border-bottom: 1px solid var(--line-strong);
}

/* ── SectionIndex §9.3.4 ─────────────────────────────────── */

.section-index {
  margin-top: var(--sp-3);
  max-width: var(--measure-article);
}

.section-index a {
  display: block;
  padding: 6px 0;
  font: var(--w-text) var(--fs-body-s)/2.1 var(--sans);
  color: var(--body);
}

.section-index a:hover { color: var(--link-hover); }

/* Sticky header plus a breath, so an anchor jump does not land under it. */
.article-body h2,
.article-body h3 { scroll-margin-top: 128px; }

/* ── SectionRail §9.3.5 ──────────────────────────────────── */

.section-rail a {
  display: block;
  padding: 6px 0;
  font: var(--w-text) var(--fs-small)/1.7 var(--sans);
  letter-spacing: 0.02em;
  color: var(--faded);
}

.section-rail a:hover { color: var(--link-hover); }

.section-rail a[aria-current="true"] {
  color: var(--ink);
  font-weight: 400;
}

@media (min-width: 1024px) {
  .article-layout.has-rail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 190px;
    gap: 80px;
  }

  .article-layout.has-rail .section-rail {
    position: sticky;
    top: 128px;
    align-self: start;
  }
}

@media (max-width: 1023px) {
  .section-rail { display: none; }
}

/* The wrapper carries the gap above the text so the rail starts level with it. */
.article-layout { margin-top: var(--sp-5); }

.article-layout .article-body { margin-top: 0; }

/* ── PostListRow §4.6 ────────────────────────────────────── */

.post-list {
  border-bottom: 1px solid var(--line);
}

.post-list-row {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 80px;
  padding: 40px 0;
  border-top: 1px solid var(--line);
  align-items: baseline;
}

.post-list-row .date {
  font: var(--w-text) var(--fs-small)/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--faded);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.post-list-row .title {
  font: 400 21px/1.7 var(--serif);
  margin: 0;
}

.post-list-row:hover .title { color: var(--link-hover); }

/* ── ArticleBody §4.7 ────────────────────────────────────── */

.article-head .date {
  font: var(--w-text) 15px/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--faded);
  margin: var(--sp-1) 0 0;
  font-variant-numeric: tabular-nums;
}

.article-body {
  margin-top: var(--sp-5);
}

/* The measure is set on the text children so figures can run to container width.
   §9.5 held this at 400 while the rest of the site skimmed at 300 — weight, not
   size, is what makes Noto Sans KR read solid at Korean stroke density. §14.23
   takes the whole site to 400 for the same reason, so the two now agree. */
.article-body > p,
.article-body > ul,
.article-body > ol,
.article-body > blockquote {
  max-width: var(--measure-article);
  font: 400 var(--fs-read)/2.1 var(--sans);
  margin: 0 0 1.6em;
}

.article-body > :last-child { margin-bottom: 0; }

/* §2 exception 1 — 시·산문, 추모의 글, 편지 전사문 are set in 명조; §9.5 raises
   the size, because for 명조 400 size is the lever. */
.article-body.prose > p,
.article-body.prose > blockquote {
  font: 400 var(--fs-prose)/2.2 var(--serif);
}

.article-body h2 {
  font: 400 25px/1.6 var(--serif);
  max-width: var(--measure-article);
  margin: 2.4em 0 var(--sp-1);
}

/* §9.4.6 — 조 headings step down out of 명조 so the 정관 reads as two levels. */
.article-body h3 {
  font: 400 var(--fs-body)/1.8 var(--sans);
  max-width: var(--measure-article);
  margin: 2em 0 0.4em;
}

.article-body > h2:first-child { margin-top: 0; }

/* ── ArticleTable §13.3 ──────────────────────────────────── */

/* The site's rule is horizontal only: a line over each row and one closing the
   table. No vertical rules, no stripes, no fill, no right alignment — digits
   line up because they are tabular, not because the column is flushed right. */
.article-body .table-wrap {
  margin: 48px 0;
  overflow-x: auto;
  max-width: 100%;
  /* On a screen the box reaches the edge of, a swipe that runs past the last
     column would otherwise carry on into the browser's back gesture. */
  overscroll-behavior-x: contain;
}

.article-body .table-wrap:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.article-table {
  border-collapse: collapse;
  min-width: 100%;
  border-bottom: 1px solid var(--line);
}

.article-table th,
.article-table td {
  border-top: 1px solid var(--line);
  padding: 12px 24px 12px 0;
  text-align: left;
  vertical-align: top;
  font: 400 var(--fs-body-s)/1.7 var(--sans);
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* A column label speaks in the language of a DefList dt. */
.article-table th {
  font: var(--w-text) 15px/1.7 var(--sans);
  letter-spacing: 0.16em;
  color: var(--label);
  white-space: nowrap;
}

.article-table th:last-child,
.article-table td:last-child { padding-right: 0; }

.article-foot {
  margin-top: var(--sp-figure);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}

/* ── DefList §4.8 ────────────────────────────────────────── */

.def-list { margin: 0; }

.def-row {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: var(--sp-2);
  padding: 24px 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}

.def-row dt {
  font: var(--w-text) var(--fs-small)/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--label);
}

/* §9.5 — a value is body text: an account number misread costs more than the
   lightness is worth. */
.def-row dd {
  font: 400 var(--fs-body-s)/1.8 var(--sans);
  color: var(--ink-soft);
  margin: 0;
}

.def-row dd.numeric { font-variant-numeric: tabular-nums; }

/* ── TextLink §4.9 ───────────────────────────────────────── */

/* The underline belongs to the inner <span>, not to the link: a border on the 44px-tall
   target would draw the line at the bottom of the box instead of under the words. */
.text-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font: var(--w-text) 15.5px/1 var(--sans);
  letter-spacing: 0.1em;
  color: var(--ink);
}

.text-link > span {
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 5px;
}

.text-link:hover {
  color: var(--link-hover);
}

.text-link:hover > span {
  border-color: currentColor;
}

.article-body a {
  color: inherit;
  border-bottom: 1px solid var(--line-strong);
}

.article-body a:hover {
  color: var(--link-hover);
  border-color: currentColor;
}

/* ── DonateButton §4.10 ──────────────────────────────────── */

.donate-button {
  display: inline-block;
  background: var(--accent);
  color: var(--bg);
  font: var(--w-text) 16.5px/1 var(--sans);
  letter-spacing: 0.14em;
  padding: 20px 56px;
  border: none;
  cursor: pointer;
}

.donate-button:hover { background: var(--accent-hover); }

.donate-button[disabled],
.donate-button[aria-disabled="true"] {
  background: transparent;
  color: var(--label);
  border: 1px solid var(--line-strong);
  cursor: default;
}

.donate-button.loading { pointer-events: none; }

.donate-note {
  font: var(--w-text) var(--fs-body-s)/2.1 var(--sans);
  color: var(--body);
  margin: var(--sp-1) 0 0;
  max-width: var(--measure-body);
}

/* ── SiteFooter §4.11 ────────────────────────────────────── */

/* §10.8 — 먹지. 이안실 opens the site with a dark field and the footer closes it
   with one; a block of corporate information has to change surface, not just be
   ruled off, to read as a different order of thing from the body above it. */
.site-footer {
  background: var(--dark-bg);
  font: var(--w-text) 15px/2.1 var(--sans);
  letter-spacing: 0.06em;
  color: var(--dark-body);
}

.site-footer .inner {
  padding-top: 72px;
  padding-bottom: 72px;
}

.site-footer .info {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px var(--sp-6);
}

.site-footer p { margin: 0; }

.site-footer .org {
  font: 500 15.5px/2.1 var(--sans);
  color: var(--dark-ink);
  margin-bottom: 8px;
}

.site-footer .account { font-variant-numeric: tabular-nums; }

.site-footer .links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 40px;
  margin-top: 56px;
  padding-top: 28px;
  border-top: 1px solid var(--line-dark);
}

.site-footer .copyright {
  margin-top: 8px;
  text-align: right;
}

/* 13px of text on its own leaves a 28px-tall target. */
.site-footer a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--dark-ink);
}

/* --link-hover is a 종이 colour and falls under 3:1 on 먹지; --dark-label is the
   hover of every dark surface here (§10.8). */
.site-footer a:hover { color: var(--dark-label); }

/* The global ring is --ink, which is 1.02:1 on 먹지 — invisible. Same answer the
   이안실 block gives (§4.4). */
.site-footer a:focus-visible { outline-color: var(--dark-ink); }

/* ── EmptyState §4.12 ────────────────────────────────────── */

.empty-state {
  border-top: 1px solid var(--line);
  padding: 120px 0;
  text-align: center;
  font: var(--w-text) 16.5px/1.8 var(--sans);
  color: var(--label);
}

/* ── ChronologyRow §4.14 ─────────────────────────────────── */

.chronology-row {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: var(--sp-2);
  padding: 14px 0;
  align-items: baseline;
}

.chronology-row .year {
  font: 700 16px/1.9 var(--serif);
  letter-spacing: 0.04em;
  color: var(--accent-text);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.chronology-row .entry {
  font: var(--w-text) var(--fs-body-s)/1.9 var(--sans);
  color: var(--ink-soft);
  max-width: var(--measure-article);
  margin: 0;
}

/* §4.14 — the only rules in a 연보 mark decade boundaries. */
.chronology-row.decade-start {
  border-top: 1px solid var(--line);
  margin-top: 48px;
  padding-top: 48px;
}

/* ── ImageFigure §8.1–8.3 ────────────────────────────────── */

.image-figure {
  margin: var(--sp-figure) 0;
}

.image-figure img {
  display: block;
  width: 100%;
  height: auto;
  background: transparent;
}

/* §8.1 — 800–1199px originals stay inside the text measure. */
.image-figure.medium img {
  max-width: min(100%, var(--figure-w, 100%));
}

/* §8.1 — under 800px, never scaled up; the extra whitespace carries the weight. */
.image-figure.small {
  margin-block: var(--sp-figure-small);
}

.image-figure.small img {
  width: auto;
  max-width: 100%;
}

/* Centred as a block, but the caption still aligns to the image's left edge (§8.3),
   so the figure — not the img — is what gets centred. */
.image-figure.tall {
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
}

.image-figure.tall img {
  width: auto;
  max-height: 85vh;
}

/* A figure that is a whole section keeps the §3.3 rhythm instead of adding to it. */
main > .container > .image-figure:only-child { margin-block: 0; }

.image-figure figcaption {
  font: var(--w-text) 15px/1.8 var(--sans);
  color: var(--faded);
  margin-top: 16px;
  max-width: var(--measure-article);
}

/* §8.4 — only an image with more pixels than it is drawn at is given a cursor
   and a focus stop; photo.js adds the class, so no-JS gives no false promise. */
img.zoomable { cursor: zoom-in; }

/* ── The lead photograph §9.4.4 ──────────────────────────── */

/* Records and news put the picture first: the object, then the label beside it. */
.lead-figure { margin: var(--sp-4) 0 0; }

.lead-figure img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 85vh;
}

.lead-figure figcaption {
  font: var(--w-text) 15px/1.8 var(--sans);
  color: var(--faded);
  margin-top: 16px;
  max-width: var(--measure-article);
}

/* ── Home portrait §9.4.8, §10.9 ─────────────────────────── */

/* Stacked under the text below 1024px; hung full width the portrait becomes a wall. */
.hero-portrait { margin-top: var(--sp-figure); }

.hero-portrait img {
  display: block;
  width: auto;
  max-width: min(560px, 100%);
  max-height: 85vh;
}

.hero-portrait figcaption {
  margin-top: 16px;
  font: var(--w-text) 15px/1.6 var(--sans);
  color: var(--faded);
  max-width: min(560px, 100%);
}

/* §10.9 — 좌 글 · 우 초상. The office asked for the title, the lead and the
   photograph in one screenful, so the hero gives up its 210px opening for
   84px and the display size drops to what the left column can hold. */
@media (min-width: 1024px) {
  .hero.container {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--sp-6);
    margin-top: var(--sp-5);
  }

  .hero-copy { max-width: 640px; }

  .hero .display-title { font-size: clamp(44px, 4.2vw, 60px); }

  .hero .hero-portrait {
    margin: 0;
    flex: 0 1 400px;
  }

  /* 66vh keeps the photograph from becoming a wall on a laptop; the crop is
     1,864px wide, so 420px of display never scales it up (§8.1). */
  .hero .hero-portrait img {
    display: block;
    width: auto;
    max-width: 100%;
    max-height: min(66vh, 620px);
    margin-left: auto;
  }
}

/* Between 1024 and 1200 the left column falls under the width the title needs,
   and "불굴의 항일 혁명가" breaks into a third line. The photograph gives up the
   width instead — §10.10 keeps the title at two lines. */
@media (min-width: 1024px) and (max-width: 1199px) {
  .hero.container { gap: var(--sp-5); }

  .hero .hero-portrait { flex: 0 1 340px; }
}

/* ── Lightbox §8.4 ───────────────────────────────────────── */

/* A <dialog>, so the browser owns the focus trap and Esc; the UA frame is undone
   and the 먹지 fills the screen instead. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  border: none;
  background: var(--dark-bg);
  color: var(--dark-ink);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  /* Safe-area insets so a notch or home bar never sits over the photograph. */
  padding: max(72px, env(safe-area-inset-top)) max(var(--gutter), env(safe-area-inset-right))
           max(72px, env(safe-area-inset-bottom)) max(var(--gutter), env(safe-area-inset-left));
  overscroll-behavior: contain;
}

.lightbox:not([open]) { display: none; }

.lightbox figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  min-height: 0;
}

/* No CSS width, so the original is never drawn past its own pixels (§8.4).
   Pinch zoom stays the visitor's own (§6.5). */
.lightbox img {
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  object-fit: contain;
}

.lightbox figcaption {
  font: var(--w-text) 15px/1.8 var(--sans);
  color: var(--dark-body);
  text-align: center;
}

.lightbox .close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 48px;
  height: 48px;
  background: none;
  border: none;
  color: var(--dark-ink);
  font: var(--w-text) 22px/1 var(--sans);
  cursor: pointer;
}

.lightbox .close:focus-visible { outline: 2px solid var(--dark-ink); }

/* ── Scroll-in fade §0-5 ─────────────────────────────────── */

/* Hidden only once JS can reveal it again, so a no-JS visitor sees everything. */
.js .reveal {
  opacity: 0;
  transition: opacity 0.9s ease-out;
}

.js .reveal.is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transition: none; }

  /* 겹쳐 넘기기도 움직임이다 — 끈 사람에게는 예전처럼 즉시 바뀐다. */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── Page-level odds and ends ────────────────────────────── */

/* Beats `main > *` (a class outranks the element selector), so a save notice
   does not open a 200px hole above the screen it belongs to. */
main > .page-notice {
  margin-top: var(--sp-4);
  font: var(--w-text) var(--fs-body-s)/1.8 var(--sans);
  color: var(--body);
  border-left: 1px solid var(--line-strong);
  padding-left: 20px;
}

.screen-lead { margin-top: var(--sp-4); }

.after-list { margin-top: var(--sp-4); }

.def-row + .after-list,
.article-body + .after-list { margin-top: var(--sp-3); }

/* 갈래 표기 on a list row and the officer's affiliation on a def row: the same
   voice, one step quieter than what it follows. */
.board,
.def-row dd .note {
  font: var(--w-text) 15px/1.6 var(--sans);
  letter-spacing: 0.1em;
  color: var(--label);
  white-space: nowrap;
}

.def-row dd .note { letter-spacing: 0; }

.event-list li + li { margin-top: 8px; }

/* §9.6 — a name appears only where one is known; a row without one shows nothing
   in its place. */
.post-list-row .author,
.media-row .author {
  font: var(--w-text) 15px/1 var(--sans);
  letter-spacing: 0.06em;
  color: var(--faded);
  margin-left: 14px;
  white-space: nowrap;
}

/* §9.3.6 — the label is already a breadcrumb sentence, so its parent becomes the
   link. Padding on an inline box widens the hit area without moving the line;
   15px is what carries the 13.5px line box to the full 44px target. */
.section-label a {
  color: inherit;
  padding: 15px 0;
}

.section-label a:hover { color: var(--link-hover); }

/* §9.3.1 — the strip follows the label directly; the 84px below a label belongs
   to screens where the label is the only thing above the content. */
.list-head .section-label { margin-bottom: 0; }

.list-head + * { margin-top: var(--sp-4); }

.era-period {
  font: 400 var(--fs-year)/1 var(--serif);
  letter-spacing: 0.06em;
  color: var(--faded);
  margin: 0 0 var(--sp-1);
}

.era-summary { margin-top: var(--sp-1); }

.source-note {
  font: var(--w-text) 15px/1.9 var(--sans);
  color: var(--faded);
  max-width: var(--measure-article);
  margin-top: var(--sp-4);
}

/* §5.7 — a signature, not a byline: the writer's name closes their own words.
   Scoped through .article-body and qualified by the tag so it outranks both
   paragraph rules it sits among; a bare `.signature` loses to
   `.article-body > p` and comes out in 고딕. */
.article-body p.signature {
  font: 400 16px/1.8 var(--serif);
  color: var(--ink-soft);
  max-width: var(--measure-article);
  margin-top: var(--sp-4);
  text-align: right;
}

.finance-year {
  font: 400 var(--fs-year)/1 var(--serif);
  letter-spacing: 0.06em;
  color: var(--ink);
  margin: 0 0 var(--sp-1);
}

.finance-note { margin-top: var(--sp-1); }

.article-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
}

/* ── Imported body HTML §4.7, §8.1 ───────────────────────── */

/* §2 exception 3 — emphasis switches typeface instead of adding weight. */
.article-body strong {
  font-family: var(--serif);
  font-weight: 400;
}

/* Fallback for bodies stored before the import started promoting these paragraphs to
   <h2> (html_content.promote_headings). Re-importing removes the need for this rule. */
.article-body > p:has(> strong:only-child) {
  font: 400 25px/1.6 var(--serif);
  color: var(--ink);
  margin: 2.4em 0 var(--sp-1);
}

.article-body > p:first-child:has(> strong:only-child) { margin-top: 0; }

/* Figures and images run to container width; the text measure stays on the text. */
.article-body > figure,
.article-body > p:has(> img) { max-width: none; }

/* No CSS width: the intrinsic width is the ceiling, so a small scan is never
   blown up past its own pixels (§8.1). */
.article-body img {
  display: block;
  margin: var(--sp-figure) 0;
}

.article-body figure { margin: var(--sp-figure) 0; }

.article-body figure img { margin: 0; }

.article-body figcaption {
  font: var(--w-text) 15px/1.8 var(--sans);
  color: var(--faded);
  margin-top: 16px;
  max-width: var(--measure-article);
}

/* ── Donate form §5.10 ───────────────────────────────────── */

.donate-form { margin-top: var(--sp-1); }

.donate-form .field { margin-bottom: 28px; }

.donate-form label {
  display: block;
  font: var(--w-text) var(--fs-small)/1 var(--sans);
  letter-spacing: 0.16em;
  color: var(--label);
  margin-bottom: 12px;
}

.donate-form input {
  width: 100%;
  max-width: 22em;
  background: var(--field-bg);
  border: 1px solid var(--line-control);
  border-radius: 0;
  padding: 14px 16px;
  font: 400 16px/1.6 var(--sans);
  color: var(--ink);
}

.donate-form input:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.hint {
  font: var(--w-text) 15px/1.7 var(--sans);
  color: var(--label);
  margin-top: 8px;
  max-width: var(--measure-body);
}

.donate-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: var(--sp-3);
}

.donate-button.secondary {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-control);
}

.donate-button.secondary:hover {
  background: transparent;
  color: var(--link-hover);
  border-color: currentColor;
}

.donate-error:empty { display: none; }

.donate-error {
  font: var(--w-text) 15.5px/1.8 var(--sans);
  color: var(--error);
  margin-top: var(--sp-1);
  max-width: var(--measure-body);
}

/* ── Tablet §6.1 ─────────────────────────────────────────── */

@media (max-width: 1023px) {
  .timeline-row,
  .post-list-row {
    grid-template-columns: 140px 1fr;
    gap: 48px;
  }

  .media-row { gap: 48px; }
}

/* ── Mobile §6.2–6.4 ─────────────────────────────────────── */

@media (max-width: 719px) {
  /* §14.16 — 히어로 세 행은 행갈이가 곧 문안이다(불굴의 항일 혁명가 / 겸손과 통합의
     지도자 / 지운 김철수 선생). 좁은 화면에서 한 행이 다시 접히면 여섯 행이 되어
     읽는 순서가 무너지므로, 가장 긴 행(9.21em 실측)이 열에 들어가는 크기로 내린다.
     9.6은 그 실측에 반올림과 스크롤바 여유를 더한 값이다. */
  .hero .display-title {
    font-size: min(var(--fs-display), calc((100vw - 2 * var(--gutter)) / 9.6));
  }

  .display-title { line-height: 1.55; }

  .era-title { font-size: 32px; }

  .section-label { letter-spacing: 0.22em; }

  .section-label.center { margin-right: -0.22em; }

  /* §6.4 — no hamburger: five items on two rows.
     §14.20 — 두 줄을 가운데로 세워 현판으로 만든다. 왼쪽에 붙은 작은 글자 두 줄은
     떠 있는 텍스트로 읽혔다. 아래 여는 글도 가운데이므로 첫 화면이 한 구성이 된다.
     §14.25 — 이름 줄까지 함께 따라 내려온다. §13.2는 이름을 -35px만큼 걷어 올려
     내비 줄만 남겼는데, 그러면 스크롤한 뒤로는 여기가 어느 사이트인지 화면에 없다.
     현판을 만들어 놓고 그 현판을 치우는 셈이라 걷어 올리지 않는다. */

  .site-header .inner {
    display: block;
    padding-top: 4px;
    padding-bottom: 4px;
    text-align: center;
  }

  /* 이 화면에서 이름은 유일한 표제다 — 15px는 그 몫에 작았다(§14.20).
     §14.25에서 한 단 더 올린다: 늘 붙어 있는 줄이니 읽히는 크기여야 한다. */
  .site-header .wordmark {
    display: block;
    font-size: 22px;
    padding: 14px 0 0;
  }

  /* §14.20 — 띠에는 아래 선과 불투명한 면이 필요하다. 선이 없으면 따라 내려온
     반투명 면이 사진 위에서 흐지부지 끝나 '떠 있는 글자'가 된다. 데스크톱은 폭이
     넉넉해 선 없이도 띠로 읽히므로 여기서만 긋고, 자바스크립트로 붙였다 뗐다 하지
     않는다 — 맨 위에서도 현판 아래 선으로 읽힌다. */
  .site-header {
    background: var(--dark-bg);
    border-bottom: 1px solid var(--line-dark);
  }

  /* §13.2 — at 24px the five items filled all 272px a 320px screen leaves, and any
     of 400 weight on the current item, a device font or the reader's own font size
     tipped the row into two. 20px buys 17px back. Wrapping stays allowed: if the
     reader enlarges the type, folding is more honest than hiding (1.4.10). */
  .site-nav {
    flex-wrap: wrap;
    justify-content: center;
    gap: 0 20px;
  }

  /* §6.3 연표형 → 세로 쌓기 */
  .timeline-row,
  .post-list-row {
    display: block;
    padding: 40px 0;
  }

  .timeline-row .year {
    font-size: 18px;
    margin-bottom: 10px;
  }

  .post-list-row {
    padding: 28px 0;
    min-height: 56px;
  }

  .post-list-row .date { margin-bottom: 10px; }

  .post-list-row .title { font-size: 20px; }

  /* §6.3 반반형 → 세로 쌓기 */
  .grid-halves {
    grid-template-columns: 1fr;
    gap: 64px;
  }

  /* §9.3.2 — the photograph takes the whole column and the type stands under it.
     §10.1 — 360px is the ceiling, so no stored photograph is ever stretched. */
  .media-row {
    grid-template-columns: 1fr;
    gap: 18px;
    padding: 28px 0;
  }

  .media-row .photo {
    width: 100%;
    max-width: 360px;
  }

  .media-row .title { font-size: 20px; }

  /* §6.3 정의형 표 → 레이블이 값 위로 */
  .def-row {
    display: block;
    padding: 20px 0;
  }

  .def-row dt { margin-bottom: 10px; }

  .chronology-row {
    display: block;
    padding: 10px 0;
  }

  .chronology-row .year { margin-bottom: 4px; }

  .chronology-row.decade-start {
    margin-top: 32px;
    padding-top: 32px;
  }

  .gate-intro .inner { padding: var(--sp-4) var(--gutter); }

  .gate-intro .display { margin-bottom: 48px; }

  .gate-intro .display.narrow { display: block; }

  /* Out of sight, not out of the accessibility tree: the narrow fold beside it
     is aria-hidden, so this is the copy a screen reader reads here — and it
     reads the verse once at every width (view contract §2-3). */
  .gate-intro .display.refolded {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* §10.8 — one column, the links stacked, and the account number free to fold. */
  .site-footer .info {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .site-footer .links {
    display: block;
    margin-top: 40px;
  }

  .site-footer .links a { display: flex; }

  .site-footer .copyright { text-align: left; }

  .site-footer .account { word-break: keep-all; }

  .empty-state { padding: 72px 0; }

  .donate-button { display: block; text-align: center; padding: 20px 24px; }

  .donate-actions { display: block; }

  .donate-actions .donate-button { width: 100%; margin-bottom: 12px; }

  .article-foot { gap: 20px; }

  .article-body img,
  .article-body figure { margin: var(--sp-figure) 0; }

  .article-body h2,
  .article-body > p:has(> strong:only-child) { font-size: 21px; }

  /* §13.3 — the scroll box reaches past the gutter to the edge of the screen, so
     the column that does not fit is cut by the screen rather than by a margin:
     the eye can see that there is more to the right. The negative margins move
     the box but cannot widen it while `max-width: 100%` holds it to the column,
     which left the cut 48px short of the screen; the cap is lifted here only. */
  .article-body .table-wrap {
    margin-inline: -24px;
    padding-inline: 24px;
    max-width: none;
  }

  /* A ring 4px outside a box that reaches both edges of the screen is a ring
     with no sides. Drawn inside instead, so the focused table stays outlined. */
  .article-body .table-wrap:focus-visible { outline-offset: -2px; }

  .board { white-space: normal; }
}

/* §14.25 — 15.5px 내비(§14.23)는 320px에서 두 줄로 접혔고, 그 두 줄이 이제 화면에
   내내 붙어 있어 158px, 곧 화면의 28%를 먹었다. 가장 좁은 기기에서만 자간과 사이를
   줄여 한 줄로 되돌린다. 글자 크기는 건드리지 않는다 — 그것이 이 회차의 요청이었다. */
@media (max-width: 359px) {
  .site-nav { gap: 0 13px; }

  .site-nav a { letter-spacing: 0.02em; }

  /* 이름도 같은 이유로 자간만 줄인다. 320px에서 22px·0.12em은 두 줄로 접혀 늘 붙어
     있는 띠를 한 줄만큼 더 키웠다. 크기를 되돌리는 대신 자간을 내준다. */
  .site-header .wordmark { letter-spacing: 0.02em; }
}

/* ── Print — 연보 and 글 상세 get read on paper §4.14, §5.7 ── */

/* §14.10 — 화면이 낮으면 면의 숨통이 먼저 양보한다. 판이 한 화면을 넘어서면
   여는 글은 문이 아니라 벽이 되고, 두 갈래의 높이도 다시 갈라진다. */
@media (max-height: 840px) {
  .gate-intro .inner { padding-block: var(--sp-3); }

  .gate-intro .section-label { margin-bottom: var(--sp-3); }

  .gate-intro .display { margin-bottom: var(--sp-4); }
}

/* 더 낮은 화면에서는 한 단계 더. 행간까지 좁히는 것은 여기가 마지막이다 —
   이 아래로는 시구나 부기를 잘라내야 하고, 그것은 조판이 아니라 삭제다. */
@media (max-height: 700px) {
  .gate-intro .inner { padding-block: var(--sp-2); }

  .gate-intro .hanmun { margin-bottom: var(--sp-2); }

  .gate-intro .note { line-height: 1.9; }
}

@media print {
  .site-header,
  .site-footer,
  .skip-link,
  .lightbox,
  .donate-button,
  .article-foot,
  .category-strip,
  .pager,
  .section-rail,
  .site-nav { display: none !important; }

  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
    line-height: 1.9;
  }

  main > * { margin-top: 0; }
  main > :last-child { margin-bottom: 0; }

  .container { max-width: none; padding: 0; }

  /* 먹지 does not print: on paper the 여는 글 is ink on the page like the rest,
     so every 먹지-면 colour underneath has to come back to black. */
  .gate-intro { background: #fff; min-height: 0; }
  .gate-intro, .gate-intro * { color: #000; }
  .gate-intro .inner { padding: 24pt 0; }

  .article-body > p,
  .article-body > blockquote,
  .chronology-row .entry,
  .image-figure figcaption { max-width: none; }

  .js .reveal { opacity: 1; }

  .timeline-row,
  .post-list-row,
  .media-row,
  .chronology-row,
  .def-row,
  .lead-figure,
  .image-figure { break-inside: avoid; }

  .article-layout.has-rail { display: block; }

  /* Paper does not scroll: a table left in its box would print with the last
     columns cut off. */
  .article-body .table-wrap {
    overflow: visible;
    margin-inline: 0;
    padding-inline: 0;
    max-width: none;
  }

  .article-table tr { break-inside: avoid; }

  .screen-title, .era-title, .article-head { break-after: avoid; }

  @page { margin: 18mm; }
}

/* ── Hero 한지 §14.26 — home-a-archive 시안 이식, §14.27에서 밝은 면으로 ── */

/* The entrance stands on 한지 under the dark band: the masthead scale stays,
   the dark field went back to the header and footer. The declaration's red
   field butts straight against it — 한지, 주홍, 먹지 stack as one plate. */
.hero-main {
  margin-top: 0;
  background: var(--paper);
}

.hero-main + .union-decl { margin-top: 0; }

.hero-main + * { margin-top: var(--sp-section-hero-end); }

.hero-main .hero {
  margin-top: 0;
  padding-top: 104px;
  padding-bottom: 104px;
}

.hero-main .section-label {
  display: flex;
  align-items: center;
  gap: 16px;
  color: var(--accent-text);
  margin-bottom: 44px;
}

.hero-main .section-label::before {
  content: "";
  width: 40px;
  height: 2px;
  background: var(--accent);
}

/* The longest line is the 8em name; the min() keeps it one line on any screen,
   the clamp keeps it inside the 720px column the desktop flex leaves. */
.hero-main .hero .display-title {
  font-weight: 800;
  font-size: min(clamp(44px, 5vw, 72px), calc((100vw - 2 * var(--gutter)) / 8));
  line-height: 1.16;
  letter-spacing: 0;
  margin-bottom: 0;
}

.hero-main .hero .display-title .epithet {
  display: inline-block;
  font: 400 clamp(19px, 1.8vw, 25px)/1.75 var(--serif);
  letter-spacing: 0.08em;
  color: var(--body);
  margin-bottom: 30px;
}

.hero-main .hero-portrait img {
  border: 1px solid var(--line);
  background: #fff;
}

@media (max-width: 719px) {
  .hero-main .hero {
    padding-top: 56px;
    padding-bottom: 72px;
  }

  .hero-main .section-label { margin-bottom: 32px; }
}

/* ── 창립 취지문 §14.27 — 붉은 면 하나, 나머지는 흰 면 ────── */

/* The vow stands on the site's one red field — a flat plate, no texture; the
   pledges and the full text read on the 먹지 below it, and that red-on-dark
   junction is what carries the section. Type does the ideology: hard edges,
   一二三, nothing else. */
.union-band {
  background: var(--accent);
  color: #fff;
  padding: 110px 0 100px;
}

.union-eyebrow {
  font: 500 var(--fs-label)/1 var(--sans);
  letter-spacing: 0.3em;
  color: #fff;
  margin: 0 0 36px;
}

.union-title {
  font: 800 clamp(38px, 3.6vw, 54px)/1.3 var(--serif);
  letter-spacing: 0;
  margin: 0;
}

/* The vow reads as the declaration's own voice: large 명조 against the red,
   held off the title by a white rule instead of white space alone. */
.union-vow {
  font: 400 clamp(23px, 2vw, 29px)/1.85 var(--serif);
  letter-spacing: 0.01em;
  max-width: 30em;
  margin: 56px 0 0;
  padding-top: 48px;
  border-top: 2px solid rgba(255, 255, 255, 0.55);
  text-wrap: pretty;
}

.union-field {
  background: var(--dark-bg);
  color: var(--dark-ink);
  padding: 100px 0 110px;
}

.union-pledges {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.union-pledges li {
  border: 1px solid #3a352c;
  padding: 36px 32px;
}

.union-pledges .num {
  display: block;
  font: 800 44px/1 var(--serif);
  color: var(--accent-dark);
}

.union-pledges p {
  font: var(--w-text) 15.5px/1.9 var(--sans);
  color: var(--dark-body);
  margin: 20px 0 0;
  text-wrap: pretty;
}

.union-full { margin-top: 72px; }

.union-full summary {
  display: inline-block;
  font: var(--w-text) 16.5px/1 var(--sans);
  letter-spacing: 0.14em;
  color: var(--dark-ink);
  border: 1px solid #4a4238;
  padding: 18px 36px;
  cursor: pointer;
  list-style: none;
}

.union-full summary::-webkit-details-marker { display: none; }

.union-full summary:hover,
.union-full[open] summary {
  border-color: var(--accent-dark);
  color: var(--accent-dark);
}

.union-fulltext {
  margin-top: 56px;
  max-width: 34em;
}

.union-fulltext p {
  font: var(--w-text) 16.5px/2.1 var(--sans);
  margin: 0 0 2em;
  text-wrap: pretty;
}

.union-fulltext p:last-child { margin-bottom: 0; }

.union-sign {
  font: var(--w-text) var(--fs-footer)/1 var(--sans);
  letter-spacing: 0.06em;
  color: var(--dark-body);
  margin: 72px 0 0;
  padding-top: 28px;
  border-top: 1px solid var(--line-dark);
}

.union-sign a {
  color: var(--dark-ink);
  border-bottom: 1px solid var(--line-dark);
}

.union-sign a:hover {
  color: var(--accent-dark);
  border-color: currentColor;
}

/* The global ring is --ink, invisible on the 먹지 field. */
.union-field :focus-visible { outline-color: var(--dark-ink); }

@media (max-width: 1023px) {
  .union-pledges { grid-template-columns: 1fr; }
}

@media (max-width: 719px) {
  .union-band { padding: 64px 0 60px; }

  .union-field { padding: 60px 0 72px; }

  .union-vow {
    margin-top: 40px;
    padding-top: 36px;
  }

  .union-pledges li { padding: 28px 24px; }

  .union-full { margin-top: 48px; }
}
