@sensiblestats/widget-react 0.48.10 → 0.50.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_react26 = require("react");
39
+ var import_react39 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/kickoff.ts
@@ -120,6 +120,7 @@ var STRINGS = {
120
120
  graceNote: "Unpins on next open \xB7 or in 4 h",
121
121
  suspendedLabel: "Suspended",
122
122
  fullTimeLabel: "Full time",
123
+ ownGoalLabel: "OG",
123
124
  inSlipLabel: "In slip",
124
125
  oddsUnavailable: "Odds unavailable right now",
125
126
  momentumLabel: "Momentum",
@@ -129,7 +130,18 @@ var STRINGS = {
129
130
  tabToday: "Today",
130
131
  sectionLive: "Live",
131
132
  halfTime: "HT",
132
- staleStates: "Live scores can't be updated \u2014 showing the last known state."
133
+ staleStates: "Live scores can't be updated \u2014 showing the last known state.",
134
+ tabGames: "Games",
135
+ tabLeaderboard: "Leaderboard",
136
+ gamesLoginRequired: "Sign in to play and climb the leaderboard",
137
+ back: "Back",
138
+ leaderboardOffBoard: "Outside top 50",
139
+ leaderboardThisWeek: "This week",
140
+ leaderboardAllTime: "All time",
141
+ gamePlay: "Play",
142
+ gameResume: "Resume",
143
+ gameLocked: "Locked",
144
+ gameVoided: "Voided"
133
145
  },
134
146
  tr: {
135
147
  launcherLabel: "SensibleStats ile sohbet et",
@@ -198,6 +210,7 @@ var STRINGS = {
198
210
  graceNote: "Bir sonraki a\xE7\u0131l\u0131\u015Fta kald\u0131r\u0131l\u0131r \xB7 en ge\xE7 4 saat",
199
211
  suspendedLabel: "Ask\u0131da",
200
212
  fullTimeLabel: "Ma\xE7 sonu",
213
+ ownGoalLabel: "KK",
201
214
  inSlipLabel: "Kuponda",
202
215
  oddsUnavailable: "Oranlar \u015Fu anda kullan\u0131lam\u0131yor",
203
216
  momentumLabel: "Momentum",
@@ -207,7 +220,18 @@ var STRINGS = {
207
220
  tabToday: "Bug\xFCn",
208
221
  sectionLive: "Canl\u0131",
209
222
  halfTime: "\u0130Y",
210
- staleStates: "Canl\u0131 skorlar g\xFCncellenemiyor \u2014 son bilinen durum g\xF6steriliyor."
223
+ staleStates: "Canl\u0131 skorlar g\xFCncellenemiyor \u2014 son bilinen durum g\xF6steriliyor.",
224
+ tabGames: "Oyunlar",
225
+ tabLeaderboard: "Lider Tablosu",
226
+ gamesLoginRequired: "Oynamak ve lider tablosuna girmek i\xE7in giri\u015F yap\u0131n",
227
+ back: "Geri",
228
+ leaderboardOffBoard: "\u0130lk 50 d\u0131\u015F\u0131nda",
229
+ leaderboardThisWeek: "Bu hafta",
230
+ leaderboardAllTime: "T\xFCm zamanlar",
231
+ gamePlay: "Oyna",
232
+ gameResume: "Devam et",
233
+ gameLocked: "Kilitli",
234
+ gameVoided: "\u0130ptal edildi"
211
235
  }
212
236
  };
213
237
  function resolveLocaleStrings(locale) {
@@ -299,12 +323,24 @@ function normalizeUi(cfg) {
299
323
  graceNote: strings.graceNote,
300
324
  suspendedLabel: strings.suspendedLabel,
301
325
  fullTimeLabel: strings.fullTimeLabel,
326
+ ownGoalLabel: strings.ownGoalLabel,
302
327
  inSlipLabel: strings.inSlipLabel,
303
328
  oddsUnavailable: strings.oddsUnavailable,
304
329
  momentumLabel: strings.momentumLabel,
305
330
  accordionValueLabel: strings.accordionValueLabel,
306
331
  accordionRetry: strings.accordionRetry,
307
- accordionSuspended: strings.accordionSuspended
332
+ accordionSuspended: strings.accordionSuspended,
333
+ tabGames: strings.tabGames,
334
+ tabLeaderboard: strings.tabLeaderboard,
335
+ gamesLoginRequired: strings.gamesLoginRequired,
336
+ back: strings.back,
337
+ leaderboardOffBoard: strings.leaderboardOffBoard,
338
+ leaderboardThisWeek: strings.leaderboardThisWeek,
339
+ leaderboardAllTime: strings.leaderboardAllTime,
340
+ gamePlay: strings.gamePlay,
341
+ gameResume: strings.gameResume,
342
+ gameLocked: strings.gameLocked,
343
+ gameVoided: strings.gameVoided
308
344
  };
309
345
  }
310
346
  function toClientOptions(cfg) {
@@ -1139,7 +1175,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
1139
1175
  }
1140
1176
 
1141
1177
  // src/useLiveMonitor.ts
1142
- var import_react3 = require("react");
1178
+ var import_react4 = require("react");
1143
1179
 
1144
1180
  // src/pinStore.ts
1145
1181
  var MAX_MATCH_PINS = 5;
@@ -1201,6 +1237,13 @@ function createPinStore(storageKey, sessionId, onChange) {
1201
1237
  };
1202
1238
  }
1203
1239
 
1240
+ // src/useTabs.ts
1241
+ var import_react3 = require("react");
1242
+ function useTabs(initial = "chat") {
1243
+ const [activeTab, setActiveTab] = (0, import_react3.useState)(initial);
1244
+ return { activeTab, setActiveTab };
1245
+ }
1246
+
1204
1247
  // src/useLiveMonitor.ts
1205
1248
  var GOAL_OR_RED = /* @__PURE__ */ new Set(["goal", "red"]);
1206
1249
  var MIN_POLL_MS = 5e3;
@@ -1221,37 +1264,37 @@ function phaseForPin(snapshot, pin) {
1221
1264
  return snapshot.markets.find((mk) => mk.key === pin.key)?.phase;
1222
1265
  }
1223
1266
  function useLiveMonitor(opts) {
1224
- const sessionIdRef = (0, import_react3.useRef)(crypto.randomUUID());
1225
- const [pins, setPins] = (0, import_react3.useState)([]);
1226
- const [store] = (0, import_react3.useState)(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins));
1227
- const [enabled, setEnabled] = (0, import_react3.useState)(true);
1228
- const [snapshot, setSnapshotState] = (0, import_react3.useState)(null);
1229
- const [activeTab, setActiveTabState] = (0, import_react3.useState)("chat");
1230
- const [chatDot, setChatDot] = (0, import_react3.useState)(false);
1231
- const [matchesDot, setMatchesDot] = (0, import_react3.useState)(false);
1232
- const [oddsDot, setOddsDot] = (0, import_react3.useState)(false);
1233
- const [todayDot, setTodayDot] = (0, import_react3.useState)(false);
1234
- const [lastViewedPrices, setLastViewedPrices] = (0, import_react3.useState)({});
1235
- const [inSlip, setInSlip] = (0, import_react3.useState)({});
1236
- const [openMarket, setOpenMarket] = (0, import_react3.useState)({});
1237
- const [marketOdds, setMarketOdds] = (0, import_react3.useState)({});
1238
- const pinsRef = (0, import_react3.useRef)(pins);
1267
+ const sessionIdRef = (0, import_react4.useRef)(crypto.randomUUID());
1268
+ const [pins, setPins] = (0, import_react4.useState)([]);
1269
+ const [store] = (0, import_react4.useState)(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins));
1270
+ const [enabled, setEnabled] = (0, import_react4.useState)(true);
1271
+ const [snapshot, setSnapshotState] = (0, import_react4.useState)(null);
1272
+ const { activeTab, setActiveTab: setActiveTabState } = useTabs("chat");
1273
+ const [chatDot, setChatDot] = (0, import_react4.useState)(false);
1274
+ const [matchesDot, setMatchesDot] = (0, import_react4.useState)(false);
1275
+ const [oddsDot, setOddsDot] = (0, import_react4.useState)(false);
1276
+ const [todayDot, setTodayDot] = (0, import_react4.useState)(false);
1277
+ const [lastViewedPrices, setLastViewedPrices] = (0, import_react4.useState)({});
1278
+ const [inSlip, setInSlip] = (0, import_react4.useState)({});
1279
+ const [openMarket, setOpenMarket] = (0, import_react4.useState)({});
1280
+ const [marketOdds, setMarketOdds] = (0, import_react4.useState)({});
1281
+ const pinsRef = (0, import_react4.useRef)(pins);
1239
1282
  pinsRef.current = pins;
1240
- const activeTabRef = (0, import_react3.useRef)(activeTab);
1283
+ const activeTabRef = (0, import_react4.useRef)(activeTab);
1241
1284
  activeTabRef.current = activeTab;
1242
- const snapshotRef = (0, import_react3.useRef)(snapshot);
1285
+ const snapshotRef = (0, import_react4.useRef)(snapshot);
1243
1286
  snapshotRef.current = snapshot;
1244
- const lastViewedPricesRef = (0, import_react3.useRef)(lastViewedPrices);
1287
+ const lastViewedPricesRef = (0, import_react4.useRef)(lastViewedPrices);
1245
1288
  lastViewedPricesRef.current = lastViewedPrices;
1246
- const openMarketRef = (0, import_react3.useRef)(openMarket);
1289
+ const openMarketRef = (0, import_react4.useRef)(openMarket);
1247
1290
  openMarketRef.current = openMarket;
1248
- const marketOddsRef = (0, import_react3.useRef)(marketOdds);
1291
+ const marketOddsRef = (0, import_react4.useRef)(marketOdds);
1249
1292
  marketOddsRef.current = marketOdds;
1250
1293
  const hasToday = opts.hasToday ?? false;
1251
1294
  const marketKey = (matchId, dev) => `${matchId}:${dev}`;
1252
- const getMarketOddsRef = (0, import_react3.useRef)(opts.getMarketOdds);
1295
+ const getMarketOddsRef = (0, import_react4.useRef)(opts.getMarketOdds);
1253
1296
  getMarketOddsRef.current = opts.getMarketOdds;
