@godxjp/ui 18.3.0 → 18.5.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/README.md +18 -3
- package/dist/app/theme-axes.d.ts +11 -3
- package/dist/app/theme-axes.js +2 -1
- package/dist/components/charts/chart-frame.d.ts +17 -3
- package/dist/components/charts/chart-frame.js +7 -1
- package/dist/components/charts/chart-summary.d.ts +21 -0
- package/dist/components/charts/chart-summary.js +32 -5
- package/dist/components/charts/compact-bar-trend.d.ts +29 -0
- package/dist/components/charts/compact-bar-trend.js +74 -0
- package/dist/components/charts/index.d.ts +3 -0
- package/dist/components/charts/index.js +2 -0
- package/dist/components/data-display/badge.d.ts +8 -0
- package/dist/components/data-display/badge.js +7 -1
- package/dist/components/data-display/data-table.d.ts +16 -1
- package/dist/components/data-display/data-table.js +56 -0
- package/dist/components/data-display/index.d.ts +3 -1
- package/dist/components/data-display/index.js +10 -1
- package/dist/components/data-display/list-row.d.ts +22 -4
- package/dist/components/data-display/list-row.js +21 -3
- package/dist/components/data-display/service-launcher-card.d.ts +40 -0
- package/dist/components/data-display/service-launcher-card.js +97 -0
- package/dist/components/data-entry/command-palette.d.ts +37 -0
- package/dist/components/data-entry/command-palette.js +125 -0
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/feedback/dialog.d.ts +2 -0
- package/dist/components/feedback/dialog.js +42 -33
- package/dist/components/feedback/index.d.ts +4 -1
- package/dist/components/feedback/index.js +6 -2
- package/dist/components/feedback/sheet.d.ts +26 -4
- package/dist/components/feedback/sheet.js +54 -7
- package/dist/components/feedback/two-factor-setup.d.ts +31 -0
- package/dist/components/feedback/two-factor-setup.js +97 -0
- package/dist/components/general/index.d.ts +1 -1
- package/dist/components/general/logo.d.ts +42 -8
- package/dist/components/general/logo.js +67 -14
- package/dist/components/layout/app-shell.js +22 -6
- package/dist/components/layout/auth-divider.d.ts +7 -0
- package/dist/components/layout/auth-divider.js +21 -0
- package/dist/components/layout/auth-footer.d.ts +5 -0
- package/dist/components/layout/auth-footer.js +24 -0
- package/dist/components/layout/auth-identity.d.ts +5 -0
- package/dist/components/layout/auth-identity.js +17 -0
- package/dist/components/layout/auth-shell.d.ts +8 -1
- package/dist/components/layout/auth-shell.js +25 -6
- package/dist/components/layout/auth-stack.d.ts +4 -0
- package/dist/components/layout/auth-stack.js +8 -0
- package/dist/components/layout/centered-shell.d.ts +5 -2
- package/dist/components/layout/centered-shell.js +2 -1
- package/dist/components/layout/index.d.ts +18 -3
- package/dist/components/layout/index.js +17 -2
- package/dist/components/layout/legal-document-shell.d.ts +34 -0
- package/dist/components/layout/legal-document-shell.js +186 -0
- package/dist/components/layout/master-detail.d.ts +24 -0
- package/dist/components/layout/master-detail.js +48 -0
- package/dist/components/layout/org-switcher.d.ts +9 -0
- package/dist/components/layout/org-switcher.js +218 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +3 -2
- package/dist/components/layout/sidebar-link.d.ts +43 -0
- package/dist/components/layout/sidebar-link.js +13 -0
- package/dist/components/layout/sidebar.d.ts +42 -5
- package/dist/components/layout/sidebar.js +170 -85
- package/dist/components/navigation/app-setting-picker.js +17 -6
- package/dist/components/navigation/filter-bar.d.ts +12 -3
- package/dist/components/navigation/filter-bar.js +8 -2
- package/dist/components/navigation/index.d.ts +2 -2
- package/dist/components/navigation/index.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +70 -0
- package/dist/components/navigation/tabs-scroll.js +76 -0
- package/dist/components/navigation/tabs.js +35 -20
- package/dist/email/brand-mark.d.ts +92 -0
- package/dist/email/brand-mark.js +83 -0
- package/dist/email/color.d.ts +52 -0
- package/dist/email/color.js +37 -0
- package/dist/email/geometry.d.ts +112 -0
- package/dist/email/geometry.js +89 -0
- package/dist/email/index.d.ts +78 -0
- package/dist/email/index.js +76 -0
- package/dist/email/inline-style.d.ts +25 -0
- package/dist/email/inline-style.js +21 -0
- package/dist/email/tokens.generated.d.ts +147 -0
- package/dist/email/tokens.generated.js +142 -0
- package/dist/i18n/messages/en.json +21 -2
- package/dist/i18n/messages/ja.json +21 -2
- package/dist/i18n/messages/vi.json +21 -2
- package/dist/inertia/index.d.ts +50 -0
- package/dist/inertia/index.js +5 -0
- package/dist/props/components/app.prop.d.ts +11 -1
- package/dist/props/components/charts.prop.d.ts +40 -1
- package/dist/props/components/data-display.prop.d.ts +13 -1
- package/dist/props/components/feedback.prop.d.ts +10 -0
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +374 -11
- package/dist/props/components/layout.prop.js +1 -0
- package/dist/props/components/navigation.prop.d.ts +19 -1
- package/dist/props/registry.d.ts +291 -7
- package/dist/props/registry.js +341 -7
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +1 -1
- package/dist/props/vocabulary/layout.prop.d.ts +18 -0
- package/dist/styles/base.css +9 -3
- package/dist/styles/card-layout.css +162 -8
- package/dist/styles/chart-layout.css +97 -0
- package/dist/styles/control.css +48 -2
- package/dist/styles/data-display-layout.css +52 -6
- package/dist/styles/dialog-layout.css +105 -4
- package/dist/styles/fonts.css +29 -20
- package/dist/styles/index.css +11 -3
- package/dist/styles/layout.css +368 -2
- package/dist/styles/logo-layout.css +62 -0
- package/dist/styles/navigation-layout.css +43 -0
- package/dist/styles/shell-layout.css +505 -62
- package/dist/theme/dxs.canonical.css +76 -0
- package/dist/tokens/axes.css +39 -0
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/card.css +52 -5
- package/dist/tokens/components/chart.css +47 -0
- package/dist/tokens/components/control.css +16 -0
- package/dist/tokens/components/email.css +66 -0
- package/dist/tokens/components/feedback.css +17 -0
- package/dist/tokens/components/legal-document.css +67 -0
- package/dist/tokens/components/list-row.css +23 -2
- package/dist/tokens/components/logo.css +32 -0
- package/dist/tokens/components/navigation.css +13 -0
- package/dist/tokens/components/sheet.css +19 -0
- package/dist/tokens/components/shell.css +149 -1
- package/dist/tokens/components/sidebar.css +33 -0
- package/dist/tokens/foundation.css +5 -2
- package/dist/tokens/semantic/layout.css +44 -2
- package/package.json +17 -6
|
@@ -6,26 +6,31 @@
|
|
|
6
6
|
@layer components {
|
|
7
7
|
.app-root {
|
|
8
8
|
display: grid;
|
|
9
|
+
width: 100%;
|
|
10
|
+
max-width: 100vw;
|
|
11
|
+
min-width: 0;
|
|
9
12
|
grid-template-areas:
|
|
10
13
|
"sidebar topbar"
|
|
11
14
|
"sidebar main"
|
|
12
15
|
"sidebar footer";
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
/* Rail width is a knob, never a literal (rule #45) — a service on a different design grid sets
|
|
17
|
+
* --app-shell-sidebar-width once (e.g. 255px) instead of forking this rule. */
|
|
18
|
+
grid-template-columns: var(--app-shell-sidebar-width) minmax(0, 1fr);
|
|
19
|
+
grid-template-rows: var(--app-shell-bar-height) minmax(0, 1fr) auto;
|
|
15
20
|
height: 100vh;
|
|
16
|
-
background:
|
|
17
|
-
linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
|
|
18
|
-
hsl(var(--background));
|
|
21
|
+
background: hsl(var(--background));
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
.app-root[data-collapsed="true"] {
|
|
22
|
-
grid-template-columns:
|
|
25
|
+
grid-template-columns: var(--app-shell-rail-width) minmax(0, 1fr);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
.app-sidebar {
|
|
26
29
|
grid-area: sidebar;
|
|
27
30
|
display: flex;
|
|
31
|
+
height: 100%;
|
|
28
32
|
min-width: 0;
|
|
33
|
+
min-height: 0;
|
|
29
34
|
flex-direction: column;
|
|
30
35
|
overflow: hidden;
|
|
31
36
|
border-inline-end: 1px solid hsl(var(--border));
|
|
@@ -42,14 +47,14 @@
|
|
|
42
47
|
* set to baseline; --scaling:1 alone is not enough — see foundation.css). */
|
|
43
48
|
display: flex;
|
|
44
49
|
min-width: 0;
|
|
50
|
+
overflow: hidden;
|
|
45
51
|
align-items: center;
|
|
46
|
-
gap: var(--
|
|
47
|
-
padding-inline: var(--
|
|
52
|
+
gap: var(--app-shell-bar-gap);
|
|
53
|
+
padding-inline: var(--app-shell-bar-inset);
|
|
48
54
|
border-bottom: 1px solid hsl(var(--border));
|
|
49
|
-
background: hsl(var(--
|
|
55
|
+
background: hsl(var(--card));
|
|
50
56
|
/* Opt-in brand-chrome wash — invisible by default (--topbar-gradient: none). */
|
|
51
57
|
background-image: var(--topbar-gradient);
|
|
52
|
-
backdrop-filter: blur(12px);
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
.app-main {
|
|
@@ -69,6 +74,7 @@
|
|
|
69
74
|
* content can never extend the document scroll height (gh#104 — same shell-containment
|
|
70
75
|
* family as the gh#103 body-stretch void). */
|
|
71
76
|
contain: paint;
|
|
77
|
+
background-color: var(--app-shell-main-background);
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
.app-footer {
|
|
@@ -78,7 +84,8 @@
|
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
.app-main .ui-page-container {
|
|
81
|
-
|
|
87
|
+
width: 100%;
|
|
88
|
+
max-width: var(--app-shell-page-max-width);
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
/*
|
|
@@ -92,9 +99,7 @@
|
|
|
92
99
|
display: flex;
|
|
93
100
|
min-height: 100dvh;
|
|
94
101
|
flex-direction: column;
|
|
95
|
-
background:
|
|
96
|
-
linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
|
|
97
|
-
hsl(var(--background));
|
|
102
|
+
background: hsl(var(--muted));
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
.ui-auth-shell-bar {
|
|
@@ -108,7 +113,7 @@
|
|
|
108
113
|
flex: 1 1 auto;
|
|
109
114
|
flex-direction: column;
|
|
110
115
|
align-items: center;
|
|
111
|
-
justify-content:
|
|
116
|
+
justify-content: var(--auth-shell-main-align);
|
|
112
117
|
padding: var(--auth-shell-main-padding);
|
|
113
118
|
}
|
|
114
119
|
|
|
@@ -123,6 +128,174 @@
|
|
|
123
128
|
color: hsl(var(--muted-foreground));
|
|
124
129
|
}
|
|
125
130
|
|
|
131
|
+
.ui-auth-shell[data-variant="canonical"] {
|
|
132
|
+
--control-height: var(--auth-shell-canonical-control-height);
|
|
133
|
+
--heading-h1: var(--auth-shell-canonical-heading-size);
|
|
134
|
+
--auth-shell-card-max-width: var(--auth-shell-canonical-card-max-width);
|
|
135
|
+
--auth-shell-main-padding: var(--auth-shell-canonical-main-padding);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/*
|
|
139
|
+
* NAMED FLOW PRESETS (gh#217 / gh#220) — orthogonal to `variant` and declared AFTER it (equal
|
|
140
|
+
* specificity, so source order wins) so a preset re-measures the page while `variant="canonical"`
|
|
141
|
+
* keeps owning control density and heading size. A preset owns the card measure + page gutters,
|
|
142
|
+
* so the consumer never overrides `--auth-shell-card-max-width` by hand.
|
|
143
|
+
*/
|
|
144
|
+
.ui-auth-shell[data-preset] .ui-auth-shell-card {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
gap: var(--auth-shell-card-stack-gap);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ui-auth-shell[data-preset="device-authorization"] {
|
|
151
|
+
--auth-shell-card-max-width: var(--auth-shell-device-card-max-width);
|
|
152
|
+
--auth-shell-main-padding: var(--auth-shell-device-main-padding);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.ui-auth-shell[data-preset="context-selection"] {
|
|
156
|
+
--auth-shell-card-max-width: var(--auth-shell-context-card-max-width);
|
|
157
|
+
--auth-shell-main-padding: var(--auth-shell-context-main-padding);
|
|
158
|
+
--auth-shell-card-stack-gap: var(--auth-shell-context-card-stack-gap);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* Account-recovery preset (gh#233) — one 432px measure for BOTH SCR-008 panels (password
|
|
162
|
+
* recovery and the sign-in MFA challenge). Title + description live INSIDE the bordered surface
|
|
163
|
+
* here, so the panel is `Card > CardHeader(CardTitle + CardDescription)` with no `AuthIdentity`
|
|
164
|
+
* mark above it — the preset only re-measures the page, it never dictates content. */
|
|
165
|
+
.ui-auth-shell[data-preset="account-recovery"] {
|
|
166
|
+
--auth-shell-card-max-width: var(--auth-shell-recovery-card-max-width);
|
|
167
|
+
--auth-shell-main-padding: var(--auth-shell-recovery-main-padding);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.ui-auth-identity {
|
|
171
|
+
display: flex;
|
|
172
|
+
flex-direction: column;
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: var(--auth-identity-gap);
|
|
175
|
+
text-align: center;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.ui-auth-requester {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
gap: var(--auth-requester-gap);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ui-auth-requester-icon {
|
|
185
|
+
display: inline-flex;
|
|
186
|
+
width: var(--auth-requester-icon-size);
|
|
187
|
+
height: var(--auth-requester-icon-size);
|
|
188
|
+
align-items: center;
|
|
189
|
+
justify-content: center;
|
|
190
|
+
border-radius: var(--radius-sm);
|
|
191
|
+
background: hsl(var(--accent));
|
|
192
|
+
color: hsl(var(--primary));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ui-auth-requester-icon > svg {
|
|
196
|
+
width: var(--auth-requester-glyph-size);
|
|
197
|
+
height: var(--auth-requester-glyph-size);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ui-auth-legal-footer {
|
|
201
|
+
display: flex;
|
|
202
|
+
flex-wrap: wrap;
|
|
203
|
+
align-items: center;
|
|
204
|
+
justify-content: center;
|
|
205
|
+
gap: var(--auth-footer-content-gap);
|
|
206
|
+
color: hsl(var(--muted-foreground));
|
|
207
|
+
font-family: var(--font-mono);
|
|
208
|
+
font-size: var(--auth-footer-text-font-size);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.ui-auth-legal-footer-item {
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
gap: var(--auth-footer-content-gap);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.ui-auth-stack {
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-direction: column;
|
|
220
|
+
gap: var(--auth-stack-gap);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ui-auth-shell[data-variant="canonical"] .ui-form-field {
|
|
224
|
+
--field-label-gap: var(--auth-shell-field-label-gap);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.ui-auth-shell[data-variant="canonical"] [data-slot="form-field-label"] [data-slot="label"] {
|
|
228
|
+
font-size: var(--auth-shell-field-label-font-size);
|
|
229
|
+
line-height: var(--auth-shell-field-label-line-height);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* Compact auth card density — the two card axes are wired to SEPARATE knobs (gh#232), so a
|
|
234
|
+
* service can shorten the canonical Login card without narrowing its column (or vice versa):
|
|
235
|
+
* inline column ← --auth-shell-compact-card-inset → --card-space-inset
|
|
236
|
+
* block padding ← --auth-shell-card-padding-block-compact → --card-space-shell-y
|
|
237
|
+
* header↔body ← --auth-shell-card-body-gap-compact → --card-space-body-y
|
|
238
|
+
* solo body ← --auth-shell-card-padding-block-compact → --card-space-solo-y
|
|
239
|
+
* The block knob is `initial` at :root, so its default resolves HERE against the live inset —
|
|
240
|
+
* canonical output is byte-identical to pre-gh#232 while the knob is now actually consumed.
|
|
241
|
+
* --card-space-solo-y is mapped EXPLICITLY as well as via the shell-y fallback: a solo body
|
|
242
|
+
* takes both block edges symmetrically, and naming it here keeps that contract legible at the
|
|
243
|
+
* one place a reader looks for the compact card's spacing.
|
|
244
|
+
*/
|
|
245
|
+
.ui-auth-shell[data-density="compact"] .ui-auth-shell-card {
|
|
246
|
+
--card-space-inset: var(--auth-shell-compact-card-inset);
|
|
247
|
+
--card-space-shell-y: var(
|
|
248
|
+
--auth-shell-card-padding-block-compact,
|
|
249
|
+
var(--auth-shell-compact-card-inset)
|
|
250
|
+
);
|
|
251
|
+
--card-space-body-y: var(--auth-shell-card-body-gap-compact);
|
|
252
|
+
--card-space-solo-y: var(
|
|
253
|
+
--auth-shell-card-padding-block-compact,
|
|
254
|
+
var(--auth-shell-compact-card-inset)
|
|
255
|
+
);
|
|
256
|
+
--card-space-gap: var(--auth-shell-card-gap-compact);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ui-auth-divider {
|
|
260
|
+
display: grid;
|
|
261
|
+
width: 100%;
|
|
262
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
263
|
+
align-items: center;
|
|
264
|
+
gap: var(--auth-shell-divider-gap);
|
|
265
|
+
color: hsl(var(--auth-shell-divider-label-color));
|
|
266
|
+
font-size: var(--auth-shell-divider-label-font-size);
|
|
267
|
+
line-height: 1;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.ui-auth-divider-rule {
|
|
271
|
+
height: 1px;
|
|
272
|
+
background: hsl(var(--auth-shell-divider-rule-color));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@media (max-width: 30rem) {
|
|
276
|
+
.ui-auth-shell[data-variant="canonical"] {
|
|
277
|
+
--auth-shell-main-padding: var(--auth-shell-canonical-main-padding-mobile);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Declared after the canonical mobile inset so a preset's mobile gutter wins at equal
|
|
281
|
+
* specificity: device-authorization = 5px inline (card x=5, width=380 at 390px);
|
|
282
|
+
* context-selection = edge-to-edge (0 inline). */
|
|
283
|
+
.ui-auth-shell[data-preset="device-authorization"] {
|
|
284
|
+
--auth-shell-main-padding: var(--auth-shell-device-main-padding-mobile);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.ui-auth-shell[data-preset="context-selection"] {
|
|
288
|
+
--auth-shell-main-padding: var(--auth-shell-context-main-padding-mobile);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* account-recovery = 15px inline at 390 (panel x=15, width=360). This is a DECIDED mobile
|
|
292
|
+
* contract — the supplied 390 canonical reference is a desktop 2x2 composite that overflows
|
|
293
|
+
* horizontally and is not a valid source (gh#233). */
|
|
294
|
+
.ui-auth-shell[data-preset="account-recovery"] {
|
|
295
|
+
--auth-shell-main-padding: var(--auth-shell-recovery-main-padding-mobile);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
126
299
|
/*
|
|
127
300
|
* CENTERED SHELL — authenticated, no-sidebar, centred-column page shell (hosted-ID "My Page",
|
|
128
301
|
* account / self-service, standalone settings). A flex column over the same brand-wash surface as
|
|
@@ -135,9 +308,7 @@
|
|
|
135
308
|
display: flex;
|
|
136
309
|
min-height: 100dvh;
|
|
137
310
|
flex-direction: column;
|
|
138
|
-
background:
|
|
139
|
-
linear-gradient(180deg, hsl(var(--primary) / 0.035), transparent 14rem),
|
|
140
|
-
hsl(var(--background));
|
|
311
|
+
background: hsl(var(--muted));
|
|
141
312
|
}
|
|
142
313
|
|
|
143
314
|
.ui-centered-shell-bar {
|
|
@@ -149,10 +320,9 @@
|
|
|
149
320
|
gap: var(--space-3);
|
|
150
321
|
padding-inline: var(--centered-shell-bar-padding-x);
|
|
151
322
|
border-bottom: 1px solid hsl(var(--border));
|
|
152
|
-
background: hsl(var(--
|
|
323
|
+
background: hsl(var(--card));
|
|
153
324
|
/* Opt-in brand-chrome wash — shares the topbar hook, invisible by default (none). */
|
|
154
325
|
background-image: var(--topbar-gradient);
|
|
155
|
-
backdrop-filter: blur(12px);
|
|
156
326
|
}
|
|
157
327
|
|
|
158
328
|
.ui-centered-shell-main {
|
|
@@ -171,9 +341,17 @@
|
|
|
171
341
|
.ui-centered-shell-column {
|
|
172
342
|
width: 100%;
|
|
173
343
|
margin-inline: auto;
|
|
344
|
+
/* Block offset knob — `0` (top-aligned page, the default) or `auto` (viewport-centred system
|
|
345
|
+
* surface via `align="center"`). Auto margins absorb the free space of the flex `main`, and
|
|
346
|
+
* collapse to 0 when the content overflows, so tall content still scrolls from the top. */
|
|
347
|
+
margin-block: var(--centered-shell-column-offset-block);
|
|
174
348
|
max-width: var(--centered-shell-width-md);
|
|
175
349
|
}
|
|
176
350
|
|
|
351
|
+
.ui-centered-shell-column[data-align="center"] {
|
|
352
|
+
--centered-shell-column-offset-block: auto;
|
|
353
|
+
}
|
|
354
|
+
|
|
177
355
|
.ui-centered-shell-column[data-width="sm"] {
|
|
178
356
|
max-width: var(--centered-shell-width-sm);
|
|
179
357
|
}
|
|
@@ -217,11 +395,36 @@
|
|
|
217
395
|
margin-inline-end: var(--space-1);
|
|
218
396
|
}
|
|
219
397
|
|
|
398
|
+
/* Drawer scrim = a SHARE of the ONE shared semantic scrim (--overlay-background), resolved at the
|
|
399
|
+
* call site so a scoped [data-tenant]/.dark override of --overlay-background reaches the portaled
|
|
400
|
+
* drawer (docs/TOKENS.md · "Role-mirror knobs MUST be `initial`"). Default resolves to the same
|
|
401
|
+
* rgb(0 0 0 / 0.2) it has always been; setting --app-shell-mobile-nav-background still wins. */
|
|
402
|
+
[data-slot="sheet-overlay"].app-mobile-nav-overlay {
|
|
403
|
+
background-color: var(
|
|
404
|
+
--app-shell-mobile-nav-background,
|
|
405
|
+
color-mix(in srgb, var(--overlay-background) var(--app-shell-mobile-nav-alpha), transparent)
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.app-mobile-nav-drawer {
|
|
410
|
+
padding-block-start: max(var(--sheet-pad-y), env(safe-area-inset-top));
|
|
411
|
+
padding-block-end: max(var(--sheet-pad-y), env(safe-area-inset-bottom));
|
|
412
|
+
padding-inline-start: max(var(--sheet-pad-x), env(safe-area-inset-left));
|
|
413
|
+
padding-inline-end: max(var(--sheet-pad-x), env(safe-area-inset-right));
|
|
414
|
+
overscroll-behavior: contain;
|
|
415
|
+
}
|
|
416
|
+
|
|
220
417
|
/* The drawer nav reuses the docked Sidebar node; its `.sb-root { display: contents }` flattens
|
|
221
|
-
* into the scrollable SheetBody so sections/footer flow naturally in the panel.
|
|
418
|
+
* into the scrollable SheetBody so sections/footer flow naturally in the panel.
|
|
419
|
+
* The body's INLINE inset is tokenized on the component itself
|
|
420
|
+
* (`px-[var(--app-shell-mobile-nav-inset)]` in AppShell, which wins over SheetBody's generic
|
|
421
|
+
* `px-[var(--sheet-pad-x)]` because both are utilities) — the nav owns its edge instead of being
|
|
422
|
+
* double-padded (gh#211). Do NOT set `padding-inline` here: this file is `@layer components`, so
|
|
423
|
+
* a Tailwind utility on the element always wins. */
|
|
222
424
|
.app-mobile-nav-body {
|
|
223
425
|
display: flex;
|
|
224
426
|
flex-direction: column;
|
|
427
|
+
overscroll-behavior: contain;
|
|
225
428
|
}
|
|
226
429
|
|
|
227
430
|
.app-topbar-spacer {
|
|
@@ -235,7 +438,22 @@
|
|
|
235
438
|
font-size: var(--font-size-base);
|
|
236
439
|
}
|
|
237
440
|
|
|
238
|
-
|
|
441
|
+
/*
|
|
442
|
+
* THE ONE AppShell breakpoint — 900px (56.25rem), the DXS canonical value. It is stated in exactly
|
|
443
|
+
* two places and they must agree: this rule and `max-[900px]:inline-flex` on the hamburger in
|
|
444
|
+
* `app-shell.tsx` (a CSS @media cannot read a custom property, so the trigger's visibility has to
|
|
445
|
+
* repeat the number; making it a public knob needs a `data-shell-mode` attribute — tracked in the
|
|
446
|
+
* #213 audit, out of scope here).
|
|
447
|
+
*
|
|
448
|
+
* There used to be a SECOND, conflicting `@media (max-width: 768px)` block further down that also
|
|
449
|
+
* restructured `.app-root`. It (a) dropped the `"footer"` grid area and set `.app-footer{display:
|
|
450
|
+
* none}`, silently deleting whatever a consumer passed to AppShell's `footer` slot on a phone, and
|
|
451
|
+
* (b) re-declared the grid ROW template with a 3rem literal, overriding --app-shell-bar-height so
|
|
452
|
+
* a themed bar height was ignored below 768px only. Between 768 and 900 the sidebar was hidden by
|
|
453
|
+
* THIS rule while the grid still reserved a sidebar track — incoherent. Both are gone; the
|
|
454
|
+
* footer row and the bar-height token now hold at every width.
|
|
455
|
+
*/
|
|
456
|
+
@media (width <= 56.25rem) {
|
|
239
457
|
.app-root,
|
|
240
458
|
.app-root[data-collapsed="true"] {
|
|
241
459
|
grid-template-areas:
|
|
@@ -249,6 +467,11 @@
|
|
|
249
467
|
display: none;
|
|
250
468
|
}
|
|
251
469
|
|
|
470
|
+
/* The docked rail is gone, so the bar tightens against the viewport edge (knob, not a literal). */
|
|
471
|
+
.app-topbar {
|
|
472
|
+
padding-inline: var(--app-shell-bar-inset-compact);
|
|
473
|
+
}
|
|
474
|
+
|
|
252
475
|
.app-topbar-left:has(.app-mobile-sidebar-trigger) {
|
|
253
476
|
display: flex;
|
|
254
477
|
}
|
|
@@ -262,10 +485,132 @@
|
|
|
262
485
|
display: contents;
|
|
263
486
|
}
|
|
264
487
|
|
|
488
|
+
/*
|
|
489
|
+
* ORG SWITCHER — shared Console/Admin tenant control. Widths, insets and state geometry stay
|
|
490
|
+
* inside the library so a consumer never needs `w-64` or descendant-selector overrides.
|
|
491
|
+
*/
|
|
492
|
+
.ui-org-switcher {
|
|
493
|
+
width: 100%;
|
|
494
|
+
min-width: 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.ui-org-switcher[data-collapsed="true"] {
|
|
498
|
+
display: flex;
|
|
499
|
+
justify-content: center;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.ui-org-switcher-trigger {
|
|
503
|
+
width: 100%;
|
|
504
|
+
height: var(--org-switcher-trigger-height);
|
|
505
|
+
min-width: 0;
|
|
506
|
+
justify-content: flex-start;
|
|
507
|
+
padding-inline: var(--org-switcher-trigger-padding-x);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.ui-org-switcher-trigger[data-collapsed="true"] {
|
|
511
|
+
width: var(--org-switcher-trigger-height);
|
|
512
|
+
padding: 0;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.ui-org-switcher-avatar {
|
|
516
|
+
display: grid;
|
|
517
|
+
width: var(--org-switcher-avatar-size);
|
|
518
|
+
height: var(--org-switcher-avatar-size);
|
|
519
|
+
flex: 0 0 auto;
|
|
520
|
+
place-items: center;
|
|
521
|
+
overflow: hidden;
|
|
522
|
+
border-radius: var(--radius);
|
|
523
|
+
background: hsl(var(--secondary));
|
|
524
|
+
color: hsl(var(--secondary-foreground));
|
|
525
|
+
font-size: var(--sidebar-avatar-font-size);
|
|
526
|
+
font-weight: var(--font-weight-semibold);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.ui-org-switcher-avatar > * {
|
|
530
|
+
width: 100%;
|
|
531
|
+
height: 100%;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.ui-org-switcher-current,
|
|
535
|
+
.ui-org-switcher-option {
|
|
536
|
+
display: grid;
|
|
537
|
+
min-width: 0;
|
|
538
|
+
flex: 1;
|
|
539
|
+
text-align: start;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.ui-org-switcher-name,
|
|
543
|
+
.ui-org-switcher-meta {
|
|
544
|
+
overflow: hidden;
|
|
545
|
+
line-height: 1.25;
|
|
546
|
+
text-overflow: ellipsis;
|
|
547
|
+
white-space: nowrap;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.ui-org-switcher-name {
|
|
551
|
+
font-size: var(--sidebar-user-name-font-size);
|
|
552
|
+
font-weight: var(--font-weight-medium);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.ui-org-switcher-meta {
|
|
556
|
+
color: hsl(var(--org-switcher-meta-foreground));
|
|
557
|
+
font-size: var(--sidebar-user-role-font-size);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.ui-org-switcher-chevron,
|
|
561
|
+
.ui-org-switcher-check,
|
|
562
|
+
.ui-org-switcher-spinner {
|
|
563
|
+
width: 1rem;
|
|
564
|
+
height: 1rem;
|
|
565
|
+
flex: 0 0 auto;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.ui-org-switcher-chevron {
|
|
569
|
+
margin-inline-start: auto;
|
|
570
|
+
color: hsl(var(--muted-foreground));
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.ui-org-switcher-check {
|
|
574
|
+
margin-inline-start: auto;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.ui-org-switcher-popover {
|
|
578
|
+
width: min(var(--org-switcher-menu-width), calc(100vw - var(--space-4)));
|
|
579
|
+
padding: 0;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.ui-org-switcher-sheet {
|
|
583
|
+
max-height: var(--org-switcher-sheet-max-height);
|
|
584
|
+
border-start-start-radius: var(--radius-lg);
|
|
585
|
+
border-start-end-radius: var(--radius-lg);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.ui-org-switcher-command {
|
|
589
|
+
width: 100%;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.ui-org-switcher-state {
|
|
593
|
+
display: flex;
|
|
594
|
+
min-height: var(--org-switcher-state-min-height);
|
|
595
|
+
flex-direction: column;
|
|
596
|
+
align-items: center;
|
|
597
|
+
justify-content: center;
|
|
598
|
+
gap: var(--space-3);
|
|
599
|
+
padding: var(--space-5);
|
|
600
|
+
color: hsl(var(--muted-foreground));
|
|
601
|
+
text-align: center;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.ui-org-switcher-spinner {
|
|
605
|
+
animation: spin 1s linear infinite;
|
|
606
|
+
}
|
|
607
|
+
|
|
265
608
|
.sb-product,
|
|
266
609
|
.sb-brand {
|
|
267
610
|
display: flex;
|
|
268
|
-
min-
|
|
611
|
+
min-width: 0;
|
|
612
|
+
min-height: var(--app-shell-bar-height);
|
|
613
|
+
flex: 0 0 auto;
|
|
269
614
|
align-items: center;
|
|
270
615
|
gap: var(--space-2);
|
|
271
616
|
padding-inline: var(--space-4);
|
|
@@ -294,8 +639,8 @@
|
|
|
294
639
|
|
|
295
640
|
.sb-logo-mark {
|
|
296
641
|
display: grid;
|
|
297
|
-
width:
|
|
298
|
-
height:
|
|
642
|
+
width: var(--sidebar-brand-mark-size);
|
|
643
|
+
height: var(--sidebar-brand-mark-size);
|
|
299
644
|
flex: 0 0 auto;
|
|
300
645
|
place-items: center;
|
|
301
646
|
border-radius: var(--radius);
|
|
@@ -343,19 +688,22 @@
|
|
|
343
688
|
|
|
344
689
|
.sb-nav-scroll {
|
|
345
690
|
flex: 1;
|
|
691
|
+
min-height: 0;
|
|
692
|
+
overscroll-behavior: contain;
|
|
346
693
|
overflow-y: auto;
|
|
694
|
+
padding: var(--sidebar-nav-scroll-padding);
|
|
347
695
|
}
|
|
348
696
|
|
|
349
697
|
.sb-section {
|
|
350
|
-
padding:
|
|
698
|
+
padding: 0;
|
|
351
699
|
}
|
|
352
700
|
|
|
353
701
|
.sb-section + .sb-section {
|
|
354
|
-
|
|
702
|
+
margin-top: var(--sidebar-section-gap);
|
|
355
703
|
}
|
|
356
704
|
|
|
357
705
|
.sb-section-label {
|
|
358
|
-
padding: 0 var(--
|
|
706
|
+
padding: 0 var(--sidebar-section-label-padding-x) var(--sidebar-section-label-padding-bottom);
|
|
359
707
|
color: hsl(var(--muted-foreground));
|
|
360
708
|
font-size: var(--sidebar-section-label-font-size);
|
|
361
709
|
font-weight: 700;
|
|
@@ -367,30 +715,35 @@
|
|
|
367
715
|
.sb-nav {
|
|
368
716
|
display: flex;
|
|
369
717
|
flex-direction: column;
|
|
370
|
-
gap:
|
|
718
|
+
gap: var(--sidebar-nav-gap);
|
|
371
719
|
}
|
|
372
720
|
|
|
373
721
|
.sb-nav-item {
|
|
374
722
|
display: flex;
|
|
375
723
|
width: 100%;
|
|
376
|
-
height: var(--
|
|
724
|
+
height: var(--sidebar-nav-item-height);
|
|
377
725
|
min-width: 0;
|
|
726
|
+
flex: 0 0 auto;
|
|
378
727
|
align-items: center;
|
|
379
|
-
gap: var(--
|
|
380
|
-
padding-inline: var(--
|
|
728
|
+
gap: var(--sidebar-nav-item-gap);
|
|
729
|
+
padding-inline: var(--sidebar-nav-item-padding-x);
|
|
381
730
|
border: 0;
|
|
382
731
|
border-radius: calc(var(--radius) - 1px);
|
|
383
732
|
background: transparent;
|
|
384
|
-
|
|
733
|
+
/* gh#228 — the row/label foreground is its own knob (default = the muted role, unchanged). The
|
|
734
|
+
* icon reads a SEPARATE knob on `.sb-icon` below, so a service can darken 16px nav icons
|
|
735
|
+
* without re-tinting every muted text. */
|
|
736
|
+
color: var(--sidebar-nav-item-foreground, hsl(var(--muted-foreground)));
|
|
385
737
|
cursor: pointer;
|
|
386
738
|
font-family: inherit;
|
|
387
|
-
font-size: var(--font-size
|
|
739
|
+
font-size: var(--sidebar-nav-item-font-size);
|
|
740
|
+
line-height: 1;
|
|
388
741
|
text-align: start;
|
|
389
742
|
}
|
|
390
743
|
|
|
391
744
|
.sb-nav-item:hover {
|
|
392
745
|
background: hsl(var(--accent));
|
|
393
|
-
color: hsl(var(--foreground));
|
|
746
|
+
color: var(--sidebar-nav-item-hover-foreground, hsl(var(--foreground)));
|
|
394
747
|
}
|
|
395
748
|
|
|
396
749
|
/* Active item reads its own bg/fg tokens (defaults = the hover look) so a service can give the
|
|
@@ -404,15 +757,24 @@
|
|
|
404
757
|
|
|
405
758
|
.sb-icon {
|
|
406
759
|
display: grid;
|
|
407
|
-
width:
|
|
408
|
-
height:
|
|
760
|
+
width: var(--sidebar-nav-icon-size);
|
|
761
|
+
height: var(--sidebar-nav-icon-size);
|
|
409
762
|
flex: 0 0 auto;
|
|
763
|
+
line-height: 0;
|
|
410
764
|
place-items: center;
|
|
765
|
+
/* gh#228 — the nav ICON owns its own foreground knob; the default `currentColor` resolves to the
|
|
766
|
+
* row colour, so the resting look is byte-identical to before. A service sets
|
|
767
|
+
* `--sidebar-nav-icon-foreground` alone to get canonical darker icons beside muted labels — no
|
|
768
|
+
* page-local selector, no global `--muted-foreground` re-tint. Colour only: size/geometry stay
|
|
769
|
+
* on --sidebar-nav-icon-size. */
|
|
770
|
+
color: var(--sidebar-nav-icon-foreground, currentColor);
|
|
411
771
|
}
|
|
412
772
|
|
|
413
773
|
.sb-icon svg {
|
|
414
|
-
|
|
415
|
-
|
|
774
|
+
display: block;
|
|
775
|
+
width: var(--sidebar-nav-icon-size);
|
|
776
|
+
height: var(--sidebar-nav-icon-size);
|
|
777
|
+
flex: 0 0 auto;
|
|
416
778
|
}
|
|
417
779
|
|
|
418
780
|
.sb-label {
|
|
@@ -469,7 +831,9 @@
|
|
|
469
831
|
.sb-nav-item--sub {
|
|
470
832
|
height: 1.75rem;
|
|
471
833
|
font-size: var(--sidebar-nav-sub-font-size);
|
|
472
|
-
|
|
834
|
+
/* Same row knob as a top-level row (gh#228) — one override themes the whole nav, sub rows
|
|
835
|
+
* included. Default unchanged. */
|
|
836
|
+
color: var(--sidebar-nav-item-foreground, hsl(var(--muted-foreground)));
|
|
473
837
|
}
|
|
474
838
|
|
|
475
839
|
.sb-nav-item--sub::before {
|
|
@@ -484,7 +848,7 @@
|
|
|
484
848
|
|
|
485
849
|
.sb-nav-item--sub:hover {
|
|
486
850
|
background: transparent;
|
|
487
|
-
color: hsl(var(--foreground));
|
|
851
|
+
color: var(--sidebar-nav-item-hover-foreground, hsl(var(--foreground)));
|
|
488
852
|
}
|
|
489
853
|
|
|
490
854
|
.sb-nav-item--sub[data-active="true"] {
|
|
@@ -498,6 +862,42 @@
|
|
|
498
862
|
opacity: 1;
|
|
499
863
|
}
|
|
500
864
|
|
|
865
|
+
/* gh#228 — nav ICON state knobs. Declared AFTER the row-state rules so they win at equal
|
|
866
|
+
* specificity, in the same order the row states resolve (hover → active → disabled). Each falls
|
|
867
|
+
* back to the base icon knob and finally to `currentColor` (= the row colour for that state), so
|
|
868
|
+
* the defaults are byte-identical to the pre-gh#228 rendering and setting only
|
|
869
|
+
* `--sidebar-nav-icon-foreground` themes every state at once. Colour only — no geometry. */
|
|
870
|
+
.sb-nav-item:hover .sb-icon {
|
|
871
|
+
color: var(
|
|
872
|
+
--sidebar-nav-icon-hover-foreground,
|
|
873
|
+
var(--sidebar-nav-icon-foreground, currentColor)
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.sb-nav-item[data-active="true"] .sb-icon {
|
|
878
|
+
color: var(
|
|
879
|
+
--sidebar-nav-icon-active-foreground,
|
|
880
|
+
var(--sidebar-nav-icon-foreground, currentColor)
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/* Disabled rows (`aria-disabled="true"`, set by SidebarItem for item.disabled). Defaults resolve
|
|
885
|
+
* to the RESTING row/icon colour, so a disabled row reads as inert in every state; a service dims
|
|
886
|
+
* it further with the two disabled knobs. */
|
|
887
|
+
.sb-nav-item[aria-disabled="true"] {
|
|
888
|
+
color: var(
|
|
889
|
+
--sidebar-nav-item-disabled-foreground,
|
|
890
|
+
var(--sidebar-nav-item-foreground, hsl(var(--muted-foreground)))
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.sb-nav-item[aria-disabled="true"] .sb-icon {
|
|
895
|
+
color: var(
|
|
896
|
+
--sidebar-nav-icon-disabled-foreground,
|
|
897
|
+
var(--sidebar-nav-icon-foreground, currentColor)
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
|
|
501
901
|
/* Collapsed-rail flyout — PORTALED (Radix Popover) so it escapes the sidebar's overflow and is
|
|
502
902
|
* never clipped: names a leaf item (tooltip) or reveals a group's submenu on hover/focus. */
|
|
503
903
|
.sb-flyout-pop {
|
|
@@ -645,12 +1045,40 @@
|
|
|
645
1045
|
}
|
|
646
1046
|
|
|
647
1047
|
/* Topbar — a pure slot bar. start (inline-start) · center (grows, centered) · end (inline-end).
|
|
648
|
-
* The library owns ONLY this positioning; every control inside is the consumer's to compose.
|
|
1048
|
+
* The library owns ONLY this positioning; every control inside is the consumer's to compose.
|
|
1049
|
+
*
|
|
1050
|
+
* SHRINK CONTRACT (gh#226) — a hosted console packs an intrinsically wide brand/tenant string
|
|
1051
|
+
* into `start` and a fixed-width search trigger into `center`; at a compact desktop width
|
|
1052
|
+
* (1024px minus a 16rem sidebar) that content used to push `end` (locale picker, user menu) past
|
|
1053
|
+
* the bar and out of the viewport, and leak a horizontal document scroll. The contract is:
|
|
1054
|
+
* root — never wider than its AppShell grid/flex allocation (`max-width:100%` +
|
|
1055
|
+
* `min-width:0`, so it shrinks whether the parent is a grid track or a flex line);
|
|
1056
|
+
* start — shrinks first, its content clipped INSIDE the slot (never spills over center/end);
|
|
1057
|
+
* center — `flex-basis:0`, so it yields all of its box before `start` gives up a pixel;
|
|
1058
|
+
* end — `flex:0 0 auto`, so it keeps its natural width and stays anchored inline-end.
|
|
1059
|
+
* Slots clip with `clip`, NOT `hidden`: a `hidden` box is still a scroll container, so focusing a
|
|
1060
|
+
* clipped control would scroll the slot and shove its leading content out of view. The clip
|
|
1061
|
+
* margin keeps the focus ring of an edge control paintable (WCAG 2.4.11 / 2.4.13).
|
|
1062
|
+
*
|
|
1063
|
+
* BOX KNOBS (rule #45) — --topbar-height / --topbar-inset / --topbar-gap. Their defaults are the
|
|
1064
|
+
* QUIET ones (`auto` / `0` / the previous 8px), i.e. byte-identical rendering to before they
|
|
1065
|
+
* existed: inside AppShell the `.app-topbar` grid row still owns the height and inset. A service
|
|
1066
|
+
* that mounts <Topbar> DIRECTLY on a page (no AppShell) now sizes it from the theme —
|
|
1067
|
+
* `--topbar-height: 3.5rem; --topbar-inset: var(--space-4)` — instead of an app-local class.
|
|
1068
|
+
* `--topbar-gap` re-rhythms the whole bar at once: it is both the gap BETWEEN the three clusters
|
|
1069
|
+
* and the gap INSIDE each of them, so a denser bar stays internally consistent.
|
|
1070
|
+
* The shrink contract above is unaffected — none of these touch flex/overflow. */
|
|
649
1071
|
.ui-topbar {
|
|
650
1072
|
display: flex;
|
|
651
|
-
|
|
1073
|
+
height: var(--topbar-height);
|
|
1074
|
+
width: auto;
|
|
1075
|
+
max-width: 100%;
|
|
1076
|
+
min-width: 0;
|
|
1077
|
+
flex: 1 1 0%;
|
|
652
1078
|
align-items: center;
|
|
653
|
-
gap: var(--
|
|
1079
|
+
gap: var(--topbar-gap);
|
|
1080
|
+
padding-inline: var(--topbar-inset);
|
|
1081
|
+
overflow: hidden;
|
|
654
1082
|
}
|
|
655
1083
|
.ui-topbar-start,
|
|
656
1084
|
.ui-topbar-center,
|
|
@@ -658,13 +1086,20 @@
|
|
|
658
1086
|
display: flex;
|
|
659
1087
|
min-width: 0;
|
|
660
1088
|
align-items: center;
|
|
661
|
-
gap: var(--
|
|
1089
|
+
gap: var(--topbar-gap);
|
|
1090
|
+
overflow: clip;
|
|
1091
|
+
overflow-clip-margin: var(--focus-ring-width);
|
|
1092
|
+
}
|
|
1093
|
+
.ui-topbar-start {
|
|
1094
|
+
flex: 0 1 auto;
|
|
662
1095
|
}
|
|
663
1096
|
.ui-topbar-center {
|
|
664
|
-
flex: 1 1
|
|
1097
|
+
flex: 1 1 0%;
|
|
665
1098
|
justify-content: center;
|
|
666
1099
|
}
|
|
667
1100
|
.ui-topbar-end {
|
|
1101
|
+
max-width: 100%;
|
|
1102
|
+
flex: 0 0 auto;
|
|
668
1103
|
margin-inline-start: auto;
|
|
669
1104
|
}
|
|
670
1105
|
|
|
@@ -737,7 +1172,7 @@
|
|
|
737
1172
|
|
|
738
1173
|
.tb-search {
|
|
739
1174
|
display: flex;
|
|
740
|
-
width: min(
|
|
1175
|
+
width: min(var(--topbar-search-max-width), 40vw);
|
|
741
1176
|
height: var(--control-height-sm);
|
|
742
1177
|
align-items: center;
|
|
743
1178
|
gap: var(--space-2);
|
|
@@ -812,27 +1247,18 @@
|
|
|
812
1247
|
background: hsl(var(--attention));
|
|
813
1248
|
}
|
|
814
1249
|
|
|
1250
|
+
/* TOPBAR CHIP/SEARCH DENSITY ONLY — this is NOT a second shell breakpoint. The `.app-root`
|
|
1251
|
+
* restructure that used to live here (a 768px duplicate of the 900px rule that also deleted the
|
|
1252
|
+
* footer row and re-declared the grid rows with a 3rem literal) is gone; see the note on the one
|
|
1253
|
+
* `@media (width <= 56.25rem)` block above. What remains is purely the optional `.tb-*` console
|
|
1254
|
+
* chrome collapsing to icon-only on a phone, which is independent of where the shell switches to
|
|
1255
|
+
* its drawer. */
|
|
815
1256
|
@media (max-width: 768px) {
|
|
816
|
-
.app-root,
|
|
817
|
-
.app-root[data-collapsed="true"] {
|
|
818
|
-
grid-template-areas:
|
|
819
|
-
"topbar"
|
|
820
|
-
"main";
|
|
821
|
-
grid-template-columns: minmax(0, 1fr);
|
|
822
|
-
grid-template-rows: 3rem minmax(0, 1fr);
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
.app-sidebar,
|
|
826
|
-
.app-footer,
|
|
827
1257
|
.tb-chip-sep,
|
|
828
1258
|
.tb-search .kbd {
|
|
829
1259
|
display: none;
|
|
830
1260
|
}
|
|
831
1261
|
|
|
832
|
-
.app-topbar {
|
|
833
|
-
padding-inline: var(--space-3);
|
|
834
|
-
}
|
|
835
|
-
|
|
836
1262
|
.tb-search {
|
|
837
1263
|
width: auto;
|
|
838
1264
|
min-width: var(--control-height);
|
|
@@ -843,3 +1269,20 @@
|
|
|
843
1269
|
}
|
|
844
1270
|
}
|
|
845
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
/*
|
|
1274
|
+
* REDUCED MOTION for the AppShell mobile drawer (WCAG 2.3.3 / 2.2.2). The drawer is a Sheet, so it
|
|
1275
|
+
* animates via Tailwind `data-[state]:animate-in|animate-out` + `slide-in-from-*` utilities.
|
|
1276
|
+
* DELIBERATELY UNLAYERED: Tailwind v4 emits those into `@layer utilities`, which beats any rule in
|
|
1277
|
+
* `@layer components` regardless of specificity — this gate was previously written inside the
|
|
1278
|
+
* components layer above and could never win. Same reasoning as the overlay gate in
|
|
1279
|
+
* dialog-layout.css (which also covers this drawer via [data-slot="sheet-*"]); kept here as well so
|
|
1280
|
+
* a consumer importing only `styles/shell-layout` still gets it.
|
|
1281
|
+
*/
|
|
1282
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1283
|
+
.app-mobile-nav-overlay,
|
|
1284
|
+
.app-mobile-nav-drawer {
|
|
1285
|
+
animation: none;
|
|
1286
|
+
transition: none;
|
|
1287
|
+
}
|
|
1288
|
+
}
|