@sensiblestats/widget-react 0.53.0 → 0.55.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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.55.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ede9739: Fix the daily games resetting on the second guess, and tighten three screens to the design artifact:
8
+
9
+ - Guard the play lifecycle against a state-losing submit response: an in-progress `postPlay` that returns no `clientStateJson` (e.g. a server-side concurrency retry) no longer wipes the board — the widget reconciles from `getGameResult` instead of rendering an empty state. (The root-cause fix is server-side; this is defence-in-depth so the board can never blank mid-game.)
10
+ - Guess the XI pitch now reads as a football field — fixed grass-green with visible yard-lines and a halfway line, and smaller flag dots — instead of a flat dark box.
11
+ - Mystery Tiger's first load shows one lead line above the search (no empty attribute tiles), matching the artifact; the shirt tile is labelled "Shirt" not "Kit".
12
+ - Beat the Grid filled cells now name the placed player (compact "F. Last") above the rarity score, so the fan can see who they put where.
13
+
14
+ ## 0.54.0
15
+
16
+ ### Minor Changes
17
+
18
+ - c013151: Rebuild the daily game screens to match the design artifact:
19
+
20
+ - Guess the XI now renders a real formation on the pitch (GK line at the back → forwards forward), so each flag's position is legible instead of a scatter; cut to 3 guesses.
21
+ - Career Path wraps the club-crest sequence instead of scrolling/truncating with "+N more"; loans read as "(loan)" and years are compact.
22
+ - Higher or Lower drops the answered-history list for the artifact's clean pair + footer chips.
23
+ - Mystery Tiger's first load shows the five-attribute legend instead of a bare search box.
24
+
3
25
  ## 0.53.0
4
26
 
5
27
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -4189,6 +4189,24 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, refresh }) {
4189
4189
  convRef.current = conversation;
4190
4190
  const optsRef = (0, import_react28.useRef)({ gameId, gameDay, fixtureId, refresh });
4191
4191
  optsRef.current = { gameId, gameDay, fixtureId, refresh };
4192
+ const resultRef = (0, import_react28.useRef)(null);
4193
+ resultRef.current = result;
4194
+ const refetch = (0, import_react28.useCallback)(async () => {
4195
+ const conv = convRef.current;
4196
+ if (!conv) return;
4197
+ const opts = optsRef.current;
4198
+ try {
4199
+ const payload = await conv.getGameResult(opts.gameId, opts.fixtureId, opts.gameDay);
4200
+ if (payload === null) return;
4201
+ if (payload.clientStateJson == null && resultRef.current?.clientStateJson != null) {
4202
+ setRawStatus(payload.status);
4203
+ return;
4204
+ }
4205
+ setResult(toSubmitResult(payload));
4206
+ setRawStatus(payload.status);
4207
+ } catch {
4208
+ }
4209
+ }, []);
4192
4210
  const submit = (0, import_react28.useCallback)(async (answerJson) => {
4193
4211
  const conv = convRef.current;
4194
4212
  if (!conv || inFlightRef.current) return;
@@ -4198,7 +4216,14 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, refresh }) {
4198
4216
  const opts = optsRef.current;
4199
4217
  const playResult = await conv.postPlay(opts.gameId, answerJson, opts.gameDay, opts.fixtureId);
4200
4218
  if (playResult !== null) {
4201
- setResult(playResult);
4219
+ const hasFreshState = playResult.clientStateJson != null;
4220
+ const isTerminal2 = playResult.alreadyPlayed === true;
4221
+ const holdsState = resultRef.current?.clientStateJson != null;
4222
+ if (!hasFreshState && !isTerminal2 && holdsState) {
4223
+ await refetch();
4224
+ } else {
4225
+ setResult(playResult);
4226
+ }
4202
4227
  if (playResult.pointsDelta != null) {
4203
4228
  opts.refresh?.();
4204
4229
  }
@@ -4208,22 +4233,10 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, refresh }) {
4208
4233
  inFlightRef.current = false;
4209
4234
  setSubmitting(false);
4210
4235
  }
4211
- }, []);
4236
+ }, [refetch]);
4212
4237
  const hydrate = (0, import_react28.useCallback)(() => {
4213
- const conv = convRef.current;
4214
- if (!conv) return;
4215
- const opts = optsRef.current;
4216
- void (async () => {
4217
- try {
4218
- const payload = await conv.getGameResult(opts.gameId, opts.fixtureId, opts.gameDay);
4219
- if (payload !== null) {
4220
- setResult(toSubmitResult(payload));
4221
- setRawStatus(payload.status);
4222
- }
4223
- } catch {
4224
- }
4225
- })();
4226
- }, []);
4238
+ void refetch();
4239
+ }, [refetch]);
4227
4240
  return { result, submitting, submit, hydrate, rawStatus };
