/* ==========================================================================
   shikibe's blog — 站点样式
   --------------------------------------------------------------------------
   方向：Precision & Density 的骨架 + 编辑设计的排版。
   深度策略：borders-only（全程一种，不用阴影）。
   签名元素：卡片目录 —— 每条记录是一行「编号 + 日期 + 标题 + 摘要」，
             靠顶部一条发丝线分隔，不用边框盒。

   令牌命名刻意避开 --gray-700 / --surface-2 这类通用名：
   --paper / --ink / --rule / --vermilion 描述的是「纸、墨、栏线、朱砂」，
   读到变量名就知道这是什么产品。
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. 设计令牌
   -------------------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* — 纸面：三级表面，靠亮度差分层，不用阴影 — */
  --paper: #f7f4ec;        /* 页面底 —— 稿纸米白 */
  --paper-raised: #fdfcf8; /* 卡片 / 抬起面 */
  --paper-sunk: #efebdf;   /* 输入框 / 凹陷面 */

  /* — 墨色：四级文字，全部通过 WCAG AA —
       --ink-4 只用于禁用态，当前没有禁用控件，保留备用。 — */
  --ink: #1c1a16;          /* 正文        15.81:1 */
  --ink-2: #4a463d;        /* 次级         8.55:1 */
  --ink-3: #6e6a5f;        /* 三级 / 元信息 4.91:1 */
  --ink-4: #97928a;        /* 仅禁用态，不承载信息 */

  /* — 栏线：装饰发丝刻意极轻（1.25:1），
       控件边框单独给值以满足 WCAG 2.2 非文字 3:1 — */
  --rule: #e2dccc;         /* 装饰发丝  1.25:1 */
  --rule-strong: #c9c2ae;  /* 强调分隔  1.62:1 */
  --control-line: #8c867a; /* 控件边框  3.52:1 —— 中性暖灰，不用原来的橄榄卡其 */

  /* — 朱砂：唯一强调色。只用于活跃项、编号、链接、主按钮 — */
  --vermilion: #b4432b;    /* 5.06:1 */
  --vermilion-deep: #97371f;
  --vermilion-wash: rgba(180, 67, 43, 0.07);
  /* 悬停提亮：刻意不带色相。
     用朱砂做悬停底，在深色中性底上会变成一块脏棕。 */
  --hover: rgba(28, 26, 22, 0.045);

  /* — 语义色（克制使用，仅状态提示） — */
  --signal-ok: #2f6b45;
  --signal-warn: #8a5a1a;

  /* — 字体：两个族，分工明确。没有第三个 — */
  --serif: "Noto Serif SC", "Songti SC", "Source Han Serif SC", Georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* — 字号：Major Third (1.25)，16px 基数 —
       完整音阶。个别档位当前没有组件用到（--t-h1 / --t-meta），
       保留是为了改版时不用重新推音阶。 — */
  --t-micro: 11px;   /* 编号、标签 */
  --t-meta: 12px;    /* 日期、计数 */
  --t-small: 13px;   /* 辅助文字 */
  --t-body: 16px;    /* 正文 */
  --t-lead: 18px;    /* 导语 */
  --t-h3: 20px;
  --t-h2: 25px;
  --t-h1: 31px;
  --t-display: clamp(31px, 4.6vw, 50px);

  /* — 字距：字号越大字距越紧 — */
  --track-display: -0.022em;
  --track-heading: -0.012em;
  --track-label: 0.14em;

  /* — 行高 — */
  --lead-tight: 1.22;
  --lead-snug: 1.42;
  --lead-body: 1.75;
  --lead-loose: 1.9;

  /* — 间距：4px 基数 — */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s8: 32px;
  --s10: 40px;
  --s12: 48px;
  --s16: 64px;
  --s20: 80px;
  --s24: 96px;

  /* — 圆角：小。技术感来自方角，不是大圆角 — */
  --r-xs: 2px;
  --r-sm: 3px;
  --r-md: 5px;

  /* — 控件：全站统一高度，消除「尺寸形状不统一」 — */
  --control-h: 36px;
  --control-h-lg: 40px;

  /* — 布局 — */
  --sheet: 1080px;
  --sheet-wide: 1240px;
  --masthead-h: 60px;

  /* — 动效 — */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --dur-fast: 120ms;
  --dur: 180ms;
  --dur-slow: 260ms;
  /* 入场：整个页面 0.2s 走完。分档错开 40ms，
     最慢的一档 3×40 + 200 = 320ms，视觉上尾巴几乎察觉不到。 */
  --dur-enter: 200ms;
  --stagger: 40ms;

  /* — 层级 — */
  --z-sticky: 50;
  --z-tools: 60;
  --z-drawer: 80;
  --z-skip: 100;
}

