@paro.io/expert-shared-components 1.14.59 → 1.14.60

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/lib/README.md +2 -0
  2. package/lib/components/DocumentCenter/MultiFileUploadSection.js +121 -220
  3. package/lib/components/TaxAxis/TaxAxisApi.d.ts +1 -0
  4. package/lib/components/TaxAxis/TaxAxisShell.js +52 -3
  5. package/lib/components/shared/UploadClient.d.ts +1 -2
  6. package/lib/components/shared/UploadClient.js +2 -6
  7. package/lib/index.d.ts +13 -2
  8. package/lib/index.js +27 -3
  9. package/lib/package.json +68 -0
  10. package/lib/tax-axis/components/clientReport/ExecutiveSummary.d.ts +1 -4
  11. package/lib/tax-axis/components/clientReport/ExecutiveSummary.js +6 -10
  12. package/lib/tax-axis/components/clientReport/Methodology.js +2 -2
  13. package/lib/tax-axis/components/clientReport/RecommendedStrategies.d.ts +1 -6
  14. package/lib/tax-axis/components/clientReport/RecommendedStrategies.js +24 -26
  15. package/lib/tax-axis/components/clientReport/StrategyCard.d.ts +1 -1
  16. package/lib/tax-axis/components/clientReport/StrategyCard.js +23 -39
  17. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +2 -8
  18. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +7 -9
  19. package/lib/tax-axis/components/dashboard/DashboardActions.js +5 -6
  20. package/lib/tax-axis/components/dashboard/DashboardSummary.d.ts +1 -6
  21. package/lib/tax-axis/components/dashboard/DashboardSummary.js +10 -19
  22. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.d.ts +1 -1
  23. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +95 -122
  24. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +2 -59
  25. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +49 -433
  26. package/lib/tax-axis/components/documents/DocumentCard.d.ts +3 -8
  27. package/lib/tax-axis/components/documents/DocumentCard.js +14 -83
  28. package/lib/tax-axis/components/documents/DocumentTier.d.ts +2 -5
  29. package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
  30. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +1 -36
  31. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +86 -363
  32. package/lib/tax-axis/components/extractionReview/TaxAxisExtractionReview.js +17 -17
  33. package/lib/tax-axis/components/intake/ClientParametersSection.js +30 -14
  34. package/lib/tax-axis/components/intake/CpaIntakeQuestionsSection.js +3 -3
  35. package/lib/tax-axis/components/intake/IntakeCtaCards.d.ts +2 -1
  36. package/lib/tax-axis/components/intake/IntakeCtaCards.js +13 -6
  37. package/lib/tax-axis/components/intake/RefineAnalysisSection.js +7 -7
  38. package/lib/tax-axis/components/intake/TaxAxisIntake.js +45 -6
  39. package/lib/tax-axis/components/intake/intakeSchema.d.ts +3 -0
  40. package/lib/tax-axis/components/intake/intakeSchema.js +4 -2
  41. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +2 -26
  42. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +4 -15
  43. package/lib/tax-axis/components/processing/TaxAxisProcessing.d.ts +1 -3
  44. package/lib/tax-axis/components/processing/TaxAxisProcessing.js +31 -102
  45. package/lib/tax-axis/components/prospectReport/ProspectPrintView.js +2 -0
  46. package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.d.ts +8 -1
  47. package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.js +5 -5
  48. package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.d.ts +27 -1
  49. package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.js +43 -25
  50. package/lib/tax-axis/index.d.ts +0 -4
  51. package/lib/tax-axis/index.js +1 -6
  52. package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +13 -138
  53. package/lib/tax-axis/lib/adapters/useEngineOutput.js +7 -156
  54. package/lib/tax-axis/lib/data/documents.d.ts +2 -3
  55. package/lib/tax-axis/lib/data/documents.js +25 -225
  56. package/lib/tax-axis/lib/data/strategies.js +9 -9
  57. package/lib/tax-axis/lib/documentFieldCatalog.d.ts +12 -7
  58. package/lib/tax-axis/lib/documentFieldCatalog.js +8 -805
  59. package/lib/tax-axis/lib/types/index.d.ts +1 -13
  60. package/package.json +1 -1
@@ -26,214 +26,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.TaxAxisDashboard = TaxAxisDashboard;
27
27
  const react_1 = __importStar(require("react"));
28
28
  const data_1 = require("../../lib/data");
29
- const strategyNarrative_1 = require("../../lib/data/strategyNarrative");
30
29
  const compute_1 = require("../../lib/compute");
31
- const useEngineOutput_1 = require("../../lib/adapters/useEngineOutput");
32
30
  const TaxAxisButton_1 = require("../shared/TaxAxisButton");
33
31
  const TaxAxisBadge_1 = require("../shared/TaxAxisBadge");
34
32
  const DashboardSummary_1 = require("./DashboardSummary");
33
+ const DashboardTopBar_1 = require("./DashboardTopBar");
35
34
  const DashboardActions_1 = require("./DashboardActions");
36
35
  const StrategyTile_1 = require("./StrategyTile");
37
36
  const StrategyDetailPanel_1 = require("./StrategyDetailPanel");
