@sensiblestats/widget-react 0.68.0 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/StatsWidget.tsx
2
- import { useCallback as useCallback12, useEffect as useEffect21, useMemo as useMemo4, useRef as useRef17, useState as useState41 } from "react";
2
+ import { useCallback as useCallback12, useEffect as useEffect22, useMemo as useMemo4, useRef as useRef17, useState as useState41 } from "react";
3
3
  import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
4
4
 
5
5
  // src/kickoff.ts
@@ -34,6 +34,12 @@ var STRINGS = {
34
34
  showMore: (n) => `Show ${n} more`,
35
35
  oddsLabel: "Odds",
36
36
  liveLabel: "Live",
37
+ liveCard: {
38
+ stale: (time) => `Prices from ${time}`,
39
+ suspended: "Market suspended",
40
+ noPrice: "No live price available",
41
+ fullTime: "Full time"
42
+ },
37
43
  yourMarketTag: "Your market",
38
44
  marketFloorLabel: "Market price \xB7 not a value pick",
39
45
  addToSlip: "Add to slip",
@@ -334,6 +340,12 @@ var STRINGS = {
334
340
  showMore: (n) => `${n} tane daha g\xF6ster`,
335
341
  oddsLabel: "Oran",
336
342
  liveLabel: "Canl\u0131",
343
+ liveCard: {
344
+ stale: (time) => `${time} itibar\u0131yla fiyatlar`,
345
+ suspended: "Market ask\u0131ya al\u0131nd\u0131",
346
+ noPrice: "Canl\u0131 fiyat mevcut de\u011Fil",
347
+ fullTime: "Ma\xE7 bitti"
348
+ },
337
349
  yourMarketTag: "\u0130lgilendi\u011Fin bahis",
338
350
  marketFloorLabel: "Piyasa oran\u0131 \xB7 de\u011Fer bahsi de\u011Fil",
339
351
  addToSlip: "Kupona ekle",
@@ -635,6 +647,7 @@ function normalizeUi(cfg) {
635
647
  accent: cfg.accent,
636
648
  logoUrl: cfg.logoUrl,
637
649
  headerTitle: cfg.headerTitle,
650
+ locale: cfg.locale ?? "en",
638
651
  rawBettingLabels: isEnglishLocale(cfg.locale),
639
652
  cta: cfg.cta,
640
653
  surface: cfg.surface,
@@ -741,7 +754,8 @@ function normalizeUi(cfg) {
741
754
  gamePlay: strings.gamePlay,
742
755
  gameLocked: strings.gameLocked,
743
756
  gameVoided: strings.gameVoided,
744
- games: strings.games
757
+ games: strings.games,
758
+ liveCard: strings.liveCard
745
759
  };
746
760
  }
747
761
  function toClientOptions(cfg) {
@@ -753,708 +767,709 @@ function toUserContext(cfg) {
753
767
  return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : void 0;
754
768
  }
755
769
 
756
- // src/slip.ts
757
- var ADD_TO_SLIP_TIMEOUT_MS = 1e4;
758
- var MAX_SELECTION = 64;
759
- var MAX_LINE = 32;
760
- var MAX_ODDS = 1e4;
761
- function slipPickFields(selection, label, line) {
762
- const fields = {};
763
- if (Number.isSafeInteger(selection.matchId) && selection.matchId > 0) fields.matchId = selection.matchId;
764
- if (label && label.trim() && label.length <= MAX_SELECTION) fields.selection = label;
765
- if (line && line.trim() && line.length <= MAX_LINE) fields.line = line;
766
- const odds = selection.oddsDecimal;
767
- if (Number.isFinite(odds) && odds > 1 && odds <= MAX_ODDS) fields.odds = odds;
768
- return fields;
769
- }
770
- function chipSelection(market, matchId, conversationId) {
771
- if (!market || !market.addToSlipEnabled || typeof market.matchOddsId !== "number" || typeof market.price !== "number") return null;
772
- const selection = { matchOddsId: market.matchOddsId, matchId, oddsDecimal: market.price };
773
- if (conversationId !== void 0) selection.conversationId = conversationId;
774
- return selection;
770
+ // src/chart.ts
771
+ var CHART_VIEW_W = 320;
772
+ var CHART_VIEW_H = 140;
773
+ var PLOT_X0 = 40;
774
+ var PLOT_X1 = 312;
775
+ var PLOT_Y0 = 10;
776
+ var PLOT_Y1 = 110;
777
+ var MARKER_MAX_POINTS = 8;
778
+ var FLAT_DOMAIN_PAD = 0.05;
779
+ var round2 = (n) => Math.round(n * 100) / 100;
780
+ function projectSeries(samples) {
781
+ if (samples.length < 2) return null;
782
+ const tMin = samples[0].atMs;
783
+ const tMax = samples[samples.length - 1].atMs;
784
+ if (tMax <= tMin) return null;
785
+ const prices = samples.map((s) => s.price);
786
+ const pMin = Math.min(...prices);
787
+ const pMax = Math.max(...prices);
788
+ let yMin;
789
+ let yMax;
790
+ if (pMax === pMin) {
791
+ yMin = pMin - FLAT_DOMAIN_PAD;
792
+ yMax = pMax + FLAT_DOMAIN_PAD;
793
+ } else {
794
+ const pad = (pMax - pMin) * 0.1;
795
+ yMin = pMin - pad;
796
+ yMax = pMax + pad;
797
+ }
798
+ const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
799
+ const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
800
+ const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
801
+ const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
802
+ return {
803
+ path,
804
+ markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
805
+ // The real extremes, never the padded bounds: a gridline label is a price, and the padded
806
+ // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
807
+ // two identical gridlines would collide on both React key and rendered text.
808
+ gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
809
+ { y: y(pMax), price: pMax },
810
+ { y: y(pMin), price: pMin }
811
+ ],
812
+ viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
813
+ startMs: tMin,
814
+ endMs: tMax
815
+ };
775
816
  }
776
- function wasAdded(result) {
777
- if (!result) return true;
778
- if (result.status === "price_changed") return result.accepted;
779
- return result.status === "added";
817
+
818
+ // src/model.ts
819
+ function str(v) {
820
+ return typeof v === "string" && v.length > 0 ? v : void 0;
780
821
  }
781
- function isTerminal(result) {
782
- if (!result) return true;
783
- if (result.status === "price_changed") return result.accepted;
784
- return result.status === "added" || result.status === "duplicate";
822
+ function num(v) {
823
+ return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
785
824
  }
786
- function slipOutcome(result) {
787
- if (!result) return "added";
788
- switch (result.status) {
789
- case "added":
790
- case "duplicate":
791
- return result.status;
792
- case "price_changed":
793
- return result.accepted ? "added" : "price_changed";
794
- case "rejected":
795
- return result.reason;
825
+ function readStatCells(raw) {
826
+ if (!Array.isArray(raw)) return [];
827
+ const cells = [];
828
+ for (const entry of raw) {
829
+ const label = str(entry.label);
830
+ const value = num(entry.value) ?? str(entry.value);
831
+ if (label !== void 0 && value !== void 0) cells.push({ label, value });
796
832
  }
833
+ return cells;
797
834
  }
798
- function resultToToast(result, shownOdds, ui) {
799
- if (!result) return { kind: "success", text: ui.slipAdded };
800
- switch (result.status) {
801
- case "added":
802
- return { kind: "success", text: ui.slipAdded };
803
- case "duplicate":
804
- return { kind: "success", text: ui.slipDuplicate };
805
- case "price_changed":
806
- return result.accepted ? { kind: "success", text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) } : { kind: "error", text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) };
807
- case "rejected":
808
- if (result.reason === "login_required") return { kind: "error", text: ui.slipLoginRequired };
809
- if (result.reason === "suspended") return { kind: "error", text: ui.slipSuspended };
810
- return { kind: "error", text: result.message ?? ui.slipFailed };
811
- }
835
+ function toCardVM(card) {
836
+ const entityType = str(card.entityType)?.toLowerCase();
837
+ const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
838
+ const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
839
+ const label = str(s.label);
840
+ if (!label) return null;
841
+ return {
842
+ competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
843
+ label,
844
+ image: str(s.imagePath),
845
+ stats: readStatCells(s.stats)
846
+ };
847
+ }).filter((s) => s !== null) : [];
848
+ return {
849
+ id: String(card.entityId),
850
+ kind,
851
+ name: card.canonicalName,
852
+ image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
853
+ sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
854
+ season: str(card.seasonName),
855
+ scopes
856
+ };
812
857
  }
813
-
814
- // src/useHostEvents.ts
815
- import { useCallback as useCallback5, useEffect as useEffect12, useMemo, useRef as useRef8, useState as useState34 } from "react";
816
-
817
- // src/components/ChatPanel.tsx
818
- import { useEffect as useEffect11, useState as useState33 } from "react";
819
-
820
- // src/components/ChatHeader.tsx
821
- import { useEffect, useRef, useState as useState2 } from "react";
822
-
823
- // src/assets/logo.ts
824
- var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
825
-
826
- // src/components/Icons.tsx
827
- import { jsx, jsxs } from "react/jsx-runtime";
828
- function SsMark({ className }) {
829
- return /* @__PURE__ */ jsx("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
858
+ function toActionVM(action) {
859
+ const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
860
+ const actionId = str(action.actionId) ?? str(action.id);
861
+ const actionRef = str(action.actionRef);
862
+ const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
863
+ return { label, actionId, actionRef, message };
830
864
  }
831
- function SendIcon() {
832
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
865
+ function toChipVM(intent) {
866
+ const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
867
+ return text ? { text } : null;
833
868
  }
834
- function CloseIcon() {
835
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
869
+ function chipFromText(text) {
870
+ return { text };
836
871
  }
837
- function ChevronIcon() {
838
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
872
+ function joinSelection(label, line) {
873
+ if (label && line && label.includes(line)) return label;
874
+ return [label, line].filter(Boolean).join(" ") || void 0;
839
875
  }
840
- function KebabIcon() {
841
- return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("g", { fill: "currentColor", children: [
842
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.6" }),
843
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.6" }),
844
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.6" })
845
- ] }) });
876
+ function toInsightVM(insight) {
877
+ const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
878
+ const selectionLabel = str(insight.selectionLabel);
879
+ const selectionLine = str(insight.line);
880
+ const selection = joinSelection(selectionLabel, selectionLine);
881
+ const value = insight.odds?.value;
882
+ const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
883
+ const oddsValue = insight.odds?.value;
884
+ const matchOddsId = typeof insight.odds?.matchOddsId === "number" ? insight.odds.matchOddsId : void 0;
885
+ const home = str(insight.homeTeamName);
886
+ const away = str(insight.awayTeamName);
887
+ const fixture = home && away ? `${home} vs ${away}` : void 0;
888
+ const competition = str(insight.competitionName);
889
+ const previousValue = insight.odds?.previousValue;
890
+ const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
891
+ const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
892
+ return {
893
+ id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
894
+ market,
895
+ selection,
896
+ odds,
897
+ // The wire payload carries bookmakerId (not a name); render a name only if one is present.
898
+ bookmaker: str(insight.odds?.bookmakerName),
899
+ isLive: insight.odds?.isLive === true,
900
+ phase: str(insight.phase),
901
+ fixture,
902
+ competition,
903
+ text: str(insight.text) ?? "",
904
+ disclaimer: str(insight.disclaimer),
905
+ matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
906
+ matchOddsId,
907
+ marketDeveloperName: str(insight.marketDeveloperName),
908
+ selectionLabel: str(insight.selectionLabel),
909
+ line: str(insight.line),
910
+ addToSlipEnabled: insight.addToSlipEnabled === true,
911
+ pinEnabled: insight.pinEnabled === true,
912
+ isMarketFloor: insight.isMarketFloor === true,
913
+ oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
914
+ quotedAtUtc: str(insight.odds?.quotedAtUtc),
915
+ previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
916
+ movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
917
+ homeTeamName: home,
918
+ awayTeamName: away,
919
+ homeCrest: str(insight.homeTeamImagePath),
920
+ awayCrest: str(insight.awayTeamImagePath),
921
+ competitionCrest: str(insight.competitionImagePath),
922
+ kickoffUtc: str(insight.kickoffUtc),
923
+ kickoffLabel: str(insight.kickoffLabel)
924
+ };
846
925
  }
847
- var DASHBOARD_EMOJI = {
848
- football: "\u26BD",
849
- "goal-net": "\u{1F945}",
850
- btts: "\u{1F91D}",
851
- card: "\u{1F7E8}",
852
- "corner-flag": "\u{1F6A9}",
853
- player: "\u{1F464}",
854
- target: "\u{1F3AF}",
855
- trophy: "\u{1F3C6}",
856
- "chart-line": "\u{1F4C8}",
857
- "chart-bar": "\u{1F4CA}",
858
- chat: "\u{1F4AC}",
859
- fire: "\u{1F525}",
860
- sparkle: "\u2728"
861
- };
862
- function DashboardIcon({ name }) {
863
- const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
864
- return /* @__PURE__ */ jsx("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
926
+ function toSlipSelection(vm, conversationId) {
927
+ if (vm.matchOddsId === void 0 || vm.oddsDecimal === void 0) return null;
928
+ const selection = {
929
+ matchOddsId: vm.matchOddsId,
930
+ matchId: vm.matchId,
931
+ oddsDecimal: vm.oddsDecimal
932
+ };
933
+ if (vm.quotedAtUtc !== void 0) selection.quotedAtUtc = vm.quotedAtUtc;
934
+ if (vm.id !== void 0) selection.insightId = vm.id;
935
+ if (conversationId !== void 0) selection.conversationId = conversationId;
936
+ return selection;
865
937
  }
866
-
867
- // src/components/BrandMark.tsx
868
- import { useState } from "react";
869
- import { jsx as jsx2 } from "react/jsx-runtime";
870
- function BrandMark({ logoUrl, className }) {
871
- const [failed, setFailed] = useState(false);
872
- if (!logoUrl || failed) return /* @__PURE__ */ jsx2(SsMark, { className });
873
- return /* @__PURE__ */ jsx2("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
874
- }
875
-
876
- // src/components/ChatHeader.tsx
877
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
878
- function ChatHeader({
879
- onClose,
880
- closeLabel = "Close chat",
881
- logoUrl,
882
- headerTitle,
883
- onNewConversation,
884
- canReset,
885
- newConversationLabel = "New conversation",
886
- moreOptionsLabel = "More options"
887
- }) {
888
- const [menuOpen, setMenuOpen] = useState2(false);
889
- const wrapRef = useRef(null);
890
- const kebabRef = useRef(null);
891
- const firstItemRef = useRef(null);
892
- const hasMenu = !!(canReset && onNewConversation);
893
- useEffect(() => {
894
- if (menuOpen) firstItemRef.current?.focus();
895
- }, [menuOpen]);
896
- useEffect(() => {
897
- if (!menuOpen) return;
898
- const onPointer = (e) => {
899
- if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
900
- };
901
- const onKey = (e) => {
902
- if (e.key === "Escape") {
903
- setMenuOpen(false);
904
- kebabRef.current?.focus();
905
- }
906
- };
907
- document.addEventListener("mousedown", onPointer);
908
- document.addEventListener("keydown", onKey);
909
- return () => {
910
- document.removeEventListener("mousedown", onPointer);
911
- document.removeEventListener("keydown", onKey);
938
+ function toMarketOddsVM(card) {
939
+ const rows = Array.isArray(card.rows) ? card.rows : [];
940
+ const toRow = (r, i) => {
941
+ const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
942
+ const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
943
+ const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
944
+ const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
945
+ return {
946
+ key: `${selection}:${str(r.line) ?? ""}:${i}`,
947
+ selection,
948
+ selectionLabel: str(r.selectionLabel),
949
+ line: str(r.line),
950
+ odds: price !== void 0 ? price.toFixed(2) : "",
951
+ oddsDecimal: price,
952
+ matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
953
+ quotedAtUtc: str(r.quotedAtUtc),
954
+ isMain: r.isMainLine !== false,
955
+ // === true, not !== false: a server that has not shipped the field yet leaves it undefined,
956
+ // and undefined must read as open rather than hiding every price on the card.
957
+ isSuspended: r.isSuspended === true,
958
+ previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
959
+ movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
912
960
  };
913
- }, [menuOpen]);
914
- const runNewConversation = () => {
915
- setMenuOpen(false);
916
- onNewConversation?.();
917
961
  };
918
- return /* @__PURE__ */ jsxs2("header", { className: "ss-w-header", children: [
919
- /* @__PURE__ */ jsx3(BrandMark, { logoUrl, className: "ss-w-header-mark" }),
920
- /* @__PURE__ */ jsx3("span", { className: "ss-w-header-title", children: headerTitle ?? "SensibleStats" }),
921
- hasMenu ? /* @__PURE__ */ jsxs2("div", { className: "ss-w-menu-wrap", ref: wrapRef, children: [
922
- /* @__PURE__ */ jsx3(
923
- "button",
924
- {
925
- type: "button",
926
- className: "ss-w-kebab",
927
- ref: kebabRef,
928
- "aria-haspopup": "menu",
929
- "aria-expanded": menuOpen,
930
- "aria-label": moreOptionsLabel,
931
- onClick: () => setMenuOpen((open) => !open),
932
- children: /* @__PURE__ */ jsx3(KebabIcon, {})
933
- }
934
- ),
935
- menuOpen ? /* @__PURE__ */ jsx3("div", { className: "ss-w-menu", role: "menu", "aria-label": moreOptionsLabel, children: /* @__PURE__ */ jsx3(
936
- "button",
937
- {
938
- type: "button",
939
- className: "ss-w-menu-item",
940
- role: "menuitem",
941
- ref: firstItemRef,
942
- onClick: runNewConversation,
943
- children: /* @__PURE__ */ jsx3("span", { children: newConversationLabel })
944
- }
945
- ) }) : null
946
- ] }) : null,
947
- /* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ jsx3(CloseIcon, {}) })
948
- ] });
949
- }
950
-
951
- // src/components/MessageList.tsx
952
- import { useEffect as useEffect6, useRef as useRef4 } from "react";
953
-
954
- // src/presets.ts
955
- var CLIENT_CAPABILITIES = ["price_presets"];
956
- var PRICE_TILE_PREFIX = "goal-preset-";
957
- function isPriceTile(tile) {
958
- const id = tile.signal?.entityId;
959
- return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
960
- }
961
- function tileDisplayText(tile) {
962
- const subtitle = tile.subtitle?.trim();
963
- return isPriceTile(tile) && subtitle ? subtitle : tile.title;
962
+ const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
963
+ const home = str(card.homeTeamName);
964
+ const away = str(card.awayTeamName);
965
+ const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
966
+ return {
967
+ id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
968
+ market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
969
+ fixture: home && away ? `${home} vs ${away}` : void 0,
970
+ homeTeamName: home,
971
+ awayTeamName: away,
972
+ homeCrest: str(card.homeTeamImagePath),
973
+ awayCrest: str(card.awayTeamImagePath),
974
+ competitionCrest: str(card.competitionImagePath),
975
+ competition: str(card.competitionName),
976
+ kickoffUtc: str(card.kickoffUtc),
977
+ kickoffLabel: str(card.kickoffLabel),
978
+ bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
979
+ updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
980
+ isLive: rows.some((r) => r.isLive === true),
981
+ matchId: typeof card.matchId === "number" ? card.matchId : 0,
982
+ mainRows: vms.filter((r) => r.isMain),
983
+ moreRows: vms.filter((r) => !r.isMain),
984
+ disclaimer: str(card.disclaimer),
985
+ addToSlipEnabled: card.addToSlipEnabled === true,
986
+ marketDeveloperName: str(card.marketDeveloperName),
987
+ mainLine: str(card.mainLine),
988
+ pinEnabled: card.pinEnabled === true,
989
+ statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
990
+ tag: card.tag === "your_market" ? "your_market" : void 0,
991
+ live: card.live ?? null
992
+ };
964
993
  }
965
- var MAX_BUBBLE_ASKS = 2;
966
- function bubbleAsks(messages) {
967
- for (let i = messages.length - 1; i >= 0; i--) {
968
- const m = messages[i];
969
- if (!m || m.role !== "assistant" || !m.isGreeting) continue;
970
- const dashboard = m.greetingDashboard;
971
- if (!dashboard) return [];
972
- const asks = [];
973
- dashboard.tiles.forEach((tile, index) => {
974
- const label = tile.subtitle?.trim();
975
- if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
976
- });
977
- return asks;
994
+ function toOddsMovementVM(card) {
995
+ const raw = Array.isArray(card.points) ? card.points : [];
996
+ const samples = [];
997
+ for (const p of raw) {
998
+ const price = typeof p.price === "number" && Number.isFinite(p.price) ? p.price : void 0;
999
+ const atMs = typeof p.atUtc === "string" ? Date.parse(p.atUtc) : NaN;
1000
+ if (price === void 0 || Number.isNaN(atMs)) continue;
1001
+ samples.push({ atMs, price });
978
1002
  }
979
- return [];
980
- }
981
- function runBubbleAsk(ask, deps) {
982
- deps.log?.log({ name: "popup_ask_tap", outcome: String(ask.position) });
983
- deps.open();
984
- deps.setActiveTab("chat");
985
- const displayText = tileDisplayText(ask.tile);
986
- deps.send(ask.tile.actionValue, ask.tile.actionRef ? { actionRef: ask.tile.actionRef, displayText } : { displayText });
987
- deps.onDashboardTap?.(ask.tile, ask.index, ask.layout);
988
- }
989
-
990
- // src/components/Markdown.tsx
991
- import ReactMarkdown from "react-markdown";
992
- import remarkGfm from "remark-gfm";
993
- import { jsx as jsx4 } from "react/jsx-runtime";
994
- var components = {
995
- a: ({ children, href }) => /* @__PURE__ */ jsx4("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
996
- table: ({ children }) => /* @__PURE__ */ jsx4("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ jsx4("table", { className: "ss-w-md-table", children }) }),
997
- ul: ({ children }) => /* @__PURE__ */ jsx4("ul", { className: "ss-w-md-ul", children }),
998
- ol: ({ children }) => /* @__PURE__ */ jsx4("ol", { className: "ss-w-md-ol", children }),
999
- code: ({ children }) => /* @__PURE__ */ jsx4("code", { className: "ss-w-md-code", children })
1000
- };
1001
- function Markdown({ text }) {
1002
- return /* @__PURE__ */ jsx4("div", { className: "ss-w-md", children: /* @__PURE__ */ jsx4(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children: text }) });
1003
- }
1004
-
1005
- // src/components/EntityCardList.tsx
1006
- import { useState as useState3 } from "react";
1007
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1008
- var MAX_VISIBLE = 3;
1009
- var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
1010
- function initials(name) {
1011
- return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
1003
+ samples.sort((a, b) => a.atMs - b.atMs);
1004
+ const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
1005
+ const opening = asNumber(card.openingPrice);
1006
+ const current = asNumber(card.currentPrice);
1007
+ const home = str(card.homeTeamName);
1008
+ const away = str(card.awayTeamName);
1009
+ const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
1010
+ const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
1011
+ return {
1012
+ id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
1013
+ matchId: typeof card.matchId === "number" ? card.matchId : 0,
1014
+ market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1015
+ marketDeveloperName: str(card.marketDeveloperName),
1016
+ selection,
1017
+ selectionLabel: str(card.selectionLabel),
1018
+ line: str(card.line),
1019
+ fixture: home && away ? `${home} vs ${away}` : void 0,
1020
+ competition: str(card.competitionName),
1021
+ bookmaker: str(card.bookmakerName),
1022
+ opening: opening !== void 0 ? opening.toFixed(2) : "",
1023
+ current: current !== void 0 ? current.toFixed(2) : "",
1024
+ direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
1025
+ windowHours: asNumber(card.windowHours) ?? 0,
1026
+ excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
1027
+ isSuspended: card.isSuspended === true,
1028
+ disclaimer: str(card.disclaimer),
1029
+ geometry: projectSeries(samples),
1030
+ observationCount: samples.length,
1031
+ pinEnabled: card.pinEnabled === true,
1032
+ matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
1033
+ };
1012
1034
  }
1013
- function shortSeason(season) {
1014
- return season.replace(/\d{4}/g, (year) => year.slice(2));
1035
+ function marketOddsRowToSlipSelection(vm, row, conversationId) {
1036
+ if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
1037
+ const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
1038
+ if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
1039
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1040
+ return selection;
1015
1041
  }
1016
- function Crest({ image, label }) {
1017
- return /* @__PURE__ */ jsx5(
1018
- "span",
1019
- {
1020
- className: "ss-w-ecard-crest",
1021
- style: { backgroundImage: `url(${image})` },
1022
- ...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
1023
- }
1024
- );
1042
+ function finite(v) {
1043
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1025
1044
  }
1026
- function FormBar({ w, d, l }) {
1027
- if (w + d + l === 0) return null;
1028
- return /* @__PURE__ */ jsxs3("span", { className: "ss-w-form", "aria-hidden": "true", children: [
1029
- w > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-w", style: { flexGrow: w } }) : null,
1030
- d > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-d", style: { flexGrow: d } }) : null,
1031
- l > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
1032
- ] });
1045
+ function toComboLegVM(leg) {
1046
+ if (!leg || typeof leg !== "object") return null;
1047
+ const price = finite(leg.price);
1048
+ const matchOddsId = finite(leg.matchOddsId);
1049
+ const matchId = finite(leg.matchId);
1050
+ const home = str(leg.homeTeamName);
1051
+ const away = str(leg.awayTeamName);
1052
+ const selectionLabel = str(leg.selectionLabel);
1053
+ const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
1054
+ const insightId = str(insight?.insightId);
1055
+ const statText = str(insight?.text);
1056
+ if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
1057
+ const line = str(leg.line);
1058
+ return {
1059
+ key: `${matchOddsId}`,
1060
+ matchId,
1061
+ homeTeamName: home,
1062
+ awayTeamName: away,
1063
+ homeCrest: str(leg.homeTeamImagePath),
1064
+ awayCrest: str(leg.awayTeamImagePath),
1065
+ competition: str(leg.competitionName),
1066
+ kickoffUtc: str(leg.kickoffUtc),
1067
+ kickoffLabel: str(leg.kickoffLabel),
1068
+ market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
1069
+ marketDeveloperName: str(leg.marketDeveloperName) ?? "",
1070
+ selection: joinSelection(selectionLabel, line) ?? selectionLabel,
1071
+ selectionLabel,
1072
+ line,
1073
+ odds: price.toFixed(2),
1074
+ oddsDecimal: price,
1075
+ matchOddsId,
1076
+ quotedAtUtc: str(leg.quotedAtUtc),
1077
+ insightId,
1078
+ statText
1079
+ };
1033
1080
  }
1034
- function StatCellView({ s }) {
1035
- const m = RECORD_RE.exec(s.value);
1036
- if (m) {
1037
- return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
1038
- /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ jsx5(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
1039
- /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.value })
1040
- ] });
1081
+ function toComboCardVM(card) {
1082
+ const rawLegs = Array.isArray(card?.legs) ? card.legs : [];
1083
+ const multiplication = str(card?.multiplication);
1084
+ if (rawLegs.length < 2 || !multiplication) return null;
1085
+ const legs = [];
1086
+ for (const raw of rawLegs) {
1087
+ const vm = toComboLegVM(raw);
1088
+ if (!vm) return null;
1089
+ legs.push(vm);
1041
1090
  }
1042
- return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
1043
- /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: s.value }),
1044
- /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.label })
1045
- ] });
1091
+ return {
1092
+ id: str(card.comboId) ?? legs.map((l) => l.matchOddsId).join("-"),
1093
+ legs,
1094
+ multiplication,
1095
+ replacedNote: str(card.replacedNote),
1096
+ addToSlipEnabled: card.addToSlipEnabled === true
1097
+ };
1046
1098
  }
1047
- function StatStrip({ stats }) {
1048
- if (stats.length === 0) return null;
1049
- const cols = Math.min(stats.length, 4);
1050
- return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ jsx5(StatCellView, { s }, s.label + s.value)) });
1099
+ function comboLegToSlipSelection(leg, conversationId) {
1100
+ const selection = {
1101
+ matchOddsId: leg.matchOddsId,
1102
+ matchId: leg.matchId,
1103
+ oddsDecimal: leg.oddsDecimal,
1104
+ insightId: leg.insightId
1105
+ };
1106
+ if (leg.quotedAtUtc !== void 0) selection.quotedAtUtc = leg.quotedAtUtc;
1107
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1108
+ return selection;
1051
1109
  }
1052
- function CardHeader({ c, showScopeCrest }) {
1053
- const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
1054
- return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-hd", children: [
1055
- /* @__PURE__ */ jsx5(
1056
- "span",
1057
- {
1058
- className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
1059
- style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
1060
- children: c.image ? "" : initials(c.name)
1061
- }
1062
- ),
1063
- /* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-idtext", children: [
1064
- /* @__PURE__ */ jsx5("span", { className: "ss-w-nm", children: c.name }),
1065
- c.sub ? /* @__PURE__ */ jsx5("span", { className: "ss-w-sub", children: c.sub }) : null
1066
- ] }),
1067
- /* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-meta", children: [
1068
- showScopeCrest && onlyScope?.image ? /* @__PURE__ */ jsx5(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
1069
- c.season ? /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
1070
- ] })
1071
- ] });
1110
+
1111
+ // src/slip.ts
1112
+ var ADD_TO_SLIP_TIMEOUT_MS = 1e4;
1113
+ var MAX_SELECTION = 64;
1114
+ var MAX_LINE = 32;
1115
+ var MAX_ODDS = 1e4;
1116
+ function slipPickFields(selection, label, line) {
1117
+ const fields = {};
1118
+ if (Number.isSafeInteger(selection.matchId) && selection.matchId > 0) fields.matchId = selection.matchId;
1119
+ if (label && label.trim() && label.length <= MAX_SELECTION) fields.selection = label;
1120
+ if (line && line.trim() && line.length <= MAX_LINE) fields.line = line;
1121
+ const odds = selection.oddsDecimal;
1122
+ if (Number.isFinite(odds) && odds > 1 && odds <= MAX_ODDS) fields.odds = odds;
1123
+ return fields;
1124
+ }
1125
+ function chipSelection(market, matchId, conversationId) {
1126
+ if (!market || !market.addToSlipEnabled || typeof market.matchOddsId !== "number" || typeof market.price !== "number") return null;
1127
+ const selection = { matchOddsId: market.matchOddsId, matchId, oddsDecimal: market.price };
1128
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1129
+ return selection;
1072
1130
  }
1073
- function ScopeTabs({ scopes, active, onSelect }) {
1074
- return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ jsx5(
1075
- "button",
1076
- {
1077
- type: "button",
1078
- role: "tab",
1079
- className: "ss-w-ecard-scope",
1080
- "aria-selected": i === active,
1081
- "aria-label": s.label,
1082
- title: s.label,
1083
- onClick: () => onSelect(i),
1084
- children: s.image ? /* @__PURE__ */ jsx5(Crest, { image: s.image }) : s.label
1085
- },
1086
- String(s.competitionId ?? "all")
1087
- )) });
1131
+ function wasAdded(result) {
1132
+ if (!result) return true;
1133
+ if (result.status === "price_changed") return result.accepted;
1134
+ return result.status === "added";
1088
1135
  }
1089
- function EntityCardItem({ c }) {
1090
- const [active, setActive] = useState3(0);
1091
- const hasBody = c.scopes.length > 0;
1092
- if (!hasBody) {
1093
- return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: false }) });
1136
+ function isTerminal(result) {
1137
+ if (!result) return true;
1138
+ if (result.status === "price_changed") return result.accepted;
1139
+ return result.status === "added" || result.status === "duplicate";
1140
+ }
1141
+ function slipOutcome(result) {
1142
+ if (!result) return "added";
1143
+ switch (result.status) {
1144
+ case "added":
1145
+ case "duplicate":
1146
+ return result.status;
1147
+ case "price_changed":
1148
+ return result.accepted ? "added" : "price_changed";
1149
+ case "rejected":
1150
+ return result.reason;
1094
1151
  }
1095
- const multi = c.scopes.length > 1;
1096
- const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
1097
- return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
1098
- /* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: !multi }),
1099
- multi ? /* @__PURE__ */ jsx5(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
1100
- /* @__PURE__ */ jsx5(StatStrip, { stats: scope.stats })
1101
- ] });
1102
1152
  }
