Rebranding

How a product rebrands the Colden kit in six moves (accent scale, neutral scale, font, radius, density, logo) through the design tokens, then gives it its own name in the web, the emails and the identity server, and checks the result.

Every color, radius and size of the kit's screens comes from one file, packages/ui/tokens/tokens.json, and components use only its semantic tokens, never a raw value. A product therefore changes its look in six moves, five in that file and one in a component, then its name in a handful of settings, and every screen, state and theme follows.

How the tokens reach the screens

  1. packages/ui/tokens/tokens.json holds the scales (neutral-*, accent-*), the semantic colors built on them with a light and a dark value (text-accent is {accent-600} in light and {accent-400} in dark), the type, the radii, the shadows and the sizes.
  2. pnpm --filter @colden/ui tokens:build writes src/styles/tokens.css (every token as a custom property, per theme) and src/styles/theme.css (the Tailwind theme on the semantic names). Both are committed; tokens:check fails while they are stale.
  3. Components use the semantic utilities (bg-primary, text-text-secondary, border-border-strong); the scales have no utilities of their own, so a rebrand never has to touch a component.

The six moves

Edit tokens.json, run tokens:build after each move, and look at the result in the component gallery (pnpm --filter @colden/web dev, then /dev/kit), which shows every component in light, dark and compact.

1. The accent scale

Replace the eleven steps accent-50 to accent-950 with the brand's color, lightest to darkest. accent-600 is the primary button's fill, the links and the focus ring in light, and accent-400 the links in dark, so both must keep a contrast of at least 4.5:1 on their surfaces (the token's usage states the kit's value, 6.8:1 for accent-600 on white). Generate the scale from the brand color with an even lightness ramp rather than by hand, so the hover and subtle steps stay in order.

2. The neutral scale

Replace neutral-0 to neutral-950: the surfaces, borders and text of both themes. A neutral tinted toward the accent (a cool gray for a blue brand, a warm one for an orange) looks deliberate; keep neutral-0 white, and check secondary text (text-secondary) against both the surface and the raised surface in both themes.

3. The font

type.fonts.sans and type.fonts.mono in tokens.json are the font stacks. The web loads its sans font itself through next/font in apps/web/app/layout.tsx (Inter, self-hosted at build), and that variable takes the place of the token's stack: change both together, to a font with the weights the type scale uses and the Latin Extended subset the Romanian copy needs.

4. The radius

radius-sm, radius-md (the base: buttons, inputs, selects) and radius-lg (cards, dialogs, menus) set the corners; radius-full stays for avatars, pills and switches. Square corners are 0px on the first three; very round ones raise them together, so nested elements keep their order (lg above md above sm).

5. The density

The sizes set how dense the screens are: control-sm, control-md and control-lg (the heights of buttons and inputs), row-default and row-dense (table rows), plus the sidebar, top bar and content widths. Comfortable is the default; a person can choose compact, which swaps control-md for control-sm and row-default for row-dense (data-density="compact" on <html>, from the colden_density cookie). A product for dense data work lowers the defaults; one for occasional use raises them. Keep control-md at 24 px or more, the target size of WCAG 2.2.

packages/ui/src/logo-mark.tsx draws the mark as an SVG inked with currentColor, so it takes the text or primary color of its container and follows the theme; it heads the public site's header and footer and the system pages, and the wordmark beside it on the public site is the product's name (common.appName, see The name). Replace the path, and the viewBox when the mark is not square. A mark that must keep its own colors writes them on lines marked tokens-lint-ignore with the reason, since the token rule refuses raw colors in components. The browser's icon follows Next's file convention (apps/web/app/icon.svg).

The name

The kit says Colden in a few places outside the tokens:

WhereWhat to change
apps/web/messages/en-US.json and ro-RO.jsoncommon.appName, which most titles use, and the few messages that name the product directly (search both files for Colden)
The email settings (Email:ProductName, Email:FromName, Email:From, Email:LogoUrl, Email:FooterAddress)the name in the subjects, the header and the footer, the sender, the logo next to the name and the legal sender line; see email
infra/ory/kratos/kratos.yaml (selfservice.methods.totp.config.issuer)the name authenticator apps show next to the code; run tools/helm-check.sh --sync afterward, so the chart's copy follows
apps/web/content/blog/ and the landing page's messages (marketing.*)the public site's copy
REPOSITORY_URL in apps/web/scripts/sync-docs.mjswhere the docs site links into the repository

The cookie names (colden_locale, colden_theme, ...) and the packages' names are internal and may stay.

Checking the result

pnpm --filter @colden/ui tokens:build
pnpm -r lint && pnpm -r typecheck && pnpm -r test
pnpm --filter @colden/web dev            # /dev/kit in light, dark and compact
pnpm e2e --grep accessibility            # against the Compose stack: no WCAG 2.2 AA violation
pnpm --filter @colden/e2e lighthouse     # the public pages

The lint fails on a raw color or size written in a component, the token check on stale sheets, the accessibility journey on a contrast the new scales broke, and the email snapshot tests on changed email output (run them with COLDEN_UPDATE_SNAPSHOTS=1, review the diff and commit it, as testing describes).