html[data-theme="dark"] {
  color-scheme: dark;

  /* 深色不是「把浅色反过来」，是另起一套。
     三条修正：
       1) 底色从 45° 暖黄褐（读作脏棕）改成中性偏暖（饱和度 5%）
       2) 底→卡亮度比从 1.07:1 提到 1.11:1 —— 原来的层级等于不存在
       3) 朱砂饱和 60% → 51%。暗底上高饱和暖色会发光刺眼 */
  --paper: #131312;
  --paper-raised: #1e1e1c;
  --paper-sunk: #0e0e0d;

  --ink: #ece9e2;          /* 15.33:1 */
  --ink-2: #b4b1a8;        /*  8.67:1 */
  --ink-3: #8c8981;        /*  5.32:1 */
  --ink-4: #5e5c56;

  --rule: #2b2b27;         /* 装饰发丝 */
  --rule-strong: #3e3e38;  /* 强调分隔 */
  --control-line: #6a6a62; /* 控件边框 3.13:1 on 卡片 */

  --vermilion: #c97863;    /* 5.16:1 on 卡片 */
  --vermilion-deep: #dd8a74;
  --vermilion-wash: rgba(201, 120, 99, 0.1);
  --hover: rgba(255, 255, 255, 0.045);

  --signal-ok: #7fb894;
  --signal-warn: #cfa964;
}

/* --------------------------------------------------------------------------
   2. 基础
   -------------------------------------------------------------------------- */

/* 跳转到主内容。每页第一个可聚焦元素 —— 键盘用户不必逐个 Tab 过 10 项导航。
   平时在视口外，聚焦时滑入。 */
.skip-link {
  /* 必须是 fixed 而不是 absolute：
     absolute 相对文档定位，页面滚动后再聚焦，它会出现在文档顶部（已经滚过去了），
     等于看不见。fixed 才始终贴在视口顶部。 */
  position: fixed;
  left: var(--s3);
  top: calc(-1 * var(--s16));
  z-index: var(--z-skip);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--vermilion);
  border-radius: var(--r-sm);
  background: var(--paper-raised);
  font-size: 13px;
  color: var(--ink);
  transition: top var(--dur) var(--ease-out);
}
.skip-link:focus { top: var(--s3); }

/* 锚点跳转时目标不要被吸顶报头盖住。
   报头高 60px，这里留出报头 + 一段呼吸距离。
   ⚠️ 缺这条时，点文章页侧栏的目录链接，标题会被压在报头下面。 */
[id] { scroll-margin-top: calc(var(--masthead-h) + var(--s5)); }
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t-body);
  line-height: var(--lead-body);
  overflow-x: hidden;
  transition: background-color var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease);
}

/* 纸纹：2.4% 不透明度的噪声，抵掉纯色的塑料感。
   用 160×160 的可平铺 SVG，成本远低于整屏滤镜。
   深色下要压得更低：同样的绝对噪声，在低亮度背景上会显成脏点。 */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.024;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}
html[data-theme="dark"] body::before { opacity: 0.014; }

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 0; }

::selection { background: var(--vermilion); color: var(--paper); }

:focus-visible {
  outline: 2px solid var(--vermilion);
  outline-offset: 2px;
}
:focus:not(:focus-visible) { outline: none; }

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

/* 小字号通用件 */
.label {
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* --------------------------------------------------------------------------
   3. 外壳
   -------------------------------------------------------------------------- */
.shell {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* 3.1 报头 —— 实色纸面 + 一条发丝底边。没有毛玻璃。 */
.masthead {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.masthead__inner {
  width: 100%;
  max-width: var(--sheet);
  margin: 0 auto;
  height: var(--masthead-h);
  padding: 0 var(--s6);
  display: flex;
  align-items: center;
  gap: var(--s6);
}

.masthead__brand {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s2);
  flex: 0 0 auto;
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.masthead__brand span {
  font-style: normal;
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  color: var(--ink-3);
  text-transform: uppercase;
}

.masthead__nav {
  display: flex;
  gap: var(--s6);
  min-width: 0;
  font-size: 15px;
}
.masthead__nav a {
  position: relative;
  padding: var(--s1) 0;
  white-space: nowrap;
  color: var(--ink-2);
  transition: color var(--dur-fast) var(--ease);
}
.masthead__nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--vermilion);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease-out);
}
.masthead__nav a:hover { color: var(--ink); }
.masthead__nav a:hover::after { transform: scaleX(1); }
.masthead__nav a[aria-current="page"] { color: var(--vermilion); }
.masthead__nav a[aria-current="page"]::after { transform: scaleX(1); }

