thats adam
Basic Building Blocks
The smallest functional units of the interface — indivisible elements that cannot be broken down further without losing their meaning. Buttons, type styles, labels, dividers. Everything else is built from these.
Buttons
Five variants mapped from Figma. All share the .btn base class. Hover transitions via the secondary-hover token. Active/pressed states use the blue glow token.
Filled yellow. Single most important CTA per viewport. Limit to one visible at a time.
Transparent with yellow border. Paired with primary where two CTAs are needed.
Black weight, no border. Nav-adjacent or inline link contexts.
Regular weight. Nav links. Add .btn-text--active for current page state.
Extralight 200. Exclusively for the hero audience selector — dramatic weight contrast is the point.
<button class="btn btn-primary">Get in touch</button>
<button class="btn btn-secondary">View work</button>
<a href="#" class="btn btn-ghost">Read more</a>
<a href="#" class="btn btn-text">Arbejde</a>
<a href="#" class="btn btn-text btn-text--active">Om</a>
<button class="btn btn-large-text btn-large-text--active">Designer</button>/* style.css */
.btn {
display: inline-flex; align-items: center; justify-content: center;
font-family: var(--font-primary); font-size: var(--text-m); font-weight: var(--fw-black);
line-height: var(--lh-xs); padding: var(--space-s) var(--space-m);
border-radius: var(--radius-xxs); border: 1px solid transparent; cursor: pointer;
transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
text-decoration: none; white-space: nowrap;
}
.btn:focus-visible { outline: 2px solid var(--text-on-dark-primary); outline-offset: 2px; }
/* Primary */
.btn-primary { background: var(--surface-branding-primary); color: var(--text-on-dark-btn); min-width: 120px; height: 44px; }
.btn-primary:hover { background: var(--surface-branding-secondary-hover); color: var(--surface-dominant); }
.btn-primary:focus-visible { border-color: var(--text-on-dark-btn); outline: none; }
.btn-primary:active { background: var(--color-active-glow); color: var(--text-on-dark-btn); box-shadow: 0 0 4px var(--color-active-glow); }
.btn-primary:disabled { background: var(--text-on-dark-tertiary); cursor: not-allowed; }
/* Secondary */
.btn-secondary { background: transparent; color: var(--surface-branding-secondary-hover); border-color: var(--surface-branding-secondary-hover); min-width: 120px; height: 44px; }
.btn-secondary:hover { color: var(--text-on-dark-secondary); border-color: var(--surface-branding-primary-60); }
.btn-secondary:focus-visible { background: var(--surface-branding-primary-25); border-color: var(--surface-branding-primary); color: var(--text-on-dark-primary); outline: none; }
.btn-secondary:active { color: var(--color-active-glow); border-color: var(--color-active-glow); box-shadow: 0 0 4px var(--color-active-glow); }
/* Ghost */
.btn-ghost { background: transparent; color: var(--text-on-dark-primary); padding: var(--space-xxs) var(--space-xs); }
.btn-ghost:hover { color: var(--surface-branding-secondary-hover); border-bottom: 1px solid var(--surface-branding-secondary-hover); border-radius: 0; }
.btn-ghost:active { color: var(--color-active-glow); }
/* Small text */
.btn-text { background: transparent; color: var(--text-on-dark-primary); font-weight: var(--fw-regular); padding: var(--space-xxs) 0; border-radius: 0; }
.btn-text:hover { color: var(--surface-branding-secondary-hover); border-bottom: 1px solid var(--surface-branding-secondary-hover); }
.btn-text--active { color: var(--color-active-glow); }
/* Large text */
.btn-large-text { background: transparent; color: var(--text-on-dark-primary); font-size: var(--text-2xl); font-weight: var(--fw-extralight); padding: var(--space-xs); line-height: var(--lh-m); }
.btn-large-text:hover { color: var(--surface-branding-secondary-hover); border-bottom: 1px solid var(--surface-branding-secondary-hover); border-radius: 0; }
.btn-large-text--active { color: var(--color-active-glow); border-bottom: none; }var(--text-on-dark-btn)Primary button hover & active text — black (#000000), paired with --surface-branding-secondary-hover and --color-active-glow yellow/blue backgroundsUse exactly one .btn-primary per viewport. Pair with .btn-secondary for a secondary action.
Never place two .btn-primary buttons side by side — it dilutes hierarchy and confuses intent.
Typography Utilities
Utility classes that express the type system. Semantic level (h1–h6) and visual level are decoupled — you can use .heading-xxxl on a <p> tag.
label-s · 12px semibold uppercase +2px tracking
label-m · 16px semibold uppercase +4px tracking
label-xl · 24px semibold uppercase +6px tracking
body-m — Regular 16px · line-height 24px · tertiary colour. Used for descriptions and supporting copy throughout the site.
body-l — Regular 20px · line-height 32px. Intro paragraphs and pull-out descriptions.
heading-m · Black 32px
heading-xl · Black 48px
heading-xxl · Black 56px
.label-s12px · fw-semibold · uppercase · ls-label-s · secondary colour.label-m16px · fw-semibold · uppercase · ls-label-m · secondary colour.label-xl24px · fw-semibold · uppercase · ls-label-xl · secondary colour.body-m16px · fw-regular · lh-xs · tertiary colour.body-l20px · fw-regular · lh-s · tertiary colour.heading-m32px · fw-black · lh-m · primary colour.heading-xl48px · fw-black · lh-xl · primary colour.heading-xxl56px · fw-black · lh-xxl · primary colour (responsive).heading-xxxl96px · fw-black · lh-xxxl · primary colour (responsive)<p class="label-m">Case study</p>
<h2 class="heading-xl">Designing for complexity</h2>
<p class="body-l">Intro paragraph in large body copy.</p>
<p class="body-m">Supporting copy in regular body size.</p>
<!-- Visual level is independent of the tag -->
<p class="heading-xxxl">Hero</p>/* style.css */
.heading-xxxl { font-size: var(--text-5xl); font-weight: var(--fw-black); line-height: var(--lh-xxxl); }
.heading-xxl { font-size: var(--text-4xl); font-weight: var(--fw-black); line-height: var(--lh-xxl); }
.heading-xl { font-size: var(--text-3xl); font-weight: var(--fw-black); line-height: var(--lh-xl); }
.heading-m { font-size: var(--text-2xl); font-weight: var(--fw-black); line-height: var(--lh-m); }
.label-s { font-size: var(--text-xs); font-weight: var(--fw-semibold); line-height: 1; letter-spacing: var(--ls-label-s); text-transform: uppercase; color: var(--text-on-dark-secondary); }
.label-m { font-size: var(--text-m); font-weight: var(--fw-semibold); line-height: 1; letter-spacing: var(--ls-label-m); text-transform: uppercase; color: var(--text-on-dark-secondary); }
.label-xl { font-size: var(--text-xl); font-weight: var(--fw-semibold); line-height: 1; letter-spacing: var(--ls-label-xl); text-transform: uppercase; color: var(--text-on-dark-secondary); }
.body-m { font-size: var(--text-m); line-height: var(--lh-xs); color: var(--text-on-dark-tertiary); }
.body-l { font-size: var(--text-l); line-height: var(--lh-s); color: var(--text-on-dark-tertiary); }
@media (max-width: 768px) {
.heading-xxxl { font-size: var(--text-4xl); line-height: var(--lh-xxl); }
.heading-xxl { font-size: var(--text-3xl); line-height: var(--lh-xl); }
.heading-xl { font-size: var(--text-2xl); line-height: var(--lh-m); }
.heading-m { font-size: var(--text-xl); line-height: var(--lh-m); }
}Labels & Chips
Rounded tags used for insight chips and metadata. border-radius: 12px (a rounded square, so wrapped multi-line text still reads well) with a primary-30 border.
- Research insight
- Navigation patterns
- Mobile-first
<ul class="ui-entry__chips" aria-label="Key insights">
<li class="ui-entry__chip">Research insight</li>
<li class="ui-entry__chip">Navigation patterns</li>
<li class="ui-entry__chip">Mobile-first</li>
</ul>/* template-parts/acf-blocks/user_interviews.php */
.ui-entry__chips { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-xs); }
.ui-entry__chip {
font-size: var(--text-m);
color: var(--text-on-dark-tertiary);
line-height: var(--lh-xs);
padding: var(--space-xs) var(--space-m);
border: 1px solid var(--surface-branding-primary-30);
border-radius: 12px;
max-width: 100%;
}
@media (max-width: 768px) {
.ui-entry__chips { flex-direction: row; flex-wrap: wrap; }
.ui-entry__chip { flex-shrink: 1; padding: var(--space-s) var(--space-m); }
}Dividers
1px horizontal rules using --surface-branding-primary-30. Used between list entries, section blocks, and accordion items.
.divider
<div class="divider"></div>/* style.css */
.divider { width: 100%; height: 1px; background: var(--surface-branding-primary-30); border: none; }Filter Tabs
Single tab within a Filter Bar. Three states — idle (grey), hover (white), active (white + blue ::after underline via scaleX(0→1)). Class: .work-filter-tab / .work-filter-tab--active.
class.work-filter-tab · .work-filter-tab--activepaddingvar(--space-xs) var(--space-m) — 8px 16pxfontInter · var(--fw-regular) · var(--text-m) 16pxidle colourvar(--text-on-dark-tertiary) — greyhover colourvar(--text-on-dark-primary) — whiteactive colourvar(--text-on-dark-primary) + blue ::after underline (height:2px, scaleX 0→1 from left)::after underlineposition:absolute · bottom:-2px · left/right: var(--space-m) · height:2px · background:var(--color-active-glow)<button class="work-filter-tab work-filter-tab--active" data-filter="all" role="tab" aria-selected="true">All projects</button>
<button class="work-filter-tab" data-filter="ux-design" role="tab" aria-selected="false">UX Design</button>/* archive-portfolio.php */
.work-filter-tab {
position: relative; background: transparent; border: none; cursor: pointer;
font-family: var(--font-primary); font-size: var(--text-m); font-weight: var(--fw-regular);
color: var(--text-on-dark-tertiary);
padding: var(--space-xs) var(--space-m);
transition: color 0.2s; white-space: nowrap;
}
.work-filter-tab::after {
content: ''; position: absolute; bottom: -2px; left: var(--space-m); right: var(--space-m);
height: 2px; background: var(--color-active-glow);
transform: scaleX(0); transform-origin: left; transition: transform 0.2s;
}
.work-filter-tab:hover,
.work-filter-tab--active { color: var(--text-on-dark-primary); }
.work-filter-tab--active::after { transform: scaleX(1); }Logo
Two-part lockup: SVG mark + wordmark "That's adam" with extreme weight contrast — extralight "That's" and black "adam". Two size variants.
"That's "var(--fw-extralight) 200 — the thin half"adam"var(--fw-black) 900 — the bold halfcolourvar(--text-on-dark-primary)logo fileassets/logo.svg — always inline or <img>, never rasterisefavicon fileassets/favicon.svg — "A" lettermark on #221014 background, 32×32, rx 4<a href="/da/" class="footer__logo" aria-label="That's Adam — Home">
<img src="/wp-content/themes/thats-adam/assets/logo.svg" alt="" class="footer__logo-mark" width="62" height="42" aria-hidden="true">
<span class="footer__logo-text">
<span class="footer__logo-thin">That's</span>
<span class="footer__logo-bold">adam</span>
</span>
</a>
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/wp-content/themes/thats-adam/assets/favicon.svg">/* site-footer.php (the nav uses the same rules with the .nav__ prefix) */
.footer__logo { display: flex; align-items: center; gap: var(--space-m); text-decoration: none; }
.footer__logo-text { font-size: var(--text-xl); letter-spacing: var(--ls-heading); color: var(--text-on-dark-primary); line-height: 1; white-space: nowrap; }
.footer__logo-thin { font-weight: var(--fw-extralight); }
.footer__logo-bold { font-weight: var(--fw-black); }
.footer__logo:focus-visible { outline: 2px solid var(--text-on-dark-primary); outline-offset: 2px; }Number Circle
106×106px circular badge used as a fallback when no step image is uploaded in the Flow block. 1px yellow border, no fill. Number is zero-padded in PHP.
<div class="acf-flow__img-wrap acf-flow__img-wrap--number" aria-hidden="true">
<span class="acf-flow__number">01</span>
</div>/* single-portfolio.php */
.acf-flow__img-wrap {
width: 106px; height: 106px; flex-shrink: 0;
border-radius: 100px; overflow: hidden;
display: flex; align-items: center; justify-content: center;
}
.acf-flow__img-wrap--number { border: 1px solid var(--surface-branding-primary); }
.acf-flow__number {
font-size: var(--text-3xl); /* 48px */
font-weight: var(--fw-black);
color: var(--text-on-dark-primary);
line-height: 1;
}
@media (max-width: 550px) {
.acf-flow__img-wrap { width: 56px; height: 56px; }
.acf-flow__number { font-size: var(--text-m); }
}<span class="acf-flow__number"><?php echo str_pad( $i + 1, 2, '0', STR_PAD_LEFT ); ?></span>Section Header
Pink uppercase label stacked above a black-weight heading. Used at the top of every ACF block that has a titled section. Two size combinations.
Research findings
User needs drive every decision
Case study
Designing for complexity
Labelvar(--text-xs/m) · var(--fw-semibold) · uppercase · var(--text-on-dark-secondary) · tracking var(--ls-label-m)Headingvar(--text-2xl/3xl) · var(--fw-black) · var(--text-on-dark-primary)Gap (small)var(--space-m) — 16pxGap (large)var(--space-1xl) — 40px<!-- Content blocks (small) -->
<div class="acf-text-block__header">
<p class="acf-block__label">Research findings</p>
<h2 class="acf-block__heading">User needs drive every decision</h2>
</div>
<!-- Page sections (large) -->
<p class="label-m">Case study</p>
<h2 class="heading-xl">Designing for complexity</h2>/* single-portfolio.php */
.acf-block__label {
font-size: var(--text-m); font-weight: var(--fw-semibold);
color: var(--text-on-dark-secondary);
text-transform: uppercase; letter-spacing: 4px;
margin: 0; line-height: 1;
}
.acf-block__heading {
font-size: var(--text-3xl); font-weight: var(--fw-black);
color: var(--text-on-dark-primary);
margin: 0; line-height: var(--lh-xl);
}
.acf-text-block__header { display: flex; flex-direction: column; gap: var(--space-m); }
@media (max-width: 768px) {
.acf-block__heading { font-size: var(--text-2xl); line-height: 1.15; }
}Icons
Three inline SVG icons used across the system. Always rendered as inline SVG — never <img> — to prevent distortion. Thumb-down is thumb-up with transform: scaleY(-1).
thumb_up / thumb_down44×44px · fill: currentColor (red via parent) · thumb_down uses transform:scaleY(-1)bio44×55px · inline SVG (source file: assets/icon-bio.svg) · fill: currentColorcolourvar(--surface-branding-primary) on parent<!-- thumb_up (inline SVG, inherits colour) -->
<svg class="prs-li__thumb" viewBox="0 0 40.9603 35.5369" width="44" height="44" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M22.22 0.813556L12.0633 10.9702C11.385 11.6486 11 12.5836 11 13.5552V31.8702C11 33.8869 12.65 35.5369 14.6667 35.5369H31.1667C32.6333 35.5369 33.9533 34.6569 34.54 33.3186L40.5167 19.3669C42.0567 15.7369 39.3983 11.7036 35.4567 11.7036H25.0983L26.84 3.30689C27.0233 2.39022 26.7483 1.45522 26.0883 0.795223C25.0067 -0.26811 23.2833 -0.26811 22.22 0.813556ZM3.66667 35.5369C5.68333 35.5369 7.33333 33.8869 7.33333 31.8702V17.2036C7.33333 15.1869 5.68333 13.5369 3.66667 13.5369C1.65 13.5369 0 15.1869 0 17.2036V31.8702C0 33.8869 1.65 35.5369 3.66667 35.5369Z" fill="currentColor"/>
</svg>
<!-- thumb_down: same SVG plus a modifier class -->
<svg class="prs-li__thumb prs-li__thumb--down" …>…</svg>
<!-- bio (inline SVG, inherits colour) -->
<svg class="prs-li__img--bio" viewBox="0 0 44 55" width="44" height="55" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<path d="M40.333 0C42.3581 0 44 1.64195 44 3.66699V51.333 …" fill="currentColor"/>
</svg>/* template-parts/acf-blocks/personas.php */
.prs-li__icon { width: 44px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.prs-li__thumb { display: block; flex-shrink: 0; color: var(--surface-branding-primary); }
.prs-li__thumb--down { transform: scaleY(-1); }
.prs-li__img--bio { width: 44px; height: 55px; display: block; flex-shrink: 0; color: var(--surface-branding-primary); }List Item
Icon + text pair used in persona bios. 44px icon column, 24px gap, text column with bold label prefix + regular body.
Interests: Startups, SaaS, scale-up culture, impact metrics
Frustrations: Designers who can't communicate trade-offs
layoutflex row · align-items:center · gap: 24px (var(--space-l))icon col44px wide · flex-shrink:0 · red via currentColortext16px · var(--fw-regular) · var(--text-on-dark-tertiary) · bold prefix in var(--fw-black)<div class="prs-li">
<div class="prs-li__icon" aria-hidden="true">
<svg class="prs-li__thumb" viewbox="0 0 40.9603 35.5369" width="44" height="44" fill="none">…</svg>
</div>
<p class="prs-li__text"><strong>Interests:</strong> Startups, SaaS, scale-up culture, impact metrics</p>
</div>
<!-- Frustrations use the flipped thumb -->
<div class="prs-li">
<div class="prs-li__icon" aria-hidden="true">
<svg class="prs-li__thumb prs-li__thumb--down" …>…</svg>
</div>
<p class="prs-li__text"><strong>Frustrations:</strong> Designers who can't communicate trade-offs</p>
</div>/* template-parts/acf-blocks/personas.php */
.prs-li { display: flex; flex-direction: row; align-items: center; gap: 24px; }
.prs-li--top { align-items: flex-start; }
.prs-li__icon { width: 44px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.prs-li__text {
font-size: 16px; font-weight: 400; line-height: 24px;
color: var(--text-on-dark-tertiary); margin: 0;
}Input (base)
Bare input atom. Bottom border only — no surrounding box. Four states. Used inside the Input Field molecule which adds a label and helper text.
height69pxfontRoboto · var(--fw-regular) · var(--text-l) 20pxborderbottom only · idle: var(--surface-branding-primary-30) · focus: var(--color-active-glow) 2px · success: #63eb47 (dark) / #1a7a0f (light) · error: #ff3344radius0 — no rounding<input class="contact-form__input" type="email" id="contact_email" name="contact_email"
required autocomplete="email" placeholder="your@email.com">/* page-contact.php */
.contact-form__input {
background: none;
border: none;
border-bottom: 1px solid var(--surface-branding-primary-30);
color: var(--text-on-dark-primary);
font-family: var(--font-primary);
font-size: var(--text-m);
padding: var(--space-m) 0;
transition: border-color 0.2s;
outline: none;
width: 100%;
box-sizing: border-box;
}
.contact-form__input::placeholder { color: var(--text-on-dark-tertiary); }
.contact-form__input:focus { border-bottom: 2px solid var(--color-active-glow); }Preview Image
Thumbnail used in project cards. Two aspect ratios. Hover shows a black shadow and a "View project" button overlay. Focus shows a 4px blue border.
border-radiusvar(--radius-xs) — 8pxhoverfilter: drop-shadow(0 0 30px var(--shadow-glow)) + "View project" btn overlayfocus4px solid var(--surface-branding-primary) borderaspect ratios1:1 (square) or 1:2 (portrait)<a href="/da/work/spotted/" class="project-card__image-link" tabindex="-1" aria-hidden="true">
<div class="project-card__image">
<img src="spotted.jpg" alt="Spotted app screens" loading="lazy" class="project-card__img">
</div>
</a>/* style.css — site-wide thumbnail border */
.project-card__image { border: 3px solid var(--surface-branding-primary); border-radius: var(--radius-xs); }
/* template-parts/components/project-card.php */
.project-card__image-link { display: block; border-radius: var(--radius-xs); overflow: hidden; background: var(--surface-branding-primary-10); }
.project-card__image { aspect-ratio: 1 / 1; }
.project-card__img {
width: 100%; height: 100%; object-fit: cover; display: block;
filter: grayscale(var(--card-img-grayscale));
transition: transform 0.4s ease, filter 0.4s ease;
}
.project-card__image-link:hover .project-card__img { transform: scale(1.03); filter: grayscale(0%); }Mock Up Screen
Phone-frame mockup at 208×438.63px. Black shadow via drop-shadow filter. Used in the Screen Mockups block — images must be PNG with transparent background for the shadow to work.
size208 × 438.63px (production) — scaled 75% here for displayborder-radiusvar(--radius-m) — 16pxglowfilter: drop-shadow(0 0 30px var(--shadow-glow))image requirementPNG with transparent background — glow bleeds correctly<div class="acf-screen-mockups__item" style="width:198px;">
<div class="acf-screen-mockups__mockup">
<img src="screen-dashboard.png" alt="Dashboard view" style="aspect-ratio:432/911;" loading="lazy">
</div>
<p class="acf-screen-mockups__caption">Dashboard view</p>
</div>/* single-portfolio.php */
.acf-screen-mockups__item { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-m); }
/* No overflow clip on the wrapper, so the shadow can bleed outside */
.acf-screen-mockups__mockup img {
width: 100%; height: auto; min-height: 418px;
object-fit: cover; display: block;
filter: drop-shadow(0 0 24px var(--lightbox-img-shadow));
}
.acf-screen-mockups--rounded .acf-screen-mockups__mockup img { border-radius: 12px; }Client Grid
"Selected Clients" showcase row. Client names at 50% opacity — present but not prominent. Large black-weight type makes the brand names readable at a glance.
Udvalgte klienter
label.label-m — "Selected Clients"namesvar(--text-2xl) 32px · var(--fw-black) · var(--text-on-dark-primary) · opacity: 0.5layoutflex row · gap: var(--space-2xl) 64px · flex-wrappaddingpadding-block: var(--space-4xl) 96px<section class="about-clients container">
<p class="label-m about-clients__label">Udvalgte klienter</p>
<div class="about-clients__list">
<span class="about-clients__name">Accenture</span>
<span class="about-clients__name">Novo Nordisk</span>
<span class="about-clients__name">Maersk</span>
<span class="about-clients__name">LEGO</span>
</div>
</section>/* page-about.php */
.about-clients { padding-block: var(--space-4xl); display: flex; flex-direction: column; align-items: center; gap: var(--space-2xl); }
.about-clients__label { text-align: center; }
.about-clients__list { display: flex; justify-content: space-between; align-items: center; width: 100%; opacity: 0.5; }
.about-clients__name { font-size: var(--text-2xl); font-weight: var(--fw-black); color: var(--text-on-dark-tertiary); line-height: 1; }
@media (max-width: 768px) {
.about-clients__list { flex-wrap: wrap; gap: var(--space-l); justify-content: flex-start; }
.about-clients__name { font-size: var(--text-xl); }
}<?php foreach ( $clients as $client ) : ?>
<span class="about-clients__name"><?php echo esc_html( $client['client_name'] ); ?></span>
<?php endforeach; ?>