/* ==========================================================================
   前台样式 —— 石墨灰 + 钢蓝

   只有这一个样式文件，颜色全部走 :root 变量，明暗两套值。
   规则（改之前先读一遍，不然很容易又滑回"卡片+渐变"那一套）：
     · 只有一个强调色 --accent，只用于链接、当前项、焦点框、主按钮。
     · 层级靠 1px 实线和底色，不靠阴影；阴影只出现在下拉与移动端抽屉。
     · 圆角 4px（控件 3px）。不做大圆角卡片。
     · 动效 140ms，只改颜色/背景/边框；不做入场动画、位移与缩放。
     · prefers-reduced-motion 下全部关闭。
     · 上面"不渐变、不阴影"两条在首页名片（.side-about）那一格开了一处受控破例：
       顶部一条背景图（只到头像下缘为止）、渐变名字、头像柔光环。圆角不在破例之内，
       那张卡仍用面板那档 4px。破例的值集中在 --name-grad-* / --name-glow /
       --avatar-halo 这几个 token 里，只服务那一张卡，
       不要把它当成"渐变卡片解禁"往列表、面板、后台上复制。
     · "只有一个强调色"另有一处破例，也是最后一处：页脚那三枚访问徽章的数值底
       用了三个色相（--stat-pv / --stat-uv / --stat-page，照站主给的样张做的）。
       它只服务页脚那一排，--accent 仍然只管链接、当前项、焦点框与主按钮。
   ========================================================================== */

/* ---------- 令牌 ---------- */
:root {
  /* 声明"本页支持浅色"：head 里的 <meta name="color-scheme" content="light dark">
     只是告诉浏览器两套都能画，真正决定原生控件（滚动条、输入框、下拉）
     按哪套画的是这里。缺了它，系统深色时页面是浅色、滚动条却是深色。 */
  color-scheme: light;

  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --bg: #F7F8FA;
  --bg-sub: #F1F3F7;
  --surface: #FFFFFF;
  --surface-2: #F4F6F9;

  /* 页头：浅色半透明 + 背景模糊（与原型一致）。
     页面底色本身很浅，页头靠 1px 线和模糊后的底色差分隔；真正的"顶"由它上面
     那条黑条（--top-*）提供 —— 深色只出现在黑条与代码块两处。 */
  --head-bg: rgba(247, 248, 250, .94);

  /* 顶部黑条：比页头更深一档，读起来是"站在页面外面"的一条边。
     条上的字不能用 --muted/--accent：#2C5C8F 压在 #11141A 上只有 1.9:1。 */
  --top-bg: #11141A;
  --top-fg: #E9ECF1;           /* 黑条上的亮字：蛇、分数与提示 */
  --top-pop: #07090C;          /* 贪吃蛇小层底色：比黑条再深一档 */
  --top-dim: #98A2B0;          /* 简介、链接常态 */
  --top-hover: #FFFFFF;        /* 链接悬停 */
  --top-line: #2A313C;         /* 分隔线与下边线 */
  --top-focus: #7BA3C9;        /* 黑条上的焦点框 */

  --ink: #14171C;
  --text: #2A3039;
  --muted: #5D6673;
  --faint: #8A93A1;

  --line: #E3E7EC;
  --line-soft: #EDF0F4;
  --line-strong: #CFD5DE;

  --accent: #2C5C8F;
  --accent-hover: #23496F;
  --accent-soft: #EBF1F7;
  --accent-border: #C6D7E6;

  /* 首页名片那一格的破例刻度（见文件头）：名字渐变的三段色、名字外面那一层柔光、
     头像下面那一圈光环。深色下同一组语义换一档亮度。 */
  --name-grad-a: #2C5C8F;
  --name-grad-b: #4E82BE;
  --name-grad-c: #6F72C0;
  --name-glow: rgba(78, 130, 190, .26);
  --avatar-halo: rgba(44, 92, 143, .22);

  --code-bg: #171B22;
  --code-text: #D3DAE3;

  /* 页脚访问徽章：数值那一截用了三个色相（浏览量、访客量、本页访客各一枚），
     是本站第二处、也是最后一处对"只有一个强调色"的破例，照站主给的样张做的。
     三个值都压到白字对比度 ≥ 4.5:1，明暗共用一套 —— 换深色只让标签那一截跟着换底。
     不要往列表、面板、后台上复制。 */
  --stat-label-bg: #E4E7EC;
  --stat-label-fg: #2A3039;
  --stat-pv: #A93A5A;
  --stat-uv: #8A5F1A;
  --stat-page: #5557C4;

  --shell: 1280px;
  --radius: 4px;
  --radius-sm: 3px;
  --t: 140ms cubic-bezier(.4, 0, .2, 1);
}

html[data-mode="dark"] {
  color-scheme: dark;
  --bg: #0C0E11;
  --bg-sub: #0F1216;
  --surface: #13171C;
  --surface-2: #181D23;

  /* 深色模式下页头仍是"比正文亮一档"：页面是 #0C0E11，页头取 #181D23 的半透明版。
     黑条反过来压到最深（#07090C），它和页头之间靠 1px 线分开 ——
     两块深色叠在一起时，没有这条线就分不出哪条是站外、哪条是页头。 */
  --head-bg: rgba(24, 29, 35, .92);

  --top-bg: #07090C;
  --top-fg: #E2E8F0;
  --top-pop: #0A0D12;          /* 暗色下黑条已是最深，小层反过来亮一档 */
  --top-dim: #8892A0;
  --top-hover: #FFFFFF;
  --top-line: #1E242D;
  --top-focus: #7BA3C9;

  --ink: #E9ECF1;
  --text: #BFC6D0;
  --muted: #8892A0;
  --faint: #69727F;

  --line: #212730;
  --line-soft: #1B2028;
  --line-strong: #2E363F;

  --accent: #7BA3C9;
  --accent-hover: #93B7D9;
  --accent-soft: #152029;
  --accent-border: #2A4152;

  /* 名片那一格：渐变三段整体提亮，钢蓝 → 雾蓝 → 一点淡紫；柔光跟着提亮一档，
     压在 #13171C 的卡底上才看得出来。 */
  --name-grad-a: #7BA3C9;
  --name-grad-b: #9CC3E4;
  --name-grad-c: #B5AEE8;
  --name-glow: rgba(156, 195, 228, .3);
  --avatar-halo: rgba(123, 163, 201, .32);

  --code-bg: #171D25;
  --code-text: #D6DEE8;

  /* 徽章的三枚色相不随明暗变（白字对比度已经按最暗那一档定过），
     只有标签那一截换底：压在 #0F1216 的页脚上，浅灰底会亮成一块白斑。 */
  --stat-label-bg: #232A33;
  --stat-label-fg: #C6CDD7;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 14px/1.7 var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--accent-soft); color: var(--ink); }

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 24px; }

