@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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/StatsWidget.tsx
2
- import { useEffect as useEffect9, useMemo as useMemo2, useRef as useRef6 } from "react";
2
+ import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo2, useRef as useRef7 } from "react";
3
3
  import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
4
4
 
5
5
  // src/kickoff.ts
@@ -83,7 +83,10 @@ var STRINGS = {
83
83
  fullTimeLabel: "Full time",
84
84
  inSlipLabel: "In slip",
85
85
  oddsUnavailable: "Odds unavailable right now",
86
- momentumLabel: "Momentum"
86
+ momentumLabel: "Momentum",
87
+ accordionValueLabel: "Value",
88
+ accordionRetry: "Couldn't load odds \u2014 tap to retry",
89
+ accordionSuspended: "Suspended"
87
90
  },
88
91
  tr: {
89
92
  launcherLabel: "SensibleStats ile sohbet et",
@@ -152,7 +155,10 @@ var STRINGS = {
152
155
  fullTimeLabel: "Ma\xE7 sonu",
153
156
  inSlipLabel: "Kuponda",
154
157
  oddsUnavailable: "Oranlar \u015Fu anda kullan\u0131lam\u0131yor",
155
- momentumLabel: "Momentum"
158
+ momentumLabel: "Momentum",
159
+ accordionValueLabel: "De\u011Fer",
160
+ accordionRetry: "Oranlar y\xFCklenemedi \u2014 yeniden dene",
161
+ accordionSuspended: "Ask\u0131da"
156
162
  }
157
163
  };
158
164
  function resolveLocaleStrings(locale) {
@@ -170,6 +176,7 @@ function normalizeUi(cfg) {
170
176
  cta: cfg.cta,
171
177
  surface: cfg.surface,
172
178
  ink: cfg.ink,
179
+ pinIcon: cfg.pinIcon ?? "pin",
173
180
  position: cfg.position ?? "right",
174
181
  offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },
175
182
  radius: cfg.radius ?? 16,
@@ -239,7 +246,10 @@ function normalizeUi(cfg) {
239
246
  fullTimeLabel: strings.fullTimeLabel,
240
247
  inSlipLabel: strings.inSlipLabel,
241
248
  oddsUnavailable: strings.oddsUnavailable,
242
- momentumLabel: strings.momentumLabel
249
+ momentumLabel: strings.momentumLabel,
250
+ accordionValueLabel: strings.accordionValueLabel,
251
+ accordionRetry: strings.accordionRetry,
252
+ accordionSuspended: strings.accordionSuspended
243
253
  };
244
254
  }
245
255
  function toClientOptions(cfg) {
@@ -993,6 +1003,8 @@ function useLiveMonitor(opts) {
993
1003
  const [oddsDot, setOddsDot] = useState(false);
994
1004
  const [lastViewedPrices, setLastViewedPrices] = useState({});
995
1005
  const [inSlip, setInSlip] = useState({});
1006
+ const [openMarket, setOpenMarket] = useState({});
1007
+ const [marketOdds, setMarketOdds] = useState({});
996
1008
  const pinsRef = useRef3(pins);
997
1009
  pinsRef.current = pins;
998
1010
  const activeTabRef = useRef3(activeTab);
@@ -1001,6 +1013,46 @@ function useLiveMonitor(opts) {
1001
1013
  snapshotRef.current = snapshot;
1002
1014
  const lastViewedPricesRef = useRef3(lastViewedPrices);
1003
1015
  lastViewedPricesRef.current = lastViewedPrices;
1016
+ const openMarketRef = useRef3(openMarket);
1017
+ openMarketRef.current = openMarket;
1018
+ const marketOddsRef = useRef3(marketOdds);
1019
+ marketOddsRef.current = marketOdds;
1020
+ const marketKey = (matchId, dev) => `${matchId}:${dev}`;
1021
+ const getMarketOddsRef = useRef3(opts.getMarketOdds);
1022
+ getMarketOddsRef.current = opts.getMarketOdds;
1023
+ const fetchMarket = useCallback2((matchId, dev) => {
1024
+ const key = marketKey(matchId, dev);
1025
+ const existing = marketOddsRef.current[key];
1026
+ if (existing?.loading) return;
1027
+ const loadingEntry = { ...existing, loading: true, error: false };
1028
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry };
1029
+ setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }));
1030
+ const fn = getMarketOddsRef.current;
1031
+ if (!fn) return;
1032
+ void fn(matchId, dev).then((block) => {
1033
+ const entry = { block: block ?? void 0, loading: false, error: false };
1034
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
1035
+ setMarketOdds((prev) => ({ ...prev, [key]: entry }));
1036
+ }).catch(() => {
1037
+ const entry = { ...marketOddsRef.current[key], loading: false, error: true };
1038
+ marketOddsRef.current = { ...marketOddsRef.current, [key]: entry };
1039
+ setMarketOdds((prev) => ({ ...prev, [key]: entry }));
1040
+ });
1041
+ }, []);
1042
+ const toggleMarket = useCallback2((matchId, dev) => {
1043
+ const key = marketKey(matchId, dev);
1044
+ const wasOpen = openMarketRef.current[matchId] === dev;
1045
+ const nextValue = wasOpen ? null : dev;
1046
+ openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue };
1047
+ setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }));
1048
+ const existing = marketOddsRef.current[key];
1049
+ if (!wasOpen && !(existing?.loading || existing?.block)) {
1050
+ fetchMarket(matchId, dev);
1051
+ }
1052
+ }, [fetchMarket]);
1053
+ const retryMarket = useCallback2((matchId, dev) => {
1054
+ fetchMarket(matchId, dev);
1055
+ }, [fetchMarket]);
1004
1056
  const applySnapshot = useCallback2((next) => {
1005
1057
  if (next === null) {
1006
1058
  setEnabled(false);
@@ -1020,6 +1072,16 @@ function useLiveMonitor(opts) {
1020
1072
  }
1021
1073
  }
1022
1074
  if (sawNewGoalOrRed && activeTabRef.current !== "matches") setMatchesDot(true);
1075
+ for (const m of next.matches) {
1076
+ if (!pinnedMatchIds.has(m.matchId)) continue;
1077
+ const first = m.availableMarkets?.[0];
1078
+ if (!first) continue;
1079
+ if (m.matchId in openMarketRef.current) continue;
1080
+ const dev = first.marketDeveloperName;
1081
+ openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev };
1082
+ setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }));
1083
+ fetchMarket(m.matchId, dev);
1084
+ }
1023
1085
  const marketPins = currentPins.filter((p) => p.kind !== "match");
1024
1086
  if (activeTabRef.current === "odds") {
1025
1087
  setLastViewedPrices((prevMap) => {
@@ -1070,12 +1132,17 @@ function useLiveMonitor(opts) {
1070
1132
  return;
1071
1133
  }
1072
1134
  applySnapshot(snap);
1135
+ for (const m of snap.matches) {
1136
+ if (m.phase !== "live") continue;
1137
+ const dev = openMarketRef.current[m.matchId];
1138
+ if (dev) fetchMarket(m.matchId, dev);
1139
+ }
1073
1140
  } catch {
1074
1141
  } finally {
1075
1142
  inFlightRef.current = false;
1076
1143
  scheduleRef.current();
1077
1144
  }
1078
- }, [applySnapshot]);
1145
+ }, [applySnapshot, fetchMarket]);
1079
1146
  const scheduleRef = useRef3(() => {
1080
1147
  });
