/* ==========================================================================
   Nike 设计系统覆盖层
   规范来源：docs/DESIGN-nike.md（= getdesign.md 官方 nike 包，已核对逐字相同）

   为什么全部写在覆盖层里而不改主题：
   Butterfly 的样式全部走 CSS 变量 + 编译好的 index.css，
   custom.css 在 <head> 里排在 index.css **之后**，同优先级后来居上，
   所以绝大多数改动不需要 !important，也不用碰 node_modules。

   ━━━ 这套系统的三条铁律（DESIGN-nike.md「Don't」段）━━━
   ① 容器零圆角、零阴影；唯一的深度线索是 1px 发丝线
   ② 按钮只有两种形状：胶囊（30px）和圆形图标钮 —— 不许有第三种
   ③ 颜色只有黑 / 白 / 一个浅灰承担 95% 的界面，彩色只留给图片和语义信号

   ━━━ 关于暗色 ━━━
   ⚠️ Nike 官方这份规范**没有暗色调色板**。三个来源（docs/DESIGN-nike.md、
   docs/nike-dark.md、npx getdesign@latest add nike 现拉的 DESIGN.md）
   归一化后逐字相同，canvas 始终是 #ffffff。
   下面的暗色值分两类，注释里逐条标了出处：
     [文档] —— 规范里明确写了「on dark surfaces」用途的 token，直接采用
     [推导] —— 规范没有对应值，按亮色版的同级关系推出来的
   ========================================================================== */

/* ==========================================================================
   1. 自托管字体
   规范原文：「pair Inter (Display 700 for body chrome, Display 500 for buttons)
   with Bebas Neue ... at 96px/0.9 line-height for the campaign headline tier.
   Tighten letter-spacing slightly (-0.5%)」
   文件由 tools/sync-fonts.mjs 从 @fontsource 同步过来。
   ========================================================================== */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/inter-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/inter-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/inter-latin-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebas-neue-latin-400-normal.woff2') format('woff2');
}

/* ==========================================================================
   2. 设计 token —— 亮色（规范原值）
   ========================================================================== */

:root {
  /* ---- 颜色 ---- */
  --nk-ink: #111111;
  --nk-on-primary: #ffffff;
  --nk-canvas: #ffffff;
  --nk-soft-cloud: #f5f5f5;
  --nk-charcoal: #39393b;
  --nk-ash: #4b4b4d;
  --nk-mute: #707072;
  --nk-stone: #9e9ea0;
  --nk-hairline: #cacacb;
  --nk-hairline-soft: #e5e5e5;
  --nk-sale: #d30005;
  --nk-success: #007d48;
  --nk-info: #1151ff;

  /* 反相对：在 ink 底上用的前景色。暗色模式下整体对调。 */
  --nk-cta-bg: var(--nk-ink);
  --nk-cta-fg: var(--nk-on-primary);

  /* campaign hero 的一对。两种模式下 hero 都是深底，所以前景恒为白 ——
     单独抽出来是为了不让它跟着 ink/canvas 的对调一起翻。 */
  --nk-hero-bg: #111111;
  --nk-hero-fg: #ffffff;
  /* hero 上的次要文字（副标题 / 文章元信息）。用规范里的 Stone —— 原文就是
     "Inverse secondary text on dark surfaces"。同样不能跟着明暗对调：
     暗色版的 stone 是 ash #4b4b4d，压在 #1c1c1e 的 hero 上只有 1.7:1。 */
  --nk-hero-fg-mute: #9e9ea0;

  /* ---- 圆角 ---- */
  --nk-r-none: 0px;
  --nk-r-sm: 18px;
  --nk-r-md: 24px;   /* 搜索胶囊 */
  --nk-r-lg: 30px;   /* 所有 CTA 胶囊 */
  --nk-r-full: 9999px;

  /* ---- 间距（8px 基准）---- */
  --nk-s-xxs: 2px;
  --nk-s-xs: 4px;
  --nk-s-sm: 8px;
  --nk-s-md: 12px;
  --nk-s-lg: 18px;
  --nk-s-xl: 24px;
  --nk-s-xxl: 30px;
  --nk-s-section: 48px;

  /* ---- 字体 ---- */
  /* CJK 由系统字体接管：Inter / Bebas Neue 都不含汉字字形 */
  --nk-font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Arial,
                'PingFang SC', 'Microsoft YaHei', sans-serif;
  --nk-font-display: 'Bebas Neue', 'Inter', 'Helvetica Neue', Impact, 'PingFang SC',
                     'Microsoft YaHei', sans-serif;
  --nk-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* ---- 容器 ---- */
  --nk-max-w: 1440px;

  /* ==== 改版新增：导航条 ====================================================
     [偏离规范] DESIGN-nike.md 的 primary-nav 是「canvas 底 + ink 字」，
     也就是白底黑字。这里改成黑底白字。

     理由：去掉首屏大图之后，页面第一像素就是导航条。白底导航接白底正文，
     整个页头会「消失」—— 站点没有了任何视觉锚点。黑条把品牌区和阅读区
     切开，也保住了原来 hero 那种黑白对撞的气质。

     不认同的话改这两个值就能回到规范原样，其余规则都读 token：
       --nk-nav-bg: var(--nk-canvas);  --nk-nav-fg: var(--nk-ink);
     ======================================================================= */
  --nk-nav-bg: #0a0a0a;
  --nk-nav-fg: #ffffff;

  /* ==== 改版新增：阅读面 ====================================================
     外壳（导航 / 页脚 / 列表）保持 Nike 的纯黑白，**只有文章正文**引入一个
     强调色。规范第三条铁律说「彩色只留给图片和语义信号」——
     长文里的链接、目录当前项、提示框，恰好就是语义信号。

     两个青绿是有意分开的，不是写重复了：
       --rd-accent       非文字强调（目录高亮条、提示框左边条、代码底）
       --rd-accent-text  正文里真正当文字用的（行内链接、行内代码、内联目录）

     亮色下 #18bc9c 压在白底上只有 2.4:1，当正文链接色读久了会累，
     所以文字那一档压深到 #0fa287（3.2:1）。暗色底上不存在这个问题，
     两档合并成同一个提亮值。
     ======================================================================= */
  --rd-measure: 880px;      /* 正文栏宽 */
  --rd-fs: 17.5px;          /* 正文字号 */
  --rd-lh: 1.8;             /* 正文行高。中文没有词间空格，比英文站惯用的 1.5 要松 */
  --rd-accent: #18bc9c;
  --rd-accent-text: #0fa287;
  --rd-accent-tint: #eefaf7;
}

/* ==========================================================================
   3. 设计 token —— 暗色（规范无原值，逐条标注出处）
   ========================================================================== */

[data-theme='dark'] {
  /* [文档] campaign-tile / member-benefit-card 的暗面就是 ink 底 + on-primary 字 */
  --nk-canvas: #111111;
  --nk-ink: #ffffff;
  --nk-on-primary: #111111;

  /* [推导] 规范没有 soft-cloud 的暗色对应值。
     亮色是 #ffffff → #f5f5f5（约 4% 的一档），这里取同一档感知步长。 */
  --nk-soft-cloud: #1c1c1e;

  /* [文档] Stone —— "Inverse secondary text on dark surfaces" */
  --nk-mute: #9e9ea0;
  /* [文档] Ash —— "Disabled secondary border on dark surfaces
     and very low-emphasis utility text" */
  --nk-stone: #4b4b4d;
  --nk-hairline: #4b4b4d;
  /* [推导] hairline-soft 在亮色里比 hairline 更淡一档，暗色同理更暗一档 */
  --nk-hairline-soft: #2e2e30;
  /* [推导] charcoal 亮色是「比 ink 略柔的正文色」，暗色取比纯白略柔 */
  --nk-charcoal: #e6e6e6;

  /* [文档] Success Bright —— "Inverse success on dark surfaces" */
  --nk-success: #1eaa52;
  /* [偏离规范] 规范写 sale-deep #780700 是 "dark-mode sale anchor"，
     但 #780700 落在 #111111 上对比度只有约 1.6:1，正文完全不可读。
     这里改用提亮版，保证 WCAG AA。如果只当装饰色用可以改回 #780700。 */
  --nk-sale: #ff5a5c;
  --nk-info: #6f9bff;

  /* [文档] 暗底上的 CTA 就是 button-outline-on-image：canvas 底 + ink 字。
     所以主按钮在暗色下自动翻成白底黑字。 */
  --nk-cta-bg: #ffffff;
  --nk-cta-fg: #111111;

  /* [推导] 暗色下画布本身就是 ink，hero 再用 ink 会和页面糊成一块，
     抬到 soft-cloud 那一档让它重新读作一个独立的块。前景仍是白。 */
  --nk-hero-bg: #1c1c1e;

  /* 改版新增：导航条。
     暗色画布是 #111，导航要比它再深一档才分得出层次，所以用纯黑。 */
  --nk-nav-bg: #000000;
  --nk-nav-fg: #ffffff;

  /* 改版新增：阅读面。
     暗底上不需要为可读性压深，两档合并成同一个提亮值 ——
     #2fd6b2 落在 #111111 上约 8.9:1，远超 AA。
     tint 是同色相的极暗底，用来给提示框一个「有东西」的存在感而不刺眼。 */
  --rd-accent: #2fd6b2;
  --rd-accent-text: #2fd6b2;
  --rd-accent-tint: #12241f;
}

/* ==========================================================================
   4. 把 Butterfly 的变量重映射到 Nike token
   —— 这一步做完，主题里绝大多数组件就已经是黑白的了，
      后面的规则只处理形状（圆角/阴影）和排版。
   ========================================================================== */

