@charset "UTF-8";
/* =========================================================================
   李锐 · 个人网站  样式表
   风格：Apple 极简（S3 / P2 预设）—— 大留白、强层级、克制强调色
   规则：数字全部取自设计 Token，间距只许 4/8/12/16/24/32/48/64/96
   ========================================================================= */

/* ---------- 0. Token ---------- */
:root {
  color-scheme: light;          /* 显式锁定浅色滚动条/表单控件；无此项时 Chrome 会按动画中的 body 背景色推导滚动条样式，主题切换 300ms 过渡里来回翻 → 原生滚动条（用户所指"最右侧进度条"）抖动 */
  /* 强调色插槽（P2 Apple 极简） */
  --accent: #0071e3;
  --accent-deep: #0058b0;
  --accent-soft: #eaf2fc;
  --accent-ink: #0058b0;        /* 小字号强调色「文字」专用：--accent 在 14–15px 正文上仅 3.98:1
                                   不达 AA 4.5:1，需深一档（≈7:1）。填充/描边仍用 --accent。 */
  --link: #0071e3;
  --ac-rgb: 0,113,227;          /* 呼吸点光域 RGB 分量（与第四幕同源） */
  --aura: rgba(0,113,227,.08);
  --aura-b: rgba(0,113,227,.04);
  /* 环境极光 token（§10e .aurora 用）——「极光光谱」四色：品牌蓝 → 靛 → 青 → 粉紫。
     全部 color-mix 进页面底色：边缘融进背景，永远不会有「贴上去的圆」。
     --ambient-base = 极光所载的底色（浅色跟随卡片白；深色在下方主题块覆盖）。 */
  --ambient-base: var(--card);
  /* ── AI 光谱（Apple Intelligence「一个系统」）· v86 ──────────────────────
     原先所有「AI 感」的紫散在 5 处**各自硬编码**：--au-2(#5e5ce6) / --au-4(#bf5af2) /
     aiTitleGlow rgba(140,120,255) / tabbar #tabGrad(#6f4fd2) / 气泡与 AI 发送键(#5e5ce6)。
     它们彼此"像"却没有任何规则连着 —— 正是那种说不出哪怪、但能感到「差点意思」的来源。
     现在收敛成**同一条光谱**（蓝 → 靛紫 → 粉）上的取样点：
       · 数量仍是多个 —— 渐变是 Apple Intelligence 的本体，压成单色反而把它杀死；
       · 来源只有一个 —— 调 --ai-* 一处，全站 AI 的克制度同频。
     --ai-2-rgb 是给 rgba() 写辉光用的（CSS 无法把 hex 直接拆进 rgba）。 */
  --ai-1: #2f6fe6;                    /* 蓝（光谱起点，与 #tabGrad 中段同源） */
  --ai-2: #7d7aff;                    /* 靛紫（光谱中段：极光 au-2 / AI 辉光 / Tab 收尾 / 揭幕光） */
  --ai-3: #bf5af2;                    /* 粉（光谱末段：极光 au-4 / 发送键收尾） */
  --ai-2-rgb: 125, 122, 255;          /* = --ai-2 的 RGB 分量（aiTitleGlow 等辉光用） */
  --au-1: color-mix(in srgb, var(--accent) 23%, var(--ambient-base));   /* 品牌蓝 · 主光（刻意最克制：它最靠近 hero 文字） */
  --au-2: color-mix(in srgb, var(--ai-2) 17%, var(--ambient-base));     /* 靛 —— 改引 --ai-2 */
  --au-3: color-mix(in srgb, #30c8b8 13%, var(--ambient-base));         /* 青（底部边缘微光） */
  --au-4: color-mix(in srgb, var(--ai-3) 12%, var(--ambient-base));     /* 粉紫 —— 改引 --ai-3 */
  --au-5: color-mix(in srgb, #ffd60a 12%, var(--ambient-base));         /* 暖金：与蓝在顶部暖冷相接，出「绚烂」的那一味 */

  /* 中性色阶 */
  --ink: #1d1d1f;
  --ink-2: #48484c;
  /* 灰阶严格三档（指南 §3.2.3）：主文字 / 次级 / 弱化。
     ink-3 #6e6e73 对白底约 5.07:1，满足 AA 正文 4.5:1；
     原 ink-4 #767679 与 ink-3 亮度差仅 3%，肉眼不可分 → 已并入 ink-3。 */
  --ink-3: #6e6e73;
  --surface: #f5f5f7;
  --card: #ffffff;
  /* 玻璃通透度（v81 · ③ 连续滑块）：单一变量驱动全站玻璃；默认 64% = 站点现值（标准）。
     滑块改它即全站同频；各组件按原值差值用 calc 表达，故默认严格等于现状、零视觉回归。 */
  --glass-a: 64%;
  --range-track: #d2d2d7;   /* 滑块未填充轨道（浅色） */
  --line: #e5e5e9;
  --line-strong: #dcdce0;
  --hairline: #f0f0f2;
  /* 图片占位底色（相册/首页相册缩略图懒加载时的底）。
     ⚠ 此前**只被 var(--bg-subtle, #f0f0f2) 引用却从未定义** → 兜底近白恒生效，
        深色主题下相册页实测出现 29 个 rgb(240,240,242) 白块（"闪白"从未真正修掉）。 */
  --bg-subtle: #f0f0f2;
  /* v31：hover 由「不透明中灰」改为**极轻半透明 wash**。
     Apple 从不铺实心灰块 —— 不透明灰在白色元素上读成「被选中/禁用」的廉价方块，
     且压在玻璃导航上会「糊住」玻璃材质。半透明 wash 让底色透出来 = 轻盈、有材质。
     面积越大 α 越低（大块面铺淡、小控件略深），与 Apple「大表面更克制」的层级逻辑一致。 */
  --hover: rgba(0, 0, 0, .05);        /* 控件级：nav / icon / chip / ghost */
  --hover-row: rgba(0, 0, 0, .032);   /* 行级：recent / contact（面积大 → 更淡） */
  --accent-hover: #0077ed;            /* 主按钮 hover：原地微亮（苹果式，原 #0058b0 变暗偏重） */

  /* 字体（末位为离线兜底，联网时由 Satoshi / Inter / Noto 接管） */
  --font: "Satoshi", -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Segoe UI", Roboto,
    /* 中文回退：优先苹方（macOS）→ 鸿蒙/思源/Noto（装了就用更精致的）→ 再退雅黑（Windows 默认） */
    "PingFang SC", "Hiragino Sans GB", "HarmonyOS Sans SC", "Source Han Sans SC", "Noto Sans SC",
    "Microsoft YaHei UI", "Microsoft YaHei", sans-serif;
  --font-serif: "Noto Serif SC", serif;
  /* 等宽：全站唯一一份（此前 style.css 与 hero 内联各写一套，字体回退顺序不一致） */
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Roboto Mono", monospace;

  /* 间距 */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px; --sp-9: 96px;
  --sec-gap: clamp(80px, 8vw, 124px);   /* v59：模块之间的统一竖向间距（单倍）——相邻两区之间恒等于它，不再叠加两次 padding。v86 C：上限 112→124（Apple 官网模块间距实测约 100–140px，大屏更松）*/

  /* 圆角：严格 3 档（小 8 / 中 16 / 全圆 999），全篇复用，不出现第四种 */
  --r-sm: 8px;  --r-md: 16px;  --r-pill: 999px;
  --r-pop: 16px;          /* 弹层圆角：此前只被 var(--r-pop, 16px) 引用却未定义，靠兜底生效；补进档位（= --r-md） */
  --r-glass: 22px;            /* 第 4 档圆角：专供玻璃表面（与概念页一致） */
  --sh-1: 0 1px 2px rgba(20, 20, 22, .05);
  --sh-2: 0 1px 2px rgba(20, 20, 22, .045), 0 10px 30px rgba(20, 20, 22, .075);   /* v31：苹果式双层阴影（接触影 + 柔和扩散）*/
  --sh-pop: 0 12px 40px rgba(20, 20, 22, .14);
    /* v71 高级感：玻璃顶高光 / 玻璃材质块 / 底栏反向投影 —— 此前各自硬编码散在 20+ 条规则，收敛为 token（阴影层级仍只 sh-1/2/pop 三档） */
    --sh-glass: inset 0 1px 0 rgba(255, 255, 255, .9);
    --sh-glass-lg: inset 0 1px 0 rgba(255, 255, 255, .95), inset 0 -1px 0 rgba(20, 20, 22, .05), 0 16px 48px rgba(20, 20, 22, .10);
    --sh-bar: 0 -8px 24px rgba(20, 20, 22, .08);

  /* 动效 */
  --dur-fast: .15s; --dur-base: .24s; --dur-slow: .28s;
  --ease: cubic-bezier(.32, .72, .28, 1);
  --ease-breathe: cubic-bezier(.4, 0, .3, 1);   /* v25：常驻呼吸/环境循环专用（原 5 处内联魔法值统一收口） */
  --active-scale: .97;

  /* 版心（《长文阅读页通用规范》§二.1：桌面 1200px）。v54 曾放大到 1440 → 首页过满，v55 回归 1200 */
  --wrap: 1200px;
  --nav-h: 64px;
}

/* ---------- 0b. 深色模式 ---------- */
[data-theme="dark"] {
  color-scheme: dark;           /* 与 :root 的 light 配对 —— 主题切换时原生滚动条随 data-theme 一次性确定，不再随背景色动画振荡 */
  --accent: #0a84ff;          /* 深底按钮填充：苹果暗色系统蓝（白字 ~3.6:1，按钮大字号达标，与苹果一致） */
  --accent-deep: #0a84ff;     /* 同苹果暗蓝，留作 hover 加深位 */
  --accent-soft: #16243a;
  --accent-ink: #2997ff;      /* 深底小字强调色文字：--accent 仅 4.35:1 不达 AA，改用更亮的链接蓝（≈5.2:1） */
  --link: #2997ff;
  --ac-rgb: 10,132,255;
  --aura: rgba(10,132,255,.20);
  --aura-b: rgba(10,132,255,.12);            /* 深底链接：苹果暗色链接蓝（~6.4:1，比 #4DA3FF 更收敛、不发飘） */
  /* 深底极光：光在深底上更浓（Apple 的光效在深色上最明显）；色相整体提亮一档，避免发闷。
     注：farthest-side 铺展比 closest-side 宽 ~56%，故浓度比 v2 初版（34/20/17/15）略收 */
  --ambient-base: var(--surface);
  /* 深色同一条光谱，仅整体提亮一档（深底上光要更亮才不发闷）—— 与浅色同源，改一处两边同动 */
  --ai-1: #4d8ff5;
  --ai-2: #7d7aff;
  --ai-3: #d68cff;
  --ai-2-rgb: 125, 122, 255;
  --au-1: color-mix(in srgb, var(--accent) 25%, var(--ambient-base));
  --au-2: color-mix(in srgb, var(--ai-2) 17%, var(--ambient-base));
  --au-3: color-mix(in srgb, #3adbc8 14%, var(--ambient-base));
  --au-4: color-mix(in srgb, var(--ai-3) 12%, var(--ambient-base));
  --au-5: color-mix(in srgb, #ffd60a 14%, var(--ambient-base));

  --ink: #ededed;             /* 主文字不用纯白 */
  --ink-2: #c7cbd1;
  --ink-3: #a8adb5;
  --surface: #14161a;
  --card: #1c1f24;            /* 卡片比底色亮一档做层级 */
  --line: #2a2e35;
  --line-strong: #383d45;
  --hairline: #22262c;
  --bg-subtle: #22262c;         /* 与 --hairline 同档：深色下占位块不再发白 */
  --hover: rgba(255, 255, 255, .09);
  --hover-row: rgba(255, 255, 255, .055);
  --accent-hover: #2b95ff;

  --sh-1: none;
  --sh-2: none;
  --sh-pop: 0 12px 40px rgba(0, 0, 0, .28);
    /* v71：深底投影无效且廉价（原 .5/.45/.40 纯黑大扩散）→ 层级改由「表面色亮一档 + 描边」表达 */
    --sh-glass: inset 0 1px 0 rgba(255, 255, 255, .12);
    --sh-glass-lg: inset 0 1px 0 rgba(255, 255, 255, .14), inset 0 -1px 0 rgba(255, 255, 255, .03);
    --sh-bar: 0 -8px 24px rgba(0, 0, 0, .28);
}

/* ---------- 1. Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 88px; }
body {
  margin: 0;
  background: var(--card);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.65;          /* 原 1.75：苹果正文/UI 行高约 1.5–1.7，过松显「博客感」、欠编辑式克制 */
  /* 中文正文不加负字距：负字距是「大字号展示文字」的高级感手法（指南 §3.1.6：
     大标题 -0.02~-0.04em，正文 0）。铺到中文正文会让字挤在一起，还逼出 9 处 letter-spacing:0 补丁。
     展示级文字（h1 / 各标题 / 大数字）各自保留自己的负字距。 */
  letter-spacing: 0;
  text-wrap: pretty;          /* 渐进增强：避免中英混排末行只剩一个字 */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, p, figure { margin: 0; }
a { color: var(--link); text-decoration: none; }
/* v57：补 padding: 0 —— 原先只重置了 font/color/background/border，
   <button> 仍带着 UA 默认 padding: 1px 6px。同一套 .video-card 既有 <a> 版（外链）
   也有 <button> 版（本地弹窗），<div> 版（占位）本来就没有 UA padding，
   于是 button 版内容被内缩 12px：同一网格里两张卡的封面宽度对不齐，缩略图也不再
   贴齐卡片圆角的溢出口。「同组件多载体」最容易漏的正是这一处。 */
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  /* v71：路由切换会把焦点搬到 h1（见 app.js focusView）。但 Chrome 对
     「鼠标点链接后的脚本 focus」也匹配 :focus-visible → 鼠标用户每进一页
     都会看到标题上一个蓝框。所以 h1 的圈**只在键盘模态下**画：
     <html>.kb 由 app.js 的 keydown/pointerdown 维护。
     特异性 (0,3,1) 高于上面的 :focus-visible (0,1,0)，且只作用于 h1[tabindex="-1"]，
     不会影响任何真实可交互元素的焦点圈。 */
  }
  h1[tabindex="-1"]:focus { outline: none; }
  html.kb h1[tabindex="-1"]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 5px;
  /* v16：原 border-radius:4px 是作用在「被聚焦元素本身」上的 ——
     16px 圆角的卡片一获得键盘焦点，四角就突然变尖（真 bug）。
     现代浏览器的 outline 会自动跟随元素自身圆角，故删掉这一条。 */
}
::selection { background: var(--accent-soft); color: var(--ink); }
/* v41：深色下 body 原用 --card（与卡片同色）→ 卡片=底色，只剩描边，层级失效；
   token 约定「卡片比底色亮一档」，故深色版心改用 --surface（更深一档），让卡片(72% --card)浮起来。
   浅色保持不动（白底 + 白卡 + 发丝描边是已认可的克制观感）。 */
[data-theme="dark"] body { background: var(--surface); }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--sp-6); }
.page-head { margin-bottom: var(--sp-7); }   /* 集合页/相册页页头：原为内联 style（2 处），收成类 */
/* ⚠ 这里的 font-size 已删：元素写法是 <h1 class="h2 page-title">，而 .h2(style.css 更靠后、同特异性)
   声明了 font-size: clamp(28px, 3.6vw, 40px) → 原先写的 2.5rem **永不生效（死代码）**，
   实际一直是 .h2 的响应式字号（桌面 40px / 移动 28px，行为正确）。保留 animation。 */
.page-title { animation: aiTitleGlow 5s var(--ease-breathe) infinite; }   /* 集合页/关于/相册 页标题：原为内联 style="font-size: 2.5rem"（3 处），收成类 */
/* v84·sections：页标题的 Apple Intelligence 微光 —— 蓝+一缕紫、极低不透明、5s 呼吸；
   让每页的"名字"也纳入 AI 光语言（与李锐柔光同族），但不抢字、维持编辑式克制。 */
@keyframes aiTitleGlow {
  0%, 100% { text-shadow: 0 0 26px rgba(var(--ac-rgb),.07), 0 0 42px rgba(var(--ai-2-rgb),.05); }
  50%      { text-shadow: 0 0 32px rgba(var(--ac-rgb),.18), 0 0 50px rgba(var(--ai-2-rgb),.12); }
}
.wrap.notfound { text-align: center; padding-block: 96px; }   /* 用 .wrap.notfound(0,2,0) 而非 .notfound(0,1,0)：窄屏 .wrap 的简写 padding 会清掉纵向内边距，且它在文件后面 → 同特异性下会反覆盖。提高特异性后不受顺序影响。 */   /* 404：原为内联 style，收成类。用 padding-block 而非简写 padding —— 简写会把 .wrap 的左右内边距清成 0，且被后面的 .wrap 媒体查询反覆盖。 */
.notfound .lede { margin: 0 auto var(--sp-6); }
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--card); padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.skip:focus { left: var(--sp-5); top: var(--sp-3); }

/* ---------- 2. 顶部导航 ---------- */
/* 浮起的玻璃药丸导航：通栏留白，玻璃在滚动时折射身后的内容 */
.nav {
  position: sticky; top: 0; z-index: 60;
  height: auto; padding: var(--sp-3) 0 var(--sp-2);
  background: transparent; border-bottom: 0;
}
.nav__inner {
  max-width: calc(var(--wrap) - var(--sp-6)); height: auto;   /* v55：跟随 --wrap（1200-32=1168），浮起玻璃药丸比正文内容略宽一档（等价原硬编码 1168） */
  margin: 0 auto;   /* B5：超宽屏时玻璃药丸居中，不再贴左 */
  position: relative;   /* v92：iOS Large Title 内联标题的定位锚 */
  display: flex; align-items: center; gap: var(--sp-5);
  padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-5); border-radius: var(--r-glass);
  transition: box-shadow var(--dur-base) var(--ease);
}
.nav.is-scrolled .nav__inner { box-shadow:var(--sh-glass), var(--sh-pop); }
[data-theme="dark"] .nav.is-scrolled .nav__inner { box-shadow:var(--sh-glass), var(--sh-pop); }
/* 滚动感知显隐（苹果 Safari / iOS 同款）：往下阅读导航让位、往上滚或指针到顶部再现。
   既最大化阅读空间，又不删导航（随时可达）。 */
.nav { transition: transform var(--dur-base) var(--ease), opacity var(--dur-base) var(--ease); }
.nav.is-hidden { transform: translateY(-130%); opacity: 0; pointer-events: none; }
/* ── iOS Large Title 内联标题（v92，仅移动端）────────────────────────────
   滚动 >96px → .nav.is-condensed 淡入当前页标题；与 is-scrolled / is-hidden 并存
   （下滑时导航本就让位，上滑再现即带上标题——Safari 式语义，不破坏既有显隐）。
   桌面端导航有链接排，故只在 ≤640px 显示，避免压链接。 */
.nav__inline-title {
  display: none;
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 0.938rem; font-weight: 600; color: var(--ink); letter-spacing: -0.01em;
  opacity: 0; transition: opacity var(--dur-base) var(--ease);
  pointer-events: none;
}
@media (max-width: 640px) {
  .nav__inline-title { display: block; }
  .nav.is-condensed .nav__inline-title { opacity: 1; }
}
/* ── 路由切换微过渡（v92）：opacity 淡入，不用 transform（防糊掉内部毛玻璃）── */
@keyframes routeIn { from { opacity: 0; } to { opacity: 1; } }
#main.route-in { animation: routeIn 180ms var(--ease) both; }
#main { overflow-anchor: none; }   /* v93：关滚动锚定——防真机(微信 WebView/iOS WKWebView) 在 SPA 换页时把视口往旧锚点(首页底部)拽，导致"跳到板块底部" */
@media (prefers-reduced-motion: reduce) {
  .nav__inline-title { transition: none; }
  #main.route-in { animation: none; }
}
.brand { display: flex; align-items: center; gap: var(--sp-3); color: var(--ink); position: relative; padding-bottom: var(--sp-1);
  transition: transform var(--dur-fast) var(--ease); }   /* v29：补齐按压反馈所需的过渡 */
.brand:active { transform: scale(var(--active-scale)); }   /* v29：此前无按压反馈（与卡片/按钮不一致） */
/* 品牌即文字标：无任何附加图形或呼吸点，「Lee小锐」本身就是标识。
   ① 字号近乎统一（Lee 18 / 小锐 17，只差 1px）—— 读起来是「一个名字」而不是两块拼起来的；
      同时仍满足指南 §3.1.4 的灰度对齐（中文比英文小 1~2px），兼顾统一感与配重。
   ② 呼吸感来自「字距的空气感」（两块都给 .02em）与字重克制 —— 而不是再挂一个会呼吸的小圆点：
      首屏欢迎语已有同款 .live 呼吸点，导航再来一个就是重复，且在 UI 区会读成"状态指示灯"。
      分工：页面负责呼吸，导航是静止的锚点。
   ③ 两块共用 baseline，不用 margin 硬凑；颜色统一 --ink，深浅模式自动反转。 */
.brand__name { display: inline-flex; align-items: baseline; gap: var(--sp-1); font-weight: 700; color: var(--ink); }
.brand__name-en { font-size: 1.125rem; letter-spacing: .02em; }
.brand__name-zh { font-size: 1.062rem; letter-spacing: .02em; }
/* 呼吸感：静态来自字距的空气（.02em）；动态发生在「靠近」的瞬间 —— 字距轻轻张开，像吸了一口气。
   这是"反馈"类动效（指南：动效只服务反馈/引导/层级），不是装饰。
   刻意不做持续跳动：文字标持续运动会显廉价，且首屏已有呼吸点，导航不该再挂一个会呼吸的挂件。 */
.brand__name-en,
.brand__name-zh { transition: letter-spacing var(--dur-slow) var(--ease); }
@media (hover:hover) and (pointer:fine) {
  .brand:hover .brand__name-en,
  .brand:hover .brand__name-zh { letter-spacing: .06em; }
}

