Skip to content

Commit 7006501

Browse files
design: de-slop public pages, Hindi typography, survivor flow clarity
- Replace emoji tier icons with stroked SVGs; de-card privacy list and escalation timeline; full-bleed teal closing band; redacted notice preview artifact on home - Load Noto Serif Devanagari for Hindi headings; zero letter-spacing and taller line-height for lang=hi - Translate Emergency/Privacy in hi.json; i18n for FAQ/Menu/Resources nav links - Add 4-step FlowProgress indicator across eligibility, register, submit, review-sign - On-device fingerprinting reassurance copy; plain-language rewrite of Rule 3(2)(b) confirmation line Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent e9f0b92 commit 7006501

17 files changed

Lines changed: 239 additions & 63 deletions

File tree

asmita/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

asmita/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"dependencies": {
2424
"@fontsource/noto-sans-devanagari": "^5.2.8",
25+
"@fontsource/noto-serif-devanagari": "^5.2.10",
2526
"@pdf-lib/fontkit": "^1.1.1",
2627
"@prisma/adapter-pg": "^7.8.0",
2728
"@prisma/client": "^7.8.0",

asmita/src/app/(auth)/register/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AppShell } from "@/components/layout/AppShell";
22
import { RegisterForm } from "./RegisterForm";
3+
import { FlowProgress } from "@/components/FlowProgress";
34
import { getLocale } from "@/lib/get-locale";
45
import { t } from "@/lib/i18n";
56

