Every visible container in the interface is a surface. Surfaces combine a fill, a border, and either a shadow or a backdrop blur to express how far they sit from the page plane.

The system has two families: static surfaces that form the layout structure and overlay surfaces that appear on top contextually.

Applying surfaces

A surface is always a token bundle, not a single token. Every surface has a matching set of tokens that share the same name in their group. Pick the surface, then apply its full set together.

For example, when building a raised card, use all tokens from the surface-raised group:

background: var(--color-fill-surface-raised);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-raised);

Surfaces that include a shadow or blur add it from the same family:

background: var(--color-fill-surface-action);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-action);
box-shadow: var(--shadow-surface-action);

Use outline, not border

Surface border tokens are built from semi-transparent primitives. A CSS border sits inside the element box, so the transparent border color blends with the container’s own fill and picks up its tint. Use outline instead — it renders outside the box, keeping the border color clean. On surfaces with a shadow, the outline produces a slightly darker contour that reinforces the elevation.

Do

Apply the full token bundle of a surface together — fill, border, and shadow must all come from the same surface name.

Don’t

Mix tokens across surfaces. Using fill-surface-raised with border-surface-action breaks the elevation hierarchy.

Do

Use surface-raised for static cards and surface-action only when the entire surface is clickable.

Don’t

Use surface-action for everything just because it looks more prominent. It signals interactivity — misuse makes the hierarchy noisy.

Do

Use outline for surface borders when building a container from scratch. The border renders outside the box and stays clean against transparent primitives.

Don’t

Use border for surface containers. The inner border blends with the fill through its transparency and picks up the background tint.

Do

Pair surface-sticky with its backdrop blur so the content below remains visible but softened.

Don’t

Drop a solid fill on a sticky header. The connection between the header and the scrolling content breaks.

Light and dark mode

Light mode and dark mode use fundamentally different models to express elevation. The same token names produce visually different results — but the hierarchy stays consistent.

Light mode

sunken
page
raised
modeless

Surfaces get lighter as they rise. Shadows carry the visual weight of elevation.

Dark mode

sunken
page
raised
modeless

Shadows are barely visible. Elevation is expressed by surfaces getting progressively lighter.

A raised card in light mode is white on a light-grey page. In dark mode, the same card is a lighter grey on a darker grey page. The visual relationship inverts, but the token names stay the same — surface-raised always sits above surface-page.

All surface tokens swap automatically between themes. No manual overrides or separate dark-mode code paths are needed — semantic tokens resolve to the correct primitive for each theme.

Page surface

The page surface is the default background of every screen. It is the baseline plane — every other surface is measured relative to it. Page has no border and no shadow.

surface-page

Page

The baseline page background. The bottom of the elevation scale.

Page

Apply to the root of the layout. All static surfaces sit above it and all overlays float over it. Page uses only a single fill token — no border, no shadow.

Used by: Page body, Layout root, Screen background

Tokens in bundle

background: var(--color-fill-surface-page);

Static surfaces

Static surfaces sit above the page and form the structural backbone of the layout. They do not move, do not float, and do not appear contextually.

surface-sunken

Sunken

A recessed plane that sits below the page.

Sunken

Use for inset areas, grouped list containers, or any region that should feel pushed into the page plane. Has a subtle fill darker than page and a soft border.

Used by: Grouped lists, Code blocks, Inset panels

Tokens in bundle

background: var(--color-fill-surface-sunken);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-sunken);
surface-raised

Raised

A standard card or panel lifted above the page.

Raised

The default choice for cards, content panels, and any container that needs a gentle elevation above the page. Raised surfaces use only fill and border — no shadow.

Used by: Cards, Content panels, Form groups

Tokens in bundle

background: var(--color-fill-surface-raised);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-raised);
surface-action

Action

An interactive raised surface. A card that responds to hover and press.

Action

Use when the entire surface is clickable — link cards, selectable tiles, or interactive content blocks. Action has its own shadow scale and distinct hover and pressed states.

Used by: Clickable cards, Link tiles, Selectable content blocks

Tokens in bundle

background: var(--color-fill-surface-action);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-action);
box-shadow: var(--shadow-surface-action);

Overlay surfaces

