@sensiblestats/widget-react 0.29.1 → 0.29.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -839,7 +839,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
839
839
  }
840
840
 
841
841
  // src/components/ChatPanel.tsx
842
- import { useEffect as useEffect7, useState as useState11 } from "react";
842
+ import { useEffect as useEffect7, useState as useState12 } from "react";
843
843
 
844
844
  // src/components/ChatHeader.tsx
845
845
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -1654,21 +1654,60 @@ function LinksCard({ card }) {
1654
1654
  }
1655
1655
 
1656
1656
  // src/components/dashboard/PostMatchResultCard.tsx
1657
+ import { useState as useState7 } from "react";
1657
1658
  import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
1659
+ function initials3(name) {
1660
+ return name.trim().slice(0, 3).toUpperCase();
1661
+ }
1662
+ function PostMatchCrest({
1663
+ url,
1664
+ name,
1665
+ side
1666
+ }) {
1667
+ const [failed, setFailed] = useState7(false);
1668
+ const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`;
1669
+ if (url && !failed) {
1670
+ return /* @__PURE__ */ jsx25("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1671
+ }
1672
+ return /* @__PURE__ */ jsx25("span", { className: `${cls} ss-w-fandash-postmatch-crest--fallback`, "aria-hidden": "true", children: initials3(name) });
1673
+ }
1658
1674
  function PostMatchResultCard({ card }) {
1659
1675
  const { data } = card;
1676
+ const homeWon = data.homeScore >= data.awayScore;
1677
+ const awayWon = data.awayScore >= data.homeScore;
1660
1678
  return /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-card ss-w-fandash-postmatch-result", children: [
1661
- card.title ? /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1662
- /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-scoreboard", children: [
1663
- /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-team", children: data.homeName }),
1664
- /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-score", children: data.homeScore }),
1665
- /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-sep", children: "\u2013" }),
1666
- /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-score", children: data.awayScore }),
1667
- /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-team ss-w-fandash-postmatch-team--away", children: data.awayName })
1679
+ /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-top", children: [
1680
+ card.title ? /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-pill", children: card.title }) : null,
1681
+ /* @__PURE__ */ jsx25("span", { className: `ss-w-fandash-postmatch-tag ss-w-fandash-postmatch-tag--${data.outcome}`, children: data.resultLabel })
1682
+ ] }),
1683
+ /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-main", children: [
1684
+ /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--home", children: [
1685
+ /* @__PURE__ */ jsx25(PostMatchCrest, { url: data.homeCrestUrl, name: data.homeName, side: "home" }),
1686
+ /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-team-name", children: data.homeName })
1687
+ ] }),
1688
+ /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-score-main", children: [
1689
+ /* @__PURE__ */ jsx25(
1690
+ "span",
1691
+ {
1692
+ className: `ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${homeWon ? "win" : "lose"}`,
1693
+ children: data.homeScore
1694
+ }
1695
+ ),
1696
+ /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-score-sep", children: "\u2013" }),
1697
+ /* @__PURE__ */ jsx25(
1698
+ "span",
1699
+ {
1700
+ className: `ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${awayWon ? "win" : "lose"}`,
1701
+ children: data.awayScore
1702
+ }
1703
+ )
1704
+ ] }),
1705
+ /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--away", children: [
1706
+ /* @__PURE__ */ jsx25(PostMatchCrest, { url: data.awayCrestUrl, name: data.awayName, side: "away" }),
1707
+ /* @__PURE__ */ jsx25("span", { className: "ss-w-fandash-postmatch-team-name", children: data.awayName })
1708
+ ] })
1668
1709
  ] }),
1669
1710
  /* @__PURE__ */ jsxs21("div", { className: "ss-w-fandash-postmatch-meta", children: [
1670
- data.resultLabel,
1671
- " \xB7 ",
1672
1711
  data.kickoffLabel,
1673
1712
  data.competition ? ` \xB7 ${data.competition}` : ""
1674
1713
  ] })
@@ -1680,34 +1719,75 @@ import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
1680
1719
  function PostMatchGoalsCard({ card, onTap }) {
1681
1720
  return /* @__PURE__ */ jsxs22("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-goals", onClick: () => onTap(card), children: [
1682
1721
  card.title ? /* @__PURE__ */ jsx26("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1683
- /* @__PURE__ */ jsx26("ul", { className: "ss-w-fandash-postmatch-goal-list", children: card.data.goals.map((g, i) => /* @__PURE__ */ jsx26("li", { className: g.scoredByClub ? "ss-w-fandash-postmatch-goal ss-w-fandash-postmatch-goal--club" : "ss-w-fandash-postmatch-goal", children: g.text }, `${g.text}-${i}`)) }),
1722
+ /* @__PURE__ */ jsx26("ul", { className: "ss-w-fandash-postmatch-goal-list", children: card.data.goals.map((g, i) => /* @__PURE__ */ jsxs22("li", { className: g.scoredByClub ? "ss-w-fandash-postmatch-goal ss-w-fandash-postmatch-goal--club" : "ss-w-fandash-postmatch-goal", children: [
1723
+ /* @__PURE__ */ jsx26("span", { className: "ss-w-fandash-postmatch-goal-ball" }),
1724
+ /* @__PURE__ */ jsx26("span", { children: g.text })
1725
+ ] }, `${g.text}-${i}`)) }),
1684
1726
  /* @__PURE__ */ jsx26("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1685
1727
  ] });
1686
1728
  }
1687
1729
 
1688
1730
  // src/components/dashboard/PostMatchStatsCard.tsx
1689
1731
  import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
1732
+ function splitWidths(homeNum, awayNum) {
1733
+ const total = homeNum + awayNum;
1734
+ if (total <= 0) return { home: "50%", away: "50%" };
1735
+ const homePct = Math.round(homeNum / total * 1e3) / 10;
1736
+ return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` };
1737
+ }
1690
1738
  function PostMatchStatsCard({ card, onTap }) {
1739
+ const { data } = card;
1691
1740
  return /* @__PURE__ */ jsxs23("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-stats", onClick: () => onTap(card), children: [
1692
1741
  card.title ? /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1693
- /* @__PURE__ */ jsx27("div", { className: "ss-w-fandash-postmatch-stat-rows", children: card.data.rows.map((r, i) => /* @__PURE__ */ jsxs23("div", { className: "ss-w-fandash-postmatch-stat-row", children: [
1694
- /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-value", children: r.clubValue }),
1695
- /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-label", children: r.label }),
1696
- /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-value", children: r.oppValue })
1697
- ] }, `${r.label}-${i}`)) }),
1742
+ /* @__PURE__ */ jsx27("div", { className: "ss-w-fandash-postmatch-stat-rows", children: data.rows.map((r, i) => {
1743
+ const leftValue = data.clubIsHome ? r.clubValue : r.oppValue;
1744
+ const rightValue = data.clubIsHome ? r.oppValue : r.clubValue;
1745
+ const homeNum = data.clubIsHome ? r.clubNum : r.oppNum;
1746
+ const awayNum = data.clubIsHome ? r.oppNum : r.clubNum;
1747
+ const { home, away } = splitWidths(homeNum, awayNum);
1748
+ return /* @__PURE__ */ jsxs23("div", { className: "ss-w-fandash-postmatch-stat", children: [
1749
+ /* @__PURE__ */ jsxs23("div", { className: "ss-w-fandash-postmatch-stat-row", children: [
1750
+ /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--home", children: leftValue }),
1751
+ /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-label", children: r.label }),
1752
+ /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--away", children: rightValue })
1753
+ ] }),
1754
+ /* @__PURE__ */ jsxs23("div", { className: "ss-w-fandash-postmatch-stat-bar", children: [
1755
+ /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-bar-home", style: { width: home } }),
1756
+ /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-postmatch-stat-bar-away", style: { width: away } })
1757
+ ] })
1758
+ ] }, `${r.label}-${i}`);
1759
+ }) }),
1760
+ data.rows.length > 0 ? /* @__PURE__ */ jsxs23("div", { className: "ss-w-fandash-postmatch-legend", children: [
1761
+ /* @__PURE__ */ jsxs23("span", { className: "ss-w-fandash-postmatch-legend-item", children: [
1762
+ /* @__PURE__ */ jsx27("i", { className: "ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--home" }),
1763
+ data.homeName
1764
+ ] }),
1765
+ /* @__PURE__ */ jsxs23("span", { className: "ss-w-fandash-postmatch-legend-item", children: [
1766
+ /* @__PURE__ */ jsx27("i", { className: "ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--away" }),
1767
+ data.awayName
1768
+ ] })
1769
+ ] }) : null,
1698
1770
  /* @__PURE__ */ jsx27("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1699
1771
  ] });
1700
1772
  }
