Skip to content

Commit 5149e09

Browse files
committed
refactor: centralize design system with tokens and shared components
Expand app.css with 60+ design tokens: - Colors: dark mode + light section tokens (eliminates hardcoded values) - Typography: full scale with --fs-hero through --fs-footer-copy - Spacing: --space-xs through --space-7xl - Layout: --max-w, --max-w-prose, --nav-h, --z-nav - Transitions, font-weights, line-heights, letter-spacing Create shared Svelte components: - ProductHero.svelte: reusable product page hero - Overview.svelte: white section with spec table - PillarList.svelte: numbered feature lists - CtaSection.svelte: call-to-action blocks Refactor product pages to use shared components: - augmentum, visage, mrhaven: ~75 lines each (was ~370) - Eliminates ~900 lines of duplicated CSS Update all remaining files to use design tokens: - Home page, ecosystem, nav, layout, error page Update CLAUDE.md with comprehensive design system documentation
1 parent 98a7bd0 commit 5149e09

File tree

14 files changed

+886
-1186
lines changed

14 files changed

+886
-1186
lines changed

CLAUDE.md

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,111 @@ Marketing site for Sovren Software at `sovren.software`.
1414

1515
## Design System
1616

17+
Centralized in `src/app.css` with 60+ design tokens. All styles reference tokens — no magic numbers in components.
18+
19+
### Colors
20+
21+
**Dark mode (default):**
1722
```
1823
--bg: #000000
24+
--surface: #080808
25+
--surface-2: #111111
26+
--border: rgba(255,255,255,0.1)
1927
--text-primary: #ffffff
20-
--text-secondary: rgba(255,255,255,0.6)
28+
--text-secondary: rgba(255,255,255,0.55)
2129
--text-muted: rgba(255,255,255,0.25)
22-
--border: rgba(255,255,255,0.1)
23-
--max-w: 1200px
24-
--font-mono: 'Geist Mono Variable', monospace
30+
--text-ghost: rgba(255,255,255,0.12)
31+
```
32+
33+
**Light sections (overview/CTA blocks):**
34+
```
35+
--light-bg: #ffffff
36+
--light-border: #e5e5e5
37+
--light-text-primary: #000000
38+
--light-text-body: #333333
39+
--light-text-secondary: #555555
40+
--light-text-muted: #999999
41+
--light-text-dim: #888888
42+
```
43+
44+
### Typography
45+
46+
| Token | Size | Usage |
47+
|-------|------|-------|
48+
| `--fs-hero` | clamp(3.5rem, 11vw, 8rem) | Home hero H1 |
49+
| `--fs-hero-product` | clamp(4rem, 12vw, 9rem) | Product hero H1 (Augmentum) |
50+
| `--fs-hero-large` | clamp(5rem, 18vw, 12rem) | Product hero H1 (Visage, MrHaven) |
51+
| `--fs-h2` | clamp(2rem, 5vw, 4rem) | CTA section headings |
52+
| `--fs-h2-large` | clamp(2.5rem, 6vw, 5rem) | Ecosystem closing H2 |
53+
| `--fs-thesis` | clamp(1.75rem, 3.5vw, 3.25rem) | Home thesis statement |
54+
| `--fs-lead` | clamp(1.3rem, 2.5vw, 1.7rem) | Overview lead paragraph |
55+
| `--fs-tagline` | clamp(0.95rem, 2vw, 1.1rem) | Hero taglines |
56+
| `--fs-pillar-title` | clamp(0.95rem, 1.5vw, 1.15rem) | Pillar labels |
57+
| `--fs-body` | 0.9rem | Body text |
58+
| `--fs-body-sm` | 0.875rem | Compact body |
59+
| `--fs-body-xs` | 0.85rem | Footnotes, small text |
60+
| `--fs-spec` | 0.72rem | Spec table values |
61+
| `--fs-label` | 0.65rem | Category labels |
62+
| `--fs-label-sm` | 0.62rem | Section labels |
63+
| `--fs-label-xs` | 0.58rem | Footer column labels |
64+
| `--fs-btn` | 0.7rem | Buttons |
65+
| `--fs-nav` | 0.65rem | Navigation links |
66+
| `--fs-wordmark` | 0.875rem | Logo/wordmark |
67+
68+
**Line-height tokens:** `--lh-tight`, `--lh-heading`, `--lh-default`, `--lh-relaxed`, `--lh-loose`
69+
70+
**Letter-spacing tokens:** `--ls-tight`, `--ls-default`, `--ls-moderate`, `--ls-wide`, `--ls-wider`, `--ls-widest`
71+
72+
**Font-weight tokens:** `--fw-normal`, `--fw-medium`, `--fw-semibold`, `--fw-bold`
73+
74+
### Spacing
75+
76+
| Token | Value |
77+
|-------|-------|
78+
| `--space-xs` | 0.25rem |
79+
| `--space-sm` | 0.5rem |
80+
| `--space-md` | 0.75rem |
81+
| `--space-lg` | 1rem |
82+
| `--space-xl` | 1.5rem |
83+
| `--space-2xl` | 2rem |
84+
| `--space-3xl` | 2.5rem |
85+
| `--space-4xl` | 3rem |
86+
| `--space-5xl` | 4rem |
87+
| `--space-6xl` | 6rem |
88+
| `--space-7xl` | 7rem |
89+
90+
**Section padding:** `--pad-section` (6rem 2.5rem), `--pad-section-lg` (7rem 2.5rem), `--pad-hero` (5rem 2.5rem)
91+
92+
### Layout
93+
2594
```
95+
--max-w: 1200px /* Container max-width */
96+
--max-w-prose: 760px /* Prose blocks (manifesto) */
97+
--max-w-body: 480px /* Body paragraphs */
98+
--max-w-tagline: 600px /* Tagline blocks */
99+
--nav-h: 60px /* Navigation height */
100+
--z-nav: 100 /* Navigation z-index */
101+
```
102+
103+
### Shared Components
104+
105+
Reusable Svelte components in `src/lib/`:
106+
107+
| Component | Props | Purpose |
108+
|-----------|-------|---------|
109+
| `ProductHero.svelte` | title, category, status, tagline, size | Product page hero section |
110+
| `Overview.svelte` | lead, specs[], stackNote, slot | White-background overview with spec table |
111+
| `PillarList.svelte` | label, pillars[] | Numbered feature list ("HOW IT WORKS") |
112+
| `CtaSection.svelte` | title, body, actions[] | White-background CTA with buttons |
113+
114+
**Product pages** use all four components with zero local CSS. **Home/Ecosystem** retain unique layouts but use design tokens throughout.
115+
116+
### Rules
26117

