@sensiblestats/widget-react 0.49.0 → 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_react31 = 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
@@ -1908,7 +1908,7 @@ function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup,
1908
1908
  }
1909
1909
 
1910
1910
  // src/components/ChatPanel.tsx
1911
- var import_react30 = require("react");
1911
+ var import_react38 = require("react");
1912
1912
 
1913
1913
  // src/components/ChatHeader.tsx
1914
1914
  var import_react11 = require("react");
@@ -4011,7 +4011,7 @@ function TodayPanel({ discovery, ui, monitor }) {
4011
4011
  }
4012
4012
 
4013
4013
  // src/components/GamesPanel.tsx
4014
- var import_react28 = require("react");
4014
+ var import_react36 = require("react");
4015
4015
 
4016
4016
  // src/components/GamesLoginWall.tsx
4017
4017
  var import_jsx_runtime52 = require("react/jsx-runtime");
@@ -4123,64 +4123,1385 @@ function GamesHub({
4123
4123
  }
4124
4124
 
4125
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
4138
+ };
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
+ }
4162
+ }
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 {
4181
+ }
4182
+ })();
4183
+ }, []);
4184
+ return { result, submitting, submit, hydrate, rawStatus };
4185
+ }
4186
+
4187
+ // src/components/games/MysteryTigerGame.tsx
4188
+ var import_react29 = require("react");
4126
4189
  var import_jsx_runtime55 = require("react/jsx-runtime");
4127
- function resolveScreen(gameId) {
4128
- switch (gameId) {
4129
- // D3/D4 cases go here
4130
- default:
4131
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gscreen-body", "data-testid": `game-screen-${gameId}`, children: gameId });
4190
+ function parseClientState(json) {
4191
+ if (!json) return null;
4192
+ try {
4193
+ return JSON.parse(json);
4194
+ } catch {
4195
+ return null;
4196
+ }
4197
+ }
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 }));
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
+ ] });
4310
+ }
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
+ }
4321
+ }
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
+ ] });
4337
+ }
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;
4132
5322
  }
4133
5323
  }
4134
5324
  function GameScreenHost({
4135
5325
  selected,
4136
5326
  onBack,
5327
+ conversation,
4137
5328
  ui
4138
5329
  }) {
4139
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gscreen", children: [
4140
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("button", { type: "button", className: "ss-w-gscreen-back", onClick: onBack, children: [
4141
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "ss-w-gscreen-back-arrow", "aria-hidden": "true", children: "\u2039" }),
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" }),
4142
5463
  ui.back
4143
5464
  ] }),
4144
- resolveScreen(selected.gameId)
5465
+ renderScreen()
4145
5466
  ] });
4146
5467
  }
4147
5468
 
4148
5469
  // src/components/GamesPanel.tsx
4149
- var import_jsx_runtime56 = require("react/jsx-runtime");
5470
+ var import_jsx_runtime66 = require("react/jsx-runtime");
4150
5471
  function GamesPanel({
4151
5472
  loggedIn,
4152
5473
  games,
4153
5474
  ui,
4154
5475
  conversation
4155
5476
  }) {
4156
- const [selected, setSelected] = (0, import_react28.useState)(null);
4157
- if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(GamesLoginWall, { ui });
5477
+ const [selected, setSelected] = (0, import_react36.useState)(null);
5478
+ if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(GamesLoginWall, { ui });
4158
5479
  if (selected !== null) {
4159
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
5480
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
4160
5481
  GameScreenHost,
4161
5482
  {
4162
5483
  selected,
4163
5484
  onBack: () => setSelected(null),
4164
- conversation,
5485
+ conversation: conversation ?? null,
4165
5486
  ui
4166
5487
  }
4167
5488
  ) });
4168
5489
  }
4169
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-mon-list", "data-testid": "games-hub", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
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)(
4170
5491
  GamesHub,
4171
5492
  {
4172
5493
  games,
4173
- onOpen: (g) => setSelected({ gameId: g.gameId, fixtureId: g.fixtureId }),
5494
+ onOpen: (g) => setSelected({ gameId: g.gameId, fixtureId: g.fixtureId, gameDay: g.gameDay }),
4174
5495
  ui
4175
5496
  }
4176
5497
  ) });
4177
5498
  }
4178
5499
 
4179
5500
  // src/components/Leaderboard.tsx
4180
- var import_react29 = require("react");
5501
+ var import_react37 = require("react");
4181
5502
 
4182
5503
  // src/components/LeaderboardRow.tsx
4183
- var import_jsx_runtime57 = require("react/jsx-runtime");
5504
+ var import_jsx_runtime67 = require("react/jsx-runtime");
4184
5505
  function formatPoints(n) {
4185
5506
  return n.toLocaleString("en");
4186
5507
  }
