agentcss 0.0.0-stage → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/01-tokens/README.md +236 -0
  2. package/01-tokens/behavior/dismissable.js +132 -0
  3. package/01-tokens/behavior/emit.js +76 -0
  4. package/01-tokens/behavior/focus-return.js +81 -0
  5. package/01-tokens/behavior/roving.js +152 -0
  6. package/01-tokens/behavior/typeahead.js +124 -0
  7. package/01-tokens/focus-ring-demo.html +133 -0
  8. package/01-tokens/focus-ring.css +102 -0
  9. package/01-tokens/page.css +244 -0
  10. package/01-tokens/polyfill.js +116 -0
  11. package/01-tokens/responsive-demo.html +171 -0
  12. package/01-tokens/scrollbar-demo.html +194 -0
  13. package/01-tokens/scrollbar.css +179 -0
  14. package/01-tokens/theme-toggle.js +103 -0
  15. package/01-tokens/tokens.css +972 -0
  16. package/01-tokens/typography.css +156 -0
  17. package/02-primitives/badge/README.md +71 -0
  18. package/02-primitives/badge/badge.css +141 -0
  19. package/02-primitives/badge/demo.html +101 -0
  20. package/02-primitives/button/README.md +99 -0
  21. package/02-primitives/button/button.css +353 -0
  22. package/02-primitives/button/demo.html +200 -0
  23. package/02-primitives/card/README.md +145 -0
  24. package/02-primitives/card/card.css +246 -0
  25. package/02-primitives/card/demo.html +170 -0
  26. package/02-primitives/choice/README.md +161 -0
  27. package/02-primitives/choice/choice.css +395 -0
  28. package/02-primitives/choice/demo.html +277 -0
  29. package/02-primitives/combobox/README.md +79 -0
  30. package/02-primitives/combobox/combobox.css +223 -0
  31. package/02-primitives/combobox/combobox.js +485 -0
  32. package/02-primitives/combobox/demo.html +109 -0
  33. package/02-primitives/date-range/README.md +100 -0
  34. package/02-primitives/date-range/date-range.css +206 -0
  35. package/02-primitives/date-range/date-range.js +301 -0
  36. package/02-primitives/date-range/demo.html +104 -0
  37. package/02-primitives/input/README.md +170 -0
  38. package/02-primitives/input/demo.html +246 -0
  39. package/02-primitives/input/input.css +239 -0
  40. package/02-primitives/popover/README.md +80 -0
  41. package/02-primitives/popover/demo.html +150 -0
  42. package/02-primitives/popover/popover.css +187 -0
  43. package/02-primitives/popover/popover.js +331 -0
  44. package/02-primitives/progress/README.md +82 -0
  45. package/02-primitives/progress/demo.html +154 -0
  46. package/02-primitives/progress/progress.css +172 -0
  47. package/02-primitives/select/README.md +95 -0
  48. package/02-primitives/select/demo.html +121 -0
  49. package/02-primitives/select/select.css +151 -0
  50. package/02-primitives/select/select.js +549 -0
  51. package/02-primitives/separator/README.md +63 -0
  52. package/02-primitives/separator/demo.html +84 -0
  53. package/02-primitives/separator/separator.css +73 -0
  54. package/02-primitives/skeleton/README.md +69 -0
  55. package/02-primitives/skeleton/demo.html +110 -0
  56. package/02-primitives/skeleton/skeleton.css +96 -0
  57. package/02-primitives/switch/README.md +65 -0
  58. package/02-primitives/switch/demo.html +115 -0
  59. package/02-primitives/switch/switch.css +370 -0
  60. package/03-patterns/accordion/README.md +121 -0
  61. package/03-patterns/accordion/accordion.css +453 -0
  62. package/03-patterns/accordion/accordion.js +369 -0
  63. package/03-patterns/accordion/demo.html +223 -0
  64. package/03-patterns/content/README.md +103 -0
  65. package/03-patterns/content/content.css +286 -0
  66. package/03-patterns/content/demo.html +88 -0
  67. package/03-patterns/drawer/README.md +79 -0
  68. package/03-patterns/drawer/demo.html +101 -0
  69. package/03-patterns/drawer/drawer.css +129 -0
  70. package/03-patterns/drawer/drawer.js +258 -0
  71. package/03-patterns/dropdown/README.md +78 -0
  72. package/03-patterns/dropdown/demo.html +101 -0
  73. package/03-patterns/dropdown/dropdown.css +135 -0
  74. package/03-patterns/dropdown/dropdown.js +451 -0
  75. package/03-patterns/form-validation/README.md +147 -0
  76. package/03-patterns/form-validation/demo.html +280 -0
  77. package/03-patterns/form-validation/form-validation.css +263 -0
  78. package/03-patterns/list/README.md +150 -0
  79. package/03-patterns/list/demo.html +225 -0
  80. package/03-patterns/list/flip.js +201 -0
  81. package/03-patterns/list/list.css +162 -0
  82. package/03-patterns/nav/README.md +225 -0
  83. package/03-patterns/nav/demo.html +131 -0
  84. package/03-patterns/nav/nav.css +314 -0
  85. package/03-patterns/nav/nav.js +430 -0
  86. package/03-patterns/nav/toc.js +111 -0
  87. package/03-patterns/overlay/README.md +196 -0
  88. package/03-patterns/overlay/demo.html +241 -0
  89. package/03-patterns/overlay/overlay.css +319 -0
  90. package/03-patterns/overlay/overlay.js +563 -0
  91. package/03-patterns/pagination/README.md +114 -0
  92. package/03-patterns/pagination/demo.html +165 -0
  93. package/03-patterns/pagination/pagination.css +195 -0
  94. package/03-patterns/pagination/pagination.js +395 -0
  95. package/03-patterns/reveal/README.md +91 -0
  96. package/03-patterns/reveal/demo.html +106 -0
  97. package/03-patterns/reveal/reveal.css +93 -0
  98. package/03-patterns/reveal/reveal.js +172 -0
  99. package/03-patterns/states/README.md +141 -0
  100. package/03-patterns/states/demo.html +240 -0
  101. package/03-patterns/states/states.css +252 -0
  102. package/03-patterns/tabs/README.md +84 -0
  103. package/03-patterns/tabs/demo.html +139 -0
  104. package/03-patterns/tabs/tabs.css +172 -0
  105. package/03-patterns/tabs/tabs.js +307 -0
  106. package/03-patterns/tooltip/README.md +96 -0
  107. package/03-patterns/tooltip/demo.html +78 -0
  108. package/03-patterns/tooltip/tooltip.css +89 -0
  109. package/03-patterns/tooltip/tooltip.js +288 -0
  110. package/03-patterns/tree/README.md +94 -0
  111. package/03-patterns/tree/demo.html +138 -0
  112. package/03-patterns/tree/tree.css +113 -0
  113. package/03-patterns/tree/tree.js +456 -0
  114. package/04-recipes/analysis-report/README.md +80 -0
  115. package/04-recipes/analysis-report/analysis-report.css +187 -0
  116. package/04-recipes/analysis-report/demo.html +274 -0
  117. package/04-recipes/data-showcase/README.md +45 -0
  118. package/04-recipes/data-showcase/demo.html +247 -0
  119. package/04-recipes/detail-page/README.md +93 -0
  120. package/04-recipes/detail-page/demo.html +55 -0
  121. package/04-recipes/detail-page/detail-page.css +190 -0
  122. package/04-recipes/detail-page/full.html +60 -0
  123. package/04-recipes/detail-page/null.html +60 -0
  124. package/04-recipes/detail-page/partial.html +60 -0
  125. package/04-recipes/detail-page/verify-skeleton.py +19 -0
  126. package/04-recipes/longform/README.md +93 -0
  127. package/04-recipes/longform/agc-memory.svg +4 -0
  128. package/04-recipes/longform/content.html +610 -0
  129. package/04-recipes/longform/content.md +51 -0
  130. package/04-recipes/longform/longform.html +627 -0
  131. package/04-recipes/report/README.md +176 -0
  132. package/04-recipes/report/demo.html +355 -0
  133. package/04-recipes/report/report.css +364 -0
  134. package/04-recipes/table/README.md +103 -0
  135. package/04-recipes/table/demo.html +455 -0
  136. package/04-recipes/table/table.css +372 -0
  137. package/04-recipes/tierA-tokens.css +189 -0
  138. package/09-assets/README.md +74 -0
  139. package/09-assets/bar/README.md +94 -0
  140. package/09-assets/bar/bar.css +166 -0
  141. package/09-assets/bar/bar.js +320 -0
  142. package/09-assets/bar/demo.html +176 -0
  143. package/09-assets/echarts-adapter/demo.html +192 -0
  144. package/09-assets/echarts-adapter/echarts-adapter.js +277 -0
  145. package/09-assets/model-viewer/README.md +155 -0
  146. package/09-assets/model-viewer/demo.html +105 -0
  147. package/09-assets/model-viewer/model-viewer.css +143 -0
  148. package/09-assets/model-viewer/model-viewer.js +423 -0
  149. package/09-assets/scientific-plot/README.md +94 -0
  150. package/09-assets/scientific-plot/demo.html +252 -0
  151. package/09-assets/scientific-plot/scientific-plot.css +141 -0
  152. package/09-assets/scientific-plot/scientific-plot.js +610 -0
  153. package/09-assets/sparkline/README.md +153 -0
  154. package/09-assets/sparkline/demo.html +163 -0
  155. package/09-assets/sparkline/sparkline.css +158 -0
  156. package/09-assets/sparkline/sparkline.js +508 -0
  157. package/API.md +332 -0
  158. package/CHANGELOG.md +3138 -0
  159. package/CODE_OF_CONDUCT.md +64 -0
  160. package/CONTRIBUTING.md +89 -0
  161. package/ERRORS.md +1658 -0
  162. package/LICENSE +21 -0
  163. package/README.md +497 -2
  164. package/SECURITY.md +72 -0
  165. package/START-HERE.md +164 -0
  166. package/SUPPORT.md +109 -0
  167. package/adapters/presentation/README.md +113 -0
  168. package/adapters/presentation/check.js +101 -0
  169. package/adapters/presentation/deck.schema.json +74 -0
  170. package/adapters/presentation/to-doc.js +138 -0
  171. package/ai/START-HERE.md +104 -0
  172. package/ai/behaviors.json +380 -0
  173. package/ai/behaviors.schema.json +61 -0
  174. package/ai/capabilities.json +56 -0
  175. package/ai/cli.js +387 -0
  176. package/ai/components.json +1944 -0
  177. package/ai/components.meta.json +168 -0
  178. package/ai/components.schema.json +220 -0
  179. package/ai/contract.schema.json +147 -0
  180. package/ai/deprecations.json +55 -0
  181. package/ai/deprecations.schema.json +85 -0
  182. package/ai/motion-policy.json +22 -0
  183. package/ai/patch.js +323 -0
  184. package/ai/patch.schema.json +63 -0
  185. package/ai/profiles.json +92 -0
  186. package/ai/tokens.audience.json +55 -0
  187. package/ai/tokens.audience.schema.json +73 -0
  188. package/ai/tokens.json +762 -0
  189. package/ai/tokens.schema.json +58 -0
  190. package/ai/tokens.tree.json +752 -0
  191. package/ai/tokens.tree.schema.json +56 -0
  192. package/ai/validate.js +383 -0
  193. package/dist/01-tokens/behavior/dismissable.js +60 -0
  194. package/dist/01-tokens/behavior/emit.js +21 -0
  195. package/dist/01-tokens/behavior/focus-return.js +31 -0
  196. package/dist/01-tokens/behavior/roving.js +77 -0
  197. package/dist/01-tokens/behavior/typeahead.js +61 -0
  198. package/dist/01-tokens/focus-ring.css +1 -0
  199. package/dist/01-tokens/page.css +1 -0
  200. package/dist/01-tokens/polyfill.js +78 -0
  201. package/dist/01-tokens/scrollbar.css +1 -0
  202. package/dist/01-tokens/theme-toggle.js +61 -0
  203. package/dist/01-tokens/tokens.css +1 -0
  204. package/dist/01-tokens/typography.css +1 -0
  205. package/dist/02-primitives/badge/badge.css +1 -0
  206. package/dist/02-primitives/button/button.css +1 -0
  207. package/dist/02-primitives/card/card.css +1 -0
  208. package/dist/02-primitives/choice/choice.css +1 -0
  209. package/dist/02-primitives/combobox/combobox.css +1 -0
  210. package/dist/02-primitives/combobox/combobox.js +439 -0
  211. package/dist/02-primitives/date-range/date-range.css +1 -0
  212. package/dist/02-primitives/date-range/date-range.js +267 -0
  213. package/dist/02-primitives/input/input.css +1 -0
  214. package/dist/02-primitives/popover/popover.css +1 -0
  215. package/dist/02-primitives/popover/popover.js +257 -0
  216. package/dist/02-primitives/progress/progress.css +1 -0
  217. package/dist/02-primitives/select/select.css +1 -0
  218. package/dist/02-primitives/select/select.js +449 -0
  219. package/dist/02-primitives/separator/separator.css +1 -0
  220. package/dist/02-primitives/skeleton/skeleton.css +1 -0
  221. package/dist/02-primitives/switch/switch.css +1 -0
  222. package/dist/03-patterns/accordion/accordion.css +1 -0
  223. package/dist/03-patterns/accordion/accordion.js +219 -0
  224. package/dist/03-patterns/content/content.css +1 -0
  225. package/dist/03-patterns/drawer/drawer.css +1 -0
  226. package/dist/03-patterns/drawer/drawer.js +229 -0
  227. package/dist/03-patterns/dropdown/dropdown.css +1 -0
  228. package/dist/03-patterns/dropdown/dropdown.js +365 -0
  229. package/dist/03-patterns/form-validation/form-validation.css +1 -0
  230. package/dist/03-patterns/list/flip.js +117 -0
  231. package/dist/03-patterns/list/list.css +1 -0
  232. package/dist/03-patterns/nav/nav.css +1 -0
  233. package/dist/03-patterns/nav/nav.js +322 -0
  234. package/dist/03-patterns/nav/toc.js +76 -0
  235. package/dist/03-patterns/overlay/overlay.css +1 -0
  236. package/dist/03-patterns/overlay/overlay.js +398 -0
  237. package/dist/03-patterns/pagination/pagination.css +1 -0
  238. package/dist/03-patterns/pagination/pagination.js +273 -0
  239. package/dist/03-patterns/reveal/reveal.css +1 -0
  240. package/dist/03-patterns/reveal/reveal.js +138 -0
  241. package/dist/03-patterns/states/states.css +1 -0
  242. package/dist/03-patterns/tabs/tabs.css +1 -0
  243. package/dist/03-patterns/tabs/tabs.js +242 -0
  244. package/dist/03-patterns/tooltip/tooltip.css +1 -0
  245. package/dist/03-patterns/tooltip/tooltip.js +213 -0
  246. package/dist/03-patterns/tree/tree.css +1 -0
  247. package/dist/03-patterns/tree/tree.js +383 -0
  248. package/dist/04-recipes/analysis-report/analysis-report.css +1 -0
  249. package/dist/04-recipes/detail-page/detail-page.css +1 -0
  250. package/dist/04-recipes/report/report.css +1 -0
  251. package/dist/04-recipes/table/table.css +1 -0
  252. package/dist/04-recipes/tierA-tokens.css +1 -0
  253. package/dist/09-assets/bar/bar.css +1 -0
  254. package/dist/09-assets/bar/bar.js +222 -0
  255. package/dist/09-assets/echarts-adapter/echarts-adapter.js +185 -0
  256. package/dist/09-assets/model-viewer/model-viewer.css +1 -0
  257. package/dist/09-assets/model-viewer/model-viewer.js +320 -0
  258. package/dist/09-assets/scientific-plot/scientific-plot.css +1 -0
  259. package/dist/09-assets/scientific-plot/scientific-plot.js +568 -0
  260. package/dist/09-assets/sparkline/sparkline.css +1 -0
  261. package/dist/09-assets/sparkline/sparkline.js +265 -0
  262. package/dist/COSTS.md +56 -0
  263. package/docs/AI-CONTRACT.md +197 -0
  264. package/docs/BACKLOG.md +127 -0
  265. package/docs/BENCHMARK.md +252 -0
  266. package/docs/GUIDANCE.md +154 -0
  267. package/docs/INVARIANT.md +372 -0
  268. package/docs/LAYER-BASELINE.md +158 -0
  269. package/docs/RELEASING.md +311 -0
  270. package/docs/RFC-THEME-SCOPE.md +141 -0
  271. package/docs/ROADMAP.md +182 -0
  272. package/index.html +82 -0
  273. package/package.json +107 -4
  274. package/types/index.d.ts +310 -0
