/* ============================================================================
   无名肆 · 全站共用样式（2026-10-14 重设计版）
   ----------------------------------------------------------------------------
   source: .kb/style.md（通用总纲：克制/排版第一/动效纪律/近黑暗淡/零阴影）
   source: .kb/categories/personal-site.md（个人站：极简 + 一个记忆点 + 等宽终端风）
   source: design-dna｜yamachun.com §3 Token / §5 组件规格 / §6 交互与动效 /
           §7 视觉语言 / §8 排版 / §11 模仿指南 / §12 反模式

   设计方向：「终端观测站」
   —— 双主题（深色默认 / 浅色可选），全站等宽字体，单一强调色（暗=白、浅=近黑，
      强调色只做「反转」不做彩色），语义色只进状态标签。层次全靠灰阶 + 1px 边框
      + 底色微亮，零阴影。动效两条曲线、两档时长、错峰 0.08s，全部尊重
      prefers-reduced-motion。

   与旧版的迁移说明（2026-10-14）：
   · --kb-* 变量名一个不改（改现有站点先复用别新建），只把「单套深色值」升级为
     「双主题两套值」：:root 恒为深色（默认深色，老大 2026-10-14 定），
     html[data-theme="light"] 覆盖为浅色。主题切换由各页 head 的防闪烁片段 +
     ui.js 完成，0.4s 全局颜色过渡（yamachun §2.7 同款手法）。
   · 新增组件层（按钮/表单/卡片/表格/弹窗/抽屉/Toast/状态标签/纵向导航）：
     本站此前没有这些元素，这一层是给后续页面（文章系统等）备的表现层地基，
     全部状态矩阵（默认/悬停/聚焦/禁用/加载）在 site/kit.html 可逐项验收。
   · --wall-* 展框五套方案原样保留：照片墙的「白」是展框/卡纸，刻意与站点主题
     解耦，别改成 --kb-surface（改了展框就没了）。
   ============================================================================ */

/* ---------- 主题一：深色（默认，:root 恒载，防闪烁） ---------- */
:root {
  color-scheme: dark;

  /* —— 颜色·背景与表面 —— */
  --kb-bg: #0a0a0a;                 /* 页面底（近黑，非纯黑） */
  --kb-surface: #111111;            /* 面板/卡片表面 */
  --kb-surface-hover: #1c1c1c;      /* hover / 代码块底 */

  /* —— 颜色·文字（三级灰阶，深底对比度：≈14:1 / ≈7.4:1 / ≈5.6:1，均 ≥4.5） —— */
  --kb-text: #dddddd;               /* 正文 */
  --kb-text-strong: #ffffff;        /* 强调 / 标题 / 焦点环 */
  --kb-text-2: #9a9a9a;             /* 次要文字 */
  --kb-text-3: #888888;             /* 弱化文字（元信息/占位） */

  /* —— 颜色·边框 —— */
  --kb-border: #222222;
  --kb-border-hover: #333333;

  /* —— 强调色：只有一个，且只是「反色」（暗色主题=白）。
       彩色只留给语义状态，全站没有第二种装饰色。 —— */
  --kb-accent: #ffffff;
  --kb-on-accent: #0a0a0a;          /* 强调底上的文字 */

  /* —— 语义色（仅状态标签/Toast；深底对比度均已 ≥4.5） —— */
  --kb-ok: #4caf50;   --kb-ok-bg: rgba(76, 175, 80, .12);
  --kb-bad: #f46a5e;  --kb-bad-bg: rgba(244, 67, 54, .14);
  --kb-warn: #e8b33c; --kb-warn-bg: rgba(232, 179, 60, .12);
  --kb-scrim: rgba(0, 0, 0, .62);   /* 弹窗遮罩 */

  /* —— 字体：全站等宽（cassie.codes 式终端风速成法） —— */
  --kb-font-mono: "Courier New", Courier, "Microsoft YaHei", "PingFang SC", monospace;
  --kb-font-base: 17px;             /* source: .kb/style.md §三 正文 ≥16px */

  /* —— 字号阶梯（12/13/14/16/17/20/28/40/52，不成零散值） —— */
  --kb-text-xs: 12px;               /* 元信息 / 标签 */
  --kb-text-sm: 13px;               /* 辅助说明 */
  --kb-text-md: 14px;               /* UI 控件 / 导航 */
  --kb-text-lg: 20px;               /* 区块标题 */
  --kb-text-xl: 28px;               /* 页面标题 */
  --kb-text-2xl: 40px;              /* 大标题 */
  --kb-text-3xl: 52px;              /* 首屏站名 */

  /* —— 间距：4 的倍数刻度；区块垂直间距大方 —— */
  --kb-space-section: 96px;         /* source: .kb/style.md §四 区块 80–120px */
  --kb-space-card: 24px;            /* 卡片内边距（style.md §四：20–32px） */
  --kb-wrap: 680px;                 /* 阅读宽度（一行约四十个汉字） */
  --kb-wrap-wide: 960px;            /* 宽内容（表格/卡片栅格） */

  /* —— 圆角：个人主页类 ≤6px，成两级阶梯 —— */
  --kb-radius-sm: 2px;              /* 标签 / 芯片 */
  --kb-radius: 4px;                 /* 默认（按钮/输入/卡片/面板） */

  /* —— 阴影：零。层次靠边框与底色，不靠投影（style.md §六 + personal-site.md） —— */

  /* —— 动效：两条曲线、两档时长、一个错峰步长（style.md §七 纪律） —— */
  --kb-ease: cubic-bezier(.4, 0, .2, 1);          /* 标准曲线：hover/微交互/提示 */
  --kb-ease-emph: cubic-bezier(.75, 0, .25, 1);   /* 对称曲线：结构动画（切页/展开/灯箱） */
  --kb-dur: .15s;                 /* 微交互 */
  --kb-dur-slow: .34s;            /* 结构变化（切页/弹窗/Toast/进场） */
  --kb-stagger: .08s;             /* 多层入场的正向延迟步长 */
  --kb-theme-dur: .4s;            /* 明暗切换的全局颜色过渡（yamachun §2.7） */
}

