Design tokens, patterns, and rules extracted from the landing page and app UI. Use this as the single source of truth when building new pages, marketing assets, or evolving the app's visual language.
Dark-mode only. Monochrome-first with a single accent.
| Token | Hex | HSL (approx) | Usage |
|---|---|---|---|
--bg |
#09090b |
240 6% 3.9% |
Page / app background |
--bg-subtle |
#0c0c0e |
240 8% 4.3% |
Subtle depth layer |
--field |
#0d0d0f |
240 7% 5% |
Text-input fill on cards — gently inset below --surface |
--surface |
#111113 |
240 7% 7% |
Cards, panels |
--surface-hover |
#18181b |
240 6% 10% |
Hover state for surfaces |
| Token | Hex | Usage |
|---|---|---|
--border |
#1c1c1f |
Default borders, dividers |
--border-hover |
#27272a |
Hover / focus borders |
| Token | Hex | Usage |
|---|---|---|
--text |
#fafafa |
Primary text, headings |
--text-secondary |
#a1a1aa |
Body copy, descriptions |
--text-tertiary |
#71717a |
Nav links, labels, captions |
--text-muted |
#52525b |
Section labels, disabled text |
| Token | Hex | Usage |
|---|---|---|
--accent |
#a78bfa |
Purple — glow effects, highlights |
--accent-dim |
#7c3aed |
Deeper purple — gradient stops |
--green |
#34d399 |
Success, live indicators, check marks |
The app uses shadcn HSL variables. These align to the same Zinc scale:
| Landing page | App (HSL) | Tailwind class |
|---|---|---|
#09090b |
0 0% 3.9% |
bg-background |
#111113 |
0 0% 7% |
bg-card |
#18181b |
0 0% 14.9% |
bg-secondary / bg-muted |
#fafafa |
0 0% 98% |
text-foreground |
#a1a1aa |
0 0% 63.9% |
text-muted-foreground |
| Context | Font | Fallback stack |
|---|---|---|
| App UI | Inter (variable, woff2) | system-ui, sans-serif |
| Landing page | Inter (Google Fonts, 400–700) | -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif |
| Monospace (both) | JetBrains Mono (app, bundled) | ui-monospace, monospace |
Same font, two delivery methods. The app loads Inter locally from
public/fonts/InterVariable.woff2for offline use. The landing page loads it from Google Fonts CDN for zero-config delivery.
| Element | Size | Weight | Letter-spacing | Notes |
|---|---|---|---|---|
| Hero h1 | clamp(40px, 6vw, 64px) |
700 | -0.04em |
Gradient fill (white → zinc-500) |
| Section title | clamp(28px, 4vw, 36px) |
700 | -0.035em |
|
| Section label | 12px |
600 | 0.08em |
Uppercase, muted |
| Body (hero) | 17px |
400 | normal | --text-secondary |
| Body (cards) | 13px |
400 | normal | --text-secondary, 1.55 line-height |
| Card title | 14px |
600 | -0.01em |
|
| Nav links | 13px |
500 | normal | --text-tertiary |
| Code | 12.5px |
400 | normal | Mono stack |
| Stat value | 28px |
700 | -0.03em |
|
| Stat label | 12px |
500 | 0.06em |
Uppercase, muted |
Four levels. Custom tokens defined in src/index.css via @theme inline using --text-* naming (NOT --font-size-*).
| Token | Size | Tailwind class | Line-height | Role |
|---|---|---|---|---|
| caption | 9px | text-caption |
14px | Dense UPPERCASE-only: collapsible SectionHeader rows, short keyword badges/counters, dense dropdown sub-headers |
| label | 11px | text-label |
16px | Smallest readable size — lowercase form labels, hints, emails, and standalone UPPERCASE field/group labels (e.g. "Authors", "Profile", "Changes") |
| body | 12px | text-xs (built-in) |
16px | Default everything — lists, buttons, inputs |
| title | 14px | text-sm (built-in) |
20px | Commit messages, dialog headings |
Canvas (commit-graph-canvas.tsx) uses matching named constants: SIZE_LABEL, SIZE_BODY and font constant FONT_SANS.
Use font-mono (JetBrains Mono) only for: diff viewer, code/config displays, and code input fields. All other text (commit hashes, file paths, directory paths, repo paths, branch names, commit graph) uses Inter (font-sans).
Rules:
- Never use arbitrary font sizes (
text-[Npx]). Pick from the four levels above. - UPPERCASE tracked labels split by density, not just by case:
text-caption(9px) — the collapsibleSectionHeadercomponent, short keyword badges (e.g. "LFS", "default"), counters, and dense dropdown sub-headers. Never use it for readable lowercase text.text-label(11px) — standalone uppercase field/group labels living in body content (e.g. "Authors" in the commit detail card, "Profile"/"Providers", "Changes", settingsh2/h3group titles). This is also the minimum readable size for lowercase labels, hints, and emails.
- Canvas font sizes must stay in sync with the CSS tokens.
text-xsandtext-smare Tailwind built-ins — do not redefine them.
- Headlines always use negative letter-spacing (
-0.03emto-0.04em). This is what makes them feel "designed" rather than default. - Uppercase labels always use positive letter-spacing (
0.05emto0.08em). Tight uppercase looks cramped. - Body never exceeds 480–540px width. Use
max-widthon paragraph containers. - Gradient text on hero:
linear-gradient(180deg, #fafafa 40%, #71717a 100%)withbackground-clip: text.
Not a strict 4/8px grid, but consistent patterns:
| Context | Value | Usage |
|---|---|---|
| Container padding | 24px horizontal |
All sections |
| Max content width | 1080px |
.container |
| Section padding | 96px vertical |
Between major sections |
| Hero padding | 180px top, 120px bottom |
Above fold breathing room |
| Card inner padding | 28px top/bottom, 24px sides |
Bento cards |
| Gap between cards | 1px (border trick) |
Bento grid |
| Button padding | 10px 20px (primary), 9px 18px (secondary) |
CTAs |
| Element spacing within cards | 10px gap |
Icon → title → description |
All in-app border radii derive from one token — --radius: 0.5rem (8px) in src/index.css. The @theme inline block derives the scale from it. Never use bare rounded (a Tailwind v4 alias hardcoded to 4px that ignores --radius) or arbitrary values like rounded-[3px]. An ESLint rule (no-restricted-syntax) enforces this. Use only these steps:
| Token | Value | Use for |
|---|---|---|
rounded-xs |
3px | Micro / decorative only: inline diff word-highlights, search-match highlight, checkboxes, theme-preview skeleton bars, tiny (≤14px) icon overlays, scrollbar thumb |
rounded-md |
6px | Default — buttons, inputs, menu items, list rows, badges/chips, cards |
rounded-lg |
8px | Containers — dialogs, popovers, toasts, panels |
rounded-xl |
12px | The floating app-shell card only |
rounded-full |
— | Circles & capsule pills — avatars, status dots |
Rules:
rounded-mdis the default for anything that reads as a control, row, chip, badge, or card. When unsure, userounded-md.- The 4px tier is retired:
rounded-smis kept as a token for shadcn primitives only — don't use it directly, pickrounded-xsorrounded-md. - Canvas equivalents (commit graph):
LABEL_RADIUSandROW_RADIUSmirrorrounded-md(6px). Keep them in sync with the token by hand — canvas can't read CSS vars at draw time.
Primary — white on black, bold:
background: #fafafa;
color: #09090b;
font-weight: 600;
border-radius: 8px;
padding: 10px 20px;
/* Hover: translateY(-1px) + subtle white glow shadow */Secondary — ghost with border:
background: transparent;
color: #a1a1aa;
border: 1px solid #1c1c1f;
border-radius: 8px;
padding: 9px 18px;
/* Hover: fill surface, brighten text, brighten border */Rule: Always pair a primary + secondary CTA. Primary uses action verb ("Download"), secondary uses social proof ("Star on GitHub", "View source").
- Background:
--surface(#111113) - No visible border per-card — use
1pxgrid gap with--borderbackground on the parent grid - Outer container gets
border: 1px solid var(--border)+border-radius: 12px+overflow: hidden - Hover: background shifts to
--surface-hover - Wide cards:
grid-column: span 2for emphasis
Small square containers for feature icons:
width: 36px; height: 36px;
background: var(--bg); /* darker than card */
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-tertiary); /* muted icons */Icons are 18×18px Lucide-style strokes (2px stroke width).
font-family: var(--mono);
font-size: 12.5px;
color: var(--text-secondary);
/* Inside a card with copy button absolutely positioned top-right */Pill-shaped, subtle:
border: 1px solid var(--border);
border-radius: 100px;
padding: 5px 14px;
font-size: 12px;
font-weight: 500;
color: var(--text-tertiary);Can include a pulsing dot for "live" indicators:
.dot {
width: 6px; height: 6px;
border-radius: 50%;
background: var(--green);
box-shadow: 0 0 8px rgba(52, 211, 153, 0.4);
animation: pulse 2s ease-in-out infinite;
}In-app badges (status pills, keyword labels, profile tags) use a consistent minimum size.
| Context | Text size | Padding | Examples |
|---|---|---|---|
| Minimum | text-label (11px) |
px-1.5 py-0.5 |
Smallest allowed badge anywhere in the app |
| Inline keywords | text-label |
px-1.5 py-0.5 |
"LFS", "WIP", "default", source badge, version tag |
| Canvas badges | 12px (SIZE_BODY) |
LABEL_PAD_X = 8 |
Branch/tag/stash pills in commit graph |
Rules:
- Never use
text-caption(9px) for badges.text-label(11px) is the minimum badge text size. - Minimum horizontal padding is
px-1.5(6px). Never usepx-1orpy-pxon badges. text-captionremains reserved for column headers and counters only — not badge content.- Canvas badge constants (
LABEL_HEIGHT,LABEL_PAD_X) already meet the minimum.
Round, shrink-0. Two components: AuthorAvatar (commit authors) and ProfileAvatar (profile UI).
| Context | Size | Notes |
|---|---|---|
| Minimum | 20px |
Smallest allowed avatar anywhere in the app |
| Inline / compact UI | 20px |
Commit box author, detail-panel authors, switcher trigger, dropdown items |
| Profile cards / modals | 40px |
Profile modal, settings profiles section |
Rules:
- Never render an avatar smaller than 20px. Below that, initials and icons become unreadable.
- Always pass an explicit
sizeprop — don't rely on defaults for compact contexts. - Avatars are always
rounded-full(circle).
Fixed overlay on body::before, z-index: 9999, pointer-events: none, opacity: 0.025. Uses inline SVG feTurbulence filter (fractalNoise, baseFrequency 0.9, 4 octaves). Adds subtle grain that prevents the dark background from looking like a dead LCD panel.
Behind hero and bottom CTA sections:
background: radial-gradient(
ellipse at center,
rgba(167, 139, 250, 0.08) 0%, /* accent purple */
rgba(124, 58, 237, 0.03) 40%,
transparent 70%
);Absolutely positioned, large (800×600px), centered. Subtle — you feel it more than see it.
background: rgba(9, 9, 11, 0.8); /* bg at 80% opacity */
backdrop-filter: blur(12px);
border-bottom: 1px solid transparent; /* shows on scroll */Hero headline uses vertical gradient from white to zinc-500:
background: linear-gradient(180deg, #fafafa 40%, #71717a 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;Everything uses 0.2s ease (default). Nav border uses 0.3s. No springs, no bounce — keep it sharp and intentional.
3-column grid at desktop. Alternate span-2 cards per row for visual rhythm:
- Row 1:
[span-2] [1] - Row 2:
[1] [span-2] - Row 3:
[1] [1] [1]
Falls to single column on mobile.
Grid-based, not <table>. 3-column (label | us | them). Green checks (✓) vs muted crosses (✗). First column has white text on surface bg, data columns centered.
Every section follows:
[section-label] ← 12px uppercase, muted
[section-title] ← 28-36px bold, tight tracking
[section-desc] ← 15px secondary, max-width constrained
[content] ← cards, grid, table, etc.
Separated by border-top: 1px solid var(--border) + 96px vertical padding.
| Breakpoint | What changes |
|---|---|
768px |
Bento → single column, install cards → stacked, nav links hidden |
480px |
Hero CTAs → full-width stacked, stats → vertical, smaller type |
- Terse over verbose. "Git, without the cognitive overhead" — not "A modern git client designed to reduce complexity."
- Confidence without arrogance. "Fast. Actually." — not "The fastest git client ever built."
- Address the pain. "You shouldn't need a subscription to see your branches."
- No marketing fluff. No "revolutionary", "next-gen", "AI-powered", "blazingly fast". State facts: "10 MB, starts in under a second."
- Imperative CTAs. "Download", "Star on GitHub", "Try it." — not "Get started" or "Learn more".
- "Git client for people who ship"
- "Git, without the cognitive overhead"
- "Same power, none of the bloat"
- "Try it. It's free."
- "No account, no trial, no catch."
| File | What it controls |
|---|---|
docs/index.html |
Landing page (standalone, no build step) |
src/index.css |
App theme tokens (shadcn/ui, Tailwind v4) |
components.json |
shadcn/ui config (Neutral base, Lucide icons) |
public/fonts/ |
Geist + Geist Mono woff2 files |