Tool UX governs the widgets. This chapter governs everything else — the marketing pages, the content pages, the long-form chapters where the user is reading, not calculating. /about, /membership, /agents, /handbook, /explore, /blog, /categories, and every static page that will exist next year.
Why this chapter exists: an audit on 2026-05-14 found that the marketing pages were quietly worse than the tool widgets. Eight raw-hex colors on /about. Six on /agents. Four different H1 type scales across four pages. Five different hero patterns. Six different CSS class prefixes (.about-, .m-, .at-, .hb-, .col-, .tux-) — every page is its own little design kingdom. The brand-palette test catches banned tokens leaking out of global.css; it does not catch rogue new hex values leaking in to pages. That gap is what this chapter closes.
1. The shape of a page
Every marketing page follows the same vertical skeleton. Different content, same beats:
- Hero — eyebrow (optional), h1, subhead, primary CTA (optional). One per page. Above the fold.
- Body sections — alternating cream / paper backgrounds for visual rhythm. 4-6 sections, each with its own h2 + subhead + content.
- Closer CTA (optional) — when the page has a conversion goal (e.g.
/membership→ "Become a member"). Pages like/aboutclose with a letter signature instead. - Footer — the shared HomeFooter, not a per-page footer.
No page has its own nav, its own footer, its own splash screen, or its own onboarding modal. The page IS the content; the chrome stays consistent.
2. The type scale — one set, no per-page variants
Four clamp() formulas for h1 across four pages was the worst finding in the audit. From this chapter on, there is one type scale.
| Element | Font + weight | Size (clamp) | Use for |
|---|---|---|---|
| Display H1 (hero) | Plus Jakarta Sans 800 | clamp(2.5rem, 6vw, 4.5rem) | Top of marketing pages. One per page. |
| Section H2 | Plus Jakarta Sans 800 | clamp(1.75rem, 3.5vw, 2.5rem) | Section headings inside body. |
| Subsection H3 | Plus Jakarta Sans 800 | 1.25rem | Sub-headings within a section. |
| Eyebrow (label) | JetBrains Mono 700 uppercase | 0.75rem, letter-spacing 0.12em | Section identifier above an H2. |
| Body | Inter 400 | 1.025rem, line-height 1.7 | Long-form reading copy. |
| Lede | Inter 500 | clamp(1.1rem, 1.8vw, 1.25rem) | The subhead under the hero H1. |
| Caption / meta | JetBrains Mono 500 | 0.75rem | Dates, attributions, supporting metadata. |
The handbook cover (/handbook) is intentionally outside this scale — it's a book cover, not a marketing page. That divergence is documented as a §10 exception. Any other page using a different clamp is a violation.
Membership · 2026
Everything has a solution.
The values
Two sentences max. Tells the user what the page promises in plain prose.
Default — brand-green
For most sections. Visually accents the heading.
Muted — secondary
When another nearby element is already brand-green.
3. The hero pattern
Every marketing page hero has the same four-slot anatomy. Slots can be omitted; their ORDER cannot change:
- Eyebrow (optional) — JetBrains Mono uppercase, brand-green, sits above the H1. Use it for section identifiers ("The Microapp Handbook", "The team", "Membership"). Omit on the most editorial pages (e.g.
/about's letter intentionally has no eyebrow). - H1 (required) — Display scale, max 14-18 characters per line. Center-aligned on hero pages; left-aligned on book-style pages. One per page.
- Lede (recommended) — Inter, ~36-52ch max-width, sits directly under the H1. Two sentences max. Tells the user what the page promises in plain prose.
- CTA cluster (when the page has a conversion) — see §6. Single primary CTA + optional secondary link. Not two equal-weight buttons.
Decoration policy: floating background dots and stickers are allowed on the most "marketing" pages (/membership) and discouraged on the most "editorial" pages (/about, /handbook). Pick a mood and commit; mixing partial decoration looks like an abandoned theme.
The Microapp Team
Meet the team.
Microapp is built by agents. Each one has a single job, a distinct voice, and a public handle.
4. Containers — three widths, three names
The audit found 680px, 720px, 760px, 920px, 60rem (= 960px), 1100px, and "no max-width" all in use, often inside the same page. From this chapter on, there are three.
| Container | Width | Use for |
|---|---|---|
.page-container-reading | max-width: 680px | Long-form text: letters, articles, handbook chapter bodies. ~75 chars/line at the lede size. |
.page-container-feature | max-width: 920px | Marketing pages with two-column rows, side-by-side cards, hero + supporting visual. The default for most pages. |
.page-container-grid | max-width: 1100px | Tool grids, agent grids, category hubs — anything with 3-4 column responsive grids inside. |
All three include horizontal padding (1.5rem at mobile, 2rem at desktop). Center the container; don't apply margin auto on the page body directly.
5. Section rhythm
- Vertical padding per section:
4.5rem 1.5rem(default). Compress to3rem 1.5remonly for the section directly under the hero. Expand to6rem 1.5remfor the final section before the footer. - Alternate backgrounds: cream / paper / cream / paper. Use
var(--color-brand-cream)as the base,var(--color-brand-paper)for the "alt" sections. Never invent a third background color for variety. - Section header pattern: eyebrow → h2 → lede. Three elements, top-aligned, max-width
52chon the lede. - Don't end a page on alt-paper. Closing sections sit on cream so the page meets the cream footer cleanly.
6. CTAs — one button, one style
The audit found three different CTA implementations in three pages — /membership has a Basecamp-style shadow-stack pill; the home has Tailwind utility classes; /agents uses card-as-CTA. From this chapter on, there is one primary CTA:
- Shape: rounded pill (
border-radius: 9999px), padding1rem 2rem, font Plus Jakarta Sans 800 at1rem. - Default color: green (
--color-brand-green), white text,0 4px 0 var(--color-brand-green-dark)shadow stack. - Emphasis variant: yellow (
--color-brand-yellow), ink text,0 4px 0 var(--color-brand-yellow-dark)shadow stack. Use sparingly — when you want this CTA to outweigh the one above it (e.g. closing CTA on/membership). - Hover:
translateY(-1px)+ shadow grows to 5px. Active:translateY(2px)+ shadow shrinks to 2px. Matches the rest of the brand. - Labels are imperative verbs: "Become a member", "Start reading", "Try Word Counter", "Browse the team". Not nouns. Not "Click here".
- One primary CTA per section. Two side-by-side primaries is the "I couldn't decide" anti-pattern. Use primary + ghost secondary if you need both — never two primaries.
7. Brand-token discipline — no raw hex
This is the rule the brand-palette test misses. Today the test catches palette hexes leaking out of global.css. It does not catch new rogue hexes leaking in. That's the audit's worst finding: /about has eight raw hex values that aren't in the palette at all. #5a9e3a ("the agents page green") has been silently sitting in four files for months.
- No raw hex in
src/pages/*.astroorsrc/layouts/*.astro— period. Every color goes through avar(--color-brand-X)token. If a color you need isn't in the palette, add it toglobal.cssfirst, then reference it. - No "close-but-not-exact" matches. If you wanted brand-green and typed
#5a9e3afrom memory — that's not the palette green. The palette green is--color-brand-green(its literal value lives inglobal.css— never typed in pages). Use the token; don't guess the value. - No private page palettes. A "lighter green for the agents page" is not a thing. The palette has one green family with documented variants (
--color-brand-green,--color-brand-green-dark,--color-brand-green-light,--color-brand-forest,--color-brand-lime). Pick one.
tests/page-palette.test.ts (next PR) flags every hex color in src/pages/*.astro and src/layouts/*.astro that isn't a documented exception. Like tests/ui-primitives.test.ts, it snapshots known violators in a baseline file. Future drift fails the suite; retrofits shrink the baseline.
8. Class-name discipline
Every page is currently its own design kingdom — .about-, .m-, .at-, .hb-, .col-, .tux-, and counting. Each prefix re-implements heading sizes, container widths, button styles. Six islands, zero bridges.
- Prefer shared primitives over local classes. Use
<PageHero>,<PageSection>,<PageCTA>,<ReadingContainer>fromsrc/components/page-ui/(next PR ships these). Importing beats authoring. - When you must write per-page styles (rare — only when a page has genuinely unique chrome), prefix the page's slug:
/aboutuses.about-,/membershipuses.m-. No fantasy prefixes; if your page is/something, your prefix is.something-. - No new chapter prefixes — handbook chapters use
.<slug>-(the existing pattern:.col-for colophon,.tux-for tool-ux,.pp-for this chapter).
9. The shared primitives
Same shape as Tool UX §9 — the bridge from the constitution to the implementation. The next PR scaffolds these in src/components/page-ui/; this chapter documents their names so the next page that needs them imports rather than reinvents.
import { PageHero } from "@/components/page-ui/PageHero" variant="alt" for paper-background alternation. Slot for eyebrow, h2, lede, content.
import { PageSection } from "@/components/page-ui/PageSection" clamp(). Use inside <PageHero> or as a standalone display piece. Per-page H1 styling stops here.
import { DisplayHeading } from "@/components/page-ui/Heading" <Eyebrow> for the standard section-header pattern.
import { SectionHeading } from "@/components/page-ui/Heading" import { Eyebrow } from "@/components/page-ui/Eyebrow" clamp() + max-width 52ch.
import { Lede } from "@/components/page-ui/Lede" green (default), yellow (emphasis). Handles hover + active transforms and the shadow stack. Renders as <a> or <button> via the href prop.
import { PageCTA } from "@/components/page-ui/PageCTA" import { ReadingContainer } from "@/components/page-ui/Container" import { FeatureContainer } from "@/components/page-ui/Container" import { GridContainer } from "@/components/page-ui/Container" src/components/page-ui/ with a documented signature, (2) add it to this chapter's §9, (3) only then use it in your page. The chapter is the contract.
10. Drift — what currently violates this chapter
Honest section. The conventions above were written after the existing pages had already drifted. Each row is queued for retrofit; the order is opportunistic (when we touch a page for another reason, we update it).
| Page | What drifts | Fix on next touch |
|---|---|---|
/about ✓ retrofitted | All 8 raw-hex colors swapped to var(--color-brand-*) tokens in PR (next). Editorial layout preserved; the structural primitive adoption (<PageHero> + <ReadingContainer>) deferred to a later retrofit so the diff stays reviewable. | Remaining: structural primitive adoption + private H1 clamp() → <DisplayHeading> + drop the .about- class kingdom in favor of <PageSection>. Lower priority — the visible drift (color) is fixed. |
/agents | 6 raw hex (#1a2e1a, #374151, #5a9e3a, #b9e07e, #f9f7f4, #fff); .at-/.ap- kingdom; H1 clamp is different from §2 scale | Token sweep; adopt <PageHero> + <GridContainer>; the agent profile cards stay as a per-page concern |
/handbook (cover) | #111111 and #ffffff raw hex; H1 clamp clamp(3rem, 8vw, 6rem) exceeds the §2 scale | Intentional exception — the cover is a book cover, not a marketing page. Tokens still required; the larger clamp is permitted and documented here. |
/membership | Mostly token-clean (only #000). H1 clamp is private. Basecamp-style CTA pre-dates <PageCTA>. | Token-clean #000; switch CTA + heading to primitives |
/handbook chapter layouts | Each chapter has its own class prefix (.col-, .tux-, .pp-, etc.) — intentional for chapter-specific styling, but the per-chapter h1/h2 sizes drift from §2 | Keep the chapter prefix system; introduce a shared chapter-style mixin for h1/h2 sizing |
/explore, /categories, /blog | Mostly Tailwind utility classes (clean) — but some inline style attributes with raw hex still slip through | Sweep on next touch; small diffs each |
When this table reaches zero rows, the marketing pages are consistent. Until then, the chapter is the goal and the table is the gap.
For agents and reviewers
Anyone editing a marketing page — Bob, a human, a future agent — reads this chapter before opening the PR. The next PR ships the primitives in src/components/page-ui/; once it lands, importing them by name is the path of least resistance.
Reviewers cite section numbers in PR comments. "§7 — no raw hex" beats re-arguing the rule every time. Ben adds a Page Patterns check pass to its audit alongside the existing Tool UX pass.