Understanding Hallmark's 2+1 Font Discipline: Why Three Fonts Is the Maximum

Hallmark enforces a strict 2+1 font discipline—two core type families plus one optional outlier—to maintain visual cohesion, reduce cognitive load, and keep CSS token systems predictable.

This typographic rule is a core design principle in the Nutlope/hallmark repository, governing how every generated page handles typography. By capping distinct font families at three, Hallmark eliminates "slop" and guarantees on-brand, audit-ready output.


What Is the 2+1 Font Discipline?

The 2+1 font discipline (also written as "2+I") structures every page's typography into three strict categories:

  • Display font – for headings, hero copy, and large-scale text
  • Body font – for paragraph prose and UI elements
  • Outlier font – a mono or specialty face for a single typographic moment

These three faces represent the absolute ceiling. Exceeding this limit triggers a failure in Hallmark's automated audit system, as documented in [slop-test.md](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/slop-test.md#L96).

According to [typography.md](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/typography.md#L13): "The 2+1 rule — three faces is the ceiling."


Why Three Fonts Is the Maximum

The three-font limit isn't arbitrary. It's driven by five interconnected design and architectural constraints.

Visual Cohesion

Limiting the type palette prevents chaotic mash-ups of unrelated styles. Every Hallmark page reads as a unified experience rather than a collection of competing visual voices.

Cognitive Load Reduction

Readers quickly learn the hierarchy: display → body → rare outlier. Multiple font switches create friction; three families establish predictable rhythm.

Token-Driven System Lock

Hallmark's CSS architecture relies on locked design tokens. The three fonts map directly to three variables:

:root {
  --font-display:  "Fraunces", ui-serif, Georgia, serif;
  --font-body:     "Geist",    ui-sans-serif, system-ui, sans;
  --font-outlier:  "Geist Mono", ui-monospace, monospace;
}

Source: [site/examples/press-01/tokens.css](https://github.com/Nutlope/hallmark/blob/main/site/examples/press-01/tokens.css#L42)

Adding a fourth family would require new tokens, breaking the strict "locked token" model described in [SKILL.md](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/SKILL.md#L78).

Outlier Restraint

The outlier exists for one typographic moment—a wordmark, hero statistic, or pull-quote. Using it twice defeats its purpose and signals discipline loss. The limit enforces intentional, rare deployment.

Weight vs. Family Distinction

Critical distinction: different weights within one family count as a single font. Geist 400 plus Geist 700 remains body family. Only a distinct family like Geist Mono increments the count. This prevents weight variation from inflating the total.


How the 2+1 Discipline Works in Practice

Display Font Usage

h1, .hero__display {
  font-family: var(--font-display);
  font-weight: 800;
}

Source: [site/examples/lumen-01/styles.css](https://github.com/Nutlope/hallmark/blob/main/site/examples/lumen-01/styles.css#L139)

Body Font Usage

p, .content {
  font-family: var(--font-body);
  line-height: 1.5;
}

Source: [site/examples/tally/styles.css](https://github.com/Nutlope/hallmark/blob/main/site/examples/tally/styles.css#L189)

Outlier Font Usage

.stat {
  font-family: var(--font-outlier);
  font-variant-numeric: tabular-nums;
}

The outlier appears sparingly—often just once per page for a highlighted number or code snippet.


Enforcement: The Slop Test Audit

Hallmark validates compliance through automated auditing. The logic, described in [slop-test.md](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/slop-test.md#L96):

if (countDistinctFamilies(page) > 3) {
  fail("Too many font families – maximum is three (display, body, optional outlier).");
}

Any page with four or more distinct font-family declarations fails the slop test—Hallmark's term for visual inconsistency that violates system discipline.


Summary

  • 2+1 structure: display + body + optional outlier
  • Three fonts maximum, enforced by automated audit
  • Weight variations don't count—only distinct families
  • Token-driven: --font-display, --font-body, --font-outlier
  • Outlier reserved for single typographic moments
  • Violations fail the slop-test.md audit

Frequently Asked Questions

What counts as a "font" in Hallmark's 2+1 discipline?

A font family counts as one—regardless of how many weights you use. Fraunces at 400 and Fraunces at 800 both belong to the display family. Only adding a completely different typeface like Geist Mono increments your total toward the three-font maximum.

Can I use the outlier font more than once on a page?

Technically possible, but it violates the discipline's intent. The outlier exists for a single typographic moment. Multiple appearances signal a need to restructure—likely promoting that content to display or body treatment instead.

What happens if I accidentally include a fourth font?

Hallmark's build process runs the slop test defined in [slop-test.md](https://github.com/Nutlope/hallmark/blob/main/skills/hallmark/references/slop-test.md#L96), which detects distinct font-family declarations. Exceeding three triggers an explicit failure with guidance to consolidate or reassign fonts to the existing token structure.

Why not allow more flexibility for complex designs?

The locked 2+1 font discipline prioritizes system predictability over edge-case flexibility. As implemented in Nutlope/hallmark, every generated page must pass automated audit without manual review—forcing constraints that guarantee on-brand, maintainable output at scale.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →