system

Installation

Host-owned composition. Illustrative demos below use data-au-elev / --au-elev-*; copy the install snippet into host CSS. Shallow UIs should keep semantic --au-surface / --au-surface-muted.

elevated.css
/* Nested elevation ladder (host copy). Light: shadow after step 2. Dark: lighter fills + layered shadow. */
:root {
 --au-elev-1: #fafafa; --au-elev-2: #fcfcfc; --au-elev-3: #fff; --au-elev-4: #fff;
 --au-elev-5: #fff; --au-elev-6: #fff; --au-elev-7: #fff; --au-elev-8: #fff;
 --au-elev-shadow-1: none;
 --au-elev-shadow-3: 0 0 0 1px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04), 0 4px 12px rgba(0,0,0,.06);
 --au-elev-shadow-5: 0 0 0 1px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.08);
 --au-elev-shadow-7: 0 0 0 1px rgba(0,0,0,.1), 0 4px 8px rgba(0,0,0,.05), 0 16px 40px rgba(0,0,0,.1);
}
:root[data-theme="dark"], html.dark {
 --au-elev-1: #171717; --au-elev-2: #1e1e1e; --au-elev-3: #252525; --au-elev-4: #2c2c2c;
 --au-elev-5: #333; --au-elev-6: #3a3a3a; --au-elev-7: #414141; --au-elev-8: #484848;
}
[data-au-elev] { background: var(--au-elev-bg); box-shadow: var(--au-elev-shadow); }
[data-au-elev="3"] { --au-elev-bg: var(--au-elev-3); --au-elev-shadow: var(--au-elev-shadow-3); }
[data-au-elev="5"] { --au-elev-bg: var(--au-elev-5); --au-elev-shadow: var(--au-elev-shadow-5); }
[data-au-elev="7"] { --au-elev-bg: var(--au-elev-7); --au-elev-shadow: var(--au-elev-shadow-7); }
/* Host rule: child overlay = parent level + 2 (page→3, dialog→5, menu-in-dialog→7). */

The problem

In light mode, shadow behind white surfaces signifies elevation. In dark mode, progressively lighter backgrounds do the work instead.

Fixed backgrounds break nesting: a dropdown that matches its dialog looks like one flat slab.

Same fill for dialog and menu — the menu disappears into the dialog.

Invite to your workspace

Select role
Member

The solution

Three pieces: tokens, substrate level, and an elevated wrapper. Components stay on semantic --au-surface*; hosts apply the ladder when overlays nest.

Tokens

Eight bg/shadow pairs. Light flattens to white after step 2 (shadow carries elevation). Dark keeps adding lightness plus a layered shadow recipe.

Dark

1
2
3
4
5
6
7
8

Light

1
2
3
4
5
6
7
8

Substrate

Each container knows its level. A menu on the page, inside a popover, and inside a dialog should each land two steps above their substrate — without props threaded through every opener.

On the page
BG #171717Menu #252525
Inside a popover
BG #252525Menu #333333
Inside a dialog
BG #333333Menu #414141

Elevated

Wrap a panel and set its level. The shadow recipe for that level stays; only the fill climbs, so a popover still reads as a popover three layers down.

Page
Card
Popover
Menu

Example

Invite dialog

Dialog at surface 5, role picker at surface 7 — no React context. Host sets data-au-elev from the parent substrate.

Correct: menu is two steps above the dialog fill.

Invite to your workspace

Select role
Member

Host contract

  • Semantic tokens (--au-surface, --au-surface-muted, --au-surface-hover) stay the default for shallow chrome.
  • When overlays nest (dialog → menu, card → popover), the host assigns levels: typically parent + 2.
  • dialog and future menus should not hard-code a single dark gray; they should inherit or receive a substrate level from the host.
  • Keep this ladder out of default component CSS unless a component contract explicitly depends on it.