4228
4241
  }
4229
4242
 
@@ -4325,7 +4338,7 @@ var ATTR_LABELS = {
4325
4338
  position: "Pos",
4326
4339
  nationality: "Nat",
4327
4340
  age: "Age",
4328
- shirtNumber: "Kit",
4341
+ shirtNumber: "Shirt",
4329
4342
  apps: "Apps"
4330
4343
  };
4331
4344
  var ATTR_KEYS = [
@@ -4386,6 +4399,7 @@ function MysteryTigerGame({
4386
4399
  " left"
4387
4400
  ] })
4388
4401
  ] }),
4402
+ guessResults.length === 0 && !isOver && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gt-lead", children: "Guess any squad player \u2014 each guess reveals how close you are on position, nationality, age, shirt and apps." }),
4389
4403
  guessResults.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "ss-w-gtrows", children: guessResults.map((gr, i) => {
4390
4404
  const player = config.squadPlayers.find((p) => p.id === gr.playerId);
4391
4405
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "ss-w-gtguess", children: [
@@ -4470,6 +4484,7 @@ function MysteryTigerGame({
4470
4484
 
4471
4485
  // src/components/games/HigherOrLowerGame.tsx
4472
4486
  var import_jsx_runtime56 = require("react/jsx-runtime");
4487
+ var POINTS_PER_CORRECT = 10;
4473
4488
  function parseClientState2(json) {
4474
4489
  if (!json) return null;
4475
4490
  try {
@@ -4561,39 +4576,25 @@ function HigherOrLowerGame({
4561
4576
  ] })
4562
4577
  ] })
4563
4578
  ] }),
4579
+ !isOver && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hl-foot", children: [
4580
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "ss-w-hl-chip", children: [
4581
+ score,
4582
+ " pts"
4583
+ ] }),
4584
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "ss-w-hl-chip ss-w-hl-chip--green", children: [
4585
+ "+",
4586
+ POINTS_PER_CORRECT,
4587
+ " / correct"
4588
+ ] })
4589
+ ] }),
4564
4590
  isOver && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hl-over", children: [
4565
4591
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hl-over-title", children: runEndedWrong ? "Run over" : "Nice run!" }),
4566
4592
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hl-over-score", children: score }),
4567
4593
  /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "ss-w-hl-over-sub", children: [
4568
4594
  correctCount,
4569
- " correct",
4570
- correctCount === 1 ? "" : "",
4571
- " \xB7 come back tomorrow for a new run"
4595
+ " correct \xB7 come back tomorrow for a new run"
4572
4596
  ] })
4573
- ] }),
4574
- answeredPairs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "ss-w-hlresults", children: answeredPairs.map((answered) => {
4575
- const pair = config.pairs.find((p) => p.pairIndex === answered.pairIndex);
4576
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
4577
- "div",
4578
- {
4579
- className: `ss-w-hlrrow ss-w-hlrrow--${answered.wasCorrect ? "correct" : "wrong"}`,
4580
- children: [
4581
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "ss-w-hlrrow-names", children: [
4582
- pair?.playerAName ?? "?",
4583
- " ",
4584
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("b", { className: "ss-w-hlrrow-val", children: pair?.playerAValue }),
4585
- " vs ",
4586
- pair?.playerBName ?? "?",
4587
- " ",
4588
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("b", { className: "ss-w-hlrrow-val", children: answered.playerBValue })
4589
- ] }),
4590
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlrrow-pick", children: answered.pick }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "ss-w-hlrrow-icon", children: answered.wasCorrect ? "\u2713" : "\u2717" })
4592
- ]
4593
- },
4594
- answered.pairIndex
4595
- );
4596
- }) })
4597
+ ] })
4597
4598
  ] })
4598
4599
  ] });
4599
4600
  }
