# @supertype.ai/foundations

The shared design layer for Supertype's Next apps: typography primitives,
content blocks, a long-form essay shell, token and theme CSS, and build-time
tooling for SEO, OG cards, lint rules and contrast checks.

This file is for coding agents working in an app that consumes the package. It
covers what to import and the mistakes that do not produce an error. Full
reference: https://github.com/supertypeai/foundations

## Rules

1. **Never write type styles by hand.** If you are about to write `text-sm`,
   `text-xs`, `font-medium`, `leading-tight`, `text-muted-foreground` or similar
   on a text element, there is a primitive for it. Use that instead.
2. **Retune with CSS variables, not classes.** The package owns its classnames.
   Change a `--text-*` rung, `--heading-weight` or a colour token. Do not
   override the package's utilities.
3. **Import from the right entry point.** `blocks`, `essay`, `mdx`, `seo`, `og`,
   `eslint`, `rehype` and `contrast` are subpaths, not part of the root barrel.
4. **Use colour tokens, never literal colours.** `bg-card`, `text-foreground`,
   `border-border`. No hex values, no `bg-zinc-800`, no `dark:` overrides that
   swap one token for another.

## Which component

| you want | use | from |
|---|---|---|
| a page title | `TypographyH1` (add `variant="display"` on marketing pages) | root |
| a section heading | `TypographyH2` (add `divider` for a rule under it) | root |
| a subheading | `TypographyH3`, `TypographyH4` | root |
| a kicker above a heading | `TypographyEyebrow` | root |
| interface copy, 13px | `TypographyP` | root |
| the same, secondary ink | `TypographyMuted` | root |
| reading copy, 18px | `TypographyProse` | root |
| a bulleted or numbered list | `TypographyList`, `TypographyProseList` | root |
| a timestamp, count or value | `TypographyCaption` | root |
| a form label or column header | `TypographyLabel` | root |
| small print as a block | `TypographySmall` | root |
| a number or metric | `TypographyStat` | root |
| inline code | `TypographyInlineCode` | root |
| a link | `TypographyLink` | root |
| a highlighted phrase | `TypographyHighlight` | root |
| a button, or a link that looks like one | `Button` | `/blocks` |
| a status label, count or chip | `Badge` | `/blocks` |
| a link card, or a grid of them | `Card`, `Cards` | `/blocks` |
| an aside, warning or note | `Callout` | `/blocks` |
| numbered instructions | `Steps`, `Step` | `/blocks` |
| an FAQ or collapsible, no JS | `Disclosure`, `DisclosureGroup` | `/blocks` |
| an animated accordion | `Accordion` (client) | `/blocks` |
| tabbed content | `TabGroup` when the tabs are data, `Tabs` to compose by hand (client) | `/blocks` |
| a long-form article page | `EssayHeader` + `EssayLayout` + `EssaySection` | `/essay` |
| an article whose body is prose or MDX | `EssayHeader` + `ReadingLayout` | `/essay` |
| a post meta row (date, read time, tags) | `PostMetaRow` and friends | `/essay` |
| a table of contents | `TableOfContents`, `ReadingRail` | `/essay` |
| page metadata and JSON-LD | `createSeo` | `/seo` |
| an OG image | `ogCard`, `OG_SIZE` | `/og` |
| to merge classnames | `cn` | root |

## Entry points