27-
White `#ffffff` contrast sections are used for overview/CTA blocks within product pages. Never add a second typeface. Never use color for emphasis — use weight and letter-spacing only.
118+
- Never add a second typeface
119+
- Never use color for emphasis — use weight and letter-spacing only
120+
- White contrast sections use light tokens, never hardcoded values
121+
- All transitions: `var(--transition-fast)` (0.15s)
28122

29123
## Routing
30124

src/app.css

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,116 @@
66
font-display: swap;
77
}
88

9+
/* ═══════════════════════════════════════════
10+
DESIGN TOKENS
11+
═══════════════════════════════════════════ */
12+
913
:root {
14+
/* ── Colors: Dark mode (default) ── */
1015
--bg: #000000;
1116
--surface: #080808;
1217
--surface-2: #111111;
1318
--border: rgba(255, 255, 255, 0.1);
1419
--text-primary: #ffffff;
1520
--text-secondary: rgba(255, 255, 255, 0.55);
1621
--text-muted: rgba(255, 255, 255, 0.25);
22+
--text-ghost: rgba(255, 255, 255, 0.12);
23+
24+
/* ── Colors: Light sections (inverted) ── */
25+
--light-bg: #ffffff;
26+
--light-border: #e5e5e5;
27+
--light-text-primary: #000000;
28+
--light-text-body: #333333;
29+
--light-text-secondary: #555555;
30+
--light-text-muted: #999999;
31+
--light-text-dim: #888888;
32+
33+
/* ── Typography ── */
1734
--font-mono: 'Geist Mono', ui-monospace, monospace;
35+
36+
--fs-hero: clamp(3.5rem, 11vw, 8rem);
37+
--fs-hero-product: clamp(4rem, 12vw, 9rem);
38+
--fs-hero-large: clamp(5rem, 18vw, 12rem);
39+
--fs-h2: clamp(2rem, 5vw, 4rem);
40+
--fs-h2-large: clamp(2.5rem, 6vw, 5rem);
41+
--fs-thesis: clamp(1.75rem, 3.5vw, 3.25rem);
42+
--fs-lead: clamp(1.3rem, 2.5vw, 1.7rem);
43+
--fs-tagline: clamp(0.95rem, 2vw, 1.1rem);
44+
--fs-pillar-title: clamp(0.95rem, 1.5vw, 1.15rem);
45+
--fs-body: 0.9rem;
46+
--fs-body-sm: 0.875rem;
47+
--fs-body-xs: 0.85rem;
48+
--fs-spec: 0.72rem;
49+
--fs-label: 0.65rem;
50+
--fs-label-sm: 0.62rem;
51+
--fs-label-xs: 0.58rem;
52+
--fs-nav: 0.65rem;
53+
--fs-wordmark: 0.875rem;
54+
--fs-btn: 0.7rem;
55+
--fs-scroll-hint: 0.65rem;
56+
--fs-footer-link: 0.68rem;
57+
--fs-footer-copy: 0.6rem;
58+
59+
--lh-tight: 0.95;
60+
--lh-heading: 1.05;
61+
--lh-default: 1.6;
62+
--lh-relaxed: 1.75;
63+
--lh-loose: 1.85;
64+
65+
--ls-tight: -0.01em;
66+
--ls-default: 0.02em;
67+
--ls-moderate: 0.04em;
68+
--ls-wide: 0.1em;
69+
--ls-wider: 0.18em;
70+
--ls-widest: 0.25em;
71+
72+
--fw-normal: 400;
73+
--fw-medium: 500;
74+
--fw-semibold: 600;
75+
--fw-bold: 700;
76+
77+
/* ── Spacing ── */
78+
--space-xs: 0.25rem;
79+
--space-sm: 0.5rem;
80+
--space-md: 0.75rem;
81+
--space-lg: 1rem;
82+
--space-xl: 1.5rem;
83+
--space-2xl: 2rem;
84+
--space-3xl: 2.5rem;
85+
--space-4xl: 3rem;
86+
--space-5xl: 4rem;
87+
--space-6xl: 6rem;
88+
--space-7xl: 7rem;
89+
90+
--pad-section: 6rem 2.5rem;
91+
--pad-section-lg: 7rem 2.5rem;
92+
--pad-hero: 5rem 2.5rem;
93+
94+
/* ── Layout ── */
1895
--max-w: 1200px;
96+
--max-w-prose: 760px;
97+
--max-w-body: 480px;
98+
--max-w-tagline: 600px;
99+
--nav-h: 60px;
100+
101+
/* ── Transitions ── */
102+
--transition-fast: 0.15s;
103+
--ease-default: ease;
104+
105+
/* ── Z-index ── */
106+
--z-nav: 100;
107+
108+
/* ── Breakpoints (reference only — used in @media) ── */
109+
/* --bp-mobile: 768px; */
110+
111+
/* ── Buttons ── */
112+
--btn-pad: 0.85rem 1.75rem;
19113
}
20114

