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