The One-Man Company Part III · Chapter 12 of 18

Part III · Chapter 12 of 18

Page Patterns

The marketing-page constitution — one type scale, one hero pattern, one container set, no raw hex. The same brand on /about, /membership, /agents, /handbook.

I ran an audit on the marketing pages one afternoon and found that every page was its own design kingdom.

Six page-specific CSS prefixes — .about-, .m-, .at-, .hb-, .col-, .tux-. Seven different H1 sizes. Three different CTA implementations — a Basecamp-style shadow pill on /membership, Tailwind utility classes on the home page, card-as-CTA on /agents. Container widths of 680px, 720px, 760px, 920px, 60rem (= 960px), 1100px, and "no max-width" all live in the same codebase, often within the same page. The brand looked consistent at human eyeball distance and was a six-month maintenance bill of accidental difference.

The diagnosis was that the team — and "the team" includes the version of me writing each page on a different week — had built each page as if the page were a one-off. Each page worked. Together they looked like five sites pretending to be one.

One brand, one set of pages. One audit, one chapter, one set of primitives.

The chapter that follows is the constitution that came out of the audit — the conventions every marketing page on microapp.io now honors. Most of the decisions are small. Their value comes from being repeated across every page until a member who scrolls from the home to /membership to /about feels they're inside the same product rather than three sites that share a logo.

The transferable why: a multi-page site without a constitution drifts into a portfolio of similar-looking-but-not-quite-identical pages. The drift compounds because each new page inherits the latest page's choices, not the canonical ones — and the canonical ones rot if they aren't written down. Write the conventions; reference them in PR comments; let the brand stay singular by mechanical repetition.

Locked 2026-05-14 · audit done · constitution lives in this chapter


The second decision was the smallest one with the biggest cleanup. Three container widths, three names, that's the whole set.

The seven container widths I found in the audit weren't anyone's fault. Each one made sense at the moment it was chosen — "this page reads better at 720", "this grid needs 1100 to breathe", "this hero is centered so the max-width matters less." The cost of letting each page pick its own width was that every page on the site had a slightly different shoulder margin on a 1440-pixel display, and the inconsistency read at the brand level as drift.

The version that survives is three widths covering three contexts. <ReadingContainer> at 680px for long-form text — letters, articles, book chapter bodies — about 75 characters per line at the lede size. <FeatureContainer> at 920px for marketing pages with two-column rows or hero-and-supporting-visual layouts; the default for most pages. <GridContainer> at 1100px for tool grids, agent grids, category hubs — anything with 3-or-4-column responsive grids inside.

Reading. Feature. Grid. Three names. Everything else inherits.

A page that doesn't fit one of the three is a page that's earning its way to a fourth container — but the bar is "two pages need the same thing and no existing container fits," not "I have a feeling about this specific page." The bar exists because the previous bar was zero and the system grew seven containers in eighteen months.

The transferable why: the cost of a new abstraction is the discipline required to keep everyone else from inventing one. Every container the system supports is one a future contributor has to consider when picking one. Pick the smallest set that covers the use cases; raise the bar for adding a new one; trust the constraint to produce a more consistent site than the freedom would have.

Locked 2026-05-14 · 680 · 920 · 1100 · the three containers


The third decision is the one every marketing page reaches for first. The hero pattern.

Every page hero before the audit had a slightly different anatomy. Some had an eyebrow above the H1, some didn't. Some had a subtitle below; some had a lead paragraph; some had both, awkwardly, with no rhythm between them. Some had a CTA below the lede; some had a CTA in the navigation; some had no CTA and asked the user to scroll. The variations weren't strategic — they were the residue of each page being designed in isolation.

The shape that survives is a four-slot anatomy. Eyebrow (optional, JetBrains Mono uppercase, brand-green). H1 (required, display scale, one per page). Lede (recommended, Inter, two sentences max, 52ch max-width). CTA cluster (when the page converts; primary + optional secondary, never two equal-weight primaries). The slots can be omitted; their order cannot change.

Eyebrow. H1. Lede. CTA. Four slots, fixed order.

