Skip to content

Commit f176b10

Browse files
adrienlacombeclaude
andcommitted
site: polish the explainer against the Impeccable design guidelines
Anti-patterns removed (impeccable.style detector + absolute-ban list): - side-stripe accent borders on the pipeline lanes and Freivalds callout, replaced with hue-tinted full borders and backgrounds; CSS-triangle arrowheads replaced with clip-path - per-section uppercase tracked eyebrow kickers (8x) removed; the hero keeps the single deliberate kicker - hero metric boxes (big number / small label cards) replaced with one inline mono facts row - decorative gradient chips before card headings removed - Inter (reflex-default face) swapped for Archivo; JetBrains Mono kept Real defects found while verifying in a headless browser: - .start and .arch grids blew out horizontally (grid min-width:auto vs wide <pre> content), causing page overflow at desktop and mobile - the tamper switch input was display:none, so it could not be focused or toggled from the keyboard; now visually-hidden + focus ring - the closed off-canvas mobile menu stayed in the tab order; now visibility-hidden when closed - the shared focus-visible rule forced border-radius 6px, visibly reshaping pill buttons on keyboard focus - tier tabs lacked the ARIA tabs keyboard pattern; arrow/Home/End keys and roving tabindex added Plus: skip-to-content link, theme-color meta, 44px nav-toggle target, text-wrap balance/pretty, label sizes raised off the 10px floor, hyphenation consistency (Fiat-Shamir, multi-head, 6-block/16-head/192-dim), and scroll reveals no longer gate section headings. Verified at 1440px and 390px in headless Chromium: no console errors, no horizontal scroll, screenshots inspected. Detector findings reduced from 7 to 2 (both remaining are false positives: it misses the second family in the same Google Fonts URL and counts HTML comments / CLI --flags as em-dashes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a6e9a0a commit f176b10

4 files changed

Lines changed: 83 additions & 48 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ entry.
3030

3131
### Changed
3232

33+
- Polished the explainer site against the Impeccable design guidelines: removed
34+
the AI-default scaffolding (per-section uppercase eyebrow kickers, side-stripe
35+
accent borders, hero metric boxes, decorative card chips), swapped the body
36+
face from Inter to Archivo, and fixed real defects found while verifying in a
37+
browser — grid blowouts that caused horizontal page scroll (`.start`, `.arch`),
38+
a tamper switch that could not be toggled from the keyboard, the closed mobile
39+
menu remaining in the tab order, a focus ring that reshaped pill buttons, and
40+
missing arrow-key navigation on the tier tabs.
41+
3342
- **The `prove-predictor` demo path is now commitment-bound** (#187): the full
3443
6-block predictor (synthetic and `--profile real`) routes through
3544
`pwm_prover::prove_predictor``PredictorArtifact` and is verified by

website/assets/css/style.css

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
--radius-sm: 10px;
1919
--maxw: 1120px;
2020
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
21-
--sans: "Inter", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
21+
--sans: "Archivo", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
2222
--shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.6);
2323
}
2424

@@ -35,15 +35,24 @@ body {
3535
}
3636
a { color: inherit; text-decoration: none; }
3737
code { font-family: var(--mono); font-size: 0.92em; color: var(--accent); }
38-
h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0; }
38+
h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0; text-wrap: balance; }
39+
p { text-wrap: pretty; }
40+
41+
/* skip link: hidden until keyboard-focused */
42+
.skip-link {
43+
position: absolute; top: -48px; left: 16px; z-index: 100;
44+
padding: 10px 18px; border-radius: 0 0 10px 10px;
45+
background: var(--accent); color: #06231f; font-weight: 600; font-size: 0.9rem;
46+
transition: top 0.15s ease;
47+
}
48+
.skip-link:focus-visible { top: 0; }
3949