/* ---------- 主题二：浅色（近白米色，yamachun §3 同款 #f9f9f7） ---------- */
html[data-theme="light"] {
  color-scheme: light;

  --kb-bg: #f9f9f7;
  --kb-surface: #ffffff;
  --kb-surface-hover: #f0efec;

  /* 浅底对比度：≈15:1 / ≈5.9:1 / ≈4.6:1，均 ≥4.5（text-3 特意不用 #888，
     那个值在浅底只有 ≈3.5:1，会踩 style.md §二 的红线） */
  --kb-text: #222222;
  --kb-text-strong: #141414;
  --kb-text-2: #666666;
  --kb-text-3: #6f6f6f;

  --kb-border: #e0e0e0;
  --kb-border-hover: #c6c6c6;

  --kb-accent: #141414;            /* 强调色反转为近黑（非纯黑 #000） */
  --kb-on-accent: #f9f9f7;

  --kb-ok: #1e7d32;   --kb-ok-bg: rgba(30, 125, 50, .10);
  --kb-bad: #c62828;  --kb-bad-bg: rgba(198, 40, 40, .10);
  --kb-warn: #8a6300; --kb-warn-bg: rgba(138, 99, 0, .12);
  --kb-scrim: rgba(20, 20, 20, .38);
}

/* ================= 照片墙展框（与整站主题刻意解耦） =================
   整站变浅之后，照片墙那一屏不能跟着变浅 —— 它的「白」不是页面底色，
   是装照片的卡纸 / 展框。所以这里不看 --kb-*，单独开一组 --wall-*，
   由 <html data-frame="…"> 切换。默认（不写属性）= ① 白展框。
   切换开关在照片墙页的调试面板里（「展框」一项）。
   照片墙页本身固定深色（data-theme="dark" 写死），展框方案就是它的主题。 */
:root {
  --wall-frame: #ffffff;            /* 展框底：照片之间露出来的颜色 */
  --wall-img-shade: #ebebeb;        /* 图片未到时的占位底 */
  --wall-ink: #1a1a1a;              /* 展框上的主文字 */
  --wall-ink-dim: #6a6a6a;          /* 展框上的次要文字 */
  --wall-chip: #ffffff;             /* HUD 信息牌底 */
  --wall-line: #d5d5d5;             /* HUD 描边 */
  --wall-line-hover: #b0b0b0;
  --wall-lb: rgba(18, 18, 18, .86); /* 灯箱遮罩 */
  --wall-focus: #1a1a1a;            /* 展框上的焦点环 */
}

/* ② 卡纸暖白：像美术馆的米白卡纸，比纯白柔一点 */
html[data-frame="paper"] {
  --wall-frame: #f2efe9;
  --wall-img-shade: #e6e2d9;
  --wall-ink: #1f1d19;
  --wall-ink-dim: #6d675c;
  --wall-chip: #f7f5f0;
  --wall-line: #d8d2c6;
  --wall-line-hover: #b6ae9d;
  --wall-lb: rgba(24, 22, 18, .88);
  --wall-focus: #1f1d19;
}

/* ③ 深灰展墙：展框也进深色，照片像挂在暗房墙上（HUD 仍是浅字深底） */
html[data-frame="slate"] {
  --wall-frame: #151515;
  --wall-img-shade: #1f1f1f;
  --wall-ink: #dddddd;
  --wall-ink-dim: #8a8a8a;
  --wall-chip: #1c1c1c;
  --wall-line: #2a2a2a;
  --wall-line-hover: #3a3a3a;
  --wall-lb: rgba(0, 0, 0, .9);
  --wall-focus: #dddddd;
}

/* ④ 近黑展墙：最深的一档，照片像悬在虚空里（对比最强、最「放映厅」） */
html[data-frame="black"] {
  --wall-frame: #0a0a0a;
  --wall-img-shade: #161616;
  --wall-ink: #dddddd;
  --wall-ink-dim: #8a8a8a;
  --wall-chip: #151515;
  --wall-line: #222222;
  --wall-line-hover: #333333;
  --wall-lb: rgba(0, 0, 0, .92);
  --wall-focus: #ffffff;
}

/* ⑤ 白展框 + 深色信息牌：展框保持白（照片的卡纸感），但四角 HUD 换成深底浅字，
     信息压在任何亮照片上都读得清 —— ① 的信息牌是白底，压到亮照片上会「糊」进去 */
html[data-frame="darkchip"] {
  --wall-frame: #ffffff;
  --wall-img-shade: #ebebeb;
  --wall-ink: #ededed;
  --wall-ink-dim: #b4b4b4;
  --wall-chip: rgba(12, 12, 12, .82);
  --wall-line: rgba(255, 255, 255, .14);
  --wall-line-hover: rgba(255, 255, 255, .3);
  --wall-lb: rgba(0, 0, 0, .9);
  --wall-focus: #ffffff;
}

/* ================= 基础 ================= */
* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--kb-font-mono);
  background: var(--kb-bg);
  color: var(--kb-text);
  font-size: var(--kb-font-base);
  line-height: 1.7;
  min-height: 100%;
  -webkit-font-smoothing: antialiased;
}

/* 明暗切换的全局过渡（yamachun §2.7：0.4s，只过渡颜色不过渡 layout —— 切主题不该触发重排动画）。
   2026-10-14 升级：早先是「选择器清单」写法，清单外的元素（标题/链接/标签/面板/正文……）
   会瞬间跳色，视觉上就是「闪一下」。现在改成切换期间的全站通用规则：
   * 连伪元素一起覆盖，八条通道 —— 颜色三件套 + fill/stroke（SVG 图标）
   + opacity + outline-color + box-shadow，透明度这类属性一起渐变。
   代价：这 .45s 窗口内，元素自身的 transform 类过渡（悬停位移那类）会被临时替换，
   窗口一过就还回去 —— 可接受，切主题不是高频操作。
   class 只挂 .45s（ui.js / index.html 内联脚本负责摘），不长期挂着。 */
html.theme-anim, html.theme-anim *, html.theme-anim *::before, html.theme-anim *::after {
  transition: background-color var(--kb-theme-dur) var(--kb-ease),
              color var(--kb-theme-dur) var(--kb-ease),
              border-color var(--kb-theme-dur) var(--kb-ease),
              fill var(--kb-theme-dur) var(--kb-ease),
              stroke var(--kb-theme-dur) var(--kb-ease),
              opacity var(--kb-theme-dur) var(--kb-ease),
              outline-color var(--kb-theme-dur) var(--kb-ease),
              box-shadow var(--kb-theme-dur) var(--kb-ease) !important;
}
/* 双保险：系统开了减弱动效时，即使 theme-anim 因故挂着也立刻切，不搞渐变 */
@media (prefers-reduced-motion: reduce) {
  html.theme-anim, html.theme-anim *, html.theme-anim *::before, html.theme-anim *::after {
    transition: none !important;
  }
}

