@sensiblestats/widget-react 0.22.0 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/StatsWidget.tsx
2
- import { useEffect as useEffect5, useMemo as useMemo2, useRef as useRef3 } from "react";
2
+ import { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef3 } from "react";
3
3
  import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
4
4
 
5
5
  // src/kickoff.ts
@@ -322,8 +322,9 @@ function toCardVM(card) {
322
322
  function toActionVM(action) {
323
323
  const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
324
324
  const actionId = str(action.actionId) ?? str(action.id);
325
+ const actionRef = str(action.actionRef);
325
326
  const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
326
- return { label, actionId, message };
327
+ return { label, actionId, actionRef, message };
327
328
  }
328
329
  function toChipVM(intent) {
329
330
  const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
@@ -519,8 +520,8 @@ function applyEvent(state, event) {
519
520
  return { ...state, actionsLoading: true, status: event.data.message };
520
521
  case "turn_complete": {
521
522
  const active = activeTurn(state);
522
- const text = active?.text.trim() ?? "";
523
- const popupText = active?.isGreeting && !state.isOpen && text ? text.slice(0, POPUP_MAX) : state.popupText;
523
+ const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? "");
524
+ const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText;
524
525
  return {
525
526
  ...state,
526
527
  isStreaming: false,
@@ -531,7 +532,8 @@ function applyEvent(state, event) {
531
532
  messages: mapActive(state, (t) => ({
532
533
  ...t,
533
534
  done: true,
534
- greetingDashboard: event.data.dashboard ?? void 0
535
+ greetingDashboard: event.data.dashboard ?? void 0,
536
+ clubFanDashboard: event.data.clubFanDashboard ?? void 0
535
537
  }))
536
538
  };
537
539
  }
@@ -728,7 +730,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
728
730
  }
729
731
 
730
732
  // src/components/ChatPanel.tsx
731
- import { useEffect as useEffect4, useState as useState7 } from "react";
733
+ import { useEffect as useEffect5, useState as useState8 } from "react";
732
734
 
733
735
  // src/components/ChatHeader.tsx
734
736
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -741,7 +743,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
741
743
  }
742
744
 
743
745
  // src/components/MessageList.tsx
744
- import { useEffect as useEffect3, useRef as useRef2 } from "react";
746
+ import { useEffect as useEffect4, useRef as useRef2 } from "react";
745
747
 
746
748
  // src/components/Markdown.tsx
747
749
  import ReactMarkdown from "react-markdown";
@@ -1287,28 +1289,299 @@ function GreetingDashboard({ dashboard, onTap }) {
1287
1289
  ] });
1288
1290
  }
1289
1291
 
1292
+ // src/components/dashboard/FixtureCard.tsx
1293
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1294
+ function resultClass(result) {
1295
+ const upper = result.toUpperCase();
1296
+ if (upper === "W") return "ss-w-fandash-form-pill--win";
1297
+ if (upper === "L") return "ss-w-fandash-form-pill--loss";
1298
+ return "ss-w-fandash-form-pill--draw";
1299
+ }
1300
+ function FormStrip({ form }) {
1301
+ return /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-form", children: form.map((r, i) => /* @__PURE__ */ jsx17("span", { className: `ss-w-fandash-form-pill ${resultClass(r)}`, children: r }, `${r}-${i}`)) });
1302
+ }
1303
+ function FormRow({ name, form }) {
1304
+ return /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-formrow", children: [
1305
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-formrow-name", children: name }),
1306
+ /* @__PURE__ */ jsx17(FormStrip, { form })
1307
+ ] });
1308
+ }
1309
+ function FixtureCard({ card, onTap }) {
1310
+ const { data } = card;
1311
+ const h2h = data.h2H;
1312
+ return /* @__PURE__ */ jsxs13(Fragment5, { children: [
1313
+ /* @__PURE__ */ jsxs13("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-fixture", onClick: () => onTap(card), children: [
1314
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-eyebrow", children: [
1315
+ card.title,
1316
+ " \xB7 ",
1317
+ data.competition
1318
+ ] }),
1319
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-teams", children: [
1320
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-fixture-team", children: [
1321
+ /* @__PURE__ */ jsx17(Crest2, { url: data.homeCrestUrl ?? void 0, name: data.homeName, kind: "team" }),
1322
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-name", children: data.homeName })
1323
+ ] }),
1324
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-vs", children: "v" }),
1325
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away", children: [
1326
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-name", children: data.awayName }),
1327
+ /* @__PURE__ */ jsx17(Crest2, { url: data.awayCrestUrl ?? void 0, name: data.awayName, kind: "team" })
1328
+ ] })
1329
+ ] }),
1330
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-meta", children: [
1331
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-metarow", children: [
1332
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metakey", children: data.dateLabel }),
1333
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metaval", children: data.kickoffLabel })
1334
+ ] }),
1335
+ data.venue ? /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-metarow", children: [
1336
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metakey", children: data.venueLabel }),
1337
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fixture-metaval", children: data.venue })
1338
+ ] }) : null
1339
+ ] }),
1340
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1341
+ ] }),
1342
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-card ss-w-fandash-lastfive", children: [
1343
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-eyebrow", children: data.formLabel }),
1344
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-fixture-form", children: [
1345
+ /* @__PURE__ */ jsx17(FormRow, { name: data.homeName, form: data.homeForm }),
1346
+ /* @__PURE__ */ jsx17(FormRow, { name: data.awayName, form: data.awayForm })
1347
+ ] })
1348
+ ] }),
1349
+ h2h || data.fact ? /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-card ss-w-fandash-h2h", children: [
1350
+ h2h ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
1351
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-eyebrow", children: h2h.label }),
1352
+ /* @__PURE__ */ jsxs13("div", { className: "ss-w-fandash-split", children: [
1353
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
1354
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.wins }),
1355
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.homeWinsLabel })
1356
+ ] }),
1357
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
1358
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.draws }),
1359
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.drawsLabel })
1360
+ ] }),
1361
+ /* @__PURE__ */ jsxs13("span", { className: "ss-w-fandash-split-cell", children: [
1362
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-value", children: h2h.losses }),
1363
+ /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-split-label", children: h2h.awayWinsLabel })
1364
+ ] })
1365
+ ] })
1366
+ ] }) : null,
1367
+ data.fact ? /* @__PURE__ */ jsx17("span", { className: "ss-w-fandash-fact", children: data.fact }) : null
1368
+ ] }) : null
1369
+ ] });
1370
+ }
1371
+
1372
+ // src/components/dashboard/CountdownCard.tsx
1373
+ import { Fragment as Fragment6, useEffect as useEffect3, useState as useState6 } from "react";
1374
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1375
+ var DAY_MS = 864e5;
1376
+ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
1377
+ const totalSeconds = Math.floor((kickoffUnix * 1e3 - nowMs) / 1e3);
1378
+ if (totalSeconds <= 0) return null;
1379
+ const days = Math.floor(totalSeconds / 86400);
1380
+ const hours = Math.floor(totalSeconds % 86400 / 3600);
1381
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
1382
+ const seconds = totalSeconds % 60;
1383
+ const pad = (n) => String(n).padStart(2, "0");
1384
+ if (days > 0) return [{ value: pad(days), unit: "d" }, { value: pad(hours), unit: "h" }];
1385
+ const segs = [{ value: pad(hours), unit: "h" }, { value: pad(minutes), unit: "m" }];
1386
+ if (withSeconds) segs.push({ value: pad(seconds), unit: "s" });
1387
+ return segs;
1388
+ }
1389
+ function CountdownCard({ card }) {
1390
+ const { data } = card;
1391
+ const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
1392
+ const [nowMs, setNowMs] = useState6(() => Date.now());
1393
+ const [reduced] = useState6(
1394
+ () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
1395
+ );
1396
+ const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
1397
+ useEffect3(() => {
1398
+ if (reduced) return;
1399
+ const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
1400
+ return () => window.clearInterval(id);
1401
+ }, [reduced, withinDay]);
1402
+ const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
1403
+ return /* @__PURE__ */ jsx18("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ jsxs14("div", { className: "ss-w-fandash-countdown-top", children: [
1404
+ /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
1405
+ segments ? /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ jsxs14(Fragment6, { children: [
1406
+ i > 0 ? /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
1407
+ /* @__PURE__ */ jsxs14("span", { className: "ss-w-fandash-countdown-seg", children: [
1408
+ /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
1409
+ /* @__PURE__ */ jsx18("span", { className: "ss-w-fandash-countdown-unit", children: unitLabel[s.unit] })
1410
+ ] })
1411
+ ] }, s.unit)) }) : null
1412
+ ] }) });
1413
+ }
1414
+
1415
+ // src/components/dashboard/InjuriesCard.tsx
1416
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1417
+ function ColHead({ name, crestUrl }) {
1418
+ return /* @__PURE__ */ jsxs15("span", { className: "ss-w-fandash-injuries-col-head", children: [
1419
+ /* @__PURE__ */ jsx19(Crest2, { url: crestUrl ?? void 0, name, kind: "team" }),
1420
+ /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injuries-col-head-name", children: name })
1421
+ ] });
1422
+ }
1423
+ function InjuryList({ rows, emptyLabel }) {
1424
+ if (rows.length === 0) return /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injuries-empty", children: emptyLabel });
1425
+ return /* @__PURE__ */ jsx19("ul", { className: "ss-w-fandash-injury-list", children: rows.map((r, i) => /* @__PURE__ */ jsxs15("li", { className: "ss-w-fandash-injury-row", children: [
1426
+ /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-name", children: r.playerName }),
1427
+ /* @__PURE__ */ jsxs15("span", { className: "ss-w-fandash-injury-meta", children: [
1428
+ /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-status", children: r.status }),
1429
+ r.injuryType ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-type", children: r.injuryType }) : null,
1430
+ r.expectedReturnLabel ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-injury-return", children: r.expectedReturnLabel }) : null
1431
+ ] })
1432
+ ] }, `${r.playerName}-${i}`)) });
1433
+ }
1434
+ function InjuriesCard({ card }) {
1435
+ const { data } = card;
1436
+ return /* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-card ss-w-fandash-injuries", children: [
1437
+ card.title ? /* @__PURE__ */ jsx19("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1438
+ /* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-cols", children: [
1439
+ /* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-col", children: [
1440
+ /* @__PURE__ */ jsx19(ColHead, { name: data.oursName, crestUrl: data.oursCrestUrl }),
1441
+ /* @__PURE__ */ jsx19(InjuryList, { rows: data.ours, emptyLabel: data.emptyLabel })
1442
+ ] }),
1443
+ /* @__PURE__ */ jsx19("div", { className: "ss-w-fandash-injuries-divider" }),
1444
+ /* @__PURE__ */ jsxs15("div", { className: "ss-w-fandash-injuries-col", children: [
1445
+ /* @__PURE__ */ jsx19(ColHead, { name: data.theirsName, crestUrl: data.theirsCrestUrl }),
1446
+ /* @__PURE__ */ jsx19(InjuryList, { rows: data.theirs, emptyLabel: data.emptyLabel })
1447
+ ] })
1448
+ ] })
1449
+ ] });
1450
+ }
1451
+
1452
+ // src/components/dashboard/ReasonToBetCard.tsx
1453
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
1454
+ function ReasonToBetCard({ card }) {
1455
+ return /* @__PURE__ */ jsxs16("div", { className: "ss-w-fandash-card ss-w-fandash-reasons", children: [
1456
+ card.title ? /* @__PURE__ */ jsx20("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1457
+ /* @__PURE__ */ jsx20("ul", { className: "ss-w-fandash-reason-list", children: card.data.angles.map((angle, i) => /* @__PURE__ */ jsx20("li", { className: "ss-w-fandash-reason-item", children: angle }, `${angle}-${i}`)) })
1458
+ ] });
1459
+ }
1460
+
1461
+ // src/components/dashboard/WhereToWatchCard.tsx
1462
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
1463
+ function WhereToWatchCard({ card }) {
1464
+ return /* @__PURE__ */ jsxs17("div", { className: "ss-w-fandash-card ss-w-fandash-watch", children: [
1465
+ card.title ? /* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1466
+ /* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-stations", children: card.data.stations.map((station, i) => /* @__PURE__ */ jsx21("span", { className: "ss-w-fandash-station-chip", children: station }, `${station}-${i}`)) })
1467
+ ] });
1468
+ }
1469
+
1470
+ // src/components/dashboard/CongestedWeekCard.tsx
1471
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
1472
+ function CongestedWeekCard({ card, onTap }) {
1473
+ return /* @__PURE__ */ jsxs18("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested", onClick: () => onTap(card), children: [
1474
+ card.title ? /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1475
+ /* @__PURE__ */ jsx22("div", { className: "ss-w-fandash-congested-grid", children: card.data.entries.map((entry, i) => /* @__PURE__ */ jsxs18("span", { className: "ss-w-fandash-congested-cell", children: [
1476
+ /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-day", children: entry.dayLabel }),
1477
+ /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-opponent", children: entry.opponent }),
1478
+ /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-comp", children: entry.competition }),
1479
+ /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-congested-time", children: entry.timeLabel })
1480
+ ] }, `${entry.opponent}-${i}`)) }),
1481
+ /* @__PURE__ */ jsx22("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1482
+ ] });
1483
+ }
1484
+
1485
+ // src/components/dashboard/TransfersCard.tsx
1486
+ import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
1487
+ function TransferList({ rows }) {
1488
+ if (rows.length === 0) return /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-empty", children: "None" });
1489
+ return /* @__PURE__ */ jsx23("ul", { className: "ss-w-fandash-transfer-list", children: rows.map((r, i) => /* @__PURE__ */ jsxs19("li", { className: "ss-w-fandash-transfer-row", children: [
1490
+ /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-name", children: r.playerName }),
1491
+ /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-club", children: r.otherClub }),
1492
+ r.type ? /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfer-type", children: r.type }) : null
1493
+ ] }, `${r.playerName}-${i}`)) });
1494
+ }
1495
+ function TransfersCard({ card }) {
1496
+ const { data } = card;
1497
+ return /* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-card ss-w-fandash-transfers", children: [
1498
+ card.title ? /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1499
+ /* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-cols", children: [
1500
+ /* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-col", children: [
1501
+ /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-col-head", children: "In" }),
1502
+ /* @__PURE__ */ jsx23(TransferList, { rows: data.in })
1503
+ ] }),
1504
+ /* @__PURE__ */ jsxs19("div", { className: "ss-w-fandash-transfers-col", children: [
1505
+ /* @__PURE__ */ jsx23("span", { className: "ss-w-fandash-transfers-col-head", children: "Out" }),
1506
+ /* @__PURE__ */ jsx23(TransferList, { rows: data.out })
1507
+ ] })
1508
+ ] })
1509
+ ] });
1510
+ }
1511
+
1512
+ // src/components/dashboard/LinksCard.tsx
1513
+ import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
1514
+ function LinksCard({ card }) {
1515
+ return /* @__PURE__ */ jsxs20("div", { className: "ss-w-fandash-card ss-w-fandash-links", children: [
1516
+ card.title ? /* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1517
+ /* @__PURE__ */ jsx24("div", { className: "ss-w-fandash-link-grid", children: card.data.links.map((link, i) => /* @__PURE__ */ jsxs20("a", { className: "ss-w-fandash-link-tile", href: link.url, target: "_blank", rel: "noopener noreferrer", children: [
1518
+ /* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-link-label", children: link.label }),
1519
+ /* @__PURE__ */ jsx24("span", { className: "ss-w-fandash-link-chevron", children: /* @__PURE__ */ jsx24(ChevronIcon, {}) })
1520
+ ] }, `${link.url}-${i}`)) })
1521
+ ] });
1522
+ }
1523
+
1524
+ // src/components/dashboard/ClubFanDashboard.tsx
1525
+ import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
1526
+ function ClubFanDashboard({ dashboard, onTap, ui }) {
1527
+ const orderedCards = [
1528
+ ...dashboard.cards.filter((c) => c.cardType === "countdown"),
1529
+ ...dashboard.cards.filter((c) => c.cardType !== "countdown")
1530
+ ];
1531
+ return /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash", children: [
1532
+ dashboard.greeting ? /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
1533
+ /* @__PURE__ */ jsx25("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ jsx25(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
1534
+ ] });
1535
+ }
1536
+ function FanDashboardCard({ card, onTap, ui }) {
1537
+ switch (card.cardType) {
1538
+ case "fixture":
1539
+ return /* @__PURE__ */ jsx25(FixtureCard, { card, onTap });
1540
+ case "countdown":
1541
+ return /* @__PURE__ */ jsx25(CountdownCard, { card });
1542
+ case "injuries":
1543
+ return /* @__PURE__ */ jsx25(InjuriesCard, { card });
1544
+ case "reasonToBet":
1545
+ return /* @__PURE__ */ jsx25(ReasonToBetCard, { card });
1546
+ case "whereToWatch":
1547
+ return /* @__PURE__ */ jsx25(WhereToWatchCard, { card });
1548
+ case "congestedWeek":
1549
+ return /* @__PURE__ */ jsx25(CongestedWeekCard, { card, onTap });
1550
+ case "transfers":
1551
+ return /* @__PURE__ */ jsx25(TransfersCard, { card });
1552
+ case "links":
1553
+ return /* @__PURE__ */ jsx25(LinksCard, { card });
1554
+ default:
1555
+ return null;
1556
+ }
1557
+ }
1558
+
1290
1559
  // src/components/ChatMessage.tsx