.nav__links { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
.nav__link {
  position: relative;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-pill);
  font-size: 0.938rem; font-weight: 500; color: var(--ink-3);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
@media (hover:hover) and (pointer:fine) {
  .nav__link:hover { color: var(--ink); background: var(--hover); }
}

.nav__link:active { transform: scale(var(--active-scale)); }
.nav__link.is-active { color: var(--ink); font-weight: 700; }
.nav__link.is-active::after {
  content: ""; position: absolute; left: 50%; bottom: 2px;
  width: 16px; height: 2px; border-radius: var(--r-pill);
  background: var(--accent); transform: translateX(-50%);
}
.icon-btn {
  width: 36px; height: 36px; border-radius: var(--r-pill);
  display: grid; place-items: center; color: var(--ink-3);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
@media (hover:hover) and (pointer:fine) {
  .icon-btn:hover { background: var(--hover); color: var(--ink); }
}

.icon-btn:active { transform: scale(var(--active-scale)); }
[data-theme="dark"] .ico-sun { display: none; }
[data-theme="light"] .ico-moon { display: none; }

/* ---------- 3. 通用版式 ---------- */
main { position: relative; z-index: 1; min-height: 72vh; }
/* SPA 首屏 CLS 修复（2026-10-19）：开场锁屏期间 body 被钳制为 100vh + overflow:hidden。
   此时若 main 仅 72vh，footer 会落在视口内（实测 y=756<940）；等 SPA 渲染完成、intro-lock
   移除，footer 被正文推到 ~5623 → 一次性 layout shift ≈0.146（Lighthouse CLS 橙）。
   故**仅在开场锁屏期间**让 main 撑满视口，把 footer 顶出 100vh 裁剪区（开场层本就盖住屏幕，
   无视觉影响）；渲染完成后 main 恢复 72vh，正常页面布局不受任何影响。 */
body.intro-lock main { min-height: 100vh; }
/* v59：模块竖向节奏统一为「单倍间距」—— 此前 .section 上下各留 padding，相邻两区叠加成 2 倍
   （1080 宽约 194px、1440 宽约 240px，反馈「模块间距偏大」）。改为：每块只留**顶部**间距
   = --sec-gap，末块再由 :last-child 补回底部留白 → 相邻两区之间恒等于**一个** --sec-gap。 */
.section { padding: var(--sec-gap) 0 0; }
.view > .section:last-child { padding-bottom: var(--sec-gap); }
/* 首页「停止页」底部露出一截最近更新，暗示下方有更多内容可下滑 */
.section--tight { padding: var(--sp-6) 0 0; }   /* v9/v59：顶部小留白 + 负 margin 上提窥视；与下一块的间距交给下一块的 --sec-gap */
.section--tight { margin-top: calc(-1 * clamp(72px, 12vh, 150px)); }   /* v46：取消「仅 ≥700px 才上提」门槛 —— 首屏改内容驱动高度后，矮屏也需上提「最近更新」以保持恒定呼吸间距 */
.section--tight .section__head { margin-bottom: var(--sp-6); }   /* 窥视区：头与列表拉近一档 */
.section__head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5); margin-bottom: var(--sp-7); }
/* 分区带（v59 取消硬边）：原先用「灰底（surface 60%）+ 上/下发丝线」做交替节奏。
   问题：首页上它叠在 **position:fixed 的极光**之上时，白区（透出极光、偏蓝/粉）
   与灰带（60% 灰压住极光、呈中性灰）在边界处**色相 + 明度同时突变** → 一条硬边，
   读作「割裂」而非分节（2026-10-03 反馈：首页视频区）。
   决策：**全站单一连续底色**（白 + 极光一致透出），分节节奏交给留白与 section__head，
   与 Apple 页面「一底色 + 大字距」一致。类名保留为语义标记，此处不再赋任何视觉。
   注：今后若确需"分区"，只能上**软边渐变**（大半径淡入淡出），切勿再引平铺硬底色。 */
.section--band { background: none; border: 0; }
.eyebrow {
  font-size: 0.812rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent-deep); margin-bottom: var(--sp-2);   /* 标签紧贴自己的标题（组内紧） */
}
[data-theme="dark"] .eyebrow { color: var(--link); }   /* B6：深底用链接蓝，与白底同档对比度余量 */
.h2 { font-size: clamp(28px, 3.6vw, 40px); font-weight: 600; line-height: 1.22; letter-spacing: -0.02em; text-wrap: balance; }
.h3 { font-size: clamp(19px, 2vw, 20px); font-weight: 700; line-height: 1.3; letter-spacing: -0.01em; text-wrap: balance; }
.lede { font-size: 1rem; color: var(--ink-3); max-width: 640px;
  /* 12px → 24px：40px 页标题下只留 12px 偏挤（与首页 h1→正文 41px 的节奏也不一致），
     按 8px 网格提到 --sp-5，标题区更舒展。 */
  margin-top: var(--sp-5); }

/* 视图切换动效 */
.view { animation: viewIn .24s var(--ease) both; }
@keyframes viewIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* 入场错峰：苹果式轻盈上浮 + 微缩放，平滑减速曲线（v59q 升级） */
.reveal { opacity: 0; transform: translateY(20px) scale(.985); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .34s var(--ease), transform .34s var(--ease);
  transition-delay: var(--d, 0ms);
}
/* 仅入场前挂 will-change，揭示后即卸下，避免长期占合成层 */
.reveal:not(.is-in) { will-change: opacity, transform; }
/* 阅读页「骨架级」入场（v80-①）：比 .reveal 更轻 —— 只上浮 12px、**不做微缩放**
   （正文块尺寸大，scale .985 会被看出来），过渡也短一档（--dur-base 而非 .34s）。
   只作用于结构性块（h2 / figure / blockquote / 代码块），**普通段落保持静止** ——
   阅读时文字不该动，动的是骨架；每条段落都做动画会变成幻灯片，也违背「克制动效」。 */
.reveal--soft { opacity: 0; transform: translateY(12px); }
.reveal--soft.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
  transition-delay: var(--d, 0ms);
}
/* 数字 count-up（v80-④）：等宽数字，滚动过程中宽度不跳，避免整行文字左右抖 */
.num { font-variant-numeric: tabular-nums; }
/* 主题切换柔和过渡（v59r）：仅切换瞬间对配色相关属性做交叉淡入，不列 transform/opacity，
   故不干扰入场揭示与首屏动画；无 !important，元素自带 transition（如卡片 hover/揭示）仍优先。 */
.is-theming, .is-theming * { transition: background-color .30s var(--ease), color .30s var(--ease), border-color .30s var(--ease), fill .30s var(--ease), box-shadow .30s var(--ease); }

/* ---------- 4. Hero ---------- */
.hero {
  padding: calc(var(--sp-9) + var(--sp-8)) 0 var(--sp-9);
  border-bottom: 1px solid var(--hairline);
}

.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: 48px; padding: 0 var(--sp-5); border-radius: var(--r-sm);
  /* v33：标签字重 700 → 500。按钮标签属 UI 档（站点基线：正文400 / UI500 / 标题700），
     700 是标题档 —— 「粗黑体 + 细描边」的头重脚轻，是按钮缺高级感的主因。 */
  font-size: 1rem; font-weight: 500;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.btn--primary { background: var(--accent); color: #fff; }
@media (hover:hover) and (pointer:fine) {
  .btn--primary:hover { background: var(--accent-hover); }   /* v31：原变暗成深蓝偏重 → 原地微亮 */
}
/* 深色主按钮对比度（上线前检查 P1）：白字 on 深色 --accent #0a84ff 仅 **3.65:1**，不达 AA 正文 4.5:1
   （浅色 #0071e3 = 4.70:1 达标，是深色强调色提亮后反过来压低了白字对比）。
   只给「按钮填充」单独降一档亮度 —— 链接与小字强调仍用 --link / --accent-ink，不受影响。 */
[data-theme="dark"] .btn--primary { background: #0a6ed1; }        /* 白字 5.05:1 ✅ */
@media (hover:hover) and (pointer:fine) {
  [data-theme="dark"] .btn--primary:hover { background: #0a76d8; } /* 白字 4.57:1 ✅，仍守「原地微亮」方向 */
}

/* v34：次级按钮由 v33「静音中性填充」升级为「玻璃质感静音填充」（方向 A，用户选定）。
   v34 实测：旧态是 0% 饱和纯中性灰，坐在接近纯白/纯暗底层上，彩虹只染视口边缘 →
   按钮「不参与液态光材质语言」才是与彩虹背景不搭配的真因；且边界对比≈1.2:1 低于 WCAG 3:1（深色尤弱）。
   新态：card 半透明玻璃 + backdrop-filter 模糊饱和 → 折射彩虹、与导航/芯片同一玻璃语言；
   发丝描边 + 双层阴影给出清晰边界（深浅皆可读）。沿用 .glass 的阴影/描边约定，blur 按按钮尺度收到 14px。 */
.btn--ghost {
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) - 18%), transparent);
  color: var(--ink);
  border: 1px solid color-mix(in srgb, #000 8%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  box-shadow:var(--sh-glass), inset 0 -1px 0 rgba(20,20,22,.04), var(--sh-1);
}
[data-theme="dark"] .btn--ghost {
  border-color: color-mix(in srgb, #fff 14%, transparent);
  box-shadow:var(--sh-glass), inset 0 -1px 0 rgba(255,255,255,.03), var(--sh-1);
}
/* v32：按钮内图标带过渡 —— hover 时尾箭头右移，给出「可点」的生命感（苹果 Learn more › 同款语汇）。
   注意：.btn 自身 transition 不含 svg 的 transform，故单独给一条。 */
.btn svg { transition: transform var(--dur-fast) var(--ease); }
@media (hover:hover) and (pointer:fine) {
  .btn--ghost:hover {
    background: color-mix(in srgb, var(--card) calc(var(--glass-a) - 8%), transparent);
    box-shadow:var(--sh-glass), inset 0 -1px 0 rgba(20,20,22,.05), var(--sh-2);
  }
  .btn--ghost:hover svg { transform: translateX(3px); }
}
[data-theme="dark"] .btn--ghost:hover {
  box-shadow:var(--sh-glass), inset 0 -1px 0 rgba(255,255,255,.03), var(--sh-2);
}

.btn--ghost:active { background: color-mix(in srgb, var(--card) calc(var(--glass-a) - 2%), transparent); }
[data-theme="dark"] .btn--ghost:active { background: color-mix(in srgb, var(--card) var(--glass-a), transparent); }

.btn:active { transform: scale(var(--active-scale)); }

/* ---------- 4b. 首页欢迎首屏（与开场动画第四幕「停留页」同源：文字/字号/位置一致，衔接无跳变） ---------- */
.hero--welcome {
  position: relative; overflow: hidden;
  /* v46：取消「强制撑满首屏」——原 min(92svh,940px) 让首屏内容下方留 147–195px（桌面）
     乃至 378px（平板竖屏）空档。改为内容驱动高度 + 随视口收放的底部内距：内容位置
     （padding-top）一字未动，故与开场动画第四幕「停留页」的交接零跳变；下方「最近更新」
     被上提后，首屏只留稳定 ~63–75px 的呼吸，不再是大片空白。 */
  min-height: auto;
  margin-top: calc(-1 * var(--nav-h));
  display: block;
  /* v19：由 flex 垂直居中改为顶部锚定 —— 原 align-items:center 让整块随字号(vw)在缩放时重新居中，
     导致标题（含"人工智能"）忽上忽下；顶部锚定后位置稳定，且与导航品牌恒有安全间距。 */
  /* v47：顶部 22vh → 16vh —— 导航底到首字由 142px 收到 ~88px，首屏更快进入内容
     （纯文字型 hero 的常见区间 10–16vh）。⚠ 同步补偿见 hero-v4-final.html 的 .act--page。 */
  padding: clamp(120px, 16vh, 240px) 0 clamp(124px, 17vh, 200px);   /* v46：底部随视口收放，使与「最近更新」的间距恒定。v86 C：hero 底部再多一档呼吸（112/176 → 124/200）*/
  border-bottom: 0;            /* 覆盖 .hero 的发丝线：它正好落在窥视区，割裂首屏 */
}
/* 与全站同一版心：这里**不要声明任何 max-width**。
   该元素同时带 .wrap 类（max-width:1200 + 左右 32px），而 .welcome-hero 定义在 .wrap 之后、
   权重相同 —— 任何 max-width 都会覆盖掉 1200：
     写 1040 → 首屏比 nav/section 右移 80px；写 none → 铺满视口，首屏被顶到最左边。
   正确做法是不设，交给 .wrap 统一控制。标题阅读宽度由 .welcome-hero__h1 的
   max-width:10.5em 与正文的 620px 各自兜底，不依赖此容器。 */
.welcome-hero__eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: 1.25rem; font-weight: 500; line-height: 1.4; letter-spacing: .02em; color: var(--ink-2);
  margin: 0 0 var(--sp-5);   /* v27：眉标由 700/--ink 降为 500/--ink-2 —— 700 属标题档，眉标应与正文同级但更轻更灰（参考：二阶信息缩小变灰、靠灰阶分层级） */
}
/* 眉标蓝点改用 .live（与第四幕同源呼吸点），规则见下方 .live */
.welcome-hero__h1 {
  font-size: clamp(48px, 6.4vw, 116px); line-height: 1.15; letter-spacing: -0.022em;
  font-weight: 600; color: var(--ink); max-width: 12em; text-wrap: pretty;
}
.welcome-hero__p {
  margin-top: clamp(30px, 4.6vh, 52px);
  font-size: clamp(18px, 1.7vw, 20px); line-height: 1.5; letter-spacing: 0;
  color: var(--ink-2); max-width: 620px;
}
.welcome-hero__p .serif { font-family: var(--font-serif); font-weight: 700; color: var(--ink); }

/* 与第四幕同源：双 aura 氛围光 + 呼吸蓝点（落版前后质感一致，零跳变） */
.welcome-hero { position: relative; }
/* 首屏不再自带光晕：供光统一交给全页固定的虹彩光（.aurora），避免双份叠加发灰 */
.welcome-hero__eyebrow, .welcome-hero__h1, .welcome-hero__p { position: relative; z-index: 1; }

/* v86 D-2：hero 滚动微视差（Apple 产品页那种）—— 首屏滚动时文字轻微上浮 + 极淡出。
   --hero-p 由 app.js 按滚动进度写入（0→1，在一屏的 60% 内走完），位移/透明度交给 CSS。
   ⚠ 只作用在**文字三件套**上，绝不给 .welcome-hero 容器加 transform ——
     容器一旦有 transform 就新建层叠上下文，里面的 AI 提问条 backdrop-filter 会被裁切/糊掉。 */
.welcome-hero { --hero-p: 0; }
.welcome-hero__eyebrow, .welcome-hero__h1, .welcome-hero__p {
  transform: translate3d(0, calc(var(--hero-p) * -14px), 0);
  opacity: calc(1 - var(--hero-p) * .10);
}
@media (prefers-reduced-motion: reduce) {
  .welcome-hero__eyebrow, .welcome-hero__h1, .welcome-hero__p { transform: none; opacity: 1; }
}
.live { position: relative; width: 11px; height: 11px; flex: none; }
.live__halo { position: absolute; left: 50%; top: 50%; width: 30px; height: 30px; margin: -15px 0 0 -15px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(var(--ac-rgb),.38) 0%, rgba(var(--ac-rgb),.10) 46%, transparent 72%);
  animation: haloBreathe 4s var(--ease-breathe) infinite; }
.live__dot { position: absolute; inset: 0; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 9px 1.5px rgba(var(--ac-rgb),.35);
  animation: dotBreathe 4s var(--ease-breathe) infinite; }
.live__ring { position: absolute; inset: 0; border-radius: 50%; border: 1.5px solid rgba(var(--ac-rgb),.6); opacity: 0;
  animation: liveHalo 6s var(--ease-breathe) infinite; }
@keyframes haloBreathe { 0%,100% { transform: scale(.82); opacity: .55; } 50% { transform: scale(1.16); opacity: 1; } }
@keyframes dotBreathe { 0%,100% { transform: scale(1); } 50% { transform: scale(1.14); } }
@keyframes liveHalo { 0% { transform: scale(1); opacity: .22; } 70% { opacity: .08; } 100% { transform: scale(2.6); opacity: 0; } }
/* v24：收敛首屏环境动效（苹果式安静）—— bloom 由 v12 四色虹彩收为「品牌蓝主光 + 1 冷色互补」两团，浓度下调；
   扩环 liveHalo 周期 5s→6s、终态 scale 3.1→2.6（不再外扩到眉标外），与 halo/dot 形成单一呼吸信号而非多动画打架。 */
.live__bloom { position: absolute; left: 50%; top: 50%; width: 520px; height: 520px; margin: -260px 0 0 -260px; border-radius: 50%; pointer-events: none; z-index: -1;
  background:
    radial-gradient(closest-side, rgba(var(--ac-rgb), .18) 0%, rgba(var(--ac-rgb), .06) 40%, transparent 70%),
    radial-gradient(closest-side at 32% 30%, rgba(80,205,180, .12) 0%, transparent 58%);
  mix-blend-mode: screen; opacity: .42;
  animation: liveBloom 4s var(--ease-breathe) infinite; }
@keyframes liveBloom { 0%,100% { transform: scale(.86); opacity: .30; } 50% { transform: scale(1.10); opacity: .46; } }
@keyframes liveBloomM { 0%,100% { transform: scale(.84); opacity: .40; } 50% { transform: scale(1.12); opacity: .56; } }
@media (prefers-reduced-motion: reduce) { .live__halo, .live__dot, .live__ring, .live__bloom { animation: none; } .live__ring { opacity: 0; } .live__halo { opacity: .7; } .live__bloom { opacity: .45; } .aurora { animation: none; } }
.nw { white-space: nowrap; }   /* v19：包裹"人工智能"等词，禁止跨行拆分（根治缩放跳动） */

/* ---------- 5. 文章列表 ---------- */
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-6); }
.chip {
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill); font-weight: 500;
  border: 1px solid transparent; font-size: 0.938rem; color: var(--ink-2);
  /* v37：由「白底 + 近不可见发丝线 + 灰字」的线框外观 → 「极轻中性填充胶囊」。
     原态 = 白卡底(#fff) 坐在 白页面底(#fff) 上，仅靠 1px #e5e5e9 描边成形 → 读成虚线框/占位，廉价。
     改为 --ink 6% 极轻填充：控件自带体量、无需描边；文字 ink-3→ink-2 提一档对比，不再发虚。 */
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  /* v44：补玻璃材质 —— chip 与 .btn--ghost 同属「控件」，后者早已是玻璃，前者却是纯填充，
     同一排筛选控件材质不一致。加 blur 后 chip 会折射极光（参与全站液态光语言）。
     填充维持 v37 的 --ink 6% 不动、不回升描边，避免推翻 v37 已验证的观感。 */
  -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);   /* v37：transition: all → 具名属性 */
}
@media (hover:hover) and (pointer:fine) {
  /* v37：hover 用「材质级微增」而非铺一层平灰 —— 填充加深一档 + 极轻描边定形 + 文字转 ink */
  .chip:hover {
    background: color-mix(in srgb, var(--ink) 11%, transparent);
    border-color: color-mix(in srgb, var(--ink) 10%, transparent);
    color: var(--ink);
  }
}

.chip:active { transform: scale(var(--active-scale)); }
.chip.is-on {
  /* v37：选中态字重 700 → 500。700 是标题档，小控件用标题档 = 粗黑体压小胶囊的头重脚轻，
     是筛选按钮缺高级感的主因（同 v33 按钮 700→500 结论）。选中改由实心 --ink 填充表达。 */
  background: var(--ink); border-color: var(--ink); color: var(--card);
  font-weight: 500;
  /* v84：选中筛选＝Apple Intelligence 柔光（呼吸）—— 蓝 + 一缕紫、低不透明、4.5s；
     把交互控件也纳入全站 AI 光语言（与 Tab 选中光谱环 / AI 精灵同族）。 */
  animation: chipAI 4.5s var(--ease-breathe) infinite;
}
@keyframes chipAI {
  0%, 100% { box-shadow: var(--sh-1), 0 0 10px -2px rgba(var(--ac-rgb),.12), 0 0 22px -6px rgba(var(--ai-2-rgb),.10); }
  50%      { box-shadow: var(--sh-1), 0 0 16px 1px rgba(var(--ac-rgb),.34), 0 0 32px 2px rgba(var(--ai-2-rgb),.22); }
}
@media (prefers-reduced-motion: reduce) { .chip.is-on { animation: none; } }
/* v32 修复（真 bug）：.chip.is-on 与 .chip:hover 特异性相同(0,2,0)且源码更靠后
   → 选中态把 hover 的 background/color/border 三条全部覆盖，「已选中的筛选项」hover 零反馈。
   （v32 审计实测：:hover 命中、elementFromPoint=SELF，但 bg/color/border 三项全无变化。）
   补一条更高特异性(0,3,0)的选中态 hover：原地微亮一档 —— 仍守「hover 是光不是漆」。 */
@media (hover:hover) and (pointer:fine) {
  .chip.is-on:hover { background: var(--ink-2); border-color: var(--ink-2); }
}