1081
1148
  scheduleRef.current = () => {
@@ -1153,10 +1220,17 @@ function useLiveMonitor(opts) {
1153
1220
  lastViewedPrices,
1154
1221
  inSlip,
1155
1222
  markInSlip,
1223
+ openMarket,
1224
+ marketOdds,
1225
+ toggleMarket,
1226
+ retryMarket,
1156
1227
  _setSnapshot: applySnapshot
1157
1228
  };
1158
1229
  }
1159
1230
 
1231
+ // src/components/ChatFab.tsx
1232
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState3 } from "react";
1233
+
1160
1234
  // src/components/BrandMark.tsx
1161
1235
  import { useState as useState2 } from "react";
1162
1236
 
@@ -1209,23 +1283,39 @@ function BrandMark({ logoUrl, className }) {
1209
1283
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1210
1284
  function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
1211
1285
  return /* @__PURE__ */ jsxs("div", { className: "ss-w-greeting", role: "note", children: [
1212
- /* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: text }),
1286
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
1287
+ /* @__PURE__ */ jsxs("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
1288
+ /* @__PURE__ */ jsx3("i", {}),
1289
+ /* @__PURE__ */ jsx3("i", {}),
1290
+ /* @__PURE__ */ jsx3("i", {})
1291
+ ] }),
1292
+ /* @__PURE__ */ jsx3("span", { className: "ss-w-greeting-text", children: text })
1293
+ ] }),
1213
1294
  onDismiss ? /* @__PURE__ */ jsx3("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null
1214
1295
  ] });
1215
1296
  }
1216
1297
 
1217
1298
  // src/components/ChatFab.tsx
1218
1299
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1219
- function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss" }) {
1300
+ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
1220
1301
  const bubble = popupText ?? greeting;
1221
- return /* @__PURE__ */ jsxs2("div", { className: "ss-w-fab-wrap", children: [
1302
+ const [intro, setIntro] = useState3(false);
1303
+ const armedRef = useRef4(introAllowed);
1304
+ useEffect4(() => {
1305
+ if (armedRef.current && bubble) {
1306
+ armedRef.current = false;
1307
+ setIntro(true);
1308
+ onIntroStart?.();
1309
+ }
1310
+ }, [bubble, onIntroStart]);
1311
+ return /* @__PURE__ */ jsxs2("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
1222
1312
  bubble ? /* @__PURE__ */ jsx4(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel }) : null,
1223
1313
  /* @__PURE__ */ jsx4("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ jsx4(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
1224
1314
  ] });
1225
1315
  }
1226
1316
 
1227
1317
  // src/components/ChatPanel.tsx
1228
- import { useEffect as useEffect8, useState as useState16 } from "react";
1318
+ import { useEffect as useEffect9, useState as useState17 } from "react";
1229
1319
 
1230
1320
  // src/components/ChatHeader.tsx
1231
1321
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -1238,7 +1328,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat", logoUrl, headerTitle }
1238
1328
  }
1239
1329
 
1240
1330
  // src/components/MessageList.tsx
1241
- import { useEffect as useEffect7, useRef as useRef5 } from "react";
1331
+ import { useEffect as useEffect8, useRef as useRef6 } from "react";
1242
1332
 
1243
1333
  // src/components/Markdown.tsx
1244
1334
  import ReactMarkdown from "react-markdown";
@@ -1256,7 +1346,7 @@ function Markdown({ text }) {
1256
1346
  }
1257
1347
 
1258
1348
  // src/components/EntityCardList.tsx
1259
- import { useState as useState3 } from "react";
1349
+ import { useState as useState4 } from "react";
1260
1350
  import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1261
1351
  var MAX_VISIBLE = 3;
1262
1352
  var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
@@ -1340,7 +1430,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
1340
1430
  )) });
1341
1431
  }
1342
1432
  function EntityCardItem({ c }) {
1343
- const [active, setActive] = useState3(0);
1433
+ const [active, setActive] = useState4(0);
1344
1434
  const hasBody = c.scopes.length > 0;
1345
1435
  if (!hasBody) {
1346
1436
  return /* @__PURE__ */ jsx7("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ jsx7(CardHeader, { c, showScopeCrest: false }) });
@@ -1354,7 +1444,7 @@ function EntityCardItem({ c }) {
1354
1444
  ] });
1355
1445
  }
1356
1446
  function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1357
- const [expanded, setExpanded] = useState3(false);
1447
+ const [expanded, setExpanded] = useState4(false);
1358
1448
  if (cards.length === 0) return null;
1359
1449
  const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1360
1450
  const overflow = cards.length - MAX_VISIBLE;
@@ -1365,18 +1455,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
1365
1455
  }
1366
1456
 
1367
1457
  // src/components/BettingInsightList.tsx
1368
- import { useState as useState7 } from "react";
1458
+ import { useState as useState8 } from "react";
1369
1459
 
1370
1460
  // src/components/AddToSlipButton.tsx
1371
- import { useCallback as useCallback3, useState as useState4 } from "react";
1461
+ import { useCallback as useCallback3, useState as useState5 } from "react";
1372
1462
  import { isAddToSlipResult } from "@sensiblestats/widget-sdk";
1373
1463
 
1374
1464
  // src/components/Toast.tsx
1375
- import { useEffect as useEffect4 } from "react";
1465
+ import { useEffect as useEffect5 } from "react";
1376
1466
  import { jsx as jsx8 } from "react/jsx-runtime";
1377
1467
  var DISMISS_MS = 4e3;
