Skip to content

Commit aa88fe6

Browse files
bloveclaude
andauthored
feat(website): ATC theme spike — aviation yellow, Archivo Black, scope navy (#1058)
* docs: spec — ATC theme spike (aviation yellow) for the website Reskins the website to the visual language of ATC — Live Air Traffic Radio: aviation yellow #FFAF00, Archivo Black display type, and instrument-panel data strips. Built in libs/design-tokens rather than as a website override, so the spike measures what adopting the theme actually costs. The central finding is that the accent role has to split: #FFAF00 on white is 1.84:1, so yellow is a fill colour only and the interactive ink moves to the app's scope navy #15253E (15.37:1, higher than the #004090 it replaces). The focus ring deliberately stays navy on light surfaces. Records the load-bearing risk: the homepage architecture diagram e2e added by #1048 measures text runs against their cards after document.fonts.ready, and Archivo's metrics differ from Inter's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: spec — diagrams keep Inter via a --font-diagram token Diagrams do not take the brand face. They stay clean and minimal on Inter through a new --font-diagram token, for two reasons: a heavy grotesk fights a 16-node drawing, and the diagram geometry is tuned to Inter's metrics. That second reason is the load-bearing one. EnterpriseArchitecture pins every rectangle to an 8px grid and home-architecture.spec.ts measures each rendered text run against its card, so swapping diagrams to Archivo would force a geometry rework that could exceed the retheme itself. Keeping Inter makes it zero. The carve-out is three declarations — .arch-figure text in landing.css, and the two sans rules in the docs diagram kit — which the mechanical --font-inter rename must send to --font-diagram rather than --font-sans. Section 8 now treats the overflow e2e as the gate on that carve-out holding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: implementation plan for the ATC theme spike Eleven tasks, TDD where there is something to assert: the three value-pinning token specs are updated before the values move, so each colour change has a red test first. Notable ordering constraints baked into the plan: - dark.ts needs no edit to `accent` (it derives from accentLight) but does need lines 29-33, which hardcode the old blue. Task 2 makes that a step of its own with a grep that proves no blue survives. - The font-var rename and the --font-diagram carve-out land in ONE commit. Split apart, a blind find-and-replace sends the diagram rules to Archivo and the overflow e2e can fail at 390px only. - The site is visibly broken between Task 4 and Task 5, which the plan says out loud so nobody stops to debug it. Selectors verified against the source rather than guessed: the logo mark takes the signal via `color` (PlaneMark fills with currentColor), and the docs active item is [data-docs-navlink][data-active], already at docs.css:917. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(design-tokens): ATC palette — the accent role splits into navy ink and yellow signal Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: card COLOURS are in scope; only its bundled font is not A guard that compares values at test time cannot be satisfied by declaring the divergence intentional in prose. card.spec.ts reads theme.css and asserts card/tokens.ts still matches it, so the earlier scope boundary just left nx test website red for the rest of the arc. Colours are hex literals and cost nothing to move; the font genuinely needs a bundled TTF. Splitting those. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(design-tokens): card colours follow the retheme; guard the dark accent tints The Satori social card hand-copies the light palette as hex literals, because Satori cannot read CSS variables, and card.spec.ts reads theme.css at test time and asserts the copy still matches. So the retheme left two guards red: ink and accent had moved in the tokens and not in the card. A spec that compares values at test time cannot be satisfied by declaring the divergence intentional in prose — the only way to make it green is to move the card, so the card's ink, accent, accent-surface and accent-border now follow the ATC palette. Only the card's bundled font stays out of scope. Also adds the guard the retheme was missing: darkOverrides.accent derives from brand.accentLight and flips on a repoint, while the four accent tints beside it are hardcoded rgba() and do not. The new dark-theme test derives the expected RGB triple from the token rather than pinning a second literal, so it moves with the palette; it was mutation-checked by reverting accentGlow to the old blue and confirming it goes red. The rest is honesty upkeep on comments the retheme falsified: a dark test named for a blue accent it no longer asserts, an accent-family comment, and the generator docstring that still called the cockpit fallback divergence "minor drift" when those fallbacks are now a different hue entirely. base.ts hoists AVIATION_YELLOW and SCOPE_NAVY so signal cannot drift from accentLight, nor scope from accent. No emitted value changes except #ffc233 -> #FFC233. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: add a sweep task for the 21 hardcoded brand colours the plan missed Task 2's review found the plan named only 3 of 24 hardcoded old-brand sites in apps/website/src. The rest would have survived the retheme as blue islands. Includes the one site that must NOT take the yellow: ChatLandingCodeShowcase's --chat-user-bg sits directly above --chat-user-color: #ffffff, so white on aviation yellow would be 1.84:1. It takes scope navy instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(design-tokens): emit signal, signal-strong, scope, alert and ink Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(design-tokens): guard cssVars brand emission; explain the deliberate aliases A reviewer proved by mutation that deleting all five brand names (--ds-signal, --ds-signal-strong, --ds-scope, --ds-alert, --ds-ink) from css-vars.ts left the full design-tokens suite green: the existing ds-var-sources-agree.spec.ts only checks that tokens.css is a superset of cssVars(), which is correct for the type scale but wrong for brand colors, which have no reason to exist in one emitter and not the other. - Add a scoped reverse check to ds-var-sources-agree.spec.ts asserting cssVars('light') emits all five brand names, without making the whole comparison bidirectional (which would break on the legitimate type-scale superset). - Fix the ds-var-contract.spec.ts docstring, which claimed the list is derived purely from a grep of consumer usage — false for the five new brand names (zero references outside libs/design-tokens/ today) and a trap that would lead someone to "clean up" and delete the guard. - Document the deliberate --color-signal/accent-light and --color-scope/accent duplication in theme.css, and add a Brand sub-header to the --ds-* block in tokens.css / tokens-dark.css so the generated output explains itself to a website/cockpit author. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(design-tokens): Archivo display and text faces, Inter retained for diagrams Renames fontSerif (EB Garamond) to fontDisplay (Archivo Black) and repoints fontSans at Archivo instead of Inter. Adds a new fontDiagram token that keeps Inter: EnterpriseArchitecture.tsx pins every rectangle to an 8px grid and home-architecture.spec.ts measures each rendered text run against its card after document.fonts.ready, so retyping diagram text to Archivo would silently overflow the cards and force a geometry rework larger than the retheme itself. Diagram surfaces read as information, not brand, and deliberately stay off the brand face. Regenerates theme.css/tokens.css/tokens-dark.css from the new typography values and updates the token<->CSS parity and --ds-* var contract specs accordingly. apps/website and libs/workspace-react still reference the retired --font-garamond/--font-inter names; that rename is a separate follow-up task and is expected to leave the website visually broken until it lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: record the next/font constraint that makes --font-diagram fragile theme.css emits --font-diagram as a raw 'Inter, ...' stack, which next/font's hashed family never matches. If layout.tsx stops supplying the var, diagrams silently fall back to system-ui and every glyph width shifts — defeating the carve-out the token exists for. Only the architecture e2e would notice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(website): --font-display/--font-sans, with diagrams carved out onto --font-diagram The design-tokens generator no longer emits --font-garamond or --font-inter, so every consumer reference in apps/website and libs/workspace-react moves to the new names. layout.tsx's next/font `variable` fields move with them; the faces themselves are swapped in a later task. The diagram carve-out lands here rather than as a follow-up because --font-inter was a single variable doing two jobs: ~100 body-text rules and the diagram text. Renaming it alone would retype the architecture figure and the docs diagram kit from Inter to Archivo, changing every glyph width. EnterpriseArchitecture.tsx pins its rectangles to an 8px grid and e2e/home-architecture.spec.ts measures each rendered text run against its card, so that would land as a red e2e — possibly only at the 390px viewport. Splitting the two commits would mean deliberately committing a broken geometry, so the three diagram declarations move to --font-diagram (Inter, retained for exactly this reason) in the same change: .arch-figure text (landing.css) .tp-diagram-node[data-title="sans"] .tp-diagram-title (docs.css) .tp-diagram-meta (docs.css) Diagram rules already on --font-mono are untouched; mono was never Inter. ui.css's FONTS note gains the constraint that makes --font-diagram fragile: theme.css emits it as a raw `Inter, ...` stack, which next/font's hashed family never matches, so the var has to keep being supplied by next/font in layout.tsx or diagrams fall back to system-ui silently. nx test website and nx test workspace-react pass, but these are jsdom suites that do not resolve CSS custom properties — they cannot detect a wrong font var. The architecture e2e is the real check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(design-tokens): note the next/font constraint on --font-diagram Two documentation fixes from the Task 4 review, both about the diagram carve-out that landed in the previous commit. The fontDiagram docblock explained why diagrams keep Inter but not what keeps them on it: on apps/website the var has to be supplied by next/font in layout.tsx, because the raw `Inter` literal theme.css emits never matches next/font's hashed family name. Cross-referenced to the FONTS note in apps/website/src/styles/ui.css, which now carries the same warning. The ds-var-contract docstring called `--ds-font-serif` "consumer-referenced" in a paragraph that otherwise says the greps for these names come up empty, which read as a contradiction. Reworded to what it actually is: a name this list previously guarded and the retheme retires. Note the review's stated premise was not quite right — `--ds-font-serif` is not reference-free. libs/workspace-react/src/styles/workspace.css still names it as the fallback behind var(--font-display), so the docstring now says so explicitly instead of dropping the fact, and scopes the zero-reference claim to the reserved names it was always about (verified: 0 hits each for --ds-signal, --ds-signal-strong, --ds-scope, --ds-alert, --ds-ink, --ds-font-display, --ds-font-diagram outside libs/design-tokens/). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(workspace-react): repair the dangling --ds-font-serif reference Task 4 retired --ds-font-serif from the token sources; Task 5's rename swept --font-garamond in the same declaration but left the --ds-* fallback pointing at a name that no longer exists. The failure mode is silent and worse than it looks: an undefined custom property inside a font-family list is invalid at computed-value time, so the whole declaration is dropped and .workspace-prose headings lose their font entirely. There is no partial fallback to the first entry in the list. ds-var-contract.spec.ts guarded only the other direction — that a name consumers use does not vanish. Adds the inverse check, which fails if any consumer references a --ds-* the generator does not define. Mutation-verified: restoring the bug turns it red with the exact name. --ds-surface-subtle is listed as a known pre-existing dangling reference (already broken at 218ac1c) so it stays visible rather than being hidden by the new guard. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(website): load Archivo Black and Archivo, drop EB Garamond layout.tsx now loads Archivo_Black for --font-display and Archivo for --font-sans via next/font/google, matching the ATC-derived token library. EB_Garamond is gone. Inter stays loaded here too, feeding --font-diagram. It cannot be supplied by theme.css's raw `Inter, system-ui, sans-serif` literal: next/font registers the family under a hashed name, so that literal never matches it and would silently fall back to system-ui, changing every diagram glyph width. Diagram geometry in apps/website/e2e/home-architecture.spec.ts is pinned to Inter's metrics on an 8px grid, so Inter must keep coming from next/font. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(website): signal surface scope for the ATC hero block Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(website): yellow hero block closed by the scope-navy frequency strip Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(website): the marker highlight is a yellow wash everywhere but the hero The Task 8 rule replaced the wash with an ink underline globally, but .marker-highlight is not hero-only — /langgraph, /chat, /ag-ui and /render all use it on white canvas, where they would have picked up an accent-coloured underline nobody asked for. A yellow wash is the better answer anyway: it is literally what a highlighter does, and it is the correct use of aviation yellow as a fill under near-black ink rather than as a text colour. The ink underline is now scoped to the signal block, where a yellow wash would be yellow on yellow. Also records in the plan that nx test website does not type-check — a step written as "watch the test fail" on a union change passes vacuously, because vitest skips types and React forwards unknown props to the DOM. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(website): yellow primary button and nav mark, scope-navy dark band Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(website): sweep the last hardcoded navy out of the light and dark surfaces Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: withdraw the docs left-rule step — the tokens already did it DocsControlPlane.spec.tsx guards 'rounded sidebar states without a left marker' from #963. The step would have overridden that deliberate decision to achieve something the retheme had already achieved: --color-accent-surface is now a yellow tint and --color-accent is scope navy, so the active item is already a soft yellow pill with navy ink. A plan written days earlier does not get to overrule a design decision the codebase deliberately guards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: withdraw the plan's docs left-rule step to match the spec correction Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(website): Archivo Black is single-weight — stop synthesizing bold and italic `--font-display` is Archivo Black, loaded by next/font at `weight: '400'`. Google Fonts ships it in exactly one weight and no italic, so every rule that asked for anything else was making the browser synthesize the face — smearing an already-black glyph, or shearing it into a fake oblique. jsdom cannot measure either, so nothing caught it. - Removed 48 `font-weight` declarations (500–800) from rules whose own block sets `font-family: var(--font-display)`: pages.css 21, landing.css 15, marketing.css 5, docs.css 4, ui.css 2, chrome.css 1. The face has one weight, so declaring it is noise. `.hero-heading` keeps its explicit `400` and the comment documenting the constraint at the most-read site. Rules on `--font-sans` and `--font-mono` are untouched: Archivo and JetBrains Mono are genuinely multi-weight. - Removed `font-style: italic` from the four display-face rules in landing.css (`.wp-cover-title`, `.final-cta-heading`, `.final-cta-mark`, `.proof-strip-watermark`). The faux oblique was most visible on the two that set it at 210px and up to 300px. The logo mark was aviation yellow on the white nav and footer — 1.84:1, below even the 3:1 floor for meaningful non-text graphics, and the exact thing this theme's own thesis forbids. It is now the ATC app icon in miniature: a signal-yellow squircle with an ink glyph, 10.73:1, inverting to an ink tile inside the signal scope so it does not vanish on the yellow block. The tile uses `box-sizing: border-box` rather than `content-box`. The logo sets the nav's content-row height at the two smaller breakpoints, so padding on a content-box icon inflates the whole nav — measured 58/66/81 to 64/72/81 against a `--nav-h` that e2e/nav-height.spec.ts pins to the rendered nav within 1px. Border-box insets the glyph instead, leaving every `--nav-h` offset untouched; all 8 nav-height e2e tests pass. The stale comment above the rule (the glyph "inherits the wordmark's color"; "the wordmark is Garamond") is rewritten. Also in libs/design-tokens: - The dangling-`--ds-*` guard only walked four hand-listed directories, missing libs/chat, libs/example-layouts, libs/design-tokens, apps/website/public and apps/website/e2e. Widened to the whole repo with node_modules/.next/dist/ coverage excluded. This surfaced 13 pre-existing dangling names, all from the committed generator artifact apps/website/public/whitepapers/chat-preview.html; they are listed in KNOWN_PRE_EXISTING and attributed in the comment so they stay visible rather than hidden. The guard also had to stop grepping its own docblocks, which quote retired names as prose. - `--ds-font-serif`'s comment claimed a surviving reference in workspace.css; a later commit repaired that, so it now has none. - Aviation yellow on the dark ground is 10.24:1 on `canvas` and 9.24:1 on `surface`, not 8.33:1 — that figure is the ratio against the website's scope navy, a different surface. Corrected, and the deliberate website/dark.ts surface divergence is now documented from both sides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(website): rebase repairs — #1057's strip used the retired font vars The open-source strip landed on main after this branch renamed the font custom properties, so it referenced --font-garamond and --font-inter, which no longer exist. An undefined custom property in a font-family declaration is invalid at computed-value time, so both rules would have shipped as silent system-font fallbacks that look almost right. .open-source-strip-line also puts an italic <em> inside what would have been the display face, and Archivo Black has no italic. It is body-scale editorial copy rather than display type, so it moves to --font-sans, where the italic is real: Archivo now loads style ['normal','italic']. That also retires the faux italics the sans face had been synthesizing all along, since Inter was loaded normal-only too. Adds font-vars.spec.ts, which fails if any stylesheet references a --font-* var layout.tsx does not supply. This exact bug happened twice in one day — the rename, and then a PR that landed in between — and nothing caught it: jsdom does not resolve custom properties and the Next build does not type-check CSS. Mutation-verified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent f17f456 commit aa88fe6

36 files changed

Lines changed: 2293 additions & 399 deletions

apps/website/src/app/card/tokens.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ export const CARD = {
1919
/** --color-surface-dim, the user bubble. */
2020
dim: '#f5f5f5',
2121
/** --color-text-primary / secondary / muted */
22-
ink: '#1c1c1c',
22+
ink: '#0a0a0a',
2323
inkSecondary: '#464646',
2424
inkMuted: '#737373',
2525
/** --color-border / --color-border-strong */
2626
border: '#e5e5e5',
2727
borderStrong: '#c8c8c8',
2828
/** --color-accent and its surface/border tints. */
29-
accent: '#004090',
30-
accentSurface: 'rgba(0, 64, 144, 0.06)',
31-
accentBorder: 'rgba(0, 64, 144, 0.30)',
29+
accent: '#15253e',
30+
accentSurface: 'rgba(255, 175, 0, 0.10)',
31+
accentBorder: 'rgba(255, 175, 0, 0.35)',
3232
/** BrowserFrame traffic lights (ui.css). */
3333
trafficRed: '#FF5F57',
3434
trafficAmber: '#FEBC2E',

apps/website/src/app/global.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ html {
3434
body {
3535
background-color: var(--color-bg);
3636
color: var(--color-text-primary);
37-
font-family: var(--font-inter);
37+
font-family: var(--font-sans);
3838
-webkit-font-smoothing: antialiased;
3939
-moz-osx-font-smoothing: grayscale;
4040
/* overflow-x: CLIP, never hidden. `hidden` makes <body> a scroll container

apps/website/src/app/layout.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Metadata } from 'next';
2-
import { EB_Garamond, Inter, JetBrains_Mono } from 'next/font/google';
2+
import { Archivo, Archivo_Black, Inter, JetBrains_Mono } from 'next/font/google';
33
import '@threadplane/design-tokens/tokens.css';
44
import './global.css';
55
import { Nav } from '../components/shared/Nav';
@@ -20,16 +20,31 @@ import { getFormPolicy } from '../lib/growth/form-policy';
2020
import { WebsiteSignals } from '../components/shared/WebsiteSignals';
2121
import { websiteContentCatalog } from '../lib/growth/website-content';
2222

23-
const garamond = EB_Garamond({
23+
const display = Archivo_Black({
2424
subsets: ['latin'],
25-
weight: ['400', '700', '800'],
25+
weight: '400',
26+
variable: '--font-display',
27+
});
28+
29+
const sans = Archivo({
30+
subsets: ['latin'],
31+
// Archivo ships a true italic. Loading it makes every italic on the text
32+
// face real rather than an obliqued upright — Inter was normal-only here,
33+
// so those sites had been faux-italic all along.
2634
style: ['normal', 'italic'],
27-
variable: '--font-garamond',
35+
variable: '--font-sans',
2836
});
2937

30-
const inter = Inter({
38+
/**
39+
* Inter is retained for diagrams only, and MUST be loaded here rather than
40+
* left to theme.css: next/font registers its family under a hashed name, so
41+
* theme.css's raw `Inter, system-ui` stack never matches it and would silently
42+
* fall back to system-ui. Diagram geometry is pinned to Inter's metrics —
43+
* see the FONTS note in src/styles/ui.css and e2e/home-architecture.spec.ts.
44+
*/
45+
const diagram = Inter({
3146
subsets: ['latin'],
32-
variable: '--font-inter',
47+
variable: '--font-diagram',
3348
});
3449

3550
const mono = JetBrains_Mono({
@@ -66,7 +81,7 @@ export default function RootLayout({
6681
return (
6782
<html
6883
lang="en"
69-
className={`${garamond.variable} ${inter.variable} ${mono.variable}`}
84+
className={`${display.variable} ${sans.variable} ${diagram.variable} ${mono.variable}`}
7085
>
7186
<body>
7287
{/*

apps/website/src/components/docs/DocsControlPlane.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('DocsControlPlane', () => {
5050
'[data-docs-control-plane-context] [data-control-plane-section-heading]',
5151
]) {
5252
const declarations = declarationsFor(docsCss, selector);
53-
expect(declarations).toMatch(/font-family:\s*var\(--font-inter\)/);
53+
expect(declarations).toMatch(/font-family:\s*var\(--font-sans\)/);
5454
expect(declarations).toMatch(/font-size:\s*12px/);
5555
expect(declarations).toMatch(/font-weight:\s*600/);
5656
expect(declarations).toMatch(/letter-spacing:\s*normal/);

apps/website/src/components/landing/Hero.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function Hero() {
2727
const closeInstall = useCallback(() => setInstallOpen(false), []);
2828

2929
return (
30-
<Section surface="canvas" ariaLabelledBy="hero-heading">
30+
<Section surface="signal" ariaLabelledBy="hero-heading">
3131
<Container>
3232
<div className="hero-stack">
3333
<Eyebrow tone="accent" className="hero-eyebrow">{HERO_EYEBROW}</Eyebrow>
@@ -59,7 +59,7 @@ export function Hero() {
5959
</a>
6060
</div>
6161
<HeroDemo />
62-
<p className="hero-trust">{HERO_TRUST_LINE}</p>
62+
<p className="hero-trust hero-strip">{HERO_TRUST_LINE}</p>
6363
</div>
6464
</Container>
6565
<InstallDialog open={installOpen} onClose={closeInstall} />

apps/website/src/components/landing/chat-landing/ChatLandingCodeShowcase.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class MyChatPage {
2222

2323
const SNIPPET_2 = `chat {
2424
--chat-bg: #f8f9fc;
25-
--chat-user-bg: #004090;
25+
--chat-user-bg: #15253E;
2626
--chat-user-color: #ffffff;
2727
--chat-assistant-bg: #f0f4ff;
2828
--chat-font-family: 'Inter', sans-serif;

apps/website/src/components/ui/Section.spec.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ describe('Section', () => {
99
expect(el?.getAttribute('data-surface')).toBe('dark');
1010
});
1111

12+
it('renders data-surface="signal" when asked', () => {
13+
const { container } = render(<Section surface="signal">x</Section>);
14+
const el = container.querySelector('[data-ui="section"]');
15+
expect(el?.getAttribute('data-surface')).toBe('signal');
16+
});
17+
1218
it('defaults to canvas', () => {
1319
const { container } = render(<Section>x</Section>);
1420
expect(

apps/website/src/components/ui/Section.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ReactNode, HTMLAttributes } from 'react';
22
import { cn } from '../../lib/cn';
33

4-
type Surface = 'canvas' | 'tinted' | 'white' | 'dark';
4+
type Surface = 'canvas' | 'tinted' | 'white' | 'dark' | 'signal';
55

66
interface SectionProps extends Omit<HTMLAttributes<HTMLElement>, 'id'> {
77
children: ReactNode;

apps/website/src/styles/chrome.css

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@
205205
padding: 10px 0;
206206
font-size: 15px;
207207
font-weight: 500;
208-
font-family: var(--font-inter);
208+
font-family: var(--font-sans);
209209
background: transparent;
210210
color: var(--color-text-muted);
211211
border: none;
@@ -240,7 +240,7 @@
240240
line-height: 24px;
241241
min-height: 44px;
242242
text-decoration: none;
243-
font-family: var(--font-inter);
243+
font-family: var(--font-sans);
244244
color: var(--color-text-secondary);
245245
background: transparent;
246246
}
@@ -286,7 +286,7 @@
286286
color: var(--color-accent);
287287
background: var(--color-accent-surface);
288288
text-decoration: none;
289-
font-family: var(--font-inter);
289+
font-family: var(--font-sans);
290290
font-weight: 600;
291291
}
292292
.nav-mobile-section-toggle {
@@ -301,7 +301,7 @@
301301
padding: 12px 14px;
302302
min-height: 48px;
303303
border-radius: 8px;
304-
font-family: var(--font-inter);
304+
font-family: var(--font-sans);
305305
font-size: 16px;
306306
line-height: 24px;
307307
color: var(--color-text-primary);
@@ -323,7 +323,7 @@
323323
min-height: 48px;
324324
color: var(--color-text-secondary);
325325
text-decoration: none;
326-
font-family: var(--font-inter);
326+
font-family: var(--font-sans);
327327
}
328328
.nav-mobile-github-link {
329329
display: flex;
@@ -334,7 +334,7 @@
334334
min-height: 48px;
335335
color: var(--color-text-secondary);
336336
text-decoration: none;
337-
font-family: var(--font-inter);
337+
font-family: var(--font-sans);
338338
font-size: 16px;
339339
}
340340
.nav-mobile-cta-wrap {
@@ -421,9 +421,8 @@
421421
margin-bottom: 8px;
422422
}
423423
.toast-title {
424-
font-family: var(--font-garamond);
424+
font-family: var(--font-display);
425425
font-size: 1.05rem;
426-
font-weight: 700;
427426
color: var(--color-text-primary);
428427
line-height: 1.3;
429428
margin-bottom: 6px;
@@ -461,7 +460,7 @@
461460
font-size: 12px;
462461
color: var(--color-text-muted);
463462
text-decoration: underline;
464-
font-family: var(--font-inter);
463+
font-family: var(--font-sans);
465464
}
466465

467466
/* Mobile docs-search entry (polish arc PR 3) — button reset to match the

0 commit comments

Comments
 (0)