hcd.ai — Design System

Visual Language

Single source of truth for all visual and UI decisions across the hcd.ai editorial platform. Every colour token, type scale value, spacing unit, component pattern, and layout rule — in one place.

Editorial
Magazine aesthetic. Strong type hierarchy. Content-first.
Restrained
One gradient per viewport. Whitespace is the decoration.
Accessible
WCAG 2.2 AA throughout. Every interactive colour tested.

Aesthetic Direction

The visual design says "senior practitioner who writes clearly" — not "agency portfolio" or "SaaS landing page".

Direction
Editorial / Magazine. Strong typographic hierarchy, generous whitespace, content-first. The brand gradient is the only decorative flourish — everything else is typography and whitespace.
Mood
Authoritative but approachable. Senior practitioner energy — not corporate gloss, not startup exuberance.
Anti-patterns
No hero images with gradient overlays. No 3-column feature grids with icon circles. No bubbly uniform border-radius. No purple/violet gradients. No stock-photo heroes.

Brand Identity

The logo mark and brand name — usage rules that govern every placement.

Logo Mark
36px
28px
20px
Always rounded-full — the circular mark uses border-radius: 9999px. Never oval, never square. Minimum 16px clear space on all sides. Source SVG at /assets/images/logo.svg.
Brand Name Styling

In visible body text, "hcd.ai" is always wrapped at font-weight 500:

<span class="font-medium">hcd.ai</span>
Exceptions: URLs, schema markup, meta tags, alt text, and headings (already bold) do not require the wrapper.

Brand Gradient

The signature visual element. Used sparingly — maximum one gradient element per viewport.