.post-list { display: grid; gap: var(--sp-4); }
.post {
  display: block; width: 100%; text-align: left;
  padding: var(--sp-6); border-radius: var(--r-md);
  /* v41：内容卡升级为「液态光玻璃」——半透明卡面 + 背景模糊饱和，折射彩虹极光，
     与导航/浮层/次级按钮同一材质语言；发丝描边 + 接触影给出边界与轻浮起（静止态也有层级）。 */
  background: color-mix(in srgb, var(--card) var(--glass-a), transparent);
  -webkit-backdrop-filter: blur(18px) saturate(168%);
  backdrop-filter: blur(18px) saturate(168%);
  border: 1px solid color-mix(in srgb, #000 7%, transparent);
  box-shadow:var(--sh-glass), var(--sh-1);
  transition: border-color var(--dur-base) var(--ease), transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
  --card-pad: var(--sp-6);   /* 供置顶角标复用，窄屏随 padding 一起收 */
}
@media (hover:hover) and (pointer:fine) {
  /* v84·sections：hover 更"活"——浮起大一档(-6px) + 一层极淡品牌蓝环境光(卡被"点亮")；
     仍守「hover 是光不是漆」，不引第二种填充色。 */
  .post.reveal:hover { transform: translateY(-6px); box-shadow: var(--sh-2), 0 16px 44px -16px rgba(var(--ac-rgb),.22); }
}

.post:active { transform: scale(var(--active-scale)); }
.post__top { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
/* v45 亲密性：原「元数据行→标题」与「标题→摘要」同为 12px，标题归属读不出来。
   元数据行下间距提到 16px、标题→摘要保持 12px → 标题明显更贴近它自己的摘要（skill 建议 ㉓）。 */
/* ---------- 全站「内容标签」统一语言（v78 · 2026-10-08）----------
   一条规则：无填充 + 1px --line-strong 描边 + 药丸圆角。
   层级只靠「字号 / 字重」区分：分类 .tag 12/700 · 技术栈 .stack 12/500 · 话题 .skill 14/400。
   不再用第二层底色 —— 守「一个组件内填充色最多一种」。
   （旧版只有 .post .tag 是描边，视频/作品卡继承了 accent-soft 填充 → 三处不一致，此处收敛。） */
.tag {
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  background: none; border: 1px solid var(--line-strong);
  font-size: 0.812rem; font-weight: 700; color: var(--accent-deep);
}
[data-theme="dark"] .tag { color: var(--link); }
.post__date { font-size: 0.938rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.post__dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }

/* v71 的「标签改描边」结论已上移到基础 .tag（v78），此处不再需要覆盖。 */
.post__title { font-size: 1.5rem; font-weight: 700; line-height: 1.3; letter-spacing: -.02em; color: var(--ink); }
.post__excerpt { margin-top: var(--sp-3); color: var(--ink-3); font-size: 1rem; max-width: 720px; }
.post__more {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  margin-top: var(--sp-4); font-size: 0.938rem; font-weight: 500; color: var(--link);   /* v37：CTA 标签 700→500（UI 档；同 v33 按钮结论） */
}
.post__more svg { transition: transform var(--dur-fast) var(--ease); }
@media (hover:hover) and (pointer:fine) {
  .post:hover .post__more svg { transform: translateX(3px); }
}

/* ---------- 6. 视频网格 ---------- */
.video-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-6); }
.video-card {
  width: 100%; height: 100%; text-align: left; border-radius: var(--r-md); overflow: hidden;
  display: flex; flex-direction: column;
  /* v41：内容卡升级为「液态光玻璃」——半透明卡面 + 背景模糊饱和，折射彩虹极光，
     与导航/浮层/次级按钮同一材质语言；发丝描边 + 接触影给出边界与轻浮起（静止态也有层级）。 */
  background: color-mix(in srgb, var(--card) var(--glass-a), transparent);
  -webkit-backdrop-filter: blur(18px) saturate(168%);
  backdrop-filter: blur(18px) saturate(168%);
  border: 1px solid color-mix(in srgb, #000 7%, transparent);
  box-shadow:var(--sh-glass), var(--sh-1);
  transition: border-color var(--dur-base) var(--ease), transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
}
@media (hover:hover) and (pointer:fine) {
  .video-card.reveal:hover { transform: translateY(-4px); box-shadow: var(--sh-2); }
}

.video-card:active { transform: scale(var(--active-scale)); }
.video-card__thumb {
  position: relative; aspect-ratio: 16 / 9; flex: none; display: grid; place-items: center;
  background: var(--t, var(--surface));
  /* v44：真封面尚未接入（实测 imgs=0）时，占位是一整块纯色 → 读成"灰块"偏廉价。
     补一层极浅同色明度渐变（明度差 ≤8%，skill §五允许的第一类渐变）+ 顶部内高光，
     让占位读成"有厚度的表面"。真封面接入后由 <img> 铺满覆盖，此层自动失效。 */
  background-image: linear-gradient(160deg, color-mix(in srgb, #fff 7%, transparent), transparent 62%);
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 40%, transparent);
}
/* 深色模式：不用示例浅色块，改用「比卡片亮一档的表面色」做层级（深底阴影无效） */
[data-theme="dark"] .video-card__thumb { background: var(--hover); }
/* 真实封面图：铺满 + 渐显（禁止"啪"地出现）；圆角由卡片的 overflow 统一裁切 */
.video-card__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
  animation: imgFade var(--dur-slow) var(--ease) both;
}
@keyframes imgFade { from { opacity: 0 } to { opacity: 1 } }
.video-card__thumb::after { content: ""; position: absolute; inset: 0; background: transparent; }
.video-card__thumb:has(.video-card__img)::after {   /* 只有真封面才需要压字遮罩 */
  background: linear-gradient(180deg, rgba(0,0,0,0) 50%, rgba(0,0,0,.38) 100%);
}
.play {
  position: relative; z-index: 1; width: 56px; height: 56px; border-radius: 50%;
  background: rgba(255,255,255,.92); color: #1d1d1f;
  display: grid; place-items: center;
  box-shadow:var(--sh-pop);
  transition: transform var(--dur-base) var(--ease);
}
/* ---------- v67：封面按钮改为「悬停揭示」，不再常驻压住封面 ----------
   问题：.play 是 56×56 的近实心白圆，靠 .video-card__thumb 的 place-items:center
   钉在封面正中（实测 centerX/centerY 均为 0）。而作品的新封面本身就是信息图、
   正中恰是标题区 —— 常驻按钮把封面最要紧的部分盖住了。
   策略分两种输入方式，因为它们的物理约束不同：
   · 桌面（有 hover）：默认不显示；鼠标移入时封面轻微压暗 + 按钮淡入浮起。
     压暗是必要的 —— 白按钮落在浅色封面（如新封面 #f5f5f7）上会读不出来。
   · 触屏（无 hover）：悬停揭示永远触发不了，必须常驻；但**移到左下角**，
     把中心完整让给封面（右上角已被置顶角标占用、右下角是时长角标）。 */
@media (hover: hover) and (pointer: fine) {
  .video-card__img { transition: filter var(--dur-base) var(--ease); }
  .video-card .play {
    opacity: 0; transform: scale(.9);
    transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
  }
  /* 鼠标移入 / 键盘聚焦：按钮淡入浮起 + 封面压暗；覆盖含 .play--ext / .play.is-off 所有变体 */
  .video-card:hover .play,
  .video-card:focus-visible .play { opacity: 1; transform: none; }
  /* v80-⑤：:focus-within 镜像 —— 封面压暗原本只有 :hover 有，键盘聚焦播放钮时没有，
     白色播放钮落在浅色封面上对比度就没有保障。用 :focus-within 而不是 :focus-visible，
     因为可聚焦的是里面的 .play 按钮，不是卡片本身。 */
  .video-card:hover .video-card__img,
  .video-card:focus-within .video-card__img { filter: brightness(.86); }
}
@media (hover: none) {
  .play {
    position: absolute; left: var(--sp-3); bottom: var(--sp-3);
    width: 34px; height: 34px;
  }
  .play svg { width: 15px; height: 15px; }
}

.video-card__dur {
  position: absolute; z-index: 1; right: var(--sp-3); bottom: var(--sp-3);
  padding: var(--sp-1) var(--sp-2); border-radius: var(--r-sm);
  background: rgba(0,0,0,.62); color: #fff;
  font-size: 0.812rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.video-card__body { padding: var(--sp-5); display: flex; flex-direction: column; flex: 1; }
/* v47：标题/描述收敛行数（对齐 YouTube / B站 / Behance 卡片规范）——
   长标题不 clamp 会让同一行卡片文字块高低不一、扫描时"参差"。
   标题 2 行、描述 2 行，超出省略；卡片高度由网格 + meta 底对齐兜住。 */
.video-card__title {
  font-size: 1.25rem; font-weight: 700; line-height: 1.3; letter-spacing: -.02em; color: var(--ink);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
.video-card__desc {
  margin-top: var(--sp-2); font-size: 0.938rem; color: var(--ink-3);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
.video-card__meta { display: flex; align-items: center; gap: var(--sp-2); margin-top: auto; padding-top: var(--sp-4); }

/* ---------- 6b. 空状态（集合为空 / 筛选无结果）----------
   苹果式空态：不铺灰块、不画虚线框 —— 只用一枚弱化图标 + 中性文字 + 一句引导，
   由留白承担「空」的表达，读成「还没内容」而不是「页面坏了」。
   组件内填充色只一种（图标圆底用 --surface），遵守「一个组件最多一种填充」。 */
.empty { padding: var(--sp-9) var(--sp-5); text-align: center; }
.empty__icon {
  display: grid; place-items: center; width: 56px; height: 56px;
  margin: 0 auto var(--sp-4); border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink-3);
}
.empty__title { font-size: 1.062rem; font-weight: 700; color: var(--ink); }
.empty__hint { margin-top: var(--sp-2); font-size: 0.938rem; color: var(--ink-3); }

/* ---------- 7. 关于 ---------- */
.about-grid { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
.about-grid > div:last-child { max-width: 760px; }   /* 行宽 ≈40 中文字/行 */
.profile {
  border-radius: var(--r-md); padding: var(--sp-6); text-align: center;
  /* v44：全站卡片（.post / .video-card / .recent__row）都已是液态光玻璃，
     .profile 是最后一块不透明实心卡 → 同一页里材质不统一。改用同一配方。 */
  background: color-mix(in srgb, var(--card) var(--glass-a), transparent);
  -webkit-backdrop-filter: blur(18px) saturate(168%); backdrop-filter: blur(18px) saturate(168%);
  border: 1px solid color-mix(in srgb, #000 7%, transparent);
  box-shadow:var(--sh-glass), var(--sh-1);
}
.avatar {
  width: 112px; height: 112px; margin: 0 auto var(--sp-5);
  border-radius: var(--r-md); background: var(--surface);
  display: grid; place-items: center;
  font-family: var(--font-serif); font-size: 2.5rem; font-weight: 600; color: var(--ink);   /* 40px ≥28px → 600（大标题光学降重，全站唯一漏网的 700） */
}

/* ---------- 关于我：结构化简历版（v74 · 2026-10-07）----------
   从「三段 bio + 若干卡片」改为「左身份 / 右条目」的简历式版式：
   段落被拆成可扫读的短句（左竖线）与条目（时间 + 机构 + 要点），
   经历 / 教育 / 论文**共用 .entry 组件**，视觉节奏一致。
   全页只铺 1px 发丝线、不再铺卡片底色 —— 守住「一个组件一种填充色」。 */
.about-head { margin-bottom: var(--sp-7); }
.about-grid { grid-template-columns: 340px minmax(0, 1fr); gap: var(--sp-9); align-items: start; }

/* 左栏：脱掉玻璃卡片底色，回到纯排版 */
.profile { background: none; border: none; box-shadow: none; padding: 0; text-align: left; }
.profile__photo {
  display: block; width: 100%; height: auto; aspect-ratio: 3 / 4;
  object-fit: cover; border-radius: var(--r-md);   /* v78：原为唯一的非 token 值 12px */
  border: 1px solid var(--hairline); margin: 0 0 var(--sp-5);
}
.profile__name { font-size: 1.875rem; font-weight: 600; letter-spacing: .18em; color: var(--ink); line-height: 1.2;
  animation: aiNameGlow 5s var(--ease-breathe) infinite; }
/* v84·sections：关于页的点睛 —— 这页没有筛选条，把 AI 光落在"李锐"这个名字上（与页标题/李锐柔光同族）；
   蓝+一缕紫、极低不透明、5s 呼吸。名字字距大(.18em)，用 text-shadow 让每个字各自发光，不糊成一团。 */
@keyframes aiNameGlow {
  0%, 100% { text-shadow: 0 0 22px rgba(var(--ac-rgb),.08), 0 0 38px rgba(var(--ai-2-rgb),.06); }
  50%      { text-shadow: 0 0 28px rgba(var(--ac-rgb),.20), 0 0 46px rgba(var(--ai-2-rgb),.13); }
}
/* v84·sections：减动态下关掉这三处柔光呼吸（页标题 / 名字 / 选中筛选），文字本身不受影响 */
@media (prefers-reduced-motion: reduce) {
  .page-title, .profile__name { animation: none; }
}
.profile__role { font-size: 0.938rem; color: var(--ink-2); margin-top: var(--sp-2); }
/* MBTI：跟在职位后的小胶囊 —— 只描边不填充，避免左栏多出第二块底色
   v80-④：从业年数沿用**同一个胶囊**（同一套语言、不新造组件），把 data.js 里
   一直没被引用的 SITE.years / yearsLabel 用起来。 */
.profile__mbti, .profile__years {
  display: inline-block; margin-left: var(--sp-2); vertical-align: 2px;
  padding: 2px 8px; border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  font-size: 0.812rem; font-weight: 500; letter-spacing: .08em; color: var(--ink-2);
}
.profile__facts { margin-top: var(--sp-5); }
/* iOS 设置式联系行（2026-10-15）：原来邮箱/微博是「裸链接文字」，用户不知道能点。
   现在：可点击的行 = 值变链接蓝 + 右侧 chevron 指示器 + hover 行底 wash + chevron 微移；
   不可点的行（微信）保持 plain 灰字无指示器 —— 两类一眼可分。 */
.fact {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  font-size: 0.938rem; color: var(--ink-2);
  transition: background var(--dur-fast) var(--ease);
}
.fact:last-child { border-bottom: none; }
.fact__k { flex: none; width: 3.5em; color: var(--ink-3); }
.fact__v { min-width: 0; overflow-wrap: anywhere; }
/* 可点击行的值 = 链接蓝（iOS 设置同款语义；--link 在白底 4.69:1 / 深底 5.48:1，均达 AA） */
a.fact .fact__v { color: var(--link); }
a.fact .fact__chev {
  margin-left: auto; flex: none;
  display: grid; place-items: center;
  width: 18px; height: 18px;
  color: var(--ink-3);
  transition: transform var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
a.fact .fact__chev svg { width: 13px; height: 13px; display: block; }
@media (hover:hover) and (pointer:fine) {
  a.fact:hover { background: var(--hover-row); }
  a.fact:hover .fact__v { color: var(--accent-ink); }        /* hover 蓝深一档，反馈明确 */
  a.fact:hover .fact__chev { color: var(--ink-2); transform: translateX(2px); }
}
a.fact:active { background: var(--hover-row); }
/* 键盘焦点走全局 :focus-visible（2px accent 圈 + 自动跟随圆角） */

/* 右栏顶部一句话定位：一条左竖线 + 比条目大一档，作为整页「题眼」。
   原三句与首页 headline 重复，已合并为一句 —— 宁可留白，也不重复。 */
.about-statement {
  border-left: 2px solid var(--accent); padding-left: var(--sp-4);
  font-size: 1.25rem; line-height: 1.7; font-weight: 500;
  letter-spacing: -.01em; color: var(--ink); max-width: 30em;
}

/* 区块标题：中文宽字距 + 英文小字，下方一条发丝线 */
.block { margin-top: var(--sp-8); }
.block__title {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding-bottom: var(--sp-3); margin-bottom: var(--sp-2);
  border-bottom: 1px solid var(--hairline);
}
.block__zh { font-size: 0.938rem; font-weight: 700; letter-spacing: .22em; color: var(--ink); }
.block__en { font-size: 0.812rem; letter-spacing: .1em; color: var(--ink-3); }

/* 条目行：左时间（等宽数字）+ 右内容；条目间发丝线 */
.entry {
  display: grid; grid-template-columns: 128px minmax(0, 1fr); gap: var(--sp-4);
  padding: var(--sp-5) 0; border-bottom: 1px solid var(--hairline);
}
.entry:last-child { border-bottom: none; }
.entry__period { font-size: 0.938rem; color: var(--ink-3); font-variant-numeric: tabular-nums; padding-top: 2px; }
.entry__org { font-size: 1.062rem; font-weight: 700; color: var(--ink); line-height: 1.4; }
.entry__unit { font-size: 0.938rem; color: var(--ink-2); margin-top: 3px; }
.entry__points { margin-top: var(--sp-3); }
.entry__points li {
  list-style: none; font-size: 0.938rem; line-height: 1.7; color: var(--ink-2);
  padding-left: var(--sp-4); border-left: 1px solid var(--line-strong);
}
.entry__points li + li { margin-top: var(--sp-2); }
.entry__link {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: var(--sp-3); font-size: 0.938rem; color: var(--accent-ink);
}
.entry__link:hover { text-decoration: underline; }
/* 移动端触控（③）：实测 246×24 < 44pt。它已 inline-flex + align-items:center，
   移动端补 min-height 即可；独占一行（有 margin-top），不会挤动相邻排版。 */
@media (max-width: 640px) {
  .entry__link { min-height: 46px; }   /* 46 而非 44：inline-flex 下实测 44 会量到 43（取整差 1px） */
}
/* 公众号二维码：只描边不填充，与联系方式同处左栏；白底是扫码必需，不视作第二块「填充色」 */
.profile__qr {
  display: flex; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-5); padding: var(--sp-4);
  border: 1px solid var(--hairline); border-radius: var(--r-md);
}
.profile__qr img {
  flex: none; display: block; width: 100px; height: 100px;
  border-radius: var(--r-sm); background: #fff;
}
.profile__qr-cap { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.profile__qr-k { font-size: 0.812rem; color: var(--ink-3); letter-spacing: .06em; }
.profile__qr-v { font-size: 0.938rem; font-weight: 500; color: var(--ink); }
.profile__qr-hint { font-size: 0.812rem; color: var(--ink-3); margin-top: 2px; }

.profile__cta { margin-top: var(--sp-5); }
.profile__cta .btn { width: 100%; justify-content: center; }

/* 窄屏：时间列不再并排，改为堆叠 */
@media (max-width: 720px) {
  .entry { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
  .entry__period { padding-top: 0; }
  .about-statement { font-size: 1.125rem; }
}

.skill-cloud { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.skill {
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-pill);
  background: none; border: 1px solid var(--line-strong);
  font-size: 0.938rem; color: var(--ink-2);
}

/* ---------- 8. 文章阅读页 ---------- */
.article { padding: calc(var(--nav-h) + var(--sp-5)) 0 var(--sp-9); overflow-x: clip; }
.article > .wrap:not(.article__layout) { max-width: 824px; }   /* 阅读版心：824-64=760 正文（v55 对齐规范） */

/* v80-①：文章头随滚动做一次极轻的「阻尼上移 + 淡出」——这是苹果官网「把滚动位置当时间轴」
   的连续量（不是一次性淡入）。幅度刻意压到「感觉得到但说不出」：最大 22px、最低透明度 .72。
   位移由滚动直接驱动故**不设 transform 过渡**（设了会迟滞、跟手变拖沓）；
   opacity 只给一个极短的线性过渡抹掉阶梯感。reduced-motion 下整体失效。 */
.article__head {
  max-width: 760px;
  transform: translateY(var(--head-y, 0px));
  opacity: var(--head-o, 1);
  transition: opacity .1s linear;
}
@media (prefers-reduced-motion: reduce) {
  .article__head { transform: none !important; opacity: 1 !important; }
}
.article__title { font-size: 2.5rem; font-weight: 600; line-height: 1.25; letter-spacing: -.02em; }
/* 一行内联元信息：标签 chip + 日期 · 时长 · 作者 · 规模（纯文字，无卡片框）。
   关键：用「行内流 + nowrap 单元」而不是 flex —— 每一项连同其后的间隔点是一个不可断开的
   整体，窄屏换行时间隔点永远紧跟上一项，不会孤立落到行首（曾出现「· 规模…」行首多余圆点）。 */
.article__byline {
  margin-top: var(--sp-5); font-size: 0.938rem; line-height: 1.9;   /* v60：详情页去掉导语后，标题→元信息 由 16px 提到 24px（标题 40px，16px 偏挤） */
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.article__byline__item { display: inline; white-space: nowrap; }
.article__byline__item:not(:last-child)::after {
  content: "·"; margin: 0 var(--sp-3); opacity: .5;
}
.article__advice { margin-top: var(--sp-3); font-size: 0.938rem; line-height: 1.7; color: var(--ink-3); }
.article__body { max-width: 760px; margin-top: var(--sp-7); }
.article__body p { font-size: 1.125rem; line-height: 1.7; color: var(--ink); }          /* 苹果长文正文＝近黑(非灰) + 行高 1.7；灰字(--ink-2)读着发闷、欠 crisp */
.article__body p + p { margin-top: var(--sp-5); }
/* 深底上强调色要提亮，避免发闷（深色五纪律之一） */
[data-theme="dark"] .article__body h3 { border-left-color: var(--link); }
.article__foot { margin-top: var(--sp-8); padding-top: var(--sp-6); border-top: 1px solid var(--hairline); }

/* 阅读页（文章视图）：中性背景 + 隐藏全站彩虹极光，保证阅读聚焦。
   通用规则：所有文章视图都由 <body>.is-article 启用（render() 在文章路由切换）。
   配色纪律 = 中性底（白 / --surface）+ 单一强调色 --accent（链接 / TOC 高亮 /
   h3 与引用左边框）+ 灰阶文字（--ink / --ink-2 / --ink-3），不引入第二种彩色。 */
body.is-article { background: var(--card); }
[data-theme="dark"] body.is-article { background: var(--surface); }
body.is-article .aurora { animation: none; opacity: 0; transition: opacity var(--dur-slow) var(--ease); }
/* 阅读页导航：不改为不透明顶栏（用户否决）。改用「滚动感知显隐」——
   往下读时导航上滑让位、往上滚或指针移到顶部时再现（苹果 Safari 式），
   既最大化阅读空间，又随时可达（导航始终在，只是需要时才出现）。规则见 .nav.is-hidden 与 app.js。 */

/* ---------- 9. 视频弹窗 ---------- */
.modal {
  position: fixed; inset: 0; z-index: 110;
  display: none; place-items: center; padding: var(--sp-5);
}
.modal.is-open { display: grid; }
.modal__mask {
  position: absolute; inset: 0; background: rgba(0,0,0,.42);
  animation: fadeIn var(--dur-slow) var(--ease) both;
}
@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
.modal__panel {
  position: relative; width: min(880px, 100%);
  /* v29：浮层 = Apple Liquid Glass 的正当使用场景（controls/浮起物），原实心白底少了材质语言。
     86% 不透明 + 背景模糊：能透出被压暗的背景（iOS sheet 观感），同时保住文字对比度。 */
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 22%), transparent);
  -webkit-backdrop-filter: blur(26px) saturate(170%); backdrop-filter: blur(26px) saturate(170%);
  border-radius: var(--r-md);
  border: 1px solid color-mix(in srgb, #000 8%, transparent);
  box-shadow: var(--sh-pop); overflow: hidden;
  animation: popIn var(--dur-slow) var(--ease) both;
}
@keyframes popIn { from { opacity: 0; transform: translateY(12px) scale(.98) } to { opacity: 1; transform: none } }
[data-theme="dark"] .modal__panel {
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 18%), transparent);
  border-color: color-mix(in srgb, #fff 12%, transparent);
}
.modal__close { position: absolute; top: var(--sp-3); right: var(--sp-3); z-index: 2; background: rgba(255,255,255,.9); color: #1d1d1f; }
.modal__stage {
  position: relative; aspect-ratio: 16/9; display: grid; place-items: center;
  background: var(--t, var(--surface)); text-align: center; padding: var(--sp-5);
}
.modal__stage > * { position: relative; z-index: 1; }
[data-theme="dark"] .modal__stage { background: var(--surface); }   /* 深色下不用示例色块，保证文字可读 */
.modal__stage p { font-size: 0.938rem; color: var(--ink-3); margin-top: var(--sp-3); }

/* 视频弹窗渲染修复（v59c）：panel 的 backdrop-filter（毛玻璃）+ 内部正在播放的 <video>
   会触发浏览器合成器周期性重算 → 视频上出现「规律性黑影抖动/黑闪」（已知渲染行为；</video>
   自身 background:#000，一抖即露黑）。播放本地视频时：
   ① 去掉 panel 的 backdrop-filter 并改实底；② 舞台去掉内边距，让 16:9 视频满铺、
   消除 object-fit:contain 的黑色信箱边；③ 暂停全屏极光呼吸动画（弹窗背后的周期性明暗源）。 */
body.modal-open .aurora { animation: none; }
.modal.has-video .modal__panel { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--card); }
[data-theme="dark"] .modal.has-video .modal__panel { background: var(--surface); }
.modal.has-video .modal__stage { padding: 0; }
.modal__body { padding: var(--sp-6); }
/* 视频灯箱元素（v85·清理：原内联 style 抽到 class，遵守「禁内联写尺寸/间距」纪律） */
.lightbox__video { width: 100%; height: 100%; object-fit: contain; background: #0b0b0c; }
.lightbox__frame { width: 100%; height: 100%; border: 0; }
.play--static { position: static; }
.modal__title { font-size: 1.5rem; font-weight: 700; line-height: 1.3; letter-spacing: -.02em; }
.modal__desc { margin-top: var(--sp-3); color: var(--ink-3); font-size: 1rem; }
.modal__meta { display: flex; gap: var(--sp-3); margin-top: var(--sp-4); font-size: 0.938rem; color: var(--ink-3); }

/* ---------- 10. 页脚 ---------- */
.footer { position: relative; z-index: 1; border-top: 1px solid var(--hairline); padding: var(--sp-7) 0 var(--sp-8); background: color-mix(in srgb, var(--surface) calc(var(--glass-a) - 4%), transparent); }
.footer__inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.footer__note { font-size: 0.938rem; color: var(--ink-3); }
.footer__links { display: flex; gap: var(--sp-5); font-size: 0.938rem; }
/* v32 修复（真 bug）：页脚导航此前没有任何 hover / :active 规则，且因全局 a{color:var(--link)}
   被染成强调蓝 —— 既「点了没反应」又与克制的页脚基调不搭。改为与顶部导航同款语汇：
   灰(--ink-3) → 深(--ink)，按压回弹。 */
.footer__links a {
  color: var(--ink-3);
  transition: color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
@media (hover:hover) and (pointer:fine) {
  .footer__links a:hover { color: var(--ink); }
}
.footer__links a:active { transform: scale(var(--active-scale)); }

/* ---------- 10b. 作品卡 / 通用两列卡片网格 ---------- */
.card-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-6); }
/* v60b：2 列网格仅 1 项时**不做居中**（用户反馈「强行居中不好看」）——
   单条按栅格首列自然左对齐，与上方 chips / 标题左边缘对齐，保持列表节奏，留白交给栅格本身。 */
.stack-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.stack {
  padding: var(--sp-1) var(--sp-3); border-radius: var(--r-pill);
  background: none; border: 1px solid var(--line-strong);
  font-size: 0.812rem; font-weight: 500; color: var(--ink-3);
}
.work-card__cta {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--sp-1);
  /* v78：700 → 500。v37 已把卡片 CTA 定为 UI 档 500（.post__more 同），此处一致化。 */
  font-size: 0.938rem; font-weight: 500; color: var(--link);
}
/* 同一个圆角圆形标记，换图标表达「外链」或「还没接进来」，保持视觉语言统一 */
.play.is-off { background: rgba(255,255,255,.62); color: var(--ink-3); }
[data-theme="dark"] .play.is-off { background: var(--line-strong); color: var(--ink-2); }
.video-card.is-muted { cursor: default; }
@media (hover:hover) and (pointer:fine) {
  .video-card.is-muted.reveal:hover { border-color: var(--line); box-shadow: none; transform: none; }
}

.video-card.is-muted .work-card__cta { color: var(--ink-3); }

/* ---------- 10b-2. 相册（生活）----------
   多列瀑布流：照片纵横比不一（竖构图为主），用 CSS 多列天然保比例、不裁切，
   比等高网格更尊重原图构图。圆角取 --r-md，与正文配图 / 卡片同一档。 */
.album-grid { columns: 3; column-gap: var(--sp-4); }
.album-shot { break-inside: avoid; margin: 0 0 var(--sp-4); }
.album-shot__img {
  display: block; width: 100%; height: auto; cursor: zoom-in;
  border-radius: var(--r-md);
  /* ⚠ 占位底色调 --bg-subtle 而非旧的 --thumb —— --thumb 从未定义，图未加载时没有底色、会闪白。 */
  background: var(--bg-subtle, #f0f0f2);
  /* 一道发丝描边：白底照片坐在白页面上会「没有边」，加上它与肖像图同一处理 */
  border: 1px solid var(--hairline);
  transition: filter var(--dur-base) var(--ease), transform var(--dur-base) var(--ease),
              opacity var(--dur-base) var(--ease);
}
/* 照片入场：只做「上浮 + 渐显」，不带 scale —— 缩放会让照片在过渡中轻微发虚（0,2,0 覆盖 .reveal）。 */
.album-shot.reveal { transform: translateY(18px); }
/* 图片淡入：is-pending 由 JS 打上/移除（同正文图 v65 的做法）——
   CSS 不默认 opacity:0，万一 JS 没跑起来，图片也必须正常可见、不能白屏。 */
.album-shot__img.is-pending { opacity: 0; }
@media (hover:hover) and (pointer:fine) {
  .album-shot:hover .album-shot__img { filter: brightness(.93); transform: translateY(-3px); }
}
/* v80-⑤：键盘可达的焦点镜像 —— hover 的视觉反馈必须有一条 focus 版，
   否则键盘用户「聚焦到了但看不出来」。焦点环比全局值外扩 1px（压在照片上更清楚）。 */
.album-shot:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.album-shot:focus-visible .album-shot__img { filter: brightness(.93); transform: translateY(-3px); }
.article__body img[role="button"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* 网格里不显示说明文字：视觉隐藏（仍可被读屏读到，也给灯箱供文案） */
.album-shot__cap {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
@media (max-width: 1024px) { .album-grid { columns: 2; } }

/* ---------- 10b-3. 首页相册（统一方形网格 · Apple Photos 式）----------
   首页不像「相册页」那样要保留原图比例：这里改用等高方形网格，
   object-fit:cover 把竖图/横图统一裁切进同形状框里，消除瀑布流的参差与空档，
   秩序感、克制留白 = 苹果风。悬停时框内轻微放大 + 抬升 + 双层阴影。 */
.album-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
}
.album-tiles .album-shot {
  position: relative; margin: 0;
  aspect-ratio: 1 / 1;                 /* 统一方形：每行等高、无参差 */
  overflow: hidden;                    /* 框内缩放不溢出圆角 */
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);   /* 白底照片坐在白页面上的发丝边 */
  background: var(--bg-subtle, #f0f0f2);
  transition: opacity var(--dur-base) var(--ease),
              transform var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.album-tiles .album-shot__img {
  display: block; width: 100%; height: 100%;
  border: 0; border-radius: 0; background: transparent;
  object-fit: cover;                   /* 关键：等比裁切填满，框形一致 */
  cursor: zoom-in;
  transition: transform var(--dur-slow) var(--ease);
}
.album-tiles .album-shot__cap {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
@media (hover:hover) and (pointer:fine) {
  .album-tiles .album-shot:hover { transform: translateY(-4px); box-shadow: var(--sh-2); }
  .album-tiles .album-shot:hover .album-shot__img { transform: scale(1.05); }
  /* v80-⑤：同上，首页相册瓦片的 hover 抬起也要有焦点镜像 */
  .album-tiles .album-shot:focus-visible { transform: translateY(-4px); box-shadow: var(--sh-2); }
  .album-tiles .album-shot:focus-visible .album-shot__img { transform: scale(1.05); }
}

/* ── 内容卡「呼吸」：极缓错峰浮动（生命感 · 上线前检查 ①）────────────────
   此前文章/作品/相册卡只有 hover 反馈，静置时是「死」的；首屏是生命感最该出现的地方。
   ⚠ 必须动**独立的 translate 属性**，绝不能动 transform：这些卡片本身用 transform 做
     hover 上浮（translateY(-4px)）、:active 按压（scale）、.reveal 入场 —— 动 transform
     会互相覆盖（与阅读气泡 rbBob 同一条教训）。translate 与 transform 天然叠加。
   ⚠ 只在 prefers-reduced-motion: no-preference 下挂载（遵循全站减动态约定；
     headless 默认 reduce，量动效须手动 emulate no-preference 才看得到）。
   ⚠ 幅度 ≤2px、周期 7s：是「呼吸」不是「抖动」，刻意不抢戏。 */
@keyframes cardBreathe {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -2px; }
}
@media (prefers-reduced-motion: no-preference) {
  .recent__row, .album-tiles .album-shot { animation: cardBreathe 7s var(--ease-breathe) infinite; }
  /* 错峰：负延迟让它们一上来就处在不同相位，避免整齐划一地「齐步走」 */
  .recent__row:nth-child(2) { animation-delay: -2.3s; }
  .recent__row:nth-child(3) { animation-delay: -4.6s; }
  .album-tiles .album-shot:nth-child(3n+2) { animation-delay: -2.1s; }
  .album-tiles .album-shot:nth-child(3n)   { animation-delay: -4.2s; }
}
@media (max-width: 1024px) {
  .album-tiles { grid-template-columns: repeat(2, 1fr); }
  /* 移动/平板只留前 6 张 → 干净的 2×3，不出现落单的第 7 张 */
  .album-tiles .album-shot:nth-child(n+7) { display: none; }
}

/* ---------- 10c. 最近更新（首页自动聚合）---------- */
.recent-list { display: grid; gap: var(--sp-2); }
.recent__row {
  display: grid; grid-template-columns: 72px minmax(0, 1fr) auto;
  align-items: center; gap: var(--sp-4); width: 100%; text-align: left;
  padding: var(--sp-4) var(--sp-5); border-radius: var(--r-md);
  /* v41：内容卡升级为「液态光玻璃」——半透明卡面 + 背景模糊饱和，折射彩虹极光，
     与导航/浮层/次级按钮同一材质语言；发丝描边 + 接触影给出边界与轻浮起（静止态也有层级）。 */
  background: color-mix(in srgb, var(--card) var(--glass-a), transparent);
  -webkit-backdrop-filter: blur(18px) saturate(168%);
  backdrop-filter: blur(18px) saturate(168%);
  border: 1px solid color-mix(in srgb, #000 7%, transparent);
  box-shadow:var(--sh-glass), var(--sh-1);
  transition: border-color var(--dur-base) var(--ease),
              transform var(--dur-fast) var(--ease), box-shadow var(--dur-base) var(--ease);
}
@media (hover:hover) and (pointer:fine) {
  /* v31：行 hover 三件套 —— 半透明 wash(--hover-row ~3.2%) + 边框加重 + 1px 抬起 + 微影。
     历史：v29 用不透明灰铺满 → 读成「被选中」；v30 改墨色混合底；v31 统一为半透明 wash（同时避免「实心块」廉价感）。 */
  .recent__row.reveal:hover {
    /* v41：wash 改为「叠加」在玻璃卡面之上（background-image 层），
       不再整体替换 background-color —— 否则 hover 时卡面连同玻璃一起消失，只剩一层灰。 */
    background-image: linear-gradient(var(--hover-row), var(--hover-row));
    border-color: var(--line-strong);
    transform: translateY(-1px);
    box-shadow: var(--sh-1);
  }
}

.recent__row:active { transform: scale(var(--active-scale)); }
.recent__type { display: inline-flex; align-items: center; gap: 2px; font-size: 0.812rem; font-weight: 700; color: var(--ink-3); }
.recent__title {
  font-size: 1rem; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.recent__date { font-size: 0.938rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
  /* v15：原 opacity:.7 让类型/日期只有 2.82:1 —— 信息读不清。
     改为不降整体透明度；「这一条点不开」的信号交给标题降一档灰度 + cursor:default，两者都仍过 AA。 */
.recent__row.is-muted { cursor: default; }
.recent__row.is-muted .recent__title { color: var(--ink-2); }
/* v41 深色：玻璃卡改用「表面色亮一档 + 描边」表达层级（深底阴影无效），
   hover 用卡面提亮 + 描边加重给出反馈（深色下 --sh-1/--sh-2 均为 none，光靠位移不够）。 */
[data-theme="dark"] .post,
[data-theme="dark"] .video-card,
[data-theme="dark"] .recent__row,
[data-theme="dark"] .profile {
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 8%), transparent);
  border-color: color-mix(in srgb, #fff 12%, transparent);
  box-shadow:var(--sh-glass);
}
@media (hover:hover) and (pointer:fine) {
  [data-theme="dark"] .post:hover,
  [data-theme="dark"] .video-card:hover,
  [data-theme="dark"] .recent__row:hover {
    background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 20%), transparent);
    border-color: color-mix(in srgb, #fff 20%, transparent);
  }
}
@media (hover:hover) and (pointer:fine) {
  .recent__row.is-muted:hover { border-color: var(--line); }
}

.recent__row.is-muted:active { transform: none; }
/* 下滑引导：与下方 section 头（eyebrow + h2）是不同语义 → 用 24px 明确分区。
   字号/灰度/字距都刻意弱一档，避免与 eyebrow 两个小标签互相打架（原 8px 太近、13px/6px 非尺度值）。 */
.recent__cue {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-6);              /* 与下方 section 头拉开一整档（组间疏） */
  font-size: 0.938rem; letter-spacing: .02em; color: var(--ink-3);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
/* 交互细节：下滑后引导语使命已完成 → 淡出退场（回到顶部再淡入）；≤300ms，尊重减弱动态 */
.recent__cue.is-hidden { opacity: 0; transform: translateY(-6px); pointer-events: none; }
.recent__cue svg { animation: cueBreathe 2.6s var(--ease-breathe) infinite; }
/* v25 M4：原 1.8s「弹跳」改 2.6s 呼吸脉冲（Apple：弹跳/转体/闪光属廉价感黑名单；
   位移收到 3px、只做很轻的上下浮动 + 淡入，保留「引导下滑」这一合法动效目的） */
@keyframes cueBreathe {
  0%, 100% { transform: translateY(0);    opacity: .5;  }
  50%      { transform: translateY(3px);  opacity: .85; }
}
@media (prefers-reduced-motion: reduce) { .recent__cue svg { animation: none; } }

/* ---------- 10d. 移动端底部 Tab（≤640px 接管导航）---------- */
.tabbar { display: none; }
.tabbar__defs { position: absolute; width: 0; height: 0; overflow: hidden; }   /* v84 图标渐变 defs，不占布局 */

/* ---------- 10e. 玻璃材质 · 手迹（液态光语言）---------- */
/* 玻璃 = 半透明 + 背景模糊 + 顶部高光描边（用光与材质做层级，不用重阴影/描边）。
   只给「浮起/承载内容」的大卡与悬浮 chrome 用，列表行保持干净分隔。 */
/* ---------- 环境极光：生命感，也是玻璃要折射的东西 ----------
   v3（2026-10-15）：用户二次校准——「不要太喧宾夺主，要苹果感高级感，要绚烂好看，
   但别太强烈影响阅读视线」（参考千问登录页：暖金→绿→蓝的流动光带很美，但他们做得有点过）。
   → 结论：绚烂靠**形态与暖冷过渡**，不靠浓度。光集中在视口上部（hero 区），
     下半部只留极弱边缘微光——文字区永远落在近净底上。
   ① 浓度全面下调（v2 的 30% → 23% 蓝），主光核心**移出 hero 大标题**（推到左上外侧），
      标题落在近白底上；构图「上重下轻」：内容区（RECENT/列表/正文）干净，不影响阅读视线。
   ② 有机形态：光团改椭圆 + 各自带基础旋转 + 动画内 ±3° 缓旋 —— 学千问的流动感，
      但幅度克制（他们是半个屏的浓艳光带，我们是一层氛围）。
   ③ 新增一味**暖金**（--au-5，::before 伪元素，不动 HTML）：暖金与蓝在顶部相接，
      出「绚烂」的那一度；低浓度（9%），只作过渡不作主角。
   ④ 其余继承 v2：color-mix 融边 / farthest-side 渐变自柔化（无 filter:blur）/
      质数周期呼吸 / 3.8% 胶片颗粒 / 阅读页 is-article 整体隐去。 */
.aurora { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; animation: auroraBreath 4s ease-in-out infinite; }
.aurora i { position: absolute; display: block; border-radius: 50%; will-change: transform, opacity; }
/* 三色停 = 光芯 + 半透明过渡 + 融边；柔化全靠渐变自身，不靠模糊。
   ★ farthest-side（半径取长半轴）比 closest-side 铺展宽 ~56% —— 弥补去掉 blur 后
     「光摊不开」的问题。旋转烘进 keyframes（各团基础角不同 → 有机错落）。 */
.aurora .b1 { width: 58vw; height: 37vw; left: -19%; top: -26%;
  background: radial-gradient(farthest-side, var(--au-1) 0%, color-mix(in srgb, var(--au-1) 52%, transparent) 46%, transparent 78%);
  animation: auroraSheen1 23s var(--ease-breathe) -7s infinite; }
.aurora .b2 { width: 56vw; height: 35vw; right: -11%; top: -4%;
  background: radial-gradient(farthest-side, var(--au-2) 0%, color-mix(in srgb, var(--au-2) 52%, transparent) 46%, transparent 78%);
  animation: auroraSheen2 31s var(--ease-breathe) -14s infinite; }
.aurora .b3 { width: 42vw; height: 24vw; left: -16%; bottom: -4%;
  background: radial-gradient(farthest-side, var(--au-3) 0%, color-mix(in srgb, var(--au-3) 52%, transparent) 46%, transparent 78%);
  animation: auroraSheen3 37s var(--ease-breathe) -3s infinite; }
.aurora .b4 { width: 38vw; height: 22vw; right: -12%; bottom: -2%;
  background: radial-gradient(farthest-side, var(--au-4) 0%, color-mix(in srgb, var(--au-4) 52%, transparent) 46%, transparent 78%);
  animation: auroraSheen4 43s var(--ease-breathe) -21s infinite; }
/* 暖金（伪元素，不占 HTML）：顶部与靛相接，暖冷过渡出「绚烂」；低浓度只作过渡。
   位置刻意落在 hero 右侧空白带（文字全部左对齐，x>800 无内容）—— 绚烂不碰视线 */
.aurora::before { content: ''; position: absolute; display: block; width: 42vw; height: 23vw; right: 4%; top: -6%; border-radius: 50%;
  background: radial-gradient(farthest-side, var(--au-5) 0%, color-mix(in srgb, var(--au-5) 52%, transparent) 46%, transparent 78%);
  animation: auroraSheen2 29s var(--ease-breathe) -11s infinite; }
@keyframes auroraSheen1 { 0%,100% { transform: rotate(-13deg) scale(1); opacity: .85 } 50% { transform: rotate(-10.5deg) scale(1.05); opacity: 1 } }
@keyframes auroraSheen2 { 0%,100% { transform: rotate(11deg) scale(1.02); opacity: .88 } 50% { transform: rotate(13.5deg) scale(1.07); opacity: 1 } }
@keyframes auroraSheen3 { 0%,100% { transform: rotate(-6deg) scale(1); opacity: .8 } 50% { transform: rotate(-4deg) scale(1.04); opacity: .95 } }
@keyframes auroraSheen4 { 0%,100% { transform: rotate(8deg) scale(1.01); opacity: .85 } 50% { transform: rotate(10.5deg) scale(1.06); opacity: 1 } }
@keyframes auroraBreath { 0%,100% { opacity: .92; } 50% { opacity: 1; } }   /* v11 起：与首屏呼吸蓝点同步，整片极光轻轻被点亮 */
/* 胶片颗粒：消渐变色带 + 「设计过」的质感。.038 肉眼几乎不可见，但没有它会「塑料」 */
.aurora::after { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .038;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E"); }
/* 移动端：小屏光被冲淡 → 顶部三团放大（浓度已由深色 token 独立给过，这里只调尺度）；
   底部两团压得更弱更靠外 —— 手机上内容区更窄，更不能让光碰到阅读视线 */
@media (max-width:640px){
  .aurora .b1{width:104vw;height:54vw;left:-34%;top:-20%;}
  .aurora .b2{width:88vw;height:44vw;right:-26%;top:-8%;}
  .aurora .b3{width:76vw;height:36vw;left:-24%;bottom:0%;}
  .aurora .b4{width:68vw;height:32vw;right:-20%;bottom:2%;}
  .aurora::before{width:62vw;height:30vw;right:2%;top:-10%;}
  .live__bloom{width:min(150vw,680px);height:min(150vw,680px);margin:calc(min(150vw,680px)/-2) 0 0 calc(min(150vw,680px)/-2);animation:liveBloomM 4s var(--ease-breathe) infinite;}
}
/* v41：此前 .aurora .bN（0,0,2,0）特异性高于 .aurora i（0,0,1,1），reduce 规则被压过 →
   减弱动态下极光仍在漂移；且 .aurora 自身动画在 735 行、晚于 375 行的 reduce 规则。
   此处用同级/更高特异性 + 更靠后的位置，确保真正关掉。 */
@media (prefers-reduced-motion: reduce) {
  .aurora, .aurora i, .aurora .b1, .aurora .b2, .aurora .b3, .aurora .b4, .aurora::before { animation: none; }
}

/* ---------- 玻璃材质：可复用的一个类 ---------- */
.glass {
  background:
    /* v28：镜面高光移交给 .glass::after（可呼吸），见下方 */
    radial-gradient(135% 100% at 12% 0%, rgba(var(--ac-rgb), .11), transparent 58%),
    color-mix(in srgb, var(--card) calc(var(--glass-a) - 9%), transparent);
  -webkit-backdrop-filter: blur(30px) saturate(185%);
  backdrop-filter: blur(30px) saturate(185%);
  border: 1px solid color-mix(in srgb, #000 6%, transparent);
  box-shadow:var(--sh-glass-lg);
  border-radius: var(--r-glass);
  isolation: isolate;   /* v28：让 ::after 的 z-index:-1 只在本元素内生效（背景之上、内容之下） */
}
/* v28 玻璃呼吸：镜面高光做极缓明暗呼吸（9s），赋予玻璃「生命感」。
   z-index:-1 + isolation:isolate → 高光压在玻璃底色之上、文字之下，不遮挡导航内容。 */
.glass::after {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  background: linear-gradient(135deg, rgba(255,255,255,.55), rgba(255,255,255,.12) 34%, transparent 62%);
  animation: glassSheen 9s var(--ease-breathe) infinite;
}
@keyframes glassSheen { 0%,100% { opacity: .42 } 50% { opacity: 1 } }
[data-theme="dark"] .glass::after {
  background: linear-gradient(135deg, rgba(255,255,255,.20), rgba(255,255,255,.05) 34%, transparent 62%);
}
@media (prefers-reduced-motion: reduce) { .glass::after { animation: none; opacity: .7; } }
[data-theme="dark"] .glass {
  background:
    radial-gradient(135% 100% at 12% 0%, rgba(var(--ac-rgb), .17), transparent 58%),
    color-mix(in srgb, var(--card) calc(var(--glass-a) - 12%), transparent);
  border-color: color-mix(in srgb, #fff 12%, transparent);
  box-shadow:var(--sh-glass-lg);
}
/* v23.2：删掉导航品牌的手写签名 —— 同一屏里它和 h1「做产品」的手迹重复，
   违反「手迹一处」护栏，也破坏了「品牌即文字标」的原始设计。手迹只留 h1 一处。 */
/* 标题手迹下划线：全站唯一手迹，强调一句话 */
.hl { position: relative; white-space: nowrap; }
.hl .hl-stroke { position: absolute; left: -1.5%; bottom: -.05em; width: 103%; height: .12em; overflow: visible; pointer-events: none; clip-path: inset(0 100% 0 0); animation: brushLoop 8s var(--ease) .8s infinite; }
.hl .hl-stroke svg { width: 100%; height: 100%; display: block; }
/* v28：原「dasharray:1 + pathLength=1」的归一化被 vector-effect:non-scaling-stroke 抵消，
   Chrome 改按屏幕像素算 dash → 手迹被切成约 3–4px 虚线段（屏越宽越明显 = 用户说的「大屏不连续」）。
   改由容器 clip-path 自左向右揭示，path 保持实线，彻底不依赖 dash → 任何屏宽都连续。 */
.hl .hl-stroke path { fill: none; stroke: var(--accent); stroke-width: 2.9; stroke-linecap: round; vector-effect: non-scaling-stroke; }
/* v57：手迹由「一次性揭示」改为「循环书写」—— 画出 → 长停 → 从左收回 → 短间隔 → 再画。
   它常驻 hero 首屏，「一直动」很容易变成廉价闪烁，所以节奏刻意失衡：
     8s 一轮里，真正在动的只有 1.92s（画 1.12s + 收 0.80s）= 24%，
     静止 4.48s 占 56%，空档 1.60s 占 20% —— 大部分时间它是稳定的，
     只在「看着想着」的时候才被写一遍，读起来像呼吸而非抽搐。
   收回方向取「从左追尾」（inset 的 left 由 0→100%），与揭示时「自左向右生长」同源：
   擦除跟着笔走，擦完正好回到起点，下一轮才能无缝接上。
   注意：82%→100% 是 inset(0 0 0 100%) → inset(0 100% 0 0)，
   插值全程可见宽度恒为 0（left+right ≡ 100%），故这段不可见、不会闪出残影。 */
@keyframes brushLoop {
  0%,  2%  { clip-path: inset(0 100% 0 0) }    /* 起始空档 0.16s */
  16%      { clip-path: inset(0 0 0 0)   }     /* 写完 1.12s */
  72%      { clip-path: inset(0 0 0 0)   }     /* 停留 4.48s（占多数） */
  82%      { clip-path: inset(0 0 0 100%) }    /* 从左收回 0.80s */
  100%     { clip-path: inset(0 100% 0 0) }    /* 复位 + 空档 1.44s（全程宽度 0，不可见） */
}
@media (prefers-reduced-motion: reduce) {
  .hl .hl-stroke { clip-path: inset(0 0 0 0); animation: none; }
}
/* 滚出视口 / 切到后台即停表：clip-path 动画每帧都要重绘，看不见时不该继续烧 CPU。
   由 app.js 的 observeStroke() 写 inline 的 animation-play-state（默认 running，无需 CSS 兜底）。 */

/* ---------- 11. 响应式 ---------- */
@media (max-width: 900px) {
  .about-grid { grid-template-columns: 1fr; gap: var(--sp-6); }
  .video-grid, .card-grid { grid-template-columns: 1fr; }
  /* v59：删掉 .section 的移动端 padding 覆盖 —— 交给 --sec-gap（clamp 自带 80px 下限），
     避免窄屏又回到「上下各 64px = 双倍 128px」的老问题。 */
}

/* 移动端：五个导航项在顶部会挤爆，改用底部 Tab —— 拇指可及，并适配全面屏安全区 */
@media (max-width: 640px) {
  /* v84 · 浮动 Liquid Glass 药丸（iOS 26 / Apple Intelligence 语汇）：
     由「通栏贴边 bar」改为「离屏浮起的玻璃药丸」——更高级、更 Apple Intelligence。
     ⚠ 通栏→浮动后，底部避让值必须重算（见本 media 末尾 html body padding，随实际高度走）。 */
  .tabbar {
    display: flex; position: fixed;
    left: 12px; right: 12px;
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    z-index: 70;
    border-radius: var(--r-pill);
    background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 12%), transparent);
    backdrop-filter: saturate(180%) blur(28px);
    -webkit-backdrop-filter: saturate(180%) blur(28px);
    border: 1px solid color-mix(in srgb, #000 6%, transparent);
    /* v86 F：再叠一层 0 1px 0 rgba(255,255,255,.25) 镜面高光 —— 顶缘的"厚度"更像 iOS 26
       （原只有 #fff 45% + var(--sh-glass) 两层，加深后玻璃边缘更实）。 */
    box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 45%, transparent),
                inset 0 1px 0 rgba(255, 255, 255, .25),
                var(--sh-glass), 0 14px 36px -10px rgba(20, 20, 22, .30);
    padding: 5px;
  }
  /* 药丸顶缘一缕 Apple Intelligence 光谱高光（极淡，只作身份识别，不抢戏） */
  .tabbar::before {
    content: ""; position: absolute; left: 18%; right: 18%; top: 0; height: 1px;
    border-radius: var(--r-pill); pointer-events: none; opacity: .8;
    background: linear-gradient(90deg, transparent, rgba(var(--ac-rgb), .55), color-mix(in srgb, var(--ai-3) 45%, transparent), transparent);
  }
  /* v86 B：Tab 图标渐变 #tabGrad 的蓝/紫两停改为引用 AI 光谱。
     CSS 的 stop-color 优先级**高于** SVG 的 stop-color 呈现属性，故无需改 index.html、
     也不用重新合并；末停由 #6f4fd2 收到 var(--ai-2)，与极光 au-2 / AI 辉光同源。 */
  #tabGrad stop:nth-of-type(3) { stop-color: var(--ai-1); }
  #tabGrad stop:nth-of-type(4) { stop-color: var(--ai-2); }
  /* ── 底部 Tab：陶瓷玻璃片 + SF Symbols 真字形 + 选中项光谱环（v5 定稿）──
     设计定稿与推导见 index.html.bak 的注释。要点四条：
       · 瓷片 30px / 墨迹 17px（占瓷片 57%）——v4 的 34/22 占比 65%，用户反馈「icon 过大」
       · 瓷片做在 .tabbar__ico（span）上，svg 只画字形：svg 不支持 ::after，
         而光谱环只能靠伪元素实现
       · 选中态＝蓝调瓷片(10%) + 光谱描边环(1.4px) + scale(1.05) + 呼吸光晕
       · ★ 基础规则必须带 flex:1 —— v3 曾整条误删，6 格退回内容宽度，
         430–640px 间右侧空 34–244px、≤390px 反而溢出。删改本块前先看回归断言。 */
  .tabbar__link {
    flex: 1;                           /* ★ 6 格等分填满 bar 宽度（曾误删，勿再去掉） */
    min-height: 46px; gap: 2px; padding: 4px 4px 3px;   /* v84 收窄纵向，药丸更修长 */
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    position: relative; border-radius: var(--r-pill);
    font-size: 0.812rem; font-weight: 500; color: var(--ink-3); line-height: 1.15;
    transition: color var(--dur-base) var(--ease);
  }
  .tabbar__ico {
    position: relative;                 /* 光谱环 ::after 的定位锚 */
    display: grid; place-items: center;
    width: 30px; height: 30px; padding: 3px;   /* 30 − 2×1(边) − 2×3 = 22 → svg 22px，墨迹 17px */
    border-radius: var(--r-md);
    /* v84 调淡：未选中瓷片更「素」更透气（8% 底 / 8% 描边 / 轻投影），让选中项的 Apple Intelligence 光环独大 */
    background-color: color-mix(in srgb, #fff 8%, transparent);
    background-image:
      radial-gradient(135% 100% at 12% 0%, rgba(var(--ac-rgb), .07), transparent 58%),
      linear-gradient(135deg, rgba(255,255,255,.34), rgba(255,255,255,.05) 42%, transparent 66%);
    -webkit-backdrop-filter: blur(20px) saturate(180%); backdrop-filter: blur(20px) saturate(180%);
    border: 1px solid color-mix(in srgb, var(--ink) 8%, transparent);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, #fff 45%, transparent),
      0 1px 3px -2px color-mix(in srgb, var(--ink) 14%, transparent);
    /* v86 D-1：选中/取消的缩放改「弹簧」—— iOS 同款 overshoot 曲线
       cubic-bezier(.34,1.56,.64,1)：按下去会轻微过冲再回落，那一下就是 iOS 的"活"。
       240ms（卡 ≤250ms 内）；减动态下由本 media 末尾的 media query 关掉。 */
    transition: transform 240ms cubic-bezier(.34, 1.56, .64, 1), background-color var(--dur-base) var(--ease),
                border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
  }
  .tabbar__ico svg { display: block; width: 22px; height: 22px; }
  /* ── SF Symbols 双态：未选中＝轮廓态，选中＝填充态 ──
     这是 Apple Tab Bar 的标准行为（house → house.fill）。v4 起字形换成真 SF Symbols，
     两条路径都写在同一个 <svg> 里，靠 opacity 交叉淡入切换。
     ⚠ 用 opacity 而不是 display:none —— display 无法过渡，硬切会让「形态变化」显得突兀；
       两个字形外轮廓接近，250ms 的交叉淡入读起来像一次「形变」，比硬切高级。 */
  .tabbar__ico .g-o, .tabbar__ico .g-f { transition: opacity var(--dur-base) var(--ease); }
  .tabbar__ico .g-f { opacity: 0; }
  .tabbar__link.is-active .tabbar__ico .g-o { opacity: 0; }
  .tabbar__link.is-active .tabbar__ico .g-f { opacity: 1; }
  /* v26：恢复选中「呼吸感」（用户 2026-10-16 再次明确认可）—— 玻璃瓷片柔和发光脉冲 */
  @keyframes tabIconBreath {
    0%, 100% { box-shadow: inset 0 1px 0 rgba(255,255,255,.45), 0 0 0 0 rgba(var(--ac-rgb),0); }
    50%      { box-shadow: inset 0 1px 0 rgba(255,255,255,.45), 0 0 12px 2px rgba(var(--ac-rgb),.42); }
  }
  .tabbar__link.is-active { color: var(--link); font-weight: 700; }
  .tabbar__link.is-active .tabbar__ico {
    transform: scale(1.05);
    /* 必须写 background-color 而不是简写 background —— 简写会把上面的高光/折射层重置成 none，
       选中态反而变成最「平」的一块（v43 踩过）。
       ⚠ 24% → 14% 是**双主题 A/B 截图后定的**：原 24% 与光谱环、蓝色图标三蓝相争，
       浅色下瓷片读成一块蓝斑；降到 14% 后瓷片回到「素玻璃」，颜色交给光谱环去讲。 */
    background-color: color-mix(in srgb, var(--accent) 10%, transparent);
    border-color: rgba(var(--ac-rgb),.34);
    animation: tabIconBreath 4s var(--ease-breathe) infinite;
  }
  /* ★ 光谱描边环：Apple Intelligence 的指纹，只给选中项 ──────────────────
     为什么不能用 background 分层裁剪（padding-box / border-box）做环：
       瓷片的底色与高光层本身是**半透明玻璃**，无论怎么裁，底下那层 border-box 光谱
       都会从高光的透明处透上来 → 实测整片瓷片被染成蓝紫渐变，不是环。已验证不可行。
     正解＝伪元素铺满 + mask 挖空中心，只剩描边那一圈。
     ⚠ svg 元素不支持 ::after —— 这就是瓷片必须承载在 .tabbar__ico 上的原因。
     ⚠ 环的四个色标刻意降了饱和（#0a84ff→#4aa3f5 等）：全饱和版在浅色瓷片上读成
       「霓虹圈」，降饱和后才是「玻璃边缘的虹彩」。深色底上依然清晰（双主题 A/B 验证）。 */
  @supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
    .tabbar__link.is-active .tabbar__ico::after {
      content: ""; position: absolute; inset: 0; border-radius: inherit;
      padding: 1.4px;                     /* 环的厚度（v5：1.6→1.4，配更小的瓷片） */
      pointer-events: none;
      background: linear-gradient(120deg, #4aa3f5 0%, #8b7ce8 34%, #c98ae0 62%, #f57b93 100%);
      -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
              mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      -webkit-mask-composite: xor;
              mask-composite: exclude;
    }
  }
  /* v29：移动端底部 icon 此前完全没有反馈（无 hover 也无 :active）。触摸设备没有 hover，
     按压就是它唯一的反馈通道 —— 给瓷片一个可见的按下（.94 比 .97 在小目标上更可感知）。 */
  .tabbar__link:active { background: color-mix(in srgb, var(--ink) 6%, transparent); }
  .tabbar__link:active .tabbar__ico { transform: scale(.94); }
  @media (prefers-reduced-motion: reduce) {
    .tabbar__link.is-active .tabbar__ico { animation: none; }
    /* 弹簧也要关：去掉 transform 过渡，缩放直接到位，不做位移 */
    .tabbar__ico { transition: background-color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease); }
  }
  /* v43b：原 [data-theme="dark"] .tabbar__ico 覆盖块已删除 —— 实测它在本页不参与级联
     （!important 注入也改不动），属于死代码；深浅差异现由基础规则的 #fff / var(--ink) 自动翻转承担。 */
  [data-theme="dark"] .tabbar {
    border-color: color-mix(in srgb, #fff 12%, transparent);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.10), var(--sh-glass), 0 14px 36px -10px rgba(0,0,0,.55);
  }
  .tabbar__link.is-active::after { content: none; }      /* 底部 Tab 不套用顶部那条下划线 */
  .nav__links .nav__link { display: none; }              /* 只隐藏顶部这排，Tab 里的不受影响 */
  .icon-btn { width: 44px; height: 44px; }               /* v15：移动端主题按钮补到 44×44 触控目标 */
  /* v25 复查发现并修复：intro 注入样式含 `html,body{margin:0;padding:0;}`（源码位置在 style.css 之后、
     同特异性更靠后），会把原 `body{padding-bottom:...}` 整条清掉 → 移动端底部 Tab 栏遮挡内容约 18px。
     改用 `html body`（特异性 0,0,2 > 0,0,1）确保生效；并加 64px 纯值兜底（env() 不被支持时仍有避让）。 */
  /* v57：实测底部 Tab 栏高 65px（无 safe-area 时），原 64px 补偿差 1px —— footer 最后 1px
     压在栏下。提到 66px 留 1px 余量；有 safe-area 时同步抬高，口径一致。 */
  /* v3（2026-10-16）：瓷片 32px→34px、字形 20px→24px，Tab 栏实测从 61.7px 涨到 **77.3px**，
     而避让还停在 66px → 页脚会被压住约 11px（同一类 bug 第二次出现）。
     ⚠ 这条补偿值**必须跟着 Tab 栏实际高度走**，改 tabbar 内任何尺寸都要回来复测。 */
  /* v84：通栏→浮动药丸后重算。实测药丸顶距视口底 76px（药丸高 66 + 底距 10），
     内容避让＝76 + 12(间隙) = 88px。⚠ 改药丸任何尺寸/底距都必须回来复测（同类 bug 已出 3 次）。 */
  html body { padding-bottom: 88px; padding-bottom: calc(88px + env(safe-area-inset-bottom, 0px)); }

  .wrap { padding: 0 var(--sp-5); }
  /* v45：触摸端实测页脚链接仅 28×25、品牌 69×36，均低于 Apple 44pt。
     链接用 inline 内边距 + **等量负外边距**扩大触控区 —— 触控区变大但字的位置与字间距完全不变。 */
  .footer__links a {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px;
    padding-inline: var(--sp-2); margin-inline: calc(var(--sp-2) * -1);
  }
  .brand { min-height: 44px; }
  .chip { padding: var(--sp-3) var(--sp-4); }
  .hero { padding: var(--sp-8) 0; }
  /* v20：竖屏收顶 + 取消强制撑满 —— 原 min-height:100svh + 22vh 顶部留白让首屏下部空一大片。
     内容紧贴导航下方，高度随内容排布，第一屏只剩少量呼吸感，"最近更新"窥视照常。 */
  .hero--welcome {
    padding: clamp(140px, 16vh, 160px) 0 var(--sp-8);
    min-height: auto;
  }
  .section--tight { margin-top: -64px; }   /* v20：竖屏窥视收紧一档 */
  .post { padding: var(--sp-5); --card-pad: var(--sp-5); }
  .post__title { font-size: 1.25rem; }
  .article__title { font-size: 1.75rem; letter-spacing: -0.022em; }   /* v25 F1：-1px(=-0.036em) 超中文上限 → 改 em 且不超 -0.022em */
  .section__head { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }

  /* 最近更新：窄屏改成「标题一行 + 类型/日期一行」，不再横向挤压 */
  .recent__row { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--sp-2); padding: var(--sp-4); }
  .recent__title { grid-row: 1; grid-column: 1 / -1; white-space: normal; }
  .recent__type { grid-row: 2; grid-column: 1; }
  .recent__date { grid-row: 2; grid-column: 2; text-align: right; }

  /* 弹窗改成底部 sheet：全宽、贴底、可滚动，比居中浮层更适合竖屏 */
  .modal { padding: 0; align-items: end; }
  .modal__panel { width: 100%; border-radius: var(--r-md) var(--r-md) 0 0; max-height: 92vh; overflow: auto; }
}

/* =========================================================================
   13. 长文富文本（文章 html 正文）样式 —— 与全站 Token 同源
   -------------------------------------------------------------------------
   适配 markdown 生成的 h2/h3/h4、列表、引用、表格、代码、分割线。
   颜色/圆角/间距全部走 :root 与深色模式变量，浅深双主题自动适配。
   ========================================================================= */
.article__body ul, .article__body ol {
  margin: 0 0 var(--sp-5); padding-left: var(--sp-6);
  font-size: 1.125rem; line-height: 1.7; color: var(--ink);
}
.article__body li { margin: var(--sp-2) 0; }
.article__body li::marker { color: var(--accent); }
.article__body li > ul, .article__body li > ol { margin: var(--sp-2) 0; }
.article__body strong { color: var(--ink); font-weight: 700; }
.article__body em { font-style: italic; color: var(--ink); }
.article__body a {
  color: var(--link); text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--link) 35%, transparent);
}
.article__body a:hover { border-bottom-color: var(--link); }
.article__body code {
  font-family: var(--font-mono);
  font-size: .9em; background: var(--surface); padding: 1px 6px;
  border-radius: var(--r-sm); color: var(--ink);   /* v47：6px 越出「8/16/22/999」圆角档位 → 归到 8px */
}
.article__body pre {
  margin: var(--sp-5) 0; padding: var(--sp-4) var(--sp-5);
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--r-md); overflow-x: auto;
}
.article__body pre code { background: none; padding: 0; font-size: 0.938rem; line-height: 1.6; color: var(--ink-2); }
.article__body blockquote {
  margin: var(--sp-5) 0; padding: var(--sp-3) var(--sp-5);
  background: var(--surface); border-left: 3px solid var(--accent);
  border-radius: var(--r-sm); color: var(--ink-2); font-size: 1rem;
}
.article__body blockquote p { font-size: 1rem; margin: 0; }
.article__body blockquote p + p { margin-top: var(--sp-2); }
/* 文中引用的原文（毕业贴）：复用引用块左 accent 边框，但保留正文 18px 阅读尺寸，并加居中标题 */
.article__body blockquote.article__embed { padding: var(--sp-5) var(--sp-6); margin: var(--sp-6) 0; }
.article__body blockquote.article__embed p { font-size: 1.125rem; line-height: 1.8; color: var(--ink-2); }
.article__body blockquote.article__embed p + p { margin-top: var(--sp-5); }
.article__body .article__embed__title {
  text-align: center; font-weight: 700; color: var(--ink);
  font-size: 1.25rem; letter-spacing: -.02em; margin-bottom: var(--sp-4);
}

/* 文中引文的「出处署名」：收进引文框内、底部右对齐，与引文成为一个整体。
   此前 marx 篇把它放在框外下方居中 → 与引文脱节、观感孤立，已修正。 */
.article__body blockquote.article__embed .article__embed__src {
  margin: var(--sp-4) 0 0; text-align: right;
  font-size: 0.938rem; font-weight: 500; letter-spacing: -.02em;
  color: var(--ink-3);
}

.article__body hr { border: none; border-top: 1px solid var(--hairline); margin: var(--sp-7) 0; }
.article__body img { max-width: 100%; border-radius: var(--r-md); }
.article__body table { width: 100%; border-collapse: collapse; font-size: 0.938rem; }
.article__body th, .article__body td {
  border: 1px solid var(--hairline); padding: var(--sp-2) var(--sp-3);
  text-align: left; vertical-align: top; color: var(--ink-2);
}
.article__body th { background: var(--surface); color: var(--ink); font-weight: 700; }
.article__body .table-wrap { max-width: 100%; overflow-x: auto; margin: var(--sp-5) 0; }

/* 窄屏表格：横向可滚动；给最小宽度，避免短列被压成「竖排单字」
   （曾出现「第一部分」被挤成 第/一/部/分 逐字竖排） */
@media (max-width: 640px) {
  .article__body .table-wrap { overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }
  .article__body table { min-width: 560px; }
}

/* ---------- 8b. 长文两栏阅读版式（左目录 · 右正文，对齐飞书 / 语雀） ---------- */
/* v49 起：统一阅读版心 —— 此前「有目录的长文」正文 792px、「无目录 / 轻量文章」696px，
   同一座站里两种行宽，观感就是一胖一瘦。现在把正文内容宽度钉死为同一个常量
   （v55 取 760px，回到《长文阅读页通用规范》§二.1 的目标值，填满 1200 版心、屏占比达标；
   ≈ 42 汉字/行，仍在中文可读区间上限内）。
   第二列写成 minmax(0, var(--read-w)) 而不是 1fr，并配 justify-content:center：
   目录收走后两列合计变窄、整组自动居中（留白回到两侧，屏占比观感提升），
   但正文宽度一动不动 —— 这是「目录可收起」与「所有文章胖瘦一致」能同时成立的前提：
   无目录的文章没有可收的东西，若收起就变宽，它永远比别的文章再瘦一档。 */
.article__layout {
  --toc-w: 280px;      /* 目录栏宽（展开） */
  --toc-rail: 56px;    /* 目录栏宽（收起后只留一条窄轨放按钮） */
  --read-w: 760px;     /* 正文内容宽度，全站文章共用一把尺（v55：696→760，对齐规范、填满版心） */
  display: grid;
  grid-template-columns: var(--toc-w) minmax(0, var(--read-w));
  gap: var(--sp-8);
  justify-content: center;   /* 轨道合计不满容器时整体居中 */
  max-width: var(--wrap);
  margin: 0 auto;
  align-items: start;
  transition: grid-template-columns var(--dur-base) var(--ease), gap var(--dur-base) var(--ease);
}
/* 目录收起：侧栏缩成一条窄轨。这里刻意不做成「两枚裸图标」——
   旧版只剩一个 14px 箭头 + 一个 14px chevron：既看不出是什么、又小到几乎点不中
   （远低于最小命中尺寸），观感像坏掉的空盒子。
   改成两颗「图标 + 文字」的幽灵按钮：发丝描边 + 卡片底 + hover/按压 + 8px 圆角 token，
   目录用列表图标配「目录」、返回用箭头配「返回」—— 语义直白、命中区域够大、成对出现就是控件。 */
.article__layout.is-toc-collapsed {
  --toc-w: var(--toc-rail);
  gap: var(--sp-6);
}
.is-toc-collapsed .article__side {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
}
.is-toc-collapsed .article__toc-details > .article__toc-summary {
  width: 44px; padding: 7px 0; margin: 0;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  border: 1px solid var(--hairline); border-radius: var(--r-sm);
  background: var(--card); color: var(--ink-2);
  font-size: 0.812rem; line-height: 1.1; letter-spacing: 0; text-transform: none;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.is-toc-collapsed .article__toc-summary::after { content: "目录"; }
.is-toc-collapsed .article__toc-icon svg { width: 16px; height: 16px; }
@media (hover: hover) and (pointer: fine) {
  .is-toc-collapsed .article__toc-details > .article__toc-summary:hover {
    color: var(--ink); border-color: var(--line); background: var(--hover);
  }
}
.is-toc-collapsed .article__toc-details > .article__toc-summary:active { transform: scale(var(--active-scale)); }
/* 收起：隐去原文字标签与 chevron，只留列表图标（+ 上面的 ::after「目录」） */
.is-toc-collapsed .article__toc-label,
.is-toc-collapsed .article__toc-count,
.is-toc-collapsed .article__toc-summary > svg { display: none; }
.is-toc-collapsed .article__toc-icon { display: inline-flex; }
/* 兜底：闭合的 <details> 由浏览器自行隐藏，但各引擎实现不同（Chrome 用 content-visibility:hidden，
   元素仍保留巨大布局盒子）。既然「收走」就等于列表不可见，这里显式关掉，避免任何残留可滚动区域。 */
.is-toc-collapsed .article__toc-list { display: none; }
/* 展开态：这一行本身就是开关（点它收起目录）——补一点悬停反馈，
   否则只有一个 chevron 暗示「可点」，太弱。 */
.article__toc-icon { display: none; }
@media (hover: hover) and (pointer: fine) {
  .article__toc-summary:hover,
  .article__toc-summary:hover .article__toc-label,
  .article__toc-summary:hover .article__toc-count { color: var(--ink); }
}
.article__side {
  position: sticky;
  top: calc(var(--nav-h) + var(--sp-5));
  align-self: start;
  max-height: calc(100vh - var(--nav-h) - var(--sp-7));
  /* Change 2 (2026-10-17)：移动端动态视口高度（地址栏缩放下不溢出）。不支持 dvh 的浏览器
     忽略下一行、回落到上一行 100vh，零视觉差异。 */
  max-height: calc(100dvh - var(--nav-h) - var(--sp-7));
  overflow: auto;
}
.article__main { min-width: 0; }   /* 防止宽表格 / pre 把网格撑破 */
/* v48：无目录的长文（rich HTML 但没有 ≥4 个 h2/h3 → enhanceArticle 不生成 .article__toc）
   在宽屏下两栏会空出一整列，屏占比低。
   用 :has 探测侧栏里有没有目录：没有 → 收成与轻量文章一致的单栏版心（760 居中）。
   必须限定 min-width:1080px —— 更窄时 ↓ 窄屏媒体查询已用 flex 单栏排版，别去覆盖它的 gap。
   （v76：长文内不渲染任何返回入口，返回交给独立可拖动的阅读进度气泡 .read-bubble；本条只关乎列宽。） */
@media (min-width: 1080px) {
  .article__layout:not(:has(.article__toc)) {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    max-width: 824px;   /* v55：824-64=760，与「有目录」文章正文等宽 */
  }
  .article__layout:not(:has(.article__toc)) .article__side {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

/* 章节 / 子节层级（删书名 H1 后：原 ##→H2 章、###→H3 节，页面 H1 唯一） */
/* 章节 / 子节层级（删书名 H1 后：原 ##→H2 章、###→H3 节，页面 H1 唯一）
   v58：此前 h2/h3/h4 散在**三处**定义（§4b、§13 头部、本节），特异性完全相同 →
   后写的只覆盖自己声明的属性，没声明的仍由前一份生效，结果是拼出来的怪样式：
     · **H2 同时吃到 §13 那份的左竖线+内距、和这份的上分隔线** → 一个标题上出现
       两种分区符号（左 3px 蓝条 + 上方 1px 灰线），这是真 bug，不是风格问题；
     · H3 的字号/间距来自 §13、竖线来自 §4b —— 想调一个要同时改两处，改一处没反应。
   现在合并为**唯一一份**：章(H2) 只用**上方分隔线**，节(H3) 只用**左侧竖线**，两种符号不混用。 */
.article__body h2 {
  font-size: 1.75rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.3;
  color: var(--ink); text-wrap: balance;
  /* v59：原 margin-top --sp-9(96)+padding-top --sp-7(48)=144px，章节间空档过大 → 收到 48+24=72px */
  margin: var(--sp-7) 0 var(--sp-5); padding-top: var(--sp-5);
  border-top: 1px solid var(--hairline);
}
.article__body h3 {
  font-size: 1.312rem; font-weight: 700; letter-spacing: -.02em; line-height: 1.35;
  color: var(--ink); text-wrap: balance;
  margin: var(--sp-6) 0 var(--sp-3);
  padding-left: var(--sp-4); border-left: 3px solid var(--accent);
}
/* v58：原 17px **比正文（18px）还小** —— 四级标题在层级上低于正文，是层级倒置。
   改为与正文同号，靠字重与颜色拉开；层级回到 h2 28 > h3 21 > h4/正文 18。 */
.article__body h4 {
  font-size: 1.125rem; font-weight: 700; letter-spacing: -.02em;
  margin: var(--sp-6) 0 var(--sp-3); color: var(--ink);
}
/* 落款（序/后记末尾的署名 + 日期）：两行、右对齐 —— 由源文档 <p class="sign"> 承载。
   之前源文档用 markdown 软换行（李锐\n2026 年 9 月），HTML 会把它合并成一行。 */
.article__body .sign {
  text-align: right;
  margin-top: var(--sp-6);
  color: var(--ink-3);
  font-size: 0.938rem;
  line-height: 1.7;
}

/* ---------- 长文强调范式（2026-10-05 · 新年贺词首次落地）----------
   正文是 --ink-2 / 400；强调一律「深一档 + 重一档」（--ink / 700），
   **不引入第二种彩色** —— 灰阶已足以拉开层次，加蓝反而打断长文阅读。
   关键：重点分三种角色，各自成组件，避免所有强调都挤在 <strong> 一种手段里。 */
/* ① 题眼：开篇定调那句（原文整行加粗）。放大一号单独承重，作为全文的"锚"。 */
.article__body .article__eyeline {
  font-size: 1.5rem; line-height: 1.5; font-weight: 700; color: var(--ink);
  letter-spacing: -.015em; margin-bottom: var(--sp-6);
}
/* ② 排比组：整段加粗的并列项。散成独立段落就读不出"这是一组"，
      用左侧细线把它们收拢成一个视觉单元（2px，比 blockquote 的 3px 轻一档）。 */
.article__body .article__parallel {
  margin: var(--sp-6) 0; padding-left: var(--sp-5);
  border-left: 2px solid var(--accent);
}
.article__body .article__parallel p { font-weight: 700; color: var(--ink); }
.article__body .article__parallel p + p { margin-top: var(--sp-4); }

/* v65：正文图片淡入。is-pending 由 JS 打上/移除 —— CSS 不默认 opacity:0，
   保证 JS 失效时图片仍然可见（渐进增强，不是依赖）。 */
.article__body img { transition: opacity var(--dur-slow) var(--ease); }
.article__body img.is-pending { opacity: 0; }

/* 落款落在「文中引文」（blockquote.article__embed）里时，会被上面的
   `.article__body blockquote.article__embed p{font-size: 1.125rem}` (0,2,2) 压过变成 18px；
   用 .sign 再提一档特异性 (0,3,1) 复位成设计值 15px。 */
.article__body blockquote.article__embed .sign { font-size: 0.938rem; }
/* ③ 收尾：贺词的收束。居中 + 收紧行距，给结尾一点仪式感（正文仍左对齐，不污染全文）。 */
.article__body .article__closing { margin-top: var(--sp-7); text-align: center; }
.article__body .article__closing p { font-size: 1.25rem; font-weight: 700; color: var(--ink); }
.article__body .article__closing p + p { margin-top: var(--sp-3); }

/* ---------- 公文范式（工作报告 / 讲话稿，2026-10-06 首次落地）----------
   与「现代随笔」范式区分：公文以居中标题块 + 首行缩进 2em + 部/条标题为标志，
   不用侧栏目录（内容无 h2/h3 → 自动收单栏），呈现"文件"质感而非"长读"版式。
   层级：doc__title(主标题,居中) > doc__part(部,居中+上分隔) > doc__sec(条,左对齐加粗) > 正文(缩进)。
   强调一律灰阶（--ink/700），不引入第二种彩色，与全站长文纪律一致。 */
.article__body .doc p { text-indent: 2em; }   /* 公文正文首行缩进 2 字 */
.article__body .doc .doc__title,
.article__body .doc .doc__subtitle,
.article__body .doc .doc__meta,
.article__body .doc .doc__salutation,
.article__body .doc .doc__cta,
.article__body .doc .doc__part,
.article__body .doc .doc__sec { text-indent: 0; }

.article__body .doc__title {
  text-align: center;
  font-size: 1.875rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.32;
  color: var(--ink);
  margin: var(--sp-2) 0 0;
}
.article__body .doc__subtitle {
  text-align: center;
  font-size: 1.125rem; font-weight: 500; color: var(--ink-2);
  margin: var(--sp-3) 0 0;
}
.article__body .doc__meta {
  text-align: center;
  font-size: 0.938rem; color: var(--ink-3);
  margin: var(--sp-4) 0 0;
  line-height: 1.9;
}
.article__body .doc__salutation {
  font-size: 1.125rem; color: var(--ink); font-weight: 500;
  margin: var(--sp-6) 0 var(--sp-4);
}
.article__body .doc__part {
  text-align: center;
  font-size: 1.375rem; font-weight: 700; letter-spacing: -.02em; color: var(--ink);
  margin: var(--sp-8) 0 var(--sp-5);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--hairline);
}
.article__body .doc__sec {
  font-size: 1.125rem; font-weight: 700; color: var(--ink);
  margin: var(--sp-6) 0 var(--sp-3);
}

/* ---------- 诗歌范式（2026-10-07 首次落地）----------
   诗歌与散文的根本差别：**换行本身表意** —— 一行结束就是一次呼吸/停顿，
   所以每行必须独立成行（用 <br>，绝不能并成段落），段间距只用于分「诗节」。
   形态上与散文区分：整体居中、字号略提（19）、行距放到 2.05（给呼吸）、
   字距微正（+.01em，让短句透气）；献词/署名右对齐收尾。
   强调纪律同全站：只用灰阶，不引入第二种彩色。 */
.article__body .poem { margin-top: var(--sp-6); }
.article__body .poem__stanza {
  text-align: center; font-size: 1.188rem; line-height: 2.05; color: var(--ink);
  letter-spacing: .01em; margin: 0 0 var(--sp-5); text-wrap: balance;
}
.article__body .poem__dedicate {
  text-align: right; font-size: 1.062rem; font-weight: 500; line-height: 1.8;
  color: var(--ink-2); margin: var(--sp-7) 0 0;
}
.article__body .poem__sign {
  text-align: right; font-size: 0.938rem; line-height: 1.7; color: var(--ink-3);
  margin: var(--sp-2) 0 0;
}

/* 目录（富文本长文自动生成：宽屏=左侧常驻大纲，窄屏=顶部可折叠卡） */
.article__toc-details { /* 宽屏无底色、呈纯大纲；窄屏在媒体查询里加卡片 */ }
.article__toc-summary {
  display: flex; align-items: center; gap: var(--sp-2);
  list-style: none; cursor: pointer; user-select: none;
  padding: var(--sp-2) 0;
  font-size: 0.812rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
  transition: color var(--dur-fast) var(--ease);
}
.article__toc-summary::-webkit-details-marker { display: none; }
.article__toc-summary::marker { content: ""; }
.article__toc-label { color: var(--ink-3); }
.article__toc-count {
  margin-left: var(--sp-2); font-size: 0.812rem; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--ink-3);
}
.article__toc-summary svg {
  margin-left: auto; color: var(--ink-3);
  transition: transform var(--dur-base) var(--ease);
}
.article__toc-details[open] > .article__toc-summary svg { transform: rotate(180deg); }
.article__toc-list { list-style: none; margin: var(--sp-2) 0 0; padding: 0; }
.article__toc-item { margin: 0; }
.article__toc-item.lvl-h3 .article__toc-link { padding-left: var(--sp-5); font-size: 0.938rem; }
.article__toc-link {
  display: block; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  color: var(--ink-2); font-size: 0.938rem; line-height: 1.5; text-decoration: none;
  border-bottom: none;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
/* 移动端触控目标（上线前检查 ③）：15px×1.5=22.5 + 上下 8px = **38.5px < 44pt**（实测 39px）。
   移动端把纵向内距提到 --sp-3(12px) → 46.5px ✅；桌面仍 8px，不无谓拉长目录。 */
@media (max-width: 640px) {
  .article__toc-link { padding: var(--sp-3) var(--sp-3); }
}
@media (hover:hover) and (pointer:fine) {
  .article__toc-link:hover { background: var(--hover); color: var(--ink); }
}
.article__toc-link.is-active {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-ink);   /* v47：原用 --accent，14px 下浅色 3.98 / 深色 4.35，均不达 AA 4.5 */
}
.article__toc-link:active { transform: scale(var(--active-scale)); }

/* 窄屏：单栏。用 flex + display:contents 把「返回 / 标题 / 目录 / 正文」重新排序 ——
   移动端标题优先于目录（对齐语雀 / 飞书移动端：先标题、后目录、再正文），
   目录折叠为一张卡片。 */
@media (max-width: 1079px) {
  .article__layout { display: flex; flex-direction: column; align-items: stretch; gap: var(--sp-6); max-width: 824px; }   /* v55：窄屏正文同样 760；v59b：必须补 align-items:stretch —— 基础网格规则留了 align-items:start，切成 flex 后未复位，项会按内容 fit-content 定宽、被 <pre> 撑破 */
  .article__main { display: contents; }         /* 让 head / body / foot 成为可排序的 flex 项 */
  .article__side { display: contents; }         /* 让 目录 成为可排序的 flex 项 */
  .article__head  { order: 2; }
  .article__toc   { order: 3; }
  .article__body  { order: 4; margin-top: 0; min-width: 0; }
  .article__foot  { order: 5; }
  /* v59b：display:contents 展开后，标题/目录/正文/落款都是 .article__layout 的 flex 项，
     默认 min-width:auto 会解析成「内容的 min-content 宽」—— ai-history 里的 <pre>（white-space:pre）
     最小内容宽 ≈743px，把正文项撑到 745px → 窄屏溢出、又被 .article{overflow-x:clip} 裁掉，
     正文右侧被切、手机读不了（其它无 <pre> 的文章不受影响）。给 flex 项 min-width:0，
     令 <pre> 走自身 overflow-x:auto 横向滚动，正文恢复按容器换行。 */
  .article__head, .article__toc, .article__foot { min-width: 0; }
  .article__toc-details {
    background: var(--surface); border: 1px solid var(--hairline);
    border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
  }
  .article__toc-summary { padding: 0; }
  .article__toc-list { margin-top: var(--sp-3); }
}

/* ---------- 置顶角标（v53 → v53.1） ----------
   图钉曾放在元信息行内（标签前 / 标签后），无论哪个位置都会把它后面的元素（日期 / 时长）
   右推 → 置顶卡与非置顶卡错位。改为卡片角落的「书签」：绝对定位、不参与行内流，
   元信息行在所有卡片上零位移、严格对齐。
   v53.1：首页「最近更新」行的图钉已去掉（紧凑行列表，纯文字三列网格更干净）；
   视频 / 作品卡角标做了背景冲突加固（见 .video-card__pin）。 */
.post { position: relative; }
.post__pin {
  position: absolute; top: calc(var(--card-pad) + 8px); right: var(--card-pad);
  display: inline-flex; color: var(--ink-3);
}
/* 视频 / 作品卡：角标落在缩略图右上，复用时长角标同款深色玻璃片。
   背景可能是真封面图（明暗不一），加 1px 半透明白描边 + 轻投影，保证任何底图上都浮起、不糊、不冲突。 */
.video-card__pin {
  position: absolute; z-index: 2; top: var(--sp-3); right: var(--sp-3);
  display: inline-flex; align-items: center;
  padding: var(--sp-1) var(--sp-2); border-radius: var(--r-sm);
  background: rgba(0,0,0,.62); color: #fff;
  border: 1px solid rgba(255,255,255,.22);
  box-shadow: 0 1px 4px rgba(0,0,0,.35);
}
/* 图钉在 .recent__type 内（v53，保持不变）：间距由该容器 gap 统一给出 */

/* ---------- 12. 降低动效 ---------- */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
}

/* =========================================================================
   渐进增强回退：不支持 color-mix() 的浏览器（v1.0.0 通用性加固）
   -------------------------------------------------------------------------
   全站玻璃材质与卡片底色大量使用 color-mix()。在不支持它的浏览器上，
   整条 background 声明会被判为无效 → 元素变透明，卡片/导航会「消失」，
   文字直接压在页面上（可读性崩坏）。
   这里给出不透明回退：老浏览器看到实心卡片（不好看但完全可用）。
   支持 color-mix 的浏览器**不会进入**这个块，观感不受任何影响。
   ========================================================================= */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .glass, .post, .video-card, .recent__row, .profile,
  .btn--ghost, .modal__panel {
    background: var(--card);
  }
  .footer { background: var(--surface); }
  /* 胶囊用 --ink 低比例着色，回退成透明即可（文字照常可读） */
  .chip { background: transparent; }
  /* 光谱镜片降级为实心浅蓝（无 color-mix 时无法叠折射层）：图标/文字仍可读 */
  /* 无 color-mix：瓷片的高光/折射层整条失效 → 退回实心浅蓝瓷片（图标仍可读）；
     光谱环依赖 mask 而非 color-mix，可继续保留。 */
  .tabbar__ico { background-color: var(--accent-soft); background-image: none; box-shadow: none; }
}
/* =========================================================================
   图文长文：figure / 图注 / 照片右破栏（新疆之旅等 73 图文章）
   ========================================================================= */
.article__body figure { margin: var(--sp-6) 0; }
.article__body figure img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
  border-radius: var(--r-md);
  box-shadow: var(--sh-2);
  cursor: zoom-in;
  background: var(--surface);
}
.article__body figcaption {
  margin-top: var(--sp-3);
  font-size: 0.938rem;
  line-height: 1.6;
  color: var(--ink-3);
  text-align: center;
}

/* ---------- 长文示意图（内联 SVG） ----------
   静态站没有 mermaid 渲染引擎，流程图一律改写成手写内联 SVG。两个硬约束：
   · 必须**内联**：外部 .svg 经 <img> 引入后读不到 documentElement 的 data-theme，
     深浅主题会与页面脱节（浅底图配深底页）；
   · 尺寸与颜色全部收进 class 走 Token，不在标签上写死颜色。
   图形语言沿用站点的克制取向：节点填充 --card、描边 --hairline、
   文字 --ink/--ink-2，仅箭头与关键节点用 --accent 点睛。 */
.article__body .fig-svg { display: block; width: 100%; height: auto; }
/* 窄屏：整图等比缩放会把 13px 字压到约 6px（实测 390px 视口下 svg 仅 342px 宽，不可读）。
   与表格同一套处理——给最小宽度、容器横向滚动；桌面图宽 800px 不会触发滚动。 */
.article__body .fig-scroll { overflow-x: auto; }
@media (max-width: 640px) {
  .article__body .fig-scroll { overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }
  .article__body .fig-svg { min-width: 680px; }
}
.article__body .fig-box { fill: var(--card); stroke: var(--hairline); stroke-width: 1; }
.article__body .fig-box--key { stroke: var(--accent); stroke-width: 1.5; }
.article__body .fig-t1 { fill: var(--ink); font-size: 0.812rem; font-weight: 700; }
.article__body .fig-t2 { fill: var(--ink-2); font-size: 0.812rem; }
.article__body .fig-mono { fill: var(--ink); font-family: var(--font-mono); font-size: 0.812rem; }
.article__body .fig-edge { fill: none; stroke: var(--ink-3); stroke-width: 1.5; }
.article__body .fig-edge--dash { stroke-dasharray: 5 4; }
/* 边标签的垫块：与**页面底色**同色（浅 body=--card / 深 body=--surface），
   把穿过来的连线遮断 —— 否则「属于/包含/使用」会被连线划开。 */
.article__body .fig-tag-bg { fill: var(--card); }
[data-theme="dark"] .article__body .fig-tag-bg { fill: var(--surface); }
.article__body .fig-label { fill: var(--ink-3); font-size: 0.812rem; }
.article__body .fig-arrow { fill: var(--accent); }

/* ---------- 代码块：IDE 观感 ----------
   用户明确要求「还原程序员在 IDE 里写代码的质感」，所以代码块**刻意不随主题切换**：
   IDE / 编辑器的主流是深色，技术内容站里「代码就该是深色」是读者的稳定预期。
   配色取自 VS Code Dark+，在 #1E1E1E 上的对比度均达标（默认前景 #D4D4D4 约 11:1）。
   ⚠ 这是全站唯一一处脱离页面主题的皮肤，理由如上；若要跟随主题需另配一套浅色高亮配色。
   填充：窗口 chrome（机能区）一档 + 代码区一档，同色系深浅两级，不引入第二种杂色。 */
/* 配色：随主题切换 —— 浅色用 GitHub Light 系，深色用 VS Code Dark+ 系。
   两套都在各自底色上核过对比度；行号和注释是最容易跌破 4.5:1 的两处。 */
.article__body .code {
  --code-bg: #fafafa;      /* 代码区 */
  --code-bar: #f0f0f0;     /* 窗口 chrome，与代码区差一档做层级 */
  --code-line: #e4e4e7;    /* chrome 与代码区的分隔线 */
  --code-edge: #e6e6e6;    /* 外描边 */
  --code-fg: #24292e; --code-com: #6a737d; --code-str: #0a3069; --code-kw: #cf222e;
  --code-type: #6f42c1; --code-fn: #8250df; --code-num: #0550ae; --code-attr: #0550ae;
  --code-ln: #6a737d;      /* 行号：#8c959f 只有 2.8:1，不达标 */
  --code-chrome-fg: #6a6a6f;   /* 语言标签：原 #6e6e73 on #f0f0f0 = 4.45:1，差 0.05 不达 AA；降一档 → 4.72:1 */
}
[data-theme="dark"] .article__body .code {
  --code-bg: #1e1e1e; --code-bar: #262626; --code-line: #333333; --code-edge: #2e2e2e;
  --code-fg: #d4d4d4; --code-com: #6a9955; --code-str: #ce9178; --code-kw: #569cd6;
  --code-type: #4ec9b0; --code-fn: #dcdcaa; --code-num: #b5cea8; --code-attr: #9cdcfe;
  --code-ln: #858585;      /* VS Code 原色 #6E7681 只有 3.63:1，提亮到此 = 4.52:1 */
  --code-chrome-fg: #8e8e8e;   /* 语言标签：原 #8b8b8b on #262626 = 4.44:1，差 0.06 不达 AA；提一档 → 4.62:1 */
}
.article__body .code {
  margin: var(--sp-5) 0;
  border-radius: var(--r-md); overflow: hidden;
  background: var(--code-bg); border: 1px solid var(--code-edge);
}
.article__body .code__bar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 14px; background: var(--code-bar); border-bottom: 1px solid var(--code-line);
}
/* 交通灯用真 macOS 色，IDE 窗口最强的识别信号（不随主题变） */
.article__body .code__dot { width: 10px; height: 10px; border-radius: var(--r-pill); flex: none; }
.article__body .code__dot:nth-of-type(1) { background: #ff5f57; }
.article__body .code__dot:nth-of-type(2) { background: #febc2e; }
.article__body .code__dot:nth-of-type(3) { background: #28c840; }
.article__body .code__lang {
  margin-left: auto; font-family: var(--font-mono); font-size: 0.812rem; font-weight: 500;
  letter-spacing: .04em; color: var(--code-chrome-fg);
}
/* 内部收紧（用户反馈「空格太多」）：padding 24→16、行高 1.75→1.6、行号区 3.1em→2.4em。
   外部 margin 仍为 --sp-5，与正文段落间距同节奏——只让块内更紧凑，不打乱整页呼吸。 */
.article__body .code pre {
  margin: 0; padding: var(--sp-3) var(--sp-4);
  background: none; border: 0; border-radius: 0; overflow-x: auto;
}
.article__body .code pre code {
  display: block; background: none; padding: 0;
  font-family: var(--font-mono); font-size: 0.812rem; line-height: 1.6;
  color: var(--code-fg); counter-reset: ln;
}
/* 行号：CSS counter 生成（不写死数字）。不做 sticky —— 长行横向滚动时
   sticky 行号会压在代码上，且需要不透明底色遮罩，得不偿失。 */
.article__body .code .ln { display: block; min-height: 1.6em; counter-increment: ln; }
.article__body .code .ln::before {
  content: counter(ln); display: inline-block; width: 1.6em; margin-right: .8em;
  text-align: right; user-select: none; color: var(--code-ln);
}
/* 窄屏：行号让位——省出约 2.4em 全给代码本身，减少横向滚动 */
@media (max-width: 640px) {
  .article__body .code .ln::before { display: none; }
}
.article__body .code .tok-com  { color: var(--code-com); font-style: italic; }
.article__body .code .tok-str  { color: var(--code-str); }
.article__body .code .tok-kw   { color: var(--code-kw); }
.article__body .code .tok-type { color: var(--code-type); }
.article__body .code .tok-fn   { color: var(--code-fn); }
.article__body .code .tok-num  { color: var(--code-num); }
.article__body .code .tok-attr { color: var(--code-attr); }
.article__body .code .tok-op   { color: var(--code-fg); }
.article__body .code .tok-id   { color: var(--code-fg); }

/* 文内视频（竖屏 9:16）：居中限宽，避免长条在宽屏被拉成巨幅；点击播放，不自动播 */
.article__body .article__video {
  margin: var(--sp-6) auto;
  width: min(420px, 100%);
}
.article__body .article__video video {
  display: block; width: 100%; height: auto;
  border-radius: var(--r-md); box-shadow: var(--sh-2);
  background: #000; cursor: pointer;
}
/* 原文出处（正文末尾「首发于…」小注）：由 data.js 的 source:{name,url} 通用渲染 */
.article__body .article__source {
  margin-top: var(--sp-7);
  font-size: 0.938rem; line-height: 1.7; color: var(--ink-3);
}

/* 原文配乐（v59g）：微信内嵌音乐搬不到站上、自托管 mp3 侵权；网易云对「原版 Imagine」是 VIP 曲
   （播放 API url=null，播放器渲染成空白）。改用 **Bilibili 官方 MV**（bvid=BV1G54y1y7bB，环球音乐中国
   官方投稿）——页内可播完整 3:56，国内访问最稳。代价：向 player.bilibili.com 发起外部请求，
   刻意打破「外部请求 0」，仅本篇加载，其余页面仍零外部。 */
/* 特异性 0,2,0：必须压过 `.article__body figure { margin: var(--sp-6) 0 }`（0,1,1），
   否则左右 margin 被归零、卡片靠左。 */
.article__body .article__music {
  margin: var(--sp-6) auto;
  max-width: 520px;
  background: var(--surface);
  border: 1px solid var(--hairline); border-radius: var(--r-md);
  padding: var(--sp-4);
}
[data-theme="dark"] .article__music { background: var(--card); }
.article__music__head {
  display: flex; align-items: center; gap: var(--sp-4);
}
/* 特异性 0,2,0：必须压过 `.article__body figure img`（配图清晰度规则，0,1,2），
   否则 width/height 被冲成 auto 并叠加卡片阴影与 cursor:zoom-in。 */
.article__body .article__music__cover {
  width: 64px; height: 64px; flex: none; display: block;
  margin: 0; border-radius: var(--r-sm); object-fit: cover;
  background: var(--card); box-shadow: none; cursor: default;
}
.article__music__body { min-width: 0; flex: 1; }
/* 特异性 0,2,0：必须压过 `.article__body p`（字号 18px/行高 1.8）与
   `.article__body p + p`（段距 --sp-5 = 24px），二者的特异性均为 0,1,1，
   否则曲名被放大成 18px、三行被撑成 24px 间距。 */
.article__body .article__music__label { font-size: 0.812rem; font-weight: 500; line-height: 1.4; color: var(--ink-3); margin: 0; }
.article__body .article__music__name { font-size: 1rem; font-weight: 700; line-height: 1.3; letter-spacing: -.02em; margin: 2px 0 0; }
.article__body .article__music__meta { font-size: 0.938rem; font-weight: 400; line-height: 1.4; color: var(--ink-3); margin: 2px 0 0; }
.article__music__open {
  flex: none; width: 32px; height: 32px; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--accent-ink); font-size: 0.938rem; line-height: 1; text-decoration: none;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .article__music__open:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
}
.article__music__open:active { transform: scale(var(--active-scale)); }
/* 16:9 视频容器：用 padding-bottom 兜底（不依赖 aspect-ratio，兼容老 Safari），
   播放器绝对定位铺满、圆角裁切、黑底兜底 */
.article__music__video {
  position: relative; width: 100%;
  height: 0; padding-bottom: 56.25%;
  margin: var(--sp-4) auto 0;
  border-radius: var(--r-sm); overflow: hidden; background: #000;
}
.article__body .article__music__player {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; border: 0; margin: 0;
}
/* 本地 file:// 预览兜底：Safari 拒绝渲染跨源 iframe（只见黑），
   改用「专辑封面 + 点击去 B 站播放」，与曲目一致。仅 file:// 生效，
   部署 https 仍走内嵌播放器（autoplay）。 */
.article__music__video.is-fallback { background: var(--surface); }
.article__music__fallback {
  position: absolute; inset: 0; display: block;
  text-decoration: none; overflow: hidden; color: #fff;
}
.article__music__poster {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.article__music__overlay {
  position: absolute; inset: 0; display: flex;
  flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); padding: var(--sp-4); text-align: center;
  background: linear-gradient(180deg, rgba(0,0,0,.15) 0%, rgba(0,0,0,.55) 100%);
}
.article__music__playbtn {
  width: 56px; height: 56px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.92); color: var(--accent-ink);
  box-shadow:var(--sh-pop);
  transition: transform var(--dur-fast) var(--ease);
}
.article__music__playbtn::before {
  content: ""; width: 0; height: 0; margin-left: 4px;
  border-style: solid; border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent var(--accent-ink);
}
.article__music__fallback:active .article__music__playbtn { transform: scale(var(--active-scale)); }
@media (hover: hover) and (pointer: fine) {
  .article__music__fallback:hover .article__music__playbtn { transform: scale(1.06); }
}
.article__music__hint {
  font-size: 0.812rem; font-weight: 500; line-height: 1.4;
  color: rgba(255,255,255,.92); max-width: 22em;
}
/* 宽屏：照片向右破栏，左缘贴正文、右缘贴版心右缘（文本左缘 + 808px），
   既放大观看、又绝不溢出 1200px 容器、不越右侧视口。
   几何：main 左缘 = toc-w(280)+gap(64)+容器内左留白(48) = 392px；
   距容器右缘 = 1200-392 = 808px → 取 800 留 8px 安全余量。
   **仅限「有目录」的两栏长文** —— 无目录单栏文章图与正文同宽（通用性保证）。
   HD 原图（1280px+）不变，点击灯箱看全分辨率。 */
@media (min-width: 1200px) {
  .article__layout:has(.article__toc) .article__body figure.article__fig {
    width: min(800px, calc(100vw - 400px));
    margin-left: 0;
  }
}

/* ---------- 阅读进度气泡（v76 建 / v77 改，仅文章详情页）----------
   取代 v73–v75 顶部自动隐藏工具条：独立、可拖动、常驻、用户自选位置（苹果浮动控件 / PiP 同款思路）。
   圆环 SVG 显示进度（accent 描边 + 浅色轨道），中心百分比（tabular-nums）；
   v77：拖动 = 完全自由漂浮（松手停在落点，仅视口夹紧）+ 记忆位置（localStorage）；
        点击 = 弹苹果式小菜单（.read-menu，回到顶部 / 返回列表）。不自动隐藏、不参与 .nav 互斥。
   v78：默认落点改左上角；加常驻「呼吸光晕 + 扩散波纹」（生命感）；待机 3s「退让」变淡缩小
        （移动端不压字）；窄屏 44px + 更薄玻璃。 */
.read-bubble {
  position: fixed; z-index: 80;
  left: 0; top: 0;                       /* 实际位置由 JS 注入 left/top */
  width: 48px; height: 48px; border-radius: var(--r-pill);
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 14%), transparent);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
          backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  box-shadow: 0 1px 2px rgba(20, 20, 22, .05), inset 0 1px 0 rgba(255, 255, 255, .45);
  color: var(--ink); text-decoration: none;
  opacity: 0; transform: scale(.82); pointer-events: none;
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
  cursor: grab; touch-action: none;       /* 拖动不触发页面滚动 */
  user-select: none; -webkit-user-select: none;
  -webkit-user-drag: none;                /* 禁用 <a> 原生链接拖拽，交给我们自管的拖动 */
}
.read-bubble.is-on { opacity: 1; transform: scale(1); pointer-events: auto; animation: rbBob 4s var(--ease-breathe) infinite; }
/* 呼吸 / 生命感（v78）：两个伪元素构成常驻的「活体」信号——
   ① ::before = 柔和的 accent 呼吸光晕（外发光，4s，与全站呼吸同频 --ease-breathe）；
   ② ::after  = 一圈从边缘缓缓扩散、消隐的波纹（心跳感，4s）。
   两者 pointer-events:none、只染边缘不遮中心，不引入第二种填充色。 */
.read-bubble::before {
  content: ''; position: absolute; inset: 0; border-radius: var(--r-pill); pointer-events: none;
  animation: rbGlow 4s var(--ease-breathe) infinite;
}
.read-bubble::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--r-pill); pointer-events: none;
  border: 1.5px solid color-mix(in srgb, var(--accent) 60%, transparent);
  animation: rbRipple 4s var(--ease-breathe) infinite;
}
@keyframes rbGlow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
  50%      { box-shadow: 0 0 16px 3px color-mix(in srgb, var(--accent) 36%, transparent); }
}
@keyframes rbRipple {
  0%   { transform: scale(.96); opacity: .42; }
  72%  { opacity: .05; }
  100% { transform: scale(1.85); opacity: 0; }
}
/* 待机「退让」态（v78）：静置 3s 无交互（滚动 / 指针 / 触摸）后，气泡轻轻变淡，
   让移动端阅读时不再压字；一有交互立即回到满态。pointer-events 始终可用 → 随时可点。
   悬停（精细指针）/ 按压 / 拖动 / 菜单展开时一律不进入该态。
   ⚠ v93（2026-10-20 全局走查）：**静置态不要再 scale**。
   transform 会连带缩小「点击热区」—— 44px 的气泡 scale(.95) 后只剩 41.8px，
   实测移动端静置态热区 42×42，低于 Apple HIG 的 44pt 下限。
   "退让"用 opacity 表达已经足够（.62 的对比很明显），没必要再动尺寸；
   热区恒定 ≥44px，任何时候都好点。 */
