@sensiblestats/widget-react 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -36,7 +36,7 @@ __export(index_exports, {
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/StatsWidget.tsx
39
- var import_react22 = require("react");
39
+ var import_react23 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/kickoff.ts
@@ -120,7 +120,10 @@ var STRINGS = {
120
120
  fullTimeLabel: "Full time",
121
121
  inSlipLabel: "In slip",
122
122
  oddsUnavailable: "Odds unavailable right now",
123
- momentumLabel: "Momentum"
123
+ momentumLabel: "Momentum",
124
+ accordionValueLabel: "Value",
125
+ accordionRetry: "Couldn't load odds \u2014 tap to retry",
126
+ accordionSuspended: "Suspended"
124
127
  },
125
128
  tr: {
126
129
  launcherLabel: "SensibleStats ile sohbet et",
@@ -189,7 +192,10 @@ var STRINGS = {
189
192
  fullTimeLabel: "Ma\xE7 sonu",
190
193
  inSlipLabel: "Kuponda",
191
194
  oddsUnavailable: "Oranlar \u015Fu anda kullan\u0131lam\u0131yor",
192
- momentumLabel: "Momentum"
195
+ momentumLabel: "Momentum",
196
+ accordionValueLabel: "De\u011Fer",
197
+ accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
198
+ accordionSuspended: "Ask\u0131da"
193
199
  }
194
200
  };
195
201
  function resolveLocaleStrings(locale) {
@@ -207,6 +213,7 @@ function normalizeUi(cfg) {
207
213
  cta: cfg.cta,
208
214
  surface: cfg.surface,
209
215
  ink: cfg.ink,
216
+ pinIcon: cfg.pinIcon ?? "pin",
210
217
  position: cfg.position ?? "right",
211
218
  offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },
212
219
  radius: cfg.radius ?? 16,
@@ -276,7 +283,10 @@ function normalizeUi(cfg) {
276
283
  fullTimeLabel: strings.fullTimeLabel,
277
284
  inSlipLabel: strings.inSlipLabel,
278
285
  oddsUnavailable: strings.oddsUnavailable,
279
- momentumLabel: strings.momentumLabel
286
+ momentumLabel: strings.momentumLabel,
287
+ accordionValueLabel: strings.accordionValueLabel,
288
+ accordionRetry: strings.accordionRetry,
289
+ accordionSuspended: strings.accordionSuspended
280
290
  };
281
291
  }
282
292
  function toClientOptions(cfg) {
@@ -1030,6 +1040,8 @@ function useLiveMonitor(opts) {
1030
1040
  const [oddsDot, setOddsDot] = (0, import_react3.useState)(false);
1031
1041
  const [lastViewedPrices, setLastViewedPrices] = (0, import_react3.useState)({});
1032
1042
  const [inSlip, setInSlip] = (0, import_react3.useState)({});
1043
+ const [openMarket, setOpenMarket] = (0, import_react3.useState)({});
1044
+ const [marketOdds, setMarketOdds] = (0, import_react3.useState)({});
1033
1045
  const pinsRef = (0, import_react3.useRef)(pins);
1034
1046
  pinsRef.current = pins;
1035
1047
  const activeTabRef = (0, import_react3.useRef)(activeTab);
@@ -1038,6 +1050,46 @@ function useLiveMonitor(opts) {
1038
1050
  snapshotRef.current = snapshot;
1039
1051
  const lastViewedPricesRef = (0, import_react3.useRef)(lastViewedPrices);
1040
1052
  lastViewedPricesRef.current = lastViewedPrices;
1053
+ const openMarketRef = (0, import_react3.useRef)(openMarket);
1054
+ openMarketRef.current = openMarket;
1055
+ const marketOddsRef = (0, import_react3.useRef)(marketOdds);
1056
+ marketOddsRef.current = marketOdds;
1057
+ const marketKey = (matchId, dev) => `${matchId}:${dev}`;
1058
+ const getMarketOddsRef = (0, import_react3.useRef)(opts.getMarketOdds);
1059
+ getMarketOddsRef.current = opts.getMarketOdds;
1060
+ const fetchMarket = (0, import_react3.useCallback)((matchId, dev) => {
1061
+ const key = marketKey(matchId, dev);
1062
+ const existing = marketOddsRef.current[key];
1063
+ if (existing?.loading) return;
1064
+ const loadingEntry = { ...existing, loading: true, error: false };
1065
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry };
1066
+ setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }));
1067
+ const fn = getMarketOddsRef.current;
1068
+ if (!fn) return;
1069
+ void fn(matchId, dev).then((block) => {
1070
+ const entry = { block: block ?? void 0, loading: false, error: false };
1071
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
1072
+ setMarketOdds((prev) => ({ ...prev, [key]: entry }));
1073
+ }).catch(() => {
1074
+ const entry = { ...marketOddsRef.current[key], loading: false, error: true };
1075
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
1076
+ setMarketOdds((prev) => ({ ...prev, [key]: entry }));
1077
+ });
1078
+ }, []);
1079
+ const toggleMarket = (0, import_react3.useCallback)((matchId, dev) => {
1080
+ const key = marketKey(matchId, dev);
1081
+ const wasOpen = openMarketRef.current[matchId] === dev;
1082
+ const nextValue = wasOpen ? null : dev;
1083
+ openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue };
1084
+ setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }));
1085
+ const existing = marketOddsRef.current[key];
1086
+ if (!wasOpen && !(existing?.loading || existing?.block)) {
1087
+ fetchMarket(matchId, dev);
1088
+ }
1089
+ }, [fetchMarket]);
1090
+ const retryMarket = (0, import_react3.useCallback)((matchId, dev) => {
1091
+ fetchMarket(matchId, dev);
1092
+ }, [fetchMarket]);
1041
1093
  const applySnapshot = (0, import_react3.useCallback)((next) => {
1042
1094
  if (next === null) {
1043
1095
  setEnabled(false);
@@ -1057,6 +1109,16 @@ function useLiveMonitor(opts) {
1057
1109
  }
1058
1110
  }
1059
1111
  if (sawNewGoalOrRed && activeTabRef.current !== "matches") setMatchesDot(true);
1112
+ for (const m of next.matches) {
1113
+ if (!pinnedMatchIds.has(m.matchId)) continue;
1114
+ const first = m.availableMarkets?.[0];
1115
+ if (!first) continue;
1116
+ if (m.matchId in openMarketRef.current) continue;
1117
+ const dev = first.marketDeveloperName;
1118
+ openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev };
1119
+ setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }));
1120
+ fetchMarket(m.matchId, dev);
1121
+ }
1060
1122
  const marketPins = currentPins.filter((p) => p.kind !== "match");
