@sensiblestats/widget-react 0.68.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -37,7 +37,7 @@ __export(index_exports, {
37
37
  module.exports = __toCommonJS(index_exports);
38
38
 
39
39
  // src/StatsWidget.tsx
40
- var import_react50 = require("react");
40
+ var import_react55 = require("react");
41
41
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
42
42
 
43
43
  // src/kickoff.ts
@@ -72,6 +72,12 @@ var STRINGS = {
72
72
  showMore: (n) => `Show ${n} more`,
73
73
  oddsLabel: "Odds",
74
74
  liveLabel: "Live",
75
+ liveCard: {
76
+ stale: (time) => `Prices from ${time}`,
77
+ suspended: "Market suspended",
78
+ noPrice: "No live price available",
79
+ fullTime: "Full time"
80
+ },
75
81
  yourMarketTag: "Your market",
76
82
  marketFloorLabel: "Market price \xB7 not a value pick",
77
83
  addToSlip: "Add to slip",
@@ -155,6 +161,30 @@ var STRINGS = {
155
161
  gamePlay: "Play",
156
162
  gameLocked: "Locked",
157
163
  gameVoided: "Voided",
164
+ presets: {
165
+ lang: "en",
166
+ setNumbers: "Set the numbers",
167
+ buildCombo: "Build a combo",
168
+ dialName: "Set the numbers and Build a combo",
169
+ maxPriceRow: "{count} picks, max {price}",
170
+ minPriceRow: "Picks from {price} up",
171
+ comboRow: "A combo of {legs} matches priced at about {total}",
172
+ maxPriceDisplay: (count, price) => `${count} picks, max ${price.toFixed(2)}`,
173
+ maxPriceMessage: (count, price) => `Show me ${count} picks priced at ${price.toFixed(2)} or less.`,
174
+ minPriceDisplay: (count, price) => `${count} picks from ${price.toFixed(2)} up`,
175
+ minPriceMessage: (count, price) => `Show me ${count} picks priced at ${price.toFixed(2)} or more.`,
176
+ comboDisplay: (legs, total) => `A combo of ${legs} priced at about ${total.toFixed(1)}`,
177
+ comboMessage: (legs, total) => `Build me a combo of ${legs} priced at about ${total.toFixed(1)}.`,
178
+ unavailable: "Not available today.",
179
+ send: "Send",
180
+ close: "Close",
181
+ totalLabel: "Total",
182
+ matchesLabel: "Matches",
183
+ fewerMatches: "Fewer matches",
184
+ moreMatches: "More matches",
185
+ changeNumber: (value) => `${value}, tap to change`,
186
+ changeCombo: "Change total or matches"
187
+ },
158
188
  games: {
159
189
  lang: "en",
160
190
  dailyChallenge: "Daily challenge",
@@ -372,6 +402,12 @@ var STRINGS = {
372
402
  showMore: (n) => `${n} tane daha g\xF6ster`,
373
403
  oddsLabel: "Oran",
374
404
  liveLabel: "Canl\u0131",
405
+ liveCard: {
406
+ stale: (time) => `${time} itibar\u0131yla fiyatlar`,
407
+ suspended: "Market ask\u0131ya al\u0131nd\u0131",
408
+ noPrice: "Canl\u0131 fiyat mevcut de\u011Fil",
409
+ fullTime: "Ma\xE7 bitti"
410
+ },
375
411
  yourMarketTag: "\u0130lgilendi\u011Fin bahis",
376
412
  marketFloorLabel: "Piyasa oran\u0131 \xB7 de\u011Fer bahsi de\u011Fil",
377
413
  addToSlip: "Kupona ekle",
@@ -455,6 +491,30 @@ var STRINGS = {
455
491
  gamePlay: "Oyna",
456
492
  gameLocked: "Kilitli",
457
493
  gameVoided: "\u0130ptal edildi",
494
+ presets: {
495
+ lang: "tr",
496
+ setNumbers: "Say\u0131lar\u0131 belirle",
497
+ buildCombo: "Kombin olu\u015Ftur",
498
+ dialName: "Say\u0131lar\u0131 belirle ve Kombin olu\u015Ftur",
499
+ maxPriceRow: "{count} se\xE7im, en fazla {price}",
500
+ minPriceRow: "{price} ve \xFCzeri se\xE7imler",
501
+ comboRow: "Yakla\u015F\u0131k {total} oranl\u0131 {legs} ma\xE7l\u0131k kombin",
502
+ maxPriceDisplay: (count, price) => `${count} se\xE7im, en fazla ${price.toFixed(2)}`,
503
+ maxPriceMessage: (count, price) => `${price.toFixed(2)} veya alt\u0131 oranl\u0131 ${count} se\xE7im g\xF6ster.`,
504
+ minPriceDisplay: (count, price) => `${count} se\xE7im, ${price.toFixed(2)} ve \xFCzeri`,
505
+ minPriceMessage: (count, price) => `${price.toFixed(2)} veya \xFCzeri oranl\u0131 ${count} se\xE7im g\xF6ster.`,
506
+ comboDisplay: (legs, total) => `${legs} ma\xE7l\u0131k kombin, yakla\u015F\u0131k ${total.toFixed(1)}`,
507
+ comboMessage: (legs, total) => `Yakla\u015F\u0131k ${total.toFixed(1)} oranl\u0131 ${legs} ma\xE7l\u0131k bir kombin haz\u0131rla.`,
508
+ unavailable: "Bug\xFCn mevcut de\u011Fil.",
509
+ send: "G\xF6nder",
510
+ close: "Kapat",
511
+ totalLabel: "Toplam",
512
+ matchesLabel: "Ma\xE7 say\u0131s\u0131",
513
+ fewerMatches: "Daha az ma\xE7",
514
+ moreMatches: "Daha fazla ma\xE7",
515
+ changeNumber: (value) => `${value}, de\u011Fi\u015Ftirmek i\xE7in dokun`,
516
+ changeCombo: "Toplam\u0131 veya ma\xE7lar\u0131 de\u011Fi\u015Ftir"
517
+ },
458
518
  games: {
459
519
  lang: "tr",
460
520
  dailyChallenge: "G\xFCn\xFCn meydan okumas\u0131",
@@ -673,6 +733,7 @@ function normalizeUi(cfg) {
673
733
  accent: cfg.accent,
674
734
  logoUrl: cfg.logoUrl,
675
735
  headerTitle: cfg.headerTitle,
736
+ locale: cfg.locale ?? "en",
676
737
  rawBettingLabels: isEnglishLocale(cfg.locale),
677
738
  cta: cfg.cta,
678
739
  surface: cfg.surface,
@@ -779,7 +840,9 @@ function normalizeUi(cfg) {
779
840
  gamePlay: strings.gamePlay,
780
841
  gameLocked: strings.gameLocked,
781
842
  gameVoided: strings.gameVoided,
782
- games: strings.games
843
+ games: strings.games,
844
+ presets: strings.presets,
845
+ liveCard: strings.liveCard
783
846
  };
784
847
  }
785
848
  function toClientOptions(cfg) {
@@ -791,121 +854,478 @@ function toUserContext(cfg) {
791
854
  return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : void 0;
792
855
  }
793
856
 
794
- // src/slip.ts
795
- var ADD_TO_SLIP_TIMEOUT_MS = 1e4;
796
- var MAX_SELECTION = 64;
797
- var MAX_LINE = 32;
798
- var MAX_ODDS = 1e4;
799
- function slipPickFields(selection, label, line) {
800
- const fields = {};
801
- if (Number.isSafeInteger(selection.matchId) && selection.matchId > 0) fields.matchId = selection.matchId;
802
- if (label && label.trim() && label.length <= MAX_SELECTION) fields.selection = label;
803
- if (line && line.trim() && line.length <= MAX_LINE) fields.line = line;
804
- const odds = selection.oddsDecimal;
805
- if (Number.isFinite(odds) && odds > 1 && odds <= MAX_ODDS) fields.odds = odds;
806
- return fields;
807
- }
808
- function chipSelection(market, matchId, conversationId) {
809
- if (!market || !market.addToSlipEnabled || typeof market.matchOddsId !== "number" || typeof market.price !== "number") return null;
810
- const selection = { matchOddsId: market.matchOddsId, matchId, oddsDecimal: market.price };
811
- if (conversationId !== void 0) selection.conversationId = conversationId;
812
- return selection;
813
- }
814
- function wasAdded(result) {
815
- if (!result) return true;
816
- if (result.status === "price_changed") return result.accepted;
817
- return result.status === "added";
857
+ // src/chart.ts
858
+ var CHART_VIEW_W = 320;
859
+ var CHART_VIEW_H = 140;
860
+ var PLOT_X0 = 40;
861
+ var PLOT_X1 = 312;
862
+ var PLOT_Y0 = 10;
863
+ var PLOT_Y1 = 110;
864
+ var MARKER_MAX_POINTS = 8;
865
+ var FLAT_DOMAIN_PAD = 0.05;
866
+ var round2 = (n) => Math.round(n * 100) / 100;
867
+ function projectSeries(samples) {
868
+ if (samples.length < 2) return null;
869
+ const tMin = samples[0].atMs;
870
+ const tMax = samples[samples.length - 1].atMs;
871
+ if (tMax <= tMin) return null;
872
+ const prices = samples.map((s) => s.price);
873
+ const pMin = Math.min(...prices);
874
+ const pMax = Math.max(...prices);
875
+ let yMin;
876
+ let yMax;
877
+ if (pMax === pMin) {
878
+ yMin = pMin - FLAT_DOMAIN_PAD;
879
+ yMax = pMax + FLAT_DOMAIN_PAD;
880
+ } else {
881
+ const pad = (pMax - pMin) * 0.1;
882
+ yMin = pMin - pad;
883
+ yMax = pMax + pad;
884
+ }
885
+ const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
886
+ const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
887
+ const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
888
+ const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
889
+ return {
890
+ path,
891
+ markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
892
+ // The real extremes, never the padded bounds: a gridline label is a price, and the padded
893
+ // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
894
+ // two identical gridlines would collide on both React key and rendered text.
895
+ gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
896
+ { y: y(pMax), price: pMax },
897
+ { y: y(pMin), price: pMin }
898
+ ],
899
+ viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
900
+ startMs: tMin,
901
+ endMs: tMax
902
+ };
818
903
  }
819
- function isTerminal(result) {
820
- if (!result) return true;
821
- if (result.status === "price_changed") return result.accepted;
822
- return result.status === "added" || result.status === "duplicate";
904
+
905
+ // src/model.ts
906
+ function str(v) {
907
+ return typeof v === "string" && v.length > 0 ? v : void 0;
823
908
  }
824
- function slipOutcome(result) {
825
- if (!result) return "added";
826
- switch (result.status) {
827
- case "added":
828
- case "duplicate":
829
- return result.status;
830
- case "price_changed":
831
- return result.accepted ? "added" : "price_changed";
832
- case "rejected":
833
- return result.reason;
834
- }
909
+ function num(v) {
910
+ return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
835
911
  }
836
- function resultToToast(result, shownOdds, ui) {
837
- if (!result) return { kind: "success", text: ui.slipAdded };
838
- switch (result.status) {
839
- case "added":
840
- return { kind: "success", text: ui.slipAdded };
841
- case "duplicate":
842
- return { kind: "success", text: ui.slipDuplicate };
843
- case "price_changed":
844
- return result.accepted ? { kind: "success", text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) } : { kind: "error", text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) };
845
- case "rejected":
846
- if (result.reason === "login_required") return { kind: "error", text: ui.slipLoginRequired };
847
- if (result.reason === "suspended") return { kind: "error", text: ui.slipSuspended };
848
- return { kind: "error", text: result.message ?? ui.slipFailed };
912
+ function readStatCells(raw) {
913
+ if (!Array.isArray(raw)) return [];
914
+ const cells = [];
915
+ for (const entry of raw) {
916
+ const label = str(entry.label);
917
+ const value = num(entry.value) ?? str(entry.value);
918
+ if (label !== void 0 && value !== void 0) cells.push({ label, value });
849
919
  }
920
+ return cells;
850
921
  }
851
-
852
- // src/useHostEvents.ts
853
- var import_react40 = require("react");
854
-
855
- // src/components/ChatPanel.tsx
856
- var import_react39 = require("react");
857
-
858
- // src/components/ChatHeader.tsx
859
- var import_react2 = require("react");
860
-
861
- // src/assets/logo.ts
862
- var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
863
-
864
- // src/components/Icons.tsx
865
- var import_jsx_runtime = require("react/jsx-runtime");
866
- function SsMark({ className }) {
867
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
922
+ function toCardVM(card) {
923
+ const entityType = str(card.entityType)?.toLowerCase();
924
+ const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
925
+ const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
926
+ const label = str(s.label);
927
+ if (!label) return null;
928
+ return {
929
+ competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
930
+ label,
931
+ image: str(s.imagePath),
932
+ stats: readStatCells(s.stats)
933
+ };
934
+ }).filter((s) => s !== null) : [];
935
+ return {
936
+ id: String(card.entityId),
937
+ kind,
938
+ name: card.canonicalName,
939
+ image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
940
+ sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
941
+ season: str(card.seasonName),
942
+ scopes
943
+ };
868
944
  }
869
- function SendIcon() {
870
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
945
+ function toActionVM(action) {
946
+ const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
947
+ const actionId = str(action.actionId) ?? str(action.id);
948
+ const actionRef = str(action.actionRef);
949
+ const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
950
+ return { label, actionId, actionRef, message };
871
951
  }
872
- function CloseIcon() {
873
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
952
+ function toChipVM(intent) {
953
+ const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
954
+ return text ? { text } : null;
874
955
  }
875
- function ChevronIcon() {
876
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
956
+ function chipFromText(text) {
957
+ return { text };
877
958
  }
878
- function KebabIcon() {
879
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "currentColor", children: [
880
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "5", r: "1.6" }),
881
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "1.6" }),
882
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "19", r: "1.6" })
883
- ] }) });
959
+ function joinSelection(label, line) {
960
+ if (label && line && label.includes(line)) return label;
961
+ return [label, line].filter(Boolean).join(" ") || void 0;
884
962
  }
885
- var DASHBOARD_EMOJI = {
886
- football: "\u26BD",
887
- "goal-net": "\u{1F945}",
888
- btts: "\u{1F91D}",
889
- card: "\u{1F7E8}",
890
- "corner-flag": "\u{1F6A9}",
891
- player: "\u{1F464}",
892
- target: "\u{1F3AF}",
893
- trophy: "\u{1F3C6}",
894
- "chart-line": "\u{1F4C8}",
895
- "chart-bar": "\u{1F4CA}",
896
- chat: "\u{1F4AC}",
897
- fire: "\u{1F525}",
898
- sparkle: "\u2728"
899
- };
900
- function DashboardIcon({ name }) {
901
- const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
902
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
963
+ function toInsightVM(insight) {
964
+ const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
965
+ const selectionLabel = str(insight.selectionLabel);
966
+ const selectionLine = str(insight.line);
967
+ const selection = joinSelection(selectionLabel, selectionLine);
968
+ const value = insight.odds?.value;
969
+ const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
970
+ const oddsValue = insight.odds?.value;
971
+ const matchOddsId = typeof insight.odds?.matchOddsId === "number" ? insight.odds.matchOddsId : void 0;
972
+ const home = str(insight.homeTeamName);
973
+ const away = str(insight.awayTeamName);
974
+ const fixture = home && away ? `${home} vs ${away}` : void 0;
975
+ const competition = str(insight.competitionName);
976
+ const previousValue = insight.odds?.previousValue;
977
+ const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
978
+ const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
979
+ return {
980
+ id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
981
+ market,
982
+ selection,
983
+ odds,
984
+ // The wire payload carries bookmakerId (not a name); render a name only if one is present.
985
+ bookmaker: str(insight.odds?.bookmakerName),
986
+ isLive: insight.odds?.isLive === true,
987
+ phase: str(insight.phase),
988
+ fixture,
989
+ competition,
990
+ text: str(insight.text) ?? "",
991
+ disclaimer: str(insight.disclaimer),
992
+ matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
993
+ matchOddsId,
994
+ marketDeveloperName: str(insight.marketDeveloperName),
995
+ selectionLabel: str(insight.selectionLabel),
996
+ line: str(insight.line),
997
+ addToSlipEnabled: insight.addToSlipEnabled === true,
998
+ pinEnabled: insight.pinEnabled === true,
999
+ isMarketFloor: insight.isMarketFloor === true,
1000
+ oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
1001
+ quotedAtUtc: str(insight.odds?.quotedAtUtc),
1002
+ previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1003
+ movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
1004
+ homeTeamName: home,
1005
+ awayTeamName: away,
1006
+ homeCrest: str(insight.homeTeamImagePath),
1007
+ awayCrest: str(insight.awayTeamImagePath),
1008
+ competitionCrest: str(insight.competitionImagePath),
1009
+ kickoffUtc: str(insight.kickoffUtc),
1010
+ kickoffLabel: str(insight.kickoffLabel)
1011
+ };
903
1012
  }
904
-
905
- // src/components/BrandMark.tsx
906
- var import_react = require("react");
907
- var import_jsx_runtime2 = require("react/jsx-runtime");
908
- function BrandMark({ logoUrl, className }) {
1013
+ function toSlipSelection(vm, conversationId) {
1014
+ if (vm.matchOddsId === void 0 || vm.oddsDecimal === void 0) return null;
1015
+ const selection = {
1016
+ matchOddsId: vm.matchOddsId,
1017
+ matchId: vm.matchId,
1018
+ oddsDecimal: vm.oddsDecimal
1019
+ };
1020
+ if (vm.quotedAtUtc !== void 0) selection.quotedAtUtc = vm.quotedAtUtc;
1021
+ if (vm.id !== void 0) selection.insightId = vm.id;
1022
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1023
+ return selection;
1024
+ }
1025
+ function toMarketOddsVM(card) {
1026
+ const rows = Array.isArray(card.rows) ? card.rows : [];
1027
+ const toRow = (r, i) => {
1028
+ const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
1029
+ const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
1030
+ const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
1031
+ const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
1032
+ return {
1033
+ key: `${selection}:${str(r.line) ?? ""}:${i}`,
1034
+ selection,
1035
+ selectionLabel: str(r.selectionLabel),
1036
+ line: str(r.line),
1037
+ odds: price !== void 0 ? price.toFixed(2) : "",
1038
+ oddsDecimal: price,
1039
+ matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
1040
+ quotedAtUtc: str(r.quotedAtUtc),
1041
+ isMain: r.isMainLine !== false,
1042
+ // === true, not !== false: a server that has not shipped the field yet leaves it undefined,
1043
+ // and undefined must read as open rather than hiding every price on the card.
1044
+ isSuspended: r.isSuspended === true,
1045
+ previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1046
+ movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
1047
+ };
1048
+ };
1049
+ const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
1050
+ const home = str(card.homeTeamName);
1051
+ const away = str(card.awayTeamName);
1052
+ const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
1053
+ return {
1054
+ id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
1055
+ market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1056
+ fixture: home && away ? `${home} vs ${away}` : void 0,
1057
+ homeTeamName: home,
1058
+ awayTeamName: away,
1059
+ homeCrest: str(card.homeTeamImagePath),
1060
+ awayCrest: str(card.awayTeamImagePath),
1061
+ competitionCrest: str(card.competitionImagePath),
1062
+ competition: str(card.competitionName),
1063
+ kickoffUtc: str(card.kickoffUtc),
1064
+ kickoffLabel: str(card.kickoffLabel),
1065
+ bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
1066
+ updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
1067
+ isLive: rows.some((r) => r.isLive === true),
1068
+ matchId: typeof card.matchId === "number" ? card.matchId : 0,
1069
+ mainRows: vms.filter((r) => r.isMain),
1070
+ moreRows: vms.filter((r) => !r.isMain),
1071
+ disclaimer: str(card.disclaimer),
1072
+ addToSlipEnabled: card.addToSlipEnabled === true,
1073
+ marketDeveloperName: str(card.marketDeveloperName),
1074
+ mainLine: str(card.mainLine),
1075
+ pinEnabled: card.pinEnabled === true,
1076
+ statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
1077
+ tag: card.tag === "your_market" ? "your_market" : void 0,
1078
+ live: card.live ?? null
1079
+ };
1080
+ }
1081
+ function toOddsMovementVM(card) {
1082
+ const raw = Array.isArray(card.points) ? card.points : [];
1083
+ const samples = [];
1084
+ for (const p of raw) {
1085
+ const price = typeof p.price === "number" && Number.isFinite(p.price) ? p.price : void 0;
1086
+ const atMs = typeof p.atUtc === "string" ? Date.parse(p.atUtc) : NaN;
1087
+ if (price === void 0 || Number.isNaN(atMs)) continue;
1088
+ samples.push({ atMs, price });
1089
+ }
1090
+ samples.sort((a, b) => a.atMs - b.atMs);
1091
+ const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
1092
+ const opening = asNumber(card.openingPrice);
1093
+ const current = asNumber(card.currentPrice);
1094
+ const home = str(card.homeTeamName);
1095
+ const away = str(card.awayTeamName);
1096
+ const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
1097
+ const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
1098
+ return {
1099
+ id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
1100
+ matchId: typeof card.matchId === "number" ? card.matchId : 0,
1101
+ market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1102
+ marketDeveloperName: str(card.marketDeveloperName),
1103
+ selection,
1104
+ selectionLabel: str(card.selectionLabel),
1105
+ line: str(card.line),
1106
+ fixture: home && away ? `${home} vs ${away}` : void 0,
1107
+ competition: str(card.competitionName),
1108
+ bookmaker: str(card.bookmakerName),
1109
+ opening: opening !== void 0 ? opening.toFixed(2) : "",
1110
+ current: current !== void 0 ? current.toFixed(2) : "",
1111
+ direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
1112
+ windowHours: asNumber(card.windowHours) ?? 0,
1113
+ excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
1114
+ isSuspended: card.isSuspended === true,
1115
+ disclaimer: str(card.disclaimer),
1116
+ geometry: projectSeries(samples),
1117
+ observationCount: samples.length,
1118
+ pinEnabled: card.pinEnabled === true,
1119
+ matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
1120
+ };
1121
+ }
1122
+ function marketOddsRowToSlipSelection(vm, row, conversationId) {
1123
+ if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
1124
+ const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
1125
+ if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
1126
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1127
+ return selection;
1128
+ }
1129
+ function finite(v) {
1130
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1131
+ }
1132
+ function toComboLegVM(leg) {
1133
+ if (!leg || typeof leg !== "object") return null;
1134
+ const price = finite(leg.price);
1135
+ const matchOddsId = finite(leg.matchOddsId);
1136
+ const matchId = finite(leg.matchId);
1137
+ const home = str(leg.homeTeamName);
1138
+ const away = str(leg.awayTeamName);
1139
+ const selectionLabel = str(leg.selectionLabel);
1140
+ const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
1141
+ const insightId = str(insight?.insightId);
1142
+ const statText = str(insight?.text);
1143
+ if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
1144
+ const line = str(leg.line);
1145
+ return {
1146
+ key: `${matchOddsId}`,
1147
+ matchId,
1148
+ homeTeamName: home,
1149
+ awayTeamName: away,
1150
+ homeCrest: str(leg.homeTeamImagePath),
1151
+ awayCrest: str(leg.awayTeamImagePath),
1152
+ competition: str(leg.competitionName),
1153
+ kickoffUtc: str(leg.kickoffUtc),
1154
+ kickoffLabel: str(leg.kickoffLabel),
1155
+ market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
1156
+ marketDeveloperName: str(leg.marketDeveloperName) ?? "",
1157
+ selection: joinSelection(selectionLabel, line) ?? selectionLabel,
1158
+ selectionLabel,
1159
+ line,
1160
+ odds: price.toFixed(2),
1161
+ oddsDecimal: price,
1162
+ matchOddsId,
1163
+ quotedAtUtc: str(leg.quotedAtUtc),
1164
+ insightId,
1165
+ statText
1166
+ };
1167
+ }
1168
+ function toComboCardVM(card) {
1169
+ const rawLegs = Array.isArray(card?.legs) ? card.legs : [];
1170
+ const multiplication = str(card?.multiplication);
1171
+ if (rawLegs.length < 2 || !multiplication) return null;
1172
+ const legs = [];
1173
+ for (const raw of rawLegs) {
1174
+ const vm = toComboLegVM(raw);
1175
+ if (!vm) return null;
1176
+ legs.push(vm);
1177
+ }
1178
+ return {
1179
+ id: str(card.comboId) ?? legs.map((l) => l.matchOddsId).join("-"),
1180
+ legs,
1181
+ multiplication,
1182
+ replacedNote: str(card.replacedNote),
1183
+ addToSlipEnabled: card.addToSlipEnabled === true,
1184
+ target: finite(card.target),
1185
+ legCount: finite(card.legCount)
1186
+ };
1187
+ }
1188
+ function comboLegToSlipSelection(leg, conversationId) {
1189
+ const selection = {
1190
+ matchOddsId: leg.matchOddsId,
1191
+ matchId: leg.matchId,
1192
+ oddsDecimal: leg.oddsDecimal,
1193
+ insightId: leg.insightId
1194
+ };
1195
+ if (leg.quotedAtUtc !== void 0) selection.quotedAtUtc = leg.quotedAtUtc;
1196
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1197
+ return selection;
1198
+ }
1199
+
1200
+ // src/slip.ts
1201
+ var ADD_TO_SLIP_TIMEOUT_MS = 1e4;
1202
+ var MAX_SELECTION = 64;
1203
+ var MAX_LINE = 32;
1204
+ var MAX_ODDS = 1e4;
1205
+ function slipPickFields(selection, label, line) {
1206
+ const fields = {};
1207
+ if (Number.isSafeInteger(selection.matchId) && selection.matchId > 0) fields.matchId = selection.matchId;
1208
+ if (label && label.trim() && label.length <= MAX_SELECTION) fields.selection = label;
1209
+ if (line && line.trim() && line.length <= MAX_LINE) fields.line = line;
1210
+ const odds = selection.oddsDecimal;
1211
+ if (Number.isFinite(odds) && odds > 1 && odds <= MAX_ODDS) fields.odds = odds;
1212
+ return fields;
1213
+ }
1214
+ function chipSelection(market, matchId, conversationId) {
1215
+ if (!market || !market.addToSlipEnabled || typeof market.matchOddsId !== "number" || typeof market.price !== "number") return null;
1216
+ const selection = { matchOddsId: market.matchOddsId, matchId, oddsDecimal: market.price };
1217
+ if (conversationId !== void 0) selection.conversationId = conversationId;
1218
+ return selection;
1219
+ }
1220
+ function wasAdded(result) {
1221
+ if (!result) return true;
1222
+ if (result.status === "price_changed") return result.accepted;
1223
+ return result.status === "added";
1224
+ }
1225
+ function isTerminal(result) {
1226
+ if (!result) return true;
1227
+ if (result.status === "price_changed") return result.accepted;
1228
+ return result.status === "added" || result.status === "duplicate";
1229
+ }
1230
+ function slipOutcome(result) {
1231
+ if (!result) return "added";
1232
+ switch (result.status) {
1233
+ case "added":
1234
+ case "duplicate":
1235
+ return result.status;
1236
+ case "price_changed":
1237
+ return result.accepted ? "added" : "price_changed";
1238
+ case "rejected":
1239
+ return result.reason;
1240
+ }
1241
+ }
1242
+ function resultToToast(result, shownOdds, ui) {
1243
+ if (!result) return { kind: "success", text: ui.slipAdded };
1244
+ switch (result.status) {
1245
+ case "added":
1246
+ return { kind: "success", text: ui.slipAdded };
1247
+ case "duplicate":
1248
+ return { kind: "success", text: ui.slipDuplicate };
1249
+ case "price_changed":
1250
+ return result.accepted ? { kind: "success", text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) } : { kind: "error", text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) };
1251
+ case "rejected":
1252
+ if (result.reason === "login_required") return { kind: "error", text: ui.slipLoginRequired };
1253
+ if (result.reason === "suspended") return { kind: "error", text: ui.slipSuspended };
1254
+ return { kind: "error", text: result.message ?? ui.slipFailed };
1255
+ }
1256
+ }
1257
+
1258
+ // src/useHostEvents.ts
1259
+ var import_react44 = require("react");
1260
+
1261
+ // src/components/ChatPanel.tsx
1262
+ var import_react43 = require("react");
1263
+
1264
+ // src/components/ChatHeader.tsx
1265
+ var import_react2 = require("react");
1266
+
1267
+ // src/assets/logo.ts
1268
+ var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
1269
+
1270
+ // src/components/Icons.tsx
1271
+ var import_jsx_runtime = require("react/jsx-runtime");
1272
+ function SsMark({ className }) {
1273
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { className, src: SS_LOGO_DATA_URI, alt: "", "aria-hidden": "true" });
1274
+ }
1275
+ function SendIcon() {
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
1277
+ }
1278
+ function CloseIcon() {
1279
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
1280
+ }
1281
+ function ChevronIcon() {
1282
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
1283
+ }
1284
+ function KebabIcon() {
1285
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "currentColor", children: [
1286
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "5", r: "1.6" }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "1.6" }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "19", r: "1.6" })
1289
+ ] }) });
1290
+ }
1291
+ function SlidersIcon() {
1292
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "6", r: "2" }),
1295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "12", r: "2" }),
1296
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "17", cy: "18", r: "2" })
1297
+ ] }) });
1298
+ }
1299
+ function ComboIcon() {
1300
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round", children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "11", height: "11", rx: "2" }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "10", y: "10", width: "11", height: "11", rx: "2" })
1303
+ ] }) });
1304
+ }
1305
+ var DASHBOARD_EMOJI = {
1306
+ football: "\u26BD",
1307
+ "goal-net": "\u{1F945}",
1308
+ btts: "\u{1F91D}",
1309
+ card: "\u{1F7E8}",
1310
+ "corner-flag": "\u{1F6A9}",
1311
+ player: "\u{1F464}",
1312
+ target: "\u{1F3AF}",
1313
+ trophy: "\u{1F3C6}",
1314
+ "chart-line": "\u{1F4C8}",
1315
+ "chart-bar": "\u{1F4CA}",
1316
+ chat: "\u{1F4AC}",
1317
+ fire: "\u{1F525}",
1318
+ sparkle: "\u2728"
1319
+ };
1320
+ function DashboardIcon({ name }) {
1321
+ const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name) ? DASHBOARD_EMOJI[name] : DASHBOARD_EMOJI.target;
1322
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-w-dash-emoji", "aria-hidden": "true", children: glyph });
1323
+ }
1324
+
1325
+ // src/components/BrandMark.tsx
1326
+ var import_react = require("react");
1327
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1328
+ function BrandMark({ logoUrl, className }) {
909
1329
  const [failed, setFailed] = (0, import_react.useState)(false);
910
1330
  if (!logoUrl || failed) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SsMark, { className });