/* ---------- 顶部黑条 ----------
   全站最上面那一条：左边是英文站名与一句简介，右边是站外的三个出口。
   它不是"页头的一部分"，而是页面之外的一层 —— 所以底色比页头深一档，
   下边压一条 1px 线把两层分开，滚动时它跟着页面走（不吸顶），
   吸顶的只有页头：读者往下读时，屏幕上该留的是导航，不是自我介绍。 */
.topbar { background: var(--top-bg); border-bottom: 1px solid var(--top-line); }
.topbar-inner { position: relative; display: flex; align-items: center; gap: 14px; min-height: 34px; padding-top: 5px; padding-bottom: 5px; }
/* ---------- 黑条里的贪吃蛇 ----------
   待机时只是一条低对比的蛇在自爬：无入场动画、无声、不占额外高度。
   它住在黑条左侧 —— 英文站名与简介移除后让出的那一块；悬停提亮一档，提示"这里能点"。 */
.topbar-game { margin-right: auto; flex: none; padding: 2px; border-radius: var(--radius-sm); line-height: 0; }
/* 在脚本加载前就预留待机画布尺寸，避免 canvas 默认的 300×150 撑高黑条。
   CSS 尺寸也固定，脚本按屏幕像素比放大绘图缓冲区时不改变布局。 */
.topbar-game canvas { display: block; width: 280px; height: 21px; }
/* 点开后的小层：从蛇这一侧（左）弹出，下拉层是全站允许用阴影的两处之一（另一处是移动端抽屉）。 */
.game-pop {
  position: absolute; top: calc(100% + 8px); left: 24px; z-index: 40;
  padding: 10px 12px 12px; width: max-content;
  background: var(--top-pop); border: 1px solid var(--top-line); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
}
.game-pop[hidden] { display: none; }
.game-pop-head { display: flex; align-items: center; justify-content: space-between; gap: 24px; margin-bottom: 8px; }
.game-pop .score { font: 11px/1 var(--font-mono); letter-spacing: .08em; color: var(--top-dim); }
.game-pop .close { font: 11px/1 var(--font-mono); color: var(--top-dim); transition: color var(--t); }
.game-pop .close:hover { color: var(--top-hover); }
.game-pop canvas { display: block; border: 1px solid var(--top-line); border-radius: var(--radius-sm); }
.game-pop .hint { margin: 8px 0 0; font: 11px/1.6 var(--font-mono); color: var(--top-dim); opacity: .85; }
.topbar-links {
  display: flex; align-items: center; gap: 14px; flex: none;
  font: 11.5px/1 var(--font-mono); letter-spacing: .04em;
}
.topbar-links a { color: var(--top-dim); transition: color var(--t); }
.topbar-links a:hover { color: var(--top-hover); }
/* 黑条只留文字：站外入口那批锚带图标与文字两种形态（见 siteSocials 片段），
   图标那一形态留给首页关于卡，这里藏掉。 */
.topbar-links .soc svg { display: none; }
/* 黑条上的焦点框不能用页面上的钢蓝：#2C5C8F 在 #11141A 上几乎看不见。 */
.topbar :where(a, button):focus-visible { outline-color: var(--top-focus); }

/* ---------- 页头 ----------
   浅色半透明 + 背景模糊：页头与正文几乎同色，靠 1px 线和滚动时的模糊差分隔。
   页头的"顶"由上面那条黑条提供，所以这里不需要再深一档 —— 两块深色上下叠着，
   页头就变成了黑条的延伸，导航反而更难读。 */
.site-head {
  position: sticky; top: 0; z-index: 20;
  background: var(--head-bg);
  -webkit-backdrop-filter: saturate(180%) blur(8px);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--line);
}
.head-inner { display: flex; align-items: center; gap: 32px; height: 64px; }

