Global Styles
Set up the global Master CSS entry, base layer, theme tokens, native global CSS, and shared component or utility vocabulary.
Overview
Global styles are the project-level CSS that every page can depend on. They define the Master CSS entry, default layer order, base styles, shared tokens, custom variants, generated class vocabulary, and native CSS that belongs to the whole app.
Most applications should have exactly one app stylesheet that starts with the default Master CSS entry:
@import "@master/css";That import marks the file as a full Master CSS entry. It loads the package stylesheet graph, declares the stable layer order, includes the preset theme and base styles, and gives integrations the stylesheet that receives generated CSS.
Entry stylesheet
Use the app stylesheet for project-wide styling inputs:
@import "@master/css";@theme { --color-brand: var(--color-blue-60); --spacing-action-x: 1rem;}@custom-variant motion-safe { @media (prefers-reduced-motion: no-preference) { @slot; }}Load this stylesheet once from the app root, framework layout, or build entry. Do not import it again from page-level CSS. A second import duplicates global native CSS and makes ownership harder to trace.
Use the lightweight marker only when a stylesheet should be a generated CSS entry without loading the package defaults:
@master entry;Most apps should prefer @import "@master/css";. Use @master entry; for advanced split entries that already receive the package base and theme from somewhere else.
Base layer
The default entry includes the base layer. Base styles are normalization and document baseline rules emitted before project defaults, components, and utilities.
The package base entry declares the stable layer order:
@layer theme, base, defaults, components, utilities;Write browser normalization and structural baselines in @layer base. Put broad product choices, such as the page background and text color, in @layer defaults so component and utility styles can override them:
@import "@master/css";@layer base { html { color-scheme: light dark; } :where(button, input, textarea, select) { font: inherit; }}@layer defaults { body { background: var(--color-surface-base); color: var(--color-text-body); }}defaults means the project's broad visual defaults, not browser default styles. Keep named UI roles in @layer components and local adjustments in utilities. The preset base layer still connects the configured font tokens to the document's baseline typography.
Use the split base import only when a stylesheet needs the default layer order and browser normalization without the full Master CSS entry:
@import "@master/css/base.css";That is a specialized import. It does not replace the app entry in ordinary projects.
Site typeface
Treat the app typeface as global vocabulary. Put reusable font families and OpenType feature sets in @theme; the default base layer applies them to the inherited document targets for you.
@import "@master/css";@theme { --font-sans: "Geist", "Noto Sans TC"; --font-mono: "IBM Plex Mono"; --font-feature-sans: "ss02", "ss03", "ss04", "ss06", "ss07", "ss08"; --font-feature-mono: "cv01", "cv02", "cv29";}The base layer resolves --font-sans through --font-family-sans and applies it to body and shadow hosts. It resolves --font-mono through --font-family-mono and applies it to code, kbd, samp, and pre. Define --font-feature-sans and --font-feature-mono when those stacks need shared OpenType features; otherwise the base layer falls back to normal. Form controls inherit the surrounding font and feature settings.
Load the matching font files with normal @font-face rules or a provider stylesheet before depending on those family names. Keep one-off typeface changes in markup utilities such as font-mono; reserve the global typeface tokens for typography that should be inherited by the whole app.
Shared vocabulary
Reusable styling is an ownership decision. Keep local choices in markup while a pattern is changing. Promote only the part that has become shared.
Use this order:
- Keep one-off styling in markup utilities.
- Move repeated values into theme tokens.
- Write native global CSS for global selectors and app-wide stylesheet surfaces.
- Create custom utilities for reusable low-level primitives.
- Create component classes for repeated product UI roles.
- Write broad native defaults in
@layer defaults.
Start with utilities when the style belongs to one element or one usage site:
<button class="inline-flex items-center justify-center gap-xs px-md py-xs r-lg font-medium font-sm bg-blue fg-white"> Save changes</button>Do not abstract just to shorten a class list. Abstract when the name improves product vocabulary, such as btn, card, field, toolbar, or empty-state.
When the repeated part is a value, make it a token instead of a class:
@theme { --color-brand: var(--color-blue-60); --spacing-action-x: 1rem;}<button class="r-lg fg-white bg-brand px-action-x"> Submit</button>Use Theme Tokens for shared colors, spacing, typography, radius, shadow, motion, breakpoints, container sizes, and mode-specific values.
Write native CSS when the selector itself is global output you always ship:
.skip-link { position: fixed; left: 0; top: 0; z-index: 1; padding: var(--spacing-xs) var(--spacing-md); background-color: var(--color-blue); color: white; transform: translateY(-100%);}.skip-link:focus { transform: translateY(0);}Native global CSS is emitted as part of the app stylesheet. It is not generated on demand, so use it for global surfaces and selectors that should always exist.
Component classes
Use native component classes for repeated product roles. Define class selectors in @layer components and apply them from markup:
@layer components { .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--spacing-xs); padding: var(--spacing-xs) var(--spacing-md); border-radius: var(--radius-lg); background: var(--color-blue); color: white; }}<button class="btn">Save changes</button>Native component rules are emitted by default and follow source order within their layer. They do not become utilities: @compose btn and btn:hover@sm cannot reuse this definition. Write states and conditions inside the native rule. Native pruning is an explicit opt-in.
Keep component classes small enough to combine:
@layer components { .btn { display: inline-flex; align-items: center; justify-content: center; font-weight: 500; } .btn-sm { height: 2rem; padding-inline: var(--spacing-sm); border-radius: var(--radius-md); font-size: var(--font-size-xs); } .btn-md { height: 2.5rem; padding-inline: var(--spacing-md); border-radius: var(--radius-md); font-size: var(--font-size-sm); } .btn-primary { background: var(--color-blue); color: white; }}<button class="btn btn-md btn-primary">Submit</button>Put state behavior inside the component only when it belongs to every usage:
@layer components { .btn-primary { background: var(--color-blue); color: white; &:hover { background: var(--color-blue-60); } &:focus-visible { outline: 2px solid var(--color-blue); outline-offset: var(--spacing-4xs); } }}Use markup utilities for one-off variations at a specific call site.
Custom utilities
Use custom utilities for reusable primitives that are lower-level than product components. Good utility names describe a styling capability, not a UI role.
@utilities { flow { display: grid; gap: var(--spacing-md); } content-auto { content-visibility: auto; contain-intrinsic-size: auto 32rem; } print-hidden { @variant print { display: none; } }}<section class="content-auto flow print-hidden">...</section>Custom utilities are generated only when used. Use them for shared layout helpers, rendering hints, print behavior, or other primitives that should feel like part of the project class language.
Use component classes when the name describes a UI role. Use theme tokens when the reusable part is a value.
Organize global files
Split global CSS files by ownership, then import them from the app entry. Imported CSS becomes one project entry graph.
styles/ app.css theme.css base.css buttons.css@import "@master/css";@import "./theme.css";@import "./base.css";@import "./buttons.css";@layer components { .btn { display: inline-flex; align-items: center; justify-content: center; font-weight: 500; } .btn-primary { background: var(--color-blue); color: white; }}Keep project-wide tokens, variants, generated vocabulary, and native global CSS in the global entry graph. Keep route-specific selectors in Route-level styles, and promote them here only after they become shared.
Use @compose only when a shared utility owns behavior that should stay synchronized, such as a reusable focus ring. Native CSS is the default for component declarations; composition is optional.
Define shared design tokens with @theme for colors, spacing, typography, radius, breakpoints, containers, shadows, and motion.
Write route, page, and component-specific CSS with shared project definitions, native selectors, variants, container queries, and keyframes.