:root,
[data-theme='dark'] {
  --global-font-size: 16px;          /* 规范 body-md = 16px，Butterfly 默认 14px */
  --global-bg: var(--nk-canvas);
  --font-color: var(--nk-charcoal);
  --text-highlight-color: var(--nk-ink);
  --card-bg: var(--nk-canvas);
  --card-meta: var(--nk-mute);
  --sidebar-bg: var(--nk-canvas);
  --sidebar-menu-bg: var(--nk-canvas);

  --btn-bg: var(--nk-cta-bg);
  --btn-color: var(--nk-cta-fg);
  --btn-hover-color: var(--nk-cta-bg);
  --btn-default-color: var(--nk-ink);

  --search-bg: var(--nk-soft-cloud);
  --search-input-color: var(--nk-ink);
  --search-a-color: var(--nk-ink);

  --light-grey: var(--nk-hairline-soft);
  --dark-grey: var(--nk-hairline);
  /* ⚠️ 主题用 --white 给「压在头图上的文字」上色（#page-header #site-title 等）。
     本站的 hero 在明暗两种模式下都是深底，所以这个变量必须恒为白，
     不能跟着 canvas 一起对调 —— 否则暗色下站名会变成 #111 压在 #1c1c1e 上，几乎看不见。 */
  --white: var(--nk-hero-fg);

  --hr-border: var(--nk-hairline);
  --hr-before-color: var(--nk-ink);
  --blockquote-color: var(--nk-mute);
  --blockquote-bg: var(--nk-soft-cloud);
  --toc-link-color: var(--nk-mute);
  --pseudo-hover: var(--nk-ink);
  --headline-presudo: var(--nk-hairline);
  /* 滚动条滑块。这里用 --nk-ink 是**故意**的：它跟着明暗翻转，
     亮色下深色滑块、暗色下浅色滑块，正是想要的效果。
     ⚠️ 但别照抄到「背景」类属性上 —— 那会在暗色下变成白块。
     踩过：video / .video-embed 的底色曾用 var(--nk-ink) 导致闪白。 */
  --scrollbar-color: var(--nk-ink);
  /* 「上下篇 / 相关推荐」在文章没有封面图时，用这个颜色填一块占位。
     主题只在 pagination.pug:24 用到它，改动范围可控。
     ⚠️ 原来映射成 ink：亮色下是深灰块、暗色下翻成白色再叠 opacity .4 变成浅灰块，
     两种模式都是一坨突兀的色块。改成 soft-cloud 之后它基本和页面同色，
     只在 hover 时抬一档（见第 16 节）。 */
  --default-bg-color: var(--nk-soft-cloud);
  --text-bg-hover: var(--nk-soft-cloud);
  --zoom-bg: var(--nk-canvas);
  --reward-pop: var(--nk-soft-cloud);
  --timeline-bg: var(--nk-soft-cloud);
  --preloader-bg: var(--nk-ink);
  --preloader-color: var(--nk-on-primary);

  --tab-border-color: var(--nk-hairline-soft);
  --tab-button-bg: var(--nk-soft-cloud);
  --tab-button-color: var(--nk-ink);
  --tab-button-hover-bg: var(--nk-hairline-soft);
  --tab-button-active-bg: var(--nk-canvas);

  /* 规范：零阴影。「The system has no drop-shadow elevation in its retail chrome at all.」 */
  --card-box-shadow: none;
  --card-hover-box-shadow: none;
}

/* ==========================================================================
   5. 形状复位 —— 零圆角 + 零阴影
   Butterfly 到处撒 8px/12px 圆角和柔和投影，这两条是 Nike 系统最不能容忍的。
   先一刀切归零，再单独把「按钮类」拉回胶囊。
   ========================================================================== */

#page :is(.card-widget, .recent-post-item, .article-sort-item-img, #post,
           #page-header, .container, #aside-content .card-info, .layout > div),
#post, #page, .recent-post-item, .card-widget, #card-toc, #aside-content .card-widget,
.note, .highlight, figure.highlight, #article-container img, .tabs, #rightside > div > button,
#rightside > div > a, .pagination .page-number, .pagination .extend, #post-info,
.relatedPosts > .relatedPosts-list > div {
  border-radius: var(--nk-r-none);
  box-shadow: none;
}

/* 圆形图标钮（button-icon-circular）是仅有的例外 */
#rightside button,
#rightside > div > a,
#nav #toggle-menu,
.social-icon {
  border-radius: var(--nk-r-full);
}

/* ==========================================================================
   6. 排版层级
   规范核心：只有 96px 展示层和 12–16px 的安静层，中间几乎没有过渡 ——
   「the jump from heading-xl (32px) directly to body-strong (16px) is intentional
     and creates the "billboard above, catalog below" effect」
   ========================================================================== */

body,
#page,
#article-container {
  font-family: var(--nk-font-ui);
  letter-spacing: 0;
}

body {
  font-size: 16px;
  line-height: 1.5;
  color: var(--nk-charcoal);
  background: var(--nk-canvas);
}

/* 正文标题：heading-xl 32 / heading-lg 24 / heading-md 16，全部 500 字重 */
#article-container h1 { font-size: 32px; line-height: 1.2; font-weight: 700; }
#article-container h2 { font-size: 24px; line-height: 1.2; font-weight: 700; }
#article-container h3 { font-size: 20px; line-height: 1.3; font-weight: 500; }
#article-container h4,
#article-container h5,
#article-container h6 { font-size: 16px; line-height: 1.75; font-weight: 500; }

#article-container :is(h1, h2, h3, h4, h5, h6) {
  color: var(--nk-ink);
  margin: var(--nk-s-section) 0 var(--nk-s-lg);
  padding: 0;
}
/* Butterfly 给标题加了彩色前缀符号，Nike 系统里没有装饰 */
#article-container :is(h1, h2, h3, h4, h5, h6)::before { content: none; }

#article-container p { margin: 0 0 var(--nk-s-xl); }

/* 规范：只有行内链接可以有下划线，按钮/标题/价格一律不加 */
#article-container a {
  color: var(--nk-ink);
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
  border-bottom: none;
}
#article-container a:hover { color: var(--nk-mute); }

#article-container blockquote {
  background: var(--nk-soft-cloud);
  border-left: 2px solid var(--nk-ink);
  color: var(--nk-mute);
  border-radius: var(--nk-r-none);
  padding: var(--nk-s-xl);
}

#article-container hr {
  background: none;
  border: none;
  border-top: 1px solid var(--nk-hairline);
  margin: var(--nk-s-section) 0;
}
#article-container hr::before { content: none; }

#article-container :is(code, pre) { font-family: var(--nk-font-mono); }
#article-container pre { overflow-x: auto; }

/* 中文正文行高调大。中文没有词间空格，1.5 会很挤。 */
html:lang(zh-CN) #article-container,
html:lang(zh-cn) #article-container { line-height: 1.9; }

/* ==========================================================================
   7. 页头（无大图）
   改版后全站关掉了顶部大图（_config.yml 的 `disable_top_img: true`），
   `#page-header` 里只剩下导航条 —— 原来那套 hero 规则
   （#site-info / #site-title / #site-subtitle / #scroll-down / #site_social_icons）
   对应的 DOM 已经**根本不会渲染**，所以整节删掉了，没有留死代码。

   ⚠️ 如果哪天想把首屏大图加回来，要改的不止这里：
      ① _config.yml 关掉 disable_top_img
      ② 补回 index_img / default_top_img
      ③ 重新写 #page-header.full_page 那一支的样式
      ④ scripts/post-furniture.js 的锚点要跟着变 —— top_img 不为 false 时
        Butterfly 把 #post-info 放进页头，而不是 #post 里面
   ========================================================================== */

/* 没有底图了，页头就是导航条本身：不占额外高度，不留遮罩层。 */
#page-header {
  height: auto;
  min-height: 0;
  background: var(--nk-nav-bg);
  background-image: none;
}
#page-header::before { content: none; }

/* ==========================================================================
   8. 主导航（primary-nav）
   [偏离规范] 黑底白字，原因见第 2 节 --nk-nav-bg 的注释。

   全站关掉大图之后，`#page-header` 只会拿到 `not-top-img` 这一个类
   （滚动后主题再加 `nav-fixed`）—— 原来那一支 `.full_page`（导航压在
   hero 上、透明底、反相文字）的 DOM 已经不存在，整段删掉了。

   两种状态现在长得一模一样，是有意的：页面顶端本来就是黑条，
   滚动后固定住的也是同一根黑条，不该有「变身」的动画。
   ========================================================================== */

#page-header > #nav,
#page-header.nav-fixed > #nav,
#page-header.not-top-img > #nav,
[data-theme='dark'] #page-header > #nav,
[data-theme='dark'] #page-header.nav-fixed > #nav,
[data-theme='dark'] #page-header.not-top-img > #nav {
  background: var(--nk-nav-bg);
  box-shadow: none;
  height: 60px;
  line-height: 60px;
}

#page-header > #nav a,
#page-header > #nav .site-page,
#page-header > #nav .site-name,
#page-header > #nav #site-name,
#page-header.nav-fixed > #nav a,
#page-header.nav-fixed > #nav .site-page,
#page-header.nav-fixed > #nav .site-name,
#page-header.not-top-img > #nav a,
#page-header.not-top-img > #nav .site-page,
#page-header.not-top-img > #nav .site-name,
[data-theme='dark'] #page-header > #nav a,
[data-theme='dark'] #page-header > #nav .site-page,
[data-theme='dark'] #page-header > #nav .site-name {
  color: var(--nk-nav-fg);
  text-shadow: none;
}

#nav .site-name {
  font-family: var(--nk-font-display);
  font-size: 26px;
  letter-spacing: 0;
  text-transform: uppercase;
  font-weight: 400;
}

#nav .menus_item .site-page {
  font-size: 16px;
  font-weight: 500;
  line-height: 1.5;
  padding: 0 var(--nk-s-md);
}
/* 规范：当前栏目用 2px 底部下划线，不是背景块 */
#nav .menus_item .site-page:hover {
  background: none;
  box-shadow: inset 0 -2px 0 currentColor;
  color: inherit;
}
/* 导航图标在 Nike 系统里没有位置 —— 文字导航更接近原味 */
#nav .menus_item .site-page > i.fa-fw { display: none; }

/* 语言切换项稍微弱化，让它读起来像「切换」而不是又一个栏目 */
#nav .menus_item:last-child .site-page { opacity: .7; }
#nav .menus_item:last-child .site-page:hover { opacity: 1; }

/* ==========================================================================
   9. 文章卡片（product-card）
   规范：零圆角、零内边距、零阴影，图片满幅铺在 soft-cloud 上，
   元信息紧跟在图下方，行间距 8px。
   ========================================================================== */