| import | exports |
|---|---|
| `@supertype.ai/foundations` | `cn`, `TypographyH1`, `TypographyH2`, `TypographyH3`, `TypographyH4`, `TypographyEyebrow`, `TypographyP`, `TypographyMuted`, `TypographyProse`, `TypographyList`, `TypographyProseList`, `TypographyCaption`, `TypographySmall`, `TypographyLabel`, `TypographyStat`, `TypographyInlineCode`, `TypographyLink`, `TypographyHighlight`, `headingClass`, `headingFace`, `eyebrowClass`, `toneClass`, `impliedTone`. Types: `TypographyTag`, `ParagraphVariants`, `ListProps`, `CaptionVariants`, `LabelVariants`, `StatVariants`, `Tone`, `HighlightTone` |
| `@supertype.ai/foundations/blocks` | `Cards`, `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `Callout`, `Button`, `buttonVariants`, `Badge`, `badgeVariants`, `Steps`, `Step`, `Disclosure`, `DisclosureGroup`, `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `TabGroup`, `SEGMENT`. Types: `ButtonLook`, `BadgeLook`, `TabItem` |
| `@supertype.ai/foundations/mdx` | `proseMdxComponents` |
| `@supertype.ai/foundations/essay` | `createEssay`, `EssayHeader`, `EssayLayout`, `EssaySection`, `EssayPullQuote`, `EssayFigure`, `EssayMovements`, `EssayDocument`, `EssayColumns`, `EssayAside`, `EssayBody`, `ReadingLayout`, `TableOfContents`, `ReadingRail`, `ReadingProgressBar`, `Rail`, `RailLink`, `PostMetaRow`, `PostDate`, `ReadTime`, `TagPills`, `MetaDot`, `formatPostDate`, `extractHeadings`, `readingTime`, `createSlugger`, `useReadingProgress`, `useScrollSpy`. Types: `TocHeading`, `EssayDecorations`, `EssayIndexEntry`, `EssayDocSection`, `EssayMovement`, `PostDateFormat` |
| `@supertype.ai/foundations/seo` | `createSeo`. Types: `SeoConfig`, `ArticleAuthor`, `ArticleOptions`, `PageMetadata` |
| `@supertype.ai/foundations/og` | `ogCard`, `OG_SIZE`. Types: `OgCardOptions` |
| `@supertype.ai/foundations/eslint` | `designRules` (every rule as one array — spread this), `designConfig` (the same set wrapped as a flat-config entry). The five builders `colourRules`, `typographyRules`, `themeOverrideRules`, `surfaceAsInkRules`, `renamedTokenRules` are still exported, but spreading them by hand is how a consumer ends up missing one. Types: `FlatConfigEntry`, `DesignRuleOptions`, `DesignConfigOptions`, `RestrictedSyntax`, `ColourOptions`, `TypographyOptions` |
| `@supertype.ai/foundations/rehype` | `rehypeProseCode`, `proseCodeOptions`, `PROSE_LANGS`, `PROSE_THEMES`. Build-time only, must not resolve React |
| `@supertype.ai/foundations/contrast` | `checkLegibility` (inks at 4.5:1), `checkSignals` (fills at 3:1, tinted inks at 4.5:1, labels against their own fill), `resolveTokens`, `formatFailures`, `specificity`, `parseColor`, `luminance`, `contrast`, `tokenCuts` (which cuts a token ships — fill, the label printed on it, the hue as words; the taxonomy `checkSignals` measures). Types: `Rgb`, `Theme`, `LegibilityFailure`, `TokenCuts`. Build-time only |

## Props worth knowing

- `TypographyH1`, `TypographyH3`: `variant?: "default" | "display"`.
- `TypographyH2`: `variant?`, plus `divider?: boolean` for a rule underneath.
- `TypographyP`: `variant?: "ui" | "prose"` (default `ui`), `tone?: "default" | "muted"`.
- `TypographyMuted`, `TypographyProse`, `TypographyProseList` are presets. The
  prop each one pins is removed from its type, so passing it will not compile.
