@sensiblestats/widget-react 0.51.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/StatsWidget.tsx
2
- import { useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo3, useRef as useRef13, useState as useState33 } from "react";
2
+ import { useCallback as useCallback9, useEffect as useEffect15, useMemo as useMemo3, useRef as useRef13, useState as useState34 } from "react";
3
3
  import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
4
4
 
5
5
  // src/kickoff.ts
@@ -1892,7 +1892,7 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
1892
1892
  }
1893
1893
 
1894
1894
  // src/components/ChatPanel.tsx
1895
- import { useEffect as useEffect14, useState as useState32 } from "react";
1895
+ import { useEffect as useEffect14, useState as useState33 } from "react";
1896
1896
 
1897
1897
  // src/components/ChatHeader.tsx
1898
1898
  import { useEffect as useEffect8, useRef as useRef8, useState as useState8 } from "react";
@@ -3995,7 +3995,7 @@ function TodayPanel({ discovery, ui, monitor }) {
3995
3995
  }
3996
3996
 
3997
3997
  // src/components/GamesPanel.tsx
3998
- import { useState as useState30 } from "react";
3998
+ import { useState as useState31 } from "react";
3999
3999
 
4000
4000
  // src/components/GamesLoginWall.tsx
4001
4001
  import { jsx as jsx52 } from "react/jsx-runtime";
@@ -4008,14 +4008,36 @@ import { Fragment as Fragment8, jsx as jsx53, jsxs as jsxs47 } from "react/jsx-r
4008
4008
  var GAME_ICONS = {
4009
4009
  "mystery-tiger": "\u{1F42F}",
4010
4010
  "daily-quiz": "\u{1F9E0}",
4011
- "career-path": "\u26BD",
4012
- "beat-the-grid": "\u{1F3AF}",
4013
- "guess-xi": "\u{1F4CB}",
4014
- "head-of-league": "\u{1F3C6}"
4011
+ "career-path": "\u{1F9ED}",
4012
+ "beat-the-grid": "\u{1F532}",
4013
+ "guess-the-xi": "\u{1F4CB}",
4014
+ "higher-or-lower": "\u{1F4C8}",
4015
+ "matchday-predictor": "\u{1F3AF}",
4016
+ "starting-xi": "\u{1F455}",
4017
+ "stat-ladder": "\u{1FA9C}",
4018
+ "fan-motm": "\u2B50"
4019
+ };
4020
+ var GAME_TITLES = {
4021
+ "mystery-tiger": "Mystery Tiger",
4022
+ "daily-quiz": "Daily Quiz",
4023
+ "career-path": "Career Path",
4024
+ "beat-the-grid": "Beat the Grid",
4025
+ "guess-the-xi": "Guess the XI",
4026
+ "higher-or-lower": "Higher or Lower",
4027
+ "matchday-predictor": "Matchday Predictor",
4028
+ "starting-xi": "Starting XI",
4029
+ "stat-ladder": "Stat Ladder",
4030
+ "fan-motm": "Fan MOTM"
4015
4031
  };
4016
4032
  function gameIcon(game) {
4017
4033
  return GAME_ICONS[game.gameId] ?? (game.kind === "fixture" ? "\u{1F4C5}" : "\u{1F3AE}");
4018
4034
  }