@@ -4189,14 +5510,14 @@ function LeaderboardWeeklyRow({
4189
5510
  isMe
4190
5511
  }) {
4191
5512
  const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? " ss-w-lb2-rank--top3" : ""}`;
4192
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `ss-w-lb2-row${isMe ? " ss-w-lb2-row--you" : ""}`, children: [
4193
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: rankClass, children: [
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: [
4194
5515
  "#",
4195
5516
  row.rank
4196
5517
  ] }),
4197
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-lb2-handle", children: row.handle }),
4198
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-lb2-points", children: formatPoints(row.points) }),
4199
- row.currentStreak > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "ss-w-lb2-streak", children: [
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: [
4200
5521
  "\u{1F525} ",
4201
5522
  row.currentStreak
4202
5523
  ] })
@@ -4207,28 +5528,28 @@ function LeaderboardAllTimeRow({
4207
5528
  isMe
4208
5529
  }) {
4209
5530
  const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? " ss-w-lb2-rank--top3" : ""}`;
4210
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `ss-w-lb2-row${isMe ? " ss-w-lb2-row--you" : ""}`, children: [
4211
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: rankClass, children: [
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: [
4212
5533
  "#",
4213
5534
  row.rank
4214
5535
  ] }),
4215
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-lb2-handle", children: row.handle }),
4216
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-lb2-points", children: formatPoints(row.allTimePoints) })
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) })
4217
5538
  ] });
4218
5539
  }
4219
5540
 
4220
5541
  // src/components/Leaderboard.tsx
4221
- var import_jsx_runtime58 = require("react/jsx-runtime");
5542
+ var import_jsx_runtime68 = require("react/jsx-runtime");
4222
5543
  function Leaderboard({
4223
5544
  data,
4224
5545
  ui
4225
5546
  }) {
4226
- const [segment, setSegment] = (0, import_react29.useState)("weekly");
5547
+ const [segment, setSegment] = (0, import_react37.useState)("weekly");
4227
5548
  const myRow = segment === "weekly" ? data.myWeeklyRow : data.myAllTimeRow;
4228
5549
  const offBoard = myRow !== null && myRow !== void 0 && myRow.rank === -1;
4229
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-lb2", children: [
4230
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-seg", children: [
4231
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
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)(
4232
5553
  "button",
4233
5554
  {
4234
5555
  type: "button",
@@ -4238,7 +5559,7 @@ function Leaderboard({
4238
5559
  children: ui.leaderboardThisWeek
4239
5560
  }
4240
5561
  ),
4241
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
5562
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
4242
5563
  "button",
4243
5564
  {
4244
5565
  type: "button",
@@ -4249,14 +5570,14 @@ function Leaderboard({
4249
5570
  }
4250
5571
  )
4251
5572
  ] }),
4252
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-lb2-rows", children: segment === "weekly" ? data.weeklyTop.map((row) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
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)(
4253
5574
  LeaderboardWeeklyRow,
4254
5575
  {
4255
5576
  row,
4256
5577
  isMe: row.operatorUserId === data.myWeeklyRow?.operatorUserId
4257
5578
  },
4258
5579
  row.operatorUserId
4259
- )) : data.allTimeTop.map((row) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
5580
+ )) : data.allTimeTop.map((row) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
4260
5581
  LeaderboardAllTimeRow,
4261
5582
  {
4262
5583
  row,
@@ -4264,29 +5585,29 @@ function Leaderboard({
4264
5585
  },
4265
5586
  row.operatorUserId
4266
5587
  )) }),
4267
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-kitline", children: "\u{1F3BD}" }),
4268
- myRow != null && (offBoard ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-lbgap", children: ui.leaderboardOffBoard }) : /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "ss-w-lb2-rows", children: [
4269
- segment === "weekly" && data.myWeeklyRow && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(LeaderboardWeeklyRow, { row: data.myWeeklyRow, isMe: true }),
4270
- segment === "alltime" && data.myAllTimeRow && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(LeaderboardAllTimeRow, { row: data.myAllTimeRow, isMe: true })
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 })
4271
5592
  ] })),
4272
- segment === "alltime" && data.myAllTimeRow && !offBoard && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-lb2-rows", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "ss-w-lb2-row", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-lb2-handle", children: formatPoints(data.allTimeTop.reduce((s, r) => s + r.allTimePoints, 0)) }) }) })
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)) }) }) })
4273
5594
  ] });
4274
5595
  }
4275
5596
 
4276
5597
  // src/components/LeaderboardPanel.tsx
4277
- var import_jsx_runtime59 = require("react/jsx-runtime");
5598
+ var import_jsx_runtime69 = require("react/jsx-runtime");
4278
5599
  function LeaderboardPanel({ loggedIn, data, ui }) {
4279
- if (!loggedIn) return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(GamesLoginWall, { ui });
4280
- if (data === null) return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-mon-list" });
4281
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Leaderboard, { 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 }) });
4282
5603
  }
