diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbac02f..0cd7b7f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,7 +36,7 @@ jobs:
uses: pnpm/action-setup@b0f76dfb45f55f8421693e4803ac7bb65143bd34 # v6
- name: Set up Node.js
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
node-version: 22
cache: pnpm
@@ -90,7 +90,7 @@ jobs:
uses: pnpm/action-setup@b0f76dfb45f55f8421693e4803ac7bb65143bd34 # v6
- name: Set up Node.js
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
with:
node-version: 22
cache: pnpm
diff --git a/app/[locale]/demo/page.tsx b/app/[locale]/demo/page.tsx
index bd960f3..4adfb48 100644
--- a/app/[locale]/demo/page.tsx
+++ b/app/[locale]/demo/page.tsx
@@ -53,7 +53,7 @@ export default async function DemoPage({ params }: Props) {
const path = getUnfreezePath("cyber_upi_chain", locale);
return (
-
+
{/* Lead with the killer insight in plain words, not a caveat — all three
comprehension reviewers (HRs + a normal user) said the value was buried
under a legal briefing. State it first; let the cards below be the proof. */}
@@ -137,8 +137,13 @@ export default async function DemoPage({ params }: Props) {
frozenAmountInr="1,800"
/>
-
- {t("sourcesTitle")}
+ {/* Reference material — collapsed by default so the demo leads with the
+ usable output instead of a wall of legal text. All content preserved. */}
+
+
+ {t("sourcesTitle")}
+ +
+
{t("sourcesDesc")}
@@ -152,7 +157,7 @@ export default async function DemoPage({ params }: Props) {
-
+
diff --git a/app/[locale]/impact/page.tsx b/app/[locale]/impact/page.tsx
new file mode 100644
index 0000000..bc1b83b
--- /dev/null
+++ b/app/[locale]/impact/page.tsx
@@ -0,0 +1,96 @@
+import type { Metadata } from "next";
+import { getTranslations, setRequestLocale } from "next-intl/server";
+import { Link } from "@/i18n/navigation";
+import { StatCard } from "@/components/metrics/StatCard";
+import { getPublicStats, type PublicStats } from "@/lib/metrics/public-stats";
+
+type Props = { params: Promise<{ locale: string }> };
+
+// Always render fresh so the counts are live (and never cache a build-time
+// empty state). The page issues four cheap COUNT queries — negligible load.
+export const dynamic = "force-dynamic";
+
+export async function generateMetadata({ params }: Props): Promise
{
+ const { locale } = await params;
+ const t = await getTranslations({ locale, namespace: "ImpactPage" });
+ return { title: t("title"), description: t("intro") };
+}
+
+export default async function ImpactPage({ params }: Props) {
+ const { locale } = await params;
+ setRequestLocale(locale);
+ const t = await getTranslations("ImpactPage");
+
+ let stats: PublicStats | null = null;
+ try {
+ stats = await getPublicStats();
+ } catch {
+ stats = null;
+ }
+
+ const fmt = (n: number) => n.toLocaleString("en-IN");
+
+ return (
+
+
+
{t("eyebrow")}
+
+ {t("title")}
+
+
+ {t("intro")}
+
+
+
+ {!stats || stats.casesStarted === 0 ? (
+
+ {t("emptyTitle")}
+
+ {t("emptyBody")}
+
+
+ {t("startCta")}
+
+
+ ) : (
+ <>
+
+
+ {t("updatedPrefix")}{" "}
+ {new Date(stats.generatedAt).toLocaleString("en-IN")}
+
+
+ {t("startCta")}
+
+ >
+ )}
+
+
+ {t("disclaimer")}
+
+
+ );
+}
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
index bc640b3..0cf83c9 100644
--- a/app/[locale]/layout.tsx
+++ b/app/[locale]/layout.tsx
@@ -9,6 +9,7 @@ import { NextIntlClientProvider, hasLocale } from "next-intl";
import { getTranslations, setRequestLocale } from "next-intl/server";
import { notFound } from "next/navigation";
import "../globals.css";
+import { Analytics } from "@vercel/analytics/next";
import { SiteHeader } from "@/components/layout/SiteHeader";
import { BottomTabBar } from "@/components/layout/BottomTabBar";
import { Link } from "@/i18n/navigation";
@@ -204,6 +205,7 @@ export default async function LocaleLayout({
+