1061
1123
  if (activeTabRef.current === "odds") {
1062
1124
  setLastViewedPrices((prevMap) => {
@@ -1107,12 +1169,17 @@ function useLiveMonitor(opts) {
1107
1169
  return;
1108
1170
  }
1109
1171
  applySnapshot(snap);
1172
+ for (const m of snap.matches) {
1173
+ if (m.phase !== "live") continue;
1174
+ const dev = openMarketRef.current[m.matchId];
1175
+ if (dev) fetchMarket(m.matchId, dev);
1176
+ }
1110
1177
  } catch {
1111
1178
  } finally {
1112
1179
  inFlightRef.current = false;
1113
1180
  scheduleRef.current();
1114
1181
  }
1115
- }, [applySnapshot]);
1182
+ }, [applySnapshot, fetchMarket]);
1116
1183
  const scheduleRef = (0, import_react3.useRef)(() => {
1117
1184
  });
1118
1185
  scheduleRef.current = () => {
@@ -1190,10 +1257,17 @@ function useLiveMonitor(opts) {
1190
1257
  lastViewedPrices,
1191
1258
  inSlip,
1192
1259
  markInSlip,
1260
+ openMarket,
1261
+ marketOdds,
1262
+ toggleMarket,
1263
+ retryMarket,
1193
1264
  _setSnapshot: applySnapshot
1194
1265
  };
1195
1266
  }
1196
1267
 
1268
+ // src/components/ChatFab.tsx
1269
+ var import_react5 = require("react");
1270
+
1197
1271
  // src/components/BrandMark.tsx
1198
1272
  var import_react4 = require("react");
1199
1273
 
@@ -1246,23 +1320,39 @@ function BrandMark({ logoUrl, className }) {
1246
1320
  var import_jsx_runtime3 = require("react/jsx-runtime");
1247
1321
  function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
1248
1322
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ss-w-greeting", role: "note", children: [
1249
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: text }),
1323
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
1325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {}),
1326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {}),
1327
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", {})
1328
+ ] }),
1329
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ss-w-greeting-text", children: text })
1330
+ ] }),
1250
1331
  onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null
1251
1332
  ] });
1252
1333
  }
1253
1334
 
1254
1335
  // src/components/ChatFab.tsx
1255
1336
  var import_jsx_runtime4 = require("react/jsx-runtime");
1256
- function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss" }) {
1337
+ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
1257
1338
  const bubble = popupText ?? greeting;
1258
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-w-fab-wrap", children: [
1339
+ const [intro, setIntro] = (0, import_react5.useState)(false);
1340
+ const armedRef = (0, import_react5.useRef)(introAllowed);
1341
+ (0, import_react5.useEffect)(() => {
1342
+ if (armedRef.current && bubble) {
1343
+ armedRef.current = false;
1344
+ setIntro(true);
1345
+ onIntroStart?.();
1346
+ }
1347
+ }, [bubble, onIntroStart]);
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
1259
1349
  bubble ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel }) : null,
1260
1350
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
1261
1351
  ] });
1262
1352
  }
1263
1353
 
1264
1354
  // src/components/ChatPanel.tsx
1265
- var import_react21 = require("react");
1355
+ var import_react22 = require("react");
1266
1356
 
1267
1357
  // src/components/ChatHeader.tsx
1268
1358
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -1275,7 +1365,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat", logoUrl, headerTitle }
1275
1365
  }
1276
1366
 
1277
1367
  // src/components/MessageList.tsx
1278
- var import_react19 = require("react");
1368
+ var import_react20 = require("react");
1279
1369
 
1280
1370
  // src/components/Markdown.tsx
1281
1371
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -1293,7 +1383,7 @@ function Markdown({ text }) {
1293
1383
  }
1294
1384
 
1295
1385
  // src/components/EntityCardList.tsx
1296
- var import_react5 = require("react");
1386
+ var import_react6 = require("react");
1297
1387
  var import_jsx_runtime7 = require("react/jsx-runtime");
1298
1388
  var MAX_VISIBLE = 3;
1299
1389
  var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
@@ -1377,7 +1467,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
1377
1467
  )) });
1378
1468
  }
1379
1469
  function EntityCardItem({ c }) {
1380
- const [active, setActive] = (0, import_react5.useState)(0);
1470
+ const [active, setActive] = (0, import_react6.useState)(0);
1381
1471
  const hasBody = c.scopes.length > 0;
1382
1472
  if (!hasBody) {
1383
1473
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardHeader, { c, showScopeCrest: false }) });
@@ -1391,7 +1481,7 @@ function EntityCardItem({ c }) {
1391
1481
  ] });
1392
1482
  }
1393
1483
  function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1394
- const [expanded, setExpanded] = (0, import_react5.useState)(false);
1484
+ const [expanded, setExpanded] = (0, import_react6.useState)(false);
1395
1485
  if (cards.length === 0) return null;
1396
1486
  const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1397
1487
  const overflow = cards.length - MAX_VISIBLE;
@@ -1402,18 +1492,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
1402
1492
  }
1403
1493
 
1404
1494
  // src/components/BettingInsightList.tsx
1405
- var import_react10 = require("react");
1495
+ var import_react11 = require("react");
1406
1496
 
1407
1497
  // src/components/AddToSlipButton.tsx
1408
- var import_react7 = require("react");
1498
+ var import_react8 = require("react");
1409
1499
  var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
1410
1500
 
1411
1501
  // src/components/Toast.tsx
1412
- var import_react6 = require("react");
1502
+ var import_react7 = require("react");
1413
1503
  var import_jsx_runtime8 = require("react/jsx-runtime");
1414
1504
  var DISMISS_MS = 4e3;
