/* ============================================================
   Feeeiyuuu — humanist editorial design system.

   Swiss skeleton (flush left, meta-rail grid, functional
   uppercase labels) carried by publication typography: serif
   reading text, grotesque sans for wayfinding, warm paper
   ground, generous MUJI-style whitespace. One abstract organic
   composition on the home hero (ink plate, clay circle, sage
   arch) is the only illustration; beyond it no decoration, no
   animation, no dark mode.

   Every size in this file comes from the token scales below —
   don't introduce ad-hoc values, extend the scale instead.
   ============================================================ */

:root {
  color-scheme: light;

  /* ── Color tokens ──────────────────────────────────────────
     暖纸白底 + 暖墨，取自 Anthropic 主题（#FBF9F5 / #D87756 系）。
     中性色五级 + 一个陶土强调色；面性底色只有两个柔和有机 wash
     （陶土 --accent-wash / 鼠尾草 --wash-sage），不再加色。 */
  --bg: #fbf9f5;
  --text: #211d17;
  --soft: #3e3933;
  --muted: #7a7268;
  --faint: #a69d90;
  --line: #e9e3d8;
  --line-strong: #d3cabb;
  --link: #9c4a26;
  --link-hover: #7a3418;
  --accent-wash: #f1e4d8;
  --wash-sage: #e6e8d9;
  --code-bg: #f3efe6;
  --selection: #eeddd0;

  /* ── Spacing scale (8pt grid) ────────────────────────────── */
  --space-1: 0.25rem; /*   4px */
  --space-2: 0.5rem; /*   8px */
  --space-3: 0.75rem; /*  12px */
  --space-4: 1rem; /*  16px */
  --space-5: 1.5rem; /*  24px */
  --space-6: 2rem; /*  32px */
  --space-7: 2.5rem; /*  40px */
  --space-8: 3.5rem; /*  56px */
  --space-9: 4.5rem; /*  72px */
  --space-10: 6rem; /*  96px */
  --space-11: 7rem; /* 112px */

  /* ── Type scale ──────────────────────────────────────────── */
  --text-xs: 0.75rem; /* uppercase labels, kbd, hints */
  --text-sm: 0.875rem; /* nav, dates, footer, tags */
  --text-base: 1.05rem; /* reading text */
  --text-md: 1.35rem; /* lead, h3, section headings */
  --text-lg: 1.8rem; /* h2 */
  --text-xl: 2rem; /* h1 in body */
  --text-2xl: clamp(2.25rem, 5vw, 3.3rem); /* page titles */
  --text-display: clamp(2.75rem, 7vw, 5.25rem); /* article titles */
  --text-masthead: clamp(3.2rem, 9vw, 6.4rem); /* home nameplate */

  --leading-tight: 1.2; /* display */
  --leading-snug: 1.35; /* headings */
  --leading-body: 1.75; /* interface text */
  --leading-reading: 1.85; /* article prose */

  /* 只加载这三档字重；要用新档位先去 build.mjs 的 Google Fonts
     引用里加，否则浏览器会伪造字重。 */
  --w-regular: 400;
  --w-semibold: 600;
  --w-bold: 700;

  --tracking-tight: -0.01em; /* large serif titles */
  --tracking-caps: 0.06em; /* uppercase labels */

  /* ── Layout ──────────────────────────────────────────────── */
  --content: 43rem;
  --content-wide: 62rem;
  --rail: 10rem;

  /* ── Radius ──────────────────────────────────────────────────
     圆角只用于首页最近内容的 wash 卡片与其胶囊按钮，全站别处仍走
     直角。 */
  --radius-card: 0.875rem; /* 14px — recent cards */
  --radius-pill: 999px; /* CTA buttons */

  /* ── Font stacks ─────────────────────────────────────────────
     全套同族：思源宋体/黑体（Source Han）与 Source Serif 4 /
     Source Sans 3 / Source Code Pro 是 Adobe+Google 配对设计的
     超家族，x 高度和灰度互相咬合。阅读文字走衬线，导航、元信息
     等功能性文字走无衬线，代码走 Source Code Pro。 */
  --font-serif: "Source Serif 4", "Noto Serif SC", Georgia, "Songti SC",
    serif;
  --font-sans: "Source Sans 3", "Noto Sans SC", "Helvetica Neue", Arial,
    sans-serif;
  --font-mono: "Source Code Pro", ui-monospace, "SF Mono", "Menlo",
    "Consolas", monospace;
}

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

html {
  scroll-behavior: smooth;
}

body {
  min-height: 100vh;
  margin: 0;
  overflow-x: hidden;
  color: var(--text);
  background: var(--bg);
  font-family: var(--font-serif);
  font-size: 18px;
  line-height: var(--leading-body);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.search-lock {
  overflow: hidden;
}

::selection {
  background: var(--selection);
}

a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line-strong);
}

a:hover {
  color: var(--muted);
  text-decoration-color: currentColor;
}

p {
  margin: 0 0 var(--space-4);
}

img,
svg {
  display: block;
}

img {
  max-width: 100%;
}

button,
input {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

.skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 500;
  padding: var(--space-1) var(--space-3);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  color: var(--text);
  text-decoration: none;
  transform: translateY(-160%);
  transition: transform 150ms ease;
}

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

/* ── Top navbar (blog / code / article / category pages) ────
   Sits at the top of the content column so its edges line up with the
   content below: home + blog on the left, language on the right, with a
   thin light divider and generous vertical breathing room. */
.topbar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
  margin: 0 0 var(--space-9);
  padding-bottom: var(--space-5);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

/* Full-bleed divider lines: the content stays in the centered column, but the
   rule under the navbar / article title block spans the whole viewport
   width. (article-body used to get one too, but it always lands after
   whatever the last child is — the last paragraph, or now the footnotes
   list — which reads as a stray extra line, so it's been dropped.) */
.topbar,
.article-header {
  position: relative;
}

.topbar::after,
.article-header::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100vw;
  height: 1px;
  transform: translateX(-50%);
  background: var(--line);
}

/* The navbar's full-bleed rule is the one heavy Swiss stroke on every
   page; all other dividers stay hairlines. The article title rule matches
   it — a second, equally confident stroke closing the header block. */
.topbar::after,
.article-header::after {
  height: 3px;
  background: var(--text);
}

.topbar-nav {
  display: flex;
  gap: var(--space-5);
}

.topbar a {
  color: var(--soft);
  text-decoration: none;
}

.topbar a:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.topbar a.active {
  padding: 0.15rem 0.6rem;
  background: var(--accent-wash);
  color: var(--text);
  font-weight: var(--w-bold);
  text-decoration: none;
}

/* Right-hand tool cluster in the topbar: search trigger + language
   switch. The trigger is a <button> only semantically — visually it is
   the same bare text link as everything else in the bar. */
.topbar-tools {
  display: flex;
  align-items: baseline;
  gap: var(--space-5);
}

.search-trigger {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.search-trigger:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Home has no topbar: the same tool cluster sits fixed in the top-right
   corner. */
.home-tools {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  z-index: 20;
  display: flex;
  align-items: baseline;
  gap: var(--space-5);
}

.lang-switch {
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-decoration: none;
}

.lang-switch:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── Shell ─────────────────────────────────────────────────── */
.site-shell {
  width: min(calc(100% - 2.5rem), var(--content));
  margin: 0 auto;
  padding: var(--space-6) 0 var(--space-11);
}

/* Article and list pages: wider shell so the meta rail + main grid fits. */
.site-shell--wide {
  width: min(calc(100% - 2.5rem), var(--content-wide));
}

/* ── Home ──────────────────────────────────────────────────── */
/* Editorial front page on the wide shell. The nameplate spans the full
   column — a long wordmark can never collide with the hero figure. The
   full-bleed heavy rule closing the hero is the same confident stroke
   as .topbar::after / .article-header::after. */
.home-hero {
  position: relative;
  padding: var(--space-6) 0 var(--space-7);
  margin-bottom: var(--space-8);
}

.home-hero::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100vw;
  height: 3px;
  transform: translateX(-50%);
  background: var(--text);
}

.home-masthead {
  margin-bottom: var(--space-7);
}

.home-masthead h1 {
  margin: 0;
  font-size: var(--text-masthead);
  font-weight: var(--w-bold);
  line-height: 0.95;
  letter-spacing: var(--tracking-tight);
}

/* Under the masthead: contents list left, hero figure right. */
.home-hero-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
}

/* Cover story: the newest post, front-page style — uppercase kicker,
   serif headline, lead paragraph. */
.home-feature {
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--line);
}

/* Cover art for the lead story: full-bleed at the foot of the block, above the
   recent list, matching the article page's cover treatment (square corners,
   hairline frame). */
.home-feature-cover,
.home-feature-cover picture,
.home-feature-cover img {
  display: block;
}

.home-feature-cover {
  margin: var(--space-5) 0 0;
}

.home-feature-cover img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
}

.home-feature-kicker {
  margin: 0 0 var(--space-3);
  color: var(--link);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.home-feature-title {
  margin: 0 0 var(--space-3);
  font-size: clamp(2rem, 4.5vw, 3.4rem);
  font-weight: var(--w-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

.home-feature-title a {
  color: var(--text);
  text-decoration: none;
}

.home-feature-title a:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.home-feature-lead {
  margin: 0;
  max-width: var(--content); /* keep the lead at reading measure on the wide shell */
  color: var(--soft);
  font-size: var(--text-base);
}

/* Hero figure: the ink logo plate sits on the site's single abstract
   composition — a clay circle behind its top-right corner, a sage arch
   under its bottom-left. Square, circle, arch; nothing moves. */
.home-figure {
  position: relative;
  flex: 0 0 auto;
  width: clamp(9rem, 24vw, 13rem);
  margin: 0;
}

.home-figure img {
  width: 100%;
  height: auto;
}

.home-figure::before,
.home-figure::after {
  content: "";
  position: absolute;
  z-index: -1;
}

.home-figure::before {
  top: calc(-1 * var(--space-5));
  right: calc(-1 * var(--space-5));
  width: 72%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--accent-wash);
}

.home-figure::after {
  bottom: calc(-1 * var(--space-4));
  left: calc(-1 * var(--space-6));
  width: 64%;
  aspect-ratio: 2 / 1;
  border-radius: 999px 999px 0 0;
  background: var(--wash-sage);
}

@media (max-width: 34rem) {
  .home-hero-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-7);
  }
}

/* Contents list: a plain stack of serif links under the nameplate. */
.home-links {
  margin: 0;
  padding-left: 0;
  list-style: none;
}

.home-links li {
  margin: var(--space-3) 0;
  font-size: var(--text-md);
}

.home-links a {
  color: var(--text);
  text-decoration: none;
}

.home-links a:hover {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.home-section {
  margin-bottom: var(--space-8);
}

.home-section:last-child {
  margin-bottom: 0;
}

.section-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin: 0 0 var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--line);
}

.section-heading h2 {
  margin: 0;
  font-size: var(--text-md);
  font-weight: var(--w-bold);
}

.section-more {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  white-space: nowrap;
}

/* ── Post list (date + title) ──────────────────────────────── */
.post-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.post-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-4);
  padding: var(--space-3) 0;
}

.post-date {
  flex: 0 0 auto;
  width: 6.5rem;
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--w-regular);
  font-variant-numeric: tabular-nums;
}

.post-list li > a {
  color: var(--text);
  font-size: var(--text-md);
  font-weight: var(--w-regular);
  text-decoration: none;
}

.post-list li > a:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.post-kind {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--faint);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
}

.list-empty {
  color: var(--muted);
  font-style: italic;
}

/* ── Recent cards (home) ──────────────────────────────────────
   The homepage "最近内容" list rendered as warm wash panels: sans
   title + serif summary up top, a hairline meta block (date /
   category), and a filled pill CTA. Each card is a flex column so
   the meta + button pin to the foot and CTAs line up across a row
   of uneven summaries. This is the only carded surface on the site. */
