/* 阅读页样式。移动优先：默认布局就是窄屏的样子，宽屏靠 media query 加列。
   没有构建步骤 —— 这份文件被 embed 进二进制，改完重启就生效。 */

:root {
  /* 令牌全部来自 docs/design/artboards（ReaderInline / ReaderSandbox / Mobile*）。
     ⚠️ packages/theme/src/tokens.ts 有一份等价的 TS 版本。阅读页要能被 embed
     进 Worker 二进制、零构建步骤，所以没法 import 它 —— 两处必须一起改。 */
  --bg: #FBFCFA;
  --surface: #FFFFFF;
  --muted: #F2F5F1;
  --fg: #101614;
  --body: #3A4744;
  --dim: #6B7A76;
  --line: #E2E7E3;
  --mark: #C9D2CC;
  --ink-strong: #141A19; /* 深色轨与首屏深色块（tokens.ts 的 inkStrong）*/
  --accent: #0B6B63;
  --accent-dark: #075049;
  --accent-light: #E4F0ED;
  --accent-fg: #FFFFFF;
  --warn-bg: #FBF1DA;
  --warn-fg: #8A5F0F;
  --warn-fg-dark: #6B4A0B;
  --note-bg: #E4F0ED;
  --code-bg: #F2F5F1;
  --ok-fg: #2C6238;
  --ok-bg: #E6F0E7;
  --danger-fg: #9B382C;
  --danger-bg: #F6E2DE;

  /* 图表配色。源：docs/design/artboards/Charts.dc.html。
     SVG 里一个色值都没有，全靠这八个变量 —— 所以同一份已经摄取好的 HTML
     在浅色、深色、四套主题下都是对的，换配色不必重新摄取历史文档。 */
  --pw-c0: #0B6B63; --pw-c1: #C08A2E; --pw-c2: #B05A48; --pw-c3: #3F7A52;
  --pw-c4: #3F5E8C; --pw-c5: #8A5A93; --pw-c6: #4FBCAF; --pw-c7: #7C8A86;
  --slice-ink: #FFFFFF;

  /* 文档变量。源：docs/design/artboards/TemplateLooks.dc.html（曾叫 DocThemes）。
     模板只改这几个变量加两三条结构规则 —— 版式的差别全在这里，
     断点与 DOM 所有模板共用。 */
  --doc-font: var(--font);
  --doc-size: 1rem;
  --doc-lead: 1.75;
  --doc-measure: 120ch;
  --doc-h-font: var(--font-head);
  --doc-h3-font: var(--font-head);
  --doc-h2-rule: 1px solid var(--line);
  --doc-h2-bar: 0px;
  --doc-code-radius: var(--radius-lg);
  --doc-bleed: 0px;

  /* v0.2 的令牌。声明在这里，取值由设计快照（每篇文档一份内联 CSS）覆盖。
     声明与取值分开，是因为**读路径不查模板库**：一篇文档打开时，
     它的令牌值来自自己那份快照，而默认值必须在这里等着 —— 否则
     一篇没有快照的老文档会拿到一堆 var() 求值失败的空值。 */
  --doc-radius: 8px;
  --doc-rhythm: 1;
  --doc-h2-size: 1.35em;
  --doc-h2-align: start;

  --radius: 4px;
  --radius-md: 5px;
  --radius-lg: 6px;
  --w-nav: 264px;
  --w-toc: 226px;
  --h-top: 54px;
  /* Reader Shell 的版心只有这一处数值来源。平台内联正文直接使用；识别出的
     PageWell standalone iframe 由 reader.js 把计算后的同一组值同步进去。 */
  --reader-shell-max: 1920px;
  --reader-main-start: 20px;
  --reader-main-end: 56px;
  /* 文章页（single 版式，ReaderArticle 画板）：正文容器与右侧目录是**一组**，一起居中。
     容器最宽 1180，里面的留白比正文栏的 gutter 小得多 —— 居中已经留出了两边，
     再按窗口十分之一留白就是把内容挤回中间那一条。 */
  --reader-article-max: 1180px;
  --reader-article-gutter: clamp(24px, 4vw, 56px);
  /* 两种留白（Viewer* / Reader* 画板）：
     --edge 是页面的边 —— 顶栏两头、页内目录的右侧，贴着窗口，小一点；
     --gutter 是正文栏两侧的空白，跟窗口走，1280 上 128、1920 上 192、再宽到 240 为止。
     窄屏（<900）两个都收到 16。 */
  --edge: 16px;
  --gutter: 16px;

  /* 品牌标记 Handoff 的两条渐变。设计源 docs/design/artboards/Brand.dc.html。
     走变量是为了让浅底、深底、深色首屏共用同一份 SVG 模板（base.gohtml 的 brandmark）。
     ⚠️ 换底色时**两块面板一起换一档**：后面板离地一档、前面板离地两档。
     只换前面板的话，后面那块会比前面那块还亮，深度直接读反。 */
  --mark-f0: #4FBCAF; --mark-f1: #16A398; --mark-f2: #0B6B63; --mark-f3: #075049;
  --mark-r0: #E4F0ED; --mark-r1: #B8E7E0; --mark-r2: #78CFC5;


  /* 字体（2026-09-17）：拉丁字 Open Sans，中文 Noto Sans CJK，标题与正文同一款、只差粗细。
     "Noto Sans CJK SC" 是装在本机上的那份（Linux 发行版、设计师的机器），"Noto Sans SC" 是
     Google Fonts 送来的同一款 —— 两个名字都列上，装了就不下载。
     2026-09-19 起**全站就这一对字，文档也是**：衬线令牌退成同一对字（用户看到杂志模板的衬线正文说
     「字体都不对」）。--font-serif 这个变量留着，是因为已发布文档的设计快照里写的是 var(--font-serif)
     —— 它跟着这里走，历史文档不必重新摄取就换过来。 */
  --font: "Open Sans", "Noto Sans CJK SC", "Noto Sans SC", "PingFang SC", "Hiragino Sans GB", system-ui, -apple-system, sans-serif;
  --font-head: var(--font);
  --font-serif: var(--font);
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* 平台字体库的另外两款（render/token.go 的 fontStacks 指到这里）：模板作者选 display / kai 时用；
     本机没装就退回同一对字，不退到衬线。 */
  --font-display: "Smiley Sans", var(--font);
  --font-kai: "LXGW WenKai", "Kaiti SC", STKaiti, var(--font);

  /* 正文里的几枚小图标（MarkdownStyle 画板）。callout 的五枚是蒙版：形状在这里，颜色由用它的规则给，
     所以 SVG 里只有一个占位的黑。任务清单那枚勾是背景图，得自带颜色 —— 值就是 --accent-fg，
     深色里换成深色那一份（下面两处深色块里各有一行）。 */
  --pw-i-note: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5M12 7.6v.4'/%3E%3C/svg%3E");
  --pw-i-tip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18h6M10 21h4M12 3a6 6 0 0 0-3.6 10.8c.7.5 1.1 1.3 1.1 2.1V16h5v-.1c0-.8.4-1.6 1.1-2.1A6 6 0 0 0 12 3z'/%3E%3C/svg%3E");
  --pw-i-important: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5h16v11H9.5L4 20.5z'/%3E%3Cpath d='M12 8v3.6M12 14v.4'/%3E%3C/svg%3E");
  --pw-i-warning: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.8 21.2 20H2.8z'/%3E%3Cpath d='M12 10v4.2M12 17v.4'/%3E%3C/svg%3E");
  --pw-i-caution: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8.2 3h7.6L21 8.2v7.6L15.8 21H8.2L3 15.8V8.2z'/%3E%3Cpath d='M12 7.8v5M12 15.8v.4'/%3E%3C/svg%3E");
  --pw-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E");
}

/* 设计稿只画了浅色。深色是**额外**加的 —— 阅读页是公开阅读的表面，
   夜里读的人是真实存在的。色值由浅色那套推导，保持同一个色相。 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #141A19;
    --surface: #1A2220;
    --muted: #202826;
    --fg: #E3EAE6;
    --body: #B4C0BB;
    --dim: #849490;
    --line: #273130;
    --mark: #3A4744;
    --accent: #4FBCAF;
    --accent-dark: #7FD5C9;
    --accent-light: #1F2A28;
    --accent-fg: #10221D;
    --warn-bg: #33280D;
    --warn-fg: #F0D79A;
    --warn-fg-dark: #F0D79A;
    --note-bg: #1F2A28;
    --code-bg: #202826;
    --ok-fg: #8FCB9B;
    --ok-bg: #1B2A1F;
    --danger-fg: #E9A79C;
    --danger-bg: #2E1C19;
    --mark-f0: #B8E7E0; --mark-f1: #7FD5C9; --mark-f2: #4FBCAF; --mark-f3: #2A8A80;
    --mark-r0: #075049; --mark-r1: #0B6B63; --mark-r2: #16A398;
    --pw-c0: #4FBCAF; --pw-c1: #E0AE5A; --pw-c2: #D98A76; --pw-c3: #6FA97F;
    --pw-c4: #7E9BD1; --pw-c5: #C08FCA; --pw-c6: #7FD5C9; --pw-c7: #A7B4B0;
    --slice-ink: #101614;
    --pw-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2310221D' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E");
  }
}
:root[data-theme="dark"] {
  --bg: #141A19; --surface: #1A2220; --muted: #202826;
  --fg: #E3EAE6; --body: #B4C0BB; --dim: #849490;
  --line: #273130; --mark: #3A4744;
  --accent: #4FBCAF; --accent-dark: #7FD5C9; --accent-light: #1F2A28; --accent-fg: #10221D;
  --warn-bg: #33280D; --warn-fg: #F0D79A; --warn-fg-dark: #F0D79A;
  --note-bg: #1F2A28; --code-bg: #202826;
  --ok-fg: #8FCB9B; --ok-bg: #1B2A1F; --danger-fg: #E9A79C; --danger-bg: #2E1C19;
  --mark-f0: #B8E7E0; --mark-f1: #7FD5C9; --mark-f2: #4FBCAF; --mark-f3: #2A8A80;
  --mark-r0: #075049; --mark-r1: #0B6B63; --mark-r2: #16A398;
  --pw-c0: #4FBCAF; --pw-c1: #E0AE5A; --pw-c2: #D98A76; --pw-c3: #6FA97F;
  --pw-c4: #7E9BD1; --pw-c5: #C08FCA; --pw-c6: #7FD5C9; --pw-c7: #A7B4B0;
  --slice-ink: #101614;
  --pw-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2310221D' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E");
}

/* 选了明暗之后也要告诉浏览器：滚动条、表单控件、默认 canvas 是浏览器画的，
   它们只看 color-scheme，不看我们的变量。<meta color-scheme> 写的是
   「两种都支持」，读者选了哪一种得在这里说死。 */
:root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* 深色区块里的标记（首屏那种：底是深的，但页面本身是浅色方案）。 */
.pw-on-dark {
  --mark-f0: #B8E7E0; --mark-f1: #7FD5C9; --mark-f2: #4FBCAF; --mark-f3: #2A8A80;
  --mark-r0: #075049; --mark-r1: #0B6B63; --mark-r2: #16A398;
}

/* 尺寸写在这里而不是 SVG 上：这块跟着版式走。
   <= 20px 换 brandmark-sm（另一份画），别把完整版缩到这个尺寸。 */
.pw-mark { width: 22px; height: 22px; flex-shrink: 0; display: block; }
.pw-mark-sm { width: 18px; height: 18px; }

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font-family: var(--font); font-size: 15px; line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}
/* ReaderDirect 画板：短文档也占满一屏，页脚贴着视口底边；正文变长时外壳随内容
   自然长高，页脚仍在正文之后，不用 fixed 覆盖内容。嵌入预览没有页脚，不参与这条布局。 */
.pw-reader:not(.is-embedded) {
  display: flex; min-height: 100dvh; flex-direction: column;
}
.pw-reader:not(.is-embedded) > .pw-shell { flex: 1 0 auto; width: 100%; }
.pw-reader:not(.is-embedded) > .pw-foot { flex-shrink: 0; }
h1, h2, h3, h4 { font-family: var(--font-head); font-weight: 700; text-wrap: balance; }
a { color: var(--accent); }
img, video, canvas, svg { max-width: 100%; height: auto; }

.pw-skip { position: absolute; left: -9999px; }
.pw-skip:focus { left: 8px; top: 8px; background: var(--surface); padding: 8px 12px; z-index: 20; }

/* ---- 顶栏 ---- */
.pw-top {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: 12px;
  min-height: var(--h-top);
  padding: 8px var(--edge); padding-top: max(8px, env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--line);
}
/* 顶栏：品牌 · 分隔 · 标题块。设计稿把「谁分享的、什么时候更新的」
   放在标题下面一行 —— 访客判断一份内容值不值得读，先看的是这两件事。 */