4050
/* layout */
4151
.band { max-width: var(--maxw); margin: 0 auto; padding: 96px 24px; }
4252
.band.alt { max-width: none; background: var(--bg-2); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
4353
.band.alt > * { max-width: var(--maxw); margin-left: auto; margin-right: auto; }
4454
.section-head { max-width: 760px; margin: 0 auto 48px; text-align: center; }
4555
.section-head h2 { font-size: clamp(1.7rem, 3.4vw, 2.6rem); font-weight: 800; }
46-
.kicker { display: inline-block; font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); margin-bottom: 14px; }
4756
.section-sub { color: var(--muted); margin-top: 16px; font-size: 1.05rem; }
4857

4958
/* nav */
@@ -62,16 +71,17 @@ h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; margin: 0; }
6271
.nav-links a:hover { color: var(--text); }
6372
.nav-cta { padding: 8px 16px; border: 1px solid var(--border); border-radius: 999px; color: var(--text) !important; }
6473
.nav-cta:hover { border-color: var(--accent); }
65-
.nav-toggle { display: none; background: none; border: none; color: var(--text); font-size: 1.6rem; cursor: pointer; }
74+
.nav-toggle { display: none; background: none; border: none; color: var(--text); font-size: 1.6rem; cursor: pointer; min-width: 44px; min-height: 44px; }
6675

67-
/* keyboard focus: a visible ring on every interactive element */
76+
/* keyboard focus: a visible ring on every interactive element. The outline
77+
follows each element's own border-radius; don't override the shape here. */
6878
a:focus-visible,
6979
.btn:focus-visible,
7080
.tier-tab:focus-visible,
7181
.nav-toggle:focus-visible,
7282
.nav-cta:focus-visible,
73-
.switch:focus-within,
74-
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
83+
.switch:has(input:focus-visible),
84+
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
7585

7686
/* buttons */
7787
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 22px; border-radius: 999px; font-weight: 600; font-size: 0.95rem; cursor: pointer; border: 1px solid transparent; transition: transform 0.15s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease; }
@@ -89,10 +99,10 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
8999
.hero h1 { font-size: clamp(2.4rem, 6vw, 4.2rem); font-weight: 800; letter-spacing: -0.03em; }
90100
.lede { color: var(--muted); font-size: clamp(1.02rem, 1.6vw, 1.22rem); max-width: 720px; margin: 26px auto 0; }
91101
.hero-cta { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin: 36px 0 12px; }
92-
.hero-stats { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin: 40px 0 28px; }
93-
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px 22px; min-width: 170px; }
94-
.stat-num { display: block; font-family: var(--mono); font-size: 1.5rem; font-weight: 700; color: var(--accent); }
95-
.stat-label { color: var(--muted-2); font-size: 0.84rem; }
102+
.hero-facts { display: flex; gap: 10px 0; justify-content: center; align-items: center; flex-wrap: wrap; margin: 40px auto 28px; font-family: var(--mono); font-size: 0.88rem; color: var(--muted); max-width: 760px; }
103+
.hero-facts .fact { white-space: nowrap; }
104+
.hero-facts code { font-size: 1em; }
105+
.hero-facts .fact + .fact::before { content: "·"; margin: 0 14px; color: var(--border); font-weight: 700; }
96106
.honesty { max-width: 680px; margin: 8px auto 0; padding: 16px 20px; border: 1px dashed var(--border); border-radius: var(--radius-sm); color: var(--muted); font-size: 0.92rem; background: rgba(167, 139, 250, 0.05); }
97107
.honesty strong { color: var(--accent-2); }
98108

@@ -102,8 +112,9 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
102112

103113
/* flow */
104114
.flow-controls { display: flex; gap: 16px; align-items: center; justify-content: center; flex-wrap: wrap; margin-bottom: 36px; }
105-
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; color: var(--muted); font-size: 0.92rem; }
106-
.switch input { display: none; }
115+
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; color: var(--muted); font-size: 0.92rem; position: relative; border-radius: 999px; }
116+
/* visually hidden but focusable, so the tamper switch works from the keyboard */
117+
.switch input { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; clip-path: inset(50%); overflow: hidden; white-space: nowrap; }
107118
.switch-track { width: 44px; height: 24px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); position: relative; transition: background 0.2s; }
108119
.switch-thumb { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: var(--muted); transition: transform 0.2s, background 0.2s; }
109120
.switch input:checked + .switch-track { background: rgba(251, 113, 133, 0.25); border-color: var(--bad); }
@@ -163,7 +174,6 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
163174
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 26px; transition: transform 0.2s, border-color 0.2s; }
164175
.card:hover { transform: translateY(-4px); border-color: var(--accent); }
165176
.card h3 { font-size: 1.15rem; margin-bottom: 10px; }
166-
.card h3::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 10px; background: linear-gradient(135deg, var(--accent), var(--accent-2)); }
167177
.card p { color: var(--muted); font-size: 0.94rem; margin: 0; }
168178