.masthead__tools {
  display: flex;
  align-items: center;
  gap: var(--s1);
  margin-left: auto;
  flex: 0 0 auto;
}

/* 3.2 图标按钮定义见 §8 控件（统一高度与圆角） */

/* 3.3 移动端抽屉
   ⚠️ 选择器必须写 .iconbtn.drawer-trigger：§9 的 .iconbtn { display: inline-flex }
   与本条同优先级，靠后定义会覆盖掉 display:none，导致汉堡按钮在桌面端也显示。 */
.iconbtn.drawer-trigger { display: none; }
.drawer { display: none; }

@media (max-width: 1100px) {
  .masthead__nav { gap: var(--s4); font-size: 14px; }
}
@media (max-width: 960px) {
  .masthead__nav { display: none; }
  .iconbtn.drawer-trigger { display: inline-flex; margin-left: auto; }
  .masthead__tools { margin-left: 0; }

  .drawer {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    flex-direction: column;
    padding: var(--s16) var(--s6) var(--s6);
    background: var(--paper);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--dur) var(--ease), visibility var(--dur) var(--ease);
  }
  .drawer.is-open { opacity: 1; visibility: visible; }
  .drawer__close { position: absolute; top: var(--s3); right: var(--s3); }
  .drawer a {
    font-size: 24px;
    padding: var(--s4) 0;
    border-bottom: 1px solid var(--rule);
    color: var(--ink-2);
  }
  .drawer a[aria-current="page"] { color: var(--vermilion); }
}
body.drawer-open { overflow: hidden; }

/* 3.4 页脚 —— 版本记录页（colophon）的写法 */
.colophon {
  margin-top: auto;
  border-top: 1px solid var(--rule);
  padding: var(--s8) var(--s6) var(--s12);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.colophon__inner {
  max-width: var(--sheet);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s6);
  justify-content: space-between;
}
.colophon a { border-bottom: 1px solid var(--rule-strong); }
.colophon a:hover { color: var(--vermilion); border-color: var(--vermilion); }

/* --------------------------------------------------------------------------
   4. 页面骨架
   -------------------------------------------------------------------------- */
.sheet {
  width: 100%;
  max-width: var(--sheet);
  margin: 0 auto;
  padding: var(--s16) var(--s6) var(--s20);
}
.sheet--wide { max-width: var(--sheet-wide); }

/* 页码头：编号 + 标题 + 一条通栏发丝线 */
.folio { margin-bottom: var(--s10); }
.folio__num {
  display: block;
  margin-bottom: var(--s3);
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--vermilion);
}
.folio__title {
  margin: 0 0 var(--s3);
  max-width: 20ch;
  font-size: var(--t-display);
  font-weight: 600;
  line-height: var(--lead-tight);
  letter-spacing: var(--track-display);
  /* 让浏览器自己平衡断行，不要用硬编码 <br> —— 硬断行在窄屏会撑破 */
  text-wrap: balance;
}
.folio__desc {
  margin: 0;
  max-width: 62ch;
  font-size: var(--t-lead);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}
.folio__rule { margin-top: var(--s8); }

/* 章节标记：等宽小字 + 一条引到右端的发丝线 */
.section-mark {
  display: flex;
  /* 必须是 center。空伪元素没有真正的基线，用 baseline 会让那条线
     落在文字基线上，看着像删除线。 */
  align-items: center;
  gap: var(--s4);
  margin: var(--s10) 0 var(--s3);
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.section-mark::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.section-mark:first-child { margin-top: 0; }

/* 分栏：左侧内容 + 右侧边栏。非对称，不居中。 */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 268px;
  gap: var(--s16);
  align-items: start;
}

@media (max-width: 900px) {
  .split { grid-template-columns: minmax(0, 1fr); gap: var(--s10); }
}