.pw-brand-mark {
  display: flex; align-items: center; gap: 9px; flex-shrink: 0;
  color: var(--accent); text-decoration: none;
}
.pw-brand-mark span {
  font-family: var(--font-head); font-weight: 700; font-size: 15px; color: var(--fg);
}
.pw-sep { width: 1px; height: 20px; background: var(--line); flex-shrink: 0; }
.pw-titleblock { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; }
.pw-space {
  font-size: 13.5px; font-weight: 500; text-decoration: none; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pw-submeta {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 11px; color: var(--dim);
  overflow: hidden; white-space: nowrap;
}
/* 作者芯片（ReaderInline.dc.html 顶栏）：16px 头像或首字母 + 名字。
   开了个人主页时是链接（主色），否则只是文字 —— 两种形态同一副样子，差别只有颜色。 */
.pw-author { display: inline-flex; align-items: center; gap: 6px; min-width: 0; color: var(--dim); text-decoration: none; }
a.pw-author { color: var(--accent); }
a.pw-author:hover { text-decoration: underline; }
.pw-author > span:last-child { overflow: hidden; text-overflow: ellipsis; }
.pw-author-img { width: 16px; height: 16px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.pw-author-i {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 16px; height: 16px; border-radius: 50%; background: var(--accent); color: var(--accent-fg);
  font-family: var(--font); font-size: 9.5px; font-weight: 500;
}
.pw-actions { margin-inline-start: auto; display: flex; gap: 8px; align-items: center; }

/* 当前 PageWell standalone HTML 的两个读者开关放在平台外层顶栏。
   只有 frame.js 认出当前形状并握手后才摘 hidden；任意 HTML 不会平白得到两个无效按钮。 */
.pw-html-prefs { display: flex; gap: 4px; align-items: center; }
.pw-html-prefs[hidden] { display: none; }
.pw-html-prefs svg[hidden] { display: none; }
.pw-html-prefs .pw-btn[aria-pressed="true"] {
  border-color: var(--accent); background: var(--accent-light); color: var(--accent-dark);
}
@media (max-width: 899px) { .pw-html-prefs [data-html-width] { display: none; } }

/* 散文停在行长里；其余撑到栏边。只挑直接子元素：组件（.pw-c）里的段落由组件自己排。
   只有一张图的段落（Markdown 的 ![图] 会被包成 <p>）不算散文 —— 图要撑到栏边。 */
.pw-body > :is(p, ul, ol, dl, blockquote):not(:has(> img:only-child)) { max-width: var(--doc-measure); }

/* 汉堡按钮只在窄屏出现 */
.pw-menu {
  display: grid; gap: 4px; width: 34px; height: 34px; padding: 8px;
  background: none; border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer;
}
.pw-menu span { display: block; height: 2px; background: var(--fg); border-radius: 2px; }

.pw-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 36px; padding: 6px 12px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface); color: var(--fg);
  font: inherit; font-size: 14px; text-decoration: none; cursor: pointer;
  white-space: nowrap;
}
.pw-btn:hover { border-color: var(--accent); }
.pw-btn-primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }

/* 表单提交后的等待态。site.js 在 submit 时给 <form> 标 aria-busy、禁掉提交键、
   把按钮文字换成 data-busy-label，并在前面塞一枚 .pw-spin。
   没有 JS 时什么都不发生 —— 表单照常提交，只是没有这层反馈。
   spinner 用 currentColor：深色按钮上是白圈，文字按钮上是链接色，不用为每种按钮各写一份。 */
form[aria-busy="true"] button, form[aria-busy="true"] input[type="submit"] {
  cursor: progress; opacity: .75; pointer-events: none;
}
.pw-spin {
  display: inline-block; width: 14px; height: 14px; flex-shrink: 0;
  margin-inline-end: 8px; vertical-align: -2px; box-sizing: border-box;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  opacity: .9; animation: pw-spin .7s linear infinite;
}
@keyframes pw-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .pw-spin { animation: none; border-right-color: currentColor; opacity: .5; }
}

/* ⋯ 菜单（ReaderInline 画板）：顶栏右侧只留主动作和这一枚。<details> 开合不靠脚本；
   里面是分组的动作行（复制三种 / 打印 / 下载 / 看原文 / 阅读偏好），reader.js 只负责点外面关。 */
.pw-copy, .pw-more { position: relative; }
.pw-copy > summary, .pw-more > summary { list-style: none; }
.pw-copy > summary::-webkit-details-marker, .pw-more > summary::-webkit-details-marker { display: none; }
.pw-btn-icon { min-width: 36px; padding: 6px; }
.pw-more[open] > summary { border-color: var(--accent); background: var(--accent-light); color: var(--accent-dark); }
.pw-menu-pop {
  position: absolute; inset-inline-end: 0; top: calc(100% + 6px); z-index: 12;
  display: grid; min-width: 190px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 8px 28px rgba(0,0,0,.12);
}
.pw-menu-pop button, .pw-menu-pop a {
  text-align: start; padding: 8px 10px; border: 0; border-radius: 6px;
  background: none; color: inherit; font: inherit; font-size: 13.5px; cursor: pointer; text-decoration: none;
}
.pw-menu-pop button:hover, .pw-menu-pop a:hover { background: var(--code-bg); }
.pw-more-pop { min-width: 250px; }
.pw-more-label {
  margin: 0; padding: 6px 10px 2px; font-family: var(--mono); font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--dim);
}
.pw-more-sep { border: 0; border-top: 1px solid var(--line); margin: 6px 4px; }

/* 复制成功的提示（MobileReader 画板）：底部正中一枚小胶囊，1.8 秒后自己退下。
   钉在视口上，页面滚到哪都看得见；不接受点击，免得挡住下面的东西。 */
.pw-toast {
  position: fixed; inset-inline: 0; bottom: max(24px, env(safe-area-inset-bottom)); z-index: 60;
  width: fit-content; margin: 0 auto; padding: 9px 16px; border-radius: 999px;
  background: var(--fg); color: var(--bg); font-size: 13.5px; font-weight: 500;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .18); pointer-events: none;
  opacity: 0; transform: translateY(8px); transition: opacity .18s ease, transform .18s ease;
}
.pw-toast::before { content: "✓"; margin-inline-end: .45em; }
.pw-toast.is-on { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .pw-toast { transition: none; } }

/* ---- 布局 ----
   窄屏：单列，侧栏是抽屉。宽屏：目录树 + 正文 + 页内目录三列。

   版心（ReaderInline / ReaderWide / Viewer* 画板，2026-09-15）：外壳用整个窗口，最宽 1920 —— 再宽
   就居中，「用得上这块屏」不是「把字铺到 4K 的两端」。正文栏从这一列的左边开始，**不居中**；
   散文（段落、列表、引用）停在模板定的行长（measure 令牌，默认 120ch），标题的横线、代码块、
   表格、图、组件撑到栏边。表格留在栏宽内换行，代码块撑不下才在自己的框里横滚。以前把整个正文栏卡在行长里并居中，
   一屏 2000px 只用得上 640 —— 而且一张宽表格会在那 640 里被裁掉。 */
.pw-shell { display: block; max-width: var(--reader-shell-max); margin: 0 auto; }

.pw-nav {
  display: none;
  padding: 20px 14px; border-bottom: 1px solid var(--line); background: var(--bg);
}
.pw-nav.is-open { display: block; }
.pw-tree { list-style: none; margin: 0; padding: 0; }
.pw-tree-item { padding-inline-start: calc(var(--d, 0) * 14px); }
.pw-tree-head {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--dim); padding: 0 10px 10px; margin: 0;
}
.pw-tree-item > a, .pw-tree-label {
  display: block; padding: 7px 10px; border-radius: var(--radius);
  color: var(--body); text-decoration: none; font-size: 13.5px;
}
.pw-tree-item > a:hover { background: var(--code-bg); }
.pw-tree-item.is-active > a { background: var(--accent-light); color: var(--accent-dark); font-weight: 500; }
.pw-tree-label { color: var(--dim); font-size: 13.5px; }

.pw-main { padding: var(--reader-main-start) var(--gutter) var(--reader-main-end); min-width: 0; }
/* 标题块（MarkdownStyle 画板，2026-10-09）：标题大一档、行距收紧，元信息与正文之间留够一口气 ——
   正文第一个元素不再自带上边距（见下面 :first-child），两者之间的空白只由这里定。 */
.pw-title { margin: 6px 0 10px; font-size: clamp(26px, 4.4vw, 34px); line-height: 1.24; letter-spacing: -.01em; }
.pw-meta { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 30px;
  color: var(--dim); font-size: 13.5px; }
.pw-tag { font-family: var(--mono); font-size: 11px; padding: 2px 8px;
  background: var(--code-bg); border-radius: 3px; }

.pw-body {
  overflow-wrap: anywhere;
  font-family: var(--doc-font); font-size: var(--doc-size); line-height: var(--doc-lead);
}
/* ---- 正文里的每一种 Markdown 元素（ReaderInline 画板）----
   这里管的是作者**没有**用组件、就写普通 Markdown 时得到的样子：标题、列表、表格、代码、引用、
   图、脚注。组件各自的样子在 pack 里。原则只有一条：每一种元素都要一眼认得出是什么，
   又不能比正文更抢眼 —— 表格是一张有边的卡、代码是一块底色、引用是一根线。 */
.pw-body h1, .pw-body h2, .pw-body h3 {
  line-height: 1.3; margin-top: 1.8em; font-family: var(--doc-h-font);
}
/* 小节标题与大标题同一款字（MarkdownStyle 画板，2026-10-09）。以前 h3/h4 走 --doc-h3-font，基线默认是等宽：
   中文标题里只有数字和拉丁字是等宽的，「2.1  调用时序」读起来像两种字拼的。
   已发布文档的设计快照里冻着 --doc-h3-font: var(--mono)，而且并不是每份都带 data-code 可以挑出来 ——
   所以这里不再读那个变量，所有文档一起换。内建模板没有一个自己选过 code 令牌；令牌留着只为让写了它的模板照样通过校验
   （render/builtin/base-tokens.yaml）。 */
.pw-body h3, .pw-body h4 { font-family: var(--doc-h-font); }
.pw-body h1 { font-size: 2em; line-height: 1.2; letter-spacing: -.012em; }
.pw-body h2 {
  font-size: 1.38em; margin-bottom: .75em; padding-bottom: .4em; border-bottom: var(--doc-h2-rule);
  border-inline-start: var(--doc-h2-bar) solid var(--accent);
  padding-inline-start: var(--doc-h2-bar);
  letter-spacing: -.005em;
}
.pw-body h3 { font-size: 1.17em; margin-top: 1.75em; margin-bottom: .55em; }
.pw-body h4 { font-size: 1.02em; font-weight: 600; margin-top: 1.6em; margin-bottom: .45em; }
.pw-body h5, .pw-body h6 { font-size: .92em; font-weight: 600; margin-top: 1.4em; margin-bottom: .4em; color: var(--body); }
/* 标题紧跟标题（一节开头就是小节）：不留整段的空 */
.pw-body :is(h1, h2, h3, h4) + :is(h2, h3, h4, h5) { margin-top: .6em; }
/* 正文第一个元素不带上边距：标题块下面的空白由 .pw-meta 一处说了算（以前是 20 + 一个 h2 的 1.8em，近 60px） */
.pw-body.pw-body > :first-child { margin-top: 0; } /* 两个类：要压过下面 [data-pw-doc].pw-body h2 的节奏规则 */
.pw-body p, .pw-body li { font-size: var(--doc-size); }
/* 段末不留单字一行（支持的浏览器才生效，不支持就是原样） */
.pw-body :is(p, li, blockquote) { text-wrap: pretty; }
.pw-body strong { font-weight: 650; }
.pw-body ::selection { background: color-mix(in srgb, var(--accent) 24%, transparent); }
/* 链接：下划线细一点、浅一点、离字远一点，悬停才实。链接色的定义在 :root（a 的规则），这里只管线。 */
.pw-body a { text-decoration-thickness: 1px; text-underline-offset: .16em; text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.pw-body a:hover { text-decoration-color: currentColor; }
.pw-body del { color: var(--dim); }
.pw-body sup, .pw-body sub { font-size: .72em; line-height: 0; }
.pw-body kbd {
  padding: .05em .45em; border: 1px solid var(--mark); border-bottom-width: 2px; border-radius: 4px;
  background: var(--surface); font-family: var(--mono); font-size: .85em;
}
.pw-body mark { padding: 0 .15em; background: var(--warn-bg); color: inherit; }
/* 列表：项之间松一口气，嵌套再紧回来；圆点和数字都退成灰。 */
.pw-body ul, .pw-body ol { margin: .8em 0 1.1em; padding-inline-start: 1.5em; }
.pw-body li { margin: .35em 0; }
.pw-body li > ul, .pw-body li > ol { margin: .3em 0 .4em; }
.pw-body li::marker { color: var(--dim); }
.pw-body ol > li::marker { font-variant-numeric: tabular-nums; }
/* 任务清单：方框代替圆点。摄取出来的勾选框是 disabled 的（读者勾不了），浏览器把 disabled 画成
   一片灰 —— 已完成与未完成几乎分不出来（MarkdownStyle 画板）。自己画：未完成一个空框，
   完成是主色实心加一枚勾；勾的颜色是 --accent-fg（深色里是深的），所以放在变量里随主题换。 */
.pw-body li:has(> input[type="checkbox"]) { list-style: none; margin-inline-start: -1.5em; }
.pw-body input[type="checkbox"] {
  appearance: none; -webkit-appearance: none; flex: none;
  inline-size: 1.05em; block-size: 1.05em; margin: 0 .55em 0 0; vertical-align: -.17em;
  border: 1.5px solid var(--mark); border-radius: 4px; background: var(--surface); opacity: 1;
}
.pw-body input[type="checkbox"]:checked {
  border-color: var(--accent); background: var(--accent) var(--pw-check) center / 78% no-repeat;
}
.pw-body pre {
  margin: 1.4em 0; padding: 15px 18px; overflow-x: auto;   /* 宽代码在自己的容器里横向滚动，页面本身永不横滚 */
  background: var(--code-bg); border: 1px solid var(--line); border-radius: var(--doc-code-radius);
  font-family: var(--mono); font-size: 13.5px; line-height: 1.65; tab-size: 4;
  /* 代码里不连字：JetBrains Mono 会把 --> 连成一枚箭头，源码就不再是作者敲的那几个字符了 */
  font-variant-ligatures: none;
  /* reference 主题让代码块贴边：查手册时代码是主角，不该被正文的量度框住 */
  margin-inline: calc(var(--doc-bleed) * -1); padding-inline: calc(18px + var(--doc-bleed));
}
.pw-body pre code { padding: 0; background: none; border: 0; font-size: inherit; }
/* 代码块的右上角（MarkdownStyle 画板）：语言名 + 复制。reader.js 给每块代码套一层 .pw-code，
   把复制按钮放进去；语言名是 ::before 读 data-lang 生成的 —— 不进 DOM，所以「复制为纯文本」
   与读屏都不会多出一个 typescript。两样都垫着代码块的底色，压在长的第一行上也读得清。
   按钮平时只露语言名，悬停或键盘聚焦才出来；触屏没有悬停，一直在。
   位置都减掉 --doc-bleed：pre 会向两边出血（reference 一类主题），角上的东西要跟着 pre 的边，不跟外壳的边。 */
.pw-body .pw-code { position: relative; margin: 1.4em 0; }
.pw-body .pw-code > pre { margin-block: 0; }
.pw-body .pw-code[data-lang]::before {
  content: attr(data-lang); position: absolute; inset-block-start: 7px; inset-inline-end: calc(12px - var(--doc-bleed)); z-index: 1;
  padding: 2px 6px; border-radius: 4px; background: var(--code-bg); pointer-events: none;
  font-family: var(--mono); font-size: 11px; line-height: 1.6; letter-spacing: .04em; color: var(--dim);
  transition: opacity .12s ease;
}
.pw-code-copy {
  position: absolute; inset-block-start: 6px; inset-inline-end: calc(8px - var(--doc-bleed)); z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 30px; block-size: 30px; padding: 0;
  border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--dim);
  cursor: pointer; opacity: 0; transition: opacity .12s ease, color .12s ease;
}
.pw-code-copy:hover { color: var(--fg); }
.pw-code-copy.is-done { color: var(--accent); }
.pw-code:hover > .pw-code-copy, .pw-code-copy:focus-visible { opacity: 1; }
/* 按钮出来时让开语言名，不叠在一起 */
.pw-code:hover[data-lang]::before, .pw-code:focus-within[data-lang]::before { opacity: 0; }
/* 触屏：没有悬停，按钮一直在；手机上代码的第一行常常长到右边，于是给两样单独让出一条（语言名靠左、按钮靠右），
   不压在代码上 */
