chati-dev 4.3.0 → 4.4.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 -13
- package/bin/chati.js +32 -4
- package/framework/agents/build/dev.md +9 -5
- package/framework/agents/discover/brief.md +2 -0
- package/framework/agents/discover/brownfield-wu.md +2 -0
- package/framework/agents/discover/greenfield-wu.md +18 -1
- package/framework/agents/plan/detail.md +2 -0
- package/framework/agents/plan/tasks.md +31 -0
- package/framework/agents/plan/ux-brand-architect.md +21 -2
- package/framework/agents/plan/ux-component-engineer.md +10 -0
- package/framework/agents/quality/qa-implementation.md +1 -1
- package/framework/agents/quality/qa-planning.md +1 -1
- package/framework/agents/quality/qa-visual.md +33 -21
- package/framework/config.yaml +5 -4
- package/framework/constitution.md +58 -11
- package/framework/context/governance.md +12 -10
- package/framework/context/root.md +2 -2
- package/framework/data/entity-registry.yaml +12 -4
- package/framework/data/qa-rubrics.yaml +335 -0
- package/framework/domains/constitution.yaml +3 -3
- package/framework/executors/json-validate.js +80 -0
- package/framework/executors/npm-script.js +72 -0
- package/framework/executors/path-check.js +67 -0
- package/framework/executors/registry.yaml +36 -0
- package/framework/hooks/advance-trigger.js +47 -3
- package/framework/hooks/constitution-guard.js +9 -4
- package/framework/hooks/git-push-authority.js +113 -0
- package/framework/hooks/license-guard.js +59 -9
- package/framework/hooks/model-governance.js +40 -17
- package/framework/hooks/prism-engine.js +78 -11
- package/framework/hooks/session-digest.js +12 -3
- package/framework/hooks/settings.json +7 -3
- package/framework/hooks/style-guard.js +52 -3
- package/framework/hooks/team-quality-gate.js +43 -5
- package/framework/i18n/en.yaml +3 -3
- package/framework/i18n/es.yaml +3 -3
- package/framework/i18n/fr.yaml +3 -3
- package/framework/i18n/pt.yaml +3 -3
- package/framework/intelligence/confidence.yaml +85 -6
- package/framework/intelligence/context-engine.md +9 -5
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/orchestrator/chati-router.js +59 -5
- package/framework/orchestrator/chati-update.md +19 -3
- package/framework/orchestrator/chati.md +20 -1
- package/framework/quality-gates/planning-gate.md +2 -0
- package/framework/rules/human-writing-style.md +47 -0
- package/framework/scaffold/motion-premium/README.md +12 -2
- package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +1 -1
- package/framework/scaffold/motion-premium/scaffold.yaml +6 -1
- package/framework/scaffold/motion-premium-3d/README.md +10 -0
- package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
- package/framework/scaffold/motion-premium-3d/scaffold.yaml +3 -0
- package/framework/scaffold/saas-dashboard/README.md +58 -0
- package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
- package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
- package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
- package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
- package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
- package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
- package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
- package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
- package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
- package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
- package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
- package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
- package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
- package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
- package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
- package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
- package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
- package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
- package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
- package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
- package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
- package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
- package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
- package/framework/schemas/session.schema.json +5 -0
- package/framework/schemas/task.schema.json +9 -0
- package/framework/scripts/visual-qa.js +101 -3
- package/framework/tasks/orchestrator-health.md +4 -4
- package/framework/tasks/qa-impl-verdict.md +11 -5
- package/framework/templates/brandbook-html-tmpl.md +1 -1
- package/framework/templates/qa-gate-tmpl.yaml +24 -11
- package/package.json +4 -3
- package/src/config/context-file-generator.js +0 -6
- package/src/dashboard/renderer.js +0 -36
- package/src/executors/runner.js +204 -0
- package/src/installer/core.js +13 -3
- package/src/installer/templates.js +5 -6
- package/src/intelligence/registry-manager.js +1 -1
- package/src/license/client.js +9 -3
- package/src/license/commands.js +12 -2
- package/src/license/machine-id.js +42 -1
- package/src/memory/gotchas.js +58 -40
- package/src/memory/magic-docs.js +1 -1
- package/src/memory/session-digest.js +9 -4
- package/src/orchestrator/cli.js +186 -15
- package/src/orchestrator/doctor.js +98 -16
- package/src/orchestrator/pipeline-manager.js +44 -22
- package/src/orchestrator/session-manager.js +64 -8
- package/src/telemetry/sender.js +7 -19
- package/src/terminal/run-team.js +3 -3
- package/src/upgrade/tracked-files-detector.js +34 -16
- package/src/utils/feature-flags.js +1 -1
- package/src/utils/flatten-entities.js +4 -40
- package/src/utils/schema-validator.js +0 -14
- package/src/wizard/i18n.js +3 -3
- package/src/api/index.js +0 -120
- package/src/autonomy/autonomous-gate.js +0 -294
- package/src/autonomy/build-loop.js +0 -281
- package/src/autonomy/build-state.js +0 -286
- package/src/autonomy/cause-analyzer.js +0 -177
- package/src/autonomy/escalation.js +0 -214
- package/src/autonomy/index.js +0 -51
- package/src/autonomy/mode-manager.js +0 -225
- package/src/autonomy/mode-suggester.js +0 -283
- package/src/autonomy/progress-reporter.js +0 -275
- package/src/autonomy/safety-net.js +0 -370
- package/src/config/agent-customizer.js +0 -231
- package/src/decision/analyzer.js +0 -291
- package/src/decision/engine.js +0 -250
- package/src/decision/index.js +0 -38
- package/src/decision/registry-healer.js +0 -468
- package/src/decision/registry-updater.js +0 -339
- package/src/extensions/loader.js +0 -145
- package/src/extensions/registry.js +0 -134
- package/src/gates/circuit-breaker.js +0 -151
- package/src/gates/g1-planning-complete.js +0 -154
- package/src/gates/g2-qa-planning.js +0 -156
- package/src/gates/g3-implementation.js +0 -215
- package/src/gates/g4-qa-implementation.js +0 -240
- package/src/gates/g5-deploy-ready.js +0 -181
- package/src/gates/gate-base.js +0 -185
- package/src/gates/index.js +0 -46
- package/src/health/auto-fix.js +0 -216
- package/src/health/engine.js +0 -246
- package/src/merger/semantic-merger.js +0 -292
- package/src/preview/detector.js +0 -238
- package/src/preview/index.js +0 -20
- package/src/preview/launcher.js +0 -235
- package/src/preview/log-buffer.js +0 -103
- package/src/quality/metrics-collector.js +0 -281
- package/src/quality/test-runner.js +0 -366
- package/src/tasks/executor.js +0 -195
- package/src/tasks/index.js +0 -4
- package/src/tasks/loader.js +0 -210
- package/src/tasks/router.js +0 -182
- package/src/utils/event-bus.js +0 -126
|
@@ -0,0 +1,1070 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* shell.css -- App Shell BEM Component Styles
|
|
3
|
+
* saas-dashboard preset v1.0.0
|
|
4
|
+
*
|
|
5
|
+
* WHAT THIS FILE COVERS
|
|
6
|
+
* ---------------------
|
|
7
|
+
* All CSS rules for the five shell components rendered by AppShell:
|
|
8
|
+
* AppShell (shell-root, shell-backdrop, shell-main, shell-content)
|
|
9
|
+
* Sidebar (sidebar, all sub-elements, collapsed and mobile modifiers)
|
|
10
|
+
* Topbar (topbar, topbar-inner, left/right slots, search, notifications,
|
|
11
|
+
* user menu, dropdown)
|
|
12
|
+
* Breadcrumb (breadcrumb, breadcrumb-list, breadcrumb-item variants)
|
|
13
|
+
* ThemeToggle (theme-toggle, theme-toggle-icon, overlay variant)
|
|
14
|
+
*
|
|
15
|
+
* DESIGN CONTRACT
|
|
16
|
+
* ---------------
|
|
17
|
+
* Every value in this file is expressed as a CSS custom property that
|
|
18
|
+
* was declared in globals.css. The only exceptions are:
|
|
19
|
+
* - border widths and outline offsets: 1px and 2px (no token exists,
|
|
20
|
+
* and --space-px resolves to 1px, used where appropriate).
|
|
21
|
+
* - Structural sidebar widths: consumed via --shell-sidebar-w, which
|
|
22
|
+
* itself references --spacing-sidebar-w or --spacing-sidebar-w-col.
|
|
23
|
+
* - The backdrop z-index offset (z-index calc) uses the --z-sidebar token.
|
|
24
|
+
*
|
|
25
|
+
* MOTION RULES
|
|
26
|
+
* ------------
|
|
27
|
+
* Transitions name exactly the property being animated. Easing tokens
|
|
28
|
+
* are drawn from globals.css:
|
|
29
|
+
* --ease-out entering elements
|
|
30
|
+
* --ease-in leaving elements
|
|
31
|
+
* --ease-in-out symmetric toggles (sidebar collapse, chevron rotation)
|
|
32
|
+
* The @media (prefers-reduced-motion: reduce) block at the bottom of
|
|
33
|
+
* globals.css collapses all durations, so no per-component reduced-motion
|
|
34
|
+
* block is required here.
|
|
35
|
+
*
|
|
36
|
+
* LAYER
|
|
37
|
+
* -----
|
|
38
|
+
* All rules live inside @layer shell so Tailwind utilities applied
|
|
39
|
+
* directly on elements (if any) naturally win over these structural
|
|
40
|
+
* styles without !important escalation.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
@layer shell {
|
|
44
|
+
|
|
45
|
+
/* ==========================================================================
|
|
46
|
+
1. APP SHELL ROOT GRID
|
|
47
|
+
==========================================================================
|
|
48
|
+
The outer grid places the sidebar column and the main column side by side.
|
|
49
|
+
--shell-sidebar-w is set as an inline style by AppShell.tsx and transitions
|
|
50
|
+
via the grid-template-columns transition declared here.
|
|
51
|
+
On mobile (< 768px) the sidebar leaves the grid entirely (0px column).
|
|
52
|
+
========================================================================== */
|
|
53
|
+
|
|
54
|
+
.shell-root {
|
|
55
|
+
display: grid;
|
|
56
|
+
grid-template-columns: var(--shell-sidebar-w, var(--spacing-sidebar-w)) 1fr;
|
|
57
|
+
grid-template-rows: 1fr;
|
|
58
|
+
min-height: 100dvh;
|
|
59
|
+
background-color: var(--color-bg-base);
|
|
60
|
+
transition:
|
|
61
|
+
grid-template-columns var(--duration-slow) var(--ease-in-out);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* On mobile the sidebar floats as a fixed overlay: collapse its grid lane. */
|
|
65
|
+
@media (max-width: 767px) {
|
|
66
|
+
.shell-root {
|
|
67
|
+
grid-template-columns: 0 1fr;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* --------------------------------------------------------------------------
|
|
72
|
+
1a. Mobile backdrop scrim
|
|
73
|
+
-------------------------------------------------------------------------- */
|
|
74
|
+
|
|
75
|
+
.shell-backdrop {
|
|
76
|
+
position: fixed;
|
|
77
|
+
inset: 0;
|
|
78
|
+
background-color: var(--color-overlay-scrim);
|
|
79
|
+
/* Sit just below the sidebar so it does not intercept sidebar clicks. */
|
|
80
|
+
z-index: calc(var(--z-sidebar) - 1);
|
|
81
|
+
/* Opacity transition is preserved under prefers-reduced-motion per
|
|
82
|
+
globals.css rules (opacity-only fades are kept at 80ms). */
|
|
83
|
+
opacity: 1;
|
|
84
|
+
transition:
|
|
85
|
+
opacity var(--duration-normal) var(--ease-out);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* --------------------------------------------------------------------------
|
|
89
|
+
1b. Main column: stacks topbar above scrollable content
|
|
90
|
+
-------------------------------------------------------------------------- */
|
|
91
|
+
|
|
92
|
+
.shell-main {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
min-height: 100dvh;
|
|
96
|
+
/* Clip overflowing page content: only shell-content scrolls. */
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
background-color: var(--color-bg-base);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* --------------------------------------------------------------------------
|
|
102
|
+
1c. Content area: the scrollable page canvas
|
|
103
|
+
-------------------------------------------------------------------------- */
|
|
104
|
+
|
|
105
|
+
.shell-content {
|
|
106
|
+
flex: 1 1 auto;
|
|
107
|
+
overflow-y: auto;
|
|
108
|
+
/* Padding gives page components breathing room without each page
|
|
109
|
+
having to declare its own edge spacing. */
|
|
110
|
+
padding: var(--spacing-page-edge);
|
|
111
|
+
/* Max width prevents very long lines on ultra-wide viewports. */
|
|
112
|
+
max-width: 1440px;
|
|
113
|
+
width: 100%;
|
|
114
|
+
/* Remove default outline: focus is managed programmatically via
|
|
115
|
+
AppShell route-change effect; the element receives tabIndex=-1. */
|
|
116
|
+
outline: none;
|
|
117
|
+
scroll-behavior: auto;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ==========================================================================
|
|
121
|
+
2. SIDEBAR
|
|
122
|
+
==========================================================================
|
|
123
|
+
The sidebar is a flex column occupying the left grid lane on desktop.
|
|
124
|
+
On mobile it is a fixed overlay drawer that slides in from the left.
|
|
125
|
+
Width transitions are handled by the shell-root grid column, NOT by the
|
|
126
|
+
sidebar element itself. The sidebar only transitions label opacity and
|
|
127
|
+
max-width (see comment in Sidebar.tsx for the max-width exception rationale).
|
|
128
|
+
========================================================================== */
|
|
129
|
+
|
|
130
|
+
.sidebar {
|
|
131
|
+
/* Desktop: fixed height, flex column, fills the grid lane vertically. */
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
height: 100dvh;
|
|
135
|
+
position: sticky;
|
|
136
|
+
top: 0;
|
|
137
|
+
/* Overflow hidden prevents label text from peeking out during collapse. */
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
background-color: var(--color-bg-overlay);
|
|
140
|
+
border-right: 1px solid var(--color-border-default);
|
|
141
|
+
z-index: var(--z-sidebar);
|
|
142
|
+
/* Width is driven by the shell-root grid column, no explicit width here.
|
|
143
|
+
We do set a min-width so the icon column never shrinks below collapsed size. */
|
|
144
|
+
min-width: var(--spacing-sidebar-w-col);
|
|
145
|
+
box-shadow: var(--shadow-1);
|
|
146
|
+
transition:
|
|
147
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
148
|
+
border-color var(--duration-normal) var(--ease-in-out);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* --------------------------------------------------------------------------
|
|
152
|
+
Mobile: position:fixed off-screen by default; slide in when open.
|
|
153
|
+
-------------------------------------------------------------------------- */
|
|
154
|
+
|
|
155
|
+
@media (max-width: 767px) {
|
|
156
|
+
.sidebar {
|
|
157
|
+
position: fixed;
|
|
158
|
+
top: 0;
|
|
159
|
+
left: 0;
|
|
160
|
+
height: 100dvh;
|
|
161
|
+
width: var(--spacing-sidebar-w);
|
|
162
|
+
transform: translateX(-100%);
|
|
163
|
+
transition:
|
|
164
|
+
transform var(--duration-slow) var(--ease-in-out),
|
|
165
|
+
background-color var(--duration-normal) var(--ease-in-out);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.sidebar--mobile-open {
|
|
169
|
+
transform: translateX(0);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* ==========================================================================
|
|
174
|
+
2a. Sidebar header (logo + wordmark + collapse button)
|
|
175
|
+
========================================================================== */
|
|
176
|
+
|
|
177
|
+
.sidebar-header {
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
gap: var(--space-3);
|
|
181
|
+
padding: var(--space-4) var(--space-4);
|
|
182
|
+
height: var(--spacing-topbar-h);
|
|
183
|
+
border-bottom: 1px solid var(--color-border-default);
|
|
184
|
+
flex-shrink: 0;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Logo mark: the square brand icon always visible. */
|
|
189
|
+
.sidebar-logo {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
flex-shrink: 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.sidebar-logo-mark {
|
|
197
|
+
display: block;
|
|
198
|
+
width: var(--space-8);
|
|
199
|
+
height: var(--space-8);
|
|
200
|
+
border-radius: var(--radius-sm);
|
|
201
|
+
background-color: var(--color-accent);
|
|
202
|
+
/* Fallback visual when no brand image is provided. */
|
|
203
|
+
background-image: none;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Wordmark: the text name next to the logo mark. */
|
|
207
|
+
.sidebar-wordmark {
|
|
208
|
+
font-size: var(--type-small);
|
|
209
|
+
font-weight: var(--font-weight-semibold);
|
|
210
|
+
color: var(--color-text-primary);
|
|
211
|
+
letter-spacing: var(--type-h4-ls);
|
|
212
|
+
white-space: nowrap;
|
|
213
|
+
overflow: hidden;
|
|
214
|
+
flex: 1 1 auto;
|
|
215
|
+
/* Collapse animation: opacity + max-width so it gracefully disappears
|
|
216
|
+
without leaving a gap. Transition is on opacity + max-width per the
|
|
217
|
+
exception documented in Sidebar.tsx. */
|
|
218
|
+
max-width: 200px;
|
|
219
|
+
opacity: 1;
|
|
220
|
+
will-change: max-width;
|
|
221
|
+
transition:
|
|
222
|
+
opacity var(--duration-normal) var(--ease-in-out),
|
|
223
|
+
max-width var(--duration-slow) var(--ease-in-out);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.sidebar--collapsed .sidebar-wordmark {
|
|
227
|
+
opacity: 0;
|
|
228
|
+
max-width: 0;
|
|
229
|
+
pointer-events: none;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Collapse button: shows a chevron, desktop-only. */
|
|
233
|
+
.sidebar-collapse-btn {
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
flex-shrink: 0;
|
|
238
|
+
width: var(--space-7);
|
|
239
|
+
height: var(--space-7);
|
|
240
|
+
border-radius: var(--radius-default);
|
|
241
|
+
border: none;
|
|
242
|
+
background-color: transparent;
|
|
243
|
+
color: var(--color-text-muted);
|
|
244
|
+
cursor: pointer;
|
|
245
|
+
margin-left: auto;
|
|
246
|
+
transition:
|
|
247
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
248
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.sidebar-collapse-btn:hover {
|
|
252
|
+
background-color: var(--color-bg-raised);
|
|
253
|
+
color: var(--color-text-primary);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.sidebar-collapse-btn:active {
|
|
257
|
+
background-color: var(--color-bg-highlight);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.sidebar-collapse-btn:focus-visible {
|
|
261
|
+
outline: 2px solid var(--color-focus-ring);
|
|
262
|
+
outline-offset: 2px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* Mobile: hide the collapse button (mobile uses sidebar-mobile-close-btn). */
|
|
266
|
+
@media (max-width: 767px) {
|
|
267
|
+
.sidebar-collapse-btn {
|
|
268
|
+
display: none;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* Chevron icon inside the collapse button. Rotates when sidebar is collapsed. */
|
|
273
|
+
.sidebar-collapse-icon {
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
justify-content: center;
|
|
277
|
+
transition:
|
|
278
|
+
transform var(--duration-slow) var(--ease-in-out);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.sidebar-collapse-icon--flipped {
|
|
282
|
+
transform: rotate(180deg);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* Mobile close button: visible only on mobile, hidden on desktop. */
|
|
286
|
+
.sidebar-mobile-close-btn {
|
|
287
|
+
display: none;
|
|
288
|
+
align-items: center;
|
|
289
|
+
justify-content: center;
|
|
290
|
+
flex-shrink: 0;
|
|
291
|
+
width: var(--space-8);
|
|
292
|
+
height: var(--space-8);
|
|
293
|
+
border-radius: var(--radius-default);
|
|
294
|
+
border: none;
|
|
295
|
+
background-color: transparent;
|
|
296
|
+
color: var(--color-text-muted);
|
|
297
|
+
font-size: var(--type-h3);
|
|
298
|
+
cursor: pointer;
|
|
299
|
+
margin-left: auto;
|
|
300
|
+
transition:
|
|
301
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
302
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.sidebar-mobile-close-btn:hover {
|
|
306
|
+
background-color: var(--color-bg-raised);
|
|
307
|
+
color: var(--color-text-primary);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.sidebar-mobile-close-btn:active {
|
|
311
|
+
background-color: var(--color-bg-highlight);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.sidebar-mobile-close-btn:focus-visible {
|
|
315
|
+
outline: 2px solid var(--color-focus-ring);
|
|
316
|
+
outline-offset: 2px;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
@media (max-width: 767px) {
|
|
320
|
+
.sidebar-mobile-close-btn {
|
|
321
|
+
display: flex;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* On mobile, collapse button is already hidden; keep close visible. */
|
|
325
|
+
.sidebar-collapse-btn {
|
|
326
|
+
display: none;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ==========================================================================
|
|
331
|
+
2b. Sidebar navigation
|
|
332
|
+
========================================================================== */
|
|
333
|
+
|
|
334
|
+
.sidebar-nav {
|
|
335
|
+
flex: 1 1 auto;
|
|
336
|
+
overflow-y: auto;
|
|
337
|
+
overflow-x: hidden;
|
|
338
|
+
padding: var(--space-3) 0;
|
|
339
|
+
/* Thin scrollbar track to avoid obscuring nav content. */
|
|
340
|
+
scrollbar-width: thin;
|
|
341
|
+
scrollbar-color: var(--color-border-default) transparent;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.sidebar-nav::-webkit-scrollbar {
|
|
345
|
+
width: var(--space-1);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.sidebar-nav::-webkit-scrollbar-track {
|
|
349
|
+
background: transparent;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.sidebar-nav::-webkit-scrollbar-thumb {
|
|
353
|
+
background-color: var(--color-border-default);
|
|
354
|
+
border-radius: var(--radius-pill);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Section: a named group of nav items. */
|
|
358
|
+
.sidebar-section {
|
|
359
|
+
margin-bottom: var(--space-2);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Section heading: "Account", "Support" etc.
|
|
363
|
+
Hidden by collapsing opacity + max-height when sidebar is collapsed. */
|
|
364
|
+
.sidebar-section-heading {
|
|
365
|
+
margin: 0;
|
|
366
|
+
padding: var(--space-2) var(--space-4) var(--space-1);
|
|
367
|
+
font-size: var(--type-caption);
|
|
368
|
+
font-weight: var(--font-weight-semibold);
|
|
369
|
+
color: var(--color-text-muted);
|
|
370
|
+
letter-spacing: 0.06em;
|
|
371
|
+
text-transform: uppercase;
|
|
372
|
+
white-space: nowrap;
|
|
373
|
+
overflow: hidden;
|
|
374
|
+
max-height: 32px;
|
|
375
|
+
opacity: 1;
|
|
376
|
+
will-change: max-height, padding;
|
|
377
|
+
transition:
|
|
378
|
+
opacity var(--duration-normal) var(--ease-in-out),
|
|
379
|
+
max-height var(--duration-slow) var(--ease-in-out),
|
|
380
|
+
padding var(--duration-slow) var(--ease-in-out);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.sidebar--collapsed .sidebar-section-heading {
|
|
384
|
+
opacity: 0;
|
|
385
|
+
max-height: 0;
|
|
386
|
+
padding-top: 0;
|
|
387
|
+
padding-bottom: 0;
|
|
388
|
+
pointer-events: none;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* List: reset list styles. */
|
|
392
|
+
.sidebar-section-list {
|
|
393
|
+
list-style: none;
|
|
394
|
+
margin: 0;
|
|
395
|
+
padding: 0 var(--space-2);
|
|
396
|
+
display: flex;
|
|
397
|
+
flex-direction: column;
|
|
398
|
+
gap: var(--space-px);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* ==========================================================================
|
|
402
|
+
2c. Nav item (sidebar-nav-item, active modifier)
|
|
403
|
+
========================================================================== */
|
|
404
|
+
|
|
405
|
+
.sidebar-nav-item {
|
|
406
|
+
display: flex;
|
|
407
|
+
align-items: center;
|
|
408
|
+
gap: var(--space-3);
|
|
409
|
+
padding: var(--space-2) var(--space-3);
|
|
410
|
+
height: var(--space-10);
|
|
411
|
+
border-radius: var(--radius-default);
|
|
412
|
+
color: var(--color-text-secondary);
|
|
413
|
+
text-decoration: none;
|
|
414
|
+
font-size: var(--type-small);
|
|
415
|
+
font-weight: var(--font-weight-medium);
|
|
416
|
+
white-space: nowrap;
|
|
417
|
+
overflow: hidden;
|
|
418
|
+
position: relative;
|
|
419
|
+
/* Left accent line for active state: rendered via box-shadow so it
|
|
420
|
+
stays inside the border-radius without a pseudo-element. */
|
|
421
|
+
transition:
|
|
422
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
423
|
+
color var(--duration-fast) var(--ease-in-out),
|
|
424
|
+
box-shadow var(--duration-fast) var(--ease-in-out);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.sidebar-nav-item:hover {
|
|
428
|
+
background-color: var(--color-bg-raised);
|
|
429
|
+
color: var(--color-text-primary);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.sidebar-nav-item:active {
|
|
433
|
+
background-color: var(--color-bg-highlight);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.sidebar-nav-item:focus-visible {
|
|
437
|
+
outline: 2px solid var(--color-focus-ring);
|
|
438
|
+
outline-offset: 2px;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* Active state: tinted bg + accent text + left border via inset box-shadow. */
|
|
442
|
+
.sidebar-nav-item--active {
|
|
443
|
+
background-color: var(--color-bg-highlight);
|
|
444
|
+
color: var(--color-text-accent);
|
|
445
|
+
/* 3px inset left-side accent stripe. */
|
|
446
|
+
box-shadow: inset 3px 0 0 var(--color-accent);
|
|
447
|
+
font-weight: var(--font-weight-semibold);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.sidebar-nav-item--active:hover {
|
|
451
|
+
background-color: var(--color-bg-highlight);
|
|
452
|
+
color: var(--color-text-accent);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* When collapsed, center the icon by removing left padding gap. */
|
|
456
|
+
.sidebar--collapsed .sidebar-nav-item {
|
|
457
|
+
justify-content: center;
|
|
458
|
+
padding-left: 0;
|
|
459
|
+
padding-right: 0;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* ==========================================================================
|
|
463
|
+
2d. Nav item sub-elements: icon, label, badge
|
|
464
|
+
========================================================================== */
|
|
465
|
+
|
|
466
|
+
.sidebar-nav-icon {
|
|
467
|
+
display: flex;
|
|
468
|
+
align-items: center;
|
|
469
|
+
justify-content: center;
|
|
470
|
+
flex-shrink: 0;
|
|
471
|
+
width: var(--space-5);
|
|
472
|
+
height: var(--space-5);
|
|
473
|
+
color: inherit;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.sidebar-nav-label {
|
|
477
|
+
flex: 1 1 auto;
|
|
478
|
+
overflow: hidden;
|
|
479
|
+
white-space: nowrap;
|
|
480
|
+
text-overflow: ellipsis;
|
|
481
|
+
max-width: 200px;
|
|
482
|
+
opacity: 1;
|
|
483
|
+
will-change: max-width;
|
|
484
|
+
transition:
|
|
485
|
+
opacity var(--duration-normal) var(--ease-in-out),
|
|
486
|
+
max-width var(--duration-slow) var(--ease-in-out);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* Hidden label state: collapsed sidebar. */
|
|
490
|
+
.sidebar-nav-label--hidden,
|
|
491
|
+
.sidebar--collapsed .sidebar-nav-label {
|
|
492
|
+
opacity: 0;
|
|
493
|
+
max-width: 0;
|
|
494
|
+
pointer-events: none;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/* Badge: numeric count on nav items. */
|
|
498
|
+
.sidebar-nav-badge {
|
|
499
|
+
display: inline-flex;
|
|
500
|
+
align-items: center;
|
|
501
|
+
justify-content: center;
|
|
502
|
+
min-width: var(--space-5);
|
|
503
|
+
height: var(--space-5);
|
|
504
|
+
padding: 0 var(--space-1);
|
|
505
|
+
border-radius: var(--radius-pill);
|
|
506
|
+
background-color: var(--color-accent);
|
|
507
|
+
color: var(--color-text-inverse);
|
|
508
|
+
font-size: var(--type-caption);
|
|
509
|
+
font-weight: var(--font-weight-semibold);
|
|
510
|
+
letter-spacing: var(--type-caption-ls);
|
|
511
|
+
line-height: 1;
|
|
512
|
+
flex-shrink: 0;
|
|
513
|
+
transition:
|
|
514
|
+
background-color var(--duration-fast) var(--ease-in-out),
|
|
515
|
+
transform var(--duration-fast) var(--ease-spring);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/* Collapsed badge: dot indicator only (no number). */
|
|
519
|
+
.sidebar-nav-badge-dot {
|
|
520
|
+
position: absolute;
|
|
521
|
+
top: var(--space-2);
|
|
522
|
+
right: var(--space-2);
|
|
523
|
+
width: var(--space-2);
|
|
524
|
+
height: var(--space-2);
|
|
525
|
+
border-radius: var(--radius-circle);
|
|
526
|
+
background-color: var(--color-accent);
|
|
527
|
+
flex-shrink: 0;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/* ==========================================================================
|
|
531
|
+
2e. Sidebar footer: user identity block
|
|
532
|
+
========================================================================== */
|
|
533
|
+
|
|
534
|
+
.sidebar-footer {
|
|
535
|
+
display: flex;
|
|
536
|
+
flex-direction: column;
|
|
537
|
+
gap: var(--space-2);
|
|
538
|
+
padding: var(--space-3) var(--space-3);
|
|
539
|
+
border-top: 1px solid var(--color-border-default);
|
|
540
|
+
flex-shrink: 0;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.sidebar-user {
|
|
544
|
+
display: flex;
|
|
545
|
+
align-items: center;
|
|
546
|
+
gap: var(--space-3);
|
|
547
|
+
padding: var(--space-2) var(--space-1);
|
|
548
|
+
border-radius: var(--radius-default);
|
|
549
|
+
overflow: hidden;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* Avatar circle: shared base for both expanded and collapsed variants. */
|
|
553
|
+
.sidebar-user-avatar {
|
|
554
|
+
display: flex;
|
|
555
|
+
align-items: center;
|
|
556
|
+
justify-content: center;
|
|
557
|
+
flex-shrink: 0;
|
|
558
|
+
width: var(--space-8);
|
|
559
|
+
height: var(--space-8);
|
|
560
|
+
border-radius: var(--radius-circle);
|
|
561
|
+
background-color: var(--color-accent-subtle);
|
|
562
|
+
border: 1px solid var(--color-border-accent);
|
|
563
|
+
cursor: default;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/* Collapsed avatar: centered standalone, adds a title tooltip in HTML. */
|
|
567
|
+
.sidebar-user-avatar--collapsed {
|
|
568
|
+
margin: 0 auto;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.sidebar-user-initials {
|
|
572
|
+
font-size: var(--type-caption);
|
|
573
|
+
font-weight: var(--font-weight-semibold);
|
|
574
|
+
color: var(--color-text-accent);
|
|
575
|
+
letter-spacing: 0.04em;
|
|
576
|
+
line-height: 1;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.sidebar-user-info {
|
|
580
|
+
flex: 1 1 auto;
|
|
581
|
+
overflow: hidden;
|
|
582
|
+
display: flex;
|
|
583
|
+
flex-direction: column;
|
|
584
|
+
gap: var(--space-px);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.sidebar-user-name {
|
|
588
|
+
margin: 0;
|
|
589
|
+
font-size: var(--type-small);
|
|
590
|
+
font-weight: var(--font-weight-semibold);
|
|
591
|
+
color: var(--color-text-primary);
|
|
592
|
+
white-space: nowrap;
|
|
593
|
+
overflow: hidden;
|
|
594
|
+
text-overflow: ellipsis;
|
|
595
|
+
line-height: var(--type-small-lh);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.sidebar-user-email {
|
|
599
|
+
margin: 0;
|
|
600
|
+
font-size: var(--type-caption);
|
|
601
|
+
color: var(--color-text-muted);
|
|
602
|
+
white-space: nowrap;
|
|
603
|
+
overflow: hidden;
|
|
604
|
+
text-overflow: ellipsis;
|
|
605
|
+
line-height: var(--type-caption-lh);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/* ==========================================================================
|
|
609
|
+
3. TOPBAR
|
|
610
|
+
==========================================================================
|
|
611
|
+
Sticky horizontal bar across the top of the main column. Uses
|
|
612
|
+
backdrop-filter blur for the frosted-glass effect as content scrolls
|
|
613
|
+
beneath it. Height is driven by --spacing-topbar-h (48px).
|
|
614
|
+
========================================================================== */
|
|
615
|
+
|
|
616
|
+
.topbar {
|
|
617
|
+
position: sticky;
|
|
618
|
+
top: 0;
|
|
619
|
+
z-index: var(--z-topbar);
|
|
620
|
+
height: var(--spacing-topbar-h);
|
|
621
|
+
background-color: color-mix(in srgb, var(--color-bg-overlay) 85%, transparent);
|
|
622
|
+
backdrop-filter: blur(8px);
|
|
623
|
+
-webkit-backdrop-filter: blur(8px);
|
|
624
|
+
border-bottom: 1px solid var(--color-border-default);
|
|
625
|
+
flex-shrink: 0;
|
|
626
|
+
transition:
|
|
627
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
628
|
+
border-color var(--duration-normal) var(--ease-in-out);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/* Inner layout: left slot + right slot, full height flex row. */
|
|
632
|
+
.topbar-inner {
|
|
633
|
+
display: flex;
|
|
634
|
+
align-items: center;
|
|
635
|
+
justify-content: space-between;
|
|
636
|
+
height: 100%;
|
|
637
|
+
padding: 0 var(--space-4);
|
|
638
|
+
gap: var(--space-3);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/* Left slot: sidebar trigger + breadcrumb. */
|
|
642
|
+
.topbar-left {
|
|
643
|
+
display: flex;
|
|
644
|
+
align-items: center;
|
|
645
|
+
gap: var(--space-2);
|
|
646
|
+
flex: 1 1 auto;
|
|
647
|
+
min-width: 0;
|
|
648
|
+
overflow: hidden;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/* Right slot: search, notifications, user menu. */
|
|
652
|
+
.topbar-right {
|
|
653
|
+
display: flex;
|
|
654
|
+
align-items: center;
|
|
655
|
+
gap: var(--space-2);
|
|
656
|
+
flex-shrink: 0;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/* --------------------------------------------------------------------------
|
|
660
|
+
3a. Topbar icon button (shared base for hamburger, notifications, etc.)
|
|
661
|
+
-------------------------------------------------------------------------- */
|
|
662
|
+
|
|
663
|
+
.topbar-icon-btn {
|
|
664
|
+
display: inline-flex;
|
|
665
|
+
align-items: center;
|
|
666
|
+
justify-content: center;
|
|
667
|
+
flex-shrink: 0;
|
|
668
|
+
width: var(--space-9);
|
|
669
|
+
height: var(--space-9);
|
|
670
|
+
border-radius: var(--radius-default);
|
|
671
|
+
border: none;
|
|
672
|
+
background-color: transparent;
|
|
673
|
+
color: var(--color-text-secondary);
|
|
674
|
+
cursor: pointer;
|
|
675
|
+
transition:
|
|
676
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
677
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.topbar-icon-btn:hover {
|
|
681
|
+
background-color: var(--color-bg-raised);
|
|
682
|
+
color: var(--color-text-primary);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.topbar-icon-btn:active {
|
|
686
|
+
background-color: var(--color-bg-highlight);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.topbar-icon-btn:focus-visible {
|
|
690
|
+
outline: 2px solid var(--color-focus-ring);
|
|
691
|
+
outline-offset: 2px;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* Position-relative variant: used for notification bell so the badge
|
|
695
|
+
can be positioned absolutely relative to the button. */
|
|
696
|
+
.topbar-icon-btn--relative {
|
|
697
|
+
position: relative;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/* --------------------------------------------------------------------------
|
|
701
|
+
3b. Search button
|
|
702
|
+
-------------------------------------------------------------------------- */
|
|
703
|
+
|
|
704
|
+
.topbar-search-btn {
|
|
705
|
+
display: inline-flex;
|
|
706
|
+
align-items: center;
|
|
707
|
+
gap: var(--space-2);
|
|
708
|
+
height: var(--space-9);
|
|
709
|
+
padding: 0 var(--space-3);
|
|
710
|
+
border-radius: var(--radius-default);
|
|
711
|
+
border: 1px solid var(--color-border-default);
|
|
712
|
+
background-color: var(--color-bg-sunken);
|
|
713
|
+
color: var(--color-text-muted);
|
|
714
|
+
font-size: var(--type-small);
|
|
715
|
+
cursor: pointer;
|
|
716
|
+
transition:
|
|
717
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
718
|
+
border-color var(--duration-normal) var(--ease-in-out),
|
|
719
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.topbar-search-btn:hover {
|
|
723
|
+
background-color: var(--color-bg-raised);
|
|
724
|
+
border-color: var(--color-border-emphasis);
|
|
725
|
+
color: var(--color-text-secondary);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.topbar-search-btn:focus-visible {
|
|
729
|
+
outline: 2px solid var(--color-focus-ring);
|
|
730
|
+
outline-offset: 2px;
|
|
731
|
+
border-color: var(--color-border-accent);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.topbar-search-icon {
|
|
735
|
+
flex-shrink: 0;
|
|
736
|
+
color: var(--color-text-muted);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.topbar-search-label {
|
|
740
|
+
white-space: nowrap;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/* Keyboard shortcut hint: hidden on mobile. */
|
|
744
|
+
.topbar-search-kbd {
|
|
745
|
+
display: inline-flex;
|
|
746
|
+
align-items: center;
|
|
747
|
+
gap: 2px;
|
|
748
|
+
padding: 2px var(--space-1);
|
|
749
|
+
border-radius: var(--radius-sharp);
|
|
750
|
+
border: 1px solid var(--color-border-emphasis);
|
|
751
|
+
background-color: var(--color-bg-raised);
|
|
752
|
+
font-family: var(--font-mono);
|
|
753
|
+
font-size: var(--type-caption);
|
|
754
|
+
color: var(--color-text-muted);
|
|
755
|
+
line-height: 1;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
@media (max-width: 767px) {
|
|
759
|
+
.topbar-search-label,
|
|
760
|
+
.topbar-search-kbd {
|
|
761
|
+
display: none;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.topbar-search-btn {
|
|
765
|
+
width: var(--space-9);
|
|
766
|
+
padding: 0;
|
|
767
|
+
justify-content: center;
|
|
768
|
+
border: none;
|
|
769
|
+
background-color: transparent;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/* --------------------------------------------------------------------------
|
|
774
|
+
3c. Notification badge
|
|
775
|
+
-------------------------------------------------------------------------- */
|
|
776
|
+
|
|
777
|
+
.topbar-notif-badge {
|
|
778
|
+
position: absolute;
|
|
779
|
+
top: var(--space-1);
|
|
780
|
+
right: var(--space-1);
|
|
781
|
+
min-width: var(--space-4);
|
|
782
|
+
height: var(--space-4);
|
|
783
|
+
padding: 0 var(--space-1);
|
|
784
|
+
border-radius: var(--radius-pill);
|
|
785
|
+
background-color: var(--color-danger);
|
|
786
|
+
color: var(--color-neutral-0);
|
|
787
|
+
font-size: var(--type-caption);
|
|
788
|
+
font-weight: var(--font-weight-bold);
|
|
789
|
+
line-height: 1;
|
|
790
|
+
display: flex;
|
|
791
|
+
align-items: center;
|
|
792
|
+
justify-content: center;
|
|
793
|
+
pointer-events: none;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* --------------------------------------------------------------------------
|
|
797
|
+
3d. User menu trigger
|
|
798
|
+
-------------------------------------------------------------------------- */
|
|
799
|
+
|
|
800
|
+
.topbar-user-menu {
|
|
801
|
+
position: relative;
|
|
802
|
+
display: flex;
|
|
803
|
+
align-items: center;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.topbar-user-trigger {
|
|
807
|
+
display: inline-flex;
|
|
808
|
+
align-items: center;
|
|
809
|
+
gap: var(--space-2);
|
|
810
|
+
height: var(--space-9);
|
|
811
|
+
padding: 0 var(--space-2);
|
|
812
|
+
border-radius: var(--radius-default);
|
|
813
|
+
border: none;
|
|
814
|
+
background-color: transparent;
|
|
815
|
+
color: var(--color-text-secondary);
|
|
816
|
+
font-size: var(--type-small);
|
|
817
|
+
font-weight: var(--font-weight-medium);
|
|
818
|
+
cursor: pointer;
|
|
819
|
+
transition:
|
|
820
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
821
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.topbar-user-trigger:hover {
|
|
825
|
+
background-color: var(--color-bg-raised);
|
|
826
|
+
color: var(--color-text-primary);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.topbar-user-trigger:active {
|
|
830
|
+
background-color: var(--color-bg-highlight);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.topbar-user-trigger:focus-visible {
|
|
834
|
+
outline: 2px solid var(--color-focus-ring);
|
|
835
|
+
outline-offset: 2px;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/* Avatar circle in the topbar. */
|
|
839
|
+
.topbar-avatar {
|
|
840
|
+
display: inline-flex;
|
|
841
|
+
align-items: center;
|
|
842
|
+
justify-content: center;
|
|
843
|
+
flex-shrink: 0;
|
|
844
|
+
width: var(--space-8);
|
|
845
|
+
height: var(--space-8);
|
|
846
|
+
border-radius: var(--radius-circle);
|
|
847
|
+
background-color: var(--color-accent-subtle);
|
|
848
|
+
border: 1px solid var(--color-border-accent);
|
|
849
|
+
font-size: var(--type-caption);
|
|
850
|
+
font-weight: var(--font-weight-semibold);
|
|
851
|
+
color: var(--color-text-accent);
|
|
852
|
+
letter-spacing: 0.04em;
|
|
853
|
+
line-height: 1;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/* User display name: hidden on mobile. */
|
|
857
|
+
.topbar-user-name {
|
|
858
|
+
white-space: nowrap;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
@media (max-width: 767px) {
|
|
862
|
+
.topbar-user-name {
|
|
863
|
+
display: none;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/* Chevron caret: rotates when the menu is open. */
|
|
868
|
+
.topbar-chevron {
|
|
869
|
+
flex-shrink: 0;
|
|
870
|
+
color: var(--color-text-muted);
|
|
871
|
+
transition:
|
|
872
|
+
transform var(--duration-normal) var(--ease-in-out),
|
|
873
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.topbar-chevron--open {
|
|
877
|
+
transform: rotate(180deg);
|
|
878
|
+
color: var(--color-text-primary);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
@media (max-width: 767px) {
|
|
882
|
+
.topbar-chevron {
|
|
883
|
+
display: none;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/* --------------------------------------------------------------------------
|
|
888
|
+
3e. User dropdown menu
|
|
889
|
+
-------------------------------------------------------------------------- */
|
|
890
|
+
|
|
891
|
+
.topbar-dropdown {
|
|
892
|
+
position: absolute;
|
|
893
|
+
top: calc(100% + var(--space-1));
|
|
894
|
+
right: 0;
|
|
895
|
+
min-width: 180px;
|
|
896
|
+
background-color: var(--color-bg-overlay);
|
|
897
|
+
border: 1px solid var(--color-border-emphasis);
|
|
898
|
+
border-radius: var(--radius-lg);
|
|
899
|
+
box-shadow: var(--shadow-2);
|
|
900
|
+
padding: var(--space-1) var(--space-1);
|
|
901
|
+
z-index: var(--z-dropdown);
|
|
902
|
+
display: flex;
|
|
903
|
+
flex-direction: column;
|
|
904
|
+
gap: var(--space-px);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.topbar-dropdown-item {
|
|
908
|
+
display: flex;
|
|
909
|
+
align-items: center;
|
|
910
|
+
gap: var(--space-3);
|
|
911
|
+
padding: var(--space-2) var(--space-3);
|
|
912
|
+
border-radius: var(--radius-default);
|
|
913
|
+
font-size: var(--type-small);
|
|
914
|
+
font-weight: var(--font-weight-medium);
|
|
915
|
+
color: var(--color-text-secondary);
|
|
916
|
+
text-decoration: none;
|
|
917
|
+
cursor: pointer;
|
|
918
|
+
transition:
|
|
919
|
+
background-color var(--duration-normal) var(--ease-in-out),
|
|
920
|
+
color var(--duration-fast) var(--ease-in-out);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.topbar-dropdown-item:hover {
|
|
924
|
+
background-color: var(--color-bg-raised);
|
|
925
|
+
color: var(--color-text-primary);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.topbar-dropdown-item:active {
|
|
929
|
+
background-color: var(--color-bg-highlight);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.topbar-dropdown-item:focus-visible {
|
|
933
|
+
outline: 2px solid var(--color-focus-ring);
|
|
934
|
+
outline-offset: 2px;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* Destructive item (Sign out): danger color. */
|
|
938
|
+
.topbar-dropdown-item--destructive {
|
|
939
|
+
color: var(--color-danger);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
.topbar-dropdown-item--destructive:hover {
|
|
943
|
+
background-color: var(--color-danger-subtle);
|
|
944
|
+
color: var(--color-danger);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/* ==========================================================================
|
|
948
|
+
4. BREADCRUMB
|
|
949
|
+
========================================================================== */
|
|
950
|
+
|
|
951
|
+
.breadcrumb {
|
|
952
|
+
display: flex;
|
|
953
|
+
align-items: center;
|
|
954
|
+
min-width: 0;
|
|
955
|
+
overflow: hidden;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.breadcrumb-list {
|
|
959
|
+
display: flex;
|
|
960
|
+
align-items: center;
|
|
961
|
+
gap: var(--space-1);
|
|
962
|
+
list-style: none;
|
|
963
|
+
margin: 0;
|
|
964
|
+
padding: 0;
|
|
965
|
+
white-space: nowrap;
|
|
966
|
+
overflow: hidden;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.breadcrumb-item {
|
|
970
|
+
display: flex;
|
|
971
|
+
align-items: center;
|
|
972
|
+
gap: var(--space-1);
|
|
973
|
+
flex-shrink: 0;
|
|
974
|
+
overflow: hidden;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/* Last breadcrumb: can shrink to show full preceding path. */
|
|
978
|
+
.breadcrumb-item--current {
|
|
979
|
+
overflow: hidden;
|
|
980
|
+
flex-shrink: 1;
|
|
981
|
+
min-width: 0;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/* Middle breadcrumbs: hidden on very narrow viewports. */
|
|
985
|
+
.breadcrumb-item--middle {
|
|
986
|
+
display: flex;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
@media (max-width: 479px) {
|
|
990
|
+
.breadcrumb-item--middle {
|
|
991
|
+
display: none;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
.breadcrumb-link {
|
|
996
|
+
font-size: var(--type-small);
|
|
997
|
+
font-weight: var(--font-weight-medium);
|
|
998
|
+
color: var(--color-text-muted);
|
|
999
|
+
text-decoration: none;
|
|
1000
|
+
border-radius: var(--radius-sm);
|
|
1001
|
+
padding: var(--space-px) var(--space-1);
|
|
1002
|
+
transition:
|
|
1003
|
+
color var(--duration-fast) var(--ease-in-out),
|
|
1004
|
+
background-color var(--duration-normal) var(--ease-in-out);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.breadcrumb-link:hover {
|
|
1008
|
+
color: var(--color-text-primary);
|
|
1009
|
+
background-color: var(--color-bg-raised);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
.breadcrumb-link:focus-visible {
|
|
1013
|
+
outline: 2px solid var(--color-focus-ring);
|
|
1014
|
+
outline-offset: 2px;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.breadcrumb-current {
|
|
1018
|
+
font-size: var(--type-small);
|
|
1019
|
+
font-weight: var(--font-weight-semibold);
|
|
1020
|
+
color: var(--color-text-primary);
|
|
1021
|
+
overflow: hidden;
|
|
1022
|
+
text-overflow: ellipsis;
|
|
1023
|
+
white-space: nowrap;
|
|
1024
|
+
padding: var(--space-px) var(--space-1);
|
|
1025
|
+
display: block;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
.breadcrumb-separator {
|
|
1029
|
+
color: var(--color-text-muted);
|
|
1030
|
+
font-size: var(--type-caption);
|
|
1031
|
+
user-select: none;
|
|
1032
|
+
flex-shrink: 0;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/* ==========================================================================
|
|
1036
|
+
5. THEME TOGGLE
|
|
1037
|
+
==========================================================================
|
|
1038
|
+
Both Sun and Moon icons are always in the DOM; the active icon has
|
|
1039
|
+
opacity:1 (set inline by the component) and the inactive one has
|
|
1040
|
+
opacity:0. This produces a cross-fade without layout shift.
|
|
1041
|
+
========================================================================== */
|
|
1042
|
+
|
|
1043
|
+
.theme-toggle {
|
|
1044
|
+
/* Inherits topbar-icon-btn layout and interaction styles.
|
|
1045
|
+
Additional override: relative positioning for the overlay icon. */
|
|
1046
|
+
position: relative;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
/* Base icon: stacks at its natural flow position. */
|
|
1050
|
+
.theme-toggle-icon {
|
|
1051
|
+
display: flex;
|
|
1052
|
+
align-items: center;
|
|
1053
|
+
justify-content: center;
|
|
1054
|
+
/* Only opacity is transitioned, no transform. */
|
|
1055
|
+
transition:
|
|
1056
|
+
opacity var(--duration-normal) var(--ease-in-out);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/* Overlay icon: absolute, stacked exactly over the base icon. */
|
|
1060
|
+
.theme-toggle-icon--overlay {
|
|
1061
|
+
position: absolute;
|
|
1062
|
+
inset: 0;
|
|
1063
|
+
display: flex;
|
|
1064
|
+
align-items: center;
|
|
1065
|
+
justify-content: center;
|
|
1066
|
+
transition:
|
|
1067
|
+
opacity var(--duration-normal) var(--ease-in-out);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
} /* end @layer shell */
|