4283
5604
 
4284
5605
  // src/components/ChatPanel.tsx
4285
- var import_jsx_runtime60 = require("react/jsx-runtime");
5606
+ var import_jsx_runtime70 = require("react/jsx-runtime");
4286
5607
  var FULLSCREEN_QUERY = "(max-width: 639px)";
4287
5608
  function useIsModal() {
4288
- const [modal, setModal] = (0, import_react30.useState)(false);
4289
- (0, import_react30.useEffect)(() => {
5609
+ const [modal, setModal] = (0, import_react38.useState)(false);
5610
+ (0, import_react38.useEffect)(() => {
4290
5611
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
4291
5612
  const mql = window.matchMedia(FULLSCREEN_QUERY);
4292
5613
  const sync = () => setModal(mql.matches);
@@ -4296,10 +5617,10 @@ function useIsModal() {
4296
5617
  }, []);
4297
5618
  return modal;
4298
5619
  }
4299
- function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn }) {
5620
+ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }) {
4300
5621
  const { state, close, stop, send, reset } = controller;
4301
5622
  const isModal = useIsModal();
4302
- (0, import_react30.useEffect)(() => {
5623
+ (0, import_react38.useEffect)(() => {
4303
5624
  const onKey = (e) => {
4304
5625
  if (e.key === "Escape") close();
4305
5626
  };
@@ -4310,11 +5631,11 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
4310
5631
  monitor?.setActiveTab("chat");
4311
5632
  send(text);
4312
5633
  };
4313
- (0, import_react30.useEffect)(() => {
5634
+ (0, import_react38.useEffect)(() => {
4314
5635
  if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
4315
5636
  }, [monitor, state.isStreaming, state.messages.length]);
4316
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
4317
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
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)(
4318
5639
  ChatHeader,
4319
5640
  {
4320
5641
  onClose: close,
@@ -4327,7 +5648,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
4327
5648
  moreOptionsLabel: ui.moreOptions
4328
5649
  }
4329
5650
  ),
4330
- monitor && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
5651
+ monitor && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
4331
5652
  TabBar,
4332
5653
  {
4333
5654
  monitor,
@@ -4339,19 +5660,19 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
4339
5660
  gamesEnabled: gamesResult?.enabled ?? false
4340
5661
  }
4341
5662
  ),
4342
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
5663
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
4343
5664
  "div",
4344
5665
  {
4345
5666
  style: !monitor || monitor.activeTab === "chat" ? { display: "contents" } : { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" },
4346
- children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
5667
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(MessageList, { controller, ui, slip, onDashboardTap, monitor })
4347
5668
  }
4348
5669
  ),
4349
- monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(TodayPanel, { discovery, ui, monitor }),
4350
- monitor && monitor.activeTab === "following" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(MatchesPanel, { monitor, ui, slip }),
4351
- monitor && monitor.activeTab === "odds" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(OddsPanel, { monitor, ui, slip }),
4352
- monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(GamesPanel, { loggedIn: !!loggedIn, games: gamesResult.games, ui }),
4353
- monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(LeaderboardPanel, { loggedIn: !!loggedIn, data: leaderboardResult.data, ui }),
4354
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: handleSend, onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
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 })
4355
5676
  ] });
4356
5677
  }
4357
5678
 
@@ -5304,10 +6625,315 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
5304
6625
 
5305
6626
  /* Off-board treatment: dashed pill indicating rank is outside top N */