1254
- const fetchMarket = (0, import_react3.useCallback)((matchId, dev) => {
1297
+ const fetchMarket = (0, import_react4.useCallback)((matchId, dev) => {
1255
1298
  const key = marketKey(matchId, dev);
1256
1299
  const existing = marketOddsRef.current[key];
1257
1300
  if (existing?.loading) return;
@@ -1270,7 +1313,7 @@ function useLiveMonitor(opts) {
1270
1313
  setMarketOdds((prev) => ({ ...prev, [key]: entry }));
1271
1314
  });
1272
1315
  }, []);
1273
- const toggleMarket = (0, import_react3.useCallback)((matchId, dev) => {
1316
+ const toggleMarket = (0, import_react4.useCallback)((matchId, dev) => {
1274
1317
  const key = marketKey(matchId, dev);
1275
1318
  const wasOpen = openMarketRef.current[matchId] === dev;
1276
1319
  const nextValue = wasOpen ? null : dev;
@@ -1281,10 +1324,10 @@ function useLiveMonitor(opts) {
1281
1324
  fetchMarket(matchId, dev);
1282
1325
  }
1283
1326
  }, [fetchMarket]);
1284
- const retryMarket = (0, import_react3.useCallback)((matchId, dev) => {
1327
+ const retryMarket = (0, import_react4.useCallback)((matchId, dev) => {
1285
1328
  fetchMarket(matchId, dev);
1286
1329
  }, [fetchMarket]);
1287
- const applySnapshot = (0, import_react3.useCallback)((next) => {
1330
+ const applySnapshot = (0, import_react4.useCallback)((next) => {
1288
1331
  if (next === null) {
1289
1332
  setEnabled(false);
1290
1333
  return;
@@ -1347,12 +1390,12 @@ function useLiveMonitor(opts) {
1347
1390
  snapshotRef.current = next;
1348
1391
  setSnapshotState(next);
1349
1392
  }, [store]);
1350
- const inFlightRef = (0, import_react3.useRef)(false);
1351
- const timerRef = (0, import_react3.useRef)(void 0);
1352
- const disabledRef = (0, import_react3.useRef)(false);
1353
- const getLiveMonitorRef = (0, import_react3.useRef)(opts.getLiveMonitor);
1393
+ const inFlightRef = (0, import_react4.useRef)(false);
1394
+ const timerRef = (0, import_react4.useRef)(void 0);
1395
+ const disabledRef = (0, import_react4.useRef)(false);
1396
+ const getLiveMonitorRef = (0, import_react4.useRef)(opts.getLiveMonitor);
1354
1397
  getLiveMonitorRef.current = opts.getLiveMonitor;
1355
- const tick = (0, import_react3.useCallback)(async () => {
1398
+ const tick = (0, import_react4.useCallback)(async () => {
1356
1399
  if (inFlightRef.current || disabledRef.current || pinsRef.current.length === 0) return;
1357
1400
  inFlightRef.current = true;
1358
1401
  try {
@@ -1374,7 +1417,7 @@ function useLiveMonitor(opts) {
1374
1417
  scheduleRef.current();
1375
1418
  }
1376
1419
  }, [applySnapshot, fetchMarket]);
1377
- const scheduleRef = (0, import_react3.useRef)(() => {
1420
+ const scheduleRef = (0, import_react4.useRef)(() => {
1378
1421
  });
1379
1422
  scheduleRef.current = () => {
1380
1423
  window.clearTimeout(timerRef.current);
@@ -1382,8 +1425,8 @@ function useLiveMonitor(opts) {
1382
1425
  const hinted = (snapshotRef.current?.nextPollSeconds ?? DEFAULT_POLL_MS / 1e3) * 1e3;
1383
1426
  timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted));
1384
1427
  };
1385
- const prevPinsLengthRef = (0, import_react3.useRef)(0);
1386
- (0, import_react3.useEffect)(() => {
1428
+ const prevPinsLengthRef = (0, import_react4.useRef)(0);
1429
+ (0, import_react4.useEffect)(() => {
1387
1430
  const wasEmpty = prevPinsLengthRef.current === 0;
1388
1431
  prevPinsLengthRef.current = pins.length;
1389
1432
  if (pins.length === 0) {
@@ -1392,20 +1435,20 @@ function useLiveMonitor(opts) {
1392
1435
  }
1393
1436
  if (wasEmpty) void tick();
1394
1437
  }, [pins.length, tick]);
1395
- (0, import_react3.useEffect)(() => {
1438
+ (0, import_react4.useEffect)(() => {
1396
1439
  const matchPins = pins.filter((p) => p.kind === "match").length;
1397
1440
  const marketPins = pins.length - matchPins;
1398
1441
  if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
1399
1442
  if (activeTab === "odds" && marketPins === 0) setActiveTabState(hasToday ? "today" : "chat");
1400
1443
  if (activeTab === "today" && !hasToday) setActiveTabState("chat");
1401
1444
  }, [pins, activeTab, hasToday]);
1402
- const prevIsOpenRef = (0, import_react3.useRef)(false);
1403
- (0, import_react3.useEffect)(() => {
1445
+ const prevIsOpenRef = (0, import_react4.useRef)(false);
1446
+ (0, import_react4.useEffect)(() => {
1404
1447
  const wasClosed = !prevIsOpenRef.current;
1405
1448
  prevIsOpenRef.current = opts.isOpen;
1406
1449
  if (wasClosed && opts.isOpen) void tick();
1407
1450
  }, [opts.isOpen, tick]);
1408
- (0, import_react3.useEffect)(() => {
1451
+ (0, import_react4.useEffect)(() => {
1409
1452
  const onVisibility = () => {
1410
1453
  if (document.visibilityState === "hidden") window.clearTimeout(timerRef.current);
1411
1454
  else void tick();
@@ -1416,7 +1459,7 @@ function useLiveMonitor(opts) {
1416
1459
  window.clearTimeout(timerRef.current);
1417
1460
  };
1418
1461
  }, [tick]);
1419
- const setActiveTab = (0, import_react3.useCallback)((tab) => {
1462
+ const setActiveTab = (0, import_react4.useCallback)((tab) => {
1420
1463
  setActiveTabState(tab);
1421
1464
  if (tab === "chat") setChatDot(false);
1422
1465
  if (tab === "today") setTodayDot(false);
@@ -1437,13 +1480,13 @@ function useLiveMonitor(opts) {
1437
1480
  void tick();
1438
1481
  }
1439
1482
  }, [tick]);
1440
- const togglePin = (0, import_react3.useCallback)((pin) => store.toggle(pin), [store]);
1441
- const isPinned = (0, import_react3.useCallback)((key) => pinsRef.current.some((p) => p.key === key), []);
1442
- const markChatActivity = (0, import_react3.useCallback)(() => setChatDot(true), []);
1443
- const markTodayActivity = (0, import_react3.useCallback)(() => {
1483
+ const togglePin = (0, import_react4.useCallback)((pin) => store.toggle(pin), [store]);
1484
+ const isPinned = (0, import_react4.useCallback)((key) => pinsRef.current.some((p) => p.key === key), []);
1485
+ const markChatActivity = (0, import_react4.useCallback)(() => setChatDot(true), []);
1486
+ const markTodayActivity = (0, import_react4.useCallback)(() => {
1444
1487
  if (activeTabRef.current !== "today") setTodayDot(true);
1445
1488
  }, []);
1446
- const markInSlip = (0, import_react3.useCallback)((matchOddsId) => {
1489
+ const markInSlip = (0, import_react4.useCallback)((matchOddsId) => {
1447
1490
  setInSlip((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
1448
1491
  }, []);
1449
1492
  return {
@@ -1472,7 +1515,7 @@ function useLiveMonitor(opts) {
1472
1515
  }
1473
1516
 
1474
1517
  // src/useMatchDiscovery.ts
1475
- var import_react4 = require("react");
1518
+ var import_react5 = require("react");
1476
1519
 
1477
1520
  // src/scheduleCache.ts
1478
1521
  var PREFIX = "ss-w-schedule:";
@@ -1560,27 +1603,27 @@ function localDateOf(now) {
1560
1603
  return `${y}-${m}-${d}`;
1561
1604
  }
1562
1605
  function useMatchDiscovery(opts) {
1563
- const [groups, setGroups] = (0, import_react4.useState)([]);
1564
- const [states, setStates] = (0, import_react4.useState)({});
1565
- const [failures, setFailures] = (0, import_react4.useState)(0);
1566
- const [expanded, setExpanded] = (0, import_react4.useState)({});
1567
- const [touched, setTouched] = (0, import_react4.useState)({});
1568
- const groupsRef = (0, import_react4.useRef)(groups);
1606
+ const [groups, setGroups] = (0, import_react5.useState)([]);
1607
+ const [states, setStates] = (0, import_react5.useState)({});
1608
+ const [failures, setFailures] = (0, import_react5.useState)(0);
1609
+ const [expanded, setExpanded] = (0, import_react5.useState)({});
1610
+ const [touched, setTouched] = (0, import_react5.useState)({});
1611
+ const groupsRef = (0, import_react5.useRef)(groups);
1569
1612
  groupsRef.current = groups;
1570
- const statesRef = (0, import_react4.useRef)(states);
1613
+ const statesRef = (0, import_react5.useRef)(states);
1571
1614
  statesRef.current = states;
1572
- const getStatesRef = (0, import_react4.useRef)(opts.getStates);
1615
+ const getStatesRef = (0, import_react5.useRef)(opts.getStates);
1573
1616
  getStatesRef.current = opts.getStates;
1574
1617
  const pinnedKey = opts.pinnedMatchIds.join(",");
1575
- const [localDate, setLocalDate] = (0, import_react4.useState)(() => localDateOf(/* @__PURE__ */ new Date()));
1576
- (0, import_react4.useEffect)(() => {
1618
+ const [localDate, setLocalDate] = (0, import_react5.useState)(() => localDateOf(/* @__PURE__ */ new Date()));
1619
+ (0, import_react5.useEffect)(() => {
1577
1620
  const id = setInterval(() => {
1578
1621
  const next = localDateOf(/* @__PURE__ */ new Date());
1579
1622
  setLocalDate((prev) => prev === next ? prev : next);
1580
1623
  }, ROLLOVER_CHECK_MS);
1581
1624
  return () => clearInterval(id);
1582
1625
  }, []);
1583
- (0, import_react4.useEffect)(() => {
1626
+ (0, import_react5.useEffect)(() => {
1584
1627
  let cancelled = false;
1585
1628
  const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
1586
1629
  const cached = readSchedule(opts.operatorId, localDate, Date.now());
@@ -1605,7 +1648,7 @@ function useMatchDiscovery(opts) {
1605
1648
  cancelled = true;
1606
1649
  };
1607
1650
  }, [opts.operatorId, localDate]);
1608
- (0, import_react4.useEffect)(() => {
1651
+ (0, import_react5.useEffect)(() => {
1609
1652
  setExpanded((prev) => {
1610
1653
  const next = {};
1611
1654
  for (const group of groups) {
@@ -1616,7 +1659,7 @@ function useMatchDiscovery(opts) {
1616
1659
  return next;
1617
1660
  });
1618
1661
  }, [groups, pinnedKey, touched]);
1619
- const tick = (0, import_react4.useCallback)(async () => {
1662
+ const tick = (0, import_react5.useCallback)(async () => {
1620
1663
  const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now());
1621
1664
  if (ids.length === 0) return;
1622
1665
  try {
@@ -1632,7 +1675,7 @@ function useMatchDiscovery(opts) {
1632
1675
  setFailures((n) => n + 1);
1633
1676
  }
1634
1677
  }, []);
1635
- (0, import_react4.useEffect)(() => {
1678
+ (0, import_react5.useEffect)(() => {
1636
1679
  if (!opts.isOpen) return;
1637
1680
  void tick();
1638
1681
  const id = setInterval(() => {
@@ -1641,17 +1684,118 @@ function useMatchDiscovery(opts) {
1641
1684
  return () => clearInterval(id);
1642
1685
  }, [opts.isOpen, tick, groups]);
1643
1686
  const stale = failures >= STALE_AFTER_FAILURES;
1644
- const liveCount = (0, import_react4.useMemo)(
1687
+ const liveCount = (0, import_react5.useMemo)(
1645
1688
  () => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
1646
1689
  [states, stale]
1647
1690
  );
1648
- const toggleGroup = (0, import_react4.useCallback)((competitionId) => {
1691
+ const toggleGroup = (0, import_react5.useCallback)((competitionId) => {
1649
1692
  setTouched((prev) => ({ ...prev, [competitionId]: true }));
1650
1693
  setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
1651
1694
  }, []);
1652
1695
  return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick };
1653
1696
  }
1654
1697
 
1698
+ // src/useGames.ts
1699
+ var import_react6 = require("react");
1700
+ var GAMES_POLL_MS = 6e4;
1701
+ var DEFAULT_TZ = "Europe/London";
1702
+ function computeGameDay(timezone) {
1703
+ return new Intl.DateTimeFormat("en-CA", { timeZone: timezone }).format(/* @__PURE__ */ new Date());
1704
+ }
1705
+ function useGames(conversation, { activeTab, operatorTimezone }) {
1706
+ const [enabled, setEnabled] = (0, import_react6.useState)(true);
1707
+ const [games, setGames] = (0, import_react6.useState)([]);
1708
+ const [loading, setLoading] = (0, import_react6.useState)(false);
1709
+ const [refreshCount, setRefreshCount] = (0, import_react6.useState)(0);
1710
+ const inFlightRef = (0, import_react6.useRef)(false);
1711
+ const enabledRef = (0, import_react6.useRef)(true);
1712
+ const conversationRef = (0, import_react6.useRef)(conversation);
1713
+ conversationRef.current = conversation;
1714
+ const tzRef = (0, import_react6.useRef)(operatorTimezone ?? DEFAULT_TZ);
1715
+ tzRef.current = operatorTimezone ?? DEFAULT_TZ;
1716
+ (0, import_react6.useEffect)(() => {
1717
+ if (!enabledRef.current) return;
1718
+ let active = true;
1719
+ const doFetch = async () => {
1720
+ const conv = conversationRef.current;
1721
+ if (!conv || inFlightRef.current || !active) return;
1722
+ inFlightRef.current = true;
1723
+ setLoading(true);
1724
+ try {
1725
+ const gameDay = computeGameDay(tzRef.current);
1726
+ const result = await conv.getGames(gameDay);
1727
+ if (!active) return;
1728
+ if (result === null) {
1729
+ enabledRef.current = false;
1730
+ setEnabled(false);
1731
+ } else {
1732
+ setGames(result.games);
1733
+ }
1734
+ } catch {
1735
+ } finally {
1736
+ inFlightRef.current = false;
1737
+ if (active) setLoading(false);
1738
+ }
1739
+ };
1740
+ void doFetch();
1741
+ let intervalId;
1742
+ if (activeTab === "games") {
1743
+ intervalId = window.setInterval(() => {
1744
+ if (!enabledRef.current) {
1745
+ window.clearInterval(intervalId);
1746
+ return;
1747
+ }
1748
+ void doFetch();
1749
+ }, GAMES_POLL_MS);
1750
+ }
1751
+ return () => {
1752
+ active = false;
1753
+ if (intervalId !== void 0) window.clearInterval(intervalId);
1754
+ };
1755
+ }, [activeTab, refreshCount]);
1756
+ const refresh = (0, import_react6.useCallback)(() => {
1757
+ setRefreshCount((c) => c + 1);
1758
+ }, []);
1759
+ return { enabled, games, loading, refresh };
1760
+ }
1761
+
1762
+ // src/useLeaderboard.ts
1763
+ var import_react7 = require("react");
1764
+ function useLeaderboard(conversation, { activeTab }) {
1765
+ const [data, setData] = (0, import_react7.useState)(null);
1766
+ const [loading, setLoading] = (0, import_react7.useState)(false);
1767
+ const [refreshCount, setRefreshCount] = (0, import_react7.useState)(0);
1768
+ const inFlightRef = (0, import_react7.useRef)(false);
1769
+ const conversationRef = (0, import_react7.useRef)(conversation);
1770
+ conversationRef.current = conversation;
1771
+ (0, import_react7.useEffect)(() => {
1772
+ if (activeTab !== "leaderboard") return;
1773
+ let active = true;
1774
+ const doFetch = async () => {
1775
+ const conv = conversationRef.current;
1776
+ if (!conv || inFlightRef.current) return;
1777
+ inFlightRef.current = true;
1778
+ setLoading(true);
1779
+ try {
1780
+ const result = await conv.getLeaderboard();
1781
+ if (active) setData(result);
1782
+ } catch {
1783
+ } finally {
1784
+ inFlightRef.current = false;
1785
+ if (active) setLoading(false);
1786
+ }
1787
+ };
1788
+ void doFetch();
1789
+ return () => {
1790
+ active = false;
1791
+ };
1792
+ }, [activeTab, refreshCount]);
1793
+ const refresh = (0, import_react7.useCallback)(() => {
1794
+ setRefreshCount((c) => c + 1);
1795
+ }, []);
1796
+ return { data, loading, refresh };
1797
+ }
1798
+
1655
1799
  // src/liveClock.ts
1656
1800
  function isTreatedLive(state, pollStale) {
1657
1801
  return state?.phase === "live" && !pollStale;
@@ -1664,17 +1808,17 @@ function visibleGroupsOf(groups, states) {
1664
1808
  }
1665
1809
 
1666
1810
  // src/eventLogContext.ts
1667
- var import_react5 = require("react");
1668
- var EventLogContext = (0, import_react5.createContext)(null);
1811
+ var import_react8 = require("react");
1812
+ var EventLogContext = (0, import_react8.createContext)(null);
1669
1813
  function useEventLog() {
1670
- return (0, import_react5.useContext)(EventLogContext);
1814
+ return (0, import_react8.useContext)(EventLogContext);
1671
1815
  }
1672
1816
 
1673
1817
  // src/components/ChatFab.tsx
1674
- var import_react7 = require("react");
1818
+ var import_react10 = require("react");
1675
1819
 
1676
1820
  // src/components/BrandMark.tsx
1677
- var import_react6 = require("react");
1821
+ var import_react9 = require("react");
1678
1822
 
1679
1823
  // src/assets/logo.ts
1680
1824
  var SS_LOGO_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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";
@@ -1723,7 +1867,7 @@ function DashboardIcon({ name }) {
1723
1867
  // src/components/BrandMark.tsx
1724
1868
  var import_jsx_runtime2 = require("react/jsx-runtime");
1725
1869
  function BrandMark({ logoUrl, className }) {
1726
- const [failed, setFailed] = (0, import_react6.useState)(false);
1870
+ const [failed, setFailed] = (0, import_react9.useState)(false);
1727
1871
  if (!logoUrl || failed) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SsMark, { className });
1728
1872
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { className, src: logoUrl, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1729
1873
  }
@@ -1748,9 +1892,9 @@ function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss" }) {
1748
1892
  var import_jsx_runtime4 = require("react/jsx-runtime");
1749
1893
  function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart }) {
1750
1894
  const bubble = popupText ?? greeting;
1751
- const [intro, setIntro] = (0, import_react7.useState)(false);
1752
- const armedRef = (0, import_react7.useRef)(introAllowed);
1753
- (0, import_react7.useEffect)(() => {
1895
+ const [intro, setIntro] = (0, import_react10.useState)(false);
1896
+ const armedRef = (0, import_react10.useRef)(introAllowed);
1897
+ (0, import_react10.useEffect)(() => {
1754
1898
  if (armedRef.current && bubble) {
1755
1899
  armedRef.current = false;
1756
1900
  setIntro(true);
@@ -1764,10 +1908,10 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
1764
1908
  }
1765
1909
 
1766
1910
  // src/components/ChatPanel.tsx
1767
- var import_react25 = require("react");
1911
+ var import_react38 = require("react");
1768
1912
 
1769
1913
  // src/components/ChatHeader.tsx
1770
- var import_react8 = require("react");
1914
+ var import_react11 = require("react");
1771
1915
  var import_jsx_runtime5 = require("react/jsx-runtime");
1772
1916
  function ChatHeader({
1773
1917
  onClose,
@@ -1779,15 +1923,15 @@ function ChatHeader({
1779
1923
  newConversationLabel = "New conversation",
1780
1924
  moreOptionsLabel = "More options"
1781
1925
  }) {
1782
- const [menuOpen, setMenuOpen] = (0, import_react8.useState)(false);
1783
- const wrapRef = (0, import_react8.useRef)(null);
1784
- const kebabRef = (0, import_react8.useRef)(null);
1785
- const firstItemRef = (0, import_react8.useRef)(null);
1926
+ const [menuOpen, setMenuOpen] = (0, import_react11.useState)(false);
1927
+ const wrapRef = (0, import_react11.useRef)(null);
1928
+ const kebabRef = (0, import_react11.useRef)(null);
1929
+ const firstItemRef = (0, import_react11.useRef)(null);
1786
1930
  const hasMenu = !!(canReset && onNewConversation);
1787
- (0, import_react8.useEffect)(() => {
1931
+ (0, import_react11.useEffect)(() => {
1788
1932
  if (menuOpen) firstItemRef.current?.focus();
1789
1933
  }, [menuOpen]);
1790
- (0, import_react8.useEffect)(() => {
1934
+ (0, import_react11.useEffect)(() => {
1791
1935
  if (!menuOpen) return;
1792
1936
  const onPointer = (e) => {
1793
1937
  if (!wrapRef.current?.contains(e.target)) setMenuOpen(false);
@@ -1843,7 +1987,7 @@ function ChatHeader({
1843
1987
  }
1844
1988
 
1845
1989
  // src/components/MessageList.tsx
1846
- var import_react23 = require("react");
1990
+ var import_react26 = require("react");
1847
1991
 
1848
1992
  // src/components/Markdown.tsx
1849
1993
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -1861,7 +2005,7 @@ function Markdown({ text }) {
1861
2005
  }
1862
2006
 
1863
2007
  // src/components/EntityCardList.tsx
1864
- var import_react9 = require("react");
2008
+ var import_react12 = require("react");
1865
2009
  var import_jsx_runtime7 = require("react/jsx-runtime");
1866
2010
  var MAX_VISIBLE = 3;
1867
2011
  var RECORD_RE = /^(\d+)-(\d+)-(\d+)$/;
@@ -1945,7 +2089,7 @@ function ScopeTabs({ scopes, active, onSelect }) {
1945
2089
  )) });
1946
2090
  }
1947
2091
  function EntityCardItem({ c }) {
1948
- const [active, setActive] = (0, import_react9.useState)(0);
2092
+ const [active, setActive] = (0, import_react12.useState)(0);
1949
2093
  const hasBody = c.scopes.length > 0;
1950
2094
  if (!hasBody) {
1951
2095
  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 }) });
@@ -1959,7 +2103,7 @@ function EntityCardItem({ c }) {
1959
2103
  ] });
1960
2104
  }
1961
2105
  function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
1962
- const [expanded, setExpanded] = (0, import_react9.useState)(false);
2106
+ const [expanded, setExpanded] = (0, import_react12.useState)(false);
1963
2107
  if (cards.length === 0) return null;
1964
2108
  const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
1965
2109
  const overflow = cards.length - MAX_VISIBLE;
@@ -1970,18 +2114,18 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
1970
2114
  }
1971
2115
 
1972
2116
  // src/components/BettingInsightList.tsx
1973
- var import_react14 = require("react");
2117
+ var import_react17 = require("react");
1974
2118
 
1975
2119
  // src/components/AddToSlipButton.tsx
1976
- var import_react11 = require("react");
2120
+ var import_react14 = require("react");
1977
2121
  var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
1978
2122
 
1979
2123
  // src/components/Toast.tsx
1980
- var import_react10 = require("react");
2124
+ var import_react13 = require("react");
1981
2125
  var import_jsx_runtime8 = require("react/jsx-runtime");
1982
2126
  var DISMISS_MS = 4e3;
1983
2127
  function Toast({ toast, onDismiss }) {
1984
- (0, import_react10.useEffect)(() => {
2128
+ (0, import_react13.useEffect)(() => {
1985
2129
  if (!toast) return;
1986
2130
  const timer = setTimeout(onDismiss, DISMISS_MS);
1987
2131
  return () => clearTimeout(timer);
@@ -1999,10 +2143,10 @@ function withTimeout(value) {
1999
2143
  ]);
2000
2144
  }
2001
2145
  function SlipButton({ selection, shownOdds, marketName, marketDeveloperName, slip, ui }) {
2002
- const [pending, setPending] = (0, import_react11.useState)(false);
2003
- const [settled, setSettled] = (0, import_react11.useState)(false);
2004
- const [toast, setToast] = (0, import_react11.useState)(null);
2005
- const dismiss = (0, import_react11.useCallback)(() => setToast(null), []);
2146
+ const [pending, setPending] = (0, import_react14.useState)(false);
2147
+ const [settled, setSettled] = (0, import_react14.useState)(false);
2148
+ const [toast, setToast] = (0, import_react14.useState)(null);
2149
+ const dismiss = (0, import_react14.useCallback)(() => setToast(null), []);
2006
2150
  const log = useEventLog();
2007
2151
  const handler = slip.onAddToSlip;
2008
2152
  if (!ui || !handler || !selection) return null;
@@ -2092,14 +2236,14 @@ function OddsMovementBadge({
2092
2236
  }
2093
2237
 
2094
2238
  // src/components/Crest.tsx
2095
- var import_react12 = require("react");
2239
+ var import_react15 = require("react");
2096
2240
  var import_jsx_runtime11 = require("react/jsx-runtime");
2097
2241
  function initials2(name) {
2098
2242
  return (name ?? "").trim().slice(0, 1).toUpperCase() || "?";
2099
2243
  }
2100
2244
  function Crest2({ url, name, kind }) {
2101
2245
  const cls = kind === "comp" ? "ss-w-bi-comp-logo" : "ss-w-bi-crest";
2102
- const [failed, setFailed] = (0, import_react12.useState)(false);
2246
+ const [failed, setFailed] = (0, import_react15.useState)(false);
2103
2247
  if (url && !failed) {
2104
2248
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
2105
2249
  }
@@ -2107,7 +2251,7 @@ function Crest2({ url, name, kind }) {
2107
2251
  }
2108
2252
 
2109
2253
  // src/components/PinToggle.tsx
2110
- var import_react13 = require("react");
2254
+ var import_react16 = require("react");
2111
2255
  var import_jsx_runtime12 = require("react/jsx-runtime");
2112
2256
  var PIN_GLYPHS = {
2113
2257
  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" },
@@ -2115,8 +2259,8 @@ var PIN_GLYPHS = {
2115
2259
  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" }
2116
2260
  };
2117
2261
  function PinToggle({ pin, monitor, ui }) {
2118
- const [toast, setToast] = (0, import_react13.useState)(null);
2119
- const dismiss = (0, import_react13.useCallback)(() => setToast(null), []);
2262
+ const [toast, setToast] = (0, import_react16.useState)(null);
2263
+ const dismiss = (0, import_react16.useCallback)(() => setToast(null), []);
2120
2264
  const log = useEventLog();
2121
2265
  if (!monitor || !monitor.enabled) return null;
2122
2266
  const key = pinKey(pin);
@@ -2176,7 +2320,7 @@ function StatRows({ stats }) {
2176
2320
  ] }, `${s.label}:${s.value}`)) });
2177
2321
  }
2178
2322
  function ScopedStats({ scopes }) {
2179
- const [active, setActive] = (0, import_react14.useState)(0);
2323
+ const [active, setActive] = (0, import_react17.useState)(0);
2180
2324
  const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
2181
2325
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-scoped", children: [
2182
2326
  /* @__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)) }),
@@ -2187,7 +2331,7 @@ function hasStatsContent(it) {
2187
2331
  return !!it.scopes && it.scopes.length >= 2 || it.stats.length > 0;
2188
2332
  }
2189
2333
  function ReasonStrip({ it, ui }) {
2190
- const [open, setOpen] = (0, import_react14.useState)(false);
2334
+ const [open, setOpen] = (0, import_react17.useState)(false);
2191
2335
  const log = useEventLog();
2192
2336
  const hasScopes = !!it.scopes && it.scopes.length >= 2;
2193
2337
  const hasStats = hasStatsContent(it);
@@ -2307,7 +2451,7 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
2307
2451
  }
2308
2452
 
2309
2453
  // src/components/MarketOddsCardList.tsx
2310
- var import_react15 = require("react");
2454
+ var import_react18 = require("react");
2311
2455
  var import_jsx_runtime14 = require("react/jsx-runtime");
2312
2456
  function OddsRow({ vm, row, ui, slip, inSlipIds }) {
2313
2457
  const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
@@ -2324,7 +2468,7 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
2324
2468
  ] });
2325
2469
  }
2326
2470
  function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
2327
- const [open, setOpen] = (0, import_react15.useState)(false);
2471
+ const [open, setOpen] = (0, import_react18.useState)(false);
2328
2472
  const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
2329
2473
  const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
2330
2474
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
@@ -2627,7 +2771,7 @@ function FixtureCard({ card }) {
2627
2771
  }
2628
2772
 
2629
2773
  // src/components/dashboard/CountdownCard.tsx
2630
- var import_react16 = require("react");
2774
+ var import_react19 = require("react");
2631
2775
  var import_jsx_runtime20 = require("react/jsx-runtime");
2632
2776
  var DAY_MS = 864e5;
2633
2777
  function remainingSegments(kickoffUnix, nowMs, withSeconds) {
@@ -2646,12 +2790,12 @@ function remainingSegments(kickoffUnix, nowMs, withSeconds) {
2646
2790
  function CountdownCard({ card }) {
2647
2791
  const { data } = card;
2648
2792
  const unitLabel = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit };
2649
- const [nowMs, setNowMs] = (0, import_react16.useState)(() => Date.now());
2650
- const [reduced] = (0, import_react16.useState)(
2793
+ const [nowMs, setNowMs] = (0, import_react19.useState)(() => Date.now());
2794
+ const [reduced] = (0, import_react19.useState)(
2651
2795
  () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches
2652
2796
  );
2653
2797
  const withinDay = data.kickoffUnix * 1e3 - nowMs < DAY_MS;
2654
- (0, import_react16.useEffect)(() => {
2798
+ (0, import_react19.useEffect)(() => {
2655
2799
  if (reduced) return;
2656
2800
  const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1e3 : 6e4);
2657
2801
  return () => window.clearInterval(id);
@@ -2659,7 +2803,7 @@ function CountdownCard({ card }) {
2659
2803
  const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced);
2660
2804
  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: [
2661
2805
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-eyebrow", children: card.title ?? "Kick-off in" }),
2662
- 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_react16.Fragment, { children: [
2806
+ 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_react19.Fragment, { children: [
2663
2807
  i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-colon", children: ":" }) : null,
2664
2808
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-fandash-countdown-seg", children: [
2665
2809
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-fandash-countdown-value", children: s.value }),
@@ -2670,7 +2814,7 @@ function CountdownCard({ card }) {
2670
2814
  }
2671
2815
 
2672
2816
  // src/components/dashboard/InjuriesCard.tsx
2673
- var import_react17 = require("react");
2817
+ var import_react20 = require("react");
2674
2818
  var import_jsx_runtime21 = require("react/jsx-runtime");
2675
2819
  var SHOWN = 3;
2676
2820
  function ColHead({ name, crestUrl }) {
@@ -2693,7 +2837,7 @@ function InjuryList({ rows, emptyLabel, limit }) {
2693
2837
  }
2694
2838
  function InjuriesCard({ card, ui }) {
2695
2839
  const { data } = card;
2696
- const [expanded, setExpanded] = (0, import_react17.useState)(false);
2840
+ const [expanded, setExpanded] = (0, import_react20.useState)(false);
2697
2841
  const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN);
2698
2842
  const limit = expanded ? void 0 : SHOWN;
2699
2843
  const showMore = ui?.showMore ?? ((n) => `Show ${n} more`);
@@ -2799,7 +2943,7 @@ function LinksCard({ card }) {
2799
2943
  }
2800
2944
 
2801
2945
  // src/components/dashboard/PostMatchResultCard.tsx
2802
- var import_react18 = require("react");
2946
+ var import_react21 = require("react");
2803
2947
  var import_jsx_runtime27 = require("react/jsx-runtime");
2804
2948
  function initials3(name) {
2805
2949
  return name.trim().slice(0, 3).toUpperCase();
@@ -2809,7 +2953,7 @@ function PostMatchCrest({
2809
2953
  name,
2810
2954
  side
2811
2955
  }) {
2812
- const [failed, setFailed] = (0, import_react18.useState)(false);
2956
+ const [failed, setFailed] = (0, import_react21.useState)(false);
2813
2957
  const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
2814
2958
  if (url && !failed) {
2815
2959
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -3008,10 +3152,10 @@ function RestingFormCard({ card }) {
3008
3152
  }
3009
3153
 
3010
3154
  // src/components/dashboard/LiveScoreCard.tsx
3011
- var import_react20 = require("react");
3155
+ var import_react23 = require("react");
3012
3156
 
3013
3157
  // src/useLiveClock.ts
3014
- var import_react19 = require("react");
3158
+ var import_react22 = require("react");
3015
3159
  var TICK_MS = 6e4;
3016
3160
  var MAX_LIVE_TICK_MINUTES = 15;
3017
3161
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -3020,10 +3164,10 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
3020
3164
  return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
3021
3165
  }
3022
3166
  function useLiveClock(minute, clockRunning, receivedAtMs) {
3023
- const [displayMinute, setDisplayMinute] = (0, import_react19.useState)(
3167
+ const [displayMinute, setDisplayMinute] = (0, import_react22.useState)(
3024
3168
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
3025
3169
  );
3026
- (0, import_react19.useEffect)(() => {
3170
+ (0, import_react22.useEffect)(() => {
3027
3171
  setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs));
3028
3172
  if (!clockRunning) return;
3029
3173
  const id = window.setInterval(() => {
@@ -3040,7 +3184,7 @@ function initials5(name) {
3040
3184
  return name.trim().slice(0, 3).toUpperCase();
3041
3185
  }
3042
3186
  function LiveCrest({ url, name, side }) {
3043
- const [failed, setFailed] = (0, import_react20.useState)(false);
3187
+ const [failed, setFailed] = (0, import_react23.useState)(false);
3044
3188
  const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
3045
3189
  if (url && !failed) {
3046
3190
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
@@ -3059,7 +3203,7 @@ function LiveScoreCard({
3059
3203
  }) {
3060
3204
  const { data } = card;
3061
3205
  const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`;
3062
- const seedRef = (0, import_react20.useRef)(null);
3206
+ const seedRef = (0, import_react23.useRef)(null);
3063
3207
  if (!seedRef.current || seedRef.current.key !== seedKey) {
3064
3208
  seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
3065
3209
  }
@@ -3099,7 +3243,7 @@ function LiveScoreCard({
3099
3243
  }
3100
3244
 
3101
3245
  // src/components/dashboard/LiveTimelineCard.tsx
3102
- var import_react21 = require("react");
3246
+ var import_react24 = require("react");
3103
3247
  var import_jsx_runtime37 = require("react/jsx-runtime");
3104
3248
  var SHOWN2 = 3;
3105
3249
  function EventIcon({ type }) {
@@ -3141,7 +3285,7 @@ function EventRow({ e }) {
3141
3285
  ] });
3142
3286
  }
3143
3287
  function LiveTimelineCard({ card, ui }) {
3144
- const [expanded, setExpanded] = (0, import_react21.useState)(false);
3288
+ const [expanded, setExpanded] = (0, import_react24.useState)(false);
3145
3289
  const events = card.data.events;
3146
3290
  if (!events || events.length === 0) return null;
3147
3291
  const sorted = [...events].sort((a, b) => b.minute - a.minute);
@@ -3166,7 +3310,7 @@ function LiveTimelineCard({ card, ui }) {
3166
3310
  }
3167
3311
 
3168
3312
  // src/components/dashboard/MomentumWave.tsx
3169
- var import_react22 = require("react");
3313
+ var import_react25 = require("react");
3170
3314
  var import_jsx_runtime38 = require("react/jsx-runtime");
3171
3315
  var WIDTH = 270;
3172
3316
  var HEIGHT = 56;
@@ -3190,7 +3334,7 @@ function MomentumWave({
3190
3334
  }) {
3191
3335
  if (points.length === 0) return null;
3192
3336
  const { area, line, lastLeftPct, lastTopPx } = buildPaths(points);
3193
- const clipId = (0, import_react22.useId)();
3337
+ const clipId = (0, import_react25.useId)();
3194
3338
  const topClipId = `${clipId}-top`;
3195
3339
  const bottomClipId = `${clipId}-bottom`;
3196
3340
  const topClass = clubIsHome ? "ss-w-fandash-live-mom-home" : "ss-w-fandash-live-mom-away";
@@ -3381,11 +3525,11 @@ function turnAnchor(messages) {
3381
3525
  }
3382
3526
  function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
3383
3527
  const { state, send } = controller;
3384
- const listRef = (0, import_react23.useRef)(null);
3385
- const endRef = (0, import_react23.useRef)(null);
3386
- const pinnedRef = (0, import_react23.useRef)(true);
3387
- const anchoredTurnRef = (0, import_react23.useRef)(null);
3388
- (0, import_react23.useEffect)(() => {
3528
+ const listRef = (0, import_react26.useRef)(null);
3529
+ const endRef = (0, import_react26.useRef)(null);
3530
+ const pinnedRef = (0, import_react26.useRef)(true);
3531
+ const anchoredTurnRef = (0, import_react26.useRef)(null);
3532
+ (0, import_react26.useEffect)(() => {
3389
3533
  const anchor = turnAnchor(state.messages);
3390
3534
  const list = listRef.current;
3391
3535
  if (anchor && anchor.turnId !== anchoredTurnRef.current) {
@@ -3441,10 +3585,10 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
3441
3585
  }
3442
3586
 
3443
3587
  // src/components/ChatInput.tsx
3444
- var import_react24 = require("react");
3588
+ var import_react27 = require("react");
3445
3589
  var import_jsx_runtime44 = require("react/jsx-runtime");
3446
3590
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
3447
- const [value, setValue] = (0, import_react24.useState)("");
3591
+ const [value, setValue] = (0, import_react27.useState)("");
3448
3592
  const submit = () => {
3449
3593
  const t = value.trim();
3450
3594
  if (!t) return;
@@ -3465,12 +3609,16 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
3465
3609
 
3466
3610
  // src/components/TabBar.tsx
3467
3611
  var import_jsx_runtime45 = require("react/jsx-runtime");
3468
- function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday }) {
3612
+ function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday, gamesEnabled }) {
3469
3613
  const tabs = [
3470
3614
  { tab: "chat", label: ui.tabChat, count: 0, dot: monitor.chatDot },
3471
3615
  ...hasToday ? [{ tab: "today", label: ui.tabToday, count: todayCount, dot: monitor.todayDot }] : [],
3472
3616
  ...matchCount > 0 ? [{ tab: "following", label: ui.tabFollowing, count: matchCount, dot: monitor.matchesDot }] : [],
3473
- ...oddsCount > 0 ? [{ tab: "odds", label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : []
3617
+ ...oddsCount > 0 ? [{ tab: "odds", label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : [],
3618
+ ...gamesEnabled ? [
3619
+ { tab: "games", label: ui.tabGames, count: 0, dot: false },
3620
+ { tab: "leaderboard", label: ui.tabLeaderboard, count: 0, dot: false }
3621
+ ] : []
3474
3622
  ];
3475
3623
  if (tabs.length < 2) return null;
3476
3624
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "ss-w-tabs", role: "tablist", children: tabs.map(({ tab, label, count, dot }) => {
@@ -3579,9 +3727,28 @@ function isPromoted(row, promotedPins) {
3579
3727
  function formatTime(iso) {
3580
3728
  return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
3581
3729
  }
3730
+ function groupScorers(goals, ownGoalLabel) {
3731
+ const order = [];
3732
+ const minutesByPlayer = /* @__PURE__ */ new Map();
3733
+ for (const g of goals) {
3734
+ const name = g.player ?? "";
3735
+ const minute = g.ownGoal ? `${g.minuteLabel} (${ownGoalLabel})` : g.minuteLabel;
3736
+ if (!minutesByPlayer.has(name)) {
3737
+ minutesByPlayer.set(name, []);
3738
+ order.push(name);
3739
+ }
3740
+ minutesByPlayer.get(name).push(minute);
3741
+ }
3742
+ return order.map((name) => {
3743
+ const minutes = minutesByPlayer.get(name).join(", ");
3744
+ return { player: name, label: name ? `${name} ${minutes}` : minutes };
3745
+ });
3746
+ }
3582
3747
  function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
3583
3748
  const live = match.phase === "live";
3584
- const scorers = match.events.filter((e) => e.type === "goal");
3749
+ const goals = match.events.filter((e) => e.type === "goal");
3750
+ const homeScorers = groupScorers(goals.filter((e) => e.side === "home"), ui.ownGoalLabel);
3751
+ const awayScorers = groupScorers(goals.filter((e) => e.side === "away"), ui.ownGoalLabel);
3585
3752
  const promotedRows = match.statRows.filter((row) => isPromoted(row, promotedPins));
3586
3753
  const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins));
3587
3754
  const orderedRows = [...promotedRows, ...otherRows];
@@ -3617,7 +3784,11 @@ function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }) {
3617
3784
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-name", children: match.awayTeamName })
3618
3785
  ] })
3619
3786
  ] }),
3620
- scorers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-scorers", children: scorers.map((e) => `${e.player ?? ""} ${e.minuteLabel}`).join(", ") }),
3787
+ (homeScorers.length > 0 || awayScorers.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "ss-w-mon-scorers", children: [
3788
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("ul", { className: "ss-w-mon-scorers-col ss-w-mon-scorers-home", children: homeScorers.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("li", { children: s.label }, `${s.player}-${i}`)) }),
3789
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "ss-w-mon-scorers-ball", "aria-hidden": "true", children: "\u26BD" }),
3790
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("ul", { className: "ss-w-mon-scorers-col ss-w-mon-scorers-away", children: awayScorers.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("li", { children: s.label }, `${s.player}-${i}`)) })
3791
+ ] }),
3621
3792
  /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "ss-w-mon-stats", children: orderedRows.map((row) => {
3622
3793
  const total = row.homeNum + row.awayNum;
3623
3794
  const homePct = total > 0 ? row.homeNum / total * 75 : 0;
@@ -3839,114 +4010,1713 @@ function TodayPanel({ discovery, ui, monitor }) {
3839
4010
  ] });
3840
4011
  }
3841
4012
 
3842
- // src/components/ChatPanel.tsx
4013
+ // src/components/GamesPanel.tsx
4014
+ var import_react36 = require("react");
4015
+
4016
+ // src/components/GamesLoginWall.tsx
3843
4017
  var import_jsx_runtime52 = require("react/jsx-runtime");
3844
- var FULLSCREEN_QUERY = "(max-width: 639px)";
3845
- function useIsModal() {
3846
- const [modal, setModal] = (0, import_react25.useState)(false);
3847
- (0, import_react25.useEffect)(() => {
3848
- if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
3849
- const mql = window.matchMedia(FULLSCREEN_QUERY);
3850
- const sync = () => setModal(mql.matches);
3851
- sync();
3852
- mql.addEventListener("change", sync);
3853
- return () => mql.removeEventListener("change", sync);
3854
- }, []);
3855
- return modal;
4018
+ function GamesLoginWall({ ui }) {
4019
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "ss-w-games-wall", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("p", { children: ui.gamesLoginRequired }) }) });
3856
4020
  }
3857
- function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery }) {
3858
- const { state, close, stop, send, reset } = controller;
3859
- const isModal = useIsModal();
3860
- (0, import_react25.useEffect)(() => {
3861
- const onKey = (e) => {
3862
- if (e.key === "Escape") close();
3863
- };
3864
- window.addEventListener("keydown", onKey);
3865
- return () => window.removeEventListener("keydown", onKey);
3866
- }, [close]);
3867
- const handleSend = (text) => {
3868
- monitor?.setActiveTab("chat");
3869
- send(text);
4021
+
4022
+ // src/components/GameTile.tsx
4023
+ var import_jsx_runtime53 = require("react/jsx-runtime");
4024
+ var GAME_ICONS = {
4025
+ "mystery-tiger": "\u{1F42F}",
4026
+ "daily-quiz": "\u{1F9E0}",
4027
+ "career-path": "\u26BD",
4028
+ "beat-the-grid": "\u{1F3AF}",
4029
+ "guess-xi": "\u{1F4CB}",
4030
+ "head-of-league": "\u{1F3C6}"
4031
+ };
4032
+ function gameIcon(game) {
4033
+ return GAME_ICONS[game.gameId] ?? (game.kind === "fixture" ? "\u{1F4C5}" : "\u{1F3AE}");
4034
+ }
4035
+ function formatCountdown(lockAtUtc) {
4036
+ const diff = new Date(lockAtUtc).getTime() - Date.now();
4037
+ if (diff <= 0) return null;
4038
+ const totalMins = Math.floor(diff / 6e4);
4039
+ const hours = Math.floor(totalMins / 60);
4040
+ const mins = totalMins % 60;
4041
+ if (hours > 0) return `${hours}h ${mins}m`;
4042
+ return `${mins}m`;
4043
+ }
4044
+ function tileStatusLabel(game, ui) {
4045
+ switch (game.status) {
4046
+ case "available":
4047
+ return ui.gamePlay;
4048
+ case "in_progress":
4049
+ return ui.gameResume;
4050
+ case "played":
4051
+ case "graded": {
4052
+ const pts = game.score ?? 0;
4053
+ return `+${pts.toLocaleString("en")}`;
4054
+ }
4055
+ case "locked":
4056
+ return ui.gameLocked;
4057
+ case "voided":
4058
+ return ui.gameVoided;
4059
+ default:
4060
+ return "";
4061
+ }
4062
+ }
4063
+ var DISABLED_STATUSES = /* @__PURE__ */ new Set(["locked", "voided"]);
4064
+ function GameTile({
4065
+ game,
4066
+ onOpen,
4067
+ ui
4068
+ }) {
4069
+ const disabled = DISABLED_STATUSES.has(game.status);
4070
+ const statusLabel = tileStatusLabel(game, ui);
4071
+ const countdown = game.kind === "fixture" && game.lockAtUtc ? formatCountdown(game.lockAtUtc) : null;
4072
+ const statusClass = `ss-w-tile-status ss-w-tile-status--${game.status}`;
4073
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
4074
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "ss-w-tile-icon", children: gameIcon(game) }),
4075
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "ss-w-tile-title", children: game.title ?? game.gameId }),
4076
+ countdown !== null ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: statusClass, "data-testid": "tile-countdown", children: countdown }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: statusClass, children: statusLabel }),
4077
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: `ss-w-tile-chip ss-w-tile-chip--${game.ranked ? "skill" : "fun"}`, children: game.ranked ? "Skill" : "For fun" })
4078
+ ] });
4079
+ if (disabled) {
4080
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "ss-w-tile", "data-disabled": true, children: inner });
4081
+ }
4082
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
4083
+ "button",
4084
+ {
4085
+ type: "button",
4086
+ className: "ss-w-tile",
4087
+ onClick: () => onOpen(game),
4088
+ children: inner
4089
+ }
4090
+ );
4091
+ }
4092
+
4093
+ // src/components/GamesHub.tsx
4094
+ var import_jsx_runtime54 = require("react/jsx-runtime");
4095
+ function GamesHub({
4096
+ games,
4097
+ weeklyPrize,
4098
+ streak,
4099
+ weeklyRank,
4100
+ onOpen,
4101
+ ui
4102
+ }) {
4103
+ const showPrize = weeklyPrize || streak !== void 0 || weeklyRank !== void 0;
4104
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "ss-w-games-hub", children: [
4105
+ showPrize && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "ss-w-prize", children: [
4106
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "ss-w-prize-icon", children: "\u{1F3C6}" }),
4107
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "ss-w-prize-body", children: [
4108
+ weeklyPrize && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "ss-w-prize-text", children: weeklyPrize }),
4109
+ (streak !== void 0 || weeklyRank !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "ss-w-g-chips", children: [
4110
+ streak !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "ss-w-g-chip ss-w-g-chip--streak", children: [
4111
+ "\u{1F525} ",
4112
+ streak
4113
+ ] }),
4114
+ weeklyRank !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "ss-w-g-chip ss-w-g-chip--rank", children: [
4115
+ "#",
4116
+ weeklyRank
4117
+ ] })
4118
+ ] })
4119
+ ] })
4120
+ ] }),
4121
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "ss-w-gmatrix", children: games.map((g) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(GameTile, { game: g, onOpen, ui }, `${g.gameId}-${g.gameDay}`)) })
4122
+ ] });
4123
+ }
4124
+
4125
+ // src/components/GameScreenHost.tsx
4126
+ var import_react35 = require("react");
4127
+
4128
+ // src/useGamePlay.ts
4129
+ var import_react28 = require("react");
4130
+ function toSubmitResult(payload) {
4131
+ return {
4132
+ // 'pending' means the play is recorded but awaiting resolution (fixture games)
4133
+ alreadyPlayed: payload.status === "played" || payload.status === "graded" || payload.status === "pending",
4134
+ score: payload.score,
4135
+ isCorrect: payload.isCorrect,
4136
+ clientStateJson: payload.clientStateJson,
4137
+ attemptsUsed: payload.attemptsUsed
3870
4138
  };
3871
- (0, import_react25.useEffect)(() => {
3872
- if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
3873
- }, [monitor, state.isStreaming, state.messages.length]);
3874
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
3875
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3876
- ChatHeader,
3877
- {
3878
- onClose: close,
3879
- closeLabel: ui.closeChat,
3880
- logoUrl: ui.logoUrl,
3881
- headerTitle: ui.headerTitle,
3882
- onNewConversation: reset,
3883
- canReset: state.messages.length > 0,
3884
- newConversationLabel: ui.newConversation,
3885
- moreOptionsLabel: ui.moreOptions
3886
- }
3887
- ),
3888
- monitor && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3889
- TabBar,
3890
- {
3891
- monitor,
3892
- ui,
3893
- matchCount: monitor.pins.filter((p) => p.kind === "match").length,
3894
- oddsCount: monitor.pins.filter((p) => p.kind !== "match").length,
3895
- todayCount: discovery?.liveCount ?? 0,
3896
- hasToday: discovery ? visibleGroupsOf(discovery.groups, discovery.states).length > 0 : false
4139
+ }
4140
+ function useGamePlay(conversation, { gameId, gameDay, fixtureId, refresh }) {
4141
+ const [result, setResult] = (0, import_react28.useState)(null);
4142
+ const [submitting, setSubmitting] = (0, import_react28.useState)(false);
4143
+ const [rawStatus, setRawStatus] = (0, import_react28.useState)(null);
4144
+ const inFlightRef = (0, import_react28.useRef)(false);
4145
+ const convRef = (0, import_react28.useRef)(conversation);
4146
+ convRef.current = conversation;
4147
+ const optsRef = (0, import_react28.useRef)({ gameId, gameDay, fixtureId, refresh });
4148
+ optsRef.current = { gameId, gameDay, fixtureId, refresh };
4149
+ const submit = (0, import_react28.useCallback)(async (answerJson) => {
4150
+ const conv = convRef.current;
4151
+ if (!conv || inFlightRef.current) return;
4152
+ inFlightRef.current = true;
4153
+ setSubmitting(true);
4154
+ try {
4155
+ const opts = optsRef.current;
4156
+ const playResult = await conv.postPlay(opts.gameId, answerJson, opts.gameDay, opts.fixtureId);
4157
+ if (playResult !== null) {
4158
+ setResult(playResult);
4159
+ if (playResult.pointsDelta != null) {
4160
+ opts.refresh?.();
4161
+ }
3897
4162
  }
3898
- ),
3899
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3900
- "div",
3901
- {
3902
- style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
3903
- children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
4163
+ } catch {
4164
+ } finally {
4165
+ inFlightRef.current = false;
4166
+ setSubmitting(false);
4167
+ }
4168
+ }, []);
4169
+ const hydrate = (0, import_react28.useCallback)(() => {
4170
+ const conv = convRef.current;
4171
+ if (!conv) return;
4172
+ const opts = optsRef.current;
4173
+ void (async () => {
4174
+ try {
4175
+ const payload = await conv.getGameResult(opts.gameId, opts.fixtureId, opts.gameDay);
4176
+ if (payload !== null) {
4177
+ setResult(toSubmitResult(payload));
4178
+ setRawStatus(payload.status);
4179
+ }
4180
+ } catch {
3904
4181
  }
3905
- ),
3906
- monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(TodayPanel, { discovery, ui, monitor }),
3907
- monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MatchesPanel, { monitor, ui, slip }),
3908
- monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(OddsPanel, { monitor, ui, slip }),
3909
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
3910
- ] });
4182
+ })();
4183
+ }, []);
4184
+ return { result, submitting, submit, hydrate, rawStatus };
3911
4185
  }
3912
4186
 
3913
- // src/styles/css.generated.ts
3914
- var WIDGET_CSS = `.ss-w-root { all: revert; }
3915
- .ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }
3916
- .ss-w-root {
3917
- --ss-w-accent: #17936a;
3918
- --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;
3919
- --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;
3920
- --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
3921
- --ss-w-pos: #1aa563; --ss-w-neg: #e0524b;
3922
- --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
3923
- --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;
3924
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
3925
- font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);
4187
+ // src/components/games/MysteryTigerGame.tsx
4188
+ var import_react29 = require("react");
4189
+ var import_jsx_runtime55 = require("react/jsx-runtime");
4190
+ function parseClientState(json) {
4191
+ if (!json) return null;
4192
+ try {
4193
+ return JSON.parse(json);
4194
+ } catch {
4195
+ return null;
4196
+ }
3926
4197
  }
3927
- @media (prefers-color-scheme: dark) {
3928
- .ss-w-root[data-ss-w-theme="auto"] {
3929
- --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;
3930
- --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
3931
- --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
3932
- --ss-w-pos: #37c891; --ss-w-neg: #f0655d;
3933
- --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
4198
+ var ATTR_LABELS = {
4199
+ position: "Pos",
4200
+ nationality: "Nat",
4201
+ age: "Age",
4202
+ shirtNumber: "Kit",
4203
+ apps: "Apps"
4204
+ };
4205
+ var ATTR_KEYS = [
4206
+ "position",
4207
+ "nationality",
4208
+ "age",
4209
+ "shirtNumber",
4210
+ "apps"
4211
+ ];
4212
+ function MysteryTigerGame({
4213
+ config,
4214
+ result,
4215
+ submitting,
4216
+ onSubmit
4217
+ }) {
4218
+ const [query, setQuery] = (0, import_react29.useState)("");
4219
+ const inputId = (0, import_react29.useId)();
4220
+ const clientState = parseClientState(result?.clientStateJson);
4221
+ const alreadyGuessedIds = new Set(
4222
+ clientState?.guessResults.map((g) => g.playerId) ?? []
4223
+ );
4224
+ const isOver = result?.alreadyPlayed === true || clientState?.solved === true || clientState?.failed === true;
4225
+ const filtered = config && !isOver ? config.squadPlayers.filter(
4226
+ (p) => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase())
4227
+ ) : [];
4228
+ function handleSelect(playerId) {
4229
+ if (!config || isOver || submitting) return;
4230
+ const prevGuesses = clientState?.guessResults.map((g) => g.playerId) ?? [];
4231
+ const newGuesses = [...prevGuesses, playerId];
4232
+ setQuery("");
4233
+ onSubmit(JSON.stringify({ guesses: newGuesses }));
3934
4234
  }
4235
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gt", "data-testid": "game-screen-mystery-tiger", children: [
4236
+ !config && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4237
+ config && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
4238
+ isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: `ss-w-gt-banner ss-w-gt-banner--${clientState.solved ? "solved" : "failed"}`, children: [
4239
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gt-banner-label", children: clientState.solved ? "\u{1F42F} You found them!" : "\u{1F614} Better luck tomorrow" }),
4240
+ clientState.revealedPlayerName && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gt-banner-name", children: clientState.revealedPlayerName })
4241
+ ] }),
4242
+ !isOver && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gtta", children: [
4243
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4244
+ "input",
4245
+ {
4246
+ id: inputId,
4247
+ type: "text",
4248
+ role: "textbox",
4249
+ className: "ss-w-gtta-i",
4250
+ placeholder: "Search squad players\u2026",
4251
+ value: query,
4252
+ disabled: submitting || isOver,
4253
+ onChange: (e) => setQuery(e.target.value),
4254
+ autoComplete: "off",
4255
+ "aria-label": "Search for a player",
4256
+ "aria-autocomplete": "list"
4257
+ }
4258
+ ),
4259
+ query.length > 0 && filtered.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gtta-drop", role: "listbox", children: filtered.map((p) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4260
+ "div",
4261
+ {
4262
+ className: "ss-w-gtta-opt",
4263
+ role: "option",
4264
+ "aria-selected": false,
4265
+ onClick: () => handleSelect(p.id),
4266
+ onKeyDown: (e) => {
4267
+ if (e.key === "Enter") handleSelect(p.id);
4268
+ },
4269
+ tabIndex: 0,
4270
+ children: p.name
4271
+ },
4272
+ p.id
4273
+ )) })
4274
+ ] }),
4275
+ clientState && clientState.guessResults.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { children: [
4276
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gthdr", children: [
4277
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gthdr-c ss-w-gthdr-c--name", children: "Player" }),
4278
+ ATTR_KEYS.map((key) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gthdr-c", children: ATTR_LABELS[key] }, key))
4279
+ ] }),
4280
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gtrows", children: clientState.guessResults.map((gr, i) => {
4281
+ const player = config.squadPlayers.find((p) => p.id === gr.playerId);
4282
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gtrow", children: [
4283
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gtrow-nm", children: player?.name ?? `#${gr.playerId}` }),
4284
+ ATTR_KEYS.map((key) => {
4285
+ const v = gr[key];
4286
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4287
+ "div",
4288
+ {
4289
+ className: `ss-w-gtile ss-w-gtile--${v.verdict}`,
4290
+ "data-testid": `verdict-${key}-${i}`,
4291
+ "data-verdict": v.verdict,
4292
+ "aria-label": `${ATTR_LABELS[key]}: ${v.verdict}${v.direction ? ` ${v.direction}` : ""}`,
4293
+ children: v.direction && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "ss-w-gtile-dir", "aria-hidden": "true", children: v.direction === "up" ? "\u2191" : "\u2193" })
4294
+ },
4295
+ key
4296
+ );
4297
+ })
4298
+ ] }, gr.playerId);
4299
+ }) })
4300
+ ] }),
4301
+ clientState?.hintLine && !isOver && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gt-hint", children: clientState.hintLine }),
4302
+ !isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gt-hint", children: [
4303
+ clientState.guessesRemaining,
4304
+ " guess",
4305
+ clientState.guessesRemaining !== 1 ? "es" : "",
4306
+ " remaining"
4307
+ ] })
4308
+ ] })
4309
+ ] });
3935
4310
  }