1103
- function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1104
- const [expanded, setExpanded] = useState3(false);
1105
- if (cards.length === 0) return null;
1106
- const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1107
- const overflow = cards.length - MAX_VISIBLE;
1108
- return /* @__PURE__ */ jsxs3("div", { className: "ss-w-cards", children: [
1109
- visible.map((c) => /* @__PURE__ */ jsx5(EntityCardItem, { c }, c.id)),
1110
- overflow > 0 ? /* @__PURE__ */ jsx5("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
1111
- ] });
1153
+ function resultToToast(result, shownOdds, ui) {
1154
+ if (!result) return { kind: "success", text: ui.slipAdded };
1155
+ switch (result.status) {
1156
+ case "added":
1157
+ return { kind: "success", text: ui.slipAdded };
1158
+ case "duplicate":
1159
+ return { kind: "success", text: ui.slipDuplicate };
1160
+ case "price_changed":
1161
+ return result.accepted ? { kind: "success", text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) } : { kind: "error", text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) };
1162
+ case "rejected":
1163
+ if (result.reason === "login_required") return { kind: "error", text: ui.slipLoginRequired };
1164
+ if (result.reason === "suspended") return { kind: "error", text: ui.slipSuspended };
1165
+ return { kind: "error", text: result.message ?? ui.slipFailed };
1166
+ }
1112
1167
  }