@media (hover: none) {
  .pw-code-copy { opacity: 1; }
  .pw-body .pw-code > pre { padding-block-start: 40px; }
  /* 18px 正好是代码正文的起点：pre 出血多少，它的内边距就补多少 */
  .pw-body .pw-code[data-lang]::before { inset-inline: 18px auto; inset-block-start: 9px; padding: 2px 0; background: none; }
  .pw-code:hover[data-lang]::before, .pw-code:focus-within[data-lang]::before { opacity: 1; }
}

/* ---- 代码高亮（CodeBlocks 画板，2026-09-19）----
   词元类由服务端在摄取时打上（render/highlight.go 的 tok-* 类名，chroma 的短名），
   颜色只在这里：全是调色板里已有的变量，所以同一份摄取好的 HTML 在浅色、深色、
   每一套模板下都对，换配色不必重新摄取 —— 与图表 SVG 同一条纪律。
   八个色位按角色分：关键字 靛蓝 c4 · 类型 梅紫 c5 · 函数 主色 c0 · 字符串 森绿 c3 ·
   数字 琥珀 c1 · 内建 / 常量 陶土 c2 · 注释 次要字色（斜体）· 标签 c4 / 属性 c3。
   变量名、运算符、标点不上色：代码的底色是文字，颜色是路标，不是壁纸。 */
.pw-body pre .tok-k, .pw-body pre .tok-kc, .pw-body pre .tok-kd, .pw-body pre .tok-kn,
.pw-body pre .tok-kp, .pw-body pre .tok-kr, .pw-body pre .tok-ow, .pw-body pre .tok-nt { color: var(--pw-c4); }
.pw-body pre .tok-kt, .pw-body pre .tok-nc, .pw-body pre .tok-nn { color: var(--pw-c5); }
.pw-body pre .tok-nf, .pw-body pre .tok-fm, .pw-body pre .tok-nd { color: var(--pw-c0); }
.pw-body pre .tok-s, .pw-body pre .tok-sa, .pw-body pre .tok-sb, .pw-body pre .tok-sc, .pw-body pre .tok-dl,
.pw-body pre .tok-sd, .pw-body pre .tok-s2, .pw-body pre .tok-sh, .pw-body pre .tok-si, .pw-body pre .tok-sx,
.pw-body pre .tok-sr, .pw-body pre .tok-s1, .pw-body pre .tok-ss, .pw-body pre .tok-na { color: var(--pw-c3); }
.pw-body pre .tok-se { color: var(--pw-c2); }
.pw-body pre .tok-m, .pw-body pre .tok-mb, .pw-body pre .tok-mf, .pw-body pre .tok-mh, .pw-body pre .tok-mi,
.pw-body pre .tok-il, .pw-body pre .tok-mo, .pw-body pre .tok-l, .pw-body pre .tok-ld { color: var(--pw-c1); }
.pw-body pre .tok-nb, .pw-body pre .tok-bp, .pw-body pre .tok-no, .pw-body pre .tok-ne { color: var(--pw-c2); }
.pw-body pre .tok-c, .pw-body pre .tok-ch, .pw-body pre .tok-cm, .pw-body pre .tok-c1, .pw-body pre .tok-cs,
.pw-body pre .tok-cp, .pw-body pre .tok-cpf { color: var(--dim); font-style: italic; }
.pw-body pre .tok-o, .pw-body pre .tok-p { color: var(--body); }
/* diff 与终端输出那几类 */
.pw-body pre .tok-gd { color: var(--danger-fg); }
.pw-body pre .tok-gi { color: var(--ok-fg); }
.pw-body pre .tok-gh, .pw-body pre .tok-gu, .pw-body pre .tok-gs { font-weight: 700; }
.pw-body pre .tok-ge { font-style: italic; }
.pw-body pre .tok-gp, .pw-body pre .tok-go { color: var(--dim); }
.pw-body pre .tok-gr, .pw-body pre .tok-gt { color: var(--danger-fg); }
.pw-body code { font-family: var(--mono); font-size: .88em; font-variant-ligatures: none; }
/* clone：行内代码折到下一行时，每一段都有自己的内边距和圆角 —— 表格窄列里的路径常常要折 */
.pw-body :not(pre) > code {
  padding: .12em .4em; background: var(--code-bg); border-radius: 5px;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
/* 普通引用：一根灰线，字是正文色 —— 以前整段变灰，长引用就读不下去了。callout 那一族在下面另有样子。 */
.pw-body blockquote {
  margin: 1.5em 0; padding: .15em 0 .15em 1.15em; border-inline-start: 3px solid var(--mark); color: var(--body);
}
.pw-body blockquote > :first-child { margin-top: 0; }
.pw-body blockquote > :last-child { margin-bottom: 0; }
.pw-body hr { border: 0; border-top: 1px solid var(--line); margin: 2.6em 0; }
/* 脚注：一根短线引出，小一号、正文次一级的颜色 —— 它是注，不是正文的最后一节 */
.pw-body .footnotes { margin-top: 3em; font-size: .9em; color: var(--body); }
.pw-body .footnotes > hr { inline-size: 4em; margin: 0 0 1.1em; }
.pw-body .footnotes ol { padding-inline-start: 1.4em; }
.pw-body .footnotes li { font-size: inherit; }
.pw-body .footnote-backref { text-decoration: none; }
.pw-body img { max-width: 100%; height: auto; border-radius: var(--doc-radius); }
/* 表格（ReaderInline / MobileReader / MarkdownStyle 画板）：一张有边、圆角的卡；表头一行底色；
   行与行之间一根线，没有竖线。列始终分在正文宽度里，内容放不下就在单元格里换行，表格不横滚（2026-09-20 定的，
   别把横滑带回来）。.pw-table-scroll 是历史类名，现在只承担边框与圆角裁切；存量正文由 reader.js 补上同一层外壳。
   列宽按内容分（table-layout: auto，2026-10-09）：以前是 fixed 等分，「字段 | 说明」两列各占一半，
   长的那列平白多折两行。auto 不会把表撑出栏外，靠的是单元格的 overflow-wrap: anywhere —— 它让每格的最小宽度
   降到一个字，表格怎么都分得下。代价是短词也可能被挤成一字一行（「阶/段」「Na/me」），所以每格再垫一个底：
   最多 6em，且所有列的底加起来不超过栏宽的 80%（cqi 量的是外框，--pw-cols 是列数），剩下两成按内容分。 */
.pw-body table:not(.pw-c *) {
  width: 100%; max-width: 100%; margin: 1.4em 0; table-layout: auto;
  border: 1px solid var(--line); border-radius: var(--doc-radius); border-collapse: collapse;
  font-size: .92em; line-height: 1.55; font-variant-numeric: tabular-nums;
}
.pw-body .pw-table-scroll:not(.pw-c *) {
  width: 100%; max-width: 100%; overflow: hidden; margin: 1.4em 0; container-type: inline-size;
  border: 1px solid var(--line); border-radius: var(--doc-radius);
}
.pw-body .pw-table-scroll:not(.pw-c *) > table {
  width: 100%; max-width: 100%; margin: 0; table-layout: auto;
  border: 0; border-radius: 0;
}
/* 列数只数到 6：再多每列的底已经小到垫不住一个词，干脆不垫（99 列分 80% ≈ 没有底）。 */
.pw-body .pw-table-scroll > table { --pw-cols: 1; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(2)) { --pw-cols: 2; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(3)) { --pw-cols: 3; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(4)) { --pw-cols: 4; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(5)) { --pw-cols: 5; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(6)) { --pw-cols: 6; }
.pw-body .pw-table-scroll > table:has(tr > :nth-child(7)) { --pw-cols: 99; }
/* :not(.pw-c *)：组件（compare、resume …）里的表由组件自己的 CSS 排，这里不插手 ——
   compare 把表撑到 100%，套上这里的 display:block 会变成一张空了大半的卡。 */
.pw-body :is(th, td):not(.pw-c *) {
  padding: 10px 14px; border: 0; border-bottom: 1px solid var(--line); text-align: start; vertical-align: top;
  white-space: normal; overflow-wrap: anywhere; word-break: normal;
  min-width: min(6em, 80cqi / var(--pw-cols, 99));
}
/* 表头用正文字、半粗、正文色（以前是 11px 等宽大写的灰字：中文表头没有大小写，只剩下又小又淡） */
.pw-body thead th:not(.pw-c *) {
  padding: 9px 14px; background: var(--muted); border-bottom: 1px solid var(--line);
  font-family: inherit; font-size: .95em; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--fg);
}
/* 窄屏把格子的内边距收一点：五列表在 390 宽的手机上，每格省下的 8px 就是半个字 */
@media (max-width: 719px) {
  .pw-body :is(th, td):not(.pw-c *), .pw-body thead th:not(.pw-c *) { padding: 9px 10px; }
}
.pw-body tbody th:not(.pw-c *) { font-weight: 600; color: var(--fg); }
.pw-body tbody tr:last-child > :not(.pw-c *) { border-bottom: 0; }

/* 沙箱 */
.pw-sandbox-note, .pw-sandbox-warn, .pw-dev {
  margin: 0 0 14px; padding: 10px 14px; border-radius: var(--radius); font-size: 14px;
}
.pw-sandbox-note { background: var(--note-bg); color: var(--fg); }
.pw-sandbox-warn, .pw-dev { background: var(--warn-bg); color: var(--warn-fg); }
.pw-dev { margin: 10px 14px; }
/* 制品页（ReaderSandbox 画板）：内容区只有那份内容 —— 铺满这一列，没有文章边距、没有边框盒。
   iframe 默认一屏高；沙箱那边报了高度之后由 reader.js 设成内容的实际高度（.is-sized），
   于是内容区自己不出垂直滚动条。 */
.pw-main.is-frame { padding: 0; }
.pw-main.is-frame .pw-sandbox-warn { margin: 12px 16px; }
/* 制品页的外壳不设最大宽度：那份内容要整列的宽。认得出的 standalone 在 iframe 里
   自己套 Reader Shell 的版心（reader.js 把 --reader-shell-max 那一组同步进去）。 */