.layout {
  max-width: var(--nk-max-w);
  padding: var(--nk-s-section) var(--nk-s-xl);
}

#recent-posts .recent-post-item {
  background: var(--nk-canvas);
  border-radius: var(--nk-r-none);
  box-shadow: none;
  border: none;
  border-bottom: 1px solid var(--nk-hairline-soft);
  margin-bottom: var(--nk-s-section);
  padding-bottom: var(--nk-s-section);
}
#recent-posts .recent-post-item:hover { box-shadow: none; transform: none; }

.recent-post-item .post_cover {
  background: var(--nk-soft-cloud);
  border-radius: var(--nk-r-none);
}
.recent-post-item .post_cover img {
  border-radius: var(--nk-r-none);
  transition: none;
}
.recent-post-item .post_cover img:hover { transform: none; }

#recent-posts .recent-post-info { padding: 0 0 0 var(--nk-s-xl); }
/* no-cover 这个类在 .recent-post-info 上，不在 .recent-post-item 上 —— 写错了会静默失效 */
#recent-posts .recent-post-info.no-cover { padding-left: 0; }

#recent-posts .article-title {
  font-size: 24px;
  line-height: 1.2;
  font-weight: 700;
  color: var(--nk-ink);
  margin-bottom: var(--nk-s-sm);
}
#recent-posts .article-title:hover {
  color: var(--nk-ink);
  text-decoration: underline;
  text-underline-offset: 4px;
}

#recent-posts .content {
  font-size: 16px;
  line-height: 1.5;
  color: var(--nk-mute);
  margin-top: var(--nk-s-sm);
}

/* 元信息行 = caption-md 14/500/mute */
.article-meta-wrap,
.article-meta-wrap a,
#post-info .post-meta,
#post-info .post-meta a {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--nk-mute);
}
.article-meta-wrap a:hover,
#post-info .post-meta a:hover { color: var(--nk-ink); }
.article-meta-wrap .article-meta-label { color: var(--nk-stone); }

/* ==========================================================================
   10. 文章页（PDP）
   规范：正文列窄、信息行用 1px 发丝线堆叠（pdp-disclosure-row）。
   ========================================================================== */

#post {
  background: var(--nk-canvas);
  border: none;
  box-shadow: none;
  border-radius: var(--nk-r-none);
  padding: 0;
}

/* ⚠️ 改版后文章标题**在正文里**，不在头图上。
   `disable_top_img: true` 让 post.pug 走 `if top_img === false` 那一支，
   把 #post-info 渲染进 #post 内部。所以下面全部是 `#post #post-info`，
   而不是从前的 `#page-header #post-info`，前景色也从 hero 的白字
   回到普通的 ink。

   #post-info 的内部结构由 scripts/post-furniture.js 在构建期重写，
   形状是固定的：
     h1.post-title → .post-tags → p.post-subtitle → dl#post-meta.post-meta-grid
   改那个脚本的输出，就要回来同步这里。 */

/* ⚠️ 不能写 `margin: 0 auto`。#post-info 和 #article-container 是兄弟节点，
   父容器比 880px 宽（右边还要留给粘性目录），居中会让标题区比正文右移几十像素 ——
   页面上表现为「标题和正文没对齐」，很难看出是居中造成的。两者都靠左。 */
#post #post-info {
  max-width: var(--rd-measure);
  margin: 0;
  padding: 0 0 var(--nk-s-xl);
}

#post #post-info .post-title {
  font-family: var(--nk-font-ui);
  font-size: clamp(30px, 4.2vw, 40px);
  line-height: 1.18;
  font-weight: 700;
  letter-spacing: -0.022em;
  color: var(--nk-ink);
  text-shadow: none;
  border-bottom: none;
  margin: 0 0 var(--nk-s-md);
}

/* ---- 标题下面那排标签药丸 ---- */
/* 零圆角是铁律①，所以是方角描边而不是胶囊 —— 胶囊只留给按钮（铁律②）。 */
#post #post-info .post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--nk-s-sm);
  margin: 0 0 var(--nk-s-lg);
}
#post #post-info .post-tag {
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--nk-mute);
  border: 1px solid var(--nk-hairline-soft);
  border-radius: var(--nk-r-none);
  padding: 3px 8px;
  text-decoration: none;
}
#post #post-info .post-tag:hover {
  color: var(--rd-accent-text);
  border-color: var(--rd-accent);
}

/* ---- 一句话摘要（front matter 的 description）----
   这是整个改版里最省力气的一处：一行字就能让读者判断要不要往下读。
   主题原本完全不渲染 description，只在首页列表里当摘要用。 */
#post #post-info .post-subtitle {
  font-size: 18px;
  line-height: 1.65;
  color: var(--nk-mute);
  margin: 0 0 var(--nk-s-xl);
  max-width: 44em;
}

/* ---- 作者 / 发布 / 更新 / 阅读时长 ----
   主题原来是一行带图标的文字（📅 Created 2026-08-10 | 🕐 Updated …）。
   改成小标签在上、值在下的网格：扫一眼就知道有哪几项，
   而且「更新于」和「发布于」不再挤在同一行里靠竖线分隔。
   auto-fit 让它在窄屏自动从 4 列掉到 2 列再到 1 列，不需要写断点。 */
#post #post-info .post-meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, max-content));
  gap: var(--nk-s-lg) var(--nk-s-section);
  margin: 0;
  padding: 0 0 var(--nk-s-xl);
  border-bottom: 1px solid var(--nk-hairline-soft);
}
#post #post-info .post-meta-grid .pm-cell { min-width: 0; }
#post #post-info .post-meta-grid dt {
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--nk-mute);
  margin: 0 0 var(--nk-s-xs);
}
#post #post-info .post-meta-grid dd {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--nk-ink);
  font-variant-numeric: tabular-nums;
}

/* 标签已经搬到标题下面了，文末那一份是重复的。
   `.tag_share` 里还有分享按钮（本站关掉了），所以只藏标签列表本身。 */
#post .tag_share .post-meta__tag-list { display: none; }

/* ---- 正文栏宽 ----
   规范没有规定正文列宽，原来写的 720px 是按 16px/1.5 推的。
   改版把正文放大到 17.5px 并把行高抬到 1.8（中文没有词间空格，
   1.5 会挤成一堵墙），栏宽同步放到 880px —— 中文约 38 字一行，
   英文约 85 字符，都在长文的舒适区里。 */
/* ⚠️ 限宽和放大字号只给「真正在读的长文」——
   文章页 (#post) 和普通页面 (#page，比如「关于」)。
   不能写成裸的 `#article-container`：page.pug 把**所有**页面的内容都塞进这个
   容器，包括三栏枢纽首页和分区列表页 —— 它们是多列布局，880px 会把三栏挤扁。
   枢纽页的解除见第 21b 节。 */
#post #article-container,
#page #article-container {
  max-width: var(--rd-measure);
  font-size: var(--rd-fs);
  line-height: var(--rd-lh);
}

/* ---- 文章页的整体栏宽：正文严格居中 ----

   ⚠️ 这里要分清两种「居中」，它们看起来差很多：

     ① 把 [正文 + 右侧目录] 当成一个盒子居中
        —— 盒子两边的留白确实相等，但读者眼睛盯着的是**正文**，
           而正文只占盒子左边一段。1920 下实测正文中心在 784，
           页面中心是 960，视觉上明显偏左。这是改之前的做法。

     ② 让**正文列**本身对准页面中线，目录浮在右边的留白里
        —— 正文中心 = 页面中心。Quarto（也就是 christianjmills.com 用的
           那套）和 Claude 的对话框都是这个形状。这是现在的做法。

   实现方式是三列网格：`1fr | 880px | 1fr`。两侧的 1fr 恒等，
   所以中间列必然落在正中；目录放进右边那一列，左边那列是空的。

   为什么只在 ≥1400px 生效：再窄的话两侧 1fr 会被压到放不下目录
   （1200px 时每侧只剩 120px），那时候「一组居中」反而更合理 ——
   两边留白本来就没多少，看不出偏移。 */
@media screen and (min-width: 1400px) {
  #body-wrap.post #content-inner.layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--rd-measure) minmax(0, 1fr);
    column-gap: var(--nk-s-section);
    align-items: start;
    max-width: none;
  }
  /* 主题给内容列写死了 `width: 74%`（_page/common.styl:34），
     网格里必须让它回到 auto，否则中间列会缩成 74% 再居中，白折腾。 */
  #body-wrap.post #content-inner.layout > #post {
    grid-column: 2;
    width: auto;
  }
  #body-wrap.post #content-inner.layout > #aside-content {
    grid-column: 3;
    width: auto;
    max-width: 280px;
    /* ⚠️ 必须显式 stretch，抵消上面那条 align-items:start。
       否则这一列只有**自身内容那么高**（实测 367px），而 position:sticky
       只能在自己的容器里粘 —— 目录滚过 367px 就跟着页面走掉了。
       窄屏走 flex 分支，默认就是 stretch，所以那边一直正常，
       这个 bug 只在 ≥1400px 出现，很容易漏测。 */
    align-self: stretch;
  }
}

/* ≥1400px 以下：回到原来的「一组居中」。 */
@media screen and (max-width: 1399px) {
  #body-wrap.post .layout {
    max-width: 1280px;
    margin-left: auto;
    margin-right: auto;
  }
}

/* ---- h2 通栏发丝线 ----
   christianjmills.com 的「清晰」有很大一块来自这一条：
   章节边界不靠留白猜，直接画出来。发丝线本来就是这套系统唯一合法的
   深度线索（铁律①），所以这一笔完全在规范之内。 */
#article-container h2 {
  padding-bottom: var(--nk-s-sm);
  border-bottom: 1px solid var(--nk-hairline-soft);
  margin-top: var(--nk-s-section);
  font-size: 27px;
}
#article-container h3 { font-size: 21px; }

/* 正文链接：唯一允许上色的地方 */
#article-container a {
  color: var(--rd-accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
#article-container a:hover { color: var(--nk-ink); }

/* 行内代码。底色用 soft-cloud，字用强调色 —— 和链接区分开：
   链接有下划线，代码有底色，两者不会看混。 */
#article-container :not(pre) > code {
  color: var(--rd-accent-text);
  background: var(--nk-soft-cloud);
  border: 1px solid var(--nk-hairline-soft);
  border-radius: var(--nk-r-none);
  padding: 2px 6px;
  font-size: 0.86em;
}