4035
+ function prettifyGameId(gameId) {
4036
+ return gameId.split("-").map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
4037
+ }
4038
+ function gameTitle(game) {
4039
+ return game.title ?? GAME_TITLES[game.gameId] ?? prettifyGameId(game.gameId);
4040
+ }
4019
4041
  function formatCountdown(lockAtUtc) {
4020
4042
  const diff = new Date(lockAtUtc).getTime() - Date.now();
4021
4043
  if (diff <= 0) return null;
@@ -4056,7 +4078,7 @@ function GameTile({
4056
4078
  const statusClass = `ss-w-tile-status ss-w-tile-status--${game.status}`;
4057
4079
  const inner = /* @__PURE__ */ jsxs47(Fragment8, { children: [
4058
4080
  /* @__PURE__ */ jsx53("span", { className: "ss-w-tile-icon", children: gameIcon(game) }),
4059
- /* @__PURE__ */ jsx53("span", { className: "ss-w-tile-title", children: game.title ?? game.gameId }),
4081
+ /* @__PURE__ */ jsx53("span", { className: "ss-w-tile-title", children: gameTitle(game) }),
4060
4082
  countdown !== null ? /* @__PURE__ */ jsx53("span", { className: statusClass, "data-testid": "tile-countdown", children: countdown }) : /* @__PURE__ */ jsx53("span", { className: statusClass, children: statusLabel }),
4061
4083
  /* @__PURE__ */ jsx53("span", { className: `ss-w-tile-chip ss-w-tile-chip--${game.ranked ? "skill" : "fun"}`, children: game.ranked ? "Skill" : "For fun" })
4062
4084
  ] });
@@ -4107,7 +4129,7 @@ function GamesHub({
4107
4129
  }
4108
4130
 
4109
4131
  // src/components/GameScreenHost.tsx
4110
- import { useEffect as useEffect13, useRef as useRef12, useState as useState29 } from "react";
4132
+ import { useEffect as useEffect13, useRef as useRef12, useState as useState30 } from "react";
4111
4133
 
4112
4134
  // src/useGamePlay.ts
4113
4135
  import { useCallback as useCallback8, useRef as useRef11, useState as useState22 } from "react";
@@ -4170,6 +4192,89 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, refresh }) {
4170
4192
 
4171
4193
  // src/components/games/MysteryTigerGame.tsx
4172
4194
  import { useState as useState23, useId as useId2 } from "react";
4195
+
4196
+ // src/components/games/nationFlags.ts
4197
+ var FLAGS = {
4198
+ england: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}",
4199
+ scotland: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}",
4200
+ wales: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0077}\u{E006C}\u{E0073}\u{E007F}",
4201
+ "northern ireland": "\u{1F1EC}\u{1F1E7}",
4202
+ "republic of ireland": "\u{1F1EE}\u{1F1EA}",
4203
+ ireland: "\u{1F1EE}\u{1F1EA}",
4204
+ "united kingdom": "\u{1F1EC}\u{1F1E7}",
4205
+ france: "\u{1F1EB}\u{1F1F7}",
4206
+ spain: "\u{1F1EA}\u{1F1F8}",
4207
+ portugal: "\u{1F1F5}\u{1F1F9}",
4208
+ germany: "\u{1F1E9}\u{1F1EA}",
4209
+ italy: "\u{1F1EE}\u{1F1F9}",
4210
+ netherlands: "\u{1F1F3}\u{1F1F1}",
4211
+ belgium: "\u{1F1E7}\u{1F1EA}",
4212
+ switzerland: "\u{1F1E8}\u{1F1ED}",
4213
+ austria: "\u{1F1E6}\u{1F1F9}",
4214
+ denmark: "\u{1F1E9}\u{1F1F0}",
4215
+ sweden: "\u{1F1F8}\u{1F1EA}",
4216
+ norway: "\u{1F1F3}\u{1F1F4}",
4217
+ finland: "\u{1F1EB}\u{1F1EE}",
4218
+ iceland: "\u{1F1EE}\u{1F1F8}",
4219
+ poland: "\u{1F1F5}\u{1F1F1}",
4220
+ czechia: "\u{1F1E8}\u{1F1FF}",
4221
+ "czech republic": "\u{1F1E8}\u{1F1FF}",
4222
+ croatia: "\u{1F1ED}\u{1F1F7}",
4223
+ serbia: "\u{1F1F7}\u{1F1F8}",
4224
+ "bosnia and herzegovina": "\u{1F1E7}\u{1F1E6}",
4225
+ greece: "\u{1F1EC}\u{1F1F7}",
4226
+ romania: "\u{1F1F7}\u{1F1F4}",
4227
+ ukraine: "\u{1F1FA}\u{1F1E6}",
4228
+ russia: "\u{1F1F7}\u{1F1FA}",
4229
+ hungary: "\u{1F1ED}\u{1F1FA}",
4230
+ slovakia: "\u{1F1F8}\u{1F1F0}",
4231
+ slovenia: "\u{1F1F8}\u{1F1EE}",
4232
+ turkey: "\u{1F1F9}\u{1F1F7}",
4233
+ t\u00FCrkiye: "\u{1F1F9}\u{1F1F7}",
4234
+ albania: "\u{1F1E6}\u{1F1F1}",
4235
+ "north macedonia": "\u{1F1F2}\u{1F1F0}",
4236
+ brazil: "\u{1F1E7}\u{1F1F7}",
4237
+ argentina: "\u{1F1E6}\u{1F1F7}",
4238
+ uruguay: "\u{1F1FA}\u{1F1FE}",
4239
+ colombia: "\u{1F1E8}\u{1F1F4}",
4240
+ chile: "\u{1F1E8}\u{1F1F1}",
4241
+ peru: "\u{1F1F5}\u{1F1EA}",
4242
+ ecuador: "\u{1F1EA}\u{1F1E8}",
4243
+ paraguay: "\u{1F1F5}\u{1F1FE}",
4244
+ mexico: "\u{1F1F2}\u{1F1FD}",
4245
+ "united states": "\u{1F1FA}\u{1F1F8}",
4246
+ usa: "\u{1F1FA}\u{1F1F8}",
4247
+ canada: "\u{1F1E8}\u{1F1E6}",
4248
+ jamaica: "\u{1F1EF}\u{1F1F2}",
4249
+ nigeria: "\u{1F1F3}\u{1F1EC}",
4250
+ ghana: "\u{1F1EC}\u{1F1ED}",
4251
+ senegal: "\u{1F1F8}\u{1F1F3}",
4252
+ ivorycoast: "\u{1F1E8}\u{1F1EE}",
4253
+ "cote d'ivoire": "\u{1F1E8}\u{1F1EE}",
4254
+ "ivory coast": "\u{1F1E8}\u{1F1EE}",
4255
+ cameroon: "\u{1F1E8}\u{1F1F2}",
4256
+ egypt: "\u{1F1EA}\u{1F1EC}",
4257
+ morocco: "\u{1F1F2}\u{1F1E6}",
4258
+ algeria: "\u{1F1E9}\u{1F1FF}",
4259
+ tunisia: "\u{1F1F9}\u{1F1F3}",
4260
+ mali: "\u{1F1F2}\u{1F1F1}",
4261
+ "south africa": "\u{1F1FF}\u{1F1E6}",
4262
+ "dr congo": "\u{1F1E8}\u{1F1E9}",
4263
+ japan: "\u{1F1EF}\u{1F1F5}",
4264
+ "south korea": "\u{1F1F0}\u{1F1F7}",
4265
+ korea: "\u{1F1F0}\u{1F1F7}",
4266
+ australia: "\u{1F1E6}\u{1F1FA}",
4267
+ "saudi arabia": "\u{1F1F8}\u{1F1E6}",
4268
+ iran: "\u{1F1EE}\u{1F1F7}",
4269
+ "new zealand": "\u{1F1F3}\u{1F1FF}"
4270
+ };
4271
+ function nationalityFlag(nationality) {
4272
+ if (!nationality) return "\u{1F3F3}\uFE0F";
4273
+ const key = nationality.trim().toLowerCase();
4274
+ return FLAGS[key] ?? nationality.slice(0, 3).toUpperCase();
4275
+ }
4276
+
4277
+ // src/components/games/MysteryTigerGame.tsx
4173
4278
  import { Fragment as Fragment9, jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
4174
4279
  function parseClientState(json) {
4175
4280
  if (!json) return null;
@@ -4200,6 +4305,15 @@ function verdictGlyph(v) {
4200
4305
  if (v.direction === "down") return "\u2193";
4201
4306
  return "\u2248";
4202
4307
  }
4308
+ function directionArrow(v) {
4309
+ if (v.direction === "up") return "\u25B2";
4310
+ if (v.direction === "down") return "\u25BC";
4311
+ return "";
4312
+ }
4313
+ function tileFace(key, v) {
4314
+ if (!v.value) return verdictGlyph(v);
4315
+ return key === "nationality" ? nationalityFlag(v.value) : v.value;
4316
+ }
4203
4317
  function MysteryTigerGame({
4204
4318
  config,
4205
4319
  result,
@@ -4245,16 +4359,20 @@ function MysteryTigerGame({
4245
4359
  ] }),
4246
4360
  /* @__PURE__ */ jsx55("div", { className: "ss-w-gtrow", children: ATTR_KEYS.map((key) => {
4247
4361
  const v = gr[key];
4362
+ const arrow = directionArrow(v);
4248
4363
  return /* @__PURE__ */ jsxs49(
4249
4364
  "div",
4250
4365
  {
4251
4366
  className: `ss-w-gtile ss-w-gtile--${v.verdict}`,
4252
4367
  "data-testid": `verdict-${key}-${i}`,
4253
4368
  "data-verdict": v.verdict,
4254
- "aria-label": `${ATTR_LABELS[key]}: ${v.verdict}${v.direction ? ` ${v.direction}` : ""}`,
4369
+ "aria-label": `${ATTR_LABELS[key]}: ${v.value ?? v.verdict}${v.direction ? ` ${v.direction}` : ""}`,
4255
4370
  children: [
4256
4371
  /* @__PURE__ */ jsx55("span", { className: "ss-w-gtile-lab", children: ATTR_LABELS[key] }),
4257
- /* @__PURE__ */ jsx55("span", { className: "ss-w-gtile-v", "aria-hidden": "true", children: verdictGlyph(v) })
4372
+ /* @__PURE__ */ jsxs49("span", { className: "ss-w-gtile-v", "aria-hidden": "true", children: [
4373
+ tileFace(key, v),
4374
+ arrow && /* @__PURE__ */ jsx55("span", { className: "ss-w-gtile-dir", children: arrow })
4375
+ ] })
4258
4376
  ]
4259
4377
  },
4260
4378
  key
@@ -4768,6 +4886,7 @@ function BeatTheGridGame({
4768
4886
  }
4769
4887
 
4770
4888
  // src/components/games/GuessTheXiGame.tsx
4889
+ import { useState as useState26, useId as useId5 } from "react";
4771
4890
  import { Fragment as Fragment14, jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
4772
4891
  function parseClientState5(json) {
4773
4892
  if (!json) return null;
@@ -4777,6 +4896,16 @@ function parseClientState5(json) {
4777
4896
  return null;
4778
4897
  }
4779
4898
  }
4899
+ function toRows(positions) {
4900
+ const byRow = /* @__PURE__ */ new Map();
4901
+ positions.forEach((p, i) => {
4902
+ const rowKey = Number(p.slot?.split(":")[0]) || i + 1;
4903
+ const bucket = byRow.get(rowKey) ?? [];
4904
+ bucket.push(p);
4905
+ byRow.set(rowKey, bucket);
4906
+ });
4907
+ return [...byRow.keys()].sort((a, b) => a - b).map((k) => byRow.get(k));
4908
+ }
4780
4909
  function RevealCard({ reveal }) {
4781
4910
  return /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi-reveal", "data-reveal-type": reveal.type ?? "", children: [
4782
4911
  reveal.slot && /* @__PURE__ */ jsx59("span", { className: "ss-w-gxi-reveal-slot", children: reveal.slot }),
@@ -4789,51 +4918,90 @@ function GuessTheXiGame({
4789
4918
  submitting,
4790
4919
  onSubmit
4791
4920
  }) {
4921
+ const [query, setQuery] = useState26("");
4922
+ const inputId = useId5();
4792
4923
  const clientState = parseClientState5(result?.clientStateJson);
4793
4924
  const isOver = result?.alreadyPlayed === true || clientState?.status === "solved" || clientState?.status === "failed";
4794
4925
  const solved = clientState?.status === "solved";
4926
+ const guessedTeamIds = new Set(clientState?.guessHistory.map((g) => g.teamId) ?? []);
4927
+ const rows = config ? toRows(config.positions) : [];
4928
+ const filtered = config && !isOver ? config.teamPool.filter(
4929
+ (t) => !guessedTeamIds.has(t.teamId) && t.teamName.toLowerCase().includes(query.toLowerCase())
4930
+ ) : [];
4795
4931
  function handlePick(teamId) {
4796
4932
  if (!config || isOver || submitting) return;
4797
4933
  const prevGuesses = clientState?.guessHistory.map((g) => ({ teamId: g.teamId })) ?? [];
4798
4934
  const newGuesses = [...prevGuesses, { teamId }];
4935
+ setQuery("");
4799
4936
  onSubmit(JSON.stringify({ guesses: newGuesses }));
4800
4937
  }
4938
+ const wrongGuesses = (clientState?.guessHistory ?? []).filter((g) => !g.wasCorrect);
4801
4939
  return /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi", "data-testid": "game-screen-guess-the-xi", children: [
4802
4940
  !config && /* @__PURE__ */ jsx59("div", { className: "ss-w-gscreen-body", children: "Loading\u2026" }),
4803
4941
  config && /* @__PURE__ */ jsxs53(Fragment14, { children: [
4804
4942
  /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi-head", children: [
4805
4943
  /* @__PURE__ */ jsxs53("div", { children: [
4806
4944
  /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-title", children: "Guess the XI" }),
4807
- /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-sub", children: config.poolLabel })
4945
+ /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi-sub", children: [
4946
+ "Which team? \xB7 ",
4947
+ config.poolLabel
4948
+ ] })
4808
4949
  ] }),
4809
4950
  clientState && !isOver && /* @__PURE__ */ jsxs53("span", { className: "ss-w-gxi-left", children: [
4810
- "Guess ",
4811
- clientState.guessesUsed + 1,
4812
- "/6"
4951
+ Math.max(0, 6 - clientState.guessesUsed),
4952
+ " left"
4813
4953
  ] })
4814
4954
  ] }),
4815
- config.positions.length > 0 && /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-pitch", children: config.positions.map((pos, i) => /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi-pslot", children: [
4816
- /* @__PURE__ */ jsx59("span", { className: "ss-w-gxi-pslot-pos", children: pos.slot }),
4817
- /* @__PURE__ */ jsx59("span", { className: "ss-w-gxi-pslot-nat", children: pos.nationality })
4818
- ] }, `${pos.slot}-${i}`)) }),
4955
+ rows.length > 0 && /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-pitch", children: rows.map((row, r) => /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-prow", children: row.map((pos, c) => /* @__PURE__ */ jsx59(
4956
+ "div",
4957
+ {
4958
+ className: "ss-w-gxi-flag",
4959
+ title: pos.nationality,
4960
+ "aria-label": pos.nationality,
4961
+ children: nationalityFlag(pos.nationality)
4962
+ },
4963
+ `${pos.slot}-${c}`
4964
+ )) }, r)) }),
4819
4965
  clientState && clientState.earnedReveals.length > 0 && /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-reveals", children: clientState.earnedReveals.map((r, i) => /* @__PURE__ */ jsx59(RevealCard, { reveal: r }, i)) }),
