agamarora.com v2. One element at a time. Research, reason, lock, move on.
Design system for agamarora.com v2.
12 years across analytics, gaming, D2C retail, logistics, and AI. Looks like chaos on a resume. Makes sense as convergence. This site makes that visible.
Quality bar: Stripe, Linear. Not copying, targeting the same audience. The site is the first artifact they judge.
Every decision made with AI (Claude Code + gstack). None delegated. AI researches, generates specimens, renders demos. I choose, refine, lock. The design system proves AI doesn't replace taste, it amplifies it.
Each section starts unlocked, goes through research and exploration, gets locked with rationale and usage rules. Agents that build the site read these rules. Nothing is arbitrary.
Research. Reason. Lock. Move on.
n-900 #E8E4DF, Primary (15.6:1 AAA)
n-800 #C8C0B8, Secondary (11.0:1 AAA)
n-700 #A59D95, Tertiary (7.4:1 AAA)
n-600 #8A817A, Muted (5.2:1 AA)
n-500 #6B6359, Decorative only (3.4:1 AA-lg)
n-400 #403A33, Disabled / invisible (1.8:1)
n-50 #0B0A09, Primary (17.9:1 AAA)
n-200 #201D18, Secondary (15.2:1 AAA)
n-400 #403A33, Tertiary (10.1:1 AAA)
n-500 #6B6359, Muted (5.3:1 AA)
n-600 #8A817A, Decorative (3.4:1 AA-lg)
n-700 #A59D95, Disabled (2.4:1)
| Token | Hex | Dark role | Light role | vs Dark | vs Light |
|---|---|---|---|---|---|
| n-50 | #0B0A09 | Background | Primary text | 1.0:1 | 17.9:1 |
| n-100 | #12110F | Surface | , | 1.1:1 | 17.0:1 |
| n-150 | #191714 | Elevated | , | 1.1:1 | 16.1:1 |
| n-200 | #201D18 | Border | Secondary text | 1.2:1 | 15.2:1 |
| n-300 | #2D2924 | Heavy border | , | 1.4:1 | 13.0:1 |
| n-400 | #403A33 | Subtle divider | Tertiary text | 1.8:1 | 10.1:1 |
| n-500 | #6B6359 | Decorative (3.4 AA-lg) | Muted text | 3.4:1 | 5.3:1 |
| n-600 | #8A817A | Muted text (AA) | Decorative (3.4 AA-lg) | 5.2:1 | 3.4:1 |
| n-700 | #A59D95 | Secondary text | , | 7.4:1 | 2.4:1 |
| n-800 | #C8C0B8 | Strong secondary | , | 11.0:1 | 1.6:1 |
| n-900 | #E8E4DF | Primary text | Surface | 15.6:1 | 1.1:1 |
| n-950 | #F5F3EF | , | Background | 17.9:1 | 1.0:1 |
| ACCENT | |||||
| gold | #E5A54B | Accent, links, mark | Buttons, large marks | 9.3:1 | 1.9:1 |
| gold-text | #7A5C12 | , | Links, gold text | , | 5.6:1 |
| SEMANTIC | |||||
| success | #3DA86B | 6.6:1 AA | #2D7A4E 4.7:1 | 6.6:1 | 4.7:1 |
| error | #D4564E | 4.9:1 AA | #A33F39 5.7:1 | 4.9:1 | 5.7:1 |
| info | #5B8FC7 | 5.8:1 AA | #3D6A94 5.1:1 | 5.8:1 | 5.1:1 |
Build dark first. Background is n-50 #0B0A09. Live site is dark-only. Light mode is documented for print contexts (resume PDF) and as future-state spec — same tokens, reversed (n-950 becomes bg, n-50 becomes text).
On dark:
On light: use n-50, n-200, n-400, n-500 for the same hierarchy (reversed).
Gold #E5A54B is for interactive or identity elements only: the aa. mark, links, buttons, active states. If gold appears on something the user can't click or that doesn't represent the brand, it's wrong.
On light backgrounds: use #7A5C12 for gold text (passes AA). Use #E5A54B only on buttons or elements larger than 24px.
Don't use more than 3 surface levels on one screen.
n-200 #201D18 for standard borders. n-300 #2D2924 for emphasized dividers. Never use a border heavier than n-400.
Success/error/warning/info colors are for status communication only: form validation, notifications, badges. Never use them decoratively. On dark mode use the bright variants. On light mode use the darkened variants (see token table).
If you're unsure which shade to use, start with the highest contrast option that isn't primary text. n-700 is the safest "I need readable text but it's not the main thing" choice on dark. n-900 is always safe for anything the user needs to read.
| Element | Space after | Space before (from body) | Logic |
|---|---|---|---|
| Display | 1.5rem (24px) | , | Hero, first element |
| H1 | 1.25rem (20px) | , | Page title, near top |
| H2 | 1rem (16px) | 3rem (48px) | New section break |
| H3 | 0.75rem (12px) | 2rem (32px) | Minor break |
| Body / Body lg | 1rem (16px) | , | Paragraph spacing |
| Small | 0.5rem (8px) | , | Compact |
| Caption | 0.25rem (4px) | , | Minimal |
Principle: space before headings > space after. Headings belong to the content below them, not above (Gestalt proximity).
| Token | rem | px | clamp() | Weight | Tracking | LH | Dark color | Light color |
|---|---|---|---|---|---|---|---|---|
| display | 4.209 | 67 | clamp(2.25rem, 5vw+1rem, 4.209rem) | 700 | -0.025em | 1.05 | n-900 #E8E4DF | n-50 #0B0A09 |
| h1 | 3.157 | 50 | clamp(1.875rem, 4vw+0.75rem, 3.157rem) | 700 | -0.02em | 1.1 | n-900 #E8E4DF | n-50 #0B0A09 |
| h2 | 2.369 | 38 | clamp(1.5rem, 3vw+0.5rem, 2.369rem) | 600 | -0.015em | 1.15 | n-800 #C8C0B8 | n-200 #201D18 |
| h3 | 1.777 | 28 | clamp(1.25rem, 2vw+0.5rem, 1.777rem) | 600 | -0.01em | 1.2 | n-700 #A59D95 | n-300 #2D2924 |
| body-lg | 1.333 | 21 | clamp(1.125rem, 1vw+0.875rem, 1.333rem) | 400 | 0 | 1.55 | n-800 #C8C0B8 | n-300 #2D2924 |
| body | 1.0 | 16 | 1rem (fixed) | 400 | 0 | 1.6 | n-700 #A59D95 | n-400 #403A33 |
| small | 0.75 | 12 | 0.75rem (fixed) | 500 | +0.01em | 1.5 | n-600 #8A817A | n-500 #6B6359 |
| caption | 0.6875 | 11 | 0.6875rem (fixed) | 500 | +0.08em | 1.45 | n-500 #6B6359 | n-500 #6B6359 |
Scale ratio: Perfect Fourth (1.333). Base: 16px (1rem). Floor: 11px. Max body width: 65ch.
Satoshi for everything. Weight + color token + size creates hierarchy. Never add another sans-serif font. The fallback stack is: system-ui, -apple-system, 'Segoe UI', sans-serif
Never use Patrick Hand for headings, body, or UI text. It appears exclusively in the aa. and /aa marks. Mixing it with body text kills both the mark's specialness and text readability.
Labels, timestamps, code, technical metadata, section headers in the moodboard. Weights 400 (default) and 500 (emphasis). Plus weight 300 used exclusively for the / cursor in the /aa mark. Always pair with loose tracking (+0.05em to +0.12em) when in uppercase.
Display: -0.025em. H1: -0.02em. Body: 0. Small: +0.01em. Caps: +0.08em. This is optical compensation from Bringhurst, not style preference. No exceptions.
Display: 1.05. H1: 1.1. Body: 1.6. At large sizes the eye tracks easily. At small sizes lines blur together without extra leading.
Paragraphs and body-lg never wider than 65 characters (max-width: 65ch). Headings can go wider. Too wide and the eye loses its place on the return sweep (Bringhurst recommends 45-75ch).
700 = headings (display, h1). 600 = subheadings (h2, h3) and inline emphasis in body. 500 = labels and small text emphasis. 400 = body text. Don't use 700 for body. Use 600 (not 700) for bold words within paragraphs.
Display/H1/H2/H3/Body-lg use clamp() for responsive scaling. Body/small/caption are fixed rem values because they're already at readable minimums. Use the clamp values from the token reference, don't invent new ones.
4px base unit. 11-token scale from 2px to 128px. Spacious density for editorial portfolio. Semantic aliases for common patterns. Informed by Ant Design, Vercel/Geist, Radix, and Material Design 3.
Base: 4px. Scale: 2, 4, 8, 12, 16, 24, 32, 48, 64, 96, 128. Jumps accelerate as values grow (matches human spatial perception). Informed by Ant Design (4px base), Vercel/Geist (4-128px range), Radix (4px base, 9 steps).
| Alias | Resolves to | Value | Usage |
|---|---|---|---|
| --gap-tight | --space-3 | 8px | Icon + label, inline elements |
| --gap-default | --space-5 | 16px | Stacked siblings, form fields |
| --gap-loose | --space-6 | 24px | Group-to-group within section |
| --padding-element | --space-4 | 12px | Buttons, tags, small components |
| --padding-card | --space-7 | 32px | Cards, panels, content containers |
| --padding-section | --space-8 | 48px | Page sections, vertical rhythm |
| --padding-page | --space-10 | 96px | Hero, viewport sections, top-level |
| --margin-page-x | responsive | 24/48/96px | Horizontal page margins (mobile/tablet/desktop) |
Agents use aliases, not raw tokens. --padding-card is intent, --space-7 is implementation. The alias layer means we can adjust density globally without touching every component.
| Token | Desktop (1024px+) | Tablet (768px) | Mobile (<768px) |
|---|---|---|---|
| 1-6 | 2-24px | same | same (fixed) |
| 7 | 32px | 28px | 24px |
| 8 | 48px | 40px | 32px |
| 9 | 64px | 48px | 40px |
| 10 | 96px | 72px | 48px |
| 11 | 128px | 96px | 64px |
Tokens 1-6 are fixed (already at perceptual minimums). Tokens 7-11 compress by ~25% per breakpoint step. Same Gestalt relationships, less absolute space. Like the type scale's clamp().
Compact = SaaS dashboard. Spacious = editorial portfolio. Same content, completely different signal. Generous spacing reads as confidence and taste. That's the Stripe/Linear quality bar.
Every margin, padding, and gap uses a named token or semantic alias. Never padding: 20px. Always padding: var(--space-6) or padding: var(--padding-card).
Elements that belong together get smaller gaps (space-3 to space-5). Unrelated groups get larger gaps (space-7+). The gap size IS the relationship signal. This is the same principle from the typography section applied to all layout.
Prefer semantic aliases (--padding-card, --gap-default) over raw tokens (--space-7, --space-5). Aliases express intent. If density changes later, only the alias resolution changes, not every component.
Section padding is --padding-section (48px) minimum on desktop, compressed to 32px on mobile. The convergence scroll sections use --padding-page (96px) to center content in viewport-height frames.
Horizontal page margins: --space-6 (24px) mobile, --space-8 (48px) tablet, --space-10 (96px) desktop. Content floats in a centered column. Never edge-to-edge.
--space-1 (2px) is for optical adjustments: nudging alignment, border-adjacent corrections. Never use it for layout spacing. Minimum layout gap is --space-2 (4px).
Vertical spacing between text elements (heading margins, paragraph gaps) follows the typography section's rhythm table. This spacing system covers everything else: component padding, layout gaps, section breaks.
Spacious density means: if you're choosing between two adjacent tokens, pick the larger one. Too much space reads as editorial confidence. Too little reads as cramped. The Stripe/Linear pages all err on the side of generous.
The starter aliases above are not exhaustive. When building a new component that will be reused, create a semantic alias for its spacing. Naming convention: --{padding|gap|margin}-{component}. Examples: --padding-nav, --gap-grid, --margin-footer. Always resolve to an existing --space-N token. Never alias to a raw pixel value. Register new aliases in the CSS :root block alongside the originals so they're discoverable.
If a component is removed, remove its alias too. Dead aliases are clutter. If you need to change the density of a component, change the alias resolution (e.g., --padding-card: var(--space-6) instead of var(--space-7)), never override inline. The :root block is the single source of truth for all alias-to-token mappings.
Three named width tiers instead of a grid system. Content-based breakpoints aligned to where spacing and typography already compress. Manuscript layout for sequential narrative. Informed by Bringhurst (measure theory), Muller-Brockmann (grid theory), Tschichold (proportional canons), NN/g (scroll attention + visual anchoring), Gestalt psychology (proximity ratios).
This is where sustained prose lives. At ~65ch in Satoshi at 16px, it sits within Bringhurst's ideal reading measure of 45-75 characters per line. The eye's return sweep stays accurate, reducing regressions and cognitive load. Chapter text, body paragraphs, about sections.
Structural content: hero headings, cards, asymmetric layouts. 1.5x narrow.
Outer content bound. Beyond this: only background color, SVG layers, full-bleed decoration. NN/g: visual anchoring breaks above ~1400px.
Breakpoints are set where the layout actually breaks, not where devices start. Each threshold marks a shift in which perceptual constraint dominates: touch targets below 640px, reading measure at 1024px, spatial luxury at 1440px.
Muller-Brockmann's grid theory: grids reduce cognitive load by creating predictable spatial relationships for parallel content. A manuscript grid (single column with margins) is correct for sequential, linear content.
This product is a scroll-driven narrative. One thing at a time. No sidebars, no parallel content streams, no data tables. Width tiers + spacing tokens handle all layout needs.
If a future component needs a grid (card arrangement, bento layout), use CSS Grid auto-fit with spacing tokens ad hoc. Do not pre-build a grid system for hypothetical needs.
Gestalt proximity: the brain reads spatial distance as semantic distance. The ratio between internal spacing and section spacing must be at least 3:1 to signal a clear grouping change. NN/g scroll attention data: generous section spacing creates re-engagement "beats" but too much triggers the "illusion of completeness" where users think the page is done.
100vh chapter sections: 96px padding top/bottom on desktop, compresses to 48px on mobile via spacing responsive rules.
All containers are horizontally centered (margin-inline: auto). Within the default container (1080px), text blocks can be offset left or right. The narrow column (720px) floats within the default, giving ~180px of offset room per side.
The SVG convergence layer is position: fixed, full viewport. Its spatial logic is independent of content containers.
This gives asymmetry within structure. Tschichold: white space is an active element, not a passive background. The offset room is intentional, not leftover.
All width tiers collapse. Content is fluid at 100% minus inline padding. Fixed inline padding of --space-6 (24px) on each side.
At 375px (iPhone SE/13 mini): 327px content width, ~36ch in Satoshi. Below Bringhurst's 45ch minimum. This is accepted: Dyson and Shaikh research shows users adapt to shorter line lengths on mobile, reading in shorter bursts. Content structure matters more than measure at this width.
Spacing tokens 7-11 compress ~25% per the spacing spec. Section padding drops from 96px to 48px. No offset/asymmetry: text is left-aligned, edge-to-edge within padding.
No text, image, card, or interactive element wider than 1320px. Full-bleed backgrounds (color, SVG, gradients) are fine. Content is not background.
Any sustained reading (paragraphs, chapter text, about sections) must be constrained to 720px / ~65ch. This is a readability constraint from measure theory, not a style preference.
Use the documented breakpoints: --bp-small (640px), --bp-medium (1024px), --bp-large (1440px). Section 04 spacing also uses --bp-tablet (768px) as a compression threshold. CSS @media can't read custom properties, so write the literal value with the token name in a comment beside it. Do not invent device-specific breakpoints (375px etc.). If the layout breaks at a width not covered, the content is too wide for its container — fix the content.
Do not create grid utility classes or a column system. If a component needs columns, use CSS Grid auto-fit with spacing tokens inline. The product is sequential narrative, not a dashboard.
Gestalt proximity requires a clear ratio gap between "same group" and "different group" spacing. Internal: --space-5 (16px). Between sections: --space-9 to --space-10 (64-96px). Never use the same spacing token for both.
Below --bp-small (640px), all containers are width: 100%; padding-inline: var(--space-6). No offsets, no asymmetry. Left-aligned, edge-to-edge within padding.
Containers are always centered. Asymmetry happens within the container via margin-inline offsets. The narrow column has ~180px of offset room within the default container. Use this for alternating chapter layouts.
Sections can be min-height: 100vh for scroll-driven chapters, but content should not depend on exact viewport height. Use padding and vertical centering. Let content determine natural height, constrained by min-height for the scroll mechanic.
4-step scale aligned to spacing base. Cognitive research (Bar & Neta, 2006): humans prefer curved contours, sharp corners activate threat detection. Small radii = refined/intentional. Large radii = friendly/casual. For warm editorial: enough softness to match Satoshi's humanist character without drifting into consumer-app territory.
8px is the primary default. Aligns with Stripe/Linear/Vercel's "premium default." Reads as intentionally soft, not accidentally sharp. 4px base matches spacing grid.
Easing and duration conventions rooted in physical-world perception (Disney's 12 Principles, 1981). Objects decelerate into rest, so ease-out on enter feels natural. Duration thresholds from Miller (1968) and Nielsen (1993): <100ms = instant, 100-300ms = responsive, 300-500ms = cinematic, >500ms = narrative. The expressive decelerate curve (0.16, 1, 0.3, 1) pairs with the warm-but-precise aesthetic.
International Typographic Style (Swiss Design, 1950s): in text-first layouts, visual elements create rhythm and breathing room, not compete with content. For dark editorial: the risk is either looking empty or looking like a gaming site. Subtle texture makes flat digital surfaces feel like a material (Julesz, 1981, pre-attentive texture processing).
Portfolio sites are transient interfaces (Alan Cooper, "About Face"): users scan, evaluate, and leave. The component set optimizes for reading flow and scannability, not interaction variety. Build only what the scroll-driven narrative demands. Every component you don't build is a design decision you don't have to maintain.
NN/g tone research (2016): for professional credibility with enterprise audiences, the highest-trust combination is serious + casual + respectful + matter-of-fact. Tone and typography must match: Satoshi's geometric-humanist character pairs with writing that is clear and direct but not robotic. The formula: write like you're explaining your work to a sharp peer over coffee.
The audience reads precise documentation daily (Anthropic, Stripe, Linear hiring managers). They value:
Examples:
Not: "I dramatically improved the delivery experience"
But: "Reduced delivery time from 60 days to 7. NPS went from 3.6 to 4.7."
Not: "Selected Projects & Case Studies"
But: "Work"
Design system complete. All 10 sections locked. Item 11 is a living collection that grows with inspiration.
Compositional techniques collected from real sites that push craft. Not tokens or rules, spatial ideas, motion patterns, and layout approaches that inform how the site FEELS. This section grows as inspiration is found. Each pattern has a live demo, source attribution, and implementation notes.
Oversized ghost text creates spatial depth. Content cards sit ON TOP of the background word, breaking the flat plane. The background text is not decoration, it's a section label scaled to architecture. Color: #151515 or lower, visible enough to read but never competing with foreground content.
Elements exist at different distances from the viewer. On scroll, layers move at different speeds creating the illusion of depth. Not the 2013 "parallax website" gimmick, this is spatial design. The page is a space you move THROUGH, not a surface you move UP. Bear.plus achieves this with Three.js for 3D objects and GSAP ScrollTrigger for 2D layers at different scroll speeds.
This section grows as you discover inspiration. Each pattern gets a number (11.N), a live demo, source attribution, and implementation notes.