/* ==========================================================================
   10b. 文章页家具（由 scripts/post-furniture.js 注入）
   ========================================================================== */

/* ---- 「本文属于以下系列」 ---- */
.post-series {
  border: 1px solid var(--nk-hairline-soft);
  border-left: 3px solid var(--rd-accent);
  background: var(--rd-accent-tint);
  padding: var(--nk-s-lg) var(--nk-s-xl);
  margin: 0 0 var(--nk-s-xxl);
  font-size: 15.5px;
  line-height: 1.7;
}
.post-series-head {
  margin: 0 0 var(--nk-s-sm);
  color: var(--nk-charcoal);
}
.post-series-head strong { font-weight: 600; color: var(--nk-ink); }
.post-series-nth,
.post-series .series-nth {
  margin-left: var(--nk-s-md);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nk-mute);
}
.post-series-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}
.post-series-list li {
  display: flex;
  gap: var(--nk-s-md);
  align-items: baseline;
  padding: var(--nk-s-xs) 0;
}
.post-series-list .series-n {
  flex: none;
  width: 1.6em;
  font-size: 12px;
  color: var(--nk-mute);
  font-variant-numeric: tabular-nums;
}
.post-series-list a { color: var(--rd-accent-text); }
/* 当前这一篇不做成链接（点了原地不动），用字重和颜色标出来 */
.post-series-list .is-current {
  font-weight: 600;
  color: var(--nk-ink);
}

/* ---- 正文顶部的内联目录 ----
   和右栏那条粘性目录不是重复：右栏在窄屏会整个消失（第 17 节），
   而长文在手机上恰恰最需要一个能跳转的纲要。
   少于 3 节的文章不会注入（见 post-furniture.js 里的阈值）。 */
.post-toc-inline {
  margin: 0 0 var(--nk-s-section);
  padding: 0 0 0 var(--nk-s-xl);
  border-left: 2px solid var(--nk-hairline-soft);
}
.post-toc-inline-head {
  margin: 0 0 var(--nk-s-sm);
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--nk-mute);
}
.post-toc-inline ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
.post-toc-inline ul { line-height: 1.5; }
.post-toc-inline li { margin: 0 0 var(--nk-s-sm); }
.post-toc-inline a {
  font-size: 15.5px;
  color: var(--rd-accent-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.post-toc-inline a:hover { border-bottom-color: currentColor; }

/* ==========================================================================
   10c. 判断台账（由 scripts/post-furniture.js + scripts/stale-tag.js 注入）

   字段定义和写作规矩见 docs/STYLE.md 第二、五节。这里只管长相。
   全部用 token，所以暗色不需要单独再写一遍。
   ========================================================================== */

/* ---- 置信度徽章 ----
   三档用「填充 → 描边 → 虚线描边」的视觉强度阶梯来区分，不靠颜色。
   靠颜色的话要么和站点的黑白基调打架，要么在暗色下重新调一遍。
   零圆角是铁律①，所以和 .post-tag 一样是方角。 */
.post-conf {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: var(--nk-r-none);
  white-space: nowrap;
}
/* 押注：最强的一档，实底 */
.post-conf-bet {
  background: var(--nk-ink);
  color: var(--nk-on-primary);
  border-color: var(--nk-ink);
}
/* 倾向：中间档，实线描边 */
.post-conf-lean {
  color: var(--nk-ink);
  border-color: var(--nk-ink);
}
/* 猜：最弱的一档，虚线描边 —— 虚线本身就在说「这事还没定」 */
.post-conf-guess {
  color: var(--nk-mute);
  border-style: dashed;
  border-color: var(--nk-hairline);
}
.post-conf-other {
  color: var(--nk-mute);
  border-color: var(--nk-hairline-soft);
}

/* 「改判过」。它是这一排里信息量最大的东西，所以是可点的（跳到变更记录），
   而且下调时染成 sale —— 下调 = 我当初高估了自己，这是最该被看见的情况。 */
.post-conf-revised {
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nk-mute);
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  align-self: center;
  margin-left: calc(var(--nk-s-sm) * -1 + 6px);
}
.post-conf-revised.is-down { color: var(--nk-sale); }
.post-conf-revised:hover { border-bottom-style: solid; }

/* ---- 整篇被取代的横幅 ----
   页面最顶上，比系列框还靠前。一篇文章如果整个结论都不作数了，
   这是读者唯一需要先看到的东西。 */
.post-superseded {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nk-s-md);
  border: 1px solid var(--nk-hairline-soft);
  border-left: 3px solid var(--nk-sale);
  padding: var(--nk-s-lg) var(--nk-s-xl);
  margin: 0 0 var(--nk-s-xxl);
  font-size: 15.5px;
}
.post-superseded-flag {
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--nk-sale);
  font-weight: 600;
}
.post-superseded a { color: var(--rd-accent-text); }

/* ---- 看法变更记录 ----
   ⚠️ 这个框在正文**顶部**（系列框下面）。判断被下调过的话，读者必须在读之前知道，
      不是读完才发现 —— 和新闻的更正声明同理。post-furniture.js 里也写了这一条，
      两处一起改，不要只挪 CSS。

   用 soft-cloud 底而不是 accent tint：accent 那套是「导航/延伸阅读」的语汇
   （系列框、内联目录都在用），而这个框是「注意」，语义不同就不该长一样。 */
.post-review {
  background: var(--nk-soft-cloud);
  border: 1px solid var(--nk-hairline-soft);
  padding: 0;
  margin: 0 0 var(--nk-s-xxl);
  font-size: 15.5px;
  line-height: 1.7;
  scroll-margin-top: 90px;   /* 从「复盘于」跳过来时别被吸顶导航挡住 */
}
.post-review-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nk-s-md);
  padding: var(--nk-s-md) var(--nk-s-xl);
  cursor: pointer;
  list-style: none;
}
/* summary 的默认三角在各浏览器里长得不一样，去掉自己画 */
.post-review-head::-webkit-details-marker { display: none; }
.post-review-head::marker { content: ''; }
.post-review-head::after {
  content: '＋';
  margin-left: auto;
  color: var(--nk-mute);
  font-size: 13px;
}
.post-review[open] .post-review-head::after,
.post-review details[open] .post-review-head::after { content: '－'; }
.post-review-count { font-weight: 600; color: var(--nk-ink); }
.post-review-latest {
  font-size: 12px;
  letter-spacing: 0.05em;
  color: var(--nk-mute);
  font-variant-numeric: tabular-nums;
}
.post-review-list {
  margin: 0;
  padding: 0 var(--nk-s-xl) var(--nk-s-lg);
  list-style: none;
  border-top: 1px solid var(--nk-hairline-soft);
}
.post-review-item {
  padding: var(--nk-s-md) 0 var(--nk-s-md) var(--nk-s-lg);
  border-left: 2px solid var(--nk-hairline);
  margin-top: var(--nk-s-md);
}
.post-review-item.is-down { border-left-color: var(--nk-sale); }
.post-review-item.is-up { border-left-color: var(--nk-success); }
.post-review-date {
  font-size: 12px;
  color: var(--nk-mute);
  font-variant-numeric: tabular-nums;
  margin-right: var(--nk-s-md);
}
.post-review-to {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nk-ink);
  font-weight: 600;
}
.post-review-why {
  margin: var(--nk-s-xs) 0 0;
  color: var(--nk-charcoal);
}
.post-review-ref {
  display: inline-block;
  margin-top: var(--nk-s-xs);
  font-size: 14px;
  color: var(--rd-accent-text);
}

/* ---- 支撑关系（rests_on / 反向边）----
   这是判断之间唯一有方向的关系。用发丝线左边条，和内联目录同一个语汇 ——
   它们都是「结构性的指路」，不是内容本身。 */
.post-rests,
.post-supports,
.post-related-picked {
  padding: 0 0 0 var(--nk-s-xl);
  border-left: 2px solid var(--nk-hairline-soft);
  font-size: 15.5px;
  line-height: 1.7;
}
.post-rests { margin: 0 0 var(--nk-s-xxl); }
.post-supports { margin: var(--nk-s-section) 0 var(--nk-s-lg); }
.post-related-picked { margin: var(--nk-s-lg) 0 0; }

.post-rests-head,
.post-supports-head,
.post-related-picked-head {
  margin: 0 0 var(--nk-s-sm);
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--nk-mute);
}
.post-rests-list,
.post-supports-list,
.post-related-picked-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.post-rests-list li,
.post-supports-list li,
.post-related-picked-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--nk-s-sm);
  margin: 0 0 var(--nk-s-sm);
}
.post-rests-list a,
.post-supports-list a,
.post-related-picked-list a {
  color: var(--rd-accent-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.post-rests-list a:hover,
.post-supports-list a:hover,
.post-related-picked-list a:hover { border-bottom-color: currentColor; }
/* 支撑项后面跟的置信度徽章比正文小一号，别喧宾夺主 */
.post-rests-list .post-conf { font-size: 10px; padding: 2px 6px; }

/* ---- 段落级的「已推翻 / 已过时」----
   ⚠️ 不用 text-decoration: line-through。中文长段落打删除线会横穿汉字笔画，
      整段就废了 —— 而这个标记的目的恰恰是**保留可读**，不是隐藏。
      一行以内的短句用 Markdown 的 ~~删除线~~ 就够，不需要这个组件。

   降对比度用 color 而不是 opacity：opacity 会把里面的链接、行内代码一起冲淡，
   在暗色下尤其糊。只改文字色，链接仍然认得出是链接。 */
.post-stale {
  border-left: 3px solid var(--nk-stone);
  padding: var(--nk-s-sm) 0 var(--nk-s-sm) var(--nk-s-lg);
  margin: 0 0 var(--nk-s-xl);
}
.post-stale.is-overturned { border-left-color: var(--nk-sale); }
.post-stale-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--nk-s-md);
  margin: 0 0 var(--nk-s-sm);
}
.post-stale-flag {
  font-size: 10.5px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--nk-stone);
}
.post-stale.is-overturned .post-stale-flag { color: var(--nk-sale); }
.post-stale-when {
  font-size: 12px;
  color: var(--nk-mute);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
}
.post-stale-when:hover { border-bottom-style: solid; }
.post-stale-body { color: var(--nk-mute); }
.post-stale-body > *:last-child { margin-bottom: 0; }