1291
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1560
+ import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
1292
1561
  function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1293
1562
  if (message.role === "user") {
1294
- return /* @__PURE__ */ jsx17("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx17("div", { className: "ss-w-bubble", children: message.text }) });
1563
+ return /* @__PURE__ */ jsx26("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx26("div", { className: "ss-w-bubble", children: message.text }) });
1295
1564
  }
1296
- return /* @__PURE__ */ jsxs13("div", { className: "ss-w-msg ss-w-bot", children: [
1297
- message.text && !message.greetingDashboard ? /* @__PURE__ */ jsx17(Markdown, { text: message.text }) : null,
1298
- message.greetingDashboard ? /* @__PURE__ */ jsx17(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1299
- /* @__PURE__ */ jsx17(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1300
- /* @__PURE__ */ jsx17(BettingInsightList, { insights: message.insights, ui, slip }),
1301
- /* @__PURE__ */ jsx17(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1302
- /* @__PURE__ */ jsx17(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1303
- /* @__PURE__ */ jsx17(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1565
+ const onFanDashboardTap = (card) => {
1566
+ onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || "" });
1567
+ };
1568
+ return /* @__PURE__ */ jsxs22("div", { className: "ss-w-msg ss-w-bot", children: [
1569
+ message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ jsx26(Markdown, { text: message.text }) : null,
1570
+ message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ jsx26(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1571
+ message.clubFanDashboard ? /* @__PURE__ */ jsx26(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
1572
+ /* @__PURE__ */ jsx26(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1573
+ /* @__PURE__ */ jsx26(BettingInsightList, { insights: message.insights, ui, slip }),
1574
+ /* @__PURE__ */ jsx26(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1575
+ /* @__PURE__ */ jsx26(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1576
+ /* @__PURE__ */ jsx26(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1304
1577
  ] });
1305
1578
  }
1306
1579
 
1307
1580
  // src/components/IntentChips.tsx
1308
- import { jsx as jsx18 } from "react/jsx-runtime";
1581
+ import { jsx as jsx27 } from "react/jsx-runtime";
1309
1582
  function IntentChips({ chips, onPick }) {
1310
1583
  if (chips.length === 0) return null;
1311
- return /* @__PURE__ */ jsx18("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1584
+ return /* @__PURE__ */ jsx27("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx27("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1312
1585
  }
1313
1586
 
1314
1587
  // src/scroll.ts
@@ -1318,18 +1591,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1318
1591
  }
1319
1592
 
1320
1593
  // src/components/MessageList.tsx
1321
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1594
+ import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
1322
1595
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1323
1596
  const { state, send } = controller;
1324
1597
  const listRef = useRef2(null);
1325
1598
  const endRef = useRef2(null);
1326
1599
  const pinnedRef = useRef2(true);
1327
- useEffect3(() => {
1600
+ useEffect4(() => {
1328
1601
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1329
1602
  }, [state.messages, state.status]);
1330
1603
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1331
- const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
1332
- return /* @__PURE__ */ jsxs14(
1604
+ const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
1605
+ return /* @__PURE__ */ jsxs23(
1333
1606
  "div",
1334
1607
  {
1335
1608
  className: "ss-w-list",
@@ -1339,12 +1612,12 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1339
1612
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1340
1613
  },
1341
1614
  children: [
1342
- state.messages.map((m) => /* @__PURE__ */ jsx19(
1615
+ state.messages.map((m) => /* @__PURE__ */ jsx28(
1343
1616
  ChatMessage,
1344
1617
  {
1345
1618
  message: m,
1346
1619
  disabled: state.isStreaming,
1347
- onAct: (a) => send(a.message, { actionId: a.actionId, displayText: a.label }),
1620
+ onAct: (a) => send(a.message, { actionId: a.actionId, actionRef: a.actionRef, displayText: a.label }),
1348
1621
  onTap: (tile, index) => {
1349
1622
  send(tile.actionValue, { displayText: tile.title });
1350
1623
  if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
@@ -1354,25 +1627,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1354
1627
  },
1355
1628
  m.id
1356
1629
  )),
1357
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx19(ActionButtons, { actions: [], loading: true, onAct: () => {
1630
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx28(ActionButtons, { actions: [], loading: true, onAct: () => {
1358
1631
  } }) : null,
1359
- state.status ? /* @__PURE__ */ jsx19("div", { className: "ss-w-status", children: state.status }) : null,
1360
- state.error ? /* @__PURE__ */ jsxs14("div", { className: "ss-w-error", role: "alert", children: [
1361
- /* @__PURE__ */ jsx19("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1362
- /* @__PURE__ */ jsx19("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1632
+ state.status ? /* @__PURE__ */ jsx28("div", { className: "ss-w-status", children: state.status }) : null,
1633
+ state.error ? /* @__PURE__ */ jsxs23("div", { className: "ss-w-error", role: "alert", children: [
1634
+ /* @__PURE__ */ jsx28("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1635
+ /* @__PURE__ */ jsx28("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1363
1636
  ] }) : null,
1364
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx19(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1365
- /* @__PURE__ */ jsx19("div", { ref: endRef })
1637
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx28(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1638
+ /* @__PURE__ */ jsx28("div", { ref: endRef })
1366
1639
  ]
1367
1640
  }
1368
1641
  );
1369
1642
  }
1370
1643
 
1371
1644
  // src/components/ChatInput.tsx
1372
- import { useState as useState6 } from "react";
1373
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1645
+ import { useState as useState7 } from "react";
1646
+ import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
1374
1647
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1375
- const [value, setValue] = useState6("");
1648
+ const [value, setValue] = useState7("");
1376
1649
  const submit = () => {
1377
1650
  const t = value.trim();
1378
1651
  if (!t) return;
@@ -1385,18 +1658,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1385
1658
  submit();
1386
1659
  }
1387
1660
  };
1388
- return /* @__PURE__ */ jsxs15("div", { className: "ss-w-input", children: [
1389
- /* @__PURE__ */ jsx20("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1390
- streaming ? /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx20("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx20(SendIcon, {}) })
1661
+ return /* @__PURE__ */ jsxs24("div", { className: "ss-w-input", children: [
1662
+ /* @__PURE__ */ jsx29("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1663
+ streaming ? /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx29("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx29(SendIcon, {}) })
1391
1664
  ] });
1392
1665
  }
1393
1666
 
1394
1667
  // src/components/ChatPanel.tsx
1395
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1668
+ import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
1396
1669
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1397
1670
  function useIsModal() {
1398
- const [modal, setModal] = useState7(false);
1399
- useEffect4(() => {
1671
+ const [modal, setModal] = useState8(false);
1672
+ useEffect5(() => {
1400
1673
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1401
1674
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1402
1675
  const sync = () => setModal(mql.matches);
@@ -1409,17 +1682,17 @@ function useIsModal() {
1409
1682
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1410
1683
  const { state, close, stop, send } = controller;
1411
1684
  const isModal = useIsModal();
1412
- useEffect4(() => {
1685
+ useEffect5(() => {
1413
1686
  const onKey = (e) => {
1414
1687
  if (e.key === "Escape") close();
1415
1688
  };
1416
1689
  window.addEventListener("keydown", onKey);
1417
1690
  return () => window.removeEventListener("keydown", onKey);
1418
1691
  }, [close]);
1419
- return /* @__PURE__ */ jsxs16("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1420
- /* @__PURE__ */ jsx21(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1421
- /* @__PURE__ */ jsx21(MessageList, { controller, ui, slip, onDashboardTap }),
1422
- /* @__PURE__ */ jsx21(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1692
+ return /* @__PURE__ */ jsxs25("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1693
+ /* @__PURE__ */ jsx30(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1694
+ /* @__PURE__ */ jsx30(MessageList, { controller, ui, slip, onDashboardTap }),
1695
+ /* @__PURE__ */ jsx30(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1423
1696
  ] });
1424
1697
  }
1425
1698
 
@@ -1772,10 +2045,122 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1772
2045
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
1773
2046
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
1774
2047
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
2048
+
2049
+ /* club fan pre-match dashboard */
2050
+ .ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
2051
+ .ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }
2052
+ .ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }
2053
+
2054
+ /* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both
2055
+ share the same box so the two families read as one system, not two ad hoc layouts. */
2056
+ .ss-w-fandash-card {
2057
+ display: flex; flex-direction: column; gap: 8px;
2058
+ padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);
2059
+ background: var(--ss-w-panel); text-align: left;
2060
+ color: inherit; font: inherit; width: 100%; min-width: 0;
2061
+ }
2062
+ .ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }
2063
+ .ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }
2064
+ .ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }
2065
+
2066
+ /* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label
2067
+ split reused by the fixture head-to-head (and any future stat-row card). */
2068
+ .ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
2069
+ .ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
2070
+ .ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }
2071
+ .ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }
2072
+ .ss-w-fandash-split-label { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); overflow-wrap: anywhere; }
2073
+
2074
+ /* fixture card */
2075
+ .ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }
2076
+ .ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
2077
+ .ss-w-fandash-fixture-team--away { justify-content: flex-end; }
2078
+ .ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }
2079
+ .ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }
2080
+ .ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
2081
+ .ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }
2082
+ .ss-w-fandash-fixture-vs { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
2083
+ /* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */
2084
+ .ss-w-fandash-fixture-meta { display: flex; flex-direction: column; gap: 1px; border-top: 1px solid var(--ss-w-line); padding-top: 8px; }
2085
+ .ss-w-fandash-fixture-metarow { display: flex; align-items: baseline; gap: 9px; }
2086
+ .ss-w-fandash-fixture-metakey { flex: none; width: 44px; font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
2087
+ .ss-w-fandash-fixture-metaval { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
2088
+ .ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }
2089
+ /* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */
2090
+ .ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }
2091
+ /* extra breathing room between the tally row and the fact beyond the card's own gap */
2092
+ .ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }
2093
+
2094
+ /* last-five: one row per side, team name left, form pills right */
2095
+ .ss-w-fandash-fixture-form { display: flex; flex-direction: column; gap: 5px; }
2096
+ .ss-w-fandash-formrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2097
+ .ss-w-fandash-formrow-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 600; }
2098
+ .ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }
2099
+ .ss-w-fandash-form-pill {
2100
+ display: inline-grid; place-items: center; width: 16px; height: 16px;
2101
+ border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;
2102
+ }
2103
+ .ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }
2104
+ .ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }
2105
+ .ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }
2106
+
2107
+ /* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each
2108
+ segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not
2109
+ repeated here; the fixture card below carries it. */
2110
+ .ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2111
+ .ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }
2112
+ .ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }
2113
+ .ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }
2114
+ .ss-w-fandash-countdown-unit { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); margin-top: 3px; }
2115
+ .ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }
2116
+
2117
+ /* injuries + transfers: two-column ours/theirs, in/out */
2118
+ .ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
2119
+ /* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */
2120
+ .ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }
2121
+ .ss-w-fandash-injuries-divider { background: var(--ss-w-line); }
2122
+ .ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
2123
+ .ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }
2124
+ .ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }
2125
+ .ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }
2126
+ .ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }
2127
+ .ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2128
+ .ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }
2129
+ .ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }
2130
+ .ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }
2131
+ .ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }
2132
+ .ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }
2133
+ .ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }
2134
+ .ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }
2135
+ .ss-w-fandash-transfer-type { align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 1px 7px; margin-top: 2px; }
2136
+
2137
+ /* reason-to-bet */
2138
+ .ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
2139
+ .ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }
2140
+ .ss-w-fandash-reason-item::before { content: "\u2022"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }
2141
+
2142
+ /* where-to-watch */
2143
+ .ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }
2144
+ .ss-w-fandash-station-chip { font-size: 11.5px; font-weight: 600; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 999px; padding: 4px 10px; }
2145
+
2146
+ /* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */
2147
+ .ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
2148
+ .ss-w-fandash-congested-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 8px; border-radius: 10px; background: var(--ss-w-bubble); }
2149
+ .ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
2150
+ .ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
2151
+ .ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
2152
+ .ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
2153
+
2154
+ /* links: 2-column grid of tappable tiles */
2155
+ .ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
2156
+ .ss-w-fandash-link-tile { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 11px 13px; border-radius: 10px; border: 1px solid transparent; text-decoration: none; color: inherit; background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); }
2157
+ .ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
2158
+ .ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
2159
+ .ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }
1775
2160
  `;
1776
2161
 
1777
2162
  // src/StatsWidget.tsx
1778
- import { jsx as jsx22 } from "react/jsx-runtime";
2163
+ import { jsx as jsx31 } from "react/jsx-runtime";
1779
2164
  function buildClient(props) {
1780
2165
  try {
1781
2166
  if ("client" in props && props.client) {
@@ -1821,14 +2206,14 @@ function StatsWidget(props) {
1821
2206
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
1822
2207
  [built]
1823
2208
  );
1824
- useEffect5(() => {
2209
+ useEffect6(() => {
1825
2210
  if (!built || !ui.injectStyles) return;
1826
2211
  const node = rootRef.current?.getRootNode();
1827
2212
  if (node) injectStyles(node);
1828
2213
  }, [built, ui.injectStyles]);
1829
2214
  if (!built) return null;
1830
2215
  const attrs = themeAttrs(ui);
1831
- return /* @__PURE__ */ jsx22("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ jsx22(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx22(
2216
+ return /* @__PURE__ */ jsx31("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ jsx31(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx31(
1832
2217
  ChatFab,
1833
2218
  {
1834
2219
  label: ui.launcherLabel,