1113
1168
 
1114
- // src/components/AddToSlipButton.tsx
1115
- import { useCallback, useState as useState4 } from "react";
1116
- import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
1169
+ // src/useHostEvents.ts
1170
+ import { useCallback as useCallback5, useEffect as useEffect13, useMemo, useRef as useRef8, useState as useState34 } from "react";
1117
1171
 
1118
- // src/chart.ts
1119
- var CHART_VIEW_W = 320;
1120
- var CHART_VIEW_H = 140;
1121
- var PLOT_X0 = 40;
1122
- var PLOT_X1 = 312;
1123
- var PLOT_Y0 = 10;
1124
- var PLOT_Y1 = 110;
1125
- var MARKER_MAX_POINTS = 8;
1126
- var FLAT_DOMAIN_PAD = 0.05;
1127
- var round2 = (n) => Math.round(n * 100) / 100;
1128
- function projectSeries(samples) {
1129
- if (samples.length < 2) return null;
1130
- const tMin = samples[0].atMs;
1131
- const tMax = samples[samples.length - 1].atMs;
1132
- if (tMax <= tMin) return null;
1133
- const prices = samples.map((s) => s.price);
1134
- const pMin = Math.min(...prices);
1135
- const pMax = Math.max(...prices);
1136
- let yMin;
1137
- let yMax;
1138
- if (pMax === pMin) {
1139
- yMin = pMin - FLAT_DOMAIN_PAD;
1140
- yMax = pMax + FLAT_DOMAIN_PAD;
1141
- } else {
1142
- const pad = (pMax - pMin) * 0.1;
1143
- yMin = pMin - pad;
1144
- yMax = pMax + pad;
1145
- }
1146
- const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
1147
- const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
1148
- const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
1149
- const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
1150
- return {
1151
- path,
1152
- markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
1153
- // The real extremes, never the padded bounds: a gridline label is a price, and the padded
1154
- // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
1155
- // two identical gridlines would collide on both React key and rendered text.
1156
- gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
1157
- { y: y(pMax), price: pMax },
1158
- { y: y(pMin), price: pMin }
1159
- ],
1160
- viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
1161
- startMs: tMin,
1162
- endMs: tMax
1163
- };
1164
- }
1172
+ // src/components/ChatPanel.tsx
1173
+ import { useEffect as useEffect12, useState as useState33 } from "react";
1165
1174
 