1378
1468
  function Toast({ toast, onDismiss }) {
1379
- useEffect4(() => {
1469
+ useEffect5(() => {
1380
1470
  if (!toast) return;
1381
1471
  const timer = setTimeout(onDismiss, DISMISS_MS);
1382
1472
  return () => clearTimeout(timer);
@@ -1394,9 +1484,9 @@ function withTimeout(value) {
1394
1484
  ]);
1395
1485
  }
1396
1486
  function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
1397
- const [pending, setPending] = useState4(false);
1398
- const [settled, setSettled] = useState4(false);
1399
- const [toast, setToast] = useState4(null);
1487
+ const [pending, setPending] = useState5(false);
1488
+ const [settled, setSettled] = useState5(false);
1489
+ const [toast, setToast] = useState5(null);
1400
1490
  const dismiss = useCallback3(() => setToast(null), []);
1401
1491
  const handler = slip.onAddToSlip;
1402
1492
  if (!ui || !handler || !selection) return null;
@@ -1461,14 +1551,14 @@ function OddsMovementBadge({
1461
1551
  }
1462
1552
 
1463
1553
  // src/components/Crest.tsx
1464
- import { useState as useState5 } from "react";
1554
+ import { useState as useState6 } from "react";
1465
1555
  import { jsx as jsx11 } from "react/jsx-runtime";
1466
1556
  function initials2(name) {
1467
1557
  return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
1468
1558
  }
1469
1559
  function Crest2({ url, name, kind }) {
1470
1560
  const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
1471
- const [failed, setFailed] = useState5(false);
1561
+ const [failed, setFailed] = useState6(false);
1472
1562
  if (url && !failed) {
1473
1563
  return /* @__PURE__ */ jsx11("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1474
1564
  }
@@ -1476,10 +1566,15 @@ function Crest2({ url, name, kind }) {
1476
1566
  }
1477
1567
 
1478
1568
  // src/components/PinToggle.tsx
1479
- import { useCallback as useCallback4, useState as useState6 } from "react";
1569
+ import { useCallback as useCallback4, useState as useState7 } from "react";
1480
1570
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1571
+ var PIN_GLYPHS = {
1572
+ 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" },
1573
+ 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" },
1574
+ 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" }
1575
+ };
1481
1576
  function PinToggle({ pin, monitor, ui }) {
1482
- const [toast, setToast] = useState6(null);
1577
+ const [toast, setToast] = useState7(null);
1483
1578
  const dismiss = useCallback4(() => setToast(null), []);
1484
1579
  if (!monitor || !monitor.enabled) return null;
1485
1580
  const key = pinKey(pin);
@@ -1493,6 +1588,7 @@ function PinToggle({ pin, monitor, ui }) {
1493
1588
  setToast({ kind: "error", text: ui.marketLimitToast });
1494
1589
  }
1495
1590
  };
1591
+ const glyph = PIN_GLYPHS[ui.pinIcon];
1496
1592
  return /* @__PURE__ */ jsxs7("div", { className: "ss-w-pin-wrap", children: [
1497
1593
  /* @__PURE__ */ jsx12(
1498
1594
  "button",
@@ -1500,10 +1596,22 @@ function PinToggle({ pin, monitor, ui }) {
1500
1596
  type: "button",
1501
1597
  className: "ss-w-pin",
1502
1598
  "data-on": pinned || void 0,
1599
+ "data-icon": ui.pinIcon,
1503
1600
  "aria-pressed": pinned,
1504
1601
  "aria-label": pinned ? labels.unpin : labels.pin,
1505
1602
  onClick,
1506
- children: /* @__PURE__ */ jsx12("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx12("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" }) })
1603
+ children: /* @__PURE__ */ jsx12("svg", { viewBox: glyph.viewBox, "aria-hidden": "true", children: /* @__PURE__ */ jsx12(
1604
+ "path",
1605
+ {
1606
+ transform: glyph.transform,
1607
+ d: glyph.d,
1608
+ fill: pinned ? "currentColor" : "none",
1609
+ stroke: pinned ? "none" : "currentColor",
1610
+ strokeWidth: glyph.strokeWidth,
1611
+ strokeLinejoin: "round",
1612
+ strokeLinecap: "round"
1613
+ }
1614
+ ) })
1507
1615
  }
1508
1616
  ),
1509
1617
  /* @__PURE__ */ jsx12(Toast, { toast, onDismiss: dismiss })
@@ -1519,7 +1627,7 @@ function StatRows({ stats }) {
1519
1627
  ] }, `${s.label}:${s.value}`)) });
1520
1628
  }
1521
1629
  function ScopedStats({ scopes }) {
1522
- const [active, setActive] = useState7(0);
1630
+ const [active, setActive] = useState8(0);
1523
1631
  const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
1524
1632
  return /* @__PURE__ */ jsxs8("div", { className: "ss-w-bi-scoped", children: [
1525
1633
  /* @__PURE__ */ jsx13("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ jsx13("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
@@ -1530,7 +1638,7 @@ function hasStatsContent(it) {
1530
1638
  return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
1531
1639
  }
1532
1640
  function ReasonStrip({ it, ui }) {
1533
- const [open, setOpen] = useState7(false);
1641
+ const [open, setOpen] = useState8(false);
1534
1642
  const hasScopes = !!it.scopes && it.scopes.length >= 2;
1535
1643
  const hasStats = hasStatsContent(it);
1536
1644
  const hasText = !!it.text;
@@ -1640,7 +1748,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
1640
1748
  }
1641
1749
 
1642
1750
  // src/components/MarketOddsCardList.tsx
1643
- import { useState as useState8 } from "react";
1751
+ import { useState as useState9 } from "react";
1644
1752
  import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1645
1753
  function OddsRow({ vm, row, ui, slip, inSlipIds }) {
1646
1754
  const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
@@ -1656,48 +1764,50 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
1656
1764
  /* @__PURE__ */ jsx14(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
1657
1765
  ] });
1658
1766
  }
1659
- function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
1660
- const [open, setOpen] = useState8(false);
1767
+ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader }) {
1768
+ const [open, setOpen] = useState9(false);
1661
1769
  const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
1662
1770
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
1663
1771
  const showPin = !!monitor && vm.pinEnabled;
1664
1772
  const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin;
1665
1773
  return /* @__PURE__ */ jsxs9("div", { className: "ss-w-mocard", children: [
1666
- showHeader ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-header", children: [
1667
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ jsxs9(Fragment2, { children: [
1668
- /* @__PURE__ */ jsx14(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
1669
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-comp", children: vm.competition })
1670
- ] }) : null }),
1671
- /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-header-right", children: [
1672
- vm.isLive ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-live", children: [
1673
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1674
- ui?.liveLabel ?? "Live"
1675
- ] }) : null,
1676
- kickoff ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-kick", children: [
1677
- kickoff.dayLabel,
1678
- " ",
1679
- kickoff.time
1680
- ] }) : null,
1681
- showPin && ui ? /* @__PURE__ */ jsx14(
1682
- PinToggle,
1683
- {
1684
- ui,
1685
- monitor,
1686
- pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
1687
- }
1688
- ) : null
1689
- ] })
1690
- ] }) : null,
1691
- hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-mo-sub", children: [
1692
- hasNamedTeams ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-fixture", children: [
1693
- /* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
1694
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
1695
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
1696
- /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
1697
- /* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
1698
- ] }) : vm.fixture ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
1699
- vm.market ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-market", children: vm.market }) : null
1700
- ] }) : null,
1774
+ !hideHeader && /* @__PURE__ */ jsxs9(Fragment2, { children: [
1775
+ showHeader ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-header", children: [
1776
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-header-left", children: vm.competition ? /* @__PURE__ */ jsxs9(Fragment2, { children: [
1777
+ /* @__PURE__ */ jsx14(Crest2, { kind: "comp", url: vm.competitionCrest, name: vm.competition }),
1778
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-comp", children: vm.competition })
1779
+ ] }) : null }),
1780
+ /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-header-right", children: [
1781
+ vm.isLive ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-live", children: [
1782
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1783
+ ui?.liveLabel ?? "Live"
1784
+ ] }) : null,
1785
+ kickoff ? /* @__PURE__ */ jsxs9("span", { className: "ss-w-bi-kick", children: [
1786
+ kickoff.dayLabel,
1787
+ " ",
1788
+ kickoff.time
1789
+ ] }) : null,
1790
+ showPin && ui ? /* @__PURE__ */ jsx14(
1791
+ PinToggle,
1792
+ {
1793
+ ui,
1794
+ monitor,
1795
+ pin: { kind: "market", matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }
1796
+ }
1797
+ ) : null
1798
+ ] })
1799
+ ] }) : null,
1800
+ hasNamedTeams || vm.fixture || vm.market ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-mo-sub", children: [
1801
+ hasNamedTeams ? /* @__PURE__ */ jsxs9("div", { className: "ss-w-bi-fixture", children: [
1802
+ /* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.homeCrest, name: vm.homeTeamName }),
1803
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.homeTeamName }),
1804
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-vs", "aria-hidden": "true", children: "vs" }),
1805
+ /* @__PURE__ */ jsx14("span", { className: "ss-w-bi-team", children: vm.awayTeamName }),
1806
+ /* @__PURE__ */ jsx14(Crest2, { kind: "team", url: vm.awayCrest, name: vm.awayTeamName })
1807
+ ] }) : vm.fixture ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-teams", children: vm.fixture }) : null,
1808
+ vm.market ? /* @__PURE__ */ jsx14("span", { className: "ss-w-mo-market", children: vm.market }) : null
1809
+ ] }) : null
1810
+ ] }),
1701
1811
  /* @__PURE__ */ jsxs9("div", { className: "ss-w-mo-rows", children: [
1702
1812
  vm.mainRows.map((row) => /* @__PURE__ */ jsx14(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)),
1703
1813
  open ? vm.moreRows.map((row) => /* @__PURE__ */ jsx14(OddsRow, { vm, row, ui, slip, inSlipIds }, row.key)) : null
@@ -1710,9 +1820,9 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds }) {
1710
1820
  vm.disclaimer ? /* @__PURE__ */ jsx14("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
1711
1821
  ] });