@media (hover: hover) and (pointer: fine) {
  .read-bubble.is-on.is-idle:not(.is-dragging):not(.is-active):not(:hover) { opacity: .62; }
  .read-bubble:hover { box-shadow: var(--sh-glass), var(--sh-pop); }
}
@media (hover: none) {
  .read-bubble.is-on.is-idle:not(.is-dragging):not(.is-active) { opacity: .62; }
}
.read-bubble.is-dragging {
  cursor: grabbing; box-shadow: var(--sh-glass), var(--sh-pop);
  transform: scale(1.06); transition: none;   /* 跟手时不加过渡，避免拖拽迟滞 */
  animation: none;                            /* v83 拖动时停掉轻浮动，严格跟手不抖 */
}
.read-bubble:active { transform: scale(.97); }
.read-bubble__ring {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg);                  /* 从 12 点方向起算进度 */
}
.read-bubble__track { fill: none; stroke: var(--line); stroke-width: 3; }
.read-bubble__bar {
  fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round;
  transition: stroke-dashoffset var(--dur-fast) linear;
}
.read-bubble__pct {
  /* v83·改：数字不再视觉显示——曾因 line-height:1.8 把盒子撑到 ~18px、胀出气泡骑到圆环下弧（重叠 bug），
     且与表情抢位。现改为**屏幕阅读器专用（sr-only）**：视觉隐藏、仅作 AT 兜底，进度由外圈圆环承担。 */
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
/* v83.1 · 中性化（用户反馈「太女性化」）——剥掉萌系女性化语言：
   删玫瑰腮红 / 删粉色耳内 / 删眼里高光(anime 水光眼) / 大眼收小为冷静点眼 / 咧嘴笑改克制小嘴。
   保留玻璃圆体 + accent 进度环 + 两只中性玻璃耳 + 眨眼·轻浮动·呼吸（生命感）+ 品牌蓝（AI 感/全站统一）。
   配色回到站点原生三色：玻璃 / ink(眼·嘴) / accent(环·光晕)——零粉色，性别中性、偏干净科技。 */
.read-bubble__ear {
  position: absolute; top: -6px; width: 13px; height: 14px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--card) calc(var(--glass-a) + 26%), transparent),
    color-mix(in srgb, var(--card) calc(var(--glass-a) + 4%), transparent));   /* 上亮下暗 → 立体 */
  -webkit-backdrop-filter: blur(16px) saturate(180%);
          backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line); border-bottom: none;   /* 底部与头顶融合，不露接缝 */
  border-radius: 8px 8px 3px 3px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.5), 0 1px 3px rgba(20,20,22,.10);   /* 顶高光 + 底投影 → 3D */
  pointer-events: none;
}
.read-bubble__ear--l { left: 10px;  transform: rotate(-14deg); transform-origin: bottom center; }
.read-bubble__ear--r { right: 10px; transform: rotate(14deg);  transform-origin: bottom center; }
.read-bubble__orb {                       /* 弥散光球（参照 AI 精灵）：顶高光 + 右下极光环境光 → 球体体积 */
  position: absolute; inset: 0; border-radius: var(--r-pill); pointer-events: none;
  background:
    radial-gradient(75% 55% at 30% 16%, rgba(255,255,255,.80), rgba(255,255,255,0) 60%),
    radial-gradient(125% 115% at 74% 92%, color-mix(in srgb, var(--accent) 42%, transparent), transparent 62%),
    radial-gradient(60% 60% at 84% 10%, color-mix(in srgb, var(--accent) 15%, transparent), transparent 60%);
}
/* ===== v85 · AI 精灵五官「生动化」（眼睛 + 嘴巴）=====
   调研依据（Pophie 角色动画 / OpenAI ChatGPT Dots 状态映射）：
   ① 眼睛必须有**角膜高光**——纯黑实心点 = 死眼，一颗白点高光立刻"湿润"；
   ② 虹膜要**极轻微漂移**（±0.5px）——人眼从不真正定格，静止即"死"；
   ③ 眨眼要自然（快闭慢开），左右眼**只让视线错开**、眨眼保持同步（真人双眼同步眨）；
   ④ 表情跟状态走：悬停＝专注（眼放大）、菜单展开＝注视、拖动＝俏皮眯眼。
   尺度约束：48px 精灵、眼仅 5.6px —— 只加"湿润感 + 微动"，不放大成动漫眼，守中性、零粉色。 */