::selection { background: var(--kb-accent); color: var(--kb-on-accent); }

img { max-width: 100%; height: auto; }
a { color: inherit; }

/* —— 键盘焦点：全站一处兜底 ——
   用 :where() 把优先级压到 0，谁写了更具体的规则谁说了算。
   focus-visible 只在键盘操作时出现，鼠标点击不打扰。 */
:where(a, button, [tabindex], input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--kb-accent);
  outline-offset: 3px;
  border-radius: var(--kb-radius-sm);
}

/* —— 跳转链接：键盘用户第一站（Tab 第一下就见） —— */
.skip-link {
  position: fixed;
  top: 8px; left: 8px;
  z-index: 300;
  padding: 8px 14px;
  background: var(--kb-accent);
  color: var(--kb-on-accent);
  font-size: var(--kb-text-md);
  letter-spacing: 1px;
  text-decoration: none;
  border-radius: var(--kb-radius);
  transform: translateY(-200%);
  transition: transform var(--kb-dur) var(--kb-ease);
}
.skip-link:focus-visible { transform: none; outline-offset: 2px; }

/* —— 只给读屏、界面上看不见 —— */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* —— 布局容器 —— */
.wrap { max-width: var(--kb-wrap); margin: 0 auto; padding: 0 24px; }
.wrap-wide { max-width: var(--kb-wrap-wide); }
@media (max-width: 600px) { .wrap { padding: 0 20px; } }

/* ================= 页头（站名 + 运行态元信息） ================= */
.site-head { padding: 32px 0 0; }
.site-head .head-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.site-head .brand {
  display: inline-block;
  min-height: 44px;                 /* 手指点得到 */
  line-height: 32px;
  font-size: var(--kb-text-lg);
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--kb-text);
  text-decoration: none;
  position: relative;
  transition: color var(--kb-dur) var(--kb-ease);
}
/* 悬停：一根 1px 下划线从左边长出来（design-dna｜yamachun §5.1 导航项同款动作） */
.site-head .brand::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 4px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--kb-dur-slow) var(--kb-ease);
}
.site-head .brand:hover { color: var(--kb-text-strong); }
.site-head .brand:hover::after,
.site-head .brand:focus-visible::after { transform: scaleX(1); }

.site-head .head-meta {
  font-size: var(--kb-text-xs);
  letter-spacing: 2px;
  color: var(--kb-text-3);
  white-space: nowrap;
}
@media (max-width: 600px) {
  .site-head .head-meta { display: none; }   /* 窄屏优先留给站名 */
}

/* ================= 页面标题区 ================= */
.page-head { padding: 48px 0 32px; }
.page-title {
  font-size: var(--kb-text-xl);
  font-weight: 700;
  letter-spacing: 3px;
  line-height: 1.4;
  color: var(--kb-text-strong);
}
.page-meta {
  font-size: var(--kb-text-md);
  color: var(--kb-text-3);
  letter-spacing: 1px;
  margin-top: 8px;
}

/* ================= 区块标题（大写英文 + 中文，本站内页语言） ================= */
.section-label {
  font-size: var(--kb-text-xs);
  font-weight: 700;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--kb-text-3);
  display: flex;
  align-items: center;
  gap: 12px;
}
.section-label::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--kb-border);   /* 标题后面拖一条细线，当分隔不当装饰 */
}

/* ================= 按钮（状态矩阵：默认/悬停/聚焦/按下/禁用/加载） ================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;                /* 触摸目标 */
  padding: 0 18px;
  font: inherit;
  font-size: var(--kb-text-md);
  letter-spacing: 1px;
  line-height: 1.4;
  color: var(--kb-text);
  background: transparent;
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--kb-dur) var(--kb-ease),
              border-color var(--kb-dur) var(--kb-ease),
              color var(--kb-dur) var(--kb-ease);
}
.btn:hover { background: var(--kb-surface-hover); border-color: var(--kb-border-hover); color: var(--kb-text-strong); }
.btn:active { transform: scale(.98); }         /* 按下去要有回话 */
.btn:focus-visible { outline-offset: 2px; }
/* 禁用：不是消失，是「明确不能点」——去掉交互暗示，保留可读性 */
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
}
.btn:disabled:hover, .btn[aria-disabled="true"]:hover {
  background: transparent; border-color: var(--kb-border); color: var(--kb-text);
}
/* 加载：转圈 + 屏蔽指针；文字留着，宽度不跳 */
.btn.is-loading { pointer-events: none; }
.btn.is-loading::before {
  content: '';
  width: 13px; height: 13px;
  border: 1.5px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* 主按钮：全站唯一的实底（强调色反转）。密度克制——一屏最多一个 */
.btn-primary {
  background: var(--kb-accent);
  border-color: var(--kb-accent);
  color: var(--kb-on-accent);
}
.btn-primary:hover { background: var(--kb-text); border-color: var(--kb-text); color: var(--kb-bg); }
.btn-primary:disabled:hover, .btn-primary[aria-disabled="true"]:hover {
  background: var(--kb-accent); border-color: var(--kb-accent); color: var(--kb-on-accent);
}
/* 文字按钮：无边框纯文字，悬停右移（catalogue-link 同款，yamachun §5.5） */
.btn-text {
  border-color: transparent;
  padding: 0 4px;
  min-height: 44px;
}
.btn-text:hover { background: transparent; color: var(--kb-text-strong); }
.btn-text .go { transition: transform var(--kb-dur) var(--kb-ease); }
.btn-text:hover .go { transform: translateX(4px); }

/* ================= 表单（默认/悬停/聚焦/禁用/错误 + 说明与报错） ================= */
.field { margin-bottom: 20px; }
.field > label {
  display: block;
  font-size: var(--kb-text-sm);
  letter-spacing: 1px;
  color: var(--kb-text-2);
  margin-bottom: 6px;
}
.field input, .field textarea, .field select {
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  font-size: 16px;               /* ≥16px：手机聚焦时浏览器不自动放大 */
  color: var(--kb-text);
  background: var(--kb-surface);
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  transition: border-color var(--kb-dur) var(--kb-ease), background var(--kb-dur) var(--kb-ease);
}
.field input::placeholder, .field textarea::placeholder { color: var(--kb-text-3); }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--kb-border-hover); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--kb-accent);
}
/* 键盘聚焦时补可见焦点环（鼠标聚焦只变边框，不抢视觉） */
.field input:focus-visible, .field textarea:focus-visible, .field select:focus-visible {
  outline: 2px solid var(--kb-accent);
  outline-offset: 1px;
}
.field textarea { min-height: 120px; resize: vertical; line-height: 1.7; }
.field select { appearance: none; padding-right: 32px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--kb-text-3) 50%),
                    linear-gradient(135deg, var(--kb-text-3) 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.field .hint { margin-top: 6px; font-size: var(--kb-text-sm); color: var(--kb-text-3); line-height: 1.5; }
/* 错误：边框转语义色 + 一行说明；颜色之外还有文字，不靠色觉单一通道 */
.field.has-error input, .field.has-error textarea, .field.has-error select { border-color: var(--kb-bad); }
.field .error-msg { margin-top: 6px; font-size: var(--kb-text-sm); color: var(--kb-bad); }
/* 禁用 */
.field input:disabled, .field textarea:disabled, .field select:disabled {
  opacity: .45; cursor: not-allowed; background: var(--kb-surface);
}
/* 复选/单选：强调色来自 accent-color，跟主题走 */
.field input[type="checkbox"], .field input[type="radio"] { accent-color: var(--kb-accent); width: 16px; height: 16px; }

/* ================= 卡片（默认/悬停/聚焦内含） ================= */
.card {
  display: block;
  padding: var(--kb-space-card);
  background: var(--kb-surface);
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  text-decoration: none;
  color: var(--kb-text);
  transition: background var(--kb-dur) var(--kb-ease), border-color var(--kb-dur) var(--kb-ease);
}
/* hover = 边框变色 + 底色微亮（刻意偏离 yamachun 的「上浮+阴影」：
   .kb/style.md §六 与 personal-site.md 都要求个人站零阴影，层次靠边框与灰阶） */
.card:hover { background: var(--kb-surface-hover); border-color: var(--kb-border-hover); }
.card:focus-within { border-color: var(--kb-accent); }
.card .card-title { font-size: var(--kb-text-lg); font-weight: 700; letter-spacing: 1px; color: var(--kb-text-strong); }
.card .card-meta { font-size: var(--kb-text-xs); letter-spacing: 2px; color: var(--kb-text-3); margin-bottom: 10px; }
.card .card-desc { font-size: var(--kb-text-md); color: var(--kb-text-2); margin-top: 10px; line-height: 1.7; }
.card .card-go { font-size: var(--kb-text-md); color: var(--kb-text-3); margin-top: 14px;
  transition: transform var(--kb-dur) var(--kb-ease), color var(--kb-dur) var(--kb-ease); }
.card:hover .card-go { transform: translateX(4px); color: var(--kb-text-strong); }

/* 卡片栅格：桌面 3 列 / 平板 2 列 / 手机 1 列 */
.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 1024px) { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .card-grid { grid-template-columns: 1fr; } }

