diff --git a/src/components/DailyDigest.tsx b/src/components/DailyDigest.tsx
new file mode 100644
index 0000000..5cf9e47
--- /dev/null
+++ b/src/components/DailyDigest.tsx
@@ -0,0 +1,92 @@
+import { useMemo } from 'react';
+import { Link } from '@tanstack/react-router';
+import { Newspaper, TrendingDown, TrendingUp } from 'lucide-react';
+import { Card, CardBody, CardHeader } from '@/components/ui/Card';
+import { teamFlag } from '@/lib/teams';
+import { dayKeyOf } from '@/lib/format';
+import { useT } from '@/lib/i18n';
+import { useTournamentStore } from '@/stores/tournamentStore';
+
+/** The day in brief: yesterday's results + the model's biggest title-odds moves. */
+export function DailyDigest() {
+ const t = useT();
+ const snapshot = useTournamentStore((s) => s.snapshot);
+ const model = useTournamentStore((s) => s.model);
+
+ const digest = useMemo(() => {
+ if (!snapshot) return null;
+ const now = new Date();
+ const yesterdayKey = dayKeyOf(new Date(now.getTime() - 24 * 3600_000).toISOString());
+ const yesterday = snapshot.fixtures
+ .filter((f) => f.status === 'finished' && dayKeyOf(f.kickoff) === yesterdayKey)
+ .sort((a, b) => a.kickoff.localeCompare(b.kickoff));
+
+ let movers: { team: string; delta: number }[] = [];
+ const hist = model?.history ?? [];
+ if (hist.length >= 2) {
+ const latest = hist[hist.length - 1]!;
+ const cutoff = new Date(latest.t).getTime() - 20 * 3600_000;
+ const base = [...hist].reverse().find((h) => new Date(h.t).getTime() <= cutoff) ?? hist[0]!;
+ if (base !== latest) {
+ const before = new Map(base.top.map((x) => [x.team, x.champion]));
+ movers = latest.top
+ .map((x) => ({ team: x.team, delta: x.champion - (before.get(x.team) ?? 0) }))
+ .filter((m) => Math.abs(m.delta) >= 0.005)
+ .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta))
+ .slice(0, 3);
+ }
+ }
+ if (yesterday.length === 0 && movers.length === 0) return null;
+ return { yesterday, movers };
+ }, [snapshot, model]);
+
+ if (!digest) return null;
+
+ return (
+
+
+
+ {t.live.digestTitle}
+
+
+ {digest.yesterday.length > 0 && (
+
+
{t.live.digestYesterday}
+
+ {digest.yesterday.map((f) => (
+ -
+
+ {f.home.team && teamFlag(f.home.team)}
+ {f.home.label}
+ {f.homeScore}–{f.awayScore}
+ {f.away.label}
+ {f.away.team && teamFlag(f.away.team)}
+
+
+ ))}
+
+
+ )}
+ {digest.movers.length > 0 && (
+
+
{t.live.digestMovers}
+
+ {digest.movers.map((m) => (
+ -
+
+ {teamFlag(m.team)}
+ {m.team}
+ 0 ? 'text-accent' : 'text-danger'}`}>
+ {m.delta > 0 ? : }
+ {m.delta > 0 ? '+' : ''}{(m.delta * 100).toFixed(1)} pp
+
+
+
+ ))}
+
+
+ )}
+
+
+ );
+}
diff --git a/src/features/live/LivePage.tsx b/src/features/live/LivePage.tsx
index acf6d43..a4af72e 100644
--- a/src/features/live/LivePage.tsx
+++ b/src/features/live/LivePage.tsx
@@ -2,6 +2,7 @@ import { useMemo } from 'react';
import { Radio } from 'lucide-react';
import { PageHeader } from '@/components/ui/PageHeader';
import { MatchCard } from '@/components/MatchCard';
+import { DailyDigest } from '@/components/DailyDigest';
import { useTournamentStore } from '@/stores/tournamentStore';
import { useFavoriteStore } from '@/stores/favoriteStore';
import { isToday } from '@/lib/format';
@@ -76,6 +77,8 @@ export function LivePage() {
subtitle={fmt(t.live.subtitle, { season: snapshot.season })}
/>
+
+
{favMatch && (
★ {t.live.myTeam}
diff --git a/src/lib/i18n/de.ts b/src/lib/i18n/de.ts
index 691f809..f311462 100644
--- a/src/lib/i18n/de.ts
+++ b/src/lib/i18n/de.ts
@@ -68,6 +68,9 @@ export const de: Dict = {
comingUp: "Demnächst",
myTeam: "Mein Team",
latestResults: "Letzte Ergebnisse",
+ digestTitle: "Der Tag in Kürze",
+ digestYesterday: "Gestern",
+ digestMovers: "Bewegung bei den Titelchancen",
empty: "Der Spielplan ist geladen. Sobald das Turnier läuft, tauchen die Spiele hier auf.",
},
match: {
diff --git a/src/lib/i18n/en.ts b/src/lib/i18n/en.ts
index cd1e826..4c0cf24 100644
--- a/src/lib/i18n/en.ts
+++ b/src/lib/i18n/en.ts
@@ -67,6 +67,9 @@ export const en = {
comingUp: "Coming up",
myTeam: "My team",
latestResults: "Latest results",
+ digestTitle: "The day in brief",
+ digestYesterday: "Yesterday",
+ digestMovers: "Title-odds movers",
empty: "The schedule is ready. Matches will appear here once the tournament kicks off.",
},
match: {