1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
---
title: Elevation
summary: >-
Two shadow levels only. A bounded surface reads by being a step lighter
than what's behind it, not by a border around its edge; shadow is reserved
for the one floating layer in a view.
---
## Surface contrast does the work
This system's own rule: no border marks the edge of a bounded surface. A
flat [Card](<%= relative_url('/components/card/') %>) is the default
everywhere — `--gl-color-surface-card` is one neutral step lighter than
`--gl-color-surface-page` around it, and that tonal step is what reads as
"a card," not an outline. Shadow is the exception, not the baseline.
Hairlines have not disappeared from the system — a
[CardRow](<%= relative_url('/components/card-row/') %>) still divides from
its neighbor on one, a table still rules its rows, an underline tab still
sits on one — they just no longer wrap a whole surface. A divider inside a
card; never a border around one.
## The two levels
<ul class="gl-elevation-grid">
<li>
<div class="gl-elevation-demo" style="box-shadow: 0 1px 2px rgba(20, 18, 14, 0.05);"></div>
<div class="gl-specimen__meta"><code>shadow-sm</code></div>
<p class="gl-muted" style="font-size: var(--gl-step--2); margin: var(--gl-space-3xs) 0 0;">Barely-there separation — a Switch thumb, a focused Input.</p>
</li>
<li>
<div class="gl-elevation-demo" style="box-shadow: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);"></div>
<div class="gl-specimen__meta"><code>shadow-float</code></div>
<p class="gl-muted" style="font-size: var(--gl-step--2); margin: var(--gl-space-3xs) 0 0;">The one floating layer in a view. Apply it to at most one element on screen at a time.</p>
</li>
</ul>
<figure class="example">
<figcaption>Flat vs. float</figcaption>
<div data-layout="grid" data-surface="sunken">
<article class="card">
<div class="card-body">
<h3 style="font-size: var(--gl-step--1);">Flat</h3>
<p>The default. A step lighter than the page, no border, no shadow.</p>
</div>
</article>
<article class="card" data-elevated>
<div class="card-body">
<h3 style="font-size: var(--gl-step--1);">Elevated</h3>
<p>shadow-float. Reserved for one element per view — a Dialog, a Toast.</p>
</div>
</article>
</div>
<details><summary>Markup</summary>
<pre><code><article class="card">
<div class="card-body">
<h3>Flat</h3>
<p>The default. A step lighter than the page, no border, no shadow.</p>
</div>
</article>
<article class="card" data-elevated>
<div class="card-body">
<h3>Elevated</h3>
<p>shadow-float. Reserved for one element per view — a Dialog, a Toast.</p>
</div>
</article></code></pre>
</details>
</figure>
## Elevation in the dark theme
Shadows barely register on a near-black surface. The dark theme leans on
surface lightness instead — `--gl-color-surface-card` is one neutral step
lighter than `--gl-color-surface-page`, same as in light mode. The shadow
tokens still apply; they simply stop being the primary signal.
## Rules
- **At most one `--gl-shadow-float` on screen.** If two things both claim to
be the topmost layer, neither is.
- **No border around a bounded surface, ever.** Surface contrast does the
identifying work a border would; a card that borders and floats looks like
a sticker.
- **Never animate a shadow's blur.** If a floated element needs to arrive,
animate its `opacity`, or do not animate it at all.