/* ================= 档案列表（writing 页一行一条） ================= */
.entry-list { list-style: none; border-top: 1px solid var(--kb-border); }
.entry { border-bottom: 1px solid var(--kb-border); }
.entry a {
  display: flex;
  align-items: baseline;
  gap: 16px;
  min-height: 56px;
  padding: 14px 12px;
  color: var(--kb-text);
  text-decoration: none;
  transition: background var(--kb-dur) var(--kb-ease);
}
.entry a:hover { background: var(--kb-surface-hover); }
.entry a:hover .entry-title { color: var(--kb-text-strong); }
.entry a:focus-visible { outline-offset: -2px; }
.entry-idx  { flex: 0 0 auto; font-size: var(--kb-text-sm); color: var(--kb-text-3); letter-spacing: 1px; }
.entry-date { flex: 0 0 auto; font-size: var(--kb-text-md); color: var(--kb-text-3); letter-spacing: 1px; }
.entry-title { flex: 1 1 auto; font-size: var(--kb-font-base); transition: color var(--kb-dur) var(--kb-ease); }
.entry-note { flex: 0 0 auto; font-size: var(--kb-text-md); color: var(--kb-text-3); }
.entry-go {
  flex: 0 0 auto;
  font-size: var(--kb-text-md);
  color: var(--kb-text-3);
  transition: transform var(--kb-dur) var(--kb-ease), color var(--kb-dur) var(--kb-ease);
}
.entry a:hover .entry-go { transform: translateX(4px); color: var(--kb-text-strong); }
@media (max-width: 600px) {
  .entry a { flex-wrap: wrap; gap: 2px; padding: 12px; }
  .entry-idx { display: none; }               /* 窄屏先省掉编号 */
  .entry-title { flex: 1 0 100%; margin-bottom: 2px; }
  .entry-go { margin-left: auto; }
  .entry a:hover .entry-go { transform: none; }
}

/* —— 返回行 —— */
.back { font-size: var(--kb-text-md); letter-spacing: 1px; padding: 24px 0 0; }
.back a { color: var(--kb-text-2); text-decoration: none; transition: color var(--kb-dur) var(--kb-ease); }
.back a:hover { color: var(--kb-text-strong); }

/* ================= 纵向导航（侧栏形态，给后续页面备用；样板页可验收） ================= */
.nav-list { list-style: none; }
.nav-list li + li { margin-top: 2px; }
.nav-list a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  padding: 0 12px;
  font-size: var(--kb-text-md);
  letter-spacing: 1px;
  color: var(--kb-text-2);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: color var(--kb-dur) var(--kb-ease), background var(--kb-dur) var(--kb-ease),
              border-color var(--kb-dur) var(--kb-ease);
}
.nav-list a:hover { color: var(--kb-text-strong); background: var(--kb-surface-hover); }
.nav-list a[aria-current="page"] { color: var(--kb-text-strong); border-left-color: var(--kb-accent); }
.nav-list a:focus-visible { outline-offset: -2px; }

/* ================= 表格（行悬停 / 表头 / 空状态） ================= */
.table-wrap { overflow-x: auto; border: 1px solid var(--kb-border); border-radius: var(--kb-radius); }
.table { width: 100%; border-collapse: collapse; font-size: var(--kb-text-md); }
.table th {
  text-align: left;
  font-size: var(--kb-text-xs);
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--kb-text-3);
  padding: 12px 16px;
  border-bottom: 1px solid var(--kb-border);
  white-space: nowrap;
}
.table td { padding: 12px 16px; border-bottom: 1px solid var(--kb-border); color: var(--kb-text); }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background var(--kb-dur) var(--kb-ease); }
.table tbody tr:hover { background: var(--kb-surface-hover); }
.table .num { font-variant-numeric: tabular-nums; color: var(--kb-text-2); }
.table-empty { padding: 32px 16px; text-align: center; color: var(--kb-text-3); font-size: var(--kb-text-md); }

