agentcss 0.16.1 → 0.24.1
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.
- package/01-tokens/focus-ring-demo.html +1 -1
- package/01-tokens/page.css +32 -0
- package/01-tokens/responsive-demo.html +1 -1
- package/01-tokens/scrollbar-demo.html +1 -1
- package/02-primitives/badge/demo.html +1 -1
- package/02-primitives/button/demo.html +1 -1
- package/02-primitives/card/demo.html +1 -1
- package/02-primitives/choice/choice.css +31 -2
- package/02-primitives/choice/demo.html +1 -1
- package/02-primitives/combobox/demo.html +1 -1
- package/02-primitives/date-range/demo.html +1 -1
- package/02-primitives/delta/demo.html +1 -1
- package/02-primitives/input/demo.html +1 -1
- package/02-primitives/input/input.css +14 -0
- package/02-primitives/metric/demo.html +1 -1
- package/02-primitives/popover/demo.html +1 -1
- package/02-primitives/progress/demo.html +1 -1
- package/02-primitives/progress/progress.css +56 -0
- package/02-primitives/select/demo.html +1 -1
- package/02-primitives/separator/demo.html +1 -1
- package/02-primitives/skeleton/demo.html +1 -1
- package/02-primitives/skeleton/skeleton.css +18 -0
- package/02-primitives/switch/demo.html +1 -1
- package/02-primitives/switch/switch.css +61 -2
- package/02-primitives/timeline/README.md +70 -0
- package/02-primitives/timeline/demo.html +161 -0
- package/02-primitives/timeline/timeline.css +152 -0
- package/02-primitives/upload/README.md +142 -0
- package/02-primitives/upload/demo.html +318 -0
- package/02-primitives/upload/upload.css +490 -0
- package/02-primitives/upload/upload.js +676 -0
- package/03-patterns/accordion/demo.html +1 -1
- package/03-patterns/content/demo.html +1 -1
- package/03-patterns/drawer/demo.html +1 -1
- package/03-patterns/drawer/drawer.js +30 -5
- package/03-patterns/dropdown/demo.html +1 -1
- package/03-patterns/form-validation/demo.html +1 -1
- package/03-patterns/list/demo.html +1 -1
- package/03-patterns/nav/demo.html +1 -1
- package/03-patterns/overlay/demo.html +1 -1
- package/03-patterns/pagination/demo.html +1 -1
- package/03-patterns/states/demo.html +1 -1
- package/03-patterns/tabs/demo.html +1 -1
- package/03-patterns/tooltip/demo.html +1 -1
- package/03-patterns/tree/demo.html +1 -1
- package/04-recipes/app-shell/README.md +272 -0
- package/04-recipes/app-shell/app-shell.css +588 -0
- package/04-recipes/app-shell/demo.html +326 -0
- package/04-recipes/app-shell/shell-nav.js +288 -0
- package/04-recipes/table/table.css +22 -0
- package/09-assets/bar/demo.html +1 -1
- package/09-assets/echarts-adapter/demo.html +1 -1
- package/09-assets/model-viewer/demo.html +1 -1
- package/09-assets/sparkline/demo.html +1 -1
- package/AGENTS.md +8 -0
- package/API.md +4 -0
- package/CHANGELOG.md +795 -0
- package/CONTRIBUTING.md +22 -1
- package/README.md +17 -5
- package/README.zh-CN.md +16 -6
- package/START-HERE.md +12 -7
- package/ai/START-HERE.md +37 -3
- package/ai/behaviors.json +32 -0
- package/ai/cli.js +183 -25
- package/ai/components.json +185 -7
- package/ai/components.meta.json +13 -0
- package/ai/pitfalls-writing.json +119 -0
- package/ai/pitfalls.json +193 -0
- package/dist/01-tokens/page.css +1 -1
- package/dist/02-primitives/choice/choice.css +1 -1
- package/dist/02-primitives/input/input.css +1 -1
- package/dist/02-primitives/progress/progress.css +1 -1
- package/dist/02-primitives/skeleton/skeleton.css +1 -1
- package/dist/02-primitives/switch/switch.css +1 -1
- package/dist/02-primitives/timeline/timeline.css +1 -0
- package/dist/02-primitives/upload/upload.css +1 -0
- package/dist/02-primitives/upload/upload.js +515 -0
- package/dist/03-patterns/drawer/drawer.js +14 -4
- package/dist/04-recipes/app-shell/app-shell.css +1 -0
- package/dist/04-recipes/app-shell/shell-nav.js +173 -0
- package/dist/04-recipes/table/table.css +1 -1
- package/dist/COSTS.md +12 -10
- package/docs/ACCESSIBILITY.md +20 -7
- package/docs/AI-CONTRACT.md +2 -0
- package/docs/BUDGET.md +179 -0
- package/docs/CONVENTIONS.md +3 -0
- package/docs/STABILITY.md +126 -0
- package/esm/index.mjs +2 -0
- package/esm/upload.mjs +7 -0
- package/index.html +5 -2
- package/llms-full.txt +153 -0
- package/llms.txt +55 -0
- package/package.json +4 -1
package/ai/components.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
3
|
"generatedBy": "05-audit/gen-ai-contract.py",
|
|
4
|
-
"libraryVersion": "0.
|
|
4
|
+
"libraryVersion": "0.24.1",
|
|
5
5
|
"$comment": "机器可读的组件契约。slots = BEM 元素名(在本库里元素名就是插槽名),states.enum = 组件会在 DOM 上写出的 data-* 取值,states.legacyClass = 仍未收敛到 data 属性的历史状态类(INVARIANT I-8 未达标)。",
|
|
6
6
|
"maturityCriteria": {
|
|
7
7
|
"alpha": "缺 demo.html 或缺 05-audit 下的专属门禁 ⇒ 还没被机器验证过,不要用",
|
|
8
8
|
"beta": "有 demo + 专属门禁,但**下面至少有一条没过**:① 状态仍用 .is-* class 表达(违反 INVARIANT I-8);② 该收编到微行为核的行为还是**手写副本**(manual)或**根本没做**(gap) ⇒ 改一处不会全库跟着变(I-14 的病)",
|
|
9
9
|
"stable": "以上四条全过:有 demo + 专属门禁 + 状态全在 data-* 属性上 + 行为零欠账",
|
|
10
10
|
"$note": "成熟度是【计算出来的】,不是拍的。手写把某个组件改成 stable 而它还有 manual / gap ⇒ 门禁会红。",
|
|
11
|
-
"$whyFourth": "🔴 为什么第四条判据不能省:用前三条时多数组件会**全是 stable** ⇒ ladder 没有任何鉴别力(对标 Primer 六档阶梯,每档都有硬判据)。补上「行为欠账」这一条后:**stable
|
|
12
|
-
"$strictImpact": "✅ strict 档位放行全部
|
|
11
|
+
"$whyFourth": "🔴 为什么第四条判据不能省:用前三条时多数组件会**全是 stable** ⇒ ladder 没有任何鉴别力(对标 Primer 六档阶梯,每档都有硬判据)。补上「行为欠账」这一条后:**stable 40 / beta 0**(本行由生成器算出,不要手改)。全库达标时 ladder 靠**正向控制**证明还有鉴别力(maturity-gate ③:塞一条合成债务必须降 beta),不是靠\"总得留几个 beta\"。",
|
|
12
|
+
"$strictImpact": "✅ strict 档位放行全部 40 个组件 —— 没有任何组件带着未收编的手写行为或未做的行为(本行由生成器算出,不要手改)"
|
|
13
13
|
},
|
|
14
14
|
"summary": {
|
|
15
|
-
"total":
|
|
15
|
+
"total": 40,
|
|
16
16
|
"byMaturity": {
|
|
17
|
-
"stable":
|
|
17
|
+
"stable": 40
|
|
18
18
|
},
|
|
19
19
|
"byTier": {
|
|
20
|
-
"primitive":
|
|
20
|
+
"primitive": 17,
|
|
21
21
|
"pattern": 14,
|
|
22
|
-
"recipe":
|
|
22
|
+
"recipe": 5,
|
|
23
23
|
"asset": 4
|
|
24
24
|
}
|
|
25
25
|
},
|
|
@@ -1819,6 +1819,119 @@
|
|
|
1819
1819
|
"globalAlso": [],
|
|
1820
1820
|
"behaviorRef": "API.md#switch"
|
|
1821
1821
|
},
|
|
1822
|
+
{
|
|
1823
|
+
"id": "timeline",
|
|
1824
|
+
"tier": "primitive",
|
|
1825
|
+
"purpose": "时间轴:按时间排的事件序列(公告 / 大事记 / 版本记录)。顺序即信息,用 ol;状态交给 badge,颜色在这里会失效",
|
|
1826
|
+
"rootClass": "timeline",
|
|
1827
|
+
"maturity": "stable",
|
|
1828
|
+
"maturityReasons": {
|
|
1829
|
+
"hasDemo": true,
|
|
1830
|
+
"hasDedicatedGate": true,
|
|
1831
|
+
"statesOnDomAttributes": true,
|
|
1832
|
+
"behaviorDebt": []
|
|
1833
|
+
},
|
|
1834
|
+
"gates": [
|
|
1835
|
+
"timeline-check.js"
|
|
1836
|
+
],
|
|
1837
|
+
"files": {
|
|
1838
|
+
"css": "02-primitives/timeline/timeline.css",
|
|
1839
|
+
"js": null,
|
|
1840
|
+
"jsAlso": [],
|
|
1841
|
+
"demo": "02-primitives/timeline/demo.html"
|
|
1842
|
+
},
|
|
1843
|
+
"slots": [
|
|
1844
|
+
"timeline__body",
|
|
1845
|
+
"timeline__item",
|
|
1846
|
+
"timeline__item--latest",
|
|
1847
|
+
"timeline__time",
|
|
1848
|
+
"timeline__title"
|
|
1849
|
+
],
|
|
1850
|
+
"variants": [
|
|
1851
|
+
"timeline--compact"
|
|
1852
|
+
],
|
|
1853
|
+
"states": {
|
|
1854
|
+
"enum": {},
|
|
1855
|
+
"boolean": [],
|
|
1856
|
+
"legacyClass": []
|
|
1857
|
+
},
|
|
1858
|
+
"aria": {
|
|
1859
|
+
"roles": [],
|
|
1860
|
+
"attrs": []
|
|
1861
|
+
},
|
|
1862
|
+
"usesOtherNamespaces": [],
|
|
1863
|
+
"global": null,
|
|
1864
|
+
"globalAlso": [],
|
|
1865
|
+
"behaviorRef": "API.md#timeline"
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
"id": "upload",
|
|
1869
|
+
"tier": "primitive",
|
|
1870
|
+
"purpose": "文件上传:零 JS 的原生形态 + 拖放/多文件/校验的增强形态",
|
|
1871
|
+
"rootClass": "upload",
|
|
1872
|
+
"maturity": "stable",
|
|
1873
|
+
"maturityReasons": {
|
|
1874
|
+
"hasDemo": true,
|
|
1875
|
+
"hasDedicatedGate": true,
|
|
1876
|
+
"statesOnDomAttributes": true,
|
|
1877
|
+
"behaviorDebt": []
|
|
1878
|
+
},
|
|
1879
|
+
"gates": [
|
|
1880
|
+
"upload-check.js"
|
|
1881
|
+
],
|
|
1882
|
+
"files": {
|
|
1883
|
+
"css": "02-primitives/upload/upload.css",
|
|
1884
|
+
"js": "02-primitives/upload/upload.js",
|
|
1885
|
+
"jsAlso": [],
|
|
1886
|
+
"demo": "02-primitives/upload/demo.html"
|
|
1887
|
+
},
|
|
1888
|
+
"slots": [
|
|
1889
|
+
"upload__browse",
|
|
1890
|
+
"upload__dropzone",
|
|
1891
|
+
"upload__hint",
|
|
1892
|
+
"upload__icon",
|
|
1893
|
+
"upload__input",
|
|
1894
|
+
"upload__item",
|
|
1895
|
+
"upload__list",
|
|
1896
|
+
"upload__mark",
|
|
1897
|
+
"upload__meta",
|
|
1898
|
+
"upload__name",
|
|
1899
|
+
"upload__progress",
|
|
1900
|
+
"upload__remove",
|
|
1901
|
+
"upload__status",
|
|
1902
|
+
"upload__title"
|
|
1903
|
+
],
|
|
1904
|
+
"variants": [
|
|
1905
|
+
"upload--compact",
|
|
1906
|
+
"upload--drop"
|
|
1907
|
+
],
|
|
1908
|
+
"states": {
|
|
1909
|
+
"enum": {
|
|
1910
|
+
"state": [
|
|
1911
|
+
"done",
|
|
1912
|
+
"dragover",
|
|
1913
|
+
"error",
|
|
1914
|
+
"pending"
|
|
1915
|
+
]
|
|
1916
|
+
},
|
|
1917
|
+
"boolean": [],
|
|
1918
|
+
"legacyClass": []
|
|
1919
|
+
},
|
|
1920
|
+
"aria": {
|
|
1921
|
+
"roles": [
|
|
1922
|
+
"status"
|
|
1923
|
+
],
|
|
1924
|
+
"attrs": [
|
|
1925
|
+
"describedby",
|
|
1926
|
+
"label",
|
|
1927
|
+
"live"
|
|
1928
|
+
]
|
|
1929
|
+
},
|
|
1930
|
+
"usesOtherNamespaces": [],
|
|
1931
|
+
"global": "Upload",
|
|
1932
|
+
"globalAlso": [],
|
|
1933
|
+
"behaviorRef": "API.md#upload"
|
|
1934
|
+
},
|
|
1822
1935
|
{
|
|
1823
1936
|
"id": "analysis-report",
|
|
1824
1937
|
"tier": "recipe",
|
|
@@ -1874,6 +1987,71 @@
|
|
|
1874
1987
|
"globalAlso": [],
|
|
1875
1988
|
"behaviorRef": "API.md#analysis-report"
|
|
1876
1989
|
},
|
|
1990
|
+
{
|
|
1991
|
+
"id": "app-shell",
|
|
1992
|
+
"tier": "recipe",
|
|
1993
|
+
"purpose": "应用外壳:侧栏 + 顶栏 + 主区三段式;sticky 侧栏自滚、min-width 防撑破、窄屏收走侧栏",
|
|
1994
|
+
"rootClass": "shell",
|
|
1995
|
+
"maturity": "stable",
|
|
1996
|
+
"maturityReasons": {
|
|
1997
|
+
"hasDemo": true,
|
|
1998
|
+
"hasDedicatedGate": true,
|
|
1999
|
+
"statesOnDomAttributes": true,
|
|
2000
|
+
"behaviorDebt": []
|
|
2001
|
+
},
|
|
2002
|
+
"gates": [
|
|
2003
|
+
"app-shell-check.js"
|
|
2004
|
+
],
|
|
2005
|
+
"files": {
|
|
2006
|
+
"css": "04-recipes/app-shell/app-shell.css",
|
|
2007
|
+
"js": "04-recipes/app-shell/shell-nav.js",
|
|
2008
|
+
"jsAlso": [],
|
|
2009
|
+
"demo": "04-recipes/app-shell/demo.html"
|
|
2010
|
+
},
|
|
2011
|
+
"slots": [
|
|
2012
|
+
"shell__brand",
|
|
2013
|
+
"shell__brand-mark",
|
|
2014
|
+
"shell__brand-text",
|
|
2015
|
+
"shell__content",
|
|
2016
|
+
"shell__link",
|
|
2017
|
+
"shell__link-label",
|
|
2018
|
+
"shell__main",
|
|
2019
|
+
"shell__menu",
|
|
2020
|
+
"shell__scroll",
|
|
2021
|
+
"shell__side",
|
|
2022
|
+
"shell__side--drawer",
|
|
2023
|
+
"shell__side-group",
|
|
2024
|
+
"shell__side-label",
|
|
2025
|
+
"shell__title",
|
|
2026
|
+
"shell__topbar",
|
|
2027
|
+
"shell__topbar-end"
|
|
2028
|
+
],
|
|
2029
|
+
"variants": [
|
|
2030
|
+
"shell--flat",
|
|
2031
|
+
"shell--rail",
|
|
2032
|
+
"shell--scroll-main"
|
|
2033
|
+
],
|
|
2034
|
+
"states": {
|
|
2035
|
+
"enum": {},
|
|
2036
|
+
"boolean": [],
|
|
2037
|
+
"legacyClass": []
|
|
2038
|
+
},
|
|
2039
|
+
"aria": {
|
|
2040
|
+
"roles": [
|
|
2041
|
+
"region"
|
|
2042
|
+
],
|
|
2043
|
+
"attrs": [
|
|
2044
|
+
"current",
|
|
2045
|
+
"haspopup",
|
|
2046
|
+
"hidden",
|
|
2047
|
+
"label"
|
|
2048
|
+
]
|
|
2049
|
+
},
|
|
2050
|
+
"usesOtherNamespaces": [],
|
|
2051
|
+
"global": "ShellNav",
|
|
2052
|
+
"globalAlso": [],
|
|
2053
|
+
"behaviorRef": "API.md#app-shell"
|
|
2054
|
+
},
|
|
1877
2055
|
{
|
|
1878
2056
|
"id": "detail-page",
|
|
1879
2057
|
"tier": "recipe",
|
package/ai/components.meta.json
CHANGED
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"tier": "recipe",
|
|
26
26
|
"purpose": "组合型研究报告页面:正文与辅助栏并排,窄屏自然退回单栏"
|
|
27
27
|
},
|
|
28
|
+
"app-shell": {
|
|
29
|
+
"rootClass": "shell",
|
|
30
|
+
"tier": "recipe",
|
|
31
|
+
"purpose": "应用外壳:侧栏 + 顶栏 + 主区三段式;sticky 侧栏自滚、min-width 防撑破、窄屏收走侧栏"
|
|
32
|
+
},
|
|
28
33
|
"badge": {
|
|
29
34
|
"rootClass": "badge",
|
|
30
35
|
"purpose": "状态标签:计数、分类、结果标记"
|
|
@@ -125,6 +130,10 @@
|
|
|
125
130
|
"rootClass": "select",
|
|
126
131
|
"purpose": "自定义下拉选择(非原生)"
|
|
127
132
|
},
|
|
133
|
+
"timeline": {
|
|
134
|
+
"rootClass": "timeline",
|
|
135
|
+
"purpose": "时间轴:按时间排的事件序列(公告 / 大事记 / 版本记录)。顺序即信息,用 ol;状态交给 badge,颜色在这里会失效"
|
|
136
|
+
},
|
|
128
137
|
"separator": {
|
|
129
138
|
"rootClass": "separator",
|
|
130
139
|
"purpose": "分隔线,可带中间文字"
|
|
@@ -146,6 +155,10 @@
|
|
|
146
155
|
"rootClass": "switch",
|
|
147
156
|
"purpose": "开关切换"
|
|
148
157
|
},
|
|
158
|
+
"upload": {
|
|
159
|
+
"rootClass": "upload",
|
|
160
|
+
"purpose": "文件上传:零 JS 的原生形态 + 拖放/多文件/校验的增强形态"
|
|
161
|
+
},
|
|
149
162
|
"table": {
|
|
150
163
|
"rootClass": "table",
|
|
151
164
|
"tier": "recipe",
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"generatedBy": "hand-curated, then frozen (this file is a fact, not a build product)",
|
|
4
|
+
"source": "curated from the same internal lessons log as pitfalls.json (41 entries). Only the failures that happen while producing prose, demos and published pages — not inside a component, and not about running the gates. Sanitized: project names, dates, customer context and vendor-specific details removed.",
|
|
5
|
+
"note": "Same schema as pitfalls.json. `scope` is always \"writing\" and `components` is always empty here: these failures have no component to join to. `agentcss ai pitfalls --scope=writing` reads this file; plain `ai pitfalls` merges both files and reports which ones it loaded.",
|
|
6
|
+
"scopes": {
|
|
7
|
+
"writing": "写出来的东西:代码可能全绿、组件也可能都对,但读者读到的是错的,或者读不下去。"
|
|
8
|
+
},
|
|
9
|
+
"pitfalls": [
|
|
10
|
+
{
|
|
11
|
+
"id": "demo-must-prove-the-claim",
|
|
12
|
+
"title": "演示要证明的是正文那句话,不是「能动就行」",
|
|
13
|
+
"scope": "writing",
|
|
14
|
+
"components": [],
|
|
15
|
+
"symptom": "交互演示跑得很顺,但它演示出来的现象与正文结论相反(该被牺牲的项最后反而被保留)。画面本身没 bug,它证明的东西错了。",
|
|
16
|
+
"fix": "写完演示先自问一句「它演出来的现象,是不是正文那句话」;把「谁被保留、谁被牺牲」逐项对照结论核一遍,顺序、标注、结果文案三处一起看。",
|
|
17
|
+
"tags": ["demo", "narrative"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "identifiers-from-source",
|
|
21
|
+
"title": "编号、常量、行号、API 名一律回源检索,检索不到就降级表述",
|
|
22
|
+
"scope": "writing",
|
|
23
|
+
"components": [],
|
|
24
|
+
"symptom": "凭印象写出的编号在仓库里根本不存在;行号偏 1~2 行,代码块起止对不上,读者按它查不到任何东西。",
|
|
25
|
+
"fix": "正文里出现的每个编号、常量、行号、API 名先 grep 一遍:命中就附 file:line,未命中就明写「未能核实,本文不作断言」。行号宁可给范围(374-378),也不要给不确定的单点。",
|
|
26
|
+
"tags": ["evidence", "citation"]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "prerender-when-host-strips-scripts",
|
|
30
|
+
"title": "目标平台会剥 <script>/<style> 时,架构一开始就得是构建期预渲染",
|
|
31
|
+
"scope": "writing",
|
|
32
|
+
"components": [],
|
|
33
|
+
"symptom": "客户端渲染做出来的页面在浏览器里完全正常,粘进公众号或笔记软件后是一片空白 —— 它们会剥掉脚本与样式块,并清洗 class。等于渲染层全废。",
|
|
34
|
+
"fix": "目标含微信/知识库时:构建期把数据渲染成最终 HTML;样式写成元素上的 style=\"…\"(唯一能穿过清洗的形式);代码高亮也在构建期做完;展开/收起用原生 <details>。不要交付完再改架构。",
|
|
35
|
+
"tags": ["publishing", "prerender"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "two-output-formats",
|
|
39
|
+
"title": "「能进任何知识库」要两种载体:自包含 HTML + Markdown",
|
|
40
|
+
"scope": "writing",
|
|
41
|
+
"components": [],
|
|
42
|
+
"symptom": "只给 HTML,对方要 Markdown 沉淀;于是两份各自维护,正文很快走样,改一处忘一处。",
|
|
43
|
+
"fix": "内容只维护一份数据源,构建脚本同时产出 .html(自包含、内联样式)与 .md(纯文本,图注指向 HTML)。新增内容只改数据源,两个产物自动同步。",
|
|
44
|
+
"tags": ["publishing", "output"]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "source-graded-by-citation",
|
|
48
|
+
"title": "来源按「有没有引注」分级,自标缺引注的要明写不作定论",
|
|
49
|
+
"scope": "writing",
|
|
50
|
+
"components": [],
|
|
51
|
+
"symptom": "把「二次综述、且该综述自己标了 [citation needed]」的句子当定论引用,后面整段论证都挂在它上面。",
|
|
52
|
+
"fix": "分三级:一手原件 > 有引注的二次综述 > 自标缺引注的二次综述。第三类照常使用,但必须写明「证据等级偏低,不构成定论,后文论证不依赖它」。",
|
|
53
|
+
"tags": ["evidence", "sources"]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "unverified-source-not-authoritative",
|
|
57
|
+
"title": "核不实的来源就降级,别挂权威名头",
|
|
58
|
+
"scope": "writing",
|
|
59
|
+
"components": [],
|
|
60
|
+
"symptom": "想让一句话更有分量,就给某机构署名;等真去核,原始报告是扫描件、提不出文本,于是含糊写成「据相关机构」。",
|
|
61
|
+
"fix": "老实写「出自公开综述,非原件;尝试核过该档案但无法提取文本」。把核证失败的过程写出来,比含糊挂名更可信,也才配得上「证据等级」这套说法。",
|
|
62
|
+
"tags": ["evidence", "sources"]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "md-table-cell-no-pipe",
|
|
66
|
+
"title": "Markdown 表格单元格里不能出现竖线",
|
|
67
|
+
"scope": "writing",
|
|
68
|
+
"components": [],
|
|
69
|
+
"symptom": "用 `a | b` 表达「拆成两段」,渲染时这一行被撑出额外列,整张表崩掉。HTML 侧完全看不出问题。",
|
|
70
|
+
"fix": "单元格内一律用「‖」或「/」代替竖线;写入前先扫一遍内容里的 `|`。",
|
|
71
|
+
"tags": ["markdown", "table"]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "declare-what-you-did-not-decode",
|
|
75
|
+
"title": "记法不统一时,写「本册不解码」比硬猜值钱",
|
|
76
|
+
"scope": "writing",
|
|
77
|
+
"components": [],
|
|
78
|
+
"symptom": "两套公开整理稿对同一字段的记法互相冲突,硬挑一套去逐条解码;猜错一条,整篇「无幻觉」的立身之本就没了。",
|
|
79
|
+
"fix": "把能核对的部分给足(字段宽度、已确认的编码),然后明写一句「公开记法不统一,本册不逐条解码」。主动划清边界是加分项,审稿人看得出来。",
|
|
80
|
+
"tags": ["evidence", "scope"]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": "majority-of-independent-evidence",
|
|
84
|
+
"title": "注释与数据冲突时,数独立证据的票,并注明残留",
|
|
85
|
+
"scope": "writing",
|
|
86
|
+
"components": [],
|
|
87
|
+
"symptom": "老注释写 A,三处数据都指向 B,随手挑一个写进正文;或者只报一句「这里存在矛盾」就交稿。",
|
|
88
|
+
"fix": "把每条独立证据列出来数一遍,多数派胜出,然后照实记一句「该注释应是改数后忘记同步的残留」。不替老代码圆场,也不止步于「有矛盾」。",
|
|
89
|
+
"tags": ["evidence", "conflict"]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "plain-language-pass",
|
|
93
|
+
"title": "定稿前做一遍「说人话」校对",
|
|
94
|
+
"scope": "writing",
|
|
95
|
+
"components": [],
|
|
96
|
+
"symptom": "括号套括号的长句、成串没解释的术语、形容词比证据多;读者要读两遍才知道在说什么,第二遍就不读了。",
|
|
97
|
+
"fix": "三个动作:把括号堆砌拆成顺叙;一句话只承载一个意象;把「少得不可思议」这类带劲的说法换成平实表达。说服力来自证据,不来自形容词。",
|
|
98
|
+
"tags": ["prose", "editing"]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "reproducible-over-descriptive",
|
|
102
|
+
"title": "从「有什么」升级到「怎么算」:控制流 + 可手算算例 + 版本固定",
|
|
103
|
+
"scope": "writing",
|
|
104
|
+
"components": [],
|
|
105
|
+
"symptom": "文章能回答「这里有什么」,读者仍不知道它到底怎么算,也没法自己复现一遍;引证写着「某版本」,具体是哪个提交说不清。",
|
|
106
|
+
"fix": "三个动作:关键路径画成 输入→状态变化→输出 的阶梯;给一组小数字让读者拿笔跟算,并用独立公式验算同解;引证带 commit hash,外部资料列成编号文献并注明各自用于何处。",
|
|
107
|
+
"tags": ["prose", "reproducibility"]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "counterfactual-worked-example",
|
|
111
|
+
"title": "讲「为什么这样选」,就把被否掉的方案算死",
|
|
112
|
+
"scope": "writing",
|
|
113
|
+
"components": [],
|
|
114
|
+
"symptom": "只写结论「因为位数不够,所以加了扩展位」,读者只能选择信或不信。",
|
|
115
|
+
"fix": "补一笔反事实账:换成另一种分配会算出什么不可行的结果(差多少、缺多少)。成本只有一个算例,读者会自己得出结论。",
|
|
116
|
+
"tags": ["prose", "argument"]
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
package/ai/pitfalls.json
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"generatedBy": "hand-curated, then frozen (this file is a fact, not a build product)",
|
|
4
|
+
"source": "curated from an internal frontend lessons log (41 entries). Sanitized: project names, dates, customer context and vendor-specific details removed; only the reusable failure mode is kept.",
|
|
5
|
+
"note": "Each entry is a failure that actually shipped at least once. `components` is the join key used by `agentcss ai components --json`; `scope` separates component-level defects from page-level and process-level ones.",
|
|
6
|
+
"scopes": {
|
|
7
|
+
"component": "一个组件自身的实现缺陷:换页面也照样复现。",
|
|
8
|
+
"layout": "页面/版式层面:单个组件都对,拼起来才出问题。",
|
|
9
|
+
"process": "交付过程:代码可能全绿,但结论是错的。"
|
|
10
|
+
},
|
|
11
|
+
"pitfalls": [
|
|
12
|
+
{
|
|
13
|
+
"id": "popover-measure-after-render",
|
|
14
|
+
"title": "浮层定位必须在可见状态下测量",
|
|
15
|
+
"scope": "component",
|
|
16
|
+
"components": ["popover", "dropdown", "tooltip", "select"],
|
|
17
|
+
"symptom": "隐藏状态下读不到宽高,打开后位置算错;靠近视口边缘时整块溢出屏幕。",
|
|
18
|
+
"fix": "先以 visibility:hidden 渲染,读到尺寸后再定位(含视口钳制与上下翻转),最后显示。箭头用旋转 45° 的方块,不要用背景图。",
|
|
19
|
+
"tags": ["positioning", "overlay"]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "fixed-element-inventory",
|
|
23
|
+
"title": "新增全局悬浮元素前先盘点既有悬浮层",
|
|
24
|
+
"scope": "component",
|
|
25
|
+
"components": ["overlay", "drawer", "tooltip"],
|
|
26
|
+
"symptom": "两个 position:fixed 的按钮/提示落在同一角落,同一页里叠在一起;没有「悬浮层注册表」,只有看过才知道谁占了位。",
|
|
27
|
+
"fix": "动手前全仓搜一遍固定定位与高 z-index 的节点;同域旧元素按语义让位或合并;挂载点选应用级,不要藏在某个页面里(那样用户根本找不到入口)。",
|
|
28
|
+
"tags": ["fixed", "z-index"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "single-scroll-container",
|
|
32
|
+
"title": "多个滚动容器必然导致行号/表头漂移",
|
|
33
|
+
"scope": "component",
|
|
34
|
+
"components": ["table", "content"],
|
|
35
|
+
"symptom": "表头、行号、正文各自滚动时位置对不上;用 transform 同步只能在某一帧对上,一停就错。",
|
|
36
|
+
"fix": "只留一个滚动容器(父级 overflow:auto),内部全部 min-width:max-content,需要钉住的列/行用 sticky。结构上不可能漂移,不需要 JS 同步。",
|
|
37
|
+
"tags": ["scroll", "sticky"]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "empty-state-no-decoration",
|
|
41
|
+
"title": "空态不要留装饰性元素",
|
|
42
|
+
"scope": "component",
|
|
43
|
+
"components": ["states", "table", "list"],
|
|
44
|
+
"symptom": "没有内容时仍渲染行号 / 表头 / 占位槽,看起来像「加载坏了」。",
|
|
45
|
+
"fix": "渲染前判断内容是否为空;为空时连装饰元素一起省掉,只留一句说明和一个下一步动作。",
|
|
46
|
+
"tags": ["empty", "state"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "table-overflow-wrapper",
|
|
50
|
+
"title": "表格必须有自己的横向滚动容器",
|
|
51
|
+
"scope": "component",
|
|
52
|
+
"components": ["table"],
|
|
53
|
+
"symptom": "列一多就把整页撑出横向滚动;手机上整页左右晃。",
|
|
54
|
+
"fix": "外层套一个 overflow-x:auto 的容器,并给它 tabindex=\"0\" 与可读名字(否则键盘用户滚不动,axe 也会报 scrollable-region-focusable)。",
|
|
55
|
+
"tags": ["mobile", "overflow", "a11y"]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "chart-multiline-label",
|
|
59
|
+
"title": "SVG 的 <text> 不认换行符",
|
|
60
|
+
"scope": "component",
|
|
61
|
+
"components": ["bar", "sparkline", "scientific-plot"],
|
|
62
|
+
"symptom": "标签里写了 \\n,渲染成一行并溢出画布,遮挡相邻元素。",
|
|
63
|
+
"fix": "多行标签拆成多个 <text> 元素并各自定位;或在绘制前按测量宽度手动断行。",
|
|
64
|
+
"tags": ["svg", "chart"]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "line-height-constant-sync",
|
|
68
|
+
"title": "用常量算行高时,常量必须与 CSS 同源",
|
|
69
|
+
"scope": "component",
|
|
70
|
+
"components": ["content"],
|
|
71
|
+
"symptom": "滚动到第 N 行总是差几像素;改过一次 CSS 行高后偏移突然变大。",
|
|
72
|
+
"fix": "行高只留一个来源(读计算样式,或用 CSS 变量同时喂给布局与脚本);滚不动时兜底到 scrollIntoView 而不是继续调常量。",
|
|
73
|
+
"tags": ["css", "sync"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "text-injection-xss",
|
|
77
|
+
"title": "动态内容一律走 DOM API,不拼 innerHTML",
|
|
78
|
+
"scope": "component",
|
|
79
|
+
"components": ["list", "states", "table"],
|
|
80
|
+
"symptom": "字段一扩展就漏转义;恶意字符串(含标签的错误信息、用户输入的名称)直接变成 DOM。",
|
|
81
|
+
"fix": "动态值用 textContent / createElement / appendChild;innerHTML 只留纯静态模板与已转义内容。配一条恶意输入的契约测试。",
|
|
82
|
+
"tags": ["security", "escaping"]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "empty-layout-min-height",
|
|
86
|
+
"title": "空态时主列矮于侧栏会留下大片空白",
|
|
87
|
+
"scope": "layout",
|
|
88
|
+
"components": ["analysis-report", "detail-page", "app-shell"],
|
|
89
|
+
"symptom": "内容少时主列只有半屏,侧栏更高,页面底部或 footer 上方出现一块死白。",
|
|
90
|
+
"fix": "给主列一个与视口相关的最小高度(calc(100dvh - 顶栏)),或让空态块自己撑满;改完专门看一眼「空态整页」而不是只看有数据的那一屏。",
|
|
91
|
+
"tags": ["layout", "empty"]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "self-contained-page-budget",
|
|
95
|
+
"title": "自包含页面的体积预算要一开始就定",
|
|
96
|
+
"scope": "layout",
|
|
97
|
+
"components": [],
|
|
98
|
+
"symptom": "直接内嵌原图,手机打开等于下几百 KB;表格没有滚动容器,整页被撑破。",
|
|
99
|
+
"fix": "先定预算(例如整页 < 400KB);图片统一缩到 720px 宽、quality ≤ 72、progressive;正文 ≥ 16px;表格套 overflow-x:auto。交付前跑一遍标签配平。",
|
|
100
|
+
"tags": ["performance", "mobile", "images"]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"id": "tokens-not-hardcoded",
|
|
104
|
+
"title": "系列化产出先把设计令牌抽成一组常量",
|
|
105
|
+
"scope": "layout",
|
|
106
|
+
"components": [],
|
|
107
|
+
"symptom": "第二份产出与第一份「看起来是一家人但就是不一样」;改一次配色要改 N 个文件。",
|
|
108
|
+
"fix": "先定一组令牌(颜色/字号/间距/字体栈),渲染器只引用令牌、不写死值;新产出直接继承同一组。",
|
|
109
|
+
"tags": ["tokens", "consistency"]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": "dom-stub-smoke",
|
|
113
|
+
"title": "语法检查通过 ≠ 交互能跑",
|
|
114
|
+
"scope": "process",
|
|
115
|
+
"components": [],
|
|
116
|
+
"symptom": "node --check 与 schema 校验全绿,按钮点了没反应:属性名与判断值对不上(data-k=\"V\" 却判 === 'verb'),状态机把刚清掉的项又塞回队列。",
|
|
117
|
+
"fix": "含交互的页面交付前跑一次 DOM 桩冒烟:getElementById 返回同一对象、innerHTML 赋值时注册其中所有 id、事件存根后手动触发。断言落到状态(显示值/条数/文案),不落到「没报错」。",
|
|
118
|
+
"tags": ["testing", "interaction"]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": "parallel-edits-verify",
|
|
122
|
+
"title": "同一文件的多处修改要串行,并逐条 grep 复核",
|
|
123
|
+
"scope": "process",
|
|
124
|
+
"components": [],
|
|
125
|
+
"symptom": "一次发多个修改,工具全部返回成功,事后发现其中几处根本没落盘;直接构建就把旧文案带进成品。",
|
|
126
|
+
"fix": "同一文件串行提交;确实要并行时,提交后用「改后独有的关键词」逐条 grep,搜不到就是没生效。",
|
|
127
|
+
"tags": ["tooling", "verification"]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "stale-server-verify",
|
|
131
|
+
"title": "调试前先确认你连的不是旧进程",
|
|
132
|
+
"scope": "process",
|
|
133
|
+
"components": [],
|
|
134
|
+
"symptom": "端口被旧实例占着,新实例起不来;curl 仍返回 200 和旧内容,于是「改了没生效」查了半天。",
|
|
135
|
+
"fix": "起服务前先结束占用该端口的进程;验证到内容级(关键标记 grep),状态码 200 不代表新代码在跑。",
|
|
136
|
+
"tags": ["debugging", "verification"]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "field-name-from-definition",
|
|
140
|
+
"title": "消费方写的字段名必须对着定义抄",
|
|
141
|
+
"scope": "process",
|
|
142
|
+
"components": [],
|
|
143
|
+
"symptom": "凭记忆写 currentId,实际返回 { current };参数运行时恒 undefined,入口整轮不可用,而路由级测试全绿。",
|
|
144
|
+
"fix": "写字段名时打开定义文件对一遍;新入口上线前至少做一次组件级冒烟(真点一次),路由级测试不证明「组件传对了参数」。",
|
|
145
|
+
"tags": ["integration", "testing"]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "human-semantic-review",
|
|
149
|
+
"title": "语义正确性只有人眼能查",
|
|
150
|
+
"scope": "process",
|
|
151
|
+
"components": [],
|
|
152
|
+
"symptom": "测试全绿,但每个数字/决策都可能在语义上错:取错引号里的值、常量被当成正确结果放行。",
|
|
153
|
+
"fix": "交付前把界面上每个数字与决策对照原始数据源走一遍;演示数据用最小可验证样本,让错误无处藏身。",
|
|
154
|
+
"tags": ["review", "semantics"]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"id": "evidence-grading",
|
|
158
|
+
"title": "措辞强度必须与证据等级匹配",
|
|
159
|
+
"scope": "process",
|
|
160
|
+
"components": [],
|
|
161
|
+
"symptom": "把「按约定位宽写的仿真」说成「机器输出」;把频率证据(grep 计数)说成机制证据;样本内成立被写成上界。",
|
|
162
|
+
"fix": "证据分层:源码实证 > 一手资料 > 可复跑脚本 > 数值模型 > 类比;数值模型显式标注「不是机器输出」;要证上界就解析求极值,不靠采样点。",
|
|
163
|
+
"tags": ["writing", "evidence"]
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"id": "long-doc-consistency",
|
|
167
|
+
"title": "长文里同一结论会被说三遍,还可能自相矛盾",
|
|
168
|
+
"scope": "process",
|
|
169
|
+
"components": [],
|
|
170
|
+
"symptom": "同一件事在开头、证据注、章末各说一遍;更糟的是后一章推翻了前一章刚纠正过的简化。",
|
|
171
|
+
"fix": "定稿前做跨章一致性扫描:把每章的开头句/小结抽出来并排看,重复的压成一条,矛盾的改成交叉引用。",
|
|
172
|
+
"tags": ["writing", "consistency"]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"id": "counterfactual-model-drift",
|
|
176
|
+
"title": "反事实推演最容易偷偷换掉前面的模型",
|
|
177
|
+
"scope": "process",
|
|
178
|
+
"components": [],
|
|
179
|
+
"symptom": "正文刚确立「A 要和 B 合起来才完整」,推演时却把 A 当成完整值,推出与正文矛盾的结论。",
|
|
180
|
+
"fix": "推演前先把已确立的模型逐条列出来,确认沿用的是同一套;把「这里很容易换模型」写进正文,反而成了教学点。",
|
|
181
|
+
"tags": ["writing", "reasoning"]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "fixture-demo-split-truth",
|
|
185
|
+
"title": "门禁测 fixture、示例教另一套:两份标记各说各话",
|
|
186
|
+
"scope": "process",
|
|
187
|
+
"components": ["app-shell"],
|
|
188
|
+
"symptom": "fixture 里是契约推荐的写法,demo 页里却是相反的写法(例如图标态用 aria-label 而不是 .shell__link-label),门禁全绿 —— 因为判据只读 fixture。而使用者只会照 demo 抄,抄走的正是文档用整节否定掉的做法。",
|
|
189
|
+
"fix": "判据要落在真实页面的 DOM 上:存在性断言(该有的元素在不在)+ 可访问名比对(浏览器算出来的名字等不等于那段文字)。fixture 守机制(改坏规则要变红),demo 守教法(教的东西必须是对的)—— 两组缺一不可。",
|
|
190
|
+
"tags": ["gate", "docs", "a11y"]
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
}
|
package/dist/01-tokens/page.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.page {margin:0;min-height:100vh;min-height:100dvh;background:var(--paper);color:var(--text-primary);font-family:var(--sans);font-size:var(--fs-base);line-height:var(--lh-base);-webkit-text-size-adjust:100%;padding-block:calc(env(safe-area-inset-top, 0px) + var(--sp-6)) calc(env(safe-area-inset-bottom, 0px) + var(--sp-6));padding-inline:max(env(safe-area-inset-right, 0px), var(--sp-4)) max(env(safe-area-inset-left, 0px), var(--sp-4));}.page *, .page *::before, .page *::after {box-sizing:border-box;}.page .wrap {margin-inline:auto;max-width:min(var(--measure-page), 100%);}.page .wrap--prose {max-width:min(var(--measure-prose), 100%);}.page h1 {font-family:var(--sans);font-size:var(--fs-2xl);font-weight:500;letter-spacing:var(--tracking-title);line-height:var(--lh-tight);margin:0 0 var(--sp-3);max-width:var(--measure-title);}.page h2 {font-size:var(--fs-lg);margin:var(--sp-7) 0 var(--sp-3);}.page .rule-top {border-top:1px solid var(--border-decor);padding-top:var(--sp-4);}.page .rule-bottom {border-bottom:1px solid var(--border-decor);padding-bottom:var(--sp-2);margin-bottom:var(--sp-4);}.page code {font-family:var(--mono);font-size:0.9em;background:var(--surface-sunken);padding:1px 4px;border-radius:var(--r-xs);}.page .box {background:var(--surface);border:1px solid var(--border-decor);border-radius:var(--r-md);padding:var(--sp-5);}.page .box.bad {background:var(--surface-sunken);}.page .cmp {display:grid;grid-template-columns:minmax(0, 1fr) minmax(0, 1fr);gap:var(--sp-4);}.page .cmp--wide-first {grid-template-columns:minmax(0, 1.55fr) minmax(0, 1fr);}@media (max-width:640px) {.page .cmp, .page .cmp--wide-first, .page .cmp--clip {grid-template-columns:minmax(0, 1fr);}}.page .cmp__pane {padding:var(--sp-4);border:1px solid var(--border-decor);border-radius:var(--r-md);background:var(--surface-sunken);min-width:0;}.page .cmp--clip .cmp__pane {overflow:hidden;}.page .cmp__pane > h3 {margin:0 0 var(--sp-3);font-size:var(--fs-sm);font-weight:500;}.page .cmp__bad > h3 {color:var(--danger);}.page .cmp__good > h3 {color:var(--success);}.page .cmp__why {margin:var(--sp-3) 0 0;font-size:var(--fs-xs);line-height:1.6;color:var(--text-secondary);}
|
|
1
|
+
.page {margin:0;min-height:100vh;min-height:100dvh;background:var(--paper);color:var(--text-primary);font-family:var(--sans);font-size:var(--fs-base);line-height:var(--lh-base);-webkit-text-size-adjust:100%;padding-block:calc(env(safe-area-inset-top, 0px) + var(--sp-6)) calc(env(safe-area-inset-bottom, 0px) + var(--sp-6));padding-inline:max(env(safe-area-inset-right, 0px), var(--sp-4)) max(env(safe-area-inset-left, 0px), var(--sp-4));}.page *, .page *::before, .page *::after {box-sizing:border-box;}.page .wrap {margin-inline:auto;max-width:min(var(--measure-page), 100%);}.page .wrap--prose {max-width:min(var(--measure-prose), 100%);}.page h1 {font-family:var(--sans);font-size:var(--fs-2xl);font-weight:500;letter-spacing:var(--tracking-title);line-height:var(--lh-tight);margin:0 0 var(--sp-3);max-width:var(--measure-title);}.page h2 {font-size:var(--fs-lg);margin:var(--sp-7) 0 var(--sp-3);}.page .rule-top {border-top:1px solid var(--border-decor);padding-top:var(--sp-4);}.page .rule-bottom {border-bottom:1px solid var(--border-decor);padding-bottom:var(--sp-2);margin-bottom:var(--sp-4);}.page code {font-family:var(--mono);font-size:0.9em;background:var(--surface-sunken);padding:1px 4px;border-radius:var(--r-xs);}:where(.page) pre {overflow-x:auto;}.page .box {background:var(--surface);border:1px solid var(--border-decor);border-radius:var(--r-md);padding:var(--sp-5);}.page .box.bad {background:var(--surface-sunken);}.page .cmp {display:grid;grid-template-columns:minmax(0, 1fr) minmax(0, 1fr);gap:var(--sp-4);}.page .cmp--wide-first {grid-template-columns:minmax(0, 1.55fr) minmax(0, 1fr);}@media (max-width:640px) {.page .cmp, .page .cmp--wide-first, .page .cmp--clip {grid-template-columns:minmax(0, 1fr);}}.page .cmp__pane {padding:var(--sp-4);border:1px solid var(--border-decor);border-radius:var(--r-md);background:var(--surface-sunken);min-width:0;}.page .cmp--clip .cmp__pane {overflow:hidden;}.page .cmp__pane > h3 {margin:0 0 var(--sp-3);font-size:var(--fs-sm);font-weight:500;}.page .cmp__bad > h3 {color:var(--danger);}.page .cmp__good > h3 {color:var(--success);}.page .cmp__why {margin:var(--sp-3) 0 0;font-size:var(--fs-xs);line-height:1.6;color:var(--text-secondary);}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.choice {position:relative;display:flex;align-items:center;min-height:44px;cursor:pointer;user-select:none;}.choice__label {display:flex;align-items:center;gap:var(--sp-2);cursor:pointer;min-height:44px;flex:1;min-width:0;}.choice--radio .choice__label {border-radius:var(--r-sm);}.choice__input {position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;z-index:1;}.choice__mark {position:relative;flex:none;display:grid;place-items:center;width:20px;height:20px;background:var(--surface);border:1px solid var(--border-control);transition:background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);}@media (hover:hover) and (pointer:fine) {.choice:hover .choice__mark {border-color:var(--text-tertiary);}}.choice__input:focus-visible ~ .choice__label .choice__mark {outline:2px solid var(--accent);outline-offset:2px;}.choice__mark::after {content:"";position:absolute;width:5px;height:9px;border:solid var(--text-on-accent);border-width:0 2px 2px 0;transform:rotate(45deg) scale(0);transform-origin:center;transition:transform var(--dur-fast) var(--ease-out);}.choice__input:checked ~ .choice__label .choice__mark {background:var(--accent);border-color:var(--accent);}.choice__input:checked ~ .choice__label .choice__mark::after {transform:rotate(45deg) scale(1);}.choice__input:disabled {cursor:not-allowed;}.choice__input:disabled ~ .choice__label .choice__mark, .choice__input:disabled ~ .choice__label {background:var(--surface-sunken);border-color:var(--border-decor);}.choice__input:disabled ~ .choice__label {color:var(--text-tertiary);cursor:not-allowed;}.choice__label {font-size:var(--fs-sm);line-height:var(--lh-base);color:var(--text-primary);}.choice__hint {font-size:var(--fs-xs);color:var(--text-tertiary);line-height:1.5;}.choice--checkbox .choice__mark {border-radius:5px;}.choice--checkbox .choice__input:indeterminate ~ .choice__label .choice__mark {background:var(--surface);border-color:var(--accent);}.choice--checkbox .choice__input:indeterminate ~ .choice__label .choice__mark::after {width:10px;height:2px;border:none;background:var(--accent);border-radius:1px;transform:none;}.choice--radio .choice__mark {border-radius:var(--r-pill);}.choice--radio .choice__mark::after {width:8px;height:8px;border:none;background:var(--text-on-accent);border-radius:var(--r-pill);transform:scale(0);}.choice--radio .choice__input:checked ~ .choice__label .choice__mark {background:var(--accent);border-color:var(--accent);}.choice--radio .choice__input:checked ~ .choice__label .choice__mark::after {transform:scale(1);}.choice__group {border:none;margin:0;padding:0;min-width:0;}.choice__legend {padding:0;margin-bottom:var(--sp-2);font-size:var(--fs-sm);font-weight:500;color:var(--text-primary);}.choice__options {display:flex;flex-direction:column;gap:var(--sp-1);}.select {position:relative;display:inline-flex;align-items:center;width:100%;}.select__control {width:100%;height:44px;padding:0 40px 0 var(--sp-3);font-family:inherit;font-size:16px;line-height:1.5;color:var(--text-primary);background:var(--surface);border:1px solid var(--border-control);border-radius:var(--r-sm);appearance:none;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;transition:border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);}.select__control::-ms-expand {display:none;}.select__control::-webkit-calendar-picker-indicator {opacity:0;}@media (hover:hover) and (pointer:fine) {.select__control:hover:not(:disabled) {border-color:var(--text-tertiary);}}.select__control:focus {outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}.select__control:disabled {background:var(--surface-sunken);color:var(--text-tertiary);border-color:var(--border-decor);cursor:not-allowed;}.select__arrow {position:absolute;inset-inline-end:var(--sp-3);pointer-events:none;color:var(--text-tertiary);display:grid;place-items:center;}.select__control--auto {height:auto;min-height:44px;padding-block:var(--sp-2);}@media (prefers-reduced-motion:reduce) {.choice__mark::after {transition:none;}}
|
|
1
|
+
.choice {position:relative;display:flex;align-items:center;min-height:44px;cursor:pointer;user-select:none;}.choice__label {display:flex;align-items:center;gap:var(--sp-2);cursor:pointer;min-height:44px;flex:1;min-width:0;}.choice--radio .choice__label {border-radius:var(--r-sm);}.choice__input {position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;z-index:1;}.choice__mark {position:relative;flex:none;display:grid;place-items:center;width:20px;height:20px;background:var(--surface);border:1px solid var(--border-control);transition:background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);}@media (hover:hover) and (pointer:fine) {.choice:hover .choice__mark {border-color:var(--text-tertiary);}}.choice__input:focus-visible ~ .choice__label .choice__mark {outline:2px solid var(--accent);outline-offset:2px;}.choice__mark::after {content:"";position:absolute;width:5px;height:9px;border:solid var(--text-on-accent);border-width:0 2px 2px 0;transform:rotate(45deg) scale(0);transform-origin:center;transition:transform var(--dur-fast) var(--ease-out);}.choice__input:checked ~ .choice__label .choice__mark {background:var(--accent);border-color:var(--accent);}.choice__input:checked ~ .choice__label .choice__mark::after {transform:rotate(45deg) scale(1);}.choice__input:disabled {cursor:not-allowed;}.choice__input:disabled ~ .choice__label .choice__mark, .choice__input:disabled ~ .choice__label {background:var(--surface-sunken);border-color:var(--border-decor);}.choice__input:disabled ~ .choice__label {color:var(--text-tertiary);cursor:not-allowed;}.choice__label {font-size:var(--fs-sm);line-height:var(--lh-base);color:var(--text-primary);}.choice__hint {font-size:var(--fs-xs);color:var(--text-tertiary);line-height:1.5;}.choice--checkbox .choice__mark {border-radius:5px;}.choice--checkbox .choice__input:indeterminate ~ .choice__label .choice__mark {background:var(--surface);border-color:var(--accent);}.choice--checkbox .choice__input:indeterminate ~ .choice__label .choice__mark::after {width:10px;height:2px;border:none;background:var(--accent);border-radius:1px;transform:none;}.choice--radio .choice__mark {border-radius:var(--r-pill);}.choice--radio .choice__mark::after {width:8px;height:8px;border:none;background:var(--text-on-accent);border-radius:var(--r-pill);transform:scale(0);}.choice--radio .choice__input:checked ~ .choice__label .choice__mark {background:var(--accent);border-color:var(--accent);}.choice--radio .choice__input:checked ~ .choice__label .choice__mark::after {transform:scale(1);}.choice__group {border:none;margin:0;padding:0;min-width:0;}.choice__legend {padding:0;margin-bottom:var(--sp-2);font-size:var(--fs-sm);font-weight:500;color:var(--text-primary);}.choice__options {display:flex;flex-direction:column;gap:var(--sp-1);}.select {position:relative;display:inline-flex;align-items:center;width:100%;}.select__control {width:100%;height:44px;padding:0 40px 0 var(--sp-3);font-family:inherit;font-size:16px;line-height:1.5;color:var(--text-primary);background:var(--surface);border:1px solid var(--border-control);border-radius:var(--r-sm);appearance:none;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;transition:border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);}.select__control::-ms-expand {display:none;}.select__control::-webkit-calendar-picker-indicator {opacity:0;}@media (hover:hover) and (pointer:fine) {.select__control:hover:not(:disabled) {border-color:var(--text-tertiary);}}.select__control:focus {outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}.select__control:disabled {background:var(--surface-sunken);color:var(--text-tertiary);border-color:var(--border-decor);cursor:not-allowed;}.select__arrow {position:absolute;inset-inline-end:var(--sp-3);pointer-events:none;color:var(--text-tertiary);display:grid;place-items:center;}.select__control--auto {height:auto;min-height:44px;padding-block:var(--sp-2);}@media (prefers-reduced-motion:reduce) {.choice__mark::after {transition:none;}}@media (forced-colors:active) {.choice--radio .choice__mark::after {background:CanvasText;}.choice--checkbox .choice__input:indeterminate ~ .choice__label .choice__mark::after {background:CanvasText;}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.field {display:flex;flex-direction:column;gap:var(--sp-1);}.field__label {font-size:var(--fs-sm);font-weight:500;color:var(--text-primary);line-height:var(--lh-tight);}.field__req {color:var(--danger);margin-inline-start:2px;}.field__input {width:100%;box-sizing:border-box;height:44px;padding:0 var(--sp-3);font-family:inherit;font-size:16px;line-height:1.5;color:var(--text-primary);background:var(--surface);border:1px solid var(--border-control);border-radius:var(--r-sm);transition:border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);}.field__input::placeholder {color:var(--text-tertiary);opacity:1;}.field__input--textarea {height:auto;min-height:88px;padding:var(--sp-3);resize:vertical;line-height:var(--lh-base);}.field__input--sm {height:36px;font-size:16px;min-height:44px;}@media (hover:hover) and (pointer:fine) {.field__input:hover:not(:disabled):not([readonly]) {border-color:var(--text-tertiary);}}.field__input:focus {outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}.field__input:disabled {background:var(--surface-sunken);color:var(--text-tertiary);border-color:var(--border-decor);cursor:not-allowed;}.field__input[readonly] {background:var(--surface-sunken);color:var(--text-primary);border-color:var(--border-decor);cursor:default;}.field__input[readonly]:focus {border-color:var(--text-tertiary);box-shadow:0 0 0 3px var(--surface-sunken);}.field__input[aria-invalid="true"] {border-color:var(--danger);}.field__input[aria-invalid="true"]:focus {border-color:var(--danger);box-shadow:0 0 0 3px var(--danger-bg);}.field__input[aria-invalid="true"] {background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23b3261e' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--sp-3) center;padding-inline-end:40px;}.field__hint {font-size:var(--fs-xs);color:var(--text-tertiary);line-height:1.5;}.field__error {display:flex;align-items:flex-start;gap:var(--sp-1);font-size:var(--fs-xs);color:var(--danger);line-height:1.5;}.field__error::before {content:"";flex:none;width:14px;height:14px;margin-top:3px;background:currentColor;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E") center/contain no-repeat;}.field__input[aria-invalid="false"][data-state="valid"] {border-color:var(--success);}.field--row {flex-direction:row;align-items:center;gap:var(--sp-3);}.field--row .field__label {flex:none;min-width:88px;}@media (max-width:480px) {.field--row {flex-direction:column;align-items:stretch;}.field--row .field__label {min-width:0;}}
|
|
1
|
+
.field {display:flex;flex-direction:column;gap:var(--sp-1);}.field__label {font-size:var(--fs-sm);font-weight:500;color:var(--text-primary);line-height:var(--lh-tight);}.field__req {color:var(--danger);margin-inline-start:2px;}.field__input {width:100%;box-sizing:border-box;height:44px;padding:0 var(--sp-3);font-family:inherit;font-size:16px;line-height:1.5;color:var(--text-primary);background:var(--surface);border:1px solid var(--border-control);border-radius:var(--r-sm);transition:border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);}.field__input::placeholder {color:var(--text-tertiary);opacity:1;}.field__input--textarea {height:auto;min-height:88px;padding:var(--sp-3);resize:vertical;line-height:var(--lh-base);}.field__input--sm {height:36px;font-size:16px;min-height:44px;}@media (hover:hover) and (pointer:fine) {.field__input:hover:not(:disabled):not([readonly]) {border-color:var(--text-tertiary);}}.field__input:focus {outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}.field__input:disabled {background:var(--surface-sunken);color:var(--text-tertiary);border-color:var(--border-decor);cursor:not-allowed;}.field__input[readonly] {background:var(--surface-sunken);color:var(--text-primary);border-color:var(--border-decor);cursor:default;}.field__input[readonly]:focus {border-color:var(--text-tertiary);box-shadow:0 0 0 3px var(--surface-sunken);}.field__input[aria-invalid="true"] {border-color:var(--danger);}.field__input[aria-invalid="true"]:focus {border-color:var(--danger);box-shadow:0 0 0 3px var(--danger-bg);}.field__input[aria-invalid="true"] {background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23b3261e' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--sp-3) center;padding-inline-end:40px;}.field__hint {font-size:var(--fs-xs);color:var(--text-tertiary);line-height:1.5;}.field__error {display:flex;align-items:flex-start;gap:var(--sp-1);font-size:var(--fs-xs);color:var(--danger);line-height:1.5;}.field__error::before {content:"";flex:none;width:14px;height:14px;margin-top:3px;background:currentColor;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 8v5M12 16.5v.5'/%3E%3C/svg%3E") center/contain no-repeat;}@media (forced-colors:active) {.field__error::before {background:CanvasText;}}.field__input[aria-invalid="false"][data-state="valid"] {border-color:var(--success);}.field--row {flex-direction:row;align-items:center;gap:var(--sp-3);}.field--row .field__label {flex:none;min-width:88px;}@media (max-width:480px) {.field--row {flex-direction:column;align-items:stretch;}.field--row .field__label {min-width:0;}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.progress {display:block;width:100%;height:var(--progress-h);background:var(--surface-sunken);border-radius:var(--r-full);overflow:hidden;}.progress__bar {display:block;height:100%;width:var(--progress, 0%);background:var(--accent);border-radius:inherit;transition:width var(--progress-dur) var(--ease-out);}.progress--success .progress__bar {background:var(--success);}.progress--warning .progress__bar {background:var(--warning);}.progress--danger .progress__bar {background:var(--danger);}.progress--lg {--progress-h:10px;}.progress--sm {--progress-h:4px;}.progress-ring {display:inline-grid;place-items:center;position:relative;width:var(--ring-size);height:var(--ring-size);border-radius:50%;background:conic-gradient( var(--accent) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0 );}.progress-ring__label {display:grid;place-items:center;width:calc(100% - var(--ring-thickness) * 2);height:calc(100% - var(--ring-thickness) * 2);border-radius:50%;background:var(--surface);font-size:var(--fs-sm);color:var(--text-primary);font-variant-numeric:tabular-nums;}.progress-ring--success {background:conic-gradient(var(--success) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0);}.progress-ring--danger {background:conic-gradient(var(--danger) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0);}.progress--indeterminate .progress__bar {width:35%;animation:progress-slide 1.1s var(--ease-out) infinite;}@keyframes progress-slide {0% {transform:translateX(-100%);}100% {transform:translateX(340%);}}.progress-steps {display:flex;gap:var(--sp-1);}.progress-steps__seg {flex:1;height:var(--progress-h, 4px);background:var(--surface-sunken);border-radius:var(--r-full);}.progress-steps__seg--done {background:var(--accent);}.progress-steps__seg--current {background:var(--accent);opacity:0.55;}.progress[aria-busy='true'] {cursor:progress;}@media (prefers-reduced-motion:reduce) {.progress__bar {transition:none;}.progress--indeterminate .progress__bar {animation:none;transform:none;width:25%;background:var(--accent);}.progress--indeterminate .progress__bar::after {content:none;}.progress--indeterminate.progress--success .progress__bar {background:var(--success);}.progress--indeterminate.progress--warning .progress__bar {background:var(--warning);}.progress--indeterminate.progress--danger .progress__bar {background:var(--danger);}}
|
|
1
|
+
.progress {display:block;width:100%;height:var(--progress-h);background:var(--surface-sunken);border-radius:var(--r-full);overflow:hidden;outline:1px solid transparent;outline-offset:-1px;}.progress__bar {display:block;height:100%;width:var(--progress, 0%);background:var(--accent);border-radius:inherit;transition:width var(--progress-dur) var(--ease-out);}.progress--success .progress__bar {background:var(--success);}.progress--warning .progress__bar {background:var(--warning);}.progress--danger .progress__bar {background:var(--danger);}@media (forced-colors:active) {.progress .progress__bar {background:Highlight;}}.progress--lg {--progress-h:10px;}.progress--sm {--progress-h:4px;}.progress-ring {display:inline-grid;place-items:center;position:relative;width:var(--ring-size);height:var(--ring-size);border-radius:50%;background:conic-gradient( var(--accent) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0 );}.progress-ring__label {display:grid;place-items:center;width:calc(100% - var(--ring-thickness) * 2);height:calc(100% - var(--ring-thickness) * 2);border-radius:50%;background:var(--surface);font-size:var(--fs-sm);color:var(--text-primary);font-variant-numeric:tabular-nums;}.progress-ring--success {background:conic-gradient(var(--success) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0);}.progress-ring--danger {background:conic-gradient(var(--danger) calc(var(--progress-num, 0) * 1%), var(--surface-sunken) 0);}@media (forced-colors:active) {.progress-ring {background:none;outline:2px solid CanvasText;outline-offset:-2px;}}.progress--indeterminate .progress__bar {width:35%;animation:progress-slide 1.1s var(--ease-out) infinite;}@keyframes progress-slide {0% {transform:translateX(-100%);}100% {transform:translateX(340%);}}.progress-steps {display:flex;gap:var(--sp-1);}.progress-steps__seg {flex:1;height:var(--progress-h, 4px);background:var(--surface-sunken);border-radius:var(--r-full);}.progress-steps__seg--done {background:var(--accent);}.progress-steps__seg--current {background:var(--accent);opacity:0.55;}.progress[aria-busy='true'] {cursor:progress;}@media (prefers-reduced-motion:reduce) {.progress__bar {transition:none;}.progress--indeterminate .progress__bar {animation:none;transform:none;width:25%;background:var(--accent);}.progress--indeterminate .progress__bar::after {content:none;}.progress--indeterminate.progress--success .progress__bar {background:var(--success);}.progress--indeterminate.progress--warning .progress__bar {background:var(--warning);}.progress--indeterminate.progress--danger .progress__bar {background:var(--danger);}}
|