3936
- .ss-w-root[data-ss-w-theme="dark"] {
3937
- --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;
3938
- --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
3939
- --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
3940
- --ss-w-pos: #37c891; --ss-w-neg: #f0655d;
3941
- --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
4311
+
4312
+ // src/components/games/HigherOrLowerGame.tsx
4313
+ var import_jsx_runtime56 = require("react/jsx-runtime");
4314
+ function parseClientState2(json) {
4315
+ if (!json) return null;
4316
+ try {
4317
+ return JSON.parse(json);
4318
+ } catch {
4319
+ return null;
4320
+ }
3942
4321
  }
3943
- .ss-w-root[data-ss-w-theme="light"] {
3944
- --ss-w-accent: #17936a; --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;
3945
- --ss-w-ink: #14181d; --ss-w-faint: #6b7580;
3946
- --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
3947
- --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
4322
+ function AnsweredRow({
4323
+ answered,
4324
+ pair
4325
+ }) {
4326
+ const cls = `ss-w-hlrrow ss-w-hlrrow--${answered.wasCorrect ? "correct" : "wrong"}`;
4327
+ const icon = answered.wasCorrect ? "\u2713" : "\u2717";
4328
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: cls, children: [
4329
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "ss-w-hlrrow-names", children: [
4330
+ pair?.playerAName ?? "?",
4331
+ " vs ",
4332
+ pair?.playerBName ?? "?"
4333
+ ] }),
4334
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlrrow-pick", children: answered.pick }),
4335
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlrrow-icon", children: icon })
4336
+ ] });
3948
4337
  }
