diff --git a/src/features/scoreboard/ScoreboardPage.tsx b/src/features/scoreboard/ScoreboardPage.tsx
index 7de1c15..cff66fb 100644
--- a/src/features/scoreboard/ScoreboardPage.tsx
+++ b/src/features/scoreboard/ScoreboardPage.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState, type ReactNode } from 'react';
import { Link } from '@tanstack/react-router';
-import { Scale } from 'lucide-react';
+import { Scale, Zap } from 'lucide-react';
import { PageHeader } from '@/components/ui/PageHeader';
import { Card, CardBody, CardHeader } from '@/components/ui/Card';
import { Term } from '@/components/ui/Term';
@@ -142,6 +142,8 @@ export function ScoreboardPage() {
+
+
{data ? (
{data.rows.length === 0 && (
@@ -155,3 +157,41 @@ export function ScoreboardPage() {
);
}
+
+/** The results the frozen model found least likely — the tournament's shocks. */
+function Upsets({ rows }: { rows: ScoreboardRow[] }) {
+ const t = useT();
+ const upsets = rows
+ .filter((r) => r.scored && !r.late)
+ .map((r) => ({ r, p: r.model[r.scored!.outcome] }))
+ .filter((u) => u.p < 0.30)
+ .sort((a, b) => a.p - b.p)
+ .slice(0, 5);
+ if (upsets.length === 0) return null;
+ return (
+
+
+
+ {t.scoreboard.upsets.title}
+
+
+
+ {upsets.map(({ r, p }) => (
+ -
+
+ {teamFlag(r.home)}
+ {r.home}
+ {r.homeScore}–{r.awayScore}
+ {r.away}
+ {teamFlag(r.away)}
+
+ {fmt(t.scoreboard.upsets.chance, { pct: `${Math.max(1, Math.round(p * 100))}%` })}
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/lib/i18n/de.ts b/src/lib/i18n/de.ts
index d3449a6..e3b12db 100644
--- a/src/lib/i18n/de.ts
+++ b/src/lib/i18n/de.ts
@@ -245,6 +245,10 @@ export const de: Dict = {
marketCloser: "Markt näher dran",
},
emptyRows: "Noch keine eingefrorenen Prognosen — der erste Snapshot entsteht {minutes} Minuten vor Anstoß.",
+ upsets: {
+ title: "Größte Überraschungen",
+ chance: "{pct} wahrscheinlich",
+ },
},
methodology: {
title: "Methodik",
diff --git a/src/lib/i18n/en.ts b/src/lib/i18n/en.ts
index 78e23ee..ffc8790 100644
--- a/src/lib/i18n/en.ts
+++ b/src/lib/i18n/en.ts
@@ -244,6 +244,10 @@ export const en = {
marketCloser: "market closer",
},
emptyRows: "No frozen forecasts yet — the first snapshot is taken {minutes} minutes before kickoff.",
+ upsets: {
+ title: "Biggest surprises",
+ chance: "{pct} likely",
+ },
},
methodology: {
title: "Methodology",