Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions app/budget/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useState } from "react";
import { IndianRupee, MapPin, TrendingUp, CheckCircle, Clock, AlertCircle, ChevronRight } from "lucide-react";
import budgetData from "@/data/budget.json";
import { formatCrore } from "@/lib/utils";
import { unionBudget } from "@/lib/sources";
import SourceTag from "@/components/SourceTag";

const NATIONAL = budgetData.national;
const STATES = budgetData.states;
Expand All @@ -23,7 +25,7 @@ export default function BudgetPage() {
maxWidth: 1400, margin: "0 auto",
}}>
<div style={{ fontSize: 12, letterSpacing: 4, color: "#FFB703", textTransform: "uppercase", marginBottom: "0.75rem" }}>
Union Budget 2024-25 + State Budgets
Union Budget 2025-26 + State Budgets
</div>
<h1 style={{
fontFamily: "'Bebas Neue', sans-serif",
Expand All @@ -39,8 +41,11 @@ export default function BudgetPage() {
</span>
</h1>
<p style={{ color: "#888", fontSize: 15, maxWidth: 600, lineHeight: 1.7 }}>
Every rupee of your tax money tracked. Where India's ₹47.96 lakh crore budget goes — nationally and state-wise.
Every rupee of your tax money tracked. Where India's ₹50.65 lakh crore Union Budget (FY 2025-26) goes — nationally and state-wise.
</p>
<div style={{ marginTop: "1rem" }}>
<SourceTag source={unionBudget()} sourceLabel="Union Budget 2025-26 · indiabudget.gov.in" verifiedOn="2026-08-01" />
</div>

{/* View toggle */}
<div style={{ display: "flex", gap: 6, marginTop: "2rem" }}>
Expand Down Expand Up @@ -80,12 +85,12 @@ export default function BudgetPage() {
marginBottom: "3rem",
}}>
{[
{ val: "₹47.96 Lakh Cr", label: "Total Budget", color: "#FFB703", sub: "FY 2024-25" },
{ val: "₹11.3 Lakh Cr", label: "Interest Payments", color: "#E63946", sub: "23.5% of budget — debt servicing" },
{ val: "4.9%", label: "Fiscal Deficit / GDP", color: "#FF6B2B", sub: "₹16.16 lakh crore deficit" },
{ val: "₹32.93 Lakh Cr", label: "Estimated GDP", color: "#4ade80", sub: "FY 2024-25" },
{ val: "₹25.97 Lakh Cr", label: "Tax Revenue", color: "#06b6d4", sub: "Direct + Indirect taxes" },
{ val: "₹1.11 Lakh Cr", label: "Capital Expenditure", color: "#8b5cf6", sub: "Infrastructure & assets" },
{ val: "₹50.65 Lakh Cr", label: "Total Budget", color: "#FFB703", sub: "FY 2025-26 (Budget Estimate)" },
{ val: "₹12.76 Lakh Cr", label: "Interest Payments", color: "#E63946", sub: "~25% of expenditure — debt servicing" },
{ val: "4.4%", label: "Fiscal Deficit / GDP", color: "#FF6B2B", sub: "FY 2025-26 target" },
{ val: "₹356.97 Lakh Cr", label: "Nominal GDP (assumed)", color: "#4ade80", sub: "FY 2025-26 assumption" },
{ val: "₹28.37 Lakh Cr", label: "Net Tax Receipts", color: "#06b6d4", sub: "Centre's net tax revenue" },
{ val: "₹11.21 Lakh Cr", label: "Capital Expenditure", color: "#8b5cf6", sub: "Infrastructure & assets" },
].map((s, i) => (
<div key={i} style={{
padding: "1.5rem",
Expand Down Expand Up @@ -180,8 +185,11 @@ export default function BudgetPage() {
<AlertCircle size={16} /> The Debt Problem
</h3>
<p style={{ color: "#888", fontSize: 13, lineHeight: 1.7 }}>
India spends <strong style={{ color: "#E63946" }}>₹11.29 lakh crore (23.5%)</strong> of its entire budget on interest payments alone — more than defence, education, and health combined. This money goes to servicing the national debt of ₹169 lakh crore and creates less for public services.
India spends roughly <strong style={{ color: "#E63946" }}>₹12.76 lakh crore (~25%)</strong> of its FY2025-26 budget on interest payments alone — more than defence, education, and health combined. This services a national debt now above ₹185 lakh crore, leaving less for public services.
</p>
<div style={{ marginTop: "0.75rem" }}>
<SourceTag source={unionBudget()} sourceLabel="Budget at a Glance 2025-26" verifiedOn="2026-08-01" compact />
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -256,7 +264,7 @@ export default function BudgetPage() {
<div style={{ fontFamily: "'Bebas Neue', sans-serif", fontSize: 32, color: "#FFB703", lineHeight: 1 }}>
{formatCrore(selectedState.budget_cr)}
</div>
<div style={{ color: "#555", fontSize: 12 }}>State Budget 2024-25</div>
<div style={{ color: "#555", fontSize: 12 }}>State Budget (latest available)</div>
<div style={{ color: "#888", fontSize: 12 }}>₹{selectedState.per_capita_budget.toLocaleString()} per person</div>
</div>
</div>
Expand Down
118 changes: 118 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,63 @@
--font-inter: "Inter", sans-serif;
}

/* ============================================================
DESIGN TOKENS — single source of truth for the visual system.
Use via var(--token) in inline styles or classes across the app.
============================================================ */
:root {
/* Surface / background ramp (dark) */
--bg: #060607;
--surface-0: #0a0a0c;
--surface-1: rgba(255, 255, 255, 0.02);
--surface-2: rgba(255, 255, 255, 0.04);
--surface-3: rgba(255, 255, 255, 0.06);
--border: rgba(255, 255, 255, 0.08);
--border-strong: rgba(255, 255, 255, 0.14);

/* Text ramp */
--text: #f2f2f3;
--text-dim: #a1a1aa;
--text-mute: #6b6b73;
--text-faint: #48484f;

/* Accents */
--accent: #FF6B2B;
--accent-2: #E63946;
--gold: #FFB703;
--cyan: #06b6d4;
--green: #4ade80;
--violet: #8b5cf6;

/* Semantic (freshness / severity) */
--fresh: #4ade80;
--aging: #FFB703;
--stale: #ef4444;

/* Spacing scale (4px base) */
--s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
--s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

/* Radius */
--r-sm: 6px; --r-md: 10px; --r-lg: 14px; --r-xl: 20px; --r-pill: 999px;

/* Shadows */
--shadow-sm: 0 2px 8px rgba(0,0,0,0.3);
--shadow-md: 0 8px 24px rgba(0,0,0,0.35);
--shadow-lg: 0 20px 48px rgba(0,0,0,0.45);

/* Motion */
--ease: cubic-bezier(0.22, 1, 0.36, 1);
--dur-fast: 0.18s;
--dur: 0.3s;
--dur-slow: 0.6s;

/* Fonts */
--font-display: "Bebas Neue", sans-serif;
--font-serif: "Playfair Display", serif;
--font-body: "Inter", system-ui, sans-serif;
}

* {
box-sizing: border-box;
margin: 0;
Expand Down Expand Up @@ -124,3 +181,64 @@ body::before {
-webkit-box-orient: vertical;
overflow: hidden;
}

/* ============================================================
MOTION PRIMITIVES — scroll-reveal + staggered entrances.
Add .reveal to an element; it animates in when .is-visible
is toggled by the AnimatedSection / Reveal observer.
============================================================ */
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
will-change: opacity, transform;
}
.reveal.is-visible {
opacity: 1;
transform: none;
}
/* Stagger children: set --i on each child (index) for a cascade */
.stagger > * {
opacity: 0;
transform: translateY(18px);
transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
transition-delay: calc(var(--i, 0) * 60ms);
}
.stagger.is-visible > * {
opacity: 1;
transform: none;
}

@keyframes fade-up {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: none; }
}
.animate-fade-up { animation: fade-up var(--dur-slow) var(--ease) both; }

@keyframes count-pop {
0% { transform: scale(0.96); }
60% { transform: scale(1.02); }
100% { transform: scale(1); }
}

/* Card hover lift — apply .lift for a consistent interaction */
.lift { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.lift:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }

/* Focus-visible for keyboard a11y */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: var(--r-sm);
}

/* Respect users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
.reveal, .stagger > * { opacity: 1 !important; transform: none !important; }
}
6 changes: 3 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ export const metadata: Metadata = {
title: "NagrikNazar — The Citizen's Eye on Indian Politics",
description:
"India's most comprehensive political transparency platform. Track politician criminal records, assets, controversies, budget allocation, and government project progress. Built for every Indian citizen.",
keywords: "india politics transparency, politician criminal records, budget tracker, neta exposed, election commission data, ADR india",
keywords: "india politics transparency, politician criminal records, budget tracker, election commission data, ADR india, myneta, PRS, non-partisan accountability",
openGraph: {
title: "NagrikNazar — The Citizen's Eye",
description: "Exposing the truth about Indian politics for every citizen.",
description: "A non-partisan, fully-sourced view of Indian politics — criminal records, assets, budgets and controversies, every claim traceable to an official record.",
type: "website",
locale: "en_IN",
},
twitter: {
card: "summary_large_image",
title: "NagrikNazar — The Citizen's Eye",
description: "Exposing the truth about Indian politics for every citizen.",
description: "A non-partisan, fully-sourced view of Indian politics. Every claim traceable to an official record.",
},
};

Expand Down
127 changes: 127 additions & 0 deletions app/methodology/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"use client";
import Link from "next/link";
import { ShieldCheck, Scale, FileText, ExternalLink, CheckCircle2, AlertTriangle, Calendar } from "lucide-react";
import { PRIMARY_SOURCES } from "@/lib/sources";
import AnimatedSection from "@/components/AnimatedSection";

export default function MethodologyPage() {
return (
<div style={{ minHeight: "100vh", paddingTop: 64 }}>
{/* Hero */}
<div style={{
padding: "4rem 1.5rem 3rem",
background: "linear-gradient(180deg, rgba(74,222,128,0.06) 0%, transparent 100%)",
borderBottom: "1px solid var(--border)",
}}>
<div style={{ maxWidth: 1000, margin: "0 auto" }}>
<div style={{ fontSize: 12, letterSpacing: 4, color: "var(--green)", textTransform: "uppercase", marginBottom: "0.75rem" }}>
How we know what we publish
</div>
<h1 style={{ fontFamily: "var(--font-display)", fontSize: "clamp(2.5rem, 6vw, 4.5rem)", color: "#fff", letterSpacing: 1, lineHeight: 1 }}>
METHODOLOGY <span style={{ color: "var(--green)" }}>&amp; SOURCES</span>
</h1>
<p style={{ color: "var(--text-dim)", fontSize: 16, maxWidth: 680, lineHeight: 1.8, marginTop: "1rem" }}>
This platform exists to make government and politics understandable and checkable for
every citizen. It is not aligned with any party. Every figure here traces back to an
official record or a respected non-partisan body — and you can click through to verify
it yourself.
</p>
</div>
</div>

<div style={{ maxWidth: 1000, margin: "0 auto", padding: "3rem 1.5rem" }}>
{/* Principles */}
<AnimatedSection stagger style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: "1rem", marginBottom: "3rem" }}>
{[
{ icon: <ShieldCheck size={22} color="var(--green)" />, title: "Every claim is sourced", body: "Each fact links to the document proving it — a court judgment, an EC affidavit, a CAG report, or named news coverage. No unsourced assertions." },
{ icon: <Scale size={22} color="var(--gold)" />, title: "Non-partisan by design", body: "Ruling party and opposition are held to the exact same standard and the same sourcing bar. The data decides prominence, not us." },
{ icon: <Calendar size={22} color="var(--cyan)" />, title: "Honest about freshness", body: "Every fact shows when it was last verified, with a colour dot: green (recent), amber (check for updates), red (likely outdated)." },
{ icon: <FileText size={22} color="var(--accent)" />, title: "Allegation ≠ conviction", body: "We use precise legal language — pending case, chargesheeted, alleged, acquitted, convicted — reflecting each matter's actual current status." },
].map((c) => (
<div key={c.title} className="lift" style={{ padding: "1.5rem", background: "var(--surface-1)", border: "1px solid var(--border)", borderRadius: "var(--r-lg)" }}>
<div style={{ marginBottom: "0.75rem" }}>{c.icon}</div>
<div style={{ color: "#fff", fontWeight: 700, fontSize: 15, marginBottom: "0.4rem" }}>{c.title}</div>
<div style={{ color: "var(--text-mute)", fontSize: 13, lineHeight: 1.7 }}>{c.body}</div>
</div>
))}
</AnimatedSection>

{/* Primary sources */}
<AnimatedSection>
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "#fff", letterSpacing: 1, marginBottom: "1.5rem" }}>
OUR PRIMARY SOURCES
</h2>
<div style={{ display: "grid", gap: "0.75rem", marginBottom: "3rem" }}>
{PRIMARY_SOURCES.map((s) => (
<a key={s.name} href={s.url} target="_blank" rel="noopener noreferrer" className="lift" style={{
display: "grid", gridTemplateColumns: "1fr auto", gap: "1rem", alignItems: "center",
padding: "1rem 1.25rem", background: "var(--surface-1)", border: "1px solid var(--border)",
borderRadius: "var(--r-md)", textDecoration: "none",
}}>
<div>
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 3 }}>
<span style={{ color: "#fff", fontWeight: 700, fontSize: 15 }}>{s.name}</span>
<span style={{ fontSize: 10, color: "var(--text-mute)", border: "1px solid var(--border)", borderRadius: 4, padding: "1px 6px" }}>{s.type}</span>
</div>
<div style={{ color: "var(--text-mute)", fontSize: 13, lineHeight: 1.6 }}>{s.role}</div>
</div>
<ExternalLink size={16} color="var(--text-mute)" />
</a>
))}
</div>
</AnimatedSection>