.card-grid {
  display: grid;
  /* minmax(0,1fr) — not bare 1fr — so a long unbreakable token (e.g. a URL
     in a summary) can't blow one track wider than the others. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
}

.card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: var(--space-6) var(--space-5) var(--space-5);
  background: var(--accent-wash);
  border-radius: var(--radius-card);
}

.card-body {
  flex: 1 1 auto;
  margin-bottom: var(--space-7);
}

.card-title {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: var(--w-bold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

.card-title a {
  color: var(--text);
  text-decoration: none;
}

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

/* Uneven summaries would break the button baseline; clamp to keep
   cards close in height. */
.card-summary {
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
  overflow-wrap: anywhere;
  color: var(--soft);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}

.card-meta {
  margin: 0 0 var(--space-5);
}

.card-meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line-strong);
}

.card-meta dt {
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.card-meta dd {
  margin: 0;
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.card-cta {
  align-self: flex-start;
  padding: var(--space-2) var(--space-5);
  background: var(--text);
  color: var(--bg);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--w-semibold);
  text-decoration: none;
  border-radius: var(--radius-pill);
}

.card-cta:hover {
  background: var(--soft);
}

@media (max-width: 56rem) {
  .card-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 34rem) {
  .card-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Page header (collection / archive / tags / about) ─────── */
.page-header {
  margin-bottom: var(--space-6);
}

.page-header h1 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-2xl);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

.page-header p {
  margin: 0;
  color: var(--soft);
}

.page-meta {
  margin-top: var(--space-2);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* ── Archive ───────────────────────────────────────────────── */
.archive-year {
  margin-bottom: var(--space-6);
}

.archive-year-num {
  margin: 0 0 var(--space-3);
  font-size: var(--text-md);
  font-weight: var(--w-bold);
}

/* ── Tags index ────────────────────────────────────────────── */
.tag-index {
  margin: 0;
  padding: 0;
  list-style: none;
}

.tag-index li {
  padding: var(--space-1) 0;
}

.tag-index .tag-count {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.inline-tags {
  margin-top: var(--space-2);
}

.inline-tags a,
.inline-tags span {
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.inline-tags a {
  text-decoration: none;
}

.inline-tags a:hover {
  color: var(--link);
  text-decoration: underline;
}

/* ── Article ───────────────────────────────────────────────── */
/* Swiss grid: oversized flush-left serif title under the heavy navbar
   rule, then a two-column grid — uppercase meta rail on the left, body
   on the right. */
.article-header {
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-7);
}

.article-header h1 {
  margin: 0;
  font-size: var(--text-display);
  font-weight: var(--w-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

/* The same asymmetric grid carries article pages and list pages: meta
   rail in the left column, reading column on the right. */
.article-grid,
.page-grid {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}

.article-main,
.page-main {
  max-width: var(--content);
  min-width: 0;
}

.article-rail,
.page-rail {
  position: sticky;
  top: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border-left: 3px solid var(--link);
  padding-left: var(--space-4);
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* Actionable links in the rails step up one notch — zh category names
   at the xs label size are genuinely hard to read; labels, dates and
   counts stay xs. */
.article-rail a,
.page-rail a {
  color: var(--text);
  font-size: var(--text-sm);
  text-decoration: none;
}

.article-rail a:hover,
.page-rail a:hover {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.page-rail-label,
.page-rail-count {
  color: var(--muted);
}

.page-rail-count {
  margin-top: var(--space-2);
}

.page-rail a.active {
  padding: 0.15rem 0.5rem;
  margin-left: -0.5rem;
  background: var(--accent-wash);
  color: var(--text);
  text-decoration: none;
}

.entry-cover-article {
  margin: 0 0 var(--space-5);
}

.entry-cover-article img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
}

/* ── Article body (prose) ──────────────────────────────────── */
.article-body {
  font-size: var(--text-base);
  line-height: var(--leading-reading);
  padding-bottom: var(--space-8);
  overflow-wrap: break-word;
  /* CJK 排印增强，按引擎支持渐进生效：标点挤压（Chrome/Edge）、
     中西文自动四分空、行尾标点悬挂（Safari）。不支持的引擎忽略。 */
  text-spacing-trim: normal;
  text-autospace: normal;
  hanging-punctuation: allow-end;
}

.article-body p {
  text-indent: 0;
  text-wrap: pretty;
}

/* zh prose is set justified like print; en keeps its ragged right. */
:lang(zh) .article-body p {
  text-align: justify;
}

.article-body p.indent {
  text-indent: 2em;
}

.article-body h1,
.article-body h2,
.article-body h3,
.article-body h4 {
  margin: var(--space-7) 0 var(--space-4);
  font-weight: var(--w-semibold);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  scroll-margin-top: var(--space-5);
  text-wrap: balance;
  clear: both;
}

.article-body h1 {
  font-size: var(--text-xl);
}
.article-body h2 {
  margin-top: var(--space-8);
  font-size: var(--text-lg);
}

.article-body h3 {
  font-size: var(--text-md);
}
/* h4 is not a serif heading but a functional label — the same uppercase
   sans grammar as the rail and table headers. Sub-steps inside a numbered
   section ("Standard", "任务一 | …") read as specimen labels instead of
   bold text drowning in the prose. */
.article-body h4 {
  margin: var(--space-6) 0 var(--space-3);
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.article-body .article-lead {
  margin: 0 0 var(--space-6);
  color: var(--soft);
  font-size: var(--text-md);
  font-weight: var(--w-semibold);
  line-height: var(--leading-body);
}

.article-body ul,
.article-body ol {
  margin: var(--space-4) 0;
  padding-left: var(--space-5);
}

.article-body li {
  margin: var(--space-1) 0;
}

/* Terracotta list markers — the same single-accent grammar as the issue
   №, the rail border and the end mark. */
.article-body li::marker {
  color: var(--link);
  font-variant-numeric: tabular-nums;
}

.article-body a {
  color: var(--text);
  text-underline-offset: 0.15em;
}

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

.article-body code {
  padding: 0.1rem 0.35rem;
  background: var(--code-bg);
  font-family: var(--font-mono);
  font-size: 0.86em;
}

.article-body pre {
  margin: var(--space-5) 0;
  padding: var(--space-4);
  overflow: auto;
  background: var(--code-bg);
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.article-body pre code {
  padding: 0;
  background: none;
  font-size: inherit;
}

.article-body blockquote {
  margin: var(--space-5) 0;
  padding: 0.1rem 0 0.1rem var(--space-4);
  border-left: 3px solid var(--link);
  color: var(--soft);
  font-size: var(--text-md);
  font-style: italic;
}

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

/* CJK has no italics — synthetic obliquing just smears the glyphs. */
:lang(zh) .article-body blockquote {
  font-style: normal;
}

.article-body .callout {
  margin: var(--space-5) 0;
  padding: var(--space-3) var(--space-4);
  border-left: 2px solid var(--text);
  background: var(--code-bg);
}

.article-body .callout p {
  margin: var(--space-2) 0 0;
}

.article-body .callout p:first-child {
  margin-top: 0;
}

.article-body .callout-title {
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.article-body img {
  height: auto;
  margin: var(--space-5) 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
}

/* Section break: a short ink dash, flush left — the modernist stand-in
   for a full-width hairline or a centered asterisk. */
.article-body hr {
  width: var(--space-6);
  height: 2px;
  margin: var(--space-7) 0;
  border: 0;
  background: var(--text);
}

.article-body .footnote-ref a {
  padding: 0 0.15em;
  color: var(--link);
  text-decoration: none;
}

.article-body hr.footnotes-sep {
  position: relative;
  left: 50%;
  width: 100vw;
  height: 1px;
  transform: translateX(-50%);
  margin: var(--space-7) 0 var(--space-6);
  background: var(--line);
}

.article-body .footnotes {
  padding-left: var(--space-5);
  font-size: var(--text-sm);
  color: var(--soft);
}

.article-body .footnotes li {
  margin: var(--space-1) 0;
}

.article-body .footnote-backref {
  margin-left: var(--space-1);
  text-decoration: none;
}

.article-body .table-wrap {
  overflow-x: auto;
  margin: var(--space-5) 0;
}

/* Modernist data table: a heavy rule on top, hairlines between rows,
   no vertical borders, no fills — structure over decoration. */
.article-body table {
  width: 100%;
  border-collapse: collapse;
  border-top: 2px solid var(--text);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.article-body th,
.article-body td {
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}

.article-body th {
  border-bottom: 1px solid var(--line-strong);
  color: var(--soft);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-bold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
}

.article-body ul.task-list {
  padding-left: var(--space-1);
  list-style: none;
}

.article-body .task-item {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
}

.article-body del {
  color: var(--muted);
}

/* Editorial end mark: a small terracotta square closes the piece — the
   only place the accent color appears as a mark rather than a link. */
.article-end {
  width: var(--space-2);
  height: var(--space-2);
  margin-top: var(--space-6);
  background: var(--link);
  clear: both;
}

/* ── Rich media figures ────────────────────────────────────── */
.article-body .media {
  margin: var(--space-5) 0;
}

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

.article-body .media video,
.article-body .embed-frame {
  width: 100%;
  border: 1px solid var(--line);
  background: #000;
}

.article-body .media audio {
  width: 100%;
}

.article-body .embed-frame {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.article-body .embed-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

.article-body .html-embed-frame {
  width: 100%;
  /* Never taller than the small-screen viewport (minus room for the
     surrounding text), so an embed can't swallow a phone's whole screen. */
  height: min(480px, 80vh);
  overflow: hidden;
}

@media (max-width: 600px) {
  .article-body .html-embed-frame {
    height: min(400px, 70vh);
  }
}

.article-body .html-embed-frame iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

.article-body .media figcaption {
  margin-top: var(--space-2);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-align: left;
}

/* ── Figure variants (`![alt|wide]` …) ─────────────────────── */
/* wide: break out over the rail column to the full grid width. */
.article-body .media--wide {
  width: calc(100% + var(--rail) + var(--space-8));
  margin-left: calc(-1 * (var(--rail) + var(--space-8)));
}

/* full: bleed edge-to-edge across the viewport; the caption comes back
   to the shell's width so it stays anchored to the layout. */
.article-body .media--full {
  position: relative;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
}

.article-body .media--full img {
  border-left: 0;
  border-right: 0;
  border-radius: 0;
}

.article-body .media--full figcaption {
  width: min(calc(100% - 2.5rem), var(--content-wide));
  margin-left: auto;
  margin-right: auto;
}

/* left / right: small figure with text running around it. */
.article-body .media--left,
.article-body .media--right {
  width: min(45%, 16rem);
  margin-top: var(--space-2);
  margin-bottom: var(--space-4);
}

.article-body .media--left {
  float: left;
  margin-right: var(--space-5);
}

.article-body .media--right {
  float: right;
  margin-left: var(--space-5);
}

/* half: consecutive figures share one row (grouped at build time). */
.article-body .media-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin: var(--space-5) 0;
  align-items: start;
}

.article-body .media-row .media {
  margin: 0;
}

/* plain: borderless, for diagrams and transparent artwork.
   frame: a paper-tinted mat around screenshots that would otherwise
   bleed into the page ground. */
.article-body .media--plain img,
.article-body .media--frame img {
  border: 0;
}

.article-body .media--frame {
  padding: var(--space-4);
  background: var(--code-bg);
  border-radius: var(--radius-card);
}

/* ── Article footer: tags / prev-next / related ────────────── */
.article-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.article-tags .tag {
  color: var(--link-hover);
  background: var(--accent-wash);
  padding: 0.15rem 0.55rem;
  text-decoration: none;
}

.article-tags .tag:hover {
  color: var(--link-hover);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── Footer ────────────────────────────────────────────────── */
.site-footer {
  position: relative;
  margin-top: var(--space-10);
  padding: var(--space-6) 0;
  color: var(--link-hover);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
}

.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 100vw;
  height: 100%;
  transform: translateX(-50%);
  background: var(--accent-wash);
  z-index: -1;
}

.site-footer p {
  margin: 0 0 var(--space-1);
}

.footer-links {
  margin-top: var(--space-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

/* ── 404 ───────────────────────────────────────────────────── */
.not-found h1 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-display);
  font-weight: var(--w-bold);
}

.not-found-recent {
  margin-top: var(--space-6);
}

/* ── Search overlay ────────────────────────────────────────── */
.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 12vh var(--space-4) var(--space-4);
  background: rgba(33, 29, 23, 0.28);
  opacity: 0;
  pointer-events: none;
  transition: opacity 160ms ease;
}

.search-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.search-box {
  width: min(38rem, 100%);
  background: var(--bg);
  border: 1px solid var(--line-strong);
  box-shadow: 0 12px 40px rgba(33, 29, 23, 0.15);
}

.search-input-wrap {
  padding: var(--space-4);
  border-bottom: 1px solid var(--line);
}

.search-input {
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--font-sans);
  font-size: 1rem;
}

.search-results {
  max-height: 24rem;
  overflow: auto;
}

.search-result-item {
  display: block;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  text-decoration: none;
}

.search-result-item:last-child {
  border-bottom: 0;
}

.search-result-item:hover,
.search-result-item.active {
  background: var(--code-bg);
}

.search-result-item span {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.search-result-item h4 {
  margin: 0.15rem 0;
  font-size: var(--text-base);
  font-weight: var(--w-bold);
}

.search-result-item p {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.search-result-item mark {
  padding: 0 0.1em;
  background: var(--selection);
  color: inherit;
}

.search-empty {
  padding: var(--space-6) var(--space-4);
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  text-align: center;
}

.search-hint {
  padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--line);
  color: var(--faint);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  text-align: center;
}

kbd {
  padding: 0.05rem 0.3rem;
  border: 1px solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* ── Math (KaTeX) ──────────────────────────────────────────── */
.katex-display {
  margin: var(--space-5) 0;
  padding: var(--space-1) 0;
  overflow-x: auto;
  overflow-y: hidden;
}

/* ── Responsive ────────────────────────────────────────────── */
/* Below the wide-shell width the rail grids collapse: the rail becomes
   a horizontal meta row above the main column, and the article TOC is
   dropped (the piece itself is right there). */
@media (max-width: 56rem) {
  .article-grid,
  .page-grid {
    display: block;
  }

  .article-rail,
  .page-rail {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-5);
    margin-bottom: var(--space-6);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--line);
  }

  .page-rail-count {
    margin-top: 0;
  }

  /* No rail column to break out over. */
  .article-body .media--wide {
    width: 100%;
    margin-left: 0;
  }
}

@media (max-width: 600px) {
  body {
    font-size: 17px;
  }

  .site-shell {
    width: calc(100% - 1.75rem);
    padding-top: var(--space-5);
  }

  .post-list li {
    flex-wrap: wrap;
    gap: 0.15rem var(--space-4);
  }

  .post-date {
    width: auto;
  }

  .post-kind {
    display: none;
  }

  /* Small screens: floats and rows stack into the single column. */
  .article-body .media--left,
  .article-body .media--right {
    float: none;
    width: 100%;
    margin-left: 0;
    margin-right: 0;
  }

  .article-body .media-row {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── Print ─────────────────────────────────────────────────── */
/* Articles print like the publication they imitate: chrome gone, black
   ink on white paper, meta collapsed to one line above the text. */
@media print {
  .skip-link,
  .home-tools,
  .topbar,
  .search-overlay,
  .site-footer,
  .page-rail {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }

  .site-shell,
  .site-shell--wide {
    width: auto;
    padding: 0;
  }

  .article-grid,
  .page-grid {
    display: block;
  }

  .article-rail {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-5);
    margin-bottom: var(--space-6);
  }

  .article-header::after {
    display: none;
  }

  .article-body pre {
    white-space: pre-wrap;
    overflow: visible;
  }

  .article-body a {
    text-decoration: none;
  }

  .article-body .media--wide,
  .article-body .media--full {
    position: static;
    width: 100%;
    margin-left: 0;
    transform: none;
  }
}
