Claude Skill

typography-audit

Audits font loading, type scales, measure, spacing, OpenType, and rendered punctuation with 78 scoped rules. Use when asked to "audit typography", "fix the fonts", or "review my type system". For a new visual direction use ui-design Direction; for general UI defects use ui-design

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download mblode-agent-skills-skills_typography-audit-24f4fd8.zip · 58 KB
Part of mblode/agent-skills — 22 skills

Install

skills CLI npx skills add https://github.com/mblode/agent-skills/tree/main/skills/typography-audit
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install mblode-agent-skills@llmmart
Git git clone https://github.com/mblode/agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole mblode/agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Typography Audit

78 rules in 10 categories for web typography. Every finding names file, rule, and fix.

  • IS: typography only: font loading, sizing, punctuation, spacing, hierarchy, text layout, OpenType features, typeface pairing, brand type, display type.
  • IS NOT: broad UI review (accessibility, forms, navigation: use ui-design Audit mode), or a redesign (new typefaces, scales: use ui-design Direction mode).

Audit Workflow

Track this checklist:

Audit progress:
- [ ] Step 1: Scope. List changed files (or full sweep), map signals to categories
- [ ] Step 2: Run CRITICAL rules in scope (font-, size-, punct-)
- [ ] Step 3: Run HIGH rules in scope (spacing-)
- [ ] Step 4: Run remaining in-scope categories by descending priority
- [ ] Step 5: Report per the contract; every finding has file:line, rule ID, fix
  1. Scope to changed files unless a full sweep is requested. For a PR, use the diff against its actual base merge-base, including committed changes, filtered to .css, .scss, .html, .tsx/.jsx, and template files.
  2. Map code to categories via the signal table; skip categories with no signal.
  3. Load rule files by prefix (rules/font-*.md, etc.), only for the categories the signals selected.
  4. Run categories in priority order so CRITICAL findings surface even if the audit is cut short.
  5. After fixes, re-run only the rules that produced findings, then finalize the report.

Scoping Signals → Categories

Signal in code Categories to load
@font-face, font-family, font files, variable fonts, font-stretch, transform: scaleX on text font-
font-size, clamp(), media-query type changes, max-width on text, <em>/<strong>, text-decoration size-
Copy in HTML/JSX (headings, paragraphs, labels) punct-
line-height, letter-spacing, word-spacing, margin on text, text-transform: uppercase spacing-
Heading elements, type scale tokens, --text-* properties hierarchy-
text-align, lists, blockquotes, multi-column text layout-
font-feature-settings, font-variant-*, figures/fractions in copy opentype-
Logo/wordmark styles, brand tokens, text color tokens, license comments brand-
Two or more distinct font-family values pairing-
Hero/display sizes, drop caps, initial-letter display-

Rule Categories by Priority

Priority Category Impact Prefix Rules
1 Font Selection & Weights CRITICAL font- 11
2 Sizing & Measure CRITICAL size- 6
3 Punctuation & Special Characters CRITICAL punct- 12
4 Spacing & Rhythm HIGH spacing- 8
5 Hierarchy & Scale MEDIUM-HIGH hierarchy- 8
6 Alignment & Layout MEDIUM layout- 6
7 OpenType Features MEDIUM opentype- 7
8 Brand & Identity MEDIUM brand- 8
9 Typeface Pairing MEDIUM pairing- 5
10 Display & Headlines LOW-MEDIUM display- 7

Category map and impact rationale: rules/_sections.md. Each rule file gives why it matters plus an incorrect and a correct example. Category impact reflects the category's worst-case rules; report findings with the rule's own frontmatter impact, which frequently differs (e.g. brand-color is HIGH inside the MEDIUM brand- category because it holds the WCAG contrast floor).

Review Output Contract

Report findings as:

## Typography Audit Findings

### path/to/file.css
- [CRITICAL] `punct-smart-quotes` (file.css:42): Straight quotes in heading copy.
  - Fix: Replace `"` with `&ldquo;`/`&rdquo;` (or UTF-8 curly quotes).
- [CRITICAL] `size-line-height` (file.css:18): `line-height: 20px`, a fixed value the 48px `h1` inherits, so its lines overlap.
  - Fix: Use unitless `line-height: 1.5`.

### path/to/clean-file.css
- ✓ pass
  • Group by file; order by impact within file.
  • Every finding: impact tag, rule ID, file:line, one-line issue, fix.
  • Include clean files as ✓ pass so coverage is visible.
  • End with a summary: counts per impact level.

Gotchas

  • Don't preload every rule file. Load only the prefixes the signal table selects; a full load spends the budget on categories with no signal in scope.
  • Report the rule's frontmatter impact, never the category's. Two rules get misreported most: brand-color is HIGH (an accessibility floor, not a brand nicety) and punct-daggers is LOW-MEDIUM (decoration, despite sitting in a CRITICAL category).
  • Punctuation rules apply to rendered copy only. Flagging straight quotes or -- inside <code>, <pre>, or JS/TS string literals is a false positive; "fixing" them breaks the code.
  • Confirm the rendered font and computed styles through ui-verification when a finding depends on them. A CSS declaration alone does not prove which face loaded.
  • Don't flag missing OpenType features without confirming the loaded font ships them. Browsers silently ignore unsupported font-feature-settings tags, so the fix does nothing.
  • Every finding needs file:line and a concrete fix; an unactionable finding forces a redo.
  • An audit is not a redesign. Proposing new pairings or scales turns a 10-minute review into a design project; flag the issue and route redesign asks to ui-design.
  • Don't equalize priorities. A LOW-MEDIUM display- nit above a CRITICAL faux-bold finding buries what actually looks broken.

Related Skills

  • ui-design Audit mode: broad frontend quality (accessibility, forms, navigation, motion); its typography coverage is shallower.
  • ui-design Direction mode: choosing typefaces, scales, and visual direction from scratch; run when a finding becomes a redesign request.
  • copywriting: heading and label wording. This skill governs only the casing of that copy (punct-case-rules).

Maintenance only: evals/evals.json contains regression scenarios for changes to this skill; it does not load during a user task.

