From 3a14fcc4ca3f30dad544e050fd389408169e5a32 Mon Sep 17 00:00:00 2001 From: Justin Paul Date: Sat, 6 Jun 2026 21:34:47 -0400 Subject: [PATCH] Redesign the frontend: real type, hero landing, depth Lifts the UI from wireframe to a finished heritage look: Fraunces (display serif) + Inter (sans) via next/font; a proper hero landing with a feature triad and the Origin mark; a warm bronze-tinted background gradient for depth; a sticky branded header and refined footer. Polished button (sizes + bronze focus ring + shadow), card (rounded-xl, soft layered shadow), and input (bronze focus) primitives that carry across every page. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Justin Paul --- frontend/app/globals.css | 40 +++++++++----- frontend/app/layout.tsx | 41 ++++++++++----- frontend/app/page.tsx | 86 ++++++++++++++++++++++++------- frontend/components/ui/button.tsx | 12 ++--- frontend/components/ui/card.tsx | 2 +- frontend/components/ui/input.tsx | 2 +- 6 files changed, 131 insertions(+), 52 deletions(-) diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 517decd..55e685a 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -1,44 +1,56 @@ @import "tailwindcss"; -/* Brand palette (docs/brand): warm ink + bronze + paper. */ +/* Brand palette + type (docs/brand): warm ink + bronze + paper, serif display. */ @theme { --color-bronze: #a06a42; --color-bronze-deep: #8a5836; --color-paper: #f7f3ec; --color-ink: #1a1a17; - --font-serif: Georgia, "Times New Roman", "Liberation Serif", ui-serif, serif; + --font-sans: var(--font-inter), ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-serif: var(--font-fraunces), Georgia, "Times New Roman", ui-serif, serif; } -/* Adaptive tokens (ink/paper flip for light/dark; bronze + paper are constant). */ +/* Adaptive tokens — ink/paper flip for light/dark; bronze + paper are constant. */ :root { - --background: #f7f3ec; /* paper */ - --foreground: #1a1a17; /* ink */ + --background: #f7f3ec; + --foreground: #1a1a17; --muted: #6b6862; - --surface: #fbf8f2; - --border: #e4dccb; + --surface: #fffdf9; + --border: #e6ddcc; } @media (prefers-color-scheme: dark) { :root { - --background: #1a1a17; /* warm near-black */ - --foreground: #f2eee6; /* warm off-white */ + --background: #161410; + --foreground: #f2eee6; --muted: #9a968e; - --surface: #232019; - --border: #3a352c; + --surface: #211d17; + --border: #353029; } } body { - background: var(--background); + /* A faint bronze warmth pooled at the top gives the flat paper some depth. */ + background: + radial-gradient( + 1100px 520px at 50% -8%, + color-mix(in srgb, var(--color-bronze) 9%, var(--background)), + var(--background) 60% + ); + background-attachment: fixed; color: var(--foreground); - font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + font-family: var(--font-sans); } -/* Headings use the heritage serif register. */ h1, h2, h3, .font-serif { font-family: var(--font-serif); + letter-spacing: -0.015em; +} + +::selection { + background: color-mix(in srgb, var(--color-bronze) 22%, transparent); } diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 6c97fc7..f3ddafd 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,38 +1,55 @@ import type { Metadata } from "next"; +import { Fraunces, Inter } from "next/font/google"; import Link from "next/link"; import "./globals.css"; +// Heritage display serif + clean humanist sans (per docs/brand typography). +const serif = Fraunces({ + subsets: ["latin"], + variable: "--font-fraunces", + display: "swap", + axes: ["opsz"], +}); +const sans = Inter({ subsets: ["latin"], variable: "--font-inter", display: "swap" }); + export const metadata: Metadata = { - title: "Provenance", - description: "Where it came from matters — family and land, every fact sourced.", + title: "Provenance — where it came from matters", + description: + "Trace your family and your land in one place — every fact linked to the record it came from. Self-hosted, sourced, and yours to keep.", icons: { icon: "/favicon.svg" }, }; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - - -
-
+ + +
+
{/* eslint-disable-next-line @next/next/no-img-element */} Provenance -
-
{children}
+ +
{children}
+
-
- where it came from matters +
+ where it came from matters + Self-hosted · source-available · your data, your infrastructure
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index e30ed1b..9a7a7b2 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -1,27 +1,77 @@ +import { BadgeCheck, MapPin, ShieldCheck, Users } from "lucide-react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; +const features = [ + { + icon: Users, + title: "Family and land, together", + body: "People, relationships, and life events alongside property and chain-of-title — one documented story of where you come from.", + }, + { + icon: BadgeCheck, + title: "Sourced or it didn't happen", + body: "Every fact can carry a citation back to the record it came from. Sources are first-class, reusable, and visible.", + }, + { + icon: ShieldCheck, + title: "Yours to keep", + body: "Self-hosted and source-available. Living people protected by default. Open formats — export anytime, run it anywhere.", + }, +]; + export default function Home() { return ( -
-
-

- Where it came from matters -

-

- Trace where you come from — your family and your - land — with every fact linked to a source, on infrastructure you control. -

-
-
- - - - - - -
+
+
+
+

+ Family · Land · Provenance +

+

+ Where it came from{" "} + matters. +

+

+ Trace your family and your land in one place — every name, every parcel, every claim + linked to the record it came from. Self-hosted, sourced, and yours to keep. +

+
+ + + + + + +
+
+ +
+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + + +
+
+
+ +
+ {features.map((f) => ( +
+
+ +
+

{f.title}

+

{f.body}

+
+ ))} +
); } diff --git a/frontend/components/ui/button.tsx b/frontend/components/ui/button.tsx index 6d9ee94..beb9c6f 100644 --- a/frontend/components/ui/button.tsx +++ b/frontend/components/ui/button.tsx @@ -4,19 +4,19 @@ import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; const buttonVariants = cva( - "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-bronze focus-visible:ring-offset-1 disabled:pointer-events-none disabled:opacity-50", + "inline-flex items-center justify-center gap-2 rounded-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-bronze focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--background)] disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { - // Bronze is the brand accent; paper reads cleanly on it. - default: "bg-bronze text-paper hover:bg-bronze-deep", + default: "bg-bronze text-paper shadow-sm hover:bg-bronze-deep hover:shadow", outline: - "border border-bronze text-bronze bg-transparent hover:bg-bronze hover:text-paper", + "border border-[var(--border)] bg-[var(--surface)] hover:border-bronze hover:text-bronze", ghost: "text-[var(--foreground)] hover:bg-bronze/10", }, size: { - default: "h-10 px-4 py-2", - sm: "h-9 px-3", + default: "h-10 px-4 text-sm", + sm: "h-9 px-3 text-sm", + lg: "h-12 px-6 text-base", }, }, defaultVariants: { variant: "default", size: "default" }, diff --git a/frontend/components/ui/card.tsx b/frontend/components/ui/card.tsx index 3267028..cf329ae 100644 --- a/frontend/components/ui/card.tsx +++ b/frontend/components/ui/card.tsx @@ -6,7 +6,7 @@ export function Card({ className, ...props }: React.HTMLAttributes