@timbal-ai/timbal-react 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +18 -4
  3. package/dist/app.cjs +3532 -1483
  4. package/dist/app.d.cts +75 -30
  5. package/dist/app.d.ts +75 -30
  6. package/dist/app.esm.js +29 -7
  7. package/dist/{chart-artifact-CMnDys2t.d.ts → chart-artifact-2OTDTRwM.d.ts} +194 -40
  8. package/dist/{chart-artifact-C8-Py6lc.d.cts → chart-artifact-CS3qyGIY.d.cts} +194 -40
  9. package/dist/chat.cjs +264 -107
  10. package/dist/chat.d.cts +2 -2
  11. package/dist/chat.d.ts +2 -2
  12. package/dist/chat.esm.js +4 -3
  13. package/dist/chunk-5ECRZ5O7.esm.js +899 -0
  14. package/dist/{chunk-QU7ET55D.esm.js → chunk-AZL2WANO.esm.js} +320 -177
  15. package/dist/{chunk-OH23AX2V.esm.js → chunk-B4XAC4G7.esm.js} +430 -780
  16. package/dist/chunk-EDEKQYSU.esm.js +10 -0
  17. package/dist/{chunk-GQBYZRD7.esm.js → chunk-IGHBLJV3.esm.js} +38 -27
  18. package/dist/{chunk-OFWC4MIY.esm.js → chunk-JYDJRGDE.esm.js} +5 -3
  19. package/dist/{chunk-VOWNCS3F.esm.js → chunk-SZDYIRMB.esm.js} +1567 -490
  20. package/dist/chunk-TZI3ID3C.esm.js +232 -0
  21. package/dist/{chunk-THBA27QY.esm.js → chunk-WMKPT5BV.esm.js} +242 -123
  22. package/dist/{chunk-VXMM2HX7.esm.js → chunk-ZNYAETFD.esm.js} +1 -1
  23. package/dist/{circular-progress-Ci8L-Hfa.d.cts → circular-progress-CDsJwIPF.d.cts} +19 -77
  24. package/dist/{circular-progress-Ci8L-Hfa.d.ts → circular-progress-CDsJwIPF.d.ts} +19 -77
  25. package/dist/index.cjs +5506 -3626
  26. package/dist/index.d.cts +7 -6
  27. package/dist/index.d.ts +7 -6
  28. package/dist/index.esm.js +45 -33
  29. package/dist/kanban-U5xNe9py.d.cts +212 -0
  30. package/dist/kanban-U5xNe9py.d.ts +212 -0
  31. package/dist/{layout-BTJyU8wd.d.ts → layout-B8r6Jbat.d.ts} +1 -1
  32. package/dist/{layout-C2G-FcER.d.cts → layout-Cu7Ijn04.d.cts} +1 -1
  33. package/dist/site.cjs +358 -0
  34. package/dist/site.d.cts +184 -0
  35. package/dist/site.d.ts +184 -0
  36. package/dist/site.esm.js +322 -0
  37. package/dist/studio.cjs +702 -343
  38. package/dist/studio.d.cts +1 -1
  39. package/dist/studio.d.ts +1 -1
  40. package/dist/studio.esm.js +7 -5
  41. package/dist/styles.css +56 -0
  42. package/dist/{timbal-v2-button-CNfdwGq4.d.cts → timbal-v2-button-B7vPs7gg.d.cts} +2 -2
  43. package/dist/{timbal-v2-button-CNfdwGq4.d.ts → timbal-v2-button-B7vPs7gg.d.ts} +2 -2
  44. package/dist/ui.cjs +1504 -659
  45. package/dist/ui.d.cts +11 -4
  46. package/dist/ui.d.ts +11 -4
  47. package/dist/ui.esm.js +35 -26
  48. package/dist/{welcome-DXqsGTwH.d.ts → welcome-DduQAC4K.d.ts} +4 -0
  49. package/dist/{welcome-BFGRoNfK.d.cts → welcome-NXZlcihe.d.cts} +4 -0
  50. package/package.json +9 -1
  51. package/dist/button-BoyX5pM_.d.cts +0 -18
  52. package/dist/button-BoyX5pM_.d.ts +0 -18
  53. package/dist/chunk-UCGVL7ZY.esm.js +0 -52
@@ -15,27 +15,36 @@ import {
15
15
  studioIntegrationCardClass,
16
16
  studioTopbarPillHeightClass,
17
17
  toNum
18
- } from "./chunk-GQBYZRD7.esm.js";
18
+ } from "./chunk-IGHBLJV3.esm.js";
19
19
  import {
20
20
  Checkbox,
21
+ CopyButton,
22
+ Popover,
23
+ PopoverContent,
24
+ PopoverTrigger,
21
25
  Skeleton
22
- } from "./chunk-UCGVL7ZY.esm.js";
26
+ } from "./chunk-5ECRZ5O7.esm.js";
23
27
  import {
24
28
  PillSegmentedTabs
25
- } from "./chunk-VXMM2HX7.esm.js";
29
+ } from "./chunk-ZNYAETFD.esm.js";
26
30
  import {
31
+ Avatar,
32
+ AvatarFallback,
27
33
  Button,
28
34
  Dialog,
29
35
  DialogContent,
30
36
  DialogTitle,
37
+ TIMBAL_V2_ELEVATED_GRADIENT,
31
38
  TIMBAL_V2_ELEVATED_SURFACE,
32
39
  TIMBAL_V2_LOGO_TILE,
33
40
  TIMBAL_V2_SWITCH_THUMB,
34
41
  TIMBAL_V2_SWITCH_TRACK_OFF,
35
42
  TimbalV2Button,
36
- cn,
37
43
  controlClass
38
- } from "./chunk-QU7ET55D.esm.js";
44
+ } from "./chunk-AZL2WANO.esm.js";
45
+ import {
46
+ cn
47
+ } from "./chunk-EDEKQYSU.esm.js";
39
48
 
40
49
  // src/design/ui-vocabulary.ts