169179
/* tiers */
@@ -192,6 +202,8 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
192202

193203
/* architecture */
194204
.arch { display: grid; grid-template-columns: 1.3fr 1fr; gap: 28px; align-items: center; }
205+
/* min-width: 0 lets the dag pre scroll inside its column instead of widening it */
206+
.arch > * { min-width: 0; }
195207
.arch-crates { display: flex; flex-direction: column; gap: 12px; }
196208
.crate { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 16px 20px; }
197209
.crate code { color: var(--accent); font-weight: 700; }
@@ -202,7 +214,9 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
202214

203215
/* start */
204216
.start { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
205-
.start-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; }
217+
/* min-width: 0 lets the column shrink below the pre's intrinsic width, so long
218+
command lines scroll inside the card instead of blowing out the page. */
219+
.start-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; min-width: 0; }
206220
.start-card h3 { font-size: 1.1rem; margin-bottom: 14px; }
207221
.code { background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 18px; font-family: var(--mono); font-size: 0.88rem; color: var(--text); overflow-x: auto; white-space: pre; line-height: 1.7; margin: 0; }
208222
.c-dim { color: var(--muted-2); }
@@ -222,11 +236,15 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
222236

223237
/* responsive */
224238
@media (max-width: 820px) {
225-
.nav-links { position: fixed; top: 60px; right: 0; flex-direction: column; align-items: flex-start; gap: 18px; background: var(--surface); border: 1px solid var(--border); border-radius: 0 0 0 var(--radius); padding: 24px; transform: translateX(110%); transition: transform 0.25s ease; }
226-
.nav-links.open { transform: none; }
239+
/* visibility keeps the closed off-canvas menu out of the tab order and out
240+
of the page's scroll width */
241+
.nav-links { position: fixed; top: 60px; right: 0; flex-direction: column; align-items: flex-start; gap: 18px; background: var(--surface); border: 1px solid var(--border); border-radius: 0 0 0 var(--radius); padding: 24px; transform: translateX(110%); visibility: hidden; transition: transform 0.25s ease, visibility 0.25s; }
242+
.nav-links.open { transform: none; visibility: visible; }
227243
.nav-toggle { display: block; }
228244
.why-cols, .frei, .arch, .start { grid-template-columns: 1fr; }
229245
.band { padding: 64px 20px; }
246+
.hero-facts { flex-direction: column; gap: 8px; }
247+
.hero-facts .fact + .fact::before { content: none; }
230248
}
231249
@media (prefers-reduced-motion: reduce) {
232250
* { animation: none !important; transition: none !important; scroll-behavior: auto; }
@@ -252,8 +270,8 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
252270

253271
/* lanes */
254272
.pflow-lane{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--radius);padding:16px;position:relative;}
255-
.pflow-lane--prover{border-left:3px solid var(--accent);}
256-
.pflow-lane--verifier{border-left:3px solid var(--accent-3);}
273+
.pflow-lane--prover{border-color:color-mix(in srgb, var(--accent) 35%, var(--border));background:linear-gradient(180deg, rgba(94, 234, 212, 0.04), transparent 55%), var(--bg-2);}
274+
.pflow-lane--verifier{border-color:color-mix(in srgb, var(--accent-3) 35%, var(--border));background:linear-gradient(180deg, rgba(56, 189, 248, 0.04), transparent 55%), var(--bg-2);}
257275
.pflow-lane-head{display:flex;align-items:baseline;gap:12px;margin-bottom:14px;flex-wrap:wrap;}
258276
.pflow-lane-tag{font-family:var(--mono);font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;font-weight:700;color:#06231f;background:var(--accent);padding:4px 12px;border-radius:999px;}
259277
.pflow-lane-tag--v{color:#04141f;background:var(--accent-3);}
@@ -270,13 +288,13 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
270288
.pflow-card p{color:var(--muted);font-size:.84rem;line-height:1.5;margin:0;}
271289
.pflow-card--emph{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent),0 16px 36px -24px var(--accent);}
272290

273-
/* horizontal connectors: gradient bar + arrowhead */
291+
/* horizontal connectors: gradient bar + clip-path arrowhead */
274292
.pflow-card::after{content:"";position:absolute;top:50%;left:100%;width:26px;height:2px;transform:translateY(-50%);background:linear-gradient(90deg,var(--accent),var(--accent-3));opacity:.85;}
275-
.pflow-card::before{content:"";position:absolute;top:50%;left:calc(100% + 22px);width:0;height:0;transform:translateY(-50%);border-left:6px solid var(--accent-3);border-top:4px solid transparent;border-bottom:4px solid transparent;opacity:.95;}
293+
.pflow-card::before{content:"";position:absolute;top:50%;left:calc(100% + 22px);width:7px;height:9px;transform:translateY(-50%);background:var(--accent-3);clip-path:polygon(0 0, 100% 50%, 0 100%);opacity:.95;}
276294
.pflow-track > .pflow-card:last-child::after,
277295
.pflow-track > .pflow-card:last-child::before{display:none;}
278296
.pflow-card--v::after{background:linear-gradient(90deg,var(--accent-3),var(--accent-2));}
279-
.pflow-card--v::before{border-left-color:var(--accent-2);}
297+
.pflow-card--v::before{background:var(--accent-2);}
280298
/* verifier lane flows vertically (Verify then Verdict), so the full-width Verify
281299
card has no card to its right: hide its horizontal connector on wide screens.
282300
The mobile query below re-enables it as a downward link. */
@@ -290,7 +308,7 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
290308
/* crossing block */
291309
.pflow-cross{position:relative;display:flex;flex-direction:column;align-items:center;gap:10px;padding:2px 0;}
292310
.pflow-boundary{position:relative;width:100%;height:1px;background:repeating-linear-gradient(90deg,var(--border) 0 10px,transparent 10px 18px);display:flex;justify-content:center;}
293-
.pflow-boundary span{position:relative;top:-9px;font-family:var(--mono);font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted-2);background:var(--bg);padding:0 10px;}
311+
.pflow-boundary span{position:relative;top:-9px;font-family:var(--mono);font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;color:var(--muted-2);background:var(--bg);padding:0 10px;}
294312
.pflow-artifact{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:center;text-align:center;background:linear-gradient(135deg,rgba(167,139,250,.16),rgba(94,234,212,.10));border:1px solid var(--accent-2);border-radius:999px;padding:9px 20px;box-shadow:0 0 0 1px rgba(167,139,250,.25),0 14px 34px -20px var(--accent-2);}
295313
.pflow-artifact-tag{font-family:var(--mono);font-size:.84rem;font-weight:700;color:var(--accent-2);letter-spacing:.02em;}
296314
.pflow-artifact-body{font-family:var(--mono);font-size:.8rem;color:var(--text);}
@@ -301,8 +319,8 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
301319
.pflow-card--v{grid-column:1 / -1;}
302320