3949
-
4338
+ function HigherOrLowerGame({
4339
+ config,
4340
+ result,
4341
+ submitting,
4342
+ onSubmit
4343
+ }) {
4344
+ const clientState = parseClientState2(result?.clientStateJson);
4345
+ const answeredCount = clientState?.answeredPairs.length ?? 0;
4346
+ const runEndedWrong = clientState?.answeredPairs.some((p) => !p.wasCorrect) ?? false;
4347
+ const allPairsAnswered = config != null && answeredCount >= config.pairs.length;
4348
+ const isOver = result?.alreadyPlayed === true || runEndedWrong || allPairsAnswered;
4349
+ const currentPair = config && !isOver ? config.pairs[answeredCount] ?? null : null;
4350
+ function handlePick(pick) {
4351
+ if (!config || isOver || submitting || !currentPair) return;
4352
+ const prevAnswers = clientState?.answeredPairs.map((p) => ({ pairIndex: p.pairIndex, pick: p.pick })) ?? [];
4353
+ const newAnswers = [...prevAnswers, { pairIndex: currentPair.pairIndex, pick }];
4354
+ onSubmit(JSON.stringify({ answers: newAnswers }));
4355
+ }
4356
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hl", "data-testid": "game-screen-higher-or-lower", children: [
4357
+ !config && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4358
+ config && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
4359
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlctx", children: [
4360
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlctx-fam", children: config.statLabel }),
4361
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlctx-szn", children: config.seasonLabel })
4362
+ ] }),
4363
+ currentPair && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpair", children: [
4364
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpc", children: [
4365
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-name", children: currentPair.playerAName }),
4366
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-val", children: currentPair.playerAValue })
4367
+ ] }),
4368
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpc ss-w-hlpc--b", children: [
4369
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-name", children: currentPair.playerBName }),
4370
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-val ss-w-hlpc-val--hidden", children: "?" })
4371
+ ] })
4372
+ ] }),
4373
+ !isOver && currentPair && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlbtns", children: [
4374
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
4375
+ "button",
4376
+ {
4377
+ type: "button",
4378
+ className: "ss-w-hlbtn",
4379
+ disabled: submitting,
4380
+ onClick: () => handlePick("higher"),
4381
+ children: "Higher"
4382
+ }
4383
+ ),
4384
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
4385
+ "button",
4386
+ {
4387
+ type: "button",
4388
+ className: "ss-w-hlbtn",
4389
+ disabled: submitting,
4390
+ onClick: () => handlePick("lower"),
4391
+ children: "Lower"
4392
+ }
4393
+ )
4394
+ ] }),
4395
+ clientState && clientState.answeredPairs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlresults", children: clientState.answeredPairs.map((answered) => {
4396
+ const pair = config.pairs.find((p) => p.pairIndex === answered.pairIndex);
4397
+ const vCls = `ss-w-hlpc-val ss-w-hlpc-val--${answered.wasCorrect ? "correct" : "wrong"}`;
4398
+ const badgeCls = `ss-w-hlpc-badge ss-w-hlpc-badge--${answered.wasCorrect ? "correct" : "wrong"}`;
4399
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlrrow", children: [
4400
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpair", children: [
4401
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpc", children: [
4402
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-name", children: pair?.playerAName ?? "?" }),
4403
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-val", children: pair?.playerAValue })
4404
+ ] }),
4405
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hlpc ss-w-hlpc--b", children: [
4406
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlpc-name", children: pair?.playerBName ?? "?" }),
4407
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: vCls, children: answered.playerBValue }),
4408
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: badgeCls, children: answered.wasCorrect ? "\u2713" : "\u2717" })
4409
+ ] })
4410
+ ] }),
4411
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AnsweredRow, { answered, pair })
4412
+ ] }, answered.pairIndex);
4413
+ }) })
4414
+ ] })
4415
+ ] });
4416
+ }
4417
+
4418
+ // src/components/games/CareerPathGame.tsx
4419
+ var import_react30 = require("react");
4420
+ var import_jsx_runtime57 = require("react/jsx-runtime");
4421
+ function parseClientState3(json) {
4422
+ if (!json) return null;
4423
+ try {
4424
+ return JSON.parse(json);
4425
+ } catch {
4426
+ return null;
4427
+ }
4428
+ }
4429
+ function SpellYear({ spell }) {
4430
+ const parts = [];
4431
+ if (spell.startYear) parts.push(String(spell.startYear));
4432
+ if (spell.endYear) parts.push(String(spell.endYear));
4433
+ if (parts.length === 0) return null;
4434
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-spell-yr", children: parts.join(" \u2013 ") });
4435
+ }
4436
+ function ClubSpellCard({ spell }) {
4437
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `ss-w-cpath-club${spell.isLoan ? " ss-w-cpath-club--loan" : ""}`, children: [
4438
+ spell.crestUrl ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
4439
+ "img",
4440
+ {
4441
+ src: spell.crestUrl,
4442
+ alt: spell.clubName,
4443
+ className: "ss-w-cpath-crest",
4444
+ loading: "lazy"
4445
+ }
4446
+ ) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-crest ss-w-cpath-crest--fallback", "aria-hidden": "true" }),
4447
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-club-info", children: [
4448
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-club-name", children: spell.clubName }),
4449
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(SpellYear, { spell }),
4450
+ spell.isLoan && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-loan-badge", children: "Loan" })
4451
+ ] })
4452
+ ] });
4453
+ }
4454
+ function CareerPathGame({
4455
+ config,
4456
+ result,
4457
+ submitting,
4458
+ onSubmit
4459
+ }) {
4460
+ const [query, setQuery] = (0, import_react30.useState)("");
4461
+ const inputId = (0, import_react30.useId)();
4462
+ const clientState = parseClientState3(result?.clientStateJson);
4463
+ const alreadyGuessedIds = new Set(
4464
+ clientState?.guessResults.map((g) => g.playerId) ?? []
4465
+ );
4466
+ const isOver = result?.alreadyPlayed === true || clientState?.solved === true || clientState?.failed === true;
4467
+ const visiblePath = clientState?.visiblePath ?? config?.initialPath ?? [];
4468
+ const filtered = config && !isOver ? config.typeaheadPool.filter(
4469
+ (p) => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase())
4470
+ ) : [];
4471
+ function handleSelect(playerId) {
4472
+ if (!config || isOver || submitting) return;
4473
+ const prevGuesses = clientState?.guessResults.map((g) => g.playerId) ?? [];
4474
+ const newGuesses = [...prevGuesses, playerId];
4475
+ setQuery("");
4476
+ onSubmit(JSON.stringify({ guesses: newGuesses }));
4477
+ }
4478
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath", "data-testid": "game-screen-career-path", children: [
4479
+ !config && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4480
+ config && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
4481
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-ctx", children: [
4482
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-ctx-label", children: "Career clubs" }),
4483
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "ss-w-cpath-ctx-count", children: [
4484
+ config.totalClubs,
4485
+ " clubs total"
4486
+ ] })
4487
+ ] }),
4488
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-path", children: [
4489
+ visiblePath.map((spell, i) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ClubSpellCard, { spell }, `${spell.clubName}-${i}`)),
4490
+ (clientState?.totalClubs ?? config.totalClubs) > visiblePath.length && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-hidden", children: [
4491
+ "+",
4492
+ (clientState?.totalClubs ?? config.totalClubs) - visiblePath.length,
4493
+ " more clubs hidden"
4494
+ ] })
4495
+ ] }),
4496
+ isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `ss-w-cpath-banner ss-w-cpath-banner--${clientState.solved ? "solved" : "failed"}`, children: [
4497
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-banner-label", children: clientState.solved ? "Career traced!" : "Better luck tomorrow" }),
4498
+ clientState.revealedPlayerName && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-banner-name", children: clientState.revealedPlayerName })
4499
+ ] }),
4500
+ !isOver && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-gtta", children: [
4501
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
4502
+ "input",
4503
+ {
4504
+ id: inputId,
4505
+ type: "text",
4506
+ role: "textbox",
4507
+ className: "ss-w-gtta-i",
4508
+ placeholder: "Search players\u2026",
4509
+ value: query,
4510
+ disabled: submitting || isOver,
4511
+ onChange: (e) => setQuery(e.target.value),
4512
+ autoComplete: "off",
4513
+ "aria-label": "Search for a player",
4514
+ "aria-autocomplete": "list"
4515
+ }
4516
+ ),
4517
+ query.length > 0 && filtered.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-gtta-drop", role: "listbox", children: filtered.map((p) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
4518
+ "div",
4519
+ {
4520
+ className: "ss-w-gtta-opt",
4521
+ role: "option",
4522
+ "aria-selected": false,
4523
+ onClick: () => handleSelect(p.id),
4524
+ onKeyDown: (e) => {
4525
+ if (e.key === "Enter") handleSelect(p.id);
4526
+ },
4527
+ tabIndex: 0,
4528
+ children: p.name
4529
+ },
4530
+ p.id
4531
+ )) })
4532
+ ] }),
4533
+ clientState?.hintLine && !isOver && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-hint", children: clientState.hintLine }),
4534
+ !isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-hint", children: [
4535
+ clientState.guessesRemaining,
4536
+ " guess",
4537
+ clientState.guessesRemaining !== 1 ? "es" : "",
4538
+ " remaining"
4539
+ ] })
4540
+ ] })
4541
+ ] });
4542
+ }
4543
+
4544
+ // src/components/games/BeatTheGridGame.tsx
4545
+ var import_react31 = __toESM(require("react"), 1);
4546
+ var import_jsx_runtime58 = require("react/jsx-runtime");
4547
+ function parseClientState4(json) {
4548
+ if (!json) return null;
4549
+ try {
4550
+ return JSON.parse(json);
4551
+ } catch {
4552
+ return null;
4553
+ }
4554
+ }
4555
+ function findCellResult(cells, row, col) {
4556
+ return cells.find((c) => c.row === row && c.col === col);
4557
+ }
4558
+ function SearchSheet({
4559
+ row,
4560
+ col,
4561
+ rowLabel,
4562
+ colLabel,
4563
+ playerPool,
4564
+ alreadyFilledIds,
4565
+ onPick,
4566
+ onDismiss
4567
+ }) {
4568
+ const [query, setQuery] = (0, import_react31.useState)("");
4569
+ const inputId = (0, import_react31.useId)();
4570
+ const filtered = playerPool.filter(
4571
+ (p) => !alreadyFilledIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase())
4572
+ );
4573
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-btg-sheet", "data-testid": "btg-search-sheet", children: [
4574
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-btg-sheet-hdr", children: [
4575
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-btg-sheet-ctx", children: [
4576
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-sheet-row", children: rowLabel }),
4577
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-sheet-sep", children: "\xD7" }),
4578
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-sheet-col", children: colLabel })
4579
+ ] }),
4580
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
4581
+ "button",
4582
+ {
4583
+ type: "button",
4584
+ className: "ss-w-btg-sheet-close",
4585
+ "data-testid": "btg-sheet-dismiss",
4586
+ "aria-label": "Dismiss",
4587
+ onClick: onDismiss,
4588
+ children: "\u2715"
4589
+ }
4590
+ )
4591
+ ] }),
4592
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-gtta", children: [
4593
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
4594
+ "input",
4595
+ {
4596
+ id: inputId,
4597
+ type: "text",
4598
+ role: "textbox",
4599
+ className: "ss-w-gtta-i",
4600
+ placeholder: "Search players\u2026",
4601
+ value: query,
4602
+ onChange: (e) => setQuery(e.target.value),
4603
+ autoComplete: "off",
4604
+ "aria-label": `Search player for ${rowLabel} \xD7 ${colLabel}`,
4605
+ "aria-autocomplete": "list",
4606
+ autoFocus: true
4607
+ }
4608
+ ),
4609
+ query.length > 0 && filtered.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-gtta-drop ss-w-btg-ta-list", role: "listbox", children: filtered.map((p) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
4610
+ "div",
4611
+ {
4612
+ className: "ss-w-gtta-opt",
4613
+ role: "option",
4614
+ "aria-selected": false,
4615
+ onClick: () => onPick(row, col, p.id),
4616
+ onKeyDown: (e) => {
4617
+ if (e.key === "Enter") onPick(row, col, p.id);
4618
+ },
4619
+ tabIndex: 0,
4620
+ children: p.name
4621
+ },
4622
+ p.id
4623
+ )) })
4624
+ ] })
4625
+ ] });
4626
+ }
4627
+ function BeatTheGridGame({
4628
+ config,
4629
+ result,
4630
+ submitting,
4631
+ onSubmit,
4632
+ playerPool
4633
+ }) {
4634
+ const [activeCell, setActiveCell] = (0, import_react31.useState)(null);
4635
+ const clientState = parseClientState4(result?.clientStateJson);
4636
+ const filledCells = clientState?.cells ?? [];
4637
+ const isLocked2 = result?.alreadyPlayed === true || clientState?.isComplete === true;
4638
+ const alreadyFilledIds = new Set(filledCells.map((c) => c.playerId));
4639
+ function handleCellClick(row, col) {
4640
+ if (isLocked2 || submitting) return;
4641
+ const alreadyFilled = findCellResult(filledCells, row, col);
4642
+ if (alreadyFilled) return;
4643
+ setActiveCell({ row, col });
4644
+ }
4645
+ function handlePick(row, col, playerId) {
4646
+ setActiveCell(null);
4647
+ const prevCells = filledCells.map((c) => ({ row: c.row, col: c.col, playerId: c.playerId }));
4648
+ const newCells = [...prevCells, { row, col, playerId }];
4649
+ onSubmit(JSON.stringify({ cells: newCells }));
4650
+ }
4651
+ if (!config) {
4652
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-btg", "data-testid": "game-screen-beat-the-grid", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }) });
4653
+ }
4654
+ const rows = config.rows;
4655
+ const cols = config.cols;
4656
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-btg", "data-testid": "game-screen-beat-the-grid", children: [
4657
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-btg-ctx", children: [
4658
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "ss-w-btg-ctx-score", children: [
4659
+ "Score: ",
4660
+ clientState?.totalScore ?? 0
4661
+ ] }),
4662
+ !isLocked2 && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "ss-w-btg-ctx-left", children: [
4663
+ config.maxGuesses - filledCells.length,
4664
+ " cell",
4665
+ config.maxGuesses - filledCells.length !== 1 ? "s" : "",
4666
+ " left"
4667
+ ] }),
4668
+ isLocked2 && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-ctx-done", children: "Complete" })
4669
+ ] }),
4670
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
4671
+ "div",
4672
+ {
4673
+ className: "ss-w-btg-grid",
4674
+ style: { gridTemplateColumns: `auto repeat(${cols.length}, 1fr)` },
4675
+ role: "grid",
4676
+ children: [
4677
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-btg-gc ss-w-btg-gc--corner" }),
4678
+ cols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-btg-gc ss-w-btg-gc--colhdr", children: col }, col)),
4679
+ rows.map((rowLabel, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_react31.default.Fragment, { children: [
4680
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-btg-gc ss-w-btg-gc--rowhdr", children: rowLabel }),
4681
+ cols.map((colLabel, colIdx) => {
4682
+ const filled = findCellResult(filledCells, rowIdx, colIdx);
4683
+ const isActive = activeCell?.row === rowIdx && activeCell?.col === colIdx;
4684
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
4685
+ "button",
4686
+ {
4687
+ type: "button",
4688
+ "data-testid": `btg-cell-${rowIdx}-${colIdx}`,
4689
+ "aria-label": `${rowLabel} ${colLabel}`,
4690
+ className: [
4691
+ "ss-w-btg-gc ss-w-btg-cell",
4692
+ filled ? filled.isCorrect ? "ss-w-btg-cell--correct" : "ss-w-btg-cell--wrong" : "",
4693
+ isActive ? "ss-w-btg-cell--active" : ""
4694
+ ].filter(Boolean).join(" "),
4695
+ disabled: isLocked2 || submitting,
4696
+ onClick: () => handleCellClick(rowIdx, colIdx),
4697
+ children: filled ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
4698
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-score", children: filled.rarityScore }),
4699
+ filled.isCorrect && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-check", "aria-hidden": "true", children: "\u2713" })
4700
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-empty", "aria-hidden": "true", children: "+" })
4701
+ },
4702
+ `cell-${rowIdx}-${colIdx}`
4703
+ );
4704
+ })
4705
+ ] }, rowIdx))
4706
+ ]
4707
+ }
4708
+ ),
4709
+ activeCell !== null && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
4710
+ SearchSheet,
4711
+ {
4712
+ row: activeCell.row,
4713
+ col: activeCell.col,
4714
+ rowLabel: rows[activeCell.row] ?? "",
4715
+ colLabel: cols[activeCell.col] ?? "",
4716
+ playerPool,
4717
+ alreadyFilledIds,
4718
+ onPick: handlePick,
4719
+ onDismiss: () => setActiveCell(null)
4720
+ }
4721
+ )
4722
+ ] });
4723
+ }
4724
+
4725
+ // src/components/games/GuessTheXiGame.tsx
4726
+ var import_jsx_runtime59 = require("react/jsx-runtime");
4727
+ function parseClientState5(json) {
4728
+ if (!json) return null;
4729
+ try {
4730
+ return JSON.parse(json);
4731
+ } catch {
4732
+ return null;
4733
+ }
4734
+ }
4735
+ function RevealCard({ reveal }) {
4736
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "ss-w-gxi-reveal", "data-reveal-type": reveal.type ?? "", children: [
4737
+ reveal.slot && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-reveal-slot", children: reveal.slot }),
4738
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-reveal-val", children: reveal.value })
4739
+ ] });
4740
+ }
4741
+ function GuessTheXiGame({
4742
+ config,
4743
+ result,
4744
+ submitting,
4745
+ onSubmit
4746
+ }) {
4747
+ const clientState = parseClientState5(result?.clientStateJson);
4748
+ const isOver = result?.alreadyPlayed === true || clientState?.status === "solved" || clientState?.status === "failed";
4749
+ function handlePick(teamId) {
4750
+ if (!config || isOver || submitting) return;
4751
+ const prevGuesses = clientState?.guessHistory.map((g) => ({ teamId: g.teamId })) ?? [];
4752
+ const newGuesses = [...prevGuesses, { teamId }];
4753
+ onSubmit(JSON.stringify({ guesses: newGuesses }));
4754
+ }
4755
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "ss-w-gxi", "data-testid": "game-screen-guess-the-xi", children: [
4756
+ !config && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4757
+ config && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(import_jsx_runtime59.Fragment, { children: [
4758
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gxi-ctx", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-ctx-label", children: config.poolLabel }) }),
4759
+ config.positions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gxi-pitch", children: config.positions.map((pos) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "ss-w-gxi-pslot", children: [
4760
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-pslot-pos", children: pos.slot }),
4761
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-pslot-nat", children: pos.nationality })
4762
+ ] }, pos.slot)) }),
4763
+ clientState && clientState.earnedReveals.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gxi-reveals", children: clientState.earnedReveals.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(RevealCard, { reveal: r }, i)) }),
4764
+ isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: `ss-w-gxi-banner ss-w-gxi-banner--${clientState.status}`, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "ss-w-gxi-banner-label", children: clientState.status === "solved" ? `Solved! ${clientState.score} pts` : "Better luck tomorrow" }) }),
4765
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gxi-pool", children: config.teamPool.map((team) => {
4766
+ const guessRecord = clientState?.guessHistory.find((g) => g.teamId === team.teamId);
4767
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
4768
+ "button",
4769
+ {
4770
+ type: "button",
4771
+ className: [
4772
+ "ss-w-gxi-team-btn",
4773
+ guessRecord ? guessRecord.wasCorrect ? "ss-w-gxi-team-btn--correct" : "ss-w-gxi-team-btn--wrong" : ""
4774
+ ].filter(Boolean).join(" "),
4775
+ disabled: isOver || submitting,
4776
+ onClick: () => handlePick(team.teamId),
4777
+ children: team.teamName
4778
+ },
4779
+ team.teamId
4780
+ );
4781
+ }) }),
4782
+ !isOver && clientState && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "ss-w-gxi-hint", children: [
4783
+ "Guess ",
4784
+ clientState.guessesUsed + 1,
4785
+ " of 6"
4786
+ ] })
4787
+ ] })
4788
+ ] });
4789
+ }
4790
+
4791
+ // src/components/games/DailyQuizGame.tsx
4792
+ var import_react32 = require("react");
4793
+ var import_jsx_runtime60 = require("react/jsx-runtime");
4794
+ function parseClientState6(json) {
4795
+ if (!json) return null;
4796
+ try {
4797
+ return JSON.parse(json);
4798
+ } catch {
4799
+ return null;
4800
+ }
4801
+ }
4802
+ function findResult(results, index) {
4803
+ return results.find((r) => r.index === index);
4804
+ }
4805
+ function DailyQuizGame({
4806
+ config,
4807
+ result,
4808
+ submitting,
4809
+ onSubmit
4810
+ }) {
4811
+ const [selections, setSelections] = (0, import_react32.useState)(/* @__PURE__ */ new Map());
4812
+ const clientState = parseClientState6(result?.clientStateJson);
4813
+ const isRevealed = (clientState?.results.length ?? 0) > 0 || result?.alreadyPlayed === true;
4814
+ const allAnswered = config != null && selections.size === config.questions.length;
4815
+ function handleSelect(questionIndex, optionIndex) {
4816
+ if (isRevealed || submitting) return;
4817
+ setSelections((prev) => new Map(prev).set(questionIndex, optionIndex));
4818
+ }
4819
+ function handleSubmit() {
4820
+ if (!config || !allAnswered || isRevealed || submitting) return;
4821
+ const answers = config.questions.map((q) => ({
4822
+ index: q.index,
4823
+ selectedOptionIndex: selections.get(q.index) ?? 0
4824
+ }));
4825
+ onSubmit(JSON.stringify({ answers }));
4826
+ }
4827
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "ss-w-dq", "data-testid": "game-screen-daily-quiz", children: [
4828
+ !config && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4829
+ config && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
4830
+ isRevealed && result?.score != null && /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "ss-w-dq-score", children: [
4831
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "ss-w-dq-score-val", children: result.score }),
4832
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "ss-w-dq-score-label", children: "pts" })
4833
+ ] }),
4834
+ !isRevealed && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "ss-w-dq-prog", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
4835
+ "div",
4836
+ {
4837
+ className: "ss-w-dq-prog-fill",
4838
+ style: { width: `${Math.round(selections.size / config.questions.length * 100)}%` }
4839
+ }
4840
+ ) }),
4841
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "ss-w-dq-questions", children: config.questions.map((q) => {
4842
+ const qResult = clientState ? findResult(clientState.results, q.index) : void 0;
4843
+ const selectedIdx = selections.get(q.index);
4844
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "ss-w-dq-q", children: [
4845
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "ss-w-dq-qstem", children: q.stem }),
4846
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "ss-w-dq-opts", children: q.options.map((opt, optIdx) => {
4847
+ let optCls = "ss-w-dq-qopt";
4848
+ if (qResult) {
4849
+ if (optIdx === qResult.correctOptionIndex) {
4850
+ optCls += " ss-w-dq-qopt--correct";
4851
+ } else if (optIdx === selectedIdx && !qResult.isCorrect) {
4852
+ optCls += " ss-w-dq-qopt--wrong";
4853
+ }
4854
+ } else if (optIdx === selectedIdx) {
4855
+ optCls += " ss-w-dq-qopt--selected";
4856
+ }
4857
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
4858
+ "button",
4859
+ {
4860
+ type: "button",
4861
+ className: optCls,
4862
+ disabled: isRevealed || submitting,
4863
+ onClick: () => handleSelect(q.index, optIdx),
4864
+ children: [
4865
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "ss-w-dq-qopt-letter", children: String.fromCharCode(65 + optIdx) }),
4866
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "ss-w-dq-qopt-text", children: opt })
4867
+ ]
4868
+ },
4869
+ optIdx
4870
+ );
4871
+ }) }),
4872
+ qResult?.revealText && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: `ss-w-dq-qwhy ss-w-dq-qwhy--${qResult.isCorrect ? "correct" : "wrong"}`, children: qResult.revealText })
4873
+ ] }, q.index);
4874
+ }) }),
4875
+ !isRevealed && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
4876
+ "button",
4877
+ {
4878
+ type: "button",
4879
+ className: "ss-w-dq-submit",
4880
+ disabled: !allAnswered || submitting,
4881
+ onClick: handleSubmit,
4882
+ "aria-label": "Submit answers",
4883
+ children: submitting ? "Submitting\u2026" : "Submit"
4884
+ }
4885
+ )
4886
+ ] })
4887
+ ] });
4888
+ }
4889
+
4890
+ // src/components/games/MatchdayPredictorGame.tsx
4891
+ var import_react33 = require("react");
4892
+ var import_jsx_runtime61 = require("react/jsx-runtime");
4893
+ function parseClientState7(json) {
4894
+ if (!json) return null;
4895
+ try {
4896
+ return JSON.parse(json);
4897
+ } catch {
4898
+ return null;
4899
+ }
4900
+ }
4901
+ function isLocked(kickoffUtc) {
4902
+ try {
4903
+ return new Date(kickoffUtc).getTime() <= Date.now();
4904
+ } catch {
4905
+ return true;
4906
+ }
4907
+ }
4908
+ function MatchdayPredictorGame({
4909
+ config,
4910
+ result,
4911
+ submitting,
4912
+ onSubmit
4913
+ }) {
4914
+ const [homeScore, setHomeScore] = (0, import_react33.useState)(0);
4915
+ const [awayScore, setAwayScore] = (0, import_react33.useState)(0);
4916
+ const [firstScorerPlayerId, setFirstScorerPlayerId] = (0, import_react33.useState)(null);
4917
+ const clientState = parseClientState7(result?.clientStateJson);
4918
+ const alreadyPlayed = result?.alreadyPlayed === true;
4919
+ if (alreadyPlayed && clientState) {
4920
+ if (!clientState.graded) {
4921
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp", "data-testid": "game-screen-matchday-predictor", children: [
4922
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-live", children: [
4923
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-live-score", children: [
4924
+ clientState.predictedHomeScore,
4925
+ " \u2013 ",
4926
+ clientState.predictedAwayScore
4927
+ ] }),
4928
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-live-label", children: "Locked in \u2014 awaiting result" })
4929
+ ] }),
4930
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-fun", children: "For fun \u2014 not in the leaderboard" })
4931
+ ] });
4932
+ }
4933
+ const r = clientState.result;
4934
+ const actualScore = `${r.homeScore} \u2013 ${r.awayScore}`;
4935
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp", "data-testid": "game-screen-matchday-predictor", children: [
4936
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-live", children: [
4937
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-live-score", children: actualScore }),
4938
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-live-label", children: "Full-time result" }),
4939
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-live-outcome", children: [
4940
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: `ss-w-mp-live-row${clientState.exactScoreCorrect ? " ss-w-mp-live-row--correct" : ""}`, children: [
4941
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-live-row-key", children: "Exact score" }),
4942
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-live-row-val", children: clientState.exactScoreCorrect ? "\u2713" : "\u2717" })
4943
+ ] }),
4944
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: `ss-w-mp-live-row${clientState.outcomeCorrect ? " ss-w-mp-live-row--correct" : ""}`, children: [
4945
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-live-row-key", children: "Result (W/D/L)" }),
4946
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-live-row-val", children: clientState.outcomeCorrect ? "\u2713" : "\u2717" })
4947
+ ] }),
4948
+ !clientState.firstScorerVoid && /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: `ss-w-mp-live-row${clientState.firstScorerCorrect ? " ss-w-mp-live-row--correct" : ""}`, children: [
4949
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-live-row-key", children: "First scorer" }),
4950
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "ss-w-mp-live-row-val", children: [
4951
+ clientState.firstScorerCorrect ? "\u2713" : "\u2717",
4952
+ r.firstScorerName ? ` ${r.firstScorerName}` : ""
4953
+ ] })
4954
+ ] })
4955
+ ] })
4956
+ ] }),
4957
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-fun", children: "For fun \u2014 not in the leaderboard" })
4958
+ ] });
4959
+ }
4960
+ if (!config) {
4961
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp", "data-testid": "game-screen-matchday-predictor", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }) });
4962
+ }
4963
+ const locked = isLocked(config.kickoffUtc);
4964
+ const disabled = locked || submitting;
4965
+ function handleSubmit() {
4966
+ if (disabled || !config) return;
4967
+ onSubmit(
4968
+ JSON.stringify({
4969
+ homeScore,
4970
+ awayScore,
4971
+ ...firstScorerPlayerId !== null ? { firstScorerPlayerId } : {}
4972
+ })
4973
+ );
4974
+ }
4975
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp", "data-testid": "game-screen-matchday-predictor", children: [
4976
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-pred-score", children: [
4977
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-team", children: [
4978
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-team-name", children: config.homeTeam.name }),
4979
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-stepper", children: [
4980
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
4981
+ "button",
4982
+ {
4983
+ type: "button",
4984
+ className: "ss-w-mp-stepper-btn",
4985
+ "aria-label": "-",
4986
+ disabled: disabled || homeScore <= 0,
4987
+ onClick: () => setHomeScore((s) => Math.max(0, s - 1)),
4988
+ children: "\u2212"
4989
+ }
4990
+ ),
4991
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-stepper-val", children: homeScore }),
4992
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
4993
+ "button",
4994
+ {
4995
+ type: "button",
4996
+ className: "ss-w-mp-stepper-btn",
4997
+ "aria-label": "+",
4998
+ disabled,
4999
+ onClick: () => setHomeScore((s) => s + 1),
5000
+ children: "+"
5001
+ }
5002
+ )
5003
+ ] })
5004
+ ] }),
5005
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-sep", children: "\u2013" }),
5006
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-team", children: [
5007
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-team-name", children: config.awayTeam.name }),
5008
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-stepper", children: [
5009
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5010
+ "button",
5011
+ {
5012
+ type: "button",
5013
+ className: "ss-w-mp-stepper-btn",
5014
+ "aria-label": "-",
5015
+ disabled: disabled || awayScore <= 0,
5016
+ onClick: () => setAwayScore((s) => Math.max(0, s - 1)),
5017
+ children: "\u2212"
5018
+ }
5019
+ ),
5020
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "ss-w-mp-stepper-val", children: awayScore }),
5021
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5022
+ "button",
5023
+ {
5024
+ type: "button",
5025
+ className: "ss-w-mp-stepper-btn",
5026
+ "aria-label": "+",
5027
+ disabled,
5028
+ onClick: () => setAwayScore((s) => s + 1),
5029
+ children: "+"
5030
+ }
5031
+ )
5032
+ ] })
5033
+ ] })
5034
+ ] }),
5035
+ config.scorerPool.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "ss-w-mp-scorer", children: [
5036
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-scorer-label", children: "First scorer (optional)" }),
5037
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-scorer-list", children: config.scorerPool.map((p) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5038
+ "button",
5039
+ {
5040
+ type: "button",
5041
+ className: `ss-w-mp-scorer-opt${firstScorerPlayerId === p.playerId ? " ss-w-mp-scorer-opt--selected" : ""}`,
5042
+ disabled,
5043
+ onClick: () => setFirstScorerPlayerId((id) => id === p.playerId ? null : p.playerId),
5044
+ children: p.playerName
5045
+ },
5046
+ p.playerId
5047
+ )) })
5048
+ ] }),
5049
+ locked && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-live-label", children: "Submissions are now closed" }),
5050
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5051
+ "button",
5052
+ {
5053
+ type: "button",
5054
+ className: "ss-w-mp-savebtn",
5055
+ disabled,
5056
+ onClick: handleSubmit,
5057
+ "aria-label": "Save prediction",
5058
+ children: submitting ? "Saving\u2026" : "Save prediction"
5059
+ }
5060
+ ),
5061
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "ss-w-mp-fun", children: "For fun \u2014 not in the leaderboard" })
5062
+ ] });
5063
+ }
5064
+
5065
+ // src/components/games/StartingXiGame.tsx
5066
+ var import_react34 = require("react");
5067
+ var import_jsx_runtime62 = require("react/jsx-runtime");
5068
+ function parseClientState8(json) {
5069
+ if (!json) return null;
5070
+ try {
5071
+ return JSON.parse(json);
5072
+ } catch {
5073
+ return null;
5074
+ }
5075
+ }
5076
+ function parseFormationRows(formation) {
5077
+ const parts = formation.split("-").map(Number).filter((n) => n > 0);
5078
+ if (parts.length === 0) return [1, 4, 3, 3];
5079
+ return [1, ...parts];
5080
+ }
5081
+ function StartingXiGame({
5082
+ config,
5083
+ result,
5084
+ submitting,
5085
+ onSubmit
5086
+ }) {
5087
+ const [picked, setPicked] = (0, import_react34.useState)([]);
5088
+ const clientState = parseClientState8(result?.clientStateJson);
5089
+ const alreadyPlayed = result?.alreadyPlayed === true;
5090
+ if (alreadyPlayed) {
5091
+ if (!clientState) {
5092
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi", "data-testid": "game-screen-starting-xi", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-status", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-status-label", children: "This game has been voided" }) }) });
5093
+ }
5094
+ if (clientState.status === "pending") {
5095
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi", "data-testid": "game-screen-starting-xi", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-status", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ss-w-sxi-status-label", children: [
5096
+ "Prediction locked in (",
5097
+ clientState.predictedCount,
5098
+ " players) \u2014 awaiting result"
5099
+ ] }) }) });
5100
+ }
5101
+ if (clientState.status === "graded") {
5102
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi", "data-testid": "game-screen-starting-xi", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ss-w-sxi-status ss-w-sxi-status--graded", children: [
5103
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-status-score", children: clientState.score }),
5104
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ss-w-sxi-status-label", children: [
5105
+ clientState.correctCount,
5106
+ " correct starters"
5107
+ ] })
5108
+ ] }) });
5109
+ }
5110
+ }
5111
+ if (!config) {
5112
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi", "data-testid": "game-screen-starting-xi", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }) });
5113
+ }
5114
+ const formationRows = parseFormationRows(config.formation);
5115
+ const pickedSet = new Set(picked);
5116
+ const canSubmit = picked.length === 11 && !submitting;
5117
+ function togglePlayer(playerId) {
5118
+ if (submitting) return;
5119
+ setPicked((prev) => {
5120
+ if (prev.includes(playerId)) {
5121
+ return prev.filter((id) => id !== playerId);
5122
+ }
5123
+ if (prev.length >= 11) return prev;
5124
+ return [...prev, playerId];
5125
+ });
5126
+ }
5127
+ function handleSubmit() {
5128
+ if (!canSubmit) return;
5129
+ onSubmit(JSON.stringify({ predictedPlayerIds: picked }));
5130
+ }
5131
+ let slotIndex = 0;
5132
+ const pitchRows = formationRows.map((count, rowIdx) => {
5133
+ const rowSlots = picked.slice(slotIndex, slotIndex + count);
5134
+ slotIndex += count;
5135
+ return { rowIdx, count, rowSlots };
5136
+ });
5137
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "ss-w-sxi", "data-testid": "game-screen-starting-xi", children: [
5138
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-formation", children: config.formation }),
5139
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-pitch", children: pitchRows.map(({ rowIdx, count, rowSlots }) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-pitch-row", children: Array.from({ length: count }).map((_, i) => {
5140
+ const playerId = rowSlots[i];
5141
+ const player = playerId != null ? config.squadSheet.find((p) => p.playerId === playerId) : void 0;
5142
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
5143
+ "div",
5144
+ {
5145
+ className: `ss-w-sxi-pslot${player ? " ss-w-sxi-pslot--filled" : ""}`,
5146
+ onClick: () => {
5147
+ if (player) togglePlayer(player.playerId);
5148
+ },
5149
+ onKeyDown: (e) => {
5150
+ if (e.key === "Enter" && player) togglePlayer(player.playerId);
5151
+ },
5152
+ tabIndex: player ? 0 : -1,
5153
+ role: player ? "button" : void 0,
5154
+ "aria-label": player ? `Remove ${player.playerName ?? ""}` : void 0,
5155
+ children: [
5156
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-pslot-num", children: player?.jerseyNumber ?? (rowIdx === 0 ? "GK" : "?") }),
5157
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-pslot-name", children: player?.playerName ?? "" })
5158
+ ]
5159
+ },
5160
+ i
5161
+ );
5162
+ }) }, rowIdx)) }),
5163
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "ss-w-sxi-squad", children: config.squadSheet.map((p) => {
5164
+ const isPicked = pickedSet.has(p.playerId);
5165
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
5166
+ "div",
5167
+ {
5168
+ className: `ss-w-sxi-squad-row${isPicked ? " ss-w-sxi-squad-row--picked" : ""}`,
5169
+ onClick: () => togglePlayer(p.playerId),
5170
+ onKeyDown: (e) => {
5171
+ if (e.key === "Enter") togglePlayer(p.playerId);
5172
+ },
5173
+ tabIndex: 0,
5174
+ role: "button",
5175
+ "aria-pressed": isPicked,
5176
+ children: [
5177
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ss-w-sxi-squad-name", children: p.playerName }),
5178
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "ss-w-sxi-squad-pos", children: p.positionName })
5179
+ ]
5180
+ },
5181
+ p.playerId
5182
+ );
5183
+ }) }),
5184
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
5185
+ "button",
5186
+ {
5187
+ type: "button",
5188
+ className: "ss-w-sxi-savebtn",
5189
+ disabled: !canSubmit,
5190
+ onClick: handleSubmit,
5191
+ "aria-label": "Predict XI",
5192
+ children: submitting ? "Submitting\u2026" : `Predict XI (${picked.length}/11)`
5193
+ }
5194
+ )
5195
+ ] });
5196
+ }
5197
+
5198
+ // src/components/games/StatLadderGame.tsx
5199
+ var import_jsx_runtime63 = require("react/jsx-runtime");
5200
+ function parseClientState9(json) {
5201
+ if (!json) return null;
5202
+ try {
5203
+ return JSON.parse(json);
5204
+ } catch {
5205
+ return null;
5206
+ }
5207
+ }
5208
+ function StatLadderGame({
5209
+ config,
5210
+ result,
5211
+ submitting,
5212
+ onSubmit
5213
+ }) {
5214
+ const clientState = parseClientState9(result?.clientStateJson);
5215
+ const revealed = clientState != null;
5216
+ if (!config) {
5217
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl", "data-testid": "game-screen-stat-ladder", children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }) });
5218
+ }
5219
+ const mysteryName = revealed ? clientState.revealedRank2.playerName : null;
5220
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "ss-w-sl", "data-testid": "game-screen-stat-ladder", children: [
5221
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl-title", children: config.statLabel }),
5222
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl-ladder", children: config.ladder.map((rung) => {
5223
+ const isMystery = rung.rank === 2;
5224
+ let rowCls = "ss-w-sl-lrow";
5225
+ if (isMystery) rowCls += " ss-w-sl-mystery";
5226
+ if (isMystery && revealed) {
5227
+ rowCls = rowCls.replace(" ss-w-sl-mystery", "");
5228
+ rowCls += clientState.isCorrect ? " ss-w-sl-lrow--correct" : " ss-w-sl-lrow--wrong";
5229
+ }
5230
+ const displayName = isMystery ? revealed ? mysteryName : "?" : rung.playerName ?? "?";
5231
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: rowCls, children: [
5232
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "ss-w-sl-lrow-rank", children: [
5233
+ "#",
5234
+ rung.rank
5235
+ ] }),
5236
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl-lrow-name", children: displayName }),
5237
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl-lrow-stat", children: rung.statValue })
5238
+ ] }, rung.rank);
5239
+ }) }),
5240
+ revealed && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: `ss-w-sl-reveal ss-w-sl-reveal--${clientState.isCorrect ? "correct" : "wrong"}`, children: clientState.isCorrect ? "Correct!" : `Wrong \u2014 it was ${clientState.revealedRank2.playerName}` }),
5241
+ !revealed && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "ss-w-sl-picker", children: config.playerPool.map((p) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5242
+ "button",
5243
+ {
5244
+ type: "button",
5245
+ className: "ss-w-sl-picker-opt",
5246
+ disabled: submitting,
5247
+ "aria-label": p.playerName,
5248
+ onClick: () => onSubmit(JSON.stringify({ guessedPlayerId: p.playerId })),
5249
+ children: p.playerName
5250
+ },
5251
+ p.playerId
5252
+ )) })
5253
+ ] });
5254
+ }
5255
+
5256
+ // src/components/games/FanMotmGame.tsx
5257
+ var import_jsx_runtime64 = require("react/jsx-runtime");
5258
+ function parseClientState10(json) {
5259
+ if (!json) return null;
5260
+ try {
5261
+ return JSON.parse(json);
5262
+ } catch {
5263
+ return null;
5264
+ }
5265
+ }
5266
+ function FanMotmGame({
5267
+ config,
5268
+ result,
5269
+ submitting,
5270
+ onSubmit
5271
+ }) {
5272
+ const clientState = parseClientState10(result?.clientStateJson);
5273
+ const alreadyVoted = result?.alreadyPlayed === true;
5274
+ if (!config) {
5275
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-motm", "data-testid": "game-screen-fan-motm", children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }) });
5276
+ }
5277
+ const pickedId = clientState?.pickedPlayerId ?? null;
5278
+ function handleVote(candidateId) {
5279
+ if (alreadyVoted || submitting) return;
5280
+ onSubmit(JSON.stringify({ pickedPlayerId: candidateId }));
5281
+ }
5282
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "ss-w-motm", "data-testid": "game-screen-fan-motm", children: [
5283
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-motm-title", children: "Man of the Match \u2014 your vote" }),
5284
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-motm-votes", children: config.candidates.map((c) => {
5285
+ const isVoted = alreadyVoted && pickedId === c.playerId;
5286
+ const rowCls = `ss-w-motm-vrow${isVoted ? " ss-w-motm-vrow--voted" : ""}${alreadyVoted ? " ss-w-motm-vrow--result" : ""}`;
5287
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
5288
+ "button",
5289
+ {
5290
+ type: "button",
5291
+ className: rowCls,
5292
+ "data-testid": `motm-candidate-${c.playerId}`,
5293
+ disabled: alreadyVoted || submitting,
5294
+ onClick: () => handleVote(c.playerId),
5295
+ children: [
5296
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-motm-vfill", style: { width: isVoted ? "100%" : "0%" } }),
5297
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "ss-w-motm-vrow-name", children: c.playerName })
5298
+ ]
5299
+ },
5300
+ c.playerId
5301
+ );
5302
+ }) }),
5303
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "ss-w-motm-fun", children: "For fun \u2014 unranked community vote" })
5304
+ ] });
5305
+ }
5306
+
5307
+ // src/components/GameScreenHost.tsx
5308
+ var import_jsx_runtime65 = require("react/jsx-runtime");
5309
+ var FIXTURE_GAME_IDS = /* @__PURE__ */ new Set([
5310
+ "matchday-predictor",
5311
+ "starting-xi",
5312
+ "stat-ladder",
5313
+ "fan-motm"
5314
+ ]);
5315
+ var PENDING_POLL_INTERVAL_MS = 3e4;
5316
+ function safeParseConfig(json) {
5317
+ if (!json) return null;
5318
+ try {
5319
+ return JSON.parse(json);
5320
+ } catch {
5321
+ return null;
5322
+ }
5323
+ }
5324
+ function GameScreenHost({
5325
+ selected,
5326
+ onBack,
5327
+ conversation,
5328
+ ui
5329
+ }) {
5330
+ const { gameId, fixtureId, gameDay = "" } = selected;
5331
+ const [configJson, setConfigJson] = (0, import_react35.useState)(null);
5332
+ (0, import_react35.useEffect)(() => {
5333
+ setConfigJson(null);
5334
+ if (!conversation) return;
5335
+ let cancelled = false;
5336
+ void (async () => {
5337
+ try {
5338
+ const payload = await conversation.getGameConfig(gameId, fixtureId, gameDay || void 0);
5339
+ if (!cancelled && payload?.configJson) {
5340
+ setConfigJson(payload.configJson);
5341
+ }
5342
+ } catch {
5343
+ }
5344
+ })();
5345
+ return () => {
5346
+ cancelled = true;
5347
+ };
5348
+ }, [conversation, gameId, fixtureId, gameDay]);
5349
+ const { result, submitting, submit, hydrate, rawStatus } = useGamePlay(conversation, {
5350
+ gameId,
5351
+ gameDay,
5352
+ fixtureId: fixtureId || void 0
5353
+ });
5354
+ (0, import_react35.useEffect)(() => {
5355
+ if (conversation) hydrate();
5356
+ }, [conversation, gameId]);
5357
+ const hydrateRef = (0, import_react35.useRef)(hydrate);
5358
+ hydrateRef.current = hydrate;
5359
+ (0, import_react35.useEffect)(() => {
5360
+ if (!FIXTURE_GAME_IDS.has(gameId)) return;
5361
+ if (rawStatus !== "pending") return;
5362
+ const timerId = setInterval(() => {
5363
+ hydrateRef.current();
5364
+ }, PENDING_POLL_INTERVAL_MS);
5365
+ return () => clearInterval(timerId);
5366
+ }, [gameId, rawStatus]);
5367
+ const sharedProps = {
5368
+ result,
5369
+ submitting,
5370
+ onSubmit: submit,
5371
+ ui
5372
+ };
5373
+ function renderScreen() {
5374
+ switch (gameId) {
5375
+ case "mystery-tiger":
5376
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5377
+ MysteryTigerGame,
5378
+ {
5379
+ ...sharedProps,
5380
+ config: safeParseConfig(configJson)
5381
+ }
5382
+ );
5383
+ case "higher-or-lower":
5384
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5385
+ HigherOrLowerGame,
5386
+ {
5387
+ ...sharedProps,
5388
+ config: safeParseConfig(configJson)
5389
+ }
5390
+ );
5391
+ case "career-path":
5392
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5393
+ CareerPathGame,
5394
+ {
5395
+ ...sharedProps,
5396
+ config: safeParseConfig(configJson)
5397
+ }
5398
+ );
5399
+ case "beat-the-grid":
5400
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5401
+ BeatTheGridGame,
5402
+ {
5403
+ ...sharedProps,
5404
+ config: safeParseConfig(configJson),
5405
+ playerPool: []
5406
+ }
5407
+ );
5408
+ case "guess-the-xi":
5409
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5410
+ GuessTheXiGame,
5411
+ {
5412
+ ...sharedProps,
5413
+ config: safeParseConfig(configJson)
5414
+ }
5415
+ );
5416
+ case "daily-quiz":
5417
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5418
+ DailyQuizGame,
5419
+ {
5420
+ ...sharedProps,
5421
+ config: safeParseConfig(configJson)
5422
+ }
5423
+ );
5424
+ case "matchday-predictor":
5425
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5426
+ MatchdayPredictorGame,
5427
+ {
5428
+ ...sharedProps,
5429
+ config: safeParseConfig(configJson)
5430
+ }
5431
+ );
5432
+ case "starting-xi":
5433
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5434
+ StartingXiGame,
5435
+ {
5436
+ ...sharedProps,
5437
+ config: safeParseConfig(configJson)
5438
+ }
5439
+ );
5440
+ case "stat-ladder":
5441
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5442
+ StatLadderGame,
5443
+ {
5444
+ ...sharedProps,
5445
+ config: safeParseConfig(configJson)
5446
+ }
5447
+ );
5448
+ case "fan-motm":
5449
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5450
+ FanMotmGame,
5451
+ {
5452
+ ...sharedProps,
5453
+ config: safeParseConfig(configJson)
5454
+ }
5455
+ );
5456
+ default:
5457
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "ss-w-gscreen-body", "data-testid": `game-screen-${gameId}`, children: gameId });
5458
+ }
5459
+ }
5460
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "ss-w-gscreen", children: [
5461
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("button", { type: "button", className: "ss-w-gscreen-back", onClick: onBack, children: [
5462
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "ss-w-gscreen-back-arrow", "aria-hidden": "true", children: "\u2039" }),
5463
+ ui.back
5464
+ ] }),
5465
+ renderScreen()
5466
+ ] });
5467
+ }
5468
+
5469
+ // src/components/GamesPanel.tsx
5470
+ var import_jsx_runtime66 = require("react/jsx-runtime");
5471
+ function GamesPanel({
5472
+ loggedIn,
5473
+ games,
5474
+ ui,
5475
+ conversation
5476
+ }) {
5477
+ const [selected, setSelected] = (0, import_react36.useState)(null);
5478
+ if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(GamesLoginWall, { ui });
5479
+ if (selected !== null) {
5480
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
5481
+ GameScreenHost,
5482
+ {
5483
+ selected,
5484
+ onBack: () => setSelected(null),
5485
+ conversation: conversation ?? null,
5486
+ ui
5487
+ }
5488
+ ) });
5489
+ }
5490
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "ss-w-mon-list", "data-testid": "games-hub", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
5491
+ GamesHub,
5492
+ {
5493
+ games,
5494
+ onOpen: (g) => setSelected({ gameId: g.gameId, fixtureId: g.fixtureId, gameDay: g.gameDay }),
5495
+ ui
5496
+ }
5497
+ ) });
5498
+ }
5499
+
5500
+ // src/components/Leaderboard.tsx
5501
+ var import_react37 = require("react");
5502
+
5503
+ // src/components/LeaderboardRow.tsx
5504
+ var import_jsx_runtime67 = require("react/jsx-runtime");
5505
+ function formatPoints(n) {
5506
+ return n.toLocaleString("en");
5507
+ }
5508
+ function LeaderboardWeeklyRow({
5509
+ row,
5510
+ isMe
5511
+ }) {
5512
+ const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? " ss-w-lb2-rank--top3" : ""}`;
5513
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: `ss-w-lb2-row${isMe ? " ss-w-lb2-row--you" : ""}`, children: [
5514
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: rankClass, children: [
5515
+ "#",
5516
+ row.rank
5517
+ ] }),
5518
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "ss-w-lb2-handle", children: row.handle }),
5519
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "ss-w-lb2-points", children: formatPoints(row.points) }),
5520
+ row.currentStreak > 0 && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "ss-w-lb2-streak", children: [
5521
+ "\u{1F525} ",
5522
+ row.currentStreak
5523
+ ] })
5524
+ ] });
5525
+ }
5526
+ function LeaderboardAllTimeRow({
5527
+ row,
5528
+ isMe
5529
+ }) {
5530
+ const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? " ss-w-lb2-rank--top3" : ""}`;
5531
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: `ss-w-lb2-row${isMe ? " ss-w-lb2-row--you" : ""}`, children: [
5532
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: rankClass, children: [
5533
+ "#",
5534
+ row.rank
5535
+ ] }),
5536
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "ss-w-lb2-handle", children: row.handle }),
5537
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "ss-w-lb2-points", children: formatPoints(row.allTimePoints) })
5538
+ ] });
5539
+ }
5540
+
5541
+ // src/components/Leaderboard.tsx
5542
+ var import_jsx_runtime68 = require("react/jsx-runtime");
5543
+ function Leaderboard({
5544
+ data,
5545
+ ui
5546
+ }) {
5547
+ const [segment, setSegment] = (0, import_react37.useState)("weekly");
5548
+ const myRow = segment === "weekly" ? data.myWeeklyRow : data.myAllTimeRow;
5549
+ const offBoard = myRow !== null && myRow !== void 0 && myRow.rank === -1;
5550
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "ss-w-lb2", children: [
5551
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "ss-w-seg", children: [
5552
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5553
+ "button",
5554
+ {
5555
+ type: "button",
5556
+ className: "ss-w-seg-btn",
5557
+ ...segment === "weekly" ? { "data-on": "" } : {},
5558
+ onClick: () => setSegment("weekly"),
5559
+ children: ui.leaderboardThisWeek
5560
+ }
5561
+ ),
5562
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5563
+ "button",
5564
+ {
5565
+ type: "button",
5566
+ className: "ss-w-seg-btn",
5567
+ ...segment === "alltime" ? { "data-on": "" } : {},
5568
+ onClick: () => setSegment("alltime"),
5569
+ children: ui.leaderboardAllTime
5570
+ }
5571
+ )
5572
+ ] }),
5573
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "ss-w-lb2-rows", children: segment === "weekly" ? data.weeklyTop.map((row) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5574
+ LeaderboardWeeklyRow,
5575
+ {
5576
+ row,
5577
+ isMe: row.operatorUserId === data.myWeeklyRow?.operatorUserId
5578
+ },
5579
+ row.operatorUserId
5580
+ )) : data.allTimeTop.map((row) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
5581
+ LeaderboardAllTimeRow,
5582
+ {
5583
+ row,
5584
+ isMe: row.operatorUserId === data.myAllTimeRow?.operatorUserId
5585
+ },
5586
+ row.operatorUserId
5587
+ )) }),
5588
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "ss-w-kitline", children: "\u{1F3BD}" }),
5589
+ myRow != null && (offBoard ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "ss-w-lbgap", children: ui.leaderboardOffBoard }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "ss-w-lb2-rows", children: [
5590
+ segment === "weekly" && data.myWeeklyRow && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(LeaderboardWeeklyRow, { row: data.myWeeklyRow, isMe: true }),
5591
+ segment === "alltime" && data.myAllTimeRow && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(LeaderboardAllTimeRow, { row: data.myAllTimeRow, isMe: true })
5592
+ ] })),
5593
+ segment === "alltime" && data.myAllTimeRow && !offBoard && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "ss-w-lb2-rows", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "ss-w-lb2-row", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "ss-w-lb2-handle", children: formatPoints(data.allTimeTop.reduce((s, r) => s + r.allTimePoints, 0)) }) }) })
5594
+ ] });
5595
+ }
5596
+
5597
+ // src/components/LeaderboardPanel.tsx
5598
+ var import_jsx_runtime69 = require("react/jsx-runtime");
5599
+ function LeaderboardPanel({ loggedIn, data, ui }) {
5600
+ if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(GamesLoginWall, { ui });
5601
+ if (data === null) return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "ss-w-mon-list" });
5602
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Leaderboard, { data, ui }) });
5603
+ }
5604
+
5605
+ // src/components/ChatPanel.tsx
5606
+ var import_jsx_runtime70 = require("react/jsx-runtime");
5607
+ var FULLSCREEN_QUERY = "(max-width: 639px)";
5608
+ function useIsModal() {
5609
+ const [modal, setModal] = (0, import_react38.useState)(false);
5610
+ (0, import_react38.useEffect)(() => {
5611
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
5612
+ const mql = window.matchMedia(FULLSCREEN_QUERY);
5613
+ const sync = () => setModal(mql.matches);
5614
+ sync();
5615
+ mql.addEventListener("change", sync);
5616
+ return () => mql.removeEventListener("change", sync);
5617
+ }, []);
5618
+ return modal;
5619
+ }
5620
+ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }) {
5621
+ const { state, close, stop, send, reset } = controller;
5622
+ const isModal = useIsModal();
5623
+ (0, import_react38.useEffect)(() => {
5624
+ const onKey = (e) => {
5625
+ if (e.key === "Escape") close();
5626
+ };
5627
+ window.addEventListener("keydown", onKey);
5628
+ return () => window.removeEventListener("keydown", onKey);
5629
+ }, [close]);
5630
+ const handleSend = (text) => {
5631
+ monitor?.setActiveTab("chat");
5632
+ send(text);
5633
+ };
5634
+ (0, import_react38.useEffect)(() => {
5635
+ if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
5636
+ }, [monitor, state.isStreaming, state.messages.length]);
5637
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
5638
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
5639
+ ChatHeader,
5640
+ {
5641
+ onClose: close,
5642
+ closeLabel: ui.closeChat,
5643
+ logoUrl: ui.logoUrl,
5644
+ headerTitle: ui.headerTitle,
5645
+ onNewConversation: reset,
5646
+ canReset: state.messages.length > 0,
5647
+ newConversationLabel: ui.newConversation,
5648
+ moreOptionsLabel: ui.moreOptions
5649
+ }
5650
+ ),
5651
+ monitor && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
5652
+ TabBar,
5653
+ {
5654
+ monitor,
5655
+ ui,
5656
+ matchCount: monitor.pins.filter((p) => p.kind === "match").length,
5657
+ oddsCount: monitor.pins.filter((p) => p.kind !== "match").length,
5658
+ todayCount: discovery?.liveCount ?? 0,
5659
+ hasToday: discovery ? visibleGroupsOf(discovery.groups, discovery.states).length > 0 : false,
5660
+ gamesEnabled: gamesResult?.enabled ?? false
5661
+ }
5662
+ ),
5663
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
5664
+ "div",
5665
+ {
5666
+ style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
5667
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
5668
+ }
5669
+ ),
5670
+ monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(TodayPanel, { discovery, ui, monitor }),
5671
+ monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(MatchesPanel, { monitor, ui, slip }),
5672
+ monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(OddsPanel, { monitor, ui, slip }),
5673
+ monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(GamesPanel, { loggedIn: !!loggedIn, games: gamesResult.games, ui, conversation }),
5674
+ monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(LeaderboardPanel, { loggedIn: !!loggedIn, data: leaderboardResult.data, ui }),
5675
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
5676
+ ] });
5677
+ }
5678
+
5679
+ // src/styles/css.generated.ts
5680
+ var WIDGET_CSS = `.ss-w-root { all: revert; }
5681
+ .ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }
5682
+ .ss-w-root {
5683
+ --ss-w-accent: #17936a;
5684
+ --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;
5685
+ --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;
5686
+ --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
5687
+ --ss-w-pos: #1aa563; --ss-w-neg: #e0524b;
5688
+ --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
5689
+ --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;
5690
+ --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;
5691
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
5692
+ font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);
5693
+ }
5694
+ @media (prefers-color-scheme: dark) {
5695
+ .ss-w-root[data-ss-w-theme="auto"] {
5696
+ --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;
5697
+ --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
5698
+ --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
5699
+ --ss-w-pos: #37c891; --ss-w-neg: #f0655d;
5700
+ --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
5701
+ --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;
5702
+ }
5703
+ }
5704
+ .ss-w-root[data-ss-w-theme="dark"] {
5705
+ --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;
5706
+ --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;
5707
+ --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;
5708
+ --ss-w-pos: #37c891; --ss-w-neg: #f0655d;
5709
+ --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;
5710
+ --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;
5711
+ }
5712
+ .ss-w-root[data-ss-w-theme="light"] {
5713
+ --ss-w-accent: #17936a; --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;
5714
+ --ss-w-ink: #14181d; --ss-w-faint: #6b7580;
5715
+ --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;
5716
+ --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;
5717
+ --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;
5718
+ }
5719
+
3950
5720
  /* launcher */
3951
5721
  .ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
3952
5722
  .ss-w-root[data-ss-w-pos="right"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }
@@ -4679,7 +6449,12 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
4679
6449
  .ss-w-mon-vs { font-size: 12px; font-weight: 700; color: var(--ss-w-faint); text-transform: uppercase; }
4680
6450
  .ss-w-mon-score { display: flex; align-items: baseline; justify-content: center; font-size: 26px; font-weight: 850; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; color: var(--ss-w-ink); }
4681
6451
  .ss-w-mon-score i { font-style: normal; color: var(--ss-w-faint); font-weight: 500; margin: 0 4px; }
4682
- .ss-w-mon-scorers { font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }
6452
+ .ss-w-mon-scorers { display: grid; grid-template-columns: 1fr auto 1fr; align-items: start; column-gap: 10px; font-size: 11.5px; color: var(--ss-w-faint); }
6453
+ .ss-w-mon-scorers-col { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
6454
+ .ss-w-mon-scorers-col li { overflow-wrap: anywhere; }
6455
+ .ss-w-mon-scorers-home { text-align: right; }
6456
+ .ss-w-mon-scorers-away { text-align: left; }
6457
+ .ss-w-mon-scorers-ball { flex: none; align-self: start; line-height: 1.35; }
4683
6458
  .ss-w-mon-stats { display: flex; flex-direction: column; gap: 10px; }
4684
6459
  .ss-w-mon-stat { display: flex; flex-direction: column; gap: 5px; }
4685
6460
  .ss-w-mon-pstrip { padding: 6px 8px; border-radius: 8px; background: color-mix(in srgb, var(--ss-w-accent) 8%, transparent); }
@@ -4781,10 +6556,384 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
4781
6556
  .ss-w-drow-crest { width: 16px; height: 16px; flex: none; border-radius: 50%; object-fit: contain; background: var(--ss-w-bubble); }
4782
6557
 
4783
6558
  .ss-w-stale { font-size: 11px; font-weight: 600; color: var(--ss-w-cta); background: color-mix(in srgb, var(--ss-w-cta) 12%, var(--ss-w-panel)); border-radius: 8px; padding: 6px 9px; }
6559
+
6560
+ /* ---- Games hub (D2) ---- */
6561
+ /* Hub shell: prize banner \u2192 chips \u2192 game matrix, all in a single column */
6562
+ .ss-w-games-hub { display: flex; flex-direction: column; gap: 12px; }
6563
+
6564
+ /* Prize banner: CTA-tinted card with icon + body column (label + chips) */
6565
+ .ss-w-prize { display: flex; align-items: flex-start; gap: 10px; padding: 11px 13px; border-radius: 12px; background: color-mix(in srgb, var(--ss-w-cta) 10%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-cta) 22%, var(--ss-w-line)); }
6566
+ .ss-w-prize-icon { flex: none; font-size: 20px; line-height: 1; padding-top: 1px; }
6567
+ .ss-w-prize-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
6568
+ .ss-w-prize-text { font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.35; overflow-wrap: anywhere; }
6569
+
6570
+ /* Hub chips (streak / rank) \u2014 NOT .ss-w-chip which belongs to intent chips */
6571
+ .ss-w-g-chips { display: flex; gap: 6px; flex-wrap: wrap; }
6572
+ .ss-w-g-chip { display: inline-flex; align-items: center; font-size: 11px; font-weight: 700; border-radius: 999px; padding: 3px 10px; border: 1px solid transparent; white-space: nowrap; }
6573
+ .ss-w-g-chip--streak { color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border-color: var(--ss-w-cta); }
6574
+ .ss-w-g-chip--rank { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-accent) 24%, var(--ss-w-line)); }
6575
+
6576
+ /* Game matrix: 2-column grid of tiles */
6577
+ .ss-w-gmatrix { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
6578
+
6579
+ /* Game tile: a tappable card with status-driven visual state */
6580
+ .ss-w-tile { display: flex; flex-direction: column; gap: 6px; padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line); background: var(--ss-w-panel); cursor: pointer; text-align: left; font: inherit; color: inherit; width: 100%; min-width: 0; transition: background .12s ease; }
6581
+ .ss-w-tile:not([data-disabled]):hover { background: var(--ss-w-bubble); }
6582
+ .ss-w-tile[data-disabled] { opacity: .6; cursor: default; pointer-events: none; }
6583
+ .ss-w-tile-icon { font-size: 22px; line-height: 1; }
6584
+ .ss-w-tile-title { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.25; overflow-wrap: anywhere; }
6585
+ .ss-w-tile-status { font-size: 11px; color: var(--ss-w-faint); font-weight: 500; }
6586
+ .ss-w-tile-status--available { color: var(--ss-w-accent); font-weight: 600; }
6587
+ .ss-w-tile-status--in_progress { color: var(--ss-w-accent); font-weight: 600; }
6588
+ .ss-w-tile-status--played { color: var(--ss-w-correct); font-weight: 700; font-variant-numeric: tabular-nums; }
6589
+ .ss-w-tile-status--graded { color: var(--ss-w-correct); font-weight: 700; font-variant-numeric: tabular-nums; }
6590
+ /* Skill / For-fun kind chip */
6591
+ .ss-w-tile-chip { display: inline-flex; align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; border-radius: 999px; padding: 2px 7px; margin-top: 2px; }
6592
+ .ss-w-tile-chip--skill { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); }
6593
+ .ss-w-tile-chip--fun { color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); }
6594
+
6595
+ /* Game screen host: back-row + placeholder body */
6596
+ .ss-w-gscreen { display: flex; flex-direction: column; gap: 0; }
6597
+ .ss-w-gscreen-back { display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; padding: 6px 0 10px; align-self: flex-start; }
6598
+ .ss-w-gscreen-back-arrow { font-size: 11px; font-weight: 700; }
6599
+ .ss-w-gscreen-body { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 16px; color: var(--ss-w-faint); font-size: 13px; text-align: center; }
6600
+
6601
+ /* ---- Leaderboard (D2) ---- */
6602
+ /* Outer shell */
6603
+ .ss-w-lb2 { display: flex; flex-direction: column; gap: 12px; }
6604
+
6605
+ /* Segmented control: This week / All time */
6606
+ .ss-w-seg { display: inline-flex; gap: 2px; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }
6607
+ .ss-w-seg-btn { font-size: 12px; font-weight: 600; border: none; border-radius: 7px; padding: 5px 12px; color: var(--ss-w-faint); background: none; cursor: pointer; font: inherit; white-space: nowrap; }
6608
+ .ss-w-seg-btn[data-on] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 3px rgba(0,0,0,.09); }
6609
+
6610
+ /* Row list */
6611
+ .ss-w-lb2-rows { display: flex; flex-direction: column; border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; background: var(--ss-w-panel); }
6612
+ .ss-w-lb2-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--ss-w-line); }
6613
+ .ss-w-lb2-row:last-child { border-bottom: none; }
6614
+ /* Highlighted "you" row: full-width tint via negative margin trick, contained by border-radius above */
6615
+ .ss-w-lb2-row--you { background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); }
6616
+ .ss-w-lb2-rank { flex: none; min-width: 30px; font-size: 12.5px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-faint); }
6617
+ .ss-w-lb2-rank--top3 { color: var(--ss-w-cta); }
6618
+ .ss-w-lb2-handle { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ss-w-ink); }
6619
+ .ss-w-lb2-points { flex: none; font-size: 13px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
6620
+ .ss-w-lb2-streak { flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); padding-left: 4px; }
6621
+
6622
+ /* Kit-prize separator: a labelled hairline (eyebrow + two growing lines) */
6623
+ .ss-w-kitline { display: flex; align-items: center; gap: 8px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); }
6624
+ .ss-w-kitline::before, .ss-w-kitline::after { content: ""; flex: 1; height: 1px; background: var(--ss-w-line); }
6625
+
6626
+ /* Off-board treatment: dashed pill indicating rank is outside top N */
6627
+ .ss-w-lbgap { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 12px; font-size: 11.5px; color: var(--ss-w-faint); border: 1px dashed var(--ss-w-line); border-radius: 10px; }
6628
+
6629
+ /* ---- Mystery Tiger game screen (D3) ---- */
6630
+ .ss-w-gt { display: flex; flex-direction: column; gap: 10px; }
6631
+ /* Typeahead wrapper: relative so the dropdown can position under it */
6632
+ .ss-w-gtta { position: relative; }
6633
+ .ss-w-gtta-i { width: 100%; box-sizing: border-box; padding: 9px 12px; border-radius: 10px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); color: var(--ss-w-ink); font: inherit; font-size: 13px; outline: none; transition: border-color .12s; }
6634
+ .ss-w-gtta-i:focus { border-color: var(--ss-w-accent); }
6635
+ .ss-w-gtta-i:disabled { opacity: .5; cursor: not-allowed; }
6636
+ .ss-w-gtta-drop { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 10; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 10px; max-height: 180px; overflow-y: auto; box-shadow: 0 4px 16px rgba(0,0,0,.12); }
6637
+ .ss-w-gtta-opt { padding: 9px 12px; font-size: 13px; cursor: pointer; color: var(--ss-w-ink); border-bottom: 1px solid var(--ss-w-line); }
6638
+ .ss-w-gtta-opt:last-child { border-bottom: none; }
6639
+ .ss-w-gtta-opt:hover { background: var(--ss-w-bubble); }
6640
+ /* Column header labels: one cell per attribute */
6641
+ .ss-w-gthdr { display: grid; grid-template-columns: 1fr repeat(5, 36px); gap: 4px; padding: 0 2px; }
6642
+ .ss-w-gthdr-c { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6643
+ .ss-w-gthdr-c--name { text-align: left; }
6644
+ /* Guess rows */
6645
+ .ss-w-gtrows { display: flex; flex-direction: column; gap: 4px; }
6646
+ .ss-w-gtrow { display: grid; grid-template-columns: 1fr repeat(5, 36px); gap: 4px; align-items: center; }
6647
+ .ss-w-gtrow-nm { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 4px; }
6648
+ /* Verdict tiles */
6649
+ .ss-w-gtile { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 36px; border-radius: 8px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; gap: 1px; transition: transform .1s; }
6650
+ .ss-w-gtile--exact { background: var(--ss-w-correct); color: #fff; }
6651
+ .ss-w-gtile--near { background: var(--ss-w-cta); color: var(--ss-w-cta-ink, #fff); }
6652
+ .ss-w-gtile--miss { background: var(--ss-w-bubble); color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); }
6653
+ .ss-w-gtile-dir { font-size: 11px; line-height: 1; }
6654
+ /* Hint line */
6655
+ .ss-w-gt-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; padding: 2px 0; font-style: italic; }
6656
+ /* Outcome banner: shown when solved or failed */
6657
+ .ss-w-gt-banner { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 12px; border-radius: 12px; text-align: center; }
6658
+ .ss-w-gt-banner--solved { background: color-mix(in srgb, var(--ss-w-correct) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); }
6659
+ .ss-w-gt-banner--failed { background: color-mix(in srgb, var(--ss-w-wrong) 8%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); }
6660
+ .ss-w-gt-banner-name { font-size: 16px; font-weight: 750; color: var(--ss-w-ink); }
6661
+ .ss-w-gt-banner-label { font-size: 12px; color: var(--ss-w-faint); }
6662
+
6663
+ /* ---- Higher or Lower game screen (D3) ---- */
6664
+ .ss-w-hl { display: flex; flex-direction: column; gap: 12px; }
6665
+ /* Stat context header: family name + season */
6666
+ .ss-w-hlctx { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
6667
+ .ss-w-hlctx-fam { font-size: 14px; font-weight: 750; color: var(--ss-w-ink); }
6668
+ .ss-w-hlctx-szn { font-size: 11.5px; color: var(--ss-w-faint); font-weight: 500; }
6669
+ /* Score chip */
6670
+ .ss-w-hl-score { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 11%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 22%, var(--ss-w-line)); border-radius: 999px; padding: 3px 10px; }
6671
+ /* Pair card: two player cards + divider */
6672
+ .ss-w-hlpair { display: flex; align-items: stretch; gap: 0; border-radius: 14px; border: 1.5px solid var(--ss-w-line); overflow: hidden; background: var(--ss-w-panel); }
6673
+ /* Player card */
6674
+ .ss-w-hlpc { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 10px; text-align: center; }
6675
+ .ss-w-hlpc--b { border-left: 1px solid var(--ss-w-line); }
6676
+ .ss-w-hlpc-name { font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.25; word-break: break-word; min-width: 0; }
6677
+ .ss-w-hlpc-val { font-size: 22px; font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; line-height: 1; }
6678
+ .ss-w-hlpc-val--hidden { color: var(--ss-w-faint); font-size: 26px; }
6679
+ .ss-w-hlpc-val--correct { color: var(--ss-w-correct); }
6680
+ .ss-w-hlpc-val--wrong { color: var(--ss-w-cta); }
6681
+ .ss-w-hlpc-badge { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; border-radius: 999px; padding: 2px 8px; }
6682
+ .ss-w-hlpc-badge--correct { color: #fff; background: var(--ss-w-correct); }
6683
+ .ss-w-hlpc-badge--wrong { color: var(--ss-w-cta-ink, #fff); background: var(--ss-w-cta); }
6684
+ /* Higher / Lower buttons */
6685
+ .ss-w-hlbtns { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
6686
+ .ss-w-hlbtn { padding: 11px; border-radius: 10px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); color: var(--ss-w-ink); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; transition: background .1s, border-color .1s, color .1s; }
6687
+ .ss-w-hlbtn:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); color: var(--ss-w-accent); }
6688
+ .ss-w-hlbtn:disabled { opacity: .5; cursor: not-allowed; }
6689
+ /* Answered pair result rows */
6690
+ .ss-w-hlresults { display: flex; flex-direction: column; gap: 4px; }
6691
+ .ss-w-hlrrow { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 8px; font-size: 12px; background: var(--ss-w-bubble); }
6692
+ .ss-w-hlrrow--correct { background: color-mix(in srgb, var(--ss-w-correct) 8%, var(--ss-w-panel)); }
6693
+ .ss-w-hlrrow--wrong { background: color-mix(in srgb, var(--ss-w-cta) 8%, var(--ss-w-panel)); }
6694
+ .ss-w-hlrrow-names { flex: 1; min-width: 0; font-weight: 600; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6695
+ .ss-w-hlrrow-pick { font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-faint); }
6696
+ .ss-w-hlrrow-icon { font-size: 14px; flex: none; }
6697
+
6698
+ /* ---- Career Path game screen (D3) ---- */
6699
+ .ss-w-cpath { display: flex; flex-direction: column; gap: 12px; }
6700
+ /* Context header */
6701
+ .ss-w-cpath-ctx { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 4px; }
6702
+ .ss-w-cpath-ctx-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
6703
+ .ss-w-cpath-ctx-count { font-size: 12px; font-weight: 600; color: var(--ss-w-accent); }
6704
+ /* Career path: vertical timeline of club spells */
6705
+ .ss-w-cpath-path { display: flex; flex-direction: column; gap: 4px; }
6706
+ /* Single club card */
6707
+ .ss-w-cpath-club { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 10px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }
6708
+ .ss-w-cpath-club--loan { border-style: dashed; }
6709
+ /* Crest image / fallback */
6710
+ .ss-w-cpath-crest { width: 30px; height: 30px; object-fit: contain; flex: none; border-radius: 4px; }
6711
+ .ss-w-cpath-crest--fallback { background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 4px; }
6712
+ /* Club info: name + years */
6713
+ .ss-w-cpath-club-info { display: flex; flex: 1; min-width: 0; align-items: center; gap: 6px; flex-wrap: wrap; }
6714
+ .ss-w-cpath-club-name { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6715
+ .ss-w-cpath-spell-yr { font-size: 11px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; }
6716
+ .ss-w-cpath-loan-badge { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; padding: 1px 7px; border-radius: 999px; background: color-mix(in srgb, var(--ss-w-cta) 15%, var(--ss-w-panel)); color: var(--ss-w-cta-ink, #1b1300); border: 1px solid color-mix(in srgb, var(--ss-w-cta) 30%, var(--ss-w-line)); flex: none; }
6717
+ /* Hidden clubs indicator */
6718
+ .ss-w-cpath-hidden { font-size: 11.5px; color: var(--ss-w-faint); font-style: italic; text-align: center; padding: 6px 0 2px; }
6719
+ /* Hint line */
6720
+ .ss-w-cpath-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; padding: 2px 0; font-style: italic; }
6721
+ /* Outcome banner */
6722
+ .ss-w-cpath-banner { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 12px; border-radius: 12px; text-align: center; }
6723
+ .ss-w-cpath-banner--solved { background: color-mix(in srgb, var(--ss-w-correct) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); }
6724
+ .ss-w-cpath-banner--failed { background: color-mix(in srgb, var(--ss-w-wrong) 8%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); }
6725
+ .ss-w-cpath-banner-name { font-size: 16px; font-weight: 750; color: var(--ss-w-ink); }
6726
+ .ss-w-cpath-banner-label { font-size: 12px; color: var(--ss-w-faint); }
6727
+
6728
+ /* ---- Beat the Grid game screen (D3) ---- */
6729
+ .ss-w-btg { display: flex; flex-direction: column; gap: 10px; }
6730
+ /* Score/context row */
6731
+ .ss-w-btg-ctx { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
6732
+ .ss-w-btg-ctx-score { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
6733
+ .ss-w-btg-ctx-left { font-size: 12px; color: var(--ss-w-faint); font-weight: 500; }
6734
+ .ss-w-btg-ctx-done { font-size: 12px; font-weight: 700; color: var(--ss-w-correct); }
6735
+ /* Grid layout \u2014 col count driven inline via style */
6736
+ .ss-w-btg-grid { display: grid; gap: 4px; width: 100%; }
6737
+ /* Generic grid cell */
6738
+ .ss-w-btg-gc { display: flex; align-items: center; justify-content: center; text-align: center; border-radius: 8px; min-height: 42px; padding: 4px; font-size: 11px; word-break: break-word; line-height: 1.2; }
6739
+ /* Corner placeholder */
6740
+ .ss-w-btg-gc--corner { background: none; }
6741
+ /* Column header */
6742
+ .ss-w-btg-gc--colhdr { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); }
6743
+ /* Row header */
6744
+ .ss-w-btg-gc--rowhdr { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); writing-mode: horizontal-tb; }
6745
+ /* Interactive cells */
6746
+ .ss-w-btg-cell { flex-direction: column; gap: 2px; cursor: pointer; background: var(--ss-w-panel); border: 1.5px solid var(--ss-w-line); transition: border-color .12s, background .12s; }
6747
+ .ss-w-btg-cell:hover:not(:disabled) { border-color: var(--ss-w-accent); background: var(--ss-w-bubble); }
6748
+ .ss-w-btg-cell:disabled { cursor: not-allowed; opacity: .75; }
6749
+ .ss-w-btg-cell--correct { background: color-mix(in srgb, var(--ss-w-correct) 14%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-correct) 35%, var(--ss-w-line)); }
6750
+ .ss-w-btg-cell--wrong { background: color-mix(in srgb, var(--ss-w-wrong) 10%, var(--ss-w-panel)); }
6751
+ .ss-w-btg-cell--active { border-color: var(--ss-w-accent); }
6752
+ .ss-w-btg-cell-score { font-size: 14px; font-weight: 800; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }
6753
+ .ss-w-btg-cell-check { font-size: 12px; color: var(--ss-w-correct); line-height: 1; }
6754
+ .ss-w-btg-cell-empty { font-size: 16px; color: var(--ss-w-faint); }
6755
+ /* Scoped search sheet: slides up over the grid */
6756
+ .ss-w-btg-sheet { display: flex; flex-direction: column; gap: 10px; padding: 12px; background: var(--ss-w-panel); border: 1.5px solid var(--ss-w-line); border-radius: 14px; box-shadow: 0 4px 20px rgba(0,0,0,.1); }
6757
+ .ss-w-btg-sheet-hdr { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
6758
+ .ss-w-btg-sheet-ctx { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
6759
+ .ss-w-btg-sheet-row { font-size: 12.5px; font-weight: 700; color: var(--ss-w-ink); }
6760
+ .ss-w-btg-sheet-sep { font-size: 13px; color: var(--ss-w-faint); font-weight: 500; }
6761
+ .ss-w-btg-sheet-col { font-size: 12.5px; font-weight: 700; color: var(--ss-w-accent); }
6762
+ .ss-w-btg-sheet-close { background: none; border: none; cursor: pointer; font-size: 14px; color: var(--ss-w-faint); padding: 2px 6px; border-radius: 6px; line-height: 1; font: inherit; }
6763
+ .ss-w-btg-sheet-close:hover { color: var(--ss-w-ink); background: var(--ss-w-bubble); }
6764
+
6765
+ /* ---- Guess the XI game screen (D3) ---- */
6766
+ .ss-w-gxi { display: flex; flex-direction: column; gap: 12px; }
6767
+ /* Context label (pool label) */
6768
+ .ss-w-gxi-ctx { display: flex; align-items: center; }
6769
+ .ss-w-gxi-ctx-label { font-size: 12px; font-weight: 700; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .05em; }
6770
+ /* Positions pitch: compact slot grid */
6771
+ .ss-w-gxi-pitch { display: flex; flex-wrap: wrap; gap: 5px; }
6772
+ .ss-w-gxi-pslot { display: flex; flex-direction: column; align-items: center; gap: 2px; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 8px; padding: 6px 10px; min-width: 52px; }
6773
+ .ss-w-gxi-pslot-pos { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-accent); }
6774
+ .ss-w-gxi-pslot-nat { font-size: 10px; color: var(--ss-w-faint); font-weight: 500; text-align: center; line-height: 1.2; }
6775
+ /* Earned reveals */
6776
+ .ss-w-gxi-reveals { display: flex; flex-direction: column; gap: 4px; }
6777
+ .ss-w-gxi-reveal { display: flex; align-items: center; gap: 6px; padding: 7px 10px; background: color-mix(in srgb, var(--ss-w-cta) 8%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-cta) 22%, var(--ss-w-line)); border-radius: 8px; }
6778
+ .ss-w-gxi-reveal-slot { font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-cta-ink, #1b1300); background: var(--ss-w-cta); border-radius: 6px; padding: 1px 6px; flex: none; }
6779
+ .ss-w-gxi-reveal-val { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
6780
+ /* Team pool: responsive flex grid of buttons */
6781
+ .ss-w-gxi-pool { display: flex; flex-wrap: wrap; gap: 6px; }
6782
+ .ss-w-gxi-team-btn { font: inherit; font-size: 12.5px; font-weight: 650; border-radius: 10px; padding: 9px 14px; cursor: pointer; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); color: var(--ss-w-ink); transition: background .1s, border-color .1s; }
6783
+ .ss-w-gxi-team-btn:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6784
+ .ss-w-gxi-team-btn:disabled { opacity: .5; cursor: not-allowed; }
6785
+ .ss-w-gxi-team-btn--correct { background: color-mix(in srgb, var(--ss-w-correct) 14%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-correct) 35%, var(--ss-w-line)); color: var(--ss-w-correct); }
6786
+ .ss-w-gxi-team-btn--wrong { background: color-mix(in srgb, var(--ss-w-wrong) 8%, var(--ss-w-panel)); text-decoration: line-through; opacity: .65; }
6787
+ /* Outcome banner */
6788
+ .ss-w-gxi-banner { display: flex; align-items: center; justify-content: center; padding: 10px 12px; border-radius: 10px; }
6789
+ .ss-w-gxi-banner--solved { background: color-mix(in srgb, var(--ss-w-correct) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); }
6790
+ .ss-w-gxi-banner--failed { background: color-mix(in srgb, var(--ss-w-wrong) 8%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); }
6791
+ .ss-w-gxi-banner-label { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
6792
+ /* Hint line */
6793
+ .ss-w-gxi-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; font-style: italic; }
6794
+
6795
+ /* ---- Daily Quiz game screen (D3) ---- */
6796
+ .ss-w-dq { display: flex; flex-direction: column; gap: 14px; }
6797
+ /* Score banner (post-reveal) */
6798
+ .ss-w-dq-score { display: flex; align-items: baseline; justify-content: center; gap: 4px; padding: 10px; background: color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); border-radius: 12px; }
6799
+ .ss-w-dq-score-val { font-size: 26px; font-weight: 800; color: var(--ss-w-correct); font-variant-numeric: tabular-nums; }
6800
+ .ss-w-dq-score-label { font-size: 13px; font-weight: 650; color: var(--ss-w-faint); }
6801
+ /* Progress bar */
6802
+ .ss-w-dq-prog { height: 4px; border-radius: 999px; background: var(--ss-w-bubble); overflow: hidden; }
6803
+ .ss-w-dq-prog-fill { height: 100%; border-radius: 999px; background: var(--ss-w-accent); transition: width .25s ease; }
6804
+ /* Questions list */
6805
+ .ss-w-dq-questions { display: flex; flex-direction: column; gap: 16px; }
6806
+ /* Single question */
6807
+ .ss-w-dq-q { display: flex; flex-direction: column; gap: 8px; }
6808
+ .ss-w-dq-qstem { font-size: 13.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.4; }
6809
+ /* Options grid: 2 across */
6810
+ .ss-w-dq-opts { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
6811
+ .ss-w-dq-qopt { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-radius: 10px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); font: inherit; font-size: 12.5px; cursor: pointer; text-align: left; color: var(--ss-w-ink); transition: background .1s, border-color .1s; }
6812
+ .ss-w-dq-qopt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6813
+ .ss-w-dq-qopt:disabled { cursor: not-allowed; }
6814
+ .ss-w-dq-qopt--selected { border-color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 8%, var(--ss-w-panel)); }
6815
+ .ss-w-dq-qopt--correct { border-color: var(--ss-w-correct); background: color-mix(in srgb, var(--ss-w-correct) 12%, var(--ss-w-panel)); color: var(--ss-w-correct); }
6816
+ .ss-w-dq-qopt--wrong { border-color: color-mix(in srgb, var(--ss-w-cta) 50%, var(--ss-w-line)); background: color-mix(in srgb, var(--ss-w-cta) 8%, var(--ss-w-panel)); opacity: .75; }
6817
+ /* Option letter badge */
6818
+ .ss-w-dq-qopt-letter { flex: none; width: 20px; height: 20px; border-radius: 50%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); font-size: 10px; font-weight: 800; display: flex; align-items: center; justify-content: center; color: var(--ss-w-faint); }
6819
+ .ss-w-dq-qopt-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6820
+ /* Why/reveal text */
6821
+ .ss-w-dq-qwhy { font-size: 11.5px; padding: 6px 10px; border-radius: 8px; line-height: 1.4; }
6822
+ .ss-w-dq-qwhy--correct { background: color-mix(in srgb, var(--ss-w-correct) 9%, var(--ss-w-panel)); color: var(--ss-w-correct); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 22%, var(--ss-w-line)); }
6823
+ .ss-w-dq-qwhy--wrong { background: var(--ss-w-bubble); color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); }
6824
+ /* Submit button */
6825
+ .ss-w-dq-submit { width: 100%; padding: 13px; border-radius: 12px; border: none; background: var(--ss-w-accent); color: #fff; font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; transition: opacity .15s; }
6826
+ .ss-w-dq-submit:disabled { opacity: .4; cursor: not-allowed; }
6827
+ .ss-w-dq-submit:hover:not(:disabled) { opacity: .88; }
6828
+
6829
+ /* \u2500\u2500 Matchday Predictor \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
6830
+ .ss-w-mp { display: flex; flex-direction: column; gap: 14px; }
6831
+ /* Score prediction row */
6832
+ .ss-w-mp-pred-score { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 12px 0; }
6833
+ .ss-w-mp-team { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; min-width: 0; }
6834
+ .ss-w-mp-team-name { font-size: 12px; font-weight: 650; color: var(--ss-w-ink); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
6835
+ .ss-w-mp-stepper { display: flex; align-items: center; gap: 8px; }
6836
+ .ss-w-mp-stepper-btn { width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); font: inherit; font-size: 18px; font-weight: 700; color: var(--ss-w-ink); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background .1s; }
6837
+ .ss-w-mp-stepper-btn:hover:not(:disabled) { background: var(--ss-w-bubble); }
6838
+ .ss-w-mp-stepper-btn:disabled { opacity: .35; cursor: not-allowed; }
6839
+ .ss-w-mp-stepper-val { font-size: 26px; font-weight: 800; color: var(--ss-w-ink); min-width: 28px; text-align: center; font-variant-numeric: tabular-nums; }
6840
+ .ss-w-mp-sep { font-size: 22px; font-weight: 700; color: var(--ss-w-faint); padding: 0 4px; }
6841
+ /* First-scorer picker */
6842
+ .ss-w-mp-scorer { display: flex; flex-direction: column; gap: 6px; }
6843
+ .ss-w-mp-scorer-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }
6844
+ .ss-w-mp-scorer-list { display: flex; flex-wrap: wrap; gap: 6px; }
6845
+ .ss-w-mp-scorer-opt { padding: 6px 12px; border-radius: 999px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); font: inherit; font-size: 12px; font-weight: 600; color: var(--ss-w-ink); cursor: pointer; transition: background .1s, border-color .1s; }
6846
+ .ss-w-mp-scorer-opt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6847
+ .ss-w-mp-scorer-opt--selected { border-color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); color: var(--ss-w-accent); }
6848
+ .ss-w-mp-scorer-opt:disabled { opacity: .35; cursor: not-allowed; }
6849
+ /* Save button */
6850
+ .ss-w-mp-savebtn { width: 100%; padding: 13px; border-radius: 12px; border: none; background: var(--ss-w-accent); color: #fff; font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; transition: opacity .15s; }
6851
+ .ss-w-mp-savebtn:disabled { opacity: .4; cursor: not-allowed; }
6852
+ .ss-w-mp-savebtn:hover:not(:disabled) { opacity: .88; }
6853
+ /* Live / pending state */
6854
+ .ss-w-mp-live { display: flex; flex-direction: column; gap: 10px; align-items: center; text-align: center; padding: 14px 0; }
6855
+ .ss-w-mp-live-score { font-size: 30px; font-weight: 800; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }
6856
+ .ss-w-mp-live-label { font-size: 12px; color: var(--ss-w-faint); font-style: italic; }
6857
+ .ss-w-mp-live-outcome { display: flex; flex-direction: column; gap: 6px; width: 100%; }
6858
+ .ss-w-mp-live-row { display: flex; align-items: center; justify-content: space-between; padding: 7px 12px; border-radius: 10px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); font-size: 12.5px; }
6859
+ .ss-w-mp-live-row--correct { border-color: color-mix(in srgb, var(--ss-w-correct) 40%, var(--ss-w-line)); background: color-mix(in srgb, var(--ss-w-correct) 8%, var(--ss-w-panel)); }
6860
+ .ss-w-mp-live-row-key { color: var(--ss-w-faint); font-weight: 600; }
6861
+ .ss-w-mp-live-row-val { font-weight: 700; color: var(--ss-w-ink); }
6862
+ .ss-w-mp-live-row--correct .ss-w-mp-live-row-val { color: var(--ss-w-correct); }
6863
+ /* For-fun note */
6864
+ .ss-w-mp-fun { font-size: 11px; color: var(--ss-w-faint); text-align: center; font-style: italic; }
6865
+
6866
+ /* \u2500\u2500 Starting XI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
6867
+ .ss-w-sxi { display: flex; flex-direction: column; gap: 14px; }
6868
+ .ss-w-sxi-formation { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }
6869
+ /* Formation pitch area */
6870
+ .ss-w-sxi-pitch { display: flex; flex-direction: column; gap: 10px; padding: 12px 8px; border-radius: 12px; background: color-mix(in srgb, var(--ss-w-accent) 4%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); min-height: 260px; }
6871
+ .ss-w-sxi-pitch-row { display: flex; justify-content: center; gap: 6px; flex-wrap: wrap; }
6872
+ /* Player slot */
6873
+ .ss-w-sxi-pslot { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 64px; cursor: pointer; }
6874
+ .ss-w-sxi-pslot-num { width: 36px; height: 36px; border-radius: 50%; border: 2px dashed var(--ss-w-line); background: var(--ss-w-bubble); display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: var(--ss-w-faint); transition: border-color .1s, background .1s; }
6875
+ .ss-w-sxi-pslot--filled .ss-w-sxi-pslot-num { border-style: solid; border-color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); color: var(--ss-w-accent); }
6876
+ .ss-w-sxi-pslot-name { font-size: 9.5px; font-weight: 600; color: var(--ss-w-ink); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
6877
+ /* Squad picker */
6878
+ .ss-w-sxi-squad { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow-y: auto; }
6879
+ .ss-w-sxi-squad-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-radius: 8px; border: 1px solid var(--ss-w-line); background: var(--ss-w-panel); cursor: pointer; transition: background .1s; }
6880
+ .ss-w-sxi-squad-row:hover:not(.ss-w-sxi-squad-row--picked) { background: var(--ss-w-bubble); }
6881
+ .ss-w-sxi-squad-row--picked { background: color-mix(in srgb, var(--ss-w-accent) 8%, var(--ss-w-panel)); border-color: var(--ss-w-accent); }
6882
+ .ss-w-sxi-squad-name { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
6883
+ .ss-w-sxi-squad-pos { font-size: 10.5px; color: var(--ss-w-faint); }
6884
+ .ss-w-sxi-savebtn { width: 100%; padding: 13px; border-radius: 12px; border: none; background: var(--ss-w-accent); color: #fff; font: inherit; font-size: 14px; font-weight: 700; cursor: pointer; transition: opacity .15s; }
6885
+ .ss-w-sxi-savebtn:disabled { opacity: .4; cursor: not-allowed; }
6886
+ .ss-w-sxi-savebtn:hover:not(:disabled) { opacity: .88; }
6887
+ /* Pending / graded states */
6888
+ .ss-w-sxi-status { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 14px 12px; border-radius: 12px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); text-align: center; }
6889
+ .ss-w-sxi-status--graded { background: color-mix(in srgb, var(--ss-w-correct) 8%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); }
6890
+ .ss-w-sxi-status-score { font-size: 28px; font-weight: 800; color: var(--ss-w-correct); font-variant-numeric: tabular-nums; }
6891
+ .ss-w-sxi-status-label { font-size: 12.5px; color: var(--ss-w-faint); }
6892
+
6893
+ /* \u2500\u2500 Stat Ladder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
6894
+ .ss-w-sl { display: flex; flex-direction: column; gap: 14px; }
6895
+ .ss-w-sl-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }
6896
+ /* Ladder list */
6897
+ .ss-w-sl-ladder { display: flex; flex-direction: column; gap: 6px; }
6898
+ .ss-w-sl-lrow { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 10px; border: 1px solid var(--ss-w-line); background: var(--ss-w-panel); }
6899
+ .ss-w-sl-lrow-rank { font-size: 11px; font-weight: 800; color: var(--ss-w-faint); width: 18px; flex: none; text-align: center; }
6900
+ .ss-w-sl-lrow-name { flex: 1; font-size: 13px; font-weight: 650; color: var(--ss-w-ink); }
6901
+ .ss-w-sl-lrow-stat { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }
6902
+ /* Mystery rung */
6903
+ .ss-w-sl-mystery { border: 1.5px dashed var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 5%, var(--ss-w-panel)); }
6904
+ .ss-w-sl-mystery .ss-w-sl-lrow-name { color: var(--ss-w-faint); font-style: italic; }
6905
+ /* Reveal overlay: correct / wrong */
6906
+ .ss-w-sl-lrow--correct { border-color: color-mix(in srgb, var(--ss-w-correct) 40%, var(--ss-w-line)); background: color-mix(in srgb, var(--ss-w-correct) 8%, var(--ss-w-panel)); }
6907
+ .ss-w-sl-lrow--wrong { border-color: color-mix(in srgb, var(--ss-w-wrong, #e05050) 30%, var(--ss-w-line)); background: color-mix(in srgb, var(--ss-w-wrong, #e05050) 6%, var(--ss-w-panel)); }
6908
+ /* Player picker */
6909
+ .ss-w-sl-picker { display: flex; flex-wrap: wrap; gap: 6px; }
6910
+ .ss-w-sl-picker-opt { padding: 6px 12px; border-radius: 999px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); font: inherit; font-size: 12px; font-weight: 600; color: var(--ss-w-ink); cursor: pointer; transition: background .1s, border-color .1s; }
6911
+ .ss-w-sl-picker-opt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6912
+ .ss-w-sl-picker-opt:disabled { opacity: .35; cursor: not-allowed; }
6913
+ .ss-w-sl-reveal { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 12px; border-radius: 12px; text-align: center; font-size: 13px; font-weight: 650; color: var(--ss-w-ink); }
6914
+ .ss-w-sl-reveal--correct { background: color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-correct) 28%, var(--ss-w-line)); color: var(--ss-w-correct); }
6915
+ .ss-w-sl-reveal--wrong { background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); }
6916
+
6917
+ /* \u2500\u2500 Fan MOTM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
6918
+ .ss-w-motm { display: flex; flex-direction: column; gap: 14px; }
6919
+ .ss-w-motm-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }
6920
+ /* Vote candidate list */
6921
+ .ss-w-motm-votes { display: flex; flex-direction: column; gap: 6px; }
6922
+ .ss-w-motm-vrow { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-radius: 10px; border: 1.5px solid var(--ss-w-line); background: var(--ss-w-panel); cursor: pointer; transition: background .1s, border-color .1s; position: relative; overflow: hidden; }
6923
+ .ss-w-motm-vrow:hover:not(.ss-w-motm-vrow--voted):not(.ss-w-motm-vrow--result) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6924
+ .ss-w-motm-vrow--voted { border-color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 8%, var(--ss-w-panel)); cursor: default; }
6925
+ .ss-w-motm-vrow--result { cursor: default; }
6926
+ .ss-w-motm-vrow-name { flex: 1; font-size: 13px; font-weight: 650; color: var(--ss-w-ink); position: relative; z-index: 1; }
6927
+ .ss-w-motm-vrow-pct { font-size: 12px; font-weight: 700; color: var(--ss-w-faint); position: relative; z-index: 1; font-variant-numeric: tabular-nums; }
6928
+ /* Share fill bar (behind content) */
6929
+ .ss-w-motm-vfill { position: absolute; top: 0; left: 0; height: 100%; background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); transition: width .4s ease; pointer-events: none; }
6930
+ .ss-w-motm-vrow--voted .ss-w-motm-vfill { background: color-mix(in srgb, var(--ss-w-accent) 18%, var(--ss-w-panel)); }
6931
+ /* For-fun note */
6932
+ .ss-w-motm-fun { font-size: 11px; color: var(--ss-w-faint); text-align: center; font-style: italic; }
4784
6933
  `;