.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand .mark {
  display: grid; place-items: center; width: 26px; height: 26px; flex: none;
  border: 1px solid var(--ink); border-radius: var(--radius-sm);
  font: 600 13px/1 var(--font-mono); color: var(--ink);
}
.brand-logo { width: 26px; height: 26px; object-fit: contain; flex: none; }
.brand-text { min-width: 0; }
.brand-text strong { display: block; font-size: 14.5px; font-weight: 600; color: var(--ink); letter-spacing: .01em; line-height: 1.35; }
.brand-text small { display: block; font-size: 11.5px; color: var(--faint); letter-spacing: .04em; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.nav { display: flex; align-items: center; gap: 2px; margin-left: 8px; }
.nav > a, .nav-group > a {
  position: relative; display: block; padding: 6px 11px; border-radius: var(--radius-sm);
  font-size: 13.5px; color: var(--muted); white-space: nowrap;
  transition: color var(--t), background var(--t);
}
.nav > a:hover, .nav-group > a:hover { color: var(--ink); background: var(--surface-2); }
.nav > a[aria-current="page"], .nav-group > a[aria-current="page"] { color: var(--ink); font-weight: 500; }
.nav > a[aria-current="page"]::after, .nav-group > a[aria-current="page"]::after {
  content: ""; position: absolute; left: 11px; right: 11px; bottom: -1px; height: 2px; background: var(--accent);
}

/* 下拉是一块浮在页头下面的面板：页头已经是浅色，浮层要靠边框与阴影
   把自己从页面上"抬起来"，不能只靠底色差。 */
.nav-group { position: relative; }
.nav-drop {
  position: absolute; top: 100%; left: 0; z-index: 30; min-width: 168px;
  padding: 4px; margin-top: 6px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 12px 28px -16px rgba(16, 24, 32, .28);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity var(--t), transform var(--t), visibility var(--t);
}
html[data-mode="dark"] .nav-drop { background: var(--surface-2); border-color: var(--line-strong); }
html[data-mode="dark"] .nav-drop a:hover { background: rgba(255, 255, 255, .05); }
.nav-group:hover .nav-drop,
.nav-group:focus-within .nav-drop { opacity: 1; visibility: visible; transform: none; }
.nav-drop a {
  display: block; padding: 7px 10px; border-radius: var(--radius-sm);
  font-size: 13px; color: var(--muted); white-space: nowrap;
  transition: color var(--t), background var(--t);
}
.nav-drop a:hover { color: var(--ink); background: var(--surface-2); }
.nav-drop a[aria-current="page"] { color: var(--accent); }

.head-tools { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.icon-btn {
  display: grid; place-items: center; width: 32px; height: 32px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted);
  transition: color var(--t), border-color var(--t), background var(--t);
}
.icon-btn:hover { color: var(--ink); border-color: var(--line-strong); background: var(--surface-2); }
.menu-btn { display: none; }
html[data-mode="light"] .icon-moon,
html[data-mode="dark"] .icon-sun { display: none; }

/* ---------- 通用按钮 ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; padding: 0 14px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font-size: 13px; font-weight: 500;
  white-space: nowrap; transition: background var(--t), border-color var(--t), color var(--t);
}
.btn:hover { border-color: var(--faint); color: var(--ink); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: #fff; }
.btn--sm { height: 28px; padding: 0 11px; font-size: 12.5px; }
html[data-mode="dark"] .btn--primary { color: #0C0E11; }

/* ==========================================================================
   首页
   ========================================================================== */
/* 40px 是"页头下面留一口气"的那一档：标题区自带 24px 下内边距，两者相加
   刚好把第一篇文章推到一屏视线以下的位置，又不至于空出一大块。 */
.layout { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 56px; padding-top: 40px; padding-bottom: 72px; }

/* 分类区：首页第一屏整行那一排分类入口，与下面的列表之间只有一条 1px 线 ——
   不套卡片、不铺底色，因为这一屏的重点是列表，分类区只是"进门时看一眼"的那块。
   只画置顶的分类；一个都没置顶时模板整块不画，这里不留空壳。 */
.lead-topics { padding-bottom: 24px; border-bottom: 1px solid var(--line); }

/* ---------- 分类入口的格子 ----------
   一格一个分类：上面是该分类最新一篇的封面，下面是分类名与篇数，整格点过去就是分类页。
   图不是装饰 —— 它替"这一站在写哪些主题"举了证；哪一格整个分类都没配封面，
   就留一块 surface-2 的色块（service 那边不编假图，这里也不拿别的图凑）。
   缩略图只压饱和度、不做悬停放大：全站那一处缩放留给文章列表的封面。
   格子数不设上限：顶了几个画几个，一行放不下自己换行。 */
.lead-topics ul { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
.topic a {
  display: block; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; transition: border-color var(--t);
}
.topic a:hover { border-color: var(--line-strong); }
.topic .pic { display: block; aspect-ratio: 16 / 10; background: var(--surface-2); }
.topic .pic img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.72); transition: filter var(--t);
}
.topic a:hover .pic img { filter: saturate(1); }
html[data-mode="dark"] .topic .pic img { filter: saturate(.7) brightness(.9); }
html[data-mode="dark"] .topic a:hover .pic img { filter: saturate(.95) brightness(.98); }
.topic .cap {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding: 7px 9px; font-size: 12.5px; color: var(--text);
  border-top: 1px solid var(--line-soft);
}
.topic a:hover .cap { color: var(--accent); }
.topic .cap .c { flex: none; font: 11.5px/1 var(--font-mono); color: var(--faint); }

/* 视觉隐藏但保留给读屏与搜索引擎（栏目页等处仍用它兜底一个不占位的标题）。 */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- 文章列表 ---------- */
.post-list { margin-top: 8px; }
.post {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 28px; padding: 22px 12px; margin: 0 -12px;
  border-bottom: 1px solid var(--line); border-radius: var(--radius);
  transition: background var(--t);
}
.post--cover { grid-template-columns: minmax(0, 1fr) 168px; }
/* 第一篇是这一屏的头条:标题大一号,和下面几篇拉开层次。 */
.post-list > .post:first-child { padding-top: 26px; }
.post-list > .post:first-child h2 { font-size: 21px; }
.post:hover { background: var(--surface-2); }
.post:last-child { border-bottom: 0; }
.post-body { min-width: 0; }
.post .kicker { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font: 11px/1 var(--font-mono); letter-spacing: .07em; text-transform: uppercase; color: var(--faint); }
.post .kicker a { color: var(--accent); }
.post .kicker .dot, .post .meta .dot, .article-head .meta .dot {
  width: 3px; height: 3px; border-radius: 50%; background: var(--line-strong); flex: none;
}
/* 置顶那一枚标记借 .article-head .tag 的那一套 token，不另开颜色。
   它存在的原因是列表按"置顶在前"排，行里不写一句，人只会以为这篇是最新发布的。 */
.post .kicker .pin {
  flex: none; padding: 2px 7px; border: 1px solid var(--accent-border);
  border-radius: var(--radius-sm); background: var(--accent-soft); color: var(--accent);
}
.post h2 { margin-top: 10px; font-size: 17.5px; font-weight: 600; line-height: 1.45; color: var(--ink); letter-spacing: -.005em; }
.post:hover h2 { color: var(--accent); }
.post h2 a { display: block; }
.post p { margin-top: 8px; font-size: 13.5px; line-height: 1.75; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.post .meta { display: flex; align-items: center; gap: 10px; margin-top: 14px;
  font: 11.5px/1 var(--font-mono); color: var(--faint); letter-spacing: .03em; }
.post .meta:empty { display: none; }
.post .thumb {
  align-self: start; aspect-ratio: 16 / 10; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2);
  transition: border-color var(--t);
}
/* 缩略图的悬停：常态压一点饱和度（列表里十几张彩图会抢标题的注意力），
   悬停时回到原色并轻微推近 4%。这是全站唯一一处缩放动效 —— 它承担的是
   "这张图可以点"的提示，不是为了好看；缩放被 overflow:hidden 裁在框内，
   不会推动任何布局。prefers-reduced-motion 下全局把 transition 关掉，只留色变。 */
.post .thumb img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.72);
  transition: filter var(--t), transform 220ms cubic-bezier(.4, 0, .2, 1);
}
.post:hover .thumb { border-color: var(--line-strong); }
.post:hover .thumb img { filter: saturate(1); transform: scale(1.04); }
html[data-mode="dark"] .post .thumb img { filter: saturate(.7) brightness(.9); }
html[data-mode="dark"] .post:hover .thumb img { filter: saturate(.95) brightness(.98); }