body.is-artifact .pw-shell { max-width: none; }
.pw-frame-wrap { position: relative; background: var(--bg); }
.pw-frame { display: block; width: 100%; height: calc(100dvh - var(--h-top)); min-height: 320px; border: 0; }
/* ?toolbar=0：只剩内容。没有顶栏，凡是按顶栏高度让位的（iframe 一屏高、标题的滚动停靠）都让 0；
   目录树与本页目录不渲染，外壳也就不必给它们留栏 —— 用块排版，不去和各档 grid 列宽一条条比优先级。 */
.pw-reader.no-bar { --h-top: 0px; }
.pw-reader.no-bar > .pw-shell { display: block; max-width: none; }
.pw-main.is-frame .pw-backlinks, .pw-main.is-frame .pw-pager { padding-inline: 16px; }
/* 全屏：原生 Fullscreen API 下那一块自己就是整块屏幕；兜底（iOS Safari）用固定定位铺满。上面不盖任何提示或按钮。 */
/* 沙箱网页的文字版（ReaderSandbox 画板 iframe 下面那一行）：收着是一行，展开是一栏散文。 */
.pw-frame-text { border-top: 1px solid var(--line); padding: 0 max(16px, min(var(--gutter), 32px)); }
.pw-frame-text > summary { display: flex; align-items: center; gap: 8px; min-height: 48px; cursor: pointer; list-style: none; color: var(--dim); font-size: 14px; }
.pw-frame-text > summary::-webkit-details-marker { display: none; }
.pw-frame-text > summary::before { content: ""; width: 7px; height: 7px; border: solid currentColor; border-width: 0 1.6px 1.6px 0; transform: rotate(-45deg); transition: transform .15s; }
.pw-frame-text[open] > summary::before { transform: rotate(45deg); }
.pw-frame-text > summary:hover { color: var(--fg); }
.pw-frame-text-in { max-width: 72ch; padding-bottom: 32px; color: var(--body); font-size: 15px; line-height: 1.7; }
.pw-frame-text-in section + section { margin-top: 14px; }
.pw-frame-text-in p { margin: 0; }
.pw-frame-wrap:fullscreen { background: var(--bg); }
.pw-frame-wrap:fullscreen .pw-frame { height: 100% !important; min-height: 0; }
html.is-fullscreen, html.is-fullscreen body { overflow: hidden; }
html.is-fullscreen .pw-frame-wrap { position: fixed; inset: 0; z-index: 100; background: var(--bg); }
html.is-fullscreen .pw-frame { height: 100% !important; min-height: 0; }
/* 顶栏里的制品标题与那枚 Sandboxed 小标 */
.pw-doctitle { cursor: default; }
.pw-space-link { color: var(--accent); text-decoration: none; }
.pw-space-link:hover { text-decoration: underline; }
.pw-sandbox-chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px; border-radius: 3px;
  background: var(--warn-bg); color: var(--warn-fg); font-family: var(--font); font-size: 11px; cursor: help;
}

.pw-backlinks { margin-top: 48px; padding-top: 20px; border-top: 1px solid var(--line); }
.pw-backlinks h2 { font-size: 15px; color: var(--dim); margin: 0 0 8px; }
.pw-backlinks ul { margin: 0; padding-inline-start: 18px; }

/* 上一篇 / 下一篇：小标（← Previous / Next →）+ 标题。桌面并排两张，手机上叠成两张整行的卡
   （MobileReader 画板）—— 并排时 175px 里两个标题都被截断。 */
.pw-pager { display: flex; gap: 12px; justify-content: space-between; margin-top: 36px; }
.pw-pager a {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  padding: 11px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: var(--fg); font-size: 14.5px;
}
.pw-pager a:hover { border-color: var(--accent); }
.pw-pager-l { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); }
.pw-pager-t { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pw-next { text-align: end; align-items: flex-end; }
@media (max-width: 560px) {
  .pw-pager { flex-direction: column; gap: 10px; margin-top: 28px; }
  .pw-pager a { flex: none; }
  .pw-pager-t { white-space: normal; }
}

/* 页内目录（ReaderOutline 画板，2026-10-09 重画）。
   - 不挂在分栏线上了：用户说栏左边那根贯穿整栏的竖线「不美观」。栏与正文之间只靠留白分开；
     当前一节是一块浅主色的底（圆角），悬停是一块灰底 —— 不再是线上的一段 2px。
   - 层级按**嵌套**缩进（Depth，render.Outline 算的），不按 h 几：以前只有 h3 起才缩进，
     用 # 分章、## 分节的文档章和节排成同一层。有下级的目录里，一级条目用正文色、半粗，
     组与组之间多留一口气；整份都是一级的目录就是平平一列，不加粗。
   - 编号（Heading.Num）排成等宽的一栏，文字挂在编号右边。
   - 读者可以收起它（默认展开）：标题行右边那枚按钮；收起后栏缩成一条，只留一枚展开按钮。
     偏好记在本机（pw:prefs 的 outline），首帧之前由 PrefsScript 落到 <html data-outline> 上，刷新不闪。
   - 桌面上一条只占一行，不换行（2026-10-10，用户：「目录不换行展示，还是一行，宽度不够可以水平滚动」）：
     带日期、括号的长标题在窄栏里折成两三行，一份目录读起来像一段段文字。链接那一栏加宽到 260，
     仍比栏宽的那条就越过栏边，整张列表横着滚；标题行与收起按钮在滚动层外面，不跟着走。
     手机上的抽屉照旧折行 —— 那里一行就是整屏宽，横着滚反而难用。 */
.pw-toc { display: none; }
.pw-toc-head { display: flex; align-items: center; gap: 6px; margin: 0 0 10px; padding-inline-start: 10px; }
.pw-toc-h { flex-grow: 1; margin: 0; font-family: var(--mono); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .14em; color: var(--dim); }
/* 标题行右边的按钮：「全部折叠 / 全部展开」（.pw-toc-all，reader.js 挂，只在有可折的章节时才有）与整栏收起。 */
.pw-toc-toggle, .pw-toc-all {
  display: none; align-items: center; justify-content: center; flex: none;
  inline-size: 28px; block-size: 28px; padding: 0; border: 1px solid transparent; border-radius: 6px;
  background: none; color: var(--dim); cursor: pointer;
}
.pw-toc-all { display: inline-flex; }
.pw-toc-toggle:hover, .pw-toc-all:hover { background: var(--muted); color: var(--fg); }
.pw-toc-toggle:focus-visible, .pw-toc-all:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
.pw-toc-toggle .pw-i-show, html[data-outline="hidden"] .pw-toc-toggle .pw-i-hide { display: none; }
html[data-outline="hidden"] .pw-toc-toggle .pw-i-show { display: block; }
.pw-toc ol { list-style: none; margin: 0; padding: 0; }
.pw-toc a {
  display: flex; gap: 8px; align-items: baseline;
  padding: 5px 10px; border-radius: 6px;
  color: var(--body); text-decoration: none; font-size: 13px; line-height: 1.45;
}
.pw-toc a:hover { background: var(--muted); color: var(--fg); }
/* 键盘焦点是一圈光晕（和插件 popup 的主按钮同一套）；鼠标点不出框 */
.pw-toc a:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
.pw-toc-n { flex: none; min-width: 2ch; font-family: var(--mono); font-size: 11px; font-weight: 400;
  font-variant-numeric: tabular-nums; color: var(--dim); }
.pw-toc-t { min-width: 0; }
/* 层级：二级缩一格，三级再缩一格、小一号、变暗 */
.pw-toc-d2 > a { padding-inline-start: 24px; }
.pw-toc-d3 > a { padding-inline-start: 38px; font-size: 12.5px; color: var(--dim); }
/* 有下级的目录：一级是一组的组名。:where 把这条的分量压到和下面「当前一节」一样，好让后者盖过它 */
.pw-toc :where(ol:has(.pw-toc-d2)) .pw-toc-d1 > a { color: var(--fg); font-weight: 500; }
.pw-toc :where(ol:has(.pw-toc-d2)) .pw-toc-d1:not(:first-child) { margin-top: 8px; }
/* 有编号的目录里，下级条目对齐上级的文字（编号栏 2ch + 8 间距），不比上级的文字还靠左 */
.pw-toc ol:has(.pw-toc-n) .pw-toc-d2 > a { padding-inline-start: 32px; }
.pw-toc ol:has(.pw-toc-n) .pw-toc-d3 > a { padding-inline-start: 46px; }
/* 按章节折叠（2026-10-10，用户：「目录需要支持折叠」）：有下级的条目前面一枚箭头，点它收起 / 展开下面那几条，
   点文字照旧跳过去。箭头占的是文字原来起头的那 16px —— 有下级的目录里每一条都往右让 16，有没有箭头文字都对齐；
   整份一级的目录没有箭头，也不让位。箭头是 reader.js 挂的（折叠本来就要脚本），位置在这里先让好，挂上来时文字不跳。 */
.pw-toc li { position: relative; }
.pw-toc ol:has(.pw-toc-d2) .pw-toc-d1 > a { padding-inline-start: 26px; }
.pw-toc ol:has(.pw-toc-d2) .pw-toc-d2 > a { padding-inline-start: 40px; }
.pw-toc ol:has(.pw-toc-d2) .pw-toc-d3 > a { padding-inline-start: 54px; }
.pw-toc ol:has(.pw-toc-d2):has(.pw-toc-n) .pw-toc-d2 > a { padding-inline-start: 48px; }
.pw-toc ol:has(.pw-toc-d2):has(.pw-toc-n) .pw-toc-d3 > a { padding-inline-start: 62px; }
.pw-toc-fold {
  position: absolute; inset-block-start: 2.5px; inset-inline-start: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 16px; block-size: 24px; padding: 0; border: 0; border-radius: 4px;
  background: none; color: var(--dim); cursor: pointer;
}
.pw-toc-d2 > .pw-toc-fold { inset-inline-start: 24px; }
.pw-toc ol:has(.pw-toc-n) .pw-toc-d2 > .pw-toc-fold { inset-inline-start: 32px; }
.pw-toc-fold:hover { color: var(--fg); }
.pw-toc-fold:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
.pw-toc-fold svg { transition: transform .15s ease; }
.pw-toc-fold[aria-expanded="true"] svg { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .pw-toc-fold svg { transition: none; } }
/* 当前一节；被折进去时由看得见的那条上级替它亮着（is-current-in，reader.js 给的），读者总知道自己在哪一章 */
.pw-toc a:is(.is-current, .is-current-in) { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent-dark); }
.pw-toc a:is(.is-current, .is-current-in) .pw-toc-n { color: var(--accent); }
/* 点目录（或带 #锚 打开）时标题停在顶栏下方 16px，不被顶栏盖住 */
.pw-body :is(h1, h2, h3, h4, h5, h6) { scroll-margin-top: calc(var(--h-top) + 16px); }

.pw-foot {
  display: flex; gap: 12px; align-items: center; justify-content: center;
  padding: 24px 16px; padding-bottom: max(24px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); color: var(--dim); font-size: 13px;
}
.pw-brand { text-decoration: none; font-weight: 600; }
.pw-dim { color: var(--dim); }
/* 页脚里的 Report 与它前面那个点：和品牌、年份同一行（ReaderInline 画板） */
.pw-foot .pw-report { color: var(--dim); }
.pw-foot-sep { color: var(--mark); }

/* ---- 居中卡片（分享码 / 密码 / 错误 / 设备码） ---- */
.pw-centered {
  position: relative; display: grid; place-items: center; grid-template-rows: minmax(0, 1fr) auto;
  min-height: 100dvh; padding: 74px 20px 0;
}
/* 页脚那一行横贯页面、贴在底边；卡在上面那一格里居中 */
.pw-centered > .pw-foot { justify-self: stretch; width: 100%; }
/* 门上的品牌一行（MobileCode 画板）与右上角的外观开关：都贴着视口的角，卡在中间居中 */
.pw-gate-top { position: absolute; inset-block-start: 0; inset-inline-start: 0; display: flex; align-items: center; height: 54px; padding: 0 16px; }
.pw-card {
  width: 100%; max-width: 380px; padding: 32px 28px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
}
.pw-card h1 { margin: 0 0 14px; font-size: 20px; }
.pw-card label { display: block; margin-bottom: 6px; font-size: 14px; color: var(--dim); }
.pw-card input {
  width: 100%; min-height: 46px; padding: 10px 12px; margin-bottom: 10px;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--line); border-radius: var(--radius);
  font: inherit; font-size: 16px;  /* 16px 以下 iOS Safari 会在聚焦时放大页面 */
  font-family: var(--mono); letter-spacing: .06em;
}
/* 分享码：一个 56px 的框、22px、宽字距（MobileCode 画板）。不拆成六格 —— 拆开在手机上粘贴会失败，
   而码正是从聊天里粘过来的。 */
.pw-card input[name="code"] { min-height: 56px; font-size: 22px; letter-spacing: .22em; }
.pw-card input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.pw-card .pw-btn { width: 100%; min-height: 46px; }
.pw-hint { margin: 0 0 14px; color: var(--dim); font-size: 13px; }
.pw-error { padding: 10px 12px; margin-bottom: 12px; background: var(--warn-bg);
  color: var(--warn-fg); border-radius: var(--radius); font-size: 14px; }

