WRESTLINGCOLLEGES.COM

Build in public ·

Redesigning a data site without the AI look or losing Lighthouse

How wrestlingcolleges.com got a real identity (navy, crimson, the weight-class ladder) while mobile Lighthouse went 62 to 94 and CLS fell from 0.3 to 0.01.

On this page

The site you are reading was, until a couple of weeks ago, a competent grey table with a blue link color. It worked. It also looked like every other thing an AI assistant builds when you say “make a directory,” and I did not want a recruiting site for wrestlers to feel like a SaaS pricing page.

Six pull requests later it has a look. Mobile Lighthouse performance went from 62 to 94 on program pages and 83 to 99 on state pages, and layout shift went from 0.19–0.31 to 0.012. The design did not cost the score. This post is about how, because the performance part almost went the other way.

Start from the anti-default list

Before drawing anything, my Claude Code agent worked through a design skill whose first move is a list of AI defaults to avoid: the purple-to-blue gradient, the three-column feature grid with icons, the rounded-everything card soup, Inter for everything, hero text that says nothing. The point of the list is not that any of these are bad. It is that a reader recognizes them within a second, and what they recognize is “nobody chose this.”

So every choice had to be a choice. Three directions, each on a different axis:

Real numbers on the artboards

Each direction got three artboards: the home hero, the Pitt-Johnstown page header, and a logo plus palette. Every artboard used real data. Not lorem ipsum, not “1,234 programs,” but the actual counts on the site that day (207 programs, 75 D2, 132 D3, 38 states, 50 deep profiles), the actual light-room ladder built from 164 rosters, and UPJ’s real coach, form status, cost and depth.

This matters more than it sounds. A design that looks good with fake data is a design of the fake data. Real cell values are long, real names break lines, real ladders have a bar at 285 that is taller than you expected. If the direction survives that, it survives.

I asked for direction A in two more palettes. A2 (crimson) won. The tokens are mat navy #1B3A5C, tape crimson #D7263D, chalk, paper and ink. Type is Big Shoulders Display for headlines, Atkinson Hyperlegible for body, IBM Plex Mono for stamps and metadata: about 104 KB of latin variable fonts, preloaded.

The weight-class ladder, ten weights from 125 to 285, is the one thing this site has that a general college search does not. So it became the identity: it is the favicon, it is the header mark, and on the home page it is the hero, built from real roster data. The hero shows the aggregate of programs with one or fewer wrestlers at each weight across rooms of 15 or more, the same rule the newsletter teaser uses, so it never leaks per-program depth. The bars rise on load with a staggered CSS animation, the top two weights turn crimson, and it stops dead under prefers-reduced-motion.

On a program page the same ladder is the depth block: a grey ghost with a lock when you are not signed in (no per-weight data is in the HTML at all), a navy panel with real bars once a Recruit Pass unlocks it. On /compare it shrinks to mini ladders in the depth row. One shape, three sizes, and the site starts to look like itself.

The performance story, which almost went wrong

Then I ran Lighthouse and the program page had CLS of 0.31 on mobile. Two causes.

The first was font swap. Distinctive webfonts mean the browser paints a fallback first and swaps when the real font arrives, and if the two fonts are different widths, every line rewraps. The standard fix is a metric-compatible local fallback with size-adjust. I had one for Atkinson, guessed against Verdana at 96%, and it was wrong. Big Shoulders had no fallback at all, so every headline jumped.

The fix was to stop guessing. In Chrome, with each face loaded, we measured the rendered width of the same test string in the webfont and in candidate system fonts and took the ratio. Atkinson is about Arial times 0.98. Big Shoulders is about Arial Narrow times 0.954 (or Impact times 0.956, or plain Arial times 0.78, if you need the alternates). Those become named local fallbacks:

@font-face { font-family: "Atkinson Fallback"; src: local("Arial"); size-adjust: 98%; }
@font-face { font-family: "BSD Fallback Narrow"; src: local("Arial Narrow"); size-adjust: 95.4%; }

Plus <link rel="preload"> for both variable woff2 files, and a min-height on the search slot that had been growing on mount. CLS: 0.012.

The second cause was LCP at 5.9 seconds on the program page. The Firebase bundle for Recruit Pass, about 550 KB, was loading with the page. Nobody needs it before first paint; it exists to check whether you are signed in. So the import moved inside requestIdleCallback with a 2.5 second timeout, Vite split it into its own chunk, and the page renders locked by default until the check resolves. LCP: 2.9 seconds. Nothing visible changed for a signed-in reader.

Two smaller ones worth knowing

Astro scopes page-level <style> blocks to the elements it renders. Anything a script renders after load, like the unlocked depth panel or the compare table, gets no styles unless you use <style is:global>. It turned out the compare page’s old styles had never applied at all.

And axe caught two things a human did not: the “.COM” in the footer inherited a muted small color and hit 2.3:1 contrast, and breadcrumb links relied on color alone because a page-level rule had removed the underline. Accessibility went 93 to 100 once those were fixed.

What I would tell anyone doing this

Measure the fallback, do not guess it. One Chrome measurement of width ratios turned a 0.3 CLS into 0.01. Any plan that says “swap in a distinctive webfont” should ship with that number attached, or the design costs exactly the performance score it was supposed to be worth.

Zero URLs, headings or JSON-LD changed in the six PRs. Before-and-after captures are in the repo. If something looks broken on your phone, /correct reaches me.

build-in-publicdesignperformance

Two posts a month + the monthly recruiting-changes email — one list, unsubscribe anytime
I'm the:

Independent publication; not affiliated with the NCAA or any institution. Facts link to their sources; anything about a specific program is as of the date shown — send a correction.