/* 边栏 */
.margin-col { display: flex; flex-direction: column; gap: var(--s8); }
.margin-note {
  padding-left: var(--s4);
  border-left: 2px solid var(--rule-strong);
}
.margin-note__title {
  margin: 0 0 var(--s3);
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.margin-note p {
  margin: 0 0 var(--s3);
  font-size: var(--t-small);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}
.margin-note p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   5. 签名组件：卡片目录
   -------------------------------------------------------------------------- */
.catalog { border-bottom: 1px solid var(--rule); }

/* 一行记录：编号列 + 内容列，靠顶部发丝线分隔 */
.entry {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: var(--s6);
  padding: var(--s5) var(--s3) var(--s5) 0;
  border-top: 1px solid var(--rule);
  transition: background-color var(--dur-fast) var(--ease);
}
.entry:hover { background: var(--hover); }

.entry__meta {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  padding-top: var(--s1);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: 0.03em;
  color: var(--ink-3);
}
.entry__no { color: var(--vermilion); font-weight: 500; }

.entry__title {
  margin: 0 0 var(--s2);
  font-size: var(--t-h3);
  font-weight: 600;
  line-height: var(--lead-snug);
  letter-spacing: var(--track-heading);
  transition: color var(--dur-fast) var(--ease);
}
.entry:hover .entry__title { color: var(--vermilion); }

.entry__excerpt {
  margin: 0;
  font-size: var(--t-small);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}

@media (max-width: 640px) {
  /* 窄屏点线引导会被压成 24px 的碎点，不如不要 */
  .ledger__leader { display: none; }
  .ledger__row { flex-wrap: wrap; }
  .entry { grid-template-columns: minmax(0, 1fr); gap: var(--s2); padding-right: 0; }
  .entry__meta { flex-direction: row; gap: var(--s3); padding-top: 0; }
}

/* 头条：卡片目录的放大版 */
.lead-entry {
  display: block;
  padding: var(--s8) 0 var(--s10);
  border-top: 2px solid var(--ink);
}
.lead-entry__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s4);
  margin-bottom: var(--s5);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.lead-entry__title {
  margin: 0 0 var(--s5);
  max-width: 22ch;
  font-size: clamp(28px, 4vw, 42px);
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: var(--track-display);
  transition: color var(--dur-fast) var(--ease);
}
.lead-entry:hover .lead-entry__title { color: var(--vermilion); }
.lead-entry__excerpt {
  margin: 0;
  max-width: 58ch;
  font-size: var(--t-lead);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   6. 账本：点线引导的索引行（归档页）
   -------------------------------------------------------------------------- */
.ledger { border-bottom: 1px solid var(--rule); }
.ledger__row {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding: var(--s3) var(--s3) var(--s3) 0;
  border-top: 1px solid var(--rule);
  transition: background-color var(--dur-fast) var(--ease);
}
.ledger__row:hover { background: var(--hover); }
.ledger__date {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.ledger__title {
  /* 必须是 0 1 auto + min-width:0。写成 0 0 auto 时中文长标题
     不收缩，窄屏直接溢出被 overflow-x:hidden 裁掉。 */
  flex: 0 1 auto;
  min-width: 0;
  font-size: var(--t-small);
  transition: color var(--dur-fast) var(--ease);
}
.ledger__row:hover .ledger__title { color: var(--vermilion); }
.ledger__leader {
  flex: 1 1 auto;
  min-width: var(--s6);
  border-bottom: 1px dotted var(--rule-strong);
  /* 不要加 translateY 抬升。.ledger__row 是 align-items:baseline，
     空元素的基线就是它的下外边距边缘 —— 所以 border-bottom 本来
     就正好落在文字基线上。再抬 4px 就跑到文字腰部了。 */
}
.ledger__tag {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: var(--t-micro);
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   7. 索引卡 / 图版
   -------------------------------------------------------------------------- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  gap: var(--s6);
}

.index-card {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  padding: var(--s5);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: var(--paper-raised);
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur) var(--ease-out);
}
.index-card:hover { border-color: var(--control-line); transform: translateY(-2px); }
.index-card__no {
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: var(--track-label);
  color: var(--vermilion);
}
.index-card__title {
  margin: 0;
  font-size: var(--t-lead);
  font-weight: 600;
  line-height: var(--lead-snug);
  letter-spacing: var(--track-heading);
}
.index-card__desc {
  margin: 0;
  flex: 1;
  font-size: var(--t-small);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}
.index-card__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  padding-top: var(--s3);
  border-top: 1px solid var(--rule);
}