/* 文章底部的版权/相关文章/分页，全部改成发丝线堆叠 */
.relatedPosts > .relatedPosts-list > div,
.post-copyright,
#pagination.pagination-post {
  border-radius: var(--nk-r-none);
  box-shadow: none;
  border-top: 1px solid var(--nk-hairline);
}
.relatedPosts > .headline,
.relatedPosts-list .content .title {
  font-size: 16px;
  font-weight: 500;
  line-height: 1.75;
  color: var(--nk-ink);
}

/* ==========================================================================
   11. 侧栏（filter-sidebar）
   规范：canvas 底、零圆角、组间距 18px、组标题 body-strong、
   条目之间 1px 发丝线，计数用 mute。
   ========================================================================== */

#aside-content .card-widget {
  background: var(--nk-canvas);
  border: none;
  border-top: 1px solid var(--nk-hairline);
  border-radius: var(--nk-r-none);
  box-shadow: none;
  padding: var(--nk-s-xl) 0;
  margin-bottom: 0;
}
#aside-content .card-widget:first-child { border-top: none; }

#aside-content .card-info .author-info__name {
  font-family: var(--nk-font-display);
  font-size: 32px;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0;
  color: var(--nk-ink);
}
#aside-content .card-info .author-info__description,
#aside-content .card-info .site-data a .headline {
  font-size: 12px;
  font-weight: 500;
  color: var(--nk-mute);
}
#aside-content .card-info .site-data a .length-num {
  font-size: 24px;
  font-weight: 500;
  color: var(--nk-ink);
}
/* 头像在 Nike 系统里没有对应件；保留但去掉圆形装饰感 */
#aside-content .card-info img.avatar-img { border-radius: var(--nk-r-none); }

#aside-content .item-headline {
  font-size: 16px;
  font-weight: 500;
  line-height: 1.75;
  color: var(--nk-ink);
  margin-bottom: var(--nk-s-md);
}
#aside-content .item-headline i { display: none; }

#aside-content .aside-list .aside-list-item,
#aside-content .card-archives li,
#aside-content .card-categories li {
  border-bottom: 1px solid var(--nk-hairline-soft);
}
#aside-content :is(.card-archives, .card-categories) li a {
  font-size: 14px;
  font-weight: 500;
  color: var(--nk-ink);
  padding: var(--nk-s-md) 0;
}
#aside-content :is(.card-archives, .card-categories) li a:hover { color: var(--nk-mute); }
#aside-content :is(.card-archives, .card-categories) .card-archive-list-count,
#aside-content :is(.card-archives, .card-categories) .card-category-list-count {
  color: var(--nk-mute);
}

/* ==========================================================================
   12. 按钮 / 标签（button-primary + filter-chip）
   规范：所有 CTA 是 30px 胶囊；filter-chip 未选中是 canvas 底 + 发丝线描边，
   选中直接整体反相成 ink 底白字 —— 「No middle state.」
   ========================================================================== */

.button--animated,
#post-info .post-meta + .button,
.pagination .page-number,
.pagination .extend,
#pagination .prev-post a,
#pagination .next-post a {
  border-radius: var(--nk-r-lg);
  box-shadow: none;
  font-size: 16px;
  font-weight: 500;
}

.pagination .page-number {
  background: var(--nk-canvas);
  border: 1px solid var(--nk-hairline);
  color: var(--nk-ink);
  min-width: 40px;
  height: 40px;
  line-height: 38px;
  margin: 0 var(--nk-s-xs);
}
.pagination .page-number.current,
.pagination .page-number:hover {
  background: var(--nk-cta-bg);
  color: var(--nk-cta-fg);
  border-color: var(--nk-cta-bg);
}

/* 标签云 / 分类页的标签 = filter-chip */
.tag-cloud-list a,
#article-container .tag-list a,
.article-meta-wrap .article-meta__tags a,
#aside-content .card-tag-cloud a {
  display: inline-block;
  font-size: 12px !important;
  font-weight: 500;
  line-height: 1.5;
  color: var(--nk-ink) !important;
  background: var(--nk-canvas);
  border: 1px solid var(--nk-hairline);
  border-radius: var(--nk-r-lg);
  padding: var(--nk-s-sm) var(--nk-s-lg);
  margin: 0 var(--nk-s-sm) var(--nk-s-sm) 0;
}
.tag-cloud-list a:hover,
#aside-content .card-tag-cloud a:hover,
.article-meta-wrap .article-meta__tags a:hover {
  background: var(--nk-cta-bg);
  color: var(--nk-cta-fg) !important;
  border-color: var(--nk-cta-bg);
}

/* ==========================================================================
   13. 目录（TOC）
   ========================================================================== */

#card-toc {
  background: var(--nk-canvas);
  border-radius: var(--nk-r-none);
  box-shadow: none;
  border-left: 1px solid var(--nk-hairline);
}

/* ---- 目录：跟着视口长，而不是被压在一个 140px 的小格子里 ----

   🔴 病根不在 sticky。主题的 .sticky_layout 本来就是 position:sticky，
      粘顶一直是好的（实测滚到页面底部它都还在）。真正的问题是主题给
      `.toc-content` 写死了 `max-height: 140px`（_page/common.styl）——
      不管你屏幕多高，目录永远只有 140px，多出来的条目藏在一个
      几乎看不见的内部滚动条后面。文章越长目录越长，也就越没法用，
      而长文恰恰最需要目录。

   参照 christianjmills.com：它的规则是
   `.sidebar { position:sticky; overflow-y:auto; max-height:100vh }`，
   再由 JS 按导航条高度动态设 top 和 max-height。
   本站不需要那段 JS —— 导航条会整个滚走，不是固定的。

   ⚠️ **只改这一个数，不要动布局。**
      试过把侧栏改成 flex 列、让列表 `flex:1` 撑满剩余高度：
      `.sticky_layout` 没有确定高度，`flex:1` + `min-height:0` 当场塌成 0，
      连 sticky 都跟着失效（目录直接滚走）。经典的 flex 塌陷，别再试。

   🕳️ 150px 是实测凑的：目录实际贴在视口 55px 处
      （`.sticky_layout` 的 CSS top 是 20px，但它自带 35px 上边距，
      而 sticky 用的是**外边距盒**，所以是 20+35），
      再减掉卡片标题 24px、上下内边距，和底部一点呼吸位。
      主题升级后如果目录贴顶的位置变了，回来调这个数。 */
#aside-content #card-toc .toc-content {
  /* 干掉主题写死的 140px（_page/common.styl） */
  max-height: calc(100vh - 150px);
  overflow-y: auto;
  /* 目录滚到底之后不要带着整个页面接着滚 —— 那个手感很糟 */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--nk-hairline) transparent;
}

/* WebKit 的滚动条默认又粗又亮，压成一条发丝线 */
#aside-content #card-toc .toc-content::-webkit-scrollbar { width: 6px; }
#aside-content #card-toc .toc-content::-webkit-scrollbar-thumb {
  background: var(--nk-hairline);
  border-radius: var(--nk-r-none);
}
#aside-content #card-toc .toc-content::-webkit-scrollbar-track { background: transparent; }
/* ⚠️ 必须带上 #aside-content —— 主题写的是
   `#aside-content #card-toc .toc-content .toc-link.active`（**两个 id**）。
   这里只写一个 id 的话优先级不够，整条规则被静默丢掉，
   目录高亮会保持主题默认的青色 #00c4b6，在黑白系统里非常扎眼。
   （CONTEXT.md 第 9 条记的就是这个坑，这里之前正是漏网的一处。） */
#aside-content #card-toc .toc-content .toc-link {
  font-size: 14px;
  font-weight: 500;
  color: var(--nk-mute);
  border-left: 2px solid transparent;
  padding-left: var(--nk-s-md);
}
#aside-content #card-toc .toc-content .toc-link:hover {
  color: var(--nk-ink);
}
/* 当前章节用强调色。右栏目录是阅读界面的一部分，
   所以它和正文一样可以上色（见第 2 节 --rd-accent 的注释）。 */
#aside-content #card-toc .toc-content .toc-link.active {
  background: none;
  color: var(--rd-accent-text);
  border-left-color: var(--rd-accent);
  font-weight: 600;
}

/* 「Contents」那行标题降级成小字标签 —— 它是路牌，不是内容，
   不该和目录条目抢注意力。 */
#aside-content #card-toc .item-headline {
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--nk-mute);
  margin-bottom: var(--nk-s-md);
}
#aside-content #card-toc .item-headline i { display: none; }

/* 阅读进度百分比。
   主题给的是 `float:right; margin-top:-9px; font-size:140%; font-style:italic` ——
   浮动 + 负边距 + 放大 140% 三者叠加，字形会顶出标题行的盒子被切掉一截。
   改成 flex 排一行，去掉负边距和斜体，数字就能完整显示。 */
#aside-content #card-toc .item-headline {
  display: flex;
  align-items: baseline;
  gap: var(--nk-s-sm);
}
#aside-content #card-toc .item-headline span:not(.toc-percentage) {
  flex: 1 1 auto;
  margin-left: 0;
}
#aside-content #card-toc .toc-percentage {
  float: none;
  margin-top: 0;
  flex: 0 0 auto;
  font-size: 13px;
  font-style: normal;
  font-weight: 500;
  font-variant-numeric: tabular-nums;   /* 数字等宽，滚动时不会左右跳 */
  color: var(--nk-mute);
  line-height: 1;
}

/* ==========================================================================
   14. 搜索（search-pill）
   规范：soft-cloud 底、24px 圆角、40px 高；聚焦时翻成 canvas 底 + 2px ink 描边，
   外面套 12px 的 soft-cloud 光晕（系统里唯一的 focus ring）。
   ========================================================================== */

