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-h1down 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 (h1–h4) 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.