@sentropic/design-system-svelte 0.34.20 → 0.34.21

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.
@@ -0,0 +1,660 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from "svelte";
3
+
4
+ /** Un lien de navigation principal du chrome. */
5
+ export interface AppChromeNavItem {
6
+ label: string;
7
+ href: string;
8
+ /** Marqué actif (souligné, aria-current=page). */
9
+ active?: boolean;
10
+ }
11
+
12
+ /** Une option du sélecteur de thème. */
13
+ export interface AppChromeThemeOption {
14
+ id: string;
15
+ label: string;
16
+ }
17
+
18
+ export type AppChromeColorMode = "light" | "dark" | "auto";
19
+ export type AppChromeLocale = "fr" | "en";
20
+
21
+ export interface AppChromeProps {
22
+ // ── Marque ──────────────────────────────────────────────────────────────
23
+ /** Nom de marque (défaut « Sentropic »). */
24
+ brandName?: string;
25
+ /** Sous-titre produit sous le nom (ex. « Design System », « dataviz »). */
26
+ productName?: string;
27
+ /** Source du logo carré (ex. `/SENT-logo-squared.svg`). */
28
+ logoSrc?: string;
29
+ /** Texte alternatif du logo (décoratif par défaut). */
30
+ logoAlt?: string;
31
+ /** Cible du lien de marque. Défaut `/`. */
32
+ brandHref?: string;
33
+ /** aria-label du lien de marque (sinon dérivé de brandName + productName). */
34
+ brandLabel?: string;
35
+
36
+ // ── Navigation ──────────────────────────────────────────────────────────
37
+ /** Liens de nav principaux (pills soulignées + état actif). */
38
+ nav?: AppChromeNavItem[];
39
+ /** aria-label de la nav principale. */
40
+ navLabel?: string;
41
+
42
+ // ── Contrôle thème (contrôlé) ─────────────────────────────────────────────
43
+ /** Options de thème. Vide => le sélecteur est masqué. */
44
+ themes?: AppChromeThemeOption[];
45
+ /** Id du thème actif. */
46
+ theme?: string;
47
+ /** Callback de changement de thème. */
48
+ onThemeChange?: (id: string) => void;
49
+ /** aria-label du sélecteur de thème. */
50
+ themeLabel?: string;
51
+
52
+ // ── Contrôle mode couleur (contrôlé) ───────────────────────────────────────
53
+ /** Mode couleur actif. Undefined => le toggle est masqué. */
54
+ colorMode?: AppChromeColorMode;
55
+ /** Callback de changement (cycle light -> dark -> auto). */
56
+ onColorModeChange?: (mode: AppChromeColorMode) => void;
57
+ /** Libellés accessibles des 3 modes (light/dark/auto). */
58
+ colorModeLabels?: { light: string; dark: string; auto: string };
59
+
60
+ // ── Contrôle langue (contrôlé) ─────────────────────────────────────────────
61
+ /** Langue active. Undefined => le sélecteur est masqué. */
62
+ locale?: AppChromeLocale;
63
+ /** Callback de changement de langue. */
64
+ onLocaleChange?: (locale: AppChromeLocale) => void;
65
+ /** aria-label du sélecteur de langue. */
66
+ localeLabel?: string;
67
+
68
+ // ── Lien GitHub ────────────────────────────────────────────────────────────
69
+ /** URL du dépôt. Undefined => le lien est masqué. */
70
+ githubHref?: string;
71
+ /** aria-label du lien GitHub. */
72
+ githubLabel?: string;
73
+
74
+ // ── Identité ───────────────────────────────────────────────────────────────
75
+ /** Zone identité à droite (IdentityMenu, bouton connexion, …). */
76
+ identity?: Snippet;
77
+
78
+ // ── Mobile ─────────────────────────────────────────────────────────────────
79
+ /** État ouvert du tiroir mobile (contrôlé). */
80
+ mobileMenuOpen?: boolean;
81
+ /** Callback de bascule du tiroir mobile. */
82
+ onMobileMenuToggle?: () => void;
83
+ /** aria-label du bouton burger. */
84
+ menuLabel?: string;
85
+
86
+ class?: string;
87
+ }
88
+
89
+ let appChromeIdCounter = 0;
90
+ function nextAppChromeId(): number {
91
+ return ++appChromeIdCounter;
92
+ }
93
+ </script>
94
+
95
+ <script lang="ts">
96
+ import { untrack } from "svelte";
97
+ import {
98
+ Boxes,
99
+ ChevronDown,
100
+ Github,
101
+ Globe,
102
+ Moon,
103
+ Palette,
104
+ Sun,
105
+ } from "@lucide/svelte";
106
+ import AppHeader from "./AppHeader.svelte";
107
+
108
+ let {
109
+ brandName = "Sentropic",
110
+ productName,
111
+ logoSrc,
112
+ logoAlt = "",
113
+ brandHref = "/",
114
+ brandLabel,
115
+ nav = [],
116
+ navLabel = "Primary",
117
+ themes = [],
118
+ theme,
119
+ onThemeChange,
120
+ themeLabel = "Change theme",
121
+ colorMode,
122
+ onColorModeChange,
123
+ colorModeLabels = { light: "Light mode", dark: "Dark mode", auto: "Auto mode" },
124
+ locale,
125
+ onLocaleChange,
126
+ localeLabel = "Change language",
127
+ githubHref,
128
+ githubLabel = "GitHub",
129
+ identity,
130
+ mobileMenuOpen = false,
131
+ onMobileMenuToggle,
132
+ menuLabel = "Menu",
133
+ class: className,
134
+ }: AppChromeProps = $props();
135
+
136
+ let isThemeOpen = $state(false);
137
+ let isLocaleOpen = $state(false);
138
+
139
+ const drawerId = untrack(() => `st-appChrome-drawer-${nextAppChromeId()}`);
140
+
141
+ const activeTheme = $derived(themes.find((t) => t.id === theme) ?? themes[0]);
142
+ const showThemeSelector = $derived(themes.length > 0);
143
+ const showColorMode = $derived(colorMode !== undefined);
144
+ const showLocaleSelector = $derived(locale !== undefined);
145
+ const showGithub = $derived(Boolean(githubHref));
146
+
147
+ function pickTheme(id: string) {
148
+ onThemeChange?.(id);
149
+ isThemeOpen = false;
150
+ }
151
+
152
+ function pickLocale(value: AppChromeLocale) {
153
+ onLocaleChange?.(value);
154
+ isLocaleOpen = false;
155
+ }
156
+
157
+ function cycleColorMode() {
158
+ const next: AppChromeColorMode =
159
+ colorMode === "light" ? "dark" : colorMode === "dark" ? "auto" : "light";
160
+ onColorModeChange?.(next);
161
+ }
162
+
163
+ function colorModeAriaLabel(): string {
164
+ if (colorMode === "light") return colorModeLabels.dark;
165
+ if (colorMode === "dark") return colorModeLabels.auto;
166
+ return colorModeLabels.light;
167
+ }
168
+
169
+ const classes = () => ["st-appChrome", className].filter(Boolean).join(" ");
170
+
171
+ function closeMenus(target: EventTarget | null) {
172
+ const el = target as Element | null;
173
+ if (isThemeOpen && el && !el.closest(".st-appChrome__themeWrap")) isThemeOpen = false;
174
+ if (isLocaleOpen && el && !el.closest(".st-appChrome__localeWrap")) isLocaleOpen = false;
175
+ }
176
+ </script>
177
+
178
+ <svelte:window
179
+ onclick={(e) => closeMenus(e.target)}
180
+ onkeydown={(e) => {
181
+ if (e.key === "Escape") {
182
+ isThemeOpen = false;
183
+ isLocaleOpen = false;
184
+ }
185
+ }}
186
+ />
187
+
188
+ <!-- ── Marque ─────────────────────────────────────────────────────────────── -->
189
+ {#snippet brand()}
190
+ <a class="st-appChrome__brand" href={brandHref} aria-label={brandLabel ?? ([brandName, productName].filter(Boolean).join(" ") || undefined)}>
191
+ {#if logoSrc}
192
+ <img class="st-appChrome__brandMark" src={logoSrc} alt={logoAlt} aria-hidden={logoAlt ? undefined : "true"} />
193
+ {/if}
194
+ {#if brandName || productName}
195
+ <span class="st-appChrome__brandCopy">
196
+ {#if brandName}<span class="st-appChrome__brandName">{brandName}</span>{/if}
197
+ {#if productName}<span class="st-appChrome__brandProduct">{productName}</span>{/if}
198
+ </span>
199
+ {/if}
200
+ </a>
201
+ {/snippet}
202
+
203
+ <!-- ── Nav principale ─────────────────────────────────────────────────────── -->
204
+ {#snippet navContent()}
205
+ {#each nav as item (item.href)}
206
+ <a
207
+ class="st-appChrome__navLink st-appHeader__navLink"
208
+ href={item.href}
209
+ aria-current={item.active ? "page" : undefined}
210
+ >
211
+ {item.label}
212
+ </a>
213
+ {/each}
214
+ {/snippet}
215
+
216
+ <!-- ── Sélecteur de thème ─────────────────────────────────────────────────── -->
217
+ {#snippet themeSelector()}
218
+ <div class="st-appChrome__themeWrap st-appChrome__menuWrap">
219
+ <button
220
+ type="button"
221
+ class="st-appChrome__control st-appHeader__control"
222
+ onclick={() => (isThemeOpen = !isThemeOpen)}
223
+ aria-expanded={isThemeOpen}
224
+ aria-haspopup="true"
225
+ aria-label={themeLabel}
226
+ >
227
+ <Palette size={14} aria-hidden="true" />
228
+ <span>{activeTheme?.label}</span>
229
+ <ChevronDown size={12} class="st-appChrome__chevron {isThemeOpen ? 'is-rotated' : ''}" aria-hidden="true" />
230
+ </button>
231
+ {#if isThemeOpen}
232
+ <div class="st-appChrome__menu" role="menu">
233
+ {#each themes as option (option.id)}
234
+ <button
235
+ type="button"
236
+ class="st-appChrome__menuItem"
237
+ class:is-active={theme === option.id}
238
+ role="menuitem"
239
+ onclick={() => pickTheme(option.id)}
240
+ >
241
+ <span class="st-appChrome__check" aria-hidden="true">{#if theme === option.id}✓{/if}</span>
242
+ <span>{option.label}</span>
243
+ </button>
244
+ {/each}
245
+ </div>
246
+ {/if}
247
+ </div>
248
+ {/snippet}
249
+
250
+ <!-- ── Toggle mode couleur ────────────────────────────────────────────────── -->
251
+ {#snippet colorModeToggle()}
252
+ <button
253
+ type="button"
254
+ class="st-appChrome__control st-appChrome__iconControl st-appHeader__control"
255
+ onclick={cycleColorMode}
256
+ aria-label={colorModeAriaLabel()}
257
+ >
258
+ {#if colorMode === "dark"}
259
+ <Moon size={16} strokeWidth={2} aria-hidden="true" />
260
+ {:else if colorMode === "light"}
261
+ <Sun size={16} strokeWidth={2} aria-hidden="true" />
262
+ {:else}
263
+ <Sun size={16} strokeWidth={1.5} aria-hidden="true" style="opacity:0.65" />
264
+ {/if}
265
+ </button>
266
+ {/snippet}
267
+
268
+ <!-- ── Sélecteur de langue ────────────────────────────────────────────────── -->
269
+ {#snippet localeSelector()}
270
+ <div class="st-appChrome__localeWrap st-appChrome__menuWrap">
271
+ <button
272
+ type="button"
273
+ class="st-appChrome__control st-appHeader__control"
274
+ onclick={() => (isLocaleOpen = !isLocaleOpen)}
275
+ aria-expanded={isLocaleOpen}
276
+ aria-haspopup="true"
277
+ aria-label={localeLabel}
278
+ >
279
+ <Globe size={14} aria-hidden="true" />
280
+ <span>{locale?.toUpperCase()}</span>
281
+ <ChevronDown size={12} class="st-appChrome__chevron {isLocaleOpen ? 'is-rotated' : ''}" aria-hidden="true" />
282
+ </button>
283
+ {#if isLocaleOpen}
284
+ <div class="st-appChrome__menu" role="menu">
285
+ {#each (["fr", "en"] as AppChromeLocale[]) as value (value)}
286
+ <button
287
+ type="button"
288
+ class="st-appChrome__menuItem"
289
+ class:is-active={locale === value}
290
+ role="menuitem"
291
+ onclick={() => pickLocale(value)}
292
+ >
293
+ <span class="st-appChrome__check" aria-hidden="true">{#if locale === value}✓{/if}</span>
294
+ <span>{value === "fr" ? "Français" : "English"}</span>
295
+ </button>
296
+ {/each}
297
+ </div>
298
+ {/if}
299
+ </div>
300
+ {/snippet}
301
+
302
+ <!-- ── Lien GitHub ────────────────────────────────────────────────────────── -->
303
+ {#snippet githubLink()}
304
+ <a
305
+ class="st-appChrome__control st-appChrome__iconControl st-appHeader__control"
306
+ href={githubHref}
307
+ rel="noreferrer"
308
+ target="_blank"
309
+ aria-label={githubLabel}
310
+ >
311
+ <Github size={16} strokeWidth={2.1} aria-hidden="true" />
312
+ </a>
313
+ {/snippet}
314
+
315
+ <!-- ── Zone de contrôles utilitaires (droite) ─────────────────────────────── -->
316
+ {#snippet utilityNav()}
317
+ <div class="st-appChrome__utilityNav">
318
+ {#if showThemeSelector}{@render themeSelector()}{/if}
319
+ {#if showColorMode}{@render colorModeToggle()}{/if}
320
+ {#if showLocaleSelector}{@render localeSelector()}{/if}
321
+ {#if showGithub}{@render githubLink()}{/if}
322
+ {#if identity}<div class="st-appChrome__identity">{@render identity()}</div>{/if}
323
+ </div>
324
+ {/snippet}
325
+
326
+ <!-- ── Actions desktop (nav + contrôles dans une barre, burger mobile) ─────── -->
327
+ {#snippet actions()}
328
+ {@render utilityNav()}
329
+ <button
330
+ type="button"
331
+ class="st-appChrome__burgerTrigger"
332
+ onclick={onMobileMenuToggle}
333
+ aria-expanded={mobileMenuOpen}
334
+ aria-controls={drawerId}
335
+ aria-label={menuLabel}
336
+ >
337
+ <Boxes size={20} aria-hidden="true" />
338
+ </button>
339
+ {/snippet}
340
+
341
+ <div class={classes()}>
342
+ <AppHeader
343
+ class="st-appChrome__header"
344
+ brandHref={brandHref}
345
+ brandLabel={brandLabel}
346
+ logo={brand}
347
+ nav={navContent}
348
+ actions={actions}
349
+ />
350
+
351
+ {#if mobileMenuOpen}
352
+ <nav id={drawerId} class="st-appChrome__drawer" aria-label={navLabel}>
353
+ <div class="st-appChrome__drawerSection">
354
+ {#each nav as item (item.href)}
355
+ <a
356
+ class="st-appChrome__drawerLink"
357
+ href={item.href}
358
+ aria-current={item.active ? "page" : undefined}
359
+ onclick={() => onMobileMenuToggle?.()}
360
+ >
361
+ {item.label}
362
+ </a>
363
+ {/each}
364
+ </div>
365
+
366
+ {#if showThemeSelector}
367
+ <div class="st-appChrome__drawerSection">
368
+ <span class="st-appChrome__drawerLabel">{themeLabel}</span>
369
+ <div class="st-appChrome__drawerSwitcher">
370
+ {#each themes as option (option.id)}
371
+ <button
372
+ type="button"
373
+ class="st-appChrome__drawerBtn"
374
+ class:is-active={theme === option.id}
375
+ onclick={() => { onThemeChange?.(option.id); onMobileMenuToggle?.(); }}
376
+ >
377
+ {option.label}
378
+ </button>
379
+ {/each}
380
+ </div>
381
+ </div>
382
+ {/if}
383
+
384
+ {#if showColorMode}
385
+ <div class="st-appChrome__drawerSection">
386
+ <span class="st-appChrome__drawerLabel">{colorModeLabels.light} / {colorModeLabels.dark}</span>
387
+ <div class="st-appChrome__drawerSwitcher">
388
+ {#each (["light", "dark", "auto"] as AppChromeColorMode[]) as mode (mode)}
389
+ <button
390
+ type="button"
391
+ class="st-appChrome__drawerBtn"
392
+ class:is-active={colorMode === mode}
393
+ onclick={() => onColorModeChange?.(mode)}
394
+ >
395
+ {mode === "light" ? colorModeLabels.light : mode === "dark" ? colorModeLabels.dark : colorModeLabels.auto}
396
+ </button>
397
+ {/each}
398
+ </div>
399
+ </div>
400
+ {/if}
401
+
402
+ {#if showLocaleSelector}
403
+ <div class="st-appChrome__drawerSection">
404
+ <span class="st-appChrome__drawerLabel">{localeLabel}</span>
405
+ <div class="st-appChrome__drawerSwitcher">
406
+ {#each (["fr", "en"] as AppChromeLocale[]) as value (value)}
407
+ <button
408
+ type="button"
409
+ class="st-appChrome__drawerBtn"
410
+ class:is-active={locale === value}
411
+ onclick={() => { onLocaleChange?.(value); onMobileMenuToggle?.(); }}
412
+ >
413
+ {value === "fr" ? "Français" : "English"}
414
+ </button>
415
+ {/each}
416
+ </div>
417
+ </div>
418
+ {/if}
419
+
420
+ {#if showGithub || identity}
421
+ <div class="st-appChrome__drawerSection">
422
+ {#if showGithub}
423
+ <a class="st-appChrome__drawerLink" href={githubHref} rel="noreferrer" target="_blank">{githubLabel}</a>
424
+ {/if}
425
+ {#if identity}<div class="st-appChrome__identity">{@render identity()}</div>{/if}
426
+ </div>
427
+ {/if}
428
+ </nav>
429
+ {/if}
430
+ </div>
431
+
432
+ <style>
433
+ /* Le markup, les classes et les tokens sont byte-identiques entre svelte/
434
+ react/vue : la source de vérité du CSS est le bloc publié (styles.css).
435
+ Ce <style> scoped ne fait que rendre la démo Svelte autonome. */
436
+ .st-appChrome {
437
+ width: 100%;
438
+ }
439
+
440
+ :global(.st-appChrome__header .st-appHeader__bar) {
441
+ max-width: none;
442
+ }
443
+
444
+ .st-appChrome__brand {
445
+ align-items: center;
446
+ color: var(--st-semantic-text-primary);
447
+ display: inline-flex;
448
+ flex: 0 0 auto;
449
+ gap: var(--st-spacing-3, 0.75rem);
450
+ min-width: 0;
451
+ text-decoration: none;
452
+ }
453
+
454
+ .st-appChrome__brandMark {
455
+ aspect-ratio: 1;
456
+ display: inline-block;
457
+ flex: 0 0 auto;
458
+ height: 2rem;
459
+ object-fit: contain;
460
+ width: 2rem;
461
+ }
462
+
463
+ .st-appChrome__brandCopy {
464
+ display: grid;
465
+ gap: 0.08rem;
466
+ line-height: 1;
467
+ min-width: 0;
468
+ }
469
+
470
+ .st-appChrome__brandName {
471
+ color: var(--st-semantic-text-primary);
472
+ font-size: 1rem;
473
+ font-weight: 760;
474
+ }
475
+
476
+ .st-appChrome__brandProduct {
477
+ color: var(--st-semantic-text-secondary);
478
+ font-size: 0.75rem;
479
+ font-weight: 650;
480
+ }
481
+
482
+ .st-appChrome__utilityNav {
483
+ align-items: center;
484
+ display: flex;
485
+ gap: var(--st-spacing-2, 0.5rem);
486
+ }
487
+
488
+ .st-appChrome__menuWrap {
489
+ display: inline-block;
490
+ position: relative;
491
+ }
492
+
493
+ .st-appChrome__control {
494
+ font-size: 0.75rem;
495
+ }
496
+
497
+ .st-appChrome__iconControl {
498
+ justify-content: center;
499
+ padding: 0;
500
+ width: 2.25rem;
501
+ }
502
+
503
+ .st-appChrome__chevron {
504
+ transition: transform var(--st-motion-fast, 120ms) ease;
505
+ }
506
+
507
+ :global(.st-appChrome__chevron.is-rotated) {
508
+ transform: rotate(180deg);
509
+ }
510
+
511
+ .st-appChrome__menu {
512
+ background: var(--st-semantic-surface-raised, var(--st-semantic-surface-default));
513
+ border: 1px solid var(--st-semantic-border-subtle);
514
+ border-radius: var(--st-radius-sm, 0.375rem);
515
+ box-shadow: var(--st-shadow-medium, 0 8px 24px rgb(15 23 42 / 0.08));
516
+ display: flex;
517
+ flex-direction: column;
518
+ gap: 0.1rem;
519
+ min-width: 8.5rem;
520
+ padding: 0.25rem;
521
+ position: absolute;
522
+ right: 0;
523
+ top: calc(100% + 4px);
524
+ z-index: var(--st-zindex-overlay, 80);
525
+ }
526
+
527
+ .st-appChrome__menuItem {
528
+ align-items: center;
529
+ background: transparent;
530
+ border: 0;
531
+ border-radius: var(--st-radius-xs, 0.25rem);
532
+ color: var(--st-semantic-text-secondary);
533
+ cursor: pointer;
534
+ display: flex;
535
+ font: inherit;
536
+ font-size: 0.82rem;
537
+ font-weight: 550;
538
+ gap: 0.45rem;
539
+ padding: 0.35rem 0.65rem;
540
+ text-align: left;
541
+ width: 100%;
542
+ transition: background-color var(--st-motion-fast, 120ms) ease,
543
+ color var(--st-motion-fast, 120ms) ease;
544
+ }
545
+
546
+ .st-appChrome__menuItem:hover {
547
+ background: var(--st-semantic-surface-subtle);
548
+ color: var(--st-semantic-text-primary);
549
+ }
550
+
551
+ .st-appChrome__menuItem.is-active {
552
+ color: var(--st-semantic-text-link);
553
+ font-weight: 650;
554
+ }
555
+
556
+ .st-appChrome__check {
557
+ align-items: center;
558
+ display: inline-flex;
559
+ font-size: 0.75rem;
560
+ justify-content: center;
561
+ width: 0.75rem;
562
+ }
563
+
564
+ .st-appChrome__burgerTrigger {
565
+ align-items: center;
566
+ background: transparent;
567
+ border: 0;
568
+ border-radius: var(--st-radius-xs, 0.25rem);
569
+ color: var(--st-semantic-text-secondary);
570
+ cursor: pointer;
571
+ display: none;
572
+ height: 2.25rem;
573
+ justify-content: center;
574
+ width: 2.25rem;
575
+ }
576
+
577
+ .st-appChrome__burgerTrigger:hover {
578
+ background: var(--st-semantic-surface-subtle);
579
+ color: var(--st-semantic-text-primary);
580
+ }
581
+
582
+ .st-appChrome__drawer {
583
+ background: var(--st-semantic-surface-default);
584
+ border-bottom: 1px solid var(--st-semantic-border-subtle);
585
+ box-shadow: var(--st-shadow-medium, 0 10px 20px rgb(15 23 42 / 0.05));
586
+ display: none;
587
+ flex-direction: column;
588
+ gap: var(--st-spacing-5, 1.25rem);
589
+ padding: var(--st-spacing-5, 1.25rem);
590
+ }
591
+
592
+ .st-appChrome__drawerSection {
593
+ display: flex;
594
+ flex-direction: column;
595
+ gap: var(--st-spacing-2, 0.5rem);
596
+ }
597
+
598
+ .st-appChrome__drawerLabel {
599
+ color: var(--st-semantic-text-secondary);
600
+ font-size: 0.75rem;
601
+ font-weight: 700;
602
+ letter-spacing: 0.05em;
603
+ text-transform: uppercase;
604
+ }
605
+
606
+ .st-appChrome__drawerLink {
607
+ align-items: center;
608
+ border-bottom: 1px solid var(--st-semantic-border-subtle);
609
+ color: var(--st-semantic-text-primary);
610
+ display: inline-flex;
611
+ font-size: 1rem;
612
+ font-weight: 650;
613
+ gap: 0.45rem;
614
+ padding: 0.45rem 0;
615
+ text-decoration: none;
616
+ }
617
+
618
+ .st-appChrome__drawerLink[aria-current="page"],
619
+ .st-appChrome__drawerLink:hover {
620
+ color: var(--st-semantic-text-link);
621
+ }
622
+
623
+ .st-appChrome__drawerSwitcher {
624
+ display: flex;
625
+ gap: var(--st-spacing-2, 0.5rem);
626
+ }
627
+
628
+ .st-appChrome__drawerBtn {
629
+ background: var(--st-semantic-surface-subtle);
630
+ border: 1px solid var(--st-semantic-border-subtle);
631
+ border-radius: var(--st-radius-xs, 0.25rem);
632
+ color: var(--st-semantic-text-secondary);
633
+ cursor: pointer;
634
+ flex: 1;
635
+ font: inherit;
636
+ font-size: 0.75rem;
637
+ font-weight: 650;
638
+ padding: 0.45rem;
639
+ }
640
+
641
+ .st-appChrome__drawerBtn.is-active {
642
+ background: var(--st-semantic-border-interactive);
643
+ border-color: var(--st-semantic-border-interactive);
644
+ color: var(--st-semantic-text-on-emphasis, var(--st-semantic-surface-default));
645
+ }
646
+
647
+ @media (max-width: 768px) {
648
+ .st-appChrome__utilityNav {
649
+ display: none;
650
+ }
651
+
652
+ .st-appChrome__burgerTrigger {
653
+ display: inline-flex;
654
+ }
655
+
656
+ .st-appChrome__drawer {
657
+ display: flex;
658
+ }
659
+ }
660
+ </style>