/* goblog 读者端样式 —— 珊瑚红 / 卡片式。

   动手改之前先看这几条，否则很容易把风格改散：
   1. 顶栏是直角，卡片是 10px 圆角。顶栏的"平"和卡片的"软"是这套观感的
      主要对比，两边一起加圆角会立刻变回到处一样的模板脸。
   2. 只有一个强调色（珊瑚红），另加一个暖金做点缀。颜色只用来表示
      "可点""当前""标记"，不做装饰。
   3. 版式照 blog.awa.moe（Hexo 的 Icarus 主题）的骨架：顶部一条导航、
      左栏作者卡、右栏文章卡片。字号 14px、卡片内边距 21px、
      文章标题 28px 且字重只有 400——标题不用加粗是它观感清爽的关键。
   4. 深色模式跟着系统走：两套颜色共用同一组变量名，不写第二套规则。

   单独一个文件而不是内联 <style>：安全响应头里的 CSP 没有放开 style-src，
   内联样式会被浏览器直接拦掉，页面会退化成裸 HTML。 */

:root {
  color-scheme: light dark;

  /* 底色与卡片配色对齐参考站（Hexo 的 Icarus 主题）：
     浅色 #f5f5f5 + 纯白卡片，深色 #2b2b2b + #3c3c3c 卡片。
     之前那套暖白/暖灰是我自己配的，配上珊瑚红之后整体偏"土"——
     中性灰底 + 一个彩色强调色，对比关系比"两种暖色叠在一起"清楚得多。 */
  /* 底色保持中性灰，不跟参考站走。

     参考站用的是和它强调色同色相的淡紫底。我们的配色是单独定的，
     跟着改会把整套观感拽向另一个方向——结构、字体、间距这些可以照搬，
     颜色是我们自己的。 */
  --bg: #f5f5f5;
  --card: #ffffff;
  --nav: rgba(255, 255, 255, .77);
  --title: #363636;
  --fg: #4a4a4a;
  --muted: #7a7a7a;
  --hint: #9a9a9a;
  --line: #e6e6e6;
  --hover: #fafafa;

  --accent: #884499;
  --accent-strong: #6d3680;
  --accent-2: #b07ac8;
  --accent-3: #6f86c9;

  --avatar: linear-gradient(150deg, #b07ac8, #6d3680);
  --btn-bg: #f5f5f5;
  --btn-fg: rgba(0, 0, 0, .7);

  /* 代码高亮的记号颜色。
     取值参考 GitHub 的深色主题：代码块本身是深色的，几十种语言下都不会
     出错的配色自己配很容易翻车。颜色全部走变量，浅色模式下代码块也是
     深色块——一块深色区域让代码和正文一眼分开，不需要再加边框和标题。 */
  --code-bg: #2f3136;
  --code-fg: #e6e6ea;
  --code-keyword: #ff9d8c;
  --code-string: #9ec9f0;
  --code-number: #e8c07d;
  --code-function: #c9a7f5;
  --code-variable: #e8b088;
  --code-tag: #a7d8a0;
  --code-punctuation: #9aa0a6;
  --code-comment: #9aa0a6;
  --code-diff-add: #a7d8a0;
  --code-diff-del: #ff9d8c;

  --radius: 10px;
  /* 容器宽度照参考站（Bulma 的断点容器）：1152px，屏幕够宽时 1344px。
     之前我一直卡在 1200px：在 1440 宽的窗口下比参考站窄 12%，
     三栏各少 36px，看起来就是没有铺开。 */
  --shell: 1152px;
  /* 正文栏宽。40rem = 640px，18px 字号下大约一行 35 个汉字，
     落在中文阅读最舒服的 30–40 字区间里。 */
  --measure: 40rem;
  --mono: "Source Code Pro", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", "PingFang SC", "Microsoft YaHei", monospace;
}

/* 自托管字体。

   读者端的 CSP 是 default-src 'self'，Google Fonts 那类外链会被浏览器
   直接拦掉，所以字体文件必须由本站发出去。两款都是开源字体（Ubuntu 与
   Source Code Pro 走 SIL OFL），可以随站点一起分发。

   只带了拉丁字母：一套中文字体动辄好几 MB，按需子集化又要在构建期引入
   字体工具链；参考站也是同样的做法——它的字体栈里中文回落到系统字体。
   font-display: swap 让文字先用后备字体显示，字体到位再换，不会白屏。 */
@font-face {
  font-family: Ubuntu;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/ubuntu-400.woff2") format("woff2");
}
@font-face {
  font-family: Ubuntu;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/ubuntu-700.woff2") format("woff2");
}
@font-face {
  font-family: "Source Code Pro";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/source-code-pro-400.woff2") format("woff2");
}

@media (prefers-color-scheme: dark) {
  /* 只在"没有手动选过浅色"时生效：用户手动选过，就以他的选择为准。 */
  :root:not([data-theme="light"]) {
    --bg: #2b2b2b;
    --card: #3c3c3c;
    --nav: rgba(69, 69, 69, .77);
    --title: #ffffff;
    --fg: #e6e6e6;
    --muted: #b5b5b5;
    --hint: #9a9a9a;
    --line: #4a4a4a;
    --hover: #464646;

    --accent: #a878c0;
    --accent-strong: #8e5aa8;
    --accent-2: #c79bd8;
    --accent-3: #8fa6e0;

    --btn-bg: #2b2b2b;
    --btn-fg: #ffffff;

    --code-bg: #1c1917;
  }
}

/* 手动选了深色。这一组值和上面媒体查询里那组必须一致——
   CSS 没有变量块的复用机制，但漏掉一处，就会出现"跟随系统时颜色对、
   手动切深色时颜色不对"这种只在一条路径上出现的 bug。 */
:root[data-theme="dark"] {
  --bg: #2b2b2b;
  --card: #3c3c3c;
  --nav: rgba(69, 69, 69, .77);
  --title: #ffffff;
  --fg: #e6e6e6;
  --muted: #b5b5b5;
  --hint: #9a9a9a;
  --line: #4a4a4a;
  --hover: #464646;

  --accent: #a878c0;
  --accent-strong: #8e5aa8;
  --accent-2: #c79bd8;
  --accent-3: #8fa6e0;

  --btn-bg: #2b2b2b;
  --btn-fg: #ffffff;

  --code-bg: #1c1917;
}

* { box-sizing: border-box; }

/* 切换深浅色的那一瞬间才挂上的类（见 app.js）：
   让底色和文字是"划过去"而不是"跳过去"。
   常驻全局过渡会让每一次交互都慢半拍，所以只在这 300ms 里开。 */
:root.theme-switching,
:root.theme-switching * {
  transition: background-color .2s ease-out, color .2s ease-out, border-color .2s ease-out !important;
}

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

/* 点击"回到顶部"这类锚点链接时平滑滚动，但尊重系统的"减少动态效果"设置。 */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  /* 字体栈照参考站：Ubuntu 打头，中文回落到系统字体。
     Ubuntu 的字形比默认的 Segoe UI / 苹方更圆、字怀更开，同样是 14px，
     观感要"轻"一些——这也是参考站整套版式看起来不挤的原因之一。 */
  font-family: Ubuntu, Roboto, "Open Sans", "PingFang SC", "Hiragino Sans GB",
    "Microsoft YaHei", sans-serif;
  font-size: 14px;
  line-height: 1.7;
  /* 中文断行：标点不跑到行首，长链接不撑破布局。 */
  line-break: strict;
  overflow-wrap: break-word;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-strong); text-decoration: underline; text-underline-offset: .18em; }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* 内联 SVG 图标。
   用 em 做单位：图标大小跟着所在文字走，元信息里的图标和标题里的大图标
   用同一份 CSS 就够了。vertical-align 的负值是让图标的中线落在汉字的中腰上。 */