/* ================= 状态标签（语义色只在这里出现） ================= */
.tag {
  display: inline-block;
  width: fit-content;
  padding: 2px 8px;
  font-size: var(--kb-text-xs);
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--kb-text-2);
  background: transparent;
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius-sm);
  white-space: nowrap;
}
.tag-ok   { color: var(--kb-ok);   border-color: var(--kb-ok);   background: var(--kb-ok-bg); }
.tag-bad  { color: var(--kb-bad);  border-color: var(--kb-bad);  background: var(--kb-bad-bg); }
.tag-warn { color: var(--kb-warn); border-color: var(--kb-warn); background: var(--kb-warn-bg); }

/* ================= 弹窗 / 抽屉 ================= */
.modal-backdrop, .drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: var(--kb-scrim);
}
.modal-backdrop.is-open, .drawer-backdrop.is-open { display: flex; }
.modal-backdrop.is-open { animation: fade-in var(--kb-dur-slow) var(--kb-ease); }
.modal-panel {
  width: min(480px, 100%);
  max-height: 85vh;
  overflow-y: auto;
  background: var(--kb-surface);
  border: 1px solid var(--kb-border-hover);
  border-radius: var(--kb-radius);
  padding: var(--kb-space-card);
}
.modal-backdrop.is-open .modal-panel { animation: panel-in var(--kb-dur-slow) var(--kb-ease-emph); }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 12px; }
.modal-title { font-size: var(--kb-text-lg); font-weight: 700; letter-spacing: 2px; color: var(--kb-text-strong); }
.modal-body { font-size: var(--kb-text-md); color: var(--kb-text-2); line-height: 1.8; }
.modal-foot { display: flex; justify-content: flex-end; gap: 12px; margin-top: 24px; }
.modal-close {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; font-size: var(--kb-text-md);
  color: var(--kb-text-3);
  background: transparent;
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  cursor: pointer;
  transition: color var(--kb-dur) var(--kb-ease), border-color var(--kb-dur) var(--kb-ease);
}
.modal-close:hover { color: var(--kb-text-strong); border-color: var(--kb-border-hover); }

.drawer-backdrop { justify-content: flex-end; padding: 0; }
.drawer-backdrop.is-open { animation: fade-in var(--kb-dur-slow) var(--kb-ease); }
.drawer-panel {
  width: min(420px, 92vw);
  height: 100%;
  overflow-y: auto;
  background: var(--kb-surface);
  border-left: 1px solid var(--kb-border-hover);
  padding: var(--kb-space-card);
  display: flex;
  flex-direction: column;
}
.drawer-backdrop.is-open .drawer-panel { animation: drawer-in var(--kb-dur-slow) var(--kb-ease-emph); }
.drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.drawer-body { flex: 1; }
.drawer-foot { margin-top: 24px; display: flex; gap: 12px; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes panel-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes drawer-in {
  from { transform: translateX(100%); }
  to   { transform: none; }
}

/* ================= Toast（右下角堆叠，四语义型，自动退场） ================= */
.toast-stack {
  position: fixed;
  right: 16px; bottom: 16px;
  z-index: 250;
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: min(340px, calc(100vw - 32px));
  pointer-events: none;           /* 容器不挡点击，只有 toast 本体接 */
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  background: var(--kb-surface);
  border: 1px solid var(--kb-border-hover);
  border-radius: var(--kb-radius);
  font-size: var(--kb-text-md);
  color: var(--kb-text);
  box-shadow: none;
  animation: toast-in var(--kb-dur-slow) var(--kb-ease-emph);
}
.toast.is-leaving { animation: toast-out var(--kb-dur) var(--kb-ease) forwards; }
.toast .t-dot { flex: 0 0 auto; width: 8px; height: 8px; margin-top: 7px; border-radius: 50%; background: var(--kb-text-3); }
.toast .t-body { flex: 1; line-height: 1.6; }
.toast .t-close {
  flex: 0 0 auto; min-width: 44px; min-height: 44px; margin: -12px -14px -12px 0;
  display: inline-flex; align-items: center; justify-content: center;
  font: inherit; color: var(--kb-text-3); background: transparent; border: 0; cursor: pointer;
  transition: color var(--kb-dur) var(--kb-ease);
}
.toast .t-close:hover { color: var(--kb-text-strong); }
.toast-ok   .t-dot { background: var(--kb-ok); }
.toast-warn .t-dot { background: var(--kb-warn); }
.toast-bad  .t-dot { background: var(--kb-bad); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes toast-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(6px); }
}

/* ================= 文章正文 ================= */
.article { padding: 24px 0 var(--kb-space-section); }
.post-title { font-size: var(--kb-text-xl); font-weight: 700; line-height: 1.4; letter-spacing: 1px; color: var(--kb-text-strong); }
.post-date { font-size: var(--kb-text-md); color: var(--kb-text-3); letter-spacing: 1px; margin-top: 8px; }
.prose { margin-top: 32px; font-size: var(--kb-font-base); }
.prose p { margin-bottom: 24px; color: var(--kb-text); }
.prose h2 { font-size: var(--kb-text-lg); font-weight: 700; margin: 48px 0 16px; letter-spacing: 1px; color: var(--kb-text-strong); }
.prose h3 { font-size: var(--kb-font-base); font-weight: 700; margin: 32px 0 12px; color: var(--kb-text-strong); }
.prose ul, .prose ol { margin: 0 0 24px; padding-left: 24px; }
.prose li { margin-bottom: 8px; }
.prose blockquote {
  margin: 0 0 24px;
  padding: 0 0 0 20px;
  border-left: 1px solid var(--kb-border-hover);
  color: var(--kb-text-2);
}
.prose code {
  font-size: 15px;
  background: var(--kb-surface-hover);
  padding: 2px 6px;
  border-radius: var(--kb-radius-sm);
}
.prose pre {
  margin: 0 0 24px;
  padding: 16px;
  background: var(--kb-surface);
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  overflow-x: auto;
}
.prose pre code { background: none; padding: 0; }
.prose img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 0 24px;
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
}
.prose a { color: var(--kb-text-strong); text-decoration: underline; text-underline-offset: 4px; text-decoration-color: var(--kb-border-hover); }
.prose a:hover { text-decoration-color: var(--kb-accent); }

