@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.cjs CHANGED
@@ -36,7 +36,7 @@ __export(index_exports, {
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/StatsWidget.tsx
39
- var import_react11 = require("react");
39
+ var import_react12 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/kickoff.ts
@@ -359,8 +359,9 @@ function toCardVM(card) {
359
359
  function toActionVM(action) {
360
360
  const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
361
361
  const actionId = str(action.actionId) ?? str(action.id);
362
+ const actionRef = str(action.actionRef);
362
363
  const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
363
- return { label, actionId, message };
364
+ return { label, actionId, actionRef, message };
364
365
  }
365
366
  function toChipVM(intent) {
366
367
  const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
@@ -556,8 +557,8 @@ function applyEvent(state, event) {
556
557
  return { ...state, actionsLoading: true, status: event.data.message };
557
558
  case "turn_complete": {
558
559
  const active = activeTurn(state);
559
- const text = active?.text.trim() ?? "";
560
- const popupText = active?.isGreeting && !state.isOpen && text ? text.slice(0, POPUP_MAX) : state.popupText;
560
+ const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? "");
561
+ const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText;
561
562
  return {
562
563
  ...state,
563
564
  isStreaming: false,
@@ -568,7 +569,8 @@ function applyEvent(state, event) {
568
569
  messages: mapActive(state, (t) => ({
569
570
  ...t,
570
571
  done: true,
571
- greetingDashboard: event.data.dashboard ?? void 0
572
+ greetingDashboard: event.data.dashboard ?? void 0,
573
+ clubFanDashboard: event.data.clubFanDashboard ?? void 0
572
574
  }))
573
575
  };
574
576
  }
@@ -765,7 +767,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
765
767
  }
766
768
 
767
769
  // src/components/ChatPanel.tsx
768
- var import_react10 = require("react");
770
+ var import_react11 = require("react");
769
771
 
770
772
  // src/components/ChatHeader.tsx
771
773
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -778,7 +780,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
778
780
  }
779
781
 
780
782
  // src/components/MessageList.tsx
781
- var import_react8 = require("react");
783
+ var import_react9 = require("react");
782
784
 
783
785
  // src/components/Markdown.tsx
784
786
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -1324,28 +1326,299 @@ function GreetingDashboard({ dashboard, onTap }) {
1324
1326
  ] });
1325
1327
  }
1326
1328
 
1327
- // src/components/ChatMessage.tsx
1329
+ // src/components/dashboard/FixtureCard.tsx
1328
1330
  var import_jsx_runtime17 = require("react/jsx-runtime");