1415
1505
  function Toast({ toast, onDismiss }) {
1416
- (0, import_react6.useEffect)(() => {
1506
+ (0, import_react7.useEffect)(() => {
1417
1507
  if (!toast) return;
1418
1508
  const timer = setTimeout(onDismiss, DISMISS_MS);
1419
1509
  return () => clearTimeout(timer);
@@ -1431,10 +1521,10 @@ function withTimeout(value) {
1431
1521
  ]);
1432
1522
  }
1433
1523
  function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
1434
- const [pending, setPending] = (0, import_react7.useState)(false);
1435
- const [settled, setSettled] = (0, import_react7.useState)(false);
1436
- const [toast, setToast] = (0, import_react7.useState)(null);
1437
- const dismiss = (0, import_react7.useCallback)(() => setToast(null), []);
1524
+ const [pending, setPending] = (0, import_react8.useState)(false);
1525
+ const [settled, setSettled] = (0, import_react8.useState)(false);
1526
+ const [toast, setToast] = (0, import_react8.useState)(null);
1527
+ const dismiss = (0, import_react8.useCallback)(() => setToast(null), []);
1438
1528
  const handler = slip.onAddToSlip;
1439
1529
  if (!ui || !handler || !selection) return null;
1440
1530
  const onClick = async () => {
@@ -1498,14 +1588,14 @@ function OddsMovementBadge({
1498
1588
  }
1499
1589
 
1500
1590
  // src/components/Crest.tsx
1501
- var import_react8 = require("react");
1591
+ var import_react9 = require("react");
1502
1592
  var import_jsx_runtime11 = require("react/jsx-runtime");
1503
1593
  function initials2(name) {
1504
1594
  return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
1505
1595
  }
1506
1596
  function Crest2({ url, name, kind }) {
1507
1597
  const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
1508
- const [failed, setFailed] = (0, import_react8.useState)(false);
1598
+ const [failed, setFailed] = (0, import_react9.useState)(false);
1509
1599
  if (url && !failed) {
1510
1600
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1511
1601
  }
@@ -1513,11 +1603,16 @@ function Crest2({ url, name, kind }) {
1513
1603
  }
1514
1604
 
1515
1605
  // src/components/PinToggle.tsx
1516
- var import_react9 = require("react");
1606
+ var import_react10 = require("react");
1517
1607
  var import_jsx_runtime12 = require("react/jsx-runtime");
1608
+ var PIN_GLYPHS = {
1609
+ pin: { viewBox: "0 0 24 24", strokeWidth: 1.4, transform: "scale(1.5)", d: "M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z" },
1610
+ star: { viewBox: "0 0 24 24", strokeWidth: 2, d: "M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.35 6.1 20.4l1.1-6.47L2.5 9.35l6.5-.95z" },
1611
+ bookmark: { viewBox: "0 0 24 24", strokeWidth: 2, d: "M7 3h10a1.5 1.5 0 0 1 1.5 1.5V21l-6.5-3.6L5.5 21V4.5A1.5 1.5 0 0 1 7 3z" }
1612
+ };
1518
1613
  function PinToggle({ pin, monitor, ui }) {
1519
- const [toast, setToast] = (0, import_react9.useState)(null);
1520
- const dismiss = (0, import_react9.useCallback)(() => setToast(null), []);
1614
+ const [toast, setToast] = (0, import_react10.useState)(null);
1615
+ const dismiss = (0, import_react10.useCallback)(() => setToast(null), []);
1521
1616
  if (!monitor || !monitor.enabled) return null;
1522
1617
  const key = pinKey(pin);
1523
1618
  const pinned = monitor.isPinned(key);
@@ -1530,6 +1625,7 @@ function PinToggle({ pin, monitor, ui }) {
1530
1625
  setToast({ kind: "error", text: ui.marketLimitToast });
1531
1626
  }
1532
1627
  };
1628
+ const glyph = PIN_GLYPHS[ui.pinIcon];
1533
1629
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-pin-wrap", children: [
1534
1630
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1535
1631
  "button",
@@ -1537,10 +1633,22 @@ function PinToggle({ pin, monitor, ui }) {
1537
1633
  type: "button",
1538
1634
  className: "ss-w-pin",
1539
1635
  "data-on": pinned || void 0,
1636
+ "data-icon": ui.pinIcon,
1540
1637
  "aria-pressed": pinned,
1541
1638
  "aria-label": pinned ? labels.unpin : labels.pin,
1542
1639
  onClick,
1543
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { fill: "currentColor", d: "M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z" }) })
1640
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { viewBox: glyph.viewBox, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1641
+ "path",
1642
+ {
1643
+ transform: glyph.transform,
1644
+ d: glyph.d,
1645
+ fill: pinned ? "currentColor" : "none",
1646
+ stroke: pinned ? "none" : "currentColor",
1647
+ strokeWidth: glyph.strokeWidth,
1648
+ strokeLinejoin: "round",
1649
+ strokeLinecap: "round"
1650
+ }
1651
+ ) })
1544
1652
  }
1545
1653
  ),
1546
1654
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Toast, { toast, onDismiss: dismiss })
@@ -1556,7 +1664,7 @@ function StatRows({ stats }) {
1556
1664
  ] }, `${s.label}:${s.value}`)) });
1557
1665
  }
1558
1666
  function ScopedStats({ scopes }) {
1559
- const [active, setActive] = (0, import_react10.useState)(0);
1667
+ const [active, setActive] = (0, import_react11.useState)(0);
1560
1668
  const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
1561
1669
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-scoped", children: [
1562
1670
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
@@ -1567,7 +1675,7 @@ function hasStatsContent(it) {
1567
1675
  return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
1568
1676
  }
1569
1677
  function ReasonStrip({ it, ui }) {
1570
- const [open, setOpen] = (0, import_react10.useState)(false);
1678
+ const [open, setOpen] = (0, import_react11.useState)(false);
1571
1679
  const hasScopes = !!it.scopes && it.scopes.length >= 2;
1572
1680
  const hasStats = hasStatsContent(it);
1573
1681
  const hasText = !!it.text;
@@ -1677,7 +1785,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
1677
1785
  }
1678
1786
 
1679
1787
  // src/components/MarketOddsCardList.tsx
1680
- var import_react11 = require("react");
1788
+ var import_react12 = require("react");
1681
1789
  var import_jsx_runtime14 = require("react/jsx-runtime");
1682
1790
  function OddsRow({ vm, row, ui, slip, inSlipIds }) {
1683
1791
  const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
@@ -1693,48 +1801,50 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
1693
1801
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
1694
1802
  ] });
1695
1803
  }