911
1331
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -948,551 +1368,211 @@ function ChatHeader({
948
1368
  document.removeEventListener("mousedown", onPointer);
949
1369
  document.removeEventListener("keydown", onKey);
950
1370
  };
951
- }, [menuOpen]);
952
- const runNewConversation = () => {
953
- setMenuOpen(false);
954
- onNewConversation?.();
955
- };
956
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "ss-w-header", children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BrandMark, { logoUrl, className: "ss-w-header-mark" }),
958
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ss-w-header-title", children: headerTitle ?? "SensibleStats" }),
959
- hasMenu ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ss-w-menu-wrap", ref: wrapRef, children: [
960
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
961
- "button",
962
- {
963
- type: "button",
964
- className: "ss-w-kebab",
965
- ref: kebabRef,
966
- "aria-haspopup": "menu",
967
- "aria-expanded": menuOpen,
968
- "aria-label": moreOptionsLabel,
969
- onClick: () => setMenuOpen((open) => !open),
970
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(KebabIcon, {})
971
- }
972
- ),
973
- menuOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ss-w-menu", role: "menu", "aria-label": moreOptionsLabel, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
974
- "button",
975
- {
976
- type: "button",
977
- className: "ss-w-menu-item",
978
- role: "menuitem",
979
- ref: firstItemRef,
980
- onClick: runNewConversation,
981
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: newConversationLabel })
982
- }
983
- ) }) : null
984
- ] }) : null,
985
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CloseIcon, {}) })
986
- ] });
987
- }
988
-
989
- // src/components/MessageList.tsx
990
- var import_react21 = require("react");
991
-
992
- // src/presets.ts
993
- var CLIENT_CAPABILITIES = ["price_presets"];
994
- var PRICE_TILE_PREFIX = "goal-preset-";
995
- function isPriceTile(tile) {
996
- const id = tile.signal?.entityId;
997
- return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
998
- }
999
- function tileDisplayText(tile) {
1000
- const subtitle = tile.subtitle?.trim();
1001
- return isPriceTile(tile) && subtitle ? subtitle : tile.title;
1002
- }
1003
- var MAX_BUBBLE_ASKS = 2;
1004
- function bubbleAsks(messages) {
1005
- for (let i = messages.length - 1; i >= 0; i--) {
1006
- const m = messages[i];
1007
- if (!m || m.role !== "assistant" || !m.isGreeting) continue;
1008
- const dashboard = m.greetingDashboard;
1009
- if (!dashboard) return [];
1010
- const asks = [];
1011
- dashboard.tiles.forEach((tile, index) => {
1012
- const label = tile.subtitle?.trim();
1013
- if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
1014
- });
1015
- return asks;
1016
- }
1017
- return [];
1018
- }
1019
- function runBubbleAsk(ask, deps) {
1020
- deps.log?.log({ name: "popup_ask_tap", outcome: String(ask.position) });
1021
- deps.open();
1022
- deps.setActiveTab("chat");
1023
- const displayText = tileDisplayText(ask.tile);
1024
- deps.send(ask.tile.actionValue, ask.tile.actionRef ? { actionRef: ask.tile.actionRef, displayText } : { displayText });
1025
- deps.onDashboardTap?.(ask.tile, ask.index, ask.layout);
1026
- }
1027
-
1028
- // src/components/Markdown.tsx
1029
- var import_react_markdown = __toESM(require("react-markdown"), 1);
1030
- var import_remark_gfm = __toESM(require("remark-gfm"), 1);
1031
- var import_jsx_runtime4 = require("react/jsx-runtime");
1032
- var components = {
1033
- a: ({ children, href }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
1034
- table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("table", { className: "ss-w-md-table", children }) }),
1035
- ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "ss-w-md-ul", children }),
1036
- ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "ss-w-md-ol", children }),
1037
- code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { className: "ss-w-md-code", children })
1038
- };
1039
- function Markdown({ text }) {
1040
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-w-md", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components, children: text }) });
1041
- }
1042
-
1043
- // src/components/EntityCardList.tsx
1044
- var import_react3 = require("react");
1045
- var import_jsx_runtime5 = require("react/jsx-runtime");
1046
- var MAX_VISIBLE = 3;
1047
- var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
1048
- function initials(name) {
1049
- return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
1050
- }
1051
- function shortSeason(season) {
1052
- return season.replace(/\d{4}/g, (year) => year.slice(2));
1053
- }
1054
- function Crest({ image, label }) {
1055
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1056
- "span",
1057
- {
1058
- className: "ss-w-ecard-crest",
1059
- style: { backgroundImage: `url(${image})` },
1060
- ...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
1061
- }
1062
- );
1063
- }
1064
- function FormBar({ w, d, l }) {
1065
- if (w + d + l === 0) return null;
1066
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-form", "aria-hidden": "true", children: [
1067
- w > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-w", style: { flexGrow: w } }) : null,
1068
- d > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-d", style: { flexGrow: d } }) : null,
1069
- l > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
1070
- ] });
1071
- }
1072
- function StatCellView({ s }) {
1073
- const m = RECORD_RE.exec(s.value);
1074
- if (m) {
1075
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-cell", children: [
1076
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
1077
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-clabel", children: s.value })
1078
- ] });
1079
- }
1080
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-cell", children: [
1081
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-cval", children: s.value }),
1082
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-clabel", children: s.label })
1083
- ] });
1084
- }
1085
- function StatStrip({ stats }) {
1086
- if (stats.length === 0) return null;
1087
- const cols = Math.min(stats.length, 4);
1088
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatCellView, { s }, s.label + s.value)) });
1089
- }
1090
- function CardHeader({ c, showScopeCrest }) {
1091
- const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
1092
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-hd", children: [
1093
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1094
- "span",
1095
- {
1096
- className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
1097
- style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
1098
- children: c.image ? "" : initials(c.name)
1099
- }
1100
- ),
1101
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-ecard-idtext", children: [
1102
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-nm", children: c.name }),
1103
- c.sub ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
1104
- ] }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-ecard-meta", children: [
1106
- showScopeCrest && onlyScope?.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
1107
- c.season ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
1108
- ] })
1109
- ] });
1110
- }
1111
- function ScopeTabs({ scopes, active, onSelect }) {
1112
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1113
- "button",
1114
- {
1115
- type: "button",
1116
- role: "tab",
1117
- className: "ss-w-ecard-scope",
1118
- "aria-selected": i === active,
1119
- "aria-label": s.label,
1120
- title: s.label,
1121
- onClick: () => onSelect(i),
1122
- children: s.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Crest, { image: s.image }) : s.label
1123
- },
1124
- String(s.competitionId ?? "all")
1125
- )) });
1126
- }
1127
- function EntityCardItem({ c }) {
1128
- const [active, setActive] = (0, import_react3.useState)(0);
1129
- const hasBody = c.scopes.length > 0;
1130
- if (!hasBody) {
1131
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardHeader, { c, showScopeCrest: false }) });
1132
- }
1133
- const multi = c.scopes.length > 1;
1134
- const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
1135
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
1136
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardHeader, { c, showScopeCrest: !multi }),
1137
- multi ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
1138
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatStrip, { stats: scope.stats })
1139
- ] });
1140
- }
1141
- function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1142
- const [expanded, setExpanded] = (0, import_react3.useState)(false);
1143
- if (cards.length === 0) return null;
1144
- const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1145
- const overflow = cards.length - MAX_VISIBLE;
1146
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-cards", children: [
1147
- visible.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EntityCardItem, { c }, c.id)),
1148
- overflow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
1149
- ] });
1150
- }
1151
-
1152
- // src/components/AddToSlipButton.tsx
1153
- var import_react7 = require("react");
1154
- var import_widget_sdk = require("@sensiblestats/widget-sdk");
1155
-
1156
- // src/chart.ts
1157
- var CHART_VIEW_W = 320;
1158
- var CHART_VIEW_H = 140;
1159
- var PLOT_X0 = 40;
1160
- var PLOT_X1 = 312;
1161
- var PLOT_Y0 = 10;
1162
- var PLOT_Y1 = 110;
1163
- var MARKER_MAX_POINTS = 8;
1164
- var FLAT_DOMAIN_PAD = 0.05;
1165
- var round2 = (n) => Math.round(n * 100) / 100;
1166
- function projectSeries(samples) {
1167
- if (samples.length < 2) return null;
1168
- const tMin = samples[0].atMs;
1169
- const tMax = samples[samples.length - 1].atMs;
1170
- if (tMax <= tMin) return null;
1171
- const prices = samples.map((s) => s.price);
1172
- const pMin = Math.min(...prices);
1173
- const pMax = Math.max(...prices);
1174
- let yMin;
1175
- let yMax;
1176
- if (pMax === pMin) {
1177
- yMin = pMin - FLAT_DOMAIN_PAD;
1178
- yMax = pMax + FLAT_DOMAIN_PAD;
1179
- } else {
1180
- const pad = (pMax - pMin) * 0.1;
1181
- yMin = pMin - pad;
1182
- yMax = pMax + pad;
1183
- }
1184
- const x = (atMs) => round2(PLOT_X0 + (atMs - tMin) / (tMax - tMin) * (PLOT_X1 - PLOT_X0));
1185
- const y = (price) => round2(PLOT_Y1 - (price - yMin) / (yMax - yMin) * (PLOT_Y1 - PLOT_Y0));
1186
- const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }));
1187
- const path = projected.map((p, i) => `${i === 0 ? "M" : "L"}${p.x} ${p.y}`).join(" ");
1188
- return {
1189
- path,
1190
- markers: samples.length <= MARKER_MAX_POINTS ? projected : [],
1191
- // The real extremes, never the padded bounds: a gridline label is a price, and the padded
1192
- // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —
1193
- // two identical gridlines would collide on both React key and rendered text.
1194
- gridlines: pMax === pMin ? [{ y: y(pMax), price: pMax }] : [
1195
- { y: y(pMax), price: pMax },
1196
- { y: y(pMin), price: pMin }
1197
- ],
1198
- viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,
1199
- startMs: tMin,
1200
- endMs: tMax
1371
+ }, [menuOpen]);
1372
+ const runNewConversation = () => {
1373
+ setMenuOpen(false);
1374
+ onNewConversation?.();
1201
1375
  };
1376
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("header", { className: "ss-w-header", children: [
1377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BrandMark, { logoUrl, className: "ss-w-header-mark" }),
1378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ss-w-header-title", children: headerTitle ?? "SensibleStats" }),
1379
+ hasMenu ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ss-w-menu-wrap", ref: wrapRef, children: [
1380
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1381
+ "button",
1382
+ {
1383
+ type: "button",
1384
+ className: "ss-w-kebab",
1385
+ ref: kebabRef,
1386
+ "aria-haspopup": "menu",
1387
+ "aria-expanded": menuOpen,
1388
+ "aria-label": moreOptionsLabel,
1389
+ onClick: () => setMenuOpen((open) => !open),
1390
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(KebabIcon, {})
1391
+ }
1392
+ ),
1393
+ menuOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ss-w-menu", role: "menu", "aria-label": moreOptionsLabel, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1394
+ "button",
1395
+ {
1396
+ type: "button",
1397
+ className: "ss-w-menu-item",
1398
+ role: "menuitem",
1399
+ ref: firstItemRef,
1400
+ onClick: runNewConversation,
1401
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: newConversationLabel })
1402
+ }
1403
+ ) }) : null
1404
+ ] }) : null,
1405
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CloseIcon, {}) })
1406
+ ] });
1202
1407
  }
1203
1408
 
1204
- // src/model.ts
1205
- function str(v) {
1206
- return typeof v === "string" && v.length > 0 ? v : void 0;
1409
+ // src/components/MessageList.tsx
1410
+ var import_react22 = require("react");
1411
+
1412
+ // src/presets.ts
1413
+ var CLIENT_CAPABILITIES = ["price_presets"];
1414
+ var PRICE_TILE_PREFIX = "goal-preset-";
1415
+ function isPriceTile(tile) {
1416
+ const id = tile.signal?.entityId;
1417
+ return typeof id === "string" && id.startsWith(PRICE_TILE_PREFIX);
1207
1418
  }
1208
- function num(v) {
1209
- return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
1419
+ function tileDisplayText(tile) {
1420
+ const subtitle = tile.subtitle?.trim();
1421
+ return isPriceTile(tile) && subtitle ? subtitle : tile.title;
1210
1422
  }
1211
- function readStatCells(raw) {
1212
- if (!Array.isArray(raw)) return [];
1213
- const cells = [];
1214
- for (const entry of raw) {
1215
- const label = str(entry.label);
1216
- const value = num(entry.value) ?? str(entry.value);
1217
- if (label !== void 0 && value !== void 0) cells.push({ label, value });
1423
+ var MAX_BUBBLE_ASKS = 2;
1424
+ function bubbleAsks(messages) {
1425
+ for (let i = messages.length - 1; i >= 0; i--) {
1426
+ const m = messages[i];
1427
+ if (!m || m.role !== "assistant" || !m.isGreeting) continue;
1428
+ const dashboard = m.greetingDashboard;
1429
+ if (!dashboard) return [];
1430
+ const asks = [];
1431
+ dashboard.tiles.forEach((tile, index) => {
1432
+ const label = tile.subtitle?.trim();
1433
+ if (asks.length < MAX_BUBBLE_ASKS && isPriceTile(tile) && label) asks.push({ tile, index, position: asks.length, layout: dashboard.layout, label });
1434
+ });
1435
+ return asks;
1218
1436
  }
1219
- return cells;
1220
- }
1221
- function toCardVM(card) {
1222
- const entityType = str(card.entityType)?.toLowerCase();
1223
- const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
1224
- const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
1225
- const label = str(s.label);
1226
- if (!label) return null;
1227
- return {
1228
- competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
1229
- label,
1230
- image: str(s.imagePath),
1231
- stats: readStatCells(s.stats)
1232
- };
1233
- }).filter((s) => s !== null) : [];
1234
- return {
1235
- id: String(card.entityId),
1236
- kind,
1237
- name: card.canonicalName,
1238
- image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
1239
- sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
1240
- season: str(card.seasonName),
1241
- scopes
1242
- };
1243
- }
1244
- function toActionVM(action) {
1245
- const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
1246
- const actionId = str(action.actionId) ?? str(action.id);
1247
- const actionRef = str(action.actionRef);
1248
- const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label;
1249
- return { label, actionId, actionRef, message };
1250
- }
1251
- function toChipVM(intent) {
1252
- const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
1253
- return text ? { text } : null;
1254
- }
1255
- function chipFromText(text) {
1256
- return { text };
1257
- }
1258
- function joinSelection(label, line) {
1259
- if (label && line && label.includes(line)) return label;
1260
- return [label, line].filter(Boolean).join(" ") || void 0;
1437
+ return [];
1261
1438
  }
1262
- function toInsightVM(insight) {
1263
- const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? "";
1264
- const selectionLabel = str(insight.selectionLabel);
1265
- const selectionLine = str(insight.line);
1266
- const selection = joinSelection(selectionLabel, selectionLine);
1267
- const value = insight.odds?.value;
1268
- const odds = typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : void 0;
1269
- const oddsValue = insight.odds?.value;
1270
- const matchOddsId = typeof insight.odds?.matchOddsId === "number" ? insight.odds.matchOddsId : void 0;
1271
- const home = str(insight.homeTeamName);
1272
- const away = str(insight.awayTeamName);
1273
- const fixture = home && away ? `${home} vs ${away}` : void 0;
1274
- const competition = str(insight.competitionName);
1275
- const previousValue = insight.odds?.previousValue;
1276
- const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
1277
- const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
1278
- return {
1279
- id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
1280
- market,
1281
- selection,
1282
- odds,
1283
- // The wire payload carries bookmakerId (not a name); render a name only if one is present.
1284
- bookmaker: str(insight.odds?.bookmakerName),
1285
- isLive: insight.odds?.isLive === true,
1286
- phase: str(insight.phase),
1287
- fixture,
1288
- competition,
1289
- text: str(insight.text) ?? "",
1290
- disclaimer: str(insight.disclaimer),
1291
- matchId: typeof insight.matchId === "number" ? insight.matchId : 0,
1292
- matchOddsId,
1293
- marketDeveloperName: str(insight.marketDeveloperName),
1294
- selectionLabel: str(insight.selectionLabel),
1295
- line: str(insight.line),
1296
- addToSlipEnabled: insight.addToSlipEnabled === true,
1297
- pinEnabled: insight.pinEnabled === true,
1298
- isMarketFloor: insight.isMarketFloor === true,
1299
- oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
1300
- quotedAtUtc: str(insight.odds?.quotedAtUtc),
1301
- previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1302
- movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0,
1303
- homeTeamName: home,
1304
- awayTeamName: away,
1305
- homeCrest: str(insight.homeTeamImagePath),
1306
- awayCrest: str(insight.awayTeamImagePath),
1307
- competitionCrest: str(insight.competitionImagePath),
1308
- kickoffUtc: str(insight.kickoffUtc),
1309
- kickoffLabel: str(insight.kickoffLabel)
1310
- };
1439
+ function runBubbleAsk(ask, deps) {
1440
+ deps.log?.log({ name: "popup_ask_tap", outcome: String(ask.position) });
1441
+ deps.open();
1442
+ deps.setActiveTab("chat");
1443
+ const displayText = tileDisplayText(ask.tile);
1444
+ deps.send(ask.tile.actionValue, ask.tile.actionRef ? { actionRef: ask.tile.actionRef, displayText } : { displayText });
1445
+ deps.onDashboardTap?.(ask.tile, ask.index, ask.layout);
1311
1446
  }
1312
- function toSlipSelection(vm, conversationId) {
1313
- if (vm.matchOddsId === void 0 || vm.oddsDecimal === void 0) return null;
1314
- const selection = {
1315
- matchOddsId: vm.matchOddsId,
1316
- matchId: vm.matchId,
1317
- oddsDecimal: vm.oddsDecimal
1318
- };
1319
- if (vm.quotedAtUtc !== void 0) selection.quotedAtUtc = vm.quotedAtUtc;
1320
- if (vm.id !== void 0) selection.insightId = vm.id;
1321
- if (conversationId !== void 0) selection.conversationId = conversationId;
1322
- return selection;
1447
+
1448
+ // src/components/Markdown.tsx
1449
+ var import_react_markdown = __toESM(require("react-markdown"), 1);
1450
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
1451
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1452
+ var components = {
1453
+ a: ({ children, href }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
1454
+ table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("table", { className: "ss-w-md-table", children }) }),
1455
+ ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "ss-w-md-ul", children }),
1456
+ ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "ss-w-md-ol", children }),
1457
+ code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { className: "ss-w-md-code", children })
1458
+ };
1459
+ function Markdown({ text }) {
1460
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-w-md", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components, children: text }) });
1323
1461
  }
1324
- function toMarketOddsVM(card) {
1325
- const rows = Array.isArray(card.rows) ? card.rows : [];
1326
- const toRow = (r, i) => {
1327
- const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? "";
1328
- const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
1329
- const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
1330
- const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
1331
- return {
1332
- key: `${selection}:${str(r.line) ?? ""}:${i}`,
1333
- selection,
1334
- selectionLabel: str(r.selectionLabel),
1335
- line: str(r.line),
1336
- odds: price !== void 0 ? price.toFixed(2) : "",
1337
- oddsDecimal: price,
1338
- matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
1339
- quotedAtUtc: str(r.quotedAtUtc),
1340
- isMain: r.isMainLine !== false,
1341
- // === true, not !== false: a server that has not shipped the field yet leaves it undefined,
1342
- // and undefined must read as open rather than hiding every price on the card.
1343
- isSuspended: r.isSuspended === true,
1344
- previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
1345
- movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
1346
- };
1347
- };
1348
- const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended);
1349
- const home = str(card.homeTeamName);
1350
- const away = str(card.awayTeamName);
1351
- const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
1352
- return {
1353
- id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
1354
- market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1355
- fixture: home && away ? `${home} vs ${away}` : void 0,
1356
- homeTeamName: home,
1357
- awayTeamName: away,
1358
- homeCrest: str(card.homeTeamImagePath),
1359
- awayCrest: str(card.awayTeamImagePath),
1360
- competitionCrest: str(card.competitionImagePath),
1361
- competition: str(card.competitionName),
1362
- kickoffUtc: str(card.kickoffUtc),
1363
- kickoffLabel: str(card.kickoffLabel),
1364
- bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
1365
- updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
1366
- isLive: rows.some((r) => r.isLive === true),
1367
- matchId: typeof card.matchId === "number" ? card.matchId : 0,
1368
- mainRows: vms.filter((r) => r.isMain),
1369
- moreRows: vms.filter((r) => !r.isMain),
1370
- disclaimer: str(card.disclaimer),
1371
- addToSlipEnabled: card.addToSlipEnabled === true,
1372
- marketDeveloperName: str(card.marketDeveloperName),
1373
- mainLine: str(card.mainLine),
1374
- pinEnabled: card.pinEnabled === true,
1375
- statText: card.insight && typeof card.insight === "object" ? str(card.insight.text) : void 0,
1376
- tag: card.tag === "your_market" ? "your_market" : void 0
1377
- };
1462
+
1463
+ // src/components/EntityCardList.tsx
1464
+ var import_react3 = require("react");
1465
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1466
+ var MAX_VISIBLE = 3;
1467
+ var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
1468
+ function initials(name) {
1469
+ return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
1378
1470
  }
1379
- function toOddsMovementVM(card) {
1380
- const raw = Array.isArray(card.points) ? card.points : [];
1381
- const samples = [];
1382
- for (const p of raw) {
1383
- const price = typeof p.price === "number" && Number.isFinite(p.price) ? p.price : void 0;
1384
- const atMs = typeof p.atUtc === "string" ? Date.parse(p.atUtc) : NaN;
1385
- if (price === void 0 || Number.isNaN(atMs)) continue;
1386
- samples.push({ atMs, price });
1471
+ function shortSeason(season) {
1472
+ return season.replace(/\d{4}/g, (year) => year.slice(2));
1473
+ }
1474
+ function Crest({ image, label }) {
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1476
+ "span",
1477
+ {
1478
+ className: "ss-w-ecard-crest",
1479
+ style: { backgroundImage: `url(${image})` },
1480
+ ...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
1481
+ }
1482
+ );
1483
+ }
1484
+ function FormBar({ w, d, l }) {
1485
+ if (w + d + l === 0) return null;
1486
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-form", "aria-hidden": "true", children: [
1487
+ w > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-w", style: { flexGrow: w } }) : null,
1488
+ d > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-d", style: { flexGrow: d } }) : null,
1489
+ l > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
1490
+ ] });
1491
+ }
1492
+ function StatCellView({ s }) {
1493
+ const m = RECORD_RE.exec(s.value);
1494
+ if (m) {
1495
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-cell", children: [
1496
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-clabel", children: s.value })
1498
+ ] });
1387
1499
  }