#local-search .local-search-box input {
  background: var(--nk-soft-cloud);
  color: var(--nk-ink);
  border: 1px solid transparent;
  border-radius: var(--nk-r-md);
  height: 40px;
  padding: var(--nk-s-sm) var(--nk-s-lg);
  font-size: 16px;
  font-family: var(--nk-font-ui);
}
#local-search .local-search-box input:focus {
  background: var(--nk-canvas);
  border: 2px solid var(--nk-ink);
  box-shadow: 0 0 0 12px var(--nk-soft-cloud);
  outline: none;
}
#search-dialog {
  background: var(--nk-canvas);
  border-radius: var(--nk-r-none);
  box-shadow: none;
  border: 1px solid var(--nk-hairline);
}
#search-dialog .search-dialog__title {
  font-size: 24px;
  font-weight: 700;
  color: var(--nk-ink);
}
.search-result-list .search-result-title {
  font-size: 16px;
  font-weight: 500;
  color: var(--nk-ink);
}

/* ==========================================================================
   15. 页脚（footer）
   规范：canvas 底、顶部一条 1px 发丝线、文字 caption-md + mute，
   最底下的版权行是 utility-xs（9px）。
   ========================================================================== */

#footer {
  background: var(--nk-canvas);
  background-image: none;
  border-top: 1px solid var(--nk-hairline);
}
#footer::before { content: none; }
#footer-wrap {
  color: var(--nk-mute);
  font-size: 14px;
  font-weight: 500;
  padding: var(--nk-s-section) var(--nk-s-xl);
}
#footer-wrap a { color: var(--nk-mute); }
#footer-wrap a:hover { color: var(--nk-ink); }
#footer-wrap .framework-info,
#footer-wrap .copyright + div {
  font-size: 9px;
  line-height: 1.75;
  color: var(--nk-mute);
}

/* ==========================================================================
   16. 右下角工具条（button-icon-circular）
   规范：40px 圆形，soft-cloud 底 + ink 图标。
   ========================================================================== */

#rightside > div > button,
#rightside > div > a {
  background: var(--nk-soft-cloud);
  color: var(--nk-ink);
  border-radius: var(--nk-r-full);
  width: 40px;
  height: 40px;
  line-height: 40px;
  margin-bottom: var(--nk-s-sm);
  box-shadow: none;
}
#rightside > div > button:hover,
#rightside > div > a:hover {
  background: var(--nk-cta-bg);
  color: var(--nk-cta-fg);
}

/* ==========================================================================
   17. 响应式
   规范断点：1023 / 599。区块节奏 48 → 32 → 24px，
   展示层标题 96 → 64 → 48px（line-height 恒定 0.9）。
   ========================================================================== */

@media screen and (max-width: 1023px) {
  :root { --nk-s-section: 32px; }
  .layout { padding: var(--nk-s-section) var(--nk-s-lg); }
  #article-container :is(h1, h2, h3, h4, h5, h6) { margin-top: var(--nk-s-section); }
}

@media screen and (max-width: 599px) {
  :root { --nk-s-section: 24px; }
  .layout { padding: var(--nk-s-section) var(--nk-s-md); }
  /* #site-info / #site-title 的 DOM 已经不存在了（见第 7 节），这里不再有对应规则。 */
  #post #post-info .post-subtitle { font-size: 16.5px; }
  #article-container { font-size: 16.5px; line-height: 1.75; }
  #article-container h2 { font-size: 23px; }
  #recent-posts .recent-post-info { padding-left: 0; }
  #recent-posts .article-title { font-size: 20px; }
}

/* ==========================================================================
   18. 文章里的媒体（图 / 视频 / 嵌入播放器）
   都必须服从版心宽度。图片主题已经处理了，视频和 iframe 没有。
   ========================================================================== */

/* ⚠️ 裸 <video> 默认按【视频原始分辨率】渲染，一个 1920 宽的 mp4 会直接
   撑破版心、压到右侧目录上。VS Code 粘贴视频时插入的就是裸标签，
   所以这条不能只写给 .video-local —— 得覆盖 #article-container 下所有 video。 */
#article-container video,
#article-container iframe {
  display: block;
  max-width: 100%;
  border: 0;
}
/* ⚠️ 宽高都用 auto + 两个上限，而不是 width:100%。
   原因是竖屏视频：手机拍的 1080×1920 如果撑满 720px 的版心，
   高度会变成 1280px —— 读者得滚三屏才划得过去。
   加上 max-height 之后，横屏视频仍然铺满版心（受 max-width 约束），
   竖屏视频则按高度封顶、自动居中。两种朝向都不会失控。 */
#article-container video {
  width: auto;
  height: auto;
  max-height: 80vh;
  /* ⚠️ 必须用 margin 简写一次写全：下面若再出现 `margin: X 0`，
     简写会把左右重置成 0，auto 居中就失效了（踩过）。 */
  margin: var(--nk-s-lg) auto;
  /* ⚠️ 这里**不能用 --nk-ink**。它是「前景色」token，暗色模式下会翻成 #ffffff，
     结果视频底下压一块纯白，画面渲染出来之前刺眼地闪一下。
     （写 `var(--nk-ink, #111111)` 也没用 —— 那个回退值只在变量未定义时生效，
     而它永远有定义。）用一个**不随明暗翻转**的字面值。 */
  background: #0d0d0f;
}

/* 外链视频的「点击加载」占位块（{% video %} 生成，由 js/media.js 接管点击）。
   整块可点，不只是那个播放按钮 —— 「点画面就该播」。
   封面图由构建流程抓到本地（source-en/video-covers/），走内联 background-image。 */
.video-embed.is-facade {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--nk-s-md);
  cursor: pointer;
  border: 1px solid var(--nk-hairline);
  background-size: cover;
  background-position: center;
  transition: background-color 0.2s;
}
/* 有封面时压一层半透明黑：① 保证白色播放键和标题在任何画面上都可读，
   ② hover 时减淡，给出「可以点」的反馈。 */
.video-embed.is-facade.has-cover::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.42);
  transition: background-color 0.22s;
}
.video-embed.is-facade.has-cover { position: relative; }
.video-embed.is-facade.has-cover:hover::before { background: rgba(0, 0, 0, 0.22); }
.video-embed.is-facade.has-cover > * { position: relative; }   /* 压在遮罩之上 */
/* 没封面时（抓取失败/离线）退回纯色块 —— 仍然可用，只是朴素 */
.video-embed.is-facade:not(.has-cover):hover { background: var(--nk-charcoal); }
/* 有封面时标题给一层描边阴影，压在亮画面上也读得清 */
.video-embed.is-facade.has-cover .video-hint {
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}
.video-play {
  width: 60px;
  height: 60px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: var(--nk-r-full);   /* 圆形图标钮 —— 系统里允许的两种形状之一 */
  background: transparent;
  color: #ffffff;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background-color 0.2s, transform 0.2s;
}
.video-embed.is-facade:hover .video-play {
  background: rgba(255, 255, 255, 0.16);
  transform: scale(1.06);
}
.video-play svg { width: 24px; height: 24px; fill: currentColor; margin-left: 3px; }
.video-hint {
  color: rgba(255, 255, 255, 0.72);
  font-size: 13px;
  font-weight: 500;
  padding: 0 var(--nk-s-lg);
  text-align: center;
}

/* {% video %} 生成的嵌入播放器外壳。
   aspect-ratio 直接声明 16:9，不用再玩 padding-top 百分比那套老 hack。 */
.video-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  /* 宽度上限由 {% video %} 按比例算好写在内联 style 里（竖屏视频用），
     这里只负责居中 —— 宽度被夹小之后不居中会贴在左边。 */
  margin: var(--nk-s-lg) auto;
  /* 同上：不能用 --nk-ink，它暗色下是白的 */
  background: #0d0d0f;
}
.video-embed > iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}


/* ==========================================================================
   19. 文章底部：上一篇 / 下一篇、相关推荐
   这两块在没有封面图时会填一块纯色占位。--default-bg-color 已经改成
   soft-cloud（第 4 节），这里再处理 hover 和形状。
   ========================================================================== */

/* 主题的 hover 是 opacity .4→.5 再加 scale(1.1)。
   纯色块上放大看不出任何变化，而透明度那 0.1 的差别肉眼也分辨不出 ——
   等于「鼠标放上去没反应」。改成直接换一档颜色。 */
#pagination .pagination-related .cover,
.relatedPosts .pagination-related .cover {
  opacity: 1;
  transform: none;
  transition: background-color 0.22s;
}
#pagination .pagination-related:hover .cover,
.relatedPosts .pagination-related:hover .cover {
  opacity: 1;
  transform: none;
}
/* 💡 hover 时改的是【变量】而不是 background。
   因为主题是在 pug 里打了内联 `style="background: var(--default-bg-color)"`，
   内联样式压得过任何选择器 —— 但 var() 是在元素上现场解析的，
   所以在父元素上换掉变量值，内联那句就会跟着变。不用 !important。 */
#pagination .pagination-related:hover,
.relatedPosts .pagination-related:hover {
  --default-bg-color: var(--nk-hairline-soft);
}

/* 发丝线代替色块来划分区域 —— 系统里唯一允许的深度线索 */
#pagination .pagination-related,
.relatedPosts .pagination-related {
  border: 1px solid var(--nk-hairline-soft);
}
#pagination.pagination-post { background: transparent; }

/* ==========================================================================
   20. 焦点环
   浏览器默认的焦点环在暗色页面上是白色的（Chrome 特意做成高对比，好让它在
   任何背景上都可见），点一下视频/按钮就会闪出一个白框再淡出 —— 在这套
   零圆角零阴影的克制系统里非常突兀。

   ⚠️ 但**不能直接 outline:none 了事**。焦点环是键盘用户唯一的位置指示，
   删掉等于让整个站对键盘不可用。正确做法是分开处理：
     :focus:not(:focus-visible)  ← 鼠标点出来的焦点，不画
     :focus-visible              ← 键盘 Tab 出来的焦点，用系统自己的语言画
   ========================================================================== */

:focus:not(:focus-visible) {
  outline: none;
}

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

/* 视频和占位块上，白色描边比 ink 更清楚（它们自己就是深色/图片底） */
#article-container video:focus-visible,
.video-embed:focus-visible,
.video-play:focus-visible {
  outline-color: #ffffff;
}