1696
- function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
1697
- const [open, setOpen] = (0, import_react11.useState)(false);
1804
+ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader }) {
1805
+ const [open, setOpen] = (0, import_react12.useState)(false);
1698
1806
  const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
1699
1807
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
1700
1808
  const showPin = !!monitor && vm.pinEnabled;
1701
1809
  const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
1702
1810
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mocard", children: [
1703
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-header", children: [
1704
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1705
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
1706
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-comp", children: vm.competition })
1707
- ] }) : null }),
1708
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-header-right", children: [
1709
- vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-live", children: [
1710
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1711
- ui?.liveLabel ?? "Live"
1712
- ] }) : null,
1713
- kickoff ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-kick", children: [
1714
- kickoff.dayLabel,
1715
- " ",
1716
- kickoff.time
1717
- ] }) : null,
1718
- showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1719
- PinToggle,
1720
- {
1721
- ui,
1722
- monitor,
1723
- pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
1724
- }
1725
- ) : null
1726
- ] })
1727
- ] }) : null,
1728
- hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mo-sub", children: [
1729
- hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-fixture", children: [
1730
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
1731
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
1732
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
1733
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
1734
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
1735
- ] }) : vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
1736
- vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-market", children: vm.market }) : null
1737
- ] }) : null,
1811
+ !hideHeader && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1812
+ showHeader ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-header", children: [
1813
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1814
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
1815
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-comp", children: vm.competition })
1816
+ ] }) : null }),
1817
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-header-right", children: [
1818
+ vm.isLive ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-live", children: [
1819
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1820
+ ui?.liveLabel ?? "Live"
1821
+ ] }) : null,
1822
+ kickoff ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-kick", children: [
1823
+ kickoff.dayLabel,
1824
+ " ",
1825
+ kickoff.time
1826
+ ] }) : null,
1827
+ showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1828
+ PinToggle,
1829
+ {
1830
+ ui,
1831
+ monitor,
1832
+ pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
1833
+ }
1834
+ ) : null
1835
+ ] })
1836
+ ] }) : null,
1837
+ hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mo-sub", children: [
1838
+ hasNamedTeams ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-bi-fixture", children: [
1839
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
1840
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
1842
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
1843
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
1844
+ ] }) : vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
1845
+ vm.market ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-mo-market", children: vm.market }) : null
1846
+ ] }) : null
1847
+ ] }),
1738
1848
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-mo-rows", children: [
1739
1849
  vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)),
1740
1850
  open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)) : null
@@ -1747,9 +1857,9 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
1747
1857
  vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
1748
1858
  ] });
1749
1859
  }
1750
- function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds }) {
1860
+ function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader }) {
1751
1861
  if (!cards || cards.length === 0) return null;
1752
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds }, vm.id)) });
1862
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds, hideHeader }, vm.id)) });
1753
1863
  }
1754
1864
 
1755
1865
  // src/components/OddsMovementCard.tsx
@@ -1987,7 +2097,7 @@ function FixtureCard({ card }) {
1987
2097
  }
1988
2098
 
1989
2099
  // src/components/dashboard/CountdownCard.tsx
1990
- var import_react12 = require("react");
2100
+ var import_react13 = require("react");
1991
2101
  var import_jsx_runtime20 = require("react/jsx-runtime");
1992
2102
  var DAY_MS = 864e5;
