@empoweredvote/ev-ui 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4601 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.js
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ AuthForm: () => AuthForm,
33
+ BallotIcon: () => BallotIcon,
34
+ BranchIcon: () => BranchIcon,
35
+ CategorySection: () => CategorySection,
36
+ CommitteeTable: () => CommitteeTable,
37
+ CompassIcon: () => CompassIcon,
38
+ FilterSidebar: () => FilterSidebar,
39
+ GovernmentBodySection: () => GovernmentBodySection,
40
+ Header: () => Header,
41
+ IssueTags: () => IssueTags,
42
+ JudicialRecordDetail: () => JudicialRecordDetail,
43
+ JudicialScorecard: () => JudicialScorecard,
44
+ LegislativeInlineSummary: () => LegislativeInlineSummary,
45
+ LegislativeRecord: () => LegislativeRecord,
46
+ PoliticianCard: () => PoliticianCard,
47
+ PoliticianProfile: () => PoliticianProfile,
48
+ RadarChartCore: () => RadarChartCore,
49
+ SiteHeader: () => SiteHeader,
50
+ SocialLinks: () => SocialLinks,
51
+ StanceAccordion: () => StanceAccordion,
52
+ SubGroupSection: () => SubGroupSection,
53
+ accessibleText: () => accessibleText,
54
+ borderRadius: () => borderRadius,
55
+ breakpoints: () => breakpoints,
56
+ colorScales: () => colorScales,
57
+ colors: () => colors,
58
+ dataVizPalette: () => dataVizPalette,
59
+ defaultCtaButton: () => defaultCtaButton,
60
+ defaultNavItems: () => defaultNavItems,
61
+ duration: () => duration,
62
+ easing: () => easing,
63
+ focus: () => focus,
64
+ fontSizes: () => fontSizes,
65
+ fontWeights: () => fontWeights,
66
+ fonts: () => fonts,
67
+ letterSpacing: () => letterSpacing,
68
+ lineHeights: () => lineHeights,
69
+ opacity: () => opacity,
70
+ pillars: () => pillars,
71
+ semanticTokens: () => semanticTokens,
72
+ shadows: () => shadows,
73
+ spacing: () => spacing,
74
+ textStyles: () => textStyles,
75
+ tierColors: () => tierColors,
76
+ useMediaQuery: () => useMediaQuery,
77
+ zIndex: () => zIndex
78
+ });
79
+ module.exports = __toCommonJS(index_exports);
80
+
81
+ // src/RadarChartCore.jsx
82
+ var import_react = __toESM(require("react"));
83
+ var import_web = require("@react-spring/web");
84
+ var import_react2 = require("react");
85
+ function RadarChartCore({
86
+ topics,
87
+ data,
88
+ compareData = {},
89
+ invertedSpokes = {},
90
+ unansweredSpokes = {},
91
+ onToggleInversion = () => {
92
+ },
93
+ onReplaceTopic = () => {
94
+ },
95
+ size = 400,
96
+ labelFontSize = 18,
97
+ padding = 80,
98
+ labelOffset = 20
99
+ }) {
100
+ const radius = size / 2 - 40;
101
+ const centerX = size / 2;
102
+ const centerY = size / 2;
103
+ const spokes = Object.entries(data);
104
+ const numSpokes = Math.max(spokes.length, 1);
105
+ const prevCountRef = (0, import_react2.useRef)(numSpokes);
106
+ const countChanged = numSpokes !== prevCountRef.current;
107
+ (0, import_react2.useEffect)(() => {
108
+ prevCountRef.current = numSpokes;
109
+ }, [numSpokes]);
110
+ const pointsArr = spokes.map(([shortTitle, value], index) => {
111
+ var _a;
112
+ const topic = topics.find((t) => t.short_title === shortTitle);
113
+ const max = ((_a = topic == null ? void 0 : topic.stances) == null ? void 0 : _a.length) || 10;
114
+ const pct = Math.min(value / max * 10, 10);
115
+ const angle = 2 * Math.PI * index / numSpokes;
116
+ const adjusted = value === 0 ? 0 : invertedSpokes[shortTitle] ? 11 - pct : pct;
117
+ const r = adjusted / 10 * radius;
118
+ const x = centerX + r * Math.sin(angle);
119
+ const y = centerY - r * Math.cos(angle);
120
+ return [x, y];
121
+ });
122
+ const targetPoints = pointsArr.map((p) => p.join(",")).join(" ");
123
+ const spring = (0, import_web.useSpring)({
124
+ to: { points: targetPoints },
125
+ immediate: countChanged,
126
+ reset: countChanged,
127
+ config: { tension: 300, friction: 30 }
128
+ });
129
+ const hasCompareData = Object.keys(compareData).length > 0;
130
+ const centerPoints = spokes.map(() => `${centerX},${centerY}`).join(" ");
131
+ let comparePoints = null;
132
+ if (hasCompareData) {
133
+ const cpts = spokes.map(([shortTitle], index) => {
134
+ var _a, _b;
135
+ const value = (_a = compareData[shortTitle]) != null ? _a : 0;
136
+ const topic = topics.find((t) => t.short_title === shortTitle);
137
+ const max = ((_b = topic == null ? void 0 : topic.stances) == null ? void 0 : _b.length) || 10;
138
+ const pct = Math.min(value / max * 10, 10);
139
+ const angle = 2 * Math.PI * index / numSpokes;
140
+ const adjusted = value === 0 ? 0 : invertedSpokes[shortTitle] ? 11 - pct : pct;
141
+ const r = adjusted / 10 * radius;
142
+ const x = centerX + r * Math.sin(angle);
143
+ const y = centerY - r * Math.cos(angle);
144
+ return `${x},${y}`;
145
+ });
146
+ comparePoints = cpts.join(" ");
147
+ }
148
+ const hadCompareDataRef = (0, import_react2.useRef)(false);
149
+ const compareJustAppeared = hasCompareData && !hadCompareDataRef.current;
150
+ (0, import_react2.useEffect)(() => {
151
+ hadCompareDataRef.current = hasCompareData;
152
+ }, [hasCompareData]);
153
+ const compareSpring = (0, import_web.useSpring)({
154
+ to: { points: comparePoints || centerPoints || `${centerX},${centerY}` },
155
+ immediate: countChanged || compareJustAppeared,
156
+ reset: countChanged || compareJustAppeared,
157
+ config: { tension: 300, friction: 30 }
158
+ });
159
+ const labelMeta = spokes.map(([shortTitle], i) => {
160
+ const angle = 2 * Math.PI * i / numSpokes;
161
+ const baseFSize = labelFontSize;
162
+ const lines = wrapLabel(shortTitle, 12);
163
+ const longestLineLen = lines.reduce(
164
+ (max, ln) => ln.length > max ? ln.length : max,
165
+ 0
166
+ );
167
+ const fSize = adaptiveFontSize(longestLineLen, baseFSize);
168
+ const estimatedWidth = longestLineLen * fSize * 0.6;
169
+ const sinA = Math.sin(angle);
170
+ const side = sinA < -0.1 ? "left" : sinA > 0.1 ? "right" : "center";
171
+ return { estimatedWidth, side };
172
+ });
173
+ const leftLabelWidths = labelMeta.filter((m) => m.side === "left").map((m) => m.estimatedWidth);
174
+ const rightLabelWidths = labelMeta.filter((m) => m.side === "right").map((m) => m.estimatedWidth);
175
+ const minPadding = 40;
176
+ const maxPadding = padding * 2;
177
+ const rawLeftPadding = Math.min(
178
+ Math.max(
179
+ leftLabelWidths.length ? Math.max(...leftLabelWidths) + labelOffset : 0,
180
+ minPadding
181
+ ),
182
+ maxPadding
183
+ );
184
+ const rawRightPadding = Math.min(
185
+ Math.max(
186
+ rightLabelWidths.length ? Math.max(...rightLabelWidths) + labelOffset : 0,
187
+ minPadding
188
+ ),
189
+ maxPadding
190
+ );
191
+ const symmetricPadding = Math.max(rawLeftPadding, rawRightPadding);
192
+ const leftPadding = symmetricPadding;
193
+ const rightPadding = symmetricPadding;
194
+ const verticalPadding = padding;
195
+ const guidePolygons = [];
196
+ for (let level = 1; level <= 5; level++) {
197
+ const scale = level / 5;
198
+ const ring = [];
199
+ for (let i = 0; i < numSpokes; i++) {
200
+ const angle = 2 * Math.PI * i / numSpokes;
201
+ const x = centerX + radius * scale * Math.sin(angle);
202
+ const y = centerY - radius * scale * Math.cos(angle);
203
+ ring.push(`${x},${y}`);
204
+ }
205
+ guidePolygons.push(
206
+ /* @__PURE__ */ import_react.default.createElement("polygon", { key: level, points: ring.join(" "), fill: "none", stroke: "#ccc" })
207
+ );
208
+ }
209
+ return /* @__PURE__ */ import_react.default.createElement(
210
+ "svg",
211
+ {
212
+ className: "w-full h-auto max-h-full",
213
+ viewBox: `-${leftPadding} -${verticalPadding} ${size + leftPadding + rightPadding} ${size + verticalPadding * 2}`,
214
+ preserveAspectRatio: "xMidYMid meet"
215
+ },
216
+ guidePolygons,
217
+ spokes.map(([shortTitle], i) => {
218
+ const angle = 2 * Math.PI * i / numSpokes;
219
+ const x = centerX + radius * Math.sin(angle);
220
+ const y = centerY - radius * Math.cos(angle);
221
+ const isUnanswered = !!unansweredSpokes[shortTitle];
222
+ return /* @__PURE__ */ import_react.default.createElement(
223
+ "line",
224
+ {
225
+ key: `line-${shortTitle}`,
226
+ x1: centerX,
227
+ y1: centerY,
228
+ x2: x,
229
+ y2: y,
230
+ stroke: isUnanswered ? "#9ca3af" : "black",
231
+ strokeDasharray: isUnanswered ? "4 3" : void 0,
232
+ opacity: isUnanswered ? 0.6 : 1
233
+ }
234
+ );
235
+ }),
236
+ spokes.map(([shortTitle], i) => {
237
+ const angle = 2 * Math.PI * i / numSpokes;
238
+ const anchor = angle > Math.PI ? "end" : angle < Math.PI && angle > 0 ? "start" : "middle";
239
+ const cosA = Math.cos(angle);
240
+ const isTop = cosA > 0.5;
241
+ const isBottom = cosA < -0.5;
242
+ const baseFSize = labelFontSize;
243
+ const lines = wrapLabel(shortTitle, 12);
244
+ const longestLine = lines.reduce(
245
+ (max, ln) => ln.length > max ? ln.length : max,
246
+ 0
247
+ );
248
+ const fSize = adaptiveFontSize(longestLine, baseFSize);
249
+ const lineHeight = fSize * 1.1;
250
+ const dynamicLabelOffset = lines.length > 1 ? labelOffset + 8 : labelOffset;
251
+ const offset = radius + dynamicLabelOffset;
252
+ const labelX = centerX + offset * Math.sin(angle);
253
+ let labelY = centerY - offset * Math.cos(angle);
254
+ if (isTop && lines.length > 1) {
255
+ labelY -= (lines.length - 1) * lineHeight;
256
+ }
257
+ const isUnansweredLabel = !!unansweredSpokes[shortTitle];
258
+ return /* @__PURE__ */ import_react.default.createElement(
259
+ "text",
260
+ {
261
+ key: `label-${shortTitle}`,
262
+ x: labelX,
263
+ y: labelY,
264
+ textAnchor: anchor,
265
+ dominantBaseline: isBottom ? "hanging" : "auto",
266
+ onClick: () => onReplaceTopic(shortTitle),
267
+ className: "text-xl font-medium mb-1 md:text-base md:font-normal",
268
+ fill: isUnansweredLabel ? "#9ca3af" : void 0,
269
+ style: { cursor: "pointer", userSelect: "none", fontSize: fSize }
270
+ },
271
+ lines.map((ln, idx) => /* @__PURE__ */ import_react.default.createElement("tspan", { key: idx, x: labelX, dy: idx === 0 ? "0" : `${lineHeight}` }, ln))
272
+ );
273
+ }),
274
+ countChanged ? /* @__PURE__ */ import_react.default.createElement(
275
+ "polygon",
276
+ {
277
+ key: "user-static",
278
+ points: targetPoints,
279
+ style: {
280
+ fill: "rgba(255, 87, 64, 0.4)",
281
+ stroke: "rgb(255, 87, 64)",
282
+ strokeWidth: 3
283
+ }
284
+ }
285
+ ) : /* @__PURE__ */ import_react.default.createElement(
286
+ import_web.animated.polygon,
287
+ {
288
+ key: "user-animated",
289
+ points: spring.points,
290
+ style: {
291
+ fill: "rgba(255, 87, 64, 0.4)",
292
+ stroke: "rgb(255, 87, 64)",
293
+ strokeWidth: 3
294
+ }
295
+ }
296
+ ),
297
+ hasCompareData && comparePoints ? countChanged || compareJustAppeared ? /* @__PURE__ */ import_react.default.createElement(
298
+ "polygon",
299
+ {
300
+ key: "compare-static",
301
+ points: comparePoints,
302
+ style: {
303
+ fill: "rgba(89, 176, 196, 0.3)",
304
+ stroke: "rgb(89, 176, 196)",
305
+ strokeWidth: 2
306
+ }
307
+ }
308
+ ) : /* @__PURE__ */ import_react.default.createElement(
309
+ import_web.animated.polygon,
310
+ {
311
+ key: "compare-animated",
312
+ points: compareSpring.points,
313
+ style: {
314
+ fill: "rgba(89, 176, 196, 0.3)",
315
+ stroke: "rgb(89, 176, 196)",
316
+ strokeWidth: 2
317
+ }
318
+ }
319
+ ) : null,
320
+ spokes.map(([shortTitle], i) => {
321
+ const angle = 2 * Math.PI * i / numSpokes;
322
+ const x = centerX + radius * Math.sin(angle);
323
+ const y = centerY - radius * Math.cos(angle);
324
+ const isUnansweredHitbox = !!unansweredSpokes[shortTitle];
325
+ return /* @__PURE__ */ import_react.default.createElement(
326
+ "line",
327
+ {
328
+ key: `hitbox-${shortTitle}`,
329
+ x1: centerX,
330
+ y1: centerY,
331
+ x2: x,
332
+ y2: y,
333
+ stroke: "transparent",
334
+ strokeWidth: 14,
335
+ onClick: () => isUnansweredHitbox ? onReplaceTopic(shortTitle) : onToggleInversion(shortTitle),
336
+ style: { cursor: "pointer" }
337
+ }
338
+ );
339
+ })
340
+ );
341
+ }
342
+ function adaptiveFontSize(longestLineLen, baseFSize) {
343
+ return Math.max(baseFSize, 10);
344
+ }
345
+ function wrapLabel(label, maxChars = 12) {
346
+ const str = String(label);
347
+ let rawWords;
348
+ if (str.includes("/")) {
349
+ rawWords = str.split("/").reduce((acc, segment, idx, arr) => {
350
+ const part = idx < arr.length - 1 ? segment + "/" : segment;
351
+ if (part.trim()) acc.push(part.trim());
352
+ return acc;
353
+ }, []);
354
+ } else {
355
+ rawWords = str.split(/\s+/);
356
+ }
357
+ const lines = [];
358
+ let line = "";
359
+ for (const word of rawWords) {
360
+ if (line === "") {
361
+ line = word;
362
+ } else if ((line + " " + word).length <= maxChars) {
363
+ line += " " + word;
364
+ } else {
365
+ lines.push(line);
366
+ line = word;
367
+ }
368
+ }
369
+ if (line) lines.push(line);
370
+ if (lines.length > 2) {
371
+ const overflow = lines.splice(2).join(" ");
372
+ lines[1] = lines[1] + " " + overflow;
373
+ }
374
+ return lines;
375
+ }
376
+
377
+ // src/Header.jsx
378
+ var import_react4 = __toESM(require("react"));
379
+
380
+ // src/tokens.js
381
+ var colorScales = {
382
+ coral: {
383
+ "050": "#FAF6F5",
384
+ "100": "#F6E6E4",
385
+ "200": "#F2C6C0",
386
+ "300": "#F2988C",
387
+ "400": "#F66855",
388
+ "500": "#FF5740",
389
+ "600": "#FF2B0F",
390
+ "700": "#E61B00",
391
+ "800": "#B31D09",
392
+ "900": "#8E1F10",
393
+ "950": "#6C1E13"
394
+ },
395
+ teal: {
396
+ // Smoothed scale — original 400→500 had a ~45 lightness jump.
397
+ // 400 now bridges the light wash into the deep brand muted-blue.
398
+ "050": "#F5F9FA",
399
+ "100": "#E4F3F6",
400
+ "200": "#C0E8F2",
401
+ "300": "#7DD4E8",
402
+ "400": "#3AABB8",
403
+ "500": "#00657C",
404
+ "600": "#005366",
405
+ "700": "#003E4D",
406
+ "800": "#03303A",
407
+ "900": "#05262E",
408
+ "950": "#051A1E"
409
+ },
410
+ skyblue: {
411
+ "050": "#F6F8F8",
412
+ "100": "#E9F0F1",
413
+ "200": "#CDE0E5",
414
+ "300": "#A7CFD8",
415
+ "400": "#7FBECC",
416
+ "500": "#59B0C4",
417
+ "600": "#3A9BB0",
418
+ "700": "#327E8F",
419
+ "800": "#2B616E",
420
+ "900": "#264C55",
421
+ "950": "#1E383D"
422
+ },
423
+ yellow: {
424
+ "050": "#FAF9F5",
425
+ "100": "#F6F2E4",
426
+ "200": "#F1E7C0",
427
+ "300": "#F2DC8D",
428
+ "400": "#F5D356",
429
+ "500": "#FED12E",
430
+ "600": "#FAC400",
431
+ "700": "#D0A301",
432
+ "800": "#9F7F09",
433
+ "900": "#7B640E",
434
+ "950": "#5B4B10"
435
+ },
436
+ gray: {
437
+ "050": "#F7F7F8",
438
+ "100": "#EBEDEF",
439
+ "200": "#D3D7DE",
440
+ "300": "#B3BBCC",
441
+ "400": "#8F9EBC",
442
+ "500": "#6B7280",
443
+ "600": "#535964",
444
+ "700": "#41454E",
445
+ "800": "#2F3237",
446
+ "900": "#212326",
447
+ "950": "#131416"
448
+ }
449
+ };
450
+ var tierColors = {
451
+ federal: {
452
+ bg: "#FFFFFF",
453
+ // white — lightest tier
454
+ accent: colorScales.teal["700"],
455
+ // #003E4D
456
+ text: colorScales.teal["700"]
457
+ // #003E4D — 7.5:1 on white, AA
458
+ },
459
+ state: {
460
+ bg: "#F7FBFC",
461
+ // gentle teal wash — midpoint between white and 050
462
+ accent: colorScales.teal["500"],
463
+ // #00657C
464
+ text: colorScales.teal["500"]
465
+ // #00657C — 6.66:1 on white, AA
466
+ },
467
+ local: {
468
+ bg: "#EDF6F8",
469
+ // #EDF6F8 — between 050 and 100, darkest tier
470
+ accent: colorScales.teal["200"],
471
+ // #C0E8F2 — decorative only
472
+ text: colorScales.teal["600"]
473
+ // #005366 — 8.1:1 on white, AA
474
+ }
475
+ };
476
+ var colors = {
477
+ // Primary brand (locked)
478
+ evCoral: "#FF5740",
479
+ // 3.14:1 on white — large text / UI only
480
+ evMutedBlue: "#00657C",
481
+ // 6.66:1 on white — AA body text safe
482
+ evLightBlue: "#59B0C4",
483
+ // 2.49:1 on white — decorative / dark bg only
484
+ evYellow: "#FED12E",
485
+ // 1.46:1 on white — accent / dark bg only
486
+ evYellowLight: "#FEF3C7",
487
+ evYellowDark: "#D0A301",
488
+ black: "#1C1C1C",
489
+ white: "#FFFFFF",
490
+ // Legacy aliases (deprecated — use evMutedBlue / evLightBlue instead)
491
+ evTeal: "#00657C",
492
+ evTealDark: "#003E4D",
493
+ evTealLight: "#59B0C4",
494
+ // Backgrounds
495
+ bgLight: "#F0F8FA",
496
+ bgWhite: "#FFFFFF",
497
+ // Text
498
+ textPrimary: "#00657C",
499
+ // Muted Blue — 6.66:1 on white ✓ AA
500
+ textSecondary: "#4A5568",
501
+ // ~6.0:1 on white ✓ AA
502
+ textMuted: "#718096",
503
+ // ~4.6:1 on white ✓ AA
504
+ textWhite: "#FFFFFF",
505
+ // Borders
506
+ borderLight: "#E2EBEF",
507
+ borderMedium: "#C9CFD1",
508
+ // State
509
+ error: "#EF4444",
510
+ errorLight: "#FEF2F2",
511
+ success: "#22C55E",
512
+ successLight: "#F0FDF4",
513
+ warning: "#F59E0B",
514
+ warningLight: "#FFFBEB",
515
+ info: "#3A9BB0",
516
+ infoLight: "#F5F9FA"
517
+ };
518
+ var accessibleText = {
519
+ coral: "#E61B00",
520
+ // coral-700, 4.64:1 on white
521
+ teal: "#00657C",
522
+ // teal-500 (brand muted blue), 6.66:1
523
+ skyblue: "#327E8F",
524
+ // skyblue-700, 4.65:1 on white
525
+ yellow: "#7B640E"
526
+ // yellow-900, 5.72:1 on white
527
+ };
528
+ var pillars = {
529
+ inform: {
530
+ name: "Inform",
531
+ accent: "yellow",
532
+ color: "#FED12E",
533
+ dark: "#D0A301",
534
+ light: "#FAF9F5",
535
+ textColor: "#7B640E",
536
+ // AA-safe text — yellow-900
537
+ darkMode: { color: "#FED12E", dark: "#FEE88A", textOnAccent: "#1C1C1C" }
538
+ },
539
+ empower: {
540
+ name: "Empower",
541
+ accent: "coral",
542
+ color: "#FF5740",
543
+ dark: "#E61B00",
544
+ light: "#FAF6F5",
545
+ textColor: "#E61B00",
546
+ // AA-safe text — coral-700
547
+ darkMode: { color: "#FF5740", dark: "#F66855", textOnAccent: "#FFFFFF" }
548
+ },
549
+ connect: {
550
+ name: "Connect",
551
+ accent: "teal",
552
+ color: "#00657C",
553
+ dark: "#003E4D",
554
+ light: "#F5F9FA",
555
+ textColor: "#00657C",
556
+ // Already AA — muted blue
557
+ darkMode: { color: "#3A9BB0", dark: "#59B0C4", textOnAccent: "#FFFFFF" }
558
+ }
559
+ };
560
+ var semanticTokens = {
561
+ light: {
562
+ layerBase: { background: "#F7F7F8", text: "#535964", icon: "#535964", border: "#D3D7DE" },
563
+ // 6.58:1
564
+ layerOne: { background: "#EBEDEF", text: "#41454E", icon: "#41454E", border: "#D3D7DE" },
565
+ // 7.23:1
566
+ layerTwo: { background: "#D3D7DE", text: "#2F3237", icon: "#2F3237", border: "#B3BBCC" },
567
+ // 7.60:1
568
+ heading: { text: "#2F3237" },
569
+ // 12.02:1 on gray-050
570
+ divider: "#D3D7DE",
571
+ link: { default: "#00657C", hovered: "#003E4D", focused: "#003E4D", pressed: "#003E4D" },
572
+ input: { background: "#F7F7F8", text: "#41454E", border: "#41454E", icon: "#6B7280" },
573
+ // text bumped from gray-500 to gray-700 for AA
574
+ buttonPrimary: {
575
+ background: { default: "#005366", hovered: "#003E4D", pressed: "#03303A", focused: "#005366", disabled: "#D3D7DE" },
576
+ text: { default: "#FFFFFF", disabled: "#8F9EBC" }
577
+ },
578
+ buttonSecondary: {
579
+ background: { default: "#F7F7F8", hovered: "#EBEDEF", pressed: "#D3D7DE", focused: "#EBEDEF", disabled: "#F7F7F8" },
580
+ text: { default: "#003E4D", disabled: "#8F9EBC" },
581
+ border: { default: "#003E4D", disabled: "#D3D7DE" }
582
+ },
583
+ // Feedback states
584
+ badge: { background: "#EBEDEF", text: "#41454E", border: "#D3D7DE" },
585
+ tooltip: { background: "#2F3237", text: "#EBEDEF" },
586
+ overlay: "rgba(19, 20, 22, 0.5)",
587
+ skeleton: { from: "#EBEDEF", to: "#D3D7DE" }
588
+ },
589
+ dark: {
590
+ layerBase: { background: "#131416", text: "#B3BBCC", icon: "#B3BBCC", border: "#41454E" },
591
+ // 9.56:1 ✓ AAA
592
+ layerOne: { background: "#2F3237", text: "#D3D7DE", icon: "#D3D7DE", border: "#41454E" },
593
+ // 8.91:1 ✓ AAA
594
+ layerTwo: { background: "#41454E", text: "#EBEDEF", icon: "#EBEDEF", border: "#535964" },
595
+ // 8.18:1 ✓ AAA
596
+ heading: { text: "#EBEDEF" },
597
+ // 15.70:1 on layerBase ✓ AAA
598
+ divider: "#41454E",
599
+ link: { default: "#59B0C4", hovered: "#7FBECC", focused: "#7FBECC", pressed: "#3A9BB0" },
600
+ // 7.40:1 on layerBase ✓ AAA
601
+ input: { background: "#1E2024", text: "#D3D7DE", border: "#6B7280", icon: "#B3BBCC" },
602
+ // border bumped to gray-500 for 3.37:1 UI ✓
603
+ buttonPrimary: {
604
+ // Darkened from skyblue to teal for white-text AA compliance
605
+ background: { default: "#005366", hovered: "#327E8F", pressed: "#003E4D", focused: "#005366", disabled: "#2F3237" },
606
+ text: { default: "#FFFFFF", disabled: "#535964" }
607
+ // 8.64:1 / 4.65:1 / 11.69:1 ✓ AA+
608
+ },
609
+ buttonSecondary: {
610
+ background: { default: "#131416", hovered: "#2F3237", pressed: "#41454E", focused: "#2F3237", disabled: "#131416" },
611
+ text: { default: "#59B0C4", disabled: "#535964" },
612
+ // 7.40:1 ✓ AAA
613
+ border: { default: "#59B0C4", disabled: "#41454E" }
614
+ },
615
+ // Feedback states
616
+ badge: { background: "#41454E", text: "#EBEDEF", border: "#535964" },
617
+ tooltip: { background: "#EBEDEF", text: "#2F3237" },
618
+ overlay: "rgba(19, 20, 22, 0.75)",
619
+ skeleton: { from: "#2F3237", to: "#41454E" }
620
+ }
621
+ };
622
+ var dataVizPalette = [
623
+ { name: "Teal", base: "#00657C", shades: ["#C0E8F2", "#55D9F6", "#3AABB8", "#00657C", "#003E4D"] },
624
+ { name: "Sky Blue", base: "#59B0C4", shades: ["#CDE0E5", "#A7CFD8", "#7FBECC", "#59B0C4", "#327E8F"] },
625
+ { name: "Ocean", base: "#2563A0", shades: ["#CDDCED", "#7BADD4", "#4D8FC2", "#2563A0", "#193F68"] },
626
+ { name: "Coral", base: "#FF5740", shades: ["#F6E6E4", "#F2988C", "#F66855", "#FF5740", "#B31D09"] },
627
+ { name: "Terracotta", base: "#C2674A", shades: ["#F0DCD4", "#D9A48E", "#CF8568", "#C2674A", "#7A3D2C"] },
628
+ { name: "Yellow", base: "#FED12E", shades: ["#F6F2E4", "#F2DC8D", "#F5D356", "#FED12E", "#9F7F09"] },
629
+ { name: "Honey", base: "#D4940B", shades: ["#F5EACE", "#E8C563", "#DCA930", "#D4940B", "#805A06"] },
630
+ { name: "Sage", base: "#5A9A6E", shades: ["#D4E8DA", "#9ACBAA", "#74B589", "#5A9A6E", "#376043"] },
631
+ { name: "Dusk", base: "#7C6B9E", shades: ["#E4DFF0", "#B5A8CF", "#9788B8", "#7C6B9E", "#4D4263"] },
632
+ { name: "Stone", base: "#6B7280", shades: ["#EBEDEF", "#B3BBCC", "#8F9EBC", "#6B7280", "#41454E"] }
633
+ ];
634
+ var fonts = {
635
+ primary: "'Manrope', sans-serif",
636
+ fallback: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
637
+ };
638
+ var fontWeights = {
639
+ regular: 400,
640
+ medium: 500,
641
+ semibold: 600,
642
+ bold: 700,
643
+ extrabold: 800
644
+ };
645
+ var fontSizes = {
646
+ xs: "12px",
647
+ sm: "14px",
648
+ base: "16px",
649
+ lg: "18px",
650
+ xl: "20px",
651
+ "2xl": "24px",
652
+ "3xl": "30px",
653
+ "4xl": "36px",
654
+ "5xl": "48px"
655
+ };
656
+ var lineHeights = {
657
+ tight: 1.25,
658
+ normal: 1.5,
659
+ relaxed: 1.75
660
+ };
661
+ var letterSpacing = {
662
+ tight: "-0.02em",
663
+ normal: "0",
664
+ wide: "0.05em"
665
+ };
666
+ var textStyles = {
667
+ displayTitle: { fontSize: "48px", fontWeight: 800, lineHeight: 1.1, letterSpacing: "-0.03em" },
668
+ displaySub: { fontSize: "36px", fontWeight: 700, lineHeight: 1.15, letterSpacing: "-0.02em" },
669
+ h1: { fontSize: "30px", fontWeight: 700, lineHeight: 1.25, letterSpacing: "-0.02em" },
670
+ h2: { fontSize: "24px", fontWeight: 700, lineHeight: 1.3, letterSpacing: "-0.01em" },
671
+ h3: { fontSize: "20px", fontWeight: 600, lineHeight: 1.35, letterSpacing: "0" },
672
+ h4: { fontSize: "18px", fontWeight: 600, lineHeight: 1.4, letterSpacing: "0" },
673
+ bodyLg: { fontSize: "18px", fontWeight: 400, lineHeight: 1.6, letterSpacing: "0" },
674
+ body: { fontSize: "16px", fontWeight: 400, lineHeight: 1.5, letterSpacing: "0" },
675
+ bodySm: { fontSize: "14px", fontWeight: 400, lineHeight: 1.5, letterSpacing: "0" },
676
+ label: { fontSize: "14px", fontWeight: 500, lineHeight: 1.4, letterSpacing: "0.01em" },
677
+ labelSm: { fontSize: "12px", fontWeight: 500, lineHeight: 1.4, letterSpacing: "0.02em" },
678
+ caption: { fontSize: "12px", fontWeight: 400, lineHeight: 1.4, letterSpacing: "0.01em" },
679
+ overline: { fontSize: "11px", fontWeight: 700, lineHeight: 1.4, letterSpacing: "0.08em", textTransform: "uppercase" }
680
+ };
681
+ var spacing = {
682
+ 0: "0",
683
+ "050": "2px",
684
+ 1: "4px",
685
+ "150": "6px",
686
+ 2: "8px",
687
+ 3: "12px",
688
+ 4: "16px",
689
+ 5: "20px",
690
+ 6: "24px",
691
+ 8: "32px",
692
+ 10: "40px",
693
+ 12: "48px",
694
+ 16: "64px",
695
+ 20: "80px",
696
+ 24: "96px"
697
+ };
698
+ var borderRadius = {
699
+ none: "0",
700
+ sm: "4px",
701
+ md: "8px",
702
+ lg: "10px",
703
+ xl: "12px",
704
+ "2xl": "16px",
705
+ full: "9999px"
706
+ };
707
+ var shadows = {
708
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
709
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
710
+ lg: "0 10px 25px -3px rgba(0, 0, 0, 0.1), 0 4px 10px -4px rgba(0, 0, 0, 0.05)",
711
+ xl: "0 20px 40px -8px rgba(0, 0, 0, 0.12), 0 8px 16px -6px rgba(0, 0, 0, 0.06)",
712
+ inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)",
713
+ glowCoral: "0 0 0 3px rgba(255, 87, 64, 0.25)",
714
+ glowTeal: "0 0 0 3px rgba(0, 101, 124, 0.2)",
715
+ cardHover: "0 12px 32px -4px rgba(0, 0, 0, 0.12), 0 4px 8px -2px rgba(0, 0, 0, 0.04)",
716
+ none: "none"
717
+ };
718
+ var duration = {
719
+ instant: "50ms",
720
+ fast: "120ms",
721
+ // Micro-interactions: toggles, checkboxes
722
+ normal: "200ms",
723
+ // Buttons, inputs, small transitions
724
+ slow: "350ms",
725
+ // Panels, cards, modals
726
+ slower: "500ms"
727
+ // Page transitions, complex orchestration
728
+ };
729
+ var easing = {
730
+ default: "cubic-bezier(0.2, 0, 0, 1)",
731
+ // General-purpose (Material 3 standard)
732
+ enter: "cubic-bezier(0, 0, 0.2, 1)",
733
+ // Elements appearing (decelerate)
734
+ exit: "cubic-bezier(0.4, 0, 1, 1)",
735
+ // Elements leaving (accelerate)
736
+ spring: "cubic-bezier(0.34, 1.56, 0.64, 1)",
737
+ // Playful overshoot — buttons, badges
738
+ linear: "linear"
739
+ };
740
+ var focus = {
741
+ ring: "0 0 0 2px #FFFFFF, 0 0 0 4px #00657C",
742
+ // White gap + brand muted blue (6.66:1 on white)
743
+ ringDark: "0 0 0 2px #131416, 0 0 0 4px #59B0C4",
744
+ // Dark gap + light blue (6.84:1 on dark)
745
+ ringCoral: "0 0 0 2px #FFFFFF, 0 0 0 4px #FF5740",
746
+ // Coral variant for pillar contexts
747
+ offset: "2px"
748
+ };
749
+ var zIndex = {
750
+ hide: -1,
751
+ base: 0,
752
+ dropdown: 10,
753
+ sticky: 20,
754
+ header: 30,
755
+ overlay: 40,
756
+ modal: 50,
757
+ toast: 60,
758
+ tooltip: 70
759
+ };
760
+ var opacity = {
761
+ disabled: 0.4,
762
+ muted: 0.6,
763
+ subtle: 0.8,
764
+ full: 1
765
+ };
766
+ var breakpoints = {
767
+ sm: "640px",
768
+ md: "768px",
769
+ lg: "1024px",
770
+ xl: "1280px"
771
+ };
772
+
773
+ // src/useMediaQuery.js
774
+ var import_react3 = require("react");
775
+ function useMediaQuery(query) {
776
+ const [matches, setMatches] = (0, import_react3.useState)(() => {
777
+ if (typeof window === "undefined") return false;
778
+ return window.matchMedia(query).matches;
779
+ });
780
+ (0, import_react3.useEffect)(() => {
781
+ if (typeof window === "undefined") return;
782
+ const mql = window.matchMedia(query);
783
+ const handler = (e) => setMatches(e.matches);
784
+ mql.addEventListener("change", handler);
785
+ setMatches(mql.matches);
786
+ return () => mql.removeEventListener("change", handler);
787
+ }, [query]);
788
+ return matches;
789
+ }
790
+
791
+ // src/Header.jsx
792
+ function Header({
793
+ logoSrc,
794
+ logoAlt = "Empowered Vote",
795
+ navItems = [],
796
+ ctaButton,
797
+ currentPath,
798
+ onNavigate,
799
+ profileMenu,
800
+ style = {}
801
+ }) {
802
+ const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react4.useState)(false);
803
+ const [openDropdown, setOpenDropdown] = (0, import_react4.useState)(null);
804
+ const [profileOpen, setProfileOpen] = (0, import_react4.useState)(false);
805
+ const isMobile = useMediaQuery("(max-width: 768px)");
806
+ const profileRef = (0, import_react4.useRef)(null);
807
+ (0, import_react4.useEffect)(() => {
808
+ if (!profileOpen) return;
809
+ const handleClickOutside = (e) => {
810
+ if (profileRef.current && !profileRef.current.contains(e.target)) {
811
+ setProfileOpen(false);
812
+ }
813
+ };
814
+ document.addEventListener("mousedown", handleClickOutside);
815
+ return () => document.removeEventListener("mousedown", handleClickOutside);
816
+ }, [profileOpen]);
817
+ const handleNavClick = (e, href) => {
818
+ if (onNavigate) {
819
+ e.preventDefault();
820
+ onNavigate(href);
821
+ }
822
+ };
823
+ const styles2 = {
824
+ header: {
825
+ backgroundColor: colors.bgWhite,
826
+ position: "sticky",
827
+ top: 0,
828
+ zIndex: 50,
829
+ width: "100%",
830
+ ...style
831
+ },
832
+ container: {
833
+ maxWidth: "1512px",
834
+ margin: "0 auto",
835
+ padding: isMobile ? `${spacing[3]} ${spacing[3]}` : `${spacing[4]} ${spacing[6]}`,
836
+ display: "flex",
837
+ alignItems: "center",
838
+ justifyContent: "space-between"
839
+ },
840
+ logo: {
841
+ height: "43px",
842
+ cursor: "pointer"
843
+ },
844
+ nav: {
845
+ display: isMobile ? "none" : "flex",
846
+ alignItems: "center",
847
+ gap: spacing[10]
848
+ },
849
+ navItem: {
850
+ fontFamily: fonts.primary,
851
+ fontWeight: fontWeights.bold,
852
+ fontSize: fontSizes.xl,
853
+ color: colors.evTeal,
854
+ textDecoration: "none",
855
+ cursor: "pointer",
856
+ display: "flex",
857
+ alignItems: "center",
858
+ gap: spacing[2],
859
+ position: "relative"
860
+ },
861
+ navItemActive: {
862
+ textDecoration: "underline"
863
+ },
864
+ dropdownIcon: {
865
+ width: "16px",
866
+ height: "9px"
867
+ },
868
+ dropdown: {
869
+ position: "absolute",
870
+ top: "100%",
871
+ left: 0,
872
+ paddingTop: spacing[2],
873
+ zIndex: 100
874
+ },
875
+ dropdownInner: {
876
+ backgroundColor: colors.bgWhite,
877
+ borderRadius: borderRadius.lg,
878
+ boxShadow: "0 10px 40px rgba(0,0,0,0.1)",
879
+ minWidth: "200px",
880
+ padding: spacing[2]
881
+ },
882
+ dropdownItem: {
883
+ display: "block",
884
+ padding: `${spacing[3]} ${spacing[4]}`,
885
+ fontFamily: fonts.primary,
886
+ fontWeight: fontWeights.medium,
887
+ fontSize: fontSizes.base,
888
+ color: colors.evTeal,
889
+ textDecoration: "none",
890
+ borderRadius: borderRadius.md,
891
+ cursor: "pointer"
892
+ },
893
+ ctaButton: {
894
+ backgroundColor: colors.evTeal,
895
+ color: colors.textWhite,
896
+ fontFamily: fonts.primary,
897
+ fontWeight: fontWeights.bold,
898
+ fontSize: fontSizes.xl,
899
+ padding: `${spacing[3]} ${spacing[8]}`,
900
+ borderRadius: borderRadius.lg,
901
+ border: "none",
902
+ cursor: "pointer",
903
+ textDecoration: "none",
904
+ display: "inline-block"
905
+ },
906
+ mobileMenuButton: {
907
+ display: isMobile ? "block" : "none",
908
+ background: "none",
909
+ border: "none",
910
+ cursor: "pointer",
911
+ padding: spacing[2]
912
+ },
913
+ hamburger: {
914
+ width: "24px",
915
+ height: "2px",
916
+ backgroundColor: colors.evTeal,
917
+ position: "relative"
918
+ },
919
+ mobileMenu: {
920
+ display: mobileMenuOpen ? "flex" : "none",
921
+ flexDirection: "column",
922
+ position: "absolute",
923
+ top: "100%",
924
+ left: 0,
925
+ right: 0,
926
+ backgroundColor: colors.bgWhite,
927
+ padding: spacing[4],
928
+ boxShadow: "0 4px 20px rgba(0,0,0,0.1)"
929
+ },
930
+ mobileNavItem: {
931
+ fontFamily: fonts.primary,
932
+ fontWeight: fontWeights.bold,
933
+ fontSize: fontSizes.lg,
934
+ color: colors.evTeal,
935
+ textDecoration: "none",
936
+ padding: `${spacing[3]} 0`,
937
+ borderBottom: `1px solid ${colors.borderLight}`
938
+ },
939
+ profileButton: {
940
+ width: "40px",
941
+ height: "40px",
942
+ borderRadius: borderRadius.full,
943
+ border: `2px solid ${colors.evTeal}`,
944
+ backgroundColor: colors.bgLight,
945
+ cursor: "pointer",
946
+ display: "flex",
947
+ alignItems: "center",
948
+ justifyContent: "center",
949
+ padding: 0
950
+ },
951
+ profileDropdown: {
952
+ position: "absolute",
953
+ top: "100%",
954
+ right: 0,
955
+ paddingTop: spacing[2],
956
+ zIndex: 100
957
+ },
958
+ profileDropdownInner: {
959
+ backgroundColor: colors.bgWhite,
960
+ borderRadius: borderRadius.lg,
961
+ boxShadow: "0 10px 40px rgba(0,0,0,0.1)",
962
+ minWidth: "160px",
963
+ padding: spacing[2]
964
+ },
965
+ profileDropdownItem: {
966
+ display: "block",
967
+ width: "100%",
968
+ padding: `${spacing[3]} ${spacing[4]}`,
969
+ fontFamily: fonts.primary,
970
+ fontWeight: fontWeights.medium,
971
+ fontSize: fontSizes.base,
972
+ color: colors.evTeal,
973
+ textDecoration: "none",
974
+ borderRadius: borderRadius.md,
975
+ cursor: "pointer",
976
+ border: "none",
977
+ backgroundColor: "transparent",
978
+ textAlign: "left"
979
+ },
980
+ mobileDivider: {
981
+ height: "1px",
982
+ backgroundColor: colors.borderLight,
983
+ margin: `${spacing[3]} 0`
984
+ },
985
+ profileLabel: {
986
+ padding: `${spacing[2]} ${spacing[4]} ${spacing[3]}`,
987
+ fontFamily: fonts.primary,
988
+ fontWeight: fontWeights.semibold,
989
+ fontSize: fontSizes.sm,
990
+ color: colors.textMuted,
991
+ borderBottom: `1px solid ${colors.borderLight}`,
992
+ marginBottom: spacing[1],
993
+ overflow: "hidden",
994
+ textOverflow: "ellipsis",
995
+ whiteSpace: "nowrap"
996
+ }
997
+ };
998
+ const NavLink = ({ item }) => {
999
+ const isActive = currentPath === item.href;
1000
+ const hasDropdown = item.dropdown && item.dropdown.length > 0;
1001
+ const isOpen = openDropdown === item.label;
1002
+ return /* @__PURE__ */ import_react4.default.createElement(
1003
+ "div",
1004
+ {
1005
+ style: { position: "relative" },
1006
+ onMouseEnter: () => hasDropdown && setOpenDropdown(item.label),
1007
+ onMouseLeave: () => hasDropdown && setOpenDropdown(null)
1008
+ },
1009
+ /* @__PURE__ */ import_react4.default.createElement(
1010
+ "a",
1011
+ {
1012
+ href: item.href,
1013
+ onClick: (e) => handleNavClick(e, item.href),
1014
+ style: {
1015
+ ...styles2.navItem,
1016
+ ...isActive ? styles2.navItemActive : {}
1017
+ }
1018
+ },
1019
+ item.label,
1020
+ hasDropdown && /* @__PURE__ */ import_react4.default.createElement(
1021
+ "svg",
1022
+ {
1023
+ style: styles2.dropdownIcon,
1024
+ viewBox: "0 0 16 9",
1025
+ fill: "none",
1026
+ xmlns: "http://www.w3.org/2000/svg"
1027
+ },
1028
+ /* @__PURE__ */ import_react4.default.createElement(
1029
+ "path",
1030
+ {
1031
+ d: "M1 1L8 8L15 1",
1032
+ stroke: colors.evTeal,
1033
+ strokeWidth: "2",
1034
+ strokeLinecap: "round",
1035
+ strokeLinejoin: "round"
1036
+ }
1037
+ )
1038
+ )
1039
+ ),
1040
+ hasDropdown && isOpen && /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.dropdown }, /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.dropdownInner }, item.dropdown.map((dropdownItem, idx) => /* @__PURE__ */ import_react4.default.createElement(
1041
+ "a",
1042
+ {
1043
+ key: idx,
1044
+ href: dropdownItem.href,
1045
+ onClick: (e) => handleNavClick(e, dropdownItem.href),
1046
+ style: styles2.dropdownItem,
1047
+ onMouseEnter: (e) => {
1048
+ e.target.style.backgroundColor = colors.bgLight;
1049
+ },
1050
+ onMouseLeave: (e) => {
1051
+ e.target.style.backgroundColor = "transparent";
1052
+ }
1053
+ },
1054
+ dropdownItem.label
1055
+ ))))
1056
+ );
1057
+ };
1058
+ return /* @__PURE__ */ import_react4.default.createElement("header", { style: styles2.header }, /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.container }, /* @__PURE__ */ import_react4.default.createElement(
1059
+ "a",
1060
+ {
1061
+ href: "/",
1062
+ onClick: (e) => handleNavClick(e, "/"),
1063
+ style: { display: "flex", alignItems: "center" }
1064
+ },
1065
+ logoSrc ? /* @__PURE__ */ import_react4.default.createElement("img", { src: logoSrc, alt: logoAlt, style: styles2.logo }) : /* @__PURE__ */ import_react4.default.createElement(
1066
+ "span",
1067
+ {
1068
+ style: {
1069
+ fontFamily: fonts.primary,
1070
+ fontWeight: fontWeights.bold,
1071
+ fontSize: fontSizes["2xl"],
1072
+ color: colors.evTeal
1073
+ }
1074
+ },
1075
+ "empowered.vote"
1076
+ )
1077
+ ), /* @__PURE__ */ import_react4.default.createElement("nav", { style: styles2.nav, className: "ev-header-nav" }, navItems.map((item, idx) => /* @__PURE__ */ import_react4.default.createElement(NavLink, { key: idx, item }))), /* @__PURE__ */ import_react4.default.createElement("div", { style: { display: isMobile ? "none" : "flex", alignItems: "center", gap: spacing[4] } }, ctaButton && /* @__PURE__ */ import_react4.default.createElement(
1078
+ "a",
1079
+ {
1080
+ href: ctaButton.href,
1081
+ onClick: (e) => handleNavClick(e, ctaButton.href),
1082
+ style: styles2.ctaButton,
1083
+ className: "ev-header-cta",
1084
+ onMouseEnter: (e) => {
1085
+ e.target.style.backgroundColor = colors.evTealDark;
1086
+ },
1087
+ onMouseLeave: (e) => {
1088
+ e.target.style.backgroundColor = colors.evTeal;
1089
+ }
1090
+ },
1091
+ ctaButton.label
1092
+ ), profileMenu && /* @__PURE__ */ import_react4.default.createElement("div", { ref: profileRef, style: { position: "relative" } }, /* @__PURE__ */ import_react4.default.createElement(
1093
+ "button",
1094
+ {
1095
+ style: styles2.profileButton,
1096
+ onClick: () => setProfileOpen(!profileOpen),
1097
+ "aria-label": "Profile menu",
1098
+ "aria-expanded": profileOpen
1099
+ },
1100
+ /* @__PURE__ */ import_react4.default.createElement(
1101
+ "svg",
1102
+ {
1103
+ width: "20",
1104
+ height: "20",
1105
+ viewBox: "0 0 24 24",
1106
+ fill: "none",
1107
+ stroke: colors.evTeal,
1108
+ strokeWidth: "2",
1109
+ strokeLinecap: "round",
1110
+ strokeLinejoin: "round"
1111
+ },
1112
+ /* @__PURE__ */ import_react4.default.createElement("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
1113
+ /* @__PURE__ */ import_react4.default.createElement("circle", { cx: "12", cy: "7", r: "4" })
1114
+ )
1115
+ ), profileOpen && /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.profileDropdown }, /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.profileDropdownInner }, profileMenu.label && /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.profileLabel }, profileMenu.label), profileMenu.items.map((item, idx) => {
1116
+ if (item.href) {
1117
+ return /* @__PURE__ */ import_react4.default.createElement(
1118
+ "a",
1119
+ {
1120
+ key: idx,
1121
+ href: item.href,
1122
+ onClick: (e) => {
1123
+ setProfileOpen(false);
1124
+ if (onNavigate) {
1125
+ e.preventDefault();
1126
+ onNavigate(item.href);
1127
+ }
1128
+ },
1129
+ style: styles2.profileDropdownItem,
1130
+ onMouseEnter: (e) => {
1131
+ e.target.style.backgroundColor = colors.bgLight;
1132
+ },
1133
+ onMouseLeave: (e) => {
1134
+ e.target.style.backgroundColor = "transparent";
1135
+ }
1136
+ },
1137
+ item.label
1138
+ );
1139
+ }
1140
+ return /* @__PURE__ */ import_react4.default.createElement(
1141
+ "button",
1142
+ {
1143
+ key: idx,
1144
+ onClick: () => {
1145
+ var _a;
1146
+ setProfileOpen(false);
1147
+ (_a = item.onClick) == null ? void 0 : _a.call(item);
1148
+ },
1149
+ style: styles2.profileDropdownItem,
1150
+ onMouseEnter: (e) => {
1151
+ e.target.style.backgroundColor = colors.bgLight;
1152
+ },
1153
+ onMouseLeave: (e) => {
1154
+ e.target.style.backgroundColor = "transparent";
1155
+ }
1156
+ },
1157
+ item.label
1158
+ );
1159
+ }))))), /* @__PURE__ */ import_react4.default.createElement(
1160
+ "button",
1161
+ {
1162
+ style: styles2.mobileMenuButton,
1163
+ className: "ev-header-mobile-toggle",
1164
+ onClick: () => setMobileMenuOpen(!mobileMenuOpen),
1165
+ "aria-label": "Toggle menu",
1166
+ "aria-expanded": mobileMenuOpen
1167
+ },
1168
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.hamburger }, /* @__PURE__ */ import_react4.default.createElement(
1169
+ "span",
1170
+ {
1171
+ style: {
1172
+ position: "absolute",
1173
+ top: "-8px",
1174
+ left: 0,
1175
+ width: "100%",
1176
+ height: "2px",
1177
+ backgroundColor: colors.evTeal
1178
+ }
1179
+ }
1180
+ ), /* @__PURE__ */ import_react4.default.createElement(
1181
+ "span",
1182
+ {
1183
+ style: {
1184
+ position: "absolute",
1185
+ top: "8px",
1186
+ left: 0,
1187
+ width: "100%",
1188
+ height: "2px",
1189
+ backgroundColor: colors.evTeal
1190
+ }
1191
+ }
1192
+ ))
1193
+ )), /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.mobileMenu, className: "ev-header-mobile-menu" }, navItems.map((item, idx) => {
1194
+ const hasDropdown = item.dropdown && item.dropdown.length > 0;
1195
+ return /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, { key: idx }, hasDropdown ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
1196
+ "span",
1197
+ {
1198
+ style: {
1199
+ ...styles2.mobileNavItem,
1200
+ cursor: "default",
1201
+ display: "block"
1202
+ }
1203
+ },
1204
+ item.label
1205
+ ), item.dropdown.map((sub, subIdx) => /* @__PURE__ */ import_react4.default.createElement(
1206
+ "a",
1207
+ {
1208
+ key: subIdx,
1209
+ href: sub.href,
1210
+ onClick: (e) => {
1211
+ handleNavClick(e, sub.href);
1212
+ setMobileMenuOpen(false);
1213
+ },
1214
+ style: {
1215
+ ...styles2.mobileNavItem,
1216
+ fontWeight: fontWeights.medium,
1217
+ fontSize: fontSizes.base,
1218
+ paddingLeft: spacing[4]
1219
+ }
1220
+ },
1221
+ sub.label
1222
+ ))) : /* @__PURE__ */ import_react4.default.createElement(
1223
+ "a",
1224
+ {
1225
+ href: item.href,
1226
+ onClick: (e) => {
1227
+ handleNavClick(e, item.href);
1228
+ setMobileMenuOpen(false);
1229
+ },
1230
+ style: styles2.mobileNavItem
1231
+ },
1232
+ item.label
1233
+ ));
1234
+ }), ctaButton && /* @__PURE__ */ import_react4.default.createElement(
1235
+ "a",
1236
+ {
1237
+ href: ctaButton.href,
1238
+ onClick: (e) => {
1239
+ handleNavClick(e, ctaButton.href);
1240
+ setMobileMenuOpen(false);
1241
+ },
1242
+ style: { ...styles2.ctaButton, marginTop: spacing[4], textAlign: "center" }
1243
+ },
1244
+ ctaButton.label
1245
+ ), profileMenu && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("div", { style: styles2.mobileDivider }), profileMenu.label && /* @__PURE__ */ import_react4.default.createElement(
1246
+ "span",
1247
+ {
1248
+ style: {
1249
+ ...styles2.mobileNavItem,
1250
+ fontWeight: fontWeights.medium,
1251
+ fontSize: fontSizes.sm,
1252
+ color: colors.textMuted,
1253
+ cursor: "default",
1254
+ display: "block",
1255
+ borderBottom: "none"
1256
+ }
1257
+ },
1258
+ profileMenu.label
1259
+ ), profileMenu.items.map((item, idx) => {
1260
+ if (item.href) {
1261
+ return /* @__PURE__ */ import_react4.default.createElement(
1262
+ "a",
1263
+ {
1264
+ key: idx,
1265
+ href: item.href,
1266
+ onClick: (e) => {
1267
+ setMobileMenuOpen(false);
1268
+ if (onNavigate) {
1269
+ e.preventDefault();
1270
+ onNavigate(item.href);
1271
+ }
1272
+ },
1273
+ style: styles2.mobileNavItem
1274
+ },
1275
+ item.label
1276
+ );
1277
+ }
1278
+ return /* @__PURE__ */ import_react4.default.createElement(
1279
+ "button",
1280
+ {
1281
+ key: idx,
1282
+ onClick: () => {
1283
+ var _a;
1284
+ setMobileMenuOpen(false);
1285
+ (_a = item.onClick) == null ? void 0 : _a.call(item);
1286
+ },
1287
+ style: {
1288
+ ...styles2.mobileNavItem,
1289
+ background: "none",
1290
+ border: "none",
1291
+ cursor: "pointer",
1292
+ width: "100%",
1293
+ textAlign: "left"
1294
+ }
1295
+ },
1296
+ item.label
1297
+ );
1298
+ }))));
1299
+ }
1300
+
1301
+ // src/SiteHeader.jsx
1302
+ var import_react5 = __toESM(require("react"));
1303
+ var defaultNavItems = [
1304
+ { label: "About Us", href: "https://empowered.vote/about" },
1305
+ {
1306
+ label: "Features",
1307
+ href: "#",
1308
+ dropdown: [
1309
+ { label: "Political Compass", href: "https://compass.empowered.vote" },
1310
+ { label: "Find Representatives", href: "https://essentials.empowered.vote" },
1311
+ { label: "Read & Rank", href: "https://readrank.empowered.vote" },
1312
+ { label: "Treasury Tracker", href: "https://ev-prototypes.netlify.app/treasury-tracker/dist" },
1313
+ { label: "Empowered Badges", href: "https://ev-prototypes.netlify.app/empowered-badges/dist" }
1314
+ ]
1315
+ },
1316
+ { label: "Volunteer", href: "https://empowered.vote/volunteer" },
1317
+ { label: "FAQ", href: "https://empowered.vote/faq" }
1318
+ ];
1319
+ var defaultCtaButton = {
1320
+ label: "Donate",
1321
+ href: "https://empowered.vote/donate"
1322
+ };
1323
+ function SiteHeader({
1324
+ logoSrc = "/EVLogo.svg",
1325
+ currentPath,
1326
+ onNavigate,
1327
+ profileMenu,
1328
+ style = {}
1329
+ }) {
1330
+ const handleNavigate = (href) => {
1331
+ if (onNavigate) {
1332
+ onNavigate(href);
1333
+ } else {
1334
+ window.location.href = href;
1335
+ }
1336
+ };
1337
+ return /* @__PURE__ */ import_react5.default.createElement(
1338
+ Header,
1339
+ {
1340
+ logoSrc,
1341
+ logoAlt: "Empowered Vote",
1342
+ navItems: defaultNavItems,
1343
+ ctaButton: defaultCtaButton,
1344
+ currentPath,
1345
+ onNavigate: handleNavigate,
1346
+ profileMenu,
1347
+ style
1348
+ }
1349
+ );
1350
+ }
1351
+
1352
+ // src/FilterSidebar.jsx
1353
+ var import_react6 = __toESM(require("react"));
1354
+ function FilterSidebar({
1355
+ title = "Filter by",
1356
+ zipCode = "",
1357
+ onZipChange,
1358
+ onZipClear,
1359
+ onZipSubmit,
1360
+ filterOptions = [
1361
+ { value: "All", label: "All" },
1362
+ { value: "Local", label: "Local" },
1363
+ { value: "State", label: "State" },
1364
+ { value: "Federal", label: "Federal" }
1365
+ ],
1366
+ selectedFilter = "All",
1367
+ onFilterChange,
1368
+ locationLabel,
1369
+ buildingImageSrc,
1370
+ zipInputRef,
1371
+ autocompleteContainerRef,
1372
+ style = {}
1373
+ }) {
1374
+ const isMobile = useMediaQuery("(max-width: 768px)");
1375
+ const handleKeyDown = (e) => {
1376
+ if (e.key === "Enter" && onZipSubmit) {
1377
+ onZipSubmit();
1378
+ }
1379
+ };
1380
+ const styles2 = {
1381
+ sidebar: isMobile ? {
1382
+ width: "100%",
1383
+ padding: `${spacing[3]} ${spacing[4]}`,
1384
+ backgroundColor: colors.bgWhite,
1385
+ borderBottom: `1px solid ${colors.borderLight}`,
1386
+ ...style
1387
+ } : {
1388
+ width: "300px",
1389
+ flexShrink: 0,
1390
+ padding: spacing[6],
1391
+ backgroundColor: colors.bgWhite,
1392
+ borderRight: `1px solid ${colors.borderLight}`,
1393
+ position: "sticky",
1394
+ top: 0,
1395
+ height: "calc(100vh - 75px)",
1396
+ display: "flex",
1397
+ flexDirection: "column",
1398
+ overflow: "hidden",
1399
+ ...style
1400
+ },
1401
+ title: {
1402
+ fontFamily: fonts.primary,
1403
+ fontWeight: fontWeights.bold,
1404
+ fontSize: fontSizes.lg,
1405
+ color: colors.textPrimary,
1406
+ marginBottom: spacing[4]
1407
+ },
1408
+ section: {
1409
+ marginBottom: spacing[6]
1410
+ },
1411
+ sectionLabel: {
1412
+ fontFamily: fonts.primary,
1413
+ fontWeight: fontWeights.medium,
1414
+ fontSize: fontSizes.sm,
1415
+ color: colors.textSecondary,
1416
+ marginBottom: spacing[2]
1417
+ },
1418
+ contentTop: {
1419
+ flexShrink: 0
1420
+ },
1421
+ zipInputWrapper: {
1422
+ position: "relative",
1423
+ display: "flex",
1424
+ alignItems: "center"
1425
+ },
1426
+ zipInput: {
1427
+ width: "100%",
1428
+ padding: `${spacing[2]} ${spacing[3]}`,
1429
+ paddingRight: spacing[8],
1430
+ fontFamily: fonts.primary,
1431
+ fontSize: fontSizes.base,
1432
+ color: colors.textPrimary,
1433
+ border: `1px solid ${colors.evTeal}`,
1434
+ borderRadius: borderRadius.md,
1435
+ outline: "none"
1436
+ },
1437
+ clearButton: {
1438
+ position: "absolute",
1439
+ right: spacing[2],
1440
+ background: "none",
1441
+ border: "none",
1442
+ cursor: "pointer",
1443
+ padding: spacing[1],
1444
+ color: colors.evTeal,
1445
+ fontSize: fontSizes.lg,
1446
+ lineHeight: 1,
1447
+ display: zipCode ? "block" : "none"
1448
+ },
1449
+ radioGroup: {
1450
+ display: "flex",
1451
+ flexDirection: isMobile ? "row" : "column",
1452
+ flexWrap: isMobile ? "wrap" : "nowrap",
1453
+ gap: spacing[2]
1454
+ },
1455
+ radioLabel: {
1456
+ display: "flex",
1457
+ alignItems: "center",
1458
+ gap: spacing[2],
1459
+ cursor: "pointer",
1460
+ fontFamily: fonts.primary,
1461
+ fontSize: fontSizes.base,
1462
+ color: colors.textPrimary
1463
+ },
1464
+ radioInput: {
1465
+ width: "16px",
1466
+ height: "16px",
1467
+ accentColor: colors.evTeal,
1468
+ cursor: "pointer"
1469
+ },
1470
+ imageSection: {
1471
+ flexGrow: 1,
1472
+ flexShrink: 1,
1473
+ minHeight: 0,
1474
+ display: "flex",
1475
+ flexDirection: "column",
1476
+ overflow: "hidden"
1477
+ },
1478
+ locationLabel: {
1479
+ fontFamily: fonts.primary,
1480
+ fontWeight: fontWeights.bold,
1481
+ fontSize: fontSizes.base,
1482
+ color: colors.textPrimary,
1483
+ marginBottom: spacing[3]
1484
+ },
1485
+ buildingImage: {
1486
+ width: "100%",
1487
+ borderRadius: borderRadius.lg,
1488
+ objectFit: "cover",
1489
+ aspectRatio: "1/2.25",
1490
+ flexShrink: 1,
1491
+ minHeight: 0,
1492
+ overflow: "hidden"
1493
+ },
1494
+ buildingPlaceholder: {
1495
+ width: "100%",
1496
+ aspectRatio: "1/2.25",
1497
+ backgroundColor: colors.bgLight,
1498
+ borderRadius: borderRadius.lg,
1499
+ display: "flex",
1500
+ alignItems: "center",
1501
+ justifyContent: "center",
1502
+ color: colors.textMuted,
1503
+ fontFamily: fonts.primary,
1504
+ fontSize: fontSizes.sm
1505
+ }
1506
+ };
1507
+ return /* @__PURE__ */ import_react6.default.createElement("aside", { style: styles2.sidebar, className: "ev-filter-sidebar" }, !isMobile && /* @__PURE__ */ import_react6.default.createElement("h2", { style: styles2.title }, title), /* @__PURE__ */ import_react6.default.createElement("div", { style: isMobile ? void 0 : styles2.contentTop }, /* @__PURE__ */ import_react6.default.createElement("div", { style: isMobile ? { marginBottom: spacing[3] } : styles2.section }, !isMobile && /* @__PURE__ */ import_react6.default.createElement("label", { style: styles2.sectionLabel }, "Location"), autocompleteContainerRef ? /* @__PURE__ */ import_react6.default.createElement(
1508
+ "div",
1509
+ {
1510
+ ref: autocompleteContainerRef,
1511
+ style: styles2.zipInputWrapper,
1512
+ className: "ev-autocomplete-container"
1513
+ }
1514
+ ) : /* @__PURE__ */ import_react6.default.createElement("div", { style: styles2.zipInputWrapper }, /* @__PURE__ */ import_react6.default.createElement(
1515
+ "input",
1516
+ {
1517
+ ref: zipInputRef,
1518
+ type: "text",
1519
+ value: zipCode,
1520
+ onChange: (e) => onZipChange == null ? void 0 : onZipChange(e.target.value),
1521
+ onKeyDown: handleKeyDown,
1522
+ placeholder: "ZIP or address",
1523
+ style: styles2.zipInput,
1524
+ "aria-label": "Search location"
1525
+ }
1526
+ ), /* @__PURE__ */ import_react6.default.createElement(
1527
+ "button",
1528
+ {
1529
+ type: "button",
1530
+ onClick: onZipClear,
1531
+ style: styles2.clearButton,
1532
+ "aria-label": "Clear ZIP code"
1533
+ },
1534
+ "\xD7"
1535
+ ))), /* @__PURE__ */ import_react6.default.createElement("div", { style: isMobile ? {} : styles2.section }, !isMobile && /* @__PURE__ */ import_react6.default.createElement("label", { style: styles2.sectionLabel }, "Group"), /* @__PURE__ */ import_react6.default.createElement("div", { style: styles2.radioGroup, role: "radiogroup", "aria-label": "Filter by group" }, filterOptions.map((option) => /* @__PURE__ */ import_react6.default.createElement("label", { key: option.value, style: styles2.radioLabel }, /* @__PURE__ */ import_react6.default.createElement(
1536
+ "input",
1537
+ {
1538
+ type: "radio",
1539
+ name: "filter",
1540
+ value: option.value,
1541
+ checked: selectedFilter === option.value,
1542
+ onChange: () => onFilterChange == null ? void 0 : onFilterChange(option.value),
1543
+ style: styles2.radioInput
1544
+ }
1545
+ ), option.label))))), !isMobile && /* @__PURE__ */ import_react6.default.createElement("div", { style: styles2.imageSection }, locationLabel && /* @__PURE__ */ import_react6.default.createElement("div", { style: styles2.locationLabel }, locationLabel), buildingImageSrc ? /* @__PURE__ */ import_react6.default.createElement(
1546
+ "img",
1547
+ {
1548
+ src: buildingImageSrc,
1549
+ alt: `${selectedFilter} government building`,
1550
+ style: styles2.buildingImage
1551
+ }
1552
+ ) : /* @__PURE__ */ import_react6.default.createElement("div", { style: styles2.buildingPlaceholder }, "No image")));
1553
+ }
1554
+
1555
+ // src/PoliticianCard.jsx
1556
+ var import_react7 = __toESM(require("react"));
1557
+ function PoliticianCard({
1558
+ id,
1559
+ imageSrc,
1560
+ name,
1561
+ title,
1562
+ subtitle,
1563
+ onClick,
1564
+ onCompassClick,
1565
+ variant = "horizontal",
1566
+ style = {},
1567
+ badge,
1568
+ imageFocalPoint,
1569
+ footer
1570
+ }) {
1571
+ const isHorizontal = variant === "horizontal";
1572
+ const handleCardClick = (e) => {
1573
+ if (e.target.closest(".ev-compass-button")) return;
1574
+ onClick == null ? void 0 : onClick();
1575
+ };
1576
+ const handleCompassClick = (e) => {
1577
+ e.stopPropagation();
1578
+ onCompassClick == null ? void 0 : onCompassClick();
1579
+ };
1580
+ const styles2 = {
1581
+ card: {
1582
+ display: "flex",
1583
+ flexDirection: isHorizontal ? "row" : "column",
1584
+ alignItems: "stretch",
1585
+ backgroundColor: colors.bgWhite,
1586
+ borderRadius: borderRadius.lg,
1587
+ border: `1px solid ${colors.borderLight}`,
1588
+ overflow: "hidden",
1589
+ cursor: onClick ? "pointer" : "default",
1590
+ transition: "box-shadow 0.2s ease, transform 0.2s ease",
1591
+ position: "relative",
1592
+ minHeight: isHorizontal ? "130px" : void 0,
1593
+ height: "100%",
1594
+ ...style
1595
+ },
1596
+ imageWrapper: {
1597
+ width: isHorizontal ? "90px" : "100%",
1598
+ height: isHorizontal ? void 0 : "auto",
1599
+ aspectRatio: isHorizontal ? void 0 : "4/5",
1600
+ flexShrink: 0,
1601
+ overflow: "hidden"
1602
+ },
1603
+ image: {
1604
+ width: "100%",
1605
+ height: "100%",
1606
+ objectFit: "cover",
1607
+ objectPosition: imageFocalPoint != null ? imageFocalPoint : "center 20%"
1608
+ },
1609
+ imagePlaceholder: {
1610
+ width: "100%",
1611
+ height: "100%",
1612
+ backgroundColor: colors.evTeal,
1613
+ display: "flex",
1614
+ alignItems: "center",
1615
+ justifyContent: "center",
1616
+ color: "#ffffff",
1617
+ fontFamily: fonts.primary,
1618
+ fontSize: isHorizontal ? fontSizes.base : fontSizes.xl,
1619
+ fontWeight: fontWeights.bold,
1620
+ borderRadius: 0
1621
+ },
1622
+ content: {
1623
+ flex: 1,
1624
+ padding: isHorizontal ? `${spacing[2]} ${spacing[3]}` : spacing[3],
1625
+ minWidth: 0,
1626
+ display: "flex",
1627
+ flexDirection: "column"
1628
+ },
1629
+ name: {
1630
+ fontFamily: fonts.primary,
1631
+ fontWeight: fontWeights.bold,
1632
+ fontSize: isHorizontal ? fontSizes.sm : fontSizes.base,
1633
+ color: colors.evTeal,
1634
+ margin: 0,
1635
+ marginBottom: spacing[1],
1636
+ overflow: "hidden",
1637
+ textOverflow: "ellipsis",
1638
+ whiteSpace: isHorizontal ? "nowrap" : "normal",
1639
+ display: isHorizontal ? "block" : "-webkit-box",
1640
+ WebkitLineClamp: isHorizontal ? void 0 : 2,
1641
+ WebkitBoxOrient: "vertical"
1642
+ },
1643
+ title: {
1644
+ fontFamily: fonts.primary,
1645
+ fontWeight: fontWeights.regular,
1646
+ fontSize: isHorizontal ? fontSizes.xs : fontSizes.sm,
1647
+ color: colors.textSecondary,
1648
+ margin: 0,
1649
+ overflow: "hidden",
1650
+ textOverflow: "ellipsis",
1651
+ display: "-webkit-box",
1652
+ WebkitLineClamp: 2,
1653
+ WebkitBoxOrient: "vertical"
1654
+ },
1655
+ subtitle: {
1656
+ fontFamily: fonts.primary,
1657
+ fontWeight: fontWeights.regular,
1658
+ fontSize: isHorizontal ? "11px" : fontSizes.xs,
1659
+ color: colors.textMuted,
1660
+ margin: 0,
1661
+ marginTop: spacing[1],
1662
+ overflow: "hidden",
1663
+ textOverflow: "ellipsis",
1664
+ whiteSpace: "nowrap"
1665
+ },
1666
+ compassButton: {
1667
+ width: isHorizontal ? "28px" : "36px",
1668
+ height: isHorizontal ? "28px" : "36px",
1669
+ borderRadius: "50%",
1670
+ backgroundColor: colors.evTeal,
1671
+ border: "none",
1672
+ cursor: "pointer",
1673
+ display: "flex",
1674
+ alignItems: "center",
1675
+ justifyContent: "center",
1676
+ flexShrink: 0,
1677
+ alignSelf: "center",
1678
+ marginRight: isHorizontal ? spacing[3] : 0,
1679
+ marginTop: isHorizontal ? 0 : spacing[2],
1680
+ position: isHorizontal ? "relative" : "absolute",
1681
+ bottom: isHorizontal ? "auto" : spacing[3],
1682
+ right: isHorizontal ? "auto" : spacing[3],
1683
+ transition: "background-color 0.2s ease"
1684
+ },
1685
+ compassIcon: {
1686
+ width: isHorizontal ? "20px" : "24px",
1687
+ height: isHorizontal ? "20px" : "24px",
1688
+ color: colors.textWhite
1689
+ },
1690
+ badge: {
1691
+ position: "absolute",
1692
+ bottom: spacing[1],
1693
+ right: spacing[1],
1694
+ backgroundColor: colors.evCoral,
1695
+ color: colors.textWhite,
1696
+ fontFamily: fonts.primary,
1697
+ fontWeight: fontWeights.semibold,
1698
+ fontSize: "10px",
1699
+ lineHeight: 1,
1700
+ padding: `${spacing[1]} ${spacing[2]}`,
1701
+ borderRadius: borderRadius.full,
1702
+ zIndex: 1,
1703
+ letterSpacing: "0.02em",
1704
+ textTransform: "uppercase"
1705
+ }
1706
+ };
1707
+ const CompassIcon2 = () => /* @__PURE__ */ import_react7.default.createElement(
1708
+ "svg",
1709
+ {
1710
+ style: styles2.compassIcon,
1711
+ viewBox: "0 0 24 24",
1712
+ fill: "none",
1713
+ xmlns: "http://www.w3.org/2000/svg"
1714
+ },
1715
+ /* @__PURE__ */ import_react7.default.createElement(
1716
+ "polygon",
1717
+ {
1718
+ points: "12,1 21.5,6.5 21.5,17.5 12,23 2.5,17.5 2.5,6.5",
1719
+ fill: "none",
1720
+ stroke: "currentColor",
1721
+ strokeWidth: "1.5",
1722
+ strokeLinejoin: "round"
1723
+ }
1724
+ ),
1725
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "12", y2: "1", stroke: "currentColor", strokeWidth: "1" }),
1726
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "21.5", y2: "6.5", stroke: "currentColor", strokeWidth: "1" }),
1727
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "21.5", y2: "17.5", stroke: "currentColor", strokeWidth: "1" }),
1728
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "12", y2: "23", stroke: "currentColor", strokeWidth: "1" }),
1729
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "2.5", y2: "17.5", stroke: "currentColor", strokeWidth: "1" }),
1730
+ /* @__PURE__ */ import_react7.default.createElement("line", { x1: "12", y1: "12", x2: "2.5", y2: "6.5", stroke: "currentColor", strokeWidth: "1" }),
1731
+ /* @__PURE__ */ import_react7.default.createElement(
1732
+ "polygon",
1733
+ {
1734
+ points: "12,4 18,7.5 18,16 12,19.5 7,15 5,8",
1735
+ fill: "currentColor",
1736
+ opacity: "0.35"
1737
+ }
1738
+ ),
1739
+ /* @__PURE__ */ import_react7.default.createElement(
1740
+ "polygon",
1741
+ {
1742
+ points: "12,4 18,7.5 18,16 12,19.5 7,15 5,8",
1743
+ fill: "none",
1744
+ stroke: "currentColor",
1745
+ strokeWidth: "1.5",
1746
+ strokeLinejoin: "round"
1747
+ }
1748
+ )
1749
+ );
1750
+ const [imgError, setImgError] = (0, import_react7.useState)(false);
1751
+ (0, import_react7.useEffect)(() => {
1752
+ setImgError(false);
1753
+ }, [imageSrc]);
1754
+ const getInitials = (n) => {
1755
+ var _a;
1756
+ const parts = (n || "").split(" ").filter(Boolean);
1757
+ const initials = parts.length >= 2 ? parts[0][0] + parts[parts.length - 1][0] : ((_a = parts[0]) == null ? void 0 : _a[0]) || "?";
1758
+ return initials.toUpperCase();
1759
+ };
1760
+ return /* @__PURE__ */ import_react7.default.createElement(
1761
+ "div",
1762
+ {
1763
+ style: styles2.card,
1764
+ className: "ev-politician-card",
1765
+ onClick: handleCardClick,
1766
+ onMouseEnter: (e) => {
1767
+ if (onClick) {
1768
+ e.currentTarget.style.boxShadow = shadows.md;
1769
+ e.currentTarget.style.transform = "translateY(-2px)";
1770
+ }
1771
+ },
1772
+ onMouseLeave: (e) => {
1773
+ e.currentTarget.style.boxShadow = "none";
1774
+ e.currentTarget.style.transform = "none";
1775
+ },
1776
+ role: onClick ? "button" : void 0,
1777
+ tabIndex: onClick ? 0 : void 0,
1778
+ onKeyDown: (e) => {
1779
+ if (onClick && (e.key === "Enter" || e.key === " ")) {
1780
+ e.preventDefault();
1781
+ onClick();
1782
+ }
1783
+ }
1784
+ },
1785
+ badge && /* @__PURE__ */ import_react7.default.createElement("span", { style: styles2.badge }, badge),
1786
+ /* @__PURE__ */ import_react7.default.createElement("div", { style: styles2.imageWrapper }, imageSrc && !imgError ? /* @__PURE__ */ import_react7.default.createElement(
1787
+ "img",
1788
+ {
1789
+ src: imageSrc,
1790
+ alt: `${name} portrait`,
1791
+ style: styles2.image,
1792
+ onError: () => setImgError(true)
1793
+ }
1794
+ ) : /* @__PURE__ */ import_react7.default.createElement("div", { style: styles2.imagePlaceholder }, getInitials(name))),
1795
+ /* @__PURE__ */ import_react7.default.createElement("div", { style: styles2.content }, /* @__PURE__ */ import_react7.default.createElement("h3", { style: styles2.name }, name), /* @__PURE__ */ import_react7.default.createElement("p", { style: styles2.title }, title), subtitle && /* @__PURE__ */ import_react7.default.createElement("p", { style: styles2.subtitle }, subtitle), footer && /* @__PURE__ */ import_react7.default.createElement("div", { style: { marginTop: "auto", marginLeft: "-5px" } }, footer)),
1796
+ onCompassClick && /* @__PURE__ */ import_react7.default.createElement(
1797
+ "button",
1798
+ {
1799
+ type: "button",
1800
+ style: styles2.compassButton,
1801
+ className: "ev-compass-button",
1802
+ onClick: handleCompassClick,
1803
+ onMouseEnter: (e) => {
1804
+ e.currentTarget.style.backgroundColor = colors.evTealDark;
1805
+ },
1806
+ onMouseLeave: (e) => {
1807
+ e.currentTarget.style.backgroundColor = colors.evTeal;
1808
+ },
1809
+ "aria-label": `View ${name}'s compass`
1810
+ },
1811
+ /* @__PURE__ */ import_react7.default.createElement(CompassIcon2, null)
1812
+ )
1813
+ );
1814
+ }
1815
+
1816
+ // src/CategorySection.jsx
1817
+ var import_react8 = __toESM(require("react"));
1818
+ function CategorySection({
1819
+ title,
1820
+ infoTooltip,
1821
+ websiteUrl,
1822
+ children,
1823
+ style = {},
1824
+ tier
1825
+ }) {
1826
+ var _a, _b;
1827
+ const [showTooltip, setShowTooltip] = (0, import_react8.useState)(false);
1828
+ const tierStyle = tier ? tierColors[tier] : null;
1829
+ const styles2 = {
1830
+ section: {
1831
+ marginBottom: spacing[8],
1832
+ ...style
1833
+ },
1834
+ header: {
1835
+ display: "flex",
1836
+ alignItems: "center",
1837
+ gap: spacing[2],
1838
+ marginBottom: spacing[4]
1839
+ },
1840
+ titlePill: {
1841
+ display: "inline-flex",
1842
+ alignItems: "center",
1843
+ padding: `${spacing[2]} ${spacing[4]}`,
1844
+ backgroundColor: colors.bgWhite,
1845
+ border: `1px solid ${(_a = tierStyle == null ? void 0 : tierStyle.accent) != null ? _a : colors.borderMedium}`,
1846
+ borderRadius: borderRadius.lg,
1847
+ fontFamily: fonts.primary,
1848
+ fontWeight: fontWeights.medium,
1849
+ fontSize: fontSizes.base,
1850
+ color: (_b = tierStyle == null ? void 0 : tierStyle.text) != null ? _b : colors.textPrimary
1851
+ },
1852
+ infoButton: {
1853
+ width: "20px",
1854
+ height: "20px",
1855
+ borderRadius: "50%",
1856
+ border: `1px solid ${colors.borderMedium}`,
1857
+ backgroundColor: colors.bgWhite,
1858
+ cursor: "pointer",
1859
+ display: "flex",
1860
+ alignItems: "center",
1861
+ justifyContent: "center",
1862
+ fontFamily: fonts.primary,
1863
+ fontSize: fontSizes.xs,
1864
+ color: colors.textMuted,
1865
+ position: "relative"
1866
+ },
1867
+ tooltip: {
1868
+ position: "absolute",
1869
+ top: "100%",
1870
+ left: "50%",
1871
+ transform: "translateX(-50%)",
1872
+ marginTop: spacing[2],
1873
+ padding: `${spacing[2]} ${spacing[3]}`,
1874
+ backgroundColor: colors.textPrimary,
1875
+ color: colors.textWhite,
1876
+ fontFamily: fonts.primary,
1877
+ fontSize: fontSizes.sm,
1878
+ borderRadius: borderRadius.md,
1879
+ whiteSpace: "nowrap",
1880
+ zIndex: 100
1881
+ },
1882
+ externalLink: {
1883
+ display: "inline-flex",
1884
+ alignItems: "center",
1885
+ justifyContent: "center",
1886
+ color: colors.textMuted,
1887
+ textDecoration: "none"
1888
+ },
1889
+ grid: {
1890
+ display: "grid",
1891
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(250px, 100%), 1fr))",
1892
+ gap: spacing[4]
1893
+ }
1894
+ };
1895
+ return /* @__PURE__ */ import_react8.default.createElement("section", { style: styles2.section, className: "ev-category-section" }, /* @__PURE__ */ import_react8.default.createElement("div", { style: styles2.header }, /* @__PURE__ */ import_react8.default.createElement("span", { style: styles2.titlePill }, title), infoTooltip && /* @__PURE__ */ import_react8.default.createElement(
1896
+ "button",
1897
+ {
1898
+ type: "button",
1899
+ style: styles2.infoButton,
1900
+ onMouseEnter: () => setShowTooltip(true),
1901
+ onMouseLeave: () => setShowTooltip(false),
1902
+ onFocus: () => setShowTooltip(true),
1903
+ onBlur: () => setShowTooltip(false),
1904
+ "aria-label": `Info about ${title}`
1905
+ },
1906
+ "i",
1907
+ showTooltip && /* @__PURE__ */ import_react8.default.createElement("div", { style: styles2.tooltip, role: "tooltip" }, infoTooltip)
1908
+ ), websiteUrl && /* @__PURE__ */ import_react8.default.createElement(
1909
+ "a",
1910
+ {
1911
+ href: websiteUrl,
1912
+ target: "_blank",
1913
+ rel: "noopener noreferrer",
1914
+ style: styles2.externalLink,
1915
+ "aria-label": `Visit official website for ${title}`
1916
+ },
1917
+ /* @__PURE__ */ import_react8.default.createElement(
1918
+ "svg",
1919
+ {
1920
+ viewBox: "0 0 24 24",
1921
+ fill: "none",
1922
+ xmlns: "http://www.w3.org/2000/svg",
1923
+ style: { width: "14px", height: "14px" }
1924
+ },
1925
+ /* @__PURE__ */ import_react8.default.createElement(
1926
+ "path",
1927
+ {
1928
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14",
1929
+ stroke: "currentColor",
1930
+ strokeWidth: "2",
1931
+ strokeLinecap: "round",
1932
+ strokeLinejoin: "round"
1933
+ }
1934
+ )
1935
+ )
1936
+ )), /* @__PURE__ */ import_react8.default.createElement("div", { style: styles2.grid, className: "ev-category-grid" }, children));
1937
+ }
1938
+
1939
+ // src/SubGroupSection.jsx
1940
+ var import_react9 = __toESM(require("react"));
1941
+ function SubGroupSection({ title, websiteUrl, children }) {
1942
+ const styles2 = {
1943
+ section: {
1944
+ marginBottom: spacing[4]
1945
+ },
1946
+ header: {
1947
+ display: "flex",
1948
+ alignItems: "center",
1949
+ gap: spacing[2],
1950
+ marginBottom: spacing[2]
1951
+ },
1952
+ label: {
1953
+ fontSize: fontSizes.xs,
1954
+ fontWeight: fontWeights.semibold,
1955
+ textTransform: "uppercase",
1956
+ letterSpacing: "0.8px",
1957
+ color: colors.textMuted,
1958
+ fontFamily: fonts.primary
1959
+ },
1960
+ link: {
1961
+ display: "inline-flex",
1962
+ alignItems: "center",
1963
+ justifyContent: "center",
1964
+ color: colors.textMuted,
1965
+ textDecoration: "none"
1966
+ },
1967
+ grid: {
1968
+ display: "grid",
1969
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(250px, 100%), 1fr))",
1970
+ gap: spacing[2]
1971
+ }
1972
+ };
1973
+ return /* @__PURE__ */ import_react9.default.createElement("div", { style: styles2.section }, title && /* @__PURE__ */ import_react9.default.createElement("div", { style: styles2.header }, /* @__PURE__ */ import_react9.default.createElement("span", { style: styles2.label }, title), websiteUrl && /* @__PURE__ */ import_react9.default.createElement(
1974
+ "a",
1975
+ {
1976
+ href: websiteUrl,
1977
+ target: "_blank",
1978
+ rel: "noopener noreferrer",
1979
+ style: styles2.link
1980
+ },
1981
+ /* @__PURE__ */ import_react9.default.createElement("svg", { viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react9.default.createElement("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react9.default.createElement("path", { d: "M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z", stroke: "currentColor", strokeWidth: "2" }))
1982
+ )), /* @__PURE__ */ import_react9.default.createElement("div", { style: styles2.grid, className: "ev-subgroup-grid" }, children));
1983
+ }
1984
+
1985
+ // src/GovernmentBodySection.jsx
1986
+ var import_react10 = __toESM(require("react"));
1987
+ function GovernmentBodySection({
1988
+ title,
1989
+ websiteUrl,
1990
+ tier,
1991
+ defaultExpanded = true,
1992
+ children
1993
+ }) {
1994
+ var _a;
1995
+ const [expanded, setExpanded] = (0, import_react10.useState)(defaultExpanded);
1996
+ const tierStyle = tier ? tierColors[tier] : null;
1997
+ const accentColor = (_a = tierStyle == null ? void 0 : tierStyle.accent) != null ? _a : colors.borderMedium;
1998
+ const styles2 = {
1999
+ section: {
2000
+ marginBottom: spacing[5],
2001
+ borderLeft: `3px solid ${accentColor}`,
2002
+ paddingLeft: spacing[4]
2003
+ },
2004
+ header: {
2005
+ display: "flex",
2006
+ alignItems: "center",
2007
+ gap: spacing[2],
2008
+ marginBottom: expanded ? spacing[3] : 0,
2009
+ cursor: "pointer",
2010
+ userSelect: "none"
2011
+ },
2012
+ title: {
2013
+ fontSize: fontSizes.base,
2014
+ fontWeight: fontWeights.bold,
2015
+ color: colors.textPrimary,
2016
+ fontFamily: fonts.primary
2017
+ },
2018
+ toggle: {
2019
+ fontSize: fontSizes.xs,
2020
+ color: colors.textMuted,
2021
+ transition: "transform 0.2s",
2022
+ transform: expanded ? "rotate(0deg)" : "rotate(-90deg)"
2023
+ },
2024
+ link: {
2025
+ display: "inline-flex",
2026
+ alignItems: "center",
2027
+ justifyContent: "center",
2028
+ color: colors.textMuted,
2029
+ textDecoration: "none"
2030
+ },
2031
+ content: {
2032
+ display: expanded ? "block" : "none"
2033
+ }
2034
+ };
2035
+ return /* @__PURE__ */ import_react10.default.createElement("section", { style: styles2.section, className: "ev-gov-body-section" }, /* @__PURE__ */ import_react10.default.createElement(
2036
+ "div",
2037
+ {
2038
+ style: styles2.header,
2039
+ onClick: () => setExpanded((prev) => !prev),
2040
+ role: "button",
2041
+ tabIndex: 0,
2042
+ onKeyDown: (e) => {
2043
+ if (e.key === "Enter" || e.key === " ") {
2044
+ e.preventDefault();
2045
+ setExpanded((prev) => !prev);
2046
+ }
2047
+ },
2048
+ "aria-expanded": expanded,
2049
+ "aria-label": `${expanded ? "Collapse" : "Expand"} ${title}`
2050
+ },
2051
+ /* @__PURE__ */ import_react10.default.createElement("span", { style: styles2.title }, title),
2052
+ websiteUrl && /* @__PURE__ */ import_react10.default.createElement(
2053
+ "a",
2054
+ {
2055
+ href: websiteUrl,
2056
+ target: "_blank",
2057
+ rel: "noopener noreferrer",
2058
+ style: styles2.link,
2059
+ onClick: (e) => e.stopPropagation(),
2060
+ "aria-label": `Visit ${title} website`
2061
+ },
2062
+ /* @__PURE__ */ import_react10.default.createElement("svg", { viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", style: { width: "14px", height: "14px" } }, /* @__PURE__ */ import_react10.default.createElement("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react10.default.createElement("path", { d: "M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z", stroke: "currentColor", strokeWidth: "2" }))
2063
+ ),
2064
+ /* @__PURE__ */ import_react10.default.createElement("span", { style: styles2.toggle, "aria-hidden": "true" }, "\u25BC")
2065
+ ), /* @__PURE__ */ import_react10.default.createElement("div", { style: styles2.content }, children));
2066
+ }
2067
+
2068
+ // src/SocialLinks.jsx
2069
+ var import_react11 = __toESM(require("react"));
2070
+ var SOCIAL_PLATFORMS = [
2071
+ { test: /facebook\.com/i, platform: "facebook" },
2072
+ { test: /twitter\.com|x\.com/i, platform: "twitter" },
2073
+ { test: /instagram\.com/i, platform: "instagram" },
2074
+ { test: /linkedin\.com/i, platform: "linkedin" },
2075
+ { test: /youtube\.com|youtu\.be/i, platform: "youtube" }
2076
+ ];
2077
+ function SocialLinks({
2078
+ website,
2079
+ twitter,
2080
+ facebook,
2081
+ instagram,
2082
+ linkedin,
2083
+ extraLinks = [],
2084
+ size = "md",
2085
+ style = {}
2086
+ }) {
2087
+ const iconSizes = {
2088
+ sm: "16px",
2089
+ md: "18px",
2090
+ lg: "20px"
2091
+ };
2092
+ const boxSizes = {
2093
+ sm: "32px",
2094
+ md: "36px",
2095
+ lg: "40px"
2096
+ };
2097
+ const iconSize = iconSizes[size];
2098
+ const boxSize = boxSizes[size];
2099
+ const styles2 = {
2100
+ container: {
2101
+ display: "flex",
2102
+ alignItems: "center",
2103
+ gap: spacing[2],
2104
+ flexWrap: "wrap",
2105
+ ...style
2106
+ },
2107
+ link: {
2108
+ color: "#6A7282",
2109
+ transition: "color 0.2s ease, border-color 0.2s ease",
2110
+ display: "flex",
2111
+ alignItems: "center",
2112
+ justifyContent: "center",
2113
+ width: boxSize,
2114
+ height: boxSize,
2115
+ border: "1px solid #E5E7EB",
2116
+ borderRadius: "10px"
2117
+ },
2118
+ icon: {
2119
+ width: iconSize,
2120
+ height: iconSize
2121
+ }
2122
+ };
2123
+ const formatUrl = (value, platform) => {
2124
+ if (!value) return null;
2125
+ if (value.startsWith("http")) return value;
2126
+ switch (platform) {
2127
+ case "twitter":
2128
+ return `https://twitter.com/${value.replace("@", "")}`;
2129
+ case "facebook":
2130
+ return `https://facebook.com/${value}`;
2131
+ case "instagram":
2132
+ return `https://instagram.com/${value.replace("@", "")}`;
2133
+ case "linkedin":
2134
+ return `https://linkedin.com/in/${value}`;
2135
+ default:
2136
+ return value;
2137
+ }
2138
+ };
2139
+ const platformIconMap = {
2140
+ twitter: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement(
2141
+ "path",
2142
+ {
2143
+ d: "M4 4L10.5 12.5M20 20L13.5 11.5M10.5 12.5L4 20H8L13.5 11.5M10.5 12.5L16 4H20L13.5 11.5",
2144
+ stroke: "currentColor",
2145
+ strokeWidth: "2",
2146
+ strokeLinecap: "round",
2147
+ strokeLinejoin: "round"
2148
+ }
2149
+ )),
2150
+ facebook: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement(
2151
+ "path",
2152
+ {
2153
+ d: "M18 2H15C13.6739 2 12.4021 2.52678 11.4645 3.46447C10.5268 4.40215 10 5.67392 10 7V10H7V14H10V22H14V14H17L18 10H14V7C14 6.73478 14.1054 6.48043 14.2929 6.29289C14.4804 6.10536 14.7348 6 15 6H18V2Z",
2154
+ stroke: "currentColor",
2155
+ strokeWidth: "2",
2156
+ strokeLinecap: "round",
2157
+ strokeLinejoin: "round"
2158
+ }
2159
+ )),
2160
+ instagram: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement("rect", { x: "2", y: "2", width: "20", height: "20", rx: "5", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react11.default.createElement("circle", { cx: "12", cy: "12", r: "4", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react11.default.createElement("circle", { cx: "18", cy: "6", r: "1", fill: "currentColor" })),
2161
+ linkedin: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement(
2162
+ "path",
2163
+ {
2164
+ d: "M16 8C17.5913 8 19.1174 8.63214 20.2426 9.75736C21.3679 10.8826 22 12.4087 22 14V21H18V14C18 13.4696 17.7893 12.9609 17.4142 12.5858C17.0391 12.2107 16.5304 12 16 12C15.4696 12 14.9609 12.2107 14.5858 12.5858C14.2107 12.9609 14 13.4696 14 14V21H10V14C10 12.4087 10.6321 10.8826 11.7574 9.75736C12.8826 8.63214 14.4087 8 16 8Z",
2165
+ stroke: "currentColor",
2166
+ strokeWidth: "2",
2167
+ strokeLinecap: "round",
2168
+ strokeLinejoin: "round"
2169
+ }
2170
+ ), /* @__PURE__ */ import_react11.default.createElement("rect", { x: "2", y: "9", width: "4", height: "12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), /* @__PURE__ */ import_react11.default.createElement("circle", { cx: "4", cy: "4", r: "2", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })),
2171
+ youtube: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement("rect", { x: "2", y: "5", width: "20", height: "14", rx: "3", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react11.default.createElement("polygon", { points: "10,9 16,12 10,15", fill: "currentColor" }))
2172
+ };
2173
+ const links = [
2174
+ {
2175
+ href: formatUrl(twitter, "twitter"),
2176
+ label: "X (Twitter)",
2177
+ icon: platformIconMap.twitter
2178
+ },
2179
+ {
2180
+ href: formatUrl(facebook, "facebook"),
2181
+ label: "Facebook",
2182
+ icon: platformIconMap.facebook
2183
+ },
2184
+ {
2185
+ href: formatUrl(instagram, "instagram"),
2186
+ label: "Instagram",
2187
+ icon: platformIconMap.instagram
2188
+ },
2189
+ {
2190
+ href: formatUrl(linkedin, "linkedin"),
2191
+ label: "LinkedIn",
2192
+ icon: platformIconMap.linkedin
2193
+ },
2194
+ {
2195
+ href: website,
2196
+ label: "Website",
2197
+ icon: /* @__PURE__ */ import_react11.default.createElement("svg", { style: styles2.icon, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react11.default.createElement("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }), /* @__PURE__ */ import_react11.default.createElement(
2198
+ "path",
2199
+ {
2200
+ d: "M2 12H22M12 2C14.5 4.5 16 8 16 12C16 16 14.5 19.5 12 22C9.5 19.5 8 16 8 12C8 8 9.5 4.5 12 2Z",
2201
+ stroke: "currentColor",
2202
+ strokeWidth: "2",
2203
+ strokeLinecap: "round",
2204
+ strokeLinejoin: "round"
2205
+ }
2206
+ ))
2207
+ }
2208
+ ].filter((link) => link.href);
2209
+ extraLinks.forEach((url) => {
2210
+ const detected = SOCIAL_PLATFORMS.find(({ test }) => test.test(url));
2211
+ if (detected && platformIconMap[detected.platform]) {
2212
+ const alreadyPresent = links.some(
2213
+ (l) => l.href === url || l.href && l.href.includes(detected.platform)
2214
+ );
2215
+ if (!alreadyPresent) {
2216
+ links.push({
2217
+ href: url,
2218
+ label: detected.platform.charAt(0).toUpperCase() + detected.platform.slice(1),
2219
+ icon: platformIconMap[detected.platform]
2220
+ });
2221
+ }
2222
+ }
2223
+ });
2224
+ if (links.length === 0) {
2225
+ return null;
2226
+ }
2227
+ return /* @__PURE__ */ import_react11.default.createElement("div", { style: styles2.container, className: "ev-social-links" }, links.map((link) => /* @__PURE__ */ import_react11.default.createElement(
2228
+ "a",
2229
+ {
2230
+ key: link.label,
2231
+ href: link.href,
2232
+ target: "_blank",
2233
+ rel: "noopener noreferrer",
2234
+ style: styles2.link,
2235
+ "aria-label": link.label,
2236
+ onMouseEnter: (e) => {
2237
+ e.currentTarget.style.color = colors.evTeal;
2238
+ e.currentTarget.style.borderColor = colors.evTeal;
2239
+ },
2240
+ onMouseLeave: (e) => {
2241
+ e.currentTarget.style.color = "#6A7282";
2242
+ e.currentTarget.style.borderColor = "#E5E7EB";
2243
+ }
2244
+ },
2245
+ link.icon
2246
+ )));
2247
+ }
2248
+
2249
+ // src/IssueTags.jsx
2250
+ var import_react12 = __toESM(require("react"));
2251
+ function IssueTags({
2252
+ tags = [],
2253
+ selectedTags = [],
2254
+ onTagClick,
2255
+ variant = "default",
2256
+ style = {}
2257
+ }) {
2258
+ const isSelectable = variant === "selectable";
2259
+ const styles2 = {
2260
+ container: {
2261
+ display: "flex",
2262
+ flexWrap: "wrap",
2263
+ gap: spacing[2],
2264
+ ...style
2265
+ },
2266
+ tag: (isSelected) => ({
2267
+ display: "inline-flex",
2268
+ alignItems: "center",
2269
+ padding: `${spacing[2]} ${spacing[4]}`,
2270
+ borderRadius: borderRadius.full,
2271
+ fontFamily: fonts.primary,
2272
+ fontWeight: fontWeights.medium,
2273
+ fontSize: fontSizes.sm,
2274
+ border: `1px solid ${isSelected ? colors.evTeal : colors.borderMedium}`,
2275
+ backgroundColor: isSelected ? colors.evTeal : colors.bgWhite,
2276
+ color: isSelected ? colors.textWhite : colors.textPrimary,
2277
+ cursor: onTagClick ? "pointer" : "default",
2278
+ transition: "all 0.2s ease",
2279
+ userSelect: "none"
2280
+ })
2281
+ };
2282
+ const handleTagClick = (tag) => {
2283
+ if (onTagClick) {
2284
+ onTagClick(tag.value);
2285
+ }
2286
+ };
2287
+ const handleKeyDown = (e, tag) => {
2288
+ if (onTagClick && (e.key === "Enter" || e.key === " ")) {
2289
+ e.preventDefault();
2290
+ onTagClick(tag.value);
2291
+ }
2292
+ };
2293
+ return /* @__PURE__ */ import_react12.default.createElement("div", { style: styles2.container, className: "ev-issue-tags", role: "list" }, tags.map((tag) => {
2294
+ const isSelected = selectedTags.includes(tag.value);
2295
+ return /* @__PURE__ */ import_react12.default.createElement(
2296
+ "span",
2297
+ {
2298
+ key: tag.value,
2299
+ style: styles2.tag(isSelected),
2300
+ onClick: () => handleTagClick(tag),
2301
+ onKeyDown: (e) => handleKeyDown(e, tag),
2302
+ onMouseEnter: (e) => {
2303
+ if (onTagClick && !isSelected) {
2304
+ e.currentTarget.style.borderColor = colors.evTeal;
2305
+ e.currentTarget.style.color = colors.evTeal;
2306
+ }
2307
+ },
2308
+ onMouseLeave: (e) => {
2309
+ if (onTagClick && !isSelected) {
2310
+ e.currentTarget.style.borderColor = colors.borderMedium;
2311
+ e.currentTarget.style.color = colors.textPrimary;
2312
+ }
2313
+ },
2314
+ role: "listitem",
2315
+ tabIndex: onTagClick ? 0 : void 0,
2316
+ "aria-pressed": isSelectable ? isSelected : void 0
2317
+ },
2318
+ tag.label
2319
+ );
2320
+ }));
2321
+ }
2322
+
2323
+ // src/CommitteeTable.jsx
2324
+ var import_react13 = __toESM(require("react"));
2325
+ var ROLE_ORDER = {
2326
+ "chair": 0,
2327
+ "co-chair": 1,
2328
+ "vice chair": 2,
2329
+ "vice-chair": 2,
2330
+ "ranking member": 3,
2331
+ "member": 4
2332
+ };
2333
+ function getRoleRank(position) {
2334
+ if (!position) return 99;
2335
+ const lower = formatPosition(position).toLowerCase();
2336
+ for (const [key, rank] of Object.entries(ROLE_ORDER)) {
2337
+ if (lower.includes(key)) return rank;
2338
+ }
2339
+ return 99;
2340
+ }
2341
+ function formatPosition(position) {
2342
+ if (!position) return "";
2343
+ return position.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
2344
+ }
2345
+ function CommitteeTable({
2346
+ committees = [],
2347
+ title = "Committee Memberships",
2348
+ maxVisible = 6,
2349
+ style = {}
2350
+ }) {
2351
+ const [showAll, setShowAll] = (0, import_react13.useState)(false);
2352
+ if (committees.length === 0) {
2353
+ return null;
2354
+ }
2355
+ const sorted = [...committees].sort((a, b) => getRoleRank(a.position) - getRoleRank(b.position));
2356
+ const visible = showAll ? sorted : sorted.slice(0, maxVisible);
2357
+ const hasMore = sorted.length > maxVisible;
2358
+ const styles2 = {
2359
+ container: {
2360
+ ...style
2361
+ },
2362
+ heading: {
2363
+ display: "flex",
2364
+ alignItems: "center",
2365
+ gap: spacing[2],
2366
+ fontFamily: fonts.primary,
2367
+ fontWeight: fontWeights.semibold,
2368
+ fontSize: "18px",
2369
+ color: "#101828",
2370
+ margin: 0,
2371
+ marginBottom: spacing[3]
2372
+ },
2373
+ table: {
2374
+ width: "100%",
2375
+ borderCollapse: "collapse"
2376
+ },
2377
+ row: {
2378
+ borderBottom: "1px solid #F3F4F6"
2379
+ },
2380
+ cell: {
2381
+ padding: `${spacing[2]} 0`,
2382
+ fontFamily: fonts.primary,
2383
+ fontSize: "14px",
2384
+ verticalAlign: "top"
2385
+ },
2386
+ nameCell: {
2387
+ color: "#364153",
2388
+ paddingRight: spacing[4]
2389
+ },
2390
+ positionCell: {
2391
+ color: "#6A7282",
2392
+ textAlign: "right",
2393
+ whiteSpace: "nowrap"
2394
+ },
2395
+ link: {
2396
+ color: "#364153",
2397
+ textDecoration: "none"
2398
+ },
2399
+ toggle: {
2400
+ display: "inline-flex",
2401
+ alignItems: "center",
2402
+ gap: spacing[1],
2403
+ fontFamily: fonts.primary,
2404
+ fontSize: "14px",
2405
+ fontWeight: fontWeights.medium,
2406
+ color: "#6A7282",
2407
+ background: "none",
2408
+ border: "none",
2409
+ padding: `${spacing[2]} 0`,
2410
+ cursor: "pointer"
2411
+ }
2412
+ };
2413
+ return /* @__PURE__ */ import_react13.default.createElement("div", { style: styles2.container, className: "ev-committee-table" }, /* @__PURE__ */ import_react13.default.createElement("h4", { style: styles2.heading }, /* @__PURE__ */ import_react13.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react13.default.createElement("path", { d: "M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" }), /* @__PURE__ */ import_react13.default.createElement("circle", { cx: "9", cy: "7", r: "4" }), /* @__PURE__ */ import_react13.default.createElement("path", { d: "M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75" })), title), /* @__PURE__ */ import_react13.default.createElement("table", { style: styles2.table }, /* @__PURE__ */ import_react13.default.createElement("tbody", null, visible.map((committee, index) => /* @__PURE__ */ import_react13.default.createElement("tr", { key: index, style: styles2.row }, /* @__PURE__ */ import_react13.default.createElement("td", { style: { ...styles2.cell, ...styles2.nameCell } }, committee.url ? /* @__PURE__ */ import_react13.default.createElement(
2414
+ "a",
2415
+ {
2416
+ href: committee.url,
2417
+ target: "_blank",
2418
+ rel: "noopener noreferrer",
2419
+ style: styles2.link,
2420
+ onMouseEnter: (e) => {
2421
+ e.currentTarget.style.textDecoration = "underline";
2422
+ },
2423
+ onMouseLeave: (e) => {
2424
+ e.currentTarget.style.textDecoration = "none";
2425
+ }
2426
+ },
2427
+ committee.name
2428
+ ) : committee.name), /* @__PURE__ */ import_react13.default.createElement("td", { style: { ...styles2.cell, ...styles2.positionCell } }, formatPosition(committee.position)))))), hasMore && /* @__PURE__ */ import_react13.default.createElement(
2429
+ "button",
2430
+ {
2431
+ type: "button",
2432
+ style: styles2.toggle,
2433
+ onClick: () => setShowAll(!showAll)
2434
+ },
2435
+ showAll ? "Show less" : `Show all ${sorted.length} committees`,
2436
+ /* @__PURE__ */ import_react13.default.createElement(
2437
+ "svg",
2438
+ {
2439
+ width: "14",
2440
+ height: "14",
2441
+ viewBox: "0 0 24 24",
2442
+ fill: "none",
2443
+ stroke: "currentColor",
2444
+ strokeWidth: "2",
2445
+ strokeLinecap: "round",
2446
+ strokeLinejoin: "round",
2447
+ style: { transform: showAll ? "rotate(180deg)" : "none", transition: "transform 0.2s" }
2448
+ },
2449
+ /* @__PURE__ */ import_react13.default.createElement("polyline", { points: "6 9 12 15 18 9" })
2450
+ )
2451
+ ));
2452
+ }
2453
+
2454
+ // src/PoliticianProfile.jsx
2455
+ var import_react16 = __toESM(require("react"));
2456
+
2457
+ // src/LegislativeInlineSummary.jsx
2458
+ var import_react14 = __toESM(require("react"));
2459
+ function normalizePosition(pos) {
2460
+ if (!pos) return "";
2461
+ return pos.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2462
+ }
2463
+ function deriveAttendance(votes) {
2464
+ if (!votes || votes.length === 0) return null;
2465
+ const present = votes.filter((v) => {
2466
+ const norm = normalizePosition(v.position);
2467
+ return norm !== "Not Voting" && norm !== "Absent";
2468
+ }).length;
2469
+ return Math.round(present / votes.length * 100);
2470
+ }
2471
+ function getMostRecentAction(bills, votes) {
2472
+ const items = [];
2473
+ (bills || []).forEach((b) => {
2474
+ if (b.introduced_at) {
2475
+ items.push({
2476
+ date: b.introduced_at,
2477
+ text: `${b.number}: ${b.title} \u2014 ${b.status_label}`
2478
+ });
2479
+ }
2480
+ });
2481
+ (votes || []).forEach((v) => {
2482
+ if (v.vote_date) {
2483
+ const topic = v.bill_title || v.vote_question;
2484
+ const normPos = normalizePosition(v.position);
2485
+ items.push({
2486
+ date: v.vote_date,
2487
+ text: `Voted ${normPos} on ${topic} \u2014 ${v.result}`
2488
+ });
2489
+ }
2490
+ });
2491
+ if (items.length === 0) return null;
2492
+ items.sort((a, b) => a.date < b.date ? 1 : -1);
2493
+ return items[0].text;
2494
+ }
2495
+ function LegislativeInlineSummary({ summary, politicianId, onNavigateToRecord }) {
2496
+ const isMobile = useMediaQuery("(max-width: 768px)");
2497
+ if (!summary) return null;
2498
+ const bills = summary.recent_bills || [];
2499
+ const votes = summary.recent_votes || [];
2500
+ if (bills.length === 0 && votes.length === 0) return null;
2501
+ const attendancePct = deriveAttendance(votes);
2502
+ const billsAdvanced = bills.length > 0 ? bills.length : null;
2503
+ const mostRecentAction = getMostRecentAction(bills, votes);
2504
+ const stats = [];
2505
+ if (attendancePct !== null) {
2506
+ stats.push({ value: `Voted in ${attendancePct}% of roll calls`, label: null });
2507
+ }
2508
+ if (billsAdvanced !== null) {
2509
+ const billLabel = billsAdvanced === 1 ? "Authored 1 bill that advanced past introduction" : `Authored ${billsAdvanced} bills that advanced past introduction`;
2510
+ stats.push({ value: billLabel, label: null });
2511
+ }
2512
+ const recordHref = "/politician/" + politicianId + "/record";
2513
+ const card = {
2514
+ borderTop: `1px solid ${colors.borderLight}`,
2515
+ padding: `${spacing[4]} ${spacing[4]} 0`,
2516
+ marginTop: spacing[4],
2517
+ fontFamily: fonts.primary
2518
+ };
2519
+ const statsRow = {
2520
+ display: "flex",
2521
+ flexDirection: isMobile ? "column" : "row",
2522
+ gap: isMobile ? spacing[2] : spacing[6],
2523
+ marginBottom: mostRecentAction ? spacing[3] : spacing[2],
2524
+ alignItems: isMobile ? "flex-start" : "center"
2525
+ };
2526
+ const statItem = {
2527
+ display: "inline-flex",
2528
+ alignItems: "baseline",
2529
+ gap: spacing[1]
2530
+ };
2531
+ const statValue = {
2532
+ fontFamily: fonts.primary,
2533
+ fontSize: fontSizes.sm,
2534
+ fontWeight: fontWeights.semibold,
2535
+ color: colors.evTeal
2536
+ };
2537
+ const statLabel = {
2538
+ fontFamily: fonts.primary,
2539
+ fontSize: fontSizes.sm,
2540
+ fontWeight: fontWeights.regular,
2541
+ color: colors.textSecondary
2542
+ };
2543
+ const actionLine = {
2544
+ fontFamily: fonts.primary,
2545
+ fontSize: fontSizes.xs,
2546
+ color: colors.textSecondary,
2547
+ whiteSpace: "nowrap",
2548
+ overflow: "hidden",
2549
+ textOverflow: "ellipsis",
2550
+ marginBottom: spacing[3]
2551
+ };
2552
+ const footerRow = {
2553
+ display: "flex",
2554
+ justifyContent: "flex-end"
2555
+ };
2556
+ const recordLink = {
2557
+ display: "inline-flex",
2558
+ alignItems: "center",
2559
+ gap: spacing[1],
2560
+ color: colors.evTeal,
2561
+ textDecoration: "none",
2562
+ fontFamily: fonts.primary,
2563
+ fontSize: fontSizes.sm,
2564
+ fontWeight: fontWeights.medium
2565
+ };
2566
+ return /* @__PURE__ */ import_react14.default.createElement("div", { style: card }, stats.length > 0 && /* @__PURE__ */ import_react14.default.createElement("div", { style: statsRow }, stats.map((s, i) => /* @__PURE__ */ import_react14.default.createElement("div", { key: i, style: statItem }, /* @__PURE__ */ import_react14.default.createElement("span", { style: statValue }, s.value), s.label && /* @__PURE__ */ import_react14.default.createElement("span", { style: statLabel }, s.label)))), mostRecentAction && /* @__PURE__ */ import_react14.default.createElement("div", { style: actionLine, title: mostRecentAction }, mostRecentAction), /* @__PURE__ */ import_react14.default.createElement("div", null), /* @__PURE__ */ import_react14.default.createElement("div", { style: footerRow }, /* @__PURE__ */ import_react14.default.createElement(
2567
+ "button",
2568
+ {
2569
+ onClick: () => {
2570
+ if (onNavigateToRecord) {
2571
+ onNavigateToRecord(recordHref);
2572
+ } else {
2573
+ window.location.href = recordHref;
2574
+ }
2575
+ },
2576
+ style: {
2577
+ ...recordLink,
2578
+ border: "none",
2579
+ background: "none",
2580
+ cursor: "pointer",
2581
+ padding: 0
2582
+ },
2583
+ onMouseEnter: (e) => {
2584
+ e.currentTarget.style.textDecoration = "underline";
2585
+ },
2586
+ onMouseLeave: (e) => {
2587
+ e.currentTarget.style.textDecoration = "none";
2588
+ }
2589
+ },
2590
+ "View Full Legislative Record",
2591
+ /* @__PURE__ */ import_react14.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true" }, /* @__PURE__ */ import_react14.default.createElement("path", { d: "M9 18l6-6-6-6" }))
2592
+ )));
2593
+ }
2594
+
2595
+ // src/JudicialScorecard.jsx
2596
+ var import_react15 = __toESM(require("react"));
2597
+
2598
+ // src/judicialUtils.js
2599
+ function formatDate(dateStr) {
2600
+ if (!dateStr) return "";
2601
+ const cleaned = dateStr.replace(/T.*$/, "");
2602
+ const parts = cleaned.split("-");
2603
+ if (parts.length === 2) {
2604
+ const d2 = /* @__PURE__ */ new Date(`${cleaned}-01T12:00:00`);
2605
+ if (isNaN(d2.getTime())) return dateStr;
2606
+ return d2.toLocaleDateString("en-US", { month: "long", year: "numeric" });
2607
+ }
2608
+ const d = /* @__PURE__ */ new Date(`${cleaned}T12:00:00`);
2609
+ if (isNaN(d.getTime())) return dateStr;
2610
+ return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
2611
+ }
2612
+ var METRIC_LABELS = {
2613
+ reversal_rate: "Reversal Rate",
2614
+ caseload_volume: "Cases Handled",
2615
+ avg_disposition_days: "Avg. Days to Resolve",
2616
+ retention_vote_pct: "Last Retention Vote"
2617
+ };
2618
+ function formatMetricValue(type, value) {
2619
+ if (type === "reversal_rate" || type === "retention_vote_pct") return `${value}%`;
2620
+ if (type === "avg_disposition_days") return `${Math.round(value)} days`;
2621
+ if (type === "caseload_volume") return Math.round(value).toLocaleString();
2622
+ return String(value);
2623
+ }
2624
+
2625
+ // src/JudicialScorecard.jsx
2626
+ var sectionStyle = {
2627
+ fontFamily: "'Manrope', sans-serif",
2628
+ borderTop: "1px solid #e2e8f0",
2629
+ paddingTop: "24px",
2630
+ marginTop: "24px"
2631
+ };
2632
+ var headingStyle = {
2633
+ fontSize: "16px",
2634
+ fontWeight: 700,
2635
+ color: "#2d3748",
2636
+ marginBottom: "16px"
2637
+ };
2638
+ var cardGridStyle = {
2639
+ display: "grid",
2640
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
2641
+ gap: "12px",
2642
+ marginBottom: "16px"
2643
+ };
2644
+ var metricCardStyle = {
2645
+ backgroundColor: "#f7fafc",
2646
+ borderRadius: "8px",
2647
+ padding: "14px 16px",
2648
+ border: "1px solid #e2e8f0"
2649
+ };
2650
+ var metricValueStyle = {
2651
+ fontSize: "22px",
2652
+ fontWeight: 700,
2653
+ color: "#2d3748",
2654
+ lineHeight: 1.2
2655
+ };
2656
+ var metricLabelStyle = {
2657
+ fontSize: "12px",
2658
+ fontWeight: 600,
2659
+ color: "#718096",
2660
+ textTransform: "uppercase",
2661
+ letterSpacing: "0.5px",
2662
+ marginBottom: "4px"
2663
+ };
2664
+ var metricContextStyle = {
2665
+ fontSize: "12px",
2666
+ color: "#a0aec0",
2667
+ marginTop: "4px"
2668
+ };
2669
+ var evalChipStyle = {
2670
+ display: "inline-flex",
2671
+ alignItems: "center",
2672
+ gap: "6px",
2673
+ backgroundColor: "#ebf8ff",
2674
+ color: "#2b6cb0",
2675
+ borderRadius: "6px",
2676
+ padding: "6px 12px",
2677
+ fontSize: "13px",
2678
+ fontWeight: 600,
2679
+ marginRight: "8px",
2680
+ marginBottom: "8px"
2681
+ };
2682
+ var disciplinaryStyle = {
2683
+ borderLeft: "3px solid #fc8181",
2684
+ backgroundColor: "#fff5f5",
2685
+ borderRadius: "0 6px 6px 0",
2686
+ padding: "10px 14px",
2687
+ marginBottom: "8px",
2688
+ fontSize: "13px",
2689
+ color: "#742a2a"
2690
+ };
2691
+ var linkStyle = {
2692
+ display: "inline-flex",
2693
+ alignItems: "center",
2694
+ gap: "4px",
2695
+ color: "#319795",
2696
+ fontSize: "14px",
2697
+ fontWeight: 600,
2698
+ textDecoration: "none",
2699
+ marginTop: "8px",
2700
+ cursor: "pointer"
2701
+ };
2702
+ function JudicialScorecard({ judicialRecord, politicianId, onNavigateToRecord }) {
2703
+ if (!judicialRecord) return null;
2704
+ const { evaluations = [], metrics = [], disciplinary_records: disciplinary = [] } = judicialRecord;
2705
+ if (evaluations.length === 0 && metrics.length === 0 && disciplinary.length === 0) {
2706
+ return null;
2707
+ }
2708
+ const handleNavigate = (e) => {
2709
+ e.preventDefault();
2710
+ if (onNavigateToRecord) {
2711
+ onNavigateToRecord(`/politician/${politicianId}/judicial-record`);
2712
+ }
2713
+ };
2714
+ return /* @__PURE__ */ import_react15.default.createElement("section", { style: sectionStyle }, /* @__PURE__ */ import_react15.default.createElement("h3", { style: headingStyle }, "Judicial Record"), evaluations.length > 0 && /* @__PURE__ */ import_react15.default.createElement("div", { style: { marginBottom: "16px" } }, evaluations.slice(0, 3).map((ev, i) => /* @__PURE__ */ import_react15.default.createElement("span", { key: i, style: evalChipStyle }, ev.rating, /* @__PURE__ */ import_react15.default.createElement("span", { style: { fontWeight: 400, color: "#4a90a4", fontSize: "11px" } }, "\u2014 ", ev.source)))), metrics.length > 0 && /* @__PURE__ */ import_react15.default.createElement("div", { style: cardGridStyle }, metrics.slice(0, 4).map((m, i) => /* @__PURE__ */ import_react15.default.createElement("div", { key: i, style: metricCardStyle }, /* @__PURE__ */ import_react15.default.createElement("div", { style: metricLabelStyle }, METRIC_LABELS[m.metric_type] || m.metric_type.replace(/_/g, " ")), /* @__PURE__ */ import_react15.default.createElement("div", { style: metricValueStyle }, formatMetricValue(m.metric_type, m.value)), m.context_label && /* @__PURE__ */ import_react15.default.createElement("div", { style: metricContextStyle }, m.context_label)))), disciplinary.length > 0 && /* @__PURE__ */ import_react15.default.createElement("div", { style: { marginBottom: "12px" } }, disciplinary.slice(0, 2).map((d, i) => /* @__PURE__ */ import_react15.default.createElement("div", { key: i, style: disciplinaryStyle }, /* @__PURE__ */ import_react15.default.createElement("strong", null, d.record_type), " \u2014 ", formatDate(d.record_date), d.description && /* @__PURE__ */ import_react15.default.createElement("div", { style: { marginTop: "4px" } }, d.description)))), /* @__PURE__ */ import_react15.default.createElement("a", { href: `/politician/${politicianId}/judicial-record`, onClick: handleNavigate, style: linkStyle }, "View Full Judicial Record \u2192"));
2715
+ }
2716
+
2717
+ // src/PoliticianProfile.jsx
2718
+ function formatTermDate(dateStr, precision) {
2719
+ if (!dateStr) return null;
2720
+ if (precision === "year") {
2721
+ const year = parseInt(dateStr, 10);
2722
+ if (!isNaN(year) && year > 1900 && year < 2100) return String(year);
2723
+ }
2724
+ const d = new Date(dateStr);
2725
+ if (isNaN(d.getTime())) return null;
2726
+ return d.toLocaleDateString("en-US", { month: "short", year: "numeric" });
2727
+ }
2728
+ function getTermLine(pol) {
2729
+ const precision = pol.term_date_precision;
2730
+ const start = formatTermDate(pol.term_start, precision);
2731
+ if (!start) return null;
2732
+ const end = formatTermDate(pol.term_end, precision);
2733
+ if (!end) return `Since ${start}`;
2734
+ return `${start} \u2013 ${end}`;
2735
+ }
2736
+ function stripRetain(s) {
2737
+ return (s || "").replace(/\s*\(Retain\s+.+?\?\)/, "");
2738
+ }
2739
+ function qualifyLocalTitle(baseTitle, pol) {
2740
+ if (!pol.government_name || !baseTitle) return baseTitle;
2741
+ const dt = pol.district_type || "";
2742
+ if (!dt.startsWith("LOCAL") && dt !== "COUNTY") return baseTitle;
2743
+ const gov = pol.government_name.split(",")[0].trim();
2744
+ const govCore = gov.replace(/^City of\s+/i, "").replace(/\s+County$/i, "").trim();
2745
+ if (govCore && baseTitle.toLowerCase().includes(govCore.toLowerCase())) return baseTitle;
2746
+ let prefix = dt === "COUNTY" ? gov : gov.replace(/^City of\s+/i, "");
2747
+ if (prefix.endsWith("County") && baseTitle.startsWith("County"))
2748
+ prefix = prefix.replace(/\s+County$/, "");
2749
+ return `${prefix} ${baseTitle}`;
2750
+ }
2751
+ function buildTitleAndSubtitle(pol) {
2752
+ const cleanTitle = stripRetain(pol.office_title);
2753
+ const cleanChamber = stripRetain(pol.chamber_name);
2754
+ const dashIdx = cleanTitle.lastIndexOf(" - ");
2755
+ const title = (() => {
2756
+ if (dashIdx > 0) return qualifyLocalTitle(cleanTitle.slice(0, dashIdx), pol);
2757
+ if (pol.district_type === "NATIONAL_JUDICIAL")
2758
+ return cleanTitle || cleanChamber;
2759
+ if (pol.district_type === "SCHOOL" && pol.government_name) {
2760
+ const schoolName = pol.government_name.split(",")[0];
2761
+ return cleanChamber ? `${schoolName} ${cleanChamber}` : schoolName;
2762
+ }
2763
+ if (/(_EXEC)$/.test(pol.district_type) || pol.district_type === "COUNTY")
2764
+ return qualifyLocalTitle(cleanTitle || cleanChamber, pol);
2765
+ return qualifyLocalTitle(cleanChamber || cleanTitle, pol);
2766
+ })();
2767
+ const subtitle = (() => {
2768
+ if (dashIdx > 0) return normalizeDistrictSubtitle(cleanTitle.slice(dashIdx + 3));
2769
+ if (pol.district_type === "NATIONAL_JUDICIAL")
2770
+ return cleanChamber || null;
2771
+ if (pol.district_id && /^[1-9]\d*$/.test(pol.district_id))
2772
+ return `District ${pol.district_id}`;
2773
+ if (pol.district_id === "0" && !/(_EXEC)$/.test(pol.district_type))
2774
+ return "At-Large";
2775
+ return null;
2776
+ })();
2777
+ return { title, subtitle };
2778
+ }
2779
+ function getTierLabel(districtType, officeTitle) {
2780
+ if (!districtType) return null;
2781
+ if (districtType.startsWith("NATIONAL")) return "FEDERAL";
2782
+ if (districtType.startsWith("STATE")) return "STATE";
2783
+ if (districtType === "JUDICIAL" && officeTitle) {
2784
+ const t = officeTitle.toLowerCase();
2785
+ if (t.includes("supreme court") || t.includes("appeals") || t.includes("tax court")) return "STATE";
2786
+ }
2787
+ return "LOCAL";
2788
+ }
2789
+ function getTierColors(tier) {
2790
+ switch (tier) {
2791
+ case "FEDERAL":
2792
+ return { bg: "#EFF6FF", text: "#1E40AF" };
2793
+ case "STATE":
2794
+ return { bg: "#F0FDF4", text: "#166534" };
2795
+ default:
2796
+ return { bg: "#FDF4FF", text: "#7E22CE" };
2797
+ }
2798
+ }
2799
+ function isLinkedInUrl(url) {
2800
+ if (!url) return false;
2801
+ try {
2802
+ const hostname = new URL(url).hostname.toLowerCase();
2803
+ return hostname.includes("linkedin.com");
2804
+ } catch {
2805
+ return url.toLowerCase().includes("linkedin.com");
2806
+ }
2807
+ }
2808
+ var SOCIAL_PLATFORMS2 = [
2809
+ { test: /facebook\.com/i, platform: "facebook" },
2810
+ { test: /twitter\.com|x\.com/i, platform: "twitter" },
2811
+ { test: /instagram\.com/i, platform: "instagram" },
2812
+ { test: /linkedin\.com/i, platform: "linkedin" },
2813
+ { test: /youtube\.com|youtu\.be/i, platform: "youtube" }
2814
+ ];
2815
+ function detectSocialPlatform(url) {
2816
+ if (!url) return null;
2817
+ for (const { test, platform } of SOCIAL_PLATFORMS2) {
2818
+ if (test.test(url)) return platform;
2819
+ }
2820
+ return null;
2821
+ }
2822
+ function extractDomain(url) {
2823
+ try {
2824
+ return new URL(url).hostname.replace(/^www\./, "");
2825
+ } catch {
2826
+ return url.replace(/^https?:\/\/(www\.)?/, "").split("/")[0];
2827
+ }
2828
+ }
2829
+ function extractLinkedIn(pol) {
2830
+ let linkedinUrl = null;
2831
+ const websites = [];
2832
+ (pol.urls || []).forEach((url) => {
2833
+ if (isLinkedInUrl(url)) {
2834
+ if (!linkedinUrl) linkedinUrl = url;
2835
+ } else {
2836
+ websites.push(url);
2837
+ }
2838
+ });
2839
+ (pol.contacts || []).forEach((c) => {
2840
+ if (c.website_url && c.website_url.trim()) {
2841
+ if (isLinkedInUrl(c.website_url)) {
2842
+ if (!linkedinUrl) linkedinUrl = c.website_url;
2843
+ }
2844
+ }
2845
+ });
2846
+ return { linkedinUrl, personWebsites: websites };
2847
+ }
2848
+ function capitalize(str) {
2849
+ if (!str) return str;
2850
+ return str.replace(/\b\w/g, (c) => c.toUpperCase());
2851
+ }
2852
+ function normalizeDistrictSubtitle(raw) {
2853
+ if (!raw) return raw;
2854
+ const match = raw.match(/(\d+)(?:st|nd|rd|th)\s+Congressional\s+District/i);
2855
+ if (match) return `District ${match[1]}`;
2856
+ return raw;
2857
+ }
2858
+ function formatAddress(addr) {
2859
+ const lines = [addr.address_1, addr.address_2, addr.address_3].filter(Boolean);
2860
+ const cityState = [addr.city, addr.state].filter(Boolean).join(", ");
2861
+ const cityStateZip = [cityState, addr.postal_code].filter(Boolean).join(" ");
2862
+ if (cityStateZip) lines.push(cityStateZip);
2863
+ return lines;
2864
+ }
2865
+ var CalendarIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), /* @__PURE__ */ import_react16.default.createElement("line", { x1: "16", y1: "2", x2: "16", y2: "6" }), /* @__PURE__ */ import_react16.default.createElement("line", { x1: "8", y1: "2", x2: "8", y2: "6" }), /* @__PURE__ */ import_react16.default.createElement("line", { x1: "3", y1: "10", x2: "21", y2: "10" }));
2866
+ var ClockIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react16.default.createElement("polyline", { points: "12 6 12 12 16 14" }));
2867
+ var MapPinIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" }), /* @__PURE__ */ import_react16.default.createElement("circle", { cx: "12", cy: "10", r: "3" }));
2868
+ var PhoneIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("path", { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07A19.5 19.5 0 013.07 10.8 19.79 19.79 0 01.07 2.18 2 2 0 012.02 0h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L6.09 7.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z" }));
2869
+ var MailIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("path", { d: "M4 4H20C21.1 4 22 4.9 22 6V18C22 19.1 21.1 20 20 20H4C2.9 20 2 19.1 2 18V6C2 4.9 2.9 4 4 4Z" }), /* @__PURE__ */ import_react16.default.createElement("path", { d: "M22 6L12 13L2 6" }));
2870
+ var GlobeIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react16.default.createElement("path", { d: "M2 12H22M12 2C14.5 4.5 16 8 16 12C16 16 14.5 19.5 12 22C9.5 19.5 8 16 8 12C8 8 9.5 4.5 12 2Z" }));
2871
+ var ExternalLinkIcon = ({ size = 16 }) => /* @__PURE__ */ import_react16.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }), /* @__PURE__ */ import_react16.default.createElement("polyline", { points: "15 3 21 3 21 9" }), /* @__PURE__ */ import_react16.default.createElement("line", { x1: "10", y1: "14", x2: "21", y2: "3" }));
2872
+ function PoliticianProfile({
2873
+ politician = {},
2874
+ onBack,
2875
+ backLabel,
2876
+ children,
2877
+ banner,
2878
+ // slot for injecting content inside the card after heroRow
2879
+ style = {},
2880
+ legislativeSummary,
2881
+ judicialRecord,
2882
+ politicianId,
2883
+ onNavigateToRecord,
2884
+ imageFocalPoint
2885
+ }) {
2886
+ const isMobile = useMediaQuery("(max-width: 768px)");
2887
+ const pol = politician;
2888
+ const displayName = pol.full_name || [pol.first_name, pol.last_name].filter(Boolean).join(" ") || "Unknown";
2889
+ const label = backLabel || displayName;
2890
+ const profileImageUrl = (() => {
2891
+ if (pol.images && pol.images.length > 0) {
2892
+ const defaultImg = pol.images.find((img) => img.type === "default");
2893
+ return defaultImg ? defaultImg.url : pol.images[0].url;
2894
+ }
2895
+ return pol.photo_origin_url;
2896
+ })();
2897
+ const initials = [pol.first_name, pol.last_name].filter(Boolean).map((n) => n[0]).join("");
2898
+ const [imgError, setImgError] = (0, import_react16.useState)(false);
2899
+ (0, import_react16.useEffect)(() => {
2900
+ setImgError(false);
2901
+ }, [profileImageUrl]);
2902
+ const getSocialHandle = (type) => {
2903
+ var _a;
2904
+ const identifier = (_a = pol.identifiers) == null ? void 0 : _a.find(
2905
+ (i) => {
2906
+ var _a2;
2907
+ return ((_a2 = i.identifier_type) == null ? void 0 : _a2.toUpperCase()) === type.toUpperCase();
2908
+ }
2909
+ );
2910
+ return identifier == null ? void 0 : identifier.identifier_value;
2911
+ };
2912
+ const twitter = getSocialHandle("TWITTER");
2913
+ const facebook = getSocialHandle("FACEBOOK");
2914
+ const instagram = getSocialHandle("INSTAGRAM");
2915
+ const { linkedinUrl, personWebsites } = extractLinkedIn(pol);
2916
+ const tier = getTierLabel(pol.district_type, pol.office_title);
2917
+ const tierColors2 = tier ? getTierColors(tier) : null;
2918
+ const { title: roleTitle, subtitle: roleSubtitle } = buildTitleAndSubtitle(pol);
2919
+ const roleLine = [roleTitle, roleSubtitle].filter(Boolean).join(" \u2013 ");
2920
+ const termLine = getTermLine(pol);
2921
+ const committees = (pol.committees || []).map((c) => {
2922
+ var _a;
2923
+ return {
2924
+ name: c.name,
2925
+ position: c.position,
2926
+ url: (_a = c.urls) == null ? void 0 : _a[0]
2927
+ };
2928
+ });
2929
+ const addresses = (pol.addresses || []).map((addr) => ({
2930
+ type: capitalize(addr.contact_type || addr.type || "office"),
2931
+ lines: formatAddress(addr)
2932
+ })).filter((a) => a.lines.length > 0);
2933
+ const phonesByType = {};
2934
+ const emailsByType = {};
2935
+ const allWebsites = [];
2936
+ const socialWebsiteUrls = [];
2937
+ (pol.contacts || []).forEach((c) => {
2938
+ const cType = capitalize(c.contact_type || "office");
2939
+ if (c.phone && c.phone.trim()) {
2940
+ if (!phonesByType[cType]) phonesByType[cType] = [];
2941
+ phonesByType[cType].push(c.phone.trim());
2942
+ }
2943
+ if (c.email && c.email.trim()) {
2944
+ if (!emailsByType[cType]) emailsByType[cType] = [];
2945
+ emailsByType[cType].push(c.email.trim());
2946
+ }
2947
+ if (c.website_url && c.website_url.trim() && !isLinkedInUrl(c.website_url)) {
2948
+ const url = c.website_url.trim();
2949
+ if (detectSocialPlatform(url)) {
2950
+ if (!socialWebsiteUrls.includes(url)) socialWebsiteUrls.push(url);
2951
+ } else {
2952
+ allWebsites.push(url);
2953
+ }
2954
+ }
2955
+ });
2956
+ (pol.email_addresses || []).forEach((email) => {
2957
+ if (email && email.trim()) {
2958
+ if (!emailsByType["General"]) emailsByType["General"] = [];
2959
+ if (!Object.values(emailsByType).flat().includes(email.trim())) {
2960
+ emailsByType["General"].push(email.trim());
2961
+ }
2962
+ }
2963
+ });
2964
+ personWebsites.forEach((url) => {
2965
+ if (detectSocialPlatform(url)) {
2966
+ if (!socialWebsiteUrls.includes(url)) socialWebsiteUrls.push(url);
2967
+ } else {
2968
+ if (!allWebsites.includes(url)) allWebsites.push(url);
2969
+ }
2970
+ });
2971
+ const hasAddresses = addresses.length > 0;
2972
+ const hasPhones = Object.keys(phonesByType).length > 0;
2973
+ const hasEmails = Object.values(emailsByType).some((emails) => emails.some((e) => e && e.trim()));
2974
+ const hasWebsites = allWebsites.length > 0;
2975
+ const hasWebsitesCol = hasWebsites || twitter || facebook || instagram || linkedinUrl || socialWebsiteUrls.length > 0;
2976
+ const hasContactInfo = hasAddresses || hasPhones || hasEmails || hasWebsitesCol;
2977
+ const hasSocial = twitter || facebook || instagram || linkedinUrl;
2978
+ const divider = {
2979
+ borderTop: "1px solid #E5E7EB",
2980
+ margin: `${spacing[6]} 0`
2981
+ };
2982
+ const sectionHeading = {
2983
+ display: "flex",
2984
+ alignItems: "center",
2985
+ gap: spacing[2],
2986
+ fontFamily: fonts.primary,
2987
+ fontWeight: fontWeights.semibold,
2988
+ fontSize: "18px",
2989
+ color: "#101828",
2990
+ margin: 0,
2991
+ marginBottom: spacing[4]
2992
+ };
2993
+ const styles2 = {
2994
+ container: {
2995
+ fontFamily: fonts.primary,
2996
+ ...style
2997
+ },
2998
+ backLink: {
2999
+ display: "inline-flex",
3000
+ alignItems: "center",
3001
+ gap: spacing[2],
3002
+ color: colors.evTeal,
3003
+ fontFamily: fonts.primary,
3004
+ fontWeight: fontWeights.medium,
3005
+ fontSize: fontSizes.base,
3006
+ textDecoration: "none",
3007
+ cursor: "pointer",
3008
+ marginBottom: spacing[6],
3009
+ background: "none",
3010
+ border: "none",
3011
+ padding: 0
3012
+ },
3013
+ card: {
3014
+ background: colors.bgWhite,
3015
+ borderRadius: borderRadius.lg,
3016
+ boxShadow: shadows.lg,
3017
+ padding: isMobile ? spacing[4] : spacing[8],
3018
+ marginBottom: spacing[8]
3019
+ },
3020
+ // Hero row
3021
+ heroRow: {
3022
+ display: "flex",
3023
+ flexDirection: isMobile ? "column" : "row",
3024
+ gap: isMobile ? spacing[4] : spacing[8],
3025
+ alignItems: isMobile ? "center" : "flex-start"
3026
+ },
3027
+ photoWrap: {
3028
+ width: isMobile ? "150px" : "192px",
3029
+ height: isMobile ? "150px" : "240px",
3030
+ flexShrink: 0
3031
+ },
3032
+ photo: {
3033
+ width: "100%",
3034
+ height: "100%",
3035
+ borderRadius: borderRadius.lg,
3036
+ objectFit: "cover",
3037
+ objectPosition: imageFocalPoint != null ? imageFocalPoint : "center 20%",
3038
+ background: colors.borderLight
3039
+ },
3040
+ placeholder: {
3041
+ width: "100%",
3042
+ height: "100%",
3043
+ borderRadius: borderRadius.lg,
3044
+ background: colors.evTeal,
3045
+ display: "flex",
3046
+ alignItems: "center",
3047
+ justifyContent: "center",
3048
+ color: "#ffffff",
3049
+ fontSize: isMobile ? fontSizes.xl : fontSizes["3xl"],
3050
+ fontWeight: fontWeights.bold
3051
+ },
3052
+ infoCol: {
3053
+ flex: 1,
3054
+ minWidth: 0,
3055
+ textAlign: isMobile ? "center" : "left"
3056
+ },
3057
+ tierBadge: tierColors2 ? {
3058
+ display: "inline-block",
3059
+ fontFamily: fonts.primary,
3060
+ fontWeight: fontWeights.semibold,
3061
+ fontSize: "11px",
3062
+ letterSpacing: "0.05em",
3063
+ color: tierColors2.text,
3064
+ background: tierColors2.bg,
3065
+ padding: "3px 10px",
3066
+ borderRadius: borderRadius.full,
3067
+ marginBottom: spacing[2]
3068
+ } : null,
3069
+ name: {
3070
+ fontFamily: fonts.primary,
3071
+ fontWeight: fontWeights.bold,
3072
+ fontSize: isMobile ? fontSizes["2xl"] : "30px",
3073
+ color: "#101828",
3074
+ margin: 0,
3075
+ marginBottom: spacing[1],
3076
+ lineHeight: 1.2
3077
+ },
3078
+ roleLine: {
3079
+ fontFamily: fonts.primary,
3080
+ fontWeight: fontWeights.regular,
3081
+ fontSize: isMobile ? fontSizes.base : fontSizes.lg,
3082
+ color: "#364153",
3083
+ margin: 0,
3084
+ marginBottom: spacing[1]
3085
+ },
3086
+ officeDesc: {
3087
+ fontFamily: fonts.primary,
3088
+ fontSize: fontSizes.base,
3089
+ color: "#6A7282",
3090
+ margin: 0,
3091
+ marginBottom: spacing[3],
3092
+ lineHeight: 1.5
3093
+ },
3094
+ metaRow: {
3095
+ display: "flex",
3096
+ alignItems: "center",
3097
+ gap: spacing[4],
3098
+ flexWrap: "wrap",
3099
+ marginBottom: spacing[4],
3100
+ justifyContent: isMobile ? "center" : "flex-start"
3101
+ },
3102
+ metaItem: {
3103
+ display: "inline-flex",
3104
+ alignItems: "center",
3105
+ gap: spacing[1],
3106
+ fontFamily: fonts.primary,
3107
+ fontSize: fontSizes.sm,
3108
+ color: "#6A7282"
3109
+ },
3110
+ submitBtn: {
3111
+ display: "inline-flex",
3112
+ alignItems: "center",
3113
+ gap: spacing[2],
3114
+ fontFamily: fonts.primary,
3115
+ fontWeight: fontWeights.semibold,
3116
+ fontSize: fontSizes.sm,
3117
+ color: "#ffffff",
3118
+ background: colors.evTeal,
3119
+ border: "none",
3120
+ borderRadius: borderRadius.md,
3121
+ padding: `${spacing[2]} ${spacing[5]}`,
3122
+ cursor: "pointer",
3123
+ textDecoration: "none",
3124
+ transition: "background 0.2s",
3125
+ marginBottom: spacing[3]
3126
+ },
3127
+ // Contact section
3128
+ contactGrid: {
3129
+ display: "grid",
3130
+ gridTemplateColumns: isMobile ? "1fr" : (() => {
3131
+ const cols = [];
3132
+ if (hasAddresses) cols.push("1fr");
3133
+ if (hasPhones) cols.push("140px");
3134
+ if (hasEmails) cols.push("minmax(180px, 1fr)");
3135
+ if (hasWebsitesCol) cols.push("1fr");
3136
+ return cols.join(" ");
3137
+ })(),
3138
+ gap: isMobile ? spacing[4] : spacing[6]
3139
+ },
3140
+ contactGroup: {
3141
+ minWidth: 0
3142
+ },
3143
+ contactLabel: {
3144
+ fontFamily: fonts.primary,
3145
+ fontWeight: fontWeights.semibold,
3146
+ fontSize: "11px",
3147
+ letterSpacing: "0.05em",
3148
+ textTransform: "uppercase",
3149
+ color: "#6A7282",
3150
+ margin: 0,
3151
+ marginBottom: spacing[1],
3152
+ display: "flex",
3153
+ alignItems: "center",
3154
+ gap: spacing[1]
3155
+ },
3156
+ contactValue: {
3157
+ fontFamily: fonts.primary,
3158
+ fontSize: fontSizes.sm,
3159
+ color: "#364153",
3160
+ lineHeight: 1.6,
3161
+ margin: 0,
3162
+ marginBottom: spacing[2]
3163
+ },
3164
+ contactLink: {
3165
+ color: "#364153",
3166
+ textDecoration: "none",
3167
+ wordBreak: "break-all"
3168
+ },
3169
+ contactSubLabel: {
3170
+ fontFamily: fonts.primary,
3171
+ fontWeight: fontWeights.medium,
3172
+ fontSize: "12px",
3173
+ color: "#9CA3AF",
3174
+ margin: 0,
3175
+ marginBottom: spacing[1]
3176
+ },
3177
+ // Coming soon
3178
+ comingSoon: {
3179
+ display: "inline-flex",
3180
+ alignItems: "center",
3181
+ gap: spacing[1],
3182
+ fontFamily: fonts.primary,
3183
+ fontSize: fontSizes.sm,
3184
+ color: "#6A7282",
3185
+ background: "#F3F4F6",
3186
+ padding: `${spacing[1]} ${spacing[3]}`,
3187
+ borderRadius: borderRadius.full
3188
+ }
3189
+ };
3190
+ return /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.container, className: "ev-politician-profile" }, onBack && /* @__PURE__ */ import_react16.default.createElement(
3191
+ "button",
3192
+ {
3193
+ type: "button",
3194
+ style: styles2.backLink,
3195
+ onClick: onBack,
3196
+ onMouseEnter: (e) => {
3197
+ e.currentTarget.style.textDecoration = "underline";
3198
+ },
3199
+ onMouseLeave: (e) => {
3200
+ e.currentTarget.style.textDecoration = "none";
3201
+ }
3202
+ },
3203
+ /* @__PURE__ */ import_react16.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react16.default.createElement("path", { d: "M15 19l-7-7 7-7" })),
3204
+ label
3205
+ ), /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.card }, /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.heroRow }, /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.photoWrap }, profileImageUrl && !imgError ? /* @__PURE__ */ import_react16.default.createElement(
3206
+ "img",
3207
+ {
3208
+ src: profileImageUrl,
3209
+ alt: `${displayName} portrait`,
3210
+ style: styles2.photo,
3211
+ onError: () => setImgError(true)
3212
+ }
3213
+ ) : /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.placeholder }, initials || "?")), /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.infoCol }, styles2.tierBadge && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.tierBadge }, tier), /* @__PURE__ */ import_react16.default.createElement("h1", { style: styles2.name }, displayName), banner, /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.roleLine }, roleLine), pol.office_description && /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.officeDesc }, pol.office_description), (termLine || pol.total_years_in_office > 0) && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.metaRow }, termLine && /* @__PURE__ */ import_react16.default.createElement("span", { style: styles2.metaItem }, /* @__PURE__ */ import_react16.default.createElement(CalendarIcon, { size: 14 }), termLine), pol.total_years_in_office > 0 && /* @__PURE__ */ import_react16.default.createElement("span", { style: styles2.metaItem }, /* @__PURE__ */ import_react16.default.createElement(ClockIcon, { size: 14 }), pol.total_years_in_office, " ", pol.total_years_in_office === 1 ? "year" : "years", " in office")), pol.web_form_url && /* @__PURE__ */ import_react16.default.createElement(
3214
+ "a",
3215
+ {
3216
+ href: pol.web_form_url,
3217
+ target: "_blank",
3218
+ rel: "noopener noreferrer",
3219
+ style: styles2.submitBtn,
3220
+ onMouseEnter: (e) => {
3221
+ e.currentTarget.style.background = colors.evTealDark;
3222
+ },
3223
+ onMouseLeave: (e) => {
3224
+ e.currentTarget.style.background = colors.evTeal;
3225
+ }
3226
+ },
3227
+ /* @__PURE__ */ import_react16.default.createElement(ExternalLinkIcon, { size: 14 }),
3228
+ "Submit a Message"
3229
+ ))), hasContactInfo && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { style: divider }), /* @__PURE__ */ import_react16.default.createElement("div", { style: sectionHeading }, /* @__PURE__ */ import_react16.default.createElement(MailIcon, { size: 20 }), "Contact Information"), /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.contactGrid }, hasAddresses && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.contactGroup }, /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.contactLabel }, /* @__PURE__ */ import_react16.default.createElement(MapPinIcon, { size: 12 }), "Addresses"), addresses.map((addr, i) => /* @__PURE__ */ import_react16.default.createElement("div", { key: `addr-${i}` }, /* @__PURE__ */ import_react16.default.createElement("p", { style: { ...styles2.contactSubLabel, ...i === 0 ? { marginTop: 0 } : { marginTop: spacing[2] } } }, addr.type), /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.contactValue }, addr.lines.map((line, j) => /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, { key: j }, line, j < addr.lines.length - 1 && /* @__PURE__ */ import_react16.default.createElement("br", null))))))), hasPhones && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.contactGroup }, /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.contactLabel }, /* @__PURE__ */ import_react16.default.createElement(PhoneIcon, { size: 12 }), "Phone"), Object.entries(phonesByType).map(([type, phones], i) => /* @__PURE__ */ import_react16.default.createElement("div", { key: `phone-${type}` }, /* @__PURE__ */ import_react16.default.createElement("p", { style: { ...styles2.contactSubLabel, ...i === 0 ? { marginTop: 0 } : { marginTop: spacing[2] } } }, type), phones.map((phone, j) => /* @__PURE__ */ import_react16.default.createElement("p", { key: j, style: styles2.contactValue }, /* @__PURE__ */ import_react16.default.createElement(
3230
+ "a",
3231
+ {
3232
+ href: `tel:${phone}`,
3233
+ style: styles2.contactLink,
3234
+ onMouseEnter: (e) => {
3235
+ e.currentTarget.style.textDecoration = "underline";
3236
+ },
3237
+ onMouseLeave: (e) => {
3238
+ e.currentTarget.style.textDecoration = "none";
3239
+ }
3240
+ },
3241
+ phone
3242
+ )))))), hasEmails && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.contactGroup }, /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.contactLabel }, /* @__PURE__ */ import_react16.default.createElement(MailIcon, { size: 12 }), "Email"), Object.entries(emailsByType).filter(([, emails]) => emails.some((e) => e && e.trim())).map(([type, emails], i) => /* @__PURE__ */ import_react16.default.createElement("div", { key: `email-${type}` }, /* @__PURE__ */ import_react16.default.createElement("p", { style: { ...styles2.contactSubLabel, ...i === 0 ? { marginTop: 0 } : { marginTop: spacing[2] } } }, type), emails.filter((e) => e && e.trim()).map((email, j) => /* @__PURE__ */ import_react16.default.createElement("p", { key: j, style: styles2.contactValue }, /* @__PURE__ */ import_react16.default.createElement(
3243
+ "a",
3244
+ {
3245
+ href: `mailto:${email}`,
3246
+ style: styles2.contactLink,
3247
+ onMouseEnter: (e) => {
3248
+ e.currentTarget.style.textDecoration = "underline";
3249
+ },
3250
+ onMouseLeave: (e) => {
3251
+ e.currentTarget.style.textDecoration = "none";
3252
+ }
3253
+ },
3254
+ email
3255
+ )))))), hasWebsitesCol && /* @__PURE__ */ import_react16.default.createElement("div", { style: styles2.contactGroup }, /* @__PURE__ */ import_react16.default.createElement("p", { style: styles2.contactLabel }, /* @__PURE__ */ import_react16.default.createElement(GlobeIcon, { size: 12 }), "Websites"), allWebsites.map((url, i) => /* @__PURE__ */ import_react16.default.createElement("p", { key: i, style: styles2.contactValue }, /* @__PURE__ */ import_react16.default.createElement(
3256
+ "a",
3257
+ {
3258
+ href: url,
3259
+ target: "_blank",
3260
+ rel: "noopener noreferrer",
3261
+ style: styles2.contactLink,
3262
+ onMouseEnter: (e) => {
3263
+ e.currentTarget.style.textDecoration = "underline";
3264
+ },
3265
+ onMouseLeave: (e) => {
3266
+ e.currentTarget.style.textDecoration = "none";
3267
+ }
3268
+ },
3269
+ extractDomain(url)
3270
+ ))), (hasSocial || socialWebsiteUrls.length > 0) && /* @__PURE__ */ import_react16.default.createElement(
3271
+ SocialLinks,
3272
+ {
3273
+ twitter,
3274
+ facebook,
3275
+ instagram,
3276
+ linkedin: linkedinUrl,
3277
+ extraLinks: socialWebsiteUrls,
3278
+ size: "sm",
3279
+ style: { marginTop: allWebsites.length > 0 ? "8px" : 0 }
3280
+ }
3281
+ )))), committees.length > 0 && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { style: divider }), /* @__PURE__ */ import_react16.default.createElement(CommitteeTable, { committees })), pol.is_judicial ? /* @__PURE__ */ import_react16.default.createElement(
3282
+ JudicialScorecard,
3283
+ {
3284
+ judicialRecord,
3285
+ politicianId,
3286
+ onNavigateToRecord
3287
+ }
3288
+ ) : /* @__PURE__ */ import_react16.default.createElement(
3289
+ LegislativeInlineSummary,
3290
+ {
3291
+ summary: legislativeSummary,
3292
+ politicianId,
3293
+ onNavigateToRecord
3294
+ }
3295
+ )), children);
3296
+ }
3297
+
3298
+ // src/LegislativeRecord.jsx
3299
+ var import_react17 = __toESM(require("react"));
3300
+ var DEFAULT_LIMIT = 25;
3301
+ function normalizeText(str) {
3302
+ if (!str) return "";
3303
+ return str.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
3304
+ }
3305
+ function extractYear(dateStr) {
3306
+ if (!dateStr || typeof dateStr !== "string") return null;
3307
+ const year = dateStr.slice(0, 4);
3308
+ return /^\d{4}$/.test(year) ? year : null;
3309
+ }
3310
+ function getYears(items, dateKey) {
3311
+ const yearSet = /* @__PURE__ */ new Set();
3312
+ items.forEach((item) => {
3313
+ const y = extractYear(item[dateKey]);
3314
+ if (y) yearSet.add(y);
3315
+ });
3316
+ return Array.from(yearSet).sort((a, b) => b.localeCompare(a));
3317
+ }
3318
+ function formatDate2(dateStr) {
3319
+ if (!dateStr) return "";
3320
+ const year = extractYear(dateStr);
3321
+ if (!year) return dateStr;
3322
+ const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
3323
+ const monthIdx = parseInt(dateStr.slice(5, 7), 10) - 1;
3324
+ const day = parseInt(dateStr.slice(8, 10), 10);
3325
+ if (isNaN(monthIdx) || monthIdx < 0 || monthIdx > 11) return year;
3326
+ if (isNaN(day)) return `${monthNames[monthIdx]} ${year}`;
3327
+ return `${monthNames[monthIdx]} ${day}, ${year}`;
3328
+ }
3329
+ var ROLE_BADGE_CONFIG = {
3330
+ chair: { label: "Chair", bg: colors.evCoral, text: colors.textWhite },
3331
+ vice_chair: { label: "Vice Chair", bg: colors.evTealLight, text: colors.textWhite },
3332
+ ranking_member: { label: "Ranking Member", bg: colors.evTeal, text: colors.textWhite },
3333
+ ex_officio: { label: "Ex Officio", bg: colors.textMuted, text: colors.textWhite },
3334
+ member: { label: "Member", bg: colors.borderMedium, text: colors.textSecondary }
3335
+ };
3336
+ function getRoleBadge(role) {
3337
+ const key = (role || "member").toLowerCase().replace(/\s+/g, "_");
3338
+ return ROLE_BADGE_CONFIG[key] || ROLE_BADGE_CONFIG.member;
3339
+ }
3340
+ function getStatusBadge(statusLabel) {
3341
+ const s = (statusLabel || "").toLowerCase();
3342
+ if (s === "became law") {
3343
+ return { bg: "#dcfce7", text: colors.success };
3344
+ }
3345
+ if (s === "vetoed") {
3346
+ return { bg: "#fee2e2", text: colors.error };
3347
+ }
3348
+ if (s === "passed house" || s === "passed senate") {
3349
+ return { bg: colors.bgLight, text: colors.evTeal };
3350
+ }
3351
+ if (s === "failed") {
3352
+ return { bg: colors.borderLight, text: colors.textMuted };
3353
+ }
3354
+ if (s === "introduced") {
3355
+ return { bg: colors.borderLight, text: colors.textMuted };
3356
+ }
3357
+ return { bg: colors.borderLight, text: colors.textSecondary };
3358
+ }
3359
+ function getPositionBadge(position) {
3360
+ const norm = normalizeText(position);
3361
+ if (norm === "Yea") {
3362
+ return { bg: "#bbf7d0", text: colors.success };
3363
+ }
3364
+ if (norm === "Nay") {
3365
+ return { bg: "#fecaca", text: colors.error };
3366
+ }
3367
+ if (norm === "Not Voting") {
3368
+ return { bg: colors.borderLight, text: colors.textMuted };
3369
+ }
3370
+ if (norm === "Abstain") {
3371
+ return { bg: colors.evYellowLight, text: colors.evYellowDark };
3372
+ }
3373
+ if (norm === "Absent") {
3374
+ return { bg: colors.borderLight, text: colors.textMuted };
3375
+ }
3376
+ return { bg: colors.borderLight, text: colors.textSecondary };
3377
+ }
3378
+ function Badge({ label, bg, text }) {
3379
+ return /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3380
+ display: "inline-block",
3381
+ background: bg,
3382
+ color: text,
3383
+ borderRadius: borderRadius.full,
3384
+ fontSize: fontSizes.xs,
3385
+ fontWeight: fontWeights.semibold,
3386
+ fontFamily: fonts.primary,
3387
+ padding: `${spacing[1]} ${spacing[3]}`,
3388
+ whiteSpace: "nowrap"
3389
+ } }, label);
3390
+ }
3391
+ function SectionHeader({ title, yearFilter, years, onYearChange }) {
3392
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3393
+ display: "flex",
3394
+ alignItems: "center",
3395
+ justifyContent: "space-between",
3396
+ marginBottom: spacing[4]
3397
+ } }, /* @__PURE__ */ import_react17.default.createElement("h2", { style: {
3398
+ fontFamily: fonts.primary,
3399
+ fontSize: fontSizes.xl,
3400
+ fontWeight: fontWeights.bold,
3401
+ color: colors.evTeal,
3402
+ margin: 0
3403
+ } }, title), years && years.length > 0 && /* @__PURE__ */ import_react17.default.createElement(
3404
+ "select",
3405
+ {
3406
+ value: yearFilter,
3407
+ onChange: (e) => onYearChange(e.target.value),
3408
+ style: {
3409
+ fontFamily: fonts.primary,
3410
+ fontSize: fontSizes.sm,
3411
+ color: colors.textSecondary,
3412
+ border: `1px solid ${colors.borderLight}`,
3413
+ borderRadius: borderRadius.md,
3414
+ padding: `${spacing[1]} ${spacing[2]}`,
3415
+ background: colors.bgWhite,
3416
+ cursor: "pointer"
3417
+ }
3418
+ },
3419
+ /* @__PURE__ */ import_react17.default.createElement("option", { value: "All" }, "All years"),
3420
+ years.map((y) => /* @__PURE__ */ import_react17.default.createElement("option", { key: y, value: y }, y))
3421
+ ));
3422
+ }
3423
+ function ShowAllLink({ totalCount, visibleCount, onClick }) {
3424
+ if (totalCount <= visibleCount) return null;
3425
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: { textAlign: "center", marginTop: spacing[3] } }, /* @__PURE__ */ import_react17.default.createElement(
3426
+ "button",
3427
+ {
3428
+ type: "button",
3429
+ onClick,
3430
+ style: {
3431
+ background: "none",
3432
+ border: "none",
3433
+ color: colors.evTeal,
3434
+ fontSize: fontSizes.sm,
3435
+ fontFamily: fonts.primary,
3436
+ fontWeight: fontWeights.medium,
3437
+ cursor: "pointer",
3438
+ padding: `${spacing[1]} ${spacing[2]}`
3439
+ },
3440
+ onMouseEnter: (e) => {
3441
+ e.currentTarget.style.textDecoration = "underline";
3442
+ },
3443
+ onMouseLeave: (e) => {
3444
+ e.currentTarget.style.textDecoration = "none";
3445
+ }
3446
+ },
3447
+ "Show all ",
3448
+ totalCount,
3449
+ " items"
3450
+ ));
3451
+ }
3452
+ function EmptyState({ message }) {
3453
+ return /* @__PURE__ */ import_react17.default.createElement("p", { style: {
3454
+ fontFamily: fonts.primary,
3455
+ fontSize: fontSizes.sm,
3456
+ color: colors.textMuted,
3457
+ fontStyle: "italic",
3458
+ margin: 0,
3459
+ padding: `${spacing[3]} 0`
3460
+ } }, message);
3461
+ }
3462
+ function Spinner() {
3463
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3464
+ display: "flex",
3465
+ justifyContent: "center",
3466
+ alignItems: "center",
3467
+ padding: spacing[10]
3468
+ } }, /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3469
+ width: "40px",
3470
+ height: "40px",
3471
+ borderRadius: borderRadius.full,
3472
+ border: `3px solid ${colors.borderLight}`,
3473
+ borderTopColor: colors.evTeal,
3474
+ animation: "ev-spin 0.8s linear infinite"
3475
+ } }), /* @__PURE__ */ import_react17.default.createElement("style", null, `@keyframes ev-spin { to { transform: rotate(360deg); } }`));
3476
+ }
3477
+ function CommitteesSection({ committees, leadership }) {
3478
+ const [showAll, setShowAll] = (0, import_react17.useState)(false);
3479
+ const visible = showAll ? committees : committees.slice(0, DEFAULT_LIMIT);
3480
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: { marginBottom: spacing[8] } }, /* @__PURE__ */ import_react17.default.createElement(SectionHeader, { title: "Committees & Leadership" }), leadership && leadership.length > 0 && /* @__PURE__ */ import_react17.default.createElement("div", { style: { display: "flex", flexWrap: "wrap", gap: spacing[2], marginBottom: spacing[4] } }, leadership.map((role, i) => /* @__PURE__ */ import_react17.default.createElement("div", { key: i, style: {
3481
+ display: "inline-flex",
3482
+ alignItems: "center",
3483
+ gap: spacing[1],
3484
+ background: colors.evCoral,
3485
+ color: colors.textWhite,
3486
+ borderRadius: borderRadius.md,
3487
+ padding: `${spacing[1]} ${spacing[3]}`,
3488
+ fontFamily: fonts.primary,
3489
+ fontSize: fontSizes.sm,
3490
+ fontWeight: fontWeights.semibold
3491
+ } }, role.title, role.chamber && /* @__PURE__ */ import_react17.default.createElement("span", { style: { fontWeight: fontWeights.regular, opacity: 0.85 } }, "(", role.chamber, ")")))), committees.length === 0 ? /* @__PURE__ */ import_react17.default.createElement(EmptyState, { message: "Committee information is not available for this office." }) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", null, visible.map((c, i) => {
3492
+ const badge = getRoleBadge(c.role);
3493
+ return /* @__PURE__ */ import_react17.default.createElement("div", { key: i, style: {
3494
+ display: "flex",
3495
+ alignItems: "center",
3496
+ justifyContent: "space-between",
3497
+ padding: `${spacing[3]} 0`,
3498
+ borderBottom: `1px solid ${colors.borderLight}`,
3499
+ gap: spacing[3]
3500
+ } }, /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3501
+ fontFamily: fonts.primary,
3502
+ fontSize: fontSizes.sm,
3503
+ color: colors.textSecondary,
3504
+ flex: 1,
3505
+ minWidth: 0
3506
+ } }, c.committee_name, c.parent_name && /* @__PURE__ */ import_react17.default.createElement("span", { style: { color: colors.textMuted, marginLeft: spacing[1] } }, "(", c.parent_name, ")")), /* @__PURE__ */ import_react17.default.createElement(Badge, { label: badge.label, bg: badge.bg, text: badge.text }));
3507
+ })), !showAll && /* @__PURE__ */ import_react17.default.createElement(
3508
+ ShowAllLink,
3509
+ {
3510
+ totalCount: committees.length,
3511
+ visibleCount: DEFAULT_LIMIT,
3512
+ onClick: () => setShowAll(true)
3513
+ }
3514
+ )));
3515
+ }
3516
+ function LegislationSection({ bills, isMobile }) {
3517
+ const years = getYears(bills, "introduced_at");
3518
+ const [yearFilter, setYearFilter] = (0, import_react17.useState)("All");
3519
+ const [showAll, setShowAll] = (0, import_react17.useState)(false);
3520
+ const handleYearChange = (y) => {
3521
+ setYearFilter(y);
3522
+ setShowAll(false);
3523
+ };
3524
+ const filtered = yearFilter === "All" ? bills : bills.filter((b) => extractYear(b.introduced_at) === yearFilter);
3525
+ const visible = showAll ? filtered : filtered.slice(0, DEFAULT_LIMIT);
3526
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: { marginBottom: spacing[8] } }, /* @__PURE__ */ import_react17.default.createElement(
3527
+ SectionHeader,
3528
+ {
3529
+ title: "Sponsored Legislation",
3530
+ yearFilter,
3531
+ years,
3532
+ onYearChange: handleYearChange
3533
+ }
3534
+ ), bills.length === 0 ? /* @__PURE__ */ import_react17.default.createElement(EmptyState, { message: "Sponsored legislation data is not available for this office." }) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", null, visible.map((bill, i) => {
3535
+ const statusBadge = getStatusBadge(bill.status_label);
3536
+ return /* @__PURE__ */ import_react17.default.createElement("div", { key: i, style: {
3537
+ display: "flex",
3538
+ flexDirection: isMobile ? "column" : "row",
3539
+ alignItems: isMobile ? "flex-start" : "center",
3540
+ gap: isMobile ? spacing[1] : spacing[3],
3541
+ padding: `${spacing[3]} 0`,
3542
+ borderBottom: `1px solid ${colors.borderLight}`
3543
+ } }, /* @__PURE__ */ import_react17.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3544
+ fontFamily: fonts.primary,
3545
+ fontSize: fontSizes.xs,
3546
+ fontWeight: fontWeights.bold,
3547
+ color: colors.textSecondary,
3548
+ marginRight: spacing[2]
3549
+ } }, bill.number), /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3550
+ fontFamily: fonts.primary,
3551
+ fontSize: fontSizes.sm,
3552
+ color: colors.textSecondary
3553
+ } }, bill.title)), /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3554
+ display: "flex",
3555
+ alignItems: "center",
3556
+ gap: spacing[2],
3557
+ flexShrink: 0,
3558
+ flexWrap: "wrap"
3559
+ } }, /* @__PURE__ */ import_react17.default.createElement(Badge, { label: bill.status_label || "Unknown", bg: statusBadge.bg, text: statusBadge.text }), bill.introduced_at && /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3560
+ fontFamily: fonts.primary,
3561
+ fontSize: fontSizes.xs,
3562
+ color: colors.textMuted
3563
+ } }, formatDate2(bill.introduced_at)), /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3564
+ fontFamily: fonts.primary,
3565
+ fontSize: fontSizes.xs,
3566
+ color: colors.textMuted,
3567
+ fontStyle: "italic"
3568
+ } }, bill.is_sponsor ? "Sponsored" : "Cosponsored")));
3569
+ })), !showAll && /* @__PURE__ */ import_react17.default.createElement(
3570
+ ShowAllLink,
3571
+ {
3572
+ totalCount: filtered.length,
3573
+ visibleCount: DEFAULT_LIMIT,
3574
+ onClick: () => setShowAll(true)
3575
+ }
3576
+ )));
3577
+ }
3578
+ function VotingSection({ votes, isMobile }) {
3579
+ const years = getYears(votes, "vote_date");
3580
+ const [yearFilter, setYearFilter] = (0, import_react17.useState)("All");
3581
+ const [showAll, setShowAll] = (0, import_react17.useState)(false);
3582
+ const handleYearChange = (y) => {
3583
+ setYearFilter(y);
3584
+ setShowAll(false);
3585
+ };
3586
+ const filtered = yearFilter === "All" ? votes : votes.filter((v) => extractYear(v.vote_date) === yearFilter);
3587
+ const visible = showAll ? filtered : filtered.slice(0, DEFAULT_LIMIT);
3588
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: { marginBottom: spacing[8] } }, /* @__PURE__ */ import_react17.default.createElement(
3589
+ SectionHeader,
3590
+ {
3591
+ title: "Voting Record",
3592
+ yearFilter,
3593
+ years,
3594
+ onYearChange: handleYearChange
3595
+ }
3596
+ ), votes.length === 0 ? /* @__PURE__ */ import_react17.default.createElement(EmptyState, { message: "Voting records are not available for this office." }) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", null, visible.map((vote, i) => {
3597
+ const positionBadge = getPositionBadge(vote.position);
3598
+ const normPosition = normalizeText(vote.position);
3599
+ const topic = vote.bill_title || vote.vote_question;
3600
+ const sourceUrl = vote.bill_url;
3601
+ return /* @__PURE__ */ import_react17.default.createElement("div", { key: i, style: {
3602
+ display: "flex",
3603
+ flexDirection: isMobile ? "column" : "row",
3604
+ alignItems: isMobile ? "flex-start" : "center",
3605
+ gap: isMobile ? spacing[1] : spacing[3],
3606
+ padding: `${spacing[3]} 0`,
3607
+ borderBottom: `1px solid ${colors.borderLight}`
3608
+ } }, /* @__PURE__ */ import_react17.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3609
+ fontFamily: fonts.primary,
3610
+ fontSize: fontSizes.sm,
3611
+ color: colors.textSecondary
3612
+ } }, topic)), /* @__PURE__ */ import_react17.default.createElement("div", { style: {
3613
+ display: "flex",
3614
+ alignItems: "center",
3615
+ gap: spacing[2],
3616
+ flexShrink: 0,
3617
+ flexWrap: "wrap"
3618
+ } }, vote.vote_date && /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3619
+ fontFamily: fonts.primary,
3620
+ fontSize: fontSizes.xs,
3621
+ color: colors.textMuted
3622
+ } }, formatDate2(vote.vote_date)), /* @__PURE__ */ import_react17.default.createElement(Badge, { label: normPosition || "Unknown", bg: positionBadge.bg, text: positionBadge.text }), vote.result && /* @__PURE__ */ import_react17.default.createElement("span", { style: {
3623
+ fontFamily: fonts.primary,
3624
+ fontSize: fontSizes.xs,
3625
+ color: vote.result === "Passed" ? colors.success : colors.textMuted,
3626
+ fontWeight: fontWeights.medium
3627
+ } }, vote.result), sourceUrl && /* @__PURE__ */ import_react17.default.createElement(
3628
+ "a",
3629
+ {
3630
+ href: sourceUrl,
3631
+ target: "_blank",
3632
+ rel: "noopener noreferrer",
3633
+ style: {
3634
+ fontFamily: fonts.primary,
3635
+ fontSize: fontSizes.xs,
3636
+ color: colors.evTeal,
3637
+ textDecoration: "none"
3638
+ },
3639
+ onMouseEnter: (e) => {
3640
+ e.currentTarget.style.textDecoration = "underline";
3641
+ },
3642
+ onMouseLeave: (e) => {
3643
+ e.currentTarget.style.textDecoration = "none";
3644
+ }
3645
+ },
3646
+ "Source"
3647
+ )));
3648
+ })), !showAll && /* @__PURE__ */ import_react17.default.createElement(
3649
+ ShowAllLink,
3650
+ {
3651
+ totalCount: filtered.length,
3652
+ visibleCount: DEFAULT_LIMIT,
3653
+ onClick: () => setShowAll(true)
3654
+ }
3655
+ )));
3656
+ }
3657
+ function LegislativeRecord({
3658
+ committees = [],
3659
+ leadership = [],
3660
+ bills = [],
3661
+ votes = [],
3662
+ loading = false,
3663
+ politicianName = ""
3664
+ }) {
3665
+ const isMobile = useMediaQuery("(max-width: 768px)");
3666
+ if (loading) {
3667
+ return /* @__PURE__ */ import_react17.default.createElement(Spinner, null);
3668
+ }
3669
+ return /* @__PURE__ */ import_react17.default.createElement("div", { style: { fontFamily: fonts.primary } }, politicianName && /* @__PURE__ */ import_react17.default.createElement("h1", { style: {
3670
+ fontFamily: fonts.primary,
3671
+ fontSize: isMobile ? fontSizes["2xl"] : fontSizes["4xl"],
3672
+ fontWeight: fontWeights.bold,
3673
+ color: colors.evTeal,
3674
+ marginBottom: spacing[8],
3675
+ marginTop: 0
3676
+ } }, "Legislative Record: ", politicianName), /* @__PURE__ */ import_react17.default.createElement(CommitteesSection, { committees, leadership }), /* @__PURE__ */ import_react17.default.createElement(LegislationSection, { bills, isMobile }), /* @__PURE__ */ import_react17.default.createElement(VotingSection, { votes, isMobile }));
3677
+ }
3678
+
3679
+ // src/JudicialRecordDetail.jsx
3680
+ var import_react18 = __toESM(require("react"));
3681
+ var containerStyle = {
3682
+ fontFamily: "'Manrope', sans-serif",
3683
+ maxWidth: "800px"
3684
+ };
3685
+ var backBtnStyle = {
3686
+ display: "inline-flex",
3687
+ alignItems: "center",
3688
+ gap: "4px",
3689
+ color: "#718096",
3690
+ fontSize: "14px",
3691
+ fontWeight: 600,
3692
+ cursor: "pointer",
3693
+ background: "none",
3694
+ border: "none",
3695
+ padding: "8px 0",
3696
+ marginBottom: "16px"
3697
+ };
3698
+ var nameStyle = {
3699
+ fontSize: "24px",
3700
+ fontWeight: 700,
3701
+ color: "#2d3748",
3702
+ marginBottom: "4px"
3703
+ };
3704
+ var roleStyle = {
3705
+ fontSize: "15px",
3706
+ color: "#718096",
3707
+ marginBottom: "24px"
3708
+ };
3709
+ var sectionHeadingStyle = {
3710
+ fontSize: "18px",
3711
+ fontWeight: 700,
3712
+ color: "#2d3748",
3713
+ marginTop: "32px",
3714
+ marginBottom: "12px",
3715
+ paddingBottom: "8px",
3716
+ borderBottom: "2px solid #e2e8f0"
3717
+ };
3718
+ var tableStyle = {
3719
+ width: "100%",
3720
+ borderCollapse: "collapse",
3721
+ fontSize: "14px"
3722
+ };
3723
+ var thStyle = {
3724
+ textAlign: "left",
3725
+ padding: "8px 12px",
3726
+ fontWeight: 600,
3727
+ color: "#718096",
3728
+ borderBottom: "1px solid #e2e8f0",
3729
+ fontSize: "12px",
3730
+ textTransform: "uppercase",
3731
+ letterSpacing: "0.5px"
3732
+ };
3733
+ var tdStyle = {
3734
+ padding: "10px 12px",
3735
+ borderBottom: "1px solid #f7fafc",
3736
+ color: "#2d3748"
3737
+ };
3738
+ var detailRowStyle = {
3739
+ display: "flex",
3740
+ gap: "8px",
3741
+ padding: "8px 0",
3742
+ borderBottom: "1px solid #f7fafc"
3743
+ };
3744
+ var detailLabelStyle = {
3745
+ fontWeight: 600,
3746
+ color: "#718096",
3747
+ minWidth: "160px",
3748
+ fontSize: "14px"
3749
+ };
3750
+ var detailValueStyle = {
3751
+ color: "#2d3748",
3752
+ fontSize: "14px"
3753
+ };
3754
+ var emptyStateStyle = {
3755
+ padding: "24px",
3756
+ backgroundColor: "#f7fafc",
3757
+ borderRadius: "8px",
3758
+ color: "#a0aec0",
3759
+ fontSize: "14px",
3760
+ textAlign: "center"
3761
+ };
3762
+ function JudicialRecordDetail({ politician = {}, judicialRecord, onBack }) {
3763
+ var _a;
3764
+ if (!judicialRecord) {
3765
+ return /* @__PURE__ */ import_react18.default.createElement("div", { style: containerStyle }, /* @__PURE__ */ import_react18.default.createElement("button", { style: backBtnStyle, onClick: onBack }, "\u2190 Back to Profile"), /* @__PURE__ */ import_react18.default.createElement("div", { style: emptyStateStyle }, "No judicial record data available."));
3766
+ }
3767
+ const {
3768
+ judge_detail: detail,
3769
+ evaluations = [],
3770
+ metrics = [],
3771
+ disciplinary_records: disciplinary = []
3772
+ } = judicialRecord;
3773
+ const displayName = politician.full_name || `${politician.first_name || ""} ${politician.last_name || ""}`.trim();
3774
+ return /* @__PURE__ */ import_react18.default.createElement("div", { style: containerStyle }, /* @__PURE__ */ import_react18.default.createElement("button", { style: backBtnStyle, onClick: onBack }, "\u2190 Back to Profile"), /* @__PURE__ */ import_react18.default.createElement("h1", { style: nameStyle }, displayName), /* @__PURE__ */ import_react18.default.createElement("p", { style: roleStyle }, (detail == null ? void 0 : detail.court_role) || politician.office_title, (detail == null ? void 0 : detail.date_seated) && ` \xB7 Seated ${formatDate(detail.date_seated)}`), detail && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("h2", { style: sectionHeadingStyle }, "Background"), detail.appointed_by && /* @__PURE__ */ import_react18.default.createElement("div", { style: detailRowStyle }, /* @__PURE__ */ import_react18.default.createElement("span", { style: detailLabelStyle }, "Appointed by"), /* @__PURE__ */ import_react18.default.createElement("span", { style: detailValueStyle }, detail.appointed_by, " (", detail.appointing_president_party, ")")), detail.confirmation_vote && /* @__PURE__ */ import_react18.default.createElement("div", { style: detailRowStyle }, /* @__PURE__ */ import_react18.default.createElement("span", { style: detailLabelStyle }, "Confirmation Vote"), /* @__PURE__ */ import_react18.default.createElement("span", { style: detailValueStyle }, detail.confirmation_vote)), detail.election_type && /* @__PURE__ */ import_react18.default.createElement("div", { style: detailRowStyle }, /* @__PURE__ */ import_react18.default.createElement("span", { style: detailLabelStyle }, "Election Type"), /* @__PURE__ */ import_react18.default.createElement("span", { style: detailValueStyle }, detail.election_type === "retention" ? "Retention (Yes/No)" : "Contested Election")), ((_a = detail.areas_of_focus) == null ? void 0 : _a.length) > 0 && /* @__PURE__ */ import_react18.default.createElement("div", { style: detailRowStyle }, /* @__PURE__ */ import_react18.default.createElement("span", { style: detailLabelStyle }, "Areas of Focus"), /* @__PURE__ */ import_react18.default.createElement("span", { style: detailValueStyle }, detail.areas_of_focus.join(", ")))), /* @__PURE__ */ import_react18.default.createElement("h2", { style: sectionHeadingStyle }, "Performance Evaluations"), evaluations.length === 0 ? /* @__PURE__ */ import_react18.default.createElement("div", { style: emptyStateStyle }, "No evaluation data available yet.") : /* @__PURE__ */ import_react18.default.createElement("table", { style: tableStyle }, /* @__PURE__ */ import_react18.default.createElement("thead", null, /* @__PURE__ */ import_react18.default.createElement("tr", null, /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Source"), /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Rating"), /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Date"))), /* @__PURE__ */ import_react18.default.createElement("tbody", null, evaluations.map((ev, i) => /* @__PURE__ */ import_react18.default.createElement("tr", { key: i }, /* @__PURE__ */ import_react18.default.createElement("td", { style: tdStyle }, ev.source_url ? /* @__PURE__ */ import_react18.default.createElement("a", { href: ev.source_url, target: "_blank", rel: "noopener noreferrer", style: { color: "#319795" } }, ev.source) : ev.source), /* @__PURE__ */ import_react18.default.createElement("td", { style: { ...tdStyle, fontWeight: 600 } }, ev.rating), /* @__PURE__ */ import_react18.default.createElement("td", { style: tdStyle }, formatDate(ev.rating_date)))))), /* @__PURE__ */ import_react18.default.createElement("h2", { style: sectionHeadingStyle }, "Performance Metrics"), metrics.length === 0 ? /* @__PURE__ */ import_react18.default.createElement("div", { style: emptyStateStyle }, "No performance metric data available yet.") : /* @__PURE__ */ import_react18.default.createElement("table", { style: tableStyle }, /* @__PURE__ */ import_react18.default.createElement("thead", null, /* @__PURE__ */ import_react18.default.createElement("tr", null, /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Metric"), /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Value"), /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Context"), /* @__PURE__ */ import_react18.default.createElement("th", { style: thStyle }, "Period"))), /* @__PURE__ */ import_react18.default.createElement("tbody", null, metrics.map((m, i) => /* @__PURE__ */ import_react18.default.createElement("tr", { key: i }, /* @__PURE__ */ import_react18.default.createElement("td", { style: { ...tdStyle, fontWeight: 600 } }, METRIC_LABELS[m.metric_type] || m.metric_type.replace(/_/g, " ")), /* @__PURE__ */ import_react18.default.createElement("td", { style: tdStyle }, formatMetricValue(m.metric_type, m.value)), /* @__PURE__ */ import_react18.default.createElement("td", { style: { ...tdStyle, color: "#718096", fontSize: "13px" } }, m.context_label), /* @__PURE__ */ import_react18.default.createElement("td", { style: tdStyle }, m.time_period))))), disciplinary.length > 0 && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("h2", { style: sectionHeadingStyle }, "Disciplinary History"), disciplinary.map((d, i) => /* @__PURE__ */ import_react18.default.createElement("div", { key: i, style: {
3775
+ borderLeft: "3px solid #fc8181",
3776
+ backgroundColor: "#fff5f5",
3777
+ borderRadius: "0 6px 6px 0",
3778
+ padding: "12px 16px",
3779
+ marginBottom: "10px"
3780
+ } }, /* @__PURE__ */ import_react18.default.createElement("div", { style: { fontWeight: 700, color: "#742a2a", fontSize: "14px" } }, d.record_type, " \u2014 ", formatDate(d.record_date)), d.description && /* @__PURE__ */ import_react18.default.createElement("div", { style: { color: "#9b2c2c", fontSize: "13px", marginTop: "4px" } }, d.description), d.source_url && /* @__PURE__ */ import_react18.default.createElement(
3781
+ "a",
3782
+ {
3783
+ href: d.source_url,
3784
+ target: "_blank",
3785
+ rel: "noopener noreferrer",
3786
+ style: { color: "#c53030", fontSize: "12px", marginTop: "4px", display: "inline-block" }
3787
+ },
3788
+ "View source \u2192"
3789
+ )))));
3790
+ }
3791
+
3792
+ // src/AuthForm.jsx
3793
+ var import_react19 = __toESM(require("react"));
3794
+ function AuthForm({
3795
+ logoSrc = "/EVLogo.svg",
3796
+ appName = "Empowered Vote",
3797
+ appSubtitle,
3798
+ mode = "login",
3799
+ onSubmit,
3800
+ onModeSwitch,
3801
+ error = null,
3802
+ submitting = false
3803
+ }) {
3804
+ const [username, setUsername] = (0, import_react19.useState)("");
3805
+ const [password, setPassword] = (0, import_react19.useState)("");
3806
+ const [confirmPassword, setConfirmPassword] = (0, import_react19.useState)("");
3807
+ const [showPasswords, setShowPasswords] = (0, import_react19.useState)(false);
3808
+ const [passwordMismatch, setPasswordMismatch] = (0, import_react19.useState)(false);
3809
+ const isLogin = mode === "login";
3810
+ const handleSubmit = (e) => {
3811
+ e.preventDefault();
3812
+ if (!username.trim() || !password) return;
3813
+ if (!isLogin && password !== confirmPassword) {
3814
+ setPasswordMismatch(true);
3815
+ return;
3816
+ }
3817
+ setPasswordMismatch(false);
3818
+ onSubmit == null ? void 0 : onSubmit(username.trim(), password);
3819
+ };
3820
+ const EyeOpen = () => /* @__PURE__ */ import_react19.default.createElement(
3821
+ "svg",
3822
+ {
3823
+ xmlns: "http://www.w3.org/2000/svg",
3824
+ fill: "none",
3825
+ viewBox: "0 0 24 24",
3826
+ strokeWidth: 1.5,
3827
+ stroke: "currentColor",
3828
+ style: { width: "20px", height: "20px" }
3829
+ },
3830
+ /* @__PURE__ */ import_react19.default.createElement(
3831
+ "path",
3832
+ {
3833
+ strokeLinecap: "round",
3834
+ strokeLinejoin: "round",
3835
+ d: "M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
3836
+ }
3837
+ ),
3838
+ /* @__PURE__ */ import_react19.default.createElement(
3839
+ "path",
3840
+ {
3841
+ strokeLinecap: "round",
3842
+ strokeLinejoin: "round",
3843
+ d: "M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
3844
+ }
3845
+ )
3846
+ );
3847
+ const EyeClosed = () => /* @__PURE__ */ import_react19.default.createElement(
3848
+ "svg",
3849
+ {
3850
+ xmlns: "http://www.w3.org/2000/svg",
3851
+ fill: "none",
3852
+ viewBox: "0 0 24 24",
3853
+ strokeWidth: 1.5,
3854
+ stroke: "currentColor",
3855
+ style: { width: "20px", height: "20px" }
3856
+ },
3857
+ /* @__PURE__ */ import_react19.default.createElement(
3858
+ "path",
3859
+ {
3860
+ strokeLinecap: "round",
3861
+ strokeLinejoin: "round",
3862
+ d: "M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"
3863
+ }
3864
+ )
3865
+ );
3866
+ const PasswordToggle = () => /* @__PURE__ */ import_react19.default.createElement(
3867
+ "button",
3868
+ {
3869
+ type: "button",
3870
+ onClick: () => setShowPasswords((prev) => !prev),
3871
+ style: styles.passwordToggle
3872
+ },
3873
+ showPasswords ? /* @__PURE__ */ import_react19.default.createElement(EyeOpen, null) : /* @__PURE__ */ import_react19.default.createElement(EyeClosed, null)
3874
+ );
3875
+ const displayError = passwordMismatch ? "Passwords do not match." : error;
3876
+ return /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.wrapper }, /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.container }, /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.header }, logoSrc && /* @__PURE__ */ import_react19.default.createElement("img", { src: logoSrc, alt: appName, style: styles.logo }), appName && /* @__PURE__ */ import_react19.default.createElement("h1", { style: styles.appName }, appName), appSubtitle && /* @__PURE__ */ import_react19.default.createElement("p", { style: styles.appSubtitle }, appSubtitle)), /* @__PURE__ */ import_react19.default.createElement("form", { onSubmit: handleSubmit, style: styles.card }, /* @__PURE__ */ import_react19.default.createElement("h2", { style: styles.cardTitle }, isLogin ? "Welcome Back" : "Create Account"), /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.fieldGroup }, /* @__PURE__ */ import_react19.default.createElement("label", { style: styles.label }, "Username"), /* @__PURE__ */ import_react19.default.createElement(
3877
+ "input",
3878
+ {
3879
+ type: "text",
3880
+ name: "username",
3881
+ autoComplete: "off",
3882
+ style: styles.input,
3883
+ value: username,
3884
+ onChange: (e) => setUsername(e.target.value),
3885
+ onFocus: (e) => Object.assign(e.target.style, styles.inputFocus),
3886
+ onBlur: (e) => {
3887
+ e.target.style.outline = "none";
3888
+ e.target.style.boxShadow = "none";
3889
+ e.target.style.borderColor = colors.borderLight;
3890
+ },
3891
+ required: true
3892
+ }
3893
+ )), /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.fieldGroup }, /* @__PURE__ */ import_react19.default.createElement("label", { style: styles.label }, "Password"), /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.passwordWrapper }, /* @__PURE__ */ import_react19.default.createElement(
3894
+ "input",
3895
+ {
3896
+ type: showPasswords ? "text" : "password",
3897
+ name: "password",
3898
+ style: { ...styles.input, paddingRight: "40px" },
3899
+ value: password,
3900
+ onChange: (e) => setPassword(e.target.value),
3901
+ onFocus: (e) => Object.assign(e.target.style, styles.inputFocus),
3902
+ onBlur: (e) => {
3903
+ e.target.style.outline = "none";
3904
+ e.target.style.boxShadow = "none";
3905
+ e.target.style.borderColor = colors.borderLight;
3906
+ },
3907
+ required: true
3908
+ }
3909
+ ), /* @__PURE__ */ import_react19.default.createElement(PasswordToggle, null))), !isLogin && /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.fieldGroup }, /* @__PURE__ */ import_react19.default.createElement("label", { style: styles.label }, "Confirm Password"), /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.passwordWrapper }, /* @__PURE__ */ import_react19.default.createElement(
3910
+ "input",
3911
+ {
3912
+ type: showPasswords ? "text" : "password",
3913
+ name: "confirmPassword",
3914
+ style: { ...styles.input, paddingRight: "40px" },
3915
+ value: confirmPassword,
3916
+ onChange: (e) => setConfirmPassword(e.target.value),
3917
+ onFocus: (e) => Object.assign(e.target.style, styles.inputFocus),
3918
+ onBlur: (e) => {
3919
+ e.target.style.outline = "none";
3920
+ e.target.style.boxShadow = "none";
3921
+ e.target.style.borderColor = colors.borderLight;
3922
+ },
3923
+ required: true
3924
+ }
3925
+ ), /* @__PURE__ */ import_react19.default.createElement(PasswordToggle, null))), displayError && /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.errorBox }, /* @__PURE__ */ import_react19.default.createElement("p", { style: styles.errorText }, displayError)), /* @__PURE__ */ import_react19.default.createElement(
3926
+ "button",
3927
+ {
3928
+ type: "submit",
3929
+ disabled: submitting || !username.trim() || !password,
3930
+ style: {
3931
+ ...styles.submitButton,
3932
+ opacity: submitting || !username.trim() || !password ? 0.6 : 1,
3933
+ cursor: submitting || !username.trim() || !password ? "not-allowed" : "pointer"
3934
+ },
3935
+ onMouseEnter: (e) => {
3936
+ if (!submitting) e.target.style.backgroundColor = "#e64d38";
3937
+ },
3938
+ onMouseLeave: (e) => {
3939
+ e.target.style.backgroundColor = colors.evCoral;
3940
+ }
3941
+ },
3942
+ submitting ? isLogin ? "Signing In..." : "Creating Account..." : isLogin ? "Sign In" : "Create Account"
3943
+ ), onModeSwitch && /* @__PURE__ */ import_react19.default.createElement("div", { style: styles.modeSwitch }, /* @__PURE__ */ import_react19.default.createElement("p", { style: styles.modeSwitchText }, isLogin ? "Don't have an account?" : "Already have an account?"), /* @__PURE__ */ import_react19.default.createElement(
3944
+ "button",
3945
+ {
3946
+ type: "button",
3947
+ onClick: onModeSwitch,
3948
+ style: styles.modeSwitchButton,
3949
+ onMouseEnter: (e) => {
3950
+ e.target.style.backgroundColor = colors.evTeal;
3951
+ e.target.style.color = colors.textWhite;
3952
+ },
3953
+ onMouseLeave: (e) => {
3954
+ e.target.style.backgroundColor = "transparent";
3955
+ e.target.style.color = colors.evTeal;
3956
+ }
3957
+ },
3958
+ isLogin ? "Create Account" : "Sign In"
3959
+ )))));
3960
+ }
3961
+ var styles = {
3962
+ wrapper: {
3963
+ minHeight: "100vh",
3964
+ display: "flex",
3965
+ alignItems: "center",
3966
+ justifyContent: "center",
3967
+ backgroundColor: "#f8f9fa",
3968
+ padding: `0 ${spacing[4]}`,
3969
+ fontFamily: fonts.primary
3970
+ },
3971
+ container: {
3972
+ width: "100%",
3973
+ maxWidth: "384px"
3974
+ },
3975
+ header: {
3976
+ display: "flex",
3977
+ flexDirection: "column",
3978
+ alignItems: "center",
3979
+ marginBottom: spacing[8]
3980
+ },
3981
+ logo: {
3982
+ height: "64px",
3983
+ width: "auto",
3984
+ marginBottom: spacing[4]
3985
+ },
3986
+ appName: {
3987
+ fontSize: fontSizes["2xl"],
3988
+ fontWeight: fontWeights.semibold,
3989
+ color: colors.evTeal,
3990
+ margin: 0,
3991
+ fontFamily: fonts.primary
3992
+ },
3993
+ appSubtitle: {
3994
+ color: colors.textMuted,
3995
+ fontSize: fontSizes.sm,
3996
+ marginTop: spacing[1],
3997
+ margin: `${spacing[1]} 0 0 0`,
3998
+ fontFamily: fonts.primary
3999
+ },
4000
+ card: {
4001
+ backgroundColor: colors.bgWhite,
4002
+ padding: spacing[8],
4003
+ borderRadius: "16px",
4004
+ boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)",
4005
+ border: `1px solid ${colors.borderLight}`
4006
+ },
4007
+ cardTitle: {
4008
+ fontSize: fontSizes.xl,
4009
+ fontWeight: fontWeights.semibold,
4010
+ marginBottom: spacing[6],
4011
+ textAlign: "center",
4012
+ color: colors.textSecondary,
4013
+ margin: `0 0 ${spacing[6]} 0`,
4014
+ fontFamily: fonts.primary
4015
+ },
4016
+ fieldGroup: {
4017
+ marginBottom: spacing[4]
4018
+ },
4019
+ label: {
4020
+ display: "block",
4021
+ marginBottom: spacing[1],
4022
+ fontSize: fontSizes.sm,
4023
+ fontWeight: fontWeights.medium,
4024
+ color: colors.textMuted,
4025
+ fontFamily: fonts.primary
4026
+ },
4027
+ input: {
4028
+ width: "100%",
4029
+ border: `1px solid ${colors.borderLight}`,
4030
+ borderRadius: borderRadius.lg,
4031
+ padding: `10px ${spacing[4]}`,
4032
+ fontSize: fontSizes.base,
4033
+ fontFamily: fonts.primary,
4034
+ outline: "none",
4035
+ transition: "border-color 0.2s, box-shadow 0.2s",
4036
+ boxSizing: "border-box"
4037
+ },
4038
+ inputFocus: {
4039
+ outline: "none",
4040
+ boxShadow: `0 0 0 2px ${colors.evTealLight}`,
4041
+ borderColor: "transparent"
4042
+ },
4043
+ passwordWrapper: {
4044
+ position: "relative"
4045
+ },
4046
+ passwordToggle: {
4047
+ position: "absolute",
4048
+ top: 0,
4049
+ right: "12px",
4050
+ bottom: 0,
4051
+ display: "flex",
4052
+ alignItems: "center",
4053
+ background: "none",
4054
+ border: "none",
4055
+ color: colors.textMuted,
4056
+ cursor: "pointer",
4057
+ padding: 0
4058
+ },
4059
+ errorBox: {
4060
+ marginBottom: spacing[4],
4061
+ padding: spacing[3],
4062
+ backgroundColor: "#fef2f2",
4063
+ border: "1px solid #fecaca",
4064
+ borderRadius: borderRadius.lg
4065
+ },
4066
+ errorText: {
4067
+ color: colors.error,
4068
+ fontSize: fontSizes.sm,
4069
+ textAlign: "center",
4070
+ margin: 0,
4071
+ fontFamily: fonts.primary
4072
+ },
4073
+ submitButton: {
4074
+ width: "100%",
4075
+ backgroundColor: colors.evCoral,
4076
+ color: colors.textWhite,
4077
+ padding: "10px 0",
4078
+ borderRadius: borderRadius.lg,
4079
+ border: "none",
4080
+ fontWeight: fontWeights.semibold,
4081
+ fontSize: fontSizes.base,
4082
+ fontFamily: fonts.primary,
4083
+ cursor: "pointer",
4084
+ transition: "background-color 0.2s",
4085
+ boxShadow: shadows.sm
4086
+ },
4087
+ modeSwitch: {
4088
+ marginTop: spacing[6],
4089
+ paddingTop: spacing[6],
4090
+ borderTop: `1px solid ${colors.borderLight}`
4091
+ },
4092
+ modeSwitchText: {
4093
+ textAlign: "center",
4094
+ fontSize: fontSizes.sm,
4095
+ color: colors.textMuted,
4096
+ marginBottom: spacing[3],
4097
+ margin: `0 0 ${spacing[3]} 0`,
4098
+ fontFamily: fonts.primary
4099
+ },
4100
+ modeSwitchButton: {
4101
+ width: "100%",
4102
+ padding: "10px 0",
4103
+ border: `2px solid ${colors.evTeal}`,
4104
+ color: colors.evTeal,
4105
+ borderRadius: borderRadius.lg,
4106
+ backgroundColor: "transparent",
4107
+ fontWeight: fontWeights.medium,
4108
+ fontSize: fontSizes.base,
4109
+ fontFamily: fonts.primary,
4110
+ cursor: "pointer",
4111
+ transition: "background-color 0.2s, color 0.2s"
4112
+ }
4113
+ };
4114
+
4115
+ // src/StanceAccordion.jsx
4116
+ var import_react21 = __toESM(require("react"));
4117
+
4118
+ // src/Favicon.jsx
4119
+ var import_react20 = __toESM(require("react"));
4120
+ function Favicon({ url, size = 16 }) {
4121
+ try {
4122
+ const domain = new URL(url).hostname;
4123
+ return /* @__PURE__ */ import_react20.default.createElement(
4124
+ "img",
4125
+ {
4126
+ src: `https://www.google.com/s2/favicons?sz=${size}&domain=${domain}`,
4127
+ alt: "",
4128
+ width: size,
4129
+ height: size,
4130
+ style: { verticalAlign: "middle", flexShrink: 0 }
4131
+ }
4132
+ );
4133
+ } catch {
4134
+ return /* @__PURE__ */ import_react20.default.createElement(
4135
+ "svg",
4136
+ {
4137
+ width: size,
4138
+ height: size,
4139
+ viewBox: "0 0 24 24",
4140
+ fill: "none",
4141
+ stroke: "currentColor",
4142
+ strokeWidth: "1.5",
4143
+ style: { verticalAlign: "middle", flexShrink: 0 }
4144
+ },
4145
+ /* @__PURE__ */ import_react20.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
4146
+ /* @__PURE__ */ import_react20.default.createElement("path", { d: "M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })
4147
+ );
4148
+ }
4149
+ }
4150
+
4151
+ // src/StanceAccordion.jsx
4152
+ function getDisplayUrl(url) {
4153
+ try {
4154
+ const u = new URL(url);
4155
+ let host = u.hostname.replace(/^www\./, "");
4156
+ const path = u.pathname === "/" ? "" : u.pathname;
4157
+ const display = host + path;
4158
+ return display.length > 60 ? display.slice(0, 57) + "..." : display;
4159
+ } catch {
4160
+ return url.length > 60 ? url.slice(0, 57) + "..." : url;
4161
+ }
4162
+ }
4163
+ function StanceAccordion({
4164
+ topics,
4165
+ polAnswers,
4166
+ politicianId,
4167
+ allTopics,
4168
+ expandedTopics,
4169
+ verdictsByTopic,
4170
+ // Record<string, 'agreed' | 'disagreed'> | undefined — DEPRECATED, no longer rendered
4171
+ verdictsByQuote,
4172
+ // Record<quote_id, 'agreed' | 'disagreed'> | undefined
4173
+ initialExpandedTopicId,
4174
+ apiUrl = "https://api.empowered.vote"
4175
+ }) {
4176
+ var _a;
4177
+ const [expandedTopicId, setExpandedTopicId] = (0, import_react21.useState)(null);
4178
+ const [loadingId, setLoadingId] = (0, import_react21.useState)(null);
4179
+ const [showAll, setShowAll] = (0, import_react21.useState)(false);
4180
+ const contextCache = (0, import_react21.useRef)(/* @__PURE__ */ new Map());
4181
+ const quotesCache = (0, import_react21.useRef)(null);
4182
+ const polAnswerMap = {};
4183
+ if (polAnswers) {
4184
+ polAnswers.forEach((a) => {
4185
+ polAnswerMap[String(a.topic_id)] = a.value;
4186
+ });
4187
+ }
4188
+ const topicById = {};
4189
+ if (allTopics) {
4190
+ allTopics.forEach((t) => {
4191
+ topicById[String(t.id)] = t;
4192
+ });
4193
+ }
4194
+ function getStanceLabel(topicId, value) {
4195
+ const topic = topicById[String(topicId)];
4196
+ if (!topic || !topic.stances || !value) return "No position";
4197
+ const idx = value - 1;
4198
+ if (idx < 0 || idx >= topic.stances.length) return "No position";
4199
+ return topic.stances[idx].text || "No position";
4200
+ }
4201
+ async function fetchContext(topicId) {
4202
+ if (contextCache.current.has(topicId)) return;
4203
+ try {
4204
+ const res = await fetch(
4205
+ `${apiUrl}/compass/politicians/${politicianId}/${topicId}/context`,
4206
+ { credentials: "include" }
4207
+ );
4208
+ if (res.status === 404) {
4209
+ contextCache.current.set(topicId, { reasoning: "", sources: [] });
4210
+ } else if (res.ok) {
4211
+ const data = await res.json();
4212
+ contextCache.current.set(topicId, {
4213
+ reasoning: data.reasoning || "",
4214
+ sources: data.sources || []
4215
+ });
4216
+ } else {
4217
+ contextCache.current.set(topicId, { reasoning: "", sources: [] });
4218
+ }
4219
+ } catch {
4220
+ contextCache.current.set(topicId, { reasoning: "", sources: [] });
4221
+ }
4222
+ }
4223
+ async function ensureQuotesFetched() {
4224
+ if (quotesCache.current !== null) return;
4225
+ try {
4226
+ const res = await fetch(
4227
+ `${apiUrl}/essentials/quotes?politician_id=${politicianId}`,
4228
+ { credentials: "include" }
4229
+ );
4230
+ if (res.ok) {
4231
+ const data = await res.json();
4232
+ quotesCache.current = data.quotes || [];
4233
+ } else {
4234
+ quotesCache.current = [];
4235
+ }
4236
+ } catch {
4237
+ quotesCache.current = [];
4238
+ }
4239
+ }
4240
+ const handleToggle = (0, import_react21.useCallback)(
4241
+ async (topicId) => {
4242
+ if (expandedTopicId === topicId) {
4243
+ setExpandedTopicId(null);
4244
+ return;
4245
+ }
4246
+ setExpandedTopicId(topicId);
4247
+ if (contextCache.current.has(topicId) && quotesCache.current !== null) return;
4248
+ setLoadingId(topicId);
4249
+ try {
4250
+ await Promise.all([fetchContext(topicId), ensureQuotesFetched()]);
4251
+ } finally {
4252
+ setLoadingId(null);
4253
+ }
4254
+ },
4255
+ [expandedTopicId, politicianId, apiUrl]
4256
+ );
4257
+ (0, import_react21.useEffect)(() => {
4258
+ if (initialExpandedTopicId && topics && topics.length > 0) {
4259
+ handleToggle(String(initialExpandedTopicId));
4260
+ }
4261
+ }, [initialExpandedTopicId, topics == null ? void 0 : topics.length]);
4262
+ if (!topics || topics.length === 0) return null;
4263
+ const hasToggle = expandedTopics && expandedTopics.length > topics.length;
4264
+ const baseTopics = hasToggle && showAll ? expandedTopics : topics;
4265
+ let visibleTopics = baseTopics;
4266
+ if (initialExpandedTopicId) {
4267
+ const fullList = expandedTopics || topics;
4268
+ const pinned = fullList.find((t) => String(t.id) === String(initialExpandedTopicId));
4269
+ if (pinned && String((_a = baseTopics[0]) == null ? void 0 : _a.id) !== String(initialExpandedTopicId)) {
4270
+ visibleTopics = [pinned, ...baseTopics.filter((t) => String(t.id) !== String(initialExpandedTopicId))];
4271
+ }
4272
+ }
4273
+ return /* @__PURE__ */ import_react21.default.createElement(
4274
+ "div",
4275
+ {
4276
+ className: "flex flex-col",
4277
+ style: { fontFamily: "'Manrope', sans-serif" }
4278
+ },
4279
+ /* @__PURE__ */ import_react21.default.createElement(
4280
+ "h3",
4281
+ {
4282
+ className: "text-sm font-semibold text-neutral-400 uppercase tracking-wider mb-2",
4283
+ style: { fontSize: "12px" }
4284
+ },
4285
+ "Stance Breakdown"
4286
+ ),
4287
+ visibleTopics.map((topic) => {
4288
+ const topicId = String(topic.id);
4289
+ const value = polAnswerMap[topicId];
4290
+ const label = getStanceLabel(topicId, value);
4291
+ const isExpanded = expandedTopicId === topicId;
4292
+ const isLoading = loadingId === topicId;
4293
+ const cached = contextCache.current.get(topicId);
4294
+ const fullTopic = topicById[topicId];
4295
+ const questionText = fullTopic == null ? void 0 : fullTopic.question_text;
4296
+ const topicQuotes = quotesCache.current ? quotesCache.current.filter((q) => {
4297
+ if (!q.issue) return false;
4298
+ if (topic.topic_key) return q.issue === topic.topic_key;
4299
+ return topic.short_title && q.issue.toLowerCase() === topic.short_title.toLowerCase();
4300
+ }) : [];
4301
+ return /* @__PURE__ */ import_react21.default.createElement("div", { key: topicId, className: "border-b border-neutral-100" }, /* @__PURE__ */ import_react21.default.createElement(
4302
+ "button",
4303
+ {
4304
+ type: "button",
4305
+ onClick: () => handleToggle(topicId),
4306
+ className: "w-full flex items-center justify-between py-3 px-2 text-left cursor-pointer hover:bg-neutral-50 transition-colors"
4307
+ },
4308
+ /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ import_react21.default.createElement("span", { className: "text-sm font-medium text-neutral-800 truncate" }, topic.short_title), questionText && /* @__PURE__ */ import_react21.default.createElement("span", { className: "text-xs text-neutral-400 mt-0.5" }, questionText), /* @__PURE__ */ import_react21.default.createElement("span", { className: "text-xs text-neutral-500 mt-0.5" }, label)),
4309
+ /* @__PURE__ */ import_react21.default.createElement(
4310
+ "svg",
4311
+ {
4312
+ width: "16",
4313
+ height: "16",
4314
+ viewBox: "0 0 24 24",
4315
+ fill: "none",
4316
+ stroke: "currentColor",
4317
+ strokeWidth: "2",
4318
+ strokeLinecap: "round",
4319
+ strokeLinejoin: "round",
4320
+ className: "text-neutral-400 flex-shrink-0 ml-2",
4321
+ style: {
4322
+ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
4323
+ transition: "transform 0.2s ease"
4324
+ }
4325
+ },
4326
+ /* @__PURE__ */ import_react21.default.createElement("polyline", { points: "9 18 15 12 9 6" })
4327
+ )
4328
+ ), /* @__PURE__ */ import_react21.default.createElement(
4329
+ "div",
4330
+ {
4331
+ style: {
4332
+ display: "grid",
4333
+ gridTemplateRows: isExpanded ? "1fr" : "0fr",
4334
+ transition: "grid-template-rows 0.25s ease"
4335
+ }
4336
+ },
4337
+ /* @__PURE__ */ import_react21.default.createElement("div", { style: { overflow: "hidden" } }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "px-2 pb-4" }, isLoading && /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center py-3" }, /* @__PURE__ */ import_react21.default.createElement(
4338
+ "div",
4339
+ {
4340
+ style: {
4341
+ width: "20px",
4342
+ height: "20px",
4343
+ border: "2px solid #e2e8f0",
4344
+ borderTopColor: "#00657c",
4345
+ borderRadius: "50%",
4346
+ animation: "ev-spin 0.8s linear infinite"
4347
+ }
4348
+ }
4349
+ )), !isLoading && cached && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, cached.reasoning ? /* @__PURE__ */ import_react21.default.createElement(
4350
+ "p",
4351
+ {
4352
+ className: "text-sm text-neutral-700 mb-3",
4353
+ style: { whiteSpace: "pre-wrap", lineHeight: 1.6 }
4354
+ },
4355
+ cached.reasoning
4356
+ ) : null, cached.sources && cached.sources.length > 0 && /* @__PURE__ */ import_react21.default.createElement("div", { className: "mt-2" }, /* @__PURE__ */ import_react21.default.createElement("p", { className: "text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-1.5" }, "References"), /* @__PURE__ */ import_react21.default.createElement("ol", { className: "list-decimal list-inside space-y-1" }, cached.sources.map((src, i) => /* @__PURE__ */ import_react21.default.createElement("li", { key: i, className: "text-xs text-neutral-600" }, /* @__PURE__ */ import_react21.default.createElement(
4357
+ "a",
4358
+ {
4359
+ href: src,
4360
+ target: "_blank",
4361
+ rel: "noreferrer",
4362
+ className: "inline-flex items-center gap-1.5 hover:text-[#00657c] transition-colors"
4363
+ },
4364
+ /* @__PURE__ */ import_react21.default.createElement(Favicon, { url: src }),
4365
+ /* @__PURE__ */ import_react21.default.createElement("span", { className: "underline underline-offset-2" }, getDisplayUrl(src))
4366
+ ))))), topicQuotes.length > 0 && /* @__PURE__ */ import_react21.default.createElement("div", { style: { marginTop: "12px" } }, /* @__PURE__ */ import_react21.default.createElement(
4367
+ "p",
4368
+ {
4369
+ style: {
4370
+ fontSize: "11px",
4371
+ fontWeight: 600,
4372
+ color: "#737373",
4373
+ textTransform: "uppercase",
4374
+ letterSpacing: "0.05em",
4375
+ marginBottom: "8px"
4376
+ }
4377
+ },
4378
+ "Quotes"
4379
+ ), topicQuotes.map((quote) => {
4380
+ const verdict = verdictsByQuote ? verdictsByQuote[quote.id] : void 0;
4381
+ const borderColor = verdict === "agreed" ? "#0e7490" : verdict === "disagreed" ? "#b45309" : "#e2e8f0";
4382
+ const sourceName = quote.source_name || quote.sourceName;
4383
+ return /* @__PURE__ */ import_react21.default.createElement(
4384
+ "div",
4385
+ {
4386
+ key: quote.id,
4387
+ style: {
4388
+ borderLeft: `3px solid ${borderColor}`,
4389
+ paddingLeft: "10px",
4390
+ paddingTop: "6px",
4391
+ paddingBottom: "6px",
4392
+ marginBottom: "8px"
4393
+ }
4394
+ },
4395
+ /* @__PURE__ */ import_react21.default.createElement(
4396
+ "p",
4397
+ {
4398
+ style: {
4399
+ fontSize: "13px",
4400
+ fontStyle: "italic",
4401
+ color: "#374151",
4402
+ margin: 0,
4403
+ lineHeight: 1.5
4404
+ }
4405
+ },
4406
+ quote.text
4407
+ ),
4408
+ verdict === "agreed" && /* @__PURE__ */ import_react21.default.createElement(
4409
+ "span",
4410
+ {
4411
+ style: {
4412
+ display: "inline-flex",
4413
+ alignItems: "center",
4414
+ gap: "4px",
4415
+ backgroundColor: "#ecfeff",
4416
+ color: "#0e7490",
4417
+ padding: "2px 8px",
4418
+ borderRadius: "9999px",
4419
+ fontSize: "11px",
4420
+ fontWeight: 500,
4421
+ marginTop: "4px",
4422
+ flexShrink: 0
4423
+ }
4424
+ },
4425
+ /* @__PURE__ */ import_react21.default.createElement("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react21.default.createElement("path", { d: "M5 13l4 4L19 7" })),
4426
+ "Agreed"
4427
+ ),
4428
+ verdict === "disagreed" && /* @__PURE__ */ import_react21.default.createElement(
4429
+ "span",
4430
+ {
4431
+ style: {
4432
+ display: "inline-flex",
4433
+ alignItems: "center",
4434
+ gap: "4px",
4435
+ backgroundColor: "#fffbeb",
4436
+ color: "#b45309",
4437
+ padding: "2px 8px",
4438
+ borderRadius: "9999px",
4439
+ fontSize: "11px",
4440
+ fontWeight: 500,
4441
+ marginTop: "4px",
4442
+ flexShrink: 0
4443
+ }
4444
+ },
4445
+ /* @__PURE__ */ import_react21.default.createElement("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react21.default.createElement("path", { d: "M6 18L18 6M6 6l12 12" })),
4446
+ "Disagreed"
4447
+ ),
4448
+ sourceName && /* @__PURE__ */ import_react21.default.createElement(
4449
+ "a",
4450
+ {
4451
+ href: quote.source_url || quote.sourceUrl,
4452
+ target: "_blank",
4453
+ rel: "noreferrer",
4454
+ style: {
4455
+ display: "block",
4456
+ fontSize: "11px",
4457
+ color: "#00657c",
4458
+ marginTop: "3px",
4459
+ textDecoration: "none"
4460
+ }
4461
+ },
4462
+ sourceName
4463
+ )
4464
+ );
4465
+ })), !cached.reasoning && (!cached.sources || cached.sources.length === 0) && topicQuotes.length === 0 && /* @__PURE__ */ import_react21.default.createElement("p", { className: "text-sm text-neutral-400 italic py-2" }, "No detailed reasoning available for this topic."))))
4466
+ ));
4467
+ }),
4468
+ hasToggle && /* @__PURE__ */ import_react21.default.createElement(
4469
+ "button",
4470
+ {
4471
+ type: "button",
4472
+ onClick: () => setShowAll((v) => !v),
4473
+ className: "text-sm font-medium mt-2 px-2 py-1 self-start cursor-pointer hover:underline",
4474
+ style: { color: "#00657c" }
4475
+ },
4476
+ showAll ? "Show fewer" : `Show all ${expandedTopics.length} topics`
4477
+ )
4478
+ );
4479
+ }
4480
+
4481
+ // src/icons.js
4482
+ var import_react22 = __toESM(require("react"));
4483
+ function BallotIcon({ size = 16, color = "currentColor" }) {
4484
+ return /* @__PURE__ */ import_react22.default.createElement(
4485
+ "svg",
4486
+ {
4487
+ width: size,
4488
+ height: size,
4489
+ viewBox: "0 0 24 24",
4490
+ fill: "none",
4491
+ stroke: color,
4492
+ strokeWidth: "2",
4493
+ strokeLinecap: "round",
4494
+ strokeLinejoin: "round",
4495
+ xmlns: "http://www.w3.org/2000/svg"
4496
+ },
4497
+ /* @__PURE__ */ import_react22.default.createElement("path", { d: "m9 12 2 2 4-4" }),
4498
+ /* @__PURE__ */ import_react22.default.createElement("path", { d: "M5 7c0-1.1.9-2 2-2h10a2 2 0 0 1 2 2v12H5V7Z" }),
4499
+ /* @__PURE__ */ import_react22.default.createElement("path", { d: "M22 19H2" })
4500
+ );
4501
+ }
4502
+ function CompassIcon({ size = 16, color = "currentColor" }) {
4503
+ return /* @__PURE__ */ import_react22.default.createElement(
4504
+ "svg",
4505
+ {
4506
+ width: size,
4507
+ height: size,
4508
+ viewBox: "0 0 24 24",
4509
+ fill: "none",
4510
+ stroke: color,
4511
+ strokeWidth: "2",
4512
+ strokeLinecap: "round",
4513
+ strokeLinejoin: "round",
4514
+ xmlns: "http://www.w3.org/2000/svg"
4515
+ },
4516
+ /* @__PURE__ */ import_react22.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
4517
+ /* @__PURE__ */ import_react22.default.createElement("path", { d: "m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z" })
4518
+ );
4519
+ }
4520
+ function BranchIcon({ size = 16, color = "currentColor", branch }) {
4521
+ let paths;
4522
+ switch (branch) {
4523
+ case "executive":
4524
+ paths = /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, /* @__PURE__ */ import_react22.default.createElement("path", { d: "M3 21h18" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M5 21V7l8-4v18" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M19 21V11l-6-4" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M9 9v.01" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M9 12v.01" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M9 15v.01" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M9 18v.01" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M5 21h14" }), /* @__PURE__ */ import_react22.default.createElement("line", { x1: "13", y1: "5", x2: "13", y2: "3" }), /* @__PURE__ */ import_react22.default.createElement("line", { x1: "13", y1: "3", x2: "15", y2: "4" }));
4525
+ break;
4526
+ case "legislative":
4527
+ paths = /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, /* @__PURE__ */ import_react22.default.createElement("path", { d: "M8 21h12a2 2 0 0 0 2-2v-2H10v2a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v3h4" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M19 17V5a2 2 0 0 0-2-2H4" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M15 8h-5" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M15 12h-5" }));
4528
+ break;
4529
+ case "judicial":
4530
+ paths = /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, /* @__PURE__ */ import_react22.default.createElement("path", { d: "M12 3v19" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M5 8l7-5 7 5" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M3 13l2-5 2 5a3 3 0 0 1-4 0z" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M17 13l2-5 2 5a3 3 0 0 1-4 0z" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M8 21h8" }));
4531
+ break;
4532
+ default:
4533
+ paths = /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, /* @__PURE__ */ import_react22.default.createElement("path", { d: "M10 18v-7" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M11.12 2.198a2 2 0 0 1 1.76.006l7.866 3.847c.476.233.31.949-.22.949H3.474c-.53 0-.695-.716-.22-.949z" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M14 18v-7" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M18 18v-7" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M3 22h18" }), /* @__PURE__ */ import_react22.default.createElement("path", { d: "M6 18v-7" }));
4534
+ break;
4535
+ }
4536
+ return /* @__PURE__ */ import_react22.default.createElement(
4537
+ "svg",
4538
+ {
4539
+ width: size,
4540
+ height: size,
4541
+ viewBox: "0 0 24 24",
4542
+ fill: "none",
4543
+ stroke: color,
4544
+ strokeWidth: "2",
4545
+ strokeLinecap: "round",
4546
+ strokeLinejoin: "round",
4547
+ xmlns: "http://www.w3.org/2000/svg"
4548
+ },
4549
+ paths
4550
+ );
4551
+ }
4552
+ // Annotate the CommonJS export names for ESM import in node:
4553
+ 0 && (module.exports = {
4554
+ AuthForm,
4555
+ BallotIcon,
4556
+ BranchIcon,
4557
+ CategorySection,
4558
+ CommitteeTable,
4559
+ CompassIcon,
4560
+ FilterSidebar,
4561
+ GovernmentBodySection,
4562
+ Header,
4563
+ IssueTags,
4564
+ JudicialRecordDetail,
4565
+ JudicialScorecard,
4566
+ LegislativeInlineSummary,
4567
+ LegislativeRecord,
4568
+ PoliticianCard,
4569
+ PoliticianProfile,
4570
+ RadarChartCore,
4571
+ SiteHeader,
4572
+ SocialLinks,
4573
+ StanceAccordion,
4574
+ SubGroupSection,
4575
+ accessibleText,
4576
+ borderRadius,
4577
+ breakpoints,
4578
+ colorScales,
4579
+ colors,
4580
+ dataVizPalette,
4581
+ defaultCtaButton,
4582
+ defaultNavItems,
4583
+ duration,
4584
+ easing,
4585
+ focus,
4586
+ fontSizes,
4587
+ fontWeights,
4588
+ fonts,
4589
+ letterSpacing,
4590
+ lineHeights,
4591
+ opacity,
4592
+ pillars,
4593
+ semanticTokens,
4594
+ shadows,
4595
+ spacing,
4596
+ textStyles,
4597
+ tierColors,
4598
+ useMediaQuery,
4599
+ zIndex
4600
+ });
4601
+ //# sourceMappingURL=index.js.map