1166
- // src/model.ts
1167
- function str(v) {
1168
- return typeof v === "string" && v.length > 0 ? v : void 0;
1175
+ // src/components/ChatHeader.tsx
1176
+ import { useEffect, useRef, useState as useState2 } from "react";
1177
+
1178
+ // src/assets/logo.ts
1179
+ var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
1180
+
1181
+ // src/components/Icons.tsx
1182
+ import { jsx, jsxs } from "react/jsx-runtime";
1183
+ function SsMark({ className }) {
1184
+ return /* @__PURE__ */ jsx("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
1169
1185
  }
1170
- function num(v) {
1171
- return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
1186
+ function SendIcon() {
1187
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
1172
1188
  }
1173
- function readStatCells(raw) {
1174
- if (!Array.isArray(raw)) return [];
1175
- const cells = [];
1176
- for (const entry of raw) {
1177
- const label = str(entry.label);
1178
- const value = num(entry.value) ?? str(entry.value);
1179
- if (label !== void 0 && value !== void 0) cells.push({ label, value });
1180
- }
1181
- return cells;
1189
+ function CloseIcon() {
1190
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
1182
1191
  }
1183
- function toCardVM(card) {
1184
- const entityType = str(card.entityType)?.toLowerCase();
1185
- const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
1186
- const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
1187
- const label = str(s.label);
1188
- if (!label) return null;
1189
- return {
1190
- competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
1191
- label,
1192
- image: str(s.imagePath),
1193
- stats: readStatCells(s.stats)
1192
+ function ChevronIcon() {
1193
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
1194
+ }
1195
+ function KebabIcon() {
1196
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("g", { fill: "currentColor", children: [
1197
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.6" }),
1198
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.6" }),
1199
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.6" })
1200
+ ] }) });
1201
+ }
1202
+ var DASHBOARD_EMOJI = {
1203
+ football: "\u26BD",
1204
+ "goal-net": "\u{1F945}",
1205
+ btts: "\u{1F91D}",
1206
+ card: "\u{1F7E8}",
1207
+ "corner-flag": "\u{1F6A9}",
1208
+ player: "\u{1F464}",
1209
+ target: "\u{1F3AF}",
1210
+ trophy: "\u{1F3C6}",
1211
+ "chart-line": "\u{1F4C8}",
1212
+ "chart-bar": "\u{1F4CA}",
1213
+ chat: "\u{1F4AC}",
1214
+ fire: "\u{1F525}",
1215
+ sparkle: "\u2728"
1216
+ };
1217
+ function DashboardIcon({ name }) {
1218
+ const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
1219
+ return /* @__PURE__ */ jsx("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
1220
+ }
1221
+
1222
+ // src/components/BrandMark.tsx
1223
+ import { useState } from "react";
1224
+ import { jsx as jsx2 } from "react/jsx-runtime";
1225
+ function BrandMark({ logoUrl, className }) {
1226
+ const [failed, setFailed] = useState(false);
1227
+ if (!logoUrl || failed) return /* @__PURE__ */ jsx2(SsMark, { className });
1228
+ return /* @__PURE__ */ jsx2("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1229
+ }
1230
+
1231
+ // src/components/ChatHeader.tsx
1232
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1233
+ function ChatHeader({
1234
+ onClose,
1235
+ closeLabel = "Close chat",
1236
+ logoUrl,
1237
+ headerTitle,
1238
+ onNewConversation,
1239
+ canReset,
1240
+ newConversationLabel = "New conversation",
1241
+ moreOptionsLabel = "More options"
1242
+ }) {
1243
+ const [menuOpen, setMenuOpen] = useState2(false);
1244
+ const wrapRef = useRef(null);
1245
+ const kebabRef = useRef(null);
1246
+ const firstItemRef = useRef(null);
1247
+ const hasMenu = !!(canReset && onNewConversation);
1248
+ useEffect(() => {
1249
+ if (menuOpen) firstItemRef.current?.focus();
1250
+ }, [menuOpen]);
1251
+ useEffect(() => {
1252
+ if (!menuOpen) return;
1253
+ const onPointer = (e) => {
1254
+ if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
1194
1255
  };
1195
- }).filter((s) => s !== null) : [];
1196
- return {
1197
- id: String(card.entityId),
1198
- kind,
1199
- name: card.canonicalName,
1200
- image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
1201
- sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
1202
- season: str(card.seasonName),
1203
- scopes
1256
+ const onKey = (e) => {
1257
+ if (e.key === "Escape") {
1258
+ setMenuOpen(false);
1259
+ kebabRef.current?.focus();
1260
+ }
1261
+ };
1262
+ document.addEventListener("mousedown", onPointer);
1263
+ document.addEventListener("keydown", onKey);
1264
+ return () => {
1265
+ document.removeEventListener("mousedown", onPointer);
1266
+ document.removeEventListener("keydown", onKey);
1267
+ };
1268
+ }, [menuOpen]);
1269
+ const runNewConversation = () => {
1270
+ setMenuOpen(false);
1271
+ onNewConversation?.();
1204
1272
  };
1273
+ return /* @__PURE__ */ jsxs2("header", { className: "ss-w-header", children: [
1274
+ /* @__PURE__ */ jsx3(BrandMark, { logoUrl, className: "ss-w-header-mark" }),
1275
+ /* @__PURE__ */ jsx3("span", { className: "ss-w-header-title", children: headerTitle ?? "SensibleStats" }),
1276
+ hasMenu ? /* @__PURE__ */ jsxs2("div", { className: "ss-w-menu-wrap", ref: wrapRef, children: [
1277
+ /* @__PURE__ */ jsx3(
1278
+ "button",
1279
+ {
1280
+ type: "button",
1281
+ className: "ss-w-kebab",
1282
+ ref: kebabRef,
1283
+ "aria-haspopup": "menu",
1284
+ "aria-expanded": menuOpen,
1285
+ "aria-label": moreOptionsLabel,
1286
+ onClick: () => setMenuOpen((open) => !open),
1287
+ children: /* @__PURE__ */ jsx3(KebabIcon, {})
1288
+ }
1289
+ ),
1290
+ menuOpen ? /* @__PURE__ */ jsx3("div", { className: "ss-w-menu", role: "menu", "aria-label": moreOptionsLabel, children: /* @__PURE__ */ jsx3(
1291
+ "button",
1292
+ {
1293
+ type: "button",
1294
+ className: "ss-w-menu-item",
1295
+ role: "menuitem",
1296
+ ref: firstItemRef,
1297
+ onClick: runNewConversation,
1298
+ children: /* @__PURE__ */ jsx3("span", { children: newConversationLabel })
1299
+ }
1300
+ ) }) : null
1301
+ ] }) : null,
1302
+ /* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ jsx3(CloseIcon, {}) })
1303
+ ] });
1205
1304
  }
1206
- function toActionVM(action) {
1207
- const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
1208
- const actionId = str(action.actionId) ?? str(action.id);
1209
- const actionRef = str(action.actionRef);
1210
- const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
1211
- return { label, actionId, actionRef, message };
1305
+
1306
+ // src/components/MessageList.tsx
1307
+ import { useEffect as useEffect7, useRef as useRef4 } from "react";
1308
+
1309
+ // src/presets.ts
1310
+ var CLIENT_CAPABILITIES = ["price_presets"];
1311
+ var PRICE_TILE_PREFIX = "goal-preset-";
1312
+ function isPriceTile(tile) {
1313
+ const id = tile.signal?.entityId;
1314
+ return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
1212
1315
  }
1213
- function toChipVM(intent) {
1214
- const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
1215
- return text ? { text } : null;
1316
+ function tileDisplayText(tile) {
1317
+ const subtitle = tile.subtitle?.trim();
1318
+ return isPriceTile(tile) && subtitle ? subtitle : tile.title;
1216
1319
  }
1217
- function chipFromText(text) {
1218
- return { text };
1320
+ var MAX_BUBBLE_ASKS = 2;
1321
+ function bubbleAsks(messages) {
1322
+ for (let i = messages.length - 1; i >= 0; i--) {
1323
+ const m = messages[i];
1324
+ if (!m || m.role !== "assistant" || !m.isGreeting) continue;
1325
+ const dashboard = m.greetingDashboard;
1326
+ if (!dashboard) return [];
1327
+ const asks = [];
1328
+ dashboard.tiles.forEach((tile, index) => {
1329
+ const label = tile.subtitle?.trim();
1330
+ if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
1331
+ });
1332
+ return asks;
1333
+ }
1334
+ return [];
1219
1335
  }
1220
- function joinSelection(label, line) {
1221
- if (label && line && label.includes(line)) return label;
1222
- return [label, line].filter(Boolean).join(" ") || void 0;
1336
+ function runBubbleAsk(ask, deps) {
1337
+ deps.log?.log({ name: "popup_ask_tap", outcome: String(ask.position) });
1338
+ deps.open();
1339
+ deps.setActiveTab("chat");
1340
+ const displayText = tileDisplayText(ask.tile);
1341
+ deps.send(ask.tile.actionValue, ask.tile.actionRef ? { actionRef: ask.tile.actionRef, displayText } : { displayText });
1342
+ deps.onDashboardTap?.(ask.tile, ask.index, ask.layout);
1223
1343
  }
1224
- function toInsightVM(insight) {
1225
- const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
1226
- const selectionLabel = str(insight.selectionLabel);
1227
- const selectionLine = str(insight.line);
1228
- const selection = joinSelection(selectionLabel, selectionLine);
1229
- const value = insight.odds?.value;
1230
- const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
1231
- const oddsValue = insight.odds?.value;
1232
- const matchOddsId = typeof insight.odds?.matchOddsId === "number" ? insight.odds.matchOddsId : void 0;
1233
- const home = str(insight.homeTeamName);
1234
- const away = str(insight.awayTeamName);
1235
- const fixture = home && away ? `${home} vs ${away}` : void 0;
1236
- const competition = str(insight.competitionName);
1237
- const previousValue = insight.odds?.previousValue;
1238
- const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
1239
- const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
1240
- return {
1241
- id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
1242
- market,
1243
- selection,
1244
- odds,
1245
- // The wire payload carries bookmakerId (not a name); render a name only if one is present.
1246
- bookmaker: str(insight.odds?.bookmakerName),
1247
- isLive: insight.odds?.isLive === true,
1248
- phase: str(insight.phase),
1249
- fixture,
1250
- competition,
1251
- text: str(insight.text) ?? "",
1252
- disclaimer: str(insight.disclaimer),
1253
- matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
1254
- matchOddsId,
1255
- marketDeveloperName: str(insight.marketDeveloperName),
1256
- selectionLabel: str(insight.selectionLabel),
1257
- line: str(insight.line),
1258
- addToSlipEnabled: insight.addToSlipEnabled === true,
1259
- pinEnabled: insight.pinEnabled === true,
1260
- isMarketFloor: insight.isMarketFloor === true,
1261
- oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
1262
- quotedAtUtc: str(insight.odds?.quotedAtUtc),
1263
- previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1264
- movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
1265
- homeTeamName: home,
1266
- awayTeamName: away,
1267
- homeCrest: str(insight.homeTeamImagePath),
1268
- awayCrest: str(insight.awayTeamImagePath),
1269
- competitionCrest: str(insight.competitionImagePath),
1270
- kickoffUtc: str(insight.kickoffUtc),
1271
- kickoffLabel: str(insight.kickoffLabel)
1272
- };
1344
+
1345
+ // src/components/Markdown.tsx
1346
+ import ReactMarkdown from "react-markdown";
1347
+ import remarkGfm from "remark-gfm";
1348
+ import { jsx as jsx4 } from "react/jsx-runtime";
1349
+ var components = {
1350
+ a: ({ children, href }) => /* @__PURE__ */ jsx4("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
1351
+ table: ({ children }) => /* @__PURE__ */ jsx4("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ jsx4("table", { className: "ss-w-md-table", children }) }),
1352
+ ul: ({ children }) => /* @__PURE__ */ jsx4("ul", { className: "ss-w-md-ul", children }),
1353
+ ol: ({ children }) => /* @__PURE__ */ jsx4("ol", { className: "ss-w-md-ol", children }),
1354
+ code: ({ children }) => /* @__PURE__ */ jsx4("code", { className: "ss-w-md-code", children })
1355
+ };
1356
+ function Markdown({ text }) {
1357
+ return /* @__PURE__ */ jsx4("div", { className: "ss-w-md", children: /* @__PURE__ */ jsx4(ReactMarkdown, { remarkPlugins: [remarkGfm], components, children: text }) });
1273
1358
  }
1274
- function toSlipSelection(vm, conversationId) {
1275
- if (vm.matchOddsId === void 0 || vm.oddsDecimal === void 0) return null;
1276
- const selection = {
1277
- matchOddsId: vm.matchOddsId,
1278
- matchId: vm.matchId,
1279
- oddsDecimal: vm.oddsDecimal
1280
- };
1281
- if (vm.quotedAtUtc !== void 0) selection.quotedAtUtc = vm.quotedAtUtc;
1282
- if (vm.id !== void 0) selection.insightId = vm.id;
1283
- if (conversationId !== void 0) selection.conversationId = conversationId;
1284
- return selection;
1359
+
1360
+ // src/components/EntityCardList.tsx
1361
+ import { useState as useState3 } from "react";
1362
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1363
+ var MAX_VISIBLE = 3;
1364
+ var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
1365
+ function initials(name) {
1366
+ return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
1285
1367
  }
1286
- function toMarketOddsVM(card) {
1287
- const rows = Array.isArray(card.rows) ? card.rows : [];
1288
- const toRow = (r, i) => {
1289
- const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
1290
- const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
1291
- const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
1292
- const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
1293
- return {
1294
- key: `${selection}:${str(r.line) ?? ""}:${i}`,
1295
- selection,
1296
- selectionLabel: str(r.selectionLabel),
1297
- line: str(r.line),
1298
- odds: price !== void 0 ? price.toFixed(2) : "",
1299
- oddsDecimal: price,
1300
- matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
1301
- quotedAtUtc: str(r.quotedAtUtc),
1302
- isMain: r.isMainLine !== false,
1303
- // === true, not !== false: a server that has not shipped the field yet leaves it undefined,
1304
- // and undefined must read as open rather than hiding every price on the card.
1305
- isSuspended: r.isSuspended === true,
1306
- previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1307
- movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
1308
- };
1309
- };
1310
- const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
1311
- const home = str(card.homeTeamName);
1312
- const away = str(card.awayTeamName);
1313
- const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
1314
- return {
1315
- id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
1316
- market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1317
- fixture: home && away ? `${home} vs ${away}` : void 0,
1318
- homeTeamName: home,
1319
- awayTeamName: away,
1320
- homeCrest: str(card.homeTeamImagePath),
1321
- awayCrest: str(card.awayTeamImagePath),
1322
- competitionCrest: str(card.competitionImagePath),
1323
- competition: str(card.competitionName),
1324
- kickoffUtc: str(card.kickoffUtc),
1325
- kickoffLabel: str(card.kickoffLabel),
1326
- bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
1327
- updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
1328
- isLive: rows.some((r) => r.isLive === true),
1329
- matchId: typeof card.matchId === "number" ? card.matchId : 0,
1330
- mainRows: vms.filter((r) => r.isMain),
1331
- moreRows: vms.filter((r) => !r.isMain),
1332
- disclaimer: str(card.disclaimer),
1333
- addToSlipEnabled: card.addToSlipEnabled === true,
1334
- marketDeveloperName: str(card.marketDeveloperName),
1335
- mainLine: str(card.mainLine),
1336
- pinEnabled: card.pinEnabled === true,
1337
- statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
1338
- tag: card.tag === "your_market" ? "your_market" : void 0
1339
- };
1368
+ function shortSeason(season) {
1369
+ return season.replace(/\d{4}/g, (year) => year.slice(2));
1340
1370
  }
1341
- function toOddsMovementVM(card) {
1342
- const raw = Array.isArray(card.points) ? card.points : [];
1343
- const samples = [];
1344
- for (const p of raw) {
1345
- const price = typeof p.price === "number" && Number.isFinite(p.price) ? p.price : void 0;
1346
- const atMs = typeof p.atUtc === "string" ? Date.parse(p.atUtc) : NaN;
1347
- if (price === void 0 || Number.isNaN(atMs)) continue;
1348
- samples.push({ atMs, price });
1349
- }
1350
- samples.sort((a, b) => a.atMs - b.atMs);
1351
- const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
1352
- const opening = asNumber(card.openingPrice);
1353
- const current = asNumber(card.currentPrice);
1354
- const home = str(card.homeTeamName);
1355
- const away = str(card.awayTeamName);
1356
- const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
1357
- const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
1358
- return {
1359
- id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
1360
- matchId: typeof card.matchId === "number" ? card.matchId : 0,
1361
- market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1362
- marketDeveloperName: str(card.marketDeveloperName),
1363
- selection,
1364
- selectionLabel: str(card.selectionLabel),
1365
- line: str(card.line),
1366
- fixture: home && away ? `${home} vs ${away}` : void 0,
1367
- competition: str(card.competitionName),
1368
- bookmaker: str(card.bookmakerName),
1369
- opening: opening !== void 0 ? opening.toFixed(2) : "",
1370
- current: current !== void 0 ? current.toFixed(2) : "",
1371
- direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
1372
- windowHours: asNumber(card.windowHours) ?? 0,
1373
- excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
1374
- isSuspended: card.isSuspended === true,
1375
- disclaimer: str(card.disclaimer),
1376
- geometry: projectSeries(samples),
1377
- observationCount: samples.length,
1378
- pinEnabled: card.pinEnabled === true,
1379
- matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
1380
- };
1371
+ function Crest({ image, label }) {
1372
+ return /* @__PURE__ */ jsx5(
1373
+ "span",
1374
+ {
1375
+ className: "ss-w-ecard-crest",
1376
+ style: { backgroundImage: `url(${image})` },
1377
+ ...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
1378
+ }
1379
+ );
1381
1380
  }
1382
- function marketOddsRowToSlipSelection(vm, row, conversationId) {
1383
- if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
1384
- const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
1385
- if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
1386
- if (conversationId !== void 0) selection.conversationId = conversationId;
1387
- return selection;
1381
+ function FormBar({ w, d, l }) {
1382
+ if (w + d + l === 0) return null;
1383
+ return /* @__PURE__ */ jsxs3("span", { className: "ss-w-form", "aria-hidden": "true", children: [
1384
+ w > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-w", style: { flexGrow: w } }) : null,
1385
+ d > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-d", style: { flexGrow: d } }) : null,
1386
+ l > 0 ? /* @__PURE__ */ jsx5("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
1387
+ ] });
1388
1388
  }
1389
- function finite(v) {
1390
- return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1389
+ function StatCellView({ s }) {
1390
+ const m = RECORD_RE.exec(s.value);
1391
+ if (m) {
1392
+ return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
1393
+ /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ jsx5(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
1394
+ /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.value })
1395
+ ] });
1396
+ }
1397
+ return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-cell", children: [
1398
+ /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-cval", children: s.value }),
1399
+ /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-clabel", children: s.label })
1400
+ ] });
1391
1401
  }
1392
- function toComboLegVM(leg) {
1393
- if (!leg || typeof leg !== "object") return null;
1394
- const price = finite(leg.price);
1395
- const matchOddsId = finite(leg.matchOddsId);
1396
- const matchId = finite(leg.matchId);
1397
- const home = str(leg.homeTeamName);
1398
- const away = str(leg.awayTeamName);
1399
- const selectionLabel = str(leg.selectionLabel);
1400
- const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
1401
- const insightId = str(insight?.insightId);
1402
- const statText = str(insight?.text);
1403
- if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
1404
- const line = str(leg.line);
1405
- return {
1406
- key: `${matchOddsId}`,
1407
- matchId,
1408
- homeTeamName: home,
1409
- awayTeamName: away,
1410
- homeCrest: str(leg.homeTeamImagePath),
1411
- awayCrest: str(leg.awayTeamImagePath),
1412
- competition: str(leg.competitionName),
1413
- kickoffUtc: str(leg.kickoffUtc),
1414
- kickoffLabel: str(leg.kickoffLabel),
1415
- market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
1416
- marketDeveloperName: str(leg.marketDeveloperName) ?? "",
1417
- selection: joinSelection(selectionLabel, line) ?? selectionLabel,
1418
- selectionLabel,
1419
- line,
1420
- odds: price.toFixed(2),
1421
- oddsDecimal: price,
1422
- matchOddsId,
1423
- quotedAtUtc: str(leg.quotedAtUtc),
1424
- insightId,
1425
- statText
1426
- };
1402
+ function StatStrip({ stats }) {
1403
+ if (stats.length === 0) return null;
1404
+ const cols = Math.min(stats.length, 4);
1405
+ return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ jsx5(StatCellView, { s }, s.label + s.value)) });
1427
1406
  }
1428
- function toComboCardVM(card) {
1429
- const rawLegs = Array.isArray(card?.legs) ? card.legs : [];
1430
- const multiplication = str(card?.multiplication);
1431
- if (rawLegs.length < 2 || !multiplication) return null;
1432
- const legs = [];
1433
- for (const raw of rawLegs) {
1434
- const vm = toComboLegVM(raw);
1435
- if (!vm) return null;
1436
- legs.push(vm);
1407
+ function CardHeader({ c, showScopeCrest }) {
1408
+ const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
1409
+ return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard-hd", children: [
1410
+ /* @__PURE__ */ jsx5(
1411
+ "span",
1412
+ {
1413
+ className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
1414
+ style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
1415
+ children: c.image ? "" : initials(c.name)
1416
+ }
1417
+ ),
1418
+ /* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-idtext", children: [
1419
+ /* @__PURE__ */ jsx5("span", { className: "ss-w-nm", children: c.name }),
1420
+ c.sub ? /* @__PURE__ */ jsx5("span", { className: "ss-w-sub", children: c.sub }) : null
1421
+ ] }),
1422
+ /* @__PURE__ */ jsxs3("span", { className: "ss-w-ecard-meta", children: [
1423
+ showScopeCrest && onlyScope?.image ? /* @__PURE__ */ jsx5(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
1424
+ c.season ? /* @__PURE__ */ jsx5("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
1425
+ ] })
1426
+ ] });
1427
+ }
1428
+ function ScopeTabs({ scopes, active, onSelect }) {
1429
+ return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ jsx5(
1430
+ "button",
1431
+ {
1432
+ type: "button",
1433
+ role: "tab",
1434
+ className: "ss-w-ecard-scope",
1435
+ "aria-selected": i === active,
1436
+ "aria-label": s.label,
1437
+ title: s.label,
1438
+ onClick: () => onSelect(i),
1439
+ children: s.image ? /* @__PURE__ */ jsx5(Crest, { image: s.image }) : s.label
1440
+ },
1441
+ String(s.competitionId ?? "all")
1442
+ )) });
1443
+ }
1444
+ function EntityCardItem({ c }) {
1445
+ const [active, setActive] = useState3(0);
1446
+ const hasBody = c.scopes.length > 0;
1447
+ if (!hasBody) {
1448
+ return /* @__PURE__ */ jsx5("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: false }) });
1437
1449
  }
1438
- return {
1439
- id: str(card.comboId) ?? legs.map((l) => l.matchOddsId).join("-"),
1440
- legs,
1441
- multiplication,
1442
- replacedNote: str(card.replacedNote),
1443
- addToSlipEnabled: card.addToSlipEnabled === true
1444
- };
1450
+ const multi = c.scopes.length > 1;
1451
+ const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
1452
+ return /* @__PURE__ */ jsxs3("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
1453
+ /* @__PURE__ */ jsx5(CardHeader, { c, showScopeCrest: !multi }),
1454
+ multi ? /* @__PURE__ */ jsx5(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
1455
+ /* @__PURE__ */ jsx5(StatStrip, { stats: scope.stats })
1456
+ ] });
1445
1457
  }
1446
- function comboLegToSlipSelection(leg, conversationId) {
1447
- const selection = {
1448
- matchOddsId: leg.matchOddsId,
1449
- matchId: leg.matchId,
1450
- oddsDecimal: leg.oddsDecimal,
1451
- insightId: leg.insightId
1452
- };
1453
- if (leg.quotedAtUtc !== void 0) selection.quotedAtUtc = leg.quotedAtUtc;
1454
- if (conversationId !== void 0) selection.conversationId = conversationId;
1455
- return selection;
1458
+ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1459
+ const [expanded, setExpanded] = useState3(false);
1460
+ if (cards.length === 0) return null;
1461
+ const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1462
+ const overflow = cards.length - MAX_VISIBLE;
1463
+ return /* @__PURE__ */ jsxs3("div", { className: "ss-w-cards", children: [
1464
+ visible.map((c) => /* @__PURE__ */ jsx5(EntityCardItem, { c }, c.id)),
1465
+ overflow > 0 ? /* @__PURE__ */ jsx5("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
1466
+ ] });
1456
1467
  }
1457
1468
 
1469
+ // src/components/AddToSlipButton.tsx
1470
+ import { useCallback, useState as useState4 } from "react";
1471
+ import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
1472
+
1458
1473
  // src/eventLogContext.ts
1459
1474
  import { createContext, useContext } from "react";
1460
1475
  var EventLogContext = createContext(null);
@@ -2010,10 +2025,10 @@ function ComboCardList({ cards, ui, slip }) {
2010
2025
  }
2011
2026
 
2012
2027
  // src/components/MarketOddsCardList.tsx
2013
- import { useState as useState8 } from "react";
2028
+ import { useEffect as useEffect3, useState as useState8 } from "react";
2014
2029
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2015
- function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
2016
- const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
2030
+ function OddsRow({ vm, row, ui, slip, inSlipIds, history, suppressSlip }) {
2031
+ const selection = vm.addToSlipEnabled && !suppressSlip ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
2017
2032
  const inSlip = !!inSlipIds && row.matchOddsId != null && !!inSlipIds[row.matchOddsId];
2018
2033
  return /* @__PURE__ */ jsxs10("div", { className: "ss-w-mo-row", children: [
2019
2034
  /* @__PURE__ */ jsx15("span", { className: "ss-w-mo-sel", children: row.selection }),
@@ -2031,17 +2046,34 @@ function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
2031
2046
  "\u2713 ",
2032
2047
  ui.inSlipLabel
2033
2048
  ] }) : null,
2034
- /* @__PURE__ */ jsx15(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui })
2049
+ !suppressSlip ? /* @__PURE__ */ jsx15(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui }) : null
2035
2050
  ] });
