Add Grid, the twenty-first theme

Swiss neo-grotesque systems design: a near-white cool sheet with the
twelve-column hairline grid painted behind the content rather than implied,
one heavy Archivo run lowercase and slammed left, and exactly one signal red
used as a geometric mark. It fills the editorial cluster's neo-grotesque slot,
which until now was serif-led on every one of its members.

Skill side: the theme spec, and the catalog count from twenty to twenty-one in
the four places SKILL.md states it.

Site side: the token block, the switcher entry, the twenty-first dropdown dot,
Archivo added to the font load, the Buro Grid example page with its thumbnail,
and an entry in the theme contact sheet.

Not added to scroll-demos.json on purpose. Grid's motion is near-zero by
design, no reveals and no parallax, so a scroll recording would be an empty
file advertising something the theme refuses to do.

README carries the new count only, no new section.
This commit is contained in:
Youssef
2026-08-06 16:32:20 +01:00
parent 0a0f706bc0
commit f5f4a2ceb0
9 changed files with 695 additions and 18 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
**A design skill for Claude Code, Cursor, and Codex that refuses to look AI-generated.**
[Live demo →](https://www.usehallmark.com)  ·  twenty themes  ·  four verbs  ·  press `T` to cycle.
[Live demo →](https://www.usehallmark.com)  ·  twenty-one themes  ·  four verbs  ·  press `T` to cycle.
Made by Together AI.
@@ -10,7 +10,7 @@ Made by Together AI.
<img src="site/OG-hallmark.png" alt="Hallmark, a design skill that refuses to look AI-generated" />
</p>
Hallmark picks a macrostructure for the brief, dresses it in one of twenty themes, runs fifty-seven slop-test gates plus a pre-emit self-critique, and refuses the on-distribution defaults every LLM was trained into. Two pages by Hallmark for two different briefs feel like different sites, not colour-swaps of the same template.
Hallmark picks a macrostructure for the brief, dresses it in one of twenty-one themes, runs fifty-seven slop-test gates plus a pre-emit self-critique, and refuses the on-distribution defaults every LLM was trained into. Two pages by Hallmark for two different briefs feel like different sites, not colour-swaps of the same template.
---
Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

+5 -4
View File
@@ -1,12 +1,12 @@
<!doctype html>
<!-- Internal review sheet: all 20 themes as live, scaled previews of the landing
<!-- Internal review sheet: all 21 themes as live, scaled previews of the landing
(../index.html?theme=KEY). Click any card to open it full. Not linked from
the public site. -->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hallmark — all 20 themes</title>
<title>Hallmark — all 21 themes</title>
<style>
:root {
--thumb-w: 460px;
@@ -78,7 +78,7 @@
</head>
<body>
<header class="top">
<h1>Hallmark — all <b>20</b> themes</h1>
<h1>Hallmark — all <b>21</b> themes</h1>
<p class="sub">Live previews of the landing in each theme. Click any card to open it full in a new tab. Tags are my recommendation, not a decision — yours to make.</p>
<div class="legend">
<span><i class="dot dot--keep"></i> Keep — distinctive</span>
@@ -110,7 +110,8 @@
{ k:"carnival", n:"Carnival", v:"Keep", t:"keep" },
{ k:"cobalt", n:"Cobalt", v:"New", t:"keep" },
{ k:"lumen", n:"Lumen", v:"Keep", t:"keep" },
{ k:"hum", n:"Hum", v:"Default", t:"keep" }
{ k:"hum", n:"Hum", v:"Default", t:"keep" },
{ k:"grid", n:"Grid", v:"New", t:"keep" }
];
var grid = document.getElementById("grid");
THEMES.forEach(function (th, i) {
+44
View File
@@ -1172,3 +1172,47 @@
--dur-short: 220ms;
--dur-long: 420ms;
}
/* ──────────────────────────────────────────────────────────────
/* ──────────────────────────────────────────────────────────────
GRID - Swiss International, the grid made visible (editorial cluster)
Near-white sheet, one signal red, exposed 12-column hairlines, heavy
neo-grotesque. Neutrals carry a whisper of cool chroma so no grey is
flat. Axes: light / grotesk-heavy / warm-red near-mono.
────────────────────────────────────────────────────────────── */
[data-theme="grid"] {
--color-paper: oklch(99% 0.003 255); /* near-white sheet, faint cool, never #fff */
--color-paper-2: oklch(97.2% 0.003 255);
--color-paper-3: oklch(94.5% 0.004 255);
--color-rule: oklch(88% 0.004 255); /* the exposed grid hairline */
--color-rule-2: oklch(72% 0.005 255);
--color-muted: oklch(48% 0.006 255);
--color-neutral: oklch(34% 0.006 255);
--color-ink-2: oklch(26% 0.008 255);
--color-ink: oklch(16% 0.010 255); /* cool near-black */
--color-accent: oklch(55% 0.21 28); /* the one signal red */
--color-accent-ink: oklch(99% 0.003 255);
--color-focus: oklch(55% 0.21 28);
--font-display: "Archivo", "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
--font-body: "Archivo", "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
--font-serif: ui-serif, Georgia, serif;
--font-label: "Archivo", ui-sans-serif, sans-serif;
--font-mono: "Spline Sans Mono", "Geist Mono", ui-monospace, monospace;
--display-weight: 800;
--display-style: normal;
--text-display: clamp(2.75rem, 7vw + 0.5rem, 6rem);
--text-display-s: clamp(2rem, 3.5vw + 0.5rem, 3.25rem);
--tracking-display: -0.045em;
--tracking-tight: -0.02em;
--tracking-label: 0.04em;
--section-gap: 6rem;
--section-head-gap: 1.5rem;
--radius-card: 0; --radius-pill: 0; --radius-input: 0;
--rule-card: 1px; --shadow-card: none;
}
+467
View File
@@ -0,0 +1,467 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Büro Grid · Identity and signage systems</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<style>
/* Hallmark · macrostructure: Manifesto · theme: Grid (candidate) · tone: rational/Swiss */
:root {
/* palette - every value oklch, referenced by var() only */
--paper: oklch(99.4% 0.003 255);
--ink: oklch(15% 0.01 255);
--red: oklch(55% 0.21 28);
--grid-line: oklch(93% 0.004 255);
--hair: oklch(87% 0.004 255);
--muted: oklch(45% 0.006 255);
--tint: oklch(97.2% 0.003 255);
--on-ink: oklch(99.4% 0.003 255);
/* type */
--font-display: "Archivo", sans-serif;
--font-body: "Archivo", sans-serif;
/* 4pt spacing scale */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 48px;
--space-8: 64px;
--space-9: 96px;
--space-10: 128px;
/* layout */
--page: 1280px;
--gutter: clamp(16px, 4vw, 56px);
--measure: 64ch;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { overflow-x: clip; scroll-behavior: smooth; }
body {
overflow-x: clip;
background: var(--paper);
color: var(--ink);
font-family: var(--font-body);
font-size: 16px;
line-height: 1.5;
padding-inline: var(--gutter);
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
a { color: inherit; text-decoration: none; transition: color 0.18s ease; }
:where(a):focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
a:active { opacity: 0.7; }
::selection { background: var(--red); color: var(--on-ink); }
.skip {
position: absolute; left: var(--space-4); top: -56px; z-index: 30;
background: var(--ink); color: var(--on-ink);
padding: var(--space-2) var(--space-4);
font-size: 13px; font-weight: 600;
}
.skip:focus-visible { top: var(--space-4); outline: 2px solid var(--red); outline-offset: 3px; }
/* ---- structural skeleton: the exposed 12-column hairline grid ---- */
.page { position: relative; }
.rails { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.rails__inner {
height: 100%;
max-width: var(--page);
margin-inline: auto;
background-image: repeating-linear-gradient(
to right,
var(--grid-line) 0,
var(--grid-line) 1px,
transparent 1px,
transparent calc(100% / 12)
);
}
.shell { position: relative; z-index: 1; max-width: var(--page); margin-inline: auto; }
.grid {
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
gap: 0;
}
/* Section mark - a short red bar on the section's own hairline. It is the only
thing that opens a section here, all the way down the page. No words. */
.sec-head { padding-block: var(--space-6) var(--space-6); }
.sec-head__rule { height: 3px; width: var(--space-9); background: var(--red); border: 0; margin: 0; }
.sec-head__rule + .sec-head__title { margin-top: var(--space-4); }
.sec-head__title {
font-family: var(--font-display); font-weight: 800;
font-size: clamp(28px, 3.6vw, 46px); letter-spacing: -0.025em;
line-height: 1.02; margin-top: var(--space-3);
overflow-wrap: anywhere; min-width: 0;
}
/* ---- top nav: a band of cells divided by hairlines ---- */
.topbar {
position: sticky; top: 0; z-index: 5;
background: var(--paper);
border-block: 1px solid var(--ink);
}
.topbar__cell {
grid-column: span 2;
display: flex; align-items: center;
padding: var(--space-4) var(--space-4);
border-inline-start: 1px solid var(--hair);
font-size: 13px; font-weight: 500; letter-spacing: 0.04em;
text-transform: uppercase; line-height: 1.1;
min-width: 0;
}
.topbar__cell:first-child { border-inline-start: 0; }
.topbar__mark {
grid-column: span 4;
font-weight: 800; font-size: 15px; letter-spacing: -0.01em;
text-transform: none;
}
.topbar__link:hover { text-decoration: underline; text-underline-offset: 4px; }
.topbar__lang { justify-content: flex-end; gap: var(--space-2); }
.topbar__lang a[aria-current="true"] { color: var(--ink); }
.topbar__lang a:not([aria-current="true"]) { color: var(--muted); }
.topbar__lang a:hover { color: var(--ink); }
.topbar__slash { color: var(--hair); }
/* ---- hero ---- */
.hero { padding-block: var(--space-8) clamp(64px, 12vw, 152px); }
.hero__title {
font-family: var(--font-display); font-weight: 800;
font-size: clamp(52px, 10.5vw, 136px);
letter-spacing: -0.045em; line-height: 0.9;
text-transform: lowercase;
margin-block: var(--space-5) var(--space-7);
overflow-wrap: anywhere; min-width: 0;
}
.hero__period {
display: inline-block;
width: 0.52em; height: 0.52em;
margin-left: 0.08em;
background: var(--red);
vertical-align: baseline;
}
.hero__foot {
display: grid;
grid-template-columns: minmax(0, var(--measure)) minmax(0, 1fr);
gap: var(--space-6);
align-items: end;
border-top: 2px solid var(--ink);
padding-top: var(--space-5);
}
.hero__lead { max-width: var(--measure); font-size: 17px; color: var(--ink); }
.hero__note {
font-size: 13px; color: var(--muted);
text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.5;
justify-self: end; text-align: right;
}
/* ---- method band: practice / method / standort ---- */
.band { padding-block: clamp(48px, 8vw, 112px); border-top: 1px solid var(--ink); }
/* a real ordered list: counter() draws A / B / C, nothing is typed */
.band__cols { margin-top: var(--space-4); list-style: none; margin-inline: 0; padding: 0; counter-reset: band; }
.band__col {
counter-increment: band;
grid-column: span 4;
padding-inline-end: var(--space-6);
padding-top: var(--space-4);
border-top: 1px solid var(--hair);
min-width: 0;
}
.band__col:first-child { border-top-color: var(--ink); }
.band__col::before {
content: counter(band, upper-alpha);
display: block;
font-family: var(--font-display); font-weight: 800; font-size: 14px;
color: var(--muted); letter-spacing: 0;
}
.band__col h3 {
font-family: var(--font-display); font-weight: 800;
font-size: 20px; letter-spacing: -0.01em; line-height: 1.1;
margin-block: var(--space-3) var(--space-3);
overflow-wrap: anywhere; min-width: 0;
}
.band__col p { font-size: 15px; color: var(--ink); max-width: 46ch; }
/* ---- work index: numbered full-width rows ---- */
.work { padding-block: clamp(48px, 8vw, 112px); border-top: 1px solid var(--ink); }
.work__list { margin-top: var(--space-5); border-top: 2px solid var(--ink); list-style: none; }
.work__list > li { list-style: none; }
.row {
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
gap: 0; align-items: baseline;
padding-block: var(--space-5);
border-bottom: 1px solid var(--hair);
transition: background-color 0.2s ease;
}
.row:hover { background: var(--tint); }
.row:active { opacity: 0.82; }
.row:focus-visible { outline: 2px solid var(--red); outline-offset: -2px; }
.row__no {
grid-column: span 1;
font-family: var(--font-display); font-weight: 800; font-size: 15px;
color: var(--muted); padding-inline-start: var(--space-1);
}
.row__title {
grid-column: span 7;
font-family: var(--font-display); font-weight: 700;
font-size: clamp(19px, 2.4vw, 27px); letter-spacing: -0.02em;
line-height: 1.08; min-width: 0; overflow-wrap: anywhere;
transition: transform 0.2s ease;
}
.row:hover .row__title { transform: translateX(var(--space-2)); }
.row__meta {
grid-column: span 3;
font-size: 13px; color: var(--muted);
text-transform: uppercase; letter-spacing: 0.05em; line-height: 1.5;
min-width: 0;
}
.row__mark { grid-column: span 1; justify-self: end; align-self: center; }
.row__mark span {
display: block; width: 12px; height: 12px; background: var(--red);
}
/* ---- manifesto ---- */
.manifesto { padding-block: clamp(64px, 11vw, 152px); border-top: 1px solid var(--ink); }
.manifesto__body { margin-top: var(--space-6); }
.manifesto__line {
grid-column: 1 / span 10;
font-family: var(--font-display); font-weight: 500;
font-size: clamp(27px, 4.6vw, 54px);
letter-spacing: -0.02em; line-height: 1.1;
overflow-wrap: anywhere; min-width: 0;
}
.manifesto__dot { color: var(--red); }
/* ---- contact ---- */
.contact { padding-block: clamp(48px, 8vw, 112px); border-top: 1px solid var(--ink); }
.contact__body { margin-top: var(--space-6); }
.contact__main { grid-column: 1 / span 7; min-width: 0; }
.contact__mail {
display: inline-block;
font-family: var(--font-display); font-weight: 800;
font-size: clamp(24px, 4vw, 44px); letter-spacing: -0.025em;
line-height: 1.05; overflow-wrap: anywhere;
border-bottom: 2px solid var(--hair); padding-bottom: var(--space-2);
transition: border-color 0.18s ease, color 0.18s ease;
}
.contact__mail:hover { border-bottom-color: var(--red); }
.contact__meta { grid-column: 9 / span 4; align-self: end; min-width: 0; }
.contact__meta p { font-size: 14px; color: var(--muted); line-height: 1.6; }
.contact__meta p + p { margin-top: var(--space-4); }
/* ---- footer: another band of equal cells ---- */
.foot { border-top: 1px solid var(--ink); padding-block: var(--space-7) var(--space-8); }
.foot__cell {
grid-column: span 3;
padding-inline: var(--space-4);
border-inline-start: 1px solid var(--hair);
font-size: 13px; color: var(--muted); line-height: 1.6;
min-width: 0; overflow-wrap: anywhere;
}
.foot__cell:first-child { border-inline-start: 0; padding-inline-start: 0; }
.foot__mark {
font-family: var(--font-display); font-weight: 800; font-size: 15px;
color: var(--ink); letter-spacing: -0.01em; margin-bottom: var(--space-2);
}
.foot__cell a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
/* ---- responsive ---- */
@media (max-width: 860px) {
.hero__foot { grid-template-columns: 1fr; gap: var(--space-5); }
.hero__note { justify-self: start; text-align: left; }
.band__col { grid-column: span 6; }
.band__col:nth-child(2) { border-top-color: var(--ink); }
.contact__main { grid-column: 1 / -1; }
.contact__meta { grid-column: 1 / -1; margin-top: var(--space-6); align-self: start; }
.manifesto__line { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
.topbar__cell { grid-column: span 6; padding-block: var(--space-3); }
.topbar__mark { grid-column: 1 / -1; border-bottom: 1px solid var(--hair); }
.topbar__cell:nth-child(2), .topbar__cell:nth-child(4) { border-inline-start: 0; }
.band__col { grid-column: 1 / -1; }
.band__col { border-top-color: var(--hair); }
.band__col:first-child { border-top-color: var(--ink); }
.row { grid-template-columns: auto minmax(0, 1fr); row-gap: var(--space-2); }
.row__no { grid-column: 1; }
.row__title { grid-column: 2; }
.row__meta { grid-column: 2; }
.row__mark { grid-column: 2; justify-self: start; }
.foot__cell { grid-column: span 6; margin-top: var(--space-5); }
.foot__cell:nth-child(-n+2) { margin-top: 0; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}
</style>
</head>
<body>
<div class="page" id="top">
<div class="rails" aria-hidden="true"><div class="rails__inner"></div></div>
<a class="skip" href="#main">Skip to content</a>
<div class="shell">
<header class="topbar grid">
<a class="topbar__cell topbar__mark" href="#top">Büro Grid</a>
<a class="topbar__cell topbar__link" href="#work">Work</a>
<a class="topbar__cell topbar__link" href="#method">Method</a>
<a class="topbar__cell topbar__link" href="#contact">Contact</a>
<div class="topbar__cell topbar__lang">
<a href="#top" aria-current="true">DE</a>
<span class="topbar__slash" aria-hidden="true">/</span>
<a href="#top">EN</a>
</div>
</header>
<main id="main">
<section class="hero" aria-labelledby="hero-title">
<h1 class="hero__title" id="hero-title">schedule,<br />then ship<span class="hero__period" aria-hidden="true"></span></h1>
<div class="hero__foot">
<p class="hero__lead">Büro Grid builds identity, wayfinding, and editorial systems for institutions that plan in decades. We draw the grid first, so every decision after it has somewhere to stand.</p>
<p class="hero__note">Basel, since 2009<br />Working in DE / EN</p>
</div>
</section>
<section class="band" id="method" aria-labelledby="method-title">
<div class="sec-head">
<hr class="sec-head__rule" />
<h2 class="sec-head__title" id="method-title">Structure before surface</h2>
</div>
<ol class="band__cols grid">
<li class="band__col">
<h3>Practice</h3>
<p>Identity systems, signage programmes, and editorial grids. Each project begins as a set of rules, never as a single picture.</p>
</li>
<li class="band__col">
<h3>Method</h3>
<p>Fixed modules, one measure, a single accent. The system has to survive twenty years of new hands, new content, and new signage.</p>
</li>
<li class="band__col">
<h3>Standort</h3>
<p>Based in Basel, working across the institutional landscape in German and English. On site whenever the building itself needs us.</p>
</li>
</ol>
</section>
<section class="work" id="work" aria-labelledby="work-title">
<div class="sec-head">
<hr class="sec-head__rule" />
<h2 class="sec-head__title" id="work-title">Index of selected work</h2>
</div>
<ol class="work__list">
<li>
<a class="row" href="#contact">
<span class="row__no">01</span>
<span class="row__title">Kunsthalle Basel</span>
<span class="row__meta">Wayfinding system · 2024</span>
<span class="row__mark" aria-hidden="true"><span></span></span>
</a>
</li>
<li>
<a class="row" href="#contact">
<span class="row__no">02</span>
<span class="row__title">Rheinhafen Authority</span>
<span class="row__meta">Identity &amp; signage · 2023</span>
<span class="row__mark" aria-hidden="true"></span>
</a>
</li>
<li>
<a class="row" href="#contact">
<span class="row__no">03</span>
<span class="row__title">Universität Basel Press</span>
<span class="row__meta">Editorial grid · 2023</span>
<span class="row__mark" aria-hidden="true"></span>
</a>
</li>
<li>
<a class="row" href="#contact">
<span class="row__no">04</span>
<span class="row__title">Kantonsbibliothek</span>
<span class="row__meta">Identity system · 2022</span>
<span class="row__mark" aria-hidden="true"></span>
</a>
</li>
<li>
<a class="row" href="#contact">
<span class="row__no">05</span>
<span class="row__title">Tramnetz Nord</span>
<span class="row__meta">Platform signage · 2021</span>
<span class="row__mark" aria-hidden="true"></span>
</a>
</li>
<li>
<a class="row" href="#contact">
<span class="row__no">06</span>
<span class="row__title">Museum für Gestaltung</span>
<span class="row__meta">Type &amp; grid manual · 2020</span>
<span class="row__mark" aria-hidden="true"></span>
</a>
</li>
</ol>
</section>
<section class="manifesto" aria-labelledby="pos-title">
<div class="sec-head">
<hr class="sec-head__rule" />
<h2 class="sec-head__title" id="pos-title">Position</h2>
</div>
<div class="manifesto__body grid">
<p class="manifesto__line">A grid is not decoration. It is a decision made once, in public, so that every decision after it can be smaller, calmer, and easier to defend<span class="manifesto__dot">.</span></p>
</div>
</section>
<section class="contact" id="contact" aria-labelledby="contact-title">
<div class="sec-head">
<hr class="sec-head__rule" />
<h2 class="sec-head__title" id="contact-title">Start something that outlasts its brief</h2>
</div>
<div class="contact__body grid">
<div class="contact__main">
<a class="contact__mail" href="mailto:studio@burogrid.example">studio@burogrid.example</a>
</div>
<div class="contact__meta">
<p>Steinenvorstadt 12<br />4051 Basel, Switzerland</p>
<p>New commissions for 2026 open from September.</p>
</div>
</div>
</section>
</main>
<footer class="foot grid">
<div class="foot__cell">
<p class="foot__mark">Büro Grid</p>
<p>Identity systems and signage, Basel.</p>
</div>
<div class="foot__cell">
<p><a href="mailto:studio@burogrid.example">studio@burogrid.example</a></p>
<p>+41 61 000 00 00</p>
</div>
<div class="foot__cell">
<p>Steinenvorstadt 12<br />4051 Basel</p>
</div>
<div class="foot__cell">
<p>DE / EN</p>
<p>© 2026 Büro Grid</p>
</div>
</footer>
</div>
</div>
</body>
</html>
+12 -2
View File
@@ -50,11 +50,11 @@
}
</style>
<!-- Google Fonts — Anton, Albert Sans, Fraunces, Geist, Geist Mono, Hanken Grotesk, Inter, Inter Tight, Newsreader, Playfair Display, Public Sans. -->
<!-- Google Fonts — Anton, Albert Sans, Archivo, Fraunces, Geist, Geist Mono, Hanken Grotesk, Inter, Inter Tight, Newsreader, Playfair Display, Public Sans. -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700;800&family=Anton&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;0,9..144,600;0,9..144,900;1,9..144,400;1,9..144,500&family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&family=Hanken+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Inter+Tight:ital,wght@0,500;0,600;0,700;0,800;1,500;1,600;1,700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400;1,6..72,500&family=Playfair+Display:ital,wght@1,400;1,500;1,600&family=Public+Sans:wght@400;500;600;700&family=Young+Serif&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" />
href="https://fonts.googleapis.com/css2?family=Albert+Sans:wght@400;500;600;700;800&family=Anton&family=Archivo:wght@400;500;600;700;800&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,500;0,9..144,600;0,9..144,900;1,9..144,400;1,9..144,500&family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&family=Hanken+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Inter+Tight:ital,wght@0,500;0,600;0,700;0,800;1,500;1,600;1,700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400;1,6..72,500&family=Playfair+Display:ital,wght@1,400;1,500;1,600&family=Public+Sans:wght@400;500;600;700&family=Young+Serif&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" />
<link rel="stylesheet" href="css/tokens.css?v=24" />
<link rel="stylesheet" href="css/base.css?v=24" />
@@ -193,6 +193,9 @@
<button class="theme-dropdown__dot" type="button" data-theme-btn="cobalt" aria-label="20 · Cobalt"
style="--dot: oklch(98.5% 0.004 250); --dot-edge: oklch(58% 0.20 256); --num: oklch(30% 0.05 256);"><span
class="theme-dropdown__num">20</span></button>
<button class="theme-dropdown__dot" type="button" data-theme-btn="grid" aria-label="21 · Grid"
style="--dot: oklch(99% 0.003 255); --dot-edge: oklch(55% 0.21 28); --num: oklch(30% 0.06 28);"><span
class="theme-dropdown__num">21</span></button>
</div>
</div>
@@ -338,6 +341,13 @@
<p class="ex-card__prompt"><span class="ex-card__prompt-mark">$</span> /hallmark build an AI reasoning tool, Lumen</p>
</a>
<a class="ex-card" style="--scroll-dur:3.3s" role="listitem" href="examples/grid-01/" target="_blank" rel="noopener" aria-label="Open the Buro Grid example, a Swiss identity and signage studio built in the Grid theme">
<div class="ex-card__thumb" aria-hidden="true">
<img src="_tests/_thumbs/grid-01.jpg?v=24" alt="" loading="lazy" width="1600" height="1000" />
</div>
<p class="ex-card__prompt"><span class="ex-card__prompt-mark">$</span> /hallmark build a signage studio site, Grid</p>
</a>
</div>
</section>
+28 -5
View File
@@ -60,6 +60,7 @@ const THEMES = {
carnival: "Carnival",
lumen: "Lumen",
cobalt: "Cobalt",
grid: "Grid",
};
const STORAGE_KEY = "hallmark-theme";
@@ -88,6 +89,7 @@ const ARCHETYPES = {
lumen: { hero: "marquee", footer: "colophon" },
hum: { hero: "hum", footer: "colophon" },
cobalt: { hero: "cobalt", footer: "colophon" },
grid: { hero: "marquee", footer: "colophon" },
};
/* — Theme → genre map ——————————————————————————————————
@@ -125,7 +127,7 @@ const THEME_GENRES = {
/* — Locked hero title —————————————————————————————————
The H1 string is the same across every theme. Only the visual
treatment swaps — italic vs roman, serif vs sans, all-caps vs not.
The page is the demo: one sentence, twenty distinct designs. */
The page is the demo: one sentence, twenty-one distinct designs. */
const HERO_TITLE = "A design skill that refuses to look AI-generated.";
/* — Per-theme copy fixtures —————————————————————————————
@@ -228,7 +230,7 @@ const COPY = {
quote: "An almanac is a book that knows where to look.",
attrib: "Almanac, frontispiece",
salutation: "Reference note,",
letterBody: "This page is a reference, not an argument. The numbers are the point: 21 macrostructures, 50 archetypes, 20 themes, 57 slop-test gates. Cross-referenced so the next page Hallmark builds is genuinely different from the last.",
letterBody: "This page is a reference, not an argument. The numbers are the point: 21 macrostructures, 50 archetypes, 21 themes, 57 slop-test gates. Cross-referenced so the next page Hallmark builds is genuinely different from the last.",
signoff: "— editor",
captionA: "Vol. III",
captionB: "Plate 12",
@@ -460,7 +462,7 @@ const COPY = {
carnival: {
eyebrow: "NO TEMPLATES · NO DEFAULTS",
title: HERO_TITLE,
lede: "20 themes that refuse to blend in. Pick one and the whole page changes — the bones, not the paint.",
lede: "21 themes that refuse to blend in. Pick one and the whole page changes — the bones, not the paint.",
ctaLabel: "Install",
proofLabel: "ON THE BILL",
proofA: "21 page-shapes, 50 archetypes",
@@ -472,7 +474,7 @@ const COPY = {
quote: "A PAGE THAT HEDGES IS A PAGE THAT FAILS.",
attrib: "CARNIVAL",
salutation: "WE PRINT POSTERS, NOT TEMPLATES.",
letterBody: "Every model was trained on the same page. Carnival refuses it — loud type, duo-tone ink, ornaments that mean it. 20 themes in the catalog, and not one of them whispers.",
letterBody: "Every model was trained on the same page. Carnival refuses it — loud type, duo-tone ink, ornaments that mean it. 21 themes in the catalog, and not one of them whispers.",
signoff: "— CARNIVAL",
captionA: "BILL 01",
captionB: "OUT NOW",
@@ -492,7 +494,7 @@ const COPY = {
quote: "two briefs, two pages — not one template, recoloured.",
attrib: "lumen",
salutation: "built to refuse the default.",
letterBody: "every model emits the same page. lumen is the part that refuses — lowercase classical serif, one accent verb, a hand-built apparatus where the orb used to be. twenty themes in the catalog, and the numbers hold under load.",
letterBody: "every model emits the same page. lumen is the part that refuses — lowercase classical serif, one accent verb, a hand-built apparatus where the orb used to be. twenty-one themes in the catalog, and the numbers hold under load.",
signoff: "— lumen",
captionA: "00 · spec",
captionB: "night foundry",
@@ -538,6 +540,27 @@ const COPY = {
captionA: "Cobalt",
captionB: "v1.1",
},
grid: {
eyebrow: "SWISS INTERNATIONAL",
title: HERO_TITLE,
lede: "The grid, made visible. A near-white sheet, exposed twelve-column hairlines, one signal red, and a heavy neo-grotesque set flush-left. Rational, exact, built for institutions that plan in decades.",
ctaLabel: "Method",
proofLabel: "System",
proofA: "Exposed 12-column hairline grid",
proofB: "Archivo 800 · flush-left · tight tracking",
proofC: "One red element per viewport",
cta: "Read the method",
stat: "12",
qualifier: "columns, exposed.",
quote: "Structure before surface. One grid, two weights, one red.",
attrib: "Grid note",
salutation: "Schedule, then ship.",
letterBody: "Swiss International, executed straight: the grid is not scaffolding you hide, it is the design. Content snaps to twelve columns, asymmetric spans make the rhythm, and a single red mark does all the emotional work.",
signoff: "Flush left,",
captionA: "Grid",
captionB: "Twelve columns",
},
};
/* — Slot population ———————————————————————————————————— */
+5 -5
View File
@@ -35,7 +35,7 @@ If the user types anything that does not clearly map to `audit`, `redesign`, or
- Treat PDFs, README files, `.md` briefs, docs, transcripts, and pitch decks as reference material. Do **not** copy them word-for-word into the page unless the user explicitly says to use that text verbatim.
- Before editing, state the exact files you expect to modify/create/delete. Deletions require explicit confirmation.
The default Design flow always picks a theme. By default it picks one of the **20 named themes** — the *catalog* — and rotates among them per the diversification rule. There is also a quiet *custom* branch that constructs a one-off OKLCH palette + free-font pairing for the brief; the custom route fires **only when the brief carries a creative-intent signal** (the user names a brand colour, names a multi-attribute vibe the catalog can't carry, or explicitly asks for a custom theme). For vanilla briefs, the user never sees the words "catalog" or "custom" — the catalog runs silently. See Step 1 (signal detection) and Step 2.6 (dispatch); the protocol lives in [`references/custom-theme.md`](references/custom-theme.md).
The default Design flow always picks a theme. By default it picks one of the **21 named themes** — the *catalog* — and rotates among them per the diversification rule. There is also a quiet *custom* branch that constructs a one-off OKLCH palette + free-font pairing for the brief; the custom route fires **only when the brief carries a creative-intent signal** (the user names a brand colour, names a multi-attribute vibe the catalog can't carry, or explicitly asks for a custom theme). For vanilla briefs, the user never sees the words "catalog" or "custom" — the catalog runs silently. See Step 1 (signal detection) and Step 2.6 (dispatch); the protocol lives in [`references/custom-theme.md`](references/custom-theme.md).
---
@@ -237,7 +237,7 @@ If two non-default signals fire (rare), ask one short follow-up: *"This brief fi
State the genre out loud at Step 2.5 alongside the macrostructure and theme picks: *"Genre: atmospheric. Macrostructure: Marquee Hero. Theme: Bloom (atmospheric cluster)."*
**Theme route — only surface when the brief signals it.** Hallmark has two theme routes: **catalog** (the 20 named themes — Specimen, Atelier, Brutal, Newsprint, Studio, Manifesto, Terminal, Midnight, Almanac, Garden, Riso, Sport, Bloom, Coral, Cobalt, Aurora, Editorial, Carnival, Lumen, Hum) and **custom** (made-to-measure for one brief — a *tuned* OKLCH palette + free-font pairing on Hallmark's structures, or, when the brief's structure itself is the ask, a fully *bespoke* page designed from first principles; bound by every slop-test gate either way; see [`references/custom-theme.md`](references/custom-theme.md)). **Catalog is the default.** The catalog rotation is *scoped to the genre's theme cluster* — atmospheric rotates Bloom/Midnight/Terminal/Aurora/Lumen, modern-minimal rotates Coral/Cobalt, playful stays on Hum, editorial walks the remaining twelve (Specimen, Atelier, Brutal, Newsprint, Studio, Manifesto, Almanac, Garden, Riso, Sport, Editorial, Carnival). Do **not** offer the user a choice on every prompt — that's friction, not discipline. Surface the catalog/custom fork only when the brief carries one of these signals:
**Theme route — only surface when the brief signals it.** Hallmark has two theme routes: **catalog** (the 21 named themes — Specimen, Atelier, Brutal, Newsprint, Studio, Manifesto, Terminal, Midnight, Almanac, Garden, Riso, Sport, Bloom, Coral, Cobalt, Aurora, Editorial, Carnival, Lumen, Hum, Grid) and **custom** (made-to-measure for one brief — a *tuned* OKLCH palette + free-font pairing on Hallmark's structures, or, when the brief's structure itself is the ask, a fully *bespoke* page designed from first principles; bound by every slop-test gate either way; see [`references/custom-theme.md`](references/custom-theme.md)). **Catalog is the default.** The catalog rotation is *scoped to the genre's theme cluster* — atmospheric rotates Bloom/Midnight/Terminal/Aurora/Lumen, modern-minimal rotates Coral/Cobalt, playful stays on Hum, editorial walks the remaining thirteen (Specimen, Atelier, Brutal, Newsprint, Studio, Manifesto, Almanac, Garden, Riso, Sport, Editorial, Carnival, Grid). Do **not** offer the user a choice on every prompt — that's friction, not discipline. Surface the catalog/custom fork only when the brief carries one of these signals:
- The user explicitly says **custom theme** / **tailored to our brand** / **make it ours** / **something unique** / **play with the colors and fonts**.
- The user names a **specific brand colour** as the anchor (e.g., "use our terracotta", "the brand red is hex #c0392b", "anchor on sea-blue").
@@ -248,7 +248,7 @@ If any of those fires, ask one short follow-up before picking: *"This brief read
**Custom has two depths** — *tuned* (a palette + fonts on Hallmark's structures) and *bespoke* (a page designed from first principles, own structure too) for when the brief's **structure itself** is the ask: "no theme / from scratch / fully bespoke", or a page-shape no catalog macrostructure fits. Both fire the one fork above, default to catalog on silence, and **pass every slop-test gate** — the depth simply follows the brief. See [`references/custom-theme.md`](references/custom-theme.md) § Bespoke depth.
If none of the signals fires, **proceed with catalog silently. Do not mention the fork.** Most briefs don't need a custom theme — the catalog's 20 themes plus the rotation rule already deliver structural variety. See Step 2.6 for the dispatch.
If none of the signals fires, **proceed with catalog silently. Do not mention the fork.** Most briefs don't need a custom theme — the catalog's 21 themes plus the rotation rule already deliver structural variety. See Step 2.6 for the dispatch.
**If the user opts out or skips fields** (says "go ahead", "you pick", "skip", "just build it", "don't ask", answers some fields and leaves others blank, or simply doesn't engage with the question after one prompt):
@@ -336,10 +336,10 @@ By the time you reach this step, one of four things is true:
0. **A `study` diagnosis was emitted earlier in this conversation and the user is asking to build from it** (phrases: *"build it"*, *"make it"*, *"use this DNA"*, *"build with this"* — immediately following the diagnosis) → theme route is **studied-DNA**. **Skip catalog/custom dispatch entirely.** The studied paper OKLCH, accent OKLCH, type roles (with named candidates), macrostructure, and nav/footer archetypes from the diagnosis become the locked system for this build. Diversification is suspended — you're following an external DNA, not rotating the catalog. The Step 6 stamp records `theme: studied-DNA (source: <URL or image>)` plus the actual OKLCH/font values inline. **If the user later pivots with phrases like *"use Newsprint instead"* / *"ignore the DNA"* / *"rotate to a different theme"*,** route back to the normal dispatch below and resume diversification. Continue to Step 3.
1. **The user named custom** (because they said so, or because Step 1's signal detection fired and they confirmed) → load [`references/custom-theme.md`](references/custom-theme.md). For a **tuned** custom: ask the **one** follow-up (vibe in 48 words + optional anchor colour), construct the OKLCH palette + free-font pairing, compute the three axis values (paper-band / display-style / accent-hue). If the brief's **structure itself** is the ask (signal 5 — "from scratch / no theme", or a page-shape no catalog macrostructure fits), take the **bespoke** depth instead: design the palette, type, **and** structure from first principles (custom-theme.md § Bespoke depth). **Every slop-test gate still fires either way.** Then continue to Step 3.
2. **The user named catalog** (or implicitly accepted it by not naming custom) → pick one of the 20 named themes per the diversification rule above. Existing flow — continue to Step 3.
2. **The user named catalog** (or implicitly accepted it by not naming custom) → pick one of the 21 named themes per the diversification rule above. Existing flow — continue to Step 3.
3. **Neither was discussed** (Step 1's signals didn't fire — vanilla brief) → default to **catalog**. Do not pause. Do not ask. Continue to Step 3.
**Custom is a quiet branch, not a default question.** Most briefs route to catalog and the user never sees the words "catalog" or "custom." The 20 named themes plus the rotation rule already deliver structural variety; the fork is reserved for when the brief specifically asks for a tuned look the catalog can't carry.
**Custom is a quiet branch, not a default question.** Most briefs route to catalog and the user never sees the words "catalog" or "custom." The 21 named themes plus the rotation rule already deliver structural variety; the fork is reserved for when the brief specifically asks for a tuned look the catalog can't carry.
A custom theme is a **complete** OKLCH palette + font pairing tuned to the brief — not a one-off colour swap, not an excuse to bypass the rules. Every constraint in [`color.md`](references/color.md), [`typography.md`](references/typography.md), and [`anti-patterns.md`](references/anti-patterns.md) still applies. The 58 slop-test gates fire unchanged. The Step 5 preview block surfaces the palette + pairing in plain text **before** any code is emitted, so the user can redirect.
+132
View File
@@ -0,0 +1,132 @@
# Theme - Grid
Swiss neo-grotesque systems design: the object-poster and transit-signage school, executed on a **near-white cool sheet with an exposed 12-column hairline grid, one heavy grotesk, and exactly one signal red used as a geometric mark**. Giant lowercase Archivo slams to the left margin, the column rules stay visible behind the content, and every surface butts against a hairline. It reads like a wayfinding manual: rational, gridded, set once and built to outlast its brief.
The material, in one line: **a visible column grid, one grotesk, and one red square.**
> **The editorial exception.** The editorial cluster is otherwise serif-led (Newsprint, Editorial, Specimen). Grid is its Swiss neo-grotesque slot: no serif anywhere, structure carried by an exposed grid and hairlines, warmth carried by one red. A brief wanting a roman serif or a soft column is a different editorial theme.
## Axes (diversification)
- **Paper band** - **light**, cool near-white (`--color-paper: oklch(99% 0.003 255)`, faintly cool, never `#fff`). Stepped at `paper-2 97.2%` and `paper-3 94.5%`. Ink is cool near-black `--color-ink: oklch(16% 0.010 255)`.
- **Display style** - **grotesk-heavy** (Archivo **800**, `--display-weight: 800`), run **lowercase** at `--tracking-display: -0.045em`. Heavy plus lowercase is the differentiator against every uppercase-condensed and serif option.
- **Accent hue** - **warm signal red** (`--color-accent: oklch(55% 0.21 28)`), one saturated red near 28°, used as a square, a bar, a period, never a wash. `--color-focus` is the same red.
## Reference register
Vitra, Braun, the Vignelli canon, Museum fur Gestaltung, the Swiss International poster tradition. The material to match: the institutional identity manual and the transit-signage system - a modular grid drawn in public, one grotesk, one red, no image needed. When in doubt, ask whether this reads like a systems manual or like a marketing template, and keep the former. Never name any of these in the output.
## Typography
**Archivo only, one family across the whole page** (400/500/600/700/800). Swiss discipline comes from weight, scale, and tracking, not from a second family. `--font-serif` and `--font-mono` resolve to unused fallbacks; do not load them.
- **Display** - Archivo 800, **lowercase**, `clamp(52px, 10.5vw, 136px)`, `letter-spacing: -0.045em`, `line-height: 0.9`. Slammed to the left margin, edge-aligned to the grid.
- **Body** - Archivo 400, 16px, `line-height: 1.5`.
- **Label voice** - Archivo uppercase at 12px, weight 600, `letter-spacing: 0.09em`, `--color-muted`. It sets captions, table headers, meta rows, folios, units, and index numbering - the quiet caps counterpoint to the giant lowercase display. It never sits above a heading as a kicker.
## Material
- **The exposed 12-column hairline grid is the theme.** A `repeating-linear-gradient` of 1px `--color-rule` lines every `calc(100% / 12)`, painted behind the content, capped to the shell width. The grid is content, not scaffolding to delete, and content rides `repeat(12, minmax(0,1fr))` on top of it.
- **Red only as a geometric mark, under 5% of any viewport.** A solid `0.52em` square where a full stop would fall, a short block terminating a row, a `3px` bar over a head. Never a fill wash, never a gradient, never a second colour.
- **Hairlines and ink rules do all the structure; zero cards.** `--radius-card: 0`, `--shadow-card: none`. Faint `--color-rule` hairlines split cells, a 1px-to-2px solid `--color-ink` rule tops a section, and content butts flush against it. No boxes, no float, no drop shadow.
- **Cells, not tiles.** Where the page needs repeated units, they are equal cells of the same grid divided by `border-inline-start` hairlines, sharing the band's top and bottom rules. The band reads as one ruled object, not as a row of separate objects.
- **`::selection` is red on paper.** The one place the accent floods anything.
**Shapes Grid suits** (affinities, never requirements): a numbered index of full-width rows riding the 12 columns, with a hairline between fields and a hover tint; a type specimen where the grid is the exhibit; figures set in bordered cells with caps labels beneath.
## Motion
Near-zero. No reveals, no parallax, no autoplay. The only motion is hover micro-state: a row background shifts to `--color-paper-2` and its title slides 8px, links underline, a bordered surface shifts its border to red. Everything transitions in ~0.18-0.2s ease. Smooth scroll only, and `prefers-reduced-motion: reduce` kills transitions and `scroll-behavior`.
## Do-nots (this theme's own failure modes)
- **Never hide the grid.** The rails stay visible. Deleting them because they look like scaffolding removes the theme.
- **Never uppercase display, never a serif, never a mono body.** Grid's display is lowercase Archivo; uppercase-condensed is Manifesto or Brutal, and the second family never arrives.
- **Never a dark ground, and never a 3px black rule boxing a solid block.** A dark statement page is Manifesto; marker-weight structure is Brutal. Grid is a 99% sheet drawn with a 1px pencil.
- **Never a second accent, a gradient, or a red wash.** One red, geometric, under 5%.
- **Never a card, a radius, or a drop shadow.** Depth is hairlines and ink rules.
- **Never a centred hero.** Slam left.
## Macrostructure affinity
**Grid loves these.**
- **Index-First** - a numbered register of full-width rows riding the twelve columns, hairline between fields *(canonical - grid-01)*
- **Type Specimen** - the grid is the exhibit and the type is the subject
- **Catalogue** - equal ruled cells sharing the band's top and bottom rules
- **Portfolio Grid** - work as a modular register, not as cards
- **Split Studio** - when a studio's two halves each want their own column span
## Macrostructure rejection
**Grid refuses these.**
- **Photographic** - Grid needs no image; the grid is the picture
- **Manifesto** - dark, uppercase and shouted; Grid is a light sheet drawn with a 1px pencil
- **Quote-Led** - too intimate and too centred; Grid slams left
- **Bento Grid** - bento is boxes with radii; Grid is cells divided by hairlines, zero radius
## Voice fixtures
Rational, plainspoken, institutional. Name the system, the place, the year concretely. No hype.
- *"Schedule, then ship."*
- *"Identity, wayfinding, and editorial systems for institutions that plan in decades."*
- *"We draw the grid first, so every decision after it has somewhere to stand."*
- *"Basel, since 2009. Working in DE / EN."*
- *"Twelve columns. One grotesk. One red."*
Never any of: *seamless, robust, cutting-edge, leverage, synergy, revolutionary, unlock, supercharge, elevate, curated, bespoke*. Never "click here." Name the system, the city, the year.
## How Grid differs from its neighbours
| vs | difference |
|---|---|
| **Manifesto** | Manifesto is a **dark** ground (`oklch(10% 0.005 60)`), Anton 400 **uppercase** at `--lh-tight: 0.86`, red `#E51A1A`. Grid is a **light** sheet (`oklch(99% 0.003 255)`), Archivo **800 lowercase**, red `oklch(55% 0.21 28)`. Same "one red, type carries it" DNA, opposite value and case. |
| **Cobalt** | Cobalt is modern-minimal: electric cobalt `oklch(58% 0.20 256)`, Space Grotesk plus JetBrains Mono, graphite code surfaces, 6-10px radii. Grid is editorial: red accent, single-family Archivo, an exposed 12-column grid, zero radius, no code. Blue instrument vs red Swiss manual. |
| **Brutal** | Both are light near-neutral sheets with one red and zero radius, but Brutal draws with **3px** black rules (`--color-rule: oklch(12%)`) boxing solid inverted blocks in Albert Sans 700 **uppercase**. Grid draws with **1px** hairlines (`--color-rule: oklch(88%)`) painting a **visible column grid**, Archivo 800 **lowercase**, no solid panels. Marker vs pencil; shout vs quiet. |
## When the brief routes here
*identity · brand system · wayfinding · signage · design studio · type specimen · editorial grid · institution · museum · archive · index · directory · systems · modular · Swiss · grotesque · manual · programme*. Categories: design and branding studios, cultural institutions, publishers, specimens and catalogs, portfolio indexes. Tone: rational, systematic, precise, institutional, disciplined, timeless, calm-authoritative.
Warm, consumer, image-led, or serif-editorial briefs route elsewhere. When the brief wants a visible grid, one grotesk, and one red, it is Grid.
## Build hint
```html
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
```
```css
html, body { overflow-x: clip; }
body { background: var(--color-paper); color: var(--color-ink);
font-family: var(--font-body); font-size: 16px; line-height: 1.5; }
/* THE ground: the exposed 12-column hairline grid, painted behind the content */
.rails {
position: absolute; inset: 0; z-index: 0; pointer-events: none;
max-width: 1280px; margin-inline: auto;
background-image: repeating-linear-gradient(to right,
var(--color-rule) 0, var(--color-rule) 1px,
transparent 1px, transparent calc(100% / 12));
}
h1, h2 { font-family: var(--font-display); font-weight: var(--display-weight);
font-size: clamp(52px, 10.5vw, 136px); letter-spacing: var(--tracking-display);
line-height: 0.9; text-transform: lowercase; }
.period { /* the one signal, as a mark */
display: inline-block; width: 0.52em; height: 0.52em;
background: var(--color-accent);
}
::selection { background: var(--color-accent); color: var(--color-accent-ink); }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
* { transition-duration: 0.01ms !important; }
}
```
Grid supplies the sheet, the rails, the one grotesk, and the one red. What rides those twelve columns is the brief's business, not the theme's.