38
- const STRATEGY_TYPE_LABELS = {
39
- ENTITY_RESTRUCTURING: "Entity Restructuring",
40
- QBI_199A_OPTIMIZATION: "QBI §199A Optimization",
41
- DOCUMENTATION_GAP_REMEDIATION: "Documentation Gap Remediation",
42
- RETIREMENT_PLAN: "Retirement Plan Optimization",
43
- DEPRECIATION_ACCELERATION: "Depreciation Acceleration",
44
- COST_SEGREGATION: "Cost Segregation",
45
- RD_CREDIT: "R&D Tax Credit",
46
- HSA_MAXIMIZATION: "HSA Maximization",
47
- SALT_PTE: "SALT / PTE Optimization",
48
- WOTC: "Work Opportunity Tax Credit",
49
- INCOME_DEFERRAL: "Income Deferral",
50
- CHARITABLE_GIVING: "Charitable Giving Strategy",
51
- FAMILY_EMPLOYMENT: "Family Employment",
52
- MEALS_DEDUCTIONS: "Business Meals Deduction",
53
- OPPORTUNITY_ZONE: "Opportunity Zone Investment",
54
- ACCOUNTING_METHOD: "Accounting Method Change",
55
- BONUS_DEPRECIATION: "Bonus Depreciation §168(k)",
56
- SECTION_179: "Section 179 Expensing",
57
- };
58
- function humanizeStrategyType(raw) {
59
- if (STRATEGY_TYPE_LABELS[raw])
60
- return STRATEGY_TYPE_LABELS[raw];
61
- return raw
62
- .replace(/_/g, " ")
63
- .replace(/\b\w/g, (c) => c.toUpperCase());
64
- }
65
- // Build a lookup from strategy_id → strategy_name using engineOutput.strategy_analysis
66
- function buildEngineNameLookup(llm) {
67
- var _a;
68
- const map = new Map();
69
- const analysis = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.strategy_analysis;
70
- if (Array.isArray(analysis)) {
71
- for (const a of analysis) {
72
- if (a.strategy_id && a.strategy_name)
73
- map.set(a.strategy_id, a.strategy_name);
74
- }
75
- }
76
- return map;
77
- }
78
- // Build a lookup from strategy_id → roadmap bucket using engineOutput.implementation_roadmap
79
- function buildRoadmapBucketLookup(llm) {
80
- var _a, _b;
81
- const map = new Map();
82
- const roadmap = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.implementation_roadmap;
83
- if (!roadmap)
84
- return map;
85
- const bucketKeys = [
86
- { key: "quick_wins", bucket: "now" },
87
- { key: "immediate", bucket: "now" },
88
- { key: "thirty_day", bucket: "30d" },
89
- { key: "ninety_day", bucket: "90d" },
90
- { key: "annual", bucket: "filing" },
91
- ];
92
- for (const { key, bucket } of bucketKeys) {
93
- for (const item of (_b = roadmap[key]) !== null && _b !== void 0 ? _b : []) {
94
- if (item.strategy_id)
95
- map.set(item.strategy_id, bucket);
96
- }
97
- }
98
- return map;
99
- }
100
- // LLM sometimes emits these literal placeholder strings as why_it_applies / next_step
101
- // content. When detected, we fall back to STRATEGY_NARRATIVE static content.
102
- const PLACEHOLDER_WHY = "This strategy may apply based on your financial profile.";
103
- const PLACEHOLDER_NEXT = "Discuss with your CPA to evaluate and implement this strategy.";
104
- function isMissingOrPlaceholder(value, knownPlaceholder) {
105
- if (!value)
106
- return true;
107
- const trimmed = value.trim();
108
- if (trimmed === "")
109
- return true;
110
- if (trimmed === knownPlaceholder)
111
- return true;
112
- return false;
113
- }
114
- // Parse "S10" -> 10. Returns null if strategyId doesn't match the SN pattern.
115
- function parseStrategyNumber(strategyId) {
116
- if (!strategyId)
117
- return null;
118
- const match = strategyId.match(/^S(\d+)$/);
119
- if (!match)
120
- return null;
121
- return parseInt(match[1], 10);
122
- }
123
- // Build a strategy_id -> client_summary entry lookup using strategy_analysis as the join table.
124
- function buildClientSummaryLookup(llm) {
125
- var _a, _b, _c, _d;
126
- const lookup = new Map();
127
- const engineOutput = (_a = llm.engineOutput) !== null && _a !== void 0 ? _a : llm.rawOutput;
128
- if (!engineOutput)
129
- return lookup;
130
- const strategyAnalysis = (_b = engineOutput.strategy_analysis) !== null && _b !== void 0 ? _b : [];
131
- const clientSummaryStrategies = (_d = (_c = engineOutput.client_summary) === null || _c === void 0 ? void 0 : _c.strategies) !== null && _d !== void 0 ? _d : [];
132
- // strategy_name -> client_summary entry
133
- const byName = new Map();
134
- for (const cs of clientSummaryStrategies) {
135
- if (cs.strategy_name) {
136
- byName.set(cs.strategy_name, cs);
137
- }
138
- }
139
- // strategy_id -> client_summary entry (via strategy_analysis name lookup)
140
- for (const sa of strategyAnalysis) {
141
- if (sa.strategy_id && sa.strategy_name) {
142
- const cs = byName.get(sa.strategy_name);
143
- if (cs) {
144
- lookup.set(sa.strategy_id, cs);
145
- }
146
- }
147
- }
148
- return lookup;
149
- }
150
- function mapLlmToStrategies(llm, profile) {
151
- const nameLookup = buildEngineNameLookup(llm);
152
- const bucketLookup = buildRoadmapBucketLookup(llm);
153
- const clientSummaryLookup = buildClientSummaryLookup(llm);
154
- return llm.strategies
155
- .filter((s) => s.applicable)
156
- .map((s, idx) => {
157
- var _a, _b, _c, _d, _e, _f, _g;
158
- const id = (_a = s.strategyId) !== null && _a !== void 0 ? _a : s.strategyType;
159
- const name = (_b = nameLookup.get(id)) !== null && _b !== void 0 ? _b : humanizeStrategyType(s.strategyType);
160
- const timelineBucket = (_c = bucketLookup.get(id)) !== null && _c !== void 0 ? _c : (s.priority === "HIGH" ? "now" : "90d");
161
- const weightedScore = (_d = s.weightedScore) !== null && _d !== void 0 ? _d : (s.priority === "HIGH" ? 85 : s.priority === "MEDIUM" ? 70 : 55);
162
- // Lookup the client_summary entry for this strategy (top-3 strategies only)
163
- const csEntry = clientSummaryLookup.get(id);
164
- const llmWhy = csEntry === null || csEntry === void 0 ? void 0 : csEntry.why_it_applies;
165
- const llmNext = csEntry === null || csEntry === void 0 ? void 0 : csEntry.next_step;
166
- // Strategy number for STRATEGY_NARRATIVE static lookup (e.g. "S10" -> 10)
167
- const strategyNumber = parseStrategyNumber(id);
168
- const staticNarrative = strategyNumber !== null ? strategyNarrative_1.STRATEGY_NARRATIVE[strategyNumber] : undefined;
169
- // clientBrief: prefer LLM why_it_applies, fall back to static, then neutral default
170
- let clientBrief;
171
- if (!isMissingOrPlaceholder(llmWhy, PLACEHOLDER_WHY)) {
172
- clientBrief = llmWhy;
173
- }
174
- else if (staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.whyMatters) {
175
- clientBrief = staticNarrative.whyMatters(profile);
176
- }
177
- else {
178
- clientBrief = "Your preparer will review this strategy and include the analysis in your engagement report.";
179
- }
180
- // action: prefer LLM next_step, fall back to static nextSteps, then implementationSteps[0]
181
- let action;
182
- if (!isMissingOrPlaceholder(llmNext, PLACEHOLDER_NEXT)) {
183
- action = llmNext;
184
- }
185
- else if (staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.nextSteps) {
186
- action = staticNarrative.nextSteps;
187
- }
188
- else if ((_e = s.implementationSteps) === null || _e === void 0 ? void 0 : _e[0]) {
189
- action = s.implementationSteps[0];
190
- }
191
- else {
192
- action = "Work with your CPA to implement this strategy.";
193
- }
194
- // Pull calculation_trace fields. Defensive about shape.
195
- const ct = ((_f = s.calculationTrace) !== null && _f !== void 0 ? _f : {});
196
- const sourceDocuments = Array.isArray(ct.source_documents) ? ct.source_documents : undefined;
197
- const specialistNote = typeof ct.specialist_note === "string" && ct.specialist_note.trim() !== ""
198
- ? ct.specialist_note
199
- : ((_g = staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.whySpecialist) !== null && _g !== void 0 ? _g : undefined);
200
- const positionStrength = typeof ct.position_strength === "string" ? ct.position_strength : undefined;
201
- const authority = typeof ct.irs_cite === "string" ? ct.irs_cite : undefined;
202
- const formsFromTrace = Array.isArray(ct.forms_required) ? ct.forms_required.join(", ") : undefined;
203
- return {
204
- rank: idx + 1,
205
- code: id,
206
- name,
207
- cat: "income",
208
- priority: (s.priority || "MEDIUM").toUpperCase(),
209
- score: Math.round(weightedScore),
210
- entities: [],
211
- lo: s.estimatedSavings.min,
212
- hi: s.estimatedSavings.max,
213
- timeline: timelineBucket === "now" ? "Act now" : timelineBucket === "30d" ? "Within 30 days" : "Within 90 days",
214
- timelineBucket,
215
- clientBrief,
216
- action,
217
- forms: formsFromTrace !== null && formsFromTrace !== void 0 ? formsFromTrace : s.requiredForms.join(", "),
218
- abstract: s.summary,
219
- sources: [],
220
- trace: [],
221
- cost: undefined,
222
- sourceDocuments,
223
- specialistNote,
224
- positionStrength,
225
- authority,
226
- quickWin: s.quickWin,
227
- };
228
- });
229
- }
230
- function buildLlmComputed(strategies) {
231
- const map = new Map();
232
- for (const s of strategies) {
233
- map.set(s.rank, { lo: s.lo, hi: s.hi, sources: s.sources, trace: s.trace });
234
- }
235
- return map;
236
- }
237
37
  // ─── Formatting helper ──────────────────────────────────────────
