Making It Yours
This is a member-only chapter. Log in with your Signal Over Noise membership email to continue.
Log in to readModule 3: Making It Yours
Most sites look generic because they use framework defaults or copy-paste CSS from Stack Overflow without a system underneath. This module covers a different approach: define the design at the token level first, then build components on top. Claude Code can extend this system indefinitely without breaking the visual consistency.
Why Not Just Use Tailwind?
Tailwind is popular, and for good reason. But it creates a dependency that buries your design decisions inside utility class names spread across every component. When you want to change your primary colour, you update a config file — but the colour only changes if every class that uses it was written correctly.
CSS custom properties (variables) are the alternative. They’re native to the browser, they cascade correctly, and they’re readable. When Claude Code generates a new component using var(--color-primary), that component automatically gets the right colour, because the definition lives in one place.
I use this approach across all eight of my Astro sites. The variable names are slightly different per project, but the structure is the same.
Building Your Token Layer
Create src/styles/global.css. This file defines everything that’s site-wide — colours, typography, spacing, and any global resets.
/* src/styles/global.css */
:root {
/* Colours */
--color-text: #1a1a2e;
--color-text-muted: #6b7280;
--color-background: #ffffff;
--color-primary: #457b9d;
--color-primary-dark: #2c5f7a;
--color-border: #e5e7eb;
--color-surface: #f9fafb;
/* Typography */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'Fira Code', 'Cascadia Code', monospace;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 2rem;
/* Spacing */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
/* Layout */
--container-max: 1200px;
--container-narrow: 720px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
}
/* Global resets */
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: var(--font-sans);
font-size: var(--font-size-base);
color: var(--color-text);
background: var(--color-background);
line-height: 1.6;
margin: 0;
}
img {
max-width: 100%;
height: auto;
}
a {
color: var(--color-primary);
}
Import this in your layout’s <head>:
<style is:global>
@import '../styles/global.css';
</style>
Or reference it directly:
<link rel="stylesheet" href="/styles/global.css" />
Either works. The is:global approach keeps everything inside the component file.
Choosing Your Colours
Pick three: a text colour, a background colour, and a primary accent. Everything else derives from those.
For jimchristian.net I used a near-black text on white with a deep teal accent. For signalovernoise.at the background is very dark (almost black) with a lighter accent. For definitelyrealproducts.com it’s deliberately garish — that’s part of the joke.
The pattern is always the same: define the palette as custom properties, build components that reference the properties, never hardcode a hex value inside a component.
Generating a palette with Claude Code:
I need a colour palette for a site about [topic].
The mood is [adjective, adjective].
Give me CSS custom properties for: text, text-muted, background,
primary accent, primary-dark, border, surface.
Use the variable names from src/styles/global.css.
Claude Code will return CSS variables you can paste directly in.
Typography
System fonts are fast and look fine. But if you want something more distinctive, Google Fonts or a self-hosted variable font gives you more control.
For thinklikeacoder.org, the book companion site, I used a serif for headings and a clean sans-serif for body text. That typographic contrast does a lot of the design work on its own.
To add a Google Font, add this to your layout’s <head>:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet" />
Then reference it in your custom property:
--font-sans: 'Inter', system-ui, sans-serif;
Responsive Layout
The most useful responsive pattern is a container with a max-width, centred with auto margins:
.container {
width: 100%;
max-width: var(--container-max);
margin-inline: auto;
padding-inline: var(--space-6);
}
Use this class on every section. Content stays readable at any viewport width without writing media queries for every component.
For two-column layouts, CSS Grid with a sensible minimum column width handles the breakpoint automatically:
.grid-auto {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
gap: var(--space-6);
}
This is the pattern I use on the product grid on this platform. At large viewports it’s three columns. At small viewports it’s one. No media query required.
How Claude Code Extends the System
Once your token layer is in place, tell Claude Code about it at the start of any design task:
This project uses CSS custom properties for all design values.
The variables are defined in src/styles/global.css.
Do not hardcode any colour, spacing, or font values —
always reference the custom properties.
Put this in your project CLAUDE.md and you only have to say it once. After that, every generated component uses the token system without being reminded.
You now have a design system that scales. Module 4 covers content — how to write in Markdown and have Astro organise it for you.
Check Your Understanding
Answer all questions correctly to complete this module.
1. Why recommend CSS custom properties over Tailwind?
2. How many colours do you need to start a design system?
3. What instruction should be in your project CLAUDE.md for design consistency?
Pass the quiz above to unlock
Save failed. Please try again.