Files (agent-skills)
  • evals
    • evals.json 1.4 KB
      {
        "skill_name": "typography-audit",
        "evals": [
          {
            "id": 1,
            "prompt": "Audit a PR whose committed CSS sets an h1 to 48px while inheriting a fixed 20px line-height. The unstaged diff is empty.",
            "expected_output": "Inspect the PR branch diff and report the overlapping-line risk.",
            "files": [],
            "assertions": [
              "Includes committed changes against the actual PR base",
              "Names the inherited fixed line-height",
              "Uses the rule-specific impact rather than the category default"
            ]
          },
          {
            "id": 2,
            "prompt": "Audit code samples that contain straight quotes and a --no-input flag, beside rendered paragraph text.",
            "expected_output": "Keep code punctuation verbatim and scope typography rules to rendered prose.",
            "files": [],
            "assertions": [
              "Does not replace quotes inside code",
              "Does not alter --no-input",
              "Distinguishes declared fonts from the face actually loaded"
            ]
          }
        ],
        "routing": {
          "should_trigger": [
            "Audit a PR whose committed CSS sets an h1 to 48px while inheriting a fixed 20px line-height. The unstaged diff is empty.",
            "Audit code samples that contain straight quotes and a --no-input flag, beside rendered paragraph text."
          ],
          "near_miss": [
            {
              "prompt": "Choose a new visual direction for our landing page.",
              "expected": "ui-design Direction"
            }
          ]
        }
      }
      
  • rules
    • brand-capitalization.md 957 B
      ---
      title: Choose Consistent Brand Capitalization
      impact: LOW-MEDIUM
      tags: brand, capitalization, naming, consistency
      ---
      
      ## Choose Consistent Brand Capitalization
      
      Pick one capitalization style for the brand name and enforce it everywhere. Prefer a single word with an initial capital (e.g., "Typewolf" not "TypeWolf" or "TYPEWOLF"). Avoid all-caps brand names in running text (they disrupt reading flow), and mid-word capitals unless essential to the brand.
      
      Drop ".com" in prose. Enforce the style across all media, docs, and code.
      
      **Incorrect (inconsistent capitalization):**
      
      ```html
      <p>Welcome to TypeWolf.com</p>              <!-- .com, mid-word cap -->
      <p>TYPEWOLF is a typography resource.</p>    <!-- all caps in prose -->
      <p>Visit typewolf for inspiration.</p>       <!-- lowercase -->
      ```
      
      **Correct (consistent style):**
      
      ```html
      <p>Welcome to Typewolf</p>
      <p>Typewolf is a typography resource.</p>
      <p>Visit Typewolf for inspiration.</p>
      ```
      
    • brand-color.md 1.4 KB
      ---
      title: Use Color Intentionally in Typography
      impact: HIGH
      tags: color, contrast, tinted-black, brand, accessibility
      ---
      
      ## Use Color Intentionally in Typography
      
      Every text color has to clear WCAG AA: 4.5:1 against its background for body text, 3:1 for large text (24px+, or 19px+ bold). That is the floor, not the target, and it applies to secondary text, placeholders, and disabled labels too, which is where brand palettes usually fail. Inside that budget, use color for hierarchy and identity. Avoid pure black (#000) on pure white (#fff): the extreme contrast strains the eyes. Use tinted blacks and off-whites for a refined, readable result.
      
      **Incorrect (pure black on pure white, no brand color):**
      
      ```css
      body {
        color: #000000;
        background: #ffffff;
      }
      ```
      
      **Correct (tinted black, brand-informed palette):**
      
      ```css
      :root {
        --text-primary: #1a1a2e;     /* dark navy, not pure black */
        --text-secondary: #4a4a68;    /* lighter for secondary text */
        --bg-primary: #fafaf8;        /* warm off-white */
        --accent: #2d5f8a;            /* brand blue for links/highlights */
      }
      
      body {
        color: var(--text-primary);
        background: var(--bg-primary);
      }
      
      a {
        color: var(--accent);
      }
      ```
      
      Subtle tints (warm, cool, brand-hued) add atmosphere without hurting readability. Measure the computed pair, not the token name: a `--text-secondary` that reads as "gray" can still land at 3.1:1 on an off-white background.
      
    • brand-cross-medium.md 814 B
      ---
      title: Keep Type Consistent Across Media
      impact: LOW-MEDIUM
      tags: cross-medium, web, print, app, consistency
      ---
      
      ## Keep Type Consistent Across Media
      
      Use the same typefaces across web, print, and app, licensing each medium separately as needed. Consistency builds recognition: readers subconsciously tie your type choices to your brand.
      
      **Incorrect (different faces per medium):**
      
      ```
      Web:   font-family: 'Open Sans', sans-serif;
      Print: Myriad Pro (from Adobe)
      App:   San Francisco (system font)
      ```
      
      **Correct (same family everywhere):**
      
      ```
      Web:   font-family: 'Inter', sans-serif;
      Print: Inter (desktop license)
      App:   Inter (embedded font)
      ```
      
      When a font is unavailable on a platform, use the closest metrically compatible alternative. Document the type system and its platform-specific variations.
      
    • brand-dark-backgrounds.md 1 KB
      ---
      title: Handle Dark Backgrounds Carefully
      impact: MEDIUM-HIGH
      tags: dark-mode, reversed-text, contrast, readability
      ---
      
      ## Handle Dark Backgrounds Carefully
      
      Light text on dark (reversed type) is harder to read in long passages, so use off-white, not pure white, to reduce glare. Reserve reversed type for short sections, headers, and UI, not extended body text. In dark mode, increase font weight slightly and loosen line height.
      
      **Incorrect (pure white on pure black, extended body):**
      
      ```css
      .dark-section {
        background: #000;
        color: #fff; /* harsh contrast, eye strain */
      }
      
      .dark-section .article {
        /* Long body text in reversed type: hard to read */
      }
      ```
      
      **Correct (off-white on dark, limited reversed body text):**
      
      ```css
      .dark-section {
        background: #1a1a2e;
        color: #e8e8ed; /* off-white, reduces glare */
      }
      
      .dark-section body {
        font-weight: 450; /* slightly heavier for dark backgrounds */
        line-height: 1.6; /* slightly looser */
      }
      ```
      
      Test dark backgrounds across screen brightness levels and lighting conditions.
      
    • brand-equity.md 1.3 KB
      ---
      title: Protect Brand Typographic Equity
      impact: LOW-MEDIUM
      tags: brand, consistency, equity, identity
      ---
      
      ## Protect Brand Typographic Equity
      
      Once core type choices are set, stick with them; frequent changes erode recognition. Document the system (typefaces, sizes, weights, colors, spacing) as design tokens or CSS custom properties and require adherence across all touchpoints.
      
      **Incorrect (ad-hoc fonts per surface, nothing documented):**
      
      ```css
      /* landing.css */
      h1 { font-family: 'Fraunces', serif; }
      
      /* dashboard.css: someone picked a different heading face */
      h1 { font-family: 'Playfair Display', serif; }
      
      /* email.css: a third variant, hardcoded */
      h1 { font-family: Georgia, serif; }
      ```
      
      **Correct (system documented in tokens, used everywhere):**
      
      ```css
      :root {
        /* Primary typeface: Inter (licensed for web) */
        --font-primary: 'Inter', -apple-system, sans-serif;
      
        /* Heading typeface: Fraunces (Google Fonts, SIL OFL) */
        --font-heading: 'Fraunces', Georgia, serif;
      
        /* Monospace: JetBrains Mono */
        --font-mono: 'JetBrains Mono', monospace;
      }
      
      h1 { font-family: var(--font-heading); }
      ```
      
      Allow evolution but require justification. Add at least one distinctive typographic move per project as a deliberate part of the system, not a one-off. Keep links to foundry pages and license docs.
      
    • brand-identifiable-body.md 1013 B
      ---
      title: Make Body Text Distinctive
      impact: LOW-MEDIUM
      tags: brand, body-text, identity, distinctive, default
      ---
      
      ## Make Body Text Distinctive
      
      Go beyond default system fonts and generic web fonts. Your body text should be distinctive enough that a reader could identify your brand from a paragraph alone. Experiment with less common typefaces, consider custom fonts, and pair font choices with deliberate size, weight, and color decisions.
      
      **Incorrect (generic, indistinguishable body text):**
      
      ```css
      body {
        font-family: Arial, sans-serif;
        font-size: 16px;
        color: #333;
        /* Looks like every other website */
      }
      ```
      
      **Correct (considered, distinctive body text):**
      
      ```css
      body {
        font-family: 'Söhne', sans-serif;
        font-size: 18px;
        color: #1a1a2e;
        line-height: 1.55;
        font-feature-settings: "kern", "liga", "calt";
      }
      ```
      
      Add at least one distinctive typographic move per project: a unique typeface choice, unusual weight, or specific OpenType feature that gives the typography personality.
      
    • brand-licensing.md 1.4 KB
      ---
      title: License Fonts Properly
      impact: HIGH
      tags: licensing, web-fonts, open-source, commercial
      ---
      
      ## License Fonts Properly
      
      Every font license specifies permitted uses. Web, desktop, and app-embedded use often require separate licenses. Never use pirated fonts or files converted from a desktop-only license.
      
      **Incorrect (desktop font converted and self-hosted without a web license):**
      
      ```css
      @font-face {
        font-family: 'Gotham';
        /* .otf from a designer's machine run through a converter;
           the desktop license does not cover web embedding */
        src: url('/fonts/gotham-converted.woff2') format('woff2');
      }
      ```
      
      **Correct (licensed source, terms documented in code):**
      
      ```css
      @font-face {
        font-family: 'Inter';
        /* SIL OFL 1.1: web use and self-hosting permitted.
           License: /fonts/LICENSE-Inter.txt */
        src: url('/fonts/Inter-Variable.woff2') format('woff2');
      }
      ```
      
      **Checklist:**
      
      - Verify the license covers web use (self-hosted or CDN)
      - Check pageview limits on commercial web font licenses
      - Confirm embedding rights for apps or PDFs
      - Ensure the license covers the number of domains/projects
      - Keep license documentation accessible to the team
      
      Open-source: Google Fonts (SIL OFL), Adobe Fonts (with Creative Cloud), Font Squirrel, fonts.bunny.net. Commercial foundries: Hoefler&Co, Commercial Type, Klim, Grilli Type, Dinamo, Colophon. On a limited budget, start open-source and upgrade as the brand matures.
      
    • brand-logo-typeface.md 1.1 KB
      ---
      title: Choose Logo Typeface Based on Specific Letters
      impact: LOW-MEDIUM
      tags: logo, typeface, letterforms, brand, identity
      ---
      
      ## Choose Logo Typeface Based on Specific Letters
      
      Choose a logo or wordmark typeface by the specific letters in the brand name, not overall aesthetics. An A or g that's generic in one face may be striking in another.
      
      **Incorrect (default UI face reused for the wordmark, no distinctive glyphs):**
      
      ```css
      /* "Agatha" set in the same face as the rest of the UI;
         nothing in the wordmark is memorable */
      .logo {
        font-family: 'Helvetica Neue', sans-serif;
        font-weight: 700;
      }
      ```
      
      **Correct (chosen for the specific letters in the name):**
      
      ```css
      /* "Agatha": chosen because Didot's 'A' and 'g' are distinctive */
      .logo {
        font-family: 'Didot', serif;
        font-size: 2rem;
        letter-spacing: 0.05em;
      }
      ```
      
      **Process:** set the brand name in 20-30 candidates, focus on the most prominent letters, test at large and small sizes, verify the license covers logo use. Use swashes, discretionary ligatures, and stylistic alternates sparingly; check italic variants for swash characters (often in separate files or behind OpenType features).
      
    • display-drop-caps.md 1.2 KB
      ---
      title: Implement Drop Caps or Initial Caps
      impact: MEDIUM
      tags: drop-cap, initial-letter, initial-cap, editorial
      ---
      
      ## Implement Drop Caps or Initial Caps
      
      Drop caps (a large initial letter spanning multiple lines) add editorial polish at the start of articles or major sections. Use CSS `initial-letter` with a float fallback, not a bare `font-size` bump (which breaks line alignment).
      
      **Incorrect (oversized first letter with no drop-cap handling):**
      
      ```css
      .article > p:first-of-type::first-letter {
        font-size: 3.5em;
        /* No initial-letter or float, so the huge glyph sits on the first
           baseline and shoves line 1 away from the rest of the paragraph */
      }
      ```
      
      **Correct (initial-letter with float fallback):**
      
      ```css
      .article > p:first-of-type::first-letter {
        initial-letter: 3; /* spans 3 lines */
        font-weight: 700;
        margin-right: 0.1em;
        color: var(--accent);
      }
      
      @supports not (initial-letter: 3) {
        .article > p:first-of-type::first-letter {
          float: left;
          font-size: 3.5em;
          line-height: 0.8;
          padding-right: 0.1em;
        }
      }
      ```
      
      Keep them simple; decorative versions look heavy on screen. Use at the start of articles or major sections, never every paragraph. Small caps after the drop cap ease the transition to body text.
      
    • display-grid-breaking.md 1 KB
      ---
      title: Break the Grid Intentionally
      impact: LOW-MEDIUM
      tags: grid, layout, oversized, pull-quotes, editorial
      ---
      
      ## Break the Grid Intentionally
      
      Oversized type, full-bleed images, and pull quotes that extend past the text column break monotony. Break the grid as a deliberate choice, keeping the underlying structure intact.
      
      **Incorrect (accidental grid break, sloppy layout):**
      
      ```css
      blockquote {
        width: 120%; /* overflows container randomly */
      }
      ```
      
      **Correct (intentional grid break with structure):**
      
      ```css
      .article {
        max-width: 65ch;
        margin: 0 auto;
      }
      
      /* Pull quote breaks the grid intentionally */
      .pull-quote {
        max-width: 85ch;
        margin: 3rem -5rem;
        padding: 2rem;
        font-size: 1.5em;
        line-height: 1.35;
        font-style: italic;
        border-left: 3px solid var(--accent);
      }
      
      /* Full-bleed image breaks the grid */
      .full-bleed {
        width: 100vw;
        margin-left: calc(-50vw + 50%);
      }
      
      @media (max-width: 768px) {
        .pull-quote {
          margin: 2rem 0;
        }
      }
      ```
      
      Allow grid deviations only when they serve the content. Use whitespace as a design element.
      
    • display-headline-opentype.md 1.1 KB
      ---
      title: Enable Extra OpenType Features for Headlines
      impact: LOW-MEDIUM
      tags: opentype, headlines, dlig, swsh, display
      ---
      
      ## Enable Extra OpenType Features for Headlines
      
      Headlines benefit from OpenType features that distract in body text. On display sizes, add discretionary ligatures (`dlig`) and swashes (`swsh`) to the standard body set (`kern`, `liga`, `clig`, `calt`).
      
      **Incorrect (display face stuck on the body feature set):**
      
      ```css
      body, h1, h2 {
        font-feature-settings: "kern", "liga", "clig", "calt";
        /* Headlines never show the dlig/swsh glyphs the display font ships */
      }
      ```
      
      **Correct (extended feature set on headlines only):**
      
      ```css
      body {
        font-feature-settings: "kern", "liga", "clig", "calt";
      }
      
      h1, h2 {
        font-feature-settings: "kern", "liga", "clig", "calt", "dlig", "swsh";
      }
      ```
      
      Enable swashes on specific letters when the font indexes swash variants:
      
      ```css
      .headline .decorative-letter {
        font-feature-settings: "swsh" 2; /* second swash variant */
      }
      ```
      
      Only enable features the font supports: unsupported tags are silently ignored but add CSS weight. Never apply `dlig`/`swsh` to body text; they hurt sustained reading.
      
    • display-headline-spacing.md 1 KB
      ---
      title: Tighten Spacing for Large Headlines
      impact: MEDIUM
      tags: headlines, tracking, line-height, negative-leading, display
      ---
      
      ## Tighten Spacing for Large Headlines
      
      Large display text needs tighter line height and letter-spacing than body text. At 48px+, the default line height creates excessive vertical gaps, and default tracking feels too loose.
      
      Display cuts may need less tracking adjustment than text cuts used at large sizes.
      
      **Incorrect (body line-height applied to headlines):**
      
      ```css
      h1 {
        font-size: 64px;
        line-height: 1.5; /* way too much space between lines */
      }
      ```
      
      **Correct (tightened for display):**
      
      ```css
      h1 {
        font-size: 64px;
        line-height: 1.05;
        letter-spacing: -0.02em;
      }
      
      /* Responsive scaling */
      @media (max-width: 768px) {
        h1 {
          font-size: 36px;
          line-height: 1.15;
          letter-spacing: -0.01em;
        }
      }
      ```
      
      Use negative letter-spacing carefully. Test multi-line headlines to ensure letters do not overlap or collide. Descenders on one line should not touch ascenders on the next.
      
    • display-large-type.md 1 KB
      ---
      title: Use Large Type as a Design Element
      impact: LOW-MEDIUM
      tags: large-type, display, hero, design-element
      ---
      
      ## Use Large Type as a Design Element
      
      Huge type can anchor a design. If you load a web font, show it at large sizes where its character is most visible: small web fonts are indistinguishable from system fonts and waste bandwidth. Large letters can also be screened back and layered as abstract background elements.
      
      **Incorrect (web font only at body size):**
      
      ```css
      body {
        font-family: 'Playfair Display', serif;
        font-size: 16px;
        /* Wasting a beautiful display face at tiny size */
      }
      ```
      
      **Correct (web font showcased at large size):**
      
      ```css
      .hero-headline {
        font-family: 'Playfair Display', serif;
        font-size: clamp(3rem, 8vw, 8rem);
        line-height: 1.05;
        letter-spacing: -0.02em;
      }
      
      body {
        font-family: 'Source Serif Pro', serif; /* text face for body */
        font-size: 18px;
      }
      ```
      
      On small screens, tone down huge type so readers don't scroll three screen-heights through one headline.
      
    • display-lead-paragraph.md 1 KB
      ---
      title: Style a Lead Paragraph
      impact: LOW-MEDIUM
      tags: lead, lede, introduction, editorial, first-paragraph
      ---
      
      ## Style a Lead Paragraph
      
      A lead (lede) is an article's opening paragraph, styled larger, lighter, or in a different typeface to draw readers in. Keep it short (1-3 sentences); it bridges the headline and the body.
      
      **Incorrect (no lead, body starts abruptly):**
      
      ```html
      <h1>The Art of Typography</h1>
      <p>Typography is the art and technique of arranging type...</p>
      <!-- Same size as every other paragraph -->
      ```
      
      **Correct (styled lead paragraph):**
      
      ```css
      .article > p:first-of-type {
        font-size: 1.25em;
        line-height: 1.5;
        color: var(--text-secondary);
      }
      ```
      
      ```html
      <h1>The Art of Typography</h1>
      <p>Good typography is invisible. The reader should never notice the type,
      only the content it conveys.</p>
      <p>Typography is the art and technique of arranging type...</p>
      ```
      
      The lead may also differ in color; after it, transition into body text with initial small caps or a drop cap for polish.
      
    • display-swashes.md 892 B
      ---
      title: Use Swashes and Alternates Sparingly
      impact: LOW-MEDIUM
      tags: swashes, stylistic-alternates, logos, display
      ---
      
      ## Use Swashes and Alternates Sparingly
      
      Swashes and stylistic alternates add flair to logos and display text but distract in body copy. Apply them to specific letters for memorability. Find swashes in italic variants or separate font files.
      
      **Incorrect (swashes enabled globally):**
      
      ```css
      body {
        font-feature-settings: "swsh", "salt"; /* swashes in body text */
      }
      ```
      
      **Correct (swashes only on display elements):**
      
      ```css
      body {
        font-feature-settings: "kern", "liga", "calt";
      }
      
      .logo {
        font-feature-settings: "kern", "liga", "swsh";
      }
      
      /* Enable swash on a specific letter */
      .logo .initial {
        font-feature-settings: "swsh" 1;
      }
      ```
      
      `font-feature-settings: "ss01"` through `"ss20"` access numbered stylistic sets (curated alternate glyph collections).
      
    • font-body-selection.md 1.1 KB
      ---
      title: Choose Body Fonts for Legibility
      impact: HIGH
      tags: body-text, x-height, apertures, counters, contrast
      ---
      
      ## Choose Body Fonts for Legibility
      
      Select body fonts with low stroke contrast, large x-height, open apertures, and large counters; these maximize readability at small sizes. Prefer text-cut faces. Avoid overly large x-heights, which flatten the distinction between ascenders and descenders.
      
      Humanist and modern sans-serifs work well if they meet these traits; geometric sans-serifs are generally weaker for body.
      
      **Incorrect (display face used for body):**
      
      ```css
      body {
        font-family: 'Playfair Display', serif; /* high contrast, display face */
        font-size: 16px;
      }
      ```
      
      **Correct (text-optimized face for body):**
      
      ```css
      body {
        font-family: 'Source Serif Pro', serif; /* low contrast, large x-height */
        font-size: 18px;
      }
      ```
      
      Qualities to evaluate:
      - **Low stroke contrast**: even thickness across strokes
      - **Large x-height**: tall lowercase relative to capitals
      - **Open apertures**: wide openings in c, e, s
      - **Large counters**: spacious enclosed areas in o, d, b
      
    • font-condensed-extended.md 1.6 KB
      ---
      title: Change Width with Real Faces, Never Distortion
      impact: HIGH
      tags: condensed, extended, width, distortion, font-stretch
      ---
      
      ## Change Width with Real Faces, Never Distortion
      
      Never stretch, squish, or skew type with CSS transforms or width hacks; distortion destroys the designed stroke proportions, thinning verticals and thickening horizontals. Need narrower or wider text? Use a condensed or extended cut, or a variable font's width axis. Use condensed faces for headlines and tight UI labels (navigation, badges, tags) where you control line breaks, never for body copy: narrow letterforms cut readability at small sizes. Extended cuts are rarely needed but work for stylistic effect at large sizes.
      
      **Incorrect (CSS distortion, or condensed used for body):**
      
      ```css
      h1 {
        font-family: 'Inter', sans-serif;
        transform: scaleX(0.8); /* squished, stroke weights now uneven */
      }
      
      body {
        font-family: 'Roboto Condensed', sans-serif;
        font-size: 16px; /* narrow letterforms at reading size */
      }
      ```
      
      **Correct (real width variants):**
      
      ```css
      body {
        font-family: 'Roboto', sans-serif;
        font-size: 18px;
      }
      
      h1 {
        font-family: 'Roboto Condensed', sans-serif;
        font-size: 48px;
        letter-spacing: -0.01em;
      }
      
      /* Or a variable font's width axis */
      h1 {
        font-family: 'Inter VF', sans-serif;
        font-stretch: 85%; /* real condensed rendering */
      }
      ```
      
      Exception: deliberate distortion inside a logo, as an explicit design choice on a fixed piece of artwork. Re-tune size, line height, letter-spacing, and padding after any width swap; a metrically compatible replacement swaps in more easily but still needs the pass.
      
    • font-face-setup.md 1.2 KB
      ---
      title: Correct @font-face Declarations
      impact: CRITICAL
      tags: font-face, css, web-fonts, font-loading
      ---
      
      ## Correct @font-face Declarations
      
      Each `@font-face` declaration must map to the same `font-family` name with distinct `font-weight` and `font-style` values. This lets the browser automatically select the correct font file when CSS applies `font-weight: bold` or `font-style: italic`.
      
      **Incorrect (separate family names per weight):**
      
      ```css
      @font-face {
        font-family: 'MyFont-Regular';
        src: url('/fonts/MyFont-Regular.woff2') format('woff2');
      }
      @font-face {
        font-family: 'MyFont-Bold';
        src: url('/fonts/MyFont-Bold.woff2') format('woff2');
      }
      
      h1 { font-family: 'MyFont-Bold'; }  /* manual switching */
      p { font-family: 'MyFont-Regular'; }
      ```
      
      **Correct (single family, weight/style differentiated):**
      
      ```css
      @font-face {
        font-family: 'MyFont';
        font-weight: 400;
        font-style: normal;
        src: url('/fonts/MyFont-Regular.woff2') format('woff2');
      }
      @font-face {
        font-family: 'MyFont';
        font-weight: 700;
        font-style: normal;
        src: url('/fonts/MyFont-Bold.woff2') format('woff2');
      }
      
      body { font-family: 'MyFont', sans-serif; }
      h1 { font-weight: 700; }  /* browser selects correct file */
      p { font-weight: 400; }
      ```
      
    • font-fallbacks.md 1.1 KB
      ---
      title: Define Strong Fallback Font Stacks
      impact: CRITICAL
      tags: fallback, font-stack, system-fonts, glyphs
      ---
      
      ## Define Strong Fallback Font Stacks
      
      Every `font-family` declaration needs a carefully chosen fallback stack. Include likely-installed system fonts that match the primary font's metrics and style. Test with fallbacks active to catch layout shifts. Ensure accent and special character support.
      
      **Incorrect (no meaningful fallback):**
      
      ```css
      body {
        font-family: 'Libre Baskerville';
      }
      ```
      
      **Correct (robust fallback stack):**
      
      ```css
      body {
        font-family: 'Libre Baskerville', 'Georgia', 'Times New Roman', serif;
      }
      
      /* Sans-serif example */
      h1 {
        font-family: 'Inter', 'Helvetica Neue', 'Arial', sans-serif;
      }
      ```
      
      Use `size-adjust`, `ascent-override`, and `descent-override` in `@font-face` for fallbacks to minimize layout shift (CLS):
      
      ```css
      @font-face {
        font-family: 'Inter Fallback';
        src: local('Arial');
        size-adjust: 107%;
        ascent-override: 90%;
        descent-override: 22%;
      }
      ```
      
      Avoid over-subsetting fonts, which can cause empty glyph boxes for characters outside the subset range.
      
    • font-monospaced.md 839 B
      ---
      title: Reserve Monospaced Fonts for Short Blocks
      impact: MEDIUM-HIGH
      tags: monospace, code, body-text, readability
      ---
      
      ## Reserve Monospaced Fonts for Short Blocks
      
      Monospaced fonts reduce readability in long text: uniform letter widths disrupt reading rhythm. Use them only for code blocks, terminal output, and short stylistic elements. Never set body copy in a monospaced face.
      
      **Incorrect (monospace for body text):**
      
      ```css
      body {
        font-family: 'Fira Mono', monospace;
        font-size: 16px;
      }
      ```
      
      **Correct (proportional for body, mono for code):**
      
      ```css
      body {
        font-family: 'Inter', sans-serif;
        font-size: 18px;
      }
      
      code, pre {
        font-family: 'Fira Code', 'Fira Mono', monospace;
        font-size: 0.9em;
      }
      ```
      
      Brief monospaced sections (a stylistic data readout, a hero element) are fine as a design choice; keep them short.
      
    • font-optical-sizes.md 1.6 KB
      ---
      title: Use Text and Display Optical Sizes Correctly
      impact: MEDIUM-HIGH
      tags: optical-size, display, text, caption, font-selection
      ---
      
      ## Use Text and Display Optical Sizes Correctly
      
      Many families ship optical-size variants, named Text, Display, Banner, Headline, Poster, Titling, or Caption, each tuned to a size range. Display cuts have finer details, tighter spacing, and higher contrast for large sizes. Text cuts have more open spacing, a larger x-height, and lower contrast for body readability.
      
      Never use a Display, Banner, Headline, Poster, or Titling cut for body copy: the fine details disappear and the tight spacing closes up. Never use a Caption cut for web body text; it is drawn for very small print sizes. The reverse also shows: a text cut at 72px looks clunky and loose.
      
      **Incorrect (display cut used at body size):**
      
      ```css
      body {
        font-family: 'Garamond Display', serif; /* designed for 24px+ */
        font-size: 16px; /* too small for a display cut */
      }
      ```
      
      **Correct (text cut for body, display cut for headings):**
      
      ```css
      body {
        font-family: 'Garamond Text', serif; /* optimized for 12-18px */
        font-size: 18px;
      }
      
      h1 {
        font-family: 'Garamond Display', serif; /* optimized for 24px+ */
        font-size: 48px;
      }
      ```
      
      Variable fonts with an `opsz` axis handle this automatically:
      
      ```css
      body {
        font-family: 'Garamond VF', serif;
        font-optical-sizing: auto; /* browser adjusts based on font-size */
      }
      ```
      
      A display cut also wants a richer OpenType feature set than body text; see `display-headline-opentype`. For swapping a display face out at small breakpoints, see `size-responsive`.
      
    • font-quality.md 1.3 KB
      ---
      title: Evaluate Font Quality Before Use
      impact: MEDIUM
      tags: font-quality, kerning, licensing, sources
      ---
      
      ## Evaluate Font Quality Before Use
      
      Test a font's kerning with word samples before committing. Poor kerning (uneven letter spacing) signals low quality. Prefer reputable foundries and distributors; never use pirated fonts.
      
      **Incorrect (unvetted free font from an aggregator):**
      
      ```css
      @font-face {
        font-family: 'CoolFreeFont';
        /* Downloaded from a free-fonts aggregator: no kerning pairs,
           missing accents and figure styles, unknown license */
        src: url('/fonts/coolfreefont.woff2') format('woff2');
      }
      ```
      
      **Correct (vetted face from a reputable source):**
      
      ```css
      @font-face {
        font-family: 'Source Serif 4';
        /* Adobe-designed, SIL OFL: full kerning, complete glyph set,
           verified at https://fonts.google.com */
        src: url('/fonts/SourceSerif4-Variable.woff2') format('woff2');
      }
      ```
      
      **How to evaluate:**
      
      1. Set it in body text; look for uneven spacing in pairs like T+y, A+V, W+a
      2. Check punctuation positioning relative to letters
      3. Verify all needed glyphs (accents, special characters, figure styles)
      4. Confirm the license covers web use
      
      Reputable sources, commercial: Adobe Fonts, Hoefler&Co, Commercial Type, Klim, Grilli Type; open source: Google Fonts, Font Squirrel (with verification), fonts.bunny.net; variable fonts: v-fonts.com.
      
    • font-rendering.md 966 B
      ---
      title: Apply Antialiased Font Smoothing on macOS
      impact: MEDIUM
      tags: font-smoothing, antialiased, webkit, rendering, macOS
      ---
      
      ## Apply Antialiased Font Smoothing on macOS
      
      macOS browsers default to subpixel antialiasing, rendering text heavier than intended. `-webkit-font-smoothing: antialiased` switches to grayscale antialiasing for thinner, crisper text, most visible on light-on-dark surfaces and small sizes.
      
      Apply it once at the outermost layout element (`<body>` or root layout wrapper) so all text inherits it; per-component use renders inconsistently.
      
      **Incorrect (applied per-component or not at all):**
      
      ```css
      .button {
        -webkit-font-smoothing: antialiased; /* inconsistent: only buttons get crisp text */
      }
      ```
      
      **Correct (applied at root):**
      
      ```css
      body {
        -webkit-font-smoothing: antialiased;
      }
      ```
      
      **Tailwind:**
      
      ```html
      <body class="antialiased">
      ```
      
      macOS-only: no effect on Windows or Linux, so it is safe to apply unconditionally.
      
    • font-true-styles.md 2 KB
      ---
      title: Load Real Italic and Bold Styles
      impact: CRITICAL
      tags: font-face, italic, bold, faux-styles, font-synthesis
      ---
      
      ## Load Real Italic and Bold Styles
      
      Load actual regular, italic, bold, and bold-italic files so the browser never synthesizes styles. Faux italic mechanically slants the roman instead of using redesigned letterforms; faux bold smears artificial weight onto the outline; faux small caps shrink uppercase into thin, unbalanced glyphs. Confirm a real italic by its letterforms: a, e, f, and g change shape, they do not just lean.
      
      Prefer true italics over obliques (slanted roman). Use WOFF2; consider variable fonts to cut file count.
      
      **Incorrect (single font file, browser synthesizes styles):**
      
      ```css
      @font-face {
        font-family: 'MyFont';
        src: url('/fonts/MyFont-Regular.woff2') format('woff2');
      }
      
      /* Browser fakes both */
      em { font-style: italic; }
      strong { font-weight: bold; }
      ```
      
      **Correct (all four styles loaded explicitly):**
      
      ```css
      @font-face {
        font-family: 'MyFont';
        font-weight: 400;
        font-style: normal;
        src: url('/fonts/MyFont-Regular.woff2') format('woff2');
      }
      @font-face {
        font-family: 'MyFont';
        font-weight: 400;
        font-style: italic;
        src: url('/fonts/MyFont-Italic.woff2') format('woff2');
      }
      @font-face {
        font-family: 'MyFont';
        font-weight: 700;
        font-style: normal;
        src: url('/fonts/MyFont-Bold.woff2') format('woff2');
      }
      @font-face {
        font-family: 'MyFont';
        font-weight: 700;
        font-style: italic;
        src: url('/fonts/MyFont-BoldItalic.woff2') format('woff2');
      }
      ```
      
      If bandwidth is constrained, drop the least-used style (usually bold italic) rather than relying on faux rendering.
      
      `font-synthesis: none` surfaces missing style files, but do not ship it on `body`. It applies to fallback fonts too, so if the webfont fails to load, `<strong>` renders at regular weight and `<em>` renders upright: emphasis vanishes from the page. Keep it to a development build. Real small caps come from `font-variant-caps`, not from synthesis; see `opentype-small-caps`.
      
    • font-variable-fonts.md 1 KB
      ---
      title: Prefer WOFF2 and Variable Fonts
      impact: MEDIUM
      tags: woff2, variable-fonts, font-format, performance
      ---
      
      ## Prefer WOFF2 and Variable Fonts
      
      Make WOFF2 the primary web font format: best compression (30-50% smaller than WOFF). Variable fonts bundle multiple weights and styles in one file, cutting HTTP requests and total file size.
      
      **Incorrect (legacy formats, multiple files):**
      
      ```css
      @font-face {
        font-family: 'MyFont';
        font-weight: 400;
        src: url('/fonts/MyFont-Regular.ttf') format('truetype');
      }
      @font-face {
        font-family: 'MyFont';
        font-weight: 700;
        src: url('/fonts/MyFont-Bold.ttf') format('truetype');
      }
      ```
      
      **Correct (WOFF2 with variable font):**
      
      ```css
      @font-face {
        font-family: 'MyFont';
        font-weight: 100 900;
        font-style: normal;
        font-display: swap;
        src: url('/fonts/MyFont-Variable.woff2') format('woff2-variations');
      }
      
      body { font-weight: 400; }
      h1 { font-weight: 700; }
      .light { font-weight: 300; }
      ```
      
      Use `font-display: swap` to prevent invisible text during loading.
      
    • font-weight-body.md 973 B
      ---
      title: Use Appropriate Body Text Weight
      impact: HIGH
      tags: font-weight, body-text, legibility, thin-fonts
      ---
      
      ## Use Appropriate Body Text Weight
      
      Set body text weight to regular (400) or book/medium (500). Avoid ultra-light or thin weights for longform reading because they lack sufficient contrast against the background, especially on low-resolution screens. Use heavier weights only at large display sizes.
      
      Test rendering across platforms: fonts often appear thinner on macOS than on Windows.
      
      **Incorrect (ultra-light body text):**
      
      ```css
      body {
        font-family: 'Helvetica Neue', sans-serif;
        font-weight: 200; /* ultra-light, hard to read at body sizes */
        font-size: 16px;
      }
      ```
      
      **Correct (readable body weight):**
      
      ```css
      body {
        font-family: 'Helvetica Neue', sans-serif;
        font-weight: 400; /* regular weight for body */
        font-size: 18px;
      }
      
      /* Thin weights reserved for large display text */
      .hero-title {
        font-weight: 200;
        font-size: 72px;
      }
      ```
      
    • hierarchy-body-first.md 1.2 KB
      ---
      title: Start Layout with Body Text
      impact: MEDIUM
      tags: body-text, layout, design-process, hierarchy
      ---
      
      ## Start Layout with Body Text
      
      Begin every design with body text: typeface, size, line height, measure. All other type (headings, labels, captions) derives from it. Starting with headings or decorative type leaves body text feeling like an afterthought.
      
      **Incorrect (starting with the hero heading):**
      
      ```css
      /* Designed the flashy heading first */
      h1 {
        font-family: 'Playfair Display', serif;
        font-size: 72px;
      }
      
      /* Then tried to make body text work around it */
      body {
        font-family: Arial, sans-serif;  /* default, unconsidered */
        font-size: 14px;                 /* too small, squeezed in */
      }
      ```
      
      **Correct (body text first, headings derived):**
      
      ```css
      /* 1. Set body text foundation */
      body {
        font-family: 'Source Serif Pro', serif;
        font-size: 18px;
        line-height: 1.5;
        max-width: 65ch;
      }
      
      /* 2. Derive headings from body */
      h1 {
        font-family: 'Source Serif Pro', serif;
        font-size: 2.5rem;
        line-height: 1.15;
      }
      
      h2 { font-size: 1.75rem; }
      h3 { font-size: 1.25rem; }
      ```
      
      Edit copy for clarity and remove redundant UI text; good typography starts with well-written content.
      
    • hierarchy-caps-subheads.md 900 B
      ---
      title: Use Letterspaced Caps for Subheadings
      impact: LOW-MEDIUM
      tags: subheadings, uppercase, small-caps, letterspacing, hierarchy
      ---
      
      ## Use Letterspaced Caps for Subheadings
      
      Letterspaced uppercase or small caps work well for subheadings and labels. Size caps down slightly to avoid shouting (uppercase at body size feels too loud). Small caps with slight tracking make an elegant secondary heading level.
      
      **Incorrect (full-size uppercase, no spacing):**
      
      ```css
      .subhead {
        text-transform: uppercase;
        font-size: 18px;  /* same as body, feels aggressive */
      }
      ```
      
      **Correct (sized down, tracked uppercase):**
      
      ```css
      .subhead {
        text-transform: uppercase;
        font-size: 0.75rem;
        letter-spacing: 0.1em;
        font-weight: 600;
        color: var(--text-secondary);
      }
      
      /* Or small caps variant */
      .subhead-sc {
        font-variant-caps: all-small-caps;
        letter-spacing: 0.05em;
        font-size: 1rem;
      }
      ```
      
    • hierarchy-consistent-system.md 1.2 KB
      ---
      title: Define and Document a Type System
      impact: MEDIUM-HIGH
      tags: type-system, consistency, design-tokens, documentation
      ---
      
      ## Define and Document a Type System
      
      Define a consistent set of type styles (sizes, weights, line-heights, colors) and apply them uniformly; avoid one-off changes. Document it so contributors follow, and enforce with CSS custom properties or design tokens.
      
      **Incorrect (ad hoc styling throughout):**
      
      ```css
      .page-a h2 { font-size: 28px; font-weight: 700; }
      .page-b h2 { font-size: 24px; font-weight: 600; }  /* different from page-a */
      .page-c h2 { font-size: 30px; font-weight: 800; }  /* different again */
      ```
      
      **Correct (systematic type scale):**
      
      ```css
      :root {
        --font-body: 'Inter', sans-serif;
        --font-heading: 'Inter', sans-serif;
      
        --text-sm: 0.875rem;
        --text-base: 1rem;
        --text-lg: 1.25rem;
        --text-xl: 1.5rem;
        --text-2xl: 2rem;
        --text-3xl: 2.5rem;
      
        --leading-tight: 1.2;
        --leading-normal: 1.5;
      }
      
      h2 {
        font-family: var(--font-heading);
        font-size: var(--text-2xl);
        line-height: var(--leading-tight);
        font-weight: 700;
      }
      ```
      
      Don't obsess over baseline grids on the web. Prioritize consistent font size, line height, and line length over pixel-perfect vertical alignment; accept web fluidity.
      
    • hierarchy-heading-color.md 1 KB
      ---
      title: Lighten Headings as They Grow
      impact: MEDIUM
      tags: headings, color, weight, large-type, balance
      ---
      
      ## Lighten Headings as They Grow
      
      As headings grow, reduce weight or lighten color to keep balance: a 48px bold heading feels overwhelming. Prefer darkened brand hues over flat gray, which looks lifeless.
      
      **Incorrect (heavy weight at all sizes):**
      
      ```css
      h1 { font-size: 48px; font-weight: 900; color: #000; }
      h2 { font-size: 32px; font-weight: 900; color: #000; }
      h3 { font-size: 24px; font-weight: 900; color: #000; }
      ```
      
      **Correct (progressive lightening):**
      
      ```css
      h1 {
        font-size: 48px;
        font-weight: 400;    /* lighter weight at large size */
        color: #1a1a2e;      /* slightly tinted, not pure black */
      }
      
      h2 {
        font-size: 32px;
        font-weight: 600;
      }
      
      h3 {
        font-size: 24px;
        font-weight: 700;
      }
      ```
      
      Lighten weight before lightening color. A lower weight at 48px keeps full contrast, while a lighter color spends contrast the reader needs; heading text still has to clear the WCAG floor (see `brand-color`).
      
    • hierarchy-heading-levels.md 1 KB
      ---
      title: Keep Heading Levels Shallow and Descriptive
      impact: MEDIUM-HIGH
      tags: headings, h1, h2, h3, semantic, skimmable
      ---
      
      ## Keep Heading Levels Shallow and Descriptive
      
      Limit heading depth to h1–h3 in most contexts. Deeper levels (h4–h6) often indicate content that should be restructured. Write descriptive, skimmable headings that tell the reader what the section contains, not generic labels.
      
      Avoid all-italic headings; they feel weak at heading sizes.
      
      **Incorrect (deep nesting, generic headings):**
      
      ```html
      <h1>Documentation</h1>
      <h2>Getting Started</h2>
      <h3>Prerequisites</h3>
      <h4>System Requirements</h4>
      <h5>Minimum Specifications</h5>  <!-- too deep -->
      <h6>Processor</h6>              <!-- way too deep -->
      ```
      
      **Correct (shallow, descriptive headings):**
      
      ```html
      <h1>Documentation</h1>
      <h2>Install on macOS, Linux, or Windows</h2>
      <h3>System requirements</h3>
      <!-- Restructure deeper content as lists or prose -->
      ```
      
      Use `text-transform: uppercase` or `text-transform: capitalize` in CSS rather than typing headings in all caps in the HTML.
      
    • hierarchy-modular-scale.md 1.2 KB
      ---
      title: Use a Modular Scale as a Guide, Not a Constraint
      impact: MEDIUM
      tags: modular-scale, type-scale, sizing, hierarchy
      ---
      
      ## Use a Modular Scale as a Guide, Not a Constraint
      
      A modular scale (e.g., 1.25, 1.333, 1.5 ratios) gives a starting set of harmonious sizes, but it's a guide, not a rule. If a size feels optically wrong for the typeface, break the scale: typefaces have sweet spots where they look best; use those sizes even when they fall outside the scale.
      
      **Incorrect (rigid adherence to scale despite optical issues):**
      
      ```css
      /* Scale: 1.25 ratio */
      :root {
        --text-sm: 12.8px;  /* scale says 12.8, but 13px reads better */
        --text-base: 16px;
        --text-lg: 20px;
        --text-xl: 25px;    /* scale says 25, but 24px pairs better */
      }
      ```
      
      **Correct (scale as starting point, optical adjustments):**
      
      ```css
      :root {
        --text-sm: 13px;    /* rounded for readability */
        --text-base: 18px;  /* typeface sweet spot */
        --text-lg: 20px;
        --text-xl: 24px;    /* optically balanced with body */
        --text-2xl: 32px;
        --text-3xl: 48px;
      }
      ```
      
      Store the resolved sizes as tokens rather than computing the ratio in CSS. The whole point of the rule is that some steps deviate from the ratio, and a `calc()` chain cannot hold a deviation.
      
    • hierarchy-size-contrast.md 951 B
      ---
      title: Ensure Strong Size Contrast Between Levels
      impact: MEDIUM-HIGH
      tags: size-contrast, hierarchy, headings, near-equal
      ---
      
      ## Ensure Strong Size Contrast Between Levels
      
      When two elements have different roles, make their sizes clearly different. Near-equal sizes (e.g., 16px and 18px) read as ambiguous: the reader cannot tell which ranks higher. Sizes should be either identical (same role) or noticeably different (different levels).
      
      **Incorrect (ambiguous near-equal sizes):**
      
      ```css
      h2 { font-size: 20px; }
      h3 { font-size: 18px; }  /* barely different from h2 */
      p  { font-size: 16px; }  /* barely different from h3 */
      ```
      
      **Correct (clear size jumps between levels):**
      
      ```css
      h2 { font-size: 28px; }
      h3 { font-size: 20px; }  /* clearly smaller than h2 */
      p  { font-size: 18px; }  /* clearly body text */
      ```
      
      Use at least a 20 to 25% size jump between adjacent levels. If size alone cannot differentiate, add weight, color, or caps.
      
    • hierarchy-weight-contrast.md 1016 B
      ---
      title: Build Hierarchy with Multiple Axes
      impact: MEDIUM
      tags: hierarchy, weight, italics, caps, color, contrast
      ---
      
      ## Build Hierarchy with Multiple Axes
      
      Build hierarchy with weight, italics, caps, color, and size, but change one axis at a time. Stacking changes (bold + large + colored + caps) creates noise, not hierarchy.
      
      **Incorrect (too many changes at once):**
      
      ```css
      h2 {
        font-size: 32px;
        font-weight: 900;
        text-transform: uppercase;
        letter-spacing: 0.1em;
        color: #ff0000;
        /* five axes changed simultaneously */
      }
      ```
      
      **Correct (one or two axes per level):**
      
      ```css
      /* Size + weight for primary heading */
      h2 {
        font-size: 28px;
        font-weight: 700;
      }
      
      /* Size + caps for section label */
      .section-label {
        font-size: 14px;
        text-transform: uppercase;
        letter-spacing: 0.1em;
      }
      
      /* Style for inline emphasis */
      .aside-note {
        font-style: italic;
        color: var(--text-secondary);
      }
      ```
      
      Build incrementally: start with size, then add weight, then caps or color for specific elements.
      
    • layout-center-alignment.md 959 B
      ---
      title: Center-Align Text Sparingly
      impact: MEDIUM-HIGH
      tags: text-align, center, alignment, readability
      ---
      
      ## Center-Align Text Sparingly
      
      Center-aligned text disrupts the left reading edge that anchors the reader's eye. Use it only for intentional formal or display contexts: invitations, short hero text, or single-line captions. Never center-align more than a few lines.
      
      When centering text, increase line height slightly to compensate for the ragged edges on both sides.
      
      **Incorrect (centered body paragraphs):**
      
      ```css
      .article p {
        text-align: center; /* hard to read at paragraph length */
      }
      ```
      
      **Correct (centered for display only, left for prose):**
      
      ```css
      .article p {
        text-align: left;
      }
      
      .hero-tagline {
        text-align: center;
        line-height: 1.6; /* slightly more than normal */
        max-width: 40ch;  /* keep lines short */
        margin: 0 auto;
      }
      ```
      
      Avoid default `text-align: center` on containers that may hold paragraph-length text.
      
    • layout-justified-text.md 1 KB
      ---
      title: Avoid Justified Text on the Web
      impact: MEDIUM-HIGH
      tags: text-align, justified, hyphenation, rivers
      ---
      
      ## Avoid Justified Text on the Web
      
      Justified text creates rivers and uneven word spacing on the web, where hyphenation is inconsistent. Justify only with strong hyphenation (`hyphens: auto`) and a long enough measure. Never justify narrow columns. Never use letterspacing to fill justified lines: it produces grotesque spacing.
      
      **Incorrect (justified without hyphenation):**
      
      ```css
      .article {
        text-align: justify;
        /* no hyphenation: creates rivers and stretched words */
      }
      ```
      
      **Correct (left-aligned, or justified with hyphenation):**
      
      ```css
      /* Preferred: left-aligned */
      .article {
        text-align: left;
      }
      
      /* If justified, require hyphenation and adequate measure */
      .article-justified {
        text-align: justify;
        hyphens: auto;
        -webkit-hyphens: auto;
        max-width: 65ch; /* ensure long lines for justification to work */
      }
      ```
      
      Browser hyphenation depends on language dictionaries: set `lang` on `<html>` and test thoroughly.
      
    • layout-lists.md 1.5 KB
      ---
      title: Format Lists with Proper Markup and Spacing
      impact: MEDIUM
      tags: lists, ul, ol, bullets, hanging, vertical-spacing
      ---
      
      ## Format Lists with Proper Markup and Spacing
      
      Use semantic `<ul>` or `<ol>` elements, never paragraphs with typed dashes. Keep `list-style-position: outside`: `inside` wraps continuation lines under the bullet and destroys the left text edge. Add vertical spacing between items so a wrapped line stays visually grouped with its own bullet.
      
      **Incorrect (fake list, inside positioning):**
      
      ```html
      <p>- First item that is long enough to wrap onto a second line which
      goes under the bullet</p>
      <p>- Second item</p>
      ```
      
      ```css
      ul {
        list-style-position: inside; /* wrapped lines sit under the bullet */
      }
      ```
      
      **Correct (semantic markup, outside positioning, spaced items):**
      
      ```html
      <ul>
        <li>First item that is long enough to wrap onto a second line, which
        stays indented from the bullet.</li>
        <li>Second item</li>
      </ul>
      ```
      
      ```css
      /* Indented bullets: text indented from the left edge (safer web default) */
      ul {
        list-style-position: outside;
        padding-left: 1.5em;
      }
      
      li {
        margin-bottom: 0.5em;
      }
      
      /* Hanging bullets: bullets sit in the margin, print-like */
      ul.hanging {
        list-style-position: outside;
        padding-left: 0;
        margin-left: 1em;
      }
      ```
      
      Prefer indented bullets on the web and avoid hanging bullets on mobile, where the margin space they need does not exist. Test long content at narrow viewports: if item titles wrap, increase vertical spacing between items and tighten line height so wrapped lines stay grouped.
      
    • layout-optical-balance.md 995 B
      ---
      title: Balance Layouts Optically
      impact: LOW-MEDIUM
      tags: optical-centering, visual-balance, alignment, overshoot
      ---
      
      ## Balance Layouts Optically
      
      Optically center elements slightly above true mathematical center: the eye reads the geometric center as too low. Account for overshoot in round and pointed shapes (an "O" must extend slightly past baseline and cap height to look the same size as flat letters). Trust your eye over measurements.
      
      **Incorrect (mathematically centered, looks low):**
      
      ```css
      .modal {
        position: fixed;
        top: 50%;
        transform: translateY(-50%); /* looks like it sags */
      }
      ```
      
      **Correct (optically centered, slightly above midpoint):**
      
      ```css
      .modal {
        position: fixed;
        top: 45%; /* slightly above center */
        transform: translateY(-50%);
      }
      
      /* Or use padding bias */
      .card-icon {
        padding: 1rem 1rem 1.25rem 1rem; /* more bottom padding */
      }
      ```
      
      Applies to icons in buttons, text in cards, logos in headers, anywhere visual centering beats pixel math.
      
    • layout-proximity-dividers.md 1.1 KB
      ---
      title: Use Proximity and Dividers to Clarify Associations
      impact: MEDIUM
      tags: proximity, dividers, rules, captions, headings
      ---
      
      ## Use Proximity and Dividers to Clarify Associations
      
      Place captions and descriptions close to the images or elements they describe. Use dividers (horizontal rules) to separate unrelated sections, placing them above headings, not below: a divider below a heading underlines it (a Victorian convention) and weakens its link to the content.
      
      **Incorrect (divider below heading, caption far from image):**
      
      ```html
      <h2>Our Process</h2>
      <hr>  <!-- separates heading from its content -->
      <p>We follow a three-step approach...</p>
      
      <img src="photo.jpg" alt="Team meeting">
      
      <p class="caption">The team during a strategy session.</p>
      <!-- Caption is far from image if other content intervenes -->
      ```
      
      **Correct (divider above heading, caption adjacent to image):**
      
      ```html
      <hr>  <!-- separates from previous section -->
      <h2>Our Process</h2>
      <p>We follow a three-step approach...</p>
      
      <figure>
        <img src="photo.jpg" alt="Team meeting">
        <figcaption>The team during a strategy session.</figcaption>
      </figure>
      ```
      
    • layout-widows-orphans.md 1.5 KB
      ---
      title: Manage Widows and Orphans with Non-Breaking Spaces
      impact: LOW-MEDIUM
      tags: widows, orphans, non-breaking-space, headlines, nowrap
      ---
      
      ## Manage Widows and Orphans with Non-Breaking Spaces
      
      A single word dangling on a headline's last line looks awkward. Insert a non-breaking space (`&nbsp;`) between the last two words of headlines and nav items. Use `white-space: nowrap` sparingly for short phrases.
      
      On body paragraphs, accept imperfection: dynamic content and responsive design make full widow/orphan control impractical.
      
      **Incorrect (headline with a dangling word):**
      
      ```html
      <h1>Getting Started with Web
      Typography</h1>
      <!-- "Typography" sits alone on the second line -->
      ```
      
      **Correct (non-breaking space prevents break):**
      
      ```html
      <h1>Getting Started with Web&nbsp;Typography</h1>
      ```
      
      Also use `&nbsp;` for:
      - Navigation items: `About&nbsp;Us`
      - Time expressions: `3:00&nbsp;PM`
      - Brand names: `New&nbsp;York`
      - Short phrases on homepage hero text
      
      CSS `text-wrap` also helps, and it is Baseline since October 2024. Use `balance` for headings and short UI copy (distributes text evenly across lines) and `pretty` for body paragraphs (avoids orphaned last words by adjusting only the final lines). `balance` silently stops applying past 6 lines in Chromium and 10 in Firefox, so it is a heading tool, not a paragraph one; `pretty` costs layout performance, so keep it off short strings where it buys nothing.
      
      ```css
      h1, h2, h3 {
        text-wrap: balance;
      }
      
      p {
        text-wrap: pretty;
      }
      ```
      
    • opentype-body-features.md 1 KB
      ---
      title: Enable Standard OpenType Features for Body
      impact: MEDIUM
      tags: font-feature-settings, kern, liga, calt, opentype
      ---
      
      ## Enable Standard OpenType Features for Body
      
      Enable four OpenType features on body text: `kern` (kerning), `liga` (standard ligatures), `clig` (contextual ligatures), `calt` (contextual alternates). They improve letter spacing and glyph substitution automatically.
      
      **Incorrect (default browser settings, features may be off):**
      
      ```css
      body {
        font-family: 'Source Serif Pro', serif;
        /* relies on browser defaults */
      }
      ```
      
      **Correct (explicit OpenType features enabled):**
      
      ```css
      body {
        font-family: 'Source Serif Pro', serif;
        font-kerning: normal;
        font-feature-settings: "kern", "liga", "clig", "calt";
      }
      ```
      
      Modern CSS alternative using individual properties:
      
      ```css
      body {
        font-kerning: normal;
        font-variant-ligatures: common-ligatures contextual;
      }
      ```
      
      Browsers enable `kern` and `liga` by default; explicit declarations ensure consistent behavior across browsers and font configs.
      
    • opentype-kerning.md 1.2 KB
      ---
      title: Use Metrics Kerning, Adjust Tracking First
      impact: MEDIUM
      tags: kerning, tracking, metrics, optical, letter-spacing
      ---
      
      ## Use Metrics Kerning, Adjust Tracking First
      
      Use the font's built-in kern tables (metrics kerning), not optical kerning: quality fonts ship crafted kern pairs. Adjust overall tracking (letter-spacing) before individual pairs. Reserve manual kerning for large display type and logos.
      
      **Incorrect (optical kerning or excessive manual adjustment):**
      
      ```css
      body {
        font-kerning: auto; /* may not use metrics */
      }
      
      /* Over-kerning body text */
      body {
        letter-spacing: -0.02em;
      }
      ```
      
      **Correct (metrics kerning, tracking adjustments before kerning):**
      
      ```css
      body {
        font-kerning: normal; /* use font's built-in kern tables */
      }
      
      /* If large heading spacing feels off, adjust tracking first */
      h1 {
        letter-spacing: -0.02em; /* tracking adjustment */
      }
      
      /* Manual kerning only for logos/display (use spans) */
      .logo .letter-A { margin-right: -0.05em; }
      ```
      
      Use hair (`&hairsp;`) or thin (`&thinsp;`) spaces where spacing feels off but a full adjustment is too much. Accept minor kerning irregularities in body text; they are inherent to the Latin alphabet.
      
    • opentype-ligatures.md 1.1 KB
      ---
      title: Manage Ligatures by Context
      impact: MEDIUM-HIGH
      tags: ligatures, discretionary, standard, code, opentype
      ---
      
      ## Manage Ligatures by Context
      
      Enable standard ligatures (`liga`) in body text. Keep discretionary ligatures (`dlig`) off in body: they distract. Disable all ligatures in code blocks, where fi/fl/ffi ligatures obscure individual characters.
      
      **Incorrect (discretionary ligatures in body, ligatures in code):**
      
      ```css
      body {
        font-feature-settings: "liga", "dlig"; /* dlig distracting in body */
      }
      
      code {
        /* inherits ligatures, fi becomes a single glyph */
      }
      ```
      
      **Correct (standard only in body, none in code):**
      
      ```css
      body {
        font-feature-settings: "liga", "clig", "calt";
        /* no "dlig" in body text */
      }
      
      code, pre {
        font-variant-ligatures: none;
        font-feature-settings: "liga" 0, "clig" 0, "calt" 0;
      }
      
      /* Discretionary ligatures for headlines only */
      h1 {
        font-feature-settings: "liga", "dlig", "calt";
      }
      ```
      
      Standard ligatures: fi, fl, ffi, ffl (always appropriate in body).
      Discretionary ligatures: st, ct, decorative forms (headlines/display only).
      
    • opentype-monoscript-kerning.md 1.1 KB
      ---
      title: Do Not Adjust Spacing on Monospaced or Script Fonts
      impact: MEDIUM-HIGH
      tags: monospace, script, kerning, tracking, connected
      ---
      
      ## Do Not Adjust Spacing on Monospaced or Script Fonts
      
      Monospaced fonts require uniform character widths, so adjusting letter-spacing breaks their alignment purpose. Connected script fonts rely on precise glyph connections, so adding or removing space breaks the joins between letters.
      
      Keep spacing and kerning at the font's built-in metrics for both types.
      
      **Incorrect (letterspacing a monospaced or script font):**
      
      ```css
      code {
        font-family: 'Fira Code', monospace;
        letter-spacing: 0.05em; /* breaks column alignment */
      }
      
      .script-heading {
        font-family: 'Great Vibes', cursive;
        letter-spacing: 0.1em; /* breaks letter connections */
      }
      ```
      
      **Correct (use default spacing):**
      
      ```css
      code {
        font-family: 'Fira Code', monospace;
        letter-spacing: normal;
      }
      
      .script-heading {
        font-family: 'Great Vibes', cursive;
        letter-spacing: normal;
      }
      ```
      
      Do not apply optical kerning to these font types either. Use metrics kerning only.
      
    • opentype-oldstyle-figures.md 1.1 KB
      ---
      title: Use Oldstyle Figures in Running Text
      impact: LOW-MEDIUM
      tags: oldstyle-figures, onum, lnum, lining, numbers
      ---
      
      ## Use Oldstyle Figures in Running Text
      
      Oldstyle (lowercase) figures have ascenders and descenders, so they blend into body text. Use `onum` for running text; use lining figures (`lnum`) next to uppercase, in UI, and in headings where alignment matters.
      
      **Incorrect (lining figures disrupting body text flow):**
      
      ```css
      body {
        /* default lining figures stick up from the baseline */
      }
      ```
      
      ```html
      <p>The event attracted 1,247 attendees in 2024.</p>
      <!-- Lining "1,247" and "2024" look oversized in body text -->
      ```
      
      **Correct (oldstyle figures for body, lining for UI):**
      
      ```css
      body {
        font-variant-numeric: oldstyle-nums;
      }
      
      /* Or using font-feature-settings */
      body {
        font-feature-settings: "onum";
      }
      
      /* Lining figures for UI and headings */
      .btn, .heading, .table-cell {
        font-variant-numeric: lining-nums;
      }
      ```
      
      Optionally spell out one through nine in prose (style-guide dependent). Verify the font ships `onum` before enabling it; not all fonts include oldstyle figure glyphs.
      
    • opentype-small-caps.md 1.1 KB
      ---
      title: Use Real Small Caps, Not Pseudo
      impact: MEDIUM
      tags: small-caps, font-variant, opentype, abbreviations
      ---
      
      ## Use Real Small Caps, Not Pseudo
      
      Real small caps are designed glyphs whose proportions match lowercase letters. Pseudo small caps (shrunken uppercase) look thin and uneven. Enable real ones via `font-variant-caps` or `font-feature-settings`, with slight letter-spacing (0.05em). Use them for abbreviations (NASA, HTML) in running text and for subheadings.
      
      **Incorrect (pseudo small caps via font-size reduction):**
      
      ```css
      .abbr {
        font-size: 0.8em;
        text-transform: uppercase; /* fake small caps */
      }
      ```
      
      **Correct (real OpenType small caps):**
      
      ```css
      .abbr {
        font-variant-caps: all-small-caps;
        letter-spacing: 0.05em;
      }
      
      /* Or using font-feature-settings */
      .abbr {
        font-feature-settings: "smcp", "c2sc";
        letter-spacing: 0.05em;
      }
      ```
      
      Verify the font ships `smcp` (small caps from lowercase) and optionally `c2sc` (from uppercase); not all fonts include real small-cap glyphs. Without them the browser fakes small caps by shrinking uppercase, producing the same thin uneven result as doing it by hand.
      
    • opentype-tabular-figures.md 933 B
      ---
      title: Use Tabular Figures in Data Contexts
      impact: HIGH
      tags: tabular-figures, tnum, tables, alignment, numbers
      ---
      
      ## Use Tabular Figures in Data Contexts
      
      Use tabular (monospaced-width) figures wherever numbers align vertically: tables, price lists. Right-align number columns; use commas as thousands separators. Enable `tnum` via `font-feature-settings`, or pick a font with tabular figures by default.
      
      **Incorrect (proportional figures in a table):**
      
      ```css
      .price-table td {
        /* default proportional figures, numbers don't align */
        text-align: left;
      }
      ```
      
      **Correct (tabular figures, right-aligned):**
      
      ```css
      .price-table td.number {
        font-variant-numeric: tabular-nums;
        text-align: right;
      }
      
      /* Or using font-feature-settings */
      .price-table td.number {
        font-feature-settings: "tnum";
        text-align: right;
      }
      ```
      
      Fallback: if the font lacks tabular figures, use a monospaced or system font for data columns.
      
    • pairing-contrast-harmony.md 1.9 KB
      ---
      title: Pair by Contrast or Harmony, Never Similarity
      impact: MEDIUM
      tags: pairing, contrast, harmony, similarity, same-genre
      ---
      
      ## Pair by Contrast or Harmony, Never Similarity
      
      Typefaces should either harmonize (share structural qualities) or contrast strongly (differ clearly and intentionally). Almost-the-same pairs create tension without purpose, and two faces from one category are the usual cause: two neo-grotesques, or two serifs, read as an accident rather than a decision because the reader cannot tell the roles apart. Serif plus sans is the safe default, since it carries structural contrast for free.
      
      Judge harmony by comparing handwritten vs constructed feel, stress angles, and skeletal structures.
      
      **Incorrect (same category, neither matching nor contrasting):**
      
      ```css
      h1 { font-family: 'Helvetica', sans-serif; }
      body { font-family: 'Arial', sans-serif; }
      /* Both neo-grotesque, nearly identical: no contrast, no harmony */
      
      h1 { font-family: 'Bodoni', serif; }      /* modern serif, vertical stress */
      body { font-family: 'Garamond', serif; }   /* old-style serif, diagonal stress */
      /* Two serifs whose structural philosophies clash */
      ```
      
      **Correct (harmonious, shared calligraphic roots):**
      
      ```css
      h1 { font-family: 'Palatino', serif; }
      body { font-family: 'Optima', sans-serif; }
      /* Both have calligraphic influence and humanist proportions */
      ```
      
      **Correct (contrasting, clear structural difference):**
      
      ```css
      h1 { font-family: 'Futura', sans-serif; }   /* geometric */
      body { font-family: 'Baskerville', serif; }  /* transitional */
      ```
      
      Two faces from one category work only when their genres are distinctly different and their roles are distinct: a geometric sans over a humanist sans, a slab serif over an old-style body, or two cuts of one family (Freight Display over Freight Text). Never mix modern with old-style serifs. Faces by the same designer also tend to pair well, since designers reuse consistent principles.
      
    • pairing-limit-typefaces.md 983 B
      ---
      title: Limit to Two Typefaces
      impact: MEDIUM-HIGH
      tags: pairing, typeface-count, simplicity, system
      ---
      
      ## Limit to Two Typefaces
      
      Use at most two typefaces: one for body, one for display/headings. More faces add complexity and visual discord. If you need more, enforce a strict system with a clear role per face.
      
      **Incorrect (too many faces, no system):**
      
      ```css
      h1 { font-family: 'Playfair Display', serif; }
      h2 { font-family: 'Lora', serif; }
      h3 { font-family: 'Merriweather', serif; }  /* three serifs! */
      p { font-family: 'Open Sans', sans-serif; }
      .label { font-family: 'Roboto', sans-serif; } /* two sans! */
      ```
      
      **Correct (two typefaces with clear roles):**
      
      ```css
      :root {
        --font-heading: 'Playfair Display', serif;
        --font-body: 'Source Sans Pro', sans-serif;
      }
      
      h1, h2, h3 { font-family: var(--font-heading); }
      body { font-family: var(--font-body); }
      ```
      
      A single typeface with multiple weights can carry an entire project, especially a versatile superfamily.
      
    • pairing-stress-skeleton.md 2.2 KB
      ---
      title: Match Stress and Skeleton When Pairing
      impact: MEDIUM
      tags: stress, skeleton, pairing, genre, structure
      ---
      
      ## Match Stress and Skeleton When Pairing
      
      A typeface's stress angle (where the thickest part of curved strokes falls) and its skeleton (calligraphic vs constructed) predict compatibility. Pair within a group; crossing groups creates subtle but persistent visual tension.
      
      | Group | Stress and skeleton | Serifs | Sans |
      |-------|---------------------|--------|------|
      | Calligraphic | Diagonal, moderate contrast | Old-style: Garamond, Caslon, Jenson | Humanist: Gill Sans, Frutiger, Myriad, Optima |
      | Rational | Vertical, high contrast | Modern/Didone: Bodoni, Didot | Geometric: Futura, Avenir, Century Gothic |
      | Static | Vertical, low contrast | Transitional: Baskerville, Times, Georgia. Slab: Rockwell, Clarendon, Sentinel | Grotesque: Franklin Gothic, News Gothic, Trade Gothic. Neo-grotesque: Helvetica, Univers, Akzidenz-Grotesk |
      
      **Incorrect (crossed groups):**
      
      ```css
      h1 { font-family: 'Futura', sans-serif; }    /* rational, vertical stress */
      body { font-family: 'Garamond', serif; }      /* calligraphic, diagonal stress */
      
      h1 { font-family: 'Helvetica Neue', sans-serif; } /* static, constructed */
      body { font-family: 'Adobe Caslon', serif; }      /* calligraphic, diagonal */
      ```
      
      **Correct (paired within a group):**
      
      ```css
      /* Calligraphic */
      h1 { font-family: 'Frutiger', sans-serif; }
      body { font-family: 'Adobe Caslon', serif; }
      
      /* Rational */
      h1 { font-family: 'Avenir', sans-serif; }
      body { font-family: 'Didot', serif; }
      
      /* Static: neo-grotesque over slab */
      h1 { font-family: 'Helvetica Neue', sans-serif; }
      body { font-family: 'Sentinel', serif; }
      ```
      
      Inside the static group, grotesques suit transitional serifs and neo-grotesques suit slabs. Body-text caveat by genre: geometric and neo-grotesque sans are weak at small sizes, so verify extended reading before setting body in either, while humanist sans and slabs carry body well. For screens, a neo-humanist sans over a contemporary serif (Calibri over Charter) is the most reliable all-around pair. "Grotesque", "grotesk", and "gothic" name the same genre. Treat these groupings as guidance, not law: know them before breaking them.
      
    • pairing-superfamilies.md 1 KB
      ---
      title: Use Superfamilies for Easy Pairing
      impact: LOW-MEDIUM
      tags: superfamily, serif-sans, pairing, harmony
      ---
      
      ## Use Superfamilies for Easy Pairing
      
      Superfamilies include serif and sans-serif variants built on the same skeleton, so they pair harmoniously with no guesswork.
      
      **Popular superfamilies:**
      - FF Tisa + FF Tisa Sans
      - Calluna + Calluna Sans
      - Freight Text + Freight Sans
      - Adelle + Adelle Sans
      - FF Meta + FF Meta Serif
      - FF Scala + FF Scala Sans
      - Fedra Serif + Fedra Sans
      - Source Serif + Source Sans
      
      **Incorrect (unrelated pair that clashes):**
      
      ```css
      h1 { font-family: 'Bodoni', serif; }
      body { font-family: 'Futura', sans-serif; }
      /* High-contrast modern serif with geometric sans: risky */
      ```
      
      **Correct (superfamily pair):**
      
      ```css
      h1 { font-family: 'Source Serif Pro', serif; }
      body { font-family: 'Source Sans Pro', sans-serif; }
      /* Same design DNA, guaranteed harmony */
      ```
      
      Most superfamily sans-serifs are humanist, since readable text serifs are usually humanist and need a humanist sans counterpart.
      
    • pairing-ui-fonts.md 1 KB
      ---
      title: Choose UI Fonts with Distinct Ambiguous Glyphs
      impact: HIGH
      tags: ui, glyphs, l-I-1, legibility, interface
      ---
      
      ## Choose UI Fonts with Distinct Ambiguous Glyphs
      
      For UI and data-heavy interfaces, pick fonts where l (lowercase L), I (uppercase i), and 1 (one) are visually distinct: ambiguous glyphs confuse IDs, codes, passwords, and data entry. Serifs help, since the serifs on I and l aid disambiguation. Use condensed faces for tight headlines and labels, never body text.
      
      **Incorrect (ambiguous glyphs in UI):**
      
      ```css
      .code-input {
        font-family: 'Helvetica', sans-serif;
        /* I, l, and 1 look nearly identical */
      }
      ```
      
      **Correct (distinct glyphs for UI):**
      
      ```css
      .code-input {
        font-family: 'Inter', sans-serif;
        /* Inter has distinct I (with serifs), l, and 1 */
      }
      
      /* Or use a monospaced font for code/ID fields */
      .code-input {
        font-family: 'JetBrains Mono', monospace;
      }
      ```
      
      **Fonts with distinct l/I/1:** Inter, IBM Plex Sans, Fira Sans, Source Sans Pro, Noto Sans. Test the string "Il1|" before committing to a UI typeface.
      
    • punct-abbreviations.md 767 B
      ---
      title: Clean Up Abbreviations and Decades
      impact: HIGH
      tags: abbreviations, acronyms, decades, punctuation
      ---
      
      ## Clean Up Abbreviations and Decades
      
      Remove unnecessary punctuation from abbreviations and decades. Drop apostrophes from decades (1990s, not 1990’s). Remove periods from acronyms (NASA, not N.A.S.A.). These errors mark amateur work.
      
      **Incorrect (unnecessary punctuation):**
      
      ```html
      <p>The company was founded in the 1990's.</p>
      <p>She works at N.A.S.A. on A.I. projects.</p>
      ```
      
      **Correct (clean abbreviations):**
      
      ```html
      <p>The company was founded in the 1990s.</p>
      <p>She works at NASA on AI projects.</p>
      ```
      
      Exception: lowercase abbreviations that could be misread as words ("e.g.", "i.e.", "a.m.", "p.m.") may keep periods for clarity.
      
    • punct-ampersands.md 732 B
      ---
      title: Use Ampersands Sparingly
      impact: MEDIUM
      tags: ampersand, punctuation, proper-names
      ---
      
      ## Use Ampersands Sparingly
      
      Reserve ampersands for proper names, established shorthand, and tight spaces. Do not use them for "and" in running text. Many typefaces have beautifully designed ampersand glyphs that work as decorative elements in display contexts.
      
      **Incorrect (ampersands in prose):**
      
      ```html
      <p>We focus on design & development & strategy.</p>
      <p>Read the terms & conditions before signing.</p>
      ```
      
      **Correct (ampersands for proper names and shorthand):**
      
      ```html
      <p>We focus on design, development, and strategy.</p>
      <p>Johnson &amp; Johnson reported earnings today.</p>
      <p>This is an R&amp;D initiative.</p>
      ```
      
    • punct-case-rules.md 1.3 KB
      ---
      title: Use Sentence Case for Headings
      impact: HIGH
      tags: capitalization, sentence-case, title-case, headings
      ---
      
      ## Use Sentence Case for Headings
      
      Set headings, buttons, labels, and nav items in sentence case, and apply it everywhere. Sentence case reads faster, survives translation, and never leaves a reviewer arguing over whether "For" is capitalized. Title case is defensible in editorial contexts, but only as a whole-project decision, never mixed in file by file. Enforce the choice in the build or CMS rather than by hand.
      
      **Incorrect (inconsistent casing):**
      
      ```html
      <h1>Getting Started with Typography</h1>  <!-- title case -->
      <h2>How to choose the right font</h2>     <!-- sentence case -->
      <h3>Best Practices For Line Height</h3>   <!-- inconsistent title case -->
      ```
      
      **Correct (sentence case throughout):**
      
      ```html
      <h1>Getting started with typography</h1>
      <h2>How to choose the right font</h2>
      <h3>Best practices for line height</h3>
      <button>Save changes</button>
      ```
      
      Always capitalize the first word, proper nouns, and "I". Do not reach for `text-transform: capitalize` to fake title case; it capitalizes every word including articles and prepositions, which no title-case style permits. Wording itself (what a heading should say) belongs to `copywriting`; this rule governs only the casing.
      
    • punct-daggers.md 796 B
      ---
      title: Use Daggers and Special Marks Correctly
      impact: LOW-MEDIUM
      tags: dagger, double-dagger, footnotes, hedera, manicule
      ---
      
      ## Use Daggers and Special Marks Correctly
      
      Use dagger (†) and double dagger (‡) for footnotes when asterisks are taken or numbering is impractical. Use hedera (❧) and manicule (☞) sparingly, as decoration only.
      
      **Incorrect (improvised footnote markers):**
      
      ```html
      <p>This claim requires citation.*</p>
      <p>*See appendix A. **See appendix B.</p>
      ```
      
      **Correct (proper footnote markers):**
      
      ```html
      <p>This claim requires citation.&dagger;</p>
      <p>Another point to note.&Dagger;</p>
      
      <footer>
        <p>&dagger; See appendix A.</p>
        <p>&Dagger; See appendix B.</p>
      </footer>
      ```
      
      **Footnote marker order:** * † ‡ § ‖ ¶ (then double up: ** †† etc.)
      
    • punct-dashes.md 1.4 KB
      ---
      title: Em Dash vs En Dash vs Hyphen
      impact: CRITICAL
      tags: dashes, em-dash, en-dash, hyphen, punctuation
      ---
      
      ## Em Dash vs En Dash vs Hyphen
      
      Each dash serves a distinct purpose. Never use double hyphens (`--`) as a substitute for an em dash. Choose either spaced en dashes or unspaced em dashes for parenthetical breaks and apply the choice consistently throughout the project.
      
      If the em dash looks too wide in your chosen typeface, switch to spaced en dashes.
      
      **Incorrect (double hyphens and wrong dash types):**
      
      ```html
      <p>Typography--the art of type--matters.</p>
      <p>Pages 10-20 cover the basics.</p>
      <p>The New York-London flight departs at noon.</p>
      ```
      
      **Correct (proper dash characters):**
      
      ```html
      <!-- Em dash for breaks (unspaced style) -->
      <p>Typography&mdash;the art of type&mdash;matters.</p>
      
      <!-- Or en dash for breaks (spaced style) -->
      <p>Typography &ndash; the art of type &ndash; matters.</p>
      
      <!-- En dash for ranges -->
      <p>Pages 10&ndash;20 cover the basics.</p>
      
      <!-- En dash for relationships/connections -->
      <p>The New York&ndash;London flight departs at noon.</p>
      ```
      
      **Key characters:**
      
      | Character | Name | HTML Entity | Use |
      |-----------|------|-------------|-----|
      | &mdash; | Em dash | `&mdash;` | Parenthetical breaks, attribution |
      | – | En dash | `&ndash;` | Ranges, relationships |
      | - | Hyphen | `-` | Compound words only |
      
      Use em dash for attribution in blockquotes: `&mdash;Robert Bringhurst`
      
    • punct-diacritics.md 860 B
      ---
      title: Support Accented Characters and Diacritics
      impact: CRITICAL
      tags: diacritics, accents, unicode, utf-8, glyphs
      ---
      
      ## Support Accented Characters and Diacritics
      
      Ensure fonts include all needed accented characters. Use correct diacritics (café, not cafe; naïve, not naive). Store accents as Unicode characters, not composed sequences. Avoid over-subsetting, which strips accented glyphs.
      
      **Incorrect (missing diacritics, wrong encoding):**
      
      ```html
      <meta charset="iso-8859-1">
      <p>The cafe serves a prix fixe menu with creme brulee.</p>
      ```
      
      **Correct (UTF-8 with proper diacritics):**
      
      ```html
      <meta charset="utf-8">
      <p>The caf&eacute; serves a prix fixe menu with cr&egrave;me br&ucirc;l&eacute;e.</p>
      ```
      
      Verify glyph coverage before selecting a font: test content covering all target languages. Avoid subsetting that removes accented ranges.
      
    • punct-fractions.md 895 B
      ---
      title: Use Proper Fraction and Math Entities
      impact: MEDIUM
      tags: fractions, multiplication, math, entities
      ---
      
      ## Use Proper Fraction and Math Entities
      
      Use Unicode fraction characters and proper math symbols instead of improvised alternatives. The multiplication sign (×) is not the letter "x". Standard fractions have dedicated Unicode characters.
      
      **Incorrect (improvised fractions and symbols):**
      
      ```html
      <p>The display is 1920x1080 pixels.</p>
      <p>Add 1/2 cup of flour and 3/4 tsp salt.</p>
      ```
      
      **Correct (proper entities):**
      
      ```html
      <p>The display is 1920&times;1080 pixels.</p>
      <p>Add &frac12; cup of flour and &frac34; tsp salt.</p>
      ```
      
      **Common fraction entities:**
      
      | Fraction | Entity | Unicode |
      |----------|--------|---------|
      | ½ | `&frac12;` | U+00BD |
      | ¼ | `&frac14;` | U+00BC |
      | ¾ | `&frac34;` | U+00BE |
      | ⅓ | `&#8531;` | U+2153 |
      | ⅔ | `&#8532;` | U+2154 |
      
    • punct-midpoints.md 670 B
      ---
      title: Use Midpoint Separators with Thin Spaces
      impact: LOW-MEDIUM
      tags: midpoint, interpunct, separator, thin-space
      ---
      
      ## Use Midpoint Separators with Thin Spaces
      
      Prefer midpoints (·) over pipes (|) or bullets (•) for inline horizontal list separators. Flank the midpoint with hair spaces (`&hairsp;`) or thin spaces (`&thinsp;`).
      
      **Incorrect (pipes or bullets as separators):**
      
      ```html
      <span>About | Blog | Contact</span>
      <span>About &bull; Blog &bull; Contact</span>
      ```
      
      **Correct (midpoints with thin spaces):**
      
      ```html
      <span>About&thinsp;&middot;&thinsp;Blog&thinsp;&middot;&thinsp;Contact</span>
      ```
      
      Use `&middot;` (U+00B7), not a period or bullet.
      
    • punct-primes.md 950 B
      ---
      title: Use Prime Marks for Measurements
      impact: MEDIUM-HIGH
      tags: primes, measurements, feet, inches, minutes, seconds
      ---
      
      ## Use Prime Marks for Measurements
      
      Prime (′) and double prime (″) marks are distinct from quotation marks and apostrophes. Use them for feet/inches, minutes/seconds, and coordinates. Never substitute curly quotes or straight quotes for primes.
      
      **Incorrect (quotes used as primes):**
      
      ```html
      <p>The board is 6' 2" long.</p>
      <p>The coordinates are 40° 26' 46" N.</p>
      ```
      
      **Correct (true prime characters):**
      
      ```html
      <p>The board is 6&prime; 2&Prime; long.</p>
      <p>The coordinates are 40&deg; 26&prime; 46&Prime; N.</p>
      ```
      
      **Key characters:**
      
      | Character | Name | HTML Entity | Unicode |
      |-----------|------|-------------|---------|
      | ′ | Prime (single) | `&prime;` | U+2032 |
      | ″ | Double prime | `&Prime;` | U+2033 |
      
      Primes should lean slightly to the right, distinct from the curly shape of apostrophes.
      
    • punct-single-space.md 642 B
      ---
      title: One Space After Periods
      impact: MEDIUM
      tags: spacing, periods, sentences, double-space
      ---
      
      ## One Space After Periods
      
      Use exactly one space between sentences. Double spacing after periods is a typewriter-era habit. HTML collapses multiple spaces, but they survive in `<pre>` blocks, emails, and CMS content.
      
      **Incorrect (double spaces):**
      
      ```html
      <p>Typography matters.  Good type improves readability.  Every detail counts.</p>
      ```
      
      **Correct (single spaces):**
      
      ```html
      <p>Typography matters. Good type improves readability. Every detail counts.</p>
      ```
      
      Audit copy for double spaces; normalize in the CMS or build pipeline.
      
    • punct-smart-quotes.md 1.3 KB
      ---
      title: Use Smart Quotes, Never Straight
      impact: CRITICAL
      tags: quotes, apostrophes, punctuation, utf-8
      ---
      
      ## Use Smart Quotes, Never Straight
      
      Smart (curly) quotes are the hallmark of professional typography. Straight quotes are a typewriter remnant and belong only in code. Dumb quotes in headlines are especially noticeable.
      
      Use UTF-8 encoding and normalize content at build or render time. Enable smart-quote conversion in the CMS or build pipeline.
      
      **Incorrect (straight/dumb quotes):**
      
      ```html
      <p>"It's a beautiful day," she said.</p>
      <p>The "best" option isn't always obvious.</p>
      ```
      
      **Correct (smart/curly quotes):**
      
      ```html
      <p>&ldquo;It&rsquo;s a beautiful day,&rdquo; she said.</p>
      <p>The &ldquo;best&rdquo; option isn&rsquo;t always obvious.</p>
      ```
      
      Or using UTF-8 directly:
      
      ```html
      <p>“It’s a beautiful day,” she said.</p>
      ```
      
      **Key characters:**
      
      | Character | Name | HTML Entity | Mac Shortcut |
      |-----------|------|-------------|--------------|
      | “ | Left double quote | `&ldquo;` | Opt+[ |
      | ” | Right double quote | `&rdquo;` | Opt+Shift+[ |
      | ‘ | Left single quote | `&lsquo;` | Opt+] |
      | ’ | Right single quote / apostrophe | `&rsquo;` | Opt+Shift+] |
      
      Use single quotes inside double quotes (US convention). Reserve straight quotes exclusively for code contexts.
      
    • punct-symbols.md 946 B
      ---
      title: Copyright, Trademark, and Registered Marks
      impact: MEDIUM
      tags: copyright, trademark, registered, symbols, superscript
      ---
      
      ## Copyright, Trademark, and Registered Marks
      
      Use correct Unicode characters or HTML entities for ©, ™, and ®. Set trademark and registered marks as superscripts; keep copyright inline at the surrounding text size. Never duplicate word and symbol (avoid "Copyright ©").
      
      Use a non-breaking space (`&nbsp;`) between the copyright symbol and the year.
      
      **Incorrect (wrong formatting):**
      
      ```html
      <p>Copyright (c) 2025 Acme Corp</p>
      <p>Acme(TM) Widget</p>
      <p>Copyright &copy; 2025</p>  <!-- missing non-breaking space -->
      ```
      
      **Correct (proper symbols and spacing):**
      
      ```html
      <p>&copy;&nbsp;2025 Acme Corp</p>
      <p>Acme<sup>&trade;</sup> Widget</p>
      <p>Acme<sup>&reg;</sup> Widget</p>
      ```
      
      ```css
      /* Ensure superscript marks are sized appropriately */
      sup {
        font-size: 0.6em;
        vertical-align: super;
      }
      ```
      
    • size-body-text.md 985 B
      ---
      title: Set Body Text Size by Context
      impact: CRITICAL
      tags: font-size, body-text, mobile, desktop, print
      ---
      
      ## Set Body Text Size by Context
      
      Set body size first; it anchors the whole typographic system. Use 16-24px desktop, 15-19px mobile, 10-12pt print. Adjust for x-height (a large x-height feels bigger at the same pixel size). Avoid oversized desktop body (above 24px); scale headings down proportionally on smaller screens.
      
      **Incorrect (one size for all contexts):**
      
      ```css
      body {
        font-size: 14px; /* too small for comfortable reading */
      }
      ```
      
      **Correct (responsive body sizing):**
      
      ```css
      body {
        font-size: 18px; /* desktop default */
        line-height: 1.5;
      }
      
      @media (max-width: 768px) {
        body {
          font-size: 16px; /* mobile */
        }
      }
      
      @media print {
        body {
          font-size: 11pt;
        }
      }
      ```
      
      Find the typeface's sweet spot by testing one size up and down. If 19px looks right but 18px is too small and 20px too large, use 19px even if it breaks your modular scale.
      
    • size-emphasis.md 1.7 KB
      ---
      title: Emphasize with Italics, Never Underlines or Caps
      impact: HIGH
      tags: emphasis, italic, underline, links, all-caps
      ---
      
      ## Emphasize with Italics, Never Underlines or Caps
      
      Use italics for emphasis in running text: they emphasize without disrupting reading flow. Reserve bold for strong semantic importance. All caps reduces reading speed and reads as shouting. Never underline for emphasis; on the web an underline universally signals a hyperlink, so it creates a false affordance and readers click text that does nothing. In print it is a typewriter-era substitute for italics with no place in modern typography.
      
      Limit how much text is emphasized: if everything is emphasized, nothing is. Prefer body fonts with a real italic.
      
      **Incorrect (bold, caps, and underline for emphasis):**
      
      ```html
      <p>Typography is <b>REALLY</b> important for readability.</p>
      <p>This is an <span class="important">important</span> point.</p>
      ```
      
      ```css
      .important {
        text-decoration: underline; /* looks like a link */
      }
      ```
      
      **Correct (italics for emphasis, underlines reserved for links):**
      
      ```html
      <p>Typography is <em>really</em> important for readability.</p>
      <p>Italicize publication titles: <cite>The Elements of Typographic Style</cite>.</p>
      <p>Read more on <a href="/typography">our typography page</a>.</p>
      ```
      
      ```css
      a {
        text-decoration: underline;
        text-decoration-thickness: 1px;
        text-underline-offset: 0.15em;
      }
      
      em {
        font-style: italic;
      }
      ```
      
      Use `<em>` for emphasis and `<cite>` for publication titles; reserve `<i>` for an alternate voice (technical terms, foreign phrases). The same false affordance applies to color: never give non-link text your link color, which is the most common way headings get mistaken for links.
      
    • size-hanging-punctuation.md 1 KB
      ---
      title: Use Hanging Punctuation Where Feasible
      impact: LOW-MEDIUM
      tags: hanging-punctuation, alignment, optical, blockquotes
      ---
      
      ## Use Hanging Punctuation Where Feasible
      
      Hanging punctuation moves quotation marks and other punctuation into the margin to align the left edge optically, creating a cleaner edge. Web support is limited, so apply it only to the left edge of blockquotes and display text, where it has the most impact.
      
      **Incorrect (punctuation disrupts left alignment):**
      
      ```html
      <blockquote>
        <p>"Good typography is invisible."</p>
      </blockquote>
      ```
      
      ```css
      blockquote {
        /* Quote mark pushes text inward */
      }
      ```
      
      **Correct (hanging punctuation on blockquotes):**
      
      ```css
      /* hanging-punctuation is not Baseline: Safari ships it, Chrome and
         Firefox do not, so the fallback has to be scoped or it double-shifts. */
      blockquote p {
        hanging-punctuation: first last;
      }
      
      @supports not (hanging-punctuation: first) {
        blockquote p {
          text-indent: -0.4em;
        }
      }
      ```
      
      Applying it across all body text is impractical to maintain on the web.
      
    • size-line-height.md 1 KB
      ---
      title: Set Line Height for Comfortable Reading
      impact: CRITICAL
      tags: line-height, leading, readability, unitless
      ---
      
      ## Set Line Height for Comfortable Reading
      
      Set body line height to about 1.45-1.6, always unitless so it inherits correctly. Adjust for font size, line length, and x-height: large-x-height sans faces may need slightly more. Longer lines need more leading, shorter lines less. Avoid excessive leading (above 1.8); it disconnects lines visually.
      
      **Incorrect (too tight, units used):**
      
      ```css
      body {
        font-size: 18px;
        line-height: 20px; /* fixed value, doesn't scale */
      }
      
      h1 {
        font-size: 48px;
        /* inherits 20px line-height, causing overlap */
      }
      ```
      
      **Correct (unitless, proportional):**
      
      ```css
      body {
        font-size: 18px;
        line-height: 1.5; /* unitless, scales with font-size */
      }
      
      h1 {
        font-size: 48px;
        line-height: 1.15; /* tighter for large headings */
      }
      
      .caption {
        font-size: 14px;
        line-height: 1.4; /* slightly tighter for small text */
      }
      ```
      
      Set line height before paragraph spacing; together they establish vertical rhythm.
      
    • size-line-length.md 1022 B
      ---
      title: Keep Line Length Between 45 and 75 Characters
      impact: HIGH
      tags: measure, line-length, characters-per-line, readability
      ---
      
      ## Keep Line Length Between 45 and 75 Characters
      
      Ideal measure is about 66 characters per line including spaces. Under 45 forces excessive hyphenation or ragged edges; over 75 makes readers lose their place on line return. Constrain measure per breakpoint with `ch` units or `max-width` on text containers.
      
      **Incorrect (no measure constraint):**
      
      ```css
      .article {
        width: 100%; /* lines can stretch to 120+ characters on wide screens */
        font-size: 18px;
      }
      ```
      
      **Correct (constrained measure):**
      
      ```css
      .article {
        max-width: 65ch; /* approximately 65 characters */
        font-size: 18px;
        margin: 0 auto;
      }
      
      @media (max-width: 768px) {
        .article {
          max-width: 100%;
          padding: 0 1rem;
          /* Narrower screen naturally constrains measure */
        }
      }
      ```
      
      `ch` equals the width of the "0" glyph: it approximates character count but varies by typeface, so test with real content.
      
    • size-responsive.md 1009 B
      ---
      title: Adapt Typography Across Breakpoints
      impact: HIGH
      tags: responsive, mobile, media-queries, display-faces, scaling
      ---
      
      ## Adapt Typography Across Breakpoints
      
      Scale headings down on smaller screens. Swap display faces to text faces on small screens via media queries: display cuts with fine details lose legibility at small sizes. Limit long light-on-dark text on mobile where screen glare reduces contrast.
      
      **Incorrect (desktop type unchanged on mobile):**
      
      ```css
      h1 {
        font-family: 'Playfair Display', serif;
        font-size: 72px; /* stays huge on mobile */
      }
      ```
      
      **Correct (responsive scaling and font swapping):**
      
      ```css
      h1 {
        font-family: 'Playfair Display', serif;
        font-size: 48px;
      }
      
      @media (max-width: 768px) {
        h1 {
          font-family: 'Source Serif Pro', serif; /* text cut for small screens */
          font-size: 28px;
          line-height: 1.2;
        }
      }
      ```
      
      Identify display faces by their naming: Display, Banner, Headline, Poster, Titling. These should not appear at body sizes on any screen.
      
    • spacing-hair-thin-spaces.md 1.1 KB
      ---
      title: Use Hair and Thin Spaces for Fine Adjustments
      impact: LOW-MEDIUM
      tags: hair-space, thin-space, em-dash, citations, spacing
      ---
      
      ## Use Hair and Thin Spaces for Fine Adjustments
      
      When a full word space is too wide but no space is too tight, use hair spaces (`&hairsp;`) or thin spaces (`&thinsp;`): around em dashes, after citations, between nested punctuation, and around special characters.
      
      **Incorrect (no space or full space around em dashes):**
      
      ```html
      <p>Typography&mdash;the art of type&mdash;matters.</p>       <!-- too tight -->
      <p>Typography &mdash; the art of type &mdash; matters.</p>  <!-- too loose -->
      ```
      
      **Correct (thin spaces around em dashes):**
      
      ```html
      <p>Typography&thinsp;&mdash;&thinsp;the art of type&thinsp;&mdash;&thinsp;matters.</p>
      ```
      
      **Common uses:**
      
      | Context | Spacing |
      |---------|---------|
      | Around em dashes | `&thinsp;` or `&hairsp;` |
      | Between quote and attribution | `&hairsp;` |
      | Around midpoint separators | `&thinsp;` |
      | Between units and values | `&thinsp;` (e.g., 5&thinsp;kg) |
      
      Use `&hairsp;` (U+200A, thinnest) when `&thinsp;` (U+2009) still feels too wide.
      
    • spacing-letterspacing-body.md 1.3 KB
      ---
      title: Never Letterspace Body Text
      impact: HIGH
      tags: letter-spacing, tracking, body-text, readability
      ---
      
      ## Never Letterspace Body Text
      
      Adding letter-spacing to body text destroys the carefully designed spacing built into the font's metrics. Professional typefaces are spaced for optimal readability at text sizes. The only exceptions are very small captions, where slight positive tracking aids legibility, and display-size lowercase.
      
      If small text is hard to read, the fix is a larger font size, not tracking. Tracking does not buy back legibility lost to size, and anything below 12px fails readers with low vision and is unreadable at arm's length on a high-density phone. Keep 12px as the floor, and reserve it for non-essential text (a photo credit, a legal footnote), never for content a reader has to act on.
      
      **Incorrect (letterspacing applied to body):**
      
      ```css
      body {
        letter-spacing: 0.05em; /* disrupts natural rhythm */
      }
      
      p {
        letter-spacing: 1px; /* even worse */
      }
      ```
      
      **Correct (no letterspacing on body):**
      
      ```css
      body {
        letter-spacing: normal;
      }
      
      /* Only small non-essential text may benefit from slight tracking */
      .photo-credit {
        font-size: 12px;
        letter-spacing: 0.02em;
      }
      ```
      
      Remember: kerning adjusts space between specific letter pairs; letterspacing (tracking) adjusts uniform space between all letters. They are different tools.
      
    • spacing-letterspacing-uppercase.md 1.4 KB
      ---
      title: Add Letterspacing to Uppercase Text
      impact: MEDIUM-HIGH
      tags: letter-spacing, uppercase, tracking, small-caps, word-spacing
      ---
      
      ## Add Letterspacing to Uppercase Text
      
      Uppercase letters are designed to sit next to lowercase letters, so in all caps they appear too tightly spaced. Add roughly 0.05 to 0.2em of letter-spacing, more for smaller uppercase text and less for larger. Raise `word-spacing` alongside it: as inter-letter gaps approach the inter-word gap, words merge into one run of caps.
      
      Avoid setting multi-line blocks in all uppercase; it significantly reduces reading speed.
      
      **Incorrect (uppercase untracked, or tracked without word spacing):**
      
      ```css
      .label {
        text-transform: uppercase;
        /* no letter-spacing adjustment */
      }
      
      .small-caps-label {
        font-variant-caps: all-small-caps;
        letter-spacing: 0.15em;
        /* words blur together at this tracking */
      }
      ```
      
      **Correct (tracking plus proportional word spacing):**
      
      ```css
      .label {
        text-transform: uppercase;
        letter-spacing: 0.1em;
        font-size: 0.75rem;
      }
      
      /* Larger uppercase needs less tracking */
      .section-title {
        text-transform: uppercase;
        letter-spacing: 0.05em;
        font-size: 1.25rem;
      }
      
      .small-caps-label {
        font-variant-caps: all-small-caps;
        letter-spacing: 0.15em;
        word-spacing: 0.1em;
      }
      ```
      
      Do not letterspace or apply optical kerning to monospaced or connected script fonts; keep their spacing at the font's built-in metrics.
      
    • spacing-nav-items.md 1 KB
      ---
      title: Space Navigation Items with CSS Padding
      impact: MEDIUM
      tags: navigation, padding, spacing, selected-state
      ---
      
      ## Space Navigation Items with CSS Padding
      
      Use CSS padding (not spaces or margin hacks) to space navigation items. Limit the number of navigation items for clarity. Indicate the current page by styling the selected item as active/inactive, and do not gray out navigable items.
      
      **Incorrect (spaces for nav padding, grayed navigable items):**
      
      ```html
      <nav>
        <a href="/">Home</a>&nbsp;&nbsp;&nbsp;
        <a href="/about">About</a>&nbsp;&nbsp;&nbsp;
        <a href="/blog" style="color: gray">Blog</a>  <!-- grayed but navigable -->
      </nav>
      ```
      
      **Correct (CSS padding, clear selected state):**
      
      ```css
      nav a {
        padding: 0.5rem 1rem;
        text-decoration: none;
        color: var(--text-secondary);
      }
      
      nav a[aria-current="page"] {
        color: var(--text-primary);
        font-weight: 600;
      }
      
      nav a:hover {
        color: var(--text-primary);
      }
      ```
      
      Never gray out items that are still navigable. Keep the selected item readable and visually prominent.
      
    • spacing-paragraph-indent.md 639 B
      ---
      title: Apply Indents Correctly
      impact: MEDIUM
      tags: text-indent, paragraphs, first-paragraph, sizing
      ---
      
      ## Apply Indents Correctly
      
      When using indentation for paragraph separation, indent only paragraphs after the first (the opening paragraph has nothing to separate from). Size indents to 1 to 1.5em; larger indents (2 to 3em) suit wide columns with ample margins.
      
      **Incorrect (every paragraph indented, including first):**
      
      ```css
      p {
        text-indent: 1.5em;
      }
      ```
      
      **Correct (indent only after first paragraph):**
      
      ```css
      p + p {
        text-indent: 1.5em;
      }
      ```
      
      Use smaller indents for narrow columns; above 3em is counterproductive.
      
    • spacing-paragraph-margins.md 1.5 KB
      ---
      title: Add Adequate Margins, Gutters, and Padding Around Text
      impact: HIGH
      tags: margins, padding, gutters, columns, mobile
      ---
      
      ## Add Adequate Margins, Gutters, and Padding Around Text
      
      Text needs breathing room on every edge: column gutters wide enough that adjacent columns do not read as one, container padding that keeps text off the screen edges, thumb space on mobile, and print gutters. Text touching a phone's bezel is one of the most common and most obvious layout defects. Keep paragraph spacing modest and responsive; paragraphs should neither run together nor float apart.
      
      **Incorrect (no gutters, text hits the screen edge, paragraphs run together):**
      
      ```css
      .grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0; /* columns touch */
      }
      
      .article {
        padding: 0; /* text hits screen edges on mobile */
      }
      
      p {
        margin: 0; /* paragraphs run together */
      }
      ```
      
      **Correct (gutters, container padding, responsive paragraph spacing):**
      
      ```css
      .grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 2rem; /* comfortable gutter between columns */
      }
      
      .article {
        padding: 2rem;
        max-width: 65ch;
        margin: 0 auto;
      }
      
      p {
        margin-bottom: 1em;
      }
      
      @media (max-width: 768px) {
        .article {
          padding: 1rem; /* minimum thumb space */
        }
      
        .grid {
          grid-template-columns: 1fr; /* stack rather than shrink the measure */
        }
      }
      ```
      
      Set line height before paragraph spacing; the two values work together to make vertical rhythm. Break long copy into readable paragraphs with subheadings and lists rather than shipping a wall of text.
      
    • spacing-paragraph-separation.md 831 B
      ---
      title: Use Line Breaks or Indents, Not Both
      impact: MEDIUM
      tags: paragraphs, line-breaks, indents, separation
      ---
      
      ## Use Line Breaks or Indents, Not Both
      
      Separate paragraphs with either vertical space (line breaks) or indentation, never both (an indent after a line break is redundant). Line breaks are the web default and aid scanning; indents feel formal and classical, flowing longform content more smoothly.
      
      **Incorrect (both indent and space):**
      
      ```css
      p {
        text-indent: 1.5em;
        margin-bottom: 1.5em; /* double separation */
      }
      ```
      
      **Correct (line breaks only, the web default):**
      
      ```css
      p {
        margin-bottom: 1em;
        text-indent: 0;
      }
      ```
      
      **Or indents only (longform/editorial):**
      
      ```css
      p {
        margin-bottom: 0;
        text-indent: 1.5em;
      }
      
      p:first-of-type {
        text-indent: 0; /* no indent on first paragraph */
      }
      ```
      
    • spacing-subhead-proximity.md 799 B
      ---
      title: Place Subheadings Closer to Following Content
      impact: MEDIUM-HIGH
      tags: subheadings, proximity, whitespace, visual-grouping
      ---
      
      ## Place Subheadings Closer to Following Content
      
      Give a subheading more space above (separating it from prior content) than below (connecting it to the content it introduces). This proximity groups the heading with its section. Use extra space above large subheaders.
      
      **Incorrect (equal spacing, heading floats between sections):**
      
      ```css
      h2 {
        margin-top: 1.5rem;
        margin-bottom: 1.5rem;
      }
      ```
      
      **Correct (more space above, less below):**
      
      ```css
      h2 {
        margin-top: 2.5rem;
        margin-bottom: 0.75rem;
      }
      
      h3 {
        margin-top: 2rem;
        margin-bottom: 0.5rem;
      }
      ```
      
      The larger the heading, the more top margin it needs to separate from the preceding section.
      
    • _sections.md 3.2 KB
      # Sections
      
      The 10 rule categories: heading order = audit priority. Rule files are named `<prefix>-<slug>.md`. `_template.md` scaffolds new rule files and is not loaded during an audit.
      
      Category impact is the impact of the category's worst-case rules, not an average. A rule's own frontmatter `impact` is the authoritative value and often differs from its category, so report findings with the rule-level value. The rules that most diverge from their category are `brand-color` and `brand-licensing` (HIGH inside MEDIUM), `pairing-ui-fonts` (HIGH inside MEDIUM), `opentype-tabular-figures` (HIGH inside MEDIUM), `punct-daggers` and `punct-midpoints` (LOW-MEDIUM inside CRITICAL), and `font-rendering` (MEDIUM inside CRITICAL).
      
      Counts must reconcile with `ls rules/ | grep -v '^_' | wc -l` (total: 78).
      
      ## 1. Font Selection & Weights (font), 11 rules
      
      **CRITICAL.** Faux bold and italic, broken `@font-face` mappings, and missing fallback stacks make text render wrong or not at all. Also covers weight, width, optical size, and font quality.
      
      ## 2. Sizing & Measure (size), 6 rules
      
      **CRITICAL.** Body size, line height, and measure decide whether the text is readable at all, and a fixed-px line height inherited by a heading overlaps lines outright. Also covers responsive scaling and emphasis.
      
      ## 3. Punctuation & Special Characters (punct), 12 rules
      
      **CRITICAL.** The most visible sign of amateur typography: straight quotes, double hyphens for dashes, and missing diacritics are non-negotiable in rendered copy. The rest of the category (footnote marks, symbols, fractions, separators) is refinement, priced MEDIUM and below per rule.
      
      ## 4. Spacing & Rhythm (spacing), 8 rules
      
      **HIGH.** Letterspaced body text, cramped gutters, and text touching a phone bezel cost readability directly. Uppercase tracking, subhead proximity, and paragraph separation control rhythm.
      
      ## 5. Hierarchy & Scale (hierarchy), 8 rules
      
      **MEDIUM-HIGH.** Size contrast, weight variation, and shallow semantic heading levels make content scannable and navigable by screen reader. Body first; headings derive from it.
      
      ## 6. Alignment & Layout (layout), 6 rules
      
      **MEDIUM.** Justified text without hyphenation and centered body copy break the left reading edge; list markup, proximity, and widow control affect page-level readability.
      
      ## 7. OpenType Features (opentype), 7 rules
      
      **MEDIUM.** Mostly refinement, since browsers enable `kern` and `liga` by default. The exceptions carry real cost: misaligned figures in a data table, and ligatures inside code blocks that obscure individual characters.
      
      ## 8. Brand & Identity (brand), 8 rules
      
      **MEDIUM.** Mostly consistency and recognition, but this is where the WCAG contrast floor (`brand-color`) and font licensing exposure (`brand-licensing`) live, both HIGH.
      
      ## 9. Typeface Pairing (pairing), 5 rules
      
      **MEDIUM.** Combine typefaces by matching stress and skeleton, by deliberate contrast, or via superfamilies; same-category pairs read as accidents. `pairing-ui-fonts` is HIGH: ambiguous l/I/1 glyphs cause real data-entry errors.
      
      ## 10. Display & Headlines (display), 7 rules
      
      **LOW-MEDIUM.** Headline spacing, drop caps, swashes, lead paragraphs, and headline-specific OpenType features add polish to large type.
      
    • _template.md 1.3 KB
      ---
      title: Imperative Rule Title (e.g. "Use Smart Quotes, Never Straight")
      impact: MEDIUM
      tags: tag1, tag2, tag3
      ---
      
      ## Imperative Rule Title (must match frontmatter title)
      
      One short paragraph: what the rule requires and why it matters (readability, professionalism, rendering). Lead with the requirement, not history.
      
      **Incorrect (one phrase naming what's wrong):**
      
      ```css
      /* Bad example: CSS or HTML, whichever the rule governs */
      body {
        line-height: 20px; /* fixed value, doesn't scale */
      }
      ```
      
      **Correct (one phrase naming what's right):**
      
      ```css
      /* Good example showing the fix */
      body {
        line-height: 1.5; /* unitless, scales with font-size */
      }
      ```
      
      Optional closing line: an edge case, exception, or escalation (e.g. "If bandwidth is constrained, drop bold italic rather than relying on faux rendering.").
      
      <!-- Conventions:
        - impact: one of CRITICAL, HIGH, MEDIUM-HIGH, MEDIUM, LOW-MEDIUM; may differ from the category impact in _sections.md.
        - Filename: <prefix>-<slug>.md where <prefix> is a section ID from _sections.md.
        - Every rule MUST have the **Incorrect**/**Correct** pair; checklist-style rules still show a violating and a conforming example.
        - Optional extras after the pair: a key-characters table (entities/shortcuts) or a "Reference: [name](url)" line.
        - Target length: under 60 lines. -->
      
  • SKILL.md 6.2 KB
    ---
    name: typography-audit
    description: Audits font loading, type scales, measure, spacing, OpenType, and rendered punctuation with 78 scoped rules. Use when asked to "audit typography", "fix the fonts", or "review my type system". For a new visual direction use ui-design Direction; for general UI defects use ui-design Audit.
    ---
    
    # Typography Audit
    
    78 rules in 10 categories for web typography. Every finding names file, rule, and fix.
    
    - **IS:** typography only: font loading, sizing, punctuation, spacing, hierarchy, text layout, OpenType features, typeface pairing, brand type, display type.
    - **IS NOT:** broad UI review (accessibility, forms, navigation: use `ui-design` Audit mode), or a redesign (new typefaces, scales: use `ui-design` Direction mode).
    
    ## Audit Workflow
    
    Track this checklist:
    
    ```text
    Audit progress:
    - [ ] Step 1: Scope. List changed files (or full sweep), map signals to categories
    - [ ] Step 2: Run CRITICAL rules in scope (font-, size-, punct-)
    - [ ] Step 3: Run HIGH rules in scope (spacing-)
    - [ ] Step 4: Run remaining in-scope categories by descending priority
    - [ ] Step 5: Report per the contract; every finding has file:line, rule ID, fix
    ```
    
    1. Scope to changed files unless a full sweep is requested. For a PR, use the diff against its actual base merge-base, including committed changes, filtered to `.css`, `.scss`, `.html`, `.tsx`/`.jsx`, and template files.
    2. Map code to categories via the signal table; skip categories with no signal.
    3. Load rule files by prefix (`rules/font-*.md`, etc.), only for the categories the signals selected.
    4. Run categories in priority order so CRITICAL findings surface even if the audit is cut short.
    5. After fixes, re-run only the rules that produced findings, then finalize the report.
    
    ## Scoping Signals → Categories
    
    | Signal in code | Categories to load |
    |--------------------|--------------------|
    | `@font-face`, `font-family`, font files, variable fonts, `font-stretch`, `transform: scaleX` on text | `font-` |
    | `font-size`, `clamp()`, media-query type changes, `max-width` on text, `<em>`/`<strong>`, `text-decoration` | `size-` |
    | Copy in HTML/JSX (headings, paragraphs, labels) | `punct-` |
    | `line-height`, `letter-spacing`, `word-spacing`, `margin` on text, `text-transform: uppercase` | `spacing-` |
    | Heading elements, type scale tokens, `--text-*` properties | `hierarchy-` |
    | `text-align`, lists, blockquotes, multi-column text | `layout-` |
    | `font-feature-settings`, `font-variant-*`, figures/fractions in copy | `opentype-` |
    | Logo/wordmark styles, brand tokens, text color tokens, license comments | `brand-` |
    | Two or more distinct `font-family` values | `pairing-` |
    | Hero/display sizes, drop caps, `initial-letter` | `display-` |
    
    ## Rule Categories by Priority
    
    | Priority | Category | Impact | Prefix | Rules |
    |----------|----------|--------|--------|-------|
    | 1 | Font Selection & Weights | CRITICAL | `font-` | 11 |
    | 2 | Sizing & Measure | CRITICAL | `size-` | 6 |
    | 3 | Punctuation & Special Characters | CRITICAL | `punct-` | 12 |
    | 4 | Spacing & Rhythm | HIGH | `spacing-` | 8 |
    | 5 | Hierarchy & Scale | MEDIUM-HIGH | `hierarchy-` | 8 |
    | 6 | Alignment & Layout | MEDIUM | `layout-` | 6 |
    | 7 | OpenType Features | MEDIUM | `opentype-` | 7 |
    | 8 | Brand & Identity | MEDIUM | `brand-` | 8 |
    | 9 | Typeface Pairing | MEDIUM | `pairing-` | 5 |
    | 10 | Display & Headlines | LOW-MEDIUM | `display-` | 7 |
    
    Category map and impact rationale: `rules/_sections.md`. Each rule file gives why it matters plus an incorrect and a correct example. Category impact reflects the category's worst-case rules; report findings with the rule's own frontmatter `impact`, which frequently differs (e.g. `brand-color` is HIGH inside the MEDIUM `brand-` category because it holds the WCAG contrast floor).
    
    ## Review Output Contract
    
    Report findings as:
    
    ```markdown
    ## Typography Audit Findings
    
    ### path/to/file.css
    - [CRITICAL] `punct-smart-quotes` (file.css:42): Straight quotes in heading copy.
      - Fix: Replace `"` with `&ldquo;`/`&rdquo;` (or UTF-8 curly quotes).
    - [CRITICAL] `size-line-height` (file.css:18): `line-height: 20px`, a fixed value the 48px `h1` inherits, so its lines overlap.
      - Fix: Use unitless `line-height: 1.5`.
    
    ### path/to/clean-file.css
    - ✓ pass
    ```
    
    - Group by file; order by impact within file.
    - Every finding: impact tag, rule ID, `file:line`, one-line issue, fix.
    - Include clean files as `✓ pass` so coverage is visible.
    - End with a summary: counts per impact level.
    
    ## Gotchas
    
    - Don't preload every rule file. Load only the prefixes the signal table selects; a full load spends the budget on categories with no signal in scope.
    - Report the rule's frontmatter `impact`, never the category's. Two rules get misreported most: `brand-color` is HIGH (an accessibility floor, not a brand nicety) and `punct-daggers` is LOW-MEDIUM (decoration, despite sitting in a CRITICAL category).
    - Punctuation rules apply to rendered copy only. Flagging straight quotes or `--` inside `<code>`, `<pre>`, or JS/TS string literals is a false positive; "fixing" them breaks the code.
    - Confirm the rendered font and computed styles through `ui-verification` when a finding depends on them. A CSS declaration alone does not prove which face loaded.
    - Don't flag missing OpenType features without confirming the loaded font ships them. Browsers silently ignore unsupported `font-feature-settings` tags, so the fix does nothing.
    - Every finding needs `file:line` and a concrete fix; an unactionable finding forces a redo.
    - An audit is not a redesign. Proposing new pairings or scales turns a 10-minute review into a design project; flag the issue and route redesign asks to `ui-design`.
    - Don't equalize priorities. A LOW-MEDIUM `display-` nit above a CRITICAL faux-bold finding buries what actually looks broken.
    
    ## Related Skills
    
    - `ui-design` Audit mode: broad frontend quality (accessibility, forms, navigation, motion); its typography coverage is shallower.
    - `ui-design` Direction mode: choosing typefaces, scales, and visual direction from scratch; run when a finding becomes a redesign request.
    - `copywriting`: heading and label wording. This skill governs only the casing of that copy (`punct-case-rules`).
    
    Maintenance only: `evals/evals.json` contains regression scenarios for changes to this skill; it does not load during a user task.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related