1712
1822
  }
1713
- function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds }) {
1823
+ function MarketOddsCardList({ cards, ui, slip, monitor, inSlipIds, hideHeader }) {
1714
1824
  if (!cards || cards.length === 0) return null;
1715
- return /* @__PURE__ */ jsx14("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx14(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds }, vm.id)) });
1825
+ return /* @__PURE__ */ jsx14("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ jsx14(MarketOddsCard, { vm, ui, slip, monitor, inSlipIds, hideHeader }, vm.id)) });
1716
1826
  }
1717
1827
 
1718
1828
  // src/components/OddsMovementCard.tsx
@@ -1950,7 +2060,7 @@ function FixtureCard({ card }) {
1950
2060
  }
1951
2061
 
1952
2062
  // src/components/dashboard/CountdownCard.tsx
1953
- import { Fragment as Fragment6, useEffect as useEffect5, useState as useState9 } from "react";
2063
+ import { Fragment as Fragment6, useEffect as useEffect6, useState as useState10 } from "react";
1954
2064
  import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1955
2065
  var DAY_MS = 864e5;
1956
2066
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -1969,12 +2079,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
1969
2079
  function CountdownCard({ card }) {
1970
2080
  const { data } = card;
1971
2081
  const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
1972
- const [nowMs, setNowMs] = useState9(() => Date.now());
1973
- const [reduced] = useState9(
2082
+ const [nowMs, setNowMs] = useState10(() => Date.now());
2083
+ const [reduced] = useState10(
1974
2084
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
1975
2085
  );
1976
2086
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
1977
- useEffect5(() => {
2087
+ useEffect6(() => {
1978
2088
  if (reduced) return;
1979
2089
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
1980
2090
  return () => window.clearInterval(id);
@@ -1993,7 +2103,7 @@ function CountdownCard({ card }) {
1993
2103
  }
1994
2104
 
1995
2105
  // src/components/dashboard/InjuriesCard.tsx
1996
- import { useState as useState10 } from "react";
2106
+ import { useState as useState11 } from "react";
1997
2107
  import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1998
2108
  var SHOWN = 3;
1999
2109
  function ColHead({ name, crestUrl }) {
@@ -2016,7 +2126,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
2016
2126
  }
2017
2127
  function InjuriesCard({ card, ui }) {
2018
2128
  const { data } = card;
2019
- const [expanded, setExpanded] = useState10(false);
2129
+ const [expanded, setExpanded] = useState11(false);
2020
2130
  const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
2021
2131
  const limit = expanded ? void 0 : SHOWN;
2022
2132
  const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
@@ -2120,7 +2230,7 @@ function LinksCard({ card }) {
2120
2230
  }
2121
2231
 
2122
2232
  // src/components/dashboard/PostMatchResultCard.tsx
2123
- import { useState as useState11 } from "react";
2233
+ import { useState as useState12 } from "react";
2124
2234
  import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
2125
2235
  function initials3(name) {
2126
2236
  return name.trim().slice(0, 3).toUpperCase();
@@ -2130,7 +2240,7 @@ function PostMatchCrest({
2130
2240
  name,
2131
2241
  side
2132
2242
  }) {
2133
- const [failed, setFailed] = useState11(false);
2243
+ const [failed, setFailed] = useState12(false);
2134
2244
  const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
2135
2245
  if (url && !failed) {
2136
2246
  return /* @__PURE__ */ jsx27("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2329,10 +2439,10 @@ function RestingFormCard({ card }) {
2329
2439
  }
2330
2440
 
2331
2441
  // src/components/dashboard/LiveScoreCard.tsx
2332
- import { useRef as useRef4, useState as useState13 } from "react";
2442
+ import { useRef as useRef5, useState as useState14 } from "react";
2333
2443
 
2334
2444
  // src/useLiveClock.ts
2335
- import { useEffect as useEffect6, useState as useState12 } from "react";
2445
+ import { useEffect as useEffect7, useState as useState13 } from "react";
2336
2446
  var TICK_MS = 6e4;
2337
2447
  var MAX_LIVE_TICK_MINUTES = 15;
2338
2448
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -2341,10 +2451,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
2341
2451
  return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
2342
2452
  }
2343
2453
  function useLiveClock(minute, clockRunning, receivedAtMs) {
2344
- const [displayMinute, setDisplayMinute] = useState12(
2454
+ const [displayMinute, setDisplayMinute] = useState13(
2345
2455
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
2346
2456
  );
2347
- useEffect6(() => {
2457
+ useEffect7(() => {
2348
2458
  setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
2349
2459
  if (!clockRunning) return;
2350
2460
  const id = window.setInterval(() => {
@@ -2361,7 +2471,7 @@ function initials5(name) {
2361
2471
  return name.trim().slice(0, 3).toUpperCase();
2362
2472
  }
2363
2473
  function LiveCrest({ url, name, side }) {
2364
- const [failed, setFailed] = useState13(false);
2474
+ const [failed, setFailed] = useState14(false);
2365
2475
  const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
2366
2476
  if (url && !failed) {
2367
2477
  return /* @__PURE__ */ jsx36("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -2380,7 +2490,7 @@ function LiveScoreCard({
2380
2490
  }) {
2381
2491
  const { data } = card;
2382
2492
  const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
2383
- const seedRef = useRef4(null);
2493
+ const seedRef = useRef5(null);
2384
2494
  if (!seedRef.current || seedRef.current.key !== seedKey) {
2385
2495
  seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
2386
2496
  }
@@ -2420,7 +2530,7 @@ function LiveScoreCard({
2420
2530
  }
2421
2531
 
2422
2532
  // src/components/dashboard/LiveTimelineCard.tsx
2423
- import { useState as useState14 } from "react";
2533
+ import { useState as useState15 } from "react";
2424
2534
  import { jsx as jsx37, jsxs as jsxs32 } from "react/jsx-runtime";
2425
2535
  var SHOWN2 = 3;
2426
2536
  function EventIcon({ type }) {
@@ -2462,7 +2572,7 @@ function EventRow({ e }) {
2462
2572
  ] });
2463
2573
  }
2464
2574
  function LiveTimelineCard({ card, ui }) {
2465
- const [expanded, setExpanded] = useState14(false);
2575
+ const [expanded, setExpanded] = useState15(false);
2466
2576
  const events = card.data.events;
2467
2577
  if (!events || events.length === 0) return null;
2468
2578
  const sorted = [...events].sort((a, b) => b.minute - a.minute);
@@ -2702,11 +2812,11 @@ function turnAnchor(messages) {
2702
2812
  }
2703
2813
  function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
2704
2814
  const { state, send } = controller;
2705
- const listRef = useRef5(null);
2706
- const endRef = useRef5(null);
2707
- const pinnedRef = useRef5(true);
2708
- const anchoredTurnRef = useRef5(null);
2709
- useEffect7(() => {
2815
+ const listRef = useRef6(null);
2816
+ const endRef = useRef6(null);
2817
+ const pinnedRef = useRef6(true);
2818
+ const anchoredTurnRef = useRef6(null);
2819
+ useEffect8(() => {
2710
2820
  const anchor = turnAnchor(state.messages);
2711
2821
  const list = listRef.current;
2712
2822
  if (anchor && anchor.turnId !== anchoredTurnRef.current) {
@@ -2762,10 +2872,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
2762
2872
  }
2763
2873
 
2764
2874
  // src/components/ChatInput.tsx
2765
- import { useState as useState15 } from "react";
2875
+ import { useState as useState16 } from "react";
2766
2876
  import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
2767
2877
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
2768
- const [value, setValue] = useState15("");
2878
+ const [value, setValue] = useState16("");
2769
2879
  const submit = () => {
2770
2880
  const t = value.trim();
2771
2881
  if (!t) return;
@@ -2822,8 +2932,63 @@ function TabBar({ monitor, ui, matchCount, oddsCount }) {
2822
2932
  }) });
2823
2933
  }
2824
2934
 
2825
- // src/components/MonitorMatchCard.tsx
2935
+ // src/components/MarketAccordion.tsx
2826
2936
  import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
2937
+ function MarketAccordion({ match, monitor, ui, slip }) {
2938
+ const markets = match.availableMarkets ?? [];
2939
+ if (markets.length === 0) return null;
2940
+ const open = monitor.openMarket[match.matchId] ?? null;
2941
+ return /* @__PURE__ */ jsx46("div", { className: "ss-w-acc", children: markets.map((m) => {
2942
+ const isOpen = open === m.marketDeveloperName;
2943
+ const key = `${match.matchId}:${m.marketDeveloperName}`;
2944
+ const entry = monitor.marketOdds[key];
2945
+ return /* @__PURE__ */ jsxs40("div", { className: isOpen ? "ss-w-acc-row ss-w-acc-row-open" : "ss-w-acc-row", children: [
2946
+ /* @__PURE__ */ jsxs40(
2947
+ "button",
2948
+ {
2949
+ type: "button",
2950
+ className: "ss-w-acc-head",
2951
+ onClick: () => monitor.toggleMarket(match.matchId, m.marketDeveloperName),
2952
+ children: [
2953
+ /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-chevron", children: isOpen ? "\u25BE" : "\u25B8" }),
2954
+ /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-label", children: m.marketLabel }),
2955
+ m.hasInsight && /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-badge", children: "\u2605" }),
2956
+ m.suspended && /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-susp", children: ui.accordionSuspended })
2957
+ ]
2958
+ }
2959
+ ),
2960
+ isOpen && /* @__PURE__ */ jsxs40("div", { className: "ss-w-acc-panel", children: [
2961
+ entry?.error && /* @__PURE__ */ jsx46(
2962
+ "div",
2963
+ {
2964
+ className: "ss-w-acc-retry",
2965
+ onClick: () => monitor.retryMarket(match.matchId, m.marketDeveloperName),
2966
+ children: ui.accordionRetry
2967
+ }
2968
+ ),
2969
+ entry?.block?.insight?.text && /* @__PURE__ */ jsxs40("div", { className: "ss-w-acc-insight", children: [
2970
+ /* @__PURE__ */ jsx46("span", { className: "ss-w-acc-badge", children: ui.accordionValueLabel }),
2971
+ " ",
2972
+ entry.block.insight.text
2973
+ ] }),
2974
+ entry?.block?.card && /* @__PURE__ */ jsx46(
2975
+ MarketOddsCardList,
2976
+ {
2977
+ cards: [toMarketOddsVM(entry.block.card)],
2978
+ ui,
2979
+ slip,
2980
+ monitor,
2981
+ inSlipIds: monitor.inSlip,
2982
+ hideHeader: true
2983
+ }
2984
+ )
2985
+ ] })
2986
+ ] }, m.marketDeveloperName);
2987
+ }) });
2988
+ }
2989
+
2990
+ // src/components/MonitorMatchCard.tsx
2991
+ import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
2827
2992
  function chipSelection(row, matchId, conversationId) {
2828
2993
  const chip = row.market;
2829
2994
  if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== "number" || typeof chip.price !== "number") return null;
@@ -2846,63 +3011,63 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
2846
3011
  const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins));
2847
3012
  const orderedRows = [...promotedRows, ...otherRows];
2848
3013
  const kickoff = match.phase === "preMatch" && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : void 0;
2849
- return /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon", children: [
2850
- /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-top", children: [
2851
- live && /* @__PURE__ */ jsxs40("span", { className: "ss-w-fandash-live-pill", children: [
2852
- /* @__PURE__ */ jsx46("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
3014
+ return /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon", children: [
3015
+ /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-top", children: [
3016
+ live && /* @__PURE__ */ jsxs41("span", { className: "ss-w-fandash-live-pill", children: [
3017
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
2853
3018
  ui.liveLabel
2854
3019
  ] }),
2855
- match.phase === "fullTime" && /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
2856
- kickoff && /* @__PURE__ */ jsxs40("span", { className: "ss-w-mon-pill", children: [
3020
+ match.phase === "fullTime" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
3021
+ kickoff && /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-pill", children: [
2857
3022
  kickoff.dayLabel,
2858
3023
  " \xB7 ",
2859
3024
  kickoff.time
2860
3025
  ] }),
2861
- live && match.minuteLabel && /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
2862
- match.competitionName && /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-comp", children: match.competitionName }),
2863
- /* @__PURE__ */ jsx46(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
3026
+ live && match.minuteLabel && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-min", children: match.minuteLabel }),
3027
+ match.competitionName && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-comp", children: match.competitionName }),
3028
+ /* @__PURE__ */ jsx47(PinToggle, { ui, monitor, pin: { kind: "match", matchId: match.matchId } })
2864
3029
  ] }),
2865
- /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-main", children: [
2866
- /* @__PURE__ */ jsxs40("span", { className: "ss-w-mon-side", children: [
2867
- /* @__PURE__ */ jsx46(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
2868
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-name", children: match.homeTeamName })
3030
+ /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-main", children: [
3031
+ /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-side", children: [
3032
+ /* @__PURE__ */ jsx47(Crest2, { kind: "team", url: match.homeCrestUrl ?? void 0, name: match.homeTeamName ?? void 0 }),
3033
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: match.homeTeamName })
2869
3034
  ] }),
2870
- match.phase === "preMatch" ? /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ jsxs40("span", { className: "ss-w-mon-score", children: [
3035
+ match.phase === "preMatch" ? /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-vs", children: "vs" }) : /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-score", children: [
2871
3036
  match.homeScore,
2872
- /* @__PURE__ */ jsx46("i", { children: "\u2013" }),
3037
+ /* @__PURE__ */ jsx47("i", { children: "\u2013" }),
2873
3038
  match.awayScore
2874
3039
  ] }),
2875
- /* @__PURE__ */ jsxs40("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
2876
- /* @__PURE__ */ jsx46(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
2877
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-name", children: match.awayTeamName })
3040
+ /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-side ss-w-mon-side--away", children: [
3041
+ /* @__PURE__ */ jsx47(Crest2, { kind: "team", url: match.awayCrestUrl ?? void 0, name: match.awayTeamName ?? void 0 }),
3042
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: match.awayTeamName })
2878
3043
  ] })
2879
3044
  ] }),
2880
- scorers.length > 0 && /* @__PURE__ */ jsx46("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
2881
- /* @__PURE__ */ jsx46("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
3045
+ scorers.length > 0 && /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
3046
+ /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
2882
3047
  const total = row.homeNum + row.awayNum;
2883
3048
  const homePct = total > 0 ? row.homeNum / total * 75 : 0;
2884
3049
  const awayPct = total > 0 ? row.awayNum / total * 75 : 0;
2885
3050
  const promoted = isPromoted(row, promotedPins);
2886
3051
  const selection = chipSelection(row, match.matchId, slip.conversationId);
2887
- return /* @__PURE__ */ jsxs40("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
2888
- /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-stat-row", children: [
2889
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
2890
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-l", children: row.label }),
2891
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
3052
+ return /* @__PURE__ */ jsxs41("div", { className: promoted ? "ss-w-mon-stat ss-w-mon-pstrip" : "ss-w-mon-stat", children: [
3053
+ /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-stat-row", children: [
3054
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: row.homeValue }),
3055
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-l", children: row.label }),
3056
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: row.awayValue })
2892
3057
  ] }),
2893
- /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-bar", children: [
2894
- /* @__PURE__ */ jsx46("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
2895
- /* @__PURE__ */ jsx46("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
3058
+ /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-bar", children: [
3059
+ /* @__PURE__ */ jsx47("b", { className: "ss-w-mon-bar-home", style: { width: `${homePct}%` } }),
3060
+ /* @__PURE__ */ jsx47("i", { className: "ss-w-mon-bar-away", style: { width: `${awayPct}%` } })
2896
3061
  ] }),
2897
- row.market && /* @__PURE__ */ jsxs40("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
2898
- /* @__PURE__ */ jsxs40("span", { children: [
3062
+ row.market && /* @__PURE__ */ jsxs41("div", { className: promoted ? "ss-w-mon-stat-mkt ss-w-mon-mkt" : "ss-w-mon-stat-mkt", children: [
3063
+ /* @__PURE__ */ jsxs41("span", { children: [
2899
3064
  row.market.marketLabel,
2900
3065
  " \xB7 ",
2901
3066
  row.market.selectionLabel
2902
3067
  ] }),
2903
- /* @__PURE__ */ jsxs40("span", { className: "ss-w-mon-stat-mkt-right", children: [
2904
- row.market.isSuspended ? /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
2905
- /* @__PURE__ */ jsx46(
3068
+ /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-stat-mkt-right", children: [
3069
+ row.market.isSuspended ? /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }) : typeof row.market.price === "number" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-price", children: row.market.price.toFixed(2) }),
3070
+ /* @__PURE__ */ jsx47(
2906
3071
  SlipButton,
2907
3072
  {
2908
3073
  selection,
@@ -2916,68 +3081,69 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
2916
3081
  ] })
2917
3082
  ] }, row.label);
2918
3083
  }) }),
2919
- match.status === "stale" && /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
2920
- match.momentum.length > 0 && /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-mom", children: [
2921
- /* @__PURE__ */ jsxs40("div", { className: "ss-w-mon-stat-row", children: [
2922
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
2923
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
2924
- /* @__PURE__ */ jsx46("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
3084
+ match.status === "stale" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-asof", children: ui.asOf(formatTime(match.asOfUtc)) }),
3085
+ match.momentum.length > 0 && /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-mom", children: [
3086
+ /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-stat-row", children: [
3087
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--home", children: typeof match.momentumHomePct === "number" ? `${match.momentumHomePct}%` : "" }),
3088
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-l", children: ui.momentumLabel }),
3089
+ /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-stat-v ss-w-mon-stat-v--away", children: typeof match.momentumHomePct === "number" ? `${100 - match.momentumHomePct}%` : "" })
2925
3090
  ] }),
2926
- /* @__PURE__ */ jsx46(MomentumWave, { points: match.momentum, clubIsHome: true })
3091
+ /* @__PURE__ */ jsx47(MomentumWave, { points: match.momentum, clubIsHome: true })
2927
3092
  ] }),
2928
- match.mainMarket && match.phase !== "fullTime" && /* @__PURE__ */ jsx46(MarketOddsCardList, { cards: [toMarketOddsVM(match.mainMarket)], ui, slip }),
2929
- match.phase === "fullTime" && /* @__PURE__ */ jsx46("div", { className: "ss-w-mon-grace", children: ui.graceNote })
3093
+ match.phase === "fullTime" && /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-grace", children: ui.graceNote })
2930
3094
  ] });
2931
3095
  }
2932
3096
 
2933
3097
  // src/components/MonitorTabs.tsx
2934
- import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
3098
+ import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
2935
3099
  function ContextLine({ m, monitor, ui }) {
2936
3100
  const kick = m.kickoffUtc ? ui.bettingKickoff(m.kickoffUtc) : void 0;
2937
- return /* @__PURE__ */ jsxs41("div", { className: "ss-w-mk-ctx", children: [
2938
- /* @__PURE__ */ jsxs41("span", { className: "ss-w-mk-ctx-side", children: [
2939
- /* @__PURE__ */ jsx47(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
2940
- /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: m.homeTeamName })
3101
+ return /* @__PURE__ */ jsxs42("div", { className: "ss-w-mk-ctx", children: [
3102
+ /* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-side", children: [
3103
+ /* @__PURE__ */ jsx48(Crest2, { kind: "team", url: m.homeCrestUrl ?? void 0, name: m.homeTeamName ?? void 0 }),
3104
+ /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-name", children: m.homeTeamName })
2941
3105
  ] }),
2942
- m.phase === "preMatch" ? kick && /* @__PURE__ */ jsxs41("span", { className: "ss-w-mon-pill", children: [
3106
+ m.phase === "preMatch" ? kick && /* @__PURE__ */ jsxs42("span", { className: "ss-w-mon-pill", children: [
2943
3107
  kick.dayLabel,
2944
3108
  " ",
2945
3109
  kick.time
2946
- ] }) : typeof m.homeScore === "number" && /* @__PURE__ */ jsxs41("b", { children: [
3110
+ ] }) : typeof m.homeScore === "number" && /* @__PURE__ */ jsxs42("b", { children: [
2947
3111
  m.homeScore,
2948
3112
  "\u2013",
2949
3113
  m.awayScore
2950
3114
  ] }),
2951
- /* @__PURE__ */ jsxs41("span", { className: "ss-w-mk-ctx-side", children: [
2952
- /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
2953
- /* @__PURE__ */ jsx47(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
3115
+ /* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-side", children: [
3116
+ /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-name", children: m.awayTeamName }),
3117
+ /* @__PURE__ */ jsx48(Crest2, { kind: "team", url: m.awayCrestUrl ?? void 0, name: m.awayTeamName ?? void 0 })
2954
3118
  ] }),
2955
- m.minuteLabel && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
2956
- /* @__PURE__ */ jsxs41("span", { className: "ss-w-mk-ctx-right", children: [
2957
- m.isSuspended && !m.isSettled && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
2958
- m.isSettled && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
2959
- m.status === "stale" && /* @__PURE__ */ jsx47("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
3119
+ m.minuteLabel && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-min", children: m.minuteLabel }),
3120
+ /* @__PURE__ */ jsxs42("span", { className: "ss-w-mk-ctx-right", children: [
3121
+ m.isSuspended && !m.isSettled && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-susp", children: ui.suspendedLabel }),
3122
+ m.isSettled && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-pill", children: ui.fullTimeLabel }),
3123
+ m.status === "stale" && /* @__PURE__ */ jsx48("span", { className: "ss-w-mon-asof", children: ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })) }),
2960
3124
  (() => {
2961
3125
  const pin = monitor.pins.find((p) => p.key === m.key);
2962
- return pin ? /* @__PURE__ */ jsx47(PinToggle, { ui, monitor, pin }) : null;
3126
+ return pin ? /* @__PURE__ */ jsx48(PinToggle, { ui, monitor, pin }) : null;
2963
3127
  })()
2964
3128
  ] })
2965
3129
  ] });
2966
3130
  }
2967
3131
  function MatchesPanel({ monitor, ui, slip }) {
2968
3132
  const matches = (monitor.snapshot?.matches ?? []).filter((m) => monitor.pins.some((p) => p.kind === "match" && p.matchId === m.matchId));
2969
- if (matches.length === 0) return /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
2970
- return /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ jsx47(
2971
- MonitorMatchCard,
2972
- {
2973
- match: m,
2974
- promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
2975
- monitor,
2976
- ui,
2977
- slip
2978
- },
2979
- m.matchId
2980
- )) });
3133
+ if (matches.length === 0) return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty", children: ui.emptyMatchesTab });
3134
+ return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-list", children: matches.map((m) => /* @__PURE__ */ jsxs42("div", { className: "ss-w-mon-item", children: [
3135
+ /* @__PURE__ */ jsx48(
3136
+ MonitorMatchCard,
3137
+ {
3138
+ match: m,
3139
+ promotedPins: monitor.pins.filter((p) => p.kind !== "match" && p.matchId === m.matchId),
3140
+ monitor,
3141
+ ui,
3142
+ slip
3143
+ }
3144
+ ),
3145
+ /* @__PURE__ */ jsx48(MarketAccordion, { match: m, monitor, ui, slip })
3146
+ ] }, m.matchId)) });
2981
3147
  }
2982
3148
  function withSinceViewMovement(vm, prev) {
2983
3149
  const primary = vm.mainRows[0];
@@ -2991,10 +3157,10 @@ function withSinceViewMovement(vm, prev) {
2991
3157
  }
2992
3158
  function OddsPanel({ monitor, ui, slip }) {
2993
3159
  const markets = (monitor.snapshot?.markets ?? []).filter((m) => monitor.pins.some((p) => p.key === m.key));
2994
- if (markets.length === 0) return /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
2995
- return /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ jsxs41("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
2996
- /* @__PURE__ */ jsx47(ContextLine, { m, monitor, ui }),
2997
- m.card && /* @__PURE__ */ jsx47(
3160
+ if (markets.length === 0) return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty", children: ui.emptyOddsTab });
3161
+ return /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-list", children: markets.map((m) => /* @__PURE__ */ jsxs42("div", { className: "ss-w-mon-oddspin", "data-settled": m.isSettled || void 0, children: [
3162
+ /* @__PURE__ */ jsx48(ContextLine, { m, monitor, ui }),
3163
+ m.card && /* @__PURE__ */ jsx48(
2998
3164
  MarketOddsCardList,
2999
3165
  {
3000
3166
  cards: [withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])],
@@ -3003,17 +3169,17 @@ function OddsPanel({ monitor, ui, slip }) {
3003
3169
  inSlipIds: monitor.inSlip
3004
3170
  }
3005
3171
  ),
3006
- m.history && /* @__PURE__ */ jsx47(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
3007
- !m.card && !m.history && /* @__PURE__ */ jsx47("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
3172
+ m.history && /* @__PURE__ */ jsx48(OddsMovementCardList, { cards: [toOddsMovementVM(m.history)], ui }),
3173
+ !m.card && !m.history && /* @__PURE__ */ jsx48("div", { className: "ss-w-mon-empty-card", children: ui.oddsUnavailable })
3008
3174
  ] }, m.key)) });
3009
3175
  }
3010
3176
 
3011
3177
  // src/components/ChatPanel.tsx
3012
- import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
3178
+ import { jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
3013
3179
  var FULLSCREEN_QUERY = "(max-width: 639px)";
3014
3180
  function useIsModal() {
3015
- const [modal, setModal] = useState16(false);
3016
- useEffect8(() => {
3181
+ const [modal, setModal] = useState17(false);
3182
+ useEffect9(() => {
3017
3183
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
3018
3184
  const mql = window.matchMedia(FULLSCREEN_QUERY);
3019
3185
  const sync = () => setModal(mql.matches);
@@ -3026,7 +3192,7 @@ function useIsModal() {
3026
3192
  function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3027
3193
  const { state, close, stop, send } = controller;
3028
3194
  const isModal = useIsModal();
3029
- useEffect8(() => {
3195
+ useEffect9(() => {
3030
3196
  const onKey = (e) => {
3031
3197
  if (e.key === "Escape") close();
3032
3198
  };
@@ -3037,12 +3203,12 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3037
3203
  monitor?.setActiveTab("chat");
3038
3204
  send(text);
3039
3205
  };
3040
- useEffect8(() => {
3206
+ useEffect9(() => {
3041
3207
  if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
3042
3208
  }, [monitor, state.isStreaming, state.messages.length]);
3043
- return /* @__PURE__ */ jsxs42("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
3044
- /* @__PURE__ */ jsx48(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
3045
- monitor && /* @__PURE__ */ jsx48(
3209
+ return /* @__PURE__ */ jsxs43("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
3210
+ /* @__PURE__ */ jsx49(ChatHeader, { onClose: close, closeLabel: ui.closeChat, logoUrl: ui.logoUrl, headerTitle: ui.headerTitle }),
3211
+ monitor && /* @__PURE__ */ jsx49(
3046
3212
  TabBar,
3047
3213
  {
3048
3214
  monitor,
@@ -3051,16 +3217,16 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor }) {
3051
3217
  oddsCount: monitor.pins.filter((p) => p.kind !== "match").length
3052
3218
  }
3053
3219
  ),
3054
- /* @__PURE__ */ jsx48(
3220
+ /* @__PURE__ */ jsx49(
3055
3221
  "div",
3056
3222
  {
3057
3223
  style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
3058
- children: /* @__PURE__ */ jsx48(MessageList, { controller, ui, slip, onDashboardTap, monitor })
3224
+ children: /* @__PURE__ */ jsx49(MessageList, { controller, ui, slip, onDashboardTap, monitor })
3059
3225
  }
3060
3226
  ),
3061
- monitor && monitor.activeTab === "matches" && /* @__PURE__ */ jsx48(MatchesPanel, { monitor, ui, slip }),
3062
- monitor && monitor.activeTab === "odds" && /* @__PURE__ */ jsx48(OddsPanel, { monitor, ui, slip }),
3063
- /* @__PURE__ */ jsx48(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
3227
+ monitor && monitor.activeTab === "matches" && /* @__PURE__ */ jsx49(MatchesPanel, { monitor, ui, slip }),
3228
+ monitor && monitor.activeTab === "odds" && /* @__PURE__ */ jsx49(OddsPanel, { monitor, ui, slip }),
3229
+ /* @__PURE__ */ jsx49(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
3064
3230
  ] });
3065
3231
  }
3066
3232
 
@@ -3108,8 +3274,40 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3108
3274
  .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); }
3109
3275
  .ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }
3110
3276
  .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); }
3111
- .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; }
3277
+ .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; }
3112
3278
  .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; }
3279
+ .ss-w-greeting-text { display: block; }
3280
+ /* Typing indicator: overlays the text area so bubble height stays put; hidden at
3281
+ rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */
3282
+ .ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }
3283
+ .ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }
3284
+ /* One-shot launcher attention intro: FAB nudges, then the greeting types in.
3285
+ Gated behind no-preference so reduce-motion users get the greeting shown
3286
+ statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once
3287
+ per page load; every animation runs a single time and settles at rest. */
3288
+ @media (prefers-reduced-motion: no-preference) {
3289
+ .ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }
3290
+ .ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }
3291
+ .ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }
3292
+ .ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }
3293
+ .ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }
3294
+ .ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }
3295
+ .ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }
3296
+ }
3297
+ @keyframes ss-w-nudge {
3298
+ 0%, 100% { transform: none; }
3299
+ 22% { transform: translateY(-9px) rotate(-9deg); }
3300
+ 44% { transform: translateY(0) rotate(7deg); }
3301
+ 64% { transform: translateY(-4px) rotate(-4deg); }
3302
+ 82% { transform: rotate(2deg); }
3303
+ }
3304
+ @keyframes ss-w-greet-in {
3305
+ from { opacity: 0; transform: translateY(8px) scale(.92); }
3306
+ to { opacity: 1; transform: none; }
3307
+ }
3308
+ @keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }
3309
+ @keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }
3310
+ @keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
3113
3311
 
3114
3312
  /* panel */
3115
3313
  .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); }
