devnonla-ui 0.1.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/package.json +66 -0
  4. package/src/alert/Alert.tsx +109 -0
  5. package/src/app/App.tsx +36 -0
  6. package/src/button/Button.tsx +278 -0
  7. package/src/button/ButtonCopy.tsx +60 -0
  8. package/src/calendar/Calendar.tsx +133 -0
  9. package/src/chat/AgentPanel.tsx +203 -0
  10. package/src/chat/common/bgTasks.ts +41 -0
  11. package/src/chat/common/sse.ts +156 -0
  12. package/src/chat/common/types.ts +43 -0
  13. package/src/chat/common/useAgentStream.ts +351 -0
  14. package/src/chat/common/utils.ts +73 -0
  15. package/src/chat/index.ts +56 -0
  16. package/src/chat/message-ui/ChatAgentMessage.tsx +29 -0
  17. package/src/chat/message-ui/ChatError.tsx +24 -0
  18. package/src/chat/message-ui/ChatInput.tsx +162 -0
  19. package/src/chat/message-ui/ChatMarkdown.tsx +128 -0
  20. package/src/chat/message-ui/ChatMarkdownTable.tsx +45 -0
  21. package/src/chat/message-ui/ChatSpinner.tsx +5 -0
  22. package/src/chat/message-ui/ChatThinking.tsx +61 -0
  23. package/src/chat/message-ui/ChatUserMessage.tsx +72 -0
  24. package/src/chat/message-ui/ChatWelcome.tsx +70 -0
  25. package/src/chat/message-ui/MermaidBlock.tsx +266 -0
  26. package/src/chat/message-ui/mermaidFence.ts +55 -0
  27. package/src/chat/message-ui/sanitizeMermaid.ts +135 -0
  28. package/src/chat/tool-ui/BackgroundTaskToolUI.tsx +36 -0
  29. package/src/chat/tool-ui/BackgroundTasksBar.tsx +152 -0
  30. package/src/chat/tool-ui/CallAgentToolUI.tsx +168 -0
  31. package/src/chat/tool-ui/ChatToolCall.tsx +77 -0
  32. package/src/chat/tool-ui/GetCurrentTimeToolUI.tsx +49 -0
  33. package/src/chat/tool-ui/ReadSkillToolUI.tsx +80 -0
  34. package/src/chat/tool-ui/RunJsToolUI.tsx +106 -0
  35. package/src/chat/tool-ui/ToolUiBadge.tsx +10 -0
  36. package/src/chat/tool-ui/ToolUiTrailing.tsx +24 -0
  37. package/src/chat/tool-ui/WebFetchToolUI.tsx +53 -0
  38. package/src/chat/tool-ui/registry.ts +29 -0
  39. package/src/chat/tool-ui/types.ts +22 -0
  40. package/src/checkbox/Checkbox.tsx +50 -0
  41. package/src/codeblock/CodeBlock.tsx +76 -0
  42. package/src/codeblock/highlight.ts +159 -0
  43. package/src/colorpicker/ColorPicker.tsx +45 -0
  44. package/src/datepicker/DatePicker.tsx +481 -0
  45. package/src/desktop/DesktopHeader.tsx +92 -0
  46. package/src/desktop/DesktopIcon.tsx +34 -0
  47. package/src/desktop/DesktopStage.tsx +6 -0
  48. package/src/desktop/DesktopWindow.tsx +504 -0
  49. package/src/desktop/MeadowDesktop.tsx +15 -0
  50. package/src/desktop/MeadowShell.tsx +12 -0
  51. package/src/desktop/MeadowWallpaper.tsx +5 -0
  52. package/src/desktop/assets/desktop-meadow.jpg +0 -0
  53. package/src/desktop/assets.d.ts +9 -0
  54. package/src/desktop/surface.ts +1 -0
  55. package/src/drawer/Drawer.tsx +125 -0
  56. package/src/dropdown/ContextMenu.tsx +97 -0
  57. package/src/dropdown/Dropdown.tsx +139 -0
  58. package/src/dropdown/menuClasses.ts +9 -0
  59. package/src/empty/Empty.tsx +47 -0
  60. package/src/form/Form.tsx +95 -0
  61. package/src/form/FormItem.tsx +145 -0
  62. package/src/form/common/context.ts +13 -0
  63. package/src/form/common/enum.ts +20 -0
  64. package/src/form/common/rules.ts +68 -0
  65. package/src/form/common/types.ts +169 -0
  66. package/src/form/index.ts +35 -0
  67. package/src/form/partials/FormItemHelps.tsx +31 -0
  68. package/src/form/variants/FieldCheckbox.tsx +20 -0
  69. package/src/form/variants/FieldColor.tsx +63 -0
  70. package/src/form/variants/FieldDateTime.tsx +25 -0
  71. package/src/form/variants/FieldHidden.tsx +9 -0
  72. package/src/form/variants/FieldInput.tsx +24 -0
  73. package/src/form/variants/FieldNumber.tsx +28 -0
  74. package/src/form/variants/FieldObject.tsx +29 -0
  75. package/src/form/variants/FieldRadio.tsx +40 -0
  76. package/src/form/variants/FieldRepeater.tsx +62 -0
  77. package/src/form/variants/FieldRepeaterItem.tsx +64 -0
  78. package/src/form/variants/FieldSelect.tsx +27 -0
  79. package/src/form/variants/FieldSelectMultiple.tsx +32 -0
  80. package/src/form/variants/FieldSelectRemote.tsx +66 -0
  81. package/src/form/variants/FieldSwitch.tsx +17 -0
  82. package/src/form/variants/FieldTextarea.tsx +25 -0
  83. package/src/form/variants/FieldTime.tsx +25 -0
  84. package/src/form-layout/FormLayout.tsx +74 -0
  85. package/src/icon/FluentIcon.tsx +28 -0
  86. package/src/icon/fluent.ts +75 -0
  87. package/src/index.ts +214 -0
  88. package/src/input/Input.tsx +371 -0
  89. package/src/input/SearchInput.tsx +73 -0
  90. package/src/lib/cn.ts +6 -0
  91. package/src/lib/placement.ts +44 -0
  92. package/src/lib/sizes.ts +117 -0
  93. package/src/lib/surface.ts +8 -0
  94. package/src/menu/Menu.tsx +98 -0
  95. package/src/message/message.tsx +214 -0
  96. package/src/modal/Modal.tsx +277 -0
  97. package/src/pagination/Pagination.tsx +103 -0
  98. package/src/popconfirm/Popconfirm.tsx +134 -0
  99. package/src/popover/Popover.tsx +116 -0
  100. package/src/scroll/OverlayScroll.tsx +141 -0
  101. package/src/segmented/Segmented.tsx +67 -0
  102. package/src/select/Select.tsx +319 -0
  103. package/src/skeleton/Skeleton.tsx +47 -0
  104. package/src/spin/Spin.tsx +160 -0
  105. package/src/styles.css +897 -0
  106. package/src/switch/Switch.tsx +58 -0
  107. package/src/table/Table.tsx +387 -0
  108. package/src/tag/Tag.tsx +109 -0
  109. package/src/theme.ts +131 -0
  110. package/src/timepicker/TimePicker.tsx +751 -0
  111. package/src/tooltip/Tooltip.tsx +59 -0
package/src/styles.css ADDED
@@ -0,0 +1,897 @@
1
+ @import "highlight.js/styles/github.css";
2
+
3
+ /**
4
+ * NonlaUI theme — single source of color.
5
+ *
6
+ * Light-only. Warm paper + charcoal ink, amber brand.
7
+ * Override `--nonla-*` knobs in the consuming app (CSS or `<App theme>`).
8
+ * Components read only these tokens — never edit Button/Tag/… to retheme.
9
+ */
10
+
11
+ :root,
12
+ .dark,
13
+ .nonla-ui {
14
+ color-scheme: light;
15
+
16
+ /* ── Knobs (override these) ──────────────────────────────────────────── */
17
+ --nonla-bg: #fffcf1;
18
+ --nonla-fg: #1f1f1e;
19
+ /* Text rank on cream — same ink, contrast steps ~13.6 / 7 / 4.5 / 3 (WCAG AAA body → AA body → AA UI). */
20
+ --nonla-fg-muted: color-mix(in oklab, var(--nonla-fg) 78%, var(--nonla-bg));
21
+ --nonla-fg-tertiary: color-mix(in oklab, var(--nonla-fg) 64%, var(--nonla-bg));
22
+ --nonla-fg-quaternary: color-mix(in oklab, var(--nonla-fg) 50%, var(--nonla-bg));
23
+ --nonla-brand: #eb9d29;
24
+ /* Ink on brand fills — charcoal, not white (white fails WCAG on amber). */
25
+ --nonla-solid-fg: var(--nonla-fg);
26
+ --nonla-danger: #c0392b;
27
+ --nonla-success: #1f9d55;
28
+ --nonla-warn: #c47d12;
29
+ --nonla-link: var(--nonla-brand);
30
+ --nonla-radius: 8px;
31
+ --nonla-height: 32px;
32
+ --nonla-height-sm: 24px;
33
+ --nonla-height-lg: 40px;
34
+
35
+ --nonla-ink: var(--nonla-fg);
36
+ --nonla-surface: #ffffff;
37
+ --nonla-elevated: var(--nonla-surface);
38
+ --nonla-chip: color-mix(in oklab, var(--nonla-fg) 5%, var(--nonla-bg));
39
+ --nonla-chip-hover: color-mix(in oklab, var(--nonla-fg) 9%, var(--nonla-bg));
40
+ --nonla-border: color-mix(in oklab, var(--nonla-fg) 7%, var(--nonla-bg));
41
+ --nonla-input: color-mix(in oklab, var(--nonla-fg) 12%, var(--nonla-bg));
42
+ --nonla-composer: var(--nonla-surface);
43
+ --nonla-chat-bg: #fcfcfc;
44
+
45
+ /* Neutral frost — blur shows whatever sits behind, no page-tint */
46
+ --nonla-meadow: #4f7a32;
47
+ --nonla-glass: color-mix(in srgb, white 58%, transparent);
48
+ --nonla-glass-bar: color-mix(in srgb, white 28%, transparent);
49
+ --nonla-glass-menu: color-mix(in srgb, white 48%, transparent);
50
+ --nonla-glass-border: color-mix(in srgb, white 62%, transparent);
51
+ --nonla-glass-highlight: color-mix(in srgb, white 70%, transparent);
52
+ --nonla-ink-hover: color-mix(in srgb, var(--nonla-ink) 6%, transparent);
53
+ --nonla-ink-active: color-mix(in srgb, var(--nonla-ink) 8%, transparent);
54
+ --nonla-ink-line: color-mix(in srgb, var(--nonla-ink) 14%, transparent);
55
+ --nonla-desktop-bar-height: 42px;
56
+
57
+ /* Preset accents — Button color="blue" / Tag color="purple" / … */
58
+ --nonla-blue: #1677ff;
59
+ --nonla-purple: #722ed1;
60
+ --nonla-cyan: #13c2c2;
61
+ --nonla-green: #0ac864;
62
+ --nonla-magenta: #eb2f96;
63
+ --nonla-pink: #eb2f96;
64
+ --nonla-red: #ef4444;
65
+ --nonla-orange: #fa8c16;
66
+ --nonla-yellow: #fadb14;
67
+ --nonla-volcano: #fa541c;
68
+ --nonla-geekblue: #2f54eb;
69
+ --nonla-lime: #a0d911;
70
+ --nonla-gold: #faad14;
71
+
72
+ /* ── Derived map (do not set unless you need a one-off exception) ───── */
73
+ --nonla-radius-sm: max(0px, calc(var(--nonla-radius) - 2px));
74
+ --nonla-radius-lg: calc(var(--nonla-radius) + 2px);
75
+ --radius: var(--nonla-radius);
76
+ --background: var(--nonla-bg);
77
+ --foreground: var(--nonla-fg);
78
+ --card: var(--nonla-surface);
79
+ --card-foreground: var(--nonla-fg);
80
+ --popover: var(--nonla-elevated);
81
+ --popover-foreground: var(--nonla-fg);
82
+ /* Nonla: --primary = ink (emphasis), not CTA — CTA is --brand */
83
+ --primary: var(--nonla-ink);
84
+ --primary-foreground: var(--nonla-bg);
85
+ --secondary: var(--nonla-chip);
86
+ --secondary-foreground: var(--nonla-fg);
87
+ --muted: var(--nonla-chip);
88
+ --muted-foreground: var(--nonla-fg-muted);
89
+ --accent: color-mix(in oklab, var(--nonla-brand) 14%, transparent);
90
+ --accent-foreground: var(--brand-700);
91
+ --destructive: var(--nonla-danger);
92
+ --destructive-foreground: var(--nonla-surface);
93
+ --border: var(--nonla-border);
94
+ --input: var(--nonla-input);
95
+ --ring: color-mix(in oklab, var(--nonla-brand) 55%, transparent);
96
+
97
+ /* Brand scale — 500 is the knob. Tints → white, shades → black. */
98
+ --brand-50: color-mix(in oklab, var(--nonla-brand) 5%, white);
99
+ --brand-100: color-mix(in oklab, var(--nonla-brand) 12%, white);
100
+ --brand-200: color-mix(in oklab, var(--nonla-brand) 24%, white);
101
+ --brand-300: color-mix(in oklab, var(--nonla-brand) 42%, white);
102
+ --brand-400: color-mix(in oklab, var(--nonla-brand) 68%, white);
103
+ --brand-500: var(--nonla-brand);
104
+ --brand-600: color-mix(in oklab, var(--nonla-brand) 82%, black);
105
+ --brand-700: color-mix(in oklab, var(--nonla-brand) 64%, black);
106
+ --brand-800: color-mix(in oklab, var(--nonla-brand) 48%, black);
107
+ --brand: var(--brand-500);
108
+ --brand-text: var(--brand-700);
109
+ --link: var(--nonla-link);
110
+ --success: var(--nonla-success);
111
+ --warn: var(--nonla-warn);
112
+ --tertiary-foreground: var(--nonla-fg-tertiary);
113
+ --quaternary-foreground: var(--nonla-fg-quaternary);
114
+ --border-subtle: color-mix(in srgb, var(--nonla-border) 65%, transparent);
115
+ --control-bg: var(--nonla-chip);
116
+ --control-bg-hover: var(--nonla-chip-hover);
117
+ --elevated-shadow: 0 16px 48px color-mix(in srgb, var(--nonla-fg) 10%, transparent), 0 0 0 1px color-mix(in srgb, var(--nonla-fg) 6%, transparent);
118
+ --popper-shadow: 0 16px 48px color-mix(in srgb, var(--nonla-fg) 10%, transparent), 0 0 0 1px color-mix(in srgb, var(--nonla-fg) 6%, transparent);
119
+ --popper-border: var(--nonla-border);
120
+ --mask: color-mix(in srgb, var(--nonla-fg) 28%, transparent);
121
+ --meadow: var(--nonla-meadow);
122
+ --glass: var(--nonla-glass);
123
+ --glass-bar: var(--nonla-glass-bar);
124
+ --glass-menu: var(--nonla-glass-menu);
125
+ --glass-border: var(--nonla-glass-border);
126
+ --glass-highlight: var(--nonla-glass-highlight);
127
+ --ink-hover: var(--nonla-ink-hover);
128
+ --ink-active: var(--nonla-ink-active);
129
+ --ink-line: var(--nonla-ink-line);
130
+
131
+ /* Motion — shadcn-like ease-out-expo */
132
+ --nonla-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
133
+ --nonla-ease-in: cubic-bezier(0.4, 0, 1, 1);
134
+ --nonla-dur-fast: 150ms;
135
+ --nonla-dur: 200ms;
136
+ --nonla-dur-slow: 300ms;
137
+
138
+ /* Chat type — one scale for full-page chat and side panels */
139
+ --chat-body-size: 15px;
140
+ --chat-body-leading: 24px;
141
+ --chat-h1-size: 16px;
142
+ --chat-h2-size: 16px;
143
+ --chat-h3-size: 14px;
144
+ --chat-h4-size: 14px;
145
+ --chat-p-mb: 12px;
146
+ --chat-h-mt: 16px;
147
+ --chat-h-mb: 8px;
148
+ --chat-composer-size: 14px;
149
+ --chat-composer-leading: 22px;
150
+ --chat-code-size: 12.5px;
151
+ --nonla-scrollbar-size: 6px;
152
+ --nonla-scrollbar-thumb: color-mix(in oklab, var(--nonla-fg) 22%, var(--nonla-bg));
153
+ --nonla-scrollbar-thumb-hover: var(--nonla-fg-quaternary);
154
+
155
+ color: var(--foreground);
156
+ }
157
+
158
+ /* Tailwind v4 — scan this package + expose semantic color utilities. */
159
+ @source "./**/*.tsx";
160
+
161
+ @theme inline {
162
+ --radius: var(--nonla-radius);
163
+ --radius-xs: 2px;
164
+ --radius-sm: 4px;
165
+ --radius-md: 6px;
166
+ --radius-lg: 8px;
167
+ --radius-xl: 12px;
168
+ --radius-2xl: 16px;
169
+ --radius-3xl: 20px;
170
+ --radius-4xl: 24px;
171
+ --radius-full: 9999px;
172
+
173
+ --color-background: var(--background);
174
+ --color-foreground: var(--foreground);
175
+ --color-card: var(--card);
176
+ --color-card-foreground: var(--card-foreground);
177
+ --color-popover: var(--popover);
178
+ --color-popover-foreground: var(--popover-foreground);
179
+ --color-primary: var(--primary);
180
+ --color-primary-foreground: var(--primary-foreground);
181
+ --color-secondary: var(--secondary);
182
+ --color-secondary-foreground: var(--secondary-foreground);
183
+ --color-muted: var(--muted);
184
+ --color-muted-foreground: var(--muted-foreground);
185
+ --color-accent: var(--accent);
186
+ --color-accent-foreground: var(--accent-foreground);
187
+ --color-destructive: var(--destructive);
188
+ --color-destructive-foreground: var(--destructive-foreground);
189
+ --color-border: var(--border);
190
+ --color-border-subtle: var(--border-subtle);
191
+ --default-border-color: var(--border);
192
+ --color-input: var(--input);
193
+ --color-ring: var(--ring);
194
+ --color-brand: var(--brand);
195
+ --color-brand-50: var(--brand-50);
196
+ --color-brand-100: var(--brand-100);
197
+ --color-brand-200: var(--brand-200);
198
+ --color-brand-300: var(--brand-300);
199
+ --color-brand-400: var(--brand-400);
200
+ --color-brand-500: var(--brand-500);
201
+ --color-brand-600: var(--brand-600);
202
+ --color-brand-700: var(--brand-700);
203
+ --color-brand-800: var(--brand-800);
204
+ --color-brand-text: var(--brand-text);
205
+ --color-link: var(--link);
206
+ --color-success: var(--success);
207
+ --color-warn: var(--warn);
208
+ --color-tertiary-foreground: var(--tertiary-foreground);
209
+ --color-quaternary-foreground: var(--quaternary-foreground);
210
+ --color-meadow: var(--meadow);
211
+ --color-glass: var(--glass);
212
+ --color-glass-bar: var(--glass-bar);
213
+ --color-glass-menu: var(--glass-menu);
214
+ --color-glass-border: var(--glass-border);
215
+ --color-glass-highlight: var(--glass-highlight);
216
+ --color-ink-hover: var(--ink-hover);
217
+ --color-ink-active: var(--ink-active);
218
+ --color-ink-line: var(--ink-line);
219
+ --color-chat: var(--nonla-chat-bg);
220
+
221
+ --shadow-card: none;
222
+ --shadow-whisper: none;
223
+ --shadow-button-outline: 0 0 0 1px var(--border);
224
+ --shadow-drop: 0 2px 8px color-mix(in oklab, var(--nonla-fg) 10%, transparent);
225
+ --shadow-panel: 0 0 0 1px var(--border), 0 4px 16px color-mix(in oklab, var(--nonla-fg) 10%, transparent);
226
+
227
+ --spacing-control-xs: 24px;
228
+ --spacing-control-sm: 28px;
229
+ --spacing-control-md: 32px;
230
+ --spacing-control-lg: 36px;
231
+ --spacing-nav-item: 32px;
232
+ --spacing-field-sm: 28px;
233
+ --spacing-field-md: 32px;
234
+ --spacing-field-lg: 36px;
235
+ --spacing-field-nav: 32px;
236
+ --spacing-desktop-bar: var(--nonla-desktop-bar-height);
237
+
238
+ /* --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; */
239
+ --font-sans: "ui-sans-serif", -apple-system, "system-ui", Segoe UI Variable Display, Segoe UI, Helvetica, Apple Color Emoji, Arial, "sans-serif", Segoe UI Emoji, Segoe UI Symbol;
240
+ --font-family-sans: var(--font-sans);
241
+ --default-font-family: var(--font-sans);
242
+
243
+ --text-2xs: 11px;
244
+ --text-2xs--line-height: 14px;
245
+ --text-xs: 12px;
246
+ --text-xs--line-height: 16px;
247
+ --text-sm: 13px;
248
+ --text-sm--line-height: 18px;
249
+ --text-md: 16px;
250
+ --text-md--line-height: 24px;
251
+ --text-base: 14px;
252
+ --text-base--line-height: 20px;
253
+ --text-lg: 18px;
254
+ --text-lg--line-height: 28px;
255
+ --text-xl: 24px;
256
+ --text-xl--line-height: 32px;
257
+ --text-2xl: 28px;
258
+ --text-2xl--line-height: 42px;
259
+
260
+ --animate-fadeIn: fadeIn 0.28s ease-out both;
261
+ }
262
+
263
+ @keyframes fadeIn {
264
+ from {
265
+ opacity: 0;
266
+ transform: translateY(4px);
267
+ }
268
+ to {
269
+ opacity: 1;
270
+ transform: translateY(0);
271
+ }
272
+ }
273
+
274
+ @keyframes nonla-chat-shimmer {
275
+ 0% {
276
+ background-position: 100% 0;
277
+ }
278
+ 100% {
279
+ background-position: -100% 0;
280
+ }
281
+ }
282
+
283
+ .nonla-chat-shimmer {
284
+ background-image: linear-gradient(90deg, var(--muted-foreground) 0%, var(--foreground) 45%, var(--muted-foreground) 90%);
285
+ background-size: 200% 100%;
286
+ background-clip: text;
287
+ -webkit-background-clip: text;
288
+ color: transparent;
289
+ animation: nonla-chat-shimmer 1.8s ease-in-out infinite;
290
+ }
291
+
292
+ @media (prefers-reduced-motion: reduce) {
293
+ .nonla-chat-shimmer {
294
+ animation: none;
295
+ background-image: none;
296
+ background-clip: border-box;
297
+ -webkit-background-clip: border-box;
298
+ color: var(--muted-foreground);
299
+ }
300
+ }
301
+
302
+ /* Toast host — top-center stack */
303
+ .nonla-message-host {
304
+ position: fixed;
305
+ top: 16px;
306
+ left: 50%;
307
+ transform: translateX(-50%);
308
+ z-index: 10000;
309
+ display: flex;
310
+ flex-direction: column;
311
+ align-items: center;
312
+ gap: 8px;
313
+ pointer-events: none;
314
+ max-width: min(420px, calc(100vw - 32px));
315
+ }
316
+
317
+ .nonla-message-item {
318
+ pointer-events: auto;
319
+ display: inline-flex;
320
+ align-items: center;
321
+ gap: 8px;
322
+ padding: 9px 12px;
323
+ border-radius: var(--radius);
324
+ font-size: 14px;
325
+ line-height: 1.5714;
326
+ animation: nonla-message-in var(--nonla-dur) var(--nonla-ease-out);
327
+ will-change: transform, opacity;
328
+ }
329
+
330
+ .nonla-message-item.is-leaving {
331
+ animation: nonla-message-out 150ms var(--nonla-ease-in) forwards;
332
+ }
333
+
334
+ .nonla-message-icon {
335
+ display: inline-flex;
336
+ flex-shrink: 0;
337
+ width: 16px;
338
+ height: 16px;
339
+ align-items: center;
340
+ justify-content: center;
341
+ }
342
+
343
+ .nonla-message-content {
344
+ min-width: 0;
345
+ word-break: break-word;
346
+ }
347
+
348
+ .nonla-message-spin {
349
+ animation: nonla-message-spin 0.8s linear infinite;
350
+ }
351
+
352
+ @keyframes nonla-message-in {
353
+ from {
354
+ opacity: 0;
355
+ transform: translateY(-8px) scale(0.98);
356
+ }
357
+ to {
358
+ opacity: 1;
359
+ transform: translateY(0) scale(1);
360
+ }
361
+ }
362
+
363
+ @keyframes nonla-message-out {
364
+ from {
365
+ opacity: 1;
366
+ transform: translateY(0) scale(1);
367
+ }
368
+ to {
369
+ opacity: 0;
370
+ transform: translateY(-6px) scale(0.98);
371
+ }
372
+ }
373
+
374
+ @keyframes nonla-message-spin {
375
+ to {
376
+ transform: rotate(360deg);
377
+ }
378
+ }
379
+
380
+ /* ── Spin: agent / subAgent (3×3 random snake — color only) ─────────────── */
381
+ .nonla-spin-matrix {
382
+ align-content: center;
383
+ justify-content: center;
384
+ }
385
+
386
+ .nonla-spin-matrix-cell {
387
+ display: block;
388
+ width: 100%;
389
+ height: 100%;
390
+ border-radius: 999px;
391
+ background: var(--nonla-chip-hover);
392
+ transition: background 120ms linear;
393
+ }
394
+
395
+ .nonla-spin-matrix-cell.is-on {
396
+ background: var(--nonla-ink);
397
+ }
398
+
399
+ @media (prefers-reduced-motion: reduce) {
400
+ .nonla-spin-matrix-cell {
401
+ transition: none;
402
+ }
403
+ }
404
+
405
+ @keyframes nonla-check-in {
406
+ from {
407
+ opacity: 0;
408
+ transform: scale(0.5);
409
+ }
410
+ to {
411
+ opacity: 1;
412
+ transform: scale(1);
413
+ }
414
+ }
415
+
416
+ @keyframes nonla-overlay-in {
417
+ from {
418
+ opacity: 0;
419
+ }
420
+ to {
421
+ opacity: 1;
422
+ }
423
+ }
424
+ @keyframes nonla-overlay-out {
425
+ from {
426
+ opacity: 1;
427
+ }
428
+ to {
429
+ opacity: 0;
430
+ }
431
+ }
432
+
433
+ /* shadcn-style zoom: fade + scale(0.95) ↔ 1 (no slide) */
434
+ @keyframes nonla-modal-in {
435
+ from {
436
+ opacity: 0;
437
+ transform: translate(-50%, 0) scale(0.95);
438
+ }
439
+ to {
440
+ opacity: 1;
441
+ transform: translate(-50%, 0) scale(1);
442
+ }
443
+ }
444
+ @keyframes nonla-modal-out {
445
+ from {
446
+ opacity: 1;
447
+ transform: translate(-50%, 0) scale(1);
448
+ }
449
+ to {
450
+ opacity: 0;
451
+ transform: translate(-50%, 0) scale(0.95);
452
+ }
453
+ }
454
+ @keyframes nonla-modal-in-centered {
455
+ from {
456
+ opacity: 0;
457
+ transform: translate(-50%, -50%) scale(0.95);
458
+ }
459
+ to {
460
+ opacity: 1;
461
+ transform: translate(-50%, -50%) scale(1);
462
+ }
463
+ }
464
+ @keyframes nonla-modal-out-centered {
465
+ from {
466
+ opacity: 1;
467
+ transform: translate(-50%, -50%) scale(1);
468
+ }
469
+ to {
470
+ opacity: 0;
471
+ transform: translate(-50%, -50%) scale(0.95);
472
+ }
473
+ }
474
+
475
+ @keyframes nonla-drawer-in-right {
476
+ from {
477
+ transform: translateX(100%);
478
+ }
479
+ to {
480
+ transform: translateX(0);
481
+ }
482
+ }
483
+ @keyframes nonla-drawer-out-right {
484
+ from {
485
+ transform: translateX(0);
486
+ }
487
+ to {
488
+ transform: translateX(100%);
489
+ }
490
+ }
491
+ @keyframes nonla-drawer-in-left {
492
+ from {
493
+ transform: translateX(-100%);
494
+ }
495
+ to {
496
+ transform: translateX(0);
497
+ }
498
+ }
499
+ @keyframes nonla-drawer-out-left {
500
+ from {
501
+ transform: translateX(0);
502
+ }
503
+ to {
504
+ transform: translateX(-100%);
505
+ }
506
+ }
507
+ @keyframes nonla-drawer-in-bottom {
508
+ from {
509
+ transform: translateY(100%);
510
+ }
511
+ to {
512
+ transform: translateY(0);
513
+ }
514
+ }
515
+ @keyframes nonla-drawer-out-bottom {
516
+ from {
517
+ transform: translateY(0);
518
+ }
519
+ to {
520
+ transform: translateY(100%);
521
+ }
522
+ }
523
+ @keyframes nonla-drawer-in-top {
524
+ from {
525
+ transform: translateY(-100%);
526
+ }
527
+ to {
528
+ transform: translateY(0);
529
+ }
530
+ }
531
+ @keyframes nonla-drawer-out-top {
532
+ from {
533
+ transform: translateY(0);
534
+ }
535
+ to {
536
+ transform: translateY(-100%);
537
+ }
538
+ }
539
+
540
+ /* Direction-aware popper (Popover / Select / Dropdown / Tooltip) */
541
+ @keyframes nonla-pop-in-top {
542
+ from {
543
+ opacity: 0;
544
+ transform: translateY(6px) scale(0.96);
545
+ }
546
+ to {
547
+ opacity: 1;
548
+ transform: translateY(0) scale(1);
549
+ }
550
+ }
551
+ @keyframes nonla-pop-in-bottom {
552
+ from {
553
+ opacity: 0;
554
+ transform: translateY(-6px) scale(0.96);
555
+ }
556
+ to {
557
+ opacity: 1;
558
+ transform: translateY(0) scale(1);
559
+ }
560
+ }
561
+ @keyframes nonla-pop-in-left {
562
+ from {
563
+ opacity: 0;
564
+ transform: translateX(6px) scale(0.96);
565
+ }
566
+ to {
567
+ opacity: 1;
568
+ transform: translateX(0) scale(1);
569
+ }
570
+ }
571
+ @keyframes nonla-pop-in-right {
572
+ from {
573
+ opacity: 0;
574
+ transform: translateX(-6px) scale(0.96);
575
+ }
576
+ to {
577
+ opacity: 1;
578
+ transform: translateX(0) scale(1);
579
+ }
580
+ }
581
+ @keyframes nonla-pop-out {
582
+ from {
583
+ opacity: 1;
584
+ transform: scale(1);
585
+ }
586
+ to {
587
+ opacity: 0;
588
+ transform: scale(0.96);
589
+ }
590
+ }
591
+
592
+ /* Frosted overlay — macOS menu chrome: outer hairline + inner white rim */
593
+ .nonla-glass {
594
+ border: 1px solid rgb(255 255 255 / 0.78);
595
+ background: var(--glass);
596
+ color: var(--foreground);
597
+ box-shadow:
598
+ 0 0 0 0.5px color-mix(in srgb, black 22%, transparent),
599
+ 0 10px 28px color-mix(in srgb, black 14%, transparent),
600
+ inset 0 0 0 0.5px rgb(255 255 255 / 0.55),
601
+ inset 0 1px 0 rgb(255 255 255 / 0.92);
602
+ -webkit-backdrop-filter: blur(24px) saturate(160%);
603
+ backdrop-filter: blur(24px) saturate(160%);
604
+ }
605
+
606
+ .nonla-btn-glass {
607
+ border-color: var(--glass-border);
608
+ background: var(--glass);
609
+ box-shadow: inset 0 1px 0 var(--glass-highlight);
610
+ -webkit-backdrop-filter: blur(24px);
611
+ backdrop-filter: blur(24px);
612
+ transition: box-shadow var(--nonla-dur-fast) var(--nonla-ease-out), transform var(--nonla-dur-fast) var(--nonla-ease-out);
613
+ }
614
+ .nonla-btn-glass:hover:not(:disabled):not([aria-disabled]) {
615
+ box-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 0 0 999px var(--ink-hover);
616
+ }
617
+ .nonla-btn-glass:active:not(:disabled):not([aria-disabled]) {
618
+ transform: scale(0.98);
619
+ box-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 0 0 999px var(--ink-active);
620
+ }
621
+
622
+ /* Nested glass chip — hover is frost only; selected tints with brand */
623
+ .nonla-glass-chip,
624
+ .nonla-menu-item[data-highlighted] {
625
+ background: var(--glass-bar);
626
+ border-color: var(--glass-border);
627
+ -webkit-backdrop-filter: blur(24px);
628
+ backdrop-filter: blur(24px);
629
+ }
630
+ .nonla-glass-chip-on {
631
+ background: var(--glass-bar);
632
+ border-color: color-mix(in oklab, var(--brand) 38%, var(--glass-border));
633
+ box-shadow: inset 0 0 0 999px color-mix(in oklab, var(--brand) 18%, transparent);
634
+ -webkit-backdrop-filter: blur(24px);
635
+ backdrop-filter: blur(24px);
636
+ }
637
+ @media (prefers-reduced-motion: reduce) {
638
+ .nonla-btn-glass {
639
+ transition: box-shadow var(--nonla-dur-fast) var(--nonla-ease-out);
640
+ }
641
+ .nonla-btn-glass:active:not(:disabled):not([aria-disabled]) {
642
+ transform: none;
643
+ }
644
+ }
645
+
646
+ .nonla-overlay {
647
+ position: fixed;
648
+ inset: 0;
649
+ background: var(--mask);
650
+ }
651
+ .nonla-overlay[data-state="open"] {
652
+ animation: nonla-overlay-in var(--nonla-dur) var(--nonla-ease-out);
653
+ }
654
+ .nonla-overlay[data-state="closed"] {
655
+ animation: nonla-overlay-out var(--nonla-dur-fast) var(--nonla-ease-in);
656
+ }
657
+
658
+ .nonla-modal-overlay {
659
+ position: fixed;
660
+ inset: 0;
661
+ z-index: 9990;
662
+ background: var(--mask);
663
+ }
664
+ .nonla-modal-overlay[data-state="open"] {
665
+ animation: nonla-overlay-in var(--nonla-dur) var(--nonla-ease-out);
666
+ }
667
+ .nonla-modal-overlay[data-state="closed"] {
668
+ animation: nonla-overlay-out var(--nonla-dur-fast) var(--nonla-ease-in) forwards;
669
+ pointer-events: none;
670
+ }
671
+
672
+ .nonla-modal-content {
673
+ position: fixed;
674
+ left: 50%;
675
+ top: 60px;
676
+ z-index: 9991;
677
+ transform: translate(-50%, 0);
678
+ display: flex;
679
+ flex-direction: column;
680
+ width: min(480px, calc(100vw - 32px));
681
+ max-height: calc(100vh - 88px);
682
+ overflow: hidden;
683
+ border-radius: calc(var(--radius) + 4px);
684
+ padding: 0;
685
+ outline: none;
686
+ will-change: transform, opacity;
687
+ }
688
+ .nonla-modal-content[data-state="open"] {
689
+ animation: nonla-modal-in var(--nonla-dur) var(--nonla-ease-out);
690
+ }
691
+ .nonla-modal-content[data-state="closed"] {
692
+ animation: nonla-modal-out var(--nonla-dur-fast) var(--nonla-ease-in) forwards;
693
+ pointer-events: none;
694
+ }
695
+ .nonla-modal-content[data-centered="true"] {
696
+ top: 50%;
697
+ transform: translate(-50%, -50%);
698
+ max-height: calc(100vh - 64px);
699
+ }
700
+ .nonla-modal-content[data-centered="true"][data-state="open"] {
701
+ animation: nonla-modal-in-centered var(--nonla-dur) var(--nonla-ease-out);
702
+ }
703
+ .nonla-modal-content[data-centered="true"][data-state="closed"] {
704
+ animation: nonla-modal-out-centered var(--nonla-dur-fast) var(--nonla-ease-in) forwards;
705
+ pointer-events: none;
706
+ }
707
+
708
+ .nonla-modal-header {
709
+ display: flex;
710
+ align-items: center;
711
+ justify-content: space-between;
712
+ gap: 12px;
713
+ flex-shrink: 0;
714
+ padding: 12px 16px;
715
+ background: transparent;
716
+ }
717
+ .nonla-modal-title {
718
+ margin: 0;
719
+ font-size: 15px;
720
+ font-weight: 600;
721
+ line-height: 1.4;
722
+ color: var(--foreground);
723
+ }
724
+ .nonla-modal-close {
725
+ display: inline-flex;
726
+ align-items: center;
727
+ justify-content: center;
728
+ width: 28px;
729
+ height: 28px;
730
+ margin: -4px -6px -4px 0;
731
+ border: 0;
732
+ border-radius: var(--radius);
733
+ background: transparent;
734
+ color: var(--muted-foreground);
735
+ font-size: 18px;
736
+ line-height: 1;
737
+ cursor: pointer;
738
+ }
739
+ .nonla-modal-close:hover {
740
+ color: var(--foreground);
741
+ background: var(--control-bg);
742
+ }
743
+ .nonla-modal-body {
744
+ flex: 1 1 auto;
745
+ overflow: auto;
746
+ padding: 16px 16px 24px;
747
+ font-size: 14px;
748
+ line-height: 1.5;
749
+ color: var(--foreground);
750
+ background: transparent;
751
+ }
752
+ .nonla-modal-footer {
753
+ display: flex;
754
+ align-items: center;
755
+ justify-content: flex-end;
756
+ gap: 8px;
757
+ flex-shrink: 0;
758
+ padding: 10px 16px;
759
+ background: transparent;
760
+ }
761
+
762
+ .nonla-drawer-panel {
763
+ will-change: transform;
764
+ }
765
+ .nonla-drawer-panel[data-side="right"][data-state="open"] {
766
+ animation: nonla-drawer-in-right var(--nonla-dur-slow) var(--nonla-ease-out);
767
+ }
768
+ .nonla-drawer-panel[data-side="right"][data-state="closed"] {
769
+ animation: nonla-drawer-out-right var(--nonla-dur) var(--nonla-ease-in);
770
+ }
771
+ .nonla-drawer-panel[data-side="left"][data-state="open"] {
772
+ animation: nonla-drawer-in-left var(--nonla-dur-slow) var(--nonla-ease-out);
773
+ }
774
+ .nonla-drawer-panel[data-side="left"][data-state="closed"] {
775
+ animation: nonla-drawer-out-left var(--nonla-dur) var(--nonla-ease-in);
776
+ }
777
+ .nonla-drawer-panel[data-side="bottom"][data-state="open"] {
778
+ animation: nonla-drawer-in-bottom var(--nonla-dur-slow) var(--nonla-ease-out);
779
+ }
780
+ .nonla-drawer-panel[data-side="bottom"][data-state="closed"] {
781
+ animation: nonla-drawer-out-bottom var(--nonla-dur) var(--nonla-ease-in);
782
+ }
783
+ .nonla-drawer-panel[data-side="top"][data-state="open"] {
784
+ animation: nonla-drawer-in-top var(--nonla-dur-slow) var(--nonla-ease-out);
785
+ }
786
+ .nonla-drawer-panel[data-side="top"][data-state="closed"] {
787
+ animation: nonla-drawer-out-top var(--nonla-dur) var(--nonla-ease-in);
788
+ }
789
+
790
+ .nonla-popper {
791
+ will-change: transform, opacity;
792
+ transform-origin: var(--radix-popover-content-transform-origin, var(--radix-dropdown-menu-content-transform-origin, var(--radix-select-content-transform-origin, var(--radix-tooltip-content-transform-origin, center))));
793
+ }
794
+ .nonla-popper[data-state="open"][data-side="top"] {
795
+ animation: nonla-pop-in-top var(--nonla-dur-fast) var(--nonla-ease-out);
796
+ }
797
+ .nonla-popper[data-state="open"][data-side="bottom"] {
798
+ animation: nonla-pop-in-bottom var(--nonla-dur-fast) var(--nonla-ease-out);
799
+ }
800
+ .nonla-popper[data-state="open"][data-side="left"] {
801
+ animation: nonla-pop-in-left var(--nonla-dur-fast) var(--nonla-ease-out);
802
+ }
803
+ .nonla-popper[data-state="open"][data-side="right"] {
804
+ animation: nonla-pop-in-right var(--nonla-dur-fast) var(--nonla-ease-out);
805
+ }
806
+ .nonla-popper[data-state="open"]:not([data-side]) {
807
+ animation: nonla-pop-in-bottom var(--nonla-dur-fast) var(--nonla-ease-out);
808
+ }
809
+ .nonla-popper[data-state="closed"] {
810
+ animation: nonla-pop-out 100ms var(--nonla-ease-in);
811
+ }
812
+
813
+ .nonla-codeblock-pre code,
814
+ .nonla-codeblock-pre .hljs {
815
+ color: var(--foreground);
816
+ background: transparent;
817
+ }
818
+
819
+ .nonla-codeblock-pre .hljs-line {
820
+ display: inline-block;
821
+ min-width: 100%;
822
+ min-height: 1.65em;
823
+ }
824
+ .nonla-codeblock-pre:not(.whitespace-pre-wrap) .hljs-line {
825
+ width: max-content;
826
+ }
827
+ .nonla-codeblock-pre.whitespace-pre-wrap .hljs-line {
828
+ width: 100%;
829
+ }
830
+
831
+ .nonla-codeblock-lines code {
832
+ counter-reset: nonla-code-line;
833
+ }
834
+
835
+ .nonla-codeblock-lines .hljs-line::before {
836
+ counter-increment: nonla-code-line;
837
+ content: counter(nonla-code-line);
838
+ display: inline-block;
839
+ width: 1.75rem;
840
+ margin-right: 1rem;
841
+ text-align: right;
842
+ color: var(--quaternary-foreground);
843
+ user-select: none;
844
+ font-size: 11px;
845
+ }
846
+
847
+ .nonla-scroll-hidden {
848
+ scrollbar-width: none;
849
+ -ms-overflow-style: none;
850
+ }
851
+ .nonla-scroll-hidden::-webkit-scrollbar {
852
+ display: none;
853
+ width: 0;
854
+ height: 0;
855
+ }
856
+
857
+ * {
858
+ scrollbar-width: thin;
859
+ scrollbar-color: var(--nonla-scrollbar-thumb) transparent;
860
+ }
861
+ ::-webkit-scrollbar {
862
+ width: var(--nonla-scrollbar-size);
863
+ height: var(--nonla-scrollbar-size);
864
+ }
865
+ ::-webkit-scrollbar-track {
866
+ background: transparent;
867
+ }
868
+ ::-webkit-scrollbar-thumb {
869
+ background: var(--nonla-scrollbar-thumb);
870
+ border-radius: 99px;
871
+ }
872
+ ::-webkit-scrollbar-thumb:hover {
873
+ background: var(--nonla-scrollbar-thumb-hover);
874
+ }
875
+
876
+ .nonla-scroll-hover {
877
+ scrollbar-color: transparent transparent;
878
+ }
879
+ .nonla-scroll-hover:hover {
880
+ scrollbar-color: var(--nonla-scrollbar-thumb) transparent;
881
+ }
882
+ .nonla-scroll-hover::-webkit-scrollbar-thumb {
883
+ background: transparent;
884
+ }
885
+ .nonla-scroll-hover:hover::-webkit-scrollbar-thumb {
886
+ background: var(--nonla-scrollbar-thumb);
887
+ }
888
+ .nonla-scroll-hover:hover::-webkit-scrollbar-thumb:hover {
889
+ background: var(--nonla-scrollbar-thumb-hover);
890
+ }
891
+
892
+ .nonla-overlay-thumb {
893
+ background: var(--nonla-scrollbar-thumb);
894
+ }
895
+ .group\/scroll:hover .nonla-overlay-thumb {
896
+ background: var(--nonla-scrollbar-thumb-hover);
897
+ }