@wealthx/shadcn 1.5.37 → 1.5.39

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 (60) hide show
  1. package/.turbo/turbo-build.log +142 -133
  2. package/CHANGELOG.md +12 -0
  3. package/dist/{chunk-LSSIWLYU.mjs → chunk-6XNEHTII.mjs} +1 -1
  4. package/dist/{chunk-ULQ53FRJ.mjs → chunk-7NQKFPXE.mjs} +1 -1
  5. package/dist/{chunk-734FOOJC.mjs → chunk-B5PSUONN.mjs} +25 -58
  6. package/dist/{chunk-DSVKEVX6.mjs → chunk-CZOGJC76.mjs} +1 -1
  7. package/dist/chunk-EFHPSKVF.mjs +192 -0
  8. package/dist/{chunk-JPGL36WQ.mjs → chunk-FL7DEYUA.mjs} +6 -7
  9. package/dist/{chunk-2CHH5QOA.mjs → chunk-FQUT5XD6.mjs} +1 -1
  10. package/dist/chunk-MGIDYXOP.mjs +814 -0
  11. package/dist/{chunk-OG2VM34K.mjs → chunk-MHBQJVHE.mjs} +1 -1
  12. package/dist/{chunk-NB3ZL36B.mjs → chunk-MZI77ZMX.mjs} +17 -2
  13. package/dist/chunk-R7M657QL.mjs +587 -0
  14. package/dist/{chunk-DIH2NZZ3.mjs → chunk-RRROLESJ.mjs} +33 -23
  15. package/dist/components/ui/ai-assistant-drawer.js +269 -121
  16. package/dist/components/ui/ai-assistant-drawer.mjs +2 -1
  17. package/dist/components/ui/ai-conversations/index.js +474 -286
  18. package/dist/components/ui/ai-conversations/index.mjs +2 -1
  19. package/dist/components/ui/chat-input-area.js +429 -0
  20. package/dist/components/ui/chat-input-area.mjs +11 -0
  21. package/dist/components/ui/file-preview-dialog.js +6 -7
  22. package/dist/components/ui/file-preview-dialog.mjs +2 -2
  23. package/dist/components/ui/kanban-column.js +6 -7
  24. package/dist/components/ui/kanban-column.mjs +3 -3
  25. package/dist/components/ui/opportunity-card.js +6 -7
  26. package/dist/components/ui/opportunity-card.mjs +2 -2
  27. package/dist/components/ui/page-top-bar.js +182 -5
  28. package/dist/components/ui/page-top-bar.mjs +3 -1
  29. package/dist/components/ui/pipeline-board.js +6 -7
  30. package/dist/components/ui/pipeline-board.mjs +4 -4
  31. package/dist/components/ui/policy-ai/index.js +1636 -0
  32. package/dist/components/ui/policy-ai/index.mjs +36 -0
  33. package/dist/components/ui/progress.js +6 -7
  34. package/dist/components/ui/progress.mjs +1 -1
  35. package/dist/components/ui/stage-timeline.js +6 -7
  36. package/dist/components/ui/stage-timeline.mjs +2 -2
  37. package/dist/components/ui/support-agent/index.js +1131 -0
  38. package/dist/components/ui/support-agent/index.mjs +27 -0
  39. package/dist/index.js +5609 -4100
  40. package/dist/index.mjs +77 -41
  41. package/dist/styles.css +1 -1
  42. package/package.json +16 -1
  43. package/src/components/index.tsx +54 -0
  44. package/src/components/ui/ai-assistant-drawer.tsx +24 -51
  45. package/src/components/ui/ai-conversations/index.tsx +16 -8
  46. package/src/components/ui/ai-conversations/thread.tsx +38 -27
  47. package/src/components/ui/chat-input-area.tsx +244 -0
  48. package/src/components/ui/page-top-bar.tsx +31 -5
  49. package/src/components/ui/policy-ai/index.tsx +41 -0
  50. package/src/components/ui/policy-ai/policy-ai-panel.tsx +526 -0
  51. package/src/components/ui/policy-ai/policy-ai-primitives.tsx +332 -0
  52. package/src/components/ui/policy-ai/policy-ai-responses.tsx +543 -0
  53. package/src/components/ui/progress.tsx +15 -12
  54. package/src/components/ui/support-agent/index.tsx +25 -0
  55. package/src/components/ui/support-agent/support-agent-fab.tsx +116 -0
  56. package/src/components/ui/support-agent/support-agent-panel.tsx +498 -0
  57. package/src/components/ui/support-agent/support-agent-primitives.tsx +354 -0
  58. package/src/styles/globals.css +1 -0
  59. package/src/styles/styles-css.ts +1 -1
  60. package/tsup.config.ts +3 -0