115+
/* ═══════════════════════════════════════════
116+
RESET
117+
═══════════════════════════════════════════ */
118+
21119
*, *::before, *::after {
22120
box-sizing: border-box;
23121
margin: 0;
@@ -33,7 +131,7 @@ body {
33131
background-color: var(--bg);
34132
color: var(--text-primary);
35133
font-family: var(--font-mono);
36-
line-height: 1.6;
134+
line-height: var(--lh-default);
37135
-webkit-font-smoothing: antialiased;
38136
-moz-osx-font-smoothing: grayscale;
39137
}

src/lib/CtaSection.svelte

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<script>
2+
/** @type {string} */
3+
export let title;
4+
/** @type {string} */
5+
export let body;
6+
/** @type {Array<{label: string, href: string, style?: 'primary'|'secondary', external?: boolean}>} */
7+
export let actions = [];
8+
</script>
9+
10+
<section class="cta">
11+
<div class="cta-inner">
12+
<h2>{@html title}</h2>
13+
<p>{body}</p>
14+
{#if actions.length === 1}
15+
<a
16+
href={actions[0].href}
17+
class="btn-primary"
18+
target={actions[0].external ? '_blank' : undefined}
19+
rel={actions[0].external ? 'noreferrer' : undefined}
20+
>
21+
{actions[0].label}
22+
</a>
23+
{:else if actions.length > 1}
24+
<div class="cta-links">
25+
{#each actions as a}
26+
<a
27+
href={a.href}
28+
class={a.style === 'secondary' ? 'btn-secondary' : 'btn-primary'}
29+
target={a.external ? '_blank' : undefined}
30+
rel={a.external ? 'noreferrer' : undefined}
31+
>
32+
{a.label}
33+
</a>
34+
{/each}
35+
</div>
36+
{/if}
37+
</div>
38+
</section>
39+
40+
<style>
41+
.cta {
42+
background: var(--light-bg);
43+
color: var(--light-text-primary);
44+
padding: var(--pad-section);
45+
border-top: 1px solid var(--light-border);
46+
}
47+
48+
.cta-inner {
49+
max-width: var(--max-w);
50+
margin: 0 auto;
51+
display: flex;
52+
flex-direction: column;
53+
gap: var(--space-xl);
54+
}
55+
56+
h2 {
57+
font-size: var(--fs-h2);
58+
font-weight: var(--fw-bold);
59+
letter-spacing: 0.08em;
60+
line-height: var(--lh-heading);
61+
}
62+
63+
p {
64+
font-size: var(--fs-body-sm);
65+
color: var(--light-text-secondary);
66+
max-width: var(--max-w-body);
67+
line-height: 1.7;
68+
letter-spacing: var(--ls-default);
69+
}
70+
71+
.cta-links {
72+
display: flex;
73+
gap: var(--space-lg);
74+
flex-wrap: wrap;
75+
margin-top: var(--space-sm);
76+
}
77+
78+
.btn-primary {
79+
display: inline-block;
80+
font-family: var(--font-mono);
81+
font-size: var(--fs-btn);
82+
letter-spacing: var(--ls-wider);
83+
padding: var(--btn-pad);
84+
background: var(--light-text-primary);
85+
color: var(--light-bg);
86+
text-decoration: none;
87+
transition: opacity var(--transition-fast);
88+
align-self: flex-start;
89+
margin-top: var(--space-sm);
90+
}
91+
92+
.btn-primary:hover {
93+
opacity: 0.75;
94+
}
95+
96+
.btn-secondary {
97+
display: inline-block;
98+
font-family: var(--font-mono);
99+
font-size: var(--fs-btn);
100+
letter-spacing: var(--ls-wider);
101+
padding: var(--btn-pad);
102+
border: 1px solid var(--light-text-primary);
103+
background: transparent;
104+
color: var(--light-text-primary);
105+
text-decoration: none;
106+
transition: background var(--transition-fast), color var(--transition-fast);
107+
}
108+
109+
.btn-secondary:hover {
110+
background: var(--light-text-primary);
111+
color: var(--light-bg);
112+
}
113+
</style>

0 commit comments

Comments
 (0)