One source,
read by people and agents.

The design system of this site. This page reads the tokens from the CSS and the code, so it cannot show a value that the site does not use. Coding agents read the same tokens and rules as JSON.

1. Rules

Each rule says what to do and why. Where a test checks the rule, the test is named. The other rules are checked in review.

src/lib/design/rules.ts (opens in a new tab)

  1. Use the color tokens (bg-background, text-fg-muted, border-border, text-brand). Do not write a color value in a component.

    Light and dark mode then change together, and one edit changes the site.

  2. No text under 14px, and no capitals made with CSS. Use text-sm (14px) as the smallest size.

    Small capital labels are hard to read and add noise without meaning.

    Checked bye2e/pages.spec.ts (opens in a new tab)

  3. Do not put a small label above a heading. Put the meaning in the heading, or number the heading.

    A label above a heading repeats it, and screen readers read it as a separate line.

  4. Use the mono font only for code, file paths and ids, at 14px or more.

    Mono marks text that a reader can copy into a terminal or an editor.

  5. Make headings with Title, PageHeading or SectionHeading. Use className for layout only, not for size or weight.

    One scale for the whole site. To change a size, change the variant in Title.tsx.

  6. Show less important text with text-fg-secondary or text-fg-muted. Do not lower the opacity of text-foreground. Use text-fg-faint only for decoration and disabled text.

    One opacity looks much dimmer on a dark background. Each tone has its own light and dark value, tested for APCA contrast in both schemes.

    Checked bysrc/lib/design/tokens.test.ts (opens in a new tab)

  7. Never show a state with color alone. Add an icon and a text label.

    WCAG 1.4.1. The claim checker grades each have an icon, a label and a color.

  8. Every control shows the focus ring. When an overlay closes, focus goes back to the control that opened it.

    Keyboard users must always know where they are.

    Checked bye2e/lab.spec.ts (opens in a new tab)

  9. A view that waits for the network has these states: idle, pending, streaming, complete, stopped and failed. Esc stops it, and the text that arrived stays.

    A stream can be slow, stop or fail at any point. Each case needs a clear screen.

    Checked bye2e/chat.spec.ts (opens in a new tab)e2e/check.spec.ts (opens in a new tab)e2e/lab.spec.ts (opens in a new tab)

  10. Every stream event carries the attempt it belongs to. A reducer ignores events from an attempt that is not active.

    A stopped answer must not write into a new one.

    Checked bysrc/lib/chat/chat-machine.test.ts (opens in a new tab)

  11. Animate with a spring, ease and duration from src/lib/design/motion.ts. Do not write new values in a component.

    The same kind of change then moves the same way on every page.

  12. Respect reduced motion. Motion does this through MotionConfig at the root. CSS animations need a prefers-reduced-motion block.

    Large movement can make some people feel sick.

  13. Make click and touch targets at least 24 by 24px. Buttons are 32px high.

    WCAG 2.5.8. Small targets are hard to hit on a phone.

  14. Build on the shadcn/ui base-nova components in src/components/ui, on Base UI. Merge classes with cn from the cn package. Use Lucide icons.

    The primitives handle focus, keyboard and ARIA. Do not rebuild them.

2. Color

Colors are OKLCH custom properties. Dark mode changes the values, not the names. Text colors have their own value in each scheme, because one opacity looks much dimmer on a dark background. A test checks their APCA contrast.

src/styles/globals.css (opens in a new tab)

Surface

  • bg-background

    The page.

  • bg-card

    Cards and panels that sit on the page.

  • bg-popover

    Hover cards, menus and drawers.

  • bg-secondary

    Quiet filled controls.

  • bg-muted

    Wells and hover fills.

  • bg-page-base

    Behind the page cards during a page transition.

Text

  • text-foreground

    All text. Lower its opacity for less important text.

  • text-fg-secondary

    Supporting text next to primary text. APCA Lc 75 or more.

  • text-fg-muted

    Descriptions, metadata and hints. APCA Lc 60 or more.

  • text-fg-faint

    Disabled text and decoration only.

  • text-card-foreground

    Text on a card.

  • text-popover-foreground

    Text on a popover.

  • text-secondary-foreground

    Text on a secondary fill.

  • text-muted-foreground

    Text on a muted fill.

Action

  • bg-primary

    The main button of a view.

  • text-primary-foreground

    Text on a primary fill.

  • bg-accent

    Hover fill of menu items.

  • text-accent-foreground

    Text on an accent fill.

  • bg-ring

    The focus ring. Every control shows it.

  • bg-brand

    Selection, the active citation and emphasis in headings.

  • text-brand-foreground

    Text on a brand fill.

Line

  • border-border

    Dividers and card edges.

  • border-input

    Edges of fields.

Status

  • bg-destructive

    Errors and actions that delete.

  • bg-verified

    The claim checker: verified.

  • bg-partial

    The claim checker: partly verified.

  • bg-contradicted

    The claim checker: contradicted.