.icon {
  inline-size: 1.05em;
  block-size: 1.05em;
  flex: none;
  vertical-align: -0.15em;
}

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

/* ------------------------------------------------------------------ 顶栏 */

.navbar {
  background: var(--nav);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
  backdrop-filter: blur(12px);
}
.navbar-in {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 10.5px;
  min-height: 52px;
  display: flex;
  align-items: center;
  gap: 6px;
}
/* 顶栏最左边的站名。字号和字距照参考站的品牌位取值：
   它是 14px、字重 700、字距 1.4px（≈0.1em）。
   字距拉开是为了让"站名"和紧挨着它的导航在视觉上分成两类，
   否则一排同样大小同样粗细的文字，读起来像七个并列的导航项。 */
.site-title {
  flex: none;
  margin-right: 24px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--title);
}
.site-title:hover { color: var(--accent); text-decoration: none; }
/* 导航紧跟在站名后面，左对齐。

   参考站实测：站名 x=50（宽 125），四个菜单项依次在 x=174 / 233 / 308 / 368，
   也就是紧贴站名、从左边排开；右侧两个图标在 x=1142 / 1177。
   我之前做成了"导航居中"，那不是它的样子。 */
.site-nav { display: flex; align-items: center; justify-content: flex-start; flex: 1 1 auto; }
/* 顶栏一律直角：当前项是一块实心色块，而不是小圆角药片。 */
.site-nav a {
  font-size: 14px;
  color: var(--muted);
  padding: 7px 13px;
  border-radius: 0;
}
.site-nav a:hover { background: var(--hover); color: var(--title); text-decoration: none; }
.site-nav a[aria-current="page"] { background: var(--accent); color: #fff; }
.navbar-end { display: flex; align-items: center; gap: 2px; flex: none; }
.navbar-end a {
  inline-size: 34px;
  block-size: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  border-radius: 0;
}
.navbar-end a:hover { background: var(--hover); color: var(--title); text-decoration: none; }
.navbar-end svg { inline-size: 16px; block-size: 16px; }

/* 深色模式切换按钮。两个图标都在 DOM 里，靠 data-theme 决定显示哪一个——
   这样切换时不用改 DOM，也就不用担心"图标和主题状态不同步"。 */
.theme-toggle {
  inline-size: 34px;
  block-size: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  color: var(--muted);
  background: none;
  border: 0;
  border-radius: 0;
  cursor: pointer;
}
.theme-toggle:hover { background: var(--hover); color: var(--title); }
.theme-toggle svg { inline-size: 16px; block-size: 16px; }
.theme-toggle .theme-icon-dark { display: none; }
/* 跟随系统的深色下显示太阳（点一下回到浅色） */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .theme-icon-light { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .theme-icon-dark { display: block; }
}
/* 手动选了深色时同理 */
:root[data-theme="dark"] .theme-toggle .theme-icon-light { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-icon-dark { display: block; }

/* 搜索：平时只是一个放大镜，点开才露出输入框。

   参考站也是这么做的（顶栏右侧只有两个 35px 的图标按钮，没有常驻输入框）：
   搜索是低频动作，让它常驻会把顶栏塞满，还把一个长长的输入框摆在导航旁边，
   视线每次扫过都要处理它。 */
.site-search { position: relative; }
.site-search > summary {
  inline-size: 34px;
  block-size: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  cursor: pointer;
  list-style: none;
}
/* 去掉浏览器自带的三角标；不同浏览器一个用 ::marker 一个用私有伪元素。 */
.site-search > summary::-webkit-details-marker { display: none; }
.site-search > summary::marker { content: ""; }
.site-search > summary:hover { background: var(--hover); color: var(--title); }
.site-search[open] > summary { background: var(--hover); color: var(--accent); }
.site-search form {
  position: absolute;
  top: 100%;
  right: 0;
  padding: 8px;
  background: var(--card);
  border-radius: 10px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}
.site-search input {
  inline-size: 13rem;
  padding: 6px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--title);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0;
}
.site-search input::placeholder { color: var(--hint); }
.site-search input:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }

/* ------------------------------------------------------------ 栏与卡片布局 */

.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 12px 10.5px 0;
}
.columns {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  margin: 0 -10.5px;
}
.column { padding: 0 10.5px; }
/* 左栏作者卡，右栏内容。窄屏时按 DOM 顺序：文章在前、作者卡落到下面。 */
.column-main { order: 2; flex: 0 0 66.667%; max-width: 66.667%; min-width: 0; }
.column-left { order: 1; flex: 0 0 33.333%; max-width: 33.333%; position: sticky; top: 64px; }
.column-right { order: 3; display: none; flex: 0 0 25%; max-width: 25%; position: sticky; top: 64px; }

/* ---------------------------------------------------- 右栏的三个小组件 */

.widget-title {
  margin: 0 0 12px;
  font-size: 16px;
  font-weight: 400;
  color: var(--title);
}
.widget-list { list-style: none; margin: 0; padding: 0; }
.widget-list li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
  border-bottom: 1px solid var(--line);
}
.widget-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.widget-list a { color: var(--fg); }
.widget-list a:hover { color: var(--accent); text-decoration: none; }
/* 日期与计数靠右，用等宽数字对成一列——这一栏是拿来扫的，不是拿来读的。 */
.widget-list .date,
.widget-list .count {
  margin-left: auto;
  flex: none;
  font-size: 12px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}