1331
+ function resultClass(result) {
1332
+ const upper = result.toUpperCase();
1333
+ if (upper === "W") return "ss-w-fandash-form-pill--win";
1334
+ if (upper === "L") return "ss-w-fandash-form-pill--loss";
1335
+ return "ss-w-fandash-form-pill--draw";
1336
+ }
1337
+ function FormStrip({ form }) {
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-form", children: form.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: `ss-w-fandash-form-pill ${resultClass(r)}`, children: r }, `${r}-${i}`)) });
1339
+ }
1340
+ function FormRow({ name, form }) {
1341
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-formrow", children: [
1342
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-formrow-name", children: name }),
1343
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormStrip, { form })
1344
+ ] });
1345
+ }
1346
+ function FixtureCard({ card, onTap }) {
1347
+ const { data } = card;
1348
+ const h2h = data.h2H;
1349
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1350
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-fixture", onClick: () => onTap(card), children: [
1351
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-eyebrow", children: [
1352
+ card.title,
1353
+ " \xB7 ",
1354
+ data.competition
1355
+ ] }),
1356
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-teams", children: [
1357
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-fixture-team", children: [
1358
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: data.homeCrestUrl ?? void 0, name: data.homeName, kind: "team" }),
1359
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-name", children: data.homeName })
1360
+ ] }),
1361
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-vs", children: "v" }),
1362
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away", children: [
1363
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-name", children: data.awayName }),
1364
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Crest2, { url: data.awayCrestUrl ?? void 0, name: data.awayName, kind: "team" })
1365
+ ] })
1366
+ ] }),
1367
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-meta", children: [
1368
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-metarow", children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metakey", children: data.dateLabel }),
1370
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metaval", children: data.kickoffLabel })
1371
+ ] }),
1372
+ data.venue ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-metarow", children: [
1373
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metakey", children: data.venueLabel }),
1374
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fixture-metaval", children: data.venue })
1375
+ ] }) : null
1376
+ ] }),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1378
+ ] }),
1379
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-lastfive", children: [
1380
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-eyebrow", children: data.formLabel }),
1381
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-fixture-form", children: [
1382
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormRow, { name: data.homeName, form: data.homeForm }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FormRow, { name: data.awayName, form: data.awayForm })
1384
+ ] })
1385
+ ] }),
1386
+ h2h || data.fact ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-h2h", children: [
1387
+ h2h ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1388
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-eyebrow", children: h2h.label }),
1389
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-fandash-split", children: [
1390
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
1391
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.wins }),
1392
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.homeWinsLabel })
1393
+ ] }),
1394
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
1395
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.draws }),
1396
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.drawsLabel })
1397
+ ] }),
1398
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "ss-w-fandash-split-cell", children: [
1399
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-value", children: h2h.losses }),
1400
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-split-label", children: h2h.awayWinsLabel })
1401
+ ] })
1402
+ ] })
1403
+ ] }) : null,
1404
+ data.fact ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ss-w-fandash-fact", children: data.fact }) : null
1405
+ ] }) : null
1406
+ ] });
1407
+ }
1408
+
1409
+ // src/components/dashboard/CountdownCard.tsx
1410
+ var import_react8 = require("react");
1411
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1412
+ var DAY_MS = 864e5;
1413
+ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
1414
+ const totalSeconds = Math.floor((kickoffUnix * 1e3 - nowMs) / 1e3);
1415
+ if (totalSeconds <= 0) return null;
1416
+ const days = Math.floor(totalSeconds / 86400);
1417
+ const hours = Math.floor(totalSeconds % 86400 / 3600);
1418
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
1419
+ const seconds = totalSeconds % 60;
1420
+ const pad = (n) => String(n).padStart(2, "0");
1421
+ if (days > 0) return [{ value: pad(days), unit: "d" }, { value: pad(hours), unit: "h" }];
1422
+ const segs = [{ value: pad(hours), unit: "h" }, { value: pad(minutes), unit: "m" }];
1423
+ if (withSeconds) segs.push({ value: pad(seconds), unit: "s" });
1424
+ return segs;
1425
+ }
1426
+ function CountdownCard({ card }) {
1427
+ const { data } = card;
1428
+ const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
1429
+ const [nowMs, setNowMs] = (0, import_react8.useState)(() => Date.now());
1430
+ const [reduced] = (0, import_react8.useState)(
1431
+ () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
1432
+ );
1433
+ const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
1434
+ (0, import_react8.useEffect)(() => {
1435
+ if (reduced) return;
1436
+ const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
1437
+ return () => window.clearInterval(id);
1438
+ }, [reduced, withinDay]);
1439
+ const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
1440
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-fandash-countdown-top", children: [
1441
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
1442
+ segments ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react8.Fragment, { children: [
1443
+ i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
1444
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
1445
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
1446
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-unit", children: unitLabel[s.unit] })
1447
+ ] })
1448
+ ] }, s.unit)) }) : null
1449
+ ] }) });
1450
+ }
1451
+
1452
+ // src/components/dashboard/InjuriesCard.tsx
1453
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1454
+ function ColHead({ name, crestUrl }) {
1455
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-fandash-injuries-col-head", children: [
1456
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Crest2, { url: crestUrl ?? void 0, name, kind: "team" }),
1457
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injuries-col-head-name", children: name })
1458
+ ] });
1459
+ }
1460
+ function InjuryList({ rows, emptyLabel }) {
1461
+ if (rows.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injuries-empty", children: emptyLabel });
1462
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "ss-w-fandash-injury-list", children: rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "ss-w-fandash-injury-row", children: [
1463
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-name", children: r.playerName }),
1464
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-fandash-injury-meta", children: [
1465
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-status", children: r.status }),
1466
+ r.injuryType ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-type", children: r.injuryType }) : null,
1467
+ r.expectedReturnLabel ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-injury-return", children: r.expectedReturnLabel }) : null
1468
+ ] })
1469
+ ] }, `${r.playerName}-${i}`)) });
1470
+ }
1471
+ function InjuriesCard({ card }) {
1472
+ const { data } = card;
1473
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-injuries", children: [
1474
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1475
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-cols", children: [
1476
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-col", children: [
1477
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColHead, { name: data.oursName, crestUrl: data.oursCrestUrl }),
1478
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InjuryList, { rows: data.ours, emptyLabel: data.emptyLabel })
1479
+ ] }),
1480
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-fandash-injuries-divider" }),
1481
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-fandash-injuries-col", children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColHead, { name: data.theirsName, crestUrl: data.theirsCrestUrl }),
1483
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InjuryList, { rows: data.theirs, emptyLabel: data.emptyLabel })
1484
+ ] })
1485
+ ] })
1486
+ ] });
1487
+ }
1488
+
1489
+ // src/components/dashboard/ReasonToBetCard.tsx
1490
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1491
+ function ReasonToBetCard({ card }) {
1492
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-reasons", children: [
1493
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1494
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "ss-w-fandash-reason-list", children: card.data.angles.map((angle, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { className: "ss-w-fandash-reason-item", children: angle }, `${angle}-${i}`)) })
1495
+ ] });
1496
+ }
1497
+
1498
+ // src/components/dashboard/WhereToWatchCard.tsx
1499
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1500
+ function WhereToWatchCard({ card }) {
1501
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-watch", children: [
1502
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1503
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-stations", children: card.data.stations.map((station, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-fandash-station-chip", children: station }, `${station}-${i}`)) })
1504
+ ] });
1505
+ }
1506
+
1507
+ // src/components/dashboard/CongestedWeekCard.tsx
1508
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1509
+ function CongestedWeekCard({ card, onTap }) {
1510
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested", onClick: () => onTap(card), children: [
1511
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1512
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-fandash-congested-grid", children: card.data.entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "ss-w-fandash-congested-cell", children: [
1513
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-day", children: entry.dayLabel }),
1514
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-opponent", children: entry.opponent }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-comp", children: entry.competition }),
1516
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-congested-time", children: entry.timeLabel })
1517
+ ] }, `${entry.opponent}-${i}`)) }),
1518
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1519
+ ] });
1520
+ }
1521
+
1522
+ // src/components/dashboard/TransfersCard.tsx
1523
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1524
+ function TransferList({ rows }) {
1525
+ if (rows.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-empty", children: "None" });
1526
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "ss-w-fandash-transfer-list", children: rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { className: "ss-w-fandash-transfer-row", children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-name", children: r.playerName }),
1528
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-club", children: r.otherClub }),
1529
+ r.type ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfer-type", children: r.type }) : null
1530
+ ] }, `${r.playerName}-${i}`)) });
1531
+ }
1532
+ function TransfersCard({ card }) {
1533
+ const { data } = card;
1534
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-transfers", children: [
1535
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1536
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-cols", children: [
1537
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-col", children: [
1538
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-col-head", children: "In" }),
1539
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TransferList, { rows: data.in })
1540
+ ] }),
1541
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-fandash-transfers-col", children: [
1542
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-fandash-transfers-col-head", children: "Out" }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TransferList, { rows: data.out })
1544
+ ] })
1545
+ ] })
1546
+ ] });
1547
+ }
1548
+
1549
+ // src/components/dashboard/LinksCard.tsx
1550
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1551
+ function LinksCard({ card }) {
1552
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-links", children: [
1553
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1554
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-fandash-link-grid", children: card.data.links.map((link, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("a", { className: "ss-w-fandash-link-tile", href: link.url, target: "_blank", rel: "noopener noreferrer", children: [
1555
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-link-label", children: link.label }),
1556
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-fandash-link-chevron", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ChevronIcon, {}) })
1557
+ ] }, `${link.url}-${i}`)) })
1558
+ ] });
1559
+ }
1560
+
1561
+ // src/components/dashboard/ClubFanDashboard.tsx
1562
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1563
+ function ClubFanDashboard({ dashboard, onTap, ui }) {
1564
+ const orderedCards = [
1565
+ ...dashboard.cards.filter((c) => c.cardType === "countdown"),
1566
+ ...dashboard.cards.filter((c) => c.cardType !== "countdown")
1567
+ ];
1568
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "ss-w-fandash", children: [
1569
+ dashboard.greeting ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
1570
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
1571
+ ] });
1572
+ }
1573
+ function FanDashboardCard({ card, onTap, ui }) {
1574
+ switch (card.cardType) {
1575
+ case "fixture":
1576
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FixtureCard, { card, onTap });
1577
+ case "countdown":
1578
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CountdownCard, { card });
1579
+ case "injuries":
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(InjuriesCard, { card });
1581
+ case "reasonToBet":
1582
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReasonToBetCard, { card });
1583
+ case "whereToWatch":
1584
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(WhereToWatchCard, { card });
1585
+ case "congestedWeek":
1586
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CongestedWeekCard, { card, onTap });
1587
+ case "transfers":
1588
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TransfersCard, { card });
1589
+ case "links":
1590
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LinksCard, { card });
1591
+ default:
1592
+ return null;
1593
+ }
1594
+ }
1595
+
1596
+ // src/components/ChatMessage.tsx
1597
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1329
1598
  function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1330