/* ==========================================================================
   20b. 把正文规则挡在枢纽 / 列表之外
   ⚠️ 这一节是整个改版里最容易踩的坑，先说清楚为什么需要它。

   Butterfly 的 page.pug 把**所有页面**的内容都渲染进同一个 `#article-container`
   —— 长文如此，三栏枢纽首页和分区列表页也如此。于是第 10 节那套「正文」规则
   （青绿链接 + 下划线、h2 通栏横线、标题 48px 上边距）会连带作用到枢纽页上，
   表现是：栏目标题变青绿、底下出现两条线（h2 的发丝线 + .hub-rule）、
   页面顶部凭空多出一大片空白。

   这些选择器都带 id（特异度 1,0,1），纯 class 压不过，所以下面必须同样带
   `#article-container` 前缀。写成 `.hub a { … }` 是不生效的。
   ========================================================================== */

/* ---- 枢纽页要一块更宽的画布 ----
   两层限制都要解：
     ① 主题的 `.layout.hide-aside { max-width: 1000px }`（_page/common.styl:44）
        —— 特异度 0,2,0，第 9 节那条裸 `.layout` 压不过它
     ② 本文件第 10 节给阅读页的 880px
   三栏各自才 300 出头，1000px 是不够的。

   :has() 在 Chrome 105+ / Safari 15.4+ / Firefox 121+ 可用；
   万一不支持，枢纽页只是变窄，不会错版 —— 所以没有做回退。 */
.layout.hide-aside:has(.hub) { max-width: 1280px; }
#page #article-container:has(> .hub) { max-width: none; }

/* 枢纽页没有标题，主题给 #page 的 50px 上边距 + .layout 的 48px 叠起来
   会在导航条和第一个栏目标题之间空出近 100px。收紧到一档。 */
.layout:has(.hub) { padding-top: var(--nk-s-xl); }
.layout:has(.hub) #page { padding-top: 0; }

/* 枢纽 / 列表里的标题不是「章节标题」，不要正文那套横线和大上边距 */
#article-container .hub-heading,
#article-container .hub-about .hub-heading {
  border-bottom: none;
  padding-bottom: 0;
  margin: 0;
}

/* 枢纽 / 列表里的链接回到黑白 —— 强调色只留给正文（见第 2 节 --rd-accent 注释） */
#article-container .hub-heading a,
#article-container .hub-item > a,
#article-container .hub-more,
#article-container .recent-posts a {
  color: var(--nk-ink);
  text-decoration: none;
}
#article-container .hub-heading a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}
#article-container .hub-item > a { border-bottom: 1px solid var(--nk-hairline-soft); }
#article-container .hub-item > a:hover { border-bottom-color: var(--nk-ink); }
#article-container .hub-more { color: var(--nk-mute); }
#article-container .hub-more:hover { color: var(--nk-ink); }
/* 「这里有什么」那几条是编辑性文案里的链接，仍然算正文，保留强调色 */
#article-container .hub-about ul a {
  color: var(--rd-accent-text);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* 列表里的分类是次要信息，不能和标题一样黑 */
#article-container .recent-posts .article-meta__categories { color: var(--nk-stone); }
#article-container .recent-posts .article-meta__categories:hover { color: var(--nk-ink); }

/* 枢纽页没有 h1，页面顶端第一个元素是栏目标题。
   正文里 h2 的 48px 上边距在这里变成了一大片空白，去掉。 */
#page #article-container > .hub:first-child { margin-top: 0; }
#page #article-container > .section-blurb:first-child { margin-top: 0; }

/* ==========================================================================
   21. 改版：三栏枢纽首页 + 分区页 + 日期在左的列表
   HTML 由 scripts/site-sections.js 生成。列表项刻意和主题 index 页同形，
   所以下面这套「日期在左」对 /blog/（主题生成）和 /notes/、/tutorials/
   （脚本生成）同时生效，只维护一份。
   ========================================================================== */

/* ---- 列表：日期在左，标题 + 摘要在右 ----
   关键是 `display: contents`：.recent-post-info 本身不产生盒子，
   它的三个孩子（标题 / 元信息 / 摘要）直接成为 .recent-post-item 这个
   grid 的成员，于是可以把元信息那一列拎到左边去。
   不这么做的话，日期被埋在 .article-meta-wrap 里，纯 CSS 拉不出来。

   ⚠️ display:contents 会让 .recent-post-info 自身的 padding/background 失效
      —— 上面第 9 节那两条 padding 规则因此不再起作用，这是预期的。 */
#recent-posts .recent-post-item {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 0 var(--nk-s-xxl);
  align-items: start;

  /* ⚠️ 必须复位高度。主题给 index_layout 1/2/3 写死了 `height: 16.8em`
     （_page/homepage.styl:26）—— 那是为「左图右文」的封面卡片准备的固定高度。
     换成 grid 之后，grid 默认 align-content:stretch 会把两行**拉伸**去填满
     这个高度，表现是标题和摘要之间凭空多出近 100px 的空隙，
     而且怎么调 margin 都不管用（问题不在间距，在行高被撑开）。 */
  height: auto;
  align-content: start;
}

/* 列表正文也要限宽。#recent-posts 本身是满栏的，摘要铺到 860px 会太长。
   列表是**扫读**的，一眼要能看完一条摘要，所以比文章页的版心更窄：
   右侧文字列约 760px（132 是日期列，30 是列间距）。 */
#recent-posts { max-width: calc(760px + 132px + var(--nk-s-xxl)); }
#recent-posts .recent-post-info { display: contents; }

#recent-posts .article-meta-wrap {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  gap: var(--nk-s-xs);
  padding-top: 6px;              /* 和标题的第一行基线对齐 */
  font-variant-numeric: tabular-nums;
}
#recent-posts .article-title { grid-column: 2; grid-row: 1; }
#recent-posts .content       { grid-column: 2; grid-row: 2; }
/* 有封面图的文章：封面进右列，排在标题上方。本站目前不用封面，
   这条是为了将来加了封面时不会把 grid 撑坏。 */
#recent-posts .post_cover    { grid-column: 2; grid-row: 1; margin-bottom: var(--nk-s-md); }

/* 主题在元信息里塞了图标和竖线分隔符（📅 Created | 📥 分类）。
   竖排之后这些都是噪音，而且脚本生成的分区页里根本没有它们 ——
   两边要长得一样，就得把主题那份多余的去掉。 */
#recent-posts .article-meta-wrap i,
#recent-posts .article-meta-wrap .article-meta-separator,
#recent-posts .article-meta-wrap .article-meta-label { display: none; }

#recent-posts .article-meta-wrap .post-meta-date { font-size: 13.5px; color: var(--nk-mute); }
#recent-posts .article-meta-wrap .article-meta,
#recent-posts .article-meta-wrap .article-meta__categories {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nk-stone);
  text-decoration: none;
}
#recent-posts .article-meta-wrap .article-meta__categories:hover { color: var(--nk-ink); }

@media screen and (max-width: 767px) {
  /* 窄屏放不下两列。回到单列，日期挪到标题上方当一行小字。 */
  #recent-posts .recent-post-item { display: block; }
  #recent-posts .recent-post-info { display: block; }
  #recent-posts .article-meta-wrap {
    flex-direction: row;
    gap: var(--nk-s-md);
    padding-top: 0;
    margin-bottom: var(--nk-s-sm);
  }
}

/* ---- 分区页顶部的一句话 ---- */
.section-blurb {
  max-width: var(--rd-measure);
  margin: 0 0 var(--nk-s-section);
  font-size: 17px;
  line-height: 1.7;
  color: var(--nk-mute);
}

/* ==========================================================================
   21b. 三栏枢纽首页
   ========================================================================== */

.hub {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--nk-s-section) calc(var(--nk-s-section) + var(--nk-s-md));
  margin: 0 0 calc(var(--nk-s-section) * 1.6);
}

/* 栏目标题下面是 2px 实线，比正文里 h2 的 1px 发丝线重一档 ——
   枢纽页上这几个标题是页面的骨架，不是章节分隔。 */
.hub-heading {
  margin: 0;
  font-size: 23px;
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--nk-ink);
}
.hub-heading a { color: inherit; text-decoration: none; }
.hub-heading a:hover { text-decoration: underline; text-underline-offset: 4px; }
.hub-rule {
  height: 2px;
  background: var(--nk-ink);
  margin: var(--nk-s-sm) 0 var(--nk-s-xl);
}

.hub-item { margin: 0 0 var(--nk-s-xl); }
.hub-item > a {
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--nk-ink);
  text-decoration: none;
  border-bottom: 1px solid var(--nk-hairline-soft);
}
.hub-item > a:hover { border-bottom-color: var(--nk-ink); }
.hub-item p {
  margin: var(--nk-s-xs) 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--nk-mute);
}

.hub-more {
  display: inline-block;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--nk-mute);
  text-decoration: none;
  border-bottom: 1px solid var(--nk-hairline-soft);
  padding-bottom: 2px;
}
.hub-more:hover { color: var(--nk-ink); border-bottom-color: var(--nk-ink); }

/* 空栏目的降级形态。
   站点只有几篇文章时，三栏里必然有一栏是空的 —— 留一片白会让人以为页面坏了，
   虚线框加一句说明则读起来像「还没写」，是诚实的状态而不是故障。 */
.hub-empty {
  font-size: 14px;
  line-height: 1.65;
  color: var(--nk-mute);
  border: 1px dashed var(--nk-hairline);
  padding: var(--nk-s-lg);
}

/* ---- 枢纽页下半部分：关于 / 这里有什么 ---- */
.hub-about {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--nk-s-section) calc(var(--nk-s-section) + var(--nk-s-md));
  padding-top: var(--nk-s-section);
  border-top: 1px solid var(--nk-hairline-soft);
}
.hub-about p {
  margin: 0 0 var(--nk-s-lg);
  font-size: 15.5px;
  line-height: 1.75;
}
.hub-about ul {
  margin: 0;
  padding-left: var(--nk-s-xl);
  font-size: 15.5px;
  line-height: 1.85;
}
.hub-about a { color: var(--rd-accent-text); }