/* ---------- 侧栏 ---------- */
/* 侧栏第一块是"关于"：一张居中的名片 —— 顶部一条背景图、图里的头像、名字、称号、
   一句话简介、一排统计数字、一排图标出口，一条中轴线串下来。
   不画标题：名字那一行已经回答了"这是谁"。
   照片只占顶部那一条，下缘压在头像的下沿上就收住 —— 名字往下全是卡底色。
   参考样张就是这个边界，所以文字一行都不坐在照片上：不需要遮罩、不需要字底光，
   用户上传一张夜景还是一张逆光，都影响不到下面的可读性，只影响那一条好不好看。
   这一张卡是全站唯一允许照片条、渐变字与柔光环的地方（见文件头），
   破例只开在这三件上：形状仍是一张普通面板，4px 圆角 + 1px 线，与正文、列表、后台同一档。
   没配背景图时那一条退成一块浅色渐变面板，几何与排布一字不改 ——
   空着也要是一张设计过的名片，不是一条塌下去的灰带。 */
.side-block { position: sticky; top: 88px; display: grid; gap: 28px; }
.side-about {
  position: relative; overflow: hidden; text-align: center;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
/* 顶部那一条 128px：头像 92 + 上下各留一段，正好让头像下缘压在这条的下沿上。
   没配图时它是一块浅钢蓝面板，撑出同一份几何 —— 有图/没图两档共用一个版式。 */
.side-about .about-cover {
  position: relative; height: 128px;
  background: linear-gradient(180deg, var(--accent-soft) 0%, var(--accent-soft) 46%, var(--surface) 100%);
}
.side-about .about-cover img { width: 100%; height: 100%; object-fit: cover; }
/* 有配图：底色让位给照片，照片只在这条的最后四分之一化进卡底，不留一条硬边 ——
   再早就把头像背后那一段也洗淡了，参考样张里头像是坐在实图上的。
   末端取 var(--surface) 而不是写死 #fff：明暗各有一份卡底色，写死会在深色下露出一条白边。 */
.side-about--cover .about-cover { background: none; }
.side-about--cover .about-cover img { filter: saturate(.95); }
html[data-mode="dark"] .side-about--cover .about-cover img { filter: saturate(.9) brightness(.92); }
.side-about--cover .about-cover::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0) 72%,
    rgba(255, 255, 255, .5) 88%,
    var(--surface) 100%);
}
html[data-mode="dark"] .side-about--cover .about-cover::after {
  background: linear-gradient(180deg,
    rgba(19, 23, 28, 0) 0%,
    rgba(19, 23, 28, 0) 72%,
    rgba(19, 23, 28, .5) 88%,
    var(--surface) 100%);
}
.side-about .about-body { position: relative; z-index: 1; }
/* 头像：名片上的主角，近三分之一卡宽。负 margin 取的正是它自身的高度 ——
   整枚提进顶部那一条里、下缘压在这条的下沿上，参考样张就是这个位置。
   白圈加一层柔光环把它从照片里托出来；这层光环是名片这一格允许的阴影，
   作用是把主体与背景分开，不是装饰。 */
.side-about .about-avatar {
  width: 92px; height: 92px; margin: -92px auto 0; padding: 4px;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 8px 24px var(--avatar-halo);
}
.side-about--cover .about-avatar {
  border: 0; background: rgba(255, 255, 255, .92);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .55), 0 8px 24px var(--avatar-halo);
}
html[data-mode="dark"] .side-about--cover .about-avatar {
  background: rgba(19, 23, 28, .82);
  box-shadow: 0 0 0 1px rgba(233, 236, 241, .22), 0 8px 24px var(--avatar-halo);
}
.side-about .about-avatar img,
.side-about .about-avatar .mono { display: block; width: 100%; height: 100%; border-radius: 50%; }
.side-about .about-avatar img { object-fit: cover; }
/* 没配头像时名字首字顶替：仓库里没有头像资源，不编一张假图；
   底色与边线借置顶徽标那一套 token，不另开颜色。 */
.side-about .about-avatar .mono {
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
  font-size: 24px; font-weight: 600; line-height: 1;
}
/* 名字往下每一行都坐在纸面上，颜色仍按 ink/muted/faint 写，只有名字这一处用渐变：
   钢蓝 → 雾蓝 → 一点淡紫，三段色在 --name-grad-* 里，明暗各一档。
   渐变压在 inline-block 的字上而不是整行块上 —— 块级 <b> 的底铺满卡宽，
   居中那几个字只会取到渐变中段，看着就是一条纯色。
   外面那一圈 --name-glow 柔光是参考样张里名字"发光"的那一档，浅色下压到 .26，
   坐在白纸上不至于糊成一团霓虹。 */
