From Generic to Intentional: How I Rebuilt the Site's Visual Identity With a Design Token System
The Site Had a Theme. It Didn’t Have an Identity.
When this site launched on Astro, the color system was inherited. The framework gave me sensible defaults and I adjusted the hue. Navy blues, gold accent, clean light background. It looked fine. It looked like a hundred other portfolios.
That was the problem.
The goal was never “a portfolio that looks fine.” The goal was a site that feels like a specific place — one that carries The Wise Operator brand consistently across scottkrukowski.com, a LinkedIn newsletter, and eventually other properties. A tweaked default isn’t a brand. It’s a starting point someone forgot to finish.
This post is about what I changed, how I changed it, and what the process of building a real design system actually looks like when you’re doing it with AI tools rather than a design agency.
What the Before State Looked Like
The original CSS was written in HSL (Hue, Saturation, Lightness) — a way of describing colors using three numbers instead of a hex code. Here’s what the core tokens looked like:
--color-background: hsl(210 25% 96%); /* near-white */
--color-foreground: hsl(210 40% 12%); /* dark navy */
--color-primary: hsl(210 50% 15%); /* deeper navy */
--color-accent: hsl(38 90% 50%); /* gold */
Light background, dark text, gold for emphasis. A perfectly reasonable professional site. Also completely generic.
There was also an in-between stage — a brief Phase A where I nudged the hue from 210 to 220 (slightly cooler blues) without changing anything structurally. That was the moment I realized the problem wasn’t the hue. It was the approach.
The Decision: Go Dark, Build a System
Two things shifted.
First, The Wise Operator brand is dark. The logo is gold on black. The aesthetic is intentional, premium, editorial. A light-background site was fighting that identity rather than carrying it.
Second, the site needed more than adjusted values. It needed a system — a set of tokens that could be applied consistently everywhere, that a component could reference without guessing, that Claude could use reliably across sessions without drift.
So instead of tweaking HSL values again, I described what I actually wanted:
“Dark canvas. Near-black background that isn’t flat. Warm ivory text, not white. Gold as the primary accent. Blue for technical/structural contexts. The whole thing should feel like a serious builder’s workspace, not a template.”
From that, Claude built a two-layer token system.
How the Token System Works
A design token is a named variable that holds a visual value. Instead of writing color: #f4b24d directly in a component, you write color: var(--two-gold). If the gold ever changes, you update one variable and every component that references it updates automatically.
The system we built has two layers.
Layer 1: Semantic tokens — these map directly to Tailwind’s color utilities so existing classes keep working:
--color-background: #07090d;
--color-foreground: #f2e6d2;
--color-accent: #f4b24d;
--color-border: rgba(255, 255, 255, 0.10);
Every Tailwind class like bg-background, text-foreground, or border-border pulls from these. Changing the semantic token changes every component that uses that utility class.
Layer 2: TWO design system tokens — a full set of named values for the brand:
--two-bg: #07090d;
--two-text: #f2e6d2;
--two-text-2: rgba(242, 230, 210, 0.78);
--two-text-3: rgba(242, 230, 210, 0.50);
--two-gold: #f4b24d;
--two-blue: #3aa7ff;
--two-surface: #0d1119;
--two-border: rgba(255, 255, 255, 0.10);
The text hierarchy (--two-text, --two-text-2, --two-text-3) means components can use graduated opacity without each one calculating it independently. The surface tokens (--two-bg, --two-bg-2, --two-surface, --two-surface-2) create depth across the dark canvas — the homepage sections don’t all feel like the same flat black because they’re referencing slightly different dark values.
Why Hex Instead of HSL
The original system used HSL because it’s easier to reason about relationships between colors. Nudging the hue by 10 degrees moves everything in the same direction.
The TWO system uses explicit hex values because the colors are intentional and fixed, not relational. The gold is #f4b24d. Not “approximately warm” — specifically that gold. Using HSL would imply flexibility that doesn’t exist. Hex makes the intention explicit.
The Background Isn’t Flat Black
One thing that’s easy to miss: the background isn’t background-color: black. It’s this:
body {
background-color: #07090d;
background-image:
radial-gradient(ellipse 80% 50% at 15% 10%, rgba(244, 178, 77, 0.06) 0%, transparent 60%),
radial-gradient(ellipse 60% 60% at 75% 45%, rgba(58, 167, 255, 0.05) 0%, transparent 55%),
linear-gradient(180deg, #07090d 0%, #060810 100%);
}
Three layers stacked:
- A faint gold radial glow in the upper left — barely visible, 6% opacity
- A faint blue radial glow in the center right — 5% opacity
- A subtle linear gradient from near-black to slightly deeper black top to bottom
At 5-6% opacity these gradients are almost imperceptible. But they’re why the background reads as dimensional rather than flat. The page has atmosphere. It earns the dark without feeling like a void.
This is one of those details that you don’t consciously notice when it’s working, but you would notice immediately if it were removed.
The Prose System
The blog you’re reading right now uses a custom .prose utility class that defines the full reading experience: font sizes, line height, heading styles, blockquote formatting, code blocks, table layouts, link colors.
Before the migration, the blog just used whatever Tailwind’s built-in prose plugin provided. After it, every element in a blog post renders with TWO-specific values — gold heading borders, blue code highlighting, warm ivory body text, gold-tinted blockquote backgrounds.
The practical impact: blog posts don’t feel like they’re from a different site than the homepage. They’re the same system, just applied to reading mode.
What the Migration Actually Required
One challenge with a global CSS migration is that components written before it may have inline styles that override the tokens. The ExperienceTimeline component, which uses React rather than static Astro, had hardcoded color values that predated the token system. Those required a separate pass to bring in line.
This is a real consequence of building incrementally with AI tools across multiple sessions. The context window resets. Claude in a new session doesn’t automatically know that component X was written before the token system existed. The PLAN.md and BRAND.md files help prevent this, but they’re only as good as the discipline to update them when decisions change.
The migration wasn’t just a CSS file edit. It was a decision to stop patching and actually commit to a system.
Before and After
The before state was a conventional professional site — light background, navy text, gold highlights. Recognizable. Forgettable.
The after state is a specific place. Dark canvas, warm ivory text, gold and blue accents with purpose. A background that breathes. Typography that earns the reading experience.
The same content. Completely different weight.
What This Means for Building With AI
The part Claude couldn’t do: decide that the site needed to feel like a specific place, and describe what that place was. That’s a brand decision, not a code decision.
The part Claude did well: once the decision was made and articulated clearly, translate that into a complete token system in a single session, apply it consistently across components, and flag the exceptions that didn’t fit cleanly.
The lesson for anyone building with AI tools: the output quality is downstream of the precision of the input. “Make it look better” produces nothing useful. “Dark canvas, near-black not flat black, warm ivory text, two accent colors with specific contexts” produces a real system.
Decisions first. Then delegation. This is true of CSS tokens and it is true of everything else worth building. “Trust in the Lord with all your heart, and lean not on your own understanding” (Proverbs 3:5). The AI can execute. But knowing what matters, what endures, what is worth the effort: that wisdom comes from somewhere deeper than a prompt.
Want to understand the terms used in this post? Check out The Vibe-Coder’s Dictionary, a growing glossary built for non-technical builders who want to understand what’s actually happening under the hood.
Comments
Back to all posts