238
38
  const fmtK = (n) => `$${(n / 1000).toFixed(n % 1000 ? 1 : 0)}K`;
239
39
  // ─── Timeline buckets for Client Summary ────────────────────────
@@ -242,66 +42,21 @@ const BUCKETS = [
242
42
  { key: "30d", label: "Within 30 Days", desc: "Documentation or payroll changes" },
243
43
  { key: "90d", label: "Within 90 Days", desc: "Structural changes — new accounts or plan setup" },
244
44
  ];
245
- function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
246
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
247
- const hasLlm = !!((_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.strategies) === null || _a === void 0 ? void 0 : _a.length);
248
- // All live fields from rawOutput — nothing hardcoded
249
- const rawOutput = (_c = (_b = llmResult === null || llmResult === void 0 ? void 0 : llmResult.rawOutput) !== null && _b !== void 0 ? _b : llmResult === null || llmResult === void 0 ? void 0 : llmResult.engineOutput) !== null && _c !== void 0 ? _c : null;
250
- const businessProfile = (_d = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.business_profile) !== null && _d !== void 0 ? _d : null;
251
- const dataQualityFlags = (_e = businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_quality_flags) !== null && _e !== void 0 ? _e : [];
252
- const riskDisclosures = (_f = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.risk_disclosures) !== null && _f !== void 0 ? _f : [];
253
- const nexusFlags = (_g = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.nexus_flags) !== null && _g !== void 0 ? _g : [];
254
- const engagementRecs = (_j = (_h = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.cpa_workflow) === null || _h === void 0 ? void 0 : _h.engagement_recommendations) !== null && _j !== void 0 ? _j : [];
255
- const excludedStrategies = (_l = (_k = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.eligibility_screening) === null || _k === void 0 ? void 0 : _k.excluded_strategies) !== null && _l !== void 0 ? _l : [];
256
- const clientSummaryOpening = (_o = (_m = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _m === void 0 ? void 0 : _m.opening) !== null && _o !== void 0 ? _o : "";
257
- const clientSummaryClosing = (_q = (_p = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _p === void 0 ? void 0 : _p.closing) !== null && _q !== void 0 ? _q : "";
258
- const dataQualityNote = (_s = (_r = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _r === void 0 ? void 0 : _r.data_quality_note) !== null && _s !== void 0 ? _s : "";
259
- const interactionWarning = (_u = (_t = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _t === void 0 ? void 0 : _t.interaction_warning) !== null && _u !== void 0 ? _u : null;
260
- // Extracted documents: live from session if provided, otherwise empty (no mock fallback)
261
- const extractionDocs = parsedDocuments !== null && parsedDocuments !== void 0 ? parsedDocuments : [];
45
+ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, userContext: _userContext = "expert", }) {
262
46
  // ─── Derived data ──────────────────────────────────────────────
263
- // Prefer useEngineOutput (full rich data: sourceDocuments, positionStrength,
264
- // clientBrief from why_it_applies, etc.) over the thin mapLlmToStrategies fallback.
265
- // engineOutput is at llmResult.engineOutput or llmResult.rawOutput (both present).
266
- const engineOutputForAdapter = (0, react_1.useMemo)(() => { var _a, _b; return (_b = (_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.engineOutput) !== null && _a !== void 0 ? _a : llmResult === null || llmResult === void 0 ? void 0 : llmResult.rawOutput) !== null && _b !== void 0 ? _b : null; }, [llmResult]);
267
- const adapted = (0, useEngineOutput_1.useEngineOutput)(engineOutputForAdapter);
268
- const llmStrategies = (0, react_1.useMemo)(() => {
269
- var _a;
270
- if (!hasLlm)
271
- return [];
272
- // Use adapted strategies when available — they carry the full engine data.
273
- if ((_a = adapted === null || adapted === void 0 ? void 0 : adapted.strategies) === null || _a === void 0 ? void 0 : _a.length)
274
- return adapted.strategies;
275
- // Fallback to thin mapping for old payload shapes without engineOutput.
276
- return mapLlmToStrategies(llmResult, profile);
277
- }, [hasLlm, adapted, llmResult, profile]);
278
- const llmComputed = (0, react_1.useMemo)(() => {
279
- var _a;
280
- if (!hasLlm)
281
- return new Map();
282
- if ((_a = adapted === null || adapted === void 0 ? void 0 : adapted.computedMap) === null || _a === void 0 ? void 0 : _a.size)
283
- return adapted.computedMap;
284
- return buildLlmComputed(llmStrategies);
285
- }, [hasLlm, adapted, llmStrategies]);
286
- const computed = (0, react_1.useMemo)(() => (hasLlm ? llmComputed : (0, compute_1.computeAllStrategies)(profile)), [hasLlm, llmComputed, profile]);
287
- const dashEligible = (0, react_1.useMemo)(() => (hasLlm ? llmStrategies : (0, compute_1.filterEligibleStrategies)(profile)), [hasLlm, llmStrategies, profile]);
47
+ const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
48
+ const dashEligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
288
49
  const maxSavings = Math.max(...dashEligible.map((s) => { var _a, _b; return (_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi; }), 1);
289
50
  // ─── State ─────────────────────────────────────────────────────
290
- // When LLM result is present, land directly on the Intelligence Report tab
291
- const [topTab, setTopTab] = (0, react_1.useState)(hasLlm ? "report" : "extraction");
51
+ const [topTab, setTopTab] = (0, react_1.useState)("extraction");
292
52
  const [reportTab, setReportTab] = (0, react_1.useState)("report");
293
53
  const [chartExpanded, setChartExpanded] = (0, react_1.useState)(false);
294
54
  const [selected, setSelected] = (0, react_1.useState)(null);
295
- // When LLM result is present, data is implicitly confirmed — skip the gate
296
- const [dataConfirmed, setDataConfirmed] = (0, react_1.useState)(hasLlm);
55
+ const [dataConfirmed, setDataConfirmed] = (0, react_1.useState)(false);
297
56
  const [reviewStatus, setReviewStatus] = (0, react_1.useState)({
298
- unreviewed: extractionDocs.reduce((a, d) => a + d.flagCount, 0),
57
+ unreviewed: data_1.EXTRACTED_DATA.reduce((a, d) => a + d.flagCount, 0),
299
58
  edits: 0,
300
59
  });
301
- // Keep review count in sync when live docs arrive after initial render
302
- (0, react_1.useEffect)(() => {
303
- setReviewStatus((prev) => (Object.assign(Object.assign({}, prev), { unreviewed: extractionDocs.reduce((a, d) => a + d.flagCount, 0) })));
304
- }, [extractionDocs]);
305
60
  // Restore confirmed state on mount — flag persists until session reset
306
61
  (0, react_1.useEffect)(() => {
307
62
  if (typeof window !== "undefined" && sessionStorage.getItem("taxAxisDataConfirmed") === "true") {
@@ -322,54 +77,15 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
322
77
  const c = computed.get(selected.rank);
323
78
  return Object.assign(Object.assign({}, selected), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : selected.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : selected.hi, sources: (_c = c === null || c === void 0 ? void 0 : c.sources) !== null && _c !== void 0 ? _c : selected.sources, trace: (_d = c === null || c === void 0 ? void 0 : c.trace) !== null && _d !== void 0 ? _d : selected.trace });
324
79
  }, [selected, computed]);
325
- // Split eligible strategies into calculable (hi > 0) vs uncalculated ($0K)
326
- const calculable = (0, react_1.useMemo)(() => dashEligible.filter((s) => { var _a, _b; return ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi) > 0; }), [dashEligible, computed]);
327
- const uncalculated = (0, react_1.useMemo)(() => dashEligible.filter((s) => { var _a, _b; return ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi) === 0; }), [dashEligible, computed]);
328
- // Sorted calculable strategies for impact distribution
329
- const sortedByImpact = (0, react_1.useMemo)(() => [...calculable].sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = computed.get(b.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : b.hi) - ((_d = (_c = computed.get(a.rank)) === null || _c === void 0 ? void 0 : _c.hi) !== null && _d !== void 0 ? _d : a.hi); }), [calculable, computed]);
330
- // Reverse-map: strategy name → document names needed (from DOC_SPECS_BASE)
331
- const strategyDocNeeds = (0, react_1.useMemo)(() => {
332
- const map = new Map();
333
- uncalculated.forEach((s) => {
334
- const docs = data_1.DOC_SPECS_BASE
335
- .filter((d) => d.strategies.some((st) => s.name.includes(st) || st.includes(s.code)))
336
- .map((d) => d.name);
337
- map.set(s.name, docs.length > 0 ? docs : ["Upload additional documents"]);
338
- });
339
- return map;
340
- }, [uncalculated]);
341
- const [uncalcExpanded, setUncalcExpanded] = (0, react_1.useState)(false);
342
- const [excludedExpanded, setExcludedExpanded] = (0, react_1.useState)(false);
343
- const [riskExpanded, setRiskExpanded] = (0, react_1.useState)(false);
80
+ // Sorted strategies for impact distribution
81
+ const sortedByImpact = (0, react_1.useMemo)(() => [...dashEligible].sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = computed.get(b.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : b.hi) - ((_d = (_c = computed.get(a.rank)) === null || _c === void 0 ? void 0 : _c.hi) !== null && _d !== void 0 ? _d : a.hi); }), [dashEligible, computed]);
344
82
  return (react_1.default.createElement("div", null,
345
- react_1.default.createElement("style", null, `
346
- @media print {
347
- * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
348
- .MuiDrawer-root, .MuiDrawer-paper, .MuiDrawer-permanent,
349
- .MuiAppBar-root { display: none !important; }
350
- .tax-axis-no-print { display: none !important; }
351
- body { background: white !important; }
352
- .min-h-screen.bg-tax-axis-navy { background: white !important; }
353
- .flex.flex-col.w-full { margin-top: 0 !important; margin-left: 0 !important; }
354
- main.w-full { width: 100% !important; margin: 0 !important; padding: 0 !important; }
355
- .rounded-\\[14px\\] { page-break-inside: avoid; break-inside: avoid; }
356
- .rounded-2xl { page-break-inside: avoid; break-inside: avoid; }
357
- }
358
- `),
359
- react_1.default.createElement(DashboardSummary_1.DashboardSummary, { profile: profile, dashEligible: dashEligible, computed: computed, dataConfirmed: dataConfirmed, reviewUnreviewed: reviewStatus.unreviewed, liveSavingsMin: hasLlm ? llmResult.summary.estimatedSavingsMin : undefined, liveSavingsMax: hasLlm ? llmResult.summary.estimatedSavingsMax : undefined, liveStrategyCount: hasLlm ? llmResult.summary.applicableCount : undefined, confidenceTier: businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.confidence_tier, dataYears: businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_years }),
360
- false && (react_1.default.createElement("div", null,
361
- dataQualityFlags.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.2)", padding: "16px 20px" } },
362
- react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2.5 flex items-center gap-2" },
363
- react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
364
- react_1.default.createElement("path", { d: "M6 1.5l5 9H1L6 1.5z", stroke: "#FB9A1D", strokeWidth: "1.2", fill: "none" }),
365
- react_1.default.createElement("path", { d: "M6 5v2.5M6 9h.005", stroke: "#FB9A1D", strokeWidth: "1.2", strokeLinecap: "round" })),
366
- "Data Quality Flags"),
367
- dataQualityFlags.map((flag, i) => (react_1.default.createElement("div", { key: i, className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(251,154,29,0.1)" : "none" } }, flag))))),
83
+ react_1.default.createElement(DashboardSummary_1.DashboardSummary, { profile: profile, dashEligible: dashEligible, computed: computed, dataConfirmed: dataConfirmed, reviewUnreviewed: reviewStatus.unreviewed }),
84
+ react_1.default.createElement(DashboardTopBar_1.DashboardTopBar, { topTab: topTab, setTopTab: setTopTab, dataConfirmed: dataConfirmed, reviewUnreviewed: reviewStatus.unreviewed }),
85
+ topTab === "extraction" && (react_1.default.createElement("div", null,
368
86
  react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)", padding: "20px 24px" } },
369
87
  react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head mb-3" }, "Document Extraction Summary"),
370
- extractionDocs.length === 0 ? (react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-text-3 font-tax-axis-body py-2" }, hasLlm
371
- ? "Parsed document data is loading..."
372
- : "No documents have been parsed yet.")) : (extractionDocs.map((doc) => (react_1.default.createElement("div", { key: doc.docId, className: "flex items-center justify-between py-2.5", style: { borderTop: "1px solid rgba(36,131,132,0.08)" } },
88
+ data_1.EXTRACTED_DATA.map((doc) => (react_1.default.createElement("div", { key: doc.docId, className: "flex items-center justify-between py-2.5", style: { borderTop: "1px solid rgba(36,131,132,0.08)" } },
373
89
  react_1.default.createElement("div", { className: "flex items-center gap-3" },
374
90
  react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-teal-light bg-tax-axis-teal-bg px-2 py-0.5 rounded" }, doc.code),
375
91
  react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text font-tax-axis-body" }, doc.docName)),
@@ -377,8 +93,9 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
377
93
  react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-3" },
378
94
  doc.fields.length,
379
95
  " fields"),
380
- doc.flagCount > 0 ? (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono rounded-full min-w-[18px] text-center px-1.5 py-0.5", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.06)" } }, doc.flagCount)) : (react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
381
- react_1.default.createElement("path", { d: "M2.5 6l3 3 4.5-5", stroke: "#0F6E56", strokeWidth: "1.5", strokeLinecap: "round" }))))))))),
96
+ doc.flagCount > 0 && (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono rounded-full min-w-[18px] text-center px-1.5 py-0.5", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.06)" } }, doc.flagCount)),
97
+ doc.flagCount === 0 && (react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
98
+ react_1.default.createElement("path", { d: "M2.5 6l3 3 4.5-5", stroke: "#0F6E56", strokeWidth: "1.5", strokeLinecap: "round" })))))))),
382
99
  !dataConfirmed ? (react_1.default.createElement("div", { className: "rounded-[14px]", style: {
383
100
  background: "linear-gradient(135deg, rgba(36,131,132,0.12), rgba(36,131,132,0.06))",
384
101
  border: "1px solid rgba(36,131,132,0.3)",
@@ -410,8 +127,8 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
410
127
  border: "1px solid rgba(15,110,86,0.25)",
411
128
  color: "#0F6E56",
412
129
  } }, "View Report"))))),
