@apliteni/apliteni-ui 0.70.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
@@ -298,8 +298,8 @@
298
298
  max-width: var(--prose-caption);
299
299
  padding: var(--space-2) var(--space-3);
300
300
  background: var(--ui-tip-bg);
301
- border: 1px solid var(--border-strong);
302
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
301
+ border: 1px solid var(--float-edge);
302
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
303
303
  border-radius: var(--radius-sm);
304
304
  font-family: var(--font-sans);
305
305
  font-size: var(--text-xs);
@@ -46,8 +46,8 @@
46
46
  max-width: var(--panel-md);
47
47
  overflow: hidden; /* clips the timer bar to the rounded corners */
48
48
  background: var(--surface); --ring-gap: var(--surface);
49
- border: 1px solid var(--border);
50
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
49
+ border: 1px solid var(--float-edge);
50
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
51
51
  animation: ui-toast-in var(--dur-med) var(--ease-out) both;
52
52
  }
53
53
 
@@ -1,13 +1,16 @@
1
1
  /* ============================================================================
2
- * Card — .ui-card (a filled surface one step off the page, edged by a hairline)
2
+ * Card — .ui-card (a filled surface one step off the page: edged in dark, dropped in light)
3
3
  * Rows: .ui-card__row / headers: .ui-card__title / .ui-card__sub
4
4
  * ========================================================================== */
5
5
 
6
- /* Flat since #284 and edged in both themes since #295: the surface is the step, the
7
- line is what makes it legible. why: docs/specification.md#elevation */
6
+ /* The surface is the step; what makes it legible depends on the theme. Dark edges the
7
+ card with the hairline (--card-edge). Light draws no line at all and casts --elev-rest
8
+ instead — a 22px penumbra off a 10px offset, the width Artur's reference uses on a
9
+ card. Chosen by him on #490 round t3. why: docs/specification.md#elevation */
8
10
  .ui-card {
9
11
  background: var(--surface); --ring-gap: var(--surface);
10
- border: 1px solid var(--border);
12
+ border: 1px solid var(--card-edge);
13
+ box-shadow: var(--elev-rest);
11
14
  border-radius: var(--radius-xl);
12
15
  /* Was `var(--space-6) 26px`; 26 is off the scale and broke the column's text edge.
13
16
  why: docs/specification.md#spacing-and-rhythm */
@@ -50,13 +53,14 @@
50
53
  cursor: pointer;
51
54
  /* Written as a <button>, the card would take the browser's frame, centred text and
52
55
  `font: 400 13.3333px Arial` — a shorthand, so `font: inherit` and not the family
53
- longhand. .ui-card states the background and, since #295, the border, so a
54
- `border: 0` here would only delete the hairline. #251 */
56
+ longhand. .ui-card states the background, the border and its rung, so a
57
+ `border: 0` here would only delete the edge dark draws. #251 */
55
58
  text-align: left;
56
59
  font: inherit;
57
60
  transition: transform var(--dur-fast) var(--ease);
58
61
  }
59
- /* The lift alone: the kit casts no shadow anywhere (#295), and cards are flat (#284). */
62
+ /* The lift alone: the card's own rung is what says it is raised, and hover is not a
63
+ change of level. why: docs/specification.md#elevation */
60
64
  .ui-card--interactive:hover { transform: translateY(-2px); }
61
65
  .ui-card--interactive:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); }
62
66
 
@@ -69,10 +69,12 @@
69
69
  flex-direction: column;
70
70
  font-family: var(--font-sans);
71
71
  background: var(--cmdk-surface); --ring-gap: var(--cmdk-surface);
72
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
73
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
74
- border: 1px solid var(--border-strong);
75
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
72
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
73
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
74
+ both lines are transparent and the drop carries the whole separation.
75
+ why: docs/specification.md#elevation */
76
+ border: 1px solid var(--float-edge);
77
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
76
78
  border-radius: var(--radius-lg);
77
79
  overflow: hidden;
78
80
  opacity: 0;