/* —— 照片：单列纵向，每张下面一行拍摄信息（竖排版式，备用） —— */
.shots { padding: 8px 0 var(--kb-space-section); }
.shot { margin: 0 0 56px; }
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  background: var(--kb-surface);
}
.shot figcaption { margin-top: 8px; font-size: var(--kb-text-sm); color: var(--kb-text-3); letter-spacing: 1px; }

/* ================= 页脚 ================= */
.site-foot {
  margin-top: 24px;
  padding: 20px 0 var(--kb-space-section);
  border-top: 1px solid var(--kb-border);   /* 一条上边框把内容和页脚分开，不用空白硬撑 */
  font-size: var(--kb-text-sm);
  color: var(--kb-text-3);
  letter-spacing: 1px;
}

/* ================= 滚动渐显（IntersectionObserver 驱动，见 ui.js） =================
   静止态挂 html.reveal-on —— 这个 class 由 JS 加；JS 要是没跑，
   内容就是普通可见文字，不会白屏。进入视口加 .is-in，逐条错峰浮现。 */
html.reveal-on .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--kb-dur-slow) var(--kb-ease-emph),
              transform var(--kb-dur-slow) var(--kb-ease-emph);
  transition-delay: calc(var(--i, 0) * var(--kb-stagger));
}
html.reveal-on .reveal.is-in { opacity: 1; transform: none; }

/* 页面级轻入场（内页 main 共用；与 view transition 不冲突——直接打开时才播） */
@media (prefers-reduced-motion: no-preference) {
  .fade { animation: fade-rise var(--kb-dur-slow) var(--kb-ease-emph) both; }
}
@keyframes fade-rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ================= 路由切换过渡（View Transitions API，渐进增强） =================
   支持该 API 的浏览器（Chrome 系）在页面间导航时自动播放；
   不支持的浏览器就是普通跳转，无任何损失。只动 opacity + 小幅位移，
   时长/曲线与全站结构动画同源。 */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vt-out var(--kb-dur-slow) var(--kb-ease) both; }
::view-transition-new(root) { animation: vt-in  var(--kb-dur-slow) var(--kb-ease) both; }
@keyframes vt-out { to { opacity: 0; transform: translateY(-6px); } }
@keyframes vt-in  { from { opacity: 0; transform: translateY(6px); } }

/* ================= 照片墙（「第一卷」= 二维无限照片场） =================
   展框铺满整个视口，它就是这一页的「底」：照片一张张贴在它上面，页面信息压在照片之上。
   交互取自参考站 christiehemmklok.com 的可拖拽全屏画廊（整屏画廊 + 抓取光标 + 拖拽平移 +
   页面不可滚动）；「无限」「不裁图」「键盘也能走」「单击放大」是本站自己加的。
   没跑 JS 时：这是一张自动换行的照片网格，照片一张不少。
   ⚠️ 颜色全部走 --wall-*（不是 --kb-*）：展框必须能独立保持白（或换其它方案）。
   这一页固定深色（html data-theme="dark" 写死在页面上），不随站点主题切换 ——
   展框方案（调试面板里可切 5 套）就是它自己的主题。
   source: .kb/categories/personal-site.md（作品展示 · 横向舞台推轨式是记忆点范本）
   source: design-dna｜christiehemmklok.com §5.6 项目轨道 / §7 全屏可拖拽画廊 */

body.page-roll {
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;           /* 拖到头别触发浏览器的「后退」手势 */
  background: var(--wall-frame);       /* 照片之间露出来的是展框，不是页面底色 */
}

.strip {
  --kb-strip-gap: 12px;                /* source: .kb/style.md §四 间距用统一刻度（4 的倍数） */
  --kb-strip-col: 260px;               /* 没 JS 时的列宽；JS 会按视口宽度改写成实际值 */
  position: fixed;
  inset: 0;
  overflow: auto;                      /* 没 JS 时靠它滚；JS 接管后换成 overflow:hidden 走 transform */
  overscroll-behavior: none;
  background: var(--wall-frame);
  cursor: grab;
  touch-action: none;                  /* 整屏都是展框，两个方向都交给拖拽 */
  user-select: none;
  -webkit-user-select: none;
  scrollbar-width: none;
}
.strip::-webkit-scrollbar { display: none; }
.strip.is-drag { overflow: hidden; }    /* JS 接管后改由 transform 平移，滚动条不再参与 */
.strip.is-dragging { cursor: grabbing; }
.strip:focus-visible { outline: 2px solid var(--wall-focus); outline-offset: -3px; }

/* 没 JS 的底子：自动换行的照片网格。JS 给它加 .is-canvas 之后变成绝对定位的画布 */
.strip-field {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kb-strip-gap);
  align-content: flex-start;
}
.strip-field.is-canvas {
  position: absolute;
  inset: 0;
  display: block;
  /* 拖动抓取阻尼：默认显式 scale(1)（不能用 none，否则浏览器对「none↔scale」不插值会跳一下） */
  transform: scale(1);
  transition: transform var(--kb-dur-slow) var(--kb-ease);   /* source: .kb/style.md §七 移动/缩放动画用 transform */
}
.strip.is-dragging .strip-field { transform: scale(.98); }   /* 按下拿起来，松手靠上面的 transition 弹回 */
@media (prefers-reduced-motion: reduce) {
  .strip-field.is-canvas { transition: none; }
  .strip.is-dragging .strip-field { transform: scale(1); }   /* 减弱动效：不缩放，只保留抓取光标 */
}

/* 画布结构：一列 = 一条纵向序列；列与列的复制品由 JS 摆位 */
.strip-field.is-canvas .strip-col {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}
.strip-field.is-canvas .strip-stack {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: var(--kb-strip-gap);
  width: var(--kb-strip-col);
}

.strip-item { flex: 0 0 auto; width: var(--kb-strip-col); margin: 0; }
.strip-item img {
  display: block;
  width: 100%;
  height: auto;                        /* 按原比例缩放，不裁图 */
  max-width: none;
  pointer-events: none;                /* 挡掉浏览器原生的「拖图片」，拖动统一由外层管 */
  -webkit-user-drag: none;
  background: var(--wall-img-shade);   /* 图还没到时先铺个底，避免闪一下白 */
}

