typeset.md

  1Typography carries most of the information on the page. Replace generic defaults (Inter, Roboto, system fallback at flat scale) with type that reflects the brand and scales with intentional contrast.
  2
  3---
  4
  5## Register
  6
  7Brand: run the font selection procedure in [brand.md](brand.md). Pairing follows the brand's lane (display serif + sans body for editorial/luxury, one committed sans for tech, etc.). Fluid `clamp()` scale, ≥1.25 ratio between steps.
  8
  9Product: system fonts and familiar sans stacks are legitimate here. One well-tuned family typically carries the whole UI. Fixed `rem` scale, 1.125–1.2 ratio between more closely-spaced steps.
 10
 11---
 12
 13## Assess Current Typography
 14
 15Analyze what's weak or generic about the current type:
 16
 171. **Font choices**:
 18   - Are we using invisible defaults? (Inter, Roboto, Arial, Open Sans, system defaults)
 19   - Does the font match the brand personality? (A playful brand shouldn't use a corporate typeface)
 20   - Are there too many font families? (More than 2-3 is almost always a mess)
 21
 222. **Hierarchy**:
 23   - Can you tell headings from body from captions at a glance?
 24   - Are font sizes too close together? (14px, 15px, 16px = muddy hierarchy)
 25   - Are weight contrasts strong enough? (Medium vs Regular is barely visible)
 26
 273. **Sizing & scale**:
 28   - Is there a consistent type scale, or are sizes arbitrary?
 29   - Does body text meet minimum readability? (16px+)
 30   - Is the sizing strategy appropriate for the context? (Fixed `rem` scales for app UIs; fluid `clamp()` for marketing/content page headings)
 31
 324. **Readability**:
 33   - Are line lengths comfortable? (45-75 characters ideal)
 34   - Is line-height appropriate for the font and context?
 35   - Is there enough contrast between text and background?
 36
 375. **Consistency**:
 38   - Are the same elements styled the same way throughout?
 39   - Are font weights used consistently? (Not bold in one section, semibold in another for the same role)
 40   - Is letter-spacing intentional or default everywhere?
 41
 42**CRITICAL**: The goal isn't to make text "fancier." It's to make it clearer, more readable, and more intentional. Good typography is invisible; bad typography is distracting.
 43
 44## Plan Typography Improvements
 45
 46Consult the [typography reference](typography.md) for detailed guidance on scales, pairing, and loading strategies.
 47
 48Create a systematic plan:
 49
 50- **Font selection**: Do fonts need replacing? What fits the brand/context?
 51- **Type scale**: Establish a modular scale (e.g., 1.25 ratio) with clear hierarchy
 52- **Weight strategy**: Which weights serve which roles? (Regular for body, Semibold for labels, Bold for headings, or whatever fits)
 53- **Spacing**: Line-heights, letter-spacing, and margins between typographic elements
 54
 55## Improve Typography Systematically
 56
 57### Font Selection
 58
 59If fonts need replacing:
 60- Choose fonts that reflect the brand personality
 61- Pair with genuine contrast (serif + sans, geometric + humanist), or use a single family in multiple weights
 62- Ensure web font loading doesn't cause layout shift (`font-display: swap`, metric-matched fallbacks)
 63
 64### Establish Hierarchy
 65
 66Build a clear type scale:
 67- **5 sizes cover most needs**: caption, secondary, body, subheading, heading
 68- **Use a consistent ratio** between levels (1.25, 1.333, or 1.5)
 69- **Combine dimensions**: Size + weight + color + space for strong hierarchy. Don't rely on size alone
 70- **App UIs**: Use a fixed `rem`-based type scale, optionally adjusted at 1-2 breakpoints. Fluid sizing undermines the spatial predictability that dense, container-based layouts need
 71- **Marketing / content pages**: Use fluid sizing via `clamp(min, preferred, max)` for headings and display text. Keep body text fixed
 72
 73### Fix Readability
 74
 75- Set `max-width` on text containers using `ch` units (`max-width: 65ch`)
 76- Adjust line-height per context: tighter for headings (1.1-1.2), looser for body (1.5-1.7)
 77- Increase line-height slightly for light-on-dark text
 78- Ensure body text is at least 16px / 1rem
 79
 80### Refine Details
 81
 82- Use `tabular-nums` for data tables and numbers that should align
 83- Apply proper `letter-spacing`: slightly open for small caps and uppercase, default or tight for large display text
 84- Use semantic token names (`--text-body`, `--text-heading`), not value names (`--font-16`)
 85- Set `font-kerning: normal` and consider OpenType features where appropriate
 86
 87### Weight Consistency
 88
 89- Define clear roles for each weight and stick to them
 90- Don't use more than 3-4 weights (Regular, Medium, Semibold, Bold is plenty)
 91- Load only the weights you actually use (each weight adds to page load)
 92
 93**NEVER**:
 94- Use more than 2-3 font families
 95- Pick sizes arbitrarily; commit to a scale
 96- Set body text below 16px
 97- Use decorative/display fonts for body text
 98- Disable browser zoom (`user-scalable=no`)
 99- Use `px` for font sizes; use `rem` to respect user settings
100- Default to Inter/Roboto/Open Sans when personality matters
101- Pair fonts that are similar but not identical (two geometric sans-serifs)
102
103## Verify Typography Improvements
104
105- **Hierarchy**: Can you identify heading vs body vs caption instantly?
106- **Readability**: Is body text comfortable to read in long passages?
107- **Consistency**: Are same-role elements styled identically throughout?
108- **Personality**: Does the typography reflect the brand?
109- **Performance**: Are web fonts loading efficiently without layout shift?
110- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%?
111
112When the type carries the hierarchy on its own, hand off to `{{command_prefix}}impeccable polish` for the final pass.
113
114## Live-mode signature params
115
116Each variant MUST declare a `scale` param controlling the hierarchy ratio. Express all font sizes in the variant's scoped CSS through `calc(var(--p-scale, 1) * <base>)` or, better, scale the type ramp via `clamp(min, calc(var(--p-scale, 1) * Npx), max)`. Users slide from subdued to commanding.
117
118```json
119{"id":"scale","kind":"range","min":0.85,"max":1.3,"step":0.05,"default":1,"label":"Scale"}
120```
121
122Where the variant riffs on a specific pairing, expose the pairing choice as a `steps` param (e.g. "serif display + sans body" vs. "mono display + sans body" vs. "all-sans"). Each branch routes through `:scope[data-p-pairing="X"]` selectors in scoped CSS.
123
124See `reference/live.md` for the full params contract.