@@ -86,7 +88,7 @@
86
88
  box-shadow list replaces the whole list, so `box-shadow: var(--ring)` alone
87
89
  took the panel's edge and its drop off for as long as it held focus.
88
90
  why: docs/specification.md#elevation */
89
- .ui-cmdk__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); }
91
+ .ui-cmdk__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); }
90
92
 
91
93
  /* -- The text box --------------------------------------------------------- */
92
94
 
@@ -62,10 +62,12 @@
62
62
  gap: var(--space-2);
63
63
  padding: var(--space-5);
64
64
  background: var(--confirm-surface); --ring-gap: var(--confirm-surface);
65
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
66
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
67
- border: 1px solid var(--border-strong);
68
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
65
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
66
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
67
+ both lines are transparent and the drop carries the whole separation.
68
+ why: docs/specification.md#elevation */
69
+ border: 1px solid var(--float-edge);
70
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
69
71
  border-radius: var(--radius-lg);
70
72
  opacity: 0;
71
73
  transform: translateY(8px);
@@ -78,7 +80,7 @@
78
80
  box-shadow list replaces the whole list, so `box-shadow: var(--ring)` alone
79
81
  took the panel's edge and its drop off for as long as it held focus.
80
82
  why: docs/specification.md#elevation */
81
- .ui-confirm__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); }
83
+ .ui-confirm__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); }
82
84
 
83
85
  /* -- Slots ----------------------------------------------------------------- */
84
86
  /* The question and the answers keep their size; the consequence between them is
@@ -82,14 +82,14 @@
82
82
  }
83
83
  .ui-drawer--right .ui-drawer__panel {
84
84
  right: 0;
85
- border-left: 1px solid var(--border-strong);
86
- --drawer-line: inset 1px 0 0 var(--border);
85
+ border-left: 1px solid var(--float-edge);
86
+ --drawer-line: inset 1px 0 0 var(--float-edge-inner);
87
87
  transform: translateX(100%);
88
88
  }
89
89
  .ui-drawer--left .ui-drawer__panel {
90
90
  left: 0;
91
- border-right: 1px solid var(--border-strong);
92
- --drawer-line: inset -1px 0 0 var(--border);
91
+ border-right: 1px solid var(--float-edge);
92
+ --drawer-line: inset -1px 0 0 var(--float-edge-inner);
93
93
  transform: translateX(-100%);
94
94
  }
95
95
  .ui-drawer--top .ui-drawer__panel,
@@ -100,14 +100,14 @@
100
100
  }
101
101
  .ui-drawer--top .ui-drawer__panel {
102
102
  top: 0;
103
- border-bottom: 1px solid var(--border-strong);
104
- --drawer-line: inset 0 -1px 0 var(--border);
103
+ border-bottom: 1px solid var(--float-edge);
104
+ --drawer-line: inset 0 -1px 0 var(--float-edge-inner);
105
105
  transform: translateY(-100%);
106
106
  }
107
107
  .ui-drawer--bottom .ui-drawer__panel {
108
108
  bottom: 0;
109
- border-top: 1px solid var(--border-strong);
110
- --drawer-line: inset 0 1px 0 var(--border);
109
+ border-top: 1px solid var(--float-edge);
110
+ --drawer-line: inset 0 1px 0 var(--float-edge-inner);
111
111
  transform: translateY(100%);
112
112
  }
113
113
 
@@ -71,10 +71,12 @@
71
71
  /* The floating step, not the sunken one — a panel held open over a card cannot be
72
72
  painted the colour of an inset. why: docs/specification.md#elevation */
73
73
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated);
74
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
75
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
76
- border: 1px solid var(--border-strong);
77
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
74
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
75
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
76
+ both lines are transparent and the drop carries the whole separation.
77
+ why: docs/specification.md#elevation */
78
+ border: 1px solid var(--float-edge);
79
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
78
80
  border-radius: var(--radius-lg);
79
81
  padding: var(--ui-dropdown-pad);
80
82
  opacity: 0;