1993
2103
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -2006,12 +2116,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
2006
2116
  function CountdownCard({ card }) {
2007
2117
  const { data } = card;
2008
2118
  const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
2009
- const [nowMs, setNowMs] = (0, import_react12.useState)(() => Date.now());
2010
- const [reduced] = (0, import_react12.useState)(
2119
+ const [nowMs, setNowMs] = (0, import_react13.useState)(() => Date.now());
2120
+ const [reduced] = (0, import_react13.useState)(
2011
2121
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
2012
2122
  );
2013
2123
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
2014
- (0, import_react12.useEffect)(() => {
2124
+ (0, import_react13.useEffect)(() => {
2015
2125
  if (reduced) return;
2016
2126
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
2017
2127
  return () => window.clearInterval(id);
@@ -2019,7 +2129,7 @@ function CountdownCard({ card }) {
2019
2129
  const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
2020
2130
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ss-w-fandash-card ss-w-fandash-countdown", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-fandash-countdown-top", children: [
2021
2131
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
2022
- segments ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react12.Fragment, { children: [
2132
+ segments ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-clock", children: segments.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react13.Fragment, { children: [
2023
2133
  i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
2024
2134
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
2025
2135
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
@@ -2030,7 +2140,7 @@ function CountdownCard({ card }) {
2030
2140
  }
2031
2141
 
2032
2142
  // src/components/dashboard/InjuriesCard.tsx
2033
- var import_react13 = require("react");
2143
+ var import_react14 = require("react");
2034
2144
  var import_jsx_runtime21 = require("react/jsx-runtime");
2035
2145
  var SHOWN = 3;
2036
2146
  function ColHead({ name, crestUrl }) {
@@ -2053,7 +2163,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
2053
2163
  }
2054
2164
  function InjuriesCard({ card, ui }) {
2055
2165
  const { data } = card;
2056
- const [expanded, setExpanded] = (0, import_react13.useState)(false);
2166
+ const [expanded, setExpanded] = (0, import_react14.useState)(false);
2057
2167
  const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
2058
2168
  const limit = expanded ? void 0 : SHOWN;
2059
2169
  const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
@@ -2157,7 +2267,7 @@ function LinksCard({ card }) {
2157
2267
  }
2158
2268
 
2159
2269
  // src/components/dashboard/PostMatchResultCard.tsx
2160
- var import_react14 = require("react");
2270
+ var import_react15 = require("react");
2161
2271
  var import_jsx_runtime27 = require("react/jsx-runtime");
2162
2272
  function initials3(name) {
2163
2273
  return name.trim().slice(0, 3).toUpperCase();
@@ -2167,7 +2277,7 @@ function PostMatchCrest({
2167
2277
  name,
2168
2278
  side
2169
2279
  }) {
2170
- const [failed, setFailed] = (0, import_react14.useState)(false);
2280
+ const [failed, setFailed] = (0, import_react15.useState)(false);
2171
2281
  const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
2172
2282
  if (url && !failed) {
2173
2283
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2366,10 +2476,10 @@ function RestingFormCard({ card }) {
2366
2476
  }
2367
2477
 
2368
2478
  // src/components/dashboard/LiveScoreCard.tsx
2369
- var import_react16 = require("react");
2479
+ var import_react17 = require("react");
2370
2480
 
2371
2481
  // src/useLiveClock.ts
2372
- var import_react15 = require("react");
2482
+ var import_react16 = require("react");
2373
2483
  var TICK_MS = 6e4;
2374
2484
  var MAX_LIVE_TICK_MINUTES = 15;
2375
2485
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -2378,10 +2488,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
2378
2488
  return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
2379
2489
  }
2380
2490
  function useLiveClock(minute, clockRunning, receivedAtMs) {
2381
- const [displayMinute, setDisplayMinute] = (0, import_react15.useState)(
2491
+ const [displayMinute, setDisplayMinute] = (0, import_react16.useState)(
2382
2492
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
2383
2493
  );
2384
- (0, import_react15.useEffect)(() => {
2494
+ (0, import_react16.useEffect)(() => {
2385
2495
  setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
2386
2496
  if (!clockRunning) return;
2387
2497
  const id = window.setInterval(() => {
@@ -2398,7 +2508,7 @@ function initials5(name) {
2398
2508
  return name.trim().slice(0, 3).toUpperCase();
2399
2509
  }
2400
2510
  function LiveCrest({ url, name, side }) {
2401
- const [failed, setFailed] = (0, import_react16.useState)(false);
2511
+ const [failed, setFailed] = (0, import_react17.useState)(false);
2402
2512
  const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
2403
2513
  if (url && !failed) {
2404
2514
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2417,7 +2527,7 @@ function LiveScoreCard({
2417
2527
  }) {
2418
2528
  const { data } = card;
2419
2529
  const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
2420
- const seedRef = (0, import_react16.useRef)(null);
2530
+ const seedRef = (0, import_react17.useRef)(null);
2421
2531
  if (!seedRef.current || seedRef.current.key !== seedKey) {
2422
2532
  seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
2423
2533
  }
@@ -2457,7 +2567,7 @@ function LiveScoreCard({
2457
2567
  }
2458
2568
 
2459
2569
  // src/components/dashboard/LiveTimelineCard.tsx
2460
- var import_react17 = require("react");
2570
+ var import_react18 = require("react");
2461
2571
  var import_jsx_runtime37 = require("react/jsx-runtime");
2462
2572
  var SHOWN2 = 3;
2463
2573
  function EventIcon({ type }) {
@@ -2499,7 +2609,7 @@ function EventRow({ e }) {
2499
2609
  ] });
2500
2610
  }
2501
2611
  function LiveTimelineCard({ card, ui }) {
2502
- const [expanded, setExpanded] = (0, import_react17.useState)(false);
2612
+ const [expanded, setExpanded] = (0, import_react18.useState)(false);
2503
2613
  const events = card.data.events;
2504
2614
  if (!events || events.length === 0) return null;
2505
2615
  const sorted = [...events].sort((a, b) => b.minute - a.minute);
@@ -2524,7 +2634,7 @@ function LiveTimelineCard({ card, ui }) {
2524
2634
  }
2525
2635
 
2526
2636
  // src/components/dashboard/MomentumWave.tsx
2527
- var import_react18 = require("react");
2637
+ var import_react19 = require("react");
2528
2638
  var import_jsx_runtime38 = require("react/jsx-runtime");
2529
2639
  var WIDTH = 270;
2530
2640
  var HEIGHT = 56;
@@ -2548,7 +2658,7 @@ function MomentumWave({
2548
2658
  }) {
2549
2659
  if (points.length === 0) return null;
2550
2660
  const { area, line, lastLeftPct, lastTopPx } = buildPaths(points);
2551
- const clipId = (0, import_react18.useId)();
2661
+ const clipId = (0, import_react19.useId)();
2552
2662
  const topClipId = `${clipId}-top`;
2553
2663
  const bottomClipId = `${clipId}-bottom`;
2554
2664
  const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
@@ -2739,11 +2849,11 @@ function turnAnchor(messages) {
2739
2849
  }
2740
2850
  function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
2741
2851
  const { state, send } = controller;
2742
- const listRef = (0, import_react19.useRef)(null);
2743
- const endRef = (0, import_react19.useRef)(null);
2744
- const pinnedRef = (0, import_react19.useRef)(true);
2745
- const anchoredTurnRef = (0, import_react19.useRef)(null);
2746
- (0, import_react19.useEffect)(() => {
2852
+ const listRef = (0, import_react20.useRef)(null);
2853
+ const endRef = (0, import_react20.useRef)(null);
2854
+ const pinnedRef = (0, import_react20.useRef)(true);
2855
+ const anchoredTurnRef = (0, import_react20.useRef)(null);
2856
+ (0, import_react20.useEffect)(() => {
2747
2857
  const anchor = turnAnchor(state.messages);
2748
2858
  const list = listRef.current;
2749
2859
  if (anchor && anchor.turnId !== anchoredTurnRef.current) {
@@ -2799,10 +2909,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
2799
2909
  }
2800
2910
 
2801
2911
  // src/components/ChatInput.tsx
2802
- var import_react20 = require("react");
2912
+ var import_react21 = require("react");
2803
2913
  var import_jsx_runtime44 = require("react/jsx-runtime");
2804
2914
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
2805
- const [value, setValue] = (0, import_react20.useState)("");
2915
+ const [value, setValue] = (0, import_react21.useState)("");
2806
2916
  const submit = () => {
2807
2917
  const t = value.trim();
2808
2918
  if (!t) return;
@@ -2859,8 +2969,63 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
2859
2969
  }) });
2860
2970
  }
2861
2971
 
2862
- // src/components/MonitorMatchCard.tsx
2972
+ // src/components/MarketAccordion.tsx
2863
2973
  var import_jsx_runtime46 = require("react/jsx-runtime");
2974
+ function MarketAccordion({ match, monitor, ui, slip }) {
2975
+ const markets = match.availableMarkets ?? [];
2976
+ if (markets.length === 0) return null;
2977
+ const open = monitor.openMarket[match.matchId] ?? null;
2978
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-acc", children: markets.map((m) => {
2979
+ const isOpen = open === m.marketDeveloperName;
2980
+ const key = `${match.matchId}:${m.marketDeveloperName}`;
2981
+ const entry = monitor.marketOdds[key];
2982
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: isOpen ? "ss-w-acc-row ss-w-acc-row-open" : "ss-w-acc-row", children: [
2983
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
2984
+ "button",
2985
+ {
2986
+ type: "button",
2987
+ className: "ss-w-acc-head",
2988
+ onClick: () => monitor.toggleMarket(match.matchId, m.marketDeveloperName),
2989
+ children: [
2990
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-chevron", children: isOpen ? "\u25BE" : "\u25B8" }),
2991
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-label", children: m.marketLabel }),
2992
+ m.hasInsight && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-badge", children: "\u2605" }),
2993
+ m.suspended && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-susp", children: ui.accordionSuspended })
2994
+ ]
2995
+ }
2996
+ ),
2997
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-acc-panel", children: [
2998
+ entry?.error && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
2999
+ "div",
3000
+ {
3001
+ className: "ss-w-acc-retry",
3002
+ onClick: () => monitor.retryMarket(match.matchId, m.marketDeveloperName),
3003
+ children: ui.accordionRetry
3004
+ }
3005
+ ),
3006
+ entry?.block?.insight?.text && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-acc-insight", children: [
3007
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-acc-badge", children: ui.accordionValueLabel }),
3008
+ " ",
3009
+ entry.block.insight.text
3010
+ ] }),
3011
+ entry?.block?.card && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3012
+ MarketOddsCardList,
3013
+ {
3014
+ cards: [toMarketOddsVM(entry.block.card)],
3015
+ ui,
3016
+ slip,
3017
+ monitor,
3018
+ inSlipIds: monitor.inSlip,
3019
+ hideHeader: true
3020
+ }
3021
+ )
3022
+ ] })
3023
+ ] }, m.marketDeveloperName);
3024
+ }) });
3025
+ }
3026
+
3027
+ // src/components/MonitorMatchCard.tsx
3028
+ var import_jsx_runtime47 = require("react/jsx-runtime");
2864
3029
  function chipSelection(row, matchId, conversationId) {
2865
3030
  const chip = row.market;
2866
3031
  if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== "number" || typeof chip.price !== "number") return null;
@@ -2883,63 +3048,63 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
2883
3048
  const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins));
2884
3049
  const orderedRows = [...promotedRows, ...otherRows];
2885
3050
  const kickoff = match.phase === "preMatch" && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : void 0;
2886
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon", children: [
2887
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-top", children: [
2888
- live && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-fandash-live-pill", children: [
2889
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
3051
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon", children: [
3052
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-top", children: [
3053
+ live && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-fandash-live-pill", children: [
3054
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
2890
3055
  ui.liveLabel
2891
3056
  ] }),
2892
- match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
2893
- kickoff && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-mon-pill", children: [
3057
+ match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
3058
+ kickoff && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-pill", children: [
2894
3059
  kickoff.dayLabel,
2895
3060
  " \xB7 ",
2896
3061
  kickoff.time
2897
3062
  ] }),
2898
- live && match.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
2899
- match.competitionName && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-comp", children: match.competitionName }),
2900
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
3063
+ live && match.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
3064
+ match.competitionName && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-comp", children: match.competitionName }),
3065
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
2901
3066
  ] }),