Cyan — start
#00c4cc
Green — middle
#6de847
Yellow — end
#e8f700
Approved uses
Gradient dividers (2px horizontal rules)
Gradient button fill (.btn-gradient)
Featured card shimmer overlays
Direct-answer underlines
Text selection background (yellow only)
Logo mark background
Rule: Maximum one gradient element per viewport. Gradient colours are never used as text colour, border colour, or shadow colour. They only appear in gradient contexts.
CSS Declaration
/* Gradient divider */ .divider-gradient { border: 0; height: 2px; background: linear-gradient(90deg, #00c4cc, #6de847, #e8f700); } /* Gradient button */ .btn-gradient { background: linear-gradient(135deg, #00c4cc, #6de847, #e8f700); }

Colour System

All colours defined in tailwind.config.js under colors.brand.*. Text hierarchy is weight-based, not colour-based.

Brand Gradient Colours (decorative use only)
brand-cyan
#00c4cc
Gradient start. Never standalone for text or borders.
brand-cyan-light
#e0f7f8
Subtle cyan tint backgrounds.
brand-green
#6de847
Gradient middle.
brand-green-light
#edfce6
Subtle green tint backgrounds.
brand-yellow
#e8f700
Gradient end. Text selection background.
brand-yellow-light
#fafde6
Subtle yellow tint backgrounds.
Accessible UI Colours (WCAG 2.2 AA on white)
brand-accent
#0e7490
Links, interactive text, focus rings, category labels.
4.56:1
brand-accent-hover
#0c5e73
Hover state for accent elements.
5.89:1
brand-dark
#0a0a0a
Headings, bold text, primary labels.
19.4:1
brand-text
#3a3a3a
Body text, descriptions.
10.3:1
brand-text-light
#6b6b6b
Secondary labels, descriptions, footer links.
5.33:1
brand-text-muted
#767676
Dates, hints, breadcrumbs. AA minimum.
4.54:1
brand-border
#d4d4d4
Decorative borders, dividers, card outlines.
brand-bg / surface
#ffffff
Page background, card/surface background.
Semantic Colours (not in Tailwind config)
Success
#38b858
Not currently used.
Warning
#e8a838
Not currently used.
Error
#e84040
Not currently used.
Info
#0e7490
Same as brand-accent.
Colour Rules
  1. Accent (#0e7490) is the only colour used for interactive text. Links, category labels, hover arrows — all accent.
  2. Brand gradient colours are never used as text or border colours. Only in gradient contexts.
  3. Text hierarchy is weight-based, not colour-based: dark for headings, text for body, text-light for secondary, text-muted for tertiary.
  4. No dark mode. The site is light-only. Code blocks use a dark surface (#1e1e2e) as the only exception.

Typography

Inter for all display and body text. JetBrains Mono for code and data watermarks. Both served via Google Fonts.

Font Stack
Role Font Weights Loading
Primary (display + body) Inter 400, 500, 600, 700 Google Fonts, display=swap
Code / data JetBrains Mono 500 Google Fonts, bundled with Inter
Code blocks SF Mono, Fira Code, Fira Mono, Roboto Mono System stack fallback
Fallback system-ui, sans-serif System
Type Scale — Live Examples
Display
clamp(2.5rem, 5vw, 4.5rem)
weight: 600
tracking: -0.03em
lh: 1.05
hcd.ai
Display-sm
clamp(2rem, 3.5vw, 3rem)
weight: 600
tracking: -0.02em
lh: 1.1
Design Systems
Section label
12px
weight: 500
tracking: 0.2em
uppercase
Category label
12px
weight: 500
tracking: 0.15em
accent colour
AI in Practice
Article title
18px
weight: 500
tracking: tight
lh: snug
What Is Human-Centred AI Systems Design?
Body (prose)
16px
weight: 400
tracking: normal
lh: 1.75
The most durable competitive advantage is not the algorithm — it is the quality of the decision-making system wrapped around it. Practitioners who understand both the technology and the human system it operates within are the ones building things that last.
Body (UI)
14px
weight: 400
tracking: normal
lh: relaxed
Navigation, footer, descriptions, secondary content. Slightly smaller than prose but same family and colour.
Small
12px
weight: 400–500
dates, hints
2 April 2026  ·  8 min read  ·  AI in Practice
Typography Rules
  1. Headings use negative letter-spacing: -0.02em for h1/h2, -0.03em for display.
  2. Body text is 16px with 1.75 line-height. Generous leading for readability.
  3. Section labels are always uppercase with wide tracking (0.2em). Primary structural signposting mechanism.
  4. Category labels use accent colour (#0e7490) with uppercase tracking (0.15em).
  5. No font-weight above 700. Inter weights used: 400 (body), 500 (medium), 600 (headings), 700 (rare).
  6. Brand name "hcd.ai" always rendered at font-weight 500 in body text.

Spacing

Base unit is 4px (Tailwind default). The density is spacious — editorial sites need room to breathe.

Scale
space-1 4px
space-2 8px
space-3 12px
space-4 16px
space-5 20px
space-6 24px
space-8 32px
space-10 40px
space-12 48px
space-16 64px
space-20 80px
space-28 112px
space-32 128px
Vertical Rhythm Reference
Context Spacing Tailwind
Section top padding80–128pxpt-20 md:pt-32
Section bottom padding80–112pxpb-20 md:pb-28
Between section label and content24–48pxmb-6 to mb-12
Between heading and body20–32pxmb-5 to mb-8
List item spacing0 (borders separate)space-y-0 + py-5 per row
Footer top margin128pxmt-32
Content max-width1280pxmax-w-content
Prose max-width720pxmax-w-prose
Horizontal padding — mobile24pxpx-6
Horizontal padding — desktop40pxmd:px-10

Layout & Grid

Grid-disciplined editorial. 12-column on desktop. Mobile-first.

PropertyValue
Grid columns (desktop)grid-cols-12
Grid (mobile)Single column
Content max-width1280px (max-w-content)
Prose max-width720px (max-w-prose)
Article split7/5 (content / sidebar)
Homepage hero split2-col 50/50
Featured card grid3-column (md:grid-cols-3)
Mobile breakpoint414px baseline
Tablet breakpointmd: — 768px
Desktop breakpointlg: — 1024px+
Editorial list columns (12-col grid): Col 1 = index/date (text-muted), Cols 2–3 = category label (accent, uppercase), Cols 4–11 = title (dark, medium), Col 12 = arrow indicator.

Border Radius

Radius increases with element size — small elements get small radius, large surfaces get large radius.

None 0px Dividers, borders
Small 4px Inline code badges
Medium 8px Hover row, copy buttons
Large 12px rounded-xl Code blocks, accordions
XL 16px rounded-2xl Featured cards
2XL 24px rounded-3xl Article hero images
Full 9999px rounded-full Buttons, logo, filter pills
Radius Rules
  1. Buttons are always pill-shaped (rounded-full). No square or slightly-rounded buttons.
  2. Cards use rounded-2xl (16px).
  3. Article hero images use rounded-3xl (24px).
  4. The radius increases with element size — creating visual hierarchy in curvature.

Buttons

Always pill-shaped. Three variants. All share the same padding and size.

Variant Class Background Text Border Use
Gradient .btn-gradient Brand gradient brand-dark none Hero CTA
Accent .btn-accent #0e7490 white none Primary actions (rare)
Outline .btn-outline transparent brand-dark 1px brand-dark Secondary actions
Shared properties: rounded-full, text-sm, px-5, py-2.5, inline-flex items-center gap-2, transition-all. Focus state: 2px ring, brand-accent, 2px offset.
Code
<!-- Gradient button --> <button class="btn-gradient">Explore articles ↗</button> <!-- Accent button --> <button class="btn-accent">Get in touch</button> <!-- Outline button --> <button class="btn-outline">View all articles</button>

Dividers

Two variants. The gradient divider is used sparingly as a major section separator.

Standard

Gradient

VariantClassStyleUse
Standard .divider 1px top border, brand-border List items, footer sections
Gradient .divider-gradient 2px height, brand gradient Major section separators (before Pillars, before About)

Cards

Featured cards use a gradient tint background with a JetBrains Mono watermark. Hover triggers the shimmer sweep.

cardStat is a Frontmatter field (max 24 chars). It renders as the watermark — JetBrains Mono, 44px, 27% opacity brand-accent. Cards are not photographic. The gradient tint and cardStat provide the visual interest.
Featured Card Spec
PropertyValue
Border radius16px (rounded-2xl)
Aspect ratio4:3 (aspect-[4/3])
BackgroundGradient tint: cyan 15% → green 10% → yellow 8%
cardStat fontJetBrains Mono 500, 44px, 27% opacity brand-accent
Shimmer duration800ms ease-in-out
Reduced motionShimmer duration → 0.01ms

Editorial Lists

The primary content navigation pattern. Denser than cards — more content per viewport. A 12-column grid within each full-width row.

Row structure: Index (text-muted, JetBrains Mono) / Category (accent, uppercase, 0.15em tracking) / Title (brand-dark, font-weight 500) / Arrow (muted, transitions to accent on hover). Hover background: rgba(0, 196, 204, 0.05).

Accordions

Used for FAQ sections. details/summary semantics. Chevron rotates on open.

A discipline that places human cognition, values, and oversight at the centre of how AI systems are designed, deployed, and governed. It extends human-centred design principles into the agentic and autonomous domain.
Restraint forces prioritisation. When the brand gradient is the only flourish and whitespace is the decoration, every element earns its presence. The result is editorial clarity over visual noise.
Spec
PropertyValue
Containerborder border-brand-border rounded-xl overflow-hidden
Trigger paddingpx-6 py-4, font-weight 500, brand-dark
Chevron rotation0deg → 180deg, 300ms ease
Panel transitionmax-height + opacity, 300ms ease
ARIAaria-expanded on trigger, aria-controls linking to panel

Filter Pills

Used on article listing pages to filter by pillar. Always pill-shaped. Same shape language as buttons.

Active state: bg-brand-dark text-white border-brand-dark. Hover: border transitions to brand-dark, text to brand-dark. All pills: rounded-full text-xs font-medium px-4 py-2.

Code Blocks

Dark surface (#1e1e2e) — the only dark surface in an otherwise all-light design system. 12px rounded-xl. Copy button top-right.

.featured-card { background: linear-gradient(135deg, rgba(0, 196, 204, 0.15), rgba(109, 232, 71, 0.10), rgba(232, 247, 0, 0.08) ); border-radius: 16px; /* rounded-2xl */ aspect-ratio: 4 / 3; }
Inline Code

Inline code uses bg-gray-100, font-medium, px-1.5 py-0.5, rounded (4px). Font: SF Mono / Fira Code system stack.

Code Block Spec
PropertyValue
Background#1e1e2e
Text colour#cdd6f4
Border radius12px (rounded-xl)
FontSF Mono → Fira Code → Fira Mono → Roboto Mono → system monospace
Font size14px
Line height1.625
Padding48px top (copy button space), 24px sides/bottom
Copy buttonTop-right, rgba(255,255,255,0.08) bg, #a6adc8 text. Copied state: #a6e3a1

Images

Organic, sophisticated, dark backgrounds preferred. No cliche AI imagery. Midjourney is the primary generation tool.

3:4 portrait — article hero

Article hero: aspect-ratio 3:4, rounded-3xl (24px), zoomed: scale-125 translate-y-[50px]. Loading: eager for above-fold.

4:3 — featured card background

Featured cards: Not photographic. Use gradient tint + cardStat watermark.

Image Style Guidelines
Organic, sophisticated compositions. Dark or neutral backgrounds preferred.
No cliche AI imagery: no robots, glowing brains, or neural network visualisations.
Photographer angle: natural shadows, textured materials, environmental context, activity over posing.
Midjourney is the primary generation tool.
Credit format: "Created with Midjourney" linked to midjourney.com. 12px text-muted below image.

Motion

Minimal-functional. Only transitions that aid comprehension. All animations respect prefers-reduced-motion: reduce.

Element Duration Easing What changes
Link hover 150ms ease Colour
Button hover 150ms ease Background / colour
Skip link 150ms ease Slide into view (top offset)
Accordion 300ms ease max-height + opacity
Image hover 500ms ease-out brightness(1.03) + scale(1.01)
Card shimmer 800ms ease-in-out Gradient sweep (translateX)
Reduced Motion
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } }

Accessibility

WCAG 2.2 AA throughout. Every interactive colour tested for contrast. Focus visible on all keyboard-focusable elements.

RequirementImplementation
StandardWCAG 2.2 AA
Focus indicator2px solid #0e7490, 2px offset on all interactive elements
Minimum contrast4.54:1 (brand-text-muted on white — AA minimum)
Skip linkHidden until focused, slides into view top-left
Screen reader text.sr-only class for visually hidden content
Landmarks<header>, <main>, <footer>, <nav aria-label>
ImagesAll images require descriptive alt text. Decorative elements: aria-hidden="true"
External links↗ indicator via CSS, accessible via content: " \2197" / ""
Reduced motionFull prefers-reduced-motion support — all durations → 0.01ms
Accordion ARIAaria-expanded on trigger, aria-controls linking to panel id
Filter pillsaria-pressed for toggle state
Focus indicator in CSS: :focus-visible { outline: 2px solid #0e7490; outline-offset: 2px; } Buttons use ring syntax: box-shadow: 0 0 0 2px #fff, 0 0 0 4px #0e7490.

Schema & SEO

JSON-LD structured data on every page. Implemented in <script type="application/ld+json"> in <head>.

Schema typePagesKey fields
WebSiteEvery pagepublisher, logo, founder
ArticleAll post pagesheadline, description, dates, author, pillar as articleSection
BreadcrumbListAll post pagesHome › Pillar › Article
PersonAbout pageDetailed profile: awards, alumni, knowsAbout
P0 schema bugs (outstanding): Article schema must be in <head> (not body), FAQPage schema must be in <head>, Person schema missing on About page. These are priority fixes before next content publish.

Decisions Log

Rationale behind the key design choices. Understanding why prevents drift.

DateDecisionRationale
2026-03-17 WordPress to Eleventy static Full control over markup, SEO, performance
2026-03-17 Inter as sole typeface Clean, professional, excellent weight range, ubiquitous web font loading
2026-03-17 Editorial list pattern over card grids Denser, scannable, more content per viewport. Cards only for featured
2026-03-17 Pill buttons only Consistent shape language. Rounded-full everywhere
2026-03-17 No dark mode Editorial content sites are light. Code blocks are the exception
2026-03-17 Gradient as accent, not foundation One gradient divider or button per section. Restraint is the brand
2026-03-24 Design system codified Extracted from live site into DESIGN.md as single source of truth

File Structure

How the design system maps to the Eleventy source files.

static-site/ tailwind.config.js -- Colour palette, typography, max-widths (token source of truth) src/assets/css/input.css -- Component utilities, custom CSS (component source of truth) src/assets/css/output.css -- Generated CSS (do not edit) src/_includes/layouts/ base.njk -- Shell: head, header, footer, scripts post.njk -- Article layout (extends base) commentary.njk -- Commentary layout (extends base) src/index.njk -- Homepage src/articles.njk -- Article listing src/about.njk -- About page src/contact.njk -- Contact page