@sensiblestats/widget-react 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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_react12 = require("react");
39
+ var import_react13 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/kickoff.ts
@@ -262,7 +262,7 @@ function themeAttrs(ui) {
262
262
  }
263
263
 
264
264
  // src/useChatStream.ts
265
- var import_react = require("react");
265
+ var import_react2 = require("react");
266
266
  var import_widget_sdk3 = require("@sensiblestats/widget-sdk");
267
267
 
268
268
  // src/reducer.ts
@@ -604,28 +604,71 @@ function reducer(state, action) {
604
604
  return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
605
605
  case "STOP":
606
606
  return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
607
+ case "LIVE_REFRESH":
608
+ return {
609
+ ...state,
610
+ messages: state.messages.map(
611
+ (m) => m.role === "assistant" && m.id === action.messageId && m.clubFanDashboard ? { ...m, clubFanDashboard: { ...m.clubFanDashboard, cards: action.cards } } : m
612
+ )
613
+ };
607
614
  }
608
615
  }
609
616
 
617
+ // src/useLiveDashboardPoll.ts
618
+ var import_react = require("react");
619
+ var POLL_INTERVAL_MS = 6e4;
620
+ function findLiveMessageId(messages) {
621
+ for (const m of messages.slice().reverse()) {
622
+ if (m.role === "assistant" && m.clubFanDashboard?.phase === "live") return m.id;
623
+ }
624
+ return null;
625
+ }
626
+ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
627
+ const messageId = findLiveMessageId(messages);
628
+ const inFlightRef = (0, import_react.useRef)(false);
629
+ (0, import_react.useEffect)(() => {
630
+ if (!messageId) return;
631
+ const tick = async () => {
632
+ if (inFlightRef.current) return;
633
+ inFlightRef.current = true;
634
+ try {
635
+ const payload = await getLiveDashboard();
636
+ if (payload && payload.phase === "live") {
637
+ dispatch({ kind: "LIVE_REFRESH", messageId, cards: payload.cards });
638
+ } else {
639
+ window.clearInterval(id);
640
+ }
641
+ } catch {
642
+ } finally {
643
+ inFlightRef.current = false;
644
+ }
645
+ };
646
+ const id = window.setInterval(() => {
647
+ void tick();
648
+ }, POLL_INTERVAL_MS);
649
+ return () => window.clearInterval(id);
650
+ }, [messageId, dispatch, getLiveDashboard]);
651
+ }
652
+
610
653
  // src/useChatStream.ts
611
654
  var STREAM_FALLBACK_TIMEOUT_MS = 3e4;