/* ---- 个人主页 ---- */
.pw-phead { max-width: 720px; margin: 0 auto; padding: 40px 20px 12px; }
.pw-phead h1 { margin: 0; font-size: 28px; }
.pw-handle { margin: 2px 0 10px; color: var(--dim); font-family: var(--mono); }
.pw-plist { max-width: 720px; margin: 0 auto; padding: 0 20px 60px; }
.pw-pitem { padding: 18px 0; border-top: 1px solid var(--line); }
.pw-pitem h2 { margin: 0 0 4px; font-size: 18px; }
.pw-pitem h2 a { text-decoration: none; }
.pw-empty { padding: 40px 0; color: var(--dim); text-align: center; }

/* ---- 手机上的顶栏（MobileReader 画板）----
   品牌只留标记（字与分隔去掉）；标题块第二行只留作者（制品页连这一行都没有，见本段末尾）——
   阅读时长与更新日期标题下面已经有一份，顶栏里 150px 的标题块装不下三样。
   截断用省略号，不整行隐藏：作者是访客判断「值不值得读」先看的那件事。 */
@media (max-width: 560px) {
  .pw-top .pw-brand-mark span, .pw-top .pw-sep { display: none; }
  .pw-top { gap: 8px; }
  .pw-submeta > :not(.pw-author):not(.pw-sandbox-chip):not(.pw-sep-dot:has(+ .pw-sandbox-chip)) { display: none; }
  .pw-actions { gap: 6px; }
  .pw-actions .pw-btn-primary { min-height: 34px; padding-inline: 12px; font-size: 13.5px; }
  /* 制品页在手机上只要那份在跑的页（MobileReader 画板最右那部手机）：顶栏只剩标题，
     文字版与页脚（品牌 · Report）不出 —— 它们在 iframe 下面，一屏之后才看得到，看到时只是一截空白后的杂项。
     文字版仍在 DOM 里（搜索引擎读的是它），只是不显示；Report 在电脑上的页脚里照旧。
     内容区至少一屏高：沙箱报的高度比一屏矮时，下面不留一截空的页面底色。 */
  body.is-artifact .pw-submeta, body.is-artifact .pw-frame-text, body.is-artifact > .pw-foot { display: none; }
  body.is-artifact .pw-frame { min-height: calc(100dvh - var(--h-top)); }
}

@media (min-width: 900px) {
  /* 目录栏的右侧贴着窗口边（--edge），栏宽跟着长一点，链接那一栏 260px 不变。
     以前是 207：目录一条一行之后（见「页内目录」），那么窄几乎每条带日期的标题都得横着滚。 */
  :root {
    --edge: clamp(16px, 2vw, 40px);
    --gutter: clamp(64px, 10vw, 240px);
    --w-toc: calc(260px + var(--edge));
    --reader-main-start: 28px;
    --reader-main-end: 80px;
  }
  .pw-menu { display: none; }
  .pw-shell {
    display: grid; gap: 0;
    grid-template-columns: var(--w-nav) minmax(0, 1fr);
  }
  .pw-nav {
    display: block; position: sticky; top: var(--h-top); align-self: start;
    max-height: calc(100dvh - var(--h-top)); overflow-y: auto;
    border-bottom: 0; border-inline-end: 1px solid var(--line);
  }
  /* 沙箱里跑的制品（.pw-main.is-frame）没有正文栏：整列都是它的。 */
  .pw-main.is-frame { padding: 0; }
  .pw-main.is-frame .pw-sandbox-warn { margin: 12px var(--gutter); }
}
@media (min-width: 1240px) {
  .pw-shell { grid-template-columns: var(--w-nav) minmax(0, 1fr) var(--w-toc); }
  /* 目录栏（ReaderOutline 画板）：没有分栏线，栏与正文之间只靠留白。里面那层才是钉住的 ——
     钉在 aside 自己身上的话，它只有内容那么高。钉住的这层排成一列：标题行在上、不动；列表在下、
     自己滚（竖着滚长目录，横着滚越过栏边的那条）。要是让整层一起滚，横着一滚收起按钮就出了栏，
     横向滚动条也会落在长目录的最底下、看不见。列表左右各留 4px：当前一节的底与焦点光晕是圆角的
     一块，会滚的那层（overflow）会裁掉出界的东西。 */
  .pw-toc { display: block; align-self: stretch; padding: 0 var(--edge) 0 0; }
  .pw-toc-in {
    position: sticky; top: var(--h-top);
    display: flex; flex-direction: column;
    max-height: calc(100dvh - var(--h-top));
    padding-top: 24px;
  }
  .pw-toc:not(.is-sheet) .pw-toc-head { flex: none; margin: 0 4px 7px; }
  /* 一列网格：列宽取「最长那条」与「栏宽」里大的那个 —— 每一条的底（当前、悬停）一样宽，
     横着滚过去也一直铺到最长那条的尽头，不会只有栏宽那么一截。 */
  .pw-toc:not(.is-sheet) ol {
    display: grid; grid-template-columns: auto;
    min-height: 0; overflow: auto; overscroll-behavior: contain; scrollbar-width: thin;
    padding: 3px 4px 28px;
  }
  .pw-toc:not(.is-sheet) a { white-space: nowrap; }
  .pw-toc:not(.is-sheet) .pw-toc-toggle { display: inline-flex; }
  /* 收起：栏缩成一条，只留那枚按钮（换成「展开」的图标），描一圈边好让人认得出这是个开关 */
  html[data-outline="hidden"] { --w-toc: calc(36px + var(--edge)); }
  html[data-outline="hidden"] .pw-toc:not(.is-sheet) :is(.pw-toc-h, ol) { display: none; }
  html[data-outline="hidden"] .pw-toc:not(.is-sheet) .pw-toc-all { display: none; }
  html[data-outline="hidden"] .pw-toc:not(.is-sheet) .pw-toc-head { padding: 0; }
  html[data-outline="hidden"] .pw-toc:not(.is-sheet) .pw-toc-toggle { border-color: var(--line); background: var(--surface); }
}

/* ---- 手机上的两张抽屉（MobileNav 画板）----
   ☰ 开「目录」（空间的树，<900 时树不在屏幕上），页内目录按钮开「本页目录」（<1240 时右栏不在屏幕上）。
   同一份 DOM：桌面上 .pw-nav / .pw-toc 是栏，手机上是从底部升起的抽屉 —— 圆角 14、把手、
   48px 的头（标题 · ✕）、列表自己滚、最高 78% 视口。遮罩 / ✕ / Esc / 选中一项都关（reader.js）。
   动画只动 transform；减少动态时不动。 */
.pw-sheet-head { display: flex; align-items: center; gap: 12px; }
.pw-sheet-close { display: none; }
.pw-scrim { display: none; }
.pw-outline-btn { display: none; }
@media (max-width: 1239px) {
  .pw-outline-btn { display: inline-flex; }
}
.pw-nav.is-sheet, .pw-toc.is-sheet {
  display: block; position: fixed; inset-inline: 0; bottom: 0; z-index: 40;
  max-height: 78dvh; box-sizing: border-box; overflow-y: auto; overscroll-behavior: contain;
  padding: 0 8px 20px; padding-bottom: max(20px, env(safe-area-inset-bottom));
  background: var(--surface); border: 1px solid var(--mark); border-bottom: 0;
  border-radius: 14px 14px 0 0; box-shadow: 0 -12px 40px -14px rgba(16, 22, 20, .4);
  transform: translateY(100%); visibility: hidden;
  transition: transform .2s ease, visibility 0s linear .2s;
}
.pw-nav.is-sheet.is-open, .pw-toc.is-sheet.is-open { transform: none; visibility: visible; transition: transform .2s ease; }
.pw-toc.is-sheet .pw-toc-in { position: static; max-height: none; overflow: visible; margin: 0; padding: 0; }
.is-sheet .pw-sheet-head {
  position: sticky; top: 0; z-index: 1; flex-wrap: wrap; gap: 0 12px;
  min-height: 48px; margin: 0 0 6px; padding: 0 4px 0 12px; background: var(--surface); border-bottom: 1px solid var(--line);
}
/* 把手：头顶正中一段 36×4 的灰条 */
.is-sheet .pw-sheet-head::before {
  content: ""; flex-basis: 100%; width: 36px; height: 4px; margin: 8px auto 2px; border-radius: 2px; background: var(--mark);
}
.is-sheet .pw-tree-head, .is-sheet .pw-toc-h {
  flex-grow: 1; margin: 0; padding: 0; font-family: var(--font); font-size: 16px; font-weight: 500;
  letter-spacing: 0; text-transform: none; color: var(--fg);
}
.is-sheet .pw-sheet-close {
  display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px;
  border: 0; border-radius: var(--radius); background: none; color: var(--dim); cursor: pointer;
}
.is-sheet .pw-sheet-close:hover { background: var(--code-bg); color: var(--fg); }
/* 抽屉里「全部折叠 / 展开」与关闭按钮一样大：手指点的 */
.is-sheet .pw-toc-all { inline-size: 36px; block-size: 36px; border: 0; border-radius: var(--radius); }
.is-sheet .pw-toc-all:hover { background: var(--code-bg); }
.pw-nav.is-sheet .pw-tree-item > a, .pw-nav.is-sheet .pw-tree-label {
  display: flex; align-items: center; min-height: 44px; padding: 8px 12px; font-size: 15px; line-height: 1.35;
}
.pw-nav.is-sheet .pw-tree-item.is-folder { margin-top: 2px; }
.pw-toc.is-sheet ol { padding-inline-start: 8px; }
.pw-toc.is-sheet a { min-height: 40px; padding-block: 9px; font-size: 14.5px; }
.pw-toc.is-sheet .pw-toc-fold { inset-block-start: 8px; }
.pw-toc.is-sheet .pw-toc-d3 > a { font-size: 13.5px; }
.pw-scrim.is-on {
  display: block; position: fixed; inset: 0; z-index: 39; background: rgba(16, 22, 20, .42);
}
html.pw-sheet-open, html.pw-sheet-open body { overflow: hidden; }
@media (prefers-reduced-motion: reduce) {
  .pw-nav.is-sheet, .pw-toc.is-sheet { transition: none; }
}

/* callout（> [!NOTE] 那一族）。
   摄取管线早就在 blockquote 上挂了 pw-callout 与 data-callout，但一直没人
   给它上色 —— 于是页面上它和普通引用长得一模一样，而作者写 [!WARNING]
   的时候是**指望它显眼**的。标签用 ::before 读 data-callout 生成，
   这也是消毒器特意放行那个属性的原因。 */
/* 2026-10-09（MarkdownStyle 画板）：一张浅底卡，左上一枚图标 + 首字母大写的类型名，替掉以前 10.5px 的
   等宽大写小签 —— 作者写 [!WARNING] 是要它被看见。图标是 ::after 上的蒙版（颜色随类型的变量走，
   SVG 里没有色值）；类型名仍是 ::before 读 data-callout，正文 HTML 一个字没改，已发布的全部跟着换。 */
.pw-body .pw-callout {
  --pw-co: var(--accent-dark); --pw-co-bg: var(--note-bg); --pw-co-icon: var(--pw-i-note);
  position: relative; margin: 1.5em 0; padding: 12px 16px 13px 42px;
  border: 1px solid color-mix(in srgb, var(--pw-co) 22%, transparent); border-radius: var(--doc-radius);
  background: var(--pw-co-bg); color: var(--fg);
}
.pw-body .pw-callout > :first-child { margin-top: 0; }
.pw-body .pw-callout > :last-child { margin-bottom: 0; }
.pw-body .pw-callout::before {
  content: attr(data-callout);
  display: block; margin-bottom: 2px;
  font-family: var(--font); font-size: .9em; font-weight: 700; line-height: 1.6;
  letter-spacing: 0; text-transform: capitalize; color: var(--pw-co);
}
.pw-body .pw-callout::after {
  content: ""; position: absolute; inset-inline-start: 15px; inset-block-start: 15.5px;
  inline-size: 17px; block-size: 17px; background: var(--pw-co);
  -webkit-mask: var(--pw-co-icon) center / contain no-repeat; mask: var(--pw-co-icon) center / contain no-repeat;
}
.pw-body .pw-callout-tip { --pw-co: var(--ok-fg); --pw-co-bg: var(--ok-bg); --pw-co-icon: var(--pw-i-tip); }
.pw-body .pw-callout-important { --pw-co: var(--pw-c4); --pw-co-bg: color-mix(in srgb, var(--pw-c4) 9%, var(--bg)); --pw-co-icon: var(--pw-i-important); }
.pw-body .pw-callout-warning { --pw-co: var(--warn-fg-dark); --pw-co-bg: var(--warn-bg); --pw-co-icon: var(--pw-i-warning); }
.pw-body .pw-callout-caution { --pw-co: var(--danger-fg); --pw-co-bg: var(--danger-bg); --pw-co-icon: var(--pw-i-caution); }
/* 窄屏不留悬挂缩进：图标和类型名一行，正文从卡的左边起 —— 手机上那 26px 是一行少两个字 */
@media (max-width: 719px) {
  .pw-body .pw-callout { padding: 11px 14px 12px; }
  .pw-body .pw-callout::before { padding-inline-start: 25px; }
  .pw-body .pw-callout::after { inset-inline-start: 14px; inset-block-start: 14.5px; }
}

