Design System.
Every element of the site on one page. Each one shows what it looks like, which properties you can change, the exact token that controls it, and the HTML to copy.
Edit values in styles.css → part 1 · Tokens for colors, type and spacing (they cascade everywhere); part 2 · Components to reshape one element. Reload to preview.
01 · Colors
:root → COLORAll colors are defined once in :root. Change a hex value and every element using that token updates. To re-theme the whole site, the two that matter most are --accent (every blue) and --ink / --bg (the base contrast).
02 · Typography
:root → TYPEThree families: --font-display (Inter Tight) for headings, --font-body (Inter) for prose, --font-mono for labels. Sizes are fluid clamp(min, vw, max) — the middle number scales with viewport width; raise the max to make a size bigger on large screens. Swap a family by changing one variable; every element follows.
03 · Spacing & tokens
:root → LAYOUT / RADIUS / MOTION06 · Status & eyebrow
.ds-status · .ds-eyebrowHero status line with a pulsing dot.
- --ok #18b45a
- Dot colour (the green).
- color --ink-soft
- Label text.
- animation 2.4s
- Pulse speed — the duration in
.ds-status__dot.
<span class="ds-status"><span class="ds-status__dot"></span> Available for work — Jun 2026</span>
Small mono label that opens each section. A 26×1px rule precedes the text; the index number is in --accent.
<span class="ds-eyebrow"><span class="ds-eyebrow__idx">02</span> Projects</span>
07 · Section heading
.ds-section-headThree case studies.
End-to-end design across startups, corporations and consulting.
The standard opener for every major block: eyebrow, big display title, optional one-line sub.
- .ds-section-title --text-title
- Display 500, clamp(34→56px).
- .ds-section-sub --text-body
- Capped at 52ch for readability.
<div class="ds-section-head"> <span class="ds-eyebrow"><span class="ds-eyebrow__idx">02</span> Selected work</span> <h2 class="ds-section-title">Three case studies.</h2> <p class="ds-section-sub">Optional one-line description.</p> </div>
08 · Project card
.ds-card-grid · .ds-cardCivic
End-to-end redesign of a 25-year-old platform for the full lifecycle of fines — 700+ fields across 45 screens.
View case study →Energy Manager
Monitoring and optimizing energy across complex building portfolios, from discovery to developer handoff.
View case study →Building X
First end-to-end mapping of the building onboarding journey — 40+ users across 3 continents.
View case study →Cards sit on a --works-bg band. They lift and cast a shadow on hover. The grid drops to one column below 880px.
- .ds-card-grid repeat(3, 1fr)
- Column count; gap clamp(16→22px).
- radius --radius
- Card corners (16px).
- border --line-card
- Resting border on the band.
- hover translateY(-6px)
- Lift + box-shadow; speed = --dur-slow.
- .ds-card__thumb 160px
- Cover height; holds an image or .ds-ph.
<a class="ds-card" href="#"> <div class="ds-card__thumb"><!-- img or .ds-ph --></div> <div class="ds-card__num">01 / 2024–</div> <h3 class="ds-card__title">Civic</h3> <div class="ds-card__tags"><span class="ds-tag">Product Design</span></div> <p class="ds-card__desc">Short summary…</p> <span class="ds-card__cta">View case study →</span> </a>
09 · Pillars · stats · clients
.ds-pillars · .ds-stat · .ds-clients- Lead end-to-end design across the full product lifecycle.
- Turn complexity into clear, AI-ready information architecture.
- Grow design culture — mentoring teams and documenting frameworks.
- Act as product owner — bridging design and development end-to-end.
Inter 300 list with auto decimal-leading-zero counters in --accent and hairline rules between items.
Big Inter Tight 500 number (56px, ls −0.04em) over a small caption. Wrap part of the number in .accent to colour it.
<div class="ds-stat"><div class="ds-stat__num">9<span class="accent">+</span></div> <div class="ds-stat__cap">Years of experience</div></div>
Mono --ink-faint label beside a wrapping list of Inter Tight 500 names; a --line rule sits on top.
10 · Contact & footer
.ds-contact · .ds-footerLet's talk.
The best way to reach me is by email — I usually reply within a day.
Closing call-to-action. Display headline with the email underlined in --accent (hover turns the whole word accent).
- .ds-contact__headline --text-display
- clamp(40→104px).
- .ds-contact__mail 2px --accent
- Bottom border on the link.
- border-top --line-strong
- The rule that separates it from the page above.
<section class="ds-contact"> <span class="ds-eyebrow"><span class="ds-eyebrow__idx">04</span> Contact</span> <h2 class="ds-contact__headline">Let's <a class="ds-contact__mail" href="mailto:#">talk.</a></h2> <p class="ds-contact__sub">Best reached by email.</p> </section>
Mono meta row — copyright left, links right; collapses and wraps on narrow screens. Links hover to --accent-ink.
11 · Project page
.ds-crumb · .ds-meta · .ds-proj-section · .ds-nextBack link on inner pages; the arrow nudges 3px left on hover, colour → --accent-ink.
Definition list of project facts; auto-fits as many 160px columns as the width allows.
<dl class="ds-meta"> <div><dt>Role</dt><dd>Lead Product Designer</dd></div> <div><dt>Year</dt><dd>2024 — present</dd></div> </dl>
01 Challenge
A 25-year-old platform handled the full lifecycle of fines across 700+ fields and 45 screens, with no shared structure.
The goal was to make it learnable for new operators while keeping experts fast — without losing any of the legal detail.
Two columns: a numbered heading on the left, prose (max 60ch) on the right. Collapses to one column below 880px.
<section class="ds-proj-section"> <h2><span class="s-idx">01</span> Challenge</h2> <div class="ds-proj-body"><p>…</p></div> </section>
Media block (image or .ds-ph) with a mono caption. Media height is fluid clamp(240→400px), radius --radius-md.
Large "next case study" link at the foot of a project; the arrow (in --accent) slides 6px right on hover.
12 · Bullets & filters
.ds-bullets · .btn-filter- Good information architecture is invisible — you only notice it when it's missing.
- The fastest way to align a team is a shared artifact, not a longer meeting.
- Constraints are a gift: they turn an infinite problem into a solvable one.
A dash-marked list with hairline rules. The — marker is coloured --accent. Pair it with .btn-filter pills to filter items (toggle .is-on in JS).
<ul class="ds-bullets"> <li>A single point on its own line.</li> <li>Another point.</li> </ul>
13 · Image placeholder
.ds-phA diagonal-stripe placeholder with a mono caption of what belongs there. Drop it inside any sized, position:relative; overflow:hidden box (card thumb, figure, hero). Replace with a real <img> when ready.
<div style="position:relative;height:200px;overflow:hidden"> <div class="ds-ph"></div> <div class="ds-ph__label">Project shot — 1600×1000</div> </div>