@media screen and (max-width: 1023px) {
  .hub { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media screen and (max-width: 767px) {
  .hub,
  .hub-about { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   22. 导航条右上角的工具图标行
   HTML 由 scripts/nav-utils.js 在构建期注入：邮箱等社交图标 + 明暗切换 + 搜索。
   ========================================================================== */

/* ⚠️ #menus 在主题里是 display:block（菜单项靠自身 inline-block 排成一行）。
   往里塞一个块级的 flex 容器会**另起一行**，图标整排掉到导航条下面去 ——
   而且因为 #nav 有固定高度，它是溢出到页面上的，不是把导航撑高。
   所以这里必须先把 #menus 本身改成 flex 行。
   两个 id 的特异度才压得过主题的 `#menus`。 */
#nav #menus {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
#nav #menus .menus_items { display: flex; align-items: center; }

#nav-utils {
  display: flex;
  align-items: center;
  gap: var(--nk-s-sm);
  margin-left: var(--nk-s-lg);
  /* 和菜单项之间加一道竖线：左边是「去哪」，右边是「做什么」，
     两组东西性质不同，靠间距区分不够明确。
     线的高度用固定值而不是 stretch —— 导航条是 60px 行高，
     stretch 会让它顶天立地，看着像把导航切成两半。 */
  padding-left: var(--nk-s-lg);
  border-left: 1px solid rgba(255, 255, 255, .18);
  height: 22px;
}

/* 图标钮本身。规范铁律②说按钮只有胶囊和圆形图标钮两种形状，
   这里走圆形图标钮那一支。 */
#nav-utils .nav-util {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  border-radius: var(--nk-r-full);
  color: var(--nk-nav-fg);
  opacity: .85;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: opacity .2s, background-color .2s;
}
#nav-utils .nav-util:hover {
  opacity: 1;
  background: rgba(255, 255, 255, .12);
}
#nav-utils .nav-util i { margin: 0; line-height: 1; }

/* ---- 搜索按钮保持主题原样 ----
   它在菜单**左边**、带「⌕ Search」文字，这是用户明确要的形态。
   这里只解决一件事：颜色。

   ⚠️ 主题编译出来的是
        `#page-header.not-top-img #nav span.site-page { color: var(--font-color) }`
      特异度 (2,2,1)。而 --font-color 在亮色下是 charcoal #39393b ——
      压在黑底导航上几乎看不见。
      第 8 节那批导航配色规则写的是 `#page-header ... #nav .site-page`，
      少一个 `span` 元素选择器 (2,2,0)，**压不过它**。
      所以这里必须原样带上 `span` 才生效。 */
#page-header.not-top-img #nav span.site-page,
#page-header.nav-fixed #nav span.site-page,
[data-theme='dark'] #page-header.not-top-img #nav span.site-page,
[data-theme='dark'] #page-header.nav-fixed #nav span.site-page {
  color: var(--nk-nav-fg);
  text-shadow: none;
}
/* 主题给 .site-page 挂了一条 hover 从左展开的蓝色下划线伪元素，
   黑白系统里没有位置放它 —— 悬停统一用第 8 节那条 2px 白色下边线。 */
#nav span.site-page:not(.child):after { content: none; }
#nav #search-button span.site-page:hover { box-shadow: inset 0 -2px 0 currentColor; }

/* 搜索按钮的盒子。这里同时决定了**焦点环（那个胶囊框）的大小** ——
   焦点环是 `outline: 2px` + `outline-offset: 2px`（第 20 节），
   紧贴着元素盒子画，所以想让胶囊宽松一点只能加这里的左右内边距。
   57px + 左右各 5 = 67px，加上 2×2 的 offset，胶囊外沿 61 → 71，约 +16%。

   上下改成对称的 3px：主题原本给的是 `padding-bottom: 6px`
   （#nav .site-page），那是为它自己那条 hover 从左展开的下划线留的位置 ——
   而那条下划线上面已经用 `:after { content: none }` 关掉了。
   留着只会让胶囊整体偏下，看着像没对齐。

   胶囊形状来自 `.social-icon { border-radius: var(--nk-r-full) }`（第 5 节），
   搜索按钮那个 span 正好带 social-icon 这个类。 */
#nav #search-button span.site-page {
  padding: 3px 5px;
}

/* 右下角齿轮面板里的明暗按钮藏起来 —— 同一个功能不该有两个入口。
   ⚠️ 只能用 display:none，**不能删掉它**：导航里那个按钮是靠
   `document.getElementById('darkmode').click()` 把事件转给它的
   （见 scripts/nav-utils.js 顶部说明）。它不在 DOM 里，导航按钮就是哑的。 */
#rightside #darkmode { display: none; }

@media screen and (max-width: 768px) {
  /* ⚠️ 上面那条 `#nav #menus .menus_items { display: flex }` 会**盖掉**主题
     在窄屏把菜单收进汉堡的 `display: none`（主题那条特异度更低）。
     不补这一句的话，菜单项在手机上仍然横着排，把导航撑出屏幕 ——
     表现是整页可以左右横拖。 */
  #nav #menus .menus_items { display: none; }

  /* 工具行仍然留在导航条上（和 CJM 一致），但去掉分隔线和外边距，给汉堡让位。 */
  #nav-utils {
    margin-left: auto;
    padding-left: 0;
    border-left: none;
    gap: var(--nk-s-xs);
  }
}

/* ==========================================================================
   23. note 提示框的暗色适配

   Butterfly 的 note 颜色全部写死在亮色值上（`--note-info-bg: #eef7fa` 之类），
   **没有暗色分支**。结果是暗色页面上每个提示框都是一块刺眼的浅底白块，
   正文黑底、框子亮底，对比强烈到会打断阅读。

   这里只重定义那几个 CSS 变量，不碰主题的任何选择器 ——
   主题升级换了布局也不影响，除非它把变量名改了。

   配色规则：底色取该色相压到接近画布的极暗值（和 --rd-accent-tint 同一档手法），
   边条和图标取提亮值保证在暗底上可见（对比度 ≥ 4.5:1）。
   ========================================================================== */

[data-theme='dark'] {
  /* default —— 无类型的普通提示，走中性灰，不引入色相 */
  --note-default-bg: #1c1c1e;
  --note-default-border: #707072;
  --note-default-text: #9e9ea0;

  /* info —— 用 Nike 调色板的暗色 info */
  --note-info-bg: #141a2b;
  --note-info-border: #6f9bff;
  --note-info-text: #8fb2ff;

  /* success —— Nike 的 success-bright */
  --note-success-bg: #10231a;
  --note-success-border: #1eaa52;
  --note-success-text: #3ecb72;

  /* warning —— Nike 规范里没有琥珀色，这一档是推导的 */
  --note-warning-bg: #241c10;
  --note-warning-border: #e8a33d;
  --note-warning-text: #f0b862;

  /* danger —— 用第 3 节那个为可读性提亮过的 sale */
  --note-danger-bg: #261415;
  --note-danger-border: #ff5a5c;
  --note-danger-text: #ff8082;

  /* primary —— 取 Nike 的 accent-purple-soft */
  --note-primary-bg: #1b1728;
  --note-primary-border: #beaffd;
  --note-primary-text: #cdc0ff;

  /* modern 样式那一套（本站默认是 flat，但文章里可以逐条指定 modern） */
  --note-modern-default-bg: #1c1c1e;
  --note-modern-default-border: #4b4b4d;
  --note-modern-default-text: #e9e9ec;
  --note-modern-info-bg: #141a2b;
  --note-modern-info-border: #2f4a8a;
  --note-modern-info-text: #8fb2ff;
  --note-modern-success-bg: #10231a;
  --note-modern-success-border: #1e5c36;
  --note-modern-success-text: #3ecb72;
  --note-modern-warning-bg: #241c10;
  --note-modern-warning-border: #7a5a1f;
  --note-modern-warning-text: #f0b862;
  --note-modern-danger-bg: #261415;
  --note-modern-danger-border: #7a2f31;
  --note-modern-danger-text: #ff8082;
  --note-modern-primary-bg: #1b1728;
  --note-modern-primary-border: #4a3d7a;
  --note-modern-primary-text: #cdc0ff;
}

/* 零圆角是铁律①。主题配置里 note.border_radius 是 3，这里统一压平。 */
#article-container .note { border-radius: var(--nk-r-none); }

/* label 的颜色类名只有 default/blue/pink/red/purple/orange/green 七个
   （scripts/tag/label.js）。写了别的名字时元素只剩 `<mark class="hl-label 乱写">`，
   于是掉回浏览器给 <mark> 的默认黄底 —— 在这套黑白系统里非常刺眼，
   在暗色下更是一块荧光。这里给一个中性回退，写错时是「不显眼」而不是「炸眼」。 */
#article-container .hl-label:not(.default):not(.blue):not(.pink):not(.red):not(.purple):not(.orange):not(.green) {
  background-color: var(--nk-soft-cloud);
  color: var(--nk-ink);
}

/* ==========================================================================
   24. note 的第七种类型：accent（站点强调色）

   主题自带 default / info / success / warning / danger / primary 六种，
   颜色分别是灰蓝绿橙红紫 —— 都是「语义信号」。
   但有一类框不表达语义，只是想突出一下（「本文属于以下系列」「相关阅读」
   「书籍链接」这种），用红橙绿都不对味，用灰又太没存在感。

   这一种直接用站点自己的强调色，和正文链接、目录高亮同一个青绿，
   读起来是「这是本站的东西」而不是「这里有个警告」。

   用法：{% note accent 'fa-regular fa-lightbulb' %}…{% endnote %}

   ⚠️ 主题的 note 是靠 `.note.<类型>` 加 CSS 变量上色的，而 accent 不在
      它的类型表里，所以这里必须把边条 / 底色 / 图标色三条都写全 ——
      少写一条就会出现「边是青绿的但底色是透明」这种半成品。
   ========================================================================== */

#article-container .note.accent {
  border-left-color: var(--rd-accent);
}
#article-container .note.accent.flat {
  background: var(--rd-accent-tint);
}
#article-container .note.accent.modern {
  border-color: var(--rd-accent) !important;
  background: var(--rd-accent-tint);
}
/* 自定义图标渲染成 <i class="note-icon">，内置图标走 ::before —— 两条都要 */
#article-container .note.accent .note-icon,
#article-container .note.accent:not(.no-icon)::before {
  color: var(--rd-accent);
}