2036
2051
  }
2052
+ var STALE_AFTER_MS = 12e4;
2053
+ function fmtHhMm(iso, locale) {
2054
+ return new Date(iso).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit", hour12: false });
2055
+ }
2037
2056
  function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
2038
2057
  const [open, setOpen] = useState8(false);
2039
2058
  const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
2040
2059
  const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
2041
2060
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
2042
- const showPin = !!monitor && vm.pinEnabled;
2061
+ const live = vm.live ?? null;
2062
+ const closedReason = live?.closedReason ?? null;
2063
+ const isClosed = closedReason !== null;
2064
+ const asOfMs = live ? new Date(live.asOfUtc).getTime() : NaN;
2065
+ const isStale = live != null && !isClosed && (vm.awaitingLiveUpdate === true || Date.now() - asOfMs > STALE_AFTER_MS);
2066
+ const staleTime = isStale && live ? fmtHhMm(live.asOfUtc, ui?.locale ?? "en") : null;
2067
+ const [, setStaleTick] = useState8(0);
2068
+ const watchStale = live != null && !isClosed && !isStale;
2069
+ useEffect3(() => {
2070
+ if (!watchStale) return;
2071
+ const id = window.setTimeout(() => setStaleTick((n) => n + 1), Math.max(0, asOfMs + STALE_AFTER_MS - Date.now()) + 1);
2072
+ return () => window.clearTimeout(id);
2073
+ }, [watchStale, asOfMs]);
2074
+ const showPin = !!monitor && vm.pinEnabled && !live;
2043
2075
  const history = showPin && !pinRef && !hideHeader ? monitor : void 0;
