diff --git a/README.md b/README.md
index c6c02f8..50fa583 100644
--- a/README.md
+++ b/README.md
@@ -51,8 +51,9 @@ archive), who is on call, the alert feed, and an *Account* tab for your own
password and the ntfy topic your pages go to. It is built for a phone first. On a phone
it navigates through a hamburger menu and has a sticky action bar, it follows the
system's dark mode, and it can be added to the home screen. From 900px wide it switches
-to a sidebar with the queue and the incident side by side. Statistics remain in
-[terdut-tui](https://github.com/yeniklas/terdut-tui) for now.
+to a sidebar with the queue and the incident side by side. The Stats page shows
+incident counts, MTTA and MTTR, and alert frequency by name, hour and day over a
+chosen range.
You sign in with a username and password. Users have no password until one is
set, and a user without one can only use API keys:
diff --git a/internal/web/static/app.css b/internal/web/static/app.css
index c6f42c6..29a860c 100644
--- a/internal/web/static/app.css
+++ b/internal/web/static/app.css
@@ -867,3 +867,40 @@ button.rota-day:hover { background: var(--surface-2); }
.overview-head { display: flex; align-items: baseline; gap: 8px; }
.overview-count { margin-left: auto; color: var(--muted); font-size: 18px; font-weight: 700; }
.overview-item p { margin: 4px 0 0; }
+
+/* ---------- stats page ---------- */
+
+#view-stats .chips { padding-left: 0; padding-right: 0; }
+.stats { display: grid; gap: 14px; padding-bottom: 16px; }
+.stat-tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
+.stat-tile {
+ --sev: var(--border-strong);
+ background: var(--surface); border: 1px solid var(--border);
+ border-left: 3px solid var(--sev); border-radius: var(--radius);
+ box-shadow: var(--shadow); padding: 12px;
+}
+.stat-tile.st-triggered { --sev: var(--crit); }
+.stat-tile.st-acknowledged { --sev: var(--warn); }
+.stat-tile.st-resolved { --sev: var(--ok); }
+.stat-value { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
+.stat-label { margin-top: 2px; font-size: 12px; color: var(--muted); }
+.chart-card + .chart-card { margin-top: 0; }
+.chart-title {
+ margin-bottom: 10px; font-size: 13px; font-weight: 700;
+ text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted);
+}
+.hbars { list-style: none; display: grid; gap: 6px; }
+.hbar { display: grid; grid-template-columns: minmax(80px, 34%) 1fr auto; align-items: center; gap: 8px; font-size: 13px; }
+.hbar-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.hbar-track { height: 10px; border-radius: 5px; background: var(--surface-2); overflow: hidden; }
+.hbar-fill { display: block; height: 100%; border-radius: 5px; background: var(--ok); }
+.hbar-count { min-width: 2ch; text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; }
+.columns { display: block; width: 100%; height: auto; }
+.columns .axis { stroke: var(--border-strong); stroke-width: 1; }
+.columns .col-hit { fill: transparent; }
+.columns .col-bar { fill: var(--accent); }
+.columns .col:hover .col-bar { opacity: 0.75; }
+.columns .col-label { fill: var(--faint); font-size: 10px; font-family: var(--font); }
+@media (min-width: 900px) {
+ .stat-tiles { grid-template-columns: repeat(3, 1fr); }
+}
diff --git a/internal/web/static/index.html b/internal/web/static/index.html
index 2174927..284493d 100644
--- a/internal/web/static/index.html
+++ b/internal/web/static/index.html
@@ -90,6 +90,10 @@
Alerts
+
+
+ Stats
+
Team
@@ -128,6 +132,7 @@
+