/* 图版：图像带框 + 下方等宽图注 */
.plate { display: block; }
.plate__frame {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: var(--paper-sunk);
}
.plate__frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.plate:hover .plate__frame img { transform: scale(1.03); }
.plate__frame--wide { aspect-ratio: 16 / 9; }
.plate__count {
  position: absolute;
  left: var(--s3); bottom: var(--s3);
  padding: 3px var(--s2);
  border-radius: var(--r-xs);
  background: var(--paper-raised);
  font-family: var(--mono);
  font-size: var(--t-micro);
  color: var(--ink-2);
}
.plate__caption {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding-top: var(--s3);
}
.plate__title {
  margin: 0;
  font-size: var(--t-body);
  font-weight: 600;
  transition: color var(--dur-fast) var(--ease);
}
.plate:hover .plate__title { color: var(--vermilion); }
.plate__date {
  font-family: var(--mono);
  font-size: var(--t-micro);
  color: var(--ink-3);
}
.plate__desc {
  margin: var(--s1) 0 0;
  font-size: var(--t-small);
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   8. 骨架屏
   形状必须和真实组件一一对应 —— 通用转圈圈等于没做。
   用法见 §「骨架屏」文档；JS 侧提供 Skeleton.show(el, variant, count)。
   -------------------------------------------------------------------------- */
.sk {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xs);
  background: var(--rule);
}
.sk::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 50%;
  background: linear-gradient(90deg, transparent 0%, var(--paper-raised) 50%, transparent 100%);
  /* 用 transform 而不是 background-position：
     后者每帧都要重绘整块渐变，前者只走合成层。 */
  animation: sk-sweep 1.4s ease-in-out infinite;
}
@keyframes sk-sweep {
  from { transform: translateX(-100%); }
  to { transform: translateX(300%); }
}

/* 原子块 */
.sk-line { height: 12px; }
.sk-line--short { width: 40%; }
.sk-line--mid { width: 72%; }
.sk-title { height: 20px; width: 62%; }
.sk-meta { height: 10px; width: 52px; }
.sk-media { aspect-ratio: 4 / 3; border-radius: var(--r-sm); }

/* 目录行骨架 —— 与 .entry 同栅格，切换时不跳动 */
.sk-entry {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  gap: var(--s6);
  padding: var(--s5) var(--s3) var(--s5) 0;
  border-top: 1px solid var(--rule);
}
.sk-entry__meta { display: flex; flex-direction: column; gap: var(--s2); padding-top: var(--s1); }
.sk-entry__body { display: flex; flex-direction: column; gap: var(--s3); }

/* 索引卡骨架 —— 与 .index-card 同盒模型 */
.sk-card {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  padding: var(--s5);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: var(--paper-raised);
}

/* 图版骨架 */
.sk-plate { display: flex; flex-direction: column; gap: var(--s3); }

/* 正文骨架 —— 段落用不等宽行，模仿真实断行 */
.sk-prose { display: flex; flex-direction: column; gap: var(--s3); }
.sk-prose .sk-line:nth-child(3n) { width: 88%; }
.sk-prose .sk-line:nth-child(4n) { width: 64%; }

@media (max-width: 640px) {
  .sk-entry { grid-template-columns: minmax(0, 1fr); gap: var(--s3); padding-right: 0; }
  .sk-entry__meta { flex-direction: row; gap: var(--s3); padding-top: 0; }
}

/* 减少动效时停掉扫光，留静态灰块 —— 骨架屏的意义是「占位」不是「动」 */
@media (prefers-reduced-motion: reduce) {
  .sk::after { animation: none; background: none; }
}

/* --------------------------------------------------------------------------
   9. 控件
   统一规则：所有控件同高（--control-h）、同圆角（--r-sm）、同边框色。
   按钮文字用衬线，不用等宽大写 —— 等宽大写只留给真正的元信息（日期/编号）。
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  height: var(--control-h);
  padding: 0 var(--s4);
  border: 1px solid var(--control-line);
  border-radius: var(--r-sm);
  background: var(--paper-raised);
  font-family: var(--serif);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  color: var(--ink);
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}
/* 悬停要有实感：底色 + 边框同时变，不能只换个字色 */
.btn:hover {
  background: var(--paper-sunk);
  border-color: var(--ink-3);
}
.btn:active { background: var(--rule); }

.btn--solid {
  background: var(--vermilion);
  border-color: var(--vermilion);
  color: var(--paper);
}
.btn--solid:hover {
  background: var(--vermilion-deep);
  border-color: var(--vermilion-deep);
  color: var(--paper);
}
.btn--solid:active { background: var(--vermilion-deep); }

.btn--ghost {
  border-color: transparent;
  background: transparent;
}
.btn--ghost:hover {
  border-color: var(--rule);
  background: var(--paper-raised);
}