.side-about .about-id { margin-top: 14px; padding: 0 16px; }
.side-about .about-id b {
  display: inline-block; font-size: 20px; font-weight: 700; line-height: 1.4;
  background-image: linear-gradient(96deg, var(--name-grad-a) 0%, var(--name-grad-b) 48%, var(--name-grad-c) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  text-shadow: 0 0 16px var(--name-glow);
}
/* 强制颜色模式（Windows 高对比度那一类）下 background-image 会被系统丢掉，
   而字色是被我们设成透明的 —— 不兜这一句，名字整行会直接看不见。
   全站只有渐变字这一处需要它，其余地方本来就吃系统色。 */
@media (forced-colors: active) {
  .side-about .about-id b {
    background-image: none;
    -webkit-text-fill-color: Text; color: CanvasText; text-shadow: none;
  }
}
.side-about .about-id small { display: block; margin-top: 5px; font: 11px/1.4 var(--font-mono); letter-spacing: .06em; color: var(--faint); }
.side-about .about-motto { margin-top: 10px; padding: 0 18px; font-size: 12.5px; line-height: 1.75; color: var(--muted); }
/* 统计行：flex 等分、列间只留一道竖分隔 —— 参考样张里这一排上下都没有横线，
   居中名片上再画两条通栏横线就像表格了。某列数为 0 被模板省掉时
   剩下的列自动均分，不留空位 —— 一排"0"比少一列更像坏了的地方。 */
.side-about .about-stats { display: flex; margin-top: 16px; padding: 4px 8px; }
.side-about .about-stats li { flex: 1; min-width: 0; }
.side-about .about-stats li + li { border-left: 1px solid var(--line-soft); }
.side-about .about-stats b { display: block; font: 600 21px/1.2 var(--font-mono); letter-spacing: -.01em; color: var(--ink); }
.side-about .about-stats span { display: block; margin-top: 4px; font-size: 11px; line-height: 1.4; color: var(--faint); }
/* 图标出口：收成圆形跟头像呼应，描边与页头图标按钮同一套安静档；
   片段里的文字在这一处由 CSS 藏掉只留图标（可访问名字在锚的 aria-label 上）。 */
.side-about .about-socs { display: flex; justify-content: center; gap: 12px; padding: 16px 16px 18px; }
.side-about .about-socs .soc {
  display: grid; place-items: center; width: 34px; height: 34px;
  border: 1px solid var(--line); border-radius: 50%; color: var(--muted);
  transition: color var(--t), border-color var(--t), background var(--t);
}
.side-about .about-socs .soc svg { width: 17px; height: 17px; }
.side-about .about-socs .soc:hover { color: var(--accent); border-color: var(--accent-border); background: var(--accent-soft); }
.side-about .about-socs .soc span { display: none; }
.side-sec > h3 {
  padding-bottom: 8px; margin-bottom: 12px; border-bottom: 1px solid var(--line);
  font: 11px/1.4 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--faint);
}
.mini-list li + li { margin-top: 10px; }
.mini-list a { display: block; font-size: 13px; line-height: 1.6; color: var(--text); transition: color var(--t); }
.mini-list a:hover { color: var(--accent); }
.mini-list time { display: block; margin-top: 3px; font: 11px/1 var(--font-mono); color: var(--faint); }

/* ---------- 分页 ---------- */
.pager { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 32px; }
.pager a, .pager span {
  display: grid; place-items: center; min-width: 32px; height: 32px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: 12.5px/1 var(--font-mono); color: var(--muted); transition: all var(--t);
}
.pager a:hover { border-color: var(--line-strong); color: var(--ink); }
/* 当前页是实心 ink 块:分页条上只有"你在第几页"这一个事实,
   用强调色浅底会让人以为那是可点的按钮。 */
.pager .is-current { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.pager .is-disabled { color: var(--faint); opacity: .55; }
.pager .grow { flex: 1; border: 0; padding: 0; min-width: 0; }
.pager .count { border: 0; color: var(--faint); }

.empty { padding: 48px 0; font-size: 13.5px; color: var(--faint); }

/* ==========================================================================
   文章详情
   ========================================================================== */
.article-wrap { display: grid; grid-template-columns: minmax(0, 1fr) 210px; gap: 56px; padding-top: 32px; padding-bottom: 80px; }
/* 后台预览那一屏顶部这条带。草稿在前台根本不存在，而人是从后台新标签页跳进来的，
   不写一句"这是预览、访客看不到"，他就会以为这篇已经公开了。
   底色与描边沿用 .article-head .tag 那一套 token，不另开颜色。 */
.preview-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 22px; padding: 10px 14px; border: 1px solid var(--accent-border);
  border-radius: var(--radius); background: var(--accent-soft);
  font: 12.5px/1.5 var(--font-mono); color: var(--muted); }
.preview-bar__badge { flex: none; padding: 2px 7px; border: 1px solid var(--accent-border);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--accent);
  font-size: 11px; letter-spacing: .06em; }
.preview-bar__back { margin-left: auto; color: var(--accent); transition: color var(--t); }
.preview-bar__back:hover { color: var(--accent-hover); }
.crumbs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font: 11.5px/1 var(--font-mono); color: var(--faint); letter-spacing: .03em; }
.crumbs a:hover { color: var(--accent); }
.crumbs .sep { color: var(--line-strong); }

.article-head { margin-top: 22px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.article-head .tag {
  display: inline-block; padding: 3px 8px; border: 1px solid var(--accent-border);
  border-radius: var(--radius-sm); background: var(--accent-soft);
  font: 11px/1.4 var(--font-mono); letter-spacing: .06em; color: var(--accent);
}
.article-head h1 { margin-top: 14px; font-size: 30px; line-height: 1.38; font-weight: 600;
  color: var(--ink); letter-spacing: -.015em; }
.article-head .meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 16px;
  font: 12px/1 var(--font-mono); color: var(--faint); }
.article-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.article-tags .tag:hover { background: var(--accent); border-color: var(--accent); color: var(--surface); }

/* /t 索引页：枚数直接跟在名字后面，不给每枚标签再铺一层徽章底色。 */
.tag-cloud { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 24px; }
.tag-cloud a { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 3px; font: 13px/1.4 var(--font-mono); color: var(--ink); }
.tag-cloud a:hover { border-color: var(--accent); color: var(--accent); }
.tag-cloud span { font-size: 11px; color: var(--faint); }

/* ---------- 正文 ---------- */
.prose { max-width: 78ch; padding-top: 28px; font-size: 15.5px; line-height: 1.9; color: var(--text); }
.prose > * + * { margin-top: 20px; }
/* 正文第一块就是标题时，标题的 40px 上边距会叠在 padding 上，空出一大段。 */
.prose > :first-child { margin-top: 0; }
.prose h1, .prose h2 { margin-top: 40px; padding-top: 4px; font-size: 19px; font-weight: 600;
  color: var(--ink); letter-spacing: -.005em; scroll-margin-top: 88px; }
.prose h3 { margin-top: 28px; font-size: 16px; font-weight: 600; color: var(--ink); scroll-margin-top: 88px; }
.prose h4 { margin-top: 22px; font-size: 14.5px; font-weight: 600; color: var(--ink); }
.prose p { text-align: justify; }
.prose a { color: var(--accent); border-bottom: 1px solid var(--accent-border); }
.prose a:hover { border-bottom-color: var(--accent); }
.prose strong { color: var(--ink); font-weight: 600; }
.prose ul, .prose ol { padding-left: 22px; }
.prose ul li { list-style: disc; }
.prose ol li { list-style: decimal; }
.prose li + li { margin-top: 6px; }
.prose li::marker { color: var(--faint); }
.prose blockquote { padding: 2px 0 2px 18px; border-left: 2px solid var(--accent);
  color: var(--muted); font-size: 14.5px; }
