weifuwu 0.93.2 → 0.94.0

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 (124) hide show
  1. package/README.md +5 -5
  2. package/dist/client/components/ActionSheet/ActionSheet.d.ts +1 -1
  3. package/dist/client/components/AlertGroup/AlertGroup.d.ts +1 -1
  4. package/dist/client/components/Anchor/Anchor.d.ts +1 -1
  5. package/dist/client/components/AppShell/AppShell.d.ts +20 -3
  6. package/dist/client/components/AuthPage/AuthPage.d.ts +1 -1
  7. package/dist/client/components/AutoComplete/AutoComplete.d.ts +1 -1
  8. package/dist/client/components/AvatarGroup/AvatarGroup.d.ts +1 -1
  9. package/dist/client/components/Button/Button.d.ts +8 -2
  10. package/dist/client/components/Chart/Chart.d.ts +1 -1
  11. package/dist/client/components/Chart/chart-utils.d.ts +1 -1
  12. package/dist/client/components/ChatInput/ChatInput.d.ts +3 -1
  13. package/dist/client/components/CodeBlock/CodeBlock.d.ts +1 -1
  14. package/dist/client/components/CodeBlock/highlight.d.ts +1 -1
  15. package/dist/client/components/Confirm/Confirm.d.ts +1 -1
  16. package/dist/client/components/CronPicker/CronPicker.d.ts +31 -0
  17. package/dist/client/components/DatePicker/DatePicker.d.ts +1 -1
  18. package/dist/client/components/DatePicker/calendar-utils.d.ts +1 -1
  19. package/dist/client/components/Descriptions/Descriptions.d.ts +1 -1
  20. package/dist/client/components/Drawer/Drawer.d.ts +4 -1
  21. package/dist/client/components/DropZone/DropZone.d.ts +1 -1
  22. package/dist/client/components/Dropdown/Dropdown.d.ts +1 -1
  23. package/dist/client/components/Editor/Editor.d.ts +1 -1
  24. package/dist/client/components/Editor/edit-events.d.ts +1 -1
  25. package/dist/client/components/Editor/model/apply.d.ts +1 -1
  26. package/dist/client/components/Editor/model/diff.d.ts +1 -1
  27. package/dist/client/components/Editor/model/dom.d.ts +1 -1
  28. package/dist/client/components/Editor/model/history.d.ts +1 -1
  29. package/dist/client/components/Editor/model/html.d.ts +1 -1
  30. package/dist/client/components/Editor/model/inverse.d.ts +1 -1
  31. package/dist/client/components/Editor/model/types.d.ts +1 -1
  32. package/dist/client/components/Editor/tools/table.d.ts +1 -1
  33. package/dist/client/components/Editor/tools/toolbar.d.ts +1 -1
  34. package/dist/client/components/Editor/tools/types.d.ts +1 -1
  35. package/dist/client/components/FilePreview/FilePreview.d.ts +1 -1
  36. package/dist/client/components/FilePreview/markdown.d.ts +1 -1
  37. package/dist/client/components/FileTree/FileTree.d.ts +1 -1
  38. package/dist/client/components/FileUpload/FileUpload.d.ts +1 -1
  39. package/dist/client/components/FloatButton/FloatButton.d.ts +1 -1
  40. package/dist/client/components/Grid/Grid.d.ts +1 -1
  41. package/dist/client/components/Highlight/Highlight.d.ts +1 -1
  42. package/dist/client/components/HoverCard/HoverCard.d.ts +1 -1
  43. package/dist/client/components/Icon/Icon.d.ts +1 -1
  44. package/dist/client/components/Img/Img.d.ts +1 -1
  45. package/dist/client/components/InView/InView.d.ts +1 -1
  46. package/dist/client/components/Input/Input.d.ts +6 -0
  47. package/dist/client/components/InputNumber/InputNumber.d.ts +1 -1
  48. package/dist/client/components/JSONViewer/JSONViewer.d.ts +1 -1
  49. package/dist/client/components/Layout/Layout.d.ts +1 -1
  50. package/dist/client/components/Link/Link.d.ts +1 -1
  51. package/dist/client/components/List/List.d.ts +1 -1
  52. package/dist/client/components/ListScaffold/ListScaffold.d.ts +40 -0
  53. package/dist/client/components/LogViewer/LogViewer.d.ts +1 -1
  54. package/dist/client/components/Markdown/Markdown.d.ts +1 -1
  55. package/dist/client/components/Markdown/parser.d.ts +1 -1
  56. package/dist/client/components/Menu/Menu.d.ts +3 -1
  57. package/dist/client/components/MessageBubble/MessageBubble.d.ts +1 -1
  58. package/dist/client/components/Modal/Modal.d.ts +5 -1
  59. package/dist/client/components/NavBar/NavBar.d.ts +1 -1
  60. package/dist/client/components/NavMenu/NavMenu.d.ts +1 -1
  61. package/dist/client/components/OfficeEditor/ai/ai-bridge.d.ts +1 -1
  62. package/dist/client/components/OfficeEditor/model/apply.d.ts +1 -1
  63. package/dist/client/components/OfficeEditor/model/types.d.ts +1 -1
  64. package/dist/client/components/PasswordInput/PasswordInput.d.ts +1 -1
  65. package/dist/client/components/Popconfirm/Popconfirm.d.ts +1 -1
  66. package/dist/client/components/Popover/Popover.d.ts +1 -1
  67. package/dist/client/components/PromptTemplate/PromptTemplate.d.ts +1 -1
  68. package/dist/client/components/RelationGraph/RelationGraph.d.ts +1 -1
  69. package/dist/client/components/Result/Result.d.ts +1 -1
  70. package/dist/client/components/Scrollbar/Scrollbar.d.ts +1 -1
  71. package/dist/client/components/SheetGrid/SheetGrid.d.ts +2 -2
  72. package/dist/client/components/Skeleton/Skeleton.d.ts +1 -1
  73. package/dist/client/components/SlideCanvas/SlideCanvas.d.ts +2 -2
  74. package/dist/client/components/Space/Space.d.ts +1 -1
  75. package/dist/client/components/StatusDot/StatusDot.d.ts +25 -0
  76. package/dist/client/components/TabBar/TabBar.d.ts +1 -1
  77. package/dist/client/components/TagsInput/TagsInput.d.ts +1 -1
  78. package/dist/client/components/Textarea/Textarea.d.ts +6 -0
  79. package/dist/client/components/ThemeSwitch/ThemeSwitch.d.ts +1 -1
  80. package/dist/client/components/Timeline/Timeline.d.ts +1 -1
  81. package/dist/client/components/Tooltip/Tooltip.d.ts +1 -1
  82. package/dist/client/components/VirtualTable/VirtualTable.d.ts +1 -1
  83. package/dist/client/components/WordCloud/WordCloud.d.ts +1 -1
  84. package/dist/client/components/index.d.ts +9 -3
  85. package/dist/client/components/index.js +36 -36
  86. package/dist/client/components/style.css +1 -1
  87. package/dist/client/layout/decl.d.ts +9 -0
  88. package/dist/client/layout/define.d.ts +41 -0
  89. package/dist/client/layout/index.d.ts +20 -0
  90. package/dist/client/layout/index.js +17 -0
  91. package/dist/client/layout/weifuwu-layout.css +1 -1
  92. package/dist/client/vdom/context/UIContext.d.ts +1 -1
  93. package/dist/client/vdom/core/create-component.d.ts +42 -0
  94. package/dist/client/vdom/core/create-item.d.ts +52 -0
  95. package/dist/client/vdom/core/vnode.d.ts +8 -2
  96. package/dist/client/vdom/hooks/env.d.ts +12 -0
  97. package/dist/client/vdom/hooks/field.d.ts +54 -0
  98. package/dist/client/vdom/hooks/overlay.d.ts +60 -0
  99. package/dist/client/vdom/hooks/signal.d.ts +25 -0
  100. package/dist/client/vdom/index.d.ts +9 -2
  101. package/dist/client/vdom/index.js +3 -3
  102. package/dist/client/vdom/jsx-runtime.d.ts +4 -4
  103. package/dist/client/vdom/jsx-runtime.js +1 -1
  104. package/dist/client/vdom/testing.js +2 -2
  105. package/dist/dev/index.js +7 -6
  106. package/dist/server/ai/index.js +7 -0
  107. package/dist/server/ai/types.d.ts +1 -1
  108. package/dist/server/email/index.js +1 -0
  109. package/dist/server/index.js +235 -5
  110. package/dist/server/messager/index.js +1 -0
  111. package/dist/server/postgres/index.js +56 -0
  112. package/dist/server/queue/index.js +1 -0
  113. package/dist/server/redis/index.js +3 -0
  114. package/dist/server/scheduler/index.js +1 -0
  115. package/dist/server/ui/index.d.ts +1 -1
  116. package/dist/server/ui/index.js +15 -0
  117. package/dist/server/user/index.js +1 -0
  118. package/dist/server/user/token.d.ts +1 -1
  119. package/dist/server/workflows/index.js +24 -0
  120. package/dist/shared/router/index.js +2 -0
  121. package/docs/client.md +143 -10
  122. package/docs/layout.md +14 -14
  123. package/docs/server.md +1 -1
  124. package/package.json +66 -12
@@ -0,0 +1,9 @@
1
+ /**
2
+ * weifuwu/client/layout — 原语声明(defineLayout——生成器消费——BEM 直拼单源)
3
+ *
4
+ * W4 样本:row/stack 族(机制验证——生成 = 手写逐属性等价——等价后手写
5
+ * _row.css/_stack.css 删除——生成器输出进 bundle 汇编)。
6
+ * 声明添加 = 新原语(组合缺省(gap/align defaults)声明即生成)。
7
+ */
8
+ import type { StructureDecl } from './define.ts';
9
+ export declare const structures: StructureDecl[];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * weifuwu/client/layout — defineLayout(布局原语声明 + 生成器)
3
+ *
4
+ * 设计(2027-09——分层抽象 W4):layout 174 类手写实证——原语 = **声明**:
5
+ * 语义词 → 属性组合(stack/row/grid、组合缺省、零优先级默认、断点变体)。
6
+ * 生成器输出 = 与手写**逐属性等价**的 CSS(硬验收——diff 等价才迁移)。
7
+ *
8
+ * 生成规则(与手写纪律对齐):
9
+ * - **基规则**(正常优先级——display 等结构面)
10
+ * - **零优先级默认**(`:where()`——gap/align 默认被覆盖工具靠优先级获胜,
11
+ * 不依赖 import 顺序——L3 定案)
12
+ * - **变体**(wf-row-reverse——继承基 + cover 覆盖;变体默认零优先级同基)
13
+ * - 输出格式稳定(单行规则——注释头)
14
+ *
15
+ * 用法(build 期——bundle.ts 调 generateLayoutCss 拼入汇编):
16
+ * const css = generateLayoutCss([
17
+ * structure({ class: 'wf-row', base: { display: 'flex', 'flex-wrap': 'wrap' },
18
+ * defaults: { gap: 'var(--wf-gap, var(--wf-gap-md))', 'align-items': 'var(--wf-align, center)' },
19
+ * variants: { 'wf-row-reverse': { cover: { 'flex-direction': 'row-reverse' } } } }),
20
+ * ])
21
+ */
22
+ /** 结构原语声明(class + 基/默认/变体) */
23
+ export interface StructureDecl {
24
+ /** 基类(wf-row) */
25
+ class: string;
26
+ /** 基规则(正常优先级——display 等结构面) */
27
+ base?: Record<string, string>;
28
+ /** 零优先级默认(:where() 包装——gap/align 默认) */
29
+ defaults?: Record<string, string>;
30
+ /** 变体(wf-row-reverse——继承基 + cover 覆盖;变体默认零优先级同基) */
31
+ variants?: Record<string, {
32
+ cover?: Record<string, string>;
33
+ defaults?: Record<string, string>;
34
+ }>;
35
+ }
36
+ /** 生成器:声明 → CSS(规则序:基 → 零优先级默认 → 变体基/默认——手写序对齐) */
37
+ export declare function generateLayoutCss(decls: StructureDecl[]): string;
38
+ /** 逐属性等价(生成 vs 手写——解析比对——硬验收用) */
39
+ export declare function parseProps(css: string): Map<string, Map<string, string>>;
40
+ /** 等价断言(生成 ⊆ 手写——声明覆盖的选择器逐属性相等;手写多余 = 未迁移面) */
41
+ export declare function isEquivalent(generated: string, handwritten: string): boolean;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * weifuwu/client/layout — 布局原语声明 + 装配(defineLayout 生态公共面)
3
+ *
4
+ * 三面:
5
+ * - **原语声明**(define.ts):StructureDecl/generateLayoutCss/parseProps/
6
+ * isEquivalent——自定义布局语言(构建期声明 → 生成 CSS——声明比实现短
7
+ * 且机械部分全消失判据)
8
+ * - **内建声明**(decl.ts):row/stack/items 族(生成 = 旧手写逐属性等价冻结快照)
9
+ * - **装配**(bundle.ts):bundleLayout/bundleComponents/layerMapOf/LAYER_OF/
10
+ * LAYER_ORDER——node 构建管线(build.mjs/审计脚本共用——装配单源)
11
+ *
12
+ * 注意:bundle 面含 node:fs 依赖(构建期工具)——浏览器消费只引
13
+ * `weifuwu/client/layout/weifuwu-layout.css`(CSS 面);JS 面是构建期工具。
14
+ */
15
+ export type { StructureDecl } from './define.ts';
16
+ export { generateLayoutCss, parseProps, isEquivalent } from './define.ts';
17
+ export { structures } from './decl.ts';
18
+ export { LAYER_ORDER, LAYER_OF } from './bundle.ts';
19
+ export type { CssBundle } from './bundle.ts';
20
+ export { layoutEntryFiles, isLayoutSourceDir, bundleLayout, bundleComponents, layerMapOf } from './bundle.ts';
@@ -0,0 +1,17 @@
1
+ var g=(a,t)=>t&&Object.keys(t).length?`${a} { ${Object.entries(t).map(([i,e])=>`${i}: ${e};`).join(" ")} }`:"",v=a=>a.replace(/^0\\.|^0\\./gm,"").replace(/\s+/g," ").trim();function w(a){let t=[];for(let i of a){let e=`.${i.class}`,o=g(e,i.base??{});o&&t.push(o);let c=g(`:where(${e})`,i.defaults??{});c&&t.push(c);for(let[s,n]of Object.entries(i.variants??{})){let r=`.${s}`,l=g(r,{...i.base??{},...n.cover??{}});l&&t.push(l);let f=g(`:where(${r})`,{...i.defaults??{},...n.defaults??{}});f&&t.push(f)}}return t.join(`
2
+ `)}function y(a){let t=new Map,i=a.replace(/\/\*[\s\S]*?\*\//g,""),e=/([^{}]+)\{([^{}]*)\}/g,o;for(;o=e.exec(i);){let c=o[1].replace(/\s+/g," ").trim(),s=new Map;for(let r of o[2].split(";")){let l=r.indexOf(":");l<0||s.set(r.slice(0,l).trim(),r.slice(l+1).trim())}let n=t.get(c);if(n)for(let[r,l]of s)n.set(r,l);else t.set(c,s)}return t}function j(a,t){let i=y(a),e=y(t);for(let[o,c]of i){let s=e.get(o);if(!s)return!1;for(let[n,r]of c)if(v(s.get(n)??"")!==v(r))return!1}return!0}var m=[{class:"wf-stack",base:{display:"flex","flex-direction":"column"},defaults:{gap:"var(--wf-gap, var(--wf-gap-md))","align-items":"var(--wf-align, stretch)"}},{class:"wf-row",base:{display:"flex","flex-wrap":"wrap"},defaults:{gap:"var(--wf-gap, var(--wf-gap-md))","align-items":"var(--wf-align, center)"},variants:{"wf-row-reverse":{cover:{"flex-direction":"row-reverse"}}}},{class:"wf-items-start",base:{"--wf-align":"flex-start"}},{class:"wf-items-center",base:{"--wf-align":"center"}},{class:"wf-items-end",base:{"--wf-align":"flex-end"}},{class:"wf-items-stretch",base:{"--wf-align":"stretch"}},{class:"wf-grid",base:{display:"grid","grid-template-columns":"var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))"},defaults:{gap:"var(--wf-gap, var(--wf-gap-lg))"}},{class:"wf-center",base:{display:"flex","flex-direction":"column","align-items":"center","justify-content":"center"}},{class:"wf-justify-between",base:{display:"flex","justify-content":"space-between"},defaults:{"align-items":"var(--wf-align, center)",gap:"var(--wf-gap, var(--wf-gap-md))"}},{class:"wf-justify-end",base:{display:"flex","justify-content":"flex-end"},defaults:{"align-items":"var(--wf-align, center)",gap:"var(--wf-gap, var(--wf-gap-md))"}},{class:"wf-justify-center",base:{display:"flex","justify-content":"center"},defaults:{"align-items":"var(--wf-align, center)",gap:"var(--wf-gap, var(--wf-gap-md))"}},{class:"wf-fill",base:{flex:"1","min-width":"0","min-height":"0"}},{class:"wf-fill-hover",base:{"border-radius":"var(--wf-radius-sm)",padding:"2px 4px",margin:"-2px -4px",transition:"background 0.15s ease"}},{class:"wf-cover",base:{position:"fixed",inset:"0",display:"flex","align-items":"center","justify-content":"center","z-index":"var(--wf-z, var(--wf-cover-z))"}}];import{readFile as b,readdir as _}from"node:fs/promises";import{join as p,resolve as h}from"node:path";var k=["tokens","base","layout","components","utilities"],x={_tokens:"tokens",_dark:"tokens",_presets:"tokens",_props:"tokens",_base:"base",_stack:"layout",_row:"layout",_split:"layout",_center:"layout",_justify:"layout",_fill:"layout",_grid:"layout",_cluster:"layout",_cover:"layout",_position:"layout",_sticky:"layout",_overflow:"layout","_safe-area":"layout",_layer:"layout","_align-self":"layout",_nowrap:"layout",_shrink:"layout",_container:"layout","_app-shell":"layout",_surface:"utilities",_spacing:"utilities",_border:"utilities",_text:"utilities",_hidden:"utilities",_block:"utilities",_flex:"utilities",_popup:"layout"},E="tokens",O=a=>a.replace(/@import\s+['"][^'"]+['"]\s*;?\s*\n?/g,"");async function $(a){let t=await b(p(a,"weifuwu-layout.css"),"utf-8"),i=[];for(let e of t.split(`
3
+ `)){let o=e.match(/@import\s+['"]([^'"]+)['"]/);o&&i.push(o[1].replace(/^\.\//,""))}if(!i.length)throw new Error(`layout \u5165\u53E3\u65E0 @import\uFF08${a}/weifuwu-layout.css\uFF09\u2014\u2014\u88C5\u914D\u5355\u6E90\u5931\u6548`);return i}async function L(a){try{let t=await _(a);return t.includes("weifuwu-layout.css")&&t.some(i=>/^_[a-z-]+\.css$/.test(i))}catch{return!1}}async function R(a){let t=h(a),i=await $(t),e=[p(t,"weifuwu-layout.css")],o=[];for(let s of i){if(s==="_stack.css"){e.push(p(t,"decl.ts"),p(t,"define.ts")),o.push(`@layer ${x._stack} {
4
+ ${w(m)}
5
+ }`);continue}if(s==="_row.css")continue;let n=p(t,s);e.push(n);let r=O(await b(n,"utf-8")).trim(),l=s.replace(/\.css$/,""),f=x[l];if(!f)throw new Error(`layout \u6587\u4EF6\u672A\u767B\u8BB0 @layer \u6620\u5C04: ${s}\uFF08\u5728 src/client/layout/bundle.ts LAYER_OF \u4E2D\u767B\u8BB0\uFF09`);o.push(f===E?r:`@layer ${f} {
6
+ ${r}
7
+ }`)}return{css:`/* weifuwu/client/layout \u2014 CSS \u5E03\u5C40\u539F\u8BED + \u8BBE\u8BA1 Token\uFF08\u88C5\u914D\u5355\u6E90\uFF1Asrc/client/layout/bundle.ts\uFF09 */
8
+
9
+ @layer ${k.join(", ")};
10
+
11
+ ${o.join(`
12
+
13
+ `)}
14
+ `,inputs:e}}async function S(a,t){let{css:i,inputs:e}=await R(a),o=h(t),c=(await _(o,{withFileTypes:!0})).filter(n=>n.isDirectory()).map(n=>n.name),s=`${i}@layer components {
15
+ `;for(let n of c){let r=p(o,n,`${n}.css`);try{s+=`${await b(r,"utf-8")}
16
+ `,e.push(r)}catch{}}return s+=`}
17
+ `,{css:s,inputs:e}}function C(a){let t=new Map,i=/\.wf-[a-z0-9]+(?:-[a-z0-9]+)*(?:--[a-z-]+)?/g,e=a.replace(/\/\*[\s\S]*?\*\//g,""),o=(n,r)=>{for(let l of n.matchAll(i)){let f=l[0].slice(1);t.has(f)||t.set(f,r)}},c="",s=0;for(;s<e.length;){let n=e.indexOf("@layer",s);if(n===-1){c+=e.slice(s);break}let r=e.indexOf("{",n),l=e.indexOf(";",n);if(l!==-1&&(r===-1||l<r)){c+=e.slice(s,l+1),s=l+1;continue}if(r===-1){c+=e.slice(s);break}let f=e.slice(n+6,r).trim(),d=0,u=r;for(;u<e.length;u++)if(e[u]==="{")d++;else if(e[u]==="}"&&(d--,d===0)){u++;break}c+=e.slice(s,n),o(e.slice(r+1,u-1),f),s=u}return o(c,"unlayered"),t}export{x as LAYER_OF,k as LAYER_ORDER,S as bundleComponents,R as bundleLayout,w as generateLayoutCss,j as isEquivalent,L as isLayoutSourceDir,C as layerMapOf,$ as layoutEntryFiles,y as parseProps,m as structures};
@@ -1 +1 @@
1
- @layer tokens,base,layout,components,utilities;:root{--wf-brand-seed: #4f6ef7;--wf-brand-500: var(--wf-brand-seed);--wf-brand-600: color-mix(in srgb, var(--wf-brand-seed) 85%, #000);--wf-brand-700: color-mix(in srgb, var(--wf-brand-seed) 70%, #000);--wf-brand-50: color-mix(in srgb, var(--wf-brand-seed) 12%, #fff);--wf-green-500: #22c55e;--wf-green-50: #f0fdf4;--wf-green-700: #15803d;--wf-amber-500: #f59e0b;--wf-amber-50: #fffbeb;--wf-amber-700: #b45309;--wf-red-500: #ef4444;--wf-red-50: #fef2f2;--wf-red-700: #b91c1c;--wf-sky-500: #1677ff;--wf-sky-50: #e6f4ff;--wf-sky-700: #0369a1;--wf-slate-900: #0f172a;--wf-slate-500: #64748b;--wf-slate-400: #94a3b8;--wf-slate-300: #cbd5e1;--wf-slate-200: #e2e8f0;--wf-slate-100: #f1f5f9;--wf-slate-50: #f8fafc;--wf-white: #ffffff;--wf-dark-brand-seed: #6b8aff;--wf-dark-brand-500: var(--wf-dark-brand-seed);--wf-dark-brand-600: color-mix(in srgb, var(--wf-dark-brand-seed) 78%, #fff);--wf-dark-brand-50: color-mix(in srgb, var(--wf-dark-brand-seed) 12%, #0f172a);--wf-dark-green-500: #4ade80;--wf-dark-green-50: #14532d;--wf-dark-amber-500: #fbbf24;--wf-dark-amber-50: #451a03;--wf-dark-red-500: #f87171;--wf-dark-red-50: #451a1a;--wf-dark-sky-500: #60a5fa;--wf-dark-sky-50: #172554;--wf-dark-slate-900: #f1f5f9;--wf-dark-slate-500: #94a3b8;--wf-dark-slate-400: #64748b;--wf-dark-slate-300: #475569;--wf-dark-slate-200: #334155;--wf-dark-slate-100: #1e293b;--wf-dark-bg: #0f172a;--wf-dark-overlay: rgba(0, 0, 0, .6);--wf-dark-fill: var(--wf-dark-slate-200);--wf-dark-bg-hover: var(--wf-dark-state-hover);--wf-dark-state-hover: rgba(255, 255, 255, .06);--wf-dark-state-pressed: rgba(255, 255, 255, .1);--wf-dark-surface-shadow: var(--wf-dark-shadow);--wf-dark-shadow-sm: 0 1px 2px rgba(0, 0, 0, .2);--wf-dark-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .3);--wf-dark-shadow: 0 1px 3px rgba(0, 0, 0, .3);--wf-dark-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--wf-dark-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4)}:root{--wf-space-xs: 4px;--wf-space-sm: 8px;--wf-space: 12px;--wf-space-md: 16px;--wf-space-lg: 24px;--wf-space-xl: 32px;--wf-space-2xl: 40px;--wf-gap-xs: var(--wf-space-xs);--wf-gap-sm: var(--wf-space-sm);--wf-gap-md: var(--wf-space);--wf-gap-lg: var(--wf-space-md);--wf-gap-xl: var(--wf-space-lg);--wf-gap-2xl: var(--wf-space-xl);--wf-radius-xs: 2px;--wf-radius-sm: 4px;--wf-radius: 6px;--wf-radius-md: 8px;--wf-radius-lg: 12px;--wf-radius-xl: 20px;--wf-surface-radius: var(--wf-radius-md);--wf-surface-shadow: var(--wf-shadow);--wf-shadow-sm: 0 1px 2px rgba(0,0,0,.05);--wf-shadow-inset: inset 0 1px 2px rgba(0,0,0,.04);--wf-shadow: 0 1px 3px rgba(0,0,0,.08);--wf-shadow-md: 0 4px 12px rgba(0,0,0,.1);--wf-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1);--wf-z-sticky: 40;--wf-z-overlay: 80;--wf-z-modal: 100;--wf-tour-min-width: 240px;--wf-kanban-col-min-width: 200px;--wf-layout-sider-width: 240px;--wf-layout-sider-collapsed-width: 64px;--wf-layout-header-height: 56px;--wf-kanban-col-max-width: 300px;--wf-treeselect-min-width: 200px;--wf-navmenu-min-width: 160px;--wf-select-menu-min-width: 200px;--wf-treeselect-max-width: 320px;--wf-treeselect-dropdown-max-height: 260px;--wf-z-popover: 120;--wf-z-toast: 140;--wf-z-tooltip: 160;--wf-z-dropdown: var(--wf-z-popover);--wf-pop-z: var(--wf-z-popover);--wf-cover-z: var(--wf-z-modal);--wf-color-primary: var(--wf-brand-500);--wf-color-primary-hover: var(--wf-brand-600);--wf-color-primary-bg: var(--wf-brand-50);--wf-color-success: var(--wf-green-500);--wf-color-success-bg: var(--wf-green-50);--wf-color-warning: var(--wf-amber-500);--wf-color-warning-bg: var(--wf-amber-50);--wf-color-error: var(--wf-red-500);--wf-color-error-bg: var(--wf-red-50);--wf-color-text: var(--wf-slate-900);--wf-color-text-secondary: var(--wf-slate-500);--wf-color-text-tertiary: var(--wf-slate-400);--wf-color-text-disabled: var(--wf-slate-300);--wf-color-bg: var(--wf-white);--wf-color-bg-secondary: var(--wf-slate-50);--wf-color-bg-tertiary: var(--wf-slate-100);--wf-color-border: var(--wf-slate-200);--wf-color-border-light: var(--wf-slate-100);--wf-color-border-dark: var(--wf-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-color-bg-elevated: var(--wf-color-bg);--wf-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;--wf-font-mono: "SF Mono", "Fira Code", "JetBrains Mono", "PingFang SC", "Microsoft YaHei", monospace;--wf-font-size-xs: 12px;--wf-font-size-sm: 13px;--wf-font-size-base: 14px;--wf-font-size-lg: 15px;--wf-font-size-xl: 16px;--wf-font-size-2xl: 21px;--wf-font-size-3xl: 24px;--wf-font-size-4xl: 30px;--wf-font-size-5xl: 36px;--wf-font-size-display: 30px;--wf-heading-case: none;--wf-heading-tracking: 0;--wf-font-weight-normal: 400;--wf-font-weight-medium: 500;--wf-font-weight-semibold: 600;--wf-font-weight-bold: 700;--wf-line-height-tight: 1.25;--wf-line-height: 1.5;--wf-line-height-relaxed: 1.75;--wf-border-width: 1px;--wf-focus-ring: 0 0 0 2px var(--wf-color-primary-bg), 0 0 0 1px var(--wf-color-primary);--wf-transition-duration: var(--wf-dur-fast);--wf-transition-timing: var(--wf-ease-out);--wf-transition: var(--wf-transition-duration) var(--wf-transition-timing);--wf-dur-fast: .12s;--wf-dur-base: .2s;--wf-dur-slow: .3s;--wf-ease-out: cubic-bezier(.16, 1, .3, 1);--wf-ease-in: cubic-bezier(.4, 0, 1, 1);--wf-ease-in-out: cubic-bezier(.4, 0, .2, 1);--wf-ease-snap: cubic-bezier(.34, 1.56, .64, 1);--wf-ease-standard: ease;--wf-dur-md: var(--wf-dur-base);--wf-motion-sm: 4px;--wf-dur-spin: .6s;--wf-dur-pulse: 1.2s;--wf-dur-blink: 1.1s;--wf-dur-progress: 1.4s;--wf-color-info: var(--wf-sky-500);--wf-color-info-bg: var(--wf-sky-50);--wf-color-primary-text: var(--wf-brand-700);--wf-color-success-text: var(--wf-green-700);--wf-color-warning-text: var(--wf-amber-700);--wf-color-error-text: var(--wf-red-700);--wf-color-info-text: var(--wf-sky-700);--wf-color-fill: var(--wf-slate-100);--wf-color-bg-subtle: var(--wf-color-fill);--wf-state-hover: rgba(0, 0, 0, .04);--wf-state-pressed: rgba(0, 0, 0, .08);--wf-color-bg-hover: var(--wf-state-hover);--wf-color-on-brand: #fff;--wf-color-on-warning: #451a03;--wf-overlay: rgba(0, 0, 0, .4);--wf-overlay-blur: 4px;--wf-accent-color: var(--wf-color-primary);--wf-caret-color: var(--wf-color-primary);--wf-control-pad-y: 10px;--wf-control-height: 36px;--wf-field-height: var(--wf-control-height);--wf-field-radius: var(--wf-radius);--wf-bp-sm: 640px;--wf-bp-md: 768px;--wf-bp-lg: 1024px;--wf-bp-xl: 1280px;--wf-sidebar-width: 240px;--wf-opacity-disabled: .5;--wf-letter-spacing-wide: .5px;--wf-heading-display-tracking: -.5px;--wf-nums: "tabular-nums"}@supports not (color: color-mix(in srgb,red 50%,blue)){:root{--wf-brand-600: #3b5ae0;--wf-brand-700: #4338ca;--wf-brand-50: #eef1ff;--wf-dark-brand-600: #8ba3ff;--wf-dark-brand-50: #1e293b}}:root[data-theme=dark]{color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}}:root[data-preset=minimal]{--wf-brand-seed: #64748b;--wf-dark-brand-seed: #94a3b8}:root[data-preset=compact]{--wf-control-height: 32px;--wf-control-pad-y: 6px;--wf-space-xs: 3px;--wf-space-sm: 6px;--wf-space: 9px;--wf-space-md: 12px;--wf-space-lg: 18px;--wf-space-xl: 24px;--wf-space-2xl: 30px;--wf-font-size-sm: 12px;--wf-font-size-base: 13px}:root[data-preset=rounded]{--wf-radius-sm: 8px;--wf-radius: 12px;--wf-radius-md: 16px;--wf-radius-lg: 20px;--wf-radius-xl: 28px;--wf-surface-radius: var(--wf-radius-md);--wf-btn-radius: 999px;--wf-field-radius: var(--wf-radius-md)}@property --wf-gap{syntax: "*"; inherits: false;}@property --wf-align{syntax: "*"; inherits: false;}@property --wf-justify{syntax: "*"; inherits: false;}@property --wf-cols{syntax: "*"; inherits: false;}@property --wf-max{syntax: "*"; inherits: false;}@property --wf-w-sm{syntax: "*"; inherits: false;}@property --wf-z{syntax: "*"; inherits: false;}@property --wf-offset{syntax: "*"; inherits: false;}@property --wf-popup-max{syntax: "*"; inherits: false;}@layer base{*,*:before,*:after{box-sizing:border-box}::selection{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}*{scrollbar-width:thin;scrollbar-color:var(--wf-color-border-dark) transparent}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--wf-color-border-dark);border-radius:var(--wf-radius-sm);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:var(--wf-color-text-secondary);background-clip:padding-box;border:2px solid transparent}:root{color-scheme:light}body{margin:0;background:var(--wf-color-bg);color:var(--wf-color-text);font-family:var(--wf-font-sans);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);-webkit-font-smoothing:antialiased}a{color:var(--wf-color-primary-text);text-decoration:none}a:hover{color:var(--wf-color-primary-hover);text-decoration:underline}input,textarea,select,button{font-family:inherit;font-size:inherit;line-height:inherit}input,textarea,select{accent-color:var(--wf-accent-color);caret-color:var(--wf-caret-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space)}input:focus,textarea:focus,select:focus{outline:none;box-shadow:var(--wf-focus-ring);border-color:var(--wf-color-primary)}input:disabled,textarea:disabled,select:disabled,button:disabled{opacity:var(--wf-opacity-disabled);cursor:not-allowed}button{accent-color:var(--wf-accent-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space-md);min-height:var(--wf-control-height);cursor:pointer;transition:border-color var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),background-color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}button:hover{border-color:var(--wf-color-primary);color:var(--wf-color-primary-text)}button:active:not(:disabled),[role=button]:active{filter:brightness(.95)}button:focus-visible,[tabindex]:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}[role=button]{cursor:pointer;transition:background-color var(--wf-dur-fast) var(--wf-ease-out),border-color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}@media(pointer:coarse){button,[role=button],input,textarea,select,.wf-card--clickable,.wf-table-th--sortable,.wf-accordion-summary,.wf-tag-close,.wf-checkbox,.wf-switch,.wf-radio,.wf-datepicker-cell{min-height:44px;min-width:44px}}h1,h2,h3,h4,h5,h6{font-weight:var(--wf-font-weight-semibold);line-height:var(--wf-line-height-tight);color:var(--wf-color-text)}p{line-height:var(--wf-line-height-relaxed)}small{font-size:var(--wf-font-size-sm);color:var(--wf-color-text-tertiary)}label{font-size:var(--wf-font-size-base);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text)}table{width:100%;border-collapse:collapse}th{text-align:left;font-weight:var(--wf-font-weight-medium);font-size:var(--wf-font-size-xs);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);background:var(--wf-color-bg-secondary)}td{padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);color:var(--wf-color-text);font-size:var(--wf-font-size-base)}hr{border:none;border-top:var(--wf-border-width) solid var(--wf-color-border);margin:var(--wf-space-md) 0}pre,code{font-family:var(--wf-font-mono);font-size:var(--wf-font-size-sm)}pre{background:var(--wf-color-bg-secondary);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-space) var(--wf-space-md);overflow-x:auto;white-space:pre}code{background:var(--wf-color-bg-secondary);padding:2px 6px;border-radius:var(--wf-radius-sm)}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}body.wf-dragging{user-select:none;-webkit-user-select:none}@keyframes wf-stream-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.wf-stream-in{animation:wf-stream-in var(--wf-dur-base) var(--wf-ease-out) both}@media(prefers-reduced-motion:reduce){.wf-stream-in{animation-duration:.01ms}}.wf-hero-cursor{animation:wf-hero-blink 1s step-end infinite;color:var(--wf-color-primary)}@keyframes wf-hero-blink{0%,to{opacity:1}50%{opacity:0}}}@layer layout{.wf-stack{display:flex;flex-direction:column}:where(.wf-stack){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, stretch)}}@layer layout{.wf-row{display:flex;flex-wrap:wrap}:where(.wf-row){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-row-reverse{display:flex;flex-direction:row-reverse;flex-wrap:wrap}:where(.wf-row-reverse){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-items-start{--wf-align: flex-start}.wf-items-center{--wf-align: center}.wf-items-end{--wf-align: flex-end}.wf-items-stretch{--wf-align: stretch}}@layer layout{.wf-split{display:flex;justify-content:space-between}:where(.wf-split){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-split>:last-child{flex-shrink:0}}@layer layout{.wf-center{display:flex;flex-direction:column;align-items:center;justify-content:center}}@layer layout{.wf-justify-between{display:flex;justify-content:space-between}:where(.wf-justify-between){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-end{display:flex;justify-content:flex-end}:where(.wf-justify-end){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-center{display:flex;justify-content:center}:where(.wf-justify-center){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}}@layer layout{.wf-fill{flex:1;min-width:0;min-height:0}.wf-fill-hover{border-radius:var(--wf-radius-sm);padding:2px 4px;margin:-2px -4px;transition:background .15s ease}.wf-fill-hover:hover{background:var(--wf-color-bg-secondary)}}@layer layout{.wf-grid{display:grid;grid-template-columns:var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))}:where(.wf-grid){gap:var(--wf-gap, var(--wf-gap-lg))}}@layer layout{.wf-cluster{display:flex;flex-wrap:wrap}:where(.wf-cluster){gap:var(--wf-gap, var(--wf-gap-sm));justify-content:var(--wf-justify, center);align-items:var(--wf-align, center)}}@layer layout{.wf-cover{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--wf-z, var(--wf-cover-z))}}@layer layout{.wf-relative{position:relative}.wf-absolute{position:absolute}}@layer layout{.wf-sticky{position:sticky;top:var(--wf-offset, 0)}}@layer layout{.wf-overflow-auto{overflow:auto}.wf-overflow-hidden{overflow:hidden}.wf-overflow-x{overflow-x:auto}}@layer layout{.wf-safe-bottom{padding-bottom:env(safe-area-inset-bottom)}.wf-safe-top{padding-top:env(safe-area-inset-top)}}@layer layout{.wf-layer{position:relative;z-index:var(--wf-z, 1)}}@layer layout{.wf-self-start{align-self:flex-start}.wf-self-center{align-self:center}.wf-self-end{align-self:flex-end}.wf-self-stretch{align-self:stretch}}@layer layout{.wf-nowrap{display:flex;flex-wrap:nowrap}:where(.wf-nowrap){gap:var(--wf-gap, var(--wf-gap-md))}}@layer layout{.wf-shrink{min-width:0;min-height:0}.wf-min-width-0{min-width:0}}@layer layout{.wf-container{width:100%;max-width:var(--wf-max, 1200px);margin:0 auto;padding:0 var(--wf-gap, var(--wf-gap-lg))}}@layer layout{.wf-app-shell{display:grid;grid-template-columns:var(--wf-sidebar-width, 240px) minmax(0,1fr);height:100vh;overflow:hidden}.wf-sidebar{display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;background:var(--wf-color-bg-secondary);border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-sidebar-header{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-md);border-bottom:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-sidebar-body{flex:1;padding:var(--wf-space-sm);overflow-y:auto}.wf-sidebar-footer{padding:var(--wf-space-sm);border-top:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-nav{display:flex;flex-direction:column;gap:2px}.wf-nav-group{font-size:var(--wf-font-size-xs);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space-md) var(--wf-space-sm) var(--wf-space-xs)}.wf-nav-item{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-sm) var(--wf-space);border-radius:var(--wf-radius);color:var(--wf-color-text-secondary);font-size:var(--wf-font-size-base);text-decoration:none;cursor:pointer;border:none;background:none;width:100%;text-align:left;font-family:inherit;transition:background var(--wf-transition),color var(--wf-transition)}.wf-nav-item:hover{background:var(--wf-color-bg-tertiary);color:var(--wf-color-text);text-decoration:none}.wf-nav-item:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}.wf-nav-item--active{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text);font-weight:var(--wf-font-weight-medium)}.wf-nav-item--active:hover{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}.wf-nav--collapsed .wf-nav-item{justify-content:center;gap:0;padding:var(--wf-space-sm)}.wf-nav--collapsed .wf-nav-label{display:none}.wf-nav--collapsed .wf-nav-group{text-align:center;padding-left:0;padding-right:0;overflow:hidden;white-space:nowrap}.wf-main{padding:var(--wf-space-lg);min-width:0;min-height:0;overflow-y:auto;background:var(--wf-color-bg);--wf-main-max: none}.wf-main>*{max-width:var(--wf-main-max);margin-inline:auto}@media(pointer:coarse){.wf-nav-item{min-height:44px}}@media(max-width:767.98px){.wf-app-shell{grid-template-columns:1fr;height:auto;overflow:visible}.wf-sidebar{position:static;height:auto;border-right:none;border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-main{padding:var(--wf-space-md);overflow:visible}}}@layer utilities{.wf-surface{border-radius:var(--wf-surface-radius);box-shadow:var(--wf-surface-shadow);background:var(--wf-surface-bg)}.wf-surface--flat{box-shadow:none}.wf-bg-secondary{background:var(--wf-color-bg-secondary)}.wf-bg-tertiary{background:var(--wf-color-bg-tertiary)}.wf-bg-primary{background:var(--wf-color-primary-bg)}.wf-bg-warning{background:var(--wf-color-warning-bg)}.wf-bg-error{background:var(--wf-color-error-bg)}.wf-bg-none{background:transparent}.wf-pill{border-radius:999px}.wf-radius-sm{border-radius:var(--wf-radius-sm)}.wf-radius{border-radius:var(--wf-radius)}.wf-radius-md{border-radius:var(--wf-radius-md)}.wf-radius-lg{border-radius:var(--wf-radius-lg)}.wf-shadow{box-shadow:var(--wf-shadow)}.wf-elevate{transition:box-shadow var(--wf-dur-fast) var(--wf-ease-out),transform var(--wf-dur-fast) var(--wf-ease-out)}.wf-elevate:hover{box-shadow:var(--wf-shadow-md);transform:translateY(-2px)}.wf-elevate:focus-visible{outline:none;box-shadow:var(--wf-shadow-md),var(--wf-focus-ring)}.wf-panel-in{animation:wf-panel-in var(--wf-dur-fast) var(--wf-ease-out);transform-origin:top center}@keyframes wf-panel-in{0%{opacity:0;transform:translateY(calc(var(--wf-motion-sm) * -1)) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.wf-bubble{display:inline-block;max-width:70%;padding:var(--wf-space-sm) var(--wf-space-md);border-radius:var(--wf-radius-md);background:var(--wf-color-bg-secondary);color:var(--wf-color-text);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);white-space:pre-wrap;word-break:break-word}.wf-bubble--own{background:var(--wf-color-primary);color:var(--wf-color-on-brand);border-bottom-right-radius:var(--wf-radius-sm)}.wf-bubble--ai{background:var(--wf-color-primary-bg);border:var(--wf-border-width) solid var(--wf-color-border-light);border-bottom-left-radius:var(--wf-radius-sm)}.wf-rounded-sm{border-radius:var(--wf-radius-sm)}.wf-rounded-md{border-radius:var(--wf-radius-md)}.wf-card-outline{border:var(--wf-border-width) solid var(--wf-color-border)}}@layer utilities{.wf-border{border:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-top{border-top:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-bottom{border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-left{border-left:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-right{border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-none{border:none}}@layer utilities{.wf-text-left{text-align:left}.wf-text-center{text-align:center}.wf-text-right{text-align:right}.wf-font-xs{font-size:var(--wf-font-size-xs)}.wf-font-sm{font-size:var(--wf-font-size-sm)}.wf-font-base{font-size:var(--wf-font-size-base)}.wf-font-lg{font-size:var(--wf-font-size-lg)}.wf-font-2xl{font-size:var(--wf-font-size-2xl)}.wf-font-3xl{font-size:var(--wf-font-size-3xl)}.wf-font-4xl{font-size:var(--wf-font-size-4xl)}.wf-nums{font-variant-numeric:var(--wf-nums)}.wf-text-secondary{color:var(--wf-color-text-secondary)}.wf-text-tertiary{color:var(--wf-color-text-tertiary)}.wf-text-danger{color:var(--wf-color-error-text)}.wf-text-primary{color:var(--wf-color-primary-text)}.wf-text-success{color:var(--wf-color-success-text)}.wf-text-warning{color:var(--wf-color-warning-text)}.wf-font-mono{font-family:var(--wf-font-mono)}.wf-text-error{color:var(--wf-color-error-text)}.wf-text-on-brand{color:var(--wf-color-on-brand)}.wf-text-on-warning{color:var(--wf-color-on-warning)}.wf-medium{font-weight:var(--wf-font-weight-medium)}.wf-semibold{font-weight:var(--wf-font-weight-semibold)}.wf-bold{font-weight:var(--wf-font-weight-bold)}.wf-tracking-wide{letter-spacing:var(--wf-letter-spacing-wide)}.wf-uppercase{text-transform:uppercase}.wf-pre-wrap{white-space:pre-wrap;word-break:break-word}.wf-break-word{overflow-wrap:break-word;word-break:break-word}.wf-text-nowrap{white-space:nowrap}.wf-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}@layer utilities{.wf-padding-none{padding:0}.wf-padding-xs{padding:var(--wf-space-xs)}.wf-padding-sm{padding:var(--wf-space-sm)}.wf-padding-md{padding:var(--wf-space-md)}.wf-padding-lg{padding:var(--wf-space-lg)}.wf-padding-xl{padding:var(--wf-space-xl)}.wf-padding-x-xs{padding-left:var(--wf-space-xs);padding-right:var(--wf-space-xs)}.wf-padding-x-sm{padding-left:var(--wf-space-sm);padding-right:var(--wf-space-sm)}.wf-padding-x-md{padding-left:var(--wf-space-md);padding-right:var(--wf-space-md)}.wf-padding-y-xs{padding-top:var(--wf-space-xs);padding-bottom:var(--wf-space-xs)}.wf-padding-y-sm{padding-top:var(--wf-space-sm);padding-bottom:var(--wf-space-sm)}.wf-padding-y-md{padding-top:var(--wf-space-md);padding-bottom:var(--wf-space-md)}.wf-padding-y-lg{padding-top:var(--wf-space-lg);padding-bottom:var(--wf-space-lg)}.wf-padding-top-sm{padding-top:var(--wf-space-sm)}.wf-padding-left-sm{padding-left:var(--wf-space-sm)}.wf-padding-bottom-xs{padding-bottom:var(--wf-space-xs)}.wf-padding-bottom-sm{padding-bottom:var(--wf-space-sm)}.wf-padding-bottom-md{padding-bottom:var(--wf-space-md)}.wf-margin-none{margin:0}.wf-margin-top-none{margin-top:0}.wf-margin-top-xs{margin-top:var(--wf-space-xs)}.wf-margin-top-sm{margin-top:var(--wf-space-sm)}.wf-margin-top-md{margin-top:var(--wf-space-md)}.wf-margin-bottom-xs{margin-bottom:var(--wf-space-xs)}.wf-margin-bottom-sm{margin-bottom:var(--wf-space-sm)}.wf-margin-bottom-md{margin-bottom:var(--wf-space-md)}.wf-margin-bottom-lg{margin-bottom:var(--wf-space-lg)}.wf-margin-left-xs{margin-left:var(--wf-space-xs)}.wf-margin-left-sm{margin-left:var(--wf-space-sm)}.wf-margin-x-auto{margin-left:auto;margin-right:auto}.wf-margin-y-xs{margin-top:var(--wf-space-xs);margin-bottom:var(--wf-space-xs)}.wf-gap-none{gap:0}.wf-gap-xs{gap:var(--wf-gap-xs)}.wf-gap-sm{gap:var(--wf-gap-sm)}.wf-gap-md{gap:var(--wf-gap-md)}.wf-gap-lg{gap:var(--wf-gap-lg)}.wf-gap-xl{gap:var(--wf-gap-xl)}.wf-width-full{width:100%}.wf-width-sm{width:var(--wf-w-sm, 480px)}.wf-height-full{height:100%}}@layer utilities{:where(.wf-block){display:block}}@layer utilities{:where(.wf-flex){display:flex}@media(min-width:640px){.wf-flex\@sm{display:flex}}@media(min-width:1024px){.wf-flex\@lg{display:flex}}}@layer utilities{:where(.wf-hidden){display:none}@media(min-width:1024px){.wf-hidden\@lg{display:none}}.wf-dim{opacity:.7}.wf-pointer{cursor:pointer}}@layer layout{.wf-popup{max-width:min(var(--wf-popup-max, 480px),calc(100vw - 32px));box-sizing:border-box}.wf-popup-mask{position:fixed;inset:0;z-index:var(--wf-z-overlay);background:var(--wf-overlay)}}
1
+ @layer tokens,base,layout,components,utilities;@layer layout{.wf-stack{display:flex;flex-direction:column}:where(.wf-stack){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, stretch)}.wf-row{display:flex;flex-wrap:wrap}:where(.wf-row){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-row-reverse{display:flex;flex-wrap:wrap;flex-direction:row-reverse}:where(.wf-row-reverse){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-items-start{--wf-align: flex-start}.wf-items-center{--wf-align: center}.wf-items-end{--wf-align: flex-end}.wf-items-stretch{--wf-align: stretch}.wf-grid{display:grid;grid-template-columns:var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))}:where(.wf-grid){gap:var(--wf-gap, var(--wf-gap-lg))}.wf-center{display:flex;flex-direction:column;align-items:center;justify-content:center}.wf-justify-between{display:flex;justify-content:space-between}:where(.wf-justify-between){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-end{display:flex;justify-content:flex-end}:where(.wf-justify-end){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-center{display:flex;justify-content:center}:where(.wf-justify-center){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-fill{flex:1;min-width:0;min-height:0}.wf-fill-hover{border-radius:var(--wf-radius-sm);padding:2px 4px;margin:-2px -4px;transition:background .15s ease}.wf-cover{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--wf-z, var(--wf-cover-z))}}:root{--wf-brand-seed: #4f6ef7;--wf-brand-500: var(--wf-brand-seed);--wf-brand-600: color-mix(in srgb, var(--wf-brand-seed) 85%, #000);--wf-brand-700: color-mix(in srgb, var(--wf-brand-seed) 70%, #000);--wf-brand-50: color-mix(in srgb, var(--wf-brand-seed) 12%, #fff);--wf-green-500: #22c55e;--wf-green-50: #f0fdf4;--wf-green-700: #15803d;--wf-amber-500: #f59e0b;--wf-amber-50: #fffbeb;--wf-amber-700: #b45309;--wf-red-500: #ef4444;--wf-red-50: #fef2f2;--wf-red-700: #b91c1c;--wf-sky-500: #1677ff;--wf-sky-50: #e6f4ff;--wf-sky-700: #0369a1;--wf-slate-900: #0f172a;--wf-slate-500: #64748b;--wf-slate-400: #94a3b8;--wf-slate-300: #cbd5e1;--wf-slate-200: #e2e8f0;--wf-slate-100: #f1f5f9;--wf-slate-50: #f8fafc;--wf-white: #ffffff;--wf-dark-brand-seed: #6b8aff;--wf-dark-brand-500: var(--wf-dark-brand-seed);--wf-dark-brand-600: color-mix(in srgb, var(--wf-dark-brand-seed) 78%, #fff);--wf-dark-brand-50: color-mix(in srgb, var(--wf-dark-brand-seed) 12%, #0f172a);--wf-dark-green-500: #4ade80;--wf-dark-green-50: #14532d;--wf-dark-amber-500: #fbbf24;--wf-dark-amber-50: #451a03;--wf-dark-red-500: #f87171;--wf-dark-red-50: #451a1a;--wf-dark-sky-500: #60a5fa;--wf-dark-sky-50: #172554;--wf-dark-slate-900: #f1f5f9;--wf-dark-slate-500: #94a3b8;--wf-dark-slate-400: #64748b;--wf-dark-slate-300: #475569;--wf-dark-slate-200: #334155;--wf-dark-slate-100: #1e293b;--wf-dark-bg: #0f172a;--wf-dark-overlay: rgba(0, 0, 0, .6);--wf-dark-fill: var(--wf-dark-slate-200);--wf-dark-bg-hover: var(--wf-dark-state-hover);--wf-dark-state-hover: rgba(255, 255, 255, .06);--wf-dark-state-pressed: rgba(255, 255, 255, .1);--wf-dark-surface-shadow: var(--wf-dark-shadow);--wf-dark-shadow-sm: 0 1px 2px rgba(0, 0, 0, .2);--wf-dark-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .3);--wf-dark-shadow: 0 1px 3px rgba(0, 0, 0, .3);--wf-dark-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--wf-dark-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .4)}:root{--wf-space-xs: 4px;--wf-space-sm: 8px;--wf-space: 12px;--wf-space-md: 16px;--wf-space-lg: 24px;--wf-space-xl: 32px;--wf-space-2xl: 40px;--wf-gap-xs: var(--wf-space-xs);--wf-gap-sm: var(--wf-space-sm);--wf-gap-md: var(--wf-space);--wf-gap-lg: var(--wf-space-md);--wf-gap-xl: var(--wf-space-lg);--wf-gap-2xl: var(--wf-space-xl);--wf-radius-xs: 2px;--wf-radius-sm: 4px;--wf-radius: 6px;--wf-radius-md: 8px;--wf-radius-lg: 12px;--wf-radius-xl: 20px;--wf-surface-radius: var(--wf-radius-md);--wf-surface-shadow: var(--wf-shadow);--wf-shadow-sm: 0 1px 2px rgba(0,0,0,.05);--wf-shadow-inset: inset 0 1px 2px rgba(0,0,0,.04);--wf-shadow: 0 1px 3px rgba(0,0,0,.08);--wf-shadow-md: 0 4px 12px rgba(0,0,0,.1);--wf-shadow-lg: 0 10px 15px -3px rgba(0,0,0,.1);--wf-z-sticky: 40;--wf-z-overlay: 80;--wf-z-modal: 100;--wf-tour-min-width: 240px;--wf-kanban-col-min-width: 200px;--wf-layout-sider-width: 240px;--wf-layout-sider-collapsed-width: 64px;--wf-layout-header-height: 56px;--wf-kanban-col-max-width: 300px;--wf-treeselect-min-width: 200px;--wf-navmenu-min-width: 160px;--wf-select-menu-min-width: 200px;--wf-treeselect-max-width: 320px;--wf-treeselect-dropdown-max-height: 260px;--wf-z-popover: 120;--wf-z-toast: 140;--wf-z-tooltip: 160;--wf-z-dropdown: var(--wf-z-popover);--wf-pop-z: var(--wf-z-popover);--wf-cover-z: var(--wf-z-modal);--wf-color-primary: var(--wf-brand-500);--wf-color-primary-hover: var(--wf-brand-600);--wf-color-primary-bg: var(--wf-brand-50);--wf-color-success: var(--wf-green-500);--wf-color-success-bg: var(--wf-green-50);--wf-color-warning: var(--wf-amber-500);--wf-color-warning-bg: var(--wf-amber-50);--wf-color-error: var(--wf-red-500);--wf-color-error-bg: var(--wf-red-50);--wf-color-text: var(--wf-slate-900);--wf-color-text-secondary: var(--wf-slate-500);--wf-color-text-tertiary: var(--wf-slate-400);--wf-color-text-disabled: var(--wf-slate-300);--wf-color-bg: var(--wf-white);--wf-color-bg-secondary: var(--wf-slate-50);--wf-color-bg-tertiary: var(--wf-slate-100);--wf-color-border: var(--wf-slate-200);--wf-color-border-light: var(--wf-slate-100);--wf-color-border-dark: var(--wf-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-color-bg-elevated: var(--wf-color-bg);--wf-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif;--wf-font-mono: "SF Mono", "Fira Code", "JetBrains Mono", "PingFang SC", "Microsoft YaHei", monospace;--wf-font-size-xs: 12px;--wf-font-size-sm: 13px;--wf-font-size-base: 14px;--wf-font-size-lg: 15px;--wf-font-size-xl: 16px;--wf-font-size-2xl: 21px;--wf-font-size-3xl: 24px;--wf-font-size-4xl: 30px;--wf-font-size-5xl: 36px;--wf-font-size-display: 30px;--wf-heading-case: none;--wf-heading-tracking: 0;--wf-font-weight-normal: 400;--wf-font-weight-medium: 500;--wf-font-weight-semibold: 600;--wf-font-weight-bold: 700;--wf-line-height-tight: 1.25;--wf-line-height: 1.5;--wf-line-height-relaxed: 1.75;--wf-border-width: 1px;--wf-focus-ring: 0 0 0 2px var(--wf-color-primary-bg), 0 0 0 1px var(--wf-color-primary);--wf-transition-duration: var(--wf-dur-fast);--wf-transition-timing: var(--wf-ease-out);--wf-transition: var(--wf-transition-duration) var(--wf-transition-timing);--wf-dur-fast: .12s;--wf-dur-base: .2s;--wf-dur-slow: .3s;--wf-ease-out: cubic-bezier(.16, 1, .3, 1);--wf-ease-in: cubic-bezier(.4, 0, 1, 1);--wf-ease-in-out: cubic-bezier(.4, 0, .2, 1);--wf-ease-snap: cubic-bezier(.34, 1.56, .64, 1);--wf-ease-standard: ease;--wf-dur-md: var(--wf-dur-base);--wf-motion-sm: 4px;--wf-dur-spin: .6s;--wf-dur-pulse: 1.2s;--wf-dur-blink: 1.1s;--wf-dur-progress: 1.4s;--wf-color-info: var(--wf-sky-500);--wf-color-info-bg: var(--wf-sky-50);--wf-color-primary-text: var(--wf-brand-700);--wf-color-success-text: var(--wf-green-700);--wf-color-warning-text: var(--wf-amber-700);--wf-color-error-text: var(--wf-red-700);--wf-color-info-text: var(--wf-sky-700);--wf-color-fill: var(--wf-slate-100);--wf-color-bg-subtle: var(--wf-color-fill);--wf-state-hover: rgba(0, 0, 0, .04);--wf-state-pressed: rgba(0, 0, 0, .08);--wf-color-bg-hover: var(--wf-state-hover);--wf-color-on-brand: #fff;--wf-color-on-warning: #451a03;--wf-overlay: rgba(0, 0, 0, .4);--wf-overlay-blur: 4px;--wf-accent-color: var(--wf-color-primary);--wf-caret-color: var(--wf-color-primary);--wf-control-pad-y: 10px;--wf-control-height: 36px;--wf-field-height: var(--wf-control-height);--wf-field-radius: var(--wf-radius);--wf-bp-sm: 640px;--wf-bp-md: 768px;--wf-bp-lg: 1024px;--wf-bp-xl: 1280px;--wf-sidebar-width: 240px;--wf-opacity-disabled: .5;--wf-letter-spacing-wide: .5px;--wf-heading-display-tracking: -.5px;--wf-nums: "tabular-nums"}@supports not (color: color-mix(in srgb,red 50%,blue)){:root{--wf-brand-600: #3b5ae0;--wf-brand-700: #4338ca;--wf-brand-50: #eef1ff;--wf-dark-brand-600: #8ba3ff;--wf-dark-brand-50: #1e293b}}:root[data-theme=dark]{color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--wf-color-primary: var(--wf-dark-brand-500);--wf-color-primary-hover: var(--wf-dark-brand-600);--wf-color-primary-bg: var(--wf-dark-brand-50);--wf-color-success: var(--wf-dark-green-500);--wf-color-success-bg: var(--wf-dark-green-50);--wf-color-warning: var(--wf-dark-amber-500);--wf-color-warning-bg: var(--wf-dark-amber-50);--wf-color-error: var(--wf-dark-red-500);--wf-color-error-bg: var(--wf-dark-red-50);--wf-color-info: var(--wf-dark-sky-500);--wf-color-info-bg: var(--wf-dark-sky-50);--wf-color-text: var(--wf-dark-slate-900);--wf-color-text-secondary: var(--wf-dark-slate-500);--wf-color-text-tertiary: var(--wf-dark-slate-400);--wf-color-text-disabled: var(--wf-dark-slate-300);--wf-color-bg: var(--wf-dark-bg);--wf-color-bg-secondary: var(--wf-dark-slate-100);--wf-color-bg-tertiary: var(--wf-dark-slate-200);--wf-color-fill: var(--wf-dark-fill);--wf-color-bg-subtle: var(--wf-dark-fill);--wf-color-bg-hover: var(--wf-dark-bg-hover);--wf-state-hover: var(--wf-dark-state-hover);--wf-state-pressed: var(--wf-dark-state-pressed);--wf-color-bg-elevated: var(--wf-dark-slate-100);--wf-color-border: var(--wf-dark-slate-200);--wf-color-border-light: var(--wf-dark-slate-100);--wf-color-border-dark: var(--wf-dark-slate-300);--wf-surface-bg: var(--wf-color-bg);--wf-surface-shadow: var(--wf-dark-surface-shadow);--wf-shadow-sm: var(--wf-dark-shadow-sm);--wf-shadow: var(--wf-dark-shadow);--wf-shadow-md: var(--wf-dark-shadow-md);--wf-shadow-lg: var(--wf-dark-shadow-lg);--wf-shadow-inset: var(--wf-dark-shadow-inset);--wf-color-primary-text: var(--wf-dark-brand-500);--wf-color-success-text: var(--wf-dark-green-500);--wf-color-warning-text: var(--wf-dark-amber-500);--wf-color-error-text: var(--wf-dark-red-500);--wf-color-info-text: var(--wf-dark-sky-500);--wf-overlay: var(--wf-dark-overlay)}}:root[data-preset=minimal]{--wf-brand-seed: #64748b;--wf-dark-brand-seed: #94a3b8}:root[data-preset=compact]{--wf-control-height: 32px;--wf-control-pad-y: 6px;--wf-space-xs: 3px;--wf-space-sm: 6px;--wf-space: 9px;--wf-space-md: 12px;--wf-space-lg: 18px;--wf-space-xl: 24px;--wf-space-2xl: 30px;--wf-font-size-sm: 12px;--wf-font-size-base: 13px}:root[data-preset=rounded]{--wf-radius-sm: 8px;--wf-radius: 12px;--wf-radius-md: 16px;--wf-radius-lg: 20px;--wf-radius-xl: 28px;--wf-surface-radius: var(--wf-radius-md);--wf-btn-radius: 999px;--wf-field-radius: var(--wf-radius-md)}@property --wf-gap{syntax: "*"; inherits: false;}@property --wf-align{syntax: "*"; inherits: false;}@property --wf-justify{syntax: "*"; inherits: false;}@property --wf-cols{syntax: "*"; inherits: false;}@property --wf-max{syntax: "*"; inherits: false;}@property --wf-w-sm{syntax: "*"; inherits: false;}@property --wf-z{syntax: "*"; inherits: false;}@property --wf-offset{syntax: "*"; inherits: false;}@property --wf-popup-max{syntax: "*"; inherits: false;}@layer base{*,*:before,*:after{box-sizing:border-box}::selection{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}*{scrollbar-width:thin;scrollbar-color:var(--wf-color-border-dark) transparent}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--wf-color-border-dark);border-radius:var(--wf-radius-sm);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:var(--wf-color-text-secondary);background-clip:padding-box;border:2px solid transparent}:root{color-scheme:light}body{margin:0;background:var(--wf-color-bg);color:var(--wf-color-text);font-family:var(--wf-font-sans);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);-webkit-font-smoothing:antialiased}a{color:var(--wf-color-primary-text);text-decoration:none}a:hover{color:var(--wf-color-primary-hover);text-decoration:underline}input,textarea,select,button{font-family:inherit;font-size:inherit;line-height:inherit}input,textarea,select{accent-color:var(--wf-accent-color);caret-color:var(--wf-caret-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space)}input:focus,textarea:focus,select:focus{outline:none;box-shadow:var(--wf-focus-ring);border-color:var(--wf-color-primary)}input:disabled,textarea:disabled,select:disabled,button:disabled{opacity:var(--wf-opacity-disabled);cursor:not-allowed}button{accent-color:var(--wf-accent-color);background:var(--wf-color-bg);color:var(--wf-color-text);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-control-pad-y) var(--wf-space-md);min-height:var(--wf-control-height);cursor:pointer;transition:border-color var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),background-color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}button:hover{border-color:var(--wf-color-primary);color:var(--wf-color-primary-text)}button:active:not(:disabled),[role=button]:active{filter:brightness(.95)}button:focus-visible,[tabindex]:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}[role=button]{cursor:pointer;transition:background-color var(--wf-dur-fast) var(--wf-ease-out),border-color var(--wf-dur-fast) var(--wf-ease-out),box-shadow var(--wf-dur-fast) var(--wf-ease-out),color var(--wf-dur-fast) var(--wf-ease-out),filter var(--wf-dur-fast) var(--wf-ease-out)}@media(pointer:coarse){button,[role=button],input,textarea,select,.wf-card--clickable,.wf-table-th--sortable,.wf-accordion-summary,.wf-tag-close,.wf-checkbox,.wf-switch,.wf-radio,.wf-datepicker-cell{min-height:44px;min-width:44px}}h1,h2,h3,h4,h5,h6{font-weight:var(--wf-font-weight-semibold);line-height:var(--wf-line-height-tight);color:var(--wf-color-text)}p{line-height:var(--wf-line-height-relaxed)}small{font-size:var(--wf-font-size-sm);color:var(--wf-color-text-tertiary)}label{font-size:var(--wf-font-size-base);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text)}table{width:100%;border-collapse:collapse}th{text-align:left;font-weight:var(--wf-font-weight-medium);font-size:var(--wf-font-size-xs);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);background:var(--wf-color-bg-secondary)}td{padding:var(--wf-space) var(--wf-space-sm);border-bottom:var(--wf-border-width) solid var(--wf-color-border);color:var(--wf-color-text);font-size:var(--wf-font-size-base)}hr{border:none;border-top:var(--wf-border-width) solid var(--wf-color-border);margin:var(--wf-space-md) 0}pre,code{font-family:var(--wf-font-mono);font-size:var(--wf-font-size-sm)}pre{background:var(--wf-color-bg-secondary);border:var(--wf-border-width) solid var(--wf-color-border);border-radius:var(--wf-radius);padding:var(--wf-space) var(--wf-space-md);overflow-x:auto;white-space:pre}code{background:var(--wf-color-bg-secondary);padding:2px 6px;border-radius:var(--wf-radius-sm)}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}body.wf-dragging{user-select:none;-webkit-user-select:none}@keyframes wf-stream-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.wf-stream-in{animation:wf-stream-in var(--wf-dur-base) var(--wf-ease-out) both}@media(prefers-reduced-motion:reduce){.wf-stream-in{animation-duration:.01ms}}.wf-hero-cursor{animation:wf-hero-blink 1s step-end infinite;color:var(--wf-color-primary)}@keyframes wf-hero-blink{0%,to{opacity:1}50%{opacity:0}}}@layer layout{.wf-stack{display:flex;flex-direction:column}:where(.wf-stack){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, stretch)}.wf-row{display:flex;flex-wrap:wrap}:where(.wf-row){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-row-reverse{display:flex;flex-wrap:wrap;flex-direction:row-reverse}:where(.wf-row-reverse){gap:var(--wf-gap, var(--wf-gap-md));align-items:var(--wf-align, center)}.wf-items-start{--wf-align: flex-start}.wf-items-center{--wf-align: center}.wf-items-end{--wf-align: flex-end}.wf-items-stretch{--wf-align: stretch}.wf-grid{display:grid;grid-template-columns:var(--wf-cols, repeat(auto-fill, minmax(280px, 1fr)))}:where(.wf-grid){gap:var(--wf-gap, var(--wf-gap-lg))}.wf-center{display:flex;flex-direction:column;align-items:center;justify-content:center}.wf-justify-between{display:flex;justify-content:space-between}:where(.wf-justify-between){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-end{display:flex;justify-content:flex-end}:where(.wf-justify-end){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-justify-center{display:flex;justify-content:center}:where(.wf-justify-center){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-fill{flex:1;min-width:0;min-height:0}.wf-fill-hover{border-radius:var(--wf-radius-sm);padding:2px 4px;margin:-2px -4px;transition:background .15s ease}.wf-cover{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:var(--wf-z, var(--wf-cover-z))}}@layer layout{.wf-split{display:flex;justify-content:space-between}:where(.wf-split){align-items:var(--wf-align, center);gap:var(--wf-gap, var(--wf-gap-md))}.wf-split>:last-child{flex-shrink:0}}@layer layout{.wf-cluster{display:flex;flex-wrap:wrap}:where(.wf-cluster){gap:var(--wf-gap, var(--wf-gap-sm));justify-content:var(--wf-justify, center);align-items:var(--wf-align, center)}}@layer layout{.wf-relative{position:relative}.wf-absolute{position:absolute}}@layer layout{.wf-sticky{position:sticky;top:var(--wf-offset, 0)}}@layer layout{.wf-overflow-auto{overflow:auto}.wf-overflow-hidden{overflow:hidden}.wf-overflow-x{overflow-x:auto}}@layer layout{.wf-safe-bottom{padding-bottom:env(safe-area-inset-bottom)}.wf-safe-top{padding-top:env(safe-area-inset-top)}}@layer layout{.wf-layer{position:relative;z-index:var(--wf-z, 1)}}@layer layout{.wf-self-start{align-self:flex-start}.wf-self-center{align-self:center}.wf-self-end{align-self:flex-end}.wf-self-stretch{align-self:stretch}}@layer layout{.wf-nowrap{display:flex;flex-wrap:nowrap}:where(.wf-nowrap){gap:var(--wf-gap, var(--wf-gap-md))}}@layer layout{.wf-shrink{min-width:0;min-height:0}.wf-min-width-0{min-width:0}}@layer layout{.wf-container{width:100%;max-width:var(--wf-max, 1200px);margin:0 auto;padding:0 var(--wf-gap, var(--wf-gap-lg))}}@layer layout{.wf-app-shell{display:grid;grid-template-columns:var(--wf-sidebar-width, 240px) minmax(0,1fr);height:100vh;overflow:hidden}.wf-sidebar{display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;background:var(--wf-color-bg-secondary);border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-sidebar-header{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-md);border-bottom:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-sidebar-body{flex:1;padding:var(--wf-space-sm);overflow-y:auto}.wf-sidebar-footer{padding:var(--wf-space-sm);border-top:var(--wf-border-width) solid var(--wf-color-border-light);flex-shrink:0}.wf-nav{display:flex;flex-direction:column;gap:2px}.wf-nav-group{font-size:var(--wf-font-size-xs);font-weight:var(--wf-font-weight-medium);color:var(--wf-color-text-tertiary);text-transform:var(--wf-heading-case);letter-spacing:var(--wf-heading-tracking);padding:var(--wf-space-md) var(--wf-space-sm) var(--wf-space-xs)}.wf-nav-item{display:flex;align-items:center;gap:var(--wf-gap-sm);padding:var(--wf-space-sm) var(--wf-space);border-radius:var(--wf-radius);color:var(--wf-color-text-secondary);font-size:var(--wf-font-size-base);text-decoration:none;cursor:pointer;border:none;background:none;width:100%;text-align:left;font-family:inherit;transition:background var(--wf-transition),color var(--wf-transition)}.wf-nav-item:hover{background:var(--wf-color-bg-tertiary);color:var(--wf-color-text);text-decoration:none}.wf-nav-item:focus-visible{outline:none;box-shadow:var(--wf-focus-ring)}.wf-nav-item--active{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text);font-weight:var(--wf-font-weight-medium)}.wf-nav-item--active:hover{background:var(--wf-color-primary-bg);color:var(--wf-color-primary-text)}.wf-nav--collapsed .wf-nav-item{justify-content:center;gap:0;padding:var(--wf-space-sm)}.wf-nav--collapsed .wf-nav-label{display:none}.wf-nav--collapsed .wf-nav-group{text-align:center;padding-left:0;padding-right:0;overflow:hidden;white-space:nowrap}.wf-main{padding:var(--wf-space-lg);min-width:0;min-height:0;overflow-y:auto;background:var(--wf-color-bg);--wf-main-max: none}.wf-main>*{max-width:var(--wf-main-max);margin-inline:auto}@media(pointer:coarse){.wf-nav-item{min-height:44px}}@media(max-width:767.98px){.wf-app-shell{grid-template-columns:1fr;height:auto;overflow:visible}.wf-sidebar{position:static;height:auto;border-right:none;border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-main{padding:var(--wf-space-md);overflow:visible}}}@layer utilities{.wf-surface{border-radius:var(--wf-surface-radius);box-shadow:var(--wf-surface-shadow);background:var(--wf-surface-bg)}.wf-surface--flat{box-shadow:none}.wf-bg-secondary{background:var(--wf-color-bg-secondary)}.wf-bg-tertiary{background:var(--wf-color-bg-tertiary)}.wf-bg-primary{background:var(--wf-color-primary-bg)}.wf-bg-warning{background:var(--wf-color-warning-bg)}.wf-bg-error{background:var(--wf-color-error-bg)}.wf-bg-none{background:transparent}.wf-pill{border-radius:999px}.wf-radius-sm{border-radius:var(--wf-radius-sm)}.wf-radius{border-radius:var(--wf-radius)}.wf-radius-md{border-radius:var(--wf-radius-md)}.wf-radius-lg{border-radius:var(--wf-radius-lg)}.wf-shadow{box-shadow:var(--wf-shadow)}.wf-elevate{transition:box-shadow var(--wf-dur-fast) var(--wf-ease-out),transform var(--wf-dur-fast) var(--wf-ease-out)}.wf-elevate:hover{box-shadow:var(--wf-shadow-md);transform:translateY(-2px)}.wf-elevate:focus-visible{outline:none;box-shadow:var(--wf-shadow-md),var(--wf-focus-ring)}.wf-panel-in{animation:wf-panel-in var(--wf-dur-fast) var(--wf-ease-out);transform-origin:top center}@keyframes wf-panel-in{0%{opacity:0;transform:translateY(calc(var(--wf-motion-sm) * -1)) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.wf-bubble{display:inline-block;max-width:70%;padding:var(--wf-space-sm) var(--wf-space-md);border-radius:var(--wf-radius-md);background:var(--wf-color-bg-secondary);color:var(--wf-color-text);font-size:var(--wf-font-size-base);line-height:var(--wf-line-height);white-space:pre-wrap;word-break:break-word}.wf-bubble--own{background:var(--wf-color-primary);color:var(--wf-color-on-brand);border-bottom-right-radius:var(--wf-radius-sm)}.wf-bubble--ai{background:var(--wf-color-primary-bg);border:var(--wf-border-width) solid var(--wf-color-border-light);border-bottom-left-radius:var(--wf-radius-sm)}.wf-rounded-sm{border-radius:var(--wf-radius-sm)}.wf-rounded-md{border-radius:var(--wf-radius-md)}.wf-card-outline{border:var(--wf-border-width) solid var(--wf-color-border)}}@layer utilities{.wf-border{border:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-top{border-top:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-bottom{border-bottom:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-left{border-left:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-right{border-right:var(--wf-border-width) solid var(--wf-color-border)}.wf-border-none{border:none}}@layer utilities{.wf-text-left{text-align:left}.wf-text-center{text-align:center}.wf-text-right{text-align:right}.wf-font-xs{font-size:var(--wf-font-size-xs)}.wf-font-sm{font-size:var(--wf-font-size-sm)}.wf-font-base{font-size:var(--wf-font-size-base)}.wf-font-lg{font-size:var(--wf-font-size-lg)}.wf-font-2xl{font-size:var(--wf-font-size-2xl)}.wf-font-3xl{font-size:var(--wf-font-size-3xl)}.wf-font-4xl{font-size:var(--wf-font-size-4xl)}.wf-nums{font-variant-numeric:var(--wf-nums)}.wf-text-secondary{color:var(--wf-color-text-secondary)}.wf-text-tertiary{color:var(--wf-color-text-tertiary)}.wf-text-danger{color:var(--wf-color-error-text)}.wf-text-primary{color:var(--wf-color-primary-text)}.wf-text-success{color:var(--wf-color-success-text)}.wf-text-warning{color:var(--wf-color-warning-text)}.wf-font-mono{font-family:var(--wf-font-mono)}.wf-text-error{color:var(--wf-color-error-text)}.wf-text-on-brand{color:var(--wf-color-on-brand)}.wf-text-on-warning{color:var(--wf-color-on-warning)}.wf-medium{font-weight:var(--wf-font-weight-medium)}.wf-semibold{font-weight:var(--wf-font-weight-semibold)}.wf-bold{font-weight:var(--wf-font-weight-bold)}.wf-tracking-wide{letter-spacing:var(--wf-letter-spacing-wide)}.wf-uppercase{text-transform:uppercase}.wf-pre-wrap{white-space:pre-wrap;word-break:break-word}.wf-break-word{overflow-wrap:break-word;word-break:break-word}.wf-text-nowrap{white-space:nowrap}.wf-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}@layer utilities{.wf-padding-none{padding:0}.wf-padding-xs{padding:var(--wf-space-xs)}.wf-padding-sm{padding:var(--wf-space-sm)}.wf-padding-md{padding:var(--wf-space-md)}.wf-padding-lg{padding:var(--wf-space-lg)}.wf-padding-xl{padding:var(--wf-space-xl)}.wf-padding-x-xs{padding-left:var(--wf-space-xs);padding-right:var(--wf-space-xs)}.wf-padding-x-sm{padding-left:var(--wf-space-sm);padding-right:var(--wf-space-sm)}.wf-padding-x-md{padding-left:var(--wf-space-md);padding-right:var(--wf-space-md)}.wf-padding-y-xs{padding-top:var(--wf-space-xs);padding-bottom:var(--wf-space-xs)}.wf-padding-y-sm{padding-top:var(--wf-space-sm);padding-bottom:var(--wf-space-sm)}.wf-padding-y-md{padding-top:var(--wf-space-md);padding-bottom:var(--wf-space-md)}.wf-padding-y-lg{padding-top:var(--wf-space-lg);padding-bottom:var(--wf-space-lg)}.wf-padding-top-sm{padding-top:var(--wf-space-sm)}.wf-padding-left-sm{padding-left:var(--wf-space-sm)}.wf-padding-bottom-xs{padding-bottom:var(--wf-space-xs)}.wf-padding-bottom-sm{padding-bottom:var(--wf-space-sm)}.wf-padding-bottom-md{padding-bottom:var(--wf-space-md)}.wf-margin-none{margin:0}.wf-margin-top-none{margin-top:0}.wf-margin-top-xs{margin-top:var(--wf-space-xs)}.wf-margin-top-sm{margin-top:var(--wf-space-sm)}.wf-margin-top-md{margin-top:var(--wf-space-md)}.wf-margin-bottom-xs{margin-bottom:var(--wf-space-xs)}.wf-margin-bottom-sm{margin-bottom:var(--wf-space-sm)}.wf-margin-bottom-md{margin-bottom:var(--wf-space-md)}.wf-margin-bottom-lg{margin-bottom:var(--wf-space-lg)}.wf-margin-left-xs{margin-left:var(--wf-space-xs)}.wf-margin-left-sm{margin-left:var(--wf-space-sm)}.wf-margin-x-auto{margin-left:auto;margin-right:auto}.wf-margin-y-xs{margin-top:var(--wf-space-xs);margin-bottom:var(--wf-space-xs)}.wf-gap-none{gap:0}.wf-gap-xs{gap:var(--wf-gap-xs)}.wf-gap-sm{gap:var(--wf-gap-sm)}.wf-gap-md{gap:var(--wf-gap-md)}.wf-gap-lg{gap:var(--wf-gap-lg)}.wf-gap-xl{gap:var(--wf-gap-xl)}.wf-width-full{width:100%}.wf-width-sm{width:var(--wf-w-sm, 480px)}.wf-height-full{height:100%}}@layer utilities{:where(.wf-block){display:block}}@layer utilities{:where(.wf-flex){display:flex}@media(min-width:640px){.wf-flex\@sm{display:flex}}@media(min-width:1024px){.wf-flex\@lg{display:flex}}}@layer utilities{:where(.wf-hidden){display:none}@media(min-width:1024px){.wf-hidden\@lg{display:none}}.wf-dim{opacity:.7}.wf-pointer{cursor:pointer}}@layer layout{.wf-popup{max-width:min(var(--wf-popup-max, 480px),calc(100vw - 32px));box-sizing:border-box}.wf-popup-mask{position:fixed;inset:0;z-index:var(--wf-z-overlay);background:var(--wf-overlay)}}
@@ -35,7 +35,7 @@ export type { Ui };
35
35
  * - 中间件注入面:`[key: string]: unknown` 索引签名 + **declare module 合并**
36
36
  * (应用/中间件作者扩展——同后端 `declare module 'weifuwu' { interface Context }`):
37
37
  * ```ts
38
- * declare module 'weifuwu/vdom' { interface UIContext { api: ApiClient } }
38
+ * declare module 'weifuwu/client/vdom' { interface UIContext { api: ApiClient } }
39
39
  * ```
40
40
  * - 组件泛型:Component<P, C = UIContext>——默认增强后的 UIContext) */
41
41
  export interface UIContext {
@@ -0,0 +1,42 @@
1
+ /**
2
+ * vdom core — createComponent(组件声明抽象——状态类/aria/role 机械面生成)
3
+ *
4
+ * 设计(2027-09——分层抽象 W3):组件层 80 状态类 · 240 aria 手写实证——
5
+ * 类名拼接与布尔 aria 是**派生面**(prop 状态 → 类/aria 的确定性映射)——
6
+ * 声明化(BEM 规则单源在 createComponent——组件内无 `--${variant}` 模板)。
7
+ *
8
+ * 抽象边界(防配置地狱护栏):只生成**机械部分**(类 + aria 布尔 + role)——
9
+ * 结构/内容/事件/业务 = render 自由面(皮)。判据:声明比实现短且机械部分
10
+ * 全消失——否则抽象失败(判负登记)。
11
+ *
12
+ * 用法:
13
+ * const PayBtn = createComponent<PayProps>({
14
+ * class: 'wf-pay-btn',
15
+ * enumStates: { variant: null }, // 直拼 wf-pay-btn--<v>
16
+ * boolStates: { active: 'wf-pay-btn--active' },
17
+ * ariaBools: { active: 'aria-pressed' },
18
+ * render: (root, props) => h('button', { ...root, onClick: props.onClick }, props.label),
19
+ * })
20
+ * // 旧:cls 数组 7 行 + aria 2 行 → 新:声明行 + render
21
+ */
22
+ import type { Component, VNode } from './vnode.ts';
23
+ import type { UIContext } from '../context/UIContext.ts';
24
+ export interface CreateComponentDecl<P = Record<string, unknown>> {
25
+ /** BEM 词根(wf-btn——直拼 `wf-btn--<v>`;布尔状态用 boolStates 显式类) */
26
+ class: string;
27
+ /** 布尔状态 → 类变体({ checked: 'wf-x--checked' }) */
28
+ boolStates?: Record<string, string>;
29
+ /** 枚举状态 → 类变体(值直拼 `wf-x--<v>`(null)或显式映射) */
30
+ enumStates?: Record<string, Record<string, string> | null>;
31
+ /** 布尔 → aria 属性({ loading: 'aria-busy' }——真值写出属性) */
32
+ ariaBools?: Record<string, string>;
33
+ /** 根 role(静态) */
34
+ role?: string;
35
+ /** 皮(rootProps 组装毕——class/aria/role/class 透传已含——缺省
36
+ * 根元素直接透传——render 负责结构/内容/事件——ctx 透传(i18n 等)) */
37
+ render?: (rootProps: Record<string, unknown>, props: P, ctx: UIContext) => VNode | null;
38
+ /** 缺省渲染的根标签(render 未提供时——button) */
39
+ tag?: string;
40
+ }
41
+ /** 组件声明 → 组件工厂(同步——两阶段语义与手写一致) */
42
+ export declare function createComponent<P = Record<string, unknown>>(decl: CreateComponentDecl<P>): Component<P>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * createItem —— 交互元素状态捆绑原语(原语全面化回馈 #2)
3
+ *
4
+ * 为什么存在:createComponent(组件级声明)在 W3 判负调查中暴露结构性错位——
5
+ * 组件 = 容器 + 可交互子项(Tabs 的 tab / SegmentedControl 的 option /
6
+ * TabBar 的 item),**状态类和 aria 布尔几乎总在子项上**(43 组件含状态面,
7
+ * 12 组件是「同条件驱动类 + aria 双面」的真机械面)。抽象单位切错了——
8
+ * 从「组件」下沉到「交互元素」:
9
+ *
10
+ * ```ts
11
+ * const tab = createItem({ cls: 'wf-tab', role: 'tab', aria: 'aria-selected' })
12
+ * // 循环内:
13
+ * h('button', tab(act === key, { onClick }), label)
14
+ * // → { class: 'wf-tab wf-tab--active', role: 'tab', 'aria-selected': true, onClick }
15
+ * ```
16
+ *
17
+ * 单源回报:类后缀与 aria 布尔**捆绑声明**——不可能改一面漏一面
18
+ * (aria-selected 与 --active 不同步 = a11y bug——同类手写双面同步是历史重复源)。
19
+ * aria 布尔直传内核(ariaBoolValue 归一——回馈 #1 后全库无手写三元冗余)。
20
+ *
21
+ * 边界(诚实):单活动态(一个元素一个激活布尔)。多状态子项
22
+ * (Menu 的 current+expanded / Tree 的 checked+selected+open)不在契约——
23
+ * 手写保留(判负登记);aria 多值(Tree checked 'mixed' / Cascader 多态)
24
+ * 用 ariaText 文本值兜底,多值枚举仍判负。
25
+ */
26
+ export interface ItemStateDecl {
27
+ /** 基类(如 'wf-tab')——active 时派生 `cls + suffix` */
28
+ cls: string;
29
+ /** 活动态类后缀(默认 '--active'——组件类名约定) */
30
+ suffix?: string;
31
+ /** role(所有实例同值——如 'tab'/'option') */
32
+ role?: string;
33
+ /** 活动态 aria 布尔键(布尔直传内核归一——非 active 时 false 保留) */
34
+ aria?: string;
35
+ /** 活动态 aria 文本值(active → value;非 active → undefined 移除) */
36
+ ariaText?: {
37
+ key: string;
38
+ value: string;
39
+ };
40
+ /** roving tabindex(active → 0 · 非 active → -1——键盘焦点管理面) */
41
+ roving?: boolean;
42
+ }
43
+ /**
44
+ * 生成「交互元素状态 props」工厂——返回 (active, extra) => props。
45
+ * - active=true:类带后缀 · aria 布尔 true(或 ariaText value)
46
+ * - active=false:类无后缀 · aria 布尔 false(保留状态——与属性移除语义不同)
47
+ * · ariaText undefined(移除)
48
+ * - extra 后置 spread(extra 胜——扩展不用改声明)
49
+ * - **class 例外:extra.class 追加而非覆盖**(disabled/focus/variant 等
50
+ * 第二类面与状态后缀共存——覆盖会丢状态类——契约锁定合并语义)
51
+ */
52
+ export declare function createItem(decl: ItemStateDecl): (active: boolean, extra?: Record<string, unknown>) => Record<string, unknown>;
@@ -4,7 +4,10 @@
4
4
  * 设计(对齐 vdom-x 契约 + 设计规则 §4.0/§6.3):
5
5
  * ① vnode 纯数据——零回填字段(el/_render/_id 等全部在影子层——可自由克隆/
6
6
  * 比较/序列化——用户写 JSX 就能推导 vnode 形状)
7
- * ② h() 除 key 剥离外零转换——children 原样(false/嵌套数组保留——不 filter)
7
+ * ② h() 除 key 剥离 + class 归一外零转换——children 原样(false/嵌套数组保留——
8
+ * 不 filter);class 归一(2027-09——组件层 105 文件 180 处模板拼接手搓实证——
9
+ * 对象/数组条件类万库通用形态——内核承载:字符串直通零成本 · 对象/数组归一
10
+ * 为空格串(协议/SSR/diff 零改——归一时机 vnode 创建——一次)
8
11
  * ③ key 业务身份声明协议:key 从 props 剥离进 vnode.key(组件 props 不见 key)
9
12
  * ④ children 值域协议:vnode/string/number/boolean/空洞(null/undefined)/嵌套数组
10
13
  * (数组 = 隐式 Fragment——递归展开统一在 childrenOf——单一规则源——
@@ -34,11 +37,14 @@ export type RenderFn<P = Record<string, unknown>> = (props: P) => VNode | null |
34
37
  * 同步执行不存在「半挂载」可观察状态——mouting 竞态类 bug 结构性消灭)
35
38
  * - renderFn = 每次渲染(ctx.render()/props 变化触发——**纯同步**)
36
39
  * - 异步边界 = useAsyncData/useObservable/useExternal(hooks——流语义) */
37
- export type Component<P = Record<string, unknown>, C = UIContext> = (initProps: P, ctx: C) => RenderFn<P>;
40
+ export type Component<P = Record<string, unknown>, C = UIContext> = (initProps: P, ctx: C) => RenderFn<P> | VNode | null | (VNode | null)[];
38
41
  type HType = string | symbol | Component<any, any>;
39
42
  /** h()——创建 vnode(纯数据——除 key 剥离外零转换)
40
43
  * children 原样:单子节点直接存、多子节点存数组、无子节点不存——false/嵌套
41
44
  * 数组保留(不 filter——空洞占位法在消费侧) */
45
+ /** class 归一(字符串直通 · 数组展开 · 对象条件真值 · 嵌套递归——false/null 剔除)
46
+ * 万库通用条件类形态(对象 = { 'wf-active': isActive }——零模板拼接) */
47
+ export declare function normalizeClass(v: unknown): string | undefined;
42
48
  export declare function h(type: HType, props?: Record<string, unknown> | null, ...children: VNodeChild[]): VNode;
43
49
  /** jsx 运行时(自动导入——`<div/>` 编译目标——React 兼容签名 jsx(type, props, key)——
44
50
  * props 内 key 同样剥离;jsxs/jsxDEV 同形状(children 已在 props.children) */
@@ -12,6 +12,9 @@ import type { ExternalStore } from '../store.ts';
12
12
  import { Subject } from '../observable/index.ts';
13
13
  import { type PopupHandle, type PopupOpenOptions } from './popup-manager.ts';
14
14
  import { type TweenOptions } from './stable.ts';
15
+ import { type SignalHandle } from './signal.ts';
16
+ import { type OverlayHandle, type OverlayOptions } from './overlay.ts';
17
+ import { type FieldHandle, type FieldOptions } from './field.ts';
15
18
  /** hooks 环境(per 组件实例——renderComponent 注入) */
16
19
  /** me() 会话面(useSession 返回——轻量结构——不依赖 server 类型) */
17
20
  export interface UserSession {
@@ -150,6 +153,15 @@ export interface Ui {
150
153
  useVisualViewport(): import('./stable.ts').VisualViewportHandle;
151
154
  /** 响应式系统偏好(prefers-reduced-motion——mount 期一次判定) */
152
155
  useReducedMotion(): boolean;
156
+ /** 局部状态原语(set 自动重渲染——getter 纪律:get() 任意位置读最新)
157
+ * **增量原语**:不取代既有 ctx.render() 用法(存量保留) */
158
+ useSignal<T>(init: T): SignalHandle<T>;
159
+ /** 弹层行为契约(open/onOpenChange/焦点困禁/滚动锁/Esc/遮罩单源——
160
+ * sync 渲染期调用(openPopup 生命周期)——详见 hooks/overlay.ts) */
161
+ useOverlay(opts: OverlayOptions): OverlayHandle;
162
+ /** 表单字段契约(label/error/hint/aria 连接单源——renderLabel/Error/Hint
163
+ * 结构渲染——类为皮(字段 CSS)——详见 hooks/field.ts) */
164
+ useField(opts: FieldOptions): FieldHandle;
153
165
  }
154
166
  /** SSR 预取等待集合(并行 fetch 的 in-flight promise——uiSsr 等待会合) */
155
167
  export declare const asyncInflight: Set<Promise<unknown>>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * vdom hooks — useField(表单字段行为契约——label/error/hint/aria 连接单源)
3
+ *
4
+ * 设计(2027-09——分层抽象 W5):表单字段(Input/Select/DatePicker……)的
5
+ * label/required·error/hint 结构与 aria 连接(label for ↔ input id ·
6
+ * aria-invalid · aria-describedby · aria-required)重复手写实证——
7
+ * 契约化:字段作者只写输入面——标签/错误/提示/aria 由契约结构性保证。
8
+ *
9
+ * 结构类(labelClass/errClass/hintClass/reqClass/wrapErrClass)是皮
10
+ * (字段 CSS 定)——行为(属性/连接/态)契约内建。**渲染期 opts**(useOverlay
11
+ * 同模式——每次渲染读最新)。
12
+ *
13
+ * 用法:
14
+ * const f = useField({ label, error, hint, required, name })
15
+ * if (!f.hasWrap) return h('input', f.inputProps())
16
+ * return h('div', { class: `wf-x-wrap${f.stateClass}` }, [
17
+ * f.renderLabel(), h('input', f.inputProps()), f.renderError(), f.renderHint(),
18
+ * ])
19
+ */
20
+ import type { HookEnv } from './env.ts';
21
+ import type { VNode } from '../core/vnode.ts';
22
+ export interface FieldOptions {
23
+ label?: string;
24
+ error?: string;
25
+ hint?: string;
26
+ required?: boolean;
27
+ /** 连接 id 基(显式 id 或 name——label for ↔ input id) */
28
+ name?: string;
29
+ id?: string;
30
+ /** 包装面(错误态类——字段 CSS 的 --err 变体) */
31
+ wrapErrClass?: string;
32
+ /** 标签/错误/提示的类(皮——字段 CSS) */
33
+ labelClass?: string;
34
+ errClass?: string;
35
+ hintClass?: string;
36
+ reqClass?: string;
37
+ /** 必填星字符(默认 *) */
38
+ reqChar?: string;
39
+ }
40
+ export interface FieldHandle {
41
+ /** 包装与否(无 label/error/hint = 裸输入——Input 先例) */
42
+ hasWrap: boolean;
43
+ /** 错误态类('' 或 ' --err'——组件拼到 wrap class) */
44
+ stateClass: string;
45
+ /** 输入 id(name/id 提供时——label for 连接) */
46
+ inputId: string | undefined;
47
+ /** 输入面(id/aria-invalid/aria-describedby/aria-required) */
48
+ inputProps(): Record<string, unknown>;
49
+ renderLabel(): VNode | null;
50
+ renderError(): VNode | null;
51
+ renderHint(): VNode | null;
52
+ }
53
+ /** 表单字段契约(mount 期调用;opts 渲染期读最新——闭包引用) */
54
+ export declare function useField(env: HookEnv, optsIn: FieldOptions): FieldHandle;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * vdom hooks — useOverlay(弹层行为契约——开/关/焦点/滚动锁/Esc 单源)
3
+ *
4
+ * 设计(2027-09——分层抽象 W2):弹层家族(Modal/Drawer/ActionSheet)的
5
+ * 行为面(open 同步 openPopup 生命周期 · trapFocus · lockScroll ·
6
+ * 遮罩点击 · Esc 关闭 · presence 退场)**契约化**——组件作者只写**皮**
7
+ * (overlay/panel 的 class 与内容)——行为正确性由契约结构性保证。
8
+ *
9
+ * 分工(与 popup-manager 的关系):useOverlay 是 popup-manager(openPopup)
10
+ * 的**组件作者友好封装**(受控同步模式 Modal 先例的契约化)——float 定位
11
+ * 族(Popover/Tooltip)不在此契约(正交组合 usePopupPosition——未来
12
+ * usePopover 契约 = useOverlay + usePopupPosition)。
13
+ *
14
+ * 用法:
15
+ * const ov = ctx.ui.useOverlay({ open, onOpenChange, role: 'dialog', maskClosable })
16
+ * const root = h('div', { class: 'wf-modal' }, [
17
+ * h('div', { ...ov.maskProps, class: 'wf-modal-overlay' }),
18
+ * h('div', { ...ov.panelProps, class: 'wf-modal-content' }, content),
19
+ * ])
20
+ * ov.sync(root) // 渲染期同步(openPopup 生命周期)
21
+ * return root
22
+ */
23
+ import type { HookEnv } from './env.ts';
24
+ import type { VNode } from '../core/vnode.ts';
25
+ export interface OverlayOptions {
26
+ /** 受控 open(父层) */
27
+ open?: boolean;
28
+ /** 关闭上抛(遮罩/Esc/close()) */
29
+ onOpenChange?: (v: boolean) => void;
30
+ /** 面板角色(默认 dialog——alertdialog 场景覆盖) */
31
+ role?: string;
32
+ /** Tab 焦点困禁(默认 true——`{...panelProps}` 面板内循环) */
33
+ trapFocus?: boolean;
34
+ /** 滚动锁(默认 true——body 锁定 + 焦点归还) */
35
+ lockScroll?: boolean;
36
+ /** 遮罩点击关闭(默认 true——危险确认 false) */
37
+ maskClosable?: boolean;
38
+ /** Esc 关闭(默认 true——危险确认可 false) */
39
+ closeOnEscape?: boolean;
40
+ /** presence 退场动画(退场 class → animationend → 卸载) */
41
+ presence?: boolean;
42
+ }
43
+ export interface OverlayHandle {
44
+ /** 遮罩面(onClick 行为——类名是皮——组件拼接) */
45
+ maskProps: {
46
+ onClick?: (e: Event) => void;
47
+ };
48
+ /** 面板面(role/aria-modal——类名是皮) */
49
+ panelProps: {
50
+ role: string;
51
+ 'aria-modal': true;
52
+ };
53
+ /** 关闭(上抛 onOpenChange(false)) */
54
+ close(): void;
55
+ /** 渲染期同步(openPopup 生命周期——open 变化/内容更新;latestOpts
56
+ * 渲染期最新配置——缺省用 mount 初值) */
57
+ sync(root: () => VNode, latestOpts?: OverlayOptions): void;
58
+ }
59
+ /** 弹层行为契约(mount 期调用——状态闭包;sync 渲染期调用) */
60
+ export declare function useOverlay(env: HookEnv, opts: OverlayOptions): OverlayHandle;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * vdom hooks — useSignal(局部状态原语——setter 自动重渲染)
3
+ *
4
+ * 设计(2027-09——分层抽象 W1):组件层 260 处手动 `ctx.render()` 实证——
5
+ * 状态变更必须手动触发渲染(忘了 = 界面不动——`setter` 自动重渲染消灭
6
+ * 该类 bug)。心智对齐主流(useState 半同构)但保持 getter 纪律:
7
+ * `get()` 任意位置读最新(getter 规则同 useMedia/useBreakpoint——
8
+ * mount 闭包持有永远最新)。
9
+ *
10
+ * 形态:`useSignal(init) → { get, set }`
11
+ * - set(v):v 为值或函数((prev) => next——函数式更新)
12
+ * - set 自动 requestRender(组件重渲染——get 读到新值)
13
+ * - 跨渲染保持(hook 状态缓存——mount 闭包同先例)
14
+ * - **语义**:signal 是**增量原语**(不取代 ctx.render() 的既有用法——
15
+ * 新组件/维护组件推荐;存量保留)
16
+ */
17
+ import type { HookEnv } from './env.ts';
18
+ export interface SignalHandle<T> {
19
+ /** 读最新(任意位置——getter 纪律) */
20
+ get(): T;
21
+ /** 写(值或函数式更新)——自动重渲染 */
22
+ set(v: T | ((prev: T) => T)): void;
23
+ }
24
+ /** 局部状态原语(mount 期调用一次——hook 状态缓存保持) */
25
+ export declare function useSignal<T>(env: HookEnv, init: T): SignalHandle<T>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * weifuwu/vdom — 新版本 vdom 公共面(独立实现区)
2
+ * weifuwu/client/vdom — 新版本 vdom 公共面(独立实现区)
3
3
  *
4
4
  * 决策(2026-12):
5
5
  * - ui-dom 保持不变——本目录**完全独立实现**(零引用 ui-dom——不 re-export)——
@@ -38,7 +38,7 @@
38
38
  * 5. core/html(commandToHtml——流式 SSR)——待
39
39
  * 6. hooks/browser/middlewares 独立实现——待
40
40
  */
41
- export { h, jsx, jsxs, jsxDEV } from './core/vnode.ts';
41
+ export { h, jsx, jsxs, jsxDEV, normalizeClass } from './core/vnode.ts';
42
42
  export { keyOf, keyedId } from './core/node/keyed.ts';
43
43
  export { Fragment } from './core/node/fragment.ts';
44
44
  export { UIRouter } from './core/router.ts';
@@ -50,6 +50,9 @@ export type { Component, RenderFn, VNode, VNodeChild } from './core/vnode.ts';
50
50
  export type { Ui } from './hooks/env.ts';
51
51
  /** 页面作者渲染入口(ctx.stream——vnode → Response 命令流) */
52
52
  export type { RenderCtx } from './core/protocol.ts';
53
+ export { useSignal, type SignalHandle } from './hooks/signal.ts';
54
+ export { useOverlay, type OverlayOptions, type OverlayHandle } from './hooks/overlay.ts';
55
+ export { useField, type FieldOptions, type FieldHandle } from './hooks/field.ts';
53
56
  export type { Browser } from './browser/Browser.ts';
54
57
  export type { ApiClient } from './middlewares/api.ts';
55
58
  export type { AuthClient, I18nState } from './middlewares/auth-i18n.ts';
@@ -63,6 +66,10 @@ export { renderToStreamV2 as renderToStream } from './core/v2/integrate.ts';
63
66
  export { diffToStreamV2 as diffStream } from './core/v2/integrate.ts';
64
67
  export { CommandApplier } from './core/patch/index.ts';
65
68
  export { createComponentRegistry } from './core/node/component.ts';
69
+ export { createItem } from './core/create-item.ts';
70
+ export type { ItemStateDecl } from './core/create-item.ts';
71
+ export { createComponent } from './core/create-component.ts';
72
+ export type { CreateComponentDecl } from './core/create-component.ts';
66
73
  export { aiStream } from './hooks/ai-stream.ts';
67
74
  export type { AiStreamHandle } from './hooks/ai-stream.ts';
68
75
  export type { ExternalStore } from './store.ts';