413
- (react_1.default.createElement("div", null,
414
- react_1.default.createElement("div", { className: "flex gap-0 mb-5 tax-axis-no-print", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } }, [["report", "Preparer Report"], ["client", "Client Summary"]].map(([id, lbl]) => (react_1.default.createElement("button", { key: id, onClick: () => setReportTab(id), className: "bg-transparent border-0 font-tax-axis-body mr-6", style: {
130
+ topTab === "report" && dataConfirmed && (react_1.default.createElement("div", null,
131
+ react_1.default.createElement("div", { className: "flex gap-0 mb-5", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } }, [["report", "Preparer Report"], ["client", "Client Summary"]].map(([id, lbl]) => (react_1.default.createElement("button", { key: id, onClick: () => setReportTab(id), className: "bg-transparent border-0 font-tax-axis-body mr-6", style: {
415
132
  padding: "10px 0",
416
133
  fontSize: 14,
417
134
  fontWeight: reportTab === id ? 600 : 400,
@@ -422,23 +139,6 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
422
139
  marginBottom: "-1px",
423
140
  } }, lbl)))),
424
141
  reportTab === "report" ? (react_1.default.createElement("div", null,
425
- reviewStatus.unreviewed > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 flex items-center gap-3", style: {
426
- background: "rgba(251,154,29,0.06)",
427
- border: "1px solid rgba(251,154,29,0.20)",
428
- borderLeft: "4px solid #FB9A1D",
429
- padding: "14px 20px",
430
- } },
431
- react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "flex-shrink-0" },
432
- react_1.default.createElement("path", { d: "M8 1.5l6.5 12H1.5L8 1.5z", stroke: "#FB9A1D", strokeWidth: "1.3", fill: "none" }),
433
- react_1.default.createElement("path", { d: "M8 6.5v3M8 11h.005", stroke: "#FB9A1D", strokeWidth: "1.3", strokeLinecap: "round" })),
434
- react_1.default.createElement("div", { className: "flex-1" },
435
- react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body" },
436
- reviewStatus.unreviewed,
437
- " extracted value",
438
- reviewStatus.unreviewed > 1 ? "s" : "",
439
- " flagged for review"),
440
- react_1.default.createElement("span", { className: "text-[12px] text-tax-axis-text-2 font-tax-axis-body ml-2" }, "\u2014 strategy savings may shift after corrections")),
441
- onReviewData && (react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onReviewData, className: "flex-shrink-0" }, "Review Extracted Values")))),
442
142
  react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: {
443
143
  background: "#0E1132",
444
144
  border: "1px solid rgba(36,131,132,0.12)",
@@ -454,94 +154,50 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
454
154
  color: "#9498B8",
455
155
  } }, chartExpanded ? "Collapse \u2191" : "Expand \u2193")),