.prose code {
  padding: 1px 5px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2); font: 12.5px/1.6 var(--font-mono); color: var(--ink);
}
.prose pre {
  overflow-x: auto; padding: 16px 18px; tab-size: 4;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--code-bg); color: var(--code-text);
  font: 12.5px/1.75 var(--font-mono);
}
.prose pre code { padding: 0; border: 0; background: none; color: inherit; font: inherit; }
/* 代码块外面那一层 .codebox 由 site.js 加：pre 自己横向滚动，复制按钮挂在里面
   会跟着一起滚出可视区（长行代码时按钮就跑到屏幕外了），只能站在这层不滚的外壳上。
   没有脚本时没有这层外壳，也没有按钮，代码块照样读得完。
   tab-size 收到 4：Go 与 Makefile 用制表符缩进，浏览器默认的 8 会让十行代码
   宽到读不下去。 */
.prose .codebox { position: relative; }
.prose .codebox pre { margin: 0; }
.code-copy {
  position: absolute; top: 8px; right: 8px;
  padding: 2px 8px; border: 1px solid rgba(255, 255, 255, .18); border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, .07); color: var(--code-text);
  font: 11px/1.6 var(--font-mono); letter-spacing: .04em;
  opacity: 0; transition: opacity var(--t), background var(--t), border-color var(--t);
}
.code-copy:hover { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .34); color: #fff; }
.code-copy:disabled { cursor: default; opacity: 1; }
/* 悬停才露出来是给鼠标的；触屏没有悬停，键盘也得看得见这一颗。
   关掉动效时同理 —— 一条把 transition 全清的规则会让 opacity: 0 永远留着。 */
@media (hover: none) { .code-copy { opacity: 1; } }
.code-copy:focus-visible { opacity: 1; }
.prose figure { margin: 26px 0; }
.prose figure img { border: 1px solid var(--line); border-radius: var(--radius); }
.prose figcaption { margin-top: 8px; font: 11.5px/1.6 var(--font-mono); color: var(--faint); }
.prose img { border-radius: var(--radius); }
.prose table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.prose th, .prose td { padding: 8px 12px; border: 1px solid var(--line); text-align: left; }
.prose th { background: var(--surface-2); font-weight: 600; color: var(--ink); font-size: 12.5px; }
.prose hr { height: 1px; border: 0; background: var(--line); }

/* 正文图片：正文里按栏宽显示，点开看原图。
   历史文章里的 <img> 常带 height=200 这类展示属性，灯箱里必须用
   width/height:auto 覆盖掉，否则"放大"出来还是 200px 高。 */
.prose img { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; gap: 12px;
  padding: 56px 24px 44px;
  background: rgba(10, 12, 16, .9);
}
.lightbox[hidden] { display: none; }
.lightbox img {
  width: auto; height: auto;
  max-width: 100%; max-height: calc(100vh - 100px);
  border: 1px solid rgba(255, 255, 255, .16); border-radius: var(--radius);
  background: var(--surface); cursor: zoom-out;
}
.lightbox .lb-close {
  position: absolute; top: 16px; right: 16px;
  display: grid; place-items: center; width: 32px; height: 32px;
  border: 1px solid rgba(255, 255, 255, .24); border-radius: var(--radius-sm);
  color: #cfd6e0; font: 400 18px/1 var(--font-sans);
  transition: background var(--t), border-color var(--t), color var(--t);
}
.lightbox .lb-close:hover { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .4); color: #fff; }
.lightbox .lb-cap {
  position: absolute; left: 0; right: 0; bottom: 16px;
  padding: 0 24px; text-align: center;
  font: 11.5px/1.6 var(--font-mono); color: #98a2b0;
}
.lightbox .lb-cap:empty { display: none; }
/* 灯箱打开时锁住页面滚动：背景跟着滚会让人分不清哪层能动。 */
html.is-locked, html.is-locked body { overflow: hidden; }

.article-foot { max-width: 78ch; margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--line); }
.article-foot .row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.article-foot .lic { font-size: 12px; color: var(--faint); line-height: 1.8; }
.article-foot .lic a { color: var(--muted); border-bottom: 1px solid var(--line-strong); }

/* ---------- 评论 ----------
   访客写的是纯文本:.comment-body 靠 white-space: pre-wrap 还原他按的换行,
   所以这一栏不解析 HTML,也就不用为它准备第二份标签白名单。
   名字左边那一格是昵称首字的方块,与页头没配 logo 时同一画法:接第三方头像服务
   等于把每个访客的 IP 交给别人,还多一个断网就破图的来源。
   两条提示都不另开颜色(全站只有钢蓝一个强调色):说什么由那句话负责,
   role="alert" 负责让读屏软件也念出来。 */
.comments { max-width: 78ch; margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--line); }
.comments > h2 { font-size: 15px; font-weight: 600; color: var(--ink); }
.comments > h2 b { margin-left: 6px; font: 500 12.5px/1 var(--font-mono); color: var(--faint); }
.comment-notice, .comment-error {
  margin-top: 14px; padding: 8px 12px; border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.7;
}
.comment-notice { border: 1px solid var(--accent-border); background: var(--accent-soft); color: var(--ink); }
.comment-error { border: 1px solid var(--line-strong); background: var(--surface-2); color: var(--ink); }
.comment-list { margin-top: 18px; }
.comment + .comment { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line-soft); }
.comment-who { display: flex; align-items: center; gap: 8px; }
.comment-who .monogram {
  display: grid; place-items: center; width: 22px; height: 22px; flex: none;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  font: 500 11px/1 var(--font-mono); color: var(--muted);
}
.comment-who strong { font-size: 13px; font-weight: 600; color: var(--ink); }
.comment-who time { margin-left: auto; font: 11.5px/1 var(--font-mono); color: var(--faint); }
.comment-body {
  margin-top: 8px; padding-left: 30px; font-size: 14px; line-height: 1.8; color: var(--text);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.comment-empty { margin-top: 14px; font-size: 13px; color: var(--faint); }

.comment-form { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); }
.comment-form h3 {
  padding-bottom: 8px; font: 11px/1.4 var(--font-mono); letter-spacing: .1em; color: var(--faint);
}
.comment-form .field { margin-top: 12px; }
.comment-form label { display: block; margin-bottom: 6px; font: 11.5px/1 var(--font-mono); color: var(--faint); letter-spacing: .04em; }
.comment-form input, .comment-form textarea {
  width: 100%; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); font: 14px/1.7 var(--font-sans);
  transition: border-color var(--t);
}
.comment-form input:hover, .comment-form textarea:hover { border-color: var(--faint); }
.comment-form textarea { min-height: 88px; resize: vertical; }
/* 蜜罐那一栏:留在 DOM 里但看不见也摸不着(不占版面、不进 Tab 顺序)。
   用 display: none 有些机器人会整块跳过,反而收不到"填了就是机器人"这个信号。 */