1388
- samples.sort((a, b) => a.atMs - b.atMs);
1389
- const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
1390
- const opening = asNumber(card.openingPrice);
1391
- const current = asNumber(card.currentPrice);
1392
- const home = str(card.homeTeamName);
1393
- const away = str(card.awayTeamName);
1394
- const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? "";
1395
- const bookmakerId = typeof card.bookmakerId === "number" ? card.bookmakerId : "";
1396
- return {
1397
- id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}:${selection}:${bookmakerId}`,
1398
- matchId: typeof card.matchId === "number" ? card.matchId : 0,
1399
- market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
1400
- marketDeveloperName: str(card.marketDeveloperName),
1401
- selection,
1402
- selectionLabel: str(card.selectionLabel),
1403
- line: str(card.line),
1404
- fixture: home && away ? `${home} vs ${away}` : void 0,
1405
- competition: str(card.competitionName),
1406
- bookmaker: str(card.bookmakerName),
1407
- opening: opening !== void 0 ? opening.toFixed(2) : "",
1408
- current: current !== void 0 ? current.toFixed(2) : "",
1409
- direction: card.movementDirection === "shortened" || card.movementDirection === "drifted" ? card.movementDirection : void 0,
1410
- windowHours: asNumber(card.windowHours) ?? 0,
1411
- excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,
1412
- isSuspended: card.isSuspended === true,
1413
- disclaimer: str(card.disclaimer),
1414
- geometry: projectSeries(samples),
1415
- observationCount: samples.length,
1416
- pinEnabled: card.pinEnabled === true,
1417
- matchOddsId: typeof card.matchOddsId === "number" ? card.matchOddsId : void 0
1418
- };
1500
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-cell", children: [
1501
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-cval", children: s.value }),
1502
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-clabel", children: s.label })
1503
+ ] });
1419
1504
  }
1420
- function marketOddsRowToSlipSelection(vm, row, conversationId) {
1421
- if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
1422
- const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
1423
- if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
1424
- if (conversationId !== void 0) selection.conversationId = conversationId;
1425
- return selection;
1505
+ function StatStrip({ stats }) {
1506
+ if (stats.length === 0) return null;
1507
+ const cols = Math.min(stats.length, 4);
1508
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatCellView, { s }, s.label + s.value)) });
1426
1509
  }
1427
- function finite(v) {
1428
- return typeof v === "number" && Number.isFinite(v) ? v : void 0;
1510
+ function CardHeader({ c, showScopeCrest }) {
1511
+ const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
1512
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard-hd", children: [
1513
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1514
+ "span",
1515
+ {
1516
+ className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
1517
+ style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
1518
+ children: c.image ? "" : initials(c.name)
1519
+ }
1520
+ ),
1521
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-ecard-idtext", children: [
1522
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-nm", children: c.name }),
1523
+ c.sub ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
1524
+ ] }),
1525
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-w-ecard-meta", children: [
1526
+ showScopeCrest && onlyScope?.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
1527
+ c.season ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
1528
+ ] })
1529
+ ] });
1429
1530
  }
1430
- function toComboLegVM(leg) {
1431
- if (!leg || typeof leg !== "object") return null;
1432
- const price = finite(leg.price);
1433
- const matchOddsId = finite(leg.matchOddsId);
1434
- const matchId = finite(leg.matchId);
1435
- const home = str(leg.homeTeamName);
1436
- const away = str(leg.awayTeamName);
1437
- const selectionLabel = str(leg.selectionLabel);
1438
- const insight = leg.insight && typeof leg.insight === "object" ? leg.insight : void 0;
1439
- const insightId = str(insight?.insightId);
1440
- const statText = str(insight?.text);
1441
- if (price === void 0 || matchOddsId === void 0 || matchId === void 0 || !home || !away || !selectionLabel || !insightId || !statText) return null;
1442
- const line = str(leg.line);
1443
- return {
1444
- key: `${matchOddsId}`,
1445
- matchId,
1446
- homeTeamName: home,
1447
- awayTeamName: away,
1448
- homeCrest: str(leg.homeTeamImagePath),
1449
- awayCrest: str(leg.awayTeamImagePath),
1450
- competition: str(leg.competitionName),
1451
- kickoffUtc: str(leg.kickoffUtc),
1452
- kickoffLabel: str(leg.kickoffLabel),
1453
- market: str(leg.marketLabel) ?? str(leg.marketDeveloperName) ?? "",
1454
- marketDeveloperName: str(leg.marketDeveloperName) ?? "",
1455
- selection: joinSelection(selectionLabel, line) ?? selectionLabel,
1456
- selectionLabel,
1457
- line,
1458
- odds: price.toFixed(2),
1459
- oddsDecimal: price,
1460
- matchOddsId,
1461
- quotedAtUtc: str(leg.quotedAtUtc),
1462
- insightId,
1463
- statText
1464
- };
1531
+ function ScopeTabs({ scopes, active, onSelect }) {
1532
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1533
+ "button",
1534
+ {
1535
+ type: "button",
1536
+ role: "tab",
1537
+ className: "ss-w-ecard-scope",
1538
+ "aria-selected": i === active,
1539
+ "aria-label": s.label,
1540
+ title: s.label,
1541
+ onClick: () => onSelect(i),
1542
+ children: s.image ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Crest, { image: s.image }) : s.label
1543
+ },
1544
+ String(s.competitionId ?? "all")
1545
+ )) });
1465
1546
  }
1466
- function toComboCardVM(card) {
1467
- const rawLegs = Array.isArray(card?.legs) ? card.legs : [];
1468
- const multiplication = str(card?.multiplication);
1469
- if (rawLegs.length < 2 || !multiplication) return null;
1470
- const legs = [];
1471
- for (const raw of rawLegs) {
1472
- const vm = toComboLegVM(raw);
1473
- if (!vm) return null;
1474
- legs.push(vm);
1547
+ function EntityCardItem({ c }) {
1548
+ const [active, setActive] = (0, import_react3.useState)(0);
1549
+ const hasBody = c.scopes.length > 0;
1550
+ if (!hasBody) {
1551
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardHeader, { c, showScopeCrest: false }) });
1475
1552
  }
1476
- return {
1477
- id: str(card.comboId) ?? legs.map((l) => l.matchOddsId).join("-"),
1478
- legs,
1479
- multiplication,
1480
- replacedNote: str(card.replacedNote),
1481
- addToSlipEnabled: card.addToSlipEnabled === true
1482
- };
1553
+ const multi = c.scopes.length > 1;
1554
+ const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
1555
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
1556
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardHeader, { c, showScopeCrest: !multi }),
1557
+ multi ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
1558
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatStrip, { stats: scope.stats })
1559
+ ] });
1483
1560
  }
1484
- function comboLegToSlipSelection(leg, conversationId) {
1485
- const selection = {
1486
- matchOddsId: leg.matchOddsId,
1487
- matchId: leg.matchId,
1488
- oddsDecimal: leg.oddsDecimal,
1489
- insightId: leg.insightId
1490
- };
1491
- if (leg.quotedAtUtc !== void 0) selection.quotedAtUtc = leg.quotedAtUtc;
1492
- if (conversationId !== void 0) selection.conversationId = conversationId;
1493
- return selection;
1561
+ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1562
+ const [expanded, setExpanded] = (0, import_react3.useState)(false);
1563
+ if (cards.length === 0) return null;
1564
+ const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1565
+ const overflow = cards.length - MAX_VISIBLE;
1566
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-w-cards", children: [
1567
+ visible.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EntityCardItem, { c }, c.id)),
1568
+ overflow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
1569
+ ] });
1494
1570
  }
1495
1571
 
1572
+ // src/components/AddToSlipButton.tsx
1573
+ var import_react7 = require("react");
1574
+ var import_widget_sdk = require("@sensiblestats/widget-sdk");
1575
+
1496
1576
  // src/eventLogContext.ts
1497
1577
  var import_react4 = require("react");
1498
1578
  var EventLogContext = (0, import_react4.createContext)(null);
@@ -1994,6 +2074,13 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
1994
2074
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InsightCard, { it, ui, slip, monitor }, it.id)) });
1995
2075
  }
1996
2076
 
2077
+ // src/presetToolsContext.ts
2078
+ var import_react12 = require("react");
2079
+ var PresetToolsContext = (0, import_react12.createContext)(null);
2080
+ function usePresetTools() {
2081
+ return (0, import_react12.useContext)(PresetToolsContext);
2082
+ }
2083
+
1997
2084
  // src/components/ComboCardList.tsx
1998
2085
  var import_jsx_runtime14 = require("react/jsx-runtime");
1999
2086
  function ComboLegRow({ leg, addToSlipEnabled, ui, slip }) {
@@ -2036,10 +2123,13 @@ function ComboLegRow({ leg, addToSlipEnabled, ui, slip }) {
2036
2123
  ] });
2037
2124
  }
2038
2125
  function ComboCardView({ vm, ui, slip }) {
2126
+ const tools = usePresetTools();
2127
+ const { target, legCount } = vm;
2039
2128
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-combo", children: [
2040
2129
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ol", { className: "ss-w-combo-legs", role: "list", children: vm.legs.map((leg) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ComboLegRow, { leg, addToSlipEnabled: vm.addToSlipEnabled, ui, slip }, leg.key)) }),
2041
2130
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-combo-math", children: vm.multiplication }),
2042
- vm.replacedNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "ss-w-combo-note", children: vm.replacedNote }) : null
2131
+ vm.replacedNote ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "ss-w-combo-note", children: vm.replacedNote }) : null,
2132
+ tools && target !== void 0 && legCount !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "ss-w-combo-change", onClick: () => tools.openBuilder(target, legCount), children: tools.changeLabel }) : null
2043
2133
  ] });
2044
2134
  }
2045
2135
  function ComboCardList({ cards, ui, slip }) {
@@ -2048,10 +2138,10 @@ function ComboCardList({ cards, ui, slip }) {
2048
2138
  }
2049
2139
 
2050
2140
  // src/components/MarketOddsCardList.tsx
2051
- var import_react12 = require("react");
2141
+ var import_react13 = require("react");
2052
2142
  var import_jsx_runtime15 = require("react/jsx-runtime");
2053
- function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
2054
- const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
2143
+ function OddsRow({ vm, row, ui, slip, inSlipIds, history, suppressSlip }) {
2144
+ const selection = vm.addToSlipEnabled && !suppressSlip ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
2055
2145
  const inSlip = !!inSlipIds && row.matchOddsId != null && !!inSlipIds[row.matchOddsId];
2056
2146
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-mo-row", children: [
2057
2147
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-mo-sel", children: row.selection }),
@@ -2069,17 +2159,34 @@ function OddsRow({ vm, row, ui, slip, inSlipIds, history }) {
2069
2159
  "\u2713 ",
2070
2160
  ui.inSlipLabel
2071
2161
  ] }) : null,
2072
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui })
2162
+ !suppressSlip ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SlipButton, { selection, shownOdds: row.odds, marketDeveloperName: vm.marketDeveloperName, selectionLabel: row.selectionLabel, line: row.line, slip, ui }) : null
2073
2163
  ] });
2074
2164
  }
2165
+ var STALE_AFTER_MS = 12e4;
2166
+ function fmtHhMm(iso, locale) {
2167
+ return new Date(iso).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit", hour12: false });
2168
+ }
2075
2169
  function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
2076
- const [open, setOpen] = (0, import_react12.useState)(false);
2170
+ const [open, setOpen] = (0, import_react13.useState)(false);
2077
2171
  const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
2078
2172
  const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
2079
2173
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
2080
- const showPin = !!monitor && vm.pinEnabled;
2174
+ const live = vm.live ?? null;
2175
+ const closedReason = live?.closedReason ?? null;
2176
+ const isClosed = closedReason !== null;
2177
+ const asOfMs = live ? new Date(live.asOfUtc).getTime() : NaN;
2178
+ const isStale = live != null && !isClosed && (vm.awaitingLiveUpdate === true || Date.now() - asOfMs > STALE_AFTER_MS);
2179
+ const staleTime = isStale && live ? fmtHhMm(live.asOfUtc, ui?.locale ?? "en") : null;
2180
+ const [, setStaleTick] = (0, import_react13.useState)(0);
2181
+ const watchStale = live != null && !isClosed && !isStale;
2182
+ (0, import_react13.useEffect)(() => {
2183
+ if (!watchStale) return;
2184
+ const id = window.setTimeout(() => setStaleTick((n) => n + 1), Math.max(0, asOfMs + STALE_AFTER_MS - Date.now()) + 1);
2185
+ return () => window.clearTimeout(id);
2186
+ }, [watchStale, asOfMs]);
2187
+ const showPin = !!monitor && vm.pinEnabled && !live;
2081
2188
  const history = showPin && !pinRef && !hideHeader ? monitor : void 0;
2082
- const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
2189
+ const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin || !!live;
2083
2190
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: hideHeader ? "ss-w-mocard ss-w-mocard--bare" : "ss-w-mocard", children: [
2084
2191
  !hideHeader && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2085
2192
  showHeader ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-bi-header", children: [
@@ -2088,7 +2195,14 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
2088
2195
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-bi-comp", children: vm.competition })
2089
2196
  ] }) : null }),
2090
2197
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-bi-header-right", children: [
2091
- vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-bi-live", children: [
2198
+ live && !isClosed ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-bi-score", children: [
2200
+ live.homeScore,
2201
+ "\u2013",
2202
+ live.awayScore
2203
+ ] }),
2204
+ live.minuteLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-bi-min", children: live.minuteLabel }) : null
2205
+ ] }) : !live && vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "ss-w-bi-live", children: [
2092
2206
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
2093
2207
  ui?.liveLabel ?? "Live"
2094
2208
  ] }) : null,
@@ -2118,14 +2232,17 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
2118
2232
  ] }) : null
2119
2233
  ] }),
2120
2234
  vm.statText && !hideHeader && !pinRef ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "ss-w-mo-stat", children: vm.statText }) : null,
2121
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-mo-rows", children: [
2122
- vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds, history }, row.key)),
2123
- open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds, history }, row.key)) : null
2235
+ isClosed ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "ss-w-mo-closed", children: closedReason === "suspended" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: ui?.liveCard.suspended ?? "Market suspended" }) : closedReason === "no_live_price" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: ui?.liveCard.noPrice ?? "No live price available" }) : closedReason === "full_time" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: ui?.liveCard.fullTime ?? "Full time" }) : null }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2236
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-mo-rows", children: [
2237
+ vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)),
2238
+ open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds, history, suppressSlip: isStale }, row.key)) : null
2239
+ ] }),
2240
+ vm.moreRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
2241
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
2242
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
2243
+ ] }) : null,
2244
+ staleTime ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "ss-w-mo-stale", children: ui?.liveCard.stale(staleTime) ?? `Prices from ${staleTime}` }) : null
2124
2245
  ] }),
2125
- vm.moreRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", className: "ss-w-mo-more", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
2126
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
2127
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: `ss-w-mo-more-chev${open ? " ss-w-mo-more-chev-up" : ""}`, "aria-hidden": "true" })
2128
- ] }) : null,
2129
2246
  vm.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: vm.bookmaker }) }) : null,
2130
2247
  vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
2131
2248
  ] });
@@ -2136,7 +2253,7 @@ function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader, p
2136
2253
  }
2137
2254
 
2138
2255
  // src/components/CompactOddsList.tsx
2139
- var import_react13 = require("react");
2256
+ var import_react14 = require("react");
2140
2257
 
2141
2258
  // src/compactList.ts
2142
2259
  var COMPACT_MIN_CARDS = 3;
@@ -2249,11 +2366,11 @@ function Row({ row, columns, ui, slip, monitor, rowRef }) {
2249
2366
  ] });
2250
2367
  }
2251
2368
  function CompactOddsList({ list, ui, slip, monitor }) {
2252
- const [shown, setShown] = (0, import_react13.useState)(COMPACT_PAGE);
2369
+ const [shown, setShown] = (0, import_react14.useState)(COMPACT_PAGE);
2253
2370
  const hidden = list.rowCount - shown;
2254
- const [focusIndex, setFocusIndex] = (0, import_react13.useState)(null);
2255
- const focusRef = (0, import_react13.useRef)(null);
2256
- (0, import_react13.useEffect)(() => {
2371
+ const [focusIndex, setFocusIndex] = (0, import_react14.useState)(null);
2372
+ const focusRef = (0, import_react14.useRef)(null);
2373
+ (0, import_react14.useEffect)(() => {
2257
2374
  if (focusIndex !== null) focusRef.current?.focus();
2258
2375
  }, [focusIndex]);
2259
2376
  let left = shown;
@@ -2554,7 +2671,7 @@ function FixtureCard({ card }) {
2554
2671
  }
2555
2672
 
2556
2673
  // src/components/dashboard/CountdownCard.tsx
2557
- var import_react14 = require("react");
2674
+ var import_react15 = require("react");
2558
2675
  var import_jsx_runtime22 = require("react/jsx-runtime");
2559
2676
  var DAY_MS = 864e5;
2560
2677
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -2573,12 +2690,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
2573
2690
  function CountdownCard({ card }) {
2574
2691
  const { data } = card;
2575
2692
  const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
2576
- const [nowMs, setNowMs] = (0, import_react14.useState)(() => Date.now());
2577
- const [reduced] = (0, import_react14.useState)(
2693
+ const [nowMs, setNowMs] = (0, import_react15.useState)(() => Date.now());
2694
+ const [reduced] = (0, import_react15.useState)(
2578
2695
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
2579
2696
  );
2580
2697
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
2581
- (0, import_react14.useEffect)(() => {
2698
+ (0, import_react15.useEffect)(() => {
2582
2699
  if (reduced) return;
2583
2700
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
2584
2701
  return () => window.clearInterval(id);
@@ -2586,7 +2703,7 @@ function CountdownCard({ card }) {
2586
2703
  const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
2587
2704
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-fandash-countdown-top", children: [
2588
2705
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
2589
- segments ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react14.Fragment, { children: [
2706
+ segments ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react15.Fragment, { children: [
2590
2707
  i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
2591
2708
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
2592
2709
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
@@ -2597,7 +2714,7 @@ function CountdownCard({ card }) {
2597
2714
  }
2598
2715
 
2599
2716
  // src/components/dashboard/InjuriesCard.tsx
2600
- var import_react15 = require("react");
2717
+ var import_react16 = require("react");
2601
2718
  var import_jsx_runtime23 = require("react/jsx-runtime");
2602
2719
  var SHOWN = 3;
2603
2720
  function ColHead({ name, crestUrl }) {
@@ -2620,7 +2737,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
2620
2737
  }
2621
2738
  function InjuriesCard({ card, ui }) {
2622
2739
  const { data } = card;
2623
- const [expanded, setExpanded] = (0, import_react15.useState)(false);
2740
+ const [expanded, setExpanded] = (0, import_react16.useState)(false);
2624
2741
  const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
2625
2742
  const limit = expanded ? void 0 : SHOWN;
2626
2743
  const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
@@ -2726,7 +2843,7 @@ function LinksCard({ card }) {
2726
2843
  }
2727
2844
 
2728
2845
  // src/components/dashboard/PostMatchResultCard.tsx
2729
- var import_react16 = require("react");
2846
+ var import_react17 = require("react");
2730
2847
  var import_jsx_runtime29 = require("react/jsx-runtime");
2731
2848
  function initials3(name) {
2732
2849
  return name.trim().slice(0, 3).toUpperCase();
@@ -2736,7 +2853,7 @@ function PostMatchCrest({
2736
2853
  name,
2737
2854
  side
2738
2855
  }) {
2739
- const [failed, setFailed] = (0, import_react16.useState)(false);
2856
+ const [failed, setFailed] = (0, import_react17.useState)(false);
2740
2857
  const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
2741
2858
  if (url && !failed) {
2742
2859
  return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2935,10 +3052,10 @@ function RestingFormCard({ card }) {
2935
3052
  }
2936
3053
 
2937
3054
  // src/components/dashboard/LiveScoreCard.tsx
2938
- var import_react18 = require("react");
3055
+ var import_react19 = require("react");
2939
3056
 
2940
3057
  // src/useLiveClock.ts
2941
- var import_react17 = require("react");
3058
+ var import_react18 = require("react");
2942
3059
  var TICK_MS = 6e4;
2943
3060
  var MAX_LIVE_TICK_MINUTES = 15;
2944
3061
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -2947,10 +3064,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
2947
3064
  return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
2948
3065
  }
2949
3066
  function useLiveClock(minute, clockRunning, receivedAtMs) {
2950
- const [displayMinute, setDisplayMinute] = (0, import_react17.useState)(
3067
+ const [displayMinute, setDisplayMinute] = (0, import_react18.useState)(
2951
3068
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
2952
3069
  );
2953
- (0, import_react17.useEffect)(() => {
3070
+ (0, import_react18.useEffect)(() => {
2954
3071
  setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
2955
3072
  if (!clockRunning) return;
2956
3073
  const id = window.setInterval(() => {
@@ -2967,7 +3084,7 @@ function initials5(name) {
2967
3084
  return name.trim().slice(0, 3).toUpperCase();
2968
3085
  }
2969
3086
  function LiveCrest({ url, name, side }) {
2970
- const [failed, setFailed] = (0, import_react18.useState)(false);
3087
+ const [failed, setFailed] = (0, import_react19.useState)(false);
2971
3088
  const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
2972
3089
  if (url && !failed) {
2973
3090
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2986,7 +3103,7 @@ function LiveScoreCard({
2986
3103
  }) {
2987
3104
  const { data } = card;
2988
3105
  const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
2989
- const seedRef = (0, import_react18.useRef)(null);
3106
+ const seedRef = (0, import_react19.useRef)(null);
2990
3107
  if (!seedRef.current || seedRef.current.key !== seedKey) {
2991
3108
  seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
2992
3109
  }
@@ -3026,7 +3143,7 @@ function LiveScoreCard({
3026
3143
  }
3027
3144
 
3028
3145
  // src/components/dashboard/LiveTimelineCard.tsx
3029
- var import_react19 = require("react");
3146
+ var import_react20 = require("react");
3030
3147
  var import_jsx_runtime39 = require("react/jsx-runtime");
3031
3148
  var SHOWN2 = 3;
3032
3149
  function EventIcon({ type }) {
@@ -3068,7 +3185,7 @@ function EventRow({ e }) {
3068
3185
  ] });
3069
3186
  }
3070
3187
  function LiveTimelineCard({ card, ui }) {
3071
- const [expanded, setExpanded] = (0, import_react19.useState)(false);
3188
+ const [expanded, setExpanded] = (0, import_react20.useState)(false);
3072
3189
  const events = card.data.events;
3073
3190
  if (!events || events.length === 0) return null;
3074
3191
  const sorted = [...events].sort((a, b) => b.minute - a.minute);
@@ -3093,7 +3210,7 @@ function LiveTimelineCard({ card, ui }) {
3093
3210
  }
3094
3211
 
3095
3212
  // src/components/dashboard/MomentumWave.tsx
3096
- var import_react20 = require("react");
3213
+ var import_react21 = require("react");
3097
3214
  var import_jsx_runtime40 = require("react/jsx-runtime");
3098
3215
  var WIDTH = 270;
3099
3216
  var HEIGHT = 56;
@@ -3117,7 +3234,7 @@ function MomentumWave({
3117
3234
  }) {
3118
3235
  if (points.length === 0) return null;
3119
3236
  const { area, line, lastLeftPct, lastTopPx } = buildPaths(points);
3120
- const clipId = (0, import_react20.useId)();
3237
+ const clipId = (0, import_react21.useId)();
3121
3238
  const topClipId = `${clipId}-top`;
3122
3239
  const bottomClipId = `${clipId}-bottom`;
3123
3240
  const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
@@ -3310,11 +3427,11 @@ function turnAnchor(messages) {
3310
3427
  }
3311
3428
  function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
3312
3429
  const { state, send } = controller;
3313
- const listRef = (0, import_react21.useRef)(null);
3314
- const endRef = (0, import_react21.useRef)(null);
3315
- const pinnedRef = (0, import_react21.useRef)(true);
3316
- const anchoredTurnRef = (0, import_react21.useRef)(null);
3317
- (0, import_react21.useEffect)(() => {
3430
+ const listRef = (0, import_react22.useRef)(null);
3431
+ const endRef = (0, import_react22.useRef)(null);
3432
+ const pinnedRef = (0, import_react22.useRef)(true);
3433
+ const anchoredTurnRef = (0, import_react22.useRef)(null);
3434
+ (0, import_react22.useEffect)(() => {
3318
3435
  const anchor = turnAnchor(state.messages);
3319
3436
  const list = listRef.current;
3320
3437
  if (anchor && anchor.turnId !== anchoredTurnRef.current) {
@@ -3371,11 +3488,15 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
3371
3488
  }
3372
3489
 
3373
3490
  // src/components/ChatInput.tsx
3374
- var import_react22 = require("react");
3491
+ var import_react23 = require("react");
3375
3492
  var import_jsx_runtime46 = require("react/jsx-runtime");
3376
- function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
3377
- const [value, setValue] = (0, import_react22.useState)("");
3493
+ var ChatInput = (0, import_react23.forwardRef)(function ChatInput2({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message", disabled = false, onType }, ref) {
3494
+ const [value, setValue] = (0, import_react23.useState)("");
3495
+ const textareaRef = (0, import_react23.useRef)(null);
3496
+ const stopRef = (0, import_react23.useRef)(null);
3497
+ const textBoxWantsFocusRef = (0, import_react23.useRef)(false);
3378
3498
  const submit = () => {
3499
+ if (disabled) return;
3379
3500
  const t = value.trim();
3380
3501
  if (!t) return;
3381
3502
  onSend(t);
@@ -3387,11 +3508,48 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
3387
3508
  submit();
3388
3509
  }
3389
3510
  };
3511
+ (0, import_react23.useImperativeHandle)(ref, () => ({
3512
+ focus() {
3513
+ const box = textareaRef.current;
3514
+ if (box && !box.disabled) {
3515
+ textBoxWantsFocusRef.current = false;
3516
+ box.focus();
3517
+ return;
3518
+ }
3519
+ textBoxWantsFocusRef.current = true;
3520
+ stopRef.current?.focus();
3521
+ }
3522
+ }), []);
3523
+ (0, import_react23.useEffect)(() => {
3524
+ if (streaming || disabled || !textBoxWantsFocusRef.current) return;
3525
+ textBoxWantsFocusRef.current = false;
3526
+ const box = textareaRef.current;
3527
+ if (!box) return;
3528
+ const active = box.getRootNode().activeElement;
3529
+ const input = box.closest(".ss-w-input");
3530
+ const isWithinComponent = input?.contains(active);
3531
+ if (!active || active === box.ownerDocument.body || isWithinComponent) box.focus();
3532
+ }, [streaming, disabled]);
3390
3533
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-input", children: [
3391
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
3392
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SendIcon, {}) })
3534
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3535
+ "textarea",
3536
+ {
3537
+ ref: textareaRef,
3538
+ className: "ss-w-textarea",
3539
+ rows: 1,
3540
+ placeholder,
3541
+ value,
3542
+ disabled: streaming || disabled,
3543
+ onChange: (e) => {
3544
+ setValue(e.target.value);
3545
+ onType?.();
3546
+ },
3547
+ onKeyDown
3548
+ }
3549
+ ),
3550
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { ref: stopRef, type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, disabled, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, disabled, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SendIcon, {}) })
3393
3551
  ] });
3394
- }
3552
+ });
3395
3553
 
3396
3554
  // src/components/TabBar.tsx
3397
3555
  var import_jsx_runtime47 = require("react/jsx-runtime");
@@ -3484,10 +3642,10 @@ function MarketAccordion({ match, monitor, ui, slip }) {
3484
3642
  }
3485
3643
 
3486
3644
  // src/components/LiveFactBlock.tsx
3487
- var import_react23 = require("react");
3645
+ var import_react24 = require("react");
3488
3646
  var import_jsx_runtime49 = require("react/jsx-runtime");
3489
3647
  function LiveFactBlock({ facts, matchId, ui, slip, onAsk }) {
3490
- const [expanded, setExpanded] = (0, import_react23.useState)(false);
3648
+ const [expanded, setExpanded] = (0, import_react24.useState)(false);
3491
3649
  const [current, ...earlier] = facts;
3492
3650
  if (!current) return null;
3493
3651
  const m = current.market;
@@ -3874,7 +4032,7 @@ function TodayPanel({ discovery, ui, monitor }) {
3874
4032
  }
3875
4033
 
3876
4034
  // src/components/GamesPanel.tsx
3877
- var import_react37 = require("react");
4035
+ var import_react38 = require("react");
3878
4036
 
3879
4037
  // src/components/GamesLoginWall.tsx
3880
4038
  var import_jsx_runtime55 = require("react/jsx-runtime");
@@ -3883,7 +4041,7 @@ function GamesLoginWall({ ui }) {
3883
4041
  }
3884
4042
 
3885
4043
  // src/components/GamesHub.tsx
3886
- var import_react24 = require("react");
4044
+ var import_react25 = require("react");
3887
4045
 
3888
4046
  // src/components/games/ui/gameMeta.ts
3889
4047
  function prettifyGameId(gameId) {
@@ -4068,8 +4226,8 @@ function pickHeroGame(games) {
4068
4226
  }
4069
4227
  var tileKey = (g) => `${g.gameId}-${g.gameDay}-${g.fixtureId}`;
4070
4228
  function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
4071
- const [, setTick] = (0, import_react24.useState)(0);
4072
- (0, import_react24.useEffect)(() => {
4229
+ const [, setTick] = (0, import_react25.useState)(0);
4230
+ (0, import_react25.useEffect)(() => {
4073
4231
  const id = setInterval(() => setTick((t) => t + 1), 6e4);
4074
4232
  return () => clearInterval(id);
4075
4233
  }, []);
@@ -4129,10 +4287,10 @@ function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
4129
4287
  }
4130
4288
 
4131
4289
  // src/components/GameScreenHost.tsx
4132
- var import_react36 = require("react");
4290
+ var import_react37 = require("react");
4133
4291
 
4134
4292
  // src/useGamePlay.ts
4135
- var import_react25 = require("react");
4293
+ var import_react26 = require("react");
4136
4294
  function toSubmitResult(payload) {
4137
4295
  return {
4138
4296
  // 'pending' means the play is recorded but awaiting resolution (fixture games)
@@ -4144,17 +4302,17 @@ function toSubmitResult(payload) {
4144
4302
  };
4145
4303
  }
4146
4304
  function useGamePlay(conversation, { gameId, gameDay, fixtureId, locale, refresh }) {
4147
- const [result, setResult] = (0, import_react25.useState)(null);
4148
- const [submitting, setSubmitting] = (0, import_react25.useState)(false);
4149
- const [rawStatus, setRawStatus] = (0, import_react25.useState)(null);
4150
- const inFlightRef = (0, import_react25.useRef)(false);
4151
- const convRef = (0, import_react25.useRef)(conversation);
4305
+ const [result, setResult] = (0, import_react26.useState)(null);
4306
+ const [submitting, setSubmitting] = (0, import_react26.useState)(false);
4307
+ const [rawStatus, setRawStatus] = (0, import_react26.useState)(null);
4308
+ const inFlightRef = (0, import_react26.useRef)(false);
4309
+ const convRef = (0, import_react26.useRef)(conversation);
4152
4310
  convRef.current = conversation;
4153
- const optsRef = (0, import_react25.useRef)({ gameId, gameDay, fixtureId, locale, refresh });
4311
+ const optsRef = (0, import_react26.useRef)({ gameId, gameDay, fixtureId, locale, refresh });
4154
4312
  optsRef.current = { gameId, gameDay, fixtureId, locale, refresh };
4155
- const resultRef = (0, import_react25.useRef)(null);
4313
+ const resultRef = (0, import_react26.useRef)(null);
4156
4314
  resultRef.current = result;
4157
- const refetch = (0, import_react25.useCallback)(async () => {
4315
+ const refetch = (0, import_react26.useCallback)(async () => {
4158
4316
  const conv = convRef.current;
4159
4317
  if (!conv) return;
4160
4318
  const opts = optsRef.current;
@@ -4170,7 +4328,7 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, locale, refresh
4170
4328
  } catch {
4171
4329
  }
4172
4330
  }, []);
4173
- const submit = (0, import_react25.useCallback)(async (answerJson) => {
4331
+ const submit = (0, import_react26.useCallback)(async (answerJson) => {
4174
4332
  const conv = convRef.current;
4175
4333
  if (!conv || inFlightRef.current) return;
4176
4334
  inFlightRef.current = true;
@@ -4197,14 +4355,14 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, locale, refresh
4197
4355
  setSubmitting(false);
4198
4356
  }
4199
4357
  }, [refetch]);
4200
- const hydrate = (0, import_react25.useCallback)(() => {
4358
+ const hydrate = (0, import_react26.useCallback)(() => {
4201
4359
  void refetch();
4202
4360
  }, [refetch]);
4203
4361
  return { result, submitting, submit, hydrate, rawStatus };
4204
4362
  }
4205
4363
 
4206
4364
  // src/components/games/MysteryTigerGame.tsx
4207
- var import_react27 = require("react");
4365
+ var import_react28 = require("react");
4208
4366
 
4209
4367
  // src/components/games/nationFlags.ts
4210
4368
  var FLAGS = {
@@ -4415,7 +4573,7 @@ function isNationCode(flag) {
4415
4573
  }
4416
4574
 
4417
4575
  // src/components/games/PlayerAvatar.tsx
4418
- var import_react26 = require("react");
4576
+ var import_react27 = require("react");
4419
4577
  var import_jsx_runtime61 = require("react/jsx-runtime");
4420
4578
  function initialsOf(name) {
4421
4579
  const parts = name.trim().split(/\s+/).filter(Boolean);
@@ -4433,7 +4591,7 @@ function PlayerAvatar({
4433
4591
  imagePath,
4434
4592
  className
4435
4593
  }) {
4436
- const [failed, setFailed] = (0, import_react26.useState)(false);
4594
+ const [failed, setFailed] = (0, import_react27.useState)(false);
4437
4595
  const showImage = Boolean(imagePath) && !isPlaceholderImage(imagePath) && !failed;
4438
4596
  return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className, "aria-hidden": "true", children: showImage ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("img", { src: imagePath, alt: "", loading: "lazy", onError: () => setFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-av-initials", children: initialsOf(name) }) });
4439
4597
  }
@@ -4648,8 +4806,8 @@ function MysteryTigerGame({
4648
4806
  onBack
4649
4807
  }) {
4650
4808
  const t = ui.games.mysteryTiger;
4651
- const [query, setQuery] = (0, import_react27.useState)("");
4652
- const inputId = (0, import_react27.useId)();
4809
+ const [query, setQuery] = (0, import_react28.useState)("");
4810
+ const inputId = (0, import_react28.useId)();
4653
4811
  const clientState = parseClientState(result?.clientStateJson);
4654
4812
  const guessResults = clientState?.guessResults ?? [];
4655
4813
  const alreadyGuessedIds = new Set(guessResults.map((g) => g.playerId));
@@ -4924,13 +5082,13 @@ function HigherOrLowerGame({
4924
5082
  }
4925
5083
 
4926
5084
  // src/components/games/CareerPathGame.tsx
4927
- var import_react29 = require("react");
5085
+ var import_react30 = require("react");
4928
5086
 
4929
5087
  // src/components/games/ui/CrestShield.tsx
4930
- var import_react28 = require("react");
5088
+ var import_react29 = require("react");
4931
5089
  var import_jsx_runtime72 = require("react/jsx-runtime");
4932
5090
  function CrestShield({ src, name, size = 28 }) {
4933
- const [failed, setFailed] = (0, import_react28.useState)(false);
5091
+ const [failed, setFailed] = (0, import_react29.useState)(false);
4934
5092
  if (src && !isPlaceholderImage(src) && !failed) {
4935
5093
  return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("img", { className: "ss-g-crest", src, alt: name, width: size, height: size, loading: "lazy", onError: () => setFailed(true) });
4936
5094
  }
@@ -4962,8 +5120,8 @@ function CareerPathGame({
4962
5120
  }) {
4963
5121
  const s = ui.games.careerPath;
4964
5122
  const title = gameTitle({ gameId: "career-path" }, ui.games.titles);
4965
- const [query, setQuery] = (0, import_react29.useState)("");
4966
- const inputId = (0, import_react29.useId)();
5123
+ const [query, setQuery] = (0, import_react30.useState)("");
5124
+ const inputId = (0, import_react30.useId)();
4967
5125
  const clientState = parseClientState3(result?.clientStateJson);
4968
5126
  const alreadyGuessedIds = new Set(clientState?.guessResults.map((g) => g.playerId) ?? []);
4969
5127
  const isOver = result?.alreadyPlayed === true || clientState?.solved === true || clientState?.failed === true;
@@ -5082,7 +5240,7 @@ function CareerPathGame({
5082
5240
  }
5083
5241
 
5084
5242
  // src/components/games/BeatTheGridGame.tsx
5085
- var import_react30 = __toESM(require("react"), 1);
5243
+ var import_react31 = __toESM(require("react"), 1);
5086
5244
  var import_jsx_runtime74 = require("react/jsx-runtime");
5087
5245
  function criterionIconKind(label, key) {
5088
5246
  const l = (key ?? label).toLowerCase();
@@ -5163,10 +5321,10 @@ function SearchSheet({
5163
5321
  ui
5164
5322
  }) {
5165
5323
  const s = ui.games.beatTheGrid;
5166
- const [query, setQuery] = (0, import_react30.useState)("");
5167
- const inputId = (0, import_react30.useId)();
5168
- const inputRef = (0, import_react30.useRef)(null);
5169
- (0, import_react30.useEffect)(() => {
5324
+ const [query, setQuery] = (0, import_react31.useState)("");
5325
+ const inputId = (0, import_react31.useId)();
5326
+ const inputRef = (0, import_react31.useRef)(null);
5327
+ (0, import_react31.useEffect)(() => {
5170
5328
  inputRef.current?.focus();
5171
5329
  }, [row, col]);
5172
5330
  const filtered = playerPool.filter(
@@ -5231,7 +5389,7 @@ function BeatTheGridGame({
5231
5389
  }) {
5232
5390
  const s = ui.games.beatTheGrid;
5233
5391
  const title = gameTitle({ gameId: "beat-the-grid" }, ui.games.titles);
5234
- const [activeCell, setActiveCell] = (0, import_react30.useState)(null);
5392
+ const [activeCell, setActiveCell] = (0, import_react31.useState)(null);
5235
5393
  const clientState = parseClientState4(result?.clientStateJson);
5236
5394
  const filledCells = clientState?.cells ?? [];
5237
5395
  const isLocked2 = result?.alreadyPlayed === true || clientState?.isComplete === true;
@@ -5305,7 +5463,7 @@ function BeatTheGridGame({
5305
5463
  /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { "aria-hidden": "true", children: abbr }),
5306
5464
  /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "ss-g-sr", children: rowLabel })
5307
5465
  ] });
5308
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(import_react30.default.Fragment, { children: [
5466
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(import_react31.default.Fragment, { children: [
5309
5467
  /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "ss-g-btg-rowhdr", "data-meta": rowMeta ? "true" : void 0, children: rowHeaderContent }),
5310
5468
  cols.map((colLabel, colIdx) => {
5311
5469
  const filled = findCellResult(filledCells, rowIdx, colIdx);
@@ -5386,7 +5544,7 @@ function BeatTheGridGame({
5386
5544
  }
5387
5545
 
5388
5546
  // src/components/games/GuessTheXiGame.tsx
5389
- var import_react31 = require("react");
5547
+ var import_react32 = require("react");
5390
5548
 
5391
5549
  // src/components/games/ui/PitchSvg.tsx
5392
5550
  var import_jsx_runtime75 = require("react/jsx-runtime");
@@ -5475,8 +5633,8 @@ function GuessTheXiGame({
5475
5633
  onBack
5476
5634
  }) {
5477
5635
  const t = ui.games.guessTheXi;
5478
- const [query, setQuery] = (0, import_react31.useState)("");
5479
- const inputId = (0, import_react31.useId)();
5636
+ const [query, setQuery] = (0, import_react32.useState)("");
5637
+ const inputId = (0, import_react32.useId)();
5480
5638
  const clientState = parseClientState5(result?.clientStateJson);
5481
5639
  const isOver = result?.alreadyPlayed === true || clientState?.status === "solved" || clientState?.status === "failed";
5482
5640
  const solved = clientState?.status === "solved";
@@ -5617,7 +5775,7 @@ function GuessTheXiGame({
5617
5775
  }
5618
5776
 
5619
5777
  // src/components/games/DailyQuizGame.tsx
5620
- var import_react32 = require("react");
5778
+ var import_react33 = require("react");
5621
5779
  var import_jsx_runtime77 = require("react/jsx-runtime");
5622
5780
  function parseClientState6(json) {
5623
5781
  if (!json) return null;
@@ -5658,8 +5816,8 @@ function DailyQuizGame({
5658
5816
  }) {
5659
5817
  const s = ui.games.dailyQuiz;
5660
5818
  const title = gameTitle({ gameId: "daily-quiz" }, ui.games.titles);
5661
- const [selections, setSelections] = (0, import_react32.useState)(/* @__PURE__ */ new Map());
5662
- const [page, setPage] = (0, import_react32.useState)(0);
5819
+ const [selections, setSelections] = (0, import_react33.useState)(/* @__PURE__ */ new Map());
5820
+ const [page, setPage] = (0, import_react33.useState)(0);
5663
5821
  const clientState = parseClientState6(result?.clientStateJson);
5664
5822
  const results = clientState?.results ?? [];
5665
5823
  const isRevealed = results.length > 0 || result?.alreadyPlayed === true;
@@ -5769,7 +5927,7 @@ function DailyQuizGame({
5769
5927
  }
5770
5928
 
5771
5929
  // src/components/games/MatchdayPredictorGame.tsx
5772
- var import_react33 = require("react");
5930
+ var import_react34 = require("react");
5773
5931
  var import_jsx_runtime78 = require("react/jsx-runtime");
5774
5932
  var SCORER_SEARCH_THRESHOLD = 9;
5775
5933
  function parseClientState7(json) {
@@ -5865,12 +6023,12 @@ function MatchdayPredictorGame({
5865
6023
  onBack
5866
6024
  }) {
5867
6025
  const t = ui.games.predictor;
5868
- const [homeScore, setHomeScore] = (0, import_react33.useState)(0);
5869
- const [awayScore, setAwayScore] = (0, import_react33.useState)(0);
5870
- const [firstScorerPlayerId, setFirstScorerPlayerId] = (0, import_react33.useState)(null);
5871
- const [lastEdited, setLastEdited] = (0, import_react33.useState)("home");
5872
- const [query, setQuery] = (0, import_react33.useState)("");
5873
- const searchId = (0, import_react33.useId)();
6026
+ const [homeScore, setHomeScore] = (0, import_react34.useState)(0);
6027
+ const [awayScore, setAwayScore] = (0, import_react34.useState)(0);
6028
+ const [firstScorerPlayerId, setFirstScorerPlayerId] = (0, import_react34.useState)(null);
6029
+ const [lastEdited, setLastEdited] = (0, import_react34.useState)("home");
6030
+ const [query, setQuery] = (0, import_react34.useState)("");
6031
+ const searchId = (0, import_react34.useId)();
5874
6032
  const clientState = parseClientState7(result?.clientStateJson);
5875
6033
  const alreadyPlayed = result?.alreadyPlayed === true;
5876
6034
  const header = /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
@@ -6037,7 +6195,7 @@ function MatchdayPredictorGame({
6037
6195
  }
6038
6196
 
6039
6197
  // src/components/games/StartingXiGame.tsx
6040
- var import_react34 = require("react");
6198
+ var import_react35 = require("react");
6041
6199
  var import_jsx_runtime79 = require("react/jsx-runtime");
6042
6200
  var POINTS_PER_STARTER = 8;
6043
6201
  var XI_SIZE = 11;
@@ -6081,10 +6239,10 @@ function StartingXiGame({
6081
6239
  lockAtUtc
6082
6240
  }) {
6083
6241
  const t = ui.games.startingXi;
6084
- const [slotPlayers, setSlotPlayers] = (0, import_react34.useState)(() => Array(XI_SIZE).fill(null));
6085
- const [active, setActive] = (0, import_react34.useState)(0);
6086
- const [query, setQuery] = (0, import_react34.useState)("");
6087
- const searchId = (0, import_react34.useId)();
6242
+ const [slotPlayers, setSlotPlayers] = (0, import_react35.useState)(() => Array(XI_SIZE).fill(null));
6243
+ const [active, setActive] = (0, import_react35.useState)(0);
6244
+ const [query, setQuery] = (0, import_react35.useState)("");
6245
+ const searchId = (0, import_react35.useId)();
6088
6246
  const clientState = parseClientState8(result?.clientStateJson);
6089
6247
  const alreadyPlayed = result?.alreadyPlayed === true;
6090
6248
  const header = /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
@@ -6223,7 +6381,7 @@ function StartingXiGame({
6223
6381
  }
6224
6382
 
6225
6383
  // src/components/games/StatLadderGame.tsx
6226
- var import_react35 = require("react");
6384
+ var import_react36 = require("react");
6227
6385
  var import_jsx_runtime80 = require("react/jsx-runtime");
6228
6386
  function ladderClue(ladder) {
6229
6387
  const mystery = ladder.find((r) => r.rank === 2);
@@ -6260,9 +6418,9 @@ function StatLadderGame({
6260
6418
  onBack
6261
6419
  }) {
6262
6420
  const t = ui.games.statLadder;
6263
- const [query, setQuery] = (0, import_react35.useState)("");
6264
- const [selectedId, setSelectedId] = (0, import_react35.useState)(null);
6265
- const searchId = (0, import_react35.useId)();
6421
+ const [query, setQuery] = (0, import_react36.useState)("");
6422
+ const [selectedId, setSelectedId] = (0, import_react36.useState)(null);
6423
+ const searchId = (0, import_react36.useId)();
6266
6424
  const clientState = parseClientState9(result?.clientStateJson);
6267
6425
  const revealed = clientState != null;
6268
6426
  const header = /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(GameHeader, { title: gameTitle({ gameId: "stat-ladder" }, ui.games.titles), eyebrow: t.eyebrow, onBack, backLabel: ui.back });
@@ -6467,8 +6625,8 @@ function GameScreenHost({
6467
6625
  ui
6468
6626
  }) {
6469
6627
  const { gameId, fixtureId, gameDay = "", lockAtUtc = null } = selected;
6470
- const [configJson, setConfigJson] = (0, import_react36.useState)(null);
6471
- (0, import_react36.useEffect)(() => {
6628
+ const [configJson, setConfigJson] = (0, import_react37.useState)(null);
6629
+ (0, import_react37.useEffect)(() => {
6472
6630
  setConfigJson(null);
6473
6631
  if (!conversation) return;
6474
6632
  let cancelled = false;
@@ -6491,12 +6649,12 @@ function GameScreenHost({
6491
6649
  fixtureId: fixtureId || void 0,
6492
6650
  locale: ui.games.lang
6493
6651
  });
6494
- (0, import_react36.useEffect)(() => {
6652
+ (0, import_react37.useEffect)(() => {
6495
6653
  if (conversation) hydrate();
6496
6654
  }, [conversation, gameId]);
6497
- const hydrateRef = (0, import_react36.useRef)(hydrate);
6655
+ const hydrateRef = (0, import_react37.useRef)(hydrate);
6498
6656
  hydrateRef.current = hydrate;
6499
- (0, import_react36.useEffect)(() => {
6657
+ (0, import_react37.useEffect)(() => {
6500
6658
  if (!FIXTURE_GAME_IDS.has(gameId)) return;
6501
6659
  if (rawStatus !== "pending") return;
6502
6660
  const timerId = setInterval(() => {
@@ -6631,8 +6789,8 @@ function GamesPanel({
6631
6789
  leaderboard,
6632
6790
  refreshHub
6633
6791
  }) {
6634
- const [selected, setSelected] = (0, import_react37.useState)(null);
6635
- (0, import_react37.useEffect)(() => {
6792
+ const [selected, setSelected] = (0, import_react38.useState)(null);
6793
+ (0, import_react38.useEffect)(() => {
6636
6794
  ensureGamesFonts();
6637
6795
  }, []);
6638
6796
  if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(GamesLoginWall, { ui });
@@ -6663,7 +6821,7 @@ function GamesPanel({
6663
6821
  }
6664
6822
 
6665
6823
  // src/components/Leaderboard.tsx
6666
- var import_react38 = require("react");
6824
+ var import_react39 = require("react");
6667
6825
 
6668
6826
  // src/components/LeaderboardRow.tsx
6669
6827
  var import_jsx_runtime84 = require("react/jsx-runtime");
@@ -6748,7 +6906,7 @@ function Leaderboard({
6748
6906
  ui,
6749
6907
  onPlay
6750
6908
  }) {
6751
- const [segment, setSegment] = (0, import_react38.useState)("weekly");
6909
+ const [segment, setSegment] = (0, import_react39.useState)("weekly");
6752
6910
  const myRow = segment === "weekly" ? data.myWeeklyRow : data.myAllTimeRow;
6753
6911
  const offBoard = myRow !== null && myRow !== void 0 && myRow.rank === -1;
6754
6912
  const isEmpty = segment === "weekly" ? data.weeklyTop.length === 0 : data.allTimeTop.length === 0;
@@ -6827,12 +6985,440 @@ function LeaderboardPanel({ loggedIn, data, loading, onPlay, ui }) {
6827
6985
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Leaderboard, { data: data ?? EMPTY_PAYLOAD, ui, onPlay }) });
6828
6986
  }
6829
6987
 
6830
- // src/components/ChatPanel.tsx
6988
+ // src/components/PresetSpeedDial.tsx
6989
+ var import_react40 = require("react");
6831
6990
  var import_jsx_runtime88 = require("react/jsx-runtime");
6991
+ function PresetSpeedDial({ expanded, showDot, strings, onToggle, onOpen, rootRef, buttonRef }) {
6992
+ const pillsId = (0, import_react40.useId)();
6993
+ const tabIndex = expanded ? 0 : -1;
6994
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { ref: rootRef, className: "ss-w-dial", children: [
6995
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
6996
+ "button",
6997
+ {
6998
+ ref: buttonRef,
6999
+ type: "button",
7000
+ className: "ss-w-dial-btn",
7001
+ "aria-expanded": expanded,
7002
+ "aria-controls": pillsId,
7003
+ "aria-label": strings.dialName,
7004
+ onClick: onToggle,
7005
+ children: [
7006
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "ss-w-dial-icon ss-w-dial-icon--open", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SlidersIcon, {}) }),
7007
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "ss-w-dial-icon ss-w-dial-icon--close", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(CloseIcon, {}) }),
7008
+ showDot && !expanded ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "ss-w-dial-dot", "aria-hidden": "true" }) : null
7009
+ ]
7010
+ }
7011
+ ),
7012
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { id: pillsId, className: "ss-w-dial-pills", "data-open": expanded ? "" : void 0, children: [
7013
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "ss-w-dial-pill", tabIndex, onClick: () => onOpen("numbers"), children: [
7014
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SlidersIcon, {}),
7015
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "ss-w-dial-pill-label", children: strings.setNumbers })
7016
+ ] }),
7017
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "ss-w-dial-pill", tabIndex, onClick: () => onOpen("combo"), children: [
7018
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(ComboIcon, {}),
7019
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "ss-w-dial-pill-label", children: strings.buildCombo })
7020
+ ] })
7021
+ ] })
7022
+ ] });
7023
+ }
7024
+
7025
+ // src/components/PresetTools.tsx
7026
+ var import_react41 = require("react");
7027
+
7028
+ // src/presetGrid.ts
7029
+ var DEFAULT_SINGLES_LIMITS = [1.3, 1.5, 1.7, 2];
7030
+ var DEFAULT_SINGLES_FLOORS = [1.5, 2, 2.5, 3];
7031
+ var DEFAULT_COMBO_TOTALS = [3, 5, 10, 20, 50];
7032
+ var FIXED_SINGLES_COUNT = 3;
7033
+ var MIN_COMBO_LEGS = 2;
7034
+ var MAX_COMBO_LEGS = 6;
7035
+ var START = { maxPrice: 1.5, minPrice: 2, comboTotal: 5, comboLegs: 3 };
7036
+ var finite2 = (v) => typeof v === "number" && Number.isFinite(v);
7037
+ var cents = (n) => Math.round(n * 100);
7038
+ function samePrice(a, b) {
7039
+ return cents(a) === cents(b);
7040
+ }
7041
+ function isPresetGrid(v) {
7042
+ if (!v || typeof v !== "object") return false;
7043
+ const g = v;
7044
+ return Array.isArray(g.singles) && Array.isArray(g.singlesFrom) && Array.isArray(g.combos) && finite2(g.maxLegs);
7045
+ }
7046
+ function drawable(p) {
7047
+ return !!p && finite2(p.price) && finite2(p.matchOddsId) && finite2(p.matchId) && typeof p.homeTeamName === "string" && typeof p.awayTeamName === "string";
7048
+ }
7049
+ function choices(defaults, present) {
7050
+ const out = [];
7051
+ for (const n of [...defaults, ...present]) {
7052
+ if (finite2(n) && n > 0 && !out.some((m) => samePrice(m, n))) out.push(n);
7053
+ }
7054
+ return out.sort((a, b) => a - b);
7055
+ }
7056
+ function singlesLimits(grid) {
7057
+ return choices(DEFAULT_SINGLES_LIMITS, grid.singles.map((c) => c?.price));
7058
+ }
7059
+ function singlesFloors(grid) {
7060
+ return choices(DEFAULT_SINGLES_FLOORS, grid.singlesFrom.map((c) => c?.price));
7061
+ }
7062
+ function comboTotals(grid) {
7063
+ return choices(DEFAULT_COMBO_TOTALS, grid.combos.map((c) => c?.total));
7064
+ }
7065
+ function comboLegChoices(grid) {
7066
+ const max = Math.min(MAX_COMBO_LEGS, Math.floor(grid.maxLegs));
7067
+ const out = [];
7068
+ for (let n = MIN_COMBO_LEGS; n <= max; n++) out.push(n);
7069
+ return out;
7070
+ }
7071
+ function cycle(values, current) {
7072
+ if (values.length === 0) return current;
7073
+ const i = values.findIndex((v) => samePrice(v, current));
7074
+ return values[(i + 1) % values.length] ?? current;
7075
+ }
7076
+ function startValue(values, preferred) {
7077
+ return values.find((v) => samePrice(v, preferred)) ?? values[0] ?? preferred;
7078
+ }
7079
+ function nearest(values, target) {
7080
+ const first = values[0];
7081
+ if (first === void 0) return target;
7082
+ if (!(target > 0)) return first;
7083
+ const distance = (v) => Math.abs(Math.log(v / target));
7084
+ return values.reduce((best, v) => distance(v) < distance(best) ? v : best, first);
7085
+ }
7086
+ function clampLegs(values, legs) {
7087
+ const lo = values[0];
7088
+ const hi = values[values.length - 1];
7089
+ if (lo === void 0 || hi === void 0) return legs;
7090
+ return Math.min(Math.max(Math.round(legs), lo), hi);
7091
+ }
7092
+ function findSingles(cells, price, count) {
7093
+ const cell = cells.find((c) => !!c && finite2(c.price) && samePrice(c.price, price) && c.count === count);
7094
+ return cell && Array.isArray(cell.picks) && cell.picks.length === count && cell.picks.every(drawable) ? cell : null;
7095
+ }
7096
+ function findCombo(grid, total, legs) {
7097
+ const cell = grid.combos.find((c) => !!c && finite2(c.total) && samePrice(c.total, total) && c.legs === legs);
7098
+ const combo = cell?.combo;
7099
+ const whole = !!combo && typeof combo.multiplication === "string" && combo.multiplication !== "" && Array.isArray(combo.legs) && combo.legs.length === legs && combo.legs.every(drawable);
7100
+ return cell && whole ? cell : null;
7101
+ }
7102
+ function idsOf(picks) {
7103
+ return { matchOddsIds: picks.map((p) => p.matchOddsId), matchIds: picks.map((p) => p.matchId) };
7104
+ }
7105
+ function maxPriceAsk(cell, s) {
7106
+ return {
7107
+ message: s.maxPriceMessage(cell.count, cell.price),
7108
+ displayText: s.maxPriceDisplay(cell.count, cell.price),
7109
+ preset: { kind: "max_price", price: cell.price, count: cell.count, ...idsOf(cell.picks) }
7110
+ };
7111
+ }
7112
+ function minPriceAsk(cell, s) {
7113
+ return {
7114
+ message: s.minPriceMessage(cell.count, cell.price),
7115
+ displayText: s.minPriceDisplay(cell.count, cell.price),
7116
+ preset: { kind: "min_price", price: cell.price, count: cell.count, ...idsOf(cell.picks) }
7117
+ };
7118
+ }
7119
+ function comboAsk(cell, s) {
7120
+ return {
7121
+ message: s.comboMessage(cell.legs, cell.total),
7122
+ displayText: s.comboDisplay(cell.legs, cell.total),
7123
+ preset: { kind: "combo", total: cell.total, legs: cell.legs, ...idsOf(cell.combo.legs) }
7124
+ };
7125
+ }
7126
+
7127
+ // src/components/PresetTools.tsx
7128
+ var import_jsx_runtime89 = require("react/jsx-runtime");
7129
+ var FOCUSABLE = 'button:not([disabled]), [href], input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
7130
+ function PresetToolModal({ title, closeLabel, onClose, children, footer }) {
7131
+ const dialogRef = (0, import_react41.useRef)(null);
7132
+ const titleId = (0, import_react41.useId)();
7133
+ (0, import_react41.useEffect)(() => {
7134
+ dialogRef.current?.focus();
7135
+ }, []);
7136
+ (0, import_react41.useEffect)(() => {
7137
+ const onKey = (e) => {
7138
+ if (e.key !== "Escape") return;
7139
+ e.stopPropagation();
7140
+ e.preventDefault();
7141
+ onClose();
7142
+ };
7143
+ window.addEventListener("keydown", onKey, true);
7144
+ return () => window.removeEventListener("keydown", onKey, true);
7145
+ }, [onClose]);
7146
+ const trapTab = (e) => {
7147
+ if (e.key !== "Tab") return;
7148
+ const dialog = dialogRef.current;
7149
+ if (!dialog) return;
7150
+ const items = Array.from(dialog.querySelectorAll(FOCUSABLE));
7151
+ const first = items[0];
7152
+ const last = items[items.length - 1];
7153
+ if (!first || !last) {
7154
+ e.preventDefault();
7155
+ return;
7156
+ }
7157
+ const active = dialog.getRootNode().activeElement;
7158
+ if (e.shiftKey && (active === first || active === dialog)) {
7159
+ e.preventDefault();
7160
+ last.focus();
7161
+ } else if (!e.shiftKey && active === last) {
7162
+ e.preventDefault();
7163
+ first.focus();
7164
+ }
7165
+ };
7166
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-tool-backdrop", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { ref: dialogRef, className: "ss-w-tool", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, tabIndex: -1, onKeyDown: trapTab, children: [
7167
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-tool-head", children: [
7168
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("h2", { id: titleId, className: "ss-w-tool-title", children: title }),
7169
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(CloseIcon, {}) })
7170
+ ] }),
7171
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-tool-body", children }),
7172
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-tool-foot", children: footer }) : null
7173
+ ] }) });
7174
+ }
7175
+ function fillTemplate(template, slots) {
7176
+ return template.split(/(\{[a-z]+\})/).filter((part) => part !== "").map((part, i) => {
7177
+ const key = /^\{([a-z]+)\}$/.exec(part)?.[1];
7178
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(import_react41.Fragment, { children: key !== void 0 && key in slots ? slots[key] : part }, i);
7179
+ });
7180
+ }
7181
+ function NumberButton({ value, label, onCycle }) {
7182
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-num", "aria-label": label, onClick: onCycle, children: value });
7183
+ }
7184
+ function SendButton({ label, display, disabled, onClick }) {
7185
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-send", "aria-label": `${label}: ${display}`, disabled, onClick, children: label });
7186
+ }
7187
+ function PickList({ picks, formatKickoff }) {
7188
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("ul", { className: "ss-w-tool-picks", role: "list", children: picks.map((p) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("li", { className: "ss-w-tool-pick", children: [
7189
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "ss-w-tool-pick-match", children: [
7190
+ p.homeTeamName,
7191
+ " \u2013 ",
7192
+ p.awayTeamName
7193
+ ] }),
7194
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "ss-w-tool-pick-sel", children: [
7195
+ p.marketLabel,
7196
+ ": ",
7197
+ p.selectionLabel,
7198
+ p.line ? ` ${p.line}` : ""
7199
+ ] }),
7200
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-tool-pick-kick", children: formatKickoff(p.kickoffUtc) }),
7201
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-tool-pick-price", children: p.price.toFixed(2) })
7202
+ ] }, p.matchOddsId)) });
7203
+ }
7204
+ function ComboPreview({ cell, formatKickoff }) {
7205
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
7206
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(PickList, { picks: cell.combo.legs, formatKickoff }),
7207
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-tool-math", children: cell.combo.multiplication })
7208
+ ] });
7209
+ }
7210
+ function Unavailable({ text }) {
7211
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-tool-unavailable", children: text });
7212
+ }
7213
+ function SetNumbersTool({ grid, strings, streaming, formatKickoff, onSend, onClose }) {
7214
+ const limits = singlesLimits(grid);
7215
+ const floors = singlesFloors(grid);
7216
+ const totals = comboTotals(grid);
7217
+ const legChoices = comboLegChoices(grid);
7218
+ const count = FIXED_SINGLES_COUNT;
7219
+ const [maxPrice, setMaxPrice] = (0, import_react41.useState)(() => startValue(limits, START.maxPrice));
7220
+ const [minPrice, setMinPrice] = (0, import_react41.useState)(() => startValue(floors, START.minPrice));
7221
+ const [total, setTotal] = (0, import_react41.useState)(() => startValue(totals, START.comboTotal));
7222
+ const [legs, setLegs] = (0, import_react41.useState)(() => startValue(legChoices, START.comboLegs));
7223
+ const [announcement, setAnnouncement] = (0, import_react41.useState)("");
7224
+ const maxCell = findSingles(grid.singles, maxPrice, count);
7225
+ const minCell = findSingles(grid.singlesFrom, minPrice, count);
7226
+ const comboCell = findCombo(grid, total, legs);
7227
+ const announce = (display, available) => setAnnouncement(available ? display : `${display}. ${strings.unavailable}`);
7228
+ const nextMax = () => {
7229
+ const v = cycle(limits, maxPrice);
7230
+ setMaxPrice(v);
7231
+ announce(strings.maxPriceDisplay(count, v), !!findSingles(grid.singles, v, count));
7232
+ };
7233
+ const nextMin = () => {
7234
+ const v = cycle(floors, minPrice);
7235
+ setMinPrice(v);
7236
+ announce(strings.minPriceDisplay(count, v), !!findSingles(grid.singlesFrom, v, count));
7237
+ };
7238
+ const nextLegs = () => {
7239
+ const v = cycle(legChoices, legs);
7240
+ setLegs(v);
7241
+ announce(strings.comboDisplay(v, total), !!findCombo(grid, total, v));
7242
+ };
7243
+ const nextTotal = () => {
7244
+ const v = cycle(totals, total);
7245
+ setTotal(v);
7246
+ announce(strings.comboDisplay(legs, v), !!findCombo(grid, v, legs));
7247
+ };
7248
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(PresetToolModal, { title: strings.setNumbers, closeLabel: strings.close, onClose, children: [
7249
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("section", { className: "ss-w-tool-row", children: [
7250
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.maxPriceRow, {
7251
+ count: String(count),
7252
+ price: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(NumberButton, { value: maxPrice.toFixed(2), label: strings.changeNumber(maxPrice.toFixed(2)), onCycle: nextMax })
7253
+ }) }),
7254
+ maxCell ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(PickList, { picks: maxCell.picks, formatKickoff }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Unavailable, { text: strings.unavailable }),
7255
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(SendButton, { label: strings.send, display: strings.maxPriceDisplay(count, maxPrice), disabled: !maxCell || streaming, onClick: () => {
7256
+ if (maxCell) onSend(maxPriceAsk(maxCell, strings));
7257
+ } })
7258
+ ] }),
7259
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("section", { className: "ss-w-tool-row", children: [
7260
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.minPriceRow, {
7261
+ count: String(count),
7262
+ price: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(NumberButton, { value: minPrice.toFixed(2), label: strings.changeNumber(minPrice.toFixed(2)), onCycle: nextMin })
7263
+ }) }),
7264
+ minCell ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(PickList, { picks: minCell.picks, formatKickoff }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Unavailable, { text: strings.unavailable }),
7265
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(SendButton, { label: strings.send, display: strings.minPriceDisplay(count, minPrice), disabled: !minCell || streaming, onClick: () => {
7266
+ if (minCell) onSend(minPriceAsk(minCell, strings));
7267
+ } })
7268
+ ] }),
7269
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("section", { className: "ss-w-tool-row", children: [
7270
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.comboRow, {
7271
+ legs: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(NumberButton, { value: String(legs), label: strings.changeNumber(String(legs)), onCycle: nextLegs }),
7272
+ total: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(NumberButton, { value: total.toFixed(1), label: strings.changeNumber(total.toFixed(1)), onCycle: nextTotal })
7273
+ }) }),
7274
+ comboCell ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ComboPreview, { cell: comboCell, formatKickoff }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Unavailable, { text: strings.unavailable }),
7275
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(SendButton, { label: strings.send, display: strings.comboDisplay(legs, total), disabled: !comboCell || streaming, onClick: () => {
7276
+ if (comboCell) onSend(comboAsk(comboCell, strings));
7277
+ } })
7278
+ ] }),
7279
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-vh", "aria-live": "polite", children: announcement })
7280
+ ] });
7281
+ }
7282
+ function BuildComboTool({ grid, strings, streaming, formatKickoff, initialTotal, initialLegs, onSend, onClose }) {
7283
+ const totals = comboTotals(grid);
7284
+ const legChoices = comboLegChoices(grid);
7285
+ const [total, setTotal] = (0, import_react41.useState)(() => initialTotal !== void 0 ? nearest(totals, initialTotal) : startValue(totals, START.comboTotal));
7286
+ const [legs, setLegs] = (0, import_react41.useState)(() => initialLegs !== void 0 ? clampLegs(legChoices, initialLegs) : startValue(legChoices, START.comboLegs));
7287
+ const [announcement, setAnnouncement] = (0, import_react41.useState)("");
7288
+ const cell = findCombo(grid, total, legs);
7289
+ const minLegs = legChoices[0] ?? legs;
7290
+ const maxLegs = legChoices[legChoices.length - 1] ?? legs;
7291
+ const display = strings.comboDisplay(legs, total);
7292
+ const choose = (nextTotal, nextLegs) => {
7293
+ setTotal(nextTotal);
7294
+ setLegs(nextLegs);
7295
+ const d = strings.comboDisplay(nextLegs, nextTotal);
7296
+ setAnnouncement(findCombo(grid, nextTotal, nextLegs) ? d : `${d}. ${strings.unavailable}`);
7297
+ };
7298
+ const footer = /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(SendButton, { label: strings.send, display, disabled: !cell || streaming, onClick: () => {
7299
+ if (cell) onSend(comboAsk(cell, strings));
7300
+ } });
7301
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(PresetToolModal, { title: strings.buildCombo, closeLabel: strings.close, onClose, footer, children: [
7302
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-tool-section", role: "group", "aria-label": strings.totalLabel, children: [
7303
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-tool-label", "aria-hidden": "true", children: strings.totalLabel }),
7304
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-tool-chips", children: totals.map((t) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-chip", "aria-pressed": samePrice(t, total), onClick: () => choose(t, legs), children: t.toFixed(1) }, t)) })
7305
+ ] }),
7306
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-tool-section", role: "group", "aria-label": strings.matchesLabel, children: [
7307
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-tool-label", "aria-hidden": "true", children: strings.matchesLabel }),
7308
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-tool-stepper", children: [
7309
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-step", "aria-label": strings.fewerMatches, disabled: legs <= minLegs, onClick: () => choose(total, legs - 1), children: "\u2212" }),
7310
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-tool-count", children: legs }),
7311
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-tool-step", "aria-label": strings.moreMatches, disabled: legs >= maxLegs, onClick: () => choose(total, legs + 1), children: "+" })
7312
+ ] })
7313
+ ] }),
7314
+ cell ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ComboPreview, { cell, formatKickoff }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Unavailable, { text: strings.unavailable }),
7315
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "ss-w-vh", "aria-live": "polite", children: announcement })
7316
+ ] });
7317
+ }
7318
+
7319
+ // src/usePresetDial.ts
7320
+ var import_react42 = require("react");
7321
+ function sendInFlight(messages, isStreaming) {
7322
+ const last = messages[messages.length - 1];
7323
+ return isStreaming && !!last && last.role === "assistant" && !last.done && !last.isGreeting;
7324
+ }
7325
+ function lastUserId(messages) {
7326
+ for (let i = messages.length - 1; i >= 0; i--) {
7327
+ const m = messages[i];
7328
+ if (m && m.role === "user") return m.id;
7329
+ }
7330
+ return null;
7331
+ }
7332
+ var SCROLL_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "]);
7333
+ function usePresetDial({ layerRef, dialRef, dialButtonRef, messages, isStreaming, activeTab }) {
7334
+ const [expanded, setExpanded] = (0, import_react42.useState)(() => !sendInFlight(messages, isStreaming));
7335
+ const fold = (0, import_react42.useCallback)(() => setExpanded(false), []);
7336
+ const toggle = (0, import_react42.useCallback)(() => setExpanded((e) => !e), []);
7337
+ const currentUserId = lastUserId(messages);
7338
+ const userIdRef = (0, import_react42.useRef)(currentUserId);
7339
+ (0, import_react42.useEffect)(() => {
7340
+ if (currentUserId === userIdRef.current) return;
7341
+ userIdRef.current = currentUserId;
7342
+ setExpanded(false);
7343
+ }, [currentUserId]);
7344
+ const tabRef = (0, import_react42.useRef)(activeTab);
7345
+ (0, import_react42.useEffect)(() => {
7346
+ if (activeTab === tabRef.current) return;
7347
+ tabRef.current = activeTab;
7348
+ setExpanded(false);
7349
+ }, [activeTab]);
7350
+ const expandedRef = (0, import_react42.useRef)(expanded);
7351
+ expandedRef.current = expanded;
7352
+ (0, import_react42.useEffect)(() => {
7353
+ const onEscape = (e) => {
7354
+ const dial = dialRef.current;
7355
+ if (e.key !== "Escape" || !dial || !e.composedPath().includes(dial)) return;
7356
+ e.stopPropagation();
7357
+ e.preventDefault();
7358
+ if (!expandedRef.current) return;
7359
+ setExpanded(false);
7360
+ dialButtonRef.current?.focus();
7361
+ };
7362
+ window.addEventListener("keydown", onEscape, true);
7363
+ return () => window.removeEventListener("keydown", onEscape, true);
7364
+ }, [dialRef, dialButtonRef]);
7365
+ (0, import_react42.useEffect)(() => {
7366
+ if (!expanded) return;
7367
+ const layer = layerRef.current;
7368
+ const inDial = (e) => {
7369
+ const dial = dialRef.current;
7370
+ return !!dial && e.composedPath().includes(dial);
7371
+ };
7372
+ const inList = (e) => e.composedPath().some((n) => n instanceof Element && n.classList.contains("ss-w-list"));
7373
+ const onPress = (e) => {
7374
+ if (!inDial(e)) setExpanded(false);
7375
+ };
7376
+ const onScrollGesture = (e) => {
7377
+ if (inList(e) && !inDial(e)) setExpanded(false);
7378
+ };
7379
+ const onKey = (e) => {
7380
+ if (SCROLL_KEYS.has(e.key) && inList(e)) setExpanded(false);
7381
+ };
7382
+ const doc = layer?.ownerDocument ?? document;
7383
+ doc.addEventListener("pointerdown", onPress, true);
7384
+ layer?.addEventListener("wheel", onScrollGesture, { passive: true });
7385
+ layer?.addEventListener("touchmove", onScrollGesture, { passive: true });
7386
+ window.addEventListener("keydown", onKey, true);
7387
+ return () => {
7388
+ doc.removeEventListener("pointerdown", onPress, true);
7389
+ layer?.removeEventListener("wheel", onScrollGesture);
7390
+ layer?.removeEventListener("touchmove", onScrollGesture);
7391
+ window.removeEventListener("keydown", onKey, true);
7392
+ };
7393
+ }, [expanded, layerRef, dialRef]);
7394
+ return { expanded, toggle, fold };
7395
+ }
7396
+
7397
+ // src/presetSeen.ts
7398
+ var KEY = "ss-w-presets-tool-opened";
7399
+ var openedThisPage = false;
7400
+ function readToolSeen() {
7401
+ if (openedThisPage) return true;
7402
+ try {
7403
+ return window.localStorage.getItem(KEY) === "1";
7404
+ } catch {
7405
+ return false;
7406
+ }
7407
+ }
7408
+ function markToolSeen() {
7409
+ openedThisPage = true;
7410
+ try {
7411
+ window.localStorage.setItem(KEY, "1");
7412
+ } catch {
7413
+ }
7414
+ }
7415
+
7416
+ // src/components/ChatPanel.tsx
7417
+ var import_jsx_runtime90 = require("react/jsx-runtime");
6832
7418
  var FULLSCREEN_QUERY = "(max-width: 639px)";
6833
7419
  function useIsModal() {
6834
- const [modal, setModal] = (0, import_react39.useState)(false);
6835
- (0, import_react39.useEffect)(() => {
7420
+ const [modal, setModal] = (0, import_react43.useState)(false);
7421
+ (0, import_react43.useEffect)(() => {
6836
7422
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
6837
7423
  const mql = window.matchMedia(FULLSCREEN_QUERY);
6838
7424
  const sync = () => setModal(mql.matches);
@@ -6842,10 +7428,11 @@ function useIsModal() {
6842
7428
  }, []);
6843
7429
  return modal;
6844
7430
  }
6845
- function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }) {
7431
+ var HIDDEN_LAYER_STYLE = { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" };
7432
+ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation, presetGrid }) {
6846
7433
  const { state, close, stop, send, reset } = controller;
6847
7434
  const isModal = useIsModal();
6848
- (0, import_react39.useEffect)(() => {
7435
+ (0, import_react43.useEffect)(() => {
6849
7436
  const onKey = (e) => {
6850
7437
  if (e.key === "Escape") close();
6851
7438
  };
@@ -6860,11 +7447,66 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6860
7447
  monitor?.setActiveTab("chat");
6861
7448
  send(text, { grounding });
6862
7449
  };
6863
- (0, import_react39.useEffect)(() => {
7450
+ (0, import_react43.useEffect)(() => {
6864
7451
  if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
6865
7452
  }, [monitor, state.isStreaming, state.messages.length]);
6866
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
6867
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
7453
+ const onChatTab = !monitor || monitor.activeTab === "chat";
7454
+ const layerRef = (0, import_react43.useRef)(null);
7455
+ const dialRef = (0, import_react43.useRef)(null);
7456
+ const dialButtonRef = (0, import_react43.useRef)(null);
7457
+ const inputRef = (0, import_react43.useRef)(null);
7458
+ const focusAfterCloseRef = (0, import_react43.useRef)(null);
7459
+ const [tool, setTool] = (0, import_react43.useState)(null);
7460
+ const [toolSeen, setToolSeen] = (0, import_react43.useState)(readToolSeen);
7461
+ const dial = usePresetDial({
7462
+ layerRef,
7463
+ dialRef,
7464
+ dialButtonRef,
7465
+ messages: state.messages,
7466
+ isStreaming: state.isStreaming,
7467
+ activeTab: monitor?.activeTab ?? "chat"
7468
+ });
7469
+ const { fold } = dial;
7470
+ const showDial = !!presetGrid && onChatTab && !tool;
7471
+ const openTool = (0, import_react43.useCallback)((next) => {
7472
+ fold();
7473
+ markToolSeen();
7474
+ setToolSeen(true);
7475
+ setTool(next);
7476
+ }, [fold]);
7477
+ const onPill = (0, import_react43.useCallback)((kind) => openTool(kind === "numbers" ? { kind: "numbers" } : { kind: "combo" }), [openTool]);
7478
+ const toolsValue = (0, import_react43.useMemo)(
7479
+ () => presetGrid ? { openBuilder: (total, legs) => openTool({ kind: "combo", total, legs }), changeLabel: ui.presets.changeCombo } : null,
7480
+ [presetGrid, openTool, ui.presets.changeCombo]
7481
+ );
7482
+ const closeTool = (0, import_react43.useCallback)(() => {
7483
+ focusAfterCloseRef.current = "dial";
7484
+ setTool(null);
7485
+ }, []);
7486
+ const sendAsk = (0, import_react43.useCallback)((ask) => {
7487
+ focusAfterCloseRef.current = "composer";
7488
+ setTool(null);
7489
+ monitor?.setActiveTab("chat");
7490
+ send(ask.message, { displayText: ask.displayText, preset: ask.preset });
7491
+ }, [monitor, send]);
7492
+ const formatKickoff = (0, import_react43.useCallback)((kickoffUtc) => {
7493
+ const k = ui.bettingKickoff(kickoffUtc);
7494
+ return `${k.dayLabel} ${k.time}`;
7495
+ }, [ui]);
7496
+ (0, import_react43.useEffect)(() => {
7497
+ if (tool) return;
7498
+ const target = focusAfterCloseRef.current;
7499
+ focusAfterCloseRef.current = null;
7500
+ if (target === "dial") dialButtonRef.current?.focus();
7501
+ else if (target === "composer") inputRef.current?.focus();
7502
+ }, [tool]);
7503
+ (0, import_react43.useEffect)(() => {
7504
+ if (!tool || onChatTab && presetGrid) return;
7505
+ focusAfterCloseRef.current = "composer";
7506
+ setTool(null);
7507
+ }, [tool, onChatTab, presetGrid]);
7508
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
7509
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
6868
7510
  ChatHeader,
6869
7511
  {
6870
7512
  onClose: close,
@@ -6877,7 +7519,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6877
7519
  moreOptionsLabel: ui.moreOptions
6878
7520
  }
6879
7521
  ),
6880
- monitor && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
7522
+ monitor && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
6881
7523
  TabBar,
6882
7524
  {
6883
7525
  monitor,
@@ -6889,17 +7531,26 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6889
7531
  gamesEnabled: gamesResult?.enabled ?? false
6890
7532
  }
6891
7533
  ),
6892
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
6893
- "div",
6894
- {
6895
- style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
6896
- children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
6897
- }
6898
- ),
6899
- monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(TodayPanel, { discovery, ui, monitor }),
6900
- monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(MatchesPanel, { monitor, ui, slip, onAsk: handleAsk }),
6901
- monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(OddsPanel, { monitor, ui, slip }),
6902
- monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
7534
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { ref: layerRef, className: "ss-w-chat-layer", "data-dial": presetGrid ? "" : void 0, style: onChatTab ? void 0 : HIDDEN_LAYER_STYLE, children: [
7535
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(PresetToolsContext.Provider, { value: toolsValue, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor }) }),
7536
+ showDial ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
7537
+ PresetSpeedDial,
7538
+ {
7539
+ expanded: dial.expanded,
7540
+ showDot: !toolSeen,
7541
+ strings: ui.presets,
7542
+ onToggle: dial.toggle,
7543
+ onOpen: onPill,
7544
+ rootRef: dialRef,
7545
+ buttonRef: dialButtonRef
7546
+ }
7547
+ ) : null,
7548
+ tool && presetGrid && onChatTab ? tool.kind === "numbers" ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(SetNumbersTool, { grid: presetGrid, strings: ui.presets, streaming: state.isStreaming, formatKickoff, onSend: sendAsk, onClose: closeTool }) : /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BuildComboTool, { grid: presetGrid, strings: ui.presets, streaming: state.isStreaming, formatKickoff, initialTotal: tool.total, initialLegs: tool.legs, onSend: sendAsk, onClose: closeTool }) : null
7549
+ ] }),
7550
+ monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(TodayPanel, { discovery, ui, monitor }),
7551
+ monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(MatchesPanel, { monitor, ui, slip, onAsk: handleAsk }),
7552
+ monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(OddsPanel, { monitor, ui, slip }),
7553
+ monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
6903
7554
  GamesPanel,
6904
7555
  {
6905
7556
  loggedIn: !!loggedIn,
@@ -6913,7 +7564,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6913
7564
  }
6914
7565
  }
6915
7566
  ),
6916
- monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
7567
+ monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
6917
7568
  LeaderboardPanel,
6918
7569
  {
6919
7570
  loggedIn: !!loggedIn,
@@ -6923,7 +7574,20 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
6923
7574
  ui
6924
7575
  }
6925
7576
  ),
6926
- (!monitor || monitor.activeTab !== "games" && monitor.activeTab !== "leaderboard") && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
7577
+ (!monitor || monitor.activeTab !== "games" && monitor.activeTab !== "leaderboard") && /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
7578
+ ChatInput,
7579
+ {
7580
+ ref: inputRef,
7581
+ placeholder: ui.placeholder,
7582
+ streaming: state.isStreaming,
7583
+ onSend: handleSend,
7584
+ onStop: stop,
7585
+ stopLabel: ui.stopResponse,
7586
+ sendLabel: ui.sendMessage,
7587
+ disabled: !!tool,
7588
+ onType: fold
7589
+ }
7590
+ )
6927
7591
  ] });
6928
7592
  }
6929
7593
 
@@ -7132,15 +7796,15 @@ function toSlipEvent(name, entry) {
7132
7796
  // src/useHostEvents.ts
7133
7797
  function useHostEvents(opts) {
7134
7798
  const { host, operatorId, currentUser, logger, isOpen, closePanel, onOpenMatch, openMatchLabel } = opts;
7135
- const [added, setAdded] = (0, import_react40.useState)({});
7136
- const [settled, setSettled] = (0, import_react40.useState)({});
7137
- const markAdded = (0, import_react40.useCallback)((matchOddsId) => {
7799
+ const [added, setAdded] = (0, import_react44.useState)({});
7800
+ const [settled, setSettled] = (0, import_react44.useState)({});
7801
+ const markAdded = (0, import_react44.useCallback)((matchOddsId) => {
7138
7802
  setAdded((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
7139
7803
  }, []);
7140
- const settle = (0, import_react40.useCallback)((matchOddsId) => {
7804
+ const settle = (0, import_react44.useCallback)((matchOddsId) => {
7141
7805
  setSettled((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
7142
7806
  }, []);
7143
- const clearMarks = (0, import_react40.useCallback)((ids) => {
7807
+ const clearMarks = (0, import_react44.useCallback)((ids) => {
7144
7808
  const drop = (prev) => {
7145
7809
  if (!ids.some((id) => prev[id])) return prev;
7146
7810
  const next = { ...prev };
@@ -7151,26 +7815,26 @@ function useHostEvents(opts) {
7151
7815
  setSettled(drop);
7152
7816
  }, []);
7153
7817
  const hasHost = host !== void 0;
7154
- const ledger = (0, import_react40.useMemo)(
7818
+ const ledger = (0, import_react44.useMemo)(
7155
7819
  () => hasHost ? createSlipLedger(`ss-w-slip:${operatorId}`) : null,
7156
7820
  [hasHost, operatorId]
7157
7821
  );
7158
- const currentUserRef = (0, import_react40.useRef)(currentUser);
7822
+ const currentUserRef = (0, import_react44.useRef)(currentUser);
7159
7823
  currentUserRef.current = currentUser;
7160
- const recordAdd = (0, import_react40.useCallback)((add) => {
7824
+ const recordAdd = (0, import_react44.useCallback)((add) => {
7161
7825
  ledger?.record({ id: add.selection.matchOddsId, market: add.market, ...add.pick, user: currentUserRef.current });
7162
7826
  }, [ledger]);
7163
- const slipState = (0, import_react40.useMemo)(
7827
+ const slipState = (0, import_react44.useMemo)(
7164
7828
  () => ({ added, settled, settle, recordAdd }),
7165
7829
  [added, settled, settle, recordAdd]
7166
7830
  );
7167
7831
  const hasOpenMatch = typeof onOpenMatch === "function";
7168
7832
  const tracksViews = hasHost || hasOpenMatch;
7169
- const views = (0, import_react40.useMemo)(
7833
+ const views = (0, import_react44.useMemo)(
7170
7834
  () => tracksViews ? createMatchViews(`ss-w-views:${operatorId}`, { user: currentUser }) : null,
7171
7835
  [tracksViews, operatorId, currentUser]
7172
7836
  );
7173
- const sinkRef = (0, import_react40.useRef)(() => {
7837
+ const sinkRef = (0, import_react44.useRef)(() => {
7174
7838
  });
7175
7839
  sinkRef.current = (command) => {
7176
7840
  if (command.kind === "matchOpened") {
@@ -7191,11 +7855,11 @@ function useHostEvents(opts) {
7191
7855
  logger?.log(toSlipEvent(name, entry));
7192
7856
  }
7193
7857
  };
7194
- (0, import_react40.useEffect)(() => {
7858
+ (0, import_react44.useEffect)(() => {
7195
7859
  if (!host) return;
7196
7860
  return attachHost(host, (command) => sinkRef.current(command));
7197
7861
  }, [host]);
7198
- (0, import_react40.useEffect)(() => {
7862
+ (0, import_react44.useEffect)(() => {
7199
7863
  if (!isOpen || !views) return;
7200
7864
  const held = views.markOpened();
7201
7865
  if (held.length === 0) return;
@@ -7204,7 +7868,7 @@ function useHostEvents(opts) {
7204
7868
  }
7205
7869
  void logger?.flushNow();
7206
7870
  }, [isOpen, views, logger]);
7207
- const openMatchRef = (0, import_react40.useRef)(() => {
7871
+ const openMatchRef = (0, import_react44.useRef)(() => {
7208
7872
  });
7209
7873
  openMatchRef.current = (matchId) => {
7210
7874
  if (views?.view(matchId) === "log") {
@@ -7218,7 +7882,7 @@ function useHostEvents(opts) {
7218
7882
  }
7219
7883
  if (typeof window.matchMedia === "function" && window.matchMedia(FULLSCREEN_QUERY).matches) closePanel();
7220
7884
  };
7221
- const matchLink = (0, import_react40.useMemo)(
7885
+ const matchLink = (0, import_react44.useMemo)(
7222
7886
  () => hasOpenMatch ? { open: (matchId) => openMatchRef.current(matchId), label: openMatchLabel } : null,
7223
7887
  [hasOpenMatch, openMatchLabel]
7224
7888
  );
@@ -7286,12 +7950,27 @@ function themeAttrs(ui) {
7286
7950
  }
7287
7951
 
7288
7952
  // src/useChatStream.ts
7289
- var import_react42 = require("react");
7953
+ var import_react46 = require("react");
7290
7954
  var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
7291
7955
 
7292
7956
  // src/reducer.ts
7293
7957
  var import_widget_sdk3 = require("@sensiblestats/widget-sdk");
7294
7958
  var POPUP_MAX = 160;
7959
+ function markAwaitingLiveUpdate(messages, held = []) {
7960
+ if (!messages.some((m) => m.role === "assistant" && m.marketOdds.some((vm) => vm.live != null))) return messages;
7961
+ const heldFlags = /* @__PURE__ */ new Map();
7962
+ for (const m of held) {
7963
+ if (m.role !== "assistant") continue;
7964
+ for (const vm of m.marketOdds) if (vm.live != null) heldFlags.set(`${m.id}|${vm.id}`, vm.awaitingLiveUpdate === true);
7965
+ }
7966
+ return messages.map((m) => {
7967
+ if (m.role !== "assistant" || !m.marketOdds.some((vm) => vm.live != null)) return m;
7968
+ return {
7969
+ ...m,
7970
+ marketOdds: m.marketOdds.map((vm) => vm.live != null ? { ...vm, awaitingLiveUpdate: heldFlags.get(`${m.id}|${vm.id}`) ?? true } : vm)
7971
+ };
7972
+ });
7973
+ }
7295
7974
  function initialState(starters) {
7296
7975
  return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, configuredStarters: starters, error: null, lastUserInput: null, lastDisplayText: null, popupText: null, conversationId: null };
7297
7976
  }
@@ -7383,7 +8062,7 @@ function reducer(state, action) {
7383
8062
  case "RESTORE":
7384
8063
  return {
7385
8064
  ...state,
7386
- messages: action.messages,
8065
+ messages: markAwaitingLiveUpdate(action.messages, state.messages),
7387
8066
  conversationId: action.conversationId,
7388
8067
  isStreaming: false,
7389
8068
  status: null,
@@ -7397,6 +8076,22 @@ function reducer(state, action) {
7397
8076
  return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
7398
8077
  case "STOP":
7399
8078
  return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
8079
+ case "UPDATE_LIVE_CARD": {
8080
+ const { matchId, live, mainRows, moreRows, addToSlipEnabled } = action;
8081
+ return {
8082
+ ...state,
8083
+ messages: state.messages.map((m) => {
8084
+ if (m.role !== "assistant") return m;
8085
+ if (!m.marketOdds.some((vm) => vm.matchId === matchId && vm.live != null)) return m;
8086
+ return {
8087
+ ...m,
8088
+ marketOdds: m.marketOdds.map(
8089
+ (vm) => vm.matchId === matchId && vm.live != null ? { ...vm, live, mainRows, moreRows, addToSlipEnabled, awaitingLiveUpdate: false } : vm
8090
+ )
8091
+ };
8092
+ })
8093
+ };
8094
+ }
7400
8095
  case "LIVE_REFRESH":
7401
8096
  return {
7402
8097
  ...state,
@@ -7415,7 +8110,7 @@ function reducer(state, action) {
7415
8110
  }
7416
8111
 
7417
8112
  // src/useLiveDashboardPoll.ts
7418
- var import_react41 = require("react");
8113
+ var import_react45 = require("react");
7419
8114
  var POLL_INTERVAL_MS = 6e4;
7420
8115
  var LEAD_MS = 12e4;
7421
8116
  var GIVE_UP_MS = 30 * 6e4;
@@ -7457,13 +8152,13 @@ function findEarliestWakeupMs(messages) {
7457
8152
  return earliest;
7458
8153
  }
7459
8154
  function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
7460
- const [, forceUpdate] = (0, import_react41.useReducer)((x) => x + 1, 0);
8155
+ const [, forceUpdate] = (0, import_react45.useReducer)((x) => x + 1, 0);
7461
8156
  const anchor = findAnchor(messages);
7462
- const anchorRef = (0, import_react41.useRef)(anchor);
8157
+ const anchorRef = (0, import_react45.useRef)(anchor);
7463
8158
  anchorRef.current = anchor;
7464
- const inFlightRef = (0, import_react41.useRef)(false);
8159
+ const inFlightRef = (0, import_react45.useRef)(false);
7465
8160
  const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null;
7466
- (0, import_react41.useEffect)(() => {
8161
+ (0, import_react45.useEffect)(() => {
7467
8162
  if (!anchorKey || !anchorRef.current) return;
7468
8163
  const tick = async () => {
7469
8164
  if (inFlightRef.current) return;
@@ -7499,7 +8194,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
7499
8194
  }, POLL_INTERVAL_MS);
7500
8195
  return () => window.clearInterval(id);
7501
8196
  }, [anchorKey, dispatch, getLiveDashboard]);
7502
- (0, import_react41.useEffect)(() => {
8197
+ (0, import_react45.useEffect)(() => {
7503
8198
  if (anchorKey !== null) return;
7504
8199
  const wakeAt = findEarliestWakeupMs(messages);
7505
8200
  if (wakeAt === null) return;
@@ -7564,36 +8259,36 @@ function seedIdCounter(messages) {
7564
8259
  return max + 1;
7565
8260
  }
7566
8261
  function useChatStream(conversation, starterTexts, greetingMessage, storageKey) {
7567
- const boot = (0, import_react42.useMemo)(() => {
8262
+ const boot = (0, import_react46.useMemo)(() => {
7568
8263
  const payload = storageKey ? readConversation(storageKey, Date.now()) : null;
7569
8264
  const restored = payload != null && payload !== "expired" && payload !== "corrupt";
7570
8265
  const base = initialState(starterTexts.map(chipFromText));
7571
8266
  if (restored) {
7572
- return { state: { ...base, messages: payload.messages, conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
8267
+ return { state: { ...base, messages: markAwaitingLiveUpdate(payload.messages), conversationId: payload.conversationId, starters: [] }, restored: true, stale: false };
7573
8268
  }
7574
8269
  return { state: base, restored: false, stale: payload === "expired" || payload === "corrupt" };
7575
8270
  }, []);
7576
- const [state, dispatch] = (0, import_react42.useReducer)(reducer, boot.state);
7577
- const idRef = (0, import_react42.useRef)(seedIdCounter(boot.state.messages));
7578
- const handleRef = (0, import_react42.useRef)(null);
7579
- const fallbackTimerRef = (0, import_react42.useRef)(null);
7580
- const stateRef = (0, import_react42.useRef)(state);
8271
+ const [state, dispatch] = (0, import_react46.useReducer)(reducer, boot.state);
8272
+ const idRef = (0, import_react46.useRef)(seedIdCounter(boot.state.messages));
8273
+ const handleRef = (0, import_react46.useRef)(null);
8274
+ const fallbackTimerRef = (0, import_react46.useRef)(null);
8275
+ const stateRef = (0, import_react46.useRef)(state);
7581
8276
  stateRef.current = state;
7582
- const greetedRef = (0, import_react42.useRef)(boot.restored);
7583
- const hydratedRef = (0, import_react42.useRef)(false);
7584
- const restoreSeededRef = (0, import_react42.useRef)(false);
8277
+ const greetedRef = (0, import_react46.useRef)(boot.restored);
8278
+ const hydratedRef = (0, import_react46.useRef)(false);
8279
+ const restoreSeededRef = (0, import_react46.useRef)(false);
7585
8280
  if (!restoreSeededRef.current) {
7586
8281
  restoreSeededRef.current = true;
7587
8282
  if (boot.restored && boot.state.conversationId) conversation.conversationId = boot.state.conversationId;
7588
8283
  }
7589
8284
  const nextId = () => `m${idRef.current++}`;
7590
- const clearFallbackTimer = (0, import_react42.useCallback)(() => {
8285
+ const clearFallbackTimer = (0, import_react46.useCallback)(() => {
7591
8286
  if (fallbackTimerRef.current != null) {
7592
8287
  clearTimeout(fallbackTimerRef.current);
7593
8288
  fallbackTimerRef.current = null;
7594
8289
  }
7595
8290
  }, []);
7596
- const armFallbackTimer = (0, import_react42.useCallback)((onFire) => {
8291
+ const armFallbackTimer = (0, import_react46.useCallback)((onFire) => {
7597
8292
  clearFallbackTimer();
7598
8293
  fallbackTimerRef.current = setTimeout(() => {
7599
8294
  fallbackTimerRef.current = null;
@@ -7602,7 +8297,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7602
8297
  onFire();
7603
8298
  }, STREAM_FALLBACK_TIMEOUT_MS);
7604
8299
  }, [clearFallbackTimer]);
7605
- const consume = (0, import_react42.useCallback)((handle, onError) => {
8300
+ const consume = (0, import_react46.useCallback)((handle, onError) => {
7606
8301
  ;
7607
8302
  (async () => {
7608
8303
  try {
@@ -7620,7 +8315,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7620
8315
  }
7621
8316
  })();
7622
8317
  }, [clearFallbackTimer]);
7623
- const run = (0, import_react42.useCallback)((input, displayText) => {
8318
+ const run = (0, import_react46.useCallback)((input, displayText) => {
7624
8319
  handleRef.current?.cancel();
7625
8320
  clearFallbackTimer();
7626
8321
  dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
@@ -7632,7 +8327,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7632
8327
  });
7633
8328
  consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
7634
8329
  }, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
7635
- const send = (0, import_react42.useCallback)((text, opts) => {
8330
+ const send = (0, import_react46.useCallback)((text, opts) => {
7636
8331
  const trimmed = text.trim();
7637
8332
  if (!trimmed) return;
7638
8333
  run({
@@ -7640,14 +8335,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7640
8335
  actionId: opts?.actionId,
7641
8336
  actionRef: opts?.actionRef,
7642
8337
  grounding: opts?.grounding,
7643
- clientCapabilities: [...CLIENT_CAPABILITIES]
8338
+ clientCapabilities: [...CLIENT_CAPABILITIES],
8339
+ ...opts?.preset ? { preset: opts.preset } : {}
7644
8340
  }, opts?.displayText);
7645
8341
  }, [run]);
7646
- const retry = (0, import_react42.useCallback)(() => {
8342
+ const retry = (0, import_react46.useCallback)(() => {
7647
8343
  const last = stateRef.current.lastUserInput;
7648
8344
  if (last) run(last, stateRef.current.lastDisplayText ?? void 0);
7649
8345
  }, [run]);
7650
- const fireGreeting = (0, import_react42.useCallback)(() => {
8346
+ const fireGreeting = (0, import_react46.useCallback)(() => {
7651
8347
  const message = greetingMessage?.trim();
7652
8348
  if (!message) return;
7653
8349
  try {
@@ -7662,15 +8358,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7662
8358
  dispatch({ kind: "STOP" });
7663
8359
  }
7664
8360
  }, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
7665
- (0, import_react42.useEffect)(() => {
8361
+ (0, import_react46.useEffect)(() => {
7666
8362
  if (greetedRef.current) return;
7667
8363
  greetedRef.current = true;
7668
8364
  fireGreeting();
7669
8365
  }, [fireGreeting]);
7670
- (0, import_react42.useEffect)(() => {
8366
+ (0, import_react46.useEffect)(() => {
7671
8367
  if (boot.stale && storageKey) clearConversation(storageKey);
7672
8368
  }, []);
7673
- (0, import_react42.useEffect)(() => {
8369
+ (0, import_react46.useEffect)(() => {
7674
8370
  if (!storageKey || state.isStreaming) return;
7675
8371
  if (hydratedRef.current) {
7676
8372
  hydratedRef.current = false;
@@ -7687,7 +8383,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7687
8383
  if (persistable.length === 0) return;
7688
8384
  writeConversation(storageKey, state.conversationId, persistable, Date.now());
7689
8385
  }, [storageKey, state.isStreaming, state.messages, state.conversationId]);
7690
- (0, import_react42.useEffect)(() => {
8386
+ (0, import_react46.useEffect)(() => {
7691
8387
  if (!storageKey) return;
7692
8388
  const onStorage = (e) => {
7693
8389
  if (e.key !== storageKey || e.storageArea !== window.localStorage) return;
@@ -7711,25 +8407,25 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7711
8407
  window.addEventListener("storage", onStorage);
7712
8408
  return () => window.removeEventListener("storage", onStorage);
7713
8409
  }, [storageKey, conversation, fireGreeting]);
7714
- const open = (0, import_react42.useCallback)(() => dispatch({ kind: "OPEN" }), []);
7715
- const close = (0, import_react42.useCallback)(() => {
8410
+ const open = (0, import_react46.useCallback)(() => dispatch({ kind: "OPEN" }), []);
8411
+ const close = (0, import_react46.useCallback)(() => {
7716
8412
  handleRef.current?.cancel();
7717
8413
  handleRef.current = null;
7718
8414
  clearFallbackTimer();
7719
8415
  dispatch({ kind: "CLOSE" });
7720
8416
  }, [clearFallbackTimer]);
7721
- const stop = (0, import_react42.useCallback)(() => {
8417
+ const stop = (0, import_react46.useCallback)(() => {
7722
8418
  handleRef.current?.cancel();
7723
8419
  handleRef.current = null;
7724
8420
  clearFallbackTimer();
7725
8421
  dispatch({ kind: "STOP" });
7726
8422
  }, [clearFallbackTimer]);
7727
- const toggle = (0, import_react42.useCallback)(() => {
8423
+ const toggle = (0, import_react46.useCallback)(() => {
7728
8424
  if (stateRef.current.isOpen) close();
7729
8425
  else open();
7730
8426
  }, [close, open]);
7731
- const dismissPopup = (0, import_react42.useCallback)(() => dispatch({ kind: "DISMISS_POPUP" }), []);
7732
- const reset = (0, import_react42.useCallback)(() => {
8427
+ const dismissPopup = (0, import_react46.useCallback)(() => dispatch({ kind: "DISMISS_POPUP" }), []);
8428
+ const reset = (0, import_react46.useCallback)(() => {
7733
8429
  handleRef.current?.cancel();
7734
8430
  handleRef.current = null;
7735
8431
  clearFallbackTimer();
@@ -7740,18 +8436,18 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
7740
8436
  greetedRef.current = true;
7741
8437
  fireGreeting();
7742
8438
  }, [storageKey, conversation, clearFallbackTimer, fireGreeting]);
7743
- const getLiveDashboard = (0, import_react42.useCallback)(() => conversation.getLiveDashboard(), [conversation]);
8439
+ const getLiveDashboard = (0, import_react46.useCallback)(() => conversation.getLiveDashboard(), [conversation]);
7744
8440
  useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard });
7745
- return { state, open, close, stop, toggle, send, retry, dismissPopup, reset };
8441
+ return { state, open, close, stop, toggle, send, retry, dismissPopup, reset, _dispatch: dispatch };
7746
8442
  }
7747
8443
 
7748
8444
  // src/useLiveMonitor.ts
7749
- var import_react44 = require("react");
8445
+ var import_react48 = require("react");
7750
8446
 
7751
8447
  // src/useTabs.ts
7752
- var import_react43 = require("react");
8448
+ var import_react47 = require("react");
7753
8449
  function useTabs(initial = "chat") {
7754
- const [activeTab, setActiveTab] = (0, import_react43.useState)(initial);
8450
+ const [activeTab, setActiveTab] = (0, import_react47.useState)(initial);
7755
8451
  return { activeTab, setActiveTab };
7756
8452
  }
7757
8453
 
@@ -7759,6 +8455,7 @@ function useTabs(initial = "chat") {
7759
8455
  var GOAL_OR_RED = /* @__PURE__ */ new Set(["goal", "red"]);
7760
8456
  var MIN_POLL_MS = 5e3;
7761
8457
  var DEFAULT_POLL_MS = 6e4;
8458
+ var LIVE_WATCH_POLL_MS = 12e3;
7762
8459
  function eventIdentity(e) {
7763
8460
  return `${e.type}:${e.side}:${e.minuteLabel}:${e.player ?? ""}`;
7764
8461
  }
@@ -7775,36 +8472,38 @@ function phaseForPin(snapshot, pin) {
7775
8472
  return snapshot.markets.find((mk) => mk.key === pin.key)?.phase;
7776
8473
  }
7777
8474
  function useLiveMonitor(opts) {
7778
- const sessionIdRef = (0, import_react44.useRef)(crypto.randomUUID());
7779
- const [pins, setPins] = (0, import_react44.useState)([]);
7780
- const [store] = (0, import_react44.useState)(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins));
7781
- const [enabled, setEnabled] = (0, import_react44.useState)(true);
7782
- const [snapshot, setSnapshotState] = (0, import_react44.useState)(null);
8475
+ const sessionIdRef = (0, import_react48.useRef)(crypto.randomUUID());
8476
+ const [pins, setPins] = (0, import_react48.useState)([]);
8477
+ const [store] = (0, import_react48.useState)(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins));
8478
+ const [enabled, setEnabled] = (0, import_react48.useState)(true);
8479
+ const [snapshot, setSnapshotState] = (0, import_react48.useState)(null);
7783
8480
  const { activeTab, setActiveTab: setActiveTabState } = useTabs("chat");
7784
- const [chatDot, setChatDot] = (0, import_react44.useState)(false);
7785
- const [matchesDot, setMatchesDot] = (0, import_react44.useState)(false);
7786
- const [oddsDot, setOddsDot] = (0, import_react44.useState)(false);
7787
- const [todayDot, setTodayDot] = (0, import_react44.useState)(false);
7788
- const [lastViewedPrices, setLastViewedPrices] = (0, import_react44.useState)({});
7789
- const [openMarket, setOpenMarket] = (0, import_react44.useState)({});
7790
- const [marketOdds, setMarketOdds] = (0, import_react44.useState)({});
7791
- const pinsRef = (0, import_react44.useRef)(pins);
8481
+ const [chatDot, setChatDot] = (0, import_react48.useState)(false);
8482
+ const [matchesDot, setMatchesDot] = (0, import_react48.useState)(false);
8483
+ const [oddsDot, setOddsDot] = (0, import_react48.useState)(false);
8484
+ const [todayDot, setTodayDot] = (0, import_react48.useState)(false);
8485
+ const [lastViewedPrices, setLastViewedPrices] = (0, import_react48.useState)({});
8486
+ const [openMarket, setOpenMarket] = (0, import_react48.useState)({});
8487
+ const [marketOdds, setMarketOdds] = (0, import_react48.useState)({});
8488
+ const pinsRef = (0, import_react48.useRef)(pins);
7792
8489
  pinsRef.current = pins;
7793
- const activeTabRef = (0, import_react44.useRef)(activeTab);
8490
+ const watchesRef = (0, import_react48.useRef)(opts.watches ?? []);
8491
+ watchesRef.current = opts.watches ?? [];
8492
+ const activeTabRef = (0, import_react48.useRef)(activeTab);
7794
8493
  activeTabRef.current = activeTab;
7795
- const snapshotRef = (0, import_react44.useRef)(snapshot);
8494
+ const snapshotRef = (0, import_react48.useRef)(snapshot);
7796
8495
  snapshotRef.current = snapshot;
7797
- const lastViewedPricesRef = (0, import_react44.useRef)(lastViewedPrices);
8496
+ const lastViewedPricesRef = (0, import_react48.useRef)(lastViewedPrices);
7798
8497
  lastViewedPricesRef.current = lastViewedPrices;
7799
- const openMarketRef = (0, import_react44.useRef)(openMarket);
8498
+ const openMarketRef = (0, import_react48.useRef)(openMarket);
7800
8499
  openMarketRef.current = openMarket;
7801
- const marketOddsRef = (0, import_react44.useRef)(marketOdds);
8500
+ const marketOddsRef = (0, import_react48.useRef)(marketOdds);
7802
8501
  marketOddsRef.current = marketOdds;
7803
8502
  const hasToday = opts.hasToday ?? false;
7804
8503
  const marketKey = (matchId, dev) => `${matchId}:${dev}`;
7805
- const getMarketOddsRef = (0, import_react44.useRef)(opts.getMarketOdds);
8504
+ const getMarketOddsRef = (0, import_react48.useRef)(opts.getMarketOdds);
7806
8505
  getMarketOddsRef.current = opts.getMarketOdds;
7807
- const fetchMarket = (0, import_react44.useCallback)((matchId, dev) => {
8506
+ const fetchMarket = (0, import_react48.useCallback)((matchId, dev) => {
7808
8507
  const key = marketKey(matchId, dev);
7809
8508
  const existing = marketOddsRef.current[key];
7810
8509
  if (existing?.loading) return;
@@ -7823,7 +8522,7 @@ function useLiveMonitor(opts) {
7823
8522
  setMarketOdds((prev) => ({ ...prev, [key]: entry }));
7824
8523
  });
7825
8524
  }, []);
7826
- const toggleMarket = (0, import_react44.useCallback)((matchId, dev) => {
8525
+ const toggleMarket = (0, import_react48.useCallback)((matchId, dev) => {
7827
8526
  const key = marketKey(matchId, dev);
7828
8527
  const wasOpen = openMarketRef.current[matchId] === dev;
7829
8528
  const nextValue = wasOpen ? null : dev;
@@ -7834,10 +8533,10 @@ function useLiveMonitor(opts) {
7834
8533
  fetchMarket(matchId, dev);
7835
8534
  }
7836
8535
  }, [fetchMarket]);
7837
- const retryMarket = (0, import_react44.useCallback)((matchId, dev) => {
8536
+ const retryMarket = (0, import_react48.useCallback)((matchId, dev) => {
7838
8537
  fetchMarket(matchId, dev);
7839
8538
  }, [fetchMarket]);
7840
- const applySnapshot = (0, import_react44.useCallback)((next) => {
8539
+ const applySnapshot = (0, import_react48.useCallback)((next) => {
7841
8540
  if (next === null) {
7842
8541
  setEnabled(false);
7843
8542
  return;
@@ -7900,17 +8599,18 @@ function useLiveMonitor(opts) {
7900
8599
  snapshotRef.current = next;
7901
8600
  setSnapshotState(next);
7902
8601
  }, [store]);
7903
- const inFlightRef = (0, import_react44.useRef)(false);
7904
- const timerRef = (0, import_react44.useRef)(void 0);
7905
- const disabledRef = (0, import_react44.useRef)(false);
7906
- const mountedRef = (0, import_react44.useRef)(false);
7907
- const getLiveMonitorRef = (0, import_react44.useRef)(opts.getLiveMonitor);
8602
+ const inFlightRef = (0, import_react48.useRef)(false);
8603
+ const timerRef = (0, import_react48.useRef)(void 0);
8604
+ const disabledRef = (0, import_react48.useRef)(false);
8605
+ const mountedRef = (0, import_react48.useRef)(false);
8606
+ const getLiveMonitorRef = (0, import_react48.useRef)(opts.getLiveMonitor);
7908
8607
  getLiveMonitorRef.current = opts.getLiveMonitor;
7909
- const tick = (0, import_react44.useCallback)(async () => {
7910
- if (inFlightRef.current || disabledRef.current || pinsRef.current.length === 0) return;
8608
+ const tick = (0, import_react48.useCallback)(async () => {
8609
+ const allPins = [...pinsRef.current, ...watchesRef.current];
8610
+ if (inFlightRef.current || disabledRef.current || allPins.length === 0) return;
7911
8611
  inFlightRef.current = true;
7912
8612
  try {
7913
- const snap = await getLiveMonitorRef.current(pinsRef.current);
8613
+ const snap = await getLiveMonitorRef.current(allPins);
7914
8614
  if (!mountedRef.current) return;
7915
8615
  if (snap === null) {
7916
8616
  disabledRef.current = true;
@@ -7929,44 +8629,53 @@ function useLiveMonitor(opts) {
7929
8629
  scheduleRef.current();
7930
8630
  }
7931
8631
  }, [applySnapshot, fetchMarket]);
7932
- const scheduleRef = (0, import_react44.useRef)(() => {
8632
+ const scheduleRef = (0, import_react48.useRef)(() => {
7933
8633
  });
7934
8634
  scheduleRef.current = () => {
7935
8635
  window.clearTimeout(timerRef.current);
7936
- if (!mountedRef.current || disabledRef.current || pinsRef.current.length === 0 || document.visibilityState === "hidden") return;
7937
- const hinted = (snapshotRef.current?.nextPollSeconds ?? DEFAULT_POLL_MS / 1e3) * 1e3;
8636
+ const hasWork = pinsRef.current.length > 0 || watchesRef.current.length > 0;
8637
+ if (!mountedRef.current || disabledRef.current || !hasWork || document.visibilityState === "hidden") return;
8638
+ const fallbackMs = watchesRef.current.length > 0 ? LIVE_WATCH_POLL_MS : DEFAULT_POLL_MS;
8639
+ const hinted = snapshotRef.current ? snapshotRef.current.nextPollSeconds * 1e3 : fallbackMs;
7938
8640
  timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted));
7939
8641
  };
7940
- (0, import_react44.useEffect)(() => {
8642
+ (0, import_react48.useEffect)(() => {
7941
8643
  mountedRef.current = true;
7942
8644
  return () => {
7943
8645
  mountedRef.current = false;
7944
8646
  };
7945
8647
  }, []);
7946
- const prevPinsLengthRef = (0, import_react44.useRef)(0);
7947
- (0, import_react44.useEffect)(() => {
7948
- const wasEmpty = prevPinsLengthRef.current === 0;
8648
+ const prevPinsLengthRef = (0, import_react48.useRef)(0);
8649
+ (0, import_react48.useEffect)(() => {
8650
+ const wasEmpty = prevPinsLengthRef.current === 0 && watchesRef.current.length === 0;
7949
8651
  prevPinsLengthRef.current = pins.length;
7950
- if (pins.length === 0) {
8652
+ if (pins.length === 0 && watchesRef.current.length === 0) {
7951
8653
  window.clearTimeout(timerRef.current);
7952
8654
  return;
7953
8655
  }
7954
8656
  if (wasEmpty) void tick();
7955
8657
  }, [pins.length, tick]);
7956
- (0, import_react44.useEffect)(() => {
8658
+ const prevWatchesLengthRef = (0, import_react48.useRef)(0);
8659
+ const watchesLength = opts.watches?.length ?? 0;
8660
+ (0, import_react48.useEffect)(() => {
8661
+ const wasEmpty = prevWatchesLengthRef.current === 0 && pinsRef.current.length === 0;
8662
+ prevWatchesLengthRef.current = watchesLength;
8663
+ if (wasEmpty && watchesLength > 0) void tick();
8664
+ }, [watchesLength, tick]);
8665
+ (0, import_react48.useEffect)(() => {
7957
8666
  const matchPins = pins.filter((p) => p.kind === "match").length;
7958
8667
  const marketPins = pins.length - matchPins;
7959
8668
  if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
7960
8669
  if (activeTab === "odds" && marketPins === 0) setActiveTabState(hasToday ? "today" : "chat");
7961
8670
  if (activeTab === "today" && !hasToday) setActiveTabState("chat");
7962
8671
  }, [pins, activeTab, hasToday]);
7963
- const prevIsOpenRef = (0, import_react44.useRef)(false);
7964
- (0, import_react44.useEffect)(() => {
8672
+ const prevIsOpenRef = (0, import_react48.useRef)(false);
8673
+ (0, import_react48.useEffect)(() => {
7965
8674
  const wasClosed = !prevIsOpenRef.current;
7966
8675
  prevIsOpenRef.current = opts.isOpen;
7967
8676
  if (wasClosed && opts.isOpen) void tick();
7968
8677
  }, [opts.isOpen, tick]);
7969
- (0, import_react44.useEffect)(() => {
8678
+ (0, import_react48.useEffect)(() => {
7970
8679
  const onVisibility = () => {
7971
8680
  if (document.visibilityState === "hidden") window.clearTimeout(timerRef.current);
7972
8681
  else void tick();
@@ -7977,7 +8686,7 @@ function useLiveMonitor(opts) {
7977
8686
  window.clearTimeout(timerRef.current);
7978
8687
  };
7979
8688
  }, [tick]);
7980
- const setActiveTab = (0, import_react44.useCallback)((tab) => {
8689
+ const setActiveTab = (0, import_react48.useCallback)((tab) => {
7981
8690
  setActiveTabState(tab);
7982
8691
  if (tab === "chat") setChatDot(false);
7983
8692
  if (tab === "today") setTodayDot(false);
@@ -7998,14 +8707,14 @@ function useLiveMonitor(opts) {
7998
8707
  void tick();
7999
8708
  }
8000
8709
  }, [tick]);
8001
- const togglePin = (0, import_react44.useCallback)((pin) => {
8710
+ const togglePin = (0, import_react48.useCallback)((pin) => {
8002
8711
  const result = store.toggle(pin);
8003
8712
  pinsRef.current = store.pins;
8004
8713
  return result;
8005
8714
  }, [store]);
8006
- const isPinned = (0, import_react44.useCallback)((key) => pinsRef.current.some((p) => p.key === key), []);
8007
- const markChatActivity = (0, import_react44.useCallback)(() => setChatDot(true), []);
8008
- const markTodayActivity = (0, import_react44.useCallback)(() => {
8715
+ const isPinned = (0, import_react48.useCallback)((key) => pinsRef.current.some((p) => p.key === key), []);
8716
+ const markChatActivity = (0, import_react48.useCallback)(() => setChatDot(true), []);
8717
+ const markTodayActivity = (0, import_react48.useCallback)(() => {
8009
8718
  if (activeTabRef.current !== "today") setTodayDot(true);
8010
8719
  }, []);
8011
8720
  return {
@@ -8032,7 +8741,7 @@ function useLiveMonitor(opts) {
8032
8741
  }
8033
8742
 
8034
8743
  // src/useMatchDiscovery.ts
8035
- var import_react45 = require("react");
8744
+ var import_react49 = require("react");
8036
8745
 
8037
8746
  // src/scheduleCache.ts
8038
8747
  var PREFIX = "ss-w-schedule:";
@@ -8120,27 +8829,27 @@ function localDateOf(now) {
8120
8829
  return `${y}-${m}-${d}`;
8121
8830
  }
8122
8831
  function useMatchDiscovery(opts) {
8123
- const [groups, setGroups] = (0, import_react45.useState)([]);
8124
- const [states, setStates] = (0, import_react45.useState)({});
8125
- const [failures, setFailures] = (0, import_react45.useState)(0);
8126
- const [expanded, setExpanded] = (0, import_react45.useState)({});
8127
- const [touched, setTouched] = (0, import_react45.useState)({});
8128
- const groupsRef = (0, import_react45.useRef)(groups);
8832
+ const [groups, setGroups] = (0, import_react49.useState)([]);
8833
+ const [states, setStates] = (0, import_react49.useState)({});
8834
+ const [failures, setFailures] = (0, import_react49.useState)(0);
8835
+ const [expanded, setExpanded] = (0, import_react49.useState)({});
8836
+ const [touched, setTouched] = (0, import_react49.useState)({});
8837
+ const groupsRef = (0, import_react49.useRef)(groups);
8129
8838
  groupsRef.current = groups;
8130
- const statesRef = (0, import_react45.useRef)(states);
8839
+ const statesRef = (0, import_react49.useRef)(states);
8131
8840
  statesRef.current = states;
8132
- const getStatesRef = (0, import_react45.useRef)(opts.getStates);
8841
+ const getStatesRef = (0, import_react49.useRef)(opts.getStates);
8133
8842
  getStatesRef.current = opts.getStates;
8134
8843
  const pinnedKey = opts.pinnedMatchIds.join(",");
8135
- const [localDate, setLocalDate] = (0, import_react45.useState)(() => localDateOf(/* @__PURE__ */ new Date()));
8136
- (0, import_react45.useEffect)(() => {
8844
+ const [localDate, setLocalDate] = (0, import_react49.useState)(() => localDateOf(/* @__PURE__ */ new Date()));
8845
+ (0, import_react49.useEffect)(() => {
8137
8846
  const id = setInterval(() => {
8138
8847
  const next = localDateOf(/* @__PURE__ */ new Date());
8139
8848
  setLocalDate((prev) => prev === next ? prev : next);
8140
8849
  }, ROLLOVER_CHECK_MS);
8141
8850
  return () => clearInterval(id);
8142
8851
  }, []);
8143
- (0, import_react45.useEffect)(() => {
8852
+ (0, import_react49.useEffect)(() => {
8144
8853
  let cancelled = false;
8145
8854
  const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
8146
8855
  const cached = readSchedule(opts.operatorId, localDate, Date.now());
@@ -8165,7 +8874,7 @@ function useMatchDiscovery(opts) {
8165
8874
  cancelled = true;
8166
8875
  };
8167
8876
  }, [opts.operatorId, localDate]);
8168
- (0, import_react45.useEffect)(() => {
8877
+ (0, import_react49.useEffect)(() => {
8169
8878
  setExpanded((prev) => {
8170
8879
  const next = {};
8171
8880
  for (const group of groups) {
@@ -8176,7 +8885,7 @@ function useMatchDiscovery(opts) {
8176
8885
  return next;
8177
8886
  });
8178
8887
  }, [groups, pinnedKey, touched]);
8179
- const tick = (0, import_react45.useCallback)(async () => {
8888
+ const tick = (0, import_react49.useCallback)(async () => {
8180
8889
  const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now());
8181
8890
  if (ids.length === 0) return;
8182
8891
  try {
@@ -8192,7 +8901,7 @@ function useMatchDiscovery(opts) {
8192
8901
  setFailures((n) => n + 1);
8193
8902
  }
8194
8903
  }, []);
8195
- (0, import_react45.useEffect)(() => {
8904
+ (0, import_react49.useEffect)(() => {
8196
8905
  if (!opts.isOpen) return;
8197
8906
  void tick();
8198
8907
  const id = setInterval(() => {
@@ -8201,11 +8910,11 @@ function useMatchDiscovery(opts) {
8201
8910
  return () => clearInterval(id);
8202
8911
  }, [opts.isOpen, tick, groups]);
8203
8912
  const stale = failures >= STALE_AFTER_FAILURES;
8204
- const liveCount = (0, import_react45.useMemo)(
8913
+ const liveCount = (0, import_react49.useMemo)(
8205
8914
  () => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
8206
8915
  [states, stale]
8207
8916
  );
8208
- const toggleGroup = (0, import_react45.useCallback)((competitionId) => {
8917
+ const toggleGroup = (0, import_react49.useCallback)((competitionId) => {
8209
8918
  setTouched((prev) => ({ ...prev, [competitionId]: true }));
8210
8919
  setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
8211
8920
  }, []);
@@ -8213,25 +8922,25 @@ function useMatchDiscovery(opts) {
8213
8922
  }
8214
8923
 
8215
8924
  // src/useGames.ts
8216
- var import_react46 = require("react");
8925
+ var import_react50 = require("react");
8217
8926
  var GAMES_POLL_MS = 6e4;
8218
8927
  var DEFAULT_TZ = "Europe/London";
8219
8928
  function computeGameDay(timezone) {
8220
8929
  return new Intl.DateTimeFormat("en-CA", { timeZone: timezone }).format(/* @__PURE__ */ new Date());
8221
8930
  }
8222
8931
  function useGames(conversation, { activeTab, operatorTimezone }) {
8223
- const [enabled, setEnabled] = (0, import_react46.useState)(false);
8224
- const [games, setGames] = (0, import_react46.useState)([]);
8225
- const [loading, setLoading] = (0, import_react46.useState)(false);
8226
- const [refreshCount, setRefreshCount] = (0, import_react46.useState)(0);
8227
- const inFlightRef = (0, import_react46.useRef)(false);
8228
- const hardOffRef = (0, import_react46.useRef)(false);
8229
- const conversationRef = (0, import_react46.useRef)(conversation);
8932
+ const [enabled, setEnabled] = (0, import_react50.useState)(false);
8933
+ const [games, setGames] = (0, import_react50.useState)([]);
8934
+ const [loading, setLoading] = (0, import_react50.useState)(false);
8935
+ const [refreshCount, setRefreshCount] = (0, import_react50.useState)(0);
8936
+ const inFlightRef = (0, import_react50.useRef)(false);
8937
+ const hardOffRef = (0, import_react50.useRef)(false);
8938
+ const conversationRef = (0, import_react50.useRef)(conversation);
8230
8939
  conversationRef.current = conversation;
8231
- const tzRef = (0, import_react46.useRef)(operatorTimezone ?? DEFAULT_TZ);
8940
+ const tzRef = (0, import_react50.useRef)(operatorTimezone ?? DEFAULT_TZ);
8232
8941
  tzRef.current = operatorTimezone ?? DEFAULT_TZ;
8233
8942
  const ready = conversation != null;
8234
- (0, import_react46.useEffect)(() => {
8943
+ (0, import_react50.useEffect)(() => {
8235
8944
  if (hardOffRef.current) return;
8236
8945
  let active = true;
8237
8946
  const doFetch = async () => {
@@ -8274,22 +8983,22 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
8274
8983
  if (intervalId !== void 0) window.clearInterval(intervalId);
8275
8984
  };
8276
8985
  }, [activeTab, refreshCount, ready]);
8277
- const refresh = (0, import_react46.useCallback)(() => {
8986
+ const refresh = (0, import_react50.useCallback)(() => {
8278
8987
  setRefreshCount((c) => c + 1);
8279
8988
  }, []);
8280
8989
  return { enabled, games, loading, refresh };
8281
8990
  }
8282
8991
 
8283
8992
  // src/useLeaderboard.ts
8284
- var import_react47 = require("react");
8993
+ var import_react51 = require("react");
8285
8994
  function useLeaderboard(conversation, { activeTab }) {
8286
- const [data, setData] = (0, import_react47.useState)(null);
8287
- const [loading, setLoading] = (0, import_react47.useState)(false);
8288
- const [refreshCount, setRefreshCount] = (0, import_react47.useState)(0);
8289
- const inFlightRef = (0, import_react47.useRef)(false);
8290
- const conversationRef = (0, import_react47.useRef)(conversation);
8995
+ const [data, setData] = (0, import_react51.useState)(null);
8996
+ const [loading, setLoading] = (0, import_react51.useState)(false);
8997
+ const [refreshCount, setRefreshCount] = (0, import_react51.useState)(0);
8998
+ const inFlightRef = (0, import_react51.useRef)(false);
8999
+ const conversationRef = (0, import_react51.useRef)(conversation);
8291
9000
  conversationRef.current = conversation;
8292
- (0, import_react47.useEffect)(() => {
9001
+ (0, import_react51.useEffect)(() => {
8293
9002
  if (activeTab !== "leaderboard" && activeTab !== "games") return;
8294
9003
  let active = true;
8295
9004
  const doFetch = async () => {
@@ -8312,18 +9021,65 @@ function useLeaderboard(conversation, { activeTab }) {
8312
9021
  inFlightRef.current = false;
8313
9022
  };
8314
9023
  }, [activeTab, refreshCount]);
8315
- const refresh = (0, import_react47.useCallback)(() => {
9024
+ const refresh = (0, import_react51.useCallback)(() => {
8316
9025
  setRefreshCount((c) => c + 1);
8317
9026
  }, []);
8318
9027
  return { data, loading, refresh };
8319
9028
  }
8320
9029
 
9030
+ // src/usePresetGrid.ts
9031
+ var import_react52 = require("react");
9032
+ var GRID_MAX_AGE_MS = 6e5;
9033
+ function usePresetGrid({ getPricePresets, isOpen, locale, now = Date.now }) {
9034
+ const [grid, setGrid] = (0, import_react52.useState)(null);
9035
+ const keptRef = (0, import_react52.useRef)(null);
9036
+ const localeRef = (0, import_react52.useRef)(locale);
9037
+ const inFlightRef = (0, import_react52.useRef)(false);
9038
+ const mountedRef = (0, import_react52.useRef)(true);
9039
+ const getRef = (0, import_react52.useRef)(getPricePresets);
9040
+ getRef.current = getPricePresets;
9041
+ const nowRef = (0, import_react52.useRef)(now);
9042
+ nowRef.current = now;
9043
+ (0, import_react52.useEffect)(() => {
9044
+ mountedRef.current = true;
9045
+ return () => {
9046
+ mountedRef.current = false;
9047
+ };
9048
+ }, []);
9049
+ (0, import_react52.useEffect)(() => {
9050
+ if (localeRef.current !== locale) {
9051
+ localeRef.current = locale;
9052
+ keptRef.current = null;
9053
+ setGrid(null);
9054
+ }
9055
+ if (!isOpen || inFlightRef.current) return;
9056
+ const kept = keptRef.current;
9057
+ const age = kept ? nowRef.current() - Date.parse(kept.builtAtUtc) : Number.NaN;
9058
+ if (age <= GRID_MAX_AGE_MS) return;
9059
+ inFlightRef.current = true;
9060
+ Promise.resolve().then(() => getRef.current(locale)).then((body) => {
9061
+ if (body === null) {
9062
+ keptRef.current = null;
9063
+ if (mountedRef.current) setGrid(null);
9064
+ return;
9065
+ }
9066
+ if (!isPresetGrid(body)) return;
9067
+ keptRef.current = body;
9068
+ if (mountedRef.current) setGrid(body);
9069
+ }).catch(() => {
9070
+ }).finally(() => {
9071
+ inFlightRef.current = false;
9072
+ });
9073
+ }, [isOpen, locale]);
9074
+ return grid;
9075
+ }
9076
+
8321
9077
  // src/popupTelemetry.ts
8322
- var import_react48 = require("react");
9078
+ var import_react53 = require("react");
8323
9079
  function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
8324
- const shownRef = (0, import_react48.useRef)(/* @__PURE__ */ new Set());
8325
- const closedTextRef = (0, import_react48.useRef)(null);
8326
- (0, import_react48.useEffect)(() => {
9080
+ const shownRef = (0, import_react53.useRef)(/* @__PURE__ */ new Set());
9081
+ const closedTextRef = (0, import_react53.useRef)(null);
9082
+ (0, import_react53.useEffect)(() => {
8327
9083
  if (isOpen) {
8328
9084
  if (closedTextRef.current) log?.log({ name: "popup_opened" });
8329
9085
  closedTextRef.current = null;
@@ -8335,65 +9091,65 @@ function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
8335
9091
  log?.log({ name: "popup_shown" });
8336
9092
  }
8337
9093
  }, [log, isOpen, popupText]);
8338
- return (0, import_react48.useCallback)(() => {
9094
+ return (0, import_react53.useCallback)(() => {
8339
9095
  log?.log({ name: "popup_dismissed" });
8340
9096
  dismissPopup();
8341
9097
  }, [log, dismissPopup]);
8342
9098
  }
8343
9099
 
8344
9100
  // src/components/ChatFab.tsx
8345
- var import_react49 = require("react");
9101
+ var import_react54 = require("react");
8346
9102
 
8347
9103
  // src/components/GreetingBubble.tsx
8348
- var import_jsx_runtime89 = require("react/jsx-runtime");
9104
+ var import_jsx_runtime91 = require("react/jsx-runtime");
8349
9105
  function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss", asks }) {
8350
- const body = /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
8351
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
8352
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", {}),
8353
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", {}),
8354
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", {})
9106
+ const body = /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
9107
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
9108
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", {}),
9109
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", {}),
9110
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", {})
8355
9111
  ] }),
8356
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "ss-w-greeting-text", children: text })
9112
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "ss-w-greeting-text", children: text })
8357
9113
  ] });
8358
- const dismiss = onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null;
9114
+ const dismiss = onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null;
8359
9115
  if (!asks || asks.length === 0) {
8360
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-greeting", role: "note", children: [
9116
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "ss-w-greeting", role: "note", children: [
8361
9117
  body,
8362
9118
  dismiss
8363
9119
  ] });
8364
9120
  }
8365
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-greeting ss-w-greeting--asks", role: "note", children: [
8366
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "ss-w-greeting-top", children: [
9121
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "ss-w-greeting ss-w-greeting--asks", role: "note", children: [
9122
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "ss-w-greeting-top", children: [
8367
9123
  body,
8368
9124
  dismiss
8369
9125
  ] }),
8370
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "ss-w-greeting-asks", children: asks.map((ask, i) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("button", { type: "button", className: "ss-w-greeting-ask", onClick: ask.onTap, children: ask.label }, `${i}:${ask.label}`)) })
9126
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("div", { className: "ss-w-greeting-asks", children: asks.map((ask, i) => /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("button", { type: "button", className: "ss-w-greeting-ask", onClick: ask.onTap, children: ask.label }, `${i}:${ask.label}`)) })
8371
9127
  ] });
8372
9128
  }
8373
9129
 
8374
9130
  // src/components/ChatFab.tsx
8375
- var import_jsx_runtime90 = require("react/jsx-runtime");
9131
+ var import_jsx_runtime92 = require("react/jsx-runtime");
8376
9132
  function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart, asks }) {
8377
9133
  const bubble = popupText ?? greeting;
8378
- const [intro, setIntro] = (0, import_react49.useState)(false);
8379
- const armedRef = (0, import_react49.useRef)(introAllowed);
8380
- (0, import_react49.useEffect)(() => {
9134
+ const [intro, setIntro] = (0, import_react54.useState)(false);
9135
+ const armedRef = (0, import_react54.useRef)(introAllowed);
9136
+ (0, import_react54.useEffect)(() => {
8381
9137
  if (armedRef.current && bubble) {
8382
9138
  armedRef.current = false;
8383
9139
  setIntro(true);
8384
9140
  onIntroStart?.();
8385
9141
  }
8386
9142
  }, [bubble, onIntroStart]);
8387
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
8388
- bubble ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel, asks: popupText ? asks : void 0 }) : null,
8389
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
9143
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
9144
+ bubble ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel, asks: popupText ? asks : void 0 }) : null,
9145
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
8390
9146
  ] });
8391
9147
  }
8392
9148
 
8393
9149
  // src/components/HostEventsProvider.tsx
8394
- var import_jsx_runtime91 = require("react/jsx-runtime");
9150
+ var import_jsx_runtime93 = require("react/jsx-runtime");
8395
9151
  function HostEventsProvider({ value, children }) {
8396
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(SlipStateContext.Provider, { value: value.slipState, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(MatchLinkContext.Provider, { value: value.matchLink, children }) });
9152
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(SlipStateContext.Provider, { value: value.slipState, children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(MatchLinkContext.Provider, { value: value.matchLink, children }) });
8397
9153
  }
8398
9154
 
8399
9155
  // src/styles/css.generated.ts
@@ -8789,6 +9545,12 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
8789
9545
  .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; }
8790
9546
  .ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }
8791
9547
  .ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
9548
+ /* Stage 4: live card score+minute in header (R18). */
9549
+ .ss-w-bi-score { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); white-space: nowrap; }
9550
+ .ss-w-bi-min { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; }
9551
+ /* D12: closed state message row; D13: stale-price notice. */
9552
+ .ss-w-mo-closed { padding: 6px 0; font-size: 12.5px; color: var(--ss-w-faint); }
9553
+ .ss-w-mo-stale { margin: 0; font-size: 11px; color: var(--ss-w-faint); }
8792
9554
  /* The card's stat, in the Live tab accordion's insight style. No row below it is marked (R17). */
8793
9555
  .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; }
8794
9556
  .ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
@@ -8824,6 +9586,71 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
8824
9586
  .ss-w-combo-leg-stat { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 9px; }
8825
9587
  .ss-w-combo-math { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; line-height: 1.4; color: var(--ss-w-ink); text-align: right; background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 8px 10px; overflow-wrap: anywhere; }
8826
9588
  .ss-w-combo-note { font-size: 11px; line-height: 1.4; color: var(--ss-w-faint); }
9589
+ .ss-w-combo-change { align-self: flex-start; min-height: 36px; padding: 6px 12px; font: inherit; font-size: 12px; font-weight: 650; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; cursor: pointer; }
9590
+
9591
+ /* onboarding presets stage 2: the two tools (spec Stage 2 Behaviour, boards 1c and 2c). A sheet
9592
+ over the message list, inside .ss-w-chat-layer; the body scrolls and the builder's Send sits in
9593
+ the footer, so it stays visible on a phone. Colours come from the theme tokens. */
9594
+ .ss-w-tool-backdrop { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; justify-content: flex-end; background: rgba(0,0,0,.35); }
9595
+ .ss-w-tool { display: flex; flex-direction: column; min-height: 0; max-height: 100%; background: var(--ss-w-panel); color: var(--ss-w-ink); border-top: 1px solid var(--ss-w-line); border-radius: 16px 16px 0 0; box-shadow: 0 -8px 24px rgba(0,0,0,.18); outline: none; }
9596
+ .ss-w-tool-head { flex: none; display: flex; align-items: center; gap: 8px; padding: 12px 14px 8px; }
9597
+ .ss-w-tool-title { flex: 1; font-size: 15px; font-weight: 700; line-height: 1.3; }
9598
+ .ss-w-tool-close { flex: none; width: 36px; height: 36px; display: grid; place-items: center; font-size: 16px; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: none; border-radius: 50%; cursor: pointer; }
9599
+ .ss-w-tool-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 12px; padding: 4px 14px 14px; }
9600
+ .ss-w-tool-body > * { flex: none; }
9601
+ .ss-w-tool-foot { flex: none; padding: 10px 14px 12px; border-top: 1px solid var(--ss-w-line); }
9602
+ .ss-w-tool-row { display: flex; flex-direction: column; gap: 8px; padding: 10px 11px; border: 1px solid var(--ss-w-line); border-left: 3px solid var(--ss-w-accent); border-radius: 12px; }
9603
+ .ss-w-tool-ask { font-size: 14px; font-weight: 650; line-height: 1.7; color: var(--ss-w-ink); overflow-wrap: anywhere; }
9604
+ .ss-w-tool-num { display: inline-block; min-width: 44px; min-height: 32px; margin: 0 2px; padding: 3px 8px; font: inherit; font-variant-numeric: tabular-nums; font-weight: 800; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 55%, var(--ss-w-line)); border-radius: 8px; cursor: pointer; }
9605
+ .ss-w-tool-picks { list-style: none; display: flex; flex-direction: column; gap: 4px; }
9606
+ .ss-w-tool-pick { display: grid; grid-template-columns: 1fr auto; column-gap: 8px; padding: 5px 8px; font-size: 12px; line-height: 1.35; background: var(--ss-w-bubble); border-radius: 8px; }
9607
+ .ss-w-tool-pick-match { grid-column: 1; font-weight: 650; color: var(--ss-w-ink); overflow-wrap: anywhere; }
9608
+ .ss-w-tool-pick-sel { grid-column: 1; color: var(--ss-w-faint); overflow-wrap: anywhere; }
9609
+ .ss-w-tool-pick-kick { grid-column: 1; font-size: 11px; color: var(--ss-w-faint); }
9610
+ .ss-w-tool-pick-price { grid-column: 2; grid-row: 1 / span 3; align-self: center; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 800; color: var(--ss-w-accent); }
9611
+ .ss-w-tool-math { padding: 6px 8px; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 700; text-align: right; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; overflow-wrap: anywhere; }
9612
+ .ss-w-tool-unavailable { padding: 6px 8px; font-size: 12px; color: var(--ss-w-faint); border: 1px dashed var(--ss-w-line); border-radius: 8px; }
9613
+ .ss-w-tool-send { align-self: flex-end; min-height: 40px; padding: 8px 18px; font: inherit; font-size: 13px; font-weight: 700; color: #fff; background: var(--ss-w-accent); border: none; border-radius: 20px; cursor: pointer; }
9614
+ .ss-w-tool-send:disabled { color: var(--ss-w-faint); background: var(--ss-w-bubble); cursor: not-allowed; }
9615
+ .ss-w-tool-foot .ss-w-tool-send { width: 100%; }
9616
+ .ss-w-tool-section { display: flex; flex-direction: column; gap: 6px; }
9617
+ .ss-w-tool-label { font-size: 11.5px; font-weight: 650; color: var(--ss-w-faint); }
9618
+ .ss-w-tool-chips { display: flex; flex-wrap: wrap; gap: 6px; }
9619
+ .ss-w-tool-chip { min-width: 52px; min-height: 36px; padding: 6px 10px; font: inherit; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ss-w-ink); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 18px; cursor: pointer; }
9620
+ .ss-w-tool-chip[aria-pressed="true"] { color: #fff; background: var(--ss-w-accent); border-color: var(--ss-w-accent); }
9621
+ .ss-w-tool-stepper { display: inline-flex; align-items: center; gap: 10px; }
9622
+ .ss-w-tool-step { width: 40px; height: 40px; display: grid; place-items: center; font: inherit; font-size: 18px; font-weight: 700; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 50%; cursor: pointer; }
9623
+ .ss-w-tool-step:disabled { opacity: .5; cursor: not-allowed; }
9624
+ .ss-w-tool-count { min-width: 24px; text-align: center; font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; }
9625
+
9626
+ /* onboarding presets stage 2: the chat layer and the speed dial (spec Stage 2 Behaviour). The
9627
+ layer is the message list's positioned box (P6), so the dial sits against the list's bottom
9628
+ right and rises with the composer: right 8px puts the 44px button's centre on Send's (12px
9629
+ padding + 18px), bottom 10px is above the composer's top border. While the button shows the list
9630
+ gets 54px more bottom padding so its last message can scroll clear. */
9631
+ .ss-w-chat-layer { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
9632
+ .ss-w-chat-layer[data-dial] .ss-w-list { padding-bottom: 68px; }
9633
+ .ss-w-dial { position: absolute; left: 12px; right: 8px; bottom: 10px; z-index: 2; display: flex; flex-direction: column-reverse; align-items: flex-end; gap: 8px; pointer-events: none; }
9634
+ .ss-w-dial-btn, .ss-w-dial-pill { pointer-events: auto; }
9635
+ .ss-w-dial-btn { position: relative; flex: none; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; font-size: 20px; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-w-line)); border-radius: 50%; box-shadow: 0 4px 14px rgba(0,0,0,.18); cursor: pointer; }
9636
+ .ss-w-dial-btn[aria-expanded="true"] { color: var(--ss-w-panel); background: var(--ss-w-accent); border-color: var(--ss-w-accent); }
9637
+ .ss-w-dial-btn:focus-visible, .ss-w-dial-pill:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }
9638
+ .ss-w-dial-icon { grid-area: 1 / 1; display: grid; place-items: center; transition: transform 200ms ease, opacity 200ms ease; }
9639
+ .ss-w-dial-icon--close { opacity: 0; transform: rotate(-90deg); }
9640
+ .ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--open { opacity: 0; transform: rotate(90deg); }
9641
+ .ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--close { opacity: 1; transform: none; }
9642
+ .ss-w-dial-dot { position: absolute; top: 3px; right: 3px; width: 10px; height: 10px; background: var(--ss-w-accent); border: 2px solid var(--ss-w-panel); border-radius: 50%; }
9643
+ .ss-w-dial-pills { max-width: 100%; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
9644
+ .ss-w-dial-pill { max-width: 100%; min-height: 44px; display: inline-flex; align-items: center; gap: 8px; padding: 6px 16px 6px 12px; font: inherit; font-size: 12.5px; font-weight: 650; line-height: 1.25; text-align: left; white-space: normal; overflow-wrap: anywhere; color: var(--ss-w-ink); background: var(--ss-w-panel); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 35%, var(--ss-w-line)); border-radius: 22px; box-shadow: 0 4px 14px rgba(0,0,0,.16); cursor: pointer; opacity: 0; visibility: hidden; transform: translateY(14px) scale(.5); transform-origin: bottom right; transition: opacity 200ms ease, transform 200ms ease, visibility 0s linear 200ms; }
9645
+ .ss-w-dial-pill svg { flex: none; font-size: 18px; color: var(--ss-w-accent); }
9646
+ .ss-w-dial-pill-label { min-width: 0; }
9647
+ .ss-w-dial-pills[data-open] .ss-w-dial-pill { opacity: 1; visibility: visible; transform: none; transition: opacity 200ms ease, transform 200ms ease, visibility 0s; }
9648
+ @media (prefers-reduced-motion: reduce) {
9649
+ .ss-w-dial-pill { transform: none; transition: opacity 200ms ease, visibility 0s linear 200ms; }
9650
+ .ss-w-dial-pills[data-open] .ss-w-dial-pill { transition: opacity 200ms ease, visibility 0s; }
9651
+ .ss-w-dial-icon { transition: opacity 200ms ease; }
9652
+ .ss-w-dial-icon--close, .ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--open { transform: none; }
9653
+ }
8827
9654
 
8828
9655
  /* Compact price list (D16): three or more cards of one turn, one row per fixture. Team names wrap
8829
9656
  to a second line and are never cut; the time sits above the match pin, with no column of its own. */
@@ -8910,6 +9737,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
8910
9737
  .ss-w-textarea { font-size: 16px; }
8911
9738
  }
8912
9739
  .ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }
9740
+ .ss-w-send:disabled { opacity: .45; cursor: not-allowed; }
8913
9741
  .ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }
8914
9742
 
8915
9743
  /* add to slip */
@@ -9949,7 +10777,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
9949
10777
  `;