456
156
  sortedByImpact
457
- .slice(0, chartExpanded ? calculable.length : 12)
157
+ .slice(0, chartExpanded ? dashEligible.length : 12)
458
158
  .map((s, i) => {
459
159
  var _a, _b, _c, _d;
460
160
  const chi = (_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi;
461
161
  const clo = (_d = (_c = computed.get(s.rank)) === null || _c === void 0 ? void 0 : _c.lo) !== null && _d !== void 0 ? _d : s.lo;
462
162
  const w = (chi / maxSavings) * 100;
463
163
  return (react_1.default.createElement("div", { key: s.rank, className: "flex items-center gap-3 cursor-pointer", style: { marginBottom: chartExpanded ? 14 : 10 }, onClick: () => setSelected(s) },
464
- react_1.default.createElement("span", { className: `text-tax-axis-text font-tax-axis-body flex-shrink-0 overflow-hidden text-ellipsis whitespace-nowrap ${chartExpanded ? "w-[100px] sm:w-[180px] text-[13px]" : "w-[100px] sm:w-[140px] text-[12px]"}` }, s.name),
164
+ react_1.default.createElement("span", { className: "text-tax-axis-text font-tax-axis-body flex-shrink-0 overflow-hidden text-ellipsis whitespace-nowrap", style: {
165
+ fontSize: chartExpanded ? 13 : 12,
166
+ width: chartExpanded ? 180 : 140,
167
+ } }, s.name),
465
168
  react_1.default.createElement("div", { className: "flex-1 bg-tax-axis-surface-2 rounded-sm overflow-hidden", style: { height: chartExpanded ? 10 : 6 } },
466
169
  react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
467
170
  width: `${w}%`,
468
171
  background: "linear-gradient(90deg, #248384, #A1E5E6)",
469
172
  transition: "width 0.8s cubic-bezier(.16,1,.3,1)",
470
173
  } })),
471
- react_1.default.createElement("span", { className: `font-semibold text-tax-axis-teal-light font-tax-axis-mono flex-shrink-0 text-right ${chartExpanded ? "w-[60px] sm:w-[100px] text-[13px]" : "w-[60px] sm:w-[80px] text-[12px]"}` },
174
+ react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light font-tax-axis-mono flex-shrink-0 text-right", style: {
175
+ fontSize: chartExpanded ? 13 : 12,
176
+ width: chartExpanded ? 100 : 80,
177
+ } },
472
178
  fmtK(clo),
473
179
  "\u2013",
474
180
  fmtK(chi))));