/* ---- 图表 ----
   源：docs/design/artboards/Charts.dc.html（那块画板里有这一段的原文）。
   几何由 render/chart_svg.go 算，SVG 里没有任何颜色 —— 全在这里。 */
.pw-chart { margin: 1.6em 0; }
.pw-chart .pw-s0 { --c: var(--pw-c0); } .pw-chart .pw-s1 { --c: var(--pw-c1); }
.pw-chart .pw-s2 { --c: var(--pw-c2); } .pw-chart .pw-s3 { --c: var(--pw-c3); }
.pw-chart .pw-s4 { --c: var(--pw-c4); } .pw-chart .pw-s5 { --c: var(--pw-c5); }
.pw-chart .pw-s6 { --c: var(--pw-c6); } .pw-chart .pw-s7 { --c: var(--pw-c7); }

.pw-chart svg  { width: 100%; height: auto; display: block; }
.pw-chart text { font-family: var(--font); font-size: 11px; fill: var(--dim); }
.pw-grid  { stroke: var(--line); stroke-width: 1; }
.pw-axis  { stroke: var(--mark); stroke-width: 1; }
.pw-zero  { stroke: var(--dim); stroke-width: 1; stroke-dasharray: 3 3; }
.pw-bar, .pw-slice, .pw-dot, .pw-swatch { fill: var(--c); }
.pw-line  { fill: none; stroke: var(--c); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pw-area  { fill: var(--c); opacity: .18; stroke: none; }
.pw-band  { fill: var(--c); opacity: .42; stroke: none; }
/* 扇区上的百分比压在扇区颜色上，所以它跟着**配色的明暗**走而不是跟着主题：
   浅色下扇区是深色，字要白；深色下配色整体调亮，白字就没对比度了。
   ⚠️ 选择器必须带 .pw-chart 前缀：上面的 `.pw-chart text` 是 (0,1,1)，
   光写 `.pw-slice-label` 是 (0,1,0)，会被压掉 —— 而压掉之后标签变成 --dim，
   看起来只是「有点淡」，不像坏了。 */
.pw-chart .pw-slice-label { fill: var(--slice-ink); font-weight: 600; }
.pw-chart .pw-donut-center { fill: var(--fg); font-size: 13px; font-weight: 600; }

.pw-chart figcaption {
  margin-top: 8px; color: var(--dim); font-size: 13.5px; text-align: center;
}
/* 数据表：图表能被搜索引擎与 llms.txt 读到的唯一途径，所以它一直在 DOM 里，
   只是默认折起来。别改成 display:none —— 那会连爬虫一起挡掉。 */
.pw-chart-data { margin-top: 8px; font-size: 13px; }
.pw-chart-data summary {
  color: var(--dim); cursor: pointer; font-family: var(--mono); font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase;
}
.pw-chart-data table { margin-top: 8px; }
.pw-block-bad {
  padding: 12px 14px; border: 1px dashed var(--dangerLine, var(--mark));
  border-radius: var(--radius); background: var(--muted);
}
.pw-block-err { margin: 0; color: var(--warn-fg-dark); font-family: var(--mono); font-size: 12.5px; }

/* 宽窄两版：640 的 viewBox 缩到手机宽度只剩 0.51 倍，11px 轴标签落地是 5.6px。
   一份 SVG 做不到「图缩小、字不缩」，因为布局是按字宽算的。 */
.pw-chart .pw-narrow { display: none; }
@media (max-width: 559px) {
  .pw-chart .pw-wide { display: none; }
  .pw-chart .pw-narrow { display: block; }
}

/* ---- 模板 ----
   2026-09-19 之前这里有四套「主题」（manual / whitepaper / reference / note）各自的变量。
   主题没有了：模板（文章、简历…）的样子全在它自己的设计快照里，用的是下面这些
   --doc-* 变量与 [data-*] 属性；平台基线就是 :root 上的默认值。 */

/* 结构规则挂在 data-doc-layout 上，不挂在模板名上。
   两者是不同的东西：模板决定**长什么样**（字号、行距、组件），
   版式决定**有几列**。分开之后，市场里一个新模板写 layout: single
   就能拿到文章页的骨架，不必等我们在这里补一条选择器 ——
   而「新模板的排版要改 reader.css 才生效」等于模板市场根本没有市场。 */
/* is-solo：单独公开的一篇或 doc scope 直链。没有树，所以外壳少掉左边那一栏 ——
   模板连 nav 都不渲染，这里只负责让栅格别给它留位。目录（右栏）照旧。 */
@media (min-width: 900px) {
  .pw-shell.is-solo { grid-template-columns: minmax(0, 1fr); }
}
@media (min-width: 1240px) {
  .pw-shell.is-solo { grid-template-columns: minmax(0, 1fr) var(--w-toc); }
  /* 沙箱里跑的网页（body.is-artifact）不出本页目录，也就不给它留那一栏 —— 留着就是右边一条空白。
     ReaderSandbox 画板只有树与内容两栏：那份内容要整列的宽。 */
  body.is-artifact .pw-shell { grid-template-columns: var(--w-nav) minmax(0, 1fr); }
  body.is-artifact .pw-shell.is-solo { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 文章页：single 版式（ReaderArticle / TemplateLooks 画板，2026-09-19）----
   single 是有设计感的长文（文章模板与它的变体）：没有目录树那一栏。
   有树的版式把正文栏锚在树旁边、从左边开始；没有树的文章没有东西可以锚，
   于是**正文容器 + 右侧目录是一组，一起居中**：容器最宽 1180，封面、表格、代码、图
   撑到容器边，散文停在模板的 measure，目录贴在容器右边而不是窗口右边。
   以前这里把整个外壳卡在 1040 居中、还把目录藏掉 —— 一屏 1920 只用中间 656px，
   而目录在桌面上没有任何入口（本页目录按钮只在 <1240 出现）。
   制品（body.is-artifact）不在此列：那份内容要整列的宽，见上面 .is-frame 一段。 */
@media (min-width: 900px) {
  [data-doc-layout="single"] body:not(.is-artifact) .pw-shell,
  [data-doc-layout="single"] body:not(.is-artifact) .pw-shell.is-solo {
    grid-template-columns: minmax(0, var(--reader-article-max)); justify-content: center;
  }
  [data-doc-layout="single"] body:not(.is-artifact) .pw-main { padding-inline: var(--reader-article-gutter); }
  /* 文章页里散文撑满容器：容器本身就是行长（最宽 1180，减去两边留白约 1068 ≈ 120ch，
     与平台默认的 measure 一个量级）。模板的 measure 令牌在这个版式里不再截断段落 ——
     用户看着 64ch 的段落说「没有撑满一行就换行了」；而且 measure 冻在每篇的设计快照里，
     只改模板令牌救不了已发布的那些。 */
  [data-doc-layout="single"] body:not(.is-artifact) .pw-body > :is(p, ul, ol, dl, blockquote) { max-width: none; }
  /* 有树时树收进 ☰ 抽屉：长文仍然需要在空间里跳转，只是不常驻。 */
  [data-doc-layout="single"] .pw-nav { display: none; }
  [data-doc-layout="single"] .pw-nav.is-open {
    display: block; position: static; max-height: none;
    border-inline-end: 0; border-bottom: 1px solid var(--line);
  }
  [data-doc-layout="single"] .pw-menu { display: grid; }
}
@media (min-width: 1240px) {
  /* 目录栏右侧的留白是正文容器左侧留白的镜像：容器左边留 --reader-article-gutter，目录右边留
     同一个值减 4 —— 目录的每一条与标题行各自内缩 4px，看得见的右边界是那一层。一组居中之后，
     文字左边与目录右边的空白在任何宽度都相等（ReaderArticle 画板 v128）。以前右边是页面边
     --edge：1920 上被两边各 220 的居中留白盖住，到 1280–1512 的笔记本上左边比右边宽 20 多 px
     （用户：「这个左右边距是不是不对」）。收起时目录栏只剩那枚按钮，留白照样镜像。 */
  [data-doc-layout="single"] body:not(.is-artifact) .pw-shell,
  [data-doc-layout="single"] body:not(.is-artifact) .pw-shell.is-solo {
    --toc-end: calc(var(--reader-article-gutter) - 4px);
    --w-toc: calc(260px + var(--toc-end));
    grid-template-columns: minmax(0, var(--reader-article-max)) var(--w-toc);
  }
  html[data-outline="hidden"][data-doc-layout="single"] body:not(.is-artifact) .pw-shell {
    --w-toc: calc(36px + var(--toc-end));
  }
  [data-doc-layout="single"] body:not(.is-artifact) .pw-toc { padding: 0 var(--toc-end) 0 0; }
}

/* ---- 简历（```resume）----
   沿用 TemplateLooks / ReaderInline 的既有设计词汇：这里**一个新色值都没有**，
   全是已有变量，所以浅色、深色、四套版式下都自动是对的
   （画板补齐的处理方式见 docs/design/README.md「待补的画板」）。

   ⚠️ 类名与 render/resume.go 吐的 HTML 一一对应。消毒器会丢掉
   <header>/<footer>/<main>，所以那边用的是 div —— 换标签之前先看
   resume_test.go 里那条盯着消毒器的测试。 */
.pw-resume { margin: 1.4em 0; }
.pw-resume-head {
  margin-bottom: 18px; padding-bottom: 12px; border-bottom: 2px solid var(--accent);
}
.pw-resume-name {
  margin: 0; font-family: var(--doc-h-font); font-size: 1.9em;
  line-height: 1.15; font-weight: 600; color: var(--fg);
}
.pw-resume-title { margin: 4px 0 0; font-size: 1.05em; color: var(--accent-dark); }
.pw-resume-contact {
  display: flex; flex-wrap: wrap; gap: 3px 16px;
  margin: 10px 0 0; font-size: .88em; color: var(--dim);
}
.pw-resume-summary { margin: 0 0 1.4em; color: var(--body); }
/* 侧栏只在有内容且屏幕够宽时才成为一列。resume.go 在没有侧栏时
   根本不输出 .pw-resume-cols —— 空列会让主栏无缘无故窄一截。 */
.pw-resume-cols { display: grid; gap: 0 32px; }
@media (min-width: 720px) {
  .pw-resume-cols { grid-template-columns: minmax(0, 1fr) 208px; }
}
.pw-resume-sec { margin: 0 0 1.4em; }
.pw-resume .pw-resume-sec > h2 {
  margin: 0 0 .7em; padding: 0 0 4px;
  border-bottom: 1px solid var(--line); border-inline-start: 0; padding-inline-start: 0;
  font-family: var(--doc-h-font); font-size: 1em; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--dim);
}
.pw-resume-item { margin: 0 0 1.1em; }
.pw-resume-role { margin: 0; font-weight: 600; color: var(--fg); }
.pw-resume-meta {
  display: flex; flex-wrap: wrap; gap: 1px 12px;
  margin: 2px 0 6px; font-size: .87em; color: var(--dim);
}
.pw-resume-org { color: var(--body); font-weight: 500; }
.pw-resume-when { font-family: var(--mono); font-size: .93em; }
.pw-resume-note { margin: 0 0 6px; color: var(--body); }
.pw-resume-item ul { margin: 0; padding-inline-start: 1.15em; }
.pw-resume-item li { margin: .18em 0; }
.pw-resume-side { font-size: .95em; }
.pw-resume-tags {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none;
}
.pw-resume-tags li {
  padding: 2px 8px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--muted); font-size: .84em; color: var(--body);
}

/* ---- 沙箱里那份独立文档（render.Frame）----
   它没有顶栏、没有侧边树：带 CSS 的模板要的就是一整页归自己，
   我们只负责给出版心和基础排版，剩下的让模板覆盖。 */
body.pw-frame { margin: 0; background: var(--bg); color: var(--body); }
body.pw-frame > .pw-body {
  max-width: var(--doc-measure); margin: 0 auto; padding: 28px 20px 64px;
}

/* artifact：铺满，不要文章行长。种类是 running page，不是 typeset doc。 */
body.pw-frame.pw-artifact { margin: 0; }
body.pw-frame.pw-artifact > .pw-artifact-root {
  max-width: none; margin: 0; padding: 0; min-height: 100dvh;
}
[data-pw-artifact] {
  contain: paint;
  isolation: isolate;
  position: relative;
}

@media print {
  .pw-top, .pw-nav, .pw-toc, .pw-pager, .pw-foot, .pw-menu, .pw-scrim { display: none !important; }
  .pw-main { padding: 0; }
  .pw-body { max-width: none; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 11px; color: #666; }
  /* 打印用宽版：纸比手机宽。数据表一律展开 —— 打出来的东西没法点开 <details>。 */
  .pw-chart .pw-narrow { display: none !important; }
  .pw-chart .pw-wide { display: block !important; }
  .pw-chart-data[open], .pw-chart-data { display: block; }
  .pw-chart-data > *:not(summary) { display: revert !important; }
  .pw-chart, figure { break-inside: avoid; }
  /* 简历基本上就是为了打印/导 PDF 而存在的：一条经历被分页切成两半
     是这份东西最难看的失败方式。 */
  .pw-resume-item, .pw-resume-head { break-inside: avoid; }
  .pw-resume-sec > h2 { break-after: avoid; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* ══════════════════════════════════════════════════════════════════════
   v0.2：文档容器、令牌属性、组件外壳、库块、embed、行为原语
   出处：docs/design/artboards/Components.dc.html（待补，见 docs/design/README.md）
   ══════════════════════════════════════════════════════════════════════ */

/* 文档容器 —— **不要删这三行**。
 *
 * 它们是「模板作者可以写真的 CSS」这件事的第四道保证
 * （docs/TEMPLATES.md §5.2：解析 → 白名单 → 作用域 → 容器隔离）。
 * 前三道在 render/css 里，这一道在这里：
 *
 *   contain: paint    → position: fixed / 超大 z-index / 100vw 的元素
 *                       **画不出这个盒子**
 *   isolation: isolate → 新的层叠上下文，z-index 出不去
 *   position: relative → 让绝对定位的子元素以它为基准，而不是视口
 *
 * 所以 position / z-index / transform 才敢出现在放行清单里 ——
 * 隔离靠容器，不靠禁属性。这三行看起来毫无作用，删掉之后
 * 一个模板就能盖住整个界面，而那件事只有被人做出来才会被发现。 */
[data-pw-doc] {
  contain: paint;
  isolation: isolate;
  position: relative;
}

/* ---------- 属性型令牌 ----------
 *
 * 每一个都对应 render/builtin/base-tokens.yaml 里的一个 enum 令牌，
 * 值落在文档容器的 data-* 上。为什么不映射成一个 CSS 变量：像 bar 这种
 * 取值要同时改两三条声明（关掉横线、加一根竖条、加内边距），
 * 一个变量承载不了。 */

/* 分节标题的装饰 */
[data-pw-doc][data-rule="line"].pw-body h2 { border-bottom: 1px solid var(--line); padding-bottom: .3em; }
[data-pw-doc][data-rule="none"].pw-body h2 { border-bottom: 0; padding-bottom: 0; }
[data-pw-doc][data-rule="bar"].pw-body h2 {
  border-bottom: 0; padding-bottom: 0;
  padding-inline-start: .6em; border-inline-start: 3px solid var(--accent);
}
[data-pw-doc].pw-body h2 { font-size: var(--doc-h2-size); text-align: var(--doc-h2-align); }
[data-pw-doc][data-align="center"].pw-body h2,
[data-pw-doc][data-align="center"].pw-body h3 { text-align: center; }

/* 自动编号。counter 挂在容器上，于是一篇文档里的编号从 1 开始，
   而不是跟着页面上别的东西累加。 */
[data-pw-doc][data-numbering] { counter-reset: pw-h2; }
[data-pw-doc][data-numbering="decimal"].pw-body h2,
[data-pw-doc][data-numbering="roman"].pw-body h2,
[data-pw-doc][data-numbering="badge"].pw-body h2 { counter-increment: pw-h2; }
[data-pw-doc][data-numbering="decimal"].pw-body h2::before {
  content: counter(pw-h2) ". "; color: var(--accent); font-variant-numeric: tabular-nums;
}
[data-pw-doc][data-numbering="roman"].pw-body h2::before {
  content: counter(pw-h2, upper-roman) ". "; color: var(--accent);
}
[data-pw-doc][data-numbering="badge"].pw-body h2::before {
  content: counter(pw-h2);
  display: inline-grid; place-items: center;
  inline-size: 1.5em; block-size: 1.5em; margin-inline-end: .5em;
  border-radius: 50%; background: var(--accent); color: var(--accent-fg);
  font-family: var(--mono); font-size: .6em; font-weight: 700; vertical-align: .25em;
}

/* 图片 */
[data-pw-doc].pw-body img { border-radius: 0; }
[data-pw-doc][data-img="rounded"].pw-body img { border-radius: var(--doc-radius); }
[data-pw-doc][data-img="card"].pw-body img {
  border-radius: var(--doc-radius); box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 8px 24px rgba(0,0,0,.08);
}
[data-pw-doc][data-img="frame"].pw-body img {
  border-radius: var(--doc-radius); border: 1px solid var(--line); padding: 6px; background: var(--surface);
}

/* 链接 */
[data-pw-doc][data-link="underline"].pw-body a { text-decoration: underline; text-underline-offset: .16em; }
[data-pw-doc][data-link="accent"].pw-body a { text-decoration: none; color: var(--accent); font-weight: 500; }
[data-pw-doc][data-link="plain"].pw-body a { text-decoration: none; color: inherit; border-bottom: 1px solid var(--mark); }

/* 列表标记 */
[data-pw-doc][data-list="dash"].pw-body ul { list-style: none; padding-inline-start: 1.1em; }
[data-pw-doc][data-list="dash"].pw-body ul > li::before {
  content: "—"; color: var(--dim); margin-inline-start: -1.1em; margin-inline-end: .45em;
}
[data-pw-doc][data-list="accent"].pw-body ul > li::marker { color: var(--accent); }
[data-pw-doc][data-list="none"].pw-body ul { list-style: none; padding-inline-start: 0; }

/* 表格 */
[data-pw-doc][data-table="zebra"].pw-body tbody tr:nth-child(even) { background: var(--muted); }
[data-pw-doc][data-table="plain"].pw-body table { border: 0; border-radius: 0; }
[data-pw-doc][data-table="plain"].pw-body th,
[data-pw-doc][data-table="plain"].pw-body td { border: 0; border-bottom: 1px solid var(--line); }
[data-pw-doc][data-table="plain"].pw-body thead th { background: none; }

/* 代码块 */
[data-pw-doc][data-codeblock="plain"].pw-body pre { background: none; border: 1px solid var(--line); }
[data-pw-doc][data-codeblock="dark"].pw-body pre { background: #10221D; color: #E7EEEB; border-color: transparent; }
[data-pw-doc][data-codeblock="dark"].pw-body pre code { color: inherit; }
/* 浅色页面上的深色代码块：词元颜色换成深色那套色位（值与上面 :root[data-theme=dark] 的同一份，
   源 DarkPalette / Charts 画板）——浅色色位压在深底上没有对比度。 */
[data-pw-doc][data-codeblock="dark"].pw-body pre {
  --pw-c0: #4FBCAF; --pw-c1: #E0AE5A; --pw-c2: #D98A76; --pw-c3: #6FA97F;
  --pw-c4: #7E9BD1; --pw-c5: #C08FCA; --dim: #849490; --body: #B4C0BB;
  --danger-fg: #E9A79C; --ok-fg: #8FCB9B;
}
/* 角上的语言名与复制按钮挂在外壳 .pw-code 上，不在 pre 里 —— pre 换了底，它们得跟着换，
   否则深色块上会压一块浅色的签。深色那组值与上面 pre 的、与深色主题的同一份。 */
[data-pw-doc][data-codeblock="plain"].pw-body .pw-code[data-lang]::before { background: var(--bg); }
[data-pw-doc][data-codeblock="dark"].pw-body .pw-code {
  --code-bg: #10221D; --dim: #849490; --fg: #E3EAE6; --surface: #1A2220; --line: #273130;
}

/* 节奏。组件用 calc(… * var(--doc-rhythm)) 接它，正文段落在这里接。 */
[data-pw-doc].pw-body p,
[data-pw-doc].pw-body ul,
[data-pw-doc].pw-body ol { margin-block: calc(1em * var(--doc-rhythm)); }
[data-pw-doc].pw-body h2 { margin-block-start: calc(1.8em * var(--doc-rhythm)); }

/* ---------- 组件外壳 ----------
 *
 * 每个组件的产出被套在 .pw-c.pw-c-<名字> 里，而组件自己那段 CSS
 * 被作用域到那个类下面。外壳本身**不带外边距**：间距是组件的设计，
 * 外壳只提供一个作用域。 */
.pw-c { display: block; }
.pw-c > :first-child { margin-block-start: 0; }

/* 组件出错时那个看得见的方块。不静默失败：作者要能一眼看到
   哪一块坏了、为什么坏。 */
.pw-block-bad {
  margin: 1.4em 0; padding: 10px 12px;
  border: 1px solid var(--warn-fg); border-radius: var(--radius-md);
  background: var(--warn-bg);
}

/* ---------- 库块（mermaid / katex / echarts …） ----------
 *
 * ⚠️ **声明原文默认可见。** 它只在 JS 真的把这块升级成图之后才隐藏。
 * 这是这一层能同时要「图」和「SEO」的全部理由：爬虫、屏幕阅读器、
 * 没有 JS 的读者拿到的是那段声明，不是一个空框。
 * 谁想把 display:none 挪到默认状态上，请先回答「爬虫看到什么」。 */
.pw-lib { margin: calc(1.6em * var(--doc-rhythm)) 0; }
.pw-lib-src {
  margin: 0; padding: 12px 14px; overflow-x: auto;
  background: var(--code-bg); border-radius: var(--doc-radius);
  font-family: var(--mono); font-size: 12.5px; line-height: 1.6; font-variant-ligatures: none;
}
.pw-lib > figcaption { margin-top: .5em; font-size: 13px; color: var(--dim); }
.pw-lib.is-ready .pw-lib-src { display: none; }
.pw-lib.is-ready > .pw-lib-out { display: block; overflow-x: auto; }
/* 画出来的图（流程图、时序图 …）居中，不再顶在左边；宽度是它自己的自然尺寸（Mermaid 写在
   行内样式里），只在比栏窄的屏上收到栏宽。 */
.pw-lib-out svg { display: block; max-width: 100%; height: auto; margin: 0 auto; }
/* Mermaid 的节点文字是 foreignObject 里的 HTML（<p>、<span>）。它在 body 下的临时容器里量尺寸，
   量完才被放进 .pw-body —— 于是正文那些 `.pw-body p { font-size: 1rem }`、标题外边距会在放进来
   之后才生效，框是按 14px 量的、字按 16px 画，每个词都被切掉半个字。这里把正文排版在图里
   归零，让画出来的和量出来的是同一副样子。 */
.pw-lib-out { overflow-wrap: normal; }
.pw-lib-out :is(p, h1, h2, h3, h4, h5, h6, ul, ol, li) {
  margin: 0; padding: 0; font: inherit; line-height: inherit;
}
/* 流程图的方框和站点的卡片同一种圆角（Mermaid 自己不给圆角配置；rx 作为 CSS 属性各家浏览器都认） */
.pw-lib-out svg .node rect { rx: 4px; ry: 4px; }
.pw-lib-off .pw-lib-src { border-inline-start: 3px solid var(--warn-fg); }
/* ---------- 图：点开全屏单独看（DiagramFullscreen 画板） ----------
 *
 * 文档里：右上角一枚按钮，悬停或键盘聚焦时才露出来；触屏没有悬停，一直在。整张图也能点（zoom-in 光标）。
 * 查看层：铺满窗口、页面自己的底色（图的颜色是照着这块底画的），标题 · 退出在上，缩放条在下。
 * 颜色变量由 reader.js 从这篇文档抄到查看层上 —— 它挂在 <body> 上，不在 [data-pw-doc] 里。 */
/* 图表（.pw-chart）同一套：按钮挂在图的右上角，点在图上就打开（点图题、数据表不算，reader.js 拦） */
.pw-lib.is-zoomable, .pw-chart.is-zoomable { position: relative; }
.pw-lib.is-zoomable > .pw-lib-out, .pw-chart.is-zoomable > svg { cursor: zoom-in; }
.pw-dgv-open {
  position: absolute; inset-block-start: 0; inset-inline-end: 0; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 32px; block-size: 32px; padding: 0;
  border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--dim);
  box-shadow: 0 1px 2px rgba(16, 22, 20, .06); cursor: pointer;
  opacity: 0; transition: opacity .12s ease, color .12s ease;
}
.pw-lib.is-zoomable:hover > .pw-dgv-open, .pw-chart.is-zoomable:hover > .pw-dgv-open, .pw-dgv-open:focus-visible { opacity: 1; }
.pw-dgv-open:hover { color: var(--fg); }
@media (hover: none) { .pw-dgv-open { opacity: 1; } }

html.pw-dgv-locked, html.pw-dgv-locked body { overflow: hidden; }
.pw-dgv {
  position: fixed; inset: 0; z-index: 110; overflow: hidden; outline: none;
  background: var(--bg); color: var(--body); font-family: var(--font);
  animation: pw-dgv-in .12s ease-out;
}
@keyframes pw-dgv-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .pw-dgv { animation: none; } }
.pw-dgv-stage { position: absolute; inset: 0; cursor: grab; touch-action: none; }
.pw-dgv.is-dragging .pw-dgv-stage { cursor: grabbing; }
/* 只平移，不缩放：缩放改的是 SVG 的宽高（reader.js），所以放到多大字都是清楚的 */
.pw-dgv-canvas { position: absolute; inset-block-start: 0; inset-inline-start: 0; transform-origin: 0 0; overflow-wrap: normal; }
.pw-dgv-canvas svg { display: block; max-width: none; }
/* 图表的克隆外面套的那层 .pw-chart 只为让配色与字的选择器认得它，文档里的上下间距不要 */
.pw-dgv-canvas > .pw-chart { margin: 0; }
/* 与 .pw-lib-out 同一组归零：节点字是 foreignObject 里的 HTML，按什么量的就得按什么画 */
.pw-dgv-canvas :is(p, h1, h2, h3, h4, h5, h6, ul, ol, li) { margin: 0; padding: 0; font: inherit; line-height: inherit; }
.pw-dgv-canvas svg .node rect { rx: 4px; ry: 4px; }
.pw-dgv-head {
  position: absolute; inset-block-start: 16px; inset-inline: 20px 16px;
  display: flex; align-items: center; gap: 12px; pointer-events: none;
}
.pw-dgv-title {
  flex: 1; min-inline-size: 0; font-size: 14px; font-weight: 500; line-height: 32px; color: var(--body);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-dgv-exit {
  pointer-events: auto; display: inline-flex; align-items: center; gap: .3em; block-size: 32px; padding: 0 12px;
  border: 0; border-radius: 16px; background: color-mix(in srgb, var(--fg) 72%, transparent); color: var(--bg);
  font: inherit; font-size: 12.5px; white-space: nowrap; cursor: pointer;
}
@media (pointer: coarse) { .pw-dgv-esc { display: none; } }
.pw-dgv-bar {
  position: absolute; inset-inline-start: 50%; inset-block-end: max(24px, calc(env(safe-area-inset-bottom) + 12px));
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 2px; block-size: 44px; padding: 0 4px;
  border: 1px solid var(--line); border-radius: 22px; background: var(--surface);
  box-shadow: 0 1px 2px rgba(16, 22, 20, .06), 0 12px 32px -14px rgba(16, 22, 20, .32);
}
.pw-dgv-bar button {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 36px; block-size: 36px; padding: 0; border: 0; border-radius: 18px;
  background: transparent; color: var(--body); cursor: pointer;
}
.pw-dgv-bar button:hover:not(:disabled) { background: var(--muted); color: var(--fg); }
.pw-dgv-bar button:disabled { opacity: .35; cursor: default; }
.pw-dgv-pct {
  min-inline-size: 52px; text-align: center; font-family: var(--mono); font-size: 12px;
  font-variant-numeric: tabular-nums; color: var(--body);
}
.pw-dgv-sep { inline-size: 1px; block-size: 20px; margin: 0 4px; background: var(--line); }
.pw-dgv :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.pw-lib-off > figcaption { color: var(--warn-fg-dark); }
.pw-lib-out .katex-display { overflow-x: auto; overflow-y: hidden; }
.pw-math-inline { display: inline; margin: 0; }
.pw-math-inline > .pw-lib-src {
  display: inline; margin: 0; padding: 0 .15em; overflow: visible;
  border-radius: 3px; font-size: .9em; line-height: inherit;
}
.pw-math-inline.is-ready > .pw-lib-out { display: inline; overflow: visible; }

/* ---------- embed：一块要跑代码的东西 ----------
 *
 * 页面其余部分仍然 inline、仍然被索引 —— 只有这一块在隔离源上跑
 * （docs/TEMPLATES.md §6.6）。iframe 由 reader.js 换进来；换进来之前
 * 读者看到的是海报、标题与说明，而不是一个空框。 */
.pw-embed {
  margin: calc(1.6em * var(--doc-rhythm)) 0;
  border: 1px solid var(--mark); border-radius: var(--doc-radius);
  overflow: hidden; background: var(--surface);
}
.pw-embed-poster { display: block; width: 100%; height: auto; }
.pw-embed-title { margin: 0; padding: 10px 14px; font-weight: 600; font-size: 14px; }
.pw-embed-note { margin: 0; padding: 0 14px 12px; font-size: 13px; color: var(--dim); }
.pw-embed iframe { display: block; width: 100%; border: 0; background: var(--bg); }
.pw-embed.is-ready .pw-embed-poster { display: none; }

/* ---------- 行为原语 ----------
 *
 * ⚠️ 每一条的**默认状态都是「全部显示」**，收起来的样子只在
 * .is-ready 之后才生效 —— 而 .is-ready 是 reader.js 加的。
 *
 * 这条是这一层能同时要「交互」和「SEO」的全部理由：所有状态的内容
 * 都在 DOM 里，JS 只决定显示哪一个。于是爬虫、屏幕阅读器、没有 JS 的
 * 读者拿到的是**全部**内容，而不是第一屏。
 * 谁想把某个行为的初始状态写成 display:none，请先回答同一个问题。 */

/* reveal：滚动进入视口时淡入。没有 JS 时它本来就是显示的。 */
[data-behavior="reveal"].is-ready { opacity: 0; transform: translateY(10px); }
[data-behavior="reveal"].is-ready.is-in {
  opacity: 1; transform: none;
  transition: opacity .5s ease, transform .5s ease;
}

/* steps：一次显示一步。 */
[data-behavior="steps"].is-ready .pw-step-hidden { display: none; }
/* 导航在列表上面（reader.js 把它插在最前）：按钮钉在原地，新的一步在下面展开。 */
.pw-steps-nav {
  display: flex; gap: 8px; align-items: center;
  margin: 0 0 12px; font-size: 13px; color: var(--dim);
}
.pw-steps-nav button {
  min-height: 32px; padding: 4px 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-md);
  background: var(--surface); color: var(--fg); font: inherit; font-size: 13px;
}
.pw-steps-nav button[disabled] { opacity: .45; cursor: default; }
.pw-steps-dots { display: flex; gap: 5px; margin-inline-start: auto; }
.pw-steps-dots i {
  inline-size: 6px; block-size: 6px; border-radius: 50%;
  background: var(--mark); display: block;
}
.pw-steps-dots i.is-on { background: var(--accent); }

/* scrolly：图钉住，文字滚。窄屏上退回「图在上、文字在下」。 */
[data-behavior="scrolly"].is-ready .pw-scrolly-fig { position: sticky; top: 72px; }
@media (max-width: 719px) {
  [data-behavior="scrolly"].is-ready .pw-scrolly-fig { position: static; }
}

/* tabs / accordion：没有 JS 时全部展开，各自带小标题。 */
[data-behavior="tabs"].is-ready .pw-tab-panel[hidden] { display: none; }
.pw-tablist { display: flex; gap: 4px; flex-wrap: wrap; border-bottom: 1px solid var(--line); }
.pw-tablist button {
  padding: 8px 12px; min-height: 40px; cursor: pointer;
  border: 0; border-bottom: 2px solid transparent; background: none;
  color: var(--dim); font: inherit; font-size: 14px;
}
.pw-tablist button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent); }
[data-behavior="accordion"].is-ready .pw-acc-body[hidden] { display: none; }
.pw-acc-head {
  display: flex; width: 100%; gap: 8px; align-items: center; text-align: start;
  padding: 10px 0; min-height: 44px; cursor: pointer;
  border: 0; border-top: 1px solid var(--line); background: none;
  color: var(--fg); font: inherit; font-weight: 600;
}
.pw-acc-head::before { content: "▸"; color: var(--accent); transition: transform .18s ease; }
.pw-acc-head[aria-expanded="true"]::before { transform: rotate(90deg); }

/* compare：前后对比滑块。没有 JS 时两张图并排。 */
[data-behavior="compare"].is-ready .pw-cmp-wrap { position: relative; overflow: hidden; }
[data-behavior="compare"].is-ready .pw-cmp-wrap > :nth-child(2) {
  position: absolute; inset: 0; clip-path: inset(0 0 0 var(--pw-split, 50%));
}
.pw-cmp-handle {
  position: absolute; inset-block: 0; inset-inline-start: var(--pw-split, 50%);
  inline-size: 2px; background: var(--accent); cursor: ew-resize;
}
.pw-cmp-handle::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 28px; block-size: 28px; margin: -14px 0 0 -14px;
  border-radius: 50%; background: var(--accent);
}