Overlay surfaces float above static surfaces. Each overlay is tied to a specific component family — use the one that matches the component you are building. The order below reflects the stacking order, from lowest to highest.

  1. 1
    Sticky Appears on scroll, behind fixed chrome
  2. 2
    Fixed Always-on chrome — navbars, sidebars
  3. 3
    Modeless Popovers, tooltips, toasts — above chrome
  4. 4
    Modal Top of the stack, blocks everything below
surface-sticky

Sticky

A dynamic overlay that appears on scroll. Semi-transparent with a backdrop blur.

Sticky

Does not exist in the default page state — it appears behind sticky headers and scroll-anchored elements when content scrolls underneath. Always paired with a backdrop blur so the content below remains visible but softened.

Used by: Sticky headers, Scroll-anchored toolbars, Anchored sub-navigation

Tokens in bundle

background: var(--color-fill-surface-sticky);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-sticky);
backdrop-filter: blur(var(--blur-surface-sticky));
surface-fixed

Fixed

A permanent overlay pinned to the layout. Always visible regardless of scroll.

Fixed

Use for components with an absolute position in the layout — navbars, sidebars, navigation rails, bottom bars. Fixed surfaces are on the page at all times and may be expanded or minimized, but their position never changes.

Used by: Navbars, Sidebars, Navigation rails, Bottom bars

Tokens in bundle

background: var(--color-fill-surface-fixed);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-fixed);
box-shadow: var(--shadow-surface-fixed);
surface-modeless

Modeless

Non-blocking overlays that appear near their trigger.

default
brand
info
warning
critical
neutral-dark

Use for popovers, tooltips, dropdowns, toasts, and alerts. Modeless has colored variants for brand, critical, info, warning, and neutral-dark messaging surfaces.

Used by: Popovers, Tooltips, Dropdowns, Toasts, Alerts

Tokens in bundle

background: var(--color-fill-surface-modeless);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-modeless);
box-shadow: var(--shadow-surface-modeless);
surface-modal

Modal

The top of the surface stack. Paired with a full-page underlay.

Modal

Reserved for modal dialogs. The modal surface floats above everything else while the modal-underlay fill covers the rest of the page behind it, combined with a backdrop blur. Use only for blocking, focused interactions.

Used by: Modal dialogs, Confirmation dialogs, Full-screen prompts

Tokens in bundle

background: var(--color-fill-surface-modal);
outline: var(--primitive-border-width-1) solid var(--color-border-surface-modal);
box-shadow: var(--shadow-surface-modal);

/* underlay */
background: var(--color-fill-surface-modal-underlay);
backdrop-filter: blur(var(--blur-surface-modal-underlay));

Token reference

Every surface fill and border token, flat. Shadows and blurs used by surfaces live in v2/core/effects.css.

Surface fills

Preview Semantic name Primitive reference
--color-fill-surface-sunken
L semantic
--color-fill-surface-page
L semantic
--color-fill-surface-raised
L semantic
--color-fill-surface-action
L semantic
--color-fill-surface-action-hovered
L semantic
--color-fill-surface-action-pressed
L semantic
--color-fill-surface-sticky
L semantic
--color-fill-surface-fixed
L semantic
--color-fill-surface-modeless
L semantic
--color-fill-surface-modeless-brand
L semantic
--color-fill-surface-modeless-critical
L semantic
--color-fill-surface-modeless-info
L semantic
--color-fill-surface-modeless-warning
L semantic
--color-fill-surface-modeless-neutral-dark
L semantic
--color-fill-surface-modal
L semantic
--color-fill-surface-modal-underlay
L semantic

Surface borders

Preview Semantic name Primitive reference
--color-border-surface-sunken
L semantic
--color-border-surface-raised
L semantic
--color-border-surface-action
L semantic
--color-border-surface-action-hovered
L semantic
--color-border-surface-action-pressed
L semantic
--color-border-surface-sticky
L semantic
--color-border-surface-fixed
L semantic
--color-border-surface-modeless
L semantic
--color-border-surface-modeless-brand
L semantic
--color-border-surface-modeless-critical
L semantic
--color-border-surface-modeless-info
L semantic
--color-border-surface-modeless-warning
L semantic
--color-border-surface-modeless-neutral-dark
L semantic
--color-border-surface-modal
L semantic
Page tokens