.read-bubble__eye {
  position: absolute; top: 17.8px; width: 5.6px; height: 5.6px; border-radius: var(--r-pill);
  background: radial-gradient(circle at 34% 26%, var(--ink-2), var(--ink) 72%);
  transform-origin: center; overflow: hidden;
  animation: rbBlink 6.4s ease-in-out infinite, rbGaze 9.4s ease-in-out infinite;
  transition: scale var(--dur-fast) var(--ease);
  pointer-events: none;
}
.read-bubble__eye--l { left: 15.5px; }
.read-bubble__eye--r { right: 15.5px; animation-delay: 0s, -1.9s; }  /* 只让视线错开 1.9s → 自然视差 */
/* 角膜高光：小白点，缓慢呼吸闪烁（像光在湿眼球上游走） */
.read-bubble__eye::before {
  content: ''; position: absolute; top: .6px; left: 1px;
  width: 1.3px; height: 1.3px; border-radius: var(--r-pill);
  background: radial-gradient(circle, #fff 0%, rgba(255,255,255,.92) 55%, rgba(255,255,255,0) 76%);
  animation: rbGlint 4.3s ease-in-out infinite;
}
/* 下缘反光：极淡 accent 收边，让眼球像被环境光托起的一颗玻璃珠 */
.read-bubble__eye::after {
  content: ''; position: absolute; left: 14%; right: 14%; bottom: .35px; height: .8px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--accent) 62%, transparent);
  opacity: .28;
}
.read-bubble__mouth {                     /* 柔和立体小嘴：轻微呼吸缩放 + 随状态变化 */
  position: absolute; top: 28px; left: 50%; transform: translateX(-50%);
  width: 6.4px; height: 3.4px;
  border: 1.4px solid var(--ink); border-top-color: transparent;
  border-radius: 0 0 8px 8px; opacity: .58;
  transform-origin: center top;
  animation: rbSmile 5.4s var(--ease-breathe) infinite;
  transition: width var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
  pointer-events: none;
}
/* 状态：悬停＝专注；菜单展开＝注视（眼略大、笑意更浓） */
@media (hover: hover) and (pointer: fine) {
  .read-bubble:hover .read-bubble__eye { scale: 1.16; }
  .read-bubble:hover .read-bubble__mouth { width: 7.2px; opacity: .82; }
}
/* 菜单展开 = 「倾听/注视」态：眼略大 + 小圆嘴（像"哦"），表情真的变了，而不只是变宽 */
.read-bubble.is-active .read-bubble__eye { scale: 1.1; }
.read-bubble.is-active .read-bubble__mouth {
  width: 4.2px; height: 4.2px; border-color: var(--ink); border-radius: 50%;
  opacity: .82; animation: none;
}
/* 拖动＝俏皮眯眼（松手即停，不吸附） */
.read-bubble.is-dragging .read-bubble__eye { animation: none; scale: 1.14 .72; }