1599
  if (message.role === "user") {
1331
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1332
1601
  }
1333
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1334
- message.text && !message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Markdown, { text: message.text }) : null,
1335
- message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1336
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1337
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1338
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1339
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1340
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1602
+ const onFanDashboardTap = (card) => {
1603
+ onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || "" });
1604
+ };
1605
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1606
+ message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Markdown, { text: message.text }) : null,
1607
+ message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1608
+ message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
1609
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1610
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1611
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1612
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1341
1614
  ] });
1342
1615
  }
1343
1616
 
1344
1617
  // src/components/IntentChips.tsx
1345
- var import_jsx_runtime18 = require("react/jsx-runtime");
1618
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1346
1619
  function IntentChips({ chips, onPick }) {
1347
1620
  if (chips.length === 0) return null;
1348
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1349
1622
  }
1350
1623
 
1351
1624
  // src/scroll.ts
@@ -1355,18 +1628,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1355
1628
  }
1356
1629
 
1357
1630
  // src/components/MessageList.tsx
1358
- var import_jsx_runtime19 = require("react/jsx-runtime");
1631
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1359
1632
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1360
1633
  const { state, send } = controller;
1361
- const listRef = (0, import_react8.useRef)(null);
1362
- const endRef = (0, import_react8.useRef)(null);
1363
- const pinnedRef = (0, import_react8.useRef)(true);
1364
- (0, import_react8.useEffect)(() => {
1634
+ const listRef = (0, import_react9.useRef)(null);
1635
+ const endRef = (0, import_react9.useRef)(null);
1636
+ const pinnedRef = (0, import_react9.useRef)(true);
1637
+ (0, import_react9.useEffect)(() => {
1365
1638
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1366
1639
  }, [state.messages, state.status]);
1367
1640
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1368
- const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
1369
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1641
+ const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
1642
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1370
1643
  "div",
1371
1644
  {
1372
1645
  className: "ss-w-list",
@@ -1376,12 +1649,12 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1376
1649
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1377
1650
  },
1378
1651
  children: [
1379
- state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1652
+ state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1380
1653
  ChatMessage,
1381
1654
  {
1382
1655
  message: m,
1383
1656
  disabled: state.isStreaming,
1384
- onAct: (a) => send(a.message, { actionId: a.actionId, displayText: a.label }),
1657
+ onAct: (a) => send(a.message, { actionId: a.actionId, actionRef: a.actionRef, displayText: a.label }),
1385
1658
  onTap: (tile, index) => {
1386
1659
  send(tile.actionValue, { displayText: tile.title });
1387
1660
  if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
@@ -1391,25 +1664,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1391
1664
  },
1392
1665
  m.id
1393
1666
  )),
1394
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1667
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1395
1668
  } }) : null,