@@ -102,7 +104,7 @@
102
104
  a panel that takes focus any other way has the same claim on the ring. The
103
105
  ring is COMPOSED with the floating treatment rather than over it: a box-shadow
104
106
  list replaces the whole list. why: docs/specification.md#elevation */
105
- .ui-dropdown__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); }
107
+ .ui-dropdown__panel:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring), inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); }
106
108
 
107
109
  /* Opening upward. The kit releases its own `top` here so that nothing outside
108
110
  the kit has to: an absolute box with both edges pinned is stretched between
@@ -67,8 +67,12 @@
67
67
  .ui-fbcomposer {
68
68
  position: fixed; z-index: 71; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(14px);
69
69
  width: min(520px, calc(100vw - 32px)); background: var(--bg-elevated); --ring-gap: var(--bg-elevated); border-radius: 18px;
70
- /* The shadow was its only edge until #295; now it takes the hairline. */
71
- border: 1px solid var(--border); opacity: 0; pointer-events: none;
70
+ /* The shadow was its only edge until #295, which replaced it with the hairline; since
71
+ #490 light is back on the drop and dark keeps the line.
72
+ why: docs/specification.md#elevation */
73
+ border: 1px solid var(--float-edge);
74
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
75
+ opacity: 0; pointer-events: none;
72
76
  transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease); overflow: hidden;
73
77
  }
74
78
  .ui-fbcomposer.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
@@ -28,7 +28,9 @@
28
28
  .ui-app-page .topbar { position: sticky; top: 0; z-index: var(--z-sticky); }
29
29
 
30
30
  /* The rail uses the card surface so its labels stay on a reading ground.
31
- Its border separates navigation from the page in both themes.
31
+ Dark keeps its edge (--rail-edge); light casts --elev-rail, sideways, because the rail
32
+ is flush to a screen edge. Reopens the light half of #454.
33
+ why: docs/specification.md#elevation
32
34
  overflow-y, because the box is pinned at the viewport's height for the whole
33
35
  scroll of .ui-app — without it a row past that height paints below the fold
34
36
  and no amount of document scrolling brings it back. The rail's own padding is
@@ -38,7 +40,8 @@
38
40
  flex-direction: column;
39
41
  gap: var(--space-5);
40
42
  padding: var(--space-5) var(--space-4);
41
- border-right: var(--ui-rail-rule) solid var(--border);
43
+ border-right: var(--ui-rail-rule) solid var(--rail-edge);
44
+ box-shadow: var(--elev-rail);
42
45
  background: var(--surface); --ring-gap: var(--surface);
43
46
  position: sticky;
44
47
  top: var(--ui-app-top, 0px);
@@ -296,7 +299,7 @@
296
299
  why: docs/specification.md#elevation */
297
300
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item:is(:hover, :focus-visible) > .ui-nav__label,
298
301
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-app__user-trigger:is(:hover, :focus-visible) > .ui-app__who,
299
- .ui-app__rail .ui-app__fold:is(:hover, :focus-visible) > .ui-nav__label { position: fixed; left: calc(var(--ui-rail-w) + var(--space-2)); z-index: var(--z-dropdown); width: max-content; max-width: 15rem; margin-block: -7px; padding: 6px 10px; border: 1px solid var(--border-strong); box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); border-radius: var(--radius-xs); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); opacity: 1; pointer-events: none; }
302
+ .ui-app__rail .ui-app__fold:is(:hover, :focus-visible) > .ui-nav__label { position: fixed; left: calc(var(--ui-rail-w) + var(--space-2)); z-index: var(--z-dropdown); width: max-content; max-width: 15rem; margin-block: -7px; padding: 6px 10px; border: 1px solid var(--float-edge); box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); border-radius: var(--radius-xs); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); opacity: 1; pointer-events: none; }
300
303
  @supports (anchor-name: --a) and (anchor-scope: --a) {
301
304
  .ui-app.is-collapsed,
302
305
  .ui-app:has(.ui-app__fold) { anchor-scope: --ui-rail; }
@@ -395,7 +398,7 @@
395
398
  .ui-app__search:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); border-color: var(--accent); }