.widget-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.widget-tags a {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  line-height: 18px;
  padding: 2px 9px;
  border-radius: 4px;
  background: var(--btn-bg);
  color: var(--muted);
}
.widget-tags a:hover { background: var(--accent); color: #fff; text-decoration: none; }
.widget-tags a span { font-size: 11px; opacity: .7; }

.card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
  overflow: hidden;
}
.card-content { padding: 21px; }

/* ------------------------------------------------------------ 左栏：作者卡 */

.profile { text-align: center; }
.profile-avatar {
  inline-size: 128px;
  block-size: 128px;
  margin: 0 auto;
  border-radius: 20px;
  background: var(--avatar);
  box-shadow: 0 5px 9px 2px rgba(0, 0, 0, .08);
  object-fit: cover;
  display: block;
}
.profile-name { margin: 14px 0 0; font-size: 21px; font-weight: 400; color: var(--title); }
.profile-signature { margin: 5px 0 0; font-size: 12px; color: var(--muted); }
.profile-bio { margin: 14px 0 0; font-size: 13px; line-height: 1.75; color: var(--fg); text-align: left; }

/* 三个数字：标签在上、数字在下（照参考站），中间用细线隔开——
   比三个小卡片轻，也比一行纯文字更能一眼扫到。 */
.profile-stats {
  display: flex;
  margin: 16px 0 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.profile-stats > * {
  flex: 1;
  padding: 9px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  color: inherit;
}
/* 分隔线用"除第一个之外都加左边框"，而不是给每种组合写一遍相邻选择器：
   这里混了 <a> 和 <span> 两种元素，逐个写会漏。 */
.profile-stats > * + * { border-left: 1px solid var(--line); }
.profile-stats .n {
  display: block;
  font-size: 17px;
  color: var(--title);
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}
/* 标签做成大写小字，和数字拉开层次；数字才是这一格的主体。 */
.profile-stats .l {
  font-size: 10.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.profile-stats > a:hover { text-decoration: none; }
.profile-stats > a:hover .n { color: var(--accent); }

/* 「在做 / 在读」：站长没填就整块不显示，不留空占位。 */
.profile-now { margin: 16px 0 0; border-top: 1px solid var(--line); padding-top: 12px; text-align: left; }
.profile-now .row { display: flex; gap: 10px; font-size: 12.5px; line-height: 1.7; padding: 3px 0; }
.profile-now .key { flex: none; inline-size: 44px; color: var(--muted); }
.profile-now .key::before {
  content: "";
  display: inline-block;
  inline-size: 5px;
  block-size: 5px;
  background: var(--accent-2);
  margin-right: 7px;
  vertical-align: .1em;
}
.profile-now .value { color: var(--fg); }

.profile-links { display: flex; justify-content: center; gap: 6px; margin: 16px 0 0; }
.profile-links a {
  inline-size: 32px;
  block-size: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  background: var(--btn-bg);
  color: var(--muted);
}
.profile-links a:hover { background: var(--accent); color: #fff; text-decoration: none; }
.profile-subscribe {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 12px 0 0;
  padding: 8px 0;
  font-size: 12.5px;
  text-align: center;
  background: var(--accent);
  color: #fff;
  /* 胶囊形，照参考站的 is-rounded。它是这张卡上唯一想让人点的那一个，
     直角矩形会和上面那些方方正正的统计格混在一起。 */
  border-radius: 999px;
}
.profile-subscribe:hover { background: var(--accent-strong); color: #fff; text-decoration: none; }

/* -------------------------------------------------------------- 文章卡片 */

.level {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 21px;
}
.meta {
  display: flex;
  align-items: center;
  /* 手机上这一串（日期 · 分类 · 更新时间 · 浏览量）比屏幕还宽，
     不换行就会被硬挤出横向滚动。 */
  flex-wrap: wrap;
  gap: .4rem;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
  /* 日期用等宽数字：列表里几行的日期能对齐成一列。 */
  font-variant-numeric: tabular-nums;
}
.meta b { font-weight: 400; color: var(--hint); }
.meta-sep { color: var(--hint); }
.post-cat { font-size: 12px; color: var(--muted); flex: none; }
.post-cat:hover { color: var(--accent); }

/* 标题 28px、字重 400：不加粗是这套版式里最反直觉、也最关键的一条。 */
.post-title {
  margin: 0 0 18px;
  font-size: 28px;
  line-height: 1.2;
  font-weight: 400;
  letter-spacing: -.01em;
  color: var(--title);
}
.post-title a { color: inherit; }
.post-title a:hover { color: var(--accent); text-decoration: none; }

/* 摘要与正文都限制在 40rem（约 45 个汉字）以内。
   卡片本身可以宽，但一行 60 个汉字的正文读起来会串行——
   版式再好看，读不下去也是白搭。 */
.post-summary { margin: 0; max-width: 40rem; color: var(--fg); }
.post-summary p { margin: 0 0 12px; }
.post-summary p:last-child { margin-bottom: 0; }

.button {
  display: inline-block;
  margin-top: 18px;
  font-size: 12px;
  border-radius: var(--radius);
  padding: 4px 12px;
  background: var(--btn-bg);
  color: var(--btn-fg);
}
.button:hover { background: var(--accent); color: #fff; text-decoration: none; }

.empty { color: var(--muted); }

/* ---------------------------------------------------------------- 页面标题 */

.page-title {
  margin: 0;
  padding: 21px;
  font-size: 21px;
  font-weight: 400;
  color: var(--title);
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}
.page-title .icon { color: var(--accent); margin-right: .3em; }

/* 页面标题出现在卡片内部时，不再自成一张卡。
   外面的 .card 已经给了底色、圆角和内边距，标题再套一层就成了"卡里还有
   一张卡"——两层边框叠在一起，看起来像没对齐。 */
.card .page-title {
  margin: 0 0 16px;
  padding: 0;
  background: none;
  border-radius: 0;
  box-shadow: none;
}

/* ---------------------------------------------------------------- 文章页 */

.post h1 {
  margin: 0 0 18px;
  font-size: clamp(24px, 1.1rem + 1.6vw, 30px);
  line-height: 1.25;
  font-weight: 400;
  letter-spacing: -.015em;
  color: var(--title);
}
.post > .meta { margin-bottom: 12px; }
.post-body {
  margin-top: 24px;
  max-width: 40rem;
  font-size: 15px;
  line-height: 1.95;
}

/* 正文最后一块的下外边距不参与外层间距。

   它的值取决于正文最后一个元素是什么——段落是 1.15rem、引用块和代码块
   是 1.5rem——于是"正文结束到上一篇/下一篇之间"空多少会随文章内容变，
   同一页上一篇文章是 21px、下一篇可能是 28px。归零之后统一由下面那条
   栏内间距规则给。 */
.post-body > *:last-child { margin-bottom: 0; }

.post-body h2,
.post-body h3,
.post-body h4 { line-height: 1.45; letter-spacing: -.01em; color: var(--title); }
/* 标题上方的留白明显大于下方：长文的分段靠这个，不靠分割线。 */
.post-body h2 { font-size: 21px; font-weight: 600; margin: 2.4rem 0 .9rem; }
.post-body h3 { font-size: 17px; font-weight: 600; margin: 2rem 0 .7rem; }
.post-body h4 { font-size: 15px; font-weight: 600; margin: 1.75rem 0 .5rem; color: var(--muted); }

/* 锚点跳转时给顶栏留出位置。

   顶栏是吸顶的，占着视口最上面那 53px。没有这条时，浏览器会把目标标题
   滚到视口顶端（top: 0），标题正好被顶栏盖住——点了目录却看不见标题。
   留 68px = 顶栏高度加上一点余量，跳过去之后标题完整露在下面。 */
.post-body h2,
.post-body h3,
.post-body h4 {
  scroll-margin-top: 68px;
}

/* 标题锚点。平时不显示，鼠标移到标题上才浮出来。

   一直亮着的话，每一节的标题后面都挂一个井号，正文看着很吵；
   而它真正的用途是"想把这一节的地址发给别人"，那是个低频动作，
   要的时候找得到就够了。 */
.post-body .headerlink {
  margin-left: .35em;
  color: var(--hint);
  font-weight: 400;
  text-decoration: none;
  opacity: 0;
  transition: opacity .15s ease-out, color .15s ease-out;
}
.post-body h2:hover .headerlink,
.post-body h3:hover .headerlink,
.post-body h4:hover .headerlink,
.post-body .headerlink:focus-visible {
  opacity: 1;
}
.post-body .headerlink:hover { color: var(--accent); }

/* 剧透：正文里写成 ||这样|| 的内容默认是糊的，鼠标移上去才显形。

   模糊值比编辑器那边大一点（正文的字更大），但也没大到完全看不出内容——
   留一点轮廓，读者能判断"这一段大概多长"，才愿意去点它。

   :active 是给触屏兜底的：那边没有悬停，手指按住时显形，
   至少不是永远看不清。 */
.post-body .blur {
  filter: blur(5px);
  cursor: help;
  transition: filter .18s ease-out;
}
.post-body .blur:hover,
.post-body .blur:focus,
.post-body .blur:active {
  filter: none;
}

/* 触屏没有悬停，锚点会永远看不到，所以常显（淡一点，别抢戏）。 */
@media (hover: none) {
  .post-body .headerlink { opacity: .45; }
}

.post-body p { margin: 1.15rem 0; }
.post-body ul, .post-body ol { margin: 1.15rem 0; padding-left: 1.5em; }
.post-body li { margin: .35rem 0; }
.post-body li > ul, .post-body li > ol { margin: .35rem 0; }

.post-body a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
}
.post-body a:hover { text-decoration-thickness: 2px; }

.post-body img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 1.75rem 0;
  border-radius: var(--radius);
}

.post-body blockquote {
  margin: 1.5rem 0;
  padding: .8rem 1.2rem;
  border-radius: var(--radius);
  background: var(--hover);
  color: var(--fg);
}
.post-body blockquote p { margin: .4rem 0; }

.post-body hr { border: 0; border-top: 1px solid var(--line); margin: 2.2rem 0; }

/* ------------------------------------------------------------ 代码与高亮 */

.post-body code {
  font-family: var(--mono);
  font-size: .88em;
  padding: .12em .4em;
  border-radius: 6px;
  background: var(--hover);
}
.post-body pre {
  position: relative;
  margin: 1.5rem 0;
  padding: 34px 16px 16px;
  overflow-x: auto;
  border-radius: var(--radius);
  background: var(--code-bg);
}
.post-body pre code { padding: 0; font-size: 13px; background: none; }

/* 代码块工具条由 app.js 注入（渐进增强：没有 JS 时就是一个普通代码块）。 */
.code-toolbar {
  position: absolute;
  inset: 0 0 auto 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 10px;
  font-size: 11px;
  color: #9aa0a6;
}
.code-lang { letter-spacing: .08em; text-transform: uppercase; }
.code-copy {
  font: inherit;
  color: #9aa0a6;
  background: none;
  border: 0;
  padding: 2px 6px;
  cursor: pointer;
}
.code-copy:hover { color: #e6e6ea; }

/* 高亮的类名是 chroma 的约定（1–3 个小写字母），没法改，所以这里按它的
   记号类型分组。只写"有区别"的那几类，其余继承代码块的正文颜色——
   给每个记号都配一种颜色只会让代码看起来像圣诞树。

   注释刻意**不用斜体**：代码注释里中文很常见，而中文没有真正的斜体，
   浏览器只会把字斜着拉一下，糊得很难看。 */
.post-body pre code { color: var(--code-fg); }
/* .cp 是预处理指令（#include、#!/bin/bash 这类），它属于注释大类，
   但 chroma 给的是独立类名，漏掉的话 shell 脚本第一行会是默认色。 */
.post-body pre .c, .post-body pre .ch, .post-body pre .cm,
.post-body pre .c1, .post-body pre .cs, .post-body pre .cp { color: var(--code-comment); }

.post-body pre .k, .post-body pre .kc, .post-body pre .kd,
.post-body pre .kn, .post-body pre .kp, .post-body pre .kr,
.post-body pre .kt { color: var(--code-keyword); }

.post-body pre .s, .post-body pre .sa, .post-body pre .sb,
.post-body pre .sc, .post-body pre .dl, .post-body pre .sd,
.post-body pre .s2, .post-body pre .se, .post-body pre .sh,
.post-body pre .si, .post-body pre .sx, .post-body pre .sr,
.post-body pre .s1, .post-body pre .ss { color: var(--code-string); }

.post-body pre .m, .post-body pre .mb, .post-body pre .mf,
.post-body pre .mh, .post-body pre .mi, .post-body pre .il,
.post-body pre .mo { color: var(--code-number); }

.post-body pre .nf, .post-body pre .fm, .post-body pre .nc,
.post-body pre .nd, .post-body pre .ne, .post-body pre .nn,
.post-body pre .no, .post-body pre .ni, .post-body pre .nl { color: var(--code-function); }

.post-body pre .nv, .post-body pre .na, .post-body pre .nb,
.post-body pre .nx, .post-body pre .py { color: var(--code-variable); }

.post-body pre .nt { color: var(--code-tag); }
.post-body pre .o, .post-body pre .ow { color: var(--code-fg); }
.post-body pre .p { color: var(--code-punctuation); }

/* 差异块（```diff）别只靠颜色：符号前缀本身也带着信息，色盲用户分得清。 */
.post-body pre .gi { color: var(--code-diff-add); }
.post-body pre .gd { color: var(--code-diff-del); }

/* ---------------------------------------------------------------- 表格 */

.post-body table {
  display: block;
  width: 100%;
  margin: 1.5rem 0;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: 14px;
}
.post-body th, .post-body td { padding: .55rem .8rem; border-bottom: 1px solid var(--line); text-align: left; }
.post-body th { color: var(--muted); font-weight: 600; border-bottom-color: var(--title); }

/* -------------------------------------------------------------- 上一篇/下一篇 */

.siblings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 21px;
}
.sibling {
  display: block;
  padding: 21px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
  color: var(--title);
  font-size: 14px;
  line-height: 1.55;
}
.sibling:hover { color: var(--accent); text-decoration: none; }
.sibling .label {
  display: block;
  margin-bottom: .4rem;
  font-size: 12px;
  color: var(--muted);
}
.sibling.newer { text-align: right; }

/* ------------------------------------------------------------------ 标签 */

.tag-list, .tag-cloud {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 0;
  margin: 14px 0 0;
}
.tag-list a, .tag-cloud a {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font-size: 12px;
  line-height: 18px;
  padding: 2px 9px;
  border-radius: 4px;
  background: var(--btn-bg);
  color: var(--muted);
}
.tag-list a:hover, .tag-cloud a:hover { background: var(--accent); color: #fff; text-decoration: none; }
/* 标签云按顺序轮换三种点缀色：一整片同色的小方块看不出区别，
   而标签云本来就是用来"扫"的。 */
.tag-cloud a:nth-child(3n+1) { background: var(--accent); color: #fff; }
.tag-cloud a:nth-child(3n+2) { background: var(--accent-2); color: #fff; }
.tag-cloud a:nth-child(3n) { background: var(--accent-3); color: #fff; }
.tag-cloud { margin: 0; padding: 21px; background: var(--card); border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1); gap: 8px; }
.tag-cloud .count, .tag-list .count { opacity: .7; font-size: 11px; }

/* ------------------------------------------------------------------ 归档 */

.archive-year {
  padding: 21px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}
.archive-year h2 {
  margin: 0 0 12px;
  font-size: 17px;
  font-weight: 400;
  color: var(--title);
}
.archive-list { list-style: none; margin: 0; padding: 0; }
.archive-list li {
  display: flex;
  gap: 14px;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
}
.archive-list li:last-child { border-bottom: 0; }
.archive-list time {
  flex: none;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ 友链 */

/* 说明文字沿用正文的排版，但不套正文为长文准备的那两处限制：
   40rem 的行宽对一段说明太窄，24px 的上外边距在卡片里也是多余的。 */
.friend-intro {
  max-width: none;
  margin-top: 0;
  font-size: 14px;
  line-height: 1.8;
}

/* 关于页的正文也套在卡片里。上外边距去掉——那个 24px 是为了把正文和
   文章标题拉开，而这里上面是卡片的 padding。 */
.about-body {
  max-width: none;
  margin-top: 0;
}

.friend-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* 用 auto-fill 而不是固定两列：友链的描述有长有短，固定列数会让
     短的那张卡片右侧空出一大截。宽度不够时它自己就退回一列。 */
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 12px;
}

.friend-card { min-width: 0; }

.friend-link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
  color: inherit;
}
.friend-link:hover {
  color: inherit;
  text-decoration: none;
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, .08), 0 0 1px rgba(0, 0, 0, .1);
}

.friend-avatar {
  inline-size: 48px;
  block-size: 48px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--btn-bg);
}
/* 没抓到对方头像时的占位：一个圆底加站点名首字母。 */
.friend-initial {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  color: var(--accent);
}

.friend-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* 不加这条的话，长站点名会把 flex 项撑开、把右边的图标挤出卡片。 */
  min-width: 0;
}
.friend-name {
  color: var(--title);
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.friend-desc {
  color: var(--muted);
  font-size: 12px;
  /* 描述最多两行：再多就把卡片撑成高低不齐的一列。 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 外链图标只在悬停时亮起来。它在一排卡片里反复出现，一直高亮会抢戏。 */
.friend-link .icon {
  flex: none;
  margin-left: auto;
  color: var(--hint);
  transition: color .2s ease-out;
}
.friend-link:hover .icon { color: var(--accent); }

/* 打不开的友链淡下去。排序在服务端做（is_lost 排最后）。 */
.friend-card.is-lost { opacity: .5; }

/* ------------------------------------------------------------------ 分页 */

/* -------------------------------------------------------------- 文章目录 */

/* -------------------------------------------------------------- 碎碎念 */

/* 时间线。每条一张卡，和文章列表同一种底色——它们是同一个站点的内容，
   只是长短不同。

   列表之间用 grid gap 给间距而不是给每张卡写 margin：
   和主栏里那条「相邻块留 21px」的规则是同一个思路。 */
.note-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
}
.note {
  padding: 18px 21px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}

/* 碎碎念里的正文和文章正文是同一套排版（都带 .post-body），
   但两处要压一压，否则短内容被撑得比说话还长。 */
.note-body { margin-top: 0; }
.note-body p:first-child { margin-top: 0; }
.note-body p:last-child { margin-bottom: 0; }
.note-body img { margin: 12px 0; border-radius: var(--radius); }

.note-meta {
  margin: 12px 0 0;
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 8px;
}
.note-time { color: var(--muted); }
.note-time:hover { color: var(--accent); }
/* "已编辑"用弱化的样式：它是补充信息，不该和日期抢注意力。 */
.note-edited {
  font-size: 11px;
  color: var(--hint);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 7px;
}
.note-sep { color: var(--hint); }

.notes-intro {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
}

/* 右栏最上面那一块，和「最近文章」「标签」是同一类 widget。
   每一项是「序号 + 标题」，编号用等宽数字——这样一列下来数字是齐的，
   不会因为 1 和 10 的宽度差把标题推得忽左忽右。 */
.toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.toc-list li { border-bottom: 1px solid var(--line); }
.toc-list li:last-child { border-bottom: 0; }
.toc-list a {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
  color: var(--fg);
}
.toc-list a:hover { color: var(--accent); text-decoration: none; }
.toc-num {
  flex: none;
  min-inline-size: 14px;
  font-size: 11px;
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}
.toc-text { min-width: 0; }
/* 三级标题缩进一级，层级一眼看得出来。 */
.toc-list .toc-l3 a { padding-left: 18px; }

/* -------------------------------------------------------- 文章末尾的版权 */

/* 照参考站的形式：上面一条是标题和这篇文章的地址，下面一排是
   Author / Posted on / Updated on / Licensed under。

   独立成一张卡片（.card 已经在模板上给了底色和圆角）。
   间距交给上面那条「栏内块间距」规则统一给，这里不写 margin-top。 */
.post-license {
  font-size: 12.5px;
}
.license-title {
  margin: 0;
  font-size: 14px;
  color: var(--title);
}
/* 标题那一条和下面那排字段之间再分一次：上面是"这是哪篇文章"，
   下面是"它的元信息"，两类东西。 */
.license-head {
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.license-url {
  margin: 4px 0 0;
  color: var(--muted);
  /* 长地址在窄屏上要能断行，否则会把卡片撑出去。 */
  overflow-wrap: anywhere;
}
.license-url a { color: inherit; }

.license-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  margin-top: 12px;
}
/* 标签用大写小字、值用正常字号：和作者卡的统计格是同一套层次。 */
.license-meta .key {
  display: block;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--hint);
}
.license-meta .value {
  display: block;
  margin-top: 2px;
  color: var(--fg);
}

/* 许可徽章。图标位比正文里的图标略大一点：它们要在圆环里画出图形，
   小一号就看不出来是什么了。上一版没有这条规则，用的是默认尺寸，
   而徽章本身又是"圆环 + 8px 字母"拼的——两个原因叠在一起就成了糊的。 */
.license-icons a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
}
.license-icons a:hover { color: var(--accent); }
.license-icons .icon {
  inline-size: 18px;
  block-size: 18px;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  margin: 21px 0;
}
.pagination a, .pagination span {
  min-inline-size: 30px;
  block-size: 30px;
  padding: 0 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  background: var(--card);
  color: var(--muted);
  border-radius: 4px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}
.pagination a:hover { background: var(--accent); color: #fff; text-decoration: none; }
.pagination [aria-current="page"] { background: var(--accent); color: #fff; }
.pagination .disabled { opacity: .5; }
.page-numbers { list-style: none; display: flex; gap: 5px; margin: 0; padding: 0; }
.page-numbers li { display: flex; }

/* ------------------------------------------------------------------ 评论区 */

.comments {
  padding: 21px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .05), 0 0 1px rgba(0, 0, 0, .1);
}
.comments h2 { margin: 0 0 14px; font-size: 17px; font-weight: 400; color: var(--title); }
.comment-list { list-style: none; margin: 0; padding: 0; }
.comment { padding: 14px 0; border-bottom: 1px solid var(--line); }
.comment.is-reply { margin-left: 1.5rem; padding-left: 14px; border-left: 2px solid var(--line); }
.comment-meta { display: flex; align-items: center; gap: .5rem; margin: 0 0 .4rem; font-size: 12px; color: var(--hint); }
.comment-author { font-weight: 600; color: var(--title); }
.comment-body { white-space: pre-wrap; font-size: 14px; }
.comment-actions { margin: .35rem 0 0; font-size: 12px; }
.comment-notice, .comment-alert {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 0 0 14px;
  padding: .6rem .8rem;
  border-radius: 6px;
  font-size: 13px;
}
.comment-notice { background: rgba(127, 182, 217, .16); }
.comment-alert { background: rgba(224, 96, 96, .14); color: var(--accent-strong); }
.comment-empty { color: var(--muted); }
.comment-pages { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 14px; font-size: 13px; }
.comment-pages .disabled { color: var(--hint); }
.comment-page-number { color: var(--hint); font-size: 12px; }

.comment-form { margin-top: 21px; border-top: 1px solid var(--line); padding-top: 18px; }
.comment-form-title { margin: 0 0 .8rem; font-size: 15px; font-weight: 600; color: var(--title); }
.comment-cancel-reply { margin: 0 0 .8rem; font-size: 12px; }
.comment-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 12px; }
.comment-form p { margin: 0 0 12px; }
.comment-form label { display: block; margin-bottom: .3rem; font-size: 12px; color: var(--muted); }
.comment-form input, .comment-form textarea {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 14px;
  color: var(--title);
  background: var(--btn-bg);
  border: 1px solid transparent;
  border-radius: 6px;
}
.comment-form input:focus-visible, .comment-form textarea:focus-visible {
  border-color: var(--accent);
  outline: none;
}
.comment-form textarea { resize: vertical; }
/* 蜜罐：真人看不见这个输入框（移出视口而不是 display:none——
   有些脚本会跳过隐藏元素），脚本按字段名一路填过去就会填上它。 */
.comment-honeypot { position: absolute; left: -9999px; }
.comment-submit { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.btn-comment {
  font: inherit;
  font-size: 13px;
  padding: 8px 18px;
  color: #fff;
  background: var(--accent);
  border: 0;
  border-radius: 4px;
  cursor: pointer;
}
.btn-comment:hover { background: var(--accent-strong); }
.comment-hint { font-size: 12px; color: var(--hint); }

/* ------------------------------------------------------------ 404 与提示 */

.notfound { padding: 60px 21px; text-align: center; }
.notfound-icon { margin: 0 0 12px; color: var(--hint); }
.notfound-icon .icon { inline-size: 2.5rem; block-size: 2.5rem; }
.notfound h1 { margin: 0 0 .5rem; font-size: 21px; font-weight: 400; color: var(--title); }
.notfound p { margin: .5rem 0; color: var(--muted); }
.btn-home {
  display: inline-block;
  margin-top: 12px;
  padding: 8px 18px;
  font-size: 13px;
  background: var(--accent);
  color: #fff;
  border-radius: 4px;
}
.btn-home:hover { background: var(--accent-strong); color: #fff; text-decoration: none; }

.preview-banner {
  max-width: var(--shell);
  margin: 12px auto 0;
  padding: 10px 21px;
  font-size: 13px;
  background: rgba(232, 163, 61, .18);
  color: var(--title);
  border-radius: var(--radius);
}
.preview-banner .icon { margin-right: .4em; }

/* ------------------------------------------------------------------ 页脚 */

.site-footer {
  max-width: var(--shell);
  margin: 21px auto 0;
  padding: 21px 10.5px 30px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 12px;
  color: var(--muted);
}
.site-footer p { margin: 0; }
.footer-links { display: flex; gap: 16px; }
.footer-links a { color: var(--muted); }
.footer-links a:hover { color: var(--accent); }
.footer-links .icon { margin-right: .35em; }

/* 页脚文字是渲染过的 Markdown，里面可能是 <p>：
   段落自带外边距，不去掉的话页脚会被撑高、和右边的链接对不齐。 */
.footer-text p { margin: 0; }
.footer-text p + p { margin-top: 4px; }
.footer-text a { color: inherit; text-decoration: underline; }

/* 回到顶部的圆形按钮。它和旁边的文字链接是两回事：那些是"去别处"，
   这个是"回上面"，形状上分开之后一眼就能区分。 */
.footer-top {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 50%;
  background: var(--btn-bg);
  color: var(--muted);
  transition: background-color .2s ease-out, color .2s ease-out;
}
.footer-top:hover { background: var(--accent); color: #fff; text-decoration: none; }
.footer-top .icon { inline-size: 16px; block-size: 16px; margin: 0; }

/* ------------------------------------------------------------------ 窄屏 */

/* 宽屏才出现第三栏：左 25% / 中 50% / 右 25%。
   三个断点的取值跟着参考站（它用的是 Bulma 的 768 / 1088 / 1280），
   所以栏数和比例在各尺寸下都对得上：≤768 单列、769–1279 两栏、
   ≥1280 三栏。 */
@media (min-width: 1280px) {
  .column-left { flex: 0 0 25%; max-width: 25%; }
  .column-main { flex: 0 0 50%; max-width: 50%; }
  .column-right { display: block; }
}

@media (min-width: 1408px) {
  :root { --shell: 1344px; }
}

@media (max-width: 1279px) {
  /* 窄一点时右栏收进主栏下面，不占横向空间。 */
  .column-right { display: none; }
}

/* 顶栏折成两行：站名一行居中，导航和右侧图标一行居中。

   参考站就是这么做的——它的容器在窄屏从 flex 换成 block，两块各占一行。
   两行各自居中、左右留白对称；挤在一行的话，站名靠左、导航要么被压扁
   要么得横向滚动，两头都不齐。

   断点用的是 1088 而不是页面内容的 768：参考站顶栏的这一档比它自己
   内容的断点更大（Bulma 的 navbar 桌面态从 1088 起），所以在 900px
   这种"内容已经两栏、顶栏还是两行"的宽度下，两者是对齐的。 */
@media (max-width: 1087px) {
  .navbar-in {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 2px;
  }
  .site-title {
    /* 独占一行，所以得 flex-basis 100%；用 text-align 居中而不是
       justify-content，否则站名会随行内剩余空间左右漂。 */
    flex: 0 0 100%;
    margin-right: 0;
    padding: 8px 0 4px;
    text-align: center;
  }
  .site-nav {
    /* 和第二行的右侧图标并排，作为一个整体居中。 */
    flex: 0 1 auto;
    justify-content: center;
    flex-wrap: wrap;
  }
  .navbar-end { flex: 0 0 auto; }
}

@media (max-width: 768px) {
  /* 三栏在这里堆成一列。

     顺序上主栏必须排在最前面：手机上打开一篇文章，第一眼该看到的是文章，
     不是作者卡。麻烦在于 DOM 里作者卡（.column-left）排在主栏前面——宽屏时
     它本来就在左边，结构上说得通。所以这里不能把 order 归零让它按 DOM 顺序
     走，得显式把主栏提到前面。

     间距一律由容器上的 row-gap 给。以前是靠给某一栏加 margin-top 顶开下一块，
     但 DOM 顺序和视觉顺序不一致时，那段间距会落到最上面（导航与作者卡之间），
     真正的两张卡之间反倒是 0，贴成一张。 */
  .columns { row-gap: 21px; }
  .column-main { order: 1; }
  .column-left { order: 2; }
  .column-main, .column-left {
    flex: 0 0 100%;
    max-width: 100%;
    position: static;
  }
  .post-title { font-size: 21px; }
  .profile-avatar { inline-size: 96px; block-size: 96px; }
  .post-body { font-size: 15px; }
}

@media (max-width: 600px) {
  /* 导航在窄屏改成折行显示（见上面 768px 那段），这里不再做横向滚动；
     只把导航项的内边距收一点，免得五项加两个图标在 375px 上放不下。 */
  .site-nav { gap: 0; }
  .site-nav a { white-space: nowrap; padding: 7px 10px; }
  .site-search { display: none; }
  .card-content, .comments, .archive-year, .tag-cloud, .page-title { padding: 16px; }
  .post-title { font-size: 19px; }

  /* 手机上「发布时间」和右边的「分类」挤在同一行，宽度不够就折成两行，
     一半靠左一半靠右，看起来像没对齐。改成明确的两行：时间在上、分类在下，
     都靠左。 */
  .level { flex-direction: column; align-items: flex-start; gap: .4rem; margin-bottom: 14px; }
  .post-title { margin-bottom: 14px; }
  /* 作者卡上的平台图标在窄屏会更挤，把间距和尺寸收一点。 */
  .profile-links { gap: 5px; }
  .profile-links a { inline-size: 30px; block-size: 30px; }
}

/* ------------------------------------------------------------------ 动画 */

/* 进页面时导航、作者卡、内容、页脚依次轻微上浮淡入。

   参考站是"head 里先给这几块设 opacity:0，加载完再用 JS 打开"——
   那样一旦脚本没跑或报错，整页就是白的。这里用纯 CSS 的动画：
   动画本身就是从不可见到可见，不需要 JS 兜底，脚本失败也不影响阅读。

   整段包在 prefers-reduced-motion 里：系统里开了"减少动态效果"的人
   看到的就是静态页面，没有任何位移。 */
@media (prefers-reduced-motion: no-preference) {
  /* 只让"看得见的小块"动。

     第一版是拿整栏（.column-main）做位移+淡入，结果掉帧：整栏很高，
     一帧要重绘一大片；而顶栏还带 backdrop-filter 背景模糊，
     带着它做 transform，浏览器每帧都要重算一次模糊。

     现在改成：导航只淡入不动（避开模糊重算），卡片逐张入场。
     位移也收到 4px、时长收到 0.32s——动得越小越快，看起来越"稳"。 */
  /* 节奏放慢：0.32s 起步太快，卡片像"弹"出来而不是浮上来。
     时长 0.62s、位移 8px、缓动改成 ease-out 的慢收尾——
     同样一段位移，收尾越慢越显得稳。 */
  /* 顶栏只淡入，不做位移动画。

     参考站确实是把顶栏从 -96px 滑下来的，但那个"帘幕拉下来"的观感
     和这套版面不合：顶栏是吸顶的，它从屏幕外滑进来会让人以为页面
     在往下滚。这里只让它淡入。 */
  .navbar-in { animation: fade-in .3s ease-out both; }
  /* 用 > * 而不是 > .card：文章页的主栏里是 <article class="post">，
     归档页里是 .archive-year，都不是 .card——上一版只匹配 .card，
     结果那些页面的主栏一动不动，看起来就像"右边栏没有动画"。
     这里要的是"主栏里每一个直接子块都入场"，与它是什么标签无关。 */
  /* 正文从顶部往下揭开。

     用 clip-path 而不是淡入：淡入是"慢慢变清楚"，揭开是"从上面铺下来"。
     结束值停在 inset(-24px)——往外多留 24px 是为了不把卡片的阴影裁掉；
     inset(0) 会把边框外的投影一起剪掉，动画一结束卡片就会"啪"地失去阴影。 */
  /* 每块从 0.8 倍"弹"出来。

     这是参考站的实际做法（实测其卡片行内样式：初始 opacity:0 且
     transform: scale(0.8)，随后 transition 到 opacity:1 / scale(1)，
     0.3s ease-out）。之前我做的淡入、往上浮、往下揭开，都猜错了方向。 */
  .column-left > *,
  .column-main > *,
  /* 右栏也要入场。之前只写了左栏和主栏，宽屏下右栏那三张卡是"啪"地出现的——
     它和主栏同时可见，少了它就会觉得动画"差一口气"。 */
  .column-right > * {
    animation: pop-in .3s ease-out both;
    will-change: opacity, transform;
  }
  .site-footer {
    animation: fade-in .3s ease-out both;
    /* 提前告诉浏览器这两样要动，让它把元素提到自己的合成层里，
       而不是每帧重新栅格化。元素都是小卡片，多几个层的代价可以忽略。 */
    will-change: opacity, transform;
  }
  /* 依次入场：作者卡、正文卡片、页脚。
     间隔从 40ms 放宽到 80ms：间隔太密时几块几乎同时动，
     看不出先后，"依次浮现"就退化成"整页闪一下"。 */
  /* 每块间隔 80ms——这是从参考站实测出来的值：
     它的第 1 张卡在 ~70ms 开始、第 2 张 ~150ms、第 3 张 ~230ms。
     单块时长也是 0.3s，和它一致。 */
  .column-left > * { animation-delay: .04s; }
  .column-main > *:nth-child(1) { animation-delay: .08s; }
  .column-main > *:nth-child(2) { animation-delay: .16s; }
  .column-main > *:nth-child(3) { animation-delay: .24s; }
  .column-main > *:nth-child(4) { animation-delay: .32s; }
  .column-main > *:nth-child(n + 5) { animation-delay: .4s; }
  /* 右栏跟在主栏之后，而不是同时：它和主栏同时可见，一起入场会像"整页闪一下"。 */
  .column-right > *:nth-child(1) { animation-delay: .44s; }
  .column-right > *:nth-child(2) { animation-delay: .52s; }
  .column-right > *:nth-child(n + 3) { animation-delay: .6s; }
  .site-footer { animation-delay: .48s; }

  /* 文章标题的下划线从左往右铺开。
     用背景渐变而不是 text-decoration：后者的动画在各浏览器上不一致，
     而且没法只动下划线不动文字。 */
  .post-title a {
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 1px;
    transition: background-size .28s cubic-bezier(.25, .46, .45, .94), color .2s ease-out;
  }
  .post-title a:hover { background-size: 100% 1px; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* 从上方滑入。起始 -100% 是"整条正好藏在视口上方"，不是随便取的值。 */
@keyframes drop-in {
  from { opacity: 0; transform: translate3d(0, -100%, 0); }
  to   { opacity: 1; transform: none; }
}

/* 从 0.8 倍弹出来。缩放而不是位移：块是从中心"长开"的，
   不是从某个方向滑进来的——这是参考站的做法。 */
@keyframes pop-in {
  from { opacity: 0; transform: scale(.8); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------- 换页过渡 */

/* 让浏览器接管站内跳转时的"换页"这一下。

   开了它，等待新页面的那几百毫秒里旧页面会以快照的形式留在原地，而不是
   先白屏——服务器在大陆之外，这段时间恰恰是最影响"丝滑"的一环。

   过渡本身压到 0.12s、而且只让旧页面淡出：新页面一就位就直接显示，接着
   由上面那套栏内入场动画一块块铺出来。这里如果也做整体淡入，就会变成
   "整页先淡入一次、各块再弹一次"，看着像播了两遍。

   不支持这个特性的浏览器（Firefox 目前没有）会忽略整段，行为和以前一样。 */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: fade-out .12s ease-out both; }
::view-transition-new(root) { animation: none; }

@keyframes fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* 系统里开了"减少动态效果"的人不该看到这层过渡。 */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* 全站只用一个交互节奏：0.2s ease-out。参考站也是这个值。
   统一之后，悬停不会有的快有的慢——那种"手感不一致"比没有动画更显廉价。 */
a,
button,
.button,
.pagination a,
.tag-list a,
.tag-cloud a,
.profile-links a,
.profile-subscribe,
.sibling,
.btn-comment {
  transition: background-color .2s ease-out, color .2s ease-out, border-color .2s ease-out,
    transform .2s ease-out;
}

/* 卡片只过渡位移，阴影瞬间切换。

   阴影的过渡是浏览器每帧重新绘制一遍阴影——悬停一张大卡片时，
   这点开销肉眼就能看出掉帧。位移走合成层、不受影响，
   所以"抬起"仍然平滑，只有阴影是直接换过去的。 */
.card {
  transition: transform .2s ease-out, background-color .2s ease-out, color .2s ease-out;
}

/* 卡片悬停抬起 2px。位移很小，但配上阴影变化，鼠标扫过列表时
   能明确感觉到"这一张是可以点的"。 */
.column-main .card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, .08), 0 0 1px rgba(0, 0, 0, .1);
}

/* ------------------------------------------------------------ 栏内块间距 */

/* 栏里相邻的两块之间统一留 21px。

   以前是每块自己管自己的间距：文章卡片靠 `.card + .card`、归档年份靠
   margin-bottom、上/下篇和评论区各自带 margin-top，页面标题却没有。
   这种写法只要有一块忘了写、或者相邻的两块类型不同（匹配不上那个
   "+ 兄弟"选择器），它们就会严丝合缝地贴在一起——归档页的「归档」标题
   和「2026 年」卡片就是这么粘住的，标签页、分类页、搜索页一样。

   改成由容器统一给：以后往栏里加新的块类型，不用再记得补 margin。

   这条规则必须留在样式表最后：它和 `.tag-cloud { margin: 0 }` 那种
   组件自带的重置是同一个优先级，谁在后面谁赢——第一版把它写在布局
   那一节，结果标签云自己的 `margin: 0` 在后面，把这里给的间距又抹掉了。 */
.column-main > * + *,
.column-left > * + *,
.column-right > * + * {
  margin-top: 21px;
}
