Introduction
Design today is often a race for attention through saturation. For this site I took the opposite approach: by removing the variable of color, I focus entirely on the fundamental pillars of interface design— composition, spacing, and typography.
The result is a strict but flexible system. Every page type—hero, blog, project detail, gallery, contact—uses the same type scale, the same spacing rhythm, and the same component language. In the sections below, each part of the system is explained with the actual UI shown in place.
01 / Typography
Three typefaces carry the whole system. Space Grotesk handles display and headings—tight tracking, bold weight, optional italic for emphasis. Roboto Flex is used for all body copy so reading stays comfortable. JetBrains Mono is reserved for labels, metadata, code, and form controls: it signals “technical” or “structural” without needing color.
| Role | CSS variable | Tailwind | Usage |
|---|---|---|---|
| Display / headings | --font-heading | font-heading | Titles, section headers, nav brand |
| Body | --font-body | font-body | Paragraphs, descriptions |
| Mono / technical | --font-mono | font-mono | Labels, tags, code, metadata, inputs |
Sizes are tuned for contrast. Hero type goes very large (7xl–9xl) with tight line-height; section titles sit in the 2xl–4xl range; body stays lg–xl with relaxed leading. Mono text is kept small (10px–13px) and uppercase with wide letter-spacing so it reads as supporting detail.
Space Grotesk
Display & headings
JetBrains Mono
Labels, code & metadata
Type scale in use
ABCDEFG
HIJKLMN
The quick brown fox jumps over the lazy dog. A minimalist approach to typography ensures clarity and visual impact.
Scale in Tailwind
Hero: text-7xl md:text-9xl font-heading font-bold leading-[0.85] tracking-tighter
Page title: text-5xl md:text-7xl font-heading font-bold tracking-tighter uppercase
Section: text-3xl font-heading font-bold tracking-tighter uppercase
Card title: text-2xl font-heading font-bold tracking-tighter
Body: text-lg font-body leading-relaxed
Meta: font-mono text-[10px] opacity-40 uppercase tracking-widest02 / Color & hierarchy
The palette is monochrome only. There are no accent colors. Everything is built from foreground and background plus opacity steps (e.g. 40%, 60%, 80%). Borders use a subtle border token; strong emphasis uses full foreground.
Light and dark themes swap background and foreground values; the same opacity scale applies in both. Primary actions invert: solid foreground with background text, and hover often adds italic or a slight scale instead of a new color.
Themes are defined in theme.css (:root and .dark). Use opacity steps like foreground/40, foreground/80 for hierarchy.
03 / Layout & rhythm
Content width is capped at max-w-5xl for the main app and max-w-3xl for long-form (blog, contact). Sections are separated with large vertical gaps (space-y-32, py-20–py-32) and horizontal borders (border-b border-border) so the page breathes.
Grids are 2- or 3-column at md and up, with consistent gaps (12–24). Galleries use aspect ratios (e.g. 4/5 for project cards, 21/9 for hero images) so layout stays predictable. A 12-column grid underlies the structure but isn’t visually dominant.
12-column base grid
12-COLUMN GRID — CONSISTENT ACROSS BREAKPOINTS
Key tokens
- Nav-to-content gap:
--content-offset-top-mobile(10rem),--content-offset-top-desktop(14rem). Applied onmainaspt-[var(--content-offset-top-mobile)] md:pt-[var(--content-offset-top-desktop)]in layout. - Content width:
max-w-5xlfor main app shell;max-w-3xlfor long-form (blog, contact). - Section spacing:
space-y-32between major sections;py-20–py-32for vertical rhythm;border-b border-borderfor section separation.
04 / Components
Buttons, inputs, cards, and badges share the same language: borders, uppercase mono labels, and hover states that use foreground/background inversion or underline. Nothing is rounded; corners stay sharp. Primary buttons are solid foreground with background text and hover:italic; secondary is outlined and inverts on hover. Inputs are underline-only (no filled box) with mono placeholder text.
Buttons
Inputs
Cards & containers
INFORMATION ARCHITECTURE
Every element is placed with mathematical precision to ensure optimal user flow and aesthetic balance.
Badges, tags & pills
Snippets
Primary button
<button className="px-8 py-3 bg-foreground text-background font-mono text-xs tracking-widest uppercase hover:italic transition-all">
Primary Action
</button>Secondary button
<button className="px-8 py-3 border border-border font-mono text-xs tracking-widest uppercase hover:bg-foreground hover:text-background transition-all">
Secondary
</button>Ghost link
<button className="px-4 py-3 flex items-center gap-2 font-mono text-xs tracking-widest uppercase hover:underline underline-offset-4 transition-all">
Ghost Link <ArrowUpRight size={14} />
</button>Icon button
<button className="p-2 border border-border hover:bg-foreground hover:text-background transition-colors" aria-label="...">
<Icon size={18} />
</button>Underline input (with label)
<div className="space-y-2">
<label className="font-mono text-[10px] opacity-40 uppercase">Name</label>
<input type="text" placeholder="Your name" className="w-full bg-transparent border-b border-border py-3 focus:border-border outline-none transition-colors font-mono text-sm" />
</div>Bordered card (hover invert)
<div className="border border-border p-8 space-y-4 hover:bg-foreground hover:text-background transition-all group">
<div className="w-12 h-12 border border-border bg-background text-foreground flex items-center justify-center">...</div>
<h4 className="text-2xl font-heading font-bold tracking-tighter">TITLE</h4>
<p className="text-sm opacity-60 group-hover:opacity-100 leading-relaxed">Description.</p>
</div>Badge
<span className="px-2 py-0.5 border border-border font-mono text-[9px] tracking-[0.2em] uppercase opacity-60">
STABLE
</span>Cards use a single border and optional hover state that inverts foreground/background so the whole block becomes a call-to-action. Badges and tags are small, bordered, mono, and uppercase—used for categories, status, and tech stack.
05 / Page patterns
Reusable layouts for hero, blog, project detail, gallery, and contact. Each uses the same type scale, spacing, and borders.
Hero (landing)
Two-column grid: display headline left, lead + mono pills right. grid md:grid-cols-2 gap-12 items-end. Section: pt-20 pb-32 border-b border-border.
Blog / article
Wrapper max-w-3xl mx-auto space-y-24. Header: meta line (font-mono 10px) + title (5xl–7xl) + subtitle. Sections space-y-12, dividers border-t border-border.
Entity (e.g. project detail)
Back link (mono, uppercase), large italic title (6xl–9xl), meta row with icons. Hero image aspect-[21/9]. Two-column: grid md:grid-cols-3 gap-16, main content md:col-span-2, tags and links on the right.
Gallery
Section header with title + index (mono). Grid md:grid-cols-2 gap-x-12 gap-y-24. Card aspect-[4/5], image group-hover:scale-105 grayscale hover:grayscale-0.
Contact
Title (6xl–8xl italic) + mono subtitle. Two columns: info (Direct, Location, Social) + form. Inputs underline-only; submit primary button (bg-foreground text-background).
06 / Motion
Use motion/react for entrance and hover. No new colors—motion supports hierarchy and feedback.
- Fade/slide in:
initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }}withtransition. - Stagger:
delay: index * 0.1,whileInView,viewport={{ once: true }}. - Hover:
hover:italic,group-hover:scale-105,hover:grayscale-0. - Slide-swap text: Two stacked
motion.divs—oney: 0 → "-100%", oney: "100%" → 0; use for nav or card titles. - Active indicator:
motion.divwithlayoutId="activeTab"so the dot animates between nav tabs.
Checklist for new work
Before shipping a new page or component, confirm:
- Use only
font-heading,font-body,font-monoand the existing scale. - Use theme colors (background, foreground, border) and opacity; no new hues.
- Match section spacing (
space-y-32,py-20–py-32) and content width (max-w-3xl/max-w-5xl). - Buttons and inputs use mono, uppercase, tracking-widest where specified.
- Cards and galleries use border, aspect ratios, and hover (italic/scale/overlay) as in the system.
- Nav and footer stay consistent with existing layout and typography.