/* 输入框：凹陷面 + 合规边框 + 聚焦光环 */
.field { position: relative; display: block; }
.field input {
  width: 100%;
  height: var(--control-h-lg);
  appearance: none;
  -webkit-appearance: none;
  padding: 0 var(--s3);
  border: 1px solid var(--control-line);
  border-radius: var(--r-sm);
  background: var(--paper-sunk);
  font-family: var(--serif);
  font-size: 14px;
  transition:
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease);
}
.field input::placeholder { color: var(--ink-3); }
.field input:hover { border-color: var(--ink-3); }
.field input:focus {
  outline: none;
  border-color: var(--vermilion);
  background: var(--paper-raised);
  box-shadow: 0 0 0 3px var(--vermilion-wash);
}
.field__icon {
  position: absolute;
  top: 50%; left: var(--s3);
  transform: translateY(-50%);
  display: flex;
  color: var(--ink-3);
  pointer-events: none;
}
.field__icon svg { width: 16px; height: 16px; }
.field--icon input { padding-left: var(--s10); }

/* 筛选标签：与按钮同高、同圆角，方角不是胶囊 */
.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chip {
  display: inline-flex;
  align-items: center;
  height: var(--control-h);
  padding: 0 var(--s3);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: transparent;
  font-family: var(--serif);
  font-size: 13px;
  line-height: 1;
  color: var(--ink-2);
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}
.chip:hover {
  background: var(--paper-raised);
  border-color: var(--ink-3);
  color: var(--ink);
}
.chip.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* 行内标签：这里保留等宽 —— 标签本身就是元信息 */
.tag {
  display: inline-block;
  padding: 2px var(--s2);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-xs);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: 0.03em;
  color: var(--ink-3);
}

/* 图标按钮：与按钮同高，44px 触达区 */
.iconbtn {
  width: var(--control-h);
  height: var(--control-h);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  transition:
    color var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease);
}
.iconbtn:hover { color: var(--ink); background: var(--paper-sunk); }
.iconbtn svg { width: 17px; height: 17px; }

/* 工具条：列表页的搜索 + 筛选，位置固定在页头之下 */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3);
  padding-bottom: var(--s5);
  border-bottom: 1px solid var(--rule);
}
.toolbar__search { flex: 1 1 260px; max-width: 380px; }

/* 空状态 */
.blank {
  padding: var(--s10) 0;
  /* 左对齐，不居中。全站都是左对齐 + 左侧栏线节奏，
     中间冒出一段居中文字会像是没对齐。 */
  text-align: left;
  /* 只留下边框。上边框会和上方区块的下边框形成「两条平行线夹一片空白」，
     看起来像渲染错误。 */
  border-bottom: 1px solid var(--rule);
}
.blank__title {
  margin: 0 0 var(--s2);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.blank__desc { margin: 0; font-size: var(--t-small); color: var(--ink-2); }

/* 画布类留白仍然居中 —— 那块的语义是「一块待挂载的区域」，
   居中读起来才对。 */
.blank--tall {
  padding: var(--s24) var(--s6);
  text-align: center;
}

/* --------------------------------------------------------------------------
   10. 正文排版
   -------------------------------------------------------------------------- */
.article__head {
  padding-bottom: var(--s6);
  margin-bottom: var(--s8);
  border-bottom: 1px solid var(--rule);
}
.article__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s4);
  margin-bottom: var(--s5);
  font-family: var(--mono);
  font-size: var(--t-micro);
  letter-spacing: 0.05em;
  color: var(--ink-3);
}
.article__title {
  margin: 0 0 var(--s5);
  font-size: clamp(27px, 3.6vw, 38px);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: var(--track-display);
}
.article__standfirst {
  margin: 0;
  font-size: var(--t-lead);
  line-height: var(--lead-snug);
  color: var(--ink-2);
}

