Overview

This document defines the design system for stoll.studio, including the theming system, colors, typography, spacing, layout, and components. All design tokens are implemented as CSS custom properties in a 5-tier architecture.

Global Constants Fixed values (black, white, phosphor): never change across themes
Base Tokens Per-theme primitives (text, accents, surfaces, borders, spacing scale, type scale)
Status Tokens Per-theme state values (info, success, error, warning)
Semantic Tokens Reference base/status tokens for specific purposes (links, bullets, code)
Component Tokens Reference base/semantic tokens for specific components (sticky bar, blockquotes, skip link)
Behind the scenes

This page documents the design system. The CSS manifests it. The Figma file materializes it. As a space for visual exploration and adjustment. Plotting out the token architecture as Figma variables and building a dedicated Token Inspector page allows to see the system as a whole and refactor it with confidence.

This page Documents the system: tokens, components, decisions, changelog
themes.css Manifests the system: CSS custom properties, theme definitions
Figma file Materializes the system: Figma variables mirroring the token structure, Token Inspector page for visual review and color exploration

Open Figma Token Inspector ↗

Themes

Four themes available, activated via URL parameter (?theme=name) or the footer switcher. Themes override base color tokens; semantic and component tokens inherit automatically.

Light Light theme: white surface, Hanken Grotesk, yellow accent bar with black text
Dark Dark theme: #1a1a1a surface, Hanken Grotesk, blue bar (#5dade2) with black text
Vibrant Vibrant blue (#3D38F5) surface, pink (#FF0080) accents, lime (#D4FF00) links
Terminal Single phosphor green (#00FF41) at varying opacities on pure black (#000), IBM Plex Mono throughout, normal weight (400) for all text

Theme switching is handled by theme-switcher.js which reads the URL parameter, applies the data-theme attribute on <html>, and propagates the theme to all internal links. A critical inline script in <head> prevents flash of unstyled content.

Light Theme Colors

Text colors.

Primary #313131: main headings, strong text
Secondary #515151: body text, paragraphs
Tertiary #7a7a7a: muted text, bullets
Quaternary #9a9a9a: dates, very muted elements
Light #c0c0c0: taglines, very light text

Accent, surface and border colors.

Accent 1 #ffff00: signature yellow
Accent 2 #268bd2: blue (links, code)
Accent 3 #ff0000: red accent
Surface #ffffff: main background
Surface Emphasized #f5f5f5: table headers, cards
Surface Secondary #f9f9f9: code blocks, blockquotes
Border #eee: primary borders
Border Secondary #e5e5e5: secondary borders
Border Strong #cccccc: structural dividers
Image BG #d5d5d5: translucent image card background

Status colors.

Info #268bd2: informational (blue)
Success #27ae60: success states (green)
Error #e74c3c: error states (red)
Warning #f39c12: warning states (orange)

Semantic and component colors.

Divider #cccccc: structural dividers (via Border Strong)
Link #268bd2: links (via Info/Accent 2)
Hover opacity: 0.75 on a:hover / a:focus, no color token, theme-agnostic
Code #268bd2: inline code text (via Accent 2)
Bullet #7a7a7a: list bullets (via Tertiary)
Meta #7a7a7a: figcaptions, project meta table headers, blockquote citations (via Tertiary)
Meta Secondary #9a9a9a: project subtitles, project credits (via Quaternary)
Sticky Bar BG #ffff00: Accent 1 yellow
Sticky Bar Text #000: black
Blockquote BG #f9f9f9: blockquote background (via Surface Secondary)
Blockquote Border #ffff00: blockquote left border (via Accent 1)
Skip Link BG #000: skip-to-content background (global black)
Skip Link Text #fff: skip-to-content text (global white)
Dark Theme Colors

Text colors.

Primary #ffffff: main headings, strong text
Secondary #e0e0e0: body text, paragraphs
Tertiary #b0b0b0: muted text, bullets
Quaternary #808080: dates, very muted elements
Light #606060: taglines, very light text

Accent, surface and border colors.

Accent 1 #ffff00: signature yellow
Accent 2 #5dade2: blue
Accent 3 #ff0000: red accent
Surface #1a1a1a: main background
Surface Emphasized #2a2a2a: table headers, cards
Surface Secondary #242424: code blocks, blockquotes
Border #333: primary borders
Border Secondary #444: secondary borders
Border Strong #666666: structural dividers

Status colors.

Info #5dade2: informational (blue)
Success #2ecc71: success states (green)
Error #e74c3c: error states (red)
Warning #f39c12: warning states (orange)

Semantic and component colors.

Divider #666666: structural dividers (via Border Strong)
Link #5dade2: links, interactive elements
Hover opacity: 0.75 on a:hover / a:focus, no color token, theme-agnostic
Code #5dade2: inline code text (via Accent 2)
Bullet #b0b0b0: list bullets (via Tertiary)
Meta #b0b0b0: figcaptions, project meta table headers, blockquote citations (via Tertiary)
Meta Secondary #808080: project subtitles, project credits (via Quaternary)
Sticky Bar BG #5dade2: Accent 2 blue
Sticky Bar Text #000: black
Blockquote BG #242424: blockquote background (via Surface Secondary)
Blockquote Border #ffff00: blockquote left border (via Accent 1)
Skip Link BG #000: skip-to-content background (global black)
Skip Link Text #fff: skip-to-content text (global white)
Vibrant Theme Colors

Text colors.

Primary #ffffff: main headings, strong text
Secondary rgba(255, 255, 255, 0.75): body text
Tertiary rgba(255, 255, 255, 0.6): muted text
Quaternary rgba(255, 255, 255, 0.45): dates, very muted
Light rgba(255, 255, 255, 0.3): taglines

Accent, surface and border colors.

Accent 1 #FF0080: pink
Accent 2 #D4FF00: lime
Accent 3 #00FFD9: cyan-teal accent
Surface #3D38F5: vibrant blue background
Surface Emphasized #312CDB: table headers, cards
Surface Secondary #4942F7: code blocks, blockquotes
Border rgba(255, 255, 255, 0.15): primary borders
Border Secondary rgba(255, 255, 255, 0.2): secondary borders
Border Strong rgba(255, 255, 255, 0.3): structural dividers

Status colors.

Info #69A0FF: informational (blue)
Success #00FF33: success states (green)
Error #FF3366: error states (red)
Warning #FFB800: warning states (orange)

Semantic and component colors.

Divider rgba(255, 255, 255, 0.3): structural dividers (via Border Strong)
Link #D4FF00: lime links
Hover opacity: 0.75 on a:hover / a:focus, no color token, theme-agnostic
Code #D4FF00: inline code text (via Accent 2 lime)
Bullet rgba(255, 255, 255, 0.4): list bullets (white-40)
Meta rgba(255, 255, 255, 0.6): figcaptions, project meta table headers, blockquote citations (via Tertiary / white-60)
Meta Secondary rgba(255, 255, 255, 0.45): project subtitles, project credits (via Quaternary / white-45)
Sticky Bar BG #FF0080: Accent 1 pink
Sticky Bar Text #fff: white
Blockquote BG #4942F7: blockquote background (via Surface Secondary)
Blockquote Border #FF0080: blockquote left border (via Accent 1 pink)
Skip Link BG #FF0080: skip-to-content background (Accent 1 pink)
Skip Link Text #fff: skip-to-content text (global white)
Terminal Theme Colors

Text colors.

Primary #00FF41: phosphor green, all headings
Secondary rgba(0, 255, 65, 0.85): body text
Tertiary rgba(0, 255, 65, 0.70): muted text
Quaternary rgba(0, 255, 65, 0.60): dates, very muted
Light rgba(0, 255, 65, 0.50): taglines

Accent, surface and border colors.

Accent 1 #00FF41: phosphor green (all accents unified)
Accent 2 #00FF41: phosphor green (all accents unified)
Accent 3 #00FF41: phosphor green (all accents unified)
Surface #000000: pure black background
Surface Emphasized #111111: table headers, cards
Surface Secondary #222222: code blocks, blockquotes
Border rgba(0, 255, 65, 0.15): primary borders
Border Secondary rgba(0, 255, 65, 0.2): secondary borders
Border Strong rgba(0, 255, 65, 0.30): structural dividers

Status colors.

Info #00BFFF: informational (cyan-blue)
Success #00FF41: success states (phosphor green)
Error #FF0000: error states (red)
Warning #FFFF00: warning states (yellow)

Semantic and component colors.

Divider rgba(0, 255, 65, 0.30): structural dividers (via Border Strong)
Link #00FF41: terminal green links (uses Primary color)
Hover opacity: 0.75 on a:hover / a:focus, no color token, theme-agnostic
Code #00FF41: inline code text (via Accent 2, phosphor green)
Bullet rgba(0, 255, 65, 0.4): list bullets (phosphor-40)
Meta rgba(0, 255, 65, 0.70): figcaptions, project meta table headers, blockquote citations (via Tertiary / phosphor-70)
Meta Secondary rgba(0, 255, 65, 0.60): project subtitles, project credits (via Quaternary / phosphor-60)
Sticky Bar BG #00FF41: terminal green
Sticky Bar Text #000: black
Blockquote BG #222222: blockquote background (via Surface Secondary)
Blockquote Border #00FF41: blockquote left border (via Accent 1, phosphor)
Skip Link BG #00FF41: skip-to-content background (Accent 1, phosphor)
Skip Link Text #000: skip-to-content text (global black)

Typography: Terminal theme uses monospace font throughout for authentic terminal aesthetic.

Font Family IBM Plex Mono everywhere (headings, body, navigation, all text)
Font Weight All weights normalized to 400 (normal): headings, body, bold text all use regular weight for authentic terminal look
Typography

Font families and their usage across the site.

Primary Hanken Grotesk (variable, 100–900): body text, headings, labels
Monospace IBM Plex Mono: code blocks, navigation links

Font sizes (desktop base: 20px, mobile base: 18px).

H1 2rem (40px): page titles
H2 1.3rem (26px) desktop, 1.8rem mobile: main statements
H3 1.25rem (25px) desktop, 1.4rem mobile
Body 1rem (20px) desktop, 1.05rem mobile
Masthead 1.5rem (30px) desktop, 1.6rem mobile
Small/Meta 0.8–0.85rem (16–17px): captions, dates, notes

Font weights using variable font capabilities.

300 Light
400 Regular (default body text)
500 Medium (navigation links)
550 Between medium and semi-bold (two-col labels)
600 Semi-bold (headings, bold text)
Spacing

Spacing scale using rem units (scales with base font size).

XS 0.25rem (5px): tight spacing, table cells
SM 0.5rem (10px): small gaps, heading margins
MD 1rem (20px): standard spacing, paragraph margins, navigation gap
LG 1.5rem (30px): section spacing, figures
XL 2rem (40px): large spacing, project credits
2XL 2.5rem (50px): section dividers (two-col margin-bottom)
3XL 3rem (60px): masthead margin
Layout

Breakpoints and responsive behavior.

Desktop ≥769px: two-column grids, inline navigation, container max-width 72rem
Mobile ≤768px: single column, hamburger menu with overlay, theme select dropdown, 18px base font
Small ≤600px: project column grids collapse to single column

Two-column structural layout (.two-col): the primary layout pattern used across all pages.

.two-col Grid section: 30% / 1fr on desktop, stacked on mobile. Top border, 0.75rem padding-top, 2.5rem margin-bottom.
.two-col-label Left column: topic name or section headline. Font-weight 550, primary color.
.two-col-role Right column, row 1: role or subtitle. Secondary color, 0.75rem margin-bottom.
.two-col-content Right column: body text, tables, nested grids. Spans rows 2–20 (or 1–20 when no role).
.two-col-note Left column, row 2: muted sidenote. 0.8rem, quaternary color.

Column grids: nest inside .two-col-content. Shared across stoll.studio (project.css) and teaching.stoll.studio (course.css). Usage: <div class="columns columns-2">.

.columns-2 Two equal columns (1fr 1fr). Collapses to 1 column on mobile.
.columns-3 Three equal columns (1fr 1fr 1fr). Collapses to 1 column on mobile.
.columns-4 Four equal columns. Collapses to 2 columns on mobile (not 1: image grids stay readable at 2).
.columns-1-2 Asymmetric, small left (1fr 2fr). Collapses to 1 column on mobile.
.columns-2-1 Asymmetric, large left (2fr 1fr). Collapses to 1 column on mobile.
Components

Navigation. Desktop: horizontal inline with masthead (flexbox, baseline-aligned). Mobile: hamburger menu with full-screen overlay.

Active state Underline via aria-current="page", 6px offset, 2px thickness
Hover state Same underline style as active state
Font IBM Plex Mono, weight 500
Mobile toggle CSS-only hamburger icon (3 lines, 24×2px, 7px spacing), animates to X on open. Uses var(--color-primary).
Mobile overlay Full-screen fixed overlay (z-index: 100001), var(--color-surface) background, vertical links at 1.5rem, fadein animation.
Mobile a11y aria-expanded, aria-label toggling, Escape key closes, body scroll lock when open.

Sticky bar: position sticky at top, z-index 99999.

Light Yellow (#ffff00) background, black text
Dark Blue (#5dade2) background, black text
Vibrant Pink (#FF0080) background, white text
Terminal Terminal green (#00FF41) background, black text

Content table (.content-table): a lightweight table used for structured lists across all pages.

.pl-year Optional first column: year/date, nowrap, secondary color, 1% width
.pl-name Name column: nowrap, bold label with optional small subtitle
.pl-desc Description column: secondary color, wrapping text

Table behavior rules.

First row No top padding (aligns with label baseline)
Last row No bottom border or padding
After paragraph p + .content-table adds top border and padding on first row
Mobile .pl-year hidden, data-year attribute shown as small label above name

Other components.

Custom bullets ⚬ character, tertiary color, 0.9em indent. Navigation excluded.
Blockquotes Surface-secondary background, 4px --color-accent-1 left border, 0.95rem text. Accent 1 is yellow in light/dark/terminal, pink in vibrant.
Figures 1.5rem margin, caption 0.8rem italic in meta color
Header Flex container: H1 left, inline meta right (language switcher, page note), baseline-aligned. Stacks vertically on mobile.
Footer Desktop: flex row, copyright left, theme links + DS link right. Mobile: stacked column, right-aligned, theme <select> dropdown replaces inline links.
Contact Form
AI agent-ready by design

Contact form (.contact-form): loaded via contact-form.css on the Contact page only. All fields are fully theme-aware through CSS custom properties.

Field layout .contact-form-field wrapper, 1rem bottom margin. Label above input, display: block, font-weight 500, --color-primary.
Inputs / textarea Full-width, 0.5rem padding, 4px border-radius. Border: --color-divider. Background: --color-surface. Text: --color-primary via both color and -webkit-text-fill-color (prevents browser override).
Select Native appearance removed. Custom arrow via ::after on the field wrapper (:has(select)). Options get explicit background/color to override browser defaults in dark themes.
Focus state No default outline. Border color switches to --color-primary.
Autofill override :-webkit-autofill uses -webkit-box-shadow: 0 0 0 1000px var(--color-surface) inset to suppress the browser's autofill background color, plus -webkit-text-fill-color: var(--color-primary).
Submit button Filled: --color-primary background, --color-surface text. Hover: inverted (surface background, primary text). Disabled: 50% opacity.
Form messages Hidden by default. Success: --color-success background, --color-black text. Error: --color-error background, --color-black text. Black is used (not primary) because --color-primary in terminal is the same green as --color-success.
AI agent-ready Explicit <label for> associations, standard name attributes, no JS-only submission barrier: intentionally usable by web-browsing AI agents and MCP browser tools.

Chrome WebMCP Early Preview ↗: a standard for exposing structured tools to AI agents. Standard HTML form actions map to the declarative model.

Accessibility
Skip link Hidden by default (top: -40px), visible on focus (top: 6px). High contrast black/white.
ARIA labels Navigation: aria-label="Main navigation". Current page: aria-current="page". Mobile toggle: aria-expanded, aria-label toggling.
Semantic HTML <header role="banner">, <nav role="navigation">, <main role="main">, <footer role="contentinfo">
Hreflang CV pages include hreflang tags for de/en with x-default fallback to English
CSS Architecture
poole.min.css Base framework (Poole by @mdo)
poole.overrides.min.css Custom overrides: two-col layout, content tables, navigation, footer, responsive styles
project.css Project-specific components: column grids, figures, project cards and headers
animations.css Animation definitions
contact-form.css Contact page only: form fields, select arrow, autofill override, button states, success/error messages
themes.css All CSS custom properties, theme definitions (light, dark, vibrant, terminal), and variable application rules. Loaded from /_themes/ submodule.
Changelog
2026-02-23 Added .columns-4 grid variant (4 equal columns, collapses to 2 on mobile). Updated design system docs to document .columns-4 and note shared naming convention with teaching.stoll.studio. Added cross-site theme carry: links between sister sites now pass the current theme as a URL parameter. Added Design System link to teaching.stoll.studio footer.
2026-02-22 Token system refinements. Added --color-meta and --color-meta-secondary semantic tokens to all 4 theme sections (figcaptions, project meta headers, blockquote citations, subtitles, credits: cascade via Tertiary/Quaternary). Changed --color-divider to reference Border Strong instead of Border Secondary in all themes (unified cascade from :root). Removed hardcoded rgba overrides for --color-meta/--color-meta-secondary in vibrant and terminal theme blocks: now resolved via CSS cascade through base tokens. Updated Figma variables to match.
2026-02-21 Documentation audit against themes.css source of truth. Added missing tokens across all themes: --color-image-bg (#d5d5d5) to light theme; Accent 3, Border Strong, and full Status Colors tables to dark, vibrant, and terminal themes. Corrected all four themes' "Link Hover" rows: no per-theme hover color token exists; hover is a global opacity: 0.75 on a:hover/a:focus. Fixed terminal theme: all three accents unified to #00FF41 (was yellow/cyan); Surface Emphasized #0A0A0A→#111111, Surface Secondary #050505→#222222; text colors Secondary–Light corrected from hex to rgba opacity variants. Added Contact Form component section. Fixed form message text color: --color-surface--color-black. Updated CSS Architecture table.
2026-02-19 Renamed .project-list.content-table across both repos: it's the generic default table style, not project-specific
2026-02-13 Added Terminal theme with bright green on black aesthetic and IBM Plex Mono throughout. Renamed themes: "default" → "light", "teaching" → "vibrant"
2026-02-12 Mobile hamburger navigation with full-screen overlay, footer theme select dropdown for mobile, --color-divider semantic token for structural dividers
2026-02-11 Added theme switcher to footer, dark theme sticky bar fix, navigation active/hover states, content tables across all pages, CV language switcher, Projects in navigation
2026-02-07 Initial design system documentation, theming system with URL-based switching
System Musings Log
2026-02-22 Status tokens: their own tier, or not?
Status tokens (info, success, error, warning) are semantically meaningful: they describe intent, not raw values. That makes them feel like they belong in the semantic tier. But semantic tokens reference base tokens, and status colors don't have obvious base equivalents to reference. Promoting them to base tokens just to create a reference chain adds indirection without clarity. Keeping them as their own tier is a pragmatic compromise, but it breaks the clean base to semantic to component cascade logic. No resolution yet.