5306
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; }
5307
6933
  `;
5308
6934
 
5309
6935
  // src/StatsWidget.tsx
5310
- var import_jsx_runtime61 = require("react/jsx-runtime");
6936
+ var import_jsx_runtime71 = require("react/jsx-runtime");
5311
6937
  function buildClient(props) {
5312
6938
  try {
5313
6939
  if ("client" in props && props.client) {
@@ -5332,23 +6958,23 @@ function injectStyles(root) {
5332
6958
  function StatsWidget(props) {
5333
6959
  const injectedClient = "client" in props ? props.client : void 0;
5334
6960
  const cfg = props.config;
5335
- const built = (0, import_react31.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
5336
- const logger = (0, import_react31.useMemo)(
6961
+ const built = (0, import_react39.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
6962
+ const logger = (0, import_react39.useMemo)(
5337
6963
  () => built ? built.client.createEventLogger({
5338
6964
  operatorUserId: cfg?.userContext?.operatorUserId,
5339
6965
  anonymousUserId: cfg?.userContext?.anonymousUserId
5340
6966
  }) : null,
5341
6967
  [built?.client]
5342
6968
  );
5343
- const ui = (0, import_react31.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
5344
- const rootRef = (0, import_react31.useRef)(null);
5345
- const introDoneRef = (0, import_react31.useRef)(false);
5346
- const markIntroDone = (0, import_react31.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)(() => {
5347
6973
  introDoneRef.current = true;
5348
6974
  }, []);
5349
6975
  const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
5350
6976
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
5351
- const [hasToday, setHasToday] = (0, import_react31.useState)(false);
6977
+ const [hasToday, setHasToday] = (0, import_react39.useState)(false);
5352
6978
  const monitor = useLiveMonitor({
5353
6979
  getLiveMonitor: (pins) => built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null),
5354
6980
  getMarketOdds: (matchId, dev) => built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null),
@@ -5356,15 +6982,15 @@ function StatsWidget(props) {
5356
6982
  isOpen: controller.state.isOpen,
5357
6983
  hasToday
5358
6984
  });
5359
- const getSchedule = (0, import_react31.useCallback)(
6985
+ const getSchedule = (0, import_react39.useCallback)(
5360
6986
  (localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
5361
6987
  [built]
5362
6988
  );
5363
- const getStates = (0, import_react31.useCallback)(
6989
+ const getStates = (0, import_react39.useCallback)(
5364
6990
  (matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
5365
6991
  [built]
5366
6992
  );
5367
- const pinnedMatchIds = (0, import_react31.useMemo)(
6993
+ const pinnedMatchIds = (0, import_react39.useMemo)(
5368
6994
  () => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
5369
6995
  [monitor.pins]
5370
6996
  );
@@ -5376,19 +7002,19 @@ function StatsWidget(props) {
5376
7002
  pinnedMatchIds
5377
7003
  });
5378
7004
  const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
5379
- (0, import_react31.useEffect)(() => {
7005
+ (0, import_react39.useEffect)(() => {
5380
7006
  setHasToday(todayHasContent);
5381
7007
  }, [todayHasContent]);
5382
7008
  const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
5383
7009
  const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
5384
7010
  const markTodayActivity = monitor.markTodayActivity;
5385
- const prevLiveCountRef = (0, import_react31.useRef)(0);
5386
- (0, import_react31.useEffect)(() => {
7011
+ const prevLiveCountRef = (0, import_react39.useRef)(0);
7012
+ (0, import_react39.useEffect)(() => {
5387
7013
  const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
5388
7014
  prevLiveCountRef.current = discovery.liveCount;
5389
7015
  if (rose) markTodayActivity();
5390
7016
  }, [discovery.liveCount, markTodayActivity]);
5391
- const slip = (0, import_react31.useMemo)(
7017
+ const slip = (0, import_react39.useMemo)(
5392
7018
  () => {
5393
7019
  const handler = props.config?.onAddToSlip;
5394
7020
  return {
@@ -5411,18 +7037,18 @@ function StatsWidget(props) {
5411
7037
  },
5412
7038
  [props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip]
5413
7039
  );
5414
- const onDashboardTap = (0, import_react31.useMemo)(
7040
+ const onDashboardTap = (0, import_react39.useMemo)(
5415
7041
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
5416
7042
  [built, logger]
5417
7043
  );
5418
7044
  const operatorUserId = cfg?.userContext?.operatorUserId;
5419
7045
  const anonymousUserId = cfg?.userContext?.anonymousUserId;
5420
7046
  const conversationId = controller.state.conversationId ?? void 0;
5421
- (0, import_react31.useEffect)(() => {
7047
+ (0, import_react39.useEffect)(() => {
5422
7048
  if (!logger) return;
5423
7049
  logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
5424
7050
  }, [logger, operatorUserId, anonymousUserId, conversationId]);
5425
- (0, import_react31.useEffect)(() => {
7051
+ (0, import_react39.useEffect)(() => {
5426
7052
  if (!logger) return;
5427
7053
  const onHide = () => {
5428
7054
  logger.flushOnHide();
@@ -5439,14 +7065,14 @@ function StatsWidget(props) {
5439
7065
  logger.dispose();
5440
7066
  };
5441
7067
  }, [logger]);
5442
- (0, import_react31.useEffect)(() => {
7068
+ (0, import_react39.useEffect)(() => {
5443
7069
  if (!built || !ui.injectStyles) return;
5444
7070
  const node = rootRef.current?.getRootNode();
5445
7071
  if (node) injectStyles(node);
5446
7072
  }, [built, ui.injectStyles]);
5447
7073
  if (!built) return null;
5448
7074
  const attrs = themeAttrs(ui);
5449
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ (0, import_jsx_runtime61.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_runtime61.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)(
5450
7076
  ChatPanel,
5451
7077
  {
5452
7078
  controller,
@@ -5459,7 +7085,7 @@ function StatsWidget(props) {
5459
7085
  leaderboardResult,
5460
7086
  loggedIn: !!operatorUserId
5461
7087
  }
5462
- ) : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7088
+ ) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
5463
7089
  ChatFab,
5464
7090
  {
5465
7091
  label: ui.launcherLabel,