2902
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-main", children: [
2903
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-mon-side", children: [
2904
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
2905
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-name", children: match.homeTeamName })
3067
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-main", children: [
3068
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-side", children: [
3069
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
3070
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: match.homeTeamName })
2906
3071
  ] }),
2907
- match.phase === "preMatch" ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-mon-score", children: [
3072
+ match.phase === "preMatch" ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-score", children: [
2908
3073
  match.homeScore,
2909
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("i", { children: "\u2013" }),
3074
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("i", { children: "\u2013" }),
2910
3075
  match.awayScore
2911
3076
  ] }),
2912
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
2913
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
2914
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-name", children: match.awayTeamName })
3077
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
3078
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
3079
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: match.awayTeamName })
2915
3080
  ] })
2916
3081
  ] }),
2917
- scorers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
2918
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
3082
+ scorers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
3083
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
2919
3084
  const total = row.homeNum + row.awayNum;
2920
3085
  const homePct = total > 0 ? row.homeNum / total * 75 : 0;
2921
3086
  const awayPct = total > 0 ? row.awayNum / total * 75 : 0;
2922
3087
  const promoted = isPromoted(row, promotedPins);
2923
3088
  const selection = chipSelection(row, match.matchId, slip.conversationId);
2924
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
2925
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
2926
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
2927
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-l", children: row.label }),
2928
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
3089
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
3090
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
3091
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
3092
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-l", children: row.label }),
3093
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
2929
3094
  ] }),
2930
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-bar", children: [
2931
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
2932
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
3095
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-bar", children: [
3096
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
3097
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
2933
3098
  ] }),
2934
- row.market && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
2935
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { children: [
3099
+ row.market && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
3100
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { children: [
2936
3101
  row.market.marketLabel,
2937
3102
  " \xB7 ",
2938
3103
  row.market.selectionLabel
2939
3104
  ] }),
2940
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ss-w-mon-stat-mkt-right", children: [
2941
- row.market.isSuspended ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
2942
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3105
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-stat-mkt-right", children: [
3106
+ row.market.isSuspended ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
3107
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
2943
3108
  SlipButton,
2944
3109
  {
2945
3110
  selection,
@@ -2953,68 +3118,69 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
2953
3118
  ] })
2954
3119
  ] }, row.label);
2955
3120
  }) }),
2956
- match.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
2957
- match.momentum.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-mom", children: [
2958
- /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
2959
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
2960
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
2961
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
3121
+ match.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
3122
+ match.momentum.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-mom", children: [
3123
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-stat-row", children: [
3124
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
3125
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
3126
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
2962
3127
  ] }),
2963
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(MomentumWave, { points: match.momentum, clubIsHome: true })
3128
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(MomentumWave, { points: match.momentum, clubIsHome: true })
2964
3129
  ] }),
2965
- match.mainMarket && match.phase !== "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(MarketOddsCardList, { cards: [toMarketOddsVM(match.mainMarket)], ui, slip }),
2966
- match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ss-w-mon-grace", children: ui.graceNote })
3130
+ match.phase === "fullTime" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-grace", children: ui.graceNote })
2967
3131
  ] });
2968
3132
  }
2969
3133
 
2970
3134
  // src/components/MonitorTabs.tsx
