@salesmind-ai/design-system 0.3.0 → 0.3.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 (212) hide show
  1. package/README.md +32 -2
  2. package/dist/admin/index.cjs +68 -2928
  3. package/dist/admin/index.cjs.map +1 -1
  4. package/dist/admin/index.js +5 -2915
  5. package/dist/admin/index.js.map +1 -1
  6. package/dist/blog/index.cjs +53 -1064
  7. package/dist/blog/index.cjs.map +1 -1
  8. package/dist/blog/index.js +8 -1054
  9. package/dist/blog/index.js.map +1 -1
  10. package/dist/charts/index.cjs +46 -2694
  11. package/dist/charts/index.cjs.map +1 -1
  12. package/dist/charts/index.js +3 -2680
  13. package/dist/charts/index.js.map +1 -1
  14. package/dist/chunk-2GARWEJK.js +17 -0
  15. package/dist/chunk-2GARWEJK.js.map +1 -0
  16. package/dist/chunk-3NKRFUAR.js +37 -0
  17. package/dist/chunk-3NKRFUAR.js.map +1 -0
  18. package/dist/chunk-3TGSIILM.cjs +201 -0
  19. package/dist/chunk-3TGSIILM.cjs.map +1 -0
  20. package/dist/chunk-4GM5BGBN.cjs +801 -0
  21. package/dist/chunk-4GM5BGBN.cjs.map +1 -0
  22. package/dist/chunk-5LGDEZWY.cjs +2434 -0
  23. package/dist/chunk-5LGDEZWY.cjs.map +1 -0
  24. package/dist/chunk-6H4DSTXR.js +786 -0
  25. package/dist/chunk-6H4DSTXR.js.map +1 -0
  26. package/dist/chunk-6UNG76Y2.js +153 -0
  27. package/dist/chunk-6UNG76Y2.js.map +1 -0
  28. package/dist/chunk-7PX2AZ6Y.js +39 -0
  29. package/dist/chunk-7PX2AZ6Y.js.map +1 -0
  30. package/dist/chunk-B6AVAX4F.js +1415 -0
  31. package/dist/chunk-B6AVAX4F.js.map +1 -0
  32. package/dist/chunk-BILT5KD3.js +264 -0
  33. package/dist/chunk-BILT5KD3.js.map +1 -0
  34. package/dist/chunk-C2BCDNAV.js +24 -0
  35. package/dist/chunk-C2BCDNAV.js.map +1 -0
  36. package/dist/chunk-CH42VPWE.cjs +421 -0
  37. package/dist/chunk-CH42VPWE.cjs.map +1 -0
  38. package/dist/chunk-CJ2MKVAF.cjs +46 -0
  39. package/dist/chunk-CJ2MKVAF.cjs.map +1 -0
  40. package/dist/chunk-DP74LUXG.cjs +98 -0
  41. package/dist/chunk-DP74LUXG.cjs.map +1 -0
  42. package/dist/chunk-E7D6EKJ4.cjs +44 -0
  43. package/dist/chunk-E7D6EKJ4.cjs.map +1 -0
  44. package/dist/chunk-ECXBTUH6.cjs +584 -0
  45. package/dist/chunk-ECXBTUH6.cjs.map +1 -0
  46. package/dist/chunk-EFRAP5ES.js +157 -0
  47. package/dist/chunk-EFRAP5ES.js.map +1 -0
  48. package/dist/chunk-F6YYWMME.js +485 -0
  49. package/dist/chunk-F6YYWMME.js.map +1 -0
  50. package/dist/chunk-FAFAP4L5.js +183 -0
  51. package/dist/chunk-FAFAP4L5.js.map +1 -0
  52. package/dist/chunk-GUZIMHWS.js +1608 -0
  53. package/dist/chunk-GUZIMHWS.js.map +1 -0
  54. package/dist/chunk-H2Y6BSTL.cjs +69 -0
  55. package/dist/chunk-H2Y6BSTL.cjs.map +1 -0
  56. package/dist/chunk-HN4PHABT.js +126 -0
  57. package/dist/chunk-HN4PHABT.js.map +1 -0
  58. package/dist/chunk-HRENHNDJ.js +211 -0
  59. package/dist/chunk-HRENHNDJ.js.map +1 -0
  60. package/dist/chunk-I75BFEYT.cjs +2561 -0
  61. package/dist/chunk-I75BFEYT.cjs.map +1 -0
  62. package/dist/chunk-IFRATNLU.js +562 -0
  63. package/dist/chunk-IFRATNLU.js.map +1 -0
  64. package/dist/chunk-IYPXJ6YC.cjs +69 -0
  65. package/dist/chunk-IYPXJ6YC.cjs.map +1 -0
  66. package/dist/chunk-JPJN4YBC.js +409 -0
  67. package/dist/chunk-JPJN4YBC.js.map +1 -0
  68. package/dist/chunk-KBA2LFBG.js +62 -0
  69. package/dist/chunk-KBA2LFBG.js.map +1 -0
  70. package/dist/chunk-KCKUSU2M.cjs +166 -0
  71. package/dist/chunk-KCKUSU2M.cjs.map +1 -0
  72. package/dist/chunk-KJ2OXQF4.js +287 -0
  73. package/dist/chunk-KJ2OXQF4.js.map +1 -0
  74. package/dist/chunk-KNQEIU7O.cjs +1202 -0
  75. package/dist/chunk-KNQEIU7O.cjs.map +1 -0
  76. package/dist/chunk-KVGSVGRK.cjs +569 -0
  77. package/dist/chunk-KVGSVGRK.cjs.map +1 -0
  78. package/dist/chunk-L352JRV6.cjs +105 -0
  79. package/dist/chunk-L352JRV6.cjs.map +1 -0
  80. package/dist/chunk-LJADZITX.cjs +298 -0
  81. package/dist/chunk-LJADZITX.cjs.map +1 -0
  82. package/dist/chunk-LMJPWXTZ.cjs +194 -0
  83. package/dist/chunk-LMJPWXTZ.cjs.map +1 -0
  84. package/dist/chunk-LOWEAQST.js +701 -0
  85. package/dist/chunk-LOWEAQST.js.map +1 -0
  86. package/dist/chunk-MDB2WCRQ.cjs +137 -0
  87. package/dist/chunk-MDB2WCRQ.cjs.map +1 -0
  88. package/dist/chunk-MQDEE7HC.cjs +283 -0
  89. package/dist/chunk-MQDEE7HC.cjs.map +1 -0
  90. package/dist/chunk-MQRB634A.cjs +34 -0
  91. package/dist/chunk-MQRB634A.cjs.map +1 -0
  92. package/dist/chunk-MTI27RDV.js +185 -0
  93. package/dist/chunk-MTI27RDV.js.map +1 -0
  94. package/dist/chunk-MU6GW5ZV.js +2317 -0
  95. package/dist/chunk-MU6GW5ZV.js.map +1 -0
  96. package/dist/chunk-NN3TUHIH.js +28 -0
  97. package/dist/chunk-NN3TUHIH.js.map +1 -0
  98. package/dist/chunk-NT4LBP7D.cjs +111 -0
  99. package/dist/chunk-NT4LBP7D.cjs.map +1 -0
  100. package/dist/chunk-OLV7OD3X.cjs +502 -0
  101. package/dist/chunk-OLV7OD3X.cjs.map +1 -0
  102. package/dist/chunk-OXNXEQY7.js +2538 -0
  103. package/dist/chunk-OXNXEQY7.js.map +1 -0
  104. package/dist/chunk-P5BOFE5A.js +546 -0
  105. package/dist/chunk-P5BOFE5A.js.map +1 -0
  106. package/dist/chunk-Q2MFGYTE.cjs +1449 -0
  107. package/dist/chunk-Q2MFGYTE.cjs.map +1 -0
  108. package/dist/chunk-Q75DBVDY.cjs +68 -0
  109. package/dist/chunk-Q75DBVDY.cjs.map +1 -0
  110. package/dist/chunk-REQ5Q6ZI.js +1022 -0
  111. package/dist/chunk-REQ5Q6ZI.js.map +1 -0
  112. package/dist/chunk-SICKWUWB.js +62 -0
  113. package/dist/chunk-SICKWUWB.js.map +1 -0
  114. package/dist/chunk-T343CCH5.js +1190 -0
  115. package/dist/chunk-T343CCH5.js.map +1 -0
  116. package/dist/chunk-TEC62D4A.cjs +1624 -0
  117. package/dist/chunk-TEC62D4A.cjs.map +1 -0
  118. package/dist/chunk-TW5JB35D.js +2122 -0
  119. package/dist/chunk-TW5JB35D.js.map +1 -0
  120. package/dist/chunk-VC5LMUVQ.cjs +20 -0
  121. package/dist/chunk-VC5LMUVQ.cjs.map +1 -0
  122. package/dist/chunk-VM7WFMKI.cjs +76 -0
  123. package/dist/chunk-VM7WFMKI.cjs.map +1 -0
  124. package/dist/chunk-W2WTP6HS.cjs +233 -0
  125. package/dist/chunk-W2WTP6HS.cjs.map +1 -0
  126. package/dist/chunk-WH7PYHZY.cjs +35 -0
  127. package/dist/chunk-WH7PYHZY.cjs.map +1 -0
  128. package/dist/chunk-XQZVY7JJ.cjs +717 -0
  129. package/dist/chunk-XQZVY7JJ.cjs.map +1 -0
  130. package/dist/chunk-XU3OMQ7V.js +98 -0
  131. package/dist/chunk-XU3OMQ7V.js.map +1 -0
  132. package/dist/chunk-XWPDRMZG.js +62 -0
  133. package/dist/chunk-XWPDRMZG.js.map +1 -0
  134. package/dist/chunk-Y3CPKNB7.js +67 -0
  135. package/dist/chunk-Y3CPKNB7.js.map +1 -0
  136. package/dist/chunk-YNVRDD2P.js +98 -0
  137. package/dist/chunk-YNVRDD2P.js.map +1 -0
  138. package/dist/chunk-YSYR54XR.js +92 -0
  139. package/dist/chunk-YSYR54XR.js.map +1 -0
  140. package/dist/chunk-YTYDQBVY.cjs +162 -0
  141. package/dist/chunk-YTYDQBVY.cjs.map +1 -0
  142. package/dist/chunk-ZDLOA2UT.cjs +1042 -0
  143. package/dist/chunk-ZDLOA2UT.cjs.map +1 -0
  144. package/dist/chunk-ZWUKRCOJ.cjs +2162 -0
  145. package/dist/chunk-ZWUKRCOJ.cjs.map +1 -0
  146. package/dist/core/index.cjs +807 -4333
  147. package/dist/core/index.cjs.map +1 -1
  148. package/dist/core/index.js +14 -4130
  149. package/dist/core/index.js.map +1 -1
  150. package/dist/i18n/index.cjs +86 -558
  151. package/dist/i18n/index.cjs.map +1 -1
  152. package/dist/i18n/index.js +1 -544
  153. package/dist/i18n/index.js.map +1 -1
  154. package/dist/index.cjs +1432 -17139
  155. package/dist/index.cjs.map +1 -1
  156. package/dist/index.css +11 -7
  157. package/dist/index.css.map +1 -1
  158. package/dist/index.js +31 -16784
  159. package/dist/index.js.map +1 -1
  160. package/dist/marketing/index.cjs +142 -3072
  161. package/dist/marketing/index.cjs.map +1 -1
  162. package/dist/marketing/index.js +11 -3042
  163. package/dist/marketing/index.js.map +1 -1
  164. package/dist/motion/index.cjs +26 -1222
  165. package/dist/motion/index.cjs.map +1 -1
  166. package/dist/motion/index.js +2 -1215
  167. package/dist/motion/index.js.map +1 -1
  168. package/dist/nav/index.cjs +101 -1518
  169. package/dist/nav/index.cjs.map +1 -1
  170. package/dist/nav/index.js +4 -1498
  171. package/dist/nav/index.js.map +1 -1
  172. package/dist/report/index.cjs +171 -2403
  173. package/dist/report/index.cjs.map +1 -1
  174. package/dist/report/index.js +3 -2363
  175. package/dist/report/index.js.map +1 -1
  176. package/dist/sections/index.cjs +28 -378
  177. package/dist/sections/index.cjs.map +1 -1
  178. package/dist/sections/index.css +1 -4
  179. package/dist/sections/index.css.map +1 -1
  180. package/dist/sections/index.js +4 -372
  181. package/dist/sections/index.js.map +1 -1
  182. package/dist/social-proof/index.cjs +53 -1249
  183. package/dist/social-proof/index.cjs.map +1 -1
  184. package/dist/social-proof/index.css +10 -3
  185. package/dist/social-proof/index.css.map +1 -1
  186. package/dist/social-proof/index.js +6 -1234
  187. package/dist/social-proof/index.js.map +1 -1
  188. package/dist/theme/index.cjs +38 -565
  189. package/dist/theme/index.cjs.map +1 -1
  190. package/dist/theme/index.js +2 -555
  191. package/dist/theme/index.js.map +1 -1
  192. package/dist/web/client/index.cjs +48 -0
  193. package/dist/web/client/index.cjs.map +1 -0
  194. package/dist/web/client/index.css +456 -0
  195. package/dist/web/client/index.css.map +1 -0
  196. package/dist/web/client/index.d.cts +172 -0
  197. package/dist/web/client/index.d.ts +172 -0
  198. package/dist/web/client/index.js +7 -0
  199. package/dist/web/client/index.js.map +1 -0
  200. package/dist/web/index.cjs +158 -1346
  201. package/dist/web/index.cjs.map +1 -1
  202. package/dist/web/index.d.cts +5 -893
  203. package/dist/web/index.d.ts +5 -893
  204. package/dist/web/index.js +9 -1305
  205. package/dist/web/index.js.map +1 -1
  206. package/dist/web/server/index.cjs +32 -0
  207. package/dist/web/server/index.cjs.map +1 -0
  208. package/dist/web/server/index.d.cts +725 -0
  209. package/dist/web/server/index.d.ts +725 -0
  210. package/dist/web/server/index.js +3 -0
  211. package/dist/web/server/index.js.map +1 -0
  212. package/package.json +14 -1