.prose { font-size: var(--t-body); line-height: var(--lead-body); }
.prose > :first-child { margin-top: 0; }
.prose > * + * { margin-top: 1.15em; }
.prose h2 {
  margin-top: 2.1em;
  font-size: var(--t-h2);
  font-weight: 600;
  line-height: var(--lead-tight);
  letter-spacing: var(--track-heading);
}
.prose h2::before {
  content: "";
  display: block;
  width: var(--s8);
  margin-bottom: var(--s4);
  border-top: 2px solid var(--vermilion);
}
.prose h3 {
  margin-top: 1.7em;
  font-size: var(--t-h3);
  font-weight: 600;
  letter-spacing: var(--track-heading);
}
.prose a { color: var(--vermilion); border-bottom: 1px solid var(--vermilion); }
.prose a:hover { background: var(--vermilion-wash); }
.prose strong { font-weight: 600; }
.prose code {
  padding: 1px var(--s1);
  border: 1px solid var(--rule);
  border-radius: var(--r-xs);
  background: var(--paper-sunk);
  font-family: var(--mono);
  font-size: 0.86em;
}
.prose pre {
  padding: var(--s4);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  background: var(--paper-sunk);
  overflow-x: auto;
  font-family: var(--mono);
  font-size: var(--t-small);
  line-height: 1.65;
}
.prose pre code { padding: 0; border: 0; background: none; }
.prose blockquote {
  margin: 0;
  padding: var(--s2) 0 var(--s2) var(--s5);
  border-left: 2px solid var(--vermilion);
  color: var(--ink-2);
}
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li + li { margin-top: 0.4em; }
.prose img { border: 1px solid var(--rule); border-radius: var(--r-sm); }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.prose th, .prose td {
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--rule);
  text-align: left;
}
.prose th {
  border-bottom: 1px solid var(--control-line);
  font-family: var(--mono);
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.prose figure { margin: 0; }
.prose figcaption {
  margin-top: var(--s2);
  font-family: var(--mono);
  font-size: var(--t-micro);
  color: var(--ink-3);
}

/* 事实表（关于页 / 详情页侧栏） */
.facts { display: flex; flex-direction: column; }
.facts__row {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--t-small);
}
.facts__row:last-child { border-bottom: 0; }
.facts__k { color: var(--ink-3); flex: 0 0 auto; }
.facts__v {
  color: var(--ink);
  text-align: right;
  /* 长值（URL / 长标题）不设 min-width:0 会把左侧的键挤出容器 */
  min-width: 0;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   11. 浮动工具条
   整条显隐，不是隐藏其中一个按钮 —— 用 opacity 藏按钮会留下空槽位，
   看起来像坏掉的控件。滚动 400px 后由 JS 加 .is-shown。
   -------------------------------------------------------------------------- */
.tools {
  position: fixed;
  left: var(--s5);
  bottom: var(--s5);
  z-index: var(--z-tools);
  display: flex;
  padding: var(--s1);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background: var(--paper-raised);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  animation: fade-in var(--dur-enter) var(--ease-out) both;
  transition:
    opacity var(--dur) var(--ease),
    visibility var(--dur) var(--ease),
    transform var(--dur) var(--ease-out);
}
.tools.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
}
.tools .iconbtn { width: 34px; height: 34px; }

@media (max-width: 960px) {
  .tools { left: var(--s3); bottom: var(--s3); }
}

/* --------------------------------------------------------------------------
   12. 骨架模式：按 G 给所有 data-slot 描边
   -------------------------------------------------------------------------- */
html.show-slots [data-slot] {
  position: relative;
  outline: 1px dashed var(--vermilion);
  outline-offset: 2px;
}
html.show-slots [data-slot]::after {
  content: attr(data-slot);
  position: absolute;
  top: 0; left: 0;
  z-index: 5;
  padding: 1px 5px;
  border-radius: 0 0 var(--r-xs) 0;
  background: var(--vermilion);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   13. 无 JS 兜底
   -------------------------------------------------------------------------- */
.noscript-bar {
  position: relative;
  z-index: 10;
  padding: var(--s3) var(--s6);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-sunk);
  font-family: var(--mono);
  font-size: var(--t-micro);
  line-height: 1.9;
  color: var(--ink-2);
}
.noscript-bar strong { font-weight: 500; margin-right: var(--s3); color: var(--ink); }
.noscript-bar a {
  margin-right: var(--s3);
  color: var(--vermilion);
  border-bottom: 1px solid var(--vermilion);
}

/* --------------------------------------------------------------------------
   14. 动效
   -------------------------------------------------------------------------- */

/* 入场：淡入 + 8px 上浮。不用缩放、不用模糊 ——
   那是「弹出来」的观感，和纸的质感冲突。纸是「落下来」的。 */