@@ -59,6 +60,7 @@ export default async function RegisterPage() {
5960

6061
{/* RIGHT - form */}
6162
<div className="min-w-0 flex-1">
63+
<FlowProgress step={2} locale={locale} />
6264
<RegisterForm locale={locale} />
6365
</div>
6466

asmita/src/app/(public)/how-it-works/page.tsx

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,50 @@ export default async function HowItWorksPage() {
1515
{ num: "06", title: t(locale, "hiw.step6.title"), body: t(locale, "hiw.step6.body") },
1616
];
1717

18+
const tierIconProps = {
19+
width: 18,
20+
height: 18,
21+
viewBox: "0 0 24 24",
22+
fill: "none",
23+
stroke: "currentColor",
24+
strokeWidth: 1.75,
25+
strokeLinecap: "round" as const,
26+
strokeLinejoin: "round" as const,
27+
};
28+
1829
const tiers = [
19-
{ label: "Tier 01", icon: "✉", title: t(locale, "hiw.tier1.title"), body: t(locale, "hiw.tier1.body") },
20-
{ label: "Tier 02", icon: "↗", title: t(locale, "hiw.tier2.title"), body: t(locale, "hiw.tier2.body") },
21-
{ label: "Tier 03", icon: "⚡", title: t(locale, "hiw.tier3.title"), body: t(locale, "hiw.tier3.body") },
30+
{
31+
label: "Tier 01",
32+
icon: (
33+
<svg {...tierIconProps}>
34+
<rect x="3" y="5" width="18" height="14" rx="2" />
35+
<path d="M3 7l9 6 9-6" />
36+
</svg>
37+
),
38+
title: t(locale, "hiw.tier1.title"),
39+
body: t(locale, "hiw.tier1.body"),
40+
},
41+
{
42+
label: "Tier 02",
43+
icon: (
44+
<svg {...tierIconProps}>
45+
<path d="M7 17L17 7" />
46+
<path d="M9 7h8v8" />
47+
</svg>
48+
),
49+
title: t(locale, "hiw.tier2.title"),
50+
body: t(locale, "hiw.tier2.body"),
51+
},
52+
{
53+
label: "Tier 03",
54+
icon: (
55+
<svg {...tierIconProps}>
56+
<path d="M13 2L4.5 13.5H11L10 22l8.5-11.5H12L13 2z" />
57+
</svg>
58+
),
59+
title: t(locale, "hiw.tier3.title"),
60+
body: t(locale, "hiw.tier3.body"),
61+
},
2262
];
2363

2464
const timeline = [
@@ -110,9 +150,12 @@ export default async function HowItWorksPage() {
110150
<p className="font-mono text-[10px] uppercase tracking-[0.16em] text-[var(--muted)]">
111151
{tier.label}
112152
</p>
113-
<p className="mt-3 text-2xl" aria-hidden>
153+
<span
154+
className="mt-3 inline-flex h-9 w-9 items-center justify-center rounded-lg bg-[var(--teal-soft)] text-[var(--teal)]"
155+
aria-hidden
156+
>
114157
{tier.icon}
115-
</p>
158+
</span>
116159
<h3 className="font-display mt-2 text-[18px] font-normal leading-[1.25] tracking-tight md:text-[20px]">
117160
{tier.title}
118161
</h3>
@@ -137,26 +180,21 @@ export default async function HowItWorksPage() {
137180
<p className="muted mt-5 max-w-lg text-base leading-[1.75] md:text-[17px]">
138181
{t(locale, "hiw.escalation.sub")}
139182
</p>
140-
<div className="mt-10 grid gap-4 md:grid-cols-3">
183+
<div className="mt-10 grid gap-8 md:grid-cols-3 md:gap-6">
141184
{timeline.map((item, i) => (
142185
<div
143186
key={item.day}
144-
className="relative rounded-xl border border-[var(--border)] bg-[var(--surface)] p-6"
145-
style={{ boxShadow: "var(--shadow-soft)" }}
187+
className="pt-5"
188+
style={{
189+
borderTop: `2px solid ${i === 0 ? "var(--teal)" : i === 1 ? "var(--saffron)" : "var(--rose)"}`,
190+
}}
146191
>
147-
<div className="mb-4 flex items-center gap-3">
148-
<div
149-
className="h-2 w-2 rounded-full"
150-
style={{ background: i === 0 ? "var(--teal)" : i === 1 ? "var(--saffron)" : "var(--rose)" }}
151-
aria-hidden
152-
/>
153-
<p
154-
className="font-mono text-[11px] font-semibold uppercase tracking-[0.16em]"
155-
style={{ color: i === 0 ? "var(--teal)" : i === 1 ? "var(--saffron)" : "var(--rose)" }}
156-
>
157-
{item.day}
158-
</p>
159-
</div>
192+
<p
193+
className="mb-4 font-mono text-[11px] font-semibold uppercase tracking-[0.16em]"
194+
style={{ color: i === 0 ? "var(--teal)" : i === 1 ? "var(--saffron)" : "var(--rose)" }}
195+
>
196+
{item.day}
197+
</p>
160198
<h3 className="font-display text-[18px] font-normal leading-[1.25] tracking-tight md:text-[20px]">
161199
{item.title}
162200
</h3>

asmita/src/app/(public)/page.tsx

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,47 @@ export default async function HomePage() {
9191
</p>
9292
</div>
9393
<div className="hidden md:block">
94+
{/* Redacted notice preview - the real artifact this platform produces */}
9495
<div
95-
className="rounded-xl border border-[var(--border)] bg-[var(--surface)] px-8 py-6 text-center"
96-
style={{ boxShadow: "var(--shadow-soft)" }}
96+
className="w-[300px] rounded-md border border-[var(--border)] bg-white p-6"
97+
style={{ boxShadow: "var(--shadow-soft)", transform: "rotate(0.5deg)" }}
98+
aria-hidden
9799
>
98-
<p className="font-display text-[48px] font-normal leading-none text-[var(--teal)]">
99-
{t(locale, "home.blockA.stat")}
100+
<p className="font-mono text-[10px] uppercase tracking-[0.16em] text-[var(--muted)]">
101+
Takedown notice
100102
</p>
101-
<p className="muted mt-2 text-sm leading-[1.6]">
102-
{t(locale, "home.blockA.statLabel")}
103+
<p className="font-display mt-2 text-[15px] leading-snug">
104+
Re: Removal under Rule 3(2)(b), IT Rules 2021
103105
</p>
106+
<div className="mt-4 space-y-2">
107+
<div className="h-2 rounded-full bg-[var(--hairline)]" />
108+
<div className="h-2 w-4/5 rounded-full bg-[var(--hairline)]" />
109+
<div className="h-2 w-2/3 rounded-full bg-[var(--foreground)] opacity-70" />
110+
<div className="h-2 rounded-full bg-[var(--hairline)]" />
111+
<div className="h-2 w-3/5 rounded-full bg-[var(--hairline)]" />
112+
</div>
113+
<p className="mt-4 font-mono text-[10px] text-[var(--muted)]">
114+
PDQ fingerprint only. No image attached.
115+
</p>
116+
<div className="mt-4 flex items-center justify-between border-t border-[var(--hairline)] pt-3">
117+
<span className="font-mono text-[10px] font-semibold uppercase tracking-[0.16em] text-[var(--teal)]">
118+
Signed
119+
</span>
120+
<svg width="12" height="10" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
121+
<path
122+
d="M1 4l2.5 2.5L9 1"
123+
stroke="var(--teal)"
124+
strokeWidth="1.5"
125+
strokeLinecap="round"
126+
strokeLinejoin="round"
127+
/>
128+
</svg>
129+
</div>
104130
</div>
131+
<p className="muted mt-4 max-w-[300px] text-center text-sm leading-[1.6]">
132+
<span className="font-semibold text-[var(--teal)]">{t(locale, "home.blockA.stat")}</span>{" "}
133+
{t(locale, "home.blockA.statLabel")}
134+
</p>
105135
</div>
106136
</div>
107137
</div>
@@ -120,13 +150,9 @@ export default async function HomePage() {
120150
<br />
121151
{t(locale, "home.blockB.title.2")}
122152
</h2>
123-
<ul className="mt-10 space-y-4">
153+
<ul className="mt-8 divide-y divide-[var(--hairline)]">
124154
{privacyItems.map(({ bold, detail }) => (
125-
<li
126-
key={bold}
127-
className="flex items-start gap-4 rounded-xl border border-[var(--border)] bg-[var(--surface)] px-6 py-5"
128-
style={{ boxShadow: "var(--shadow-soft)" }}
129-
>
155+
<li key={bold} className="flex items-start gap-4 py-6">
130156
<span
131157
className="mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[var(--teal-soft)]"
132158
aria-hidden
@@ -167,26 +193,24 @@ export default async function HomePage() {
167193
</div>
168194
</section>
169195

170-
<div className="container">
171-
<div className="hairline" />
172-
</div>
173-
174-
{/* CLOSING - invitation, not a sales pitch */}
175-
<section className="container pb-24 pt-20 text-center md:pb-32 md:pt-28">
176-
<div className="mx-auto max-w-2xl">
177-
<h2 className="font-display text-[32px] font-normal leading-[1.15] tracking-tight md:text-[52px] md:leading-[1.12]">
178-
{t(locale, "home.closing.title")}
179-
</h2>
180-
<p className="muted mx-auto mt-7 max-w-lg text-base leading-[1.75] md:text-lg">
181-
{t(locale, "home.closing.body")}
182-
</p>
183-
<div className="mt-10 flex flex-wrap justify-center gap-3">
184-
<Link className="btn btn-primary" href="/start">
185-
{t(locale, "home.closing.cta1")}
186-
</Link>
187-
<Link className="btn btn-secondary" href="/faq">
188-
{t(locale, "home.closing.cta2")}
189-
</Link>
196+
{/* CLOSING - full-bleed teal band, invitation not a sales pitch */}
197+
<section className="band-teal">
198+
<div className="container pb-20 pt-16 text-center md:pb-28 md:pt-24">
199+
<div className="mx-auto max-w-2xl">
200+
<h2 className="font-display text-[32px] font-normal leading-[1.15] tracking-tight md:text-[52px] md:leading-[1.12]">
201+
{t(locale, "home.closing.title")}
202+
</h2>
203+
<p className="muted mx-auto mt-7 max-w-lg text-base leading-[1.75] md:text-lg">
204+
{t(locale, "home.closing.body")}
205+
</p>
206+
<div className="mt-10 flex flex-wrap justify-center gap-3">
207+
<Link className="btn btn-inverse" href="/start">
208+
{t(locale, "home.closing.cta1")}
209+
</Link>
210+
<Link className="btn btn-ghost-light" href="/faq">
211+
{t(locale, "home.closing.cta2")}
212+
</Link>
213+
</div>
190214
</div>
191215
</div>
192216
</section>

asmita/src/app/(victim)/review-sign/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { redirect } from "next/navigation";
22
import { AppShell } from "@/components/layout/AppShell";
33
import { requireSession } from "@/lib/auth/middleware";
44
import { ReviewSignForm } from "./ReviewSignForm";
5+
import { FlowProgress } from "@/components/FlowProgress";
56
import { getLocale } from "@/lib/get-locale";
67

78
export default async function ReviewSignPage() {
@@ -15,6 +16,9 @@ export default async function ReviewSignPage() {
1516
<AppShell>
1617
<div className="page-canvas">
1718
<div className="container py-16 md:py-24">
19+
<div className="mx-auto max-w-5xl">
20+
<FlowProgress step={4} locale={locale} />
21+
</div>
1822
<ReviewSignForm locale={locale} />
1923
</div>
2024
</div>

asmita/src/app/(victim)/submit/SubmitForm.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,18 @@ export function SubmitForm({ enableHashUpload = false, platforms = [], locale }:
243243
</ul>
244244
)}
245245

246+
{hashFiles.some((f) => f.status === "hashing") && (
247+
<p className="muted text-sm leading-[1.6]">
248+
{t(locale, "submit.hash.processingNote")}
249+
</p>
250+
)}
251+
252+
{hashedFiles.length > 0 && hashFiles.every((f) => f.status !== "hashing") && (
253+
<p className="text-sm leading-[1.6] font-medium text-[var(--teal)]">
254+
{t(locale, "submit.hash.doneNote")}
255+
</p>
256+
)}
257+
246258
{lowQuality && (
247259
<p className="text-sm text-amber-700">
248260
{t(locale, "submit.hash.lowQuality")}

asmita/src/app/(victim)/submit/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AppShell } from "@/components/layout/AppShell";
22
import { SubmitForm } from "./SubmitForm";
3+
import { FlowProgress } from "@/components/FlowProgress";
34
import { listHashPickerPlatforms, type HashPickerPlatform } from "@/lib/hash-submission";
45
import { getLocale } from "@/lib/get-locale";
56
import { t } from "@/lib/i18n";
@@ -71,6 +72,7 @@ export default async function SubmitPage() {
7172

7273
{/* RIGHT - form */}
7374
<div className="min-w-0 flex-1">
75+
<FlowProgress step={3} locale={locale} />
7476
<h1 className="font-display text-[28px] font-normal leading-[1.2] tracking-tight md:text-[36px]">
7577
{t(locale, "submit.form.title")}
7678
</h1>

asmita/src/app/eligibility/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AppShell } from "@/components/layout/AppShell";
22
import { EligibilityWizard } from "./EligibilityWizard";
3+
import { FlowProgress } from "@/components/FlowProgress";
34
import { getLocale } from "@/lib/get-locale";
45
import { t } from "@/lib/i18n";
56

@@ -59,6 +60,7 @@ export default async function EligibilityPage() {
5960

6061
{/* RIGHT - wizard steps */}
6162
<div className="min-w-0 flex-1">
63+
<FlowProgress step={1} locale={locale} />
6264
<EligibilityWizard locale={locale} />
6365
</div>
6466

asmita/src/app/globals.css

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
--teal-soft: #e8f5f3;
1313
--saffron: #9f4f17;
1414
--rose: #b24a5a;
15+
--font-deva: "Noto Sans Devanagari";
1516
--radius: 8px;
1617
--radius-lg: 14px;
1718
--shadow-soft: 0 16px 50px rgba(17, 24, 39, 0.06);
@@ -22,7 +23,7 @@
2223
--color-foreground: var(--foreground);
2324
--font-sans: var(--font-inter), "Inter", "Noto Sans Devanagari", system-ui, sans-serif;
2425
--font-mono: var(--font-geist-mono), ui-monospace, monospace;
25-
--font-display: var(--font-serif), "Iowan Old Style", Georgia, "Times New Roman", serif;
26+
--font-display: var(--font-serif), "Noto Serif Devanagari", "Iowan Old Style", Georgia, "Times New Roman", serif;
2627
}
2728

2829
body {
@@ -40,6 +41,17 @@ body {
4041
letter-spacing: -0.01em;
4142
}
4243

44+
/* Devanagari needs no negative tracking (compresses matras/conjuncts)
45+
and taller line-height for stacked diacritics */
46+
html[lang="hi"] body {
47+
letter-spacing: 0;
48+
}
49+
50+
html[lang="hi"] .font-display {
51+
letter-spacing: 0;
52+
line-height: 1.45;
53+
}
54+
4355
a {
4456
text-decoration: none;
4557
}
@@ -275,6 +287,27 @@ select {
275287
opacity: 1;
276288
}
277289

290+
/* Full-bleed teal band - breaks the cream card rhythm once per page */
291+
.band-teal {
292+
background: var(--teal);
293+
color: #ffffff;
294+
}
295+
296+
.band-teal .muted {
297+
color: rgba(255, 255, 255, 0.78);
298+
}
299+
300+
.btn-inverse {
301+
background: #ffffff;
302+
color: var(--teal-dark);
303+
}
304+
305+
.btn-ghost-light {
306+
border: 1px solid rgba(255, 255, 255, 0.4);
307+
background: transparent;
308+
color: #ffffff;
309+
}
310+
278311
.site-footer {
279312
--site-footer-text: #1f2937;
280313
--site-footer-muted: #4b5563;

0 commit comments

Comments
 (0)