303321
/* Freivalds callout */
304-
.pflow-frei{margin-top:14px;padding:14px;background:var(--bg-2);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:var(--radius-sm);display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;}
305-
.pflow-frei-head{flex-basis:100%;font-family:var(--mono);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);}
322+
.pflow-frei{margin-top:14px;padding:14px;background:linear-gradient(180deg, rgba(94, 234, 212, 0.05), transparent 70%), var(--bg-2);border:1px solid color-mix(in srgb, var(--accent) 32%, var(--border));border-radius:var(--radius-sm);display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;}
323+
.pflow-frei-head{flex-basis:100%;font-family:var(--mono);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);}
306324
.pflow-frei-eq{font-family:var(--mono);font-size:1.02rem;font-weight:700;color:var(--text);background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:6px 12px;}
307325
.pflow-frei-why{font-family:var(--mono);font-size:.78rem;color:var(--muted);}
308326
.pflow-frei-note{flex-basis:100%;font-size:.74rem;color:var(--muted-2);line-height:1.5;margin-top:6px;padding-top:8px;border-top:1px dashed var(--border);}
@@ -334,9 +352,9 @@ button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; bo
334352
@media (max-width:560px){
335353
.pflow-track,.pflow-track--v{grid-template-columns:1fr;gap:24px;}
336354
.pflow-card::after{content:"";display:block;top:100%;left:50%;width:2px;height:24px;transform:translateX(-50%);background:linear-gradient(180deg,var(--accent),var(--accent-3));}
337-
.pflow-card::before{content:"";display:block;top:calc(100% + 20px);left:50%;width:0;height:0;transform:translateX(-50%);border-top:6px solid var(--accent-3);border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:0;}
355+
.pflow-card::before{content:"";display:block;top:calc(100% + 20px);left:50%;width:9px;height:7px;transform:translateX(-50%);background:var(--accent-3);clip-path:polygon(0 0, 100% 0, 50% 100%);}
338356
.pflow-card--v::after{background:linear-gradient(180deg,var(--accent-3),var(--accent-2));}
339-
.pflow-card--v::before{border-top-color:var(--accent-2);}
357+
.pflow-card--v::before{background:var(--accent-2);}
340358
.pflow-track > .pflow-card:last-child::after,
341359
.pflow-track > .pflow-card:last-child::before{display:none;}
342360
.pflow-artifact{border-radius:var(--radius);flex-direction:column;gap:6px;padding:14px 18px;}

website/assets/js/app.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
}
2222
const reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2323

