diff --git a/AGENTS.md b/AGENTS.md
index 6915d2a9..88882fa7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -21,6 +21,6 @@ Two long-lived branches:
**Rules:**
- Never push directly to `main` or `dev`. PRs only.
-- The staging URL emits `` and serves `robots.txt: Disallow /` — see `src/app/robots.ts` and `src/app/layout.tsx`. Don't undo without thinking through duplicate-content SEO impact on the prod domain. Vercel Preview SSO is disabled (URL is publicly shareable), so the noindex is the only thing keeping crawlers out.
+- The staging URL emits `` and serves `robots.txt: Disallow /`, see `src/app/robots.ts` and `src/app/layout.tsx`. Don't undo without thinking through duplicate-content SEO impact on the prod domain. Vercel Preview SSO is disabled (URL is publicly shareable), so the noindex is the only thing keeping crawlers out.
- Hotfix path: if prod is on fire and waiting through `dev` is unacceptable, open the fix PR directly against `main`, merge (CI deploys automatically), then immediately fast-forward `dev` from `main` (`git checkout dev && git merge --ff-only main && git push`) so the two branches don't diverge.
- Required GitHub secrets (repo-level, not environment-scoped): `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`.
diff --git a/README.md b/README.md
index 8288e9d6..219c7f70 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
[](./LICENSE) [](https://creativecommons.org/licenses/by/4.0/) [](https://openchainbench.com/benchmarks) [](https://openchainbench.com/mcp) [](https://openchainbench.com/llms.txt)
-OpenChainBench publishes one benchmark at a time, each shipping with the harness that produces its data. The goal is to make performance an observable property of crypto infra — measured in the open, by anyone who wants to add a provider or a metric.
+OpenChainBench publishes one benchmark at a time, each shipping with the harness that produces its data. The goal is to make performance an observable property of crypto infra, measured in the open, by anyone who wants to add a provider or a metric.
Community-run, MIT-licensed harnesses + CC-BY-4.0 data, PRs from any party including the providers we benchmark.
@@ -14,7 +14,7 @@ Community-run, MIT-licensed harnesses + CC-BY-4.0 data, PRs from any party inclu
- **50** self-contained Go harnesses, each shipping a `/metrics` Prometheus endpoint
- **32** curated question/answer pages · **23** "alternatives to X" landing pages
- **26** machine-readable API routes (citation, badges, MCP, feeds, per-format quotes)
-- One shared Prometheus, one materialization worker, CDN-fastpath snapshot store — cold reads in < 100 ms edge, no origin fan-out on hot paths
+- One shared Prometheus, one materialization worker, CDN-fastpath snapshot store: cold reads in < 100 ms edge, no origin fan-out on hot paths
## Quickstart
diff --git a/docs/architecture.md b/docs/architecture.md
index 75abcbfd..94116edc 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -70,7 +70,7 @@ build clones the OCB `dev` branch fresh).
## Known constraints
- Prometheus must be reachable from the materialization worker; the site only needs the Redis store (plus Prometheus for the live fallback path).
-- Worker sweep cost grows linearly with providers (one Prometheus call per provider per metric per benchmark) — the heaviest bench, hyperliquid-frontends, declares 100+ providers. The Prom client bounds concurrency with a global query semaphore.
+- Worker sweep cost grows linearly with providers (one Prometheus call per provider per metric per benchmark), the heaviest bench, hyperliquid-frontends, declares 100+ providers. The Prom client bounds concurrency with a global query semaphore.
- `generateStaticParams` reads the YAML filenames directly so the route table is stable even when Prometheus or the store is offline.
- Spec changes that alter a bench's provider list require a worker image rebuild to show up on the site (the worker bakes its OCB checkout at build time).
@@ -105,7 +105,7 @@ The live dashboard at [openchainbench.com](https://openchainbench.com) has its *
```
The browser opens a WebSocket **directly to the Railway relay**. Vercel
-Functions are never invoked for live data — keeps cost flat at ~$5/mo
+Functions are never invoked for live data, keeps cost flat at ~$5/mo
regardless of viewer count.
### Why a separate relay (not Vercel SSE)
@@ -122,9 +122,9 @@ Three message types arrive on `/ws`, all JSON:
| `type` | When | Payload |
|---|---|---|
-| `snapshot` | First message on every connect | `{ buckets: [{ ts, perChain }], nowMs }` — the last 10 min of incremental per-chain volume, padded with empty buckets on the left so the chart is full from t=0. |
-| `swap` | Per real trade (filtered: `buy`/`sell`, `operation=regular\|arbitrage`) | `{ chain, pool, pair, exchange, side, usd, hash, onChainMs, mobulaMs, receivedMs }` — enriched with pair name + DEX from a top-N catalog fetched at boot. |
-| `stats` | Every 1 s | `{ global: {vol24h, trades24h, …, mcap, byChain[]}, live: {swaps, vol, chains}, nowMs }` — ground-truth global stats from REST + per-session live counters. |
+| `snapshot` | First message on every connect | `{ buckets: [{ ts, perChain }], nowMs }`, the last 10 min of incremental per-chain volume, padded with empty buckets on the left so the chart is full from t=0. |
+| `swap` | Per real trade (filtered: `buy`/`sell`, `operation=regular\|arbitrage`) | `{ chain, pool, pair, exchange, side, usd, hash, onChainMs, mobulaMs, receivedMs }`, enriched with pair name + DEX from a top-N catalog fetched at boot. |
+| `stats` | Every 1 s | `{ global: {vol24h, trades24h, …, mcap, byChain[]}, live: {swaps, vol, chains}, nowMs }`, ground-truth global stats from REST + per-session live counters. |
The browser snapshots the first message, then accumulates `swap` events into incremental buckets matching the relay's bucket boundaries (using the snapshot's `nowMs` to learn the relay/browser clock offset).
diff --git a/src/app/api/badge/[slug]/[provider]/route.ts b/src/app/api/badge/[slug]/[provider]/route.ts
index d699b26b..ff0c0ba1 100644
--- a/src/app/api/badge/[slug]/[provider]/route.ts
+++ b/src/app/api/badge/[slug]/[provider]/route.ts
@@ -385,7 +385,7 @@ function placeholderSvg(benchTitle: string): NextResponse {
Math.max(W_MIN, TEXT_X + title.length * CH_11 + 30),
);
const svg = `
-