/* —— HUD：压在照片场上的一圈信息 ——
   只剩对角两块：左上 = 唯一的出口（站名 → 首页），右下 = 操作提示。
   容器 pointer-events:none，只有站名能点 —— 往任意方向拖都不会被这层挡住。
   每块垫一块实底小板（1px 描边、小圆角、零阴影），压在任意照片上都读得清。
   颜色走 --wall-*：默认跟展框同色的白板，换成 ⑤ 深色信息牌时也不用来改这一块。
   source: design-dna｜christiehemmklok.com §4 定位（fixed + 内边距 + pointer-events:none 容器）
   source: .kb/style.md §六 层次靠边框不靠投影、§五 圆角成阶梯 */
.hud {
  --hud-pad: 16px;
  position: fixed;
  inset: 0;
  z-index: 20;
  pointer-events: none;                /* 整层不吃指针，拖拽不会被它挡住 */
  font-size: var(--kb-text-sm);
  letter-spacing: 1px;
  line-height: 1.6;
  transition: opacity var(--kb-dur-slow) var(--kb-ease);
}
/* 整层不吃指针；「放大时整圈退场」写在这一层（.hud），
   两块各自的入场写在它们自己身上 —— 分层是为了不让两件事抢同一个 opacity。
   ⚠️ 下面所有入场动画一律用 fill-mode: backwards，不用 both：
      both 会把动画的最后一帧锁死，之后普通声明就压不过它了。 */
.hud-inner { position: absolute; inset: 0; }
body.lb-on .hud { opacity: 0; }

.hud-brand,
.strip-hint {
  position: absolute;
  margin: 0;
  max-width: min(48vw, 340px);
  padding: 6px 11px;
  background: var(--wall-chip);
  border: 1px solid var(--wall-line);
  border-radius: var(--kb-radius-sm);
}
.hud-brand {
  top: max(var(--hud-pad), env(safe-area-inset-top, 0px));
  left: max(var(--hud-pad), env(safe-area-inset-left, 0px));
  pointer-events: auto;                /* 整圈里只有这一个能点 */
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--wall-ink);
  text-decoration: none;
  transition: background var(--kb-dur) var(--kb-ease), border-color var(--kb-dur) var(--kb-ease);
}

/* —— 悬停：一根 1px 下划线从左边长出来 ——
     参考站导航项的那个动作（design-dna｜yamachun §6「下划线从 0 到 100% 宽」） */
.hud-brand::after {
  content: '';
  position: absolute;
  left: 11px;                          /* 跟内边距对齐，宽度正好等于文字宽 */
  right: 11px;
  bottom: 4px;
  height: 1px;
  background: currentColor;            /* 跟着 --wall-ink 走，换展框方案不用改 */
  transform: scaleX(0);
  transform-origin: left center;       /* 从左往右长 */
  transition: transform var(--kb-dur-slow) var(--kb-ease);
}
.hud-brand:hover { border-color: var(--wall-line-hover); }
.hud-brand:hover::after,
.hud-brand:focus-visible::after { transform: scaleX(1); }
.hud-brand:active { transform: scale(.97); }
.hud-brand:focus-visible { outline: 2px solid var(--wall-focus); outline-offset: 2px; }

/* —— 两块各自的入场 ——
   站名（左上）先来（0.12s）：从上方 -4px 落下 + 从左往右擦出来的遮罩，像标签被装上去；
   提示（右下）跟着来（0.34s）：从下方 +4px 升起，只淡入不擦。 */
@keyframes hud-brand-in {
  from { clip-path: inset(0 100% 0 0); transform: translateY(-4px); opacity: .4; }
  to   { clip-path: inset(0 0 0 0);    transform: none;             opacity: 1; }
}
@keyframes hud-hint-in {
  from { transform: translateY(4px); opacity: 0; }
  to   { transform: none;            opacity: 1; }
}
@media (prefers-reduced-motion: no-preference) {
  .hud-brand  { animation: hud-brand-in .42s var(--kb-ease-emph) .12s backwards; }
  .strip-hint { animation: hud-hint-in  var(--kb-dur-slow) var(--kb-ease) .34s backwards; }
}

.strip-hint {
  bottom: max(var(--hud-pad), env(safe-area-inset-bottom, 0px));
  right: max(var(--hud-pad), env(safe-area-inset-right, 0px));
  letter-spacing: 2px;
  color: var(--wall-ink-dim);
  transition: opacity var(--kb-dur) var(--kb-ease);
}
.strip-hint.is-gone { opacity: 0; }   /* 上手拖过一次就把提示收掉 */

/* —— 照片查看器（2026-10-14 从「单击放大的灯箱」升级）——
   同一张照片从它在墙上的位置长到屏幕中央（FLIP），落位之后是完整的查看器：
   左右切换 / 缩放 / 缩放后拖动 / 信息条 / 下载原图。
   做法不变：盒子按「放大后该多大」排版，位置与缩放全交给 transform 补，
   整个过程只动 transform + opacity 两条通道，不触发重排。
   时长与曲线跟站里其它结构变化共用一条（--kb-dur-slow / --kb-ease），不新增第三条曲线。
   控件语言跟展框一致（--wall-*）：chip 底 + 1px 线，压在照片上不抢戏。
   source: .kb/style.md §七（时长统一、曲线收敛、移动缩放只用 transform） */
.lb {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  background: var(--wall-lb);
  opacity: 0;
  transition: opacity var(--kb-dur-slow) var(--kb-ease);
}
.lb.is-open { display: block; }
.lb.is-shown { opacity: 1; }
.lb-img {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  max-width: none;
  max-height: none;
  border: 0;
  background: none;
  transform-origin: 0 0;               /* 缩放锚在左上角，位置换算才是纯加减法 */
  will-change: transform;
  /* opacity 一起过渡：换图的淡入淡出走这条路，不另开动画 */
  transition: transform var(--kb-dur-slow) var(--kb-ease), opacity var(--kb-dur) var(--kb-ease);
}
/* 未缩放：双击放大（光标给放大镜）；缩放中：照片可拖，光标给抓手 */
.lb-img { pointer-events: auto; cursor: zoom-in; }
.lb.is-zoomed .lb-img { cursor: grab; }
.lb.is-panning .lb-img { cursor: grabbing; }
/* 直接操纵（拖动平移 / 双指捏合）必须跟手 —— .34s 的缓动在这里是橡皮筋，关掉 */
.lb.is-panning .lb-img { transition: none; }

/* —— 顶条：序号 + 这一张的信息 —— */
.lb-bar {
  position: absolute;
  left: 0; right: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  font-size: var(--kb-text-xs);
  letter-spacing: 1px;
  color: var(--wall-ink);
  opacity: 0;                          /* 跟着遮罩一起淡入，不抢照片的第一眼 */
  transition: opacity var(--kb-dur-slow) var(--kb-ease);
  pointer-events: none;                /* 条子本身不挡照片；里面的按钮单独打开 */
}
.lb.is-shown .lb-bar { opacity: 1; }
.lb-top { top: 0; justify-content: space-between; }
.lb-bottom { bottom: 0; justify-content: center; pointer-events: none; }
.lb-count { font-weight: 700; letter-spacing: 2px; font-variant-numeric: tabular-nums; }
.lb-meta { color: var(--wall-ink-dim); }
.lb-bar .lb-btn, .lb-bar .lb-nav { pointer-events: auto; }

/* —— 左右切换：贴在左右中，手机上 44px 也点得到 —— */
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 10px;
  font: inherit;
  font-size: 16px;
  line-height: 1;
  color: var(--wall-ink);
  background: var(--wall-chip);
  border: 1px solid var(--wall-line);
  border-radius: var(--kb-radius-sm);
  cursor: pointer;
  opacity: 0;
  transition: background var(--kb-dur) var(--kb-ease), border-color var(--kb-dur) var(--kb-ease),
              opacity var(--kb-dur-slow) var(--kb-ease);
}
.lb.is-shown .lb-nav { opacity: 1; }
.lb-prev { left: max(16px, env(safe-area-inset-left, 0px)); }
.lb-next { right: max(16px, env(safe-area-inset-right, 0px)); }
.lb-nav:hover { border-color: var(--wall-line-hover); }
.lb-nav:focus-visible { outline: 2px solid var(--wall-focus); outline-offset: 2px; }

/* —— 底条：缩放值 / 缩小 / 放大 / 下载 / 关闭 —— */
.lb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 10px;
  font: inherit;
  font-size: var(--kb-text-xs);
  letter-spacing: 1px;
  color: var(--wall-ink);
  background: var(--wall-chip);
  border: 1px solid var(--wall-line);
  border-radius: var(--kb-radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--kb-dur) var(--kb-ease), border-color var(--kb-dur) var(--kb-ease);
}
.lb-btn:hover { border-color: var(--wall-line-hover); }
.lb-btn:focus-visible { outline: 2px solid var(--wall-focus); outline-offset: 2px; }
.lb-zoom-val {
  min-width: 56px;
  text-align: center;
  color: var(--wall-ink-dim);
  font-variant-numeric: tabular-nums;
  letter-spacing: 1px;
}
.lb-download { padding: 0 14px; }

/* 很窄的屏幕上：条子贴边一点、字号收一点，别让这一圈挤掉照片 */
@media (max-width: 600px) {
  .lb-bar { padding: 8px 10px; gap: 8px; }
  .lb-meta { display: none; }               /* 序号留着就够，尺寸信息窄屏让位 */
  .lb-nav { min-width: 40px; min-height: 40px; padding: 0 8px; }
  .lb-btn { min-width: 40px; min-height: 40px; padding: 0 8px; }
  .lb-download { padding: 0 10px; }
  .hud { --hud-pad: 12px; font-size: var(--kb-text-xs); }
  .hud-brand { font-size: 14px; letter-spacing: 2px; }
  .strip-hint { letter-spacing: 1px; }
}

@media (prefers-reduced-motion: reduce) {
  .strip-hint,
  .lb,
  .lb-img { transition: none; }
}

/* —— 404 ——
   注意：404.html 不引用这份样式表（它必须能脱离相对路径独立成立 —— 大多来自
   乱输的地址或过期链接，可能落在任意子路径下）。它的样式整块内联在
   docs/tools/make-release.py 的 NOT_FOUND 模板里，那边同步维护，改版时两处一起看。 */

/* ================= 主题切换按钮（全站同一位置：左下角） ================= */
.theme-toggle {
  position: fixed;
  left: 16px; bottom: 16px;
  z-index: 150;
  width: 44px; height: 44px;          /* 触摸目标 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--kb-text-2);
  background: var(--kb-surface);
  border: 1px solid var(--kb-border);
  border-radius: var(--kb-radius);
  cursor: pointer;
  transition: color var(--kb-dur) var(--kb-ease), background var(--kb-dur) var(--kb-ease),
              border-color var(--kb-dur) var(--kb-ease);
}
.theme-toggle:hover { color: var(--kb-text-strong); background: var(--kb-surface-hover); border-color: var(--kb-border-hover); }
.theme-toggle:active { transform: scale(.96); }
.theme-toggle svg {
  display: block;
  position: absolute;               /* 两个图标叠在同一格交叉淡化 —— display 切换会「闪」 */
  transition: opacity var(--kb-dur) var(--kb-ease), transform var(--kb-dur) var(--kb-ease);
}
/* 两个图标按主题切：深色主题显示「太阳」（点它去浅色），浅色主题显示「月亮」。
   2026-10-14：display 切换 → 旋转 + 淡入淡出，切主题时图标自己也参与过渡。 */
.theme-toggle .ic-sun  { opacity: 1; transform: rotate(0deg) scale(1); }
.theme-toggle .ic-moon { opacity: 0; transform: rotate(-90deg) scale(.4); }
html[data-theme="light"] .theme-toggle .ic-sun  { opacity: 0; transform: rotate(90deg) scale(.4); }
html[data-theme="light"] .theme-toggle .ic-moon { opacity: 1; transform: rotate(0deg) scale(1); }

/* ================= 响应式（桌面 / 平板 / 手机） ================= */
@media (max-width: 1024px) {
  :root { --kb-text-3xl: 44px; --kb-text-2xl: 34px; }
}
@media (max-width: 640px) {
  :root {
    --kb-text-3xl: 34px;
    --kb-text-2xl: 26px;
    --kb-text-xl: 24px;
    --kb-space-section: 64px;      /* 手机上区块间距收一档，别滚不到头 */
    --kb-space-card: 20px;
  }
  .page-head { padding: 32px 0 24px; }
  .toast-stack { left: 16px; width: auto; }   /* 手机上 Toast 通栏 */
  .modal-foot { flex-direction: column-reverse; }
  .modal-foot .btn { width: 100%; }
}

/* ================= 全局：尊重「减少动态效果」 =================
   系统开了减弱动效：过渡与一律关掉，动画不播，内容直接呈现。
   canvas 背景线在 JS 里单独处理（画一张静态的线，不飘不跟鼠标）。 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  html.reveal-on .reveal { opacity: 1; transform: none; transition: none; }
  .fade { animation: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  .btn.is-loading::before { animation-duration: .01ms !important; }
}