1396
- state.status ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1397
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1398
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1399
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1669
+ state.status ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1670
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1671
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1672
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1400
1673
  ] }) : null,
1401
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1402
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: endRef })
1674
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1675
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { ref: endRef })
1403
1676
  ]
1404
1677
  }
1405
1678
  );
1406
1679
  }
1407
1680
 
1408
1681
  // src/components/ChatInput.tsx
1409
- var import_react9 = require("react");
1410
- var import_jsx_runtime20 = require("react/jsx-runtime");
1682
+ var import_react10 = require("react");
1683
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1411
1684
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1412
- const [value, setValue] = (0, import_react9.useState)("");
1685
+ const [value, setValue] = (0, import_react10.useState)("");
1413
1686
  const submit = () => {
1414
1687
  const t = value.trim();
1415
1688
  if (!t) return;
@@ -1422,18 +1695,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1422
1695
  submit();
1423
1696
  }
1424
1697
  };
1425
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-input", children: [
1426
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1427
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SendIcon, {}) })
1698
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "ss-w-input", children: [
1699
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1700
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SendIcon, {}) })
1428
1701
  ] });
1429
1702
  }
1430
1703
 
1431
1704
  // src/components/ChatPanel.tsx
1432
- var import_jsx_runtime21 = require("react/jsx-runtime");
1705
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1433
1706
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1434
1707
  function useIsModal() {
1435
- const [modal, setModal] = (0, import_react10.useState)(false);
1436
- (0, import_react10.useEffect)(() => {
1708
+ const [modal, setModal] = (0, import_react11.useState)(false);
1709
+ (0, import_react11.useEffect)(() => {
1437
1710
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1438
1711
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1439
1712
  const sync = () => setModal(mql.matches);
@@ -1446,17 +1719,17 @@ function useIsModal() {
1446
1719
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1447
1720
  const { state, close, stop, send } = controller;
1448
1721
  const isModal = useIsModal();
1449
- (0, import_react10.useEffect)(() => {
1722
+ (0, import_react11.useEffect)(() => {
1450
1723
  const onKey = (e) => {
1451
1724
  if (e.key === "Escape") close();
1452
1725
  };
1453
1726
  window.addEventListener("keydown", onKey);
1454
1727
  return () => window.removeEventListener("keydown", onKey);
1455
1728
  }, [close]);
1456
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1457
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1458
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1459
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1730
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1731
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1460
1733
  ] });
1461
1734
  }
1462
1735
 
@@ -1809,10 +2082,122 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1809
2082
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
1810
2083
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
1811
2084
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
2085
+
2086
+ /* club fan pre-match dashboard */
2087
+ .ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
2088
+ .ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }
2089
+ .ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }
2090
+
2091
+ /* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both
2092
+ share the same box so the two families read as one system, not two ad hoc layouts. */
2093
+ .ss-w-fandash-card {
2094
+ display: flex; flex-direction: column; gap: 8px;
2095
+ padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);
2096
+ background: var(--ss-w-panel); text-align: left;
2097
+ color: inherit; font: inherit; width: 100%; min-width: 0;
2098
+ }
2099
+ .ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }
2100
+ .ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }
2101
+ .ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }
2102
+
2103
+ /* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label
2104
+ split reused by the fixture head-to-head (and any future stat-row card). */
2105
+ .ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
2106
+ .ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
2107
+ .ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }
2108
+ .ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }
2109
+ .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; }
2110
+
2111
+ /* fixture card */
2112
+ .ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }
2113
+ .ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
2114
+ .ss-w-fandash-fixture-team--away { justify-content: flex-end; }
2115
+ .ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }
2116
+ .ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }
2117
+ .ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
2118
+ .ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }
2119
+ .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); }
2120
+ /* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */
2121
+ .ss-w-fandash-fixture-meta { display: flex; flex-direction: column; gap: 1px; border-top: 1px solid var(--ss-w-line); padding-top: 8px; }
2122
+ .ss-w-fandash-fixture-metarow { display: flex; align-items: baseline; gap: 9px; }
2123
+ .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); }
2124
+ .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); }
2125
+ .ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }
2126
+ /* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */
2127
+ .ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }
2128
+ /* extra breathing room between the tally row and the fact beyond the card's own gap */
2129
+ .ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }
2130
+
2131
+ /* last-five: one row per side, team name left, form pills right */
2132
+ .ss-w-fandash-fixture-form { display: flex; flex-direction: column; gap: 5px; }
2133
+ .ss-w-fandash-formrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2134
+ .ss-w-fandash-formrow-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 600; }
2135
+ .ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }
2136
+ .ss-w-fandash-form-pill {
2137
+ display: inline-grid; place-items: center; width: 16px; height: 16px;
2138
+ border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;
2139
+ }
2140
+ .ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }
2141
+ .ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }
2142
+ .ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }
2143
+
2144
+ /* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each
2145
+ segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not
2146
+ repeated here; the fixture card below carries it. */
2147
+ .ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2148
+ .ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }
2149
+ .ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }
2150
+ .ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }
2151
+ .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; }
2152
+ .ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }
2153
+
2154
+ /* injuries + transfers: two-column ours/theirs, in/out */
2155
+ .ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
2156
+ /* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */
2157
+ .ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }
2158
+ .ss-w-fandash-injuries-divider { background: var(--ss-w-line); }
2159
+ .ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
2160
+ .ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }
2161
+ .ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }
2162
+ .ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }
2163
+ .ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }
2164
+ .ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2165
+ .ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }
2166
+ .ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }
2167
+ .ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }
2168
+ .ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }
2169
+ .ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }
2170
+ .ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }
2171
+ .ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }
2172
+ .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; }
2173
+
2174
+ /* reason-to-bet */
2175
+ .ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
2176
+ .ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }
2177
+ .ss-w-fandash-reason-item::before { content: "\u2022"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }
2178
+
2179
+ /* where-to-watch */
2180
+ .ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }
2181
+ .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; }
2182
+
2183
+ /* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */
2184
+ .ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
2185
+ .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); }
2186
+ .ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }
2187
+ .ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
2188
+ .ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
2189
+ .ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }
2190
+
2191
+ /* links: 2-column grid of tappable tiles */
2192
+ .ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
2193
+ .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)); }
2194
+ .ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
2195
+ .ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
2196
+ .ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }
1812
2197
  `;
1813
2198
 
1814
2199
  // src/StatsWidget.tsx
1815
- var import_jsx_runtime22 = require("react/jsx-runtime");
2200
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1816
2201
  function buildClient(props) {
1817
2202
  try {
1818
2203
  if ("client" in props && props.client) {
@@ -1837,11 +2222,11 @@ function injectStyles(root) {
1837
2222
  function StatsWidget(props) {
1838
2223
  const injectedClient = "client" in props ? props.client : void 0;
1839
2224
  const cfg = props.config;
1840
- const built = (0, import_react11.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
1841
- const ui = (0, import_react11.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
1842
- const rootRef = (0, import_react11.useRef)(null);
2225
+ const built = (0, import_react12.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
2226
+ const ui = (0, import_react12.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
2227
+ const rootRef = (0, import_react12.useRef)(null);
1843
2228
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
1844
- const slip = (0, import_react11.useMemo)(
2229
+ const slip = (0, import_react12.useMemo)(
1845
2230
  () => ({
1846
2231
  onAddToSlip: props.config?.onAddToSlip,
1847
2232
  conversationId: controller.state.conversationId ?? void 0,
@@ -1854,18 +2239,18 @@ function StatsWidget(props) {
1854
2239
  }),
1855
2240
  [props.config?.onAddToSlip, controller.state.conversationId, built]
1856
2241
  );
1857
- const onDashboardTap = (0, import_react11.useMemo)(
2242
+ const onDashboardTap = (0, import_react12.useMemo)(
1858
2243
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
1859
2244
  [built]
1860
2245
  );
1861
- (0, import_react11.useEffect)(() => {
2246
+ (0, import_react12.useEffect)(() => {
1862
2247
  if (!built || !ui.injectStyles) return;
1863
2248
  const node = rootRef.current?.getRootNode();
1864
2249
  if (node) injectStyles(node);
1865
2250
  }, [built, ui.injectStyles]);
1866
2251
  if (!built) return null;
1867
2252
  const attrs = themeAttrs(ui);
1868
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("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__ */ (0, import_jsx_runtime22.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2253
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("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__ */ (0, import_jsx_runtime31.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1869
2254
  ChatFab,
1870
2255
  {
1871
2256
  label: ui.launcherLabel,