@@ -4610,18 +4611,22 @@ function parseClientState3(json) {
4610
4611
  }
4611
4612
  }
4612
4613
  function spellYears(spell) {
4613
- const parts = [];
4614
- if (spell.startYear) parts.push(String(spell.startYear));
4615
- if (spell.endYear) parts.push(String(spell.endYear));
4616
- return parts.join("\u2013");
4614
+ if (!spell.startYear) return "";
4615
+ const yy = (y) => `'${String(y % 100).padStart(2, "0")}`;
4616
+ if (spell.endYear && spell.endYear !== spell.startYear) {
4617
+ return `${yy(spell.startYear)}\u2013${String(spell.endYear % 100).padStart(2, "0")}`;
4618
+ }
4619
+ return yy(spell.startYear);
4617
4620
  }
4618
4621
  function ClubSpellCard({ spell }) {
4619
4622
  const years = spellYears(spell);
4620
4623
  return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: `ss-w-cpath-club${spell.isLoan ? " ss-w-cpath-club--loan" : ""}`, children: [
4621
4624
  spell.crestUrl ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("img", { src: spell.crestUrl, alt: "", className: "ss-w-cpath-crest", loading: "lazy" }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-crest ss-w-cpath-crest--fallback", "aria-hidden": "true", children: spell.clubName.slice(0, 3).toUpperCase() }),
4622
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-club-name", children: spell.clubName }),
4623
- years && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-spell-yr", children: years }),
4624
- spell.isLoan && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-loan-badge", children: "Loan" })
4625
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "ss-w-cpath-club-name", children: [
4626
+ spell.clubName,
4627
+ spell.isLoan && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-loan-note", children: " (loan)" })
4628
+ ] }),
4629
+ years && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-spell-yr", children: years })
4625
4630
  ] });
4626
4631
  }
4627
4632
  function CareerPathGame({
@@ -4636,8 +4641,6 @@ function CareerPathGame({
4636
4641
  const alreadyGuessedIds = new Set(clientState?.guessResults.map((g) => g.playerId) ?? []);
4637
4642
  const isOver = result?.alreadyPlayed === true || clientState?.solved === true || clientState?.failed === true;
4638
4643
  const visiblePath = clientState?.visiblePath ?? config?.initialPath ?? [];
4639
- const totalClubs = clientState?.totalClubs ?? config?.totalClubs ?? visiblePath.length;
4640
- const hiddenCount = Math.max(0, totalClubs - visiblePath.length);
4641
4644
  const filtered = config && !isOver ? config.typeaheadPool.filter(
4642
4645
  (p) => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase())
4643
4646
  ) : [];
@@ -4661,20 +4664,10 @@ function CareerPathGame({
4661
4664
  " left"
4662
4665
  ] })
4663
4666
  ] }),