9950
10778
 
9951
10779
  // src/StatsWidget.tsx
9952
- var import_jsx_runtime92 = require("react/jsx-runtime");
10780
+ var import_jsx_runtime94 = require("react/jsx-runtime");
9953
10781
  function buildClient(props) {
9954
10782
  try {
9955
10783
  if ("client" in props && props.client) {
@@ -9974,39 +10802,54 @@ function injectStyles(root) {
9974
10802
  function StatsWidget(props) {
9975
10803
  const injectedClient = "client" in props ? props.client : void 0;
9976
10804
  const cfg = props.config;
9977
- const built = (0, import_react50.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
9978
- const logger = (0, import_react50.useMemo)(
10805
+ const built = (0, import_react55.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
10806
+ const logger = (0, import_react55.useMemo)(
9979
10807
  () => built ? built.client.createEventLogger({
9980
10808
  operatorUserId: cfg?.userContext?.operatorUserId,
9981
10809
  anonymousUserId: cfg?.userContext?.anonymousUserId
9982
10810
  }) : null,
9983
10811
  [built?.client]
9984
10812
  );
9985
- const ui = (0, import_react50.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
9986
- const rootRef = (0, import_react50.useRef)(null);
9987
- const introDoneRef = (0, import_react50.useRef)(false);
9988
- const markIntroDone = (0, import_react50.useCallback)(() => {
10813
+ const ui = (0, import_react55.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
10814
+ const rootRef = (0, import_react55.useRef)(null);
10815
+ const introDoneRef = (0, import_react55.useRef)(false);
10816
+ const markIntroDone = (0, import_react55.useCallback)(() => {
9989
10817
  introDoneRef.current = true;
9990
10818
  }, []);
9991
10819
  const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
9992
10820
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
9993
- const [hasToday, setHasToday] = (0, import_react50.useState)(false);
10821
+ const [hasToday, setHasToday] = (0, import_react55.useState)(false);
10822
+ const liveCardWatches = (0, import_react55.useMemo)(() => {
10823
+ const seen = /* @__PURE__ */ new Set();
10824
+ const out = [];
10825
+ for (const msg of controller.state.messages) {
10826
+ if (msg.role !== "assistant") continue;
10827
+ for (const vm of msg.marketOdds) {
10828
+ if (vm.live == null || seen.has(vm.matchId)) continue;
10829
+ seen.add(vm.matchId);
10830
+ out.push({ key: `live:card:${vm.matchId}`, kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName ?? "FULLTIME_RESULT" });
10831
+ }
10832
+ }
10833
+ return out;
10834
+ }, [controller.state.messages]);
10835
+ const locale = cfg?.locale;
9994
10836
  const monitor = useLiveMonitor({
9995
- getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
10837
+ getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins, locale) : Promise.resolve(null),
9996
10838
  getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
9997
10839
  storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
9998
10840
  isOpen: controller.state.isOpen,
9999
- hasToday
10841
+ hasToday,
10842
+ watches: liveCardWatches
10000
10843
  });
10001
- const getSchedule = (0, import_react50.useCallback)(
10844
+ const getSchedule = (0, import_react55.useCallback)(
10002
10845
  (localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
10003
10846
  [built]
10004
10847
  );
10005
- const getStates = (0, import_react50.useCallback)(
10848
+ const getStates = (0, import_react55.useCallback)(
10006
10849
  (matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
10007
10850
  [built]
10008
10851
  );
10009
- const pinnedMatchIds = (0, import_react50.useMemo)(
10852
+ const pinnedMatchIds = (0, import_react55.useMemo)(
10010
10853
  () => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
10011
10854
  [monitor.pins]
10012
10855
  );
@@ -10018,14 +10861,54 @@ function StatsWidget(props) {
10018
10861
  pinnedMatchIds
10019
10862
  });
10020
10863
  const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
10021
- (0, import_react50.useEffect)(() => {
10864
+ (0, import_react55.useEffect)(() => {
10022
10865
  setHasToday(todayHasContent);
10023
10866
  }, [todayHasContent]);
10867
+ const prevLiveSnapshotRef = (0, import_react55.useRef)(monitor.snapshot);
10868
+ (0, import_react55.useEffect)(() => {
10869
+ const snap = monitor.snapshot;
10870
+ if (!snap || snap === prevLiveSnapshotRef.current) return;
10871
+ prevLiveSnapshotRef.current = snap;
10872
+ for (const market of snap.markets) {
10873
+ if (!market.key.startsWith("live:card:")) continue;
10874
+ const matchId = parseInt(market.key.slice("live:card:".length), 10);
10875
+ if (!Number.isFinite(matchId)) continue;
10876
+ let mainRows = [];
10877
+ let moreRows = [];
10878
+ let addToSlipEnabled = false;
10879
+ if (market.card) {
10880
+ const updated = toMarketOddsVM(market.card);
10881
+ mainRows = updated.mainRows;
10882
+ moreRows = updated.moreRows;
10883
+ addToSlipEnabled = updated.addToSlipEnabled;
10884
+ }
10885
+ let closedReason = null;
10886
+ if (market.phase === "fullTime" || market.phase === "postponed") closedReason = "full_time";
10887
+ else if (market.isSuspended) closedReason = "suspended";
10888
+ else if (!market.card) closedReason = "no_live_price";
10889
+ const live = {
10890
+ phase: market.phase,
10891
+ homeScore: market.homeScore ?? null,
10892
+ awayScore: market.awayScore ?? null,
10893
+ minuteLabel: market.minuteLabel ?? null,
10894
+ isSuspended: market.isSuspended,
10895
+ isSettled: market.isSettled,
10896
+ asOfUtc: market.asOfUtc,
10897
+ closedReason
10898
+ };
10899
+ controller._dispatch?.({ kind: "UPDATE_LIVE_CARD", matchId, live, mainRows, moreRows, addToSlipEnabled });
10900
+ }
10901
+ }, [monitor.snapshot]);
10024
10902
  const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
10025
10903
  const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
10904
+ const getPricePresets = (0, import_react55.useCallback)(
10905
+ (locale2) => built ? built.conversation.getPricePresets(locale2) : Promise.resolve(null),
10906
+ [built]
10907
+ );
10908
+ const presetGrid = usePresetGrid({ getPricePresets, isOpen: controller.state.isOpen, locale: ui.presets.lang });
10026
10909
  const markTodayActivity = monitor.markTodayActivity;
10027
- const prevLiveCountRef = (0, import_react50.useRef)(0);
10028
- (0, import_react50.useEffect)(() => {
10910
+ const prevLiveCountRef = (0, import_react55.useRef)(0);
10911
+ (0, import_react55.useEffect)(() => {
10029
10912
  const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
10030
10913
  prevLiveCountRef.current = discovery.liveCount;
10031
10914
  if (rose) markTodayActivity();
@@ -10041,7 +10924,7 @@ function StatsWidget(props) {
10041
10924
  openMatchLabel: ui.openMatch
10042
10925
  });
10043
10926
  const markAdded = hostEvents.markAdded;
10044
- const slip = (0, import_react50.useMemo)(
10927
+ const slip = (0, import_react55.useMemo)(
10045
10928
  () => {
10046
10929
  const handler = props.config?.onAddToSlip;
10047
10930
  return {
@@ -10060,7 +10943,7 @@ function StatsWidget(props) {
10060
10943
  },
10061
10944
  [props.config?.onAddToSlip, controller.state.conversationId, markAdded]
10062
10945
  );
10063
- const onDashboardTap = (0, import_react50.useMemo)(
10946
+ const onDashboardTap = (0, import_react55.useMemo)(
10064
10947
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
10065
10948
  [built, logger]
10066
10949
  );
@@ -10078,11 +10961,11 @@ function StatsWidget(props) {
10078
10961
  const operatorUserId = cfg?.userContext?.operatorUserId;
10079
10962
  const anonymousUserId = cfg?.userContext?.anonymousUserId;
10080
10963
  const conversationId = controller.state.conversationId ?? void 0;
10081
- (0, import_react50.useEffect)(() => {
10964
+ (0, import_react55.useEffect)(() => {
10082
10965
  if (!logger) return;
10083
10966
  logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
10084
10967
  }, [logger, operatorUserId, anonymousUserId, conversationId]);
10085
- (0, import_react50.useEffect)(() => {
10968
+ (0, import_react55.useEffect)(() => {
10086
10969
  if (!logger) return;
10087
10970
  logger.resume();
10088
10971
  const onHide = () => {
@@ -10100,14 +10983,14 @@ function StatsWidget(props) {
10100
10983
  logger.dispose();
10101
10984
  };
10102
10985
  }, [logger]);
10103
- (0, import_react50.useEffect)(() => {
10986
+ (0, import_react55.useEffect)(() => {
10104
10987
  if (!built || !ui.injectStyles) return;
10105
10988
  const node = rootRef.current?.getRootNode();
10106
10989
  if (node) injectStyles(node);
10107
10990
  }, [built, ui.injectStyles]);
10108
10991
  if (!built) return null;
10109
10992
  const attrs = themeAttrs(ui);
10110
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(HostEventsProvider, { value: hostEvents, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
10993
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(HostEventsProvider, { value: hostEvents, children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
10111
10994
  ChatPanel,
10112
10995
  {
10113
10996
  controller,
@@ -10119,9 +11002,10 @@ function StatsWidget(props) {
10119
11002
  gamesResult,
10120
11003
  leaderboardResult,
10121
11004
  loggedIn: !!operatorUserId,
10122
- conversation: built?.conversation ?? null
11005
+ conversation: built?.conversation ?? null,
11006
+ presetGrid
10123
11007
  }
10124
- ) : /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
11008
+ ) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
10125
11009
  ChatFab,
10126
11010
  {
10127
11011
  label: ui.launcherLabel,