@@ -0,0 +1,131 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <link rel="icon" href="data:,">
7
+ <title>导航 · 页头 / 目录 / 移动端抽屉</title>
8
+ <link rel="stylesheet" href="../../01-tokens/tokens.css">
9
+ <link rel="stylesheet" href="../../01-tokens/typography.css">
10
+ <link rel="stylesheet" href="../../01-tokens/page.css">
11
+ <link rel="stylesheet" href="../../02-primitives/button/button.css">
12
+ <link rel="stylesheet" href="nav.css">
13
+ <style>
14
+ .skip { position: absolute; top: 0; left: 0; z-index: var(--z-raised); /* 🔴*/
15
+ background: var(--accent); color: var(--text-on-accent); padding: var(--sp-2) var(--sp-4);
16
+ font-size: var(--fs-sm); text-decoration: none;
17
+ transform: translateY(-120%); }
18
+ .skip:focus { transform: translateY(0); }
19
+ .shell { display: grid; gap: var(--sp-6); max-width: 1040px; margin: 0 auto;
20
+ padding: var(--sp-6) var(--sp-5) var(--sp-8); grid-template-columns: 1fr; }
21
+ @media (min-width: 60rem) {.shell { grid-template-columns: 12rem minmax(0,1fr); }
22
+
23
+ }
24
+ main { max-width: var(--measure-prose); min-width: 0; }
25
+ p { max-width: var(--measure-prose); margin: 0 0 var(--sp-4); }
26
+ p.small { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.7; }
27
+ .aside { background: var(--warning-bg);
28
+ padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
29
+ font-size: var(--fs-sm); max-width: var(--measure-prose); margin: 0 0 var(--sp-5);
30
+ line-height: 1.65; }
31
+ .spacer { height: 55vh; }
32
+
33
+ /* 让目录高亮有滚动空间 */
34
+ </style>
35
+ </head>
36
+ <body class="page page">
37
+
38
+ <a class="skip" href="#main">跳到主内容</a>
39
+
40
+ <header class="nav" data-nav>
41
+ <div class="nav__inner">
42
+ <a class="nav__brand" href="#">技术考古 <span>/ AGC</span></a>
43
+ <button class="nav__toggle" id="nav-toggle" aria-expanded="false"
44
+ aria-controls="nav-list" aria-label="打开菜单"><i></i></button>
45
+ <ul class="nav__list" id="nav-list">
46
+ <li><a class="nav__link" href="#main" aria-current="page">制导计算机</a></li>
47
+ <li><a class="nav__link" href="#mem">存储器</a></li>
48
+ <li><a class="nav__link" href="#sched">调度</a></li>
49
+ <li><a class="nav__link" href="#sim">复现</a></li>
50
+ </ul>
51
+ </div>
52
+ <div class="nav__scrim" id="nav-scrim"></div>
53
+ </header>
54
+
55
+ <div class="shell">
56
+
57
+ <nav class="toc" aria-label="本页目录">
58
+ <p class="toc__title">本页</p>
59
+ <ul class="toc__list" id="toc-list">
60
+ <li><a class="toc__link" href="#top">本页</a></li>
61
+ <li><a class="toc__link" href="#mem">存储器构成</a></li>
62
+ <li><a class="toc__link" href="#sched">优先级与准入</a></li>
63
+ <li><a class="toc__link" href="#sim">把它跑起来</a></li>
64
+ </ul>
65
+ </nav>
66
+
67
+ <main id="main">
68
+ <h1 id="top">导航的三件事</h1>
69
+ <p class="lead">
70
+ 页头告诉你<b>在哪</b>,目录告诉你<b>读到哪</b>,抽屉在窄屏上替你省掉横向空间。
71
+ 三件事看起来简单,做错都会让用户"点了个寂寞"。
72
+ </p>
73
+
74
+ <div class="aside">
75
+ <b>请这样试:</b>① 把窗口拖窄到 768px 以下 → 出现汉堡按钮,点它开合抽屉,
76
+ 试 <code>Esc</code>、点遮罩、点链接后关闭;② 滚动正文,看左侧目录是否跟着高亮;
77
+ ③ 点页头的"存储器",看它是否标记为当前页。
78
+ </div>
79
+
80
+ <h2 id="mem" class="rule-top">存储器构成</h2>
81
+ <p>
82
+ AGC 的核心存储器是 2048 个 36 位字,总容量 73,728 位。指令与数据混在一起,
83
+ 地址按字计。真正让人吃惊的是每位宇航员分到的 4 KB 重写区——那不是共享内存,
84
+ 是<strong>每人一份</strong>。
85
+ </p>
86
+ <p>
87
+ 换句话说:三个人可以各自在自己的 4 KB 里堆程序,哪怕会覆盖掉别人写的东西。
88
+ 在那个年代这已经算是很大的宽容。
89
+ </p>
90
+ <div class="spacer"></div>
91
+
92
+ <h2 id="sched" class="rule-top">优先级与准入</h2>
93
+ <p>
94
+ AGC 的调度靠优先级抢占:更高优先级的任务可以打断低优先级的任务。
95
+ 这套机制加上准入控制,让关键任务(姿态、点火)不会被普通计算饿死。
96
+ </p>
97
+ <p>
98
+ 阿波罗 13 号在 33 万公里外反复报出的告警,就是这套机制在工作——
99
+ 它宁可一直报错,也不肯停机,因为停了机地面就失去了唯一的实时数据源。
100
+ </p>
101
+ <div class="spacer"></div>
102
+
103
+ <h2 id="sim" class="rule-top">把它跑起来</h2>
104
+ <p>
105
+ 工具链的成熟度足以支撑一次完整考古:从反汇编、到逐指令模拟、到和原厂手册对照。
106
+ 这条路走过一遍之后的结论是——手册里的描述与实现的实际行为在细节上有出入,
107
+ 而正是这些出入最能说明当时的工程取舍。
108
+ </p>
109
+ <p class="small">
110
+ 目录高亮<strong>统一用 <code>scroll</code> 监听 + <code>requestAnimationFrame</code> 节流</strong>,
111
+ <strong>不依赖 <code>IntersectionObserver</code></strong>。
112
+ 早期版本用的是它 + <code>rootMargin</code>,结果滚到两节之间时观察区里
113
+ 一个 section 都没有,高亮卡住不动 —— 现在改成纯计算,任何滚动位置都有答案。
114
+ </p>
115
+ </main>
116
+
117
+ </div>
118
+
119
+ <script src="toc.js"></script>
120
+ <script src="nav.js"></script>
121
+ <script>
122
+ /* ---------------------------------------------------------------- 目录高亮 */
123
+ Toc.init({ links: '#toc-list .toc__link', sections: 'main h2[id], main h1[id]' });
124
+
125
+ /* ------------------------------------------------ 抽屉
126
+ 行为全部在 nav.js 里(本页只负责写 data-nav)。
127
+ ⚠️ 这里曾经抄了 60 行开关逻辑,而抄出来的版本把 aria-hidden
128
+ 打在了抽屉的祖先上 ⇒ 抽屉本身对读屏消失。抽成组件后修掉了。 */
129
+ </script>
130
+ </body>
131
+ </html>
@@ -0,0 +1,314 @@
1
+ /* ============================================================================
2
+ frontend-lib / 03-patterns / nav / nav.css
3
+ 页头 + 长文目录 + 移动端抽屉
4
+
5
+ 依赖:01-tokens/tokens.css + 02-primitives/button/button.css
6
+ 版本:A ✅ / B ✅ / C ✅
7
+
8
+ 配套:toc.js(目录高亮,可降级)
9
+ 规范:抽屉的展开/收起见本文件顶部说明
10
+ ========================================================================= */
11
+
12
+ /* ============================================================================
13
+ 1. 跳到主内容
14
+ =========================================================================
15
+ 键盘用户第一个 Tab 就该能跳过整个导航。
16
+ 平时移出视口,聚焦时滑入 —— 用 transform 不用 display:none,
17
+ 否则它无法被 Tab 聚焦(display:none 会移出 tab 顺序)。 */
18
+ .skip {
19
+ position: absolute;
20
+ top: 0; inset-inline-start: 0;
21
+ z-index: var(--z-toast);
22
+ transform: translateY(-120%);
23
+ background: var(--accent);
24
+ /* 🔴 暗色下 --accent 变亮(#7aa9de),白字会看不清。 */
25
+ color: var(--text-on-accent);
26
+ padding: var(--sp-2) var(--sp-4);
27
+ font-size: var(--fs-sm);
28
+ text-decoration: none;
29
+ transition: transform var(--dur-fast) var(--ease-out);
30
+ }
31
+ .skip:focus { transform: translateY(0); }
32
+
33
+ /* ============================================================================
34
+ 2. 页头
35
+ ========================================================================= */
36
+ .nav {
37
+ position: sticky;
38
+ top: 0;
39
+ z-index: var(--z-header);
40
+ background: var(--paper);
41
+ border-bottom: 1px solid var(--border-decor);
42
+ }
43
+ .nav__inner {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: var(--sp-4);
47
+ max-width: 1040px;
48
+ margin: 0 auto;
49
+ padding: 0 var(--sp-5);
50
+ min-height: 56px; /* 触摸目标不小于 44px,这里是页头整体 */
51
+ }
52
+ .nav__brand {
53
+ /* 🔴 补内边距:移动端实测高度正好 24px,
54
+ 卡在 WCAG 2.5.8 的下限上,**没有余量** ——
55
+ 换字号/换字体就可能掉到 24px 以下。
56
+ 点击区用内边距撑开而不是固定 height:内容变了,触摸目标不会退化。 */
57
+ display: inline-flex;
58
+ align-items: center;
59
+ min-height: 44px; /* Apple/Google 建议值;WCAG 2.5.8 下限是 24 */
60
+ padding: var(--sp-2) 0;
61
+ font-size: var(--fs-sm);
62
+ font-weight: 500;
63
+ color: var(--text-primary);
64
+ text-decoration: none;
65
+ white-space: nowrap;
66
+ }
67
+ .nav__brand span { color: var(--text-tertiary); font-weight: 400; }
68
+
69
+ .nav__list {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: var(--sp-4);
73
+ list-style: none;
74
+ margin: 0 0 0 auto; /* 靠右 */
75
+ padding: 0;
76
+ }
77
+ .nav__link {
78
+ display: block;
79
+ padding: var(--sp-2) 0;
80
+ font-size: var(--fs-sm);
81
+ color: var(--text-secondary);
82
+ text-decoration: none;
83
+ border-bottom: 2px solid transparent; /* 预留位:选中时下方那条线不推内容 */
84
+ transition: color var(--dur-fast) var(--ease-out),
85
+ border-color var(--dur-fast) var(--ease-out);
86
+ }
87
+ @media (hover: hover) and (pointer: fine) {
88
+ .nav__link:hover { color: var(--text-primary); }
89
+ }
90
+ /* 🔴 当前页指示用 aria-current,不是自定义 class ——
91
+ 屏幕阅读器会播报"当前页面",自定义 class 它不知道。 */
92
+ .nav__link[aria-current="page"] {
93
+ color: var(--accent);
94
+ border-bottom-color: var(--accent);
95
+ font-weight: 500;
96
+ }
97
+ .nav__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
98
+
99
+ /* 汉堡:桌面隐藏 */
100
+ .nav__toggle {
101
+ display: none;
102
+ margin-inline-start: auto;
103
+ width: 44px; height: 44px; /* 触摸目标 44px,硬下限 */
104
+ align-items: center; justify-content: center;
105
+ background: none;
106
+ border: 1px solid var(--border-decor);
107
+ border-radius: var(--r-sm);
108
+ cursor: pointer;
109
+ color: var(--text-primary);
110
+ }
111
+ .nav__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
112
+
113
+ /* 三条线:中间那条用 transform 收成箭头,展开时变 X */
114
+ .nav__toggle i {
115
+ display: block;
116
+ width: 18px; height: 1.5px;
117
+ background: currentColor;
118
+ position: relative;
119
+ transition: transform var(--dur-base) var(--ease-out),
120
+ opacity var(--dur-fast) var(--ease-out);
121
+ }
122
+ .nav__toggle i::before,
123
+ .nav__toggle i::after {
124
+ content: "";
125
+ position: absolute;
126
+ inset-inline-start: 0;
127
+ width: 18px; height: 1.5px;
128
+ background: currentColor;
129
+ transition: transform var(--dur-base) var(--ease-out);
130
+ }
131
+ .nav__toggle i::before { top: -5.5px; }
132
+ .nav__toggle i::after { top: 5.5px; }
133
+
134
+ .nav__toggle[aria-expanded="true"] i { transform: rotate(45deg); }
135
+ .nav__toggle[aria-expanded="true"] i::before { transform: translateY(5.5px) rotate(-90deg); }
136
+ .nav__toggle[aria-expanded="true"] i::after { opacity: 0; }
137
+
138
+ /* ============================================================================
139
+ 3. 移动端:抽屉
140
+ =========================================================================
141
+ 🔴 按 08-状态切换规范:展开/收起**只动 transform**,不动 width/height/top ——
142
+ 那样会引起重排,页面会"抖一下"。
143
+
144
+ 🔴 抽屉打开时背景必须锁(inert),否则用户能 Tab 到抽屉外面去 ——
145
+ 视觉上抽屉是覆盖层,逻辑上却不是模态,两边不一致。 */
146
+ @media (max-width: 48rem) {
147
+ .nav__toggle { display: flex; }
148
+
149
+ .nav__list {
150
+ position: fixed;
151
+ top: 0; inset-inline-end: 0; bottom: 0;
152
+ z-index: var(--z-overlay);
153
+ width: min(280px, 82vw);
154
+ margin: 0;
155
+ padding: var(--sp-7) var(--sp-5) var(--sp-5);
156
+ flex-direction: column;
157
+ align-items: stretch;
158
+ gap: 0;
159
+ background: var(--surface);
160
+ border-inline-start: 1px solid var(--border-decor);
161
+ box-shadow: var(--shadow-2);
162
+
163
+ transform: translateX(100%); /* 收起态:在视口外 */
164
+ transition: transform var(--dur-base) var(--ease-out);
165
+ overflow-y: auto;
166
+ }
167
+ .nav__list[data-state="open"] { transform: translateX(0); }
168
+
169
+ .nav__link {
170
+ padding: var(--sp-3) 0;
171
+ border-bottom: 1px solid var(--border-decor);
172
+ /* 抽屉里用整行色块表示当前页,比 2px 下划线清楚(竖排时) */
173
+ border-bottom-width: 1px;
174
+ }
175
+ .nav__link[aria-current="page"] {
176
+ color: var(--accent);
177
+ font-weight: 500;
178
+ }
179
+
180
+ .nav__scrim {
181
+ position: fixed;
182
+ inset: 0;
183
+ z-index: var(--z-header); /* 比抽屉低一层 */
184
+ /* 🔴 原来写死 rgba(21,24,28,.4)(深色遮罩)。
185
+ 暗色模式下纸底本来就是深的 ⇒ 遮罩与底几乎同色 ⇒ **看不出"有遮罩"**。
186
+ 改用令牌,深浅两套各自成立。 */
187
+ background: var(--scrim);
188
+ opacity: 0;
189
+ pointer-events: none;
190
+ transition: opacity var(--dur-base) var(--ease-out);
191
+ }
192
+ .nav__scrim[data-state="open"] { opacity: 1; pointer-events: auto; }
193
+ }
194
+
195
+ /* ============================================================================
196
+ 4. 长文目录
197
+ ========================================================================= */
198
+ .toc {
199
+ /* 容器本身也要有定义 —— 否则 HTML 里的 class="toc" 是个悬空引用。
200
+ refs.py 会抓这种"引用了但没定义"的类。 */
201
+ min-width: 0;
202
+ }
203
+
204
+ /* 🔴 sticky 必须**在库里**而不是 demo 里。
205
+ 修正:原来这条只写在 demo 的内联 <style> 里,
206
+ 于是任何引了 nav.css 的页面都**没有 sticky** ——
207
+ 目录会随正文滚出视口,"跟着走"这个最基本的效果没有。
208
+ **布局规则写在 demo 里 = 分层崩了。**
209
+
210
+ 偏移量要大于页头高度,否则 sticky 会停在页头下面被遮住。
211
+ 窄屏时目录在正文上方,不需要 sticky。 */
212
+ @media (min-width: 60rem) {
213
+ .toc {
214
+ position: sticky;
215
+ top: 76px; /* 页头 56px + 20px 留白 */
216
+ align-self: start; /* 🔴 grid 子项默认 stretch,会让 sticky 无处可动 */
217
+ max-height: calc(100vh - 96px);
218
+ overflow-y: auto; /* 目录比视口高时可滚 */
219
+ }
220
+ }
221
+ .toc__title {
222
+ font-size: var(--fs-xs);
223
+ color: var(--text-tertiary);
224
+ text-transform: uppercase;
225
+ letter-spacing: 0.1em;
226
+ margin: 0 0 var(--sp-3);
227
+ font-weight: 500;
228
+ }
229
+ .toc__list { list-style: none; margin: 0; padding: 0; }
230
+ /* 🔴 为什么这里保留竖条(0.8.4 · 全库竖条政策)
231
+ 它不是装饰竖条,是**当前项指示器**:目录里"你在这一节"由它标记,
232
+ 与当前项的文字加重是**两条独立线索** ——
233
+ 去掉它,纯色弱 / 低对比场景下当前项就只剩字重变化可辨。
234
+ ⚠️ 未选中时是灰调分隔色(--border-decor)、选中时才变强调色(--accent),
235
+ 所以它平时就是一条安静的目录导轨,只有当前项会被点亮。 */
236
+ .toc__link {
237
+ display: block;
238
+ padding: var(--sp-1) 0 var(--sp-1) var(--sp-3);
239
+ color: var(--text-tertiary);
240
+ text-decoration: none;
241
+ font-size: var(--fs-xs);
242
+ border-inline-start: 2px solid var(--border-decor);
243
+ white-space: nowrap; /* 目录项换行就乱了 */
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ transition: color var(--dur-fast) var(--ease-out),
247
+ border-color var(--dur-fast) var(--ease-out);
248
+ }
249
+ @media (hover: hover) and (pointer: fine) {
250
+ .toc__link:hover { color: var(--text-primary); }
251
+ }
252
+ .toc__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
253
+ /* 🔴 当前节用 aria-current="true"(不是 "location")——
254
+ "true" 表示"在当前范围内当前位置",目录高亮用它是通行做法。 */
255
+ .toc__link[aria-current="true"] {
256
+ color: var(--accent);
257
+ /* 🔴 必须是 border-inline-start-color(逻辑),与 .toc__link 的
258
+ border-inline-start 同侧。写物理 border-left-color 的话 RTL 下会着错边。 */
259
+ border-inline-start-color: var(--accent);
260
+ font-weight: 500;
261
+ }
262
+
263
+ /* ============================================================================
264
+ reduced-motion
265
+ =========================================================================
266
+ 抽屉的位移动画对前庭功能障碍患者是有刺激的 ⇒ 关掉,
267
+ 但保留遮罩的 opacity 过渡(无刺激,且能交代"挡住了")。
268
+ ========================================================================= */
269
+ @media (prefers-reduced-motion: reduce) {
270
+ .nav__list, .nav__toggle i, .nav__toggle i::before, .nav__scrim {
271
+ transition: opacity var(--dur-fast) linear;
272
+ transform: none;
273
+ }
274
+ .nav__toggle[aria-expanded="true"] i { transform: none; }
275
+ .nav__toggle[aria-expanded="true"] i::before { transform: none; }
276
+ }
277
+
278
+ /* 🔴 这两条**必须**带断点。抽屉的"收起态"靠 translateX(100%) 移出视口,
279
+ 动画被关掉后得有东西撑着它;但曾经写在**无断点**的 reduced-motion 段里
280
+ ⇒ 开启「减少动态效果」的桌面用户,顶部导航整体飞出屏幕右侧
281
+ (实测 1440 视口 scrollWidth 1440 → 1512 = 列表自身宽度),菜单直接消失。
282
+ 默认环境下截图看不到它,只有 emulateMedia({reducedMotion:'reduce'}) 才暴露。
283
+ ⭐ 教训:「关掉动画」不能顺手把布局也关掉。 */
284
+ @media (prefers-reduced-motion: reduce) and (max-width: 48rem) {
285
+ .nav__list { transform: translateX(100%); } /* 收起态:仍在视口外 */
286
+ .nav__list[data-state="open"] { transform: translateX(0); }
287
+ }
288
+
289
+ /* ============================================================================
290
+ 反模式
291
+ =========================================================================
292
+ 1. 抽屉展开时动 width / left / top
293
+ ⇒ 引起重排,页面抖一下。只该动 transform。
294
+
295
+ 2. 抽屉打开后背景仍可 Tab / 可点
296
+ 视觉上是覆盖层,逻辑上不是模态,两边不一致。
297
+ 打开时给背景加 inert。
298
+
299
+ 3. 汉堡按钮小于 44px
300
+ 触摸目标是硬下限(WCAG 2.5.8 要 24px,但 44 是实践标准)。
301
+
302
+ 4. 当前页指示用自定义 class 而不是 aria-current
303
+ 屏幕阅读器不知道,用户失去"我在哪"。
304
+
305
+ 5. 目录项允许换行
306
+ 换行会让行高跳变,目录看着散。截断(ellipsis)。
307
+
308
+ 6. 目录高亮在不支持 IntersectionObserver 时就整个不做
309
+ 目录会变成一堆"点得动但看不出当前位置"的死链接。
310
+ scroll 监听,体验降级但功能不消失。
311
+
312
+ 7. 页头 sticky 但没给背景色
313
+ 内容会从页头下面透出来,看着像重影。
314
+ ========================================================================= */