2971
- var import_jsx_runtime47 = require("react/jsx-runtime");
3135
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2972
3136
  function ContextLine({ m, monitor, ui }) {
2973
3137
  const kick = m.kickoffUtc ? ui.bettingKickoff(m.kickoffUtc) : void 0;
2974
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mk-ctx", children: [
2975
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
2976
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
2977
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: m.homeTeamName })
3138
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mk-ctx", children: [
3139
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
3140
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
3141
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-name", children: m.homeTeamName })
2978
3142
  ] }),
2979
- m.phase === "preMatch" ? kick && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mon-pill", children: [
3143
+ m.phase === "preMatch" ? kick && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mon-pill", children: [
2980
3144
  kick.dayLabel,
2981
3145
  " ",
2982
3146
  kick.time
2983
- ] }) : typeof m.homeScore === "number" && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("b", { children: [
3147
+ ] }) : typeof m.homeScore === "number" && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("b", { children: [
2984
3148
  m.homeScore,
2985
3149
  "\u2013",
2986
3150
  m.awayScore
2987
3151
  ] }),
2988
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
2989
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
2990
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
3152
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-side", children: [
3153
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
3154
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
2991
3155
  ] }),
2992
- m.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
2993
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ss-w-mk-ctx-right", children: [
2994
- m.isSuspended && !m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
2995
- m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
2996
- m.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
3156
+ m.minuteLabel && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
3157
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "ss-w-mk-ctx-right", children: [
3158
+ m.isSuspended && !m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
3159
+ m.isSettled && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
3160
+ m.status === "stale" && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
2997
3161
  (() => {
2998
3162
  const pin = monitor.pins.find((p) => p.key === m.key);
2999
- return pin ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(PinToggle, { ui, monitor, pin }) : null;
3163
+ return pin ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PinToggle, { ui, monitor, pin }) : null;
3000
3164
  })()
3001
3165
  ] })
3002
3166
  ] });
3003
3167
  }
3004
3168
  function MatchesPanel({ monitor, ui, slip }) {
3005
3169
  const matches = (monitor.snapshot?.matches ?? []).filter((m) => monitor.pins.some((p) => p.kind === "match" && p.matchId === m.matchId));
3006
- if (matches.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
3007
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3008
- MonitorMatchCard,
3009
- {
3010
- match: m,
3011
- promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
3012
- monitor,
3013
- ui,
3014
- slip
3015
- },
3016
- m.matchId
3017
- )) });
3170
+ if (matches.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
3171
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mon-item", children: [
3172
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3173
+ MonitorMatchCard,
3174
+ {
3175
+ match: m,
3176
+ promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
3177
+ monitor,
3178
+ ui,
3179
+ slip
3180
+ }
3181
+ ),
3182
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(MarketAccordion, { match: m, monitor, ui, slip })
3183
+ ] }, m.matchId)) });
3018
3184
  }
3019
3185
  function withSinceViewMovement(vm, prev) {
3020
3186
  const primary = vm.mainRows[0];
@@ -3028,10 +3194,10 @@ function withSinceViewMovement(vm, prev) {
3028
3194
  }
3029
3195
  function OddsPanel({ monitor, ui, slip }) {
3030
3196
  const markets = (monitor.snapshot?.markets ?? []).filter((m) => monitor.pins.some((p) => p.key === m.key));
3031
- if (markets.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
3032
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
3033
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ContextLine, { m, monitor, ui }),
3034
- m.card && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3197
+ if (markets.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
3198
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
3199
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ContextLine, { m, monitor, ui }),
3200
+ m.card && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3035
3201
  MarketOddsCardList,
3036
3202
  {
3037
3203
  cards: [withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])],
@@ -3040,17 +3206,17 @@ function OddsPanel({ monitor, ui, slip }) {
3040
3206
  inSlipIds: monitor.inSlip
3041
3207
  }
3042
3208
  ),
3043
- m.history && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
3044
- !m.card && !m.history && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
3209
+ m.history && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
3210
+ !m.card && !m.history && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
3045
3211
  ] }, m.key)) });
3046
3212
  }
3047
3213
 
3048
3214
  // src/components/ChatPanel.tsx
3049
- var import_jsx_runtime48 = require("react/jsx-runtime");
3215
+ var import_jsx_runtime49 = require("react/jsx-runtime");
3050
3216
  var FULLSCREEN_QUERY = "(max-width: 639px)";
3051
3217
  function useIsModal() {
3052
- const [modal, setModal] = (0, import_react21.useState)(false);
3053
- (0, import_react21.useEffect)(() => {
3218
+ const [modal, setModal] = (0, import_react22.useState)(false);
3219
+ (0, import_react22.useEffect)(() => {
3054
3220
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
3055
3221
  const mql = window.matchMedia(FULLSCREEN_QUERY);
3056
3222
  const sync = () => setModal(mql.matches);
@@ -3063,7 +3229,7 @@ function useIsModal() {
3063
3229
  function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3064
3230
  const { state, close, stop, send } = controller;
3065
3231
  const isModal = useIsModal();
3066
- (0, import_react21.useEffect)(() => {
3232
+ (0, import_react22.useEffect)(() => {
3067
3233
  const onKey = (e) => {
3068
3234
  if (e.key === "Escape") close();
3069
3235
  };
@@ -3074,12 +3240,12 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3074
3240
  monitor?.setActiveTab("chat");
3075
3241
  send(text);
3076
3242
  };
3077
- (0, import_react21.useEffect)(() => {
3243
+ (0, import_react22.useEffect)(() => {
3078
3244
  if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
3079
3245
  }, [monitor, state.isStreaming, state.messages.length]);
3080
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
3081
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
3082
- monitor && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3246
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
3247
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
3248
+ monitor && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3083
3249
  TabBar,
3084
3250
  {
3085
3251
  monitor,
@@ -3088,16 +3254,16 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3088
3254
  oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
3089
3255
  }
3090
3256
  ),
3091
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3257
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3092
3258
  "div",
3093
3259
  {
3094
3260
  style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
3095
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
3261
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
3096
3262
  }
3097
3263
  ),
3098
- monitor && monitor.activeTab === "matches" && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(MatchesPanel, { monitor, ui, slip }),
3099
- monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(OddsPanel, { monitor, ui, slip }),
3100
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
3264
+ monitor && monitor.activeTab === "matches" && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MatchesPanel, { monitor, ui, slip }),
3265
+ monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(OddsPanel, { monitor, ui, slip }),
3266
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
3101
3267
  ] });
3102
3268
  }
3103
3269
 
@@ -3145,8 +3311,40 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3145
3311
  .ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }
3146
3312
  .ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }
3147
3313
  .ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }
3148
- .ss-w-greeting-body { flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }
3314
+ .ss-w-greeting-body { position: relative; flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }
3149
3315
  .ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }
3316
+ .ss-w-greeting-text { display: block; }
3317
+ /* Typing indicator: overlays the text area so bubble height stays put; hidden at
3318
+ rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */
3319
+ .ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }
3320
+ .ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }
3321
+ /* One-shot launcher attention intro: FAB nudges, then the greeting types in.
3322
+ Gated behind no-preference so reduce-motion users get the greeting shown
3323
+ statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once
3324
+ per page load; every animation runs a single time and settles at rest. */
3325
+ @media (prefers-reduced-motion: no-preference) {
3326
+ .ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }
3327
+ .ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }
3328
+ .ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }
3329
+ .ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }
3330
+ .ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }
3331
+ .ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }
3332
+ .ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }
3333
+ }
3334
+ @keyframes ss-w-nudge {
3335
+ 0%, 100% { transform: none; }
3336
+ 22% { transform: translateY(-9px) rotate(-9deg); }
3337
+ 44% { transform: translateY(0) rotate(7deg); }
3338
+ 64% { transform: translateY(-4px) rotate(-4deg); }
3339
+ 82% { transform: rotate(2deg); }
3340
+ }
3341
+ @keyframes ss-w-greet-in {
3342
+ from { opacity: 0; transform: translateY(8px) scale(.92); }
3343
+ to { opacity: 1; transform: none; }
3344
+ }
3345
+ @keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }
3346
+ @keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
3347
+ @keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
3150
3348
 
3151
3349
  /* panel */
3152
3350
  .ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(460px, calc(100vw - 40px)); height: min(640px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }
@@ -3850,10 +4048,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3850
4048
  .ss-w-mon-oddspin { display: flex; flex-direction: column; gap: 10px; padding: 12px; border: 1px solid var(--ss-w-line); border-radius: 12px; background: var(--ss-w-panel); }
3851
4049
  .ss-w-mon-oddspin[data-settled] .ss-w-mo-price,
3852
4050
  .ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }
4051
+
4052
+ /* market accordion (Task 9): one collapsed row per available market, expanding into a reused
4053
+ MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */
4054
+ .ss-w-acc { display: flex; flex-direction: column; gap: 6px; }
4055
+ .ss-w-acc-row { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); overflow: hidden; }
4056
+ .ss-w-acc-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 9px 11px; background: none; border: none; cursor: pointer; text-align: left; font: inherit; color: var(--ss-w-ink); }
4057
+ .ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; }
4058
+ .ss-w-acc-label { font-size: 12.5px; font-weight: 600; }
4059
+ .ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); }
4060
+ .ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); }
4061
+ .ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
4062
+ .ss-w-acc-insight { 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; }
4063
+ .ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
3853
4064
  `;
3854
4065
 
3855
4066
  // src/StatsWidget.tsx
3856
- var import_jsx_runtime49 = require("react/jsx-runtime");
4067
+ var import_jsx_runtime50 = require("react/jsx-runtime");
3857
4068
  function buildClient(props) {
3858
4069
  try {
3859
4070
  if ("client" in props && props.client) {
@@ -3878,16 +4089,21 @@ function injectStyles(root) {
3878
4089
  function StatsWidget(props) {
3879
4090
  const injectedClient = "client" in props ? props.client : void 0;
3880
4091
  const cfg = props.config;
3881
- const built = (0, import_react22.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
3882
- const ui = (0, import_react22.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
3883
- const rootRef = (0, import_react22.useRef)(null);
4092
+ const built = (0, import_react23.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
4093
+ const ui = (0, import_react23.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
4094
+ const rootRef = (0, import_react23.useRef)(null);
4095
+ const introDoneRef = (0, import_react23.useRef)(false);
4096
+ const markIntroDone = (0, import_react23.useCallback)(() => {
4097
+ introDoneRef.current = true;
4098
+ }, []);
3884
4099
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
3885
4100
  const monitor = useLiveMonitor({
3886
4101
  getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
4102
+ getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
3887
4103
  storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
3888
4104
  isOpen: controller.state.isOpen
3889
4105
  });
3890
- const slip = (0, import_react22.useMemo)(
4106
+ const slip = (0, import_react23.useMemo)(
3891
4107
  () => {
3892
4108
  const handler = props.config?.onAddToSlip;
3893
4109
  return {
@@ -3910,18 +4126,18 @@ function StatsWidget(props) {
3910
4126
  },
3911
4127
  [props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
3912
4128
  );
3913
- const onDashboardTap = (0, import_react22.useMemo)(
4129
+ const onDashboardTap = (0, import_react23.useMemo)(
3914
4130
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
3915
4131
  [built]
3916
4132
  );
3917
- (0, import_react22.useEffect)(() => {
4133
+ (0, import_react23.useEffect)(() => {
3918
4134
  if (!built || !ui.injectStyles) return;
3919
4135
  const node = rootRef.current?.getRootNode();
3920
4136
  if (node) injectStyles(node);
3921
4137
  }, [built, ui.injectStyles]);
3922
4138
  if (!built) return null;
3923
4139
  const attrs = themeAttrs(ui);
3924
- return /* @__PURE__ */ (0, import_jsx_runtime49.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_runtime49.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4140
+ return /* @__PURE__ */ (0, import_jsx_runtime50.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_runtime50.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3925
4141
  ChatFab,
3926
4142
  {
3927
4143
  label: ui.launcherLabel,
@@ -3930,7 +4146,9 @@ function StatsWidget(props) {
3930
4146
  logoUrl: ui.logoUrl,
3931
4147
  onOpen: controller.open,
3932
4148
  onDismissPopup: controller.dismissPopup,
3933
- dismissLabel: ui.dismissGreeting
4149
+ dismissLabel: ui.dismissGreeting,
4150
+ introAllowed: !introDoneRef.current,
4151
+ onIntroStart: markIntroDone
3934
4152
  }
3935
4153
  ) });
3936
4154
  }