@keyframes rbBlink {
  0%, 89%, 100% { transform: scaleY(1); }   /* 快闭 */
  92%           { transform: scaleY(.05); }
  95%           { transform: scaleY(1); }   /* 稍慢开 → 自然 */
}
@keyframes rbGaze {                          /* 独立 translate 属性 → 与眨眼的 transform 叠加不打架 */
  0%, 100% { translate: 0 0; }
  20% { translate: .5px -.1px; }
  43% { translate: .28px .18px; }
  66% { translate: -.5px 0; }
  84% { translate: -.18px -.15px; }
}
@keyframes rbGlint {
  0%, 100% { opacity: .9;  translate: 0 0; }
  50%      { opacity: .45; translate: .18px .1px; }
}
@keyframes rbSmile {
  0%, 100% { transform: translateX(-50%) scaleX(1); }
  50%      { transform: translateX(-50%) scaleX(1.07); }
}
@keyframes rbBob {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -2.5px; }
}
[data-theme="dark"] .read-bubble {
  background: color-mix(in srgb, var(--surface) calc(var(--glass-a) + 16%), transparent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .24), inset 0 1px 0 rgba(255, 255, 255, .07);
}
[data-theme="dark"] .read-bubble__ear {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--surface) calc(var(--glass-a) + 6%), transparent),
    color-mix(in srgb, var(--surface) calc(var(--glass-a) - 6%), transparent));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.10), 0 1px 3px rgba(0,0,0,.34);
}
[data-theme="dark"] .read-bubble__orb {
  background:
    radial-gradient(75% 55% at 30% 16%, rgba(255,255,255,.20), rgba(255,255,255,0) 60%),
    radial-gradient(125% 115% at 74% 92%, color-mix(in srgb, var(--accent) 60%, transparent), transparent 62%),
    radial-gradient(60% 60% at 84% 10%, color-mix(in srgb, var(--accent) 22%, transparent), transparent 60%);
}
[data-theme="dark"] .read-bubble__eye {
  /* 深色与浅色同为一颗"深玻璃珠"，只多一道**内侧轮廓光**：
     暗底上靠亮边勾出眼形，白高光落在深珠上才清晰（白珠/灰珠都试过，高光会消失）。 */
  background: radial-gradient(circle at 34% 26%, #555b64, #16181c 80%);
  box-shadow: inset 0 0 0 .7px rgba(255, 255, 255, .38),
              inset 0 -1px 2px rgba(0, 0, 0, .5);
}
[data-theme="dark"] .read-bubble__eye::before {
  /* 高光：深珠上清晰的白点 */
  top: .6px; left: 1px; width: 1.3px; height: 1.3px;
  background: radial-gradient(circle, #fff 0%, rgba(255,255,255,.95) 60%, rgba(255,255,255,0) 78%);
  opacity: 1;
}
[data-theme="dark"] .read-bubble__eye::after {    /* 下缘反光在深色里提亮一点，配合轮廓光 */
  background: color-mix(in srgb, var(--accent) 78%, transparent);
  opacity: .38;
}
/* 气泡展开菜单时的「锚定」态：一圈极淡的 accent 光晕，告诉用户「菜单从这里弹出」，
   不抢戏、只是把源控件和浮层的关系说出来（与 iOS 长按浮层同源思路）。 */
.read-bubble.is-active {
  box-shadow: var(--sh-glass), var(--sh-pop),
              0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}
/* 移动端（v78）：更小（48→44）+ 玻璃更薄（压字更轻），配合「待机退让」把遮挡降到最低 */
@media (max-width: 640px) {
  .read-bubble { width: 44px; height: 44px; background: color-mix(in srgb, var(--card) var(--glass-a), transparent); }
  [data-theme="dark"] .read-bubble { background: color-mix(in srgb, var(--surface) calc(var(--glass-a) + 2%), transparent); }
  .read-bubble__pct { /* 已 sr-only，无需移动端覆盖 */ }
  /* 移动端「AI 精灵」等比缩放：耳/眼/嘴随 44px 头部收一档，玻璃同值（v83.2 耳改立体渐变） */
  .read-bubble__ear { top: -5px; width: 12px; height: 13px; background: linear-gradient(180deg, color-mix(in srgb, var(--card) calc(var(--glass-a) + 12%), transparent), color-mix(in srgb, var(--card) calc(var(--glass-a) - 6%), transparent)); }
  .read-bubble__eye { top: 16.3px; width: 5.1px; height: 5.1px; }
  .read-bubble__eye--l { left: 14.2px; }
  .read-bubble__eye--r { right: 14.2px; }
  .read-bubble__mouth { top: 25.7px; width: 5.9px; height: 3.1px; }
  [data-theme="dark"] .read-bubble__ear { background: linear-gradient(180deg, color-mix(in srgb, var(--surface) calc(var(--glass-a) + 2%), transparent), color-mix(in srgb, var(--surface) calc(var(--glass-a) - 10%), transparent)); }
}
@media (prefers-reduced-motion: reduce) {
  .read-bubble::before, .read-bubble::after { animation: none; }
  .read-bubble, .read-bubble__eye,
  .read-bubble__eye::before, .read-bubble__mouth { animation: none; }  /* 关轻浮动 / 眨眼 / 视线 / 高光闪烁 / 嘴呼吸 */
}

/* ---------- 气泡操作菜单（v77 建 · v79 重设计，苹果式小浮层）----------
   点气泡就地弹出磨砂小菜单：回到顶部 / 返回列表。
   设计语言 = iOS / macOS 上下文菜单：磨砂玻璃底 + 发丝描边 + 轻投影，从气泡方向缩放展开。
   **v79 重设计**（用户：「这两个按钮没有设计感」）：
   ① 比例舒展：容器 min-width 168 / padding 6，行 padding 10×14、图标·文字间距 12 → 行高约 38px；
   ② 图标更精：18px、stroke 1.8（原 2 在 18px 下偏「重」，1.8 更利落）；
   ③ **方向感知 hover 提前量（本次点睛）**：悬「回到顶部」时 ↑ 上移 2px、悬「返回列表」时 ← 左移 2px
      —— 图标语义与它的动作方向一致，指哪儿动哪儿（呼应全站「hover 提前量」的招牌手法）；
   ④ hover 底改**中性极浅灰**（`--ink 7%`）而非原 accent 蓝块：蓝块在玻璃上偏「网页下拉」，
      中性灰更接近 macOS 菜单的克制感，品牌蓝只留在图标描边里（组件内填充色仍只有一种）。
   动效 ≤ --dur-base，缓动 --ease。 */
.read-menu {
  position: fixed; z-index: 90;          /* 高于气泡(80) */
  min-width: 168px; padding: 6px;
  display: flex; flex-direction: column; gap: 2px;
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 22%), transparent);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
          backdrop-filter: blur(24px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-glass), var(--sh-pop);
  /* 收起：淡出 + 缩回 + 延迟隐藏（visibility 跟随，避免占位/误触） */
  opacity: 0; visibility: hidden; transform: scale(.9);
  transform-origin: center;
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              visibility 0s linear var(--dur-fast);
}
.read-menu.is-open {
  opacity: 1; visibility: visible; transform: scale(1);
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur-base) var(--ease),
              visibility 0s;
}
.read-menu__item {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 10px 14px;
  border: 0; background: transparent;
  font: inherit; font-size: 0.938rem; font-weight: 500; color: var(--ink);
  letter-spacing: -0.01em;
  text-align: left; border-radius: var(--r-sm);
  cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.read-menu__item svg {
  width: 18px; height: 18px; flex: 0 0 18px;
  fill: none; stroke: var(--accent); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--dur-base) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  /* 中性极浅灰底（--ink 混色在浅/深两主题都自适应），比原蓝块克制 */
  .read-menu__item:hover { background: color-mix(in srgb, var(--ink) 7%, transparent); }
  /* 方向感知：↑ 上移 / ← 左移，图标跟着动作方向动 */
  .read-menu__item[data-act="top"]:hover svg  { transform: translateY(-2px); }
  .read-menu__item[data-act="list"]:hover svg { transform: translateX(-2px); }
}
.read-menu__item:active {
  background: color-mix(in srgb, var(--ink) 11%, transparent);
  transform: scale(var(--active-scale));
}
[data-theme="dark"] .read-menu {
  background: color-mix(in srgb, var(--surface) calc(var(--glass-a) + 24%), transparent);
}

