WQI.web​qualityindex

/ / design

Web Quality Index design system.

A clinical, restrained, monochrome reference for a public-utility data product. Derived from Tranco, Internet.nl, and Have I Been Pwned. The page you are on is the manual: every token enumerated, every primitive shown in use.

Built on tokens.css + typography.css + global.css.

Color tokens

Single source of truth. Anything that needs a color reads from here. Hex values shown for review only — never hard-code them.

Surfaces

--bg #fafaf7 page background
--bg-alt #f3f3f0 subtle alt fill (zebra rows, n/a tiles)
--bg-hi #ffffff panel background — score block, vendor card

Foreground

--fg #111111 primary text
--fg-mute #555555 metadata, captions, table headers
--fg-faint #8a8a85 n/a, deemphasized, breadcrumbs

Rules

--rule #d8d6cf hairline divider
--rule-hard #1a1a1a section break, primary button, focus

Live accent

The only non-monochrome color outside the verdict scale. Reserved for live-data signals: the pulsing dot in the method banner, the "live" badge, and selection highlights.

--live #006e51 live-data accent — the only color outside verdicts
--live-bg #d8efe5 live badge fill

Verdict tones

Three semantic tones, each as a fg + bg pair. Desaturated on purpose — the data has to feel measured, not alarming. Used by GradeCell, GradePill, VerdictPill, score-heat cells, and DeltaCell.

--pass #1f6f3a
--pass-bg #e2efe3
--warn #8a6d00
--warn-bg #f4ecc8
--fail #913026
--fail-bg #f1d9d4

Typography

Two variable fonts. Newsreader (display serif) carries h1 and the homepage hero. Inter Variable carries body and h2/h3 sans. System monospace stack carries every numeric, table header, and metadata pill.

Newsreader Display — var(--font-display)
Aa

The web is critical infrastructure.

Inter Body — var(--font-ui)
Aa

Same rules for every site. Nobody — including us — can move a score without changing the methodology in public, with a version bump and a logged reason.

Mono numerics — var(--font-mono)
1234567890

WQI v0.5.0 · 86 live / 86 total factors · scanned 2026-04-27

Type scale

Grade primitives

Four small Astro components live in src/components/primitives/. Each renders a single CSS-class pattern with consistent props. Use these — don't reach for the raw .gcell or .verdict-pill classes from page templates.

GradeCell — 28×28 (md) or 24×24 (sm) heatmap tile

A B C D F
A B C D F
<GradeCell grade={letter} />
<GradeCell grade={letter} size="sm" />
<GradeCell grade={letter} transition:name={`vendor-grade-${slug}`} />

GradePill — inline tinted pill, used inside .identity-strip

A · B · C · D · F ·

<GradePill grade={letter} transition:name={`vendor-grade-${slug}`} />

VerdictPill — uppercase tag for verdict columns + counts

42 pass 7 warn 3 fail 1 n/a · pass warn fail na

<VerdictPill verdict="pass">{count} pass</VerdictPill>
<VerdictPill verdict="fail" /> {/* falls back to literal "fail" label */}

DeltaCell — signed-percentage cell, color reflects sign

CaseΔ
positive, positive-is-bad (default)+12.3%
positive, positive-is-good+12.3%
negative, positive-is-bad (default)-4.0%
negative, positive-is-good (goodWhenNegative)-4.0%
zero0%
null / unmeasured
<DeltaCell value={f.delta_pct} />                  {/* default: + is bad */}
<DeltaCell value={f.delta_pct} goodWhenNegative />  {/* flip the polarity */}

Data table

The .dt-data class is the dense scorecard table used on /vendors and /vendor/:slug. Sticky header, hairline row dividers, monospace numerics, 1px accent slide-in on row hover (look at the left edge as your cursor enters a row).

# Grade Score Agency Scored Portfolio
1 A 94.2 Internet.nl Reference internet.nl 312 312
2 B 81.7 Tranco Top-Tier Hosts tranco-list.eu 248 260
3 C 72.0 Have I Been Pwned haveibeenpwned.com 1 1
4 D 64.5 Sample Mid-Pack Agency midpack.example 18 32
5 F 41.2 Sample Low-Score Vendor lowscore.example 4 12

Column helper classes

Identity strip

Single-line metadata pill at the top of every data page. Replaces the old hero gauge / score block. The grade pill is the lede; the rest is whatever metadata the page has — composite, verdict counts, scan timestamp, attribution, etc. Wraps freely on narrow viewports.

example.com · B 82/100 composite · 78/86 factors scored · 62 pass 12 warn 4 fail · method v0.5.0 · scanned 2026-04-27

<p class="identity-strip">
  <GradePill grade={letter} />
  <span><strong>{score}</strong>/100 composite</span>
  <span>·</span>
  <VerdictPill verdict="pass">{n} pass</VerdictPill>
  ...
</p>

Facts grid

Compact 4-column label/value grid. Two pairs per row at desktop, stacks to 2-column on mobile. Used on /d/:domain for site-facts. Don't use it for prose — it's deliberately hairline-dense.

Hosting
Cloudflare (US)
DNS provider
Cloudflare
Platform
WordPress
Email provider
Google Workspace
DMARC policy
reject
Domain age
7.4 years
<div class="facts-grid">
  <div class="fact-k">Hosting</div>
  <div class="fact-v">Cloudflare (US)</div>
  ...
</div>

Spacing scale

4px base. Every margin and padding pulls from this — vertical rhythm only holds if you don't reach for arbitrary 0.7rem values. If you find yourself wanting one, the answer is almost always "round to the nearest token."

Motion

All transitions consume the duration + easing tokens. Reduced-motion users get instant changes via the media-query override in tokens.css.

TokenValueWhen to use
--dur-fast 120ms hover/focus state changes, table row tint
--dur-medium 220ms view-transition morphs (default)
--dur-slow 400ms rare — only when distance traveled is large
--ease-out cubic-bezier(0.16, 1, 0.3, 1) outbound motion (entering, expanding)
--ease-std cubic-bezier(0.4, 0, 0.2, 1) all-other transitions (recolor, hover)

What NOT to do