612
655
  function useChatStream(conversation, starterTexts, greetingMessage) {
613
- const seed = (0, import_react.useMemo)(() => initialState(starterTexts.map(chipFromText)), []);
614
- const [state, dispatch] = (0, import_react.useReducer)(reducer, seed);
615
- const idRef = (0, import_react.useRef)(0);
616
- const handleRef = (0, import_react.useRef)(null);
617
- const fallbackTimerRef = (0, import_react.useRef)(null);
618
- const stateRef = (0, import_react.useRef)(state);
656
+ const seed = (0, import_react2.useMemo)(() => initialState(starterTexts.map(chipFromText)), []);
657
+ const [state, dispatch] = (0, import_react2.useReducer)(reducer, seed);
658
+ const idRef = (0, import_react2.useRef)(0);
659
+ const handleRef = (0, import_react2.useRef)(null);
660
+ const fallbackTimerRef = (0, import_react2.useRef)(null);
661
+ const stateRef = (0, import_react2.useRef)(state);
619
662
  stateRef.current = state;
620
- const greetedRef = (0, import_react.useRef)(false);
663
+ const greetedRef = (0, import_react2.useRef)(false);
621
664
  const nextId = () => `m${idRef.current++}`;
622
- const clearFallbackTimer = (0, import_react.useCallback)(() => {
665
+ const clearFallbackTimer = (0, import_react2.useCallback)(() => {
623
666
  if (fallbackTimerRef.current != null) {
624
667
  clearTimeout(fallbackTimerRef.current);
625
668
  fallbackTimerRef.current = null;
626
669
  }
627
670
  }, []);
628
- const armFallbackTimer = (0, import_react.useCallback)((onFire) => {
671
+ const armFallbackTimer = (0, import_react2.useCallback)((onFire) => {
629
672
  clearFallbackTimer();
630
673
  fallbackTimerRef.current = setTimeout(() => {
631
674
  fallbackTimerRef.current = null;
@@ -634,7 +677,7 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
634
677
  onFire();
635
678
  }, STREAM_FALLBACK_TIMEOUT_MS);
636
679
  }, [clearFallbackTimer]);
637
- const consume = (0, import_react.useCallback)((handle, onError) => {
680
+ const consume = (0, import_react2.useCallback)((handle, onError) => {
638
681
  ;
639
682
  (async () => {
640
683
  try {
@@ -652,7 +695,7 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
652
695
  }
653
696
  })();
654
697
  }, [clearFallbackTimer]);
655
- const run = (0, import_react.useCallback)((input, displayText) => {
698
+ const run = (0, import_react2.useCallback)((input, displayText) => {
656
699
  handleRef.current?.cancel();
657
700
  clearFallbackTimer();
658
701
  dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
@@ -664,16 +707,16 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
664
707
  });
665
708
  consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
666
709
  }, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
667
- const send = (0, import_react.useCallback)((text, opts) => {
710
+ const send = (0, import_react2.useCallback)((text, opts) => {
668
711
  const trimmed = text.trim();
669
712
  if (!trimmed) return;
670
713
  run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText);
671
714
  }, [run]);
672
- const retry = (0, import_react.useCallback)(() => {
715
+ const retry = (0, import_react2.useCallback)(() => {
673
716
  const last = stateRef.current.lastUserInput;
674
717
  if (last) run(last, stateRef.current.lastDisplayText ?? void 0);
675
718
  }, [run]);
676
- (0, import_react.useEffect)(() => {
719
+ (0, import_react2.useEffect)(() => {
677
720
  const message = greetingMessage?.trim();
678
721
  if (!message || greetedRef.current) return;
679
722
  greetedRef.current = true;
@@ -689,24 +732,26 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
689
732
  dispatch({ kind: "STOP" });
690
733
  }
691
734
  }, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
692
- const open = (0, import_react.useCallback)(() => dispatch({ kind: "OPEN" }), []);
693
- const close = (0, import_react.useCallback)(() => {
735
+ const open = (0, import_react2.useCallback)(() => dispatch({ kind: "OPEN" }), []);
736
+ const close = (0, import_react2.useCallback)(() => {
694
737
  handleRef.current?.cancel();
695
738
  handleRef.current = null;
696
739
  clearFallbackTimer();
697
740
  dispatch({ kind: "CLOSE" });
698
741
  }, [clearFallbackTimer]);
699
- const stop = (0, import_react.useCallback)(() => {
742
+ const stop = (0, import_react2.useCallback)(() => {
700
743
  handleRef.current?.cancel();
701
744
  handleRef.current = null;
702
745
  clearFallbackTimer();
703
746
  dispatch({ kind: "STOP" });
704
747
  }, [clearFallbackTimer]);
705
- const toggle = (0, import_react.useCallback)(() => {
748
+ const toggle = (0, import_react2.useCallback)(() => {
706
749
  if (stateRef.current.isOpen) close();
707
750
  else open();
708
751
  }, [close, open]);
709
- const dismissPopup = (0, import_react.useCallback)(() => dispatch({ kind: "DISMISS_POPUP" }), []);
752
+ const dismissPopup = (0, import_react2.useCallback)(() => dispatch({ kind: "DISMISS_POPUP" }), []);
753
+ const getLiveDashboard = (0, import_react2.useCallback)(() => conversation.getLiveDashboard(), [conversation]);
754
+ useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard });
710
755
  return { state, open, close, stop, toggle, send, retry, dismissPopup };
711
756
  }
712
757
 
@@ -767,7 +812,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
767
812
  }
768
813
 
769
814
  // src/components/ChatPanel.tsx
770
- var import_react11 = require("react");
815
+ var import_react12 = require("react");
771
816
 
772
817
  // src/components/ChatHeader.tsx
773
818
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -780,7 +825,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
780
825
  }
781
826
 
782
827
  // src/components/MessageList.tsx
783
- var import_react9 = require("react");
828
+ var import_react10 = require("react");
784
829
 
785
830
  // src/components/Markdown.tsx
786
831
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -798,7 +843,7 @@ function Markdown({ text }) {
798
843
  }
799
844
 
800
845
  // src/components/EntityCardList.tsx
801
- var import_react2 = require("react");
846
+ var import_react3 = require("react");
802
847
  var import_jsx_runtime6 = require("react/jsx-runtime");
803
848
  var MAX_VISIBLE = 3;
804
849
  var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
@@ -830,7 +875,7 @@ function StatRows({ stats }) {
830
875
  }) });
831
876
  }
832
877
  function CardBody({ c }) {
833
- const [active, setActive] = (0, import_react2.useState)(0);
878
+ const [active, setActive] = (0, import_react3.useState)(0);
834
879
  if (c.scopes.length === 0) return null;
835
880
  const season = c.season ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null;
836
881
  if (c.scopes.length === 1) {
@@ -889,7 +934,7 @@ function EntityCardItem({ c }) {
889
934
  ] });
890
935
  }
891
936
  function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
892
- const [expanded, setExpanded] = (0, import_react2.useState)(false);
937
+ const [expanded, setExpanded] = (0, import_react3.useState)(false);
893
938
  if (cards.length === 0) return null;
894
939
  const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
895
940
  const overflow = cards.length - MAX_VISIBLE;
@@ -900,10 +945,10 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
900
945
  }
901
946
 
902
947
  // src/components/BettingInsightList.tsx
903
- var import_react6 = require("react");
948
+ var import_react7 = require("react");
904
949
 
905
950
  // src/components/AddToSlipButton.tsx
906
- var import_react4 = require("react");
951
+ var import_react5 = require("react");
907
952
  var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
908
953
 
909
954
  // src/slip.ts
@@ -935,11 +980,11 @@ function resultToToast(result, shownOdds, ui) {
935
980
  }
936
981
 
937
982
  // src/components/Toast.tsx
938
- var import_react3 = require("react");
983
+ var import_react4 = require("react");
939
984
  var import_jsx_runtime7 = require("react/jsx-runtime");
940
985
  var DISMISS_MS = 4e3;
941
986
  function Toast({ toast, onDismiss }) {
942
- (0, import_react3.useEffect)(() => {
987
+ (0, import_react4.useEffect)(() => {
943
988
  if (!toast) return;
944
989
  const timer = setTimeout(onDismiss, DISMISS_MS);
945
990
  return () => clearTimeout(timer);
@@ -957,10 +1002,10 @@ function withTimeout(value) {
957
1002
  ]);
958
1003
  }
959
1004
  function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
960
- const [pending, setPending] = (0, import_react4.useState)(false);
961
- const [settled, setSettled] = (0, import_react4.useState)(false);
962
- const [toast, setToast] = (0, import_react4.useState)(null);
963
- const dismiss = (0, import_react4.useCallback)(() => setToast(null), []);
1005
+ const [pending, setPending] = (0, import_react5.useState)(false);
1006
+ const [settled, setSettled] = (0, import_react5.useState)(false);
1007
+ const [toast, setToast] = (0, import_react5.useState)(null);
1008
+ const dismiss = (0, import_react5.useCallback)(() => setToast(null), []);
964
1009
  const handler = slip.onAddToSlip;
965
1010
  if (!ui || !handler || !selection) return null;
966
1011
  const onClick = async () => {
@@ -1024,14 +1069,14 @@ function OddsMovementBadge({
1024
1069
  }
1025
1070
 
1026
1071
  // src/components/Crest.tsx
1027
- var import_react5 = require("react");
1072
+ var import_react6 = require("react");
1028
1073
  var import_jsx_runtime10 = require("react/jsx-runtime");
1029
1074
  function initials2(name) {
1030
1075
  return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
1031
1076
  }
1032
1077
  function Crest2({ url, name, kind }) {
1033
1078
  const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
1034
- const [failed, setFailed] = (0, import_react5.useState)(false);
1079
+ const [failed, setFailed] = (0, import_react6.useState)(false);
1035
1080
  if (url && !failed) {
1036
1081
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1037
1082
  }
@@ -1047,7 +1092,7 @@ function StatRows2({ stats }) {
1047
1092
  ] }, `${s.label}:${s.value}`)) });
1048
1093
  }
1049
1094
  function ScopedStats({ scopes }) {
1050
- const [active, setActive] = (0, import_react6.useState)(0);
1095
+ const [active, setActive] = (0, import_react7.useState)(0);
1051
1096
  const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
1052
1097
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-scoped", children: [
1053
1098
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
@@ -1058,7 +1103,7 @@ function hasStatsContent(it) {
1058
1103
  return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
1059
1104
  }
1060
1105
  function ReasonStrip({ it, ui }) {
1061
- const [open, setOpen] = (0, import_react6.useState)(false);
1106
+ const [open, setOpen] = (0, import_react7.useState)(false);
1062
1107
  const hasScopes = !!it.scopes && it.scopes.length >= 2;
1063
1108
  const hasStats = hasStatsContent(it);
1064
1109
  const hasText = !!it.text;
@@ -1138,7 +1183,7 @@ function BettingInsightList({ insights, ui, slip }) {
1138
1183
  }
1139
1184
 
1140
1185
  // src/components/MarketOddsCardList.tsx
1141
- var import_react7 = require("react");
1186
+ var import_react8 = require("react");
1142
1187
  var import_jsx_runtime12 = require("react/jsx-runtime");
1143
1188
  function OddsRow({ vm, row, ui, slip }) {
1144
1189
  const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
@@ -1150,7 +1195,7 @@ function OddsRow({ vm, row, ui, slip }) {
1150
1195
  ] });
1151
1196
  }
1152
1197
  function MarketOddsCard({ vm, ui, slip }) {
1153
- const [open, setOpen] = (0, import_react7.useState)(false);
1198
+ const [open, setOpen] = (0, import_react8.useState)(false);
1154
1199
  const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
1155
1200
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
1156
1201
  const showHeader = !!vm.competition || vm.isLive || !!kickoff;
@@ -1407,7 +1452,7 @@ function FixtureCard({ card, onTap }) {
1407
1452
  }
1408
1453
 
1409
1454
  // src/components/dashboard/CountdownCard.tsx
1410
- var import_react8 = require("react");
1455
+ var import_react9 = require("react");
1411
1456
  var import_jsx_runtime18 = require("react/jsx-runtime");
1412
1457
  var DAY_MS = 864e5;
1413
1458
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -1426,12 +1471,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
1426
1471
  function CountdownCard({ card }) {
1427
1472
  const { data } = card;
1428
1473
  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)(
1474
+ const [nowMs, setNowMs] = (0, import_react9.useState)(() => Date.now());
1475
+ const [reduced] = (0, import_react9.useState)(
1431
1476
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
1432
1477
  );
1433
1478
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
1434
- (0, import_react8.useEffect)(() => {
1479
+ (0, import_react9.useEffect)(() => {
1435
1480
  if (reduced) return;
1436
1481
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
1437
1482
  return () => window.clearInterval(id);
@@ -1439,7 +1484,7 @@ function CountdownCard({ card }) {
1439
1484
  const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
1440
1485
  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
1486
  /* @__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: [
1487
+ 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_react9.Fragment, { children: [
1443
1488
  i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
1444
1489
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
1445
1490
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
@@ -1628,77 +1673,198 @@ function PostMatchNextCard({ card }) {
1628
1673
  ] });
1629
1674
  }
1630
1675
 
1631
- // src/components/dashboard/ClubFanDashboard.tsx
1676
+ // src/components/dashboard/RestingNextCard.tsx
1632
1677
  var import_jsx_runtime30 = require("react/jsx-runtime");
1678
+ function RestingNextCard({ card, onTap }) {
1679
+ const { data } = card;
1680
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-next", onClick: () => onTap(card), children: [
1681
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1682
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ss-w-fandash-resting-next-row", children: [
1683
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ss-w-fandash-resting-next-when", children: data.whenLabel }),
1684
+ data.competition ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ss-w-fandash-resting-next-competition", children: data.competition }) : null
1685
+ ] }),
1686
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1687
+ ] });
1688
+ }
1689
+
1690
+ // src/components/dashboard/RestingStandingsCard.tsx
1691
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1692
+ function RestingStandingsCard({ card, onTap }) {
1693
+ const { data } = card;
1694
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-standings", onClick: () => onTap(card), children: [
1695
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1696
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "ss-w-fandash-resting-standings-row", children: [
1697
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "ss-w-fandash-resting-standings-position", children: data.positionLabel }),
1698
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "ss-w-fandash-resting-standings-record", children: data.recordLabel })
1699
+ ] }),
1700
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1701
+ ] });
1702
+ }
1703
+
1704
+ // src/components/dashboard/RestingSeasonCard.tsx
1705
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1706
+ function RestingSeasonCard({ card, onTap }) {
1707
+ const { data } = card;
1708
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-season", onClick: () => onTap(card), children: [
1709
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1710
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "ss-w-fandash-resting-season-rows", children: [
1711
+ data.scorerLabel ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ss-w-fandash-resting-season-row", children: data.scorerLabel }) : null,
1712
+ data.playerLabel ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ss-w-fandash-resting-season-row", children: data.playerLabel }) : null,
1713
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ss-w-fandash-resting-season-row", children: data.tallyLabel })
1714
+ ] }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1716
+ ] });
1717
+ }
1718
+
1719
+ // src/components/dashboard/RestingFormCard.tsx
1720
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1721
+ function resultClass2(result) {
1722
+ const upper = result.toUpperCase();
1723
+ if (upper === "W") return "ss-w-fandash-form-pill--win";
1724
+ if (upper === "L") return "ss-w-fandash-form-pill--loss";
1725
+ return "ss-w-fandash-form-pill--draw";
1726
+ }
1727
+ function RestingFormCard({ card }) {
1728
+ const { data } = card;
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-resting-form", children: [
1730
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1731
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "ss-w-fandash-form", children: data.letters.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: `ss-w-fandash-form-pill ${resultClass2(r)}`, children: r }, `${r}-${i}`)) })
1732
+ ] });
1733
+ }
1734
+
1735
+ // src/components/dashboard/LiveScoreCard.tsx
1736
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1737
+ function LiveScoreCard({ card }) {
1738
+ const { data } = card;
1739
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-score", children: [
1740
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1741
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-postmatch-scoreboard", children: [
1742
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-postmatch-team", children: data.homeName }),
1743
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-postmatch-score", children: data.homeScore }),
1744
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-postmatch-sep", children: "\u2013" }),
1745
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-postmatch-score", children: data.awayScore }),
1746
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-postmatch-team ss-w-fandash-postmatch-team--away", children: data.awayName })
1747
+ ] }),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-fandash-live-meta", children: [
1749
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-minute", children: data.minuteLabel }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-status", children: data.statusLabel }),
1751
+ data.competition ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-fandash-live-competition", children: data.competition }) : null
1752
+ ] })
1753
+ ] });
1754
+ }
1755
+
1756
+ // src/components/dashboard/LiveTimelineCard.tsx
1757
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1758
+ function LiveTimelineCard({ card }) {
1759
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-timeline", children: [
1760
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1761
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("ul", { className: "ss-w-fandash-live-event-list", children: card.data.events.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("li", { className: e.scoredByClub ? "ss-w-fandash-live-event ss-w-fandash-live-event--club" : "ss-w-fandash-live-event", children: [
1762
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-event-minute", children: e.minuteLabel }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "ss-w-fandash-live-event-text", children: e.text })
1764
+ ] }, `${e.minuteLabel}-${i}`)) })
1765
+ ] });
1766
+ }
1767
+
1768
+ // src/components/dashboard/LiveStatsCard.tsx
1769
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1770
+ function LiveStatsCard({ card }) {
1771
+ const { data } = card;
1772
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "ss-w-fandash-card ss-w-fandash-live-stats", children: [
1773
+ card.title ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1774
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "ss-w-fandash-live-stat-rows", children: data.rows.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "ss-w-fandash-live-stat-row", children: [
1775
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-live-stat-value", children: r.clubValue }),
1776
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-live-stat-label", children: r.label }),
1777
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-live-stat-value", children: r.oppValue })
1778
+ ] }, `${r.label}-${i}`)) }),
1779
+ data.momentumLabel ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "ss-w-fandash-live-momentum", children: data.momentumLabel }) : null
1780
+ ] });
1781
+ }
1782
+
1783
+ // src/components/dashboard/ClubFanDashboard.tsx
1784
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1633
1785
  function ClubFanDashboard({ dashboard, onTap, ui }) {
1634
1786
  const orderedCards = [
1635
1787
  ...dashboard.cards.filter((c) => c.cardType === "countdown"),
1636
1788
  ...dashboard.cards.filter((c) => c.cardType !== "countdown")
1637
1789
  ];
1638
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ss-w-fandash", children: [
1639
- dashboard.greeting ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
1640
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
1790
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "ss-w-fandash", children: [
1791
+ dashboard.greeting ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ss-w-fandash-greeting", children: dashboard.greeting }) : null,
1792
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "ss-w-fandash-cards", children: orderedCards.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(FanDashboardCard, { card, onTap, ui }, `${card.cardType}-${i}`)) })
1641
1793
  ] });
1642
1794
  }
1643
1795
  function FanDashboardCard({ card, onTap, ui }) {
1644
1796
  switch (card.cardType) {
1645
1797
  case "fixture":
1646
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(FixtureCard, { card, onTap });
1798
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(FixtureCard, { card, onTap });
1647
1799
  case "countdown":
1648
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CountdownCard, { card });
1800
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CountdownCard, { card });
1649
1801
  case "injuries":
1650
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(InjuriesCard, { card });
1802
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(InjuriesCard, { card });
1651
1803
  case "reasonToBet":
1652
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReasonToBetCard, { card });
1804
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReasonToBetCard, { card });
1653
1805
  case "whereToWatch":
1654
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(WhereToWatchCard, { card });
1806
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(WhereToWatchCard, { card });
1655
1807
  case "congestedWeek":
1656
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(CongestedWeekCard, { card, onTap });
1808
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CongestedWeekCard, { card, onTap });
1657
1809
  case "transfers":
1658
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TransfersCard, { card });
1810
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TransfersCard, { card });
1659
1811
  case "links":
1660
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(LinksCard, { card });
1812
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LinksCard, { card });
1661
1813
  case "postMatchResult":
1662
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PostMatchResultCard, { card });
1814
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PostMatchResultCard, { card });
1663
1815
  case "postMatchGoals":
1664
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PostMatchGoalsCard, { card, onTap });
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PostMatchGoalsCard, { card, onTap });
1665
1817
  case "postMatchStats":
1666
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PostMatchStatsCard, { card, onTap });
1818
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PostMatchStatsCard, { card, onTap });
1667
1819
  case "postMatchTopPerformer":
1668
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PostMatchTopPerformerCard, { card, onTap });
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PostMatchTopPerformerCard, { card, onTap });
1669
1821
  case "postMatchNext":
1670
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(PostMatchNextCard, { card });
1822
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PostMatchNextCard, { card });
1823
+ case "restingNext":
1824
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RestingNextCard, { card, onTap });
1825
+ case "restingStandings":
1826
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RestingStandingsCard, { card, onTap });
1827
+ case "restingSeason":
1828
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RestingSeasonCard, { card, onTap });
1829
+ case "restingForm":
1830
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RestingFormCard, { card });
1831
+ case "liveScore":
1832
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LiveScoreCard, { card });
1833
+ case "liveTimeline":
1834
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LiveTimelineCard, { card });
1835
+ case "liveStats":
1836
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LiveStatsCard, { card });
1671
1837
  default:
1672
1838
  return null;
1673
1839
  }
1674
1840
  }
1675
1841
 
1676
1842
  // src/components/ChatMessage.tsx
1677
- var import_jsx_runtime31 = require("react/jsx-runtime");
1843
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1678
1844
  function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1679
1845
  if (message.role === "user") {
1680
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1846
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1681
1847
  }
1682
1848
  const onFanDashboardTap = (card) => {
1683
1849
  onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || "" });
1684
1850
  };
1685
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1686
- message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Markdown, { text: message.text }) : null,
1687
- message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1688
- message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
1689
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1690
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1691
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1692
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1693
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1851
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1852
+ message.text && !message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Markdown, { text: message.text }) : null,
1853
+ message.greetingDashboard && !message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1854
+ message.clubFanDashboard ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ClubFanDashboard, { dashboard: message.clubFanDashboard, onTap: onFanDashboardTap, ui }) : null,
1855
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1856
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1857
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1859
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1694
1860
  ] });
1695
1861
  }
1696
1862
 
1697
1863
  // src/components/IntentChips.tsx
1698
- var import_jsx_runtime32 = require("react/jsx-runtime");
1864
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1699
1865
  function IntentChips({ chips, onPick }) {
1700
1866
  if (chips.length === 0) return null;
1701
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1867
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1702
1868
  }
1703
1869
 
1704
1870
  // src/scroll.ts
@@ -1708,18 +1874,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1708
1874
  }
1709
1875
 
1710
1876
  // src/components/MessageList.tsx
1711
- var import_jsx_runtime33 = require("react/jsx-runtime");
1877
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1712
1878
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1713
1879
  const { state, send } = controller;
1714
- const listRef = (0, import_react9.useRef)(null);
1715
- const endRef = (0, import_react9.useRef)(null);
1716
- const pinnedRef = (0, import_react9.useRef)(true);
1717
- (0, import_react9.useEffect)(() => {
1880
+ const listRef = (0, import_react10.useRef)(null);
1881
+ const endRef = (0, import_react10.useRef)(null);
1882
+ const pinnedRef = (0, import_react10.useRef)(true);
1883
+ (0, import_react10.useEffect)(() => {
1718
1884
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1719
1885
  }, [state.messages, state.status]);
1720
1886
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1721
1887
  const hasDashboard = state.messages.some((m) => m.role === "assistant" && (m.greetingDashboard || m.clubFanDashboard));
1722
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
1888
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
1723
1889
  "div",
1724
1890
  {
1725
1891
  className: "ss-w-list",
@@ -1729,7 +1895,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1729
1895
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1730
1896
  },
1731
1897
  children: [
1732
- state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1898
+ state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
1733
1899
  ChatMessage,
1734
1900
  {
1735
1901
  message: m,
@@ -1744,25 +1910,25 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1744
1910
  },
1745
1911
  m.id
1746
1912
  )),
1747
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1913
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1748
1914
  } }) : null,
1749
- state.status ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1750
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1751
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1752
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1915
+ state.status ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1916
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1917
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1918
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1753
1919
  ] }) : null,
1754
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1755
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: endRef })
1920
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1921
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ref: endRef })
1756
1922
  ]
1757
1923
  }
1758
1924
  );
1759
1925
  }
1760
1926
 
1761
1927
  // src/components/ChatInput.tsx
1762
- var import_react10 = require("react");
1763
- var import_jsx_runtime34 = require("react/jsx-runtime");
1928
+ var import_react11 = require("react");
1929
+ var import_jsx_runtime41 = require("react/jsx-runtime");
1764
1930
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1765
- const [value, setValue] = (0, import_react10.useState)("");
1931
+ const [value, setValue] = (0, import_react11.useState)("");
1766
1932
  const submit = () => {
1767
1933
  const t = value.trim();
1768
1934
  if (!t) return;
@@ -1775,18 +1941,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1775
1941
  submit();
1776
1942
  }
1777
1943
  };
1778
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "ss-w-input", children: [
1779
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1780
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SendIcon, {}) })
1944
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "ss-w-input", children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1946
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SendIcon, {}) })
1781
1947
  ] });
1782
1948
  }
1783
1949
 
1784
1950
  // src/components/ChatPanel.tsx
1785
- var import_jsx_runtime35 = require("react/jsx-runtime");
1951
+ var import_jsx_runtime42 = require("react/jsx-runtime");
1786
1952
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1787
1953
  function useIsModal() {
1788
- const [modal, setModal] = (0, import_react11.useState)(false);
1789
- (0, import_react11.useEffect)(() => {
1954
+ const [modal, setModal] = (0, import_react12.useState)(false);
1955
+ (0, import_react12.useEffect)(() => {
1790
1956
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1791
1957
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1792
1958
  const sync = () => setModal(mql.matches);
@@ -1799,17 +1965,17 @@ function useIsModal() {
1799
1965
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1800
1966
  const { state, close, stop, send } = controller;
1801
1967
  const isModal = useIsModal();
1802
- (0, import_react11.useEffect)(() => {
1968
+ (0, import_react12.useEffect)(() => {
1803
1969
  const onKey = (e) => {
1804
1970
  if (e.key === "Escape") close();
1805
1971
  };
1806
1972
  window.addEventListener("keydown", onKey);
1807
1973
  return () => window.removeEventListener("keydown", onKey);
1808
1974
  }, [close]);
1809
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1810
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1811
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1812
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1975
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1976
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1977
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1813
1979
  ] });
1814
1980
  }
1815
1981
 
@@ -2304,10 +2470,52 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2304
2470
  .ss-w-fandash-postmatch-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2305
2471
  .ss-w-fandash-postmatch-next-opponent { font-size: 13px; font-weight: 650; overflow-wrap: anywhere; }
2306
2472
  .ss-w-fandash-postmatch-next-when { flex: none; font-size: 11.5px; color: var(--ss-w-faint); }
2473
+
2474
+ /* resting next: the between-matches fixture teaser -- when-label left, competition badge right */
2475
+ .ss-w-fandash-resting-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2476
+ .ss-w-fandash-resting-next-when { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
2477
+ .ss-w-fandash-resting-next-competition { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }
2478
+
2479
+ /* resting standings: position figure left, W-D-L/points record right */
2480
+ .ss-w-fandash-resting-standings-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
2481
+ .ss-w-fandash-resting-standings-position { font-size: 15px; font-weight: 750; color: var(--ss-w-ink); }
2482
+ .ss-w-fandash-resting-standings-record { font-size: 11.5px; color: var(--ss-w-faint); text-align: right; }
2483
+
2484
+ /* resting season: top scorer / key player / season tally as stacked rows */
2485
+ .ss-w-fandash-resting-season-rows { display: flex; flex-direction: column; gap: 4px; }
2486
+ .ss-w-fandash-resting-season-row { font-size: 12.5px; color: var(--ss-w-ink); }
2487
+
2488
+ /* resting form: reuses the fixture last-five pill classes (ss-w-fandash-form / -form-pill) */
2489
+ .ss-w-fandash-resting-form .ss-w-fandash-form { margin-top: 2px; }
2490
+
2491
+ /* live score: reuses the post-match scoreboard classes for the team/score row, with its own
2492
+ meta row -- minute called out in the accent color, status and competition beside it */
2493
+ .ss-w-fandash-live-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 11.5px; color: var(--ss-w-faint); }
2494
+ .ss-w-fandash-live-minute { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); }
2495
+ .ss-w-fandash-live-status { font-weight: 650; color: var(--ss-w-ink); }
2496
+ .ss-w-fandash-live-competition { color: var(--ss-w-faint); }
2497
+
2498
+ /* live timeline: a plain event list, the club's own events picked out in the accent color --
2499
+ same mechanism as the post-match goal list, plus a minute column */
2500
+ .ss-w-fandash-live-event-list { list-style: none; display: flex; flex-direction: column; gap: 4px; }
2501
+ .ss-w-fandash-live-event { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; color: var(--ss-w-faint); }
2502
+ .ss-w-fandash-live-event--club { color: var(--ss-w-ink); font-weight: 650; }
2503
+ .ss-w-fandash-live-event-minute { flex: none; font-variant-numeric: tabular-nums; color: var(--ss-w-faint); }
2504
+ .ss-w-fandash-live-event--club .ss-w-fandash-live-event-minute { color: var(--ss-w-accent); }
2505
+ .ss-w-fandash-live-event-text { min-width: 0; }
2506
+
2507
+ /* live stats: club value / stat label / opponent value, same 3-column layout as post-match
2508
+ stats, plus an optional momentum line underneath */
2509
+ .ss-w-fandash-live-stat-rows { display: flex; flex-direction: column; gap: 5px; }
2510
+ .ss-w-fandash-live-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; }
2511
+ .ss-w-fandash-live-stat-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
2512
+ .ss-w-fandash-live-stat-row .ss-w-fandash-live-stat-value:last-child { text-align: right; }
2513
+ .ss-w-fandash-live-stat-label { font-size: 10.5px; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }
2514
+ .ss-w-fandash-live-momentum { font-size: 11.5px; font-weight: 650; color: var(--ss-w-accent); }
2307
2515
  `;
2308
2516
 
2309
2517
  // src/StatsWidget.tsx
2310
- var import_jsx_runtime36 = require("react/jsx-runtime");
2518
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2311
2519
  function buildClient(props) {
2312
2520
  try {
2313
2521
  if ("client" in props && props.client) {
@@ -2332,11 +2540,11 @@ function injectStyles(root) {
2332
2540
  function StatsWidget(props) {
2333
2541
  const injectedClient = "client" in props ? props.client : void 0;
2334
2542
  const cfg = props.config;
2335
- const built = (0, import_react12.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
2336
- const ui = (0, import_react12.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
2337
- const rootRef = (0, import_react12.useRef)(null);
2543
+ const built = (0, import_react13.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
2544
+ const ui = (0, import_react13.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
2545
+ const rootRef = (0, import_react13.useRef)(null);
2338
2546
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
2339
- const slip = (0, import_react12.useMemo)(
2547
+ const slip = (0, import_react13.useMemo)(
2340
2548
  () => ({
2341
2549
  onAddToSlip: props.config?.onAddToSlip,
2342
2550
  conversationId: controller.state.conversationId ?? void 0,
@@ -2349,18 +2557,18 @@ function StatsWidget(props) {
2349
2557
  }),
2350
2558
  [props.config?.onAddToSlip, controller.state.conversationId, built]
2351
2559
  );
2352
- const onDashboardTap = (0, import_react12.useMemo)(
2560
+ const onDashboardTap = (0, import_react13.useMemo)(
2353
2561
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
2354
2562
  [built]
2355
2563
  );
2356
- (0, import_react12.useEffect)(() => {
2564
+ (0, import_react13.useEffect)(() => {
2357
2565
  if (!built || !ui.injectStyles) return;
2358
2566
  const node = rootRef.current?.getRootNode();
2359
2567
  if (node) injectStyles(node);
2360
2568
  }, [built, ui.injectStyles]);
2361
2569
  if (!built) return null;
2362
2570
  const attrs = themeAttrs(ui);
2363
- return /* @__PURE__ */ (0, import_jsx_runtime36.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_runtime36.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2571
+ return /* @__PURE__ */ (0, import_jsx_runtime43.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_runtime43.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2364
2572
  ChatFab,
2365
2573
  {
2366
2574
  label: ui.launcherLabel,