@odla-ai/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.
- package/README.md +88 -0
- package/css/components/buttons.css +118 -0
- package/css/components/cards.css +66 -0
- package/css/components/chart.css +24 -0
- package/css/components/chat.css +167 -0
- package/css/components/feedback.css +77 -0
- package/css/components/forms.css +132 -0
- package/css/components/nav.css +96 -0
- package/css/components/table.css +34 -0
- package/css/tokens.css +138 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/fonts/editorial.css +46 -0
- package/fonts/fira-code.css +2 -0
- package/fonts/lora.css +2 -0
- package/fonts/plex.css +4 -0
- package/fonts/satoshi.css +2 -0
- package/fonts/system.css +3 -0
- package/index.css +14 -0
- package/js/canvas.js +113 -0
- package/js/index.js +24 -0
- package/js/palette.js +37 -0
- package/js/theme.js +51 -0
- package/js/tokens.js +104 -0
- package/llms.txt +201 -0
- package/odla-ui.css +863 -0
- package/package.json +73 -0
- package/themes/chalk/styles.css +720 -0
- package/themes/chalk/theme.json +6 -0
- package/themes/chalk/ui.css +51 -0
- package/themes/clay/styles.css +726 -0
- package/themes/clay/theme.json +6 -0
- package/themes/clay/ui.css +40 -0
- package/themes/juniper/styles.css +660 -0
- package/themes/juniper/theme.json +6 -0
- package/themes/juniper/ui.css +50 -0
- package/themes/paper/styles.css +129 -0
- package/themes/paper/theme.json +6 -0
- package/themes/paper/ui.css +30 -0
- package/themes/salt/styles.css +728 -0
- package/themes/salt/theme.json +6 -0
- package/themes/salt/ui.css +48 -0
package/odla-ui.css
ADDED
|
@@ -0,0 +1,863 @@
|
|
|
1
|
+
/* odla-ui.css — GENERATED from index.css by scripts/gen-css.mjs; do not edit.
|
|
2
|
+
Flattened (no @imports) so it can be copied/served as a single file. */
|
|
3
|
+
|
|
4
|
+
/* ══════════════════════════════════════════════════════════════
|
|
5
|
+
@odla-ai/ui — token defaults
|
|
6
|
+
Every block is wrapped in :where() so it has ZERO specificity:
|
|
7
|
+
a theme's plain `:root { … }` definitions always win, regardless
|
|
8
|
+
of stylesheet load order. Without a theme, these neutral values
|
|
9
|
+
(grayscale + restrained blue) render sanely on their own.
|
|
10
|
+
Contract data lives in js/tokens.js; themes map their palettes
|
|
11
|
+
onto the required tier in themes/<name>/ui.css.
|
|
12
|
+
══════════════════════════════════════════════════════════════ */
|
|
13
|
+
|
|
14
|
+
:where(:root) {
|
|
15
|
+
/* ─── Required tier: neutral fallbacks (themes override all of these) ─── */
|
|
16
|
+
--ui-bg: #f7f7f5;
|
|
17
|
+
--ui-surface: #ffffff;
|
|
18
|
+
--ui-surface-2: #efefec;
|
|
19
|
+
--ui-text: #24272b;
|
|
20
|
+
--ui-text-muted: #64686e;
|
|
21
|
+
--ui-text-faint: #9b9fa6;
|
|
22
|
+
--ui-border: #dfe0dc;
|
|
23
|
+
--ui-border-strong: #b9bbb5;
|
|
24
|
+
--ui-accent: #3b5e8c;
|
|
25
|
+
--ui-accent-strong: #2e4a70;
|
|
26
|
+
--ui-accent-soft: rgba(59, 94, 140, 0.1);
|
|
27
|
+
--ui-on-accent: #ffffff;
|
|
28
|
+
--ui-good: #4a7c59;
|
|
29
|
+
--ui-good-soft: rgba(74, 124, 89, 0.12);
|
|
30
|
+
--ui-warn: #a07d2e;
|
|
31
|
+
--ui-warn-soft: rgba(160, 125, 46, 0.12);
|
|
32
|
+
--ui-danger: #a8433a;
|
|
33
|
+
--ui-danger-soft: rgba(168, 67, 58, 0.1);
|
|
34
|
+
--ui-code-bg: #efefec;
|
|
35
|
+
--ui-code-text: #33363b;
|
|
36
|
+
--ui-shadow: 0 1px 2px rgba(36, 39, 43, 0.04), 0 8px 24px rgba(36, 39, 43, 0.06);
|
|
37
|
+
--ui-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
38
|
+
--ui-font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
|
|
39
|
+
--ui-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
40
|
+
--ui-font-display: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
41
|
+
|
|
42
|
+
/* ─── Defaulted tier: universal scales ─── */
|
|
43
|
+
--ui-space-1: 4px;
|
|
44
|
+
--ui-space-2: 8px;
|
|
45
|
+
--ui-space-3: 12px;
|
|
46
|
+
--ui-space-4: 16px;
|
|
47
|
+
--ui-space-5: 24px;
|
|
48
|
+
--ui-space-6: 32px;
|
|
49
|
+
--ui-space-7: 48px;
|
|
50
|
+
--ui-space-8: 64px;
|
|
51
|
+
--ui-radius-sm: 4px;
|
|
52
|
+
--ui-radius-md: 7px;
|
|
53
|
+
--ui-radius-lg: 10px;
|
|
54
|
+
--ui-radius-pill: 999px;
|
|
55
|
+
--ui-text-xs: 11px;
|
|
56
|
+
--ui-text-sm: 12px;
|
|
57
|
+
--ui-text-md: 13px;
|
|
58
|
+
--ui-text-lg: 15px;
|
|
59
|
+
--ui-tracking-caps: 0.06em;
|
|
60
|
+
--ui-focus: 0 0 0 3px var(--ui-accent-soft);
|
|
61
|
+
|
|
62
|
+
/* ─── Chart roles (derived; themes may override for richer palettes) ─── */
|
|
63
|
+
--ui-chart-1: var(--ui-accent);
|
|
64
|
+
--ui-chart-2: var(--ui-good);
|
|
65
|
+
--ui-chart-3: var(--ui-warn);
|
|
66
|
+
--ui-chart-4: var(--ui-danger);
|
|
67
|
+
--ui-chart-5: color-mix(in srgb, var(--ui-accent) 45%, var(--ui-text));
|
|
68
|
+
--ui-chart-6: var(--ui-text-faint);
|
|
69
|
+
--ui-chart-grid: color-mix(in srgb, var(--ui-text) 8%, transparent);
|
|
70
|
+
--ui-chart-grid-zero: color-mix(in srgb, var(--ui-text) 22%, transparent);
|
|
71
|
+
--ui-chart-axis: var(--ui-text-muted);
|
|
72
|
+
--ui-chart-axis-faint: var(--ui-text-faint);
|
|
73
|
+
--ui-chart-band: color-mix(in srgb, var(--ui-accent) 10%, transparent);
|
|
74
|
+
--ui-chart-band-strong: color-mix(in srgb, var(--ui-accent) 22%, transparent);
|
|
75
|
+
--ui-chart-pos: var(--ui-good);
|
|
76
|
+
--ui-chart-neg: var(--ui-danger);
|
|
77
|
+
--ui-chart-tip-bg: color-mix(in srgb, var(--ui-text) 92%, transparent);
|
|
78
|
+
--ui-chart-tip-text: var(--ui-bg);
|
|
79
|
+
--ui-chart-dot-stroke: var(--ui-bg);
|
|
80
|
+
|
|
81
|
+
/* ─── Chat roles (derived) ─── */
|
|
82
|
+
--ui-chat-user-bg: var(--ui-accent-soft);
|
|
83
|
+
--ui-chat-user-text: var(--ui-text);
|
|
84
|
+
--ui-chat-assistant-bg: var(--ui-surface);
|
|
85
|
+
--ui-chat-thinking-bg: var(--ui-surface-2);
|
|
86
|
+
--ui-chat-thinking-text: var(--ui-text-muted);
|
|
87
|
+
--ui-chat-tool-accent: var(--ui-accent);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Neutral dark fallbacks — only the required tier changes; the derived
|
|
91
|
+
tiers track it automatically via var()/color-mix(). Themes that define
|
|
92
|
+
their own dark palettes override these the same zero-specificity way. */
|
|
93
|
+
:where([data-theme="dark"]) {
|
|
94
|
+
--ui-bg: #17181b;
|
|
95
|
+
--ui-surface: #1f2125;
|
|
96
|
+
--ui-surface-2: #26282d;
|
|
97
|
+
--ui-text: #e6e6e3;
|
|
98
|
+
--ui-text-muted: #a2a6ad;
|
|
99
|
+
--ui-text-faint: #6f737a;
|
|
100
|
+
--ui-border: #33363c;
|
|
101
|
+
--ui-border-strong: #4a4e56;
|
|
102
|
+
--ui-accent: #7ba1d4;
|
|
103
|
+
--ui-accent-strong: #97b7e2;
|
|
104
|
+
--ui-accent-soft: rgba(123, 161, 212, 0.14);
|
|
105
|
+
--ui-on-accent: #14161a;
|
|
106
|
+
--ui-good: #7fae8e;
|
|
107
|
+
--ui-good-soft: rgba(127, 174, 142, 0.14);
|
|
108
|
+
--ui-warn: #c5a75e;
|
|
109
|
+
--ui-warn-soft: rgba(197, 167, 94, 0.14);
|
|
110
|
+
--ui-danger: #cf7a72;
|
|
111
|
+
--ui-danger-soft: rgba(207, 122, 114, 0.14);
|
|
112
|
+
--ui-code-bg: #26282d;
|
|
113
|
+
--ui-code-text: #d4d5d2;
|
|
114
|
+
--ui-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (prefers-color-scheme: dark) {
|
|
118
|
+
:where(:root:not([data-theme="light"])) {
|
|
119
|
+
--ui-bg: #17181b;
|
|
120
|
+
--ui-surface: #1f2125;
|
|
121
|
+
--ui-surface-2: #26282d;
|
|
122
|
+
--ui-text: #e6e6e3;
|
|
123
|
+
--ui-text-muted: #a2a6ad;
|
|
124
|
+
--ui-text-faint: #6f737a;
|
|
125
|
+
--ui-border: #33363c;
|
|
126
|
+
--ui-border-strong: #4a4e56;
|
|
127
|
+
--ui-accent: #7ba1d4;
|
|
128
|
+
--ui-accent-strong: #97b7e2;
|
|
129
|
+
--ui-accent-soft: rgba(123, 161, 212, 0.14);
|
|
130
|
+
--ui-on-accent: #14161a;
|
|
131
|
+
--ui-good: #7fae8e;
|
|
132
|
+
--ui-good-soft: rgba(127, 174, 142, 0.14);
|
|
133
|
+
--ui-warn: #c5a75e;
|
|
134
|
+
--ui-warn-soft: rgba(197, 167, 94, 0.14);
|
|
135
|
+
--ui-danger: #cf7a72;
|
|
136
|
+
--ui-danger-soft: rgba(207, 122, 114, 0.14);
|
|
137
|
+
--ui-code-bg: #26282d;
|
|
138
|
+
--ui-code-text: #d4d5d2;
|
|
139
|
+
--ui-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* @odla-ai/ui — buttons & controls
|
|
144
|
+
Class-scoped by design: no bare-element rules, so these sheets coexist
|
|
145
|
+
with themes (e.g. blog themes) that style bare elements themselves.
|
|
146
|
+
`.btn` alone renders the primary variant; modifiers chain (.btn.ghost). */
|
|
147
|
+
|
|
148
|
+
.btn {
|
|
149
|
+
font: inherit;
|
|
150
|
+
font-weight: 600;
|
|
151
|
+
background: var(--ui-accent);
|
|
152
|
+
color: var(--ui-on-accent);
|
|
153
|
+
border: 0;
|
|
154
|
+
padding: 7px 13px;
|
|
155
|
+
border-radius: var(--ui-radius-md);
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
display: inline-flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
gap: 6px;
|
|
161
|
+
text-decoration: none;
|
|
162
|
+
}
|
|
163
|
+
.btn:hover { background: var(--ui-accent-strong); }
|
|
164
|
+
.btn:focus-visible { outline: none; box-shadow: var(--ui-focus); }
|
|
165
|
+
.btn:disabled { opacity: 0.45; cursor: default; }
|
|
166
|
+
|
|
167
|
+
.btn.secondary {
|
|
168
|
+
background: var(--ui-surface);
|
|
169
|
+
color: var(--ui-text);
|
|
170
|
+
border: 1px solid var(--ui-border);
|
|
171
|
+
}
|
|
172
|
+
.btn.secondary:hover { background: var(--ui-surface-2); }
|
|
173
|
+
|
|
174
|
+
.btn.ghost {
|
|
175
|
+
background: transparent;
|
|
176
|
+
color: var(--ui-accent);
|
|
177
|
+
border: 0;
|
|
178
|
+
}
|
|
179
|
+
.btn.ghost:hover { background: var(--ui-accent-soft); }
|
|
180
|
+
|
|
181
|
+
.btn.danger { background: var(--ui-danger); color: var(--ui-on-accent); }
|
|
182
|
+
.btn.danger:hover { background: color-mix(in srgb, var(--ui-danger) 82%, var(--ui-text)); }
|
|
183
|
+
|
|
184
|
+
.btn.mini { padding: 3px 9px; font-size: var(--ui-text-sm); }
|
|
185
|
+
|
|
186
|
+
/* Segmented control: a strip of buttons, one active (.on). */
|
|
187
|
+
.seg {
|
|
188
|
+
display: inline-flex;
|
|
189
|
+
border: 1px solid var(--ui-border);
|
|
190
|
+
border-radius: var(--ui-radius-md);
|
|
191
|
+
background: var(--ui-surface);
|
|
192
|
+
overflow: hidden;
|
|
193
|
+
}
|
|
194
|
+
.seg button {
|
|
195
|
+
font: inherit;
|
|
196
|
+
font-size: var(--ui-text-md);
|
|
197
|
+
background: transparent;
|
|
198
|
+
color: var(--ui-text-muted);
|
|
199
|
+
border: 0;
|
|
200
|
+
padding: 6px 12px;
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
}
|
|
203
|
+
.seg button + button { border-left: 1px solid var(--ui-border); }
|
|
204
|
+
.seg button:hover { color: var(--ui-text); }
|
|
205
|
+
.seg button.on,
|
|
206
|
+
.seg button[aria-pressed="true"] {
|
|
207
|
+
background: var(--ui-accent-soft);
|
|
208
|
+
color: var(--ui-accent-strong);
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Underlined tab bar; the active tab carries .on (or aria-selected). */
|
|
213
|
+
.tabs {
|
|
214
|
+
display: flex;
|
|
215
|
+
gap: var(--ui-space-4);
|
|
216
|
+
border-bottom: 1px solid var(--ui-border);
|
|
217
|
+
}
|
|
218
|
+
.tabs button {
|
|
219
|
+
font: inherit;
|
|
220
|
+
font-size: var(--ui-text-md);
|
|
221
|
+
background: transparent;
|
|
222
|
+
color: var(--ui-text-muted);
|
|
223
|
+
border: 0;
|
|
224
|
+
border-bottom: 2px solid transparent;
|
|
225
|
+
margin-bottom: -1px;
|
|
226
|
+
padding: 8px 2px;
|
|
227
|
+
cursor: pointer;
|
|
228
|
+
}
|
|
229
|
+
.tabs button:hover { color: var(--ui-text); }
|
|
230
|
+
.tabs button.on,
|
|
231
|
+
.tabs button[aria-selected="true"] {
|
|
232
|
+
color: var(--ui-text);
|
|
233
|
+
border-bottom-color: var(--ui-accent);
|
|
234
|
+
font-weight: 600;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* Status/metadata pill: quiet, mono, rounded. */
|
|
238
|
+
.pill {
|
|
239
|
+
font-family: var(--ui-font-mono);
|
|
240
|
+
font-size: var(--ui-text-sm);
|
|
241
|
+
background: var(--ui-surface-2);
|
|
242
|
+
border: 1px solid var(--ui-border);
|
|
243
|
+
padding: 3px 9px;
|
|
244
|
+
border-radius: var(--ui-radius-pill);
|
|
245
|
+
color: var(--ui-text-muted);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Interactive chip (link chips, removable filters). */
|
|
249
|
+
.chip {
|
|
250
|
+
font-family: var(--ui-font-mono);
|
|
251
|
+
font-size: var(--ui-text-xs);
|
|
252
|
+
padding: 2px 7px;
|
|
253
|
+
margin: 1px 3px 1px 0;
|
|
254
|
+
border-radius: 6px;
|
|
255
|
+
background: var(--ui-accent-soft);
|
|
256
|
+
border: 1px solid var(--ui-border);
|
|
257
|
+
color: var(--ui-accent-strong);
|
|
258
|
+
cursor: pointer;
|
|
259
|
+
}
|
|
260
|
+
.chip:hover { border-color: var(--ui-accent); }
|
|
261
|
+
|
|
262
|
+
/* @odla-ai/ui — form fields
|
|
263
|
+
.input/.select/.textarea are the class equivalents of themed bare
|
|
264
|
+
elements; .field wraps a label + control + error/hint. */
|
|
265
|
+
|
|
266
|
+
.input,
|
|
267
|
+
.select,
|
|
268
|
+
.textarea {
|
|
269
|
+
font: inherit;
|
|
270
|
+
font-size: var(--ui-text-md);
|
|
271
|
+
background: var(--ui-surface);
|
|
272
|
+
color: var(--ui-text);
|
|
273
|
+
border: 1px solid var(--ui-border);
|
|
274
|
+
border-radius: var(--ui-radius-md);
|
|
275
|
+
padding: 8px 10px;
|
|
276
|
+
width: 100%;
|
|
277
|
+
}
|
|
278
|
+
.input:focus,
|
|
279
|
+
.select:focus,
|
|
280
|
+
.textarea:focus {
|
|
281
|
+
outline: none;
|
|
282
|
+
border-color: var(--ui-accent);
|
|
283
|
+
box-shadow: var(--ui-focus);
|
|
284
|
+
}
|
|
285
|
+
.input::placeholder,
|
|
286
|
+
.textarea::placeholder { color: var(--ui-text-faint); }
|
|
287
|
+
.input:disabled,
|
|
288
|
+
.select:disabled,
|
|
289
|
+
.textarea:disabled { opacity: 0.55; cursor: default; }
|
|
290
|
+
|
|
291
|
+
.textarea {
|
|
292
|
+
font-family: var(--ui-font-mono);
|
|
293
|
+
resize: vertical;
|
|
294
|
+
min-height: 72px;
|
|
295
|
+
}
|
|
296
|
+
.textarea.prose-input { font-family: inherit; }
|
|
297
|
+
|
|
298
|
+
.input.invalid,
|
|
299
|
+
.select.invalid,
|
|
300
|
+
.textarea.invalid,
|
|
301
|
+
.input[aria-invalid="true"],
|
|
302
|
+
.select[aria-invalid="true"],
|
|
303
|
+
.textarea[aria-invalid="true"] {
|
|
304
|
+
border-color: var(--ui-danger);
|
|
305
|
+
}
|
|
306
|
+
.input.invalid:focus,
|
|
307
|
+
.select.invalid:focus,
|
|
308
|
+
.textarea.invalid:focus,
|
|
309
|
+
.input[aria-invalid="true"]:focus,
|
|
310
|
+
.select[aria-invalid="true"]:focus,
|
|
311
|
+
.textarea[aria-invalid="true"]:focus {
|
|
312
|
+
box-shadow: 0 0 0 3px var(--ui-danger-soft);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* Field wrapper: label above control, error/hint below. */
|
|
316
|
+
.field { margin: 0 0 var(--ui-space-4); }
|
|
317
|
+
.field-label {
|
|
318
|
+
display: block;
|
|
319
|
+
font-size: var(--ui-text-xs);
|
|
320
|
+
text-transform: uppercase;
|
|
321
|
+
letter-spacing: var(--ui-tracking-caps);
|
|
322
|
+
color: var(--ui-text-muted);
|
|
323
|
+
margin: 0 0 4px;
|
|
324
|
+
}
|
|
325
|
+
.field-error { color: var(--ui-danger); font-size: var(--ui-text-md); margin: 4px 0 0; }
|
|
326
|
+
.field-hint { color: var(--ui-text-faint); font-size: var(--ui-text-sm); margin: 4px 0 0; }
|
|
327
|
+
|
|
328
|
+
/* Checkbox/radio with label. */
|
|
329
|
+
.check {
|
|
330
|
+
display: flex;
|
|
331
|
+
align-items: center;
|
|
332
|
+
gap: var(--ui-space-2);
|
|
333
|
+
cursor: pointer;
|
|
334
|
+
font-size: var(--ui-text-md);
|
|
335
|
+
}
|
|
336
|
+
.check input {
|
|
337
|
+
accent-color: var(--ui-accent);
|
|
338
|
+
width: 15px;
|
|
339
|
+
height: 15px;
|
|
340
|
+
margin: 0;
|
|
341
|
+
flex: 0 0 auto;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Styled range slider. */
|
|
345
|
+
.range {
|
|
346
|
+
-webkit-appearance: none;
|
|
347
|
+
appearance: none;
|
|
348
|
+
width: 100%;
|
|
349
|
+
height: 4px;
|
|
350
|
+
border-radius: var(--ui-radius-pill);
|
|
351
|
+
background: var(--ui-border);
|
|
352
|
+
outline: none;
|
|
353
|
+
}
|
|
354
|
+
.range::-webkit-slider-thumb {
|
|
355
|
+
-webkit-appearance: none;
|
|
356
|
+
appearance: none;
|
|
357
|
+
width: 14px;
|
|
358
|
+
height: 14px;
|
|
359
|
+
border-radius: 50%;
|
|
360
|
+
background: var(--ui-accent);
|
|
361
|
+
border: 2px solid var(--ui-surface);
|
|
362
|
+
cursor: pointer;
|
|
363
|
+
}
|
|
364
|
+
.range::-moz-range-thumb {
|
|
365
|
+
width: 14px;
|
|
366
|
+
height: 14px;
|
|
367
|
+
border-radius: 50%;
|
|
368
|
+
background: var(--ui-accent);
|
|
369
|
+
border: 2px solid var(--ui-surface);
|
|
370
|
+
cursor: pointer;
|
|
371
|
+
}
|
|
372
|
+
.range:focus-visible { box-shadow: var(--ui-focus); }
|
|
373
|
+
|
|
374
|
+
/* Grouped form area (e.g. schema-aware add-row forms). */
|
|
375
|
+
.form-well {
|
|
376
|
+
padding: var(--ui-space-3);
|
|
377
|
+
background: var(--ui-surface-2);
|
|
378
|
+
border: 1px solid var(--ui-border);
|
|
379
|
+
border-radius: 8px;
|
|
380
|
+
margin-bottom: var(--ui-space-3);
|
|
381
|
+
}
|
|
382
|
+
.form-grid {
|
|
383
|
+
display: grid;
|
|
384
|
+
grid-template-columns: 180px 1fr;
|
|
385
|
+
gap: 8px 14px;
|
|
386
|
+
align-items: center;
|
|
387
|
+
}
|
|
388
|
+
.form-grid label {
|
|
389
|
+
font-family: var(--ui-font-mono);
|
|
390
|
+
font-size: var(--ui-text-sm);
|
|
391
|
+
color: var(--ui-text);
|
|
392
|
+
}
|
|
393
|
+
.form-grid .type { color: var(--ui-text-faint); font-size: var(--ui-text-xs); }
|
|
394
|
+
|
|
395
|
+
/* @odla-ai/ui — cards, panels, badges */
|
|
396
|
+
|
|
397
|
+
.card {
|
|
398
|
+
background: var(--ui-surface);
|
|
399
|
+
border: 1px solid var(--ui-border);
|
|
400
|
+
border-radius: var(--ui-radius-lg);
|
|
401
|
+
padding: 14px;
|
|
402
|
+
box-shadow: var(--ui-shadow);
|
|
403
|
+
}
|
|
404
|
+
.card h4 {
|
|
405
|
+
margin: 0 0 var(--ui-space-2);
|
|
406
|
+
color: var(--ui-text-muted);
|
|
407
|
+
font-weight: 600;
|
|
408
|
+
font-size: var(--ui-text-xs);
|
|
409
|
+
text-transform: uppercase;
|
|
410
|
+
letter-spacing: var(--ui-tracking-caps);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* KPI card grid. */
|
|
414
|
+
.cards {
|
|
415
|
+
display: grid;
|
|
416
|
+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
417
|
+
gap: var(--ui-space-3);
|
|
418
|
+
margin: var(--ui-space-4) 0;
|
|
419
|
+
}
|
|
420
|
+
.metric { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
|
|
421
|
+
|
|
422
|
+
.panel {
|
|
423
|
+
background: var(--ui-surface);
|
|
424
|
+
border: 1px solid var(--ui-border);
|
|
425
|
+
border-radius: var(--ui-radius-lg);
|
|
426
|
+
padding: var(--ui-space-4);
|
|
427
|
+
margin: var(--ui-space-4) 0;
|
|
428
|
+
box-shadow: var(--ui-shadow);
|
|
429
|
+
}
|
|
430
|
+
.panel h3 { margin: 0 0 var(--ui-space-3); font-weight: 700; }
|
|
431
|
+
|
|
432
|
+
/* Status badge: neutral by default, status variants chain. */
|
|
433
|
+
.badge {
|
|
434
|
+
display: inline-block;
|
|
435
|
+
font-family: var(--ui-font-mono);
|
|
436
|
+
font-size: var(--ui-text-xs);
|
|
437
|
+
font-weight: 600;
|
|
438
|
+
text-transform: uppercase;
|
|
439
|
+
letter-spacing: 0.04em;
|
|
440
|
+
padding: 2px 8px;
|
|
441
|
+
border-radius: var(--ui-radius-pill);
|
|
442
|
+
background: var(--ui-surface-2);
|
|
443
|
+
border: 1px solid var(--ui-border);
|
|
444
|
+
color: var(--ui-text-muted);
|
|
445
|
+
}
|
|
446
|
+
.badge.good { background: var(--ui-good-soft); border-color: var(--ui-good); color: var(--ui-good); }
|
|
447
|
+
.badge.warn { background: var(--ui-warn-soft); border-color: var(--ui-warn); color: var(--ui-warn); }
|
|
448
|
+
.badge.danger { background: var(--ui-danger-soft); border-color: var(--ui-danger); color: var(--ui-danger); }
|
|
449
|
+
.badge.accent { background: var(--ui-accent-soft); border-color: var(--ui-accent); color: var(--ui-accent-strong); }
|
|
450
|
+
|
|
451
|
+
/* Pass/fail verdict pill (permission inspectors, test results). */
|
|
452
|
+
.verdict {
|
|
453
|
+
font-family: var(--ui-font-mono);
|
|
454
|
+
font-size: var(--ui-text-sm);
|
|
455
|
+
font-weight: 600;
|
|
456
|
+
padding: 3px 10px;
|
|
457
|
+
border-radius: var(--ui-radius-pill);
|
|
458
|
+
}
|
|
459
|
+
.verdict-pass { background: var(--ui-good-soft); color: var(--ui-good); border: 1px solid var(--ui-good); }
|
|
460
|
+
.verdict-fail { background: var(--ui-danger-soft); color: var(--ui-danger); border: 1px solid var(--ui-danger); }
|
|
461
|
+
|
|
462
|
+
/* @odla-ai/ui — data tables
|
|
463
|
+
`.table` is the class equivalent of a themed bare <table>.
|
|
464
|
+
Wrap in `.table-wrap` for scroll + sticky header. */
|
|
465
|
+
|
|
466
|
+
.table {
|
|
467
|
+
width: 100%;
|
|
468
|
+
border-collapse: collapse;
|
|
469
|
+
font-size: var(--ui-text-md);
|
|
470
|
+
}
|
|
471
|
+
.table td,
|
|
472
|
+
.table th {
|
|
473
|
+
text-align: left;
|
|
474
|
+
padding: 7px 8px;
|
|
475
|
+
border-bottom: 1px solid var(--ui-border);
|
|
476
|
+
}
|
|
477
|
+
.table th { color: var(--ui-text-muted); font-weight: 600; }
|
|
478
|
+
.table td { font-variant-numeric: tabular-nums; }
|
|
479
|
+
|
|
480
|
+
/* Scroll container; header sticks against the sunken surface. */
|
|
481
|
+
.table-wrap { overflow: auto; max-height: 420px; }
|
|
482
|
+
.table-wrap .table thead th {
|
|
483
|
+
position: sticky;
|
|
484
|
+
top: 0;
|
|
485
|
+
background: var(--ui-surface-2);
|
|
486
|
+
z-index: 1;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* Signed values. */
|
|
490
|
+
.table .pos { color: var(--ui-good); }
|
|
491
|
+
.table .neg { color: var(--ui-danger); }
|
|
492
|
+
|
|
493
|
+
/* Inline-editable cells (data browsers). */
|
|
494
|
+
.table td.editable { cursor: text; }
|
|
495
|
+
.table td.editable:hover { background: var(--ui-accent-soft); }
|
|
496
|
+
|
|
497
|
+
/* @odla-ai/ui — navigation & layout chrome */
|
|
498
|
+
|
|
499
|
+
/* App shell: fixed sidebar + content column. */
|
|
500
|
+
.layout {
|
|
501
|
+
display: grid;
|
|
502
|
+
grid-template-columns: 260px 1fr;
|
|
503
|
+
min-height: 100vh;
|
|
504
|
+
}
|
|
505
|
+
.sidebar {
|
|
506
|
+
background: var(--ui-surface);
|
|
507
|
+
border-right: 1px solid var(--ui-border);
|
|
508
|
+
padding: var(--ui-space-4);
|
|
509
|
+
}
|
|
510
|
+
.main { padding: var(--ui-space-5) var(--ui-space-6); max-width: 1100px; min-width: 0; }
|
|
511
|
+
.head {
|
|
512
|
+
display: flex;
|
|
513
|
+
justify-content: space-between;
|
|
514
|
+
align-items: baseline;
|
|
515
|
+
gap: var(--ui-space-4);
|
|
516
|
+
}
|
|
517
|
+
.head h2 { margin: 0; font-weight: 700; }
|
|
518
|
+
.brand {
|
|
519
|
+
font-family: var(--ui-font-display);
|
|
520
|
+
font-weight: 700;
|
|
521
|
+
letter-spacing: -0.02em;
|
|
522
|
+
font-size: 18px;
|
|
523
|
+
margin-bottom: var(--ui-space-4);
|
|
524
|
+
}
|
|
525
|
+
.brand small { color: var(--ui-text-muted); font-weight: 500; }
|
|
526
|
+
|
|
527
|
+
/* Sidebar nav entry (button or link). */
|
|
528
|
+
.navitem {
|
|
529
|
+
display: block;
|
|
530
|
+
width: 100%;
|
|
531
|
+
text-align: left;
|
|
532
|
+
font: inherit;
|
|
533
|
+
font-weight: 600;
|
|
534
|
+
background: var(--ui-surface);
|
|
535
|
+
color: var(--ui-text-muted);
|
|
536
|
+
border: 1px solid var(--ui-border);
|
|
537
|
+
border-radius: var(--ui-radius-md);
|
|
538
|
+
padding: 8px 10px;
|
|
539
|
+
margin-bottom: var(--ui-space-2);
|
|
540
|
+
cursor: pointer;
|
|
541
|
+
text-decoration: none;
|
|
542
|
+
}
|
|
543
|
+
.navitem:hover { background: var(--ui-surface-2); color: var(--ui-text); }
|
|
544
|
+
.navitem.active {
|
|
545
|
+
background: var(--ui-accent-soft);
|
|
546
|
+
border-color: var(--ui-accent);
|
|
547
|
+
color: var(--ui-accent-strong);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* Content containers. */
|
|
551
|
+
.wrap { width: 100%; max-width: 1080px; margin: 0 auto; padding: 0 var(--ui-space-4); }
|
|
552
|
+
.wrap.narrow { max-width: 640px; }
|
|
553
|
+
|
|
554
|
+
/* Utility row + muted text (ubiquitous in app chrome). */
|
|
555
|
+
.row { display: flex; gap: var(--ui-space-2); align-items: center; }
|
|
556
|
+
.muted { color: var(--ui-text-muted); }
|
|
557
|
+
|
|
558
|
+
/* Off-canvas drawer. Toggle .open on both drawer and overlay. */
|
|
559
|
+
.drawer {
|
|
560
|
+
position: fixed;
|
|
561
|
+
top: 0;
|
|
562
|
+
right: 0;
|
|
563
|
+
bottom: 0;
|
|
564
|
+
width: min(340px, 88vw);
|
|
565
|
+
background: var(--ui-surface);
|
|
566
|
+
border-left: 1px solid var(--ui-border);
|
|
567
|
+
padding: var(--ui-space-4);
|
|
568
|
+
overflow-y: auto;
|
|
569
|
+
transform: translateX(100%);
|
|
570
|
+
transition: transform 0.25s ease;
|
|
571
|
+
z-index: 1001;
|
|
572
|
+
}
|
|
573
|
+
.drawer.open { transform: translateX(0); }
|
|
574
|
+
.drawer-overlay {
|
|
575
|
+
position: fixed;
|
|
576
|
+
inset: 0;
|
|
577
|
+
background: rgba(0, 0, 0, 0.4);
|
|
578
|
+
opacity: 0;
|
|
579
|
+
pointer-events: none;
|
|
580
|
+
transition: opacity 0.25s ease;
|
|
581
|
+
z-index: 1000;
|
|
582
|
+
}
|
|
583
|
+
.drawer-overlay.open { opacity: 1; pointer-events: auto; }
|
|
584
|
+
|
|
585
|
+
/* Page footer strip. */
|
|
586
|
+
.footer {
|
|
587
|
+
border-top: 1px solid var(--ui-border);
|
|
588
|
+
color: var(--ui-text-muted);
|
|
589
|
+
font-size: var(--ui-text-sm);
|
|
590
|
+
padding: var(--ui-space-5) 0;
|
|
591
|
+
margin-top: var(--ui-space-7);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* @odla-ai/ui — toasts, banners, dropzones, activity indicators */
|
|
595
|
+
|
|
596
|
+
.toast {
|
|
597
|
+
position: fixed;
|
|
598
|
+
bottom: 20px;
|
|
599
|
+
right: 20px;
|
|
600
|
+
background: var(--ui-text);
|
|
601
|
+
color: var(--ui-bg);
|
|
602
|
+
padding: 10px 14px;
|
|
603
|
+
border-radius: 8px;
|
|
604
|
+
font-size: var(--ui-text-md);
|
|
605
|
+
box-shadow: var(--ui-shadow);
|
|
606
|
+
z-index: 1100;
|
|
607
|
+
}
|
|
608
|
+
.toast.good { border-left: 3px solid var(--ui-good); }
|
|
609
|
+
.toast.warn { border-left: 3px solid var(--ui-warn); }
|
|
610
|
+
.toast.danger { border-left: 3px solid var(--ui-danger); }
|
|
611
|
+
|
|
612
|
+
/* Inline notice bar. */
|
|
613
|
+
.banner {
|
|
614
|
+
padding: 10px 14px;
|
|
615
|
+
border: 1px solid var(--ui-border);
|
|
616
|
+
border-radius: var(--ui-radius-md);
|
|
617
|
+
background: var(--ui-surface-2);
|
|
618
|
+
font-size: var(--ui-text-md);
|
|
619
|
+
margin: var(--ui-space-3) 0;
|
|
620
|
+
}
|
|
621
|
+
.banner.good { background: var(--ui-good-soft); border-color: var(--ui-good); color: var(--ui-good); }
|
|
622
|
+
.banner.warn { background: var(--ui-warn-soft); border-color: var(--ui-warn); color: var(--ui-warn); }
|
|
623
|
+
.banner.error { background: var(--ui-danger-soft); border-color: var(--ui-danger); color: var(--ui-danger); }
|
|
624
|
+
|
|
625
|
+
/* File-drop target; add .drag while a file hovers. */
|
|
626
|
+
.dropzone {
|
|
627
|
+
border: 1.5px dashed var(--ui-border);
|
|
628
|
+
border-radius: 8px;
|
|
629
|
+
padding: 18px;
|
|
630
|
+
text-align: center;
|
|
631
|
+
color: var(--ui-text-muted);
|
|
632
|
+
font-size: var(--ui-text-md);
|
|
633
|
+
background: var(--ui-surface-2);
|
|
634
|
+
margin-bottom: 14px;
|
|
635
|
+
}
|
|
636
|
+
.dropzone.drag {
|
|
637
|
+
border-color: var(--ui-accent);
|
|
638
|
+
background: var(--ui-accent-soft);
|
|
639
|
+
color: var(--ui-accent-strong);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/* Live-activity pulse dot. */
|
|
643
|
+
.live-dot {
|
|
644
|
+
display: inline-block;
|
|
645
|
+
width: 8px;
|
|
646
|
+
height: 8px;
|
|
647
|
+
border-radius: 50%;
|
|
648
|
+
background: var(--ui-good);
|
|
649
|
+
margin-right: 6px;
|
|
650
|
+
animation: ui-pulse 1.4s infinite;
|
|
651
|
+
}
|
|
652
|
+
@keyframes ui-pulse {
|
|
653
|
+
0%, 100% { opacity: 1; }
|
|
654
|
+
50% { opacity: 0.3; }
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/* Border spinner. */
|
|
658
|
+
.spinner {
|
|
659
|
+
display: inline-block;
|
|
660
|
+
width: 16px;
|
|
661
|
+
height: 16px;
|
|
662
|
+
border: 2px solid var(--ui-border);
|
|
663
|
+
border-top-color: var(--ui-accent);
|
|
664
|
+
border-radius: 50%;
|
|
665
|
+
animation: ui-spin 0.8s linear infinite;
|
|
666
|
+
vertical-align: middle;
|
|
667
|
+
}
|
|
668
|
+
@keyframes ui-spin {
|
|
669
|
+
to { transform: rotate(360deg); }
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/* @odla-ai/ui — chat surfaces
|
|
673
|
+
Shaped by the @odla-ai/ai content-block contract: text, tool_use,
|
|
674
|
+
tool_result, thinking blocks; streaming deltas; usage; typed errors. */
|
|
675
|
+
|
|
676
|
+
.chat {
|
|
677
|
+
display: flex;
|
|
678
|
+
flex-direction: column;
|
|
679
|
+
gap: var(--ui-space-4);
|
|
680
|
+
max-width: 720px;
|
|
681
|
+
margin: 0 auto;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.chat-msg { display: flex; flex-direction: column; align-items: flex-start; }
|
|
685
|
+
.chat-msg.user { align-items: flex-end; }
|
|
686
|
+
|
|
687
|
+
.chat-bubble {
|
|
688
|
+
max-width: 88%;
|
|
689
|
+
padding: 10px 14px;
|
|
690
|
+
border-radius: var(--ui-radius-lg);
|
|
691
|
+
font-size: var(--ui-text-lg);
|
|
692
|
+
line-height: 1.55;
|
|
693
|
+
overflow-wrap: break-word;
|
|
694
|
+
}
|
|
695
|
+
.chat-msg.user .chat-bubble {
|
|
696
|
+
background: var(--ui-chat-user-bg);
|
|
697
|
+
color: var(--ui-chat-user-text);
|
|
698
|
+
}
|
|
699
|
+
.chat-msg.assistant .chat-bubble {
|
|
700
|
+
background: var(--ui-chat-assistant-bg);
|
|
701
|
+
border: 1px solid var(--ui-border);
|
|
702
|
+
}
|
|
703
|
+
.chat-bubble pre {
|
|
704
|
+
font-family: var(--ui-font-mono);
|
|
705
|
+
font-size: var(--ui-text-sm);
|
|
706
|
+
background: var(--ui-code-bg);
|
|
707
|
+
color: var(--ui-code-text);
|
|
708
|
+
border-radius: var(--ui-radius-sm);
|
|
709
|
+
padding: 10px 12px;
|
|
710
|
+
overflow-x: auto;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* Collapsible reasoning panel (ThinkingBlock) — use a <details>. */
|
|
714
|
+
.chat-thinking {
|
|
715
|
+
align-self: stretch;
|
|
716
|
+
background: var(--ui-chat-thinking-bg);
|
|
717
|
+
color: var(--ui-chat-thinking-text);
|
|
718
|
+
border: 1px solid var(--ui-border);
|
|
719
|
+
border-radius: var(--ui-radius-md);
|
|
720
|
+
font-size: var(--ui-text-sm);
|
|
721
|
+
padding: 6px 10px;
|
|
722
|
+
}
|
|
723
|
+
.chat-thinking summary {
|
|
724
|
+
cursor: pointer;
|
|
725
|
+
font-family: var(--ui-font-mono);
|
|
726
|
+
font-size: var(--ui-text-xs);
|
|
727
|
+
text-transform: uppercase;
|
|
728
|
+
letter-spacing: var(--ui-tracking-caps);
|
|
729
|
+
}
|
|
730
|
+
.chat-thinking[open] summary { margin-bottom: 6px; }
|
|
731
|
+
|
|
732
|
+
/* Tool-call card (ToolUseBlock): name + streamed args. */
|
|
733
|
+
.chat-tool {
|
|
734
|
+
align-self: stretch;
|
|
735
|
+
border: 1px solid var(--ui-border);
|
|
736
|
+
border-left: 3px solid var(--ui-chat-tool-accent);
|
|
737
|
+
border-radius: var(--ui-radius-md);
|
|
738
|
+
background: var(--ui-surface);
|
|
739
|
+
padding: 8px 12px;
|
|
740
|
+
}
|
|
741
|
+
.chat-tool-name {
|
|
742
|
+
font-family: var(--ui-font-mono);
|
|
743
|
+
font-size: var(--ui-text-sm);
|
|
744
|
+
font-weight: 600;
|
|
745
|
+
color: var(--ui-chat-tool-accent);
|
|
746
|
+
}
|
|
747
|
+
.chat-tool-args {
|
|
748
|
+
font-family: var(--ui-font-mono);
|
|
749
|
+
font-size: var(--ui-text-sm);
|
|
750
|
+
background: var(--ui-code-bg);
|
|
751
|
+
color: var(--ui-code-text);
|
|
752
|
+
border-radius: var(--ui-radius-sm);
|
|
753
|
+
padding: 8px 10px;
|
|
754
|
+
margin: 6px 0 0;
|
|
755
|
+
overflow-x: auto;
|
|
756
|
+
white-space: pre-wrap;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* Tool-result card (ToolResultBlock); .error for isError results. */
|
|
760
|
+
.chat-result {
|
|
761
|
+
align-self: stretch;
|
|
762
|
+
border: 1px solid var(--ui-border);
|
|
763
|
+
border-left: 3px solid var(--ui-good);
|
|
764
|
+
border-radius: var(--ui-radius-md);
|
|
765
|
+
background: var(--ui-surface-2);
|
|
766
|
+
padding: 8px 12px;
|
|
767
|
+
font-size: var(--ui-text-md);
|
|
768
|
+
}
|
|
769
|
+
.chat-result.error {
|
|
770
|
+
border-left-color: var(--ui-danger);
|
|
771
|
+
background: var(--ui-danger-soft);
|
|
772
|
+
color: var(--ui-danger);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/* Streaming caret appended during text/thinking deltas. */
|
|
776
|
+
.chat-cursor {
|
|
777
|
+
display: inline-block;
|
|
778
|
+
width: 0.55em;
|
|
779
|
+
height: 1.1em;
|
|
780
|
+
background: var(--ui-accent);
|
|
781
|
+
vertical-align: text-bottom;
|
|
782
|
+
animation: ui-blink 1s steps(1) infinite;
|
|
783
|
+
}
|
|
784
|
+
@keyframes ui-blink {
|
|
785
|
+
50% { opacity: 0; }
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/* Composer bar. */
|
|
789
|
+
.chat-composer {
|
|
790
|
+
position: sticky;
|
|
791
|
+
bottom: 0;
|
|
792
|
+
display: flex;
|
|
793
|
+
gap: var(--ui-space-2);
|
|
794
|
+
align-items: flex-end;
|
|
795
|
+
background: var(--ui-surface);
|
|
796
|
+
border-top: 1px solid var(--ui-border);
|
|
797
|
+
padding: var(--ui-space-3);
|
|
798
|
+
}
|
|
799
|
+
.chat-composer .textarea { flex: 1; min-height: 40px; max-height: 200px; }
|
|
800
|
+
|
|
801
|
+
/* Token/cost footer (OracleUsage). */
|
|
802
|
+
.chat-usage {
|
|
803
|
+
font-family: var(--ui-font-mono);
|
|
804
|
+
font-size: var(--ui-text-xs);
|
|
805
|
+
color: var(--ui-text-faint);
|
|
806
|
+
text-align: right;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/* Error/stop-reason notices (rate_limit, context_window, refusal, …). */
|
|
810
|
+
.chat-banner {
|
|
811
|
+
align-self: stretch;
|
|
812
|
+
padding: 8px 12px;
|
|
813
|
+
border-radius: var(--ui-radius-md);
|
|
814
|
+
border: 1px solid var(--ui-border);
|
|
815
|
+
background: var(--ui-surface-2);
|
|
816
|
+
font-size: var(--ui-text-md);
|
|
817
|
+
}
|
|
818
|
+
.chat-banner.warn { background: var(--ui-warn-soft); border-color: var(--ui-warn); color: var(--ui-warn); }
|
|
819
|
+
.chat-banner.error { background: var(--ui-danger-soft); border-color: var(--ui-danger); color: var(--ui-danger); }
|
|
820
|
+
|
|
821
|
+
/* Attachment chip (image/document blocks in history or composer). */
|
|
822
|
+
.chat-attachment {
|
|
823
|
+
display: inline-flex;
|
|
824
|
+
align-items: center;
|
|
825
|
+
gap: 6px;
|
|
826
|
+
font-family: var(--ui-font-mono);
|
|
827
|
+
font-size: var(--ui-text-xs);
|
|
828
|
+
border: 1px solid var(--ui-border);
|
|
829
|
+
border-radius: var(--ui-radius-sm);
|
|
830
|
+
background: var(--ui-surface-2);
|
|
831
|
+
color: var(--ui-text-muted);
|
|
832
|
+
padding: 3px 8px;
|
|
833
|
+
}
|
|
834
|
+
.chat-attachment img {
|
|
835
|
+
max-height: 48px;
|
|
836
|
+
border-radius: var(--ui-radius-sm);
|
|
837
|
+
display: block;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/* @odla-ai/ui — chart containers
|
|
841
|
+
Rendering happens on <canvas> via js/canvas.js; colors come from the
|
|
842
|
+
--ui-chart-* tokens read with js/palette.js readPalette(). */
|
|
843
|
+
|
|
844
|
+
.chart { position: relative; }
|
|
845
|
+
.chart canvas { display: block; width: 100%; }
|
|
846
|
+
|
|
847
|
+
.chart-legend {
|
|
848
|
+
display: flex;
|
|
849
|
+
flex-wrap: wrap;
|
|
850
|
+
gap: var(--ui-space-3);
|
|
851
|
+
font-family: var(--ui-font-mono);
|
|
852
|
+
font-size: var(--ui-text-xs);
|
|
853
|
+
color: var(--ui-text-muted);
|
|
854
|
+
margin-top: var(--ui-space-2);
|
|
855
|
+
}
|
|
856
|
+
.chart-key { display: inline-flex; align-items: center; gap: 5px; }
|
|
857
|
+
.chart-key i {
|
|
858
|
+
display: inline-block;
|
|
859
|
+
width: 10px;
|
|
860
|
+
height: 10px;
|
|
861
|
+
border-radius: var(--ui-radius-sm);
|
|
862
|
+
background: currentColor;
|
|
863
|
+
}
|