4785
6934
 
4786
6935
  // src/StatsWidget.tsx
4787
- var import_jsx_runtime53 = require("react/jsx-runtime");
6936
+ var import_jsx_runtime71 = require("react/jsx-runtime");
4788
6937
  function buildClient(props) {
4789
6938
  try {
4790
6939
  if ("client" in props && props.client) {
@@ -4809,23 +6958,23 @@ function injectStyles(root) {
4809
6958
  function StatsWidget(props) {
4810
6959
  const injectedClient = "client" in props ? props.client : void 0;
4811
6960
  const cfg = props.config;
4812
- const built = (0, import_react26.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
4813
- const logger = (0, import_react26.useMemo)(
6961
+ const built = (0, import_react39.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
6962
+ const logger = (0, import_react39.useMemo)(
4814
6963
  () => built ? built.client.createEventLogger({
4815
6964
  operatorUserId: cfg?.userContext?.operatorUserId,
4816
6965
  anonymousUserId: cfg?.userContext?.anonymousUserId
4817
6966
  }) : null,
4818
6967
  [built?.client]
4819
6968
  );
4820
- const ui = (0, import_react26.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
4821
- const rootRef = (0, import_react26.useRef)(null);
4822
- const introDoneRef = (0, import_react26.useRef)(false);
4823
- const markIntroDone = (0, import_react26.useCallback)(() => {
6969
+ const ui = (0, import_react39.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
6970
+ const rootRef = (0, import_react39.useRef)(null);
6971
+ const introDoneRef = (0, import_react39.useRef)(false);
6972
+ const markIntroDone = (0, import_react39.useCallback)(() => {
4824
6973
  introDoneRef.current = true;
4825
6974
  }, []);
4826
6975
  const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
4827
6976
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
4828
- const [hasToday, setHasToday] = (0, import_react26.useState)(false);
6977
+ const [hasToday, setHasToday] = (0, import_react39.useState)(false);
4829
6978
  const monitor = useLiveMonitor({
4830
6979
  getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
4831
6980
  getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
@@ -4833,15 +6982,15 @@ function StatsWidget(props) {
4833
6982
  isOpen: controller.state.isOpen,
4834
6983
  hasToday
4835
6984
  });
4836
- const getSchedule = (0, import_react26.useCallback)(
6985
+ const getSchedule = (0, import_react39.useCallback)(
4837
6986
  (localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
4838
6987
  [built]
4839
6988
  );
4840
- const getStates = (0, import_react26.useCallback)(
6989
+ const getStates = (0, import_react39.useCallback)(
4841
6990
  (matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
4842
6991
  [built]
4843
6992
  );
4844
- const pinnedMatchIds = (0, import_react26.useMemo)(
6993
+ const pinnedMatchIds = (0, import_react39.useMemo)(
4845
6994
  () => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
4846
6995
  [monitor.pins]
4847
6996
  );
@@ -4853,17 +7002,19 @@ function StatsWidget(props) {
4853
7002
  pinnedMatchIds
4854
7003
  });
4855
7004
  const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
4856
- (0, import_react26.useEffect)(() => {
7005
+ (0, import_react39.useEffect)(() => {
4857
7006
  setHasToday(todayHasContent);
4858
7007
  }, [todayHasContent]);
7008
+ const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
7009
+ const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
4859
7010
  const markTodayActivity = monitor.markTodayActivity;
4860
- const prevLiveCountRef = (0, import_react26.useRef)(0);
4861
- (0, import_react26.useEffect)(() => {
7011
+ const prevLiveCountRef = (0, import_react39.useRef)(0);
7012
+ (0, import_react39.useEffect)(() => {
4862
7013
  const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
4863
7014
  prevLiveCountRef.current = discovery.liveCount;
4864
7015
  if (rose) markTodayActivity();
4865
7016
  }, [discovery.liveCount, markTodayActivity]);
4866
- const slip = (0, import_react26.useMemo)(
7017
+ const slip = (0, import_react39.useMemo)(
4867
7018
  () => {
4868
7019
  const handler = props.config?.onAddToSlip;
4869
7020
  return {
@@ -4886,18 +7037,18 @@ function StatsWidget(props) {
4886
7037
  },
4887
7038
  [props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
4888
7039
  );
4889
- const onDashboardTap = (0, import_react26.useMemo)(
7040
+ const onDashboardTap = (0, import_react39.useMemo)(
4890
7041
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
4891
7042
  [built, logger]
4892
7043
  );
4893
7044
  const operatorUserId = cfg?.userContext?.operatorUserId;
4894
7045
  const anonymousUserId = cfg?.userContext?.anonymousUserId;
4895
7046
  const conversationId = controller.state.conversationId ?? void 0;
4896
- (0, import_react26.useEffect)(() => {
7047
+ (0, import_react39.useEffect)(() => {
4897
7048
  if (!logger) return;
4898
7049
  logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
4899
7050
  }, [logger, operatorUserId, anonymousUserId, conversationId]);
4900
- (0, import_react26.useEffect)(() => {
7051
+ (0, import_react39.useEffect)(() => {
4901
7052
  if (!logger) return;
4902
7053
  const onHide = () => {
4903
7054
  logger.flushOnHide();
@@ -4914,14 +7065,27 @@ function StatsWidget(props) {
4914
7065
  logger.dispose();
4915
7066
  };
4916
7067
  }, [logger]);
4917
- (0, import_react26.useEffect)(() => {
7068
+ (0, import_react39.useEffect)(() => {
4918
7069
  if (!built || !ui.injectStyles) return;
4919
7070
  const node = rootRef.current?.getRootNode();
4920
7071
  if (node) injectStyles(node);
4921
7072
  }, [built, ui.injectStyles]);
4922
7073
  if (!built) return null;
4923
7074
  const attrs = themeAttrs(ui);
4924
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime53.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_runtime53.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap, monitor: monitor.enabled ? monitor : void 0, discovery }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
7075
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime71.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_runtime71.jsx)(
7076
+ ChatPanel,
7077
+ {
7078
+ controller,
7079
+ ui,
7080
+ slip,
7081
+ onDashboardTap,
7082
+ monitor: monitor.enabled ? monitor : void 0,
7083
+ discovery,
7084
+ gamesResult,
7085
+ leaderboardResult,
7086
+ loggedIn: !!operatorUserId
7087
+ }
7088
+ ) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
4925
7089
  ChatFab,
4926
7090
  {
4927
7091
  label: ui.launcherLabel,