@sensiblestats/widget-react 0.59.0 → 0.60.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 +12 -0
- package/dist/index.cjs +2622 -1542
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2600 -1520
- package/dist/index.js.map +1 -1
- package/dist/styles.css +422 -418
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/StatsWidget.tsx","../src/kickoff.ts","../src/i18n.ts","../src/config.ts","../src/slip.ts","../src/dashboardTap.ts","../src/theme.ts","../src/useChatStream.ts","../src/reducer.ts","../src/chart.ts","../src/model.ts","../src/useLiveDashboardPoll.ts","../src/conversationStore.ts","../src/useLiveMonitor.ts","../src/pinStore.ts","../src/useTabs.ts","../src/useMatchDiscovery.ts","../src/scheduleCache.ts","../src/dueSet.ts","../src/useGames.ts","../src/useLeaderboard.ts","../src/liveClock.ts","../src/eventLogContext.ts","../src/components/ChatFab.tsx","../src/components/BrandMark.tsx","../src/assets/logo.ts","../src/components/Icons.tsx","../src/components/GreetingBubble.tsx","../src/components/ChatPanel.tsx","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/Markdown.tsx","../src/components/EntityCardList.tsx","../src/components/BettingInsightList.tsx","../src/components/AddToSlipButton.tsx","../src/components/Toast.tsx","../src/components/OddsMovementBadge.tsx","../src/components/Crest.tsx","../src/components/PinToggle.tsx","../src/components/MarketOddsCardList.tsx","../src/components/OddsMovementCard.tsx","../src/components/ActionButtons.tsx","../src/components/dashboard/DashboardTile.tsx","../src/components/dashboard/GreetingDashboard.tsx","../src/components/dashboard/FixtureCard.tsx","../src/components/dashboard/CountdownCard.tsx","../src/components/dashboard/InjuriesCard.tsx","../src/components/dashboard/ReasonToBetCard.tsx","../src/components/dashboard/WhereToWatchCard.tsx","../src/components/dashboard/CongestedWeekCard.tsx","../src/components/dashboard/TransfersCard.tsx","../src/components/dashboard/LinksCard.tsx","../src/components/dashboard/PostMatchResultCard.tsx","../src/components/dashboard/PostMatchGoalsCard.tsx","../src/components/dashboard/PostMatchStatsCard.tsx","../src/components/dashboard/PostMatchTopPerformerCard.tsx","../src/components/dashboard/PostMatchNextCard.tsx","../src/components/dashboard/RestingNextCard.tsx","../src/components/dashboard/RestingStandingsCard.tsx","../src/components/dashboard/RestingSeasonCard.tsx","../src/components/dashboard/RestingFormCard.tsx","../src/components/dashboard/LiveScoreCard.tsx","../src/useLiveClock.ts","../src/components/dashboard/LiveTimelineCard.tsx","../src/components/dashboard/MomentumWave.tsx","../src/components/dashboard/LiveStatsCard.tsx","../src/components/dashboard/ClubFanDashboard.tsx","../src/components/ChatMessage.tsx","../src/components/IntentChips.tsx","../src/scroll.ts","../src/components/ChatInput.tsx","../src/components/TabBar.tsx","../src/components/MarketAccordion.tsx","../src/components/MonitorMatchCard.tsx","../src/components/MonitorTabs.tsx","../src/components/FixtureRow.tsx","../src/components/CompetitionGroup.tsx","../src/components/TodayPanel.tsx","../src/components/GamesPanel.tsx","../src/components/GamesLoginWall.tsx","../src/components/GameTile.tsx","../src/components/GamesHub.tsx","../src/components/GameScreenHost.tsx","../src/useGamePlay.ts","../src/components/games/MysteryTigerGame.tsx","../src/components/games/nationFlags.ts","../src/components/games/PlayerAvatar.tsx","../src/components/games/HigherOrLowerGame.tsx","../src/components/games/CareerPathGame.tsx","../src/components/games/BeatTheGridGame.tsx","../src/components/games/GuessTheXiGame.tsx","../src/components/games/DailyQuizGame.tsx","../src/components/games/MatchdayPredictorGame.tsx","../src/components/games/StartingXiGame.tsx","../src/components/games/StatLadderGame.tsx","../src/components/games/FanMotmGame.tsx","../src/components/Leaderboard.tsx","../src/components/LeaderboardRow.tsx","../src/components/LeaderboardEmpty.tsx","../src/components/LeaderboardPanel.tsx","../src/styles/css.generated.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'\nimport { StatsWidgetClient, type Conversation } from '@sensiblestats/widget-sdk'\nimport { normalizeUi, toClientOptions, toUserContext, type StatsWidgetConfig } from './config'\nimport { wasAdded, type SlipHandlerProps } from './slip'\nimport { createDashboardTapSignal } from './dashboardTap'\nimport { themeAttrs } from './theme'\nimport { useChatStream } from './useChatStream'\nimport { useLiveMonitor } from './useLiveMonitor'\nimport { useMatchDiscovery } from './useMatchDiscovery'\nimport { useGames } from './useGames'\nimport { useLeaderboard } from './useLeaderboard'\nimport { visibleGroupsOf } from './liveClock'\nimport { EventLogContext } from './eventLogContext'\nimport { ChatFab } from './components/ChatFab'\nimport { ChatPanel } from './components/ChatPanel'\nimport { WIDGET_CSS } from './styles/css.generated'\n\nexport type StatsWidgetProps =\n | { config: StatsWidgetConfig; client?: never }\n | { client: StatsWidgetClient; config?: Omit<StatsWidgetConfig, 'operatorId' | 'publicKey' | 'baseUrl' | 'userContext'> }\n\nfunction buildClient(props: StatsWidgetProps): { client: StatsWidgetClient; conversation: Conversation } | null {\n try {\n if ('client' in props && props.client) {\n return { client: props.client, conversation: props.client.conversation() }\n }\n const cfg = props.config as StatsWidgetConfig\n const client = new StatsWidgetClient(toClientOptions(cfg))\n return { client, conversation: client.conversation(toUserContext(cfg)) }\n } catch (err) {\n console.error('[StatsWidget] failed to initialize:', err instanceof Error ? err.message : err)\n return null\n }\n}\n\nfunction injectStyles(root: Document | ShadowRoot): void {\n const host: ParentNode = root instanceof ShadowRoot ? root : root.head\n if (host.querySelector('#ss-w-styles')) return\n const el = document.createElement('style')\n el.id = 'ss-w-styles'\n el.textContent = WIDGET_CSS\n host.appendChild(el)\n}\n\nexport function StatsWidget(props: StatsWidgetProps): JSX.Element | null {\n const injectedClient = 'client' in props ? props.client : undefined\n const cfg = props.config as Partial<StatsWidgetConfig> | undefined\n const built = useMemo(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl])\n // One logger per mount, keyed on the client identity (not on operatorUserId/anonymousUserId/\n // conversationId -- those change over the widget's lifetime and are pushed in via setIdentity\n // below, not by tearing down and recreating the logger).\n const logger = useMemo(\n () => (built ? built.client.createEventLogger({\n operatorUserId: cfg?.userContext?.operatorUserId,\n anonymousUserId: cfg?.userContext?.anonymousUserId,\n }) : null),\n [built?.client],\n )\n const ui = useMemo(() => normalizeUi((props.config ?? { operatorId: '', publicKey: '' }) as StatsWidgetConfig), [props.config])\n const rootRef = useRef<HTMLDivElement>(null)\n // One-shot launcher attention animation: the FAB nudges then the greeting\n // types in, exactly once per page load. The ref lives here (not in ChatFab,\n // which remounts every time the panel closes) so it never replays; a page\n // refresh remounts the widget and re-arms it.\n const introDoneRef = useRef(false)\n const markIntroDone = useCallback(() => { introDoneRef.current = true }, [])\n const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ''}:${cfg?.userContext?.operatorUserId ?? 'anon'}`\n const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : undefined, convStorageKey)\n // The two hooks are mutually dependent -- useMatchDiscovery needs monitor.pins, useLiveMonitor\n // needs to know whether Today has content -- so the cycle is broken with state rather than a\n // read of discovery's own render. It settles one render later, and unlike a ref it actually\n // re-renders, which is what lets the fallback effect fire when Today empties under the user.\n const [hasToday, setHasToday] = useState(false)\n const monitor = useLiveMonitor({\n getLiveMonitor: (pins) => (built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null)),\n getMarketOdds: (matchId, dev) => (built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null)),\n storageKey: `ss-w-pins:${cfg?.operatorId ?? ''}:${cfg?.userContext?.operatorUserId ?? 'anon'}`,\n isOpen: controller.state.isOpen,\n hasToday,\n })\n // Stable across renders (deps = [built], itself memoized on the client identity) -- the real\n // call site useMatchDiscovery.test.tsx's interval-churn test protects: a freshly-constructed\n // arrow here would defeat that guarantee even with the hook's own getStatesRef defense.\n const getSchedule = useCallback(\n (localDate: string, utcOffsetMinutes: number) =>\n built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),\n [built],\n )\n const getStates = useCallback(\n (matchIds: number[]) => (built ? built.conversation.getStates(matchIds) : Promise.resolve(null)),\n [built],\n )\n const pinnedMatchIds = useMemo(\n () => monitor.pins.filter((p) => p.kind === 'match').map((p) => p.matchId),\n [monitor.pins],\n )\n const discovery = useMatchDiscovery({\n getSchedule,\n getStates,\n operatorId: cfg?.operatorId ?? '',\n isOpen: controller.state.isOpen,\n pinnedMatchIds,\n })\n const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0\n useEffect(() => { setHasToday(todayHasContent) }, [todayHasContent])\n\n const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab })\n const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab })\n\n // The Today dot: the live count rising from zero is the \"something changed you have not seen\"\n // event for this tab. The hook suppresses it while Today is the active tab, exactly as the\n // other three dots are suppressed.\n const markTodayActivity = monitor.markTodayActivity\n const prevLiveCountRef = useRef(0)\n useEffect(() => {\n const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0\n prevLiveCountRef.current = discovery.liveCount\n if (rose) markTodayActivity()\n }, [discovery.liveCount, markTodayActivity])\n const slip = useMemo<SlipHandlerProps>(\n () => {\n const handler = props.config?.onAddToSlip\n return {\n // I3: the D5 persistent in-slip badge must arm from ANY add path -- a chat-message\n // insight/market card, not just the ones rendered inside the Odds tab itself -- so the\n // wasAdded->markInSlip wrap lives here (once), not duplicated per consumer.\n onAddToSlip: handler && (async (sel) => {\n const result = await handler(sel)\n if (wasAdded(result)) monitor.markInSlip(sel.matchOddsId)\n return result\n }),\n conversationId: controller.state.conversationId ?? undefined,\n onMarketClicked: (marketName) => {\n // sendSignal throws synchronously with no operatorUserId configured, and its\n // returned promise can reject on a gateway failure. Neither should ever break\n // the add-to-slip flow for a host that never wired signal tracking.\n try {\n void built?.conversation\n .sendSignal({ signalType: 'InsightMarketClicked', entityType: 'Market', entityName: marketName })\n .catch(() => undefined)\n } catch {\n // ignored — see comment above\n }\n },\n }\n },\n [props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip],\n )\n const onDashboardTap = useMemo(\n () => (built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : undefined),\n [built, logger],\n )\n\n const operatorUserId = cfg?.userContext?.operatorUserId\n const anonymousUserId = cfg?.userContext?.anonymousUserId\n const conversationId = controller.state.conversationId ?? undefined\n useEffect(() => {\n if (!logger) return\n logger.setIdentity({ operatorUserId, anonymousUserId, conversationId })\n }, [logger, operatorUserId, anonymousUserId, conversationId])\n\n useEffect(() => {\n if (!logger) return\n const onHide = (): void => { logger.flushOnHide() }\n const onVisibilityHide = (): void => {\n if (document.visibilityState === 'hidden') logger.flushOnHide()\n }\n window.addEventListener('pagehide', onHide)\n document.addEventListener('visibilitychange', onVisibilityHide)\n return () => {\n window.removeEventListener('pagehide', onHide)\n document.removeEventListener('visibilitychange', onVisibilityHide)\n // dispose() only clears the internal timer -- it does NOT flush queued events, so an\n // unflushed dispose on unmount silently drops whatever is still queued.\n logger.flushOnHide()\n logger.dispose()\n }\n }, [logger])\n\n useEffect(() => {\n if (!built || !ui.injectStyles) return\n const node = rootRef.current?.getRootNode()\n if (node) injectStyles(node as Document | ShadowRoot)\n }, [built, ui.injectStyles])\n\n if (!built) return null\n const attrs = themeAttrs(ui)\n return (\n <EventLogContext.Provider value={logger}>\n <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 as CSSProperties}>\n {controller.state.isOpen ? (\n <ChatPanel\n controller={controller}\n ui={ui}\n slip={slip}\n onDashboardTap={onDashboardTap}\n monitor={monitor.enabled ? monitor : undefined}\n discovery={discovery}\n gamesResult={gamesResult}\n leaderboardResult={leaderboardResult}\n loggedIn={!!operatorUserId}\n conversation={built?.conversation ?? null}\n />\n ) : (\n <ChatFab\n label={ui.launcherLabel}\n greeting={ui.greeting}\n popupText={controller.state.popupText}\n logoUrl={ui.logoUrl}\n onOpen={controller.open}\n onDismissPopup={controller.dismissPopup}\n dismissLabel={ui.dismissGreeting}\n introAllowed={!introDoneRef.current}\n onIntroStart={markIntroDone}\n />\n )}\n </div>\n </EventLogContext.Provider>\n )\n}\n\n// Hooks must run unconditionally; when the client failed to build we still need a Conversation-shaped stub for the hook.\nfunction emptyConversation(): Conversation {\n return { send: () => { throw new Error('widget not initialized') } } as unknown as Conversation\n}\n","export function formatBettingKickoff(\n kickoffUtc: string,\n ui: { today: string; tomorrow: string },\n locale: string,\n now: Date = new Date(),\n): { dayLabel: string; time: string } {\n const at = new Date(kickoffUtc)\n const intlLocale = locale === 'tr' ? 'tr-TR' : 'en-GB'\n const time = new Intl.DateTimeFormat(intlLocale, { hour: '2-digit', minute: '2-digit' }).format(at)\n const atLocalDate = new Date(at.getFullYear(), at.getMonth(), at.getDate())\n const nowLocalDate = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const dayDiff = Math.round((atLocalDate.getTime() - nowLocalDate.getTime()) / 86_400_000)\n const dayLabel =\n dayDiff === 0\n ? ui.today\n : dayDiff === 1\n ? ui.tomorrow\n : new Intl.DateTimeFormat(intlLocale, { weekday: 'short', day: 'numeric', month: 'short' }).format(at)\n return { dayLabel, time }\n}\n","import { formatBettingKickoff } from './kickoff'\n\nexport type Locale = 'en' | 'tr'\n\nexport interface LocaleStrings {\n launcherLabel: string\n placeholder: string\n closeChat: string\n newConversation: string\n moreOptions: string\n chatDialogLabel: string\n stopResponse: string\n sendMessage: string\n dismissGreeting: string\n somethingWentWrong: string\n retry: string\n showLess: string\n showMore: (n: number) => string\n showStats: string\n hideStats: string\n oddsLabel: string\n liveLabel: string\n marketFloorLabel: string\n addToSlip: string\n marketPrices: string\n moreLines: string\n hideLines: string\n oddsMoved: (was: string, now: string, direction: string) => string\n oddsShortened: string\n oddsDrifted: string\n updatedLabel: string\n priceMovement: string\n openingLabel: string\n currentLabel: string\n movementWindow: (hours: number) => string\n notEnoughHistory: string\n singlePricePoint: string\n selectionSuspended: string\n excludedSuspended: (n: number) => string\n chartTimeLabel: (ms: number) => string\n chartAria: (opening: string, current: string, direction: string, hours: number) => string\n inSlip: string\n slipAdded: string\n slipDuplicate: string\n slipPriceChanged: (from: string, to: string) => string\n slipPriceNotAccepted: (from: string, to: string) => string\n slipLoginRequired: string\n slipSuspended: string\n slipFailed: string\n today: string\n tomorrow: string\n bettingKickoff: (kickoffUtc: string, now?: Date) => { dayLabel: string; time: string }\n tabChat: string\n tabFollowing: string\n tabOdds: string\n tabToday: string\n sectionLive: string\n /** Short scoreboard badge for the fixture row's time column. The long-form phase name\n * for the monitor card is fullTimeLabel. */\n halfTime: string\n staleStates: string\n pinLabel: string\n unpinLabel: string\n matchPinLabel: string\n matchUnpinLabel: string\n matchLimitToast: string\n marketLimitToast: string\n emptyMatchesTab: string\n emptyOddsTab: string\n asOf: (time: string) => string\n graceNote: string\n suspendedLabel: string\n fullTimeLabel: string\n ownGoalLabel: string\n inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: string\n tabGames: string\n tabLeaderboard: string\n gamesLoginRequired: string\n back: string\n leaderboardOffBoard: string\n leaderboardThisWeek: string\n leaderboardAllTime: string\n leaderboardEmptyFreshTitle: string\n leaderboardEmptyFreshBody: string\n leaderboardEmptyColdTitle: string\n leaderboardEmptyColdBody: string\n leaderboardEmptyCta: string\n leaderboardLastWeekLabel: string\n leaderboardAllTimeEmpty: string\n gamePlay: string\n gameResume: string\n gameLocked: string\n gameVoided: string\n}\n\nconst STRINGS: Record<Locale, LocaleStrings> = {\n en: {\n launcherLabel: 'Chat with SensibleStats',\n placeholder: 'Ask about a team, player or match…',\n closeChat: 'Close chat',\n newConversation: 'New conversation',\n moreOptions: 'More options',\n chatDialogLabel: 'SensibleStats chat',\n stopResponse: 'Stop response',\n sendMessage: 'Send message',\n dismissGreeting: 'Dismiss',\n somethingWentWrong: 'Something went wrong.',\n retry: 'Retry',\n showLess: 'Show less',\n showMore: (n) => `Show ${n} more`,\n showStats: 'Show stats',\n hideStats: 'Hide stats',\n oddsLabel: 'Odds',\n liveLabel: 'Live',\n marketFloorLabel: 'Market price · not a value pick',\n addToSlip: 'Add to slip',\n marketPrices: 'Market prices',\n moreLines: 'More lines',\n hideLines: 'Hide lines',\n oddsMoved: (was, now, direction) => `was ${was}, now ${now}, ${direction}`,\n oddsShortened: 'shortened',\n oddsDrifted: 'drifted',\n updatedLabel: 'updated',\n priceMovement: 'Price movement',\n openingLabel: 'Opening',\n currentLabel: 'Current',\n movementWindow: (hours) => (hours % 24 === 0 ? `Last ${hours / 24}d` : `Last ${hours}h`),\n notEnoughHistory: 'No price history recorded yet for this selection.',\n singlePricePoint: 'Only one price recorded so far for this selection.',\n selectionSuspended: 'This selection is not currently available to bet.',\n excludedSuspended: (n) => `${n} suspended price${n === 1 ? '' : 's'} excluded from this chart.`,\n chartTimeLabel: (ms) =>\n new Intl.DateTimeFormat('en-GB', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(ms)),\n chartAria: (opening, current, direction, hours) => {\n const span = hours % 24 === 0 ? `${hours / 24} day${hours / 24 === 1 ? '' : 's'}` : `${hours} hour${hours === 1 ? '' : 's'}`\n // A flat price has no direction word; appending an empty one leaves \", .\" for a screen reader.\n const drift = direction ? `, ${direction}` : ''\n return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`\n },\n inSlip: 'In slip',\n slipAdded: 'Added to slip',\n slipDuplicate: 'Already in your slip',\n slipPriceChanged: (from, to) => `Added at ${to} (was ${from})`,\n slipPriceNotAccepted: (from, to) => `Price moved to ${to} (was ${from}). Tap to add.`,\n slipLoginRequired: 'Sign in to add to your slip',\n slipSuspended: 'Market suspended',\n slipFailed: \"Couldn't add to slip. Try again.\",\n today: 'Today',\n tomorrow: 'Tomorrow',\n bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.en, 'en', now),\n tabChat: 'Chat',\n tabFollowing: 'Following',\n tabOdds: 'Odds',\n pinLabel: 'Track odds',\n unpinLabel: 'Stop tracking odds',\n matchPinLabel: 'Track match',\n matchUnpinLabel: 'Stop tracking match',\n matchLimitToast: 'Match limit reached — unpin one first',\n marketLimitToast: 'Odds limit reached — unpin one first',\n emptyMatchesTab: 'No pinned matches yet. Pin a match from the conversation to track it live.',\n emptyOddsTab: 'No pinned odds yet. Pin a market from the conversation to track it live.',\n asOf: (time) => `Prices as of ${time}`,\n graceNote: 'Unpins on next open · or in 4 h',\n suspendedLabel: 'Suspended',\n fullTimeLabel: 'Full time',\n ownGoalLabel: 'OG',\n inSlipLabel: 'In slip',\n oddsUnavailable: 'Odds unavailable right now',\n momentumLabel: 'Momentum',\n accordionValueLabel: 'Value',\n accordionRetry: \"Couldn't load odds — tap to retry\",\n accordionSuspended: 'Suspended',\n tabToday: 'Today',\n sectionLive: 'Live',\n halfTime: 'HT',\n staleStates: \"Live scores can't be updated — showing the last known state.\",\n tabGames: 'Games',\n tabLeaderboard: 'Leaderboard',\n gamesLoginRequired: 'Sign in to play and climb the leaderboard',\n back: 'Back',\n leaderboardOffBoard: 'Outside top 50',\n leaderboardThisWeek: 'This week',\n leaderboardAllTime: 'All time',\n leaderboardEmptyFreshTitle: 'New week, blank slate',\n leaderboardEmptyFreshBody: 'No scores yet. The first fan to play a game takes #1.',\n leaderboardEmptyColdTitle: 'Be the first up',\n leaderboardEmptyColdBody: \"Nobody's on the board yet. Play a game and you're #1.\",\n leaderboardEmptyCta: \"Play today's games\",\n leaderboardLastWeekLabel: 'Last week',\n leaderboardAllTimeEmpty: 'The all-time board fills as fans play — nothing here yet.',\n gamePlay: 'Play',\n gameResume: 'Resume',\n gameLocked: 'Locked',\n gameVoided: 'Voided',\n },\n tr: {\n launcherLabel: 'SensibleStats ile sohbet et',\n placeholder: 'Bir takım, oyuncu veya maç hakkında sor…',\n closeChat: 'Sohbeti kapat',\n newConversation: 'Yeni sohbet',\n moreOptions: 'Diğer seçenekler',\n chatDialogLabel: 'SensibleStats sohbet',\n stopResponse: 'Yanıtı durdur',\n sendMessage: 'Mesaj gönder',\n dismissGreeting: 'Kapat',\n somethingWentWrong: 'Bir şeyler ters gitti.',\n retry: 'Tekrar dene',\n showLess: 'Daha az göster',\n showMore: (n) => `${n} tane daha göster`,\n showStats: 'İstatistikleri göster',\n hideStats: 'İstatistikleri gizle',\n oddsLabel: 'Oran',\n liveLabel: 'Canlı',\n marketFloorLabel: 'Piyasa oranı · değer bahsi değil',\n addToSlip: 'Kupona ekle',\n marketPrices: 'Piyasa fiyatları',\n moreLines: 'Diğer çizgiler',\n hideLines: 'Çizgileri gizle',\n oddsMoved: (was, now, direction) => `önce ${was}, şimdi ${now}, ${direction}`,\n oddsShortened: 'düştü',\n oddsDrifted: 'yükseldi',\n updatedLabel: 'güncellendi',\n priceMovement: 'Oran hareketi',\n openingLabel: 'Açılış',\n currentLabel: 'Güncel',\n movementWindow: (hours) => (hours % 24 === 0 ? `Son ${hours / 24} gün` : `Son ${hours} saat`),\n notEnoughHistory: 'Bu seçim için henüz oran geçmişi kaydedilmedi.',\n singlePricePoint: 'Bu seçim için şimdiye kadar yalnızca bir fiyat kaydedildi.',\n selectionSuspended: 'Bu seçim şu anda bahse kapalı.',\n excludedSuspended: (n) => `${n} askıya alınmış fiyat bu grafikten hariç tutuldu.`,\n chartTimeLabel: (ms) =>\n new Intl.DateTimeFormat('tr-TR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(ms)),\n chartAria: (opening, current, direction, hours) => {\n const span = hours % 24 === 0 ? `${hours / 24} gün` : `${hours} saat`\n const drift = direction ? `, ${direction}` : ''\n return `Son ${span} içindeki oran hareketi: ${opening} ile açıldı, şu anda ${current}${drift}.`\n },\n inSlip: 'Kuponda',\n slipAdded: 'Kupona eklendi',\n slipDuplicate: 'Bu seçim kuponunuzda zaten var',\n slipPriceChanged: (from, to) => `${to} oranıyla eklendi (önceki ${from})`,\n slipPriceNotAccepted: (from, to) => `Oran ${to} oldu (önceki ${from}). Eklemek için dokunun.`,\n slipLoginRequired: 'Kupona eklemek için giriş yapın',\n slipSuspended: 'Bu market askıya alındı',\n slipFailed: 'Kupona eklenemedi. Tekrar deneyin.',\n today: 'Bugün',\n tomorrow: 'Yarın',\n bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.tr, 'tr', now),\n tabChat: 'Sohbet',\n tabFollowing: 'Takip',\n tabOdds: 'Oranlar',\n pinLabel: 'Oranı takip et',\n unpinLabel: 'Oran takibini bırak',\n matchPinLabel: 'Maçı takip et',\n matchUnpinLabel: 'Maç takibini bırak',\n matchLimitToast: 'Maç limiti dolu — önce bir maçı kaldır',\n marketLimitToast: 'Oran limiti dolu — önce birini kaldır',\n emptyMatchesTab: 'Henüz sabitlenmiş maç yok. Canlı takip için sohbetteki bir maçı sabitle.',\n emptyOddsTab: 'Henüz sabitlenmiş oran yok. Canlı takip için sohbetteki bir marketi sabitle.',\n asOf: (time) => `Fiyatlar ${time} itibarıyla`,\n graceNote: 'Bir sonraki açılışta kaldırılır · en geç 4 saat',\n suspendedLabel: 'Askıda',\n fullTimeLabel: 'Maç sonu',\n ownGoalLabel: 'KK',\n inSlipLabel: 'Kuponda',\n oddsUnavailable: 'Oranlar şu anda kullanılamıyor',\n momentumLabel: 'Momentum',\n accordionValueLabel: 'Değer',\n accordionRetry: 'Oranlar yüklenemedi — yeniden dene',\n accordionSuspended: 'Askıda',\n tabToday: 'Bugün',\n sectionLive: 'Canlı',\n halfTime: 'İY',\n staleStates: 'Canlı skorlar güncellenemiyor — son bilinen durum gösteriliyor.',\n tabGames: 'Oyunlar',\n tabLeaderboard: 'Lider Tablosu',\n gamesLoginRequired: 'Oynamak ve lider tablosuna girmek için giriş yapın',\n back: 'Geri',\n leaderboardOffBoard: 'İlk 50 dışında',\n leaderboardThisWeek: 'Bu hafta',\n leaderboardAllTime: 'Tüm zamanlar',\n leaderboardEmptyFreshTitle: 'Yeni hafta, temiz sayfa',\n leaderboardEmptyFreshBody: 'Henüz skor yok. Oynayan ilk taraftar 1. sıraya geçer.',\n leaderboardEmptyColdTitle: 'İlk sen ol',\n leaderboardEmptyColdBody: 'Panoda henüz kimse yok. Bir oyun oyna, 1. sıra senin.',\n leaderboardEmptyCta: 'Bugünün oyunlarını oyna',\n leaderboardLastWeekLabel: 'Geçen hafta',\n leaderboardAllTimeEmpty: 'Tüm zamanlar panosu taraftarlar oynadıkça dolar — henüz bir şey yok.',\n gamePlay: 'Oyna',\n gameResume: 'Devam et',\n gameLocked: 'Kilitli',\n gameVoided: 'İptal edildi',\n },\n}\n\nexport function resolveLocaleStrings(locale?: string): LocaleStrings {\n return STRINGS[locale as Locale] ?? STRINGS.en\n}\n","import type { AddToSlipHandler, StatsWidgetClientOptions, UserContext } from '@sensiblestats/widget-sdk'\nimport { resolveLocaleStrings } from './i18n'\n\nexport interface StatsWidgetConfig {\n operatorId: string\n publicKey: string\n baseUrl?: string\n userContext?: UserContext\n theme?: 'light' | 'dark' | 'auto'\n accent?: string\n position?: 'left' | 'right'\n offset?: { x?: number; y?: number }\n radius?: number\n /** BCP-47-ish locale code for the widget's own chrome text (e.g. \"en\", \"tr\"). Defaults to \"en\". */\n locale?: string\n launcherLabel?: string\n greeting?: string\n /** Message auto-sent once on load (e.g. \"hello\"); its response shows as the launcher popup. */\n greetingMessage?: string\n placeholder?: string\n starters?: string[]\n injectStyles?: boolean\n /** Called when the user adds an insight's selection to the operator's slip. */\n onAddToSlip?: AddToSlipHandler\n\n // — Branding —\n /** Operator logo; replaces the SS mark in the header and the FAB launcher. */\n logoUrl?: string\n /** Header title text. Default \"SensibleStats\". */\n headerTitle?: string\n /** CTA color → --ss-w-cta. */\n cta?: string\n /** Panel/surface color → --ss-w-panel. Pair with `ink`. */\n surface?: string\n /** Primary text color → --ss-w-ink. Pair with `surface`. */\n ink?: string\n /** Icon used for the pin/save toggle on matches and odds. Default \"pin\". */\n pinIcon?: 'pin' | 'star' | 'bookmark'\n}\n\ntype UiKeys =\n | 'theme' | 'accent' | 'position' | 'offset' | 'radius' | 'locale'\n | 'launcherLabel' | 'greeting' | 'greetingMessage' | 'placeholder' | 'starters' | 'injectStyles'\n | 'logoUrl' | 'headerTitle' | 'cta' | 'surface' | 'ink' | 'pinIcon'\n\nexport interface UiConfig {\n theme: 'light' | 'dark' | 'auto'\n accent?: string\n position: 'left' | 'right'\n offset: { x: number; y: number }\n radius: number\n launcherLabel: string\n greeting?: string\n greetingMessage?: string\n placeholder: string\n starters: string[]\n injectStyles: boolean\n logoUrl?: string\n headerTitle?: string\n cta?: string\n surface?: string\n ink?: string\n pinIcon: 'pin' | 'star' | 'bookmark'\n closeChat: string\n newConversation: string\n moreOptions: string\n chatDialogLabel: string\n stopResponse: string\n sendMessage: string\n dismissGreeting: string\n somethingWentWrong: string\n retry: string\n showLess: string\n showMore: (n: number) => string\n showStats: string\n hideStats: string\n oddsLabel: string\n liveLabel: string\n marketFloorLabel: string\n marketPrices: string\n moreLines: string\n hideLines: string\n oddsMoved: (was: string, now: string, direction: string) => string\n oddsShortened: string\n oddsDrifted: string\n updatedLabel: string\n priceMovement: string\n openingLabel: string\n currentLabel: string\n movementWindow: (hours: number) => string\n notEnoughHistory: string\n singlePricePoint: string\n selectionSuspended: string\n excludedSuspended: (n: number) => string\n chartTimeLabel: (ms: number) => string\n chartAria: (opening: string, current: string, direction: string, hours: number) => string\n addToSlip: string\n inSlip: string\n slipAdded: string\n slipDuplicate: string\n slipPriceChanged: (from: string, to: string) => string\n slipPriceNotAccepted: (from: string, to: string) => string\n slipLoginRequired: string\n slipSuspended: string\n slipFailed: string\n today: string\n tomorrow: string\n bettingKickoff: (kickoffUtc: string, now?: Date) => { dayLabel: string; time: string }\n tabChat: string\n tabFollowing: string\n tabOdds: string\n tabToday: string\n sectionLive: string\n halfTime: string\n staleStates: string\n pinLabel: string\n unpinLabel: string\n matchPinLabel: string\n matchUnpinLabel: string\n matchLimitToast: string\n marketLimitToast: string\n emptyMatchesTab: string\n emptyOddsTab: string\n asOf: (time: string) => string\n graceNote: string\n suspendedLabel: string\n fullTimeLabel: string\n ownGoalLabel: string\n inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: string\n tabGames: string\n tabLeaderboard: string\n gamesLoginRequired: string\n back: string\n leaderboardOffBoard: string\n leaderboardThisWeek: string\n leaderboardAllTime: string\n leaderboardEmptyFreshTitle: string\n leaderboardEmptyFreshBody: string\n leaderboardEmptyColdTitle: string\n leaderboardEmptyColdBody: string\n leaderboardEmptyCta: string\n leaderboardLastWeekLabel: string\n leaderboardAllTimeEmpty: string\n gamePlay: string\n gameResume: string\n gameLocked: string\n gameVoided: string\n}\n\nexport function normalizeUi(cfg: Pick<StatsWidgetConfig, UiKeys>): UiConfig {\n const strings = resolveLocaleStrings(cfg.locale)\n return {\n theme: cfg.theme ?? 'auto',\n accent: cfg.accent,\n logoUrl: cfg.logoUrl,\n headerTitle: cfg.headerTitle,\n cta: cfg.cta,\n surface: cfg.surface,\n ink: cfg.ink,\n pinIcon: cfg.pinIcon ?? 'pin',\n position: cfg.position ?? 'right',\n offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },\n radius: cfg.radius ?? 16,\n launcherLabel: cfg.launcherLabel ?? strings.launcherLabel,\n greeting: cfg.greeting,\n greetingMessage: cfg.greetingMessage,\n placeholder: cfg.placeholder ?? strings.placeholder,\n starters: cfg.starters ?? [],\n injectStyles: cfg.injectStyles ?? true,\n closeChat: strings.closeChat,\n newConversation: strings.newConversation,\n moreOptions: strings.moreOptions,\n chatDialogLabel: strings.chatDialogLabel,\n stopResponse: strings.stopResponse,\n sendMessage: strings.sendMessage,\n dismissGreeting: strings.dismissGreeting,\n somethingWentWrong: strings.somethingWentWrong,\n retry: strings.retry,\n showLess: strings.showLess,\n showMore: strings.showMore,\n showStats: strings.showStats,\n hideStats: strings.hideStats,\n oddsLabel: strings.oddsLabel,\n liveLabel: strings.liveLabel,\n marketFloorLabel: strings.marketFloorLabel,\n marketPrices: strings.marketPrices,\n moreLines: strings.moreLines,\n hideLines: strings.hideLines,\n oddsMoved: strings.oddsMoved,\n oddsShortened: strings.oddsShortened,\n oddsDrifted: strings.oddsDrifted,\n updatedLabel: strings.updatedLabel,\n priceMovement: strings.priceMovement,\n openingLabel: strings.openingLabel,\n currentLabel: strings.currentLabel,\n movementWindow: strings.movementWindow,\n notEnoughHistory: strings.notEnoughHistory,\n singlePricePoint: strings.singlePricePoint,\n selectionSuspended: strings.selectionSuspended,\n excludedSuspended: strings.excludedSuspended,\n chartTimeLabel: strings.chartTimeLabel,\n chartAria: strings.chartAria,\n addToSlip: strings.addToSlip,\n inSlip: strings.inSlip,\n slipAdded: strings.slipAdded,\n slipDuplicate: strings.slipDuplicate,\n slipPriceChanged: strings.slipPriceChanged,\n slipPriceNotAccepted: strings.slipPriceNotAccepted,\n slipLoginRequired: strings.slipLoginRequired,\n slipSuspended: strings.slipSuspended,\n slipFailed: strings.slipFailed,\n today: strings.today,\n tomorrow: strings.tomorrow,\n bettingKickoff: strings.bettingKickoff,\n tabChat: strings.tabChat,\n tabFollowing: strings.tabFollowing,\n tabOdds: strings.tabOdds,\n tabToday: strings.tabToday,\n sectionLive: strings.sectionLive,\n halfTime: strings.halfTime,\n staleStates: strings.staleStates,\n pinLabel: strings.pinLabel,\n unpinLabel: strings.unpinLabel,\n matchPinLabel: strings.matchPinLabel,\n matchUnpinLabel: strings.matchUnpinLabel,\n matchLimitToast: strings.matchLimitToast,\n marketLimitToast: strings.marketLimitToast,\n emptyMatchesTab: strings.emptyMatchesTab,\n emptyOddsTab: strings.emptyOddsTab,\n asOf: strings.asOf,\n graceNote: strings.graceNote,\n suspendedLabel: strings.suspendedLabel,\n fullTimeLabel: strings.fullTimeLabel,\n ownGoalLabel: strings.ownGoalLabel,\n inSlipLabel: strings.inSlipLabel,\n oddsUnavailable: strings.oddsUnavailable,\n momentumLabel: strings.momentumLabel,\n accordionValueLabel: strings.accordionValueLabel,\n accordionRetry: strings.accordionRetry,\n accordionSuspended: strings.accordionSuspended,\n tabGames: strings.tabGames,\n tabLeaderboard: strings.tabLeaderboard,\n gamesLoginRequired: strings.gamesLoginRequired,\n back: strings.back,\n leaderboardOffBoard: strings.leaderboardOffBoard,\n leaderboardThisWeek: strings.leaderboardThisWeek,\n leaderboardAllTime: strings.leaderboardAllTime,\n leaderboardEmptyFreshTitle: strings.leaderboardEmptyFreshTitle,\n leaderboardEmptyFreshBody: strings.leaderboardEmptyFreshBody,\n leaderboardEmptyColdTitle: strings.leaderboardEmptyColdTitle,\n leaderboardEmptyColdBody: strings.leaderboardEmptyColdBody,\n leaderboardEmptyCta: strings.leaderboardEmptyCta,\n leaderboardLastWeekLabel: strings.leaderboardLastWeekLabel,\n leaderboardAllTimeEmpty: strings.leaderboardAllTimeEmpty,\n gamePlay: strings.gamePlay,\n gameResume: strings.gameResume,\n gameLocked: strings.gameLocked,\n gameVoided: strings.gameVoided,\n }\n}\n\nexport function toClientOptions(cfg: StatsWidgetConfig): StatsWidgetClientOptions {\n const opts: StatsWidgetClientOptions = { operatorId: cfg.operatorId, publicKey: cfg.publicKey }\n if (cfg.baseUrl !== undefined) opts.baseUrl = cfg.baseUrl\n return opts\n}\n\nexport function toUserContext(cfg: StatsWidgetConfig): UserContext | undefined {\n return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : undefined\n}\n","import type { AddToSlipHandler, AddToSlipResult } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from './config'\n\nexport const ADD_TO_SLIP_TIMEOUT_MS = 10_000\n\nexport interface SlipToast { kind: 'success' | 'error'; text: string }\n\nexport interface SlipHandlerProps {\n onAddToSlip?: AddToSlipHandler\n conversationId?: string\n onMarketClicked?: (marketName: string) => void\n}\n\nexport function wasAdded(result: AddToSlipResult | void): boolean {\n if (!result) return true\n if (result.status === 'price_changed') return result.accepted\n return result.status === 'added'\n}\n\nexport function isTerminal(result: AddToSlipResult | void): boolean {\n if (!result) return true\n if (result.status === 'price_changed') return result.accepted\n return result.status === 'added' || result.status === 'duplicate'\n}\n\n// slip_result's `outcome`: 'added' on success (including the assumed-success void/duplicate/\n// accepted-price-change cases), else the specific reject reason string -- so a downstream\n// consumer can tell \"the user added it\" from \"why it was refused\" without re-deriving toast text.\nexport function slipOutcome(result: AddToSlipResult | void): string {\n if (!result) return 'added'\n switch (result.status) {\n case 'added':\n case 'duplicate':\n return result.status\n case 'price_changed':\n return result.accepted ? 'added' : 'price_changed'\n case 'rejected':\n return result.reason\n }\n}\n\nexport function resultToToast(result: AddToSlipResult | void, shownOdds: string, ui: UiConfig): SlipToast {\n if (!result) return { kind: 'success', text: ui.slipAdded }\n switch (result.status) {\n case 'added':\n return { kind: 'success', text: ui.slipAdded }\n case 'duplicate':\n return { kind: 'success', text: ui.slipDuplicate }\n case 'price_changed':\n return result.accepted\n ? { kind: 'success', text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) }\n : { kind: 'error', text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) }\n case 'rejected':\n if (result.reason === 'login_required') return { kind: 'error', text: ui.slipLoginRequired }\n if (result.reason === 'suspended') return { kind: 'error', text: ui.slipSuspended }\n return { kind: 'error', text: result.message ?? ui.slipFailed }\n }\n}\n","import { ENTITY_TYPE_CODES, type Conversation, type EventLogger, type GreetingDashboardLayout, type GreetingDashboardTile, type SignalEntityType, type WidgetEntityType } from '@sensiblestats/widget-sdk'\n\nexport type DashboardTapHandler = (tile: GreetingDashboardTile, index: number, layout: GreetingDashboardLayout) => void\n\n// tile.signal.entityType is a plain string on the wire (GreetingDashboardSignalRef), so a value\n// outside the union must be checked, not asserted -- an unchecked cast would let an unrecognised\n// value reach toSignalWireBody, which throws synchronously and is swallowed by the try/catch\n// below, silently dropping the tap the same way an unresolved entityId used to.\nfunction isSignalEntityType(value: string): value is SignalEntityType {\n return Object.prototype.hasOwnProperty.call(ENTITY_TYPE_CODES, value)\n}\n\n// The server's GreetingDashboardSignalRef.entityType is PascalCase ('Team', 'Market', ...) and\n// carries a couple of values (Article/Session/Query/Conversation) that have no widget-event\n// counterpart -- those, and anything unrecognised, map to null so the caller can skip the emit\n// instead of sending a bogus entityType.\nfunction toWidgetEntityType(value: string): WidgetEntityType | null {\n switch (value.toLowerCase()) {\n case 'match': return 'match'\n case 'team': return 'team'\n case 'player': return 'player'\n case 'competition': return 'competition'\n case 'market': return 'market'\n default: return null\n }\n}\n\n/**\n * Builds the tap-to-signal side effect for a greeting dashboard tile.\n * Every tap is a MarketView signal (spec 9.4) regardless of the tile's own entity type --\n * entityType/entityId identify what was tapped, dashboardLayout/tileIndex identify where.\n *\n * `log` is threaded in as a parameter (not read via `useEventLog()`) because this module is a\n * plain factory, not a component or hook -- the caller (a component) owns the logger instance.\n */\nexport function createDashboardTapSignal(sendSignal: Conversation['sendSignal'], log?: EventLogger | null): DashboardTapHandler {\n return (tile, index, layout) => {\n const widgetEntityType = toWidgetEntityType(tile.signal.entityType)\n if (widgetEntityType) {\n log?.log({ name: 'tile_tap', entityType: widgetEntityType, entityId: tile.signal.entityId })\n }\n if (!isSignalEntityType(tile.signal.entityType)) return\n // sendSignal throws synchronously with no identity configured, and its returned promise\n // can reject on a gateway failure. Neither may break the tap -- the message this tile sent\n // still has to reach the model even when the Interest Engine can't be reached.\n try {\n void sendSignal({\n signalType: 'MarketView',\n entityType: tile.signal.entityType,\n entityId: tile.signal.entityId,\n dashboardLayout: layout,\n tileIndex: index,\n }).catch(() => undefined)\n } catch {\n // ignored -- see comment above\n }\n }\n}\n","import type { UiConfig } from './config'\n\nexport interface ThemeAttrs {\n 'data-ss-w-theme': string\n 'data-ss-w-pos': string\n style: Record<string, string>\n}\n\nexport function themeAttrs(ui: UiConfig): ThemeAttrs {\n const style: Record<string, string> = {\n '--ss-w-offset-x': `${ui.offset.x}px`,\n '--ss-w-offset-y': `${ui.offset.y}px`,\n '--ss-w-radius': `${ui.radius}px`,\n }\n if (ui.accent) style['--ss-w-accent'] = ui.accent\n if (ui.cta) style['--ss-w-cta'] = ui.cta\n if (ui.surface) style['--ss-w-panel'] = ui.surface\n if (ui.ink) style['--ss-w-ink'] = ui.ink\n if (ui.surface && ui.ink) {\n style['--ss-w-bubble'] = 'color-mix(in srgb, var(--ss-w-ink) 5%, var(--ss-w-panel))'\n style['--ss-w-line'] = 'color-mix(in srgb, var(--ss-w-ink) 12%, var(--ss-w-panel))'\n style['--ss-w-faint'] = 'color-mix(in srgb, var(--ss-w-ink) 55%, var(--ss-w-panel))'\n }\n return { 'data-ss-w-theme': ui.theme, 'data-ss-w-pos': ui.position, style }\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport type { ChatHandle, ChatInput, Conversation } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { reducer, initialState, type WidgetState, type AssistantTurn } from './reducer'\nimport { chipFromText } from './model'\nimport { useLiveDashboardPoll } from './useLiveDashboardPoll'\nimport { readConversation, writeConversation, clearConversation } from './conversationStore'\n\n// An assistant turn counts as an answer only if it carries something to show. Deliberately\n// excludes `actions` -- follow-up chips are not answer content, so an errored turn that only\n// has fallback chips must not count as answered.\nfunction hasAnswerContent(t: AssistantTurn): boolean {\n return !!t.text || t.cards.length > 0 || t.insights.length > 0 ||\n t.marketOdds.length > 0 || t.oddsMovement.length > 0 ||\n !!t.greetingDashboard || !!t.clubFanDashboard\n}\n\n// If the server never emits a terminal event (turn_complete/error) within this window, the\n// panel would otherwise spin forever -- an async generator that just ends without yielding a\n// terminal event leaves isStreaming stuck at true, since only turn_complete/error/STOP clear it.\nexport const STREAM_FALLBACK_TIMEOUT_MS = 30_000\n\n// Next id must not collide with restored m{n} ids (React keys + live-dashboard id matching).\nfunction seedIdCounter(messages: { id: string }[]): number {\n let max = -1\n for (const m of messages) {\n const n = Number(m.id.slice(1)) // ids are `m${n}`\n if (m.id[0] === 'm' && Number.isFinite(n) && n > max) max = n\n }\n return max + 1\n}\n\nexport interface SendOptions {\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap) — forwarded on ChatInput.actionRef. */\n actionRef?: string\n /** Text shown in the user bubble when it differs from the message sent upstream (e.g. an action's label). */\n displayText?: string\n}\n\nexport interface ChatController {\n state: WidgetState\n open(): void\n close(): void\n stop(): void\n toggle(): void\n send(text: string, opts?: SendOptions): void\n retry(): void\n dismissPopup(): void\n reset(): void\n}\n\nexport function useChatStream(conversation: Conversation, starterTexts: string[], greetingMessage?: string, storageKey?: string): ChatController {\n const boot = useMemo(() => {\n const payload = storageKey ? readConversation(storageKey, Date.now()) : null\n const restored = payload != null && payload !== 'expired' && payload !== 'corrupt'\n const base = initialState(starterTexts.map(chipFromText))\n if (restored) {\n return { state: { ...base, messages: payload.messages, conversationId: payload.conversationId, starters: [] }, restored: true, stale: false }\n }\n return { state: base, restored: false, stale: payload === 'expired' || payload === 'corrupt' }\n }, [])\n const [state, dispatch] = useReducer(reducer, boot.state)\n const idRef = useRef(seedIdCounter(boot.state.messages))\n const handleRef = useRef<ChatHandle | null>(null)\n const fallbackTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const stateRef = useRef(state)\n stateRef.current = state\n const greetedRef = useRef(boot.restored) // restored -> greeting already \"handled\" (suppressed)\n const hydratedRef = useRef(false) // suppresses the single re-persist a cross-tab sync would echo\n\n const restoreSeededRef = useRef(false)\n if (!restoreSeededRef.current) {\n restoreSeededRef.current = true\n if (boot.restored && boot.state.conversationId) conversation.conversationId = boot.state.conversationId\n }\n\n const nextId = () => `m${idRef.current++}`\n\n const clearFallbackTimer = useCallback(() => {\n if (fallbackTimerRef.current != null) {\n clearTimeout(fallbackTimerRef.current)\n fallbackTimerRef.current = null\n }\n }, [])\n\n // Arms a watchdog for one in-flight send. clearFallbackTimer() is called on every path that\n // supersedes this send (a newer run(), stop(), close()) or that sees a terminal event, so a\n // firing timer always means neither happened in time -- including the case where the async\n // generator simply ends without ever yielding turn_complete/error: consume()'s own `finally`\n // nulls handleRef as soon as that happens, so this cannot key off handle identity (it would\n // already look \"stale\" and the very hang it exists to catch would go unreported).\n const armFallbackTimer = useCallback((onFire: () => void) => {\n clearFallbackTimer()\n fallbackTimerRef.current = setTimeout(() => {\n fallbackTimerRef.current = null\n handleRef.current?.cancel()\n handleRef.current = null\n onFire()\n }, STREAM_FALLBACK_TIMEOUT_MS)\n }, [clearFallbackTimer])\n\n const consume = useCallback((handle: ChatHandle, onError: (err: WidgetSdkError) => void) => {\n ;(async () => {\n try {\n for await (const event of handle) {\n dispatch({ kind: 'EVENT', event })\n if (event.type === 'turn_complete' || event.type === 'error') clearFallbackTimer()\n }\n } catch (err) {\n // A superseded handle's late rejection (run() already cancelled it and armed a new\n // timer for the newer send) must not touch the current send's timer -- only clear here\n // when this handle is still the one in flight.\n if (handleRef.current === handle) clearFallbackTimer()\n if (err instanceof WidgetSdkError) onError(err)\n else if ((err as { name?: string } | null)?.name === 'AbortError') { /* expected on cancel/close — ignore */ }\n else throw err\n } finally {\n if (handleRef.current === handle) handleRef.current = null\n }\n })()\n }, [clearFallbackTimer])\n\n const run = useCallback((input: ChatInput, displayText?: string) => {\n handleRef.current?.cancel()\n clearFallbackTimer()\n dispatch({ kind: 'USER_SENT', input, userId: nextId(), assistantId: nextId(), displayText })\n const handle = conversation.send(input)\n handleRef.current = handle\n armFallbackTimer(() => {\n dispatch({ kind: 'STOP' })\n dispatch({ kind: 'STREAM_ERROR', error: new WidgetSdkError('No response received in time', 'timeout') })\n })\n consume(handle, (err) => dispatch({ kind: 'STREAM_ERROR', error: err }))\n }, [conversation, consume, clearFallbackTimer, armFallbackTimer])\n\n const send = useCallback((text: string, opts?: SendOptions) => {\n const trimmed = text.trim()\n if (!trimmed) return\n run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText)\n }, [run])\n\n const retry = useCallback(() => {\n const last = stateRef.current.lastUserInput\n if (last) run(last, stateRef.current.lastDisplayText ?? undefined)\n }, [run])\n\n // Auto-greeting: fire once on mount when configured (and not restored from storage). No\n // user bubble; its response becomes the launcher popup. Fire-and-forget — failures\n // (including a fallback timeout) are swallowed (STOP only, no visible error) since this is\n // non-critical background chatter. Also reused by reset() to re-greet after clearing.\n const fireGreeting = useCallback(() => {\n const message = greetingMessage?.trim()\n if (!message) return\n try {\n handleRef.current?.cancel()\n clearFallbackTimer()\n dispatch({ kind: 'GREETING_SENT', assistantId: nextId() })\n const handle = conversation.send({ message })\n handleRef.current = handle\n armFallbackTimer(() => dispatch({ kind: 'STOP' }))\n consume(handle, () => dispatch({ kind: 'STOP' }))\n } catch {\n dispatch({ kind: 'STOP' })\n }\n }, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer])\n\n useEffect(() => {\n if (greetedRef.current) return // restored, or already greeted\n greetedRef.current = true\n fireGreeting()\n }, [fireGreeting])\n\n // Clear a stale/corrupt blob once, from an effect (never during the render seed).\n useEffect(() => {\n if (boot.stale && storageKey) clearConversation(storageKey)\n }, [])\n\n // Persist only complete exchanges after each settle (never mid-stream, never the greeting).\n // A user message is kept only when its paired assistant turn (USER_SENT always pushes\n // [user, assistant] together) is done, non-greeting, and has real content -- this drops a\n // trailing unanswered question (panel closed mid-stream) and an empty errored bubble alike.\n useEffect(() => {\n if (!storageKey || state.isStreaming) return\n if (hydratedRef.current) { hydratedRef.current = false; return } // don't echo a sync back out\n const msgs = state.messages\n const persistable = msgs.filter((m, i) => {\n if (m.role === 'user') {\n const next = msgs[i + 1]\n return !!next && next.role === 'assistant' && next.done && !next.isGreeting && hasAnswerContent(next)\n }\n return m.done && !m.isGreeting && hasAnswerContent(m)\n })\n if (persistable.length === 0) return\n writeConversation(storageKey, state.conversationId, persistable, Date.now())\n }, [storageKey, state.isStreaming, state.messages, state.conversationId])\n\n // Live multi-tab sync: mirror another tab's write/clear of the shared conversation.\n useEffect(() => {\n if (!storageKey) return\n const onStorage = (e: StorageEvent) => {\n if (e.key !== storageKey || e.storageArea !== window.localStorage) return\n if (stateRef.current.isStreaming) return // never clobber an in-flight turn in this tab\n if (e.newValue == null) {\n // cleared elsewhere (New conversation / expiry) -> mirror a fresh conversation\n idRef.current = 0\n conversation.conversationId = undefined\n hydratedRef.current = true\n dispatch({ kind: 'RESET' })\n greetedRef.current = true\n fireGreeting()\n return\n }\n const parsed = readConversation(storageKey, Date.now())\n if (!parsed || parsed === 'expired' || parsed === 'corrupt') return\n idRef.current = seedIdCounter(parsed.messages)\n conversation.conversationId = parsed.conversationId ?? undefined\n hydratedRef.current = true\n dispatch({ kind: 'RESTORE', messages: parsed.messages, conversationId: parsed.conversationId })\n }\n window.addEventListener('storage', onStorage)\n return () => window.removeEventListener('storage', onStorage)\n }, [storageKey, conversation, fireGreeting])\n\n const open = useCallback(() => dispatch({ kind: 'OPEN' }), [])\n const close = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer(); dispatch({ kind: 'CLOSE' }) }, [clearFallbackTimer])\n const stop = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer(); dispatch({ kind: 'STOP' }) }, [clearFallbackTimer])\n const toggle = useCallback(() => { if (stateRef.current.isOpen) close(); else open() }, [close, open])\n const dismissPopup = useCallback(() => dispatch({ kind: 'DISMISS_POPUP' }), [])\n\n const reset = useCallback(() => {\n handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer()\n if (storageKey) clearConversation(storageKey)\n idRef.current = 0\n conversation.conversationId = undefined\n dispatch({ kind: 'RESET' })\n greetedRef.current = true\n fireGreeting()\n }, [storageKey, conversation, clearFallbackTimer, fireGreeting])\n\n const getLiveDashboard = useCallback(() => conversation.getLiveDashboard(), [conversation])\n useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard })\n\n return { state, open, close, stop, toggle, send, retry, dismissPopup, reset }\n}\n","import type { ChatEvent, ChatInput, ClubFanDashboardCard, ClubFanDashboardPayload, GreetingDashboard, StreamErrorEventData } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { toActionVM, toCardVM, toChipVM, toInsightVM, toMarketOddsVM, toOddsMovementVM, type ActionVM, type CardVM, type ChipVM, type InsightVM, type MarketOddsVM, type OddsMovementVM } from './model'\n\nexport interface UserMessage { role: 'user'; id: string; text: string }\nexport interface AssistantTurn { role: 'assistant'; id: string; text: string; cards: CardVM[]; actions: ActionVM[]; insights: InsightVM[]; marketOdds: MarketOddsVM[]; oddsMovement: OddsMovementVM[]; done: boolean; isGreeting?: boolean; greetingDashboard?: GreetingDashboard; clubFanDashboard?: ClubFanDashboardPayload }\nexport type Message = UserMessage | AssistantTurn\n\nexport interface WidgetState {\n isOpen: boolean\n messages: Message[]\n isStreaming: boolean\n status: string | null\n actionsLoading: boolean\n starters: ChipVM[]\n configuredStarters: ChipVM[]\n error: StreamErrorEventData | WidgetSdkError | null\n lastUserInput: ChatInput | null\n lastDisplayText: string | null\n // Launcher popup text (the auto-greeting response). Cleared on open/dismiss.\n popupText: string | null\n conversationId: string | null\n}\n\nexport type Action =\n | { kind: 'OPEN' }\n | { kind: 'CLOSE' }\n | { kind: 'USER_SENT'; input: ChatInput; userId: string; assistantId: string; displayText?: string }\n | { kind: 'GREETING_SENT'; assistantId: string }\n | { kind: 'EVENT'; event: ChatEvent }\n | { kind: 'STREAM_ERROR'; error: WidgetSdkError }\n | { kind: 'STOP' }\n | { kind: 'DISMISS_POPUP' }\n | { kind: 'LIVE_REFRESH'; messageId: string; cards: ClubFanDashboardCard[]; greeting?: string }\n | { kind: 'LIVE_TRANSITION'; messageId: string; dashboard: ClubFanDashboardPayload }\n | { kind: 'RESET' }\n | { kind: 'RESTORE'; messages: Message[]; conversationId: string | null }\n\nconst POPUP_MAX = 160\n\nexport function initialState(starters: ChipVM[]): WidgetState {\n return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, configuredStarters: starters, error: null, lastUserInput: null, lastDisplayText: null, popupText: null, conversationId: null }\n}\n\nfunction activeTurn(state: WidgetState): AssistantTurn | null {\n const last = state.messages[state.messages.length - 1]\n return last && last.role === 'assistant' && !last.done ? last : null\n}\n\nfunction mapActive(state: WidgetState, fn: (t: AssistantTurn) => AssistantTurn): Message[] {\n const last = state.messages[state.messages.length - 1]\n if (!last || last.role !== 'assistant' || last.done) return state.messages\n return [...state.messages.slice(0, -1), fn(last)]\n}\n\nfunction applyEvent(state: WidgetState, event: ChatEvent): WidgetState {\n switch (event.type) {\n case 'progress':\n return { ...state, status: event.data.message }\n case 'answer':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, text: event.data.text })) }\n case 'entity_card': {\n if (event.data.card.isUsed === false) return state\n const card = toCardVM(event.data.card)\n // Generic cards (coach/referee/stadium/competition — anything not team or\n // player) carry no distinct identity and add no user value; drop them until\n // a purpose-built variant exists.\n if (card.kind === 'generic') return state\n return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, card] })) }\n }\n case 'action_button':\n return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) }\n case 'betting_insight':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) }\n case 'market_odds':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, marketOdds: [...t.marketOdds, toMarketOddsVM(event.data.card)] })) }\n case 'odds_movement':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, oddsMovement: [...t.oddsMovement, toOddsMovementVM(event.data.card)] })) }\n case 'intent_chip': {\n const chip = toChipVM(event.data.intent)\n return chip ? { ...state, starters: [...state.starters, chip] } : state\n }\n case 'actions_loading':\n return { ...state, actionsLoading: true, status: event.data.message }\n case 'turn_complete': {\n const active = activeTurn(state)\n // A completed greeting turn surfaces its message as the launcher popup (unless already open).\n // The club fan dashboard carries its greeting line in the payload rather than as answer\n // text, so prefer that; fall back to any streamed answer text for other greeting shapes.\n const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? '')\n const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText\n return {\n ...state, isStreaming: false, status: null, actionsLoading: false, popupText,\n conversationId: event.data.conversationId ?? state.conversationId,\n messages: mapActive(state, (t) => ({\n ...t,\n done: true,\n greetingDashboard: event.data.dashboard ?? undefined,\n clubFanDashboard: event.data.clubFanDashboard ?? undefined,\n })),\n }\n }\n case 'error': {\n // A failed greeting fails silently — it's non-critical background chatter.\n const suppress = activeTurn(state)?.isGreeting === true\n return { ...state, error: suppress ? state.error : event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n }\n }\n // Unknown/unmodelled event type: never return undefined — that would corrupt\n // state and crash the next dispatch. Ignore the event and keep state intact.\n return state\n}\n\nexport function reducer(state: WidgetState, action: Action): WidgetState {\n switch (action.kind) {\n case 'OPEN':\n return { ...state, isOpen: true, popupText: null }\n case 'CLOSE':\n return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false }\n case 'USER_SENT': {\n const user: UserMessage = { role: 'user', id: action.userId, text: action.displayText ?? action.input.message }\n const assistant: AssistantTurn = { role: 'assistant', id: action.assistantId, text: '', cards: [], actions: [], insights: [], marketOdds: [], oddsMovement: [], done: false }\n return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null }\n }\n case 'GREETING_SENT': {\n // Auto-greeting: no user bubble; the assistant turn is flagged so its completion sets the popup.\n const assistant: AssistantTurn = { role: 'assistant', id: action.assistantId, text: '', cards: [], actions: [], insights: [], marketOdds: [], oddsMovement: [], done: false, isGreeting: true }\n return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null }\n }\n case 'DISMISS_POPUP':\n return { ...state, popupText: null }\n case 'RESET':\n // Preserve panel open/closed state: \"New conversation\" is an in-panel control, so the\n // panel must stay open with the fresh greeting rather than snapping shut. Cross-tab\n // clear-mirroring likewise keeps each tab's panel as it was.\n return { ...initialState(state.configuredStarters), isOpen: state.isOpen }\n case 'RESTORE':\n return {\n ...state,\n messages: action.messages,\n conversationId: action.conversationId,\n isStreaming: false,\n status: null,\n actionsLoading: false,\n starters: action.messages.length ? [] : state.configuredStarters,\n error: null,\n }\n case 'EVENT':\n return applyEvent(state, action.event)\n case 'STREAM_ERROR':\n return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'STOP':\n return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'LIVE_REFRESH':\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.role === 'assistant' && m.id === action.messageId && m.clubFanDashboard\n ? { ...m, clubFanDashboard: { ...m.clubFanDashboard, cards: action.cards, greeting: action.greeting ?? m.clubFanDashboard.greeting } }\n : m,\n ),\n }\n case 'LIVE_TRANSITION':\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.role === 'assistant' && m.id === action.messageId && m.clubFanDashboard\n ? { ...m, clubFanDashboard: action.dashboard }\n : m,\n ),\n }\n }\n}\n","export interface ChartSample { atMs: number; price: number }\nexport interface ChartGeometry {\n path: string\n markers: { x: number; y: number }[]\n gridlines: { y: number; price: number }[]\n viewBox: string\n startMs: number\n endMs: number\n}\n\nexport const CHART_VIEW_W = 320\nexport const CHART_VIEW_H = 140\n\nconst PLOT_X0 = 40\nconst PLOT_X1 = 312\nconst PLOT_Y0 = 10\nconst PLOT_Y1 = 110\n\n// Point markers are drawn only on sparse series. Measured on sandbox1, the median chartable\n// series has TWO points: without markers a two-point chart is one bare diagonal that reads as a\n// rendering glitch rather than as data. Above this count the dots crowd the line and the shape\n// carries itself.\nconst MARKER_MAX_POINTS = 8\n\n// A flat series has no price range to scale against. Widening the domain by a fixed amount keeps\n// the line horizontal through the middle of the plot instead of dividing by zero.\nconst FLAT_DOMAIN_PAD = 0.05\n\nconst round2 = (n: number): number => Math.round(n * 100) / 100\n\nexport function projectSeries(samples: ChartSample[]): ChartGeometry | null {\n if (samples.length < 2) return null\n\n // noUncheckedIndexedAccess can't see that the length check above guarantees these exist.\n const tMin = samples[0]!.atMs\n const tMax = samples[samples.length - 1]!.atMs\n if (tMax <= tMin) return null\n\n const prices = samples.map((s) => s.price)\n const pMin = Math.min(...prices)\n const pMax = Math.max(...prices)\n\n let yMin: number\n let yMax: number\n if (pMax === pMin) {\n yMin = pMin - FLAT_DOMAIN_PAD\n yMax = pMax + FLAT_DOMAIN_PAD\n } else {\n const pad = (pMax - pMin) * 0.1\n yMin = pMin - pad\n yMax = pMax + pad\n }\n\n const x = (atMs: number): number =>\n round2(PLOT_X0 + ((atMs - tMin) / (tMax - tMin)) * (PLOT_X1 - PLOT_X0))\n const y = (price: number): number =>\n round2(PLOT_Y1 - ((price - yMin) / (yMax - yMin)) * (PLOT_Y1 - PLOT_Y0))\n\n const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }))\n const path = projected.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`).join(' ')\n\n return {\n path,\n markers: samples.length <= MARKER_MAX_POINTS ? projected : [],\n // The real extremes, never the padded bounds: a gridline label is a price, and the padded\n // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —\n // two identical gridlines would collide on both React key and rendered text.\n gridlines: pMax === pMin\n ? [{ y: y(pMax), price: pMax }]\n : [\n { y: y(pMax), price: pMax },\n { y: y(pMin), price: pMin },\n ],\n viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,\n startMs: tMin,\n endMs: tMax,\n }\n}\n","import type { BettingInsight, EntityCard, MarketOddsCard, MarketOddsRow, OddsMovementCard, SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { ChartGeometry, ChartSample } from './chart'\nimport { projectSeries } from './chart'\n\nexport type CardKind = 'player' | 'team' | 'generic'\nexport interface StatCell { label: string; value: string }\nexport interface CardScope { competitionId: number | null; label: string; image?: string; stats: StatCell[] }\nexport interface CardVM { id: string; kind: CardKind; name: string; image?: string; sub?: string; season?: string; scopes: CardScope[] }\nexport interface ActionVM { label: string; actionId?: string; actionRef?: string; message: string }\nexport interface ChipVM { text: string }\nexport interface InsightScope { key: string; label: string; stats: StatCell[] }\nexport interface InsightVM {\n id: string\n market: string\n selection?: string\n odds?: string\n bookmaker?: string\n isLive: boolean\n phase?: string\n fixture?: string\n competition?: string\n scopes?: InsightScope[]\n text: string\n stats: StatCell[]\n disclaimer?: string\n matchId: number\n matchOddsId?: number\n marketDeveloperName?: string\n selectionLabel?: string\n line?: string\n addToSlipEnabled: boolean\n pinEnabled: boolean\n isMarketFloor: boolean\n oddsDecimal?: number\n quotedAtUtc?: string\n previousOdds?: string\n movementDirection?: 'shortened' | 'drifted'\n homeTeamName?: string\n awayTeamName?: string\n homeCrest?: string\n awayCrest?: string\n competitionCrest?: string\n kickoffUtc?: string\n kickoffLabel?: string\n}\n\nexport interface MarketOddsRowVM {\n key: string\n selection: string\n odds: string\n oddsDecimal?: number\n matchOddsId?: number\n quotedAtUtc?: string\n isMain: boolean\n isSuspended: boolean\n previousOdds?: string\n movementDirection?: 'shortened' | 'drifted'\n}\nexport interface MarketOddsVM {\n id: string\n market: string\n fixture?: string\n homeTeamName?: string\n awayTeamName?: string\n homeCrest?: string\n awayCrest?: string\n competitionCrest?: string\n competition?: string\n kickoffUtc?: string\n kickoffLabel?: string\n bookmaker?: string\n updatedAt?: string\n isLive: boolean\n matchId: number\n mainRows: MarketOddsRowVM[]\n moreRows: MarketOddsRowVM[]\n disclaimer?: string\n addToSlipEnabled: boolean\n marketDeveloperName?: string\n mainLine?: string\n pinEnabled: boolean\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\nfunction num(v: unknown): string | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? String(v) : undefined\n}\n\nfunction readStatCells(raw: unknown): StatCell[] {\n if (!Array.isArray(raw)) return []\n const cells: StatCell[] = []\n for (const entry of raw as Array<Record<string, unknown>>) {\n const label = str(entry.label)\n const value = num(entry.value) ?? str(entry.value)\n if (label !== undefined && value !== undefined) cells.push({ label, value })\n }\n return cells\n}\n\nexport function toCardVM(card: EntityCard): CardVM {\n const entityType = str(card.entityType)?.toLowerCase()\n const kind: CardKind = entityType === 'player' ? 'player' : entityType === 'team' ? 'team' : 'generic'\n const scopes = Array.isArray(card.scopes)\n ? (card.scopes as unknown as Array<Record<string, unknown>>)\n .map((s): CardScope | null => {\n const label = str(s.label)\n if (!label) return null\n return {\n competitionId: typeof s.competitionId === 'number' ? s.competitionId : null,\n label,\n image: str(s.imagePath),\n stats: readStatCells(s.stats),\n }\n })\n .filter((s): s is CardScope => s !== null)\n : []\n return {\n id: String(card.entityId),\n kind,\n name: card.canonicalName,\n image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),\n sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),\n season: str(card.seasonName),\n scopes,\n }\n}\n\nexport function toActionVM(action: Record<string, unknown>): ActionVM {\n const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? 'Continue'\n const actionId = str(action.actionId) ?? str(action.id)\n const actionRef = str(action.actionRef)\n const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label\n return { label, actionId, actionRef, message }\n}\n\nexport function toChipVM(intent: Record<string, unknown>): ChipVM | null {\n const text = str(intent.text) ?? str(intent.label) ?? str(intent.title)\n return text ? { text } : null\n}\n\nexport function chipFromText(text: string): ChipVM {\n return { text }\n}\n\n// A localized label can already embed the line (TR \"2.5 Üst\") -- never append it twice.\n// Shared by every selection/line join site so they can't drift out of sync (u324).\nexport function joinSelection(label?: string, line?: string): string | undefined {\n if (label && line && label.includes(line)) return label\n return [label, line].filter(Boolean).join(' ') || undefined\n}\n\nexport function toInsightVM(insight: BettingInsight): InsightVM {\n const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? ''\n const selectionLabel = str(insight.selectionLabel)\n const selectionLine = str(insight.line)\n const selection = joinSelection(selectionLabel, selectionLine)\n const value = insight.odds?.value\n const odds = typeof value === 'number' && Number.isFinite(value) ? value.toFixed(2) : undefined\n const oddsValue = insight.odds?.value\n const matchOddsId = typeof insight.odds?.matchOddsId === 'number' ? insight.odds.matchOddsId : undefined\n const home = str(insight.homeTeamName)\n const away = str(insight.awayTeamName)\n const fixture = home && away ? `${home} vs ${away}` : undefined\n const competition = str(insight.competitionName)\n const scopes = Array.isArray(insight.scopes)\n ? (insight.scopes as Array<Record<string, unknown>>)\n .map((s) => ({ key: str(s.key), label: str(s.label), stats: readStatCells(s.stats) }))\n .filter((s): s is InsightScope => !!s.key && !!s.label)\n : undefined\n const previousValue = insight.odds?.previousValue\n const previous =\n typeof previousValue === 'number' && Number.isFinite(previousValue) ? previousValue : undefined\n const direction =\n insight.odds?.movementDirection === 'shortened' || insight.odds?.movementDirection === 'drifted'\n ? insight.odds.movementDirection\n : undefined\n return {\n id: str(insight.insightId) ?? `${str(insight.ruleId) ?? 'insight'}:${num(insight.matchId) ?? ''}`,\n market,\n selection,\n odds,\n // The wire payload carries bookmakerId (not a name); render a name only if one is present.\n bookmaker: str(insight.odds?.bookmakerName),\n isLive: insight.odds?.isLive === true,\n phase: str(insight.phase),\n fixture,\n competition,\n scopes,\n text: str(insight.text) ?? '',\n stats: readStatCells(insight.stats),\n disclaimer: str(insight.disclaimer),\n matchId: typeof insight.matchId === 'number' ? insight.matchId : 0,\n matchOddsId,\n marketDeveloperName: str(insight.marketDeveloperName),\n selectionLabel: str(insight.selectionLabel),\n line: str(insight.line),\n addToSlipEnabled: insight.addToSlipEnabled === true,\n pinEnabled: insight.pinEnabled === true,\n isMarketFloor: insight.isMarketFloor === true,\n oddsDecimal: typeof oddsValue === 'number' && Number.isFinite(oddsValue) ? oddsValue : undefined,\n quotedAtUtc: str(insight.odds?.quotedAtUtc),\n previousOdds: previous !== undefined && direction !== undefined ? previous.toFixed(2) : undefined,\n movementDirection: previous !== undefined && direction !== undefined ? direction : undefined,\n homeTeamName: home,\n awayTeamName: away,\n homeCrest: str(insight.homeTeamImagePath),\n awayCrest: str(insight.awayTeamImagePath),\n competitionCrest: str(insight.competitionImagePath),\n kickoffUtc: str(insight.kickoffUtc),\n kickoffLabel: str(insight.kickoffLabel),\n }\n}\n\nexport function toSlipSelection(vm: InsightVM, conversationId?: string): SlipSelection | null {\n if (vm.matchOddsId === undefined || vm.oddsDecimal === undefined) return null\n const selection: SlipSelection = {\n matchOddsId: vm.matchOddsId,\n matchId: vm.matchId,\n oddsDecimal: vm.oddsDecimal,\n }\n if (vm.quotedAtUtc !== undefined) selection.quotedAtUtc = vm.quotedAtUtc\n if (vm.id !== undefined) selection.insightId = vm.id\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n\nexport function toMarketOddsVM(card: MarketOddsCard): MarketOddsVM {\n const rows = Array.isArray(card.rows) ? card.rows : []\n const toRow = (r: MarketOddsRow, i: number): MarketOddsRowVM => {\n const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? ''\n const price = typeof r.price === 'number' && Number.isFinite(r.price) ? r.price : undefined\n const previous =\n typeof r.previousPrice === 'number' && Number.isFinite(r.previousPrice) ? r.previousPrice : undefined\n const direction =\n r.movementDirection === 'shortened' || r.movementDirection === 'drifted' ? r.movementDirection : undefined\n return {\n key: `${selection}:${str(r.line) ?? ''}:${i}`,\n selection,\n odds: price !== undefined ? price.toFixed(2) : '',\n oddsDecimal: price,\n matchOddsId: typeof r.matchOddsId === 'number' ? r.matchOddsId : undefined,\n quotedAtUtc: str(r.quotedAtUtc),\n isMain: r.isMainLine !== false,\n // === true, not !== false: a server that has not shipped the field yet leaves it undefined,\n // and undefined must read as open rather than hiding every price on the card.\n isSuspended: r.isSuspended === true,\n previousOdds: previous !== undefined && direction !== undefined ? previous.toFixed(2) : undefined,\n movementDirection: previous !== undefined && direction !== undefined ? direction : undefined,\n }\n }\n // A suspended selection leaves the ladder entirely, same rule the live match card follows: we do\n // not show a price the bookmaker is not taking. If every line is suspended the card has no rows and\n // MarketOddsCardList renders nothing for it.\n const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended)\n const home = str(card.homeTeamName)\n const away = str(card.awayTeamName)\n const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v): v is string => !!v).sort()\n return {\n id: `${typeof card.matchId === 'number' ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ''}`,\n market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? '',\n fixture: home && away ? `${home} vs ${away}` : undefined,\n homeTeamName: home,\n awayTeamName: away,\n homeCrest: str(card.homeTeamImagePath),\n awayCrest: str(card.awayTeamImagePath),\n competitionCrest: str(card.competitionImagePath),\n competition: str(card.competitionName),\n kickoffUtc: str(card.kickoffUtc),\n kickoffLabel: str(card.kickoffLabel),\n bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),\n updatedAt: updated.length > 0 ? updated[updated.length - 1] : undefined,\n isLive: rows.some((r) => r.isLive === true),\n matchId: typeof card.matchId === 'number' ? card.matchId : 0,\n mainRows: vms.filter((r) => r.isMain),\n moreRows: vms.filter((r) => !r.isMain),\n disclaimer: str(card.disclaimer),\n addToSlipEnabled: card.addToSlipEnabled === true,\n marketDeveloperName: str(card.marketDeveloperName),\n mainLine: str(card.mainLine),\n pinEnabled: card.pinEnabled === true,\n }\n}\n\nexport interface OddsMovementVM {\n id: string\n matchId: number\n market: string\n marketDeveloperName?: string\n selection: string\n selectionLabel?: string\n line?: string\n fixture?: string\n competition?: string\n bookmaker?: string\n opening: string\n current: string\n direction?: 'shortened' | 'drifted'\n windowHours: number\n excludedCount: number\n isSuspended: boolean\n disclaimer?: string\n geometry: ChartGeometry | null\n observationCount: number\n pinEnabled: boolean\n matchOddsId?: number\n}\n\nexport function toOddsMovementVM(card: OddsMovementCard): OddsMovementVM {\n const raw = Array.isArray(card.points) ? card.points : []\n const samples: ChartSample[] = []\n for (const p of raw) {\n const price = typeof p.price === 'number' && Number.isFinite(p.price) ? p.price : undefined\n const atMs = typeof p.atUtc === 'string' ? Date.parse(p.atUtc) : NaN\n if (price === undefined || Number.isNaN(atMs)) continue\n samples.push({ atMs, price })\n }\n // projectSeries trusts sample order as the time domain (samples[0]/samples[^1] become tMin/tMax)\n // without re-checking it; every other field above is already validated, so this is the one\n // property whose violation is otherwise invisible.\n samples.sort((a, b) => a.atMs - b.atMs)\n\n const asNumber = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined\n const opening = asNumber(card.openingPrice)\n const current = asNumber(card.currentPrice)\n const home = str(card.homeTeamName)\n const away = str(card.awayTeamName)\n const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? ''\n const bookmakerId = typeof card.bookmakerId === 'number' ? card.bookmakerId : ''\n\n return {\n id: `${typeof card.matchId === 'number' ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ''}:${selection}:${bookmakerId}`,\n matchId: typeof card.matchId === 'number' ? card.matchId : 0,\n market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? '',\n marketDeveloperName: str(card.marketDeveloperName),\n selection,\n selectionLabel: str(card.selectionLabel),\n line: str(card.line),\n fixture: home && away ? `${home} vs ${away}` : undefined,\n competition: str(card.competitionName),\n bookmaker: str(card.bookmakerName),\n opening: opening !== undefined ? opening.toFixed(2) : '',\n current: current !== undefined ? current.toFixed(2) : '',\n direction:\n card.movementDirection === 'shortened' || card.movementDirection === 'drifted'\n ? card.movementDirection\n : undefined,\n windowHours: asNumber(card.windowHours) ?? 0,\n excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,\n isSuspended: card.isSuspended === true,\n disclaimer: str(card.disclaimer),\n geometry: projectSeries(samples),\n observationCount: samples.length,\n pinEnabled: card.pinEnabled === true,\n matchOddsId: typeof card.matchOddsId === 'number' ? card.matchOddsId : undefined,\n }\n}\n\nexport function marketOddsRowToSlipSelection(\n vm: MarketOddsVM, row: MarketOddsRowVM, conversationId?: string,\n): SlipSelection | null {\n if (row.matchOddsId === undefined || row.oddsDecimal === undefined) return null\n const selection: SlipSelection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal }\n if (row.quotedAtUtc !== undefined) selection.quotedAtUtc = row.quotedAtUtc\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n","import { useEffect, useReducer, useRef } from 'react'\nimport type { ClubFanDashboardPayload, CountdownCard } from '@sensiblestats/widget-sdk'\nimport type { Action, Message } from './reducer'\n\nconst POLL_INTERVAL_MS = 60_000\nconst LEAD_MS = 120_000 // start polling 2 min before kickoff\nconst GIVE_UP_MS = 30 * 60_000 // stop polling 30 min after kickoff if match never went live\n\ntype Anchor =\n | { messageId: string; kind: 'live' }\n | { messageId: string; kind: 'preMatch'; kickoffMs: number }\n\nexport interface UseLiveDashboardPollOptions {\n messages: Message[]\n dispatch: (action: Action) => void\n getLiveDashboard: () => Promise<ClubFanDashboardPayload | null>\n}\n\nfunction extractKickoffMs(dashboard: ClubFanDashboardPayload): number | null {\n const countdown = dashboard.cards.find((c): c is CountdownCard => c.cardType === 'countdown')\n if (countdown) return countdown.data.kickoffUnix * 1_000\n // fall back to any card that exposes kickoffUnix in its data\n for (const c of dashboard.cards) {\n const d = (c as { data?: { kickoffUnix?: number } }).data\n if (typeof d?.kickoffUnix === 'number') return d.kickoffUnix * 1_000\n }\n return null\n}\n\n// Returns the most recent assistant message that can serve as a polling anchor:\n// — a live dashboard (always valid), or\n// — a preMatch dashboard whose kickoff is within [kickoff − LEAD_MS, kickoff + GIVE_UP_MS].\nfunction findAnchor(messages: Message[]): Anchor | null {\n const now = Date.now()\n for (const m of messages.slice().reverse()) {\n if (m.role !== 'assistant' || !m.clubFanDashboard) continue\n const { phase } = m.clubFanDashboard\n if (phase === 'live') return { messageId: m.id, kind: 'live' }\n if (phase === 'preMatch') {\n const kickoffMs = extractKickoffMs(m.clubFanDashboard)\n if (kickoffMs === null) continue\n if (now >= kickoffMs - LEAD_MS && now <= kickoffMs + GIVE_UP_MS) {\n return { messageId: m.id, kind: 'preMatch', kickoffMs }\n }\n }\n }\n return null\n}\n\n// Returns the earliest future wakeup time for a preMatch dashboard that is not yet within the\n// poll window (kickoff − LEAD_MS still in the future). Returns null if none.\nfunction findEarliestWakeupMs(messages: Message[]): number | null {\n const now = Date.now()\n let earliest: number | null = null\n for (const m of messages) {\n if (m.role !== 'assistant' || m.clubFanDashboard?.phase !== 'preMatch') continue\n const kickoffMs = extractKickoffMs(m.clubFanDashboard)\n if (kickoffMs === null) continue\n const wakeAt = kickoffMs - LEAD_MS\n if (wakeAt > now && (earliest === null || wakeAt < earliest)) earliest = wakeAt\n }\n return earliest\n}\n\n// Polls the live club-fan dashboard every 60s for the chosen anchor:\n//\n// — Live anchor: on a live payload → LIVE_REFRESH (cards + greeting). On a post-match payload →\n// LIVE_TRANSITION (full swap to the post-match dashboard) and stop polling. On null → stop.\n// — PreMatch anchor: on a live payload → LIVE_TRANSITION (full payload swap). On null → keep\n// polling (pre-kickoff 204s) but give up if now > kickoff + GIVE_UP_MS.\n//\n// Wake-up: if a preMatch dashboard's window hasn't opened yet (kickoff − 2min still in the\n// future), schedules a setTimeout to trigger a re-render exactly when polling should begin.\nexport function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }: UseLiveDashboardPollOptions): void {\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0)\n const anchor = findAnchor(messages)\n const anchorRef = useRef<Anchor | null>(anchor)\n anchorRef.current = anchor\n const inFlightRef = useRef(false)\n\n // Polling effect — keyed on the anchor identity so it restarts when anchor changes.\n const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null\n\n useEffect(() => {\n if (!anchorKey || !anchorRef.current) return\n\n const tick = async () => {\n if (inFlightRef.current) return\n inFlightRef.current = true\n try {\n const payload = await getLiveDashboard()\n const current = anchorRef.current\n if (!current) return\n\n if (payload?.phase === 'live') {\n if (current.kind === 'preMatch') {\n dispatch({ kind: 'LIVE_TRANSITION', messageId: current.messageId, dashboard: payload })\n window.clearInterval(id)\n } else {\n dispatch({ kind: 'LIVE_REFRESH', messageId: current.messageId, cards: payload.cards, greeting: payload.greeting })\n }\n } else if (payload?.phase === 'postMatch' && current.kind === 'live') {\n // Match ended: the poll now returns the post-match dashboard. Swap the live card for it\n // and stop polling (the anchor is no longer live).\n dispatch({ kind: 'LIVE_TRANSITION', messageId: current.messageId, dashboard: payload })\n window.clearInterval(id)\n } else {\n // null (204) or non-live phase with no payload\n if (current.kind === 'live') {\n window.clearInterval(id)\n } else if (Date.now() > current.kickoffMs + GIVE_UP_MS) {\n window.clearInterval(id)\n }\n // preMatch within window: keep polling (these are pre-kickoff 204s)\n }\n } catch {\n // A network error must not crash the widget or stop the loop — swallow and retry\n // on the next tick.\n } finally {\n inFlightRef.current = false\n }\n }\n\n const id = window.setInterval(() => { void tick() }, POLL_INTERVAL_MS)\n return () => window.clearInterval(id)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [anchorKey, dispatch, getLiveDashboard])\n\n // Wake-up effect — schedules a re-render when a preMatch window opens in the future.\n useEffect(() => {\n if (anchorKey !== null) return // already polling, no wake-up needed\n const wakeAt = findEarliestWakeupMs(messages)\n if (wakeAt === null) return\n const delay = wakeAt - Date.now()\n if (delay <= 0) return\n const id = window.setTimeout(forceUpdate, delay)\n return () => window.clearTimeout(id)\n }, [anchorKey, messages, forceUpdate])\n}\n","import type { Message } from './reducer'\n\nexport const TTL_MS = 3_600_000\nexport const MAX_MESSAGES = 30\n\nexport interface StoredPayload {\n conversationId: string | null\n messages: Message[]\n}\n\ninterface StoredConversation {\n v: 1\n updatedAt: number\n conversationId: string | null\n messages: Message[]\n}\n\n// Pure read: returns the payload when a v:1 blob exists and is within TTL; a sentinel the caller\n// clears from an effect (never during render) when stale/unparseable; null when absent.\nexport function readConversation(storageKey: string, now: number): StoredPayload | 'expired' | 'corrupt' | null {\n let raw: string | null\n try {\n raw = window.localStorage.getItem(storageKey)\n } catch {\n return null // SSR / storage blocked\n }\n if (!raw) return null\n let parsed: StoredConversation\n try {\n parsed = JSON.parse(raw) as StoredConversation\n } catch {\n return 'corrupt'\n }\n if (parsed?.v !== 1 || !Array.isArray(parsed.messages) || typeof parsed.updatedAt !== 'number') return 'corrupt'\n if (now - parsed.updatedAt > TTL_MS) return 'expired'\n return { conversationId: parsed.conversationId ?? null, messages: parsed.messages }\n}\n\nexport function writeConversation(storageKey: string, conversationId: string | null, messages: Message[], now: number): void {\n let capped = messages.slice(-MAX_MESSAGES)\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify({ v: 1, updatedAt: now, conversationId, messages: capped } satisfies StoredConversation))\n return\n } catch {\n // quota / blocked: drop the oldest half and retry once, then give up (in-memory only)\n if (capped.length <= 1) return\n capped = capped.slice(Math.ceil(capped.length / 2))\n }\n }\n}\n\nexport function clearConversation(storageKey: string): void {\n try {\n window.localStorage.removeItem(storageKey)\n } catch {\n // no-op\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { LiveMonitorEvent, LiveMonitorSnapshot, MarketOddsBlock, PinRef } from '@sensiblestats/widget-sdk'\nimport { createPinStore, type PinAddResult, type PinStore } from './pinStore'\nimport { useTabs, type WidgetTab } from './useTabs'\n\n// Re-exported for back-compat; callers that already import MonitorTab continue to compile.\nexport type MonitorTab = WidgetTab\n\nexport interface LiveMonitorController {\n /** Starts TRUE (the server-side pinEnabled flag is the real affordance gate); flips to\n * false permanently for the session on a 404 (null snapshot) from the monitor endpoint. */\n enabled: boolean\n pins: PinRef[]\n snapshot: LiveMonitorSnapshot | null\n activeTab: WidgetTab\n setActiveTab(tab: WidgetTab): void\n togglePin(pin: PinRef): PinAddResult\n isPinned(key: string): boolean\n /** Set by ChatPanel when a reply lands off-tab; cleared on chat tab. */\n chatDot: boolean\n markChatActivity(): void\n /** A goal/red event arrived on a pinned match since Maçlar was last viewed. */\n matchesDot: boolean\n /** A pinned market's price changed since Oranlar was last viewed. */\n oddsDot: boolean\n /** The live count rose from zero while Today was off-screen; suppressed on the active tab. */\n todayDot: boolean\n /** Set by the discovery owner when the live count rises from zero (mirrors markChatActivity). */\n markTodayActivity(): void\n /** Last-viewed price per pin key, for client-side movement badges. */\n lastViewedPrices: Record<string, number>\n /** matchOddsIds the user added to the slip this session — drives the persistent in-slip badge. */\n inSlip: Record<number, true>\n markInSlip(matchOddsId: number): void\n /** The currently open accordion market per matchId (null = collapsed). One open at a time per match. */\n openMarket: Record<number, string | null>\n /** Lazy per-market odds cache, keyed `${matchId}:${marketDeveloperName}`. */\n marketOdds: Record<string, { block?: MarketOddsBlock; loading: boolean; error: boolean }>\n toggleMarket(matchId: number, marketDeveloperName: string): void\n /** Refetches a market's odds WITHOUT touching openMarket -- the tap-to-retry affordance for a\n * market that is already open and errored. toggleMarket would collapse it instead (it flips\n * openMarket unconditionally), which is the wrong move when the row is already showing. */\n retryMarket(matchId: number, marketDeveloperName: string): void\n /** Internal seam: applies a freshly-fetched snapshot (or null on a 404). The poll loop calls\n * this repeatedly; tests call it directly to drive dot/grace logic without a live timer.\n * Not part of the poll cadence/visibility policy itself. */\n _setSnapshot(next: LiveMonitorSnapshot | null): void\n}\n\nexport interface UseLiveMonitorOptions {\n getLiveMonitor: (pins: PinRef[]) => Promise<LiveMonitorSnapshot | null>\n getMarketOdds?: (matchId: number, marketDeveloperName: string) => Promise<MarketOddsBlock | null>\n storageKey: string\n /** false -> true transitions trigger an immediate poll tick (widget open). */\n isOpen: boolean\n /** Whether the Today tab currently has content -- picks the fallback target when a pinned tab\n * disappears, and sends the user to Chat when Today itself empties under them. */\n hasToday?: boolean\n}\n\nconst GOAL_OR_RED: ReadonlySet<LiveMonitorEvent['type']> = new Set(['goal', 'red'])\nconst MIN_POLL_MS = 5_000\nconst DEFAULT_POLL_MS = 60_000\n\nfunction eventIdentity(e: LiveMonitorEvent): string {\n return `${e.type}:${e.side}:${e.minuteLabel}:${e.player ?? ''}`\n}\n\nfunction priceForPin(snapshot: LiveMonitorSnapshot | null, pin: PinRef): number | undefined {\n if (!snapshot) return undefined\n const market = snapshot.markets.find((m) => m.key === pin.key)\n const rows = market?.card?.rows\n if (!rows || rows.length === 0) return undefined\n const row = pin.matchOddsId != null ? rows.find((r) => r.matchOddsId === pin.matchOddsId) : rows[0]\n return row?.price\n}\n\nfunction phaseForPin(snapshot: LiveMonitorSnapshot, pin: PinRef): string | undefined {\n if (pin.kind === 'match') return snapshot.matches.find((m) => m.matchId === pin.matchId)?.phase\n return snapshot.markets.find((mk) => mk.key === pin.key)?.phase\n}\n\nexport function useLiveMonitor(opts: UseLiveMonitorOptions): LiveMonitorController {\n const sessionIdRef = useRef(crypto.randomUUID())\n\n const [pins, setPins] = useState<PinRef[]>([])\n // Lazy initializer: the store fires an initial (no-op-from-the-caller's-view) onChange\n // synchronously during construction, which is a same-component render-phase state update\n // React explicitly supports — it must not run in an effect/later render.\n const [store] = useState<PinStore>(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins))\n\n const [enabled, setEnabled] = useState(true)\n const [snapshot, setSnapshotState] = useState<LiveMonitorSnapshot | null>(null)\n const { activeTab, setActiveTab: setActiveTabState } = useTabs('chat')\n const [chatDot, setChatDot] = useState(false)\n const [matchesDot, setMatchesDot] = useState(false)\n const [oddsDot, setOddsDot] = useState(false)\n const [todayDot, setTodayDot] = useState(false)\n const [lastViewedPrices, setLastViewedPrices] = useState<Record<string, number>>({})\n const [inSlip, setInSlip] = useState<Record<number, true>>({})\n const [openMarket, setOpenMarket] = useState<Record<number, string | null>>({})\n const [marketOdds, setMarketOdds] = useState<\n Record<string, { block?: MarketOddsBlock; loading: boolean; error: boolean }>\n >({})\n\n const pinsRef = useRef(pins)\n pinsRef.current = pins\n const activeTabRef = useRef(activeTab)\n activeTabRef.current = activeTab\n const snapshotRef = useRef(snapshot)\n snapshotRef.current = snapshot\n const lastViewedPricesRef = useRef(lastViewedPrices)\n lastViewedPricesRef.current = lastViewedPrices\n const openMarketRef = useRef(openMarket)\n openMarketRef.current = openMarket\n const marketOddsRef = useRef(marketOdds)\n marketOddsRef.current = marketOdds\n const hasToday = opts.hasToday ?? false\n\n const marketKey = (matchId: number, dev: string): string => `${matchId}:${dev}`\n\n const getMarketOddsRef = useRef(opts.getMarketOdds)\n getMarketOddsRef.current = opts.getMarketOdds // latest-fn pattern; fetchMarket reads the ref, deps stay stable\n\n // Stable identity ([] deps, refs only) so callers (applySnapshot, tick) can invoke it without\n // needing to sit in a dependency array.\n const fetchMarket = useCallback((matchId: number, dev: string) => {\n const key = marketKey(matchId, dev)\n const existing = marketOddsRef.current[key]\n if (existing?.loading) return // already in flight -- don't double-fetch\n const loadingEntry = { ...existing, loading: true, error: false }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry }\n setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }))\n const fn = getMarketOddsRef.current\n if (!fn) return\n void fn(matchId, dev)\n .then((block) => {\n const entry = { block: block ?? undefined, loading: false, error: false }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: entry }\n setMarketOdds((prev) => ({ ...prev, [key]: entry }))\n })\n .catch(() => {\n const entry = { ...marketOddsRef.current[key], loading: false, error: true }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: entry }\n setMarketOdds((prev) => ({ ...prev, [key]: entry }))\n })\n }, [])\n\n const toggleMarket = useCallback((matchId: number, dev: string) => {\n const key = marketKey(matchId, dev)\n const wasOpen = openMarketRef.current[matchId] === dev\n const nextValue = wasOpen ? null : dev\n openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue }\n setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }))\n // Opening a market that isn't cached yet -- fetch it. A successfully-cached reopen is a\n // no-op fetch, but an entry that previously errored (no block) MUST be retried, not\n // treated as \"cached\" -- that's what drives the tap-to-retry affordance (Task 9).\n const existing = marketOddsRef.current[key]\n if (!wasOpen && !(existing?.loading || existing?.block)) {\n fetchMarket(matchId, dev)\n }\n }, [fetchMarket])\n\n const retryMarket = useCallback((matchId: number, dev: string) => {\n fetchMarket(matchId, dev)\n }, [fetchMarket])\n\n const applySnapshot = useCallback((next: LiveMonitorSnapshot | null) => {\n if (next === null) {\n setEnabled(false)\n return\n }\n const prev = snapshotRef.current\n const currentPins = pinsRef.current\n\n const pinnedMatchIds = new Set(currentPins.filter((p) => p.kind === 'match').map((p) => p.matchId))\n let sawNewGoalOrRed = false\n for (const m of next.matches) {\n if (!pinnedMatchIds.has(m.matchId)) continue\n const prevMatch = prev?.matches.find((pm) => pm.matchId === m.matchId)\n const prevKeys = new Set((prevMatch?.events ?? []).filter((e) => GOAL_OR_RED.has(e.type)).map(eventIdentity))\n if (m.events.some((e) => GOAL_OR_RED.has(e.type) && !prevKeys.has(eventIdentity(e)))) {\n sawNewGoalOrRed = true\n break\n }\n }\n if (sawNewGoalOrRed && activeTabRef.current !== 'following') setMatchesDot(true)\n\n // Default-open the first available market per pinned match, once -- an explicit close\n // (openMarket[matchId] === null) must stick, so the guard is \"no entry at all\" not \"falsy\".\n for (const m of next.matches) {\n if (!pinnedMatchIds.has(m.matchId)) continue\n const first = m.availableMarkets?.[0]\n if (!first) continue\n if (m.matchId in openMarketRef.current) continue\n const dev = first.marketDeveloperName\n openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev }\n setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }))\n fetchMarket(m.matchId, dev)\n }\n\n const marketPins = currentPins.filter((p) => p.kind !== 'match')\n if (activeTabRef.current === 'odds') {\n setLastViewedPrices((prevMap) => {\n let changed = false\n const out = { ...prevMap }\n for (const pin of marketPins) {\n const price = priceForPin(next, pin)\n if (price !== undefined && out[pin.key] !== price) {\n out[pin.key] = price\n changed = true\n }\n }\n return changed ? out : prevMap\n })\n } else {\n let sawPriceMove = false\n for (const pin of marketPins) {\n const price = priceForPin(next, pin)\n const last = lastViewedPricesRef.current[pin.key]\n if (price !== undefined && last !== undefined && price !== last) {\n sawPriceMove = true\n break\n }\n }\n if (sawPriceMove) setOddsDot(true)\n }\n\n const graceKeys = currentPins\n .filter((p) => {\n const phase = phaseForPin(next, p)\n return phase === 'fullTime' || phase === 'postponed' || phase === 'gone'\n })\n .map((p) => p.key)\n if (graceKeys.length > 0) store.markGrace(graceKeys, sessionIdRef.current, Date.now())\n\n // Sync the ref immediately (state updates are async) -- the poll loop's schedule step reads\n // this synchronously in the SAME tick, right after this call returns, to size the next\n // delay off the snapshot that was just received rather than the one from the prior tick.\n snapshotRef.current = next\n setSnapshotState(next)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store])\n\n // Poll loop. ALL mutable inputs live in refs so `tick` is created ONCE ([applySnapshot] deps,\n // and applySnapshot itself is stable across renders): an inline getLiveMonitor lambda handed\n // in fresh from StatsWidget on every render must not re-arm the visibility listener or\n // recreate the timer chain.\n const inFlightRef = useRef(false)\n const timerRef = useRef<number | undefined>(undefined)\n const disabledRef = useRef(false)\n const getLiveMonitorRef = useRef(opts.getLiveMonitor)\n getLiveMonitorRef.current = opts.getLiveMonitor // latest-fn pattern; tick reads the ref, deps stay stable\n\n const tick = useCallback(async () => {\n if (inFlightRef.current || disabledRef.current || pinsRef.current.length === 0) return\n inFlightRef.current = true\n try {\n const snap = await getLiveMonitorRef.current(pinsRef.current)\n if (snap === null) {\n // 404 -> live monitor disabled for this operator: stop for the session, hide affordances.\n disabledRef.current = true\n applySnapshot(null)\n return\n }\n applySnapshot(snap)\n // Live-refresh the open accordion market per match. Bypasses the \"already cached\" skip\n // (that guard only lives in toggleMarket) -- fetchMarket itself only skips a fetch already\n // in flight, so this always requests fresh odds for a live match's open market.\n for (const m of snap.matches) {\n if (m.phase !== 'live') continue\n const dev = openMarketRef.current[m.matchId]\n if (dev) fetchMarket(m.matchId, dev)\n }\n } catch {\n // transient failure: keep the previous snapshot, retry on the next scheduled tick\n } finally {\n inFlightRef.current = false\n scheduleRef.current()\n }\n }, [applySnapshot, fetchMarket]) // reads refs only -- both callbacks are themselves stable\n\n const scheduleRef = useRef<() => void>(() => {})\n scheduleRef.current = () => {\n window.clearTimeout(timerRef.current)\n if (disabledRef.current || pinsRef.current.length === 0 || document.visibilityState === 'hidden') return\n const hinted = (snapshotRef.current?.nextPollSeconds ?? DEFAULT_POLL_MS / 1000) * 1000\n timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted))\n }\n\n // Immediate tick: pin list transitions 0 -> 1+ (togglePin add, or pins already present at\n // mount -- the ref starts at 0 so the first run treats \"already have pins\" the same way).\n // Dropping to zero pins clears any pending timer so a stray tick never fires with no pins.\n // It deliberately does NOT move the active tab: PinToggle is reachable from a chat message\n // card, so unpinning mid-conversation must leave the reader where they are. The per-kind\n // effect below owns the fallback, and its `activeTab` guard covers zero pins too.\n const prevPinsLengthRef = useRef(0)\n useEffect(() => {\n const wasEmpty = prevPinsLengthRef.current === 0\n prevPinsLengthRef.current = pins.length\n if (pins.length === 0) {\n window.clearTimeout(timerRef.current)\n return\n }\n if (wasEmpty) void tick()\n }, [pins.length, tick])\n\n // A tab left active after the content backing it disappears strands the user on an empty panel\n // with no tab in the strip to escape from. Three ways in: the last match pin drops while an odds\n // pin remains (pins.length alone can't see it, the OTHER kind keeps it above zero), the mirror\n // case for odds, and Today emptying under the user at the local-date rollover.\n useEffect(() => {\n const matchPins = pins.filter((p) => p.kind === 'match').length\n const marketPins = pins.length - matchPins\n if (activeTab === 'following' && matchPins === 0) setActiveTabState(hasToday ? 'today' : 'chat')\n if (activeTab === 'odds' && marketPins === 0) setActiveTabState(hasToday ? 'today' : 'chat')\n if (activeTab === 'today' && !hasToday) setActiveTabState('chat')\n }, [pins, activeTab, hasToday])\n\n // Immediate tick: widget open (false -> true transition).\n const prevIsOpenRef = useRef(false)\n useEffect(() => {\n const wasClosed = !prevIsOpenRef.current\n prevIsOpenRef.current = opts.isOpen\n if (wasClosed && opts.isOpen) void tick()\n }, [opts.isOpen, tick])\n\n // Visibility: hidden clears the pending timer; visible ticks immediately. Mounted exactly\n // once -- `tick` never changes identity, so this effect never re-fires across re-renders.\n useEffect(() => {\n const onVisibility = () => {\n if (document.visibilityState === 'hidden') window.clearTimeout(timerRef.current)\n else void tick()\n }\n document.addEventListener('visibilitychange', onVisibility)\n return () => {\n document.removeEventListener('visibilitychange', onVisibility)\n window.clearTimeout(timerRef.current)\n }\n }, [tick])\n\n const setActiveTab = useCallback((tab: WidgetTab) => {\n setActiveTabState(tab)\n if (tab === 'chat') setChatDot(false)\n if (tab === 'today') setTodayDot(false)\n if (tab === 'following') {\n setMatchesDot(false)\n void tick()\n }\n if (tab === 'odds') {\n setOddsDot(false)\n setLastViewedPrices((prevMap) => {\n const out = { ...prevMap }\n for (const pin of pinsRef.current.filter((p) => p.kind !== 'match')) {\n const price = priceForPin(snapshotRef.current, pin)\n if (price !== undefined) out[pin.key] = price\n }\n return out\n })\n void tick()\n }\n }, [tick])\n\n const togglePin = useCallback((pin: PinRef): PinAddResult => store.toggle(pin), [store])\n const isPinned = useCallback((key: string): boolean => pinsRef.current.some((p) => p.key === key), [])\n const markChatActivity = useCallback(() => setChatDot(true), [])\n // Same shape as markChatActivity: the count that drives it lives in useMatchDiscovery, which\n // cannot be read from here without making the two hooks observe each other's own render.\n const markTodayActivity = useCallback(() => {\n if (activeTabRef.current !== 'today') setTodayDot(true)\n }, [])\n const markInSlip = useCallback((matchOddsId: number) => {\n setInSlip((prev) => (prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true }))\n }, [])\n\n return {\n enabled,\n pins,\n snapshot,\n activeTab,\n setActiveTab,\n togglePin,\n isPinned,\n chatDot,\n markChatActivity,\n matchesDot,\n oddsDot,\n todayDot,\n markTodayActivity,\n lastViewedPrices,\n inSlip,\n markInSlip,\n openMarket,\n marketOdds,\n toggleMarket,\n retryMarket,\n _setSnapshot: applySnapshot,\n }\n}\n","import type { PinRef } from '@sensiblestats/widget-sdk'\n\nexport const MAX_MATCH_PINS = 5\nexport const MAX_MARKET_PINS = 10\nexport type PinAddResult = 'added' | 'removed' | 'match_limit' | 'market_limit'\n\nexport type StoredPin = PinRef & { graceAt?: number; graceSession?: string }\n\nexport interface PinStore {\n pins: PinRef[]\n /** Toggle: same key present -> remove; else add if under the kind's cap. */\n toggle(pin: PinRef): PinAddResult\n remove(key: string): void\n has(key: string): boolean\n /** D7: stamps graceAt/graceSession on the given keys, only where not already stamped. */\n markGrace(keys: string[], sessionId: string, now: number): void\n}\n\nexport function pinKey(p: Omit<PinRef, 'key'>): string {\n return `${p.kind}:${p.matchId}:${p.marketDeveloperName ?? ''}:${p.selectionLabel ?? ''}:${p.line ?? ''}:${p.matchOddsId ?? ''}`\n}\n\nexport const GRACE_MS = 4 * 60 * 60 * 1000\n\n/** D7: drop pins whose grace started in a PREVIOUS session (next widget open) or > 4h ago. */\nexport function pruneExpired(pins: StoredPin[], sessionId: string, now: number): StoredPin[] {\n return pins.filter((p) => p.graceAt === undefined || (p.graceSession === sessionId && now - p.graceAt <= GRACE_MS))\n}\n\ninterface StoredPins {\n v: 1\n pins: StoredPin[]\n}\n\nfunction safeRead(storageKey: string): StoredPin[] {\n try {\n const raw = window.localStorage.getItem(storageKey)\n if (!raw) return []\n const parsed = JSON.parse(raw) as StoredPins\n return parsed.v === 1 && Array.isArray(parsed.pins) ? parsed.pins : []\n } catch {\n return []\n }\n}\n\nfunction safeWrite(storageKey: string, pins: StoredPin[]): void {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify({ v: 1, pins } satisfies StoredPins))\n } catch {\n // storage blocked -> in-memory only for the session (spec, degradation rules)\n }\n}\n\nexport function loadPins(storageKey: string): PinRef[] {\n return safeRead(storageKey)\n}\n\nexport function createPinStore(storageKey: string, sessionId: string, onChange: (pins: PinRef[]) => void): PinStore {\n // D7 grace: pins whose subject finished in a previous session (or >4h ago) are dropped on open.\n let pins = pruneExpired(safeRead(storageKey), sessionId, Date.now())\n\n const commit = (next: StoredPin[]) => {\n pins = next\n safeWrite(storageKey, pins)\n onChange(pins)\n }\n commit(pins)\n\n return {\n get pins() {\n return pins\n },\n has: (key) => pins.some((p) => p.key === key),\n remove: (key) => commit(pins.filter((p) => p.key !== key)),\n markGrace(keys, session, now) {\n commit(\n pins.map((p) => (keys.includes(p.key) && p.graceAt === undefined ? { ...p, graceAt: now, graceSession: session } : p)),\n )\n },\n toggle(pin) {\n if (pins.some((p) => p.key === pin.key)) {\n commit(pins.filter((p) => p.key !== pin.key))\n return 'removed'\n }\n const matchCount = pins.filter((p) => p.kind === 'match').length\n const marketCount = pins.length - matchCount\n if (pin.kind === 'match' && matchCount >= MAX_MATCH_PINS) return 'match_limit'\n if (pin.kind !== 'match' && marketCount >= MAX_MARKET_PINS) return 'market_limit'\n commit([...pins, pin])\n return 'added'\n },\n }\n}\n","import { useState } from 'react'\n\nexport type WidgetTab = 'chat' | 'today' | 'following' | 'odds' | 'games' | 'leaderboard'\n\nexport function useTabs(initial: WidgetTab = 'chat'): { activeTab: WidgetTab; setActiveTab: (t: WidgetTab) => void } {\n const [activeTab, setActiveTab] = useState<WidgetTab>(initial)\n return { activeTab, setActiveTab }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { MatchState, SchedulePayload, ScheduleGroup, StatesPayload } from '@sensiblestats/widget-sdk'\nimport { readSchedule, readScheduleIgnoringTtl, writeSchedule } from './scheduleCache'\nimport { dueMatchIds } from './dueSet'\n\nconst POLL_MS = 60_000\n// Local re-render so the minute advances between network polls. Costs one render; the alternative\n// is a clock that only moves once a minute.\nconst ROLLOVER_CHECK_MS = 60_000\nconst STALE_AFTER_FAILURES = 2\n\nexport interface MatchDiscoveryController {\n groups: ScheduleGroup[]\n states: Record<number, MatchState>\n /** Advanced locally between polls so the minute ticks. */\n liveCount: number\n stale: boolean\n expanded: Record<number, boolean>\n toggleGroup(competitionId: number): void\n /** Test seam: run one states poll synchronously. Not part of the cadence policy. */\n _tick(): Promise<void>\n}\n\nexport interface UseMatchDiscoveryOptions {\n getSchedule: (localDate: string, utcOffsetMinutes: number) => Promise<SchedulePayload | null>\n getStates: (matchIds: number[]) => Promise<StatesPayload | null>\n operatorId: string\n isOpen: boolean\n pinnedMatchIds: number[]\n}\n\nfunction localDateOf(now: Date): string {\n const y = now.getFullYear()\n const m = `${now.getMonth() + 1}`.padStart(2, '0')\n const d = `${now.getDate()}`.padStart(2, '0')\n return `${y}-${m}-${d}`\n}\n\nexport function useMatchDiscovery(opts: UseMatchDiscoveryOptions): MatchDiscoveryController {\n const [groups, setGroups] = useState<ScheduleGroup[]>([])\n const [states, setStates] = useState<Record<number, MatchState>>({})\n const [failures, setFailures] = useState(0)\n const [expanded, setExpanded] = useState<Record<number, boolean>>({})\n const [touched, setTouched] = useState<Record<number, boolean>>({})\n\n const groupsRef = useRef(groups)\n groupsRef.current = groups\n const statesRef = useRef(states)\n statesRef.current = states\n // latest-fn pattern (mirrors useLiveMonitor's getLiveMonitorRef): tick reads the ref, so an\n // inline getStates lambda handed in fresh on every render cannot tear down and recreate the\n // poll interval.\n const getStatesRef = useRef(opts.getStates)\n getStatesRef.current = opts.getStates\n\n const pinnedKey = opts.pinnedMatchIds.join(',')\n\n // A widget left mounted across midnight has to move to the new day, or it holds yesterday's\n // fixtures forever with an empty due set and no polling. Cheap enough to check on a coarse\n // interval; the state only ever changes value once a day, so it re-renders once a day.\n const [localDate, setLocalDate] = useState(() => localDateOf(new Date()))\n useEffect(() => {\n const id = setInterval(() => {\n const next = localDateOf(new Date())\n setLocalDate((prev) => (prev === next ? prev : next))\n }, ROLLOVER_CHECK_MS)\n return () => clearInterval(id)\n }, [])\n\n // `states` is deliberately NOT cleared here: a 23:00 fixture still playing at 00:30 belongs to\n // neither day's window, and dropping its state would blank a score that is still true.\n useEffect(() => {\n let cancelled = false\n // getTimezoneOffset is minutes WEST of UTC, so Istanbul reports -180 for UTC+3.\n const utcOffsetMinutes = -new Date().getTimezoneOffset()\n\n const cached = readSchedule(opts.operatorId, localDate, Date.now())\n if (cached) {\n if (!cancelled) setGroups(cached.groups)\n return () => { cancelled = true }\n }\n\n void (async () => {\n try {\n const payload = await opts.getSchedule(localDate, utcOffsetMinutes)\n if (cancelled || !payload) return\n writeSchedule(opts.operatorId, localDate, payload, Date.now())\n setGroups(payload.groups)\n } catch {\n // Fixtures do not move, so an expired day beats an empty tab.\n const fallback = readScheduleIgnoringTtl(opts.operatorId, localDate)\n if (!cancelled && fallback) setGroups(fallback.groups)\n }\n })()\n\n return () => { cancelled = true }\n }, [opts.operatorId, localDate])\n\n useEffect(() => {\n setExpanded((prev) => {\n const next: Record<number, boolean> = {}\n for (const group of groups) {\n const hasPin = group.matches.some((m) => opts.pinnedMatchIds.includes(m.matchId))\n const seeded = group.expandedByDefault || hasPin\n next[group.competitionId] = touched[group.competitionId]\n ? (prev[group.competitionId] ?? seeded)\n : seeded\n }\n return next\n })\n }, [groups, pinnedKey, touched])\n\n const tick = useCallback(async () => {\n const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now())\n if (ids.length === 0) return\n try {\n const payload = await getStatesRef.current(ids)\n if (!payload) return\n setStates((prev) => {\n // Retained rather than replaced: a finished match keeps its final score after it leaves\n // the due set.\n const next = { ...prev }\n for (const state of payload.states) next[state.matchId] = state\n return next\n })\n setFailures(0)\n } catch {\n setFailures((n) => n + 1)\n }\n }, [])\n\n // `groups` is in the deps (beyond `tick`, which is now stable) so a schedule fetch that\n // resolves after the mount-time tick above gets an immediate follow-up poll, rather than\n // stranding the newly-loaded due set until the next 60s tick.\n useEffect(() => {\n if (!opts.isOpen) return\n void tick()\n const id = setInterval(() => { void tick() }, POLL_MS)\n return () => clearInterval(id)\n }, [opts.isOpen, tick, groups])\n\n const stale = failures >= STALE_AFTER_FAILURES\n\n const liveCount = useMemo(\n () => (stale\n ? 0\n // A match whose own reading has gone stale stops counting: a stalled window must not hold\n // the badge up at 1 for the rest of the day.\n : Object.values(states).filter((s) => s.phase === 'live').length),\n [states, stale],\n )\n\n const toggleGroup = useCallback((competitionId: number) => {\n setTouched((prev) => ({ ...prev, [competitionId]: true }))\n setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }))\n }, [])\n\n return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick }\n}\n","import type { SchedulePayload } from '@sensiblestats/widget-sdk'\n\nconst PREFIX = 'ss-w-schedule:'\nconst SCHEMA_VERSION = 1\nconst TTL_MS = 6 * 3600_000\n\ninterface Entry {\n v: number\n at: number\n payload: SchedulePayload\n}\n\nexport function scheduleCacheKey(operatorId: string, localDate: string): string {\n return `${PREFIX}${operatorId}:${localDate}`\n}\n\nfunction read(operatorId: string, localDate: string): Entry | null {\n try {\n const raw = localStorage.getItem(scheduleCacheKey(operatorId, localDate))\n if (!raw) return null\n const entry = JSON.parse(raw) as Entry\n // A wire change bumps SCHEMA_VERSION; without this an old entry deserializes into the new\n // shape and renders fields that are no longer there.\n if (entry.v !== SCHEMA_VERSION || !entry.payload) return null\n return entry\n } catch {\n return null\n }\n}\n\nexport function readSchedule(operatorId: string, localDate: string, nowMs: number): SchedulePayload | null {\n const entry = read(operatorId, localDate)\n if (!entry) return null\n return nowMs - entry.at > TTL_MS ? null : entry.payload\n}\n\n/** The /schedule-failed path: fixtures do not move, so a stale day beats an empty tab. */\nexport function readScheduleIgnoringTtl(operatorId: string, localDate: string): SchedulePayload | null {\n return read(operatorId, localDate)?.payload ?? null\n}\n\n// The cache is skeleton-only by construction, not by convention: a payload is rebuilt\n// field-by-field here so an excess live-state field on the wire can never be persisted.\nfunction skeletonOnly(payload: SchedulePayload): SchedulePayload {\n return {\n localDate: payload.localDate,\n groups: payload.groups.map((g) => ({\n competitionId: g.competitionId,\n competitionName: g.competitionName,\n competitionImagePath: g.competitionImagePath ?? null,\n rank: g.rank,\n expandedByDefault: g.expandedByDefault,\n matches: g.matches.map((m) => ({\n matchId: m.matchId,\n homeTeamName: m.homeTeamName,\n awayTeamName: m.awayTeamName,\n homeTeamImagePath: m.homeTeamImagePath ?? null,\n awayTeamImagePath: m.awayTeamImagePath ?? null,\n kickoffUnix: m.kickoffUnix,\n })),\n })),\n }\n}\n\nexport function writeSchedule(\n operatorId: string, localDate: string, payload: SchedulePayload, nowMs: number,\n): void {\n const keep = scheduleCacheKey(operatorId, localDate)\n const mine = `${PREFIX}${operatorId}:`\n try {\n // Scoped to this operator: two operators can share a browser, and pruning the whole prefix\n // would evict the other one's day on every write.\n for (let i = localStorage.length - 1; i >= 0; i--) {\n const key = localStorage.key(i)\n if (key && key.startsWith(mine) && key !== keep) localStorage.removeItem(key)\n }\n const entry: Entry = { v: SCHEMA_VERSION, at: nowMs, payload: skeletonOnly(payload) }\n localStorage.setItem(keep, JSON.stringify(entry))\n } catch {\n // A full or blocked localStorage must not break the tab; the schedule refetches next mount.\n }\n}\n","import type { ScheduleGroup, MatchState } from '@sensiblestats/widget-sdk'\n\n// Phases that never change again, so one answer is the last answer we need. Everything else --\n// preMatch (the clock passed but the feed has not flipped yet) and live -- is still moving.\nconst TERMINAL_PHASES: ReadonlySet<string> = new Set(['fullTime', 'postponed'])\n\n/**\n * Which of today's matches to ask about. Anything past its kickoff clock that has not yet given us\n * a terminal answer, and nothing else.\n *\n * This replaced a fixed 3.5-hour window after kickoff. The window bounded the REQUEST, but on a\n * cold load it also silently bounded what we could ever KNOW: open the widget at 15:13 and a match\n * that kicked off at 11:00 was already outside it, so it was never asked about, had no state, and\n * rendered as a fixture that had not started -- kickoff time, no score -- four hours after it\n * finished 0-1. Matches inside the window showed FT correctly, which is why only the older half of\n * the day looked wrong.\n *\n * Terminating on the answer rather than on the clock is also strictly cheaper in the steady state:\n * every finished match drops out permanently after one reply, so a late-evening poll carries only\n * what is actually still playing. The schedule is one day, and the endpoint caps at 200 ids.\n */\nexport function dueMatchIds(\n groups: ScheduleGroup[], states: Record<number, MatchState>, nowMs: number,\n): number[] {\n const due = new Set<number>()\n\n for (const group of groups) {\n for (const match of group.matches) {\n if (nowMs - match.kickoffUnix * 1000 < 0) continue\n const phase = states[match.matchId]?.phase\n if (phase !== undefined && TERMINAL_PHASES.has(phase)) continue\n due.add(match.matchId)\n }\n }\n\n return [...due]\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { GameListPayload, GameSummary } from '@sensiblestats/widget-sdk'\nimport type { WidgetTab } from './useTabs'\n\nconst GAMES_POLL_MS = 60_000\nconst DEFAULT_TZ = 'Europe/London'\n\nfunction computeGameDay(timezone: string): string {\n // en-CA uses YYYY-MM-DD format\n return new Intl.DateTimeFormat('en-CA', { timeZone: timezone }).format(new Date())\n}\n\nexport interface UseGamesResult {\n enabled: boolean\n games: GameSummary[]\n loading: boolean\n refresh: () => void\n}\n\nexport function useGames(\n conversation: { getGames: (gameDay?: string) => Promise<GameListPayload | null> } | null | undefined,\n { activeTab, operatorTimezone }: { activeTab: WidgetTab; operatorTimezone?: string },\n): UseGamesResult {\n // Games/Leaderboard tabs are hidden until we KNOW this operator has games. Every operator shares\n // one games backend, so a non-games operator does not 404 — it returns 200 with an empty list.\n // Gating on games.length (not on the 404 sentinel) is what keeps the tabs off those operators;\n // defaulting to false avoids flashing the tabs on every operator during the first fetch.\n const [enabled, setEnabled] = useState(false)\n const [games, setGames] = useState<GameSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [refreshCount, setRefreshCount] = useState(0)\n\n const inFlightRef = useRef(false)\n // Set only when the feature is entirely off for this operator (backend 404). Stops all polling —\n // distinct from \"enabled\", which merely reflects whether today's list has any games.\n const hardOffRef = useRef(false)\n const conversationRef = useRef(conversation)\n conversationRef.current = conversation\n const tzRef = useRef(operatorTimezone ?? DEFAULT_TZ)\n tzRef.current = operatorTimezone ?? DEFAULT_TZ\n\n // The conversation is often null on first render and set once the widget finishes initialising.\n // It is intentionally NOT read through the ref in the effect deps — the effect must re-run when\n // it becomes available, or the one-shot fetch never fires and the tabs never appear. (Defaulting\n // `enabled` to true used to paper over this; gating on the games list means we must actually\n // fetch.)\n const ready = conversation != null\n\n useEffect(() => {\n if (hardOffRef.current) return\n let active = true\n\n const doFetch = async (): Promise<void> => {\n const conv = conversationRef.current\n if (!conv || inFlightRef.current || !active) return\n inFlightRef.current = true\n setLoading(true)\n try {\n const gameDay = computeGameDay(tzRef.current)\n const result = await conv.getGames(gameDay)\n if (!active) return\n if (result === null) {\n // 404: games feature is not enabled for this operator at all — hide and stop polling.\n hardOffRef.current = true\n setEnabled(false)\n setGames([])\n } else {\n // 200: show the tabs only when this operator actually has games today.\n setGames(result.games)\n setEnabled(result.games.length > 0)\n }\n } catch {\n // swallow; retry next tick\n } finally {\n inFlightRef.current = false\n if (active) setLoading(false)\n }\n }\n\n // Always fetch once on mount or refresh\n void doFetch()\n\n // Poll while the games tab is active\n let intervalId: number | undefined\n if (activeTab === 'games') {\n intervalId = window.setInterval(() => {\n if (hardOffRef.current) {\n window.clearInterval(intervalId)\n return\n }\n void doFetch()\n }, GAMES_POLL_MS)\n }\n\n return () => {\n active = false\n // Release the in-flight guard so a remount (React StrictMode double-invokes effects, and any\n // dependency change re-runs this one) can fetch again. Without this, the first run's request\n // is still in flight when the second run checks the guard, the second run bails, and the\n // first run's result is dropped because `active` is now false — so `enabled` is never set.\n inFlightRef.current = false\n if (intervalId !== undefined) window.clearInterval(intervalId)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, refreshCount, ready])\n\n const refresh = useCallback(() => {\n setRefreshCount((c) => c + 1)\n }, [])\n\n return { enabled, games, loading, refresh }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { WidgetTab } from './useTabs'\n\nexport interface UseLeaderboardResult {\n data: LeaderboardPayload | null\n loading: boolean\n refresh: () => void\n}\n\nexport function useLeaderboard(\n conversation: { getLeaderboard: () => Promise<LeaderboardPayload | null> } | null | undefined,\n { activeTab }: { activeTab: WidgetTab },\n): UseLeaderboardResult {\n const [data, setData] = useState<LeaderboardPayload | null>(null)\n const [loading, setLoading] = useState(false)\n const [refreshCount, setRefreshCount] = useState(0)\n\n const inFlightRef = useRef(false)\n const conversationRef = useRef(conversation)\n conversationRef.current = conversation\n\n useEffect(() => {\n if (activeTab !== 'leaderboard') return\n let active = true\n\n const doFetch = async (): Promise<void> => {\n const conv = conversationRef.current\n if (!conv || inFlightRef.current) return\n inFlightRef.current = true\n setLoading(true)\n try {\n const result = await conv.getLeaderboard()\n if (active) setData(result)\n } catch {\n // swallow; keep previous data\n } finally {\n inFlightRef.current = false\n if (active) setLoading(false)\n }\n }\n\n void doFetch()\n return () => { active = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, refreshCount])\n\n const refresh = useCallback(() => {\n setRefreshCount((c) => c + 1)\n }, [])\n\n return { data, loading, refresh }\n}\n","import type { MatchState, ScheduleGroup } from '@sensiblestats/widget-sdk'\n\n/**\n * The single question \"is this match being presented as live right now\". Both sides of the seam\n * must ask it the same way: TodayPanel uses it to pick the live band, CompetitionGroup uses its\n * negation to decide what stays in the group. If the two ever disagree a match falls through the\n * gap and renders nowhere — that is a defect this codebase has already shipped once.\n *\n * `pollStale` is OUR fetch failing, which is a real reason to stop trusting every state at once.\n * There is deliberately no per-match staleness test here; see the note in FixtureRow.\n */\nexport function isTreatedLive(state: MatchState | undefined, pollStale: boolean): boolean {\n return state?.phase === 'live' && !pollStale\n}\n\n/**\n * A match the Today tab has no reason to keep listing. The schedule endpoint already excludes\n * terminal matches server-side (LiveMonitorScheduleComposer filters Match.MatchState), but the\n * client caches a day's schedule in localStorage for six hours — so a match that finishes while\n * the panel is open would linger in a list a fresh load would not show it in. This closes that\n * gap so both paths agree.\n *\n * fullTime only, deliberately. `postponed` arises server-side when a fixture has no kickoff\n * timestamp, which the schedule query already excludes, and hiding a postponed fixture from the\n * day it was scheduled for would be a different decision than the one being made here.\n */\nexport function isFinished(state: MatchState | undefined): boolean {\n return state?.phase === 'fullTime'\n}\n\n/**\n * What the Today tab actually contains, after the finished matches leave. This is the ONE answer\n * both the panel and the tab strip read: TodayPanel renders it, and `hasToday` decides from its\n * length whether the tab exists at all. Deciding the tab from the raw schedule instead is what\n * shipped a Today tab opening onto a blank panel once every match of the day had ended.\n */\nexport function visibleGroupsOf(\n groups: readonly ScheduleGroup[],\n states: Record<number, MatchState>,\n): ScheduleGroup[] {\n return groups\n .map((group) => ({ ...group, matches: group.matches.filter((m) => !isFinished(states[m.matchId])) }))\n .filter((group) => group.matches.length > 0)\n}\n","import { createContext, useContext } from 'react'\nimport type { EventLogger } from '@sensiblestats/widget-sdk'\n\nexport const EventLogContext = createContext<EventLogger | null>(null)\n\nexport function useEventLog(): EventLogger | null {\n return useContext(EventLogContext)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { BrandMark } from './BrandMark'\nimport { GreetingBubble } from './GreetingBubble'\n\n// Only rendered while the panel is closed. The dynamic greeting popup takes\n// precedence over the static greeting and is dismissable; both open the panel.\n//\n// introAllowed/onIntroStart drive the one-shot attention animation (the FAB\n// nudges, then the greeting types in). The latch below fires it once, the first\n// time a bubble appears; onIntroStart lets the parent record that so it never\n// replays when the FAB remounts on a later panel close. Refreshing the page\n// remounts the whole widget and re-arms it.\nexport function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = 'Dismiss', introAllowed = false, onIntroStart }: { label: string; greeting?: string; popupText?: string | null; logoUrl?: string; onOpen: () => void; onDismissPopup: () => void; dismissLabel?: string; introAllowed?: boolean; onIntroStart?: () => void }): JSX.Element {\n const bubble = popupText ?? greeting\n const [intro, setIntro] = useState(false)\n const armedRef = useRef(introAllowed)\n useEffect(() => {\n if (armedRef.current && bubble) {\n armedRef.current = false\n setIntro(true)\n onIntroStart?.()\n }\n }, [bubble, onIntroStart])\n return (\n <div className={intro ? 'ss-w-fab-wrap ss-w-intro' : 'ss-w-fab-wrap'}>\n {bubble ? <GreetingBubble text={bubble} onOpen={onOpen} onDismiss={popupText ? onDismissPopup : undefined} dismissLabel={dismissLabel} /> : null}\n <button type=\"button\" className=\"ss-w-fab\" aria-label={label} onClick={onOpen}>\n <BrandMark logoUrl={logoUrl} className=\"ss-w-fab-mark\" />\n </button>\n </div>\n )\n}\n","import { useState } from 'react'\nimport { SsMark } from './Icons'\n\n// Operator logo with a hard fallback to the built-in SS mark: a missing or\n// broken logoUrl must never leave a blank in the header or launcher.\nexport function BrandMark({ logoUrl, className }: { logoUrl?: string; className?: string }): JSX.Element {\n const [failed, setFailed] = useState(false)\n if (!logoUrl || failed) return <SsMark className={className} />\n return <img className={className} src={logoUrl} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n}\n","// SensibleStats brand mark, inlined as a data URI so the published widget\n// bundle stays self-contained (no external asset hosting / CORS concerns\n// for third-party embeds).\nexport const SS_LOGO_DATA_URI = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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\"\n","// SensibleStats brand mark, rendered from the official logo asset.\nimport { SS_LOGO_DATA_URI } from '../assets/logo'\n\nexport function SsMark({ className }: { className?: string }): JSX.Element {\n return <img className={className} src={SS_LOGO_DATA_URI} alt=\"\" aria-hidden=\"true\" />\n}\nexport function SendIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M3 20l18-8L3 4v6l12 2-12 2z\" /></svg>\n}\nexport function CloseIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" d=\"M18 6L6 18M6 6l12 12\" stroke=\"currentColor\" strokeWidth=\"2\" /></svg>\n}\nexport function ChevronIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 5l7 7-7 7\" /></svg>\n}\nexport function NewChatIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" d=\"M12 5v14M5 12h14\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" /></svg>\n}\nexport function KebabIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><g fill=\"currentColor\"><circle cx=\"12\" cy=\"5\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"19\" r=\"1.6\" /></g></svg>\n}\n\n// Dashboard tile icons are emoji (matching the betting widget mockup), not the old monochrome\n// line glyphs: they carry their own colour and read at a larger size. Rendered as text.\nconst DASHBOARD_EMOJI: Record<string, string> = {\n football: '⚽', 'goal-net': '🥅', btts: '🤝',\n card: '🟨', 'corner-flag': '🚩', player: '👤',\n target: '🎯', trophy: '🏆', 'chart-line': '📈',\n 'chart-bar': '📊', chat: '💬', fire: '🔥', sparkle: '✨',\n}\n\nexport function DashboardIcon({ name }: { name: string }): JSX.Element {\n // hasOwnProperty (not `in`, not `?? fallback`) so a prototype member name like 'toString'\n // resolves to the fallback emoji rather than an inherited function or a stray property value.\n const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name)\n ? DASHBOARD_EMOJI[name]\n : DASHBOARD_EMOJI.target\n return <span className=\"ss-w-dash-emoji\" aria-hidden=\"true\">{glyph}</span>\n}\n","export function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = 'Dismiss' }: { text: string; onOpen?: () => void; onDismiss?: () => void; dismissLabel?: string }): JSX.Element {\n return (\n <div className=\"ss-w-greeting\" role=\"note\">\n <button type=\"button\" className=\"ss-w-greeting-body\" onClick={onOpen}>\n <span className=\"ss-w-greeting-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span>\n <span className=\"ss-w-greeting-text\">{text}</span>\n </button>\n {onDismiss ? (\n <button type=\"button\" className=\"ss-w-greeting-x\" aria-label={dismissLabel} onClick={onDismiss}>×</button>\n ) : null}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { GameSummary, LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { DashboardTapHandler } from '../dashboardTap'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { MatchDiscoveryController } from '../useMatchDiscovery'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { TabBar } from './TabBar'\nimport { MatchesPanel, OddsPanel } from './MonitorTabs'\nimport { TodayPanel } from './TodayPanel'\nimport { GamesPanel } from './GamesPanel'\nimport { LeaderboardPanel } from './LeaderboardPanel'\nimport { visibleGroupsOf } from '../liveClock'\n\n// Mirrors the panel's fullscreen breakpoint in widget.css (@media max-width: 639px).\n// The panel only traps the page — and is thus truly modal — when it fills the viewport.\nconst FULLSCREEN_QUERY = '(max-width: 639px)'\n\nfunction useIsModal(): boolean {\n const [modal, setModal] = useState(false)\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n const mql = window.matchMedia(FULLSCREEN_QUERY)\n const sync = (): void => setModal(mql.matches)\n sync()\n mql.addEventListener('change', sync)\n return () => mql.removeEventListener('change', sync)\n }, [])\n return modal\n}\n\nexport function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }: {\n controller: ChatController\n ui: UiConfig\n slip: SlipHandlerProps\n onDashboardTap?: DashboardTapHandler\n /** Optional -- absent (feature off / not threaded) renders today's DOM byte-identically. */\n monitor?: LiveMonitorController\n /** Optional -- absent means the Today tab never qualifies (see hasToday below). */\n discovery?: MatchDiscoveryController\n /** Games hook result; absent for non-club operators. */\n gamesResult?: { enabled: boolean; games: GameSummary[]; loading: boolean; refresh: () => void }\n /** Leaderboard hook result; absent for non-club operators. */\n leaderboardResult?: { data: LeaderboardPayload | null; loading: boolean; refresh: () => void }\n /** True when the operator user is logged in (operatorUserId is set). */\n loggedIn?: boolean\n /** Conversation instance threaded down to GameScreenHost for game config fetching + play submits. */\n conversation?: GamePlayConversation | null\n}): JSX.Element {\n const { state, close, stop, send, reset } = controller\n const isModal = useIsModal()\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close() }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [close])\n\n // Composer always switches the visible tab to chat BEFORE the message is sent, so a reply\n // streaming in is never invisible behind the Matches/Odds tab.\n const handleSend = (text: string) => {\n monitor?.setActiveTab('chat')\n send(text)\n }\n\n // A reply landing while the user is on another tab must surface the chat dot -- markChatActivity\n // is idempotent (setChatDot(true) on an already-true dot is a no-op re-render), so re-running\n // this on every streaming/message-count change is safe.\n useEffect(() => {\n if (monitor && monitor.activeTab !== 'chat' && state.isStreaming) monitor.markChatActivity()\n }, [monitor, state.isStreaming, state.messages.length])\n\n return (\n <div className=\"ss-w-panel\" role=\"dialog\" aria-modal={isModal} aria-label={ui.chatDialogLabel}>\n <ChatHeader\n onClose={close}\n closeLabel={ui.closeChat}\n logoUrl={ui.logoUrl}\n headerTitle={ui.headerTitle}\n onNewConversation={reset}\n canReset={state.messages.length > 0}\n newConversationLabel={ui.newConversation}\n moreOptionsLabel={ui.moreOptions}\n />\n {monitor && (\n <TabBar\n monitor={monitor}\n ui={ui}\n matchCount={monitor.pins.filter((p) => p.kind === 'match').length}\n oddsCount={monitor.pins.filter((p) => p.kind !== 'match').length}\n todayCount={discovery?.liveCount ?? 0}\n hasToday={discovery ? visibleGroupsOf(discovery.groups, discovery.states).length > 0 : false}\n gamesEnabled={gamesResult?.enabled ?? false}\n />\n )}\n {/* MessageList stays MOUNTED across tab switches so its scroll-anchoring refs survive --\n `display: contents` makes the wrapper transparent to .ss-w-panel's flex layout when the\n chat tab is active. `display: none` would zero the list's clientHeight and reset its\n scrollTop, defeating MessageList's own scroll-anchoring math (and silently consuming its\n reserved-turn-space effect) the moment a tab switch happens mid-stream. Absolute-position\n + visibility:hidden instead: the list keeps its box (so its scroll position survives) but\n is pulled out of .ss-w-panel's flex flow (so it doesn't fight the active panel for space)\n and is neither painted nor interactive. `.ss-w-panel` is `position: fixed`, which already\n serves as the containing block for this. */}\n <div\n style={\n !monitor || monitor.activeTab === 'chat'\n ? { display: 'contents' }\n // display:flex (not the default block) is required here: MessageList's root carries\n // `.ss-w-list { flex: 1; ... }`, which only takes effect on a flex-item child. Without\n // it this wrapper lays out as a plain block, .ss-w-list collapses to its own\n // content height (no longer clipped by .ss-w-panel's fixed height), scrollHeight\n // drops to equal clientHeight, and the browser clamps its scrollTop to 0 --\n // silently destroying the exact scroll position this hidden-not-unmounted\n // wrapper exists to preserve.\n : { position: 'absolute', inset: 0, visibility: 'hidden', display: 'flex', flexDirection: 'column' }\n }\n >\n <MessageList controller={controller} ui={ui} slip={slip} onDashboardTap={onDashboardTap} monitor={monitor} />\n </div>\n {monitor && discovery && monitor.activeTab === 'today' && <TodayPanel discovery={discovery} ui={ui} monitor={monitor} />}\n {monitor && monitor.activeTab === 'following' && <MatchesPanel monitor={monitor} ui={ui} slip={slip} />}\n {monitor && monitor.activeTab === 'odds' && <OddsPanel monitor={monitor} ui={ui} slip={slip} />}\n {monitor && monitor.activeTab === 'games' && gamesResult && (\n <GamesPanel loggedIn={!!loggedIn} games={gamesResult.games} ui={ui} conversation={conversation} />\n )}\n {monitor && monitor.activeTab === 'leaderboard' && leaderboardResult && (\n <LeaderboardPanel\n loggedIn={!!loggedIn}\n data={leaderboardResult.data}\n loading={leaderboardResult.loading}\n onPlay={() => monitor.setActiveTab('games')}\n ui={ui}\n />\n )}\n {/* The composer is a chat affordance; hide it on the Games/Leaderboard tabs where it only confuses. */}\n {(!monitor || (monitor.activeTab !== 'games' && monitor.activeTab !== 'leaderboard')) && (\n <ChatInput placeholder={ui.placeholder} streaming={state.isStreaming} onSend={handleSend} onStop={stop} stopLabel={ui.stopResponse} sendLabel={ui.sendMessage} />\n )}\n </div>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { CloseIcon, KebabIcon } from './Icons'\nimport { BrandMark } from './BrandMark'\n\nexport function ChatHeader({\n onClose,\n closeLabel = 'Close chat',\n logoUrl,\n headerTitle,\n onNewConversation,\n canReset,\n newConversationLabel = 'New conversation',\n moreOptionsLabel = 'More options',\n}: {\n onClose: () => void\n closeLabel?: string\n logoUrl?: string\n headerTitle?: string\n onNewConversation?: () => void\n canReset?: boolean\n newConversationLabel?: string\n moreOptionsLabel?: string\n}): JSX.Element {\n const [menuOpen, setMenuOpen] = useState(false)\n const wrapRef = useRef<HTMLDivElement>(null)\n const kebabRef = useRef<HTMLButtonElement>(null)\n const firstItemRef = useRef<HTMLButtonElement>(null)\n\n // Secondary actions (currently just \"New conversation\") live behind the kebab; Close stays a\n // one-tap control since it is the most frequent action.\n const hasMenu = !!(canReset && onNewConversation)\n\n useEffect(() => {\n if (menuOpen) firstItemRef.current?.focus()\n }, [menuOpen])\n\n useEffect(() => {\n if (!menuOpen) return\n const onPointer = (e: MouseEvent) => {\n if (!wrapRef.current?.contains(e.target as Node)) setMenuOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setMenuOpen(false)\n kebabRef.current?.focus()\n }\n }\n document.addEventListener('mousedown', onPointer)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onPointer)\n document.removeEventListener('keydown', onKey)\n }\n }, [menuOpen])\n\n const runNewConversation = (): void => {\n setMenuOpen(false)\n onNewConversation?.()\n }\n\n return (\n <header className=\"ss-w-header\">\n <BrandMark logoUrl={logoUrl} className=\"ss-w-header-mark\" />\n <span className=\"ss-w-header-title\">{headerTitle ?? 'SensibleStats'}</span>\n {hasMenu ? (\n <div className=\"ss-w-menu-wrap\" ref={wrapRef}>\n <button\n type=\"button\"\n className=\"ss-w-kebab\"\n ref={kebabRef}\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n aria-label={moreOptionsLabel}\n onClick={() => setMenuOpen((open) => !open)}\n >\n <KebabIcon />\n </button>\n {menuOpen ? (\n <div className=\"ss-w-menu\" role=\"menu\" aria-label={moreOptionsLabel}>\n <button\n type=\"button\"\n className=\"ss-w-menu-item\"\n role=\"menuitem\"\n ref={firstItemRef}\n onClick={runNewConversation}\n >\n <span>{newConversationLabel}</span>\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <button type=\"button\" className=\"ss-w-close\" aria-label={closeLabel} onClick={onClose}>\n <CloseIcon />\n </button>\n </header>\n )\n}\n","import { useEffect, useRef } from 'react'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { DashboardTapHandler } from '../dashboardTap'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { ChatMessage } from './ChatMessage'\nimport { IntentChips } from './IntentChips'\nimport { ActionButtons } from './ActionButtons'\nimport { isPinnedToBottom } from '../scroll'\nimport type { Message } from '../reducer'\n\n// The element to pin to the top when a new turn begins: the user's question if\n// this turn has one (so the reply reads from just below it), otherwise the\n// assistant turn itself (an auto-greeting or greeting dashboard has no user\n// bubble, and we still want its top in view rather than its bottom).\nfunction turnAnchor(messages: Message[]): { turnId: string; anchorId: string } | null {\n const last = messages[messages.length - 1]\n if (!last || last.role !== 'assistant') return null\n const prev = messages[messages.length - 2]\n return { turnId: last.id, anchorId: prev && prev.role === 'user' ? prev.id : last.id }\n}\n\nexport function MessageList({ controller, ui, slip, onDashboardTap, monitor }: {\n controller: ChatController\n ui: UiConfig\n slip: SlipHandlerProps\n onDashboardTap?: DashboardTapHandler\n monitor?: LiveMonitorController\n}): JSX.Element {\n const { state, send } = controller\n const listRef = useRef<HTMLDivElement>(null)\n const endRef = useRef<HTMLDivElement>(null)\n // Follow the stream only while the user is at the bottom. pinnedRef is updated\n // on real scroll events (content growth fires none), so a user who scrolls up\n // stays put when late content — suggested actions, status — arrives.\n const pinnedRef = useRef(true)\n // The turn id we have already anchored to the top. On a new turn we pin its\n // start to the top so a long reply reads from its beginning instead of the\n // viewport jumping to the bottom of the answer.\n const anchoredTurnRef = useRef<string | null>(null)\n useEffect(() => {\n const anchor = turnAnchor(state.messages)\n const list = listRef.current\n if (anchor && anchor.turnId !== anchoredTurnRef.current) {\n anchoredTurnRef.current = anchor.turnId\n // Reserve a viewport of space below the new turn before scrolling, so the\n // anchor can actually reach the top even while the reply is still empty\n // (without it the scroll lands at the bottom, onScroll re-pins to bottom,\n // and the streaming reply then follows the bottom down). The spacer is the\n // endRef element; it collapses again once the turn stops streaming.\n //\n // Only reserve while the turn is actively streaming. A turn first anchored\n // when it is ALREADY complete -- panel opened after the greeting finished,\n // or a restored/cross-tab-synced conversation -- has its full height, so it\n // needs no spacer; reserving one here would never be collapsed (this branch\n // returns, and the collapse below only runs on a later !isStreaming pass\n // that never comes), leaving a viewport of dead scroll space below content.\n if (endRef.current && list) endRef.current.style.height = state.isStreaming ? `${list.clientHeight}px` : ''\n // Top-anchored, so the list is no longer pinned to the bottom; streaming\n // updates below won't yank it back down for the rest of this turn.\n pinnedRef.current = false\n list?.querySelector(`[data-msg-id=\"${anchor.anchorId}\"]`)?.scrollIntoView({ block: 'start' })\n return\n }\n // Turn finished: drop the reserved space (content above is unaffected, so the\n // anchored message keeps its position).\n if (!state.isStreaming && endRef.current) endRef.current.style.height = ''\n if (pinnedRef.current) endRef.current?.scrollIntoView({ block: 'end' })\n }, [state.messages, state.status, state.isStreaming])\n\n // Chips are always emitted by the server; the widget prefers the dashboard and\n // hides the chips client-side once a greeting dashboard, a club fan dashboard, or a\n // user message exists.\n const hasUserMessage = state.messages.some((m) => m.role === 'user')\n const hasDashboard = state.messages.some((m) => m.role === 'assistant' && (m.greetingDashboard || m.clubFanDashboard))\n return (\n <div\n className=\"ss-w-list\"\n aria-live=\"polite\"\n ref={listRef}\n onScroll={() => { if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current) }}\n >\n {state.messages.map((m) => (\n <ChatMessage\n key={m.id}\n message={m}\n disabled={state.isStreaming}\n onAct={(a) => send(a.message, { actionId: a.actionId, actionRef: a.actionRef, displayText: a.label })}\n onTap={(tile, index) => {\n send(tile.actionValue, tile.actionRef\n ? { actionRef: tile.actionRef, displayText: tile.title }\n : { displayText: tile.title })\n // Only fires from within the dashboard this message itself rendered (ChatMessage\n // renders GreetingDashboard only when message.greetingDashboard is set), so the\n // dashboard -- and its layout -- is guaranteed present here.\n if (m.role === 'assistant' && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout)\n }}\n ui={ui}\n slip={slip}\n monitor={monitor}\n />\n ))}\n {state.isStreaming && state.actionsLoading ? <ActionButtons actions={[]} loading onAct={() => {}} /> : null}\n {state.status ? <div className=\"ss-w-status\">{state.status}</div> : null}\n {state.error ? (\n <div className=\"ss-w-error\" role=\"alert\">\n <span>{'message' in state.error ? state.error.message : ui.somethingWentWrong}</span>\n <button type=\"button\" className=\"ss-w-retry\" onClick={() => controller.retry()}>{ui.retry}</button>\n </div>\n ) : null}\n {!hasUserMessage && !hasDashboard ? <IntentChips chips={state.starters} onPick={(t) => send(t)} /> : null}\n <div ref={endRef} className=\"ss-w-turn-spacer\" aria-hidden=\"true\" />\n </div>\n )\n}\n","import ReactMarkdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst components: Components = {\n a: ({ children, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"ss-w-md-link\">{children}</a>\n ),\n table: ({ children }) => (\n <div className=\"ss-w-table-wrap\"><table className=\"ss-w-md-table\">{children}</table></div>\n ),\n ul: ({ children }) => <ul className=\"ss-w-md-ul\">{children}</ul>,\n ol: ({ children }) => <ol className=\"ss-w-md-ol\">{children}</ol>,\n code: ({ children }) => <code className=\"ss-w-md-code\">{children}</code>,\n}\n\nexport function Markdown({ text }: { text: string }): JSX.Element {\n return (\n <div className=\"ss-w-md\">\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>{text}</ReactMarkdown>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { CardVM, CardScope, StatCell } from '../model'\n\nconst MAX_VISIBLE = 3\nconst RECORD_RE = /^(\\d+)-(\\d+)-(\\d+)$/\n\nfunction initials(name: string): string {\n return name.split(/\\s+/).slice(0, 2).map((w) => w[0] ?? '').join('').toUpperCase()\n}\n\n// \"2026/2027\" -> \"26/27\", \"2026\" -> \"26\"; leaves any non-4-digit token untouched.\nfunction shortSeason(season: string): string {\n return season.replace(/\\d{4}/g, (year) => year.slice(2))\n}\n\nfunction Crest({ image, label }: { image: string; label?: string }): JSX.Element {\n return (\n <span\n className=\"ss-w-ecard-crest\"\n style={{ backgroundImage: `url(${image})` }}\n {...(label ? { role: 'img', title: label, 'aria-label': label } : { 'aria-hidden': 'true' as const })}\n />\n )\n}\n\n// Proportional win/draw/loss bar. Rendered for any stat value shaped \"w-d-l\".\nfunction FormBar({ w, d, l }: { w: number; d: number; l: number }): JSX.Element | null {\n if (w + d + l === 0) return null\n return (\n <span className=\"ss-w-form\" aria-hidden=\"true\">\n {w > 0 ? <span className=\"ss-w-form-w\" style={{ flexGrow: w }} /> : null}\n {d > 0 ? <span className=\"ss-w-form-d\" style={{ flexGrow: d }} /> : null}\n {l > 0 ? <span className=\"ss-w-form-l\" style={{ flexGrow: l }} /> : null}\n </span>\n )\n}\n\nfunction StatCellView({ s }: { s: StatCell }): JSX.Element {\n const m = RECORD_RE.exec(s.value)\n if (m) {\n return (\n <div className=\"ss-w-ecard-cell\">\n <span className=\"ss-w-ecard-cval\"><FormBar w={Number(m[1])} d={Number(m[2])} l={Number(m[3])} /></span>\n <span className=\"ss-w-ecard-clabel\">{s.value}</span>\n </div>\n )\n }\n return (\n <div className=\"ss-w-ecard-cell\">\n <span className=\"ss-w-ecard-cval\">{s.value}</span>\n <span className=\"ss-w-ecard-clabel\">{s.label}</span>\n </div>\n )\n}\n\nfunction StatStrip({ stats }: { stats: StatCell[] }): JSX.Element | null {\n if (stats.length === 0) return null\n const cols = Math.min(stats.length, 4)\n return (\n <div className=\"ss-w-ecard-strip\" style={{ gridTemplateColumns: `repeat(${cols}, 1fr)` }}>\n {stats.map((s) => <StatCellView key={s.label + s.value} s={s} />)}\n </div>\n )\n}\n\nfunction CardHeader({ c, showScopeCrest }: { c: CardVM; showScopeCrest: boolean }): JSX.Element {\n const onlyScope = c.scopes.length === 1 ? c.scopes[0]! : null\n return (\n <div className=\"ss-w-ecard-hd\">\n <span\n className={c.kind === 'team' ? 'ss-w-thumb ss-w-team' : 'ss-w-thumb'}\n style={c.image ? { backgroundImage: `url(${c.image})` } : undefined}\n >\n {c.image ? '' : initials(c.name)}\n </span>\n <span className=\"ss-w-ecard-idtext\">\n <span className=\"ss-w-nm\">{c.name}</span>\n {c.sub ? <span className=\"ss-w-sub\">{c.sub}</span> : null}\n </span>\n <span className=\"ss-w-ecard-meta\">\n {showScopeCrest && onlyScope?.image ? <Crest image={onlyScope.image} label={onlyScope.label} /> : null}\n {c.season ? <span className=\"ss-w-ecard-season\">{shortSeason(c.season)}</span> : null}\n </span>\n </div>\n )\n}\n\nfunction ScopeTabs({ scopes, active, onSelect }: { scopes: CardScope[]; active: number; onSelect: (i: number) => void }): JSX.Element {\n return (\n <div className=\"ss-w-ecard-scopes\" role=\"tablist\">\n {scopes.map((s, i) => (\n <button\n key={String(s.competitionId ?? 'all')}\n type=\"button\"\n role=\"tab\"\n className=\"ss-w-ecard-scope\"\n aria-selected={i === active}\n aria-label={s.label}\n title={s.label}\n onClick={() => onSelect(i)}\n >\n {s.image ? <Crest image={s.image} /> : s.label}\n </button>\n ))}\n </div>\n )\n}\n\nfunction EntityCardItem({ c }: { c: CardVM }): JSX.Element {\n const [active, setActive] = useState(0)\n const hasBody = c.scopes.length > 0\n if (!hasBody) {\n return (\n <div className=\"ss-w-ecard ss-w-ecard-bare\" data-kind={c.kind}>\n <CardHeader c={c} showScopeCrest={false} />\n </div>\n )\n }\n const multi = c.scopes.length > 1\n const scope = c.scopes[multi ? (c.scopes[active] ? active : 0) : 0]!\n return (\n <div className=\"ss-w-ecard\" data-kind={c.kind}>\n <CardHeader c={c} showScopeCrest={!multi} />\n {multi ? <ScopeTabs scopes={c.scopes} active={active} onSelect={setActive} /> : null}\n <StatStrip stats={scope.stats} />\n </div>\n )\n}\n\nexport function EntityCardList({ cards, disabled, showLessLabel = 'Show less', showMoreLabel = (n: number) => `Show ${n} more` }: { cards: CardVM[]; disabled?: boolean; showLessLabel?: string; showMoreLabel?: (n: number) => string }): JSX.Element | null {\n const [expanded, setExpanded] = useState(false)\n if (cards.length === 0) return null\n const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE)\n const overflow = cards.length - MAX_VISIBLE\n return (\n <div className=\"ss-w-cards\">\n {visible.map((c) => <EntityCardItem key={c.id} c={c} />)}\n {overflow > 0 ? (\n <button type=\"button\" className=\"ss-w-cards-more\" disabled={disabled} onClick={() => setExpanded((v) => !v)}>\n {expanded ? showLessLabel : showMoreLabel(overflow)}\n </button>\n ) : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { InsightVM, StatCell } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { useEventLog } from '../eventLogContext'\nimport { AddToSlipButton } from './AddToSlipButton'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { Crest } from './Crest'\nimport { PinToggle } from './PinToggle'\n\nfunction StatRows({ stats }: { stats: StatCell[] }): JSX.Element {\n return (\n <div className=\"ss-w-bi-rows\">\n {stats.map((s) => (\n <div key={`${s.label}:${s.value}`} className=\"ss-w-bi-row\">\n <span className=\"ss-w-bi-row-lbl\">{s.label}</span>\n <span className=\"ss-w-bi-row-num\">{s.value}</span>\n </div>\n ))}\n </div>\n )\n}\n\nfunction ScopedStats({ scopes }: { scopes: NonNullable<InsightVM['scopes']> }): JSX.Element {\n const [active, setActive] = useState(0)\n const current = scopes[active] ?? scopes[0] ?? { key: '', label: '', stats: [] }\n return (\n <div className=\"ss-w-bi-scoped\">\n <div className=\"ss-w-bi-scopes\" role=\"group\">\n {scopes.map((s, i) => (\n <button key={s.key} type=\"button\" className=\"ss-w-bi-chip\" aria-pressed={i === active} onClick={() => setActive(i)}>\n {s.label}\n </button>\n ))}\n </div>\n <StatRows key={current.key} stats={current.stats} />\n </div>\n )\n}\n\nfunction hasStatsContent(it: InsightVM): boolean {\n return (!!it.scopes && it.scopes.length >= 2) || it.stats.length > 0\n}\n\n// The reason-to-bet prose is clamped to two lines; one right-chevron expands it to the full text\n// AND the supporting stats together (the mock's single \">\" affordance). Collapsed by default so the\n// card stays scannable. The arrow only appears when there is something more to reveal — stats, or a\n// reason long enough to be clamped.\nfunction ReasonStrip({ it, ui }: { it: InsightVM; ui?: UiConfig }): JSX.Element | null {\n const [open, setOpen] = useState(false)\n const log = useEventLog()\n const hasScopes = !!it.scopes && it.scopes.length >= 2\n const hasStats = hasStatsContent(it)\n const hasText = !!it.text\n if (!hasText && !hasStats) return null\n const expandable = hasStats || (it.text?.length ?? 0) > 90\n const onToggle = (): void => {\n setOpen((v) => {\n const next = !v\n if (next) log?.log({ name: 'insight_expand', entityType: 'match', entityId: String(it.matchId) })\n return next\n })\n }\n return (\n <div className=\"ss-w-bi-reason\">\n <span className=\"ss-w-bi-chart\" aria-hidden=\"true\" />\n <div className=\"ss-w-bi-reason-body\">\n {hasText ? <p className={`ss-w-bi-text${open ? '' : ' ss-w-bi-text-clamp'}`}>{it.text}</p> : null}\n {open && hasStats ? (hasScopes ? <ScopedStats scopes={it.scopes!} /> : <StatRows stats={it.stats} />) : null}\n </div>\n {expandable ? (\n <button\n type=\"button\"\n className=\"ss-w-bi-expand\"\n aria-expanded={open}\n aria-label={open ? ui?.hideStats ?? 'Hide stats' : ui?.showStats ?? 'Show stats'}\n onClick={onToggle}\n >\n <span className={`ss-w-bi-arrow${open ? ' ss-w-bi-arrow-open' : ''}`} aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n )\n}\n\n// Renders the fixture as the card's hero: the named team pair when present, else the prose\n// fixture, else the competition (the fallback that becomes the header hero when there is no\n// fixture at all). On a fixture card this fills its own line; the competition rides the meta line\n// above it (u350 two-tier).\nfunction CardFixture({ it }: { it: InsightVM }): JSX.Element | null {\n if (it.homeTeamName && it.awayTeamName) {\n return (\n <>\n <Crest kind=\"team\" url={it.homeCrest} name={it.homeTeamName} />\n <span className=\"ss-w-bi-team\">{it.homeTeamName}</span>\n <span className=\"ss-w-bi-vs\" aria-hidden=\"true\">vs</span>\n <span className=\"ss-w-bi-team\">{it.awayTeamName}</span>\n <Crest kind=\"team\" url={it.awayCrest} name={it.awayTeamName} />\n </>\n )\n }\n if (it.fixture) return <span className=\"ss-w-bi-fixture-txt\">{it.fixture}</span>\n if (it.competition) {\n return (\n <>\n <Crest kind=\"comp\" url={it.competitionCrest} name={it.competition} />\n <span className=\"ss-w-bi-comp\">{it.competition}</span>\n </>\n )\n }\n return null\n}\n\nfunction InsightCard(\n { it, ui, slip, monitor }: { it: InsightVM; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController },\n): JSX.Element {\n const live = it.isLive || it.phase === 'live'\n // Prefer the server-rendered chip (operator timezone + language); fall back to browser-zone\n // formatting of the raw instant for older servers that don't send a label.\n const kickoffFallback = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : undefined\n const kickoff = it.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : undefined)\n const hasNamedTeams = !!it.homeTeamName && !!it.awayTeamName\n // A fixture (team pair or prose string) is the card's hero and gets its own full-width line so\n // long club names stop truncating; the competition, kickoff and match pin sit on a quieter meta\n // line above it. Only when there is no fixture does the competition itself become the hero on a\n // single header line (u350 two-tier).\n const leftIsFixture = hasNamedTeams || !!it.fixture\n const showPin = !!monitor && it.pinEnabled\n const showHeader = leftIsFixture || !!it.competition || live || !!kickoff || showPin\n // live badge + kickoff + match pin: shared by the fixture card's meta line and the\n // competition-hero card's header-right, so the trio renders identically on both. The pin here\n // pins the MATCH; the selection pin lives on the pick row below (2026-09-06 ruling: the two\n // behaviors are never combined).\n const headerControls = (\n <>\n {live ? (\n <span className=\"ss-w-bi-live\"><span className=\"ss-w-bi-live-dot\" aria-hidden=\"true\" />{ui?.liveLabel ?? 'Live'}</span>\n ) : null}\n {kickoff ? <span className=\"ss-w-bi-kick\">{kickoff}</span> : null}\n {showPin && ui ? (\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: it.matchId }} />\n ) : null}\n </>\n )\n return (\n <div className=\"ss-w-binsight\">\n {showHeader ? (\n leftIsFixture ? (\n <div className=\"ss-w-bi-head\">\n {(it.competition || live || kickoff || showPin) ? (\n <div className=\"ss-w-bi-meta\">\n <span className=\"ss-w-bi-meta-left\">\n {it.competition ? (\n <>\n <Crest kind=\"comp\" url={it.competitionCrest} name={it.competition} />\n <span className=\"ss-w-bi-comp\">{it.competition}</span>\n </>\n ) : null}\n </span>\n <span className=\"ss-w-bi-meta-right\">{headerControls}</span>\n </div>\n ) : null}\n <div className=\"ss-w-bi-fixture-line\"><CardFixture it={it} /></div>\n </div>\n ) : (\n <div className=\"ss-w-bi-header\">\n <span className=\"ss-w-bi-header-left\"><CardFixture it={it} /></span>\n <span className=\"ss-w-bi-header-right\">{headerControls}</span>\n </div>\n )\n ) : null}\n <div className=\"ss-w-bi-action\">\n {it.market ? <span className=\"ss-w-bi-market\">{it.market}</span> : null}\n <div className=\"ss-w-bi-pick-row\">\n {it.selection ? <span className=\"ss-w-bi-sel\">{it.selection}</span> : null}\n {it.odds ? (\n <span className=\"ss-w-bi-odds\">\n <b>{it.odds}</b>\n <OddsMovementBadge previous={it.previousOdds} current={it.odds} direction={it.movementDirection} ui={ui} />\n {it.bookmaker ? <span className=\"ss-w-bi-book\">{it.bookmaker}</span> : null}\n </span>\n ) : null}\n <AddToSlipButton it={it} slip={slip} ui={ui} />\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{\n kind: 'selection',\n matchId: it.matchId,\n marketDeveloperName: it.marketDeveloperName,\n selectionLabel: it.selectionLabel,\n line: it.line,\n matchOddsId: it.matchOddsId,\n }}\n />\n ) : null}\n </div>\n </div>\n {it.isMarketFloor ? (\n <span className=\"ss-w-bi-floor\">{ui?.marketFloorLabel ?? 'Market price · not a value pick'}</span>\n ) : null}\n <ReasonStrip it={it} ui={ui} />\n {it.disclaimer ? <p className=\"ss-w-bi-disc\">{it.disclaimer}</p> : null}\n </div>\n )\n}\n\nexport function BettingInsightList(\n { insights, ui, slip, monitor }:\n { insights: InsightVM[]; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController },\n): JSX.Element | null {\n if (!insights || insights.length === 0) return null\n return (\n <div className=\"ss-w-binsights\">\n {insights.map((it) => <InsightCard key={it.id} it={it} ui={ui} slip={slip} monitor={monitor} />)}\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\nimport { isAddToSlipResult, type AddToSlipResult, type SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { toSlipSelection, type InsightVM } from '../model'\nimport { ADD_TO_SLIP_TIMEOUT_MS, isTerminal, resultToToast, slipOutcome, wasAdded, type SlipHandlerProps, type SlipToast } from '../slip'\nimport { useEventLog } from '../eventLogContext'\nimport { Toast } from './Toast'\n\nfunction withTimeout(value: Promise<AddToSlipResult | void>): Promise<AddToSlipResult | void> {\n return Promise.race([\n value,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('add-to-slip timed out')), ADD_TO_SLIP_TIMEOUT_MS)),\n ])\n}\n\nexport function SlipButton(\n { selection, shownOdds, marketName, marketDeveloperName, slip, ui }:\n { selection: SlipSelection | null; shownOdds: string; marketName: string; marketDeveloperName?: string; slip: SlipHandlerProps; ui?: UiConfig },\n): JSX.Element | null {\n const [pending, setPending] = useState(false)\n const [settled, setSettled] = useState(false)\n const [toast, setToast] = useState<SlipToast | null>(null)\n const dismiss = useCallback(() => setToast(null), [])\n const log = useEventLog()\n\n const handler = slip.onAddToSlip\n if (!ui || !handler || !selection) return null\n\n const onClick = async (): Promise<void> => {\n setPending(true)\n // A market/selection with no marketDeveloperName has no entity to report under entityType\n // 'market' -- skip the emit rather than log entityId: undefined (mirrors the PinToggle guard).\n if (marketDeveloperName !== undefined) {\n log?.log({ name: 'slip_click', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName })\n }\n try {\n const raw = await withTimeout(Promise.resolve(handler(selection)))\n // Only a genuine void return means \"assume success\". A non-null value the\n // guard rejects is a broken contract (e.g. an operator forwarding their own\n // backend's reason string, which `any` lets past the compiler) — treating it\n // as void would report a refused bet to the user as added.\n if (raw != null && !isAddToSlipResult(raw)) throw new Error('malformed add-to-slip result')\n const result = raw ?? undefined\n if (marketDeveloperName !== undefined) {\n log?.log({\n name: 'slip_result', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName,\n outcome: slipOutcome(result),\n })\n }\n setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui))\n setSettled(isTerminal(result))\n if (wasAdded(result) && slip.onMarketClicked) {\n try {\n slip.onMarketClicked(marketName)\n } catch {\n // Telemetry must never change what the user sees.\n }\n }\n } catch {\n if (marketDeveloperName !== undefined) {\n log?.log({ name: 'slip_result', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName, outcome: 'timeout' })\n }\n setToast({ kind: 'error', text: ui.slipFailed })\n } finally {\n setPending(false)\n }\n }\n\n return (\n <div className=\"ss-w-slip\">\n <button\n type=\"button\"\n className=\"ss-w-slip-btn\"\n disabled={pending || settled}\n onClick={onClick}\n >\n {settled ? ui.inSlip : ui.addToSlip}\n </button>\n <Toast toast={toast} onDismiss={dismiss} />\n </div>\n )\n}\n\nexport function AddToSlipButton(\n { it, slip, ui }: { it: InsightVM; slip: SlipHandlerProps; ui?: UiConfig },\n): JSX.Element | null {\n const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null\n return (\n <SlipButton\n selection={selection}\n shownOdds={it.odds ?? ''}\n marketName={it.market}\n marketDeveloperName={it.marketDeveloperName}\n slip={slip}\n ui={ui}\n />\n )\n}\n","import { useEffect } from 'react'\nimport type { SlipToast } from '../slip'\n\nconst DISMISS_MS = 4000\n\nexport function Toast({ toast, onDismiss }: { toast: SlipToast | null; onDismiss: () => void }): JSX.Element | null {\n useEffect(() => {\n if (!toast) return\n const timer = setTimeout(onDismiss, DISMISS_MS)\n return () => clearTimeout(timer)\n }, [toast, onDismiss])\n\n if (!toast) return null\n return (\n <div className={`ss-w-toast ss-w-toast-${toast.kind}`} role=\"status\" aria-live=\"polite\">\n {toast.text}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\n\n// One component for both card types. The market-odds row and the insight card must not drift into\n// two visual languages for the same signal, so there is exactly one place this markup exists.\nexport function OddsMovementBadge({\n previous,\n current,\n direction,\n ui,\n}: {\n previous?: string\n current: string\n direction?: 'shortened' | 'drifted'\n ui?: UiConfig\n}): JSX.Element | null {\n if (previous === undefined || direction === undefined) return null\n const directionWord =\n direction === 'shortened' ? (ui?.oddsShortened ?? 'shortened') : (ui?.oddsDrifted ?? 'drifted')\n const label =\n ui?.oddsMoved?.(previous, current, directionWord) ?? `was ${previous}, now ${current}, ${directionWord}`\n return (\n // Strikethrough is invisible to screen readers, so the whole was/now/direction sentence rides\n // on one aria-label and the visual glyphs are hidden from the accessibility tree.\n <span className=\"ss-w-move\" role=\"img\" aria-label={label}>\n <span className=\"ss-w-move-prev\" aria-hidden=\"true\">{previous}</span>\n <span className=\"ss-w-move-arrow\" aria-hidden=\"true\">{direction === 'shortened' ? '▼' : '▲'}</span>\n </span>\n )\n}\n","import { useState } from 'react'\n\nexport function initials(name?: string): string {\n return (name ?? '').trim().slice(0, 1).toUpperCase() || '?'\n}\n\n// Crest is an <img> so a broken/absent URL falls back to a monogram (first initial) -- the design\n// wants the monogram whenever the crest is missing OR fails to load, which a background-image span\n// can't detect. onError flips to the monogram; the fixed sizing keeps the row height stable either way.\nexport function Crest({ url, name, kind }: { url?: string; name?: string; kind: 'team' | 'comp' }): JSX.Element {\n const cls = kind === 'comp' ? 'ss-w-bi-comp-logo' : 'ss-w-bi-crest'\n const [failed, setFailed] = useState(false)\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return <span className={`${cls} ss-w-bi-crest-mono`} aria-hidden=\"true\">{initials(name)}</span>\n}\n","import { useCallback, useState } from 'react'\nimport type { PinRef } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport { pinKey } from '../pinStore'\nimport type { SlipToast } from '../slip'\nimport { useEventLog } from '../eventLogContext'\nimport { Toast } from './Toast'\n\n// One glyph per pinIcon choice, drawn from a single silhouette path so the\n// pinned state can toggle outline (off) → filled (on) without a second asset.\n// The pin keeps its original thumbtack (scaled into a 24 box) so the default\n// look is unchanged in shape; star and bookmark are standard marks.\nconst PIN_GLYPHS: Record<'pin' | 'star' | 'bookmark', { viewBox: string; d: string; strokeWidth: number; transform?: string }> = {\n pin: { viewBox: '0 0 24 24', strokeWidth: 1.4, transform: 'scale(1.5)', d: 'M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z' },\n star: { viewBox: '0 0 24 24', strokeWidth: 2, d: 'M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.35 6.1 20.4l1.1-6.47L2.5 9.35l6.5-.95z' },\n bookmark: { viewBox: '0 0 24 24', strokeWidth: 2, d: 'M7 3h10a1.5 1.5 0 0 1 1.5 1.5V21l-6.5-3.6L5.5 21V4.5A1.5 1.5 0 0 1 7 3z' },\n}\n\nexport function PinToggle({ pin, monitor, ui }: {\n pin: Omit<PinRef, 'key'>\n monitor: LiveMonitorController | undefined\n ui: UiConfig\n}): JSX.Element | null {\n const [toast, setToast] = useState<SlipToast | null>(null)\n const dismiss = useCallback(() => setToast(null), [])\n const log = useEventLog()\n\n if (!monitor || !monitor.enabled) return null\n\n const key = pinKey(pin)\n const pinned = monitor.isPinned(key)\n // Match pins and odds pins are separate behaviors (2026-09-06 ruling): each toggle tracks\n // exactly its own pin, and the labels name which one this is.\n const labels = pin.kind === 'match'\n ? { pin: ui.matchPinLabel, unpin: ui.matchUnpinLabel }\n : { pin: ui.pinLabel, unpin: ui.unpinLabel }\n\n const onClick = (): void => {\n const result = monitor.togglePin({ ...pin, key })\n // A market/selection pin with no marketDeveloperName has no entity to report under\n // entityType 'market' -- skip the emit rather than fall back to the match id, which would\n // mislabel a match under a market entityType.\n if ((result === 'added' || result === 'removed') && (pin.kind === 'match' || pin.marketDeveloperName !== undefined)) {\n log?.log({\n name: result === 'added' ? 'pin_add' : 'pin_remove',\n entityType: pin.kind === 'match' ? 'match' : 'market',\n entityId: pin.kind === 'match' ? String(pin.matchId) : pin.marketDeveloperName,\n marketDeveloperName: pin.marketDeveloperName,\n })\n } else if (result === 'match_limit') {\n setToast({ kind: 'error', text: ui.matchLimitToast })\n } else if (result === 'market_limit') {\n setToast({ kind: 'error', text: ui.marketLimitToast })\n }\n }\n\n const glyph = PIN_GLYPHS[ui.pinIcon]\n return (\n <div className=\"ss-w-pin-wrap\">\n <button\n type=\"button\"\n className=\"ss-w-pin\"\n data-on={pinned || undefined}\n data-icon={ui.pinIcon}\n aria-pressed={pinned}\n aria-label={pinned ? labels.unpin : labels.pin}\n onClick={onClick}\n >\n <svg viewBox={glyph.viewBox} aria-hidden=\"true\">\n <path\n transform={glyph.transform}\n d={glyph.d}\n fill={pinned ? 'currentColor' : 'none'}\n stroke={pinned ? 'none' : 'currentColor'}\n strokeWidth={glyph.strokeWidth}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n <Toast toast={toast} onDismiss={dismiss} />\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PinRef } from '@sensiblestats/widget-sdk'\nimport type { MarketOddsVM, MarketOddsRowVM } from '../model'\nimport { marketOddsRowToSlipSelection } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { SlipButton } from './AddToSlipButton'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { Crest } from './Crest'\nimport { PinToggle } from './PinToggle'\n\nfunction OddsRow(\n { vm, row, ui, slip, inSlipIds }:\n { vm: MarketOddsVM; row: MarketOddsRowVM; ui?: UiConfig; slip: SlipHandlerProps; inSlipIds?: Record<number, true> },\n): JSX.Element {\n const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null\n // D5 persistent in-slip badge: keyed by matchOddsId in monitor.inSlip (session state set via\n // markInSlip), NOT SlipButton's own local `settled` state -- that resets whenever this row's\n // VM is recreated by a fresh poll snapshot, which the badge must survive. Passed as a plain\n // id map (not the full LiveMonitorController) so callers can surface the badge without also\n // turning on this list's OWN pin-toggle header (OddsPanel already owns that pin via the\n // market snapshot's context line -- a second, independently-keyed toggle here could drift out\n // of sync with it).\n const inSlip = !!inSlipIds && row.matchOddsId != null && !!inSlipIds[row.matchOddsId]\n return (\n <div className=\"ss-w-mo-row\">\n <span className=\"ss-w-mo-sel\">{row.selection}</span>\n <OddsMovementBadge previous={row.previousOdds} current={row.odds} direction={row.movementDirection} ui={ui} />\n <span className=\"ss-w-mo-price\">{row.odds}</span>\n {inSlip && ui ? <span className=\"ss-w-mon-inslip\">✓ {ui.inSlipLabel}</span> : null}\n <SlipButton selection={selection} shownOdds={row.odds} marketName={vm.market} marketDeveloperName={vm.marketDeveloperName} slip={slip} ui={ui} />\n </div>\n )\n}\n\nfunction MarketOddsCard(\n { vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }:\n { vm: MarketOddsVM; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController; inSlipIds?: Record<number, true>; hideHeader?: boolean; pinRef?: Omit<PinRef, 'key'> },\n): JSX.Element {\n const [open, setOpen] = useState(false)\n const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : undefined\n const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : undefined)\n const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName\n const showPin = !!monitor && vm.pinEnabled\n // Chat path (no pinRef): mirror the two-pin BettingInsightList layout -- the header pin\n // becomes the MATCH pin and the odds pin drops to the market line below (2026-09-06 ruling:\n // match and odds pins are never one toggle). The OddsPanel path passes pinRef and keeps its\n // single market pin in the header, so its second toggle stays off (no key drift).\n const showMarketPin = showPin && !pinRef\n const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin\n return (\n <div className={hideHeader ? 'ss-w-mocard ss-w-mocard--bare' : 'ss-w-mocard'}>\n {!hideHeader && (\n <>\n {showHeader ? (\n <div className=\"ss-w-bi-header\">\n <span className=\"ss-w-bi-header-left\">\n {vm.competition ? (\n <>\n <Crest kind=\"comp\" url={vm.competitionCrest} name={vm.competition} />\n <span className=\"ss-w-bi-comp\">{vm.competition}</span>\n </>\n ) : null}\n </span>\n <span className=\"ss-w-bi-header-right\">\n {vm.isLive ? (\n <span className=\"ss-w-bi-live\"><span className=\"ss-w-bi-live-dot\" aria-hidden=\"true\" />{ui?.liveLabel ?? 'Live'}</span>\n ) : null}\n {kickoff ? <span className=\"ss-w-bi-kick\">{kickoff}</span> : null}\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={pinRef ?? { kind: 'match', matchId: vm.matchId }}\n />\n ) : null}\n </span>\n </div>\n ) : null}\n {(hasNamedTeams || vm.fixture || vm.market || showMarketPin) ? (\n <div className=\"ss-w-mo-sub\">\n {hasNamedTeams ? (\n <div className=\"ss-w-bi-fixture\">\n <Crest kind=\"team\" url={vm.homeCrest} name={vm.homeTeamName} />\n <span className=\"ss-w-bi-team\">{vm.homeTeamName}</span>\n <span className=\"ss-w-bi-vs\" aria-hidden=\"true\">vs</span>\n <span className=\"ss-w-bi-team\">{vm.awayTeamName}</span>\n <Crest kind=\"team\" url={vm.awayCrest} name={vm.awayTeamName} />\n </div>\n ) : vm.fixture ? <span className=\"ss-w-mo-teams\">{vm.fixture}</span> : null}\n {(vm.market || showMarketPin) ? (\n <div className=\"ss-w-mo-market-row\">\n {vm.market ? <span className=\"ss-w-mo-market\">{vm.market}</span> : null}\n {showMarketPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{ kind: 'market', matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }}\n />\n ) : null}\n </div>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n <div className=\"ss-w-mo-rows\">\n {vm.mainRows.map((row) => <OddsRow key={row.key} vm={vm} row={row} ui={ui} slip={slip} inSlipIds={inSlipIds} />)}\n {open ? vm.moreRows.map((row) => <OddsRow key={row.key} vm={vm} row={row} ui={ui} slip={slip} inSlipIds={inSlipIds} />) : null}\n </div>\n {vm.moreRows.length > 0 ? (\n <button type=\"button\" className=\"ss-w-mo-more\" aria-expanded={open} onClick={() => setOpen((v) => !v)}>\n <span>{open ? ui?.hideLines ?? 'Hide lines' : `${ui?.moreLines ?? 'More lines'} (${vm.moreRows.length})`}</span>\n <span className={`ss-w-mo-more-chev${open ? ' ss-w-mo-more-chev-up' : ''}`} aria-hidden=\"true\" />\n </button>\n ) : null}\n {vm.bookmaker ? (\n <div className=\"ss-w-mo-foot\">\n <span>{vm.bookmaker}</span>\n </div>\n ) : null}\n {vm.disclaimer ? <p className=\"ss-w-bi-disc\">{vm.disclaimer}</p> : null}\n </div>\n )\n}\n\nexport function MarketOddsCardList(\n { cards, ui, slip, monitor, inSlipIds, hideHeader, pinRef }:\n { cards: MarketOddsVM[]; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController; inSlipIds?: Record<number, true>; hideHeader?: boolean; pinRef?: Omit<PinRef, 'key'> },\n): JSX.Element | null {\n if (!cards || cards.length === 0) return null\n return (\n <div className=\"ss-w-mocards\">\n {cards.map((vm) => (\n <MarketOddsCard key={vm.id} vm={vm} ui={ui} slip={slip} monitor={monitor} inSlipIds={inSlipIds} hideHeader={hideHeader} pinRef={pinRef} />\n ))}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\nimport type { OddsMovementVM } from '../model'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { CHART_VIEW_H, CHART_VIEW_W } from '../chart'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { PinToggle } from './PinToggle'\n\nfunction directionWord(vm: OddsMovementVM, ui?: UiConfig): string {\n if (vm.direction === 'shortened') return ui?.oddsShortened ?? 'shortened'\n if (vm.direction === 'drifted') return ui?.oddsDrifted ?? 'drifted'\n return ''\n}\n\nfunction OddsMovementCard(\n { vm, ui, monitor }: { vm: OddsMovementVM; ui?: UiConfig; monitor?: LiveMonitorController },\n): JSX.Element {\n const word = directionWord(vm, ui)\n const drift = word ? `, ${word}` : ''\n const aria = ui?.chartAria\n ? ui.chartAria(vm.opening, vm.current, word, vm.windowHours)\n : `Price movement over the last ${vm.windowHours} hours: opened at ${vm.opening}, currently ${vm.current}${drift}.`\n const showPin = !!monitor && vm.pinEnabled\n\n return (\n <div className=\"ss-w-omcard\">\n <div className=\"ss-w-om-head\">\n <span className=\"ss-w-om-market\">{vm.market}</span>\n <span className=\"ss-w-om-tag\">{ui?.priceMovement ?? 'Price movement'}</span>\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{\n kind: 'selection',\n matchId: vm.matchId,\n marketDeveloperName: vm.marketDeveloperName,\n selectionLabel: vm.selectionLabel,\n line: vm.line,\n withHistory: true,\n matchOddsId: vm.matchOddsId,\n }}\n />\n ) : null}\n </div>\n {vm.fixture ? (\n <div className=\"ss-w-om-fixture\">\n <span>{vm.fixture}</span>\n {vm.competition ? <span className=\"ss-w-om-comp\">{vm.competition}</span> : null}\n </div>\n ) : null}\n <div className=\"ss-w-om-sel\">{vm.selection}</div>\n <OddsMovementBadge previous={vm.opening} current={vm.current} direction={vm.direction} ui={ui} />\n\n {vm.geometry === null ? (\n <div className=\"ss-w-om-empty\">\n {vm.observationCount === 1\n ? ui?.singlePricePoint ?? 'Only one price recorded so far for this selection.'\n : ui?.notEnoughHistory ?? 'No price history recorded yet for this selection.'}\n </div>\n ) : (\n <svg\n className=\"ss-w-om-chart\"\n viewBox={vm.geometry.viewBox}\n width=\"100%\"\n role=\"img\"\n aria-label={aria}\n >\n {vm.geometry.gridlines.map((g) => (\n <g key={g.price}>\n <line className=\"ss-w-om-grid\" x1={40} y1={g.y} x2={CHART_VIEW_W - 8} y2={g.y} />\n <text className=\"ss-w-om-ylab\" x={34} y={g.y + 3} textAnchor=\"end\">{g.price.toFixed(2)}</text>\n </g>\n ))}\n <path className=\"ss-w-om-line\" d={vm.geometry.path} fill=\"none\" />\n {vm.geometry.markers.map((m, i) => (\n <circle key={i} className=\"ss-w-om-dot\" cx={m.x} cy={m.y} r={2.5} />\n ))}\n {ui?.chartTimeLabel ? (\n <>\n <text className=\"ss-w-om-xlab\" x={40} y={CHART_VIEW_H - 8} textAnchor=\"start\">\n {ui.chartTimeLabel(vm.geometry.startMs)}\n </text>\n <text className=\"ss-w-om-xlab\" x={CHART_VIEW_W - 8} y={CHART_VIEW_H - 8} textAnchor=\"end\">\n {ui.chartTimeLabel(vm.geometry.endMs)}\n </text>\n </>\n ) : (\n <text className=\"ss-w-om-xlab\" x={40} y={CHART_VIEW_H - 8}>\n {ui?.movementWindow ? ui.movementWindow(vm.windowHours) : `Last ${vm.windowHours}h`}\n </text>\n )}\n </svg>\n )}\n\n <div className=\"ss-w-om-foot\">\n <span>{ui?.openingLabel ?? 'Opening'} <b>{vm.opening}</b></span>\n <span>{ui?.currentLabel ?? 'Current'} <b>{vm.current}</b></span>\n </div>\n {vm.bookmaker ? (\n <div className=\"ss-w-om-foot\">\n <span>{vm.bookmaker}</span>\n </div>\n ) : null}\n {vm.excludedCount > 0 ? (\n <div className=\"ss-w-om-excl\">\n {ui?.excludedSuspended ? ui.excludedSuspended(vm.excludedCount) : `${vm.excludedCount} suspended price(s) excluded from this chart.`}\n </div>\n ) : null}\n {vm.isSuspended ? (\n <div className=\"ss-w-om-susp\">{ui?.selectionSuspended ?? 'This selection is not currently available to bet.'}</div>\n ) : null}\n {vm.disclaimer ? <div className=\"ss-w-om-disc\">{vm.disclaimer}</div> : null}\n </div>\n )\n}\n\nexport function OddsMovementCardList(\n { cards, ui, monitor }: { cards: OddsMovementVM[]; ui?: UiConfig; monitor?: LiveMonitorController },\n): JSX.Element | null {\n if (!cards || cards.length === 0) return null\n return (\n <div className=\"ss-w-omcards\">\n {cards.map((vm) => <OddsMovementCard key={vm.id} vm={vm} ui={ui} monitor={monitor} />)}\n </div>\n )\n}\n","import type { ActionVM } from '../model'\n\nexport function ActionButtons({ actions, loading, disabled, onAct }: { actions: ActionVM[]; loading: boolean; disabled?: boolean; onAct: (action: ActionVM) => void }): JSX.Element | null {\n if (actions.length === 0 && !loading) return null\n return (\n <div className=\"ss-w-actions\">\n {actions.map((a, i) => (\n <button key={`${a.label}-${i}`} type=\"button\" className=\"ss-w-abtn\" disabled={disabled} onClick={() => onAct(a)}>{a.label}</button>\n ))}\n {actions.length === 0 && loading ? (\n <>\n <span className=\"ss-w-abtn-shimmer\" />\n <span className=\"ss-w-abtn-shimmer\" />\n </>\n ) : null}\n </div>\n )\n}\n","import type { GreetingDashboardTile } from '@sensiblestats/widget-sdk'\nimport { DashboardIcon, ChevronIcon } from '../Icons'\n\n// The server payload caps crests at 3 (spec D2); slicing here is a defensive floor, not a\n// server-side promise, since a badge + crest row this wide already competes for the same\n// space the title needs.\nconst MAX_CRESTS = 3\n\nexport function DashboardTile({ tile, onTap }: { tile: GreetingDashboardTile; onTap: () => void }): JSX.Element {\n const spanClass = tile.span === 'full' ? 'ss-w-dash-tile--full' : 'ss-w-dash-tile--half'\n const crests = (tile.imageUrls ?? []).slice(0, MAX_CRESTS)\n const hasMeta = Boolean(tile.badgeText) || crests.length > 0\n return (\n <button type=\"button\" className={`ss-w-dash-tile ${spanClass}`} onClick={onTap}>\n <span className=\"ss-w-dash-tile-icon\"><DashboardIcon name={tile.icon} /></span>\n <span className=\"ss-w-dash-tile-body\">\n <span className=\"ss-w-dash-tile-title\">{tile.title}</span>\n {tile.subtitle ? <span className=\"ss-w-dash-tile-subtitle\">{tile.subtitle}</span> : null}\n {hasMeta ? (\n // Badge + crests sit on their own row, below the title, instead of sharing the\n // icon/chevron row -- at the half-span tile's ~180px width a nowrap badge alone\n // (~70px) left the title column at ~22px and forced character-by-character wrapping.\n <span className=\"ss-w-dash-tile-meta\">\n {tile.badgeText ? <span className=\"ss-w-dash-tile-badge\">{tile.badgeText}</span> : null}\n {crests.length > 0 ? (\n <span className=\"ss-w-dash-tile-crests\">\n {crests.map((url, i) => (\n <span key={`${url}-${i}`} className=\"ss-w-dash-tile-crest\" style={{ backgroundImage: `url(${url})` }} aria-hidden=\"true\" />\n ))}\n </span>\n ) : null}\n </span>\n ) : null}\n </span>\n <span className=\"ss-w-dash-tile-chevron\"><ChevronIcon /></span>\n </button>\n )\n}\n","import type { GreetingDashboard as GreetingDashboardData, GreetingDashboardLayout, GreetingDashboardTile as GreetingDashboardTileData } from '@sensiblestats/widget-sdk'\nimport { DashboardTile } from './DashboardTile'\n\nconst LAYOUT_CLASSES: Record<GreetingDashboardLayout, string> = {\n market: 'ss-w-dash--market',\n goal: 'ss-w-dash--goal',\n discovery: 'ss-w-dash--discovery',\n}\n\n// The server's layout is a closed set, but a mismatched deploy or a future value\n// could still send something outside it. Falling back to goal (an allowlist check,\n// not a truthiness test) avoids emitting a class with no CSS rule behind it.\n// hasOwnProperty (not `in`) so a prototype member name like 'toString' can't slip\n// through as a layout and get interpolated into the className.\nfunction layoutClass(layout: string): string {\n return Object.prototype.hasOwnProperty.call(LAYOUT_CLASSES, layout)\n ? LAYOUT_CLASSES[layout as GreetingDashboardLayout]\n : LAYOUT_CLASSES.goal\n}\n\nexport function GreetingDashboard({ dashboard, onTap }: { dashboard: GreetingDashboardData; onTap: (tile: GreetingDashboardTileData, index: number) => void }): JSX.Element {\n return (\n <div className={`ss-w-dash ${layoutClass(dashboard.layout)}`}>\n <div className=\"ss-w-dash-head\">\n <span className=\"ss-w-dash-title\">{dashboard.title}</span>\n {dashboard.subtitle ? <span className=\"ss-w-dash-subtitle\">{dashboard.subtitle}</span> : null}\n </div>\n <div className=\"ss-w-dash-grid\">\n {dashboard.tiles.map((t, i) => (\n <DashboardTile key={`${t.title}-${i}`} tile={t} onTap={() => onTap(t, i)} />\n ))}\n </div>\n {dashboard.footerTip ? <span className=\"ss-w-dash-foot\">{dashboard.footerTip}</span> : null}\n </div>\n )\n}\n","import type { FixtureCard as FixtureCardData, FormMatch } from '@sensiblestats/widget-sdk'\nimport { Crest } from '../Crest'\n\nfunction teamFormResultClass(result: FormMatch['result']): string {\n if (result === 'W') return 'ss-w-fandash-teamform-cell--win'\n if (result === 'L') return 'ss-w-fandash-teamform-cell--loss'\n return 'ss-w-fandash-teamform-cell--draw'\n}\n\n// One historical-match cell: subject crest + score + opponent crest, ordered by which side the\n// subject team played on so the score always reads left-to-right as it happened on the pitch.\nfunction TeamFormCell({ m, subjectCrestUrl, subjectName }: {\n m: FormMatch\n subjectCrestUrl?: string | null\n subjectName: string\n}): JSX.Element {\n const subjectCrest = <Crest url={subjectCrestUrl ?? undefined} name={subjectName} kind=\"team\" />\n const opponentCrest = <Crest url={m.opponentCrestUrl ?? undefined} kind=\"team\" />\n const score = m.teamIsHome ? `${m.teamScore} - ${m.oppScore}` : `${m.oppScore} - ${m.teamScore}`\n return (\n <div className={`ss-w-fandash-teamform-cell ${teamFormResultClass(m.result)}`}>\n {m.teamIsHome ? subjectCrest : opponentCrest}\n <span className=\"ss-w-fandash-teamform-score\">{score}</span>\n {m.teamIsHome ? opponentCrest : subjectCrest}\n </div>\n )\n}\n\nconst TEAM_FORM_ROWS = 5\n\n// Two-column \"Team form\" card: left = home team's last 5, right = away team's last 5, most-recent\n// first. The rows grid is filled home-cell, away-cell per index (matching the approved two-column\n// mock) so a 2-col CSS grid lays them out in the right pairs without any extra layout wiring. A\n// shorter side just leaves later slots blank rather than shifting the other column's rows.\nfunction teamFormRows(data: FixtureCardData['data']): JSX.Element[] {\n return Array.from({ length: TEAM_FORM_ROWS }, (_, i) => i).flatMap((i) => [\n <span key={`h-${i}`} className=\"ss-w-fandash-teamform-slot\">\n {data.homeForm[i] ? (\n <TeamFormCell m={data.homeForm[i]} subjectCrestUrl={data.homeCrestUrl} subjectName={data.homeName} />\n ) : null}\n </span>,\n <span key={`a-${i}`} className=\"ss-w-fandash-teamform-slot\">\n {data.awayForm[i] ? (\n <TeamFormCell m={data.awayForm[i]} subjectCrestUrl={data.awayCrestUrl} subjectName={data.awayName} />\n ) : null}\n </span>,\n ])\n}\n\n// The fixture payload renders as three stacked [data] cards -- the fixture head (teams, kickoff,\n// venue), the last-five form, and the head-to-head record -- so each block reads as its own unit.\n// None is a tap target: the compare-form action lives in the greeting chips, so the card carries no\n// redundant CTA. (u319: the server now issues FixtureCard as a plain DataCard with no actionRef.)\nexport function FixtureCard({ card }: { card: FixtureCardData }): JSX.Element {\n const { data } = card\n const h2h = data.h2H\n return (\n <>\n <div className=\"ss-w-fandash-card ss-w-fandash-fixture\">\n <span className=\"ss-w-fandash-eyebrow\">{card.title} · {data.competition}</span>\n <div className=\"ss-w-fandash-fixture-teams\">\n <span className=\"ss-w-fandash-fixture-team\">\n <Crest url={data.homeCrestUrl ?? undefined} name={data.homeName} kind=\"team\" />\n <span className=\"ss-w-fandash-fixture-name\">{data.homeName}</span>\n </span>\n <span className=\"ss-w-fandash-fixture-vs\">v</span>\n <span className=\"ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away\">\n <span className=\"ss-w-fandash-fixture-name\">{data.awayName}</span>\n <Crest url={data.awayCrestUrl ?? undefined} name={data.awayName} kind=\"team\" />\n </span>\n </div>\n <div className=\"ss-w-fandash-fixture-meta\">\n <span className=\"ss-w-fandash-fixture-kickoff\">{data.kickoffLabel}</span>\n {data.venue ? <span className=\"ss-w-fandash-fixture-venue\"> · {data.venue}</span> : null}\n </div>\n </div>\n\n <div className=\"ss-w-fandash-card ss-w-fandash-lastfive\">\n <span className=\"ss-w-fandash-eyebrow\">{data.formLabel}</span>\n <div className=\"ss-w-fandash-teamform-head\">\n <span className=\"ss-w-fandash-teamform-head-team\">\n <Crest url={data.homeCrestUrl ?? undefined} name={data.homeName} kind=\"team\" />\n <span className=\"ss-w-fandash-teamform-head-name\">{data.homeName}</span>\n </span>\n <span className=\"ss-w-fandash-teamform-head-team\">\n <Crest url={data.awayCrestUrl ?? undefined} name={data.awayName} kind=\"team\" />\n <span className=\"ss-w-fandash-teamform-head-name\">{data.awayName}</span>\n </span>\n </div>\n <div className=\"ss-w-fandash-teamform-rows\">\n {teamFormRows(data)}\n </div>\n </div>\n\n {h2h || data.fact ? (\n <div className=\"ss-w-fandash-card ss-w-fandash-h2h\">\n {h2h ? (\n <>\n <span className=\"ss-w-fandash-eyebrow\">{h2h.label}</span>\n <div className=\"ss-w-fandash-split\">\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.wins}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.homeWinsLabel}</span>\n </span>\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.draws}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.drawsLabel}</span>\n </span>\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.losses}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.awayWinsLabel}</span>\n </span>\n </div>\n </>\n ) : null}\n {data.fact ? <span className=\"ss-w-fandash-fact\">{data.fact}</span> : null}\n </div>\n ) : null}\n </>\n )\n}\n","import { Fragment, useEffect, useState } from 'react'\nimport type { CountdownCard as CountdownCardData } from '@sensiblestats/widget-sdk'\n\ntype UnitKind = 'd' | 'h' | 'm' | 's'\ntype Segment = { value: string; unit: UnitKind }\n\nconst DAY_MS = 86_400_000\n\n// The countdown reads day:hour while the match is more than a day out, and switches to a live\n// hour:minute:second clock on match day (under a day to kickoff). `withSeconds` is dropped under\n// reduced motion so the card never shows a seconds figure it will never refresh. Returns null once\n// kickoff has passed.\nfunction remainingSegments(kickoffUnix: number, nowMs: number, withSeconds: boolean): Segment[] | null {\n const totalSeconds = Math.floor((kickoffUnix * 1000 - nowMs) / 1000)\n if (totalSeconds <= 0) return null\n const days = Math.floor(totalSeconds / 86_400)\n const hours = Math.floor((totalSeconds % 86_400) / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n const pad = (n: number) => String(n).padStart(2, '0')\n if (days > 0) return [{ value: pad(days), unit: 'd' }, { value: pad(hours), unit: 'h' }]\n const segs: Segment[] = [{ value: pad(hours), unit: 'h' }, { value: pad(minutes), unit: 'm' }]\n if (withSeconds) segs.push({ value: pad(seconds), unit: 's' })\n return segs\n}\n\nexport function CountdownCard({ card }: { card: CountdownCardData }): JSX.Element {\n const { data } = card\n // Unit labels are server-localized; the numbers are computed client-side.\n const unitLabel: Record<UnitKind, string> = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit }\n const [nowMs, setNowMs] = useState(() => Date.now())\n // Reduced motion is read once at mount: it decides whether the card ticks at all and whether it\n // shows a (necessarily static, so potentially stale) seconds figure. Ticking is otherwise\n // additive -- the segments computed at mount keep showing even if no interval ever fires.\n const [reduced] = useState(\n () => typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches,\n )\n const withinDay = data.kickoffUnix * 1000 - nowMs < DAY_MS\n useEffect(() => {\n if (reduced) return\n const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1000 : 60_000)\n return () => window.clearInterval(id)\n }, [reduced, withinDay])\n const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced)\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-countdown\">\n <div className=\"ss-w-fandash-countdown-top\">\n <span className=\"ss-w-fandash-eyebrow\">{card.title ?? 'Kick-off in'}</span>\n {segments ? (\n <span className=\"ss-w-fandash-countdown-clock\">\n {segments.map((s, i) => (\n <Fragment key={s.unit}>\n {i > 0 ? <span className=\"ss-w-fandash-countdown-colon\">:</span> : null}\n <span className=\"ss-w-fandash-countdown-seg\">\n <span className=\"ss-w-fandash-countdown-value\">{s.value}</span>\n <span className=\"ss-w-fandash-countdown-unit\">{unitLabel[s.unit]}</span>\n </span>\n </Fragment>\n ))}\n </span>\n ) : null}\n </div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { InjuriesCard as InjuriesCardData, InjuryRow } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\nimport { Crest } from '../Crest'\n\nconst SHOWN = 3\n\nfunction ColHead({ name, crestUrl }: { name: string; crestUrl?: string | null }): JSX.Element {\n return (\n <span className=\"ss-w-fandash-injuries-col-head\">\n <Crest url={crestUrl ?? undefined} name={name} kind=\"team\" />\n <span className=\"ss-w-fandash-injuries-col-head-name\">{name}</span>\n </span>\n )\n}\n\nfunction InjuryList({ rows, emptyLabel, limit }: { rows: InjuryRow[]; emptyLabel: string; limit?: number }): JSX.Element {\n if (rows.length === 0) return <span className=\"ss-w-fandash-injuries-empty\">{emptyLabel}</span>\n const shown = limit === undefined ? rows : rows.slice(0, limit)\n return (\n <ul className=\"ss-w-fandash-injury-list\">\n {shown.map((r, i) => (\n <li key={`${r.playerName}-${i}`} className=\"ss-w-fandash-injury-row\">\n <span className=\"ss-w-fandash-injury-name\">{r.playerName}</span>\n <span className=\"ss-w-fandash-injury-meta\">\n <span className=\"ss-w-fandash-injury-status\">{r.status}</span>\n {r.injuryType ? <span className=\"ss-w-fandash-injury-type\">{r.injuryType}</span> : null}\n {r.expectedReturnLabel ? <span className=\"ss-w-fandash-injury-return\">{r.expectedReturnLabel}</span> : null}\n </span>\n </li>\n ))}\n </ul>\n )\n}\n\nexport function InjuriesCard({ card, ui }: { card: InjuriesCardData; ui?: UiConfig }): JSX.Element {\n const { data } = card\n const [expanded, setExpanded] = useState(false)\n // Either side's list can be long; a shared toggle collapses both to SHOWN and reveals the rest,\n // so the card doesn't push the input off-screen. The count is how many are hidden across both sides.\n const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN)\n const limit = expanded ? undefined : SHOWN\n const showMore = ui?.showMore ?? ((n: number) => `Show ${n} more`)\n const showLess = ui?.showLess ?? 'Show less'\n // \"Ours\" is club-vs-opponent, not home-vs-away — reorder into home/away columns so the card\n // reads left-to-right like the rest of the dashboard regardless of which side the club is on.\n const homeCol = data.oursIsHome\n ? { name: data.oursName, crest: data.oursCrestUrl, rows: data.ours }\n : { name: data.theirsName, crest: data.theirsCrestUrl, rows: data.theirs }\n const awayCol = data.oursIsHome\n ? { name: data.theirsName, crest: data.theirsCrestUrl, rows: data.theirs }\n : { name: data.oursName, crest: data.oursCrestUrl, rows: data.ours }\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-injuries\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-injuries-cols\">\n <div className=\"ss-w-fandash-injuries-col\">\n <ColHead name={homeCol.name} crestUrl={homeCol.crest} />\n <InjuryList rows={homeCol.rows} emptyLabel={data.emptyLabel} limit={limit} />\n </div>\n <div className=\"ss-w-fandash-injuries-divider\" />\n <div className=\"ss-w-fandash-injuries-col\">\n <ColHead name={awayCol.name} crestUrl={awayCol.crest} />\n <InjuryList rows={awayCol.rows} emptyLabel={data.emptyLabel} limit={limit} />\n </div>\n </div>\n {hidden > 0 ? (\n <button\n type=\"button\"\n className=\"ss-w-fandash-injuries-more\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n >\n {expanded ? showLess : showMore(hidden)}\n </button>\n ) : null}\n </div>\n )\n}\n","import type { ReasonToBetCard as ReasonToBetCardData } from '@sensiblestats/widget-sdk'\n\nexport function ReasonToBetCard({ card }: { card: ReasonToBetCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-reasons\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <ul className=\"ss-w-fandash-reason-list\">\n {card.data.angles.map((angle, i) => (\n <li key={`${angle}-${i}`} className=\"ss-w-fandash-reason-item\">{angle}</li>\n ))}\n </ul>\n </div>\n )\n}\n","import type { WhereToWatchCard as WhereToWatchCardData } from '@sensiblestats/widget-sdk'\n\nexport function WhereToWatchCard({ card }: { card: WhereToWatchCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-watch\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <span className=\"ss-w-fandash-stations\">\n {card.data.stations.map((station, i) => (\n <span key={`${station}-${i}`} className=\"ss-w-fandash-station-chip\">{station}</span>\n ))}\n </span>\n </div>\n )\n}\n","import type { CongestedWeekCard as CongestedWeekCardData } from '@sensiblestats/widget-sdk'\n\nexport function CongestedWeekCard({ card, onTap }: { card: CongestedWeekCardData; onTap: (card: CongestedWeekCardData) => void }): JSX.Element {\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-congested-grid\">\n {card.data.entries.map((entry, i) => (\n <span key={`${entry.opponent}-${i}`} className=\"ss-w-fandash-congested-cell\">\n <span className=\"ss-w-fandash-congested-day\">{entry.dayLabel}</span>\n <span className=\"ss-w-fandash-congested-opponent\">{entry.opponent}</span>\n <span className=\"ss-w-fandash-congested-comp\">{entry.competition}</span>\n <span className=\"ss-w-fandash-congested-time\">{entry.timeLabel}</span>\n </span>\n ))}\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { TransfersCard as TransfersCardData, TransferRow } from '@sensiblestats/widget-sdk'\n\nfunction TransferList({ rows }: { rows: TransferRow[] }): JSX.Element {\n if (rows.length === 0) return <span className=\"ss-w-fandash-transfers-empty\">None</span>\n return (\n <ul className=\"ss-w-fandash-transfer-list\">\n {rows.map((r, i) => (\n <li key={`${r.playerName}-${i}`} className=\"ss-w-fandash-transfer-row\">\n <span className=\"ss-w-fandash-transfer-name\">{r.playerName}</span>\n <span className=\"ss-w-fandash-transfer-club\">{r.otherClub}</span>\n {r.type ? <span className=\"ss-w-fandash-transfer-type\">{r.type}</span> : null}\n </li>\n ))}\n </ul>\n )\n}\n\nexport function TransfersCard({ card }: { card: TransfersCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-transfers\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-transfers-cols\">\n <div className=\"ss-w-fandash-transfers-col\">\n <span className=\"ss-w-fandash-transfers-col-head\">In</span>\n <TransferList rows={data.in} />\n </div>\n <div className=\"ss-w-fandash-transfers-col\">\n <span className=\"ss-w-fandash-transfers-col-head\">Out</span>\n <TransferList rows={data.out} />\n </div>\n </div>\n </div>\n )\n}\n","import type { LinksCard as LinksCardData } from '@sensiblestats/widget-sdk'\nimport { ChevronIcon } from '../Icons'\n\nexport function LinksCard({ card }: { card: LinksCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-links\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-link-grid\">\n {card.data.links.map((link, i) => (\n <a key={`${link.url}-${i}`} className=\"ss-w-fandash-link-tile\" href={link.url} target=\"_blank\" rel=\"noopener noreferrer\">\n <span className=\"ss-w-fandash-link-label\">{link.label}</span>\n <span className=\"ss-w-fandash-link-chevron\"><ChevronIcon /></span>\n </a>\n ))}\n </div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PostMatchResultCard as PostMatchResultCardData } from '@sensiblestats/widget-sdk'\n\nfunction initials(name: string): string {\n return name.trim().slice(0, 3).toUpperCase()\n}\n\n// Same img-with-fallback treatment as LiveScoreCard's LiveCrest -- a broken/absent URL falls back\n// to a coloured initials chip, which a background-image span can't detect on its own.\nfunction PostMatchCrest({\n url,\n name,\n side,\n}: {\n url?: string | null\n name: string\n side: 'home' | 'away'\n}): JSX.Element {\n const [failed, setFailed] = useState(false)\n const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return (\n <span className={`${cls} ss-w-fandash-postmatch-crest--fallback`} aria-hidden=\"true\">\n {initials(name)}\n </span>\n )\n}\n\n// [data] card -- the full-time scoreboard. No tap target: the score itself is the payload, and\n// the goals/stats/top-performer cards below carry the actionRef taps for this match.\nexport function PostMatchResultCard({ card }: { card: PostMatchResultCardData }): JSX.Element {\n const { data } = card\n const homeWon = data.homeScore >= data.awayScore\n const awayWon = data.awayScore >= data.homeScore\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-postmatch-result\">\n <div className=\"ss-w-fandash-postmatch-top\">\n {/* card.title carries the server-localized \"Full time\" label -- reused as the pill text\n rather than a hardcoded English literal. */}\n {card.title ? <span className=\"ss-w-fandash-postmatch-pill\">{card.title}</span> : null}\n <span className={`ss-w-fandash-postmatch-tag ss-w-fandash-postmatch-tag--${data.outcome}`}>\n {data.resultLabel}\n </span>\n </div>\n <div className=\"ss-w-fandash-postmatch-main\">\n <div className=\"ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--home\">\n <PostMatchCrest url={data.homeCrestUrl} name={data.homeName} side=\"home\" />\n <span className=\"ss-w-fandash-postmatch-team-name\">{data.homeName}</span>\n </div>\n <div className=\"ss-w-fandash-postmatch-score-main\">\n <span\n className={`ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${homeWon ? 'win' : 'lose'}`}\n >\n {data.homeScore}\n </span>\n <span className=\"ss-w-fandash-postmatch-score-sep\">–</span>\n <span\n className={`ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${awayWon ? 'win' : 'lose'}`}\n >\n {data.awayScore}\n </span>\n </div>\n <div className=\"ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--away\">\n <PostMatchCrest url={data.awayCrestUrl} name={data.awayName} side=\"away\" />\n <span className=\"ss-w-fandash-postmatch-team-name\">{data.awayName}</span>\n </div>\n </div>\n <div className=\"ss-w-fandash-postmatch-meta\">\n {data.kickoffLabel}\n {data.competition ? ` · ${data.competition}` : ''}\n </div>\n </div>\n )\n}\n","import type { PostMatchGoalsCard as PostMatchGoalsCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- tapping sends actionLabel as a follow-up message, carrying the opaque\n// actionRef so the server resolves the pre-issued binding (see FixtureCard/CongestedWeekCard).\nexport function PostMatchGoalsCard({ card, onTap }: {\n card: PostMatchGoalsCardData\n onTap: (card: PostMatchGoalsCardData) => void\n}): JSX.Element {\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-goals\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <ul className=\"ss-w-fandash-postmatch-goal-list\">\n {card.data.goals.map((g, i) => (\n <li key={`${g.text}-${i}`} className={g.scoredByClub ? 'ss-w-fandash-postmatch-goal ss-w-fandash-postmatch-goal--club' : 'ss-w-fandash-postmatch-goal'}>\n <span className=\"ss-w-fandash-postmatch-goal-ball\" />\n <span>{g.text}</span>\n </li>\n ))}\n </ul>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchStatsCard as PostMatchStatsCardData } from '@sensiblestats/widget-sdk'\n\n// Split-bar widths as percentages, rounded to 1dp so the rendered width string stays short and\n// stable in tests. Guarded for the 0/0 case (or any non-positive total) -- an even 50/50 split\n// rather than a NaN width. Mirrors LiveStatsCard's splitWidths.\nfunction splitWidths(homeNum: number, awayNum: number): { home: string; away: string } {\n const total = homeNum + awayNum\n if (total <= 0) return { home: '50%', away: '50%' }\n const homePct = Math.round((homeNum / total) * 1000) / 10\n return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` }\n}\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function PostMatchStatsCard({ card, onTap }: {\n card: PostMatchStatsCardData\n onTap: (card: PostMatchStatsCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-stats\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-stat-rows\">\n {data.rows.map((r, i) => {\n // Row values are club-first, but the result card above renders home-left/away-right, so\n // orient by venue: the home team's value on the left, the away team's on the right. When\n // the club is the away side, that means the club's value is the RIGHT column.\n const leftValue = data.clubIsHome ? r.clubValue : r.oppValue\n const rightValue = data.clubIsHome ? r.oppValue : r.clubValue\n const homeNum = data.clubIsHome ? r.clubNum : r.oppNum\n const awayNum = data.clubIsHome ? r.oppNum : r.clubNum\n const { home, away } = splitWidths(homeNum, awayNum)\n return (\n <div key={`${r.label}-${i}`} className=\"ss-w-fandash-postmatch-stat\">\n <div className=\"ss-w-fandash-postmatch-stat-row\">\n <span className=\"ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--home\">{leftValue}</span>\n <span className=\"ss-w-fandash-postmatch-stat-label\">{r.label}</span>\n <span className=\"ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--away\">{rightValue}</span>\n </div>\n <div className=\"ss-w-fandash-postmatch-stat-bar\">\n <span className=\"ss-w-fandash-postmatch-stat-bar-home\" style={{ width: home }} />\n <span className=\"ss-w-fandash-postmatch-stat-bar-away\" style={{ width: away }} />\n </div>\n </div>\n )\n })}\n </div>\n {data.rows.length > 0 ? (\n <div className=\"ss-w-fandash-postmatch-legend\">\n <span className=\"ss-w-fandash-postmatch-legend-item\">\n <i className=\"ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--home\" />\n {data.homeName}\n </span>\n <span className=\"ss-w-fandash-postmatch-legend-item\">\n <i className=\"ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--away\" />\n {data.awayName}\n </span>\n </div>\n ) : null}\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchTopPerformerCard as PostMatchTopPerformerCardData } from '@sensiblestats/widget-sdk'\n\n// First letter of the first and last word (a single-word name yields just that one letter, since\n// first === last); whitespace/empty falls back to \"?\" rather than rendering a blank avatar.\nfunction initials(playerName: string): string {\n const words = playerName.trim().split(/\\s+/).filter(Boolean)\n if (words.length === 0) return '?'\n const first = words[0]!.charAt(0)\n const last = words[words.length - 1]!.charAt(0)\n return (words.length > 1 ? `${first}${last}` : first).toUpperCase()\n}\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard. Full mockup treatment:\n// gradient initials avatar + name + a prominent rating chip. No \"2 goals\" sub-line -- there's no\n// data for it.\nexport function PostMatchTopPerformerCard({ card, onTap }: {\n card: PostMatchTopPerformerCardData\n onTap: (card: PostMatchTopPerformerCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-performer\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-perf-row\">\n <span className=\"ss-w-fandash-postmatch-perf-avatar\" aria-hidden=\"true\">{initials(data.playerName)}</span>\n <span className=\"ss-w-fandash-postmatch-perf-name\">{data.playerName}</span>\n <span className=\"ss-w-fandash-postmatch-perf-rating\">{data.ratingLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchNextCard as PostMatchNextCardData } from '@sensiblestats/widget-sdk'\n\n// [data] card -- the upcoming fixture teaser that follows a post-match dashboard. No tap target.\n// v1 (modest): whenLabel is already a complete localized phrase composed server-side -- it\n// includes the opponent, venue and kickoff time (EN \"vs Bournemouth (H) · Sat 12 Sep · 15:00\",\n// TR \"İç sahada Bournemouth · ...\"). Rendering opponentName alongside it would duplicate the\n// opponent, so this card shows only whenLabel, dressed up with an accent rule rather than a second\n// line. The richer opponent-headline + venue chip + crest layout needs a server field split\n// (opponent vs venue vs time as separate fields) and is deferred.\nexport function PostMatchNextCard({ card }: { card: PostMatchNextCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-postmatch-next\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-next-row\">\n <span className=\"ss-w-fandash-postmatch-next-when\">{data.whenLabel}</span>\n </div>\n </div>\n )\n}\n","import type { RestingNextCard as RestingNextCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- tapping sends actionLabel as a follow-up message, carrying the opaque\n// actionRef so the server resolves the pre-issued binding (see PostMatchGoalsCard/FixtureCard).\nexport function RestingNextCard({ card, onTap }: {\n card: RestingNextCardData\n onTap: (card: RestingNextCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-next\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-next-row\">\n <span className=\"ss-w-fandash-resting-next-when\">{data.whenLabel}</span>\n {data.competition ? <span className=\"ss-w-fandash-resting-next-competition\">{data.competition}</span> : null}\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingStandingsCard as RestingStandingsCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function RestingStandingsCard({ card, onTap }: {\n card: RestingStandingsCardData\n onTap: (card: RestingStandingsCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-standings\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-standings-row\">\n <span className=\"ss-w-fandash-resting-standings-position\">{data.positionLabel}</span>\n <span className=\"ss-w-fandash-resting-standings-record\">{data.recordLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingSeasonCard as RestingSeasonCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function RestingSeasonCard({ card, onTap }: {\n card: RestingSeasonCardData\n onTap: (card: RestingSeasonCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-season\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-season-rows\">\n {data.scorerLabel ? <span className=\"ss-w-fandash-resting-season-row\">{data.scorerLabel}</span> : null}\n {data.playerLabel ? <span className=\"ss-w-fandash-resting-season-row\">{data.playerLabel}</span> : null}\n <span className=\"ss-w-fandash-resting-season-row\">{data.tallyLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingFormCard as RestingFormCardData } from '@sensiblestats/widget-sdk'\n\nfunction resultClass(result: string): string {\n const upper = result.toUpperCase()\n if (upper === 'W') return 'ss-w-fandash-form-pill--win'\n if (upper === 'L') return 'ss-w-fandash-form-pill--loss'\n return 'ss-w-fandash-form-pill--draw'\n}\n\n// [data] card -- recent form as one styled W/D/L pill per letter (same pill classes as the\n// fixture card's last-five strip). No tap target.\nexport function RestingFormCard({ card }: { card: RestingFormCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-resting-form\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <span className=\"ss-w-fandash-form\">\n {data.letters.map((r, i) => (\n <span key={`${r}-${i}`} className={`ss-w-fandash-form-pill ${resultClass(r)}`}>{r}</span>\n ))}\n </span>\n </div>\n )\n}\n","import { useRef, useState } from 'react'\nimport type { LiveScoreCard as LiveScoreCardData, LiveEventLine } from '@sensiblestats/widget-sdk'\nimport { useLiveClock } from '../../useLiveClock'\n\nfunction initials(name: string): string {\n return name.trim().slice(0, 3).toUpperCase()\n}\n\n// Crest is an <img> so a broken/absent URL falls back to a coloured initials chip -- the design\n// wants the chip whenever the crest is missing OR fails to load, which a background-image span\n// can't detect on its own.\nfunction LiveCrest({ url, name, side }: { url?: string | null; name: string; side: 'home' | 'away' }): JSX.Element {\n const [failed, setFailed] = useState(false)\n const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return (\n <span className={`${cls} ss-w-fandash-live-crest--fallback`} aria-hidden=\"true\">\n {initials(name)}\n </span>\n )\n}\n\n// Renders \"Salah 6', Núñez 9'\" from the goal events the parent filtered out of the live timeline,\n// oldest first. Events with no player name are dropped rather than rendered blank; if nothing is\n// left, the scorers line is omitted entirely.\nfunction scorersLine(goalEvents: LiveEventLine[] | undefined): string | null {\n if (!goalEvents || goalEvents.length === 0) return null\n // Defensive: only ever render actual goals, even if a caller passes an unfiltered event list.\n const named = goalEvents.filter((e) => e.type === 'goal' && e.player)\n if (named.length === 0) return null\n return named\n .slice()\n .sort((a, b) => a.minute - b.minute)\n .map((e) => `${e.player} ${e.minuteLabel}`)\n .join(', ')\n}\n\n// [data] card -- the in-play scoreboard. No tap target: the live score itself is the payload,\n// and the timeline/stats cards below carry the rest of the in-play picture.\nexport function LiveScoreCard({\n card,\n goalEvents,\n}: {\n card: LiveScoreCardData\n goalEvents?: LiveEventLine[]\n}): JSX.Element {\n const { data } = card\n\n // The reducer replaces the card object on every ~60s poll, so seeding the live-clock hook with\n // `Date.now()` on every render would restart its elapsed-time math each time and the minute\n // would never tick between polls. Reseed only when the server minute or score actually changes.\n const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`\n const seedRef = useRef<{ key: string; receivedAtMs: number } | null>(null)\n if (!seedRef.current || seedRef.current.key !== seedKey) {\n seedRef.current = { key: seedKey, receivedAtMs: Date.now() }\n }\n\n const displayMinute = useLiveClock(data.minute, data.clockRunning, seedRef.current.receivedAtMs)\n const minuteSuffix = data.minuteLabel.replace(/^\\d+/, '')\n const scorers = scorersLine(goalEvents)\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-score\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-top\">\n <span className=\"ss-w-fandash-live-pill\">\n <span className=\"ss-w-fandash-live-dot\" aria-hidden=\"true\" />\n {data.statusLabel}\n </span>\n <span className=\"ss-w-fandash-live-minute\">{`${displayMinute}${minuteSuffix}`}</span>\n {data.competition ? <span className=\"ss-w-fandash-live-competition\">{data.competition}</span> : null}\n </div>\n <div className=\"ss-w-fandash-live-main\">\n <div className=\"ss-w-fandash-live-side ss-w-fandash-live-side--home\">\n <LiveCrest url={data.homeCrestUrl} name={data.homeName} side=\"home\" />\n <span className=\"ss-w-fandash-live-team-name\">{data.homeName}</span>\n </div>\n <div className=\"ss-w-fandash-live-score-main\">\n <span className=\"ss-w-fandash-live-score-value\">{data.homeScore}</span>\n <span className=\"ss-w-fandash-live-score-sep\">–</span>\n <span className=\"ss-w-fandash-live-score-value\">{data.awayScore}</span>\n </div>\n <div className=\"ss-w-fandash-live-side ss-w-fandash-live-side--away\">\n <LiveCrest url={data.awayCrestUrl} name={data.awayName} side=\"away\" />\n <span className=\"ss-w-fandash-live-team-name\">{data.awayName}</span>\n </div>\n </div>\n {scorers ? (\n <div className=\"ss-w-fandash-live-scorers\">\n <span className=\"ss-w-fandash-live-scorers-icon\" aria-hidden=\"true\">\n ⚽\n </span>\n {scorers}\n </div>\n ) : null}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\nconst TICK_MS = 60_000\n// Generous stoppage-time headroom. The server clamps 2H to 105; if a live poll never\n// delivers a \"Finished\" transition (resolver drops the match before that lands), a stuck\n// clockRunning:true must hold here instead of climbing forever.\nconst MAX_LIVE_TICK_MINUTES = 15\n\nfunction computeDisplayMinute(minute: number, clockRunning: boolean, receivedAtMs: number): number {\n if (!clockRunning) return minute\n const elapsedMinutes = Math.floor((Date.now() - receivedAtMs) / TICK_MS)\n return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES)\n}\n\n// Ticks a live match minute forward once per real minute between server polls, so the\n// clock doesn't look frozen during the 60s gap. Reseeds immediately whenever `minute` or\n// `receivedAtMs` changes (a fresh poll), rather than waiting for the next interval tick.\nexport function useLiveClock(minute: number, clockRunning: boolean, receivedAtMs: number): number {\n const [displayMinute, setDisplayMinute] = useState(() =>\n computeDisplayMinute(minute, clockRunning, receivedAtMs),\n )\n\n useEffect(() => {\n setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs))\n\n if (!clockRunning) return\n\n const id = window.setInterval(() => {\n setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs))\n }, TICK_MS)\n\n return () => window.clearInterval(id)\n }, [minute, clockRunning, receivedAtMs])\n\n return displayMinute\n}\n","import { useState } from 'react'\nimport type { LiveTimelineCard as LiveTimelineCardData, LiveEventLine } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\n\nconst SHOWN = 3\n\n// Per-type icon: a ball mark for goals, a coloured card rectangle for yellow/red, up/down\n// arrows for a substitution. An unrecognised type (forward-compat with the server's union)\n// renders a neutral dot rather than nothing, so a new event type never looks broken.\nfunction EventIcon({ type }: { type: LiveEventLine['type'] }): JSX.Element {\n if (type === 'goal') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico ss-w-fandash-live-tl-ico--goal\" aria-hidden=\"true\">\n <span className=\"ss-w-fandash-live-tl-ball\" />\n </span>\n )\n }\n if (type === 'yellow' || type === 'red') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\">\n <span className={`ss-w-fandash-live-tl-card ss-w-fandash-live-tl-card--${type}`} />\n </span>\n )\n }\n if (type === 'sub') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\">\n <span className=\"ss-w-fandash-live-tl-subarrows\">⇅</span>\n </span>\n )\n }\n return <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\"><span className=\"ss-w-fandash-live-tl-dot\" /></span>\n}\n\n// Sub events name both players; the \"for {playerOff}\" half only renders when the server sent\n// it, and everything falls back to the server's plain text if a name field is missing.\nfunction EventLabel({ e }: { e: LiveEventLine }): JSX.Element {\n if (e.type === 'sub') {\n return (\n <span className=\"ss-w-fandash-live-tl-who\">\n {e.player ?? e.text}\n {e.playerOff ? <span className=\"ss-w-fandash-live-tl-off\"> for {e.playerOff}</span> : null}\n </span>\n )\n }\n return <span className=\"ss-w-fandash-live-tl-who\">{e.player ?? e.text}</span>\n}\n\nfunction EventRow({ e }: { e: LiveEventLine }): JSX.Element {\n const cls = [\n 'ss-w-fandash-live-tl-ev',\n e.side === 'home' ? 'ss-w-fandash-live-tl-ev--home' : 'ss-w-fandash-live-tl-ev--away',\n e.type === 'goal' ? 'ss-w-fandash-live-tl-ev--goal' : '',\n ]\n .filter(Boolean)\n .join(' ')\n return (\n <div className={cls}>\n <span className=\"ss-w-fandash-live-tl-txt\">\n <EventLabel e={e} />\n <EventIcon type={e.type} />\n </span>\n <span className=\"ss-w-fandash-live-tl-badge\">{e.minuteLabel}</span>\n </div>\n )\n}\n\n// [data] card -- the in-play event feed as a compact two-sided timeline down a centre spine:\n// each club's events sit on its own side, most-recent 3 shown with a \"See more\" toggle for the\n// rest. No tap target.\nexport function LiveTimelineCard({ card, ui }: { card: LiveTimelineCardData; ui?: UiConfig }): JSX.Element | null {\n const [expanded, setExpanded] = useState(false)\n const events = card.data.events\n if (!events || events.length === 0) return null\n\n const sorted = [...events].sort((a, b) => b.minute - a.minute)\n const rest = sorted.length - SHOWN\n const shown = expanded ? sorted : sorted.slice(0, SHOWN)\n\n const showMore = ui?.showMore ?? ((n: number) => `Show ${n} more`)\n const showLess = ui?.showLess ?? 'Show less'\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-timeline\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-tl\">\n {shown.map((e, i) => (\n <EventRow key={`${e.minute}-${e.side}-${e.type}-${i}`} e={e} />\n ))}\n </div>\n {rest > 0 ? (\n <button\n type=\"button\"\n className=\"ss-w-fandash-live-tl-more\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n >\n {expanded ? showLess : showMore(rest)}\n </button>\n ) : null}\n </div>\n )\n}\n","import { useId } from 'react'\nimport type { LiveStatsData } from '@sensiblestats/widget-sdk'\n\n// widget-sdk's events.ts defines `MomentumPoint` but its barrel (index.ts) never re-exports it on\n// its own -- only as the element type of `LiveStatsData.momentum`. Indexing off that field avoids\n// widening this task's scope to a widget-sdk barrel edit for a type alias.\ntype MomentumPoint = LiveStatsData['momentum'][number]\n\nconst WIDTH = 270\nconst HEIGHT = 56\nconst BASELINE = HEIGHT / 2 // mid-height, matches the mockup's BASE=28 for H=56\nconst SCALE = 0.26 // value ±100 -> ±26px around the baseline, same as the mockup\n\nfunction buildPaths(\n points: MomentumPoint[],\n): { area: string; line: string; lastLeftPct: number; lastTopPx: number } {\n const lastIndex = points.length - 1\n const px = (i: number): number => (lastIndex === 0 ? 0 : (i / lastIndex) * WIDTH)\n const py = (v: number): number => BASELINE - v * SCALE\n const linePts = points.map((p, i) => `${px(i).toFixed(1)},${py(p.value).toFixed(1)}`)\n const area = `M0,${BASELINE} L${linePts.join(' L')} L${WIDTH},${BASELINE} Z`\n const line = `M${linePts.join(' L')}`\n // The caller (MomentumWave) already returns null for an empty series, so lastIndex is always a\n // valid index here -- the `?? 0` only satisfies noUncheckedIndexedAccess, it never triggers.\n const lastValue = points[lastIndex]?.value ?? 0\n // The marker is an HTML overlay positioned by PERCENT of width (so it survives the SVG's\n // preserveAspectRatio=\"none\" scaling undistorted) -- always 0 for a single point, always 100 for\n // the last of more than one, matching px()'s own 0..WIDTH mapping.\n const lastLeftPct = lastIndex === 0 ? 0 : 100\n return { area, line, lastLeftPct, lastTopPx: py(lastValue) }\n}\n\n// [data] momentum wave -- no tap target. `value` is club-positive (clubPressure - oppPressure),\n// but colour follows VENUE, not club, to stay consistent with the score/timeline cards: the club's\n// own colour is --ss-w-home when `clubIsHome`, --ss-w-away otherwise. So a club-positive swing (up,\n// above the baseline) is filled with the club's venue colour, and an opponent-positive swing (down)\n// with the opponent's venue colour -- top/bottom are NOT fixed to home/away, they flip with\n// `clubIsHome` so the same team is always the same colour across every live card.\nexport function MomentumWave({\n points,\n caption,\n clubIsHome,\n}: {\n points: MomentumPoint[]\n caption?: string | null\n clubIsHome: boolean\n}): JSX.Element | null {\n if (points.length === 0) return null\n\n const { area, line, lastLeftPct, lastTopPx } = buildPaths(points)\n const clipId = useId()\n const topClipId = `${clipId}-top`\n const bottomClipId = `${clipId}-bottom`\n const topClass = clubIsHome ? 'ss-w-fandash-live-mom-home' : 'ss-w-fandash-live-mom-away'\n const bottomClass = clubIsHome ? 'ss-w-fandash-live-mom-away' : 'ss-w-fandash-live-mom-home'\n\n return (\n <div className=\"ss-w-fandash-live-mom\">\n {caption ? <span className=\"ss-w-fandash-live-mom-caption\">{caption}</span> : null}\n <div className=\"ss-w-fandash-live-mom-plot\">\n <svg\n className=\"ss-w-fandash-live-mom-svg\"\n viewBox={`0 0 ${WIDTH} ${HEIGHT}`}\n preserveAspectRatio=\"none\"\n role=\"img\"\n aria-label={caption ?? 'Momentum'}\n >\n <defs>\n <clipPath id={topClipId}>\n <rect x={0} y={0} width={WIDTH} height={BASELINE} />\n </clipPath>\n <clipPath id={bottomClipId}>\n <rect x={0} y={BASELINE} width={WIDTH} height={HEIGHT - BASELINE} />\n </clipPath>\n </defs>\n <path d={area} className={topClass} clipPath={`url(#${topClipId})`} />\n <path d={area} className={bottomClass} clipPath={`url(#${bottomClipId})`} />\n <line x1={0} y1={BASELINE} x2={WIDTH} y2={BASELINE} className=\"ss-w-fandash-live-mom-base\" />\n <path d={line} className=\"ss-w-fandash-live-mom-line\" vectorEffect=\"non-scaling-stroke\" />\n </svg>\n {/* HTML overlay dot, not an SVG <circle> -- the SVG's preserveAspectRatio=\"none\" stretches\n non-uniform scaling into an oval, and at x=WIDTH half of a circle hangs off the edge.\n An HTML element can't be deformed by the SVG's viewBox scaling, and clamp() keeps it\n fully inside the plot at both ends. */}\n <span\n className=\"ss-w-fandash-live-mom-now\"\n style={{ left: `clamp(4px, ${lastLeftPct}%, calc(100% - 4px))`, top: `${lastTopPx}px` }}\n aria-hidden=\"true\"\n />\n </div>\n </div>\n )\n}\n","import type { LiveStatsCard as LiveStatsCardData } from '@sensiblestats/widget-sdk'\nimport { MomentumWave } from './MomentumWave'\n\n// Split-bar widths as percentages, rounded to 1dp so the rendered width string stays short and\n// stable in tests. Guarded for the 0/0 case (or any non-positive total) -- an even 50/50 split\n// rather than a NaN width, since a stat can legitimately be 0-0 early in a match.\nfunction splitWidths(homeNum: number, awayNum: number): { home: string; away: string } {\n const total = homeNum + awayNum\n if (total <= 0) return { home: '50%', away: '50%' }\n const homePct = Math.round((homeNum / total) * 1000) / 10\n return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` }\n}\n\n// [data] card -- in-play match stats, home value / stat label / away value per row, each backed\n// by a home/away split bar, plus an optional momentum wave (or its text fallback). No tap target.\n//\n// LiveStatRow itself only carries clubNum/oppNum (club vs opponent), but LiveStatsData now also\n// carries `clubIsHome`/`homeName`/`awayName` (mirroring the venue signal LiveScoreCard already\n// has and the ClubIsHome pattern on RestingNextData/PostMatchNextData) -- so this card orients by\n// VENUE, not by club, to stay colour-consistent with the score and timeline cards: home is always\n// --ss-w-home on the left, away is always --ss-w-away on the right, and clubNum/oppNum are placed\n// on whichever side `clubIsHome` says the club actually occupies this match.\nexport function LiveStatsCard({ card }: { card: LiveStatsCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-stats\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-stat-rows\">\n {data.rows.map((r, i) => {\n const homeValue = data.clubIsHome ? r.clubValue : r.oppValue\n const awayValue = data.clubIsHome ? r.oppValue : r.clubValue\n const homeNum = data.clubIsHome ? r.clubNum : r.oppNum\n const awayNum = data.clubIsHome ? r.oppNum : r.clubNum\n const { home, away } = splitWidths(homeNum, awayNum)\n return (\n <div key={`${r.label}-${i}`} className=\"ss-w-fandash-live-stat\">\n <div className=\"ss-w-fandash-live-stat-row\">\n <span className=\"ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--home\">{homeValue}</span>\n <span className=\"ss-w-fandash-live-stat-label\">{r.label}</span>\n <span className=\"ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--away\">{awayValue}</span>\n </div>\n <div className=\"ss-w-fandash-live-bar\">\n <span className=\"ss-w-fandash-live-bar-home\" style={{ width: home }} />\n <span className=\"ss-w-fandash-live-bar-away\" style={{ width: away }} />\n </div>\n </div>\n )\n })}\n </div>\n {data.momentum.length > 0 ? (\n <MomentumWave points={data.momentum} caption={data.momentumLabel} clubIsHome={data.clubIsHome} />\n ) : data.momentumLabel ? (\n <span className=\"ss-w-fandash-live-momentum\">{data.momentumLabel}</span>\n ) : null}\n {data.rows.length > 0 ? (\n <div className=\"ss-w-fandash-live-legend\">\n <span className=\"ss-w-fandash-live-legend-item\">\n <i className=\"ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--home\" />\n {data.homeName}\n </span>\n <span className=\"ss-w-fandash-live-legend-item\">\n <i className=\"ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--away\" />\n {data.awayName}\n </span>\n </div>\n ) : null}\n </div>\n )\n}\n","import type {\n ClubFanDashboardCard,\n ClubFanDashboardPayload,\n CongestedWeekCard as CongestedWeekCardData,\n LiveEventLine,\n LiveTimelineCard as LiveTimelineCardData,\n PostMatchGoalsCard as PostMatchGoalsCardData,\n PostMatchStatsCard as PostMatchStatsCardData,\n PostMatchTopPerformerCard as PostMatchTopPerformerCardData,\n RestingNextCard as RestingNextCardData,\n RestingStandingsCard as RestingStandingsCardData,\n RestingSeasonCard as RestingSeasonCardData,\n} from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\nimport { FixtureCard } from './FixtureCard'\nimport { CountdownCard } from './CountdownCard'\nimport { InjuriesCard } from './InjuriesCard'\nimport { ReasonToBetCard } from './ReasonToBetCard'\nimport { WhereToWatchCard } from './WhereToWatchCard'\nimport { CongestedWeekCard } from './CongestedWeekCard'\nimport { TransfersCard } from './TransfersCard'\nimport { LinksCard } from './LinksCard'\nimport { PostMatchResultCard } from './PostMatchResultCard'\nimport { PostMatchGoalsCard } from './PostMatchGoalsCard'\nimport { PostMatchStatsCard } from './PostMatchStatsCard'\nimport { PostMatchTopPerformerCard } from './PostMatchTopPerformerCard'\nimport { PostMatchNextCard } from './PostMatchNextCard'\nimport { RestingNextCard } from './RestingNextCard'\nimport { RestingStandingsCard } from './RestingStandingsCard'\nimport { RestingSeasonCard } from './RestingSeasonCard'\nimport { RestingFormCard } from './RestingFormCard'\nimport { LiveScoreCard } from './LiveScoreCard'\nimport { LiveTimelineCard } from './LiveTimelineCard'\nimport { LiveStatsCard } from './LiveStatsCard'\n\n// The [prefill] card types (see ClubFanDashboardPayload.cs) -- tapping any of them sends its\n// actionLabel as a follow-up message, carrying the opaque actionRef so the server resolves the\n// pre-issued binding. Every other card type is a [data] card with no tap target. FixtureCard is a\n// DataCard now (u319): its tap moved to the greeting chips, so it's not in this union any more.\nexport type ClubFanDashboardTapCard =\n | CongestedWeekCardData\n | PostMatchGoalsCardData\n | PostMatchStatsCardData\n | PostMatchTopPerformerCardData\n | RestingNextCardData\n | RestingStandingsCardData\n | RestingSeasonCardData\n\nexport function ClubFanDashboard({ dashboard, onTap, ui }: {\n dashboard: ClubFanDashboardPayload\n onTap: (card: ClubFanDashboardTapCard) => void\n ui?: UiConfig\n}): JSX.Element {\n // The clock leads the dashboard, so any countdown card is floated to the top; the rest keep\n // their server order.\n const orderedCards = [\n ...dashboard.cards.filter((c) => c.cardType === 'countdown'),\n ...dashboard.cards.filter((c) => c.cardType !== 'countdown'),\n ]\n // The score card's scorers line is derived from the sibling timeline card's goal events, so it\n // needs pulling out here where the full card list is in scope. Null-safe: no timeline card (or\n // no goals in it) means no scorers line, not a crash.\n const timelineCard = dashboard.cards.find(\n (c): c is LiveTimelineCardData => c.cardType === 'liveTimeline',\n )\n const goalEvents = timelineCard?.data.events.filter((e) => e.type === 'goal')\n return (\n <div className=\"ss-w-fandash\">\n {dashboard.greeting ? <span className={dashboard.greetingIsLead ? 'ss-w-fandash-greeting ss-w-fandash-greeting--lead' : 'ss-w-fandash-greeting'}>{dashboard.greeting}</span> : null}\n <div className=\"ss-w-fandash-cards\">\n {orderedCards.map((card, i) => (\n <FanDashboardCard key={`${card.cardType}-${i}`} card={card} onTap={onTap} ui={ui} goalEvents={goalEvents} />\n ))}\n </div>\n </div>\n )\n}\n\nfunction FanDashboardCard({ card, onTap, ui, goalEvents }: {\n card: ClubFanDashboardCard\n onTap: (card: ClubFanDashboardTapCard) => void\n ui?: UiConfig\n goalEvents?: LiveEventLine[]\n}): JSX.Element | null {\n switch (card.cardType) {\n case 'fixture':\n return <FixtureCard card={card} />\n case 'countdown':\n return <CountdownCard card={card} />\n case 'injuries':\n return <InjuriesCard card={card} ui={ui} />\n case 'reasonToBet':\n return <ReasonToBetCard card={card} />\n case 'whereToWatch':\n return <WhereToWatchCard card={card} />\n case 'congestedWeek':\n return <CongestedWeekCard card={card} onTap={onTap} />\n case 'transfers':\n return <TransfersCard card={card} />\n case 'links':\n return <LinksCard card={card} />\n case 'postMatchResult':\n return <PostMatchResultCard card={card} />\n case 'postMatchGoals':\n return <PostMatchGoalsCard card={card} onTap={onTap} />\n case 'postMatchStats':\n return <PostMatchStatsCard card={card} onTap={onTap} />\n case 'postMatchTopPerformer':\n return <PostMatchTopPerformerCard card={card} onTap={onTap} />\n case 'postMatchNext':\n return <PostMatchNextCard card={card} />\n case 'restingNext':\n return <RestingNextCard card={card} onTap={onTap} />\n case 'restingStandings':\n return <RestingStandingsCard card={card} onTap={onTap} />\n case 'restingSeason':\n return <RestingSeasonCard card={card} onTap={onTap} />\n case 'restingForm':\n return <RestingFormCard card={card} />\n case 'liveScore':\n return <LiveScoreCard card={card} goalEvents={goalEvents} />\n case 'liveTimeline':\n return <LiveTimelineCard card={card} ui={ui} />\n case 'liveStats':\n return <LiveStatsCard card={card} />\n default:\n // The server's cardType is a closed set, but a mismatched deploy could still send an\n // unrecognised discriminator -- render nothing for it rather than crash the whole turn.\n return null\n }\n}\n","import type { GreetingDashboardTile } from '@sensiblestats/widget-sdk'\nimport type { Message } from '../reducer'\nimport type { ActionVM } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { Markdown } from './Markdown'\nimport { EntityCardList } from './EntityCardList'\nimport { BettingInsightList } from './BettingInsightList'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { OddsMovementCardList } from './OddsMovementCard'\nimport { ActionButtons } from './ActionButtons'\nimport { GreetingDashboard } from './dashboard/GreetingDashboard'\nimport { ClubFanDashboard, type ClubFanDashboardTapCard } from './dashboard/ClubFanDashboard'\n\nexport function ChatMessage({ message, disabled, onAct, onTap, ui, slip, monitor }: {\n message: Message\n disabled: boolean\n onAct: (a: ActionVM) => void\n onTap: (tile: GreetingDashboardTile, index: number) => void\n ui?: UiConfig\n slip: SlipHandlerProps\n monitor?: LiveMonitorController\n}): JSX.Element {\n if (message.role === 'user') {\n return <div className=\"ss-w-msg ss-w-user\" data-msg-id={message.id}><div className=\"ss-w-bubble\">{message.text}</div></div>\n }\n // A [prefill] club-fan-dashboard card tap reuses the same send path as an action button --\n // actionLabel becomes both the message and the display text, and the opaque actionRef rides\n // along so the server resolves the card's pre-issued action binding rather than re-planning\n // a prose command -- rather than threading a second tap handler through MessageList.\n const onFanDashboardTap = (card: ClubFanDashboardTapCard): void => {\n onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || '' })\n }\n return (\n <div className=\"ss-w-msg ss-w-bot\" data-msg-id={message.id}>\n {message.text && !message.greetingDashboard && !message.clubFanDashboard ? <Markdown text={message.text} /> : null}\n {message.greetingDashboard && !message.clubFanDashboard ? <GreetingDashboard dashboard={message.greetingDashboard} onTap={onTap} /> : null}\n {message.clubFanDashboard ? <ClubFanDashboard dashboard={message.clubFanDashboard} onTap={onFanDashboardTap} ui={ui} /> : null}\n <EntityCardList cards={message.cards} disabled={disabled} showLessLabel={ui?.showLess} showMoreLabel={ui?.showMore} />\n <BettingInsightList insights={message.insights} ui={ui} slip={slip} monitor={monitor} />\n <MarketOddsCardList cards={message.marketOdds} ui={ui} slip={slip} monitor={monitor} />\n <OddsMovementCardList cards={message.oddsMovement} ui={ui} monitor={monitor} />\n <ActionButtons actions={message.actions} loading={false} disabled={disabled} onAct={onAct} />\n </div>\n )\n}\n","import type { ChipVM } from '../model'\n\nexport function IntentChips({ chips, onPick }: { chips: ChipVM[]; onPick: (text: string) => void }): JSX.Element | null {\n if (chips.length === 0) return null\n return (\n <div className=\"ss-w-chips\">\n {chips.map((c, i) => (\n <button key={`${c.text}-${i}`} type=\"button\" className=\"ss-w-chip\" onClick={() => onPick(c.text)}>{c.text}</button>\n ))}\n </div>\n )\n}\n","// Distance (px) from the bottom within which the list is still considered\n// \"pinned\" — small enough that a user reading earlier content isn't counted\n// as pinned, large enough to absorb sub-pixel/rounding drift while streaming.\nexport const PIN_THRESHOLD = 48\n\n/**\n * True when the scroll container is at (or within PIN_THRESHOLD of) its bottom.\n * Used to decide whether new content should auto-scroll: we follow the stream\n * only while the user is already at the bottom, so late arrivals (e.g. suggested\n * actions) never yank a user who has scrolled up to read.\n */\nexport function isPinnedToBottom(el: Pick<HTMLElement, 'scrollHeight' | 'scrollTop' | 'clientHeight'>, threshold = PIN_THRESHOLD): boolean {\n return el.scrollHeight - el.scrollTop - el.clientHeight <= threshold\n}\n","import { useState, type KeyboardEvent } from 'react'\nimport { SendIcon } from './Icons'\n\nexport function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = 'Stop response', sendLabel = 'Send message' }: { placeholder: string; streaming: boolean; onSend: (t: string) => void; onStop: () => void; stopLabel?: string; sendLabel?: string }): JSX.Element {\n const [value, setValue] = useState('')\n const submit = () => { const t = value.trim(); if (!t) return; onSend(t); setValue('') }\n const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit() }\n }\n return (\n <div className=\"ss-w-input\">\n <textarea className=\"ss-w-textarea\" rows={1} placeholder={placeholder} value={value} disabled={streaming} onChange={(e) => setValue(e.target.value)} onKeyDown={onKeyDown} />\n {streaming ? (\n <button type=\"button\" className=\"ss-w-send ss-w-stop\" aria-label={stopLabel} onClick={onStop}><span className=\"ss-w-stop-glyph\" /></button>\n ) : (\n <button type=\"button\" className=\"ss-w-send\" aria-label={sendLabel} onClick={submit}><SendIcon /></button>\n )}\n </div>\n )\n}\n","import type { LiveMonitorController, MonitorTab } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\n\nexport function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday, gamesEnabled }: {\n monitor: LiveMonitorController\n ui: UiConfig\n matchCount: number\n oddsCount: number\n /** Live match count. NEVER the fixture count -- a Saturday would badge 41. */\n todayCount: number\n hasToday: boolean\n /** Enabled when getGames resolves non-null; false for betting operators (404 sentinel). */\n gamesEnabled?: boolean\n}): JSX.Element | null {\n const tabs: { tab: MonitorTab; label: string; count: number; dot: boolean }[] = [\n { tab: 'chat', label: ui.tabChat, count: 0, dot: monitor.chatDot },\n ...(hasToday ? [{ tab: 'today' as MonitorTab, label: ui.tabToday, count: todayCount, dot: monitor.todayDot }] : []),\n ...(matchCount > 0 ? [{ tab: 'following' as MonitorTab, label: ui.tabFollowing, count: matchCount, dot: monitor.matchesDot }] : []),\n ...(oddsCount > 0 ? [{ tab: 'odds' as MonitorTab, label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : []),\n ...(gamesEnabled ? [\n { tab: 'games' as MonitorTab, label: ui.tabGames, count: 0, dot: false },\n { tab: 'leaderboard' as MonitorTab, label: ui.tabLeaderboard, count: 0, dot: false },\n ] : []),\n ]\n\n // A lone Chat tab is chrome that selects nothing -- the strip stays hidden, as it does today\n // when nothing is pinned.\n if (tabs.length < 2) return null\n\n return (\n <div className=\"ss-w-tabs\" role=\"tablist\">\n {tabs.map(({ tab, label, count, dot }) => {\n const active = monitor.activeTab === tab\n return (\n <button\n key={tab}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n data-on={active ? '' : undefined}\n className=\"ss-w-tab\"\n onClick={() => monitor.setActiveTab(tab)}\n >\n {label}\n {count > 0 && <span className=\"ss-w-tab-count\">{count}</span>}\n {dot && !active && <span className=\"ss-w-tab-dot\" aria-hidden=\"true\" />}\n </button>\n )\n })}\n </div>\n )\n}\n","import type { LiveMonitorMatch } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { PinToggle } from './PinToggle'\nimport { toMarketOddsVM } from '../model'\n\nexport function MarketAccordion({ match, monitor, ui, slip }: {\n match: LiveMonitorMatch\n monitor: LiveMonitorController\n ui: UiConfig\n slip: SlipHandlerProps\n}): JSX.Element | null {\n const markets = match.availableMarkets ?? []\n if (markets.length === 0) return null\n const open = monitor.openMarket[match.matchId] ?? null\n\n return (\n <div className=\"ss-w-acc\">\n {markets.map((m) => {\n // A suspended market has no servable card: the odds lookup drops every suspended/stopped\n // row, so /live-monitor/market answers 404 MarketNotPriced and the panel lands on the\n // tap-to-retry affordance, which can never succeed. Don't offer the tap. `&& !m.suspended`\n // also collapses a market that suspends WHILE open, instead of leaving stale rows up.\n const isOpen = open === m.marketDeveloperName && !m.suspended\n const key = `${match.matchId}:${m.marketDeveloperName}`\n const entry = monitor.marketOdds[key]\n return (\n <div key={m.marketDeveloperName} className={isOpen ? 'ss-w-acc-row ss-w-acc-row-open' : 'ss-w-acc-row'}>\n <div className=\"ss-w-acc-head\">\n <button\n type=\"button\"\n className={m.suspended ? 'ss-w-acc-toggle ss-w-acc-toggle--susp' : 'ss-w-acc-toggle'}\n aria-expanded={isOpen}\n disabled={m.suspended}\n onClick={() => monitor.toggleMarket(match.matchId, m.marketDeveloperName)}\n >\n <span className=\"ss-w-acc-chevron\">{m.suspended ? '' : isOpen ? '▾' : '▸'}</span>\n <span className=\"ss-w-acc-label\">{m.marketLabel}</span>\n {m.hasInsight && <span className=\"ss-w-acc-badge\">★</span>}\n {m.suspended && <span className=\"ss-w-acc-susp\">{ui.accordionSuspended}</span>}\n </button>\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{ kind: 'market', matchId: match.matchId, marketDeveloperName: m.marketDeveloperName }}\n />\n </div>\n {isOpen && (\n <div className=\"ss-w-acc-panel\">\n {entry?.error && (\n <div\n className=\"ss-w-acc-retry\"\n onClick={() => monitor.retryMarket(match.matchId, m.marketDeveloperName)}\n >\n {ui.accordionRetry}\n </div>\n )}\n {entry?.block?.insight?.text && (\n <div className=\"ss-w-acc-insight\">\n <span className=\"ss-w-acc-badge\">{ui.accordionValueLabel}</span> {entry.block.insight.text}\n </div>\n )}\n {entry?.block?.card && (\n <MarketOddsCardList\n cards={[toMarketOddsVM(entry.block.card)]}\n ui={ui}\n slip={slip}\n monitor={monitor}\n inSlipIds={monitor.inSlip}\n hideHeader\n />\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n","import type { LiveMonitorEvent, LiveMonitorMatch, LiveMonitorStatRow, PinRef, SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport { SlipButton } from './AddToSlipButton'\nimport { Crest } from './Crest'\nimport { MomentumWave } from './dashboard/MomentumWave'\nimport { PinToggle } from './PinToggle'\n\nfunction chipSelection(row: LiveMonitorStatRow, matchId: number, conversationId?: string): SlipSelection | null {\n const chip = row.market\n if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== 'number' || typeof chip.price !== 'number') return null\n const selection: SlipSelection = { matchOddsId: chip.matchOddsId, matchId, oddsDecimal: chip.price }\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n\n// A stat row's market chip promotes to the top when the user has pinned that market -- matched by\n// FIELD, never by a reconstructed pin key. LiveMonitorStatPrice carries no `line`, and its\n// selectionLabel is server-localized (TR \"2.5 Üst\" vs the stored pin's raw \"Over\"), so any key\n// string built from the chip would never equal the stored pin's key. marketDeveloperName is the\n// one field both sides always share in its raw, unlocalized form; matchOddsId is an unambiguous\n// same-selection identifier when both sides carry it.\nfunction isPromoted(row: LiveMonitorStatRow, promotedPins: readonly PinRef[]): boolean {\n const chip = row.market\n if (!chip) return false\n return promotedPins.some((pin) =>\n pin.marketDeveloperName === chip.marketDeveloperName ||\n (chip.matchOddsId != null && pin.matchOddsId === chip.matchOddsId))\n}\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface ScorerLine { player: string; label: string }\n\n// One line per scorer for a single side, in the order goals were scored, with a brace collapsed\n// onto that scorer's line (\"Powell 87', 90+6'\"). An own goal carries an \"(OG)\" marker on its\n// minute. Goals arrive already ascending from the server; grouping by name preserves that order\n// via the first appearance of each scorer.\nfunction groupScorers(goals: LiveMonitorEvent[], ownGoalLabel: string): ScorerLine[] {\n const order: string[] = []\n const minutesByPlayer = new Map<string, string[]>()\n for (const g of goals) {\n const name = g.player ?? ''\n const minute = g.ownGoal ? `${g.minuteLabel} (${ownGoalLabel})` : g.minuteLabel\n if (!minutesByPlayer.has(name)) {\n minutesByPlayer.set(name, [])\n order.push(name)\n }\n minutesByPlayer.get(name)!.push(minute)\n }\n return order.map((name) => {\n const minutes = minutesByPlayer.get(name)!.join(', ')\n return { player: name, label: name ? `${name} ${minutes}` : minutes }\n })\n}\n\nexport function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }: {\n match: LiveMonitorMatch\n /** the user's non-match pins on this match — their stat rows promote to the top strip */\n promotedPins: PinRef[]\n monitor: LiveMonitorController\n ui: UiConfig\n slip: SlipHandlerProps\n}): JSX.Element {\n const live = match.phase === 'live'\n const goals = match.events.filter((e) => e.type === 'goal')\n const homeScorers = groupScorers(goals.filter((e) => e.side === 'home'), ui.ownGoalLabel)\n const awayScorers = groupScorers(goals.filter((e) => e.side === 'away'), ui.ownGoalLabel)\n const promotedRows = match.statRows.filter((row) => isPromoted(row, promotedPins))\n const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins))\n const orderedRows = [...promotedRows, ...otherRows]\n const kickoff = match.phase === 'preMatch' && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : undefined\n\n return (\n <div className=\"ss-w-mon\">\n <div className=\"ss-w-mon-top\">\n {live && (\n <span className=\"ss-w-fandash-live-pill\">\n <span className=\"ss-w-fandash-live-dot\" aria-hidden=\"true\" />\n {ui.liveLabel}\n </span>\n )}\n {match.phase === 'fullTime' && <span className=\"ss-w-mon-pill\">{ui.fullTimeLabel}</span>}\n {kickoff && <span className=\"ss-w-mon-pill\">{kickoff.dayLabel} · {kickoff.time}</span>}\n {live && match.minuteLabel && <span className=\"ss-w-mon-min\">{match.minuteLabel}</span>}\n {match.competitionName && <span className=\"ss-w-mon-comp\">{match.competitionName}</span>}\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: match.matchId }} />\n </div>\n <div className=\"ss-w-mon-main\">\n <span className=\"ss-w-mon-side\">\n <Crest kind=\"team\" url={match.homeCrestUrl ?? undefined} name={match.homeTeamName ?? undefined} />\n <span className=\"ss-w-mon-name\">{match.homeTeamName}</span>\n </span>\n {match.phase === 'preMatch' ? (\n <span className=\"ss-w-mon-vs\">vs</span>\n ) : (\n <span className=\"ss-w-mon-score\">{match.homeScore}<i>–</i>{match.awayScore}</span>\n )}\n <span className=\"ss-w-mon-side ss-w-mon-side--away\">\n <Crest kind=\"team\" url={match.awayCrestUrl ?? undefined} name={match.awayTeamName ?? undefined} />\n <span className=\"ss-w-mon-name\">{match.awayTeamName}</span>\n </span>\n </div>\n {(homeScorers.length > 0 || awayScorers.length > 0) && (\n <div className=\"ss-w-mon-scorers\">\n <ul className=\"ss-w-mon-scorers-col ss-w-mon-scorers-home\">\n {homeScorers.map((s, i) => <li key={`${s.player}-${i}`}>{s.label}</li>)}\n </ul>\n <span className=\"ss-w-mon-scorers-ball\" aria-hidden=\"true\">⚽</span>\n <ul className=\"ss-w-mon-scorers-col ss-w-mon-scorers-away\">\n {awayScorers.map((s, i) => <li key={`${s.player}-${i}`}>{s.label}</li>)}\n </ul>\n </div>\n )}\n <div className=\"ss-w-mon-stats\">\n {orderedRows.map((row) => {\n const total = row.homeNum + row.awayNum\n const homePct = total > 0 ? (row.homeNum / total) * 75 : 0\n const awayPct = total > 0 ? (row.awayNum / total) * 75 : 0\n const promoted = isPromoted(row, promotedPins)\n const selection = chipSelection(row, match.matchId, slip.conversationId)\n return (\n <div className={promoted ? 'ss-w-mon-stat ss-w-mon-pstrip' : 'ss-w-mon-stat'} key={row.label}>\n <div className=\"ss-w-mon-stat-row\">\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--home\">{row.homeValue}</span>\n <span className=\"ss-w-mon-stat-l\">{row.label}</span>\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--away\">{row.awayValue}</span>\n </div>\n <div className=\"ss-w-mon-bar\">\n <b className=\"ss-w-mon-bar-home\" style={{ width: `${homePct}%` }} />\n <i className=\"ss-w-mon-bar-away\" style={{ width: `${awayPct}%` }} />\n </div>\n {/* A suspended market drops its whole betting line -- label, price and button -- and\n the stat row keeps its bar, exactly like a row with no market at all. Showing it\n offered a price the bookmaker was not taking next to a live Add to slip whose\n only possible outcome was the slipSuspended error toast. bet365 suspends\n derivative in-play markets constantly: measured across 20 live matches, 61% of\n Goals Over/Under rows and 69% of 1st Half Goals rows were suspended against 9%\n of Fulltime Result. */}\n {row.market && !row.market.isSuspended && (\n <div className={promoted ? 'ss-w-mon-stat-mkt ss-w-mon-mkt' : 'ss-w-mon-stat-mkt'}>\n <span>{row.market.marketLabel} · {row.market.selectionLabel}</span>\n <span className=\"ss-w-mon-stat-mkt-right\">\n {typeof row.market.price === 'number' && <span className=\"ss-w-mon-price\">{row.market.price.toFixed(2)}</span>}\n <SlipButton\n selection={selection}\n shownOdds={typeof row.market.price === 'number' ? row.market.price.toFixed(2) : ''}\n marketName={row.market.marketLabel}\n marketDeveloperName={row.market.marketDeveloperName}\n slip={slip}\n ui={ui}\n />\n </span>\n </div>\n )}\n </div>\n )\n })}\n </div>\n {match.status === 'stale' && <span className=\"ss-w-mon-asof\">{ui.asOf(formatTime(match.asOfUtc))}</span>}\n {match.momentum.length > 0 && (\n <div className=\"ss-w-mon-mom\">\n {/* Label only -- no percentage split. momentumHomePct is a share of the WHOLE match's\n accumulated pressure, so it reads as a verdict on the match (\"99% - 1%\") when the\n wave beneath it is showing minute-by-minute swing. The two disagree on sight, and\n the share is the one that misleads. */}\n <span className=\"ss-w-mon-stat-l\">{ui.momentumLabel}</span>\n <MomentumWave points={match.momentum} clubIsHome={true} />\n </div>\n )}\n {match.phase === 'fullTime' && <div className=\"ss-w-mon-grace\">{ui.graceNote}</div>}\n </div>\n )\n}\n","import type { LiveMonitorMarket } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { MarketOddsRowVM, MarketOddsVM } from '../model'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { OddsMovementCardList } from './OddsMovementCard'\nimport { MarketAccordion } from './MarketAccordion'\nimport { MonitorMatchCard } from './MonitorMatchCard'\nimport { toMarketOddsVM, toOddsMovementVM } from '../model'\n\n// Slim live-only strip above an Odds-tab market card. The card itself already shows the\n// competition, fixture, market, kickoff and the unpin — so this renders ONLY the match-live\n// context the card lacks (score, minute, suspended/settled, stale as-of), and nothing at all for\n// a pre-match market (avoids duplicating the card's fixture/kickoff). (u342)\nfunction OddsLiveStrip({ m, ui }: { m: LiveMonitorMarket; ui: UiConfig }): JSX.Element | null {\n const showScore = m.phase !== 'preMatch' && typeof m.homeScore === 'number'\n const stale = m.status === 'stale'\n if (!showScore && !m.minuteLabel && !(m.isSuspended && !m.isSettled) && !m.isSettled && !stale) return null\n return (\n <div className=\"ss-w-mk-live\">\n {showScore && (\n <b className=\"ss-w-mk-live-score\">{m.homeTeamName} {m.homeScore}–{m.awayScore} {m.awayTeamName}</b>\n )}\n {m.minuteLabel && <span className=\"ss-w-mon-min\">{m.minuteLabel}</span>}\n {m.isSuspended && !m.isSettled && <span className=\"ss-w-mon-susp\">{ui.suspendedLabel}</span>}\n {m.isSettled && <span className=\"ss-w-mon-pill\">{ui.fullTimeLabel}</span>}\n {stale && (\n <span className=\"ss-w-mon-asof\">{ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }))}</span>\n )}\n </div>\n )\n}\n\nexport function MatchesPanel({ monitor, ui, slip }: { monitor: LiveMonitorController; ui: UiConfig; slip: SlipHandlerProps }): JSX.Element {\n // Only EXPLICIT match pins surface here (2026-09-06 ruling: an odds pin tracks odds, a match\n // pin tracks the match -- never combined). Filtering against current pins, not just the\n // snapshot, also makes an unpin drop the card immediately.\n const matches = (monitor.snapshot?.matches ?? []).filter((m) =>\n monitor.pins.some((p) => p.kind === 'match' && p.matchId === m.matchId))\n if (matches.length === 0) return <div className=\"ss-w-mon-empty\">{ui.emptyMatchesTab}</div>\n return (\n <div className=\"ss-w-mon-list\">\n {matches.map((m) => (\n <div key={m.matchId} className=\"ss-w-mon-item\">\n <MonitorMatchCard\n match={m}\n // promotion is PER MATCH: only odds pins on THIS match promote their stat row\n promotedPins={monitor.pins.filter((p) => p.kind !== 'match' && p.matchId === m.matchId)}\n monitor={monitor}\n ui={ui}\n slip={slip}\n />\n <MarketAccordion match={m} monitor={monitor} ui={ui} slip={slip} />\n </div>\n ))}\n </div>\n )\n}\n\n// I2 (since-view movement): the badge on a pin's PRIMARY row must reflect what THIS operator's\n// client last saw (monitor.lastViewedPrices, keyed by the market snapshot's own key), never the\n// server's own previousPrice/movementDirection window -- those two clocks are unrelated. Only the\n// first main row carries this override; other rows/lines keep whatever (if anything) the server\n// sent.\nfunction withSinceViewMovement(vm: MarketOddsVM, prev: number | undefined): MarketOddsVM {\n const primary = vm.mainRows[0]\n if (prev === undefined || !primary || primary.oddsDecimal === undefined || primary.oddsDecimal === prev) return vm\n const updatedPrimary: MarketOddsRowVM = {\n ...primary,\n previousOdds: prev.toFixed(2),\n movementDirection: primary.oddsDecimal < prev ? 'shortened' : 'drifted',\n }\n return { ...vm, mainRows: [updatedPrimary, ...vm.mainRows.slice(1)] }\n}\n\nexport function OddsPanel({ monitor, ui, slip }: { monitor: LiveMonitorController; ui: UiConfig; slip: SlipHandlerProps }): JSX.Element {\n // Same current-pins filter as MatchesPanel: only markets a stored pin still claims render, so\n // every card carries its unpin affordance and vanishes the moment that pin is removed.\n const markets = (monitor.snapshot?.markets ?? []).filter((m) =>\n monitor.pins.some((p) => p.key === m.key))\n if (markets.length === 0) return <div className=\"ss-w-mon-empty\">{ui.emptyOddsTab}</div>\n return (\n <div className=\"ss-w-mon-list\">\n {markets.map((m) => {\n // The unpin lives in the card's own header now; pass the ORIGINAL stored pin ref (found by\n // key) so its pinKey matches exactly -- the card would otherwise reconstruct a market pin\n // with line=mainLine, which never matches an accordion pin stored without a line.\n const pin = monitor.pins.find((p) => p.key === m.key)\n return (\n <div className=\"ss-w-mon-oddspin\" key={m.key} data-settled={m.isSettled || undefined}>\n <OddsLiveStrip m={m} ui={ui} />\n {/* D5 persistent in-slip badge: the wasAdded->markInSlip wrapping now lives in\n StatsWidget's own slip memo (so a conversation-path add also arms the badge) --\n this panel only reads monitor.inSlip to render it. */}\n {m.card && (\n <MarketOddsCardList\n cards={[withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])]}\n ui={ui}\n slip={slip}\n monitor={monitor}\n pinRef={pin ?? undefined}\n inSlipIds={monitor.inSlip}\n />\n )}\n {m.history && <OddsMovementCardList cards={[toOddsMovementVM(m.history)]} ui={ui} />}\n {!m.card && !m.history && <div className=\"ss-w-mon-empty-card\">{ui.oddsUnavailable}</div>}\n </div>\n )\n })}\n </div>\n )\n}\n","import type { MatchState, ScheduleMatch } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { PinToggle } from './PinToggle'\n\nfunction kickoffLabel(kickoffUnix: number): string {\n const d = new Date(kickoffUnix * 1000)\n return `${`${d.getHours()}`.padStart(2, '0')}:${`${d.getMinutes()}`.padStart(2, '0')}`\n}\n\n// The away side mirrors the home side around the score: crest on the far (right)\n// edge, name aligned inward toward the score. Reversing the flow in CSS keeps the\n// DOM order crest→name identical to home, matching the away pattern used by the\n// fandash fixture/live cards.\nfunction Side({ name, crest, away = false }: { name: string; crest?: string | null; away?: boolean }): JSX.Element {\n return (\n <span className={away ? 'ss-w-drow-side ss-w-drow-side--away' : 'ss-w-drow-side'}>\n {crest ? <img className=\"ss-w-drow-crest\" src={crest} alt=\"\" /> : null}\n <span className=\"ss-w-drow-nm\">{name}</span>\n </span>\n )\n}\n\nexport function FixtureRow({ match, state, stale, ui, monitor }: {\n match: ScheduleMatch\n state?: MatchState\n stale: boolean\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element {\n // Deliberately no per-match staleness test. u357 added one, reading Match.UpdatedAt through\n // stateAsOfUtc — but that column advances only when the DATA CHANGES, not when we poll. Measured\n // on sandbox1: every live match had a poll age of 31-48s while UpdatedAt ages ran 32-1451s, so\n // the guard suppressed the clock on 9 of 17 healthy matches, Levante v Barcelona among them. The\n // stalled window it was built for does not exist; `stale` (our own fetch failing) is the only\n // real signal we have, and it already covers the whole payload.\n const isLive = state?.phase === 'live' && !stale\n // Gated on phase, never on the presence of a number: /states counts goal rows, so it reports 0\n // for a fixture with none whatever its phase, and the due set polls anything whose kickoff clock\n // has passed. A \"NotStarted\" fixture between the clock passing and the live feed flipping would\n // otherwise read 0-0. The typeof pair only narrows the template below.\n const hasScore = (state?.phase === 'live' || state?.phase === 'fullTime')\n && typeof state.homeScore === 'number' && typeof state.awayScore === 'number'\n\n // Rendered verbatim. The minute runs ~2 min behind wall clock because the provider's own\n // `minutes` field is a snapshot we freeze until the next poll -- that is being corrected at the\n // source in the hub (deriving from the ticking period's start), NOT compensated for here. Two\n // layers each adding elapsed to the same number is how you get a 139th minute.\n const ticked = state?.phase === 'live' ? (state.minuteLabel ?? null) : null\n const when = state?.isHalfTime && !stale\n ? ui.halfTime\n : isLive\n ? (ticked ?? '\\u2014')\n : state?.phase === 'live'\n ? '\\u2014'\n : kickoffLabel(match.kickoffUnix)\n\n return (\n <div className={isLive || state?.isHalfTime ? 'ss-w-drow ss-w-drow--live' : 'ss-w-drow'}>\n <span className={isLive || state?.isHalfTime ? 'ss-w-drow-when ss-w-drow-when--live' : 'ss-w-drow-when'}>{when}</span>\n <span className=\"ss-w-drow-fx\">\n <Side name={match.homeTeamName} crest={match.homeTeamImagePath} />\n {/* The score sits between the two sides, where a scoreboard puts it. With no score yet it\n is the separating dash, so the row keeps one shape before and after kickoff. */}\n <span className={hasScore ? 'ss-w-drow-sc' : 'ss-w-drow-sc ss-w-drow-sc--idle'}>\n {hasScore ? `${state!.homeScore}–${state!.awayScore}` : '–'}\n </span>\n <Side name={match.awayTeamName} crest={match.awayTeamImagePath} away />\n </span>\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: match.matchId }} />\n </div>\n )\n}\n","import type { MatchState, ScheduleGroup } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { FixtureRow } from './FixtureRow'\nimport { isTreatedLive } from '../liveClock'\n\nexport function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor, disambiguate = false }: {\n group: ScheduleGroup\n open: boolean\n onToggle(): void\n /** True when another group on screen shares this competition's name, so the name alone\n * does not identify it. Only then is the country worth the horizontal space. */\n disambiguate?: boolean\n states: Record<number, MatchState>\n stale: boolean\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element | null {\n // A live fixture is rendered in the live band above, so it is absent here AND absent from the\n // count -- the badge has to agree with what is under the header. But once the poll goes stale\n // the live band hides itself (Task 13), so a cached phase:'live' match must fall back into its\n // group rather than vanish from the tab entirely -- mirrors FixtureRow's own isLive check.\n const own = group.matches.filter((m) => !isTreatedLive(states[m.matchId], stale))\n const hasLive = own.length !== group.matches.length\n\n // Every match hoisted into the live band leaves nothing under this header. Rendering anyway\n // produced a header reading \"Championship ... 0\" whose body was empty however you toggled it.\n // Hiding it is safe against the vanish bug the filter above guards: when the poll goes stale\n // isTreatedLive is false for everything, so own is the full list and the group comes back.\n if (own.length === 0) {\n return null\n }\n\n return (\n <div className=\"ss-w-grp\">\n <button type=\"button\" className=\"ss-w-grp-head\" aria-expanded={open} onClick={onToggle}>\n <span className=\"ss-w-grp-chev\">{open ? '▾' : '▸'}</span>\n {hasLive && <span className=\"ss-w-sec-dot\" aria-hidden=\"true\" />}\n <span className=\"ss-w-grp-name\">\n {group.competitionName}\n {disambiguate && group.competitionCountry\n ? <span className=\"ss-w-grp-country\"> ({group.competitionCountry})</span>\n : null}\n </span>\n <span className=\"ss-w-grp-count\">{own.length}</span>\n </button>\n {open && (\n <div className=\"ss-w-grp-body\">\n {own.map((m) => (\n <FixtureRow key={m.matchId} match={m} state={states[m.matchId]} stale={stale} ui={ui} monitor={monitor} />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { MatchDiscoveryController } from '../useMatchDiscovery'\nimport { CompetitionGroup } from './CompetitionGroup'\nimport { FixtureRow } from './FixtureRow'\nimport { isTreatedLive, visibleGroupsOf } from '../liveClock'\n\nexport function TodayPanel({ discovery, ui, monitor }: {\n discovery: MatchDiscoveryController\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element {\n const { groups, states, stale, expanded, toggleGroup } = discovery\n\n // Finished matches leave the day. Everything below reads visibleGroups, never groups: the live\n // band, the name-collision count, the group list and the tab strip that decides whether this\n // panel is reachable at all have to agree on what the day contains, and filtering in one place\n // is what guarantees that.\n const visibleGroups = visibleGroupsOf(groups, states)\n\n // Flat across competitions but ordered by the competition's rank, then by the fixture's position\n // inside its group -- no ranking field of the client's own. Array.sort is stable, so ties within\n // a rank keep the flatMap's group-then-match order.\n // The sort is NOT dead code: `rank` is the contract, the array order is not. That the composer\n // currently emits groups already in rank order is incidental -- nothing in the wire format\n // promises it, and a server-side reordering would silently scramble the live band without this.\n const liveRows = stale\n ? []\n : visibleGroups\n .flatMap((group) =>\n group.matches\n .filter((m) => isTreatedLive(states[m.matchId], stale))\n .map((match) => ({ match, rank: group.rank })))\n .sort((a, b) => a.rank - b.rank)\n\n // competitionName is not an identity: a real Saturday returns four groups named \"Premier\n // League\". Only collide-on-screen names pay the horizontal cost of a country suffix.\n const nameCounts = visibleGroups.reduce<Record<string, number>>((acc, g) => {\n acc[g.competitionName] = (acc[g.competitionName] ?? 0) + 1\n return acc\n }, {})\n\n return (\n <div className=\"ss-w-mon-list\">\n {stale && <div className=\"ss-w-stale\">{ui.staleStates}</div>}\n\n {liveRows.length > 0 && (\n <>\n <div className=\"ss-w-sec-head\">\n <span className=\"ss-w-sec-dot\" aria-hidden=\"true\" />\n {ui.sectionLive}\n </div>\n <div className=\"ss-w-today-live\">\n {liveRows.map(({ match }) => (\n <FixtureRow key={match.matchId} match={match} state={states[match.matchId]}\n stale={stale} ui={ui} monitor={monitor} />\n ))}\n </div>\n </>\n )}\n\n {visibleGroups.map((group) => (\n <CompetitionGroup\n key={group.competitionId}\n group={group}\n open={expanded[group.competitionId] ?? group.expandedByDefault}\n onToggle={() => toggleGroup(group.competitionId)}\n disambiguate={(nameCounts[group.competitionName] ?? 0) > 1}\n states={states}\n stale={stale}\n ui={ui}\n monitor={monitor}\n />\n ))}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { GameSummary } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { GamesLoginWall } from './GamesLoginWall'\nimport { GamesHub } from './GamesHub'\nimport { GameScreenHost } from './GameScreenHost'\n\nexport function GamesPanel({\n loggedIn,\n games,\n ui,\n conversation,\n}: {\n loggedIn: boolean\n games: GameSummary[]\n ui: UiConfig\n conversation?: GamePlayConversation | null\n}): JSX.Element {\n const [selected, setSelected] = useState<{ gameId: string; fixtureId: number; gameDay: string } | null>(null)\n\n if (!loggedIn) return <GamesLoginWall ui={ui} />\n\n if (selected !== null) {\n return (\n <div className=\"ss-w-gscreen-wrap\">\n <GameScreenHost\n selected={selected}\n onBack={() => setSelected(null)}\n conversation={conversation ?? null}\n ui={ui}\n />\n </div>\n )\n }\n\n return (\n <div className=\"ss-w-mon-list\" data-testid=\"games-hub\">\n <GamesHub\n games={games}\n onOpen={(g: GameSummary) => setSelected({ gameId: g.gameId, fixtureId: g.fixtureId, gameDay: g.gameDay })}\n ui={ui}\n />\n </div>\n )\n}\n","import type { UiConfig } from '../config'\n\nexport function GamesLoginWall({ ui }: { ui: UiConfig }): JSX.Element {\n return (\n <div className=\"ss-w-mon-list\">\n <div className=\"ss-w-games-wall\">\n <p>{ui.gamesLoginRequired}</p>\n </div>\n </div>\n )\n}\n","import type { GameSummary } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\n\nconst GAME_ICONS: Record<string, string> = {\n 'mystery-tiger': '🐯',\n 'daily-quiz': '🧠',\n 'career-path': '🧭',\n 'beat-the-grid': '🔲',\n 'guess-the-xi': '📋',\n 'higher-or-lower': '📈',\n 'matchday-predictor': '🎯',\n 'starting-xi': '👕',\n 'stat-ladder': '🪜',\n 'fan-motm': '⭐',\n}\n\n// Canonical display names keyed by gameId — the backend does not always send a title,\n// and a raw gameId (\"beat-the-grid\") must never surface to a fan.\nconst GAME_TITLES: Record<string, string> = {\n 'mystery-tiger': 'Mystery Tiger',\n 'daily-quiz': 'Daily Quiz',\n 'career-path': 'Career Path',\n 'beat-the-grid': 'Beat the Grid',\n 'guess-the-xi': 'Guess the XI',\n 'higher-or-lower': 'Higher or Lower',\n 'matchday-predictor': 'Matchday Predictor',\n 'starting-xi': 'Starting XI',\n 'stat-ladder': 'Stat Ladder',\n 'fan-motm': 'Fan MOTM',\n}\n\nfunction gameIcon(game: GameSummary): string {\n return GAME_ICONS[game.gameId] ?? (game.kind === 'fixture' ? '📅' : '🎮')\n}\n\n/** Title-cases an unknown gameId as a last resort: \"beat-the-grid\" -> \"Beat The Grid\". */\nfunction prettifyGameId(gameId: string): string {\n return gameId\n .split('-')\n .map(w => (w ? w[0]!.toUpperCase() + w.slice(1) : w))\n .join(' ')\n}\n\nfunction gameTitle(game: GameSummary): string {\n return game.title ?? GAME_TITLES[game.gameId] ?? prettifyGameId(game.gameId)\n}\n\nfunction formatCountdown(lockAtUtc: string): string | null {\n const diff = new Date(lockAtUtc).getTime() - Date.now()\n if (diff <= 0) return null\n const totalMins = Math.floor(diff / 60_000)\n const hours = Math.floor(totalMins / 60)\n const mins = totalMins % 60\n if (hours > 0) return `${hours}h ${mins}m`\n return `${mins}m`\n}\n\n/** Pure helper: maps a game's current status to a localised display label. */\nexport function tileStatusLabel(game: GameSummary, ui: UiConfig): string {\n switch (game.status) {\n case 'available':\n return ui.gamePlay\n case 'in_progress':\n return ui.gameResume\n case 'played':\n case 'graded': {\n const pts = game.score ?? 0\n return `+${pts.toLocaleString('en')}`\n }\n case 'locked':\n return ui.gameLocked\n case 'voided':\n return ui.gameVoided\n default:\n return ''\n }\n}\n\nconst DISABLED_STATUSES = new Set<GameSummary['status']>(['locked', 'voided'])\n\nexport function GameTile({\n game,\n onOpen,\n ui,\n}: {\n game: GameSummary\n onOpen: (g: GameSummary) => void\n ui: UiConfig\n}): JSX.Element {\n const disabled = DISABLED_STATUSES.has(game.status)\n const statusLabel = tileStatusLabel(game, ui)\n\n const countdown =\n game.kind === 'fixture' && game.lockAtUtc ? formatCountdown(game.lockAtUtc) : null\n\n const statusClass = `ss-w-tile-status ss-w-tile-status--${game.status}`\n\n const inner = (\n <>\n <span className=\"ss-w-tile-icon\">{gameIcon(game)}</span>\n <span className=\"ss-w-tile-title\">{gameTitle(game)}</span>\n {countdown !== null ? (\n <span className={statusClass} data-testid=\"tile-countdown\">{countdown}</span>\n ) : (\n <span className={statusClass}>{statusLabel}</span>\n )}\n <span className={`ss-w-tile-chip ss-w-tile-chip--${game.ranked ? 'skill' : 'fun'}`}>\n {game.ranked ? 'Skill' : 'For fun'}\n </span>\n </>\n )\n\n if (disabled) {\n return (\n <div className=\"ss-w-tile\" data-disabled>\n {inner}\n </div>\n )\n }\n\n return (\n <button\n type=\"button\"\n className=\"ss-w-tile\"\n onClick={() => onOpen(game)}\n >\n {inner}\n </button>\n )\n}\n","import type { GameSummary } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { GameTile } from './GameTile'\n\nexport function GamesHub({\n games,\n weeklyPrize,\n streak,\n weeklyRank,\n onOpen,\n ui,\n}: {\n games: GameSummary[]\n weeklyPrize?: string\n streak?: number\n weeklyRank?: number\n onOpen: (g: GameSummary) => void\n ui: UiConfig\n}): JSX.Element {\n const showPrize = weeklyPrize || streak !== undefined || weeklyRank !== undefined\n\n return (\n <div className=\"ss-w-games-hub\">\n {showPrize && (\n <div className=\"ss-w-prize\">\n <span className=\"ss-w-prize-icon\">🏆</span>\n <div className=\"ss-w-prize-body\">\n {weeklyPrize && <span className=\"ss-w-prize-text\">{weeklyPrize}</span>}\n {(streak !== undefined || weeklyRank !== undefined) && (\n <div className=\"ss-w-g-chips\">\n {streak !== undefined && (\n <span className=\"ss-w-g-chip ss-w-g-chip--streak\">🔥 {streak}</span>\n )}\n {weeklyRank !== undefined && (\n <span className=\"ss-w-g-chip ss-w-g-chip--rank\">#{weeklyRank}</span>\n )}\n </div>\n )}\n </div>\n </div>\n )}\n\n <div className=\"ss-w-gmatrix\">\n {games.map((g) => (\n <GameTile key={`${g.gameId}-${g.gameDay}`} game={g} onOpen={onOpen} ui={ui} />\n ))}\n </div>\n </div>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { UiConfig } from '../config'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { useGamePlay } from '../useGamePlay'\nimport { MysteryTigerGame } from './games/MysteryTigerGame'\nimport { HigherOrLowerGame } from './games/HigherOrLowerGame'\nimport { CareerPathGame } from './games/CareerPathGame'\nimport { BeatTheGridGame } from './games/BeatTheGridGame'\nimport { GuessTheXiGame } from './games/GuessTheXiGame'\nimport { DailyQuizGame } from './games/DailyQuizGame'\nimport { MatchdayPredictorGame } from './games/MatchdayPredictorGame'\nimport { StartingXiGame } from './games/StartingXiGame'\nimport { StatLadderGame } from './games/StatLadderGame'\nimport { FanMotmGame } from './games/FanMotmGame'\nimport type {\n MysteryTigerConfig,\n HolConfig,\n CareerPathConfig,\n BeatTheGridConfig,\n GuessTheXiConfig,\n DailyQuizConfig,\n MatchdayPredictorConfig,\n StartingXiConfig,\n StatLadderConfig,\n FanMotmConfig,\n} from './games/types'\n\n// Fixture games need a pending-result poll: they submit once before kickoff,\n// then remain in \"pending\" until resolved at full time.\nconst FIXTURE_GAME_IDS = new Set([\n 'matchday-predictor',\n 'starting-xi',\n 'stat-ladder',\n 'fan-motm',\n])\n\n// Poll cadence while a fixture game result is pending (30 seconds).\nconst PENDING_POLL_INTERVAL_MS = 30_000\n\nfunction safeParseConfig<T>(json: string | null | undefined): T | null {\n if (!json) return null\n try {\n return JSON.parse(json) as T\n } catch {\n return null\n }\n}\n\nexport function GameScreenHost({\n selected,\n onBack,\n conversation,\n ui,\n}: {\n selected: { gameId: string; fixtureId: number; gameDay?: string }\n onBack: () => void\n conversation: GamePlayConversation | null | undefined\n ui: UiConfig\n}): JSX.Element {\n const { gameId, fixtureId, gameDay = '' } = selected\n\n // Fetch config on open\n const [configJson, setConfigJson] = useState<string | null>(null)\n\n useEffect(() => {\n setConfigJson(null)\n if (!conversation) return\n let cancelled = false\n void (async () => {\n try {\n const payload = await conversation.getGameConfig(gameId, fixtureId, gameDay || undefined)\n if (!cancelled && payload?.configJson) {\n setConfigJson(payload.configJson)\n }\n } catch {\n // best-effort\n }\n })()\n return () => { cancelled = true }\n }, [conversation, gameId, fixtureId, gameDay])\n\n // Shared submit lifecycle\n const { result, submitting, submit, hydrate, rawStatus } = useGamePlay(conversation, {\n gameId,\n gameDay: gameDay,\n fixtureId: fixtureId || undefined,\n })\n\n // Hydrate on open for a returning fan\n useEffect(() => {\n if (conversation) hydrate()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [conversation, gameId])\n\n // Pending-result poll: while a fixture game result is pending (submitted but not yet\n // resolved at full time), poll getGameResult at a low cadence until graded or voided.\n const hydrateRef = useRef(hydrate)\n hydrateRef.current = hydrate\n\n useEffect(() => {\n if (!FIXTURE_GAME_IDS.has(gameId)) return\n if (rawStatus !== 'pending') return\n\n const timerId = setInterval(() => {\n hydrateRef.current()\n }, PENDING_POLL_INTERVAL_MS)\n\n return () => clearInterval(timerId)\n }, [gameId, rawStatus])\n\n const sharedProps = {\n result,\n submitting,\n onSubmit: submit,\n ui,\n }\n\n function renderScreen(): JSX.Element {\n switch (gameId) {\n case 'mystery-tiger':\n return (\n <MysteryTigerGame\n {...sharedProps}\n config={safeParseConfig<MysteryTigerConfig>(configJson)}\n />\n )\n case 'higher-or-lower':\n return (\n <HigherOrLowerGame\n {...sharedProps}\n config={safeParseConfig<HolConfig>(configJson)}\n />\n )\n case 'career-path':\n return (\n <CareerPathGame\n {...sharedProps}\n config={safeParseConfig<CareerPathConfig>(configJson)}\n />\n )\n case 'beat-the-grid': {\n const btgConfig = safeParseConfig<BeatTheGridConfig>(configJson)\n return (\n <BeatTheGridGame\n {...sharedProps}\n config={btgConfig}\n playerPool={btgConfig?.playerPool ?? []}\n />\n )\n }\n case 'guess-the-xi':\n return (\n <GuessTheXiGame\n {...sharedProps}\n config={safeParseConfig<GuessTheXiConfig>(configJson)}\n />\n )\n case 'daily-quiz':\n return (\n <DailyQuizGame\n {...sharedProps}\n config={safeParseConfig<DailyQuizConfig>(configJson)}\n />\n )\n case 'matchday-predictor':\n return (\n <MatchdayPredictorGame\n {...sharedProps}\n config={safeParseConfig<MatchdayPredictorConfig>(configJson)}\n />\n )\n case 'starting-xi':\n return (\n <StartingXiGame\n {...sharedProps}\n config={safeParseConfig<StartingXiConfig>(configJson)}\n />\n )\n case 'stat-ladder':\n return (\n <StatLadderGame\n {...sharedProps}\n config={safeParseConfig<StatLadderConfig>(configJson)}\n />\n )\n case 'fan-motm':\n return (\n <FanMotmGame\n {...sharedProps}\n config={safeParseConfig<FanMotmConfig>(configJson)}\n />\n )\n default:\n return (\n <div className=\"ss-w-gscreen-body\" data-testid={`game-screen-${gameId}`}>\n {gameId}\n </div>\n )\n }\n }\n\n return (\n <div className=\"ss-w-gscreen\">\n <button type=\"button\" className=\"ss-w-gscreen-back\" onClick={onBack}>\n <span className=\"ss-w-gscreen-back-arrow\" aria-hidden=\"true\">‹</span>\n {ui.back}\n </button>\n {renderScreen()}\n </div>\n )\n}\n","import { useCallback, useRef, useState } from 'react'\nimport type { GameResultPayload, GameStatePayload, SubmitPlayResult } from '@sensiblestats/widget-sdk'\n\nexport interface UseGamePlayOptions {\n gameId: string\n gameDay: string\n fixtureId?: number\n /** Called after a ranked play completes (pointsDelta present). */\n refresh?: () => void\n}\n\nexport interface UseGamePlayResult {\n result: SubmitPlayResult | null\n submitting: boolean\n submit: (answerJson: string) => Promise<void>\n hydrate: () => void\n /** Raw status string from the last getGameResult call (null until hydrated). */\n rawStatus: string | null\n}\n\nexport type GamePlayConversation = {\n postPlay: (gameId: string, answerJson: string, gameDay: string, fixtureId?: number) => Promise<SubmitPlayResult | null>\n getGameResult: (gameId: string, fixtureId?: number, gameDay?: string) => Promise<GameResultPayload | null>\n getGameConfig: (gameId: string, fixtureId?: number, gameDay?: string) => Promise<GameStatePayload | null>\n}\n\nfunction toSubmitResult(payload: GameResultPayload): SubmitPlayResult {\n return {\n // 'pending' means the play is recorded but awaiting resolution (fixture games)\n alreadyPlayed: payload.status === 'played' || payload.status === 'graded' || payload.status === 'pending',\n score: payload.score,\n isCorrect: payload.isCorrect,\n clientStateJson: payload.clientStateJson,\n attemptsUsed: payload.attemptsUsed,\n }\n}\n\nexport function useGamePlay(\n conversation: GamePlayConversation | null | undefined,\n { gameId, gameDay, fixtureId, refresh }: UseGamePlayOptions,\n): UseGamePlayResult {\n const [result, setResult] = useState<SubmitPlayResult | null>(null)\n const [submitting, setSubmitting] = useState(false)\n const [rawStatus, setRawStatus] = useState<string | null>(null)\n\n const inFlightRef = useRef(false)\n const convRef = useRef(conversation)\n convRef.current = conversation\n const optsRef = useRef({ gameId, gameDay, fixtureId, refresh })\n optsRef.current = { gameId, gameDay, fixtureId, refresh }\n // Mirror the latest result so submit() (a stable [] callback) can tell whether we\n // already hold in-progress state without wiping it.\n const resultRef = useRef<SubmitPlayResult | null>(null)\n resultRef.current = result\n\n const refetch = useCallback(async (): Promise<void> => {\n const conv = convRef.current\n if (!conv) return\n const opts = optsRef.current\n try {\n const payload = await conv.getGameResult(opts.gameId, opts.fixtureId, opts.gameDay)\n if (payload === null) return\n // Never let a null-clientState payload blank a board we already hold (e.g. a rescore that\n // couldn't reconstruct state). A first hydrate holds nothing, so a legitimately terminal\n // null-state play (voided / already-played) still renders; the status always updates.\n if (payload.clientStateJson == null && resultRef.current?.clientStateJson != null) {\n setRawStatus(payload.status)\n return\n }\n setResult(toSubmitResult(payload))\n setRawStatus(payload.status)\n } catch {\n // best-effort\n }\n }, [])\n\n const submit = useCallback(async (answerJson: string): Promise<void> => {\n const conv = convRef.current\n if (!conv || inFlightRef.current) return\n inFlightRef.current = true\n setSubmitting(true)\n try {\n const opts = optsRef.current\n const playResult = await conv.postPlay(opts.gameId, answerJson, opts.gameDay, opts.fixtureId)\n if (playResult !== null) {\n // Guard against a state-losing response: a still-in-progress submit that carries no\n // ClientStateJson (e.g. a server-side concurrency retry) must NOT overwrite the board\n // we already hold. Reconcile from the server instead of rendering an empty state.\n const hasFreshState = playResult.clientStateJson != null\n const isTerminal = playResult.alreadyPlayed === true\n const holdsState = resultRef.current?.clientStateJson != null\n if (!hasFreshState && !isTerminal && holdsState) {\n await refetch()\n } else {\n setResult(playResult)\n }\n if (playResult.pointsDelta != null) {\n opts.refresh?.()\n }\n }\n } catch {\n // best-effort; leave result unchanged\n } finally {\n inFlightRef.current = false\n setSubmitting(false)\n }\n }, [refetch])\n\n const hydrate = useCallback((): void => {\n void refetch()\n }, [refetch])\n\n return { result, submitting, submit, hydrate, rawStatus }\n}\n","import { useState, useId } from 'react'\nimport type { GameScreenProps, MysteryTigerConfig, MysteryTigerClientState, MysteryTigerGuessResult, MysteryTigerAttributeVerdict } from './types'\nimport { nationalityFlag } from './nationFlags'\nimport { initialsOf } from './PlayerAvatar'\n\nfunction parseClientState(json: string | null | undefined): MysteryTigerClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as MysteryTigerClientState\n } catch {\n return null\n }\n}\n\nconst ATTR_LABELS: Record<string, string> = {\n position: 'Pos',\n nationality: 'Nat',\n age: 'Age',\n shirtNumber: 'Shirt',\n apps: 'Apps',\n}\n\nconst ATTR_KEYS: (keyof Omit<MysteryTigerGuessResult, 'playerId'>)[] = [\n 'position', 'nationality', 'age', 'shirtNumber', 'apps',\n]\n\n// The masked \"profile\" shown in the hero card — the dimensions the fan is hunting on, values\n// hidden (•••) so the answer isn't spoiled. Jersey is only listed when the shirt tile is enabled.\nconst PROFILE_ROWS: { key: string; label: string }[] = [\n { key: 'position', label: 'Position' },\n { key: 'nationality', label: 'Nationality' },\n { key: 'age', label: 'Age' },\n { key: 'shirtNumber', label: 'Jersey number' },\n { key: 'apps', label: 'Match count' },\n]\n\nconst MAX_GUESSES = 6\n\nfunction verdictGlyph(v: MysteryTigerAttributeVerdict): string {\n if (v.verdict === 'exact') return '✓'\n if (v.verdict === 'miss') return '✗'\n if (v.direction === 'up') return '↑'\n if (v.direction === 'down') return '↓'\n return '≈'\n}\n\n// Direction arrow shown next to a numeric value (\"22 ▲\" = mystery player is older/higher/more).\nfunction directionArrow(v: MysteryTigerAttributeVerdict): string {\n if (v.direction === 'up') return '▲'\n if (v.direction === 'down') return '▼'\n return ''\n}\n\n// The display face of a tile: the guessed player's own value (a flag for nationality), falling\n// back to the verdict glyph when the backend sent no value (older payloads / unknown data).\nfunction tileFace(key: string, v: MysteryTigerAttributeVerdict): string {\n if (!v.value) return verdictGlyph(v)\n return key === 'nationality' ? nationalityFlag(v.value) : v.value\n}\n\nexport function MysteryTigerGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<MysteryTigerConfig>): JSX.Element {\n const [query, setQuery] = useState('')\n // The revealed photo can 404; fall back to initials on the same portrait box.\n const [portraitFailed, setPortraitFailed] = useState(false)\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const guessResults = clientState?.guessResults ?? []\n const alreadyGuessedIds = new Set<number>(guessResults.map(g => g.playerId))\n const shirtEnabled = config?.shirtTileEnabled ?? clientState?.shirtTileEnabled ?? false\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.solved === true ||\n clientState?.failed === true\n\n const guessesUsed = clientState?.guessesUsed ?? guessResults.length\n const revealPhoto = isOver && Boolean(clientState?.revealedPlayerImagePath) && !portraitFailed\n const revealName = isOver ? clientState?.revealedPlayerName : undefined\n\n const filtered =\n config && !isOver\n ? config.squadPlayers.filter(\n p => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handleSelect(playerId: number) {\n if (!config || isOver || submitting) return\n const prevGuesses = guessResults.map(g => g.playerId)\n const newGuesses = [...prevGuesses, playerId]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n return (\n <div className=\"ss-w-gt\" data-testid=\"game-screen-mystery-tiger\">\n {!config && <div className=\"ss-w-gscreen-body\">Loading…</div>}\n\n {config && (\n <>\n <div className=\"ss-w-gt-head\">\n <div>\n <div className=\"ss-w-gt-title\">Mystery Tiger</div>\n <div className=\"ss-w-gt-sub\">Guess today's squad player</div>\n </div>\n {clientState && !isOver && (\n <span className=\"ss-w-gt-left\">{clientState.guessesRemaining} left</span>\n )}\n </div>\n\n <div className=\"ss-w-gscroll\">\n {/* Hero card — the mystery player as a portrait beside the profile you're hunting on.\n In progress: silhouette + masked (•••) rows. Solved/failed: the real photo (or\n initials) is revealed. */}\n <div className={`ss-w-gt-card${isOver ? ' ss-w-gt-card--reveal' : ''}`}>\n <div className=\"ss-w-gt-sil\">\n {revealPhoto ? (\n <img\n src={clientState!.revealedPlayerImagePath}\n alt=\"\"\n onError={() => setPortraitFailed(true)}\n />\n ) : isOver && revealName ? (\n <span className=\"ss-w-av-initials\">{initialsOf(revealName)}</span>\n ) : (\n <svg viewBox=\"0 0 96 118\" role=\"img\" aria-label=\"hidden player silhouette\">\n <circle cx=\"48\" cy=\"40\" r=\"21\" fill=\"var(--ss-w-faint)\" />\n <path d=\"M8 118c0-25 18-39 40-39s40 14 40 39z\" fill=\"var(--ss-w-faint)\" />\n </svg>\n )}\n </div>\n {!isOver && (\n <div className=\"ss-w-gt-attrs\">\n {PROFILE_ROWS.filter(r => r.key !== 'shirtNumber' || shirtEnabled).map(row => (\n <div key={row.key} className=\"ss-w-gt-attr\">\n <span className=\"ss-w-gt-attr-k\">{row.label}</span>\n <span className=\"ss-w-gt-attr-v\">•••</span>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Progress dots — one per guess allowance; used guesses filled. */}\n {!isOver && (\n <div className=\"ss-w-gt-dots\" aria-label={`${guessesUsed} of ${MAX_GUESSES} guesses used`}>\n {Array.from({ length: MAX_GUESSES }).map((_, i) => (\n <i key={i} className={i < guessesUsed ? 'ss-w-gt-dot ss-w-gt-dot--on' : 'ss-w-gt-dot'} />\n ))}\n </div>\n )}\n\n {/* One-line explainer + key so the tiles and arrows make sense. */}\n {!isOver && (\n <div className=\"ss-w-gt-lead\">\n {guessResults.length === 0\n ? 'Guess a squad player — each guess compares it to the mystery player on Pos, Nat, Age, Shirt & Apps: '\n : 'Tiles: '}\n <span className=\"ss-w-gt-key\"><b className=\"ss-w-gt-key-ok\">✓</b> match · <b>▲</b> higher · <b>▼</b> lower</span>\n </div>\n )}\n\n {/* Guess rows — one labelled block per guess */}\n {guessResults.length > 0 && (\n <div className=\"ss-w-gtrows\">\n {guessResults.map((gr, i) => {\n const player = config.squadPlayers.find(p => p.id === gr.playerId)\n return (\n <div key={gr.playerId} className=\"ss-w-gtguess\">\n <div className=\"ss-w-gtguess-nm\">{i + 1} · {player?.name ?? `#${gr.playerId}`}</div>\n <div className=\"ss-w-gtrow\">\n {ATTR_KEYS.map(key => {\n const v = gr[key]\n const arrow = directionArrow(v)\n return (\n <div\n key={key}\n className={`ss-w-gtile ss-w-gtile--${v.verdict}`}\n data-testid={`verdict-${key}-${i}`}\n data-verdict={v.verdict}\n aria-label={`${ATTR_LABELS[key]}: ${v.value ?? v.verdict}${v.direction ? ` ${v.direction}` : ''}`}\n >\n <span className=\"ss-w-gtile-lab\">{ATTR_LABELS[key]}</span>\n <span className=\"ss-w-gtile-v\" aria-hidden=\"true\">\n {tileFace(key, v)}\n {arrow && <span className=\"ss-w-gtile-dir\">{arrow}</span>}\n </span>\n </div>\n )\n })}\n </div>\n </div>\n )\n })}\n </div>\n )}\n\n {/* Hint (in progress only) */}\n {clientState?.hintLine && !isOver && (\n <div className=\"ss-w-gt-hint\">💡 {clientState.hintLine}</div>\n )}\n\n {/* Terminal outcome */}\n {isOver && clientState && (\n <div className={`ss-w-gt-banner ss-w-gt-banner--${clientState.solved ? 'solved' : 'failed'}`}>\n <div className=\"ss-w-gt-banner-label\">\n {clientState.solved ? '🐯 You found them!' : '😔 Out of guesses'}\n </div>\n {clientState.revealedPlayerName && (\n <div className=\"ss-w-gt-banner-name\">{clientState.revealedPlayerName}</div>\n )}\n <div className=\"ss-w-gt-banner-sub\">\n {clientState.guessesUsed} guess{clientState.guessesUsed === 1 ? '' : 'es'} · come back tomorrow\n </div>\n </div>\n )}\n </div>\n\n {/* Typeahead input — pinned at the bottom, always reachable. */}\n {!isOver && (\n <div className=\"ss-w-gpin ss-w-gtta\">\n <input\n id={inputId}\n type=\"text\"\n role=\"textbox\"\n className=\"ss-w-gtta-i\"\n placeholder=\"Search squad players…\"\n value={query}\n disabled={submitting || isOver}\n onChange={e => setQuery(e.target.value)}\n autoComplete=\"off\"\n aria-label=\"Search for a player\"\n aria-autocomplete=\"list\"\n />\n {query.length > 0 && filtered.length > 0 && (\n <div className=\"ss-w-gtta-drop\" role=\"listbox\">\n {filtered.map(p => (\n <div\n key={p.id}\n className=\"ss-w-gtta-opt\"\n role=\"option\"\n aria-selected={false}\n onClick={() => handleSelect(p.id)}\n onKeyDown={e => { if (e.key === 'Enter') handleSelect(p.id) }}\n tabIndex={0}\n >\n {p.name}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","// Maps a nationality country-name string (as the games backend emits it) to a flag emoji.\n// UK home nations use subdivision flag emoji; everything else uses regional-indicator pairs.\n// Unmapped nationalities fall back to a short uppercased code so a slot is never blank.\n\nconst FLAGS: Record<string, string> = {\n england: '🏴\\u{E0067}\\u{E0062}\\u{E0065}\\u{E006E}\\u{E0067}\\u{E007F}',\n scotland: '🏴\\u{E0067}\\u{E0062}\\u{E0073}\\u{E0063}\\u{E0074}\\u{E007F}',\n wales: '🏴\\u{E0067}\\u{E0062}\\u{E0077}\\u{E006C}\\u{E0073}\\u{E007F}',\n 'northern ireland': '🇬🇧',\n 'republic of ireland': '🇮🇪',\n ireland: '🇮🇪',\n 'united kingdom': '🇬🇧',\n france: '🇫🇷', spain: '🇪🇸', portugal: '🇵🇹', germany: '🇩🇪', italy: '🇮🇹',\n netherlands: '🇳🇱', belgium: '🇧🇪', switzerland: '🇨🇭', austria: '🇦🇹',\n denmark: '🇩🇰', sweden: '🇸🇪', norway: '🇳🇴', finland: '🇫🇮', iceland: '🇮🇸',\n poland: '🇵🇱', czechia: '🇨🇿', 'czech republic': '🇨🇿', croatia: '🇭🇷',\n serbia: '🇷🇸', 'bosnia and herzegovina': '🇧🇦', greece: '🇬🇷', romania: '🇷🇴',\n ukraine: '🇺🇦', russia: '🇷🇺', hungary: '🇭🇺', slovakia: '🇸🇰', slovenia: '🇸🇮',\n turkey: '🇹🇷', türkiye: '🇹🇷', albania: '🇦🇱', 'north macedonia': '🇲🇰',\n brazil: '🇧🇷', argentina: '🇦🇷', uruguay: '🇺🇾', colombia: '🇨🇴', chile: '🇨🇱',\n peru: '🇵🇪', ecuador: '🇪🇨', paraguay: '🇵🇾', mexico: '🇲🇽', 'united states': '🇺🇸',\n usa: '🇺🇸', canada: '🇨🇦', jamaica: '🇯🇲',\n nigeria: '🇳🇬', ghana: '🇬🇭', senegal: '🇸🇳', ivorycoast: '🇨🇮', \"cote d'ivoire\": '🇨🇮',\n 'ivory coast': '🇨🇮', cameroon: '🇨🇲', egypt: '🇪🇬', morocco: '🇲🇦', algeria: '🇩🇿',\n tunisia: '🇹🇳', mali: '🇲🇱', 'south africa': '🇿🇦', 'dr congo': '🇨🇩',\n japan: '🇯🇵', 'south korea': '🇰🇷', korea: '🇰🇷', australia: '🇦🇺',\n 'saudi arabia': '🇸🇦', iran: '🇮🇷', 'new zealand': '🇳🇿',\n}\n\nexport function nationalityFlag(nationality: string | null | undefined): string {\n if (!nationality) return '🏳️'\n const key = nationality.trim().toLowerCase()\n return FLAGS[key] ?? nationality.slice(0, 3).toUpperCase()\n}\n","import { useState } from 'react'\n\n// Two-letter initials from a display name: first + last token, or the first two letters\n// of a single-token name. Used as the photo fallback so an avatar circle is never a bare ball.\nexport function initialsOf(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n const first = parts[0]\n if (!first) return '?'\n const last = parts[parts.length - 1]\n if (parts.length === 1 || !last) return first.slice(0, 2).toUpperCase()\n return ((first[0] ?? '') + (last[0] ?? '')).toUpperCase()\n}\n\n// Circular player avatar. Shows the photo when an imagePath is present and loads; otherwise\n// (missing URL or a broken image) falls back to the player's initials on the same circle.\nexport function PlayerAvatar({\n name,\n imagePath,\n className,\n}: {\n name: string\n imagePath?: string\n className: string\n}): JSX.Element {\n const [failed, setFailed] = useState(false)\n const showImage = Boolean(imagePath) && !failed\n\n return (\n <div className={className} aria-hidden=\"true\">\n {showImage ? (\n <img src={imagePath} alt=\"\" loading=\"lazy\" onError={() => setFailed(true)} />\n ) : (\n <span className=\"ss-w-av-initials\">{initialsOf(name)}</span>\n )}\n </div>\n )\n}\n","import type { GameScreenProps, HolConfig, HolClientState } from './types'\nimport { PlayerAvatar } from './PlayerAvatar'\n\n// Points awarded per correct pick — mirrors HigherOrLowerContentGenerator.PointsPerCorrect.\nconst POINTS_PER_CORRECT = 10\n\nfunction parseClientState(json: string | null | undefined): HolClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as HolClientState\n } catch {\n return null\n }\n}\n\nexport function HigherOrLowerGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<HolConfig>): JSX.Element {\n const clientState = parseClientState(result?.clientStateJson)\n\n const answeredPairs = clientState?.answeredPairs ?? []\n const answeredCount = answeredPairs.length\n const runEndedWrong = answeredPairs.some(p => !p.wasCorrect)\n const allPairsAnswered = config != null && answeredCount >= config.pairs.length\n const isOver = result?.alreadyPlayed === true || runEndedWrong || allPairsAnswered\n\n const currentPair = config && !isOver ? config.pairs[answeredCount] ?? null : null\n\n const correctCount = answeredPairs.filter(p => p.wasCorrect).length\n const score = clientState?.score ?? correctCount\n const runLength = clientState?.runLength ?? 0\n\n function handlePick(pick: 'higher' | 'lower') {\n if (!config || isOver || submitting || !currentPair) return\n const prevAnswers = answeredPairs.map(p => ({ pairIndex: p.pairIndex, pick: p.pick }))\n const newAnswers = [...prevAnswers, { pairIndex: currentPair.pairIndex, pick }]\n onSubmit(JSON.stringify({ answers: newAnswers }))\n }\n\n return (\n <div className=\"ss-w-hl\" data-testid=\"game-screen-higher-or-lower\">\n {!config && <div className=\"ss-w-gscreen-body\">Loading…</div>}\n\n {config && (\n <>\n <div className=\"ss-w-hl-head\">\n <div>\n <div className=\"ss-w-hl-title\">Higher or Lower</div>\n <div className=\"ss-w-hl-sub\">{config.statLabel} · {config.seasonLabel}</div>\n </div>\n {runLength > 0 && !isOver && <span className=\"ss-w-hl-streak\">🔥 {runLength}</span>}\n </div>\n\n {currentPair && (\n <>\n <div className=\"ss-w-hl-q\">Who has more {config.statLabel.toLowerCase()}?</div>\n <div className=\"ss-w-hlpair\">\n {/* Player A — value always visible */}\n <div className=\"ss-w-hlpc\">\n <PlayerAvatar\n className=\"ss-w-hlpc-av\"\n name={currentPair.playerAName}\n imagePath={currentPair.playerAImagePath}\n />\n <div className=\"ss-w-hlpc-name\">{currentPair.playerAName}</div>\n <div className=\"ss-w-hlpc-stat\">{config.statLabel}</div>\n <div className=\"ss-w-hlpc-val\">{currentPair.playerAValue}</div>\n </div>\n\n {/* Higher / Lower — middle column */}\n <div className=\"ss-w-hlbtns\">\n <button\n type=\"button\"\n className=\"ss-w-hlbtn ss-w-hlbtn--up\"\n disabled={submitting}\n onClick={() => handlePick('higher')}\n >\n Higher ▲\n </button>\n <span className=\"ss-w-hl-or\">or</span>\n <button\n type=\"button\"\n className=\"ss-w-hlbtn ss-w-hlbtn--dn\"\n disabled={submitting}\n onClick={() => handlePick('lower')}\n >\n Lower ▼\n </button>\n </div>\n\n {/* Player B — value hidden until answered */}\n <div className=\"ss-w-hlpc ss-w-hlpc--b\">\n <PlayerAvatar\n className=\"ss-w-hlpc-av\"\n name={currentPair.playerBName}\n imagePath={currentPair.playerBImagePath}\n />\n <div className=\"ss-w-hlpc-name\">{currentPair.playerBName}</div>\n <div className=\"ss-w-hlpc-stat\">{config.statLabel}</div>\n <div className=\"ss-w-hlpc-val ss-w-hlpc-val--hidden\">?</div>\n </div>\n </div>\n </>\n )}\n\n {/* In-progress footer chips (artifact layout): the run's points on the left (the header\n already carries the live streak, so a correct-count here would just duplicate it) and\n the per-correct reward on the right. */}\n {!isOver && (\n <div className=\"ss-w-hl-foot\">\n <span className=\"ss-w-hl-chip\">{score} pts</span>\n <span className=\"ss-w-hl-chip ss-w-hl-chip--green\">+{POINTS_PER_CORRECT} / correct</span>\n </div>\n )}\n\n {isOver && (\n <div className=\"ss-w-hl-over\">\n <div className=\"ss-w-hl-over-title\">{runEndedWrong ? '🚫 Run over' : '🎉 Perfect run!'}</div>\n <div className=\"ss-w-hl-over-score\">{score}<span className=\"ss-w-hl-over-unit\"> pts</span></div>\n <div className=\"ss-w-hl-over-sub\">\n {correctCount} correct in a row{runEndedWrong ? ' before a wrong pick' : ''} · come back tomorrow for a new run\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import { useState, useId, Fragment } from 'react'\nimport type { GameScreenProps, CareerPathConfig, CareerPathClientState, CareerPathClubSpell } from './types'\n\nfunction parseClientState(json: string | null | undefined): CareerPathClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as CareerPathClientState\n } catch {\n return null\n }\n}\n\n// Compact 2-digit year, apostrophe-prefixed like the mockup: 2011 → '11, 2011–2012 → '11–12.\nfunction spellYears(spell: CareerPathClubSpell): string {\n if (!spell.startYear) return ''\n const yy = (y: number) => `'${String(y % 100).padStart(2, '0')}`\n if (spell.endYear && spell.endYear !== spell.startYear) {\n return `${yy(spell.startYear)}–${String(spell.endYear % 100).padStart(2, '0')}`\n }\n return yy(spell.startYear)\n}\n\nfunction ClubSpellCard({ spell }: { spell: CareerPathClubSpell }): JSX.Element {\n const years = spellYears(spell)\n return (\n <div className={`ss-w-cpath-club${spell.isLoan ? ' ss-w-cpath-club--loan' : ''}`}>\n {spell.crestUrl ? (\n <img src={spell.crestUrl} alt=\"\" className=\"ss-w-cpath-crest\" loading=\"lazy\" />\n ) : (\n <div className=\"ss-w-cpath-crest ss-w-cpath-crest--fallback\" aria-hidden=\"true\">\n {spell.clubName.slice(0, 3).toUpperCase()}\n </div>\n )}\n <span className=\"ss-w-cpath-club-name\">\n {spell.clubName}\n {spell.isLoan && <span className=\"ss-w-cpath-loan-note\"> (loan)</span>}\n </span>\n {years && <span className=\"ss-w-cpath-spell-yr\">{years}</span>}\n </div>\n )\n}\n\nexport function CareerPathGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<CareerPathConfig>): JSX.Element {\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyGuessedIds = new Set<number>(clientState?.guessResults.map(g => g.playerId) ?? [])\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.solved === true ||\n clientState?.failed === true\n\n const visiblePath = clientState?.visiblePath ?? config?.initialPath ?? []\n\n const filtered =\n config && !isOver\n ? config.typeaheadPool.filter(\n p => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handleSelect(playerId: number): void {\n if (!config || isOver || submitting) return\n const prevGuesses = clientState?.guessResults.map(g => g.playerId) ?? []\n const newGuesses = [...prevGuesses, playerId]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n return (\n <div className=\"ss-w-cpath\" data-testid=\"game-screen-career-path\">\n {!config && <div className=\"ss-w-gscreen-body\">Loading…</div>}\n\n {config && (\n <>\n <div className=\"ss-w-cpath-head\">\n <div>\n <div className=\"ss-w-cpath-title\">Career Path</div>\n <div className=\"ss-w-cpath-sub\">Guess the mystery player from the clubs they've played for, oldest first.</div>\n </div>\n {clientState && !isOver && (\n <span className=\"ss-w-cpath-left\">{clientState.guessesRemaining} left</span>\n )}\n </div>\n\n <div className=\"ss-w-gscroll\">\n {/* Career sequence — club crests oldest→newest, wrapping to fit (no truncation) */}\n <div className=\"ss-w-cpath-seq\">\n {visiblePath.map((spell, i) => (\n <Fragment key={`${spell.clubName}-${i}`}>\n {i > 0 && <span className=\"ss-w-cpath-arrow\" aria-hidden=\"true\">›</span>}\n <ClubSpellCard spell={spell} />\n </Fragment>\n ))}\n </div>\n\n {/* Hint (in progress) */}\n {clientState?.hintLine && !isOver && (\n <div className=\"ss-w-cpath-hint\">💡 {clientState.hintLine}</div>\n )}\n\n {/* Terminal outcome */}\n {isOver && clientState && (\n <div className={`ss-w-cpath-banner ss-w-cpath-banner--${clientState.solved ? 'solved' : 'failed'}`}>\n <div className=\"ss-w-cpath-banner-label\">\n {clientState.solved ? '✅ Career traced!' : '😔 Out of guesses'}\n </div>\n {clientState.revealedPlayerName && (\n <div className=\"ss-w-cpath-banner-name\">{clientState.revealedPlayerName}</div>\n )}\n <div className=\"ss-w-cpath-banner-sub\">\n {clientState.guessesUsed} guess{clientState.guessesUsed === 1 ? '' : 'es'} · come back tomorrow\n </div>\n </div>\n )}\n </div>\n\n {/* Typeahead — pinned at the bottom, always reachable. */}\n {!isOver && (\n <div className=\"ss-w-gpin ss-w-gtta\">\n <input\n id={inputId}\n type=\"text\"\n role=\"textbox\"\n className=\"ss-w-gtta-i\"\n placeholder=\"Name the player…\"\n value={query}\n disabled={submitting || isOver}\n onChange={e => setQuery(e.target.value)}\n autoComplete=\"off\"\n aria-label=\"Search for a player\"\n aria-autocomplete=\"list\"\n />\n {query.length > 0 && filtered.length > 0 && (\n <div className=\"ss-w-gtta-drop\" role=\"listbox\">\n {filtered.map(p => (\n <div\n key={p.id}\n className=\"ss-w-gtta-opt\"\n role=\"option\"\n aria-selected={false}\n onClick={() => handleSelect(p.id)}\n onKeyDown={e => { if (e.key === 'Enter') handleSelect(p.id) }}\n tabIndex={0}\n >\n {p.name}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import React, { useState, useId } from 'react'\nimport type { GameScreenProps, BeatTheGridConfig, BtgClientState, BtgCellResult } from './types'\n\nexport interface PlayerEntry {\n id: number\n name: string\n}\n\n// BeatTheGridGame extends GameScreenProps with a `playerPool` prop because the\n// ConfigJson does not include a player list — the pool comes from the host (e.g. squad).\nexport interface BeatTheGridGameProps extends GameScreenProps<BeatTheGridConfig> {\n playerPool: PlayerEntry[]\n}\n\ninterface ActiveCell {\n row: number\n col: number\n}\n\nfunction parseClientState(json: string | null | undefined): BtgClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as BtgClientState\n } catch {\n return null\n }\n}\n\nfunction findCellResult(cells: BtgCellResult[], row: number, col: number): BtgCellResult | undefined {\n return cells.find(c => c.row === row && c.col === col)\n}\n\n// Compact initials for a placed player, e.g. \"Andrew Robertson\" → \"A. Robertson\" trimmed to fit\n// the cell. Falls back to an empty string when the name is unknown.\nfunction shortName(name: string | undefined): string {\n if (!name) return ''\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return ''\n const first = parts[0]!\n if (parts.length === 1) return first\n const last = parts[parts.length - 1]!\n return `${first.charAt(0)}. ${last}`\n}\n\nfunction SearchSheet({\n row,\n col,\n rowLabel,\n colLabel,\n playerPool,\n alreadyFilledIds,\n onPick,\n onDismiss,\n}: {\n row: number\n col: number\n rowLabel: string\n colLabel: string\n playerPool: PlayerEntry[]\n alreadyFilledIds: Set<number>\n onPick: (row: number, col: number, playerId: number) => void\n onDismiss: () => void\n}): JSX.Element {\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const filtered = playerPool.filter(\n p => !alreadyFilledIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n\n return (\n <div className=\"ss-w-btg-sheet\" data-testid=\"btg-search-sheet\">\n <div className=\"ss-w-btg-sheet-hdr\">\n <div className=\"ss-w-btg-sheet-ctx\">\n <span className=\"ss-w-btg-sheet-row\">{rowLabel}</span>\n <span className=\"ss-w-btg-sheet-sep\">×</span>\n <span className=\"ss-w-btg-sheet-col\">{colLabel}</span>\n </div>\n <button\n type=\"button\"\n className=\"ss-w-btg-sheet-close\"\n data-testid=\"btg-sheet-dismiss\"\n aria-label=\"Dismiss\"\n onClick={onDismiss}\n >\n ✕\n </button>\n </div>\n {playerPool.length === 0 ? (\n <div className=\"ss-w-btg-sheet-empty\">No players available to search yet.</div>\n ) : (\n <div className=\"ss-w-gtta\">\n <input\n id={inputId}\n type=\"text\"\n role=\"textbox\"\n className=\"ss-w-gtta-i\"\n placeholder=\"Search players…\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n autoComplete=\"off\"\n aria-label={`Search player for ${rowLabel} × ${colLabel}`}\n aria-autocomplete=\"list\"\n autoFocus\n />\n {query.length > 0 && filtered.length > 0 && (\n <div className=\"ss-w-gtta-drop ss-w-btg-ta-list\" role=\"listbox\">\n {filtered.map(p => (\n <div\n key={p.id}\n className=\"ss-w-gtta-opt\"\n role=\"option\"\n aria-selected={false}\n onClick={() => onPick(row, col, p.id)}\n onKeyDown={e => { if (e.key === 'Enter') onPick(row, col, p.id) }}\n tabIndex={0}\n >\n {p.name}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nexport function BeatTheGridGame({\n config,\n result,\n submitting,\n onSubmit,\n playerPool,\n}: BeatTheGridGameProps): JSX.Element {\n const [activeCell, setActiveCell] = useState<ActiveCell | null>(null)\n\n const clientState = parseClientState(result?.clientStateJson)\n const filledCells = clientState?.cells ?? []\n\n const isLocked =\n result?.alreadyPlayed === true ||\n clientState?.isComplete === true\n\n const alreadyFilledIds = new Set<number>(filledCells.map(c => c.playerId))\n\n function handleCellClick(row: number, col: number): void {\n if (isLocked || submitting) return\n const alreadyFilled = findCellResult(filledCells, row, col)\n if (alreadyFilled) return\n setActiveCell({ row, col })\n }\n\n function handlePick(row: number, col: number, playerId: number): void {\n setActiveCell(null)\n const prevCells = filledCells.map(c => ({ row: c.row, col: c.col, playerId: c.playerId }))\n const newCells = [...prevCells, { row, col, playerId }]\n onSubmit(JSON.stringify({ cells: newCells }))\n }\n\n if (!config) {\n return (\n <div className=\"ss-w-btg\" data-testid=\"game-screen-beat-the-grid\">\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n </div>\n )\n }\n\n const rows = config.rows\n const cols = config.cols\n\n return (\n <div className=\"ss-w-btg\" data-testid=\"game-screen-beat-the-grid\">\n <div className=\"ss-w-btg-head\">\n <div>\n <div className=\"ss-w-btg-title\">Beat the Grid</div>\n <div className=\"ss-w-btg-sub\">Fill each cell with a player who fits</div>\n </div>\n <div className=\"ss-w-btg-ctx\">\n <span className=\"ss-w-btg-ctx-score\">{clientState?.totalScore ?? 0} pts</span>\n {!isLocked && (\n <span className=\"ss-w-btg-ctx-left\">\n {config.maxGuesses - filledCells.length} cell{config.maxGuesses - filledCells.length !== 1 ? 's' : ''} left\n </span>\n )}\n </div>\n </div>\n\n <div className=\"ss-w-gscroll\">\n {/* Grid: col headers + row headers + cells */}\n <div\n className=\"ss-w-btg-grid\"\n style={{ gridTemplateColumns: `auto repeat(${cols.length}, 1fr)` } as React.CSSProperties}\n role=\"grid\"\n >\n {/* Top-left empty corner */}\n <div className=\"ss-w-btg-gc ss-w-btg-gc--corner\" />\n {/* Column headers */}\n {cols.map(col => (\n <div key={col} className=\"ss-w-btg-gc ss-w-btg-gc--colhdr\">\n {col}\n </div>\n ))}\n {/* Rows */}\n {rows.map((rowLabel, rowIdx) => (\n <React.Fragment key={rowIdx}>\n {/* Row header */}\n <div className=\"ss-w-btg-gc ss-w-btg-gc--rowhdr\">\n {rowLabel}\n </div>\n {/* Cells */}\n {cols.map((colLabel, colIdx) => {\n const filled = findCellResult(filledCells, rowIdx, colIdx)\n const isActive = activeCell?.row === rowIdx && activeCell?.col === colIdx\n return (\n <button\n key={`cell-${rowIdx}-${colIdx}`}\n type=\"button\"\n data-testid={`btg-cell-${rowIdx}-${colIdx}`}\n aria-label={`${rowLabel} ${colLabel}`}\n className={[\n 'ss-w-btg-gc ss-w-btg-cell',\n filled ? (filled.isCorrect ? 'ss-w-btg-cell--correct' : 'ss-w-btg-cell--wrong') : '',\n isActive ? 'ss-w-btg-cell--active' : '',\n ].filter(Boolean).join(' ')}\n disabled={isLocked || submitting}\n onClick={() => handleCellClick(rowIdx, colIdx)}\n >\n {filled ? (\n <>\n <span className=\"ss-w-btg-cell-nm\">\n {shortName(playerPool.find(p => p.id === filled.playerId)?.name)}\n </span>\n <span className=\"ss-w-btg-cell-score\">\n {filled.rarityScore}\n {filled.isCorrect && <span className=\"ss-w-btg-cell-check\" aria-hidden=\"true\"> ✓</span>}\n </span>\n </>\n ) : (\n <span className=\"ss-w-btg-cell-empty\" aria-hidden=\"true\">+</span>\n )}\n </button>\n )\n })}\n </React.Fragment>\n ))}\n </div>\n\n {/* Terminal summary */}\n {isLocked && (\n <div className=\"ss-w-btg-done\">\n <div className=\"ss-w-btg-done-label\">🔲 Grid complete</div>\n <div className=\"ss-w-btg-done-score\">{clientState?.totalScore ?? 0}</div>\n <div className=\"ss-w-btg-done-sub\">\n {filledCells.filter(c => c.isCorrect).length}/{filledCells.length} correct · come back tomorrow\n </div>\n </div>\n )}\n </div>\n\n {/* Scoped search sheet — pinned at the bottom so it never sits below the fold. */}\n {activeCell !== null && (\n <div className=\"ss-w-gpin\">\n <SearchSheet\n row={activeCell.row}\n col={activeCell.col}\n rowLabel={rows[activeCell.row] ?? ''}\n colLabel={cols[activeCell.col] ?? ''}\n playerPool={playerPool}\n alreadyFilledIds={alreadyFilledIds}\n onPick={handlePick}\n onDismiss={() => setActiveCell(null)}\n />\n </div>\n )}\n </div>\n )\n}\n","import { useState, useId } from 'react'\nimport type { GameScreenProps, GuessTheXiConfig, XiClientState, XiSlotEntry } from './types'\nimport { nationalityFlag } from './nationFlags'\n\n// Total guesses allowed per day. Kept in sync with GuessTheXiScorer.MaxGuesses on the backend.\nconst MAX_GUESSES = 3\n\nfunction parseClientState(json: string | null | undefined): XiClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as XiClientState\n } catch {\n return null\n }\n}\n\n/**\n * Groups the flat position list into formation rows keyed by the \"row:col\" slot's row part, then\n * orders the rows so the GOALKEEPER LINE (row 1) sits at the BOTTOM — the football convention: a\n * team defends the bottom goal and attacks upward (GK → defence → midfield → attack).\n */\nfunction toRows(positions: XiSlotEntry[]): XiSlotEntry[][] {\n const byRow = new Map<number, XiSlotEntry[]>()\n positions.forEach((p, i) => {\n const rowKey = Number(p.slot?.split(':')[0]) || i + 1\n const bucket = byRow.get(rowKey) ?? []\n bucket.push(p)\n byRow.set(rowKey, bucket)\n })\n // Descending: highest row number (forwards) at the top, row 1 (GK) at the bottom.\n return [...byRow.keys()].sort((a, b) => b - a).map(k => byRow.get(k)!)\n}\n\n// Football formation notation from the grouped rows — the outfield lines from defence to attack,\n// goalkeeper excluded (e.g. GK/4/2/3/1 → \"4-2-3-1\"). `rows` arrive attack-first (descending), so\n// read them bottom-up and drop the goalkeeper line.\nfunction formationLabel(rows: XiSlotEntry[][]): string {\n if (rows.length < 2) return ''\n const gkFirst = [...rows].reverse()\n return gkFirst.slice(1).map(r => r.length).join('-')\n}\n\n// Canonical position labels per formation, goalkeeper first then each outfield line, left→right.\n// Lets us print a real position (GK, RB, CDM, ST…) under every flag so the fan can read the shape\n// and see at a glance which end is the goalkeeper — without the config having to carry positions.\nconst FORMATION_POSITIONS: Record<string, string[][]> = {\n '4-4-2': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'RM'], ['ST', 'ST']],\n '4-3-3': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CM', 'CM', 'CM'], ['LW', 'ST', 'RW']],\n '4-2-3-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM', 'CDM'], ['LW', 'CAM', 'RW'], ['ST']],\n '4-1-4-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM'], ['LM', 'CM', 'CM', 'RM'], ['ST']],\n '4-5-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'CM', 'RM'], ['ST']],\n '4-4-1-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'RM'], ['CAM'], ['ST']],\n '4-1-2-1-2': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM'], ['LM', 'RM'], ['CAM'], ['ST', 'ST']],\n '3-5-2': [['GK'], ['CB', 'CB', 'CB'], ['LWB', 'CM', 'CM', 'CM', 'RWB'], ['ST', 'ST']],\n '3-4-3': [['GK'], ['CB', 'CB', 'CB'], ['LM', 'CM', 'CM', 'RM'], ['LW', 'ST', 'RW']],\n '5-3-2': [['GK'], ['LWB', 'CB', 'CB', 'CB', 'RWB'], ['CM', 'CM', 'CM'], ['ST', 'ST']],\n '5-4-1': [['GK'], ['LWB', 'CB', 'CB', 'CB', 'RWB'], ['LM', 'CM', 'CM', 'RM'], ['ST']],\n}\n\n// Line-level fallback when the exact formation is not in the table above: the goalkeeper line, the\n// forward line, then defence/midfield by depth. Always correct at the line grain even when the\n// specific role is not — enough to read the shape and spot the keeper.\nfunction lineFallback(lineIdx: number, totalLines: number): string {\n if (lineIdx === 0) return 'GK'\n if (lineIdx === totalLines - 1) return 'FWD'\n if (lineIdx === 1) return 'DEF'\n return 'MID'\n}\n\n// Map each slot (\"row:col\") to a position label, reading the rows goalkeeper-first.\nfunction positionsBySlot(formation: string, rowsAttackFirst: XiSlotEntry[][]): Map<string, string> {\n const gkFirst = [...rowsAttackFirst].reverse()\n const template = FORMATION_POSITIONS[formation]\n const map = new Map<string, string>()\n gkFirst.forEach((line, li) => {\n line.forEach((entry, ci) => {\n if (!entry.slot) return\n const label = template?.[li]?.[ci] ?? lineFallback(li, gkFirst.length)\n map.set(entry.slot, label)\n })\n })\n return map\n}\n\n// Just the surname, to fit the label under a flag (\"Andrey Santos\" → \"Santos\").\nfunction surname(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n return parts.length ? parts[parts.length - 1]! : name\n}\n\nexport function GuessTheXiGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<GuessTheXiConfig>): JSX.Element {\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.status === 'solved' ||\n clientState?.status === 'failed'\n const solved = clientState?.status === 'solved'\n\n const guessedTeamIds = new Set<number>(clientState?.guessHistory.map(g => g.teamId) ?? [])\n const rows = config ? toRows(config.positions) : []\n // Only name the shape when the data is a real formation; a neutral fallback grid has no shape.\n const formation = config?.hasRealFormation ? formationLabel(rows) : ''\n // Position label under every flag (GK/CB/CM/ST…), so the formation reads and the keeper's end is\n // obvious. Derived from the formation coordinates, not from any answer-revealing field.\n const posBySlot = config?.hasRealFormation ? positionsBySlot(formation, rows) : new Map<string, string>()\n\n // A wrong guess can earn a player-name reveal; pin each to its slot so we can print the surname\n // under that flag. Position-type reveals are redundant now that every position is already shown.\n const nameBySlot = new Map<string, string>()\n ;(clientState?.earnedReveals ?? []).forEach(r => { if (r.slot && r.type !== 'position') nameBySlot.set(r.slot, r.value) })\n\n const filtered =\n config && !isOver\n ? config.teamPool.filter(\n t => !guessedTeamIds.has(t.teamId) && t.teamName.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handlePick(teamId: number): void {\n if (!config || isOver || submitting) return\n const prevGuesses = clientState?.guessHistory.map(g => ({ teamId: g.teamId })) ?? []\n const newGuesses = [...prevGuesses, { teamId }]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n const wrongGuesses = (clientState?.guessHistory ?? []).filter(g => !g.wasCorrect)\n const revealCount = nameBySlot.size\n\n return (\n <div className=\"ss-w-gxi\" data-testid=\"game-screen-guess-the-xi\">\n {!config && <div className=\"ss-w-gscreen-body\">Loading…</div>}\n\n {config && (\n <>\n <div className=\"ss-w-gxi-head\">\n <div>\n <div className=\"ss-w-gxi-title\">\n Guess the XI\n {formation && (\n <span className=\"ss-w-gxi-form\" aria-label={`Formation ${formation}`}>{formation}</span>\n )}\n </div>\n <div className=\"ss-w-gxi-sub\">Name the team · flags are each player's nationality · {config.poolLabel}</div>\n </div>\n {clientState && !isOver && (\n <span className=\"ss-w-gxi-left\">{Math.max(0, MAX_GUESSES - clientState.guessesUsed)} left</span>\n )}\n </div>\n\n <div className=\"ss-w-gscroll\">\n {/* Pitch — a flag per slot, in formation rows (GK at the bottom). A revealed slot shows\n the earned hint (position letter or player name) on the flag itself. */}\n {rows.length > 0 && (\n <div className=\"ss-w-gxi-pitch\">\n {rows.map((row, r) => (\n <div key={r} className=\"ss-w-gxi-prow\">\n {row.map((pos, c) => {\n const posLabel = pos.slot ? posBySlot.get(pos.slot) ?? '' : ''\n const name = pos.slot ? nameBySlot.get(pos.slot) : undefined\n return (\n <div key={`${pos.slot}-${c}`} className=\"ss-w-gxi-slot\">\n <div\n className={`ss-w-gxi-flag${name ? ' ss-w-gxi-flag--revealed' : ''}`}\n title={pos.nationality}\n aria-label={`${posLabel ? posLabel + ' — ' : ''}${pos.nationality}${name ? ' — ' + name : ''}`}\n >\n {nationalityFlag(pos.nationality)}\n </div>\n {posLabel && <span className=\"ss-w-gxi-pos\">{posLabel}</span>}\n {name && <span className=\"ss-w-gxi-flag-lab\">{surname(name)}</span>}\n </div>\n )\n })}\n </div>\n ))}\n </div>\n )}\n\n {revealCount > 0 && !isOver && (\n <div className=\"ss-w-gxi-revnote\">🔎 {revealCount} player{revealCount === 1 ? '' : 's'} revealed — highlighted on the pitch</div>\n )}\n\n {/* Wrong guesses so far */}\n {!isOver && wrongGuesses.length > 0 && (\n <div className=\"ss-w-gxi-wrong\">\n {wrongGuesses.map(g => {\n const team = config.teamPool.find(t => t.teamId === g.teamId)\n return <span key={g.teamId} className=\"ss-w-gxi-wrong-pill\">{team?.teamName ?? `#${g.teamId}`}</span>\n })}\n </div>\n )}\n\n {/* Terminal banner */}\n {isOver && clientState && (\n <div className={`ss-w-gxi-banner ss-w-gxi-banner--${solved ? 'solved' : 'failed'}`}>\n <div className=\"ss-w-gxi-banner-label\">{solved ? '✅ Solved!' : '😔 Out of guesses'}</div>\n <div className=\"ss-w-gxi-banner-score\">{clientState.score}</div>\n <div className=\"ss-w-gxi-banner-sub\">\n {clientState.guessesUsed} guess{clientState.guessesUsed === 1 ? '' : 'es'} · come back tomorrow\n </div>\n </div>\n )}\n </div>\n\n {/* Name-the-team typeahead — pinned at the bottom, always reachable. */}\n {!isOver && (\n <div className=\"ss-w-gpin ss-w-gtta\">\n <input\n id={inputId}\n type=\"text\"\n role=\"textbox\"\n className=\"ss-w-gtta-i\"\n placeholder=\"Name the team…\"\n value={query}\n disabled={submitting || isOver}\n onChange={e => setQuery(e.target.value)}\n autoComplete=\"off\"\n aria-label=\"Name the team\"\n aria-autocomplete=\"list\"\n />\n {query.length > 0 && filtered.length > 0 && (\n <div className=\"ss-w-gtta-drop\" role=\"listbox\">\n {filtered.map(t => (\n <div\n key={t.teamId}\n className=\"ss-w-gtta-opt\"\n role=\"option\"\n aria-selected={false}\n onClick={() => handlePick(t.teamId)}\n onKeyDown={e => { if (e.key === 'Enter') handlePick(t.teamId) }}\n tabIndex={0}\n >\n {t.teamName}\n </div>\n ))}\n </div>\n )}\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { GameScreenProps, DailyQuizConfig, DailyQuizClientState, DailyQuizResult } from './types'\n\nfunction parseClientState(json: string | null | undefined): DailyQuizClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as DailyQuizClientState\n } catch {\n return null\n }\n}\n\nfunction findResult(results: DailyQuizResult[], index: number): DailyQuizResult | undefined {\n return results.find(r => r.index === index)\n}\n\nexport function DailyQuizGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<DailyQuizConfig>): JSX.Element {\n // Local selection state: map from question index → selected option index\n const [selections, setSelections] = useState<Map<number, number>>(new Map())\n\n const clientState = parseClientState(result?.clientStateJson)\n const isRevealed = (clientState?.results.length ?? 0) > 0 || result?.alreadyPlayed === true\n\n const allAnswered = config != null && selections.size === config.questions.length\n\n function handleSelect(questionIndex: number, optionIndex: number): void {\n if (isRevealed || submitting) return\n setSelections(prev => new Map(prev).set(questionIndex, optionIndex))\n }\n\n function handleSubmit(): void {\n if (!config || !allAnswered || isRevealed || submitting) return\n const answers = config.questions.map(q => ({\n index: q.index,\n selectedOptionIndex: selections.get(q.index) ?? 0,\n }))\n onSubmit(JSON.stringify({ answers }))\n }\n\n return (\n <div className=\"ss-w-dq\" data-testid=\"game-screen-daily-quiz\">\n {!config && (\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n )}\n\n {config && (\n <>\n {/* Score banner (after reveal) */}\n {isRevealed && result?.score != null && (\n <div className=\"ss-w-dq-score\">\n <span className=\"ss-w-dq-score-val\">{result.score}</span>\n <span className=\"ss-w-dq-score-label\">pts</span>\n </div>\n )}\n\n {/* Progress bar */}\n {!isRevealed && (\n <div className=\"ss-w-dq-prog\">\n <div\n className=\"ss-w-dq-prog-fill\"\n style={{ width: `${Math.round((selections.size / config.questions.length) * 100)}%` } as React.CSSProperties}\n />\n </div>\n )}\n\n {/* Questions */}\n <div className=\"ss-w-dq-questions\">\n {config.questions.map(q => {\n const qResult = clientState ? findResult(clientState.results, q.index) : undefined\n const selectedIdx = selections.get(q.index)\n\n return (\n <div key={q.index} className=\"ss-w-dq-q\">\n <div className=\"ss-w-dq-qstem\">{q.stem}</div>\n\n <div className=\"ss-w-dq-opts\">\n {q.options.map((opt, optIdx) => {\n let optCls = 'ss-w-dq-qopt'\n if (qResult) {\n if (optIdx === qResult.correctOptionIndex) {\n optCls += ' ss-w-dq-qopt--correct'\n } else if (optIdx === selectedIdx && !qResult.isCorrect) {\n optCls += ' ss-w-dq-qopt--wrong'\n }\n } else if (optIdx === selectedIdx) {\n optCls += ' ss-w-dq-qopt--selected'\n }\n\n return (\n <button\n key={optIdx}\n type=\"button\"\n className={optCls}\n disabled={isRevealed || submitting}\n onClick={() => handleSelect(q.index, optIdx)}\n >\n <span className=\"ss-w-dq-qopt-letter\">\n {String.fromCharCode(65 + optIdx)}\n </span>\n <span className=\"ss-w-dq-qopt-text\">{opt}</span>\n </button>\n )\n })}\n </div>\n\n {/* Reveal text (post-submit) */}\n {qResult?.revealText && (\n <div className={`ss-w-dq-qwhy ss-w-dq-qwhy--${qResult.isCorrect ? 'correct' : 'wrong'}`}>\n {qResult.revealText}\n </div>\n )}\n </div>\n )\n })}\n </div>\n\n {/* Submit button (single submit; hidden after reveal) */}\n {!isRevealed && (\n <button\n type=\"button\"\n className=\"ss-w-dq-submit\"\n disabled={!allAnswered || submitting}\n onClick={handleSubmit}\n aria-label=\"Submit answers\"\n >\n {submitting ? 'Submitting…' : 'Submit'}\n </button>\n )}\n </>\n )}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type {\n GameScreenProps,\n MatchdayPredictorConfig,\n MatchdayPredictorClientState,\n} from './types'\n\nfunction parseClientState(json: string | null | undefined): MatchdayPredictorClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as MatchdayPredictorClientState\n } catch {\n return null\n }\n}\n\nfunction isLocked(kickoffUtc: string): boolean {\n try {\n return new Date(kickoffUtc).getTime() <= Date.now()\n } catch {\n return true\n }\n}\n\nexport function MatchdayPredictorGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<MatchdayPredictorConfig>): JSX.Element {\n const [homeScore, setHomeScore] = useState(0)\n const [awayScore, setAwayScore] = useState(0)\n const [firstScorerPlayerId, setFirstScorerPlayerId] = useState<number | null>(null)\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyPlayed = result?.alreadyPlayed === true\n\n // Show the played state (pending or graded) when the fan has already submitted\n if (alreadyPlayed && clientState) {\n if (!clientState.graded) {\n // Ungraded — awaiting result\n return (\n <div className=\"ss-w-mp\" data-testid=\"game-screen-matchday-predictor\">\n <div className=\"ss-w-mp-live\">\n <div className=\"ss-w-mp-live-score\">\n {clientState.predictedHomeScore} – {clientState.predictedAwayScore}\n </div>\n <div className=\"ss-w-mp-live-label\">Locked in — awaiting result</div>\n </div>\n <div className=\"ss-w-mp-fun\">For fun — not in the leaderboard</div>\n </div>\n )\n }\n\n // Graded — show outcome\n const r = clientState.result\n const actualScore = `${r.homeScore} – ${r.awayScore}`\n return (\n <div className=\"ss-w-mp\" data-testid=\"game-screen-matchday-predictor\">\n <div className=\"ss-w-mp-live\">\n <div className=\"ss-w-mp-live-score\">{actualScore}</div>\n <div className=\"ss-w-mp-live-label\">Full-time result</div>\n <div className=\"ss-w-mp-live-outcome\">\n <div className={`ss-w-mp-live-row${clientState.exactScoreCorrect ? ' ss-w-mp-live-row--correct' : ''}`}>\n <span className=\"ss-w-mp-live-row-key\">Exact score</span>\n <span className=\"ss-w-mp-live-row-val\">{clientState.exactScoreCorrect ? '✓' : '✗'}</span>\n </div>\n <div className={`ss-w-mp-live-row${clientState.outcomeCorrect ? ' ss-w-mp-live-row--correct' : ''}`}>\n <span className=\"ss-w-mp-live-row-key\">Result (W/D/L)</span>\n <span className=\"ss-w-mp-live-row-val\">{clientState.outcomeCorrect ? '✓' : '✗'}</span>\n </div>\n {!clientState.firstScorerVoid && (\n <div className={`ss-w-mp-live-row${clientState.firstScorerCorrect ? ' ss-w-mp-live-row--correct' : ''}`}>\n <span className=\"ss-w-mp-live-row-key\">First scorer</span>\n <span className=\"ss-w-mp-live-row-val\">\n {clientState.firstScorerCorrect ? '✓' : '✗'}\n {r.firstScorerName ? ` ${r.firstScorerName}` : ''}\n </span>\n </div>\n )}\n </div>\n </div>\n <div className=\"ss-w-mp-fun\">For fun — not in the leaderboard</div>\n </div>\n )\n }\n\n // Pre-submit (or config loading)\n if (!config) {\n return (\n <div className=\"ss-w-mp\" data-testid=\"game-screen-matchday-predictor\">\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n </div>\n )\n }\n\n const locked = isLocked(config.kickoffUtc)\n const disabled = locked || submitting\n\n function handleSubmit(): void {\n if (disabled || !config) return\n onSubmit(\n JSON.stringify({\n homeScore,\n awayScore,\n ...(firstScorerPlayerId !== null ? { firstScorerPlayerId } : {}),\n }),\n )\n }\n\n return (\n <div className=\"ss-w-mp\" data-testid=\"game-screen-matchday-predictor\">\n {/* Score prediction */}\n <div className=\"ss-w-mp-pred-score\">\n <div className=\"ss-w-mp-team\">\n <div className=\"ss-w-mp-team-name\">{config.homeTeam.name}</div>\n <div className=\"ss-w-mp-stepper\">\n <button\n type=\"button\"\n className=\"ss-w-mp-stepper-btn\"\n aria-label=\"-\"\n disabled={disabled || homeScore <= 0}\n onClick={() => setHomeScore(s => Math.max(0, s - 1))}\n >\n −\n </button>\n <span className=\"ss-w-mp-stepper-val\">{homeScore}</span>\n <button\n type=\"button\"\n className=\"ss-w-mp-stepper-btn\"\n aria-label=\"+\"\n disabled={disabled}\n onClick={() => setHomeScore(s => s + 1)}\n >\n +\n </button>\n </div>\n </div>\n\n <span className=\"ss-w-mp-sep\">–</span>\n\n <div className=\"ss-w-mp-team\">\n <div className=\"ss-w-mp-team-name\">{config.awayTeam.name}</div>\n <div className=\"ss-w-mp-stepper\">\n <button\n type=\"button\"\n className=\"ss-w-mp-stepper-btn\"\n aria-label=\"-\"\n disabled={disabled || awayScore <= 0}\n onClick={() => setAwayScore(s => Math.max(0, s - 1))}\n >\n −\n </button>\n <span className=\"ss-w-mp-stepper-val\">{awayScore}</span>\n <button\n type=\"button\"\n className=\"ss-w-mp-stepper-btn\"\n aria-label=\"+\"\n disabled={disabled}\n onClick={() => setAwayScore(s => s + 1)}\n >\n +\n </button>\n </div>\n </div>\n </div>\n\n {/* First-scorer picker */}\n {config.scorerPool.length > 0 && (\n <div className=\"ss-w-mp-scorer\">\n <div className=\"ss-w-mp-scorer-label\">First scorer (optional)</div>\n <div className=\"ss-w-mp-scorer-list\">\n {config.scorerPool.map(p => (\n <button\n key={p.playerId}\n type=\"button\"\n className={`ss-w-mp-scorer-opt${firstScorerPlayerId === p.playerId ? ' ss-w-mp-scorer-opt--selected' : ''}`}\n disabled={disabled}\n onClick={() =>\n setFirstScorerPlayerId(id => (id === p.playerId ? null : p.playerId))\n }\n >\n {p.playerName}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Lock notice */}\n {locked && (\n <div className=\"ss-w-mp-live-label\">Submissions are now closed</div>\n )}\n\n {/* Save */}\n <button\n type=\"button\"\n className=\"ss-w-mp-savebtn\"\n disabled={disabled}\n onClick={handleSubmit}\n aria-label=\"Save prediction\"\n >\n {submitting ? 'Saving…' : 'Save prediction'}\n </button>\n\n <div className=\"ss-w-mp-fun\">For fun — not in the leaderboard</div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type {\n GameScreenProps,\n StartingXiConfig,\n StartingXiClientState,\n} from './types'\n\nfunction parseClientState(json: string | null | undefined): StartingXiClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as StartingXiClientState\n } catch {\n return null\n }\n}\n\n// Parse formation string like \"4-3-3\" into row sizes [4, 3, 3] plus a GK row [1].\nfunction parseFormationRows(formation: string): number[] {\n const parts = formation.split('-').map(Number).filter(n => n > 0)\n if (parts.length === 0) return [1, 4, 3, 3]\n return [1, ...parts]\n}\n\nexport function StartingXiGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<StartingXiConfig>): JSX.Element {\n const [picked, setPicked] = useState<number[]>([])\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyPlayed = result?.alreadyPlayed === true\n\n // Show status states\n if (alreadyPlayed) {\n if (!clientState) {\n return (\n <div className=\"ss-w-sxi\" data-testid=\"game-screen-starting-xi\">\n <div className=\"ss-w-sxi-status\">\n <div className=\"ss-w-sxi-status-label\">This game has been voided</div>\n </div>\n </div>\n )\n }\n\n if (clientState.status === 'pending') {\n return (\n <div className=\"ss-w-sxi\" data-testid=\"game-screen-starting-xi\">\n <div className=\"ss-w-sxi-status\">\n <div className=\"ss-w-sxi-status-label\">\n Prediction locked in ({clientState.predictedCount} players) — awaiting result\n </div>\n </div>\n </div>\n )\n }\n\n if (clientState.status === 'graded') {\n return (\n <div className=\"ss-w-sxi\" data-testid=\"game-screen-starting-xi\">\n <div className=\"ss-w-sxi-status ss-w-sxi-status--graded\">\n <div className=\"ss-w-sxi-status-score\">{clientState.score}</div>\n <div className=\"ss-w-sxi-status-label\">\n {clientState.correctCount} correct starters\n </div>\n </div>\n </div>\n )\n }\n }\n\n if (!config) {\n return (\n <div className=\"ss-w-sxi\" data-testid=\"game-screen-starting-xi\">\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n </div>\n )\n }\n\n const formationRows = parseFormationRows(config.formation)\n const pickedSet = new Set(picked)\n const canSubmit = picked.length === 11 && !submitting\n\n function togglePlayer(playerId: number): void {\n if (submitting) return\n setPicked(prev => {\n if (prev.includes(playerId)) {\n return prev.filter(id => id !== playerId)\n }\n if (prev.length >= 11) return prev\n return [...prev, playerId]\n })\n }\n\n function handleSubmit(): void {\n if (!canSubmit) return\n onSubmit(JSON.stringify({ predictedPlayerIds: picked }))\n }\n\n // Render the pitch as rows derived from formation\n let slotIndex = 0\n const pitchRows = formationRows.map((count, rowIdx) => {\n const rowSlots = picked.slice(slotIndex, slotIndex + count)\n slotIndex += count\n return { rowIdx, count, rowSlots }\n })\n\n return (\n <div className=\"ss-w-sxi\" data-testid=\"game-screen-starting-xi\">\n <div className=\"ss-w-sxi-formation\">{config.formation}</div>\n\n {/* Pitch visualization */}\n <div className=\"ss-w-sxi-pitch\">\n {pitchRows.map(({ rowIdx, count, rowSlots }) => (\n <div key={rowIdx} className=\"ss-w-sxi-pitch-row\">\n {Array.from({ length: count }).map((_, i) => {\n const playerId = rowSlots[i]\n const player = playerId != null\n ? config.squadSheet.find(p => p.playerId === playerId)\n : undefined\n return (\n <div\n key={i}\n className={`ss-w-sxi-pslot${player ? ' ss-w-sxi-pslot--filled' : ''}`}\n onClick={() => { if (player) togglePlayer(player.playerId) }}\n onKeyDown={e => { if (e.key === 'Enter' && player) togglePlayer(player.playerId) }}\n tabIndex={player ? 0 : -1}\n role={player ? 'button' : undefined}\n aria-label={player ? `Remove ${player.playerName ?? ''}` : undefined}\n >\n <div className=\"ss-w-sxi-pslot-num\">\n {player?.jerseyNumber ?? (rowIdx === 0 ? 'GK' : '?')}\n </div>\n <div className=\"ss-w-sxi-pslot-name\">\n {player?.playerName ?? ''}\n </div>\n </div>\n )\n })}\n </div>\n ))}\n </div>\n\n {/* Squad picker */}\n <div className=\"ss-w-sxi-squad\">\n {config.squadSheet.map(p => {\n const isPicked = pickedSet.has(p.playerId)\n return (\n <div\n key={p.playerId}\n className={`ss-w-sxi-squad-row${isPicked ? ' ss-w-sxi-squad-row--picked' : ''}`}\n onClick={() => togglePlayer(p.playerId)}\n onKeyDown={e => { if (e.key === 'Enter') togglePlayer(p.playerId) }}\n tabIndex={0}\n role=\"button\"\n aria-pressed={isPicked}\n >\n <span className=\"ss-w-sxi-squad-name\">{p.playerName}</span>\n <span className=\"ss-w-sxi-squad-pos\">{p.positionName}</span>\n </div>\n )\n })}\n </div>\n\n <button\n type=\"button\"\n className=\"ss-w-sxi-savebtn\"\n disabled={!canSubmit}\n onClick={handleSubmit}\n aria-label=\"Predict XI\"\n >\n {submitting ? 'Submitting…' : `Predict XI (${picked.length}/11)`}\n </button>\n </div>\n )\n}\n","import type {\n GameScreenProps,\n StatLadderConfig,\n StatLadderClientState,\n} from './types'\n\nfunction parseClientState(json: string | null | undefined): StatLadderClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as StatLadderClientState\n } catch {\n return null\n }\n}\n\nexport function StatLadderGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<StatLadderConfig>): JSX.Element {\n const clientState = parseClientState(result?.clientStateJson)\n const revealed = clientState != null\n\n if (!config) {\n return (\n <div className=\"ss-w-sl\" data-testid=\"game-screen-stat-ladder\">\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n </div>\n )\n }\n\n // Determine the mystery rung's actual name once revealed\n const mysteryName = revealed\n ? clientState!.revealedRank2.playerName\n : null\n\n return (\n <div className=\"ss-w-sl\" data-testid=\"game-screen-stat-ladder\">\n <div className=\"ss-w-sl-title\">{config.statLabel}</div>\n\n {/* Ladder */}\n <div className=\"ss-w-sl-ladder\">\n {config.ladder.map(rung => {\n const isMystery = rung.rank === 2\n let rowCls = 'ss-w-sl-lrow'\n if (isMystery) rowCls += ' ss-w-sl-mystery'\n if (isMystery && revealed) {\n rowCls = rowCls.replace(' ss-w-sl-mystery', '')\n rowCls += clientState!.isCorrect ? ' ss-w-sl-lrow--correct' : ' ss-w-sl-lrow--wrong'\n }\n\n const displayName = isMystery\n ? (revealed ? mysteryName : '?')\n : (rung.playerName ?? '?')\n\n return (\n <div key={rung.rank} className={rowCls}>\n <div className=\"ss-w-sl-lrow-rank\">#{rung.rank}</div>\n <div className=\"ss-w-sl-lrow-name\">{displayName}</div>\n <div className=\"ss-w-sl-lrow-stat\">{rung.statValue}</div>\n </div>\n )\n })}\n </div>\n\n {/* Result banner after guessing */}\n {revealed && (\n <div className={`ss-w-sl-reveal ss-w-sl-reveal--${clientState!.isCorrect ? 'correct' : 'wrong'}`}>\n {clientState!.isCorrect ? 'Correct!' : `Wrong — it was ${clientState!.revealedRank2.playerName}`}\n </div>\n )}\n\n {/* Player picker (hidden after reveal) */}\n {!revealed && (\n <div className=\"ss-w-sl-picker\">\n {config.playerPool.map(p => (\n <button\n key={p.playerId}\n type=\"button\"\n className=\"ss-w-sl-picker-opt\"\n disabled={submitting}\n aria-label={p.playerName}\n onClick={() => onSubmit(JSON.stringify({ guessedPlayerId: p.playerId }))}\n >\n {p.playerName}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n","import type {\n GameScreenProps,\n FanMotmConfig,\n FanMotmClientState,\n} from './types'\n\nfunction parseClientState(json: string | null | undefined): FanMotmClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as FanMotmClientState\n } catch {\n return null\n }\n}\n\nexport function FanMotmGame({\n config,\n result,\n submitting,\n onSubmit,\n}: GameScreenProps<FanMotmConfig>): JSX.Element {\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyVoted = result?.alreadyPlayed === true\n\n if (!config) {\n return (\n <div className=\"ss-w-motm\" data-testid=\"game-screen-fan-motm\">\n <div className=\"ss-w-gscreen-body\">Loading…</div>\n </div>\n )\n }\n\n const pickedId = clientState?.pickedPlayerId ?? null\n\n function handleVote(candidateId: number): void {\n if (alreadyVoted || submitting) return\n onSubmit(JSON.stringify({ pickedPlayerId: candidateId }))\n }\n\n return (\n <div className=\"ss-w-motm\" data-testid=\"game-screen-fan-motm\">\n <div className=\"ss-w-motm-title\">Man of the Match — your vote</div>\n\n <div className=\"ss-w-motm-votes\">\n {config.candidates.map(c => {\n const isVoted = alreadyVoted && pickedId === c.playerId\n const rowCls = `ss-w-motm-vrow${isVoted ? ' ss-w-motm-vrow--voted' : ''}${alreadyVoted ? ' ss-w-motm-vrow--result' : ''}`\n return (\n <button\n key={c.playerId}\n type=\"button\"\n className={rowCls}\n data-testid={`motm-candidate-${c.playerId}`}\n disabled={alreadyVoted || submitting}\n onClick={() => handleVote(c.playerId)}\n >\n <div className=\"ss-w-motm-vfill\" style={{ width: isVoted ? '100%' : '0%' } as React.CSSProperties} />\n <span className=\"ss-w-motm-vrow-name\">{c.playerName}</span>\n </button>\n )\n })}\n </div>\n\n <div className=\"ss-w-motm-fun\">For fun — unranked community vote</div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { LeaderboardWeeklyRow, LeaderboardAllTimeRow, formatPoints } from './LeaderboardRow'\nimport { LeaderboardEmpty } from './LeaderboardEmpty'\n\ntype Segment = 'weekly' | 'alltime'\n\nexport function Leaderboard({\n data,\n ui,\n onPlay,\n}: {\n data: LeaderboardPayload\n ui: UiConfig\n /** Jumps to the Games tab from the empty-state CTA. */\n onPlay?: () => void\n}): JSX.Element {\n const [segment, setSegment] = useState<Segment>('weekly')\n\n const myRow = segment === 'weekly' ? data.myWeeklyRow : data.myAllTimeRow\n const offBoard = myRow !== null && myRow !== undefined && myRow.rank === -1\n const isEmpty = segment === 'weekly'\n ? data.weeklyTop.length === 0\n : data.allTimeTop.length === 0\n\n return (\n <div className=\"ss-w-lb2\">\n <div className=\"ss-w-seg\">\n <button\n type=\"button\"\n className=\"ss-w-seg-btn\"\n {...(segment === 'weekly' ? { 'data-on': '' } : {})}\n onClick={() => setSegment('weekly')}\n >\n {ui.leaderboardThisWeek}\n </button>\n <button\n type=\"button\"\n className=\"ss-w-seg-btn\"\n {...(segment === 'alltime' ? { 'data-on': '' } : {})}\n onClick={() => setSegment('alltime')}\n >\n {ui.leaderboardAllTime}\n </button>\n </div>\n\n {isEmpty ? (\n <LeaderboardEmpty\n segment={segment}\n lastWeek={data.lastWeek}\n weeklyPrize={data.weeklyPrize}\n onPlay={onPlay}\n ui={ui}\n />\n ) : (\n <>\n <div className=\"ss-w-lb2-rows\">\n {segment === 'weekly'\n ? data.weeklyTop.map((row) => (\n <LeaderboardWeeklyRow\n key={row.operatorUserId}\n row={row}\n isMe={row.operatorUserId === data.myWeeklyRow?.operatorUserId}\n />\n ))\n : data.allTimeTop.map((row) => (\n <LeaderboardAllTimeRow\n key={row.operatorUserId}\n row={row}\n isMe={row.operatorUserId === data.myAllTimeRow?.operatorUserId}\n />\n ))}\n </div>\n\n {/* Kit-prize separator */}\n <div className=\"ss-w-kitline\">🎽</div>\n\n {/* Pinned \"you\" row or off-board treatment */}\n {myRow != null && (\n offBoard ? (\n <div className=\"ss-w-lbgap\">{ui.leaderboardOffBoard}</div>\n ) : (\n <div className=\"ss-w-lb2-rows\">\n {segment === 'weekly' && data.myWeeklyRow && (\n <LeaderboardWeeklyRow row={data.myWeeklyRow} isMe />\n )}\n {segment === 'alltime' && data.myAllTimeRow && (\n <LeaderboardAllTimeRow row={data.myAllTimeRow} isMe />\n )}\n </div>\n )\n )}\n\n {/* All-time footer: show rank + total when available */}\n {segment === 'alltime' && data.myAllTimeRow && !offBoard && (\n <div className=\"ss-w-lb2-rows\">\n <div className=\"ss-w-lb2-row\">\n <span className=\"ss-w-lb2-handle\">\n {formatPoints(data.allTimeTop.reduce((s, r) => s + r.allTimePoints, 0))}\n </span>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import type { LeaderboardRow as SDKRow, AllTimeRow } from '@sensiblestats/widget-sdk'\n\n/** Formats a points integer with thousands separators. */\nexport function formatPoints(n: number): string {\n return n.toLocaleString('en')\n}\n\nexport function LeaderboardWeeklyRow({\n row,\n isMe,\n}: {\n row: SDKRow\n isMe: boolean\n}): JSX.Element {\n const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? ' ss-w-lb2-rank--top3' : ''}`\n return (\n <div className={`ss-w-lb2-row${isMe ? ' ss-w-lb2-row--you' : ''}`}>\n <span className={rankClass}>#{row.rank}</span>\n <span className=\"ss-w-lb2-handle\">{row.handle}</span>\n <span className=\"ss-w-lb2-points\">{formatPoints(row.points)}</span>\n {row.currentStreak > 0 && (\n <span className=\"ss-w-lb2-streak\">🔥 {row.currentStreak}</span>\n )}\n </div>\n )\n}\n\nexport function LeaderboardAllTimeRow({\n row,\n isMe,\n}: {\n row: AllTimeRow\n isMe: boolean\n}): JSX.Element {\n const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? ' ss-w-lb2-rank--top3' : ''}`\n return (\n <div className={`ss-w-lb2-row${isMe ? ' ss-w-lb2-row--you' : ''}`}>\n <span className={rankClass}>#{row.rank}</span>\n <span className=\"ss-w-lb2-handle\">{row.handle}</span>\n <span className=\"ss-w-lb2-points\">{formatPoints(row.allTimePoints)}</span>\n </div>\n )\n}\n","import type { LeaderboardChampion } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { formatPoints } from './LeaderboardRow'\n\ntype Segment = 'weekly' | 'alltime'\n\n/**\n * Default state for the leaderboard when the active segment has no ranked rows.\n * Weekly boards reset every week, so this is what most fans see at the start of a week.\n * - weekly + a prior champion -> \"fresh week\" copy plus a last-week continuity strip\n * - weekly + no history -> \"cold start\" copy (club's first-ever week)\n * - all-time -> a quiet single line; it fills as fans play\n */\nexport function LeaderboardEmpty({\n segment,\n lastWeek,\n weeklyPrize,\n onPlay,\n ui,\n}: {\n segment: Segment\n lastWeek?: LeaderboardChampion | null\n weeklyPrize?: string | null\n onPlay?: () => void\n ui: UiConfig\n}): JSX.Element {\n if (segment === 'alltime') {\n return (\n <div className=\"ss-w-lb-empty ss-w-lb-empty--alltime\">\n <div className=\"ss-w-lb-empty-icon\" aria-hidden=\"true\">📊</div>\n <p className=\"ss-w-lb-empty-body\">{ui.leaderboardAllTimeEmpty}</p>\n </div>\n )\n }\n\n const fresh = lastWeek != null\n const title = fresh ? ui.leaderboardEmptyFreshTitle : ui.leaderboardEmptyColdTitle\n const body = fresh ? ui.leaderboardEmptyFreshBody : ui.leaderboardEmptyColdBody\n\n return (\n <div className=\"ss-w-lb-empty\">\n {weeklyPrize && (\n <div className=\"ss-w-prize\">\n <span className=\"ss-w-prize-icon\" aria-hidden=\"true\">🏆</span>\n <div className=\"ss-w-prize-body\">\n <span className=\"ss-w-prize-text\">{weeklyPrize}</span>\n </div>\n </div>\n )}\n\n <div className=\"ss-w-lb-empty-hero\">\n <div className=\"ss-w-lb-empty-icon\" aria-hidden=\"true\">{fresh ? '🏆' : '🎮'}</div>\n <h4 className=\"ss-w-lb-empty-title\">{title}</h4>\n <p className=\"ss-w-lb-empty-body\">{body}</p>\n {onPlay && (\n <button type=\"button\" className=\"ss-w-lb-empty-cta\" onClick={onPlay}>\n {ui.leaderboardEmptyCta}\n </button>\n )}\n </div>\n\n {fresh && lastWeek && (\n <div className=\"ss-w-lb-last\">\n <span className=\"ss-w-lb-last-label\">{ui.leaderboardLastWeekLabel}</span>\n <span className=\"ss-w-lb-last-champ\" aria-hidden=\"true\">🥇</span>\n <span className=\"ss-w-lb-last-handle\">{lastWeek.handle}</span>\n <span className=\"ss-w-lb-last-points\">{formatPoints(lastWeek.points)}</span>\n </div>\n )}\n </div>\n )\n}\n","import type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { GamesLoginWall } from './GamesLoginWall'\nimport { Leaderboard } from './Leaderboard'\n\n/** Settled empty board (no rows yet) — a fetch that returned null once loading is done. */\nconst EMPTY_PAYLOAD: LeaderboardPayload = {\n week: '',\n weeklyTop: [],\n myWeeklyRow: null,\n allTimeTop: [],\n myAllTimeRow: null,\n weeklyPrize: null,\n lastWeek: null,\n}\n\nexport function LeaderboardPanel({ loggedIn, data, loading, onPlay, ui }: {\n loggedIn: boolean\n data: LeaderboardPayload | null\n loading?: boolean\n onPlay?: () => void\n ui: UiConfig\n}): JSX.Element {\n if (!loggedIn) return <GamesLoginWall ui={ui} />\n // Still fetching with nothing to show yet: keep the panel blank (skeleton-free).\n if (data === null && loading) return <div className=\"ss-w-mon-list\" />\n return (\n <div className=\"ss-w-mon-list\">\n <Leaderboard data={data ?? EMPTY_PAYLOAD} ui={ui} onPlay={onPlay} />\n </div>\n )\n}\n","// AUTO-GENERATED by scripts/gen-css.mjs from widget.css. Do not edit.\nexport const WIDGET_CSS = \".ss-w-root { all: revert; }\\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\\n.ss-w-root {\\n --ss-w-accent: #17936a;\\n --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n --ss-w-pos: #1aa563; --ss-w-neg: #e0524b;\\n --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;\\n --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;\\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, Helvetica, Arial, sans-serif;\\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\\n}\\n@media (prefers-color-scheme: dark) {\\n .ss-w-root[data-ss-w-theme=\\\"auto\\\"] {\\n --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n --ss-w-pos: #37c891; --ss-w-neg: #f0655d;\\n --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;\\n --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;\\n }\\n}\\n.ss-w-root[data-ss-w-theme=\\\"dark\\\"] {\\n --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n --ss-w-pos: #37c891; --ss-w-neg: #f0655d;\\n --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;\\n --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;\\n}\\n.ss-w-root[data-ss-w-theme=\\\"light\\\"] {\\n --ss-w-accent: #17936a; --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;\\n --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;\\n}\\n\\n/* launcher */\\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\\n.ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }\\n.ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\\n.ss-w-greeting-body { position: relative; flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }\\n.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }\\n.ss-w-greeting-text { display: block; }\\n/* Typing indicator: overlays the text area so bubble height stays put; hidden at\\n rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */\\n.ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }\\n.ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }\\n/* One-shot launcher attention intro: FAB nudges, then the greeting types in.\\n Gated behind no-preference so reduce-motion users get the greeting shown\\n statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once\\n per page load; every animation runs a single time and settles at rest. */\\n@media (prefers-reduced-motion: no-preference) {\\n .ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }\\n .ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }\\n .ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }\\n .ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }\\n .ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }\\n .ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }\\n .ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }\\n}\\n@keyframes ss-w-nudge {\\n 0%, 100% { transform: none; }\\n 22% { transform: translateY(-9px) rotate(-9deg); }\\n 44% { transform: translateY(0) rotate(7deg); }\\n 64% { transform: translateY(-4px) rotate(-4deg); }\\n 82% { transform: rotate(2deg); }\\n}\\n@keyframes ss-w-greet-in {\\n from { opacity: 0; transform: translateY(8px) scale(.92); }\\n to { opacity: 1; transform: none; }\\n}\\n@keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }\\n@keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }\\n@keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }\\n\\n/* panel */\\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(460px, calc(100vw - 40px)); height: min(640px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-panel { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-panel { left: var(--ss-w-offset-x); }\\n@media (max-width: 639px) {\\n /* Fill via inset with no explicit height (like the site's working panel) so the\\n input stays visible when the mobile keyboard/URL-bar shrinks the viewport. The\\n position-specific selectors override the right/left offsets set above. */\\n .ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-panel,\\n .ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-panel { inset: 0; width: auto; height: auto; border: none; border-radius: 0; }\\n}\\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-header-mark { width: 18px; height: 18px; display: block; object-fit: contain; }\\n.ss-w-header-title { font-weight: 660; flex: 1; }\\n.ss-w-close { background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\\n.ss-w-menu-wrap { position: relative; display: grid; place-items: center; }\\n.ss-w-kebab { background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\\n.ss-w-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 5; min-width: 184px; padding: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,.18); }\\n.ss-w-menu-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 10px; background: none; border: none; border-radius: 8px; color: var(--ss-w-ink); font: inherit; font-size: 13px; text-align: left; cursor: pointer; }\\n.ss-w-menu-item:hover, .ss-w-menu-item:focus-visible { background: var(--ss-w-bubble); }\\n.ss-w-menu-item svg { color: var(--ss-w-faint); font-size: 15px; flex: none; }\\n\\n/* messages */\\n/* .ss-w-mon-list (Matches/Odds tab scrollers) shares .ss-w-list's box/scroll rules by design --\\n same visual rhythm as the chat message list -- but gets its own class so it isn't the same DOM\\n landmark as the chat list when both exist in the panel at once (Task 16 fix round, M4). */\\n/* Children of this scrolling column flex container must NOT shrink. The default flex-shrink:1\\n compresses every child to fit the panel instead of letting the container scroll, and\\n .ss-w-grp's own overflow:hidden then clips the compressed content away entirely — 27\\n competition groups rendered as blank bars on a phone. Applies to the pinned cards too. */\\n.ss-w-mon-list > * { flex: none; }\\n.ss-w-list, .ss-w-mon-list { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 14px; display: flex; flex-direction: column; gap: 12px; scroll-padding-top: 14px; }\\n/* Transient bottom spacer: reserves a viewport of room below a new turn so its\\n top can be scrolled into view while the reply is still streaming in. Height is\\n set imperatively and flex must not shrink it away. */\\n.ss-w-turn-spacer { flex: none; }\\n.ss-w-msg { display: flex; }\\n.ss-w-user { justify-content: flex-end; }\\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\\n.ss-w-bot { flex-direction: column; gap: 8px; }\\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\\n\\n/* markdown */\\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\\n.ss-w-md > *:first-child { margin-top: 0; }\\n.ss-w-md > *:last-child { margin-bottom: 0; }\\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\\n.ss-w-table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }\\n.ss-w-md-table { border-collapse: collapse; width: max-content; min-width: 100%; font-variant-numeric: tabular-nums; }\\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; white-space: nowrap; }\\n.ss-w-md-table th { background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); font-weight: 700; }\\n.ss-w-md-table tbody tr:nth-child(even) { background: var(--ss-w-bubble); }\\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\\n\\n/* entity cards */\\n.ss-w-cards { display: flex; flex-direction: column; gap: 8px; }\\n\\n/* Entity card: identity header row over a horizontal stat strip */\\n.ss-w-ecard { display: flex; flex-direction: column; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; text-align: left; }\\n\\n.ss-w-ecard-idtext { display: flex; flex-direction: column; gap: 1px; min-width: 0; max-width: 100%; }\\n.ss-w-thumb { width: 54px; height: 54px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 16px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; box-shadow: 0 1px 3px rgba(0,0,0,.14); }\\n.ss-w-thumb.ss-w-team { border-radius: 12px; }\\n.ss-w-ecard[data-kind=\\\"player\\\"] .ss-w-thumb { background-color: var(--ss-w-accent); }\\n.ss-w-nm { font-weight: 680; line-height: 1.15; overflow-wrap: anywhere; }\\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n\\n/* bare card (no stat scopes): simple avatar + name row */\\n.ss-w-ecard-bare { display: flex; align-items: center; }\\n.ss-w-ecard-bare .ss-w-ecard-hd { padding: 10px 12px; }\\n\\n.ss-w-ecard-hd { display: flex; align-items: center; gap: 11px; padding: 11px 13px; }\\n.ss-w-ecard-hd .ss-w-thumb { width: 40px; height: 40px; font-size: 13px; box-shadow: none; }\\n.ss-w-ecard-hd .ss-w-thumb.ss-w-team { border-radius: 10px; }\\n.ss-w-ecard-meta { display: inline-flex; align-items: center; gap: 7px; flex: none; align-self: flex-start; margin-left: auto; }\\n.ss-w-ecard-meta .ss-w-ecard-season { margin: 0; }\\n\\n/* scope tabs: reuse the underline pattern, relocated above the strip */\\n.ss-w-ecard-scopes { display: flex; align-items: stretch; gap: 2px; padding: 0 11px; border-top: 1px solid var(--ss-w-line); flex-wrap: wrap; }\\n.ss-w-ecard-scope { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 7px 8px; margin-bottom: -1px; border-bottom: 2px solid transparent; }\\n.ss-w-ecard-scope[aria-selected=\\\"true\\\"] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }\\n.ss-w-ecard-scope .ss-w-ecard-crest { width: 14px; height: 14px; }\\n.ss-w-ecard-scopes + .ss-w-ecard-strip { border-top: none; }\\n\\n.ss-w-ecard-crest { width: 15px; height: 15px; flex: none; display: block; border-radius: 4px; background-size: cover; background-position: center; }\\n.ss-w-ecard-season { flex: none; margin-left: auto; align-self: center; margin-bottom: 5px; font-size: 10.5px; 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: 3px 9px; white-space: nowrap; }\\n\\n/* stat strip: 1px gap over a line-colored ground paints hairlines between cells, wrap-safe */\\n.ss-w-ecard-strip { display: grid; gap: 1px; background: var(--ss-w-line); border-top: 1px solid var(--ss-w-line); }\\n.ss-w-ecard-cell { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 4px; padding: 10px 4px 11px; background: var(--ss-w-panel); }\\n.ss-w-ecard-cval { height: 20px; display: flex; align-items: center; font-size: 17px; font-weight: 720; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }\\n.ss-w-ecard-cval .ss-w-form { width: 42px; }\\n.ss-w-ecard-clabel { font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); font-weight: 600; font-variant-numeric: tabular-nums; }\\n\\n.ss-w-form { justify-self: end; display: flex; height: 6px; width: 48px; border-radius: 4px; overflow: hidden; gap: 2px; }\\n.ss-w-form span { display: block; border-radius: 2px; }\\n.ss-w-form-w { background: var(--ss-w-pos); }\\n.ss-w-form-d { background: var(--ss-w-faint); }\\n.ss-w-form-l { background: var(--ss-w-neg); }\\n\\n.ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }\\n.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }\\n.ss-w-cards-more:disabled { opacity: .5; cursor: default; }\\n\\n/* betting insights */\\n.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 8px; }\\n\\n/* header, competition-hero fallback: comp on the left, live badge + kickoff + pin on the right,\\n all on one line (used when there is no fixture, and by MarketOddsCardList) */\\n.ss-w-bi-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-bi-header-left { display: inline-flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); }\\n.ss-w-bi-header-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }\\n/* two-tier header: a quiet meta line (competition + kickoff + match pin) stacked above the\\n fixture, so long club names get the whole width to themselves and stop truncating (u350) */\\n.ss-w-bi-head { display: flex; flex-direction: column; gap: 6px; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-bi-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }\\n.ss-w-bi-meta-left { display: inline-flex; align-items: center; gap: 5px; min-width: 0; flex: 1; }\\n.ss-w-bi-meta-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }\\n.ss-w-bi-fixture-line { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-bi-comp { font-size: 10.5px; color: var(--ss-w-faint); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-bi-kick { font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; flex: none; }\\n.ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; gap: 4px; flex: none; }\\n.ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }\\n.ss-w-bi-floor { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; align-self: flex-start; flex: none; }\\n\\n/* crests -- CSS background-image on a span, never <img> (matches .ss-w-ecard-crest precedent) */\\n.ss-w-bi-comp-logo { width: 16px; height: 16px; flex: none; display: block; border-radius: 50%; object-fit: contain; }\\n.ss-w-bi-crest { width: 24px; height: 24px; flex: none; display: block; border-radius: 50%; object-fit: contain; }\\n.ss-w-bi-crest-mono { display: grid; place-items: center; font-size: 10px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }\\n\\n/* fixture atoms -- crest-flanked team pair; shared by the insight fixture line and MarketOddsCardList */\\n.ss-w-bi-team { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-bi-vs { font-size: 10px; font-weight: 600; color: var(--ss-w-faint); flex: none; }\\n.ss-w-bi-fixture-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n/* shared crest-flanked team row (MarketOddsCardList); matches .ss-w-bi-fixture-line's hero weight\\n so the fixture reads the same on both card types (u350) */\\n.ss-w-bi-fixture { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n\\n/* row 2, two-tier: the market label owns a full-width line above the pick row (selection grows\\n left, odds + slip + pin sit right), so neither the market name nor the fixture clips (u350) */\\n.ss-w-bi-action { display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.25; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-bi-pick-row { display: flex; align-items: center; gap: 9px; }\\n.ss-w-bi-sel { flex: 1; min-width: 0; font-size: 13px; font-weight: 700; line-height: 1.2; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-bi-odds { flex: none; margin-left: auto; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }\\n.ss-w-bi-odds b { font-size: 20px; font-family: ui-monospace, monospace; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.05; }\\n.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }\\n.ss-w-bi-pick-row .ss-w-slip { flex: none; }\\n\\n/* row 3: bar-chart glyph + reasoning prose + stats-expander chevron, in a subtle strip */\\n.ss-w-bi-reason { display: flex; align-items: flex-start; gap: 8px; background: var(--ss-w-bubble); border-radius: 10px; padding: 8px 10px; }\\n.ss-w-bi-chart { flex: none; width: 13px; height: 12px; margin-top: 2px; opacity: .55;\\n background:\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) left / 3px 55% no-repeat,\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) center / 3px 100% no-repeat,\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) right / 3px 75% no-repeat;\\n background-position: left bottom, center bottom, right bottom;\\n}\\n.ss-w-bi-reason-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex: 1; }\\n.ss-w-bi-text { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); }\\n.ss-w-bi-text-clamp { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\\n.ss-w-bi-expand { flex: none; align-self: center; display: grid; place-items: center; width: 22px; height: 22px; margin: -2px -4px -2px 0; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; }\\n.ss-w-bi-expand:hover { color: var(--ss-w-ink); }\\n.ss-w-bi-arrow { width: 7px; height: 7px; border-right: 1.6px solid currentColor; border-top: 1.6px solid currentColor; transform: rotate(45deg); transition: transform .15s ease; }\\n.ss-w-bi-arrow-open { transform: rotate(135deg); }\\n.ss-w-bi-rows { display: flex; flex-direction: column; }\\n.ss-w-bi-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-bi-row:first-child { border-top: none; }\\n.ss-w-bi-row-lbl { font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 13px; flex: none; color: var(--ss-w-ink); }\\n.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\\n.ss-w-bi-scoped { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-bi-scopes { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }\\n.ss-w-bi-chip { font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 10px; color: var(--ss-w-faint); background: none; cursor: pointer; }\\n.ss-w-bi-chip[aria-pressed=\\\"true\\\"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }\\n\\n/* market odds card */\\n.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-mocard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }\\n/* Embedded inside the market accordion, which already provides the card frame + accent rail --\\n drop the inner frame so odds rows aren't double-bordered. */\\n.ss-w-mocard--bare { border: none; border-radius: 0; padding: 0; background: none; }\\n.ss-w-mo-sub { display: flex; flex-direction: column; gap: 5px; min-width: 0; }\\n.ss-w-mo-teams { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mo-market-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }\\n.ss-w-mo-market { font-size: 11.5px; font-weight: 600; color: var(--ss-w-faint); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mo-more { align-self: flex-start; display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11.5px; font-weight: 600; padding: 2px 0; cursor: pointer; }\\n.ss-w-mo-more:hover { text-decoration: underline; }\\n.ss-w-mo-more-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }\\n.ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }\\n.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }\\n.ss-w-mo-row:last-child { border-bottom: none; }\\n.ss-w-mo-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); flex: 1; min-width: 0; }\\n.ss-w-mo-price { margin-left: auto; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; color: var(--ss-w-accent); }\\n/* Movement: BOTH directions share --ss-w-faint on purpose. Green-good/red-bad would frame a\\n shortening price as a discount, which inverts what it actually means for the bettor. */\\n.ss-w-move { display: inline-flex; align-items: baseline; gap: 4px; color: var(--ss-w-faint); }\\n.ss-w-move-prev { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 12px; text-decoration: line-through; }\\n.ss-w-move-arrow { font-size: 9px; line-height: 1; }\\n/* margin-left:auto is row layout, not badge styling -- it belongs to the market-odds row, which is\\n a flex row, and must NOT follow the badge into the insight card's odds column. */\\n.ss-w-mo-row .ss-w-move { margin-left: auto; }\\n.ss-w-mo-row .ss-w-move + .ss-w-mo-price { margin-left: 0; }\\n.ss-w-mo-row .ss-w-slip { margin: 0; flex: none; }\\n.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }\\n\\n/* odds movement card */\\n.ss-w-omcards { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-omcard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-om-head { display: flex; align-items: center; gap: 8px; }\\n.ss-w-om-market { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-om-tag { margin-left: auto; flex: none; font-size: 9px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); border-radius: 8px; padding: 2px 7px; }\\n.ss-w-om-fixture { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-om-comp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-om-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }\\n.ss-w-om-chart { display: block; width: 100%; height: auto; }\\n/* Single neutral accent in BOTH directions, deliberately. Colouring a shortening price green\\n frames it as a discount, which inverts what it means for the bettor -- the same reason\\n .ss-w-move keeps both directions on --ss-w-faint. */\\n.ss-w-om-line { stroke: var(--ss-w-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }\\n.ss-w-om-dot { fill: var(--ss-w-accent); }\\n.ss-w-om-grid { stroke: var(--ss-w-line); stroke-width: 1; }\\n.ss-w-om-ylab, .ss-w-om-xlab { fill: var(--ss-w-faint); font-size: 9px; font-family: ui-monospace, monospace; }\\n.ss-w-om-empty { font-size: 11.5px; color: var(--ss-w-faint); padding: 6px 0; }\\n.ss-w-om-foot { display: flex; align-items: center; gap: 14px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-om-foot b { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ss-w-ink); }\\n.ss-w-om-excl { font-size: 10.5px; color: var(--ss-w-faint); }\\n.ss-w-om-susp { font-size: 11px; font-weight: 600; color: #c0392b; }\\n.ss-w-om-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\\n\\n/* action buttons */\\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\\n/* text-align is explicit because a <button> defaults to center, and a follow-up question long\\n enough to wrap then sets its second line ragged on both sides. */\\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; text-align: left; }\\n.ss-w-abtn:disabled { opacity: .5; cursor: default; }\\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\\n\\n/* intent chips */\\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\\n\\n/* input */\\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\\n.ss-w-textarea:disabled { opacity: .55; cursor: not-allowed; }\\n/* iOS Safari zooms the page when a focused field's font-size is < 16px. Bump it\\n on touch devices only, so the desktop 13px design is unchanged. */\\n@media (pointer: coarse) {\\n .ss-w-textarea { font-size: 16px; }\\n}\\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\\n\\n/* add to slip */\\n.ss-w-slip { position: relative; display: flex; }\\n.ss-w-slip-btn { font-size: 11.5px; font-weight: 620; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border: 1px solid var(--ss-w-cta); border-radius: 14px; padding: 5px 12px; cursor: pointer; white-space: nowrap; }\\n.ss-w-slip-btn:disabled { opacity: .6; cursor: default; background: var(--ss-w-bubble); color: var(--ss-w-faint); border-color: var(--ss-w-line); }\\n/* Anchored to the RIGHT of its (narrow) button wrapper and sized by content, growing leftward\\n into the card -- inheriting the wrapper's width squeezes the text to one character per line.\\n Every toast site (slip buttons, pin toggles) sits at the right edge of its row. */\\n.ss-w-toast { position: absolute; top: calc(100% + 6px); right: 0; z-index: 1; width: max-content; max-width: 210px; font-size: 11px; font-weight: 560; border-radius: 10px; padding: 5px 10px; overflow-wrap: anywhere; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\\n.ss-w-toast-success { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }\\n.ss-w-toast-error { color: #c0392b; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n\\n/* pin affordance */\\n.ss-w-pin-wrap { position: relative; display: inline-flex; flex: none; }\\n.ss-w-pin { flex: none; display: grid; place-items: center; width: 22px; height: 22px; padding: 0; border-radius: 50%; background: none; border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); cursor: pointer; }\\n.ss-w-pin svg { width: 12px; height: 12px; }\\n.ss-w-pin:hover { color: var(--ss-w-ink); border-color: var(--ss-w-faint); }\\n.ss-w-pin[data-on] { background: var(--ss-w-accent); border-color: var(--ss-w-accent); color: #fff; }\\n.ss-w-pin[data-on]:hover { background: var(--ss-w-accent); color: #fff; }\\n\\n@media (prefers-reduced-motion: reduce) {\\n .ss-w-abtn-shimmer { animation: none; }\\n}\\n\\n/* greeting dashboard */\\n.ss-w-dash { display: flex; flex-direction: column; gap: 12px; padding: 4px 0; }\\n.ss-w-dash-head { display: flex; flex-direction: column; }\\n.ss-w-dash-title { font-size: 18px; font-weight: 700; line-height: 1.25; color: var(--ss-w-ink); }\\n.ss-w-dash-subtitle { font-size: 13px; color: var(--ss-w-faint); margin-top: 4px; }\\n.ss-w-dash-foot { font-size: 11px; color: var(--ss-w-faint); margin-top: 2px; }\\n\\n.ss-w-dash-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-dash-tile--half { grid-column: span 1; }\\n.ss-w-dash-tile--full { grid-column: 1 / -1; }\\n\\n.ss-w-dash-tile {\\n display: flex; align-items: center; gap: 10px;\\n padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);\\n background: var(--ss-w-panel); text-align: left; cursor: pointer; width: 100%;\\n color: inherit; font: inherit;\\n min-width: 0; /* the panel is min(400px, 100vw - 40px): without this,\\n a long Turkish title blows the column out */\\n}\\n.ss-w-dash-tile-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px; font-size: 22px; }\\n.ss-w-dash-emoji { line-height: 1; }\\n.ss-w-dash-tile-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; flex: 1; }\\n.ss-w-dash-tile-title { min-width: 0; font-weight: 600; font-size: 14px; overflow-wrap: anywhere; }\\n.ss-w-dash-tile-subtitle { min-width: 0; font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-dash-tile-chevron { flex: none; margin-left: auto; width: 14px; height: 14px; color: var(--ss-w-faint); }\\n\\n/* Badge + crests share their own row, below the title -- NOT the icon/chevron row. A\\n nowrap badge (~70px) sitting beside icon+chevron in a ~180px half-span tile left the\\n title column at ~22px wide, wrapping every title character-by-character. Here the row\\n gets the body's full width, so a badge this size is comfortably inside it. */\\n.ss-w-dash-tile-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }\\n.ss-w-dash-tile-badge { flex: none; font-size: 10.5px; 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: 3px 9px; white-space: nowrap; }\\n\\n.ss-w-dash-tile-crests { flex: none; display: flex; align-items: center; }\\n.ss-w-dash-tile-crest {\\n width: 18px; height: 18px; border-radius: 50%;\\n background-size: cover; background-position: center; background-color: var(--ss-w-bubble);\\n margin-left: -6px; border: 2px solid var(--ss-w-panel); /* overlapping stack, capped at 3 in DashboardTile */\\n}\\n.ss-w-dash-tile-crest:first-child { margin-left: 0; }\\n\\n/* Market: default 2-column grid, tiles get the same accent rail as the other card\\n families (.ss-w-binsight, .ss-w-mocard, .ss-w-omcard) so a market tile reads as\\n part of that visual language rather than a plain unstyled button. */\\n.ss-w-dash--market .ss-w-dash-tile { border-left: 3px solid var(--ss-w-accent); }\\n\\n/* Goal: one column of pill rows. */\\n.ss-w-dash--goal .ss-w-dash-grid { grid-template-columns: 1fr; }\\n.ss-w-dash--goal .ss-w-dash-tile { border-radius: 999px; padding: 10px 14px; }\\n\\n/* Discovery: tinted bento cards. Stacked (icon over text) so a two- or three-word title gets\\n the tile's full width instead of the ~100px left of a horizontal icon+chevron -- that narrow\\n column was wrapping \\\"Most interesting angles\\\" onto three lines. The chevron is dropped (the\\n whole card is the tap target) and the badge + crest row is forced onto one line. */\\n.ss-w-dash--discovery .ss-w-dash-tile { flex-direction: column; align-items: stretch; gap: 8px; }\\n.ss-w-dash--discovery .ss-w-dash-tile-icon { align-self: flex-start; width: 32px; height: 32px; font-size: 26px; }\\n.ss-w-dash--discovery .ss-w-dash-tile-chevron { display: none; }\\n/* The full-span trends tile has the whole panel width, so its icon and title sit on one row\\n (horizontal, centre-aligned) rather than stacking like the narrow half tiles. */\\n.ss-w-dash--discovery .ss-w-dash-tile--full { flex-direction: row; align-items: center; }\\n.ss-w-dash--discovery .ss-w-dash-tile--full .ss-w-dash-tile-icon { align-self: center; }\\n.ss-w-dash--discovery .ss-w-dash-tile-meta { flex-wrap: nowrap; }\\n.ss-w-dash--discovery .ss-w-dash-tile-crest { width: 22px; height: 22px; }\\n/* Tints mix a hue into the live panel rather than hardcoding a light pastel, so a dark\\n operator surface (e.g. --ss-w-panel set from a navy `surface` brand color) yields a\\n readable tinted-dark card instead of near-white ink on a fixed light pastel. */\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(1) { background: color-mix(in srgb, #34c759 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: color-mix(in srgb, #3a82f6 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: color-mix(in srgb, #f5a623 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: color-mix(in srgb, #a855f7 10%, var(--ss-w-panel)); }\\n\\n/* club fan pre-match dashboard */\\n.ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }\\n.ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }\\n.ss-w-fandash-greeting--lead { font-weight: 400; }\\n.ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }\\n\\n/* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both\\n share the same box so the two families read as one system, not two ad hoc layouts. */\\n.ss-w-fandash-card {\\n display: flex; flex-direction: column; gap: 8px;\\n padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);\\n background: var(--ss-w-panel); text-align: left;\\n color: inherit; font: inherit; width: 100%; min-width: 0;\\n}\\n.ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }\\n.ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }\\n.ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }\\n\\n/* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label\\n split reused by the fixture head-to-head (and any future stat-row card). */\\n.ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }\\n.ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }\\n.ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-fandash-split-label { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n\\n/* fixture card */\\n.ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }\\n.ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }\\n.ss-w-fandash-fixture-team--away { justify-content: flex-end; }\\n.ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }\\n.ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }\\n.ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }\\n.ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }\\n.ss-w-fandash-fixture-vs { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }\\n/* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */\\n.ss-w-fandash-fixture-meta { border-top: 1px solid var(--ss-w-line); padding-top: 10px; text-align: center; font-size: 12.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-fixture-kickoff { font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-fandash-fixture-venue { font-weight: 600; }\\n.ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }\\n/* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */\\n.ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }\\n/* extra breathing room between the tally row and the fact beyond the card's own gap */\\n.ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }\\n\\n/* Team form: a two-column result-card grid, left = home team's last 5, right = away team's last 5,\\n most-recent first. The head row carries each column's crest + name; the rows grid is filled\\n home-cell/away-cell per index so the 2-col grid lays out pairs without extra JS bookkeeping. */\\n.ss-w-fandash-teamform-head { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; }\\n.ss-w-fandash-teamform-head-team { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 11.5px; font-weight: 750; }\\n.ss-w-fandash-teamform-head-team .ss-w-bi-crest { width: 18px; height: 18px; }\\n.ss-w-fandash-teamform-head-team .ss-w-bi-crest-mono { font-size: 8px; }\\n.ss-w-fandash-teamform-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-teamform-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 6px; }\\n.ss-w-fandash-teamform-slot { display: block; min-width: 0; }\\n.ss-w-fandash-teamform-cell {\\n display: flex; align-items: center; gap: 4px; border-radius: 7px; padding: 4px 5px; color: #fff;\\n}\\n.ss-w-fandash-teamform-cell--win { background: var(--ss-w-pos); }\\n.ss-w-fandash-teamform-cell--loss { background: var(--ss-w-neg); }\\n.ss-w-fandash-teamform-cell--draw { background: var(--ss-w-faint); }\\n.ss-w-fandash-teamform-cell .ss-w-bi-crest { width: 16px; height: 16px; flex: none; background: rgba(255, 255, 255, .22); }\\n.ss-w-fandash-teamform-cell .ss-w-bi-crest-mono { font-size: 7px; color: #fff; }\\n.ss-w-fandash-teamform-score { flex: 1; text-align: center; font-size: 12.5px; font-weight: 750; font-variant-numeric: tabular-nums; }\\n.ss-w-fandash-injuries-more { margin-top: 10px; width: 100%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 7px; font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); cursor: pointer; }\\n.ss-w-fandash-injuries-more:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }\\n.ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }\\n.ss-w-fandash-form-pill {\\n display: inline-grid; place-items: center; width: 16px; height: 16px;\\n border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;\\n}\\n.ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }\\n.ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }\\n.ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }\\n\\n/* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each\\n segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not\\n repeated here; the fixture card below carries it. */\\n.ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }\\n.ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }\\n.ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }\\n.ss-w-fandash-countdown-unit { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); margin-top: 3px; }\\n.ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }\\n\\n/* injuries + transfers: two-column ours/theirs, in/out */\\n.ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }\\n/* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */\\n.ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }\\n.ss-w-fandash-injuries-divider { background: var(--ss-w-line); }\\n.ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }\\n.ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }\\n.ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }\\n.ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }\\n.ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }\\n.ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }\\n.ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }\\n.ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }\\n.ss-w-fandash-transfer-type { align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 1px 7px; margin-top: 2px; }\\n\\n/* reason-to-bet */\\n.ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }\\n.ss-w-fandash-reason-item::before { content: \\\"•\\\"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }\\n\\n/* where-to-watch */\\n.ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-w-fandash-station-chip { font-size: 11.5px; font-weight: 600; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 999px; padding: 4px 10px; }\\n\\n/* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */\\n.ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-congested-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 8px; border-radius: 10px; background: var(--ss-w-bubble); }\\n.ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }\\n.ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }\\n.ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }\\n\\n/* links: 2-column grid of tappable tiles */\\n.ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-link-tile { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 11px 13px; border-radius: 10px; border: 1px solid transparent; text-decoration: none; color: inherit; background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); }\\n.ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }\\n.ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }\\n.ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }\\n\\n/* post-match result: full-time scoreboard, mirroring the live card's crest + big-score treatment.\\n A neutral \\\"Full time\\\" pill sits left of a coloured Win/Draw/Loss tag; the 3-column main row\\n (home crest+name | score | away crest+name, away reversed) puts the winner's score in full ink\\n and the loser's dimmed; a centered meta line sits under a divider. */\\n.ss-w-fandash-postmatch-top { display: flex; align-items: center; gap: 8px; margin-bottom: 15px; }\\n.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; }\\n.ss-w-fandash-postmatch-tag { margin-left: auto; flex: none; font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; }\\n.ss-w-fandash-postmatch-tag--win { color: var(--ss-w-pos); }\\n.ss-w-fandash-postmatch-tag--loss { color: var(--ss-w-neg); }\\n.ss-w-fandash-postmatch-tag--draw { color: var(--ss-w-faint); }\\n.ss-w-fandash-postmatch-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-fandash-postmatch-side { display: flex; align-items: center; gap: 10px; min-width: 0; }\\n.ss-w-fandash-postmatch-side--away { flex-direction: row-reverse; text-align: right; }\\n.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); }\\n.ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--home { background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--away { background: var(--ss-w-away); }\\n.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); }\\n.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; }\\n.ss-w-fandash-postmatch-score-value--win { color: var(--ss-w-ink); }\\n.ss-w-fandash-postmatch-score-value--lose { color: var(--ss-w-faint); }\\n.ss-w-fandash-postmatch-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 5px; }\\n.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; }\\n\\n/* post-match goals: a football-ball icon per goal (mirrors the live timeline ball, duplicated here\\n under the postmatch prefix), text dimmed for opponent goals and picked out in full ink + bold\\n for the club's own goals */\\n.ss-w-fandash-postmatch-goal-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-postmatch-goal { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ss-w-faint); }\\n.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); }\\n.ss-w-fandash-postmatch-goal--club { color: var(--ss-w-ink); font-weight: 650; }\\n\\n/* post-match stats: home value / stat label / away value, oriented by venue (u316), each row now\\n backed by a home/away split bar -- the big upgrade from plain text -- plus a legend. Mirrors\\n LiveStatsCard's split-bar treatment under the postmatch-prefixed classes; the shared\\n --ss-w-home/--ss-w-away/--ss-w-track tokens are defined above. */\\n.ss-w-fandash-postmatch-stat-rows { display: flex; flex-direction: column; gap: 15px; }\\n.ss-w-fandash-postmatch-stat { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-fandash-postmatch-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-fandash-postmatch-stat-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-postmatch-stat-value--home { color: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-stat-value--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-fandash-postmatch-stat-label { font-size: 10.5px; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }\\n.ss-w-fandash-postmatch-stat-bar { position: relative; height: 8px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-fandash-postmatch-stat-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-stat-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n.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); }\\n.ss-w-fandash-postmatch-legend-item { display: inline-flex; align-items: center; gap: 6px; }\\n.ss-w-fandash-postmatch-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }\\n.ss-w-fandash-postmatch-legend-swatch--home { background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-legend-swatch--away { background: var(--ss-w-away); }\\n\\n/* post-match top performer (full mockup treatment): gradient initials avatar + name + a\\n prominent rating chip. Avatar gradient reuses the --ss-w-away token, same pairing as the live\\n crest fallback; \\\"?\\\" renders through the same avatar span when the name is blank. */\\n.ss-w-fandash-postmatch-perf-row { display: flex; align-items: center; gap: 12px; }\\n.ss-w-fandash-postmatch-perf-avatar {\\n flex: none; width: 42px; height: 42px; border-radius: 50%;\\n display: grid; place-items: center;\\n font-size: 14px; font-weight: 800; color: #fff;\\n background: linear-gradient(135deg, var(--ss-w-away), color-mix(in srgb, var(--ss-w-away) 55%, #000));\\n}\\n.ss-w-fandash-postmatch-perf-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 700; }\\n.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; }\\n\\n/* post-match next (v1, modest): whenLabel is already a complete localized phrase (opponent +\\n venue + kickoff) composed server-side, so this card renders just that one line -- dressed up\\n with an accent rule rather than a duplicated opponent line. The richer opponent-headline/venue-\\n chip/crest layout from the mockup needs a server field split and is deferred. */\\n.ss-w-fandash-postmatch-next-row { display: flex; align-items: center; gap: 10px; border-left: 3px solid var(--ss-w-accent); padding-left: 10px; }\\n.ss-w-fandash-postmatch-next-when { font-size: 13.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.3; }\\n\\n/* resting next: the between-matches fixture teaser -- when-label left, competition badge right */\\n.ss-w-fandash-resting-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-resting-next-when { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }\\n.ss-w-fandash-resting-next-competition { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }\\n\\n/* resting standings: position figure left, W-D-L/points record right */\\n.ss-w-fandash-resting-standings-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-resting-standings-position { font-size: 15px; font-weight: 750; color: var(--ss-w-ink); }\\n.ss-w-fandash-resting-standings-record { font-size: 11.5px; color: var(--ss-w-faint); text-align: right; }\\n\\n/* resting season: top scorer / key player / season tally as stacked rows */\\n.ss-w-fandash-resting-season-rows { display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-fandash-resting-season-row { font-size: 12.5px; color: var(--ss-w-ink); }\\n\\n/* resting form: reuses the fixture last-five pill classes (ss-w-fandash-form / -form-pill) */\\n.ss-w-fandash-resting-form .ss-w-fandash-form { margin-top: 2px; }\\n\\n/* live score: pulsing Live pill, crests (real image or a coloured initials fallback), a big\\n tabular score, and an optional scorers line. Also where the shared home/away venue-colour\\n tokens (--ss-w-home / --ss-w-away / --ss-w-track) are defined above -- the timeline and stats\\n cards reuse them. */\\n.ss-w-fandash-live-top { display: flex; align-items: center; gap: 8px; }\\n.ss-w-fandash-live-pill { display: inline-flex; flex: none; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: #fff; background: var(--ss-w-neg); border-radius: 6px; padding: 3px 8px; }\\n.ss-w-fandash-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; animation: ss-w-fandash-live-pulse 1.3s ease-in-out infinite; }\\n@keyframes ss-w-fandash-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }\\n@media (prefers-reduced-motion: reduce) {\\n .ss-w-fandash-live-dot { animation: none; }\\n}\\n.ss-w-fandash-live-minute { flex: none; font-size: 13.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-competition { margin-left: auto; font-size: 11px; font-weight: 650; color: var(--ss-w-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-live-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-fandash-live-side { display: flex; align-items: center; gap: 10px; min-width: 0; }\\n.ss-w-fandash-live-side--away { flex-direction: row-reverse; text-align: right; }\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--home { background: var(--ss-w-home); }\\n.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--away { background: var(--ss-w-away); }\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-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; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 5px; }\\n.ss-w-fandash-live-scorers { margin-top: 12px; display: flex; justify-content: flex-end; gap: 7px; align-items: center; font-size: 12.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-fandash-live-scorers-icon { flex: none; color: var(--ss-w-away); }\\n\\n/* live timeline: a compact two-sided event list down a centre spine -- each club's events sit on\\n its own side (home left, away right), most-recent 3 shown with a \\\"See more\\\" toggle for the\\n rest. A 3-column grid (txt | badge | txt) per row; the spine itself is a ::before on the list. */\\n.ss-w-fandash-live-tl { position: relative; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-live-tl::before { content: \\\"\\\"; position: absolute; left: 50%; top: 1px; bottom: 1px; width: 2px; background: var(--ss-w-line); transform: translateX(-1px); }\\n.ss-w-fandash-live-tl-ev { display: grid; grid-template-columns: 1fr 32px 1fr; align-items: center; gap: 6px; }\\n.ss-w-fandash-live-tl-txt { display: flex; align-items: center; gap: 7px; font-size: 13px; min-width: 0; }\\n.ss-w-fandash-live-tl-ev--home .ss-w-fandash-live-tl-txt { grid-column: 1; justify-content: flex-end; }\\n.ss-w-fandash-live-tl-ev--away .ss-w-fandash-live-tl-txt { grid-column: 3; justify-content: flex-start; flex-direction: row-reverse; }\\n.ss-w-fandash-live-tl-who { font-weight: 650; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-fandash-live-tl-off { font-weight: 500; color: var(--ss-w-faint); }\\n.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-who { font-weight: 800; }\\n.ss-w-fandash-live-tl-badge { grid-column: 2; justify-self: center; min-width: 29px; height: 19px; padding: 0 4px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 800; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); font-variant-numeric: tabular-nums; z-index: 1; }\\n.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-badge { background: var(--ss-w-accent); color: #fff; border-color: transparent; }\\n.ss-w-fandash-live-tl-ico { width: 17px; height: 17px; flex: none; display: grid; place-items: center; }\\n.ss-w-fandash-live-tl-ico--goal { border-radius: 50%; background: color-mix(in srgb, var(--ss-w-away) 16%, transparent); }\\n.ss-w-fandash-live-tl-ball { width: 12px; height: 12px; 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); }\\n.ss-w-fandash-live-tl-card { width: 9px; height: 12px; border-radius: 2px; display: block; }\\n.ss-w-fandash-live-tl-card--yellow { background: var(--ss-w-cta); }\\n.ss-w-fandash-live-tl-card--red { background: var(--ss-w-away); }\\n.ss-w-fandash-live-tl-subarrows { font-size: 11px; font-weight: 900; line-height: 1; letter-spacing: -1px; color: var(--ss-w-accent); }\\n.ss-w-fandash-live-tl-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ss-w-faint); }\\n.ss-w-fandash-live-tl-more { margin-top: 4px; width: 100%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 7px; font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); cursor: pointer; }\\n.ss-w-fandash-live-tl-more:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }\\n\\n/* live stats: club value / stat label / opponent value, each row backed by a home/away split\\n bar, plus an optional momentum wave (or its text fallback) and a club/opponent colour legend.\\n No side signal reaches this card, so the club is always the home token and the opponent is\\n always the away token -- see LiveStatsCard.tsx. */\\n.ss-w-fandash-live-stat-rows { display: flex; flex-direction: column; gap: 15px; }\\n.ss-w-fandash-live-stat { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-fandash-live-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-fandash-live-stat-value { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-stat-value--home { color: var(--ss-w-home); }\\n.ss-w-fandash-live-stat-value--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-fandash-live-stat-label { font-size: 10.5px; font-weight: 700; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .04em; }\\n.ss-w-fandash-live-bar { position: relative; height: 8px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-fandash-live-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-fandash-live-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n\\n.ss-w-fandash-live-momentum { font-size: 11.5px; font-weight: 650; color: var(--ss-w-accent); }\\n.ss-w-fandash-live-mom { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-fandash-live-mom-caption { display: block; margin-bottom: 5px; font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); }\\n.ss-w-fandash-live-mom-svg { width: 100%; height: 56px; display: block; overflow: visible; }\\n.ss-w-fandash-live-mom-home { fill: var(--ss-w-home); fill-opacity: .85; }\\n.ss-w-fandash-live-mom-away { fill: var(--ss-w-away); fill-opacity: .85; }\\n.ss-w-fandash-live-mom-line { fill: none; stroke: color-mix(in srgb, var(--ss-w-ink) 55%, transparent); stroke-width: 1.5; }\\n.ss-w-fandash-live-mom-base { stroke: var(--ss-w-line); stroke-width: 1; stroke-dasharray: 3 3; }\\n.ss-w-fandash-live-mom-plot { position: relative; }\\n.ss-w-fandash-live-mom-now {\\n position: absolute; width: 7px; height: 7px; border-radius: 50%;\\n transform: translate(-50%, -50%);\\n background: var(--ss-w-panel); border: 1.5px solid var(--ss-w-ink);\\n pointer-events: none;\\n}\\n.ss-w-mon-mom { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); text-align: center; }\\n.ss-w-mon-mom .ss-w-fandash-live-mom { margin-top: 6px; padding-top: 0; border-top: none; }\\n\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-legend-item { display: inline-flex; align-items: center; gap: 6px; }\\n.ss-w-fandash-live-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }\\n.ss-w-fandash-live-legend-swatch--home { background: var(--ss-w-home); }\\n.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }\\n\\n/* live monitor tab bar: underline pattern mirrors .ss-w-ecard-scope; the unread dot uses --ss-w-neg */\\n.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); overflow-x: auto; scrollbar-width: none; }\\n.ss-w-tabs::-webkit-scrollbar { display: none; }\\n.ss-w-tab { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 9px 12px; margin-bottom: -1px; border-bottom: 2px solid transparent; flex: none; white-space: nowrap; }\\n.ss-w-tab[data-on] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }\\n.ss-w-tab-count { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 999px; padding: 1px 6px; }\\n.ss-w-tab[data-on] .ss-w-tab-count { color: var(--ss-w-accent); }\\n.ss-w-tab-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }\\n\\n/* Matches tab match card (MonitorMatchCard): pill row, crest/score main row, per-stat split\\n bars (venue-oriented -- home always left/blue, away always right/red, never club-oriented,\\n the u316 bug class), a promoted-market strip for the user's pinned stat chips, and a grace\\n note once the match has gone full time. Reuses the --ss-w-home/--ss-w-away/--ss-w-track venue\\n tokens and .ss-w-fandash-live-pill for the Live pill so all live surfaces share one look. */\\n.ss-w-mon { display: flex; flex-direction: column; gap: 10px; padding: 12px; border: 1px solid var(--ss-w-line); border-radius: 12px; background: var(--ss-w-panel); }\\n.ss-w-mon-top { display: flex; align-items: center; gap: 8px; }\\n.ss-w-mon-pill { display: inline-flex; flex: none; align-items: center; font-size: 10.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 6px; padding: 3px 8px; }\\n.ss-w-mon-min { flex: none; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-mon-comp { margin-left: auto; font-size: 11px; font-weight: 650; color: var(--ss-w-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mon-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-mon-side { display: flex; align-items: center; gap: 8px; min-width: 0; }\\n.ss-w-mon-side--away { flex-direction: row-reverse; text-align: right; }\\n/* long club names (Wolverhampton Wanderers) wrap to two lines instead of truncating mid-word */\\n.ss-w-mon-name { min-width: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.2; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-mon-vs { font-size: 12px; font-weight: 700; color: var(--ss-w-faint); text-transform: uppercase; }\\n.ss-w-mon-score { display: flex; align-items: baseline; justify-content: center; font-size: 26px; font-weight: 850; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; color: var(--ss-w-ink); }\\n.ss-w-mon-score i { font-style: normal; color: var(--ss-w-faint); font-weight: 500; margin: 0 4px; }\\n.ss-w-mon-scorers { display: grid; grid-template-columns: 1fr auto 1fr; align-items: start; column-gap: 10px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mon-scorers-col { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\\n.ss-w-mon-scorers-col li { overflow-wrap: anywhere; }\\n.ss-w-mon-scorers-home { text-align: right; }\\n.ss-w-mon-scorers-away { text-align: left; }\\n.ss-w-mon-scorers-ball { flex: none; align-self: start; line-height: 1.35; }\\n.ss-w-mon-stats { display: flex; flex-direction: column; gap: 10px; }\\n.ss-w-mon-stat { display: flex; flex-direction: column; gap: 5px; }\\n.ss-w-mon-pstrip { padding: 6px 8px; border-radius: 8px; background: color-mix(in srgb, var(--ss-w-accent) 8%, transparent); }\\n.ss-w-mon-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-mon-stat-v { font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-mon-stat-v--home { color: var(--ss-w-home); }\\n.ss-w-mon-stat-v--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-mon-stat-l { font-size: 10px; font-weight: 700; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }\\n.ss-w-mon-bar { position: relative; height: 6px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-mon-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-mon-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n.ss-w-mon-stat-mkt { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mon-mkt { background: color-mix(in srgb, var(--ss-w-accent) 10%, transparent); border-radius: 6px; padding: 3px 6px; color: var(--ss-w-ink); }\\n.ss-w-mon-stat-mkt-right { display: flex; align-items: center; gap: 6px; margin-left: auto; }\\n.ss-w-mon-price { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 700; color: var(--ss-w-accent); }\\n.ss-w-mon-susp { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 6px; padding: 2px 6px; }\\n.ss-w-mon-asof { display: block; font-size: 10.5px; font-weight: 600; color: var(--ss-w-cta); }\\n.ss-w-mon-grace { font-size: 11px; color: var(--ss-w-faint); border-top: 1px solid var(--ss-w-line); padding-top: 8px; }\\n\\n/* Matches/Odds tab panels (MonitorTabs): the shared per-market-pin context line, the empty\\n state shown when the snapshot carries no matches/markets yet, the persistent D5 in-slip badge,\\n and the per-market-pin wrapper card (struck price on settlement is a pure CSS hook off its\\n [data-settled] attribute -- no separate class on the price element itself). */\\n.ss-w-mk-ctx { display: flex; align-items: center; gap: 6px; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--ss-w-line); }\\n/* the score and the trailing badges/pin never shrink or wrap -- only the fixture name truncates */\\n.ss-w-mk-ctx b { flex: none; white-space: nowrap; }\\n/* the context line's fixture name stays single-line (the two-line clamp is for the match card) */\\n.ss-w-mk-ctx .ss-w-mon-name { display: block; white-space: nowrap; text-overflow: ellipsis; }\\n.ss-w-mk-ctx-side { display: flex; align-items: center; gap: 6px; min-width: 0; }\\n.ss-w-mk-ctx-right { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }\\n/* flex:1 keeps the composer pinned to the panel bottom when a tab is empty */\\n.ss-w-mon-empty { flex: 1; padding: 24px 16px; text-align: center; font-size: 12.5px; color: var(--ss-w-faint); }\\n/* Per-pin unavailable state: the pin's context line still rendered above (score, name, unpin), but\\n the pin has neither a card nor history (compose-time rescue failed) -- a small inline note beats\\n a bare context line with nothing under it. */\\n.ss-w-mon-empty-card { padding: 8px 0 2px; font-size: 12px; color: var(--ss-w-faint); }\\n.ss-w-mon-inslip { display: inline-flex; flex: none; align-items: center; gap: 3px; font-size: 10.5px; font-weight: 700; color: var(--ss-w-pos); }\\n/* Odds-tab item is bare: the visible card is the market-odds card itself (no outer wrapper card),\\n with an optional slim live strip above it. */\\n.ss-w-mon-oddspin { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-mk-live { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 0 2px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mk-live-score { color: var(--ss-w-ink); font-weight: 700; font-variant-numeric: tabular-nums; }\\n.ss-w-mon-oddspin[data-settled] .ss-w-mo-price,\\n.ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }\\n\\n/* market accordion (Task 9): one collapsed row per available market, expanding into a reused\\n MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */\\n/* Pinned-match tile: the match card + its odds accordion, spaced apart. */\\n.ss-w-mon-item { display: flex; flex-direction: column; gap: 10px; }\\n.ss-w-acc { display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-acc-row { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); overflow: hidden; }\\n/* Row header: expand toggle (flex:1) + the market PinToggle as a sibling (no nested buttons). */\\n.ss-w-acc-head { display: flex; align-items: center; gap: 8px; padding: 6px 9px 6px 11px; }\\n.ss-w-acc-toggle { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; background: none; border: none; cursor: pointer; text-align: left; font: inherit; color: var(--ss-w-ink); padding: 5px 0; }\\n/* Suspended: the row stays listed (knowing a market is off is useful) but is not tappable --\\n its card is unservable, so a pointer cursor would promise something that cannot load. */\\n.ss-w-acc-toggle--susp { cursor: default; color: var(--ss-w-faint); }\\n.ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; flex: none; }\\n.ss-w-acc-label { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); flex: none; }\\n.ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); flex: none; }\\n.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-acc-insight { font-size: 12px; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 7px 9px; }\\n.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }\\n\\n/* ---- Today tab (u355) ---- */\\n.ss-w-sec-head { display: flex; align-items: center; gap: 7px; padding: 2px 2px 0; font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); }\\n.ss-w-sec-head::after { content: \\\"\\\"; flex: 1; height: 1px; background: var(--ss-w-line); }\\n.ss-w-sec-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }\\n.ss-w-today-live { display: flex; flex-direction: column; gap: 2px; }\\n\\n.ss-w-grp { border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; }\\n.ss-w-grp-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 11px; background: var(--ss-w-bubble); border: none; font: inherit; color: var(--ss-w-ink); cursor: pointer; text-align: left; }\\n.ss-w-grp-head:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: -2px; }\\n.ss-w-grp-chev { color: var(--ss-w-faint); font-size: 10px; flex: none; }\\n.ss-w-grp-name { font-size: 12px; font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-grp-country { font-weight: 600; color: var(--ss-w-faint); }\\n.ss-w-grp-count { margin-left: auto; flex: none; font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 999px; padding: 1px 7px; font-variant-numeric: tabular-nums; }\\n.ss-w-grp-body { display: flex; flex-direction: column; padding: 2px 11px 6px; }\\n\\n.ss-w-drow { display: grid; grid-template-columns: 42px minmax(0,1fr) 22px; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-drow:last-child { border-bottom: none; }\\n.ss-w-drow-when { font-size: 11px; font-weight: 700; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }\\n.ss-w-drow-when--live { color: var(--ss-w-neg); }\\n/* Each side ellipsises independently: a single joined string truncates the away team off the end,\\n which is the u350 betting-card truncation one layer down. */\\n.ss-w-drow-fx { display: flex; align-items: center; gap: 6px; min-width: 0; }\\n.ss-w-drow-side { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1 1 0; }\\n/* Away side mirrors home around the score: crest to the far edge, name aligned inward. */\\n.ss-w-drow-side--away { flex-direction: row-reverse; text-align: right; }\\n.ss-w-drow-nm { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n/* Centre slot of .ss-w-drow-fx, between the two sides: flex:none so a widening score never\\n steals width the team names need to avoid ellipsis. min-width holds the slot at the width of a\\n one-digit scoreline so an unscored row's bare dash does not pull the column out of line -- the\\n scores read as a column down the list, not a jitter. */\\n.ss-w-drow-sc { flex: none; min-width: 26px; text-align: center; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-drow-sc--idle { color: var(--ss-w-faint); font-weight: 600; }\\n.ss-w-drow--live { background: color-mix(in srgb, var(--ss-w-neg) 5%, transparent); border-radius: 8px; padding: 7px 6px; margin: 0 -6px; border-bottom: none; }\\n.ss-w-drow-crest { width: 16px; height: 16px; flex: none; border-radius: 50%; object-fit: contain; background: var(--ss-w-bubble); }\\n\\n.ss-w-stale { font-size: 11px; font-weight: 600; color: var(--ss-w-cta); background: color-mix(in srgb, var(--ss-w-cta) 12%, var(--ss-w-panel)); border-radius: 8px; padding: 6px 9px; }\\n\\n/* ---- Games hub (D2) ---- */\\n/* Hub shell: prize banner → chips → game matrix, all in a single column */\\n.ss-w-games-hub { display: flex; flex-direction: column; gap: 12px; }\\n\\n/* Prize banner: CTA-tinted card with icon + body column (label + chips) */\\n.ss-w-prize { display: flex; align-items: flex-start; gap: 10px; padding: 11px 13px; border-radius: 12px; background: color-mix(in srgb, var(--ss-w-cta) 10%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-cta) 22%, var(--ss-w-line)); }\\n.ss-w-prize-icon { flex: none; font-size: 20px; line-height: 1; padding-top: 1px; }\\n.ss-w-prize-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-prize-text { font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.35; overflow-wrap: anywhere; }\\n\\n/* Hub chips (streak / rank) — NOT .ss-w-chip which belongs to intent chips */\\n.ss-w-g-chips { display: flex; gap: 6px; flex-wrap: wrap; }\\n.ss-w-g-chip { display: inline-flex; align-items: center; font-size: 11px; font-weight: 700; border-radius: 999px; padding: 3px 10px; border: 1px solid transparent; white-space: nowrap; }\\n.ss-w-g-chip--streak { color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border-color: var(--ss-w-cta); }\\n.ss-w-g-chip--rank { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-color: color-mix(in srgb, var(--ss-w-accent) 24%, var(--ss-w-line)); }\\n\\n/* Game matrix: 2-column grid of tiles */\\n.ss-w-gmatrix { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\\n\\n/* Game tile: a tappable card with status-driven visual state */\\n.ss-w-tile { display: flex; flex-direction: column; gap: 6px; padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line); background: var(--ss-w-panel); cursor: pointer; text-align: left; font: inherit; color: inherit; width: 100%; min-width: 0; transition: background .12s ease; }\\n.ss-w-tile:not([data-disabled]):hover { background: var(--ss-w-bubble); }\\n.ss-w-tile[data-disabled] { opacity: .6; cursor: default; pointer-events: none; }\\n.ss-w-tile-icon { font-size: 22px; line-height: 1; }\\n.ss-w-tile-title { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.25; overflow-wrap: anywhere; }\\n.ss-w-tile-status { font-size: 11px; color: var(--ss-w-faint); font-weight: 500; }\\n.ss-w-tile-status--available { color: var(--ss-w-accent); font-weight: 600; }\\n.ss-w-tile-status--in_progress { color: var(--ss-w-accent); font-weight: 600; }\\n.ss-w-tile-status--played { color: var(--ss-w-correct); font-weight: 700; font-variant-numeric: tabular-nums; }\\n.ss-w-tile-status--graded { color: var(--ss-w-correct); font-weight: 700; font-variant-numeric: tabular-nums; }\\n/* Skill / For-fun kind chip */\\n.ss-w-tile-chip { display: inline-flex; align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; border-radius: 999px; padding: 2px 7px; margin-top: 2px; }\\n.ss-w-tile-chip--skill { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); }\\n.ss-w-tile-chip--fun { color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); }\\n\\n/* Game screen host: back-row + placeholder body */\\n/* Game screen fills the panel; the board scrolls internally and the search/input bar stays\\n pinned at the bottom so the fan never has to scroll to reach it. */\\n.ss-w-gscreen-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 14px; overflow: hidden; }\\n.ss-w-gscreen { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0; }\\n.ss-w-gscreen > .ss-w-gxi, .ss-w-gscreen > .ss-w-gt, .ss-w-gscreen > .ss-w-cpath,\\n.ss-w-gscreen > .ss-w-btg, .ss-w-gscreen > .ss-w-hl { flex: 1; min-height: 0; }\\n/* Daily Quiz has no inner .ss-w-gscroll region — its whole body (score, questions, submit) is the\\n scroller, so it takes the fill AND the overflow here. Without this it was clipped by the\\n overflow:hidden frame and the lower questions + Submit could not be reached. */\\n.ss-w-gscreen > .ss-w-dq { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }\\n/* Scrollable board + guess-history region. */\\n.ss-w-gscroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 10px; padding-bottom: 2px; }\\n/* Bottom-pinned bar (search input / action). */\\n.ss-w-gpin { flex-shrink: 0; padding-top: 10px; }\\n/* Heads stay put above the scroll region. */\\n.ss-w-gxi-head, .ss-w-gt-head, .ss-w-cpath-head, .ss-w-btg-head { flex-shrink: 0; }\\n/* Mystery Tiger explainer key (✓ / ▲ / ▼). */\\n.ss-w-gt-key { white-space: nowrap; }\\n.ss-w-gt-key b { font-weight: 800; color: var(--ss-w-ink); }\\n.ss-w-gt-key-ok { color: var(--ss-w-correct) !important; }\\n/* Higher or Lower terminal score unit. */\\n.ss-w-hl-over-unit { font-size: 14px; font-weight: 700; color: var(--ss-w-faint); }\\n.ss-w-gscreen-back { display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; padding: 6px 0 10px; align-self: flex-start; }\\n.ss-w-gscreen-back-arrow { font-size: 11px; font-weight: 700; }\\n.ss-w-gscreen-body { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 16px; color: var(--ss-w-faint); font-size: 13px; text-align: center; }\\n\\n/* ---- Leaderboard (D2) ---- */\\n/* Outer shell */\\n.ss-w-lb2 { display: flex; flex-direction: column; gap: 12px; }\\n\\n/* Segmented control: This week / All time */\\n.ss-w-seg { display: inline-flex; gap: 2px; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }\\n.ss-w-seg-btn { font-size: 12px; font-weight: 600; border: none; border-radius: 7px; padding: 5px 12px; color: var(--ss-w-faint); background: none; cursor: pointer; font: inherit; white-space: nowrap; }\\n.ss-w-seg-btn[data-on] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 3px rgba(0,0,0,.09); }\\n\\n/* Row list */\\n.ss-w-lb2-rows { display: flex; flex-direction: column; border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; background: var(--ss-w-panel); }\\n.ss-w-lb2-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-lb2-row:last-child { border-bottom: none; }\\n/* Highlighted \\\"you\\\" row: full-width tint via negative margin trick, contained by border-radius above */\\n.ss-w-lb2-row--you { background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); }\\n.ss-w-lb2-rank { flex: none; min-width: 30px; font-size: 12.5px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-faint); }\\n.ss-w-lb2-rank--top3 { color: var(--ss-w-cta); }\\n.ss-w-lb2-handle { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ss-w-ink); }\\n.ss-w-lb2-points { flex: none; font-size: 13px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-lb2-streak { flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); padding-left: 4px; }\\n\\n/* Kit-prize separator: a labelled hairline (eyebrow + two growing lines) */\\n.ss-w-kitline { display: flex; align-items: center; gap: 8px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); }\\n.ss-w-kitline::before, .ss-w-kitline::after { content: \\\"\\\"; flex: 1; height: 1px; background: var(--ss-w-line); }\\n\\n/* Off-board treatment: dashed pill indicating rank is outside top N */\\n.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; }\\n\\n/* ---- Leaderboard empty / weekly-reset default state ---- */\\n.ss-w-lb-empty { display: flex; flex-direction: column; gap: 12px; flex: 1; }\\n.ss-w-lb-empty-hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 8px; padding: 20px 16px; border: 1px dashed color-mix(in srgb, var(--ss-w-cta) 30%, var(--ss-w-line)); border-radius: 14px; background: color-mix(in srgb, var(--ss-w-cta) 6%, var(--ss-w-panel)); }\\n.ss-w-lb-empty--alltime { align-items: center; justify-content: center; text-align: center; padding: 24px 16px; }\\n.ss-w-lb-empty-icon { font-size: 30px; line-height: 1; }\\n.ss-w-lb-empty-title { margin: 2px 0 0; font-size: 16px; font-weight: 800; color: var(--ss-w-ink); }\\n.ss-w-lb-empty-body { margin: 0; max-width: 30ch; font-size: 12.5px; line-height: 1.4; color: var(--ss-w-faint); }\\n.ss-w-lb-empty-cta { margin-top: 6px; border: none; border-radius: 10px; padding: 9px 18px; font: inherit; font-size: 13px; font-weight: 700; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); cursor: pointer; }\\n.ss-w-lb-empty-cta:hover { filter: brightness(1.04); }\\n.ss-w-lb-last { display: flex; align-items: center; gap: 7px; padding-top: 10px; border-top: 1px solid var(--ss-w-line); font-size: 11px; }\\n.ss-w-lb-last-label { text-transform: uppercase; letter-spacing: .05em; font-weight: 700; color: var(--ss-w-faint); }\\n.ss-w-lb-last-handle { flex: 1; min-width: 0; font-weight: 600; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-lb-last-points { flex: none; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n\\n/* ---- Mystery Tiger game screen (D3) ---- */\\n.ss-w-gt { display: flex; flex-direction: column; gap: 10px; }\\n/* Typeahead wrapper: relative so the dropdown can position under it */\\n.ss-w-gtta { position: relative; }\\n.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; }\\n.ss-w-gtta-i:focus { border-color: var(--ss-w-accent); }\\n.ss-w-gtta-i:disabled { opacity: .5; cursor: not-allowed; }\\n/* Opens UPWARD (bottom-anchored) because the input is pinned to the panel's bottom edge — a\\n downward menu would be clipped off-screen. */\\n.ss-w-gtta-drop { position: absolute; left: 0; right: 0; bottom: calc(100% + 4px); top: auto; z-index: 10; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 10px; max-height: 200px; overflow-y: auto; box-shadow: 0 -4px 16px rgba(0,0,0,.16); }\\n.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); }\\n.ss-w-gtta-opt:last-child { border-bottom: none; }\\n.ss-w-gtta-opt:hover { background: var(--ss-w-bubble); }\\n/* Header: title + sub + remaining chip */\\n.ss-w-gt-head { display: flex; align-items: flex-start; gap: 8px; }\\n.ss-w-gt-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-gt-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }\\n.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; }\\n/* Hero card — portrait + the masked profile the fan is hunting on. On reveal the silhouette\\n becomes the real photo (or initials) and the profile rows drop away. Fully token-driven. */\\n.ss-w-gt-card { display: grid; grid-template-columns: 96px 1fr; gap: 12px; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 12px; }\\n.ss-w-gt-card--reveal { grid-template-columns: 1fr; justify-items: center; }\\n.ss-w-gt-sil { width: 96px; height: 118px; border-radius: 11px; overflow: hidden; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); display: grid; place-items: center; }\\n.ss-w-gt-sil svg, .ss-w-gt-sil img { display: block; width: 100%; height: 100%; }\\n.ss-w-gt-sil img { object-fit: cover; }\\n.ss-w-gt-attrs { display: flex; flex-direction: column; justify-content: center; }\\n.ss-w-gt-attr { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 2px; }\\n.ss-w-gt-attr + .ss-w-gt-attr { border-top: 1px solid var(--ss-w-line); }\\n.ss-w-gt-attr-k { color: var(--ss-w-faint); font-size: 12px; font-weight: 600; }\\n.ss-w-gt-attr-v { color: var(--ss-w-faint); font-size: 13px; font-weight: 800; letter-spacing: .12em; }\\n/* Progress dots — one per guess allowance; used guesses filled with the accent. */\\n.ss-w-gt-dots { display: flex; gap: 7px; justify-content: center; }\\n.ss-w-gt-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ss-w-wrong); }\\n.ss-w-gt-dot--on { background: var(--ss-w-accent); }\\n/* Guess rows — one labelled block per guess */\\n.ss-w-gtrows { display: flex; flex-direction: column; gap: 8px; }\\n/* First-load legend (empty state) */\\n.ss-w-gt-lead { font-size: 11.5px; color: var(--ss-w-faint); line-height: 1.4; }\\n.ss-w-gtguess { display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-gtguess-nm { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }\\n.ss-w-gtrow { display: grid; grid-template-columns: repeat(5, 1fr); gap: 5px; }\\n/* Verdict tiles: label on top, verdict glyph below */\\n.ss-w-gtile { display: flex; flex-direction: column; align-items: center; justify-content: center; aspect-ratio: 1; border-radius: 8px; gap: 2px; min-width: 0; }\\n.ss-w-gtile-lab { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; opacity: .75; }\\n.ss-w-gtile-v { display: inline-flex; align-items: center; gap: 1px; font-size: 13px; font-weight: 800; line-height: 1; max-width: 100%; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-gtile-dir { font-size: 9px; line-height: 1; }\\n.ss-w-gtile--exact { background: var(--ss-w-correct); color: #062611; }\\n.ss-w-gtile--near { background: var(--ss-w-accent); color: #241700; }\\n.ss-w-gtile--miss { background: var(--ss-w-bubble); color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); }\\n/* Hint line */\\n.ss-w-gt-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)); }\\n/* Terminal outcome banner */\\n.ss-w-gt-banner { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 16px 12px; border-radius: 14px; text-align: center; }\\n.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)); }\\n.ss-w-gt-banner--failed { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n.ss-w-gt-banner-name { font-size: 20px; font-weight: 800; text-transform: uppercase; letter-spacing: .01em; color: var(--ss-w-accent); }\\n.ss-w-gt-banner-label { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-gt-banner-sub { font-size: 11px; color: var(--ss-w-faint); }\\n\\n/* ---- Higher or Lower game screen (D3) — artifact hl-pair/pcard/hlb layout ---- */\\n.ss-w-hl { display: flex; flex-direction: column; gap: 12px; }\\n/* Header: title + sub + streak chip */\\n.ss-w-hl-head { display: flex; align-items: flex-start; gap: 8px; }\\n.ss-w-hl-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-hl-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }\\n.ss-w-hl-streak { margin-left: auto; flex: none; 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: 4px 10px; white-space: nowrap; }\\n/* Question line */\\n.ss-w-hl-q { text-align: center; font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-faint); }\\n/* Pair: player A | Higher/Lower | player B */\\n.ss-w-hlpair { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: stretch; }\\n.ss-w-hlpc { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 14px 6px; text-align: center; min-width: 0; }\\n/* Player photo (was a 42px ball emoji): fixed 60px circle on both cards so they stay identical\\n regardless of name length. Falls back to initials when no photo URL is present. */\\n.ss-w-hlpc-av { width: 60px; height: 60px; border-radius: 50%; overflow: hidden; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); display: grid; place-items: center; flex: none; }\\n.ss-w-hlpc-av img { width: 100%; height: 100%; object-fit: cover; display: block; }\\n.ss-w-av-initials { font-size: 18px; font-weight: 800; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .02em; }\\n.ss-w-hlpc-name { font-size: 12.5px; font-weight: 700; color: var(--ss-w-ink); line-height: 1.15; }\\n.ss-w-hlpc-stat { font-size: 8.5px; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .04em; }\\n.ss-w-hlpc-val { font-size: 30px; font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; line-height: 1; }\\n.ss-w-hlpc-val--hidden { color: var(--ss-w-faint); }\\n/* Higher / Lower — middle column. The pair grid stretches this column to the cards' height, so\\n space-between pins Higher to the top and Lower to the bottom, with \\\"or\\\" centered between the\\n two players. */\\n.ss-w-hlbtns { display: flex; flex-direction: column; gap: 6px; justify-content: space-between; }\\n.ss-w-hl-or { text-align: center; font-size: 11px; font-weight: 700; color: var(--ss-w-faint); }\\n.ss-w-hlbtn { font: inherit; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; border-radius: 9px; padding: 10px 12px; cursor: pointer; border: 1px solid var(--ss-w-line); white-space: nowrap; transition: border-color .1s, background .1s; }\\n/* Both options are neutral until picked — an amber default read as \\\"already selected\\\". */\\n.ss-w-hlbtn--up, .ss-w-hlbtn--dn { background: var(--ss-w-panel); color: var(--ss-w-ink); }\\n.ss-w-hlbtn:hover:not(:disabled) { border-color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); color: var(--ss-w-accent); }\\n.ss-w-hlbtn:disabled { opacity: .5; cursor: not-allowed; }\\n/* Run-over terminal panel */\\n.ss-w-hl-over { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 16px; text-align: center; display: flex; flex-direction: column; gap: 5px; }\\n.ss-w-hl-over-title { font-size: 16px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); }\\n.ss-w-hl-over-score { font-size: 34px; font-weight: 800; color: var(--ss-w-accent); line-height: 1; font-variant-numeric: tabular-nums; }\\n.ss-w-hl-over-sub { font-size: 11px; color: var(--ss-w-faint); }\\n/* Answered history — clean single-line rows with the revealed value */\\n/* In-progress footer chips (artifact) */\\n.ss-w-hl-foot { display: flex; align-items: center; gap: 8px; }\\n.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; }\\n.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)); }\\n\\n/* ---- Career Path game screen (D3) — artifact cpath/club/cto layout ---- */\\n.ss-w-cpath { display: flex; flex-direction: column; gap: 12px; }\\n/* Header */\\n.ss-w-cpath-head { display: flex; align-items: flex-start; gap: 8px; }\\n.ss-w-cpath-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-cpath-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }\\n.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; }\\n/* Career sequence — horizontal crests with arrows */\\n.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; }\\n.ss-w-cpath-arrow { align-self: flex-start; flex: none; color: var(--ss-w-faint); font-size: 13px; padding-top: 9px; }\\n/* Single club — small vertical card */\\n.ss-w-cpath-club { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 56px; flex: none; }\\n.ss-w-cpath-crest { width: 34px; height: 34px; object-fit: contain; flex: none; border-radius: 8px; }\\n.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); }\\n.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; }\\n.ss-w-cpath-spell-yr { font-size: 8px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; }\\n.ss-w-cpath-loan-note { display: block; color: var(--ss-w-faint); font-weight: 500; }\\n.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)); }\\n/* Hint line */\\n.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)); }\\n/* Terminal outcome */\\n.ss-w-cpath-banner { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 16px 12px; border-radius: 14px; text-align: center; }\\n.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)); }\\n.ss-w-cpath-banner--failed { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n.ss-w-cpath-banner-name { font-size: 20px; font-weight: 800; text-transform: uppercase; letter-spacing: .01em; color: var(--ss-w-accent); }\\n.ss-w-cpath-banner-label { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-cpath-banner-sub { font-size: 11px; color: var(--ss-w-faint); }\\n\\n/* ---- Beat the Grid game screen (D3) — artifact grid/gc layout ---- */\\n.ss-w-btg { display: flex; flex-direction: column; gap: 10px; }\\n/* Header */\\n.ss-w-btg-head { display: flex; align-items: flex-start; gap: 8px; }\\n.ss-w-btg-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-btg-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }\\n.ss-w-btg-ctx { margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }\\n.ss-w-btg-ctx-score { font-size: 13px; font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; }\\n.ss-w-btg-ctx-left { font-size: 11px; color: var(--ss-w-faint); font-weight: 500; white-space: nowrap; }\\n/* Terminal summary */\\n.ss-w-btg-done { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 16px 12px; border-radius: 14px; text-align: center; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n.ss-w-btg-done-label { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-btg-done-score { font-size: 34px; font-weight: 800; color: var(--ss-w-accent); line-height: 1; font-variant-numeric: tabular-nums; }\\n.ss-w-btg-done-sub { font-size: 11px; color: var(--ss-w-faint); }\\n/* Empty search pool note */\\n.ss-w-btg-sheet-empty { font-size: 12px; color: var(--ss-w-faint); text-align: center; padding: 14px 8px; }\\n/* Grid layout — col count driven inline via style */\\n.ss-w-btg-grid { display: grid; gap: 4px; width: 100%; }\\n/* Generic grid cell */\\n.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; }\\n/* Corner placeholder */\\n.ss-w-btg-gc--corner { background: none; }\\n/* Column header */\\n.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); }\\n/* Row header */\\n.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; }\\n/* Interactive cells */\\n.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; }\\n.ss-w-btg-cell:hover:not(:disabled) { border-color: var(--ss-w-accent); background: var(--ss-w-bubble); }\\n.ss-w-btg-cell:disabled { cursor: not-allowed; opacity: .75; }\\n.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)); }\\n.ss-w-btg-cell--wrong { background: color-mix(in srgb, var(--ss-w-wrong) 10%, var(--ss-w-panel)); }\\n.ss-w-btg-cell--active { border-color: var(--ss-w-accent); }\\n.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; }\\n.ss-w-btg-cell-score { font-size: 12px; font-weight: 800; color: var(--ss-w-accent); font-variant-numeric: tabular-nums; }\\n.ss-w-btg-cell--correct .ss-w-btg-cell-score { color: var(--ss-w-correct); }\\n.ss-w-btg-cell-check { color: var(--ss-w-correct); line-height: 1; }\\n.ss-w-btg-cell-empty { font-size: 16px; color: var(--ss-w-faint); }\\n/* Scoped search sheet: slides up over the grid */\\n.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); }\\n.ss-w-btg-sheet-hdr { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\\n.ss-w-btg-sheet-ctx { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }\\n.ss-w-btg-sheet-row { font-size: 12.5px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-btg-sheet-sep { font-size: 13px; color: var(--ss-w-faint); font-weight: 500; }\\n.ss-w-btg-sheet-col { font-size: 12.5px; font-weight: 700; color: var(--ss-w-accent); }\\n.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; }\\n.ss-w-btg-sheet-close:hover { color: var(--ss-w-ink); background: var(--ss-w-bubble); }\\n\\n/* ---- Guess the XI game screen (D3) ---- */\\n.ss-w-gxi { display: flex; flex-direction: column; gap: 12px; }\\n/* Header */\\n.ss-w-gxi-head { display: flex; align-items: flex-start; gap: 8px; }\\n.ss-w-gxi-title { font-size: 18px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em; color: var(--ss-w-ink); line-height: 1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\\n/* Formation pill next to the title, e.g. \\\"4-2-3-1\\\". */\\n.ss-w-gxi-form { font-size: 12px; font-weight: 800; letter-spacing: .06em; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 26%, var(--ss-w-line)); border-radius: 999px; padding: 2px 9px; font-variant-numeric: tabular-nums; }\\n.ss-w-gxi-sub { font-size: 11px; color: var(--ss-w-faint); margin-top: 4px; }\\n.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; }\\n/* Pitch: a flag per slot laid out in formation rows on a green field. A real min-height plus\\n space-between distributes the formation lines top→bottom like a pitch (GK at the back, forwards\\n forward); yard-line stripes reinforce the read. Without a height the lines collapse together. */\\n/* A football pitch is grass-green regardless of the operator accent, so the field uses fixed\\n green values (not --ss-w-correct, which is a muted per-operator token that vanished on dark\\n themes) plus visible horizontal yard-lines and a brighter halfway line. */\\n.ss-w-gxi-pitch { position: relative; display: flex; flex-direction: column; justify-content: space-between; gap: 6px; min-height: 210px; padding: 14px 10px; border-radius: 14px; border: 1px solid rgba(46, 160, 86, .38);\\n background:\\n 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%),\\n repeating-linear-gradient(180deg, transparent 0 31px, rgba(255,255,255,.045) 31px 32px),\\n linear-gradient(180deg, rgba(46, 160, 86, .28), rgba(38, 132, 71, .16)); }\\n.ss-w-gxi-prow { display: flex; justify-content: center; align-items: flex-start; gap: 12px; }\\n.ss-w-gxi-slot { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 46px; }\\n.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; }\\n/* A slot whose player has been revealed by a wrong guess. */\\n.ss-w-gxi-flag--revealed { border-color: var(--ss-w-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ss-w-accent) 45%, transparent); }\\n/* Position label shown under every flag (GK, CB, CM, ST…) — reads the formation and marks the\\n keeper's end. Muted so it sits behind the flag, not competing with it. */\\n.ss-w-gxi-pos { font-size: 8.5px; line-height: 1.05; font-weight: 800; letter-spacing: .04em; text-align: center; color: rgba(255,255,255,.82); text-shadow: 0 1px 2px rgba(0,0,0,.5); }\\n/* Player surname, shown under the position once a wrong guess reveals it — in the accent colour. */\\n.ss-w-gxi-flag-lab { font-size: 8px; line-height: 1.05; font-weight: 700; text-align: center; color: var(--ss-w-accent); max-width: 46px; word-break: break-word; }\\n.ss-w-gxi-revnote { font-size: 11px; color: var(--ss-w-faint); }\\n/* Wrong-guess trail */\\n.ss-w-gxi-wrong { display: flex; flex-wrap: wrap; gap: 6px; }\\n.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; }\\n/* Earned reveals */\\n.ss-w-gxi-reveals { display: flex; flex-direction: column; gap: 4px; }\\n.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; }\\n.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; }\\n.ss-w-gxi-reveal-val { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }\\n/* Terminal outcome banner */\\n.ss-w-gxi-banner { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 16px 12px; border-radius: 14px; text-align: center; }\\n.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)); }\\n.ss-w-gxi-banner--failed { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n.ss-w-gxi-banner-label { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-gxi-banner-score { font-size: 34px; font-weight: 800; color: var(--ss-w-accent); line-height: 1; font-variant-numeric: tabular-nums; }\\n.ss-w-gxi-banner-sub { font-size: 11px; color: var(--ss-w-faint); }\\n/* Hint line */\\n.ss-w-gxi-hint { font-size: 11.5px; color: var(--ss-w-faint); text-align: center; font-style: italic; }\\n\\n/* ---- Daily Quiz game screen (D3) ---- */\\n.ss-w-dq { display: flex; flex-direction: column; gap: 14px; }\\n/* Score banner (post-reveal) */\\n.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; }\\n.ss-w-dq-score-val { font-size: 26px; font-weight: 800; color: var(--ss-w-correct); font-variant-numeric: tabular-nums; }\\n.ss-w-dq-score-label { font-size: 13px; font-weight: 650; color: var(--ss-w-faint); }\\n/* Progress bar */\\n.ss-w-dq-prog { height: 4px; border-radius: 999px; background: var(--ss-w-bubble); overflow: hidden; }\\n.ss-w-dq-prog-fill { height: 100%; border-radius: 999px; background: var(--ss-w-accent); transition: width .25s ease; }\\n/* Questions list */\\n.ss-w-dq-questions { display: flex; flex-direction: column; gap: 16px; }\\n/* Single question */\\n.ss-w-dq-q { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-dq-qstem { font-size: 13.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.4; }\\n/* Options grid: 2 across */\\n.ss-w-dq-opts { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\\n.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; }\\n.ss-w-dq-qopt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }\\n.ss-w-dq-qopt:disabled { cursor: not-allowed; }\\n.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)); }\\n.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); }\\n.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; }\\n/* Option letter badge */\\n.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); }\\n.ss-w-dq-qopt-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n/* Why/reveal text */\\n.ss-w-dq-qwhy { font-size: 11.5px; padding: 6px 10px; border-radius: 8px; line-height: 1.4; }\\n.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)); }\\n.ss-w-dq-qwhy--wrong { background: var(--ss-w-bubble); color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); }\\n/* Submit button */\\n.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; }\\n.ss-w-dq-submit:disabled { opacity: .4; cursor: not-allowed; }\\n.ss-w-dq-submit:hover:not(:disabled) { opacity: .88; }\\n\\n/* ── Matchday Predictor ──────────────────────────────────────────────────── */\\n.ss-w-mp { display: flex; flex-direction: column; gap: 14px; }\\n/* Score prediction row */\\n.ss-w-mp-pred-score { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 12px 0; }\\n.ss-w-mp-team { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; min-width: 0; }\\n.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%; }\\n.ss-w-mp-stepper { display: flex; align-items: center; gap: 8px; }\\n.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; }\\n.ss-w-mp-stepper-btn:hover:not(:disabled) { background: var(--ss-w-bubble); }\\n.ss-w-mp-stepper-btn:disabled { opacity: .35; cursor: not-allowed; }\\n.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; }\\n.ss-w-mp-sep { font-size: 22px; font-weight: 700; color: var(--ss-w-faint); padding: 0 4px; }\\n/* First-scorer picker */\\n.ss-w-mp-scorer { display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-mp-scorer-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }\\n.ss-w-mp-scorer-list { display: flex; flex-wrap: wrap; gap: 6px; }\\n.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; }\\n.ss-w-mp-scorer-opt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }\\n.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); }\\n.ss-w-mp-scorer-opt:disabled { opacity: .35; cursor: not-allowed; }\\n/* Save button */\\n.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; }\\n.ss-w-mp-savebtn:disabled { opacity: .4; cursor: not-allowed; }\\n.ss-w-mp-savebtn:hover:not(:disabled) { opacity: .88; }\\n/* Live / pending state */\\n.ss-w-mp-live { display: flex; flex-direction: column; gap: 10px; align-items: center; text-align: center; padding: 14px 0; }\\n.ss-w-mp-live-score { font-size: 30px; font-weight: 800; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }\\n.ss-w-mp-live-label { font-size: 12px; color: var(--ss-w-faint); font-style: italic; }\\n.ss-w-mp-live-outcome { display: flex; flex-direction: column; gap: 6px; width: 100%; }\\n.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; }\\n.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)); }\\n.ss-w-mp-live-row-key { color: var(--ss-w-faint); font-weight: 600; }\\n.ss-w-mp-live-row-val { font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-mp-live-row--correct .ss-w-mp-live-row-val { color: var(--ss-w-correct); }\\n/* For-fun note */\\n.ss-w-mp-fun { font-size: 11px; color: var(--ss-w-faint); text-align: center; font-style: italic; }\\n\\n/* ── Starting XI ─────────────────────────────────────────────────────────── */\\n.ss-w-sxi { display: flex; flex-direction: column; gap: 14px; }\\n.ss-w-sxi-formation { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }\\n/* Formation pitch area */\\n.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; }\\n.ss-w-sxi-pitch-row { display: flex; justify-content: center; gap: 6px; flex-wrap: wrap; }\\n/* Player slot */\\n.ss-w-sxi-pslot { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 64px; cursor: pointer; }\\n.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; }\\n.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); }\\n.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%; }\\n/* Squad picker */\\n.ss-w-sxi-squad { display: flex; flex-direction: column; gap: 4px; max-height: 200px; overflow-y: auto; }\\n.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; }\\n.ss-w-sxi-squad-row:hover:not(.ss-w-sxi-squad-row--picked) { background: var(--ss-w-bubble); }\\n.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); }\\n.ss-w-sxi-squad-name { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }\\n.ss-w-sxi-squad-pos { font-size: 10.5px; color: var(--ss-w-faint); }\\n.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; }\\n.ss-w-sxi-savebtn:disabled { opacity: .4; cursor: not-allowed; }\\n.ss-w-sxi-savebtn:hover:not(:disabled) { opacity: .88; }\\n/* Pending / graded states */\\n.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; }\\n.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)); }\\n.ss-w-sxi-status-score { font-size: 28px; font-weight: 800; color: var(--ss-w-correct); font-variant-numeric: tabular-nums; }\\n.ss-w-sxi-status-label { font-size: 12.5px; color: var(--ss-w-faint); }\\n\\n/* ── Stat Ladder ─────────────────────────────────────────────────────────── */\\n.ss-w-sl { display: flex; flex-direction: column; gap: 14px; }\\n.ss-w-sl-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }\\n/* Ladder list */\\n.ss-w-sl-ladder { display: flex; flex-direction: column; gap: 6px; }\\n.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); }\\n.ss-w-sl-lrow-rank { font-size: 11px; font-weight: 800; color: var(--ss-w-faint); width: 18px; flex: none; text-align: center; }\\n.ss-w-sl-lrow-name { flex: 1; font-size: 13px; font-weight: 650; color: var(--ss-w-ink); }\\n.ss-w-sl-lrow-stat { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); font-variant-numeric: tabular-nums; }\\n/* Mystery rung */\\n.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)); }\\n.ss-w-sl-mystery .ss-w-sl-lrow-name { color: var(--ss-w-faint); font-style: italic; }\\n/* Reveal overlay: correct / wrong */\\n.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)); }\\n.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)); }\\n/* Player picker */\\n.ss-w-sl-picker { display: flex; flex-wrap: wrap; gap: 6px; }\\n.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; }\\n.ss-w-sl-picker-opt:hover:not(:disabled) { background: var(--ss-w-bubble); border-color: var(--ss-w-accent); }\\n.ss-w-sl-picker-opt:disabled { opacity: .35; cursor: not-allowed; }\\n.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); }\\n.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); }\\n.ss-w-sl-reveal--wrong { background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); }\\n\\n/* ── Fan MOTM ────────────────────────────────────────────────────────────── */\\n.ss-w-motm { display: flex; flex-direction: column; gap: 14px; }\\n.ss-w-motm-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); text-align: center; }\\n/* Vote candidate list */\\n.ss-w-motm-votes { display: flex; flex-direction: column; gap: 6px; }\\n.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; }\\n.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); }\\n.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; }\\n.ss-w-motm-vrow--result { cursor: default; }\\n.ss-w-motm-vrow-name { flex: 1; font-size: 13px; font-weight: 650; color: var(--ss-w-ink); position: relative; z-index: 1; }\\n.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; }\\n/* Share fill bar (behind content) */\\n.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; }\\n.ss-w-motm-vrow--voted .ss-w-motm-vfill { background: color-mix(in srgb, var(--ss-w-accent) 18%, var(--ss-w-panel)); }\\n/* For-fun note */\\n.ss-w-motm-fun { font-size: 11px; color: var(--ss-w-faint); text-align: center; font-style: italic; }\\n\"\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["useCallback","useEffect","useMemo","useRef","useState","useEffect","useReducer","useRef","WidgetSdkError","useReducer","useRef","WidgetSdkError","useEffect","useCallback","useEffect","useRef","useState","useRef","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","TTL_MS","useState","useRef","useEffect","useCallback","useMemo","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","useState","useEffect","useRef","useState","useState","jsx","useState","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","useEffect","useState","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","jsx","useState","jsx","jsxs","useState","useCallback","useState","useEffect","jsx","jsx","jsxs","useState","useCallback","jsx","jsxs","directionWord","useState","jsx","initials","Crest","useCallback","useState","jsx","jsxs","useState","useCallback","jsx","jsxs","useState","Crest","useState","Fragment","jsx","jsxs","useState","Crest","Fragment","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","Crest","Fragment","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","Crest","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","initials","jsx","jsxs","jsx","jsxs","jsx","jsxs","initials","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useRef","useState","useEffect","useState","jsx","jsxs","initials","useState","useRef","useState","jsx","jsxs","SHOWN","jsx","jsxs","jsx","jsxs","splitWidths","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","useRef","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs","Crest","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","useState","jsx","Fragment","jsx","jsxs","jsx","jsxs","useEffect","useRef","useState","useCallback","useRef","useState","isTerminal","useState","useId","useState","jsx","Fragment","jsx","jsxs","useState","useId","Fragment","jsx","jsxs","parseClientState","useState","useId","Fragment","jsx","jsxs","parseClientState","useState","useId","Fragment","jsx","jsxs","parseClientState","isLocked","useState","useId","Fragment","jsx","jsxs","MAX_GUESSES","parseClientState","useState","useId","useState","Fragment","jsx","jsxs","parseClientState","useState","jsx","jsxs","parseClientState","useState","jsx","jsxs","parseClientState","jsx","jsxs","parseClientState","jsx","jsxs","parseClientState","jsx","jsxs","useState","useEffect","useRef","jsx","useState","useState","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","useState","jsx","jsx","jsxs","useState","useEffect","jsx","useMemo","useRef","useCallback","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/StatsWidget.tsx","../src/kickoff.ts","../src/i18n.ts","../src/config.ts","../src/slip.ts","../src/dashboardTap.ts","../src/theme.ts","../src/useChatStream.ts","../src/reducer.ts","../src/chart.ts","../src/model.ts","../src/useLiveDashboardPoll.ts","../src/conversationStore.ts","../src/useLiveMonitor.ts","../src/pinStore.ts","../src/useTabs.ts","../src/useMatchDiscovery.ts","../src/scheduleCache.ts","../src/dueSet.ts","../src/useGames.ts","../src/useLeaderboard.ts","../src/liveClock.ts","../src/eventLogContext.ts","../src/components/ChatFab.tsx","../src/components/BrandMark.tsx","../src/assets/logo.ts","../src/components/Icons.tsx","../src/components/GreetingBubble.tsx","../src/components/ChatPanel.tsx","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/Markdown.tsx","../src/components/EntityCardList.tsx","../src/components/BettingInsightList.tsx","../src/components/AddToSlipButton.tsx","../src/components/Toast.tsx","../src/components/OddsMovementBadge.tsx","../src/components/Crest.tsx","../src/components/PinToggle.tsx","../src/components/MarketOddsCardList.tsx","../src/components/OddsMovementCard.tsx","../src/components/ActionButtons.tsx","../src/components/dashboard/DashboardTile.tsx","../src/components/dashboard/GreetingDashboard.tsx","../src/components/dashboard/FixtureCard.tsx","../src/components/dashboard/CountdownCard.tsx","../src/components/dashboard/InjuriesCard.tsx","../src/components/dashboard/ReasonToBetCard.tsx","../src/components/dashboard/WhereToWatchCard.tsx","../src/components/dashboard/CongestedWeekCard.tsx","../src/components/dashboard/TransfersCard.tsx","../src/components/dashboard/LinksCard.tsx","../src/components/dashboard/PostMatchResultCard.tsx","../src/components/dashboard/PostMatchGoalsCard.tsx","../src/components/dashboard/PostMatchStatsCard.tsx","../src/components/dashboard/PostMatchTopPerformerCard.tsx","../src/components/dashboard/PostMatchNextCard.tsx","../src/components/dashboard/RestingNextCard.tsx","../src/components/dashboard/RestingStandingsCard.tsx","../src/components/dashboard/RestingSeasonCard.tsx","../src/components/dashboard/RestingFormCard.tsx","../src/components/dashboard/LiveScoreCard.tsx","../src/useLiveClock.ts","../src/components/dashboard/LiveTimelineCard.tsx","../src/components/dashboard/MomentumWave.tsx","../src/components/dashboard/LiveStatsCard.tsx","../src/components/dashboard/ClubFanDashboard.tsx","../src/components/ChatMessage.tsx","../src/components/IntentChips.tsx","../src/scroll.ts","../src/components/ChatInput.tsx","../src/components/TabBar.tsx","../src/components/MarketAccordion.tsx","../src/components/MonitorMatchCard.tsx","../src/components/MonitorTabs.tsx","../src/components/FixtureRow.tsx","../src/components/CompetitionGroup.tsx","../src/components/TodayPanel.tsx","../src/components/GamesPanel.tsx","../src/components/GamesLoginWall.tsx","../src/components/GamesHub.tsx","../src/components/games/ui/gameMeta.ts","../src/components/GameTileArt.tsx","../src/components/games/ui/Chip.tsx","../src/components/games/ui/icons.tsx","../src/components/GameTile.tsx","../src/components/GameScreenHost.tsx","../src/useGamePlay.ts","../src/components/games/MysteryTigerGame.tsx","../src/components/games/nationFlags.ts","../src/components/games/PlayerAvatar.tsx","../src/components/games/ui/GameHeader.tsx","../src/components/games/ui/SegmentProgress.tsx","../src/components/games/ui/SearchField.tsx","../src/components/games/ui/FooterBar.tsx","../src/components/games/ui/Silhouette.tsx","../src/components/games/ui/GameButton.tsx","../src/components/games/ui/ResultCard.tsx","../src/components/games/ui/OptionList.tsx","../src/components/games/HigherOrLowerGame.tsx","../src/components/games/CareerPathGame.tsx","../src/components/games/ui/CrestShield.tsx","../src/components/games/BeatTheGridGame.tsx","../src/components/games/GuessTheXiGame.tsx","../src/components/games/ui/PitchSvg.tsx","../src/components/games/ui/formations.ts","../src/components/games/DailyQuizGame.tsx","../src/components/games/MatchdayPredictorGame.tsx","../src/components/games/StartingXiGame.tsx","../src/components/games/StatLadderGame.tsx","../src/components/games/FanMotmGame.tsx","../src/components/games/ui/fonts.ts","../src/components/Leaderboard.tsx","../src/components/LeaderboardRow.tsx","../src/components/LeaderboardEmpty.tsx","../src/components/LeaderboardPanel.tsx","../src/styles/css.generated.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'\nimport { StatsWidgetClient, type Conversation } from '@sensiblestats/widget-sdk'\nimport { normalizeUi, toClientOptions, toUserContext, type StatsWidgetConfig } from './config'\nimport { wasAdded, type SlipHandlerProps } from './slip'\nimport { createDashboardTapSignal } from './dashboardTap'\nimport { themeAttrs } from './theme'\nimport { useChatStream } from './useChatStream'\nimport { useLiveMonitor } from './useLiveMonitor'\nimport { useMatchDiscovery } from './useMatchDiscovery'\nimport { useGames } from './useGames'\nimport { useLeaderboard } from './useLeaderboard'\nimport { visibleGroupsOf } from './liveClock'\nimport { EventLogContext } from './eventLogContext'\nimport { ChatFab } from './components/ChatFab'\nimport { ChatPanel } from './components/ChatPanel'\nimport { WIDGET_CSS } from './styles/css.generated'\n\nexport type StatsWidgetProps =\n | { config: StatsWidgetConfig; client?: never }\n | { client: StatsWidgetClient; config?: Omit<StatsWidgetConfig, 'operatorId' | 'publicKey' | 'baseUrl' | 'userContext'> }\n\nfunction buildClient(props: StatsWidgetProps): { client: StatsWidgetClient; conversation: Conversation } | null {\n try {\n if ('client' in props && props.client) {\n return { client: props.client, conversation: props.client.conversation() }\n }\n const cfg = props.config as StatsWidgetConfig\n const client = new StatsWidgetClient(toClientOptions(cfg))\n return { client, conversation: client.conversation(toUserContext(cfg)) }\n } catch (err) {\n console.error('[StatsWidget] failed to initialize:', err instanceof Error ? err.message : err)\n return null\n }\n}\n\nfunction injectStyles(root: Document | ShadowRoot): void {\n const host: ParentNode = root instanceof ShadowRoot ? root : root.head\n if (host.querySelector('#ss-w-styles')) return\n const el = document.createElement('style')\n el.id = 'ss-w-styles'\n el.textContent = WIDGET_CSS\n host.appendChild(el)\n}\n\nexport function StatsWidget(props: StatsWidgetProps): JSX.Element | null {\n const injectedClient = 'client' in props ? props.client : undefined\n const cfg = props.config as Partial<StatsWidgetConfig> | undefined\n const built = useMemo(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl])\n // One logger per mount, keyed on the client identity (not on operatorUserId/anonymousUserId/\n // conversationId -- those change over the widget's lifetime and are pushed in via setIdentity\n // below, not by tearing down and recreating the logger).\n const logger = useMemo(\n () => (built ? built.client.createEventLogger({\n operatorUserId: cfg?.userContext?.operatorUserId,\n anonymousUserId: cfg?.userContext?.anonymousUserId,\n }) : null),\n [built?.client],\n )\n const ui = useMemo(() => normalizeUi((props.config ?? { operatorId: '', publicKey: '' }) as StatsWidgetConfig), [props.config])\n const rootRef = useRef<HTMLDivElement>(null)\n // One-shot launcher attention animation: the FAB nudges then the greeting\n // types in, exactly once per page load. The ref lives here (not in ChatFab,\n // which remounts every time the panel closes) so it never replays; a page\n // refresh remounts the widget and re-arms it.\n const introDoneRef = useRef(false)\n const markIntroDone = useCallback(() => { introDoneRef.current = true }, [])\n const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ''}:${cfg?.userContext?.operatorUserId ?? 'anon'}`\n const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : undefined, convStorageKey)\n // The two hooks are mutually dependent -- useMatchDiscovery needs monitor.pins, useLiveMonitor\n // needs to know whether Today has content -- so the cycle is broken with state rather than a\n // read of discovery's own render. It settles one render later, and unlike a ref it actually\n // re-renders, which is what lets the fallback effect fire when Today empties under the user.\n const [hasToday, setHasToday] = useState(false)\n const monitor = useLiveMonitor({\n getLiveMonitor: (pins) => (built ? built.conversation.getLiveMonitor(pins) : Promise.resolve(null)),\n getMarketOdds: (matchId, dev) => (built ? built.conversation.getMarketOdds(matchId, dev) : Promise.resolve(null)),\n storageKey: `ss-w-pins:${cfg?.operatorId ?? ''}:${cfg?.userContext?.operatorUserId ?? 'anon'}`,\n isOpen: controller.state.isOpen,\n hasToday,\n })\n // Stable across renders (deps = [built], itself memoized on the client identity) -- the real\n // call site useMatchDiscovery.test.tsx's interval-churn test protects: a freshly-constructed\n // arrow here would defeat that guarantee even with the hook's own getStatesRef defense.\n const getSchedule = useCallback(\n (localDate: string, utcOffsetMinutes: number) =>\n built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),\n [built],\n )\n const getStates = useCallback(\n (matchIds: number[]) => (built ? built.conversation.getStates(matchIds) : Promise.resolve(null)),\n [built],\n )\n const pinnedMatchIds = useMemo(\n () => monitor.pins.filter((p) => p.kind === 'match').map((p) => p.matchId),\n [monitor.pins],\n )\n const discovery = useMatchDiscovery({\n getSchedule,\n getStates,\n operatorId: cfg?.operatorId ?? '',\n isOpen: controller.state.isOpen,\n pinnedMatchIds,\n })\n const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0\n useEffect(() => { setHasToday(todayHasContent) }, [todayHasContent])\n\n const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab })\n const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab })\n\n // The Today dot: the live count rising from zero is the \"something changed you have not seen\"\n // event for this tab. The hook suppresses it while Today is the active tab, exactly as the\n // other three dots are suppressed.\n const markTodayActivity = monitor.markTodayActivity\n const prevLiveCountRef = useRef(0)\n useEffect(() => {\n const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0\n prevLiveCountRef.current = discovery.liveCount\n if (rose) markTodayActivity()\n }, [discovery.liveCount, markTodayActivity])\n const slip = useMemo<SlipHandlerProps>(\n () => {\n const handler = props.config?.onAddToSlip\n return {\n // I3: the D5 persistent in-slip badge must arm from ANY add path -- a chat-message\n // insight/market card, not just the ones rendered inside the Odds tab itself -- so the\n // wasAdded->markInSlip wrap lives here (once), not duplicated per consumer.\n onAddToSlip: handler && (async (sel) => {\n const result = await handler(sel)\n if (wasAdded(result)) monitor.markInSlip(sel.matchOddsId)\n return result\n }),\n conversationId: controller.state.conversationId ?? undefined,\n onMarketClicked: (marketName) => {\n // sendSignal throws synchronously with no operatorUserId configured, and its\n // returned promise can reject on a gateway failure. Neither should ever break\n // the add-to-slip flow for a host that never wired signal tracking.\n try {\n void built?.conversation\n .sendSignal({ signalType: 'InsightMarketClicked', entityType: 'Market', entityName: marketName })\n .catch(() => undefined)\n } catch {\n // ignored — see comment above\n }\n },\n }\n },\n [props.config?.onAddToSlip, controller.state.conversationId, built, monitor.markInSlip],\n )\n const onDashboardTap = useMemo(\n () => (built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : undefined),\n [built, logger],\n )\n\n const operatorUserId = cfg?.userContext?.operatorUserId\n const anonymousUserId = cfg?.userContext?.anonymousUserId\n const conversationId = controller.state.conversationId ?? undefined\n useEffect(() => {\n if (!logger) return\n logger.setIdentity({ operatorUserId, anonymousUserId, conversationId })\n }, [logger, operatorUserId, anonymousUserId, conversationId])\n\n useEffect(() => {\n if (!logger) return\n const onHide = (): void => { logger.flushOnHide() }\n const onVisibilityHide = (): void => {\n if (document.visibilityState === 'hidden') logger.flushOnHide()\n }\n window.addEventListener('pagehide', onHide)\n document.addEventListener('visibilitychange', onVisibilityHide)\n return () => {\n window.removeEventListener('pagehide', onHide)\n document.removeEventListener('visibilitychange', onVisibilityHide)\n // dispose() only clears the internal timer -- it does NOT flush queued events, so an\n // unflushed dispose on unmount silently drops whatever is still queued.\n logger.flushOnHide()\n logger.dispose()\n }\n }, [logger])\n\n useEffect(() => {\n if (!built || !ui.injectStyles) return\n const node = rootRef.current?.getRootNode()\n if (node) injectStyles(node as Document | ShadowRoot)\n }, [built, ui.injectStyles])\n\n if (!built) return null\n const attrs = themeAttrs(ui)\n return (\n <EventLogContext.Provider value={logger}>\n <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 as CSSProperties}>\n {controller.state.isOpen ? (\n <ChatPanel\n controller={controller}\n ui={ui}\n slip={slip}\n onDashboardTap={onDashboardTap}\n monitor={monitor.enabled ? monitor : undefined}\n discovery={discovery}\n gamesResult={gamesResult}\n leaderboardResult={leaderboardResult}\n loggedIn={!!operatorUserId}\n conversation={built?.conversation ?? null}\n />\n ) : (\n <ChatFab\n label={ui.launcherLabel}\n greeting={ui.greeting}\n popupText={controller.state.popupText}\n logoUrl={ui.logoUrl}\n onOpen={controller.open}\n onDismissPopup={controller.dismissPopup}\n dismissLabel={ui.dismissGreeting}\n introAllowed={!introDoneRef.current}\n onIntroStart={markIntroDone}\n />\n )}\n </div>\n </EventLogContext.Provider>\n )\n}\n\n// Hooks must run unconditionally; when the client failed to build we still need a Conversation-shaped stub for the hook.\nfunction emptyConversation(): Conversation {\n return { send: () => { throw new Error('widget not initialized') } } as unknown as Conversation\n}\n","export function formatBettingKickoff(\n kickoffUtc: string,\n ui: { today: string; tomorrow: string },\n locale: string,\n now: Date = new Date(),\n): { dayLabel: string; time: string } {\n const at = new Date(kickoffUtc)\n const intlLocale = locale === 'tr' ? 'tr-TR' : 'en-GB'\n const time = new Intl.DateTimeFormat(intlLocale, { hour: '2-digit', minute: '2-digit' }).format(at)\n const atLocalDate = new Date(at.getFullYear(), at.getMonth(), at.getDate())\n const nowLocalDate = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n const dayDiff = Math.round((atLocalDate.getTime() - nowLocalDate.getTime()) / 86_400_000)\n const dayLabel =\n dayDiff === 0\n ? ui.today\n : dayDiff === 1\n ? ui.tomorrow\n : new Intl.DateTimeFormat(intlLocale, { weekday: 'short', day: 'numeric', month: 'short' }).format(at)\n return { dayLabel, time }\n}\n","import { formatBettingKickoff } from './kickoff'\n\nexport type Locale = 'en' | 'tr'\n\n// Games-tab copy (u393). Each game task adds its own keys here, in en AND tr.\nexport interface GamesStrings {\n // BCP-47 tag set on the games roots so CSS text-transform uppercases Turkish i → İ.\n lang: 'en' | 'tr'\n dailyChallenge: string\n playNow: string\n dailyGames: string\n newSetAtMidnight: string\n matchdayGames: string\n kickoffAt: (dayTime: string) => string\n statStreak: string\n statToday: string\n statRank: string\n unitDays: string\n unitPts: string\n thisWeek: string\n newToday: string\n resume: string\n done: string\n doneWithScore: (score: number) => string\n locksAt: (dayTime: string) => string\n // Points with the locale's digit grouping (\"1,200\" en / \"1.200\" tr). Used by the hub TODAY stat and doneWithScore.\n formatPts: (n: number) => string\n // Shared by every game screen (loading branch, result card, primary guess button).\n loading: string\n backToGames: string\n alreadyPlayedTitle: string\n guess: string\n // Localised \"Sat 15:00\". A function so each locale owns its Intl locale.\n formatDayTime: (iso: string) => string\n taglines: Record<string, string>\n mysteryTiger: {\n eyebrow: string\n labels: Record<'position' | 'nationality' | 'age' | 'shirtNumber' | 'apps', string>\n yourGuesses: string\n legendMatch: string\n legendClose: string\n legendHigher: string\n searchLabel: string\n searchPlaceholder: string\n optionsLabel: string\n progress: (used: number, total: number) => string\n solved: string\n failed: string\n detail: (guesses: number) => string\n }\n higherOrLower: {\n eyebrow: (points: number) => string\n streak: string\n whoHadMore: string\n season: (label: string) => string\n higher: string\n lower: string\n vs: string\n lastAnswer: (name: string, value: number) => string\n answersSoFar: (answered: number, total: number) => string\n runOver: string\n perfectRun: string\n runDetail: (correct: number) => string\n }\n guessTheXi: {\n pitchLabel: string\n notThem: string\n whichClub: (left: number) => string\n searchPlaceholder: string\n optionsLabel: string\n solved: string\n failed: string\n detail: (guesses: number) => string\n }\n dailyQuiz: {\n questionOf: (i: number, n: number) => string\n results: string\n next: string\n previous: string\n submit: string\n submitting: string\n correctOf: (correct: number, n: number) => string\n progressAria: (i: number, n: number) => string\n }\n careerPath: {\n eyebrow: string\n mysteryPlayer: string\n lockPosition: string\n lockNationality: string\n firstClub: string\n loan: string\n nextClubHidden: string\n moreClubs: (k: number) => string\n searchLabel: string\n searchPlaceholder: string\n solved: string\n failed: string\n guessesLine: (n: number) => string\n }\n beatTheGrid: {\n eyebrow: string\n filled: (n: number, total: number) => string\n toGo: (n: number) => string\n progressAria: (n: number, total: number) => string\n rowAbbrev: Record<string, string>\n pickCell: (row: string, col: string) => string\n cellFilled: (row: string, col: string, name: string, verdict: string) => string\n correct: string\n wrong: string\n closeSearch: string\n searchLabel: (row: string, col: string) => string\n searchPlaceholder: string\n emptyPool: string\n complete: string\n summary: (correct: number, filled: number) => string\n }\n predictor: {\n eyebrow: (home: string, away: string) => string\n home: string\n away: string\n goalsUp: (team: string) => string\n goalsDown: (team: string) => string\n firstScorer: string\n optional: string\n searchLabel: string\n searchPlaceholder: string\n noScorer: string\n save: string\n saving: string\n closed: string\n saved: string\n savedDetail: (p: { home: string; away: string; h: number; a: number; scorer: string | null }) => string\n fullTime: (h: number, a: number) => string\n exactScore: string\n outcome: string\n firstScorerRow: string\n correct: string\n incorrect: string\n forFun: string\n }\n startingXi: {\n eyebrow: string\n perStarter: (n: number) => string\n picked: (n: number) => string\n toGo: (n: number) => string\n pickSlot: (pos: string) => string\n clearSlot: (pos: string, name: string) => string\n pickFor: (pos: string) => string\n allPicked: string\n searchLabel: string\n submit: string\n submitting: string\n locksAt: (dayTime: string) => string\n locksSoon: string\n pending: (n: number) => string\n gradedLine: (correct: number) => string\n voided: string\n }\n motm: {\n title: string\n eyebrow: string\n voted: string\n yourVote: string\n youVoted: (name: string) => string\n thanks: string\n tapToVote: string\n forFun: string\n }\n statLadder: {\n eyebrow: string\n question: (stat: string) => { pre: string; emph: string; post: string }\n whoSecond: string\n clue: (\n c: { value: number; above: { name: string; diff: number } | null; below: { name: string; diff: number } | null },\n stat: string,\n ) => string\n searchLabel: string\n searchPlaceholder: string\n guess: string\n correct: string\n wrong: (name: string) => string\n }\n}\n\nconst formatPtsEn = (n: number): string => new Intl.NumberFormat('en-GB').format(n)\nconst formatPtsTr = (n: number): string => new Intl.NumberFormat('tr-TR').format(n)\n\nexport interface LocaleStrings {\n launcherLabel: string\n placeholder: string\n closeChat: string\n newConversation: string\n moreOptions: string\n chatDialogLabel: string\n stopResponse: string\n sendMessage: string\n dismissGreeting: string\n somethingWentWrong: string\n retry: string\n showLess: string\n showMore: (n: number) => string\n showStats: string\n hideStats: string\n oddsLabel: string\n liveLabel: string\n marketFloorLabel: string\n addToSlip: string\n marketPrices: string\n moreLines: string\n hideLines: string\n oddsMoved: (was: string, now: string, direction: string) => string\n oddsShortened: string\n oddsDrifted: string\n updatedLabel: string\n priceMovement: string\n openingLabel: string\n currentLabel: string\n movementWindow: (hours: number) => string\n notEnoughHistory: string\n singlePricePoint: string\n selectionSuspended: string\n excludedSuspended: (n: number) => string\n chartTimeLabel: (ms: number) => string\n chartAria: (opening: string, current: string, direction: string, hours: number) => string\n inSlip: string\n slipAdded: string\n slipDuplicate: string\n slipPriceChanged: (from: string, to: string) => string\n slipPriceNotAccepted: (from: string, to: string) => string\n slipLoginRequired: string\n slipSuspended: string\n slipFailed: string\n today: string\n tomorrow: string\n bettingKickoff: (kickoffUtc: string, now?: Date) => { dayLabel: string; time: string }\n tabChat: string\n tabFollowing: string\n tabOdds: string\n tabToday: string\n sectionLive: string\n /** Short scoreboard badge for the fixture row's time column. The long-form phase name\n * for the monitor card is fullTimeLabel. */\n halfTime: string\n staleStates: string\n pinLabel: string\n unpinLabel: string\n matchPinLabel: string\n matchUnpinLabel: string\n matchLimitToast: string\n marketLimitToast: string\n emptyMatchesTab: string\n emptyOddsTab: string\n asOf: (time: string) => string\n graceNote: string\n suspendedLabel: string\n fullTimeLabel: string\n ownGoalLabel: string\n inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: string\n tabGames: string\n tabLeaderboard: string\n gamesLoginRequired: string\n back: string\n leaderboardOffBoard: string\n leaderboardThisWeek: string\n leaderboardAllTime: string\n leaderboardEmptyFreshTitle: string\n leaderboardEmptyFreshBody: string\n leaderboardEmptyColdTitle: string\n leaderboardEmptyColdBody: string\n leaderboardEmptyCta: string\n leaderboardLastWeekLabel: string\n leaderboardAllTimeEmpty: string\n gamePlay: string\n gameLocked: string\n gameVoided: string\n games: GamesStrings\n}\n\nconst STRINGS: Record<Locale, LocaleStrings> = {\n en: {\n launcherLabel: 'Chat with SensibleStats',\n placeholder: 'Ask about a team, player or match…',\n closeChat: 'Close chat',\n newConversation: 'New conversation',\n moreOptions: 'More options',\n chatDialogLabel: 'SensibleStats chat',\n stopResponse: 'Stop response',\n sendMessage: 'Send message',\n dismissGreeting: 'Dismiss',\n somethingWentWrong: 'Something went wrong.',\n retry: 'Retry',\n showLess: 'Show less',\n showMore: (n) => `Show ${n} more`,\n showStats: 'Show stats',\n hideStats: 'Hide stats',\n oddsLabel: 'Odds',\n liveLabel: 'Live',\n marketFloorLabel: 'Market price · not a value pick',\n addToSlip: 'Add to slip',\n marketPrices: 'Market prices',\n moreLines: 'More lines',\n hideLines: 'Hide lines',\n oddsMoved: (was, now, direction) => `was ${was}, now ${now}, ${direction}`,\n oddsShortened: 'shortened',\n oddsDrifted: 'drifted',\n updatedLabel: 'updated',\n priceMovement: 'Price movement',\n openingLabel: 'Opening',\n currentLabel: 'Current',\n movementWindow: (hours) => (hours % 24 === 0 ? `Last ${hours / 24}d` : `Last ${hours}h`),\n notEnoughHistory: 'No price history recorded yet for this selection.',\n singlePricePoint: 'Only one price recorded so far for this selection.',\n selectionSuspended: 'This selection is not currently available to bet.',\n excludedSuspended: (n) => `${n} suspended price${n === 1 ? '' : 's'} excluded from this chart.`,\n chartTimeLabel: (ms) =>\n new Intl.DateTimeFormat('en-GB', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(ms)),\n chartAria: (opening, current, direction, hours) => {\n const span = hours % 24 === 0 ? `${hours / 24} day${hours / 24 === 1 ? '' : 's'}` : `${hours} hour${hours === 1 ? '' : 's'}`\n // A flat price has no direction word; appending an empty one leaves \", .\" for a screen reader.\n const drift = direction ? `, ${direction}` : ''\n return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`\n },\n inSlip: 'In slip',\n slipAdded: 'Added to slip',\n slipDuplicate: 'Already in your slip',\n slipPriceChanged: (from, to) => `Added at ${to} (was ${from})`,\n slipPriceNotAccepted: (from, to) => `Price moved to ${to} (was ${from}). Tap to add.`,\n slipLoginRequired: 'Sign in to add to your slip',\n slipSuspended: 'Market suspended',\n slipFailed: \"Couldn't add to slip. Try again.\",\n today: 'Today',\n tomorrow: 'Tomorrow',\n bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.en, 'en', now),\n tabChat: 'Chat',\n tabFollowing: 'Following',\n tabOdds: 'Odds',\n pinLabel: 'Track odds',\n unpinLabel: 'Stop tracking odds',\n matchPinLabel: 'Track match',\n matchUnpinLabel: 'Stop tracking match',\n matchLimitToast: 'Match limit reached — unpin one first',\n marketLimitToast: 'Odds limit reached — unpin one first',\n emptyMatchesTab: 'No pinned matches yet. Pin a match from the conversation to track it live.',\n emptyOddsTab: 'No pinned odds yet. Pin a market from the conversation to track it live.',\n asOf: (time) => `Prices as of ${time}`,\n graceNote: 'Unpins on next open · or in 4 h',\n suspendedLabel: 'Suspended',\n fullTimeLabel: 'Full time',\n ownGoalLabel: 'OG',\n inSlipLabel: 'In slip',\n oddsUnavailable: 'Odds unavailable right now',\n momentumLabel: 'Momentum',\n accordionValueLabel: 'Value',\n accordionRetry: \"Couldn't load odds — tap to retry\",\n accordionSuspended: 'Suspended',\n tabToday: 'Today',\n sectionLive: 'Live',\n halfTime: 'HT',\n staleStates: \"Live scores can't be updated — showing the last known state.\",\n tabGames: 'Games',\n tabLeaderboard: 'Leaderboard',\n gamesLoginRequired: 'Sign in to play and climb the leaderboard',\n back: 'Back',\n leaderboardOffBoard: 'Outside top 50',\n leaderboardThisWeek: 'This week',\n leaderboardAllTime: 'All time',\n leaderboardEmptyFreshTitle: 'New week, blank slate',\n leaderboardEmptyFreshBody: 'No scores yet. The first fan to play a game takes #1.',\n leaderboardEmptyColdTitle: 'Be the first up',\n leaderboardEmptyColdBody: \"Nobody's on the board yet. Play a game and you're #1.\",\n leaderboardEmptyCta: \"Play today's games\",\n leaderboardLastWeekLabel: 'Last week',\n leaderboardAllTimeEmpty: 'The all-time board fills as fans play — nothing here yet.',\n gamePlay: 'Play',\n gameLocked: 'Locked',\n gameVoided: 'Voided',\n games: {\n lang: 'en',\n dailyChallenge: 'Daily challenge',\n playNow: 'Play now',\n dailyGames: 'Daily games',\n newSetAtMidnight: 'New set at midnight',\n matchdayGames: 'Matchday games',\n kickoffAt: (t) => `Kick-off ${t}`,\n statStreak: 'Streak',\n statToday: 'Today',\n statRank: 'Rank',\n unitDays: 'days',\n unitPts: 'pts',\n thisWeek: 'this week',\n newToday: 'New today',\n resume: 'Resume',\n done: 'Done',\n doneWithScore: (s) => `Done · +${formatPtsEn(s)}`,\n locksAt: (t) => `Locks ${t}`,\n formatPts: formatPtsEn,\n loading: 'Loading…',\n backToGames: 'Back to games',\n alreadyPlayedTitle: 'Played today',\n guess: 'Guess',\n formatDayTime: (iso) =>\n new Intl.DateTimeFormat('en-GB', { weekday: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(iso)),\n taglines: {\n 'mystery-tiger': 'One player. Six guesses.',\n 'higher-or-lower': 'Who had more?',\n 'guess-the-xi': 'Name the team',\n 'daily-quiz': 'Test your club knowledge',\n 'career-path': 'Follow the clubs',\n 'beat-the-grid': 'Fill all 9 cells',\n 'matchday-predictor': 'Call the score',\n 'starting-xi': 'Pick the lineup',\n 'stat-ladder': 'Find the missing rung',\n 'fan-motm': 'Vote at full time',\n },\n mysteryTiger: {\n eyebrow: 'Daily · resets 00:00',\n labels: { position: 'POS', nationality: 'NAT', age: 'AGE', shirtNumber: 'NO.', apps: 'APPS' },\n yourGuesses: 'Your guesses',\n legendMatch: 'Match',\n legendClose: 'Close',\n legendHigher: 'Mystery is higher',\n searchLabel: 'Guess a squad player',\n searchPlaceholder: 'Search by name',\n optionsLabel: 'Squad players',\n progress: (used, total) => `${used} of ${total} guesses used`,\n solved: 'You found them!',\n failed: 'Out of guesses',\n detail: (n) => `${n} ${n === 1 ? 'guess' : 'guesses'} · back tomorrow`,\n },\n higherOrLower: {\n eyebrow: (p) => `+${p} per correct`,\n streak: 'Streak',\n whoHadMore: 'Who had more',\n season: (l) => `${l} season`,\n higher: 'Higher',\n lower: 'Lower',\n vs: 'VS',\n lastAnswer: (name, value) => `${name} had ${value}`,\n answersSoFar: (a, total) => `${a} of ${total} answered`,\n runOver: 'Run over',\n perfectRun: 'Perfect run!',\n runDetail: (c) => `${c} correct in a row · back tomorrow`,\n },\n guessTheXi: {\n pitchLabel: 'Starting line-up by nationality',\n notThem: 'Not them:',\n whichClub: (left) => `Which club is this? · ${left} left`,\n searchPlaceholder: 'Search clubs',\n optionsLabel: 'Clubs',\n solved: 'Solved!',\n failed: 'Out of guesses',\n detail: (n) => `${n} ${n === 1 ? 'guess' : 'guesses'} · back tomorrow`,\n },\n dailyQuiz: {\n questionOf: (i, n) => `Question ${i} of ${n}`,\n results: 'Results',\n next: 'Next',\n previous: 'Previous',\n submit: 'Submit',\n submitting: 'Submitting…',\n correctOf: (c, n) => `${c} of ${n} correct`,\n progressAria: (i, n) => `Question ${i} of ${n}`,\n },\n careerPath: {\n eyebrow: 'Oldest club first',\n mysteryPlayer: 'Mystery player',\n lockPosition: 'Position',\n lockNationality: 'Nationality',\n firstClub: 'First club',\n loan: 'Loan',\n nextClubHidden: 'Next club — revealed after a wrong guess',\n moreClubs: (k) => `+ ${k} more club${k === 1 ? '' : 's'}`,\n searchLabel: 'Who is it?',\n searchPlaceholder: 'Search any player',\n solved: 'Career traced!',\n failed: 'Out of guesses',\n guessesLine: (n) => `${n} guess${n === 1 ? '' : 'es'} · come back tomorrow`,\n },\n beatTheGrid: {\n eyebrow: 'Fill each cell with a player who fits',\n filled: (n, t) => `${n} of ${t} filled`,\n toGo: (n) => `${n} to go`,\n progressAria: (n, t) => `${n} of ${t} cells filled`,\n rowAbbrev: { Goalkeeper: 'GK', Defender: 'DEF', Midfielder: 'MID', Forward: 'FWD' },\n pickCell: (r, c) => `Pick a ${r.toLowerCase()} with ${c}`,\n cellFilled: (r, c, name, verdict) => `${r} with ${c}: ${name}, ${verdict.toLowerCase()}`,\n correct: 'Correct',\n wrong: 'Wrong',\n closeSearch: 'Close player search',\n searchLabel: (r, c) => `Search player for ${r} × ${c}`,\n searchPlaceholder: 'Search players',\n emptyPool: 'No players available to search yet.',\n complete: 'Grid complete',\n summary: (c, f) => `${c}/${f} correct · come back tomorrow`,\n },\n predictor: {\n eyebrow: (home, away) => `${home} v ${away}`,\n home: 'Home',\n away: 'Away',\n goalsUp: (team) => `${team} goals up`,\n goalsDown: (team) => `${team} goals down`,\n firstScorer: 'First scorer',\n optional: 'Optional',\n searchLabel: 'Search first scorer',\n searchPlaceholder: 'Search squad',\n noScorer: 'No first scorer',\n save: 'Save prediction',\n saving: 'Saving…',\n closed: 'Submissions are now closed',\n saved: 'Prediction saved',\n savedDetail: (p) =>\n `${p.home ? `${p.home} ` : ''}${p.h}–${p.a}${p.away ? ` ${p.away}` : ''}${p.scorer ? ` · ${p.scorer} first` : ''} · awaiting result`,\n fullTime: (h, a) => `Full time ${h} – ${a}`,\n exactScore: 'Exact score',\n outcome: 'Result (W/D/L)',\n firstScorerRow: 'First scorer',\n correct: 'Correct',\n incorrect: 'Incorrect',\n forFun: 'For fun — not in the leaderboard',\n },\n startingXi: {\n eyebrow: 'Predict the lineup',\n perStarter: (n) => `+${n} per starter`,\n picked: (n) => `${n} of 11 picked`,\n toGo: (n) => `${n} to go`,\n pickSlot: (pos) => `Pick ${pos}`,\n clearSlot: (pos, name) => `Remove ${name} from ${pos}`,\n pickFor: (pos) => `Pick your ${pos}`,\n allPicked: 'All 11 picked — tap a player on the pitch to swap',\n searchLabel: 'Search squad',\n submit: 'Lock in my XI',\n submitting: 'Submitting…',\n locksAt: (t) => `Locks ${t}, about an hour before kick-off`,\n locksSoon: 'Locks about an hour before kick-off',\n pending: (n) => `Prediction locked in (${n} players) — awaiting result`,\n gradedLine: (c) => `${c} of 11 correct`,\n voided: 'This game has been voided',\n },\n motm: {\n title: 'Man of the Match',\n eyebrow: 'Fan vote',\n voted: 'Voted',\n yourVote: 'Your vote',\n youVoted: (name) => `You voted ${name}`,\n thanks: \"Thanks — results aren't shown for this vote\",\n tapToVote: 'Tap a player to vote',\n forFun: 'For fun — unranked community vote',\n },\n statLadder: {\n eyebrow: 'Last match',\n question: (stat) => ({ pre: 'Who made the ', emph: '2nd-most', post: ` ${stat.toLowerCase()}?` }),\n whoSecond: \"Who's 2nd?\",\n clue: (c, stat) => {\n const parts: string[] = []\n if (c.above) parts.push(c.above.diff === 0 ? `the same as ${c.above.name}` : `${c.above.diff} fewer than ${c.above.name}`)\n if (c.below) parts.push(c.below.diff === 0 ? `the same as ${c.below.name}` : `${c.below.diff} more than ${c.below.name}`)\n return `They made ${c.value} ${stat.toLowerCase()}${parts.length ? `, ${parts.join(' and ')}` : ''}.`\n },\n searchLabel: 'Guess the 2nd player',\n searchPlaceholder: 'Search squad',\n guess: 'Guess',\n correct: 'Correct!',\n wrong: (name) => `Wrong — it was ${name}`,\n },\n },\n },\n tr: {\n launcherLabel: 'SensibleStats ile sohbet et',\n placeholder: 'Bir takım, oyuncu veya maç hakkında sor…',\n closeChat: 'Sohbeti kapat',\n newConversation: 'Yeni sohbet',\n moreOptions: 'Diğer seçenekler',\n chatDialogLabel: 'SensibleStats sohbet',\n stopResponse: 'Yanıtı durdur',\n sendMessage: 'Mesaj gönder',\n dismissGreeting: 'Kapat',\n somethingWentWrong: 'Bir şeyler ters gitti.',\n retry: 'Tekrar dene',\n showLess: 'Daha az göster',\n showMore: (n) => `${n} tane daha göster`,\n showStats: 'İstatistikleri göster',\n hideStats: 'İstatistikleri gizle',\n oddsLabel: 'Oran',\n liveLabel: 'Canlı',\n marketFloorLabel: 'Piyasa oranı · değer bahsi değil',\n addToSlip: 'Kupona ekle',\n marketPrices: 'Piyasa fiyatları',\n moreLines: 'Diğer çizgiler',\n hideLines: 'Çizgileri gizle',\n oddsMoved: (was, now, direction) => `önce ${was}, şimdi ${now}, ${direction}`,\n oddsShortened: 'düştü',\n oddsDrifted: 'yükseldi',\n updatedLabel: 'güncellendi',\n priceMovement: 'Oran hareketi',\n openingLabel: 'Açılış',\n currentLabel: 'Güncel',\n movementWindow: (hours) => (hours % 24 === 0 ? `Son ${hours / 24} gün` : `Son ${hours} saat`),\n notEnoughHistory: 'Bu seçim için henüz oran geçmişi kaydedilmedi.',\n singlePricePoint: 'Bu seçim için şimdiye kadar yalnızca bir fiyat kaydedildi.',\n selectionSuspended: 'Bu seçim şu anda bahse kapalı.',\n excludedSuspended: (n) => `${n} askıya alınmış fiyat bu grafikten hariç tutuldu.`,\n chartTimeLabel: (ms) =>\n new Intl.DateTimeFormat('tr-TR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(ms)),\n chartAria: (opening, current, direction, hours) => {\n const span = hours % 24 === 0 ? `${hours / 24} gün` : `${hours} saat`\n const drift = direction ? `, ${direction}` : ''\n return `Son ${span} içindeki oran hareketi: ${opening} ile açıldı, şu anda ${current}${drift}.`\n },\n inSlip: 'Kuponda',\n slipAdded: 'Kupona eklendi',\n slipDuplicate: 'Bu seçim kuponunuzda zaten var',\n slipPriceChanged: (from, to) => `${to} oranıyla eklendi (önceki ${from})`,\n slipPriceNotAccepted: (from, to) => `Oran ${to} oldu (önceki ${from}). Eklemek için dokunun.`,\n slipLoginRequired: 'Kupona eklemek için giriş yapın',\n slipSuspended: 'Bu market askıya alındı',\n slipFailed: 'Kupona eklenemedi. Tekrar deneyin.',\n today: 'Bugün',\n tomorrow: 'Yarın',\n bettingKickoff: (kickoffUtc, now) => formatBettingKickoff(kickoffUtc, STRINGS.tr, 'tr', now),\n tabChat: 'Sohbet',\n tabFollowing: 'Takip',\n tabOdds: 'Oranlar',\n pinLabel: 'Oranı takip et',\n unpinLabel: 'Oran takibini bırak',\n matchPinLabel: 'Maçı takip et',\n matchUnpinLabel: 'Maç takibini bırak',\n matchLimitToast: 'Maç limiti dolu — önce bir maçı kaldır',\n marketLimitToast: 'Oran limiti dolu — önce birini kaldır',\n emptyMatchesTab: 'Henüz sabitlenmiş maç yok. Canlı takip için sohbetteki bir maçı sabitle.',\n emptyOddsTab: 'Henüz sabitlenmiş oran yok. Canlı takip için sohbetteki bir marketi sabitle.',\n asOf: (time) => `Fiyatlar ${time} itibarıyla`,\n graceNote: 'Bir sonraki açılışta kaldırılır · en geç 4 saat',\n suspendedLabel: 'Askıda',\n fullTimeLabel: 'Maç sonu',\n ownGoalLabel: 'KK',\n inSlipLabel: 'Kuponda',\n oddsUnavailable: 'Oranlar şu anda kullanılamıyor',\n momentumLabel: 'Momentum',\n accordionValueLabel: 'Değer',\n accordionRetry: 'Oranlar yüklenemedi — yeniden dene',\n accordionSuspended: 'Askıda',\n tabToday: 'Bugün',\n sectionLive: 'Canlı',\n halfTime: 'İY',\n staleStates: 'Canlı skorlar güncellenemiyor — son bilinen durum gösteriliyor.',\n tabGames: 'Oyunlar',\n tabLeaderboard: 'Lider Tablosu',\n gamesLoginRequired: 'Oynamak ve lider tablosuna girmek için giriş yapın',\n back: 'Geri',\n leaderboardOffBoard: 'İlk 50 dışında',\n leaderboardThisWeek: 'Bu hafta',\n leaderboardAllTime: 'Tüm zamanlar',\n leaderboardEmptyFreshTitle: 'Yeni hafta, temiz sayfa',\n leaderboardEmptyFreshBody: 'Henüz skor yok. Oynayan ilk taraftar 1. sıraya geçer.',\n leaderboardEmptyColdTitle: 'İlk sen ol',\n leaderboardEmptyColdBody: 'Panoda henüz kimse yok. Bir oyun oyna, 1. sıra senin.',\n leaderboardEmptyCta: 'Bugünün oyunlarını oyna',\n leaderboardLastWeekLabel: 'Geçen hafta',\n leaderboardAllTimeEmpty: 'Tüm zamanlar panosu taraftarlar oynadıkça dolar — henüz bir şey yok.',\n gamePlay: 'Oyna',\n gameLocked: 'Kilitli',\n gameVoided: 'İptal edildi',\n games: {\n lang: 'tr',\n dailyChallenge: 'Günün meydan okuması',\n playNow: 'Hemen oyna',\n dailyGames: 'Günlük oyunlar',\n newSetAtMidnight: 'Yeni set gece yarısı',\n matchdayGames: 'Maç günü oyunları',\n kickoffAt: (t) => `Başlama ${t}`,\n statStreak: 'Seri',\n statToday: 'Bugün',\n statRank: 'Sıra',\n unitDays: 'gün',\n unitPts: 'puan',\n thisWeek: 'bu hafta',\n newToday: 'Bugün yeni',\n resume: 'Devam et',\n done: 'Tamamlandı',\n doneWithScore: (s) => `Tamamlandı · +${formatPtsTr(s)}`,\n locksAt: (t) => `Kilit ${t}`,\n formatPts: formatPtsTr,\n loading: 'Yükleniyor…',\n backToGames: 'Oyunlara dön',\n alreadyPlayedTitle: 'Bugün oynadın',\n guess: 'Tahmin',\n formatDayTime: (iso) =>\n new Intl.DateTimeFormat('tr-TR', { weekday: 'short', hour: '2-digit', minute: '2-digit' }).format(new Date(iso)),\n taglines: {\n 'mystery-tiger': 'Bir oyuncu. Altı tahmin.',\n 'higher-or-lower': 'Kimin daha fazlası var?',\n 'guess-the-xi': 'Takımı bil',\n 'daily-quiz': 'Kulüp bilgini sına',\n 'career-path': 'Kulüpleri takip et',\n 'beat-the-grid': '9 hücreyi doldur',\n 'matchday-predictor': 'Skoru tahmin et',\n 'starting-xi': 'İlk 11’i seç',\n 'stat-ladder': 'Eksik basamağı bul',\n 'fan-motm': 'Maç sonunda oy ver',\n },\n mysteryTiger: {\n eyebrow: 'Günlük · 00:00’da yenilenir',\n labels: { position: 'POZ', nationality: 'UYR', age: 'YAŞ', shirtNumber: 'NO.', apps: 'MAÇ' },\n yourGuesses: 'Tahminlerin',\n legendMatch: 'Eşleşme',\n legendClose: 'Yakın',\n legendHigher: 'Gizli oyuncu daha yüksek',\n searchLabel: 'Kadrodan bir oyuncu tahmin et',\n searchPlaceholder: 'İsimle ara',\n optionsLabel: 'Kadro oyuncuları',\n progress: (used, total) => `${total} tahminden ${used} kullanıldı`,\n solved: 'Buldun!',\n failed: 'Tahmin hakkın bitti',\n detail: (n) => `${n} tahmin · yarın yine gel`,\n },\n higherOrLower: {\n eyebrow: (p) => `Doğru başına +${p}`,\n streak: 'Seri',\n whoHadMore: 'Kimin daha fazlası var',\n season: (l) => `${l} sezonu`,\n higher: 'Daha fazla',\n lower: 'Daha az',\n vs: 'VS',\n lastAnswer: (name, value) => `${name}: ${value}`,\n answersSoFar: (a, total) => `${total} eşleşmeden ${a} yanıtlandı`,\n runOver: 'Seri bitti',\n perfectRun: 'Kusursuz seri!',\n runDetail: (c) => `Üst üste ${c} doğru · yarın yine gel`,\n },\n guessTheXi: {\n pitchLabel: 'Uyruklara göre ilk 11',\n notThem: 'Bunlar değil:',\n whichClub: (left) => `Bu hangi kulüp? · ${left} hak kaldı`,\n searchPlaceholder: 'Kulüp ara',\n optionsLabel: 'Kulüpler',\n solved: 'Bildin!',\n failed: 'Tahmin hakkın bitti',\n detail: (n) => `${n} tahmin · yarın yine gel`,\n },\n dailyQuiz: {\n questionOf: (i, n) => `Soru ${i} / ${n}`,\n results: 'Sonuçlar',\n next: 'İleri',\n previous: 'Önceki',\n submit: 'Gönder',\n submitting: 'Gönderiliyor…',\n correctOf: (c, n) => `${n} soruda ${c} doğru`,\n progressAria: (i, n) => `Soru ${i} / ${n}`,\n },\n careerPath: {\n eyebrow: 'En eski kulüp önce',\n mysteryPlayer: 'Gizemli oyuncu',\n lockPosition: 'Mevki',\n lockNationality: 'Uyruk',\n firstClub: 'İlk kulüp',\n loan: 'Kiralık',\n nextClubHidden: 'Sıradaki kulüp — yanlış tahminden sonra açılır',\n moreClubs: (k) => `+ ${k} kulüp daha`,\n searchLabel: 'Bu kim?',\n searchPlaceholder: 'Herhangi bir oyuncu ara',\n solved: 'Kariyer çözüldü!',\n failed: 'Tahmin hakkın bitti',\n guessesLine: (n) => `${n} tahmin · yarın tekrar gel`,\n },\n beatTheGrid: {\n eyebrow: 'Her hücreye uyan bir oyuncu yerleştir',\n filled: (n, t) => `${t} hücreden ${n} dolu`,\n toGo: (n) => `${n} kaldı`,\n progressAria: (n, t) => `${t} hücreden ${n} dolu`,\n rowAbbrev: { Goalkeeper: 'KL', Defender: 'DEF', Midfielder: 'OS', Forward: 'FV' },\n pickCell: (r, c) => `${r} × ${c} için oyuncu seç`,\n cellFilled: (r, c, name, verdict) => `${r} × ${c}: ${name}, ${verdict.toLocaleLowerCase('tr')}`,\n correct: 'Doğru',\n wrong: 'Yanlış',\n closeSearch: 'Oyuncu aramayı kapat',\n searchLabel: (r, c) => `${r} × ${c} için oyuncu ara`,\n searchPlaceholder: 'Oyuncu ara',\n emptyPool: 'Henüz aranacak oyuncu yok.',\n complete: 'Tablo tamamlandı',\n summary: (c, f) => `${f} hücrede ${c} doğru · yarın tekrar gel`,\n },\n predictor: {\n eyebrow: (home, away) => `${home} - ${away}`,\n home: 'Ev sahibi',\n away: 'Deplasman',\n goalsUp: (team) => `${team} golünü artır`,\n goalsDown: (team) => `${team} golünü azalt`,\n firstScorer: 'İlk golü atan',\n optional: 'İsteğe bağlı',\n searchLabel: 'İlk golcüyü ara',\n searchPlaceholder: 'Kadroda ara',\n noScorer: 'İlk gol yok',\n save: 'Tahmini kaydet',\n saving: 'Kaydediliyor…',\n closed: 'Tahminler kapandı',\n saved: 'Tahmin kaydedildi',\n savedDetail: (p) =>\n `${p.home ? `${p.home} ` : ''}${p.h}–${p.a}${p.away ? ` ${p.away}` : ''}${p.scorer ? ` · ilk gol ${p.scorer}` : ''} · sonuç bekleniyor`,\n fullTime: (h, a) => `Maç sonu ${h} – ${a}`,\n exactScore: 'Tam skor',\n outcome: 'Sonuç (G/B/M)',\n firstScorerRow: 'İlk golü atan',\n correct: 'Doğru',\n incorrect: 'Yanlış',\n forFun: 'Eğlence için — sıralamaya girmez',\n },\n startingXi: {\n eyebrow: 'Kadroyu tahmin et',\n perStarter: (n) => `İlk 11 oyuncu başına +${n}`,\n picked: (n) => `11 oyuncudan ${n} seçildi`,\n toGo: (n) => `${n} kaldı`,\n pickSlot: (pos) => `${pos} seç`,\n clearSlot: (pos, name) => `${name} oyuncusunu ${pos} mevkiinden çıkar`,\n pickFor: (pos) => `${pos} için oyuncu seç`,\n allPicked: '11 oyuncu seçildi — değiştirmek için sahadaki oyuncuya dokun',\n searchLabel: 'Kadroda ara',\n submit: 'İlk 11’imi kilitle',\n submitting: 'Gönderiliyor…',\n locksAt: (t) => `${t} kilitlenir, başlamadan yaklaşık bir saat önce`,\n locksSoon: 'Başlamadan yaklaşık bir saat önce kilitlenir',\n pending: (n) => `Tahmin kilitlendi (${n} oyuncu) — sonuç bekleniyor`,\n gradedLine: (c) => `11 oyuncudan ${c} doğru`,\n voided: 'Bu oyun iptal edildi',\n },\n motm: {\n title: 'Maçın Oyuncusu',\n eyebrow: 'Taraftar oylaması',\n voted: 'Oy verildi',\n yourVote: 'Oy verdiğin',\n youVoted: (name) => `${name} için oy verdin`,\n thanks: 'Teşekkürler — bu oylamanın sonuçları gösterilmiyor',\n tapToVote: 'Oy vermek için bir oyuncuya dokun',\n forFun: 'Eğlence için — sıralamaya girmeyen taraftar oylaması',\n },\n statLadder: {\n eyebrow: 'Son maç',\n question: (stat) => ({ pre: `${stat.toLocaleLowerCase('tr')} sıralamasında `, emph: '2. sırada', post: ' kim var?' }),\n whoSecond: '2. kim?',\n clue: (c, stat) => {\n const parts: string[] = []\n if (c.above) parts.push(c.above.diff === 0 ? `${c.above.name} ile aynı` : `${c.above.name} oyuncusundan ${c.above.diff} eksik`)\n if (c.below) parts.push(c.below.diff === 0 ? `${c.below.name} ile aynı` : `${c.below.name} oyuncusundan ${c.below.diff} fazla`)\n return `${c.value} ${stat.toLocaleLowerCase('tr')}${parts.length ? `: ${parts.join(' ve ')}` : ''}.`\n },\n searchLabel: '2. oyuncuyu tahmin et',\n searchPlaceholder: 'Kadroda ara',\n guess: 'Tahmin et',\n correct: 'Doğru!',\n wrong: (name) => `Yanlış — doğru cevap ${name}`,\n },\n },\n },\n}\n\nexport function resolveLocaleStrings(locale?: string): LocaleStrings {\n return STRINGS[locale as Locale] ?? STRINGS.en\n}\n","import type { AddToSlipHandler, StatsWidgetClientOptions, UserContext } from '@sensiblestats/widget-sdk'\nimport { resolveLocaleStrings } from './i18n'\nimport type { GamesStrings } from './i18n'\n\nexport interface StatsWidgetConfig {\n operatorId: string\n publicKey: string\n baseUrl?: string\n userContext?: UserContext\n theme?: 'light' | 'dark' | 'auto'\n accent?: string\n position?: 'left' | 'right'\n offset?: { x?: number; y?: number }\n radius?: number\n /** BCP-47-ish locale code for the widget's own chrome text (e.g. \"en\", \"tr\"). Defaults to \"en\". */\n locale?: string\n launcherLabel?: string\n greeting?: string\n /** Message auto-sent once on load (e.g. \"hello\"); its response shows as the launcher popup. */\n greetingMessage?: string\n placeholder?: string\n starters?: string[]\n injectStyles?: boolean\n /** Called when the user adds an insight's selection to the operator's slip. */\n onAddToSlip?: AddToSlipHandler\n\n // — Branding —\n /** Operator logo; replaces the SS mark in the header and the FAB launcher. */\n logoUrl?: string\n /** Header title text. Default \"SensibleStats\". */\n headerTitle?: string\n /** CTA color → --ss-w-cta. */\n cta?: string\n /** Panel/surface color → --ss-w-panel. Pair with `ink`. */\n surface?: string\n /** Primary text color → --ss-w-ink. Pair with `surface`. */\n ink?: string\n /** Icon used for the pin/save toggle on matches and odds. Default \"pin\". */\n pinIcon?: 'pin' | 'star' | 'bookmark'\n}\n\ntype UiKeys =\n | 'theme' | 'accent' | 'position' | 'offset' | 'radius' | 'locale'\n | 'launcherLabel' | 'greeting' | 'greetingMessage' | 'placeholder' | 'starters' | 'injectStyles'\n | 'logoUrl' | 'headerTitle' | 'cta' | 'surface' | 'ink' | 'pinIcon'\n\nexport interface UiConfig {\n theme: 'light' | 'dark' | 'auto'\n accent?: string\n position: 'left' | 'right'\n offset: { x: number; y: number }\n radius: number\n launcherLabel: string\n greeting?: string\n greetingMessage?: string\n placeholder: string\n starters: string[]\n injectStyles: boolean\n logoUrl?: string\n headerTitle?: string\n cta?: string\n surface?: string\n ink?: string\n pinIcon: 'pin' | 'star' | 'bookmark'\n closeChat: string\n newConversation: string\n moreOptions: string\n chatDialogLabel: string\n stopResponse: string\n sendMessage: string\n dismissGreeting: string\n somethingWentWrong: string\n retry: string\n showLess: string\n showMore: (n: number) => string\n showStats: string\n hideStats: string\n oddsLabel: string\n liveLabel: string\n marketFloorLabel: string\n marketPrices: string\n moreLines: string\n hideLines: string\n oddsMoved: (was: string, now: string, direction: string) => string\n oddsShortened: string\n oddsDrifted: string\n updatedLabel: string\n priceMovement: string\n openingLabel: string\n currentLabel: string\n movementWindow: (hours: number) => string\n notEnoughHistory: string\n singlePricePoint: string\n selectionSuspended: string\n excludedSuspended: (n: number) => string\n chartTimeLabel: (ms: number) => string\n chartAria: (opening: string, current: string, direction: string, hours: number) => string\n addToSlip: string\n inSlip: string\n slipAdded: string\n slipDuplicate: string\n slipPriceChanged: (from: string, to: string) => string\n slipPriceNotAccepted: (from: string, to: string) => string\n slipLoginRequired: string\n slipSuspended: string\n slipFailed: string\n today: string\n tomorrow: string\n bettingKickoff: (kickoffUtc: string, now?: Date) => { dayLabel: string; time: string }\n tabChat: string\n tabFollowing: string\n tabOdds: string\n tabToday: string\n sectionLive: string\n halfTime: string\n staleStates: string\n pinLabel: string\n unpinLabel: string\n matchPinLabel: string\n matchUnpinLabel: string\n matchLimitToast: string\n marketLimitToast: string\n emptyMatchesTab: string\n emptyOddsTab: string\n asOf: (time: string) => string\n graceNote: string\n suspendedLabel: string\n fullTimeLabel: string\n ownGoalLabel: string\n inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: string\n tabGames: string\n tabLeaderboard: string\n gamesLoginRequired: string\n back: string\n leaderboardOffBoard: string\n leaderboardThisWeek: string\n leaderboardAllTime: string\n leaderboardEmptyFreshTitle: string\n leaderboardEmptyFreshBody: string\n leaderboardEmptyColdTitle: string\n leaderboardEmptyColdBody: string\n leaderboardEmptyCta: string\n leaderboardLastWeekLabel: string\n leaderboardAllTimeEmpty: string\n gamePlay: string\n gameLocked: string\n gameVoided: string\n games: GamesStrings\n}\n\nexport function normalizeUi(cfg: Pick<StatsWidgetConfig, UiKeys>): UiConfig {\n const strings = resolveLocaleStrings(cfg.locale)\n return {\n theme: cfg.theme ?? 'auto',\n accent: cfg.accent,\n logoUrl: cfg.logoUrl,\n headerTitle: cfg.headerTitle,\n cta: cfg.cta,\n surface: cfg.surface,\n ink: cfg.ink,\n pinIcon: cfg.pinIcon ?? 'pin',\n position: cfg.position ?? 'right',\n offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },\n radius: cfg.radius ?? 16,\n launcherLabel: cfg.launcherLabel ?? strings.launcherLabel,\n greeting: cfg.greeting,\n greetingMessage: cfg.greetingMessage,\n placeholder: cfg.placeholder ?? strings.placeholder,\n starters: cfg.starters ?? [],\n injectStyles: cfg.injectStyles ?? true,\n closeChat: strings.closeChat,\n newConversation: strings.newConversation,\n moreOptions: strings.moreOptions,\n chatDialogLabel: strings.chatDialogLabel,\n stopResponse: strings.stopResponse,\n sendMessage: strings.sendMessage,\n dismissGreeting: strings.dismissGreeting,\n somethingWentWrong: strings.somethingWentWrong,\n retry: strings.retry,\n showLess: strings.showLess,\n showMore: strings.showMore,\n showStats: strings.showStats,\n hideStats: strings.hideStats,\n oddsLabel: strings.oddsLabel,\n liveLabel: strings.liveLabel,\n marketFloorLabel: strings.marketFloorLabel,\n marketPrices: strings.marketPrices,\n moreLines: strings.moreLines,\n hideLines: strings.hideLines,\n oddsMoved: strings.oddsMoved,\n oddsShortened: strings.oddsShortened,\n oddsDrifted: strings.oddsDrifted,\n updatedLabel: strings.updatedLabel,\n priceMovement: strings.priceMovement,\n openingLabel: strings.openingLabel,\n currentLabel: strings.currentLabel,\n movementWindow: strings.movementWindow,\n notEnoughHistory: strings.notEnoughHistory,\n singlePricePoint: strings.singlePricePoint,\n selectionSuspended: strings.selectionSuspended,\n excludedSuspended: strings.excludedSuspended,\n chartTimeLabel: strings.chartTimeLabel,\n chartAria: strings.chartAria,\n addToSlip: strings.addToSlip,\n inSlip: strings.inSlip,\n slipAdded: strings.slipAdded,\n slipDuplicate: strings.slipDuplicate,\n slipPriceChanged: strings.slipPriceChanged,\n slipPriceNotAccepted: strings.slipPriceNotAccepted,\n slipLoginRequired: strings.slipLoginRequired,\n slipSuspended: strings.slipSuspended,\n slipFailed: strings.slipFailed,\n today: strings.today,\n tomorrow: strings.tomorrow,\n bettingKickoff: strings.bettingKickoff,\n tabChat: strings.tabChat,\n tabFollowing: strings.tabFollowing,\n tabOdds: strings.tabOdds,\n tabToday: strings.tabToday,\n sectionLive: strings.sectionLive,\n halfTime: strings.halfTime,\n staleStates: strings.staleStates,\n pinLabel: strings.pinLabel,\n unpinLabel: strings.unpinLabel,\n matchPinLabel: strings.matchPinLabel,\n matchUnpinLabel: strings.matchUnpinLabel,\n matchLimitToast: strings.matchLimitToast,\n marketLimitToast: strings.marketLimitToast,\n emptyMatchesTab: strings.emptyMatchesTab,\n emptyOddsTab: strings.emptyOddsTab,\n asOf: strings.asOf,\n graceNote: strings.graceNote,\n suspendedLabel: strings.suspendedLabel,\n fullTimeLabel: strings.fullTimeLabel,\n ownGoalLabel: strings.ownGoalLabel,\n inSlipLabel: strings.inSlipLabel,\n oddsUnavailable: strings.oddsUnavailable,\n momentumLabel: strings.momentumLabel,\n accordionValueLabel: strings.accordionValueLabel,\n accordionRetry: strings.accordionRetry,\n accordionSuspended: strings.accordionSuspended,\n tabGames: strings.tabGames,\n tabLeaderboard: strings.tabLeaderboard,\n gamesLoginRequired: strings.gamesLoginRequired,\n back: strings.back,\n leaderboardOffBoard: strings.leaderboardOffBoard,\n leaderboardThisWeek: strings.leaderboardThisWeek,\n leaderboardAllTime: strings.leaderboardAllTime,\n leaderboardEmptyFreshTitle: strings.leaderboardEmptyFreshTitle,\n leaderboardEmptyFreshBody: strings.leaderboardEmptyFreshBody,\n leaderboardEmptyColdTitle: strings.leaderboardEmptyColdTitle,\n leaderboardEmptyColdBody: strings.leaderboardEmptyColdBody,\n leaderboardEmptyCta: strings.leaderboardEmptyCta,\n leaderboardLastWeekLabel: strings.leaderboardLastWeekLabel,\n leaderboardAllTimeEmpty: strings.leaderboardAllTimeEmpty,\n gamePlay: strings.gamePlay,\n gameLocked: strings.gameLocked,\n gameVoided: strings.gameVoided,\n games: strings.games,\n }\n}\n\nexport function toClientOptions(cfg: StatsWidgetConfig): StatsWidgetClientOptions {\n const opts: StatsWidgetClientOptions = { operatorId: cfg.operatorId, publicKey: cfg.publicKey }\n if (cfg.baseUrl !== undefined) opts.baseUrl = cfg.baseUrl\n return opts\n}\n\nexport function toUserContext(cfg: StatsWidgetConfig): UserContext | undefined {\n return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : undefined\n}\n","import type { AddToSlipHandler, AddToSlipResult } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from './config'\n\nexport const ADD_TO_SLIP_TIMEOUT_MS = 10_000\n\nexport interface SlipToast { kind: 'success' | 'error'; text: string }\n\nexport interface SlipHandlerProps {\n onAddToSlip?: AddToSlipHandler\n conversationId?: string\n onMarketClicked?: (marketName: string) => void\n}\n\nexport function wasAdded(result: AddToSlipResult | void): boolean {\n if (!result) return true\n if (result.status === 'price_changed') return result.accepted\n return result.status === 'added'\n}\n\nexport function isTerminal(result: AddToSlipResult | void): boolean {\n if (!result) return true\n if (result.status === 'price_changed') return result.accepted\n return result.status === 'added' || result.status === 'duplicate'\n}\n\n// slip_result's `outcome`: 'added' on success (including the assumed-success void/duplicate/\n// accepted-price-change cases), else the specific reject reason string -- so a downstream\n// consumer can tell \"the user added it\" from \"why it was refused\" without re-deriving toast text.\nexport function slipOutcome(result: AddToSlipResult | void): string {\n if (!result) return 'added'\n switch (result.status) {\n case 'added':\n case 'duplicate':\n return result.status\n case 'price_changed':\n return result.accepted ? 'added' : 'price_changed'\n case 'rejected':\n return result.reason\n }\n}\n\nexport function resultToToast(result: AddToSlipResult | void, shownOdds: string, ui: UiConfig): SlipToast {\n if (!result) return { kind: 'success', text: ui.slipAdded }\n switch (result.status) {\n case 'added':\n return { kind: 'success', text: ui.slipAdded }\n case 'duplicate':\n return { kind: 'success', text: ui.slipDuplicate }\n case 'price_changed':\n return result.accepted\n ? { kind: 'success', text: ui.slipPriceChanged(shownOdds, result.newOddsDecimal.toFixed(2)) }\n : { kind: 'error', text: ui.slipPriceNotAccepted(shownOdds, result.newOddsDecimal.toFixed(2)) }\n case 'rejected':\n if (result.reason === 'login_required') return { kind: 'error', text: ui.slipLoginRequired }\n if (result.reason === 'suspended') return { kind: 'error', text: ui.slipSuspended }\n return { kind: 'error', text: result.message ?? ui.slipFailed }\n }\n}\n","import { ENTITY_TYPE_CODES, type Conversation, type EventLogger, type GreetingDashboardLayout, type GreetingDashboardTile, type SignalEntityType, type WidgetEntityType } from '@sensiblestats/widget-sdk'\n\nexport type DashboardTapHandler = (tile: GreetingDashboardTile, index: number, layout: GreetingDashboardLayout) => void\n\n// tile.signal.entityType is a plain string on the wire (GreetingDashboardSignalRef), so a value\n// outside the union must be checked, not asserted -- an unchecked cast would let an unrecognised\n// value reach toSignalWireBody, which throws synchronously and is swallowed by the try/catch\n// below, silently dropping the tap the same way an unresolved entityId used to.\nfunction isSignalEntityType(value: string): value is SignalEntityType {\n return Object.prototype.hasOwnProperty.call(ENTITY_TYPE_CODES, value)\n}\n\n// The server's GreetingDashboardSignalRef.entityType is PascalCase ('Team', 'Market', ...) and\n// carries a couple of values (Article/Session/Query/Conversation) that have no widget-event\n// counterpart -- those, and anything unrecognised, map to null so the caller can skip the emit\n// instead of sending a bogus entityType.\nfunction toWidgetEntityType(value: string): WidgetEntityType | null {\n switch (value.toLowerCase()) {\n case 'match': return 'match'\n case 'team': return 'team'\n case 'player': return 'player'\n case 'competition': return 'competition'\n case 'market': return 'market'\n default: return null\n }\n}\n\n/**\n * Builds the tap-to-signal side effect for a greeting dashboard tile.\n * Every tap is a MarketView signal (spec 9.4) regardless of the tile's own entity type --\n * entityType/entityId identify what was tapped, dashboardLayout/tileIndex identify where.\n *\n * `log` is threaded in as a parameter (not read via `useEventLog()`) because this module is a\n * plain factory, not a component or hook -- the caller (a component) owns the logger instance.\n */\nexport function createDashboardTapSignal(sendSignal: Conversation['sendSignal'], log?: EventLogger | null): DashboardTapHandler {\n return (tile, index, layout) => {\n const widgetEntityType = toWidgetEntityType(tile.signal.entityType)\n if (widgetEntityType) {\n log?.log({ name: 'tile_tap', entityType: widgetEntityType, entityId: tile.signal.entityId })\n }\n if (!isSignalEntityType(tile.signal.entityType)) return\n // sendSignal throws synchronously with no identity configured, and its returned promise\n // can reject on a gateway failure. Neither may break the tap -- the message this tile sent\n // still has to reach the model even when the Interest Engine can't be reached.\n try {\n void sendSignal({\n signalType: 'MarketView',\n entityType: tile.signal.entityType,\n entityId: tile.signal.entityId,\n dashboardLayout: layout,\n tileIndex: index,\n }).catch(() => undefined)\n } catch {\n // ignored -- see comment above\n }\n }\n}\n","import type { UiConfig } from './config'\n\nexport interface ThemeAttrs {\n 'data-ss-w-theme': string\n 'data-ss-w-pos': string\n style: Record<string, string>\n}\n\nexport function themeAttrs(ui: UiConfig): ThemeAttrs {\n const style: Record<string, string> = {\n '--ss-w-offset-x': `${ui.offset.x}px`,\n '--ss-w-offset-y': `${ui.offset.y}px`,\n '--ss-w-radius': `${ui.radius}px`,\n }\n if (ui.accent) style['--ss-w-accent'] = ui.accent\n if (ui.cta) style['--ss-w-cta'] = ui.cta\n if (ui.surface) style['--ss-w-panel'] = ui.surface\n if (ui.ink) style['--ss-w-ink'] = ui.ink\n if (ui.surface && ui.ink) {\n style['--ss-w-bubble'] = 'color-mix(in srgb, var(--ss-w-ink) 5%, var(--ss-w-panel))'\n style['--ss-w-line'] = 'color-mix(in srgb, var(--ss-w-ink) 12%, var(--ss-w-panel))'\n style['--ss-w-faint'] = 'color-mix(in srgb, var(--ss-w-ink) 55%, var(--ss-w-panel))'\n }\n return { 'data-ss-w-theme': ui.theme, 'data-ss-w-pos': ui.position, style }\n}\n","import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'\nimport type { ChatHandle, ChatInput, Conversation } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { reducer, initialState, type WidgetState, type AssistantTurn } from './reducer'\nimport { chipFromText } from './model'\nimport { useLiveDashboardPoll } from './useLiveDashboardPoll'\nimport { readConversation, writeConversation, clearConversation } from './conversationStore'\n\n// An assistant turn counts as an answer only if it carries something to show. Deliberately\n// excludes `actions` -- follow-up chips are not answer content, so an errored turn that only\n// has fallback chips must not count as answered.\nfunction hasAnswerContent(t: AssistantTurn): boolean {\n return !!t.text || t.cards.length > 0 || t.insights.length > 0 ||\n t.marketOdds.length > 0 || t.oddsMovement.length > 0 ||\n !!t.greetingDashboard || !!t.clubFanDashboard\n}\n\n// If the server never emits a terminal event (turn_complete/error) within this window, the\n// panel would otherwise spin forever -- an async generator that just ends without yielding a\n// terminal event leaves isStreaming stuck at true, since only turn_complete/error/STOP clear it.\nexport const STREAM_FALLBACK_TIMEOUT_MS = 30_000\n\n// Next id must not collide with restored m{n} ids (React keys + live-dashboard id matching).\nfunction seedIdCounter(messages: { id: string }[]): number {\n let max = -1\n for (const m of messages) {\n const n = Number(m.id.slice(1)) // ids are `m${n}`\n if (m.id[0] === 'm' && Number.isFinite(n) && n > max) max = n\n }\n return max + 1\n}\n\nexport interface SendOptions {\n actionId?: string\n /** Opaque predefined-action-contract ref (e.g. a club-dashboard tap) — forwarded on ChatInput.actionRef. */\n actionRef?: string\n /** Text shown in the user bubble when it differs from the message sent upstream (e.g. an action's label). */\n displayText?: string\n}\n\nexport interface ChatController {\n state: WidgetState\n open(): void\n close(): void\n stop(): void\n toggle(): void\n send(text: string, opts?: SendOptions): void\n retry(): void\n dismissPopup(): void\n reset(): void\n}\n\nexport function useChatStream(conversation: Conversation, starterTexts: string[], greetingMessage?: string, storageKey?: string): ChatController {\n const boot = useMemo(() => {\n const payload = storageKey ? readConversation(storageKey, Date.now()) : null\n const restored = payload != null && payload !== 'expired' && payload !== 'corrupt'\n const base = initialState(starterTexts.map(chipFromText))\n if (restored) {\n return { state: { ...base, messages: payload.messages, conversationId: payload.conversationId, starters: [] }, restored: true, stale: false }\n }\n return { state: base, restored: false, stale: payload === 'expired' || payload === 'corrupt' }\n }, [])\n const [state, dispatch] = useReducer(reducer, boot.state)\n const idRef = useRef(seedIdCounter(boot.state.messages))\n const handleRef = useRef<ChatHandle | null>(null)\n const fallbackTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const stateRef = useRef(state)\n stateRef.current = state\n const greetedRef = useRef(boot.restored) // restored -> greeting already \"handled\" (suppressed)\n const hydratedRef = useRef(false) // suppresses the single re-persist a cross-tab sync would echo\n\n const restoreSeededRef = useRef(false)\n if (!restoreSeededRef.current) {\n restoreSeededRef.current = true\n if (boot.restored && boot.state.conversationId) conversation.conversationId = boot.state.conversationId\n }\n\n const nextId = () => `m${idRef.current++}`\n\n const clearFallbackTimer = useCallback(() => {\n if (fallbackTimerRef.current != null) {\n clearTimeout(fallbackTimerRef.current)\n fallbackTimerRef.current = null\n }\n }, [])\n\n // Arms a watchdog for one in-flight send. clearFallbackTimer() is called on every path that\n // supersedes this send (a newer run(), stop(), close()) or that sees a terminal event, so a\n // firing timer always means neither happened in time -- including the case where the async\n // generator simply ends without ever yielding turn_complete/error: consume()'s own `finally`\n // nulls handleRef as soon as that happens, so this cannot key off handle identity (it would\n // already look \"stale\" and the very hang it exists to catch would go unreported).\n const armFallbackTimer = useCallback((onFire: () => void) => {\n clearFallbackTimer()\n fallbackTimerRef.current = setTimeout(() => {\n fallbackTimerRef.current = null\n handleRef.current?.cancel()\n handleRef.current = null\n onFire()\n }, STREAM_FALLBACK_TIMEOUT_MS)\n }, [clearFallbackTimer])\n\n const consume = useCallback((handle: ChatHandle, onError: (err: WidgetSdkError) => void) => {\n ;(async () => {\n try {\n for await (const event of handle) {\n dispatch({ kind: 'EVENT', event })\n if (event.type === 'turn_complete' || event.type === 'error') clearFallbackTimer()\n }\n } catch (err) {\n // A superseded handle's late rejection (run() already cancelled it and armed a new\n // timer for the newer send) must not touch the current send's timer -- only clear here\n // when this handle is still the one in flight.\n if (handleRef.current === handle) clearFallbackTimer()\n if (err instanceof WidgetSdkError) onError(err)\n else if ((err as { name?: string } | null)?.name === 'AbortError') { /* expected on cancel/close — ignore */ }\n else throw err\n } finally {\n if (handleRef.current === handle) handleRef.current = null\n }\n })()\n }, [clearFallbackTimer])\n\n const run = useCallback((input: ChatInput, displayText?: string) => {\n handleRef.current?.cancel()\n clearFallbackTimer()\n dispatch({ kind: 'USER_SENT', input, userId: nextId(), assistantId: nextId(), displayText })\n const handle = conversation.send(input)\n handleRef.current = handle\n armFallbackTimer(() => {\n dispatch({ kind: 'STOP' })\n dispatch({ kind: 'STREAM_ERROR', error: new WidgetSdkError('No response received in time', 'timeout') })\n })\n consume(handle, (err) => dispatch({ kind: 'STREAM_ERROR', error: err }))\n }, [conversation, consume, clearFallbackTimer, armFallbackTimer])\n\n const send = useCallback((text: string, opts?: SendOptions) => {\n const trimmed = text.trim()\n if (!trimmed) return\n run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText)\n }, [run])\n\n const retry = useCallback(() => {\n const last = stateRef.current.lastUserInput\n if (last) run(last, stateRef.current.lastDisplayText ?? undefined)\n }, [run])\n\n // Auto-greeting: fire once on mount when configured (and not restored from storage). No\n // user bubble; its response becomes the launcher popup. Fire-and-forget — failures\n // (including a fallback timeout) are swallowed (STOP only, no visible error) since this is\n // non-critical background chatter. Also reused by reset() to re-greet after clearing.\n const fireGreeting = useCallback(() => {\n const message = greetingMessage?.trim()\n if (!message) return\n try {\n handleRef.current?.cancel()\n clearFallbackTimer()\n dispatch({ kind: 'GREETING_SENT', assistantId: nextId() })\n const handle = conversation.send({ message })\n handleRef.current = handle\n armFallbackTimer(() => dispatch({ kind: 'STOP' }))\n consume(handle, () => dispatch({ kind: 'STOP' }))\n } catch {\n dispatch({ kind: 'STOP' })\n }\n }, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer])\n\n useEffect(() => {\n if (greetedRef.current) return // restored, or already greeted\n greetedRef.current = true\n fireGreeting()\n }, [fireGreeting])\n\n // Clear a stale/corrupt blob once, from an effect (never during the render seed).\n useEffect(() => {\n if (boot.stale && storageKey) clearConversation(storageKey)\n }, [])\n\n // Persist only complete exchanges after each settle (never mid-stream, never the greeting).\n // A user message is kept only when its paired assistant turn (USER_SENT always pushes\n // [user, assistant] together) is done, non-greeting, and has real content -- this drops a\n // trailing unanswered question (panel closed mid-stream) and an empty errored bubble alike.\n useEffect(() => {\n if (!storageKey || state.isStreaming) return\n if (hydratedRef.current) { hydratedRef.current = false; return } // don't echo a sync back out\n const msgs = state.messages\n const persistable = msgs.filter((m, i) => {\n if (m.role === 'user') {\n const next = msgs[i + 1]\n return !!next && next.role === 'assistant' && next.done && !next.isGreeting && hasAnswerContent(next)\n }\n return m.done && !m.isGreeting && hasAnswerContent(m)\n })\n if (persistable.length === 0) return\n writeConversation(storageKey, state.conversationId, persistable, Date.now())\n }, [storageKey, state.isStreaming, state.messages, state.conversationId])\n\n // Live multi-tab sync: mirror another tab's write/clear of the shared conversation.\n useEffect(() => {\n if (!storageKey) return\n const onStorage = (e: StorageEvent) => {\n if (e.key !== storageKey || e.storageArea !== window.localStorage) return\n if (stateRef.current.isStreaming) return // never clobber an in-flight turn in this tab\n if (e.newValue == null) {\n // cleared elsewhere (New conversation / expiry) -> mirror a fresh conversation\n idRef.current = 0\n conversation.conversationId = undefined\n hydratedRef.current = true\n dispatch({ kind: 'RESET' })\n greetedRef.current = true\n fireGreeting()\n return\n }\n const parsed = readConversation(storageKey, Date.now())\n if (!parsed || parsed === 'expired' || parsed === 'corrupt') return\n idRef.current = seedIdCounter(parsed.messages)\n conversation.conversationId = parsed.conversationId ?? undefined\n hydratedRef.current = true\n dispatch({ kind: 'RESTORE', messages: parsed.messages, conversationId: parsed.conversationId })\n }\n window.addEventListener('storage', onStorage)\n return () => window.removeEventListener('storage', onStorage)\n }, [storageKey, conversation, fireGreeting])\n\n const open = useCallback(() => dispatch({ kind: 'OPEN' }), [])\n const close = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer(); dispatch({ kind: 'CLOSE' }) }, [clearFallbackTimer])\n const stop = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer(); dispatch({ kind: 'STOP' }) }, [clearFallbackTimer])\n const toggle = useCallback(() => { if (stateRef.current.isOpen) close(); else open() }, [close, open])\n const dismissPopup = useCallback(() => dispatch({ kind: 'DISMISS_POPUP' }), [])\n\n const reset = useCallback(() => {\n handleRef.current?.cancel(); handleRef.current = null; clearFallbackTimer()\n if (storageKey) clearConversation(storageKey)\n idRef.current = 0\n conversation.conversationId = undefined\n dispatch({ kind: 'RESET' })\n greetedRef.current = true\n fireGreeting()\n }, [storageKey, conversation, clearFallbackTimer, fireGreeting])\n\n const getLiveDashboard = useCallback(() => conversation.getLiveDashboard(), [conversation])\n useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard })\n\n return { state, open, close, stop, toggle, send, retry, dismissPopup, reset }\n}\n","import type { ChatEvent, ChatInput, ClubFanDashboardCard, ClubFanDashboardPayload, GreetingDashboard, StreamErrorEventData } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { toActionVM, toCardVM, toChipVM, toInsightVM, toMarketOddsVM, toOddsMovementVM, type ActionVM, type CardVM, type ChipVM, type InsightVM, type MarketOddsVM, type OddsMovementVM } from './model'\n\nexport interface UserMessage { role: 'user'; id: string; text: string }\nexport interface AssistantTurn { role: 'assistant'; id: string; text: string; cards: CardVM[]; actions: ActionVM[]; insights: InsightVM[]; marketOdds: MarketOddsVM[]; oddsMovement: OddsMovementVM[]; done: boolean; isGreeting?: boolean; greetingDashboard?: GreetingDashboard; clubFanDashboard?: ClubFanDashboardPayload }\nexport type Message = UserMessage | AssistantTurn\n\nexport interface WidgetState {\n isOpen: boolean\n messages: Message[]\n isStreaming: boolean\n status: string | null\n actionsLoading: boolean\n starters: ChipVM[]\n configuredStarters: ChipVM[]\n error: StreamErrorEventData | WidgetSdkError | null\n lastUserInput: ChatInput | null\n lastDisplayText: string | null\n // Launcher popup text (the auto-greeting response). Cleared on open/dismiss.\n popupText: string | null\n conversationId: string | null\n}\n\nexport type Action =\n | { kind: 'OPEN' }\n | { kind: 'CLOSE' }\n | { kind: 'USER_SENT'; input: ChatInput; userId: string; assistantId: string; displayText?: string }\n | { kind: 'GREETING_SENT'; assistantId: string }\n | { kind: 'EVENT'; event: ChatEvent }\n | { kind: 'STREAM_ERROR'; error: WidgetSdkError }\n | { kind: 'STOP' }\n | { kind: 'DISMISS_POPUP' }\n | { kind: 'LIVE_REFRESH'; messageId: string; cards: ClubFanDashboardCard[]; greeting?: string }\n | { kind: 'LIVE_TRANSITION'; messageId: string; dashboard: ClubFanDashboardPayload }\n | { kind: 'RESET' }\n | { kind: 'RESTORE'; messages: Message[]; conversationId: string | null }\n\nconst POPUP_MAX = 160\n\nexport function initialState(starters: ChipVM[]): WidgetState {\n return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, configuredStarters: starters, error: null, lastUserInput: null, lastDisplayText: null, popupText: null, conversationId: null }\n}\n\nfunction activeTurn(state: WidgetState): AssistantTurn | null {\n const last = state.messages[state.messages.length - 1]\n return last && last.role === 'assistant' && !last.done ? last : null\n}\n\nfunction mapActive(state: WidgetState, fn: (t: AssistantTurn) => AssistantTurn): Message[] {\n const last = state.messages[state.messages.length - 1]\n if (!last || last.role !== 'assistant' || last.done) return state.messages\n return [...state.messages.slice(0, -1), fn(last)]\n}\n\nfunction applyEvent(state: WidgetState, event: ChatEvent): WidgetState {\n switch (event.type) {\n case 'progress':\n return { ...state, status: event.data.message }\n case 'answer':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, text: event.data.text })) }\n case 'entity_card': {\n if (event.data.card.isUsed === false) return state\n const card = toCardVM(event.data.card)\n // Generic cards (coach/referee/stadium/competition — anything not team or\n // player) carry no distinct identity and add no user value; drop them until\n // a purpose-built variant exists.\n if (card.kind === 'generic') return state\n return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, card] })) }\n }\n case 'action_button':\n return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) }\n case 'betting_insight':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) }\n case 'market_odds':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, marketOdds: [...t.marketOdds, toMarketOddsVM(event.data.card)] })) }\n case 'odds_movement':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, oddsMovement: [...t.oddsMovement, toOddsMovementVM(event.data.card)] })) }\n case 'intent_chip': {\n const chip = toChipVM(event.data.intent)\n return chip ? { ...state, starters: [...state.starters, chip] } : state\n }\n case 'actions_loading':\n return { ...state, actionsLoading: true, status: event.data.message }\n case 'turn_complete': {\n const active = activeTurn(state)\n // A completed greeting turn surfaces its message as the launcher popup (unless already open).\n // The club fan dashboard carries its greeting line in the payload rather than as answer\n // text, so prefer that; fall back to any streamed answer text for other greeting shapes.\n const greetingLine = event.data.clubFanDashboard?.greeting?.trim() || (active?.text.trim() ?? '')\n const popupText = active?.isGreeting && !state.isOpen && greetingLine ? greetingLine.slice(0, POPUP_MAX) : state.popupText\n return {\n ...state, isStreaming: false, status: null, actionsLoading: false, popupText,\n conversationId: event.data.conversationId ?? state.conversationId,\n messages: mapActive(state, (t) => ({\n ...t,\n done: true,\n greetingDashboard: event.data.dashboard ?? undefined,\n clubFanDashboard: event.data.clubFanDashboard ?? undefined,\n })),\n }\n }\n case 'error': {\n // A failed greeting fails silently — it's non-critical background chatter.\n const suppress = activeTurn(state)?.isGreeting === true\n return { ...state, error: suppress ? state.error : event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n }\n }\n // Unknown/unmodelled event type: never return undefined — that would corrupt\n // state and crash the next dispatch. Ignore the event and keep state intact.\n return state\n}\n\nexport function reducer(state: WidgetState, action: Action): WidgetState {\n switch (action.kind) {\n case 'OPEN':\n return { ...state, isOpen: true, popupText: null }\n case 'CLOSE':\n return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false }\n case 'USER_SENT': {\n const user: UserMessage = { role: 'user', id: action.userId, text: action.displayText ?? action.input.message }\n const assistant: AssistantTurn = { role: 'assistant', id: action.assistantId, text: '', cards: [], actions: [], insights: [], marketOdds: [], oddsMovement: [], done: false }\n return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null }\n }\n case 'GREETING_SENT': {\n // Auto-greeting: no user bubble; the assistant turn is flagged so its completion sets the popup.\n const assistant: AssistantTurn = { role: 'assistant', id: action.assistantId, text: '', cards: [], actions: [], insights: [], marketOdds: [], oddsMovement: [], done: false, isGreeting: true }\n return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null }\n }\n case 'DISMISS_POPUP':\n return { ...state, popupText: null }\n case 'RESET':\n // Preserve panel open/closed state: \"New conversation\" is an in-panel control, so the\n // panel must stay open with the fresh greeting rather than snapping shut. Cross-tab\n // clear-mirroring likewise keeps each tab's panel as it was.\n return { ...initialState(state.configuredStarters), isOpen: state.isOpen }\n case 'RESTORE':\n return {\n ...state,\n messages: action.messages,\n conversationId: action.conversationId,\n isStreaming: false,\n status: null,\n actionsLoading: false,\n starters: action.messages.length ? [] : state.configuredStarters,\n error: null,\n }\n case 'EVENT':\n return applyEvent(state, action.event)\n case 'STREAM_ERROR':\n return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'STOP':\n return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'LIVE_REFRESH':\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.role === 'assistant' && m.id === action.messageId && m.clubFanDashboard\n ? { ...m, clubFanDashboard: { ...m.clubFanDashboard, cards: action.cards, greeting: action.greeting ?? m.clubFanDashboard.greeting } }\n : m,\n ),\n }\n case 'LIVE_TRANSITION':\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.role === 'assistant' && m.id === action.messageId && m.clubFanDashboard\n ? { ...m, clubFanDashboard: action.dashboard }\n : m,\n ),\n }\n }\n}\n","export interface ChartSample { atMs: number; price: number }\nexport interface ChartGeometry {\n path: string\n markers: { x: number; y: number }[]\n gridlines: { y: number; price: number }[]\n viewBox: string\n startMs: number\n endMs: number\n}\n\nexport const CHART_VIEW_W = 320\nexport const CHART_VIEW_H = 140\n\nconst PLOT_X0 = 40\nconst PLOT_X1 = 312\nconst PLOT_Y0 = 10\nconst PLOT_Y1 = 110\n\n// Point markers are drawn only on sparse series. Measured on sandbox1, the median chartable\n// series has TWO points: without markers a two-point chart is one bare diagonal that reads as a\n// rendering glitch rather than as data. Above this count the dots crowd the line and the shape\n// carries itself.\nconst MARKER_MAX_POINTS = 8\n\n// A flat series has no price range to scale against. Widening the domain by a fixed amount keeps\n// the line horizontal through the middle of the plot instead of dividing by zero.\nconst FLAT_DOMAIN_PAD = 0.05\n\nconst round2 = (n: number): number => Math.round(n * 100) / 100\n\nexport function projectSeries(samples: ChartSample[]): ChartGeometry | null {\n if (samples.length < 2) return null\n\n // noUncheckedIndexedAccess can't see that the length check above guarantees these exist.\n const tMin = samples[0]!.atMs\n const tMax = samples[samples.length - 1]!.atMs\n if (tMax <= tMin) return null\n\n const prices = samples.map((s) => s.price)\n const pMin = Math.min(...prices)\n const pMax = Math.max(...prices)\n\n let yMin: number\n let yMax: number\n if (pMax === pMin) {\n yMin = pMin - FLAT_DOMAIN_PAD\n yMax = pMax + FLAT_DOMAIN_PAD\n } else {\n const pad = (pMax - pMin) * 0.1\n yMin = pMin - pad\n yMax = pMax + pad\n }\n\n const x = (atMs: number): number =>\n round2(PLOT_X0 + ((atMs - tMin) / (tMax - tMin)) * (PLOT_X1 - PLOT_X0))\n const y = (price: number): number =>\n round2(PLOT_Y1 - ((price - yMin) / (yMax - yMin)) * (PLOT_Y1 - PLOT_Y0))\n\n const projected = samples.map((s) => ({ x: x(s.atMs), y: y(s.price) }))\n const path = projected.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`).join(' ')\n\n return {\n path,\n markers: samples.length <= MARKER_MAX_POINTS ? projected : [],\n // The real extremes, never the padded bounds: a gridline label is a price, and the padded\n // bounds are prices nobody was ever offered. A flat series has one real extreme, not two —\n // two identical gridlines would collide on both React key and rendered text.\n gridlines: pMax === pMin\n ? [{ y: y(pMax), price: pMax }]\n : [\n { y: y(pMax), price: pMax },\n { y: y(pMin), price: pMin },\n ],\n viewBox: `0 0 ${CHART_VIEW_W} ${CHART_VIEW_H}`,\n startMs: tMin,\n endMs: tMax,\n }\n}\n","import type { BettingInsight, EntityCard, MarketOddsCard, MarketOddsRow, OddsMovementCard, SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { ChartGeometry, ChartSample } from './chart'\nimport { projectSeries } from './chart'\n\nexport type CardKind = 'player' | 'team' | 'generic'\nexport interface StatCell { label: string; value: string }\nexport interface CardScope { competitionId: number | null; label: string; image?: string; stats: StatCell[] }\nexport interface CardVM { id: string; kind: CardKind; name: string; image?: string; sub?: string; season?: string; scopes: CardScope[] }\nexport interface ActionVM { label: string; actionId?: string; actionRef?: string; message: string }\nexport interface ChipVM { text: string }\nexport interface InsightScope { key: string; label: string; stats: StatCell[] }\nexport interface InsightVM {\n id: string\n market: string\n selection?: string\n odds?: string\n bookmaker?: string\n isLive: boolean\n phase?: string\n fixture?: string\n competition?: string\n scopes?: InsightScope[]\n text: string\n stats: StatCell[]\n disclaimer?: string\n matchId: number\n matchOddsId?: number\n marketDeveloperName?: string\n selectionLabel?: string\n line?: string\n addToSlipEnabled: boolean\n pinEnabled: boolean\n isMarketFloor: boolean\n oddsDecimal?: number\n quotedAtUtc?: string\n previousOdds?: string\n movementDirection?: 'shortened' | 'drifted'\n homeTeamName?: string\n awayTeamName?: string\n homeCrest?: string\n awayCrest?: string\n competitionCrest?: string\n kickoffUtc?: string\n kickoffLabel?: string\n}\n\nexport interface MarketOddsRowVM {\n key: string\n selection: string\n odds: string\n oddsDecimal?: number\n matchOddsId?: number\n quotedAtUtc?: string\n isMain: boolean\n isSuspended: boolean\n previousOdds?: string\n movementDirection?: 'shortened' | 'drifted'\n}\nexport interface MarketOddsVM {\n id: string\n market: string\n fixture?: string\n homeTeamName?: string\n awayTeamName?: string\n homeCrest?: string\n awayCrest?: string\n competitionCrest?: string\n competition?: string\n kickoffUtc?: string\n kickoffLabel?: string\n bookmaker?: string\n updatedAt?: string\n isLive: boolean\n matchId: number\n mainRows: MarketOddsRowVM[]\n moreRows: MarketOddsRowVM[]\n disclaimer?: string\n addToSlipEnabled: boolean\n marketDeveloperName?: string\n mainLine?: string\n pinEnabled: boolean\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\nfunction num(v: unknown): string | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? String(v) : undefined\n}\n\nfunction readStatCells(raw: unknown): StatCell[] {\n if (!Array.isArray(raw)) return []\n const cells: StatCell[] = []\n for (const entry of raw as Array<Record<string, unknown>>) {\n const label = str(entry.label)\n const value = num(entry.value) ?? str(entry.value)\n if (label !== undefined && value !== undefined) cells.push({ label, value })\n }\n return cells\n}\n\nexport function toCardVM(card: EntityCard): CardVM {\n const entityType = str(card.entityType)?.toLowerCase()\n const kind: CardKind = entityType === 'player' ? 'player' : entityType === 'team' ? 'team' : 'generic'\n const scopes = Array.isArray(card.scopes)\n ? (card.scopes as unknown as Array<Record<string, unknown>>)\n .map((s): CardScope | null => {\n const label = str(s.label)\n if (!label) return null\n return {\n competitionId: typeof s.competitionId === 'number' ? s.competitionId : null,\n label,\n image: str(s.imagePath),\n stats: readStatCells(s.stats),\n }\n })\n .filter((s): s is CardScope => s !== null)\n : []\n return {\n id: String(card.entityId),\n kind,\n name: card.canonicalName,\n image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),\n sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),\n season: str(card.seasonName),\n scopes,\n }\n}\n\nexport function toActionVM(action: Record<string, unknown>): ActionVM {\n const label = str(action.actionLabel) ?? str(action.label) ?? str(action.text) ?? str(action.title) ?? 'Continue'\n const actionId = str(action.actionId) ?? str(action.id)\n const actionRef = str(action.actionRef)\n const message = str(action.actionValue) ?? str(action.message) ?? str(action.query) ?? label\n return { label, actionId, actionRef, message }\n}\n\nexport function toChipVM(intent: Record<string, unknown>): ChipVM | null {\n const text = str(intent.text) ?? str(intent.label) ?? str(intent.title)\n return text ? { text } : null\n}\n\nexport function chipFromText(text: string): ChipVM {\n return { text }\n}\n\n// A localized label can already embed the line (TR \"2.5 Üst\") -- never append it twice.\n// Shared by every selection/line join site so they can't drift out of sync (u324).\nexport function joinSelection(label?: string, line?: string): string | undefined {\n if (label && line && label.includes(line)) return label\n return [label, line].filter(Boolean).join(' ') || undefined\n}\n\nexport function toInsightVM(insight: BettingInsight): InsightVM {\n const market = str(insight.marketLabel) ?? str(insight.marketDeveloperName) ?? ''\n const selectionLabel = str(insight.selectionLabel)\n const selectionLine = str(insight.line)\n const selection = joinSelection(selectionLabel, selectionLine)\n const value = insight.odds?.value\n const odds = typeof value === 'number' && Number.isFinite(value) ? value.toFixed(2) : undefined\n const oddsValue = insight.odds?.value\n const matchOddsId = typeof insight.odds?.matchOddsId === 'number' ? insight.odds.matchOddsId : undefined\n const home = str(insight.homeTeamName)\n const away = str(insight.awayTeamName)\n const fixture = home && away ? `${home} vs ${away}` : undefined\n const competition = str(insight.competitionName)\n const scopes = Array.isArray(insight.scopes)\n ? (insight.scopes as Array<Record<string, unknown>>)\n .map((s) => ({ key: str(s.key), label: str(s.label), stats: readStatCells(s.stats) }))\n .filter((s): s is InsightScope => !!s.key && !!s.label)\n : undefined\n const previousValue = insight.odds?.previousValue\n const previous =\n typeof previousValue === 'number' && Number.isFinite(previousValue) ? previousValue : undefined\n const direction =\n insight.odds?.movementDirection === 'shortened' || insight.odds?.movementDirection === 'drifted'\n ? insight.odds.movementDirection\n : undefined\n return {\n id: str(insight.insightId) ?? `${str(insight.ruleId) ?? 'insight'}:${num(insight.matchId) ?? ''}`,\n market,\n selection,\n odds,\n // The wire payload carries bookmakerId (not a name); render a name only if one is present.\n bookmaker: str(insight.odds?.bookmakerName),\n isLive: insight.odds?.isLive === true,\n phase: str(insight.phase),\n fixture,\n competition,\n scopes,\n text: str(insight.text) ?? '',\n stats: readStatCells(insight.stats),\n disclaimer: str(insight.disclaimer),\n matchId: typeof insight.matchId === 'number' ? insight.matchId : 0,\n matchOddsId,\n marketDeveloperName: str(insight.marketDeveloperName),\n selectionLabel: str(insight.selectionLabel),\n line: str(insight.line),\n addToSlipEnabled: insight.addToSlipEnabled === true,\n pinEnabled: insight.pinEnabled === true,\n isMarketFloor: insight.isMarketFloor === true,\n oddsDecimal: typeof oddsValue === 'number' && Number.isFinite(oddsValue) ? oddsValue : undefined,\n quotedAtUtc: str(insight.odds?.quotedAtUtc),\n previousOdds: previous !== undefined && direction !== undefined ? previous.toFixed(2) : undefined,\n movementDirection: previous !== undefined && direction !== undefined ? direction : undefined,\n homeTeamName: home,\n awayTeamName: away,\n homeCrest: str(insight.homeTeamImagePath),\n awayCrest: str(insight.awayTeamImagePath),\n competitionCrest: str(insight.competitionImagePath),\n kickoffUtc: str(insight.kickoffUtc),\n kickoffLabel: str(insight.kickoffLabel),\n }\n}\n\nexport function toSlipSelection(vm: InsightVM, conversationId?: string): SlipSelection | null {\n if (vm.matchOddsId === undefined || vm.oddsDecimal === undefined) return null\n const selection: SlipSelection = {\n matchOddsId: vm.matchOddsId,\n matchId: vm.matchId,\n oddsDecimal: vm.oddsDecimal,\n }\n if (vm.quotedAtUtc !== undefined) selection.quotedAtUtc = vm.quotedAtUtc\n if (vm.id !== undefined) selection.insightId = vm.id\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n\nexport function toMarketOddsVM(card: MarketOddsCard): MarketOddsVM {\n const rows = Array.isArray(card.rows) ? card.rows : []\n const toRow = (r: MarketOddsRow, i: number): MarketOddsRowVM => {\n const selection = joinSelection(str(r.selectionLabel), str(r.line)) ?? ''\n const price = typeof r.price === 'number' && Number.isFinite(r.price) ? r.price : undefined\n const previous =\n typeof r.previousPrice === 'number' && Number.isFinite(r.previousPrice) ? r.previousPrice : undefined\n const direction =\n r.movementDirection === 'shortened' || r.movementDirection === 'drifted' ? r.movementDirection : undefined\n return {\n key: `${selection}:${str(r.line) ?? ''}:${i}`,\n selection,\n odds: price !== undefined ? price.toFixed(2) : '',\n oddsDecimal: price,\n matchOddsId: typeof r.matchOddsId === 'number' ? r.matchOddsId : undefined,\n quotedAtUtc: str(r.quotedAtUtc),\n isMain: r.isMainLine !== false,\n // === true, not !== false: a server that has not shipped the field yet leaves it undefined,\n // and undefined must read as open rather than hiding every price on the card.\n isSuspended: r.isSuspended === true,\n previousOdds: previous !== undefined && direction !== undefined ? previous.toFixed(2) : undefined,\n movementDirection: previous !== undefined && direction !== undefined ? direction : undefined,\n }\n }\n // A suspended selection leaves the ladder entirely, same rule the live match card follows: we do\n // not show a price the bookmaker is not taking. If every line is suspended the card has no rows and\n // MarketOddsCardList renders nothing for it.\n const vms = rows.map(toRow).filter((r) => r.selection && r.odds && !r.isSuspended)\n const home = str(card.homeTeamName)\n const away = str(card.awayTeamName)\n const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v): v is string => !!v).sort()\n return {\n id: `${typeof card.matchId === 'number' ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ''}`,\n market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? '',\n fixture: home && away ? `${home} vs ${away}` : undefined,\n homeTeamName: home,\n awayTeamName: away,\n homeCrest: str(card.homeTeamImagePath),\n awayCrest: str(card.awayTeamImagePath),\n competitionCrest: str(card.competitionImagePath),\n competition: str(card.competitionName),\n kickoffUtc: str(card.kickoffUtc),\n kickoffLabel: str(card.kickoffLabel),\n bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),\n updatedAt: updated.length > 0 ? updated[updated.length - 1] : undefined,\n isLive: rows.some((r) => r.isLive === true),\n matchId: typeof card.matchId === 'number' ? card.matchId : 0,\n mainRows: vms.filter((r) => r.isMain),\n moreRows: vms.filter((r) => !r.isMain),\n disclaimer: str(card.disclaimer),\n addToSlipEnabled: card.addToSlipEnabled === true,\n marketDeveloperName: str(card.marketDeveloperName),\n mainLine: str(card.mainLine),\n pinEnabled: card.pinEnabled === true,\n }\n}\n\nexport interface OddsMovementVM {\n id: string\n matchId: number\n market: string\n marketDeveloperName?: string\n selection: string\n selectionLabel?: string\n line?: string\n fixture?: string\n competition?: string\n bookmaker?: string\n opening: string\n current: string\n direction?: 'shortened' | 'drifted'\n windowHours: number\n excludedCount: number\n isSuspended: boolean\n disclaimer?: string\n geometry: ChartGeometry | null\n observationCount: number\n pinEnabled: boolean\n matchOddsId?: number\n}\n\nexport function toOddsMovementVM(card: OddsMovementCard): OddsMovementVM {\n const raw = Array.isArray(card.points) ? card.points : []\n const samples: ChartSample[] = []\n for (const p of raw) {\n const price = typeof p.price === 'number' && Number.isFinite(p.price) ? p.price : undefined\n const atMs = typeof p.atUtc === 'string' ? Date.parse(p.atUtc) : NaN\n if (price === undefined || Number.isNaN(atMs)) continue\n samples.push({ atMs, price })\n }\n // projectSeries trusts sample order as the time domain (samples[0]/samples[^1] become tMin/tMax)\n // without re-checking it; every other field above is already validated, so this is the one\n // property whose violation is otherwise invisible.\n samples.sort((a, b) => a.atMs - b.atMs)\n\n const asNumber = (v: unknown): number | undefined =>\n typeof v === 'number' && Number.isFinite(v) ? v : undefined\n const opening = asNumber(card.openingPrice)\n const current = asNumber(card.currentPrice)\n const home = str(card.homeTeamName)\n const away = str(card.awayTeamName)\n const selection = joinSelection(str(card.selectionLabel), str(card.line)) ?? ''\n const bookmakerId = typeof card.bookmakerId === 'number' ? card.bookmakerId : ''\n\n return {\n id: `${typeof card.matchId === 'number' ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ''}:${selection}:${bookmakerId}`,\n matchId: typeof card.matchId === 'number' ? card.matchId : 0,\n market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? '',\n marketDeveloperName: str(card.marketDeveloperName),\n selection,\n selectionLabel: str(card.selectionLabel),\n line: str(card.line),\n fixture: home && away ? `${home} vs ${away}` : undefined,\n competition: str(card.competitionName),\n bookmaker: str(card.bookmakerName),\n opening: opening !== undefined ? opening.toFixed(2) : '',\n current: current !== undefined ? current.toFixed(2) : '',\n direction:\n card.movementDirection === 'shortened' || card.movementDirection === 'drifted'\n ? card.movementDirection\n : undefined,\n windowHours: asNumber(card.windowHours) ?? 0,\n excludedCount: asNumber(card.excludedSuspendedCount) ?? 0,\n isSuspended: card.isSuspended === true,\n disclaimer: str(card.disclaimer),\n geometry: projectSeries(samples),\n observationCount: samples.length,\n pinEnabled: card.pinEnabled === true,\n matchOddsId: typeof card.matchOddsId === 'number' ? card.matchOddsId : undefined,\n }\n}\n\nexport function marketOddsRowToSlipSelection(\n vm: MarketOddsVM, row: MarketOddsRowVM, conversationId?: string,\n): SlipSelection | null {\n if (row.matchOddsId === undefined || row.oddsDecimal === undefined) return null\n const selection: SlipSelection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal }\n if (row.quotedAtUtc !== undefined) selection.quotedAtUtc = row.quotedAtUtc\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n","import { useEffect, useReducer, useRef } from 'react'\nimport type { ClubFanDashboardPayload, CountdownCard } from '@sensiblestats/widget-sdk'\nimport type { Action, Message } from './reducer'\n\nconst POLL_INTERVAL_MS = 60_000\nconst LEAD_MS = 120_000 // start polling 2 min before kickoff\nconst GIVE_UP_MS = 30 * 60_000 // stop polling 30 min after kickoff if match never went live\n\ntype Anchor =\n | { messageId: string; kind: 'live' }\n | { messageId: string; kind: 'preMatch'; kickoffMs: number }\n\nexport interface UseLiveDashboardPollOptions {\n messages: Message[]\n dispatch: (action: Action) => void\n getLiveDashboard: () => Promise<ClubFanDashboardPayload | null>\n}\n\nfunction extractKickoffMs(dashboard: ClubFanDashboardPayload): number | null {\n const countdown = dashboard.cards.find((c): c is CountdownCard => c.cardType === 'countdown')\n if (countdown) return countdown.data.kickoffUnix * 1_000\n // fall back to any card that exposes kickoffUnix in its data\n for (const c of dashboard.cards) {\n const d = (c as { data?: { kickoffUnix?: number } }).data\n if (typeof d?.kickoffUnix === 'number') return d.kickoffUnix * 1_000\n }\n return null\n}\n\n// Returns the most recent assistant message that can serve as a polling anchor:\n// — a live dashboard (always valid), or\n// — a preMatch dashboard whose kickoff is within [kickoff − LEAD_MS, kickoff + GIVE_UP_MS].\nfunction findAnchor(messages: Message[]): Anchor | null {\n const now = Date.now()\n for (const m of messages.slice().reverse()) {\n if (m.role !== 'assistant' || !m.clubFanDashboard) continue\n const { phase } = m.clubFanDashboard\n if (phase === 'live') return { messageId: m.id, kind: 'live' }\n if (phase === 'preMatch') {\n const kickoffMs = extractKickoffMs(m.clubFanDashboard)\n if (kickoffMs === null) continue\n if (now >= kickoffMs - LEAD_MS && now <= kickoffMs + GIVE_UP_MS) {\n return { messageId: m.id, kind: 'preMatch', kickoffMs }\n }\n }\n }\n return null\n}\n\n// Returns the earliest future wakeup time for a preMatch dashboard that is not yet within the\n// poll window (kickoff − LEAD_MS still in the future). Returns null if none.\nfunction findEarliestWakeupMs(messages: Message[]): number | null {\n const now = Date.now()\n let earliest: number | null = null\n for (const m of messages) {\n if (m.role !== 'assistant' || m.clubFanDashboard?.phase !== 'preMatch') continue\n const kickoffMs = extractKickoffMs(m.clubFanDashboard)\n if (kickoffMs === null) continue\n const wakeAt = kickoffMs - LEAD_MS\n if (wakeAt > now && (earliest === null || wakeAt < earliest)) earliest = wakeAt\n }\n return earliest\n}\n\n// Polls the live club-fan dashboard every 60s for the chosen anchor:\n//\n// — Live anchor: on a live payload → LIVE_REFRESH (cards + greeting). On a post-match payload →\n// LIVE_TRANSITION (full swap to the post-match dashboard) and stop polling. On null → stop.\n// — PreMatch anchor: on a live payload → LIVE_TRANSITION (full payload swap). On null → keep\n// polling (pre-kickoff 204s) but give up if now > kickoff + GIVE_UP_MS.\n//\n// Wake-up: if a preMatch dashboard's window hasn't opened yet (kickoff − 2min still in the\n// future), schedules a setTimeout to trigger a re-render exactly when polling should begin.\nexport function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }: UseLiveDashboardPollOptions): void {\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0)\n const anchor = findAnchor(messages)\n const anchorRef = useRef<Anchor | null>(anchor)\n anchorRef.current = anchor\n const inFlightRef = useRef(false)\n\n // Polling effect — keyed on the anchor identity so it restarts when anchor changes.\n const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null\n\n useEffect(() => {\n if (!anchorKey || !anchorRef.current) return\n\n const tick = async () => {\n if (inFlightRef.current) return\n inFlightRef.current = true\n try {\n const payload = await getLiveDashboard()\n const current = anchorRef.current\n if (!current) return\n\n if (payload?.phase === 'live') {\n if (current.kind === 'preMatch') {\n dispatch({ kind: 'LIVE_TRANSITION', messageId: current.messageId, dashboard: payload })\n window.clearInterval(id)\n } else {\n dispatch({ kind: 'LIVE_REFRESH', messageId: current.messageId, cards: payload.cards, greeting: payload.greeting })\n }\n } else if (payload?.phase === 'postMatch' && current.kind === 'live') {\n // Match ended: the poll now returns the post-match dashboard. Swap the live card for it\n // and stop polling (the anchor is no longer live).\n dispatch({ kind: 'LIVE_TRANSITION', messageId: current.messageId, dashboard: payload })\n window.clearInterval(id)\n } else {\n // null (204) or non-live phase with no payload\n if (current.kind === 'live') {\n window.clearInterval(id)\n } else if (Date.now() > current.kickoffMs + GIVE_UP_MS) {\n window.clearInterval(id)\n }\n // preMatch within window: keep polling (these are pre-kickoff 204s)\n }\n } catch {\n // A network error must not crash the widget or stop the loop — swallow and retry\n // on the next tick.\n } finally {\n inFlightRef.current = false\n }\n }\n\n const id = window.setInterval(() => { void tick() }, POLL_INTERVAL_MS)\n return () => window.clearInterval(id)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [anchorKey, dispatch, getLiveDashboard])\n\n // Wake-up effect — schedules a re-render when a preMatch window opens in the future.\n useEffect(() => {\n if (anchorKey !== null) return // already polling, no wake-up needed\n const wakeAt = findEarliestWakeupMs(messages)\n if (wakeAt === null) return\n const delay = wakeAt - Date.now()\n if (delay <= 0) return\n const id = window.setTimeout(forceUpdate, delay)\n return () => window.clearTimeout(id)\n }, [anchorKey, messages, forceUpdate])\n}\n","import type { Message } from './reducer'\n\nexport const TTL_MS = 3_600_000\nexport const MAX_MESSAGES = 30\n\nexport interface StoredPayload {\n conversationId: string | null\n messages: Message[]\n}\n\ninterface StoredConversation {\n v: 1\n updatedAt: number\n conversationId: string | null\n messages: Message[]\n}\n\n// Pure read: returns the payload when a v:1 blob exists and is within TTL; a sentinel the caller\n// clears from an effect (never during render) when stale/unparseable; null when absent.\nexport function readConversation(storageKey: string, now: number): StoredPayload | 'expired' | 'corrupt' | null {\n let raw: string | null\n try {\n raw = window.localStorage.getItem(storageKey)\n } catch {\n return null // SSR / storage blocked\n }\n if (!raw) return null\n let parsed: StoredConversation\n try {\n parsed = JSON.parse(raw) as StoredConversation\n } catch {\n return 'corrupt'\n }\n if (parsed?.v !== 1 || !Array.isArray(parsed.messages) || typeof parsed.updatedAt !== 'number') return 'corrupt'\n if (now - parsed.updatedAt > TTL_MS) return 'expired'\n return { conversationId: parsed.conversationId ?? null, messages: parsed.messages }\n}\n\nexport function writeConversation(storageKey: string, conversationId: string | null, messages: Message[], now: number): void {\n let capped = messages.slice(-MAX_MESSAGES)\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify({ v: 1, updatedAt: now, conversationId, messages: capped } satisfies StoredConversation))\n return\n } catch {\n // quota / blocked: drop the oldest half and retry once, then give up (in-memory only)\n if (capped.length <= 1) return\n capped = capped.slice(Math.ceil(capped.length / 2))\n }\n }\n}\n\nexport function clearConversation(storageKey: string): void {\n try {\n window.localStorage.removeItem(storageKey)\n } catch {\n // no-op\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { LiveMonitorEvent, LiveMonitorSnapshot, MarketOddsBlock, PinRef } from '@sensiblestats/widget-sdk'\nimport { createPinStore, type PinAddResult, type PinStore } from './pinStore'\nimport { useTabs, type WidgetTab } from './useTabs'\n\n// Re-exported for back-compat; callers that already import MonitorTab continue to compile.\nexport type MonitorTab = WidgetTab\n\nexport interface LiveMonitorController {\n /** Starts TRUE (the server-side pinEnabled flag is the real affordance gate); flips to\n * false permanently for the session on a 404 (null snapshot) from the monitor endpoint. */\n enabled: boolean\n pins: PinRef[]\n snapshot: LiveMonitorSnapshot | null\n activeTab: WidgetTab\n setActiveTab(tab: WidgetTab): void\n togglePin(pin: PinRef): PinAddResult\n isPinned(key: string): boolean\n /** Set by ChatPanel when a reply lands off-tab; cleared on chat tab. */\n chatDot: boolean\n markChatActivity(): void\n /** A goal/red event arrived on a pinned match since Maçlar was last viewed. */\n matchesDot: boolean\n /** A pinned market's price changed since Oranlar was last viewed. */\n oddsDot: boolean\n /** The live count rose from zero while Today was off-screen; suppressed on the active tab. */\n todayDot: boolean\n /** Set by the discovery owner when the live count rises from zero (mirrors markChatActivity). */\n markTodayActivity(): void\n /** Last-viewed price per pin key, for client-side movement badges. */\n lastViewedPrices: Record<string, number>\n /** matchOddsIds the user added to the slip this session — drives the persistent in-slip badge. */\n inSlip: Record<number, true>\n markInSlip(matchOddsId: number): void\n /** The currently open accordion market per matchId (null = collapsed). One open at a time per match. */\n openMarket: Record<number, string | null>\n /** Lazy per-market odds cache, keyed `${matchId}:${marketDeveloperName}`. */\n marketOdds: Record<string, { block?: MarketOddsBlock; loading: boolean; error: boolean }>\n toggleMarket(matchId: number, marketDeveloperName: string): void\n /** Refetches a market's odds WITHOUT touching openMarket -- the tap-to-retry affordance for a\n * market that is already open and errored. toggleMarket would collapse it instead (it flips\n * openMarket unconditionally), which is the wrong move when the row is already showing. */\n retryMarket(matchId: number, marketDeveloperName: string): void\n /** Internal seam: applies a freshly-fetched snapshot (or null on a 404). The poll loop calls\n * this repeatedly; tests call it directly to drive dot/grace logic without a live timer.\n * Not part of the poll cadence/visibility policy itself. */\n _setSnapshot(next: LiveMonitorSnapshot | null): void\n}\n\nexport interface UseLiveMonitorOptions {\n getLiveMonitor: (pins: PinRef[]) => Promise<LiveMonitorSnapshot | null>\n getMarketOdds?: (matchId: number, marketDeveloperName: string) => Promise<MarketOddsBlock | null>\n storageKey: string\n /** false -> true transitions trigger an immediate poll tick (widget open). */\n isOpen: boolean\n /** Whether the Today tab currently has content -- picks the fallback target when a pinned tab\n * disappears, and sends the user to Chat when Today itself empties under them. */\n hasToday?: boolean\n}\n\nconst GOAL_OR_RED: ReadonlySet<LiveMonitorEvent['type']> = new Set(['goal', 'red'])\nconst MIN_POLL_MS = 5_000\nconst DEFAULT_POLL_MS = 60_000\n\nfunction eventIdentity(e: LiveMonitorEvent): string {\n return `${e.type}:${e.side}:${e.minuteLabel}:${e.player ?? ''}`\n}\n\nfunction priceForPin(snapshot: LiveMonitorSnapshot | null, pin: PinRef): number | undefined {\n if (!snapshot) return undefined\n const market = snapshot.markets.find((m) => m.key === pin.key)\n const rows = market?.card?.rows\n if (!rows || rows.length === 0) return undefined\n const row = pin.matchOddsId != null ? rows.find((r) => r.matchOddsId === pin.matchOddsId) : rows[0]\n return row?.price\n}\n\nfunction phaseForPin(snapshot: LiveMonitorSnapshot, pin: PinRef): string | undefined {\n if (pin.kind === 'match') return snapshot.matches.find((m) => m.matchId === pin.matchId)?.phase\n return snapshot.markets.find((mk) => mk.key === pin.key)?.phase\n}\n\nexport function useLiveMonitor(opts: UseLiveMonitorOptions): LiveMonitorController {\n const sessionIdRef = useRef(crypto.randomUUID())\n\n const [pins, setPins] = useState<PinRef[]>([])\n // Lazy initializer: the store fires an initial (no-op-from-the-caller's-view) onChange\n // synchronously during construction, which is a same-component render-phase state update\n // React explicitly supports — it must not run in an effect/later render.\n const [store] = useState<PinStore>(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins))\n\n const [enabled, setEnabled] = useState(true)\n const [snapshot, setSnapshotState] = useState<LiveMonitorSnapshot | null>(null)\n const { activeTab, setActiveTab: setActiveTabState } = useTabs('chat')\n const [chatDot, setChatDot] = useState(false)\n const [matchesDot, setMatchesDot] = useState(false)\n const [oddsDot, setOddsDot] = useState(false)\n const [todayDot, setTodayDot] = useState(false)\n const [lastViewedPrices, setLastViewedPrices] = useState<Record<string, number>>({})\n const [inSlip, setInSlip] = useState<Record<number, true>>({})\n const [openMarket, setOpenMarket] = useState<Record<number, string | null>>({})\n const [marketOdds, setMarketOdds] = useState<\n Record<string, { block?: MarketOddsBlock; loading: boolean; error: boolean }>\n >({})\n\n const pinsRef = useRef(pins)\n pinsRef.current = pins\n const activeTabRef = useRef(activeTab)\n activeTabRef.current = activeTab\n const snapshotRef = useRef(snapshot)\n snapshotRef.current = snapshot\n const lastViewedPricesRef = useRef(lastViewedPrices)\n lastViewedPricesRef.current = lastViewedPrices\n const openMarketRef = useRef(openMarket)\n openMarketRef.current = openMarket\n const marketOddsRef = useRef(marketOdds)\n marketOddsRef.current = marketOdds\n const hasToday = opts.hasToday ?? false\n\n const marketKey = (matchId: number, dev: string): string => `${matchId}:${dev}`\n\n const getMarketOddsRef = useRef(opts.getMarketOdds)\n getMarketOddsRef.current = opts.getMarketOdds // latest-fn pattern; fetchMarket reads the ref, deps stay stable\n\n // Stable identity ([] deps, refs only) so callers (applySnapshot, tick) can invoke it without\n // needing to sit in a dependency array.\n const fetchMarket = useCallback((matchId: number, dev: string) => {\n const key = marketKey(matchId, dev)\n const existing = marketOddsRef.current[key]\n if (existing?.loading) return // already in flight -- don't double-fetch\n const loadingEntry = { ...existing, loading: true, error: false }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: loadingEntry }\n setMarketOdds((prev) => ({ ...prev, [key]: loadingEntry }))\n const fn = getMarketOddsRef.current\n if (!fn) return\n void fn(matchId, dev)\n .then((block) => {\n const entry = { block: block ?? undefined, loading: false, error: false }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: entry }\n setMarketOdds((prev) => ({ ...prev, [key]: entry }))\n })\n .catch(() => {\n const entry = { ...marketOddsRef.current[key], loading: false, error: true }\n marketOddsRef.current = { ...marketOddsRef.current, [key]: entry }\n setMarketOdds((prev) => ({ ...prev, [key]: entry }))\n })\n }, [])\n\n const toggleMarket = useCallback((matchId: number, dev: string) => {\n const key = marketKey(matchId, dev)\n const wasOpen = openMarketRef.current[matchId] === dev\n const nextValue = wasOpen ? null : dev\n openMarketRef.current = { ...openMarketRef.current, [matchId]: nextValue }\n setOpenMarket((prev) => ({ ...prev, [matchId]: nextValue }))\n // Opening a market that isn't cached yet -- fetch it. A successfully-cached reopen is a\n // no-op fetch, but an entry that previously errored (no block) MUST be retried, not\n // treated as \"cached\" -- that's what drives the tap-to-retry affordance (Task 9).\n const existing = marketOddsRef.current[key]\n if (!wasOpen && !(existing?.loading || existing?.block)) {\n fetchMarket(matchId, dev)\n }\n }, [fetchMarket])\n\n const retryMarket = useCallback((matchId: number, dev: string) => {\n fetchMarket(matchId, dev)\n }, [fetchMarket])\n\n const applySnapshot = useCallback((next: LiveMonitorSnapshot | null) => {\n if (next === null) {\n setEnabled(false)\n return\n }\n const prev = snapshotRef.current\n const currentPins = pinsRef.current\n\n const pinnedMatchIds = new Set(currentPins.filter((p) => p.kind === 'match').map((p) => p.matchId))\n let sawNewGoalOrRed = false\n for (const m of next.matches) {\n if (!pinnedMatchIds.has(m.matchId)) continue\n const prevMatch = prev?.matches.find((pm) => pm.matchId === m.matchId)\n const prevKeys = new Set((prevMatch?.events ?? []).filter((e) => GOAL_OR_RED.has(e.type)).map(eventIdentity))\n if (m.events.some((e) => GOAL_OR_RED.has(e.type) && !prevKeys.has(eventIdentity(e)))) {\n sawNewGoalOrRed = true\n break\n }\n }\n if (sawNewGoalOrRed && activeTabRef.current !== 'following') setMatchesDot(true)\n\n // Default-open the first available market per pinned match, once -- an explicit close\n // (openMarket[matchId] === null) must stick, so the guard is \"no entry at all\" not \"falsy\".\n for (const m of next.matches) {\n if (!pinnedMatchIds.has(m.matchId)) continue\n const first = m.availableMarkets?.[0]\n if (!first) continue\n if (m.matchId in openMarketRef.current) continue\n const dev = first.marketDeveloperName\n openMarketRef.current = { ...openMarketRef.current, [m.matchId]: dev }\n setOpenMarket((prevOpen) => ({ ...prevOpen, [m.matchId]: dev }))\n fetchMarket(m.matchId, dev)\n }\n\n const marketPins = currentPins.filter((p) => p.kind !== 'match')\n if (activeTabRef.current === 'odds') {\n setLastViewedPrices((prevMap) => {\n let changed = false\n const out = { ...prevMap }\n for (const pin of marketPins) {\n const price = priceForPin(next, pin)\n if (price !== undefined && out[pin.key] !== price) {\n out[pin.key] = price\n changed = true\n }\n }\n return changed ? out : prevMap\n })\n } else {\n let sawPriceMove = false\n for (const pin of marketPins) {\n const price = priceForPin(next, pin)\n const last = lastViewedPricesRef.current[pin.key]\n if (price !== undefined && last !== undefined && price !== last) {\n sawPriceMove = true\n break\n }\n }\n if (sawPriceMove) setOddsDot(true)\n }\n\n const graceKeys = currentPins\n .filter((p) => {\n const phase = phaseForPin(next, p)\n return phase === 'fullTime' || phase === 'postponed' || phase === 'gone'\n })\n .map((p) => p.key)\n if (graceKeys.length > 0) store.markGrace(graceKeys, sessionIdRef.current, Date.now())\n\n // Sync the ref immediately (state updates are async) -- the poll loop's schedule step reads\n // this synchronously in the SAME tick, right after this call returns, to size the next\n // delay off the snapshot that was just received rather than the one from the prior tick.\n snapshotRef.current = next\n setSnapshotState(next)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [store])\n\n // Poll loop. ALL mutable inputs live in refs so `tick` is created ONCE ([applySnapshot] deps,\n // and applySnapshot itself is stable across renders): an inline getLiveMonitor lambda handed\n // in fresh from StatsWidget on every render must not re-arm the visibility listener or\n // recreate the timer chain.\n const inFlightRef = useRef(false)\n const timerRef = useRef<number | undefined>(undefined)\n const disabledRef = useRef(false)\n const getLiveMonitorRef = useRef(opts.getLiveMonitor)\n getLiveMonitorRef.current = opts.getLiveMonitor // latest-fn pattern; tick reads the ref, deps stay stable\n\n const tick = useCallback(async () => {\n if (inFlightRef.current || disabledRef.current || pinsRef.current.length === 0) return\n inFlightRef.current = true\n try {\n const snap = await getLiveMonitorRef.current(pinsRef.current)\n if (snap === null) {\n // 404 -> live monitor disabled for this operator: stop for the session, hide affordances.\n disabledRef.current = true\n applySnapshot(null)\n return\n }\n applySnapshot(snap)\n // Live-refresh the open accordion market per match. Bypasses the \"already cached\" skip\n // (that guard only lives in toggleMarket) -- fetchMarket itself only skips a fetch already\n // in flight, so this always requests fresh odds for a live match's open market.\n for (const m of snap.matches) {\n if (m.phase !== 'live') continue\n const dev = openMarketRef.current[m.matchId]\n if (dev) fetchMarket(m.matchId, dev)\n }\n } catch {\n // transient failure: keep the previous snapshot, retry on the next scheduled tick\n } finally {\n inFlightRef.current = false\n scheduleRef.current()\n }\n }, [applySnapshot, fetchMarket]) // reads refs only -- both callbacks are themselves stable\n\n const scheduleRef = useRef<() => void>(() => {})\n scheduleRef.current = () => {\n window.clearTimeout(timerRef.current)\n if (disabledRef.current || pinsRef.current.length === 0 || document.visibilityState === 'hidden') return\n const hinted = (snapshotRef.current?.nextPollSeconds ?? DEFAULT_POLL_MS / 1000) * 1000\n timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted))\n }\n\n // Immediate tick: pin list transitions 0 -> 1+ (togglePin add, or pins already present at\n // mount -- the ref starts at 0 so the first run treats \"already have pins\" the same way).\n // Dropping to zero pins clears any pending timer so a stray tick never fires with no pins.\n // It deliberately does NOT move the active tab: PinToggle is reachable from a chat message\n // card, so unpinning mid-conversation must leave the reader where they are. The per-kind\n // effect below owns the fallback, and its `activeTab` guard covers zero pins too.\n const prevPinsLengthRef = useRef(0)\n useEffect(() => {\n const wasEmpty = prevPinsLengthRef.current === 0\n prevPinsLengthRef.current = pins.length\n if (pins.length === 0) {\n window.clearTimeout(timerRef.current)\n return\n }\n if (wasEmpty) void tick()\n }, [pins.length, tick])\n\n // A tab left active after the content backing it disappears strands the user on an empty panel\n // with no tab in the strip to escape from. Three ways in: the last match pin drops while an odds\n // pin remains (pins.length alone can't see it, the OTHER kind keeps it above zero), the mirror\n // case for odds, and Today emptying under the user at the local-date rollover.\n useEffect(() => {\n const matchPins = pins.filter((p) => p.kind === 'match').length\n const marketPins = pins.length - matchPins\n if (activeTab === 'following' && matchPins === 0) setActiveTabState(hasToday ? 'today' : 'chat')\n if (activeTab === 'odds' && marketPins === 0) setActiveTabState(hasToday ? 'today' : 'chat')\n if (activeTab === 'today' && !hasToday) setActiveTabState('chat')\n }, [pins, activeTab, hasToday])\n\n // Immediate tick: widget open (false -> true transition).\n const prevIsOpenRef = useRef(false)\n useEffect(() => {\n const wasClosed = !prevIsOpenRef.current\n prevIsOpenRef.current = opts.isOpen\n if (wasClosed && opts.isOpen) void tick()\n }, [opts.isOpen, tick])\n\n // Visibility: hidden clears the pending timer; visible ticks immediately. Mounted exactly\n // once -- `tick` never changes identity, so this effect never re-fires across re-renders.\n useEffect(() => {\n const onVisibility = () => {\n if (document.visibilityState === 'hidden') window.clearTimeout(timerRef.current)\n else void tick()\n }\n document.addEventListener('visibilitychange', onVisibility)\n return () => {\n document.removeEventListener('visibilitychange', onVisibility)\n window.clearTimeout(timerRef.current)\n }\n }, [tick])\n\n const setActiveTab = useCallback((tab: WidgetTab) => {\n setActiveTabState(tab)\n if (tab === 'chat') setChatDot(false)\n if (tab === 'today') setTodayDot(false)\n if (tab === 'following') {\n setMatchesDot(false)\n void tick()\n }\n if (tab === 'odds') {\n setOddsDot(false)\n setLastViewedPrices((prevMap) => {\n const out = { ...prevMap }\n for (const pin of pinsRef.current.filter((p) => p.kind !== 'match')) {\n const price = priceForPin(snapshotRef.current, pin)\n if (price !== undefined) out[pin.key] = price\n }\n return out\n })\n void tick()\n }\n }, [tick])\n\n const togglePin = useCallback((pin: PinRef): PinAddResult => store.toggle(pin), [store])\n const isPinned = useCallback((key: string): boolean => pinsRef.current.some((p) => p.key === key), [])\n const markChatActivity = useCallback(() => setChatDot(true), [])\n // Same shape as markChatActivity: the count that drives it lives in useMatchDiscovery, which\n // cannot be read from here without making the two hooks observe each other's own render.\n const markTodayActivity = useCallback(() => {\n if (activeTabRef.current !== 'today') setTodayDot(true)\n }, [])\n const markInSlip = useCallback((matchOddsId: number) => {\n setInSlip((prev) => (prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true }))\n }, [])\n\n return {\n enabled,\n pins,\n snapshot,\n activeTab,\n setActiveTab,\n togglePin,\n isPinned,\n chatDot,\n markChatActivity,\n matchesDot,\n oddsDot,\n todayDot,\n markTodayActivity,\n lastViewedPrices,\n inSlip,\n markInSlip,\n openMarket,\n marketOdds,\n toggleMarket,\n retryMarket,\n _setSnapshot: applySnapshot,\n }\n}\n","import type { PinRef } from '@sensiblestats/widget-sdk'\n\nexport const MAX_MATCH_PINS = 5\nexport const MAX_MARKET_PINS = 10\nexport type PinAddResult = 'added' | 'removed' | 'match_limit' | 'market_limit'\n\nexport type StoredPin = PinRef & { graceAt?: number; graceSession?: string }\n\nexport interface PinStore {\n pins: PinRef[]\n /** Toggle: same key present -> remove; else add if under the kind's cap. */\n toggle(pin: PinRef): PinAddResult\n remove(key: string): void\n has(key: string): boolean\n /** D7: stamps graceAt/graceSession on the given keys, only where not already stamped. */\n markGrace(keys: string[], sessionId: string, now: number): void\n}\n\nexport function pinKey(p: Omit<PinRef, 'key'>): string {\n return `${p.kind}:${p.matchId}:${p.marketDeveloperName ?? ''}:${p.selectionLabel ?? ''}:${p.line ?? ''}:${p.matchOddsId ?? ''}`\n}\n\nexport const GRACE_MS = 4 * 60 * 60 * 1000\n\n/** D7: drop pins whose grace started in a PREVIOUS session (next widget open) or > 4h ago. */\nexport function pruneExpired(pins: StoredPin[], sessionId: string, now: number): StoredPin[] {\n return pins.filter((p) => p.graceAt === undefined || (p.graceSession === sessionId && now - p.graceAt <= GRACE_MS))\n}\n\ninterface StoredPins {\n v: 1\n pins: StoredPin[]\n}\n\nfunction safeRead(storageKey: string): StoredPin[] {\n try {\n const raw = window.localStorage.getItem(storageKey)\n if (!raw) return []\n const parsed = JSON.parse(raw) as StoredPins\n return parsed.v === 1 && Array.isArray(parsed.pins) ? parsed.pins : []\n } catch {\n return []\n }\n}\n\nfunction safeWrite(storageKey: string, pins: StoredPin[]): void {\n try {\n window.localStorage.setItem(storageKey, JSON.stringify({ v: 1, pins } satisfies StoredPins))\n } catch {\n // storage blocked -> in-memory only for the session (spec, degradation rules)\n }\n}\n\nexport function loadPins(storageKey: string): PinRef[] {\n return safeRead(storageKey)\n}\n\nexport function createPinStore(storageKey: string, sessionId: string, onChange: (pins: PinRef[]) => void): PinStore {\n // D7 grace: pins whose subject finished in a previous session (or >4h ago) are dropped on open.\n let pins = pruneExpired(safeRead(storageKey), sessionId, Date.now())\n\n const commit = (next: StoredPin[]) => {\n pins = next\n safeWrite(storageKey, pins)\n onChange(pins)\n }\n commit(pins)\n\n return {\n get pins() {\n return pins\n },\n has: (key) => pins.some((p) => p.key === key),\n remove: (key) => commit(pins.filter((p) => p.key !== key)),\n markGrace(keys, session, now) {\n commit(\n pins.map((p) => (keys.includes(p.key) && p.graceAt === undefined ? { ...p, graceAt: now, graceSession: session } : p)),\n )\n },\n toggle(pin) {\n if (pins.some((p) => p.key === pin.key)) {\n commit(pins.filter((p) => p.key !== pin.key))\n return 'removed'\n }\n const matchCount = pins.filter((p) => p.kind === 'match').length\n const marketCount = pins.length - matchCount\n if (pin.kind === 'match' && matchCount >= MAX_MATCH_PINS) return 'match_limit'\n if (pin.kind !== 'match' && marketCount >= MAX_MARKET_PINS) return 'market_limit'\n commit([...pins, pin])\n return 'added'\n },\n }\n}\n","import { useState } from 'react'\n\nexport type WidgetTab = 'chat' | 'today' | 'following' | 'odds' | 'games' | 'leaderboard'\n\nexport function useTabs(initial: WidgetTab = 'chat'): { activeTab: WidgetTab; setActiveTab: (t: WidgetTab) => void } {\n const [activeTab, setActiveTab] = useState<WidgetTab>(initial)\n return { activeTab, setActiveTab }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { MatchState, SchedulePayload, ScheduleGroup, StatesPayload } from '@sensiblestats/widget-sdk'\nimport { readSchedule, readScheduleIgnoringTtl, writeSchedule } from './scheduleCache'\nimport { dueMatchIds } from './dueSet'\n\nconst POLL_MS = 60_000\n// Local re-render so the minute advances between network polls. Costs one render; the alternative\n// is a clock that only moves once a minute.\nconst ROLLOVER_CHECK_MS = 60_000\nconst STALE_AFTER_FAILURES = 2\n\nexport interface MatchDiscoveryController {\n groups: ScheduleGroup[]\n states: Record<number, MatchState>\n /** Advanced locally between polls so the minute ticks. */\n liveCount: number\n stale: boolean\n expanded: Record<number, boolean>\n toggleGroup(competitionId: number): void\n /** Test seam: run one states poll synchronously. Not part of the cadence policy. */\n _tick(): Promise<void>\n}\n\nexport interface UseMatchDiscoveryOptions {\n getSchedule: (localDate: string, utcOffsetMinutes: number) => Promise<SchedulePayload | null>\n getStates: (matchIds: number[]) => Promise<StatesPayload | null>\n operatorId: string\n isOpen: boolean\n pinnedMatchIds: number[]\n}\n\nfunction localDateOf(now: Date): string {\n const y = now.getFullYear()\n const m = `${now.getMonth() + 1}`.padStart(2, '0')\n const d = `${now.getDate()}`.padStart(2, '0')\n return `${y}-${m}-${d}`\n}\n\nexport function useMatchDiscovery(opts: UseMatchDiscoveryOptions): MatchDiscoveryController {\n const [groups, setGroups] = useState<ScheduleGroup[]>([])\n const [states, setStates] = useState<Record<number, MatchState>>({})\n const [failures, setFailures] = useState(0)\n const [expanded, setExpanded] = useState<Record<number, boolean>>({})\n const [touched, setTouched] = useState<Record<number, boolean>>({})\n\n const groupsRef = useRef(groups)\n groupsRef.current = groups\n const statesRef = useRef(states)\n statesRef.current = states\n // latest-fn pattern (mirrors useLiveMonitor's getLiveMonitorRef): tick reads the ref, so an\n // inline getStates lambda handed in fresh on every render cannot tear down and recreate the\n // poll interval.\n const getStatesRef = useRef(opts.getStates)\n getStatesRef.current = opts.getStates\n\n const pinnedKey = opts.pinnedMatchIds.join(',')\n\n // A widget left mounted across midnight has to move to the new day, or it holds yesterday's\n // fixtures forever with an empty due set and no polling. Cheap enough to check on a coarse\n // interval; the state only ever changes value once a day, so it re-renders once a day.\n const [localDate, setLocalDate] = useState(() => localDateOf(new Date()))\n useEffect(() => {\n const id = setInterval(() => {\n const next = localDateOf(new Date())\n setLocalDate((prev) => (prev === next ? prev : next))\n }, ROLLOVER_CHECK_MS)\n return () => clearInterval(id)\n }, [])\n\n // `states` is deliberately NOT cleared here: a 23:00 fixture still playing at 00:30 belongs to\n // neither day's window, and dropping its state would blank a score that is still true.\n useEffect(() => {\n let cancelled = false\n // getTimezoneOffset is minutes WEST of UTC, so Istanbul reports -180 for UTC+3.\n const utcOffsetMinutes = -new Date().getTimezoneOffset()\n\n const cached = readSchedule(opts.operatorId, localDate, Date.now())\n if (cached) {\n if (!cancelled) setGroups(cached.groups)\n return () => { cancelled = true }\n }\n\n void (async () => {\n try {\n const payload = await opts.getSchedule(localDate, utcOffsetMinutes)\n if (cancelled || !payload) return\n writeSchedule(opts.operatorId, localDate, payload, Date.now())\n setGroups(payload.groups)\n } catch {\n // Fixtures do not move, so an expired day beats an empty tab.\n const fallback = readScheduleIgnoringTtl(opts.operatorId, localDate)\n if (!cancelled && fallback) setGroups(fallback.groups)\n }\n })()\n\n return () => { cancelled = true }\n }, [opts.operatorId, localDate])\n\n useEffect(() => {\n setExpanded((prev) => {\n const next: Record<number, boolean> = {}\n for (const group of groups) {\n const hasPin = group.matches.some((m) => opts.pinnedMatchIds.includes(m.matchId))\n const seeded = group.expandedByDefault || hasPin\n next[group.competitionId] = touched[group.competitionId]\n ? (prev[group.competitionId] ?? seeded)\n : seeded\n }\n return next\n })\n }, [groups, pinnedKey, touched])\n\n const tick = useCallback(async () => {\n const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now())\n if (ids.length === 0) return\n try {\n const payload = await getStatesRef.current(ids)\n if (!payload) return\n setStates((prev) => {\n // Retained rather than replaced: a finished match keeps its final score after it leaves\n // the due set.\n const next = { ...prev }\n for (const state of payload.states) next[state.matchId] = state\n return next\n })\n setFailures(0)\n } catch {\n setFailures((n) => n + 1)\n }\n }, [])\n\n // `groups` is in the deps (beyond `tick`, which is now stable) so a schedule fetch that\n // resolves after the mount-time tick above gets an immediate follow-up poll, rather than\n // stranding the newly-loaded due set until the next 60s tick.\n useEffect(() => {\n if (!opts.isOpen) return\n void tick()\n const id = setInterval(() => { void tick() }, POLL_MS)\n return () => clearInterval(id)\n }, [opts.isOpen, tick, groups])\n\n const stale = failures >= STALE_AFTER_FAILURES\n\n const liveCount = useMemo(\n () => (stale\n ? 0\n // A match whose own reading has gone stale stops counting: a stalled window must not hold\n // the badge up at 1 for the rest of the day.\n : Object.values(states).filter((s) => s.phase === 'live').length),\n [states, stale],\n )\n\n const toggleGroup = useCallback((competitionId: number) => {\n setTouched((prev) => ({ ...prev, [competitionId]: true }))\n setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }))\n }, [])\n\n return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick }\n}\n","import type { SchedulePayload } from '@sensiblestats/widget-sdk'\n\nconst PREFIX = 'ss-w-schedule:'\nconst SCHEMA_VERSION = 1\nconst TTL_MS = 6 * 3600_000\n\ninterface Entry {\n v: number\n at: number\n payload: SchedulePayload\n}\n\nexport function scheduleCacheKey(operatorId: string, localDate: string): string {\n return `${PREFIX}${operatorId}:${localDate}`\n}\n\nfunction read(operatorId: string, localDate: string): Entry | null {\n try {\n const raw = localStorage.getItem(scheduleCacheKey(operatorId, localDate))\n if (!raw) return null\n const entry = JSON.parse(raw) as Entry\n // A wire change bumps SCHEMA_VERSION; without this an old entry deserializes into the new\n // shape and renders fields that are no longer there.\n if (entry.v !== SCHEMA_VERSION || !entry.payload) return null\n return entry\n } catch {\n return null\n }\n}\n\nexport function readSchedule(operatorId: string, localDate: string, nowMs: number): SchedulePayload | null {\n const entry = read(operatorId, localDate)\n if (!entry) return null\n return nowMs - entry.at > TTL_MS ? null : entry.payload\n}\n\n/** The /schedule-failed path: fixtures do not move, so a stale day beats an empty tab. */\nexport function readScheduleIgnoringTtl(operatorId: string, localDate: string): SchedulePayload | null {\n return read(operatorId, localDate)?.payload ?? null\n}\n\n// The cache is skeleton-only by construction, not by convention: a payload is rebuilt\n// field-by-field here so an excess live-state field on the wire can never be persisted.\nfunction skeletonOnly(payload: SchedulePayload): SchedulePayload {\n return {\n localDate: payload.localDate,\n groups: payload.groups.map((g) => ({\n competitionId: g.competitionId,\n competitionName: g.competitionName,\n competitionImagePath: g.competitionImagePath ?? null,\n rank: g.rank,\n expandedByDefault: g.expandedByDefault,\n matches: g.matches.map((m) => ({\n matchId: m.matchId,\n homeTeamName: m.homeTeamName,\n awayTeamName: m.awayTeamName,\n homeTeamImagePath: m.homeTeamImagePath ?? null,\n awayTeamImagePath: m.awayTeamImagePath ?? null,\n kickoffUnix: m.kickoffUnix,\n })),\n })),\n }\n}\n\nexport function writeSchedule(\n operatorId: string, localDate: string, payload: SchedulePayload, nowMs: number,\n): void {\n const keep = scheduleCacheKey(operatorId, localDate)\n const mine = `${PREFIX}${operatorId}:`\n try {\n // Scoped to this operator: two operators can share a browser, and pruning the whole prefix\n // would evict the other one's day on every write.\n for (let i = localStorage.length - 1; i >= 0; i--) {\n const key = localStorage.key(i)\n if (key && key.startsWith(mine) && key !== keep) localStorage.removeItem(key)\n }\n const entry: Entry = { v: SCHEMA_VERSION, at: nowMs, payload: skeletonOnly(payload) }\n localStorage.setItem(keep, JSON.stringify(entry))\n } catch {\n // A full or blocked localStorage must not break the tab; the schedule refetches next mount.\n }\n}\n","import type { ScheduleGroup, MatchState } from '@sensiblestats/widget-sdk'\n\n// Phases that never change again, so one answer is the last answer we need. Everything else --\n// preMatch (the clock passed but the feed has not flipped yet) and live -- is still moving.\nconst TERMINAL_PHASES: ReadonlySet<string> = new Set(['fullTime', 'postponed'])\n\n/**\n * Which of today's matches to ask about. Anything past its kickoff clock that has not yet given us\n * a terminal answer, and nothing else.\n *\n * This replaced a fixed 3.5-hour window after kickoff. The window bounded the REQUEST, but on a\n * cold load it also silently bounded what we could ever KNOW: open the widget at 15:13 and a match\n * that kicked off at 11:00 was already outside it, so it was never asked about, had no state, and\n * rendered as a fixture that had not started -- kickoff time, no score -- four hours after it\n * finished 0-1. Matches inside the window showed FT correctly, which is why only the older half of\n * the day looked wrong.\n *\n * Terminating on the answer rather than on the clock is also strictly cheaper in the steady state:\n * every finished match drops out permanently after one reply, so a late-evening poll carries only\n * what is actually still playing. The schedule is one day, and the endpoint caps at 200 ids.\n */\nexport function dueMatchIds(\n groups: ScheduleGroup[], states: Record<number, MatchState>, nowMs: number,\n): number[] {\n const due = new Set<number>()\n\n for (const group of groups) {\n for (const match of group.matches) {\n if (nowMs - match.kickoffUnix * 1000 < 0) continue\n const phase = states[match.matchId]?.phase\n if (phase !== undefined && TERMINAL_PHASES.has(phase)) continue\n due.add(match.matchId)\n }\n }\n\n return [...due]\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { GameListPayload, GameSummary } from '@sensiblestats/widget-sdk'\nimport type { WidgetTab } from './useTabs'\n\nconst GAMES_POLL_MS = 60_000\nconst DEFAULT_TZ = 'Europe/London'\n\nfunction computeGameDay(timezone: string): string {\n // en-CA uses YYYY-MM-DD format\n return new Intl.DateTimeFormat('en-CA', { timeZone: timezone }).format(new Date())\n}\n\nexport interface UseGamesResult {\n enabled: boolean\n games: GameSummary[]\n loading: boolean\n refresh: () => void\n}\n\nexport function useGames(\n conversation: { getGames: (gameDay?: string) => Promise<GameListPayload | null> } | null | undefined,\n { activeTab, operatorTimezone }: { activeTab: WidgetTab; operatorTimezone?: string },\n): UseGamesResult {\n // Games/Leaderboard tabs are hidden until we KNOW this operator has games. Every operator shares\n // one games backend, so a non-games operator does not 404 — it returns 200 with an empty list.\n // Gating on games.length (not on the 404 sentinel) is what keeps the tabs off those operators;\n // defaulting to false avoids flashing the tabs on every operator during the first fetch.\n const [enabled, setEnabled] = useState(false)\n const [games, setGames] = useState<GameSummary[]>([])\n const [loading, setLoading] = useState(false)\n const [refreshCount, setRefreshCount] = useState(0)\n\n const inFlightRef = useRef(false)\n // Set only when the feature is entirely off for this operator (backend 404). Stops all polling —\n // distinct from \"enabled\", which merely reflects whether today's list has any games.\n const hardOffRef = useRef(false)\n const conversationRef = useRef(conversation)\n conversationRef.current = conversation\n const tzRef = useRef(operatorTimezone ?? DEFAULT_TZ)\n tzRef.current = operatorTimezone ?? DEFAULT_TZ\n\n // The conversation is often null on first render and set once the widget finishes initialising.\n // It is intentionally NOT read through the ref in the effect deps — the effect must re-run when\n // it becomes available, or the one-shot fetch never fires and the tabs never appear. (Defaulting\n // `enabled` to true used to paper over this; gating on the games list means we must actually\n // fetch.)\n const ready = conversation != null\n\n useEffect(() => {\n if (hardOffRef.current) return\n let active = true\n\n const doFetch = async (): Promise<void> => {\n const conv = conversationRef.current\n if (!conv || inFlightRef.current || !active) return\n inFlightRef.current = true\n setLoading(true)\n try {\n const gameDay = computeGameDay(tzRef.current)\n const result = await conv.getGames(gameDay)\n if (!active) return\n if (result === null) {\n // 404: games feature is not enabled for this operator at all — hide and stop polling.\n hardOffRef.current = true\n setEnabled(false)\n setGames([])\n } else {\n // 200: show the tabs only when this operator actually has games today.\n setGames(result.games)\n setEnabled(result.games.length > 0)\n }\n } catch {\n // swallow; retry next tick\n } finally {\n inFlightRef.current = false\n if (active) setLoading(false)\n }\n }\n\n // Always fetch once on mount or refresh\n void doFetch()\n\n // Poll while the games tab is active\n let intervalId: number | undefined\n if (activeTab === 'games') {\n intervalId = window.setInterval(() => {\n if (hardOffRef.current) {\n window.clearInterval(intervalId)\n return\n }\n void doFetch()\n }, GAMES_POLL_MS)\n }\n\n return () => {\n active = false\n // Release the in-flight guard so a remount (React StrictMode double-invokes effects, and any\n // dependency change re-runs this one) can fetch again. Without this, the first run's request\n // is still in flight when the second run checks the guard, the second run bails, and the\n // first run's result is dropped because `active` is now false — so `enabled` is never set.\n inFlightRef.current = false\n if (intervalId !== undefined) window.clearInterval(intervalId)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, refreshCount, ready])\n\n const refresh = useCallback(() => {\n setRefreshCount((c) => c + 1)\n }, [])\n\n return { enabled, games, loading, refresh }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { WidgetTab } from './useTabs'\n\nexport interface UseLeaderboardResult {\n data: LeaderboardPayload | null\n loading: boolean\n refresh: () => void\n}\n\nexport function useLeaderboard(\n conversation: { getLeaderboard: () => Promise<LeaderboardPayload | null> } | null | undefined,\n { activeTab }: { activeTab: WidgetTab },\n): UseLeaderboardResult {\n const [data, setData] = useState<LeaderboardPayload | null>(null)\n const [loading, setLoading] = useState(false)\n const [refreshCount, setRefreshCount] = useState(0)\n\n const inFlightRef = useRef(false)\n const conversationRef = useRef(conversation)\n conversationRef.current = conversation\n\n useEffect(() => {\n // The Games hub's stat row (rank, streak) reads the same payload.\n if (activeTab !== 'leaderboard' && activeTab !== 'games') return\n let active = true\n\n const doFetch = async (): Promise<void> => {\n const conv = conversationRef.current\n if (!conv || inFlightRef.current) return\n inFlightRef.current = true\n setLoading(true)\n try {\n const result = await conv.getLeaderboard()\n if (active) setData(result)\n } catch {\n // swallow; keep previous data\n } finally {\n inFlightRef.current = false\n if (active) setLoading(false)\n }\n }\n\n void doFetch()\n return () => { active = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [activeTab, refreshCount])\n\n const refresh = useCallback(() => {\n setRefreshCount((c) => c + 1)\n }, [])\n\n return { data, loading, refresh }\n}\n","import type { MatchState, ScheduleGroup } from '@sensiblestats/widget-sdk'\n\n/**\n * The single question \"is this match being presented as live right now\". Both sides of the seam\n * must ask it the same way: TodayPanel uses it to pick the live band, CompetitionGroup uses its\n * negation to decide what stays in the group. If the two ever disagree a match falls through the\n * gap and renders nowhere — that is a defect this codebase has already shipped once.\n *\n * `pollStale` is OUR fetch failing, which is a real reason to stop trusting every state at once.\n * There is deliberately no per-match staleness test here; see the note in FixtureRow.\n */\nexport function isTreatedLive(state: MatchState | undefined, pollStale: boolean): boolean {\n return state?.phase === 'live' && !pollStale\n}\n\n/**\n * A match the Today tab has no reason to keep listing. The schedule endpoint already excludes\n * terminal matches server-side (LiveMonitorScheduleComposer filters Match.MatchState), but the\n * client caches a day's schedule in localStorage for six hours — so a match that finishes while\n * the panel is open would linger in a list a fresh load would not show it in. This closes that\n * gap so both paths agree.\n *\n * fullTime only, deliberately. `postponed` arises server-side when a fixture has no kickoff\n * timestamp, which the schedule query already excludes, and hiding a postponed fixture from the\n * day it was scheduled for would be a different decision than the one being made here.\n */\nexport function isFinished(state: MatchState | undefined): boolean {\n return state?.phase === 'fullTime'\n}\n\n/**\n * What the Today tab actually contains, after the finished matches leave. This is the ONE answer\n * both the panel and the tab strip read: TodayPanel renders it, and `hasToday` decides from its\n * length whether the tab exists at all. Deciding the tab from the raw schedule instead is what\n * shipped a Today tab opening onto a blank panel once every match of the day had ended.\n */\nexport function visibleGroupsOf(\n groups: readonly ScheduleGroup[],\n states: Record<number, MatchState>,\n): ScheduleGroup[] {\n return groups\n .map((group) => ({ ...group, matches: group.matches.filter((m) => !isFinished(states[m.matchId])) }))\n .filter((group) => group.matches.length > 0)\n}\n","import { createContext, useContext } from 'react'\nimport type { EventLogger } from '@sensiblestats/widget-sdk'\n\nexport const EventLogContext = createContext<EventLogger | null>(null)\n\nexport function useEventLog(): EventLogger | null {\n return useContext(EventLogContext)\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { BrandMark } from './BrandMark'\nimport { GreetingBubble } from './GreetingBubble'\n\n// Only rendered while the panel is closed. The dynamic greeting popup takes\n// precedence over the static greeting and is dismissable; both open the panel.\n//\n// introAllowed/onIntroStart drive the one-shot attention animation (the FAB\n// nudges, then the greeting types in). The latch below fires it once, the first\n// time a bubble appears; onIntroStart lets the parent record that so it never\n// replays when the FAB remounts on a later panel close. Refreshing the page\n// remounts the whole widget and re-arms it.\nexport function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = 'Dismiss', introAllowed = false, onIntroStart }: { label: string; greeting?: string; popupText?: string | null; logoUrl?: string; onOpen: () => void; onDismissPopup: () => void; dismissLabel?: string; introAllowed?: boolean; onIntroStart?: () => void }): JSX.Element {\n const bubble = popupText ?? greeting\n const [intro, setIntro] = useState(false)\n const armedRef = useRef(introAllowed)\n useEffect(() => {\n if (armedRef.current && bubble) {\n armedRef.current = false\n setIntro(true)\n onIntroStart?.()\n }\n }, [bubble, onIntroStart])\n return (\n <div className={intro ? 'ss-w-fab-wrap ss-w-intro' : 'ss-w-fab-wrap'}>\n {bubble ? <GreetingBubble text={bubble} onOpen={onOpen} onDismiss={popupText ? onDismissPopup : undefined} dismissLabel={dismissLabel} /> : null}\n <button type=\"button\" className=\"ss-w-fab\" aria-label={label} onClick={onOpen}>\n <BrandMark logoUrl={logoUrl} className=\"ss-w-fab-mark\" />\n </button>\n </div>\n )\n}\n","import { useState } from 'react'\nimport { SsMark } from './Icons'\n\n// Operator logo with a hard fallback to the built-in SS mark: a missing or\n// broken logoUrl must never leave a blank in the header or launcher.\nexport function BrandMark({ logoUrl, className }: { logoUrl?: string; className?: string }): JSX.Element {\n const [failed, setFailed] = useState(false)\n if (!logoUrl || failed) return <SsMark className={className} />\n return <img className={className} src={logoUrl} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n}\n","// SensibleStats brand mark, inlined as a data URI so the published widget\n// bundle stays self-contained (no external asset hosting / CORS concerns\n// for third-party embeds).\nexport const SS_LOGO_DATA_URI = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAYAAAAuSOLAAAAAAXNSR0IArs4c6QAAAJplWElmTU0AKgAAAAgAAwESAAMAAAABAAEAAAExAAIAAAA9AAAAModpAAQAAAABAAAAcAAAAABBZG9iZSBQaG90b3Nob3AgMjYuMTAgKDIwMjUwNzMwLm0uMzE2NiAwN2IxMjM0KSAgKE1hY2ludG9zaCkAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAI6oAMABAAAAAEAAAI6AAAAACwGtVwAAAQwaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6QzBGRTM5NjM5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6QzBGRTM5NjI5NEJEMTFGMEJGNjZEMjUyN0U0MzU5RUM8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0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\"\n","// SensibleStats brand mark, rendered from the official logo asset.\nimport { SS_LOGO_DATA_URI } from '../assets/logo'\n\nexport function SsMark({ className }: { className?: string }): JSX.Element {\n return <img className={className} src={SS_LOGO_DATA_URI} alt=\"\" aria-hidden=\"true\" />\n}\nexport function SendIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M3 20l18-8L3 4v6l12 2-12 2z\" /></svg>\n}\nexport function CloseIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" d=\"M18 6L6 18M6 6l12 12\" stroke=\"currentColor\" strokeWidth=\"2\" /></svg>\n}\nexport function ChevronIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M9 5l7 7-7 7\" /></svg>\n}\nexport function NewChatIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" d=\"M12 5v14M5 12h14\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" /></svg>\n}\nexport function KebabIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><g fill=\"currentColor\"><circle cx=\"12\" cy=\"5\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"19\" r=\"1.6\" /></g></svg>\n}\n\n// Dashboard tile icons are emoji (matching the betting widget mockup), not the old monochrome\n// line glyphs: they carry their own colour and read at a larger size. Rendered as text.\nconst DASHBOARD_EMOJI: Record<string, string> = {\n football: '⚽', 'goal-net': '🥅', btts: '🤝',\n card: '🟨', 'corner-flag': '🚩', player: '👤',\n target: '🎯', trophy: '🏆', 'chart-line': '📈',\n 'chart-bar': '📊', chat: '💬', fire: '🔥', sparkle: '✨',\n}\n\nexport function DashboardIcon({ name }: { name: string }): JSX.Element {\n // hasOwnProperty (not `in`, not `?? fallback`) so a prototype member name like 'toString'\n // resolves to the fallback emoji rather than an inherited function or a stray property value.\n const glyph = Object.prototype.hasOwnProperty.call(DASHBOARD_EMOJI, name)\n ? DASHBOARD_EMOJI[name]\n : DASHBOARD_EMOJI.target\n return <span className=\"ss-w-dash-emoji\" aria-hidden=\"true\">{glyph}</span>\n}\n","export function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = 'Dismiss' }: { text: string; onOpen?: () => void; onDismiss?: () => void; dismissLabel?: string }): JSX.Element {\n return (\n <div className=\"ss-w-greeting\" role=\"note\">\n <button type=\"button\" className=\"ss-w-greeting-body\" onClick={onOpen}>\n <span className=\"ss-w-greeting-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span>\n <span className=\"ss-w-greeting-text\">{text}</span>\n </button>\n {onDismiss ? (\n <button type=\"button\" className=\"ss-w-greeting-x\" aria-label={dismissLabel} onClick={onDismiss}>×</button>\n ) : null}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { GameSummary, LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { DashboardTapHandler } from '../dashboardTap'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { MatchDiscoveryController } from '../useMatchDiscovery'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { TabBar } from './TabBar'\nimport { MatchesPanel, OddsPanel } from './MonitorTabs'\nimport { TodayPanel } from './TodayPanel'\nimport { GamesPanel } from './GamesPanel'\nimport { LeaderboardPanel } from './LeaderboardPanel'\nimport { visibleGroupsOf } from '../liveClock'\n\n// Mirrors the panel's fullscreen breakpoint in widget.css (@media max-width: 639px).\n// The panel only traps the page — and is thus truly modal — when it fills the viewport.\nconst FULLSCREEN_QUERY = '(max-width: 639px)'\n\nfunction useIsModal(): boolean {\n const [modal, setModal] = useState(false)\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n const mql = window.matchMedia(FULLSCREEN_QUERY)\n const sync = (): void => setModal(mql.matches)\n sync()\n mql.addEventListener('change', sync)\n return () => mql.removeEventListener('change', sync)\n }, [])\n return modal\n}\n\nexport function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation }: {\n controller: ChatController\n ui: UiConfig\n slip: SlipHandlerProps\n onDashboardTap?: DashboardTapHandler\n /** Optional -- absent (feature off / not threaded) renders today's DOM byte-identically. */\n monitor?: LiveMonitorController\n /** Optional -- absent means the Today tab never qualifies (see hasToday below). */\n discovery?: MatchDiscoveryController\n /** Games hook result; absent for non-club operators. */\n gamesResult?: { enabled: boolean; games: GameSummary[]; loading: boolean; refresh: () => void }\n /** Leaderboard hook result; absent for non-club operators. */\n leaderboardResult?: { data: LeaderboardPayload | null; loading: boolean; refresh: () => void }\n /** True when the operator user is logged in (operatorUserId is set). */\n loggedIn?: boolean\n /** Conversation instance threaded down to GameScreenHost for game config fetching + play submits. */\n conversation?: GamePlayConversation | null\n}): JSX.Element {\n const { state, close, stop, send, reset } = controller\n const isModal = useIsModal()\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close() }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [close])\n\n // Composer always switches the visible tab to chat BEFORE the message is sent, so a reply\n // streaming in is never invisible behind the Matches/Odds tab.\n const handleSend = (text: string) => {\n monitor?.setActiveTab('chat')\n send(text)\n }\n\n // A reply landing while the user is on another tab must surface the chat dot -- markChatActivity\n // is idempotent (setChatDot(true) on an already-true dot is a no-op re-render), so re-running\n // this on every streaming/message-count change is safe.\n useEffect(() => {\n if (monitor && monitor.activeTab !== 'chat' && state.isStreaming) monitor.markChatActivity()\n }, [monitor, state.isStreaming, state.messages.length])\n\n return (\n <div className=\"ss-w-panel\" role=\"dialog\" aria-modal={isModal} aria-label={ui.chatDialogLabel}>\n <ChatHeader\n onClose={close}\n closeLabel={ui.closeChat}\n logoUrl={ui.logoUrl}\n headerTitle={ui.headerTitle}\n onNewConversation={reset}\n canReset={state.messages.length > 0}\n newConversationLabel={ui.newConversation}\n moreOptionsLabel={ui.moreOptions}\n />\n {monitor && (\n <TabBar\n monitor={monitor}\n ui={ui}\n matchCount={monitor.pins.filter((p) => p.kind === 'match').length}\n oddsCount={monitor.pins.filter((p) => p.kind !== 'match').length}\n todayCount={discovery?.liveCount ?? 0}\n hasToday={discovery ? visibleGroupsOf(discovery.groups, discovery.states).length > 0 : false}\n gamesEnabled={gamesResult?.enabled ?? false}\n />\n )}\n {/* MessageList stays MOUNTED across tab switches so its scroll-anchoring refs survive --\n `display: contents` makes the wrapper transparent to .ss-w-panel's flex layout when the\n chat tab is active. `display: none` would zero the list's clientHeight and reset its\n scrollTop, defeating MessageList's own scroll-anchoring math (and silently consuming its\n reserved-turn-space effect) the moment a tab switch happens mid-stream. Absolute-position\n + visibility:hidden instead: the list keeps its box (so its scroll position survives) but\n is pulled out of .ss-w-panel's flex flow (so it doesn't fight the active panel for space)\n and is neither painted nor interactive. `.ss-w-panel` is `position: fixed`, which already\n serves as the containing block for this. */}\n <div\n style={\n !monitor || monitor.activeTab === 'chat'\n ? { display: 'contents' }\n // display:flex (not the default block) is required here: MessageList's root carries\n // `.ss-w-list { flex: 1; ... }`, which only takes effect on a flex-item child. Without\n // it this wrapper lays out as a plain block, .ss-w-list collapses to its own\n // content height (no longer clipped by .ss-w-panel's fixed height), scrollHeight\n // drops to equal clientHeight, and the browser clamps its scrollTop to 0 --\n // silently destroying the exact scroll position this hidden-not-unmounted\n // wrapper exists to preserve.\n : { position: 'absolute', inset: 0, visibility: 'hidden', display: 'flex', flexDirection: 'column' }\n }\n >\n <MessageList controller={controller} ui={ui} slip={slip} onDashboardTap={onDashboardTap} monitor={monitor} />\n </div>\n {monitor && discovery && monitor.activeTab === 'today' && <TodayPanel discovery={discovery} ui={ui} monitor={monitor} />}\n {monitor && monitor.activeTab === 'following' && <MatchesPanel monitor={monitor} ui={ui} slip={slip} />}\n {monitor && monitor.activeTab === 'odds' && <OddsPanel monitor={monitor} ui={ui} slip={slip} />}\n {monitor && monitor.activeTab === 'games' && gamesResult && (\n <GamesPanel loggedIn={!!loggedIn} games={gamesResult.games} ui={ui} conversation={conversation} leaderboard={leaderboardResult?.data ?? null} />\n )}\n {monitor && monitor.activeTab === 'leaderboard' && leaderboardResult && (\n <LeaderboardPanel\n loggedIn={!!loggedIn}\n data={leaderboardResult.data}\n loading={leaderboardResult.loading}\n onPlay={() => monitor.setActiveTab('games')}\n ui={ui}\n />\n )}\n {/* The composer is a chat affordance; hide it on the Games/Leaderboard tabs where it only confuses. */}\n {(!monitor || (monitor.activeTab !== 'games' && monitor.activeTab !== 'leaderboard')) && (\n <ChatInput placeholder={ui.placeholder} streaming={state.isStreaming} onSend={handleSend} onStop={stop} stopLabel={ui.stopResponse} sendLabel={ui.sendMessage} />\n )}\n </div>\n )\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { CloseIcon, KebabIcon } from './Icons'\nimport { BrandMark } from './BrandMark'\n\nexport function ChatHeader({\n onClose,\n closeLabel = 'Close chat',\n logoUrl,\n headerTitle,\n onNewConversation,\n canReset,\n newConversationLabel = 'New conversation',\n moreOptionsLabel = 'More options',\n}: {\n onClose: () => void\n closeLabel?: string\n logoUrl?: string\n headerTitle?: string\n onNewConversation?: () => void\n canReset?: boolean\n newConversationLabel?: string\n moreOptionsLabel?: string\n}): JSX.Element {\n const [menuOpen, setMenuOpen] = useState(false)\n const wrapRef = useRef<HTMLDivElement>(null)\n const kebabRef = useRef<HTMLButtonElement>(null)\n const firstItemRef = useRef<HTMLButtonElement>(null)\n\n // Secondary actions (currently just \"New conversation\") live behind the kebab; Close stays a\n // one-tap control since it is the most frequent action.\n const hasMenu = !!(canReset && onNewConversation)\n\n useEffect(() => {\n if (menuOpen) firstItemRef.current?.focus()\n }, [menuOpen])\n\n useEffect(() => {\n if (!menuOpen) return\n const onPointer = (e: MouseEvent) => {\n if (!wrapRef.current?.contains(e.target as Node)) setMenuOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setMenuOpen(false)\n kebabRef.current?.focus()\n }\n }\n document.addEventListener('mousedown', onPointer)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onPointer)\n document.removeEventListener('keydown', onKey)\n }\n }, [menuOpen])\n\n const runNewConversation = (): void => {\n setMenuOpen(false)\n onNewConversation?.()\n }\n\n return (\n <header className=\"ss-w-header\">\n <BrandMark logoUrl={logoUrl} className=\"ss-w-header-mark\" />\n <span className=\"ss-w-header-title\">{headerTitle ?? 'SensibleStats'}</span>\n {hasMenu ? (\n <div className=\"ss-w-menu-wrap\" ref={wrapRef}>\n <button\n type=\"button\"\n className=\"ss-w-kebab\"\n ref={kebabRef}\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n aria-label={moreOptionsLabel}\n onClick={() => setMenuOpen((open) => !open)}\n >\n <KebabIcon />\n </button>\n {menuOpen ? (\n <div className=\"ss-w-menu\" role=\"menu\" aria-label={moreOptionsLabel}>\n <button\n type=\"button\"\n className=\"ss-w-menu-item\"\n role=\"menuitem\"\n ref={firstItemRef}\n onClick={runNewConversation}\n >\n <span>{newConversationLabel}</span>\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <button type=\"button\" className=\"ss-w-close\" aria-label={closeLabel} onClick={onClose}>\n <CloseIcon />\n </button>\n </header>\n )\n}\n","import { useEffect, useRef } from 'react'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { DashboardTapHandler } from '../dashboardTap'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { ChatMessage } from './ChatMessage'\nimport { IntentChips } from './IntentChips'\nimport { ActionButtons } from './ActionButtons'\nimport { isPinnedToBottom } from '../scroll'\nimport type { Message } from '../reducer'\n\n// The element to pin to the top when a new turn begins: the user's question if\n// this turn has one (so the reply reads from just below it), otherwise the\n// assistant turn itself (an auto-greeting or greeting dashboard has no user\n// bubble, and we still want its top in view rather than its bottom).\nfunction turnAnchor(messages: Message[]): { turnId: string; anchorId: string } | null {\n const last = messages[messages.length - 1]\n if (!last || last.role !== 'assistant') return null\n const prev = messages[messages.length - 2]\n return { turnId: last.id, anchorId: prev && prev.role === 'user' ? prev.id : last.id }\n}\n\nexport function MessageList({ controller, ui, slip, onDashboardTap, monitor }: {\n controller: ChatController\n ui: UiConfig\n slip: SlipHandlerProps\n onDashboardTap?: DashboardTapHandler\n monitor?: LiveMonitorController\n}): JSX.Element {\n const { state, send } = controller\n const listRef = useRef<HTMLDivElement>(null)\n const endRef = useRef<HTMLDivElement>(null)\n // Follow the stream only while the user is at the bottom. pinnedRef is updated\n // on real scroll events (content growth fires none), so a user who scrolls up\n // stays put when late content — suggested actions, status — arrives.\n const pinnedRef = useRef(true)\n // The turn id we have already anchored to the top. On a new turn we pin its\n // start to the top so a long reply reads from its beginning instead of the\n // viewport jumping to the bottom of the answer.\n const anchoredTurnRef = useRef<string | null>(null)\n useEffect(() => {\n const anchor = turnAnchor(state.messages)\n const list = listRef.current\n if (anchor && anchor.turnId !== anchoredTurnRef.current) {\n anchoredTurnRef.current = anchor.turnId\n // Reserve a viewport of space below the new turn before scrolling, so the\n // anchor can actually reach the top even while the reply is still empty\n // (without it the scroll lands at the bottom, onScroll re-pins to bottom,\n // and the streaming reply then follows the bottom down). The spacer is the\n // endRef element; it collapses again once the turn stops streaming.\n //\n // Only reserve while the turn is actively streaming. A turn first anchored\n // when it is ALREADY complete -- panel opened after the greeting finished,\n // or a restored/cross-tab-synced conversation -- has its full height, so it\n // needs no spacer; reserving one here would never be collapsed (this branch\n // returns, and the collapse below only runs on a later !isStreaming pass\n // that never comes), leaving a viewport of dead scroll space below content.\n if (endRef.current && list) endRef.current.style.height = state.isStreaming ? `${list.clientHeight}px` : ''\n // Top-anchored, so the list is no longer pinned to the bottom; streaming\n // updates below won't yank it back down for the rest of this turn.\n pinnedRef.current = false\n list?.querySelector(`[data-msg-id=\"${anchor.anchorId}\"]`)?.scrollIntoView({ block: 'start' })\n return\n }\n // Turn finished: drop the reserved space (content above is unaffected, so the\n // anchored message keeps its position).\n if (!state.isStreaming && endRef.current) endRef.current.style.height = ''\n if (pinnedRef.current) endRef.current?.scrollIntoView({ block: 'end' })\n }, [state.messages, state.status, state.isStreaming])\n\n // Chips are always emitted by the server; the widget prefers the dashboard and\n // hides the chips client-side once a greeting dashboard, a club fan dashboard, or a\n // user message exists.\n const hasUserMessage = state.messages.some((m) => m.role === 'user')\n const hasDashboard = state.messages.some((m) => m.role === 'assistant' && (m.greetingDashboard || m.clubFanDashboard))\n return (\n <div\n className=\"ss-w-list\"\n aria-live=\"polite\"\n ref={listRef}\n onScroll={() => { if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current) }}\n >\n {state.messages.map((m) => (\n <ChatMessage\n key={m.id}\n message={m}\n disabled={state.isStreaming}\n onAct={(a) => send(a.message, { actionId: a.actionId, actionRef: a.actionRef, displayText: a.label })}\n onTap={(tile, index) => {\n send(tile.actionValue, tile.actionRef\n ? { actionRef: tile.actionRef, displayText: tile.title }\n : { displayText: tile.title })\n // Only fires from within the dashboard this message itself rendered (ChatMessage\n // renders GreetingDashboard only when message.greetingDashboard is set), so the\n // dashboard -- and its layout -- is guaranteed present here.\n if (m.role === 'assistant' && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout)\n }}\n ui={ui}\n slip={slip}\n monitor={monitor}\n />\n ))}\n {state.isStreaming && state.actionsLoading ? <ActionButtons actions={[]} loading onAct={() => {}} /> : null}\n {state.status ? <div className=\"ss-w-status\">{state.status}</div> : null}\n {state.error ? (\n <div className=\"ss-w-error\" role=\"alert\">\n <span>{'message' in state.error ? state.error.message : ui.somethingWentWrong}</span>\n <button type=\"button\" className=\"ss-w-retry\" onClick={() => controller.retry()}>{ui.retry}</button>\n </div>\n ) : null}\n {!hasUserMessage && !hasDashboard ? <IntentChips chips={state.starters} onPick={(t) => send(t)} /> : null}\n <div ref={endRef} className=\"ss-w-turn-spacer\" aria-hidden=\"true\" />\n </div>\n )\n}\n","import ReactMarkdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst components: Components = {\n a: ({ children, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"ss-w-md-link\">{children}</a>\n ),\n table: ({ children }) => (\n <div className=\"ss-w-table-wrap\"><table className=\"ss-w-md-table\">{children}</table></div>\n ),\n ul: ({ children }) => <ul className=\"ss-w-md-ul\">{children}</ul>,\n ol: ({ children }) => <ol className=\"ss-w-md-ol\">{children}</ol>,\n code: ({ children }) => <code className=\"ss-w-md-code\">{children}</code>,\n}\n\nexport function Markdown({ text }: { text: string }): JSX.Element {\n return (\n <div className=\"ss-w-md\">\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>{text}</ReactMarkdown>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { CardVM, CardScope, StatCell } from '../model'\n\nconst MAX_VISIBLE = 3\nconst RECORD_RE = /^(\\d+)-(\\d+)-(\\d+)$/\n\nfunction initials(name: string): string {\n return name.split(/\\s+/).slice(0, 2).map((w) => w[0] ?? '').join('').toUpperCase()\n}\n\n// \"2026/2027\" -> \"26/27\", \"2026\" -> \"26\"; leaves any non-4-digit token untouched.\nfunction shortSeason(season: string): string {\n return season.replace(/\\d{4}/g, (year) => year.slice(2))\n}\n\nfunction Crest({ image, label }: { image: string; label?: string }): JSX.Element {\n return (\n <span\n className=\"ss-w-ecard-crest\"\n style={{ backgroundImage: `url(${image})` }}\n {...(label ? { role: 'img', title: label, 'aria-label': label } : { 'aria-hidden': 'true' as const })}\n />\n )\n}\n\n// Proportional win/draw/loss bar. Rendered for any stat value shaped \"w-d-l\".\nfunction FormBar({ w, d, l }: { w: number; d: number; l: number }): JSX.Element | null {\n if (w + d + l === 0) return null\n return (\n <span className=\"ss-w-form\" aria-hidden=\"true\">\n {w > 0 ? <span className=\"ss-w-form-w\" style={{ flexGrow: w }} /> : null}\n {d > 0 ? <span className=\"ss-w-form-d\" style={{ flexGrow: d }} /> : null}\n {l > 0 ? <span className=\"ss-w-form-l\" style={{ flexGrow: l }} /> : null}\n </span>\n )\n}\n\nfunction StatCellView({ s }: { s: StatCell }): JSX.Element {\n const m = RECORD_RE.exec(s.value)\n if (m) {\n return (\n <div className=\"ss-w-ecard-cell\">\n <span className=\"ss-w-ecard-cval\"><FormBar w={Number(m[1])} d={Number(m[2])} l={Number(m[3])} /></span>\n <span className=\"ss-w-ecard-clabel\">{s.value}</span>\n </div>\n )\n }\n return (\n <div className=\"ss-w-ecard-cell\">\n <span className=\"ss-w-ecard-cval\">{s.value}</span>\n <span className=\"ss-w-ecard-clabel\">{s.label}</span>\n </div>\n )\n}\n\nfunction StatStrip({ stats }: { stats: StatCell[] }): JSX.Element | null {\n if (stats.length === 0) return null\n const cols = Math.min(stats.length, 4)\n return (\n <div className=\"ss-w-ecard-strip\" style={{ gridTemplateColumns: `repeat(${cols}, 1fr)` }}>\n {stats.map((s) => <StatCellView key={s.label + s.value} s={s} />)}\n </div>\n )\n}\n\nfunction CardHeader({ c, showScopeCrest }: { c: CardVM; showScopeCrest: boolean }): JSX.Element {\n const onlyScope = c.scopes.length === 1 ? c.scopes[0]! : null\n return (\n <div className=\"ss-w-ecard-hd\">\n <span\n className={c.kind === 'team' ? 'ss-w-thumb ss-w-team' : 'ss-w-thumb'}\n style={c.image ? { backgroundImage: `url(${c.image})` } : undefined}\n >\n {c.image ? '' : initials(c.name)}\n </span>\n <span className=\"ss-w-ecard-idtext\">\n <span className=\"ss-w-nm\">{c.name}</span>\n {c.sub ? <span className=\"ss-w-sub\">{c.sub}</span> : null}\n </span>\n <span className=\"ss-w-ecard-meta\">\n {showScopeCrest && onlyScope?.image ? <Crest image={onlyScope.image} label={onlyScope.label} /> : null}\n {c.season ? <span className=\"ss-w-ecard-season\">{shortSeason(c.season)}</span> : null}\n </span>\n </div>\n )\n}\n\nfunction ScopeTabs({ scopes, active, onSelect }: { scopes: CardScope[]; active: number; onSelect: (i: number) => void }): JSX.Element {\n return (\n <div className=\"ss-w-ecard-scopes\" role=\"tablist\">\n {scopes.map((s, i) => (\n <button\n key={String(s.competitionId ?? 'all')}\n type=\"button\"\n role=\"tab\"\n className=\"ss-w-ecard-scope\"\n aria-selected={i === active}\n aria-label={s.label}\n title={s.label}\n onClick={() => onSelect(i)}\n >\n {s.image ? <Crest image={s.image} /> : s.label}\n </button>\n ))}\n </div>\n )\n}\n\nfunction EntityCardItem({ c }: { c: CardVM }): JSX.Element {\n const [active, setActive] = useState(0)\n const hasBody = c.scopes.length > 0\n if (!hasBody) {\n return (\n <div className=\"ss-w-ecard ss-w-ecard-bare\" data-kind={c.kind}>\n <CardHeader c={c} showScopeCrest={false} />\n </div>\n )\n }\n const multi = c.scopes.length > 1\n const scope = c.scopes[multi ? (c.scopes[active] ? active : 0) : 0]!\n return (\n <div className=\"ss-w-ecard\" data-kind={c.kind}>\n <CardHeader c={c} showScopeCrest={!multi} />\n {multi ? <ScopeTabs scopes={c.scopes} active={active} onSelect={setActive} /> : null}\n <StatStrip stats={scope.stats} />\n </div>\n )\n}\n\nexport function EntityCardList({ cards, disabled, showLessLabel = 'Show less', showMoreLabel = (n: number) => `Show ${n} more` }: { cards: CardVM[]; disabled?: boolean; showLessLabel?: string; showMoreLabel?: (n: number) => string }): JSX.Element | null {\n const [expanded, setExpanded] = useState(false)\n if (cards.length === 0) return null\n const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE)\n const overflow = cards.length - MAX_VISIBLE\n return (\n <div className=\"ss-w-cards\">\n {visible.map((c) => <EntityCardItem key={c.id} c={c} />)}\n {overflow > 0 ? (\n <button type=\"button\" className=\"ss-w-cards-more\" disabled={disabled} onClick={() => setExpanded((v) => !v)}>\n {expanded ? showLessLabel : showMoreLabel(overflow)}\n </button>\n ) : null}\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { InsightVM, StatCell } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { useEventLog } from '../eventLogContext'\nimport { AddToSlipButton } from './AddToSlipButton'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { Crest } from './Crest'\nimport { PinToggle } from './PinToggle'\n\nfunction StatRows({ stats }: { stats: StatCell[] }): JSX.Element {\n return (\n <div className=\"ss-w-bi-rows\">\n {stats.map((s) => (\n <div key={`${s.label}:${s.value}`} className=\"ss-w-bi-row\">\n <span className=\"ss-w-bi-row-lbl\">{s.label}</span>\n <span className=\"ss-w-bi-row-num\">{s.value}</span>\n </div>\n ))}\n </div>\n )\n}\n\nfunction ScopedStats({ scopes }: { scopes: NonNullable<InsightVM['scopes']> }): JSX.Element {\n const [active, setActive] = useState(0)\n const current = scopes[active] ?? scopes[0] ?? { key: '', label: '', stats: [] }\n return (\n <div className=\"ss-w-bi-scoped\">\n <div className=\"ss-w-bi-scopes\" role=\"group\">\n {scopes.map((s, i) => (\n <button key={s.key} type=\"button\" className=\"ss-w-bi-chip\" aria-pressed={i === active} onClick={() => setActive(i)}>\n {s.label}\n </button>\n ))}\n </div>\n <StatRows key={current.key} stats={current.stats} />\n </div>\n )\n}\n\nfunction hasStatsContent(it: InsightVM): boolean {\n return (!!it.scopes && it.scopes.length >= 2) || it.stats.length > 0\n}\n\n// The reason-to-bet prose is clamped to two lines; one right-chevron expands it to the full text\n// AND the supporting stats together (the mock's single \">\" affordance). Collapsed by default so the\n// card stays scannable. The arrow only appears when there is something more to reveal — stats, or a\n// reason long enough to be clamped.\nfunction ReasonStrip({ it, ui }: { it: InsightVM; ui?: UiConfig }): JSX.Element | null {\n const [open, setOpen] = useState(false)\n const log = useEventLog()\n const hasScopes = !!it.scopes && it.scopes.length >= 2\n const hasStats = hasStatsContent(it)\n const hasText = !!it.text\n if (!hasText && !hasStats) return null\n const expandable = hasStats || (it.text?.length ?? 0) > 90\n const onToggle = (): void => {\n setOpen((v) => {\n const next = !v\n if (next) log?.log({ name: 'insight_expand', entityType: 'match', entityId: String(it.matchId) })\n return next\n })\n }\n return (\n <div className=\"ss-w-bi-reason\">\n <span className=\"ss-w-bi-chart\" aria-hidden=\"true\" />\n <div className=\"ss-w-bi-reason-body\">\n {hasText ? <p className={`ss-w-bi-text${open ? '' : ' ss-w-bi-text-clamp'}`}>{it.text}</p> : null}\n {open && hasStats ? (hasScopes ? <ScopedStats scopes={it.scopes!} /> : <StatRows stats={it.stats} />) : null}\n </div>\n {expandable ? (\n <button\n type=\"button\"\n className=\"ss-w-bi-expand\"\n aria-expanded={open}\n aria-label={open ? ui?.hideStats ?? 'Hide stats' : ui?.showStats ?? 'Show stats'}\n onClick={onToggle}\n >\n <span className={`ss-w-bi-arrow${open ? ' ss-w-bi-arrow-open' : ''}`} aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n )\n}\n\n// Renders the fixture as the card's hero: the named team pair when present, else the prose\n// fixture, else the competition (the fallback that becomes the header hero when there is no\n// fixture at all). On a fixture card this fills its own line; the competition rides the meta line\n// above it (u350 two-tier).\nfunction CardFixture({ it }: { it: InsightVM }): JSX.Element | null {\n if (it.homeTeamName && it.awayTeamName) {\n return (\n <>\n <Crest kind=\"team\" url={it.homeCrest} name={it.homeTeamName} />\n <span className=\"ss-w-bi-team\">{it.homeTeamName}</span>\n <span className=\"ss-w-bi-vs\" aria-hidden=\"true\">vs</span>\n <span className=\"ss-w-bi-team\">{it.awayTeamName}</span>\n <Crest kind=\"team\" url={it.awayCrest} name={it.awayTeamName} />\n </>\n )\n }\n if (it.fixture) return <span className=\"ss-w-bi-fixture-txt\">{it.fixture}</span>\n if (it.competition) {\n return (\n <>\n <Crest kind=\"comp\" url={it.competitionCrest} name={it.competition} />\n <span className=\"ss-w-bi-comp\">{it.competition}</span>\n </>\n )\n }\n return null\n}\n\nfunction InsightCard(\n { it, ui, slip, monitor }: { it: InsightVM; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController },\n): JSX.Element {\n const live = it.isLive || it.phase === 'live'\n // Prefer the server-rendered chip (operator timezone + language); fall back to browser-zone\n // formatting of the raw instant for older servers that don't send a label.\n const kickoffFallback = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : undefined\n const kickoff = it.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : undefined)\n const hasNamedTeams = !!it.homeTeamName && !!it.awayTeamName\n // A fixture (team pair or prose string) is the card's hero and gets its own full-width line so\n // long club names stop truncating; the competition, kickoff and match pin sit on a quieter meta\n // line above it. Only when there is no fixture does the competition itself become the hero on a\n // single header line (u350 two-tier).\n const leftIsFixture = hasNamedTeams || !!it.fixture\n const showPin = !!monitor && it.pinEnabled\n const showHeader = leftIsFixture || !!it.competition || live || !!kickoff || showPin\n // live badge + kickoff + match pin: shared by the fixture card's meta line and the\n // competition-hero card's header-right, so the trio renders identically on both. The pin here\n // pins the MATCH; the selection pin lives on the pick row below (2026-09-06 ruling: the two\n // behaviors are never combined).\n const headerControls = (\n <>\n {live ? (\n <span className=\"ss-w-bi-live\"><span className=\"ss-w-bi-live-dot\" aria-hidden=\"true\" />{ui?.liveLabel ?? 'Live'}</span>\n ) : null}\n {kickoff ? <span className=\"ss-w-bi-kick\">{kickoff}</span> : null}\n {showPin && ui ? (\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: it.matchId }} />\n ) : null}\n </>\n )\n return (\n <div className=\"ss-w-binsight\">\n {showHeader ? (\n leftIsFixture ? (\n <div className=\"ss-w-bi-head\">\n {(it.competition || live || kickoff || showPin) ? (\n <div className=\"ss-w-bi-meta\">\n <span className=\"ss-w-bi-meta-left\">\n {it.competition ? (\n <>\n <Crest kind=\"comp\" url={it.competitionCrest} name={it.competition} />\n <span className=\"ss-w-bi-comp\">{it.competition}</span>\n </>\n ) : null}\n </span>\n <span className=\"ss-w-bi-meta-right\">{headerControls}</span>\n </div>\n ) : null}\n <div className=\"ss-w-bi-fixture-line\"><CardFixture it={it} /></div>\n </div>\n ) : (\n <div className=\"ss-w-bi-header\">\n <span className=\"ss-w-bi-header-left\"><CardFixture it={it} /></span>\n <span className=\"ss-w-bi-header-right\">{headerControls}</span>\n </div>\n )\n ) : null}\n <div className=\"ss-w-bi-action\">\n {it.market ? <span className=\"ss-w-bi-market\">{it.market}</span> : null}\n <div className=\"ss-w-bi-pick-row\">\n {it.selection ? <span className=\"ss-w-bi-sel\">{it.selection}</span> : null}\n {it.odds ? (\n <span className=\"ss-w-bi-odds\">\n <b>{it.odds}</b>\n <OddsMovementBadge previous={it.previousOdds} current={it.odds} direction={it.movementDirection} ui={ui} />\n {it.bookmaker ? <span className=\"ss-w-bi-book\">{it.bookmaker}</span> : null}\n </span>\n ) : null}\n <AddToSlipButton it={it} slip={slip} ui={ui} />\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{\n kind: 'selection',\n matchId: it.matchId,\n marketDeveloperName: it.marketDeveloperName,\n selectionLabel: it.selectionLabel,\n line: it.line,\n matchOddsId: it.matchOddsId,\n }}\n />\n ) : null}\n </div>\n </div>\n {it.isMarketFloor ? (\n <span className=\"ss-w-bi-floor\">{ui?.marketFloorLabel ?? 'Market price · not a value pick'}</span>\n ) : null}\n <ReasonStrip it={it} ui={ui} />\n {it.disclaimer ? <p className=\"ss-w-bi-disc\">{it.disclaimer}</p> : null}\n </div>\n )\n}\n\nexport function BettingInsightList(\n { insights, ui, slip, monitor }:\n { insights: InsightVM[]; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController },\n): JSX.Element | null {\n if (!insights || insights.length === 0) return null\n return (\n <div className=\"ss-w-binsights\">\n {insights.map((it) => <InsightCard key={it.id} it={it} ui={ui} slip={slip} monitor={monitor} />)}\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\nimport { isAddToSlipResult, type AddToSlipResult, type SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { toSlipSelection, type InsightVM } from '../model'\nimport { ADD_TO_SLIP_TIMEOUT_MS, isTerminal, resultToToast, slipOutcome, wasAdded, type SlipHandlerProps, type SlipToast } from '../slip'\nimport { useEventLog } from '../eventLogContext'\nimport { Toast } from './Toast'\n\nfunction withTimeout(value: Promise<AddToSlipResult | void>): Promise<AddToSlipResult | void> {\n return Promise.race([\n value,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('add-to-slip timed out')), ADD_TO_SLIP_TIMEOUT_MS)),\n ])\n}\n\nexport function SlipButton(\n { selection, shownOdds, marketName, marketDeveloperName, slip, ui }:\n { selection: SlipSelection | null; shownOdds: string; marketName: string; marketDeveloperName?: string; slip: SlipHandlerProps; ui?: UiConfig },\n): JSX.Element | null {\n const [pending, setPending] = useState(false)\n const [settled, setSettled] = useState(false)\n const [toast, setToast] = useState<SlipToast | null>(null)\n const dismiss = useCallback(() => setToast(null), [])\n const log = useEventLog()\n\n const handler = slip.onAddToSlip\n if (!ui || !handler || !selection) return null\n\n const onClick = async (): Promise<void> => {\n setPending(true)\n // A market/selection with no marketDeveloperName has no entity to report under entityType\n // 'market' -- skip the emit rather than log entityId: undefined (mirrors the PinToggle guard).\n if (marketDeveloperName !== undefined) {\n log?.log({ name: 'slip_click', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName })\n }\n try {\n const raw = await withTimeout(Promise.resolve(handler(selection)))\n // Only a genuine void return means \"assume success\". A non-null value the\n // guard rejects is a broken contract (e.g. an operator forwarding their own\n // backend's reason string, which `any` lets past the compiler) — treating it\n // as void would report a refused bet to the user as added.\n if (raw != null && !isAddToSlipResult(raw)) throw new Error('malformed add-to-slip result')\n const result = raw ?? undefined\n if (marketDeveloperName !== undefined) {\n log?.log({\n name: 'slip_result', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName,\n outcome: slipOutcome(result),\n })\n }\n setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui))\n setSettled(isTerminal(result))\n if (wasAdded(result) && slip.onMarketClicked) {\n try {\n slip.onMarketClicked(marketName)\n } catch {\n // Telemetry must never change what the user sees.\n }\n }\n } catch {\n if (marketDeveloperName !== undefined) {\n log?.log({ name: 'slip_result', entityType: 'market', marketDeveloperName, entityId: marketDeveloperName, outcome: 'timeout' })\n }\n setToast({ kind: 'error', text: ui.slipFailed })\n } finally {\n setPending(false)\n }\n }\n\n return (\n <div className=\"ss-w-slip\">\n <button\n type=\"button\"\n className=\"ss-w-slip-btn\"\n disabled={pending || settled}\n onClick={onClick}\n >\n {settled ? ui.inSlip : ui.addToSlip}\n </button>\n <Toast toast={toast} onDismiss={dismiss} />\n </div>\n )\n}\n\nexport function AddToSlipButton(\n { it, slip, ui }: { it: InsightVM; slip: SlipHandlerProps; ui?: UiConfig },\n): JSX.Element | null {\n const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null\n return (\n <SlipButton\n selection={selection}\n shownOdds={it.odds ?? ''}\n marketName={it.market}\n marketDeveloperName={it.marketDeveloperName}\n slip={slip}\n ui={ui}\n />\n )\n}\n","import { useEffect } from 'react'\nimport type { SlipToast } from '../slip'\n\nconst DISMISS_MS = 4000\n\nexport function Toast({ toast, onDismiss }: { toast: SlipToast | null; onDismiss: () => void }): JSX.Element | null {\n useEffect(() => {\n if (!toast) return\n const timer = setTimeout(onDismiss, DISMISS_MS)\n return () => clearTimeout(timer)\n }, [toast, onDismiss])\n\n if (!toast) return null\n return (\n <div className={`ss-w-toast ss-w-toast-${toast.kind}`} role=\"status\" aria-live=\"polite\">\n {toast.text}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\n\n// One component for both card types. The market-odds row and the insight card must not drift into\n// two visual languages for the same signal, so there is exactly one place this markup exists.\nexport function OddsMovementBadge({\n previous,\n current,\n direction,\n ui,\n}: {\n previous?: string\n current: string\n direction?: 'shortened' | 'drifted'\n ui?: UiConfig\n}): JSX.Element | null {\n if (previous === undefined || direction === undefined) return null\n const directionWord =\n direction === 'shortened' ? (ui?.oddsShortened ?? 'shortened') : (ui?.oddsDrifted ?? 'drifted')\n const label =\n ui?.oddsMoved?.(previous, current, directionWord) ?? `was ${previous}, now ${current}, ${directionWord}`\n return (\n // Strikethrough is invisible to screen readers, so the whole was/now/direction sentence rides\n // on one aria-label and the visual glyphs are hidden from the accessibility tree.\n <span className=\"ss-w-move\" role=\"img\" aria-label={label}>\n <span className=\"ss-w-move-prev\" aria-hidden=\"true\">{previous}</span>\n <span className=\"ss-w-move-arrow\" aria-hidden=\"true\">{direction === 'shortened' ? '▼' : '▲'}</span>\n </span>\n )\n}\n","import { useState } from 'react'\n\nexport function initials(name?: string): string {\n return (name ?? '').trim().slice(0, 1).toUpperCase() || '?'\n}\n\n// Crest is an <img> so a broken/absent URL falls back to a monogram (first initial) -- the design\n// wants the monogram whenever the crest is missing OR fails to load, which a background-image span\n// can't detect. onError flips to the monogram; the fixed sizing keeps the row height stable either way.\nexport function Crest({ url, name, kind }: { url?: string; name?: string; kind: 'team' | 'comp' }): JSX.Element {\n const cls = kind === 'comp' ? 'ss-w-bi-comp-logo' : 'ss-w-bi-crest'\n const [failed, setFailed] = useState(false)\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return <span className={`${cls} ss-w-bi-crest-mono`} aria-hidden=\"true\">{initials(name)}</span>\n}\n","import { useCallback, useState } from 'react'\nimport type { PinRef } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport { pinKey } from '../pinStore'\nimport type { SlipToast } from '../slip'\nimport { useEventLog } from '../eventLogContext'\nimport { Toast } from './Toast'\n\n// One glyph per pinIcon choice, drawn from a single silhouette path so the\n// pinned state can toggle outline (off) → filled (on) without a second asset.\n// The pin keeps its original thumbtack (scaled into a 24 box) so the default\n// look is unchanged in shape; star and bookmark are standard marks.\nconst PIN_GLYPHS: Record<'pin' | 'star' | 'bookmark', { viewBox: string; d: string; strokeWidth: number; transform?: string }> = {\n pin: { viewBox: '0 0 24 24', strokeWidth: 1.4, transform: 'scale(1.5)', d: 'M9.5 1.5 14.5 6.5 13 8l-.5-.5-3 3 .3 2.2-1.4 1.4L5.6 11.3l-3.3 3.3-1-1 3.3-3.3L1.9 7.5l1.4-1.4 2.2.3 3-3L8 2.9z' },\n star: { viewBox: '0 0 24 24', strokeWidth: 2, d: 'M12 2.5l2.9 5.9 6.5.95-4.7 4.58 1.1 6.47L12 17.35 6.1 20.4l1.1-6.47L2.5 9.35l6.5-.95z' },\n bookmark: { viewBox: '0 0 24 24', strokeWidth: 2, d: 'M7 3h10a1.5 1.5 0 0 1 1.5 1.5V21l-6.5-3.6L5.5 21V4.5A1.5 1.5 0 0 1 7 3z' },\n}\n\nexport function PinToggle({ pin, monitor, ui }: {\n pin: Omit<PinRef, 'key'>\n monitor: LiveMonitorController | undefined\n ui: UiConfig\n}): JSX.Element | null {\n const [toast, setToast] = useState<SlipToast | null>(null)\n const dismiss = useCallback(() => setToast(null), [])\n const log = useEventLog()\n\n if (!monitor || !monitor.enabled) return null\n\n const key = pinKey(pin)\n const pinned = monitor.isPinned(key)\n // Match pins and odds pins are separate behaviors (2026-09-06 ruling): each toggle tracks\n // exactly its own pin, and the labels name which one this is.\n const labels = pin.kind === 'match'\n ? { pin: ui.matchPinLabel, unpin: ui.matchUnpinLabel }\n : { pin: ui.pinLabel, unpin: ui.unpinLabel }\n\n const onClick = (): void => {\n const result = monitor.togglePin({ ...pin, key })\n // A market/selection pin with no marketDeveloperName has no entity to report under\n // entityType 'market' -- skip the emit rather than fall back to the match id, which would\n // mislabel a match under a market entityType.\n if ((result === 'added' || result === 'removed') && (pin.kind === 'match' || pin.marketDeveloperName !== undefined)) {\n log?.log({\n name: result === 'added' ? 'pin_add' : 'pin_remove',\n entityType: pin.kind === 'match' ? 'match' : 'market',\n entityId: pin.kind === 'match' ? String(pin.matchId) : pin.marketDeveloperName,\n marketDeveloperName: pin.marketDeveloperName,\n })\n } else if (result === 'match_limit') {\n setToast({ kind: 'error', text: ui.matchLimitToast })\n } else if (result === 'market_limit') {\n setToast({ kind: 'error', text: ui.marketLimitToast })\n }\n }\n\n const glyph = PIN_GLYPHS[ui.pinIcon]\n return (\n <div className=\"ss-w-pin-wrap\">\n <button\n type=\"button\"\n className=\"ss-w-pin\"\n data-on={pinned || undefined}\n data-icon={ui.pinIcon}\n aria-pressed={pinned}\n aria-label={pinned ? labels.unpin : labels.pin}\n onClick={onClick}\n >\n <svg viewBox={glyph.viewBox} aria-hidden=\"true\">\n <path\n transform={glyph.transform}\n d={glyph.d}\n fill={pinned ? 'currentColor' : 'none'}\n stroke={pinned ? 'none' : 'currentColor'}\n strokeWidth={glyph.strokeWidth}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n <Toast toast={toast} onDismiss={dismiss} />\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PinRef } from '@sensiblestats/widget-sdk'\nimport type { MarketOddsVM, MarketOddsRowVM } from '../model'\nimport { marketOddsRowToSlipSelection } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { SlipButton } from './AddToSlipButton'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { Crest } from './Crest'\nimport { PinToggle } from './PinToggle'\n\nfunction OddsRow(\n { vm, row, ui, slip, inSlipIds }:\n { vm: MarketOddsVM; row: MarketOddsRowVM; ui?: UiConfig; slip: SlipHandlerProps; inSlipIds?: Record<number, true> },\n): JSX.Element {\n const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null\n // D5 persistent in-slip badge: keyed by matchOddsId in monitor.inSlip (session state set via\n // markInSlip), NOT SlipButton's own local `settled` state -- that resets whenever this row's\n // VM is recreated by a fresh poll snapshot, which the badge must survive. Passed as a plain\n // id map (not the full LiveMonitorController) so callers can surface the badge without also\n // turning on this list's OWN pin-toggle header (OddsPanel already owns that pin via the\n // market snapshot's context line -- a second, independently-keyed toggle here could drift out\n // of sync with it).\n const inSlip = !!inSlipIds && row.matchOddsId != null && !!inSlipIds[row.matchOddsId]\n return (\n <div className=\"ss-w-mo-row\">\n <span className=\"ss-w-mo-sel\">{row.selection}</span>\n <OddsMovementBadge previous={row.previousOdds} current={row.odds} direction={row.movementDirection} ui={ui} />\n <span className=\"ss-w-mo-price\">{row.odds}</span>\n {inSlip && ui ? <span className=\"ss-w-mon-inslip\">✓ {ui.inSlipLabel}</span> : null}\n <SlipButton selection={selection} shownOdds={row.odds} marketName={vm.market} marketDeveloperName={vm.marketDeveloperName} slip={slip} ui={ui} />\n </div>\n )\n}\n\nfunction MarketOddsCard(\n { vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }:\n { vm: MarketOddsVM; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController; inSlipIds?: Record<number, true>; hideHeader?: boolean; pinRef?: Omit<PinRef, 'key'> },\n): JSX.Element {\n const [open, setOpen] = useState(false)\n const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : undefined\n const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : undefined)\n const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName\n const showPin = !!monitor && vm.pinEnabled\n // Chat path (no pinRef): mirror the two-pin BettingInsightList layout -- the header pin\n // becomes the MATCH pin and the odds pin drops to the market line below (2026-09-06 ruling:\n // match and odds pins are never one toggle). The OddsPanel path passes pinRef and keeps its\n // single market pin in the header, so its second toggle stays off (no key drift).\n const showMarketPin = showPin && !pinRef\n const showHeader = !!vm.competition || vm.isLive || !!kickoff || showPin\n return (\n <div className={hideHeader ? 'ss-w-mocard ss-w-mocard--bare' : 'ss-w-mocard'}>\n {!hideHeader && (\n <>\n {showHeader ? (\n <div className=\"ss-w-bi-header\">\n <span className=\"ss-w-bi-header-left\">\n {vm.competition ? (\n <>\n <Crest kind=\"comp\" url={vm.competitionCrest} name={vm.competition} />\n <span className=\"ss-w-bi-comp\">{vm.competition}</span>\n </>\n ) : null}\n </span>\n <span className=\"ss-w-bi-header-right\">\n {vm.isLive ? (\n <span className=\"ss-w-bi-live\"><span className=\"ss-w-bi-live-dot\" aria-hidden=\"true\" />{ui?.liveLabel ?? 'Live'}</span>\n ) : null}\n {kickoff ? <span className=\"ss-w-bi-kick\">{kickoff}</span> : null}\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={pinRef ?? { kind: 'match', matchId: vm.matchId }}\n />\n ) : null}\n </span>\n </div>\n ) : null}\n {(hasNamedTeams || vm.fixture || vm.market || showMarketPin) ? (\n <div className=\"ss-w-mo-sub\">\n {hasNamedTeams ? (\n <div className=\"ss-w-bi-fixture\">\n <Crest kind=\"team\" url={vm.homeCrest} name={vm.homeTeamName} />\n <span className=\"ss-w-bi-team\">{vm.homeTeamName}</span>\n <span className=\"ss-w-bi-vs\" aria-hidden=\"true\">vs</span>\n <span className=\"ss-w-bi-team\">{vm.awayTeamName}</span>\n <Crest kind=\"team\" url={vm.awayCrest} name={vm.awayTeamName} />\n </div>\n ) : vm.fixture ? <span className=\"ss-w-mo-teams\">{vm.fixture}</span> : null}\n {(vm.market || showMarketPin) ? (\n <div className=\"ss-w-mo-market-row\">\n {vm.market ? <span className=\"ss-w-mo-market\">{vm.market}</span> : null}\n {showMarketPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{ kind: 'market', matchId: vm.matchId, marketDeveloperName: vm.marketDeveloperName, line: vm.mainLine }}\n />\n ) : null}\n </div>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n <div className=\"ss-w-mo-rows\">\n {vm.mainRows.map((row) => <OddsRow key={row.key} vm={vm} row={row} ui={ui} slip={slip} inSlipIds={inSlipIds} />)}\n {open ? vm.moreRows.map((row) => <OddsRow key={row.key} vm={vm} row={row} ui={ui} slip={slip} inSlipIds={inSlipIds} />) : null}\n </div>\n {vm.moreRows.length > 0 ? (\n <button type=\"button\" className=\"ss-w-mo-more\" aria-expanded={open} onClick={() => setOpen((v) => !v)}>\n <span>{open ? ui?.hideLines ?? 'Hide lines' : `${ui?.moreLines ?? 'More lines'} (${vm.moreRows.length})`}</span>\n <span className={`ss-w-mo-more-chev${open ? ' ss-w-mo-more-chev-up' : ''}`} aria-hidden=\"true\" />\n </button>\n ) : null}\n {vm.bookmaker ? (\n <div className=\"ss-w-mo-foot\">\n <span>{vm.bookmaker}</span>\n </div>\n ) : null}\n {vm.disclaimer ? <p className=\"ss-w-bi-disc\">{vm.disclaimer}</p> : null}\n </div>\n )\n}\n\nexport function MarketOddsCardList(\n { cards, ui, slip, monitor, inSlipIds, hideHeader, pinRef }:\n { cards: MarketOddsVM[]; ui?: UiConfig; slip: SlipHandlerProps; monitor?: LiveMonitorController; inSlipIds?: Record<number, true>; hideHeader?: boolean; pinRef?: Omit<PinRef, 'key'> },\n): JSX.Element | null {\n if (!cards || cards.length === 0) return null\n return (\n <div className=\"ss-w-mocards\">\n {cards.map((vm) => (\n <MarketOddsCard key={vm.id} vm={vm} ui={ui} slip={slip} monitor={monitor} inSlipIds={inSlipIds} hideHeader={hideHeader} pinRef={pinRef} />\n ))}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\nimport type { OddsMovementVM } from '../model'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { CHART_VIEW_H, CHART_VIEW_W } from '../chart'\nimport { OddsMovementBadge } from './OddsMovementBadge'\nimport { PinToggle } from './PinToggle'\n\nfunction directionWord(vm: OddsMovementVM, ui?: UiConfig): string {\n if (vm.direction === 'shortened') return ui?.oddsShortened ?? 'shortened'\n if (vm.direction === 'drifted') return ui?.oddsDrifted ?? 'drifted'\n return ''\n}\n\nfunction OddsMovementCard(\n { vm, ui, monitor }: { vm: OddsMovementVM; ui?: UiConfig; monitor?: LiveMonitorController },\n): JSX.Element {\n const word = directionWord(vm, ui)\n const drift = word ? `, ${word}` : ''\n const aria = ui?.chartAria\n ? ui.chartAria(vm.opening, vm.current, word, vm.windowHours)\n : `Price movement over the last ${vm.windowHours} hours: opened at ${vm.opening}, currently ${vm.current}${drift}.`\n const showPin = !!monitor && vm.pinEnabled\n\n return (\n <div className=\"ss-w-omcard\">\n <div className=\"ss-w-om-head\">\n <span className=\"ss-w-om-market\">{vm.market}</span>\n <span className=\"ss-w-om-tag\">{ui?.priceMovement ?? 'Price movement'}</span>\n {showPin && ui ? (\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{\n kind: 'selection',\n matchId: vm.matchId,\n marketDeveloperName: vm.marketDeveloperName,\n selectionLabel: vm.selectionLabel,\n line: vm.line,\n withHistory: true,\n matchOddsId: vm.matchOddsId,\n }}\n />\n ) : null}\n </div>\n {vm.fixture ? (\n <div className=\"ss-w-om-fixture\">\n <span>{vm.fixture}</span>\n {vm.competition ? <span className=\"ss-w-om-comp\">{vm.competition}</span> : null}\n </div>\n ) : null}\n <div className=\"ss-w-om-sel\">{vm.selection}</div>\n <OddsMovementBadge previous={vm.opening} current={vm.current} direction={vm.direction} ui={ui} />\n\n {vm.geometry === null ? (\n <div className=\"ss-w-om-empty\">\n {vm.observationCount === 1\n ? ui?.singlePricePoint ?? 'Only one price recorded so far for this selection.'\n : ui?.notEnoughHistory ?? 'No price history recorded yet for this selection.'}\n </div>\n ) : (\n <svg\n className=\"ss-w-om-chart\"\n viewBox={vm.geometry.viewBox}\n width=\"100%\"\n role=\"img\"\n aria-label={aria}\n >\n {vm.geometry.gridlines.map((g) => (\n <g key={g.price}>\n <line className=\"ss-w-om-grid\" x1={40} y1={g.y} x2={CHART_VIEW_W - 8} y2={g.y} />\n <text className=\"ss-w-om-ylab\" x={34} y={g.y + 3} textAnchor=\"end\">{g.price.toFixed(2)}</text>\n </g>\n ))}\n <path className=\"ss-w-om-line\" d={vm.geometry.path} fill=\"none\" />\n {vm.geometry.markers.map((m, i) => (\n <circle key={i} className=\"ss-w-om-dot\" cx={m.x} cy={m.y} r={2.5} />\n ))}\n {ui?.chartTimeLabel ? (\n <>\n <text className=\"ss-w-om-xlab\" x={40} y={CHART_VIEW_H - 8} textAnchor=\"start\">\n {ui.chartTimeLabel(vm.geometry.startMs)}\n </text>\n <text className=\"ss-w-om-xlab\" x={CHART_VIEW_W - 8} y={CHART_VIEW_H - 8} textAnchor=\"end\">\n {ui.chartTimeLabel(vm.geometry.endMs)}\n </text>\n </>\n ) : (\n <text className=\"ss-w-om-xlab\" x={40} y={CHART_VIEW_H - 8}>\n {ui?.movementWindow ? ui.movementWindow(vm.windowHours) : `Last ${vm.windowHours}h`}\n </text>\n )}\n </svg>\n )}\n\n <div className=\"ss-w-om-foot\">\n <span>{ui?.openingLabel ?? 'Opening'} <b>{vm.opening}</b></span>\n <span>{ui?.currentLabel ?? 'Current'} <b>{vm.current}</b></span>\n </div>\n {vm.bookmaker ? (\n <div className=\"ss-w-om-foot\">\n <span>{vm.bookmaker}</span>\n </div>\n ) : null}\n {vm.excludedCount > 0 ? (\n <div className=\"ss-w-om-excl\">\n {ui?.excludedSuspended ? ui.excludedSuspended(vm.excludedCount) : `${vm.excludedCount} suspended price(s) excluded from this chart.`}\n </div>\n ) : null}\n {vm.isSuspended ? (\n <div className=\"ss-w-om-susp\">{ui?.selectionSuspended ?? 'This selection is not currently available to bet.'}</div>\n ) : null}\n {vm.disclaimer ? <div className=\"ss-w-om-disc\">{vm.disclaimer}</div> : null}\n </div>\n )\n}\n\nexport function OddsMovementCardList(\n { cards, ui, monitor }: { cards: OddsMovementVM[]; ui?: UiConfig; monitor?: LiveMonitorController },\n): JSX.Element | null {\n if (!cards || cards.length === 0) return null\n return (\n <div className=\"ss-w-omcards\">\n {cards.map((vm) => <OddsMovementCard key={vm.id} vm={vm} ui={ui} monitor={monitor} />)}\n </div>\n )\n}\n","import type { ActionVM } from '../model'\n\nexport function ActionButtons({ actions, loading, disabled, onAct }: { actions: ActionVM[]; loading: boolean; disabled?: boolean; onAct: (action: ActionVM) => void }): JSX.Element | null {\n if (actions.length === 0 && !loading) return null\n return (\n <div className=\"ss-w-actions\">\n {actions.map((a, i) => (\n <button key={`${a.label}-${i}`} type=\"button\" className=\"ss-w-abtn\" disabled={disabled} onClick={() => onAct(a)}>{a.label}</button>\n ))}\n {actions.length === 0 && loading ? (\n <>\n <span className=\"ss-w-abtn-shimmer\" />\n <span className=\"ss-w-abtn-shimmer\" />\n </>\n ) : null}\n </div>\n )\n}\n","import type { GreetingDashboardTile } from '@sensiblestats/widget-sdk'\nimport { DashboardIcon, ChevronIcon } from '../Icons'\n\n// The server payload caps crests at 3 (spec D2); slicing here is a defensive floor, not a\n// server-side promise, since a badge + crest row this wide already competes for the same\n// space the title needs.\nconst MAX_CRESTS = 3\n\nexport function DashboardTile({ tile, onTap }: { tile: GreetingDashboardTile; onTap: () => void }): JSX.Element {\n const spanClass = tile.span === 'full' ? 'ss-w-dash-tile--full' : 'ss-w-dash-tile--half'\n const crests = (tile.imageUrls ?? []).slice(0, MAX_CRESTS)\n const hasMeta = Boolean(tile.badgeText) || crests.length > 0\n return (\n <button type=\"button\" className={`ss-w-dash-tile ${spanClass}`} onClick={onTap}>\n <span className=\"ss-w-dash-tile-icon\"><DashboardIcon name={tile.icon} /></span>\n <span className=\"ss-w-dash-tile-body\">\n <span className=\"ss-w-dash-tile-title\">{tile.title}</span>\n {tile.subtitle ? <span className=\"ss-w-dash-tile-subtitle\">{tile.subtitle}</span> : null}\n {hasMeta ? (\n // Badge + crests sit on their own row, below the title, instead of sharing the\n // icon/chevron row -- at the half-span tile's ~180px width a nowrap badge alone\n // (~70px) left the title column at ~22px and forced character-by-character wrapping.\n <span className=\"ss-w-dash-tile-meta\">\n {tile.badgeText ? <span className=\"ss-w-dash-tile-badge\">{tile.badgeText}</span> : null}\n {crests.length > 0 ? (\n <span className=\"ss-w-dash-tile-crests\">\n {crests.map((url, i) => (\n <span key={`${url}-${i}`} className=\"ss-w-dash-tile-crest\" style={{ backgroundImage: `url(${url})` }} aria-hidden=\"true\" />\n ))}\n </span>\n ) : null}\n </span>\n ) : null}\n </span>\n <span className=\"ss-w-dash-tile-chevron\"><ChevronIcon /></span>\n </button>\n )\n}\n","import type { GreetingDashboard as GreetingDashboardData, GreetingDashboardLayout, GreetingDashboardTile as GreetingDashboardTileData } from '@sensiblestats/widget-sdk'\nimport { DashboardTile } from './DashboardTile'\n\nconst LAYOUT_CLASSES: Record<GreetingDashboardLayout, string> = {\n market: 'ss-w-dash--market',\n goal: 'ss-w-dash--goal',\n discovery: 'ss-w-dash--discovery',\n}\n\n// The server's layout is a closed set, but a mismatched deploy or a future value\n// could still send something outside it. Falling back to goal (an allowlist check,\n// not a truthiness test) avoids emitting a class with no CSS rule behind it.\n// hasOwnProperty (not `in`) so a prototype member name like 'toString' can't slip\n// through as a layout and get interpolated into the className.\nfunction layoutClass(layout: string): string {\n return Object.prototype.hasOwnProperty.call(LAYOUT_CLASSES, layout)\n ? LAYOUT_CLASSES[layout as GreetingDashboardLayout]\n : LAYOUT_CLASSES.goal\n}\n\nexport function GreetingDashboard({ dashboard, onTap }: { dashboard: GreetingDashboardData; onTap: (tile: GreetingDashboardTileData, index: number) => void }): JSX.Element {\n return (\n <div className={`ss-w-dash ${layoutClass(dashboard.layout)}`}>\n <div className=\"ss-w-dash-head\">\n <span className=\"ss-w-dash-title\">{dashboard.title}</span>\n {dashboard.subtitle ? <span className=\"ss-w-dash-subtitle\">{dashboard.subtitle}</span> : null}\n </div>\n <div className=\"ss-w-dash-grid\">\n {dashboard.tiles.map((t, i) => (\n <DashboardTile key={`${t.title}-${i}`} tile={t} onTap={() => onTap(t, i)} />\n ))}\n </div>\n {dashboard.footerTip ? <span className=\"ss-w-dash-foot\">{dashboard.footerTip}</span> : null}\n </div>\n )\n}\n","import type { FixtureCard as FixtureCardData, FormMatch } from '@sensiblestats/widget-sdk'\nimport { Crest } from '../Crest'\n\nfunction teamFormResultClass(result: FormMatch['result']): string {\n if (result === 'W') return 'ss-w-fandash-teamform-cell--win'\n if (result === 'L') return 'ss-w-fandash-teamform-cell--loss'\n return 'ss-w-fandash-teamform-cell--draw'\n}\n\n// One historical-match cell: subject crest + score + opponent crest, ordered by which side the\n// subject team played on so the score always reads left-to-right as it happened on the pitch.\nfunction TeamFormCell({ m, subjectCrestUrl, subjectName }: {\n m: FormMatch\n subjectCrestUrl?: string | null\n subjectName: string\n}): JSX.Element {\n const subjectCrest = <Crest url={subjectCrestUrl ?? undefined} name={subjectName} kind=\"team\" />\n const opponentCrest = <Crest url={m.opponentCrestUrl ?? undefined} kind=\"team\" />\n const score = m.teamIsHome ? `${m.teamScore} - ${m.oppScore}` : `${m.oppScore} - ${m.teamScore}`\n return (\n <div className={`ss-w-fandash-teamform-cell ${teamFormResultClass(m.result)}`}>\n {m.teamIsHome ? subjectCrest : opponentCrest}\n <span className=\"ss-w-fandash-teamform-score\">{score}</span>\n {m.teamIsHome ? opponentCrest : subjectCrest}\n </div>\n )\n}\n\nconst TEAM_FORM_ROWS = 5\n\n// Two-column \"Team form\" card: left = home team's last 5, right = away team's last 5, most-recent\n// first. The rows grid is filled home-cell, away-cell per index (matching the approved two-column\n// mock) so a 2-col CSS grid lays them out in the right pairs without any extra layout wiring. A\n// shorter side just leaves later slots blank rather than shifting the other column's rows.\nfunction teamFormRows(data: FixtureCardData['data']): JSX.Element[] {\n return Array.from({ length: TEAM_FORM_ROWS }, (_, i) => i).flatMap((i) => [\n <span key={`h-${i}`} className=\"ss-w-fandash-teamform-slot\">\n {data.homeForm[i] ? (\n <TeamFormCell m={data.homeForm[i]} subjectCrestUrl={data.homeCrestUrl} subjectName={data.homeName} />\n ) : null}\n </span>,\n <span key={`a-${i}`} className=\"ss-w-fandash-teamform-slot\">\n {data.awayForm[i] ? (\n <TeamFormCell m={data.awayForm[i]} subjectCrestUrl={data.awayCrestUrl} subjectName={data.awayName} />\n ) : null}\n </span>,\n ])\n}\n\n// The fixture payload renders as three stacked [data] cards -- the fixture head (teams, kickoff,\n// venue), the last-five form, and the head-to-head record -- so each block reads as its own unit.\n// None is a tap target: the compare-form action lives in the greeting chips, so the card carries no\n// redundant CTA. (u319: the server now issues FixtureCard as a plain DataCard with no actionRef.)\nexport function FixtureCard({ card }: { card: FixtureCardData }): JSX.Element {\n const { data } = card\n const h2h = data.h2H\n return (\n <>\n <div className=\"ss-w-fandash-card ss-w-fandash-fixture\">\n <span className=\"ss-w-fandash-eyebrow\">{card.title} · {data.competition}</span>\n <div className=\"ss-w-fandash-fixture-teams\">\n <span className=\"ss-w-fandash-fixture-team\">\n <Crest url={data.homeCrestUrl ?? undefined} name={data.homeName} kind=\"team\" />\n <span className=\"ss-w-fandash-fixture-name\">{data.homeName}</span>\n </span>\n <span className=\"ss-w-fandash-fixture-vs\">v</span>\n <span className=\"ss-w-fandash-fixture-team ss-w-fandash-fixture-team--away\">\n <span className=\"ss-w-fandash-fixture-name\">{data.awayName}</span>\n <Crest url={data.awayCrestUrl ?? undefined} name={data.awayName} kind=\"team\" />\n </span>\n </div>\n <div className=\"ss-w-fandash-fixture-meta\">\n <span className=\"ss-w-fandash-fixture-kickoff\">{data.kickoffLabel}</span>\n {data.venue ? <span className=\"ss-w-fandash-fixture-venue\"> · {data.venue}</span> : null}\n </div>\n </div>\n\n <div className=\"ss-w-fandash-card ss-w-fandash-lastfive\">\n <span className=\"ss-w-fandash-eyebrow\">{data.formLabel}</span>\n <div className=\"ss-w-fandash-teamform-head\">\n <span className=\"ss-w-fandash-teamform-head-team\">\n <Crest url={data.homeCrestUrl ?? undefined} name={data.homeName} kind=\"team\" />\n <span className=\"ss-w-fandash-teamform-head-name\">{data.homeName}</span>\n </span>\n <span className=\"ss-w-fandash-teamform-head-team\">\n <Crest url={data.awayCrestUrl ?? undefined} name={data.awayName} kind=\"team\" />\n <span className=\"ss-w-fandash-teamform-head-name\">{data.awayName}</span>\n </span>\n </div>\n <div className=\"ss-w-fandash-teamform-rows\">\n {teamFormRows(data)}\n </div>\n </div>\n\n {h2h || data.fact ? (\n <div className=\"ss-w-fandash-card ss-w-fandash-h2h\">\n {h2h ? (\n <>\n <span className=\"ss-w-fandash-eyebrow\">{h2h.label}</span>\n <div className=\"ss-w-fandash-split\">\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.wins}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.homeWinsLabel}</span>\n </span>\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.draws}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.drawsLabel}</span>\n </span>\n <span className=\"ss-w-fandash-split-cell\">\n <span className=\"ss-w-fandash-split-value\">{h2h.losses}</span>\n <span className=\"ss-w-fandash-split-label\">{h2h.awayWinsLabel}</span>\n </span>\n </div>\n </>\n ) : null}\n {data.fact ? <span className=\"ss-w-fandash-fact\">{data.fact}</span> : null}\n </div>\n ) : null}\n </>\n )\n}\n","import { Fragment, useEffect, useState } from 'react'\nimport type { CountdownCard as CountdownCardData } from '@sensiblestats/widget-sdk'\n\ntype UnitKind = 'd' | 'h' | 'm' | 's'\ntype Segment = { value: string; unit: UnitKind }\n\nconst DAY_MS = 86_400_000\n\n// The countdown reads day:hour while the match is more than a day out, and switches to a live\n// hour:minute:second clock on match day (under a day to kickoff). `withSeconds` is dropped under\n// reduced motion so the card never shows a seconds figure it will never refresh. Returns null once\n// kickoff has passed.\nfunction remainingSegments(kickoffUnix: number, nowMs: number, withSeconds: boolean): Segment[] | null {\n const totalSeconds = Math.floor((kickoffUnix * 1000 - nowMs) / 1000)\n if (totalSeconds <= 0) return null\n const days = Math.floor(totalSeconds / 86_400)\n const hours = Math.floor((totalSeconds % 86_400) / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n const pad = (n: number) => String(n).padStart(2, '0')\n if (days > 0) return [{ value: pad(days), unit: 'd' }, { value: pad(hours), unit: 'h' }]\n const segs: Segment[] = [{ value: pad(hours), unit: 'h' }, { value: pad(minutes), unit: 'm' }]\n if (withSeconds) segs.push({ value: pad(seconds), unit: 's' })\n return segs\n}\n\nexport function CountdownCard({ card }: { card: CountdownCardData }): JSX.Element {\n const { data } = card\n // Unit labels are server-localized; the numbers are computed client-side.\n const unitLabel: Record<UnitKind, string> = { d: data.daysUnit, h: data.hoursUnit, m: data.minutesUnit, s: data.secondsUnit }\n const [nowMs, setNowMs] = useState(() => Date.now())\n // Reduced motion is read once at mount: it decides whether the card ticks at all and whether it\n // shows a (necessarily static, so potentially stale) seconds figure. Ticking is otherwise\n // additive -- the segments computed at mount keep showing even if no interval ever fires.\n const [reduced] = useState(\n () => typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches,\n )\n const withinDay = data.kickoffUnix * 1000 - nowMs < DAY_MS\n useEffect(() => {\n if (reduced) return\n const id = window.setInterval(() => setNowMs(Date.now()), withinDay ? 1000 : 60_000)\n return () => window.clearInterval(id)\n }, [reduced, withinDay])\n const segments = remainingSegments(data.kickoffUnix, nowMs, withinDay && !reduced)\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-countdown\">\n <div className=\"ss-w-fandash-countdown-top\">\n <span className=\"ss-w-fandash-eyebrow\">{card.title ?? 'Kick-off in'}</span>\n {segments ? (\n <span className=\"ss-w-fandash-countdown-clock\">\n {segments.map((s, i) => (\n <Fragment key={s.unit}>\n {i > 0 ? <span className=\"ss-w-fandash-countdown-colon\">:</span> : null}\n <span className=\"ss-w-fandash-countdown-seg\">\n <span className=\"ss-w-fandash-countdown-value\">{s.value}</span>\n <span className=\"ss-w-fandash-countdown-unit\">{unitLabel[s.unit]}</span>\n </span>\n </Fragment>\n ))}\n </span>\n ) : null}\n </div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { InjuriesCard as InjuriesCardData, InjuryRow } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\nimport { Crest } from '../Crest'\n\nconst SHOWN = 3\n\nfunction ColHead({ name, crestUrl }: { name: string; crestUrl?: string | null }): JSX.Element {\n return (\n <span className=\"ss-w-fandash-injuries-col-head\">\n <Crest url={crestUrl ?? undefined} name={name} kind=\"team\" />\n <span className=\"ss-w-fandash-injuries-col-head-name\">{name}</span>\n </span>\n )\n}\n\nfunction InjuryList({ rows, emptyLabel, limit }: { rows: InjuryRow[]; emptyLabel: string; limit?: number }): JSX.Element {\n if (rows.length === 0) return <span className=\"ss-w-fandash-injuries-empty\">{emptyLabel}</span>\n const shown = limit === undefined ? rows : rows.slice(0, limit)\n return (\n <ul className=\"ss-w-fandash-injury-list\">\n {shown.map((r, i) => (\n <li key={`${r.playerName}-${i}`} className=\"ss-w-fandash-injury-row\">\n <span className=\"ss-w-fandash-injury-name\">{r.playerName}</span>\n <span className=\"ss-w-fandash-injury-meta\">\n <span className=\"ss-w-fandash-injury-status\">{r.status}</span>\n {r.injuryType ? <span className=\"ss-w-fandash-injury-type\">{r.injuryType}</span> : null}\n {r.expectedReturnLabel ? <span className=\"ss-w-fandash-injury-return\">{r.expectedReturnLabel}</span> : null}\n </span>\n </li>\n ))}\n </ul>\n )\n}\n\nexport function InjuriesCard({ card, ui }: { card: InjuriesCardData; ui?: UiConfig }): JSX.Element {\n const { data } = card\n const [expanded, setExpanded] = useState(false)\n // Either side's list can be long; a shared toggle collapses both to SHOWN and reveals the rest,\n // so the card doesn't push the input off-screen. The count is how many are hidden across both sides.\n const hidden = Math.max(0, data.ours.length - SHOWN) + Math.max(0, data.theirs.length - SHOWN)\n const limit = expanded ? undefined : SHOWN\n const showMore = ui?.showMore ?? ((n: number) => `Show ${n} more`)\n const showLess = ui?.showLess ?? 'Show less'\n // \"Ours\" is club-vs-opponent, not home-vs-away — reorder into home/away columns so the card\n // reads left-to-right like the rest of the dashboard regardless of which side the club is on.\n const homeCol = data.oursIsHome\n ? { name: data.oursName, crest: data.oursCrestUrl, rows: data.ours }\n : { name: data.theirsName, crest: data.theirsCrestUrl, rows: data.theirs }\n const awayCol = data.oursIsHome\n ? { name: data.theirsName, crest: data.theirsCrestUrl, rows: data.theirs }\n : { name: data.oursName, crest: data.oursCrestUrl, rows: data.ours }\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-injuries\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-injuries-cols\">\n <div className=\"ss-w-fandash-injuries-col\">\n <ColHead name={homeCol.name} crestUrl={homeCol.crest} />\n <InjuryList rows={homeCol.rows} emptyLabel={data.emptyLabel} limit={limit} />\n </div>\n <div className=\"ss-w-fandash-injuries-divider\" />\n <div className=\"ss-w-fandash-injuries-col\">\n <ColHead name={awayCol.name} crestUrl={awayCol.crest} />\n <InjuryList rows={awayCol.rows} emptyLabel={data.emptyLabel} limit={limit} />\n </div>\n </div>\n {hidden > 0 ? (\n <button\n type=\"button\"\n className=\"ss-w-fandash-injuries-more\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n >\n {expanded ? showLess : showMore(hidden)}\n </button>\n ) : null}\n </div>\n )\n}\n","import type { ReasonToBetCard as ReasonToBetCardData } from '@sensiblestats/widget-sdk'\n\nexport function ReasonToBetCard({ card }: { card: ReasonToBetCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-reasons\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <ul className=\"ss-w-fandash-reason-list\">\n {card.data.angles.map((angle, i) => (\n <li key={`${angle}-${i}`} className=\"ss-w-fandash-reason-item\">{angle}</li>\n ))}\n </ul>\n </div>\n )\n}\n","import type { WhereToWatchCard as WhereToWatchCardData } from '@sensiblestats/widget-sdk'\n\nexport function WhereToWatchCard({ card }: { card: WhereToWatchCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-watch\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <span className=\"ss-w-fandash-stations\">\n {card.data.stations.map((station, i) => (\n <span key={`${station}-${i}`} className=\"ss-w-fandash-station-chip\">{station}</span>\n ))}\n </span>\n </div>\n )\n}\n","import type { CongestedWeekCard as CongestedWeekCardData } from '@sensiblestats/widget-sdk'\n\nexport function CongestedWeekCard({ card, onTap }: { card: CongestedWeekCardData; onTap: (card: CongestedWeekCardData) => void }): JSX.Element {\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-congested\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-congested-grid\">\n {card.data.entries.map((entry, i) => (\n <span key={`${entry.opponent}-${i}`} className=\"ss-w-fandash-congested-cell\">\n <span className=\"ss-w-fandash-congested-day\">{entry.dayLabel}</span>\n <span className=\"ss-w-fandash-congested-opponent\">{entry.opponent}</span>\n <span className=\"ss-w-fandash-congested-comp\">{entry.competition}</span>\n <span className=\"ss-w-fandash-congested-time\">{entry.timeLabel}</span>\n </span>\n ))}\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { TransfersCard as TransfersCardData, TransferRow } from '@sensiblestats/widget-sdk'\n\nfunction TransferList({ rows }: { rows: TransferRow[] }): JSX.Element {\n if (rows.length === 0) return <span className=\"ss-w-fandash-transfers-empty\">None</span>\n return (\n <ul className=\"ss-w-fandash-transfer-list\">\n {rows.map((r, i) => (\n <li key={`${r.playerName}-${i}`} className=\"ss-w-fandash-transfer-row\">\n <span className=\"ss-w-fandash-transfer-name\">{r.playerName}</span>\n <span className=\"ss-w-fandash-transfer-club\">{r.otherClub}</span>\n {r.type ? <span className=\"ss-w-fandash-transfer-type\">{r.type}</span> : null}\n </li>\n ))}\n </ul>\n )\n}\n\nexport function TransfersCard({ card }: { card: TransfersCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-transfers\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-transfers-cols\">\n <div className=\"ss-w-fandash-transfers-col\">\n <span className=\"ss-w-fandash-transfers-col-head\">In</span>\n <TransferList rows={data.in} />\n </div>\n <div className=\"ss-w-fandash-transfers-col\">\n <span className=\"ss-w-fandash-transfers-col-head\">Out</span>\n <TransferList rows={data.out} />\n </div>\n </div>\n </div>\n )\n}\n","import type { LinksCard as LinksCardData } from '@sensiblestats/widget-sdk'\nimport { ChevronIcon } from '../Icons'\n\nexport function LinksCard({ card }: { card: LinksCardData }): JSX.Element {\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-links\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-link-grid\">\n {card.data.links.map((link, i) => (\n <a key={`${link.url}-${i}`} className=\"ss-w-fandash-link-tile\" href={link.url} target=\"_blank\" rel=\"noopener noreferrer\">\n <span className=\"ss-w-fandash-link-label\">{link.label}</span>\n <span className=\"ss-w-fandash-link-chevron\"><ChevronIcon /></span>\n </a>\n ))}\n </div>\n </div>\n )\n}\n","import { useState } from 'react'\nimport type { PostMatchResultCard as PostMatchResultCardData } from '@sensiblestats/widget-sdk'\n\nfunction initials(name: string): string {\n return name.trim().slice(0, 3).toUpperCase()\n}\n\n// Same img-with-fallback treatment as LiveScoreCard's LiveCrest -- a broken/absent URL falls back\n// to a coloured initials chip, which a background-image span can't detect on its own.\nfunction PostMatchCrest({\n url,\n name,\n side,\n}: {\n url?: string | null\n name: string\n side: 'home' | 'away'\n}): JSX.Element {\n const [failed, setFailed] = useState(false)\n const cls = `ss-w-fandash-postmatch-crest ss-w-fandash-postmatch-crest--${side}`\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return (\n <span className={`${cls} ss-w-fandash-postmatch-crest--fallback`} aria-hidden=\"true\">\n {initials(name)}\n </span>\n )\n}\n\n// [data] card -- the full-time scoreboard. No tap target: the score itself is the payload, and\n// the goals/stats/top-performer cards below carry the actionRef taps for this match.\nexport function PostMatchResultCard({ card }: { card: PostMatchResultCardData }): JSX.Element {\n const { data } = card\n const homeWon = data.homeScore >= data.awayScore\n const awayWon = data.awayScore >= data.homeScore\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-postmatch-result\">\n <div className=\"ss-w-fandash-postmatch-top\">\n {/* card.title carries the server-localized \"Full time\" label -- reused as the pill text\n rather than a hardcoded English literal. */}\n {card.title ? <span className=\"ss-w-fandash-postmatch-pill\">{card.title}</span> : null}\n <span className={`ss-w-fandash-postmatch-tag ss-w-fandash-postmatch-tag--${data.outcome}`}>\n {data.resultLabel}\n </span>\n </div>\n <div className=\"ss-w-fandash-postmatch-main\">\n <div className=\"ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--home\">\n <PostMatchCrest url={data.homeCrestUrl} name={data.homeName} side=\"home\" />\n <span className=\"ss-w-fandash-postmatch-team-name\">{data.homeName}</span>\n </div>\n <div className=\"ss-w-fandash-postmatch-score-main\">\n <span\n className={`ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${homeWon ? 'win' : 'lose'}`}\n >\n {data.homeScore}\n </span>\n <span className=\"ss-w-fandash-postmatch-score-sep\">–</span>\n <span\n className={`ss-w-fandash-postmatch-score-value ss-w-fandash-postmatch-score-value--${awayWon ? 'win' : 'lose'}`}\n >\n {data.awayScore}\n </span>\n </div>\n <div className=\"ss-w-fandash-postmatch-side ss-w-fandash-postmatch-side--away\">\n <PostMatchCrest url={data.awayCrestUrl} name={data.awayName} side=\"away\" />\n <span className=\"ss-w-fandash-postmatch-team-name\">{data.awayName}</span>\n </div>\n </div>\n <div className=\"ss-w-fandash-postmatch-meta\">\n {data.kickoffLabel}\n {data.competition ? ` · ${data.competition}` : ''}\n </div>\n </div>\n )\n}\n","import type { PostMatchGoalsCard as PostMatchGoalsCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- tapping sends actionLabel as a follow-up message, carrying the opaque\n// actionRef so the server resolves the pre-issued binding (see FixtureCard/CongestedWeekCard).\nexport function PostMatchGoalsCard({ card, onTap }: {\n card: PostMatchGoalsCardData\n onTap: (card: PostMatchGoalsCardData) => void\n}): JSX.Element {\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-goals\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <ul className=\"ss-w-fandash-postmatch-goal-list\">\n {card.data.goals.map((g, i) => (\n <li key={`${g.text}-${i}`} className={g.scoredByClub ? 'ss-w-fandash-postmatch-goal ss-w-fandash-postmatch-goal--club' : 'ss-w-fandash-postmatch-goal'}>\n <span className=\"ss-w-fandash-postmatch-goal-ball\" />\n <span>{g.text}</span>\n </li>\n ))}\n </ul>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchStatsCard as PostMatchStatsCardData } from '@sensiblestats/widget-sdk'\n\n// Split-bar widths as percentages, rounded to 1dp so the rendered width string stays short and\n// stable in tests. Guarded for the 0/0 case (or any non-positive total) -- an even 50/50 split\n// rather than a NaN width. Mirrors LiveStatsCard's splitWidths.\nfunction splitWidths(homeNum: number, awayNum: number): { home: string; away: string } {\n const total = homeNum + awayNum\n if (total <= 0) return { home: '50%', away: '50%' }\n const homePct = Math.round((homeNum / total) * 1000) / 10\n return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` }\n}\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function PostMatchStatsCard({ card, onTap }: {\n card: PostMatchStatsCardData\n onTap: (card: PostMatchStatsCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-stats\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-stat-rows\">\n {data.rows.map((r, i) => {\n // Row values are club-first, but the result card above renders home-left/away-right, so\n // orient by venue: the home team's value on the left, the away team's on the right. When\n // the club is the away side, that means the club's value is the RIGHT column.\n const leftValue = data.clubIsHome ? r.clubValue : r.oppValue\n const rightValue = data.clubIsHome ? r.oppValue : r.clubValue\n const homeNum = data.clubIsHome ? r.clubNum : r.oppNum\n const awayNum = data.clubIsHome ? r.oppNum : r.clubNum\n const { home, away } = splitWidths(homeNum, awayNum)\n return (\n <div key={`${r.label}-${i}`} className=\"ss-w-fandash-postmatch-stat\">\n <div className=\"ss-w-fandash-postmatch-stat-row\">\n <span className=\"ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--home\">{leftValue}</span>\n <span className=\"ss-w-fandash-postmatch-stat-label\">{r.label}</span>\n <span className=\"ss-w-fandash-postmatch-stat-value ss-w-fandash-postmatch-stat-value--away\">{rightValue}</span>\n </div>\n <div className=\"ss-w-fandash-postmatch-stat-bar\">\n <span className=\"ss-w-fandash-postmatch-stat-bar-home\" style={{ width: home }} />\n <span className=\"ss-w-fandash-postmatch-stat-bar-away\" style={{ width: away }} />\n </div>\n </div>\n )\n })}\n </div>\n {data.rows.length > 0 ? (\n <div className=\"ss-w-fandash-postmatch-legend\">\n <span className=\"ss-w-fandash-postmatch-legend-item\">\n <i className=\"ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--home\" />\n {data.homeName}\n </span>\n <span className=\"ss-w-fandash-postmatch-legend-item\">\n <i className=\"ss-w-fandash-postmatch-legend-swatch ss-w-fandash-postmatch-legend-swatch--away\" />\n {data.awayName}\n </span>\n </div>\n ) : null}\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchTopPerformerCard as PostMatchTopPerformerCardData } from '@sensiblestats/widget-sdk'\n\n// First letter of the first and last word (a single-word name yields just that one letter, since\n// first === last); whitespace/empty falls back to \"?\" rather than rendering a blank avatar.\nfunction initials(playerName: string): string {\n const words = playerName.trim().split(/\\s+/).filter(Boolean)\n if (words.length === 0) return '?'\n const first = words[0]!.charAt(0)\n const last = words[words.length - 1]!.charAt(0)\n return (words.length > 1 ? `${first}${last}` : first).toUpperCase()\n}\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard. Full mockup treatment:\n// gradient initials avatar + name + a prominent rating chip. No \"2 goals\" sub-line -- there's no\n// data for it.\nexport function PostMatchTopPerformerCard({ card, onTap }: {\n card: PostMatchTopPerformerCardData\n onTap: (card: PostMatchTopPerformerCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-postmatch-performer\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-perf-row\">\n <span className=\"ss-w-fandash-postmatch-perf-avatar\" aria-hidden=\"true\">{initials(data.playerName)}</span>\n <span className=\"ss-w-fandash-postmatch-perf-name\">{data.playerName}</span>\n <span className=\"ss-w-fandash-postmatch-perf-rating\">{data.ratingLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { PostMatchNextCard as PostMatchNextCardData } from '@sensiblestats/widget-sdk'\n\n// [data] card -- the upcoming fixture teaser that follows a post-match dashboard. No tap target.\n// v1 (modest): whenLabel is already a complete localized phrase composed server-side -- it\n// includes the opponent, venue and kickoff time (EN \"vs Bournemouth (H) · Sat 12 Sep · 15:00\",\n// TR \"İç sahada Bournemouth · ...\"). Rendering opponentName alongside it would duplicate the\n// opponent, so this card shows only whenLabel, dressed up with an accent rule rather than a second\n// line. The richer opponent-headline + venue chip + crest layout needs a server field split\n// (opponent vs venue vs time as separate fields) and is deferred.\nexport function PostMatchNextCard({ card }: { card: PostMatchNextCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-postmatch-next\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-postmatch-next-row\">\n <span className=\"ss-w-fandash-postmatch-next-when\">{data.whenLabel}</span>\n </div>\n </div>\n )\n}\n","import type { RestingNextCard as RestingNextCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- tapping sends actionLabel as a follow-up message, carrying the opaque\n// actionRef so the server resolves the pre-issued binding (see PostMatchGoalsCard/FixtureCard).\nexport function RestingNextCard({ card, onTap }: {\n card: RestingNextCardData\n onTap: (card: RestingNextCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-next\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-next-row\">\n <span className=\"ss-w-fandash-resting-next-when\">{data.whenLabel}</span>\n {data.competition ? <span className=\"ss-w-fandash-resting-next-competition\">{data.competition}</span> : null}\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingStandingsCard as RestingStandingsCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function RestingStandingsCard({ card, onTap }: {\n card: RestingStandingsCardData\n onTap: (card: RestingStandingsCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-standings\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-standings-row\">\n <span className=\"ss-w-fandash-resting-standings-position\">{data.positionLabel}</span>\n <span className=\"ss-w-fandash-resting-standings-record\">{data.recordLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingSeasonCard as RestingSeasonCardData } from '@sensiblestats/widget-sdk'\n\n// [prefill] card -- same tap wiring as PostMatchGoalsCard/FixtureCard.\nexport function RestingSeasonCard({ card, onTap }: {\n card: RestingSeasonCardData\n onTap: (card: RestingSeasonCardData) => void\n}): JSX.Element {\n const { data } = card\n return (\n <button type=\"button\" className=\"ss-w-fandash-card ss-w-fandash-card--tap ss-w-fandash-resting-season\" onClick={() => onTap(card)}>\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-resting-season-rows\">\n {data.scorerLabel ? <span className=\"ss-w-fandash-resting-season-row\">{data.scorerLabel}</span> : null}\n {data.playerLabel ? <span className=\"ss-w-fandash-resting-season-row\">{data.playerLabel}</span> : null}\n <span className=\"ss-w-fandash-resting-season-row\">{data.tallyLabel}</span>\n </div>\n <span className=\"ss-w-fandash-card-cta\">{card.actionLabel}</span>\n </button>\n )\n}\n","import type { RestingFormCard as RestingFormCardData } from '@sensiblestats/widget-sdk'\n\nfunction resultClass(result: string): string {\n const upper = result.toUpperCase()\n if (upper === 'W') return 'ss-w-fandash-form-pill--win'\n if (upper === 'L') return 'ss-w-fandash-form-pill--loss'\n return 'ss-w-fandash-form-pill--draw'\n}\n\n// [data] card -- recent form as one styled W/D/L pill per letter (same pill classes as the\n// fixture card's last-five strip). No tap target.\nexport function RestingFormCard({ card }: { card: RestingFormCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-resting-form\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <span className=\"ss-w-fandash-form\">\n {data.letters.map((r, i) => (\n <span key={`${r}-${i}`} className={`ss-w-fandash-form-pill ${resultClass(r)}`}>{r}</span>\n ))}\n </span>\n </div>\n )\n}\n","import { useRef, useState } from 'react'\nimport type { LiveScoreCard as LiveScoreCardData, LiveEventLine } from '@sensiblestats/widget-sdk'\nimport { useLiveClock } from '../../useLiveClock'\n\nfunction initials(name: string): string {\n return name.trim().slice(0, 3).toUpperCase()\n}\n\n// Crest is an <img> so a broken/absent URL falls back to a coloured initials chip -- the design\n// wants the chip whenever the crest is missing OR fails to load, which a background-image span\n// can't detect on its own.\nfunction LiveCrest({ url, name, side }: { url?: string | null; name: string; side: 'home' | 'away' }): JSX.Element {\n const [failed, setFailed] = useState(false)\n const cls = `ss-w-fandash-live-crest ss-w-fandash-live-crest--${side}`\n if (url && !failed) {\n return <img className={cls} src={url} alt=\"\" aria-hidden=\"true\" onError={() => setFailed(true)} />\n }\n return (\n <span className={`${cls} ss-w-fandash-live-crest--fallback`} aria-hidden=\"true\">\n {initials(name)}\n </span>\n )\n}\n\n// Renders \"Salah 6', Núñez 9'\" from the goal events the parent filtered out of the live timeline,\n// oldest first. Events with no player name are dropped rather than rendered blank; if nothing is\n// left, the scorers line is omitted entirely.\nfunction scorersLine(goalEvents: LiveEventLine[] | undefined): string | null {\n if (!goalEvents || goalEvents.length === 0) return null\n // Defensive: only ever render actual goals, even if a caller passes an unfiltered event list.\n const named = goalEvents.filter((e) => e.type === 'goal' && e.player)\n if (named.length === 0) return null\n return named\n .slice()\n .sort((a, b) => a.minute - b.minute)\n .map((e) => `${e.player} ${e.minuteLabel}`)\n .join(', ')\n}\n\n// [data] card -- the in-play scoreboard. No tap target: the live score itself is the payload,\n// and the timeline/stats cards below carry the rest of the in-play picture.\nexport function LiveScoreCard({\n card,\n goalEvents,\n}: {\n card: LiveScoreCardData\n goalEvents?: LiveEventLine[]\n}): JSX.Element {\n const { data } = card\n\n // The reducer replaces the card object on every ~60s poll, so seeding the live-clock hook with\n // `Date.now()` on every render would restart its elapsed-time math each time and the minute\n // would never tick between polls. Reseed only when the server minute or score actually changes.\n const seedKey = `${data.minute}:${data.homeScore}:${data.awayScore}`\n const seedRef = useRef<{ key: string; receivedAtMs: number } | null>(null)\n if (!seedRef.current || seedRef.current.key !== seedKey) {\n seedRef.current = { key: seedKey, receivedAtMs: Date.now() }\n }\n\n const displayMinute = useLiveClock(data.minute, data.clockRunning, seedRef.current.receivedAtMs)\n const minuteSuffix = data.minuteLabel.replace(/^\\d+/, '')\n const scorers = scorersLine(goalEvents)\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-score\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-top\">\n <span className=\"ss-w-fandash-live-pill\">\n <span className=\"ss-w-fandash-live-dot\" aria-hidden=\"true\" />\n {data.statusLabel}\n </span>\n <span className=\"ss-w-fandash-live-minute\">{`${displayMinute}${minuteSuffix}`}</span>\n {data.competition ? <span className=\"ss-w-fandash-live-competition\">{data.competition}</span> : null}\n </div>\n <div className=\"ss-w-fandash-live-main\">\n <div className=\"ss-w-fandash-live-side ss-w-fandash-live-side--home\">\n <LiveCrest url={data.homeCrestUrl} name={data.homeName} side=\"home\" />\n <span className=\"ss-w-fandash-live-team-name\">{data.homeName}</span>\n </div>\n <div className=\"ss-w-fandash-live-score-main\">\n <span className=\"ss-w-fandash-live-score-value\">{data.homeScore}</span>\n <span className=\"ss-w-fandash-live-score-sep\">–</span>\n <span className=\"ss-w-fandash-live-score-value\">{data.awayScore}</span>\n </div>\n <div className=\"ss-w-fandash-live-side ss-w-fandash-live-side--away\">\n <LiveCrest url={data.awayCrestUrl} name={data.awayName} side=\"away\" />\n <span className=\"ss-w-fandash-live-team-name\">{data.awayName}</span>\n </div>\n </div>\n {scorers ? (\n <div className=\"ss-w-fandash-live-scorers\">\n <span className=\"ss-w-fandash-live-scorers-icon\" aria-hidden=\"true\">\n ⚽\n </span>\n {scorers}\n </div>\n ) : null}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\nconst TICK_MS = 60_000\n// Generous stoppage-time headroom. The server clamps 2H to 105; if a live poll never\n// delivers a \"Finished\" transition (resolver drops the match before that lands), a stuck\n// clockRunning:true must hold here instead of climbing forever.\nconst MAX_LIVE_TICK_MINUTES = 15\n\nfunction computeDisplayMinute(minute: number, clockRunning: boolean, receivedAtMs: number): number {\n if (!clockRunning) return minute\n const elapsedMinutes = Math.floor((Date.now() - receivedAtMs) / TICK_MS)\n return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES)\n}\n\n// Ticks a live match minute forward once per real minute between server polls, so the\n// clock doesn't look frozen during the 60s gap. Reseeds immediately whenever `minute` or\n// `receivedAtMs` changes (a fresh poll), rather than waiting for the next interval tick.\nexport function useLiveClock(minute: number, clockRunning: boolean, receivedAtMs: number): number {\n const [displayMinute, setDisplayMinute] = useState(() =>\n computeDisplayMinute(minute, clockRunning, receivedAtMs),\n )\n\n useEffect(() => {\n setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs))\n\n if (!clockRunning) return\n\n const id = window.setInterval(() => {\n setDisplayMinute(computeDisplayMinute(minute, clockRunning, receivedAtMs))\n }, TICK_MS)\n\n return () => window.clearInterval(id)\n }, [minute, clockRunning, receivedAtMs])\n\n return displayMinute\n}\n","import { useState } from 'react'\nimport type { LiveTimelineCard as LiveTimelineCardData, LiveEventLine } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\n\nconst SHOWN = 3\n\n// Per-type icon: a ball mark for goals, a coloured card rectangle for yellow/red, up/down\n// arrows for a substitution. An unrecognised type (forward-compat with the server's union)\n// renders a neutral dot rather than nothing, so a new event type never looks broken.\nfunction EventIcon({ type }: { type: LiveEventLine['type'] }): JSX.Element {\n if (type === 'goal') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico ss-w-fandash-live-tl-ico--goal\" aria-hidden=\"true\">\n <span className=\"ss-w-fandash-live-tl-ball\" />\n </span>\n )\n }\n if (type === 'yellow' || type === 'red') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\">\n <span className={`ss-w-fandash-live-tl-card ss-w-fandash-live-tl-card--${type}`} />\n </span>\n )\n }\n if (type === 'sub') {\n return (\n <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\">\n <span className=\"ss-w-fandash-live-tl-subarrows\">⇅</span>\n </span>\n )\n }\n return <span className=\"ss-w-fandash-live-tl-ico\" aria-hidden=\"true\"><span className=\"ss-w-fandash-live-tl-dot\" /></span>\n}\n\n// Sub events name both players; the \"for {playerOff}\" half only renders when the server sent\n// it, and everything falls back to the server's plain text if a name field is missing.\nfunction EventLabel({ e }: { e: LiveEventLine }): JSX.Element {\n if (e.type === 'sub') {\n return (\n <span className=\"ss-w-fandash-live-tl-who\">\n {e.player ?? e.text}\n {e.playerOff ? <span className=\"ss-w-fandash-live-tl-off\"> for {e.playerOff}</span> : null}\n </span>\n )\n }\n return <span className=\"ss-w-fandash-live-tl-who\">{e.player ?? e.text}</span>\n}\n\nfunction EventRow({ e }: { e: LiveEventLine }): JSX.Element {\n const cls = [\n 'ss-w-fandash-live-tl-ev',\n e.side === 'home' ? 'ss-w-fandash-live-tl-ev--home' : 'ss-w-fandash-live-tl-ev--away',\n e.type === 'goal' ? 'ss-w-fandash-live-tl-ev--goal' : '',\n ]\n .filter(Boolean)\n .join(' ')\n return (\n <div className={cls}>\n <span className=\"ss-w-fandash-live-tl-txt\">\n <EventLabel e={e} />\n <EventIcon type={e.type} />\n </span>\n <span className=\"ss-w-fandash-live-tl-badge\">{e.minuteLabel}</span>\n </div>\n )\n}\n\n// [data] card -- the in-play event feed as a compact two-sided timeline down a centre spine:\n// each club's events sit on its own side, most-recent 3 shown with a \"See more\" toggle for the\n// rest. No tap target.\nexport function LiveTimelineCard({ card, ui }: { card: LiveTimelineCardData; ui?: UiConfig }): JSX.Element | null {\n const [expanded, setExpanded] = useState(false)\n const events = card.data.events\n if (!events || events.length === 0) return null\n\n const sorted = [...events].sort((a, b) => b.minute - a.minute)\n const rest = sorted.length - SHOWN\n const shown = expanded ? sorted : sorted.slice(0, SHOWN)\n\n const showMore = ui?.showMore ?? ((n: number) => `Show ${n} more`)\n const showLess = ui?.showLess ?? 'Show less'\n\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-timeline\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-tl\">\n {shown.map((e, i) => (\n <EventRow key={`${e.minute}-${e.side}-${e.type}-${i}`} e={e} />\n ))}\n </div>\n {rest > 0 ? (\n <button\n type=\"button\"\n className=\"ss-w-fandash-live-tl-more\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n >\n {expanded ? showLess : showMore(rest)}\n </button>\n ) : null}\n </div>\n )\n}\n","import { useId } from 'react'\nimport type { LiveStatsData } from '@sensiblestats/widget-sdk'\n\n// widget-sdk's events.ts defines `MomentumPoint` but its barrel (index.ts) never re-exports it on\n// its own -- only as the element type of `LiveStatsData.momentum`. Indexing off that field avoids\n// widening this task's scope to a widget-sdk barrel edit for a type alias.\ntype MomentumPoint = LiveStatsData['momentum'][number]\n\nconst WIDTH = 270\nconst HEIGHT = 56\nconst BASELINE = HEIGHT / 2 // mid-height, matches the mockup's BASE=28 for H=56\nconst SCALE = 0.26 // value ±100 -> ±26px around the baseline, same as the mockup\n\nfunction buildPaths(\n points: MomentumPoint[],\n): { area: string; line: string; lastLeftPct: number; lastTopPx: number } {\n const lastIndex = points.length - 1\n const px = (i: number): number => (lastIndex === 0 ? 0 : (i / lastIndex) * WIDTH)\n const py = (v: number): number => BASELINE - v * SCALE\n const linePts = points.map((p, i) => `${px(i).toFixed(1)},${py(p.value).toFixed(1)}`)\n const area = `M0,${BASELINE} L${linePts.join(' L')} L${WIDTH},${BASELINE} Z`\n const line = `M${linePts.join(' L')}`\n // The caller (MomentumWave) already returns null for an empty series, so lastIndex is always a\n // valid index here -- the `?? 0` only satisfies noUncheckedIndexedAccess, it never triggers.\n const lastValue = points[lastIndex]?.value ?? 0\n // The marker is an HTML overlay positioned by PERCENT of width (so it survives the SVG's\n // preserveAspectRatio=\"none\" scaling undistorted) -- always 0 for a single point, always 100 for\n // the last of more than one, matching px()'s own 0..WIDTH mapping.\n const lastLeftPct = lastIndex === 0 ? 0 : 100\n return { area, line, lastLeftPct, lastTopPx: py(lastValue) }\n}\n\n// [data] momentum wave -- no tap target. `value` is club-positive (clubPressure - oppPressure),\n// but colour follows VENUE, not club, to stay consistent with the score/timeline cards: the club's\n// own colour is --ss-w-home when `clubIsHome`, --ss-w-away otherwise. So a club-positive swing (up,\n// above the baseline) is filled with the club's venue colour, and an opponent-positive swing (down)\n// with the opponent's venue colour -- top/bottom are NOT fixed to home/away, they flip with\n// `clubIsHome` so the same team is always the same colour across every live card.\nexport function MomentumWave({\n points,\n caption,\n clubIsHome,\n}: {\n points: MomentumPoint[]\n caption?: string | null\n clubIsHome: boolean\n}): JSX.Element | null {\n if (points.length === 0) return null\n\n const { area, line, lastLeftPct, lastTopPx } = buildPaths(points)\n const clipId = useId()\n const topClipId = `${clipId}-top`\n const bottomClipId = `${clipId}-bottom`\n const topClass = clubIsHome ? 'ss-w-fandash-live-mom-home' : 'ss-w-fandash-live-mom-away'\n const bottomClass = clubIsHome ? 'ss-w-fandash-live-mom-away' : 'ss-w-fandash-live-mom-home'\n\n return (\n <div className=\"ss-w-fandash-live-mom\">\n {caption ? <span className=\"ss-w-fandash-live-mom-caption\">{caption}</span> : null}\n <div className=\"ss-w-fandash-live-mom-plot\">\n <svg\n className=\"ss-w-fandash-live-mom-svg\"\n viewBox={`0 0 ${WIDTH} ${HEIGHT}`}\n preserveAspectRatio=\"none\"\n role=\"img\"\n aria-label={caption ?? 'Momentum'}\n >\n <defs>\n <clipPath id={topClipId}>\n <rect x={0} y={0} width={WIDTH} height={BASELINE} />\n </clipPath>\n <clipPath id={bottomClipId}>\n <rect x={0} y={BASELINE} width={WIDTH} height={HEIGHT - BASELINE} />\n </clipPath>\n </defs>\n <path d={area} className={topClass} clipPath={`url(#${topClipId})`} />\n <path d={area} className={bottomClass} clipPath={`url(#${bottomClipId})`} />\n <line x1={0} y1={BASELINE} x2={WIDTH} y2={BASELINE} className=\"ss-w-fandash-live-mom-base\" />\n <path d={line} className=\"ss-w-fandash-live-mom-line\" vectorEffect=\"non-scaling-stroke\" />\n </svg>\n {/* HTML overlay dot, not an SVG <circle> -- the SVG's preserveAspectRatio=\"none\" stretches\n non-uniform scaling into an oval, and at x=WIDTH half of a circle hangs off the edge.\n An HTML element can't be deformed by the SVG's viewBox scaling, and clamp() keeps it\n fully inside the plot at both ends. */}\n <span\n className=\"ss-w-fandash-live-mom-now\"\n style={{ left: `clamp(4px, ${lastLeftPct}%, calc(100% - 4px))`, top: `${lastTopPx}px` }}\n aria-hidden=\"true\"\n />\n </div>\n </div>\n )\n}\n","import type { LiveStatsCard as LiveStatsCardData } from '@sensiblestats/widget-sdk'\nimport { MomentumWave } from './MomentumWave'\n\n// Split-bar widths as percentages, rounded to 1dp so the rendered width string stays short and\n// stable in tests. Guarded for the 0/0 case (or any non-positive total) -- an even 50/50 split\n// rather than a NaN width, since a stat can legitimately be 0-0 early in a match.\nfunction splitWidths(homeNum: number, awayNum: number): { home: string; away: string } {\n const total = homeNum + awayNum\n if (total <= 0) return { home: '50%', away: '50%' }\n const homePct = Math.round((homeNum / total) * 1000) / 10\n return { home: `${homePct}%`, away: `${Math.round((100 - homePct) * 10) / 10}%` }\n}\n\n// [data] card -- in-play match stats, home value / stat label / away value per row, each backed\n// by a home/away split bar, plus an optional momentum wave (or its text fallback). No tap target.\n//\n// LiveStatRow itself only carries clubNum/oppNum (club vs opponent), but LiveStatsData now also\n// carries `clubIsHome`/`homeName`/`awayName` (mirroring the venue signal LiveScoreCard already\n// has and the ClubIsHome pattern on RestingNextData/PostMatchNextData) -- so this card orients by\n// VENUE, not by club, to stay colour-consistent with the score and timeline cards: home is always\n// --ss-w-home on the left, away is always --ss-w-away on the right, and clubNum/oppNum are placed\n// on whichever side `clubIsHome` says the club actually occupies this match.\nexport function LiveStatsCard({ card }: { card: LiveStatsCardData }): JSX.Element {\n const { data } = card\n return (\n <div className=\"ss-w-fandash-card ss-w-fandash-live-stats\">\n {card.title ? <span className=\"ss-w-fandash-eyebrow\">{card.title}</span> : null}\n <div className=\"ss-w-fandash-live-stat-rows\">\n {data.rows.map((r, i) => {\n const homeValue = data.clubIsHome ? r.clubValue : r.oppValue\n const awayValue = data.clubIsHome ? r.oppValue : r.clubValue\n const homeNum = data.clubIsHome ? r.clubNum : r.oppNum\n const awayNum = data.clubIsHome ? r.oppNum : r.clubNum\n const { home, away } = splitWidths(homeNum, awayNum)\n return (\n <div key={`${r.label}-${i}`} className=\"ss-w-fandash-live-stat\">\n <div className=\"ss-w-fandash-live-stat-row\">\n <span className=\"ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--home\">{homeValue}</span>\n <span className=\"ss-w-fandash-live-stat-label\">{r.label}</span>\n <span className=\"ss-w-fandash-live-stat-value ss-w-fandash-live-stat-value--away\">{awayValue}</span>\n </div>\n <div className=\"ss-w-fandash-live-bar\">\n <span className=\"ss-w-fandash-live-bar-home\" style={{ width: home }} />\n <span className=\"ss-w-fandash-live-bar-away\" style={{ width: away }} />\n </div>\n </div>\n )\n })}\n </div>\n {data.momentum.length > 0 ? (\n <MomentumWave points={data.momentum} caption={data.momentumLabel} clubIsHome={data.clubIsHome} />\n ) : data.momentumLabel ? (\n <span className=\"ss-w-fandash-live-momentum\">{data.momentumLabel}</span>\n ) : null}\n {data.rows.length > 0 ? (\n <div className=\"ss-w-fandash-live-legend\">\n <span className=\"ss-w-fandash-live-legend-item\">\n <i className=\"ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--home\" />\n {data.homeName}\n </span>\n <span className=\"ss-w-fandash-live-legend-item\">\n <i className=\"ss-w-fandash-live-legend-swatch ss-w-fandash-live-legend-swatch--away\" />\n {data.awayName}\n </span>\n </div>\n ) : null}\n </div>\n )\n}\n","import type {\n ClubFanDashboardCard,\n ClubFanDashboardPayload,\n CongestedWeekCard as CongestedWeekCardData,\n LiveEventLine,\n LiveTimelineCard as LiveTimelineCardData,\n PostMatchGoalsCard as PostMatchGoalsCardData,\n PostMatchStatsCard as PostMatchStatsCardData,\n PostMatchTopPerformerCard as PostMatchTopPerformerCardData,\n RestingNextCard as RestingNextCardData,\n RestingStandingsCard as RestingStandingsCardData,\n RestingSeasonCard as RestingSeasonCardData,\n} from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../../config'\nimport { FixtureCard } from './FixtureCard'\nimport { CountdownCard } from './CountdownCard'\nimport { InjuriesCard } from './InjuriesCard'\nimport { ReasonToBetCard } from './ReasonToBetCard'\nimport { WhereToWatchCard } from './WhereToWatchCard'\nimport { CongestedWeekCard } from './CongestedWeekCard'\nimport { TransfersCard } from './TransfersCard'\nimport { LinksCard } from './LinksCard'\nimport { PostMatchResultCard } from './PostMatchResultCard'\nimport { PostMatchGoalsCard } from './PostMatchGoalsCard'\nimport { PostMatchStatsCard } from './PostMatchStatsCard'\nimport { PostMatchTopPerformerCard } from './PostMatchTopPerformerCard'\nimport { PostMatchNextCard } from './PostMatchNextCard'\nimport { RestingNextCard } from './RestingNextCard'\nimport { RestingStandingsCard } from './RestingStandingsCard'\nimport { RestingSeasonCard } from './RestingSeasonCard'\nimport { RestingFormCard } from './RestingFormCard'\nimport { LiveScoreCard } from './LiveScoreCard'\nimport { LiveTimelineCard } from './LiveTimelineCard'\nimport { LiveStatsCard } from './LiveStatsCard'\n\n// The [prefill] card types (see ClubFanDashboardPayload.cs) -- tapping any of them sends its\n// actionLabel as a follow-up message, carrying the opaque actionRef so the server resolves the\n// pre-issued binding. Every other card type is a [data] card with no tap target. FixtureCard is a\n// DataCard now (u319): its tap moved to the greeting chips, so it's not in this union any more.\nexport type ClubFanDashboardTapCard =\n | CongestedWeekCardData\n | PostMatchGoalsCardData\n | PostMatchStatsCardData\n | PostMatchTopPerformerCardData\n | RestingNextCardData\n | RestingStandingsCardData\n | RestingSeasonCardData\n\nexport function ClubFanDashboard({ dashboard, onTap, ui }: {\n dashboard: ClubFanDashboardPayload\n onTap: (card: ClubFanDashboardTapCard) => void\n ui?: UiConfig\n}): JSX.Element {\n // The clock leads the dashboard, so any countdown card is floated to the top; the rest keep\n // their server order.\n const orderedCards = [\n ...dashboard.cards.filter((c) => c.cardType === 'countdown'),\n ...dashboard.cards.filter((c) => c.cardType !== 'countdown'),\n ]\n // The score card's scorers line is derived from the sibling timeline card's goal events, so it\n // needs pulling out here where the full card list is in scope. Null-safe: no timeline card (or\n // no goals in it) means no scorers line, not a crash.\n const timelineCard = dashboard.cards.find(\n (c): c is LiveTimelineCardData => c.cardType === 'liveTimeline',\n )\n const goalEvents = timelineCard?.data.events.filter((e) => e.type === 'goal')\n return (\n <div className=\"ss-w-fandash\">\n {dashboard.greeting ? <span className={dashboard.greetingIsLead ? 'ss-w-fandash-greeting ss-w-fandash-greeting--lead' : 'ss-w-fandash-greeting'}>{dashboard.greeting}</span> : null}\n <div className=\"ss-w-fandash-cards\">\n {orderedCards.map((card, i) => (\n <FanDashboardCard key={`${card.cardType}-${i}`} card={card} onTap={onTap} ui={ui} goalEvents={goalEvents} />\n ))}\n </div>\n </div>\n )\n}\n\nfunction FanDashboardCard({ card, onTap, ui, goalEvents }: {\n card: ClubFanDashboardCard\n onTap: (card: ClubFanDashboardTapCard) => void\n ui?: UiConfig\n goalEvents?: LiveEventLine[]\n}): JSX.Element | null {\n switch (card.cardType) {\n case 'fixture':\n return <FixtureCard card={card} />\n case 'countdown':\n return <CountdownCard card={card} />\n case 'injuries':\n return <InjuriesCard card={card} ui={ui} />\n case 'reasonToBet':\n return <ReasonToBetCard card={card} />\n case 'whereToWatch':\n return <WhereToWatchCard card={card} />\n case 'congestedWeek':\n return <CongestedWeekCard card={card} onTap={onTap} />\n case 'transfers':\n return <TransfersCard card={card} />\n case 'links':\n return <LinksCard card={card} />\n case 'postMatchResult':\n return <PostMatchResultCard card={card} />\n case 'postMatchGoals':\n return <PostMatchGoalsCard card={card} onTap={onTap} />\n case 'postMatchStats':\n return <PostMatchStatsCard card={card} onTap={onTap} />\n case 'postMatchTopPerformer':\n return <PostMatchTopPerformerCard card={card} onTap={onTap} />\n case 'postMatchNext':\n return <PostMatchNextCard card={card} />\n case 'restingNext':\n return <RestingNextCard card={card} onTap={onTap} />\n case 'restingStandings':\n return <RestingStandingsCard card={card} onTap={onTap} />\n case 'restingSeason':\n return <RestingSeasonCard card={card} onTap={onTap} />\n case 'restingForm':\n return <RestingFormCard card={card} />\n case 'liveScore':\n return <LiveScoreCard card={card} goalEvents={goalEvents} />\n case 'liveTimeline':\n return <LiveTimelineCard card={card} ui={ui} />\n case 'liveStats':\n return <LiveStatsCard card={card} />\n default:\n // The server's cardType is a closed set, but a mismatched deploy could still send an\n // unrecognised discriminator -- render nothing for it rather than crash the whole turn.\n return null\n }\n}\n","import type { GreetingDashboardTile } from '@sensiblestats/widget-sdk'\nimport type { Message } from '../reducer'\nimport type { ActionVM } from '../model'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { Markdown } from './Markdown'\nimport { EntityCardList } from './EntityCardList'\nimport { BettingInsightList } from './BettingInsightList'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { OddsMovementCardList } from './OddsMovementCard'\nimport { ActionButtons } from './ActionButtons'\nimport { GreetingDashboard } from './dashboard/GreetingDashboard'\nimport { ClubFanDashboard, type ClubFanDashboardTapCard } from './dashboard/ClubFanDashboard'\n\nexport function ChatMessage({ message, disabled, onAct, onTap, ui, slip, monitor }: {\n message: Message\n disabled: boolean\n onAct: (a: ActionVM) => void\n onTap: (tile: GreetingDashboardTile, index: number) => void\n ui?: UiConfig\n slip: SlipHandlerProps\n monitor?: LiveMonitorController\n}): JSX.Element {\n if (message.role === 'user') {\n return <div className=\"ss-w-msg ss-w-user\" data-msg-id={message.id}><div className=\"ss-w-bubble\">{message.text}</div></div>\n }\n // A [prefill] club-fan-dashboard card tap reuses the same send path as an action button --\n // actionLabel becomes both the message and the display text, and the opaque actionRef rides\n // along so the server resolves the card's pre-issued action binding rather than re-planning\n // a prose command -- rather than threading a second tap handler through MessageList.\n const onFanDashboardTap = (card: ClubFanDashboardTapCard): void => {\n onAct({ message: card.actionLabel, actionRef: card.actionRef, label: card.actionLabel || card.title || '' })\n }\n return (\n <div className=\"ss-w-msg ss-w-bot\" data-msg-id={message.id}>\n {message.text && !message.greetingDashboard && !message.clubFanDashboard ? <Markdown text={message.text} /> : null}\n {message.greetingDashboard && !message.clubFanDashboard ? <GreetingDashboard dashboard={message.greetingDashboard} onTap={onTap} /> : null}\n {message.clubFanDashboard ? <ClubFanDashboard dashboard={message.clubFanDashboard} onTap={onFanDashboardTap} ui={ui} /> : null}\n <EntityCardList cards={message.cards} disabled={disabled} showLessLabel={ui?.showLess} showMoreLabel={ui?.showMore} />\n <BettingInsightList insights={message.insights} ui={ui} slip={slip} monitor={monitor} />\n <MarketOddsCardList cards={message.marketOdds} ui={ui} slip={slip} monitor={monitor} />\n <OddsMovementCardList cards={message.oddsMovement} ui={ui} monitor={monitor} />\n <ActionButtons actions={message.actions} loading={false} disabled={disabled} onAct={onAct} />\n </div>\n )\n}\n","import type { ChipVM } from '../model'\n\nexport function IntentChips({ chips, onPick }: { chips: ChipVM[]; onPick: (text: string) => void }): JSX.Element | null {\n if (chips.length === 0) return null\n return (\n <div className=\"ss-w-chips\">\n {chips.map((c, i) => (\n <button key={`${c.text}-${i}`} type=\"button\" className=\"ss-w-chip\" onClick={() => onPick(c.text)}>{c.text}</button>\n ))}\n </div>\n )\n}\n","// Distance (px) from the bottom within which the list is still considered\n// \"pinned\" — small enough that a user reading earlier content isn't counted\n// as pinned, large enough to absorb sub-pixel/rounding drift while streaming.\nexport const PIN_THRESHOLD = 48\n\n/**\n * True when the scroll container is at (or within PIN_THRESHOLD of) its bottom.\n * Used to decide whether new content should auto-scroll: we follow the stream\n * only while the user is already at the bottom, so late arrivals (e.g. suggested\n * actions) never yank a user who has scrolled up to read.\n */\nexport function isPinnedToBottom(el: Pick<HTMLElement, 'scrollHeight' | 'scrollTop' | 'clientHeight'>, threshold = PIN_THRESHOLD): boolean {\n return el.scrollHeight - el.scrollTop - el.clientHeight <= threshold\n}\n","import { useState, type KeyboardEvent } from 'react'\nimport { SendIcon } from './Icons'\n\nexport function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = 'Stop response', sendLabel = 'Send message' }: { placeholder: string; streaming: boolean; onSend: (t: string) => void; onStop: () => void; stopLabel?: string; sendLabel?: string }): JSX.Element {\n const [value, setValue] = useState('')\n const submit = () => { const t = value.trim(); if (!t) return; onSend(t); setValue('') }\n const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit() }\n }\n return (\n <div className=\"ss-w-input\">\n <textarea className=\"ss-w-textarea\" rows={1} placeholder={placeholder} value={value} disabled={streaming} onChange={(e) => setValue(e.target.value)} onKeyDown={onKeyDown} />\n {streaming ? (\n <button type=\"button\" className=\"ss-w-send ss-w-stop\" aria-label={stopLabel} onClick={onStop}><span className=\"ss-w-stop-glyph\" /></button>\n ) : (\n <button type=\"button\" className=\"ss-w-send\" aria-label={sendLabel} onClick={submit}><SendIcon /></button>\n )}\n </div>\n )\n}\n","import type { LiveMonitorController, MonitorTab } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\n\nexport function TabBar({ monitor, ui, matchCount, oddsCount, todayCount, hasToday, gamesEnabled }: {\n monitor: LiveMonitorController\n ui: UiConfig\n matchCount: number\n oddsCount: number\n /** Live match count. NEVER the fixture count -- a Saturday would badge 41. */\n todayCount: number\n hasToday: boolean\n /** Enabled when getGames resolves non-null; false for betting operators (404 sentinel). */\n gamesEnabled?: boolean\n}): JSX.Element | null {\n const tabs: { tab: MonitorTab; label: string; count: number; dot: boolean }[] = [\n { tab: 'chat', label: ui.tabChat, count: 0, dot: monitor.chatDot },\n ...(hasToday ? [{ tab: 'today' as MonitorTab, label: ui.tabToday, count: todayCount, dot: monitor.todayDot }] : []),\n ...(matchCount > 0 ? [{ tab: 'following' as MonitorTab, label: ui.tabFollowing, count: matchCount, dot: monitor.matchesDot }] : []),\n ...(oddsCount > 0 ? [{ tab: 'odds' as MonitorTab, label: ui.tabOdds, count: oddsCount, dot: monitor.oddsDot }] : []),\n ...(gamesEnabled ? [\n { tab: 'games' as MonitorTab, label: ui.tabGames, count: 0, dot: false },\n { tab: 'leaderboard' as MonitorTab, label: ui.tabLeaderboard, count: 0, dot: false },\n ] : []),\n ]\n\n // A lone Chat tab is chrome that selects nothing -- the strip stays hidden, as it does today\n // when nothing is pinned.\n if (tabs.length < 2) return null\n\n return (\n <div className=\"ss-w-tabs\" role=\"tablist\">\n {tabs.map(({ tab, label, count, dot }) => {\n const active = monitor.activeTab === tab\n return (\n <button\n key={tab}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n data-on={active ? '' : undefined}\n className=\"ss-w-tab\"\n onClick={() => monitor.setActiveTab(tab)}\n >\n {label}\n {count > 0 && <span className=\"ss-w-tab-count\">{count}</span>}\n {dot && !active && <span className=\"ss-w-tab-dot\" aria-hidden=\"true\" />}\n </button>\n )\n })}\n </div>\n )\n}\n","import type { LiveMonitorMatch } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { PinToggle } from './PinToggle'\nimport { toMarketOddsVM } from '../model'\n\nexport function MarketAccordion({ match, monitor, ui, slip }: {\n match: LiveMonitorMatch\n monitor: LiveMonitorController\n ui: UiConfig\n slip: SlipHandlerProps\n}): JSX.Element | null {\n const markets = match.availableMarkets ?? []\n if (markets.length === 0) return null\n const open = monitor.openMarket[match.matchId] ?? null\n\n return (\n <div className=\"ss-w-acc\">\n {markets.map((m) => {\n // A suspended market has no servable card: the odds lookup drops every suspended/stopped\n // row, so /live-monitor/market answers 404 MarketNotPriced and the panel lands on the\n // tap-to-retry affordance, which can never succeed. Don't offer the tap. `&& !m.suspended`\n // also collapses a market that suspends WHILE open, instead of leaving stale rows up.\n const isOpen = open === m.marketDeveloperName && !m.suspended\n const key = `${match.matchId}:${m.marketDeveloperName}`\n const entry = monitor.marketOdds[key]\n return (\n <div key={m.marketDeveloperName} className={isOpen ? 'ss-w-acc-row ss-w-acc-row-open' : 'ss-w-acc-row'}>\n <div className=\"ss-w-acc-head\">\n <button\n type=\"button\"\n className={m.suspended ? 'ss-w-acc-toggle ss-w-acc-toggle--susp' : 'ss-w-acc-toggle'}\n aria-expanded={isOpen}\n disabled={m.suspended}\n onClick={() => monitor.toggleMarket(match.matchId, m.marketDeveloperName)}\n >\n <span className=\"ss-w-acc-chevron\">{m.suspended ? '' : isOpen ? '▾' : '▸'}</span>\n <span className=\"ss-w-acc-label\">{m.marketLabel}</span>\n {m.hasInsight && <span className=\"ss-w-acc-badge\">★</span>}\n {m.suspended && <span className=\"ss-w-acc-susp\">{ui.accordionSuspended}</span>}\n </button>\n <PinToggle\n ui={ui}\n monitor={monitor}\n pin={{ kind: 'market', matchId: match.matchId, marketDeveloperName: m.marketDeveloperName }}\n />\n </div>\n {isOpen && (\n <div className=\"ss-w-acc-panel\">\n {entry?.error && (\n <div\n className=\"ss-w-acc-retry\"\n onClick={() => monitor.retryMarket(match.matchId, m.marketDeveloperName)}\n >\n {ui.accordionRetry}\n </div>\n )}\n {entry?.block?.insight?.text && (\n <div className=\"ss-w-acc-insight\">\n <span className=\"ss-w-acc-badge\">{ui.accordionValueLabel}</span> {entry.block.insight.text}\n </div>\n )}\n {entry?.block?.card && (\n <MarketOddsCardList\n cards={[toMarketOddsVM(entry.block.card)]}\n ui={ui}\n slip={slip}\n monitor={monitor}\n inSlipIds={monitor.inSlip}\n hideHeader\n />\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n","import type { LiveMonitorEvent, LiveMonitorMatch, LiveMonitorStatRow, PinRef, SlipSelection } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport { SlipButton } from './AddToSlipButton'\nimport { Crest } from './Crest'\nimport { MomentumWave } from './dashboard/MomentumWave'\nimport { PinToggle } from './PinToggle'\n\nfunction chipSelection(row: LiveMonitorStatRow, matchId: number, conversationId?: string): SlipSelection | null {\n const chip = row.market\n if (!chip || !chip.addToSlipEnabled || typeof chip.matchOddsId !== 'number' || typeof chip.price !== 'number') return null\n const selection: SlipSelection = { matchOddsId: chip.matchOddsId, matchId, oddsDecimal: chip.price }\n if (conversationId !== undefined) selection.conversationId = conversationId\n return selection\n}\n\n// A stat row's market chip promotes to the top when the user has pinned that market -- matched by\n// FIELD, never by a reconstructed pin key. LiveMonitorStatPrice carries no `line`, and its\n// selectionLabel is server-localized (TR \"2.5 Üst\" vs the stored pin's raw \"Over\"), so any key\n// string built from the chip would never equal the stored pin's key. marketDeveloperName is the\n// one field both sides always share in its raw, unlocalized form; matchOddsId is an unambiguous\n// same-selection identifier when both sides carry it.\nfunction isPromoted(row: LiveMonitorStatRow, promotedPins: readonly PinRef[]): boolean {\n const chip = row.market\n if (!chip) return false\n return promotedPins.some((pin) =>\n pin.marketDeveloperName === chip.marketDeveloperName ||\n (chip.matchOddsId != null && pin.matchOddsId === chip.matchOddsId))\n}\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\ninterface ScorerLine { player: string; label: string }\n\n// One line per scorer for a single side, in the order goals were scored, with a brace collapsed\n// onto that scorer's line (\"Powell 87', 90+6'\"). An own goal carries an \"(OG)\" marker on its\n// minute. Goals arrive already ascending from the server; grouping by name preserves that order\n// via the first appearance of each scorer.\nfunction groupScorers(goals: LiveMonitorEvent[], ownGoalLabel: string): ScorerLine[] {\n const order: string[] = []\n const minutesByPlayer = new Map<string, string[]>()\n for (const g of goals) {\n const name = g.player ?? ''\n const minute = g.ownGoal ? `${g.minuteLabel} (${ownGoalLabel})` : g.minuteLabel\n if (!minutesByPlayer.has(name)) {\n minutesByPlayer.set(name, [])\n order.push(name)\n }\n minutesByPlayer.get(name)!.push(minute)\n }\n return order.map((name) => {\n const minutes = minutesByPlayer.get(name)!.join(', ')\n return { player: name, label: name ? `${name} ${minutes}` : minutes }\n })\n}\n\nexport function MonitorMatchCard({ match, promotedPins, monitor, ui, slip }: {\n match: LiveMonitorMatch\n /** the user's non-match pins on this match — their stat rows promote to the top strip */\n promotedPins: PinRef[]\n monitor: LiveMonitorController\n ui: UiConfig\n slip: SlipHandlerProps\n}): JSX.Element {\n const live = match.phase === 'live'\n const goals = match.events.filter((e) => e.type === 'goal')\n const homeScorers = groupScorers(goals.filter((e) => e.side === 'home'), ui.ownGoalLabel)\n const awayScorers = groupScorers(goals.filter((e) => e.side === 'away'), ui.ownGoalLabel)\n const promotedRows = match.statRows.filter((row) => isPromoted(row, promotedPins))\n const otherRows = match.statRows.filter((row) => !isPromoted(row, promotedPins))\n const orderedRows = [...promotedRows, ...otherRows]\n const kickoff = match.phase === 'preMatch' && match.kickoffUtc ? ui.bettingKickoff(match.kickoffUtc) : undefined\n\n return (\n <div className=\"ss-w-mon\">\n <div className=\"ss-w-mon-top\">\n {live && (\n <span className=\"ss-w-fandash-live-pill\">\n <span className=\"ss-w-fandash-live-dot\" aria-hidden=\"true\" />\n {ui.liveLabel}\n </span>\n )}\n {match.phase === 'fullTime' && <span className=\"ss-w-mon-pill\">{ui.fullTimeLabel}</span>}\n {kickoff && <span className=\"ss-w-mon-pill\">{kickoff.dayLabel} · {kickoff.time}</span>}\n {live && match.minuteLabel && <span className=\"ss-w-mon-min\">{match.minuteLabel}</span>}\n {match.competitionName && <span className=\"ss-w-mon-comp\">{match.competitionName}</span>}\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: match.matchId }} />\n </div>\n <div className=\"ss-w-mon-main\">\n <span className=\"ss-w-mon-side\">\n <Crest kind=\"team\" url={match.homeCrestUrl ?? undefined} name={match.homeTeamName ?? undefined} />\n <span className=\"ss-w-mon-name\">{match.homeTeamName}</span>\n </span>\n {match.phase === 'preMatch' ? (\n <span className=\"ss-w-mon-vs\">vs</span>\n ) : (\n <span className=\"ss-w-mon-score\">{match.homeScore}<i>–</i>{match.awayScore}</span>\n )}\n <span className=\"ss-w-mon-side ss-w-mon-side--away\">\n <Crest kind=\"team\" url={match.awayCrestUrl ?? undefined} name={match.awayTeamName ?? undefined} />\n <span className=\"ss-w-mon-name\">{match.awayTeamName}</span>\n </span>\n </div>\n {(homeScorers.length > 0 || awayScorers.length > 0) && (\n <div className=\"ss-w-mon-scorers\">\n <ul className=\"ss-w-mon-scorers-col ss-w-mon-scorers-home\">\n {homeScorers.map((s, i) => <li key={`${s.player}-${i}`}>{s.label}</li>)}\n </ul>\n <span className=\"ss-w-mon-scorers-ball\" aria-hidden=\"true\">⚽</span>\n <ul className=\"ss-w-mon-scorers-col ss-w-mon-scorers-away\">\n {awayScorers.map((s, i) => <li key={`${s.player}-${i}`}>{s.label}</li>)}\n </ul>\n </div>\n )}\n <div className=\"ss-w-mon-stats\">\n {orderedRows.map((row) => {\n const total = row.homeNum + row.awayNum\n const homePct = total > 0 ? (row.homeNum / total) * 75 : 0\n const awayPct = total > 0 ? (row.awayNum / total) * 75 : 0\n const promoted = isPromoted(row, promotedPins)\n const selection = chipSelection(row, match.matchId, slip.conversationId)\n return (\n <div className={promoted ? 'ss-w-mon-stat ss-w-mon-pstrip' : 'ss-w-mon-stat'} key={row.label}>\n <div className=\"ss-w-mon-stat-row\">\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--home\">{row.homeValue}</span>\n <span className=\"ss-w-mon-stat-l\">{row.label}</span>\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--away\">{row.awayValue}</span>\n </div>\n <div className=\"ss-w-mon-bar\">\n <b className=\"ss-w-mon-bar-home\" style={{ width: `${homePct}%` }} />\n <i className=\"ss-w-mon-bar-away\" style={{ width: `${awayPct}%` }} />\n </div>\n {/* A suspended market drops its whole betting line -- label, price and button -- and\n the stat row keeps its bar, exactly like a row with no market at all. Showing it\n offered a price the bookmaker was not taking next to a live Add to slip whose\n only possible outcome was the slipSuspended error toast. bet365 suspends\n derivative in-play markets constantly: measured across 20 live matches, 61% of\n Goals Over/Under rows and 69% of 1st Half Goals rows were suspended against 9%\n of Fulltime Result. */}\n {row.market && !row.market.isSuspended && (\n <div className={promoted ? 'ss-w-mon-stat-mkt ss-w-mon-mkt' : 'ss-w-mon-stat-mkt'}>\n <span>{row.market.marketLabel} · {row.market.selectionLabel}</span>\n <span className=\"ss-w-mon-stat-mkt-right\">\n {typeof row.market.price === 'number' && <span className=\"ss-w-mon-price\">{row.market.price.toFixed(2)}</span>}\n <SlipButton\n selection={selection}\n shownOdds={typeof row.market.price === 'number' ? row.market.price.toFixed(2) : ''}\n marketName={row.market.marketLabel}\n marketDeveloperName={row.market.marketDeveloperName}\n slip={slip}\n ui={ui}\n />\n </span>\n </div>\n )}\n </div>\n )\n })}\n </div>\n {match.status === 'stale' && <span className=\"ss-w-mon-asof\">{ui.asOf(formatTime(match.asOfUtc))}</span>}\n {match.momentum.length > 0 && (\n <div className=\"ss-w-mon-mom\">\n {/* Label only -- no percentage split. momentumHomePct is a share of the WHOLE match's\n accumulated pressure, so it reads as a verdict on the match (\"99% - 1%\") when the\n wave beneath it is showing minute-by-minute swing. The two disagree on sight, and\n the share is the one that misleads. */}\n <span className=\"ss-w-mon-stat-l\">{ui.momentumLabel}</span>\n <MomentumWave points={match.momentum} clubIsHome={true} />\n </div>\n )}\n {match.phase === 'fullTime' && <div className=\"ss-w-mon-grace\">{ui.graceNote}</div>}\n </div>\n )\n}\n","import type { LiveMonitorMarket } from '@sensiblestats/widget-sdk'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { UiConfig } from '../config'\nimport type { SlipHandlerProps } from '../slip'\nimport type { MarketOddsRowVM, MarketOddsVM } from '../model'\nimport { MarketOddsCardList } from './MarketOddsCardList'\nimport { OddsMovementCardList } from './OddsMovementCard'\nimport { MarketAccordion } from './MarketAccordion'\nimport { MonitorMatchCard } from './MonitorMatchCard'\nimport { toMarketOddsVM, toOddsMovementVM } from '../model'\n\n// Slim live-only strip above an Odds-tab market card. The card itself already shows the\n// competition, fixture, market, kickoff and the unpin — so this renders ONLY the match-live\n// context the card lacks (score, minute, suspended/settled, stale as-of), and nothing at all for\n// a pre-match market (avoids duplicating the card's fixture/kickoff). (u342)\nfunction OddsLiveStrip({ m, ui }: { m: LiveMonitorMarket; ui: UiConfig }): JSX.Element | null {\n const showScore = m.phase !== 'preMatch' && typeof m.homeScore === 'number'\n const stale = m.status === 'stale'\n if (!showScore && !m.minuteLabel && !(m.isSuspended && !m.isSettled) && !m.isSettled && !stale) return null\n return (\n <div className=\"ss-w-mk-live\">\n {showScore && (\n <b className=\"ss-w-mk-live-score\">{m.homeTeamName} {m.homeScore}–{m.awayScore} {m.awayTeamName}</b>\n )}\n {m.minuteLabel && <span className=\"ss-w-mon-min\">{m.minuteLabel}</span>}\n {m.isSuspended && !m.isSettled && <span className=\"ss-w-mon-susp\">{ui.suspendedLabel}</span>}\n {m.isSettled && <span className=\"ss-w-mon-pill\">{ui.fullTimeLabel}</span>}\n {stale && (\n <span className=\"ss-w-mon-asof\">{ui.asOf(new Date(m.asOfUtc).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }))}</span>\n )}\n </div>\n )\n}\n\nexport function MatchesPanel({ monitor, ui, slip }: { monitor: LiveMonitorController; ui: UiConfig; slip: SlipHandlerProps }): JSX.Element {\n // Only EXPLICIT match pins surface here (2026-09-06 ruling: an odds pin tracks odds, a match\n // pin tracks the match -- never combined). Filtering against current pins, not just the\n // snapshot, also makes an unpin drop the card immediately.\n const matches = (monitor.snapshot?.matches ?? []).filter((m) =>\n monitor.pins.some((p) => p.kind === 'match' && p.matchId === m.matchId))\n if (matches.length === 0) return <div className=\"ss-w-mon-empty\">{ui.emptyMatchesTab}</div>\n return (\n <div className=\"ss-w-mon-list\">\n {matches.map((m) => (\n <div key={m.matchId} className=\"ss-w-mon-item\">\n <MonitorMatchCard\n match={m}\n // promotion is PER MATCH: only odds pins on THIS match promote their stat row\n promotedPins={monitor.pins.filter((p) => p.kind !== 'match' && p.matchId === m.matchId)}\n monitor={monitor}\n ui={ui}\n slip={slip}\n />\n <MarketAccordion match={m} monitor={monitor} ui={ui} slip={slip} />\n </div>\n ))}\n </div>\n )\n}\n\n// I2 (since-view movement): the badge on a pin's PRIMARY row must reflect what THIS operator's\n// client last saw (monitor.lastViewedPrices, keyed by the market snapshot's own key), never the\n// server's own previousPrice/movementDirection window -- those two clocks are unrelated. Only the\n// first main row carries this override; other rows/lines keep whatever (if anything) the server\n// sent.\nfunction withSinceViewMovement(vm: MarketOddsVM, prev: number | undefined): MarketOddsVM {\n const primary = vm.mainRows[0]\n if (prev === undefined || !primary || primary.oddsDecimal === undefined || primary.oddsDecimal === prev) return vm\n const updatedPrimary: MarketOddsRowVM = {\n ...primary,\n previousOdds: prev.toFixed(2),\n movementDirection: primary.oddsDecimal < prev ? 'shortened' : 'drifted',\n }\n return { ...vm, mainRows: [updatedPrimary, ...vm.mainRows.slice(1)] }\n}\n\nexport function OddsPanel({ monitor, ui, slip }: { monitor: LiveMonitorController; ui: UiConfig; slip: SlipHandlerProps }): JSX.Element {\n // Same current-pins filter as MatchesPanel: only markets a stored pin still claims render, so\n // every card carries its unpin affordance and vanishes the moment that pin is removed.\n const markets = (monitor.snapshot?.markets ?? []).filter((m) =>\n monitor.pins.some((p) => p.key === m.key))\n if (markets.length === 0) return <div className=\"ss-w-mon-empty\">{ui.emptyOddsTab}</div>\n return (\n <div className=\"ss-w-mon-list\">\n {markets.map((m) => {\n // The unpin lives in the card's own header now; pass the ORIGINAL stored pin ref (found by\n // key) so its pinKey matches exactly -- the card would otherwise reconstruct a market pin\n // with line=mainLine, which never matches an accordion pin stored without a line.\n const pin = monitor.pins.find((p) => p.key === m.key)\n return (\n <div className=\"ss-w-mon-oddspin\" key={m.key} data-settled={m.isSettled || undefined}>\n <OddsLiveStrip m={m} ui={ui} />\n {/* D5 persistent in-slip badge: the wasAdded->markInSlip wrapping now lives in\n StatsWidget's own slip memo (so a conversation-path add also arms the badge) --\n this panel only reads monitor.inSlip to render it. */}\n {m.card && (\n <MarketOddsCardList\n cards={[withSinceViewMovement(toMarketOddsVM(m.card), monitor.lastViewedPrices[m.key])]}\n ui={ui}\n slip={slip}\n monitor={monitor}\n pinRef={pin ?? undefined}\n inSlipIds={monitor.inSlip}\n />\n )}\n {m.history && <OddsMovementCardList cards={[toOddsMovementVM(m.history)]} ui={ui} />}\n {!m.card && !m.history && <div className=\"ss-w-mon-empty-card\">{ui.oddsUnavailable}</div>}\n </div>\n )\n })}\n </div>\n )\n}\n","import type { MatchState, ScheduleMatch } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { PinToggle } from './PinToggle'\n\nfunction kickoffLabel(kickoffUnix: number): string {\n const d = new Date(kickoffUnix * 1000)\n return `${`${d.getHours()}`.padStart(2, '0')}:${`${d.getMinutes()}`.padStart(2, '0')}`\n}\n\n// The away side mirrors the home side around the score: crest on the far (right)\n// edge, name aligned inward toward the score. Reversing the flow in CSS keeps the\n// DOM order crest→name identical to home, matching the away pattern used by the\n// fandash fixture/live cards.\nfunction Side({ name, crest, away = false }: { name: string; crest?: string | null; away?: boolean }): JSX.Element {\n return (\n <span className={away ? 'ss-w-drow-side ss-w-drow-side--away' : 'ss-w-drow-side'}>\n {crest ? <img className=\"ss-w-drow-crest\" src={crest} alt=\"\" /> : null}\n <span className=\"ss-w-drow-nm\">{name}</span>\n </span>\n )\n}\n\nexport function FixtureRow({ match, state, stale, ui, monitor }: {\n match: ScheduleMatch\n state?: MatchState\n stale: boolean\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element {\n // Deliberately no per-match staleness test. u357 added one, reading Match.UpdatedAt through\n // stateAsOfUtc — but that column advances only when the DATA CHANGES, not when we poll. Measured\n // on sandbox1: every live match had a poll age of 31-48s while UpdatedAt ages ran 32-1451s, so\n // the guard suppressed the clock on 9 of 17 healthy matches, Levante v Barcelona among them. The\n // stalled window it was built for does not exist; `stale` (our own fetch failing) is the only\n // real signal we have, and it already covers the whole payload.\n const isLive = state?.phase === 'live' && !stale\n // Gated on phase, never on the presence of a number: /states counts goal rows, so it reports 0\n // for a fixture with none whatever its phase, and the due set polls anything whose kickoff clock\n // has passed. A \"NotStarted\" fixture between the clock passing and the live feed flipping would\n // otherwise read 0-0. The typeof pair only narrows the template below.\n const hasScore = (state?.phase === 'live' || state?.phase === 'fullTime')\n && typeof state.homeScore === 'number' && typeof state.awayScore === 'number'\n\n // Rendered verbatim. The minute runs ~2 min behind wall clock because the provider's own\n // `minutes` field is a snapshot we freeze until the next poll -- that is being corrected at the\n // source in the hub (deriving from the ticking period's start), NOT compensated for here. Two\n // layers each adding elapsed to the same number is how you get a 139th minute.\n const ticked = state?.phase === 'live' ? (state.minuteLabel ?? null) : null\n const when = state?.isHalfTime && !stale\n ? ui.halfTime\n : isLive\n ? (ticked ?? '\\u2014')\n : state?.phase === 'live'\n ? '\\u2014'\n : kickoffLabel(match.kickoffUnix)\n\n return (\n <div className={isLive || state?.isHalfTime ? 'ss-w-drow ss-w-drow--live' : 'ss-w-drow'}>\n <span className={isLive || state?.isHalfTime ? 'ss-w-drow-when ss-w-drow-when--live' : 'ss-w-drow-when'}>{when}</span>\n <span className=\"ss-w-drow-fx\">\n <Side name={match.homeTeamName} crest={match.homeTeamImagePath} />\n {/* The score sits between the two sides, where a scoreboard puts it. With no score yet it\n is the separating dash, so the row keeps one shape before and after kickoff. */}\n <span className={hasScore ? 'ss-w-drow-sc' : 'ss-w-drow-sc ss-w-drow-sc--idle'}>\n {hasScore ? `${state!.homeScore}–${state!.awayScore}` : '–'}\n </span>\n <Side name={match.awayTeamName} crest={match.awayTeamImagePath} away />\n </span>\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: match.matchId }} />\n </div>\n )\n}\n","import type { MatchState, ScheduleGroup } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport { FixtureRow } from './FixtureRow'\nimport { isTreatedLive } from '../liveClock'\n\nexport function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor, disambiguate = false }: {\n group: ScheduleGroup\n open: boolean\n onToggle(): void\n /** True when another group on screen shares this competition's name, so the name alone\n * does not identify it. Only then is the country worth the horizontal space. */\n disambiguate?: boolean\n states: Record<number, MatchState>\n stale: boolean\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element | null {\n // A live fixture is rendered in the live band above, so it is absent here AND absent from the\n // count -- the badge has to agree with what is under the header. But once the poll goes stale\n // the live band hides itself (Task 13), so a cached phase:'live' match must fall back into its\n // group rather than vanish from the tab entirely -- mirrors FixtureRow's own isLive check.\n const own = group.matches.filter((m) => !isTreatedLive(states[m.matchId], stale))\n const hasLive = own.length !== group.matches.length\n\n // Every match hoisted into the live band leaves nothing under this header. Rendering anyway\n // produced a header reading \"Championship ... 0\" whose body was empty however you toggled it.\n // Hiding it is safe against the vanish bug the filter above guards: when the poll goes stale\n // isTreatedLive is false for everything, so own is the full list and the group comes back.\n if (own.length === 0) {\n return null\n }\n\n return (\n <div className=\"ss-w-grp\">\n <button type=\"button\" className=\"ss-w-grp-head\" aria-expanded={open} onClick={onToggle}>\n <span className=\"ss-w-grp-chev\">{open ? '▾' : '▸'}</span>\n {hasLive && <span className=\"ss-w-sec-dot\" aria-hidden=\"true\" />}\n <span className=\"ss-w-grp-name\">\n {group.competitionName}\n {disambiguate && group.competitionCountry\n ? <span className=\"ss-w-grp-country\"> ({group.competitionCountry})</span>\n : null}\n </span>\n <span className=\"ss-w-grp-count\">{own.length}</span>\n </button>\n {open && (\n <div className=\"ss-w-grp-body\">\n {own.map((m) => (\n <FixtureRow key={m.matchId} match={m} state={states[m.matchId]} stale={stale} ui={ui} monitor={monitor} />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import type { UiConfig } from '../config'\nimport type { LiveMonitorController } from '../useLiveMonitor'\nimport type { MatchDiscoveryController } from '../useMatchDiscovery'\nimport { CompetitionGroup } from './CompetitionGroup'\nimport { FixtureRow } from './FixtureRow'\nimport { isTreatedLive, visibleGroupsOf } from '../liveClock'\n\nexport function TodayPanel({ discovery, ui, monitor }: {\n discovery: MatchDiscoveryController\n ui: UiConfig\n monitor: LiveMonitorController\n}): JSX.Element {\n const { groups, states, stale, expanded, toggleGroup } = discovery\n\n // Finished matches leave the day. Everything below reads visibleGroups, never groups: the live\n // band, the name-collision count, the group list and the tab strip that decides whether this\n // panel is reachable at all have to agree on what the day contains, and filtering in one place\n // is what guarantees that.\n const visibleGroups = visibleGroupsOf(groups, states)\n\n // Flat across competitions but ordered by the competition's rank, then by the fixture's position\n // inside its group -- no ranking field of the client's own. Array.sort is stable, so ties within\n // a rank keep the flatMap's group-then-match order.\n // The sort is NOT dead code: `rank` is the contract, the array order is not. That the composer\n // currently emits groups already in rank order is incidental -- nothing in the wire format\n // promises it, and a server-side reordering would silently scramble the live band without this.\n const liveRows = stale\n ? []\n : visibleGroups\n .flatMap((group) =>\n group.matches\n .filter((m) => isTreatedLive(states[m.matchId], stale))\n .map((match) => ({ match, rank: group.rank })))\n .sort((a, b) => a.rank - b.rank)\n\n // competitionName is not an identity: a real Saturday returns four groups named \"Premier\n // League\". Only collide-on-screen names pay the horizontal cost of a country suffix.\n const nameCounts = visibleGroups.reduce<Record<string, number>>((acc, g) => {\n acc[g.competitionName] = (acc[g.competitionName] ?? 0) + 1\n return acc\n }, {})\n\n return (\n <div className=\"ss-w-mon-list\">\n {stale && <div className=\"ss-w-stale\">{ui.staleStates}</div>}\n\n {liveRows.length > 0 && (\n <>\n <div className=\"ss-w-sec-head\">\n <span className=\"ss-w-sec-dot\" aria-hidden=\"true\" />\n {ui.sectionLive}\n </div>\n <div className=\"ss-w-today-live\">\n {liveRows.map(({ match }) => (\n <FixtureRow key={match.matchId} match={match} state={states[match.matchId]}\n stale={stale} ui={ui} monitor={monitor} />\n ))}\n </div>\n </>\n )}\n\n {visibleGroups.map((group) => (\n <CompetitionGroup\n key={group.competitionId}\n group={group}\n open={expanded[group.competitionId] ?? group.expandedByDefault}\n onToggle={() => toggleGroup(group.competitionId)}\n disambiguate={(nameCounts[group.competitionName] ?? 0) > 1}\n states={states}\n stale={stale}\n ui={ui}\n monitor={monitor}\n />\n ))}\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { GameSummary, LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { GamesLoginWall } from './GamesLoginWall'\nimport { GamesHub } from './GamesHub'\nimport { GameScreenHost } from './GameScreenHost'\nimport { ensureGamesFonts } from './games/ui/fonts'\n\nexport function GamesPanel({\n loggedIn,\n games,\n ui,\n conversation,\n leaderboard,\n}: {\n loggedIn: boolean\n games: GameSummary[]\n ui: UiConfig\n conversation?: GamePlayConversation | null\n leaderboard?: LeaderboardPayload | null\n}): JSX.Element {\n const [selected, setSelected] = useState<{ gameId: string; fixtureId: number; gameDay: string; lockAtUtc: string | null } | null>(null)\n\n useEffect(() => { ensureGamesFonts() }, [])\n\n if (!loggedIn) return <GamesLoginWall ui={ui} />\n\n if (selected !== null) {\n return (\n <div className=\"ss-w-gscreen-wrap\" lang={ui.games.lang}>\n <GameScreenHost\n selected={selected}\n onBack={() => setSelected(null)}\n conversation={conversation ?? null}\n ui={ui}\n />\n </div>\n )\n }\n\n return (\n <div className=\"ss-g-hub-wrap\" data-testid=\"games-hub\" lang={ui.games.lang}>\n <GamesHub\n games={games}\n onOpen={(g: GameSummary) => setSelected({ gameId: g.gameId, fixtureId: g.fixtureId, gameDay: g.gameDay, lockAtUtc: g.lockAtUtc ?? null })}\n myWeeklyRow={leaderboard?.myWeeklyRow ?? null}\n ui={ui}\n />\n </div>\n )\n}\n","import type { UiConfig } from '../config'\n\nexport function GamesLoginWall({ ui }: { ui: UiConfig }): JSX.Element {\n return (\n <div className=\"ss-w-mon-list\">\n <div className=\"ss-w-games-wall\">\n <p>{ui.gamesLoginRequired}</p>\n </div>\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { GameSummary, LeaderboardRow } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { GameTile } from './GameTile'\nimport { Chip } from './games/ui/Chip'\nimport { IconFlame } from './games/ui/icons'\n\nconst PLAYABLE = new Set<GameSummary['status']>(['available', 'in_progress'])\nconst DONE = new Set<GameSummary['status']>(['played', 'graded'])\n\nexport function pickHeroGame(games: GameSummary[]): GameSummary | null {\n const daily = games.filter(g => g.kind === 'daily')\n const tiger = daily.find(g => g.gameId === 'mystery-tiger')\n if (tiger && PLAYABLE.has(tiger.status)) return tiger\n const firstPlayable = daily.find(g => PLAYABLE.has(g.status))\n if (firstPlayable) return firstPlayable\n return tiger ?? daily[0] ?? null\n}\n\n// Two fixtures of one game on one day must not share a key.\nexport const tileKey = (g: GameSummary): string => `${g.gameId}-${g.gameDay}-${g.fixtureId}`\n\nexport function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }: {\n games: GameSummary[]\n myWeeklyRow?: LeaderboardRow | null\n weeklyPrize?: string\n onOpen: (g: GameSummary) => void\n ui: UiConfig\n}): JSX.Element {\n const [, setTick] = useState(0)\n useEffect(() => {\n const id = setInterval(() => setTick(t => t + 1), 60_000)\n return () => clearInterval(id)\n }, [])\n\n const hero = pickHeroGame(games)\n const daily = games.filter(g => g.kind === 'daily' && g !== hero)\n const grid = daily.filter(g => g.gameId !== 'beat-the-grid')\n const wide = daily.find(g => g.gameId === 'beat-the-grid')\n const fixtures = games.filter(g => g.kind === 'fixture')\n const kickoffs = fixtures.map(g => g.kickoffUtc).filter((k): k is string => !!k).sort()\n const todayPts = games.filter(g => DONE.has(g.status)).reduce((s, g) => s + (g.score ?? 0), 0)\n const dash = '—'\n\n return (\n <div className=\"ss-g-hub\">\n <div className=\"ss-g-stats\">\n <div className=\"ss-g-stat\"><span className=\"ss-g-stat-l\">{ui.games.statStreak}</span>\n <span className=\"ss-g-stat-v\" data-testid=\"stat-streak\">\n {myWeeklyRow ? <><IconFlame />{myWeeklyRow.currentStreak}</> : dash}\n {myWeeklyRow && <small>{ui.games.unitDays}</small>}\n </span></div>\n <div className=\"ss-g-stat\"><span className=\"ss-g-stat-l\">{ui.games.statToday}</span>\n <span className=\"ss-g-stat-v ss-g-stat-v--accent\" data-testid=\"stat-today\">{ui.games.formatPts(todayPts)}<small>{ui.games.unitPts}</small></span></div>\n <div className=\"ss-g-stat\"><span className=\"ss-g-stat-l\">{ui.games.statRank}</span>\n <span className=\"ss-g-stat-v\" data-testid=\"stat-rank\">{myWeeklyRow ? `#${myWeeklyRow.rank}` : dash}\n {myWeeklyRow && <small>{ui.games.thisWeek}</small>}</span></div>\n </div>\n\n {weeklyPrize && <Chip variant=\"accent\" className=\"ss-g-prize\">{weeklyPrize}</Chip>}\n\n {hero && <GameTile game={hero} onOpen={onOpen} ui={ui} variant=\"hero\" />}\n\n {(grid.length > 0 || wide) && (\n <section className=\"ss-g-sec\">\n <div className=\"ss-g-sec-head\"><h3>{ui.games.dailyGames}</h3><span>{ui.games.newSetAtMidnight}</span></div>\n {grid.length > 0 && <div className=\"ss-g-grid\">{grid.map(g => <GameTile key={tileKey(g)} game={g} onOpen={onOpen} ui={ui} />)}</div>}\n {wide && <GameTile game={wide} onOpen={onOpen} ui={ui} variant=\"wide\" />}\n </section>\n )}\n\n {fixtures.length > 0 && (\n <section className=\"ss-g-sec\">\n <div className=\"ss-g-sec-head\"><h3>{ui.games.matchdayGames}</h3>\n {kickoffs[0] && <span>{ui.games.kickoffAt(ui.games.formatDayTime(kickoffs[0]))}</span>}</div>\n <div className=\"ss-g-grid\">{fixtures.map(g => <GameTile key={tileKey(g)} game={g} onOpen={onOpen} ui={ui} />)}</div>\n </section>\n )}\n </div>\n )\n}\n","// Canonical display names keyed by gameId — the backend does not always send a title,\n// and a raw gameId (\"beat-the-grid\") must never surface to a fan.\nexport const GAME_TITLES: Record<string, string> = {\n 'mystery-tiger': 'Mystery Tiger',\n 'daily-quiz': 'Daily Quiz',\n 'career-path': 'Career Path',\n 'beat-the-grid': 'Beat the Grid',\n 'guess-the-xi': 'Guess the XI',\n 'higher-or-lower': 'Higher or Lower',\n 'matchday-predictor': 'Matchday Predictor',\n 'starting-xi': 'Starting XI',\n 'stat-ladder': 'Stat Ladder',\n 'fan-motm': 'Fan MOTM',\n}\n\nfunction prettifyGameId(gameId: string): string {\n return gameId.split('-').map(w => (w ? w[0]!.toUpperCase() + w.slice(1) : w)).join(' ')\n}\n\n// `title` is nullable because GameSummary.title is `string | null` (widget-sdk events.ts).\nexport function gameTitle(g: { gameId: string; title?: string | null }): string {\n return g.title ?? GAME_TITLES[g.gameId] ?? prettifyGameId(g.gameId)\n}\n\n// Design renders \"first name\" small over \"SURNAME\" big. Surname = last token.\nexport function splitName(full: string): { first: string; last: string } {\n const parts = full.trim().split(/\\s+/).filter(Boolean)\n if (parts.length <= 1) return { first: '', last: parts[0] ?? '' }\n return { first: parts.slice(0, -1).join(' '), last: parts[parts.length - 1]! }\n}\n","export function GameTileArt({ gameId }: { gameId: string }): JSX.Element {\n return (\n <svg className=\"ss-g-art\" viewBox=\"0 0 120 74\" aria-hidden=\"true\">{ART[gameId] ?? ART.default}</svg>\n )\n}\n\nconst head = (cx: number, cy: number, r: number, cls = 'ss-g-art-fg') => (\n <g className={cls}><circle cx={cx} cy={cy - r * 0.3} r={r * 0.45} /><path d={`M${cx - r} ${cy + r}c0-${r * 0.8} ${r * 0.45}-${r * 1.1} ${r}-${r * 1.1}s${r} ${r * 0.3} ${r} ${r * 1.1}z`} /></g>\n)\n\nconst ART: Record<string, JSX.Element> = {\n 'mystery-tiger': <>{head(60, 38, 26, 'ss-g-art-fg')}<text x=\"60\" y=\"36\" className=\"ss-g-art-q\" textAnchor=\"middle\">?</text></>,\n 'higher-or-lower': <>{head(32, 38, 20)}{head(88, 38, 20)}<circle cx=\"60\" cy=\"37\" r=\"11\" className=\"ss-g-art-accent\" /><path d=\"M57 33l3-3 3 3M57 41l3 3 3-3\" className=\"ss-g-art-ink\" /></>,\n 'guess-the-xi': <><rect x=\"8\" y=\"4\" width=\"104\" height=\"66\" rx=\"6\" className=\"ss-g-art-pitch\" />{[[60, 60, 'a'], [24, 46], [48, 46], [72, 46], [96, 46], [36, 30], [60, 30], [84, 30], [40, 14], [60, 14], [80, 14]].map(([x, y, a], i) => <circle key={i} cx={x as number} cy={y as number} r=\"4\" className={a ? 'ss-g-art-accent' : 'ss-g-art-dot'} />)}</>,\n 'daily-quiz': <>{[[14, 8], [62, 8], [14, 40], [62, 40]].map(([x, y], i) => <rect key={i} x={x} y={y} width=\"44\" height=\"26\" rx=\"5\" className={i === 1 ? 'ss-g-art-correct' : 'ss-g-art-block'} />)}</>,\n 'career-path': <><path d=\"M18 22h24v10c0 7-5 11-12 13-7-2-12-6-12-13z\" className=\"ss-g-art-fg\" /><path d=\"M48 37h8M84 37h8\" className=\"ss-g-art-line\" /><path d=\"M60 22h24v10c0 7-5 11-12 13-7-2-12-6-12-13z\" className=\"ss-g-art-fg\" /><rect x=\"96\" y=\"22\" width=\"18\" height=\"26\" rx=\"4\" className=\"ss-g-art-dash\" /><text x=\"105\" y=\"40\" className=\"ss-g-art-q\" textAnchor=\"middle\">?</text></>,\n 'beat-the-grid': <>{[0, 1, 2].flatMap(r => [0, 1, 2].map(c => <rect key={`${r}${c}`} x={33 + c * 19} y={10 + r * 19} width=\"16\" height=\"16\" rx=\"3\" className={(r + c) % 3 === 0 ? 'ss-g-art-accent' : 'ss-g-art-block'} />))}</>,\n 'matchday-predictor': <><path d=\"M10 20h20v9c0 6-4 9-10 11-6-2-10-5-10-11z\" className=\"ss-g-art-fg\" /><rect x=\"38\" y=\"22\" width=\"18\" height=\"24\" rx=\"4\" className=\"ss-g-art-accent-stroke\" /><rect x=\"64\" y=\"22\" width=\"18\" height=\"24\" rx=\"4\" className=\"ss-g-art-dash\" /><path d=\"M90 20h20v9c0 6-4 9-10 11-6-2-10-5-10-11z\" className=\"ss-g-art-fg\" /></>,\n 'starting-xi': <><rect x=\"8\" y=\"4\" width=\"104\" height=\"66\" rx=\"6\" className=\"ss-g-art-pitch\" />{[[60, 60], [30, 46], [50, 46], [70, 46], [90, 46], [45, 30], [75, 30], [30, 16], [60, 16], [90, 16]].map(([x, y], i) => <circle key={i} cx={x} cy={y} r=\"5\" className={i < 7 ? 'ss-g-art-accent' : 'ss-g-art-dash'} />)}</>,\n 'stat-ladder': <>{[[20, 70], [34, 52], [48, 34]].map(([y, w], i) => <rect key={i} x=\"24\" y={y} width={w} height=\"12\" rx=\"3\" className={i === 1 ? 'ss-g-art-accent' : 'ss-g-art-block'} />)}</>,\n 'fan-motm': <><circle cx=\"60\" cy=\"37\" r=\"26\" className=\"ss-g-art-accent-stroke\" />{head(60, 40, 18)}<path d=\"M84 8l2.4 5 5.4.6-4 3.7 1.1 5.4-4.9-2.7-4.9 2.7 1.1-5.4-4-3.7 5.4-.6z\" className=\"ss-g-art-accent\" /></>,\n default: <circle cx=\"60\" cy=\"37\" r=\"22\" className=\"ss-g-art-fg\" />,\n}\n","import type { ReactNode } from 'react'\n\nexport type ChipVariant = 'neutral' | 'accent' | 'success' | 'badge' | 'lock'\n\nexport function Chip({ variant = 'neutral', icon, children, className }: {\n variant?: ChipVariant; icon?: ReactNode; children: ReactNode; className?: string\n}): JSX.Element {\n return (\n <span className={`ss-g-chip ss-g-chip--${variant}${className ? ` ${className}` : ''}`}>\n {icon}{children}\n </span>\n )\n}\n\nexport function StatStack({ value, label }: { value: ReactNode; label: string }): JSX.Element {\n return (\n <span className=\"ss-g-statstack\">\n <span className=\"ss-g-statstack-v\">{value}</span>\n <span className=\"ss-g-statstack-l\">{label}</span>\n </span>\n )\n}\n","type P = { size?: number }\nconst svg = (size: number, children: JSX.Element | JSX.Element[], fill = false): JSX.Element => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill={fill ? 'currentColor' : 'none'} stroke={fill ? 'none' : 'currentColor'}\n strokeWidth={2.2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">{children}</svg>\n)\nexport const IconChevronLeft = ({ size = 20 }: P) => svg(size, <path d=\"M15 18l-6-6 6-6\" />)\nexport const IconLock = ({ size = 14 }: P) => svg(size, [<rect key=\"a\" x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\" />, <path key=\"b\" d=\"M8 11V7a4 4 0 0 1 8 0v4\" />])\nexport const IconCheck = ({ size = 14 }: P) => svg(size, <path d=\"M5 12l5 5 9-10\" />)\nexport const IconClose = ({ size = 16 }: P) => svg(size, <path d=\"M6 6l12 12M18 6L6 18\" />)\nexport const IconSearch = ({ size = 18 }: P) => svg(size, [<circle key=\"a\" cx=\"11\" cy=\"11\" r=\"7\" />, <path key=\"b\" d=\"M20 20l-3.5-3.5\" />])\nexport const IconPlus = ({ size = 20 }: P) => svg(size, <path d=\"M12 5v14M5 12h14\" />)\nexport const IconStar = ({ size = 14 }: P) => svg(size, <path d=\"M12 2.5l2.9 6 6.6.8-4.9 4.5 1.3 6.5L12 17l-5.9 3.3 1.3-6.5L2.5 9.3l6.6-.8z\" />, true)\nexport const IconBulb = ({ size = 16 }: P) => svg(size, [<path key=\"a\" d=\"M9 18h6M10 21h4\" />, <path key=\"b\" d=\"M12 3a6 6 0 0 0-3.5 10.9V16h7v-2.1A6 6 0 0 0 12 3z\" />])\nexport const IconArrowUp = ({ size = 12 }: P) => svg(size, <path d=\"M12 19V5M5 12l7-7 7 7\" />)\nexport const IconArrowDown = ({ size = 12 }: P) => svg(size, <path d=\"M12 5v14M19 12l-7 7-7-7\" />)\nexport const IconCalendar = ({ size = 18 }: P) => svg(size, [<rect key=\"a\" x=\"4\" y=\"5\" width=\"16\" height=\"15\" rx=\"2\" />, <path key=\"b\" d=\"M4 10h16M9 3v4M15 3v4\" />])\nexport const IconShield = ({ size = 18 }: P) => svg(size, <path d=\"M12 3l7 3v6c0 5-3 8-7 9-4-1-7-4-7-9V6z\" />)\nexport const IconFlag = ({ size = 18 }: P) => svg(size, <path d=\"M5 21V4M5 4h12l-2 4 2 4H5\" />)\nexport const IconBall = ({ size = 18 }: P) => svg(size, [<circle key=\"a\" cx=\"12\" cy=\"12\" r=\"9\" />, <path key=\"b\" d=\"M12 7l4 3-1.5 4.5h-5L8 10z\" />])\nexport const IconBoot = ({ size = 18 }: P) => svg(size, <path d=\"M4 6h6l1 6 8 3v3H4z\" />)\nexport const IconGloves = ({ size = 18 }: P) => svg(size, <path d=\"M7 21v-8l-2-3V6a1.5 1.5 0 0 1 3 0v3V4a1.5 1.5 0 0 1 3 0v5V3.5a1.5 1.5 0 0 1 3 0V9V5a1.5 1.5 0 0 1 3 0v9l-2 3v4z\" />)\nexport const IconFlame = ({ size = 16 }: P) => svg(size, <path d=\"M12 3c1 4 5 5 5 10a5 5 0 0 1-10 0c0-3 2-4 2-7 1.5 1 2 2 2 3 1-2 1-4 1-6z\" />, true)\n","import type { GameSummary } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { gameTitle } from './games/ui/gameMeta'\nimport { GameTileArt } from './GameTileArt'\nimport { Chip } from './games/ui/Chip'\nimport { IconChevronLeft } from './games/ui/icons'\n\nexport type TileTone = 'new' | 'accent' | 'success' | 'muted'\n\n/** Pure: the tile's status line and tone, from the existing GameSummary fields only. */\nexport function tileStatus(game: GameSummary, ui: UiConfig): { text: string; tone: TileTone } {\n switch (game.status) {\n case 'locked': return { text: ui.gameLocked, tone: 'muted' }\n case 'voided': return { text: ui.gameVoided, tone: 'muted' }\n case 'in_progress': return { text: ui.games.resume, tone: 'accent' }\n case 'played':\n case 'graded':\n return game.ranked\n ? { text: ui.games.doneWithScore(game.score ?? 0), tone: 'success' }\n : { text: ui.games.done, tone: 'success' }\n default:\n if (game.kind === 'fixture' && game.lockAtUtc && new Date(game.lockAtUtc).getTime() > Date.now()) {\n return { text: ui.games.locksAt(ui.games.formatDayTime(game.lockAtUtc)), tone: 'accent' }\n }\n return { text: ui.games.taglines[game.gameId] ?? ui.gamePlay, tone: 'new' }\n }\n}\n\nconst DISABLED = new Set<GameSummary['status']>(['locked', 'voided'])\n\nexport function GameTile({ game, onOpen, ui, variant = 'tile' }: {\n game: GameSummary; onOpen: (g: GameSummary) => void; ui: UiConfig; variant?: 'tile' | 'wide' | 'hero'\n}): JSX.Element {\n const status = tileStatus(game, ui)\n const disabled = DISABLED.has(game.status)\n const title = gameTitle(game)\n\n const body = variant === 'hero' ? (\n <>\n <span className=\"ss-g-hero-text\">\n <span className=\"ss-g-hero-eyebrow\">{ui.games.dailyChallenge}</span>\n {status.tone === 'new' && <Chip variant=\"badge\">{ui.games.newToday}</Chip>}\n <span className=\"ss-g-hero-title\">{title}</span>\n <span className=\"ss-g-hero-sub\">{ui.games.taglines[game.gameId] ?? ''}</span>\n {status.tone === 'success'\n ? <span className=\"ss-g-tile-status\" data-tone=\"success\">{status.text}</span>\n : <span className=\"ss-g-hero-cta\">{status.tone === 'accent' ? ui.games.resume : ui.games.playNow} →</span>}\n </span>\n <span className=\"ss-g-hero-art\"><GameTileArt gameId={game.gameId} /></span>\n </>\n ) : variant === 'wide' ? (\n <>\n <span className=\"ss-g-wide-art\"><GameTileArt gameId={game.gameId} /></span>\n <span className=\"ss-g-wide-text\">\n <span className=\"ss-g-tile-title\">{title}</span>\n <span className=\"ss-g-tile-status\" data-tone={status.tone}>{status.text}</span>\n {status.tone === 'new' && <Chip variant=\"badge\">{ui.games.newToday}</Chip>}\n </span>\n <span className=\"ss-g-wide-chev\"><IconChevronLeft size={18} /></span>\n </>\n ) : (\n <>\n <span className=\"ss-g-tile-art\"><GameTileArt gameId={game.gameId} /></span>\n <span className=\"ss-g-tile-title\">{title}</span>\n <span className=\"ss-g-tile-status\" data-tone={status.tone}>{status.text}</span>\n </>\n )\n\n const cls = `ss-g-tile ss-g-tile--${variant}`\n if (disabled) return <div className={cls} data-disabled aria-disabled=\"true\">{body}</div>\n return <button type=\"button\" className={cls} aria-label={`${title} — ${status.text}`} onClick={() => onOpen(game)}>{body}</button>\n}\n","import { useEffect, useRef, useState } from 'react'\nimport type { UiConfig } from '../config'\nimport type { GamePlayConversation } from '../useGamePlay'\nimport { useGamePlay } from '../useGamePlay'\nimport { MysteryTigerGame } from './games/MysteryTigerGame'\nimport { HigherOrLowerGame } from './games/HigherOrLowerGame'\nimport { CareerPathGame } from './games/CareerPathGame'\nimport { BeatTheGridGame } from './games/BeatTheGridGame'\nimport { GuessTheXiGame } from './games/GuessTheXiGame'\nimport { DailyQuizGame } from './games/DailyQuizGame'\nimport { MatchdayPredictorGame } from './games/MatchdayPredictorGame'\nimport { StartingXiGame } from './games/StartingXiGame'\nimport { StatLadderGame } from './games/StatLadderGame'\nimport { FanMotmGame } from './games/FanMotmGame'\nimport { GameHeader } from './games/ui/GameHeader'\nimport { gameTitle } from './games/ui/gameMeta'\nimport type {\n MysteryTigerConfig,\n HolConfig,\n CareerPathConfig,\n BeatTheGridConfig,\n GuessTheXiConfig,\n DailyQuizConfig,\n MatchdayPredictorConfig,\n StartingXiConfig,\n StatLadderConfig,\n FanMotmConfig,\n} from './games/types'\n\n// Fixture games need a pending-result poll: they submit once before kickoff,\n// then remain in \"pending\" until resolved at full time.\nconst FIXTURE_GAME_IDS = new Set([\n 'matchday-predictor',\n 'starting-xi',\n 'stat-ladder',\n 'fan-motm',\n])\n\n// Poll cadence while a fixture game result is pending (30 seconds).\nconst PENDING_POLL_INTERVAL_MS = 30_000\n\nfunction safeParseConfig<T>(json: string | null | undefined): T | null {\n if (!json) return null\n try {\n return JSON.parse(json) as T\n } catch {\n return null\n }\n}\n\nexport function GameScreenHost({\n selected,\n onBack,\n conversation,\n ui,\n}: {\n selected: { gameId: string; fixtureId: number; gameDay?: string; lockAtUtc?: string | null }\n onBack: () => void\n conversation: GamePlayConversation | null | undefined\n ui: UiConfig\n}): JSX.Element {\n const { gameId, fixtureId, gameDay = '', lockAtUtc = null } = selected\n\n // Fetch config on open\n const [configJson, setConfigJson] = useState<string | null>(null)\n\n useEffect(() => {\n setConfigJson(null)\n if (!conversation) return\n let cancelled = false\n void (async () => {\n try {\n const payload = await conversation.getGameConfig(gameId, fixtureId, gameDay || undefined)\n if (!cancelled && payload?.configJson) {\n setConfigJson(payload.configJson)\n }\n } catch {\n // best-effort\n }\n })()\n return () => { cancelled = true }\n }, [conversation, gameId, fixtureId, gameDay])\n\n // Shared submit lifecycle\n const { result, submitting, submit, hydrate, rawStatus } = useGamePlay(conversation, {\n gameId,\n gameDay: gameDay,\n fixtureId: fixtureId || undefined,\n })\n\n // Hydrate on open for a returning fan\n useEffect(() => {\n if (conversation) hydrate()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [conversation, gameId])\n\n // Pending-result poll: while a fixture game result is pending (submitted but not yet\n // resolved at full time), poll getGameResult at a low cadence until graded or voided.\n const hydrateRef = useRef(hydrate)\n hydrateRef.current = hydrate\n\n useEffect(() => {\n if (!FIXTURE_GAME_IDS.has(gameId)) return\n if (rawStatus !== 'pending') return\n\n const timerId = setInterval(() => {\n hydrateRef.current()\n }, PENDING_POLL_INTERVAL_MS)\n\n return () => clearInterval(timerId)\n }, [gameId, rawStatus])\n\n const sharedProps = {\n result,\n submitting,\n onSubmit: submit,\n ui,\n onBack,\n lockAtUtc,\n }\n\n function renderScreen(): JSX.Element {\n switch (gameId) {\n case 'mystery-tiger':\n return (\n <MysteryTigerGame\n {...sharedProps}\n config={safeParseConfig<MysteryTigerConfig>(configJson)}\n />\n )\n case 'higher-or-lower':\n return (\n <HigherOrLowerGame\n {...sharedProps}\n config={safeParseConfig<HolConfig>(configJson)}\n />\n )\n case 'career-path':\n return (\n <CareerPathGame\n {...sharedProps}\n config={safeParseConfig<CareerPathConfig>(configJson)}\n />\n )\n case 'beat-the-grid': {\n const btgConfig = safeParseConfig<BeatTheGridConfig>(configJson)\n return (\n <BeatTheGridGame\n {...sharedProps}\n config={btgConfig}\n playerPool={btgConfig?.playerPool ?? []}\n />\n )\n }\n case 'guess-the-xi':\n return (\n <GuessTheXiGame\n {...sharedProps}\n config={safeParseConfig<GuessTheXiConfig>(configJson)}\n />\n )\n case 'daily-quiz':\n return (\n <DailyQuizGame\n {...sharedProps}\n config={safeParseConfig<DailyQuizConfig>(configJson)}\n />\n )\n case 'matchday-predictor':\n return (\n <MatchdayPredictorGame\n {...sharedProps}\n config={safeParseConfig<MatchdayPredictorConfig>(configJson)}\n />\n )\n case 'starting-xi':\n return (\n <StartingXiGame\n {...sharedProps}\n config={safeParseConfig<StartingXiConfig>(configJson)}\n />\n )\n case 'stat-ladder':\n return (\n <StatLadderGame\n {...sharedProps}\n config={safeParseConfig<StatLadderConfig>(configJson)}\n />\n )\n case 'fan-motm':\n return (\n <FanMotmGame\n {...sharedProps}\n config={safeParseConfig<FanMotmConfig>(configJson)}\n />\n )\n default:\n return (\n <div className=\"ss-g-screen\" data-testid={`game-screen-${gameId}`}>\n <GameHeader title={gameTitle({ gameId })} onBack={onBack} backLabel={ui.back} />\n </div>\n )\n }\n }\n\n return (\n <div className=\"ss-w-gscreen\" data-testid=\"gscreen\" data-lock-at={lockAtUtc ?? undefined}>\n {renderScreen()}\n </div>\n )\n}\n","import { useCallback, useRef, useState } from 'react'\nimport type { GameResultPayload, GameStatePayload, SubmitPlayResult } from '@sensiblestats/widget-sdk'\n\nexport interface UseGamePlayOptions {\n gameId: string\n gameDay: string\n fixtureId?: number\n /** Called after a ranked play completes (pointsDelta present). */\n refresh?: () => void\n}\n\nexport interface UseGamePlayResult {\n result: SubmitPlayResult | null\n submitting: boolean\n submit: (answerJson: string) => Promise<void>\n hydrate: () => void\n /** Raw status string from the last getGameResult call (null until hydrated). */\n rawStatus: string | null\n}\n\nexport type GamePlayConversation = {\n postPlay: (gameId: string, answerJson: string, gameDay: string, fixtureId?: number) => Promise<SubmitPlayResult | null>\n getGameResult: (gameId: string, fixtureId?: number, gameDay?: string) => Promise<GameResultPayload | null>\n getGameConfig: (gameId: string, fixtureId?: number, gameDay?: string) => Promise<GameStatePayload | null>\n}\n\nfunction toSubmitResult(payload: GameResultPayload): SubmitPlayResult {\n return {\n // 'pending' means the play is recorded but awaiting resolution (fixture games)\n alreadyPlayed: payload.status === 'played' || payload.status === 'graded' || payload.status === 'pending',\n score: payload.score,\n isCorrect: payload.isCorrect,\n clientStateJson: payload.clientStateJson,\n attemptsUsed: payload.attemptsUsed,\n }\n}\n\nexport function useGamePlay(\n conversation: GamePlayConversation | null | undefined,\n { gameId, gameDay, fixtureId, refresh }: UseGamePlayOptions,\n): UseGamePlayResult {\n const [result, setResult] = useState<SubmitPlayResult | null>(null)\n const [submitting, setSubmitting] = useState(false)\n const [rawStatus, setRawStatus] = useState<string | null>(null)\n\n const inFlightRef = useRef(false)\n const convRef = useRef(conversation)\n convRef.current = conversation\n const optsRef = useRef({ gameId, gameDay, fixtureId, refresh })\n optsRef.current = { gameId, gameDay, fixtureId, refresh }\n // Mirror the latest result so submit() (a stable [] callback) can tell whether we\n // already hold in-progress state without wiping it.\n const resultRef = useRef<SubmitPlayResult | null>(null)\n resultRef.current = result\n\n const refetch = useCallback(async (): Promise<void> => {\n const conv = convRef.current\n if (!conv) return\n const opts = optsRef.current\n try {\n const payload = await conv.getGameResult(opts.gameId, opts.fixtureId, opts.gameDay)\n if (payload === null) return\n // Never let a null-clientState payload blank a board we already hold (e.g. a rescore that\n // couldn't reconstruct state). A first hydrate holds nothing, so a legitimately terminal\n // null-state play (voided / already-played) still renders; the status always updates.\n if (payload.clientStateJson == null && resultRef.current?.clientStateJson != null) {\n setRawStatus(payload.status)\n return\n }\n setResult(toSubmitResult(payload))\n setRawStatus(payload.status)\n } catch {\n // best-effort\n }\n }, [])\n\n const submit = useCallback(async (answerJson: string): Promise<void> => {\n const conv = convRef.current\n if (!conv || inFlightRef.current) return\n inFlightRef.current = true\n setSubmitting(true)\n try {\n const opts = optsRef.current\n const playResult = await conv.postPlay(opts.gameId, answerJson, opts.gameDay, opts.fixtureId)\n if (playResult !== null) {\n // Guard against a state-losing response: a still-in-progress submit that carries no\n // ClientStateJson (e.g. a server-side concurrency retry) must NOT overwrite the board\n // we already hold. Reconcile from the server instead of rendering an empty state.\n const hasFreshState = playResult.clientStateJson != null\n const isTerminal = playResult.alreadyPlayed === true\n const holdsState = resultRef.current?.clientStateJson != null\n if (!hasFreshState && !isTerminal && holdsState) {\n await refetch()\n } else {\n setResult(playResult)\n }\n if (playResult.pointsDelta != null) {\n opts.refresh?.()\n }\n }\n } catch {\n // best-effort; leave result unchanged\n } finally {\n inFlightRef.current = false\n setSubmitting(false)\n }\n }, [refetch])\n\n const hydrate = useCallback((): void => {\n void refetch()\n }, [refetch])\n\n return { result, submitting, submit, hydrate, rawStatus }\n}\n","import { useState, useId } from 'react'\nimport type { GameScreenProps, MysteryTigerConfig, MysteryTigerClientState, MysteryTigerGuessResult, MysteryTigerAttributeVerdict } from './types'\nimport { nationalityFlag } from './nationFlags'\nimport { PlayerAvatar } from './PlayerAvatar'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { SegmentProgress, type SegmentState } from './ui/SegmentProgress'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { Silhouette } from './ui/Silhouette'\nimport { ResultCard } from './ui/ResultCard'\nimport { OptionList } from './ui/OptionList'\nimport { IconBulb } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\n\nfunction parseClientState(json: string | null | undefined): MysteryTigerClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as MysteryTigerClientState\n } catch {\n return null\n }\n}\n\nexport type MtAttrKey = keyof Omit<MysteryTigerGuessResult, 'playerId'>\nconst ATTR_KEYS: MtAttrKey[] = ['position', 'nationality', 'age', 'shirtNumber', 'apps']\nconst NUMERIC_KEYS: ReadonlySet<MtAttrKey> = new Set<MtAttrKey>(['age', 'shirtNumber', 'apps'])\n\nconst MAX_GUESSES = 6\n\nfunction verdictGlyph(v: MysteryTigerAttributeVerdict): string {\n if (v.verdict === 'exact') return '✓'\n if (v.verdict === 'miss') return '✗'\n if (v.direction === 'up') return '↑'\n if (v.direction === 'down') return '↓'\n return '≈'\n}\n\n// Direction arrow shown under a numeric value (\"22 ▲\" = mystery player is older/higher/more).\nfunction directionArrow(v: MysteryTigerAttributeVerdict): string {\n if (v.direction === 'up') return '▲'\n if (v.direction === 'down') return '▼'\n return ''\n}\n\n// Full position names (Sportmonks \"Centre Forward\", \"Goalkeeper\", …) overflow the small square\n// tile, so map them to a short code for display. Anything unmapped falls back to its initials.\nconst POSITION_SHORT: Record<string, string> = {\n goalkeeper: 'GK', keeper: 'GK',\n defender: 'DEF', 'centre back': 'CB', 'center back': 'CB', 'centre-back': 'CB', 'center-back': 'CB',\n 'left back': 'LB', 'right back': 'RB', 'left wing-back': 'LWB', 'right wing-back': 'RWB', sweeper: 'SW',\n midfielder: 'MID', 'defensive midfield': 'DM', 'central midfield': 'CM', 'centre midfield': 'CM',\n 'attacking midfield': 'AM', 'left midfield': 'LM', 'right midfield': 'RM',\n 'left wing': 'LW', 'right wing': 'RW', 'left winger': 'LW', 'right winger': 'RW',\n forward: 'FWD', attacker: 'FWD', striker: 'ST', 'second striker': 'SS',\n 'centre forward': 'CF', 'center forward': 'CF', 'centre-forward': 'CF',\n}\n\nfunction shortPosition(value: string): string {\n const mapped = POSITION_SHORT[value.trim().toLowerCase()]\n if (mapped) return mapped\n if (value.length <= 3) return value.toUpperCase() // already a code (GK, ST, CB, …)\n return value.split(/[\\s-]+/).filter(Boolean).map(w => (w[0] ?? '').toUpperCase()).join('').slice(0, 3)\n}\n\n// The display face of a tile: the guessed player's own value (a flag for nationality, a short\n// code for position), falling back to the verdict glyph when the backend sent no value.\nfunction tileFace(key: MtAttrKey, v: MysteryTigerAttributeVerdict): string {\n if (!v.value) return verdictGlyph(v)\n if (key === 'nationality') return nationalityFlag(v.value)\n if (key === 'position') return shortPosition(v.value)\n return v.value\n}\n\nexport interface KnownAttribute { key: MtAttrKey; state: 'known' | 'range' | 'unknown'; text: string }\n\n// What the fan has pinned down so far, per attribute. An exact verdict reveals the value. For the\n// numeric attributes each ▲ (\"mystery is higher than v\") raises the floor and each ▼ lowers the\n// ceiling, so 23▲ + 26▼ reads \"24–25\", only ▼9 reads \"< 9\", only ▲31 reads \"> 31\".\nexport function deriveKnownAttributes(guesses: MysteryTigerGuessResult[], keys: MtAttrKey[]): KnownAttribute[] {\n return keys.map((key): KnownAttribute => {\n const exact = guesses.find(g => g[key].verdict === 'exact')\n if (exact) return { key, state: 'known', text: tileFace(key, exact[key]) }\n if (!NUMERIC_KEYS.has(key)) return { key, state: 'unknown', text: '?' }\n let maxUp: number | null = null\n let minDown: number | null = null\n for (const g of guesses) {\n const v = g[key]\n if (!v.value || !v.direction) continue\n const n = Number(v.value)\n if (!Number.isFinite(n)) continue\n if (v.direction === 'up') maxUp = maxUp === null ? n : Math.max(maxUp, n)\n else minDown = minDown === null ? n : Math.min(minDown, n)\n }\n if (maxUp !== null && minDown !== null) {\n const lo = maxUp + 1\n const hi = minDown - 1\n return { key, state: 'range', text: lo >= hi ? String(lo) : `${lo}–${hi}` }\n }\n if (minDown !== null) return { key, state: 'range', text: `< ${minDown}` }\n if (maxUp !== null) return { key, state: 'range', text: `> ${maxUp}` }\n return { key, state: 'unknown', text: '?' }\n })\n}\n\nexport function MysteryTigerGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<MysteryTigerConfig>): JSX.Element {\n const t = ui.games.mysteryTiger\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const guessResults = clientState?.guessResults ?? []\n const alreadyGuessedIds = new Set<number>(guessResults.map(g => g.playerId))\n const shirtEnabled = config?.shirtTileEnabled ?? clientState?.shirtTileEnabled ?? false\n const keys = ATTR_KEYS.filter(k => k !== 'shirtNumber' || shirtEnabled)\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.solved === true ||\n clientState?.failed === true\n\n const guessesUsed = clientState?.guessesUsed ?? guessResults.length\n const totalGuesses = clientState ? clientState.guessesUsed + clientState.guessesRemaining : MAX_GUESSES\n const score = result?.score ?? 0\n const revealName = isOver ? clientState?.revealedPlayerName : undefined\n\n const filtered =\n config && !isOver\n ? config.squadPlayers.filter(\n p => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handleSelect(playerId: number) {\n if (!config || isOver || submitting) return\n const prevGuesses = guessResults.map(g => g.playerId)\n const newGuesses = [...prevGuesses, playerId]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n const headerRight = !config ? undefined : isOver ? (\n <Chip variant=\"accent\">{score} {ui.games.unitPts}</Chip>\n ) : (\n <span data-testid=\"mt-chip\">\n <Chip>{ui.games.guess} <span className=\"ss-g-num\">{guessesUsed + 1}</span> / {totalGuesses}</Chip>\n </span>\n )\n\n const segments: SegmentState[] = Array.from({ length: totalGuesses }, (_, i) =>\n i < guessesUsed ? 'done' : i === guessesUsed ? 'current' : 'todo')\n const cols = { gridTemplateColumns: `minmax(0, 1fr) repeat(${keys.length}, 42px)` }\n const known = deriveKnownAttributes(guessResults, keys)\n\n return (\n <div className=\"ss-g-screen ss-g-mt\" data-testid=\"game-screen-mystery-tiger\">\n <GameHeader title={gameTitle({ gameId: 'mystery-tiger' })} eyebrow={t.eyebrow} right={headerRight}\n onBack={onBack} backLabel={ui.back} />\n\n {!config && <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>}\n\n {config && (\n <>\n <div className=\"ss-g-body\">\n <div className={`ss-g-mt-card${isOver ? ' ss-g-mt-card--reveal' : ''}`}>\n <div className=\"ss-g-mt-portrait\">\n {revealName ? (\n <PlayerAvatar className=\"ss-g-mt-photo\" name={revealName} imagePath={clientState?.revealedPlayerImagePath} />\n ) : (\n <Silhouette size={150} variant=\"mystery\" />\n )}\n {revealName && <span className=\"ss-g-mt-reveal-name\">{revealName}</span>}\n </div>\n <div className=\"ss-g-mt-known\" style={{ gridTemplateColumns: `repeat(${keys.length}, minmax(0, 1fr))` }}>\n {known.map(k => (\n <div key={k.key} className=\"ss-g-mt-known-cell\">\n <span className=\"ss-g-mt-lab\">{t.labels[k.key]}</span>\n <span className=\"ss-g-mt-known-v\" data-state={k.state} data-testid={`known-${k.key}`}>{k.text}</span>\n </div>\n ))}\n </div>\n </div>\n\n {!isOver && <SegmentProgress segments={segments} ariaLabel={t.progress(guessesUsed, totalGuesses)} />}\n\n {guessResults.length > 0 && (\n <div className=\"ss-g-mt-table\">\n <div className=\"ss-g-mt-thead\" style={cols}>\n <span>{t.yourGuesses}</span>\n {keys.map(k => <span key={k}>{t.labels[k]}</span>)}\n </div>\n {guessResults.map((gr, i) => {\n const name = config.squadPlayers.find(p => p.id === gr.playerId)?.name ?? `#${gr.playerId}`\n const { first, last } = splitName(name)\n return (\n <div key={gr.playerId} className=\"ss-g-mt-row\" style={cols}>\n <div className=\"ss-g-mt-who\">\n <PlayerAvatar className=\"ss-g-mt-av\" name={name} />\n <span className=\"ss-g-mt-names\">\n {first && <span className=\"ss-g-mt-first\">{first}</span>}\n <span className=\"ss-g-mt-last\">{last}</span>\n </span>\n </div>\n {keys.map(key => {\n const v = gr[key]\n const arrow = directionArrow(v)\n return (\n <div\n key={key}\n className=\"ss-g-mt-cell\"\n data-testid={`verdict-${key}-${i}`}\n data-verdict={v.verdict}\n aria-label={`${t.labels[key]}: ${v.value ?? v.verdict}${v.direction ? ` ${v.direction}` : ''}`}\n >\n <span className=\"ss-g-mt-cell-v\" aria-hidden=\"true\">{tileFace(key, v)}</span>\n {arrow && <span className=\"ss-g-mt-cell-dir\" aria-hidden=\"true\">{arrow}</span>}\n </div>\n )\n })}\n </div>\n )\n })}\n </div>\n )}\n\n {!isOver && (\n <div className=\"ss-g-mt-legend\">\n <span><i className=\"ss-g-mt-sw\" data-verdict=\"exact\" />{t.legendMatch}</span>\n <span><i className=\"ss-g-mt-sw\" data-verdict=\"near\" />{t.legendClose}</span>\n <span>▲ {t.legendHigher}</span>\n </div>\n )}\n\n {clientState?.hintLine && !isOver && (\n <div className=\"ss-g-mt-hint\"><IconBulb /><span>{clientState.hintLine}</span></div>\n )}\n\n {isOver && (\n <ResultCard\n tone={clientState?.solved ? 'win' : clientState?.failed ? 'lose' : 'neutral'}\n title={clientState?.solved ? t.solved : clientState?.failed ? t.failed : ui.games.alreadyPlayedTitle}\n score={score}\n detail={clientState ? t.detail(clientState.guessesUsed) : undefined}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {!isOver && (\n <FooterBar>\n {query.length > 0 && filtered.length > 0 && (\n <OptionList\n label={t.optionsLabel}\n options={filtered.map(p => ({\n key: p.id,\n content: <><PlayerAvatar className=\"ss-g-opt-av\" name={p.name} /><span>{p.name}</span></>,\n }))}\n onPick={k => handleSelect(Number(k))}\n />\n )}\n <SearchField id={inputId} label={t.searchLabel} placeholder={t.searchPlaceholder}\n value={query} onChange={setQuery} disabled={submitting} />\n </FooterBar>\n )}\n </>\n )}\n </div>\n )\n}\n","// Maps a nationality country-name string (as the games backend emits it) to a flag emoji.\n// UK home nations use subdivision flag emoji; everything else uses regional-indicator pairs.\n// Unmapped nationalities fall back to a short uppercased code so a slot is never blank.\n\nconst FLAGS: Record<string, string> = {\n england: '🏴\\u{E0067}\\u{E0062}\\u{E0065}\\u{E006E}\\u{E0067}\\u{E007F}',\n scotland: '🏴\\u{E0067}\\u{E0062}\\u{E0073}\\u{E0063}\\u{E0074}\\u{E007F}',\n wales: '🏴\\u{E0067}\\u{E0062}\\u{E0077}\\u{E006C}\\u{E0073}\\u{E007F}',\n 'northern ireland': '🇬🇧',\n 'republic of ireland': '🇮🇪',\n ireland: '🇮🇪',\n 'united kingdom': '🇬🇧',\n france: '🇫🇷', spain: '🇪🇸', portugal: '🇵🇹', germany: '🇩🇪', italy: '🇮🇹',\n netherlands: '🇳🇱', belgium: '🇧🇪', switzerland: '🇨🇭', austria: '🇦🇹',\n denmark: '🇩🇰', sweden: '🇸🇪', norway: '🇳🇴', finland: '🇫🇮', iceland: '🇮🇸',\n poland: '🇵🇱', czechia: '🇨🇿', 'czech republic': '🇨🇿', croatia: '🇭🇷',\n serbia: '🇷🇸', 'bosnia and herzegovina': '🇧🇦', greece: '🇬🇷', romania: '🇷🇴',\n ukraine: '🇺🇦', russia: '🇷🇺', hungary: '🇭🇺', slovakia: '🇸🇰', slovenia: '🇸🇮',\n turkey: '🇹🇷', türkiye: '🇹🇷', albania: '🇦🇱', 'north macedonia': '🇲🇰',\n brazil: '🇧🇷', argentina: '🇦🇷', uruguay: '🇺🇾', colombia: '🇨🇴', chile: '🇨🇱',\n peru: '🇵🇪', ecuador: '🇪🇨', paraguay: '🇵🇾', mexico: '🇲🇽', 'united states': '🇺🇸',\n usa: '🇺🇸', canada: '🇨🇦', jamaica: '🇯🇲',\n nigeria: '🇳🇬', ghana: '🇬🇭', senegal: '🇸🇳', ivorycoast: '🇨🇮', \"cote d'ivoire\": '🇨🇮',\n 'ivory coast': '🇨🇮', cameroon: '🇨🇲', egypt: '🇪🇬', morocco: '🇲🇦', algeria: '🇩🇿',\n tunisia: '🇹🇳', mali: '🇲🇱', 'south africa': '🇿🇦', 'dr congo': '🇨🇩',\n japan: '🇯🇵', 'south korea': '🇰🇷', korea: '🇰🇷', australia: '🇦🇺',\n 'saudi arabia': '🇸🇦', iran: '🇮🇷', 'new zealand': '🇳🇿',\n}\n\nexport function nationalityFlag(nationality: string | null | undefined): string {\n if (!nationality) return '🏳️'\n const key = nationality.trim().toLowerCase()\n return FLAGS[key] ?? nationality.slice(0, 3).toUpperCase()\n}\n","import { useState } from 'react'\n\n// Two-letter initials from a display name: first + last token, or the first two letters\n// of a single-token name. Used as the photo fallback so an avatar circle is never a bare ball.\nexport function initialsOf(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n const first = parts[0]\n if (!first) return '?'\n const last = parts[parts.length - 1]\n if (parts.length === 1 || !last) return first.slice(0, 2).toUpperCase()\n return ((first[0] ?? '') + (last[0] ?? '')).toUpperCase()\n}\n\n// Circular player avatar. Shows the photo when an imagePath is present and loads; otherwise\n// (missing URL or a broken image) falls back to the player's initials on the same circle.\nexport function PlayerAvatar({\n name,\n imagePath,\n className,\n}: {\n name: string\n imagePath?: string\n className: string\n}): JSX.Element {\n const [failed, setFailed] = useState(false)\n const showImage = Boolean(imagePath) && !failed\n\n return (\n <div className={className} aria-hidden=\"true\">\n {showImage ? (\n <img src={imagePath} alt=\"\" loading=\"lazy\" onError={() => setFailed(true)} />\n ) : (\n <span className=\"ss-w-av-initials\">{initialsOf(name)}</span>\n )}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { IconChevronLeft } from './icons'\n\nexport function GameHeader({ title, eyebrow, right, onBack, backLabel }: {\n title: string; eyebrow?: string; right?: ReactNode; onBack?: () => void; backLabel: string\n}): JSX.Element {\n return (\n <div className=\"ss-g-head\">\n {onBack && (\n <button type=\"button\" className=\"ss-g-back\" aria-label={backLabel} onClick={onBack}>\n <IconChevronLeft />\n </button>\n )}\n <div className=\"ss-g-head-text\">\n {eyebrow && <span className=\"ss-g-eyebrow\">{eyebrow}</span>}\n <h2 className=\"ss-g-title\">{title}</h2>\n </div>\n {right && <div className=\"ss-g-head-right\">{right}</div>}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\n\nexport type SegmentState = 'done' | 'current' | 'todo' | 'correct' | 'wrong'\n\nexport function SegmentProgress({ segments, ariaLabel, leftLabel, rightLabel, right }: {\n segments: SegmentState[]; ariaLabel: string; leftLabel?: string; rightLabel?: string; right?: ReactNode\n}): JSX.Element {\n return (\n <div className=\"ss-g-progress\">\n <div className=\"ss-g-progress-main\">\n {(leftLabel || rightLabel) && (\n <div className=\"ss-g-progress-labels\">\n <span>{leftLabel}</span><span className=\"ss-g-progress-rl\">{rightLabel}</span>\n </div>\n )}\n <div className=\"ss-g-segs\" role=\"img\" aria-label={ariaLabel}\n style={{ gridTemplateColumns: `repeat(${segments.length}, minmax(0, 1fr))` }}>\n {segments.map((s, i) => <span key={i} className=\"ss-g-seg\" data-state={s} />)}\n </div>\n </div>\n {right}\n </div>\n )\n}\n","import type { KeyboardEvent, Ref } from 'react'\nimport { IconSearch } from './icons'\n\nexport function SearchField({ id, label, labelHidden = false, placeholder, value, onChange, disabled, inputRef, onKeyDown }: {\n id: string; label: string; labelHidden?: boolean; placeholder: string; value: string\n onChange: (v: string) => void; disabled?: boolean; inputRef?: Ref<HTMLInputElement>\n onKeyDown?: (e: KeyboardEvent<HTMLInputElement>) => void\n}): JSX.Element {\n return (\n <div className=\"ss-g-search\">\n <label htmlFor={id} className={labelHidden ? 'ss-g-sr' : 'ss-g-search-label'}>{label}</label>\n <div className=\"ss-g-search-box\">\n <IconSearch />\n <input id={id} ref={inputRef} type=\"text\" autoComplete=\"off\" placeholder={placeholder} value={value}\n disabled={disabled} onKeyDown={onKeyDown} onChange={e => onChange(e.target.value)} />\n </div>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nexport function FooterBar({ children }: { children: ReactNode }): JSX.Element {\n return <div className=\"ss-g-footer\">{children}</div>\n}\n","export function Silhouette({ size, variant = 'default' }: { size: number; variant?: 'default' | 'selected' | 'mystery' }): JSX.Element {\n return (\n <span className={`ss-g-sil ss-g-sil--${variant}`} style={{ width: size, height: size }} aria-hidden=\"true\">\n <svg width={size * 0.86} height={size * 0.86} viewBox=\"0 0 100 100\">\n <circle cx=\"50\" cy=\"40\" r=\"19\" fill=\"currentColor\" />\n <path d=\"M12 100c0-23 17-38 38-38s38 15 38 38z\" fill=\"currentColor\" />\n </svg>\n {variant === 'mystery' && <span className=\"ss-g-sil-q\">?</span>}\n </span>\n )\n}\n","import type { ButtonHTMLAttributes } from 'react'\n\nexport type GameButtonVariant = 'primary' | 'outline' | 'accent-outline' | 'surface'\n\nexport function GameButton({ variant = 'primary', block = false, className, type = 'button', ...rest }:\n ButtonHTMLAttributes<HTMLButtonElement> & { variant?: GameButtonVariant; block?: boolean }): JSX.Element {\n const cls = `ss-g-btn ss-g-btn--${variant}${block ? ' ss-g-btn--block' : ''}${className ? ` ${className}` : ''}`\n return <button type={type} className={cls} {...rest} />\n}\n","import type { UiConfig } from '../../../config'\nimport { GameButton } from './GameButton'\n\nexport type ResultTone = 'win' | 'lose' | 'neutral'\n\n// Spec §6: every game's solved / lost / already-played state uses this one card.\nexport function ResultCard({ tone, title, score, detail, onBack, ui }: {\n tone: ResultTone; title: string; score?: number; detail?: string; onBack?: () => void; ui: UiConfig\n}): JSX.Element {\n return (\n <div className=\"ss-g-result\" data-tone={tone} role=\"status\">\n <span className=\"ss-g-result-title\">{title}</span>\n {score !== undefined && (\n <span className=\"ss-g-result-score\"><span className=\"ss-g-result-num\">{score}</span>{ui.games.unitPts}</span>\n )}\n {detail && <span className=\"ss-g-result-detail\">{detail}</span>}\n {onBack && <GameButton variant=\"outline\" onClick={onBack}>{ui.games.backToGames}</GameButton>}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\n\nexport interface OptionItem { key: string | number; content: ReactNode }\n\n// Typeahead results. Real <button>s (keyboard reachable) carrying role=option inside a listbox.\nexport function OptionList({ label, options, onPick }: {\n label: string; options: OptionItem[]; onPick: (key: string | number) => void\n}): JSX.Element {\n return (\n <div className=\"ss-g-opts\" role=\"listbox\" aria-label={label}>\n {options.map(o => (\n <button key={o.key} type=\"button\" role=\"option\" aria-selected={false} className=\"ss-g-opt\" onClick={() => onPick(o.key)}>\n {o.content}\n </button>\n ))}\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport type { GameScreenProps, HolConfig, HolClientState } from './types'\nimport { PlayerAvatar } from './PlayerAvatar'\nimport { GameHeader } from './ui/GameHeader'\nimport { StatStack } from './ui/Chip'\nimport { GameButton } from './ui/GameButton'\nimport { FooterBar } from './ui/FooterBar'\nimport { Silhouette } from './ui/Silhouette'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconArrowUp, IconArrowDown, IconCheck, IconClose } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\n\n// Points awarded per correct pick — mirrors HigherOrLowerContentGenerator.PointsPerCorrect.\nconst POINTS_PER_CORRECT = 10\n\nfunction parseClientState(json: string | null | undefined): HolClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as HolClientState\n } catch {\n return null\n }\n}\n\nfunction PlayerCard({ name, imagePath, highlight, children }: {\n name: string; imagePath?: string; highlight?: boolean; children: ReactNode\n}): JSX.Element {\n const { first, last } = splitName(name)\n return (\n <div className={`ss-g-hl-card${highlight ? ' ss-g-hl-card--b' : ''}`}>\n <div className=\"ss-g-hl-photo-wrap\">\n {imagePath\n ? <PlayerAvatar className=\"ss-g-hl-photo\" name={name} imagePath={imagePath} />\n : <Silhouette size={150} />}\n </div>\n <div className=\"ss-g-hl-info\">\n {first && <span className=\"ss-g-hl-first\">{first}</span>}\n <span className=\"ss-g-hl-surname\">{last}</span>\n {children}\n </div>\n </div>\n )\n}\n\nexport function HigherOrLowerGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<HolConfig>): JSX.Element {\n const t = ui.games.higherOrLower\n const clientState = parseClientState(result?.clientStateJson)\n\n const answeredPairs = clientState?.answeredPairs ?? []\n const answeredCount = answeredPairs.length\n const runEndedWrong = answeredPairs.some(p => !p.wasCorrect)\n const allPairsAnswered = config != null && answeredCount >= config.pairs.length\n const isOver = result?.alreadyPlayed === true || runEndedWrong || allPairsAnswered\n\n const currentPair = config && !isOver ? config.pairs[answeredCount] ?? null : null\n\n const correctCount = answeredPairs.filter(p => p.wasCorrect).length\n // A returning fan may come back with no client state: show the stored play score then.\n const score = clientState?.score ?? result?.score ?? 0\n const runLength = clientState?.runLength ?? 0\n\n const lastAnswer = answeredPairs[answeredPairs.length - 1]\n const lastAnswerPair = lastAnswer ? config?.pairs.find(p => p.pairIndex === lastAnswer.pairIndex) : undefined\n\n function handlePick(pick: 'higher' | 'lower') {\n if (!config || isOver || submitting || !currentPair) return\n const prevAnswers = answeredPairs.map(p => ({ pairIndex: p.pairIndex, pick: p.pick }))\n const newAnswers = [...prevAnswers, { pairIndex: currentPair.pairIndex, pick }]\n onSubmit(JSON.stringify({ answers: newAnswers }))\n }\n\n return (\n <div className=\"ss-g-screen ss-g-hl\" data-testid=\"game-screen-higher-or-lower\">\n <GameHeader\n title={gameTitle({ gameId: 'higher-or-lower' })}\n eyebrow={t.eyebrow(POINTS_PER_CORRECT)}\n right={config ? <StatStack value={runLength} label={t.streak} /> : undefined}\n onBack={onBack}\n backLabel={ui.back}\n />\n\n {!config && <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>}\n\n {config && (\n <>\n <div className=\"ss-g-body\">\n <div className=\"ss-g-hl-prompt\" data-testid=\"hol-prompt\">\n <span className=\"ss-g-hl-prompt-q\">{t.whoHadMore}</span>\n <span className=\"ss-g-hl-prompt-stat\">{config.statLabel}</span>\n <span className=\"ss-g-hl-prompt-season\">{t.season(config.seasonLabel)}</span>\n </div>\n\n {currentPair && (\n <div className=\"ss-g-hl-pair\">\n <PlayerCard name={currentPair.playerAName} imagePath={currentPair.playerAImagePath}>\n <span className=\"ss-g-hl-value\">{currentPair.playerAValue}</span>\n <span className=\"ss-g-hl-stat\">{config.statLabel}</span>\n </PlayerCard>\n <span className=\"ss-g-hl-vs\" aria-hidden=\"true\">{t.vs}</span>\n <PlayerCard name={currentPair.playerBName} imagePath={currentPair.playerBImagePath} highlight>\n <div className=\"ss-g-hl-btns\">\n <GameButton variant=\"primary\" disabled={submitting} onClick={() => handlePick('higher')}>\n <IconArrowUp size={16} />{t.higher}\n </GameButton>\n <GameButton variant=\"outline\" disabled={submitting} onClick={() => handlePick('lower')}>\n <IconArrowDown size={16} />{t.lower}\n </GameButton>\n </div>\n </PlayerCard>\n </div>\n )}\n\n {lastAnswer && lastAnswerPair && (\n <p className=\"ss-g-hl-feedback\" data-testid=\"hol-last\" data-correct={lastAnswer.wasCorrect ? 'true' : 'false'}>\n {lastAnswer.wasCorrect ? <IconCheck /> : <IconClose />}\n {t.lastAnswer(splitName(lastAnswerPair.playerBName).last, lastAnswer.playerBValue)}\n </p>\n )}\n\n {isOver && (\n <ResultCard\n tone={runEndedWrong ? 'lose' : allPairsAnswered ? 'win' : 'neutral'}\n title={runEndedWrong ? t.runOver : allPairsAnswered ? t.perfectRun : ui.games.alreadyPlayedTitle}\n score={score}\n detail={clientState ? t.runDetail(correctCount) : undefined}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {!isOver && (\n <FooterBar>\n <div className=\"ss-g-hl-foot\">\n <div className=\"ss-g-hl-dots\" role=\"img\" aria-label={t.answersSoFar(answeredCount, config.pairs.length)}>\n {config.pairs.map((p, i) => {\n const a = answeredPairs[i]\n return <span key={p.pairIndex} className=\"ss-g-hl-dot\" data-state={a ? (a.wasCorrect ? 'correct' : 'wrong') : 'todo'} />\n })}\n </div>\n <span className=\"ss-g-hl-pts\">\n <span data-testid=\"hol-score\">{score}</span> <span className=\"ss-g-hl-pts-unit\">{ui.games.unitPts}</span>\n </span>\n </div>\n </FooterBar>\n )}\n </>\n )}\n </div>\n )\n}\n","import { useState, useId } from 'react'\nimport type { GameScreenProps, CareerPathConfig, CareerPathClientState, CareerPathClubSpell } from './types'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { Silhouette } from './ui/Silhouette'\nimport { CrestShield } from './ui/CrestShield'\nimport { ResultCard } from './ui/ResultCard'\nimport { OptionList } from './ui/OptionList'\nimport { IconLock } from './ui/icons'\nimport { gameTitle } from './ui/gameMeta'\nimport { PlayerAvatar } from './PlayerAvatar'\n\nfunction parseClientState(json: string | null | undefined): CareerPathClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as CareerPathClientState\n } catch {\n return null\n }\n}\n\n// \"2012–2015\", \"2012\" when single-season or open-ended, '' when the generator had no start year.\nexport function spellYears(spell: CareerPathClubSpell): string {\n if (!spell.startYear) return ''\n if (spell.endYear && spell.endYear !== spell.startYear) return `${spell.startYear}–${spell.endYear}`\n return String(spell.startYear)\n}\n\nexport function CareerPathGame({\n config,\n result,\n submitting,\n onSubmit,\n onBack,\n ui,\n}: GameScreenProps<CareerPathConfig>): JSX.Element {\n const s = ui.games.careerPath\n const title = gameTitle({ gameId: 'career-path' })\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyGuessedIds = new Set<number>(clientState?.guessResults.map(g => g.playerId) ?? [])\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.solved === true ||\n clientState?.failed === true\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-career-path\">\n <GameHeader title={title} eyebrow={s.eyebrow} onBack={onBack} backLabel={ui.back} />\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const visiblePath = clientState?.visiblePath ?? config.initialPath\n const totalClubs = clientState?.totalClubs ?? config.totalClubs\n const hidden = isOver ? 0 : Math.max(0, totalClubs - visiblePath.length)\n\n const filtered = !isOver\n ? config.typeaheadPool.filter(\n p => !alreadyGuessedIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handleSelect(playerId: number): void {\n if (!config || isOver || submitting) return\n const prevGuesses = clientState?.guessResults.map(g => g.playerId) ?? []\n const newGuesses = [...prevGuesses, playerId]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n const right = !isOver && clientState\n ? (\n <span data-testid=\"cp-guess-chip\">\n <Chip variant=\"neutral\">\n {ui.games.guess} <span className=\"ss-g-num\">{clientState.guessesUsed + 1}</span> / {clientState.guessesUsed + clientState.guessesRemaining}\n </Chip>\n </span>\n )\n : undefined\n\n const outcome = clientState?.solved ? s.solved : clientState?.failed ? s.failed : ui.games.done\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-career-path\">\n <GameHeader title={title} eyebrow={s.eyebrow} right={right} onBack={onBack} backLabel={ui.back} />\n\n <div className=\"ss-g-body\">\n <div className=\"ss-g-cp-card\">\n <Silhouette size={64} variant={isOver ? 'default' : 'mystery'} />\n <div className=\"ss-g-cp-card-text\">\n <span className=\"ss-g-cp-card-title\">\n {isOver && clientState?.revealedPlayerName ? clientState.revealedPlayerName : s.mysteryPlayer}\n </span>\n {clientState?.hintLine ? (\n <span className=\"ss-g-cp-hint\">{clientState.hintLine}</span>\n ) : !isOver ? (\n <span className=\"ss-g-cp-locks\">\n <Chip variant=\"lock\" icon={<IconLock size={11} />}>{s.lockPosition}</Chip>\n <Chip variant=\"lock\" icon={<IconLock size={11} />}>{s.lockNationality}</Chip>\n </span>\n ) : null}\n </div>\n </div>\n\n <ol className=\"ss-g-cp-line\">\n {visiblePath.map((spell, i) => {\n const years = i === 0 ? s.firstClub : spellYears(spell)\n return (\n <li key={`${spell.clubName}-${i}`} className=\"ss-g-cp-step\">\n <span className=\"ss-g-cp-rail\">\n <span className=\"ss-g-cp-tile\"><CrestShield src={spell.crestUrl} name={spell.clubName} size={30} /></span>\n <span className=\"ss-g-cp-conn\" aria-hidden=\"true\" />\n </span>\n <span className=\"ss-g-cp-step-text\">\n <span className=\"ss-g-cp-club\">{spell.clubName}</span>\n <span className=\"ss-g-cp-sub\">\n <span className=\"ss-g-cp-years\">{years}</span>\n {spell.isLoan && (\n <>\n {years ? ' · ' : ''}\n <span className=\"ss-g-cp-loan\">{s.loan}</span>\n </>\n )}\n </span>\n </span>\n </li>\n )\n })}\n {hidden > 0 && (\n <li className=\"ss-g-cp-step ss-g-cp-step--hidden\">\n <span className=\"ss-g-cp-rail\">\n <span className=\"ss-g-cp-tile ss-g-cp-tile--locked\"><IconLock size={18} /></span>\n {hidden > 1 && <span className=\"ss-g-cp-conn ss-g-cp-conn--faint\" aria-hidden=\"true\" />}\n </span>\n <span className=\"ss-g-cp-step-text\"><span className=\"ss-g-cp-sub\">{s.nextClubHidden}</span></span>\n </li>\n )}\n {hidden > 1 && (\n <li className=\"ss-g-cp-step ss-g-cp-step--more\">\n <span className=\"ss-g-cp-rail\">\n <span className=\"ss-g-cp-tile ss-g-cp-tile--faint\"><IconLock size={18} /></span>\n </span>\n <span className=\"ss-g-cp-step-text\"><span className=\"ss-g-cp-sub\">{s.moreClubs(hidden - 1)}</span></span>\n </li>\n )}\n </ol>\n\n {isOver && (\n <ResultCard\n tone={clientState?.solved ? 'win' : clientState?.failed ? 'lose' : 'neutral'}\n title={outcome}\n score={result?.score}\n detail={clientState ? s.guessesLine(clientState.guessesUsed) : undefined}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {!isOver && (\n <FooterBar>\n {query.length > 0 && filtered.length > 0 && (\n <OptionList\n label={s.searchLabel}\n options={filtered.map(p => ({\n key: p.id,\n content: <><PlayerAvatar className=\"ss-g-opt-av\" name={p.name} /><span>{p.name}</span></>,\n }))}\n onPick={k => handleSelect(Number(k))}\n />\n )}\n <SearchField\n id={inputId}\n label={s.searchLabel}\n placeholder={s.searchPlaceholder}\n value={query}\n onChange={setQuery}\n disabled={submitting}\n />\n </FooterBar>\n )}\n </div>\n )\n}\n","import { useState } from 'react'\n\nexport function CrestShield({ src, name, size = 28 }: { src?: string | null; name: string; size?: number }): JSX.Element {\n const [failed, setFailed] = useState(false)\n if (src && !failed) {\n return <img className=\"ss-g-crest\" src={src} alt={name} width={size} height={size} loading=\"lazy\" onError={() => setFailed(true)} />\n }\n return (\n <svg className=\"ss-g-crest ss-g-crest--ph\" width={size} height={size * 32 / 28} viewBox=\"0 0 28 32\" role=\"img\" aria-label={name}>\n <path d=\"M2 3h24v12c0 9-6 14-12 17C8 29 2 24 2 15z\" fill=\"currentColor\" />\n </svg>\n )\n}\n","import React, { useEffect, useId, useRef, useState } from 'react'\nimport type { GameScreenProps, BeatTheGridConfig, BtgClientState, BtgCellResult } from './types'\nimport type { UiConfig } from '../../config'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { SegmentProgress } from './ui/SegmentProgress'\nimport type { SegmentState } from './ui/SegmentProgress'\nimport { SearchField } from './ui/SearchField'\nimport { Silhouette } from './ui/Silhouette'\nimport { ResultCard } from './ui/ResultCard'\nimport { OptionList } from './ui/OptionList'\nimport {\n IconCalendar, IconBall, IconBoot, IconGloves, IconShield, IconFlag, IconCheck, IconClose, IconPlus,\n} from './ui/icons'\nimport { gameTitle } from './ui/gameMeta'\nimport { PlayerAvatar } from './PlayerAvatar'\n\nexport interface PlayerEntry {\n id: number\n name: string\n}\n\n// playerPool comes from config.playerPool, threaded through by GameScreenHost.\nexport interface BeatTheGridGameProps extends GameScreenProps<BeatTheGridConfig> {\n playerPool: PlayerEntry[]\n}\n\ninterface ActiveCell {\n row: number\n col: number\n}\n\nexport type CriterionIconKind = 'calendar' | 'ball' | 'boot' | 'gloves' | 'shield' | 'flag'\n\n// Header icon from the column label text. Only the label reaches the client (no criterion type),\n// so this is a display heuristic; unknown labels (nationality groups) get the flag.\nexport function criterionIconKind(label: string): CriterionIconKind {\n const l = label.toLowerCase()\n if (l.includes('app')) return 'calendar'\n if (l.includes('goal')) return 'ball'\n if (l.includes('assist')) return 'boot'\n if (l.includes('clean')) return 'gloves'\n if (l.includes('tackle')) return 'shield'\n return 'flag'\n}\n\nexport function rowAbbrev(label: string, map: Record<string, string>): string {\n return map[label] ?? label\n}\n\nfunction CriterionIcon({ kind }: { kind: CriterionIconKind }): JSX.Element {\n switch (kind) {\n case 'calendar': return <IconCalendar />\n case 'ball': return <IconBall />\n case 'boot': return <IconBoot />\n case 'gloves': return <IconGloves />\n case 'shield': return <IconShield />\n default: return <IconFlag />\n }\n}\n\nfunction parseClientState(json: string | null | undefined): BtgClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as BtgClientState\n } catch {\n return null\n }\n}\n\nfunction findCellResult(cells: BtgCellResult[], row: number, col: number): BtgCellResult | undefined {\n return cells.find(c => c.row === row && c.col === col)\n}\n\n// Compact initials for a placed player, e.g. \"Andrew Robertson\" → \"A. Robertson\".\n// Falls back to an empty string when the name is unknown.\nfunction shortName(name: string | undefined): string {\n if (!name) return ''\n const parts = name.trim().split(/\\s+/).filter(Boolean)\n if (parts.length === 0) return ''\n const first = parts[0]!\n if (parts.length === 1) return first\n const last = parts[parts.length - 1]!\n return `${first.charAt(0)}. ${last}`\n}\n\nfunction SearchSheet({\n row,\n col,\n rowLabel,\n colLabel,\n playerPool,\n alreadyFilledIds,\n onPick,\n onDismiss,\n ui,\n}: {\n row: number\n col: number\n rowLabel: string\n colLabel: string\n playerPool: PlayerEntry[]\n alreadyFilledIds: Set<number>\n onPick: (row: number, col: number, playerId: number) => void\n onDismiss: () => void\n ui: UiConfig\n}): JSX.Element {\n const s = ui.games.beatTheGrid\n const [query, setQuery] = useState('')\n const inputId = useId()\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => { inputRef.current?.focus() }, [row, col])\n\n const filtered = playerPool.filter(\n p => !alreadyFilledIds.has(p.id) && p.name.toLowerCase().includes(query.toLowerCase()),\n )\n\n return (\n <div className=\"ss-g-btg-sheet\" data-testid=\"btg-search-sheet\">\n <div className=\"ss-g-btg-sheet-hdr\">\n <Chip variant=\"neutral\">{rowLabel}</Chip>\n <span className=\"ss-g-btg-sheet-x\" aria-hidden=\"true\"><IconClose size={12} /></span>\n <Chip variant=\"accent\">{colLabel}</Chip>\n <button\n type=\"button\"\n className=\"ss-g-btg-sheet-close\"\n data-testid=\"btg-sheet-dismiss\"\n aria-label={s.closeSearch}\n onClick={onDismiss}\n >\n <IconClose />\n </button>\n </div>\n {playerPool.length === 0 ? (\n <div className=\"ss-g-btg-sheet-empty\">{s.emptyPool}</div>\n ) : (\n <>\n <SearchField\n id={inputId}\n label={s.searchLabel(rowLabel, colLabel)}\n labelHidden\n placeholder={s.searchPlaceholder}\n value={query}\n onChange={setQuery}\n inputRef={inputRef}\n />\n {query.length > 0 && filtered.length > 0 && (\n <OptionList\n label={s.searchLabel(rowLabel, colLabel)}\n options={filtered.map(p => ({\n key: p.id,\n content: (\n <>\n <PlayerAvatar name={p.name} className=\"ss-g-opt-av\" />\n <span className=\"ss-g-btg-result-name\">{p.name}</span>\n <span className=\"ss-g-btg-result-plus\" aria-hidden=\"true\"><IconPlus size={18} /></span>\n </>\n ),\n }))}\n onPick={k => onPick(row, col, Number(k))}\n />\n )}\n </>\n )}\n </div>\n )\n}\n\nexport function BeatTheGridGame({\n config,\n result,\n submitting,\n onSubmit,\n onBack,\n ui,\n playerPool,\n}: BeatTheGridGameProps): JSX.Element {\n const s = ui.games.beatTheGrid\n const title = gameTitle({ gameId: 'beat-the-grid' })\n const [activeCell, setActiveCell] = useState<ActiveCell | null>(null)\n\n const clientState = parseClientState(result?.clientStateJson)\n const filledCells = clientState?.cells ?? []\n\n const isLocked =\n result?.alreadyPlayed === true ||\n clientState?.isComplete === true\n\n const alreadyFilledIds = new Set<number>(filledCells.map(c => c.playerId))\n\n function handleCellClick(row: number, col: number): void {\n if (isLocked || submitting) return\n const alreadyFilled = findCellResult(filledCells, row, col)\n if (alreadyFilled) return\n setActiveCell({ row, col })\n }\n\n function handlePick(row: number, col: number, playerId: number): void {\n setActiveCell(null)\n const prevCells = filledCells.map(c => ({ row: c.row, col: c.col, playerId: c.playerId }))\n const newCells = [...prevCells, { row, col, playerId }]\n onSubmit(JSON.stringify({ cells: newCells }))\n }\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-beat-the-grid\">\n <GameHeader title={title} eyebrow={s.eyebrow} onBack={onBack} backLabel={ui.back} />\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const rows = config.rows\n const cols = config.cols\n const total = rows.length * cols.length\n const correctCount = filledCells.filter(c => c.isCorrect).length\n const wrongCount = filledCells.length - correctCount\n const segments: SegmentState[] = Array.from({ length: total }, (_, i) =>\n i < correctCount ? 'correct' : i < correctCount + wrongCount ? 'wrong' : 'todo',\n )\n // A returning fan may come back with no client state: show the stored play score then.\n const totalScore = clientState?.totalScore ?? result?.score ?? 0\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-beat-the-grid\">\n <GameHeader title={title} eyebrow={s.eyebrow} onBack={onBack} backLabel={ui.back} />\n <SegmentProgress\n segments={segments}\n ariaLabel={s.progressAria(filledCells.length, total)}\n leftLabel={s.filled(filledCells.length, total)}\n rightLabel={s.toGo(Math.max(0, total - filledCells.length))}\n right={<Chip variant=\"accent\">{`${totalScore} ${ui.games.unitPts}`}</Chip>}\n />\n\n <div className=\"ss-g-body\">\n <div\n className=\"ss-g-btg-grid\"\n style={{ gridTemplateColumns: `64px repeat(${cols.length}, minmax(0, 1fr))` } as React.CSSProperties}\n role=\"grid\"\n >\n <div className=\"ss-g-btg-corner\" />\n {cols.map(col => (\n <div key={col} className=\"ss-g-btg-colhdr\">\n <CriterionIcon kind={criterionIconKind(col)} />\n <span>{col}</span>\n </div>\n ))}\n {rows.map((rowLabel, rowIdx) => {\n const abbr = rowAbbrev(rowLabel, s.rowAbbrev)\n return (\n <React.Fragment key={rowIdx}>\n <div className=\"ss-g-btg-rowhdr\">\n {abbr === rowLabel ? (\n <span>{rowLabel}</span>\n ) : (\n <>\n <span aria-hidden=\"true\">{abbr}</span>\n <span className=\"ss-g-sr\">{rowLabel}</span>\n </>\n )}\n </div>\n {cols.map((colLabel, colIdx) => {\n const filled = findCellResult(filledCells, rowIdx, colIdx)\n const isActive = activeCell?.row === rowIdx && activeCell?.col === colIdx\n const state = filled ? (filled.isCorrect ? 'correct' : 'wrong') : isActive ? 'active' : 'empty'\n return (\n <button\n key={`cell-${rowIdx}-${colIdx}`}\n type=\"button\"\n data-testid={`btg-cell-${rowIdx}-${colIdx}`}\n data-state={state}\n aria-label={\n filled\n ? s.cellFilled(rowLabel, colLabel, playerPool.find(p => p.id === filled.playerId)?.name ?? '', filled.isCorrect ? s.correct : s.wrong)\n : s.pickCell(rowLabel, colLabel)\n }\n aria-pressed={isActive}\n className=\"ss-g-btg-cell\"\n disabled={isLocked || submitting}\n onClick={() => handleCellClick(rowIdx, colIdx)}\n >\n {filled ? (\n <>\n <span\n className={`ss-g-btg-badge ss-g-btg-badge--${filled.isCorrect ? 'correct' : 'wrong'}`}\n role=\"img\"\n aria-label={filled.isCorrect ? s.correct : s.wrong}\n >\n {filled.isCorrect ? <IconCheck size={11} /> : <IconClose size={11} />}\n </span>\n <span className=\"ss-g-btg-rarity\">{filled.rarityScore}</span>\n <Silhouette size={40} />\n <span className=\"ss-g-btg-name\">\n {shortName(playerPool.find(p => p.id === filled.playerId)?.name)}\n </span>\n </>\n ) : (\n <span className=\"ss-g-btg-plus\" aria-hidden=\"true\"><IconPlus size={22} /></span>\n )}\n </button>\n )\n })}\n </React.Fragment>\n )\n })}\n </div>\n\n {isLocked && (\n <ResultCard\n tone=\"neutral\"\n title={s.complete}\n score={totalScore}\n detail={s.summary(correctCount, filledCells.length)}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {activeCell !== null && (\n <div className=\"ss-g-btg-pin\">\n <SearchSheet\n key={`${activeCell.row}-${activeCell.col}`}\n row={activeCell.row}\n col={activeCell.col}\n rowLabel={rows[activeCell.row] ?? ''}\n colLabel={cols[activeCell.col] ?? ''}\n playerPool={playerPool}\n alreadyFilledIds={alreadyFilledIds}\n onPick={handlePick}\n onDismiss={() => setActiveCell(null)}\n ui={ui}\n />\n </div>\n )}\n </div>\n )\n}\n","import { useState, useId } from 'react'\nimport type { GameScreenProps, GuessTheXiConfig, XiClientState } from './types'\nimport { nationalityFlag } from './nationFlags'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { CrestShield } from './ui/CrestShield'\nimport { PitchSvg } from './ui/PitchSvg'\nimport { ResultCard } from './ui/ResultCard'\nimport { OptionList } from './ui/OptionList'\nimport { gameTitle, splitName } from './ui/gameMeta'\nimport { toRows, formationLabel, positionsBySlot } from './ui/formations'\n\n// Total guesses allowed per day. Kept in sync with GuessTheXiScorer.MaxGuesses on the backend.\nconst MAX_GUESSES = 3\n\nfunction parseClientState(json: string | null | undefined): XiClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as XiClientState\n } catch {\n return null\n }\n}\n\nexport function GuessTheXiGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<GuessTheXiConfig>): JSX.Element {\n const t = ui.games.guessTheXi\n const [query, setQuery] = useState('')\n const inputId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n\n const isOver =\n result?.alreadyPlayed === true ||\n clientState?.status === 'solved' ||\n clientState?.status === 'failed'\n const solved = clientState?.status === 'solved'\n const failed = clientState?.status === 'failed'\n\n const guessedTeamIds = new Set<number>(clientState?.guessHistory.map(g => g.teamId) ?? [])\n const rows = config ? toRows(config.positions) : []\n // Only name the shape when the data is a real formation; a neutral fallback grid has no shape.\n const formation = config?.hasRealFormation ? formationLabel(rows) : ''\n // Position label under every node (GK/CB/CM/ST…), derived from the formation coordinates only.\n const posBySlot = config?.hasRealFormation ? positionsBySlot(formation, rows) : new Map<string, string>()\n\n // A wrong guess can earn a player-name reveal; pin each to its slot so the surname replaces that\n // node's position tag. Position-type reveals are redundant now that every position is shown.\n const nameBySlot = new Map<string, string>()\n ;(clientState?.earnedReveals ?? []).forEach(r => { if (r.slot && r.type !== 'position') nameBySlot.set(r.slot, r.value) })\n\n const filtered =\n config && !isOver\n ? config.teamPool.filter(\n tm => !guessedTeamIds.has(tm.teamId) && tm.teamName.toLowerCase().includes(query.toLowerCase()),\n )\n : []\n\n function handlePick(teamId: number): void {\n if (!config || isOver || submitting) return\n const prevGuesses = clientState?.guessHistory.map(g => ({ teamId: g.teamId })) ?? []\n const newGuesses = [...prevGuesses, { teamId }]\n setQuery('')\n onSubmit(JSON.stringify({ guesses: newGuesses }))\n }\n\n const wrongGuesses = (clientState?.guessHistory ?? []).filter(g => !g.wasCorrect)\n const guessesLeft = Math.max(0, MAX_GUESSES - (clientState?.guessesUsed ?? 0))\n const teamName = (id: number): string => config?.teamPool.find(tm => tm.teamId === id)?.teamName ?? `#${id}`\n\n return (\n <div className=\"ss-g-screen ss-g-gxi\" data-testid=\"game-screen-guess-the-xi\">\n <GameHeader\n title={gameTitle({ gameId: 'guess-the-xi' })}\n eyebrow={config?.poolLabel}\n right={formation ? <Chip variant=\"accent\">{formation}</Chip> : undefined}\n onBack={onBack}\n backLabel={ui.back}\n />\n\n {!config && <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>}\n\n {config && (\n <>\n <div className=\"ss-g-body\">\n {rows.length > 0 && (\n <div className=\"ss-g-gxi-pitch\" role=\"group\" aria-label={t.pitchLabel}>\n <PitchSvg variant=\"full\" />\n <div className=\"ss-g-gxi-rows\">\n {rows.map((row, r) => (\n <div key={r} className=\"ss-g-gxi-row\">\n {row.map((pos, c) => {\n const posLabel = pos.slot ? posBySlot.get(pos.slot) ?? '' : ''\n const name = pos.slot ? nameBySlot.get(pos.slot) : undefined\n return (\n <div key={`${pos.slot}-${c}`} className=\"ss-g-gxi-node\" data-revealed={name ? 'true' : undefined}>\n <span\n className=\"ss-g-gxi-disc\"\n role=\"img\"\n title={pos.nationality}\n aria-label={`${posLabel ? posLabel + ' — ' : ''}${pos.nationality}${name ? ' — ' + name : ''}`}\n >\n {nationalityFlag(pos.nationality)}\n </span>\n {name\n ? <span className=\"ss-g-gxi-pos ss-g-gxi-pos--name\">{splitName(name).last}</span>\n : posLabel && <span className=\"ss-g-gxi-pos\">{posLabel}</span>}\n </div>\n )\n })}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {!isOver && wrongGuesses.length > 0 && (\n <div className=\"ss-g-gxi-wrong\">\n <span className=\"ss-g-gxi-wrong-l\">{t.notThem}</span>\n {wrongGuesses.map(g => (\n <span key={g.teamId} className=\"ss-g-gxi-wrong-chip\">\n <CrestShield name={teamName(g.teamId)} size={18} />\n <s>{teamName(g.teamId)}</s>\n </span>\n ))}\n </div>\n )}\n\n {isOver && (\n <ResultCard\n tone={solved ? 'win' : failed ? 'lose' : 'neutral'}\n title={solved ? t.solved : failed ? t.failed : ui.games.alreadyPlayedTitle}\n score={clientState?.score ?? result?.score ?? 0}\n detail={clientState ? t.detail(clientState.guessesUsed) : undefined}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {!isOver && (\n <FooterBar>\n {query.length > 0 && filtered.length > 0 && (\n <OptionList\n label={t.optionsLabel}\n options={filtered.map(tm => ({\n key: tm.teamId,\n content: <><CrestShield name={tm.teamName} size={28} /><span>{tm.teamName}</span></>,\n }))}\n onPick={k => handlePick(Number(k))}\n />\n )}\n <SearchField id={inputId} label={t.whichClub(guessesLeft)} placeholder={t.searchPlaceholder}\n value={query} onChange={setQuery} disabled={submitting} />\n </FooterBar>\n )}\n </>\n )}\n </div>\n )\n}\n","export function PitchSvg({ variant }: { variant: 'full' | 'half' }): JSX.Element {\n return (\n <svg className=\"ss-g-pitch-svg\" viewBox={variant === 'full' ? '0 0 100 150' : '0 0 100 100'} preserveAspectRatio=\"none\" aria-hidden=\"true\">\n <rect x=\"4\" y=\"4\" width=\"92\" height={variant === 'full' ? 142 : 92} fill=\"none\" />\n {variant === 'full' ? (\n <>\n <line x1=\"4\" y1=\"75\" x2=\"96\" y2=\"75\" /><circle cx=\"50\" cy=\"75\" r=\"12\" fill=\"none\" />\n <rect x=\"26\" y=\"4\" width=\"48\" height=\"20\" fill=\"none\" /><rect x=\"26\" y=\"126\" width=\"48\" height=\"20\" fill=\"none\" />\n </>\n ) : (\n <>\n <path d=\"M38 4a12 12 0 0 0 24 0\" fill=\"none\" />\n <rect x=\"26\" y=\"76\" width=\"48\" height=\"20\" fill=\"none\" />\n </>\n )}\n </svg>\n )\n}\n","import type { XiSlotEntry } from '../types'\n\n/**\n * Groups the flat position list into formation rows keyed by the \"row:col\" slot's row part, then\n * orders the rows so the GOALKEEPER LINE (row 1) sits at the BOTTOM — the football convention: a\n * team defends the bottom goal and attacks upward (GK → defence → midfield → attack).\n */\nexport function toRows(positions: XiSlotEntry[]): XiSlotEntry[][] {\n const byRow = new Map<number, XiSlotEntry[]>()\n positions.forEach((p, i) => {\n const rowKey = Number(p.slot?.split(':')[0]) || i + 1\n const bucket = byRow.get(rowKey) ?? []\n bucket.push(p)\n byRow.set(rowKey, bucket)\n })\n // Descending: highest row number (forwards) at the top, row 1 (GK) at the bottom.\n return [...byRow.keys()].sort((a, b) => b - a).map(k => byRow.get(k)!)\n}\n\n// Football formation notation from the grouped rows — the outfield lines from defence to attack,\n// goalkeeper excluded (e.g. GK/4/2/3/1 → \"4-2-3-1\"). `rows` arrive attack-first (descending), so\n// read them bottom-up and drop the goalkeeper line.\nexport function formationLabel(rowsAttackFirst: XiSlotEntry[][]): string {\n if (rowsAttackFirst.length < 2) return ''\n const gkFirst = [...rowsAttackFirst].reverse()\n return gkFirst.slice(1).map(r => r.length).join('-')\n}\n\n// Canonical position labels per formation, goalkeeper first then each outfield line, left→right.\n// Lets us print a real position (GK, RB, CDM, ST…) under every node so the fan can read the shape\n// and see at a glance which end is the goalkeeper — without the config having to carry positions.\nexport const FORMATION_POSITIONS: Record<string, string[][]> = {\n '4-4-2': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'RM'], ['ST', 'ST']],\n '4-3-3': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CM', 'CM', 'CM'], ['LW', 'ST', 'RW']],\n '4-2-3-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM', 'CDM'], ['LW', 'CAM', 'RW'], ['ST']],\n '4-1-4-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM'], ['LM', 'CM', 'CM', 'RM'], ['ST']],\n '4-5-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'CM', 'RM'], ['ST']],\n '4-4-1-1': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['LM', 'CM', 'CM', 'RM'], ['CAM'], ['ST']],\n '4-1-2-1-2': [['GK'], ['LB', 'CB', 'CB', 'RB'], ['CDM'], ['LM', 'RM'], ['CAM'], ['ST', 'ST']],\n '3-5-2': [['GK'], ['CB', 'CB', 'CB'], ['LWB', 'CM', 'CM', 'CM', 'RWB'], ['ST', 'ST']],\n '3-4-3': [['GK'], ['CB', 'CB', 'CB'], ['LM', 'CM', 'CM', 'RM'], ['LW', 'ST', 'RW']],\n '5-3-2': [['GK'], ['LWB', 'CB', 'CB', 'CB', 'RWB'], ['CM', 'CM', 'CM'], ['ST', 'ST']],\n '5-4-1': [['GK'], ['LWB', 'CB', 'CB', 'CB', 'RWB'], ['LM', 'CM', 'CM', 'RM'], ['ST']],\n}\n\n// Line-level fallback when the exact formation is not in the table above: the goalkeeper line, the\n// forward line, then defence/midfield by depth. Always correct at the line grain even when the\n// specific role is not — enough to read the shape and spot the keeper.\nexport function lineFallback(lineIdx: number, totalLines: number): string {\n if (lineIdx === 0) return 'GK'\n if (lineIdx === totalLines - 1) return 'FWD'\n if (lineIdx === 1) return 'DEF'\n return 'MID'\n}\n\n// Map each slot (\"row:col\") to a position label, reading the rows goalkeeper-first.\nexport function positionsBySlot(formation: string, rowsAttackFirst: XiSlotEntry[][]): Map<string, string> {\n const gkFirst = [...rowsAttackFirst].reverse()\n const template = FORMATION_POSITIONS[formation]\n const map = new Map<string, string>()\n gkFirst.forEach((line, li) => {\n line.forEach((entry, ci) => {\n if (!entry.slot) return\n const label = template?.[li]?.[ci] ?? lineFallback(li, gkFirst.length)\n map.set(entry.slot, label)\n })\n })\n return map\n}\n","import { useState } from 'react'\nimport type { GameScreenProps, DailyQuizConfig, DailyQuizClientState, DailyQuizResult } from './types'\nimport { GameHeader } from './ui/GameHeader'\nimport { SegmentProgress } from './ui/SegmentProgress'\nimport type { SegmentState } from './ui/SegmentProgress'\nimport { GameButton } from './ui/GameButton'\nimport { FooterBar } from './ui/FooterBar'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconCheck } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\n\nfunction parseClientState(json: string | null | undefined): DailyQuizClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as DailyQuizClientState\n } catch {\n return null\n }\n}\n\nfunction findResult(results: DailyQuizResult[], index: number): DailyQuizResult | undefined {\n return results.find(r => r.index === index)\n}\n\nconst TRAILING_PAREN = /\\s*\\(([^)]*)\\)$/\nconst NAME_TOKEN = /^[\\p{L}\\p{M}.'’-]+$/u\n\nfunction OptionName({ text }: { text: string }): JSX.Element {\n const match = TRAILING_PAREN.exec(text)\n const base = match ? text.slice(0, match.index).trim() : text.trim()\n const suffix = match?.[1]?.trim() ?? ''\n const tokens = base.split(/\\s+/).filter(Boolean)\n const isPlainName = tokens.length >= 1 && tokens.length <= 4 && tokens.every(t => NAME_TOKEN.test(t))\n if (!isPlainName || base === '') {\n return (\n <span className=\"ss-g-dq-opt-name\">\n <span className=\"ss-g-dq-opt-full\">{text}</span>\n </span>\n )\n }\n const { first, last } = splitName(base)\n return (\n <span className=\"ss-g-dq-opt-name\">\n {first && <span className=\"ss-g-dq-opt-first\">{first}</span>}\n <span className=\"ss-g-dq-opt-last\">{last}</span>\n {suffix && <span className=\"ss-g-dq-opt-suffix\">{suffix}</span>}\n </span>\n )\n}\n\nexport function DailyQuizGame({\n config,\n result,\n submitting,\n onSubmit,\n onBack,\n ui,\n}: GameScreenProps<DailyQuizConfig>): JSX.Element {\n const s = ui.games.dailyQuiz\n const title = gameTitle({ gameId: 'daily-quiz' })\n // Local selection state: map from question index → selected option index\n const [selections, setSelections] = useState<Map<number, number>>(new Map())\n const [page, setPage] = useState(0)\n\n const clientState = parseClientState(result?.clientStateJson)\n const results = clientState?.results ?? []\n const isRevealed = results.length > 0 || result?.alreadyPlayed === true\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-daily-quiz\">\n <GameHeader title={title} onBack={onBack} backLabel={ui.back} />\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const questions = config.questions\n const total = questions.length\n const current = questions[Math.min(page, total - 1)]\n const isLast = page >= total - 1\n const currentAnswered = current !== undefined && selections.has(current.index)\n const allAnswered = selections.size === total\n\n function handleSelect(questionIndex: number, optionIndex: number): void {\n if (isRevealed || submitting) return\n setSelections(prev => new Map(prev).set(questionIndex, optionIndex))\n }\n\n function goNext(): void {\n if (!currentAnswered || isLast) return\n setPage(p => p + 1)\n }\n\n function goPrev(): void {\n setPage(p => Math.max(0, p - 1))\n }\n\n function handleSubmit(): void {\n if (!config || !allAnswered || isRevealed || submitting) return\n const answers = config.questions.map(q => ({\n index: q.index,\n selectedOptionIndex: selections.get(q.index) ?? 0,\n }))\n onSubmit(JSON.stringify({ answers }))\n }\n\n if (isRevealed) {\n const segments: SegmentState[] = questions.map(q => {\n const r = findResult(results, q.index)\n if (!r) return 'done'\n return r.isCorrect ? 'correct' : 'wrong'\n })\n const correctCount = results.filter(r => r.isCorrect).length\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-daily-quiz\">\n <GameHeader title={title} eyebrow={s.results} onBack={onBack} backLabel={ui.back} />\n <SegmentProgress segments={segments} ariaLabel={s.results} />\n <div className=\"ss-g-body\">\n <ResultCard\n tone=\"neutral\"\n title={results.length > 0 ? s.correctOf(correctCount, total) : ui.games.alreadyPlayedTitle}\n score={result?.score}\n onBack={onBack}\n ui={ui}\n />\n {questions.map(q => {\n const r = findResult(results, q.index)\n const picked = selections.get(q.index)\n return (\n <div key={q.index} className=\"ss-g-dq-rq\">\n <div className=\"ss-g-dq-rq-stem\">{q.stem}</div>\n {r && (\n <div className=\"ss-g-dq-rq-opts\">\n {q.options.map((opt, optIdx) => {\n let cls = 'ss-g-dq-rq-opt'\n if (optIdx === r.correctOptionIndex) cls += ' ss-g-dq-rq-opt--correct'\n else if (optIdx === picked && !r.isCorrect) cls += ' ss-g-dq-rq-opt--wrong'\n return <span key={optIdx} className={cls}>{opt}</span>\n })}\n </div>\n )}\n {r?.revealText && <div className=\"ss-g-dq-why\">{r.revealText}</div>}\n </div>\n )\n })}\n </div>\n </div>\n )\n }\n\n const segments: SegmentState[] = questions.map((_, i) => (i < page ? 'done' : i === page ? 'current' : 'todo'))\n const selectedIdx = current ? selections.get(current.index) : undefined\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-daily-quiz\">\n <GameHeader title={title} eyebrow={s.questionOf(page + 1, total)} onBack={onBack} backLabel={ui.back} />\n <SegmentProgress segments={segments} ariaLabel={s.progressAria(page + 1, total)} />\n <div className=\"ss-g-body\">\n {current && (\n <>\n <h3 className=\"ss-g-dq-stem\">{current.stem}</h3>\n <div className=\"ss-g-dq-opts\">\n {current.options.map((opt, optIdx) => {\n const selected = optIdx === selectedIdx\n return (\n <button\n key={optIdx}\n type=\"button\"\n className=\"ss-g-dq-opt\"\n aria-pressed={selected}\n disabled={submitting}\n onClick={() => handleSelect(current.index, optIdx)}\n >\n <span className=\"ss-g-dq-badge\" aria-hidden=\"true\">\n {selected ? <IconCheck /> : String.fromCharCode(65 + optIdx)}\n </span>\n <OptionName text={opt} />\n </button>\n )\n })}\n </div>\n </>\n )}\n </div>\n <FooterBar>\n <div className=\"ss-g-dq-nav\">\n {page > 0 && (\n <GameButton variant=\"outline\" onClick={goPrev} disabled={submitting}>{s.previous}</GameButton>\n )}\n {isLast ? (\n <GameButton variant=\"primary\" block onClick={handleSubmit} disabled={!currentAnswered || !allAnswered || submitting}>\n {submitting ? s.submitting : s.submit}\n </GameButton>\n ) : (\n <GameButton variant=\"primary\" block onClick={goNext} disabled={!currentAnswered || submitting}>\n {s.next}\n </GameButton>\n )}\n </div>\n </FooterBar>\n </div>\n )\n}\n","import { useId, useState } from 'react'\nimport type {\n GameScreenProps,\n MatchdayPredictorConfig,\n MatchdayPredictorClientState,\n MatchdayPredictorTeam,\n} from './types'\nimport type { GamesStrings } from '../../i18n'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { GameButton } from './ui/GameButton'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { Silhouette } from './ui/Silhouette'\nimport { CrestShield } from './ui/CrestShield'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconCheck, IconClose, IconLock, IconPlus } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\n\n// Above this many scorers the card grid gets a search filter (spec §5.7).\nconst SCORER_SEARCH_THRESHOLD = 9\n\ntype Side = 'home' | 'away'\ntype PredictorStrings = GamesStrings['predictor']\n\nfunction parseClientState(json: string | null | undefined): MatchdayPredictorClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as MatchdayPredictorClientState\n } catch {\n return null\n }\n}\n\nfunction isLocked(kickoffUtc: string): boolean {\n try {\n return new Date(kickoffUtc).getTime() <= Date.now()\n } catch {\n return true\n }\n}\n\nfunction IconMinus(): JSX.Element {\n return (\n <svg width={18} height={18} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.2}\n strokeLinecap=\"round\" aria-hidden=\"true\"><path d=\"M5 12h14\" /></svg>\n )\n}\n\nfunction TeamBadge({ team, label }: { team: MatchdayPredictorTeam; label: string }): JSX.Element {\n return (\n <div className=\"ss-g-mp-team\">\n <CrestShield name={team.name} size={44} />\n <span className=\"ss-g-mp-team-name\">{team.name}</span>\n <span className=\"ss-g-mp-team-side\">{label}</span>\n </div>\n )\n}\n\nfunction ScoreCard({ home, away, h, a, t, edit }: {\n home: MatchdayPredictorTeam\n away: MatchdayPredictorTeam\n h: number\n a: number\n t: PredictorStrings\n edit?: { disabled: boolean; active: Side; onStep: (side: Side, delta: 1 | -1) => void }\n}): JSX.Element {\n const col = (side: Side, team: MatchdayPredictorTeam, value: number): JSX.Element => (\n <div className=\"ss-g-mp-col\">\n {edit && (\n <button type=\"button\" className=\"ss-g-mp-step\" aria-label={t.goalsUp(team.name)}\n disabled={edit.disabled} onClick={() => edit.onStep(side, 1)}>\n <IconPlus size={18} />\n </button>\n )}\n <span className=\"ss-g-mp-digit\" data-testid=\"mp-digit\" data-active={edit ? String(edit.active === side) : 'false'}>\n {value}\n </span>\n {edit && (\n <button type=\"button\" className=\"ss-g-mp-step\" aria-label={t.goalsDown(team.name)}\n disabled={edit.disabled || value <= 0} onClick={() => edit.onStep(side, -1)}>\n <IconMinus />\n </button>\n )}\n </div>\n )\n return (\n <div className=\"ss-g-mp-card\">\n <TeamBadge team={home} label={t.home} />\n <div className=\"ss-g-mp-scores\">\n {col('home', home, h)}\n <span className=\"ss-g-mp-dash\" aria-hidden=\"true\">–</span>\n {col('away', away, a)}\n </div>\n <TeamBadge team={away} label={t.away} />\n </div>\n )\n}\n\nfunction OutcomeRow({ label, ok, detail, t }: { label: string; ok: boolean; detail?: string | null; t: PredictorStrings }): JSX.Element {\n return (\n <li className=\"ss-g-mp-row\" data-testid=\"mp-row\" data-ok={String(ok)}>\n <span className=\"ss-g-mp-row-k\">{label}</span>\n <span className=\"ss-g-mp-row-v\">\n {ok ? <IconCheck /> : <IconClose size={14} />}\n <span className=\"ss-g-sr\">{ok ? t.correct : t.incorrect}</span>\n {detail ? <span className=\"ss-g-mp-row-d\">{detail}</span> : null}\n </span>\n </li>\n )\n}\n\nexport function MatchdayPredictorGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<MatchdayPredictorConfig>): JSX.Element {\n const t = ui.games.predictor\n const [homeScore, setHomeScore] = useState(0)\n const [awayScore, setAwayScore] = useState(0)\n const [firstScorerPlayerId, setFirstScorerPlayerId] = useState<number | null>(null)\n const [lastEdited, setLastEdited] = useState<Side>('home')\n const [query, setQuery] = useState('')\n const searchId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyPlayed = result?.alreadyPlayed === true\n\n const header = (\n <GameHeader\n title={gameTitle({ gameId: 'matchday-predictor' })}\n eyebrow={config ? t.eyebrow(config.homeTeam.name, config.awayTeam.name) : undefined}\n right={config ? <Chip icon={<IconLock />}>{ui.games.formatDayTime(config.kickoffUtc)}</Chip> : undefined}\n onBack={onBack}\n backLabel={ui.back}\n />\n )\n\n // Played states (pending or graded) when the fan has already submitted\n if (alreadyPlayed && clientState) {\n if (!clientState.graded) {\n const scorer = config?.scorerPool.find(p => p.playerId === clientState.predictedFirstScorerPlayerId) ?? null\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-matchday-predictor\">\n {header}\n <div className=\"ss-g-body\">\n {config && (\n <ScoreCard home={config.homeTeam} away={config.awayTeam}\n h={clientState.predictedHomeScore} a={clientState.predictedAwayScore} t={t} />\n )}\n <ResultCard\n tone=\"neutral\"\n title={t.saved}\n detail={t.savedDetail({\n home: config?.homeTeam.name ?? '',\n away: config?.awayTeam.name ?? '',\n h: clientState.predictedHomeScore,\n a: clientState.predictedAwayScore,\n scorer: scorer ? splitName(scorer.playerName).last : null,\n })}\n onBack={onBack}\n ui={ui}\n />\n </div>\n <FooterBar>\n <p className=\"ss-g-mp-fun\">{t.forFun}</p>\n </FooterBar>\n </div>\n )\n }\n\n const r = clientState.result\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-matchday-predictor\">\n {header}\n <div className=\"ss-g-body\">\n {config && <ScoreCard home={config.homeTeam} away={config.awayTeam} h={r.homeScore} a={r.awayScore} t={t} />}\n <ResultCard tone=\"neutral\" title={t.fullTime(r.homeScore, r.awayScore)} onBack={onBack} ui={ui} />\n <ul className=\"ss-g-mp-rows\">\n <OutcomeRow label={t.exactScore} ok={clientState.exactScoreCorrect} t={t} />\n <OutcomeRow label={t.outcome} ok={clientState.outcomeCorrect} t={t} />\n {!clientState.firstScorerVoid && (\n <OutcomeRow label={t.firstScorerRow} ok={clientState.firstScorerCorrect} detail={r.firstScorerName} t={t} />\n )}\n </ul>\n </div>\n <FooterBar>\n <p className=\"ss-g-mp-fun\">{t.forFun}</p>\n </FooterBar>\n </div>\n )\n }\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-matchday-predictor\">\n {header}\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const locked = isLocked(config.kickoffUtc)\n const disabled = locked || submitting\n\n function step(side: Side, delta: 1 | -1): void {\n setLastEdited(side)\n if (side === 'home') setHomeScore(s => Math.max(0, s + delta))\n else setAwayScore(s => Math.max(0, s + delta))\n }\n\n function handleSubmit(): void {\n if (disabled || !config) return\n onSubmit(\n JSON.stringify({\n homeScore,\n awayScore,\n ...(firstScorerPlayerId !== null ? { firstScorerPlayerId } : {}),\n }),\n )\n }\n\n const pool = config.scorerPool\n const showSearch = pool.length > SCORER_SEARCH_THRESHOLD\n const q = query.trim().toLowerCase()\n const visible = showSearch && q ? pool.filter(p => p.playerName.toLowerCase().includes(q)) : pool\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-matchday-predictor\">\n {header}\n <div className=\"ss-g-body\">\n <ScoreCard\n home={config.homeTeam}\n away={config.awayTeam}\n h={homeScore}\n a={awayScore}\n t={t}\n edit={{ disabled, active: lastEdited, onStep: step }}\n />\n\n {pool.length > 0 && (\n <section className=\"ss-g-mp-scorer\">\n <div className=\"ss-g-mp-sec-head\">\n <h3>{t.firstScorer}</h3>\n <span>{t.optional}</span>\n </div>\n {showSearch && (\n <SearchField id={searchId} label={t.searchLabel} labelHidden placeholder={t.searchPlaceholder}\n value={query} onChange={setQuery} disabled={disabled} />\n )}\n <div className=\"ss-g-mp-grid\">\n {visible.map(p => {\n const selected = firstScorerPlayerId === p.playerId\n return (\n <button\n key={p.playerId}\n type=\"button\"\n className=\"ss-g-mp-pcard\"\n aria-pressed={selected}\n aria-label={p.playerName}\n disabled={disabled}\n onClick={() => setFirstScorerPlayerId(id => (id === p.playerId ? null : p.playerId))}\n >\n {selected && <span className=\"ss-g-mp-pcheck\"><IconCheck size={12} /></span>}\n <Silhouette size={52} variant={selected ? 'selected' : 'default'} />\n <span className=\"ss-g-mp-pname\">{splitName(p.playerName).last}</span>\n </button>\n )\n })}\n </div>\n <button\n type=\"button\"\n className=\"ss-g-mp-none\"\n aria-pressed={firstScorerPlayerId === null}\n disabled={disabled}\n onClick={() => setFirstScorerPlayerId(null)}\n >\n <span className=\"ss-g-mp-radio\" aria-hidden=\"true\" />\n {t.noScorer}\n </button>\n </section>\n )}\n\n {locked && <p className=\"ss-g-mp-closed\">{t.closed}</p>}\n </div>\n\n <FooterBar>\n <GameButton variant=\"primary\" block disabled={disabled} onClick={handleSubmit}>\n {submitting ? t.saving : t.save}\n </GameButton>\n <p className=\"ss-g-mp-fun\">{t.forFun}</p>\n </FooterBar>\n </div>\n )\n}\n","import { useId, useState } from 'react'\nimport type {\n GameScreenProps,\n StartingXiConfig,\n StartingXiClientState,\n StartingXiSquadEntry,\n} from './types'\nimport { FORMATION_POSITIONS, lineFallback } from './ui/formations'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { SegmentProgress } from './ui/SegmentProgress'\nimport type { SegmentState } from './ui/SegmentProgress'\nimport { GameButton } from './ui/GameButton'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { PitchSvg } from './ui/PitchSvg'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconLock, IconPlus } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\n\n// Display only — mirrors StartingXiScorer.PointsPerCorrectStarter (StartingXiScorer.cs:47).\nconst POINTS_PER_STARTER = 8\nconst XI_SIZE = 11\nconst DEFAULT_FORMATION = '4-3-3'\n\nexport interface XiSlot {\n index: number\n label: string\n left: number\n top: number\n}\n\nfunction parseClientState(json: string | null | undefined): StartingXiClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as StartingXiClientState\n } catch {\n return null\n }\n}\n\n/**\n * Pitch slots for a formation, goalkeeper first then each outfield line left→right. Positions are\n * percentages of an attacking-half pitch: the keeper sits lowest (top 88%), the front line highest.\n * A formation that does not add up to 10 outfield players falls back to 4-3-3 so there are always 11.\n */\nexport function formationSlots(formation: string): { formation: string; slots: XiSlot[] } {\n const parts = formation.split('-').map(Number).filter(n => n > 0)\n const valid = parts.reduce((s, n) => s + n, 0) === XI_SIZE - 1\n const used = valid ? formation : DEFAULT_FORMATION\n const outfield = valid ? parts : DEFAULT_FORMATION.split('-').map(Number)\n const lines = [1, ...outfield]\n const template = FORMATION_POSITIONS[used]\n const slots: XiSlot[] = []\n lines.forEach((count, li) => {\n const top = 88 - li * (77 / (lines.length - 1))\n for (let ci = 0; ci < count; ci++) {\n const left = count === 1 ? 50 : 12 + ci * (76 / (count - 1))\n slots.push({ index: slots.length, label: template?.[li]?.[ci] ?? lineFallback(li, lines.length), left, top })\n }\n })\n return { formation: used, slots }\n}\n\nfunction firstEmpty(slotPlayers: (number | null)[]): number | null {\n const i = slotPlayers.findIndex(p => p === null)\n return i === -1 ? null : i\n}\n\nexport function StartingXiGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n lockAtUtc,\n}: GameScreenProps<StartingXiConfig>): JSX.Element {\n const t = ui.games.startingXi\n const [slotPlayers, setSlotPlayers] = useState<(number | null)[]>(() => Array<number | null>(XI_SIZE).fill(null))\n const [active, setActive] = useState<number | null>(0)\n const [query, setQuery] = useState('')\n const searchId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyPlayed = result?.alreadyPlayed === true\n\n const header = (\n <GameHeader\n title={gameTitle({ gameId: 'starting-xi' })}\n eyebrow={t.eyebrow}\n right={<Chip variant=\"accent\">{t.perStarter(POINTS_PER_STARTER)}</Chip>}\n onBack={onBack}\n backLabel={ui.back}\n />\n )\n\n // Pending, graded and voided all render the spec §6 result card with a way back to the hub.\n function statusScreen(title: string, score?: number): JSX.Element {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-starting-xi\">\n {header}\n <div className=\"ss-g-body\">\n <ResultCard tone=\"neutral\" title={title} score={score} onBack={onBack} ui={ui} />\n </div>\n </div>\n )\n }\n\n if (alreadyPlayed) {\n if (!clientState) return statusScreen(t.voided)\n if (clientState.status === 'pending') return statusScreen(t.pending(clientState.predictedCount))\n if (clientState.status === 'graded') return statusScreen(t.gradedLine(clientState.correctCount), clientState.score)\n }\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-starting-xi\">\n {header}\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const { formation, slots } = formationSlots(config.formation)\n const byId = new Map<number, StartingXiSquadEntry>(config.squadSheet.map(p => [p.playerId, p]))\n const pickedCount = slotPlayers.filter(p => p !== null).length\n const canSubmit = pickedCount === XI_SIZE && !submitting\n const pickedSet = new Set(slotPlayers.filter((p): p is number => p !== null))\n const q = query.trim().toLowerCase()\n const available = config.squadSheet.filter(\n p => !pickedSet.has(p.playerId) && (!q || (p.playerName ?? '').toLowerCase().includes(q)),\n )\n const activeSlot = active !== null ? slots[active] ?? null : null\n\n function pick(playerId: number): void {\n if (submitting || active === null) return\n const next = [...slotPlayers]\n next[active] = playerId\n setSlotPlayers(next)\n setActive(firstEmpty(next))\n setQuery('')\n }\n\n function tapSlot(index: number): void {\n if (submitting) return\n if (slotPlayers[index] !== null) {\n const next = [...slotPlayers]\n next[index] = null\n setSlotPlayers(next)\n }\n setActive(index)\n }\n\n function handleSubmit(): void {\n if (!canSubmit) return\n onSubmit(JSON.stringify({ predictedPlayerIds: slotPlayers }))\n }\n\n const segments: SegmentState[] = slotPlayers.map(p => (p !== null ? 'current' : 'todo'))\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-starting-xi\">\n {header}\n <SegmentProgress\n segments={segments}\n ariaLabel={t.picked(pickedCount)}\n leftLabel={t.picked(pickedCount)}\n rightLabel={t.toGo(XI_SIZE - pickedCount)}\n right={<Chip>{formation}</Chip>}\n />\n <div className=\"ss-g-body\">\n <div className=\"ss-g-xi-pitch\">\n <PitchSvg variant=\"half\" />\n {slots.map(s => {\n const playerId = slotPlayers[s.index] ?? null\n const player = playerId !== null ? byId.get(playerId) ?? null : null\n const name = player?.playerName ?? ''\n const state = player ? 'filled' : active === s.index ? 'active' : 'empty'\n return (\n <button\n key={s.index}\n type=\"button\"\n className=\"ss-g-xi-slot\"\n data-state={state}\n style={{ left: `${s.left}%`, top: `${s.top}%` }}\n aria-pressed={active === s.index}\n aria-label={player ? t.clearSlot(s.label, name) : t.pickSlot(s.label)}\n disabled={submitting}\n onClick={() => tapSlot(s.index)}\n >\n <span className=\"ss-g-xi-ring\" aria-hidden=\"true\">\n {player ? (player.jerseyNumber ?? '') : <IconPlus size={18} />}\n </span>\n <span className=\"ss-g-xi-tag\" aria-hidden=\"true\">{player ? splitName(name).last : s.label}</span>\n </button>\n )\n })}\n </div>\n\n <div className=\"ss-g-xi-picker\">\n <div className=\"ss-g-xi-picker-head\">\n {activeSlot ? (\n <>\n <Chip variant=\"badge\">{activeSlot.label}</Chip>\n <strong>{t.pickFor(activeSlot.label)}</strong>\n </>\n ) : (\n <strong>{t.allPicked}</strong>\n )}\n </div>\n {activeSlot && (\n <>\n <SearchField id={searchId} label={t.searchLabel} labelHidden placeholder={t.searchLabel}\n value={query} onChange={setQuery} disabled={submitting} />\n <ul className=\"ss-g-xi-list\">\n {available.map(p => (\n <li key={p.playerId}>\n <button type=\"button\" className=\"ss-g-xi-opt\" disabled={submitting} onClick={() => pick(p.playerId)}>\n <span className=\"ss-g-xi-opt-no\" aria-hidden=\"true\">{p.jerseyNumber ?? ''}</span>\n <span className=\"ss-g-xi-opt-name\">{p.playerName}</span>\n <span className=\"ss-g-xi-opt-pos\">{p.positionName}</span>\n </button>\n </li>\n ))}\n </ul>\n </>\n )}\n </div>\n </div>\n <FooterBar>\n <GameButton variant=\"primary\" block disabled={!canSubmit} onClick={handleSubmit}>\n {submitting ? t.submitting : t.submit}\n </GameButton>\n <p className=\"ss-g-xi-lock\">\n <IconLock />\n {lockAtUtc ? t.locksAt(ui.games.formatDayTime(lockAtUtc)) : t.locksSoon}\n </p>\n </FooterBar>\n </div>\n )\n}\n","import { useId, useState } from 'react'\nimport type {\n GameScreenProps,\n StatLadderConfig,\n StatLadderClientState,\n StatLadderRung,\n} from './types'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { GameButton } from './ui/GameButton'\nimport { SearchField } from './ui/SearchField'\nimport { FooterBar } from './ui/FooterBar'\nimport { Silhouette } from './ui/Silhouette'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconBulb, IconCheck, IconShield } from './ui/icons'\nimport { gameTitle, splitName } from './ui/gameMeta'\nimport { PlayerAvatar } from './PlayerAvatar'\n\nexport interface LadderClue {\n value: number\n above: { name: string; diff: number } | null\n below: { name: string; diff: number } | null\n}\n\n/** Pure: the mystery rung's value plus its gaps to the named rungs directly above (rank 1) and below (rank 3). */\nexport function ladderClue(ladder: StatLadderRung[]): LadderClue | null {\n const mystery = ladder.find(r => r.rank === 2)\n if (!mystery) return null\n const above = ladder.find(r => r.rank === 1)\n const below = ladder.find(r => r.rank === 3)\n return {\n value: mystery.statValue,\n above: above?.playerName ? { name: above.playerName, diff: above.statValue - mystery.statValue } : null,\n below: below?.playerName ? { name: below.playerName, diff: mystery.statValue - below.statValue } : null,\n }\n}\n\nfunction parseClientState(json: string | null | undefined): StatLadderClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as StatLadderClientState\n } catch {\n return null\n }\n}\n\nfunction NameStack({ name }: { name: string }): JSX.Element {\n const { first, last } = splitName(name)\n return (\n <span className=\"ss-g-sl-name\">\n {first && <small>{`${first[0]}.`}</small>}\n <b>{last}</b>\n </span>\n )\n}\n\nexport function StatLadderGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<StatLadderConfig>): JSX.Element {\n const t = ui.games.statLadder\n const [query, setQuery] = useState('')\n const [selectedId, setSelectedId] = useState<number | null>(null)\n const searchId = useId()\n\n const clientState = parseClientState(result?.clientStateJson)\n const revealed = clientState != null\n\n const header = (\n <GameHeader title={gameTitle({ gameId: 'stat-ladder' })} eyebrow={t.eyebrow} onBack={onBack} backLabel={ui.back} />\n )\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-stat-ladder\">\n {header}\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const question = t.question(config.statLabel)\n const clue = revealed ? null : ladderClue(config.ladder)\n const rungs = [...config.ladder].sort((a, b) => a.rank - b.rank)\n const q = query.trim().toLowerCase()\n const pool = q ? config.playerPool.filter(p => p.playerName.toLowerCase().includes(q)) : config.playerPool\n\n function guess(): void {\n if (selectedId === null || submitting || revealed) return\n onSubmit(JSON.stringify({ guessedPlayerId: selectedId }))\n }\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-stat-ladder\">\n {header}\n <div className=\"ss-g-body\">\n <div className=\"ss-g-sl-prompt\">\n <Chip variant=\"accent\" icon={<IconShield size={14} />} className=\"ss-g-sl-stat\">{config.statLabel}</Chip>\n <h3 className=\"ss-g-sl-q\">\n {question.pre}<em>{question.emph}</em>{question.post}\n </h3>\n </div>\n\n <ol className=\"ss-g-sl-rungs\">\n {rungs.map(rung =>\n rung.rank === 2 ? (\n <li\n key={rung.rank}\n className=\"ss-g-sl-rung ss-g-sl-rung--mystery\"\n data-testid=\"sl-mystery-rung\"\n data-result={revealed ? (clientState!.isCorrect ? 'correct' : 'wrong') : undefined}\n >\n <span className=\"ss-g-sl-rank\">2</span>\n {revealed\n ? <PlayerAvatar name={clientState!.revealedRank2.playerName} className=\"ss-g-sl-av\" />\n : <Silhouette size={52} variant=\"mystery\" />}\n {revealed\n ? <NameStack name={clientState!.revealedRank2.playerName} />\n : <span className=\"ss-g-sl-who\">{t.whoSecond}</span>}\n <span className=\"ss-g-sl-val ss-g-sl-val--mystery\">{rung.statValue}</span>\n </li>\n ) : (\n <li key={rung.rank} className=\"ss-g-sl-rung\">\n <span className=\"ss-g-sl-rank\">{rung.rank}</span>\n <PlayerAvatar name={rung.playerName ?? '?'} className=\"ss-g-sl-av\" />\n <NameStack name={rung.playerName ?? '?'} />\n <span className=\"ss-g-sl-val\">{rung.statValue}</span>\n </li>\n ),\n )}\n </ol>\n\n {clue && (\n <p className=\"ss-g-sl-clue\">\n <IconBulb />\n <span>{t.clue(clue, config.statLabel)}</span>\n </p>\n )}\n\n {!revealed && (\n <ul className=\"ss-g-sl-pool\">\n {pool.map(p => (\n <li key={p.playerId}>\n <button\n type=\"button\"\n className=\"ss-g-sl-opt\"\n aria-label={p.playerName}\n aria-pressed={selectedId === p.playerId}\n disabled={submitting}\n onClick={() => { setSelectedId(p.playerId); setQuery(p.playerName) }}\n >\n <PlayerAvatar name={p.playerName} className=\"ss-g-sl-opt-av\" />\n <span className=\"ss-g-sl-opt-name\">{p.playerName}</span>\n {selectedId === p.playerId && <IconCheck />}\n </button>\n </li>\n ))}\n </ul>\n )}\n\n {revealed && (\n <ResultCard\n tone={clientState!.isCorrect ? 'win' : 'lose'}\n title={clientState!.isCorrect ? t.correct : t.wrong(clientState!.revealedRank2.playerName)}\n score={result?.score}\n onBack={onBack}\n ui={ui}\n />\n )}\n </div>\n\n {!revealed && (\n <FooterBar>\n <div className=\"ss-g-sl-guess\">\n <SearchField\n id={searchId}\n label={t.searchLabel}\n labelHidden\n placeholder={t.searchPlaceholder}\n value={query}\n onChange={v => { setQuery(v); setSelectedId(null) }}\n disabled={submitting}\n />\n <GameButton variant=\"primary\" disabled={selectedId === null || submitting} onClick={guess}>\n {t.guess}\n </GameButton>\n </div>\n </FooterBar>\n )}\n </div>\n )\n}\n","import type {\n GameScreenProps,\n FanMotmConfig,\n FanMotmClientState,\n} from './types'\nimport { GameHeader } from './ui/GameHeader'\nimport { Chip } from './ui/Chip'\nimport { FooterBar } from './ui/FooterBar'\nimport { ResultCard } from './ui/ResultCard'\nimport { IconCheck } from './ui/icons'\nimport { PlayerAvatar } from './PlayerAvatar'\n\nfunction parseClientState(json: string | null | undefined): FanMotmClientState | null {\n if (!json) return null\n try {\n return JSON.parse(json) as FanMotmClientState\n } catch {\n return null\n }\n}\n\nexport function FanMotmGame({\n config,\n result,\n submitting,\n onSubmit,\n ui,\n onBack,\n}: GameScreenProps<FanMotmConfig>): JSX.Element {\n const t = ui.games.motm\n const clientState = parseClientState(result?.clientStateJson)\n const alreadyVoted = result?.alreadyPlayed === true\n const pickedId = clientState?.pickedPlayerId ?? null\n\n const header = (\n <GameHeader\n title={t.title}\n eyebrow={t.eyebrow}\n right={alreadyVoted ? <Chip variant=\"success\" icon={<IconCheck />}>{t.voted}</Chip> : undefined}\n onBack={onBack}\n backLabel={ui.back}\n />\n )\n\n if (!config) {\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-fan-motm\">\n {header}\n <div className=\"ss-g-body ss-g-loading\">{ui.games.loading}</div>\n </div>\n )\n }\n\n const picked = config.candidates.find(c => c.playerId === pickedId) ?? null\n\n function handleVote(candidateId: number): void {\n if (alreadyVoted || submitting) return\n onSubmit(JSON.stringify({ pickedPlayerId: candidateId }))\n }\n\n return (\n <div className=\"ss-g-screen\" data-testid=\"game-screen-fan-motm\">\n {header}\n <div className=\"ss-g-body\">\n <ul className=\"ss-g-motm-list\">\n {config.candidates.map(c => {\n const isVoted = alreadyVoted && pickedId === c.playerId\n return (\n <li key={c.playerId}>\n <button\n type=\"button\"\n className={`ss-g-motm-row${isVoted ? ' ss-g-motm-row--voted' : ''}`}\n data-testid={`motm-candidate-${c.playerId}`}\n disabled={alreadyVoted || submitting}\n onClick={() => handleVote(c.playerId)}\n >\n <PlayerAvatar name={c.playerName} className=\"ss-g-motm-av\" />\n <span className=\"ss-g-motm-name\">{c.playerName}</span>\n {isVoted && <Chip variant=\"accent\" className=\"ss-g-motm-pill\">{t.yourVote}</Chip>}\n </button>\n </li>\n )\n })}\n </ul>\n {alreadyVoted && picked && (\n <ResultCard tone=\"neutral\" title={t.youVoted(picked.playerName)} detail={t.thanks} onBack={onBack} ui={ui} />\n )}\n </div>\n <FooterBar>\n {!alreadyVoted && <p className=\"ss-g-motm-foot\">{t.tapToVote}</p>}\n <p className=\"ss-g-motm-fun\">{t.forFun}</p>\n </FooterBar>\n </div>\n )\n}\n","const FONTS_LINK_ID = 'ss-w-games-fonts'\nconst FONTS_HREF =\n 'https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@600;700;800&family=Barlow:wght@400;500;600;700&display=swap'\n\n// Registered at document level: @font-face inside a shadow root is ignored by browsers, but\n// document fonts resolve inside the embed's shadow tree. If CSP blocks it the fallback stack renders.\nexport function ensureGamesFonts(doc: Document = document): void {\n if (!doc.head) return\n if (doc.getElementById(FONTS_LINK_ID)) return\n const link = doc.createElement('link')\n link.id = FONTS_LINK_ID\n link.rel = 'stylesheet'\n link.href = FONTS_HREF\n doc.head.appendChild(link)\n}\n","import { useState } from 'react'\nimport type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { LeaderboardWeeklyRow, LeaderboardAllTimeRow, formatPoints } from './LeaderboardRow'\nimport { LeaderboardEmpty } from './LeaderboardEmpty'\n\ntype Segment = 'weekly' | 'alltime'\n\nexport function Leaderboard({\n data,\n ui,\n onPlay,\n}: {\n data: LeaderboardPayload\n ui: UiConfig\n /** Jumps to the Games tab from the empty-state CTA. */\n onPlay?: () => void\n}): JSX.Element {\n const [segment, setSegment] = useState<Segment>('weekly')\n\n const myRow = segment === 'weekly' ? data.myWeeklyRow : data.myAllTimeRow\n const offBoard = myRow !== null && myRow !== undefined && myRow.rank === -1\n const isEmpty = segment === 'weekly'\n ? data.weeklyTop.length === 0\n : data.allTimeTop.length === 0\n\n return (\n <div className=\"ss-w-lb2\">\n <div className=\"ss-w-seg\">\n <button\n type=\"button\"\n className=\"ss-w-seg-btn\"\n {...(segment === 'weekly' ? { 'data-on': '' } : {})}\n onClick={() => setSegment('weekly')}\n >\n {ui.leaderboardThisWeek}\n </button>\n <button\n type=\"button\"\n className=\"ss-w-seg-btn\"\n {...(segment === 'alltime' ? { 'data-on': '' } : {})}\n onClick={() => setSegment('alltime')}\n >\n {ui.leaderboardAllTime}\n </button>\n </div>\n\n {isEmpty ? (\n <LeaderboardEmpty\n segment={segment}\n lastWeek={data.lastWeek}\n weeklyPrize={data.weeklyPrize}\n onPlay={onPlay}\n ui={ui}\n />\n ) : (\n <>\n <div className=\"ss-w-lb2-rows\">\n {segment === 'weekly'\n ? data.weeklyTop.map((row) => (\n <LeaderboardWeeklyRow\n key={row.operatorUserId}\n row={row}\n isMe={row.operatorUserId === data.myWeeklyRow?.operatorUserId}\n />\n ))\n : data.allTimeTop.map((row) => (\n <LeaderboardAllTimeRow\n key={row.operatorUserId}\n row={row}\n isMe={row.operatorUserId === data.myAllTimeRow?.operatorUserId}\n />\n ))}\n </div>\n\n {/* Kit-prize separator */}\n <div className=\"ss-w-kitline\">🎽</div>\n\n {/* Pinned \"you\" row or off-board treatment */}\n {myRow != null && (\n offBoard ? (\n <div className=\"ss-w-lbgap\">{ui.leaderboardOffBoard}</div>\n ) : (\n <div className=\"ss-w-lb2-rows\">\n {segment === 'weekly' && data.myWeeklyRow && (\n <LeaderboardWeeklyRow row={data.myWeeklyRow} isMe />\n )}\n {segment === 'alltime' && data.myAllTimeRow && (\n <LeaderboardAllTimeRow row={data.myAllTimeRow} isMe />\n )}\n </div>\n )\n )}\n\n {/* All-time footer: show rank + total when available */}\n {segment === 'alltime' && data.myAllTimeRow && !offBoard && (\n <div className=\"ss-w-lb2-rows\">\n <div className=\"ss-w-lb2-row\">\n <span className=\"ss-w-lb2-handle\">\n {formatPoints(data.allTimeTop.reduce((s, r) => s + r.allTimePoints, 0))}\n </span>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )\n}\n","import type { LeaderboardRow as SDKRow, AllTimeRow } from '@sensiblestats/widget-sdk'\n\n/** Formats a points integer with thousands separators. */\nexport function formatPoints(n: number): string {\n return n.toLocaleString('en')\n}\n\nexport function LeaderboardWeeklyRow({\n row,\n isMe,\n}: {\n row: SDKRow\n isMe: boolean\n}): JSX.Element {\n const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? ' ss-w-lb2-rank--top3' : ''}`\n return (\n <div className={`ss-w-lb2-row${isMe ? ' ss-w-lb2-row--you' : ''}`}>\n <span className={rankClass}>#{row.rank}</span>\n <span className=\"ss-w-lb2-handle\">{row.handle}</span>\n <span className=\"ss-w-lb2-points\">{formatPoints(row.points)}</span>\n {row.currentStreak > 0 && (\n <span className=\"ss-w-lb2-streak\">🔥 {row.currentStreak}</span>\n )}\n </div>\n )\n}\n\nexport function LeaderboardAllTimeRow({\n row,\n isMe,\n}: {\n row: AllTimeRow\n isMe: boolean\n}): JSX.Element {\n const rankClass = `ss-w-lb2-rank${row.rank <= 3 ? ' ss-w-lb2-rank--top3' : ''}`\n return (\n <div className={`ss-w-lb2-row${isMe ? ' ss-w-lb2-row--you' : ''}`}>\n <span className={rankClass}>#{row.rank}</span>\n <span className=\"ss-w-lb2-handle\">{row.handle}</span>\n <span className=\"ss-w-lb2-points\">{formatPoints(row.allTimePoints)}</span>\n </div>\n )\n}\n","import type { LeaderboardChampion } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { formatPoints } from './LeaderboardRow'\n\ntype Segment = 'weekly' | 'alltime'\n\n/**\n * Default state for the leaderboard when the active segment has no ranked rows.\n * Weekly boards reset every week, so this is what most fans see at the start of a week.\n * - weekly + a prior champion -> \"fresh week\" copy plus a last-week continuity strip\n * - weekly + no history -> \"cold start\" copy (club's first-ever week)\n * - all-time -> a quiet single line; it fills as fans play\n */\nexport function LeaderboardEmpty({\n segment,\n lastWeek,\n weeklyPrize,\n onPlay,\n ui,\n}: {\n segment: Segment\n lastWeek?: LeaderboardChampion | null\n weeklyPrize?: string | null\n onPlay?: () => void\n ui: UiConfig\n}): JSX.Element {\n if (segment === 'alltime') {\n return (\n <div className=\"ss-w-lb-empty ss-w-lb-empty--alltime\">\n <div className=\"ss-w-lb-empty-icon\" aria-hidden=\"true\">📊</div>\n <p className=\"ss-w-lb-empty-body\">{ui.leaderboardAllTimeEmpty}</p>\n </div>\n )\n }\n\n const fresh = lastWeek != null\n const title = fresh ? ui.leaderboardEmptyFreshTitle : ui.leaderboardEmptyColdTitle\n const body = fresh ? ui.leaderboardEmptyFreshBody : ui.leaderboardEmptyColdBody\n\n return (\n <div className=\"ss-w-lb-empty\">\n {weeklyPrize && (\n <div className=\"ss-w-prize\">\n <span className=\"ss-w-prize-icon\" aria-hidden=\"true\">🏆</span>\n <div className=\"ss-w-prize-body\">\n <span className=\"ss-w-prize-text\">{weeklyPrize}</span>\n </div>\n </div>\n )}\n\n <div className=\"ss-w-lb-empty-hero\">\n <div className=\"ss-w-lb-empty-icon\" aria-hidden=\"true\">{fresh ? '🏆' : '🎮'}</div>\n <h4 className=\"ss-w-lb-empty-title\">{title}</h4>\n <p className=\"ss-w-lb-empty-body\">{body}</p>\n {onPlay && (\n <button type=\"button\" className=\"ss-w-lb-empty-cta\" onClick={onPlay}>\n {ui.leaderboardEmptyCta}\n </button>\n )}\n </div>\n\n {fresh && lastWeek && (\n <div className=\"ss-w-lb-last\">\n <span className=\"ss-w-lb-last-label\">{ui.leaderboardLastWeekLabel}</span>\n <span className=\"ss-w-lb-last-champ\" aria-hidden=\"true\">🥇</span>\n <span className=\"ss-w-lb-last-handle\">{lastWeek.handle}</span>\n <span className=\"ss-w-lb-last-points\">{formatPoints(lastWeek.points)}</span>\n </div>\n )}\n </div>\n )\n}\n","import type { LeaderboardPayload } from '@sensiblestats/widget-sdk'\nimport type { UiConfig } from '../config'\nimport { GamesLoginWall } from './GamesLoginWall'\nimport { Leaderboard } from './Leaderboard'\n\n/** Settled empty board (no rows yet) — a fetch that returned null once loading is done. */\nconst EMPTY_PAYLOAD: LeaderboardPayload = {\n week: '',\n weeklyTop: [],\n myWeeklyRow: null,\n allTimeTop: [],\n myAllTimeRow: null,\n weeklyPrize: null,\n lastWeek: null,\n}\n\nexport function LeaderboardPanel({ loggedIn, data, loading, onPlay, ui }: {\n loggedIn: boolean\n data: LeaderboardPayload | null\n loading?: boolean\n onPlay?: () => void\n ui: UiConfig\n}): JSX.Element {\n if (!loggedIn) return <GamesLoginWall ui={ui} />\n // Still fetching with nothing to show yet: keep the panel blank (skeleton-free).\n if (data === null && loading) return <div className=\"ss-w-mon-list\" />\n return (\n <div className=\"ss-w-mon-list\">\n <Leaderboard data={data ?? EMPTY_PAYLOAD} ui={ui} onPlay={onPlay} />\n </div>\n )\n}\n","// AUTO-GENERATED by scripts/gen-css.mjs from widget.css. Do not edit.\nexport const WIDGET_CSS = \".ss-w-root { all: revert; }\\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\\n.ss-w-root {\\n --ss-w-accent: #17936a;\\n --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n --ss-w-pos: #1aa563; --ss-w-neg: #e0524b;\\n --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;\\n --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;\\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, Helvetica, Arial, sans-serif;\\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\\n}\\n@media (prefers-color-scheme: dark) {\\n .ss-w-root[data-ss-w-theme=\\\"auto\\\"] {\\n --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n --ss-w-pos: #37c891; --ss-w-neg: #f0655d;\\n --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;\\n --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;\\n }\\n}\\n.ss-w-root[data-ss-w-theme=\\\"dark\\\"] {\\n --ss-w-accent: #37c891; --ss-w-cta: #ffb638; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n --ss-w-pos: #37c891; --ss-w-neg: #f0655d;\\n --ss-w-home: #5b83c8; --ss-w-away: #e8384f; --ss-w-track: #232d3a;\\n --ss-w-correct: #37c86b; --ss-w-wrong: #3a3a41;\\n}\\n.ss-w-root[data-ss-w-theme=\\\"light\\\"] {\\n --ss-w-accent: #17936a; --ss-w-cta: #f5a623; --ss-w-cta-ink: #1b1300;\\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n --ss-w-home: #3a63a8; --ss-w-away: #c8102e; --ss-w-track: #e9edf1;\\n --ss-w-correct: #1f9d55; --ss-w-wrong: #b9bbc2;\\n}\\n\\n/* ── games design tokens (u393) ── derived from operator tokens so every tenant theme works.\\n Targets (Hull #F5A800/#0B0B0B/#F5F5F5): ground #0D0C0A, surface #17150F, warm #1C1810,\\n raised #211E17, line #26221A, line-warm #3A2F18, accent-tint #3A2C10, strong-line #4A4131. */\\n.ss-w-root {\\n --ss-g-ground: color-mix(in srgb, var(--ss-w-accent) 2%, var(--ss-w-panel));\\n --ss-g-surface: color-mix(in srgb, var(--ss-w-accent) 3%, color-mix(in srgb, var(--ss-w-ink) 3%, var(--ss-w-panel)));\\n --ss-g-warm: color-mix(in srgb, var(--ss-w-accent) 6%, color-mix(in srgb, var(--ss-w-ink) 2%, var(--ss-w-panel)));\\n --ss-g-raised: color-mix(in srgb, var(--ss-w-accent) 3%, color-mix(in srgb, var(--ss-w-ink) 6%, var(--ss-w-panel)));\\n --ss-g-line: color-mix(in srgb, var(--ss-w-accent) 4%, color-mix(in srgb, var(--ss-w-ink) 8%, var(--ss-w-panel)));\\n --ss-g-line-warm: color-mix(in srgb, var(--ss-w-accent) 18%, color-mix(in srgb, var(--ss-w-ink) 3%, var(--ss-w-panel)));\\n --ss-g-accent-tint: color-mix(in srgb, var(--ss-w-accent) 20%, var(--ss-w-panel));\\n --ss-g-strong-line: color-mix(in srgb, var(--ss-w-accent) 8%, color-mix(in srgb, var(--ss-w-ink) 18%, var(--ss-w-panel)));\\n --ss-g-ink: color-mix(in srgb, var(--ss-w-accent) 4%, var(--ss-w-ink));\\n --ss-g-ink-2: color-mix(in srgb, var(--ss-w-accent) 4%, color-mix(in srgb, var(--ss-w-ink) 72%, var(--ss-w-panel)));\\n --ss-g-muted: color-mix(in srgb, var(--ss-w-accent) 5%, color-mix(in srgb, var(--ss-w-ink) 60%, var(--ss-w-panel)));\\n --ss-g-faint: color-mix(in srgb, var(--ss-w-ink) 45%, var(--ss-w-panel));\\n --ss-g-on-accent: #1a1206;\\n --ss-g-on-correct: #fff;\\n --ss-g-correct: color-mix(in srgb, var(--ss-w-correct) 55%, #000);\\n --ss-g-wrong: color-mix(in srgb, var(--ss-w-neg) 55%, #000);\\n /* Brighter wrong for thin marks (borders, icons, segments) that must read on dark surfaces; --ss-g-wrong stays for fills. */\\n --ss-g-wrong-mark: var(--ss-w-neg);\\n --ss-g-success: color-mix(in srgb, var(--ss-w-pos) 80%, var(--ss-w-ink));\\n --ss-g-success-tint: color-mix(in srgb, var(--ss-w-pos) 18%, var(--ss-w-panel));\\n --ss-g-close: #e3b341;\\n --ss-g-flame: #ff6a1a;\\n /* Pitch colours are fixed in both themes: the pitch is always a dark green. */\\n --ss-g-pitch: #123524;\\n --ss-g-pitch-line: #3e7055;\\n --ss-g-pitch-chip: #0d0c0a;\\n --ss-g-pitch-ink: #f4efe6;\\n --ss-g-pitch-mark: #c9d6cd;\\n --ss-g-font-display: 'Barlow Condensed', 'Arial Narrow', system-ui, sans-serif;\\n --ss-g-font-body: 'Barlow', system-ui, -apple-system, 'Segoe UI', sans-serif;\\n}\\n\\n/* ── games ui kit (u393) ── */\\n.ss-g-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\\n.ss-g-head { display: flex; align-items: center; gap: 6px; padding: 8px 16px 8px 6px; font-family: var(--ss-g-font-body); }\\n.ss-g-back { width: 44px; height: 44px; flex: none; display: grid; place-items: center; border: 0; border-radius: 12px; background: transparent; color: var(--ss-g-ink); cursor: pointer; }\\n.ss-g-back:hover { background: var(--ss-g-surface); }\\n.ss-g-head-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.05; }\\n.ss-g-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ss-g-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-title { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 26px; text-transform: uppercase; color: var(--ss-g-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-head-right { flex: none; }\\n.ss-g-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px; font-size: 13px; font-weight: 600; white-space: nowrap; }\\n.ss-g-chip--neutral { background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); color: var(--ss-g-ink); }\\n.ss-g-chip--neutral .ss-g-num, .ss-g-chip--neutral svg { color: var(--ss-w-accent); }\\n.ss-g-chip--accent { background: var(--ss-g-accent-tint); color: var(--ss-w-accent); font-weight: 700; }\\n.ss-g-chip--success { background: var(--ss-g-success-tint); color: var(--ss-g-success); font-weight: 700; }\\n.ss-g-chip--badge { padding: 3px 8px; font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; background: var(--ss-g-accent-tint); color: var(--ss-w-accent); }\\n.ss-g-chip--lock { padding: 3px 8px; border-radius: 6px; font-size: 12px; font-weight: 500; background: var(--ss-g-raised); color: var(--ss-g-muted); }\\n.ss-g-statstack { display: flex; flex-direction: column; align-items: flex-end; line-height: 1; }\\n.ss-g-statstack-v { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 26px; color: var(--ss-w-accent); }\\n.ss-g-statstack-l { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-progress { display: flex; align-items: center; gap: 12px; padding: 0 16px 8px; }\\n.ss-g-progress-main { flex: 1; display: flex; flex-direction: column; gap: 6px; }\\n.ss-g-progress-labels { display: flex; justify-content: space-between; font-size: 12px; font-weight: 600; color: var(--ss-g-ink); }\\n.ss-g-progress-rl { color: var(--ss-g-muted); }\\n.ss-g-segs { display: grid; gap: 4px; }\\n.ss-g-seg { height: 5px; border-radius: 3px; background: var(--ss-g-line); }\\n.ss-g-seg[data-state=\\\"done\\\"] { background: var(--ss-g-strong-line); }\\n.ss-g-seg[data-state=\\\"current\\\"] { background: var(--ss-w-accent); }\\n.ss-g-seg[data-state=\\\"correct\\\"] { background: var(--ss-g-correct); }\\n.ss-g-seg[data-state=\\\"wrong\\\"] { background: var(--ss-g-wrong-mark); }\\n.ss-g-btn { min-height: 48px; padding: 0 16px; border-radius: 12px; font-family: var(--ss-g-font-body); font-size: 14px; font-weight: 700; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 8px; }\\n.ss-g-btn:disabled { opacity: .45; cursor: default; }\\n.ss-g-btn--block { width: 100%; min-height: 54px; border-radius: 14px; font-size: 16px; font-weight: 800; }\\n.ss-g-btn--primary { border: 0; background: var(--ss-w-accent); color: var(--ss-g-on-accent); }\\n.ss-g-btn--outline { border: 1.5px solid var(--ss-g-strong-line); background: transparent; color: var(--ss-g-ink); }\\n.ss-g-btn--accent-outline { border: 1.5px solid var(--ss-w-accent); background: transparent; color: var(--ss-w-accent); }\\n.ss-g-btn--surface { border: 1px solid var(--ss-g-line); background: var(--ss-g-surface); color: var(--ss-g-ink); font-weight: 600; font-size: 13px; }\\n.ss-g-search { display: flex; flex-direction: column; gap: 6px; }\\n.ss-g-search-label { font-size: 12px; font-weight: 600; color: var(--ss-g-muted); }\\n.ss-g-search-box { display: flex; align-items: center; gap: 10px; height: 50px; padding: 0 14px; border-radius: 14px; background: var(--ss-g-surface); border: 1.5px solid var(--ss-g-line); color: var(--ss-g-muted); }\\n.ss-g-search-box:focus-within { border-color: var(--ss-w-accent); }\\n.ss-g-search-box input { flex: 1; min-width: 0; border: 0; outline: none; background: transparent; color: var(--ss-g-ink); font: 500 15px var(--ss-g-font-body); }\\n.ss-g-footer { flex: none; padding: 12px 16px 16px; border-top: 1px solid var(--ss-g-line); display: flex; flex-direction: column; gap: 10px; background: var(--ss-g-ground); }\\n.ss-g-sil { position: relative; flex: none; display: inline-flex; align-items: flex-end; justify-content: center; overflow: hidden; border-radius: 50%; background: var(--ss-g-raised); color: var(--ss-g-strong-line); }\\n.ss-g-sil--selected { background: var(--ss-g-accent-tint); color: color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-g-raised)); }\\n.ss-g-sil--mystery { background: var(--ss-g-accent-tint); color: var(--ss-g-ground); }\\n.ss-g-sil-q { position: absolute; top: 22%; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 1.1em; color: var(--ss-w-accent); }\\n.ss-g-crest { flex: none; object-fit: contain; }\\n.ss-g-crest--ph { color: var(--ss-g-strong-line); }\\n.ss-g-pitch-svg { position: absolute; inset: 0; width: 100%; height: 100%; stroke: var(--ss-g-pitch-line); stroke-width: .6; }\\n/* ── games screen scaffold (u393) — shared by every game screen ── */\\n.ss-w-gscreen > .ss-g-screen { flex: 1; min-height: 0; }\\n.ss-g-screen { display: flex; flex-direction: column; min-height: 0; background: var(--ss-g-ground); color: var(--ss-g-ink); font-family: var(--ss-g-font-body); }\\n.ss-g-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 14px; padding: 4px 16px 16px; }\\n.ss-g-body .ss-g-progress { padding: 0; }\\n.ss-g-loading { align-items: center; justify-content: center; color: var(--ss-g-muted); font-size: 13px; }\\n.ss-g-opts { display: flex; flex-direction: column; gap: 4px; max-height: 232px; overflow-y: auto; }\\n.ss-g-opt { display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 6px 8px; border: 0; border-radius: 12px; background: var(--ss-g-surface); color: var(--ss-g-ink); font: 600 15px var(--ss-g-font-body); text-align: left; cursor: pointer; }\\n.ss-g-opt:hover, .ss-g-opt:focus-visible { background: var(--ss-g-raised); outline: none; }\\n.ss-g-opt-av { width: 40px; height: 40px; flex: none; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--ss-g-raised); color: var(--ss-g-muted); font-size: 13px; font-weight: 700; }\\n.ss-g-opt-av img { width: 100%; height: 100%; object-fit: cover; }\\n.ss-g-result { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 16px; border-radius: 18px; background: var(--ss-g-warm); border: 1px solid var(--ss-g-line-warm); }\\n.ss-g-result[data-tone=\\\"win\\\"] { border-color: var(--ss-g-correct); }\\n.ss-g-result[data-tone=\\\"lose\\\"] { border-color: var(--ss-g-wrong-mark); }\\n.ss-g-result-title { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 26px; text-transform: uppercase; line-height: 1; }\\n.ss-g-result-score { font-size: 13px; font-weight: 700; color: var(--ss-g-muted); }\\n.ss-g-result-num { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 40px; color: var(--ss-w-accent); margin-right: 4px; }\\n.ss-g-result-detail { font-size: 13px; color: var(--ss-g-ink-2); }\\n.ss-g-result .ss-g-btn { margin-top: 6px; }\\n\\n/* launcher */\\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\\n.ss-w-fab-mark { width: 30px; height: 30px; display: block; object-fit: contain; }\\n.ss-w-greeting { max-width: 240px; display: flex; align-items: flex-start; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\\n.ss-w-greeting-body { position: relative; flex: 1; min-width: 0; text-align: left; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 9px 4px 9px 12px; }\\n.ss-w-greeting-x { flex: none; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 17px; line-height: 1; padding: 7px 9px 0 2px; }\\n.ss-w-greeting-text { display: block; }\\n/* Typing indicator: overlays the text area so bubble height stays put; hidden at\\n rest, revealed only during the one-shot intro (see prefers-reduced-motion block). */\\n.ss-w-greeting-dots { position: absolute; top: 0; bottom: 0; left: 12px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; }\\n.ss-w-greeting-dots i { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-faint); display: block; }\\n/* One-shot launcher attention intro: FAB nudges, then the greeting types in.\\n Gated behind no-preference so reduce-motion users get the greeting shown\\n statically (text visible, no nudge, no typing). ChatFab adds .ss-w-intro once\\n per page load; every animation runs a single time and settles at rest. */\\n@media (prefers-reduced-motion: no-preference) {\\n .ss-w-intro .ss-w-fab { animation: ss-w-nudge .8s ease both; }\\n .ss-w-intro .ss-w-greeting { animation: ss-w-greet-in .45s cubic-bezier(.2,.8,.3,1.15) .8s both; }\\n .ss-w-intro .ss-w-greeting-text { animation: ss-w-greet-textin .4s ease 1.65s both; }\\n .ss-w-intro .ss-w-greeting-dots { animation: ss-w-greet-dots .95s ease .85s both; }\\n .ss-w-intro .ss-w-greeting-dots i { animation: ss-w-greet-dotbounce .5s ease .85s 2; }\\n .ss-w-intro .ss-w-greeting-dots i:nth-child(2) { animation-delay: 1s; }\\n .ss-w-intro .ss-w-greeting-dots i:nth-child(3) { animation-delay: 1.15s; }\\n}\\n@keyframes ss-w-nudge {\\n 0%, 100% { transform: none; }\\n 22% { transform: translateY(-9px) rotate(-9deg); }\\n 44% { transform: translateY(0) rotate(7deg); }\\n 64% { transform: translateY(-4px) rotate(-4deg); }\\n 82% { transform: rotate(2deg); }\\n}\\n@keyframes ss-w-greet-in {\\n from { opacity: 0; transform: translateY(8px) scale(.92); }\\n to { opacity: 1; transform: none; }\\n}\\n@keyframes ss-w-greet-textin { from { opacity: 0; } to { opacity: 1; } }\\n@keyframes ss-w-greet-dots { 0% { opacity: 0; } 14% { opacity: 1; } 78% { opacity: 1; } 100% { opacity: 0; } }\\n@keyframes ss-w-greet-dotbounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }\\n\\n/* panel */\\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(460px, calc(100vw - 40px)); height: min(640px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-panel { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-panel { left: var(--ss-w-offset-x); }\\n@media (max-width: 639px) {\\n /* Fill via inset with no explicit height (like the site's working panel) so the\\n input stays visible when the mobile keyboard/URL-bar shrinks the viewport. The\\n position-specific selectors override the right/left offsets set above. */\\n .ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-panel,\\n .ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-panel { inset: 0; width: auto; height: auto; border: none; border-radius: 0; }\\n}\\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-header-mark { width: 18px; height: 18px; display: block; object-fit: contain; }\\n.ss-w-header-title { font-weight: 660; flex: 1; }\\n.ss-w-close { background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\\n.ss-w-menu-wrap { position: relative; display: grid; place-items: center; }\\n.ss-w-kebab { background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\\n.ss-w-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 5; min-width: 184px; padding: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,.18); }\\n.ss-w-menu-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 10px; background: none; border: none; border-radius: 8px; color: var(--ss-w-ink); font: inherit; font-size: 13px; text-align: left; cursor: pointer; }\\n.ss-w-menu-item:hover, .ss-w-menu-item:focus-visible { background: var(--ss-w-bubble); }\\n.ss-w-menu-item svg { color: var(--ss-w-faint); font-size: 15px; flex: none; }\\n\\n/* messages */\\n/* .ss-w-mon-list (Matches/Odds tab scrollers) shares .ss-w-list's box/scroll rules by design --\\n same visual rhythm as the chat message list -- but gets its own class so it isn't the same DOM\\n landmark as the chat list when both exist in the panel at once (Task 16 fix round, M4). */\\n/* Children of this scrolling column flex container must NOT shrink. The default flex-shrink:1\\n compresses every child to fit the panel instead of letting the container scroll, and\\n .ss-w-grp's own overflow:hidden then clips the compressed content away entirely — 27\\n competition groups rendered as blank bars on a phone. Applies to the pinned cards too. */\\n.ss-w-mon-list > * { flex: none; }\\n.ss-w-list, .ss-w-mon-list { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 14px; display: flex; flex-direction: column; gap: 12px; scroll-padding-top: 14px; }\\n/* Transient bottom spacer: reserves a viewport of room below a new turn so its\\n top can be scrolled into view while the reply is still streaming in. Height is\\n set imperatively and flex must not shrink it away. */\\n.ss-w-turn-spacer { flex: none; }\\n.ss-w-msg { display: flex; }\\n.ss-w-user { justify-content: flex-end; }\\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\\n.ss-w-bot { flex-direction: column; gap: 8px; }\\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\\n\\n/* markdown */\\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\\n.ss-w-md > *:first-child { margin-top: 0; }\\n.ss-w-md > *:last-child { margin-bottom: 0; }\\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\\n.ss-w-table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }\\n.ss-w-md-table { border-collapse: collapse; width: max-content; min-width: 100%; font-variant-numeric: tabular-nums; }\\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; white-space: nowrap; }\\n.ss-w-md-table th { background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); font-weight: 700; }\\n.ss-w-md-table tbody tr:nth-child(even) { background: var(--ss-w-bubble); }\\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\\n\\n/* entity cards */\\n.ss-w-cards { display: flex; flex-direction: column; gap: 8px; }\\n\\n/* Entity card: identity header row over a horizontal stat strip */\\n.ss-w-ecard { display: flex; flex-direction: column; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; text-align: left; }\\n\\n.ss-w-ecard-idtext { display: flex; flex-direction: column; gap: 1px; min-width: 0; max-width: 100%; }\\n.ss-w-thumb { width: 54px; height: 54px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 16px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; box-shadow: 0 1px 3px rgba(0,0,0,.14); }\\n.ss-w-thumb.ss-w-team { border-radius: 12px; }\\n.ss-w-ecard[data-kind=\\\"player\\\"] .ss-w-thumb { background-color: var(--ss-w-accent); }\\n.ss-w-nm { font-weight: 680; line-height: 1.15; overflow-wrap: anywhere; }\\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n\\n/* bare card (no stat scopes): simple avatar + name row */\\n.ss-w-ecard-bare { display: flex; align-items: center; }\\n.ss-w-ecard-bare .ss-w-ecard-hd { padding: 10px 12px; }\\n\\n.ss-w-ecard-hd { display: flex; align-items: center; gap: 11px; padding: 11px 13px; }\\n.ss-w-ecard-hd .ss-w-thumb { width: 40px; height: 40px; font-size: 13px; box-shadow: none; }\\n.ss-w-ecard-hd .ss-w-thumb.ss-w-team { border-radius: 10px; }\\n.ss-w-ecard-meta { display: inline-flex; align-items: center; gap: 7px; flex: none; align-self: flex-start; margin-left: auto; }\\n.ss-w-ecard-meta .ss-w-ecard-season { margin: 0; }\\n\\n/* scope tabs: reuse the underline pattern, relocated above the strip */\\n.ss-w-ecard-scopes { display: flex; align-items: stretch; gap: 2px; padding: 0 11px; border-top: 1px solid var(--ss-w-line); flex-wrap: wrap; }\\n.ss-w-ecard-scope { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 7px 8px; margin-bottom: -1px; border-bottom: 2px solid transparent; }\\n.ss-w-ecard-scope[aria-selected=\\\"true\\\"] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }\\n.ss-w-ecard-scope .ss-w-ecard-crest { width: 14px; height: 14px; }\\n.ss-w-ecard-scopes + .ss-w-ecard-strip { border-top: none; }\\n\\n.ss-w-ecard-crest { width: 15px; height: 15px; flex: none; display: block; border-radius: 4px; background-size: cover; background-position: center; }\\n.ss-w-ecard-season { flex: none; margin-left: auto; align-self: center; margin-bottom: 5px; font-size: 10.5px; 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: 3px 9px; white-space: nowrap; }\\n\\n/* stat strip: 1px gap over a line-colored ground paints hairlines between cells, wrap-safe */\\n.ss-w-ecard-strip { display: grid; gap: 1px; background: var(--ss-w-line); border-top: 1px solid var(--ss-w-line); }\\n.ss-w-ecard-cell { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 4px; padding: 10px 4px 11px; background: var(--ss-w-panel); }\\n.ss-w-ecard-cval { height: 20px; display: flex; align-items: center; font-size: 17px; font-weight: 720; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }\\n.ss-w-ecard-cval .ss-w-form { width: 42px; }\\n.ss-w-ecard-clabel { font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); font-weight: 600; font-variant-numeric: tabular-nums; }\\n\\n.ss-w-form { justify-self: end; display: flex; height: 6px; width: 48px; border-radius: 4px; overflow: hidden; gap: 2px; }\\n.ss-w-form span { display: block; border-radius: 2px; }\\n.ss-w-form-w { background: var(--ss-w-pos); }\\n.ss-w-form-d { background: var(--ss-w-faint); }\\n.ss-w-form-l { background: var(--ss-w-neg); }\\n\\n.ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }\\n.ss-w-cards-more:hover:not(:disabled) { text-decoration: underline; }\\n.ss-w-cards-more:disabled { opacity: .5; cursor: default; }\\n\\n/* betting insights */\\n.ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 8px; }\\n\\n/* header, competition-hero fallback: comp on the left, live badge + kickoff + pin on the right,\\n all on one line (used when there is no fixture, and by MarketOddsCardList) */\\n.ss-w-bi-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-bi-header-left { display: inline-flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); }\\n.ss-w-bi-header-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }\\n/* two-tier header: a quiet meta line (competition + kickoff + match pin) stacked above the\\n fixture, so long club names get the whole width to themselves and stop truncating (u350) */\\n.ss-w-bi-head { display: flex; flex-direction: column; gap: 6px; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-bi-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }\\n.ss-w-bi-meta-left { display: inline-flex; align-items: center; gap: 5px; min-width: 0; flex: 1; }\\n.ss-w-bi-meta-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }\\n.ss-w-bi-fixture-line { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-bi-comp { font-size: 10.5px; color: var(--ss-w-faint); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-bi-kick { font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; flex: none; }\\n.ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; gap: 4px; flex: none; }\\n.ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }\\n.ss-w-bi-floor { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; align-self: flex-start; flex: none; }\\n\\n/* crests -- CSS background-image on a span, never <img> (matches .ss-w-ecard-crest precedent) */\\n.ss-w-bi-comp-logo { width: 16px; height: 16px; flex: none; display: block; border-radius: 50%; object-fit: contain; }\\n.ss-w-bi-crest { width: 24px; height: 24px; flex: none; display: block; border-radius: 50%; object-fit: contain; }\\n.ss-w-bi-crest-mono { display: grid; place-items: center; font-size: 10px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }\\n\\n/* fixture atoms -- crest-flanked team pair; shared by the insight fixture line and MarketOddsCardList */\\n.ss-w-bi-team { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-bi-vs { font-size: 10px; font-weight: 600; color: var(--ss-w-faint); flex: none; }\\n.ss-w-bi-fixture-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n/* shared crest-flanked team row (MarketOddsCardList); matches .ss-w-bi-fixture-line's hero weight\\n so the fixture reads the same on both card types (u350) */\\n.ss-w-bi-fixture { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n\\n/* row 2, two-tier: the market label owns a full-width line above the pick row (selection grows\\n left, odds + slip + pin sit right), so neither the market name nor the fixture clips (u350) */\\n.ss-w-bi-action { display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.25; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-bi-pick-row { display: flex; align-items: center; gap: 9px; }\\n.ss-w-bi-sel { flex: 1; min-width: 0; font-size: 13px; font-weight: 700; line-height: 1.2; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-bi-odds { flex: none; margin-left: auto; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }\\n.ss-w-bi-odds b { font-size: 20px; font-family: ui-monospace, monospace; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.05; }\\n.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }\\n.ss-w-bi-pick-row .ss-w-slip { flex: none; }\\n\\n/* row 3: bar-chart glyph + reasoning prose + stats-expander chevron, in a subtle strip */\\n.ss-w-bi-reason { display: flex; align-items: flex-start; gap: 8px; background: var(--ss-w-bubble); border-radius: 10px; padding: 8px 10px; }\\n.ss-w-bi-chart { flex: none; width: 13px; height: 12px; margin-top: 2px; opacity: .55;\\n background:\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) left / 3px 55% no-repeat,\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) center / 3px 100% no-repeat,\\n linear-gradient(var(--ss-w-accent), var(--ss-w-accent)) right / 3px 75% no-repeat;\\n background-position: left bottom, center bottom, right bottom;\\n}\\n.ss-w-bi-reason-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; flex: 1; }\\n.ss-w-bi-text { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); }\\n.ss-w-bi-text-clamp { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\\n.ss-w-bi-expand { flex: none; align-self: center; display: grid; place-items: center; width: 22px; height: 22px; margin: -2px -4px -2px 0; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; }\\n.ss-w-bi-expand:hover { color: var(--ss-w-ink); }\\n.ss-w-bi-arrow { width: 7px; height: 7px; border-right: 1.6px solid currentColor; border-top: 1.6px solid currentColor; transform: rotate(45deg); transition: transform .15s ease; }\\n.ss-w-bi-arrow-open { transform: rotate(135deg); }\\n.ss-w-bi-rows { display: flex; flex-direction: column; }\\n.ss-w-bi-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-bi-row:first-child { border-top: none; }\\n.ss-w-bi-row-lbl { font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 13px; flex: none; color: var(--ss-w-ink); }\\n.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\\n.ss-w-bi-scoped { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-bi-scopes { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }\\n.ss-w-bi-chip { font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 10px; color: var(--ss-w-faint); background: none; cursor: pointer; }\\n.ss-w-bi-chip[aria-pressed=\\\"true\\\"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }\\n\\n/* market odds card */\\n.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-mocard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }\\n/* Embedded inside the market accordion, which already provides the card frame + accent rail --\\n drop the inner frame so odds rows aren't double-bordered. */\\n.ss-w-mocard--bare { border: none; border-radius: 0; padding: 0; background: none; }\\n.ss-w-mo-sub { display: flex; flex-direction: column; gap: 5px; min-width: 0; }\\n.ss-w-mo-teams { font-size: 13px; font-weight: 650; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mo-market-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }\\n.ss-w-mo-market { font-size: 11.5px; font-weight: 600; color: var(--ss-w-faint); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mo-more { align-self: flex-start; display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11.5px; font-weight: 600; padding: 2px 0; cursor: pointer; }\\n.ss-w-mo-more:hover { text-decoration: underline; }\\n.ss-w-mo-more-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }\\n.ss-w-mo-more-chev-up { transform: translateY(1px) rotate(-135deg); }\\n.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }\\n.ss-w-mo-row:last-child { border-bottom: none; }\\n.ss-w-mo-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); flex: 1; min-width: 0; }\\n.ss-w-mo-price { margin-left: auto; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; color: var(--ss-w-accent); }\\n/* Movement: BOTH directions share --ss-w-faint on purpose. Green-good/red-bad would frame a\\n shortening price as a discount, which inverts what it actually means for the bettor. */\\n.ss-w-move { display: inline-flex; align-items: baseline; gap: 4px; color: var(--ss-w-faint); }\\n.ss-w-move-prev { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 12px; text-decoration: line-through; }\\n.ss-w-move-arrow { font-size: 9px; line-height: 1; }\\n/* margin-left:auto is row layout, not badge styling -- it belongs to the market-odds row, which is\\n a flex row, and must NOT follow the badge into the insight card's odds column. */\\n.ss-w-mo-row .ss-w-move { margin-left: auto; }\\n.ss-w-mo-row .ss-w-move + .ss-w-mo-price { margin-left: 0; }\\n.ss-w-mo-row .ss-w-slip { margin: 0; flex: none; }\\n.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }\\n\\n/* odds movement card */\\n.ss-w-omcards { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-omcard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-om-head { display: flex; align-items: center; gap: 8px; }\\n.ss-w-om-market { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-om-tag { margin-left: auto; flex: none; font-size: 9px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); border-radius: 8px; padding: 2px 7px; }\\n.ss-w-om-fixture { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }\\n.ss-w-om-comp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-om-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }\\n.ss-w-om-chart { display: block; width: 100%; height: auto; }\\n/* Single neutral accent in BOTH directions, deliberately. Colouring a shortening price green\\n frames it as a discount, which inverts what it means for the bettor -- the same reason\\n .ss-w-move keeps both directions on --ss-w-faint. */\\n.ss-w-om-line { stroke: var(--ss-w-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }\\n.ss-w-om-dot { fill: var(--ss-w-accent); }\\n.ss-w-om-grid { stroke: var(--ss-w-line); stroke-width: 1; }\\n.ss-w-om-ylab, .ss-w-om-xlab { fill: var(--ss-w-faint); font-size: 9px; font-family: ui-monospace, monospace; }\\n.ss-w-om-empty { font-size: 11.5px; color: var(--ss-w-faint); padding: 6px 0; }\\n.ss-w-om-foot { display: flex; align-items: center; gap: 14px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-om-foot b { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ss-w-ink); }\\n.ss-w-om-excl { font-size: 10.5px; color: var(--ss-w-faint); }\\n.ss-w-om-susp { font-size: 11px; font-weight: 600; color: #c0392b; }\\n.ss-w-om-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }\\n\\n/* action buttons */\\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\\n/* text-align is explicit because a <button> defaults to center, and a follow-up question long\\n enough to wrap then sets its second line ragged on both sides. */\\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; text-align: left; }\\n.ss-w-abtn:disabled { opacity: .5; cursor: default; }\\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\\n\\n/* intent chips */\\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\\n\\n/* input */\\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\\n.ss-w-textarea:disabled { opacity: .55; cursor: not-allowed; }\\n/* iOS Safari zooms the page when a focused field's font-size is < 16px. Bump it\\n on touch devices only, so the desktop 13px design is unchanged. */\\n@media (pointer: coarse) {\\n .ss-w-textarea { font-size: 16px; }\\n}\\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\\n\\n/* add to slip */\\n.ss-w-slip { position: relative; display: flex; }\\n.ss-w-slip-btn { font-size: 11.5px; font-weight: 620; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border: 1px solid var(--ss-w-cta); border-radius: 14px; padding: 5px 12px; cursor: pointer; white-space: nowrap; }\\n.ss-w-slip-btn:disabled { opacity: .6; cursor: default; background: var(--ss-w-bubble); color: var(--ss-w-faint); border-color: var(--ss-w-line); }\\n/* Anchored to the RIGHT of its (narrow) button wrapper and sized by content, growing leftward\\n into the card -- inheriting the wrapper's width squeezes the text to one character per line.\\n Every toast site (slip buttons, pin toggles) sits at the right edge of its row. */\\n.ss-w-toast { position: absolute; top: calc(100% + 6px); right: 0; z-index: 1; width: max-content; max-width: 210px; font-size: 11px; font-weight: 560; border-radius: 10px; padding: 5px 10px; overflow-wrap: anywhere; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\\n.ss-w-toast-success { color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); }\\n.ss-w-toast-error { color: #c0392b; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); }\\n\\n/* pin affordance */\\n.ss-w-pin-wrap { position: relative; display: inline-flex; flex: none; }\\n.ss-w-pin { flex: none; display: grid; place-items: center; width: 22px; height: 22px; padding: 0; border-radius: 50%; background: none; border: 1px solid var(--ss-w-line); color: var(--ss-w-faint); cursor: pointer; }\\n.ss-w-pin svg { width: 12px; height: 12px; }\\n.ss-w-pin:hover { color: var(--ss-w-ink); border-color: var(--ss-w-faint); }\\n.ss-w-pin[data-on] { background: var(--ss-w-accent); border-color: var(--ss-w-accent); color: #fff; }\\n.ss-w-pin[data-on]:hover { background: var(--ss-w-accent); color: #fff; }\\n\\n@media (prefers-reduced-motion: reduce) {\\n .ss-w-abtn-shimmer { animation: none; }\\n}\\n\\n/* greeting dashboard */\\n.ss-w-dash { display: flex; flex-direction: column; gap: 12px; padding: 4px 0; }\\n.ss-w-dash-head { display: flex; flex-direction: column; }\\n.ss-w-dash-title { font-size: 18px; font-weight: 700; line-height: 1.25; color: var(--ss-w-ink); }\\n.ss-w-dash-subtitle { font-size: 13px; color: var(--ss-w-faint); margin-top: 4px; }\\n.ss-w-dash-foot { font-size: 11px; color: var(--ss-w-faint); margin-top: 2px; }\\n\\n.ss-w-dash-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-dash-tile--half { grid-column: span 1; }\\n.ss-w-dash-tile--full { grid-column: 1 / -1; }\\n\\n.ss-w-dash-tile {\\n display: flex; align-items: center; gap: 10px;\\n padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);\\n background: var(--ss-w-panel); text-align: left; cursor: pointer; width: 100%;\\n color: inherit; font: inherit;\\n min-width: 0; /* the panel is min(400px, 100vw - 40px): without this,\\n a long Turkish title blows the column out */\\n}\\n.ss-w-dash-tile-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px; font-size: 22px; }\\n.ss-w-dash-emoji { line-height: 1; }\\n.ss-w-dash-tile-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; flex: 1; }\\n.ss-w-dash-tile-title { min-width: 0; font-weight: 600; font-size: 14px; overflow-wrap: anywhere; }\\n.ss-w-dash-tile-subtitle { min-width: 0; font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-dash-tile-chevron { flex: none; margin-left: auto; width: 14px; height: 14px; color: var(--ss-w-faint); }\\n\\n/* Badge + crests share their own row, below the title -- NOT the icon/chevron row. A\\n nowrap badge (~70px) sitting beside icon+chevron in a ~180px half-span tile left the\\n title column at ~22px wide, wrapping every title character-by-character. Here the row\\n gets the body's full width, so a badge this size is comfortably inside it. */\\n.ss-w-dash-tile-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }\\n.ss-w-dash-tile-badge { flex: none; font-size: 10.5px; 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: 3px 9px; white-space: nowrap; }\\n\\n.ss-w-dash-tile-crests { flex: none; display: flex; align-items: center; }\\n.ss-w-dash-tile-crest {\\n width: 18px; height: 18px; border-radius: 50%;\\n background-size: cover; background-position: center; background-color: var(--ss-w-bubble);\\n margin-left: -6px; border: 2px solid var(--ss-w-panel); /* overlapping stack, capped at 3 in DashboardTile */\\n}\\n.ss-w-dash-tile-crest:first-child { margin-left: 0; }\\n\\n/* Market: default 2-column grid, tiles get the same accent rail as the other card\\n families (.ss-w-binsight, .ss-w-mocard, .ss-w-omcard) so a market tile reads as\\n part of that visual language rather than a plain unstyled button. */\\n.ss-w-dash--market .ss-w-dash-tile { border-left: 3px solid var(--ss-w-accent); }\\n\\n/* Goal: one column of pill rows. */\\n.ss-w-dash--goal .ss-w-dash-grid { grid-template-columns: 1fr; }\\n.ss-w-dash--goal .ss-w-dash-tile { border-radius: 999px; padding: 10px 14px; }\\n\\n/* Discovery: tinted bento cards. Stacked (icon over text) so a two- or three-word title gets\\n the tile's full width instead of the ~100px left of a horizontal icon+chevron -- that narrow\\n column was wrapping \\\"Most interesting angles\\\" onto three lines. The chevron is dropped (the\\n whole card is the tap target) and the badge + crest row is forced onto one line. */\\n.ss-w-dash--discovery .ss-w-dash-tile { flex-direction: column; align-items: stretch; gap: 8px; }\\n.ss-w-dash--discovery .ss-w-dash-tile-icon { align-self: flex-start; width: 32px; height: 32px; font-size: 26px; }\\n.ss-w-dash--discovery .ss-w-dash-tile-chevron { display: none; }\\n/* The full-span trends tile has the whole panel width, so its icon and title sit on one row\\n (horizontal, centre-aligned) rather than stacking like the narrow half tiles. */\\n.ss-w-dash--discovery .ss-w-dash-tile--full { flex-direction: row; align-items: center; }\\n.ss-w-dash--discovery .ss-w-dash-tile--full .ss-w-dash-tile-icon { align-self: center; }\\n.ss-w-dash--discovery .ss-w-dash-tile-meta { flex-wrap: nowrap; }\\n.ss-w-dash--discovery .ss-w-dash-tile-crest { width: 22px; height: 22px; }\\n/* Tints mix a hue into the live panel rather than hardcoding a light pastel, so a dark\\n operator surface (e.g. --ss-w-panel set from a navy `surface` brand color) yields a\\n readable tinted-dark card instead of near-white ink on a fixed light pastel. */\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(1) { background: color-mix(in srgb, #34c759 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: color-mix(in srgb, #3a82f6 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: color-mix(in srgb, #f5a623 10%, var(--ss-w-panel)); }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: color-mix(in srgb, #a855f7 10%, var(--ss-w-panel)); }\\n\\n/* club fan pre-match dashboard */\\n.ss-w-fandash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }\\n.ss-w-fandash-greeting { font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ss-w-ink); }\\n.ss-w-fandash-greeting--lead { font-weight: 400; }\\n.ss-w-fandash-cards { display: flex; flex-direction: column; gap: 8px; }\\n\\n/* Shared card chrome -- a plain <div> for [data] cards, a <button> for [prefill] cards. Both\\n share the same box so the two families read as one system, not two ad hoc layouts. */\\n.ss-w-fandash-card {\\n display: flex; flex-direction: column; gap: 8px;\\n padding: 12px; border-radius: 14px; border: 1px solid var(--ss-w-line);\\n background: var(--ss-w-panel); text-align: left;\\n color: inherit; font: inherit; width: 100%; min-width: 0;\\n}\\n.ss-w-fandash-card--tap { cursor: pointer; border-left: 3px solid var(--ss-w-accent); }\\n.ss-w-fandash-card--tap:hover { background: var(--ss-w-bubble); }\\n.ss-w-fandash-card-cta { align-self: flex-start; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); }\\n\\n/* Shared alignment primitives: a small letterspaced section eyebrow, and a 3-column value/label\\n split reused by the fixture head-to-head (and any future stat-row card). */\\n.ss-w-fandash-eyebrow { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); }\\n.ss-w-fandash-split { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-split-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; min-width: 0; }\\n.ss-w-fandash-split-value { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); line-height: 1; }\\n.ss-w-fandash-split-label { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n\\n/* fixture card */\\n.ss-w-fandash-fixture-teams { display: flex; align-items: center; gap: 10px; }\\n.ss-w-fandash-fixture-team { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }\\n.ss-w-fandash-fixture-team--away { justify-content: flex-end; }\\n.ss-w-fandash-fixture-team .ss-w-bi-crest { width: 30px; height: 30px; }\\n.ss-w-fandash-fixture-team .ss-w-bi-crest-mono { font-size: 12px; }\\n.ss-w-fandash-fixture-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }\\n.ss-w-fandash-fixture-team--away .ss-w-fandash-fixture-name { text-align: right; }\\n.ss-w-fandash-fixture-vs { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }\\n/* date + venue as labelled rows, so a long stadium name gets its own line to ellipsis in */\\n.ss-w-fandash-fixture-meta { border-top: 1px solid var(--ss-w-line); padding-top: 10px; text-align: center; font-size: 12.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-fixture-kickoff { font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-fandash-fixture-venue { font-weight: 600; }\\n.ss-w-fandash-fact { font-size: 12px; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 8px; }\\n/* each head-to-head figure sits on its own shaded tile, so the grid gap separates wins/draws/losses */\\n.ss-w-fandash-h2h .ss-w-fandash-split-cell { background: var(--ss-w-bubble); border-radius: 10px; padding: 12px 6px; }\\n/* extra breathing room between the tally row and the fact beyond the card's own gap */\\n.ss-w-fandash-h2h .ss-w-fandash-fact { margin-top: 4px; }\\n\\n/* Team form: a two-column result-card grid, left = home team's last 5, right = away team's last 5,\\n most-recent first. The head row carries each column's crest + name; the rows grid is filled\\n home-cell/away-cell per index so the 2-col grid lays out pairs without extra JS bookkeeping. */\\n.ss-w-fandash-teamform-head { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; }\\n.ss-w-fandash-teamform-head-team { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 11.5px; font-weight: 750; }\\n.ss-w-fandash-teamform-head-team .ss-w-bi-crest { width: 18px; height: 18px; }\\n.ss-w-fandash-teamform-head-team .ss-w-bi-crest-mono { font-size: 8px; }\\n.ss-w-fandash-teamform-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-teamform-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 6px; }\\n.ss-w-fandash-teamform-slot { display: block; min-width: 0; }\\n.ss-w-fandash-teamform-cell {\\n display: flex; align-items: center; gap: 4px; border-radius: 7px; padding: 4px 5px; color: #fff;\\n}\\n.ss-w-fandash-teamform-cell--win { background: var(--ss-w-pos); }\\n.ss-w-fandash-teamform-cell--loss { background: var(--ss-w-neg); }\\n.ss-w-fandash-teamform-cell--draw { background: var(--ss-w-faint); }\\n.ss-w-fandash-teamform-cell .ss-w-bi-crest { width: 16px; height: 16px; flex: none; background: rgba(255, 255, 255, .22); }\\n.ss-w-fandash-teamform-cell .ss-w-bi-crest-mono { font-size: 7px; color: #fff; }\\n.ss-w-fandash-teamform-score { flex: 1; text-align: center; font-size: 12.5px; font-weight: 750; font-variant-numeric: tabular-nums; }\\n.ss-w-fandash-injuries-more { margin-top: 10px; width: 100%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 7px; font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); cursor: pointer; }\\n.ss-w-fandash-injuries-more:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }\\n.ss-w-fandash-form { display: inline-flex; gap: 3px; flex: none; }\\n.ss-w-fandash-form-pill {\\n display: inline-grid; place-items: center; width: 16px; height: 16px;\\n border-radius: 4px; font-size: 9.5px; font-weight: 700; color: #fff;\\n}\\n.ss-w-fandash-form-pill--win { background: var(--ss-w-pos); }\\n.ss-w-fandash-form-pill--loss { background: var(--ss-w-neg); }\\n.ss-w-fandash-form-pill--draw { background: var(--ss-w-faint); }\\n\\n/* countdown card: a compact top card -- section eyebrow left, colon-separated clock right. Each\\n segment stacks its figure over a small unit label (d/h/m/s). The exact kickoff date is not\\n repeated here; the fixture card below carries it. */\\n.ss-w-fandash-countdown-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-countdown-clock { display: inline-flex; align-items: flex-start; gap: 6px; color: var(--ss-w-accent); }\\n.ss-w-fandash-countdown-seg { display: inline-flex; flex-direction: column; align-items: center; }\\n.ss-w-fandash-countdown-value { font-size: 26px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.01em; }\\n.ss-w-fandash-countdown-unit { font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--ss-w-faint); margin-top: 3px; }\\n.ss-w-fandash-countdown-colon { font-size: 22px; font-weight: 750; line-height: 1; color: var(--ss-w-faint); }\\n\\n/* injuries + transfers: two-column ours/theirs, in/out */\\n.ss-w-fandash-transfers-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }\\n/* injuries: a 1px divider column sits between the two team sections, each headed by crest + name */\\n.ss-w-fandash-injuries-cols { display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr); gap: 12px; }\\n.ss-w-fandash-injuries-divider { background: var(--ss-w-line); }\\n.ss-w-fandash-injuries-col, .ss-w-fandash-transfers-col { min-width: 0; display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-fandash-transfers-col-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }\\n.ss-w-fandash-injuries-col-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-fandash-injuries-col-head .ss-w-bi-crest { width: 18px; height: 18px; }\\n.ss-w-fandash-injuries-col-head .ss-w-bi-crest-mono { font-size: 9px; }\\n.ss-w-fandash-injuries-col-head-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-injuries-empty, .ss-w-fandash-transfers-empty { font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-injury-list, .ss-w-fandash-transfer-list { list-style: none; display: flex; flex-direction: column; gap: 5px; }\\n.ss-w-fandash-injury-row, .ss-w-fandash-transfer-row { display: flex; flex-direction: column; gap: 1px; }\\n.ss-w-fandash-injury-name, .ss-w-fandash-transfer-name { font-size: 12px; font-weight: 600; overflow-wrap: anywhere; }\\n.ss-w-fandash-injury-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 10.5px; color: var(--ss-w-faint); }\\n.ss-w-fandash-injury-status { font-weight: 700; color: var(--ss-w-neg); }\\n.ss-w-fandash-transfer-club { font-size: 11px; color: var(--ss-w-faint); }\\n.ss-w-fandash-transfer-type { align-self: flex-start; font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 1px 7px; margin-top: 2px; }\\n\\n/* reason-to-bet */\\n.ss-w-fandash-reason-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-reason-item { font-size: 12.5px; padding-left: 14px; position: relative; }\\n.ss-w-fandash-reason-item::before { content: \\\"•\\\"; position: absolute; left: 0; color: var(--ss-w-accent); font-weight: 700; }\\n\\n/* where-to-watch */\\n.ss-w-fandash-stations { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-w-fandash-station-chip { font-size: 11.5px; font-weight: 600; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 999px; padding: 4px 10px; }\\n\\n/* congested week: a fixed 3-column grid of upcoming fixtures (day / opponent / comp / time) */\\n.ss-w-fandash-congested-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-congested-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 8px; border-radius: 10px; background: var(--ss-w-bubble); }\\n.ss-w-fandash-congested-day { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ss-w-faint); }\\n.ss-w-fandash-congested-opponent { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }\\n.ss-w-fandash-congested-comp { font-size: 10px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-fandash-congested-time { font-size: 10.5px; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }\\n\\n/* links: 2-column grid of tappable tiles */\\n.ss-w-fandash-link-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }\\n.ss-w-fandash-link-tile { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 11px 13px; border-radius: 10px; border: 1px solid transparent; text-decoration: none; color: inherit; background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); }\\n.ss-w-fandash-link-tile:hover { background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }\\n.ss-w-fandash-link-label { font-size: 12.5px; font-weight: 650; overflow-wrap: anywhere; }\\n.ss-w-fandash-link-chevron { flex: none; width: 12px; height: 12px; color: var(--ss-w-accent); }\\n\\n/* post-match result: full-time scoreboard, mirroring the live card's crest + big-score treatment.\\n A neutral \\\"Full time\\\" pill sits left of a coloured Win/Draw/Loss tag; the 3-column main row\\n (home crest+name | score | away crest+name, away reversed) puts the winner's score in full ink\\n and the loser's dimmed; a centered meta line sits under a divider. */\\n.ss-w-fandash-postmatch-top { display: flex; align-items: center; gap: 8px; margin-bottom: 15px; }\\n.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; }\\n.ss-w-fandash-postmatch-tag { margin-left: auto; flex: none; font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; }\\n.ss-w-fandash-postmatch-tag--win { color: var(--ss-w-pos); }\\n.ss-w-fandash-postmatch-tag--loss { color: var(--ss-w-neg); }\\n.ss-w-fandash-postmatch-tag--draw { color: var(--ss-w-faint); }\\n.ss-w-fandash-postmatch-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-fandash-postmatch-side { display: flex; align-items: center; gap: 10px; min-width: 0; }\\n.ss-w-fandash-postmatch-side--away { flex-direction: row-reverse; text-align: right; }\\n.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); }\\n.ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--home { background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-crest--fallback.ss-w-fandash-postmatch-crest--away { background: var(--ss-w-away); }\\n.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); }\\n.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; }\\n.ss-w-fandash-postmatch-score-value--win { color: var(--ss-w-ink); }\\n.ss-w-fandash-postmatch-score-value--lose { color: var(--ss-w-faint); }\\n.ss-w-fandash-postmatch-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 5px; }\\n.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; }\\n\\n/* post-match goals: a football-ball icon per goal (mirrors the live timeline ball, duplicated here\\n under the postmatch prefix), text dimmed for opponent goals and picked out in full ink + bold\\n for the club's own goals */\\n.ss-w-fandash-postmatch-goal-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-postmatch-goal { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--ss-w-faint); }\\n.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); }\\n.ss-w-fandash-postmatch-goal--club { color: var(--ss-w-ink); font-weight: 650; }\\n\\n/* post-match stats: home value / stat label / away value, oriented by venue (u316), each row now\\n backed by a home/away split bar -- the big upgrade from plain text -- plus a legend. Mirrors\\n LiveStatsCard's split-bar treatment under the postmatch-prefixed classes; the shared\\n --ss-w-home/--ss-w-away/--ss-w-track tokens are defined above. */\\n.ss-w-fandash-postmatch-stat-rows { display: flex; flex-direction: column; gap: 15px; }\\n.ss-w-fandash-postmatch-stat { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-fandash-postmatch-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-fandash-postmatch-stat-value { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-postmatch-stat-value--home { color: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-stat-value--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-fandash-postmatch-stat-label { font-size: 10.5px; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }\\n.ss-w-fandash-postmatch-stat-bar { position: relative; height: 8px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-fandash-postmatch-stat-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-stat-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n.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); }\\n.ss-w-fandash-postmatch-legend-item { display: inline-flex; align-items: center; gap: 6px; }\\n.ss-w-fandash-postmatch-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }\\n.ss-w-fandash-postmatch-legend-swatch--home { background: var(--ss-w-home); }\\n.ss-w-fandash-postmatch-legend-swatch--away { background: var(--ss-w-away); }\\n\\n/* post-match top performer (full mockup treatment): gradient initials avatar + name + a\\n prominent rating chip. Avatar gradient reuses the --ss-w-away token, same pairing as the live\\n crest fallback; \\\"?\\\" renders through the same avatar span when the name is blank. */\\n.ss-w-fandash-postmatch-perf-row { display: flex; align-items: center; gap: 12px; }\\n.ss-w-fandash-postmatch-perf-avatar {\\n flex: none; width: 42px; height: 42px; border-radius: 50%;\\n display: grid; place-items: center;\\n font-size: 14px; font-weight: 800; color: #fff;\\n background: linear-gradient(135deg, var(--ss-w-away), color-mix(in srgb, var(--ss-w-away) 55%, #000));\\n}\\n.ss-w-fandash-postmatch-perf-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 700; }\\n.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; }\\n\\n/* post-match next (v1, modest): whenLabel is already a complete localized phrase (opponent +\\n venue + kickoff) composed server-side, so this card renders just that one line -- dressed up\\n with an accent rule rather than a duplicated opponent line. The richer opponent-headline/venue-\\n chip/crest layout from the mockup needs a server field split and is deferred. */\\n.ss-w-fandash-postmatch-next-row { display: flex; align-items: center; gap: 10px; border-left: 3px solid var(--ss-w-accent); padding-left: 10px; }\\n.ss-w-fandash-postmatch-next-when { font-size: 13.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.3; }\\n\\n/* resting next: the between-matches fixture teaser -- when-label left, competition badge right */\\n.ss-w-fandash-resting-next-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-resting-next-when { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 650; }\\n.ss-w-fandash-resting-next-competition { flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ss-w-faint); }\\n\\n/* resting standings: position figure left, W-D-L/points record right */\\n.ss-w-fandash-resting-standings-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }\\n.ss-w-fandash-resting-standings-position { font-size: 15px; font-weight: 750; color: var(--ss-w-ink); }\\n.ss-w-fandash-resting-standings-record { font-size: 11.5px; color: var(--ss-w-faint); text-align: right; }\\n\\n/* resting season: top scorer / key player / season tally as stacked rows */\\n.ss-w-fandash-resting-season-rows { display: flex; flex-direction: column; gap: 4px; }\\n.ss-w-fandash-resting-season-row { font-size: 12.5px; color: var(--ss-w-ink); }\\n\\n/* resting form: reuses the fixture last-five pill classes (ss-w-fandash-form / -form-pill) */\\n.ss-w-fandash-resting-form .ss-w-fandash-form { margin-top: 2px; }\\n\\n/* live score: pulsing Live pill, crests (real image or a coloured initials fallback), a big\\n tabular score, and an optional scorers line. Also where the shared home/away venue-colour\\n tokens (--ss-w-home / --ss-w-away / --ss-w-track) are defined above -- the timeline and stats\\n cards reuse them. */\\n.ss-w-fandash-live-top { display: flex; align-items: center; gap: 8px; }\\n.ss-w-fandash-live-pill { display: inline-flex; flex: none; align-items: center; gap: 5px; font-size: 10.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: #fff; background: var(--ss-w-neg); border-radius: 6px; padding: 3px 8px; }\\n.ss-w-fandash-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; animation: ss-w-fandash-live-pulse 1.3s ease-in-out infinite; }\\n@keyframes ss-w-fandash-live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }\\n@media (prefers-reduced-motion: reduce) {\\n .ss-w-fandash-live-dot { animation: none; }\\n}\\n.ss-w-fandash-live-minute { flex: none; font-size: 13.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-competition { margin-left: auto; font-size: 11px; font-weight: 650; color: var(--ss-w-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-fandash-live-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-fandash-live-side { display: flex; align-items: center; gap: 10px; min-width: 0; }\\n.ss-w-fandash-live-side--away { flex-direction: row-reverse; text-align: right; }\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--home { background: var(--ss-w-home); }\\n.ss-w-fandash-live-crest--fallback.ss-w-fandash-live-crest--away { background: var(--ss-w-away); }\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-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; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-score-sep { color: var(--ss-w-faint); font-weight: 500; margin: 0 5px; }\\n.ss-w-fandash-live-scorers { margin-top: 12px; display: flex; justify-content: flex-end; gap: 7px; align-items: center; font-size: 12.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\n.ss-w-fandash-live-scorers-icon { flex: none; color: var(--ss-w-away); }\\n\\n/* live timeline: a compact two-sided event list down a centre spine -- each club's events sit on\\n its own side (home left, away right), most-recent 3 shown with a \\\"See more\\\" toggle for the\\n rest. A 3-column grid (txt | badge | txt) per row; the spine itself is a ::before on the list. */\\n.ss-w-fandash-live-tl { position: relative; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-fandash-live-tl::before { content: \\\"\\\"; position: absolute; left: 50%; top: 1px; bottom: 1px; width: 2px; background: var(--ss-w-line); transform: translateX(-1px); }\\n.ss-w-fandash-live-tl-ev { display: grid; grid-template-columns: 1fr 32px 1fr; align-items: center; gap: 6px; }\\n.ss-w-fandash-live-tl-txt { display: flex; align-items: center; gap: 7px; font-size: 13px; min-width: 0; }\\n.ss-w-fandash-live-tl-ev--home .ss-w-fandash-live-tl-txt { grid-column: 1; justify-content: flex-end; }\\n.ss-w-fandash-live-tl-ev--away .ss-w-fandash-live-tl-txt { grid-column: 3; justify-content: flex-start; flex-direction: row-reverse; }\\n.ss-w-fandash-live-tl-who { font-weight: 650; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-w-fandash-live-tl-off { font-weight: 500; color: var(--ss-w-faint); }\\n.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-who { font-weight: 800; }\\n.ss-w-fandash-live-tl-badge { grid-column: 2; justify-self: center; min-width: 29px; height: 19px; padding: 0 4px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 800; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); font-variant-numeric: tabular-nums; z-index: 1; }\\n.ss-w-fandash-live-tl-ev--goal .ss-w-fandash-live-tl-badge { background: var(--ss-w-accent); color: #fff; border-color: transparent; }\\n.ss-w-fandash-live-tl-ico { width: 17px; height: 17px; flex: none; display: grid; place-items: center; }\\n.ss-w-fandash-live-tl-ico--goal { border-radius: 50%; background: color-mix(in srgb, var(--ss-w-away) 16%, transparent); }\\n.ss-w-fandash-live-tl-ball { width: 12px; height: 12px; 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); }\\n.ss-w-fandash-live-tl-card { width: 9px; height: 12px; border-radius: 2px; display: block; }\\n.ss-w-fandash-live-tl-card--yellow { background: var(--ss-w-cta); }\\n.ss-w-fandash-live-tl-card--red { background: var(--ss-w-away); }\\n.ss-w-fandash-live-tl-subarrows { font-size: 11px; font-weight: 900; line-height: 1; letter-spacing: -1px; color: var(--ss-w-accent); }\\n.ss-w-fandash-live-tl-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ss-w-faint); }\\n.ss-w-fandash-live-tl-more { margin-top: 4px; width: 100%; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 7px; font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ss-w-accent); cursor: pointer; }\\n.ss-w-fandash-live-tl-more:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }\\n\\n/* live stats: club value / stat label / opponent value, each row backed by a home/away split\\n bar, plus an optional momentum wave (or its text fallback) and a club/opponent colour legend.\\n No side signal reaches this card, so the club is always the home token and the opponent is\\n always the away token -- see LiveStatsCard.tsx. */\\n.ss-w-fandash-live-stat-rows { display: flex; flex-direction: column; gap: 15px; }\\n.ss-w-fandash-live-stat { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-fandash-live-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-fandash-live-stat-value { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-fandash-live-stat-value--home { color: var(--ss-w-home); }\\n.ss-w-fandash-live-stat-value--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-fandash-live-stat-label { font-size: 10.5px; font-weight: 700; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .04em; }\\n.ss-w-fandash-live-bar { position: relative; height: 8px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-fandash-live-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-fandash-live-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n\\n.ss-w-fandash-live-momentum { font-size: 11.5px; font-weight: 650; color: var(--ss-w-accent); }\\n.ss-w-fandash-live-mom { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-fandash-live-mom-caption { display: block; margin-bottom: 5px; font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); }\\n.ss-w-fandash-live-mom-svg { width: 100%; height: 56px; display: block; overflow: visible; }\\n.ss-w-fandash-live-mom-home { fill: var(--ss-w-home); fill-opacity: .85; }\\n.ss-w-fandash-live-mom-away { fill: var(--ss-w-away); fill-opacity: .85; }\\n.ss-w-fandash-live-mom-line { fill: none; stroke: color-mix(in srgb, var(--ss-w-ink) 55%, transparent); stroke-width: 1.5; }\\n.ss-w-fandash-live-mom-base { stroke: var(--ss-w-line); stroke-width: 1; stroke-dasharray: 3 3; }\\n.ss-w-fandash-live-mom-plot { position: relative; }\\n.ss-w-fandash-live-mom-now {\\n position: absolute; width: 7px; height: 7px; border-radius: 50%;\\n transform: translate(-50%, -50%);\\n background: var(--ss-w-panel); border: 1.5px solid var(--ss-w-ink);\\n pointer-events: none;\\n}\\n.ss-w-mon-mom { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--ss-w-line); text-align: center; }\\n.ss-w-mon-mom .ss-w-fandash-live-mom { margin-top: 6px; padding-top: 0; border-top: none; }\\n\\n.ss-w-fandash-live-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); }\\n.ss-w-fandash-live-legend-item { display: inline-flex; align-items: center; gap: 6px; }\\n.ss-w-fandash-live-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }\\n.ss-w-fandash-live-legend-swatch--home { background: var(--ss-w-home); }\\n.ss-w-fandash-live-legend-swatch--away { background: var(--ss-w-away); }\\n\\n/* live monitor tab bar: underline pattern mirrors .ss-w-ecard-scope; the unread dot uses --ss-w-neg */\\n.ss-w-tabs { display: flex; align-items: stretch; gap: 2px; border-bottom: 1px solid var(--ss-w-line); overflow-x: auto; scrollbar-width: none; }\\n.ss-w-tabs::-webkit-scrollbar { display: none; }\\n.ss-w-tab { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 9px 12px; margin-bottom: -1px; border-bottom: 2px solid transparent; flex: none; white-space: nowrap; }\\n.ss-w-tab[data-on] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }\\n.ss-w-tab-count { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 999px; padding: 1px 6px; }\\n.ss-w-tab[data-on] .ss-w-tab-count { color: var(--ss-w-accent); }\\n.ss-w-tab-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }\\n\\n/* Matches tab match card (MonitorMatchCard): pill row, crest/score main row, per-stat split\\n bars (venue-oriented -- home always left/blue, away always right/red, never club-oriented,\\n the u316 bug class), a promoted-market strip for the user's pinned stat chips, and a grace\\n note once the match has gone full time. Reuses the --ss-w-home/--ss-w-away/--ss-w-track venue\\n tokens and .ss-w-fandash-live-pill for the Live pill so all live surfaces share one look. */\\n.ss-w-mon { display: flex; flex-direction: column; gap: 10px; padding: 12px; border: 1px solid var(--ss-w-line); border-radius: 12px; background: var(--ss-w-panel); }\\n.ss-w-mon-top { display: flex; align-items: center; gap: 8px; }\\n.ss-w-mon-pill { display: inline-flex; flex: none; align-items: center; font-size: 10.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 6px; padding: 3px 8px; }\\n.ss-w-mon-min { flex: none; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-mon-comp { margin-left: auto; font-size: 11px; font-weight: 650; color: var(--ss-w-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-mon-main { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; }\\n.ss-w-mon-side { display: flex; align-items: center; gap: 8px; min-width: 0; }\\n.ss-w-mon-side--away { flex-direction: row-reverse; text-align: right; }\\n/* long club names (Wolverhampton Wanderers) wrap to two lines instead of truncating mid-word */\\n.ss-w-mon-name { min-width: 0; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.2; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }\\n.ss-w-mon-vs { font-size: 12px; font-weight: 700; color: var(--ss-w-faint); text-transform: uppercase; }\\n.ss-w-mon-score { display: flex; align-items: baseline; justify-content: center; font-size: 26px; font-weight: 850; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; color: var(--ss-w-ink); }\\n.ss-w-mon-score i { font-style: normal; color: var(--ss-w-faint); font-weight: 500; margin: 0 4px; }\\n.ss-w-mon-scorers { display: grid; grid-template-columns: 1fr auto 1fr; align-items: start; column-gap: 10px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mon-scorers-col { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\\n.ss-w-mon-scorers-col li { overflow-wrap: anywhere; }\\n.ss-w-mon-scorers-home { text-align: right; }\\n.ss-w-mon-scorers-away { text-align: left; }\\n.ss-w-mon-scorers-ball { flex: none; align-self: start; line-height: 1.35; }\\n.ss-w-mon-stats { display: flex; flex-direction: column; gap: 10px; }\\n.ss-w-mon-stat { display: flex; flex-direction: column; gap: 5px; }\\n.ss-w-mon-pstrip { padding: 6px 8px; border-radius: 8px; background: color-mix(in srgb, var(--ss-w-accent) 8%, transparent); }\\n.ss-w-mon-stat-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 8px; }\\n.ss-w-mon-stat-v { font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-mon-stat-v--home { color: var(--ss-w-home); }\\n.ss-w-mon-stat-v--away { color: var(--ss-w-away); text-align: right; }\\n.ss-w-mon-stat-l { font-size: 10px; font-weight: 700; text-align: center; color: var(--ss-w-faint); text-transform: uppercase; letter-spacing: .03em; }\\n.ss-w-mon-bar { position: relative; height: 6px; border-radius: 999px; background: var(--ss-w-track); overflow: hidden; display: flex; }\\n.ss-w-mon-bar-home { height: 100%; background: var(--ss-w-home); }\\n.ss-w-mon-bar-away { height: 100%; background: var(--ss-w-away); margin-left: auto; }\\n.ss-w-mon-stat-mkt { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mon-mkt { background: color-mix(in srgb, var(--ss-w-accent) 10%, transparent); border-radius: 6px; padding: 3px 6px; color: var(--ss-w-ink); }\\n.ss-w-mon-stat-mkt-right { display: flex; align-items: center; gap: 6px; margin-left: auto; }\\n.ss-w-mon-price { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 700; color: var(--ss-w-accent); }\\n.ss-w-mon-susp { font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-bubble); border-radius: 6px; padding: 2px 6px; }\\n.ss-w-mon-asof { display: block; font-size: 10.5px; font-weight: 600; color: var(--ss-w-cta); }\\n.ss-w-mon-grace { font-size: 11px; color: var(--ss-w-faint); border-top: 1px solid var(--ss-w-line); padding-top: 8px; }\\n\\n/* Matches/Odds tab panels (MonitorTabs): the shared per-market-pin context line, the empty\\n state shown when the snapshot carries no matches/markets yet, the persistent D5 in-slip badge,\\n and the per-market-pin wrapper card (struck price on settlement is a pure CSS hook off its\\n [data-settled] attribute -- no separate class on the price element itself). */\\n.ss-w-mk-ctx { display: flex; align-items: center; gap: 6px; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--ss-w-line); }\\n/* the score and the trailing badges/pin never shrink or wrap -- only the fixture name truncates */\\n.ss-w-mk-ctx b { flex: none; white-space: nowrap; }\\n/* the context line's fixture name stays single-line (the two-line clamp is for the match card) */\\n.ss-w-mk-ctx .ss-w-mon-name { display: block; white-space: nowrap; text-overflow: ellipsis; }\\n.ss-w-mk-ctx-side { display: flex; align-items: center; gap: 6px; min-width: 0; }\\n.ss-w-mk-ctx-right { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }\\n/* flex:1 keeps the composer pinned to the panel bottom when a tab is empty */\\n.ss-w-mon-empty { flex: 1; padding: 24px 16px; text-align: center; font-size: 12.5px; color: var(--ss-w-faint); }\\n/* Per-pin unavailable state: the pin's context line still rendered above (score, name, unpin), but\\n the pin has neither a card nor history (compose-time rescue failed) -- a small inline note beats\\n a bare context line with nothing under it. */\\n.ss-w-mon-empty-card { padding: 8px 0 2px; font-size: 12px; color: var(--ss-w-faint); }\\n.ss-w-mon-inslip { display: inline-flex; flex: none; align-items: center; gap: 3px; font-size: 10.5px; font-weight: 700; color: var(--ss-w-pos); }\\n/* Odds-tab item is bare: the visible card is the market-odds card itself (no outer wrapper card),\\n with an optional slim live strip above it. */\\n.ss-w-mon-oddspin { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-mk-live { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 0 2px; font-size: 11.5px; color: var(--ss-w-faint); }\\n.ss-w-mk-live-score { color: var(--ss-w-ink); font-weight: 700; font-variant-numeric: tabular-nums; }\\n.ss-w-mon-oddspin[data-settled] .ss-w-mo-price,\\n.ss-w-mon-oddspin[data-settled] .ss-w-mon-price { text-decoration: line-through; color: var(--ss-w-faint); }\\n\\n/* market accordion (Task 9): one collapsed row per available market, expanding into a reused\\n MarketOddsCardList ladder (hideHeader -- the row header already carries the market label). */\\n/* Pinned-match tile: the match card + its odds accordion, spaced apart. */\\n.ss-w-mon-item { display: flex; flex-direction: column; gap: 10px; }\\n.ss-w-acc { display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-acc-row { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); overflow: hidden; }\\n/* Row header: expand toggle (flex:1) + the market PinToggle as a sibling (no nested buttons). */\\n.ss-w-acc-head { display: flex; align-items: center; gap: 8px; padding: 6px 9px 6px 11px; }\\n.ss-w-acc-toggle { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; background: none; border: none; cursor: pointer; text-align: left; font: inherit; color: var(--ss-w-ink); padding: 5px 0; }\\n/* Suspended: the row stays listed (knowing a market is off is useful) but is not tappable --\\n its card is unservable, so a pointer cursor would promise something that cannot load. */\\n.ss-w-acc-toggle--susp { cursor: default; color: var(--ss-w-faint); }\\n.ss-w-acc-chevron { color: var(--ss-w-faint); font-size: 11px; flex: none; }\\n.ss-w-acc-label { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-acc-badge { font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); flex: none; }\\n.ss-w-acc-susp { margin-left: auto; font-size: 10.5px; color: var(--ss-w-faint); flex: none; }\\n.ss-w-acc-panel { padding: 0 11px 10px; display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-acc-insight { font-size: 12px; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 7px 9px; }\\n.ss-w-acc-retry { font-size: 12px; color: var(--ss-w-neg); cursor: pointer; padding: 6px 0; }\\n\\n/* ---- Today tab (u355) ---- */\\n.ss-w-sec-head { display: flex; align-items: center; gap: 7px; padding: 2px 2px 0; font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); }\\n.ss-w-sec-head::after { content: \\\"\\\"; flex: 1; height: 1px; background: var(--ss-w-line); }\\n.ss-w-sec-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ss-w-neg); flex: none; }\\n.ss-w-today-live { display: flex; flex-direction: column; gap: 2px; }\\n\\n.ss-w-grp { border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; }\\n.ss-w-grp-head { display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 11px; background: var(--ss-w-bubble); border: none; font: inherit; color: var(--ss-w-ink); cursor: pointer; text-align: left; }\\n.ss-w-grp-head:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: -2px; }\\n.ss-w-grp-chev { color: var(--ss-w-faint); font-size: 10px; flex: none; }\\n.ss-w-grp-name { font-size: 12px; font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-grp-country { font-weight: 600; color: var(--ss-w-faint); }\\n.ss-w-grp-count { margin-left: auto; flex: none; font-size: 10.5px; font-weight: 700; color: var(--ss-w-faint); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 999px; padding: 1px 7px; font-variant-numeric: tabular-nums; }\\n.ss-w-grp-body { display: flex; flex-direction: column; padding: 2px 11px 6px; }\\n\\n.ss-w-drow { display: grid; grid-template-columns: 42px minmax(0,1fr) 22px; align-items: center; gap: 9px; padding: 7px 0; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-drow:last-child { border-bottom: none; }\\n.ss-w-drow-when { font-size: 11px; font-weight: 700; color: var(--ss-w-faint); font-variant-numeric: tabular-nums; }\\n.ss-w-drow-when--live { color: var(--ss-w-neg); }\\n/* Each side ellipsises independently: a single joined string truncates the away team off the end,\\n which is the u350 betting-card truncation one layer down. */\\n.ss-w-drow-fx { display: flex; align-items: center; gap: 6px; min-width: 0; }\\n.ss-w-drow-side { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1 1 0; }\\n/* Away side mirrors home around the score: crest to the far edge, name aligned inward. */\\n.ss-w-drow-side--away { flex-direction: row-reverse; text-align: right; }\\n.ss-w-drow-nm { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n/* Centre slot of .ss-w-drow-fx, between the two sides: flex:none so a widening score never\\n steals width the team names need to avoid ellipsis. min-width holds the slot at the width of a\\n one-digit scoreline so an unscored row's bare dash does not pull the column out of line -- the\\n scores read as a column down the list, not a jitter. */\\n.ss-w-drow-sc { flex: none; min-width: 26px; text-align: center; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-drow-sc--idle { color: var(--ss-w-faint); font-weight: 600; }\\n.ss-w-drow--live { background: color-mix(in srgb, var(--ss-w-neg) 5%, transparent); border-radius: 8px; padding: 7px 6px; margin: 0 -6px; border-bottom: none; }\\n.ss-w-drow-crest { width: 16px; height: 16px; flex: none; border-radius: 50%; object-fit: contain; background: var(--ss-w-bubble); }\\n\\n.ss-w-stale { font-size: 11px; font-weight: 600; color: var(--ss-w-cta); background: color-mix(in srgb, var(--ss-w-cta) 12%, var(--ss-w-panel)); border-radius: 8px; padding: 6px 9px; }\\n\\n/* Prize banner: CTA-tinted card with icon + body column (label + chips) — still used by\\n LeaderboardEmpty.tsx's weekly-prize callout. */\\n.ss-w-prize { display: flex; align-items: flex-start; gap: 10px; padding: 11px 13px; border-radius: 12px; background: color-mix(in srgb, var(--ss-w-cta) 10%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-cta) 22%, var(--ss-w-line)); }\\n.ss-w-prize-icon { flex: none; font-size: 20px; line-height: 1; padding-top: 1px; }\\n.ss-w-prize-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }\\n.ss-w-prize-text { font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); line-height: 1.35; overflow-wrap: anywhere; }\\n\\n/* ── games hub (u393) ── */\\n.ss-g-hub-wrap { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; background: var(--ss-g-ground); font-family: var(--ss-g-font-body); color: var(--ss-g-ink); }\\n.ss-g-hub { display: flex; flex-direction: column; gap: 14px; padding: 14px 16px 20px; }\\n.ss-g-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-g-stat { display: flex; flex-direction: column; gap: 2px; padding: 9px 12px; border-radius: 12px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); min-width: 0; }\\n.ss-g-stat-l { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-stat-v { display: flex; align-items: baseline; gap: 4px; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 24px; line-height: 1; white-space: nowrap; }\\n.ss-g-stat-v svg { color: var(--ss-g-flame); align-self: center; }\\n.ss-g-stat-v small { font-family: var(--ss-g-font-body); font-size: 12px; font-weight: 600; color: var(--ss-g-muted); overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-stat-v--accent { color: var(--ss-w-accent); }\\n.ss-g-prize { align-self: flex-start; }\\n.ss-g-tile { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 10px; min-width: 0; border-radius: 14px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); color: var(--ss-g-ink); text-align: left; font: inherit; cursor: pointer; }\\n.ss-g-tile:not([data-disabled]):hover { border-color: var(--ss-g-line-warm); }\\n.ss-g-tile[data-disabled] { opacity: .55; cursor: default; }\\n.ss-g-tile--tile { height: 148px; }\\n.ss-g-tile-art { height: 74px; border-radius: 10px; background: var(--ss-g-raised); display: flex; align-items: center; justify-content: center; margin-bottom: 4px; }\\n.ss-g-art { width: 100%; height: 100%; }\\n.ss-g-art-fg { fill: var(--ss-g-strong-line); }\\n.ss-g-art-accent { fill: var(--ss-w-accent); }\\n.ss-g-art-accent-stroke { fill: none; stroke: var(--ss-w-accent); stroke-width: 2; }\\n.ss-g-art-dot { fill: var(--ss-g-pitch-mark); }\\n.ss-g-art-pitch { fill: var(--ss-g-pitch); stroke: var(--ss-g-pitch-line); }\\n.ss-g-art-block { fill: var(--ss-g-line); }\\n.ss-g-art-correct { fill: var(--ss-g-correct); }\\n.ss-g-art-dash { fill: none; stroke: var(--ss-g-strong-line); stroke-dasharray: 3 2; stroke-width: 1.5; }\\n.ss-g-art-line { stroke: var(--ss-g-line-warm); stroke-width: 2; }\\n.ss-g-art-ink { fill: none; stroke: var(--ss-g-on-accent); stroke-width: 2; }\\n.ss-g-art-q { fill: var(--ss-w-accent); font: 800 20px var(--ss-g-font-display); }\\n.ss-g-tile-title { font-size: 15px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-tile-status { font-size: 12px; color: var(--ss-g-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-tile-status[data-tone=\\\"accent\\\"] { color: var(--ss-w-accent); font-weight: 600; }\\n.ss-g-tile-status[data-tone=\\\"success\\\"] { color: var(--ss-g-success); font-weight: 700; }\\n.ss-g-tile--hero { flex-direction: row; min-height: 184px; padding: 0; overflow: hidden; border-radius: 18px; background: var(--ss-g-warm); border-color: var(--ss-g-line-warm); }\\n.ss-g-hero-text { flex: 0 0 60%; display: flex; flex-direction: column; justify-content: center; gap: 6px; padding: 18px; min-width: 0; }\\n.ss-g-hero-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--ss-w-accent); }\\n.ss-g-hero-title { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 34px; line-height: .95; text-transform: uppercase; overflow-wrap: anywhere; }\\n.ss-g-hero-sub { font-size: 14px; color: var(--ss-g-ink-2); }\\n.ss-g-hero-cta { align-self: flex-start; margin-top: 6px; padding: 9px 16px; border-radius: 999px; background: var(--ss-w-accent); color: var(--ss-g-on-accent); font-size: 14px; font-weight: 700; }\\n.ss-g-hero-art { flex: 1; display: flex; align-items: center; justify-content: center; background: repeating-linear-gradient(-58deg, var(--ss-g-accent-tint) 0 14px, var(--ss-g-warm) 14px 32px); }\\n.ss-g-sec { display: flex; flex-direction: column; gap: 10px; }\\n.ss-g-sec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-top: 6px; }\\n.ss-g-sec-head h3 { font-family: var(--ss-g-font-display); font-weight: 700; font-size: 18px; letter-spacing: .06em; text-transform: uppercase; }\\n.ss-g-sec-head span { font-size: 12px; color: var(--ss-g-muted); white-space: nowrap; }\\n.ss-g-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }\\n.ss-g-tile--wide { flex-direction: row; align-items: center; gap: 14px; min-height: 104px; }\\n.ss-g-wide-art { width: 84px; height: 84px; flex: none; border-radius: 10px; background: var(--ss-g-raised); }\\n.ss-g-wide-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }\\n.ss-g-wide-chev { color: var(--ss-g-muted); transform: rotate(180deg); display: flex; }\\n\\n/* ── Mystery Tiger (u393) ── */\\n.ss-g-mt-card { flex: none; border-radius: 18px; background: var(--ss-g-warm); border: 1px solid var(--ss-g-line-warm); overflow: hidden; display: flex; flex-direction: column; }\\n.ss-g-mt-portrait { position: relative; height: 178px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; background: repeating-linear-gradient(-58deg, var(--ss-g-accent-tint) 0 16px, var(--ss-g-warm) 16px 36px); }\\n.ss-g-mt-portrait .ss-g-sil { font-size: 46px; }\\n.ss-g-mt-photo { width: 132px; height: 132px; margin-bottom: 30px; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--ss-g-accent-tint); color: var(--ss-w-accent); font: 800 40px var(--ss-g-font-display); }\\n.ss-g-mt-photo img { width: 100%; height: 100%; object-fit: cover; }\\n.ss-g-mt-reveal-name { position: absolute; bottom: 6px; left: 12px; right: 12px; text-align: center; font: 800 20px var(--ss-g-font-display); text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-mt-known { display: grid; gap: 6px; padding: 12px; }\\n.ss-g-mt-known-cell { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }\\n.ss-g-mt-lab { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-mt-known-v { width: 100%; height: 38px; border-radius: 8px; display: grid; place-items: center; font: 700 16px var(--ss-g-font-display); background: var(--ss-g-raised); color: var(--ss-g-muted); white-space: nowrap; }\\n.ss-g-mt-known-v[data-state=\\\"known\\\"] { background: var(--ss-g-correct); color: var(--ss-g-on-correct); font-size: 18px; }\\n.ss-g-mt-known-v[data-state=\\\"range\\\"] { border: 1px dashed var(--ss-g-strong-line); }\\n.ss-g-mt-table { display: flex; flex-direction: column; gap: 8px; }\\n.ss-g-mt-thead, .ss-g-mt-row { display: grid; gap: 5px; align-items: center; }\\n.ss-g-mt-thead { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-mt-thead span:not(:first-child) { text-align: center; }\\n.ss-g-mt-who { display: flex; align-items: center; gap: 8px; min-width: 0; }\\n.ss-g-mt-av { width: 38px; height: 38px; flex: none; border-radius: 50%; display: grid; place-items: center; background: var(--ss-g-raised); color: var(--ss-g-muted); font-size: 12px; font-weight: 700; overflow: hidden; }\\n.ss-g-mt-names { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }\\n.ss-g-mt-first { font-size: 11px; color: var(--ss-g-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-mt-last { font-size: 14px; font-weight: 700; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-mt-cell { height: 42px; border-radius: 8px; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1; font: 700 16px var(--ss-g-font-display); background: var(--ss-g-raised); border: 1px solid var(--ss-g-line); color: var(--ss-g-ink); overflow: hidden; }\\n.ss-g-mt-cell[data-verdict=\\\"exact\\\"] { background: var(--ss-g-correct); border-color: transparent; color: var(--ss-g-on-correct); }\\n.ss-g-mt-cell[data-verdict=\\\"near\\\"] { background: var(--ss-g-close); border-color: transparent; color: var(--ss-g-on-accent); }\\n.ss-g-mt-cell-dir { font-size: 10px; margin-top: 2px; }\\n.ss-g-mt-legend { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-mt-legend span { display: inline-flex; align-items: center; gap: 6px; }\\n.ss-g-mt-sw { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }\\n.ss-g-mt-sw[data-verdict=\\\"exact\\\"] { background: var(--ss-g-correct); }\\n.ss-g-mt-sw[data-verdict=\\\"near\\\"] { background: var(--ss-g-close); }\\n.ss-g-mt-hint { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border-radius: 14px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); font-size: 13px; color: var(--ss-g-ink-2); }\\n.ss-g-mt-hint svg { color: var(--ss-w-accent); flex: none; margin-top: 1px; }\\n\\n/* ── Higher or Lower (u393) ── */\\n.ss-g-hl-prompt { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; }\\n.ss-g-hl-prompt-q { font-size: 13px; color: var(--ss-g-muted); }\\n.ss-g-hl-prompt-stat { font: 800 30px var(--ss-g-font-display); text-transform: uppercase; letter-spacing: .02em; line-height: 1.05; }\\n.ss-g-hl-prompt-season { font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-hl-pair { display: flex; flex-direction: column; gap: 12px; }\\n.ss-g-hl-card { display: flex; min-height: 196px; border-radius: 18px; overflow: hidden; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); }\\n.ss-g-hl-card--b { border-color: var(--ss-g-line-warm); }\\n.ss-g-hl-photo-wrap { width: 40%; max-width: 170px; flex: none; display: flex; align-items: flex-end; justify-content: center; background: var(--ss-g-raised); overflow: hidden; }\\n.ss-g-hl-photo-wrap .ss-g-sil { border-radius: 0; background: transparent; }\\n.ss-g-hl-photo { width: 100%; height: 100%; display: grid; place-items: center; color: var(--ss-g-muted); font: 800 36px var(--ss-g-font-display); }\\n.ss-g-hl-photo img { width: 100%; height: 100%; object-fit: cover; object-position: top; }\\n.ss-g-hl-info { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 2px; padding: 16px; }\\n.ss-g-hl-first { font-size: 13px; color: var(--ss-g-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-hl-surname { font: 800 30px var(--ss-g-font-display); text-transform: uppercase; line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-hl-value { font: 800 76px var(--ss-g-font-display); line-height: 1; color: var(--ss-w-accent); margin-top: 10px; }\\n.ss-g-hl-stat { font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-hl-btns { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }\\n.ss-g-hl-btns .ss-g-btn { font-weight: 800; font-size: 15px; letter-spacing: .06em; text-transform: uppercase; }\\n.ss-g-hl-vs { position: relative; z-index: 1; align-self: center; width: 48px; height: 48px; margin: -30px 0; border-radius: 50%; display: grid; place-items: center; background: var(--ss-g-ground); border: 2px solid var(--ss-g-line-warm); color: var(--ss-w-accent); font: 800 18px var(--ss-g-font-display); }\\n/* Clear the VS badge that straddles the seam between the two cards. */\\n.ss-g-hl-pair > .ss-g-hl-card:first-child .ss-g-hl-info { padding-bottom: 30px; }\\n.ss-g-hl-vs + .ss-g-hl-card .ss-g-hl-info { padding-top: 30px; }\\n.ss-g-hl-feedback { display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--ss-g-ink-2); }\\n.ss-g-hl-feedback[data-correct=\\\"true\\\"] svg { color: var(--ss-g-success); }\\n.ss-g-hl-feedback[data-correct=\\\"false\\\"] svg { color: var(--ss-g-wrong-mark); }\\n.ss-g-hl-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\\n.ss-g-hl-dots { display: flex; gap: 5px; }\\n.ss-g-hl-dot { width: 22px; height: 22px; border-radius: 50%; border: 1.5px dashed var(--ss-g-strong-line); }\\n.ss-g-hl-dot[data-state=\\\"correct\\\"] { background: var(--ss-g-correct); border: 0; }\\n.ss-g-hl-dot[data-state=\\\"wrong\\\"] { background: var(--ss-g-wrong-mark); border: 0; }\\n.ss-g-hl-pts { font: 700 22px var(--ss-g-font-display); white-space: nowrap; }\\n.ss-g-hl-pts-unit { font-size: 13px; color: var(--ss-g-muted); }\\n\\n/* ── Guess the XI (u393) ── pitch colours are the fixed --ss-g-pitch* tokens (Task 1) */\\n.ss-g-gxi-pitch { position: relative; flex: none; height: 380px; border-radius: 18px; overflow: hidden; border: 1px solid var(--ss-g-pitch-line);\\n background: repeating-linear-gradient(180deg, color-mix(in srgb, var(--ss-g-pitch) 92%, var(--ss-g-pitch-mark)) 0 12.5%, var(--ss-g-pitch) 12.5% 25%); }\\n.ss-g-gxi-rows { position: absolute; inset: 14px 6px; display: flex; flex-direction: column; justify-content: space-between; }\\n.ss-g-gxi-row { display: flex; justify-content: space-evenly; align-items: flex-start; }\\n.ss-g-gxi-node { display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 0; max-width: 72px; }\\n.ss-g-gxi-disc { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; background: var(--ss-g-pitch-chip); border: 2px solid var(--ss-g-pitch-ink); font-size: 22px; line-height: 1; }\\n.ss-g-gxi-node[data-revealed] .ss-g-gxi-disc { border-color: var(--ss-w-accent); }\\n.ss-g-gxi-pos { max-width: 100%; padding: 1px 6px; border-radius: 4px; background: var(--ss-g-pitch-chip); color: var(--ss-g-pitch-ink); font-size: 11px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-gxi-pos--name { color: var(--ss-w-accent); text-transform: uppercase; }\\n.ss-g-gxi-wrong { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }\\n.ss-g-gxi-wrong-l { font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-gxi-wrong-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 4px 6px; border-radius: 999px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); font-size: 13px; color: var(--ss-g-muted); }\\n\\n/* ---- Daily Quiz (u393) ---- */\\n.ss-g-dq-stem { font-family: var(--ss-g-font-display); font-weight: 700; font-size: 30px; line-height: 1.05; overflow-wrap: anywhere; }\\n.ss-g-dq-opts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }\\n.ss-g-dq-opt { position: relative; min-height: 96px; padding: 44px 12px 12px; border-radius: 16px; border: 1.5px solid var(--ss-g-line); background: var(--ss-g-surface); color: var(--ss-g-ink); text-align: left; font: inherit; cursor: pointer; display: flex; align-items: flex-end; min-width: 0; }\\n.ss-g-dq-opt:hover:not(:disabled) { border-color: var(--ss-g-line-warm); }\\n.ss-g-dq-opt[aria-pressed=\\\"true\\\"] { border: 2px solid var(--ss-w-accent); background: var(--ss-g-warm); }\\n.ss-g-dq-opt:disabled { cursor: default; }\\n.ss-g-dq-badge { position: absolute; top: 10px; left: 10px; width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; background: var(--ss-g-raised); font-weight: 700; font-size: 13px; color: var(--ss-g-ink); }\\n.ss-g-dq-opt[aria-pressed=\\\"true\\\"] .ss-g-dq-badge { background: var(--ss-w-accent); color: var(--ss-g-on-accent); }\\n.ss-g-dq-opt-name { display: flex; flex-direction: column; min-width: 0; line-height: 1.05; }\\n.ss-g-dq-opt-first { font-size: 12px; color: var(--ss-g-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-dq-opt-last { font-family: var(--ss-g-font-display); font-weight: 700; font-size: 20px; text-transform: uppercase; overflow-wrap: anywhere; }\\n.ss-g-dq-opt-suffix { margin-top: 2px; font-size: 12px; font-weight: 600; color: var(--ss-g-muted); }\\n.ss-g-dq-opt-full { font-size: 15px; font-weight: 600; line-height: 1.25; overflow-wrap: anywhere; }\\n.ss-g-dq-nav { display: flex; gap: 10px; }\\n.ss-g-dq-nav .ss-g-btn--block { flex: 1; }\\n.ss-g-dq-rq { display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 14px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); }\\n.ss-g-dq-rq-stem { font-weight: 700; font-size: 14px; }\\n.ss-g-dq-rq-opts { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-g-dq-rq-opt { padding: 4px 10px; border-radius: 999px; font-size: 13px; font-weight: 600; background: var(--ss-g-raised); color: var(--ss-g-muted); }\\n.ss-g-dq-rq-opt--correct { background: var(--ss-g-correct); color: var(--ss-g-on-correct); }\\n.ss-g-dq-rq-opt--wrong { background: var(--ss-g-wrong); color: var(--ss-g-on-correct); }\\n.ss-g-dq-why { font-size: 13px; color: var(--ss-g-ink-2); }\\n\\n/* ---- Career Path (u393) ---- */\\n.ss-g-cp-card { display: flex; align-items: center; gap: 12px; padding: 12px; border-radius: 16px; background: var(--ss-g-warm); border: 1px solid var(--ss-g-line-warm); }\\n.ss-g-cp-card-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1; }\\n.ss-g-cp-card-title { font-family: var(--ss-g-font-display); font-weight: 700; font-size: 20px; text-transform: uppercase; overflow-wrap: anywhere; }\\n.ss-g-cp-hint { font-size: 13px; color: var(--ss-g-ink-2); }\\n.ss-g-cp-locks { display: flex; gap: 6px; flex-wrap: wrap; }\\n.ss-g-cp-line { list-style: none; display: flex; flex-direction: column; }\\n.ss-g-cp-step { display: flex; gap: 14px; align-items: stretch; }\\n.ss-g-cp-rail { display: flex; flex-direction: column; align-items: center; width: 52px; flex: none; }\\n.ss-g-cp-tile { width: 52px; height: 52px; border-radius: 14px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); display: grid; place-items: center; }\\n.ss-g-cp-tile--locked { border: 1.5px dashed var(--ss-g-strong-line); background: transparent; color: var(--ss-g-muted); }\\n.ss-g-cp-tile--faint { border: 1.5px dashed var(--ss-g-line); background: transparent; color: var(--ss-g-faint); }\\n.ss-g-cp-conn { width: 2px; flex: 1; min-height: 14px; background: var(--ss-g-line-warm); }\\n.ss-g-cp-conn--faint { background: var(--ss-g-line); }\\n.ss-g-cp-step:last-child .ss-g-cp-conn { display: none; }\\n.ss-g-cp-step-text { display: flex; flex-direction: column; justify-content: center; min-height: 52px; padding-bottom: 14px; min-width: 0; }\\n.ss-g-cp-club { font-weight: 700; font-size: 16px; overflow-wrap: anywhere; }\\n.ss-g-cp-sub { font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-cp-loan { color: var(--ss-w-accent); font-weight: 600; }\\n\\n/* Game screen host: fills the panel; each screen owns its header, gutters and scrolling. */\\n.ss-w-gscreen-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 0; overflow: hidden; background: var(--ss-g-ground); }\\n.ss-w-gscreen { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0; }\\n.ss-w-gscreen-body { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 16px; color: var(--ss-w-faint); font-size: 13px; text-align: center; }\\n\\n/* ---- Leaderboard (D2) ---- */\\n/* Outer shell */\\n.ss-w-lb2 { display: flex; flex-direction: column; gap: 12px; }\\n\\n/* Segmented control: This week / All time */\\n.ss-w-seg { display: inline-flex; gap: 2px; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }\\n.ss-w-seg-btn { font-size: 12px; font-weight: 600; border: none; border-radius: 7px; padding: 5px 12px; color: var(--ss-w-faint); background: none; cursor: pointer; font: inherit; white-space: nowrap; }\\n.ss-w-seg-btn[data-on] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 3px rgba(0,0,0,.09); }\\n\\n/* Row list */\\n.ss-w-lb2-rows { display: flex; flex-direction: column; border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; background: var(--ss-w-panel); }\\n.ss-w-lb2-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-lb2-row:last-child { border-bottom: none; }\\n/* Highlighted \\\"you\\\" row: full-width tint via negative margin trick, contained by border-radius above */\\n.ss-w-lb2-row--you { background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); }\\n.ss-w-lb2-rank { flex: none; min-width: 30px; font-size: 12.5px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-faint); }\\n.ss-w-lb2-rank--top3 { color: var(--ss-w-cta); }\\n.ss-w-lb2-handle { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ss-w-ink); }\\n.ss-w-lb2-points { flex: none; font-size: 13px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n.ss-w-lb2-streak { flex: none; font-size: 11px; font-weight: 700; color: var(--ss-w-accent); padding-left: 4px; }\\n\\n/* Kit-prize separator: a labelled hairline (eyebrow + two growing lines) */\\n.ss-w-kitline { display: flex; align-items: center; gap: 8px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); }\\n.ss-w-kitline::before, .ss-w-kitline::after { content: \\\"\\\"; flex: 1; height: 1px; background: var(--ss-w-line); }\\n\\n/* Off-board treatment: dashed pill indicating rank is outside top N */\\n.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; }\\n\\n/* ---- Leaderboard empty / weekly-reset default state ---- */\\n.ss-w-lb-empty { display: flex; flex-direction: column; gap: 12px; flex: 1; }\\n.ss-w-lb-empty-hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 8px; padding: 20px 16px; border: 1px dashed color-mix(in srgb, var(--ss-w-cta) 30%, var(--ss-w-line)); border-radius: 14px; background: color-mix(in srgb, var(--ss-w-cta) 6%, var(--ss-w-panel)); }\\n.ss-w-lb-empty--alltime { align-items: center; justify-content: center; text-align: center; padding: 24px 16px; }\\n.ss-w-lb-empty-icon { font-size: 30px; line-height: 1; }\\n.ss-w-lb-empty-title { margin: 2px 0 0; font-size: 16px; font-weight: 800; color: var(--ss-w-ink); }\\n.ss-w-lb-empty-body { margin: 0; max-width: 30ch; font-size: 12.5px; line-height: 1.4; color: var(--ss-w-faint); }\\n.ss-w-lb-empty-cta { margin-top: 6px; border: none; border-radius: 10px; padding: 9px 18px; font: inherit; font-size: 13px; font-weight: 700; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); cursor: pointer; }\\n.ss-w-lb-empty-cta:hover { filter: brightness(1.04); }\\n.ss-w-lb-last { display: flex; align-items: center; gap: 7px; padding-top: 10px; border-top: 1px solid var(--ss-w-line); font-size: 11px; }\\n.ss-w-lb-last-label { text-transform: uppercase; letter-spacing: .05em; font-weight: 700; color: var(--ss-w-faint); }\\n.ss-w-lb-last-handle { flex: 1; min-width: 0; font-weight: 600; color: var(--ss-w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\\n.ss-w-lb-last-points { flex: none; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--ss-w-ink); }\\n\\n/* PlayerAvatar initials fallback (PlayerAvatar.tsx) — size/colour inherit from the avatar class. */\\n.ss-w-av-initials { font-weight: 800; line-height: 1; text-transform: uppercase; letter-spacing: .02em; }\\n\\n/* ---- Beat the Grid (u393) ---- */\\n.ss-g-btg-grid { display: grid; gap: 6px; }\\n.ss-g-btg-colhdr { height: 60px; border-radius: 12px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; text-align: center; padding: 0 4px; font-size: 12px; font-weight: 700; line-height: 1.1; min-width: 0; overflow-wrap: anywhere; }\\n.ss-g-btg-colhdr svg { color: var(--ss-w-accent); flex: none; }\\n.ss-g-btg-rowhdr { border-radius: 12px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); display: grid; place-items: center; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 18px; letter-spacing: .04em; text-transform: uppercase; overflow-wrap: anywhere; text-align: center; }\\n.ss-g-btg-cell { position: relative; height: 98px; min-width: 0; border-radius: 12px; border: 1.5px dashed var(--ss-g-strong-line); background: transparent; color: var(--ss-g-muted); display: flex; flex-direction: column; align-items: center; justify-content: center; overflow: hidden; cursor: pointer; font: inherit; padding: 0; }\\n.ss-g-btg-cell:disabled { cursor: default; }\\n.ss-g-btg-cell[data-state=\\\"active\\\"] { border: 2px solid var(--ss-w-accent); background: var(--ss-g-warm); color: var(--ss-w-accent); }\\n.ss-g-btg-cell[data-state=\\\"correct\\\"], .ss-g-btg-cell[data-state=\\\"wrong\\\"] { justify-content: flex-end; background: var(--ss-g-surface); border-style: solid; }\\n.ss-g-btg-cell[data-state=\\\"correct\\\"] { border-color: var(--ss-g-correct); }\\n.ss-g-btg-cell[data-state=\\\"wrong\\\"] { border-color: var(--ss-g-wrong-mark); }\\n.ss-g-btg-badge { position: absolute; top: 6px; right: 6px; width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; color: var(--ss-g-on-correct); }\\n.ss-g-btg-badge--correct { background: var(--ss-g-correct); }\\n.ss-g-btg-badge--wrong { background: var(--ss-g-wrong); }\\n.ss-g-btg-rarity { position: absolute; top: 6px; left: 6px; padding: 1px 6px; border-radius: 999px; background: var(--ss-g-accent-tint); color: var(--ss-w-accent); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }\\n.ss-g-btg-cell[data-state=\\\"wrong\\\"] .ss-g-btg-rarity { background: var(--ss-g-raised); color: var(--ss-g-muted); }\\n.ss-g-btg-cell .ss-g-sil { border-radius: 0; background: transparent; }\\n.ss-g-btg-name { width: 100%; padding: 4px 2px; background: var(--ss-g-ground); color: var(--ss-g-ink); font-family: var(--ss-g-font-display); font-weight: 700; font-size: 14px; text-transform: uppercase; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-btg-plus { display: flex; }\\n.ss-g-btg-pin { flex: none; padding: 0 12px 12px; }\\n.ss-g-btg-sheet { padding: 14px; border-radius: 18px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line-warm); display: flex; flex-direction: column; gap: 12px; }\\n.ss-g-btg-sheet-hdr { display: flex; align-items: center; gap: 8px; min-width: 0; }\\n.ss-g-btg-sheet-hdr .ss-g-chip { padding: 4px 10px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-btg-sheet-x { color: var(--ss-g-muted); display: flex; flex: none; }\\n.ss-g-btg-sheet-close { margin-left: auto; flex: none; width: 44px; height: 44px; border: 0; border-radius: 10px; background: transparent; color: var(--ss-g-muted); display: grid; place-items: center; cursor: pointer; }\\n.ss-g-btg-sheet-close:hover { background: var(--ss-g-raised); color: var(--ss-g-ink); }\\n.ss-g-btg-sheet .ss-g-search-box { height: 48px; border-radius: 12px; background: var(--ss-g-ground); }\\n.ss-g-btg-sheet-empty { font-size: 13px; color: var(--ss-g-muted); }\\n.ss-g-btg-sheet .ss-g-opt { background: var(--ss-g-raised); }\\n.ss-g-btg-result-name { flex: 1; min-width: 0; font-weight: 700; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-btg-result-plus { color: var(--ss-w-accent); display: flex; }\\n\\n/* ── Starting XI (u393) ── */\\n.ss-g-xi-pitch { position: relative; flex: none; height: 400px; border-radius: 18px; overflow: hidden; background: repeating-linear-gradient(180deg, var(--ss-g-pitch) 0 40px, color-mix(in srgb, var(--ss-g-pitch) 88%, var(--ss-g-pitch-mark)) 40px 80px); border: 1px solid var(--ss-g-pitch-line); }\\n.ss-g-xi-slot { position: absolute; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 48px; border: 0; padding: 0; background: transparent; color: var(--ss-g-pitch-mark); font: inherit; cursor: pointer; }\\n.ss-g-xi-slot:disabled { cursor: default; }\\n.ss-g-xi-ring { width: 48px; height: 48px; box-sizing: border-box; display: grid; place-items: center; border-radius: 50%; border: 1.5px dashed var(--ss-g-pitch-mark); font-family: var(--ss-g-font-display); font-weight: 800; font-size: 20px; }\\n.ss-g-xi-slot[data-state=\\\"filled\\\"] .ss-g-xi-ring { border: 2px solid var(--ss-w-accent); background: var(--ss-g-accent-tint); color: var(--ss-g-ink); }\\n.ss-g-xi-slot[data-state=\\\"active\\\"] .ss-g-xi-ring { border: 2px solid var(--ss-w-accent); background: var(--ss-g-warm); color: var(--ss-w-accent); }\\n.ss-g-xi-tag { max-width: 72px; padding: 1px 6px; border-radius: 4px; background: var(--ss-g-ground); color: var(--ss-g-ink); font-size: 11px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-xi-slot[data-state=\\\"active\\\"] .ss-g-xi-tag { background: var(--ss-w-accent); color: var(--ss-g-on-accent); }\\n.ss-g-xi-picker { display: flex; flex-direction: column; gap: 10px; padding: 12px; border-radius: 16px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line-warm); }\\n.ss-g-xi-picker-head { display: flex; align-items: center; gap: 8px; font-size: 14px; }\\n.ss-g-xi-list { list-style: none; display: flex; flex-direction: column; gap: 4px; max-height: 240px; overflow-y: auto; }\\n.ss-g-xi-opt { width: 100%; display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 6px 10px; border: 0; border-radius: 10px; background: var(--ss-g-raised); color: var(--ss-g-ink); font: inherit; text-align: left; cursor: pointer; }\\n.ss-g-xi-opt:disabled { opacity: .5; cursor: default; }\\n.ss-g-xi-opt-no { width: 28px; flex: none; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 18px; color: var(--ss-w-accent); text-align: center; }\\n.ss-g-xi-opt-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-xi-opt-pos { flex: none; padding: 1px 6px; border-radius: 4px; background: var(--ss-g-line); color: var(--ss-g-ink-2); font-size: 10px; font-weight: 700; }\\n.ss-g-xi-lock { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-xi-lock svg { color: var(--ss-w-accent); flex: none; }\\n\\n/* ── Stat Ladder (u393) ── */\\n.ss-g-sl-prompt { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 6px 0 6px; text-align: center; }\\n.ss-g-sl-stat { padding: 4px 10px; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; }\\n.ss-g-sl-q { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 30px; line-height: 1.05; text-transform: uppercase; }\\n.ss-g-sl-q em { font-style: normal; color: var(--ss-w-accent); }\\n.ss-g-sl-rungs { list-style: none; display: flex; flex-direction: column; gap: 10px; }\\n.ss-g-sl-rung { min-height: 84px; display: flex; align-items: center; gap: 12px; padding: 0 16px 0 12px; border-radius: 16px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); }\\n.ss-g-sl-rung--mystery { min-height: 96px; border: 2px dashed var(--ss-w-accent); background: repeating-linear-gradient(-58deg, var(--ss-g-accent-tint) 0 14px, var(--ss-g-warm) 14px 32px); }\\n.ss-g-sl-rung--mystery[data-result=\\\"correct\\\"] { border: 2px solid var(--ss-g-correct); background: var(--ss-g-warm); }\\n.ss-g-sl-rung--mystery[data-result=\\\"wrong\\\"] { border: 2px solid var(--ss-g-wrong-mark); background: var(--ss-g-warm); }\\n.ss-g-sl-rank { width: 32px; height: 32px; flex: none; display: grid; place-items: center; border-radius: 10px; background: var(--ss-g-raised); color: var(--ss-g-ink-2); font-family: var(--ss-g-font-display); font-weight: 800; font-size: 18px; }\\n.ss-g-sl-rung:first-child .ss-g-sl-rank { background: var(--ss-g-accent-tint); color: var(--ss-w-accent); }\\n.ss-g-sl-rung--mystery .ss-g-sl-rank { background: var(--ss-w-accent); color: var(--ss-g-on-accent); }\\n.ss-g-sl-av { width: 52px; height: 52px; flex: none; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--ss-g-raised); color: var(--ss-g-ink-2); font-weight: 700; }\\n.ss-g-sl-av img { width: 100%; height: 100%; object-fit: cover; }\\n.ss-g-sl-name { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.1; }\\n.ss-g-sl-name small { font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-sl-name b { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 22px; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-sl-who { flex: 1; min-width: 0; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 22px; text-transform: uppercase; color: var(--ss-w-accent); }\\n.ss-g-sl-val { flex: none; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 34px; line-height: 1; }\\n.ss-g-sl-val--mystery { font-size: 40px; color: var(--ss-w-accent); }\\n.ss-g-sl-clue { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 14px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); font-size: 13px; line-height: 1.4; color: var(--ss-g-ink-2); }\\n.ss-g-sl-clue svg { flex: none; color: var(--ss-w-accent); }\\n.ss-g-sl-pool { list-style: none; display: flex; flex-direction: column; gap: 4px; }\\n.ss-g-sl-opt { width: 100%; min-height: 48px; display: flex; align-items: center; gap: 12px; padding: 6px 10px; border: 1px solid transparent; border-radius: 12px; background: var(--ss-g-raised); color: var(--ss-g-ink); font: inherit; text-align: left; cursor: pointer; }\\n.ss-g-sl-opt[aria-pressed=\\\"true\\\"] { border-color: var(--ss-w-accent); background: var(--ss-g-warm); }\\n.ss-g-sl-opt[aria-pressed=\\\"true\\\"] svg { color: var(--ss-w-accent); }\\n.ss-g-sl-opt:disabled { opacity: .5; cursor: default; }\\n.ss-g-sl-opt-av { width: 36px; height: 36px; flex: none; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--ss-g-line); color: var(--ss-g-ink-2); font-size: 12px; font-weight: 700; }\\n.ss-g-sl-opt-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-sl-guess { display: flex; align-items: flex-end; gap: 8px; }\\n.ss-g-sl-guess .ss-g-search { flex: 1; min-width: 0; }\\n.ss-g-sl-guess .ss-g-btn { min-height: 50px; padding: 0 20px; border-radius: 14px; }\\n\\n/* ── Matchday Predictor (u393) ── */\\n.ss-g-mp-card { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 16px 10px; border-radius: 18px; background: var(--ss-g-warm); border: 1px solid var(--ss-g-line-warm); }\\n.ss-g-mp-team { width: 84px; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }\\n.ss-g-mp-team .ss-g-crest--ph { color: var(--ss-g-strong-line); }\\n.ss-g-mp-team-name { max-width: 100%; font-family: var(--ss-g-font-display); font-weight: 800; font-size: 17px; line-height: 1.05; text-transform: uppercase; overflow-wrap: anywhere; }\\n.ss-g-mp-team-side { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ss-g-muted); }\\n.ss-g-mp-scores { display: flex; align-items: center; gap: 8px; }\\n.ss-g-mp-col { display: flex; flex-direction: column; align-items: center; gap: 6px; }\\n.ss-g-mp-step { width: 64px; height: 44px; display: grid; place-items: center; border-radius: 10px; border: 1px solid var(--ss-g-line-warm); background: var(--ss-g-raised); color: var(--ss-g-ink); cursor: pointer; }\\n.ss-g-mp-step:disabled { opacity: .4; cursor: default; }\\n.ss-g-mp-digit { width: 64px; height: 76px; display: grid; place-items: center; box-sizing: border-box; border-radius: 12px; background: var(--ss-g-ground); border: 2px solid var(--ss-g-strong-line); font-family: var(--ss-g-font-display); font-weight: 800; font-size: 52px; line-height: 1; }\\n.ss-g-mp-digit[data-active=\\\"true\\\"] { border-color: var(--ss-w-accent); color: var(--ss-w-accent); }\\n.ss-g-mp-dash { font-family: var(--ss-g-font-display); font-weight: 800; font-size: 30px; color: var(--ss-g-faint); }\\n.ss-g-mp-scorer { display: flex; flex-direction: column; gap: 10px; }\\n.ss-g-mp-sec-head { display: flex; align-items: baseline; justify-content: space-between; margin-top: 10px; }\\n.ss-g-mp-sec-head h3 { font-family: var(--ss-g-font-display); font-weight: 700; font-size: 18px; letter-spacing: .06em; text-transform: uppercase; }\\n.ss-g-mp-sec-head span { font-size: 12px; color: var(--ss-g-muted); }\\n.ss-g-mp-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }\\n.ss-g-mp-pcard { position: relative; min-width: 0; height: 116px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 6px; border-radius: 14px; border: 1px solid var(--ss-g-line); background: var(--ss-g-surface); color: var(--ss-g-ink); font: inherit; cursor: pointer; }\\n.ss-g-mp-pcard[aria-pressed=\\\"true\\\"] { border: 2px solid var(--ss-w-accent); background: var(--ss-g-warm); }\\n.ss-g-mp-pcard:disabled { cursor: default; opacity: .6; }\\n.ss-g-mp-pcheck { position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%; background: var(--ss-w-accent); color: var(--ss-g-on-accent); }\\n.ss-g-mp-pname { max-width: 100%; font-size: 13px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-mp-none { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 14px; border-radius: 12px; border: 1px solid var(--ss-g-line); background: transparent; color: var(--ss-g-muted); font: 600 14px var(--ss-g-font-body); cursor: pointer; text-align: left; }\\n.ss-g-mp-radio { width: 18px; height: 18px; flex: none; box-sizing: border-box; border-radius: 50%; border: 2px solid var(--ss-g-strong-line); }\\n.ss-g-mp-none[aria-pressed=\\\"true\\\"] { color: var(--ss-g-ink); border-color: var(--ss-g-line-warm); }\\n.ss-g-mp-none[aria-pressed=\\\"true\\\"] .ss-g-mp-radio { border-color: var(--ss-w-accent); background: var(--ss-w-accent); box-shadow: inset 0 0 0 3px var(--ss-g-ground); }\\n.ss-g-mp-closed { padding: 10px 14px; border-radius: 12px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); color: var(--ss-g-muted); font-size: 13px; text-align: center; }\\n.ss-g-mp-fun { font-size: 11px; color: var(--ss-g-faint); text-align: center; }\\n.ss-g-mp-rows { list-style: none; display: flex; flex-direction: column; gap: 6px; }\\n.ss-g-mp-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 48px; padding: 0 14px; border-radius: 12px; background: var(--ss-g-surface); border: 1px solid var(--ss-g-line); font-size: 14px; }\\n.ss-g-mp-row-k { color: var(--ss-g-ink-2); }\\n.ss-g-mp-row-v { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; color: var(--ss-g-muted); }\\n.ss-g-mp-row[data-ok=\\\"true\\\"] { border-color: var(--ss-g-correct); }\\n.ss-g-mp-row[data-ok=\\\"true\\\"] .ss-g-mp-row-v { color: var(--ss-g-success); }\\n.ss-g-mp-row-d { color: var(--ss-g-ink); }\\n\\n/* ── Fan MOTM (u393) ── */\\n.ss-g-motm-list { list-style: none; display: flex; flex-direction: column; gap: 8px; }\\n.ss-g-motm-row { width: 100%; min-height: 60px; display: flex; align-items: center; gap: 12px; padding: 0 14px 0 10px; border-radius: 14px; border: 1px solid var(--ss-g-line); background: var(--ss-g-surface); color: var(--ss-g-ink); font: inherit; text-align: left; cursor: pointer; }\\n.ss-g-motm-row:not(:disabled):hover { border-color: var(--ss-g-line-warm); }\\n.ss-g-motm-row:disabled { cursor: default; }\\n.ss-g-motm-row--voted { border: 1.5px solid var(--ss-w-accent); background: var(--ss-g-warm); }\\n.ss-g-motm-av { width: 40px; height: 40px; flex: none; border-radius: 50%; overflow: hidden; display: grid; place-items: center; background: var(--ss-g-raised); color: var(--ss-g-ink-2); font-size: 13px; font-weight: 700; }\\n.ss-g-motm-av img { width: 100%; height: 100%; object-fit: cover; }\\n.ss-g-motm-name { flex: 1; min-width: 0; font-size: 15px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\\n.ss-g-motm-pill { flex: none; padding: 3px 8px; font-size: 11px; }\\n.ss-g-motm-foot { font-size: 14px; font-weight: 600; }\\n.ss-g-motm-fun { font-size: 11px; color: var(--ss-g-faint); }\\n\"\n"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["useCallback","useEffect","useMemo","useRef","useState","useEffect","useReducer","useRef","WidgetSdkError","useReducer","useRef","WidgetSdkError","useEffect","useCallback","useEffect","useRef","useState","useRef","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","TTL_MS","useState","useRef","useEffect","useCallback","useMemo","useCallback","useEffect","useRef","useState","useCallback","useEffect","useRef","useState","useEffect","useRef","useState","useState","jsx","useState","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","useEffect","useState","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","jsx","useState","jsx","jsxs","useState","useCallback","useState","useEffect","jsx","jsx","jsxs","useState","useCallback","jsx","jsxs","directionWord","useState","jsx","initials","Crest","useCallback","useState","jsx","jsxs","useState","useCallback","jsx","jsxs","useState","Crest","useState","Fragment","jsx","jsxs","useState","Crest","Fragment","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","Crest","Fragment","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","Crest","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState","jsx","jsxs","initials","jsx","jsxs","jsx","jsxs","jsx","jsxs","initials","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useRef","useState","useEffect","useState","jsx","jsxs","initials","useState","useRef","useState","jsx","jsxs","SHOWN","jsx","jsxs","jsx","jsxs","splitWidths","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","useRef","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","jsx","jsxs","jsx","jsxs","Crest","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","useEffect","useState","jsx","useEffect","useState","Fragment","jsx","jsxs","jsx","jsxs","jsx","jsx","Fragment","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","useEffect","useRef","useState","useCallback","useRef","useState","isTerminal","useState","useId","useState","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","jsx","jsx","jsxs","jsx","Fragment","jsx","jsxs","useState","useId","Fragment","jsx","jsxs","parseClientState","useState","useId","useState","jsx","Fragment","jsx","jsxs","parseClientState","useState","useId","useEffect","useId","useRef","useState","Fragment","jsx","jsxs","parseClientState","useState","useId","useRef","useEffect","isLocked","useState","useId","Fragment","jsx","jsxs","Fragment","jsx","jsxs","MAX_GUESSES","parseClientState","useState","useId","useState","Fragment","jsx","jsxs","parseClientState","useState","segments","useId","useState","jsx","jsxs","parseClientState","useState","useId","useId","useState","Fragment","jsx","jsxs","parseClientState","useState","useId","useId","useState","jsx","jsxs","parseClientState","useState","useId","jsx","jsxs","parseClientState","jsx","useState","useEffect","useRef","jsx","useState","useEffect","useState","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","useState","jsx","jsx","jsxs","useState","useEffect","jsx","useMemo","useRef","useCallback","useState","useEffect"]}
|