Elevation levels, recesses and status fills, with their light and dark values, the parts that own them and how each separates from its parent.
Hierarchy comes from elevation levels, not from background colors. Each level pairs a fill and a shadow for each theme. In light mode every level shares one near-white fill, and the shadow alone shows elevation. Dark mode separates levels with lightness steps, and surface and raised have no shadow.
This page lists each level, the recesses and the status fills. For role shadow tokens and how Box and Card apply them, see Elevation. For the full color token list, see Colors.
Elevation levels
Bind to the semantic token, not to a ramp step. A component on --color-bg-overlay gets the right fill in both themes with no per-component override.
Level
Fill token
Light
Dark
canvas
--color-bg-default
step 2 (#fcfcfd), no shadow
step 1 (#090a0e), no shadow
surface
--color-bg-default in light, --color-bg-surface in dark
Same fill as canvas (#fcfcfd), no shadow. A surface region looks like the canvas.
step 3 (#1c1f27), no shadow
raised
--color-bg-raised
step 1 (#ffffff) plus --elevation-xs-shadow
step 3 (#1c1f27), no shadow
overlay
--color-bg-overlay
step 1 (#ffffff) plus --elevation-overlay-shadow (md)
step 4 (#252832) plus --elevation-overlay-shadow
modal
--color-bg-modal
step 1 (#ffffff) plus --elevation-modal-shadow (xl)
step 5 (#2d313d) plus --elevation-modal-shadow
tooltip
--color-bg-tooltip
step 1 (#ffffff) plus --elevation-overlay-shadow
step 6 (#373a4a) plus --elevation-overlay-shadow
In light mode the modal shadow is stronger than before: the xl shadow layer alpha is now 0.07, up from 0.03.
Owners and separation
Level
Owning parts
Separates from its parent by
canvas
AppShell
Nothing. It is the page, and it has no shadow.
surface
None. Sidebar is not at this level; see the notes below.
Nothing in light, because the fill matches the canvas. Lightness step in dark. No shadow.
raised
Panel, Card, Toolbar, the settings-section card
Shadow in light, lightness step in dark (no shadow)
overlay
Popover, Menu, ContextMenu, Drawer, Toast
Shadow in light, lightness step in dark
modal
Dialog, AlertDialog
Shadow in light, lightness step in dark
tooltip
Tooltip
Shadow in light, lightness step in dark
Notes on the table:
The step numbers and hex values come from the comments in packages/ui/src/tokens/axon-colors.css. The comments on the --color-bg-* tokens describe their older pairing of fill and shadow. The elevation-level tokens are what parts bind to.
Each level exposes its fill as --elevation-level-<level>-fill and its shadow as --elevation-level-<level>-shadow. Canvas and surface have no shadow. Raised has the xs shadow in light only. Overlay and tooltip use the overlay shadow in both themes. Modal uses the modal shadow in both themes. Some parts keep their own shadow, as noted below.
Sidebar is the one exception. It is not at a level. It paints --color-bg-surface directly in both themes (light #e9eaef, step 4; dark #1c1f27, step 3) and has no shadow. It therefore stays gray in light mode, while the surface level looks like the canvas.
Dialog and AlertDialog are on the modal level: the modal fill (--color-bg-modal) and --elevation-modal-shadow.
Drawer and Toast use the overlay fill and keep their own shadows: the directional drawer shadows (--elevation-drawer-block-start-shadow and --elevation-drawer-block-end-shadow) and --elevation-toast-shadow.
Card keeps its own elevation prop. A Card with no shadow requested shows the raised fill without a shadow.
Panels and the settings-section card keep their border in both themes.
In dark mode, raised uses the same step as surface (step 3) and has no shadow. The panel border separates it from its parent.
One shadow per stack
Only the outermost elevated surface casts a shadow. A Box or Card with a level is nested when its nearest level ancestor is raised, overlay, modal or tooltip. A nested Box paints the --color-fill-subtle wash and no shadow. A Box whose nearest level ancestor is canvas, surface or nothing keeps its level's fill and shadow.
Only a Box with a level counts. A plain Box with a background neither starts a stack nor makes its children nested.
A nested Box or Card also shows no shadow from the older elevation prop (Elevation.*, CardElevation.*).
Floating parts start a new stack. Dialog and AlertDialog are on the modal level. Popover, Menu, ContextMenu and Drawer are on the overlay level. Their own surface keeps its shadow, even when opened from a Panel, and their content counts as nested. A Card inside a Dialog shows the wash and no shadow.
A Card nested two deep gets the same wash as its parent. Treat that as a composition mistake. A review rule for it is ticketed as CORE-2390, and it will be flagged in review.
Nesting
Where the surface is
Fill
Shadow
On the canvas (nearest level ancestor is canvas, surface or none)
Its level's fill
Its level's shadow
Nested in an elevated surface (nearest level ancestor is raised, overlay, modal or tooltip)
--color-fill-subtle wash
None
Inside a floating part (Dialog, AlertDialog, Popover, Menu, ContextMenu, Drawer)
The part's own surface keeps its fill and shadow. Content inside it is nested: --color-fill-subtle wash
The part's own surface keeps its shadow. Nested content has none
A wash fill composites over whatever surface is behind it, so it works in any parent. Use one of these:
--color-bg-input
--color-fill-subtle, --color-fill-default or --color-fill-strong
--color-recess-subtle, --color-recess-default or --color-recess-strong
Do not use the opaque -solid twins for this. They match only when the parent is the page.
Recesses
Recesses are insets that sit below their parent. They are washes, so they composite over any level.
Token
Use
--color-recess-subtle
Zebra rows and table stripes
--color-recess-default
Inset wells and input fields on a panel
--color-recess-strong
Code blocks and empty states
The --color-recess-<weight>-solid tokens are opaque and match only on the page. See Colors for the swatches of the surface and fill tokens.
Status fills
Status fills use --color-status-<intent>-bg for destructive, warning, success and informative. They composite over any parent, so a status fill does not change with the level it sits on. Pair each background with the same intent's foreground. See Colors for the swatches.
Rules for apps and remotes
App and remote code never sets a fill on a remote's root or on a panel body. The shell owns the slot's frame.
Do not add a shadow inside an elevated surface. Set a level and let Box choose the wash.
Bind to the semantic fill token. Do not read a ramp step.
Translucent fills
A translucent fill lets the content behind a surface show through. Use one for a surface over a map or media, such as a floating card or a panel over a map. Set backgroundAlpha (enum BackgroundAlpha, Percent5 to Percent95) on Box or FlexBox. It is accepted only with these backgrounds, at or above the floor for each:
Background
Token
Lowest alpha for text
Allowed values
Background.Default
--color-bg-default-alpha-<n>
90
90, 95
Background.Raised
--color-bg-raised-alpha-<n>
85
85, 90, 95
Background.Overlay
--color-bg-overlay-alpha-<n>
90
90, 95
<n> is the percent opaque.
How the floors are set:
Chroma measures --color-fg-default, --color-fg-muted, --color-accent-fg and --color-accent-link on each fill over pure black and pure white backdrops, in both themes. Those two backdrops are the worst case for any content behind the surface.
A level counts only when every pair passes both WCAG contrast and APCA. The floor is the lowest level from which every higher level counts. It differs by surface because the surfaces differ in lightness.
Chroma's check fails if a floor drifts from the measurement.
Levels below the floor make no text claim. They are internal to the design system, for temporary drag feedback. Do not use them for content people need to read.
Contrast fallbacks:
With prefers-contrast: more, the fill is opaque.
With forced colors, the fill paints Canvas.
Level tokens
Each level has --elevation-level-<level>-fill and --elevation-level-<level>-shadow, for example --elevation-level-raised-fill and --elevation-level-raised-shadow. Parts bind to these tokens, not to a fill and a shadow chosen by hand. The tokens come from Chroma and reach @prepared911/ui with the Chroma advance.