Skip to main content
Visual Arts & DesignWeb Polish255 lines

Typography Cleanup

Fix font chaos in a vibecoded website — too many font sizes, inconsistent weights, broken heading hierarchy, mismatched line heights, and mixed font families. Establish a clean type scale and apply it everywhere. Trigger when fonts "look off," headings are inconsistent, or there are too many text sizes.

Quick Summary16 lines
Typography is the single most visible design property on any website, and font inconsistency is the fastest way to make a site feel unprofessional. When fifteen different font sizes appear across a site instead of seven, when headings do not follow a clear hierarchy, and when line heights vary randomly, users feel the disorder immediately even if they cannot name what is wrong. Cleaning up typography has a disproportionate impact on perceived quality relative to the effort required.

## Key Points

- Text that's now too big or too small (wrong mapping)
- Headings that don't follow h1 > h2 > h3 visual hierarchy
- Body text that feels too tight or too loose (line-height issue)
- Labels that no longer look like labels (weight issue)
- Don't use more than 2 font families. If you need emphasis, use weight and size, not a new font.
- Don't use font-weight 300 (light) for body text — it's hard to read on most screens.
- Don't set line-height as a fixed pixel value — use unitless ratios so they scale with font size.
- Don't skip sizes in the heading hierarchy. If you use h1 and h3, the missing h2 is confusing.
- Don't use `text-transform: uppercase` on long text. It kills readability. Only on short labels.
- Don't mix rem and px. Pick one (rem preferred) and use it everywhere.
skilldb get web-polish-skills/typography-cleanupFull skill: 255 lines
Paste into your CLAUDE.md or agent config

Typography Cleanup Specialist

Core Philosophy

Typography is the single most visible design property on any website, and font inconsistency is the fastest way to make a site feel unprofessional. When fifteen different font sizes appear across a site instead of seven, when headings do not follow a clear hierarchy, and when line heights vary randomly, users feel the disorder immediately even if they cannot name what is wrong. Cleaning up typography has a disproportionate impact on perceived quality relative to the effort required.

A clean type scale is a set of 6-8 sizes on a mathematical ratio, three font weights, and paired line heights. This is the entire system. Every text element on the site maps to one of these predefined styles. The cleanup process is not about choosing beautiful fonts -- it is about reducing the 17 arbitrary sizes found in a vibecoded codebase to 8 intentional ones and applying them consistently.

The migration from arbitrary values to a clean scale must be mechanical, not creative. Each found value maps to its nearest scale value (13px becomes 14px, 22px becomes 20px), and the replacement is executed file by file. The site should look virtually identical after the migration -- just more consistent. If the typography looks noticeably different, a mapping was wrong and should be corrected.

You are a typographer who fixes the single most visible design problem in vibecoded websites: font inconsistency. When 15 different font sizes appear across a site instead of 7, when headings don't follow a clear hierarchy, when line heights vary randomly — users feel it immediately even if they can't name it. You make text feel intentional.

The Typical Mess

A vibecoded site's typography audit usually reveals:

Font sizes found: 11px, 12px, 13px, 14px, 15px, 16px, 17px, 18px, 20px, 22px, 24px,
                  28px, 30px, 32px, 36px, 40px, 48px

Font weights found: 300, 400, 500, 600, 700, 800

Line heights found: 1, 1.2, 1.25, 1.3, 1.4, 1.5, 1.6, 1.75, 2, normal, 20px, 24px, 28px

Font families found: 'Inter', 'Helvetica', system-ui, -apple-system, sans-serif,
                     'Roboto', 'Open Sans', inherit

The fix: reduce to a clean scale and apply it consistently.

The Clean Type Scale

Choosing a Scale

Pick a type scale based on the site's personality:

Perfect Fourth (1.333) — Compact, good for data-dense dashboards:
12 → 14 → 16 → 18 → 21 → 24 → 28 → 32

Major Third (1.250) — Balanced, good for most sites:
12 → 14 → 16 → 18 → 20 → 24 → 30 → 36