.comment-hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.comment-actions { display: flex; align-items: center; gap: 14px; margin-top: 14px; flex-wrap: wrap; }
.comment-hint { font-size: 12px; color: var(--faint); line-height: 1.6; }

.toc { position: sticky; top: 88px; font-size: 12.5px; }
.toc h3 { font: 11px/1.4 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--faint); padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.toc ol { margin-top: 10px; border-left: 1px solid var(--line); }
.toc li a { display: block; padding: 5px 0 5px 12px; margin-left: -1px;
  border-left: 2px solid transparent; color: var(--muted); line-height: 1.5;
  transition: color var(--t), border-color var(--t); }
.toc li a:hover { color: var(--ink); }
.toc li a.on { color: var(--accent); border-left-color: var(--accent); }
.toc li.lv3 a { padding-left: 24px; font-size: 12px; }

/* 阅读进度条：只在文章页出现，由脚本写 transform。
   它压在吸顶页头的顶边上，页头是浅色的，所以用页面上的 --accent。 */
.progress {
  position: fixed; top: 0; left: 0; z-index: 40; height: 2px; width: 100%;
  background: var(--accent); transform: scaleX(0); transform-origin: 0 50%;
  pointer-events: none;
}
.progress[hidden] { display: none; }

/* ==========================================================================
   栏目页 / 404
   ========================================================================== */
/* 栏目页没有右侧栏，容器就跟着 .shell 的 1280 走：
   左边界与首页主栏对齐（同一个 .shell 内边距），右侧把侧栏让出来的那一块吃掉。
   这里千万不要再写 max-width —— 一旦小于 --shell，margin:auto 会把整块居中，
   视觉上就是"内容整体往右偏了 150px"。正文仍然由 .prose 的 78ch 自己控宽度。 */
.section-wrap { padding-top: 32px; padding-bottom: 80px; }
.page-head { padding-bottom: 22px; border-bottom: 1px solid var(--line); }
/* 非文章页的页标题只有这一档(22px):栏目页与归档页用它,
   文章页再大一号(30px),那是"一篇具体的东西"。 */
.page-head h1 { font-size: 22px; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.page-head p { margin-top: 8px; max-width: 62ch; font-size: 13.5px; color: var(--muted); line-height: 1.75; }
.archive + .archive { margin-top: 36px; }
.archive-title { margin-bottom: 6px; font: 11px/1.4 var(--font-mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint); }
/* 列表铺满 1232 之后单行接近 78 个汉字，摘要按 60em 收住（约 810px，两行 120 字），
   右侧留白由缩略图占位，读起来还是一列。 */
.section-wrap .post p { max-width: 60em; }

/* ---------- 分类切换条 ----------
   一个多页栏目下平铺的一行入口。它是"你在哪一格"的常驻提示，
   所以当前项用强调色浅底，其余只描边 —— 这一行不该比正文更抢眼。
   不用胶囊形（999px）：全站圆角只有 4px 与 3px 两档。 */
.cat-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 18px; }
.cat-tabs a {
  padding: 4px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: 12.5px; color: var(--muted);
  transition: color var(--t), border-color var(--t), background var(--t);
}
.cat-tabs a:hover { color: var(--ink); border-color: var(--line-strong); background: var(--surface); }
.cat-tabs a[aria-current="page"] {
  color: var(--accent); border-color: var(--accent-border); background: var(--accent-soft);
}

/* ---------- 分类总览 ----------
   两列的目录：一格一个分类，格与格之间只有 1px 线，不套卡片 ——
   十一个分类各套一个卡片就是十一个"重要的东西"，而这一屏要的是一眼看完全部。
   表头那条线由 .page-head 的 border-bottom 提供，这里不再叠一条。
   两列靠 :nth-child(odd) 画右线：窄屏只有一列，那条线要跟着去掉。 */
.page-head .page-facts {
  display: flex; gap: 16px; max-width: none; margin-top: 10px;
  font: 11.5px/1.4 var(--font-mono); color: var(--faint); letter-spacing: .04em;
}
.page-head .page-facts b { font-weight: 500; color: var(--ink); }

