Redesign in Prime Intellect's design language, both themes, three viewports
ci / web (push) Successful in 2m42s
ci / python (push) Successful in 3m8s

Eighteen agents: three design directions judged on whether a COO on a phone
actually learns what an environment is, on craft, and on landing without a
rewrite; one spec; a foundation of measured tokens; six build lanes; three
browser verifiers; a final gate pass.

The materials are Prime Intellect's, measured from their site: near-black
grounds, one green, sharp radii, mono small-caps labels, Geist and Geist Mono
self-hosted because production CSP is font-src 'self'. Two of their own greys
fail contrast on their own ground (#737373 is 4.02:1, #6E6E6E is 3.73:1 on
#0F0F0F), so --muted is lifted and the CSS comment carries the number — or
someone will 'correct' it back. Every text-on-ground pair in both themes is
tabulated in src/index.css with its measured ratio.

The two rules that resolved every conflict: data is mono, sentences are sans;
the language wins on materials, the lesson wins on legibility. Light mode is a
finished paper theme, not an inversion.

What did not change: the derived-tabs contract, the honesty markers, the
isolation lint, every gate. 419 contract checks, entry chunk at 74% of budget,
zero horizontal overflow on any route at 390/1024/1440 in either theme.

Also flips Alert Triage to status 'live' — the pipeline built it but never
promoted it, so it was badged SPEC on its own playable page and the home page
counted one environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mt6sHQHEnEYrJZvoMCJSB
This commit is contained in:
karti-ai
2026-08-28 21:41:15 -07:00
parent af15ba584e
commit a21596b3e4
85 changed files with 4717 additions and 2230 deletions
+75 -7
View File
@@ -7,7 +7,9 @@ import animate from 'tailwindcss-animate';
*
* The palette is PIG's, inlined as literals rather than injected at runtime:
* this site has no user-chosen accent, so a runtime theme layer would be a
* moving part that buys nothing.
* moving part that buys nothing. Every value here is `hsl(var(--token))` —
* the triples themselves, with their measured contrast ratios, live in
* src/index.css. Nothing in this file is a raw colour.
*/
/** @type {import('tailwindcss').Config} */
export default {
@@ -20,11 +22,16 @@ export default {
background: 'hsl(var(--bg))',
surface: 'hsl(var(--surface))',
'surface-2': 'hsl(var(--surface-2))',
'surface-3': 'hsl(var(--surface-3))',
border: 'hsl(var(--border))',
// The only boundary token that clears 3:1 as a non-text signal. Inputs,
// selects, outline chips and icons at rest use it; `border` is decorative.
'border-strong': 'hsl(var(--border-strong))',
input: 'hsl(var(--border))',
ring: 'hsl(var(--accent))',
ring: 'hsl(var(--ring))',
fg: 'hsl(var(--fg))',
foreground: 'hsl(var(--fg))',
'fg-2': 'hsl(var(--fg-2))',
muted: 'hsl(var(--muted))',
'muted-foreground': 'hsl(var(--muted))',
// shadcn's `accent` is its SUBTLE hover surface, not the brand. Mapping
@@ -34,15 +41,24 @@ export default {
brand: 'hsl(var(--accent))',
'accent-fg': 'hsl(var(--accent-fg))',
'accent-on': 'hsl(var(--accent-on))',
'accent-edge': 'hsl(var(--accent-edge))',
'accent-subtle': 'hsl(var(--accent-subtle))',
// The tab bar's 2px state bar: accent in dark, accent-fg in light, so
// the trigger needs one class and no theme variant.
'tab-underline': 'hsl(var(--tab-underline))',
primary: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-on))' },
secondary: { DEFAULT: 'hsl(var(--surface-2))', foreground: 'hsl(var(--fg))' },
card: { DEFAULT: 'hsl(var(--surface))', foreground: 'hsl(var(--fg))' },
popover: { DEFAULT: 'hsl(var(--surface))', foreground: 'hsl(var(--fg))' },
destructive: { DEFAULT: 'hsl(var(--danger))', foreground: 'hsl(0 0% 100%)' },
// `danger-on`, not white: white on the dark theme's red is 3.63:1.
destructive: { DEFAULT: 'hsl(var(--danger))', foreground: 'hsl(var(--danger-on))' },
positive: 'hsl(var(--positive))',
warning: 'hsl(var(--warning))',
'warning-on': 'hsl(var(--warning-on))',
'warning-subtle': 'hsl(var(--warning-subtle))',
danger: 'hsl(var(--danger))',
'danger-on': 'hsl(var(--danger-on))',
'danger-subtle': 'hsl(var(--danger-subtle))',
info: 'hsl(var(--info))',
// The board's three tile states. Named by MEANING, not by colour, so
// the high-contrast palette can swap the values without renaming.
@@ -53,16 +69,68 @@ export default {
'present-fg': 'hsl(var(--tile-present-fg))',
absent: 'hsl(var(--tile-absent))',
'absent-fg': 'hsl(var(--tile-absent-fg))',
// An unplayed tile's edge (`border-tile-empty`).
empty: 'hsl(var(--tile-empty-border))',
},
},
fontFamily: {
sans: ['Manrope Variable', 'Avenir Next', 'ui-sans-serif', 'system-ui', 'sans-serif'],
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
sans: ['Geist Variable', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
mono: ['Geist Mono Variable', 'ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
},
borderRadius: { md: '0.5rem', lg: '0.75rem', xl: '1rem' },
/*
* The type scale (spec §3). Sans unless the name says mono; the face is
* still applied by `font-mono` on the element, these only fix size,
* leading, weight and tracking. Responsive steps are the `-lg` / `-xl`
* siblings (`text-display lg:text-display-lg xl:text-display-xl`).
* Weight ceiling is 600 everywhere.
*/
fontSize: {
display: ['2.25rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
'display-lg': ['3rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
'display-xl': ['3.5rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
h1: ['1.75rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
'h1-lg': ['2rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
h2: ['1.5rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
'h2-lg': ['1.875rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
h3: ['1.125rem', { lineHeight: '1.3', fontWeight: '600', letterSpacing: '-0.01em' }],
lede: ['1.125rem', { lineHeight: '1.5', fontWeight: '400' }],
'lede-lg': ['1.25rem', { lineHeight: '1.5', fontWeight: '400' }],
// The tab claim: never mono, never uppercase, never shortened.
claim: ['1.125rem', { lineHeight: '1.35', fontWeight: '500' }],
'claim-lg': ['1.25rem', { lineHeight: '1.35', fontWeight: '500' }],
// The education floor. Nothing that explains is ever smaller.
prose: ['1rem', { lineHeight: '1.6', fontWeight: '400' }],
ui: ['0.875rem', { lineHeight: '1.4' }],
small: ['0.8125rem', { lineHeight: '1.45', fontWeight: '400' }],
caption: ['0.75rem', { lineHeight: '1.4' }],
// mono, uppercase — pair with `font-mono uppercase`.
label: ['0.6875rem', { lineHeight: '1.2', fontWeight: '500', letterSpacing: '0.04em' }],
'mono-data': ['0.8125rem', { lineHeight: '1.4', fontWeight: '400' }],
stat: ['0.8125rem', { lineHeight: '1.4', fontWeight: '600' }],
metric: ['2rem', { lineHeight: '1.1', fontWeight: '600', letterSpacing: '-0.01em' }],
// The landing's 0% → ~60% figure.
figure: ['2.5rem', { lineHeight: '1', fontWeight: '500', letterSpacing: '-0.02em' }],
'figure-lg': ['3.5rem', { lineHeight: '1', fontWeight: '500', letterSpacing: '-0.02em' }],
code: ['0.8125rem', { lineHeight: '1.6' }],
},
letterSpacing: { label: '0.04em' },
// A real four-step scale. 4px tiles/cells, 6px controls, 8px inner blocks,
// 12px surfaces. Named aliases resolve to the same CSS variables index.css
// declares, so a component can say what it means (`rounded-control`).
borderRadius: {
sm: '0.25rem',
md: '0.375rem',
lg: '0.5rem',
xl: '0.75rem',
tile: 'var(--radius-tile)',
control: 'var(--radius-control)',
surface: 'var(--radius-surface)',
},
// Overlays only. Flat components carry no shadow; borders do the work.
boxShadow: { overlay: 'var(--shadow-overlay)' },
maxWidth: { canvas: '80rem', measure: 'var(--measure)', 'measure-wide': 'var(--measure-wide)' },
transitionDuration: { 1: 'var(--dur-1)', 2: 'var(--dur-2)', 3: 'var(--dur-3)' },
transitionTimingFunction: { enter: 'var(--ease-out)', exit: 'var(--ease-in)' },
maxWidth: { canvas: '80rem' },
},
},
plugins: [animate],