475
181
  }),
476
- !chartExpanded && calculable.length > 12 && (react_1.default.createElement("div", { onClick: () => setChartExpanded(true), className: "text-[11px] text-tax-axis-teal-light font-tax-axis-mono mt-1 cursor-pointer hover:underline" },
182
+ !chartExpanded && dashEligible.length > 12 && (react_1.default.createElement("div", { onClick: () => setChartExpanded(true), className: "text-[11px] text-tax-axis-teal-light font-tax-axis-mono mt-1 cursor-pointer hover:underline" },
477
183
  "+ ",
478
- calculable.length - 12,
184
+ dashEligible.length - 12,
479
185
  " more strategies \u2014 click to view all")),
480
186
  chartExpanded && (react_1.default.createElement("div", { onClick: () => setChartExpanded(false), className: "text-[11px] text-tax-axis-text-3 font-tax-axis-mono mt-1 cursor-pointer hover:text-tax-axis-teal" },
481
187
  "Showing all ",
482
- calculable.length,
188
+ dashEligible.length,
483
189
  " strategies \u2014 click to collapse"))),
484
190
  react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest mb-2.5 font-tax-axis-head flex justify-between items-center" },
485
191
  react_1.default.createElement("span", null,
486
192
  dashEligible.length,
487
193
  " Strategies"),
488
194
  react_1.default.createElement("span", { className: "font-normal normal-case tracking-normal text-tax-axis-text-2 text-xs font-tax-axis-body" }, "Click to explore")),