@@ -0,0 +1,1636 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols)
18
+ for (var prop of __getOwnPropSymbols(b)) {
19
+ if (__propIsEnum.call(b, prop))
20
+ __defNormalProp(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, { get: all[name], enumerable: true });
40
+ };
41
+ var __copyProps = (to, from, except, desc) => {
42
+ if (from && typeof from === "object" || typeof from === "function") {
43
+ for (let key of __getOwnPropNames(from))
44
+ if (!__hasOwnProp.call(to, key) && key !== except)
45
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
46
+ }
47
+ return to;
48
+ };
49
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
50
+ // If the importer is in node compatibility mode or this is not an ESM
51
+ // file that has been converted to a CommonJS file using a Babel-
52
+ // compatible transform (i.e. "__esModule" has not been set), then set
53
+ // "default" to the CommonJS "module.exports" for node compatibility.
54
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
55
+ mod
56
+ ));
57
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
58
+
59
+ // src/components/ui/policy-ai/index.tsx
60
+ var policy_ai_exports = {};
61
+ __export(policy_ai_exports, {
62
+ PolicyAIFAB: () => PolicyAIFAB,
63
+ PolicyAIPanel: () => PolicyAIPanel,
64
+ PolicyCitationPanel: () => PolicyCitationPanel,
65
+ PolicyComparisonTable: () => PolicyComparisonTable,
66
+ PolicyQueryChip: () => PolicyQueryChip,
67
+ PolicyRankedList: () => PolicyRankedList,
68
+ PolicySingleBankAnswer: () => PolicySingleBankAnswer,
69
+ PolicyVerdictBadge: () => PolicyVerdictBadge
70
+ });
71
+ module.exports = __toCommonJS(policy_ai_exports);
72
+
73
+ // src/components/ui/policy-ai/policy-ai-primitives.tsx
74
+ var React2 = __toESM(require("react"));
75
+ var import_lucide_react2 = require("lucide-react");
76
+
77
+ // src/lib/utils.ts
78
+ var import_clsx = require("clsx");
79
+ var import_tailwind_merge = require("tailwind-merge");
80
+ var twMerge = (0, import_tailwind_merge.extendTailwindMerge)({
81
+ extend: {
82
+ classGroups: {
83
+ "font-size": [
84
+ {
85
+ text: [
86
+ "display-large",
87
+ "display-medium",
88
+ "display-small",
89
+ "h1",
90
+ "h2",
91
+ "h3",
92
+ "h4",
93
+ "h5",
94
+ "h6",
95
+ "body-large",
96
+ "body-medium",
97
+ "body-small",
98
+ "label-large",
99
+ "label-medium",
100
+ "label-small",
101
+ "button",
102
+ "button-xs",
103
+ "caption",
104
+ "overline",
105
+ "code"
106
+ ]
107
+ }
108
+ ]
109
+ }
110
+ }
111
+ });
112
+ function cn(...inputs) {
113
+ return twMerge((0, import_clsx.clsx)(inputs));
114
+ }
115
+
116
+ // src/components/ui/badge.tsx
117
+ var import_class_variance_authority = require("class-variance-authority");
118
+
119
+ // src/lib/slot.tsx
120
+ var React = __toESM(require("react"));
121
+ function mergeRefs(...refs) {
122
+ return (value) => {
123
+ for (const ref of refs) {
124
+ if (typeof ref === "function") ref(value);
125
+ else if (ref !== null)
126
+ ref.current = value;
127
+ }
128
+ };
129
+ }
130
+ var Slot = React.forwardRef(
131
+ (_a, forwardedRef) => {
132
+ var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
133
+ const child = React.Children.only(children);
134
+ if (!React.isValidElement(child)) return null;
135
+ const childProps = child.props;
136
+ const merged = __spreadValues({}, props);
137
+ for (const key of Object.keys(childProps)) {
138
+ if (key === "className") {
139
+ merged.className = [props.className, childProps.className].filter(Boolean).join(" ");
140
+ } else if (key === "style") {
141
+ merged.style = __spreadValues(__spreadValues({}, props.style), childProps.style);
142
+ } else if (key.startsWith("on") && typeof childProps[key] === "function") {
143
+ const parentHandler = props[key];
144
+ if (typeof parentHandler === "function") {
145
+ merged[key] = (...args) => {
146
+ childProps[key](...args);
147
+ parentHandler(...args);
148
+ };
149
+ } else {
150
+ merged[key] = childProps[key];
151
+ }
152
+ } else {
153
+ merged[key] = childProps[key];
154
+ }
155
+ }
156
+ const childRef = child.ref;
157
+ merged.ref = forwardedRef ? mergeRefs(forwardedRef, childRef) : childRef;
158
+ return React.cloneElement(
159
+ child,
160
+ merged
161
+ );
162
+ }
163
+ );
164
+ Slot.displayName = "Slot";
165
+
166
+ // src/components/ui/badge.tsx
167
+ var import_jsx_runtime = require("react/jsx-runtime");
168
+ var badgeVariants = (0, import_class_variance_authority.cva)(
169
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2.5 py-0.5 text-caption whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
170
+ {
171
+ variants: {
172
+ variant: {
173
+ default: "border-primary/40 bg-primary/10 text-foreground [a&]:hover:bg-primary/15",
174
+ secondary: "border-border bg-muted text-muted-foreground [a&]:hover:bg-muted/80",
175
+ destructive: "border-destructive/40 bg-destructive/10 text-destructive-text focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/15",
176
+ success: "border-success/40 bg-success/10 text-success-text [a&]:hover:bg-success/15",
177
+ warning: "border-warning/40 bg-warning/10 text-warning-text [a&]:hover:bg-warning/15",
178
+ info: "border-info/40 bg-info/10 text-info-text [a&]:hover:bg-info/15",
179
+ outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
180
+ ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
181
+ link: "text-primary underline-offset-4 [a&]:hover:underline"
182
+ }
183
+ },
184
+ defaultVariants: {
185
+ variant: "default"
186
+ }
187
+ }
188
+ );
189
+ function Badge(_a) {
190
+ var _b = _a, {
191
+ className,
192
+ variant = "default",
193
+ asChild = false
194
+ } = _b, props = __objRest(_b, [
195
+ "className",
196
+ "variant",
197
+ "asChild"
198
+ ]);
199
+ const Comp = asChild ? Slot : "span";
200
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
201
+ Comp,
202
+ __spreadValues({
203
+ className: cn(badgeVariants({ variant }), className),
204
+ "data-slot": "badge",
205
+ "data-variant": variant
206
+ }, props)
207
+ );
208
+ }
209
+
210
+ // src/components/ui/button.tsx
211
+ var import_react = require("react");
212
+ var import_class_variance_authority2 = require("class-variance-authority");
213
+ var import_lucide_react = require("lucide-react");
214
+ var import_jsx_runtime2 = require("react/jsx-runtime");
215
+ var buttonVariants = (0, import_class_variance_authority2.cva)(
216
+ "inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 font-sans text-button whitespace-nowrap transition-all active:scale-[0.98] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
217
+ {
218
+ variants: {
219
+ variant: {
220
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
221
+ secondary: "bg-brand-secondary text-brand-secondary-foreground shadow-xs hover:bg-brand-secondary/80 focus-visible:ring-brand-secondary/30",
222
+ destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
223
+ outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground focus-visible:border-border focus-visible:ring-border/50 dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
224
+ "outline-primary": "border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50",
225
+ "outline-secondary": "border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:border-brand-secondary focus-visible:ring-brand-secondary/30",
226
+ ghost: "hover:bg-accent hover:text-accent-foreground hover:shadow-xs focus-visible:ring-border/50 dark:hover:bg-accent/50",
227
+ link: "text-primary underline-offset-4 hover:underline"
228
+ },
229
+ size: {
230
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
231
+ xs: "h-6 gap-1 px-2 text-button-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
232
+ sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
233
+ lg: "h-10 px-6 has-[>svg]:px-4",
234
+ icon: "size-9",
235
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
236
+ "icon-sm": "size-8",
237
+ "icon-lg": "size-10"
238
+ }
239
+ },
240
+ defaultVariants: {
241
+ variant: "default",
242
+ size: "default"
243
+ }
244
+ }
245
+ );
246
+ var Button = (0, import_react.forwardRef)(function Button2(_a, ref) {
247
+ var _b = _a, {
248
+ className,
249
+ variant,
250
+ size,
251
+ asChild = false,
252
+ loading = false,
253
+ disabled,
254
+ type = "button",
255
+ children
256
+ } = _b, props = __objRest(_b, [
257
+ "className",
258
+ "variant",
259
+ "size",
260
+ "asChild",
261
+ "loading",
262
+ "disabled",
263
+ "type",
264
+ "children"
265
+ ]);
266
+ const Comp = asChild ? Slot : "button";
267
+ const isIconOnly = size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg";
268
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
269
+ Comp,
270
+ __spreadProps(__spreadValues({
271
+ className: cn(buttonVariants({ variant, size, className })),
272
+ "data-size": size,
273
+ "data-slot": "button",
274
+ "data-variant": variant,
275
+ disabled: loading || disabled,
276
+ ref,
277
+ type
278
+ }, props), {
279
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { "aria-hidden": "true", className: "animate-spin" }),
281
+ !isIconOnly && children
282
+ ] }) : children
283
+ })
284
+ );
285
+ });
286
+
287
+ // src/components/ui/policy-ai/policy-ai-primitives.tsx
288
+ var import_jsx_runtime3 = require("react/jsx-runtime");
289
+ var POLICY_TYPE_COLORS = {
290
+ Income: "text-primary",
291
+ Security: "text-warning",
292
+ Serviceability: "text-info",
293
+ "Loan Type": "text-secondary",
294
+ Borrower: "text-success"
295
+ };
296
+ var QUERY_TYPE_LABELS = {
297
+ single_bank: "Single bank",
298
+ cross_bank_comparison: "Cross-bank",
299
+ threshold_filter: "Filter",
300
+ ranking: "Ranking",
301
+ scenario_match: "Scenario",
302
+ general: "General"
303
+ };
304
+ function PolicyQueryChip({ context, className }) {
305
+ const { policyType, categories, queryType, bankName } = context;
306
+ const typeColor = POLICY_TYPE_COLORS[policyType];
307
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
308
+ "div",
309
+ {
310
+ "data-slot": "policy-query-chip",
311
+ className: cn(
312
+ "inline-flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground",
313
+ className
314
+ ),
315
+ children: [
316
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Tag, { className: "size-3 shrink-0", "aria-hidden": "true" }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn("font-medium", typeColor), children: policyType }),
318
+ bankName && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
319
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-border", children: "\xB7" }),
320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-foreground", children: bankName })
321
+ ] }),
322
+ categories.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
323
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-border", children: "\xB7" }),
324
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: categories.join(", ") })
325
+ ] }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { variant: "outline", className: "text-xs px-1.5 py-0 shrink-0", children: QUERY_TYPE_LABELS[queryType] })
327
+ ]
328
+ }
329
+ );
330
+ }
331
+ var VERDICT_CONFIG = {
332
+ yes: { variant: "success", label: "Yes" },
333
+ soft_no: { variant: "warning", label: "Soft No" },
334
+ no: { variant: "destructive", label: "No" },
335
+ unknown: { variant: "secondary", label: "\u2014" }
336
+ };
337
+ function PolicyVerdictBadge({
338
+ verdict,
339
+ className
340
+ }) {
341
+ const { variant, label } = VERDICT_CONFIG[verdict];
342
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
343
+ Badge,
344
+ {
345
+ "data-slot": "policy-verdict-badge",
346
+ variant,
347
+ className: cn("shrink-0", className),
348
+ children: label
349
+ }
350
+ );
351
+ }
352
+ function PolicyCitationPanel({
353
+ citations,
354
+ className
355
+ }) {
356
+ const [open, setOpen] = React2.useState(false);
357
+ if (citations.length === 0) return null;
358
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
359
+ "div",
360
+ {
361
+ "data-slot": "policy-citation-panel",
362
+ className: cn("border-t border-border", className),
363
+ children: [
364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
365
+ Button,
366
+ {
367
+ variant: "ghost",
368
+ size: "sm",
369
+ className: "w-full justify-between px-0 text-xs text-muted-foreground hover:text-foreground hover:bg-transparent gap-1",
370
+ onClick: () => setOpen((v) => !v),
371
+ "aria-expanded": open,
372
+ children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "flex items-center gap-1.5", children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.FileText, { className: "size-3", "aria-hidden": "true" }),
375
+ "View sources (",
376
+ citations.length,
377
+ ")"
378
+ ] }),
379
+ open ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronUp, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronDown, { className: "size-3", "aria-hidden": "true" })
380
+ ]
381
+ }
382
+ ),
383
+ open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "mt-1 flex flex-col gap-2 pb-1", children: citations.map((cite) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "flex gap-2 text-xs", children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "shrink-0 flex items-center justify-center size-4 bg-muted text-muted-foreground font-mono font-semibold text-xs", children: cite.index }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
387
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-foreground", children: cite.bankName }),
388
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: cite.category })
389
+ ] }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-muted-foreground leading-relaxed line-clamp-3", children: cite.excerpt })
391
+ ] })
392
+ ] }, cite.index)) })
393
+ ]
394
+ }
395
+ );
396
+ }
397
+
398
+ // src/components/ui/policy-ai/policy-ai-responses.tsx
399
+ var React5 = __toESM(require("react"));
400
+ var import_lucide_react3 = require("lucide-react");
401
+
402
+ // src/components/ui/input.tsx
403
+ var import_jsx_runtime4 = require("react/jsx-runtime");
404
+ function Input(_a) {
405
+ var _b = _a, { className, type } = _b, props = __objRest(_b, ["className", "type"]);
406
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
407
+ "input",
408
+ __spreadValues({
409
+ className: cn(
410
+ "h-9 w-full min-w-0 border border-input bg-transparent px-3 py-1 text-body-medium font-sans shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-label-medium file:text-foreground placeholder:font-normal placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
411
+ "focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-primary/20",
412
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
413
+ className
414
+ ),
415
+ "data-slot": "input",
416
+ type
417
+ }, props)
418
+ );
419
+ }
420
+
421
+ // src/components/ui/tooltip.tsx
422
+ var import_tooltip = require("@base-ui/react/tooltip");
423
+
424
+ // src/lib/theme-provider.tsx
425
+ var import_react2 = require("react");
426
+ var import_jsx_runtime5 = require("react/jsx-runtime");
427
+ var ThemeVarsContext = (0, import_react2.createContext)({});
428
+ function useThemeVars() {
429
+ return (0, import_react2.useContext)(ThemeVarsContext);
430
+ }
431
+
432
+ // src/components/ui/tooltip.tsx
433
+ var import_jsx_runtime6 = require("react/jsx-runtime");
434
+ function TooltipProvider(_a) {
435
+ var _b = _a, {
436
+ delay = 0
437
+ } = _b, props = __objRest(_b, [
438
+ "delay"
439
+ ]);
440
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
441
+ import_tooltip.Tooltip.Provider,
442
+ __spreadValues({
443
+ "data-slot": "tooltip-provider",
444
+ delay
445
+ }, props)
446
+ );
447
+ }
448
+ function Tooltip(_a) {
449
+ var props = __objRest(_a, []);
450
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Root, __spreadValues({ "data-slot": "tooltip" }, props));
451
+ }
452
+ function TooltipTrigger(_a) {
453
+ var props = __objRest(_a, []);
454
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Trigger, __spreadValues({ "data-slot": "tooltip-trigger" }, props));
455
+ }
456
+ function TooltipContent(_a) {
457
+ var _b = _a, {
458
+ className,
459
+ sideOffset = 8,
460
+ side,
461
+ children,
462
+ style
463
+ } = _b, props = __objRest(_b, [
464
+ "className",
465
+ "sideOffset",
466
+ "side",
467
+ "children",
468
+ "style"
469
+ ]);
470
+ const themeVars = useThemeVars();
471
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Positioner, { sideOffset, side, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
472
+ import_tooltip.Tooltip.Popup,
473
+ __spreadProps(__spreadValues({
474
+ className: cn(
475
+ "relative z-50 w-fit animate-in overflow-visible bg-brand-secondary px-3 py-1.5 text-caption text-balance text-brand-secondary-foreground fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards",
476
+ className
477
+ ),
478
+ "data-slot": "tooltip-content",
479
+ style: __spreadValues(__spreadValues({}, themeVars), style)
480
+ }, props), {
481
+ children: [
482
+ children,
483
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Arrow, { className: "z-50 size-2.5 rotate-45 bg-brand-secondary data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1 data-[side=top]:-bottom-1" })
484
+ ]
485
+ })
486
+ ) }) });
487
+ }
488
+
489
+ // src/components/ui/popover.tsx
490
+ var React4 = __toESM(require("react"));
491
+ var import_popover = require("@base-ui/react/popover");
492
+ var import_jsx_runtime7 = require("react/jsx-runtime");
493
+ var PopoverPortalContext = React4.createContext(void 0);
494
+ function Popover(_a) {
495
+ var props = __objRest(_a, []);
496
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Root, __spreadValues({ "data-slot": "popover" }, props));
497
+ }
498
+ function PopoverTrigger(_a) {
499
+ var props = __objRest(_a, []);
500
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Trigger, __spreadValues({ "data-slot": "popover-trigger" }, props));
501
+ }
502
+ function PopoverContent(_a) {
503
+ var _b = _a, {
504
+ className,
505
+ align = "center",
506
+ sideOffset = 4,
507
+ style
508
+ } = _b, props = __objRest(_b, [
509
+ "className",
510
+ "align",
511
+ "sideOffset",
512
+ "style"
513
+ ]);
514
+ const themeVars = useThemeVars();
515
+ const portalContainer = React4.useContext(PopoverPortalContext);
516
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Portal, { container: portalContainer != null ? portalContainer : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
517
+ import_popover.Popover.Positioner,
518
+ {
519
+ className: "z-[200]",
520
+ align,
521
+ sideOffset,
522
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
523
+ import_popover.Popover.Popup,
524
+ __spreadValues({
525
+ className: cn(
526
+ "z-50 w-72 border border-border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
527
+ className
528
+ ),
529
+ "data-slot": "popover-content",
530
+ style: __spreadValues(__spreadValues({}, themeVars), style)
531
+ }, props)
532
+ )
533
+ }
534
+ ) });
535
+ }
536
+
537
+ // src/components/ui/progress.tsx
538
+ var import_progress = require("@base-ui/react/progress");
539
+ var import_jsx_runtime8 = require("react/jsx-runtime");
540
+ function Progress(_a) {
541
+ var _b = _a, {
542
+ className,
543
+ value,
544
+ indicatorClassName
545
+ } = _b, props = __objRest(_b, [
546
+ "className",
547
+ "value",
548
+ "indicatorClassName"
549
+ ]);
550
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
551
+ import_progress.Progress.Root,
552
+ __spreadProps(__spreadValues({
553
+ className: cn("relative h-2 w-full overflow-hidden bg-muted", className),
554
+ "data-slot": "progress",
555
+ value
556
+ }, props), {
557
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_progress.Progress.Track, { className: "h-full", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
558
+ import_progress.Progress.Indicator,
559
+ {
560
+ className: cn("h-full bg-primary transition-all", indicatorClassName),
561
+ "data-slot": "progress-indicator"
562
+ }
563
+ ) })
564
+ })
565
+ );
566
+ }
567
+
568
+ // src/components/ui/tabs.tsx
569
+ var import_class_variance_authority3 = require("class-variance-authority");
570
+ var import_tabs = require("@base-ui/react/tabs");
571
+ var import_jsx_runtime9 = require("react/jsx-runtime");
572
+ function Tabs(_a) {
573
+ var _b = _a, {
574
+ className,
575
+ orientation = "horizontal"
576
+ } = _b, props = __objRest(_b, [
577
+ "className",
578
+ "orientation"
579
+ ]);
580
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
581
+ import_tabs.Tabs.Root,
582
+ __spreadValues({
583
+ className: cn(
584
+ "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
585
+ className
586
+ ),
587
+ "data-orientation": orientation,
588
+ "data-slot": "tabs"
589
+ }, props)
590
+ );
591
+ }
592
+ var tabsListVariants = (0, import_class_variance_authority3.cva)(
593
+ "group/tabs-list inline-flex w-fit items-center justify-center gap-1 rounded-none p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
594
+ {
595
+ variants: {
596
+ variant: {
597
+ default: "bg-muted",
598
+ line: "bg-transparent p-0"
599
+ }
600
+ },
601
+ defaultVariants: {
602
+ variant: "default"
603
+ }
604
+ }
605
+ );
606
+ function TabsList(_a) {
607
+ var _b = _a, {
608
+ className,
609
+ variant = "default"
610
+ } = _b, props = __objRest(_b, [
611
+ "className",
612
+ "variant"
613
+ ]);
614
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
615
+ import_tabs.Tabs.List,
616
+ __spreadValues({
617
+ className: cn(tabsListVariants({ variant }), className),
618
+ "data-slot": "tabs-list",
619
+ "data-variant": variant
620
+ }, props)
621
+ );
622
+ }
623
+ function TabsTrigger(_a) {
624
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
625
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
626
+ import_tabs.Tabs.Tab,
627
+ __spreadValues({
628
+ className: cn(
629
+ // Base layout & typography
630
+ "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap",
631
+ "rounded-none border border-transparent px-1.5 py-1 text-label-medium",
632
+ "text-muted-foreground transition-all",
633
+ // Vertical orientation
634
+ "group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start",
635
+ // Hover & focus
636
+ "hover:text-foreground",
637
+ "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring",
638
+ // Disabled
639
+ "disabled:pointer-events-none disabled:opacity-50",
640
+ // Active state — Default variant: primary/10 bg + subtle shadow
641
+ // Base UI uses data-active attribute for the active/selected tab
642
+ "data-active:bg-primary/10 data-active:text-foreground",
643
+ "group-data-[variant=default]/tabs-list:data-active:shadow-sm",
644
+ // Active state — Line variant: suppress bg & shadow
645
+ "group-data-[variant=line]/tabs-list:data-active:bg-transparent",
646
+ "group-data-[variant=line]/tabs-list:data-active:shadow-none",
647
+ // Indicator pseudo-element (visible only for Line variant, active state)
648
+ "after:absolute after:bg-primary after:opacity-0 after:transition-opacity",
649
+ "group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5",
650
+ "group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5",
651
+ "group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
652
+ // SVG icons
653
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
654
+ className
655
+ ),
656
+ "data-slot": "tabs-trigger"
657
+ }, props)
658
+ );
659
+ }
660
+
661
+ // src/components/ui/policy-ai/policy-ai-responses.tsx
662
+ var import_jsx_runtime10 = require("react/jsx-runtime");
663
+ function BankAvatar({ name }) {
664
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
665
+ "span",
666
+ {
667
+ "aria-hidden": "true",
668
+ className: "shrink-0 inline-flex items-center justify-center size-7 bg-muted text-muted-foreground text-xs font-semibold border border-border",
669
+ children: name.charAt(0).toUpperCase()
670
+ }
671
+ );
672
+ }
673
+ function QueryContextInfo({ label }) {
674
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Tooltip, { children: [
675
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
676
+ "span",
677
+ {
678
+ className: "shrink-0 text-muted-foreground/60 hover:text-muted-foreground cursor-default transition-colors",
679
+ "aria-label": label,
680
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Info, { className: "size-3.5", "aria-hidden": "true" })
681
+ }
682
+ ) }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipContent, { side: "top", children: label })
684
+ ] }) });
685
+ }
686
+ function queryContextLabel(context) {
687
+ return [
688
+ context.policyType,
689
+ ...context.categories,
690
+ context.queryType.replace(/_/g, " ")
691
+ ].join(" \xB7 ");
692
+ }
693
+ function CitationBadge({ citation }) {
694
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { children: [
695
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-label": `View source ${citation.index}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
696
+ Badge,
697
+ {
698
+ variant: "secondary",
699
+ className: "cursor-pointer px-1.5 py-0 text-xs mx-0.5 align-baseline hover:bg-secondary/80 transition-colors",
700
+ children: citation.index
701
+ }
702
+ ) }) }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverContent, { className: "w-72 p-3", sideOffset: 6, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
704
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
705
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs font-semibold text-foreground", children: citation.bankName }),
706
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: citation.category })
707
+ ] }),
708
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-xs text-muted-foreground leading-relaxed", children: citation.excerpt })
709
+ ] }) })
710
+ ] });
711
+ }
712
+ function AnswerWithCitations({
713
+ answer,
714
+ citations
715
+ }) {
716
+ const citationMap = new Map(citations.map((c) => [c.index, c]));
717
+ const parts = answer.split(/(\[\d+\])/g);
718
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-foreground leading-relaxed whitespace-pre-line", children: parts.map((part, i) => {
719
+ const match = part.match(/^\[(\d+)\]$/);
720
+ if (match) {
721
+ const citation = citationMap.get(parseInt(match[1], 10));
722
+ if (citation) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CitationBadge, { citation }, i);
723
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground", children: part }, i);
724
+ }
725
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React5.Fragment, { children: part }, i);
726
+ }) });
727
+ }
728
+ function PolicySingleBankAnswer({
729
+ bankName,
730
+ verdict,
731
+ answer,
732
+ citations,
733
+ queryContext,
734
+ className
735
+ }) {
736
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
737
+ "div",
738
+ {
739
+ "data-slot": "policy-single-bank-answer",
740
+ className: cn("border border-border bg-card flex flex-col", className),
741
+ children: [
742
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border", children: [
743
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BankAvatar, { name: bankName }),
744
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 flex items-center gap-1.5 min-w-0", children: [
745
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-sm text-foreground truncate", children: bankName }),
746
+ queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
747
+ ] }),
748
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict })
749
+ ] }),
750
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AnswerWithCitations, { answer, citations }) })
751
+ ]
752
+ }
753
+ );
754
+ }
755
+ function PolicyComparisonTable({
756
+ categories,
757
+ banks,
758
+ summaryCounts,
759
+ citations,
760
+ queryContext,
761
+ className
762
+ }) {
763
+ const [search, setSearch] = React5.useState("");
764
+ const [filter, setFilter] = React5.useState("all");
765
+ const filtered = React5.useMemo(() => {
766
+ let result = banks;
767
+ if (search.trim()) {
768
+ const q = search.toLowerCase();
769
+ result = result.filter((b) => b.bankName.toLowerCase().includes(q));
770
+ }
771
+ if (filter !== "all") {
772
+ result = result.filter((b) => b.verdict === filter);
773
+ }
774
+ return result;
775
+ }, [banks, search, filter]);
776
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
777
+ "div",
778
+ {
779
+ "data-slot": "policy-comparison-table",
780
+ className: cn("border border-border bg-card flex flex-col", className),
781
+ children: [
782
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-2.5 border-b border-border bg-muted/30", children: [
783
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
784
+ import_lucide_react3.Building2,
785
+ {
786
+ className: "size-3.5 text-muted-foreground shrink-0",
787
+ "aria-hidden": "true"
788
+ }
789
+ ),
790
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-sm flex-wrap flex-1 min-w-0", children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-foreground", children: [
792
+ summaryCounts.total,
793
+ " banks"
794
+ ] }),
795
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-muted-foreground", children: "\xB7" }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "success", className: "text-xs px-1.5 py-0", children: [
797
+ summaryCounts.yes,
798
+ " Yes"
799
+ ] }),
800
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "warning", className: "text-xs px-1.5 py-0", children: [
801
+ summaryCounts.softNo,
802
+ " Soft No"
803
+ ] }),
804
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "destructive", className: "text-xs px-1.5 py-0", children: [
805
+ summaryCounts.no,
806
+ " No"
807
+ ] })
808
+ ] }),
809
+ queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
810
+ ] }),
811
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 py-2.5 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
812
+ Input,
813
+ {
814
+ "aria-label": "Search banks",
815
+ placeholder: "Search banks\u2026",
816
+ value: search,
817
+ onChange: (e) => setSearch(e.target.value),
818
+ className: "h-8 text-sm"
819
+ }
820
+ ) }),
821
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-b border-border px-4 pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
822
+ Tabs,
823
+ {
824
+ value: filter,
825
+ onValueChange: (v) => setFilter(v),
826
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(TabsList, { variant: "line", className: "justify-start h-8 gap-0 -mb-px", children: [
827
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "all", className: "text-sm px-3 h-7", children: "All" }),
828
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "yes", className: "text-sm px-3 h-7", children: "Yes" }),
829
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "soft_no", className: "text-sm px-3 h-7", children: "Soft No" }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "no", className: "text-sm px-3 h-7", children: "No" })
831
+ ] })
832
+ }
833
+ ) }),
834
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { className: "w-full text-sm border-collapse", children: [
835
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b border-border bg-muted/20", children: [
836
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "text-left text-sm font-medium text-muted-foreground px-4 py-2", children: "Bank" }),
837
+ categories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
838
+ "th",
839
+ {
840
+ className: "text-left text-sm font-medium text-muted-foreground px-3 py-2 w-px whitespace-nowrap",
841
+ children: cat
842
+ },
843
+ cat
844
+ ))
845
+ ] }) }),
846
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
847
+ "td",
848
+ {
849
+ colSpan: categories.length + 1,
850
+ className: "px-4 py-6 text-center text-sm text-muted-foreground",
851
+ children: "No banks match your search."
852
+ }
853
+ ) }) : filtered.map((bank) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b border-border", children: [
854
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
855
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BankAvatar, { name: bank.bankName }),
856
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
857
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium text-foreground leading-snug", children: bank.bankName }),
858
+ bank.details && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground leading-snug", children: bank.details })
859
+ ] })
860
+ ] }) }),
861
+ categories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
862
+ "td",
863
+ {
864
+ className: "px-3 py-2.5 align-top w-px whitespace-nowrap",
865
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict: bank.verdict })
866
+ },
867
+ cat
868
+ ))
869
+ ] }, bank.bankName)) })
870
+ ] }) })
871
+ ]
872
+ }
873
+ );
874
+ }
875
+ var VERDICT_SCORE_COLORS = {
876
+ yes: { track: "bg-success/20", indicator: "bg-success" },
877
+ soft_no: { track: "bg-warning/20", indicator: "bg-warning" },
878
+ no: { track: "bg-destructive/20", indicator: "bg-destructive" },
879
+ unknown: { track: "bg-muted", indicator: "bg-muted-foreground" }
880
+ };
881
+ function PolicyRankedList({
882
+ categories,
883
+ banks,
884
+ citations,
885
+ queryContext,
886
+ className
887
+ }) {
888
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
889
+ "div",
890
+ {
891
+ "data-slot": "policy-ranked-list",
892
+ className: cn("border border-border bg-card flex flex-col", className),
893
+ children: [
894
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 px-4 py-2.5 border-b border-border bg-muted/30", children: [
895
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-muted-foreground shrink-0", children: "Ranked:" }),
896
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center gap-1 flex-wrap flex-1 min-w-0", children: categories.map((cat, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React5.Fragment, { children: [
897
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-muted-foreground", children: "+" }),
898
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: cat })
899
+ ] }, cat)) }),
900
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-muted-foreground shrink-0", children: [
901
+ banks.length,
902
+ " banks"
903
+ ] }),
904
+ queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
905
+ ] }),
906
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "divide-y divide-border", children: banks.map((bank) => {
907
+ var _a, _b;
908
+ const scorePercent = Math.round(bank.score * 100);
909
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col", children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3", children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "shrink-0 w-6 text-center text-sm font-bold text-muted-foreground", children: [
912
+ "#",
913
+ bank.rank
914
+ ] }),
915
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col gap-1.5", children: [
916
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
917
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium text-foreground truncate", children: bank.bankName }),
918
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
919
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-muted-foreground font-mono", children: [
920
+ scorePercent,
921
+ "%"
922
+ ] }),
923
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict: bank.verdict })
924
+ ] })
925
+ ] }),
926
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
927
+ Progress,
928
+ {
929
+ value: scorePercent,
930
+ className: cn(
931
+ "h-1.5",
932
+ ((_a = VERDICT_SCORE_COLORS[bank.verdict]) != null ? _a : VERDICT_SCORE_COLORS.unknown).track
933
+ ),
934
+ indicatorClassName: ((_b = VERDICT_SCORE_COLORS[bank.verdict]) != null ? _b : VERDICT_SCORE_COLORS.unknown).indicator,
935
+ "aria-label": `${bank.bankName} policy score: ${scorePercent}%`
936
+ }
937
+ )
938
+ ] })
939
+ ] }),
940
+ bank.highlights.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 pb-3 pl-[52px]", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "flex flex-col gap-0.5", children: bank.highlights.map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
941
+ "li",
942
+ {
943
+ className: "text-sm text-muted-foreground leading-relaxed list-disc list-inside",
944
+ children: h
945
+ },
946
+ i
947
+ )) }) })
948
+ ] }, bank.bankName);
949
+ }) })
950
+ ]
951
+ }
952
+ );
953
+ }
954
+
955
+ // src/components/ui/policy-ai/policy-ai-panel.tsx
956
+ var React7 = __toESM(require("react"));
957
+ var import_lucide_react6 = require("lucide-react");
958
+
959
+ // src/components/ui/chat-input-area.tsx
960
+ var React6 = __toESM(require("react"));
961
+ var import_lucide_react4 = require("lucide-react");
962
+
963
+ // src/components/ui/textarea.tsx
964
+ var import_jsx_runtime11 = require("react/jsx-runtime");
965
+ function Textarea(_a) {
966
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
967
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
968
+ "textarea",
969
+ __spreadValues({
970
+ className: cn(
971
+ // WealthX: removed shadow-xs (flat panels), added font-sans
972
+ "flex field-sizing-content min-h-16 w-full border border-input bg-transparent px-3 py-2 text-body-medium font-sans transition-[color,box-shadow] outline-none placeholder:font-normal placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-primary/20 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
973
+ className
974
+ ),
975
+ "data-slot": "textarea"
976
+ }, props)
977
+ );
978
+ }
979
+
980
+ // src/components/ui/chat-input-area.tsx
981
+ var import_jsx_runtime12 = require("react/jsx-runtime");
982
+ var DEFAULT_HINT = "Enter to send \xB7 Shift+Enter for new line";
983
+ function ChatInputArea({
984
+ value,
985
+ onChange,
986
+ onSend,
987
+ onAttachFile,
988
+ onAttachImage,
989
+ disabled = false,
990
+ placeholder = "Type your message\u2026",
991
+ hint = DEFAULT_HINT,
992
+ maxHeight = 160,
993
+ autoFocus = false,
994
+ className
995
+ }) {
996
+ const textareaRef = React6.useRef(null);
997
+ const fileInputRef = React6.useRef(null);
998
+ const imageInputRef = React6.useRef(null);
999
+ React6.useEffect(() => {
1000
+ if (autoFocus) {
1001
+ setTimeout(() => {
1002
+ var _a;
1003
+ return (_a = textareaRef.current) == null ? void 0 : _a.focus();
1004
+ }, 50);
1005
+ }
1006
+ }, [autoFocus]);
1007
+ const handleSend = React6.useCallback(() => {
1008
+ const text = value.trim();
1009
+ if (!text || disabled) return;
1010
+ onSend(text);
1011
+ if (textareaRef.current) {
1012
+ textareaRef.current.style.height = "auto";
1013
+ }
1014
+ }, [value, disabled, onSend]);
1015
+ const handleKeyDown = React6.useCallback(
1016
+ (e) => {
1017
+ if (e.key === "Enter" && !e.shiftKey) {
1018
+ e.preventDefault();
1019
+ handleSend();
1020
+ }
1021
+ },
1022
+ [handleSend]
1023
+ );
1024
+ const handleTextareaChange = React6.useCallback(
1025
+ (e) => {
1026
+ onChange(e.target.value);
1027
+ const el = e.target;
1028
+ el.style.height = "auto";
1029
+ el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
1030
+ },
1031
+ [onChange, maxHeight]
1032
+ );
1033
+ const handleFileChange = React6.useCallback(
1034
+ (e) => {
1035
+ var _a;
1036
+ if ((_a = e.target.files) == null ? void 0 : _a.length) {
1037
+ onAttachFile == null ? void 0 : onAttachFile(e.target.files);
1038
+ e.target.value = "";
1039
+ }
1040
+ },
1041
+ [onAttachFile]
1042
+ );
1043
+ const handleImageChange = React6.useCallback(
1044
+ (e) => {
1045
+ var _a;
1046
+ if ((_a = e.target.files) == null ? void 0 : _a.length) {
1047
+ onAttachImage == null ? void 0 : onAttachImage(e.target.files);
1048
+ e.target.value = "";
1049
+ }
1050
+ },
1051
+ [onAttachImage]
1052
+ );
1053
+ const showFileButton = typeof onAttachFile === "function";
1054
+ const showImageButton = typeof onAttachImage === "function";
1055
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1056
+ "div",
1057
+ {
1058
+ "data-slot": "chat-input-area",
1059
+ className: cn("flex flex-col gap-1.5", className),
1060
+ children: [
1061
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "border border-border bg-background flex flex-col focus-within:ring-1 focus-within:ring-ring", children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1063
+ Textarea,
1064
+ {
1065
+ ref: textareaRef,
1066
+ value,
1067
+ onChange: handleTextareaChange,
1068
+ onKeyDown: handleKeyDown,
1069
+ placeholder,
1070
+ disabled,
1071
+ rows: 3,
1072
+ className: "resize-none text-sm border-0 shadow-none focus-visible:ring-0 px-3 pt-3 pb-1 min-h-[72px]",
1073
+ "aria-label": placeholder
1074
+ }
1075
+ ),
1076
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between px-2 pb-2", children: [
1077
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-0.5", children: [
1078
+ showFileButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1079
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1080
+ Button,
1081
+ {
1082
+ variant: "ghost",
1083
+ size: "icon-sm",
1084
+ type: "button",
1085
+ title: "Attach file",
1086
+ "aria-label": "Attach file",
1087
+ disabled,
1088
+ onClick: () => {
1089
+ var _a;
1090
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
1091
+ },
1092
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Paperclip, { className: "size-3.5", "aria-hidden": "true" })
1093
+ }
1094
+ ),
1095
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1096
+ "input",
1097
+ {
1098
+ ref: fileInputRef,
1099
+ type: "file",
1100
+ multiple: true,
1101
+ className: "sr-only",
1102
+ tabIndex: -1,
1103
+ onChange: handleFileChange
1104
+ }
1105
+ )
1106
+ ] }),
1107
+ showImageButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1109
+ Button,
1110
+ {
1111
+ variant: "ghost",
1112
+ size: "icon-sm",
1113
+ type: "button",
1114
+ title: "Upload image",
1115
+ "aria-label": "Upload image",
1116
+ disabled,
1117
+ onClick: () => {
1118
+ var _a;
1119
+ return (_a = imageInputRef.current) == null ? void 0 : _a.click();
1120
+ },
1121
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.ImagePlus, { className: "size-3.5", "aria-hidden": "true" })
1122
+ }
1123
+ ),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1125
+ "input",
1126
+ {
1127
+ ref: imageInputRef,
1128
+ type: "file",
1129
+ multiple: true,
1130
+ accept: "image/*",
1131
+ className: "sr-only",
1132
+ tabIndex: -1,
1133
+ onChange: handleImageChange
1134
+ }
1135
+ )
1136
+ ] })
1137
+ ] }),
1138
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1139
+ Button,
1140
+ {
1141
+ size: "icon-sm",
1142
+ type: "button",
1143
+ "aria-label": "Send message",
1144
+ disabled: !value.trim() || disabled,
1145
+ onClick: handleSend,
1146
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Send, { className: "size-3.5", "aria-hidden": "true" })
1147
+ }
1148
+ )
1149
+ ] })
1150
+ ] }),
1151
+ hint !== false && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: hint })
1152
+ ]
1153
+ }
1154
+ );
1155
+ }
1156
+
1157
+ // src/components/ui/chat-widget-primitives.tsx
1158
+ var import_lucide_react5 = require("lucide-react");
1159
+
1160
+ // src/components/ui/avatar.tsx
1161
+ var import_avatar = require("@base-ui/react/avatar");
1162
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1163
+ function Avatar(_a) {
1164
+ var _b = _a, {
1165
+ className,
1166
+ size = "default"
1167
+ } = _b, props = __objRest(_b, [
1168
+ "className",
1169
+ "size"
1170
+ ]);
1171
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1172
+ import_avatar.Avatar.Root,
1173
+ __spreadValues({
1174
+ className: cn(
1175
+ "group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
1176
+ className
1177
+ ),
1178
+ "data-size": size,
1179
+ "data-slot": "avatar"
1180
+ }, props)
1181
+ );
1182
+ }
1183
+ function AvatarFallback(_a) {
1184
+ var _b = _a, {
1185
+ className
1186
+ } = _b, props = __objRest(_b, [
1187
+ "className"
1188
+ ]);
1189
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1190
+ import_avatar.Avatar.Fallback,
1191
+ __spreadValues({
1192
+ className: cn(
1193
+ "flex size-full items-center justify-center rounded-full overflow-hidden bg-muted text-body-small font-sans text-muted-foreground group-data-[size=sm]/avatar:text-caption",
1194
+ className
1195
+ ),
1196
+ "data-slot": "avatar-fallback"
1197
+ }, props)
1198
+ );
1199
+ }
1200
+
1201
+ // src/components/ui/chat-widget-primitives.tsx
1202
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1203
+ function ChatWidgetMessage({
1204
+ role,
1205
+ content,
1206
+ timestamp,
1207
+ isStreaming,
1208
+ className
1209
+ }) {
1210
+ if (role === "system") {
1211
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("flex items-center justify-center py-2", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-body-small text-muted-foreground", children: content }) });
1212
+ }
1213
+ const isLeft = role === "bot" || role === "advisor";
1214
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1215
+ "div",
1216
+ {
1217
+ className: cn(
1218
+ "flex gap-2",
1219
+ isLeft ? "items-start" : "flex-row-reverse items-start",
1220
+ className
1221
+ ),
1222
+ children: [
1223
+ isLeft && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Avatar, { className: "size-7", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1224
+ AvatarFallback,
1225
+ {
1226
+ className: role === "advisor" ? "bg-primary/15 text-foreground" : void 0,
1227
+ children: role === "advisor" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.UserRound, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Bot, { className: "size-3.5" })
1228
+ }
1229
+ ) }),
1230
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1231
+ "div",
1232
+ {
1233
+ className: cn(
1234
+ "flex max-w-[80%] flex-col gap-1",
1235
+ !isLeft && "items-end"
1236
+ ),
1237
+ children: [
1238
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1239
+ "div",
1240
+ {
1241
+ className: cn(
1242
+ "px-3 py-2 text-body-medium",
1243
+ isLeft ? "border border-border bg-card text-card-foreground shadow-sm" : "text-primary-foreground"
1244
+ ),
1245
+ style: !isLeft ? { backgroundColor: "var(--primary)" } : void 0,
1246
+ children: isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatWidgetTypingIndicator, {}) : content
1247
+ }
1248
+ ),
1249
+ timestamp && !isStreaming && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-[10px] text-muted-foreground", children: timestamp })
1250
+ ]
1251
+ }
1252
+ )
1253
+ ]
1254
+ }
1255
+ );
1256
+ }
1257
+ function ChatWidgetTypingIndicator({
1258
+ className
1259
+ }) {
1260
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1261
+ "div",
1262
+ {
1263
+ role: "status",
1264
+ "aria-label": "Typing",
1265
+ className: cn("flex items-center gap-1 py-0.5", className),
1266
+ children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1267
+ "span",
1268
+ {
1269
+ className: "size-1.5 animate-bounce rounded-full bg-muted-foreground/60",
1270
+ style: { animationDelay: `${i * 0.15}s` },
1271
+ "aria-hidden": "true"
1272
+ },
1273
+ i
1274
+ ))
1275
+ }
1276
+ );
1277
+ }
1278
+
1279
+ // src/components/ui/policy-ai/policy-ai-panel.tsx
1280
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1281
+ var DEFAULT_SUGGESTED = {
1282
+ Income: [
1283
+ "Which banks accept casual income?",
1284
+ "Which lenders accept bonus income, ranked best to worst?",
1285
+ "How is self-employed income assessed across lenders?"
1286
+ ],
1287
+ Security: [
1288
+ "Which banks accept apartments under 40sqm?",
1289
+ "What is the maximum LVR for a serviced apartment?",
1290
+ "Do any lenders accept hobby farm properties?"
1291
+ ],
1292
+ Serviceability: [
1293
+ "Which banks have the most flexible DTI ratio?",
1294
+ "How is HECS debt treated by different lenders?",
1295
+ "Which lenders apply the lowest assessment buffer rate?"
1296
+ ],
1297
+ "Loan Type": [
1298
+ "Which lenders offer cashback on refinances?",
1299
+ "Which banks accept low-doc construction loans?",
1300
+ "What are the pre-approval policies across lenders?"
1301
+ ],
1302
+ Borrower: [
1303
+ "Which banks accept non-resident borrowers?",
1304
+ "Which lenders offer LMI waiver for medical professionals?",
1305
+ "How do lenders treat prior credit impairment?"
1306
+ ]
1307
+ };
1308
+ var DEFAULT_THINKING_STEPS = [
1309
+ "Classifying query type\u2026",
1310
+ "Searching across 40+ banks\u2026",
1311
+ "Retrieving policy documents\u2026",
1312
+ "Generating response\u2026"
1313
+ ];
1314
+ function PolicyAIThinkingSteps({ steps }) {
1315
+ const [currentStep, setCurrentStep] = React7.useState(0);
1316
+ React7.useEffect(() => {
1317
+ setCurrentStep(0);
1318
+ }, [steps]);
1319
+ React7.useEffect(() => {
1320
+ if (currentStep >= steps.length - 1) return;
1321
+ const timer = setTimeout(() => setCurrentStep((s) => s + 1), 1400);
1322
+ return () => clearTimeout(timer);
1323
+ }, [currentStep, steps.length]);
1324
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col gap-2.5 px-4 py-3", children: steps.map((step, i) => {
1325
+ const isDone = i < currentStep;
1326
+ const isCurrent = i === currentStep;
1327
+ const isPending = i > currentStep;
1328
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1329
+ "div",
1330
+ {
1331
+ className: cn(
1332
+ "flex items-center gap-2.5 transition-opacity duration-300",
1333
+ isPending && "opacity-30"
1334
+ ),
1335
+ children: [
1336
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "shrink-0 size-4 flex items-center justify-center", children: isDone ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Check, { className: "size-3.5 text-primary", "aria-hidden": "true" }) : isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1337
+ "span",
1338
+ {
1339
+ className: "flex items-center gap-0.5",
1340
+ "aria-label": "In progress",
1341
+ children: [0, 1, 2].map((j) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1342
+ "span",
1343
+ {
1344
+ className: "size-1 bg-muted-foreground/70 animate-bounce",
1345
+ style: { animationDelay: `${j * 150}ms` }
1346
+ },
1347
+ j
1348
+ ))
1349
+ }
1350
+ ) : null }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1352
+ "span",
1353
+ {
1354
+ className: cn(
1355
+ "text-sm leading-snug transition-colors duration-200",
1356
+ isDone && "text-muted-foreground",
1357
+ isCurrent && "text-foreground font-medium",
1358
+ isPending && "text-muted-foreground"
1359
+ ),
1360
+ children: step
1361
+ }
1362
+ )
1363
+ ]
1364
+ },
1365
+ step
1366
+ );
1367
+ }) });
1368
+ }
1369
+ function ResponseCard({
1370
+ content,
1371
+ queryContext
1372
+ }) {
1373
+ if (content.type === "single_bank") {
1374
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1375
+ PolicySingleBankAnswer,
1376
+ {
1377
+ bankName: content.bankName,
1378
+ verdict: content.verdict,
1379
+ answer: content.answer,
1380
+ citations: content.citations,
1381
+ queryContext
1382
+ }
1383
+ );
1384
+ }
1385
+ if (content.type === "cross_bank_comparison") {
1386
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1387
+ PolicyComparisonTable,
1388
+ {
1389
+ categories: content.categories,
1390
+ banks: content.banks,
1391
+ summaryCounts: content.summaryCounts,
1392
+ citations: content.citations,
1393
+ queryContext
1394
+ }
1395
+ );
1396
+ }
1397
+ if (content.type === "ranked_list") {
1398
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1399
+ PolicyRankedList,
1400
+ {
1401
+ categories: content.categories,
1402
+ banks: content.banks,
1403
+ citations: content.citations,
1404
+ queryContext
1405
+ }
1406
+ );
1407
+ }
1408
+ return null;
1409
+ }
1410
+ function PolicyAIFAB({
1411
+ onClick,
1412
+ hasNudge,
1413
+ className
1414
+ }) {
1415
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("relative inline-flex shrink-0", className), children: [
1416
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1417
+ Button,
1418
+ {
1419
+ "data-slot": "policy-ai-fab",
1420
+ size: "icon",
1421
+ onClick,
1422
+ className: "size-12 shadow-lg rounded-full",
1423
+ "aria-label": "Open Policy AI",
1424
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.BrainCircuit, { className: "size-5", "aria-hidden": "true" })
1425
+ }
1426
+ ),
1427
+ hasNudge && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "absolute -top-1 -right-1 size-3 bg-destructive rounded-full border-2 border-background" })
1428
+ ] });
1429
+ }
1430
+ function PolicyAIPanel({
1431
+ open,
1432
+ onClose,
1433
+ messages = [],
1434
+ suggestedQuestions,
1435
+ isStreaming = false,
1436
+ isLoading = false,
1437
+ thinkingSteps,
1438
+ onSendMessage,
1439
+ onAttachFile,
1440
+ onAttachImage,
1441
+ onReset,
1442
+ position = "bottom-right",
1443
+ inline = false,
1444
+ className
1445
+ }) {
1446
+ var _a;
1447
+ const resolvedThinkingSteps = thinkingSteps != null ? thinkingSteps : DEFAULT_THINKING_STEPS;
1448
+ const [inputValue, setInputValue] = React7.useState("");
1449
+ const [minimised, setMinimised] = React7.useState(false);
1450
+ const [activeTab, setActiveTab] = React7.useState("Income");
1451
+ const messagesEndRef = React7.useRef(null);
1452
+ const isChatMode = messages.length > 0;
1453
+ React7.useEffect(() => {
1454
+ var _a2;
1455
+ if (open && !minimised) {
1456
+ (_a2 = messagesEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
1457
+ }
1458
+ }, [messages, open, minimised]);
1459
+ const handleSend = React7.useCallback(
1460
+ (text) => {
1461
+ if (!text || isStreaming) return;
1462
+ onSendMessage == null ? void 0 : onSendMessage(text);
1463
+ setInputValue("");
1464
+ },
1465
+ [isStreaming, onSendMessage]
1466
+ );
1467
+ if (!open) return null;
1468
+ const positionClass = position === "bottom-left" ? "left-6" : "right-6";
1469
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1470
+ "div",
1471
+ {
1472
+ "data-slot": "policy-ai-panel",
1473
+ className: cn(
1474
+ "flex flex-col bg-card",
1475
+ inline ? "h-full border-0" : [
1476
+ "fixed z-50 border border-border shadow-2xl",
1477
+ "bottom-20 w-[400px]",
1478
+ "animate-in slide-in-from-bottom-4 fade-in duration-200",
1479
+ positionClass,
1480
+ minimised && "shadow-lg"
1481
+ ],
1482
+ className
1483
+ ),
1484
+ style: inline ? void 0 : {
1485
+ maxHeight: minimised ? "auto" : "min(600px, calc(100vh - 120px))"
1486
+ },
1487
+ children: [
1488
+ !inline && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "shrink-0 flex items-center gap-2.5 px-3 py-2.5 border-b border-border bg-card", children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1490
+ import_lucide_react6.BrainCircuit,
1491
+ {
1492
+ className: "size-4 text-primary shrink-0",
1493
+ "aria-hidden": "true"
1494
+ }
1495
+ ),
1496
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-sm font-semibold text-foreground flex-1 truncate", children: "Policy AI" }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-0.5", children: [
1498
+ isChatMode && onReset && !minimised && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1499
+ Button,
1500
+ {
1501
+ variant: "ghost",
1502
+ size: "icon-sm",
1503
+ onClick: onReset,
1504
+ title: "New conversation",
1505
+ "aria-label": "New conversation",
1506
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.RotateCcw, { className: "size-3.5", "aria-hidden": "true" })
1507
+ }
1508
+ ),
1509
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1510
+ Button,
1511
+ {
1512
+ variant: "ghost",
1513
+ size: "icon-sm",
1514
+ onClick: () => setMinimised((v) => !v),
1515
+ title: minimised ? "Restore" : "Minimise",
1516
+ "aria-label": minimised ? "Restore panel" : "Minimise panel",
1517
+ children: minimised ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.ChevronDown, { className: "size-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Minus, { className: "size-3.5", "aria-hidden": "true" })
1518
+ }
1519
+ ),
1520
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1521
+ Button,
1522
+ {
1523
+ variant: "ghost",
1524
+ size: "icon-sm",
1525
+ onClick: onClose,
1526
+ title: "Close",
1527
+ "aria-label": "Close Policy AI",
1528
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.X, { className: "size-3.5", "aria-hidden": "true" })
1529
+ }
1530
+ )
1531
+ ] })
1532
+ ] }),
1533
+ (!minimised || inline) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1534
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn(!inline && "flex-1 overflow-y-auto min-h-0"), children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col justify-center h-full py-8", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PolicyAIThinkingSteps, { steps: resolvedThinkingSteps }) }) : !isChatMode ? (
1535
+ /* Home state — suggested questions by policy type */
1536
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col", children: [
1537
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "px-3 pt-3 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs text-muted-foreground leading-relaxed", children: "Ask me about lending policies across 40+ Australian banks \u2014 income, LVR, security types, serviceability, and more." }) }),
1538
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border-b border-border px-3 pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1539
+ Tabs,
1540
+ {
1541
+ value: activeTab,
1542
+ onValueChange: (v) => setActiveTab(v),
1543
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1544
+ TabsList,
1545
+ {
1546
+ variant: "line",
1547
+ className: "justify-start h-8 gap-0 -mb-px overflow-x-auto",
1548
+ children: Object.keys(DEFAULT_SUGGESTED).map(
1549
+ (type) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1550
+ TabsTrigger,
1551
+ {
1552
+ value: type,
1553
+ className: "text-xs px-2 h-7 shrink-0",
1554
+ children: type
1555
+ },
1556
+ type
1557
+ )
1558
+ )
1559
+ }
1560
+ )
1561
+ }
1562
+ ) }),
1563
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col px-3 py-2 gap-1", children: ((_a = (suggestedQuestions != null ? suggestedQuestions : DEFAULT_SUGGESTED)[activeTab]) != null ? _a : []).map((q) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1564
+ "button",
1565
+ {
1566
+ onClick: () => setInputValue(q),
1567
+ className: "w-full text-left text-xs text-foreground px-3 py-2 border border-border hover:bg-muted/60 transition-colors leading-relaxed",
1568
+ children: q
1569
+ },
1570
+ q
1571
+ )) })
1572
+ ] })
1573
+ ) : (
1574
+ /* Chat state — messages + structured response cards */
1575
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-4 px-3 py-3", children: [
1576
+ messages.map(
1577
+ (msg) => msg.role === "user" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1578
+ ChatWidgetMessage,
1579
+ {
1580
+ role: "user",
1581
+ content: msg.content
1582
+ },
1583
+ msg.id
1584
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
1585
+ msg.content && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-foreground leading-relaxed", children: msg.content }),
1586
+ msg.responseContent && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1587
+ ResponseCard,
1588
+ {
1589
+ content: msg.responseContent,
1590
+ queryContext: msg.queryContext
1591
+ }
1592
+ )
1593
+ ] }, msg.id)
1594
+ ),
1595
+ isStreaming && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PolicyAIThinkingSteps, { steps: resolvedThinkingSteps }),
1596
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: messagesEndRef })
1597
+ ] })
1598
+ ) }),
1599
+ !isLoading && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1600
+ "div",
1601
+ {
1602
+ className: cn(
1603
+ "border-t border-border px-3 py-3 bg-card",
1604
+ inline ? "sticky bottom-0 z-10" : "shrink-0"
1605
+ ),
1606
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1607
+ ChatInputArea,
1608
+ {
1609
+ value: inputValue,
1610
+ onChange: setInputValue,
1611
+ onSend: handleSend,
1612
+ onAttachFile,
1613
+ onAttachImage,
1614
+ disabled: isStreaming,
1615
+ placeholder: "Ask about lending policies\u2026",
1616
+ autoFocus: !minimised
1617
+ }
1618
+ )
1619
+ }
1620
+ )
1621
+ ] })
1622
+ ]
1623
+ }
1624
+ );
1625
+ }
1626
+ // Annotate the CommonJS export names for ESM import in node:
1627
+ 0 && (module.exports = {
1628
+ PolicyAIFAB,
1629
+ PolicyAIPanel,
1630
+ PolicyCitationPanel,
1631
+ PolicyComparisonTable,
1632
+ PolicyQueryChip,
1633
+ PolicyRankedList,
1634
+ PolicySingleBankAnswer,
1635
+ PolicyVerdictBadge
1636
+ });