@@ -0,0 +1,1415 @@
1
+ import React2, { createContext, useMemo, useContext } from 'react';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import clsx from 'clsx';
4
+
5
+ // src/report-engine/constants.ts
6
+ var EXECUTIVE_MODE = {
7
+ mode: "executive",
8
+ features: {
9
+ showMethodology: false,
10
+ showConfidenceScores: false,
11
+ showRawData: false,
12
+ showStatisticalTests: false,
13
+ chartDetailLevel: "summary",
14
+ maxInsightsShown: 5,
15
+ allowDrilldown: false
16
+ }
17
+ };
18
+ var ANALYST_MODE = {
19
+ mode: "analyst",
20
+ features: {
21
+ showMethodology: true,
22
+ showConfidenceScores: true,
23
+ showRawData: true,
24
+ showStatisticalTests: true,
25
+ chartDetailLevel: "detailed",
26
+ maxInsightsShown: 20,
27
+ allowDrilldown: true
28
+ }
29
+ };
30
+ var CONFIDENCE_THRESHOLDS = [
31
+ { level: "high", min: 90, max: 100, label: "High Confidence", color: "var(--status-success)" },
32
+ {
33
+ level: "moderate",
34
+ min: 70,
35
+ max: 89,
36
+ label: "Moderate Confidence",
37
+ color: "var(--status-info)"
38
+ },
39
+ { level: "low", min: 50, max: 69, label: "Low Confidence", color: "var(--status-warning)" },
40
+ {
41
+ level: "insufficient",
42
+ min: 0,
43
+ max: 49,
44
+ label: "Insufficient Data",
45
+ color: "var(--status-error)"
46
+ }
47
+ ];
48
+ var MINIMUM_SAMPLE_SIZES = {
49
+ overall: 30,
50
+ segment: 30,
51
+ mbtiType: 50,
52
+ correlation: 100,
53
+ timeSeries: 7
54
+ };
55
+ var INSIGHT_TYPE_CONTRACTS = {
56
+ "performance-delta": {
57
+ type: "performance-delta",
58
+ allowedCharts: ["BarChart", "LineChart", "KeyMetric"],
59
+ requiredFields: ["metric_name", "current_value", "previous_value", "time_period"],
60
+ minSampleSize: 30,
61
+ headlinePattern: "{metric} {direction} by {delta}% {timeframe}",
62
+ recommendationFormats: ["maintain-strategy", "investigate-decline", "scale-success"]
63
+ },
64
+ "behavioral-correlation": {
65
+ type: "behavioral-correlation",
66
+ allowedCharts: ["HeatmapChart", "BarChart"],
67
+ requiredFields: ["variable_a", "variable_b", "correlation_coefficient"],
68
+ minSampleSize: 100,
69
+ headlinePattern: "{variable_a} correlates with {variable_b}",
70
+ recommendationFormats: ["leverage-correlation", "investigate-causation"]
71
+ },
72
+ "funnel-leakage": {
73
+ type: "funnel-leakage",
74
+ allowedCharts: ["FunnelChart", "BarChart"],
75
+ requiredFields: ["stages", "stage_counts", "drop_rates"],
76
+ minSampleSize: 50,
77
+ headlinePattern: "{drop_rate}% drop-off at {stage}",
78
+ recommendationFormats: ["optimize-stage", "remove-friction"]
79
+ },
80
+ "audience-mismatch": {
81
+ type: "audience-mismatch",
82
+ allowedCharts: ["BarChart", "PieChart"],
83
+ requiredFields: ["target_audience", "actual_audience", "overlap_percentage"],
84
+ minSampleSize: 50,
85
+ headlinePattern: "Target audience differs by {mismatch}%",
86
+ recommendationFormats: ["refine-targeting", "expand-audience"]
87
+ },
88
+ "message-fatigue": {
89
+ type: "message-fatigue",
90
+ allowedCharts: ["LineChart", "BarChart"],
91
+ requiredFields: ["message_sequence", "engagement_rates", "fatigue_point"],
92
+ minSampleSize: 100,
93
+ headlinePattern: "Engagement drops {drop}% after message {n}",
94
+ recommendationFormats: ["reduce-frequency", "vary-content"]
95
+ },
96
+ "psychological-resonance": {
97
+ type: "psychological-resonance",
98
+ allowedCharts: ["MBTIRadar", "MBTITypeGrid", "BarChart"],
99
+ requiredFields: ["mbti_types", "response_rates", "message_type"],
100
+ minSampleSize: 50,
101
+ headlinePattern: "{mbti_type} responds {rate}% better to {message_type}",
102
+ recommendationFormats: ["personalize-messaging", "segment-by-type"]
103
+ },
104
+ "timing-pattern": {
105
+ type: "timing-pattern",
106
+ allowedCharts: ["HeatmapChart", "LineChart"],
107
+ requiredFields: ["time_slots", "engagement_rates"],
108
+ minSampleSize: 100,
109
+ headlinePattern: "Best engagement on {day} at {time}",
110
+ recommendationFormats: ["optimize-timing", "schedule-sends"]
111
+ },
112
+ "segment-outperformance": {
113
+ type: "segment-outperformance",
114
+ allowedCharts: ["BarChart", "KeyMetric"],
115
+ requiredFields: ["segments", "performance_metrics", "baseline"],
116
+ minSampleSize: 30,
117
+ headlinePattern: "{segment} outperforms by {delta}%",
118
+ recommendationFormats: ["double-down", "investigate-success"]
119
+ },
120
+ "anomaly-detection": {
121
+ type: "anomaly-detection",
122
+ allowedCharts: ["LineChart", "BarChart"],
123
+ requiredFields: ["metric", "expected_value", "actual_value", "deviation"],
124
+ minSampleSize: 30,
125
+ headlinePattern: "Unusual {direction} in {metric}",
126
+ recommendationFormats: ["investigate", "monitor"]
127
+ },
128
+ "competitive-benchmark": {
129
+ type: "competitive-benchmark",
130
+ allowedCharts: ["BarChart", "KeyMetric"],
131
+ requiredFields: ["metric", "our_value", "benchmark_value"],
132
+ minSampleSize: 30,
133
+ headlinePattern: "{position} industry benchmark by {delta}%",
134
+ recommendationFormats: ["maintain-lead", "close-gap"]
135
+ }
136
+ };
137
+ var ANALYTICAL_STATE_CONFIG = {
138
+ VALID: {
139
+ label: "Valid",
140
+ icon: "check",
141
+ color: "var(--status-success)",
142
+ action: null
143
+ },
144
+ INSUFFICIENT_SAMPLE: {
145
+ label: "Insufficient Sample",
146
+ icon: "alert-triangle",
147
+ color: "var(--status-warning)",
148
+ action: "Add more data"
149
+ },
150
+ LOW_CONFIDENCE: {
151
+ label: "Low Confidence",
152
+ icon: "alert-circle",
153
+ color: "var(--status-warning)",
154
+ action: "Interpret with caution"
155
+ },
156
+ PARTIAL_TIME_WINDOW: {
157
+ label: "Partial Data",
158
+ icon: "clock",
159
+ color: "var(--status-info)",
160
+ action: "Expand date range"
161
+ },
162
+ DATA_SKEW_DETECTED: {
163
+ label: "Data Skew",
164
+ icon: "bar-chart-2",
165
+ color: "var(--status-warning)",
166
+ action: "Review methodology"
167
+ },
168
+ CONFLICTING_SIGNALS: {
169
+ label: "Conflicting Signals",
170
+ icon: "git-merge",
171
+ color: "var(--status-error)",
172
+ action: "Manual review needed"
173
+ },
174
+ INFERRED_NOT_OBSERVED: {
175
+ label: "AI Generated",
176
+ icon: "cpu",
177
+ color: "var(--status-info)",
178
+ action: "Verify with data"
179
+ },
180
+ STALE_DATA: {
181
+ label: "Stale Data",
182
+ icon: "clock",
183
+ color: "var(--status-warning)",
184
+ action: "Refresh data"
185
+ },
186
+ FIELD_MISSING: {
187
+ label: "Missing Field",
188
+ icon: "file-x",
189
+ color: "var(--status-error)",
190
+ action: "Upload complete data"
191
+ },
192
+ CALCULATION_ERROR: {
193
+ label: "Calculation Error",
194
+ icon: "x-circle",
195
+ color: "var(--status-error)",
196
+ action: "Contact support"
197
+ }
198
+ };
199
+
200
+ // src/report-engine/confidence.ts
201
+ function calculateConfidence(params) {
202
+ const { sampleSize, requiredSize, completeness, recency, variance, aiInference } = params;
203
+ const sampleScore = Math.min(40, sampleSize / requiredSize * 40);
204
+ const completenessScore = completeness * 20;
205
+ const recencyScore = recency * 20;
206
+ const variancePenalty = variance * 10;
207
+ const aiPenalty = aiInference ? 10 : 0;
208
+ const rawScore = sampleScore + completenessScore + recencyScore - variancePenalty - aiPenalty;
209
+ return Math.max(0, Math.min(100, Math.round(rawScore)));
210
+ }
211
+ function getConfidenceLevel(score) {
212
+ const threshold = CONFIDENCE_THRESHOLDS.find((t) => score >= t.min && score <= t.max);
213
+ return threshold?.level ?? "insufficient";
214
+ }
215
+ function getConfidenceThreshold(score) {
216
+ return CONFIDENCE_THRESHOLDS.find((t) => score >= t.min && score <= t.max) ?? CONFIDENCE_THRESHOLDS[CONFIDENCE_THRESHOLDS.length - 1];
217
+ }
218
+ function calculateRecency(dataDate, maxAgeDays = 30) {
219
+ const now = /* @__PURE__ */ new Date();
220
+ const ageInDays = (now.getTime() - dataDate.getTime()) / (1e3 * 60 * 60 * 24);
221
+ if (ageInDays <= 0) return 1;
222
+ if (ageInDays >= maxAgeDays) return 0;
223
+ return 1 - ageInDays / maxAgeDays;
224
+ }
225
+ function calculateCompleteness(data, requiredFields) {
226
+ if (data.length === 0 || requiredFields.length === 0) return 0;
227
+ let totalFields = 0;
228
+ let filledFields = 0;
229
+ for (const record of data) {
230
+ for (const field of requiredFields) {
231
+ totalFields++;
232
+ const value = record[field];
233
+ if (value !== null && value !== void 0 && value !== "") {
234
+ filledFields++;
235
+ }
236
+ }
237
+ }
238
+ return totalFields > 0 ? filledFields / totalFields : 0;
239
+ }
240
+ function calculateNormalizedVariance(values) {
241
+ if (values.length < 2) return 0;
242
+ const mean = values.reduce((a, b) => a + b, 0) / values.length;
243
+ const squaredDiffs = values.map((v) => Math.pow(v - mean, 2));
244
+ const variance = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
245
+ const stdDev = Math.sqrt(variance);
246
+ const cv = mean !== 0 ? stdDev / Math.abs(mean) : 0;
247
+ return Math.min(1, cv);
248
+ }
249
+ var ReportModeContext = createContext(null);
250
+ function ReportModeProvider({
251
+ mode = "executive",
252
+ children,
253
+ onModeChange
254
+ }) {
255
+ const config = mode === "executive" ? EXECUTIVE_MODE : ANALYST_MODE;
256
+ const value = useMemo(
257
+ () => ({
258
+ ...config,
259
+ setMode: onModeChange
260
+ }),
261
+ [config, onModeChange]
262
+ );
263
+ return /* @__PURE__ */ jsx(ReportModeContext.Provider, { value, children });
264
+ }
265
+ function useReportMode() {
266
+ const context = useContext(ReportModeContext);
267
+ if (!context) {
268
+ return EXECUTIVE_MODE;
269
+ }
270
+ return context;
271
+ }
272
+ function useDataState(params) {
273
+ const {
274
+ sampleSize,
275
+ requiredSize = MINIMUM_SAMPLE_SIZES.overall,
276
+ completeness = 1,
277
+ recency = 1,
278
+ variance = 0,
279
+ aiInferred = false,
280
+ missingFields = [],
281
+ staleDays
282
+ } = params;
283
+ return useMemo(() => {
284
+ const confidenceParams = {
285
+ sampleSize,
286
+ requiredSize,
287
+ completeness,
288
+ recency,
289
+ variance,
290
+ aiInference: aiInferred
291
+ };
292
+ const confidence = calculateConfidence(confidenceParams);
293
+ const confidenceLevel = getConfidenceLevel(confidence);
294
+ let state = "VALID";
295
+ if (missingFields.length > 0) {
296
+ state = "FIELD_MISSING";
297
+ } else if (sampleSize < requiredSize) {
298
+ state = "INSUFFICIENT_SAMPLE";
299
+ } else if (staleDays && staleDays > 30) {
300
+ state = "STALE_DATA";
301
+ } else if (aiInferred) {
302
+ state = "INFERRED_NOT_OBSERVED";
303
+ } else if (confidence < 50) {
304
+ state = "LOW_CONFIDENCE";
305
+ } else if (variance > 0.7) {
306
+ state = "DATA_SKEW_DETECTED";
307
+ } else if (recency < 0.3) {
308
+ state = "PARTIAL_TIME_WINDOW";
309
+ }
310
+ const details = {
311
+ sampleSize,
312
+ requiredSize,
313
+ confidence,
314
+ missingFields: missingFields.length > 0 ? missingFields : void 0,
315
+ staleDays
316
+ };
317
+ return {
318
+ state,
319
+ confidence,
320
+ confidenceLevel,
321
+ details,
322
+ isValid: state === "VALID"
323
+ };
324
+ }, [
325
+ sampleSize,
326
+ requiredSize,
327
+ completeness,
328
+ recency,
329
+ variance,
330
+ aiInferred,
331
+ missingFields,
332
+ staleDays
333
+ ]);
334
+ }
335
+ function useChartData({
336
+ data,
337
+ requiredFields,
338
+ minSampleSize = MINIMUM_SAMPLE_SIZES.overall
339
+ }) {
340
+ return useMemo(() => {
341
+ const missingFields = [];
342
+ if (data.length > 0) {
343
+ const firstRecord = data[0];
344
+ for (const field of requiredFields) {
345
+ if (!(field in firstRecord)) {
346
+ missingFields.push(field);
347
+ }
348
+ }
349
+ }
350
+ let completeness = 1;
351
+ if (data.length > 0 && requiredFields.length > 0) {
352
+ let filled = 0;
353
+ let total = 0;
354
+ for (const record of data) {
355
+ for (const field of requiredFields) {
356
+ total++;
357
+ const value = record[field];
358
+ if (value !== null && value !== void 0 && value !== "") {
359
+ filled++;
360
+ }
361
+ }
362
+ }
363
+ completeness = total > 0 ? filled / total : 0;
364
+ }
365
+ let state = "VALID";
366
+ let message;
367
+ if (missingFields.length > 0) {
368
+ state = "FIELD_MISSING";
369
+ message = `Missing fields: ${missingFields.join(", ")}`;
370
+ } else if (data.length === 0) {
371
+ state = "INSUFFICIENT_SAMPLE";
372
+ message = "No data available";
373
+ } else if (data.length < minSampleSize) {
374
+ state = "INSUFFICIENT_SAMPLE";
375
+ message = `Sample size ${data.length} is below minimum ${minSampleSize}`;
376
+ } else if (completeness < 0.7) {
377
+ state = "LOW_CONFIDENCE";
378
+ message = `Data completeness is ${Math.round(completeness * 100)}%`;
379
+ }
380
+ const confidence = calculateConfidence({
381
+ sampleSize: data.length,
382
+ requiredSize: minSampleSize,
383
+ completeness,
384
+ recency: 1,
385
+ // Assume fresh data if not specified
386
+ variance: 0,
387
+ aiInference: false
388
+ });
389
+ const isRenderable = state === "VALID" || state === "LOW_CONFIDENCE";
390
+ return {
391
+ data,
392
+ state,
393
+ confidence,
394
+ isRenderable,
395
+ message
396
+ };
397
+ }, [data, requiredFields, minSampleSize]);
398
+ }
399
+
400
+ // src/report-engine/chart-types.ts
401
+ var CHART_REGISTRY = {
402
+ // ══════════════════════════════════════════════════════════════════════════
403
+ // TREND CHARTS (MVP)
404
+ // ══════════════════════════════════════════════════════════════════════════
405
+ line: {
406
+ id: "line",
407
+ name: "Line Chart",
408
+ description: "Shows trends over time with connected data points",
409
+ intent: "trend",
410
+ phase: "mvp",
411
+ contract: {
412
+ requiredDimensions: 1,
413
+ requiredMeasures: 1,
414
+ minDataPoints: 3,
415
+ idealDataPoints: 7,
416
+ allowNegativeValues: true,
417
+ requireNonZeroTotal: false,
418
+ warningThresholds: { sparseData: 3 },
419
+ fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
420
+ },
421
+ switchableTo: ["smooth_line", "area", "stacked_area"],
422
+ supportsStacking: false,
423
+ supportsMultipleSeries: true,
424
+ requiresTimeAxis: true
425
+ },
426
+ smooth_line: {
427
+ id: "smooth_line",
428
+ name: "Smooth Line Chart",
429
+ description: "Curved line chart for smoother trend visualization",
430
+ intent: "trend",
431
+ phase: "mvp",
432
+ contract: {
433
+ requiredDimensions: 1,
434
+ requiredMeasures: 1,
435
+ minDataPoints: 3,
436
+ idealDataPoints: 7,
437
+ allowNegativeValues: true,
438
+ requireNonZeroTotal: false,
439
+ warningThresholds: { sparseData: 3 },
440
+ fallback: { type: "show_kpi", message: "Insufficient data for trend visualization" }
441
+ },
442
+ switchableTo: ["line", "area", "stacked_area"],
443
+ supportsStacking: false,
444
+ supportsMultipleSeries: true,
445
+ requiresTimeAxis: true
446
+ },
447
+ area: {
448
+ id: "area",
449
+ name: "Area Chart",
450
+ description: "Filled area under line, emphasizes volume over time",
451
+ intent: "trend",
452
+ phase: "mvp",
453
+ contract: {
454
+ requiredDimensions: 1,
455
+ requiredMeasures: 1,
456
+ minDataPoints: 3,
457
+ idealDataPoints: 7,
458
+ allowNegativeValues: false,
459
+ requireNonZeroTotal: false,
460
+ warningThresholds: { sparseData: 3 },
461
+ fallback: { type: "show_kpi", message: "Insufficient data for area visualization" }
462
+ },
463
+ switchableTo: ["line", "smooth_line", "stacked_area", "area_100pct"],
464
+ supportsStacking: true,
465
+ supportsMultipleSeries: true,
466
+ requiresTimeAxis: true
467
+ },
468
+ stacked_area: {
469
+ id: "stacked_area",
470
+ name: "Stacked Area Chart",
471
+ description: "Multiple series stacked to show cumulative trends",
472
+ intent: "trend",
473
+ phase: "mvp",
474
+ contract: {
475
+ requiredDimensions: 1,
476
+ requiredMeasures: 2,
477
+ minDataPoints: 3,
478
+ idealDataPoints: 7,
479
+ allowNegativeValues: false,
480
+ requireNonZeroTotal: true,
481
+ warningThresholds: { sparseData: 3 },
482
+ fallback: { type: "warn", message: "Stacked area requires non-negative values" }
483
+ },
484
+ switchableTo: ["line", "area", "area_100pct"],
485
+ supportsStacking: true,
486
+ supportsMultipleSeries: true,
487
+ requiresTimeAxis: true
488
+ },
489
+ area_100pct: {
490
+ id: "area_100pct",
491
+ name: "100% Stacked Area",
492
+ description: "Shows proportional contribution over time",
493
+ intent: "trend",
494
+ phase: "mvp",
495
+ contract: {
496
+ requiredDimensions: 1,
497
+ requiredMeasures: 2,
498
+ minDataPoints: 3,
499
+ idealDataPoints: 7,
500
+ allowNegativeValues: false,
501
+ requireNonZeroTotal: true,
502
+ warningThresholds: { sparseData: 3 },
503
+ fallback: { type: "warn", message: "100% stacked requires positive totals" }
504
+ },
505
+ switchableTo: ["stacked_area", "area"],
506
+ supportsStacking: true,
507
+ supportsMultipleSeries: true,
508
+ requiresTimeAxis: true
509
+ },
510
+ // ══════════════════════════════════════════════════════════════════════════
511
+ // COMPARISON CHARTS (MVP)
512
+ // ══════════════════════════════════════════════════════════════════════════
513
+ bar: {
514
+ id: "bar",
515
+ name: "Horizontal Bar Chart",
516
+ description: "Horizontal bars for comparing categories",
517
+ intent: "comparison",
518
+ phase: "mvp",
519
+ contract: {
520
+ requiredDimensions: 1,
521
+ requiredMeasures: 1,
522
+ minDataPoints: 2,
523
+ idealDataPoints: 5,
524
+ maxDataPoints: 15,
525
+ allowNegativeValues: true,
526
+ requireNonZeroTotal: false,
527
+ warningThresholds: { tooManyCategories: 12 },
528
+ fallback: { type: "aggregate", strategy: "top_n" }
529
+ },
530
+ switchableTo: ["column", "stacked_bar", "stacked_column"],
531
+ supportsStacking: true,
532
+ supportsMultipleSeries: true,
533
+ requiresTimeAxis: false
534
+ },
535
+ column: {
536
+ id: "column",
537
+ name: "Vertical Column Chart",
538
+ description: "Vertical bars for comparing categories",
539
+ intent: "comparison",
540
+ phase: "mvp",
541
+ contract: {
542
+ requiredDimensions: 1,
543
+ requiredMeasures: 1,
544
+ minDataPoints: 2,
545
+ idealDataPoints: 5,
546
+ maxDataPoints: 12,
547
+ allowNegativeValues: true,
548
+ requireNonZeroTotal: false,
549
+ warningThresholds: { tooManyCategories: 10 },
550
+ fallback: { type: "aggregate", strategy: "top_n" }
551
+ },
552
+ switchableTo: ["bar", "stacked_column", "stacked_bar"],
553
+ supportsStacking: true,
554
+ supportsMultipleSeries: true,
555
+ requiresTimeAxis: false
556
+ },
557
+ stacked_bar: {
558
+ id: "stacked_bar",
559
+ name: "Stacked Horizontal Bar",
560
+ description: "Horizontal stacked bars showing composition per category",
561
+ intent: "comparison",
562
+ phase: "mvp",
563
+ contract: {
564
+ requiredDimensions: 1,
565
+ requiredMeasures: 2,
566
+ minDataPoints: 2,
567
+ idealDataPoints: 5,
568
+ maxDataPoints: 10,
569
+ allowNegativeValues: false,
570
+ requireNonZeroTotal: true,
571
+ warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
572
+ fallback: { type: "aggregate", strategy: "other_bucket" }
573
+ },
574
+ switchableTo: ["bar", "stacked_column", "column_100pct"],
575
+ supportsStacking: true,
576
+ supportsMultipleSeries: true,
577
+ requiresTimeAxis: false
578
+ },
579
+ stacked_column: {
580
+ id: "stacked_column",
581
+ name: "Stacked Vertical Column",
582
+ description: "Vertical stacked columns showing composition per category",
583
+ intent: "comparison",
584
+ phase: "mvp",
585
+ contract: {
586
+ requiredDimensions: 1,
587
+ requiredMeasures: 2,
588
+ minDataPoints: 2,
589
+ idealDataPoints: 5,
590
+ maxDataPoints: 10,
591
+ allowNegativeValues: false,
592
+ requireNonZeroTotal: true,
593
+ warningThresholds: { tooManyCategories: 8, imbalancedRatio: 0.9 },
594
+ fallback: { type: "aggregate", strategy: "other_bucket" }
595
+ },
596
+ switchableTo: ["column", "stacked_bar", "column_100pct"],
597
+ supportsStacking: true,
598
+ supportsMultipleSeries: true,
599
+ requiresTimeAxis: false
600
+ },
601
+ column_100pct: {
602
+ id: "column_100pct",
603
+ name: "100% Stacked Column",
604
+ description: "Shows proportional composition per category",
605
+ intent: "comparison",
606
+ phase: "mvp",
607
+ contract: {
608
+ requiredDimensions: 1,
609
+ requiredMeasures: 2,
610
+ minDataPoints: 2,
611
+ idealDataPoints: 5,
612
+ maxDataPoints: 10,
613
+ allowNegativeValues: false,
614
+ requireNonZeroTotal: true,
615
+ warningThresholds: { tooManyCategories: 8 },
616
+ fallback: { type: "warn", message: "100% stacked requires positive totals" }
617
+ },
618
+ switchableTo: ["stacked_column", "stacked_bar"],
619
+ supportsStacking: true,
620
+ supportsMultipleSeries: true,
621
+ requiresTimeAxis: false
622
+ },
623
+ combo: {
624
+ id: "combo",
625
+ name: "Combo Chart",
626
+ description: "Combines bars with line overlay (Phase 2)",
627
+ intent: "comparison",
628
+ phase: "phase2",
629
+ contract: {
630
+ requiredDimensions: 1,
631
+ requiredMeasures: 2,
632
+ minDataPoints: 3,
633
+ idealDataPoints: 6,
634
+ allowNegativeValues: true,
635
+ requireNonZeroTotal: false,
636
+ warningThresholds: { tooManyCategories: 10 },
637
+ fallback: { type: "warn", message: "Combo chart requires dual measures" }
638
+ },
639
+ switchableTo: ["column", "line"],
640
+ supportsStacking: false,
641
+ supportsMultipleSeries: true,
642
+ requiresTimeAxis: false
643
+ },
644
+ // ══════════════════════════════════════════════════════════════════════════
645
+ // COMPOSITION CHARTS (MVP)
646
+ // ══════════════════════════════════════════════════════════════════════════
647
+ pie: {
648
+ id: "pie",
649
+ name: "Pie Chart",
650
+ description: "Shows proportional composition of a whole",
651
+ intent: "composition",
652
+ phase: "mvp",
653
+ contract: {
654
+ requiredDimensions: 1,
655
+ requiredMeasures: 1,
656
+ minDataPoints: 2,
657
+ idealDataPoints: 4,
658
+ maxDataPoints: 6,
659
+ allowNegativeValues: false,
660
+ requireNonZeroTotal: true,
661
+ warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
662
+ fallback: { type: "aggregate", strategy: "other_bucket" }
663
+ },
664
+ switchableTo: ["donut", "column_100pct"],
665
+ supportsStacking: false,
666
+ supportsMultipleSeries: false,
667
+ requiresTimeAxis: false,
668
+ maxSlices: 6
669
+ },
670
+ donut: {
671
+ id: "donut",
672
+ name: "Donut Chart",
673
+ description: "Pie chart with center cutout, can display total",
674
+ intent: "composition",
675
+ phase: "mvp",
676
+ contract: {
677
+ requiredDimensions: 1,
678
+ requiredMeasures: 1,
679
+ minDataPoints: 2,
680
+ idealDataPoints: 4,
681
+ maxDataPoints: 6,
682
+ allowNegativeValues: false,
683
+ requireNonZeroTotal: true,
684
+ warningThresholds: { tooManyCategories: 6, imbalancedRatio: 0.95 },
685
+ fallback: { type: "aggregate", strategy: "other_bucket" }
686
+ },
687
+ switchableTo: ["pie", "column_100pct"],
688
+ supportsStacking: false,
689
+ supportsMultipleSeries: false,
690
+ requiresTimeAxis: false,
691
+ maxSlices: 6
692
+ },
693
+ treemap: {
694
+ id: "treemap",
695
+ name: "Treemap",
696
+ description: "Nested rectangles showing hierarchical composition (Phase 2)",
697
+ intent: "composition",
698
+ phase: "phase2",
699
+ contract: {
700
+ requiredDimensions: 1,
701
+ requiredMeasures: 1,
702
+ minDataPoints: 3,
703
+ idealDataPoints: 10,
704
+ maxDataPoints: 50,
705
+ allowNegativeValues: false,
706
+ requireNonZeroTotal: true,
707
+ warningThresholds: { tooManyCategories: 30 },
708
+ fallback: { type: "aggregate", strategy: "top_n" }
709
+ },
710
+ switchableTo: ["pie", "donut"],
711
+ supportsStacking: false,
712
+ supportsMultipleSeries: false,
713
+ requiresTimeAxis: false
714
+ },
715
+ // ══════════════════════════════════════════════════════════════════════════
716
+ // DISTRIBUTION CHARTS (MVP)
717
+ // ══════════════════════════════════════════════════════════════════════════
718
+ histogram: {
719
+ id: "histogram",
720
+ name: "Histogram",
721
+ description: "Shows distribution of values across bins",
722
+ intent: "distribution",
723
+ phase: "mvp",
724
+ contract: {
725
+ requiredDimensions: 0,
726
+ requiredMeasures: 1,
727
+ minDataPoints: 10,
728
+ idealDataPoints: 50,
729
+ allowNegativeValues: true,
730
+ requireNonZeroTotal: false,
731
+ warningThresholds: { sparseData: 10 },
732
+ fallback: { type: "show_kpi", message: "Insufficient data for distribution" }
733
+ },
734
+ switchableTo: ["radar"],
735
+ supportsStacking: false,
736
+ supportsMultipleSeries: false,
737
+ requiresTimeAxis: false
738
+ },
739
+ radar: {
740
+ id: "radar",
741
+ name: "Radar Chart",
742
+ description: "Multi-dimensional comparison in radial layout (Phase 2)",
743
+ intent: "distribution",
744
+ phase: "phase2",
745
+ contract: {
746
+ requiredDimensions: 1,
747
+ requiredMeasures: 3,
748
+ minDataPoints: 3,
749
+ idealDataPoints: 6,
750
+ maxDataPoints: 8,
751
+ allowNegativeValues: false,
752
+ requireNonZeroTotal: false,
753
+ warningThresholds: { tooManyCategories: 8 },
754
+ fallback: { type: "warn", message: "Radar works best with 3-8 dimensions" }
755
+ },
756
+ switchableTo: ["histogram"],
757
+ supportsStacking: false,
758
+ supportsMultipleSeries: true,
759
+ requiresTimeAxis: false
760
+ },
761
+ // ══════════════════════════════════════════════════════════════════════════
762
+ // RELATIONSHIP CHARTS
763
+ // ══════════════════════════════════════════════════════════════════════════
764
+ heatmap: {
765
+ id: "heatmap",
766
+ name: "Heatmap",
767
+ description: "Color-coded matrix showing intensity",
768
+ intent: "relationship",
769
+ phase: "mvp",
770
+ contract: {
771
+ requiredDimensions: 2,
772
+ requiredMeasures: 1,
773
+ minDataPoints: 9,
774
+ idealDataPoints: 25,
775
+ allowNegativeValues: true,
776
+ requireNonZeroTotal: false,
777
+ warningThresholds: { sparseData: 9 },
778
+ fallback: { type: "warn", message: "Heatmap requires grid data" }
779
+ },
780
+ switchableTo: ["scatter"],
781
+ supportsStacking: false,
782
+ supportsMultipleSeries: false,
783
+ requiresTimeAxis: false
784
+ },
785
+ scatter: {
786
+ id: "scatter",
787
+ name: "Scatter Plot",
788
+ description: "Shows correlation between two variables (Phase 2)",
789
+ intent: "relationship",
790
+ phase: "phase2",
791
+ contract: {
792
+ requiredDimensions: 0,
793
+ requiredMeasures: 2,
794
+ minDataPoints: 20,
795
+ idealDataPoints: 100,
796
+ allowNegativeValues: true,
797
+ requireNonZeroTotal: false,
798
+ warningThresholds: { sparseData: 20 },
799
+ fallback: { type: "show_kpi", message: "Scatter requires 20+ points" }
800
+ },
801
+ switchableTo: ["bubble", "heatmap"],
802
+ supportsStacking: false,
803
+ supportsMultipleSeries: true,
804
+ requiresTimeAxis: false
805
+ },
806
+ bubble: {
807
+ id: "bubble",
808
+ name: "Bubble Chart",
809
+ description: "Scatter with sized points for third dimension (Phase 2)",
810
+ intent: "relationship",
811
+ phase: "phase2",
812
+ contract: {
813
+ requiredDimensions: 0,
814
+ requiredMeasures: 3,
815
+ minDataPoints: 10,
816
+ idealDataPoints: 50,
817
+ allowNegativeValues: true,
818
+ requireNonZeroTotal: false,
819
+ warningThresholds: { sparseData: 10 },
820
+ fallback: { type: "show_kpi", message: "Bubble requires 3 measures" }
821
+ },
822
+ switchableTo: ["scatter"],
823
+ supportsStacking: false,
824
+ supportsMultipleSeries: true,
825
+ requiresTimeAxis: false
826
+ },
827
+ // ══════════════════════════════════════════════════════════════════════════
828
+ // GEOGRAPHIC CHARTS (Phase 2)
829
+ // ══════════════════════════════════════════════════════════════════════════
830
+ geo: {
831
+ id: "geo",
832
+ name: "Geographic Map",
833
+ description: "Map with regional data markers (Phase 2)",
834
+ intent: "geo",
835
+ phase: "phase2",
836
+ contract: {
837
+ requiredDimensions: 1,
838
+ // geo dimension (country/region)
839
+ requiredMeasures: 1,
840
+ minDataPoints: 1,
841
+ idealDataPoints: 10,
842
+ allowNegativeValues: true,
843
+ requireNonZeroTotal: false,
844
+ warningThresholds: {},
845
+ fallback: { type: "hide" }
846
+ },
847
+ switchableTo: ["choropleth"],
848
+ supportsStacking: false,
849
+ supportsMultipleSeries: false,
850
+ requiresTimeAxis: false
851
+ },
852
+ choropleth: {
853
+ id: "choropleth",
854
+ name: "Choropleth Map",
855
+ description: "Color-shaded regions by value (Phase 2)",
856
+ intent: "geo",
857
+ phase: "phase2",
858
+ contract: {
859
+ requiredDimensions: 1,
860
+ requiredMeasures: 1,
861
+ minDataPoints: 3,
862
+ idealDataPoints: 20,
863
+ allowNegativeValues: false,
864
+ requireNonZeroTotal: false,
865
+ warningThresholds: {},
866
+ fallback: { type: "hide" }
867
+ },
868
+ switchableTo: ["geo"],
869
+ supportsStacking: false,
870
+ supportsMultipleSeries: false,
871
+ requiresTimeAxis: false
872
+ },
873
+ // ══════════════════════════════════════════════════════════════════════════
874
+ // SPECIAL CHARTS
875
+ // ══════════════════════════════════════════════════════════════════════════
876
+ funnel: {
877
+ id: "funnel",
878
+ name: "Funnel Chart",
879
+ description: "Shows conversion through sequential stages",
880
+ intent: "comparison",
881
+ phase: "mvp",
882
+ contract: {
883
+ requiredDimensions: 1,
884
+ requiredMeasures: 1,
885
+ minDataPoints: 3,
886
+ idealDataPoints: 5,
887
+ maxDataPoints: 7,
888
+ allowNegativeValues: false,
889
+ requireNonZeroTotal: true,
890
+ warningThresholds: { tooManyCategories: 7 },
891
+ fallback: { type: "warn", message: "Funnel requires sequential stages" }
892
+ },
893
+ switchableTo: ["bar"],
894
+ supportsStacking: false,
895
+ supportsMultipleSeries: false,
896
+ requiresTimeAxis: false
897
+ },
898
+ waterfall: {
899
+ id: "waterfall",
900
+ name: "Waterfall Chart",
901
+ description: "Shows cumulative effect of sequential changes (Phase 2)",
902
+ intent: "comparison",
903
+ phase: "phase2",
904
+ contract: {
905
+ requiredDimensions: 1,
906
+ requiredMeasures: 1,
907
+ minDataPoints: 3,
908
+ idealDataPoints: 6,
909
+ maxDataPoints: 12,
910
+ allowNegativeValues: true,
911
+ requireNonZeroTotal: false,
912
+ warningThresholds: { tooManyCategories: 10 },
913
+ fallback: { type: "warn", message: "Waterfall requires sequential data" }
914
+ },
915
+ switchableTo: ["bar", "column"],
916
+ supportsStacking: false,
917
+ supportsMultipleSeries: false,
918
+ requiresTimeAxis: false
919
+ },
920
+ timeline: {
921
+ id: "timeline",
922
+ name: "Timeline",
923
+ description: "Shows events along time axis (Phase 2)",
924
+ intent: "trend",
925
+ phase: "phase2",
926
+ contract: {
927
+ requiredDimensions: 1,
928
+ requiredMeasures: 0,
929
+ minDataPoints: 2,
930
+ idealDataPoints: 10,
931
+ allowNegativeValues: false,
932
+ requireNonZeroTotal: false,
933
+ warningThresholds: {},
934
+ fallback: { type: "hide" }
935
+ },
936
+ switchableTo: ["line"],
937
+ supportsStacking: false,
938
+ supportsMultipleSeries: false,
939
+ requiresTimeAxis: true
940
+ }
941
+ };
942
+ var INTENT_CHART_FAMILIES = {
943
+ trend: ["line", "smooth_line", "area", "stacked_area", "area_100pct"],
944
+ comparison: ["bar", "column", "stacked_bar", "stacked_column", "column_100pct", "funnel"],
945
+ composition: ["pie", "donut"],
946
+ distribution: ["histogram"],
947
+ relationship: ["heatmap"],
948
+ geo: []
949
+ };
950
+ function getAllowedSwitchTargets(currentType) {
951
+ const metadata = CHART_REGISTRY[currentType];
952
+ if (!metadata) return [];
953
+ return metadata.switchableTo.filter((type) => {
954
+ const targetMeta = CHART_REGISTRY[type];
955
+ return targetMeta && targetMeta.phase === "mvp";
956
+ });
957
+ }
958
+ function canSwitchChart(from, to) {
959
+ const fromMeta = CHART_REGISTRY[from];
960
+ const toMeta = CHART_REGISTRY[to];
961
+ if (!fromMeta || !toMeta) return false;
962
+ if (fromMeta.intent !== toMeta.intent) return false;
963
+ return fromMeta.switchableTo.includes(to);
964
+ }
965
+ function validateChartData(chartType, data, dimensions, measures) {
966
+ const metadata = CHART_REGISTRY[chartType];
967
+ if (!metadata) {
968
+ return {
969
+ isValid: false,
970
+ warnings: [],
971
+ errors: [`Unknown chart type: ${chartType}`]
972
+ };
973
+ }
974
+ const contract = metadata.contract;
975
+ const warnings = [];
976
+ const errors = [];
977
+ if (data.length < contract.minDataPoints) {
978
+ errors.push(`Requires at least ${contract.minDataPoints} data points, got ${data.length}`);
979
+ }
980
+ if (contract.maxDataPoints && data.length > contract.maxDataPoints) {
981
+ warnings.push(`Chart works best with \u2264${contract.maxDataPoints} items. Consider aggregating.`);
982
+ }
983
+ if (dimensions.length < contract.requiredDimensions) {
984
+ errors.push(`Requires ${contract.requiredDimensions} dimension(s), got ${dimensions.length}`);
985
+ }
986
+ if (measures.length < contract.requiredMeasures) {
987
+ errors.push(`Requires ${contract.requiredMeasures} measure(s), got ${measures.length}`);
988
+ }
989
+ if (!contract.allowNegativeValues && data.length > 0) {
990
+ const hasNegative = data.some((row) => {
991
+ if (typeof row !== "object" || row === null) return false;
992
+ return measures.some((m) => {
993
+ const val = row[m];
994
+ return typeof val === "number" && val < 0;
995
+ });
996
+ });
997
+ if (hasNegative) {
998
+ errors.push("This chart type does not support negative values");
999
+ }
1000
+ }
1001
+ if (contract.warningThresholds.tooManyCategories && data.length > contract.warningThresholds.tooManyCategories) {
1002
+ warnings.push(`Too many categories (${data.length}). Consider grouping smaller values.`);
1003
+ }
1004
+ return {
1005
+ isValid: errors.length === 0,
1006
+ warnings,
1007
+ errors,
1008
+ fallbackAction: errors.length > 0 ? contract.fallback : void 0
1009
+ };
1010
+ }
1011
+ function getMVPChartsForIntent(intent) {
1012
+ return Object.values(CHART_REGISTRY).filter(
1013
+ (meta) => meta.intent === intent && meta.phase === "mvp"
1014
+ );
1015
+ }
1016
+ function getDefaultChartForIntent(intent) {
1017
+ const defaults = {
1018
+ trend: "line",
1019
+ comparison: "column",
1020
+ composition: "donut",
1021
+ distribution: "histogram",
1022
+ relationship: "heatmap",
1023
+ geo: "geo"
1024
+ };
1025
+ return defaults[intent];
1026
+ }
1027
+ function suggestChartType(params) {
1028
+ const {
1029
+ hasTimeAxis,
1030
+ dimensionCount,
1031
+ measureCount,
1032
+ dataPointCount,
1033
+ hasNegativeValues,
1034
+ isSequential
1035
+ } = params;
1036
+ if (hasTimeAxis && measureCount >= 1) {
1037
+ if (measureCount > 1 && !hasNegativeValues) return "stacked_area";
1038
+ return "line";
1039
+ }
1040
+ if (isSequential && !hasNegativeValues && dataPointCount <= 7) {
1041
+ return "funnel";
1042
+ }
1043
+ if (measureCount === 1 && dataPointCount <= 6 && !hasNegativeValues) {
1044
+ return "donut";
1045
+ }
1046
+ if (dimensionCount === 2 && measureCount === 1) {
1047
+ return "heatmap";
1048
+ }
1049
+ return "column";
1050
+ }
1051
+ function validateReportStructure(children) {
1052
+ const issues = [];
1053
+ const childArray = React2.Children.toArray(children);
1054
+ let hasThesis = false;
1055
+ let thesisIndex = -1;
1056
+ const getComponentName2 = (child) => {
1057
+ if (!React2.isValidElement(child)) return void 0;
1058
+ const type = child.type;
1059
+ return type.displayName || type.name;
1060
+ };
1061
+ const isChart2 = (name) => {
1062
+ return name && (name.endsWith("Chart") || name === "MBTIRadar" || name === "MBTITypeGrid" || name === "KeyMetric");
1063
+ };
1064
+ childArray.forEach((child, index) => {
1065
+ const name = getComponentName2(child);
1066
+ if (name === "ExecutiveThesis") {
1067
+ if (hasThesis) {
1068
+ issues.push({
1069
+ ruleId: "R1",
1070
+ severity: "error",
1071
+ message: "Only one ExecutiveThesis is allowed per report.",
1072
+ component: "ExecutiveThesis"
1073
+ });
1074
+ }
1075
+ hasThesis = true;
1076
+ thesisIndex = index;
1077
+ }
1078
+ if (isChart2(name)) {
1079
+ issues.push({
1080
+ ruleId: "R3",
1081
+ severity: "error",
1082
+ message: `Orphan chart detected: <${name} />. Charts must be placed inside an InsightBlock or EvidenceGroup.`,
1083
+ component: name
1084
+ });
1085
+ }
1086
+ if (name === "InsightBlock" && React2.isValidElement(child)) {
1087
+ validateInsightBlock(child, issues);
1088
+ }
1089
+ });
1090
+ if (!hasThesis) {
1091
+ issues.push({
1092
+ ruleId: "R1",
1093
+ severity: "error",
1094
+ message: "Report must contain an ExecutiveThesis."
1095
+ });
1096
+ } else if (thesisIndex > 2) {
1097
+ issues.push({
1098
+ ruleId: "R1",
1099
+ severity: "warning",
1100
+ message: "ExecutiveThesis should be the first major component in the report."
1101
+ });
1102
+ }
1103
+ return {
1104
+ isValid: issues.filter((i) => i.severity === "error").length === 0,
1105
+ issues
1106
+ };
1107
+ }
1108
+ function validateInsightBlock(node, issues) {
1109
+ const children = node.props.children;
1110
+ const childArray = React2.Children.toArray(children);
1111
+ let chartsInBlock = 0;
1112
+ const countCharts = (nodes) => {
1113
+ nodes.forEach((n) => {
1114
+ const name = getComponentName(n);
1115
+ if (isChart(name)) {
1116
+ chartsInBlock++;
1117
+ }
1118
+ if (name === "EvidenceGroup" && React2.isValidElement(n)) {
1119
+ countCharts(React2.Children.toArray(n.props.children));
1120
+ }
1121
+ });
1122
+ };
1123
+ countCharts(childArray);
1124
+ if (chartsInBlock > 3) {
1125
+ issues.push({
1126
+ ruleId: "R6",
1127
+ severity: "warning",
1128
+ message: `InsightBlock contains ${chartsInBlock} charts. Recommended maximum is 3 to prevent data dumping.`,
1129
+ component: "InsightBlock"
1130
+ });
1131
+ }
1132
+ }
1133
+ var getComponentName = (child) => {
1134
+ if (!React2.isValidElement(child)) return void 0;
1135
+ const type = child.type;
1136
+ return type.displayName || type.name;
1137
+ };
1138
+ var isChart = (name) => {
1139
+ return name && (name.endsWith("Chart") || name === "MBTIRadar" || name === "MBTITypeGrid" || name === "KeyMetric");
1140
+ };
1141
+ var ConfidenceIndicator = React2.forwardRef(
1142
+ ({ score, showScore = true, showLabel = true, size = "md", className, ...props }, ref) => {
1143
+ const threshold = getConfidenceThreshold(score);
1144
+ const normalizedScore = Math.max(0, Math.min(100, score));
1145
+ return /* @__PURE__ */ jsxs(
1146
+ "div",
1147
+ {
1148
+ ref,
1149
+ className: clsx(
1150
+ "ds-confidence-indicator",
1151
+ `ds-confidence-indicator--${size}`,
1152
+ `ds-confidence-indicator--${threshold.level}`,
1153
+ className
1154
+ ),
1155
+ role: "meter",
1156
+ "aria-valuenow": normalizedScore,
1157
+ "aria-valuemin": 0,
1158
+ "aria-valuemax": 100,
1159
+ "aria-label": `Confidence: ${threshold.label} (${normalizedScore}%)`,
1160
+ ...props,
1161
+ children: [
1162
+ /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__bar", children: /* @__PURE__ */ jsx("div", { className: "ds-confidence-indicator__fill", style: { width: `${normalizedScore}%` } }) }),
1163
+ /* @__PURE__ */ jsxs("div", { className: "ds-confidence-indicator__text", children: [
1164
+ showScore && /* @__PURE__ */ jsxs("span", { className: "ds-confidence-indicator__score", children: [
1165
+ normalizedScore,
1166
+ "%"
1167
+ ] }),
1168
+ showLabel && /* @__PURE__ */ jsx("span", { className: "ds-confidence-indicator__label", children: threshold.label })
1169
+ ] })
1170
+ ]
1171
+ }
1172
+ );
1173
+ }
1174
+ );
1175
+ ConfidenceIndicator.displayName = "ConfidenceIndicator";
1176
+ var DataCoverageBadge = React2.forwardRef(
1177
+ ({ sampleSize, requiredSize, dateRange, showDateRange = true, size = "md", className, ...props }, ref) => {
1178
+ const isSufficient = !requiredSize || sampleSize >= requiredSize;
1179
+ const percentage = requiredSize ? Math.min(100, Math.round(sampleSize / requiredSize * 100)) : 100;
1180
+ return /* @__PURE__ */ jsxs(
1181
+ "div",
1182
+ {
1183
+ ref,
1184
+ className: clsx(
1185
+ "ds-data-coverage-badge",
1186
+ `ds-data-coverage-badge--${size}`,
1187
+ !isSufficient && "ds-data-coverage-badge--insufficient",
1188
+ className
1189
+ ),
1190
+ ...props,
1191
+ children: [
1192
+ /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__sample", children: [
1193
+ /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
1194
+ "svg",
1195
+ {
1196
+ width: "14",
1197
+ height: "14",
1198
+ viewBox: "0 0 24 24",
1199
+ fill: "none",
1200
+ stroke: "currentColor",
1201
+ strokeWidth: "2",
1202
+ children: [
1203
+ /* @__PURE__ */ jsx("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
1204
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "7", r: "4" }),
1205
+ /* @__PURE__ */ jsx("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
1206
+ /* @__PURE__ */ jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
1207
+ ]
1208
+ }
1209
+ ) }),
1210
+ /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__count", children: [
1211
+ "n=",
1212
+ sampleSize.toLocaleString()
1213
+ ] }),
1214
+ requiredSize && /* @__PURE__ */ jsxs("span", { className: "ds-data-coverage-badge__required", children: [
1215
+ "(",
1216
+ percentage,
1217
+ "% of min ",
1218
+ requiredSize,
1219
+ ")"
1220
+ ] })
1221
+ ] }),
1222
+ showDateRange && dateRange && /* @__PURE__ */ jsxs("div", { className: "ds-data-coverage-badge__date", children: [
1223
+ /* @__PURE__ */ jsx("span", { className: "ds-data-coverage-badge__icon", children: /* @__PURE__ */ jsxs(
1224
+ "svg",
1225
+ {
1226
+ width: "14",
1227
+ height: "14",
1228
+ viewBox: "0 0 24 24",
1229
+ fill: "none",
1230
+ stroke: "currentColor",
1231
+ strokeWidth: "2",
1232
+ children: [
1233
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
1234
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
1235
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
1236
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
1237
+ ]
1238
+ }
1239
+ ) }),
1240
+ /* @__PURE__ */ jsxs("span", { children: [
1241
+ dateRange.start,
1242
+ " \u2013 ",
1243
+ dateRange.end
1244
+ ] })
1245
+ ] })
1246
+ ]
1247
+ }
1248
+ );
1249
+ }
1250
+ );
1251
+ DataCoverageBadge.displayName = "DataCoverageBadge";
1252
+ var DataStateIndicator = React2.forwardRef(
1253
+ ({ state, details, variant = "compact", onAction, className, ...props }, ref) => {
1254
+ const config = ANALYTICAL_STATE_CONFIG[state];
1255
+ if (state === "VALID" && variant === "compact") {
1256
+ return null;
1257
+ }
1258
+ const renderIcon = () => {
1259
+ switch (config.icon) {
1260
+ case "check":
1261
+ return /* @__PURE__ */ jsx(
1262
+ "svg",
1263
+ {
1264
+ width: "16",
1265
+ height: "16",
1266
+ viewBox: "0 0 24 24",
1267
+ fill: "none",
1268
+ stroke: "currentColor",
1269
+ strokeWidth: "2",
1270
+ children: /* @__PURE__ */ jsx("polyline", { points: "20,6 9,17 4,12" })
1271
+ }
1272
+ );
1273
+ case "alert-triangle":
1274
+ return /* @__PURE__ */ jsxs(
1275
+ "svg",
1276
+ {
1277
+ width: "16",
1278
+ height: "16",
1279
+ viewBox: "0 0 24 24",
1280
+ fill: "none",
1281
+ stroke: "currentColor",
1282
+ strokeWidth: "2",
1283
+ children: [
1284
+ /* @__PURE__ */ jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
1285
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1286
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1287
+ ]
1288
+ }
1289
+ );
1290
+ case "alert-circle":
1291
+ return /* @__PURE__ */ jsxs(
1292
+ "svg",
1293
+ {
1294
+ width: "16",
1295
+ height: "16",
1296
+ viewBox: "0 0 24 24",
1297
+ fill: "none",
1298
+ stroke: "currentColor",
1299
+ strokeWidth: "2",
1300
+ children: [
1301
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1302
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
1303
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
1304
+ ]
1305
+ }
1306
+ );
1307
+ case "x-circle":
1308
+ return /* @__PURE__ */ jsxs(
1309
+ "svg",
1310
+ {
1311
+ width: "16",
1312
+ height: "16",
1313
+ viewBox: "0 0 24 24",
1314
+ fill: "none",
1315
+ stroke: "currentColor",
1316
+ strokeWidth: "2",
1317
+ children: [
1318
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1319
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
1320
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
1321
+ ]
1322
+ }
1323
+ );
1324
+ case "cpu":
1325
+ return /* @__PURE__ */ jsxs(
1326
+ "svg",
1327
+ {
1328
+ width: "16",
1329
+ height: "16",
1330
+ viewBox: "0 0 24 24",
1331
+ fill: "none",
1332
+ stroke: "currentColor",
1333
+ strokeWidth: "2",
1334
+ children: [
1335
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", ry: "2" }),
1336
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "6", height: "6" }),
1337
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "1", x2: "9", y2: "4" }),
1338
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "1", x2: "15", y2: "4" }),
1339
+ /* @__PURE__ */ jsx("line", { x1: "9", y1: "20", x2: "9", y2: "23" }),
1340
+ /* @__PURE__ */ jsx("line", { x1: "15", y1: "20", x2: "15", y2: "23" }),
1341
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "9", x2: "23", y2: "9" }),
1342
+ /* @__PURE__ */ jsx("line", { x1: "20", y1: "14", x2: "23", y2: "14" }),
1343
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "9", x2: "4", y2: "9" }),
1344
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "14", x2: "4", y2: "14" })
1345
+ ]
1346
+ }
1347
+ );
1348
+ default:
1349
+ return /* @__PURE__ */ jsxs(
1350
+ "svg",
1351
+ {
1352
+ width: "16",
1353
+ height: "16",
1354
+ viewBox: "0 0 24 24",
1355
+ fill: "none",
1356
+ stroke: "currentColor",
1357
+ strokeWidth: "2",
1358
+ children: [
1359
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
1360
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
1361
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
1362
+ ]
1363
+ }
1364
+ );
1365
+ }
1366
+ };
1367
+ return /* @__PURE__ */ jsxs(
1368
+ "div",
1369
+ {
1370
+ ref,
1371
+ className: clsx(
1372
+ "ds-data-state-indicator",
1373
+ `ds-data-state-indicator--${variant}`,
1374
+ `ds-data-state-indicator--${state.toLowerCase().replace(/_/g, "-")}`,
1375
+ className
1376
+ ),
1377
+ role: "status",
1378
+ "aria-live": "polite",
1379
+ ...props,
1380
+ children: [
1381
+ /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__icon", style: { color: config.color }, children: renderIcon() }),
1382
+ /* @__PURE__ */ jsxs("div", { className: "ds-data-state-indicator__content", children: [
1383
+ /* @__PURE__ */ jsx("span", { className: "ds-data-state-indicator__label", children: config.label }),
1384
+ variant === "full" && details && /* @__PURE__ */ jsxs("span", { className: "ds-data-state-indicator__details", children: [
1385
+ details.message,
1386
+ details.sampleSize !== void 0 && details.requiredSize !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1387
+ " ",
1388
+ "(n=",
1389
+ details.sampleSize,
1390
+ "/",
1391
+ details.requiredSize,
1392
+ ")"
1393
+ ] }),
1394
+ details.confidence !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1395
+ " \u2022 ",
1396
+ details.confidence,
1397
+ "% confidence"
1398
+ ] }),
1399
+ details.missingFields && details.missingFields.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1400
+ " \u2022 Missing: ",
1401
+ details.missingFields.join(", ")
1402
+ ] })
1403
+ ] })
1404
+ ] }),
1405
+ config.action && onAction && /* @__PURE__ */ jsx("button", { type: "button", className: "ds-data-state-indicator__action", onClick: onAction, children: config.action })
1406
+ ]
1407
+ }
1408
+ );
1409
+ }
1410
+ );
1411
+ DataStateIndicator.displayName = "DataStateIndicator";
1412
+
1413
+ export { ANALYST_MODE, ANALYTICAL_STATE_CONFIG, CHART_REGISTRY, CONFIDENCE_THRESHOLDS, ConfidenceIndicator, DataCoverageBadge, DataStateIndicator, EXECUTIVE_MODE, INSIGHT_TYPE_CONTRACTS, INTENT_CHART_FAMILIES, MINIMUM_SAMPLE_SIZES, ReportModeProvider, calculateCompleteness, calculateConfidence, calculateNormalizedVariance, calculateRecency, canSwitchChart, getAllowedSwitchTargets, getConfidenceLevel, getConfidenceThreshold, getDefaultChartForIntent, getMVPChartsForIntent, suggestChartType, useChartData, useDataState, useReportMode, validateChartData, validateReportStructure };
1414
+ //# sourceMappingURL=out.js.map
1415
+ //# sourceMappingURL=chunk-B6AVAX4F.js.map