489
- react_1.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2.5 mb-4" },
490
- calculable.map((s, i) => {
491
- var _a, _b;
492
- const c = computed.get(s.rank);
493
- return (react_1.default.createElement(StrategyTile_1.StrategyTile, { key: s.rank, s: Object.assign(Object.assign({}, s), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi }), delay: 0.2 + i * 0.06, onClick: () => setSelected(s), maxSavings: maxSavings }));
494
- }),
495
- hasLlm && uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, onClick: () => setSelected(s), className: "rounded-[14px] p-4 cursor-pointer", style: {
496
- background: "#0E1132",
497
- border: "1px solid rgba(36,131,132,0.12)",
498
- boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
499
- animationDelay: `${0.2 + (calculable.length + i) * 0.06}s`,
500
- } },
501
- react_1.default.createElement("div", { className: "flex items-start justify-between gap-2 mb-2" },
502
- react_1.default.createElement("div", { className: "flex items-center gap-2 flex-wrap" },
503
- react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(36,131,132,0.12)", color: "#A1E5E6", border: "1px solid rgba(36,131,132,0.2)" } }, s.code),
504
- react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(148,152,184,0.1)", color: "#9498B8", border: "1px solid rgba(148,152,184,0.15)" } }, "Qualitative")),
505
- react_1.default.createElement("div", { className: "w-8 h-8 rounded-full flex items-center justify-center text-[12px] font-bold font-tax-axis-mono flex-shrink-0", style: {
506
- background: "conic-gradient(#248384 0%, #248384 55%, #1A1D3A 55%)",
507
- color: "#A1E5E6",
508
- } }, s.score)),
509
- react_1.default.createElement("div", { className: "text-[14px] font-semibold text-white font-tax-axis-head mb-1 leading-tight" }, s.name),
510
- react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-teal-light font-tax-axis-mono mb-2" }, s.timeline),
511
- react_1.default.createElement("div", { className: "h-0.5 w-full rounded-sm mb-2", style: { background: "rgba(36,131,132,0.2)" } }),
512
- react_1.default.createElement("p", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body leading-relaxed line-clamp-2" }, s.abstract || s.clientBrief))))),
513
- uncalculated.length > 0 && !hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
514
- background: "#0E1132",
515
- border: "1px solid rgba(251,154,29,0.15)",
516
- boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
517
- } },
518
- react_1.default.createElement("div", { onClick: () => setUncalcExpanded((p) => !p), className: "px-5 py-3.5 flex items-center gap-3 cursor-pointer" },
519
- react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", className: "flex-shrink-0" },
520
- react_1.default.createElement("circle", { cx: "7", cy: "7", r: "5.5", stroke: "#FB9A1D", strokeWidth: "1.2" }),
521
- react_1.default.createElement("path", { d: "M7 4.5v3M7 9.5h.005", stroke: "#FB9A1D", strokeWidth: "1.2", strokeLinecap: "round" })),
522
- react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body flex-1" }, hasLlm
523
- ? `${uncalculated.length} qualitative strateg${uncalculated.length > 1 ? "ies" : "y"} — CPA review recommended`
524
- : `${uncalculated.length} strateg${uncalculated.length > 1 ? "ies" : "y"} need more data to calculate savings`),
525
- react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: {
526
- transform: uncalcExpanded ? "rotate(180deg)" : "none",
527
- transition: "transform .2s",
528
- } },
529
- react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
530
- uncalcExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(251,154,29,0.12)", padding: "12px 20px" } },
531
- uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, className: "py-2.5 cursor-pointer", style: {
532
- borderBottom: i < uncalculated.length - 1
533
- ? "1px solid rgba(36,131,132,0.08)"
534
- : "none",
535
- }, onClick: () => setSelected(s) },
536
- react_1.default.createElement("div", { className: "flex items-center gap-2.5 mb-1" },
537
- react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono px-2 py-0.5 rounded", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.08)", border: "1px solid rgba(251,154,29,0.15)" } }, s.code),
538
- react_1.default.createElement("span", { className: "text-[13px] text-white font-tax-axis-body font-semibold" }, s.name)),
539
- react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body pl-0.5" }, hasLlm
540
- ? (s.abstract || s.clientBrief || "See CPA for details")
541
- : `Needs: ${(strategyDocNeeds.get(s.name) || ["Upload additional documents"]).join(", ")}`)))),
542
- !hasLlm && onUploadMore && (react_1.default.createElement("div", { className: "pt-3 mt-1", style: { borderTop: "1px solid rgba(251,154,29,0.12)" } },
543
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onUploadMore }, "Upload Documents"))))))),
544
- !hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
195
+ react_1.default.createElement("div", { className: "grid grid-cols-2 gap-2.5 mb-4" }, dashEligible.map((s, i) => {
196
+ var _a, _b;
197
+ const c = computed.get(s.rank);
198
+ return (react_1.default.createElement(StrategyTile_1.StrategyTile, { key: s.rank, s: Object.assign(Object.assign({}, s), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi }), delay: 0.2 + i * 0.06, onClick: () => setSelected(s), maxSavings: maxSavings }));
199
+ })),
200
+ react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
545
201
  background: "#0E1132",
546
202
  border: "1px solid rgba(36,131,132,0.12)",
547
203
  boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
@@ -554,50 +210,19 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
554
210
  react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text" }, a.name),