24-
// --- reveal on scroll ---
25-
const revealTargets = $$(".section-head, .card, .flow-step, .crate, .start-card, .stat, .tiers, .compare, .frei");
24+
// --- reveal on scroll (interactive boards and card grids only; headings and
25+
// hero content are visible immediately, never gated on a scroll transition) ---
26+
const revealTargets = $$(".card, .flow-step, .crate, .start-card, .tiers, .compare, .frei");
2627
revealTargets.forEach((el) => el.classList.add("reveal"));
2728
if ("IntersectionObserver" in window) {
2829
const io = new IntersectionObserver(
@@ -174,17 +175,30 @@
174175
renderCheck();
175176
}
176177

177-
// --- tier tabs ---
178+
// --- tier tabs (ARIA tabs pattern: click + arrow keys, roving tabindex) ---
178179
const tabs = $$(".tier-tab");
179180
if (tabs.length) {
180-
tabs.forEach((tab) => tab.addEventListener("click", () => {
181+
const select = (tab) => {
181182
const tier = tab.dataset.tier;
182183
tabs.forEach((t) => {
183184
const on = t === tab;
184185
t.classList.toggle("is-active", on);
185186
t.setAttribute("aria-selected", on ? "true" : "false");
187+
t.setAttribute("tabindex", on ? "0" : "-1");
186188
});
187189
$$(".tier-panel").forEach((p) => p.classList.toggle("is-active", p.dataset.tier === tier));
188-
}));
190+
};
191+
tabs.forEach((tab, i) => {
192+
tab.setAttribute("tabindex", tab.classList.contains("is-active") ? "0" : "-1");
193+
tab.addEventListener("click", () => select(tab));
194+
tab.addEventListener("keydown", (e) => {
195+
const delta = { ArrowRight: 1, ArrowLeft: -1, Home: -i, End: tabs.length - 1 - i }[e.key];
196+
if (delta === undefined) return;
197+
e.preventDefault();
198+
const next = tabs[(i + delta + tabs.length) % tabs.length];
199+
select(next);
200+
next.focus();
201+
});
202+
});
189203
}
190204
})();

0 commit comments

Comments
 (0)