396
399
  /* The same glyph the palette draws in its own search box, at the same box and the
397
400
  same stroke: the trigger and the thing it opens are not two search marks.
398
- src/styles/command-palette.css:107 `.ui-cmdk__search-ic svg` */
401
+ src/styles/command-palette.css:109 `.ui-cmdk__search-ic svg` */
399
402
  .ui-app__search-ic { display: flex; flex: none; }
400
403
  .ui-app__search-ic svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2.2; }
401
404
  /* Part of the button's name, so it is squeezed rather than dropped: an ellipsis
@@ -497,7 +500,7 @@
497
500
  .ui-app__rail .ui-nav__item,
498
501
  .ui-app__rail .ui-app__user-trigger { min-height: 44px; }
499
502
  .ui-app__rail .ui-nav__item:is(:hover, :focus-visible) > .ui-nav__label,
500
- .ui-app__rail .ui-app__user-trigger:is(:hover, :focus-visible) > .ui-app__who { position: fixed; left: calc(var(--ui-rail-w) + var(--space-2)); z-index: var(--z-dropdown); width: max-content; max-width: 15rem; margin-block: -7px; padding: 6px 10px; border: 1px solid var(--border-strong); box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop); border-radius: var(--radius-xs); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); opacity: 1; pointer-events: none; }
503
+ .ui-app__rail .ui-app__user-trigger:is(:hover, :focus-visible) > .ui-app__who { position: fixed; left: calc(var(--ui-rail-w) + var(--space-2)); z-index: var(--z-dropdown); width: max-content; max-width: 15rem; margin-block: -7px; padding: 6px 10px; border: 1px solid var(--float-edge); box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); border-radius: var(--radius-xs); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); opacity: 1; pointer-events: none; }
501
504
  @supports (anchor-name: --a) and (anchor-scope: --a) {
502
505
  .ui-app { anchor-scope: --ui-rail; }
503
506
  .ui-app__rail { anchor-name: --ui-rail; }
@@ -529,10 +532,12 @@
529
532
  z-index: 1;
530
533
  width: 100%;
531
534
  max-width: var(--panel-md);
532
- /* Floats over a spotlit page, so it takes the floating step and the hairline.
535
+ /* Floats over a spotlit page, so it takes the floating step and the floating
536
+ treatment: the two-step edge in dark, the drop alone in light.
533
537
  why: docs/specification.md#elevation */
534
538
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated);
535
- border: 1px solid var(--border);
539
+ border: 1px solid var(--float-edge);
540
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
536
541
  border-radius: 22px;
537
542
  padding: 38px 36px 32px;
538
543
  }
@@ -17,7 +17,10 @@
17
17
  overflow: hidden;
18
18
  border-radius: 20px;
19
19
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated); /* Elevated surface for the confirmation and its actions. */
20
- border: 1px solid var(--border);
20
+ /* The floating treatment, like every other surface on that step.
21
+ why: docs/specification.md#elevation */
22
+ border: 1px solid var(--float-edge);
23
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
21
24
  isolation: isolate;
22
25
  }
23
26
 
@@ -26,10 +26,12 @@
26
26
  max-width: var(--prose-caption);
27
27
  padding: var(--space-2) var(--space-3);
28
28
  background: var(--ui-tip-bg); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */
29
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
30
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
31
- border: 1px solid var(--border-strong);
32
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
29
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
30
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
31
+ both lines are transparent and the drop carries the whole separation.
32
+ why: docs/specification.md#elevation */
33
+ border: 1px solid var(--float-edge);
34
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
33
35
  border-radius: var(--radius-sm);
34
36
  font-family: var(--font-sans);
35
37
  font-size: var(--text-xs);
@@ -129,10 +129,12 @@
129
129
  left: 0;
130
130
  min-width: 266px;
