@sensiblestats/widget-react 0.48.5 → 0.48.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.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/useMatchDiscovery.ts","../src/scheduleCache.ts","../src/dueSet.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/liveClock.ts","../src/components/CompetitionGroup.tsx","../src/components/TodayPanel.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 { 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 = discovery.groups.length > 0\n useEffect(() => { setHasToday(todayHasContent) }, [todayHasContent])\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 controller={controller} ui={ui} slip={slip} onDashboardTap={onDashboardTap} monitor={monitor.enabled ? monitor : undefined} discovery={discovery} />\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 inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: 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 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 },\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 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 },\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 inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: 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 inSlipLabel: strings.inSlipLabel,\n oddsUnavailable: strings.oddsUnavailable,\n momentumLabel: strings.momentumLabel,\n accordionValueLabel: strings.accordionValueLabel,\n accordionRetry: strings.accordionRetry,\n accordionSuspended: strings.accordionSuspended,\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'\n\nexport type MonitorTab = 'chat' | 'today' | 'following' | 'odds'\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: MonitorTab\n setActiveTab(tab: MonitorTab): 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, setActiveTabState] = useState<MonitorTab>('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: MonitorTab) => {\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 { 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 { 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 { 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 { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { TabBar } from './TabBar'\nimport { MatchesPanel, OddsPanel } from './MonitorTabs'\nimport { TodayPanel } from './TodayPanel'\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 }: {\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}): 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?.groups.length ?? 0) > 0}\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 <ChatInput placeholder={ui.placeholder} streaming={state.isStreaming} onSend={handleSend} onStop={stop} stopLabel={ui.stopResponse} sendLabel={ui.sendMessage} />\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 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={data.oursName} crestUrl={data.oursCrestUrl} />\n <InjuryList rows={data.ours} 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={data.theirsName} crestUrl={data.theirsCrestUrl} />\n <InjuryList rows={data.theirs} 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 }: {\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}): 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 ]\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 { 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\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 scorers = match.events.filter((e) => e.type === 'goal')\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 {scorers.length > 0 && (\n <div className=\"ss-w-mon-scorers\">{scorers.map((e) => `${e.player ?? ''} ${e.minuteLabel}`).join(', ')}</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 <div className=\"ss-w-mon-stat-row\">\n {/* Always three children -- .ss-w-mon-stat-row is a 1fr/auto/1fr grid, and CSS grid\n auto-placement drops a lone child into the first (home) 1fr track instead of the\n centered auto track, so the null-percentage case must still emit empty home/away\n cells to keep the label centered like every other stat row. */}\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--home\">\n {typeof match.momentumHomePct === 'number' ? `${match.momentumHomePct}%` : ''}\n </span>\n <span className=\"ss-w-mon-stat-l\">{ui.momentumLabel}</span>\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--away\">\n {typeof match.momentumHomePct === 'number' ? `${100 - match.momentumHomePct}%` : ''}\n </span>\n </div>\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\nfunction Side({ name, crest }: { name: string; crest?: string | null }): JSX.Element {\n return (\n <span className=\"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} />\n </span>\n <PinToggle ui={ui} monitor={monitor} pin={{ kind: 'match', matchId: match.matchId }} />\n </div>\n )\n}\n","import type { MatchState } 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","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 { isFinished, isTreatedLive } 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 and the group list all have to agree on what the day contains,\n // and filtering in one place is what guarantees that.\n const visibleGroups = groups\n .map((group) => ({ ...group, matches: group.matches.filter((m) => !isFinished(states[m.matchId])) }))\n .filter((group) => group.matches.length > 0)\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","// 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-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 }\\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}\\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}\\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.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; }\\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.ss-w-dash--discovery .ss-w-dash-tile:nth-child(1) { background: #eef8f1; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }\\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); }\\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 { font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\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.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"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["useCallback","useEffect","useMemo","useRef","useState","useEffect","useReducer","useRef","WidgetSdkError","useReducer","useRef","WidgetSdkError","useEffect","useCallback","useEffect","useRef","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","TTL_MS","useState","useRef","useEffect","useCallback","useMemo","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","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/useMatchDiscovery.ts","../src/scheduleCache.ts","../src/dueSet.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/liveClock.ts","../src/components/CompetitionGroup.tsx","../src/components/TodayPanel.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 { 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 = discovery.groups.length > 0\n useEffect(() => { setHasToday(todayHasContent) }, [todayHasContent])\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 controller={controller} ui={ui} slip={slip} onDashboardTap={onDashboardTap} monitor={monitor.enabled ? monitor : undefined} discovery={discovery} />\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 inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: 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 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 },\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 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 },\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 inSlipLabel: string\n oddsUnavailable: string\n momentumLabel: string\n accordionValueLabel: string\n accordionRetry: string\n accordionSuspended: 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 inSlipLabel: strings.inSlipLabel,\n oddsUnavailable: strings.oddsUnavailable,\n momentumLabel: strings.momentumLabel,\n accordionValueLabel: strings.accordionValueLabel,\n accordionRetry: strings.accordionRetry,\n accordionSuspended: strings.accordionSuspended,\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'\n\nexport type MonitorTab = 'chat' | 'today' | 'following' | 'odds'\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: MonitorTab\n setActiveTab(tab: MonitorTab): 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, setActiveTabState] = useState<MonitorTab>('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: MonitorTab) => {\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 { 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 { 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 { 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 { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\nimport { TabBar } from './TabBar'\nimport { MatchesPanel, OddsPanel } from './MonitorTabs'\nimport { TodayPanel } from './TodayPanel'\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 }: {\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}): 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?.groups.length ?? 0) > 0}\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 <ChatInput placeholder={ui.placeholder} streaming={state.isStreaming} onSend={handleSend} onStop={stop} stopLabel={ui.stopResponse} sendLabel={ui.sendMessage} />\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 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={data.oursName} crestUrl={data.oursCrestUrl} />\n <InjuryList rows={data.ours} 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={data.theirsName} crestUrl={data.theirsCrestUrl} />\n <InjuryList rows={data.theirs} 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 }: {\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}): 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 ]\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 { 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\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 scorers = match.events.filter((e) => e.type === 'goal')\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 {scorers.length > 0 && (\n <div className=\"ss-w-mon-scorers\">{scorers.map((e) => `${e.player ?? ''} ${e.minuteLabel}`).join(', ')}</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 <div className=\"ss-w-mon-stat-row\">\n {/* Always three children -- .ss-w-mon-stat-row is a 1fr/auto/1fr grid, and CSS grid\n auto-placement drops a lone child into the first (home) 1fr track instead of the\n centered auto track, so the null-percentage case must still emit empty home/away\n cells to keep the label centered like every other stat row. */}\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--home\">\n {typeof match.momentumHomePct === 'number' ? `${match.momentumHomePct}%` : ''}\n </span>\n <span className=\"ss-w-mon-stat-l\">{ui.momentumLabel}</span>\n <span className=\"ss-w-mon-stat-v ss-w-mon-stat-v--away\">\n {typeof match.momentumHomePct === 'number' ? `${100 - match.momentumHomePct}%` : ''}\n </span>\n </div>\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 } 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","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 { isFinished, isTreatedLive } 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 and the group list all have to agree on what the day contains,\n // and filtering in one place is what guarantees that.\n const visibleGroups = groups\n .map((group) => ({ ...group, matches: group.matches.filter((m) => !isFinished(states[m.matchId])) }))\n .filter((group) => group.matches.length > 0)\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","// 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-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 }\\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}\\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}\\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.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; }\\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.ss-w-dash--discovery .ss-w-dash-tile:nth-child(1) { background: #eef8f1; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }\\n.ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }\\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); }\\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 { font-size: 11.5px; color: var(--ss-w-faint); overflow-wrap: anywhere; }\\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"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["useCallback","useEffect","useMemo","useRef","useState","useEffect","useReducer","useRef","WidgetSdkError","useReducer","useRef","WidgetSdkError","useEffect","useCallback","useEffect","useRef","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","TTL_MS","useState","useRef","useEffect","useCallback","useMemo","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","jsx","jsxs","useState","useEffect","jsx","useMemo","useRef","useCallback","useState","useEffect"]}