@@ -3813,10 +4011,23 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3813
4011
  .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); }
3814
4012
  .ss-w-mon-oddspin[data-settled] .ss-w-mo-price,
3815
4013
  .ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }
4014
+
4015
+ /* market accordion (Task 9): one collapsed row per available market, expanding into a reused
4016
+ MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */
4017
+ .ss-w-acc { display: flex; flex-direction: column; gap: 6px; }
4018
+ .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; }
4019
+ .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); }
4020
+ .ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; }
4021
+ .ss-w-acc-label { font-size: 12.5px; font-weight: 600; }
4022
+ .ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); }
4023
+ .ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); }
4024
+ .ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }
4025
+ .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; }
4026
+ .ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }
3816
4027
  `;
3817
4028
 
3818
4029
  // src/StatsWidget.tsx
3819
- import { jsx as jsx49 } from "react/jsx-runtime";
4030
+ import { jsx as jsx50 } from "react/jsx-runtime";
3820
4031
  function buildClient(props) {
3821
4032
  try {
3822
4033
  if ("client" in props && props.client) {
@@ -3843,10 +4054,15 @@ function StatsWidget(props) {
3843
4054
  const cfg = props.config;
3844
4055
  const built = useMemo2(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
3845
4056
  const ui = useMemo2(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
3846
- const rootRef = useRef6(null);
4057
+ const rootRef = useRef7(null);
4058
+ const introDoneRef = useRef7(false);
4059
+ const markIntroDone = useCallback5(() => {
4060
+ introDoneRef.current = true;
4061
+ }, []);
3847
4062
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
3848
4063
  const monitor = useLiveMonitor({
3849
4064
  getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
4065
+ getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
3850
4066
  storageKey: `ss-w-pins:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`,
3851
4067
  isOpen: controller.state.isOpen
3852
4068
  });
@@ -3877,14 +4093,14 @@ function StatsWidget(props) {
3877
4093
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
3878
4094
  [built]
3879
4095
  );
3880
- useEffect9(() => {
4096
+ useEffect10(() => {
3881
4097
  if (!built || !ui.injectStyles) return;
3882
4098
  const node = rootRef.current?.getRootNode();
3883
4099
  if (node) injectStyles(node);
3884
4100
  }, [built, ui.injectStyles]);
3885
4101
  if (!built) return null;
3886
4102
  const attrs = themeAttrs(ui);
3887
- return /* @__PURE__ */ jsx49("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__ */ jsx49(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ jsx49(
4103
+ return /* @__PURE__ */ jsx50("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__ */ jsx50(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0 }) : /* @__PURE__ */ jsx50(
3888
4104
  ChatFab,
3889
4105
  {
3890
4106
  label: ui.launcherLabel,
@@ -3893,7 +4109,9 @@ function StatsWidget(props) {
3893
4109
  logoUrl: ui.logoUrl,
3894
4110
  onOpen: controller.open,
3895
4111
  onDismissPopup: controller.dismissPopup,
3896
- dismissLabel: ui.dismissGreeting
4112
+ dismissLabel: ui.dismissGreeting,
4113
+ introAllowed: !introDoneRef.current,
4114
+ onIntroStart: markIntroDone
3897
4115
  }
3898
4116
  ) });
3899
4117
  }