4664
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-seq", children: [
4665
- visiblePath.map((spell, i) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_react30.Fragment, { children: [
4666
- i > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-arrow", "aria-hidden": "true", children: "\u2192" }),
4667
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ClubSpellCard, { spell })
4668
- ] }, `${spell.clubName}-${i}`)),
4669
- hiddenCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
4670
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-arrow", "aria-hidden": "true", children: "\u2192" }),
4671
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-hidden", children: [
4672
- "+",
4673
- hiddenCount,
4674
- " more"
4675
- ] })
4676
- ] })
4677
- ] }),
4667
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "ss-w-cpath-seq", children: visiblePath.map((spell, i) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_react30.Fragment, { children: [
4668
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "ss-w-cpath-arrow", "aria-hidden": "true", children: "\u203A" }),
4669
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ClubSpellCard, { spell })
4670
+ ] }, `${spell.clubName}-${i}`)) }),
4678
4671
  clientState?.hintLine && !isOver && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "ss-w-cpath-hint", children: [
4679
4672
  "\u{1F4A1} ",
4680
4673
  clientState.hintLine
@@ -4740,6 +4733,15 @@ function parseClientState4(json) {
4740
4733
  function findCellResult(cells, row, col) {
4741
4734
  return cells.find((c) => c.row === row && c.col === col);
4742
4735
  }
4736
+ function shortName(name) {
4737
+ if (!name) return "";
4738
+ const parts = name.trim().split(/\s+/).filter(Boolean);
4739
+ if (parts.length === 0) return "";
4740
+ const first = parts[0];
4741
+ if (parts.length === 1) return first;
4742
+ const last = parts[parts.length - 1];
4743
+ return `${first.charAt(0)}. ${last}`;
4744
+ }
4743
4745
  function SearchSheet({
4744
4746
  row,
4745
4747
  col,
@@ -4885,8 +4887,11 @@ function BeatTheGridGame({
4885
4887
  disabled: isLocked2 || submitting,
4886
4888
  onClick: () => handleCellClick(rowIdx, colIdx),
4887
4889
  children: filled ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
4888
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-score", children: filled.rarityScore }),
4889
- filled.isCorrect && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-check", "aria-hidden": "true", children: "\u2713" })
4890
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-nm", children: shortName(playerPool.find((p) => p.id === filled.playerId)?.name) }),
4891
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "ss-w-btg-cell-score", children: [
4892
+ filled.rarityScore,
4893
+ filled.isCorrect && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-check", "aria-hidden": "true", children: " \u2713" })
4894
+ ] })
4890
4895
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "ss-w-btg-cell-empty", "aria-hidden": "true", children: "+" })
4891
4896
  },
4892
4897
  `cell-${rowIdx}-${colIdx}`
@@ -4925,6 +4930,7 @@ function BeatTheGridGame({
4925
4930
  // src/components/games/GuessTheXiGame.tsx
4926
4931
  var import_react32 = require("react");
4927
4932
  var import_jsx_runtime59 = require("react/jsx-runtime");
4933
+ var MAX_GUESSES = 3;
4928
4934
  function parseClientState5(json) {
4929
4935
  if (!json) return null;
4930
4936
  try {
@@ -4980,12 +4986,12 @@ function GuessTheXiGame({
4980
4986
  /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { children: [
4981
4987
  /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "ss-w-gxi-title", children: "Guess the XI" }),
4982
4988
  /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "ss-w-gxi-sub", children: [
4983
- "Which team? \xB7 ",
4989
+ "Which team? \xB7 flags only \xB7 ",
4984
4990
  config.poolLabel
4985
4991
  ] })
4986
4992
  ] }),
4987
4993
  clientState && !isOver && /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "ss-w-gxi-left", children: [
4988
- Math.max(0, 6 - clientState.guessesUsed),
4994
+ Math.max(0, MAX_GUESSES - clientState.guessesUsed),
4989
4995
  " left"
4990
4996
  ] })
4991
4997
  ] }),
@@ -6993,6 +6999,8 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
6993
6999
  .ss-w-gt-left { margin-left: auto; flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 11%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 22%, var(--ss-w-line)); border-radius: 999px; padding: 4px 10px; white-space: nowrap; }
6994
7000
  /* Guess rows \u2014 one labelled block per guess */
6995
7001
  .ss-w-gtrows { display: flex; flex-direction: column; gap: 8px; }
7002
+ /* First-load legend (empty state) */
7003
+ .ss-w-gt-lead { font-size: 11.5px; color: var(--ss-w-faint); line-height: 1.4; }
6996
7004
  .ss-w-gtguess { display: flex; flex-direction: column; gap: 4px; }
6997
7005
  .ss-w-gtguess-nm { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
6998
7006
  .ss-w-gtrow { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; }
@@ -7045,16 +7053,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
7045
7053
  .ss-w-hl-over-score { font-size: 34px; font-weight: 800; color: var(--ss-w-accent); line-height: 1; font-variant-numeric: tabular-nums; }
7046
7054
  .ss-w-hl-over-sub { font-size: 11px; color: var(--ss-w-faint); }
7047
7055
  /* Answered history \u2014 clean single-line rows with the revealed value */
7048
- .ss-w-hlresults { display: flex; flex-direction: column; gap: 5px; }
7049
- .ss-w-hlrrow { display: flex; align-items: center; gap: 8px; padding: 8px 11px; border-radius: 10px; font-size: 12px; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); }
7050
- .ss-w-hlrrow--correct { background: color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-correct) 30%, var(--ss-w-line)); }
7051
- .ss-w-hlrrow--wrong { background: color-mix(in srgb, var(--ss-w-cta) 8%, var(--ss-w-panel)); }
7052
- .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; }
7053
- .ss-w-hlrrow-val { font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; }
7054
- .ss-w-hlrrow-pick { font-size: 10px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-faint); flex: none; }
7055
- .ss-w-hlrrow-icon { font-size: 14px; flex: none; }
7056
- .ss-w-hlrrow--correct .ss-w-hlrrow-icon { color: var(--ss-w-correct); }
7057
- .ss-w-hlrrow--wrong .ss-w-hlrrow-icon { color: var(--ss-w-cta); }
7056
+ /* In-progress footer chips (artifact) */
7057
+ .ss-w-hl-foot { display: flex; align-items: center; gap: 8px; }
7058
+ .ss-w-hl-chip { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 999px; padding: 4px 10px; }
7059
+ .ss-w-hl-chip--green { margin-left: auto; color: var(--ss-w-correct); background: color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-correct) 26%, var(--ss-w-line)); }
7058
7060
 