555
211
  react_1.default.createElement("div", { className: "flex items-center gap-2.5" },
556
212
  react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-2" }, a.savings),
557
- react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority))))))),
558
- engagementRecs.length > 0 && (react_1.default.createElement("div", { className: "mb-4" },
559
- react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head mb-3" }, "CPA Engagement Notes"),
560
- react_1.default.createElement("div", { className: "flex flex-col gap-3" }, engagementRecs.map((rec, i) => {
561
- const colonIdx = rec.indexOf(":");
562
- const hasLabel = colonIdx > 0 && colonIdx < 60;
563
- const label = hasLabel ? rec.slice(0, colonIdx).trim() : null;
564
- const body = hasLabel ? rec.slice(colonIdx + 1).trim() : rec;
565
- return (react_1.default.createElement("div", { key: i, className: "rounded-[10px] p-4", style: {
566
- background: "#0E1132",
567
- border: "1px solid rgba(36,131,132,0.12)",
568
- borderLeft: "3px solid rgba(36,131,132,0.4)",
569
- } },
570
- label && (react_1.default.createElement("div", { className: "text-xs font-semibold tracking-wide text-tax-axis-teal-light font-tax-axis-mono mb-1.5 uppercase" }, label)),
571
- react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body" }, body)));
572
- })))),
573
- nexusFlags.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)", padding: "16px 20px" } },
574
- react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2" }, "State Nexus"),
575
- nexusFlags.map((f, i) => (react_1.default.createElement("div", { key: i, className: "text-[12px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(36,131,132,0.08)" : "none" } },
576
- react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light mr-2" }, f.state),
577
- f.flag_text))))),
578
- riskDisclosures.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 overflow-hidden", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)" } },
579
- react_1.default.createElement("div", { className: "px-5 py-3.5 flex items-center justify-between cursor-pointer", onClick: () => setRiskExpanded(p => !p) },
580
- react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text-2 font-tax-axis-body" }, "Risk disclosures & IRC \u00A76694 notices"),
581
- react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { transform: riskExpanded ? "rotate(180deg)" : "none", transition: "transform .2s" } },
582
- react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
583
- riskExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(251,154,29,0.12)", padding: "12px 20px" } }, riskDisclosures.map((r, i) => (react_1.default.createElement("div", { key: i, className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(251,154,29,0.08)" : "none" } }, r))))))),
584
- excludedStrategies.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 overflow-hidden", style: { background: "#0E1132", border: "1px solid rgba(148,152,184,0.15)" } },
585
- react_1.default.createElement("div", { className: "px-5 py-3.5 flex items-center justify-between cursor-pointer", onClick: () => setExcludedExpanded(p => !p) },
586
- react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text-2 font-tax-axis-body" },
587
- excludedStrategies.length,
588
- " strategies screened \u2014 not applicable to this client"),
589
- react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { transform: excludedExpanded ? "rotate(180deg)" : "none", transition: "transform .2s" } },
590
- react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
591
- excludedExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(148,152,184,0.1)" } }, excludedStrategies.map((ex, i) => (react_1.default.createElement("div", { key: i, className: "px-5 py-2.5 flex items-start gap-3", style: { borderTop: i > 0 ? "1px solid rgba(148,152,184,0.08)" : "none" } },
592
- react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono text-tax-axis-text-3 bg-tax-axis-surface px-2 py-0.5 rounded flex-shrink-0 mt-0.5" }, ex.strategy_id),
593
- react_1.default.createElement("div", { className: "flex-1" },
594
- react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body" }, ex.reason),
595
- ex.irs_cite && (react_1.default.createElement("div", { className: "text-[10px] text-tax-axis-text-3 font-tax-axis-mono mt-0.5" }, ex.irs_cite)))))))))),
596
- react_1.default.createElement("div", { className: "tax-axis-no-print" },
213
+ react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority)))))),
214
+ react_1.default.createElement("div", { className: "rounded-[10px] mb-4 text-xs text-tax-axis-text leading-[1.7] font-tax-axis-body", style: {
215
+ padding: "14px 18px",
216
+ background: "#0E1132",
217
+ border: "1px solid rgba(36,131,132,0.12)",
218
+ } },
219
+ react_1.default.createElement("strong", null, "\u00A76694 Preparer Compliance \u2014 "),
220
+ "All HIGH priority strategies hold Substantial Authority (established IRS guidance supporting the position). No elevated preparer penalty exposure for positions taken on these strategies. OBBBA strategies default to Reasonable Basis pending IRS guidance \u2014 CPA verification required before filing."),
221
+ react_1.default.createElement("div", { style: { position: "sticky", bottom: 24, zIndex: 10, paddingTop: 12, background: "linear-gradient(to bottom, transparent 0%, #060821 24%)" } },
597
222
  react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadPreparer, className: "w-full" }, "Download Full Preparer Report")))) : (
598
223
  /* ═══ CLIENT SUMMARY — Timeline View ═══ */
599
224
  react_1.default.createElement("div", null,
600
- clientSummaryOpening ? (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body", style: { background: "rgba(36,131,132,0.04)", border: "1px solid rgba(36,131,132,0.1)", padding: "14px 16px" } }, clientSummaryOpening)) : (react_1.default.createElement("p", { className: "text-sm text-tax-axis-text leading-[1.7] mb-6 font-tax-axis-body" },
225
+ react_1.default.createElement("p", { className: "text-sm text-tax-axis-text leading-[1.7] mb-6 font-tax-axis-body" },
601
226
  profile.bizName || "Client",
602
227
  ", here's your action plan organized by urgency.",
603
228
  " ",
@@ -605,13 +230,7 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
605
230
  dashEligible.length,
606
231
  " strategies"),
607
232
  " ",
608
- "identified.")),
609
- dataQualityNote && (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[11px] text-tax-axis-text-2 font-tax-axis-body flex items-start gap-2", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)", padding: "10px 14px" } },
610
- react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", className: "flex-shrink-0 mt-0.5" },
611
- react_1.default.createElement("circle", { cx: "6", cy: "6", r: "5", stroke: "#FB9A1D", strokeWidth: "1" }),
612
- react_1.default.createElement("path", { d: "M6 4v2.5M6 8h.005", stroke: "#FB9A1D", strokeWidth: "1", strokeLinecap: "round" })),
613
- dataQualityNote)),
614
- interactionWarning && (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[11px] text-tax-axis-text-2 font-tax-axis-body", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)", padding: "10px 14px" } }, interactionWarning)),
233
+ "identified."),
615
234
  BUCKETS.map(({ key, label, desc }) => {
616
235
  const items = dashEligible.filter((s) => s.timelineBucket === key);
617
236
  if (!items.length)
@@ -660,10 +279,7 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
660
279
  s.cost && s.cost !== "$0" && (react_1.default.createElement("span", { className: "text-[11px] font-semibold font-tax-axis-mono", style: { color: "#FB9A1D" } }, s.cost)))));
661
280
  })));
662
281
  }),
663
- react_1.default.createElement("div", { className: "tax-axis-no-print" },
664
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadClient, className: "w-full mt-1.5" }, "Download Client Summary")),
665
- clientSummaryClosing && (react_1.default.createElement("div", { className: "mt-4 text-[11px] text-tax-axis-text-3 leading-[1.65] font-tax-axis-body", style: { borderTop: "1px solid rgba(36,131,132,0.08)", paddingTop: 14 } }, clientSummaryClosing)))),
666
- react_1.default.createElement("div", { className: "tax-axis-no-print" },
667
- react_1.default.createElement(DashboardActions_1.DashboardActions, { profile: profile, dashEligible: dashEligible, computed: computed, onDownloadPreparer: onDownloadPreparer, onPresent: onPresent, onSend: onSend, onReset: onReset })))),
282
+ react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadClient, className: "w-full mt-1.5" }, "Download Client Summary"))),
283
+ react_1.default.createElement(DashboardActions_1.DashboardActions, { profile: profile, dashEligible: dashEligible, computed: computed, onDownloadPreparer: onDownloadPreparer, onPresent: onPresent, onSend: onSend, onReset: onReset }))),
668
284
  enrichedSelected && (react_1.default.createElement(StrategyDetailPanel_1.StrategyDetailPanel, { s: enrichedSelected, profile: profile, computed: computed, onClose: () => setSelected(null) }))));
669
285
  }