- `TypographyCaption`, `TypographyLabel`, `TypographySmall`: `size?: "sm" | "xs" | "2xs" | "inherit"`, `as?`.
- `TypographyEyebrow`: `tone?: "heading" | "label"`, `as?`.
- `TypographyStat`: `size?: "inherit" | "card" | "panel" | "page" | "display"`, `figures?: "tabular" | "proportional"`. Keep tabular where a value updates in place.
- `TypographyLink`: `href` (required), `tone?: Tone` (default `muted`), `addArrow?`, `newTab?`. Internal versus external is decided from the href.
- `TypographyHighlight`: `tone?: HighlightTone` — `"primary" | "success" | "ochre" | "terracotta" | "sage" | "fig"`, `seed?: number`. Deliberately NOT `Tone`: this axis is categorical (which one it is), not semantic (what it means), which is the same split theme.css draws between the earth swatches and the status tokens.
- `Card`: `href`, `title`, `description`, `icon`, `external`. An href makes the whole card a link.
- `Tone` — the one semantic colour vocabulary, shared by `Button`, `Callout` and `TypographyLink`: `"muted" | "primary" | "secondary" | "brand" | "success" | "warn" | "destructive"`, defaulting to `muted` everywhere except a solid `Button`. Seven tones, seven tokens, one to one — that is the bar for adding one. There is no `neutral` (that is `muted`, the word the rest of the package uses), no `foreground` (also `muted`), no `accent` (that is `--primary`'s hover tint, so a washed `primary` renders the same thing) and no `info` (`success | warn | destructive` is already the whole triad). `brand` falls back to `--primary` in an app that defines no `--brand`.
- `Button`: `variant?: "solid" | "soft" | "outline" | "ghost" | "link"` (default `solid`), `tone?: Tone` (defaults to `primary` on a solid button and `muted` on every other variant — filling a button in is how a page says this is the action), `size?: "xs" | "sm" | "md" | "lg" | "xl"` (default `md`), `icon?: boolean` for a square glyph box, `pill?: boolean` for full-round corners, `render` for the element to become. Variant is how much ink it spends; tone is what the ink means — separate axes, so a quiet delete is `variant="ghost" tone="destructive"`, not a `destructive` variant.
- `Badge`: `variant?: "solid" | "soft" | "outline" | "ghost"` (default `solid`), `tone?: Tone`, `size?: "xs" | "sm"` (default `sm`), `pill?: boolean`. Same axes and same spellings as `Button`, minus `link` — a badge is not a link. There is no `warning` or `supertype` variant; those were `tone="warn"` and `tone="brand"` under invented names.
- `Callout`: `tone?: Tone`, `density?: "compact" | "editorial"`, `title`, `icon`, `action`.
- `DisclosureGroup`: `type?: "multiple" | "single"`, `defaultValue` (matches the title string).
- `TabsList`: `variant?: "default" | "line"`, `tone?: Tone` (default `primary`) — the tone
  inks the marker only: on `line` the underline and the active icon. The boxed track's
  marker is deliberately flat, so a tone there paints nothing.
- `TabGroup`: `tabs: readonly TabItem[]` (`{ value, label, icon?, content }`), `defaultValue?`,
  `value?`, `onValueChange?`, `variant?`, `tone?`, `iconPosition?: "inline-start" | "inline-end"`.
  `icon` is an element (`<Icons.Mic />`); the trigger sizes and inks it. Reach for it
  whenever the tabs are data — do not rebuild it over `Tabs`/`TabsTrigger`.

## Common mistakes

- `<p className="text-sm text-muted-foreground">` — use `<TypographyMuted>`.
- `<h2 className="text-lg font-semibold">` — use `<TypographyH2>`, or
  `headingClass()` if you must pass classes to someone else's component.
- Importing `Card`, `Callout` or `Button` from `@supertype.ai/foundations`. They
  live in `@supertype.ai/foundations/blocks`.
- `<Button variant="destructive">` or `variant="secondary"` — those are tones, not
  variants. Write `variant="soft" tone="destructive"`, `variant="solid" tone="secondary"`.
- `<Button size="icon-sm">` — there is one size ladder. Write `size="sm" icon`.
- `<Badge variant="warning">` / `variant="supertype"` — tones, and misspelled ones.
  Write `variant="outline" tone="warn"` and `variant="solid" tone="brand"`.
- `tone="neutral"`, `tone="foreground"` or `tone="accent"` — all three were
  removed when the tone lists merged. Write `tone="muted"` for the first two and
  `tone="primary"` for the third.
- An `<a>` or `<Link>` styled by hand to look like a button. Pass it as
  `render={<Link href="/x" />}`; the anchor keeps its link semantics.
- `<TypographyMuted tone="default">` — a type error. Use `TypographyP`.
- Binding fonts with `font.className` instead of `font.variable`. The className
  form sets `font-family` on the element and leaves the roles unresolved.
- Omitting `@source '../node_modules/@supertype.ai/foundations/dist/**/*.js'` from
  the CSS entry. Tailwind then purges every class the package ships.
- Omitting `@import "@supertype.ai/foundations/theme.css"`. `tokens.css` names the
  colour roles but holds no values, so the whole palette resolves to nothing.
- Using `Accordion` for a static FAQ. `Disclosure` needs no JavaScript.
- Adding a second `@custom-variant dark`. `tokens.css` already binds it.

Run `npx foundations doctor` in the app to check the last four.

## Surfaces

Two classes change how everything renders, and both go on `<html>` or a subtree:

- `.dark` re-points every colour token. It is bound by `tokens.css`, not by the
  OS setting.
- `.editorial` gives the heading role to the serif at weight 400 and retunes the
  whole heading ladder against an 18px body, instead of the product's 13px.

## Docs

Read from `node_modules`, so these are absolute:

- README: https://github.com/supertypeai/foundations#readme
- Typography: https://github.com/supertypeai/foundations/blob/main/docs/typography.md
- Blocks and MDX: https://github.com/supertypeai/foundations/blob/main/docs/blocks.md
- The essay shell: https://github.com/supertypeai/foundations/blob/main/docs/essay.md
- Build-time tooling: https://github.com/supertypeai/foundations/blob/main/docs/tooling.md
- The CLI: https://github.com/supertypeai/foundations/blob/main/docs/cli.md