.cat-index { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0 -12px; }
.cat-item { border-bottom: 1px solid var(--line); }
.cat-item:nth-child(odd) { border-right: 1px solid var(--line); }
.cat-row { display: grid; gap: 6px; padding: 15px 14px; transition: background var(--t); }
.cat-row:hover { background: var(--surface-2); }
.cat-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; }
.cat-name { flex: 1; min-width: 0; font-size: 15.5px; font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color var(--t); }
.cat-row:hover .cat-name { color: var(--accent); }
.cat-n { flex: none; font: 500 13px/1 var(--font-mono); color: var(--muted); letter-spacing: -.01em; }
.cat-n small { margin-left: 2px; font: 400 10.5px/1 var(--font-mono); color: var(--faint); letter-spacing: 0; }
.cat-sub { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; }
.cat-latest { flex: 1; min-width: 0; font-size: 12.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-date { flex: none; font: 11.5px/1 var(--font-mono); color: var(--faint); }

.notfound { padding: 120px 24px 140px; max-width: 640px; }
.notfound .code { font: 500 56px/1 var(--font-mono); color: var(--line-strong); letter-spacing: -.02em; }
.notfound h1 { margin-top: 18px; font-size: 22px; font-weight: 600; color: var(--ink); }
.notfound .desc { margin-top: 8px; font-size: 13.5px; color: var(--muted); }
.notfound .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.shell.search-page { padding-top: 32px; padding-bottom: 80px; }
.search-form { margin-top: 24px; max-width: 640px; }
.search-form label { display: block; margin-bottom: 8px; color: var(--muted); font-size: 13px; }
.search-fields { display: flex; gap: 8px; }
.search-fields input { flex: 1; min-width: 0; width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: 3px; background: var(--surface); color: var(--ink); font: inherit; font-size: 16px; }
.search-fields input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.search-fields input::selection { background: #245a9b; color: #fff; }
[data-mode="dark"] .search-fields input::selection { background: #9ac7ff; color: #101b2c; }
.search-fields .btn { flex: none; min-height: 44px; padding-inline: 20px; }
.search-status { margin-top: 20px; color: var(--muted); font-size: 13px; overflow-wrap: anywhere; }
/* 搜索沿用站点 shell 宽度，弹层与整页共用结果列表。 */
.search-page mark, .search-dialog mark { color: #382500; background: #ffe08a; padding: 0 .08em; font-weight: 650; border-radius: 2px; }
[data-mode="dark"] .search-page mark, [data-mode="dark"] .search-dialog mark { color: #fff3c4; background: #866200; }
.search-dialog { width: calc(100% - 32px); max-width: var(--shell); max-height: 84dvh; margin: 8dvh auto; padding: 24px; border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--bg); color: var(--text); overscroll-behavior: contain; }
.search-dialog::backdrop { background: rgba(0, 0, 0, .55); }
html:has(.search-dialog[open]) { overflow: hidden; }
.search-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.search-dialog-head h2 { color: var(--ink); font-size: 22px; font-weight: 600; }
.search-dialog-head .icon-btn { width: 44px; height: 44px; font-size: 24px; }
.search-dialog-results { min-height: 100px; }
.search-dialog .search-form { margin-top: 16px; }
.search-dialog .pager { margin-bottom: 8px; }
@media (max-width: 720px) { .search-dialog { padding: 16px; margin-top: 4dvh; max-height: 92dvh; } }

/* ==========================================================================
   页脚
   一行两栏：左边品牌与法务，右边访问徽章，两者垂直居中对齐。
   ========================================================================== */
.site-foot { border-top: 1px solid var(--line); background: var(--bg-sub); }
.foot-inner { display: flex; align-items: center; justify-content: space-between; gap: 24px;
  flex-wrap: wrap; padding: 24px; max-width: var(--shell); margin: 0 auto; }
.foot-inner .col p { font-size: 12px; color: var(--faint); line-height: 1.9; }
.foot-inner .col a { color: var(--muted); }
.foot-inner .col a:hover { color: var(--accent); }
.foot-inner .col strong { display: block; margin-bottom: 6px; font-size: 12.5px; color: var(--text); font-weight: 600; }

/* 页脚访问徽章：标签 + 数值两截拼成一枚。
   它和左侧的版权栏同排，靠 .foot-inner 的 space-between 顶到右边；
   窄屏那一栏换行时整排跟着落到版权下面（见 720px 那段）。 */
.foot-stats { display: flex; gap: 10px; flex-wrap: wrap; margin: 0; }
.stat { display: inline-flex; align-items: stretch; overflow: hidden;
  border-radius: var(--radius-sm); font-size: 11.5px; line-height: 1; }
.stat-k { display: flex; align-items: center; padding: 5px 8px;
  background: var(--stat-label-bg); color: var(--stat-label-fg); }
.stat-v { display: flex; align-items: center; padding: 5px 9px;
  font-family: var(--font-mono); color: #fff; }
.stat--pv .stat-v { background: var(--stat-pv); }
.stat--uv .stat-v { background: var(--stat-uv); }
.stat--page .stat-v { background: var(--stat-page); }

/* ==========================================================================
   响应式
   ========================================================================== */
@media (max-width: 1000px) {
  .layout { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .col-side .side-block { position: static; grid-template-columns: 1fr 1fr; gap: 24px; }
  .article-wrap { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .toc { position: static; }
}
@media (max-width: 420px) {
  /* 黑条只留三个出口：蛇那一枚 284px 会把真能点的链接挤出屏。 */
  .topbar-game, .game-pop { display: none; }
}
@media (max-width: 720px) {
  .shell { padding: 0 16px; }
  .topbar-inner { gap: 12px; min-height: 32px; }
  .topbar-links { gap: 12px; }
  .head-inner { gap: 12px; height: 58px; }
  .menu-btn { display: grid; }
  .nav { display: none; margin: 0; }
  .nav.is-open {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 5;
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    padding: 6px 16px 10px; background: var(--surface); border-bottom: 1px solid var(--line);
    box-shadow: 0 12px 24px -14px rgba(16, 24, 32, .22);
  }
  /* 抽屉是挂在页头下面的一块面板，颜色与页面一致；继承的 --muted 在这里
     偏轻，换成 --text，扫一眼就能看清哪几项可点。 */
  .nav.is-open > a, .nav.is-open .nav-group > a { padding: 11px 2px; border-radius: 0;
    border-bottom: 1px solid var(--line-soft); color: var(--text); }
  .nav.is-open > a:hover, .nav.is-open .nav-group > a:hover { background: none; color: var(--accent); }
  .nav.is-open > a[aria-current="page"]::after,
  .nav.is-open .nav-group > a[aria-current="page"]::after { display: none; }
  .nav.is-open > a[aria-current="page"],
  .nav.is-open .nav-group > a[aria-current="page"] { color: var(--accent); }
  .nav.is-open .nav-drop {
    position: static; opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; border-radius: 0; padding: 0 0 0 12px; margin: 0;
    background: transparent;
  }
  .nav.is-open .nav-drop a { padding: 9px 2px; border-bottom: 1px solid var(--line-soft); color: var(--muted); }

  .layout { padding-top: 24px; padding-bottom: 48px; }
  /* 窄屏只留一列：两列时分类名和"最新"那行都只剩十几个字，
     与其截断，不如让每一格独占一行。 */
  .cat-index { grid-template-columns: minmax(0, 1fr); margin: 0 -10px; }
  .cat-item:nth-child(odd) { border-right: 0; }
  .cat-row { padding: 14px 10px; }
  .post { gap: 14px; }
  .post--cover { grid-template-columns: minmax(0, 1fr); }
  .post--cover .thumb { order: -1; aspect-ratio: 16 / 9; }
  .article-head h1 { font-size: 23px; }
  .prose { font-size: 15px; }
  .col-side .side-block { grid-template-columns: 1fr; }
  .foot-inner { flex-direction: column; align-items: flex-start; gap: 12px; padding: 20px 16px; }
  .notfound { padding: 72px 16px 96px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .progress { display: none; }
  /* 上面那句把动效全清了，但代码块那颗是靠 opacity 藏起来的：
     不补这一行，关掉动效的人就永远看不见它。 */
  .code-copy { opacity: 1; }
}
