fix(landing): typography fixes across the landing page and feature shots - #81
Merged
Conversation
The Google Fonts request only asked for the upright axis of DM Sans (`ital...@0,...`), and `:root` in index.css sets `font-synthesis: none`. With no italic face and no synthesis, every `italic` element on the landing page rendered fully upright — the founder pull-quote in the story section and the three use-case testimonial quotes. Request the `1,...` italic axis so the real italic face loads, and collapse the discrete weight lists to `400..700` ranges (both families are variable fonts, so this serves the same files while also making intermediate weights available). Two related cleanups: - feature-shots.css declared `font-family: "Space Grotesk"` with no fallback in seven places. Whenever the webfont failed to load, those numerals, scores and titles dropped to the browser default serif instead of the sans stack. Route them through a new `--display` custom property that carries `system-ui, sans-serif`, matching how `--mono` is already handled. - The hero h1 asked for `font-extrabold` (800), but Space Grotesk's variable range stops at 700 — Google Fonts rejects a request for 800 outright — so with synthesis disabled it already rendered at 700. Use `font-bold` so the markup matches what ships. Verified in Chromium: the italic face is now registered and active (canvas metrics differ from upright), and all 245 prerendered pages carry the updated stylesheet link. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqMv2dS79q6iDEZKiZ9Rpn
…space The animated feature shots routed every numeric readout through `--mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace`. Outside macOS none of those resolve, so pace times, race predictions, elevation figures and plan details rendered in the generic monospace — DejaVu Sans Mono on Linux, Courier New on Windows. That reads as a third typeface next to DM Sans and Space Grotesk, and it is wide: in the training-plan shot it overran `.tp-day-detail`'s ellipsis clamp, so the day cards showed "5 mi · 8:42/…" instead of "5 mi · 8:42/mi". Space Grotesk carries a real `tnum` feature (verified in Chromium: tabular-nums holds "1111111111" and "0888888888" to the same width at 400/600/700), so the readouts get the brand face plus tabular figures instead. Digits stay column-aligned through the count-up animations — which was the actual reason for reaching for a monospace — and the big `44:30` / `49.8` numerals already used exactly this treatment, so the small ones now match them. DM Sans is deliberately not used here: it has no tnum table, so `font-variant-numeric: tabular-nums` is a no-op on it and the columns would jitter mid-animation. Switched: .mono, .pl-pace, .vd-pred .t, .el-tip .mi, .ac-zrow .v, .tp-phase-meta .wk, .tp-day-detail. `--mono` stays for the genuinely code-like text in the agent chat shot (tool names, the server handle), and its stack picks up Cascadia Mono, Segoe UI Mono, Consolas, Roboto Mono and DejaVu Sans Mono so those chips land on a real UI monospace off macOS rather than Courier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqMv2dS79q6iDEZKiZ9Rpn
The scrub tooltip is centred on the cursor via translate(-50%, -130%), so at either end of the profile its outer half fell outside .stage — which is overflow:hidden, so it got cut. Measured across the full sweep at 1440px and 900px: ~30px lost off the left at mile 0.0 and ~32px off the right at mile 26.2 (~22/24px at 900px), enough to swallow the grade reading. The auto-play demo ends at mile 26.2, so the clipped state is what the shot settles on. Clamp the tooltip's centre so its box stays within the stage, with a 10px gap. It has no arrow anchoring it to the cursor, so sliding it at the extremes is imperceptible, and positions away from the edges are untouched — re-measured worst-case overflow is 0 on all four edges at both widths, with mid-profile samples byte-identical to before. Vertical placement was already clear at every sample point, so it is left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqMv2dS79q6iDEZKiZ9Rpn
✅ Deploy Preview for trainpace canceled.
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 44 |
| Duplication | -1 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Both come out of the landing-page font work, where the defects were invisible in source and only showed up under measurement. CLAUDE.md gains a Typography section covering the constraints that caused those bugs: `font-synthesis: none` means a face missing from the Google Fonts URL fails silently instead of being synthesised, Space Grotesk stops at 700, italics need the `1,...` axis, Space Grotesk has a tnum table and DM Sans does not, and webfonts always need a fallback stack. The new verify-in-browser skill records the sandbox Playwright recipe — executablePath for the pinned-version mismatch, the loopback bypass so localhost is not routed through the agent proxy, and routing Google Fonts through curl since Chromium cannot reach it — along with the measurement traps behind this session's wrong turns: `document.fonts.check()` returning true for faces that do not exist, computed styles read off a proxy error page that was mistaken for the app, and a selector that matched one element twice so a two-case claim rested on a single screenshot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WqMv2dS79q6iDEZKiZ9Rpn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three typography defects on the landing page, plus a clipping bug found while verifying them. Each is verified in Chromium rather than reasoned about — details below.
1. Italic text rendered upright
The Google Fonts request asked only for the upright axis of DM Sans (
ital,opsz,wght@0,...— the leading0means upright only), and:rootinsrc/index.csssetsfont-synthesis: none. No italic face plus no synthesis means the browser silently renders italics as regular upright text.Affected the founder pull-quote in the story section and the three use-case testimonial quotes.
Fixed by adding the
1,...italic axis. DM Sans ships a real variable italic covering weights 400–700, so these are true italics, not a synthesised slant. Also collapsed the discrete weight lists to400..700ranges — both families are variable fonts, so this serves the same files while making intermediate weights available.2. Feature-shot numerals fell back to the generic monospace
The animated shots routed every numeric readout through
--mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace. Outside macOS none of those resolve, so pace times, race predictions, elevation figures and plan details rendered in the generic monospace — DejaVu Sans Mono on Linux, Courier New on Windows. That reads as a third typeface next to DM Sans and Space Grotesk.It also cost information: the fallback is wide enough to overrun
.tp-day-detail's ellipsis clamp, so the training-plan cards showed5 mi · 8:42/…instead of5 mi · 8:42/mi.Switched the readouts to Space Grotesk with tabular figures. Space Grotesk carries a real
tnumtable — verified in Chromium,tabular-numsholds1111111111and0888888888to the same width at 400/600/700 — so digits stay column-aligned through the count-up animations, which was the actual reason to reach for a monospace. The large44:30and49.8numerals already used exactly this treatment, so the small ones now match them.Worth knowing for future work: DM Sans has no
tnum, sofont-variant-numeric: tabular-numsis a no-op on it and columns would jitter mid-animation. Anything numeric in these shots needs Space Grotesk.Switched:
.mono,.pl-pace,.vd-pred .t,.el-tip .mi,.ac-zrow .v,.tp-phase-meta .wk,.tp-day-detail.--monois kept for the genuinely code-like text in the agent chat shot (tool names, the server handle), matching theapi.trainpace.com/api/mcpsnippet on the landing itself. Its stack now picks up Cascadia Mono, Segoe UI Mono, Consolas, Roboto Mono and DejaVu Sans Mono so those chips land on a real UI monospace off macOS.Separately,
feature-shots.cssdeclaredfont-family: "Space Grotesk"with no fallback in seven places — whenever the webfont failed to load, those numerals and titles dropped to the browser default serif. They now go through a--displaycustom property carryingsystem-ui, sans-serif, mirroring how--monowas already handled.3. Hero
<h1>requested an unavailable weightThe hero asked for
font-extrabold(800), but Space Grotesk's variable range stops at 700 — Google Fonts returns HTTP 400 for a request at 800 — so with synthesis disabled it was already rendering at 700. Changed tofont-boldso the markup matches what ships. No visual change.4. Elevation tooltip clipped at the card edges
Found while verifying the above. The scrub tooltip is centred on the cursor via
translate(-50%, -130%), and.stageisoverflow: hidden, so at either end of the profile its outer half fell outside the card.Swept the cursor across the full profile at 1440px and 900px, measuring the tooltip box against the stage on all four edges:
The right-edge case is what the shot settles on, since the auto-play demo eases to the end and stops there. The left-edge case is the same bug at the opposite end.
Added a
clampTipXhelper holding the tooltip inside the stage with a 10px gap. There's no arrow anchoring it to the cursor, so the shift at the extremes is imperceptible. Vertical placement was clear at every sample point and is left alone.5. Documentation (
fc3f689)These defects were all invisible in source and only showed up under measurement, so the constraints behind them are now written down.
CLAUDE.mdgains a Typography section:font-synthesis: nonemeans a face missing from the font URL fails silently rather than being synthesised, Space Grotesk stops at 700, italics need the1,...axis, Space Grotesk has atnumtable and DM Sans does not, and webfonts always need a fallback stack.A new
verify-in-browserskill (.claude/skills/) records the Playwright setup for this sandbox and the measurement traps that produce confident wrong answers — chiefly thatdocument.fonts.check()returnstruefor faces that do not exist and so cannot be used to test font availability.Verification
npm run buildpasses; all 245 prerendered pages carry the updated font stylesheet.npm run lint— 0 errors (96 pre-existing warnings, none in the touched files).No unit tests exist for this area, and the change is visual, so verification is the build/lint pair plus the browser measurements above.