@burdenoff/microfe-brainyrich 2026.828.1 → 2026.828.2

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 (30) hide show
  1. package/dist/brainyrich/BrainyRichRoot.d.ts.map +1 -1
  2. package/dist/brainyrich/BrainyRichRoot.js +59 -59
  3. package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
  4. package/dist/brainyrich/components/viz.d.ts.map +1 -1
  5. package/dist/brainyrich/components/viz.js +1 -1
  6. package/dist/brainyrich/components/viz.js.map +1 -1
  7. package/dist/brainyrich/pages/AiAssistantPage.js +192 -192
  8. package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
  9. package/dist/brainyrich/pages/AnalyticsPage.js +9 -9
  10. package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
  11. package/dist/brainyrich/pages/DashboardPage.js +115 -115
  12. package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
  13. package/dist/brainyrich/pages/FamilyPage.js +59 -59
  14. package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
  15. package/dist/brainyrich/pages/GoalsPage.js +285 -285
  16. package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
  17. package/dist/brainyrich/pages/InvestmentsPage.js +18 -18
  18. package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
  19. package/dist/brainyrich/pages/PortfoliosPage.d.ts.map +1 -1
  20. package/dist/brainyrich/pages/PortfoliosPage.js +322 -322
  21. package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
  22. package/dist/brainyrich/pages/ReportsPage.js +17 -17
  23. package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
  24. package/dist/brainyrich/pages/RiskPage.js +16 -16
  25. package/dist/brainyrich/pages/RiskPage.js.map +1 -1
  26. package/dist/brainyrich/pages/TaxPage.d.ts.map +1 -1
  27. package/dist/brainyrich/pages/TaxPage.js +14 -14
  28. package/dist/brainyrich/pages/TaxPage.js.map +1 -1
  29. package/dist/brainyrich/types/bra.d.ts.map +1 -1
  30. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AiAssistantPage.js","names":[],"sources":["../../../src/brainyrich/pages/AiAssistantPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AlertTriangle,\n BellRing,\n CheckCircle2,\n Info,\n Lightbulb,\n MoreHorizontal,\n Plus,\n ShieldAlert,\n XCircle,\n} from 'lucide-react';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n useAccounts,\n useAcknowledgeInsight,\n useCreateInsight,\n useDismissInsight,\n useGoals,\n useHouseholds,\n usePagedInsights,\n usePortfolios,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport { ConfirmDialog, LoadMore, SubjectPicker, parseSubject } from '../components';\nimport {\n DonutChart,\n FadeIn,\n GlassCard,\n LifecycleStepper,\n StatTile,\n type VizTone,\n} from '../components/viz';\nimport type {\n BraCreateInsightInput,\n BraInsight,\n BraInsightSeverity,\n BraInsightStatus,\n BraInsightType,\n} from '../types/bra';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n MetricGrid,\n SectionShell,\n formatDate,\n readEngineMetrics,\n statusBadgeVariant,\n} from './_shared';\n\nconst INSIGHT_TYPES: BraInsightType[] = [\n 'REBALANCE_DUE',\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n 'TAX_OPPORTUNITY',\n 'GOAL_AT_RISK',\n];\n\nconst INSIGHT_SEVERITIES: BraInsightSeverity[] = ['INFO', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];\n\nconst INSIGHT_STATUSES: BraInsightStatus[] = ['OPEN', 'ACKNOWLEDGED', 'RESOLVED', 'DISMISSED'];\n\nconst ALL = '__all__';\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\ninterface SeverityMeta {\n icon: typeof Info;\n tone: string;\n}\n\nfunction severityMeta(severity: BraInsightSeverity): SeverityMeta {\n switch (severity) {\n case 'CRITICAL':\n return { icon: ShieldAlert, tone: 'text-status-error-text' };\n case 'HIGH':\n return { icon: AlertTriangle, tone: 'text-status-error-text' };\n case 'MEDIUM':\n return { icon: BellRing, tone: 'text-status-warning-text' };\n case 'LOW':\n return { icon: Lightbulb, tone: 'text-status-warning-text' };\n case 'INFO':\n default:\n return { icon: Info, tone: 'text-text-secondary' };\n }\n}\n\nfunction severityTone(severity: BraInsightSeverity): VizTone {\n switch (severity) {\n case 'CRITICAL':\n return 'error';\n case 'HIGH':\n return 'purple';\n case 'MEDIUM':\n return 'warning';\n case 'LOW':\n return 'teal';\n case 'INFO':\n default:\n return 'info';\n }\n}\n\n/** Lifecycle steps for the triage stepper (DISMISSED is a terminal side-state). */\nconst LIFECYCLE_STEPS = ['Open', 'Acknowledged', 'Resolved'];\n\ninterface InsightFormState {\n title: string;\n type: BraInsightType;\n severity: BraInsightSeverity;\n /** Encoded `SUBJECT_TYPE:id` token from <SubjectPicker>. */\n subject: string;\n detail: string;\n metrics: string;\n ownerId: string;\n}\n\nfunction emptyForm(): InsightFormState {\n return {\n title: '',\n type: 'DRIFT',\n severity: 'MEDIUM',\n subject: '',\n detail: '',\n metrics: '',\n ownerId: '',\n };\n}\n\nexport function AiAssistantPage() {\n const { t } = useI18n();\n const translate = (key: string, fallback: string, params?: Record<string, string | number>) =>\n tWithFallback(t, key, fallback, params);\n\n const [severityFilter, setSeverityFilter] = useState<string>(ALL);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n const [typeFilter, setTypeFilter] = useState<string>(ALL);\n\n const {\n items: insights,\n hasMore,\n loadMore,\n isLoading,\n isFetchingNextPage,\n isError,\n refetch,\n } = usePagedInsights({\n ...(severityFilter !== ALL ? { severity: severityFilter as BraInsightSeverity } : {}),\n ...(statusFilter !== ALL ? { status: statusFilter as BraInsightStatus } : {}),\n });\n\n // Resolve subjectId -> referenced entity name via the list queries (react-query\n // dedupes these with the SubjectPicker's own calls).\n const accounts = useAccounts();\n const portfolios = usePortfolios();\n const goals = useGoals();\n const households = useHouseholds();\n const subjectNames = useMemo(() => {\n const map = new Map<string, string>();\n for (const a of accounts.data) map.set(a.id, a.name);\n for (const p of portfolios.data) map.set(p.id, p.name);\n for (const g of goals.data) map.set(g.id, g.name);\n for (const h of households.data) map.set(h.id, h.name);\n return map;\n }, [accounts.data, portfolios.data, goals.data, households.data]);\n\n const acknowledge = useAcknowledgeInsight();\n const dismiss = useDismissInsight();\n const resolve = useResolveInsight();\n const createInsight = useCreateInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<InsightFormState>(emptyForm);\n\n const setField = <K extends keyof InsightFormState>(key: K, value: InsightFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n // Type is not a backend filter arg — narrow client-side.\n const filtered = useMemo(\n () => (typeFilter === ALL ? insights : insights.filter((i) => i.type === typeFilter)),\n [insights, typeFilter]\n );\n\n const counts = useMemo(() => {\n const open = insights.filter((i) => i.status === 'OPEN').length;\n const critical = insights.filter((i) => i.severity === 'CRITICAL').length;\n const urgent = insights.filter(\n (i) => i.severity === 'HIGH' || i.severity === 'CRITICAL'\n ).length;\n const resolved = insights.filter((i) => i.status === 'RESOLVED').length;\n return { open, critical, urgent, resolved };\n }, [insights]);\n\n // Severity mix across the loaded inbox — drives the hero donut (real data only).\n const severityDist = useMemo(\n () =>\n INSIGHT_SEVERITIES.map((s) => ({\n label: humanize(s),\n value: insights.filter((i) => i.severity === s).length,\n tone: severityTone(s),\n })).filter((d) => d.value > 0),\n [insights]\n );\n\n const metricsValid = useMemo(() => {\n if (!form.metrics.trim()) return true;\n try {\n JSON.parse(form.metrics);\n return true;\n } catch {\n return false;\n }\n }, [form.metrics]);\n\n const formValid =\n form.title.trim().length > 0 && parseSubject(form.subject) !== null && metricsValid;\n\n const openCreate = () => {\n setForm(emptyForm());\n setCreateOpen(true);\n };\n\n const handleCreate = () => {\n if (!formValid) return;\n const subject = parseSubject(form.subject);\n if (!subject) return;\n let metrics: Record<string, unknown> | undefined;\n if (form.metrics.trim()) {\n try {\n metrics = JSON.parse(form.metrics) as Record<string, unknown>;\n } catch {\n return;\n }\n }\n const input: BraCreateInsightInput = {\n title: form.title.trim(),\n type: form.type,\n severity: form.severity,\n subjectType: subject.subjectType,\n subjectId: subject.subjectId,\n detail: form.detail.trim() || null,\n ...(metrics ? { metrics } : {}),\n ...(form.ownerId.trim() ? { ownerId: form.ownerId.trim() } : {}),\n };\n createInsight.mutate(input, { onSuccess: () => setCreateOpen(false) });\n };\n\n const anyFilterActive = severityFilter !== ALL || statusFilter !== ALL || typeFilter !== ALL;\n\n const body = () => {\n if (isLoading) return <LoadingState rows={4} />;\n if (isError)\n return (\n <ErrorState\n title={translate('brainyrich.insights.error.title', 'Could not load insights')}\n description={translate(\n 'brainyrich.insights.error.description',\n 'We could not reach the insights service. Please try again.'\n )}\n onRetry={() => refetch()}\n />\n );\n\n return (\n <>\n {/* Hero — premium KPI tiles + severity-mix donut, wired to the live inbox */}\n <FadeIn className=\"grid gap-4 lg:grid-cols-[minmax(0,1.55fr)_minmax(0,1fr)]\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4\">\n <StatTile\n label={translate('brainyrich.insights.metrics.total', 'Signals')}\n value={String(insights.length)}\n glow\n icon={<BellRing className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.open', 'Open')}\n value={String(counts.open)}\n icon={<Info className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.critical', 'Critical')}\n value={String(counts.critical)}\n deltaTone={counts.critical > 0 ? 'negative' : 'positive'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.resolved', 'Resolved')}\n value={String(counts.resolved)}\n deltaTone=\"positive\"\n icon={<CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />}\n />\n </div>\n\n <GlassCard className=\"flex min-w-0 flex-col p-5\">\n <p className=\"text-sm font-medium text-text-primary\">\n {translate('brainyrich.insights.hero.severityMix', 'Severity mix')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.insights.hero.severityMixHint',\n 'Distribution across the loaded inbox'\n )}\n </p>\n {severityDist.length > 0 ? (\n <div className=\"mt-2 min-w-0\">\n <DonutChart\n data={severityDist}\n centerLabel={translate('brainyrich.insights.hero.center', 'Signals')}\n centerValue={String(insights.length)}\n height={200}\n />\n </div>\n ) : (\n <p className=\"mt-6 text-sm text-text-secondary\">\n {translate('brainyrich.insights.hero.noData', 'No signals to chart yet.')}\n </p>\n )}\n </GlassCard>\n </FadeIn>\n\n {/* Quick-triage summary chips — toggle the underlying filters */}\n <FadeIn index={1} className=\"flex flex-wrap gap-2\">\n <SummaryChip\n label={translate('brainyrich.insights.metrics.open', 'Open')}\n count={counts.open}\n tone=\"info\"\n active={statusFilter === 'OPEN'}\n onClick={() => {\n setStatusFilter(statusFilter === 'OPEN' ? ALL : 'OPEN');\n setSeverityFilter(ALL);\n }}\n />\n <SummaryChip\n label={translate('brainyrich.insights.metrics.critical', 'Critical')}\n count={counts.critical}\n tone=\"error\"\n active={severityFilter === 'CRITICAL'}\n onClick={() => {\n setSeverityFilter(severityFilter === 'CRITICAL' ? ALL : 'CRITICAL');\n setStatusFilter(ALL);\n }}\n />\n <SummaryChip\n label={translate('brainyrich.insights.metrics.resolved', 'Resolved')}\n count={counts.resolved}\n tone=\"success\"\n active={statusFilter === 'RESOLVED'}\n onClick={() => {\n setStatusFilter(statusFilter === 'RESOLVED' ? ALL : 'RESOLVED');\n setSeverityFilter(ALL);\n }}\n />\n </FadeIn>\n\n {/* Filters */}\n <Card>\n <CardContent className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-end\">\n <div className=\"w-full space-y-1.5 sm:w-48\">\n <Label htmlFor=\"insight-filter-severity\">\n {translate('brainyrich.insights.filters.severity', 'Severity')}\n </Label>\n <Select value={severityFilter} onValueChange={setSeverityFilter}>\n <SelectTrigger id=\"insight-filter-severity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_SEVERITIES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full space-y-1.5 sm:w-48\">\n <Label htmlFor=\"insight-filter-status\">\n {translate('brainyrich.insights.filters.status', 'Status')}\n </Label>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger id=\"insight-filter-status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full space-y-1.5 sm:w-56\">\n <Label htmlFor=\"insight-filter-type\">\n {translate('brainyrich.insights.filters.type', 'Type')}\n </Label>\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger id=\"insight-filter-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_TYPES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </CardContent>\n </Card>\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={<BellRing className=\"size-6\" aria-hidden=\"true\" />}\n title={\n anyFilterActive\n ? translate('brainyrich.insights.empty.filteredTitle', 'No matching insights')\n : translate('brainyrich.insights.empty.title', 'No advisory insights yet')\n }\n description={\n anyFilterActive\n ? translate(\n 'brainyrich.insights.empty.filteredDescription',\n 'No insights match the selected filters. Adjust or clear them to see more.'\n )\n : translate(\n 'brainyrich.insights.empty.description',\n 'Advisory insights flag rebalancing, drift, concentration and other opportunities. Create one to get started.'\n )\n }\n action={\n anyFilterActive ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setSeverityFilter(ALL);\n setStatusFilter(ALL);\n setTypeFilter(ALL);\n }}\n >\n {translate('brainyrich.insights.actions.clearFilters', 'Clear filters')}\n </Button>\n ) : (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.create', 'New insight')}\n </Button>\n )\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filtered.map((insight, idx) => (\n <InsightCard\n key={insight.id}\n index={idx}\n insight={insight}\n subjectName={subjectNames.get(insight.subjectId)}\n translate={translate}\n onAcknowledge={() => acknowledge.mutate(insight.id)}\n onDismiss={() => dismiss.mutate(insight.id)}\n onResolve={() => resolve.mutate(insight.id)}\n acknowledgePending={acknowledge.isPending}\n dismissPending={dismiss.isPending}\n resolvePending={resolve.isPending}\n />\n ))}\n </div>\n )}\n\n <LoadMore\n hasMore={hasMore}\n onClick={loadMore}\n loading={isFetchingNextPage}\n label={translate('brainyrich.insights.actions.loadMore', 'Load more insights')}\n />\n </>\n );\n };\n\n return (\n <>\n <SectionShell\n title={translate('brainyrich.insights.title', 'Insights')}\n description={translate(\n 'brainyrich.insights.description',\n 'Advisory insights across portfolios, accounts and goals — triage, acknowledge and resolve.'\n )}\n badges={[translate('brainyrich.insights.badges.advisory', 'Advisory')]}\n actionLabel={translate('brainyrich.insights.actions.create', 'New insight')}\n onAction={openCreate}\n >\n {body()}\n </SectionShell>\n\n <InsightFormDialog\n open={createOpen}\n form={form}\n setField={setField}\n metricsValid={metricsValid}\n valid={formValid}\n pending={createInsight.isPending}\n onSubmit={handleCreate}\n onOpenChange={(v) => setCreateOpen(v)}\n translate={translate}\n />\n </>\n );\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\ninterface SummaryChipProps {\n label: string;\n count: number;\n tone: 'info' | 'error' | 'success';\n active: boolean;\n onClick: () => void;\n}\n\nfunction SummaryChip({ label, count, tone, active, onClick }: SummaryChipProps) {\n const dotClass =\n tone === 'error'\n ? 'bg-status-error-text'\n : tone === 'success'\n ? 'bg-status-success-text'\n : 'bg-status-info-text';\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-pressed={active}\n className={`group inline-flex items-center gap-2 rounded-full border px-3.5 py-1.5 text-sm font-medium transition-colors motion-safe:transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-action-primary-border)] ${\n active\n ? 'border-[var(--color-action-primary-border)] bg-bg-elevated text-text-primary shadow-[var(--shadow-elevation-1)]'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:border-[var(--color-action-primary-border)] hover:text-text-primary'\n }`}\n >\n <span className={`size-2 rounded-full ${dotClass}`} aria-hidden=\"true\" />\n {label}\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs tabular-nums text-text-primary\">\n {count}\n </span>\n </button>\n );\n}\n\ninterface InsightCardProps {\n index: number;\n insight: BraInsight;\n /** Referenced entity name resolved from the list queries, if known. */\n subjectName?: string;\n translate: Translate;\n onAcknowledge: () => void;\n onDismiss: () => void;\n onResolve: () => void;\n acknowledgePending: boolean;\n dismissPending: boolean;\n resolvePending: boolean;\n}\n\nfunction InsightCard({\n index,\n insight,\n subjectName,\n translate,\n onAcknowledge,\n onDismiss,\n onResolve,\n acknowledgePending,\n dismissPending,\n resolvePending,\n}: InsightCardProps) {\n const meta = severityMeta(insight.severity);\n const SeverityIcon = meta.icon;\n const isClosed = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n const isDismissed = insight.status === 'DISMISSED';\n const [dismissOpen, setDismissOpen] = useState(false);\n // `BraInsight.metrics` already ships in this page's own query result: it is\n // the engine's real inputs + the formula it applied. Rendering it is what\n // turns a severity label into a reviewable finding.\n const rationale = readEngineMetrics(insight.metrics);\n\n return (\n <FadeIn as=\"div\" index={index}>\n <Card className=\"overflow-hidden transition-shadow motion-safe:hover:shadow-[var(--shadow-elevation-2)]\">\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className={`mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-full bg-bg-sunken ${meta.tone}`}\n >\n <SeverityIcon className=\"size-5\" aria-hidden=\"true\" />\n </span>\n <div className=\"min-w-0\">\n <CardTitle className=\"text-base\">{insight.title}</CardTitle>\n <CardDescription className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.severity)}>\n <span className={`inline-flex items-center gap-1 ${meta.tone}`}>\n <SeverityIcon className=\"size-3\" aria-hidden=\"true\" />\n {humanize(insight.severity)}\n </span>\n </Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>\n {humanize(insight.status)}\n </Badge>\n </CardDescription>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate('brainyrich.insights.actions.menu', 'Insight actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n disabled={acknowledgePending || insight.status === 'ACKNOWLEDGED' || isClosed}\n onSelect={onAcknowledge}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.acknowledge', 'Acknowledge')}\n </DropdownMenuItem>\n <DropdownMenuItem\n disabled={resolvePending || insight.status === 'RESOLVED'}\n onSelect={onResolve}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.resolve', 'Resolve')}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"text-status-error-text focus:text-status-error-text\"\n disabled={dismissPending || insight.status === 'DISMISSED'}\n onSelect={(e) => {\n e.preventDefault();\n setDismissOpen(true);\n }}\n >\n <XCircle className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.dismiss', 'Dismiss')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {insight.detail ? <p className=\"text-sm text-text-secondary\">{insight.detail}</p> : null}\n\n {/* Rationale — the deterministic engine's own inputs and formula */}\n {rationale ? (\n <div className=\"space-y-2 rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n {translate('brainyrich.insights.card.rationale', 'Rationale')}\n </p>\n {rationale.formula ? (\n <p className=\"break-words text-xs text-text-secondary\">{rationale.formula}</p>\n ) : null}\n <MetricGrid entries={rationale.entries} />\n </div>\n ) : null}\n\n <dl className=\"grid grid-cols-2 gap-3 rounded-lg bg-bg-sunken p-3 text-sm sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.subjectType', 'Subject')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{humanize(insight.subjectType)}</dd>\n </div>\n <div className=\"min-w-0\">\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.subject', 'Reference')}\n </dt>\n <dd\n className=\"truncate font-medium text-text-primary\"\n title={subjectName ? `${subjectName} (${insight.subjectId})` : insight.subjectId}\n >\n {subjectName ?? insight.subjectId}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{formatDate(insight.createdAt)}</dd>\n </div>\n {insight.resolvedAt ? (\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.resolved', 'Resolved')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{formatDate(insight.resolvedAt)}</dd>\n </div>\n ) : null}\n </dl>\n {isDismissed ? (\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n <XCircle className=\"size-4 text-status-error-text\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.card.dismissed', 'Dismissed from active triage')}\n </div>\n ) : (\n <LifecycleStepper steps={LIFECYCLE_STEPS} current={humanize(insight.status)} />\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={acknowledgePending || insight.status === 'ACKNOWLEDGED' || isClosed}\n onClick={onAcknowledge}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.acknowledge', 'Acknowledge')}\n </Button>\n <Button\n size=\"sm\"\n disabled={resolvePending || insight.status === 'RESOLVED'}\n onClick={onResolve}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.resolve', 'Resolve')}\n </Button>\n </div>\n </CardContent>\n\n <ConfirmDialog\n open={dismissOpen}\n onOpenChange={setDismissOpen}\n title={translate('brainyrich.insights.dismiss.title', 'Dismiss this insight?')}\n description={translate(\n 'brainyrich.insights.dismiss.description',\n 'Dismissing removes this insight from active triage. You can still find it by filtering for dismissed insights.'\n )}\n confirmLabel={translate('brainyrich.insights.actions.dismiss', 'Dismiss')}\n pendingLabel={translate('brainyrich.insights.dismiss.pending', 'Dismissing…')}\n destructive\n pending={dismissPending}\n onConfirm={onDismiss}\n />\n </Card>\n </FadeIn>\n );\n}\n\ninterface InsightFormDialogProps {\n open: boolean;\n form: InsightFormState;\n setField: <K extends keyof InsightFormState>(key: K, value: InsightFormState[K]) => void;\n metricsValid: boolean;\n valid: boolean;\n pending: boolean;\n onSubmit: () => void;\n onOpenChange: (open: boolean) => void;\n translate: Translate;\n}\n\nfunction InsightFormDialog({\n open,\n form,\n setField,\n metricsValid,\n valid,\n pending,\n onSubmit,\n onOpenChange,\n translate,\n}: InsightFormDialogProps) {\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[90vh] overflow-y-auto sm:max-w-lg\">\n <DialogHeader>\n <DialogTitle>\n {translate('brainyrich.insights.form.createTitle', 'New insight')}\n </DialogTitle>\n <DialogDescription>\n {translate(\n 'brainyrich.insights.form.subtitle',\n 'Flag an advisory insight against a portfolio, account, goal or household.'\n )}\n </DialogDescription>\n </DialogHeader>\n\n <form\n className=\"space-y-4\"\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-title\">\n {translate('brainyrich.insights.form.title', 'Title')}\n </Label>\n <Input\n id=\"insight-title\"\n value={form.title}\n onChange={(e) => setField('title', e.target.value)}\n placeholder={translate(\n 'brainyrich.insights.form.titlePlaceholder',\n 'e.g. Technology concentration above threshold'\n )}\n required\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-type\">\n {translate('brainyrich.insights.form.type', 'Type')}\n </Label>\n <Select\n value={form.type}\n onValueChange={(v) => setField('type', v as BraInsightType)}\n >\n <SelectTrigger id=\"insight-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INSIGHT_TYPES.map((tpe) => (\n <SelectItem key={tpe} value={tpe}>\n {humanize(tpe)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-severity\">\n {translate('brainyrich.insights.form.severity', 'Severity')}\n </Label>\n <Select\n value={form.severity}\n onValueChange={(v) => setField('severity', v as BraInsightSeverity)}\n >\n <SelectTrigger id=\"insight-severity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INSIGHT_SEVERITIES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <SubjectPicker\n id=\"insight-subject\"\n label={translate('brainyrich.insights.form.subject', 'Subject')}\n placeholder={translate(\n 'brainyrich.insights.form.subjectPlaceholder',\n 'Select an account, portfolio, goal or household'\n )}\n value={form.subject}\n onChange={(v) => setField('subject', v)}\n />\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-owner\">\n {translate('brainyrich.insights.form.ownerId', 'Owner ID (optional)')}\n </Label>\n <Input\n id=\"insight-owner\"\n value={form.ownerId}\n onChange={(e) => setField('ownerId', e.target.value)}\n placeholder={translate(\n 'brainyrich.insights.form.ownerIdPlaceholder',\n 'Defaults to the current owner'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-detail\">\n {translate('brainyrich.insights.form.detail', 'Detail')}\n </Label>\n <Textarea\n id=\"insight-detail\"\n value={form.detail}\n onChange={(e) => setField('detail', e.target.value)}\n rows={3}\n placeholder={translate(\n 'brainyrich.insights.form.detailPlaceholder',\n 'Explain the finding and recommended action.'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-metrics\">\n {translate('brainyrich.insights.form.metrics', 'Metrics JSON (optional)')}\n </Label>\n <Textarea\n id=\"insight-metrics\"\n value={form.metrics}\n onChange={(e) => setField('metrics', e.target.value)}\n rows={3}\n className=\"font-mono text-xs\"\n placeholder='{ \"driftPct\": 8.2 }'\n aria-invalid={!metricsValid}\n />\n {!metricsValid ? (\n <p className=\"flex items-center gap-1 text-xs text-status-error-text\">\n <AlertTriangle className=\"size-3.5\" aria-hidden=\"true\" />\n {translate(\n 'brainyrich.insights.form.metricsInvalid',\n 'Enter valid JSON or leave blank.'\n )}\n </p>\n ) : null}\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={pending}\n >\n {translate('brainyrich.insights.form.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!valid || pending}>\n {pending\n ? translate('brainyrich.insights.form.saving', 'Saving…')\n : translate('brainyrich.insights.form.create', 'Create insight')}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAgFA,IAAM,KAAkC;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;AACF,GAEM,IAA2C;CAAC;CAAQ;CAAO;CAAU;CAAQ;AAAU,GAEvF,KAAuC;CAAC;CAAQ;CAAgB;CAAY;AAAW,GAEvF,IAAM;AAEZ,SAAS,EAAS,GAAuB;CACvC,OAAO,EACJ,YAAY,EACZ,MAAM,GAAG,EACT,KAAK,MAAS,EAAK,OAAO,CAAC,EAAE,YAAY,IAAI,EAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AACb;AAOA,SAAS,GAAa,GAA4C;CAChE,QAAQ,GAAR;EACE,KAAK,YACH,OAAO;GAAE,MAAM;GAAa,MAAM;EAAyB;EAC7D,KAAK,QACH,OAAO;GAAE,MAAM;GAAe,MAAM;EAAyB;EAC/D,KAAK,UACH,OAAO;GAAE,MAAM;GAAU,MAAM;EAA2B;EAC5D,KAAK,OACH,OAAO;GAAE,MAAM;GAAW,MAAM;EAA2B;EAE7D,SACE,OAAO;GAAE,MAAM;GAAM,MAAM;EAAsB;CACrD;AACF;AAEA,SAAS,GAAa,GAAuC;CAC3D,QAAQ,GAAR;EACE,KAAK,YACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,OACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAGA,IAAM,KAAkB;CAAC;CAAQ;CAAgB;AAAU;AAa3D,SAAS,KAA8B;CACrC,OAAO;EACL,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS;EACT,QAAQ;EACR,SAAS;EACT,SAAS;CACX;AACF;AAEA,SAAgB,IAAkB;CAChC,IAAM,EAAE,UAAM,GAAQ,GAChB,KAAa,GAAa,GAAkB,MAChD,EAAc,IAAG,GAAK,GAAU,CAAM,GAElC,CAAC,GAAgB,KAAqB,EAAiB,CAAG,GAC1D,CAAC,GAAc,KAAmB,EAAiB,CAAG,GACtD,CAAC,GAAY,KAAiB,EAAiB,CAAG,GAElD,EACJ,OAAO,GACP,aACA,aACA,cACA,wBACA,aACA,gBACE,EAAiB;EACnB,GAAI,MAAmB,IAA2D,CAAC,IAAtD,EAAE,UAAU,EAAqC;EAC9E,GAAI,MAAiB,IAAqD,CAAC,IAAhD,EAAE,QAAQ,EAAiC;CACxE,CAAC,GAIK,IAAW,EAAY,GACvB,IAAa,EAAc,GAC3B,IAAQ,EAAS,GACjB,IAAa,EAAc,GAC3B,KAAe,QAAc;EACjC,IAAM,oBAAM,IAAI,IAAoB;EACpC,KAAK,IAAM,KAAK,EAAS,MAAM,EAAI,IAAI,EAAE,IAAI,EAAE,IAAI;EACnD,KAAK,IAAM,KAAK,EAAW,MAAM,EAAI,IAAI,EAAE,IAAI,EAAE,IAAI;EACrD,KAAK,IAAM,KAAK,EAAM,MAAM,EAAI,IAAI,EAAE,IAAI,EAAE,IAAI;EAChD,KAAK,IAAM,KAAK,EAAW,MAAM,EAAI,IAAI,EAAE,IAAI,EAAE,IAAI;EACrD,OAAO;CACT,GAAG;EAAC,EAAS;EAAM,EAAW;EAAM,EAAM;EAAM,EAAW;CAAI,CAAC,GAE1D,IAAc,EAAsB,GACpC,IAAU,EAAkB,GAC5B,IAAU,EAAkB,GAC5B,IAAgB,EAAiB,GAEjC,CAAC,IAAY,KAAiB,EAAS,EAAK,GAC5C,CAAC,GAAM,KAAW,EAA2B,EAAS,GAEtD,MAA8C,GAAQ,MAC1D,GAAS,OAAU;EAAE,GAAG;GAAO,IAAM;CAAM,EAAE,GAGzC,KAAW,QACR,MAAe,IAAM,IAAW,EAAS,QAAQ,MAAM,EAAE,SAAS,CAAU,GACnF,CAAC,GAAU,CAAU,CACvB,GAEM,IAAS,SAON;EAAE,MANI,EAAS,QAAQ,MAAM,EAAE,WAAW,MAAM,EAAE;EAM1C,UALE,EAAS,QAAQ,MAAM,EAAE,aAAa,UAAU,EAAE;EAK1C,QAJV,EAAS,QACrB,MAAM,EAAE,aAAa,UAAU,EAAE,aAAa,UACjD,EAAE;EAE+B,UADhB,EAAS,QAAQ,MAAM,EAAE,WAAW,UAAU,EAAE;CACvB,IACzC,CAAC,CAAQ,CAAC,GAGP,KAAe,QAEjB,EAAmB,KAAK,OAAO;EAC7B,OAAO,EAAS,CAAC;EACjB,OAAO,EAAS,QAAQ,MAAM,EAAE,aAAa,CAAC,EAAE;EAChD,MAAM,GAAa,CAAC;CACtB,EAAE,EAAE,QAAQ,MAAM,EAAE,QAAQ,CAAC,GAC/B,CAAC,CAAQ,CACX,GAEM,KAAe,QAAc;EACjC,IAAI,CAAC,EAAK,QAAQ,KAAK,GAAG,OAAO;EACjC,IAAI;GAEF,OADA,KAAK,MAAM,EAAK,OAAO,GAChB;EACT,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,EAAK,OAAO,CAAC,GAEX,KACJ,EAAK,MAAM,KAAK,EAAE,SAAS,KAAK,EAAa,EAAK,OAAO,MAAM,QAAQ,IAEnE,WAAmB;EAEvB,AADA,EAAQ,GAAU,CAAC,GACnB,EAAc,EAAI;CACpB,GAEM,WAAqB;EACzB,IAAI,CAAC,IAAW;EAChB,IAAM,IAAU,EAAa,EAAK,OAAO;EACzC,IAAI,CAAC,GAAS;EACd,IAAI;EACJ,IAAI,EAAK,QAAQ,KAAK,GACpB,IAAI;GACF,IAAU,KAAK,MAAM,EAAK,OAAO;EACnC,QAAQ;GACN;EACF;EAEF,IAAM,IAA+B;GACnC,OAAO,EAAK,MAAM,KAAK;GACvB,MAAM,EAAK;GACX,UAAU,EAAK;GACf,aAAa,EAAQ;GACrB,WAAW,EAAQ;GACnB,QAAQ,EAAK,OAAO,KAAK,KAAK;GAC9B,GAAI,IAAU,EAAE,WAAQ,IAAI,CAAC;GAC7B,GAAI,EAAK,QAAQ,KAAK,IAAI,EAAE,SAAS,EAAK,QAAQ,KAAK,EAAE,IAAI,CAAC;EAChE;EACA,EAAc,OAAO,GAAO,EAAE,iBAAiB,EAAc,EAAK,EAAE,CAAC;CACvE,GAEM,KAAkB,MAAmB,KAAO,MAAiB,KAAO,MAAe;CAmPzF,OACE,kBAAA,IAAA,EAAA,UAAA,CACE,kBAAC,IAAD;EACE,OAAO,EAAU,6BAA6B,UAAU;EACxD,aAAa,EACX,mCACA,4FACF;EACA,QAAQ,CAAC,EAAU,uCAAuC,UAAU,CAAC;EACrE,aAAa,EAAU,sCAAsC,aAAa;EAC1E,UAAU;YA1PV,IAAkB,kBAAC,IAAD,EAAc,MAAM,EAAI,CAAA,IAC1C,KAEA,kBAAC,IAAD;GACE,OAAO,EAAU,mCAAmC,yBAAyB;GAC7E,aAAa,EACX,yCACA,4DACF;GACA,eAAe,GAAQ;EACxB,CAAA,IAIH,kBAAA,IAAA,EAAA,UAAA;GAEE,kBAAC,GAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,OAAO,EAAU,qCAAqC,SAAS;OAC/D,OAAO,OAAO,EAAS,MAAM;OAC7B,MAAA;OACA,MAAM,kBAAC,IAAD;QAAU,WAAU;QAAS,eAAY;OAAQ,CAAA;MACxD,CAAA;MACD,kBAAC,GAAD;OACE,OAAO,EAAU,oCAAoC,MAAM;OAC3D,OAAO,OAAO,EAAO,IAAI;OACzB,MAAM,kBAAC,IAAD;QAAM,WAAU;QAAS,eAAY;OAAQ,CAAA;MACpD,CAAA;MACD,kBAAC,GAAD;OACE,OAAO,EAAU,wCAAwC,UAAU;OACnE,OAAO,OAAO,EAAO,QAAQ;OAC7B,WAAW,EAAO,WAAW,IAAI,aAAa;OAC9C,MAAM,kBAAC,IAAD;QAAa,WAAU;QAAS,eAAY;OAAQ,CAAA;MAC3D,CAAA;MACD,kBAAC,GAAD;OACE,OAAO,EAAU,wCAAwC,UAAU;OACnE,OAAO,OAAO,EAAO,QAAQ;OAC7B,WAAU;OACV,MAAM,kBAAC,GAAD;QAAc,WAAU;QAAS,eAAY;OAAQ,CAAA;MAC5D,CAAA;KACE;QAEL,kBAAC,GAAD;KAAW,WAAU;eAArB;MACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAU,wCAAwC,cAAc;MAChE,CAAA;MACH,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,4CACA,sCACF;MACC,CAAA;MACF,GAAa,SAAS,IACrB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QACE,MAAM;QACN,aAAa,EAAU,mCAAmC,SAAS;QACnE,aAAa,OAAO,EAAS,MAAM;QACnC,QAAQ;OACT,CAAA;MACE,CAAA,IAEL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAU,mCAAmC,0BAA0B;MACvE,CAAA;KAEI;MACL;;GAGR,kBAAC,GAAD;IAAQ,OAAO;IAAG,WAAU;cAA5B;KACE,kBAAC,IAAD;MACE,OAAO,EAAU,oCAAoC,MAAM;MAC3D,OAAO,EAAO;MACd,MAAK;MACL,QAAQ,MAAiB;MACzB,eAAe;OAEb,AADA,EAAgB,MAAiB,SAAS,IAAM,MAAM,GACtD,EAAkB,CAAG;MACvB;KACD,CAAA;KACD,kBAAC,IAAD;MACE,OAAO,EAAU,wCAAwC,UAAU;MACnE,OAAO,EAAO;MACd,MAAK;MACL,QAAQ,MAAmB;MAC3B,eAAe;OAEb,AADA,EAAkB,MAAmB,aAAa,IAAM,UAAU,GAClE,EAAgB,CAAG;MACrB;KACD,CAAA;KACD,kBAAC,IAAD;MACE,OAAO,EAAU,wCAAwC,UAAU;MACnE,OAAO,EAAO;MACd,MAAK;MACL,QAAQ,MAAiB;MACzB,eAAe;OAEb,AADA,EAAgB,MAAiB,aAAa,IAAM,UAAU,GAC9D,EAAkB,CAAG;MACvB;KACD,CAAA;IACK;;GAGR,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD;IAAa,WAAU;cAAvB;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,wCAAwC,UAAU;MACxD,CAAA,GACP,kBAAC,GAAD;OAAQ,OAAO;OAAgB,eAAe;iBAA9C,CACE,kBAAC,GAAD;QAAe,IAAG;kBAChB,kBAAC,GAAD,CAAc,CAAA;OACD,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAY,OAAO;kBAChB,EAAU,mCAAmC,KAAK;OACzC,CAAA,GACX,EAAmB,KAAK,MACvB,kBAAC,GAAD;QAAoB,OAAO;kBACxB,EAAS,CAAC;OACD,GAFK,CAEL,CACb,CACY,EAAA,CAAA,CACT;QACL;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,sCAAsC,QAAQ;MACpD,CAAA,GACP,kBAAC,GAAD;OAAQ,OAAO;OAAc,eAAe;iBAA5C,CACE,kBAAC,GAAD;QAAe,IAAG;kBAChB,kBAAC,GAAD,CAAc,CAAA;OACD,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAY,OAAO;kBAChB,EAAU,mCAAmC,KAAK;OACzC,CAAA,GACX,GAAiB,KAAK,MACrB,kBAAC,GAAD;QAAoB,OAAO;kBACxB,EAAS,CAAC;OACD,GAFK,CAEL,CACb,CACY,EAAA,CAAA,CACT;QACL;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,oCAAoC,MAAM;MAChD,CAAA,GACP,kBAAC,GAAD;OAAQ,OAAO;OAAY,eAAe;iBAA1C,CACE,kBAAC,GAAD;QAAe,IAAG;kBAChB,kBAAC,GAAD,CAAc,CAAA;OACD,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAY,OAAO;kBAChB,EAAU,mCAAmC,KAAK;OACzC,CAAA,GACX,GAAc,KAAK,MAClB,kBAAC,GAAD;QAAoB,OAAO;kBACxB,EAAS,CAAC;OACD,GAFK,CAEL,CACb,CACY,EAAA,CAAA,CACT;QACL;;IACM;MACT,CAAA;GAEL,GAAS,WAAW,IACnB,kBAAC,GAAD;IACE,MAAM,kBAAC,IAAD;KAAU,WAAU;KAAS,eAAY;IAAQ,CAAA;IACvD,OACE,KACI,EAAU,2CAA2C,sBAAsB,IAC3E,EAAU,mCAAmC,0BAA0B;IAE7E,aACE,KACI,EACE,iDACA,2EACF,IACA,EACE,yCACA,8GACF;IAEN,QACE,KACE,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe;MAGb,AAFA,EAAkB,CAAG,GACrB,EAAgB,CAAG,GACnB,EAAc,CAAG;KACnB;eAEC,EAAU,4CAA4C,eAAe;IAChE,CAAA,IAER,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAAS;eAA3B,CACE,kBAAC,IAAD;MAAM,WAAU;MAAS,eAAY;KAAQ,CAAA,GAC5C,EAAU,sCAAsC,aAAa,CACxD;;GAGb,CAAA,IAED,kBAAC,OAAD;IAAK,WAAU;cACZ,GAAS,KAAK,GAAS,MACtB,kBAAC,IAAD;KAEE,OAAO;KACE;KACT,aAAa,GAAa,IAAI,EAAQ,SAAS;KACpC;KACX,qBAAqB,EAAY,OAAO,EAAQ,EAAE;KAClD,iBAAiB,EAAQ,OAAO,EAAQ,EAAE;KAC1C,iBAAiB,EAAQ,OAAO,EAAQ,EAAE;KAC1C,oBAAoB,EAAY;KAChC,gBAAgB,EAAQ;KACxB,gBAAgB,EAAQ;IACzB,GAXM,EAAQ,EAWd,CACF;GACE,CAAA;GAGP,kBAAC,GAAD;IACW;IACT,SAAS;IACT,SAAS;IACT,OAAO,EAAU,wCAAwC,oBAAoB;GAC9E,CAAA;EACD,EAAA,CAAA;CAiBY,CAAA,GAEd,kBAAC,IAAD;EACE,MAAM;EACA;EACI;EACI;EACd,OAAO;EACP,SAAS,EAAc;EACvB,UAAU;EACV,eAAe,MAAM,EAAc,CAAC;EACzB;CACZ,CAAA,CACD,EAAA,CAAA;AAEN;AAgBA,SAAS,GAAY,EAAE,UAAO,UAAO,SAAM,WAAQ,cAA6B;CAO9E,OACE,kBAAC,UAAD;EACE,MAAK;EACI;EACT,gBAAc;EACd,WAAW,sPACT,IACI,oHACA;YAPR;GAUE,kBAAC,QAAD;IAAM,WAAW,uBAhBnB,MAAS,UACL,yBACA,MAAS,YACP,2BACA;IAYgD,eAAY;GAAQ,CAAA;GACvE;GACD,kBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA;EACA;;AAEZ;AAgBA,SAAS,GAAY,EACnB,UACA,YACA,gBACA,cACA,kBACA,cACA,cACA,uBACA,mBACA,qBACmB;CACnB,IAAM,IAAO,GAAa,EAAQ,QAAQ,GACpC,IAAe,EAAK,MACpB,IAAW,EAAQ,WAAW,cAAc,EAAQ,WAAW,aAC/D,IAAc,EAAQ,WAAW,aACjC,CAAC,GAAa,KAAkB,EAAS,EAAK,GAI9C,IAAY,EAAkB,EAAQ,OAAO;CAEnD,OACE,kBAAC,GAAD;EAAQ,IAAG;EAAa;YACtB,kBAAC,IAAD;GAAM,WAAU;aAAhB;IACE,kBAAC,IAAD;KAAY,WAAU;eACpB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QACE,WAAW,qFAAqF,EAAK;kBAErG,kBAAC,GAAD;SAAc,WAAU;SAAS,eAAY;QAAQ,CAAA;OACjD,CAAA,GACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD;SAAW,WAAU;mBAAa,EAAQ;QAAiB,CAAA,GAC3D,kBAAC,IAAD;SAAiB,WAAU;mBAA3B;UACE,kBAAC,GAAD;WAAO,SAAQ;qBAAW,EAAS,EAAQ,IAAI;UAAS,CAAA;UACxD,kBAAC,GAAD;WAAO,SAAS,EAAmB,EAAQ,QAAQ;qBACjD,kBAAC,QAAD;YAAM,WAAW,kCAAkC,EAAK;sBAAxD,CACE,kBAAC,GAAD;aAAc,WAAU;aAAS,eAAY;YAAQ,CAAA,GACpD,EAAS,EAAQ,QAAQ,CACtB;;UACD,CAAA;UACP,kBAAC,GAAD;WAAO,SAAS,EAAmB,EAAQ,MAAM;qBAC9C,EAAS,EAAQ,MAAM;UACnB,CAAA;SACQ;UACd;SACF;UACL,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAqB,SAAA;iBACnB,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,cAAY,EAAU,oCAAoC,iBAAiB;kBAE3E,kBAAC,IAAD;SAAgB,WAAU;SAAS,eAAY;QAAQ,CAAA;OACjD,CAAA;MACW,CAAA,GACrB,kBAAC,GAAD;OAAqB,OAAM;iBAA3B;QACE,kBAAC,GAAD;SACE,UAAU,KAAsB,EAAQ,WAAW,kBAAkB;SACrE,UAAU;mBAFZ,CAIE,kBAAC,GAAD;UAAc,WAAU;UAAS,eAAY;SAAQ,CAAA,GACpD,EAAU,2CAA2C,aAAa,CACnD;;QAClB,kBAAC,GAAD;SACE,UAAU,KAAkB,EAAQ,WAAW;SAC/C,UAAU;mBAFZ,CAIE,kBAAC,GAAD;UAAc,WAAU;UAAS,eAAY;SAAQ,CAAA,GACpD,EAAU,uCAAuC,SAAS,CAC3C;;QAClB,kBAAC,IAAD,CAAwB,CAAA;QACxB,kBAAC,GAAD;SACE,WAAU;SACV,UAAU,KAAkB,EAAQ,WAAW;SAC/C,WAAW,MAAM;UAEf,AADA,EAAE,eAAe,GACjB,EAAe,EAAI;SACrB;mBANF,CAQE,kBAAC,GAAD;UAAS,WAAU;UAAS,eAAY;SAAQ,CAAA,GAC/C,EAAU,uCAAuC,SAAS,CAC3C;;OACC;QACT,EAAA,CAAA,CACX;;IACK,CAAA;IACZ,kBAAC,IAAD;KAAa,WAAU;eAAvB;MACG,EAAQ,SAAS,kBAAC,KAAD;OAAG,WAAU;iBAA+B,EAAQ;MAAU,CAAA,IAAI;MAGnF,IACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAU,sCAAsC,WAAW;QAC3D,CAAA;QACF,EAAU,UACT,kBAAC,KAAD;SAAG,WAAU;mBAA2C,EAAU;QAAW,CAAA,IAC3E;QACJ,kBAAC,GAAD,EAAY,SAAS,EAAU,QAAU,CAAA;OACtC;WACH;MAEJ,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAU,wCAAwC,SAAS;QAC1D,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBAAiC,EAAS,EAAQ,WAAW;QAAM,CAAA,CAC9E,EAAA,CAAA;QACL,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAU,oCAAoC,WAAW;SACxD,CAAA,GACJ,kBAAC,MAAD;UACE,WAAU;UACV,OAAO,IAAc,GAAG,EAAY,IAAI,EAAQ,UAAU,KAAK,EAAQ;oBAEtE,KAAe,EAAQ;SACtB,CAAA,CACD;;QACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAU,oCAAoC,SAAS;QACtD,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBAAiC,EAAW,EAAQ,SAAS;QAAM,CAAA,CAC9E,EAAA,CAAA;QACJ,EAAQ,aACP,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAU,qCAAqC,UAAU;QACxD,CAAA,GACJ,kBAAC,MAAD;SAAI,WAAU;mBAAiC,EAAW,EAAQ,UAAU;QAAM,CAAA,CAC/E,EAAA,CAAA,IACH;OACF;;MACH,IACC,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAS,WAAU;QAAgC,eAAY;OAAQ,CAAA,GACtE,EAAU,sCAAsC,8BAA8B,CAC5E;WAEL,kBAAC,GAAD;OAAkB,OAAO;OAAiB,SAAS,EAAS,EAAQ,MAAM;MAAI,CAAA;MAEhF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,UAAU,KAAsB,EAAQ,WAAW,kBAAkB;QACrE,SAAS;kBAJX,CAME,kBAAC,GAAD;SAAc,WAAU;SAAS,eAAY;QAAQ,CAAA,GACpD,EAAU,2CAA2C,aAAa,CAC7D;WACR,kBAAC,GAAD;QACE,MAAK;QACL,UAAU,KAAkB,EAAQ,WAAW;QAC/C,SAAS;kBAHX,CAKE,kBAAC,GAAD;SAAc,WAAU;SAAS,eAAY;QAAQ,CAAA,GACpD,EAAU,uCAAuC,SAAS,CACrD;SACL;;KACM;;IAEb,kBAAC,IAAD;KACE,MAAM;KACN,cAAc;KACd,OAAO,EAAU,qCAAqC,uBAAuB;KAC7E,aAAa,EACX,2CACA,gHACF;KACA,cAAc,EAAU,uCAAuC,SAAS;KACxE,cAAc,EAAU,uCAAuC,aAAa;KAC5E,aAAA;KACA,SAAS;KACT,WAAW;IACZ,CAAA;GACG;;CACA,CAAA;AAEZ;AAcA,SAAS,GAAkB,EACzB,SACA,SACA,aACA,iBACA,UACA,YACA,aACA,iBACA,gBACyB;CACzB,OACE,kBAAC,GAAD;EAAc;EAAoB;YAChC,kBAAC,GAAD;GAAe,WAAU;aAAzB,CACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACG,EAAU,wCAAwC,aAAa,EACrD,CAAA,GACb,kBAAC,GAAD,EAAA,UACG,EACC,qCACA,2EACF,EACiB,CAAA,CACP,EAAA,CAAA,GAEd,kBAAC,QAAD;IACE,WAAU;IACV,WAAW,MAAM;KAEf,AADA,EAAE,eAAe,GACjB,EAAS;IACX;cALF;KAOE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,kCAAkC,OAAO;MAC/C,CAAA,GACP,kBAAC,GAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,SAAS,EAAE,OAAO,KAAK;OACjD,aAAa,EACX,6CACA,+CACF;OACA,UAAA;MACD,CAAA,CACE;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,iCAAiC,MAAM;OAC7C,CAAA,GACP,kBAAC,GAAD;QACE,OAAO,EAAK;QACZ,gBAAgB,MAAM,EAAS,QAAQ,CAAmB;kBAF5D,CAIE,kBAAC,GAAD;SAAe,IAAG;mBAChB,kBAAC,GAAD,CAAc,CAAA;QACD,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,GAAc,KAAK,MAClB,kBAAC,GAAD;SAAsB,OAAO;mBAC1B,EAAS,CAAG;QACH,GAFK,CAEL,CACb,EACY,CAAA,CACT;SACL;UACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,qCAAqC,UAAU;OACrD,CAAA,GACP,kBAAC,GAAD;QACE,OAAO,EAAK;QACZ,gBAAgB,MAAM,EAAS,YAAY,CAAuB;kBAFpE,CAIE,kBAAC,GAAD;SAAe,IAAG;mBAChB,kBAAC,GAAD,CAAc,CAAA;QACD,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAmB,KAAK,MACvB,kBAAC,GAAD;SAAoB,OAAO;mBACxB,EAAS,CAAC;QACD,GAFK,CAEL,CACb,EACY,CAAA,CACT;SACL;QACF;;KAEL,kBAAC,GAAD;MACE,IAAG;MACH,OAAO,EAAU,oCAAoC,SAAS;MAC9D,aAAa,EACX,+CACA,iDACF;MACA,OAAO,EAAK;MACZ,WAAW,MAAM,EAAS,WAAW,CAAC;KACvC,CAAA;KAED,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,oCAAoC,qBAAqB;MAC/D,CAAA,GACP,kBAAC,GAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,WAAW,EAAE,OAAO,KAAK;OACnD,aAAa,EACX,+CACA,+BACF;MACD,CAAA,CACE;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBACZ,EAAU,mCAAmC,QAAQ;MACjD,CAAA,GACP,kBAAC,GAAD;OACE,IAAG;OACH,OAAO,EAAK;OACZ,WAAW,MAAM,EAAS,UAAU,EAAE,OAAO,KAAK;OAClD,MAAM;OACN,aAAa,EACX,8CACA,6CACF;MACD,CAAA,CACE;;KAEL,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QAAO,SAAQ;kBACZ,EAAU,oCAAoC,yBAAyB;OACnE,CAAA;OACP,kBAAC,GAAD;QACE,IAAG;QACH,OAAO,EAAK;QACZ,WAAW,MAAM,EAAS,WAAW,EAAE,OAAO,KAAK;QACnD,MAAM;QACN,WAAU;QACV,aAAY;QACZ,gBAAc,CAAC;OAChB,CAAA;OACC,IAQE,OAPF,kBAAC,KAAD;QAAG,WAAU;kBAAb,CACE,kBAAC,GAAD;SAAe,WAAU;SAAW,eAAY;QAAQ,CAAA,GACvD,EACC,2CACA,kCACF,CACC;;MAEF;;KAEL,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MACE,MAAK;MACL,SAAQ;MACR,eAAe,EAAa,EAAK;MACjC,UAAU;gBAET,EAAU,mCAAmC,QAAQ;KAChD,CAAA,GACR,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU,CAAC,KAAS;gBACvC,IACG,EAAU,mCAAmC,SAAS,IACtD,EAAU,mCAAmC,gBAAgB;KAC3D,CAAA,CACI,EAAA,CAAA;IACV;KACO;;CACT,CAAA;AAEZ"}
1
+ {"version":3,"file":"AiAssistantPage.js","names":[],"sources":["../../../src/brainyrich/pages/AiAssistantPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AlertTriangle,\n BellRing,\n CheckCircle2,\n Info,\n Lightbulb,\n MoreHorizontal,\n Plus,\n ShieldAlert,\n XCircle,\n} from 'lucide-react';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n useAccounts,\n useAcknowledgeInsight,\n useCreateInsight,\n useDismissInsight,\n useGoals,\n useHouseholds,\n usePagedInsights,\n usePortfolios,\n useResolveInsight,\n} from '../hooks/useBrainyRichApi';\nimport { ConfirmDialog, LoadMore, SubjectPicker, parseSubject } from '../components';\nimport {\n DonutChart,\n FadeIn,\n GlassCard,\n LifecycleStepper,\n StatTile,\n type VizTone,\n} from '../components/viz';\nimport type {\n BraCreateInsightInput,\n BraInsight,\n BraInsightSeverity,\n BraInsightStatus,\n BraInsightType,\n} from '../types/bra';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n MetricGrid,\n SectionShell,\n formatDate,\n readEngineMetrics,\n statusBadgeVariant,\n} from './_shared';\n\nconst INSIGHT_TYPES: BraInsightType[] = [\n 'REBALANCE_DUE',\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n 'TAX_OPPORTUNITY',\n 'GOAL_AT_RISK',\n];\n\nconst INSIGHT_SEVERITIES: BraInsightSeverity[] = ['INFO', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];\n\nconst INSIGHT_STATUSES: BraInsightStatus[] = ['OPEN', 'ACKNOWLEDGED', 'RESOLVED', 'DISMISSED'];\n\nconst ALL = '__all__';\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\ninterface SeverityMeta {\n icon: typeof Info;\n tone: string;\n}\n\nfunction severityMeta(severity: BraInsightSeverity): SeverityMeta {\n switch (severity) {\n case 'CRITICAL':\n return { icon: ShieldAlert, tone: 'text-status-error-text' };\n case 'HIGH':\n return { icon: AlertTriangle, tone: 'text-status-error-text' };\n case 'MEDIUM':\n return { icon: BellRing, tone: 'text-status-warning-text' };\n case 'LOW':\n return { icon: Lightbulb, tone: 'text-status-warning-text' };\n case 'INFO':\n default:\n return { icon: Info, tone: 'text-text-secondary' };\n }\n}\n\nfunction severityTone(severity: BraInsightSeverity): VizTone {\n switch (severity) {\n case 'CRITICAL':\n return 'error';\n case 'HIGH':\n return 'purple';\n case 'MEDIUM':\n return 'warning';\n case 'LOW':\n return 'teal';\n case 'INFO':\n default:\n return 'info';\n }\n}\n\n/** Lifecycle steps for the triage stepper (DISMISSED is a terminal side-state). */\nconst LIFECYCLE_STEPS = ['Open', 'Acknowledged', 'Resolved'];\n\ninterface InsightFormState {\n title: string;\n type: BraInsightType;\n severity: BraInsightSeverity;\n /** Encoded `SUBJECT_TYPE:id` token from <SubjectPicker>. */\n subject: string;\n detail: string;\n metrics: string;\n ownerId: string;\n}\n\nfunction emptyForm(): InsightFormState {\n return {\n title: '',\n type: 'DRIFT',\n severity: 'MEDIUM',\n subject: '',\n detail: '',\n metrics: '',\n ownerId: '',\n };\n}\n\nexport function AiAssistantPage() {\n const { t } = useI18n();\n const translate = (key: string, fallback: string, params?: Record<string, string | number>) =>\n tWithFallback(t, key, fallback, params);\n\n const [severityFilter, setSeverityFilter] = useState<string>(ALL);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n const [typeFilter, setTypeFilter] = useState<string>(ALL);\n\n const {\n items: insights,\n hasMore,\n loadMore,\n isLoading,\n isFetchingNextPage,\n isError,\n refetch,\n } = usePagedInsights({\n ...(severityFilter !== ALL ? { severity: severityFilter as BraInsightSeverity } : {}),\n ...(statusFilter !== ALL ? { status: statusFilter as BraInsightStatus } : {}),\n });\n\n // Resolve subjectId -> referenced entity name via the list queries (react-query\n // dedupes these with the SubjectPicker's own calls).\n const accounts = useAccounts();\n const portfolios = usePortfolios();\n const goals = useGoals();\n const households = useHouseholds();\n const subjectNames = useMemo(() => {\n const map = new Map<string, string>();\n for (const a of accounts.data) map.set(a.id, a.name);\n for (const p of portfolios.data) map.set(p.id, p.name);\n for (const g of goals.data) map.set(g.id, g.name);\n for (const h of households.data) map.set(h.id, h.name);\n return map;\n }, [accounts.data, portfolios.data, goals.data, households.data]);\n\n const acknowledge = useAcknowledgeInsight();\n const dismiss = useDismissInsight();\n const resolve = useResolveInsight();\n const createInsight = useCreateInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<InsightFormState>(emptyForm);\n\n const setField = <K extends keyof InsightFormState>(key: K, value: InsightFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n // Type is not a backend filter arg — narrow client-side.\n const filtered = useMemo(\n () => (typeFilter === ALL ? insights : insights.filter((i) => i.type === typeFilter)),\n [insights, typeFilter]\n );\n\n const counts = useMemo(() => {\n const open = insights.filter((i) => i.status === 'OPEN').length;\n const critical = insights.filter((i) => i.severity === 'CRITICAL').length;\n const urgent = insights.filter(\n (i) => i.severity === 'HIGH' || i.severity === 'CRITICAL'\n ).length;\n const resolved = insights.filter((i) => i.status === 'RESOLVED').length;\n return { open, critical, urgent, resolved };\n }, [insights]);\n\n // Severity mix across the loaded inbox — drives the hero donut (real data only).\n const severityDist = useMemo(\n () =>\n INSIGHT_SEVERITIES.map((s) => ({\n label: humanize(s),\n value: insights.filter((i) => i.severity === s).length,\n tone: severityTone(s),\n })).filter((d) => d.value > 0),\n [insights]\n );\n\n const metricsValid = useMemo(() => {\n if (!form.metrics.trim()) return true;\n try {\n JSON.parse(form.metrics);\n return true;\n } catch {\n return false;\n }\n }, [form.metrics]);\n\n const formValid =\n form.title.trim().length > 0 && parseSubject(form.subject) !== null && metricsValid;\n\n const openCreate = () => {\n setForm(emptyForm());\n setCreateOpen(true);\n };\n\n const handleCreate = () => {\n if (!formValid) return;\n const subject = parseSubject(form.subject);\n if (!subject) return;\n let metrics: Record<string, unknown> | undefined;\n if (form.metrics.trim()) {\n try {\n metrics = JSON.parse(form.metrics) as Record<string, unknown>;\n } catch {\n return;\n }\n }\n const input: BraCreateInsightInput = {\n title: form.title.trim(),\n type: form.type,\n severity: form.severity,\n subjectType: subject.subjectType,\n subjectId: subject.subjectId,\n detail: form.detail.trim() || null,\n ...(metrics ? { metrics } : {}),\n ...(form.ownerId.trim() ? { ownerId: form.ownerId.trim() } : {}),\n };\n createInsight.mutate(input, { onSuccess: () => setCreateOpen(false) });\n };\n\n const anyFilterActive = severityFilter !== ALL || statusFilter !== ALL || typeFilter !== ALL;\n\n const body = () => {\n if (isLoading) return <LoadingState rows={4} />;\n if (isError)\n return (\n <ErrorState\n title={translate('brainyrich.insights.error.title', 'Could not load insights')}\n description={translate(\n 'brainyrich.insights.error.description',\n 'We could not reach the insights service. Please try again.'\n )}\n onRetry={() => refetch()}\n />\n );\n\n return (\n <>\n {/* Hero — premium KPI tiles + severity-mix donut, wired to the live inbox */}\n <FadeIn className=\"grid gap-4 lg:grid-cols-[minmax(0,1.55fr)_minmax(0,1fr)]\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4\">\n <StatTile\n label={translate('brainyrich.insights.metrics.total', 'Signals')}\n value={String(insights.length)}\n glow\n icon={<BellRing className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.open', 'Open')}\n value={String(counts.open)}\n icon={<Info className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.critical', 'Critical')}\n value={String(counts.critical)}\n deltaTone={counts.critical > 0 ? 'negative' : 'positive'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label={translate('brainyrich.insights.metrics.resolved', 'Resolved')}\n value={String(counts.resolved)}\n deltaTone=\"positive\"\n icon={<CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />}\n />\n </div>\n\n <GlassCard className=\"flex min-w-0 flex-col p-5\">\n <p className=\"text-sm font-medium text-text-primary\">\n {translate('brainyrich.insights.hero.severityMix', 'Severity mix')}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {translate(\n 'brainyrich.insights.hero.severityMixHint',\n 'Distribution across the loaded inbox'\n )}\n </p>\n {severityDist.length > 0 ? (\n <div className=\"mt-2 min-w-0\">\n <DonutChart\n data={severityDist}\n centerLabel={translate('brainyrich.insights.hero.center', 'Signals')}\n centerValue={String(insights.length)}\n height={200}\n />\n </div>\n ) : (\n <p className=\"mt-6 text-sm text-text-secondary\">\n {translate('brainyrich.insights.hero.noData', 'No signals to chart yet.')}\n </p>\n )}\n </GlassCard>\n </FadeIn>\n\n {/* Quick-triage summary chips — toggle the underlying filters */}\n <FadeIn index={1} className=\"flex flex-wrap gap-2\">\n <SummaryChip\n label={translate('brainyrich.insights.metrics.open', 'Open')}\n count={counts.open}\n tone=\"info\"\n active={statusFilter === 'OPEN'}\n onClick={() => {\n setStatusFilter(statusFilter === 'OPEN' ? ALL : 'OPEN');\n setSeverityFilter(ALL);\n }}\n />\n <SummaryChip\n label={translate('brainyrich.insights.metrics.critical', 'Critical')}\n count={counts.critical}\n tone=\"error\"\n active={severityFilter === 'CRITICAL'}\n onClick={() => {\n setSeverityFilter(severityFilter === 'CRITICAL' ? ALL : 'CRITICAL');\n setStatusFilter(ALL);\n }}\n />\n <SummaryChip\n label={translate('brainyrich.insights.metrics.resolved', 'Resolved')}\n count={counts.resolved}\n tone=\"success\"\n active={statusFilter === 'RESOLVED'}\n onClick={() => {\n setStatusFilter(statusFilter === 'RESOLVED' ? ALL : 'RESOLVED');\n setSeverityFilter(ALL);\n }}\n />\n </FadeIn>\n\n {/* Filters */}\n <Card>\n <CardContent className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-end\">\n <div className=\"w-full space-y-1.5 sm:w-48\">\n <Label htmlFor=\"insight-filter-severity\">\n {translate('brainyrich.insights.filters.severity', 'Severity')}\n </Label>\n <Select value={severityFilter} onValueChange={setSeverityFilter}>\n <SelectTrigger id=\"insight-filter-severity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_SEVERITIES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full space-y-1.5 sm:w-48\">\n <Label htmlFor=\"insight-filter-status\">\n {translate('brainyrich.insights.filters.status', 'Status')}\n </Label>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger id=\"insight-filter-status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full space-y-1.5 sm:w-56\">\n <Label htmlFor=\"insight-filter-type\">\n {translate('brainyrich.insights.filters.type', 'Type')}\n </Label>\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger id=\"insight-filter-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>\n {translate('brainyrich.insights.filters.all', 'All')}\n </SelectItem>\n {INSIGHT_TYPES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </CardContent>\n </Card>\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={<BellRing className=\"size-6\" aria-hidden=\"true\" />}\n title={\n anyFilterActive\n ? translate('brainyrich.insights.empty.filteredTitle', 'No matching insights')\n : translate('brainyrich.insights.empty.title', 'No advisory insights yet')\n }\n description={\n anyFilterActive\n ? translate(\n 'brainyrich.insights.empty.filteredDescription',\n 'No insights match the selected filters. Adjust or clear them to see more.'\n )\n : translate(\n 'brainyrich.insights.empty.description',\n 'Advisory insights flag rebalancing, drift, concentration and other opportunities. Create one to get started.'\n )\n }\n action={\n anyFilterActive ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setSeverityFilter(ALL);\n setStatusFilter(ALL);\n setTypeFilter(ALL);\n }}\n >\n {translate('brainyrich.insights.actions.clearFilters', 'Clear filters')}\n </Button>\n ) : (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.create', 'New insight')}\n </Button>\n )\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filtered.map((insight, idx) => (\n <InsightCard\n key={insight.id}\n index={idx}\n insight={insight}\n subjectName={subjectNames.get(insight.subjectId)}\n translate={translate}\n onAcknowledge={() => acknowledge.mutate(insight.id)}\n onDismiss={() => dismiss.mutate(insight.id)}\n onResolve={() => resolve.mutate(insight.id)}\n acknowledgePending={acknowledge.isPending}\n dismissPending={dismiss.isPending}\n resolvePending={resolve.isPending}\n />\n ))}\n </div>\n )}\n\n <LoadMore\n hasMore={hasMore}\n onClick={loadMore}\n loading={isFetchingNextPage}\n label={translate('brainyrich.insights.actions.loadMore', 'Load more insights')}\n />\n </>\n );\n };\n\n return (\n <>\n <SectionShell\n title={translate('brainyrich.insights.title', 'Insights')}\n description={translate(\n 'brainyrich.insights.description',\n 'Advisory insights across portfolios, accounts and goals — triage, acknowledge and resolve.'\n )}\n badges={[translate('brainyrich.insights.badges.advisory', 'Advisory')]}\n actionLabel={translate('brainyrich.insights.actions.create', 'New insight')}\n onAction={openCreate}\n >\n {body()}\n </SectionShell>\n\n <InsightFormDialog\n open={createOpen}\n form={form}\n setField={setField}\n metricsValid={metricsValid}\n valid={formValid}\n pending={createInsight.isPending}\n onSubmit={handleCreate}\n onOpenChange={(v) => setCreateOpen(v)}\n translate={translate}\n />\n </>\n );\n}\n\ntype Translate = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string;\n\ninterface SummaryChipProps {\n label: string;\n count: number;\n tone: 'info' | 'error' | 'success';\n active: boolean;\n onClick: () => void;\n}\n\nfunction SummaryChip({ label, count, tone, active, onClick }: SummaryChipProps) {\n const dotClass =\n tone === 'error'\n ? 'bg-status-error-text'\n : tone === 'success'\n ? 'bg-status-success-text'\n : 'bg-status-info-text';\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-pressed={active}\n className={`group inline-flex items-center gap-2 rounded-full border px-3.5 py-1.5 text-sm font-medium transition-colors motion-safe:transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-action-primary-border)] ${\n active\n ? 'border-[var(--color-action-primary-border)] bg-bg-elevated text-text-primary shadow-[var(--shadow-elevation-1)]'\n : 'border-border-subtle bg-bg-surface text-text-secondary hover:border-[var(--color-action-primary-border)] hover:text-text-primary'\n }`}\n >\n <span className={`size-2 rounded-full ${dotClass}`} aria-hidden=\"true\" />\n {label}\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5 text-xs tabular-nums text-text-primary\">\n {count}\n </span>\n </button>\n );\n}\n\ninterface InsightCardProps {\n index: number;\n insight: BraInsight;\n /** Referenced entity name resolved from the list queries, if known. */\n subjectName?: string;\n translate: Translate;\n onAcknowledge: () => void;\n onDismiss: () => void;\n onResolve: () => void;\n acknowledgePending: boolean;\n dismissPending: boolean;\n resolvePending: boolean;\n}\n\nfunction InsightCard({\n index,\n insight,\n subjectName,\n translate,\n onAcknowledge,\n onDismiss,\n onResolve,\n acknowledgePending,\n dismissPending,\n resolvePending,\n}: InsightCardProps) {\n const meta = severityMeta(insight.severity);\n const SeverityIcon = meta.icon;\n const isClosed = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n const isDismissed = insight.status === 'DISMISSED';\n const [dismissOpen, setDismissOpen] = useState(false);\n // `BraInsight.metrics` already ships in this page's own query result: it is\n // the engine's real inputs + the formula it applied. Rendering it is what\n // turns a severity label into a reviewable finding.\n const rationale = readEngineMetrics(insight.metrics);\n\n return (\n <FadeIn as=\"div\" index={index}>\n <Card className=\"overflow-hidden transition-shadow motion-safe:hover:shadow-[var(--shadow-elevation-2)]\">\n <CardHeader className=\"pb-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className={`mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-full bg-bg-sunken ${meta.tone}`}\n >\n <SeverityIcon className=\"size-5\" aria-hidden=\"true\" />\n </span>\n <div className=\"min-w-0\">\n <CardTitle className=\"text-base\">{insight.title}</CardTitle>\n <CardDescription className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.severity)}>\n <span className={`inline-flex items-center gap-1 ${meta.tone}`}>\n <SeverityIcon className=\"size-3\" aria-hidden=\"true\" />\n {humanize(insight.severity)}\n </span>\n </Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>\n {humanize(insight.status)}\n </Badge>\n </CardDescription>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={translate('brainyrich.insights.actions.menu', 'Insight actions')}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n disabled={acknowledgePending || insight.status === 'ACKNOWLEDGED' || isClosed}\n onSelect={onAcknowledge}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.acknowledge', 'Acknowledge')}\n </DropdownMenuItem>\n <DropdownMenuItem\n disabled={resolvePending || insight.status === 'RESOLVED'}\n onSelect={onResolve}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.resolve', 'Resolve')}\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"text-status-error-text focus:text-status-error-text\"\n disabled={dismissPending || insight.status === 'DISMISSED'}\n onSelect={(e) => {\n e.preventDefault();\n setDismissOpen(true);\n }}\n >\n <XCircle className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.dismiss', 'Dismiss')}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {insight.detail ? <p className=\"text-sm text-text-secondary\">{insight.detail}</p> : null}\n\n {/* Rationale — the deterministic engine's own inputs and formula */}\n {rationale ? (\n <div className=\"space-y-2 rounded-lg border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-[11px] font-medium uppercase tracking-wide text-text-secondary\">\n {translate('brainyrich.insights.card.rationale', 'Rationale')}\n </p>\n {rationale.formula ? (\n <p className=\"break-words text-xs text-text-secondary\">{rationale.formula}</p>\n ) : null}\n <MetricGrid entries={rationale.entries} />\n </div>\n ) : null}\n\n <dl className=\"grid grid-cols-2 gap-3 rounded-lg bg-bg-sunken p-3 text-sm sm:grid-cols-3\">\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.subjectType', 'Subject')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{humanize(insight.subjectType)}</dd>\n </div>\n <div className=\"min-w-0\">\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.subject', 'Reference')}\n </dt>\n <dd\n className=\"truncate font-medium text-text-primary\"\n title={subjectName ? `${subjectName} (${insight.subjectId})` : insight.subjectId}\n >\n {subjectName ?? insight.subjectId}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{formatDate(insight.createdAt)}</dd>\n </div>\n {insight.resolvedAt ? (\n <div>\n <dt className=\"text-xs text-text-secondary\">\n {translate('brainyrich.insights.card.resolved', 'Resolved')}\n </dt>\n <dd className=\"font-medium text-text-primary\">{formatDate(insight.resolvedAt)}</dd>\n </div>\n ) : null}\n </dl>\n {isDismissed ? (\n <div className=\"flex items-center gap-2 rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary\">\n <XCircle className=\"size-4 text-status-error-text\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.card.dismissed', 'Dismissed from active triage')}\n </div>\n ) : (\n <LifecycleStepper steps={LIFECYCLE_STEPS} current={humanize(insight.status)} />\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={acknowledgePending || insight.status === 'ACKNOWLEDGED' || isClosed}\n onClick={onAcknowledge}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.acknowledge', 'Acknowledge')}\n </Button>\n <Button\n size=\"sm\"\n disabled={resolvePending || insight.status === 'RESOLVED'}\n onClick={onResolve}\n >\n <CheckCircle2 className=\"size-4\" aria-hidden=\"true\" />\n {translate('brainyrich.insights.actions.resolve', 'Resolve')}\n </Button>\n </div>\n </CardContent>\n\n <ConfirmDialog\n open={dismissOpen}\n onOpenChange={setDismissOpen}\n title={translate('brainyrich.insights.dismiss.title', 'Dismiss this insight?')}\n description={translate(\n 'brainyrich.insights.dismiss.description',\n 'Dismissing removes this insight from active triage. You can still find it by filtering for dismissed insights.'\n )}\n confirmLabel={translate('brainyrich.insights.actions.dismiss', 'Dismiss')}\n pendingLabel={translate('brainyrich.insights.dismiss.pending', 'Dismissing…')}\n destructive\n pending={dismissPending}\n onConfirm={onDismiss}\n />\n </Card>\n </FadeIn>\n );\n}\n\ninterface InsightFormDialogProps {\n open: boolean;\n form: InsightFormState;\n setField: <K extends keyof InsightFormState>(key: K, value: InsightFormState[K]) => void;\n metricsValid: boolean;\n valid: boolean;\n pending: boolean;\n onSubmit: () => void;\n onOpenChange: (open: boolean) => void;\n translate: Translate;\n}\n\nfunction InsightFormDialog({\n open,\n form,\n setField,\n metricsValid,\n valid,\n pending,\n onSubmit,\n onOpenChange,\n translate,\n}: InsightFormDialogProps) {\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"max-h-[90vh] overflow-y-auto sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {translate('brainyrich.insights.form.createTitle', 'New insight')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {translate(\n 'brainyrich.insights.form.subtitle',\n 'Flag an advisory insight against a portfolio, account, goal or household.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <form\n className=\"space-y-4\"\n onSubmit={(e) => {\n e.preventDefault();\n onSubmit();\n }}\n >\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-title\">\n {translate('brainyrich.insights.form.title', 'Title')}\n </Label>\n <Input\n id=\"insight-title\"\n value={form.title}\n onChange={(e) => setField('title', e.target.value)}\n placeholder={translate(\n 'brainyrich.insights.form.titlePlaceholder',\n 'e.g. Technology concentration above threshold'\n )}\n required\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-type\">\n {translate('brainyrich.insights.form.type', 'Type')}\n </Label>\n <Select\n value={form.type}\n onValueChange={(v) => setField('type', v as BraInsightType)}\n >\n <SelectTrigger id=\"insight-type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INSIGHT_TYPES.map((tpe) => (\n <SelectItem key={tpe} value={tpe}>\n {humanize(tpe)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-severity\">\n {translate('brainyrich.insights.form.severity', 'Severity')}\n </Label>\n <Select\n value={form.severity}\n onValueChange={(v) => setField('severity', v as BraInsightSeverity)}\n >\n <SelectTrigger id=\"insight-severity\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INSIGHT_SEVERITIES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <SubjectPicker\n id=\"insight-subject\"\n label={translate('brainyrich.insights.form.subject', 'Subject')}\n placeholder={translate(\n 'brainyrich.insights.form.subjectPlaceholder',\n 'Select an account, portfolio, goal or household'\n )}\n value={form.subject}\n onChange={(v) => setField('subject', v)}\n />\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-owner\">\n {translate('brainyrich.insights.form.ownerId', 'Owner ID (optional)')}\n </Label>\n <Input\n id=\"insight-owner\"\n value={form.ownerId}\n onChange={(e) => setField('ownerId', e.target.value)}\n placeholder={translate(\n 'brainyrich.insights.form.ownerIdPlaceholder',\n 'Defaults to the current owner'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-detail\">\n {translate('brainyrich.insights.form.detail', 'Detail')}\n </Label>\n <Textarea\n id=\"insight-detail\"\n value={form.detail}\n onChange={(e) => setField('detail', e.target.value)}\n rows={3}\n placeholder={translate(\n 'brainyrich.insights.form.detailPlaceholder',\n 'Explain the finding and recommended action.'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"insight-metrics\">\n {translate('brainyrich.insights.form.metrics', 'Metrics JSON (optional)')}\n </Label>\n <Textarea\n id=\"insight-metrics\"\n value={form.metrics}\n onChange={(e) => setField('metrics', e.target.value)}\n rows={3}\n className=\"font-mono text-xs\"\n placeholder='{ \"driftPct\": 8.2 }'\n aria-invalid={!metricsValid}\n />\n {!metricsValid ? (\n <p className=\"flex items-center gap-1 text-xs text-status-error-text\">\n <AlertTriangle className=\"size-3.5\" aria-hidden=\"true\" />\n {translate(\n 'brainyrich.insights.form.metricsInvalid',\n 'Enter valid JSON or leave blank.'\n )}\n </p>\n ) : null}\n </div>\n\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={pending}\n >\n {translate('brainyrich.insights.form.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={!valid || pending}>\n {pending\n ? translate('brainyrich.insights.form.saving', 'Saving…')\n : translate('brainyrich.insights.form.create', 'Create insight')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { EmptyState as l, ErrorState as u, LoadingState as d, SectionShell as f,
5
5
  import { useMemo as m, useState as ae } from "react";
6
6
  import { ArrowDownRight as oe, ArrowUpRight as h, BarChart3 as g, Coins as se, Minus as _, PieChart as ce, Plus as le, TrendingDown as ue, TrendingUp as de, Wallet as v } from "lucide-react";
7
7
  import { jsx as y, jsxs as b } from "react/jsx-runtime";
8
- import { Badge as fe, Button as x, Card as S, CardContent as C, CardDescription as w, CardHeader as T, CardTitle as pe, Dialog as me, DialogContent as he, DialogDescription as ge, DialogFooter as _e, DialogHeader as ve, DialogTitle as ye, DialogTrigger as be, Input as xe, Label as E, Select as Se, SelectContent as Ce, SelectItem as we, SelectTrigger as Te, SelectValue as D, Table as O, TableBody as k, TableCell as A, TableHead as j, TableHeader as M, TableRow as N, Tabs as Ee, TabsContent as P, TabsList as De, TabsTrigger as F, Textarea as Oe } from "@burdenoff/fe-libs/ui";
8
+ import { Badge as fe, Button as x, Card as S, CardContent as C, CardDescription as w, CardHeader as T, CardTitle as pe, Input as me, Label as E, ResponsiveDialog as he, ResponsiveDialogContent as ge, ResponsiveDialogDescription as _e, ResponsiveDialogFooter as ve, ResponsiveDialogHeader as ye, ResponsiveDialogTitle as be, ResponsiveDialogTrigger as xe, Select as Se, SelectContent as Ce, SelectItem as we, SelectTrigger as Te, SelectValue as D, Table as O, TableBody as k, TableCell as A, TableHead as j, TableHeader as M, TableRow as N, Tabs as Ee, TabsContent as P, TabsList as De, TabsTrigger as F, Textarea as Oe } from "@burdenoff/fe-libs/ui";
9
9
  //#region src/brainyrich/pages/AnalyticsPage.tsx
10
10
  var ke = {
11
11
  EQUITY: "brand",
@@ -159,12 +159,12 @@ function H() {
159
159
  onRetry: () => _.refetch()
160
160
  })
161
161
  });
162
- let Ue = Number(K.amount), We = !!K.accountId && !!K.tradeDate && K.amount.trim() !== "" && Number.isFinite(Ue) && Ue > 0 && !W.isPending, Ge = /* @__PURE__ */ b(me, {
162
+ let Ue = Number(K.amount), We = !!K.accountId && !!K.tradeDate && K.amount.trim() !== "" && Number.isFinite(Ue) && Ue > 0 && !W.isPending, Ge = /* @__PURE__ */ b(he, {
163
163
  open: Fe,
164
164
  onOpenChange: (e) => {
165
165
  G(e), e || q(V);
166
166
  },
167
- children: [/* @__PURE__ */ y(be, {
167
+ children: [/* @__PURE__ */ y(xe, {
168
168
  asChild: !0,
169
169
  children: /* @__PURE__ */ b(x, {
170
170
  size: "sm",
@@ -173,8 +173,8 @@ function H() {
173
173
  "aria-hidden": "true"
174
174
  }), "Record Transaction"]
175
175
  })
176
- }), /* @__PURE__ */ b(he, { children: [
177
- /* @__PURE__ */ b(ve, { children: [/* @__PURE__ */ y(ye, { children: "Record Transaction" }), /* @__PURE__ */ y(ge, { children: "Log a real cash flow or trade. It updates your cash-flow analytics immediately." })] }),
176
+ }), /* @__PURE__ */ b(ge, { children: [
177
+ /* @__PURE__ */ b(ye, { children: [/* @__PURE__ */ y(be, { children: "Record Transaction" }), /* @__PURE__ */ y(_e, { children: "Log a real cash flow or trade. It updates your cash-flow analytics immediately." })] }),
178
178
  H.length === 0 ? /* @__PURE__ */ y(l, {
179
179
  icon: /* @__PURE__ */ y(v, {
180
180
  className: "size-6",
@@ -235,7 +235,7 @@ function H() {
235
235
  Y,
236
236
  ")"
237
237
  ]
238
- }), /* @__PURE__ */ y(xe, {
238
+ }), /* @__PURE__ */ y(me, {
239
239
  id: "tx-amount",
240
240
  type: "number",
241
241
  min: "0",
@@ -257,7 +257,7 @@ function H() {
257
257
  children: [/* @__PURE__ */ y(E, {
258
258
  htmlFor: "tx-date",
259
259
  children: "Trade date"
260
- }), /* @__PURE__ */ y(xe, {
260
+ }), /* @__PURE__ */ y(me, {
261
261
  id: "tx-date",
262
262
  type: "date",
263
263
  value: K.tradeDate,
@@ -271,7 +271,7 @@ function H() {
271
271
  children: [/* @__PURE__ */ y(E, {
272
272
  htmlFor: "tx-symbol",
273
273
  children: "Symbol (optional)"
274
- }), /* @__PURE__ */ y(xe, {
274
+ }), /* @__PURE__ */ y(me, {
275
275
  id: "tx-symbol",
276
276
  placeholder: "e.g. AAPL",
277
277
  value: K.symbol,
@@ -304,7 +304,7 @@ function H() {
304
304
  }) : null
305
305
  ]
306
306
  }),
307
- /* @__PURE__ */ b(_e, { children: [/* @__PURE__ */ y(x, {
307
+ /* @__PURE__ */ b(ve, { children: [/* @__PURE__ */ y(x, {
308
308
  variant: "outline",
309
309
  onClick: () => G(!1),
310
310
  children: H.length === 0 ? "Close" : "Cancel"