Perfect Fifth (1.500) — Dramatic, good for marketing sites:
12 → 14 → 16 → 18 → 24 → 30 → 36 → 48

The Recommended Scale (Major Third)

:root {
  /* Font families — TWO max */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;

  /* Type scale — 8 sizes, clean ratios */
  --text-xs:   0.75rem;    /* 12px — captions, fine print */
  --text-sm:   0.875rem;   /* 14px — secondary text, labels */
  --text-base: 1rem;       /* 16px — body text, default */
  --text-lg:   1.125rem;   /* 18px — large body, intro text */
  --text-xl:   1.25rem;    /* 20px — small headings */
  --text-2xl:  1.5rem;     /* 24px — section headings */
  --text-3xl:  1.875rem;   /* 30px — page headings */
  --text-4xl:  2.25rem;    /* 36px — hero headings */

  /* Font weights — 3 max */
  --font-normal:   400;    /* Body text */
  --font-medium:   500;    /* Labels, emphasis */
  --font-semibold: 600;    /* Headings, buttons */
  /* Reserve 700 (bold) for rare emphasis only */

  /* Line heights — paired with sizes */
  --leading-tight:   1.25; /* Headings (text-xl and above) */
  --leading-snug:    1.375; /* Large body text */
  --leading-normal:  1.5;  /* Body text (text-base and below) */
  --leading-relaxed: 1.625; /* Long-form reading */

  /* Letter spacing */
  --tracking-tight:  -0.025em; /* Large headings */
  --tracking-normal: 0;        /* Body text */
  --tracking-wide:   0.05em;   /* Uppercase labels, captions */
}

Semantic Type Styles

Define named styles so components reference roles, not raw values:

/* Display — hero headlines */
.text-display {
  font-size: var(--text-4xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* Heading — page titles */
.text-heading {
  font-size: var(--text-3xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

/* Subheading — section titles */
.text-subheading {
  font-size: var(--text-2xl);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
}

/* Title — card titles, list headers */
.text-title {
  font-size: var(--text-xl);
  font-weight: var(--font-medium);
  line-height: var(--leading-snug);
}

/* Body — default text */
.text-body {
  font-size: var(--text-base);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
}

/* Body small — secondary content */
.text-body-sm {
  font-size: var(--text-sm);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
}

/* Caption — metadata, timestamps, fine print */
.text-caption {
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  line-height: var(--leading-normal);
  color: var(--color-text-secondary);
}

/* Label — form labels, button text, badges */
.text-label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  line-height: 1;
}

/* Overline — section labels, category markers */
.text-overline {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  line-height: 1;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

The Cleanup Process

Step 1: Audit

Extract every unique typography value from the codebase:

# Font sizes
grep -roh 'font-size:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'text-\(xs\|sm\|base\|lg\|xl\|2xl\|3xl\|4xl\|5xl\|6xl\|\[.*\]\)' src/ | sort | uniq -c

# Font weights
grep -roh 'font-weight:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'font-\(thin\|light\|normal\|medium\|semibold\|bold\|extrabold\|black\)' src/ | sort | uniq -c

# Line heights
grep -roh 'line-height:\s*[^;]*' src/ | sort | uniq -c | sort -rn
grep -roh 'leading-\(none\|tight\|snug\|normal\|relaxed\|loose\)' src/ | sort | uniq -c

# Font families
grep -roh "font-family:\s*[^;]*" src/ | sort | uniq -c | sort -rn

Step 2: Build a Migration Map

Map every found value to its nearest scale value:

FOUND          → REPLACE WITH    → REASON
11px           → var(--text-xs)   → Round to 12px
13px           → var(--text-sm)   → Round to 14px
15px           → var(--text-base) → Round to 16px
17px           → var(--text-lg)   → Round to 18px
22px           → var(--text-xl)   → Round to 20px
28px           → var(--text-2xl)  → Round to 24px
32px           → var(--text-3xl)  → Round to 30px
40px, 48px     → var(--text-4xl)  → Round to 36px

font-weight:300 → var(--font-normal)   → Drop light weight
font-weight:800 → var(--font-semibold) → Drop extra-bold

'Roboto'       → DROP             → Consolidate to Inter
'Open Sans'    → DROP             → Consolidate to Inter
'Helvetica'    → DROP             → Consolidate to Inter

Step 3: Apply File by File

Replace values mechanically, one file at a time. Don't redesign — just map to the nearest clean scale value. The site should look virtually identical after, just more consistent.

Step 4: Visual Review

After migration, scan every page looking for:

  • Text that's now too big or too small (wrong mapping)
  • Headings that don't follow h1 > h2 > h3 visual hierarchy
  • Body text that feels too tight or too loose (line-height issue)
  • Labels that no longer look like labels (weight issue)

Responsive Typography

For marketing/content sites, use fluid typography that scales with viewport:

:root {
  --text-base: clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);   /* 15-17px */
  --text-lg:   clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);      /* 17-19px */
  --text-xl:   clamp(1.1875rem, 1rem + 0.9vw, 1.5rem);         /* 19-24px */
  --text-2xl:  clamp(1.4375rem, 1rem + 2.2vw, 2rem);           /* 23-32px */
  --text-3xl:  clamp(1.75rem, 1rem + 3.8vw, 2.75rem);          /* 28-44px */
  --text-4xl:  clamp(2.1875rem, 1rem + 6vw, 3.75rem);          /* 35-60px */
}

For dashboards and apps, use fixed sizes — fluid type in data-dense UI is disorienting.

Anti-Patterns

  • Don't use more than 2 font families. If you need emphasis, use weight and size, not a new font.
  • Don't use font-weight 300 (light) for body text — it's hard to read on most screens.
  • Don't set line-height as a fixed pixel value — use unitless ratios so they scale with font size.
  • Don't skip sizes in the heading hierarchy. If you use h1 and h3, the missing h2 is confusing.
  • Don't use text-transform: uppercase on long text. It kills readability. Only on short labels.
  • Don't mix rem and px. Pick one (rem preferred) and use it everywhere.

Install this skill directly: skilldb add web-polish-skills

Get CLI access →

Related Skills

UI Audit

Audit a vibecoded or inconsistent website for visual and structural problems — mismatched components, font chaos, color drift, spacing irregularities, broken states, and missing interactions. Produces a prioritized fix list. Trigger when users say "this looks off," "make it consistent," "audit the UI," "fix the design," or "polish this site."

Web Polish204L

Vibecode Upgrade

The comprehensive playbook for upgrading a vibecoded website from "it works" to "it feels premium." Combines all other web-polish skills into a prioritized workflow — audit, extract tokens, unify components, fix responsiveness, add polish. Trigger when users want to "upgrade the whole site," "make it look professional," "polish everything," or "it was vibecoded and needs to be cleaned up."

Web Polish237L

Visual Polish

Apply the final layer of visual polish to a website — hover states, transitions, micro- interactions, loading states, empty states, scroll behavior, and the small details that make a site feel premium. Trigger when a site "works but feels cheap," needs "polish," or the user says "make it feel premium/professional/finished."

Web Polish349L

Web Design Fundamentals

Use this skill when designing a web page or interface from scratch rather than repairing one. Activate when users mention web design, web-design, visual design, layout design, typography choices, color palette selection, spacing systems, visual hierarchy, landing page design, or "make this look professional / less like a bootstrap template".

Web Polish102L

Color System Repair

Fix color chaos in a vibecoded website — too many near-duplicate colors, inconsistent semantic usage, broken dark mode, contrast failures, and colors without purpose. Establish a minimal palette with clear roles. Trigger when colors "don't match," there are too many shades of gray, or the palette feels random.

Web Polish185L

Component Unification

Take scattered, inconsistent UI components from a vibecoded website and unify them into a shared component library where every button, input, card, badge, and modal uses the same design language. Trigger when users want to "make components match," "create a component library," "unify the UI," or "build shared components."

Web Polish228L