Each circle shows the light value on the left and the dark value on the right. The page follows the color scheme of your system.

3. Type

DM Sans Variable for all text, at weight 400 for titles. JetBrains Mono for code, paths and ids only. Title sizes are fluid and scale with the reader’s font settings.

src/components/Title.tsx (opens in a new tab)

  • page

    Page title (h1) · 44–88px · 1.08

    On purpose

  • section

    Section title · 32–56px · 1.15

    On purpose

  • card

    Card and project title · 24–32px · 1.2

    On purpose

  • subsection

    Subsection title · 20–24px · 1.3

    On purpose

  • detail

    Detail title · 18px · 1.4

    On purpose

Body

  • text-lg

    18px on 32px

    Lead paragraphs. The answer streams in, and each claim links to its source.

  • text-base

    16px on 28px

    Body text. The answer streams in, and each claim links to its source.

  • text-sm

    14px on 24px

    Controls, metadata and hints. The smallest size. The answer streams in, and each claim links to its source.

Tones

  • text-foreground

    Primary. Headings and body text.

  • text-fg-secondary

    Secondary. Supporting text next to primary text.

  • text-fg-muted

    Muted. Descriptions, metadata and hints.

  • text-fg-faint

    Faint. Disabled text and decoration. Never for text that people must read.

4. Space and shape

Spacing follows the Tailwind scale of 4px steps. Two tokens set the rhythm of sections, and they grow at the sm (40rem) and lg (64rem) breakpoints.

TokenPhoneFrom 40remFrom 64rem
--section-paddingSpace above and below a page section.3rem4rem5rem
--section-content-gapSpace between a section title and its content.2rem2.5rem3rem
--radiusCorner radius of controls. Cards use radius + 4px, pills use full.0.5rem——

5. Motion

Springs for things that move, because a spring can stop and turn back with the pointer. Eases for things that fade. With reduced motion on, the dots jump, and only opacity changes on the rest of the site.

src/lib/design/motion.ts (opens in a new tab)

Springs

  • Panels and cards that move or resize.

  • List items that enter, and indicators that slide.

  • Citation chips and counts that appear.

  • Decorative pieces on the home page that bloom in.

  • Decorative pieces that answer the pointer.

Eases and durations

EASE_OUT
cubic-bezier(0.22, 1, 0.36, 1) · Things that enter.
EASE_IN
cubic-bezier(0.64, 0, 0.78, 0) · Things that leave.
DURATIONS.enter
280 ms · A message or panel that enters.
DURATIONS.exit
200 ms · Something that leaves.
DURATIONS.page
550 ms · A view that replaces another.
DURATIONS.reveal
700 ms · Content that scrolls into view, and the mobile menu.
DURATIONS.showcase
1100 ms · Large decorative pieces on the home page.

6. Components

The real components, in each state. Hover and focus are shown with the same classes that the states use.

src/components/ui (opens in a new tab)

Button

Base UI button with the shadcn/ui base-nova styles. The focus state is the ring that keyboard focus shows. Disabled buttons that a stream turns off stay focusable, so focus is not lost.

default

The main action of a view. One for each view.

Rest
Focus
Disabled
With icon

outline

Other actions, such as Stop and Replay.

Rest
Focus
Disabled
With icon

secondary

Quiet actions in a group.

Rest
Focus
Disabled
With icon

ghost

Actions in toolbars and lists.

Rest
Focus
Disabled
With icon

destructive

Actions that delete or stop for good.

Rest
Focus
Disabled
With icon

link

Actions inside text.

Rest
Focus
Disabled
With icon

Verdict badge

The five grades of the claim checker. Each has an icon, a label and a color, so color is never the only signal.

  • Verified

    The sources state this.

  • Partly verified

    The sources support part of this, but not all of it.

  • Not supported

    The sources cover this topic, but they do not show this.

  • Contradicted

    The sources state something different.

  • Unknown

    The public record does not cover this.

Citation chip

A number in the answer text that opens its source. It is a toggle button: aria-pressed shows the source in view.

Streams

Rest

Streams

Hover, or its source has the pointer

Streams

Active

Streams

Focus

Streams, drawers and panels

The parts that change with time have every state on a control bar in the Lab: idle, loading, slow, streaming, interrupted, error and done.

7. For agents

Coding agents work on this site. They read the same system as people do, from the files below, before they change the interface.

  1. Tokens and rules as JSON

    Colors with light and dark values and Tailwind names, type, space, motion and all rules. Built from the same modules as this page.

    /design/tokens.json

  2. Instructions

    The commands, the code style and a pointer to these rules. Agents read this file first.

    AGENTS.md (opens in a new tab)

  3. Checks

    A unit test fails when a color in the CSS has no description, or a rule names a test that does not exist. The end-to-end tests check text sizes, focus and stream states.

    src/lib/design/tokens.test.ts (opens in a new tab)