@keyframes enter {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* 正文按块错开入场。只给前四块排延迟，
   更靠后的内容基本都在首屏之外，排了也看不到。 */
.sheet > * { animation: enter var(--dur-enter) var(--ease-out) both; }
.sheet > *:nth-child(2) { animation-delay: var(--stagger); }
.sheet > *:nth-child(3) { animation-delay: calc(var(--stagger) * 2); }
.sheet > *:nth-child(4) { animation-delay: calc(var(--stagger) * 3); }

/* 报头与页脚是脚本挂载的，只做淡入，不做位移 ——
   顶栏滑一下会让人觉得页面在抖。 */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.masthead,
.colophon,

/* 尊重系统偏好：关掉位移，只保留极短淡入。
   注意 reduced-motion 不等于「无动效」—— 完全不动会让「页面已就绪」
   这个信号消失。要的是少动，不是不动。 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* 默认把所有动效压到不可感知，防止以后新增的动效漏掉这一步 */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  /* 例外：入场淡入保留 80ms，只留透明度、不留位移 */
  .sheet > *,
  .masthead,
  .colophon,
  .tools {
    animation-name: fade-in !important;
    animation-duration: 80ms !important;
    animation-delay: 0ms !important;
  }
}

/* 高对比度偏好。
   ⚠️ 必须同时写 html[data-theme="dark"]：深色主题块的选择器是 (0,1,1)，
   只写 :root (0,1,0) 会被它压过去 —— 深色用户开高对比度会完全没有效果。 */
@media (prefers-contrast: more) {
  :root,
  html[data-theme="dark"] {
    --rule: var(--control-line);
    --rule-strong: var(--control-line);
    --ink-3: var(--ink-2);
    --hover: rgba(128, 128, 128, 0.14);
  }
}

/* --------------------------------------------------------------------------
   15. 间距与宽度工具
   只用令牌值，避免页面里出现 inline style 绕过间距系统。
   -------------------------------------------------------------------------- */
.mt-3 { margin-top: var(--s3); }
.mt-4 { margin-top: var(--s4); }
.mt-5 { margin-top: var(--s5); }
.mt-8 { margin-top: var(--s8); }
.mt-10 { margin-top: var(--s10); }
.mt-12 { margin-top: var(--s12); }
.mb-5 { margin-bottom: var(--s5); }
.mb-6 { margin-bottom: var(--s6); }
.mb-8 { margin-bottom: var(--s8); }
.mb-10 { margin-bottom: var(--s10); }
.maxw-sm { max-width: 420px; }
.maxw-md { max-width: 560px; }

/* 目录行的正文变体：说说的正文就是一句话，不需要摘要的小字号 */
.entry__text {
  margin: 0;
  font-size: var(--t-body);
  line-height: var(--lead-snug);
  color: var(--ink);
}
.entry__media {
  margin-top: var(--s4);
  max-width: 360px;
}

/* --------------------------------------------------------------------------
   16. 打印
   静态站也常被打印或另存为 PDF。不做处理的话会打出：纸纹噪点、
   吸顶报头、浮动工具条、跳转链接，以及白底上的深色主题。
   -------------------------------------------------------------------------- */
@media print {
  :root,
  html[data-theme="dark"] {
    --paper: #ffffff;
    --paper-raised: #ffffff;
    --paper-sunk: #ffffff;
    --ink: #000000;
    --ink-2: #333333;
    --ink-3: #555555;
    --rule: #dddddd;
    --rule-strong: #bbbbbb;
    --control-line: #999999;
    --vermilion: #8c2f1c;
  }
  body::before { display: none; }
  .masthead,
  .drawer,
  .tools,
  .skip-link,
  .noscript-bar { display: none !important; }
  .sheet { padding: 0; max-width: none; }
  .entry,
  .ledger__row,
  .index-card,
  .plate,
  .margin-note { break-inside: avoid; }
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 10px;
    color: #555555;
  }
}

/* --------------------------------------------------------------------------
   17. 响应式收尾
   -------------------------------------------------------------------------- */
/* 触摸设备：控件提到 44px。
   Apple HIG 与 Material 的建议触达尺寸；36px 在手指上偏小。 */
@media (pointer: coarse) {
  :root {
    --control-h: 44px;
    --control-h-lg: 44px;
  }
  .tools .iconbtn { width: 40px; height: 40px; }
}

@media (max-width: 640px) {
  :root {
    --t-h1: 26px;
    --t-h2: 22px;
    --t-h3: 18px;
    --t-lead: 17px;
  }
  /* iOS 上 font-size < 16px 的输入框，聚焦时会被自动放大，页面跟着错位。
     移动端一律 16px。 */
  .field input { font-size: 16px; }
  .sheet { padding: var(--s10) var(--s4) var(--s16); }
  .masthead__inner { padding: 0 var(--s4); }
  .colophon { padding: var(--s6) var(--s4) var(--s10); }
  .card-grid { grid-template-columns: minmax(0, 1fr); }
  .folio { margin-bottom: var(--s8); }
}