41
50
  var SEMANTIC_COLOR_TOKENS = [
@@ -191,6 +200,13 @@ var HOUSE_RULES = [
191
200
  rule: "Don't nest a bordered card inside another bordered card. Group with spacing or a Section instead.",
192
201
  why: "Card-in-card doubles borders and shadows for no information gain."
193
202
  },
203
+ {
204
+ id: "no-table-in-card",
205
+ rule: "Never wrap a DataTable or table inside a Card, SurfaceCard, or ArtifactCard.",
206
+ why: "The DataTable is already designed to sit flat with its own borders and shadows. Wrapping it inside a card adds redundant borders, margins, and shadows, which looks like slop.",
207
+ slop: "<Card><DataTable columns={columns} rows={rows} getRowKey={getRowKey} /></Card>",
208
+ good: "<DataTable columns={columns} rows={rows} getRowKey={getRowKey} />"
209
+ },
194
210
  {
195
211
  id: "no-row-dividers",
196
212
  rule: "Don't put a divider between every list row. Use spacing or zebra striping.",
@@ -212,6 +228,27 @@ var HOUSE_RULES = [
212
228
  why: "Hand-rolled controls drift from the shared control-surface skin and look foreign next to kit controls.",
213
229
  slop: `<button className="rounded-lg border border-input bg-transparent px-3 h-9">`,
214
230
  good: `<SelectTrigger><SelectValue /></SelectTrigger>`
231
+ },
232
+ {
233
+ id: "no-title-repetition",
234
+ rule: "Never repeat the page title/description inside a Section, Card, or Table header.",
235
+ why: "If the Page already has a title, repeating it in the first child section or table is redundant and wastes vertical space.",
236
+ slop: `<Page title="Orders"><Section title="Orders"><DataTable ... /></Section></Page>`,
237
+ good: `<Page title="Orders"><DataTable ... /></Page>`
238
+ },
239
+ {
240
+ id: "no-chat-wrapping",
241
+ rule: "Never wrap TimbalChat or AppChatPanel in a Card, Section, or custom bordered/padded container, and never add custom heading/status blocks above it.",
242
+ why: "The chat component is a full-bleed, full-height surface that handles its own layout, welcome screen, and suggestions. Wrapping it or hand-rolling headers/online badges inside the page content is redundant and wastes layout space.",
243
+ slop: `<Page title="Assistant"><Card><div className="flex justify-between"><h3>TIBA Concierge</h3><span>Online</span></div><TimbalChat /></Card></Page>`,
244
+ good: `<Page fill><TimbalChat workforceId="..." welcome={{ heading: "Hola, soy el Concierge de TIBA", subheading: "Preg\xFAntame sobre..." }} /></Page>`
245
+ },
246
+ {
247
+ id: "no-colored-hover",
248
+ rule: "Interactive cards and list items must use neutral hover states \u2014 never hard-code colored backgrounds or borders on hover.",
249
+ why: "Colored hover highlights (like hover:bg-primary/5 or hover:bg-emerald-500/5) look dirty and break the neutral chrome aesthetic. Use the kit's clean, neutral hover states, or AlertCard, or TIMBAL_V2_SECONDARY_CHROME hover layers.",
250
+ slop: `<Card className="hover:bg-emerald-500/10 hover:border-emerald-500/30">`,
251
+ good: `<AlertCard onClick={handleClick}>`
215
252
  }
216
253
  ];
217
254
 
@@ -246,14 +283,14 @@ The most common failure is shipping the **same** layout every time: sidebar + to
246
283
  | Archetype | When | Compose |
247
284
  |-----------|------|---------|
248
285
  | **Sidebar dashboard** | Multi-section product (CRM, billing, ops) with nav | \`StudioSidebar\` in \`AppShell.sidebar\` + \`Page\` \u2192 \`Section\` |
249
- | **Focused / no-chrome** | A single tool or one-screen utility | \`AppShell\` (no sidebar) + \`Page\` (optionally just \`AppShellTopbar\`); or a centered narrow column |
286
+ | **Focused / no-chrome** | A single tool or one-screen utility | \`AppShell\` (no sidebar) + \`Page width="narrow"\` / \`"prose"\` (optionally with a custom topbar) for a centered focused column |
250
287
  | **Bento overview** | Home / at-a-glance dashboards | \`Page\` + an **asymmetric grid** of \`SurfaceCard\` / \`ChartPanel\` / \`StatTile\` spanning different widths (not a uniform row + table) |
251
288
  | **Split master\u2013detail** | Inbox, triage queue, record browser, log explorer | \`AppShell contentFill\` + \`Page fill\` + a two-column flex row, each pane \`min-h-0 overflow-y-auto\` |
252
289
  | **Full-page chat / canvas** | Chat-first app, editor, map, single full-bleed surface | \`AppShell contentFill\` + headerless \`Page fill\` + a \`min-h-0 flex-1\` child (e.g. \`TimbalChat\`) |
253
290
  | **Copilot overlay** | A data app that also wants an assistant | any of the above + \`AppShell chat={<AppChatPanel />}\` (floating, never a second column) |
254
291
  | **Section-switcher** | One page, several views | \`SubNav\` / \`PillSegmentedTabs\` (\`trackVariant="flush"\`) switching panels with state/router |
255
292
 
256
- Mix them: vary the grid columns, density, header placement (\`Page\` actions vs. a global \`AppShellTopbar\`), and whether there's a sidebar at all. Two dashboards for two domains should not look identical.
293
+ Mix them: vary the grid columns, density, header placement (\`Page\` actions vs. a global topbar), and whether there's a sidebar at all. Two dashboards for two domains should not look identical.
257
294
 
258
295
  ### Full-height pages (chat, canvas, split views)
259
296
 
@@ -264,7 +301,7 @@ The content region is a **padded scroll area** by default \u2014 great for stack
264
301
  - Give the filling child **\`min-h-0 flex-1\`** (or \`h-full\`) so its own scroll/footer resolves \u2014 e.g. \`<TimbalChat className="min-h-0 flex-1" />\`, or a two-pane row where each pane is \`min-h-0 overflow-y-auto\`.
265
302
 
266
303
  \`\`\`tsx
267
- <AppShell contentFill topbar={<AppShellTopbar actions={<ModeToggle />} />}>
304
+ <AppShell contentFill topbar={<div className="flex justify-end p-4"><ModeToggle /></div>}>
268
305
  <Page fill> {/* headerless: omit title */}
269
306
  <TimbalChat workforceId="\u2026" className="min-h-0 flex-1" />
270
307
  </Page>
@@ -273,6 +310,11 @@ The content region is a **padded scroll area** by default \u2014 great for stack
273
310
 
274
311
  **Don't** size full-height content with \`h-[calc(100dvh-\u2026)]\` (guesses chrome height \u2192 spurious scrollbar) or \`min-h-[\u2026]\` (free-growing floor \u2192 a pinned footer like the chat composer rides down on scroll). Let \`contentFill\` + \`fill\` provide the bounded height. \`Page\` with no \`title\` renders **no header** \u2014 you don't need to abandon \`Page\` to drop a heading.
275
312
 
313
+ **Full-page Assistant Guidelines (Hardened Layout):**
314
+ When creating a full-page assistant/chat page, let the chat component own the layout and welcome state completely.
315
+ - **Never wrap** \`<TimbalChat>\` or \`<AppChatPanel>\` inside standard card or section elements (like \`<Card>\`, \`<Section>\`, or custom bordered/padded panels). Wrapping degrades the viewport height calculations and wastes valuable layout estate.
316
+ - **Never add custom headings, titles, descriptions, or status badges** (e.g., "Asistente Virtual", "Online", or subtitle text blocks) inside the page. The assistant page context is already implicit. If you need a customized title or greeting, pass it through the \`welcome\` prop config: e.g., \`<TimbalChat welcome={{ heading: "Hola, soy el Concierge de TIBA", subheading: "Preg\xFAntame sobre..." }} />\`.
317
+
276
318
  ### Module layout (source folders)
277
319
 
278
320
  Presentational groups \u2014 import from the package root, not from these paths:
@@ -282,11 +324,11 @@ Presentational groups \u2014 import from the package root, not from these paths:
282
324
  | \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`ChartPanel\` |
283
325
  | \`integrations/\` | \`IntegrationCard\`, \`ConnectionRow\`, \`ConnectionRowList\`, \`IntegrationsEmptyState\`, \`PlanBadge\` |
284
326
  | \`settings/\` | \`SettingsSection\`, \`FieldRow\`, \`DangerZone\`, \`FloatingUnsavedChangesBar\` |
285
- | \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
286
- | \`layout/\` | \`AppShell\`, \`Page\`, \`Section\` |
327
+ | \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`AlertCard\`, \`CatalogCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
328
+ | \`layout/\` | \`AppShell\`, \`Page\` (auto-stacks children; \`width\` ladder), \`Section\`, \`Stack\` |
287
329
  | \`charts\` (re-exported) | \`LineAreaChart\`, \`PieChart\`, \`RadialChart\`, \`RadarChart\`, \`Sparkline\`, \`CHART_PALETTE\` |
288
330
 
289
- Also re-exported: \`Button\`, \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_AGENT_INSTRUCTIONS\`.
331
+ Also re-exported from \`/app\`: \`Button\`, \`Avatar\` / \`AvatarImage\` / \`AvatarFallback\`, \`Banner\`, \`Timeline\`, \`Kanban\` (drag-and-drop board), \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_AGENT_INSTRUCTIONS\`. Other UI primitives used in block recipes (\`Card\`, \`Input\`, \`Label\`, \`Sheet\`, \`Separator\`, \`AlertDialog\`, \`Badge\`, \`Select\`, \u2026) import from \`@timbal-ai/timbal-react/ui\` or the package root \u2014 **not** from \`/app\`.
290
332
 
291
333
  Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\`, \`themeToCss\`, \`applyTimbalTheme\`, \`TIMBAL_THEME_PRESETS\`, \`applyThemePreset\`, \`TimbalThemeStyle\`, \`THEME_AGENT_INSTRUCTIONS\`. Theming is **configured by the developer**, not surfaced as an end-user theme picker.
292
334
 
@@ -298,9 +340,12 @@ Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\
298
340
  | **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. |
299
341
  | **Context** | Do not show raw JSON context in the panel header; keep context in \`AppCopilotProvider\` only. |
300
342
  | **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\`). Apply the theme **programmatically** \u2014 do **not** add an end-user theme selector to generated apps. See \`THEME_AGENT_INSTRUCTIONS\`. |
301
- | **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. Default to **no global topbar** \u2014 put account/theme/global actions in the \`Page\` \`actions\` slot (or the sidebar). Add \`AppShellTopbar\` only when a full-width global bar is explicitly requested. |
343
+ | **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. Default to **no global topbar** \u2014 put account/theme/global actions in the \`Page\` \`actions\` slot (or the sidebar). Add a topbar only when a full-width global bar is explicitly requested. |
344
+ | **Spacing / gaps** | \`Page\` **auto-stacks its direct children with a vertical gap** \u2014 drop blocks straight in (e.g. \`Page\` \u2192 \`FilterBar\` + \`DataTable\`, or \`MetricRow\` + \`ChartPanel\`) and they breathe; do **not** wrap every block in an extra \`<div>\` (that collapses the gap). For ad-hoc clusters inside a card/row use \`Stack\` (\`gap\`, \`direction\`) instead of bare flex with no gap. Grids still need their own \`gap-*\`. |
345
+ | **Width** | \`Page\` defaults to a wide centered column. For focused / reading / form pages pass \`width\` (\`default\`, \`centered\`, \`narrow\`, \`prose\`) instead of always running full-bleed \u2014 not everything needs the full width. \`width="full"\` opts into edge-to-edge. For full-height pages that should stay centered use \`fill\` + \`fillPadded\`. |
302
346
  | **Density** | Set \`density="compact"\` on \`Page\` for tighter dashboards (full-width column, smaller section gaps, card padding, metric tiles, default chart height 220). Default is \`"default"\` (platform spacing). Wrap custom layouts with \`AppDensityProvider\` when not using \`Page\`. Per-section override: \`Section density="compact"\`. Do **not** hand-tune five layers of \`className\` padding when density covers the need. |
303
347
  | **Data** | Prefer \`DataTable\` with typed \`columns\` / \`rows\` / \`getRowKey\`; use \`ChartPanel\` with a \`ChartArtifact\` for charts (set \`chartType\` + options \u2014 see the chart catalog). Chart colors come from the theme \`--chart-1..6\` tokens; pass \`series[].color\` / \`colors\` only to override, never raw hex on every series. |
348
+ | **Boards** | For status/triage workflows (pipelines, sprint boards, review queues) use \`Kanban\` \u2014 pass \`columns\` (each with \`cards\`) + \`renderCard\`; handle \`onColumnsChange\`/\`onMove\` to persist. It's drag-and-drop **and** keyboard accessible; don't hand-roll columns of cards. |
304
349
  | **Modals** | Use \`AppConfirmDialog\` for destructive/export confirmations. |
305
350
  | **Metrics** | Overview KPIs \u2192 \`MetricRow\` or \`MetricChartCard\` (not four separate heavy cards). Values use **normal** font weight, not bold. |
306
351
  | **Integrations** | Catalog \u2192 \`IntegrationCard\` grid; connected list \u2192 \`ConnectionRow\` inside \`ConnectionRowList\`. Footer CTAs: \`Button variant="secondary"\`. |
@@ -332,7 +377,6 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
332
377
  | Component | Use for |
333
378
  |-----------|---------|
334
379
  | \`AppShell\` | Shell: optional \`sidebar\`, \`topbar\`, main \`children\`, optional floating \`chat\`. Props: \`chatTriggerLabel\`, \`chatCollapsible\`, \`chatWidth\`, \`chatHeight\`, controlled \`chatOpen\`, **\`contentFill\`** (bounded non-scrolling content region for full-bleed pages \u2014 chat/canvas/split view). |
335
- | \`AppShellTopbar\` | Full-width top bar: \`start\`, \`actions\` slots. |
336
380
  | \`AppCopilotProvider\` | React context for copilot-aware tools (page, filters, selection, etc.). |
337
381
  | \`AppChatPanel\` | Floating thread: \`workforceId\`, \`welcome\`, \`debug\`. |
338
382
  | \`useAppShellChat\` | Custom open/close trigger when \`hideChatTrigger\` on shell. |
@@ -341,7 +385,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
341
385
  | \`SubNav\` | **Section switcher** (Overview / Reports pill bar): \`items\`, \`activeId\`, \`onChange\`. Never use Radix/shadcn \`Tabs\` \u2014 it is not in this package. Switch panels with state or the router. |
342
386
  | **Menus** | **Select** = short list, no search. **Combobox** = searchable (same trigger as Select). **Command** only inside \`PopoverContent variant="list"\` or Combobox \u2014 never padded default Popover. See \`examples/app-kit/src/recipes/primitives-catalog.ts\`. |
343
387
  | \`Breadcrumbs\` | Trail: \`items: [{ label, href? }]\`. |
344
- | \`Button\` | Actions \u2014 \`variant="secondary"\` for catalog/secondary CTAs; \`variant="default"\` for primary. |
388
+ | \`Button\` | Actions. Untitled UI-style \`color\` alias (\`primary\` \\| \`secondary\` \\| \`tertiary\` \\| \`link\` \\| \`primary-destructive\` \\| \`secondary-destructive\`) + \`iconLeading\` / \`iconTrailing\`; or legacy \`variant="secondary"\` (catalog CTAs) / \`variant="default"\` (primary). \`color="primary-destructive"\` is the solid red delete CTA. |
345
389
  | \`StatTile\` | Single KPI in its own card (grid of scattered stats). Prefer \`MetricRow\` for a unified overview strip. |
346
390
  | \`StatusBadge\` | Status pill: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`\\|\`muted\`), children. Use \`danger\` for critical/error severity. |
347
391
  | \`FilterBar\` | Horizontal filter row \u2014 bottom-aligns controls. Mix \`SearchInput\` with labeled \`FilterField\` + \`Select\` (or \`Field\` + \`Select\`); labels sit above, control baselines match. |
@@ -350,7 +394,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
350
394
  | \`DataTable\` | Sortable table: \`columns\`, \`rows\`, \`getRowKey\`, optional \`sort\` / \`onSortChange\`, \`emptyTitle\`, \`showRowCount\`, \`caption\`, \`truncate: true\` on columns with long text. **Scales:** \`pageSize\` (built-in client pager), \`selectable\` + \`onSelectionChange\` (checkbox column for bulk actions), \`loading\` (skeleton rows). \`onRowClick\` for row \u2192 detail (open a \`Sheet\`). |
351
395
  | \`Avatar\` / \`AvatarFallback\` | User initials: \`variant="secondary"\` (or \`primary\` / \`chart\` alias) on **both** \`Avatar\` and \`AvatarFallback\` \u2014 same chrome as catalog **Action** buttons (\`Button variant="secondary"\`: elevated gradient, \`border-border\`, \`shadow-card\`, \`text-foreground\`). Never dark primary CTA fill or raw \`bg-blue-600\`. |
352
396
  | \`ChartPanel\` | Same shell as \`MetricChartCard\`: title row (\`px-4 pt-4\`), flush plot (\`pt-2\` only) with **no axis ticks** \u2014 hover tooltips show category + value. Pass \`title\` + \`artifact\` (omit \`artifact.title\` to avoid duplicates) or \`children\`. \`loading\` renders a plot-height skeleton. Default plot height follows page \`density\` (300 default, 220 compact); pass \`height\` to override. |
353
- | \`FieldInput\`, \`FieldTextarea\`, \`FieldSelect\`, \`FieldSwitch\` | Settings-style forms with labels and hints. |
397
+ | \`FieldInput\`, \`FieldTextarea\`, \`FieldSelect\`, \`FieldSwitch\` | Settings-style forms with labels and hints. **\`label\` is required** on every \`Field*\` component; for a label-less filter control use \`FilterField\` (optional label) or \`SearchInput\`. |
354
398
  | \`FormSection\` | Grouped form block. |
355
399
  | \`AppConfirmDialog\` | Confirm/cancel modal: \`open\`, \`onOpenChange\`, \`title\`, \`description\`, \`onConfirm\`. |
356
400
  | \`SurfaceCard\`, \`EmptyState\` | Generic surfaces when needed. |
@@ -396,9 +440,13 @@ Charts run on **recharts** with shadcn \`ChartContainer\` / \`ChartTooltipConten
396
440
  | Component | Use for |
397
441
  |-----------|---------|
398
442
  | \`InfoCard\` | Soft callout: \`icon\`, \`title\`, body, \`action\`, \`tone\` (\`info\`/\`success\`/\`warn\`/\`danger\`). |
443
+ | \`AlertCard\` | Actionable / AI-generated alert card with integrated status tags, clear titles, descriptive bodies, and automated action footers. Supports: \`title\`, \`description?\`, \`category?\`, \`categoryTone?\`, \`status?\`, \`statusTone?\`, \`action?\` (action description text), \`trailing?\` (custom element), and \`onClick?\`. Renders with a beautiful neutral hover state, avoiding loud/colored hover background effects. |
444
+ | \`CatalogCard\` | Highly sophisticated marketplace/routing catalog tile (models, datasets, tools). Supports: \`title\`, \`subtitle?\`, \`logo?\` (e.g. brand logo), \`badge?\` (e.g. model type badge), \`description?\`, \`tags?\` (metadata array), \`href?\` (title link), \`footerLinks?\` (bottom-left links), \`copyValue?\` (copy ID button), \`actions?\`, and \`onClick?\` (neutral-hover interactive state). |
399
445
  | \`DescriptionList\` | Read-only key/value metadata: \`items: [{ label, value }]\`, optional \`stacked\`. |
400
446
  | \`ExpandableSection\` | Collapsible block: \`title\`, \`icon\`, \`count\`, animated body (\`aria-expanded\` + \`aria-controls\`). |
401
447
  | \`StatusDot\` | Status indicator dot: \`tone\`, \`label\`, \`pulse\`. |
448
+ | \`Banner\` | Page-level announcement bar: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`), \`icon\`, \`title\`, body as children, right-aligned \`actions\`, \`onDismiss\` (renders the dismiss X). For in-form/field messages use \`InfoCard\` or \`Alert\` instead. |
449
+ | \`Timeline\` | Vertical event log: \`items: [{ id, title, description?, meta?, tone?, icon? }]\`. Presentational \u2014 pass already-formatted timestamps in \`meta\`. |
402
450
 
403
451
  Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/timbal-react/studio\` \u2014 optional, not required for every dashboard.
404
452
 
@@ -466,6 +514,8 @@ import {
466
514
  DataTable,
467
515
  FilterBar,
468
516
  FilterField,
517
+ AlertCard,
518
+ CatalogCard,
469
519
  } from "@timbal-ai/timbal-react/app";
470
520
  \`\`\`
471
521
 
@@ -476,6 +526,17 @@ import {
476
526
  | \`examples/app-kit/recipes/*\` | **Recipes** \u2014 one pattern each (~20\u201380 lines). Use for capability, not layout. |
477
527
  | \`examples/app-kit/reference/operations-dashboard.tsx\` | **Reference only** \u2014 full wired app; do not treat as the default generated layout. |
478
528
 
529
+ ### API gotchas \u2014 props that do NOT exist (don't guess, don't retry variations)
530
+
531
+ The compiler rejects these every time; write against the documented shapes above instead:
532
+
533
+ - \`FieldInput\` / \`FieldTextarea\` / \`FieldSelect\` / \`FieldSwitch\` **require \`label\`** \u2014 TS2741 if omitted. Label-less control \u2192 \`FilterField\` or \`SearchInput\`.
534
+ - Full-height layout: \`fill\` lives on \`Page\` (paired with \`AppShell contentFill\`) \u2014 there is no \`fill\` on \`Section\` or \`AppShell\`.
535
+ - \`WorkforceSelector\` (chat subpath / root) is a **controlled** picker: \`workforces\` (e.g. from \`useWorkforces()\`), \`value\`, \`onChange(id)\`, optional \`hideWhenSingle\` / \`placeholder\`. It does **not** fetch and has no \`workforceId\` prop \u2014 for an embedded assistant use \`AppChatPanel workforceId="\u2026"\`.
536
+ - There is **no \`Tabs\` export** \u2014 section switching uses \`SubNav\` or \`PillSegmentedTabs\`.
537
+ - \`Banner\` and \`Timeline\` exist (see menu) \u2014 import them from \`/app\`, \`/ui\`, or the root.
538
+ - If a prop still type-errors, read the actual definitions in \`node_modules/@timbal-ai/timbal-react/dist/app.d.ts\` once instead of retrying guessed prop names.
539
+
479
540
  ### Rules
480
541
 
481
542
  - Prefer stable props documented above; avoid undocumented \`design/*\` class exports (\`connectionRowListClass\` is exported but \`ConnectionRowList\` is preferred).
@@ -506,6 +567,7 @@ var GRADIENT_DIRECTIONS = /* @__PURE__ */ new Set([
506
567
  ]);
507
568
  var ICON_IMPORT_RE = /from\s+["']lucide-react["']/;
508
569
  var RAW_CONTROL_SURFACE_RE = /\bborder-input\b/;
570
+ var COLORED_HOVER_RE = /\bhover:(?:bg|from|to|via)-(?:primary|destructive|success|warn|danger|blue|emerald|green|amber|red|indigo|violet|purple|pink|rose|sky|cyan|teal|lime|yellow|orange|fuchsia)\b/;
509
571
  var RESERVED_GRADIENT_SET = new Set(RESERVED_GRADIENT_TOKENS);
510
572
  function stripVariants(util) {
511
573
  return util.replace(/^(?:[a-z-]+:)*/, "");
@@ -522,7 +584,14 @@ function lintGeneratedUi(source, options = {}) {
522
584
  let usesLucide = false;
523
585
  let iconUsageCount = 0;
524
586
  let dividerRunCount = 0;
587
+ let pageTitle = null;
588
+ const pageTitleMatch = source.match(/<Page\s+[^>]*\btitle=(?:"([^"]+)"|\{["']([^"']+)["']\})/);
589
+ if (pageTitleMatch) {
590
+ pageTitle = (pageTitleMatch[1] || pageTitleMatch[2]).trim().toLowerCase();
591
+ }
592
+ const hasChat = /\b(?:TimbalChat|AppChatPanel|Thread)\b/.test(source);
525
593
  const lucideNames = /* @__PURE__ */ new Set();
594
+ const openCards = [];
526
595
  for (let i = 0; i < lines.length; i++) {
527
596
  const line = lines[i];
528
597
  const lineNo = i + 1;
@@ -538,6 +607,33 @@ function lintGeneratedUi(source, options = {}) {
538
607
  continue;
539
608
  }
540
609
  if (isCommentOrImport(line)) continue;
610
+ const cardMatch = line.match(/<(Card|SurfaceCard|ArtifactCard)\b/);
611
+ if (cardMatch) {
612
+ const isSelfClosing = /\/>/.test(line) && line.indexOf(cardMatch[0]) < line.indexOf("/>");
613
+ if (!isSelfClosing) {
614
+ openCards.push({ type: cardMatch[1], line: lineNo });
615
+ }
616
+ }
617
+ const closeMatch = line.match(/<\/(Card|SurfaceCard|ArtifactCard)\b/);
618
+ if (closeMatch && openCards.length > 0) {
619
+ const idx = openCards.map((c) => c.type).lastIndexOf(closeMatch[1]);
620
+ if (idx !== -1) {
621
+ openCards.splice(idx, 1);
622
+ }
623
+ }
624
+ if (openCards.length > 0) {
625
+ const tableMatch = line.match(/<(DataTable|table|Table)\b/);
626
+ if (tableMatch) {
627
+ const parentCard = openCards[openCards.length - 1];
628
+ findings.push({
629
+ rule: "no-table-in-card",
630
+ severity: "error",
631
+ line: lineNo,
632
+ message: `Table inside card. Never wrap a <${tableMatch[1]}> or table inside a <${parentCard.type}> (opened on L${parentCard.line}). Place the table directly on the Page or Section instead.`,
633
+ snippet: line.trim().slice(0, 120)
634
+ });
635
+ }
636
+ }
541
637
  const rawColors = line.match(RAW_COLOR_RE);
542
638
  if (rawColors) {
543
639
  for (const m of rawColors) {
@@ -578,6 +674,15 @@ function lintGeneratedUi(source, options = {}) {
578
674
  snippet: line.trim().slice(0, 120)
579
675
  });
580
676
  }
677
+ if (COLORED_HOVER_RE.test(line)) {
678
+ findings.push({
679
+ rule: "no-colored-hover",
680
+ severity: "warn",
681
+ line: lineNo,
682
+ message: "Colored hover background/gradient. House style: interactive cards and list items must use neutral hover states \u2014 never hard-code colored backgrounds or borders on hover.",
683
+ snippet: line.trim().slice(0, 120)
684
+ });
685
+ }
581
686
  if (BOLD_VALUE_RE.test(line)) {
582
687
  findings.push({
583
688
  rule: "bold-metric",
@@ -624,6 +729,44 @@ function lintGeneratedUi(source, options = {}) {
624
729
  if (hits) iconUsageCount += hits.length;
625
730
  }
626
731
  }
732
+ if (pageTitle) {
733
+ const titleMatch = line.match(/<(Section|ChartPanel|Card|DataTable|SurfaceCard)\s+[^>]*\btitle=(?:"([^"]+)"|\{["']([^"']+)["']\})/);
734
+ if (titleMatch) {
735
+ const element = titleMatch[1];
736
+ const titleVal = (titleMatch[2] || titleMatch[3]).trim().toLowerCase();
737
+ if (titleVal === pageTitle || titleVal.includes(pageTitle) || pageTitle.includes(titleVal)) {
738
+ findings.push({
739
+ rule: "no-title-repetition",
740
+ severity: "warn",
741
+ line: lineNo,
742
+ message: `Title repetition. The <${element}> title "${titleVal}" repeats or is very similar to the <Page> title "${pageTitle}". Drop the title from the child element or use a title-less Section to avoid redundant headings.`,
743
+ snippet: line.trim().slice(0, 120)
744
+ });
745
+ }
746
+ }
747
+ }
748
+ if (hasChat) {
749
+ const wrappingMatch = line.match(/<(Card|Section|SurfaceCard|FormSection|SettingsSection)\b/);
750
+ if (wrappingMatch) {
751
+ findings.push({
752
+ rule: "no-chat-wrapping",
753
+ severity: "error",
754
+ line: lineNo,
755
+ message: `Chat component wrapping. Never wrap TimbalChat or AppChatPanel inside a <${wrappingMatch[1]}> or custom bordered container. Let the chat component fill the page or slot directly.`,
756
+ snippet: line.trim().slice(0, 120)
757
+ });
758
+ }
759
+ const headingMatch = line.match(/<(h[1-6])\b/);
760
+ if (headingMatch) {
761
+ findings.push({
762
+ rule: "no-chat-wrapping",
763
+ severity: "error",
764
+ line: lineNo,
765
+ message: `Custom heading in chat view. Do not render custom <${headingMatch[1]}> headings on the chat page. Pass welcome.heading to TimbalChat if you need to customize the welcome title.`,
766
+ snippet: line.trim().slice(0, 120)
767
+ });
768
+ }
769
+ }
627
770
  }
628
771
  if (usesLucide && iconUsageCount > maxIcons) {
629
772
  findings.push({
@@ -1356,7 +1499,20 @@ var TimbalThemeStyle = ({
1356
1499
 
1357
1500
  // src/design/app-classes.ts
1358
1501
  var appPageColumnClass = "mx-auto w-full max-w-[100rem] px-4 md:px-6 lg:px-8";
1359
- var appShellTopbarInsetClass = "w-full px-4 md:px-6";
1502
+ var PAGE_WIDTH_MAXW = {
1503
+ full: "max-w-none",
1504
+ wide: "max-w-[100rem]",
1505
+ default: "max-w-7xl",
1506
+ centered: "max-w-5xl",
1507
+ narrow: "max-w-3xl",
1508
+ prose: "max-w-2xl"
1509
+ };
1510
+ function appPageColumn(width, density = "default") {
1511
+ const lateral = density === "compact" ? "px-3 md:px-4" : "px-4 md:px-6 lg:px-8";
1512
+ const maxW = width ? PAGE_WIDTH_MAXW[width] : density === "compact" ? "max-w-none" : "max-w-[100rem]";
1513
+ return cn("mx-auto w-full", maxW, lateral);
1514
+ }
1515
+ var appShellTopbarInsetClass = "mx-auto w-full max-w-[100rem] px-4 md:px-6 lg:px-8";
1360
1516
  var appShellInsetTopClass = "pt-4 md:pt-6";
1361
1517
  var appShellInsetBottomClass = "pb-8 md:pb-10";
1362
1518
  var appShellTopbarRowClass = cn(
@@ -1423,6 +1579,15 @@ var APP_DENSITY_CLASSES = {
1423
1579
  default: appPageHeaderClass,
1424
1580
  compact: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between pb-2 pt-1"
1425
1581
  },
1582
+ /**
1583
+ * Vertical rhythm between a `Page`'s direct content blocks. Page-level gap so
1584
+ * stacked blocks (FilterBar + DataTable, MetricRow + ChartPanel, bare cards)
1585
+ * never render flush — the #1 source of gap-less generated layouts.
1586
+ */
1587
+ pageStack: {
1588
+ default: "flex flex-col gap-6",
1589
+ compact: "flex flex-col gap-4"
1590
+ },
1426
1591
  section: {
1427
1592
  default: appSectionClass,
1428
1593
  compact: "flex flex-col gap-2 py-2"
@@ -1448,12 +1613,12 @@ var APP_DENSITY_CLASSES = {
1448
1613
  compact: "relative flex min-w-0 flex-1 flex-col gap-1 px-3 py-2 text-left font-normal"
1449
1614
  },
1450
1615
  metricChartRegion: {
1451
- default: "relative min-h-0 w-full overflow-x-hidden border-t border-border/40 pt-2",
1452
- compact: "relative min-h-0 w-full overflow-x-hidden border-t border-border/40 pt-1"
1616
+ default: "relative min-h-0 w-full overflow-x-hidden pt-2",
1617
+ compact: "relative min-h-0 w-full overflow-x-hidden pt-1"
1453
1618
  },
1454
1619
  metricChartPlotRegion: {
1455
- default: "relative min-h-0 w-full overflow-x-hidden border-t border-border/40 px-0 pt-5 pb-3",
1456
- compact: "relative min-h-0 w-full overflow-x-hidden border-t border-border/40 px-0 pt-3 pb-2"
1620
+ default: "relative min-h-0 w-full overflow-x-hidden px-0 pt-5 pb-3",
1621
+ compact: "relative min-h-0 w-full overflow-x-hidden px-0 pt-3 pb-2"
1457
1622
  },
1458
1623
  chartPanelBody: {
1459
1624
  default: "pt-2 pb-3",
@@ -1482,8 +1647,71 @@ function useAppDensityClass(key, override) {
1482
1647
  return appDensityClass(key, override ?? inherited);
1483
1648
  }
1484
1649
 
1650
+ // src/charts/sparkline.tsx
1651
+ import { useId } from "react";
1652
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1653
+ var Sparkline = ({
1654
+ data,
1655
+ dataKey = "value",
1656
+ color = "var(--primary, #6366f1)",
1657
+ area = true,
1658
+ width = 96,
1659
+ height = 28,
1660
+ strokeWidth = 1.5,
1661
+ className,
1662
+ ariaLabel = "Trend"
1663
+ }) => {
1664
+ const uid = useId();
1665
+ const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
1666
+ if (values.length === 0) {
1667
+ return /* @__PURE__ */ jsx3("span", { className: cn("inline-block", className), style: { width, height } });
1668
+ }
1669
+ const pad = strokeWidth + 1;
1670
+ const min = Math.min(...values);
1671
+ const max = Math.max(...values);
1672
+ const range = max - min || 1;
1673
+ const innerW = width - pad * 2;
1674
+ const innerH = height - pad * 2;
1675
+ const points = values.map((v, i) => ({
1676
+ x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
1677
+ y: pad + innerH - (v - min) / range * innerH
1678
+ }));
1679
+ return /* @__PURE__ */ jsxs2(
1680
+ "svg",
1681
+ {
1682
+ width,
1683
+ height,
1684
+ viewBox: `0 0 ${width} ${height}`,
1685
+ className: cn("block", className),
1686
+ role: "img",
1687
+ "aria-label": ariaLabel,
1688
+ preserveAspectRatio: "none",
1689
+ children: [
1690
+ area && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1691
+ /* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs2("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
1692
+ /* @__PURE__ */ jsx3("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
1693
+ /* @__PURE__ */ jsx3("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
1694
+ ] }) }),
1695
+ /* @__PURE__ */ jsx3("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
1696
+ ] }),
1697
+ /* @__PURE__ */ jsx3(
1698
+ "path",
1699
+ {
1700
+ d: monotoneLinePath(points),
1701
+ fill: "none",
1702
+ stroke: color,
1703
+ strokeWidth,
1704
+ strokeLinecap: "round",
1705
+ strokeLinejoin: "round"
1706
+ }
1707
+ )
1708
+ ]
1709
+ }
1710
+ );
1711
+ };
1712
+
1485
1713
  // src/app/data/metrics-shared.tsx
1486
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1714
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1487
1715
  var metricCardShellClass = cn(
1488
1716
  studioIntegrationCardClass,
1489
1717
  "aui-app-metric-card shadow-none",
@@ -1493,18 +1721,22 @@ var metricTilesRowClass = "grid w-full min-w-0";
1493
1721
  var metricCellDividerClass = "border-r border-border/40";
1494
1722
  var MetricCardHeader = ({
1495
1723
  title,
1724
+ titleTag,
1496
1725
  titleId,
1497
1726
  description,
1498
1727
  actions
1499
1728
  }) => {
1500
1729
  const headerClass = useAppDensityClass("metricCardHeader");
1501
1730
  if (!title && !description && !actions) return null;
1502
- return /* @__PURE__ */ jsxs2("header", { className: headerClass, children: [
1503
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
1504
- title ? /* @__PURE__ */ jsx3("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }) : null,
1505
- description ? /* @__PURE__ */ jsx3("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
1731
+ return /* @__PURE__ */ jsxs3("header", { className: cn(headerClass, "items-center"), children: [
1732
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
1733
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2.5", children: [
1734
+ title ? /* @__PURE__ */ jsx4("h3", { id: titleId, className: "text-sm font-semibold text-foreground tracking-tight select-none", children: title }) : null,
1735
+ titleTag ? /* @__PURE__ */ jsx4("span", { className: "inline-flex rounded-full bg-muted/70 px-2 py-0.5 text-[10px] font-medium text-muted-foreground border border-border/30 tracking-tight leading-none select-none", children: titleTag }) : null
1736
+ ] }),
1737
+ description ? /* @__PURE__ */ jsx4("p", { className: "mt-1 text-xs text-muted-foreground leading-normal select-none", children: description }) : null
1506
1738
  ] }),
1507
- actions ? /* @__PURE__ */ jsx3("div", { className: "shrink-0", children: actions }) : null
1739
+ actions ? /* @__PURE__ */ jsx4("div", { className: "shrink-0 flex items-center", children: actions }) : null
1508
1740
  ] });
1509
1741
  };
1510
1742
  function metricTilesGridColsClass(n) {
@@ -1515,6 +1747,8 @@ function metricTilesGridColsClass(n) {
1515
1747
  return "grid-cols-2";
1516
1748
  case 3:
1517
1749
  return "grid-cols-3";
1750
+ case 4:
1751
+ return "grid-cols-2 md:grid-cols-4";
1518
1752
  case 5:
1519
1753
  return "grid-cols-2 sm:grid-cols-5";
1520
1754
  case 6:
@@ -1525,12 +1759,25 @@ function metricTilesGridColsClass(n) {
1525
1759
  }
1526
1760
 
1527
1761
  // src/app/data/MetricTile.tsx
1528
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1762
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1529
1763
  var trendToneClass = {
1530
1764
  up: "border-border/80 bg-muted/40 text-muted-foreground",
1531
1765
  down: "border-border/80 bg-muted/40 text-muted-foreground",
1532
1766
  neutral: "border-border/80 bg-muted/30 text-muted-foreground"
1533
1767
  };
1768
+ var inlineTrendToneClass = {
1769
+ up: "text-blue-500/90 dark:text-blue-400/95 font-medium",
1770
+ down: "text-rose-500/90 dark:text-rose-400/95 font-medium",
1771
+ neutral: "text-muted-foreground/80"
1772
+ };
1773
+ var activeToneClass = {
1774
+ default: "bg-foreground dark:bg-white",
1775
+ primary: "bg-primary",
1776
+ success: "bg-emerald-500",
1777
+ warn: "bg-amber-500",
1778
+ danger: "bg-destructive",
1779
+ neutral: "bg-border"
1780
+ };
1534
1781
  var metricTileInteractiveExtraClass = cn(
1535
1782
  "bg-transparent hover:bg-transparent active:bg-transparent",
1536
1783
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
@@ -1541,58 +1788,86 @@ var MetricTile = ({
1541
1788
  unit,
1542
1789
  trend,
1543
1790
  trendTone = "neutral",
1791
+ trendVariant = "pill",
1544
1792
  active = false,
1793
+ activeTone = "default",
1545
1794
  showDivider = false,
1546
1795
  onSelect,
1796
+ sparklineData,
1797
+ sparklineConfig,
1798
+ sparkline,
1547
1799
  ariaLabel,
1548
1800
  className
1549
1801
  }) => {
1550
1802
  const metricTileBaseClass = useAppDensityClass("metricTile");
1551
- const content = /* @__PURE__ */ jsxs3(Fragment2, { children: [
1552
- active ? /* @__PURE__ */ jsx4(
1803
+ const hasSparkline = Boolean(sparkline || sparklineData);
1804
+ const content = /* @__PURE__ */ jsxs4(Fragment3, { children: [
1805
+ active ? /* @__PURE__ */ jsx5(
1553
1806
  "span",
1554
1807
  {
1555
1808
  "aria-hidden": true,
1556
- className: "absolute inset-x-0 bottom-0 h-0.5 bg-foreground dark:bg-white"
1809
+ className: cn(
1810
+ "absolute inset-x-0 bottom-0 h-0.5 z-20 transition-colors duration-200",
1811
+ activeToneClass[activeTone]
1812
+ )
1557
1813
  }
1558
1814
  ) : null,
1559
- /* @__PURE__ */ jsx4("span", { className: "text-xs font-normal text-muted-foreground", children: label }),
1560
- /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2", children: [
1561
- /* @__PURE__ */ jsxs3("span", { className: "flex items-baseline gap-1", children: [
1562
- /* @__PURE__ */ jsx4("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
1563
- unit ? /* @__PURE__ */ jsx4("span", { className: "text-xs font-normal text-muted-foreground", children: unit }) : null
1564
- ] }),
1565
- trend ? /* @__PURE__ */ jsx4(
1566
- "span",
1567
- {
1568
- className: cn(
1569
- "rounded-full border px-1.5 py-0.5 text-xs font-normal",
1570
- trendToneClass[trendTone]
1571
- ),
1572
- children: trend
1573
- }
1574
- ) : null
1815
+ hasSparkline ? /* @__PURE__ */ jsx5("div", { className: "absolute inset-x-0 bottom-0.5 h-9 w-full overflow-hidden pointer-events-none z-0 opacity-45 dark:opacity-35 select-none", children: sparkline ?? /* @__PURE__ */ jsx5(
1816
+ Sparkline,
1817
+ {
1818
+ data: sparklineData,
1819
+ width: 160,
1820
+ height: 36,
1821
+ className: "w-full h-full",
1822
+ color: trendTone === "up" ? "var(--primary, #3b82f6)" : trendTone === "down" ? "var(--destructive, #f43f5e)" : "var(--muted-foreground, #64748b)",
1823
+ ...sparklineConfig
1824
+ }
1825
+ ) }) : null,
1826
+ /* @__PURE__ */ jsxs4("div", { className: "relative z-10 flex flex-col gap-1 w-full text-left", children: [
1827
+ /* @__PURE__ */ jsx5("span", { className: "text-xs font-semibold text-muted-foreground/80 tracking-tight", children: label }),
1828
+ /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2", children: [
1829
+ /* @__PURE__ */ jsxs4("span", { className: "flex items-baseline gap-1", children: [
1830
+ /* @__PURE__ */ jsx5("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
1831
+ unit ? /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium text-muted-foreground", children: unit }) : null
1832
+ ] }),
1833
+ trend ? trendVariant === "inline" ? /* @__PURE__ */ jsx5("span", { className: cn("text-xs leading-none select-none", inlineTrendToneClass[trendTone]), children: trend }) : /* @__PURE__ */ jsx5(
1834
+ "span",
1835
+ {
1836
+ className: cn(
1837
+ "rounded-full border px-1.5 py-0.5 text-xs font-normal select-none",
1838
+ trendToneClass[trendTone]
1839
+ ),
1840
+ children: trend
1841
+ }
1842
+ ) : null
1843
+ ] })
1575
1844
  ] })
1576
1845
  ] });
1577
1846
  const divider = showDivider ? metricCellDividerClass : void 0;
1578
1847
  if (onSelect) {
1579
- return /* @__PURE__ */ jsx4(
1848
+ return /* @__PURE__ */ jsx5(
1580
1849
  "button",
1581
1850
  {
1582
1851
  type: "button",
1583
1852
  onClick: onSelect,
1584
1853
  "aria-pressed": active,
1585
1854
  "aria-label": ariaLabel,
1586
- className: cn(metricTileBaseClass, metricTileInteractiveExtraClass, divider, className),
1855
+ className: cn(
1856
+ metricTileBaseClass,
1857
+ "transition-all duration-200 hover:bg-muted/10",
1858
+ metricTileInteractiveExtraClass,
1859
+ divider,
1860
+ className
1861
+ ),
1587
1862
  children: content
1588
1863
  }
1589
1864
  );
1590
1865
  }
1591
- return /* @__PURE__ */ jsx4("div", { className: cn(metricTileBaseClass, divider, className), children: content });
1866
+ return /* @__PURE__ */ jsx5("div", { className: cn(metricTileBaseClass, divider, className), children: content });
1592
1867
  };
1593
1868
 
1594
1869
  // src/app/theme/ThemePresetGallery.tsx
1595
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1870
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1596
1871
 
1597
1872
  // src/app/layout/app-shell-chat-context.tsx
1598
1873
  import { createContext as createContext2, useContext as useContext2 } from "react";
@@ -1618,8 +1893,8 @@ function useAppShellNav() {
1618
1893
 
1619
1894
  // src/app/layout/AppShell.tsx
1620
1895
  import { motion, useReducedMotion } from "motion/react";
1621
- import { useCallback, useMemo, useState } from "react";
1622
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1896
+ import { useCallback, useEffect, useMemo, useState } from "react";
1897
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1623
1898
  var floatingTriggerClass = cn(
1624
1899
  "aui-app-shell-chat-trigger-fixed fixed z-50 rounded-full px-5 py-2.5 text-sm font-medium shadow-card-elevated",
1625
1900
  "bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
@@ -1642,21 +1917,32 @@ var AppShellBody = ({
1642
1917
  insetExpanded,
1643
1918
  children
1644
1919
  }) => {
1920
+ const [isMobile, setIsMobile] = useState(() => {
1921
+ if (typeof window === "undefined") return false;
1922
+ return window.innerWidth < 768;
1923
+ });
1924
+ useEffect(() => {
1925
+ if (typeof window === "undefined") return;
1926
+ const onResize = () => setIsMobile(window.innerWidth < 768);
1927
+ onResize();
1928
+ window.addEventListener("resize", onResize);
1929
+ return () => window.removeEventListener("resize", onResize);
1930
+ }, []);
1645
1931
  const reducedMotion = useReducedMotion();
1646
1932
  const layoutDirection = insetExpanded ? "expand" : "collapse";
1647
1933
  const layoutTransition = studioSidebarWidthTransition(
1648
1934
  !!reducedMotion,
1649
1935
  layoutDirection
1650
1936
  );
1651
- const insetPadding = sidebar ? insetPaddingPx : 0;
1652
- return /* @__PURE__ */ jsx6(
1937
+ const insetPadding = sidebar && !isMobile ? insetPaddingPx : 0;
1938
+ return /* @__PURE__ */ jsx7(
1653
1939
  motion.div,
1654
1940
  {
1655
1941
  className: "aui-app-shell-body relative z-10 flex min-h-0 min-w-0 flex-1 flex-col",
1656
1942
  initial: false,
1657
1943
  animate: { paddingLeft: insetPadding },
1658
1944
  transition: layoutTransition,
1659
- children: /* @__PURE__ */ jsxs5(
1945
+ children: /* @__PURE__ */ jsxs6(
1660
1946
  "div",
1661
1947
  {
1662
1948
  className: cn(
@@ -1667,8 +1953,8 @@ var AppShellBody = ({
1667
1953
  !topbarContent && appShellInsetTopClass
1668
1954
  ),
1669
1955
  children: [
1670
- topbarContent ? /* @__PURE__ */ jsx6("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx6("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
1671
- /* @__PURE__ */ jsx6(
1956
+ topbarContent ? /* @__PURE__ */ jsx7("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx7("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
1957
+ /* @__PURE__ */ jsx7(
1672
1958
  "main",
1673
1959
  {
1674
1960
  className: cn(
@@ -1748,7 +2034,7 @@ var AppShell = ({
1748
2034
  setInsetPaddingPx(insetPx);
1749
2035
  }, []);
1750
2036
  const insetExpanded = insetPaddingPx >= SIDEBAR_INSET_PX_EXPANDED;
1751
- const shellBody = /* @__PURE__ */ jsx6(
2037
+ const shellBody = /* @__PURE__ */ jsx7(
1752
2038
  AppShellBody,
1753
2039
  {
1754
2040
  sidebar,
@@ -1760,7 +2046,7 @@ var AppShell = ({
1760
2046
  children
1761
2047
  }
1762
2048
  );
1763
- const tree = /* @__PURE__ */ jsx6(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs5(
2049
+ const tree = /* @__PURE__ */ jsx7(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs6(
1764
2050
  "div",
1765
2051
  {
1766
2052
  className: cn(
@@ -1770,7 +2056,7 @@ var AppShell = ({
1770
2056
  style: studioChromeShellStyle,
1771
2057
  children: [
1772
2058
  sidebar,
1773
- sidebar && navOpen ? /* @__PURE__ */ jsx6(
2059
+ sidebar && navOpen ? /* @__PURE__ */ jsx7(
1774
2060
  "button",
1775
2061
  {
1776
2062
  type: "button",
@@ -1780,7 +2066,7 @@ var AppShell = ({
1780
2066
  }
1781
2067
  ) : null,
1782
2068
  shellBody,
1783
- hasChat && chatOpen ? /* @__PURE__ */ jsx6(
2069
+ hasChat && chatOpen ? /* @__PURE__ */ jsx7(
1784
2070
  "div",
1785
2071
  {
1786
2072
  className: floatingPanelClass,
@@ -1793,7 +2079,7 @@ var AppShell = ({
1793
2079
  children: chat
1794
2080
  }
1795
2081
  ) : null,
1796
- hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx6(
2082
+ hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx7(
1797
2083
  "button",
1798
2084
  {
1799
2085
  type: "button",
@@ -1806,11 +2092,11 @@ var AppShell = ({
1806
2092
  ]
1807
2093
  }
1808
2094
  ) });
1809
- const withNav = /* @__PURE__ */ jsx6(AppShellNavProvider, { value: navControls, children: tree });
2095
+ const withNav = /* @__PURE__ */ jsx7(AppShellNavProvider, { value: navControls, children: tree });
1810
2096
  if (!hasChat) {
1811
2097
  return withNav;
1812
2098
  }
1813
- return /* @__PURE__ */ jsx6(
2099
+ return /* @__PURE__ */ jsx7(
1814
2100
  AppShellChatProvider,
1815
2101
  {
1816
2102
  value: {
@@ -1824,23 +2110,6 @@ var AppShell = ({
1824
2110
  );
1825
2111
  };
1826
2112
 
1827
- // src/app/layout/AppShellTopbar.tsx
1828
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1829
- var AppShellTopbar = ({
1830
- start,
1831
- actions,
1832
- children,
1833
- className
1834
- }) => {
1835
- return /* @__PURE__ */ jsxs6("div", { className: cn("aui-app-shell-topbar", appShellTopbarRowClass, className), children: [
1836
- /* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
1837
- start,
1838
- children
1839
- ] }),
1840
- actions ? /* @__PURE__ */ jsx7("div", { className: "aui-app-shell-topbar-actions flex shrink-0 items-center gap-2", children: actions }) : null
1841
- ] });
1842
- };
1843
-
1844
2113
  // src/app/layout/AppShellChatTrigger.tsx
1845
2114
  import { jsx as jsx8 } from "react/jsx-runtime";
1846
2115
  var floatingPositionClass = "fixed bottom-6 right-6 z-50 max-sm:bottom-4 max-sm:right-4";
@@ -1921,34 +2190,32 @@ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1921
2190
  var PageFrame = ({
1922
2191
  children,
1923
2192
  breadcrumbs,
2193
+ width,
1924
2194
  fill = false,
2195
+ fillPadded = false,
1925
2196
  className,
1926
2197
  ...headerProps
1927
2198
  }) => {
1928
2199
  const density = useAppDensity();
1929
- const pageColumnClass = useAppDensityClass("pageColumn");
1930
- return /* @__PURE__ */ jsxs8(
1931
- "div",
1932
- {
1933
- className: cn(
1934
- "aui-app-page",
1935
- fill ? "flex min-h-0 min-w-0 flex-1 flex-col" : pageColumnClass,
1936
- className
1937
- ),
1938
- "data-density": density,
1939
- children: [
1940
- breadcrumbs,
1941
- /* @__PURE__ */ jsx11(PageHeader, { ...headerProps }),
1942
- children
1943
- ]
1944
- }
1945
- );
2200
+ const stackClass = useAppDensityClass("pageStack");
2201
+ const columnClass = appPageColumn(width, density);
2202
+ const rootClass = fill ? cn(
2203
+ "flex min-h-0 min-w-0 flex-1 flex-col",
2204
+ fillPadded && columnClass
2205
+ ) : columnClass;
2206
+ return /* @__PURE__ */ jsxs8("div", { className: cn("aui-app-page", rootClass, className), "data-density": density, children: [
2207
+ breadcrumbs,
2208
+ /* @__PURE__ */ jsx11(PageHeader, { ...headerProps }),
2209
+ fill ? children : /* @__PURE__ */ jsx11("div", { className: cn("aui-app-page-stack", stackClass), children })
2210
+ ] });
1946
2211
  };
1947
2212
  var Page = ({
1948
2213
  density = "default",
1949
2214
  children,
1950
2215
  breadcrumbs,
2216
+ width,
1951
2217
  fill = false,
2218
+ fillPadded = false,
1952
2219
  className,
1953
2220
  ...headerProps
1954
2221
  }) => {
@@ -1956,7 +2223,9 @@ var Page = ({
1956
2223
  PageFrame,
1957
2224
  {
1958
2225
  breadcrumbs,
2226
+ width,
1959
2227
  fill,
2228
+ fillPadded,
1960
2229
  className,
1961
2230
  ...headerProps,
1962
2231
  children
@@ -1981,15 +2250,61 @@ var Section = ({
1981
2250
  ] });
1982
2251
  };
1983
2252
 
2253
+ // src/app/layout/Stack.tsx
2254
+ import { jsx as jsx13 } from "react/jsx-runtime";
2255
+ var GAP_CLASS = {
2256
+ none: "gap-0",
2257
+ xs: "gap-1",
2258
+ sm: "gap-2",
2259
+ md: "gap-4",
2260
+ lg: "gap-6",
2261
+ xl: "gap-8"
2262
+ };
2263
+ var ALIGN_CLASS = {
2264
+ start: "items-start",
2265
+ center: "items-center",
2266
+ end: "items-end",
2267
+ stretch: "items-stretch"
2268
+ };
2269
+ var JUSTIFY_CLASS = {
2270
+ start: "justify-start",
2271
+ center: "justify-center",
2272
+ end: "justify-end",
2273
+ between: "justify-between"
2274
+ };
2275
+ var Stack = ({
2276
+ children,
2277
+ direction = "vertical",
2278
+ gap = "md",
2279
+ align,
2280
+ justify,
2281
+ wrap = false,
2282
+ className
2283
+ }) => /* @__PURE__ */ jsx13(
2284
+ "div",
2285
+ {
2286
+ className: cn(
2287
+ "flex min-w-0",
2288
+ direction === "vertical" ? "flex-col" : "flex-row",
2289
+ GAP_CLASS[gap],
2290
+ align && ALIGN_CLASS[align],
2291
+ justify && JUSTIFY_CLASS[justify],
2292
+ wrap && "flex-wrap",
2293
+ className
2294
+ ),
2295
+ children
2296
+ }
2297
+ );
2298
+
1984
2299
  // src/app/copilot/app-copilot-context.tsx
1985
2300
  import { createContext as createContext4, useContext as useContext4 } from "react";
1986
- import { jsx as jsx13 } from "react/jsx-runtime";
2301
+ import { jsx as jsx14 } from "react/jsx-runtime";
1987
2302
  var AppCopilotContext = createContext4(null);
1988
2303
  var AppCopilotProvider = ({
1989
2304
  value,
1990
2305
  children
1991
2306
  }) => {
1992
- return /* @__PURE__ */ jsx13(AppCopilotContext.Provider, { value, children });
2307
+ return /* @__PURE__ */ jsx14(AppCopilotContext.Provider, { value, children });
1993
2308
  };
1994
2309
  function useAppCopilotContext() {
1995
2310
  return useContext4(AppCopilotContext) ?? {};
@@ -1997,7 +2312,7 @@ function useAppCopilotContext() {
1997
2312
 
1998
2313
  // src/app/chat/AppChatPanel.tsx
1999
2314
  import { XIcon } from "lucide-react";
2000
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
2315
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2001
2316
  var shellClass = "aui-app-chat-panel flex h-full min-h-0 flex-col overflow-hidden";
2002
2317
  var chromeClass = cn(
2003
2318
  "aui-app-chat-panel-chrome relative z-20 flex min-h-10 shrink-0 items-center justify-end px-2 pt-2"
@@ -2043,17 +2358,17 @@ var AppChatPanel = ({
2043
2358
  }) => {
2044
2359
  const shellChat = useAppShellChat();
2045
2360
  return /* @__PURE__ */ jsxs10("div", { className: cn(shellClass, className), children: [
2046
- shellChat?.collapsible ? /* @__PURE__ */ jsx14("div", { className: chromeClass, children: /* @__PURE__ */ jsx14(
2361
+ shellChat?.collapsible ? /* @__PURE__ */ jsx15("div", { className: chromeClass, children: /* @__PURE__ */ jsx15(
2047
2362
  "button",
2048
2363
  {
2049
2364
  type: "button",
2050
2365
  className: closeButtonClass,
2051
2366
  onClick: () => shellChat.setOpen(false),
2052
2367
  "aria-label": "Close assistant",
2053
- children: /* @__PURE__ */ jsx14(XIcon, { className: "size-4", "aria-hidden": true })
2368
+ children: /* @__PURE__ */ jsx15(XIcon, { className: "size-4", "aria-hidden": true })
2054
2369
  }
2055
2370
  ) }) : null,
2056
- /* @__PURE__ */ jsx14("div", { className: bodyClass, children: /* @__PURE__ */ jsx14(
2371
+ /* @__PURE__ */ jsx15("div", { className: bodyClass, children: /* @__PURE__ */ jsx15(
2057
2372
  TimbalRuntimeProvider,
2058
2373
  {
2059
2374
  workforceId,
@@ -2063,7 +2378,7 @@ var AppChatPanel = ({
2063
2378
  attachmentsUploadUrl,
2064
2379
  attachmentsAccept,
2065
2380
  debug,
2066
- children: /* @__PURE__ */ jsx14(
2381
+ children: /* @__PURE__ */ jsx15(
2067
2382
  Thread,
2068
2383
  {
2069
2384
  variant: "panel",
@@ -2084,41 +2399,121 @@ var AppChatPanel = ({
2084
2399
  };
2085
2400
 
2086
2401
  // src/app/surfaces/SurfaceCard.tsx
2087
- import { jsx as jsx15 } from "react/jsx-runtime";
2088
- var SurfaceCard = ({ children, className }) => {
2402
+ import { jsx as jsx16 } from "react/jsx-runtime";
2403
+ var surfaceVariantClass = {
2404
+ default: "",
2405
+ muted: "bg-none bg-muted/40 shadow-none border border-border/20",
2406
+ outline: "bg-none bg-transparent border border-border shadow-none",
2407
+ elevated: "shadow-card-elevated border border-border/80",
2408
+ flat: "bg-card/70 border border-border/50 shadow-[0_1px_3px_rgba(0,0,0,0.03),0_10px_15px_-3px_rgba(0,0,0,0.01)] dark:bg-card/40",
2409
+ hierarchical: "bg-card/90 border border-border/60 shadow-[0_1px_2px_rgba(0,0,0,0.02),0_8px_16px_rgba(0,0,0,0.01)] rounded-2xl dark:bg-card/50"
2410
+ };
2411
+ var surfaceToneClass = {
2412
+ default: "",
2413
+ primary: "ring-1 ring-inset ring-primary/25",
2414
+ success: "ring-1 ring-inset ring-emerald-500/25",
2415
+ warn: "ring-1 ring-inset ring-amber-500/30",
2416
+ danger: "ring-1 ring-inset ring-destructive/25"
2417
+ };
2418
+ var SurfaceCard = ({
2419
+ children,
2420
+ variant = "default",
2421
+ tone = "default",
2422
+ hoverable,
2423
+ onClick,
2424
+ ariaLabel,
2425
+ className
2426
+ }) => {
2089
2427
  const surfaceCardClass = useAppDensityClass("surfaceCard");
2090
- return /* @__PURE__ */ jsx15("div", { className: cn("aui-app-surface-card", surfaceCardClass, className), children });
2428
+ const isInteractive = Boolean(onClick);
2429
+ const shouldHover = hoverable ?? isInteractive;
2430
+ const baseClass = cn(
2431
+ "aui-app-surface-card",
2432
+ surfaceCardClass,
2433
+ surfaceVariantClass[variant],
2434
+ surfaceToneClass[tone],
2435
+ shouldHover && "transition-all duration-200 hover:border-border/80 hover:shadow-md",
2436
+ isInteractive && "cursor-pointer select-none active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2437
+ className
2438
+ );
2439
+ if (isInteractive) {
2440
+ return /* @__PURE__ */ jsx16(
2441
+ "button",
2442
+ {
2443
+ type: "button",
2444
+ onClick,
2445
+ "aria-label": ariaLabel,
2446
+ className: baseClass,
2447
+ children
2448
+ }
2449
+ );
2450
+ }
2451
+ return /* @__PURE__ */ jsx16("div", { className: baseClass, children });
2091
2452
  };
2092
2453
 
2093
2454
  // src/app/surfaces/StatTile.tsx
2094
- import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
2095
- var StatTile = ({ label, value, hint, className }) => {
2455
+ import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
2456
+ var statValueToneClass = {
2457
+ default: "",
2458
+ primary: "text-primary",
2459
+ success: "text-emerald-700 dark:text-emerald-400",
2460
+ warn: "text-amber-700 dark:text-amber-400",
2461
+ danger: "text-destructive"
2462
+ };
2463
+ var StatTile = ({
2464
+ label,
2465
+ value,
2466
+ hint,
2467
+ tone = "default",
2468
+ className
2469
+ }) => {
2096
2470
  const statTileClass = useAppDensityClass("statTile");
2097
2471
  return /* @__PURE__ */ jsxs11("div", { className: cn("aui-app-stat-tile", statTileClass, className), children: [
2098
- /* @__PURE__ */ jsx16("span", { className: appStatLabelClass, children: label }),
2099
- /* @__PURE__ */ jsx16("span", { className: appStatValueClass, children: value }),
2100
- hint ? /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: hint }) : null
2472
+ /* @__PURE__ */ jsx17("span", { className: appStatLabelClass, children: label }),
2473
+ /* @__PURE__ */ jsx17("span", { className: cn(appStatValueClass, statValueToneClass[tone]), children: value }),
2474
+ hint ? /* @__PURE__ */ jsx17("span", { className: "text-xs text-muted-foreground", children: hint }) : null
2101
2475
  ] });
2102
2476
  };
2103
2477
 
2104
2478
  // src/app/surfaces/EmptyState.tsx
2105
- import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
2479
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
2106
2480
  var EmptyState = ({
2107
2481
  title,
2108
2482
  description,
2109
2483
  action,
2110
- className
2484
+ className,
2485
+ variant = "default"
2111
2486
  }) => {
2112
- const emptyStateClass = useAppDensityClass("emptyState");
2113
- return /* @__PURE__ */ jsxs12("div", { className: cn("aui-app-empty-state", emptyStateClass, className), children: [
2114
- /* @__PURE__ */ jsx17("p", { className: appEmptyStateTitleClass, children: title }),
2115
- description ? /* @__PURE__ */ jsx17("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
2116
- action
2487
+ const densityClass = useAppDensityClass("emptyState");
2488
+ if (variant === "layered") {
2489
+ return /* @__PURE__ */ jsx18(
2490
+ "div",
2491
+ {
2492
+ className: cn(
2493
+ "aui-app-empty-state-layered w-full rounded-2xl border border-border/40 bg-muted/20 p-6 md:p-8 flex items-center justify-center dark:bg-muted/10",
2494
+ className
2495
+ ),
2496
+ children: /* @__PURE__ */ jsxs12("div", { className: "w-full max-w-xl rounded-xl border border-border bg-card p-6 md:p-8 shadow-[0_1px_3px_rgba(0,0,0,0.02),0_10px_15px_-3px_rgba(0,0,0,0.01)] flex flex-col items-center justify-center text-center gap-4 transition-all duration-200 hover:border-border/80 dark:bg-card/45", children: [
2497
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-1.5 items-center justify-center", children: [
2498
+ /* @__PURE__ */ jsx18("h3", { className: "text-base font-semibold text-foreground tracking-tight", children: title }),
2499
+ description ? /* @__PURE__ */ jsx18("p", { className: "max-w-sm text-sm text-muted-foreground leading-relaxed", children: description }) : null
2500
+ ] }),
2501
+ action ? /* @__PURE__ */ jsx18("div", { className: "mt-1", children: action }) : null
2502
+ ] })
2503
+ }
2504
+ );
2505
+ }
2506
+ const isCompact = variant === "compact";
2507
+ const finalClass = isCompact ? "aui-app-empty-state rounded-xl border border-border bg-gradient-to-b from-elevated-from to-elevated-to p-3 flex flex-col items-center justify-center gap-2 py-8 text-center" : cn("aui-app-empty-state", densityClass);
2508
+ return /* @__PURE__ */ jsxs12("div", { className: cn(finalClass, className), children: [
2509
+ /* @__PURE__ */ jsx18("p", { className: cn(appEmptyStateTitleClass, "font-semibold tracking-tight"), children: title }),
2510
+ description ? /* @__PURE__ */ jsx18("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
2511
+ action ? /* @__PURE__ */ jsx18("div", { className: "mt-1", children: action }) : null
2117
2512
  ] });
2118
2513
  };
2119
2514
 
2120
2515
  // src/app/surfaces/StatusBadge.tsx
2121
- import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
2516
+ import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
2122
2517
  var statusBadgeToneClass = {
2123
2518
  default: "bg-muted text-foreground ring-border",
2124
2519
  primary: "bg-primary/10 text-primary ring-primary/20",
@@ -2151,7 +2546,7 @@ var StatusBadge = ({
2151
2546
  className
2152
2547
  ),
2153
2548
  children: [
2154
- dot ? /* @__PURE__ */ jsx18(
2549
+ dot ? /* @__PURE__ */ jsx19(
2155
2550
  "span",
2156
2551
  {
2157
2552
  "aria-hidden": true,
@@ -2168,7 +2563,7 @@ var StatusBadge = ({
2168
2563
  };
2169
2564
 
2170
2565
  // src/app/surfaces/AppConfirmDialog.tsx
2171
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
2566
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
2172
2567
  var bodyClass2 = "flex flex-col gap-4 p-6";
2173
2568
  var titleClass = "pr-8";
2174
2569
  var actionsClass = "flex flex-wrap justify-end gap-2";
@@ -2183,15 +2578,15 @@ var AppConfirmDialog = ({
2183
2578
  destructive = false,
2184
2579
  className
2185
2580
  }) => {
2186
- return /* @__PURE__ */ jsx19(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx19(
2581
+ return /* @__PURE__ */ jsx20(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx20(
2187
2582
  DialogContent,
2188
2583
  {
2189
2584
  className: cn("gap-0 p-0 sm:max-w-md", className),
2190
2585
  children: /* @__PURE__ */ jsxs14("div", { className: bodyClass2, children: [
2191
- /* @__PURE__ */ jsx19(DialogTitle, { className: titleClass, children: title }),
2192
- description ? /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground", children: description }) : null,
2586
+ /* @__PURE__ */ jsx20(DialogTitle, { className: titleClass, children: title }),
2587
+ description ? /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: description }) : null,
2193
2588
  /* @__PURE__ */ jsxs14("div", { className: actionsClass, children: [
2194
- /* @__PURE__ */ jsx19(
2589
+ /* @__PURE__ */ jsx20(
2195
2590
  TimbalV2Button,
2196
2591
  {
2197
2592
  type: "button",
@@ -2201,7 +2596,7 @@ var AppConfirmDialog = ({
2201
2596
  children: cancelLabel
2202
2597
  }
2203
2598
  ),
2204
- /* @__PURE__ */ jsx19(
2599
+ /* @__PURE__ */ jsx20(
2205
2600
  TimbalV2Button,
2206
2601
  {
2207
2602
  type: "button",
@@ -2221,7 +2616,7 @@ var AppConfirmDialog = ({
2221
2616
  };
2222
2617
 
2223
2618
  // src/app/surfaces/InfoCard.tsx
2224
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
2619
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
2225
2620
  var toneClass = {
2226
2621
  neutral: "border-border bg-muted/40",
2227
2622
  info: "border-primary/25 bg-primary/5",
@@ -2229,34 +2624,67 @@ var toneClass = {
2229
2624
  warn: "border-amber-500/25 bg-amber-500/5",
2230
2625
  danger: "border-destructive/25 bg-destructive/5"
2231
2626
  };
2627
+ var toneVerticalClass = {
2628
+ neutral: "border-border/60 bg-card hover:border-border dark:bg-card/40",
2629
+ info: "border-primary/20 bg-primary/5 hover:border-primary/45",
2630
+ success: "border-emerald-500/20 bg-emerald-500/5 hover:border-emerald-500/45",
2631
+ warn: "border-amber-500/25 bg-amber-500/5 hover:border-amber-500/45",
2632
+ danger: "border-destructive/20 bg-destructive/5 hover:border-destructive/45"
2633
+ };
2232
2634
  var InfoCard = ({
2233
2635
  title,
2234
2636
  children,
2235
2637
  icon,
2236
2638
  action,
2237
2639
  tone = "neutral",
2640
+ layout = "horizontal",
2641
+ onClick,
2642
+ ariaLabel,
2238
2643
  className
2239
- }) => /* @__PURE__ */ jsxs15(
2240
- "div",
2241
- {
2242
- className: cn(
2243
- "flex items-start gap-3 rounded-xl border p-4",
2244
- toneClass[tone],
2245
- className
2246
- ),
2247
- children: [
2248
- icon ? /* @__PURE__ */ jsx20("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
2249
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2250
- title ? /* @__PURE__ */ jsx20("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
2251
- children ? /* @__PURE__ */ jsx20("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
2644
+ }) => {
2645
+ const isInteractive = Boolean(onClick);
2646
+ if (layout === "vertical") {
2647
+ const cardContent = /* @__PURE__ */ jsxs15(Fragment4, { children: [
2648
+ icon ? /* @__PURE__ */ jsx21("span", { className: "flex size-10 items-center justify-center rounded-xl bg-muted/50 border border-border/40 text-muted-foreground/80 transition-transform duration-200 group-hover:scale-105", children: icon }) : null,
2649
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-1.5 w-full text-left", children: [
2650
+ title ? /* @__PURE__ */ jsx21("p", { className: "text-sm font-semibold text-foreground tracking-tight leading-tight", children: title }) : null,
2651
+ children ? /* @__PURE__ */ jsx21("div", { className: "text-xs text-muted-foreground leading-relaxed", children }) : null
2252
2652
  ] }),
2253
- action ? /* @__PURE__ */ jsx20("div", { className: "shrink-0", children: action }) : null
2254
- ]
2653
+ action ? /* @__PURE__ */ jsx21("div", { className: "w-full mt-1", children: action }) : null
2654
+ ] });
2655
+ const baseClass2 = cn(
2656
+ "group flex flex-col gap-4 items-start rounded-2xl border p-5 transition-all duration-200 shadow-[0_1px_3px_rgba(0,0,0,0.03),0_10px_15px_-3px_rgba(0,0,0,0.01)]",
2657
+ toneVerticalClass[tone],
2658
+ isInteractive && "cursor-pointer select-none hover:shadow-md active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2659
+ className
2660
+ );
2661
+ if (isInteractive) {
2662
+ return /* @__PURE__ */ jsx21("button", { type: "button", onClick, "aria-label": ariaLabel, className: baseClass2, children: cardContent });
2663
+ }
2664
+ return /* @__PURE__ */ jsx21("div", { className: baseClass2, children: cardContent });
2255
2665
  }
2256
- );
2666
+ const horizontalContent = /* @__PURE__ */ jsxs15(Fragment4, { children: [
2667
+ icon ? /* @__PURE__ */ jsx21("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
2668
+ /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1 text-left", children: [
2669
+ title ? /* @__PURE__ */ jsx21("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
2670
+ children ? /* @__PURE__ */ jsx21("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
2671
+ ] }),
2672
+ action ? /* @__PURE__ */ jsx21("div", { className: "shrink-0", children: action }) : null
2673
+ ] });
2674
+ const baseClass = cn(
2675
+ "flex items-start gap-3 rounded-xl border p-4 transition-all duration-200",
2676
+ toneClass[tone],
2677
+ isInteractive && "cursor-pointer select-none hover:bg-muted/30 active:scale-[0.995] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2678
+ className
2679
+ );
2680
+ if (isInteractive) {
2681
+ return /* @__PURE__ */ jsx21("button", { type: "button", onClick, "aria-label": ariaLabel, className: baseClass, children: horizontalContent });
2682
+ }
2683
+ return /* @__PURE__ */ jsx21("div", { className: baseClass, children: horizontalContent });
2684
+ };
2257
2685
 
2258
2686
  // src/app/surfaces/StatusDot.tsx
2259
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
2687
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
2260
2688
  var dotClass = {
2261
2689
  online: "bg-emerald-500",
2262
2690
  busy: "bg-amber-500",
@@ -2271,7 +2699,7 @@ var StatusDot = ({
2271
2699
  className
2272
2700
  }) => /* @__PURE__ */ jsxs16("span", { className: cn("inline-flex items-center gap-1.5", className), children: [
2273
2701
  /* @__PURE__ */ jsxs16("span", { className: "relative flex size-2", children: [
2274
- pulse ? /* @__PURE__ */ jsx21(
2702
+ pulse ? /* @__PURE__ */ jsx22(
2275
2703
  "span",
2276
2704
  {
2277
2705
  className: cn(
@@ -2280,18 +2708,18 @@ var StatusDot = ({
2280
2708
  )
2281
2709
  }
2282
2710
  ) : null,
2283
- /* @__PURE__ */ jsx21("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
2711
+ /* @__PURE__ */ jsx22("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
2284
2712
  ] }),
2285
- label ? /* @__PURE__ */ jsx21("span", { className: "text-xs text-muted-foreground", children: label }) : null
2713
+ label ? /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: label }) : null
2286
2714
  ] });
2287
2715
 
2288
2716
  // src/app/surfaces/DescriptionList.tsx
2289
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
2717
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
2290
2718
  var DescriptionList = ({
2291
2719
  items,
2292
2720
  stacked = false,
2293
2721
  className
2294
- }) => /* @__PURE__ */ jsx22(
2722
+ }) => /* @__PURE__ */ jsx23(
2295
2723
  "dl",
2296
2724
  {
2297
2725
  className: cn(
@@ -2303,16 +2731,18 @@ var DescriptionList = ({
2303
2731
  {
2304
2732
  className: cn(
2305
2733
  "px-4 py-3",
2306
- stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4"
2734
+ stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4",
2735
+ item.className
2307
2736
  ),
2308
2737
  children: [
2309
- /* @__PURE__ */ jsx22("dt", { className: "text-sm text-muted-foreground", children: item.label }),
2310
- /* @__PURE__ */ jsx22(
2738
+ /* @__PURE__ */ jsx23("dt", { className: cn("text-sm text-muted-foreground", item.labelClassName), children: item.label }),
2739
+ /* @__PURE__ */ jsx23(
2311
2740
  "dd",
2312
2741
  {
2313
2742
  className: cn(
2314
2743
  "text-sm text-foreground",
2315
- !stacked && "text-right tabular-nums"
2744
+ !stacked && "text-right tabular-nums",
2745
+ item.valueClassName
2316
2746
  ),
2317
2747
  children: item.value
2318
2748
  }
@@ -2325,10 +2755,10 @@ var DescriptionList = ({
2325
2755
  );
2326
2756
 
2327
2757
  // src/app/surfaces/ExpandableSection.tsx
2328
- import { useId, useState as useState2 } from "react";
2758
+ import { useId as useId2, useState as useState2 } from "react";
2329
2759
  import { AnimatePresence, motion as motion2, useReducedMotion as useReducedMotion2 } from "motion/react";
2330
- import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
2331
- var Chevron = ({ open }) => /* @__PURE__ */ jsx23(
2760
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
2761
+ var Chevron = ({ open }) => /* @__PURE__ */ jsx24(
2332
2762
  "svg",
2333
2763
  {
2334
2764
  viewBox: "0 0 24 24",
@@ -2342,7 +2772,7 @@ var Chevron = ({ open }) => /* @__PURE__ */ jsx23(
2342
2772
  strokeLinecap: "round",
2343
2773
  strokeLinejoin: "round",
2344
2774
  "aria-hidden": true,
2345
- children: /* @__PURE__ */ jsx23("path", { d: "m6 9 6 6 6-6" })
2775
+ children: /* @__PURE__ */ jsx24("path", { d: "m6 9 6 6 6-6" })
2346
2776
  }
2347
2777
  );
2348
2778
  var ExpandableSection = ({
@@ -2356,7 +2786,7 @@ var ExpandableSection = ({
2356
2786
  className
2357
2787
  }) => {
2358
2788
  const reduceMotion = useReducedMotion2();
2359
- const panelId = useId();
2789
+ const panelId = useId2();
2360
2790
  const [internalOpen, setInternalOpen] = useState2(defaultOpen);
2361
2791
  const open = openProp ?? internalOpen;
2362
2792
  const toggle = () => {
@@ -2374,15 +2804,15 @@ var ExpandableSection = ({
2374
2804
  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",
2375
2805
  children: [
2376
2806
  /* @__PURE__ */ jsxs18("span", { className: "flex min-w-0 items-center gap-3", children: [
2377
- icon ? /* @__PURE__ */ jsx23("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
2378
- /* @__PURE__ */ jsx23("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
2379
- count != null ? /* @__PURE__ */ jsx23("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
2807
+ icon ? /* @__PURE__ */ jsx24("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
2808
+ /* @__PURE__ */ jsx24("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
2809
+ count != null ? /* @__PURE__ */ jsx24("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
2380
2810
  ] }),
2381
- /* @__PURE__ */ jsx23(Chevron, { open })
2811
+ /* @__PURE__ */ jsx24(Chevron, { open })
2382
2812
  ]
2383
2813
  }
2384
2814
  ),
2385
- /* @__PURE__ */ jsx23(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx23(
2815
+ /* @__PURE__ */ jsx24(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx24(
2386
2816
  motion2.div,
2387
2817
  {
2388
2818
  id: panelId,
@@ -2391,7 +2821,7 @@ var ExpandableSection = ({
2391
2821
  exit: reduceMotion ? void 0 : { height: 0, opacity: 0 },
2392
2822
  transition: { duration: 0.2, ease: "easeOut" },
2393
2823
  className: "overflow-hidden",
2394
- children: /* @__PURE__ */ jsx23("div", { className: "bg-muted/20", children })
2824
+ children: /* @__PURE__ */ jsx24("div", { className: "bg-muted/20", children })
2395
2825
  },
2396
2826
  "body"
2397
2827
  ) : null })
@@ -2399,19 +2829,14 @@ var ExpandableSection = ({
2399
2829
  };
2400
2830
 
2401
2831
  // src/app/surfaces/ResourceCard.tsx
2402
- import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
2403
- var resourceCardShellClass = cn(
2404
- "flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal",
2405
- TIMBAL_V2_ELEVATED_SURFACE
2406
- );
2832
+ import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
2407
2833
  var mediaShellClass = cn(
2408
2834
  "flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xl text-sm font-normal text-foreground",
2409
2835
  TIMBAL_V2_LOGO_TILE
2410
2836
  );
2411
2837
  var resourceCardInteractiveClass = cn(
2412
- resourceCardShellClass,
2413
- "cursor-pointer bg-transparent hover:bg-transparent active:bg-transparent",
2414
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
2838
+ "flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card",
2839
+ TIMBAL_V2_ELEVATED_SURFACE
2415
2840
  );
2416
2841
  var ResourceCard = ({
2417
2842
  title,
@@ -2422,37 +2847,236 @@ var ResourceCard = ({
2422
2847
  action,
2423
2848
  onClick,
2424
2849
  ariaLabel,
2425
- className
2850
+ className,
2851
+ variant = "flat",
2852
+ avatarShape = "circle"
2426
2853
  }) => {
2427
- const body = /* @__PURE__ */ jsxs19(Fragment3, { children: [
2854
+ const isInteractive = Boolean(onClick);
2855
+ const shellClass3 = cn(
2856
+ "flex min-h-[8.5rem] flex-col rounded-2xl p-5 text-left font-normal transition-all duration-200",
2857
+ variant === "default" && TIMBAL_V2_ELEVATED_SURFACE,
2858
+ variant === "flat" && "border border-border/50 bg-card/65 shadow-[0_1px_3px_rgba(0,0,0,0.05),0_10px_15px_-3px_rgba(0,0,0,0.01)] hover:border-border hover:shadow-md dark:bg-card/45",
2859
+ variant === "outline" && "border border-border/70 bg-transparent shadow-none hover:bg-muted/5",
2860
+ isInteractive && "cursor-pointer select-none active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
2861
+ );
2862
+ const dynamicMediaShellClass = cn(
2863
+ "flex size-10 shrink-0 items-center justify-center overflow-hidden text-sm font-normal text-foreground transition-all duration-200",
2864
+ avatarShape === "circle" ? "rounded-full" : "rounded-xl",
2865
+ TIMBAL_V2_LOGO_TILE
2866
+ );
2867
+ const body = /* @__PURE__ */ jsxs19(Fragment5, { children: [
2428
2868
  /* @__PURE__ */ jsxs19("div", { className: "flex items-start gap-3", children: [
2429
- media ? /* @__PURE__ */ jsx24("span", { className: mediaShellClass, children: media }) : null,
2869
+ media ? /* @__PURE__ */ jsx25("span", { className: dynamicMediaShellClass, children: media }) : null,
2430
2870
  /* @__PURE__ */ jsxs19("div", { className: "min-w-0 flex-1 pt-0.5", children: [
2431
- /* @__PURE__ */ jsx24("p", { className: "truncate text-sm font-normal leading-snug text-foreground", children: title }),
2432
- subtitle ? /* @__PURE__ */ jsx24("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground", children: subtitle }) : null
2871
+ /* @__PURE__ */ jsx25("p", { className: "truncate text-sm font-semibold leading-snug text-foreground tracking-tight", children: title }),
2872
+ subtitle ? /* @__PURE__ */ jsx25("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground/90 leading-relaxed", children: subtitle }) : null
2433
2873
  ] }),
2434
- badge ? /* @__PURE__ */ jsx24("span", { className: "shrink-0 pt-0.5", children: badge }) : null
2874
+ badge ? /* @__PURE__ */ jsx25("span", { className: "shrink-0 pt-0.5", children: badge }) : null
2435
2875
  ] }),
2436
2876
  footer || action ? /* @__PURE__ */ jsxs19("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: [
2437
- /* @__PURE__ */ jsx24("span", { className: "min-w-0 truncate", children: footer }),
2438
- action ? /* @__PURE__ */ jsx24("span", { className: "shrink-0 opacity-80", children: action }) : null
2877
+ /* @__PURE__ */ jsx25("span", { className: "min-w-0 truncate", children: footer }),
2878
+ action ? /* @__PURE__ */ jsx25("span", { className: "shrink-0 opacity-90", children: action }) : null
2879
+ ] }) : null
2880
+ ] });
2881
+ if (onClick) {
2882
+ return /* @__PURE__ */ jsx25(
2883
+ "button",
2884
+ {
2885
+ type: "button",
2886
+ onClick,
2887
+ "aria-label": ariaLabel,
2888
+ className: cn(shellClass3, className),
2889
+ children: body
2890
+ }
2891
+ );
2892
+ }
2893
+ return /* @__PURE__ */ jsx25("article", { className: cn(shellClass3, className), children: body });
2894
+ };
2895
+
2896
+ // src/app/surfaces/AlertCard.tsx
2897
+ import { ChevronRight } from "lucide-react";
2898
+ import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
2899
+ var alertCardShellClass = cn(
2900
+ "flex flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card",
2901
+ TIMBAL_V2_ELEVATED_GRADIENT
2902
+ );
2903
+ var alertCardInteractiveClass = cn(
2904
+ "flex flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card cursor-pointer",
2905
+ TIMBAL_V2_ELEVATED_GRADIENT,
2906
+ "transition-[background-color,box-shadow,border-color] duration-150 ease-in-out",
2907
+ "hover:border-foreground/20",
2908
+ "hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
2909
+ "active:from-secondary-fill-active-from active:to-secondary-fill-active-to",
2910
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
2911
+ );
2912
+ var AlertCard = ({
2913
+ title,
2914
+ description,
2915
+ category,
2916
+ categoryTone = "default",
2917
+ status,
2918
+ statusTone = "default",
2919
+ action,
2920
+ trailing,
2921
+ onClick,
2922
+ ariaLabel,
2923
+ className
2924
+ }) => {
2925
+ const showTags = Boolean(category || status);
2926
+ const showTrailing = Boolean(trailing || onClick);
2927
+ const bodyContent = /* @__PURE__ */ jsxs20("div", { className: "flex-1 min-w-0 flex flex-col h-full", children: [
2928
+ showTags ? /* @__PURE__ */ jsxs20("div", { className: "flex flex-wrap items-center gap-1.5 mb-2.5", children: [
2929
+ category ? /* @__PURE__ */ jsx26(StatusBadge, { tone: categoryTone, children: category }) : null,
2930
+ status ? /* @__PURE__ */ jsx26(StatusBadge, { tone: statusTone, children: status }) : null
2931
+ ] }) : null,
2932
+ /* @__PURE__ */ jsx26("h4", { className: "text-sm font-medium leading-snug text-foreground", children: title }),
2933
+ description ? /* @__PURE__ */ jsx26("p", { className: "mt-1.5 text-xs text-muted-foreground leading-normal", children: description }) : null,
2934
+ action ? /* @__PURE__ */ jsxs20("div", { className: "mt-auto pt-3 text-xs text-muted-foreground/90 leading-normal", children: [
2935
+ /* @__PURE__ */ jsx26("strong", { className: "font-semibold text-foreground/80", children: "Action: " }),
2936
+ action
2439
2937
  ] }) : null
2440
2938
  ] });
2939
+ const cardContent = /* @__PURE__ */ jsxs20("div", { className: "flex items-start justify-between gap-4 w-full h-full", children: [
2940
+ bodyContent,
2941
+ showTrailing ? /* @__PURE__ */ jsx26("div", { className: "shrink-0 flex items-center justify-center self-center text-muted-foreground/50", children: trailing || /* @__PURE__ */ jsx26(ChevronRight, { className: "size-4" }) }) : null
2942
+ ] });
2943
+ if (onClick) {
2944
+ return /* @__PURE__ */ jsx26(
2945
+ "button",
2946
+ {
2947
+ type: "button",
2948
+ onClick,
2949
+ "aria-label": ariaLabel,
2950
+ className: cn(alertCardInteractiveClass, className),
2951
+ children: cardContent
2952
+ }
2953
+ );
2954
+ }
2955
+ return /* @__PURE__ */ jsx26("article", { className: cn(alertCardShellClass, className), children: cardContent });
2956
+ };
2957
+
2958
+ // src/app/surfaces/CatalogCard.tsx
2959
+ import { ExternalLink } from "lucide-react";
2960
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
2961
+ var catalogCardShellClass = cn(
2962
+ "flex flex-col rounded-2xl border border-border shadow-card overflow-hidden text-left font-normal",
2963
+ TIMBAL_V2_ELEVATED_GRADIENT
2964
+ );
2965
+ var catalogCardInteractiveClass = cn(
2966
+ "flex flex-col rounded-2xl border border-border shadow-card overflow-hidden text-left font-normal cursor-pointer",
2967
+ TIMBAL_V2_ELEVATED_GRADIENT,
2968
+ "transition-[background-color,box-shadow,border-color] duration-150 ease-in-out",
2969
+ "hover:border-foreground/20",
2970
+ "hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
2971
+ "active:from-secondary-fill-active-from active:to-secondary-fill-active-to",
2972
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
2973
+ );
2974
+ var CatalogCard = ({
2975
+ title,
2976
+ subtitle,
2977
+ logo,
2978
+ href,
2979
+ badge,
2980
+ description,
2981
+ tags,
2982
+ footerLinks,
2983
+ copyValue,
2984
+ copyLabel = "Copy ID",
2985
+ actions,
2986
+ onClick,
2987
+ ariaLabel,
2988
+ className
2989
+ }) => {
2990
+ const showHeaderTags = Boolean(subtitle || badge);
2991
+ const showFooter = Boolean(footerLinks && footerLinks.length > 0 || copyValue || actions);
2992
+ const mainContent = /* @__PURE__ */ jsxs21("div", { className: "flex-1 p-5 flex flex-col h-full min-h-0", children: [
2993
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-start gap-3", children: [
2994
+ logo ? /* @__PURE__ */ jsx27("div", { className: "size-8 shrink-0 flex items-center justify-center overflow-hidden rounded-lg bg-muted/40", children: logo }) : null,
2995
+ /* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1 pt-0.5", children: [
2996
+ /* @__PURE__ */ jsx27("div", { className: "flex items-center gap-1.5 flex-wrap", children: href ? /* @__PURE__ */ jsxs21(
2997
+ "a",
2998
+ {
2999
+ href,
3000
+ target: "_blank",
3001
+ rel: "noopener noreferrer",
3002
+ className: "inline-flex items-center gap-1 hover:underline text-sm font-medium leading-snug text-foreground focus-visible:outline-none focus-visible:underline",
3003
+ onClick: (e) => e.stopPropagation(),
3004
+ children: [
3005
+ /* @__PURE__ */ jsx27("span", { className: "truncate", children: title }),
3006
+ /* @__PURE__ */ jsx27(ExternalLink, { className: "size-3.5 shrink-0 text-muted-foreground/60" })
3007
+ ]
3008
+ }
3009
+ ) : /* @__PURE__ */ jsx27("h4", { className: "text-sm font-medium leading-snug text-foreground truncate", children: title }) }),
3010
+ showHeaderTags ? /* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center gap-2 mt-1", children: [
3011
+ subtitle ? /* @__PURE__ */ jsx27("span", { className: "text-xs font-medium text-muted-foreground", children: subtitle }) : null,
3012
+ badge ? /* @__PURE__ */ jsx27("div", { className: "shrink-0 flex items-center", children: badge }) : null
3013
+ ] }) : null
3014
+ ] })
3015
+ ] }),
3016
+ description ? /* @__PURE__ */ jsx27("p", { className: "mt-3 text-xs leading-relaxed text-muted-foreground line-clamp-3", children: description }) : null,
3017
+ tags && tags.length > 0 ? /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap items-center gap-2 mt-4", children: tags.map((tag, idx) => /* @__PURE__ */ jsxs21("div", { className: "flex items-center text-xs text-muted-foreground/80", children: [
3018
+ idx > 0 && /* @__PURE__ */ jsx27("span", { className: "mr-2 text-muted-foreground/30", children: "\u2022" }),
3019
+ tag
3020
+ ] }, idx)) }) : null
3021
+ ] });
3022
+ const footerMarkup = showFooter ? /* @__PURE__ */ jsxs21("div", { className: "border-t border-border/40 px-5 py-3 flex items-center justify-between gap-4 bg-muted/[0.02]", children: [
3023
+ /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap items-center gap-4", children: footerLinks && footerLinks.length > 0 ? footerLinks.map((link, idx) => /* @__PURE__ */ jsxs21(
3024
+ "a",
3025
+ {
3026
+ href: link.href,
3027
+ target: "_blank",
3028
+ rel: "noopener noreferrer",
3029
+ className: "inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground hover:underline transition-colors focus-visible:outline-none focus-visible:underline",
3030
+ onClick: (e) => e.stopPropagation(),
3031
+ children: [
3032
+ /* @__PURE__ */ jsx27("span", { children: link.label }),
3033
+ /* @__PURE__ */ jsx27(ExternalLink, { className: "size-2.5 shrink-0 text-muted-foreground/50" })
3034
+ ]
3035
+ },
3036
+ idx
3037
+ )) : null }),
3038
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [
3039
+ actions ? actions : null,
3040
+ !actions && copyValue ? /* @__PURE__ */ jsx27(
3041
+ CopyButton,
3042
+ {
3043
+ value: copyValue,
3044
+ className: "h-7 text-xs px-2 hover:bg-muted/40 text-muted-foreground/80 hover:text-foreground",
3045
+ children: copyLabel
3046
+ }
3047
+ ) : null
3048
+ ] })
3049
+ ] }) : null;
2441
3050
  if (onClick) {
2442
- return /* @__PURE__ */ jsx24("button", { type: "button", onClick, "aria-label": ariaLabel, className: cn(resourceCardInteractiveClass, className), children: body });
3051
+ return /* @__PURE__ */ jsxs21(
3052
+ "button",
3053
+ {
3054
+ type: "button",
3055
+ onClick,
3056
+ "aria-label": ariaLabel,
3057
+ className: cn(catalogCardInteractiveClass, className),
3058
+ children: [
3059
+ mainContent,
3060
+ footerMarkup
3061
+ ]
3062
+ }
3063
+ );
2443
3064
  }
2444
- return /* @__PURE__ */ jsx24("article", { className: cn(resourceCardShellClass, className), children: body });
3065
+ return /* @__PURE__ */ jsxs21("article", { className: cn(catalogCardShellClass, className), children: [
3066
+ mainContent,
3067
+ footerMarkup
3068
+ ] });
2445
3069
  };
2446
3070
 
2447
3071
  // src/app/settings/SettingsSection.tsx
2448
- import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
3072
+ import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
2449
3073
  var SettingsSectionHeader = ({
2450
3074
  title,
2451
3075
  description,
2452
3076
  className
2453
- }) => /* @__PURE__ */ jsxs20("div", { className: cn("flex flex-col", className), children: [
2454
- /* @__PURE__ */ jsx25("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
2455
- description ? /* @__PURE__ */ jsx25("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
3077
+ }) => /* @__PURE__ */ jsxs22("div", { className: cn("flex flex-col", className), children: [
3078
+ /* @__PURE__ */ jsx28("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
3079
+ description ? /* @__PURE__ */ jsx28("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
2456
3080
  ] });
2457
3081
  var SettingsSection = ({
2458
3082
  title,
@@ -2461,7 +3085,7 @@ var SettingsSection = ({
2461
3085
  children,
2462
3086
  noBorderTop = false,
2463
3087
  className
2464
- }) => /* @__PURE__ */ jsxs20(
3088
+ }) => /* @__PURE__ */ jsxs22(
2465
3089
  "section",
2466
3090
  {
2467
3091
  className: cn(
@@ -2470,18 +3094,18 @@ var SettingsSection = ({
2470
3094
  className
2471
3095
  ),
2472
3096
  children: [
2473
- /* @__PURE__ */ jsxs20("div", { className: "min-w-0", children: [
2474
- /* @__PURE__ */ jsx25("h2", { className: "text-sm font-medium text-foreground", children: title }),
2475
- description ? /* @__PURE__ */ jsx25("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
2476
- descriptionFooter ? /* @__PURE__ */ jsx25("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
3097
+ /* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
3098
+ /* @__PURE__ */ jsx28("h2", { className: "text-sm font-medium text-foreground", children: title }),
3099
+ description ? /* @__PURE__ */ jsx28("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
3100
+ descriptionFooter ? /* @__PURE__ */ jsx28("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
2477
3101
  ] }),
2478
- /* @__PURE__ */ jsx25("div", { className: "min-w-0 space-y-3", children })
3102
+ /* @__PURE__ */ jsx28("div", { className: "min-w-0 space-y-3", children })
2479
3103
  ]
2480
3104
  }
2481
3105
  );
2482
3106
 
2483
3107
  // src/app/settings/FieldRow.tsx
2484
- import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
3108
+ import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
2485
3109
  var FieldRow = ({
2486
3110
  label,
2487
3111
  children,
@@ -2491,7 +3115,7 @@ var FieldRow = ({
2491
3115
  className
2492
3116
  }) => {
2493
3117
  if (inline) {
2494
- return /* @__PURE__ */ jsxs21(
3118
+ return /* @__PURE__ */ jsxs23(
2495
3119
  "div",
2496
3120
  {
2497
3121
  className: cn(
@@ -2499,8 +3123,8 @@ var FieldRow = ({
2499
3123
  className
2500
3124
  ),
2501
3125
  children: [
2502
- /* @__PURE__ */ jsxs21("div", { className: "min-w-0", children: [
2503
- /* @__PURE__ */ jsx26(
3126
+ /* @__PURE__ */ jsxs23("div", { className: "min-w-0", children: [
3127
+ /* @__PURE__ */ jsx29(
2504
3128
  "label",
2505
3129
  {
2506
3130
  htmlFor,
@@ -2508,25 +3132,25 @@ var FieldRow = ({
2508
3132
  children: label
2509
3133
  }
2510
3134
  ),
2511
- description ? /* @__PURE__ */ jsx26("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
3135
+ description ? /* @__PURE__ */ jsx29("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
2512
3136
  ] }),
2513
- /* @__PURE__ */ jsx26("div", { className: "shrink-0", children })
3137
+ /* @__PURE__ */ jsx29("div", { className: "shrink-0", children })
2514
3138
  ]
2515
3139
  }
2516
3140
  );
2517
3141
  }
2518
- return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-col gap-1.5", className), children: [
2519
- /* @__PURE__ */ jsx26("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
3142
+ return /* @__PURE__ */ jsxs23("div", { className: cn("flex flex-col gap-1.5", className), children: [
3143
+ /* @__PURE__ */ jsx29("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
2520
3144
  children,
2521
- description ? /* @__PURE__ */ jsx26("p", { className: "text-xs text-muted-foreground", children: description }) : null
3145
+ description ? /* @__PURE__ */ jsx29("p", { className: "text-xs text-muted-foreground", children: description }) : null
2522
3146
  ] });
2523
3147
  };
2524
3148
 
2525
3149
  // src/app/settings/FloatingUnsavedChangesBar.tsx
2526
- import { useEffect, useState as useState3 } from "react";
3150
+ import { useEffect as useEffect2, useState as useState3 } from "react";
2527
3151
  import { createPortal } from "react-dom";
2528
3152
  import { AnimatePresence as AnimatePresence2, motion as motion3, useReducedMotion as useReducedMotion3 } from "motion/react";
2529
- import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
3153
+ import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
2530
3154
  var FloatingUnsavedChangesBar = ({
2531
3155
  visible,
2532
3156
  message = "Unsaved changes",
@@ -2541,10 +3165,10 @@ var FloatingUnsavedChangesBar = ({
2541
3165
  }) => {
2542
3166
  const reduceMotion = useReducedMotion3();
2543
3167
  const [mounted, setMounted] = useState3(false);
2544
- useEffect(() => setMounted(true), []);
3168
+ useEffect2(() => setMounted(true), []);
2545
3169
  if (!mounted || typeof document === "undefined") return null;
2546
3170
  return createPortal(
2547
- /* @__PURE__ */ jsx27(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx27("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs22(
3171
+ /* @__PURE__ */ jsx30(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx30("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs24(
2548
3172
  motion3.div,
2549
3173
  {
2550
3174
  role: "region",
@@ -2558,10 +3182,10 @@ var FloatingUnsavedChangesBar = ({
2558
3182
  className
2559
3183
  ),
2560
3184
  children: [
2561
- /* @__PURE__ */ jsx27("span", { className: "text-sm text-muted-foreground", children: message }),
2562
- /* @__PURE__ */ jsxs22("span", { className: "flex items-center gap-1.5", children: [
2563
- /* @__PURE__ */ jsx27(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
2564
- /* @__PURE__ */ jsx27(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
3185
+ /* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: message }),
3186
+ /* @__PURE__ */ jsxs24("span", { className: "flex items-center gap-1.5", children: [
3187
+ /* @__PURE__ */ jsx30(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
3188
+ /* @__PURE__ */ jsx30(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
2565
3189
  ] })
2566
3190
  ]
2567
3191
  }
@@ -2571,13 +3195,13 @@ var FloatingUnsavedChangesBar = ({
2571
3195
  };
2572
3196
 
2573
3197
  // src/app/settings/DangerZone.tsx
2574
- import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
3198
+ import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
2575
3199
  var DangerZoneAction = ({
2576
3200
  title,
2577
3201
  description,
2578
3202
  action,
2579
3203
  className
2580
- }) => /* @__PURE__ */ jsxs23(
3204
+ }) => /* @__PURE__ */ jsxs25(
2581
3205
  "div",
2582
3206
  {
2583
3207
  className: cn(
@@ -2585,11 +3209,11 @@ var DangerZoneAction = ({
2585
3209
  className
2586
3210
  ),
2587
3211
  children: [
2588
- /* @__PURE__ */ jsxs23("div", { className: "min-w-0", children: [
2589
- /* @__PURE__ */ jsx28("p", { className: "text-sm font-medium text-foreground", children: title }),
2590
- description ? /* @__PURE__ */ jsx28("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
3212
+ /* @__PURE__ */ jsxs25("div", { className: "min-w-0", children: [
3213
+ /* @__PURE__ */ jsx31("p", { className: "text-sm font-medium text-foreground", children: title }),
3214
+ description ? /* @__PURE__ */ jsx31("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
2591
3215
  ] }),
2592
- /* @__PURE__ */ jsx28("div", { className: "shrink-0", children: action })
3216
+ /* @__PURE__ */ jsx31("div", { className: "shrink-0", children: action })
2593
3217
  ]
2594
3218
  }
2595
3219
  );
@@ -2598,7 +3222,7 @@ var DangerZone = ({
2598
3222
  description,
2599
3223
  children,
2600
3224
  className
2601
- }) => /* @__PURE__ */ jsxs23(
3225
+ }) => /* @__PURE__ */ jsxs25(
2602
3226
  "section",
2603
3227
  {
2604
3228
  className: cn(
@@ -2606,18 +3230,18 @@ var DangerZone = ({
2606
3230
  className
2607
3231
  ),
2608
3232
  children: [
2609
- (title || description) && /* @__PURE__ */ jsxs23("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
2610
- title ? /* @__PURE__ */ jsx28("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
2611
- description ? /* @__PURE__ */ jsx28("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
3233
+ (title || description) && /* @__PURE__ */ jsxs25("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
3234
+ title ? /* @__PURE__ */ jsx31("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
3235
+ description ? /* @__PURE__ */ jsx31("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
2612
3236
  ] }),
2613
- /* @__PURE__ */ jsx28("div", { className: "divide-y divide-border bg-card", children })
3237
+ /* @__PURE__ */ jsx31("div", { className: "divide-y divide-border bg-card", children })
2614
3238
  ]
2615
3239
  }
2616
3240
  );
2617
3241
 
2618
3242
  // src/app/integrations/IntegrationCard.tsx
2619
- import { useId as useId2 } from "react";
2620
- import { Fragment as Fragment4, jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
3243
+ import { useId as useId3 } from "react";
3244
+ import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
2621
3245
  var INTEGRATION_CATALOG_CARD_HEIGHT_CLASS = "h-[12.25rem] min-h-[12.25rem] max-h-[12.25rem]";
2622
3246
  var statusLabel = {
2623
3247
  available: null,
@@ -2625,14 +3249,14 @@ var statusLabel = {
2625
3249
  disabled: "Disabled",
2626
3250
  locked: "Locked"
2627
3251
  };
2628
- var catalogCardShellClass = cn(
3252
+ var catalogCardShellClass2 = cn(
2629
3253
  "group relative box-border flex flex-col overflow-hidden rounded-2xl px-4 pb-4 pt-4 text-left font-normal",
2630
3254
  INTEGRATION_CATALOG_CARD_HEIGHT_CLASS,
2631
3255
  TIMBAL_V2_ELEVATED_SURFACE,
2632
3256
  "transition-opacity duration-200 ease-out"
2633
3257
  );
2634
- var catalogCardInteractiveClass = cn(
2635
- catalogCardShellClass,
3258
+ var catalogCardInteractiveClass2 = cn(
3259
+ catalogCardShellClass2,
2636
3260
  "cursor-pointer bg-transparent hover:bg-transparent active:bg-transparent",
2637
3261
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
2638
3262
  );
@@ -2655,15 +3279,15 @@ var IntegrationCard = ({
2655
3279
  ariaLabel,
2656
3280
  className
2657
3281
  }) => {
2658
- const titleId = useId2();
3282
+ const titleId = useId3();
2659
3283
  const locked = status === "locked";
2660
3284
  const dimmed = status === "disabled" || locked;
2661
- const body = /* @__PURE__ */ jsxs24("div", { className: "flex h-full min-h-0 flex-col", children: [
2662
- /* @__PURE__ */ jsxs24("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
2663
- logo ? /* @__PURE__ */ jsx29("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
2664
- /* @__PURE__ */ jsx29("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs24("div", { className: "flex items-start justify-between gap-2", children: [
2665
- /* @__PURE__ */ jsxs24("div", { className: "min-w-0", children: [
2666
- /* @__PURE__ */ jsx29(
3285
+ const body = /* @__PURE__ */ jsxs26("div", { className: "flex h-full min-h-0 flex-col", children: [
3286
+ /* @__PURE__ */ jsxs26("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
3287
+ logo ? /* @__PURE__ */ jsx32("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
3288
+ /* @__PURE__ */ jsx32("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs26("div", { className: "flex items-start justify-between gap-2", children: [
3289
+ /* @__PURE__ */ jsxs26("div", { className: "min-w-0", children: [
3290
+ /* @__PURE__ */ jsx32(
2667
3291
  "h4",
2668
3292
  {
2669
3293
  id: onClick && !action ? void 0 : titleId,
@@ -2671,12 +3295,12 @@ var IntegrationCard = ({
2671
3295
  children: name
2672
3296
  }
2673
3297
  ),
2674
- statusLabel[status] ? /* @__PURE__ */ jsx29("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
3298
+ statusLabel[status] ? /* @__PURE__ */ jsx32("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
2675
3299
  ] }),
2676
- badge ? /* @__PURE__ */ jsx29("span", { className: "shrink-0", children: badge }) : null
3300
+ badge ? /* @__PURE__ */ jsx32("span", { className: "shrink-0", children: badge }) : null
2677
3301
  ] }) })
2678
3302
  ] }),
2679
- description ? /* @__PURE__ */ jsx29(
3303
+ description ? /* @__PURE__ */ jsx32(
2680
3304
  "p",
2681
3305
  {
2682
3306
  className: cn(
@@ -2686,19 +3310,19 @@ var IntegrationCard = ({
2686
3310
  children: description
2687
3311
  }
2688
3312
  ) : null,
2689
- action ? /* @__PURE__ */ jsxs24(Fragment4, { children: [
2690
- /* @__PURE__ */ jsx29("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
2691
- /* @__PURE__ */ jsx29("div", { className: "relative mt-3 shrink-0", children: action })
3313
+ action ? /* @__PURE__ */ jsxs26(Fragment6, { children: [
3314
+ /* @__PURE__ */ jsx32("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
3315
+ /* @__PURE__ */ jsx32("div", { className: "relative mt-3 shrink-0", children: action })
2692
3316
  ] }) : null
2693
3317
  ] });
2694
3318
  const shellClass3 = cn(
2695
- catalogCardShellClass,
3319
+ catalogCardShellClass2,
2696
3320
  dimmed && catalogCardMutedClass,
2697
3321
  locked && "cursor-default opacity-75",
2698
3322
  className
2699
3323
  );
2700
3324
  if (onClick && !action) {
2701
- return /* @__PURE__ */ jsx29(
3325
+ return /* @__PURE__ */ jsx32(
2702
3326
  "button",
2703
3327
  {
2704
3328
  type: "button",
@@ -2706,7 +3330,7 @@ var IntegrationCard = ({
2706
3330
  disabled: locked,
2707
3331
  "aria-label": ariaLabel,
2708
3332
  className: cn(
2709
- catalogCardInteractiveClass,
3333
+ catalogCardInteractiveClass2,
2710
3334
  dimmed && catalogCardMutedClass,
2711
3335
  locked && "cursor-default opacity-75",
2712
3336
  className
@@ -2715,12 +3339,12 @@ var IntegrationCard = ({
2715
3339
  }
2716
3340
  );
2717
3341
  }
2718
- return /* @__PURE__ */ jsx29("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
3342
+ return /* @__PURE__ */ jsx32("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
2719
3343
  };
2720
3344
 
2721
3345
  // src/app/integrations/IntegrationsEmptyState.tsx
2722
- import { useId as useId3 } from "react";
2723
- import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
3346
+ import { useId as useId4 } from "react";
3347
+ import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
2724
3348
  var IntegrationsEmptyState = ({
2725
3349
  title = "No integrations yet",
2726
3350
  description = "Connect a provider to start syncing data and powering your workforce.",
@@ -2728,8 +3352,8 @@ var IntegrationsEmptyState = ({
2728
3352
  action,
2729
3353
  className
2730
3354
  }) => {
2731
- const titleId = useId3();
2732
- return /* @__PURE__ */ jsxs25(
3355
+ const titleId = useId4();
3356
+ return /* @__PURE__ */ jsxs27(
2733
3357
  "section",
2734
3358
  {
2735
3359
  className: cn(
@@ -2739,7 +3363,7 @@ var IntegrationsEmptyState = ({
2739
3363
  ),
2740
3364
  "aria-labelledby": titleId,
2741
3365
  children: [
2742
- icon ? /* @__PURE__ */ jsx30(
3366
+ icon ? /* @__PURE__ */ jsx33(
2743
3367
  "span",
2744
3368
  {
2745
3369
  className: cn(
@@ -2751,21 +3375,21 @@ var IntegrationsEmptyState = ({
2751
3375
  children: icon
2752
3376
  }
2753
3377
  ) : null,
2754
- /* @__PURE__ */ jsx30("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
2755
- description ? /* @__PURE__ */ jsx30("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
2756
- action ? /* @__PURE__ */ jsx30("div", { className: "mt-1", children: action }) : null
3378
+ /* @__PURE__ */ jsx33("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
3379
+ description ? /* @__PURE__ */ jsx33("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
3380
+ action ? /* @__PURE__ */ jsx33("div", { className: "mt-1", children: action }) : null
2757
3381
  ]
2758
3382
  }
2759
3383
  );
2760
3384
  };
2761
3385
 
2762
3386
  // src/app/integrations/PlanBadge.tsx
2763
- import { jsx as jsx31 } from "react/jsx-runtime";
3387
+ import { jsx as jsx34 } from "react/jsx-runtime";
2764
3388
  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";
2765
- var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx31("span", { className: cn(planBadgeClass, className), children });
3389
+ var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx34("span", { className: cn(planBadgeClass, className), children });
2766
3390
 
2767
3391
  // src/app/integrations/ConnectionRow.tsx
2768
- import { Fragment as Fragment5, jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
3392
+ import { Fragment as Fragment7, jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
2769
3393
  var logoShellClass2 = cn(
2770
3394
  "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg",
2771
3395
  TIMBAL_V2_LOGO_TILE
@@ -2780,14 +3404,14 @@ var ConnectionRow = ({
2780
3404
  ariaLabel,
2781
3405
  className
2782
3406
  }) => {
2783
- const inner = /* @__PURE__ */ jsxs26(Fragment5, { children: [
2784
- logo ? /* @__PURE__ */ jsx32("span", { className: logoShellClass2, children: logo }) : null,
2785
- /* @__PURE__ */ jsxs26("div", { className: "min-w-0 flex-1", children: [
2786
- /* @__PURE__ */ jsx32("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
2787
- meta ? /* @__PURE__ */ jsx32("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
3407
+ const inner = /* @__PURE__ */ jsxs28(Fragment7, { children: [
3408
+ logo ? /* @__PURE__ */ jsx35("span", { className: logoShellClass2, children: logo }) : null,
3409
+ /* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex-1", children: [
3410
+ /* @__PURE__ */ jsx35("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
3411
+ meta ? /* @__PURE__ */ jsx35("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
2788
3412
  ] }),
2789
- badge ? /* @__PURE__ */ jsx32("span", { className: "shrink-0", children: badge }) : null,
2790
- action ? /* @__PURE__ */ jsx32("span", { className: "shrink-0", children: action }) : null
3413
+ badge ? /* @__PURE__ */ jsx35("span", { className: "shrink-0", children: badge }) : null,
3414
+ action ? /* @__PURE__ */ jsx35("span", { className: "shrink-0", children: action }) : null
2791
3415
  ] });
2792
3416
  const rowClass2 = cn(
2793
3417
  "flex w-full items-center gap-3 px-4 py-3 text-left",
@@ -2795,7 +3419,7 @@ var ConnectionRow = ({
2795
3419
  className
2796
3420
  );
2797
3421
  if (onClick) {
2798
- return /* @__PURE__ */ jsx32(
3422
+ return /* @__PURE__ */ jsx35(
2799
3423
  "button",
2800
3424
  {
2801
3425
  type: "button",
@@ -2807,7 +3431,7 @@ var ConnectionRow = ({
2807
3431
  }
2808
3432
  );
2809
3433
  }
2810
- return /* @__PURE__ */ jsx32("div", { role: "listitem", className: rowClass2, children: inner });
3434
+ return /* @__PURE__ */ jsx35("div", { role: "listitem", className: rowClass2, children: inner });
2811
3435
  };
2812
3436
  var connectionRowListClass = cn(
2813
3437
  "overflow-hidden rounded-2xl",
@@ -2815,12 +3439,12 @@ var connectionRowListClass = cn(
2815
3439
  );
2816
3440
 
2817
3441
  // src/app/integrations/ConnectionRowList.tsx
2818
- import { jsx as jsx33 } from "react/jsx-runtime";
3442
+ import { jsx as jsx36 } from "react/jsx-runtime";
2819
3443
  var ConnectionRowList = ({
2820
3444
  children,
2821
3445
  "aria-label": ariaLabel = "Connected integrations",
2822
3446
  className
2823
- }) => /* @__PURE__ */ jsx33(
3447
+ }) => /* @__PURE__ */ jsx36(
2824
3448
  "div",
2825
3449
  {
2826
3450
  role: "list",
@@ -2831,7 +3455,7 @@ var ConnectionRowList = ({
2831
3455
  );
2832
3456
 
2833
3457
  // src/app/navigation/SubNav.tsx
2834
- import { jsx as jsx34 } from "react/jsx-runtime";
3458
+ import { jsx as jsx37 } from "react/jsx-runtime";
2835
3459
  var SubNav = ({
2836
3460
  items,
2837
3461
  activeId,
@@ -2840,7 +3464,7 @@ var SubNav = ({
2840
3464
  "aria-label": ariaLabel = "Section navigation",
2841
3465
  layoutId
2842
3466
  }) => {
2843
- return /* @__PURE__ */ jsx34("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx34(
3467
+ return /* @__PURE__ */ jsx37("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx37(
2844
3468
  PillSegmentedTabs,
2845
3469
  {
2846
3470
  value: activeId,
@@ -2854,13 +3478,13 @@ var SubNav = ({
2854
3478
  };
2855
3479
 
2856
3480
  // src/app/navigation/Breadcrumbs.tsx
2857
- import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
3481
+ import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
2858
3482
  var Breadcrumbs = ({ items, className }) => {
2859
- return /* @__PURE__ */ jsx35("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx35("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
3483
+ return /* @__PURE__ */ jsx38("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx38("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
2860
3484
  const isLast = index === items.length - 1;
2861
- return /* @__PURE__ */ jsxs27("li", { className: "inline-flex items-center gap-1.5", children: [
2862
- index > 0 ? /* @__PURE__ */ jsx35("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
2863
- isLast ? /* @__PURE__ */ jsx35("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx35("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx35(
3485
+ return /* @__PURE__ */ jsxs29("li", { className: "inline-flex items-center gap-1.5", children: [
3486
+ index > 0 ? /* @__PURE__ */ jsx38("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
3487
+ isLast ? /* @__PURE__ */ jsx38("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx38("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx38(
2864
3488
  "button",
2865
3489
  {
2866
3490
  type: "button",
@@ -2874,8 +3498,8 @@ var Breadcrumbs = ({ items, className }) => {
2874
3498
  };
2875
3499
 
2876
3500
  // src/app/forms/Field.tsx
2877
- import { useId as useId4 } from "react";
2878
- import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
3501
+ import { useId as useId5 } from "react";
3502
+ import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
2879
3503
  var Field = ({
2880
3504
  label,
2881
3505
  hint,
@@ -2884,11 +3508,11 @@ var Field = ({
2884
3508
  className,
2885
3509
  htmlFor
2886
3510
  }) => {
2887
- return /* @__PURE__ */ jsxs28("div", { className: cn("aui-app-field", appFieldClass, className), children: [
2888
- /* @__PURE__ */ jsx36("label", { className: appFieldLabelClass, htmlFor, children: label }),
3511
+ return /* @__PURE__ */ jsxs30("div", { className: cn("aui-app-field", appFieldClass, className), children: [
3512
+ /* @__PURE__ */ jsx39("label", { className: appFieldLabelClass, htmlFor, children: label }),
2889
3513
  children,
2890
- hint && !error ? /* @__PURE__ */ jsx36("p", { className: appFieldHintClass, children: hint }) : null,
2891
- error ? /* @__PURE__ */ jsx36("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
3514
+ hint && !error ? /* @__PURE__ */ jsx39("p", { className: appFieldHintClass, children: hint }) : null,
3515
+ error ? /* @__PURE__ */ jsx39("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
2892
3516
  ] });
2893
3517
  };
2894
3518
  var FieldInput = ({
@@ -2900,9 +3524,9 @@ var FieldInput = ({
2900
3524
  id,
2901
3525
  ...inputProps
2902
3526
  }) => {
2903
- const autoId = useId4();
3527
+ const autoId = useId5();
2904
3528
  const inputId = id ?? inputProps.name ?? autoId;
2905
- return /* @__PURE__ */ jsx36(
3529
+ return /* @__PURE__ */ jsx39(
2906
3530
  Field,
2907
3531
  {
2908
3532
  label,
@@ -2910,7 +3534,7 @@ var FieldInput = ({
2910
3534
  error,
2911
3535
  htmlFor: inputId,
2912
3536
  className: fieldClassName,
2913
- children: /* @__PURE__ */ jsx36(
3537
+ children: /* @__PURE__ */ jsx39(
2914
3538
  "input",
2915
3539
  {
2916
3540
  id: inputId,
@@ -2924,8 +3548,8 @@ var FieldInput = ({
2924
3548
  };
2925
3549
 
2926
3550
  // src/app/forms/FieldTextarea.tsx
2927
- import { useId as useId5 } from "react";
2928
- import { jsx as jsx37 } from "react/jsx-runtime";
3551
+ import { useId as useId6 } from "react";
3552
+ import { jsx as jsx40 } from "react/jsx-runtime";
2929
3553
  var textareaClass = cn(
2930
3554
  appInputClass,
2931
3555
  "min-h-[5.5rem] resize-y py-2.5 leading-relaxed"
@@ -2939,9 +3563,9 @@ var FieldTextarea = ({
2939
3563
  id,
2940
3564
  ...props
2941
3565
  }) => {
2942
- const autoId = useId5();
3566
+ const autoId = useId6();
2943
3567
  const textareaId = id ?? props.name ?? autoId;
2944
- return /* @__PURE__ */ jsx37(
3568
+ return /* @__PURE__ */ jsx40(
2945
3569
  Field,
2946
3570
  {
2947
3571
  label,
@@ -2949,7 +3573,7 @@ var FieldTextarea = ({
2949
3573
  error,
2950
3574
  htmlFor: textareaId,
2951
3575
  className: fieldClassName,
2952
- children: /* @__PURE__ */ jsx37(
3576
+ children: /* @__PURE__ */ jsx40(
2953
3577
  "textarea",
2954
3578
  {
2955
3579
  id: textareaId,
@@ -2963,9 +3587,9 @@ var FieldTextarea = ({
2963
3587
  };
2964
3588
 
2965
3589
  // src/app/forms/FieldSelect.tsx
2966
- import { useId as useId6 } from "react";
3590
+ import { useId as useId7 } from "react";
2967
3591
  import { ChevronDownIcon } from "lucide-react";
2968
- import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
3592
+ import { jsx as jsx41, jsxs as jsxs31 } from "react/jsx-runtime";
2969
3593
  var selectWrapClass = "relative";
2970
3594
  var selectClass = cn(
2971
3595
  appInputClass,
@@ -2981,9 +3605,9 @@ var FieldSelect = ({
2981
3605
  id,
2982
3606
  ...props
2983
3607
  }) => {
2984
- const autoId = useId6();
3608
+ const autoId = useId7();
2985
3609
  const selectId = id ?? props.name ?? autoId;
2986
- return /* @__PURE__ */ jsx38(
3610
+ return /* @__PURE__ */ jsx41(
2987
3611
  Field,
2988
3612
  {
2989
3613
  label,
@@ -2991,8 +3615,8 @@ var FieldSelect = ({
2991
3615
  error,
2992
3616
  htmlFor: selectId,
2993
3617
  className: fieldClassName,
2994
- children: /* @__PURE__ */ jsxs29("div", { className: selectWrapClass, children: [
2995
- /* @__PURE__ */ jsx38(
3618
+ children: /* @__PURE__ */ jsxs31("div", { className: selectWrapClass, children: [
3619
+ /* @__PURE__ */ jsx41(
2996
3620
  "select",
2997
3621
  {
2998
3622
  id: selectId,
@@ -3002,7 +3626,7 @@ var FieldSelect = ({
3002
3626
  children
3003
3627
  }
3004
3628
  ),
3005
- /* @__PURE__ */ jsx38(
3629
+ /* @__PURE__ */ jsx41(
3006
3630
  ChevronDownIcon,
3007
3631
  {
3008
3632
  className: "pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground",
@@ -3015,8 +3639,8 @@ var FieldSelect = ({
3015
3639
  };
3016
3640
 
3017
3641
  // src/app/forms/FieldSwitch.tsx
3018
- import { useId as useId7 } from "react";
3019
- import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
3642
+ import { useId as useId8 } from "react";
3643
+ import { jsx as jsx42, jsxs as jsxs32 } from "react/jsx-runtime";
3020
3644
  var trackClass = cn(
3021
3645
  "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-[background,box-shadow,border-color] duration-200",
3022
3646
  "peer-focus-visible:ring-2 peer-focus-visible:ring-foreground/10",
@@ -3036,9 +3660,9 @@ var FieldSwitch = ({
3036
3660
  id,
3037
3661
  ...props
3038
3662
  }) => {
3039
- const autoId = useId7();
3663
+ const autoId = useId8();
3040
3664
  const inputId = id ?? props.name ?? autoId;
3041
- return /* @__PURE__ */ jsxs30(
3665
+ return /* @__PURE__ */ jsxs32(
3042
3666
  "label",
3043
3667
  {
3044
3668
  className: cn(
@@ -3047,8 +3671,8 @@ var FieldSwitch = ({
3047
3671
  ),
3048
3672
  htmlFor: inputId,
3049
3673
  children: [
3050
- /* @__PURE__ */ jsxs30("span", { className: "relative mt-0.5", children: [
3051
- /* @__PURE__ */ jsx39(
3674
+ /* @__PURE__ */ jsxs32("span", { className: "relative mt-0.5", children: [
3675
+ /* @__PURE__ */ jsx42(
3052
3676
  "input",
3053
3677
  {
3054
3678
  id: inputId,
@@ -3058,11 +3682,11 @@ var FieldSwitch = ({
3058
3682
  ...props
3059
3683
  }
3060
3684
  ),
3061
- /* @__PURE__ */ jsx39("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx39("span", { className: thumbClass }) })
3685
+ /* @__PURE__ */ jsx42("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx42("span", { className: thumbClass }) })
3062
3686
  ] }),
3063
- /* @__PURE__ */ jsxs30("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
3064
- /* @__PURE__ */ jsx39("span", { className: "text-sm font-medium text-foreground", children: label }),
3065
- description ? /* @__PURE__ */ jsx39("span", { className: "text-xs text-muted-foreground", children: description }) : null
3687
+ /* @__PURE__ */ jsxs32("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
3688
+ /* @__PURE__ */ jsx42("span", { className: "text-sm font-medium text-foreground", children: label }),
3689
+ description ? /* @__PURE__ */ jsx42("span", { className: "text-xs text-muted-foreground", children: description }) : null
3066
3690
  ] })
3067
3691
  ]
3068
3692
  }
@@ -3071,13 +3695,13 @@ var FieldSwitch = ({
3071
3695
 
3072
3696
  // src/app/forms/SearchInput.tsx
3073
3697
  import { SearchIcon } from "lucide-react";
3074
- import { jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
3698
+ import { jsx as jsx43, jsxs as jsxs33 } from "react/jsx-runtime";
3075
3699
  var SearchInput = ({
3076
3700
  className,
3077
3701
  placeholder = "Search\u2026",
3078
3702
  ...props
3079
3703
  }) => {
3080
- return /* @__PURE__ */ jsxs31(
3704
+ return /* @__PURE__ */ jsxs33(
3081
3705
  "label",
3082
3706
  {
3083
3707
  className: cn(
@@ -3086,8 +3710,8 @@ var SearchInput = ({
3086
3710
  className
3087
3711
  ),
3088
3712
  children: [
3089
- /* @__PURE__ */ jsx40(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3090
- /* @__PURE__ */ jsx40(
3713
+ /* @__PURE__ */ jsx43(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3714
+ /* @__PURE__ */ jsx43(
3091
3715
  "input",
3092
3716
  {
3093
3717
  type: "search",
@@ -3102,26 +3726,26 @@ var SearchInput = ({
3102
3726
  };
3103
3727
 
3104
3728
  // src/app/forms/FormSection.tsx
3105
- import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
3729
+ import { jsx as jsx44, jsxs as jsxs34 } from "react/jsx-runtime";
3106
3730
  var FormSection = ({ title, children, className }) => {
3107
3731
  const density = useAppDensity();
3108
3732
  const sectionClass = useAppDensityClass("section");
3109
- return /* @__PURE__ */ jsxs32(
3733
+ return /* @__PURE__ */ jsxs34(
3110
3734
  "fieldset",
3111
3735
  {
3112
3736
  className: cn("aui-app-form-section", sectionClass, "border-0 p-0", className),
3113
3737
  children: [
3114
- title ? /* @__PURE__ */ jsx41("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
3115
- /* @__PURE__ */ jsx41("div", { className: cn("flex flex-col", density === "compact" ? "gap-2" : "gap-4"), children })
3738
+ title ? /* @__PURE__ */ jsx44("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
3739
+ /* @__PURE__ */ jsx44("div", { className: cn("flex flex-col", density === "compact" ? "gap-2" : "gap-4"), children })
3116
3740
  ]
3117
3741
  }
3118
3742
  );
3119
3743
  };
3120
3744
 
3121
3745
  // src/app/data/FilterBar.tsx
3122
- import { jsx as jsx42 } from "react/jsx-runtime";
3746
+ import { jsx as jsx45 } from "react/jsx-runtime";
3123
3747
  var FilterBar = ({ children, className }) => {
3124
- return /* @__PURE__ */ jsx42(
3748
+ return /* @__PURE__ */ jsx45(
3125
3749
  "div",
3126
3750
  {
3127
3751
  className: cn("aui-app-filter-bar", appFilterBarClass, className),
@@ -3133,41 +3757,539 @@ var FilterBar = ({ children, className }) => {
3133
3757
  };
3134
3758
 
3135
3759
  // src/app/data/FilterField.tsx
3136
- import { jsx as jsx43, jsxs as jsxs33 } from "react/jsx-runtime";
3760
+ import { jsx as jsx46, jsxs as jsxs35 } from "react/jsx-runtime";
3137
3761
  var FilterField = ({
3138
3762
  label,
3139
3763
  children,
3140
3764
  className
3141
3765
  }) => {
3142
- return /* @__PURE__ */ jsxs33("div", { className: cn("aui-app-filter-field", appFieldClass, className), children: [
3143
- label ? /* @__PURE__ */ jsx43("span", { className: appFieldLabelClass, children: label }) : null,
3766
+ return /* @__PURE__ */ jsxs35("div", { className: cn("aui-app-filter-field", appFieldClass, className), children: [
3767
+ label ? /* @__PURE__ */ jsx46("span", { className: appFieldLabelClass, children: label }) : null,
3144
3768
  children
3145
3769
  ] });
3146
3770
  };
3147
3771
 
3772
+ // src/app/data/FilterDropdown.tsx
3773
+ import { useState as useState4, useMemo as useMemo2, useEffect as useEffect3 } from "react";
3774
+ import {
3775
+ CalendarIcon,
3776
+ ChevronDownIcon as ChevronDownIcon2,
3777
+ ChevronRightIcon,
3778
+ CircleDollarSignIcon,
3779
+ ListFilterIcon,
3780
+ SearchIcon as SearchIcon2,
3781
+ TrendingUpIcon,
3782
+ UserIcon,
3783
+ WalletIcon
3784
+ } from "lucide-react";
3785
+ import { jsx as jsx47, jsxs as jsxs36 } from "react/jsx-runtime";
3786
+ var DEFAULT_CONTACTS = [
3787
+ { id: "1", name: "Pedro Olivares Sanchez", email: "polivares@timbal.ai", initials: "PE" },
3788
+ { id: "2", name: "John Doe", email: "john@example.com", initials: "JD" },
3789
+ { id: "3", name: "Sarah Smith", email: "sarah@example.com", initials: "SS" }
3790
+ ];
3791
+ var OPERATORS = [
3792
+ { id: "greater_than", label: "Greater than..." },
3793
+ { id: "less_than", label: "Less than..." },
3794
+ { id: "equals", label: "Equals..." }
3795
+ ];
3796
+ function FilterDropdown({
3797
+ filters,
3798
+ onFiltersChange,
3799
+ initialFilters,
3800
+ contacts = DEFAULT_CONTACTS,
3801
+ className
3802
+ }) {
3803
+ const [isOpen, setIsOpen] = useState4(false);
3804
+ const [activeMenu, setActiveMenu] = useState4("contact");
3805
+ const [isMobile, setIsMobile] = useState4(false);
3806
+ useEffect3(() => {
3807
+ const checkMobile = () => setIsMobile(window.innerWidth < 768);
3808
+ checkMobile();
3809
+ window.addEventListener("resize", checkMobile);
3810
+ return () => window.removeEventListener("resize", checkMobile);
3811
+ }, []);
3812
+ const [selectedContacts, setSelectedContacts] = useState4(
3813
+ filters?.contacts ?? initialFilters?.contacts ?? []
3814
+ );
3815
+ const [walletInput, setWalletInput] = useState4(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
3816
+ const [appliedWallet, setAppliedWallet] = useState4(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
3817
+ const [selectedDatePreset, setSelectedDatePreset] = useState4(
3818
+ filters?.lastInvoiceDate ?? initialFilters?.lastInvoiceDate ?? null
3819
+ );
3820
+ const [customDateFrom, setCustomDateFrom] = useState4(
3821
+ filters?.customDateRange?.from ?? initialFilters?.customDateRange?.from ?? ""
3822
+ );
3823
+ const [customDateTo, setCustomDateTo] = useState4(
3824
+ filters?.customDateRange?.to ?? initialFilters?.customDateRange?.to ?? ""
3825
+ );
3826
+ const [ltvOperator, setLtvOperator] = useState4(
3827
+ filters?.lifetimeValue?.operator ?? initialFilters?.lifetimeValue?.operator ?? "greater_than"
3828
+ );
3829
+ const [ltvValue, setLtvValue] = useState4(filters?.lifetimeValue?.value ?? initialFilters?.lifetimeValue?.value ?? "");
3830
+ const [isLtvOperatorOpen, setLtvOperatorOpen] = useState4(false);
3831
+ const [outstandingOperator, setOutstandingOperator] = useState4(
3832
+ filters?.outstanding?.operator ?? initialFilters?.outstanding?.operator ?? "greater_than"
3833
+ );
3834
+ const [outstandingValue, setOutstandingValue] = useState4(filters?.outstanding?.value ?? initialFilters?.outstanding?.value ?? "");
3835
+ const [isOutstandingOperatorOpen, setOutstandingOperatorOpen] = useState4(false);
3836
+ useEffect3(() => {
3837
+ if (filters) {
3838
+ setSelectedContacts(filters.contacts ?? []);
3839
+ setWalletInput(filters.walletAddress ?? "");
3840
+ setAppliedWallet(filters.walletAddress ?? "");
3841
+ setSelectedDatePreset(filters.lastInvoiceDate ?? null);
3842
+ setCustomDateFrom(filters.customDateRange?.from ?? "");
3843
+ setCustomDateTo(filters.customDateRange?.to ?? "");
3844
+ setLtvOperator(filters.lifetimeValue?.operator ?? "greater_than");
3845
+ setLtvValue(filters.lifetimeValue?.value ?? "");
3846
+ setOutstandingOperator(filters.outstanding?.operator ?? "greater_than");
3847
+ setOutstandingValue(filters.outstanding?.value ?? "");
3848
+ }
3849
+ }, [filters]);
3850
+ const [contactSearch, setContactSearch] = useState4("");
3851
+ const [walletSearch, setWalletSearch] = useState4("");
3852
+ const refDate = useMemo2(() => new Date(2026, 5, 26), []);
3853
+ const presets = useMemo2(() => {
3854
+ const year = refDate.getFullYear();
3855
+ const month = refDate.getMonth();
3856
+ const lastMonthDate = new Date(year, month - 1, 1);
3857
+ const lastMonthLabel = lastMonthDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
3858
+ const thisMonthLabel = refDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
3859
+ const thisQuarter = Math.floor(month / 3) + 1;
3860
+ const thisQuarterLabel = `Q${thisQuarter} ${year}`;
3861
+ const lastQuarter = thisQuarter === 1 ? 4 : thisQuarter - 1;
3862
+ const lastQuarterYear = thisQuarter === 1 ? year - 1 : year;
3863
+ const lastQuarterLabel = `Q${lastQuarter} ${lastQuarterYear}`;
3864
+ const thisYearLabel = `${year}`;
3865
+ const last30 = new Date(refDate);
3866
+ last30.setDate(refDate.getDate() - 30);
3867
+ const formatDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
3868
+ const last30Label = `${formatDate(last30)} - ${formatDate(refDate)}`;
3869
+ const last90 = new Date(refDate);
3870
+ last90.setDate(refDate.getDate() - 90);
3871
+ const last90Label = `${formatDate(last90)} - ${formatDate(refDate)}`;
3872
+ return [
3873
+ { id: "last_month", label: "Last month", date: lastMonthLabel },
3874
+ { id: "this_month", label: "This month", date: thisMonthLabel },
3875
+ { id: "this_quarter", label: "This quarter", date: thisQuarterLabel },
3876
+ { id: "last_quarter", label: "Last quarter", date: lastQuarterLabel },
3877
+ { id: "this_year", label: "This year", date: thisYearLabel },
3878
+ { id: "last_30_days", label: "Last 30 days", date: last30Label },
3879
+ { id: "last_90_days", label: "Last 90 days", date: last90Label },
3880
+ { id: "custom", label: "Custom range", date: "" }
3881
+ ];
3882
+ }, [refDate]);
3883
+ const filteredContacts = useMemo2(() => {
3884
+ if (!contactSearch) return contacts;
3885
+ const query = contactSearch.toLowerCase();
3886
+ return contacts.filter(
3887
+ (c) => c.name.toLowerCase().includes(query) || c.email.toLowerCase().includes(query)
3888
+ );
3889
+ }, [contacts, contactSearch]);
3890
+ const handleContactToggle = (contactName) => {
3891
+ const next = selectedContacts.includes(contactName) ? selectedContacts.filter((name) => name !== contactName) : [...selectedContacts, contactName];
3892
+ setSelectedContacts(next);
3893
+ notifyChanges({ contacts: next });
3894
+ setIsOpen(false);
3895
+ };
3896
+ const handleWalletApply = () => {
3897
+ setAppliedWallet(walletInput);
3898
+ notifyChanges({ walletAddress: walletInput });
3899
+ setIsOpen(false);
3900
+ };
3901
+ const handleWalletClear = () => {
3902
+ setWalletInput("");
3903
+ setAppliedWallet("");
3904
+ notifyChanges({ walletAddress: "" });
3905
+ setIsOpen(false);
3906
+ };
3907
+ const handleDatePresetSelect = (presetId) => {
3908
+ setSelectedDatePreset(presetId);
3909
+ if (presetId !== "custom") {
3910
+ notifyChanges({ lastInvoiceDate: presetId, customDateRange: void 0 });
3911
+ setIsOpen(false);
3912
+ }
3913
+ };
3914
+ const handleCustomDateApply = () => {
3915
+ notifyChanges({
3916
+ lastInvoiceDate: "custom",
3917
+ customDateRange: { from: customDateFrom, to: customDateTo }
3918
+ });
3919
+ setIsOpen(false);
3920
+ };
3921
+ const handleLtvApply = () => {
3922
+ notifyChanges({
3923
+ lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null
3924
+ });
3925
+ setIsOpen(false);
3926
+ };
3927
+ const handleLtvClear = () => {
3928
+ setLtvValue("");
3929
+ notifyChanges({ lifetimeValue: null });
3930
+ setIsOpen(false);
3931
+ };
3932
+ const handleOutstandingApply = () => {
3933
+ notifyChanges({
3934
+ outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null
3935
+ });
3936
+ setIsOpen(false);
3937
+ };
3938
+ const handleOutstandingClear = () => {
3939
+ setOutstandingValue("");
3940
+ notifyChanges({ outstanding: null });
3941
+ setIsOpen(false);
3942
+ };
3943
+ const notifyChanges = (overrides) => {
3944
+ const current = {
3945
+ contacts: selectedContacts,
3946
+ walletAddress: appliedWallet,
3947
+ lastInvoiceDate: selectedDatePreset,
3948
+ customDateRange: customDateFrom || customDateTo ? { from: customDateFrom, to: customDateTo } : void 0,
3949
+ lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null,
3950
+ outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null,
3951
+ ...overrides
3952
+ };
3953
+ onFiltersChange?.(current);
3954
+ };
3955
+ const menuItems = [
3956
+ { id: "contact", label: "Contact", icon: /* @__PURE__ */ jsx47(UserIcon, { className: "size-4" }) },
3957
+ { id: "wallet", label: "Wallet address", icon: /* @__PURE__ */ jsx47(WalletIcon, { className: "size-4" }) },
3958
+ { id: "date", label: "Last invoice date", icon: /* @__PURE__ */ jsx47(CalendarIcon, { className: "size-4" }) },
3959
+ { id: "ltv", label: "Lifetime value", icon: /* @__PURE__ */ jsx47(TrendingUpIcon, { className: "size-4" }) },
3960
+ { id: "outstanding", label: "Outstanding", icon: /* @__PURE__ */ jsx47(CircleDollarSignIcon, { className: "size-4" }) }
3961
+ ];
3962
+ const activeIdx = menuItems.findIndex((item) => item.id === activeMenu);
3963
+ return /* @__PURE__ */ jsx47("div", { className: cn("inline-block", className), children: /* @__PURE__ */ jsxs36(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
3964
+ /* @__PURE__ */ jsx47(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx47(
3965
+ Button,
3966
+ {
3967
+ variant: "outline",
3968
+ size: "sm",
3969
+ shape: "pill",
3970
+ className: "border-dashed font-medium text-muted-foreground hover:text-foreground",
3971
+ iconLeading: /* @__PURE__ */ jsx47(ListFilterIcon, { className: "size-4" }),
3972
+ children: "Filter"
3973
+ }
3974
+ ) }),
3975
+ /* @__PURE__ */ jsx47(
3976
+ PopoverContent,
3977
+ {
3978
+ variant: "list",
3979
+ align: "start",
3980
+ className: "overflow-visible border-none bg-transparent p-0 shadow-none max-w-[calc(100vw-32px)] md:max-w-none",
3981
+ children: /* @__PURE__ */ jsxs36("div", { className: "relative flex flex-col md:flex-row items-stretch md:items-start w-[calc(100vw-32px)] max-w-[340px] md:w-auto md:max-w-none", children: [
3982
+ /* @__PURE__ */ jsx47("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: menuItems.map((item) => {
3983
+ const isActive = activeMenu === item.id;
3984
+ return /* @__PURE__ */ jsxs36(
3985
+ "button",
3986
+ {
3987
+ type: "button",
3988
+ className: cn(
3989
+ "flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
3990
+ isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
3991
+ ),
3992
+ onMouseEnter: () => !isMobile && setActiveMenu(item.id),
3993
+ onClick: () => setActiveMenu(item.id),
3994
+ children: [
3995
+ /* @__PURE__ */ jsxs36("span", { className: "flex items-center gap-2", children: [
3996
+ item.icon,
3997
+ /* @__PURE__ */ jsx47("span", { children: item.label })
3998
+ ] }),
3999
+ /* @__PURE__ */ jsx47(ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
4000
+ ]
4001
+ },
4002
+ item.id
4003
+ );
4004
+ }) }),
4005
+ activeMenu && /* @__PURE__ */ jsxs36(
4006
+ "div",
4007
+ {
4008
+ className: "relative left-0 mt-2 w-full md:absolute md:left-[calc(100%+6px)] md:w-80 rounded-xl border border-border bg-popover p-3 shadow-lg transition-all duration-150 md:mt-0",
4009
+ style: isMobile ? {} : { top: `${activeIdx * 36 + 6}px` },
4010
+ children: [
4011
+ activeMenu === "contact" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
4012
+ /* @__PURE__ */ jsxs36("div", { className: "relative flex items-center", children: [
4013
+ /* @__PURE__ */ jsx47(SearchIcon2, { className: "absolute left-2.5 size-4 text-muted-foreground/60" }),
4014
+ /* @__PURE__ */ jsx47(
4015
+ "input",
4016
+ {
4017
+ type: "text",
4018
+ placeholder: "Search by name or email...",
4019
+ value: contactSearch,
4020
+ onChange: (e) => setContactSearch(e.target.value),
4021
+ className: "w-full rounded-lg border border-border bg-background py-1.5 pl-8 pr-3 text-sm outline-none placeholder:text-muted-foreground/60 focus:border-border"
4022
+ }
4023
+ )
4024
+ ] }),
4025
+ /* @__PURE__ */ jsx47("div", { className: "max-h-48 overflow-y-auto flex flex-col gap-1 pr-1", children: filteredContacts.length === 0 ? /* @__PURE__ */ jsx47("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No contacts found" }) : filteredContacts.map((contact) => {
4026
+ const isChecked = selectedContacts.includes(contact.name);
4027
+ return /* @__PURE__ */ jsxs36(
4028
+ "label",
4029
+ {
4030
+ className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 hover:bg-muted/50 transition-colors",
4031
+ children: [
4032
+ /* @__PURE__ */ jsx47(
4033
+ Checkbox,
4034
+ {
4035
+ checked: isChecked,
4036
+ onCheckedChange: () => handleContactToggle(contact.name)
4037
+ }
4038
+ ),
4039
+ /* @__PURE__ */ jsx47(Avatar, { variant: "secondary", children: /* @__PURE__ */ jsx47(AvatarFallback, { children: contact.initials }) }),
4040
+ /* @__PURE__ */ jsx47("span", { className: "text-sm font-medium text-foreground", children: contact.name })
4041
+ ]
4042
+ },
4043
+ contact.id
4044
+ );
4045
+ }) })
4046
+ ] }),
4047
+ activeMenu === "wallet" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
4048
+ /* @__PURE__ */ jsx47("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx47(
4049
+ "input",
4050
+ {
4051
+ type: "text",
4052
+ placeholder: "Search by wallet...",
4053
+ value: walletInput,
4054
+ onChange: (e) => setWalletInput(e.target.value),
4055
+ className: "w-full rounded-lg border border-border bg-background px-3 py-1.5 text-sm outline-none placeholder:text-muted-foreground/60"
4056
+ }
4057
+ ) }),
4058
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
4059
+ /* @__PURE__ */ jsx47(
4060
+ Button,
4061
+ {
4062
+ variant: "ghost",
4063
+ size: "sm",
4064
+ onClick: handleWalletClear,
4065
+ className: "text-muted-foreground hover:text-foreground h-8 px-3",
4066
+ children: "Clear"
4067
+ }
4068
+ ),
4069
+ /* @__PURE__ */ jsx47(
4070
+ Button,
4071
+ {
4072
+ color: "primary",
4073
+ size: "sm",
4074
+ onClick: handleWalletApply,
4075
+ className: "h-8 px-3",
4076
+ children: "Apply"
4077
+ }
4078
+ )
4079
+ ] })
4080
+ ] }),
4081
+ activeMenu === "date" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-1", children: [
4082
+ presets.map((preset) => {
4083
+ const isSelected = selectedDatePreset === preset.id;
4084
+ return /* @__PURE__ */ jsxs36(
4085
+ "button",
4086
+ {
4087
+ type: "button",
4088
+ onClick: () => handleDatePresetSelect(preset.id),
4089
+ className: cn(
4090
+ "flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-sm text-left transition-colors outline-none",
4091
+ isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
4092
+ ),
4093
+ children: [
4094
+ /* @__PURE__ */ jsx47("span", { children: preset.label }),
4095
+ preset.date && /* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground/70", children: preset.date })
4096
+ ]
4097
+ },
4098
+ preset.id
4099
+ );
4100
+ }),
4101
+ selectedDatePreset === "custom" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2 mt-2 pt-2 border-t border-border/40", children: [
4102
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
4103
+ /* @__PURE__ */ jsx47(
4104
+ "input",
4105
+ {
4106
+ type: "date",
4107
+ value: customDateFrom,
4108
+ onChange: (e) => setCustomDateFrom(e.target.value),
4109
+ className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
4110
+ }
4111
+ ),
4112
+ /* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground", children: "to" }),
4113
+ /* @__PURE__ */ jsx47(
4114
+ "input",
4115
+ {
4116
+ type: "date",
4117
+ value: customDateTo,
4118
+ onChange: (e) => setCustomDateTo(e.target.value),
4119
+ className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
4120
+ }
4121
+ )
4122
+ ] }),
4123
+ /* @__PURE__ */ jsx47("div", { className: "flex justify-end gap-2", children: /* @__PURE__ */ jsx47(
4124
+ Button,
4125
+ {
4126
+ color: "primary",
4127
+ size: "sm",
4128
+ onClick: handleCustomDateApply,
4129
+ className: "h-7 text-xs px-2.5",
4130
+ children: "Apply"
4131
+ }
4132
+ ) })
4133
+ ] })
4134
+ ] }),
4135
+ activeMenu === "ltv" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
4136
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
4137
+ /* @__PURE__ */ jsxs36("div", { className: "relative shrink-0", children: [
4138
+ /* @__PURE__ */ jsxs36(
4139
+ "button",
4140
+ {
4141
+ type: "button",
4142
+ onClick: () => setLtvOperatorOpen(!isLtvOperatorOpen),
4143
+ className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
4144
+ children: [
4145
+ /* @__PURE__ */ jsx47("span", { children: OPERATORS.find((op) => op.id === ltvOperator)?.label.replace("...", "") }),
4146
+ /* @__PURE__ */ jsx47(ChevronDownIcon2, { className: "size-3" })
4147
+ ]
4148
+ }
4149
+ ),
4150
+ isLtvOperatorOpen && /* @__PURE__ */ jsx47("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ jsx47(
4151
+ "button",
4152
+ {
4153
+ type: "button",
4154
+ onClick: () => {
4155
+ setLtvOperator(op.id);
4156
+ setLtvOperatorOpen(false);
4157
+ },
4158
+ className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
4159
+ children: op.label
4160
+ },
4161
+ op.id
4162
+ )) })
4163
+ ] }),
4164
+ /* @__PURE__ */ jsx47(
4165
+ "input",
4166
+ {
4167
+ type: "text",
4168
+ placeholder: "0.00",
4169
+ value: ltvValue,
4170
+ onChange: (e) => setLtvValue(e.target.value),
4171
+ className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
4172
+ }
4173
+ )
4174
+ ] }),
4175
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
4176
+ /* @__PURE__ */ jsx47(
4177
+ Button,
4178
+ {
4179
+ variant: "ghost",
4180
+ size: "sm",
4181
+ onClick: handleLtvClear,
4182
+ className: "text-muted-foreground hover:text-foreground h-8 px-3",
4183
+ children: "Clear"
4184
+ }
4185
+ ),
4186
+ /* @__PURE__ */ jsx47(
4187
+ Button,
4188
+ {
4189
+ color: "primary",
4190
+ size: "sm",
4191
+ onClick: handleLtvApply,
4192
+ className: "h-8 px-3",
4193
+ children: "Apply"
4194
+ }
4195
+ )
4196
+ ] })
4197
+ ] }),
4198
+ activeMenu === "outstanding" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
4199
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
4200
+ /* @__PURE__ */ jsxs36("div", { className: "relative shrink-0", children: [
4201
+ /* @__PURE__ */ jsxs36(
4202
+ "button",
4203
+ {
4204
+ type: "button",
4205
+ onClick: () => setOutstandingOperatorOpen(!isOutstandingOperatorOpen),
4206
+ className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
4207
+ children: [
4208
+ /* @__PURE__ */ jsx47("span", { children: OPERATORS.find((op) => op.id === outstandingOperator)?.label.replace("...", "") }),
4209
+ /* @__PURE__ */ jsx47(ChevronDownIcon2, { className: "size-3" })
4210
+ ]
4211
+ }
4212
+ ),
4213
+ isOutstandingOperatorOpen && /* @__PURE__ */ jsx47("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ jsx47(
4214
+ "button",
4215
+ {
4216
+ type: "button",
4217
+ onClick: () => {
4218
+ setOutstandingOperator(op.id);
4219
+ setOutstandingOperatorOpen(false);
4220
+ },
4221
+ className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
4222
+ children: op.label
4223
+ },
4224
+ op.id
4225
+ )) })
4226
+ ] }),
4227
+ /* @__PURE__ */ jsx47(
4228
+ "input",
4229
+ {
4230
+ type: "text",
4231
+ placeholder: "0.00",
4232
+ value: outstandingValue,
4233
+ onChange: (e) => setOutstandingValue(e.target.value),
4234
+ className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
4235
+ }
4236
+ )
4237
+ ] }),
4238
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
4239
+ /* @__PURE__ */ jsx47(
4240
+ Button,
4241
+ {
4242
+ variant: "ghost",
4243
+ size: "sm",
4244
+ onClick: handleOutstandingClear,
4245
+ className: "text-muted-foreground hover:text-foreground h-8 px-3",
4246
+ children: "Clear"
4247
+ }
4248
+ ),
4249
+ /* @__PURE__ */ jsx47(
4250
+ Button,
4251
+ {
4252
+ color: "primary",
4253
+ size: "sm",
4254
+ onClick: handleOutstandingApply,
4255
+ className: "h-8 px-3",
4256
+ children: "Apply"
4257
+ }
4258
+ )
4259
+ ] })
4260
+ ] })
4261
+ ]
4262
+ }
4263
+ )
4264
+ ] })
4265
+ }
4266
+ )
4267
+ ] }) });
4268
+ }
4269
+
3148
4270
  // src/app/data/DataTable.tsx
3149
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
4271
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState5 } from "react";
3150
4272
  import {
3151
4273
  ArrowDownIcon,
3152
4274
  ArrowUpDownIcon,
3153
4275
  ArrowUpIcon,
3154
4276
  ChevronLeftIcon,
3155
- ChevronRightIcon
4277
+ ChevronRightIcon as ChevronRightIcon2
3156
4278
  } from "lucide-react";
3157
- import { jsx as jsx44, jsxs as jsxs34 } from "react/jsx-runtime";
3158
- var shellClass2 = "overflow-hidden rounded-xl border border-border bg-gradient-to-b from-elevated-from to-elevated-to shadow-card";
3159
- var tableClass = "w-full border-collapse bg-transparent text-sm";
3160
- var headRowClass = "bg-muted/40";
3161
- var headCellClass = "border-b border-border/70 px-4 py-2.5 text-left text-[11px] font-semibold uppercase tracking-[0.04em] text-muted-foreground/90";
3162
- var bodyCellClass = "border-b border-border/40 bg-transparent px-4 py-2.5 text-foreground";
3163
- var rowClass = "bg-transparent transition-colors hover:bg-muted/40 data-[clickable=true]:cursor-pointer data-[selected=true]:bg-primary/[0.06]";
3164
- var footCellClass = "border-t border-border/60 bg-muted/20 px-4 py-2.5 text-xs text-muted-foreground";
4279
+ import { jsx as jsx48, jsxs as jsxs37 } from "react/jsx-runtime";
4280
+ var shellClass2 = "w-full";
4281
+ var tableClass = "w-full border-separate border-spacing-0 bg-transparent text-sm";
4282
+ var headRowClass = "";
4283
+ var headCellClass = "bg-gradient-to-b from-white to-[#F9FAFB] dark:from-[#1F242F] dark:to-[#10121C] border-t border-b border-border px-4 py-2.5 text-left text-xs font-medium text-muted-foreground/90 first:rounded-l-lg first:border-l last:rounded-r-lg last:border-r shadow-skeuomorphic-bordered";
4284
+ var bodyCellClass = "border-b border-border/40 bg-transparent px-4 py-4 text-foreground";
4285
+ var rowClass = "bg-transparent transition-colors hover:bg-muted/20 data-[clickable=true]:cursor-pointer data-[selected=true]:bg-primary/[0.04]";
4286
+ var footCellClass = "border-t border-border/40 bg-transparent px-4 py-3 text-xs text-muted-foreground";
3165
4287
  var footInnerClass = "flex flex-wrap items-center gap-2";
3166
4288
  var emptyCellClass = "bg-transparent px-4 py-10 text-center text-sm text-muted-foreground";
3167
- var sortButtonClass = "group inline-flex min-w-0 items-center gap-1.5 rounded-md -mx-1 px-1 py-0.5 text-left font-semibold text-muted-foreground/90 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
3168
- var stickyHeadClass = "sticky top-0 z-[1] bg-muted/95 shadow-[0_1px_0_0_hsl(var(--border)/0.6)] backdrop-blur-sm";
3169
- var selectCellClass = "w-10 px-4 py-2.5 align-middle";
3170
- var pagerButtonClass = "inline-flex size-7 items-center justify-center rounded-md border border-border bg-gradient-to-b from-elevated-from to-elevated-to text-muted-foreground shadow-card transition-colors hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to hover:text-foreground disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
4289
+ var sortButtonClass = "group inline-flex min-w-0 items-center gap-1.5 rounded-md -mx-1 px-1 py-0.5 text-left font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
4290
+ var stickyHeadClass = "sticky top-0 z-[1] bg-background/95 shadow-[0_1px_0_0_hsl(var(--border)/0.4)] backdrop-blur-sm";
4291
+ var selectCellClass = "w-10 px-4 py-4 align-middle";
4292
+ var pagerButtonClass = "inline-flex size-7 items-center justify-center rounded-md border border-border bg-background text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
3171
4293
  var alignClass = {
3172
4294
  left: "text-left",
3173
4295
  center: "text-center",
@@ -3197,12 +4319,12 @@ function SortIndicator({
3197
4319
  }) {
3198
4320
  const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
3199
4321
  if (!active) {
3200
- return /* @__PURE__ */ jsx44(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
4322
+ return /* @__PURE__ */ jsx48(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
3201
4323
  }
3202
4324
  if (direction === "desc") {
3203
- return /* @__PURE__ */ jsx44(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
4325
+ return /* @__PURE__ */ jsx48(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
3204
4326
  }
3205
- return /* @__PURE__ */ jsx44(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
4327
+ return /* @__PURE__ */ jsx48(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
3206
4328
  }
3207
4329
  function DataTable({
3208
4330
  columns,
@@ -3234,7 +4356,7 @@ function DataTable({
3234
4356
  defaultPageIndex = 0,
3235
4357
  onPageChange
3236
4358
  }) {
3237
- const [uncontrolledSort, setUncontrolledSort] = useState4(
4359
+ const [uncontrolledSort, setUncontrolledSort] = useState5(
3238
4360
  defaultSort
3239
4361
  );
3240
4362
  const isSortControlled = sortProp !== void 0;
@@ -3245,19 +4367,19 @@ function DataTable({
3245
4367
  }
3246
4368
  onSortChange?.(next);
3247
4369
  };
3248
- const [uncontrolledSelected, setUncontrolledSelected] = useState4(
4370
+ const [uncontrolledSelected, setUncontrolledSelected] = useState5(
3249
4371
  defaultSelectedKeys ?? []
3250
4372
  );
3251
4373
  const isSelectionControlled = selectedKeysProp !== void 0;
3252
4374
  const selectedKeys = isSelectionControlled ? selectedKeysProp : uncontrolledSelected;
3253
- const selectedSet = useMemo2(() => new Set(selectedKeys), [selectedKeys]);
4375
+ const selectedSet = useMemo3(() => new Set(selectedKeys), [selectedKeys]);
3254
4376
  const setSelected = (next) => {
3255
4377
  if (!isSelectionControlled) {
3256
4378
  setUncontrolledSelected(next);
3257
4379
  }
3258
4380
  onSelectionChange?.(next);
3259
4381
  };
3260
- const [uncontrolledPage, setUncontrolledPage] = useState4(defaultPageIndex);
4382
+ const [uncontrolledPage, setUncontrolledPage] = useState5(defaultPageIndex);
3261
4383
  const isPageControlled = pageIndexProp !== void 0;
3262
4384
  const rawPageIndex = isPageControlled ? pageIndexProp : uncontrolledPage;
3263
4385
  const setPage = (next) => {
@@ -3266,7 +4388,7 @@ function DataTable({
3266
4388
  }
3267
4389
  onPageChange?.(next);
3268
4390
  };
3269
- const sortedRows = useMemo2(() => {
4391
+ const sortedRows = useMemo3(() => {
3270
4392
  if (!sort) return rows;
3271
4393
  const column = columns.find((col) => col.id === sort.columnId);
3272
4394
  if (!column?.sortable) return rows;
@@ -3285,13 +4407,13 @@ function DataTable({
3285
4407
  const paginated = typeof pageSize === "number" && pageSize > 0;
3286
4408
  const pageCount = paginated ? Math.max(1, Math.ceil(sortedRows.length / pageSize)) : 1;
3287
4409
  const pageIndex = Math.min(Math.max(0, rawPageIndex), pageCount - 1);
3288
- useEffect2(() => {
4410
+ useEffect4(() => {
3289
4411
  if (!paginated || isPageControlled) return;
3290
4412
  if (uncontrolledPage > pageCount - 1) {
3291
4413
  setUncontrolledPage(pageCount - 1);
3292
4414
  }
3293
4415
  }, [paginated, isPageControlled, uncontrolledPage, pageCount]);
3294
- const visibleRows = useMemo2(() => {
4416
+ const visibleRows = useMemo3(() => {
3295
4417
  if (!paginated) return sortedRows;
3296
4418
  const start = pageIndex * pageSize;
3297
4419
  return sortedRows.slice(start, start + pageSize);
@@ -3300,7 +4422,7 @@ function DataTable({
3300
4422
  const headPad = dense ? "px-3 py-2" : void 0;
3301
4423
  const colSpan = columns.length + (selectable ? 1 : 0);
3302
4424
  if (!loading && rows.length === 0 && emptyMode === "replace") {
3303
- return /* @__PURE__ */ jsx44(EmptyState, { title: emptyTitle, description: emptyDescription, className });
4425
+ return /* @__PURE__ */ jsx48(EmptyState, { title: emptyTitle, description: emptyDescription, className });
3304
4426
  }
3305
4427
  const allKeys = sortedRows.map(getRowKey);
3306
4428
  const allSelected = allKeys.length > 0 && allKeys.every((k) => selectedSet.has(k));
@@ -3325,10 +4447,10 @@ function DataTable({
3325
4447
  const hasPager = paginated && !loading && sortedRows.length > 0;
3326
4448
  const hasFoot = (showRowCount || footer || hasPager) && (loading || sortedRows.length > 0);
3327
4449
  const skeletonCount = loadingRows ?? pageSize ?? 5;
3328
- return /* @__PURE__ */ jsx44("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx44("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs34("table", { className: tableClass, children: [
3329
- caption ? /* @__PURE__ */ jsx44("caption", { className: "sr-only", children: caption }) : null,
3330
- /* @__PURE__ */ jsx44("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsxs34("tr", { children: [
3331
- selectable ? /* @__PURE__ */ jsx44("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ jsx44(
4450
+ return /* @__PURE__ */ jsx48("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx48("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs37("table", { className: tableClass, children: [
4451
+ caption ? /* @__PURE__ */ jsx48("caption", { className: "sr-only", children: caption }) : null,
4452
+ /* @__PURE__ */ jsx48("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsxs37("tr", { children: [
4453
+ selectable ? /* @__PURE__ */ jsx48("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ jsx48(
3332
4454
  Checkbox,
3333
4455
  {
3334
4456
  checked: headerCheckedState,
@@ -3340,19 +4462,19 @@ function DataTable({
3340
4462
  columns.map((col) => {
3341
4463
  const isSorted = sort?.columnId === col.id;
3342
4464
  const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
3343
- const headerContent = col.sortable ? /* @__PURE__ */ jsxs34(
4465
+ const headerContent = col.sortable ? /* @__PURE__ */ jsxs37(
3344
4466
  "button",
3345
4467
  {
3346
4468
  type: "button",
3347
4469
  className: sortButtonClass,
3348
4470
  onClick: () => setSort(nextSort(sort, col.id)),
3349
4471
  children: [
3350
- /* @__PURE__ */ jsx44("span", { className: "truncate", children: col.header }),
3351
- /* @__PURE__ */ jsx44(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
4472
+ /* @__PURE__ */ jsx48("span", { className: "truncate", children: col.header }),
4473
+ /* @__PURE__ */ jsx48(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
3352
4474
  ]
3353
4475
  }
3354
4476
  ) : col.header;
3355
- return /* @__PURE__ */ jsx44(
4477
+ return /* @__PURE__ */ jsx48(
3356
4478
  "th",
3357
4479
  {
3358
4480
  scope: "col",
@@ -3369,9 +4491,9 @@ function DataTable({
3369
4491
  );
3370
4492
  })
3371
4493
  ] }) }),
3372
- /* @__PURE__ */ jsx44("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ jsxs34("tr", { className: rowClass, "aria-hidden": true, children: [
3373
- selectable ? /* @__PURE__ */ jsx44("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ jsx44(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
3374
- columns.map((col) => /* @__PURE__ */ jsx44(
4494
+ /* @__PURE__ */ jsx48("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ jsxs37("tr", { className: rowClass, "aria-hidden": true, children: [
4495
+ selectable ? /* @__PURE__ */ jsx48("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ jsx48(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
4496
+ columns.map((col) => /* @__PURE__ */ jsx48(
3375
4497
  "td",
3376
4498
  {
3377
4499
  className: cn(
@@ -3380,17 +4502,17 @@ function DataTable({
3380
4502
  col.align && alignClass[col.align],
3381
4503
  col.className
3382
4504
  ),
3383
- children: /* @__PURE__ */ jsx44(Skeleton, { className: "h-4 w-[60%]" })
4505
+ children: /* @__PURE__ */ jsx48(Skeleton, { className: "h-4 w-[60%]" })
3384
4506
  },
3385
4507
  col.id
3386
4508
  ))
3387
- ] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ jsx44("tr", { children: /* @__PURE__ */ jsx44("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ jsxs34("div", { className: "flex flex-col items-center gap-1", children: [
3388
- /* @__PURE__ */ jsx44("p", { className: "font-medium text-foreground", children: emptyTitle }),
3389
- emptyDescription ? /* @__PURE__ */ jsx44("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
4509
+ ] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ jsx48("tr", { children: /* @__PURE__ */ jsx48("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ jsxs37("div", { className: "flex flex-col items-center gap-1", children: [
4510
+ /* @__PURE__ */ jsx48("p", { className: "font-medium text-foreground", children: emptyTitle }),
4511
+ emptyDescription ? /* @__PURE__ */ jsx48("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
3390
4512
  ] }) }) }) : visibleRows.map((row) => {
3391
4513
  const key = getRowKey(row);
3392
4514
  const isSelected = selectedSet.has(key);
3393
- return /* @__PURE__ */ jsxs34(
4515
+ return /* @__PURE__ */ jsxs37(
3394
4516
  "tr",
3395
4517
  {
3396
4518
  className: rowClass,
@@ -3406,12 +4528,12 @@ function DataTable({
3406
4528
  tabIndex: onRowClick ? 0 : void 0,
3407
4529
  role: onRowClick ? "button" : void 0,
3408
4530
  children: [
3409
- selectable ? /* @__PURE__ */ jsx44(
4531
+ selectable ? /* @__PURE__ */ jsx48(
3410
4532
  "td",
3411
4533
  {
3412
4534
  className: cn(selectCellClass, cellPad),
3413
4535
  onClick: (event) => event.stopPropagation(),
3414
- children: /* @__PURE__ */ jsx44(
4536
+ children: /* @__PURE__ */ jsx48(
3415
4537
  Checkbox,
3416
4538
  {
3417
4539
  checked: isSelected,
@@ -3421,7 +4543,7 @@ function DataTable({
3421
4543
  )
3422
4544
  }
3423
4545
  ) : null,
3424
- columns.map((col) => /* @__PURE__ */ jsx44(
4546
+ columns.map((col) => /* @__PURE__ */ jsx48(
3425
4547
  "td",
3426
4548
  {
3427
4549
  className: cn(
@@ -3431,7 +4553,7 @@ function DataTable({
3431
4553
  col.align && alignClass[col.align],
3432
4554
  col.className
3433
4555
  ),
3434
- children: col.truncate ? /* @__PURE__ */ jsx44("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
4556
+ children: col.truncate ? /* @__PURE__ */ jsx48("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
3435
4557
  },
3436
4558
  col.id
3437
4559
  ))
@@ -3440,7 +4562,7 @@ function DataTable({
3440
4562
  key
3441
4563
  );
3442
4564
  }) }),
3443
- hasFoot ? /* @__PURE__ */ jsx44("tfoot", { children: /* @__PURE__ */ jsx44("tr", { children: /* @__PURE__ */ jsx44("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ jsxs34(
4565
+ hasFoot ? /* @__PURE__ */ jsx48("tfoot", { children: /* @__PURE__ */ jsx48("tr", { children: /* @__PURE__ */ jsx48("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ jsxs37(
3444
4566
  "div",
3445
4567
  {
3446
4568
  className: cn(
@@ -3448,18 +4570,18 @@ function DataTable({
3448
4570
  (showRowCount || footer || hasPager) && "justify-between"
3449
4571
  ),
3450
4572
  children: [
3451
- /* @__PURE__ */ jsxs34("div", { className: footInnerClass, children: [
3452
- showRowCount ? /* @__PURE__ */ jsxs34("span", { children: [
4573
+ /* @__PURE__ */ jsxs37("div", { className: footInnerClass, children: [
4574
+ showRowCount ? /* @__PURE__ */ jsxs37("span", { children: [
3453
4575
  rowCountText,
3454
4576
  selectable && selectedSet.size > 0 ? ` \xB7 ${selectedSet.size} selected` : null
3455
- ] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ jsxs34("span", { children: [
4577
+ ] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ jsxs37("span", { children: [
3456
4578
  selectedSet.size,
3457
4579
  " selected"
3458
4580
  ] }) : null,
3459
4581
  footer
3460
4582
  ] }),
3461
- hasPager ? /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3462
- /* @__PURE__ */ jsxs34("span", { className: "tabular-nums", children: [
4583
+ hasPager ? /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
4584
+ /* @__PURE__ */ jsxs37("span", { className: "tabular-nums", children: [
3463
4585
  pageIndex * pageSize + 1,
3464
4586
  "\u2013",
3465
4587
  Math.min(
@@ -3470,8 +4592,8 @@ function DataTable({
3470
4592
  "of ",
3471
4593
  sortedRows.length
3472
4594
  ] }),
3473
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-1", children: [
3474
- /* @__PURE__ */ jsx44(
4595
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-1", children: [
4596
+ /* @__PURE__ */ jsx48(
3475
4597
  "button",
3476
4598
  {
3477
4599
  type: "button",
@@ -3479,10 +4601,10 @@ function DataTable({
3479
4601
  onClick: () => setPage(pageIndex - 1),
3480
4602
  disabled: pageIndex <= 0,
3481
4603
  "aria-label": "Previous page",
3482
- children: /* @__PURE__ */ jsx44(ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
4604
+ children: /* @__PURE__ */ jsx48(ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
3483
4605
  }
3484
4606
  ),
3485
- /* @__PURE__ */ jsx44(
4607
+ /* @__PURE__ */ jsx48(
3486
4608
  "button",
3487
4609
  {
3488
4610
  type: "button",
@@ -3490,7 +4612,7 @@ function DataTable({
3490
4612
  onClick: () => setPage(pageIndex + 1),
3491
4613
  disabled: pageIndex >= pageCount - 1,
3492
4614
  "aria-label": "Next page",
3493
- children: /* @__PURE__ */ jsx44(ChevronRightIcon, { className: "size-4", "aria-hidden": true })
4615
+ children: /* @__PURE__ */ jsx48(ChevronRightIcon2, { className: "size-4", "aria-hidden": true })
3494
4616
  }
3495
4617
  )
3496
4618
  ] })
@@ -3502,8 +4624,8 @@ function DataTable({
3502
4624
  }
3503
4625
 
3504
4626
  // src/app/data/ChartPanel.tsx
3505
- import { useId as useId8 } from "react";
3506
- import { jsx as jsx45, jsxs as jsxs35 } from "react/jsx-runtime";
4627
+ import { useId as useId9 } from "react";
4628
+ import { jsx as jsx49, jsxs as jsxs38 } from "react/jsx-runtime";
3507
4629
  var ChartPanel = ({
3508
4630
  title,
3509
4631
  description,
@@ -3518,17 +4640,17 @@ var ChartPanel = ({
3518
4640
  const height = heightProp ?? APP_DENSITY_CHART_HEIGHT[density];
3519
4641
  const metricChartPlotRegionClass = useAppDensityClass("metricChartPlotRegion");
3520
4642
  const chartPanelBodyClass = useAppDensityClass("chartPanelBody");
3521
- const titleId = useId8();
4643
+ const titleId = useId9();
3522
4644
  const resolvedTitle = title ?? artifact?.title;
3523
4645
  const hasHeader = Boolean(resolvedTitle || description || actions);
3524
- const body = loading ? /* @__PURE__ */ jsx45(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ jsx45(ChartArtifactView, { artifact, embedded: true, height }) : null);
3525
- return /* @__PURE__ */ jsxs35(
4646
+ const body = loading ? /* @__PURE__ */ jsx49(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ jsx49(ChartArtifactView, { artifact, embedded: true, height }) : null);
4647
+ return /* @__PURE__ */ jsxs38(
3526
4648
  "section",
3527
4649
  {
3528
4650
  className: cn(metricCardShellClass, "aui-app-chart-panel", className),
3529
4651
  "aria-labelledby": resolvedTitle ? titleId : void 0,
3530
4652
  children: [
3531
- /* @__PURE__ */ jsx45(
4653
+ /* @__PURE__ */ jsx49(
3532
4654
  MetricCardHeader,
3533
4655
  {
3534
4656
  title: resolvedTitle,
@@ -3537,14 +4659,14 @@ var ChartPanel = ({
3537
4659
  actions
3538
4660
  }
3539
4661
  ),
3540
- /* @__PURE__ */ jsx45(
4662
+ /* @__PURE__ */ jsx49(
3541
4663
  "div",
3542
4664
  {
3543
4665
  className: cn(
3544
4666
  "relative min-h-0 w-full",
3545
4667
  hasHeader ? metricChartPlotRegionClass : chartPanelBodyClass
3546
4668
  ),
3547
- children: body ?? /* @__PURE__ */ jsx45(
4669
+ children: body ?? /* @__PURE__ */ jsx49(
3548
4670
  "div",
3549
4671
  {
3550
4672
  className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
@@ -3561,10 +4683,11 @@ var ChartPanel = ({
3561
4683
  };
3562
4684
 
3563
4685
  // src/app/data/MetricRow.tsx
3564
- import { useId as useId9, useState as useState5 } from "react";
3565
- import { jsx as jsx46, jsxs as jsxs36 } from "react/jsx-runtime";
4686
+ import { useId as useId10, useState as useState6 } from "react";
4687
+ import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
3566
4688
  var MetricRow = ({
3567
4689
  title,
4690
+ titleTag,
3568
4691
  description,
3569
4692
  actions,
3570
4693
  metrics,
@@ -3576,9 +4699,9 @@ var MetricRow = ({
3576
4699
  className
3577
4700
  }) => {
3578
4701
  const metricTileClass = useAppDensityClass("metricTile");
3579
- const titleId = useId9();
4702
+ const titleId = useId10();
3580
4703
  const selectable = onMetricChange != null || activeMetricId != null;
3581
- const [internalId, setInternalId] = useState5(
4704
+ const [internalId, setInternalId] = useState6(
3582
4705
  defaultActiveMetricId ?? metrics[0]?.id
3583
4706
  );
3584
4707
  const activeId = activeMetricId ?? internalId;
@@ -3586,22 +4709,24 @@ var MetricRow = ({
3586
4709
  if (activeMetricId == null) setInternalId(id);
3587
4710
  onMetricChange?.(id);
3588
4711
  };
3589
- return /* @__PURE__ */ jsxs36(
4712
+ const hasHeader = Boolean(title || titleTag || description || actions);
4713
+ return /* @__PURE__ */ jsxs39(
3590
4714
  "section",
3591
4715
  {
3592
4716
  className: cn(metricCardShellClass, className),
3593
4717
  "aria-labelledby": title ? titleId : void 0,
3594
4718
  children: [
3595
- /* @__PURE__ */ jsx46(
4719
+ /* @__PURE__ */ jsx50(
3596
4720
  MetricCardHeader,
3597
4721
  {
3598
4722
  title,
4723
+ titleTag,
3599
4724
  titleId,
3600
4725
  description,
3601
4726
  actions
3602
4727
  }
3603
4728
  ),
3604
- /* @__PURE__ */ jsx46(
4729
+ /* @__PURE__ */ jsx50(
3605
4730
  "div",
3606
4731
  {
3607
4732
  role: selectable ? "group" : void 0,
@@ -3610,20 +4735,20 @@ var MetricRow = ({
3610
4735
  className: cn(
3611
4736
  metricTilesRowClass,
3612
4737
  metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
3613
- (title || description || actions) && "mt-3"
4738
+ hasHeader && "mt-3.5 border-t border-border/40"
3614
4739
  ),
3615
- children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs36(
4740
+ children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs39(
3616
4741
  "div",
3617
4742
  {
3618
4743
  className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
3619
4744
  "aria-hidden": true,
3620
4745
  children: [
3621
- /* @__PURE__ */ jsx46(Skeleton, { className: "h-3 w-20" }),
3622
- /* @__PURE__ */ jsx46(Skeleton, { className: "h-7 w-24" })
4746
+ /* @__PURE__ */ jsx50(Skeleton, { className: "h-3 w-20" }),
4747
+ /* @__PURE__ */ jsx50(Skeleton, { className: "h-7 w-24" })
3623
4748
  ]
3624
4749
  },
3625
4750
  `skeleton-${index}`
3626
- )) : metrics.map((m, index) => /* @__PURE__ */ jsx46(
4751
+ )) : metrics.map((m, index) => /* @__PURE__ */ jsx50(
3627
4752
  MetricTile,
3628
4753
  {
3629
4754
  label: m.label,
@@ -3631,6 +4756,11 @@ var MetricRow = ({
3631
4756
  unit: m.unit,
3632
4757
  trend: m.trend,
3633
4758
  trendTone: m.trendTone,
4759
+ trendVariant: m.trendVariant,
4760
+ activeTone: m.activeTone,
4761
+ sparklineData: m.sparklineData,
4762
+ sparklineConfig: m.sparklineConfig,
4763
+ sparkline: m.sparkline,
3634
4764
  active: selectable && m.id === activeId,
3635
4765
  showDivider: index < metrics.length - 1,
3636
4766
  onSelect: selectable ? () => select(m.id) : void 0
@@ -3645,10 +4775,11 @@ var MetricRow = ({
3645
4775
  };
3646
4776
 
3647
4777
  // src/app/data/MetricChartCard.tsx
3648
- import { useId as useId10, useState as useState6 } from "react";
3649
- import { jsx as jsx47, jsxs as jsxs37 } from "react/jsx-runtime";
4778
+ import { useId as useId11, useState as useState7 } from "react";
4779
+ import { jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
3650
4780
  var MetricChartCard = ({
3651
4781
  title,
4782
+ titleTag,
3652
4783
  description,
3653
4784
  actions,
3654
4785
  metrics,
@@ -3669,8 +4800,8 @@ var MetricChartCard = ({
3669
4800
  const height = heightProp ?? APP_DENSITY_CHART_HEIGHT[density];
3670
4801
  const metricChartRegionClass = useAppDensityClass("metricChartRegion");
3671
4802
  const metricTileClass = useAppDensityClass("metricTile");
3672
- const titleId = useId10();
3673
- const [internalId, setInternalId] = useState6(
4803
+ const titleId = useId11();
4804
+ const [internalId, setInternalId] = useState7(
3674
4805
  defaultActiveMetricId ?? metrics[0]?.id
3675
4806
  );
3676
4807
  const activeId = activeMetricId ?? internalId;
@@ -3679,24 +4810,25 @@ var MetricChartCard = ({
3679
4810
  if (activeMetricId == null) setInternalId(id);
3680
4811
  onMetricChange?.(id);
3681
4812
  };
3682
- const hasHeader = Boolean(title || description || actions);
4813
+ const hasHeader = Boolean(title || titleTag || description || actions);
3683
4814
  const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
3684
- return /* @__PURE__ */ jsxs37(
4815
+ return /* @__PURE__ */ jsxs40(
3685
4816
  "section",
3686
4817
  {
3687
4818
  className: cn(metricCardShellClass, className),
3688
4819
  "aria-labelledby": title ? titleId : void 0,
3689
4820
  children: [
3690
- /* @__PURE__ */ jsx47(
4821
+ /* @__PURE__ */ jsx51(
3691
4822
  MetricCardHeader,
3692
4823
  {
3693
4824
  title,
3694
- titleId,
4825
+ titleTag,
3695
4826
  description,
3696
- actions
4827
+ actions,
4828
+ titleId
3697
4829
  }
3698
4830
  ),
3699
- /* @__PURE__ */ jsx47(
4831
+ /* @__PURE__ */ jsx51(
3700
4832
  "div",
3701
4833
  {
3702
4834
  role: "group",
@@ -3705,20 +4837,20 @@ var MetricChartCard = ({
3705
4837
  className: cn(
3706
4838
  metricTilesRowClass,
3707
4839
  metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
3708
- hasHeader && "mt-3"
4840
+ hasHeader && "mt-3.5 border-t border-border/40"
3709
4841
  ),
3710
- children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs37(
4842
+ children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs40(
3711
4843
  "div",
3712
4844
  {
3713
4845
  className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
3714
4846
  "aria-hidden": true,
3715
4847
  children: [
3716
- /* @__PURE__ */ jsx47(Skeleton, { className: "h-3 w-20" }),
3717
- /* @__PURE__ */ jsx47(Skeleton, { className: "h-7 w-24" })
4848
+ /* @__PURE__ */ jsx51(Skeleton, { className: "h-3 w-20" }),
4849
+ /* @__PURE__ */ jsx51(Skeleton, { className: "h-7 w-24" })
3718
4850
  ]
3719
4851
  },
3720
4852
  `skeleton-${index}`
3721
- )) : metrics.map((m, index) => /* @__PURE__ */ jsx47(
4853
+ )) : metrics.map((m, index) => /* @__PURE__ */ jsx51(
3722
4854
  MetricTile,
3723
4855
  {
3724
4856
  label: m.label,
@@ -3726,6 +4858,11 @@ var MetricChartCard = ({
3726
4858
  unit: m.unit,
3727
4859
  trend: m.trend,
3728
4860
  trendTone: m.trendTone,
4861
+ trendVariant: m.trendVariant,
4862
+ activeTone: m.activeTone,
4863
+ sparklineData: m.sparklineData,
4864
+ sparklineConfig: m.sparklineConfig,
4865
+ sparkline: m.sparkline,
3729
4866
  active: m.id === active?.id,
3730
4867
  showDivider: index < metrics.length - 1,
3731
4868
  onSelect: () => select(m.id)
@@ -3734,14 +4871,14 @@ var MetricChartCard = ({
3734
4871
  ))
3735
4872
  }
3736
4873
  ),
3737
- /* @__PURE__ */ jsx47("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ jsx47(
4874
+ /* @__PURE__ */ jsx51("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ jsx51(
3738
4875
  Skeleton,
3739
4876
  {
3740
4877
  className: "w-full rounded-lg",
3741
4878
  style: { height },
3742
4879
  "aria-hidden": true
3743
4880
  }
3744
- ) : active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx47(
4881
+ ) : active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx51(
3745
4882
  LineAreaChart,
3746
4883
  {
3747
4884
  data: active.data,
@@ -3761,7 +4898,7 @@ var MetricChartCard = ({
3761
4898
  ariaLabel: chartAriaLabel
3762
4899
  },
3763
4900
  active.id
3764
- ) : /* @__PURE__ */ jsx47(
4901
+ ) : /* @__PURE__ */ jsx51(
3765
4902
  "div",
3766
4903
  {
3767
4904
  className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
@@ -3776,13 +4913,13 @@ var MetricChartCard = ({
3776
4913
  };
3777
4914
 
3778
4915
  // src/hooks/use-live-query.ts
3779
- import { useCallback as useCallback2, useEffect as useEffect3, useRef, useState as useState7 } from "react";
4916
+ import { useCallback as useCallback2, useEffect as useEffect5, useRef, useState as useState8 } from "react";
3780
4917
  function useInterval(callback, delayMs) {
3781
4918
  const saved = useRef(callback);
3782
- useEffect3(() => {
4919
+ useEffect5(() => {
3783
4920
  saved.current = callback;
3784
4921
  }, [callback]);
3785
- useEffect3(() => {
4922
+ useEffect5(() => {
3786
4923
  if (delayMs === null) return;
3787
4924
  const id = setInterval(() => saved.current(), delayMs);
3788
4925
  return () => clearInterval(id);
@@ -3795,19 +4932,19 @@ function useLiveQuery(fetcher, options = {}) {
3795
4932
  immediate = true,
3796
4933
  refetchOnFocus = true
3797
4934
  } = options;
3798
- const [data, setData] = useState7(void 0);
3799
- const [error, setError] = useState7(void 0);
3800
- const [loading, setLoading] = useState7(enabled);
3801
- const [refreshing, setRefreshing] = useState7(false);
3802
- const [lastUpdated, setLastUpdated] = useState7(null);
4935
+ const [data, setData] = useState8(void 0);
4936
+ const [error, setError] = useState8(void 0);
4937
+ const [loading, setLoading] = useState8(enabled);
4938
+ const [refreshing, setRefreshing] = useState8(false);
4939
+ const [lastUpdated, setLastUpdated] = useState8(null);
3803
4940
  const fetcherRef = useRef(fetcher);
3804
- useEffect3(() => {
4941
+ useEffect5(() => {
3805
4942
  fetcherRef.current = fetcher;
3806
4943
  }, [fetcher]);
3807
4944
  const mounted = useRef(true);
3808
4945
  const requestId = useRef(0);
3809
4946
  const hasData = useRef(false);
3810
- useEffect3(() => {
4947
+ useEffect5(() => {
3811
4948
  mounted.current = true;
3812
4949
  return () => {
3813
4950
  mounted.current = false;
@@ -3839,11 +4976,11 @@ function useLiveQuery(fetcher, options = {}) {
3839
4976
  if (!enabled) return;
3840
4977
  run();
3841
4978
  }, [enabled, run]);
3842
- useEffect3(() => {
4979
+ useEffect5(() => {
3843
4980
  if (!enabled) return;
3844
4981
  if (immediate) run();
3845
4982
  }, [enabled, immediate, run]);
3846
- useEffect3(() => {
4983
+ useEffect5(() => {
3847
4984
  if (!enabled || intervalMs === null) return;
3848
4985
  const tick = () => {
3849
4986
  if (refetchOnFocus && typeof document !== "undefined" && document.visibilityState === "hidden") {
@@ -3854,7 +4991,7 @@ function useLiveQuery(fetcher, options = {}) {
3854
4991
  const handle = setInterval(tick, intervalMs);
3855
4992
  return () => clearInterval(handle);
3856
4993
  }, [enabled, intervalMs, refetchOnFocus, run]);
3857
- useEffect3(() => {
4994
+ useEffect5(() => {
3858
4995
  if (!enabled || !refetchOnFocus || typeof document === "undefined") return;
3859
4996
  const onVisible = () => {
3860
4997
  if (document.visibilityState === "visible") run();
@@ -3865,69 +5002,6 @@ function useLiveQuery(fetcher, options = {}) {
3865
5002
  return { data, error, loading, refreshing, lastUpdated, refetch };
3866
5003
  }
3867
5004
 
3868
- // src/charts/sparkline.tsx
3869
- import { useId as useId11 } from "react";
3870
- import { Fragment as Fragment6, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
3871
- var Sparkline = ({
3872
- data,
3873
- dataKey = "value",
3874
- color = "var(--primary, #6366f1)",
3875
- area = true,
3876
- width = 96,
3877
- height = 28,
3878
- strokeWidth = 1.5,
3879
- className,
3880
- ariaLabel = "Trend"
3881
- }) => {
3882
- const uid = useId11();
3883
- const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
3884
- if (values.length === 0) {
3885
- return /* @__PURE__ */ jsx48("span", { className: cn("inline-block", className), style: { width, height } });
3886
- }
3887
- const pad = strokeWidth + 1;
3888
- const min = Math.min(...values);
3889
- const max = Math.max(...values);
3890
- const range = max - min || 1;
3891
- const innerW = width - pad * 2;
3892
- const innerH = height - pad * 2;
3893
- const points = values.map((v, i) => ({
3894
- x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
3895
- y: pad + innerH - (v - min) / range * innerH
3896
- }));
3897
- return /* @__PURE__ */ jsxs38(
3898
- "svg",
3899
- {
3900
- width,
3901
- height,
3902
- viewBox: `0 0 ${width} ${height}`,
3903
- className: cn("block", className),
3904
- role: "img",
3905
- "aria-label": ariaLabel,
3906
- preserveAspectRatio: "none",
3907
- children: [
3908
- area && /* @__PURE__ */ jsxs38(Fragment6, { children: [
3909
- /* @__PURE__ */ jsx48("defs", { children: /* @__PURE__ */ jsxs38("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
3910
- /* @__PURE__ */ jsx48("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
3911
- /* @__PURE__ */ jsx48("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
3912
- ] }) }),
3913
- /* @__PURE__ */ jsx48("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
3914
- ] }),
3915
- /* @__PURE__ */ jsx48(
3916
- "path",
3917
- {
3918
- d: monotoneLinePath(points),
3919
- fill: "none",
3920
- stroke: color,
3921
- strokeWidth,
3922
- strokeLinecap: "round",
3923
- strokeLinejoin: "round"
3924
- }
3925
- )
3926
- ]
3927
- }
3928
- );
3929
- };
3930
-
3931
5005
  export {
3932
5006
  SEMANTIC_COLOR_TOKENS,
3933
5007
  RESERVED_GRADIENT_TOKENS,
@@ -3964,16 +5038,17 @@ export {
3964
5038
  AppDensityProvider,
3965
5039
  useAppDensity,
3966
5040
  useAppDensityClass,
5041
+ Sparkline,
3967
5042
  MetricTile,
3968
5043
  useAppShellChat,
3969
5044
  useAppShellNav,
3970
5045
  AppShell,
3971
- AppShellTopbar,
3972
5046
  AppShellChatTrigger,
3973
5047
  AppShellSidebarTrigger,
3974
5048
  PageHeader,
3975
5049
  Page,
3976
5050
  Section,
5051
+ Stack,
3977
5052
  AppCopilotProvider,
3978
5053
  useAppCopilotContext,
3979
5054
  AppChatPanel,
@@ -3987,6 +5062,8 @@ export {
3987
5062
  DescriptionList,
3988
5063
  ExpandableSection,
3989
5064
  ResourceCard,
5065
+ AlertCard,
5066
+ CatalogCard,
3990
5067
  SettingsSectionHeader,
3991
5068
  SettingsSection,
3992
5069
  FieldRow,
@@ -4011,11 +5088,11 @@ export {
4011
5088
  FormSection,
4012
5089
  FilterBar,
4013
5090
  FilterField,
5091
+ FilterDropdown,
4014
5092
  DataTable,
4015
5093
  ChartPanel,
4016
5094
  MetricRow,
4017
5095
  MetricChartCard,
4018
5096
  useInterval,
4019
- useLiveQuery,
4020
- Sparkline
5097
+ useLiveQuery
4021
5098
  };