2044
- const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
2076
+ const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin || !!live;
2045
2077
  return /* @__PURE__ */ jsxs10("div", { className: hideHeader ? "ss-w-mocard ss-w-mocard--bare" : "ss-w-mocard", children: [
2046
2078
  !hideHeader && /* @__PURE__ */ jsxs10(Fragment2, { children: [
2047
2079
  showHeader ? /* @__PURE__ */ jsxs10("div", { className: "ss-w-bi-header", children: [
@@ -2050,7 +2082,14 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
2050
2082
  /* @__PURE__ */ jsx15("span", { className: "ss-w-bi-comp", children: vm.competition })
2051
2083
  ] }) : null }),
2052
2084
  /* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-header-right", children: [
2053
- vm.isLive ? /* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-live", children: [
2085
+ live && !isClosed ? /* @__PURE__ */ jsxs10(Fragment2, { children: [
2086
+ /* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-score", children: [
2087
+ live.homeScore,
2088
+ "\u2013",
2089
+ live.awayScore
2090
+ ] }),
2091
+ live.minuteLabel ? /* @__PURE__ */ jsx15("span", { className: "ss-w-bi-min", children: live.minuteLabel }) : null
2092
+ ] }) : !live && vm.isLive ? /* @__PURE__ */ jsxs10("span", { className: "ss-w-bi-live", children: [
2054
2093
  /* @__PURE__ */ jsx15("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
2055
2094
  ui?.liveLabel ?? "Live"
2056
2095
  ] }) : null,
@@ -2080,14 +2119,17 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
2080
2119
  ] }) : null
2081
2120
  ] }),
2082
2121
  vm.statText && !hideHeader && !pinRef ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-stat", children: vm.statText }) : null,
2083
- /* @__PURE__ */ jsxs10("div", { className: "ss-w-mo-rows", children: [
2084
- vm.mainRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history }, row.key)),
2085
- open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history }, row.key)) : null
2122
+ isClosed ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-closed", children: closedReason === "suspended" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.suspended ?? "Market suspended" }) : closedReason === "no_live_price" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.noPrice ?? "No live price available" }) : closedReason === "full_time" ? /* @__PURE__ */ jsx15("span", { children: ui?.liveCard.fullTime ?? "Full time" }) : null }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
2123
+ /* @__PURE__ */ jsxs10("div", { className: "ss-w-mo-rows", children: [
2124
+ vm.mainRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)),
2125
+ open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx15(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)) : null
2126
+ ] }),
2127
+ vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs10("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
2128
+ /* @__PURE__ */ jsx15("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
2129
+ /* @__PURE__ */ jsx15("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
2130
+ ] }) : null,
2131
+ staleTime ? /* @__PURE__ */ jsx15("p", { className: "ss-w-mo-stale", children: ui?.liveCard.stale(staleTime) ?? `Prices from ${staleTime}` }) : null
2086
2132
  ] }),
2087
- vm.moreRows.length > 0 ? /* @__PURE__ */ jsxs10("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
2088
- /* @__PURE__ */ jsx15("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
2089
- /* @__PURE__ */ jsx15("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
2090
- ] }) : null,
2091
2133
  vm.bookmaker ? /* @__PURE__ */ jsx15("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ jsx15("span", { children: vm.bookmaker }) }) : null,
2092
2134
  vm.disclaimer ? /* @__PURE__ */ jsx15("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
2093
2135
  ] });
@@ -2098,7 +2140,7 @@ function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader, p
2098
2140
  }
2099
2141
 
2100
2142
  // src/components/CompactOddsList.tsx
