design-tokens-and-theming

Design token system and theming

The YouTeacher landing page keeps every visual decision — color, type, spacing, radius, shadow — in one CSS file of custom properties, src/styles/design-tokens.css, declared on :root. That file calls itself the single source of truth, and the rest of the styling reads from it rather than hard-coding values.

The token layer

The tokens fall into a few families:

  • Brand color. A warm orange primary (--color-brand) with lighter hover and darker active variants, plus a slate-blue secondary and a lighter secondary.
  • Neutrals. Text, secondary text, and inverse text; page and card backgrounds, each with a separate dark counterpart; border colors; and a "sponsored/featured" pair.
  • Typography. Two font families — --font-brand (Rubik, used for headings) and --font-body (Inter) — each with system fallbacks. A fixed size scale runs from --font-size-h1 down through body, small body, and caption; three weights (regular/medium/semibold); a set of line heights; and two negative letter-spacing values for tightening large headings.
  • Spacing. A numbered scale (--space-1--space-20) in pixels, from 4px up to 80px.
  • Radius and shadow. Radii from small to full (a large value used for pills), and three elevation shadows.

How it is consumed

src/app/globals.css imports Tailwind and then the token file, sets the base font-family, background-color, and color from tokens on :root, applies a border-box reset, and maps the heading elements (h1h4) onto the size and weight tokens — with the two largest headings (h1, h2) also taking line-height and letter-spacing tokens. Components consume the same variables through CSS Modules: Header.module.css, for example, references var(--color-bg), var(--space-4), var(--radius-md), and the font tokens rather than literal values. This is the reason the design "changes in one place" — the tokens are the interface between the guide and the components.

Dark mode

Theming is layered so both the operating-system preference and an explicit user choice are honored, with the user winning:

  • Automatic. A @media (prefers-color-scheme: dark) block overrides the neutral tokens — but it is scoped to :root:not([data-theme="light"]), so following the system only applies when the user has not pinned light.
  • Manual. A separate :root[data-theme="dark"] rule sets the same dark values unconditionally, so an explicit dark choice wins even in a light-mode OS.

The manual path keys off a data-theme attribute on the root element; the header carries a theme-toggle control that drives it. The dark blocks redefine the neutral color tokens (text, backgrounds, border) and also swap the slate-blue secondary to its lighter value; the primary brand orange and the structural tokens (type, spacing, radius) stay constant across themes.

Responsive type

The scale is mobile-first by override: a @media (max-width: 767px) block in the token file shrinks the heading sizes and tightens two of the large spacing steps, so every component that reads the heading tokens scales down together without per-component media queries. Components still add their own breakpoints where layout needs it — the header, for instance, tightens its padding and logo below 480px, and globals.css enforces a 44px minimum touch target under pointer: coarse.

Why this shape

One token file, read everywhere, means a color or spacing change is a single edit; the three-way theme rule means the app respects the OS by default but lets a person override it; and the mobile-first overrides keep one type scale honest across screens instead of scattering sizes through the components.

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →