@timbal-ai/timbal-react 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  SIDEBAR_INSET_PX_EXPANDED,
3
+ STORAGE_KEYS,
3
4
  ShellInsetProvider,
4
5
  studioChromeShellStyle,
5
6
  studioSidebarWidthTransition
6
- } from "./chunk-Z27GBSOT.esm.js";
7
+ } from "./chunk-QIABF4KB.esm.js";
7
8
  import {
8
9
  ChartArtifactView,
9
10
  LineAreaChart,
@@ -16,10 +17,10 @@ import {
16
17
  studioSecondaryChromeClass,
17
18
  studioTopbarPillHeightClass,
18
19
  toNum
19
- } from "./chunk-VVTTLIGT.esm.js";
20
+ } from "./chunk-5ZKLPWVN.esm.js";
20
21
  import {
21
22
  PillSegmentedTabs
22
- } from "./chunk-YNDXBN6C.esm.js";
23
+ } from "./chunk-OISVICYF.esm.js";
23
24
  import {
24
25
  Button,
25
26
  Dialog,
@@ -31,7 +32,7 @@ import {
31
32
  TIMBAL_V2_SWITCH_TRACK_OFF,
32
33
  TimbalV2Button,
33
34
  cn
34
- } from "./chunk-QKO67F4V.esm.js";
35
+ } from "./chunk-QVAUCVQA.esm.js";
35
36
 
36
37
  // src/app/agent-instructions.ts
37
38
  var APP_KIT_AGENT_INSTRUCTIONS = `
@@ -66,6 +67,8 @@ Presentational groups \u2014 import from the package root, not from these paths:
66
67
 
67
68
  Also re-exported: \`Button\`, \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_AGENT_INSTRUCTIONS\`.
68
69
 
70
+ Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\`, \`themeToCss\`, \`applyTimbalTheme\`, \`TIMBAL_THEME_PRESETS\`, \`applyThemePreset\`, \`ThemePresetGallery\`, \`TimbalThemeStyle\`, \`THEME_AGENT_INSTRUCTIONS\`.
71
+
69
72
  ### Design guidelines (required)
70
73
 
71
74
  | Area | Rule |
@@ -73,7 +76,7 @@ Also re-exported: \`Button\`, \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_A
73
76
  | **Copilot** | Use \`AppCopilotProvider\` for page context (\`useAppCopilotContext\`). Copilot is a **floating overlay** via \`AppShell\` \`chat={<AppChatPanel />}\` \u2014 not a sidebar column that shrinks main content. |
74
77
  | **Chat panel** | \`AppChatPanel\` only; \`Thread\` uses \`variant="panel"\` internally. Dismiss with **X**; trigger is a **text-only** pill (e.g. "Assistant") \u2014 **no** MessageSquare or chat icons on the shell trigger. |
75
78
  | **Context** | Do not show raw JSON context in the panel header; keep context in \`AppCopilotProvider\` only. |
76
- | **Theming** | Use semantic Tailwind tokens (\`bg-background\`, \`text-foreground\`, \`border-border\`, \`bg-elevated-from\`, etc.) from the host app's \`styles.css\`. Optional: \`import "@timbal-ai/timbal-react/styles.css"\`. |
79
+ | **Theming** | Use semantic Tailwind tokens (\`bg-background\`, \`text-foreground\`, \`border-border\`, \`bg-elevated-from\`, etc.) from the host app's \`styles.css\`. To rebrand, **never hand-author OKLCH** \u2014 call \`createTimbalTheme({ brand })\` + \`themeToCss\`/\`applyTimbalTheme\`, or apply a catalog preset (\`TIMBAL_THEME_PRESETS\` / \`applyThemePreset\`). To offer styles, render \`ThemePresetGallery\`. See \`THEME_AGENT_INSTRUCTIONS\`. |
77
80
  | **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. \`AppShellTopbar\` for global actions (auth, theme). |
78
81
  | **Data** | Prefer \`DataTable\` with typed \`columns\` / \`rows\` / \`getRowKey\`; use \`ChartPanel\` with \`ChartArtifact\` for charts. |
79
82
  | **Modals** | Use \`AppConfirmDialog\` for destructive/export confirmations. |
@@ -173,6 +176,7 @@ Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/
173
176
  | \`resource-gallery.tsx\` | \`ResourceCard\`, \`StatusDot\`, \`Sparkline\` |
174
177
  | \`charts-panel.tsx\` | \`ChartPanel\`, \`ChartArtifact\` |
175
178
  | \`copilot-overlay.tsx\` | \`AppShell\`, \`AppChatPanel\` |
179
+ | \`theme-presets.tsx\` | \`ThemePresetGallery\`, \`applyTimbalTheme\` |
176
180
 
177
181
  ### Typical compositions
178
182
 
@@ -218,6 +222,681 @@ import {
218
222
  - For rich in-chat widgets, use **artifacts** (\`ARTIFACT_AGENT_INSTRUCTIONS\`) \u2014 app kit is for the **host application shell**.
219
223
  `.trim();
220
224
 
225
+ // src/design/oklch.ts
226
+ var clamp = (n, min, max) => Math.min(max, Math.max(min, n));
227
+ var round = (n, digits) => {
228
+ const f = 10 ** digits;
229
+ return Math.round(n * f) / f;
230
+ };
231
+ function srgbToLinear(channel) {
232
+ const c = channel / 255;
233
+ return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
234
+ }
235
+ function linearRgbToOklch(r, g, b, alpha) {
236
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
237
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
238
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
239
+ const l_ = Math.cbrt(l);
240
+ const m_ = Math.cbrt(m);
241
+ const s_ = Math.cbrt(s);
242
+ const labL = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
243
+ const labA = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
244
+ const labB = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
245
+ const c = Math.sqrt(labA * labA + labB * labB);
246
+ let h = Math.atan2(labB, labA) * 180 / Math.PI;
247
+ if (h < 0) h += 360;
248
+ return { l: labL, c, h, alpha };
249
+ }
250
+ function oklchToLinearRgb(color) {
251
+ const hRad = color.h * Math.PI / 180;
252
+ const labA = color.c * Math.cos(hRad);
253
+ const labB = color.c * Math.sin(hRad);
254
+ const l_ = color.l + 0.3963377774 * labA + 0.2158037573 * labB;
255
+ const m_ = color.l - 0.1055613458 * labA - 0.0638541728 * labB;
256
+ const s_ = color.l - 0.0894841775 * labA - 1.291485548 * labB;
257
+ const l = l_ ** 3;
258
+ const m = m_ ** 3;
259
+ const s = s_ ** 3;
260
+ return {
261
+ r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
262
+ g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
263
+ b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
264
+ };
265
+ }
266
+ function parseHex(value) {
267
+ let hex = value.trim().replace(/^#/, "");
268
+ if (![3, 4, 6, 8].includes(hex.length)) return null;
269
+ if (hex.length === 3 || hex.length === 4) {
270
+ hex = hex.split("").map((ch) => ch + ch).join("");
271
+ }
272
+ const int = Number.parseInt(hex, 16);
273
+ if (Number.isNaN(int)) return null;
274
+ const hasAlpha = hex.length === 8;
275
+ const r = int >>> (hasAlpha ? 24 : 16) & 255;
276
+ const g = int >>> (hasAlpha ? 16 : 8) & 255;
277
+ const b = int >>> (hasAlpha ? 8 : 0) & 255;
278
+ const alpha = hasAlpha ? (int & 255) / 255 : 1;
279
+ return linearRgbToOklch(
280
+ srgbToLinear(r),
281
+ srgbToLinear(g),
282
+ srgbToLinear(b),
283
+ alpha
284
+ );
285
+ }
286
+ function parseRgb(value) {
287
+ const match = value.match(
288
+ /rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)(?:[\s,/]+([0-9.%]+))?\s*\)/i
289
+ );
290
+ if (!match) return null;
291
+ const r = Number.parseFloat(match[1]);
292
+ const g = Number.parseFloat(match[2]);
293
+ const b = Number.parseFloat(match[3]);
294
+ let alpha = 1;
295
+ if (match[4]) {
296
+ alpha = match[4].includes("%") ? Number.parseFloat(match[4]) / 100 : Number.parseFloat(match[4]);
297
+ }
298
+ if (![r, g, b].every(Number.isFinite)) return null;
299
+ return linearRgbToOklch(
300
+ srgbToLinear(r),
301
+ srgbToLinear(g),
302
+ srgbToLinear(b),
303
+ Number.isFinite(alpha) ? alpha : 1
304
+ );
305
+ }
306
+ function parseOklch(value) {
307
+ const match = value.match(
308
+ /oklch\(\s*([0-9.]+%?)\s+([0-9.]+%?)\s+([0-9.]+)(?:deg)?(?:\s*\/\s*([0-9.%]+))?\s*\)/i
309
+ );
310
+ if (!match) return null;
311
+ const l = match[1].includes("%") ? Number.parseFloat(match[1]) / 100 : Number.parseFloat(match[1]);
312
+ const c = match[2].includes("%") ? Number.parseFloat(match[2]) / 100 * 0.4 : Number.parseFloat(match[2]);
313
+ const h = Number.parseFloat(match[3]);
314
+ let alpha = 1;
315
+ if (match[4]) {
316
+ alpha = match[4].includes("%") ? Number.parseFloat(match[4]) / 100 : Number.parseFloat(match[4]);
317
+ }
318
+ if (![l, c, h].every(Number.isFinite)) return null;
319
+ return { l, c, h, alpha: Number.isFinite(alpha) ? alpha : 1 };
320
+ }
321
+ function parseColor(value) {
322
+ const parsed = parseOklch(value) ?? parseHex(value) ?? parseRgb(value);
323
+ if (!parsed) {
324
+ throw new Error(
325
+ `[@timbal-ai/timbal-react] Could not parse color "${value}". Use a hex (#1E40AF), rgb()/rgba(), or oklch() string.`
326
+ );
327
+ }
328
+ return parsed;
329
+ }
330
+ function lighten(color, delta) {
331
+ return { ...color, l: clamp(color.l + delta, 0, 1) };
332
+ }
333
+ function scaleChroma(color, factor) {
334
+ return { ...color, c: clamp(color.c * factor, 0, 0.4) };
335
+ }
336
+ function withAlpha(color, alpha) {
337
+ return { ...color, alpha: clamp(alpha, 0, 1) };
338
+ }
339
+ function oklchToString(color) {
340
+ const l = round(clamp(color.l, 0, 1), 4);
341
+ const c = round(clamp(color.c, 0, 0.4), 4);
342
+ const h = round((color.h % 360 + 360) % 360, 2);
343
+ const a = clamp(color.alpha, 0, 1);
344
+ const base = `oklch(${l} ${c} ${h}`;
345
+ return a >= 1 ? `${base})` : `${base} / ${round(a, 3)})`;
346
+ }
347
+ function readableForeground(bg, options) {
348
+ const threshold = options?.threshold ?? 0.62;
349
+ const lightText = options?.light ?? "oklch(0.985 0 0)";
350
+ const darkText = options?.dark ?? "oklch(0.205 0 0)";
351
+ return bg.l >= threshold ? darkText : lightText;
352
+ }
353
+ function relativeLuminance(color) {
354
+ const { r, g, b } = oklchToLinearRgb(color);
355
+ const lr = clamp(r, 0, 1);
356
+ const lg = clamp(g, 0, 1);
357
+ const lb = clamp(b, 0, 1);
358
+ return 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;
359
+ }
360
+
361
+ // src/design/theme.ts
362
+ function primaryForMode(brand, mode) {
363
+ if (mode === "light") {
364
+ return { ...brand, l: Math.min(Math.max(brand.l, 0.42), 0.68) };
365
+ }
366
+ const lightened = lighten(brand, 0.06);
367
+ return {
368
+ ...lightened,
369
+ l: Math.min(Math.max(lightened.l, 0.5), 0.78),
370
+ c: Math.min(brand.c, 0.22)
371
+ };
372
+ }
373
+ function brandGradient(primary) {
374
+ return {
375
+ from: lighten(primary, 0.03),
376
+ to: lighten(primary, -0.02),
377
+ hoverFrom: lighten(primary, 0.06),
378
+ hoverTo: lighten(primary, 0.01),
379
+ activeFrom: lighten(primary, -0.02),
380
+ activeTo: lighten(primary, -0.06)
381
+ };
382
+ }
383
+ function neutralTints(brand) {
384
+ return {
385
+ lightHue: brand.h,
386
+ darkHue: brand.h,
387
+ lightChroma: 6e-3,
388
+ darkChroma: 8e-3
389
+ };
390
+ }
391
+ function createTimbalTheme(intent) {
392
+ const brand = parseColor(intent.brand);
393
+ const accent = intent.accent ? parseColor(intent.accent) : null;
394
+ const light = {};
395
+ const dark = {};
396
+ const root = {};
397
+ if (typeof intent.radius === "number") {
398
+ root["--radius"] = `${intent.radius}rem`;
399
+ }
400
+ const primaryLight = primaryForMode(brand, "light");
401
+ const primaryDark = primaryForMode(brand, "dark");
402
+ light["--primary"] = oklchToString(primaryLight);
403
+ light["--primary-foreground"] = readableForeground(primaryLight);
404
+ light["--ring"] = oklchToString(
405
+ scaleChroma({ ...primaryLight, l: 0.6 }, 0.7)
406
+ );
407
+ dark["--primary"] = oklchToString(primaryDark);
408
+ dark["--primary-foreground"] = readableForeground(primaryDark);
409
+ dark["--ring"] = oklchToString(scaleChroma({ ...primaryDark, l: 0.62 }, 0.6));
410
+ const gLight = brandGradient(primaryLight);
411
+ light["--primary-fill-from"] = oklchToString(gLight.from);
412
+ light["--primary-fill-to"] = oklchToString(gLight.to);
413
+ light["--primary-fill-hover-from"] = oklchToString(gLight.hoverFrom);
414
+ light["--primary-fill-hover-to"] = oklchToString(gLight.hoverTo);
415
+ light["--primary-fill-active-from"] = oklchToString(gLight.activeFrom);
416
+ light["--primary-fill-active-to"] = oklchToString(gLight.activeTo);
417
+ const gDark = brandGradient(primaryDark);
418
+ dark["--primary-fill-from"] = oklchToString(gDark.from);
419
+ dark["--primary-fill-to"] = oklchToString(gDark.to);
420
+ dark["--primary-fill-hover-from"] = oklchToString(gDark.hoverFrom);
421
+ dark["--primary-fill-hover-to"] = oklchToString(gDark.hoverTo);
422
+ dark["--primary-fill-active-from"] = oklchToString(gDark.activeFrom);
423
+ dark["--primary-fill-active-to"] = oklchToString(gDark.activeTo);
424
+ if (accent) {
425
+ const accentLight = { ...accent, l: Math.min(Math.max(accent.l, 0.9), 0.97) };
426
+ const accentDark = { ...accent, l: 0.25, c: Math.min(accent.c, 0.04) };
427
+ light["--accent"] = oklchToString(accentLight);
428
+ light["--accent-foreground"] = readableForeground(accentLight);
429
+ dark["--accent"] = oklchToString(accentDark);
430
+ dark["--accent-foreground"] = readableForeground(accentDark);
431
+ }
432
+ light["--playground-from"] = oklchToString(
433
+ withAlpha({ l: 0.91, c: 0.03, h: brand.h, alpha: 0.6 }, 0.6)
434
+ );
435
+ light["--playground-via"] = oklchToString(
436
+ withAlpha({ l: 0.965, c: 0.015, h: brand.h, alpha: 0.3 }, 0.3)
437
+ );
438
+ dark["--playground-from"] = oklchToString({
439
+ l: 0.27,
440
+ c: 0.03,
441
+ h: brand.h,
442
+ alpha: 1
443
+ });
444
+ dark["--playground-via"] = oklchToString({
445
+ l: 0.19,
446
+ c: 0.02,
447
+ h: brand.h,
448
+ alpha: 1
449
+ });
450
+ if (intent.tintNeutrals) {
451
+ const t = neutralTints(brand);
452
+ light["--secondary"] = oklchToString({
453
+ l: 0.975,
454
+ c: t.lightChroma,
455
+ h: t.lightHue,
456
+ alpha: 1
457
+ });
458
+ light["--muted"] = light["--secondary"];
459
+ light["--accent"] ?? (light["--accent"] = oklchToString({
460
+ l: 0.965,
461
+ c: t.lightChroma,
462
+ h: t.lightHue,
463
+ alpha: 1
464
+ }));
465
+ light["--border"] = oklchToString({
466
+ l: 0.91,
467
+ c: t.lightChroma,
468
+ h: t.lightHue,
469
+ alpha: 1
470
+ });
471
+ dark["--secondary"] = oklchToString({
472
+ l: 0.22,
473
+ c: t.darkChroma,
474
+ h: t.darkHue,
475
+ alpha: 1
476
+ });
477
+ dark["--muted"] = dark["--secondary"];
478
+ dark["--border"] = oklchToString({
479
+ l: 1,
480
+ c: 0,
481
+ h: 0,
482
+ alpha: 0.1
483
+ });
484
+ }
485
+ if (isDev()) {
486
+ const lum = relativeLuminance(primaryLight);
487
+ const fgIsLight = light["--primary-foreground"].includes("0.985");
488
+ const fgLum = fgIsLight ? 1 : 0.05;
489
+ const ratio = (Math.max(lum, fgLum) + 0.05) / (Math.min(lum, fgLum) + 0.05);
490
+ if (ratio < 3.5) {
491
+ console.warn(
492
+ `[@timbal-ai/timbal-react] createTimbalTheme: brand "${intent.brand}" yields a low primary/foreground contrast (~${ratio.toFixed(2)}:1). Consider a darker or more saturated brand color for buttons/CTAs.`
493
+ );
494
+ }
495
+ }
496
+ return { light, dark, root };
497
+ }
498
+ function declarations(map, indent) {
499
+ return Object.entries(map).map(([name, value]) => `${indent}${name}: ${value};`).join("\n");
500
+ }
501
+ function themeToCss(theme, options = {}) {
502
+ const indent = options.indent ?? " ";
503
+ const blocks = [];
504
+ const lightVars = { ...theme.root ?? {}, ...theme.light };
505
+ if (options.scope) {
506
+ const sel = `[data-timbal-theme="${options.scope}"]`;
507
+ if (Object.keys(lightVars).length) {
508
+ blocks.push(`${sel} {
509
+ ${declarations(lightVars, indent)}
510
+ }`);
511
+ }
512
+ if (Object.keys(theme.dark).length) {
513
+ blocks.push(
514
+ `.dark ${sel}, ${sel}.dark {
515
+ ${declarations(theme.dark, indent)}
516
+ }`
517
+ );
518
+ }
519
+ } else {
520
+ if (Object.keys(lightVars).length) {
521
+ blocks.push(`:root {
522
+ ${declarations(lightVars, indent)}
523
+ }`);
524
+ }
525
+ if (Object.keys(theme.dark).length) {
526
+ blocks.push(`.dark {
527
+ ${declarations(theme.dark, indent)}
528
+ }`);
529
+ }
530
+ }
531
+ return blocks.join("\n\n");
532
+ }
533
+ var RUNTIME_STYLE_ID = "timbal-theme-runtime";
534
+ function applyTimbalTheme(theme) {
535
+ if (typeof document === "undefined") return () => {
536
+ };
537
+ let el = document.getElementById(RUNTIME_STYLE_ID);
538
+ if (!el) {
539
+ el = document.createElement("style");
540
+ el.id = RUNTIME_STYLE_ID;
541
+ el.setAttribute("data-timbal-theme-runtime", "");
542
+ document.head.appendChild(el);
543
+ }
544
+ el.textContent = themeToCss(theme);
545
+ return () => {
546
+ el?.parentNode?.removeChild(el);
547
+ };
548
+ }
549
+ function clearTimbalTheme() {
550
+ if (typeof document === "undefined") return;
551
+ document.getElementById(RUNTIME_STYLE_ID)?.remove();
552
+ }
553
+ function isDev() {
554
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
555
+ return false;
556
+ }
557
+ return true;
558
+ }
559
+
560
+ // src/design/theme-presets.ts
561
+ var EMPTY_TOKENS = { light: {}, dark: {}, root: {} };
562
+ var TIMBAL_THEME_PRESETS = [
563
+ {
564
+ id: "platform",
565
+ label: "Platform",
566
+ description: "Shipped neutral monochrome \u2014 the Timbal Platform default. Calm, brand-agnostic.",
567
+ swatch: "oklch(0.205 0 0)",
568
+ tokens: EMPTY_TOKENS
569
+ },
570
+ {
571
+ id: "indigo",
572
+ label: "Indigo",
573
+ description: "Cool, trustworthy blue-violet \u2014 good for analytics & ops dashboards.",
574
+ swatch: "#4f46e5",
575
+ tokens: createTimbalTheme({ brand: "#4f46e5" })
576
+ },
577
+ {
578
+ id: "violet",
579
+ label: "Violet",
580
+ description: "Vivid purple \u2014 expressive, product/marketing-leaning surfaces.",
581
+ swatch: "#7c3aed",
582
+ tokens: createTimbalTheme({ brand: "#7c3aed" })
583
+ },
584
+ {
585
+ id: "forest",
586
+ label: "Forest",
587
+ description: "Grounded green \u2014 finance, sustainability, status-positive apps.",
588
+ swatch: "#16a34a",
589
+ tokens: createTimbalTheme({ brand: "#16a34a" })
590
+ },
591
+ {
592
+ id: "warm",
593
+ label: "Warm",
594
+ description: "Energetic orange \u2014 consumer, creative, high-engagement tools.",
595
+ swatch: "#ea580c",
596
+ tokens: createTimbalTheme({ brand: "#ea580c" })
597
+ },
598
+ {
599
+ id: "slate",
600
+ label: "Slate",
601
+ description: "Muted cool gray-blue with a subtle tint \u2014 understated enterprise.",
602
+ swatch: "#475569",
603
+ tokens: createTimbalTheme({ brand: "#475569", tintNeutrals: true })
604
+ }
605
+ ];
606
+ var PRESET_BY_ID = new Map(
607
+ TIMBAL_THEME_PRESETS.map((preset) => [preset.id, preset])
608
+ );
609
+ function getThemePreset(id) {
610
+ return PRESET_BY_ID.get(id);
611
+ }
612
+ function applyThemePreset(id) {
613
+ const preset = PRESET_BY_ID.get(id);
614
+ if (!preset) return () => {
615
+ };
616
+ if (typeof window !== "undefined") {
617
+ try {
618
+ window.localStorage.setItem(STORAGE_KEYS.themePreset, id);
619
+ } catch {
620
+ }
621
+ }
622
+ return applyTimbalTheme(preset.tokens);
623
+ }
624
+ function getStoredThemePreset() {
625
+ if (typeof window === "undefined") return null;
626
+ try {
627
+ const value = window.localStorage.getItem(STORAGE_KEYS.themePreset);
628
+ return value && PRESET_BY_ID.has(value) ? value : null;
629
+ } catch {
630
+ return null;
631
+ }
632
+ }
633
+
634
+ // src/design/theme-instructions.ts
635
+ var THEME_AGENT_INSTRUCTIONS = `
636
+ ## Theming (@timbal-ai/timbal-react)
637
+
638
+ The package ships a complete light + dark token system (\`styles.css\`). Components are written against semantic Tailwind tokens (\`bg-background\`, \`text-primary\`, \`border-border\`, \`bg-elevated-from\`, \`bg-bubble-user\`, \u2026). To restyle, you change CSS variables \u2014 **never** hardcode colors in component code.
639
+
640
+ ### Golden rule
641
+
642
+ **Never write \`oklch(...)\` / hex literals or hand-author paired \`:root\` + \`.dark\` blocks.** Express intent and let the package derive a complete, contrast-correct, paired palette.
643
+
644
+ ### Pick a brand color (rebrand)
645
+
646
+ \`\`\`ts
647
+ import { createTimbalTheme, themeToCss } from "@timbal-ai/timbal-react";
648
+
649
+ const theme = createTimbalTheme({ brand: "#4f46e5" /* accent?, radius?, tintNeutrals? */ });
650
+ // Build-time: write once into your app CSS (paired light + dark, guaranteed in sync):
651
+ const css = themeToCss(theme);
652
+ \`\`\`
653
+
654
+ - For a real company, look up the actual brand hex first (brandfetch / "<company> brand color hex"), then pass it as \`brand\`.
655
+ - \`createTimbalTheme\` derives \`--primary\`, its foreground, ring, the full button gradient, and a soft playground tint. You only supply intent.
656
+
657
+ ### Apply a theme
658
+
659
+ - **Build-time / SSR:** \`themeToCss(theme)\` \u2192 paste the returned CSS into your \`index.css\` (after the \`@import "@timbal-ai/timbal-react/styles.css"\`). One block, both modes.
660
+ - **Runtime / swappable:** \`applyTimbalTheme(theme)\` injects a managed \`<style>\` and returns a disposer. Works with the \`.dark\` toggle (next-themes / ModeToggle).
661
+ - **Component:** render \`<TimbalThemeStyle theme={theme} />\` (or \`preset="indigo"\`) once near the app root.
662
+
663
+ ### Offer styles to the user ("show compatible styles, then apply")
664
+
665
+ Use the closed preset catalog \u2014 do not invent options:
666
+
667
+ \`\`\`ts
668
+ import { TIMBAL_THEME_PRESETS, applyThemePreset } from "@timbal-ai/timbal-react";
669
+ // TIMBAL_THEME_PRESETS: { id, label, description, swatch, tokens }[]
670
+ \`\`\`
671
+
672
+ | Preset id | Use when |
673
+ |-----------|----------|
674
+ | \`platform\` | Neutral monochrome default (no brand) |
675
+ | \`indigo\` | Cool, trustworthy \u2014 analytics / ops dashboards |
676
+ | \`violet\` | Expressive purple \u2014 product / marketing |
677
+ | \`forest\` | Green \u2014 finance, sustainability, positive status |
678
+ | \`warm\` | Orange \u2014 consumer / creative / high-engagement |
679
+ | \`slate\` | Muted enterprise gray-blue (tinted neutrals) |
680
+
681
+ - To present options visually, render \`<ThemePresetGallery value={id} onSelect={setId} />\` \u2014 each swatch previews real components (Button + metric tile) scoped via \`data-timbal-theme\`, so the live app doesn't change until the user picks.
682
+ - On selection, call \`applyThemePreset(id)\` (persists to \`localStorage\` and restores on reload).
683
+
684
+ ### Rules
685
+
686
+ - Generated pages use **semantic Tailwind tokens only** \u2014 never literal colors or per-element \`style={{ color }}\`.
687
+ - Light/dark mode stays the \`.dark\` class (\`next-themes attribute="class"\` or \`ModeToggle\`). Presets are **brand**, not a second dark-mode system.
688
+ - Override individual tokens only for one-offs the generator doesn't cover; if you must, set the variable in **both** \`:root\` and \`.dark\` (a dev-only warning fires otherwise).
689
+ `.trim();
690
+
691
+ // src/app/theme/TimbalThemeStyle.tsx
692
+ import { jsx } from "react/jsx-runtime";
693
+ var TimbalThemeStyle = ({
694
+ theme,
695
+ preset,
696
+ scope,
697
+ nonce
698
+ }) => {
699
+ const tokens = theme ?? (preset ? getThemePreset(preset)?.tokens : void 0);
700
+ if (!tokens) return null;
701
+ const css = themeToCss(tokens, scope ? { scope } : void 0);
702
+ if (!css) return null;
703
+ return /* @__PURE__ */ jsx(
704
+ "style",
705
+ {
706
+ "data-timbal-theme-style": scope ?? "root",
707
+ nonce,
708
+ dangerouslySetInnerHTML: { __html: css }
709
+ }
710
+ );
711
+ };
712
+
713
+ // src/app/data/metrics-shared.tsx
714
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
715
+ var metricCardShellClass = cn(
716
+ studioIntegrationCardClass,
717
+ "aui-app-metric-card shadow-none",
718
+ "flex flex-col overflow-hidden"
719
+ );
720
+ var metricCardHeaderClass = "flex items-start justify-between gap-3 px-4 pb-1 pt-3";
721
+ var metricTilesRowClass = "grid w-full min-w-0";
722
+ var metricChartRegionClass = "relative min-h-0 w-full border-t border-border/40 pt-2";
723
+ var metricChartPlotRegionClass = "relative min-h-0 w-full border-t border-border/40 px-0 pt-5 pb-3";
724
+ var metricCellDividerClass = "border-r border-border/40";
725
+ var MetricCardHeader = ({
726
+ title,
727
+ titleId,
728
+ description,
729
+ actions
730
+ }) => {
731
+ if (!title && !description && !actions) return null;
732
+ return /* @__PURE__ */ jsxs("header", { className: metricCardHeaderClass, children: [
733
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
734
+ title ? /* @__PURE__ */ jsx2("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }) : null,
735
+ description ? /* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
736
+ ] }),
737
+ actions ? /* @__PURE__ */ jsx2("div", { className: "shrink-0", children: actions }) : null
738
+ ] });
739
+ };
740
+ function metricTilesGridColsClass(n) {
741
+ switch (n) {
742
+ case 1:
743
+ return "grid-cols-1";
744
+ case 2:
745
+ return "grid-cols-2";
746
+ case 3:
747
+ return "grid-cols-3";
748
+ case 5:
749
+ return "grid-cols-2 sm:grid-cols-5";
750
+ case 6:
751
+ return "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6";
752
+ default:
753
+ return "grid-cols-2 md:grid-cols-4";
754
+ }
755
+ }
756
+
757
+ // src/app/data/MetricTile.tsx
758
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
759
+ var trendToneClass = {
760
+ up: "border-border/80 bg-muted/40 text-muted-foreground",
761
+ down: "border-border/80 bg-muted/40 text-muted-foreground",
762
+ neutral: "border-border/80 bg-muted/30 text-muted-foreground"
763
+ };
764
+ var metricTileBaseClass = "relative flex min-w-0 flex-1 flex-col gap-1 px-4 py-3 text-left font-normal";
765
+ var metricTileInteractiveClass = cn(
766
+ metricTileBaseClass,
767
+ "bg-transparent hover:bg-transparent active:bg-transparent",
768
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
769
+ );
770
+ var MetricTile = ({
771
+ label,
772
+ value,
773
+ unit,
774
+ trend,
775
+ trendTone = "neutral",
776
+ active = false,
777
+ showDivider = false,
778
+ onSelect,
779
+ ariaLabel,
780
+ className
781
+ }) => {
782
+ const content = /* @__PURE__ */ jsxs2(Fragment, { children: [
783
+ active ? /* @__PURE__ */ jsx3(
784
+ "span",
785
+ {
786
+ "aria-hidden": true,
787
+ className: "absolute inset-x-0 bottom-0 h-0.5 bg-foreground dark:bg-white"
788
+ }
789
+ ) : null,
790
+ /* @__PURE__ */ jsx3("span", { className: "text-xs font-normal text-muted-foreground", children: label }),
791
+ /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-2", children: [
792
+ /* @__PURE__ */ jsxs2("span", { className: "flex items-baseline gap-1", children: [
793
+ /* @__PURE__ */ jsx3("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
794
+ unit ? /* @__PURE__ */ jsx3("span", { className: "text-xs font-normal text-muted-foreground", children: unit }) : null
795
+ ] }),
796
+ trend ? /* @__PURE__ */ jsx3(
797
+ "span",
798
+ {
799
+ className: cn(
800
+ "rounded-full border px-1.5 py-0.5 text-xs font-normal",
801
+ trendToneClass[trendTone]
802
+ ),
803
+ children: trend
804
+ }
805
+ ) : null
806
+ ] })
807
+ ] });
808
+ const divider = showDivider ? metricCellDividerClass : void 0;
809
+ if (onSelect) {
810
+ return /* @__PURE__ */ jsx3(
811
+ "button",
812
+ {
813
+ type: "button",
814
+ onClick: onSelect,
815
+ "aria-pressed": active,
816
+ "aria-label": ariaLabel,
817
+ className: cn(metricTileInteractiveClass, divider, className),
818
+ children: content
819
+ }
820
+ );
821
+ }
822
+ return /* @__PURE__ */ jsx3("div", { className: cn(metricTileBaseClass, divider, className), children: content });
823
+ };
824
+
825
+ // src/app/theme/ThemePresetGallery.tsx
826
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
827
+ var ThemePresetGallery = ({
828
+ value,
829
+ onSelect,
830
+ presets,
831
+ className
832
+ }) => {
833
+ const items = presets ? TIMBAL_THEME_PRESETS.filter((p) => presets.includes(p.id)) : TIMBAL_THEME_PRESETS;
834
+ return /* @__PURE__ */ jsx4(
835
+ "div",
836
+ {
837
+ role: "radiogroup",
838
+ "aria-label": "Theme presets",
839
+ className: cn(
840
+ "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",
841
+ className
842
+ ),
843
+ children: items.map((preset) => {
844
+ const selected = value === preset.id;
845
+ return /* @__PURE__ */ jsxs3("div", { "data-timbal-theme": preset.id, children: [
846
+ /* @__PURE__ */ jsx4(TimbalThemeStyle, { preset: preset.id, scope: preset.id }),
847
+ /* @__PURE__ */ jsxs3(
848
+ "button",
849
+ {
850
+ type: "button",
851
+ role: "radio",
852
+ "aria-checked": selected,
853
+ "aria-label": `${preset.label} theme`,
854
+ onClick: () => onSelect?.(preset.id),
855
+ className: cn(
856
+ "group flex w-full flex-col gap-3 rounded-xl border bg-card p-3 text-left transition-colors",
857
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
858
+ selected ? "border-primary ring-2 ring-primary/30" : "border-border hover:border-foreground/30"
859
+ ),
860
+ children: [
861
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between gap-2", children: [
862
+ /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2", children: [
863
+ /* @__PURE__ */ jsx4(
864
+ "span",
865
+ {
866
+ "aria-hidden": true,
867
+ className: "size-4 shrink-0 rounded-full ring-1 ring-black/10",
868
+ style: { background: preset.swatch }
869
+ }
870
+ ),
871
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium text-foreground", children: preset.label })
872
+ ] }),
873
+ selected ? /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium text-primary", children: "Selected" }) : null
874
+ ] }),
875
+ /* @__PURE__ */ jsx4("p", { className: "text-xs leading-snug text-muted-foreground", children: preset.description }),
876
+ /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2 rounded-lg border border-border bg-background p-2", children: [
877
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
878
+ /* @__PURE__ */ jsx4(Button, { size: "xs", className: "pointer-events-none", children: "Primary" }),
879
+ /* @__PURE__ */ jsx4("span", { className: "size-5 rounded-md bg-primary", "aria-hidden": true }),
880
+ /* @__PURE__ */ jsx4("span", { className: "size-5 rounded-md bg-muted", "aria-hidden": true }),
881
+ /* @__PURE__ */ jsx4(
882
+ "span",
883
+ {
884
+ className: "size-5 rounded-md border border-border bg-accent",
885
+ "aria-hidden": true
886
+ }
887
+ )
888
+ ] }),
889
+ /* @__PURE__ */ jsx4(MetricTile, { label: "Active users", value: "1,248", trend: "+8%" })
890
+ ] })
891
+ ]
892
+ }
893
+ )
894
+ ] }, preset.id);
895
+ })
896
+ }
897
+ );
898
+ };
899
+
221
900
  // src/design/app-classes.ts
222
901
  var appPageColumnClass = "mx-auto w-full max-w-6xl px-4 md:px-6";
223
902
  var appShellTopbarInsetClass = "w-full px-4 md:px-6";
@@ -282,7 +961,7 @@ function useAppShellChat() {
282
961
  // src/app/layout/AppShell.tsx
283
962
  import { motion, useReducedMotion } from "motion/react";
284
963
  import { useCallback, useState } from "react";
285
- import { jsx, jsxs } from "react/jsx-runtime";
964
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
286
965
  var floatingTriggerClass = cn(
287
966
  "aui-app-shell-chat-trigger-fixed fixed z-50 rounded-full px-5 py-2.5 text-sm font-medium shadow-card-elevated",
288
967
  "bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
@@ -311,14 +990,14 @@ var AppShellBody = ({
311
990
  layoutDirection
312
991
  );
313
992
  const insetPadding = sidebar ? insetPaddingPx : 0;
314
- return /* @__PURE__ */ jsx(
993
+ return /* @__PURE__ */ jsx5(
315
994
  motion.div,
316
995
  {
317
996
  className: "aui-app-shell-body relative z-10 flex min-h-0 min-w-0 flex-1 flex-col",
318
997
  initial: false,
319
998
  animate: { paddingLeft: insetPadding },
320
999
  transition: layoutTransition,
321
- children: /* @__PURE__ */ jsxs(
1000
+ children: /* @__PURE__ */ jsxs4(
322
1001
  "div",
323
1002
  {
324
1003
  className: cn(
@@ -326,8 +1005,8 @@ var AppShellBody = ({
326
1005
  !topbarContent && appShellInsetTopClass
327
1006
  ),
328
1007
  children: [
329
- topbarContent ? /* @__PURE__ */ jsx("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
330
- /* @__PURE__ */ jsx("main", { className: cn("aui-app-shell-main min-w-0 flex-1", mainClassName), children })
1008
+ topbarContent ? /* @__PURE__ */ jsx5("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx5("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
1009
+ /* @__PURE__ */ jsx5("main", { className: cn("aui-app-shell-main min-w-0 flex-1", mainClassName), children })
331
1010
  ]
332
1011
  }
333
1012
  )
@@ -375,7 +1054,7 @@ var AppShell = ({
375
1054
  setInsetPaddingPx(insetPx);
376
1055
  }, []);
377
1056
  const insetExpanded = insetPaddingPx >= SIDEBAR_INSET_PX_EXPANDED;
378
- const shellBody = /* @__PURE__ */ jsx(
1057
+ const shellBody = /* @__PURE__ */ jsx5(
379
1058
  AppShellBody,
380
1059
  {
381
1060
  sidebar,
@@ -386,7 +1065,7 @@ var AppShell = ({
386
1065
  children
387
1066
  }
388
1067
  );
389
- const tree = /* @__PURE__ */ jsx(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs(
1068
+ const tree = /* @__PURE__ */ jsx5(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs4(
390
1069
  "div",
391
1070
  {
392
1071
  className: cn(
@@ -397,7 +1076,7 @@ var AppShell = ({
397
1076
  children: [
398
1077
  sidebar,
399
1078
  shellBody,
400
- hasChat && chatOpen ? /* @__PURE__ */ jsx(
1079
+ hasChat && chatOpen ? /* @__PURE__ */ jsx5(
401
1080
  "div",
402
1081
  {
403
1082
  className: floatingPanelClass,
@@ -410,7 +1089,7 @@ var AppShell = ({
410
1089
  children: chat
411
1090
  }
412
1091
  ) : null,
413
- hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx(
1092
+ hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx5(
414
1093
  "button",
415
1094
  {
416
1095
  type: "button",
@@ -426,7 +1105,7 @@ var AppShell = ({
426
1105
  if (!hasChat) {
427
1106
  return tree;
428
1107
  }
429
- return /* @__PURE__ */ jsx(
1108
+ return /* @__PURE__ */ jsx5(
430
1109
  AppShellChatProvider,
431
1110
  {
432
1111
  value: {
@@ -441,24 +1120,24 @@ var AppShell = ({
441
1120
  };
442
1121
 
443
1122
  // src/app/layout/AppShellTopbar.tsx
444
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1123
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
445
1124
  var AppShellTopbar = ({
446
1125
  start,
447
1126
  actions,
448
1127
  children,
449
1128
  className
450
1129
  }) => {
451
- return /* @__PURE__ */ jsxs2("div", { className: cn("aui-app-shell-topbar", appShellTopbarRowClass, className), children: [
452
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1130
+ return /* @__PURE__ */ jsxs5("div", { className: cn("aui-app-shell-topbar", appShellTopbarRowClass, className), children: [
1131
+ /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
453
1132
  start,
454
1133
  children
455
1134
  ] }),
456
- actions ? /* @__PURE__ */ jsx2("div", { className: "aui-app-shell-topbar-actions flex shrink-0 items-center gap-2", children: actions }) : null
1135
+ actions ? /* @__PURE__ */ jsx6("div", { className: "aui-app-shell-topbar-actions flex shrink-0 items-center gap-2", children: actions }) : null
457
1136
  ] });
458
1137
  };
459
1138
 
460
1139
  // src/app/layout/AppShellChatTrigger.tsx
461
- import { jsx as jsx3 } from "react/jsx-runtime";
1140
+ import { jsx as jsx7 } from "react/jsx-runtime";
462
1141
  var floatingPositionClass = "fixed bottom-6 right-6 z-50 max-sm:bottom-4 max-sm:right-4";
463
1142
  var AppShellChatTrigger = ({
464
1143
  className,
@@ -467,7 +1146,7 @@ var AppShellChatTrigger = ({
467
1146
  }) => {
468
1147
  const shellChat = useAppShellChat();
469
1148
  if (!shellChat || shellChat.open) return null;
470
- return /* @__PURE__ */ jsx3(
1149
+ return /* @__PURE__ */ jsx7(
471
1150
  TimbalV2Button,
472
1151
  {
473
1152
  type: "button",
@@ -487,61 +1166,61 @@ var AppShellChatTrigger = ({
487
1166
  };
488
1167
 
489
1168
  // src/app/layout/PageHeader.tsx
490
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1169
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
491
1170
  var PageHeader = ({
492
1171
  title,
493
1172
  description,
494
1173
  actions,
495
1174
  className
496
1175
  }) => {
497
- return /* @__PURE__ */ jsxs3("header", { className: cn("aui-app-page-header", appPageHeaderClass, className), children: [
498
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
499
- /* @__PURE__ */ jsx4("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: title }),
500
- description ? /* @__PURE__ */ jsx4("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
1176
+ return /* @__PURE__ */ jsxs6("header", { className: cn("aui-app-page-header", appPageHeaderClass, className), children: [
1177
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
1178
+ /* @__PURE__ */ jsx8("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: title }),
1179
+ description ? /* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
501
1180
  ] }),
502
- actions ? /* @__PURE__ */ jsx4("div", { className: "aui-app-page-header-actions flex shrink-0 flex-wrap items-center gap-2", children: actions }) : null
1181
+ actions ? /* @__PURE__ */ jsx8("div", { className: "aui-app-page-header-actions flex shrink-0 flex-wrap items-center gap-2", children: actions }) : null
503
1182
  ] });
504
1183
  };
505
1184
 
506
1185
  // src/app/layout/Page.tsx
507
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1186
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
508
1187
  var Page = ({
509
1188
  children,
510
1189
  breadcrumbs,
511
1190
  className,
512
1191
  ...headerProps
513
1192
  }) => {
514
- return /* @__PURE__ */ jsxs4("div", { className: cn("aui-app-page", appPageColumnClass, className), children: [
1193
+ return /* @__PURE__ */ jsxs7("div", { className: cn("aui-app-page", appPageColumnClass, className), children: [
515
1194
  breadcrumbs,
516
- /* @__PURE__ */ jsx5(PageHeader, { ...headerProps }),
1195
+ /* @__PURE__ */ jsx9(PageHeader, { ...headerProps }),
517
1196
  children
518
1197
  ] });
519
1198
  };
520
1199
 
521
1200
  // src/app/layout/Section.tsx
522
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1201
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
523
1202
  var Section = ({
524
1203
  title,
525
1204
  description,
526
1205
  children,
527
1206
  className
528
1207
  }) => {
529
- return /* @__PURE__ */ jsxs5("section", { className: cn("aui-app-section", appSectionClass, className), children: [
530
- title ? /* @__PURE__ */ jsx6("h2", { className: appSectionTitleClass, children: title }) : null,
531
- description ? /* @__PURE__ */ jsx6("p", { className: appSectionDescriptionClass, children: description }) : null,
1208
+ return /* @__PURE__ */ jsxs8("section", { className: cn("aui-app-section", appSectionClass, className), children: [
1209
+ title ? /* @__PURE__ */ jsx10("h2", { className: appSectionTitleClass, children: title }) : null,
1210
+ description ? /* @__PURE__ */ jsx10("p", { className: appSectionDescriptionClass, children: description }) : null,
532
1211
  children
533
1212
  ] });
534
1213
  };
535
1214
 
536
1215
  // src/app/copilot/app-copilot-context.tsx
537
1216
  import { createContext as createContext2, useContext as useContext2 } from "react";
538
- import { jsx as jsx7 } from "react/jsx-runtime";
1217
+ import { jsx as jsx11 } from "react/jsx-runtime";
539
1218
  var AppCopilotContext = createContext2(null);
540
1219
  var AppCopilotProvider = ({
541
1220
  value,
542
1221
  children
543
1222
  }) => {
544
- return /* @__PURE__ */ jsx7(AppCopilotContext.Provider, { value, children });
1223
+ return /* @__PURE__ */ jsx11(AppCopilotContext.Provider, { value, children });
545
1224
  };
546
1225
  function useAppCopilotContext() {
547
1226
  return useContext2(AppCopilotContext) ?? {};
@@ -549,7 +1228,7 @@ function useAppCopilotContext() {
549
1228
 
550
1229
  // src/app/chat/AppChatPanel.tsx
551
1230
  import { XIcon } from "lucide-react";
552
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1231
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
553
1232
  var shellClass = "aui-app-chat-panel flex h-full min-h-0 flex-col overflow-hidden";
554
1233
  var chromeClass = cn(
555
1234
  "aui-app-chat-panel-chrome relative z-20 flex min-h-10 shrink-0 items-center justify-end px-2 pt-2"
@@ -594,18 +1273,18 @@ var AppChatPanel = ({
594
1273
  ...rest
595
1274
  }) => {
596
1275
  const shellChat = useAppShellChat();
597
- return /* @__PURE__ */ jsxs6("div", { className: cn(shellClass, className), children: [
598
- shellChat?.collapsible ? /* @__PURE__ */ jsx8("div", { className: chromeClass, children: /* @__PURE__ */ jsx8(
1276
+ return /* @__PURE__ */ jsxs9("div", { className: cn(shellClass, className), children: [
1277
+ shellChat?.collapsible ? /* @__PURE__ */ jsx12("div", { className: chromeClass, children: /* @__PURE__ */ jsx12(
599
1278
  "button",
600
1279
  {
601
1280
  type: "button",
602
1281
  className: closeButtonClass,
603
1282
  onClick: () => shellChat.setOpen(false),
604
1283
  "aria-label": "Close assistant",
605
- children: /* @__PURE__ */ jsx8(XIcon, { className: "size-4", "aria-hidden": true })
1284
+ children: /* @__PURE__ */ jsx12(XIcon, { className: "size-4", "aria-hidden": true })
606
1285
  }
607
1286
  ) }) : null,
608
- /* @__PURE__ */ jsx8("div", { className: bodyClass, children: /* @__PURE__ */ jsx8(
1287
+ /* @__PURE__ */ jsx12("div", { className: bodyClass, children: /* @__PURE__ */ jsx12(
609
1288
  TimbalRuntimeProvider,
610
1289
  {
611
1290
  workforceId,
@@ -615,7 +1294,7 @@ var AppChatPanel = ({
615
1294
  attachmentsUploadUrl,
616
1295
  attachmentsAccept,
617
1296
  debug,
618
- children: /* @__PURE__ */ jsx8(
1297
+ children: /* @__PURE__ */ jsx12(
619
1298
  Thread,
620
1299
  {
621
1300
  variant: "panel",
@@ -636,38 +1315,38 @@ var AppChatPanel = ({
636
1315
  };
637
1316
 
638
1317
  // src/app/surfaces/SurfaceCard.tsx
639
- import { jsx as jsx9 } from "react/jsx-runtime";
1318
+ import { jsx as jsx13 } from "react/jsx-runtime";
640
1319
  var SurfaceCard = ({ children, className }) => {
641
- return /* @__PURE__ */ jsx9("div", { className: cn("aui-app-surface-card", appSurfaceCardClass, className), children });
1320
+ return /* @__PURE__ */ jsx13("div", { className: cn("aui-app-surface-card", appSurfaceCardClass, className), children });
642
1321
  };
643
1322
 
644
1323
  // src/app/surfaces/StatTile.tsx
645
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1324
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
646
1325
  var StatTile = ({ label, value, hint, className }) => {
647
- return /* @__PURE__ */ jsxs7("div", { className: cn("aui-app-stat-tile", appStatTileClass, className), children: [
648
- /* @__PURE__ */ jsx10("span", { className: appStatLabelClass, children: label }),
649
- /* @__PURE__ */ jsx10("span", { className: appStatValueClass, children: value }),
650
- hint ? /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: hint }) : null
1326
+ return /* @__PURE__ */ jsxs10("div", { className: cn("aui-app-stat-tile", appStatTileClass, className), children: [
1327
+ /* @__PURE__ */ jsx14("span", { className: appStatLabelClass, children: label }),
1328
+ /* @__PURE__ */ jsx14("span", { className: appStatValueClass, children: value }),
1329
+ hint ? /* @__PURE__ */ jsx14("span", { className: "text-xs text-muted-foreground", children: hint }) : null
651
1330
  ] });
652
1331
  };
653
1332
 
654
1333
  // src/app/surfaces/EmptyState.tsx
655
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1334
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
656
1335
  var EmptyState = ({
657
1336
  title,
658
1337
  description,
659
1338
  action,
660
1339
  className
661
1340
  }) => {
662
- return /* @__PURE__ */ jsxs8("div", { className: cn("aui-app-empty-state", appEmptyStateClass, className), children: [
663
- /* @__PURE__ */ jsx11("p", { className: appEmptyStateTitleClass, children: title }),
664
- description ? /* @__PURE__ */ jsx11("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
1341
+ return /* @__PURE__ */ jsxs11("div", { className: cn("aui-app-empty-state", appEmptyStateClass, className), children: [
1342
+ /* @__PURE__ */ jsx15("p", { className: appEmptyStateTitleClass, children: title }),
1343
+ description ? /* @__PURE__ */ jsx15("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
665
1344
  action
666
1345
  ] });
667
1346
  };
668
1347
 
669
1348
  // src/app/surfaces/StatusBadge.tsx
670
- import { jsx as jsx12 } from "react/jsx-runtime";
1349
+ import { jsx as jsx16 } from "react/jsx-runtime";
671
1350
  var statusBadgeToneClass = {
672
1351
  default: "bg-muted text-foreground",
673
1352
  primary: "bg-primary/10 text-primary",
@@ -680,7 +1359,7 @@ var StatusBadge = ({
680
1359
  tone = "default",
681
1360
  className
682
1361
  }) => {
683
- return /* @__PURE__ */ jsx12(
1362
+ return /* @__PURE__ */ jsx16(
684
1363
  "span",
685
1364
  {
686
1365
  className: cn(
@@ -694,7 +1373,7 @@ var StatusBadge = ({
694
1373
  };
695
1374
 
696
1375
  // src/app/surfaces/AppConfirmDialog.tsx
697
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
1376
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
698
1377
  var bodyClass2 = "flex flex-col gap-4 p-6";
699
1378
  var titleClass = "pr-8";
700
1379
  var actionsClass = "flex flex-wrap justify-end gap-2";
@@ -709,15 +1388,15 @@ var AppConfirmDialog = ({
709
1388
  destructive = false,
710
1389
  className
711
1390
  }) => {
712
- return /* @__PURE__ */ jsx13(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx13(
1391
+ return /* @__PURE__ */ jsx17(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx17(
713
1392
  DialogContent,
714
1393
  {
715
1394
  className: cn("gap-0 p-0 sm:max-w-md", className),
716
- children: /* @__PURE__ */ jsxs9("div", { className: bodyClass2, children: [
717
- /* @__PURE__ */ jsx13(DialogTitle, { className: titleClass, children: title }),
718
- description ? /* @__PURE__ */ jsx13("p", { className: "text-sm text-muted-foreground", children: description }) : null,
719
- /* @__PURE__ */ jsxs9("div", { className: actionsClass, children: [
720
- /* @__PURE__ */ jsx13(
1395
+ children: /* @__PURE__ */ jsxs12("div", { className: bodyClass2, children: [
1396
+ /* @__PURE__ */ jsx17(DialogTitle, { className: titleClass, children: title }),
1397
+ description ? /* @__PURE__ */ jsx17("p", { className: "text-sm text-muted-foreground", children: description }) : null,
1398
+ /* @__PURE__ */ jsxs12("div", { className: actionsClass, children: [
1399
+ /* @__PURE__ */ jsx17(
721
1400
  TimbalV2Button,
722
1401
  {
723
1402
  type: "button",
@@ -727,7 +1406,7 @@ var AppConfirmDialog = ({
727
1406
  children: cancelLabel
728
1407
  }
729
1408
  ),
730
- /* @__PURE__ */ jsx13(
1409
+ /* @__PURE__ */ jsx17(
731
1410
  TimbalV2Button,
732
1411
  {
733
1412
  type: "button",
@@ -747,7 +1426,7 @@ var AppConfirmDialog = ({
747
1426
  };
748
1427
 
749
1428
  // src/app/surfaces/InfoCard.tsx
750
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1429
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
751
1430
  var toneClass = {
752
1431
  neutral: "border-border bg-muted/40",
753
1432
  info: "border-primary/25 bg-primary/5",
@@ -762,7 +1441,7 @@ var InfoCard = ({
762
1441
  action,
763
1442
  tone = "neutral",
764
1443
  className
765
- }) => /* @__PURE__ */ jsxs10(
1444
+ }) => /* @__PURE__ */ jsxs13(
766
1445
  "div",
767
1446
  {
768
1447
  className: cn(
@@ -771,18 +1450,18 @@ var InfoCard = ({
771
1450
  className
772
1451
  ),
773
1452
  children: [
774
- icon ? /* @__PURE__ */ jsx14("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
775
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
776
- title ? /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
777
- children ? /* @__PURE__ */ jsx14("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
1453
+ icon ? /* @__PURE__ */ jsx18("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
1454
+ /* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1", children: [
1455
+ title ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
1456
+ children ? /* @__PURE__ */ jsx18("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
778
1457
  ] }),
779
- action ? /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: action }) : null
1458
+ action ? /* @__PURE__ */ jsx18("div", { className: "shrink-0", children: action }) : null
780
1459
  ]
781
1460
  }
782
1461
  );
783
1462
 
784
1463
  // src/app/surfaces/StatusDot.tsx
785
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1464
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
786
1465
  var dotClass = {
787
1466
  online: "bg-emerald-500",
788
1467
  busy: "bg-amber-500",
@@ -795,9 +1474,9 @@ var StatusDot = ({
795
1474
  label,
796
1475
  pulse = false,
797
1476
  className
798
- }) => /* @__PURE__ */ jsxs11("span", { className: cn("inline-flex items-center gap-1.5", className), children: [
799
- /* @__PURE__ */ jsxs11("span", { className: "relative flex size-2", children: [
800
- pulse ? /* @__PURE__ */ jsx15(
1477
+ }) => /* @__PURE__ */ jsxs14("span", { className: cn("inline-flex items-center gap-1.5", className), children: [
1478
+ /* @__PURE__ */ jsxs14("span", { className: "relative flex size-2", children: [
1479
+ pulse ? /* @__PURE__ */ jsx19(
801
1480
  "span",
802
1481
  {
803
1482
  className: cn(
@@ -806,25 +1485,25 @@ var StatusDot = ({
806
1485
  )
807
1486
  }
808
1487
  ) : null,
809
- /* @__PURE__ */ jsx15("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
1488
+ /* @__PURE__ */ jsx19("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
810
1489
  ] }),
811
- label ? /* @__PURE__ */ jsx15("span", { className: "text-xs text-muted-foreground", children: label }) : null
1490
+ label ? /* @__PURE__ */ jsx19("span", { className: "text-xs text-muted-foreground", children: label }) : null
812
1491
  ] });
813
1492
 
814
1493
  // src/app/surfaces/DescriptionList.tsx
815
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1494
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
816
1495
  var DescriptionList = ({
817
1496
  items,
818
1497
  stacked = false,
819
1498
  className
820
- }) => /* @__PURE__ */ jsx16(
1499
+ }) => /* @__PURE__ */ jsx20(
821
1500
  "dl",
822
1501
  {
823
1502
  className: cn(
824
1503
  "divide-y divide-border rounded-xl border border-border bg-card",
825
1504
  className
826
1505
  ),
827
- children: items.map((item, i) => /* @__PURE__ */ jsxs12(
1506
+ children: items.map((item, i) => /* @__PURE__ */ jsxs15(
828
1507
  "div",
829
1508
  {
830
1509
  className: cn(
@@ -832,8 +1511,8 @@ var DescriptionList = ({
832
1511
  stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4"
833
1512
  ),
834
1513
  children: [
835
- /* @__PURE__ */ jsx16("dt", { className: "text-sm text-muted-foreground", children: item.label }),
836
- /* @__PURE__ */ jsx16(
1514
+ /* @__PURE__ */ jsx20("dt", { className: "text-sm text-muted-foreground", children: item.label }),
1515
+ /* @__PURE__ */ jsx20(
837
1516
  "dd",
838
1517
  {
839
1518
  className: cn(
@@ -853,8 +1532,8 @@ var DescriptionList = ({
853
1532
  // src/app/surfaces/ExpandableSection.tsx
854
1533
  import { useId, useState as useState2 } from "react";
855
1534
  import { AnimatePresence, motion as motion2, useReducedMotion as useReducedMotion2 } from "motion/react";
856
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
857
- var Chevron = ({ open }) => /* @__PURE__ */ jsx17(
1535
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1536
+ var Chevron = ({ open }) => /* @__PURE__ */ jsx21(
858
1537
  "svg",
859
1538
  {
860
1539
  viewBox: "0 0 24 24",
@@ -868,7 +1547,7 @@ var Chevron = ({ open }) => /* @__PURE__ */ jsx17(
868
1547
  strokeLinecap: "round",
869
1548
  strokeLinejoin: "round",
870
1549
  "aria-hidden": true,
871
- children: /* @__PURE__ */ jsx17("path", { d: "m6 9 6 6 6-6" })
1550
+ children: /* @__PURE__ */ jsx21("path", { d: "m6 9 6 6 6-6" })
872
1551
  }
873
1552
  );
874
1553
  var ExpandableSection = ({
@@ -889,8 +1568,8 @@ var ExpandableSection = ({
889
1568
  if (openProp == null) setInternalOpen((o) => !o);
890
1569
  onOpenChange?.(!open);
891
1570
  };
892
- return /* @__PURE__ */ jsxs13("div", { className: cn("border-b border-border last:border-0", className), children: [
893
- /* @__PURE__ */ jsxs13(
1571
+ return /* @__PURE__ */ jsxs16("div", { className: cn("border-b border-border last:border-0", className), children: [
1572
+ /* @__PURE__ */ jsxs16(
894
1573
  "button",
895
1574
  {
896
1575
  type: "button",
@@ -899,16 +1578,16 @@ var ExpandableSection = ({
899
1578
  "aria-controls": panelId,
900
1579
  className: "flex w-full items-center justify-between gap-3 bg-transparent px-4 py-3 text-left hover:bg-transparent active:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10",
901
1580
  children: [
902
- /* @__PURE__ */ jsxs13("span", { className: "flex min-w-0 items-center gap-3", children: [
903
- icon ? /* @__PURE__ */ jsx17("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
904
- /* @__PURE__ */ jsx17("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
905
- count != null ? /* @__PURE__ */ jsx17("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
1581
+ /* @__PURE__ */ jsxs16("span", { className: "flex min-w-0 items-center gap-3", children: [
1582
+ icon ? /* @__PURE__ */ jsx21("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
1583
+ /* @__PURE__ */ jsx21("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
1584
+ count != null ? /* @__PURE__ */ jsx21("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
906
1585
  ] }),
907
- /* @__PURE__ */ jsx17(Chevron, { open })
1586
+ /* @__PURE__ */ jsx21(Chevron, { open })
908
1587
  ]
909
1588
  }
910
1589
  ),
911
- /* @__PURE__ */ jsx17(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx17(
1590
+ /* @__PURE__ */ jsx21(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx21(
912
1591
  motion2.div,
913
1592
  {
914
1593
  id: panelId,
@@ -917,7 +1596,7 @@ var ExpandableSection = ({
917
1596
  exit: reduceMotion ? void 0 : { height: 0, opacity: 0 },
918
1597
  transition: { duration: 0.2, ease: "easeOut" },
919
1598
  className: "overflow-hidden",
920
- children: /* @__PURE__ */ jsx17("div", { className: "bg-muted/20", children })
1599
+ children: /* @__PURE__ */ jsx21("div", { className: "bg-muted/20", children })
921
1600
  },
922
1601
  "body"
923
1602
  ) : null })
@@ -925,7 +1604,7 @@ var ExpandableSection = ({
925
1604
  };
926
1605
 
927
1606
  // src/app/surfaces/ResourceCard.tsx
928
- import { Fragment, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1607
+ import { Fragment as Fragment2, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
929
1608
  var resourceCardShellClass = cn(
930
1609
  "flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal",
931
1610
  TIMBAL_V2_ELEVATED_SURFACE
@@ -950,35 +1629,35 @@ var ResourceCard = ({
950
1629
  ariaLabel,
951
1630
  className
952
1631
  }) => {
953
- const body = /* @__PURE__ */ jsxs14(Fragment, { children: [
954
- /* @__PURE__ */ jsxs14("div", { className: "flex items-start gap-3", children: [
955
- media ? /* @__PURE__ */ jsx18("span", { className: mediaShellClass, children: media }) : null,
956
- /* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1 pt-0.5", children: [
957
- /* @__PURE__ */ jsx18("p", { className: "truncate text-sm font-normal leading-snug text-foreground", children: title }),
958
- subtitle ? /* @__PURE__ */ jsx18("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground", children: subtitle }) : null
1632
+ const body = /* @__PURE__ */ jsxs17(Fragment2, { children: [
1633
+ /* @__PURE__ */ jsxs17("div", { className: "flex items-start gap-3", children: [
1634
+ media ? /* @__PURE__ */ jsx22("span", { className: mediaShellClass, children: media }) : null,
1635
+ /* @__PURE__ */ jsxs17("div", { className: "min-w-0 flex-1 pt-0.5", children: [
1636
+ /* @__PURE__ */ jsx22("p", { className: "truncate text-sm font-normal leading-snug text-foreground", children: title }),
1637
+ subtitle ? /* @__PURE__ */ jsx22("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground", children: subtitle }) : null
959
1638
  ] }),
960
- badge ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 pt-0.5", children: badge }) : null
1639
+ badge ? /* @__PURE__ */ jsx22("span", { className: "shrink-0 pt-0.5", children: badge }) : null
961
1640
  ] }),
962
- footer || action ? /* @__PURE__ */ jsxs14("div", { className: "mt-auto flex items-center justify-between gap-3 border-t border-border/40 pt-3 text-xs font-normal text-muted-foreground", children: [
963
- /* @__PURE__ */ jsx18("span", { className: "min-w-0 truncate", children: footer }),
964
- action ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 opacity-80", children: action }) : null
1641
+ footer || action ? /* @__PURE__ */ jsxs17("div", { className: "mt-auto flex items-center justify-between gap-3 border-t border-border/40 pt-3 text-xs font-normal text-muted-foreground", children: [
1642
+ /* @__PURE__ */ jsx22("span", { className: "min-w-0 truncate", children: footer }),
1643
+ action ? /* @__PURE__ */ jsx22("span", { className: "shrink-0 opacity-80", children: action }) : null
965
1644
  ] }) : null
966
1645
  ] });
967
1646
  if (onClick) {
968
- return /* @__PURE__ */ jsx18("button", { type: "button", onClick, "aria-label": ariaLabel, className: cn(resourceCardInteractiveClass, className), children: body });
1647
+ return /* @__PURE__ */ jsx22("button", { type: "button", onClick, "aria-label": ariaLabel, className: cn(resourceCardInteractiveClass, className), children: body });
969
1648
  }
970
- return /* @__PURE__ */ jsx18("article", { className: cn(resourceCardShellClass, className), children: body });
1649
+ return /* @__PURE__ */ jsx22("article", { className: cn(resourceCardShellClass, className), children: body });
971
1650
  };
972
1651
 
973
1652
  // src/app/settings/SettingsSection.tsx
974
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1653
+ import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
975
1654
  var SettingsSectionHeader = ({
976
1655
  title,
977
1656
  description,
978
1657
  className
979
- }) => /* @__PURE__ */ jsxs15("div", { className: cn("flex flex-col", className), children: [
980
- /* @__PURE__ */ jsx19("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
981
- description ? /* @__PURE__ */ jsx19("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
1658
+ }) => /* @__PURE__ */ jsxs18("div", { className: cn("flex flex-col", className), children: [
1659
+ /* @__PURE__ */ jsx23("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
1660
+ description ? /* @__PURE__ */ jsx23("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
982
1661
  ] });
983
1662
  var SettingsSection = ({
984
1663
  title,
@@ -987,7 +1666,7 @@ var SettingsSection = ({
987
1666
  children,
988
1667
  noBorderTop = false,
989
1668
  className
990
- }) => /* @__PURE__ */ jsxs15(
1669
+ }) => /* @__PURE__ */ jsxs18(
991
1670
  "section",
992
1671
  {
993
1672
  className: cn(
@@ -996,18 +1675,18 @@ var SettingsSection = ({
996
1675
  className
997
1676
  ),
998
1677
  children: [
999
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0", children: [
1000
- /* @__PURE__ */ jsx19("h2", { className: "text-sm font-medium text-foreground", children: title }),
1001
- description ? /* @__PURE__ */ jsx19("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
1002
- descriptionFooter ? /* @__PURE__ */ jsx19("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
1678
+ /* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
1679
+ /* @__PURE__ */ jsx23("h2", { className: "text-sm font-medium text-foreground", children: title }),
1680
+ description ? /* @__PURE__ */ jsx23("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
1681
+ descriptionFooter ? /* @__PURE__ */ jsx23("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
1003
1682
  ] }),
1004
- /* @__PURE__ */ jsx19("div", { className: "min-w-0 space-y-3", children })
1683
+ /* @__PURE__ */ jsx23("div", { className: "min-w-0 space-y-3", children })
1005
1684
  ]
1006
1685
  }
1007
1686
  );
1008
1687
 
1009
1688
  // src/app/settings/FieldRow.tsx
1010
- import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
1689
+ import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
1011
1690
  var FieldRow = ({
1012
1691
  label,
1013
1692
  children,
@@ -1017,7 +1696,7 @@ var FieldRow = ({
1017
1696
  className
1018
1697
  }) => {
1019
1698
  if (inline) {
1020
- return /* @__PURE__ */ jsxs16(
1699
+ return /* @__PURE__ */ jsxs19(
1021
1700
  "div",
1022
1701
  {
1023
1702
  className: cn(
@@ -1025,8 +1704,8 @@ var FieldRow = ({
1025
1704
  className
1026
1705
  ),
1027
1706
  children: [
1028
- /* @__PURE__ */ jsxs16("div", { className: "min-w-0", children: [
1029
- /* @__PURE__ */ jsx20(
1707
+ /* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
1708
+ /* @__PURE__ */ jsx24(
1030
1709
  "label",
1031
1710
  {
1032
1711
  htmlFor,
@@ -1034,17 +1713,17 @@ var FieldRow = ({
1034
1713
  children: label
1035
1714
  }
1036
1715
  ),
1037
- description ? /* @__PURE__ */ jsx20("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
1716
+ description ? /* @__PURE__ */ jsx24("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
1038
1717
  ] }),
1039
- /* @__PURE__ */ jsx20("div", { className: "shrink-0", children })
1718
+ /* @__PURE__ */ jsx24("div", { className: "shrink-0", children })
1040
1719
  ]
1041
1720
  }
1042
1721
  );
1043
1722
  }
1044
- return /* @__PURE__ */ jsxs16("div", { className: cn("flex flex-col gap-1.5", className), children: [
1045
- /* @__PURE__ */ jsx20("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
1723
+ return /* @__PURE__ */ jsxs19("div", { className: cn("flex flex-col gap-1.5", className), children: [
1724
+ /* @__PURE__ */ jsx24("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
1046
1725
  children,
1047
- description ? /* @__PURE__ */ jsx20("p", { className: "text-xs text-muted-foreground", children: description }) : null
1726
+ description ? /* @__PURE__ */ jsx24("p", { className: "text-xs text-muted-foreground", children: description }) : null
1048
1727
  ] });
1049
1728
  };
1050
1729
 
@@ -1052,7 +1731,7 @@ var FieldRow = ({
1052
1731
  import { useEffect, useState as useState3 } from "react";
1053
1732
  import { createPortal } from "react-dom";
1054
1733
  import { AnimatePresence as AnimatePresence2, motion as motion3, useReducedMotion as useReducedMotion3 } from "motion/react";
1055
- import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
1734
+ import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
1056
1735
  var FloatingUnsavedChangesBar = ({
1057
1736
  visible,
1058
1737
  message = "Unsaved changes",
@@ -1070,7 +1749,7 @@ var FloatingUnsavedChangesBar = ({
1070
1749
  useEffect(() => setMounted(true), []);
1071
1750
  if (!mounted || typeof document === "undefined") return null;
1072
1751
  return createPortal(
1073
- /* @__PURE__ */ jsx21(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx21("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs17(
1752
+ /* @__PURE__ */ jsx25(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx25("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs20(
1074
1753
  motion3.div,
1075
1754
  {
1076
1755
  role: "region",
@@ -1084,10 +1763,10 @@ var FloatingUnsavedChangesBar = ({
1084
1763
  className
1085
1764
  ),
1086
1765
  children: [
1087
- /* @__PURE__ */ jsx21("span", { className: "text-sm text-muted-foreground", children: message }),
1088
- /* @__PURE__ */ jsxs17("span", { className: "flex items-center gap-1.5", children: [
1089
- /* @__PURE__ */ jsx21(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
1090
- /* @__PURE__ */ jsx21(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
1766
+ /* @__PURE__ */ jsx25("span", { className: "text-sm text-muted-foreground", children: message }),
1767
+ /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-1.5", children: [
1768
+ /* @__PURE__ */ jsx25(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
1769
+ /* @__PURE__ */ jsx25(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
1091
1770
  ] })
1092
1771
  ]
1093
1772
  }
@@ -1097,13 +1776,13 @@ var FloatingUnsavedChangesBar = ({
1097
1776
  };
1098
1777
 
1099
1778
  // src/app/settings/DangerZone.tsx
1100
- import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
1779
+ import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
1101
1780
  var DangerZoneAction = ({
1102
1781
  title,
1103
1782
  description,
1104
1783
  action,
1105
1784
  className
1106
- }) => /* @__PURE__ */ jsxs18(
1785
+ }) => /* @__PURE__ */ jsxs21(
1107
1786
  "div",
1108
1787
  {
1109
1788
  className: cn(
@@ -1111,11 +1790,11 @@ var DangerZoneAction = ({
1111
1790
  className
1112
1791
  ),
1113
1792
  children: [
1114
- /* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
1115
- /* @__PURE__ */ jsx22("p", { className: "text-sm font-medium text-foreground", children: title }),
1116
- description ? /* @__PURE__ */ jsx22("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1793
+ /* @__PURE__ */ jsxs21("div", { className: "min-w-0", children: [
1794
+ /* @__PURE__ */ jsx26("p", { className: "text-sm font-medium text-foreground", children: title }),
1795
+ description ? /* @__PURE__ */ jsx26("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1117
1796
  ] }),
1118
- /* @__PURE__ */ jsx22("div", { className: "shrink-0", children: action })
1797
+ /* @__PURE__ */ jsx26("div", { className: "shrink-0", children: action })
1119
1798
  ]
1120
1799
  }
1121
1800
  );
@@ -1124,7 +1803,7 @@ var DangerZone = ({
1124
1803
  description,
1125
1804
  children,
1126
1805
  className
1127
- }) => /* @__PURE__ */ jsxs18(
1806
+ }) => /* @__PURE__ */ jsxs21(
1128
1807
  "section",
1129
1808
  {
1130
1809
  className: cn(
@@ -1132,18 +1811,18 @@ var DangerZone = ({
1132
1811
  className
1133
1812
  ),
1134
1813
  children: [
1135
- (title || description) && /* @__PURE__ */ jsxs18("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
1136
- title ? /* @__PURE__ */ jsx22("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
1137
- description ? /* @__PURE__ */ jsx22("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1814
+ (title || description) && /* @__PURE__ */ jsxs21("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
1815
+ title ? /* @__PURE__ */ jsx26("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
1816
+ description ? /* @__PURE__ */ jsx26("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1138
1817
  ] }),
1139
- /* @__PURE__ */ jsx22("div", { className: "divide-y divide-border bg-card", children })
1818
+ /* @__PURE__ */ jsx26("div", { className: "divide-y divide-border bg-card", children })
1140
1819
  ]
1141
1820
  }
1142
1821
  );
1143
1822
 
1144
1823
  // src/app/integrations/IntegrationCard.tsx
1145
1824
  import { useId as useId2 } from "react";
1146
- import { Fragment as Fragment2, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
1825
+ import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
1147
1826
  var INTEGRATION_CATALOG_CARD_HEIGHT_CLASS = "h-[12.25rem] min-h-[12.25rem] max-h-[12.25rem]";
1148
1827
  var statusLabel = {
1149
1828
  available: null,
@@ -1184,12 +1863,12 @@ var IntegrationCard = ({
1184
1863
  const titleId = useId2();
1185
1864
  const locked = status === "locked";
1186
1865
  const dimmed = status === "disabled" || locked;
1187
- const body = /* @__PURE__ */ jsxs19("div", { className: "flex h-full min-h-0 flex-col", children: [
1188
- /* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
1189
- logo ? /* @__PURE__ */ jsx23("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
1190
- /* @__PURE__ */ jsx23("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs19("div", { className: "flex items-start justify-between gap-2", children: [
1191
- /* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
1192
- /* @__PURE__ */ jsx23(
1866
+ const body = /* @__PURE__ */ jsxs22("div", { className: "flex h-full min-h-0 flex-col", children: [
1867
+ /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
1868
+ logo ? /* @__PURE__ */ jsx27("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
1869
+ /* @__PURE__ */ jsx27("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs22("div", { className: "flex items-start justify-between gap-2", children: [
1870
+ /* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
1871
+ /* @__PURE__ */ jsx27(
1193
1872
  "h4",
1194
1873
  {
1195
1874
  id: onClick && !action ? void 0 : titleId,
@@ -1197,12 +1876,12 @@ var IntegrationCard = ({
1197
1876
  children: name
1198
1877
  }
1199
1878
  ),
1200
- statusLabel[status] ? /* @__PURE__ */ jsx23("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
1879
+ statusLabel[status] ? /* @__PURE__ */ jsx27("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
1201
1880
  ] }),
1202
- badge ? /* @__PURE__ */ jsx23("span", { className: "shrink-0", children: badge }) : null
1881
+ badge ? /* @__PURE__ */ jsx27("span", { className: "shrink-0", children: badge }) : null
1203
1882
  ] }) })
1204
1883
  ] }),
1205
- description ? /* @__PURE__ */ jsx23(
1884
+ description ? /* @__PURE__ */ jsx27(
1206
1885
  "p",
1207
1886
  {
1208
1887
  className: cn(
@@ -1212,9 +1891,9 @@ var IntegrationCard = ({
1212
1891
  children: description
1213
1892
  }
1214
1893
  ) : null,
1215
- action ? /* @__PURE__ */ jsxs19(Fragment2, { children: [
1216
- /* @__PURE__ */ jsx23("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
1217
- /* @__PURE__ */ jsx23("div", { className: "relative mt-3 shrink-0", children: action })
1894
+ action ? /* @__PURE__ */ jsxs22(Fragment3, { children: [
1895
+ /* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
1896
+ /* @__PURE__ */ jsx27("div", { className: "relative mt-3 shrink-0", children: action })
1218
1897
  ] }) : null
1219
1898
  ] });
1220
1899
  const shellClass3 = cn(
@@ -1224,7 +1903,7 @@ var IntegrationCard = ({
1224
1903
  className
1225
1904
  );
1226
1905
  if (onClick && !action) {
1227
- return /* @__PURE__ */ jsx23(
1906
+ return /* @__PURE__ */ jsx27(
1228
1907
  "button",
1229
1908
  {
1230
1909
  type: "button",
@@ -1241,12 +1920,12 @@ var IntegrationCard = ({
1241
1920
  }
1242
1921
  );
1243
1922
  }
1244
- return /* @__PURE__ */ jsx23("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
1923
+ return /* @__PURE__ */ jsx27("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
1245
1924
  };
1246
1925
 
1247
1926
  // src/app/integrations/IntegrationsEmptyState.tsx
1248
1927
  import { useId as useId3 } from "react";
1249
- import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
1928
+ import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
1250
1929
  var IntegrationsEmptyState = ({
1251
1930
  title = "No integrations yet",
1252
1931
  description = "Connect a provider to start syncing data and powering your workforce.",
@@ -1255,7 +1934,7 @@ var IntegrationsEmptyState = ({
1255
1934
  className
1256
1935
  }) => {
1257
1936
  const titleId = useId3();
1258
- return /* @__PURE__ */ jsxs20(
1937
+ return /* @__PURE__ */ jsxs23(
1259
1938
  "section",
1260
1939
  {
1261
1940
  className: cn(
@@ -1265,7 +1944,7 @@ var IntegrationsEmptyState = ({
1265
1944
  ),
1266
1945
  "aria-labelledby": titleId,
1267
1946
  children: [
1268
- icon ? /* @__PURE__ */ jsx24(
1947
+ icon ? /* @__PURE__ */ jsx28(
1269
1948
  "span",
1270
1949
  {
1271
1950
  className: cn(
@@ -1277,21 +1956,21 @@ var IntegrationsEmptyState = ({
1277
1956
  children: icon
1278
1957
  }
1279
1958
  ) : null,
1280
- /* @__PURE__ */ jsx24("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
1281
- description ? /* @__PURE__ */ jsx24("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
1282
- action ? /* @__PURE__ */ jsx24("div", { className: "mt-1", children: action }) : null
1959
+ /* @__PURE__ */ jsx28("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
1960
+ description ? /* @__PURE__ */ jsx28("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
1961
+ action ? /* @__PURE__ */ jsx28("div", { className: "mt-1", children: action }) : null
1283
1962
  ]
1284
1963
  }
1285
1964
  );
1286
1965
  };
1287
1966
 
1288
1967
  // src/app/integrations/PlanBadge.tsx
1289
- import { jsx as jsx25 } from "react/jsx-runtime";
1968
+ import { jsx as jsx29 } from "react/jsx-runtime";
1290
1969
  var planBadgeClass = "inline-flex h-5 max-w-full shrink-0 items-center rounded-md border border-border bg-muted/90 px-2 text-[11px] font-normal text-muted-foreground dark:border-white/10 dark:bg-white/5 dark:text-muted-foreground";
1291
- var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx25("span", { className: cn(planBadgeClass, className), children });
1970
+ var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx29("span", { className: cn(planBadgeClass, className), children });
1292
1971
 
1293
1972
  // src/app/integrations/ConnectionRow.tsx
1294
- import { Fragment as Fragment3, jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
1973
+ import { Fragment as Fragment4, jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
1295
1974
  var logoShellClass2 = cn(
1296
1975
  "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg",
1297
1976
  TIMBAL_V2_LOGO_TILE
@@ -1306,14 +1985,14 @@ var ConnectionRow = ({
1306
1985
  ariaLabel,
1307
1986
  className
1308
1987
  }) => {
1309
- const inner = /* @__PURE__ */ jsxs21(Fragment3, { children: [
1310
- logo ? /* @__PURE__ */ jsx26("span", { className: logoShellClass2, children: logo }) : null,
1311
- /* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1", children: [
1312
- /* @__PURE__ */ jsx26("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
1313
- meta ? /* @__PURE__ */ jsx26("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
1988
+ const inner = /* @__PURE__ */ jsxs24(Fragment4, { children: [
1989
+ logo ? /* @__PURE__ */ jsx30("span", { className: logoShellClass2, children: logo }) : null,
1990
+ /* @__PURE__ */ jsxs24("div", { className: "min-w-0 flex-1", children: [
1991
+ /* @__PURE__ */ jsx30("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
1992
+ meta ? /* @__PURE__ */ jsx30("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
1314
1993
  ] }),
1315
- badge ? /* @__PURE__ */ jsx26("span", { className: "shrink-0", children: badge }) : null,
1316
- action ? /* @__PURE__ */ jsx26("span", { className: "shrink-0", children: action }) : null
1994
+ badge ? /* @__PURE__ */ jsx30("span", { className: "shrink-0", children: badge }) : null,
1995
+ action ? /* @__PURE__ */ jsx30("span", { className: "shrink-0", children: action }) : null
1317
1996
  ] });
1318
1997
  const rowClass2 = cn(
1319
1998
  "flex w-full items-center gap-3 px-4 py-3 text-left",
@@ -1321,7 +2000,7 @@ var ConnectionRow = ({
1321
2000
  className
1322
2001
  );
1323
2002
  if (onClick) {
1324
- return /* @__PURE__ */ jsx26(
2003
+ return /* @__PURE__ */ jsx30(
1325
2004
  "button",
1326
2005
  {
1327
2006
  type: "button",
@@ -1333,7 +2012,7 @@ var ConnectionRow = ({
1333
2012
  }
1334
2013
  );
1335
2014
  }
1336
- return /* @__PURE__ */ jsx26("div", { role: "listitem", className: rowClass2, children: inner });
2015
+ return /* @__PURE__ */ jsx30("div", { role: "listitem", className: rowClass2, children: inner });
1337
2016
  };
1338
2017
  var connectionRowListClass = cn(
1339
2018
  "overflow-hidden rounded-2xl",
@@ -1341,12 +2020,12 @@ var connectionRowListClass = cn(
1341
2020
  );
1342
2021
 
1343
2022
  // src/app/integrations/ConnectionRowList.tsx
1344
- import { jsx as jsx27 } from "react/jsx-runtime";
2023
+ import { jsx as jsx31 } from "react/jsx-runtime";
1345
2024
  var ConnectionRowList = ({
1346
2025
  children,
1347
2026
  "aria-label": ariaLabel = "Connected integrations",
1348
2027
  className
1349
- }) => /* @__PURE__ */ jsx27(
2028
+ }) => /* @__PURE__ */ jsx31(
1350
2029
  "div",
1351
2030
  {
1352
2031
  role: "list",
@@ -1357,7 +2036,7 @@ var ConnectionRowList = ({
1357
2036
  );
1358
2037
 
1359
2038
  // src/app/navigation/SubNav.tsx
1360
- import { jsx as jsx28 } from "react/jsx-runtime";
2039
+ import { jsx as jsx32 } from "react/jsx-runtime";
1361
2040
  var SubNav = ({
1362
2041
  items,
1363
2042
  activeId,
@@ -1366,7 +2045,7 @@ var SubNav = ({
1366
2045
  "aria-label": ariaLabel = "Section navigation",
1367
2046
  layoutId
1368
2047
  }) => {
1369
- return /* @__PURE__ */ jsx28("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx28(
2048
+ return /* @__PURE__ */ jsx32("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx32(
1370
2049
  PillSegmentedTabs,
1371
2050
  {
1372
2051
  value: activeId,
@@ -1380,13 +2059,13 @@ var SubNav = ({
1380
2059
  };
1381
2060
 
1382
2061
  // src/app/navigation/Breadcrumbs.tsx
1383
- import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
2062
+ import { jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
1384
2063
  var Breadcrumbs = ({ items, className }) => {
1385
- return /* @__PURE__ */ jsx29("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx29("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
2064
+ return /* @__PURE__ */ jsx33("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx33("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
1386
2065
  const isLast = index === items.length - 1;
1387
- return /* @__PURE__ */ jsxs22("li", { className: "inline-flex items-center gap-1.5", children: [
1388
- index > 0 ? /* @__PURE__ */ jsx29("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
1389
- isLast ? /* @__PURE__ */ jsx29("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx29("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx29(
2066
+ return /* @__PURE__ */ jsxs25("li", { className: "inline-flex items-center gap-1.5", children: [
2067
+ index > 0 ? /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
2068
+ isLast ? /* @__PURE__ */ jsx33("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx33("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx33(
1390
2069
  "button",
1391
2070
  {
1392
2071
  type: "button",
@@ -1400,7 +2079,7 @@ var Breadcrumbs = ({ items, className }) => {
1400
2079
  };
1401
2080
 
1402
2081
  // src/app/forms/Field.tsx
1403
- import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
2082
+ import { jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
1404
2083
  var Field = ({
1405
2084
  label,
1406
2085
  hint,
@@ -1409,11 +2088,11 @@ var Field = ({
1409
2088
  className,
1410
2089
  htmlFor
1411
2090
  }) => {
1412
- return /* @__PURE__ */ jsxs23("div", { className: cn("aui-app-field", appFieldClass, className), children: [
1413
- /* @__PURE__ */ jsx30("label", { className: appFieldLabelClass, htmlFor, children: label }),
2091
+ return /* @__PURE__ */ jsxs26("div", { className: cn("aui-app-field", appFieldClass, className), children: [
2092
+ /* @__PURE__ */ jsx34("label", { className: appFieldLabelClass, htmlFor, children: label }),
1414
2093
  children,
1415
- hint && !error ? /* @__PURE__ */ jsx30("p", { className: appFieldHintClass, children: hint }) : null,
1416
- error ? /* @__PURE__ */ jsx30("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
2094
+ hint && !error ? /* @__PURE__ */ jsx34("p", { className: appFieldHintClass, children: hint }) : null,
2095
+ error ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
1417
2096
  ] });
1418
2097
  };
1419
2098
  var FieldInput = ({
@@ -1426,7 +2105,7 @@ var FieldInput = ({
1426
2105
  ...inputProps
1427
2106
  }) => {
1428
2107
  const inputId = id ?? inputProps.name;
1429
- return /* @__PURE__ */ jsx30(
2108
+ return /* @__PURE__ */ jsx34(
1430
2109
  Field,
1431
2110
  {
1432
2111
  label,
@@ -1434,7 +2113,7 @@ var FieldInput = ({
1434
2113
  error,
1435
2114
  htmlFor: inputId,
1436
2115
  className: fieldClassName,
1437
- children: /* @__PURE__ */ jsx30(
2116
+ children: /* @__PURE__ */ jsx34(
1438
2117
  "input",
1439
2118
  {
1440
2119
  id: inputId,
@@ -1448,7 +2127,7 @@ var FieldInput = ({
1448
2127
  };
1449
2128
 
1450
2129
  // src/app/forms/FieldTextarea.tsx
1451
- import { jsx as jsx31 } from "react/jsx-runtime";
2130
+ import { jsx as jsx35 } from "react/jsx-runtime";
1452
2131
  var textareaClass = cn(
1453
2132
  appInputClass,
1454
2133
  "min-h-[5.5rem] resize-y py-2.5 leading-relaxed"
@@ -1463,7 +2142,7 @@ var FieldTextarea = ({
1463
2142
  ...props
1464
2143
  }) => {
1465
2144
  const textareaId = id ?? props.name;
1466
- return /* @__PURE__ */ jsx31(
2145
+ return /* @__PURE__ */ jsx35(
1467
2146
  Field,
1468
2147
  {
1469
2148
  label,
@@ -1471,7 +2150,7 @@ var FieldTextarea = ({
1471
2150
  error,
1472
2151
  htmlFor: textareaId,
1473
2152
  className: fieldClassName,
1474
- children: /* @__PURE__ */ jsx31(
2153
+ children: /* @__PURE__ */ jsx35(
1475
2154
  "textarea",
1476
2155
  {
1477
2156
  id: textareaId,
@@ -1486,7 +2165,7 @@ var FieldTextarea = ({
1486
2165
 
1487
2166
  // src/app/forms/FieldSelect.tsx
1488
2167
  import { ChevronDownIcon } from "lucide-react";
1489
- import { jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
2168
+ import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
1490
2169
  var selectWrapClass = "relative";
1491
2170
  var selectClass = cn(
1492
2171
  appInputClass,
@@ -1503,7 +2182,7 @@ var FieldSelect = ({
1503
2182
  ...props
1504
2183
  }) => {
1505
2184
  const selectId = id ?? props.name;
1506
- return /* @__PURE__ */ jsx32(
2185
+ return /* @__PURE__ */ jsx36(
1507
2186
  Field,
1508
2187
  {
1509
2188
  label,
@@ -1511,8 +2190,8 @@ var FieldSelect = ({
1511
2190
  error,
1512
2191
  htmlFor: selectId,
1513
2192
  className: fieldClassName,
1514
- children: /* @__PURE__ */ jsxs24("div", { className: selectWrapClass, children: [
1515
- /* @__PURE__ */ jsx32(
2193
+ children: /* @__PURE__ */ jsxs27("div", { className: selectWrapClass, children: [
2194
+ /* @__PURE__ */ jsx36(
1516
2195
  "select",
1517
2196
  {
1518
2197
  id: selectId,
@@ -1522,7 +2201,7 @@ var FieldSelect = ({
1522
2201
  children
1523
2202
  }
1524
2203
  ),
1525
- /* @__PURE__ */ jsx32(
2204
+ /* @__PURE__ */ jsx36(
1526
2205
  ChevronDownIcon,
1527
2206
  {
1528
2207
  className: "pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground",
@@ -1535,7 +2214,7 @@ var FieldSelect = ({
1535
2214
  };
1536
2215
 
1537
2216
  // src/app/forms/FieldSwitch.tsx
1538
- import { jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
2217
+ import { jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
1539
2218
  var trackClass = cn(
1540
2219
  "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-[background,box-shadow,border-color] duration-200",
1541
2220
  "peer-focus-visible:ring-2 peer-focus-visible:ring-foreground/10",
@@ -1556,7 +2235,7 @@ var FieldSwitch = ({
1556
2235
  ...props
1557
2236
  }) => {
1558
2237
  const inputId = id ?? props.name ?? "switch";
1559
- return /* @__PURE__ */ jsxs25(
2238
+ return /* @__PURE__ */ jsxs28(
1560
2239
  "label",
1561
2240
  {
1562
2241
  className: cn(
@@ -1565,8 +2244,8 @@ var FieldSwitch = ({
1565
2244
  ),
1566
2245
  htmlFor: inputId,
1567
2246
  children: [
1568
- /* @__PURE__ */ jsxs25("span", { className: "relative mt-0.5", children: [
1569
- /* @__PURE__ */ jsx33(
2247
+ /* @__PURE__ */ jsxs28("span", { className: "relative mt-0.5", children: [
2248
+ /* @__PURE__ */ jsx37(
1570
2249
  "input",
1571
2250
  {
1572
2251
  id: inputId,
@@ -1576,11 +2255,11 @@ var FieldSwitch = ({
1576
2255
  ...props
1577
2256
  }
1578
2257
  ),
1579
- /* @__PURE__ */ jsx33("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx33("span", { className: thumbClass }) })
2258
+ /* @__PURE__ */ jsx37("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx37("span", { className: thumbClass }) })
1580
2259
  ] }),
1581
- /* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
1582
- /* @__PURE__ */ jsx33("span", { className: "text-sm font-medium text-foreground", children: label }),
1583
- description ? /* @__PURE__ */ jsx33("span", { className: "text-xs text-muted-foreground", children: description }) : null
2260
+ /* @__PURE__ */ jsxs28("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
2261
+ /* @__PURE__ */ jsx37("span", { className: "text-sm font-medium text-foreground", children: label }),
2262
+ description ? /* @__PURE__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: description }) : null
1584
2263
  ] })
1585
2264
  ]
1586
2265
  }
@@ -1589,13 +2268,13 @@ var FieldSwitch = ({
1589
2268
 
1590
2269
  // src/app/forms/SearchInput.tsx
1591
2270
  import { SearchIcon } from "lucide-react";
1592
- import { jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
2271
+ import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
1593
2272
  var SearchInput = ({
1594
2273
  className,
1595
2274
  placeholder = "Search\u2026",
1596
2275
  ...props
1597
2276
  }) => {
1598
- return /* @__PURE__ */ jsxs26(
2277
+ return /* @__PURE__ */ jsxs29(
1599
2278
  "label",
1600
2279
  {
1601
2280
  className: cn(
@@ -1604,8 +2283,8 @@ var SearchInput = ({
1604
2283
  className
1605
2284
  ),
1606
2285
  children: [
1607
- /* @__PURE__ */ jsx34(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
1608
- /* @__PURE__ */ jsx34(
2286
+ /* @__PURE__ */ jsx38(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
2287
+ /* @__PURE__ */ jsx38(
1609
2288
  "input",
1610
2289
  {
1611
2290
  type: "search",
@@ -1620,18 +2299,18 @@ var SearchInput = ({
1620
2299
  };
1621
2300
 
1622
2301
  // src/app/forms/FormSection.tsx
1623
- import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
2302
+ import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
1624
2303
  var FormSection = ({ title, children, className }) => {
1625
- return /* @__PURE__ */ jsxs27("fieldset", { className: cn("aui-app-form-section", appSectionClass, "border-0 p-0", className), children: [
1626
- title ? /* @__PURE__ */ jsx35("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
1627
- /* @__PURE__ */ jsx35("div", { className: "flex flex-col gap-4", children })
2304
+ return /* @__PURE__ */ jsxs30("fieldset", { className: cn("aui-app-form-section", appSectionClass, "border-0 p-0", className), children: [
2305
+ title ? /* @__PURE__ */ jsx39("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
2306
+ /* @__PURE__ */ jsx39("div", { className: "flex flex-col gap-4", children })
1628
2307
  ] });
1629
2308
  };
1630
2309
 
1631
2310
  // src/app/data/FilterBar.tsx
1632
- import { jsx as jsx36 } from "react/jsx-runtime";
2311
+ import { jsx as jsx40 } from "react/jsx-runtime";
1633
2312
  var FilterBar = ({ children, className }) => {
1634
- return /* @__PURE__ */ jsx36(
2313
+ return /* @__PURE__ */ jsx40(
1635
2314
  "div",
1636
2315
  {
1637
2316
  className: cn("aui-app-filter-bar", appFilterBarClass, className),
@@ -1645,7 +2324,7 @@ var FilterBar = ({ children, className }) => {
1645
2324
  // src/app/data/DataTable.tsx
1646
2325
  import { useMemo, useState as useState4 } from "react";
1647
2326
  import { ArrowDownIcon, ArrowUpDownIcon, ArrowUpIcon } from "lucide-react";
1648
- import { jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
2327
+ import { jsx as jsx41, jsxs as jsxs31 } from "react/jsx-runtime";
1649
2328
  var shellClass2 = "overflow-hidden rounded-xl border border-border bg-card shadow-card";
1650
2329
  var tableClass = "w-full border-collapse bg-transparent text-sm";
1651
2330
  var headCellClass = "border-b border-border/60 bg-transparent px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide text-muted-foreground";
@@ -1685,12 +2364,12 @@ function SortIndicator({
1685
2364
  }) {
1686
2365
  const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
1687
2366
  if (!active) {
1688
- return /* @__PURE__ */ jsx37(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
2367
+ return /* @__PURE__ */ jsx41(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
1689
2368
  }
1690
2369
  if (direction === "desc") {
1691
- return /* @__PURE__ */ jsx37(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
2370
+ return /* @__PURE__ */ jsx41(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
1692
2371
  }
1693
- return /* @__PURE__ */ jsx37(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
2372
+ return /* @__PURE__ */ jsx41(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
1694
2373
  }
1695
2374
  function DataTable({
1696
2375
  columns,
@@ -1741,28 +2420,28 @@ function DataTable({
1741
2420
  const cellPad = dense ? "px-3 py-2" : void 0;
1742
2421
  const headPad = dense ? "px-3 py-2" : void 0;
1743
2422
  if (rows.length === 0 && emptyMode === "replace") {
1744
- return /* @__PURE__ */ jsx37(EmptyState, { title: emptyTitle, description: emptyDescription, className });
2423
+ return /* @__PURE__ */ jsx41(EmptyState, { title: emptyTitle, description: emptyDescription, className });
1745
2424
  }
1746
2425
  const rowCountText = rowCountLabel?.(sortedRows.length) ?? `${sortedRows.length} row${sortedRows.length === 1 ? "" : "s"}`;
1747
2426
  const hasFoot = Boolean((showRowCount || footer) && sortedRows.length > 0);
1748
- return /* @__PURE__ */ jsx37("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx37("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs28("table", { className: tableClass, children: [
1749
- caption ? /* @__PURE__ */ jsx37("caption", { className: "sr-only", children: caption }) : null,
1750
- /* @__PURE__ */ jsx37("thead", { className: cn(stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsx37("tr", { children: columns.map((col) => {
2427
+ return /* @__PURE__ */ jsx41("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx41("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs31("table", { className: tableClass, children: [
2428
+ caption ? /* @__PURE__ */ jsx41("caption", { className: "sr-only", children: caption }) : null,
2429
+ /* @__PURE__ */ jsx41("thead", { className: cn(stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsx41("tr", { children: columns.map((col) => {
1751
2430
  const isSorted = sort?.columnId === col.id;
1752
2431
  const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
1753
- const headerContent = col.sortable ? /* @__PURE__ */ jsxs28(
2432
+ const headerContent = col.sortable ? /* @__PURE__ */ jsxs31(
1754
2433
  "button",
1755
2434
  {
1756
2435
  type: "button",
1757
2436
  className: sortButtonClass,
1758
2437
  onClick: () => setSort(nextSort(sort, col.id)),
1759
2438
  children: [
1760
- /* @__PURE__ */ jsx37("span", { className: "truncate", children: col.header }),
1761
- /* @__PURE__ */ jsx37(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
2439
+ /* @__PURE__ */ jsx41("span", { className: "truncate", children: col.header }),
2440
+ /* @__PURE__ */ jsx41(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
1762
2441
  ]
1763
2442
  }
1764
2443
  ) : col.header;
1765
- return /* @__PURE__ */ jsx37(
2444
+ return /* @__PURE__ */ jsx41(
1766
2445
  "th",
1767
2446
  {
1768
2447
  scope: "col",
@@ -1778,10 +2457,10 @@ function DataTable({
1778
2457
  col.id
1779
2458
  );
1780
2459
  }) }) }),
1781
- /* @__PURE__ */ jsx37("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: sortedRows.length === 0 ? /* @__PURE__ */ jsx37("tr", { children: /* @__PURE__ */ jsx37("td", { colSpan: columns.length, className: emptyCellClass, children: /* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-center gap-1", children: [
1782
- /* @__PURE__ */ jsx37("p", { className: "font-medium text-foreground", children: emptyTitle }),
1783
- emptyDescription ? /* @__PURE__ */ jsx37("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
1784
- ] }) }) }) : sortedRows.map((row) => /* @__PURE__ */ jsx37(
2460
+ /* @__PURE__ */ jsx41("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: sortedRows.length === 0 ? /* @__PURE__ */ jsx41("tr", { children: /* @__PURE__ */ jsx41("td", { colSpan: columns.length, className: emptyCellClass, children: /* @__PURE__ */ jsxs31("div", { className: "flex flex-col items-center gap-1", children: [
2461
+ /* @__PURE__ */ jsx41("p", { className: "font-medium text-foreground", children: emptyTitle }),
2462
+ emptyDescription ? /* @__PURE__ */ jsx41("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
2463
+ ] }) }) }) : sortedRows.map((row) => /* @__PURE__ */ jsx41(
1785
2464
  "tr",
1786
2465
  {
1787
2466
  className: rowClass,
@@ -1795,7 +2474,7 @@ function DataTable({
1795
2474
  } : void 0,
1796
2475
  tabIndex: onRowClick ? 0 : void 0,
1797
2476
  role: onRowClick ? "button" : void 0,
1798
- children: columns.map((col) => /* @__PURE__ */ jsx37(
2477
+ children: columns.map((col) => /* @__PURE__ */ jsx41(
1799
2478
  "td",
1800
2479
  {
1801
2480
  className: cn(
@@ -1811,7 +2490,7 @@ function DataTable({
1811
2490
  },
1812
2491
  getRowKey(row)
1813
2492
  )) }),
1814
- hasFoot ? /* @__PURE__ */ jsx37("tfoot", { children: /* @__PURE__ */ jsx37("tr", { children: /* @__PURE__ */ jsx37("td", { colSpan: columns.length, className: footCellClass, children: /* @__PURE__ */ jsxs28(
2493
+ hasFoot ? /* @__PURE__ */ jsx41("tfoot", { children: /* @__PURE__ */ jsx41("tr", { children: /* @__PURE__ */ jsx41("td", { colSpan: columns.length, className: footCellClass, children: /* @__PURE__ */ jsxs31(
1815
2494
  "div",
1816
2495
  {
1817
2496
  className: cn(
@@ -1819,7 +2498,7 @@ function DataTable({
1819
2498
  showRowCount && footer ? "justify-between" : "justify-start"
1820
2499
  ),
1821
2500
  children: [
1822
- showRowCount ? /* @__PURE__ */ jsx37("span", { children: rowCountText }) : null,
2501
+ showRowCount ? /* @__PURE__ */ jsx41("span", { children: rowCountText }) : null,
1823
2502
  footer
1824
2503
  ]
1825
2504
  }
@@ -1829,53 +2508,7 @@ function DataTable({
1829
2508
 
1830
2509
  // src/app/data/ChartPanel.tsx
1831
2510
  import { useId as useId4 } from "react";
1832
-
1833
- // src/app/data/metrics-shared.tsx
1834
- import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
1835
- var metricCardShellClass = cn(
1836
- studioIntegrationCardClass,
1837
- "aui-app-metric-card shadow-none",
1838
- "flex flex-col overflow-hidden"
1839
- );
1840
- var metricCardHeaderClass = "flex items-start justify-between gap-3 px-4 pb-1 pt-3";
1841
- var metricTilesRowClass = "grid w-full min-w-0";
1842
- var metricChartRegionClass = "relative min-h-0 w-full border-t border-border/40 pt-2";
1843
- var metricChartPlotRegionClass = "relative min-h-0 w-full border-t border-border/40 px-0 pt-5 pb-3";
1844
- var metricCellDividerClass = "border-r border-border/40";
1845
- var MetricCardHeader = ({
1846
- title,
1847
- titleId,
1848
- description,
1849
- actions
1850
- }) => {
1851
- if (!title && !description && !actions) return null;
1852
- return /* @__PURE__ */ jsxs29("header", { className: metricCardHeaderClass, children: [
1853
- /* @__PURE__ */ jsxs29("div", { className: "min-w-0", children: [
1854
- title ? /* @__PURE__ */ jsx38("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }) : null,
1855
- description ? /* @__PURE__ */ jsx38("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1856
- ] }),
1857
- actions ? /* @__PURE__ */ jsx38("div", { className: "shrink-0", children: actions }) : null
1858
- ] });
1859
- };
1860
- function metricTilesGridColsClass(n) {
1861
- switch (n) {
1862
- case 1:
1863
- return "grid-cols-1";
1864
- case 2:
1865
- return "grid-cols-2";
1866
- case 3:
1867
- return "grid-cols-3";
1868
- case 5:
1869
- return "grid-cols-2 sm:grid-cols-5";
1870
- case 6:
1871
- return "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6";
1872
- default:
1873
- return "grid-cols-2 md:grid-cols-4";
1874
- }
1875
- }
1876
-
1877
- // src/app/data/ChartPanel.tsx
1878
- import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
2511
+ import { jsx as jsx42, jsxs as jsxs32 } from "react/jsx-runtime";
1879
2512
  var ChartPanel = ({
1880
2513
  title,
1881
2514
  description,
@@ -1888,14 +2521,14 @@ var ChartPanel = ({
1888
2521
  const titleId = useId4();
1889
2522
  const resolvedTitle = title ?? artifact?.title;
1890
2523
  const hasHeader = Boolean(resolvedTitle || description || actions);
1891
- const body = children ?? (artifact ? /* @__PURE__ */ jsx39(ChartArtifactView, { artifact, embedded: true, height }) : null);
1892
- return /* @__PURE__ */ jsxs30(
2524
+ const body = children ?? (artifact ? /* @__PURE__ */ jsx42(ChartArtifactView, { artifact, embedded: true, height }) : null);
2525
+ return /* @__PURE__ */ jsxs32(
1893
2526
  "section",
1894
2527
  {
1895
2528
  className: cn(metricCardShellClass, "aui-app-chart-panel", className),
1896
2529
  "aria-labelledby": resolvedTitle ? titleId : void 0,
1897
2530
  children: [
1898
- /* @__PURE__ */ jsx39(
2531
+ /* @__PURE__ */ jsx42(
1899
2532
  MetricCardHeader,
1900
2533
  {
1901
2534
  title: resolvedTitle,
@@ -1904,14 +2537,14 @@ var ChartPanel = ({
1904
2537
  actions
1905
2538
  }
1906
2539
  ),
1907
- /* @__PURE__ */ jsx39(
2540
+ /* @__PURE__ */ jsx42(
1908
2541
  "div",
1909
2542
  {
1910
2543
  className: cn(
1911
2544
  "relative min-h-0 w-full",
1912
2545
  hasHeader ? metricChartPlotRegionClass : "pt-2 pb-3"
1913
2546
  ),
1914
- children: body ?? /* @__PURE__ */ jsx39(
2547
+ children: body ?? /* @__PURE__ */ jsx42(
1915
2548
  "div",
1916
2549
  {
1917
2550
  className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
@@ -1927,77 +2560,9 @@ var ChartPanel = ({
1927
2560
  );
1928
2561
  };
1929
2562
 
1930
- // src/app/data/MetricTile.tsx
1931
- import { Fragment as Fragment4, jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
1932
- var trendToneClass = {
1933
- up: "border-border/80 bg-muted/40 text-muted-foreground",
1934
- down: "border-border/80 bg-muted/40 text-muted-foreground",
1935
- neutral: "border-border/80 bg-muted/30 text-muted-foreground"
1936
- };
1937
- var metricTileBaseClass = "relative flex min-w-0 flex-1 flex-col gap-1 px-4 py-3 text-left font-normal";
1938
- var metricTileInteractiveClass = cn(
1939
- metricTileBaseClass,
1940
- "bg-transparent hover:bg-transparent active:bg-transparent",
1941
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
1942
- );
1943
- var MetricTile = ({
1944
- label,
1945
- value,
1946
- unit,
1947
- trend,
1948
- trendTone = "neutral",
1949
- active = false,
1950
- showDivider = false,
1951
- onSelect,
1952
- ariaLabel,
1953
- className
1954
- }) => {
1955
- const content = /* @__PURE__ */ jsxs31(Fragment4, { children: [
1956
- active ? /* @__PURE__ */ jsx40(
1957
- "span",
1958
- {
1959
- "aria-hidden": true,
1960
- className: "absolute inset-x-0 bottom-0 h-0.5 bg-foreground dark:bg-white"
1961
- }
1962
- ) : null,
1963
- /* @__PURE__ */ jsx40("span", { className: "text-xs font-normal text-muted-foreground", children: label }),
1964
- /* @__PURE__ */ jsxs31("span", { className: "flex items-center gap-2", children: [
1965
- /* @__PURE__ */ jsxs31("span", { className: "flex items-baseline gap-1", children: [
1966
- /* @__PURE__ */ jsx40("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
1967
- unit ? /* @__PURE__ */ jsx40("span", { className: "text-xs font-normal text-muted-foreground", children: unit }) : null
1968
- ] }),
1969
- trend ? /* @__PURE__ */ jsx40(
1970
- "span",
1971
- {
1972
- className: cn(
1973
- "rounded-full border px-1.5 py-0.5 text-xs font-normal",
1974
- trendToneClass[trendTone]
1975
- ),
1976
- children: trend
1977
- }
1978
- ) : null
1979
- ] })
1980
- ] });
1981
- const divider = showDivider ? metricCellDividerClass : void 0;
1982
- if (onSelect) {
1983
- return /* @__PURE__ */ jsx40(
1984
- "button",
1985
- {
1986
- type: "button",
1987
- onClick: onSelect,
1988
- "aria-pressed": active,
1989
- "aria-label": ariaLabel,
1990
- className: cn(metricTileInteractiveClass, divider, className),
1991
- children: content
1992
- }
1993
- );
1994
- }
1995
- return /* @__PURE__ */ jsx40("div", { className: cn(metricTileBaseClass, divider, className), children: content });
1996
- };
1997
-
1998
2563
  // src/app/data/MetricRow.tsx
1999
2564
  import { useId as useId5, useState as useState5 } from "react";
2000
- import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
2565
+ import { jsx as jsx43, jsxs as jsxs33 } from "react/jsx-runtime";
2001
2566
  var MetricRow = ({
2002
2567
  title,
2003
2568
  description,
@@ -2019,13 +2584,13 @@ var MetricRow = ({
2019
2584
  if (activeMetricId == null) setInternalId(id);
2020
2585
  onMetricChange?.(id);
2021
2586
  };
2022
- return /* @__PURE__ */ jsxs32(
2587
+ return /* @__PURE__ */ jsxs33(
2023
2588
  "section",
2024
2589
  {
2025
2590
  className: cn(metricCardShellClass, className),
2026
2591
  "aria-labelledby": title ? titleId : void 0,
2027
2592
  children: [
2028
- /* @__PURE__ */ jsx41(
2593
+ /* @__PURE__ */ jsx43(
2029
2594
  MetricCardHeader,
2030
2595
  {
2031
2596
  title,
@@ -2034,7 +2599,7 @@ var MetricRow = ({
2034
2599
  actions
2035
2600
  }
2036
2601
  ),
2037
- /* @__PURE__ */ jsx41(
2602
+ /* @__PURE__ */ jsx43(
2038
2603
  "div",
2039
2604
  {
2040
2605
  role: selectable ? "group" : void 0,
@@ -2044,7 +2609,7 @@ var MetricRow = ({
2044
2609
  metricTilesGridColsClass(metrics.length),
2045
2610
  (title || description || actions) && "mt-3"
2046
2611
  ),
2047
- children: metrics.map((m, index) => /* @__PURE__ */ jsx41(
2612
+ children: metrics.map((m, index) => /* @__PURE__ */ jsx43(
2048
2613
  MetricTile,
2049
2614
  {
2050
2615
  label: m.label,
@@ -2067,7 +2632,7 @@ var MetricRow = ({
2067
2632
 
2068
2633
  // src/app/data/MetricChartCard.tsx
2069
2634
  import { useId as useId6, useState as useState6 } from "react";
2070
- import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
2635
+ import { jsx as jsx44, jsxs as jsxs34 } from "react/jsx-runtime";
2071
2636
  var MetricChartCard = ({
2072
2637
  title,
2073
2638
  description,
@@ -2097,13 +2662,13 @@ var MetricChartCard = ({
2097
2662
  };
2098
2663
  const hasHeader = Boolean(title || description || actions);
2099
2664
  const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
2100
- return /* @__PURE__ */ jsxs33(
2665
+ return /* @__PURE__ */ jsxs34(
2101
2666
  "section",
2102
2667
  {
2103
2668
  className: cn(metricCardShellClass, className),
2104
2669
  "aria-labelledby": title ? titleId : void 0,
2105
2670
  children: [
2106
- /* @__PURE__ */ jsx42(
2671
+ /* @__PURE__ */ jsx44(
2107
2672
  MetricCardHeader,
2108
2673
  {
2109
2674
  title,
@@ -2112,7 +2677,7 @@ var MetricChartCard = ({
2112
2677
  actions
2113
2678
  }
2114
2679
  ),
2115
- /* @__PURE__ */ jsx42(
2680
+ /* @__PURE__ */ jsx44(
2116
2681
  "div",
2117
2682
  {
2118
2683
  role: "group",
@@ -2122,7 +2687,7 @@ var MetricChartCard = ({
2122
2687
  metricTilesGridColsClass(metrics.length),
2123
2688
  hasHeader && "mt-3"
2124
2689
  ),
2125
- children: metrics.map((m, index) => /* @__PURE__ */ jsx42(
2690
+ children: metrics.map((m, index) => /* @__PURE__ */ jsx44(
2126
2691
  MetricTile,
2127
2692
  {
2128
2693
  label: m.label,
@@ -2138,7 +2703,7 @@ var MetricChartCard = ({
2138
2703
  ))
2139
2704
  }
2140
2705
  ),
2141
- /* @__PURE__ */ jsx42("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx42(
2706
+ /* @__PURE__ */ jsx44("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx44(
2142
2707
  LineAreaChart,
2143
2708
  {
2144
2709
  data: active.data,
@@ -2158,7 +2723,7 @@ var MetricChartCard = ({
2158
2723
  ariaLabel: chartAriaLabel
2159
2724
  },
2160
2725
  active.id
2161
- ) : /* @__PURE__ */ jsx42(
2726
+ ) : /* @__PURE__ */ jsx44(
2162
2727
  "div",
2163
2728
  {
2164
2729
  className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
@@ -2174,7 +2739,7 @@ var MetricChartCard = ({
2174
2739
 
2175
2740
  // src/charts/sparkline.tsx
2176
2741
  import { useId as useId7 } from "react";
2177
- import { Fragment as Fragment5, jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
2742
+ import { Fragment as Fragment5, jsx as jsx45, jsxs as jsxs35 } from "react/jsx-runtime";
2178
2743
  var Sparkline = ({
2179
2744
  data,
2180
2745
  dataKey = "value",
@@ -2189,7 +2754,7 @@ var Sparkline = ({
2189
2754
  const uid = useId7();
2190
2755
  const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
2191
2756
  if (values.length === 0) {
2192
- return /* @__PURE__ */ jsx43("span", { className: cn("inline-block", className), style: { width, height } });
2757
+ return /* @__PURE__ */ jsx45("span", { className: cn("inline-block", className), style: { width, height } });
2193
2758
  }
2194
2759
  const pad = strokeWidth + 1;
2195
2760
  const min = Math.min(...values);
@@ -2201,7 +2766,7 @@ var Sparkline = ({
2201
2766
  x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
2202
2767
  y: pad + innerH - (v - min) / range * innerH
2203
2768
  }));
2204
- return /* @__PURE__ */ jsxs34(
2769
+ return /* @__PURE__ */ jsxs35(
2205
2770
  "svg",
2206
2771
  {
2207
2772
  width,
@@ -2212,14 +2777,14 @@ var Sparkline = ({
2212
2777
  "aria-label": ariaLabel,
2213
2778
  preserveAspectRatio: "none",
2214
2779
  children: [
2215
- area && /* @__PURE__ */ jsxs34(Fragment5, { children: [
2216
- /* @__PURE__ */ jsx43("defs", { children: /* @__PURE__ */ jsxs34("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
2217
- /* @__PURE__ */ jsx43("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
2218
- /* @__PURE__ */ jsx43("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
2780
+ area && /* @__PURE__ */ jsxs35(Fragment5, { children: [
2781
+ /* @__PURE__ */ jsx45("defs", { children: /* @__PURE__ */ jsxs35("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
2782
+ /* @__PURE__ */ jsx45("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
2783
+ /* @__PURE__ */ jsx45("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
2219
2784
  ] }) }),
2220
- /* @__PURE__ */ jsx43("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
2785
+ /* @__PURE__ */ jsx45("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
2221
2786
  ] }),
2222
- /* @__PURE__ */ jsx43(
2787
+ /* @__PURE__ */ jsx45(
2223
2788
  "path",
2224
2789
  {
2225
2790
  d: monotoneLinePath(points),
@@ -2237,6 +2802,18 @@ var Sparkline = ({
2237
2802
 
2238
2803
  export {
2239
2804
  APP_KIT_AGENT_INSTRUCTIONS,
2805
+ createTimbalTheme,
2806
+ themeToCss,
2807
+ applyTimbalTheme,
2808
+ clearTimbalTheme,
2809
+ TIMBAL_THEME_PRESETS,
2810
+ getThemePreset,
2811
+ applyThemePreset,
2812
+ getStoredThemePreset,
2813
+ THEME_AGENT_INSTRUCTIONS,
2814
+ TimbalThemeStyle,
2815
+ MetricTile,
2816
+ ThemePresetGallery,
2240
2817
  appPageColumnClass,
2241
2818
  appShellTopbarInsetClass,
2242
2819
  appShellInsetTopClass,
@@ -2289,7 +2866,6 @@ export {
2289
2866
  FilterBar,
2290
2867
  DataTable,
2291
2868
  ChartPanel,
2292
- MetricTile,
2293
2869
  MetricRow,
2294
2870
  MetricChartCard,
2295
2871
  Sparkline