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.
Files changed (156) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +32 -4
  3. package/framework/agents/build/dev.md +9 -5
  4. package/framework/agents/discover/brief.md +2 -0
  5. package/framework/agents/discover/brownfield-wu.md +2 -0
  6. package/framework/agents/discover/greenfield-wu.md +18 -1
  7. package/framework/agents/plan/detail.md +2 -0
  8. package/framework/agents/plan/tasks.md +31 -0
  9. package/framework/agents/plan/ux-brand-architect.md +21 -2
  10. package/framework/agents/plan/ux-component-engineer.md +10 -0
  11. package/framework/agents/quality/qa-implementation.md +1 -1
  12. package/framework/agents/quality/qa-planning.md +1 -1
  13. package/framework/agents/quality/qa-visual.md +33 -21
  14. package/framework/config.yaml +5 -4
  15. package/framework/constitution.md +58 -11
  16. package/framework/context/governance.md +12 -10
  17. package/framework/context/root.md +2 -2
  18. package/framework/data/entity-registry.yaml +12 -4
  19. package/framework/data/qa-rubrics.yaml +335 -0
  20. package/framework/domains/constitution.yaml +3 -3
  21. package/framework/executors/json-validate.js +80 -0
  22. package/framework/executors/npm-script.js +72 -0
  23. package/framework/executors/path-check.js +67 -0
  24. package/framework/executors/registry.yaml +36 -0
  25. package/framework/hooks/advance-trigger.js +47 -3
  26. package/framework/hooks/constitution-guard.js +9 -4
  27. package/framework/hooks/git-push-authority.js +113 -0
  28. package/framework/hooks/license-guard.js +59 -9
  29. package/framework/hooks/model-governance.js +40 -17
  30. package/framework/hooks/prism-engine.js +78 -11
  31. package/framework/hooks/session-digest.js +12 -3
  32. package/framework/hooks/settings.json +7 -3
  33. package/framework/hooks/style-guard.js +52 -3
  34. package/framework/hooks/team-quality-gate.js +43 -5
  35. package/framework/i18n/en.yaml +3 -3
  36. package/framework/i18n/es.yaml +3 -3
  37. package/framework/i18n/fr.yaml +3 -3
  38. package/framework/i18n/pt.yaml +3 -3
  39. package/framework/intelligence/confidence.yaml +85 -6
  40. package/framework/intelligence/context-engine.md +9 -5
  41. package/framework/intelligence/decision-engine.md +1 -1
  42. package/framework/orchestrator/chati-router.js +59 -5
  43. package/framework/orchestrator/chati-update.md +19 -3
  44. package/framework/orchestrator/chati.md +20 -1
  45. package/framework/quality-gates/planning-gate.md +2 -0
  46. package/framework/rules/human-writing-style.md +47 -0
  47. package/framework/scaffold/motion-premium/README.md +12 -2
  48. package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +1 -1
  49. package/framework/scaffold/motion-premium/scaffold.yaml +6 -1
  50. package/framework/scaffold/motion-premium-3d/README.md +10 -0
  51. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  52. package/framework/scaffold/motion-premium-3d/scaffold.yaml +3 -0
  53. package/framework/scaffold/saas-dashboard/README.md +58 -0
  54. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  55. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  56. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  57. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  58. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  59. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  60. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  61. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  62. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  63. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  64. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  65. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  66. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  67. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  68. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  69. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  70. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  71. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  72. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  73. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  74. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  75. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  76. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  77. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  78. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  79. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  80. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  81. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  82. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  83. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  84. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  85. package/framework/schemas/session.schema.json +5 -0
  86. package/framework/schemas/task.schema.json +9 -0
  87. package/framework/scripts/visual-qa.js +101 -3
  88. package/framework/tasks/orchestrator-health.md +4 -4
  89. package/framework/tasks/qa-impl-verdict.md +11 -5
  90. package/framework/templates/brandbook-html-tmpl.md +1 -1
  91. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  92. package/package.json +4 -3
  93. package/src/config/context-file-generator.js +0 -6
  94. package/src/dashboard/renderer.js +0 -36
  95. package/src/executors/runner.js +204 -0
  96. package/src/installer/core.js +13 -3
  97. package/src/installer/templates.js +5 -6
  98. package/src/intelligence/registry-manager.js +1 -1
  99. package/src/license/client.js +9 -3
  100. package/src/license/commands.js +12 -2
  101. package/src/license/machine-id.js +42 -1
  102. package/src/memory/gotchas.js +58 -40
  103. package/src/memory/magic-docs.js +1 -1
  104. package/src/memory/session-digest.js +9 -4
  105. package/src/orchestrator/cli.js +186 -15
  106. package/src/orchestrator/doctor.js +98 -16
  107. package/src/orchestrator/pipeline-manager.js +44 -22
  108. package/src/orchestrator/session-manager.js +64 -8
  109. package/src/telemetry/sender.js +7 -19
  110. package/src/terminal/run-team.js +3 -3
  111. package/src/upgrade/tracked-files-detector.js +34 -16
  112. package/src/utils/feature-flags.js +1 -1
  113. package/src/utils/flatten-entities.js +4 -40
  114. package/src/utils/schema-validator.js +0 -14
  115. package/src/wizard/i18n.js +3 -3
  116. package/src/api/index.js +0 -120
  117. package/src/autonomy/autonomous-gate.js +0 -294
  118. package/src/autonomy/build-loop.js +0 -281
  119. package/src/autonomy/build-state.js +0 -286
  120. package/src/autonomy/cause-analyzer.js +0 -177
  121. package/src/autonomy/escalation.js +0 -214
  122. package/src/autonomy/index.js +0 -51
  123. package/src/autonomy/mode-manager.js +0 -225
  124. package/src/autonomy/mode-suggester.js +0 -283
  125. package/src/autonomy/progress-reporter.js +0 -275
  126. package/src/autonomy/safety-net.js +0 -370
  127. package/src/config/agent-customizer.js +0 -231
  128. package/src/decision/analyzer.js +0 -291
  129. package/src/decision/engine.js +0 -250
  130. package/src/decision/index.js +0 -38
  131. package/src/decision/registry-healer.js +0 -468
  132. package/src/decision/registry-updater.js +0 -339
  133. package/src/extensions/loader.js +0 -145
  134. package/src/extensions/registry.js +0 -134
  135. package/src/gates/circuit-breaker.js +0 -151
  136. package/src/gates/g1-planning-complete.js +0 -154
  137. package/src/gates/g2-qa-planning.js +0 -156
  138. package/src/gates/g3-implementation.js +0 -215
  139. package/src/gates/g4-qa-implementation.js +0 -240
  140. package/src/gates/g5-deploy-ready.js +0 -181
  141. package/src/gates/gate-base.js +0 -185
  142. package/src/gates/index.js +0 -46
  143. package/src/health/auto-fix.js +0 -216
  144. package/src/health/engine.js +0 -246
  145. package/src/merger/semantic-merger.js +0 -292
  146. package/src/preview/detector.js +0 -238
  147. package/src/preview/index.js +0 -20
  148. package/src/preview/launcher.js +0 -235
  149. package/src/preview/log-buffer.js +0 -103
  150. package/src/quality/metrics-collector.js +0 -281
  151. package/src/quality/test-runner.js +0 -366
  152. package/src/tasks/executor.js +0 -195
  153. package/src/tasks/index.js +0 -4
  154. package/src/tasks/loader.js +0 -210
  155. package/src/tasks/router.js +0 -182
  156. 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 */