{/* How data stays current */}
<AnimatedSection>
<h2 style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "#fff", letterSpacing: 1, marginBottom: "1.5rem" }}>
HOW WE KEEP IT CURRENT
</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1rem", marginBottom: "3rem" }} className="how-grid">
<div style={{ padding: "1.5rem", background: "rgba(74,222,128,0.05)", border: "1px solid rgba(74,222,128,0.2)", borderRadius: "var(--r-lg)" }}>
<div style={{ display: "flex", alignItems: "center", gap: 8, color: "var(--green)", fontWeight: 700, marginBottom: "0.75rem" }}>
<CheckCircle2 size={18} /> Live data
</div>
<ul style={{ color: "var(--text-dim)", fontSize: 13, lineHeight: 1.9, paddingLeft: 18, margin: 0 }}>
<li>News is fetched live for every politician and topic.</li>
<li>Official open datasets (data.gov.in) power budget &amp; economic figures where an API exists.</li>
<li>Deep links to MyNeta, eCourts, IndiaKanoon &amp; PRS always show you the latest at the source.</li>
</ul>
</div>
<div style={{ padding: "1.5rem", background: "rgba(255,183,3,0.05)", border: "1px solid rgba(255,183,3,0.2)", borderRadius: "var(--r-lg)" }}>
<div style={{ display: "flex", alignItems: "center", gap: 8, color: "var(--gold)", fontWeight: 700, marginBottom: "0.75rem" }}>
<AlertTriangle size={18} /> Honest limits
</div>
<ul style={{ color: "var(--text-dim)", fontSize: 13, lineHeight: 1.9, paddingLeft: 18, margin: 0 }}>
<li>There is no single public API for affidavit/criminal data — that data is structured by hand and deep-linked to MyNeta so you can verify it.</li>
<li>Every such fact carries a "verified on" date and freshness dot.</li>
<li>Spot something outdated? The source link lets you check the current position instantly.</li>
</ul>
</div>
</div>
</AnimatedSection>