2101
- import { useEffect as useEffect3, useRef as useRef2, useState as useState9 } from "react";
2143
+ import { useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
2102
2144
 
2103
2145
  // src/compactList.ts
2104
2146
  var COMPACT_MIN_CARDS = 3;
@@ -2215,7 +2257,7 @@ function CompactOddsList({ list, ui, slip, monitor }) {
2215
2257
  const hidden = list.rowCount - shown;
2216
2258
  const [focusIndex, setFocusIndex] = useState9(null);
2217
2259
  const focusRef = useRef2(null);
2218
- useEffect3(() => {
2260
+ useEffect4(() => {
2219
2261
  if (focusIndex !== null) focusRef.current?.focus();
2220
2262
  }, [focusIndex]);
2221
2263
  let left = shown;
@@ -2516,7 +2558,7 @@ function FixtureCard({ card }) {
2516
2558
  }
2517
2559
 
2518
2560
  // src/components/dashboard/CountdownCard.tsx
2519
- import { Fragment as Fragment6, useEffect as useEffect4, useState as useState10 } from "react";
2561
+ import { Fragment as Fragment6, useEffect as useEffect5, useState as useState10 } from "react";
2520
2562
  import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
2521
2563
  var DAY_MS = 864e5;
2522
2564
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -2540,7 +2582,7 @@ function CountdownCard({ card }) {
2540
2582
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
2541
2583
  );
2542
2584
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
2543
- useEffect4(() => {
2585
+ useEffect5(() => {
2544
2586
  if (reduced) return;
2545
2587
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
2546
2588
  return () => window.clearInterval(id);
@@ -2900,7 +2942,7 @@ function RestingFormCard({ card }) {
2900
2942
  import { useRef as useRef3, useState as useState14 } from "react";
2901
2943
 
2902
2944
  // src/useLiveClock.ts
2903
- import { useEffect as useEffect5, useState as useState13 } from "react";
2945
+ import { useEffect as useEffect6, useState as useState13 } from "react";
2904
2946
  var TICK_MS = 6e4;
2905
2947
  var MAX_LIVE_TICK_MINUTES = 15;
2906
2948
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -2912,7 +2954,7 @@ function useLiveClock(minute, clockRunning, receivedAtMs) {
2912
2954
  const [displayMinute, setDisplayMinute] = useState13(
2913
2955
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
2914
2956
  );
2915
- useEffect5(() => {
2957
+ useEffect6(() => {
2916
2958
  setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
2917
2959
  if (!clockRunning) return;
2918
2960
  const id = window.setInterval(() => {
@@ -3276,7 +3318,7 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
3276
3318
  const endRef = useRef4(null);
3277
3319
  const pinnedRef = useRef4(true);
3278
3320
  const anchoredTurnRef = useRef4(null);
3279
- useEffect6(() => {
3321
+ useEffect7(() => {
3280
3322
  const anchor = turnAnchor(state.messages);
3281
3323
  const list = listRef.current;
3282
3324
  if (anchor && anchor.turnId !== anchoredTurnRef.current) {
@@ -3836,7 +3878,7 @@ function TodayPanel({ discovery, ui, monitor }) {
3836
3878
  }
3837
3879
 
3838
3880
  // src/components/GamesPanel.tsx
3839
- import { useEffect as useEffect10, useState as useState31 } from "react";
3881
+ import { useEffect as useEffect11, useState as useState31 } from "react";
3840
3882
 
3841
3883
  // src/components/GamesLoginWall.tsx
3842
3884
  import { jsx as jsx55 } from "react/jsx-runtime";
@@ -3845,7 +3887,7 @@ function GamesLoginWall({ ui }) {
3845
3887
  }
3846
3888
 
3847
3889
  // src/components/GamesHub.tsx
3848
- import { useEffect as useEffect7, useState as useState18 } from "react";
3890
+ import { useEffect as useEffect8, useState as useState18 } from "react";
3849
3891
 
3850
3892
  // src/components/games/ui/gameMeta.ts
3851
3893
  function prettifyGameId(gameId) {
@@ -4031,7 +4073,7 @@ function pickHeroGame(games) {
4031
4073
  var tileKey = (g) => `${g.gameId}-${g.gameDay}-${g.fixtureId}`;
4032
4074
  function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
4033
4075
  const [, setTick] = useState18(0);
4034
- useEffect7(() => {
4076
+ useEffect8(() => {
4035
4077
  const id = setInterval(() => setTick((t) => t + 1), 6e4);
4036
4078
  return () => clearInterval(id);
4037
4079
  }, []);
@@ -4091,7 +4133,7 @@ function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
4091
4133
  }
4092
4134
 
4093
4135
  // src/components/GameScreenHost.tsx
4094
- import { useEffect as useEffect9, useRef as useRef7, useState as useState30 } from "react";
4136
+ import { useEffect as useEffect10, useRef as useRef7, useState as useState30 } from "react";
4095
4137
 
4096
4138
  // src/useGamePlay.ts
4097
4139
  import { useCallback as useCallback4, useRef as useRef5, useState as useState19 } from "react";
@@ -5044,7 +5086,7 @@ function CareerPathGame({
5044
5086
  }
5045
5087
 
5046
5088
  // src/components/games/BeatTheGridGame.tsx
5047
- import React, { useEffect as useEffect8, useId as useId4, useRef as useRef6, useState as useState24 } from "react";
5089
+ import React, { useEffect as useEffect9, useId as useId4, useRef as useRef6, useState as useState24 } from "react";
5048
5090
  import { Fragment as Fragment14, jsx as jsx74, jsxs as jsxs61 } from "react/jsx-runtime";
5049
5091
  function criterionIconKind(label, key) {
5050
5092
  const l = (key ?? label).toLowerCase();
@@ -5128,7 +5170,7 @@ function SearchSheet({
5128
5170
  const [query, setQuery] = useState24("");
5129
5171
  const inputId = useId4();
5130
5172
  const inputRef = useRef6(null);
5131
- useEffect8(() => {
5173
+ useEffect9(() => {
5132
5174
  inputRef.current?.focus();
5133
5175
  }, [row, col]);
5134
5176
  const filtered = playerPool.filter(
@@ -6430,7 +6472,7 @@ function GameScreenHost({
6430
6472
  }) {
6431
6473
  const { gameId, fixtureId, gameDay = "", lockAtUtc = null } = selected;
6432
6474
  const [configJson, setConfigJson] = useState30(null);
6433
- useEffect9(() => {
6475
+ useEffect10(() => {
6434
6476
  setConfigJson(null);
6435
6477
  if (!conversation) return;
6436
6478
  let cancelled = false;
@@ -6453,12 +6495,12 @@ function GameScreenHost({
6453
6495
  fixtureId: fixtureId || void 0,
6454
6496
  locale: ui.games.lang
6455
6497
  });
6456
- useEffect9(() => {
6498
+ useEffect10(() => {
6457
6499
  if (conversation) hydrate();
6458
6500
  }, [conversation, gameId]);
6459
6501
  const hydrateRef = useRef7(hydrate);
6460
6502
  hydrateRef.current = hydrate;
6461
- useEffect9(() => {
6503
+ useEffect10(() => {
6462
6504
  if (!FIXTURE_GAME_IDS.has(gameId)) return;
6463
6505
  if (rawStatus !== "pending") return;
6464
6506
  const timerId = setInterval(() => {
@@ -6594,7 +6636,7 @@ function GamesPanel({
6594
6636
  refreshHub
6595
6637
  }) {
6596
6638
  const [selected, setSelected] = useState31(null);
6597
- useEffect10(() => {
6639
+ useEffect11(() => {
6598
6640
  ensureGamesFonts();
6599
6641
  }, []);
6600
6642
  if (!loggedIn) return /* @__PURE__ */ jsx83(GamesLoginWall, { ui });
@@ -6794,7 +6836,7 @@ import { jsx as jsx88, jsxs as jsxs72 } from "react/jsx-runtime";
6794
6836
  var FULLSCREEN_QUERY = "(max-width: 639px)";
6795
6837
  function useIsModal() {
6796
6838
  const [modal, setModal] = useState33(false);
6797
- useEffect11(() => {
6839
+ useEffect12(() => {
6798
6840
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
6799
6841
  const mql = window.matchMedia(FULLSCREEN_QUERY);
6800
6842
  const sync = () => setModal(mql.matches);
@@ -6807,7 +6849,7 @@ function useIsModal() {
6807
6849
  function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }) {
6808
6850
  const { state, close, stop, send, reset } = controller;
6809
6851
  const isModal = useIsModal();
6810
- useEffect11(() => {
6852
+ useEffect12(() => {
6811
6853
  const onKey = (e) => {
6812
6854
  if (e.key === "Escape") close();
6813
6855
  };
@@ -6822,7 +6864,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6822
6864
  monitor?.setActiveTab("chat");
6823
6865
  send(text, { grounding });
6824
6866
  };
6825
- useEffect11(() => {
6867
+ useEffect12(() => {
6826
6868
  if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
6827
6869
  }, [monitor, state.isStreaming, state.messages.length]);
6828
6870
  return /* @__PURE__ */ jsxs72("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
@@ -7153,11 +7195,11 @@ function useHostEvents(opts) {
7153
7195
  logger?.log(toSlipEvent(name, entry));
7154
7196
  }
7155
7197
  };
7156
- useEffect12(() => {
7198
+ useEffect13(() => {
7157
7199
  if (!host) return;
7158
7200
  return attachHost(host, (command) => sinkRef.current(command));
7159
7201
  }, [host]);
7160
- useEffect12(() => {
7202
+ useEffect13(() => {
7161
7203
  if (!isOpen || !views) return;
7162
7204
  const held = views.markOpened();
7163
7205
  if (held.length === 0) return;
@@ -7248,12 +7290,27 @@ function themeAttrs(ui) {
7248
7290
  }
7249
7291
 
7250
7292
  // src/useChatStream.ts
7251
- import { useCallback as useCallback6, useEffect as useEffect14, useMemo as useMemo2, useReducer as useReducer2, useRef as useRef10 } from "react";
7293
+ import { useCallback as useCallback6, useEffect as useEffect15, useMemo as useMemo2, useReducer as useReducer2, useRef as useRef10 } from "react";
7252
7294
  import { WidgetSdkError as WidgetSdkError2 } from "@sensiblestats/widget-sdk";
7253
7295
 
7254
7296
  // src/reducer.ts
7255
7297
  import "@sensiblestats/widget-sdk";
7256
7298
  var POPUP_MAX = 160;
7299
+ function markAwaitingLiveUpdate(messages, held = []) {
7300
+ if (!messages.some((m) => m.role === "assistant" && m.marketOdds.some((vm) => vm.live != null))) return messages;
7301
+ const heldFlags = /* @__PURE__ */ new Map();
7302
+ for (const m of held) {
7303
+ if (m.role !== "assistant") continue;
7304
+ for (const vm of m.marketOdds) if (vm.live != null) heldFlags.set(`${m.id}|${vm.id}`, vm.awaitingLiveUpdate === true);
7305
+ }
7306
+ return messages.map((m) => {
7307
+ if (m.role !== "assistant" || !m.marketOdds.some((vm) => vm.live != null)) return m;
7308
+ return {
7309
+ ...m,
7310
+ marketOdds: m.marketOdds.map((vm) => vm.live != null ? { ...vm, awaitingLiveUpdate: heldFlags.get(`${m.id}|${vm.id}`) ?? true } : vm)
7311
+ };
7312
+ });
7313
+ }
7257
7314
  function initialState(starters) {
7258
7315
  return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, configuredStarters: starters, error: null, lastUserInput: null, lastDisplayText: null, popupText: null, conversationId: null };
7259
7316
  }
@@ -7345,7 +7402,7 @@ function reducer(state, action) {
7345
7402
  case "RESTORE":
7346
7403
  return {
7347
7404
  ...state,
7348
- messages: action.messages,
7405
+ messages: markAwaitingLiveUpdate(action.messages, state.messages),
7349
7406
  conversationId: action.conversationId,
7350
7407
  isStreaming: false,
7351
7408
  status: null,
@@ -7359,6 +7416,22 @@ function reducer(state, action) {
7359
7416
  return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
7360
7417
  case "STOP":
7361
7418
  return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
7419
+ case "UPDATE_LIVE_CARD": {
7420
+ const { matchId, live, mainRows, moreRows, addToSlipEnabled } = action;
7421
+ return {
7422
+ ...state,
7423
+ messages: state.messages.map((m) => {
7424
+ if (m.role !== "assistant") return m;
7425
+ if (!m.marketOdds.some((vm) => vm.matchId === matchId && vm.live != null)) return m;
7426
+ return {
7427
+ ...m,
7428
+ marketOdds: m.marketOdds.map(
7429
+ (vm) => vm.matchId === matchId && vm.live != null ? { ...vm, live, mainRows, moreRows, addToSlipEnabled, awaitingLiveUpdate: false } : vm
7430
+ )
7431
+ };
7432
+ })
7433
+ };
7434
+ }
7362
7435
  case "LIVE_REFRESH":
7363
7436
  return {
7364
7437
  ...state,
@@ -7377,7 +7450,7 @@ function reducer(state, action) {
7377
7450
  }
7378
7451
 
7379
7452
  // src/useLiveDashboardPoll.ts
7380
- import { useEffect as useEffect13, useReducer, useRef as useRef9 } from "react";
7453
+ import { useEffect as useEffect14, useReducer, useRef as useRef9 } from "react";
7381
7454
  var POLL_INTERVAL_MS = 6e4;
7382
7455
  var LEAD_MS = 12e4;
7383
7456
  var GIVE_UP_MS = 30 * 6e4;
@@ -7425,7 +7498,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
7425
7498
  anchorRef.current = anchor;
7426
7499
  const inFlightRef = useRef9(false);
7427
7500
  const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null;
7428
- useEffect13(() => {
7501
+ useEffect14(() => {
7429
7502
  if (!anchorKey || !anchorRef.current) return;
7430
7503
  const tick = async () => {
7431
7504
  if (inFlightRef.current) return;
@@ -7461,7 +7534,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
7461
7534
  }, POLL_INTERVAL_MS);
7462
7535
  return () => window.clearInterval(id);
7463
7536
  }, [anchorKey, dispatch, getLiveDashboard]);
7464
- useEffect13(() => {
7537
+ useEffect14(() => {
7465
7538
  if (anchorKey !== null) return;
7466
7539
  const wakeAt = findEarliestWakeupMs(messages);
7467
7540
  if (wakeAt === null) return;
@@ -7531,7 +7604,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7531
7604
  const restored = payload != null && payload !== "expired" && payload !== "corrupt";
7532
7605
  const base = initialState(starterTexts.map(chipFromText));
7533
7606
  if (restored) {
7534
- return { state: { ...base, messages: payload.messages, conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
7607
+ return { state: { ...base, messages: markAwaitingLiveUpdate(payload.messages), conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
7535
7608
  }
7536
7609
  return { state: base, restored: false, stale: payload === "expired" || payload === "corrupt" };
7537
7610
  }, []);
@@ -7624,15 +7697,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7624
7697
  dispatch({ kind: "STOP" });
7625
7698
  }
7626
7699
  }, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
7627
- useEffect14(() => {
7700
+ useEffect15(() => {
7628
7701
  if (greetedRef.current) return;
7629
7702
  greetedRef.current = true;
7630
7703
  fireGreeting();
7631
7704
  }, [fireGreeting]);
7632
- useEffect14(() => {
7705
+ useEffect15(() => {
7633
7706
  if (boot.stale && storageKey) clearConversation(storageKey);
7634
7707
  }, []);
7635
- useEffect14(() => {
7708
+ useEffect15(() => {
7636
7709
  if (!storageKey || state.isStreaming) return;
7637
7710
  if (hydratedRef.current) {
7638
7711
  hydratedRef.current = false;
@@ -7649,7 +7722,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7649
7722
  if (persistable.length === 0) return;
7650
7723
  writeConversation(storageKey, state.conversationId, persistable, Date.now());
7651
7724
  }, [storageKey, state.isStreaming, state.messages, state.conversationId]);
7652
- useEffect14(() => {
7725
+ useEffect15(() => {
7653
7726
  if (!storageKey) return;
7654
7727
  const onStorage = (e) => {
7655
7728
  if (e.key !== storageKey || e.storageArea !== window.localStorage) return;
@@ -7704,11 +7777,11 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7704
7777
  }, [storageKey, conversation, clearFallbackTimer, fireGreeting]);
7705
7778
  const getLiveDashboard = useCallback6(() => conversation.getLiveDashboard(), [conversation]);
7706
7779
  useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard });
7707
- return { state, open, close, stop, toggle, send, retry, dismissPopup, reset };
7780
+ return { state, open, close, stop, toggle, send, retry, dismissPopup, reset, _dispatch: dispatch };
7708
7781
  }
7709
7782
 
7710
7783
  // src/useLiveMonitor.ts
7711
- import { useCallback as useCallback7, useEffect as useEffect15, useRef as useRef11, useState as useState36 } from "react";
7784
+ import { useCallback as useCallback7, useEffect as useEffect16, useRef as useRef11, useState as useState36 } from "react";
7712
7785
 
7713
7786
  // src/useTabs.ts
7714
7787
  import { useState as useState35 } from "react";
@@ -7721,6 +7794,7 @@ function useTabs(initial = "chat") {
7721
7794
  var GOAL_OR_RED = /* @__PURE__ */ new Set(["goal", "red"]);
7722
7795
  var MIN_POLL_MS = 5e3;
7723
7796
  var DEFAULT_POLL_MS = 6e4;
7797
+ var LIVE_WATCH_POLL_MS = 12e3;
7724
7798
  function eventIdentity(e) {
7725
7799
  return `${e.type}:${e.side}:${e.minuteLabel}:${e.player ?? ""}`;
7726
7800
  }
@@ -7752,6 +7826,8 @@ function useLiveMonitor(opts) {
7752
7826
  const [marketOdds, setMarketOdds] = useState36({});
7753
7827
  const pinsRef = useRef11(pins);
7754
7828
  pinsRef.current = pins;
7829
+ const watchesRef = useRef11(opts.watches ?? []);
7830
+ watchesRef.current = opts.watches ?? [];
7755
7831
  const activeTabRef = useRef11(activeTab);
7756
7832
  activeTabRef.current = activeTab;
7757
7833
  const snapshotRef = useRef11(snapshot);
@@ -7869,10 +7945,11 @@ function useLiveMonitor(opts) {
7869
7945
  const getLiveMonitorRef = useRef11(opts.getLiveMonitor);
7870
7946
  getLiveMonitorRef.current = opts.getLiveMonitor;
7871
7947
  const tick = useCallback7(async () => {
7872
- if (inFlightRef.current || disabledRef.current || pinsRef.current.length === 0) return;
7948
+ const allPins = [...pinsRef.current, ...watchesRef.current];
7949
+ if (inFlightRef.current || disabledRef.current || allPins.length === 0) return;
7873
7950
  inFlightRef.current = true;
7874
7951
  try {
7875
- const snap = await getLiveMonitorRef.current(pinsRef.current);
7952
+ const snap = await getLiveMonitorRef.current(allPins);
7876
7953
  if (!mountedRef.current) return;
7877
7954
  if (snap === null) {
7878
7955
  disabledRef.current = true;
@@ -7895,27 +7972,36 @@ function useLiveMonitor(opts) {
7895
7972
  });
7896
7973
  scheduleRef.current = () => {
7897
7974
  window.clearTimeout(timerRef.current);
7898
- if (!mountedRef.current || disabledRef.current || pinsRef.current.length === 0 || document.visibilityState === "hidden") return;
7899
- const hinted = (snapshotRef.current?.nextPollSeconds ?? DEFAULT_POLL_MS / 1e3) * 1e3;
7975
+ const hasWork = pinsRef.current.length > 0 || watchesRef.current.length > 0;
7976
+ if (!mountedRef.current || disabledRef.current || !hasWork || document.visibilityState === "hidden") return;
7977
+ const fallbackMs = watchesRef.current.length > 0 ? LIVE_WATCH_POLL_MS : DEFAULT_POLL_MS;
7978
+ const hinted = snapshotRef.current ? snapshotRef.current.nextPollSeconds * 1e3 : fallbackMs;
7900
7979
  timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted));
7901
7980
  };
7902
- useEffect15(() => {
7981
+ useEffect16(() => {
7903
7982
  mountedRef.current = true;
7904
7983
  return () => {
7905
7984
  mountedRef.current = false;
7906
7985
  };
7907
7986
  }, []);
7908
7987
  const prevPinsLengthRef = useRef11(0);
7909
- useEffect15(() => {
7910
- const wasEmpty = prevPinsLengthRef.current === 0;
7988
+ useEffect16(() => {
7989
+ const wasEmpty = prevPinsLengthRef.current === 0 && watchesRef.current.length === 0;
7911
7990
  prevPinsLengthRef.current = pins.length;
7912
- if (pins.length === 0) {
7991
+ if (pins.length === 0 && watchesRef.current.length === 0) {
7913
7992
  window.clearTimeout(timerRef.current);
7914
7993
  return;
7915
7994
  }
7916
7995
  if (wasEmpty) void tick();
7917
7996
  }, [pins.length, tick]);
7918
- useEffect15(() => {
7997
+ const prevWatchesLengthRef = useRef11(0);
7998
+ const watchesLength = opts.watches?.length ?? 0;
7999
+ useEffect16(() => {
8000
+ const wasEmpty = prevWatchesLengthRef.current === 0 && pinsRef.current.length === 0;
8001
+ prevWatchesLengthRef.current = watchesLength;
8002
+ if (wasEmpty && watchesLength > 0) void tick();
8003
+ }, [watchesLength, tick]);
8004
+ useEffect16(() => {
7919
8005
  const matchPins = pins.filter((p) => p.kind === "match").length;
7920
8006
  const marketPins = pins.length - matchPins;
7921
8007
  if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
@@ -7923,12 +8009,12 @@ function useLiveMonitor(opts) {
7923
8009
  if (activeTab === "today" && !hasToday) setActiveTabState("chat");
7924
8010
  }, [pins, activeTab, hasToday]);
7925
8011
  const prevIsOpenRef = useRef11(false);
7926
- useEffect15(() => {
8012
+ useEffect16(() => {
7927
8013
  const wasClosed = !prevIsOpenRef.current;
7928
8014
  prevIsOpenRef.current = opts.isOpen;
7929
8015
  if (wasClosed && opts.isOpen) void tick();
7930
8016
  }, [opts.isOpen, tick]);
7931
- useEffect15(() => {
8017
+ useEffect16(() => {
7932
8018
  const onVisibility = () => {
7933
8019
  if (document.visibilityState === "hidden") window.clearTimeout(timerRef.current);
7934
8020
  else void tick();
@@ -7994,7 +8080,7 @@ function useLiveMonitor(opts) {
7994
8080
  }
7995
8081
 
7996
8082
  // src/useMatchDiscovery.ts
7997
- import { useCallback as useCallback8, useEffect as useEffect16, useMemo as useMemo3, useRef as useRef12, useState as useState37 } from "react";
8083
+ import { useCallback as useCallback8, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef12, useState as useState37 } from "react";
7998
8084
 
7999
8085
  // src/scheduleCache.ts
8000
8086
  var PREFIX = "ss-w-schedule:";
@@ -8095,14 +8181,14 @@ function useMatchDiscovery(opts) {
8095
8181
  getStatesRef.current = opts.getStates;
8096
8182
  const pinnedKey = opts.pinnedMatchIds.join(",");
8097
8183
  const [localDate, setLocalDate] = useState37(() => localDateOf(/* @__PURE__ */ new Date()));
8098
- useEffect16(() => {
8184
+ useEffect17(() => {
8099
8185
  const id = setInterval(() => {
8100
8186
  const next = localDateOf(/* @__PURE__ */ new Date());
8101
8187
  setLocalDate((prev) => prev === next ? prev : next);
8102
8188
  }, ROLLOVER_CHECK_MS);
8103
8189
  return () => clearInterval(id);
8104
8190
  }, []);
8105
- useEffect16(() => {
8191
+ useEffect17(() => {
8106
8192
  let cancelled = false;
8107
8193
  const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
8108
8194
  const cached = readSchedule(opts.operatorId, localDate, Date.now());
@@ -8127,7 +8213,7 @@ function useMatchDiscovery(opts) {
8127
8213
  cancelled = true;
8128
8214
  };
8129
8215
  }, [opts.operatorId, localDate]);
8130
- useEffect16(() => {
8216
+ useEffect17(() => {
8131
8217
  setExpanded((prev) => {
8132
8218
  const next = {};
8133
8219
  for (const group of groups) {
@@ -8154,7 +8240,7 @@ function useMatchDiscovery(opts) {
8154
8240
  setFailures((n) => n + 1);
8155
8241
  }
8156
8242
  }, []);
8157
- useEffect16(() => {
8243
+ useEffect17(() => {
8158
8244
  if (!opts.isOpen) return;
8159
8245
  void tick();
8160
8246
  const id = setInterval(() => {
@@ -8175,7 +8261,7 @@ function useMatchDiscovery(opts) {
8175
8261
  }
8176
8262
 
8177
8263
  // src/useGames.ts
8178
- import { useCallback as useCallback9, useEffect as useEffect17, useRef as useRef13, useState as useState38 } from "react";
8264
+ import { useCallback as useCallback9, useEffect as useEffect18, useRef as useRef13, useState as useState38 } from "react";
8179
8265
  var GAMES_POLL_MS = 6e4;
8180
8266
  var DEFAULT_TZ = "Europe/London";
8181
8267
  function computeGameDay(timezone) {
@@ -8193,7 +8279,7 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
8193
8279
  const tzRef = useRef13(operatorTimezone ?? DEFAULT_TZ);
8194
8280
  tzRef.current = operatorTimezone ?? DEFAULT_TZ;
8195
8281
  const ready = conversation != null;
8196
- useEffect17(() => {
8282
+ useEffect18(() => {
8197
8283
  if (hardOffRef.current) return;
8198
8284
  let active = true;
8199
8285
  const doFetch = async () => {
@@ -8243,7 +8329,7 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
8243
8329
  }
8244
8330
 
8245
8331
  // src/useLeaderboard.ts
8246
- import { useCallback as useCallback10, useEffect as useEffect18, useRef as useRef14, useState as useState39 } from "react";
8332
+ import { useCallback as useCallback10, useEffect as useEffect19, useRef as useRef14, useState as useState39 } from "react";
8247
8333
  function useLeaderboard(conversation, { activeTab }) {
8248
8334
  const [data, setData] = useState39(null);
8249
8335
  const [loading, setLoading] = useState39(false);
@@ -8251,7 +8337,7 @@ function useLeaderboard(conversation, { activeTab }) {
8251
8337
  const inFlightRef = useRef14(false);
8252
8338
  const conversationRef = useRef14(conversation);
8253
8339
  conversationRef.current = conversation;
8254
- useEffect18(() => {
8340
+ useEffect19(() => {
8255
8341
  if (activeTab !== "leaderboard" && activeTab !== "games") return;
8256
8342
  let active = true;
8257
8343
  const doFetch = async () => {
@@ -8281,11 +8367,11 @@ function useLeaderboard(conversation, { activeTab }) {
8281
8367
  }
8282
8368
 
8283
8369
  // src/popupTelemetry.ts
8284
- import { useCallback as useCallback11, useEffect as useEffect19, useRef as useRef15 } from "react";
8370
+ import { useCallback as useCallback11, useEffect as useEffect20, useRef as useRef15 } from "react";
8285
8371
  function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
8286
8372
  const shownRef = useRef15(/* @__PURE__ */ new Set());
8287
8373
  const closedTextRef = useRef15(null);
8288
- useEffect19(() => {
8374
+ useEffect20(() => {
8289
8375
  if (isOpen) {
8290
8376
  if (closedTextRef.current) log?.log({ name: "popup_opened" });
8291
8377
  closedTextRef.current = null;
@@ -8304,7 +8390,7 @@ function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
8304
8390
  }
8305
8391
 
8306
8392
  // src/components/ChatFab.tsx
8307
- import { useEffect as useEffect20, useRef as useRef16, useState as useState40 } from "react";
8393
+ import { useEffect as useEffect21, useRef as useRef16, useState as useState40 } from "react";
8308
8394
 
8309
8395
  // src/components/GreetingBubble.tsx
8310
8396
  import { jsx as jsx89, jsxs as jsxs73 } from "react/jsx-runtime";
@@ -8339,7 +8425,7 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
8339
8425
  const bubble = popupText ?? greeting;
8340
8426
  const [intro, setIntro] = useState40(false);
8341
8427
  const armedRef = useRef16(introAllowed);
8342
- useEffect20(() => {
8428
+ useEffect21(() => {
8343
8429
  if (armedRef.current && bubble) {
8344
8430
  armedRef.current = false;
8345
8431
  setIntro(true);
@@ -8751,6 +8837,12 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
8751
8837
  .ss-w-mo-more-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }
8752
8838
  .ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }
8753
8839
  .ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
8840
+ /* Stage 4: live card score+minute in header (R18). */
8841
+ .ss-w-bi-score { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); white-space: nowrap; }
8842
+ .ss-w-bi-min { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; }
8843
+ /* D12: closed state message row; D13: stale-price notice. */
8844
+ .ss-w-mo-closed { padding: 6px 0; font-size: 12.5px; color: var(--ss-w-faint); }
8845
+ .ss-w-mo-stale { margin: 0; font-size: 11px; color: var(--ss-w-faint); }
8754
8846
  /* The card's stat, in the Live tab accordion's insight style. No row below it is marked (R17). */
8755
8847
  .ss-w-mo-stat { font-size: 12px; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 7px 9px; }
8756
8848
  .ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
@@ -9953,12 +10045,27 @@ function StatsWidget(props) {
9953
10045
  const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
9954
10046
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
9955
10047
  const [hasToday, setHasToday] = useState41(false);
10048
+ const liveCardWatches = useMemo4(() => {
10049
+ const seen = /* @__PURE__ */ new Set();
10050
+ const out = [];
10051
+ for (const msg of controller.state.messages) {
10052
+ if (msg.role !== "assistant") continue;
10053
+ for (const vm of msg.marketOdds) {
10054
+ if (vm.live == null || seen.has(vm.matchId)) continue;
10055
+ seen.add(vm.matchId);
10056
+ out.push({ key: `live:card:${vm.matchId}`, kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName ?? "FULLTIME_RESULT" });
10057
+ }
10058
+ }
10059
+ return out;
10060
+ }, [controller.state.messages]);
10061
+ const locale = cfg?.locale;
9956
10062
  const monitor = useLiveMonitor({
9957
- getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
10063
+ getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins, locale) : Promise.resolve(null),
9958
10064
  getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
9959
10065
  storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
9960
10066
  isOpen: controller.state.isOpen,
9961
- hasToday
10067
+ hasToday,
10068
+ watches: liveCardWatches
9962
10069
  });
9963
10070
  const getSchedule = useCallback12(
9964
10071
  (localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
@@ -9980,14 +10087,49 @@ function StatsWidget(props) {
9980
10087
  pinnedMatchIds
9981
10088
  });
9982
10089
  const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
9983
- useEffect21(() => {
10090
+ useEffect22(() => {
9984
10091
  setHasToday(todayHasContent);
9985
10092
  }, [todayHasContent]);
10093
+ const prevLiveSnapshotRef = useRef17(monitor.snapshot);
10094
+ useEffect22(() => {
10095
+ const snap = monitor.snapshot;
10096
+ if (!snap || snap === prevLiveSnapshotRef.current) return;
10097
+ prevLiveSnapshotRef.current = snap;
10098
+ for (const market of snap.markets) {
10099
+ if (!market.key.startsWith("live:card:")) continue;
10100
+ const matchId = parseInt(market.key.slice("live:card:".length), 10);
10101
+ if (!Number.isFinite(matchId)) continue;
10102
+ let mainRows = [];
10103
+ let moreRows = [];
10104
+ let addToSlipEnabled = false;
10105
+ if (market.card) {
10106
+ const updated = toMarketOddsVM(market.card);
10107
+ mainRows = updated.mainRows;
10108
+ moreRows = updated.moreRows;
10109
+ addToSlipEnabled = updated.addToSlipEnabled;
10110
+ }
10111
+ let closedReason = null;
10112
+ if (market.phase === "fullTime" || market.phase === "postponed") closedReason = "full_time";
10113
+ else if (market.isSuspended) closedReason = "suspended";
10114
+ else if (!market.card) closedReason = "no_live_price";
10115
+ const live = {
10116
+ phase: market.phase,
10117
+ homeScore: market.homeScore ?? null,
10118
+ awayScore: market.awayScore ?? null,
10119
+ minuteLabel: market.minuteLabel ?? null,
10120
+ isSuspended: market.isSuspended,
10121
+ isSettled: market.isSettled,
10122
+ asOfUtc: market.asOfUtc,
10123
+ closedReason
10124
+ };
10125
+ controller._dispatch?.({ kind: "UPDATE_LIVE_CARD", matchId, live, mainRows, moreRows, addToSlipEnabled });
10126
+ }
10127
+ }, [monitor.snapshot]);
9986
10128
  const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
9987
10129
  const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
9988
10130
  const markTodayActivity = monitor.markTodayActivity;
9989
10131
  const prevLiveCountRef = useRef17(0);
9990
- useEffect21(() => {
10132
+ useEffect22(() => {
9991
10133
  const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
9992
10134
  prevLiveCountRef.current = discovery.liveCount;
9993
10135
  if (rose) markTodayActivity();
@@ -10040,11 +10182,11 @@ function StatsWidget(props) {
10040
10182
  const operatorUserId = cfg?.userContext?.operatorUserId;
10041
10183
  const anonymousUserId = cfg?.userContext?.anonymousUserId;
10042
10184
  const conversationId = controller.state.conversationId ?? void 0;
10043
- useEffect21(() => {
10185
+ useEffect22(() => {
10044
10186
  if (!logger) return;
10045
10187
  logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
10046
10188
  }, [logger, operatorUserId, anonymousUserId, conversationId]);
10047
- useEffect21(() => {
10189
+ useEffect22(() => {
10048
10190
  if (!logger) return;
10049
10191
  logger.resume();
10050
10192
  const onHide = () => {
@@ -10062,7 +10204,7 @@ function StatsWidget(props) {
10062
10204
  logger.dispose();
10063
10205
  };
10064
10206
  }, [logger]);
10065
- useEffect21(() => {
10207
+ useEffect22(() => {
10066
10208
  if (!built || !ui.injectStyles) return;
10067
10209
  const node = rootRef.current?.getRootNode();
10068
10210
  if (node) injectStyles(node);