/* hotspot：图上的标注点。没有 JS 时是图 + 一份编号说明列表。 */
[data-behavior="hotspot"].is-ready .pw-hot-note[hidden] { display: none; }
.pw-hot-pin {
  position: absolute; inline-size: 26px; block-size: 26px; cursor: pointer;
  border: 2px solid var(--accent-fg); border-radius: 50%;
  background: var(--accent); color: var(--accent-fg);
  font-family: var(--mono); font-size: 12px; font-weight: 700;
  transform: translate(-50%, -50%);
}

/* carousel：横向翻页。没有 JS 时依次排列。 */
[data-behavior="carousel"].is-ready .pw-car-track {
  display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
[data-behavior="carousel"].is-ready .pw-car-track > * { flex: 0 0 100%; scroll-snap-align: start; }
[data-behavior="carousel"].is-ready .pw-car-track::-webkit-scrollbar { display: none; }

/* lightbox：点图放大。 */
.pw-lightbox {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 24px;
  background: rgba(0,0,0,.82); cursor: zoom-out;
}
.pw-lightbox img { max-width: 100%; max-height: 100%; border-radius: var(--radius-md); }
.pw-lightbox button {
  position: absolute; inset-block-start: 12px; inset-inline-end: 12px;
  min-inline-size: 44px; min-block-size: 44px; cursor: pointer;
  border: 0; border-radius: var(--radius-md);
  background: rgba(255,255,255,.16); color: #fff; font-size: 18px;
}

/* sync：两块内容联动高亮。 */
[data-behavior="sync"].is-ready .is-linked { background: var(--accent-light); border-radius: 3px; }

/* sticky-toc：阅读进度。 */
.pw-toc-progress { block-size: 2px; background: var(--accent); transition: inline-size .12s linear; }

/* ---------- 动画的两条纪律 ----------
 *
 * ① 尊重 prefers-reduced-motion。前面已经有一条全局的 * { animation: none }，
 *    这里再把行为原语显式退回「全部显示」—— 全局那条只关掉动画，
 *    关不掉 display:none。
 * ② 动画不能是内容的唯一载体。所以下面这几条把「收起来」全部还原：
 *    一个只在动画之后才出现的句子，等于一个搜索引擎读不到、
 *    也打印不出来的句子。 */
@media (prefers-reduced-motion: reduce) {
  [data-behavior="reveal"].is-ready { opacity: 1; transform: none; }
  [data-behavior="steps"].is-ready .pw-step-hidden,
  [data-behavior="tabs"].is-ready .pw-tab-panel[hidden],
  [data-behavior="accordion"].is-ready .pw-acc-body[hidden],
  [data-behavior="hotspot"].is-ready .pw-hot-note[hidden] { display: revert; }
}
/* 模板作者可以用 motion: off 关掉全部动效 —— 一份要打印的东西
   （简历、一页纸）本来就不需要它们。 */
[data-pw-doc][data-motion="off"] * { animation: none !important; transition: none !important; }
[data-pw-doc][data-motion="off"] [data-behavior="reveal"].is-ready { opacity: 1; transform: none; }

/* ---------- 打印 ---------- */
@media print {
  /* 打印时**全部展开**：纸上没法点开一个标签页，也没法拖一个滑块。 */
  [data-behavior] .pw-step-hidden,
  [data-behavior] .pw-tab-panel[hidden],
  [data-behavior] .pw-acc-body[hidden],
  [data-behavior] .pw-hot-note[hidden] { display: revert !important; }
  .pw-steps-nav, .pw-tablist, .pw-cmp-handle, .pw-lightbox, .pw-dgv-open, .pw-dgv, .pw-code-copy { display: none !important; }
  [data-behavior="reveal"] { opacity: 1 !important; transform: none !important; }
  [data-behavior="scrolly"] .pw-scrolly-fig { position: static !important; }
  [data-behavior="carousel"] .pw-car-track { display: block !important; overflow: visible !important; }
  /* 库块印不出来的那些（图要 JS 才有），至少把声明原文留在纸上。 */
  .pw-lib.is-ready .pw-lib-src { display: block !important; }
  .pw-c, .pw-embed, .pw-lib { break-inside: avoid; }
  [data-pw-doc] { contain: none; }
}

/* ---------- 读者自己的开关：明暗 ----------
 *
 * 它是**读者的**偏好，不是作者的设定 —— 和浏览器的字号缩放同一类东西。
 * 所以它落在 <html> 上（`data-theme`），而不是文档容器上：
 * 文档容器上那些是作者冻进去的设计快照，读者的选择不该混进那一份。
 *
 * 必须在**没有 JavaScript 时也成立**：不选明暗就跟着系统。开关只是覆盖，不是启用。
 *
 * 这里曾经还有一条「阅读宽度」规则（加宽 = 散文也不限行长）。版心改成
 * 「散文停在行长、其余撑满整栏」之后它被去掉了：一个只会把行拉到 170 个字符的
 * 按钮不是偏好，是陷阱。别再加回来 —— 想要更宽的散文，改模板令牌 `measure`。
 */


/* 独立导出的那一个 HTML 文件：没有外壳，正文自己撑起页面。 */
body.pw-standalone { background: var(--bg); }
/* 与 Reader Shell 共用 .pw-main 的 gutter / 上下留白；这里只补没有 .pw-shell
   包裹时的最大宽度。以后调整版心只改上面的 Reader Shell 变量。 */
body.pw-standalone .pw-main { max-width: var(--reader-shell-max); margin: 0 auto; }
/* 宽度开关是 standalone 在平台顶栏里的读者覆盖；默认仍与 Markdown 共用 measure。 */
:root[data-width="wide"] body.pw-standalone .pw-body > :is(p, ul, ol, dl, blockquote):not(:has(> img:only-child)) { max-width: none; }