{/* Non-partisan statement */}
<AnimatedSection>
<div style={{ padding: "2rem", background: "var(--surface-1)", border: "1px solid var(--border)", borderRadius: "var(--r-xl)", textAlign: "center" }}>
<div style={{ fontSize: 28, marginBottom: "0.5rem" }}>⚖️</div>
<h3 style={{ color: "#fff", fontWeight: 700, fontSize: 18, marginBottom: "0.75rem" }}>Our commitment</h3>
<p style={{ color: "var(--text-dim)", fontSize: 14, lineHeight: 1.9, maxWidth: 640, margin: "0 auto" }}>
We hold power to account — whoever holds it. The goal is an informed citizen, not a
political verdict. We present sourced facts and let you draw your own conclusions.
Found an error or a better source? That feedback makes this stronger.
</p>
<Link href="/politicians" style={{
display: "inline-flex", alignItems: "center", gap: 8, marginTop: "1.5rem",
background: "linear-gradient(135deg, var(--accent), var(--accent-2))", color: "#fff",
padding: "12px 26px", borderRadius: "var(--r-md)", textDecoration: "none", fontWeight: 700, fontSize: 14,
}}>
Explore the data
</Link>
</div>
</AnimatedSection>
</div>

<style>{`@media (max-width: 768px) { .how-grid { grid-template-columns: 1fr !important; } }`}</style>
</div>
);
}
Loading