131
131
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
132
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
133
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
134
- border: 1px solid var(--border-strong);
135
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
132
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
133
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
134
+ both lines are transparent and the drop carries the whole separation.
135
+ why: docs/specification.md#elevation */
136
+ border: 1px solid var(--float-edge);
137
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
136
138
  border-radius: 16px;
137
139
  padding: 6px;
138
140
  opacity: 0;
@@ -186,7 +188,7 @@
186
188
  transition: background var(--dur-fast) var(--ease);
187
189
  }
188
190
  /* Menu rows use the reading surface and an edge on hover — see
189
- src/styles/dropdown.css:164 `.ui-dropdown__item:hover`.
191
+ src/styles/dropdown.css:166 `.ui-dropdown__item:hover`.
190
192
  why: docs/specification.md#elevation */
191
193
  .vopt:hover { outline: 1px solid var(--control-edge); outline-offset: -1px; background: var(--surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ }
192
194
  /* The row is a keyboard stop: src/components/dropdown.js:554
@@ -238,10 +240,12 @@
238
240
  right: 0; top: 44px;
239
241
  width: 252px;
240
242
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
241
- /* The two-step edge and the drop: --border-strong outside, --border one pixel
242
- inside it, then the broad faint drop. why: docs/specification.md#elevation */
243
- border: 1px solid var(--border-strong);
244
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
243
+ /* The two-step edge and the drop, through the level's own names: in DARK that is
244
+ --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
245
+ both lines are transparent and the drop carries the whole separation.
246
+ why: docs/specification.md#elevation */
247
+ border: 1px solid var(--float-edge);
248
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
245
249
  border-radius: 14px;
246
250
  overflow: hidden;
247
251
  opacity: 0;
@@ -133,10 +133,10 @@
133
133
  --pink: #e97ca5;
134
134
  --amber: #ffcf6a;
135
135
 
136
- /* The elevation ladder, bottom to top. A surface says how high it is with its step and
137
- with the hairline around it, and --muted caps how far the ladder can go. Nothing casts
138
- below the floating step; the floating step itself adds --elev-drop under its inner
139
- line and nothing else in the kit does. why: docs/specification.md#elevation */
136
+ /* The elevation ladder, bottom to top. A surface says how high it is with its step
137
+ and, IN DARK, with the hairline around it; --muted caps how far the ladder can go.
138
+ Nothing casts in dark below the floating step, and the floating step adds
139
+ --elev-drop under its inner line. why: docs/specification.md#elevation */
140
140
  --bg: #0e0d14;
141
141
  --table-bg: var(--bg);
142
142
  --surface-2: #161520; /* non-text sunken marks and tracks */
@@ -150,6 +150,15 @@
150
150
  --border: #332f45;
151
151
  --border-strong: #453f5c;
152
152
 
153
+ /* WHICH EDGE EACH LEVEL DRAWS. One name per level, so a sheet never has to ask
154
+ which theme it is in. Dark answers all four with the hairline, because a drop
155
+ on a near-black page reaches 1.20 at its core and has nowhere else to go —
156
+ light answers them with the drop instead. why: docs/specification.md#elevation */
157
+ --card-edge: var(--border); /* a card */
158
+ --rail-edge: var(--border); /* the shell's rail */
159
+ --float-edge: var(--border-strong); /* a floating surface, outer line */
160
+ --float-edge-inner: var(--border); /* a floating surface, inner line */
161
+
153
162
  /* Fields use the card surface and an edge in both themes. why: docs/specification.md#elevation */
154
163
  --field-bg: var(--surface);
155
164
  --field-edge: var(--border);
@@ -257,13 +266,20 @@
257
266
  token and cannot be — a var() inside a custom property is substituted on the
258
267
  element that DECLARES it, so an --elev-edge read here resolves at :root and
259
268
  nothing below could re-point it. A floating surface writes the pair itself:
260
- box-shadow: inset 0 0 0 1px var(--elev-edge, var(--border)), var(--elev-drop);
269
+ box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
261
270
  Dark spends 62% / 50% of the ink and reaches 1.20 at the drop's core, having
262
271
  nowhere to go on a near-black page. why: docs/specification.md#elevation */
263
272
  --elev-drop:
264
273
  0 14px 30px -12px color-mix(in srgb, var(--shadow-ink) 62%, transparent),
265
274
  0 3px 9px -4px color-mix(in srgb, var(--shadow-ink) 50%, transparent);
266
275
 
276
+ /* The ladder's two resting rungs, which only light climbs. Transparent here and
277
+ not `none`, for the reason the deprecated --shadow-* tokens are: these are read
278
+ in a layer list, and `none` is valid only alone — it would invalidate the whole
279
+ declaration and take the focus ring with it. why: docs/specification.md#elevation */
280
+ --elev-rest: 0 0 #0000; /* a card */
281
+ --elev-rail: 0 0 #0000; /* the shell's rail, cast sideways */
282
+
267
283
  /* Backdrop that dims the page behind an overlay (drawer, modal, composer). */
268
284
  --scrim: rgba(0, 0, 0, 0.58);
269
285
 
@@ -312,6 +328,17 @@
312
328
  --border: #e4e7ee;
313
329
  --border-strong: #cdd2dc;
314
330
 
331
+ /* Light draws a LEVEL with a drop and no line at all. Decided by Artur on the
332
+ #490 triage round t3: "It's better" — the soft shadow over the hairline, against
333
+ the reference he supplied. A line divides two regions of ONE surface (a card's
334
+ rows, a table's rules, the rail's head band, the topbar); a drop says a surface
335
+ is HIGHER, and only a higher surface may cast one.
336
+ why: docs/specification.md#elevation */
337
+ --card-edge: transparent;
338
+ --rail-edge: transparent;
339
+ --float-edge: transparent;
340
+ --float-edge-inner: transparent;
341
+
315
342
  /* Light draws a field with its EDGE, because since #448 it has no well left to draw it
316
343
  with: a card and a panel are both white, the sunken step falls two rungs under either,
317
344
  and --border on it measures 1.047:1. why: docs/specification.md#elevation */
@@ -389,12 +416,21 @@
389
416
  --shadow-ink: #1e1e32;
390
417
  --sheen: #ffffff;
391
418
 
392
- /* 18% / 10% against dark's 62% / 50%. Light's ink is #1e1e32 on a card that is
393
- now #ffffff, and 18% is what puts the drop core at #d7d7da — 1.44, the strongest
394
- separation either theme gets. why: docs/specification.md#elevation */
419
+ /* THE LIGHT LADDER. Three rungs, each two layers: a wide faint one and a short one.
420
+ Each layer is offset on one axis, blurred at least twice as wide as it is offset,
421
+ and held in by a negative spread. None is a glow — a glow is a zero-offset layer of
422
+ the signal's own colour. A level with no line casts a rung that reaches on every
423
+ side it exposes, which is why the wide layer's offset stays under half its blur.
424
+ why: docs/specification.md#elevation */
425
+ --elev-rest:
426
+ 0 2px 26px -3px color-mix(in srgb, var(--shadow-ink) 9%, transparent),
427
+ 0 1px 3px -1px color-mix(in srgb, var(--shadow-ink) 7%, transparent);
428
+ --elev-rail:
429
+ 10px 0 24px -14px color-mix(in srgb, var(--shadow-ink) 16%, transparent),
430
+ 1px 0 3px -1px color-mix(in srgb, var(--shadow-ink) 7%, transparent);
395
431
  --elev-drop:
396
- 0 14px 30px -12px color-mix(in srgb, var(--shadow-ink) 18%, transparent),
397
- 0 3px 9px -4px color-mix(in srgb, var(--shadow-ink) 10%, transparent);
432
+ 0 20px 46px -16px color-mix(in srgb, var(--shadow-ink) 22%, transparent),
433
+ 0 1px 14px -4px color-mix(in srgb, var(--shadow-ink) 12%, transparent);
398
434
 
399
435
  --scrim: rgba(20, 22, 40, 0.38);
400
436