/* ── 分隔线：把「导航动作」与「AI」分成两类 ───────────────────────────── */
.read-menu__sep {
  height: 1px; margin: 5px 8px; background: var(--line); flex: none;
}

/* ── AI 项：一眼看出「这是 AI 入口」（v87）──────────────────────────────
   全部复用站点**已有**的 Apple Intelligence 语汇，不新造任何一种颜色：
     ① 1px 光谱环（--ai-1 → --ai-2 → --ai-3）—— 与提问条光谱边、Tab 选中环同源，
        用 mask 挖空实现（box-shadow 做不出渐变光谱，这是站内已验证的结论）；
     ② sparkle 图标染 --ai-2 + 极淡辉光（与 aiTitleGlow 同族）；
     ③ 底只有 ≤6% 的光谱淡光 —— 是「光」不是「色块」，守「一组件一种填充」；
     ④ sparkle 缓呼吸（7s，与提问条 aiSpark 同频）。
   与另两项（回到顶部 / 返回列表）的区别是**类别**而非强弱：那两个是导航，
   这一个是 AI —— 所以靠分隔 + 光谱环 + 图标共同声明，而不是把字加粗加大。 */
.read-menu__item[data-act="ai"] {
  position: relative; isolation: isolate;      /* 让 ::before 的 z-index:-1 只在本项内生效 */
  background: rgba(var(--ai-2-rgb), .06);
}
.read-menu__item[data-act="ai"] svg {
  stroke: var(--ai-2);                          /* 兜底：不支持渐变时的单色 */
  filter: drop-shadow(0 0 6px rgba(var(--ai-2-rgb), .45));
}
/* sparkle 光谱描边：渐变本身在 SVG 里（inline stroke 引用 #rbSparkGrad），
   这里只灌三个停靠点 = --ai-1 → --ai-2 → --ai-3，双主题各自取色，SVG 里不写死颜色。 */