7059
7061
  /* ---- Career Path game screen (D3) \u2014 artifact cpath/club/cto layout ---- */
7060
7062
  .ss-w-cpath { display: flex; flex-direction: column; gap: 12px; }
@@ -7064,18 +7066,16 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
7064
7066
  .ss-w-cpath-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }
7065
7067
  .ss-w-cpath-left { margin-left: auto; flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 11%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 22%, var(--ss-w-line)); border-radius: 999px; padding: 4px 10px; white-space: nowrap; }
7066
7068
  /* Career sequence \u2014 horizontal crests with arrows */
7067
- .ss-w-cpath-seq { display: flex; flex-wrap: nowrap; align-items: flex-start; gap: 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 13px 11px; overflow-x: auto; overscroll-behavior-x: contain; }
7068
- .ss-w-cpath-arrow { align-self: center; flex: none; color: var(--ss-w-faint); font-size: 13px; padding-top: 10px; }
7069
+ .ss-w-cpath-seq { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 13px 11px; }
7070
+ .ss-w-cpath-arrow { align-self: flex-start; flex: none; color: var(--ss-w-faint); font-size: 13px; padding-top: 9px; }
7069
7071
  /* Single club \u2014 small vertical card */
7070
7072
  .ss-w-cpath-club { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 56px; flex: none; }
7071
7073
  .ss-w-cpath-crest { width: 34px; height: 34px; object-fit: contain; flex: none; border-radius: 8px; }
7072
7074
  .ss-w-cpath-crest--fallback { background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); display: grid; place-items: center; font-size: 9px; font-weight: 800; letter-spacing: .02em; color: var(--ss-w-faint); }
7073
- .ss-w-cpath-club-name { font-size: 9px; font-weight: 600; color: var(--ss-w-ink); text-align: center; line-height: 1.15; max-width: 56px; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
7075
+ .ss-w-cpath-club-name { font-size: 9px; font-weight: 600; color: var(--ss-w-ink); text-align: center; line-height: 1.15; max-width: 56px; overflow-wrap: anywhere; }
7074
7076
  .ss-w-cpath-spell-yr { font-size: 8px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; }
7075
- .ss-w-cpath-loan-badge { font-size: 7.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 0 5px; border-radius: 999px; background: color-mix(in srgb, var(--ss-w-accent) 15%, var(--ss-w-panel)); color: var(--ss-w-accent); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }
7077
+ .ss-w-cpath-loan-note { display: block; color: var(--ss-w-faint); font-weight: 500; }
7076
7078
  .ss-w-cpath-club--loan .ss-w-cpath-crest { border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-w-line)); }
7077
- /* Hidden clubs chip */
7078
- .ss-w-cpath-hidden { align-self: center; flex: none; white-space: nowrap; font-size: 9px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px dashed var(--ss-w-line); border-radius: 8px; padding: 6px 8px; }
7079
7079
  /* Hint line */
7080
7080
  .ss-w-cpath-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; padding: 6px 10px; border-radius: 10px; background: color-mix(in srgb, var(--ss-w-accent) 8%, var(--ss-w-panel)); border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }
7081
7081
  /* Terminal outcome */
@@ -7119,8 +7119,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
7119
7119
  .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)); }
7120
7120
  .ss-w-btg-cell--wrong { background: color-mix(in srgb, var(--ss-w-wrong) 10%, var(--ss-w-panel)); }
7121
7121
  .ss-w-btg-cell--active { border-color: var(--ss-w-accent); }
7122
- .ss-w-btg-cell-score { font-size: 14px; font-weight: 800; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }
7123
- .ss-w-btg-cell-check { font-size: 12px; color: var(--ss-w-correct); line-height: 1; }
7122
+ .ss-w-btg-cell-nm { font-size: 8.5px; font-weight: 600; line-height: 1.05; color: var(--ss-w-ink); text-align: center; max-width: 100%; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
7123
+ .ss-w-btg-cell-score { font-size: 12px; font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; }
7124
+ .ss-w-btg-cell--correct .ss-w-btg-cell-score { color: var(--ss-w-correct); }
7125
+ .ss-w-btg-cell-check { color: var(--ss-w-correct); line-height: 1; }
7124
7126
  .ss-w-btg-cell-empty { font-size: 16px; color: var(--ss-w-faint); }
7125
7127
  /* Scoped search sheet: slides up over the grid */
7126
7128
  .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); }
@@ -7139,10 +7141,19 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
7139
7141
  .ss-w-gxi-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }
7140
7142
  .ss-w-gxi-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }
7141
7143
  .ss-w-gxi-left { margin-left: auto; flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 11%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 22%, var(--ss-w-line)); border-radius: 999px; padding: 4px 10px; white-space: nowrap; }
7142
- /* Pitch: a flag per slot laid out in formation rows on a green field */
7143
- .ss-w-gxi-pitch { display: flex; flex-direction: column; justify-content: space-between; gap: 10px; padding: 16px 10px; border-radius: 14px; border: 1px solid color-mix(in srgb, var(--ss-w-correct) 22%, var(--ss-w-line)); background: linear-gradient(180deg, color-mix(in srgb, var(--ss-w-correct) 10%, var(--ss-w-panel)), color-mix(in srgb, var(--ss-w-correct) 4%, var(--ss-w-panel))); }
7144
- .ss-w-gxi-prow { display: flex; justify-content: space-around; align-items: center; gap: 8px; }
7145
- .ss-w-gxi-flag { width: 34px; height: 34px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 19px; line-height: 1; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); box-shadow: 0 1px 3px rgba(0,0,0,.14); overflow: hidden; }
7144
+ /* Pitch: a flag per slot laid out in formation rows on a green field. A real min-height plus
7145
+ space-between distributes the formation lines top\u2192bottom like a pitch (GK at the back, forwards
7146
+ forward); yard-line stripes reinforce the read. Without a height the lines collapse together. */
7147
+ /* A football pitch is grass-green regardless of the operator accent, so the field uses fixed
7148
+ green values (not --ss-w-correct, which is a muted per-operator token that vanished on dark
7149
+ themes) plus visible horizontal yard-lines and a brighter halfway line. */
7150
+ .ss-w-gxi-pitch { position: relative; display: flex; flex-direction: column; justify-content: space-between; gap: 8px; min-height: 300px; padding: 18px 10px; border-radius: 14px; border: 1px solid rgba(46, 160, 86, .38);
7151
+ background:
7152
+ linear-gradient(180deg, rgba(46, 160, 86, .015) 0, rgba(46, 160, 86, .015) 49.5%, rgba(255,255,255,.14) 49.5%, rgba(255,255,255,.14) 50.5%, rgba(46, 160, 86, .015) 50.5%),
7153
+ repeating-linear-gradient(180deg, transparent 0 31px, rgba(255,255,255,.045) 31px 32px),
7154
+ linear-gradient(180deg, rgba(46, 160, 86, .28), rgba(38, 132, 71, .16)); }
7155
+ .ss-w-gxi-prow { display: flex; justify-content: center; align-items: center; gap: 12px; }
7156
+ .ss-w-gxi-flag { width: 32px; height: 32px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 17px; line-height: 1; background: rgba(9, 12, 10, .55); border: 1px solid rgba(255,255,255,.16); box-shadow: 0 1px 3px rgba(0,0,0,.3); overflow: hidden; }
7146
7157
  /* Wrong-guess trail */
7147
7158
  .ss-w-gxi-wrong { display: flex; flex-wrap: wrap; gap: 6px; }
7148
7159
  .ss-w-gxi-wrong-pill { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; background: color-mix(in srgb, var(--ss-w-wrong) 10%, var(--ss-w-panel)); border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); text-decoration: line-through; }