Tokens live in src/styles.css. Components live in src/components/ui/. This page renders the actual production components — what you see is what ships. Open experiments →
Manrope is default on body via --font-sans. Fraunces is opt-in via .display-title: home h1, hanja prompt, end-screen heading.
Shadcn tokens are remapped to the brand palette in :root, so bg-primary etc. inherit our colors without patching the components themselves.
From src/components/ui/button.tsx. Recolor via :root tokens (--primary, --background, …), not by patching the component.
From src/components/nav.tsx. Rendered at the top of every page by __root.tsx. Active route gets text-foreground font-medium; others use text-muted-foreground.
Pattern: <Button size="icon-sm"><ChevronLeft /></Button>. Icons from lucide-react. Building block — for prev/next page UI use <Pagination /> below. Always set aria-label since there's no visible text.
From src/components/pagination.tsx. Controlled: pass page, pageCount, and onChange. Disables prev at 0 and next at the last page. Used by the drill recap modal.
From src/components/segmented-tabs.tsx. Controlled: pass value, onChange, options. The active option takes bg-primary; inactive ones use text-muted-foreground. Used on /import to pick between hanja and vocab imports.
hanja
vocab
vocab
From src/components/deck-card.tsx. Title (display font), optional subtitle (uppercase badge), an array of stat chips (label, value, optional suffix — leave the label empty for a prefixless stat like 181 cards), a primary action button, and an optional delete button in the top-right.
From src/components/collectible-card.tsx. Renders a Card as a hero + reading + gloss tile keyed off DeckKind: hanja gets the royal (deep indigo) shell with hangul as the reading line; vocab gets the hwatu shell in one of three palettes (red, blue, green) deterministically hashed from the hangul, with no reading line. Default mode is the full browse register (idle hwatu breathing, entrance sparkles, hover ripple + glow) used on /decks/$slug. Pass compact for the calm review register (kind-coded shell, 3D tilt, hover lift only) used inside the drill recap modal.
From src/components/line-chart.tsx, wrapping src/components/ui/chart.tsx (shadcn) over Recharts. Two modes: full (grid + axes + tooltip) and sparkline (line only). Pass color as a CSS var so brand tokens flow through. Points with muted: true render hollow — used to distinguish aborted drill sessions in the /stats view.