4820
- !isOver ? /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-pool", children: config.teamPool.map((team) => {
4821
- const guessRecord = clientState?.guessHistory.find((g) => g.teamId === team.teamId);
4822
- return /* @__PURE__ */ jsx59(
4823
- "button",
4824
- {
4825
- type: "button",
4826
- className: [
4827
- "ss-w-gxi-team-btn",
4828
- guessRecord ? guessRecord.wasCorrect ? "ss-w-gxi-team-btn--correct" : "ss-w-gxi-team-btn--wrong" : ""
4829
- ].filter(Boolean).join(" "),
4830
- disabled: submitting,
4831
- onClick: () => handlePick(team.teamId),
4832
- children: team.teamName
4833
- },
4834
- team.teamId
4835
- );
4836
- }) }) : clientState && /* @__PURE__ */ jsxs53("div", { className: `ss-w-gxi-banner ss-w-gxi-banner--${solved ? "solved" : "failed"}`, children: [
4966
+ !isOver ? /* @__PURE__ */ jsxs53(Fragment14, { children: [
4967
+ wrongGuesses.length > 0 && /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-wrong", children: wrongGuesses.map((g) => {
4968
+ const team = config.teamPool.find((t) => t.teamId === g.teamId);
4969
+ return /* @__PURE__ */ jsx59("span", { className: "ss-w-gxi-wrong-pill", children: team?.teamName ?? `#${g.teamId}` }, g.teamId);
4970
+ }) }),
4971
+ /* @__PURE__ */ jsxs53("div", { className: "ss-w-gtta", children: [
4972
+ /* @__PURE__ */ jsx59(
4973
+ "input",
4974
+ {
4975
+ id: inputId,
4976
+ type: "text",
4977
+ role: "textbox",
4978
+ className: "ss-w-gtta-i",
4979
+ placeholder: "Name the team\u2026",
4980
+ value: query,
4981
+ disabled: submitting || isOver,
4982
+ onChange: (e) => setQuery(e.target.value),
4983
+ autoComplete: "off",
4984
+ "aria-label": "Name the team",
4985
+ "aria-autocomplete": "list"
4986
+ }
4987
+ ),
4988
+ query.length > 0 && filtered.length > 0 && /* @__PURE__ */ jsx59("div", { className: "ss-w-gtta-drop", role: "listbox", children: filtered.map((t) => /* @__PURE__ */ jsx59(
4989
+ "div",
4990
+ {
4991
+ className: "ss-w-gtta-opt",
4992
+ role: "option",
4993
+ "aria-selected": false,
4994
+ onClick: () => handlePick(t.teamId),
4995
+ onKeyDown: (e) => {
4996
+ if (e.key === "Enter") handlePick(t.teamId);
4997
+ },
4998
+ tabIndex: 0,
4999
+ children: t.teamName
5000
+ },
5001
+ t.teamId
5002
+ )) })
5003
+ ] })
5004
+ ] }) : clientState && /* @__PURE__ */ jsxs53("div", { className: `ss-w-gxi-banner ss-w-gxi-banner--${solved ? "solved" : "failed"}`, children: [
4837
5005
  /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-banner-label", children: solved ? "\u2705 Solved!" : "\u{1F614} Out of guesses" }),
4838
5006
  /* @__PURE__ */ jsx59("div", { className: "ss-w-gxi-banner-score", children: clientState.score }),
4839
5007
  /* @__PURE__ */ jsxs53("div", { className: "ss-w-gxi-banner-sub", children: [
@@ -4848,7 +5016,7 @@ function GuessTheXiGame({
4848
5016
  }
4849
5017
 
4850
5018
  // src/components/games/DailyQuizGame.tsx
4851
- import { useState as useState26 } from "react";
5019
+ import { useState as useState27 } from "react";
4852
5020
  import { Fragment as Fragment15, jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
4853
5021
  function parseClientState6(json) {
4854
5022
  if (!json) return null;
@@ -4867,7 +5035,7 @@ function DailyQuizGame({
4867
5035
  submitting,
4868
5036
  onSubmit
4869
5037
  }) {
4870
- const [selections, setSelections] = useState26(/* @__PURE__ */ new Map());
5038
+ const [selections, setSelections] = useState27(/* @__PURE__ */ new Map());
4871
5039
  const clientState = parseClientState6(result?.clientStateJson);
4872
5040
  const isRevealed = (clientState?.results.length ?? 0) > 0 || result?.alreadyPlayed === true;
4873
5041
  const allAnswered = config != null && selections.size === config.questions.length;
@@ -4947,7 +5115,7 @@ function DailyQuizGame({
4947
5115
  }
4948
5116
 
4949
5117
  // src/components/games/MatchdayPredictorGame.tsx
4950
- import { useState as useState27 } from "react";
5118
+ import { useState as useState28 } from "react";
4951
5119
  import { jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
4952
5120
  function parseClientState7(json) {
4953
5121
  if (!json) return null;
@@ -4970,9 +5138,9 @@ function MatchdayPredictorGame({
4970
5138
  submitting,
4971
5139
  onSubmit
4972
5140
  }) {
4973
- const [homeScore, setHomeScore] = useState27(0);
4974
- const [awayScore, setAwayScore] = useState27(0);
4975
- const [firstScorerPlayerId, setFirstScorerPlayerId] = useState27(null);
5141
+ const [homeScore, setHomeScore] = useState28(0);
5142
+ const [awayScore, setAwayScore] = useState28(0);
5143
+ const [firstScorerPlayerId, setFirstScorerPlayerId] = useState28(null);
4976
5144
  const clientState = parseClientState7(result?.clientStateJson);
4977
5145
  const alreadyPlayed = result?.alreadyPlayed === true;
4978
5146
  if (alreadyPlayed && clientState) {
@@ -5122,7 +5290,7 @@ function MatchdayPredictorGame({
5122
5290
  }
5123
5291
 
5124
5292
  // src/components/games/StartingXiGame.tsx
5125
- import { useState as useState28 } from "react";
5293
+ import { useState as useState29 } from "react";
5126
5294
  import { jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
5127
5295
  function parseClientState8(json) {
5128
5296
  if (!json) return null;
@@ -5143,7 +5311,7 @@ function StartingXiGame({
5143
5311
  submitting,
5144
5312
  onSubmit
5145
5313
  }) {
5146
- const [picked, setPicked] = useState28([]);
5314
+ const [picked, setPicked] = useState29([]);
5147
5315
  const clientState = parseClientState8(result?.clientStateJson);
5148
5316
  const alreadyPlayed = result?.alreadyPlayed === true;
5149
5317
  if (alreadyPlayed) {
@@ -5387,7 +5555,7 @@ function GameScreenHost({
5387
5555
  ui
5388
5556
  }) {
5389
5557
  const { gameId, fixtureId, gameDay = "" } = selected;
5390
- const [configJson, setConfigJson] = useState29(null);
5558
+ const [configJson, setConfigJson] = useState30(null);
5391
5559
  useEffect13(() => {
5392
5560
  setConfigJson(null);
5393
5561
  if (!conversation) return;
@@ -5455,15 +5623,17 @@ function GameScreenHost({
5455
5623
  config: safeParseConfig(configJson)
5456
5624
  }
5457
5625
  );
5458
- case "beat-the-grid":
5626
+ case "beat-the-grid": {
5627
+ const btgConfig = safeParseConfig(configJson);
5459
5628
  return /* @__PURE__ */ jsx65(
5460
5629
  BeatTheGridGame,
5461
5630
  {
5462
5631
  ...sharedProps,
5463
- config: safeParseConfig(configJson),
5464
- playerPool: []
5632
+ config: btgConfig,
5633
+ playerPool: btgConfig?.playerPool ?? []
5465
5634
  }
5466
5635
  );
5636
+ }
5467
5637
  case "guess-the-xi":
5468
5638
  return /* @__PURE__ */ jsx65(
5469
5639
  GuessTheXiGame,
@@ -5533,7 +5703,7 @@ function GamesPanel({
5533
5703
  ui,
5534
5704
  conversation
5535
5705
  }) {
5536
- const [selected, setSelected] = useState30(null);
5706
+ const [selected, setSelected] = useState31(null);
5537
5707
  if (!loggedIn) return /* @__PURE__ */ jsx66(GamesLoginWall, { ui });
5538
5708
  if (selected !== null) {
5539
5709
  return /* @__PURE__ */ jsx66("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ jsx66(
@@ -5557,7 +5727,7 @@ function GamesPanel({
5557
5727
  }
5558
5728
 
5559
5729
  // src/components/Leaderboard.tsx
5560
- import { useState as useState31 } from "react";
5730
+ import { useState as useState32 } from "react";
5561
5731
 
5562
5732
  // src/components/LeaderboardRow.tsx
5563
5733
  import { jsx as jsx67, jsxs as jsxs60 } from "react/jsx-runtime";
@@ -5642,7 +5812,7 @@ function Leaderboard({
5642
5812
  ui,
5643
5813
  onPlay
5644
5814
  }) {
5645
- const [segment, setSegment] = useState31("weekly");
5815
+ const [segment, setSegment] = useState32("weekly");
5646
5816
  const myRow = segment === "weekly" ? data.myWeeklyRow : data.myAllTimeRow;
5647
5817
  const offBoard = myRow !== null && myRow !== void 0 && myRow.rank === -1;
5648
5818
  const isEmpty = segment === "weekly" ? data.weeklyTop.length === 0 : data.allTimeTop.length === 0;
@@ -5725,7 +5895,7 @@ function LeaderboardPanel({ loggedIn, data, loading, onPlay, ui }) {
5725
5895
  import { jsx as jsx71, jsxs as jsxs63 } from "react/jsx-runtime";
5726
5896
  var FULLSCREEN_QUERY = "(max-width: 639px)";
5727
5897
  function useIsModal() {
5728
- const [modal, setModal] = useState32(false);
5898
+ const [modal, setModal] = useState33(false);
5729
5899
  useEffect14(() => {
5730
5900
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
5731
5901
  const mql = window.matchMedia(FULLSCREEN_QUERY);
@@ -5800,7 +5970,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
5800
5970
  ui
5801
5971
  }
5802
5972
  ),
5803
- /* @__PURE__ */ jsx71(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
5973
+ (!monitor || monitor.activeTab !== "games" && monitor.activeTab !== "leaderboard") && /* @__PURE__ */ jsx71(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
5804
5974
  ] });
5805
5975
  }
5806
5976
 
@@ -6792,7 +6962,8 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
6792
6962
  /* Verdict tiles: label on top, verdict glyph below */
6793
6963
  .ss-w-gtile { display: flex; flex-direction: column; align-items: center; justify-content: center; aspect-ratio: 1; border-radius: 8px; gap: 2px; min-width: 0; }
6794
6964
  .ss-w-gtile-lab { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; opacity: .75; }
6795
- .ss-w-gtile-v { font-size: 15px; font-weight: 800; line-height: 1; }
6965
+ .ss-w-gtile-v { display: inline-flex; align-items: center; gap: 1px; font-size: 13px; font-weight: 800; line-height: 1; max-width: 100%; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6966
+ .ss-w-gtile-dir { font-size: 9px; line-height: 1; }
6796
6967
  .ss-w-gtile--exact { background: var(--ss-w-correct); color: #062611; }
6797
6968
  .ss-w-gtile--near { background: var(--ss-w-accent); color: #241700; }
6798
6969
  .ss-w-gtile--miss { background: var(--ss-w-bubble); color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); }
@@ -6827,9 +6998,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
6827
6998
  .ss-w-hlbtns { display: flex; flex-direction: column; gap: 6px; justify-content: center; }
6828
6999
  .ss-w-hl-or { text-align: center; font-size: 11px; font-weight: 700; color: var(--ss-w-faint); }
6829
7000
  .ss-w-hlbtn { font: inherit; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; border-radius: 9px; padding: 10px 12px; cursor: pointer; border: 1px solid var(--ss-w-line); white-space: nowrap; transition: border-color .1s, background .1s; }
6830
- .ss-w-hlbtn--up { background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); color: var(--ss-w-accent); border-color: color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-w-line)); }
6831
- .ss-w-hlbtn--dn { background: var(--ss-w-panel); color: var(--ss-w-ink); }
6832
- .ss-w-hlbtn:hover:not(:disabled) { border-color: var(--ss-w-accent); }
7001
+ /* Both options are neutral until picked \u2014 an amber default read as "already selected". */
7002
+ .ss-w-hlbtn--up, .ss-w-hlbtn--dn { background: var(--ss-w-panel); color: var(--ss-w-ink); }
7003
+ .ss-w-hlbtn:hover:not(:disabled) { 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); }
6833
7004
  .ss-w-hlbtn:disabled { opacity: .5; cursor: not-allowed; }
6834
7005
  /* Run-over terminal panel */
6835
7006
  .ss-w-hl-over { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 16px; text-align: center; display: flex; flex-direction: column; gap: 5px; }
@@ -6856,18 +7027,18 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
6856
7027
  .ss-w-cpath-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }
6857
7028
  .ss-w-cpath-left { margin-left: auto; flex: none; font-size: 11px; 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: 4px 10px; white-space: nowrap; }
6858
7029
  /* Career sequence \u2014 horizontal crests with arrows */
6859
- .ss-w-cpath-seq { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 13px 11px; }
6860
- .ss-w-cpath-arrow { align-self: center; color: var(--ss-w-faint); font-size: 13px; padding-top: 10px; }
7030
+ .ss-w-cpath-seq { display: flex; flex-wrap: nowrap; align-items: flex-start; gap: 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 13px 11px; overflow-x: auto; overscroll-behavior-x: contain; }
7031
+ .ss-w-cpath-arrow { align-self: center; flex: none; color: var(--ss-w-faint); font-size: 13px; padding-top: 10px; }
6861
7032
  /* Single club \u2014 small vertical card */
6862
- .ss-w-cpath-club { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 58px; }
7033
+ .ss-w-cpath-club { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 56px; flex: none; }
6863
7034
  .ss-w-cpath-crest { width: 34px; height: 34px; object-fit: contain; flex: none; border-radius: 8px; }
6864
7035
  .ss-w-cpath-crest--fallback { background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); display: grid; place-items: center; font-size: 9px; font-weight: 800; letter-spacing: .02em; color: var(--ss-w-faint); }
6865
- .ss-w-cpath-club-name { font-size: 9px; font-weight: 600; color: var(--ss-w-ink); text-align: center; line-height: 1.1; overflow-wrap: anywhere; }
7036
+ .ss-w-cpath-club-name { font-size: 9px; font-weight: 600; color: var(--ss-w-ink); text-align: center; line-height: 1.15; max-width: 56px; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
6866
7037
  .ss-w-cpath-spell-yr { font-size: 8px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; }
6867
7038
  .ss-w-cpath-loan-badge { font-size: 7.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 0 5px; border-radius: 999px; background: color-mix(in srgb, var(--ss-w-accent) 15%, var(--ss-w-panel)); color: var(--ss-w-accent); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }
6868
7039
  .ss-w-cpath-club--loan .ss-w-cpath-crest { border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-w-line)); }
6869
7040
  /* Hidden clubs chip */
6870
- .ss-w-cpath-hidden { align-self: center; font-size: 9px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px dashed var(--ss-w-line); border-radius: 8px; padding: 6px 8px; }
7041
+ .ss-w-cpath-hidden { align-self: center; flex: none; white-space: nowrap; font-size: 9px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px dashed var(--ss-w-line); border-radius: 8px; padding: 6px 8px; }
6871
7042
  /* Hint line */
6872
7043
  .ss-w-cpath-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; padding: 6px 10px; border-radius: 10px; background: color-mix(in srgb, var(--ss-w-accent) 8%, var(--ss-w-panel)); border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }
6873
7044
  /* Terminal outcome */
@@ -6931,23 +7102,18 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
6931
7102
  .ss-w-gxi-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }
6932
7103
  .ss-w-gxi-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }
6933
7104
  .ss-w-gxi-left { margin-left: auto; flex: none; font-size: 11px; 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: 4px 10px; white-space: nowrap; }
6934
- /* Positions pitch: compact slot grid */
6935
- .ss-w-gxi-pitch { display: flex; flex-wrap: wrap; gap: 5px; }
6936
- .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; }
6937
- .ss-w-gxi-pslot-pos { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-accent); }
6938
- .ss-w-gxi-pslot-nat { font-size: 10px; color: var(--ss-w-faint); font-weight: 500; text-align: center; line-height: 1.2; }
7105
+ /* Pitch: a flag per slot laid out in formation rows on a green field */
7106
+ .ss-w-gxi-pitch { display: flex; flex-direction: column; justify-content: space-between; gap: 10px; padding: 16px 10px; border-radius: 14px; border: 1px solid color-mix(in srgb, var(--ss-w-correct) 22%, var(--ss-w-line)); background: linear-gradient(180deg, color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)), color-mix(in srgb, var(--ss-w-correct) 4%, var(--ss-w-panel))); }
7107
+ .ss-w-gxi-prow { display: flex; justify-content: space-around; align-items: center; gap: 8px; }
7108
+ .ss-w-gxi-flag { width: 34px; height: 34px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 19px; line-height: 1; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); box-shadow: 0 1px 3px rgba(0,0,0,.14); overflow: hidden; }
7109
+ /* Wrong-guess trail */
7110
+ .ss-w-gxi-wrong { display: flex; flex-wrap: wrap; gap: 6px; }
7111
+ .ss-w-gxi-wrong-pill { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; background: color-mix(in srgb, var(--ss-w-wrong) 10%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); text-decoration: line-through; }
6939
7112
  /* Earned reveals */
6940
7113
  .ss-w-gxi-reveals { display: flex; flex-direction: column; gap: 4px; }
6941
7114
  .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; }
6942
7115
  .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; }
6943
7116
  .ss-w-gxi-reveal-val { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
6944
- /* Team pool: responsive flex grid of buttons */
6945
- .ss-w-gxi-pool { display: flex; flex-wrap: wrap; gap: 6px; }
6946
- .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; }
6947
- .ss-w-gxi-team-btn:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }
6948
- .ss-w-gxi-team-btn:disabled { opacity: .5; cursor: not-allowed; }
6949
- .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); }
6950
- .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; }
6951
7117
  /* Terminal outcome banner */
6952
7118
  .ss-w-gxi-banner { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 16px 12px; border-radius: 14px; text-align: center; }
6953
7119
  .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)); }
@@ -7140,7 +7306,7 @@ function StatsWidget(props) {
7140
7306
  }, []);
7141
7307
  const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
7142
7308
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
7143
- const [hasToday, setHasToday] = useState33(false);
7309
+ const [hasToday, setHasToday] = useState34(false);
7144
7310
  const monitor = useLiveMonitor({
7145
7311
  getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
7146
7312
  getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),