.read-menu__item[data-act="ai"] #rbSparkGrad stop:nth-of-type(1) { stop-color: var(--ai-1); }
.read-menu__item[data-act="ai"] #rbSparkGrad stop:nth-of-type(2) { stop-color: var(--ai-2); }
.read-menu__item[data-act="ai"] #rbSparkGrad stop:nth-of-type(3) { stop-color: var(--ai-3); }
/* 光谱描边环（同 Tab 选中环 / 提问条光谱边的做法） */
@supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
  .read-menu__item[data-act="ai"]::before {
    content: ''; position: absolute; inset: 0; border-radius: inherit; z-index: -1;
    padding: 1px; pointer-events: none;
    background: linear-gradient(100deg, var(--ai-1) 0%, var(--ai-2) 55%, var(--ai-3) 100%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
  }
}
@keyframes rbAiSpark {
  0%, 100% { transform: scale(1) rotate(0deg); opacity: .9; }
  50%      { transform: scale(1.14) rotate(6deg); opacity: 1; }
}
@media (prefers-reduced-motion: no-preference) {
  .read-menu__item[data-act="ai"] svg { animation: rbAiSpark 7s ease-in-out infinite; }
}
@media (hover: hover) and (pointer: fine) {
  /* hover 仍是「光更亮」而不是换底色 —— 与另两项的中性灰 hover 明确区分 */
  .read-menu__item[data-act="ai"]:hover { background: rgba(var(--ai-2-rgb), .13); }
  .read-menu__item[data-act="ai"]:hover svg { filter: drop-shadow(0 0 9px rgba(var(--ai-2-rgb), .62)); }
}

/* ── 气泡「一次性发现提示」（v87）───────────────────────────────────────
   文章页去掉底部 AI 条后，气泡是唯一 AI 入口。首次进入文章给一次极轻提示，
   5.2s 自动收，localStorage 记下后永不再现。
   ⚠ 脉冲挂在**提示胶囊本身**，不挂气泡 —— 气泡已有 rbBob 呼吸，同元素叠 animation 会互相顶掉。 */
.read-bubble__hint {
  position: absolute; left: calc(100% + 10px); top: 50%;
  z-index: 2; white-space: nowrap; pointer-events: none;
  padding: 6px 11px; border-radius: var(--r-pill);
  font-size: 0.812rem; font-weight: 500; letter-spacing: -0.01em; color: var(--ink);
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 22%), transparent);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
          backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--line);
  box-shadow: var(--sh-pop);
  /* 独立的 translate + scale，避免与任何 transform 叠加冲突 */
  translate: 0 -50%; scale: .92; opacity: 0;
  transition: opacity var(--dur-base) var(--ease), scale var(--dur-base) var(--ease);
}
.read-bubble.is-hinting .read-bubble__hint { opacity: 1; scale: 1; }
.read-bubble__hint.is-gone { opacity: 0; }
/* 气泡在右半屏 → 提示挂到左侧，避免出屏 */
.read-bubble.hint-left .read-bubble__hint { left: auto; right: calc(100% + 10px); }
@keyframes rbHintPulse {
  0%, 100% { box-shadow: var(--sh-pop); }
  50%      { box-shadow: var(--sh-pop), 0 0 14px 2px rgba(var(--ai-2-rgb), .30); }
}
@media (prefers-reduced-motion: no-preference) {
  .read-bubble.is-hinting .read-bubble__hint { animation: rbHintPulse 1.8s var(--ease-breathe) infinite; }
}
[data-theme="dark"] .read-bubble__hint {
  background: color-mix(in srgb, var(--surface) calc(var(--glass-a) + 24%), transparent);
}

/* v64：移动端正文 18 → 17px。18px 在 390 屏只有 342px 可用宽 ≈ 19 字/行，
   换行偏碎；17px 约 20 字/行，更接近中文阅读的舒适节奏。
   只针对 ≤640px；blockquote(16px) / embed(18px) / 题眼(24px) / 收尾(20px) 特异性更高，不受影响。 */
@media (max-width: 640px) {
  .article__body p { font-size: 1.062rem; }
}

/* =========================================================================
   图片灯箱（v66 重做：点击正文图片放大，支持翻页 / 键盘 / 滑动 / 焦点陷阱）
   -------------------------------------------------------------------------
   核心改动 = **舞台固定尺寸**。此前 .lightbox__stage 跟着图片尺寸伸缩，
   切换不同宽高比的图时整个容器连同图注左右跳（实测宽度 540↔961 跳 421px）。
   现在外框恒宽，图片在框内居中缩放 → 图注与计数的位置稳定不动，
   切换瞬间剩下的尺寸差再由「淡出 → 换图 → 淡入」掩盖掉。
   ========================================================================= */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-6);
  background: rgba(0, 0, 0, .86);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur-base) var(--ease), visibility var(--dur-base) var(--ease);
}
.lightbox.is-open { opacity: 1; visibility: visible; }
.lightbox__stage {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  /* 左右各留出 84px 通道给导航按钮 —— 否则窄一点的桌面窗口上按钮会压到图上 */
  width: min(1100px, calc(100vw - 168px));
  max-height: 92vh;
}
.lightbox__frame {
  width: 100%; height: min(72vh, 820px); min-height: 0;
  display: flex; align-items: center; justify-content: center;
}
.lightbox__img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  border-radius: var(--r-md);
  box-shadow:var(--sh-pop);
  background: #fff;
  transition: opacity .16s var(--ease);   /* v66b：与 JS 里 130ms 的淡出等待匹配 */
}
/* 切换中：先淡出，等新图解码完再淡入（掩盖不同宽高比带来的尺寸变化） */
.lightbox__img.is-swapping { opacity: 0; }
.lightbox__cap { color: #fff; font-size: 0.938rem; opacity: .82; text-align: center; max-width: 90%; }
.lightbox__close, .lightbox__nav {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255, 255, 255, .25); background: rgba(255, 255, 255, .08);
  color: #fff; cursor: pointer; border-radius: var(--r-pill);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.lightbox__close { top: var(--sp-4); right: var(--sp-4); width: 44px; height: 44px; }
.lightbox__nav { top: 50%; transform: translateY(-50%); width: 48px; height: 48px; }
.lightbox__nav--prev { left: var(--sp-4); }
.lightbox__nav--next { right: var(--sp-4); }
@media (hover: hover) and (pointer: fine) {
  .lightbox__close:hover, .lightbox__nav:hover { background: rgba(255, 255, 255, .18); }
}
.lightbox__close:active { transform: scale(var(--active-scale)); }
.lightbox__nav:active { transform: translateY(-50%) scale(var(--active-scale)); }

/* ════════════════════════════════════════════════════════════════════
   玻璃通透度控制（v81 · ③ 连续滑块）
   位置：导航栏内、紧贴主题切换按钮（同属「外观」簇，常驻可见）
   交互：点按钮 → 玻璃小面板（自身亦随 --glass-a 实时变化，即时反馈）
   滑块：左「通透」/ 右「沉稳」，中点 = 标准（站点现值 64%）
   ════════════════════════════════════════════════════════════════════ */
.glass-toggle {                       /* 注入到 .nav__links，紧跟 #themeBtn */
  position: relative;
}
.glass-panel {
  position: fixed; top: 58px; right: 14px; width: 264px; z-index: 92;
  padding: 14px 16px 15px;
  border-radius: var(--r-pop, 16px);
  border: 1px solid var(--line-strong);
  box-shadow: var(--sh-pop);
  /* 自身亦响应滑块（与 86% 强玻璃弹层同档），拖动时即时可见浓淡变化 */
  background: color-mix(in srgb, var(--card) calc(var(--glass-a) + 22%), transparent);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  opacity: 0; visibility: hidden; transform: translateY(-6px) scale(.98);
  transform-origin: top right;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), visibility 0s linear var(--dur-fast);
}
.glass-panel.is-open { opacity: 1; visibility: visible; transform: none; transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
[data-theme="dark"] .glass-panel { background: color-mix(in srgb, var(--surface) calc(var(--glass-a) + 24%), transparent); }
.glass-panel__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.glass-panel__title { font-size: 0.938rem; font-weight: 700; color: var(--ink); letter-spacing: -0.01em; }
.glass-panel__reset {
  appearance: none; border: 0; background: none; padding: 2px 4px; cursor: pointer;
  font-size: 0.812rem; font-weight: 500; color: var(--accent);
}
.glass-panel__reset:hover { color: var(--accent-deep); }
.glass-panel__row { display: flex; align-items: center; gap: 10px; }
.glass-panel__end { font-size: 0.812rem; color: var(--ink-3); flex: none; user-select: none; }
.glass-panel__hint {
  margin-top: 10px; font-size: 0.812rem; color: var(--ink-3); text-align: center;
  font-variant-numeric: tabular-nums;
}
/* ── 滑块（Apple 风：细轨道 + 白色圆纽 + 焦点环）── */
.glass-range {
  -webkit-appearance: none; appearance: none; width: 100%; height: 22px;
  background: transparent; cursor: pointer; margin: 0;
}
.glass-range:focus { outline: none; }
.glass-range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 3px;
  background: linear-gradient(to right, var(--accent) var(--p, 50%), var(--range-track) var(--p, 50%));
}
.glass-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 20px; height: 20px; margin-top: -7px; border-radius: 50%;
  background: #fff; border: 0;
  box-shadow: 0 1px 4px rgba(0,0,0,.28), 0 0 0 .5px rgba(0,0,0,.06);
  transition: transform var(--dur-fast) var(--ease);
}
.glass-range:active::-webkit-slider-thumb { transform: scale(1.08); }
.glass-range::-moz-range-track { height: 6px; border-radius: 3px; background: var(--range-track); }
.glass-range::-moz-range-progress { height: 6px; border-radius: 3px; background: var(--accent); }
.glass-range::-moz-range-thumb {
  width: 20px; height: 20px; border: 0; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.28), 0 0 0 .5px rgba(0,0,0,.06);
}
/* 键盘可达：焦点环镜像 hover */
.glass-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 1px 4px rgba(0,0,0,.28), 0 0 0 4px var(--accent-soft); }
.glass-range:focus-visible::-moz-range-thumb { box-shadow: 0 1px 4px rgba(0,0,0,.28), 0 0 0 4px var(--accent-soft); }

[data-theme="dark"] { --range-track: rgba(120,120,128,.36); }
.lightbox__count {
  position: absolute; bottom: var(--sp-4); left: 50%; transform: translateX(-50%);
  color: #fff; font-size: 0.812rem; opacity: .7; font-variant-numeric: tabular-nums;
}
/* 只有一张图时不显示翻页控件和「1 / 1」—— 没有可翻的内容却摆着按钮是噪音 */
.lightbox.is-single .lightbox__nav,
.lightbox.is-single .lightbox__count { display: none; }

/* 移动端：按钮从「垂直居中压在图上」改成**底部一条控制条**，
   不再遮挡照片；翻页主要交给滑动手势。 */
@media (max-width: 640px) {
  .lightbox { padding: var(--sp-4); }
  .lightbox__stage { width: calc(100vw - 32px); }
  .lightbox__frame { height: 58vh; }
  .lightbox__nav { top: auto; bottom: var(--sp-5); transform: none; width: 44px; height: 44px; }
  .lightbox__nav--prev { left: 24px; }
  .lightbox__nav--next { right: 24px; }
  .lightbox__nav:active { transform: scale(var(--active-scale)); }
  .lightbox__count { bottom: var(--sp-5); line-height: 44px; }   /* 与按钮垂直居中对齐 */
}

/* ---------- 页脚备案号链接（法律强制展示） ----------
   要求：视觉上必须是「原页脚多了一段灰色小字」，不得引入任何新样式语言。
   做法：只做「去浏览器默认」——color:inherit 取父级 .footer__note 的 --ink-3 灰、
   字号由继承自然等同（0.938rem）、默认无下划线。hover 才给下划线，
   与站内既有链接语汇一致。作用域严格限定在 #footerNote 内，不污染任何其它链接。 */
/* 移动端触控（③）：备案号是**行内**链接，实测 170×19 < 44pt。
   行内元素的垂直 padding 会扩大命中区、却**不参与行盒高度计算** → 命中区 19+26=45px ✅
   而视觉零位移（这也是行内链接扩触控区的标准做法，不能用 margin 去抵消，inline 垂直 margin 本就无效）。 */
#footerNote a{color:inherit;text-decoration:none;padding-top:13px;padding-bottom:13px}
#footerNote a:hover{text-decoration:underline}

/* ════════════════════════════════════════════════════════════════════
   旧设备极光 + 玻璃兜底（Change 1 · 2026-10-17）
   不支持 color-mix() 的浏览器（Safari <16.2 / Chrome <111 等）：
   ① 极光 token --au-1…--au-5 用手算静态 RGB 兜底，避免 .aurora 整片消失；
   ② 结构性玻璃表面（.glass / .tabbar / .tabbar__ico）补静态 rgba，
      避免 background/border 因 color-mix 失效而变透明「消失」。
   计算规则：color-mix(in srgb, A p%, B) = 每通道 p%×A + (100−p)×B。
   支持 color-mix 的浏览器不会进入本块，观感零差异。
   ════════════════════════════════════════════════════════════════════ */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  /* ── 浅色（默认 data-theme="light"）── */
  :root {
    --au-1: rgb(196, 222, 249);   /* mix(accent #0071e3 23%, #fff) */
    --au-2: rgb(233, 232, 255);   /* mix(ai-2 #7d7aff 17%, #fff) */
    --au-3: rgb(228, 248, 246);   /* mix(#30c8b8 13%, #fff) */
    --au-4: rgb(247, 235, 253);   /* mix(ai-3 #bf5af2 12%, #fff) */
    --au-5: rgb(255, 250, 226);   /* mix(#ffd60a 12%, #fff) */
  }
  /* 玻璃表面：与默认 --glass-a=64% 解析值对齐（.glass 55% / .tabbar 76%） */
  .glass { background: var(--card); border-color: rgba(0, 0, 0, .06); }
  .tabbar {
    background: rgba(255, 255, 255, .76);
    border-color: rgba(0, 0, 0, .06);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), inset 0 1px 0 rgba(255, 255, 255, .25), 0 14px 36px -10px rgba(20, 20, 22, .30);
  }
  .tabbar__ico {
    background-color: rgba(255, 255, 255, .08);
    border-color: rgba(29, 29, 31, .08);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), 0 1px 3px -2px rgba(29, 29, 31, .14);
  }
  .tabbar__link:active { background: rgba(29, 29, 31, .06); }
  .tabbar__link.is-active .tabbar__ico { background-color: rgba(0, 113, 227, .10); }
}

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  /* ── 深色（[data-theme="dark"]）── */
  [data-theme="dark"] {
    --au-1: rgb(18, 50, 83);      /* mix(accent #0a84ff 25%, surface #14161a) */
    --au-2: rgb(38, 39, 65);      /* mix(ai-2 #7d7aff 17%, #14161a) */
    --au-3: rgb(25, 50, 50);      /* mix(#3adbc8 14%, #14161a) */
    --au-4: rgb(43, 36, 53);      /* mix(ai-3 #d68cff 12%, #14161a) */
    --au-5: rgb(53, 49, 24);      /* mix(#ffd60a 14%, #14161a) */
  }
  [data-theme="dark"] .glass { background: #14161a; border-color: rgba(255, 255, 255, .12); }
  [data-theme="dark"] .tabbar { border-color: rgba(255, 255, 255, .12); }
}