The pattern lives in one primitive — <PageHero>. Every marketing page imports it. The H1 size is locked via the clamp() inside <DisplayHeading> so no page can reach for a custom scale. The lede is locked at 52ch by <Lede>. The CTA shape is locked by <PageCTA>. A page's hero is composed, not authored — the page decides what slots to fill, not what they look like.

The transferable why: the parts of a site users see first are the parts that benefit most from being identical across pages. A consistent hero shape is itself a brand asset — the user recognizes "this is a Microapp page" before they read a word. Lock the parts that should be identical; let the content vary. The variation that matters is in the words, not in the rhythm of the slots that hold them.

Locked 2026-05-14 · <PageHero> primitive · eyebrow → h1 → lede → CTA


The fourth decision is the one that produced the most "I disagree with myself" moments in the audit. CTAs — one button, one style.

The audit found three CTA implementations across three pages. Each one was defensible. The shadow-stack pill on /membership looked great. The Tailwind utility CTA on the home page was concise. The card-as-CTA on /agents was clever. Together they were a brand identity disagreement disguised as a stylistic preference.

The version that survives is the shadow-stack pill — rounded pill shape, brand-green by default, white text, four-pixel shadow stack in the darker green, hover lifts one pixel and grows the shadow, active sinks two pixels. Yellow variant for emphasis when the CTA needs to outweigh a nearby green one. Ink variant for the rare case when the CTA sits on a yellow surface. Labels are imperative verbs — "Become a member", "Start reading", "Browse the team" — never "Click here", never a noun, never a complete sentence.

One CTA shape. One per section. Never two side-by-side primaries.

The "two side-by-side primaries" anti-pattern is the one I write down in PR comments most often. Two equal-weight buttons read as "I couldn't decide which action mattered." The fix is always to demote one — primary + ghost secondary — or to delete one. The decision the page is asking the user to make should be the decision the design has already made for them.

The transferable why: CTAs are the place a page resolves itself. A page with a clear CTA is a page that knows what it's for; a page with three equal CTAs is a page that's negotiating with itself in public. Pick one primary action per section. Demote the rest. The visitor's eye finds the one button worth pressing, and the page accomplishes the job it was made for.

Locked 2026-05-14 · <PageCTA> primitive · primary + ghost · imperative-verb labels


The last decision is the one that turns the constitution into something the codebase enforces. Shared primitives + brand-token discipline.

A constitution without enforcement is a wish. The conventions in this chapter would have drifted within a quarter if they lived only in prose. The enforcement comes in two pieces. First, the primitives — <PageHero>, <PageSection>, <DisplayHeading>, <SectionHeading>, <Eyebrow>, <Lede>, <PageCTA>, plus the three containers — all live in src/components/page-ui/. Importing them by name is the path of least resistance; reinventing them is the path of most resistance, which is the right ergonomic gradient.

Second, the brand-token rule. No raw hex literals in src/pages/*.astro or src/layouts/*.astro. Ever. Every color goes through a var(--color-brand-X) token. The palette test in tests/page-palette.test.ts scans every page and layout (plus the page-shaping components) and fails CI when a raw hex shows up outside global.css. The existing offenders are snapshotted in a baseline file; future drift fails the test, retrofits shrink the baseline. The "baseline shrinks, never grows" rule is the enforcement that keeps the system improving over time.

The chapter is the contract. The test is the gate.

Adding a new primitive requires a PR adding it to page-ui/, documenting its signature, listing it in this chapter — and only then using it in a page. Adding a new color requires a PR adding it to global.css first, then referencing it in the page. The chapter and the test move together; one without the other drifts. With both, the site stays consistent at the speed of the work, not at the speed of a future cleanup sprint.

The transferable why: design conventions live in two places to stay alive — a chapter humans read and a test machines enforce. Either one alone fails. The chapter alone drifts because humans forget; the test alone is brittle because tests catch the cases they were written to catch and miss the rest. Both together make the system consistent in proportion to the discipline of both the writers and the gate.

Locked 2026-05-14 · page-ui/ primitives + tests/page-palette.test.ts gate

That's the page constitution. One audit, three containers, four-slot hero, one CTA shape, primitives plus a palette gate. Every marketing page from here on lives inside those choices — and shrinks the drift baseline by one row when it touches a page that drifted.