1701
1773
 
1702
1774
  // src/components/dashboard/PostMatchTopPerformerCard.tsx
1703
1775
  import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
1776
+ function initials4(playerName) {
1777
+ const words = playerName.trim().split(/\s+/).filter(Boolean);
1778
+ if (words.length === 0) return "?";
1779
+ const first = words[0].charAt(0);
1780
+ const last = words[words.length - 1].charAt(0);
1781
+ return (words.length > 1 ? `${first}${last}` : first).toUpperCase();
1782
+ }
1704
1783
  function PostMatchTopPerformerCard({ card, onTap }) {
1705
1784
  const { data } = card;
1706
1785
  return /* @__PURE__ */ jsxs24("button", { type: "button", className: "ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-performer", onClick: () => onTap(card), children: [
1707
1786
  card.title ? /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-eyebrow", children: card.title }) : null,
1708
- /* @__PURE__ */ jsxs24("div", { className: "ss-w-fandash-postmatch-performer-row", children: [
1709
- /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-postmatch-performer-name", children: data.playerName }),
1710
- /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-postmatch-performer-rating", children: data.ratingLabel })
1787
+ /* @__PURE__ */ jsxs24("div", { className: "ss-w-fandash-postmatch-perf-row", children: [
1788
+ /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-postmatch-perf-avatar", "aria-hidden": "true", children: initials4(data.playerName) }),
1789
+ /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-postmatch-perf-name", children: data.playerName }),
1790
+ /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-postmatch-perf-rating", children: data.ratingLabel })
1711
1791
  ] }),
1712
1792
  /* @__PURE__ */ jsx28("span", { className: "ss-w-fandash-card-cta", children: card.actionLabel })
1713
1793
  ] });
@@ -1783,10 +1863,10 @@ function RestingFormCard({ card }) {
1783
1863
  }
1784
1864
 
1785
1865
  // src/components/dashboard/LiveScoreCard.tsx
1786
- import { useRef as useRef3, useState as useState8 } from "react";
1866
+ import { useRef as useRef3, useState as useState9 } from "react";
1787
1867
 
1788
1868
  // src/useLiveClock.ts
1789
- import { useEffect as useEffect5, useState as useState7 } from "react";
1869
+ import { useEffect as useEffect5, useState as useState8 } from "react";
1790
1870
  var TICK_MS = 6e4;
1791
1871
  var MAX_LIVE_TICK_MINUTES = 15;
1792
1872
  function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
@@ -1795,7 +1875,7 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
1795
1875
  return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
1796
1876
  }
1797
1877
  function useLiveClock(minute, clockRunning, receivedAtMs) {
1798
- const [displayMinute, setDisplayMinute] = useState7(
1878
+ const [displayMinute, setDisplayMinute] = useState8(
1799
1879
  () => computeDisplayMinute(minute, clockRunning, receivedAtMs)
1800
1880
  );
1801
1881
  useEffect5(() => {
@@ -1811,16 +1891,16 @@ function useLiveClock(minute, clockRunning, receivedAtMs) {
1811
1891
 
1812
1892
  // src/components/dashboard/LiveScoreCard.tsx
1813
1893
  import { jsx as jsx34, jsxs as jsxs30 } from "react/jsx-runtime";
1814
- function initials3(name) {
1894
+ function initials5(name) {
1815
1895
  return name.trim().slice(0, 3).toUpperCase();
1816
1896
  }
1817
1897
  function LiveCrest({ url, name, side }) {
1818
- const [failed, setFailed] = useState8(false);
1898
+ const [failed, setFailed] = useState9(false);
1819
1899
  const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`;
1820
1900
  if (url && !failed) {
1821
1901
  return /* @__PURE__ */ jsx34("img", { className: cls, src: url, alt: "", "aria-hidden": "true", onError: () => setFailed(true) });
1822
1902
  }
1823
- return /* @__PURE__ */ jsx34("span", { className: `${cls} ss-w-fandash-live-crest--fallback`, "aria-hidden": "true", children: initials3(name) });
1903
+ return /* @__PURE__ */ jsx34("span", { className: `${cls} ss-w-fandash-live-crest--fallback`, "aria-hidden": "true", children: initials5(name) });
1824
1904
  }
1825
1905
  function scorersLine(goalEvents) {
1826
1906
  if (!goalEvents || goalEvents.length === 0) return null;
@@ -1874,7 +1954,7 @@ function LiveScoreCard({
1874
1954
  }
1875
1955
 
1876
1956
  // src/components/dashboard/LiveTimelineCard.tsx
1877
- import { useState as useState9 } from "react";
1957
+ import { useState as useState10 } from "react";
1878
1958
  import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
1879
1959
  var SHOWN = 3;
1880
1960
  function EventIcon({ type }) {
@@ -1916,7 +1996,7 @@ function EventRow({ e }) {
1916
1996
  ] });
1917
1997
  }
1918
1998
  function LiveTimelineCard({ card, ui }) {
1919
- const [expanded, setExpanded] = useState9(false);
1999
+ const [expanded, setExpanded] = useState10(false);
1920
2000
  const events = card.data.events;
1921
2001
  if (!events || events.length === 0) return null;
1922
2002
  const sorted = [...events].sort((a, b) => b.minute - a.minute);
@@ -1997,7 +2077,7 @@ function MomentumWave({
1997
2077
 
1998
2078
  // src/components/dashboard/LiveStatsCard.tsx
1999
2079
  import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
2000
- function splitWidths(homeNum, awayNum) {
2080
+ function splitWidths2(homeNum, awayNum) {
2001
2081
  const total = homeNum + awayNum;
2002
2082
  if (total <= 0) return { home: "50%", away: "50%" };
2003
2083
  const homePct = Math.round(homeNum / total * 1e3) / 10;
@@ -2012,7 +2092,7 @@ function LiveStatsCard({ card }) {
2012
2092
  const awayValue = data.clubIsHome ? r.oppValue : r.clubValue;
2013
2093
  const homeNum = data.clubIsHome ? r.clubNum : r.oppNum;
2014
2094
  const awayNum = data.clubIsHome ? r.oppNum : r.clubNum;
2015
- const { home, away } = splitWidths(homeNum, awayNum);
2095
+ const { home, away } = splitWidths2(homeNum, awayNum);
2016
2096
  return /* @__PURE__ */ jsxs33("div", { className: "ss-w-fandash-live-stat", children: [
2017
2097
  /* @__PURE__ */ jsxs33("div", { className: "ss-w-fandash-live-stat-row", children: [
2018
2098
  /* @__PURE__ */ jsx37("span", { className: "ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--home", children: homeValue }),
@@ -2205,10 +2285,10 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
2205
2285
  }
2206
2286
 
2207
2287
  // src/components/ChatInput.tsx
2208
- import { useState as useState10 } from "react";
2288
+ import { useState as useState11 } from "react";
2209
2289
  import { jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
2210
2290
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
2211
- const [value, setValue] = useState10("");
2291
+ const [value, setValue] = useState11("");
2212
2292
  const submit = () => {
2213
2293
  const t = value.trim();
2214
2294
  if (!t) return;
@@ -2231,7 +2311,7 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
2231
2311
  import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
2232
2312
  var FULLSCREEN_QUERY = "(max-width: 639px)";
2233
2313
  function useIsModal() {
2234
- const [modal, setModal] = useState11(false);
2314
+ const [modal, setModal] = useState12(false);
2235
2315
  useEffect7(() => {
2236
2316
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
2237
2317
  const mql = window.matchMedia(FULLSCREEN_QUERY);
@@ -2735,35 +2815,76 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2735
2815
  .ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }
2736
2816
  .ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }
2737
2817
 
2738
- /* post-match result: full-time scoreboard -- team names flank the score, meta line underneath */
2739
- .ss-w-fandash-postmatch-scoreboard { display: flex; align-items: center; gap: 8px; }
2740
- .ss-w-fandash-postmatch-team { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }
2741
- .ss-w-fandash-postmatch-team--away { text-align: right; }
2742
- .ss-w-fandash-postmatch-score { flex: none; font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
2743
- .ss-w-fandash-postmatch-sep { flex: none; font-size: 14px; font-weight: 700; color: var(--ss-w-faint); }
2744
- .ss-w-fandash-postmatch-meta { font-size: 11.5px; color: var(--ss-w-faint); }
2745
-
2746
- /* post-match goals: a plain list, the club's own goals picked out in the accent color */
2747
- .ss-w-fandash-postmatch-goal-list { list-style: none; display: flex; flex-direction: column; gap: 4px; }
2748
- .ss-w-fandash-postmatch-goal { font-size: 12.5px; color: var(--ss-w-faint); }
2818
+ /* post-match result: full-time scoreboard, mirroring the live card's crest + big-score treatment.
2819
+ A neutral "Full time" pill sits left of a coloured Win/Draw/Loss tag; the 3-column main row
2820
+ (home crest+name | score | away crest+name, away reversed) puts the winner's score in full ink
2821
+ and the loser's dimmed; a centered meta line sits under a divider. */
2822
+ .ss-w-fandash-postmatch-top { display: flex; align-items: center; gap: 8px; margin-bottom: 15px; }
2823
+ .ss-w-fandash-postmatch-pill { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 6px; padding: 3px 8px; }
2824
+ .ss-w-fandash-postmatch-tag { margin-left: auto; flex: none; font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; }
2825
+ .ss-w-fandash-postmatch-tag--win { color: var(--ss-w-pos); }
2826
+ .ss-w-fandash-postmatch-tag--loss { color: var(--ss-w-neg); }
2827
+ .ss-w-fandash-postmatch-tag--draw { color: var(--ss-w-faint); }
2828
+ .ss-w-fandash-postmatch-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }
2829
+ .ss-w-fandash-postmatch-side { display: flex; align-items: center; gap: 10px; min-width: 0; }
2830
+ .ss-w-fandash-postmatch-side--away { flex-direction: row-reverse; text-align: right; }
2831
+ .ss-w-fandash-postmatch-crest { width: 38px; height: 38px; border-radius: 10px; flex: none; display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 12.5px; object-fit: cover; box-shadow: 0 2px 6px rgba(0, 0, 0, .18); }
2832
+ .ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--home { background: var(--ss-w-home); }
2833
+ .ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--away { background: var(--ss-w-away); }
2834
+ .ss-w-fandash-postmatch-team-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 700; line-height: 1.15; color: var(--ss-w-ink); }
2835
+ .ss-w-fandash-postmatch-score-main { display: flex; align-items: baseline; justify-content: center; font-size: 36px; font-weight: 850; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; }
2836
+ .ss-w-fandash-postmatch-score-value--win { color: var(--ss-w-ink); }
2837
+ .ss-w-fandash-postmatch-score-value--lose { color: var(--ss-w-faint); }
2838
+ .ss-w-fandash-postmatch-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 5px; }
2839
+ .ss-w-fandash-postmatch-meta { margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--ss-w-line); font-size: 12px; color: var(--ss-w-faint); text-align: center; }
2840
+
2841
+ /* post-match goals: a football-ball icon per goal (mirrors the live timeline ball, duplicated here
2842
+ under the postmatch prefix), text dimmed for opponent goals and picked out in full ink + bold
2843
+ for the club's own goals */
2844
+ .ss-w-fandash-postmatch-goal-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }
2845
+ .ss-w-fandash-postmatch-goal { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ss-w-faint); }
2846
+ .ss-w-fandash-postmatch-goal-ball { width: 11px; height: 11px; flex: none; border-radius: 50%; background: radial-gradient(circle at 50% 42%, #fff 0 34%, transparent 36%), var(--ss-w-ink); border: 1px solid var(--ss-w-ink); }
2749
2847
  .ss-w-fandash-postmatch-goal--club { color: var(--ss-w-ink); font-weight: 650; }
2750
2848
 
2751
- /* post-match stats: club value / stat label / opponent value, three columns per row */
2752
- .ss-w-fandash-postmatch-stat-rows { display: flex; flex-direction: column; gap: 5px; }
2753
- .ss-w-fandash-postmatch-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; }
2849
+ /* post-match stats: home value / stat label / away value, oriented by venue (u316), each row now
2850
+ backed by a home/away split bar -- the big upgrade from plain text -- plus a legend. Mirrors
2851
+ LiveStatsCard's split-bar treatment under the postmatch-prefixed classes; the shared
2852
+ --ss-w-home/--ss-w-away/--ss-w-track tokens are defined above. */
2853
+ .ss-w-fandash-postmatch-stat-rows { display: flex; flex-direction: column; gap: 15px; }
2854
+ .ss-w-fandash-postmatch-stat { display: flex; flex-direction: column; gap: 7px; }
2855
+ .ss-w-fandash-postmatch-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }
2754
2856
  .ss-w-fandash-postmatch-stat-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }
2755
- .ss-w-fandash-postmatch-stat-row .ss-w-fandash-postmatch-stat-value:last-child { text-align: right; }
2857
+ .ss-w-fandash-postmatch-stat-value--home { color: var(--ss-w-home); }
2858
+ .ss-w-fandash-postmatch-stat-value--away { color: var(--ss-w-away); text-align: right; }
2756
2859
  .ss-w-fandash-postmatch-stat-label { font-size: 10.5px; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }
2757
-
2758
- /* post-match top performer: player name left, rating pill right */
2759
- .ss-w-fandash-postmatch-performer-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2760
- .ss-w-fandash-postmatch-performer-name { font-size: 13px; font-weight: 650; overflow-wrap: anywhere; }
2761
- .ss-w-fandash-postmatch-performer-rating { flex: none; font-size: 12px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 2px 9px; }
2762
-
2763
- /* post-match next: the upcoming fixture teaser -- opponent left, when-label right */
2764
- .ss-w-fandash-postmatch-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2765
- .ss-w-fandash-postmatch-next-opponent { font-size: 13px; font-weight: 650; overflow-wrap: anywhere; }
2766
- .ss-w-fandash-postmatch-next-when { flex: none; font-size: 11.5px; color: var(--ss-w-faint); }
2860
+ .ss-w-fandash-postmatch-stat-bar { position: relative; height: 8px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }
2861
+ .ss-w-fandash-postmatch-stat-bar-home { height: 100%; background: var(--ss-w-home); }
2862
+ .ss-w-fandash-postmatch-stat-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }
2863
+ .ss-w-fandash-postmatch-legend { display: flex; gap: 14px; margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); font-size: 11px; color: var(--ss-w-faint); }
2864
+ .ss-w-fandash-postmatch-legend-item { display: inline-flex; align-items: center; gap: 6px; }
2865
+ .ss-w-fandash-postmatch-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
2866
+ .ss-w-fandash-postmatch-legend-swatch--home { background: var(--ss-w-home); }
2867
+ .ss-w-fandash-postmatch-legend-swatch--away { background: var(--ss-w-away); }
2868
+
2869
+ /* post-match top performer (full mockup treatment): gradient initials avatar + name + a
2870
+ prominent rating chip. Avatar gradient reuses the --ss-w-away token, same pairing as the live
2871
+ crest fallback; "?" renders through the same avatar span when the name is blank. */
2872
+ .ss-w-fandash-postmatch-perf-row { display: flex; align-items: center; gap: 12px; }
2873
+ .ss-w-fandash-postmatch-perf-avatar {
2874
+ flex: none; width: 42px; height: 42px; border-radius: 50%;
2875
+ display: grid; place-items: center;
2876
+ font-size: 14px; font-weight: 800; color: #fff;
2877
+ background: linear-gradient(135deg, var(--ss-w-away), color-mix(in srgb, var(--ss-w-away) 55%, #000));
2878
+ }
2879
+ .ss-w-fandash-postmatch-perf-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 700; }
2880
+ .ss-w-fandash-postmatch-perf-rating { margin-left: auto; flex: none; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border-radius: 999px; padding: 3px 11px; }
2881
+
2882
+ /* post-match next (v1, modest): whenLabel is already a complete localized phrase (opponent +
2883
+ venue + kickoff) composed server-side, so this card renders just that one line -- dressed up
2884
+ with an accent rule rather than a duplicated opponent line. The richer opponent-headline/venue-
2885
+ chip/crest layout from the mockup needs a server field split and is deferred. */
2886
+ .ss-w-fandash-postmatch-next-row { display: flex; align-items: center; gap: 10px; border-left: 3px solid var(--ss-w-accent); padding-left: 10px; }
2887
+ .ss-w-fandash-postmatch-next-when { font-size: 13.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.3; }
2767
2888
 
2768
2889
  /* resting next: the between-matches fixture teaser -- when-label left, competition badge right */
2769
2890
  .ss-w-fandash-resting-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }