Commit Graph

5 Commits

Author SHA1 Message Date
Arjun Mahanti
31b53e1afd feat(design-system): add portable open-source component library
Signed-off-by: Arjun Mahanti <arjun@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
2026-09-09 08:24:52 -07:00
Arjun Mahanti
20927e4355 feat(design-system): establish portable open-source foundations
Signed-off-by: Arjun Mahanti <arjun@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
2026-09-09 08:03:48 -07:00
morgmart
b7dbe90001 fix(desktop-next): relight the dark text ramp and enforce contrast in CI
Three fixes, and a guard so they cannot regress silently.

`text-on-warning` pointed at `var(--neutral-12)`, which is near-black in light
mode and near-white in dark. The warning fill is the same amber in both, so dark
mode put #f5f5f5 on #eab308: APCA Lc 34, WCAG 1.76:1. It is a literal now — a
paired-text token follows its fill, never the mode.

The dark neutral text steps were too dim. `text-secondary` (#8f8f8f) measured
Lc 38–41 and `text-tertiary` (#6e6e6e) Lc 23–26 against an Lc 60 body target,
while passing WCAG AA at 4.4–5.6:1 — legal, and visibly murky. Raise dark
neutral-9 to #a6a6a6 and neutral-10 to #c1c1c1, sized against bg-float
(#2a2a2a), the lightest dark surface and so the binding case. Light neutral-9
moves #a3a3a3 -> #909090 for the same reason at the meta target. Both ramps stay
monotonic, and bg-inverse-hover (the other consumer of neutral-10) still carries
its paired text at Lc 70.

This is APCA's polarity asymmetry doing real work: light-on-dark needs more
separation than the same WCAG ratio implies, so the dark ramp's text steps sit
above where mirroring the light ramp would put them.

`text-disabled` stays below target deliberately — low contrast is the signal
that a control is unavailable, and WCAG exempts inactive controls for the same
reason. Raising it would make disabled read as enabled. Recorded as the one
exception, with that reason.

The guard is the durable part. `scripts/check-contrast.mjs` measures every text
role against every surface it can sit on, in both modes, and fails the build
below target. It parses `tokens.css` and resolves each `var()` chain rather than
holding a copied list of values, so it cannot drift from the system it audits.
`scripts/apca.mjs` is the algorithm, asserted against the published reference
values on every run so a bad edit to the maths fails loudly rather than quietly
shifting every verdict. Verified by falsification: reverting either fix fails
the check, and perturbing one APCA exponent trips the reference assertion.

Also corrects an earlier misreading: the two `.dark` blocks are not duplicate
declarations. The first holds the dark ramp, the second overrides surface roles
so the panel lifts off pure black. That is the intended layering.

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-09-03 21:41:51 -07:00
morgmart
30847f42ff feat(desktop-next): add the type system, fix unreachable border roles
The design system site rendered black borders and dividers while the tokens
said `#d4d4d4`. The border roles were declared in layer 2 and never registered
with Tailwind, so `border-primary` silently resolved to `--color-primary` — the
*text* colour — and every hairline drew at text contrast. Tailwind's `--color-*`
is a single namespace and text/borders share the emphasis names while holding
different values, so borders now register as `--border-color-*`.

Add typography as the second foundation, same three layers as colour: a nine-step
size ramp plus leading, tracking, and weight ramps in layer 1; ten public roles
in layer 2, each carrying its whole setting via Tailwind v4's
`--text-<name>--<property>` convention, so `text-body` alone produces correctly
set text and two supposedly identical labels cannot drift apart. Inter Variable
and JetBrains Mono, both already shipped in every current Buzz client. Every
size derives from one virtual rem, so keyboard zoom and the font-size preference
work by construction.

Soften the documentation surface to match where the product is going: regions
separated by soft fills rather than outlines, hairlines only for genuine
boundaries and never above `border-secondary`, no page-wide gradient behind
reading columns, and no all-caps labels anywhere.

The `/design/typography` page renders from the registry, so it cannot drift from
the system. Add `scripts/check-type.mjs` enforcing the four rules a token cannot
express — no arbitrary sizes (px or rem), no `uppercase`, no hand-applied
tracking, no size role paired with a weight or leading utility.

Also collapse the nav to a wrapped row below `lg`; the fixed 256px column
overflowed the viewport under 420px.

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-09-03 12:50:39 -07:00
morgmart
7cde504d7b feat(desktop-next): scaffold new client with the colour system and a design system route
Starts a second desktop client rather than reworking the existing one, so the
design system can be built from scratch without unpicking 476 raw colour usages
and 72 hover values first. The existing desktop/ client is untouched.

What lands:

- The colour system in three layers: private ramps hold values, public roles
  hold meanings, components only ever use roles. Tailwind's default palette is
  deleted with --color-*: initial, so a raw palette class is a build error.
- A machine-readable token registry, so the design system documentation renders
  from the system itself and cannot drift from it.
- /design — foundations, vocabulary, and the growth procedure, with a live
  light/dark toggle. Typography, spacing, radius, and motion are stubs that
  state what is still to decide rather than pretending to a system.
- DESIGN.md for the judgement tokens cannot express, and AGENTS.md for the rules
  an agent needs before writing any UI.

Accent is a slot rather than a colour: nothing above the ramp knows the hue, so
it can change, become a preference, or vary per theme without touching a
component. Every dark value is authored rather than observed, because the design
exploration it derives from is light-only.

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-09-02 20:15:02 -07:00