fix(website): clear WCAG AA across both themes, and stop the hero shifting

Contrast was measured, not eyeballed: 41 foreground/background pairs across
both themes and the terminal surface, each against the darkest (light) or
lightest (dark) surface it actually sits on. Five failed. Links on manila
read 3.64:1 and the footer's "No telemetry. Ever." — a claim the site goes
out of its way to make — sat at 2.86:1.

The accent needed splitting rather than moving. #c1502e clears 4.5:1 as a
button fill behind white but only 3.99:1 as an 11px eyebrow on vinyl, so
--accent keeps the brand hue for fills and a new --accent-text carries the
readable cut. The terminal gets the same treatment dark emulators give their
palettes: alarm and oxide brighten inside .tui-content so "Failed" is
legible next to its glyph.

Reduced motion no longer nukes everything. A blanket 0.01ms also kills the
transitions that answer a click, which is feedback rather than movement;
looping and travelling animation stops, the rest caps at 80ms. The TUI
already skipped its opening run and still does.

The hero reserves its box with aspect-ratio from the first paint. It was
prerendered at full unscaled height and collapsed once JS measured, moving
everything below it by ~145px. Measured shift is now 0.

Also: the webfont loads non-blocking (display=swap meant the first frame
never waited for it anyway), footer link groups nest under a heading instead
of sitting level with page sections, and eight tokens nothing referenced
stop shipping.
This commit is contained in:
Michel de Graaf
2026-07-25 00:40:13 +02:00
parent 8b8383afdf
commit 74ad230150
13 changed files with 107 additions and 57 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ const CITIZENSHIP = [
},
{
glyph: '∞',
color: 'var(--accent)',
color: 'var(--accent-text)',
title: 'Stay online',
body: (
<>
+4 -4
View File
@@ -22,7 +22,7 @@ const PLATFORMS: readonly { name: OsName; note: string; anchor: string }[] = [
const FEATURES = [
{
glyph: '→',
color: 'var(--accent)',
color: 'var(--accent-text)',
title: 'Search & download',
cmd: 'soulseek-rs "field recordings"',
body: <>Search the network, pick results in the TUI, and queue downloads with pause, resume, and retry.</>,
@@ -86,7 +86,7 @@ const FEATURES = [
},
{
glyph: '▮',
color: 'var(--accent)',
color: 'var(--accent-text)',
title: 'TUI and CLI',
cmd: 'soulseek-rs',
body: (
@@ -165,7 +165,7 @@ export const Home = () => {
>
<OsIcon name={platform.name} className="max-[519px]:size-[26px]" />
<span className="flex flex-col leading-[1.35] max-[519px]:hidden">
<b className="text-[13.5px] font-medium text-primary transition-colors group-hover:text-accent">
<b className="text-[13.5px] font-medium text-primary transition-colors group-hover:text-accent-text">
{platform.name}
</b>
<span className="text-[11.5px] text-secondary">{platform.note}</span>
@@ -251,7 +251,7 @@ export const Home = () => {
<div className="flex flex-col gap-3.5">
<Eyebrow>get started</Eyebrow>
<h2 className="text-[26px] leading-[34px] font-medium text-balance sm:text-title sm:leading-[var(--text-title--line-height)]">
Install it, then press <span className="text-accent">/</span> to search.
Install it, then press <span className="text-accent-text">/</span> to search.
</h2>
<p className="text-secondary">
Needs a Rust toolchain. From there it&rsquo;s one command, then the TUI opens.
+1 -1
View File
@@ -76,7 +76,7 @@ interface StepProps {
const Step = ({ n, title, children }: StepProps) => (
<div className="grid grid-cols-1 gap-3 sm:grid-cols-[auto_1fr] sm:gap-5">
<div className="flex size-[34px] items-center justify-center rounded-md border border-line text-sm text-accent">
<div className="flex size-[34px] items-center justify-center rounded-md border border-line text-sm text-accent-text">
{n}
</div>
<div className="flex min-w-0 flex-col gap-3">