thats adam
Composite Elements
Purposeful groupings of atoms working together as a unit. A project card is a molecule — it combines an image, a label, and a heading into a single reusable component that carries clear meaning on its own.
Project Card
Portfolio item preview combining image, type label, and title. Assembled into the Project Grid organism. The square crop image is the primary visual anchor — the hover scale draws the eye.
Anatomy
- Image — 1:1 square, border-radius: var(--radius-xs), overflow hidden, hover: scale(1.03) transition 0.4s
- Type label — label-m, red secondary, uppercase, 4px tracking
- Title — text-xl, fw-black, primary colour
<!-- Rendered output. Odd-numbered cards add .project-card--flip (image on the right). -->
<article class="project-card" data-type="ux-design" data-date="1714521600" data-title="spotted">
<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>
<div class="project-card__meta">
<p class="project-card__type label-m">UX Design / 2024</p>
<h3 class="project-card__title"><a href="/da/work/spotted/">Spottet</a></h3>
<p class="project-card__excerpt">First paragraph of the case study…</p>
<a href="/da/work/spotted/" class="btn btn-secondary project-card__cta">Se projekt</a>
</div>
</article>/* template-parts/components/project-card.php */
.project-card { display: flex; flex-direction: row; gap: var(--space-2xl); align-items: flex-start; }
.project-card--flip { flex-direction: row-reverse; }
.project-card__image-link { flex: 0 0 calc(33.333% - var(--space-2xl) * 2 / 3); 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; transition: transform 0.4s ease, filter 0.4s ease; }
.project-card__image-link:hover .project-card__img { transform: scale(1.03); filter: grayscale(0%); }
.project-card__meta { flex: 1; display: flex; flex-direction: column; gap: var(--space-s); padding-top: var(--space-s); }
.project-card__title { font-size: var(--text-xl); font-weight: var(--fw-black); line-height: var(--lh-s); color: var(--text-on-dark-primary); margin: 0; }
.project-card__title a:hover { color: var(--text-on-dark-secondary); }
.project-card__excerpt { font-size: var(--text-m); color: var(--text-on-dark-tertiary); line-height: var(--lh-m); margin: 0; }
.project-card__cta { margin-top: var(--space-s); align-self: flex-start; }
@media (max-width: 768px) {
.project-card, .project-card--flip { flex-direction: column; gap: var(--space-l); }
.project-card__image-link { flex: none; width: 100%; }
}<?php
// Shared component — used on the homepage and /work/
thats_adam_part( 'components/project-card', [
'post_id' => get_the_ID(),
'index' => $i, // odd index = flipped layout
] );
?>Stat Item
A large numeric value paired with an uppercase label. Combined into the Stats Bar organism. The number is the primary visual element — weight and scale do the work.
<div class="stats-bar__item">
<span class="stats-bar__value">17+</span>
<span class="stats-bar__label label-s">Årelang erfaring</span>
</div>/* template-parts/components/stats-bar.php */
.stats-bar__item { flex: 1; display: flex; flex-direction: column; gap: var(--space-xxs); padding-inline: var(--space-l); }
.stats-bar__item:first-child { padding-left: 0; }
.stats-bar__value { font-size: var(--text-2xl); font-weight: var(--fw-black); line-height: var(--lh-m); color: var(--text-on-dark-primary); }
.stats-bar__label { color: var(--text-on-dark-tertiary); }Service Card
Used in the 2-column services grid. Numbered badge, heading, optional body, and a bottom divider as a visual full-stop. The divider is pushed to the bottom via margin-top: auto.
01
UX / UI Design
End-to-end interface design from research and wireframes through to polished, developer-ready specifications.
Anatomy
- Number — label-s, padded with
str_pad( $i, 2, '0', STR_PAD_LEFT )in PHP - Heading — text-2xl, fw-black
- Body — body-m, optional
- Divider — 1px border-top, pushed to bottom with
margin-top: auto
<div class="svc-card">
<div class="svc-card__title">
<p class="label-s">01</p>
<h2 class="svc-card__heading">UX / UI Design</h2>
</div>
<p class="svc-card__body body-m">End-to-end interface design from research and wireframes through to polished, developer-ready specifications.</p>
<div class="svc-card__divider"></div>
</div>/* page-services.php */
.svc-card { display: flex; flex-direction: column; gap: var(--space-m); padding-block: var(--space-xs); }
.svc-card__title { display: flex; flex-direction: column; gap: var(--space-xs); }
.svc-card__heading { font-size: var(--text-2xl); font-weight: var(--fw-black); color: var(--text-on-dark-primary); line-height: var(--lh-m); margin: 0; }
.svc-card__body { margin: 0; }
.svc-card__divider { margin-top: auto; padding-top: var(--space-m); border-top: 1px solid var(--surface-branding-primary-30); }
@media (max-width: 768px) {
.svc-card__heading { font-size: var(--text-xl); }
}<?php foreach ( $services as $i => $svc ) : ?>
<div class="svc-card">
<div class="svc-card__title">
<p class="label-s"><?php echo str_pad( $i + 1, 2, '0', STR_PAD_LEFT ); ?></p>
<h2 class="svc-card__heading"><?php echo esc_html( $svc['heading'] ); ?></h2>
</div>
<?php if ( $svc['body'] ) : ?>
<p class="svc-card__body body-m"><?php echo nl2br( esc_html( $svc['body'] ) ); ?></p>
<?php endif; ?>
<div class="svc-card__divider"></div>
</div>
<?php endforeach; ?>Accordion Item
Native <details>/<summary> element — no JavaScript required. Chevron SVG rotates 180° via CSS details[open] selector. Used in the Services process section.
Opdagelse og forskning
Once the task type is defined we understand how big the diamonds will be — establishing what we already know and where to source knowledge we need.
Definere
Design criteria agreed and signed off — preventing design loops later.
<div class="svc-accordion">
<details class="svc-accordion__item" open>
<summary class="svc-accordion__summary">
<span class="svc-accordion__title">Opdagelse og forskning</span>
<svg class="svc-accordion__chevron" width="16" height="10" viewbox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M1 1L8 8L15 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
</summary>
<div class="svc-accordion__body">
<p>Establishing what we already know and where to source the knowledge we need.</p>
</div>
</details>
</div>/* page-services.php */
.svc-accordion { display: flex; flex-direction: column; }
.svc-accordion__item { border-top: 1px solid var(--surface-branding-primary-30); }
.svc-accordion__item:last-child { border-bottom: 1px solid var(--surface-branding-primary-30); }
.svc-accordion__summary {
display: flex; align-items: center; justify-content: space-between;
padding-block: var(--space-xl); cursor: pointer; list-style: none; gap: var(--space-l);
}
.svc-accordion__summary::-webkit-details-marker { display: none; }
.svc-accordion__title { font-size: var(--text-2xl); font-weight: var(--fw-black); color: var(--text-on-dark-primary); line-height: var(--lh-m); }
.svc-accordion__chevron { flex-shrink: 0; color: var(--text-on-dark-secondary); transition: transform 0.25s ease; }
details[open] .svc-accordion__chevron { transform: rotate(180deg); }
.svc-accordion__body { padding-bottom: var(--space-xl); }
.svc-accordion__body p { font-size: var(--text-m); color: var(--text-on-dark-tertiary); line-height: var(--lh-xs); margin: 0; }Filter Bar
Full-width bar: .work-filter-bar__tabs on the left, sort label + <select> on the right. Bottom border divides it from the project grid below.
Anatomy
- Tabs left —
.work-filter-bar__tabs· gap:var(--space-xs)8px · idle tabs: grey · active tab: white text + blue::afterunderline - Sort right —
.label-s"Sort by" label +.work-sort-select<select>(not an icon toggle) - Bottom border — 1px
var(--surface-branding-primary-30) - Padding —
padding-bottom: var(--space-2xl)64px
<div class="work-filter-bar container">
<div class="work-filter-bar__tabs" role="tablist" aria-label="Filtrer projekter">
<button class="work-filter-tab work-filter-tab--active" data-filter="all" role="tab" aria-selected="true">Alle projekter</button>
<button class="work-filter-tab" data-filter="ux-design" role="tab" aria-selected="false">UX Design</button>
</div>
<div class="work-filter-bar__sort">
<label for="work-sort" class="label-s">Sortér efter</label>
<select id="work-sort" class="work-sort-select">
<option value="date-desc">Nyeste først</option>
<option value="date-asc">Ældste først</option>
<option value="title-asc">A – Å</option>
</select>
</div>
</div>/* archive-portfolio.php */
.work-filter-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2xl); padding-bottom: var(--space-l); }
.work-filter-bar__tabs { display: flex; align-items: center; gap: var(--space-xs); }
.work-filter-bar__sort { display: flex; align-items: center; gap: var(--space-s); }
.work-filter-bar__sort label { color: var(--text-on-dark-tertiary); }
.work-sort-select {
background: transparent; border: 1px solid var(--surface-branding-primary-30);
border-radius: var(--radius-xxs); color: var(--text-on-dark-primary);
font-family: var(--font-primary); font-size: var(--text-m);
padding: var(--space-xs) var(--space-m); cursor: pointer;
}
.work-sort-select option { background: var(--surface-dominant); }
@media (max-width: 768px) {
.work-filter-bar { flex-direction: column; align-items: flex-start; gap: var(--space-l); }
.work-filter-bar__tabs { flex-wrap: wrap; }
.work-filter-bar__sort { width: 100%; justify-content: space-between; }
}<?php // One tab per project type
foreach ( $filter_terms as $term ) : ?>
<button class="work-filter-tab" data-filter="<?php echo esc_attr( $term->slug ); ?>" role="tab" aria-selected="false"><?php echo esc_html( $term->name ); ?></button>
<?php endforeach; ?>Input Field
Full input molecule — label + base input + optional helper text. Label is always a red semibold uppercase label. Four states matching the base atom.
Anatomy
- Label — .label-s: 12px · 600 · uppercase · red · 2px tracking
- Input base atom — bottom border, Roboto 20px
- Helper text — 12px · coloured to match state (red/green) · only shown on error/success
<div class="contact-form__field">
<label class="label-s" for="contact_email">E-mail <span class="contact-form__required" aria-hidden="true">*</span></label>
<input class="contact-form__input" type="email" id="contact_email" name="contact_email"
required autocomplete="email" placeholder="din@email.com">
</div>
<!-- Two fields side by side -->
<div class="contact-form__row">
<div class="contact-form__field">…</div>
<div class="contact-form__field">…</div>
</div>/* page-contact.php */
.contact-form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2xl); }
.contact-form__field { display: flex; flex-direction: column; gap: var(--space-s); }
.contact-form__required { color: var(--text-on-dark-secondary); }
.contact-form__textarea { resize: vertical; min-height: 160px; }
/* .contact-form__input — see Input (base) */<input class="contact-form__input" type="email" id="contact_email" name="contact_email"
value="<?php echo esc_attr( $_POST['contact_email'] ?? '' ); ?>"
required autocomplete="email" placeholder="your@email.com">Header Text Content
Centred page-header block for interior pages. Sub-heading, hero heading, description, and optional CTA button — all centred in a max-width 800px container.
Tjenester
Design that
delivers
End-to-end UX/UI design — from user research and strategy through to polished, developer-ready specifications.
Anatomy
- Sub-heading — .label-s (12px · 600 · red · uppercase)
- Heading — .heading-xxxl / .heading-xxl (responsive, 900 weight)
- Description — .body-l (Roboto 20px · tertiary)
- CTA — .btn.btn-secondary (optional, e.g. PDF download)
- Container — text-align:center · max-width: 800px · margin-inline:auto
<header class="page-header">
<p class="label-s">Tjenester</p>
<h1 class="page-header__heading">Design that<br>delivers</h1>
<p class="body-l">End-to-end UX/UI design — from user research and strategy through to polished, developer-ready specifications.</p>
<div><a href="/da/services.pdf/" class="btn btn-secondary">Download PDF</a></div>
</header>.page-header {
text-align: center;
max-width: 800px;
margin-inline: auto;
display: flex; flex-direction: column;
gap: var(--space-xl);
}
.page-header__heading {
font-size: clamp(var(--text-3xl), 6vw, var(--text-5xl));
font-weight: var(--fw-black);
color: var(--text-on-dark-primary);
line-height: 1.05;
letter-spacing: var(--ls-heading);
margin: 0;
}
.page-header .body-l { margin: 0; }Table Row
Individual row within the Table organism. Two types: header (2px bottom border) and body (1px). Column 1 is always red; remaining columns are grey.
| Feature | That's Adam | Competitor |
|---|
| Responsive | Full | Partial |
| Process |
|
|
Header col 1var(--text-xl) 24px · var(--fw-black) · var(--text-on-dark-secondary) redHeader othervar(--text-l) 20px · var(--fw-black) · var(--text-on-dark-tertiary)Body col 1var(--text-m) 16px · var(--fw-semibold) · uppercase · 4px tracking · redBody othervar(--text-m) 16px · var(--fw-regular) · tertiarypaddingvar(--space-l) var(--space-m) — 24px 16px<table class="acf-table">
<thead>
<tr><th>Feature</th><th>That's Adam</th><th>Competitor</th></tr>
</thead>
<tbody>
<!-- Single value -->
<tr>
<td><div class="acf-table__label-cell">Responsive</div></td>
<td>Full</td>
<td>Partial</td>
</tr>
<!-- Multi value: a cell with more than one line becomes a bullet list -->
<tr>
<td><div class="acf-table__label-cell">Process</div></td>
<td><ul class="acf-table__bullets"><li>Figma source of truth</li><li>CSS design tokens</li><li>Living docs</li></ul></td>
<td>Style guide only</td>
</tr>
</tbody>
</table>/* single-portfolio.php */
.acf-table th, .acf-table td { padding: var(--space-l) var(--space-m); text-align: left; vertical-align: middle; border-bottom: 1px solid var(--surface-branding-primary-30); }
.acf-table th:first-child, .acf-table td:first-child { padding-left: 0; }
.acf-table th { font-size: var(--text-l); font-weight: var(--fw-black); color: var(--text-on-dark-tertiary); border-bottom: 2px solid var(--surface-branding-primary-30); }
.acf-table th:first-child { font-size: var(--text-xl); color: var(--text-on-dark-secondary); }
.acf-table td { font-size: var(--text-m); color: var(--text-on-dark-tertiary); line-height: var(--lh-xs); }
.acf-table td:first-child { font-weight: var(--fw-semibold); color: var(--text-on-dark-secondary); text-transform: uppercase; letter-spacing: 4px; }
.acf-table__label-cell { display: flex; flex-direction: row; align-items: center; gap: var(--space-m); }Bio
Persona bio column. Name → glowing divider → italic quote → list items → demographics block. Demographics are indented 68px to align with list item text.
Marcus Klein
"I don't have time to decode a portfolio — show me the impact."
Interests: Startups, SaaS, impact metrics
Job: Head of Product
Location: Copenhagen, Denmark
Age Group: 35–44
Anatomy
- Navn — 48px · 900 · primary · letter-spacing: -0.03em
- Glowing divider — 2px height · primary background · box-shadow 0 0 30px black shadow
- Quote — var(--text-2xl) · var(--fw-regular) · italic · primary
- List items — List item atoms (thumb icons + bold label + body)
- Demographics — padding-left: 68px (= 44px icon + 24px gap)
<div class="prs-card__bio-col">
<div class="prs-card__heading-wrap">
<h3 class="prs-card__name">Marcus Klein</h3>
<div class="prs-card__divider" aria-hidden="true"></div>
<p class="prs-card__quote">“I don't have time to decode a portfolio — show me the impact.”</p>
</div>
<div class="prs-card__list-items">
<div class="prs-li">…</div> <!-- List Item atom -->
</div>
<div class="prs-card__demographics">
<p class="prs-demo__line"><strong>Job:</strong> Head of Product</p>
<p class="prs-demo__line"><strong>Location:</strong> Copenhagen, Denmark</p>
<p class="prs-demo__line"><strong>Age Group:</strong> 35–44</p>
</div>
</div>/* template-parts/acf-blocks/personas.php */
.prs-card__name { font-size: 48px; line-height: 56px; font-weight: 900; color: var(--text-on-dark-primary); margin: 0; letter-spacing: -0.03em; }
.prs-card__divider {
height: 2px; width: 100%;
background: var(--surface-branding-primary);
box-shadow: 0 0 30px 0 var(--shadow-glow);
border-radius: 1px;
}
.prs-card__quote { font-size: 32px; line-height: 56px; font-weight: 400; font-style: italic; color: var(--text-on-dark-primary); margin: 0; }
.prs-card__demographics { padding-left: 68px; } /* 44px icon + 24px gap */
.prs-demo__line { font-size: 16px; font-weight: 400; line-height: 24px; color: var(--text-on-dark-tertiary); margin: 0; }Card
Generic content card used across multiple sections. Optional rounded image, red title, grey body. The image slot is 106×106px with 8px radius.
UX Research
Systematic investigation to understand user needs and behaviours before committing to a direction.
Without image
When no image is present the card begins directly with the title. Often used for service descriptions.
image106×106px · border-radius: var(--radius-xs) 8px · optionaltitlevar(--text-xl) 24px · var(--fw-black) · var(--text-on-dark-secondary) redbodyvar(--text-m) 16px · var(--fw-regular) · var(--text-on-dark-tertiary)gapimage→text: var(--space-l) 24px · title→body: var(--space-s) 12px<article class="content-card">
<img class="content-card__img" src="research.jpg" alt="" width="106" height="106"> <!-- optional -->
<div class="content-card__text">
<h3 class="content-card__title">UX Research</h3>
<p class="content-card__body">Systematic investigation to understand user needs and behaviours before committing to a direction.</p>
</div>
</article>.content-card { display: flex; flex-direction: column; gap: var(--space-l); max-width: 280px; }
.content-card__img { width: 106px; height: 106px; object-fit: cover; border-radius: var(--radius-xs); }
.content-card__text { display: flex; flex-direction: column; gap: var(--space-s); }
.content-card__title {
font-size: var(--text-xl); font-weight: var(--fw-black);
color: var(--text-on-dark-secondary); margin: 0;
}
.content-card__body {
font-size: var(--text-m); font-weight: var(--fw-regular);
color: var(--text-on-dark-tertiary); line-height: var(--lh-xs); margin: 0;
}