qdadm 1.9.0 → 1.10.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 (61) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/src/components/InfoBanner.vue +0 -21
  4. package/src/components/dialogs/MultiStepDialog.vue +0 -19
  5. package/src/components/dialogs/UnsavedChangesDialog.vue +0 -19
  6. package/src/components/display/BannerZone.vue +4 -0
  7. package/src/components/display/CardsGrid.vue +0 -95
  8. package/src/components/display/CopyableId.vue +4 -0
  9. package/src/components/display/EmptyState.vue +0 -54
  10. package/src/components/display/IntensityBar.vue +4 -0
  11. package/src/components/display/RichCardsGrid.vue +0 -136
  12. package/src/components/edit/FormActions.vue +0 -28
  13. package/src/components/edit/FormField.vue +0 -20
  14. package/src/components/edit/FormPage.vue +0 -31
  15. package/src/components/edit/FormTab.vue +4 -0
  16. package/src/components/edit/FormTabs.vue +4 -0
  17. package/src/components/editors/JsonEditorFoldable.vue +4 -0
  18. package/src/components/editors/JsonStructuredField.vue +4 -0
  19. package/src/components/editors/JsonViewer.vue +0 -41
  20. package/src/components/editors/KeyValueEditor.vue +4 -0
  21. package/src/components/editors/LanguageEditor.vue +4 -0
  22. package/src/components/editors/PermissionEditor.vue +4 -0
  23. package/src/components/editors/ScopeEditor.vue +4 -0
  24. package/src/components/editors/VanillaJsonEditor.vue +4 -0
  25. package/src/components/item/FieldGroups.vue +4 -0
  26. package/src/components/layout/AppLayout.vue +4 -0
  27. package/src/components/layout/BaseLayout.vue +4 -0
  28. package/src/components/layout/Breadcrumb.vue +0 -57
  29. package/src/components/layout/DashboardLayout.vue +4 -0
  30. package/src/components/layout/FormLayout.vue +4 -0
  31. package/src/components/layout/ListLayout.vue +4 -0
  32. package/src/components/layout/PageHeader.vue +4 -0
  33. package/src/components/layout/PageLayout.vue +4 -0
  34. package/src/components/layout/defaults/DefaultBreadcrumb.vue +4 -0
  35. package/src/components/layout/defaults/DefaultFooter.vue +4 -0
  36. package/src/components/layout/defaults/DefaultHeader.vue +4 -0
  37. package/src/components/layout/defaults/DefaultMenu.vue +4 -0
  38. package/src/components/layout/defaults/DefaultPagination.vue +4 -0
  39. package/src/components/layout/defaults/DefaultTable.vue +4 -0
  40. package/src/components/layout/defaults/DefaultUserInfo.vue +4 -0
  41. package/src/components/pages/LoginPage.vue +4 -0
  42. package/src/components/pages/NotFoundPage.vue +4 -0
  43. package/src/components/show/ShowDisplay.vue +0 -75
  44. package/src/components/show/ShowField.vue +0 -29
  45. package/src/components/show/ShowPage.vue +4 -0
  46. package/src/entity/EntityManager.ts +4 -1
  47. package/src/kernel/Kernel.ts +5 -1
  48. package/src/kernel/KernelContext.ts +12 -2
  49. package/src/notifications/NotificationBadge.vue +4 -0
  50. package/src/notifications/NotificationPanel.vue +4 -0
  51. package/src/security/pages/RoleForm.vue +4 -0
  52. package/src/security/pages/RoleList.vue +4 -0
  53. package/src/styles/_alerts.scss +20 -0
  54. package/src/styles/_cards.scss +241 -0
  55. package/src/styles/_code.scss +43 -0
  56. package/src/styles/_dialogs.scss +36 -0
  57. package/src/styles/_forms.scss +77 -0
  58. package/src/styles/_main.scss +62 -0
  59. package/src/styles/_show-pages.scss +106 -0
  60. package/src/styles/_states.scss +45 -4
  61. package/src/styles/index.scss +1 -0
package/README.md CHANGED
@@ -96,8 +96,8 @@ Options: `transformRequest`, `transformResponse`, `responseFormat`, `clientSideP
96
96
  | Doc | Purpose |
97
97
  |-----|---------|
98
98
  | [QDADM_CREDO](QDADM_CREDO.md) | Philosophy, patterns, concepts |
99
- | [Architecture](docs/architecture.md) | PAC pattern, layers |
100
- | [Extension](docs/extension.md) | Hooks, signals, zones |
99
+ | [Architecture](../../docs/architecture.md) | PAC pattern, layers |
100
+ | [Extension](../../docs/extension.md) | Hooks, signals, zones |
101
101
 
102
102
  ## Peer Dependencies
103
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qdadm",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Vue 3 framework for admin dashboards with PrimeVue",
5
5
  "author": "quazardous",
6
6
  "license": "MIT",
@@ -71,24 +71,3 @@ const iconClass = computed(() => {
71
71
  </div>
72
72
  </Message>
73
73
  </template>
74
-
75
- <style scoped>
76
- .info-banner-content {
77
- display: flex;
78
- align-items: center;
79
- gap: 0.625rem;
80
- }
81
-
82
- .info-banner-icon {
83
- font-size: 1.125rem;
84
- flex-shrink: 0;
85
- }
86
-
87
- .info-banner-text {
88
- flex: 1;
89
- }
90
-
91
- .info-banner-text :deep(strong) {
92
- font-weight: 600;
93
- }
94
- </style>
@@ -329,22 +329,3 @@ const slotActions = computed<SlotActions>(() => ({
329
329
  </div>
330
330
  </Dialog>
331
331
  </template>
332
-
333
- <style scoped>
334
- .multi-step-dialog {
335
- padding: 0.5rem 0;
336
- }
337
-
338
- .step-content {
339
- padding: 1rem 0;
340
- }
341
-
342
- .step-actions {
343
- display: flex;
344
- justify-content: flex-end;
345
- gap: 0.5rem;
346
- margin-top: 1.5rem;
347
- padding-top: 1rem;
348
- border-top: 1px solid var(--p-surface-200);
349
- }
350
- </style>
@@ -78,22 +78,3 @@ function onSaveAndLeave(): void {
78
78
  </template>
79
79
  </SimpleDialog>
80
80
  </template>
81
-
82
- <style scoped>
83
- .dialog-content {
84
- display: flex;
85
- align-items: flex-start;
86
- gap: 1rem;
87
- }
88
-
89
- .dialog-icon {
90
- font-size: 2rem;
91
- color: var(--p-orange-500);
92
- flex-shrink: 0;
93
- }
94
-
95
- .dialog-content p {
96
- margin: 0;
97
- line-height: 1.5;
98
- }
99
- </style>
@@ -35,6 +35,10 @@ const { banners, hideBanner } = useInfoBanner()
35
35
  </template>
36
36
 
37
37
  <style scoped>
38
+ /*
39
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
40
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
41
+ */
38
42
  .banner-zone {
39
43
  position: relative;
40
44
  }
@@ -70,98 +70,3 @@ function getSeverityClass(severity?: Severity): string {
70
70
  </template>
71
71
  </div>
72
72
  </template>
73
-
74
- <style scoped>
75
- .cards-grid {
76
- display: grid;
77
- gap: 1rem;
78
- margin-bottom: 1.5rem;
79
- }
80
-
81
- .cards-grid--cols-auto {
82
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
83
- }
84
-
85
- .cards-grid--cols-2 {
86
- grid-template-columns: repeat(2, 1fr);
87
- }
88
-
89
- .cards-grid--cols-3 {
90
- grid-template-columns: repeat(3, 1fr);
91
- }
92
-
93
- .cards-grid--cols-4 {
94
- grid-template-columns: repeat(4, 1fr);
95
- }
96
-
97
- .stat-card,
98
- .card-custom {
99
- background: var(--p-surface-0);
100
- border: 1px solid var(--p-surface-200);
101
- border-radius: 0.5rem;
102
- padding: 1.25rem;
103
- }
104
-
105
- .stat-card {
106
- text-align: center;
107
- }
108
-
109
- .stat-card--clickable {
110
- cursor: pointer;
111
- transition: border-color 0.2s, box-shadow 0.2s;
112
- }
113
-
114
- .stat-card--clickable:hover {
115
- border-color: var(--p-primary-300);
116
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
117
- }
118
-
119
- .stat-value {
120
- font-size: 2rem;
121
- font-weight: 600;
122
- color: var(--p-primary-500);
123
- display: flex;
124
- align-items: center;
125
- justify-content: center;
126
- gap: 0.5rem;
127
- }
128
-
129
- .stat-value--success {
130
- color: var(--p-green-500);
131
- }
132
-
133
- .stat-value--danger {
134
- color: var(--p-red-500);
135
- }
136
-
137
- .stat-value--warning {
138
- color: var(--p-orange-500);
139
- }
140
-
141
- .stat-value--info {
142
- color: var(--p-blue-500);
143
- }
144
-
145
- .stat-icon {
146
- font-size: 1.5rem;
147
- }
148
-
149
- .stat-label {
150
- font-size: 0.875rem;
151
- color: var(--p-surface-600);
152
- margin-top: 0.25rem;
153
- }
154
-
155
- @media (max-width: 768px) {
156
- .cards-grid--cols-3,
157
- .cards-grid--cols-4 {
158
- grid-template-columns: repeat(2, 1fr);
159
- }
160
- }
161
-
162
- @media (max-width: 480px) {
163
- .cards-grid {
164
- grid-template-columns: 1fr;
165
- }
166
- }
167
- </style>
@@ -57,6 +57,10 @@ async function copyToClipboard(): Promise<void> {
57
57
  </template>
58
58
 
59
59
  <style scoped>
60
+ /*
61
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
62
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
63
+ */
60
64
  .copyable-id {
61
65
  display: inline-flex;
62
66
  align-items: center;
@@ -60,57 +60,3 @@ function getIconClass(icon: string): string {
60
60
  </div>
61
61
  </div>
62
62
  </template>
63
-
64
- <style scoped>
65
- .empty-state {
66
- display: flex;
67
- flex-direction: column;
68
- align-items: center;
69
- justify-content: center;
70
- text-align: center;
71
- padding: 2rem;
72
- color: var(--text-color-secondary);
73
- }
74
-
75
- .empty-state--sm {
76
- padding: 1rem;
77
- }
78
-
79
- .empty-state--lg {
80
- padding: 3rem;
81
- }
82
-
83
- .empty-state-icon {
84
- font-size: 2rem;
85
- margin-bottom: 0.5rem;
86
- opacity: 0.5;
87
- }
88
-
89
- .empty-state--sm .empty-state-icon {
90
- font-size: 1.5rem;
91
- }
92
-
93
- .empty-state--lg .empty-state-icon {
94
- font-size: 3rem;
95
- margin-bottom: 1rem;
96
- }
97
-
98
- .empty-state-title {
99
- margin: 0 0 0.25rem 0;
100
- font-weight: 500;
101
- color: var(--text-color-secondary);
102
- }
103
-
104
- .empty-state--lg .empty-state-title {
105
- font-size: 1.1rem;
106
- }
107
-
108
- .empty-state-description {
109
- opacity: 0.7;
110
- max-width: 300px;
111
- }
112
-
113
- .empty-state-actions {
114
- margin-top: 1rem;
115
- }
116
- </style>
@@ -134,6 +134,10 @@ onMounted(() => {
134
134
  </template>
135
135
 
136
136
  <style scoped>
137
+ /*
138
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
139
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
140
+ */
137
141
  .intensity-container {
138
142
  display: flex;
139
143
  align-items: center;
@@ -99,139 +99,3 @@ function getSeverityClass(severity: CardSeverity | undefined): string {
99
99
  </template>
100
100
  </div>
101
101
  </template>
102
-
103
- <style scoped>
104
- .rich-cards-grid {
105
- display: grid;
106
- gap: 1rem;
107
- margin-bottom: 1.5rem;
108
- }
109
-
110
- .rich-cards-grid--cols-auto {
111
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
112
- }
113
-
114
- .rich-cards-grid--cols-2 {
115
- grid-template-columns: repeat(2, 1fr);
116
- }
117
-
118
- .rich-cards-grid--cols-3 {
119
- grid-template-columns: repeat(3, 1fr);
120
- }
121
-
122
- .rich-cards-grid--cols-4 {
123
- grid-template-columns: repeat(4, 1fr);
124
- }
125
-
126
- .rich-cards-grid--cols-5 {
127
- grid-template-columns: repeat(5, 1fr);
128
- }
129
-
130
- .rich-cards-grid--cols-6 {
131
- grid-template-columns: repeat(6, 1fr);
132
- }
133
-
134
- .rich-card {
135
- background: var(--p-surface-0);
136
- border: 1px solid var(--p-surface-200);
137
- border-radius: 0.5rem;
138
- padding: 1.25rem;
139
- }
140
-
141
- .rich-card--clickable {
142
- cursor: pointer;
143
- transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
144
- }
145
-
146
- .rich-card--clickable:hover {
147
- border-color: var(--p-primary-300);
148
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
149
- transform: translateY(-2px);
150
- }
151
-
152
- .rich-card-header {
153
- display: flex;
154
- justify-content: space-between;
155
- align-items: center;
156
- margin-bottom: 0.75rem;
157
- }
158
-
159
- .rich-card-title {
160
- font-size: 0.875rem;
161
- font-weight: 500;
162
- color: var(--p-surface-600);
163
- }
164
-
165
- .rich-card-icon {
166
- font-size: 1.25rem;
167
- color: var(--p-surface-400);
168
- }
169
-
170
- .rich-card-value {
171
- font-size: 2rem;
172
- font-weight: 700;
173
- color: var(--p-surface-900);
174
- line-height: 1.2;
175
- }
176
-
177
- .rich-card-subtitle {
178
- font-size: 0.8rem;
179
- color: var(--p-surface-500);
180
- margin-top: 0.25rem;
181
- }
182
-
183
- /* Severity variants */
184
- .rich-card--success .rich-card-value {
185
- color: var(--p-green-600);
186
- }
187
-
188
- .rich-card--success .rich-card-icon {
189
- color: var(--p-green-500);
190
- }
191
-
192
- .rich-card--danger .rich-card-value {
193
- color: var(--p-red-600);
194
- }
195
-
196
- .rich-card--danger .rich-card-icon {
197
- color: var(--p-red-500);
198
- }
199
-
200
- .rich-card--warning .rich-card-value {
201
- color: var(--p-orange-600);
202
- }
203
-
204
- .rich-card--warning .rich-card-icon {
205
- color: var(--p-orange-500);
206
- }
207
-
208
- .rich-card--info .rich-card-value {
209
- color: var(--p-blue-600);
210
- }
211
-
212
- .rich-card--info .rich-card-icon {
213
- color: var(--p-blue-500);
214
- }
215
-
216
- @media (max-width: 1024px) {
217
- .rich-cards-grid--cols-5,
218
- .rich-cards-grid--cols-6 {
219
- grid-template-columns: repeat(3, 1fr);
220
- }
221
- }
222
-
223
- @media (max-width: 768px) {
224
- .rich-cards-grid--cols-3,
225
- .rich-cards-grid--cols-4,
226
- .rich-cards-grid--cols-5,
227
- .rich-cards-grid--cols-6 {
228
- grid-template-columns: repeat(2, 1fr);
229
- }
230
- }
231
-
232
- @media (max-width: 480px) {
233
- .rich-cards-grid {
234
- grid-template-columns: 1fr;
235
- }
236
- }
237
- </style>
@@ -73,31 +73,3 @@ const emit = defineEmits<{
73
73
  />
74
74
  </div>
75
75
  </template>
76
-
77
- <style scoped>
78
- .form-actions {
79
- display: flex;
80
- justify-content: space-between;
81
- align-items: center;
82
- margin-top: 1.5rem;
83
- padding-top: 1.5rem;
84
- border-top: 1px solid var(--p-surface-200);
85
- }
86
-
87
- .form-actions-left {
88
- display: flex;
89
- align-items: center;
90
- gap: 0.5rem;
91
- }
92
-
93
- .dirty-indicator {
94
- color: var(--p-orange-500);
95
- font-size: 0.5rem;
96
- animation: pulse 2s infinite;
97
- }
98
-
99
- @keyframes pulse {
100
- 0%, 100% { opacity: 1; }
101
- 50% { opacity: 0.4; }
102
- }
103
- </style>
@@ -80,23 +80,3 @@ function onBlur(): void {
80
80
  <small v-else-if="hint" class="field-hint">{{ hint }}</small>
81
81
  </div>
82
82
  </template>
83
-
84
- <style scoped>
85
- /* .field-hint and .field-error are global (main.css) */
86
-
87
- .field-invalid :deep(input),
88
- .field-invalid :deep(textarea),
89
- .field-invalid :deep(.p-inputtext),
90
- .field-invalid :deep(.p-select),
91
- .field-invalid :deep(.p-dropdown) {
92
- border-color: var(--p-red-500);
93
- }
94
-
95
- .field-invalid :deep(input:focus),
96
- .field-invalid :deep(textarea:focus),
97
- .field-invalid :deep(.p-inputtext:focus),
98
- .field-invalid :deep(.p-select:focus),
99
- .field-invalid :deep(.p-dropdown:focus) {
100
- box-shadow: 0 0 0 1px var(--p-red-500);
101
- }
102
- </style>
@@ -258,34 +258,3 @@ function onGuardStay(): void {
258
258
  />
259
259
  </div>
260
260
  </template>
261
-
262
- <style scoped>
263
- .form-page {
264
- display: flex;
265
- flex-direction: column;
266
- gap: 1rem;
267
- }
268
-
269
- .loading-state {
270
- display: flex;
271
- justify-content: center;
272
- padding: 3rem;
273
- }
274
-
275
- .form-error-message {
276
- margin: 1rem 0;
277
- }
278
-
279
- .validation-summary {
280
- margin-bottom: 1rem;
281
- }
282
-
283
- .validation-errors {
284
- margin: 0;
285
- padding-left: 1.5rem;
286
- }
287
-
288
- .validation-errors li {
289
- margin: 0.25rem 0;
290
- }
291
- </style>
@@ -155,6 +155,10 @@ function showBothCountAndBadge(): boolean {
155
155
  </template>
156
156
 
157
157
  <style scoped>
158
+ /*
159
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
160
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
161
+ */
158
162
  .tab-icon {
159
163
  margin-right: 0.5rem;
160
164
  }
@@ -63,6 +63,10 @@ function onTabChange(value: string | number): void {
63
63
  </template>
64
64
 
65
65
  <style scoped>
66
+ /*
67
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
68
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
69
+ */
66
70
  .form-tabs {
67
71
  margin-top: 1rem;
68
72
  }
@@ -299,6 +299,10 @@ function isMultiline(value: unknown): boolean {
299
299
  </template>
300
300
 
301
301
  <style scoped>
302
+ /*
303
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
304
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
305
+ */
302
306
  .json-editor-foldable {
303
307
  display: flex;
304
308
  flex-direction: column;
@@ -158,6 +158,10 @@ watch(() => props.mode, (newMode: ViewMode | null | undefined) => {
158
158
  </template>
159
159
 
160
160
  <style scoped>
161
+ /*
162
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
163
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
164
+ */
161
165
  .json-structured-field {
162
166
  width: 100%;
163
167
  }
@@ -49,44 +49,3 @@ const formattedJson = computed<string>(() => {
49
49
  <pre class="json-content" v-html="formattedJson"></pre>
50
50
  </div>
51
51
  </template>
52
-
53
- <style scoped>
54
- .json-viewer {
55
- background: var(--p-surface-50);
56
- border: 1px solid var(--p-surface-200);
57
- border-radius: 0.375rem;
58
- overflow: auto;
59
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
60
- font-size: 0.8125rem;
61
- line-height: 1.5;
62
- }
63
-
64
- .json-content {
65
- padding: 1rem;
66
- margin: 0;
67
- white-space: pre-wrap;
68
- word-break: break-word;
69
- }
70
-
71
- :deep(.json-key) {
72
- color: #881391;
73
- }
74
-
75
- :deep(.json-string) {
76
- color: #1a1aa6;
77
- }
78
-
79
- :deep(.json-number) {
80
- color: #1c00cf;
81
- }
82
-
83
- :deep(.json-boolean) {
84
- color: #0d22aa;
85
- font-weight: 500;
86
- }
87
-
88
- :deep(.json-null) {
89
- color: #808080;
90
- font-style: italic;
91
- }
92
- </style>
@@ -226,6 +226,10 @@ function updateItemValue(index: number, value: string | number): void {
226
226
  </template>
227
227
 
228
228
  <style scoped>
229
+ /*
230
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
231
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
232
+ */
229
233
  .kv-list {
230
234
  display: flex;
231
235
  flex-direction: column;
@@ -169,6 +169,10 @@ function updateFluency(index: number, fluency: number | number[]): void {
169
169
  </template>
170
170
 
171
171
  <style scoped>
172
+ /*
173
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
174
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
175
+ */
172
176
  .lang-list {
173
177
  display: flex;
174
178
  flex-direction: column;
@@ -463,6 +463,10 @@ function getSuggestionClass(item: Suggestion): string {
463
463
  </template>
464
464
 
465
465
  <style scoped>
466
+ /*
467
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
468
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
469
+ */
466
470
  /* Uses global .editor-box pattern */
467
471
  .permission-editor {
468
472
  border: 1px solid var(--p-surface-200);
@@ -282,6 +282,10 @@ onMounted(async () => {
282
282
  </template>
283
283
 
284
284
  <style scoped>
285
+ /*
286
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
287
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
288
+ */
285
289
  .scope-editor {
286
290
  border: 1px solid var(--p-surface-200);
287
291
  border-radius: 0.5rem;
@@ -160,6 +160,10 @@ onUnmounted(() => {
160
160
  </template>
161
161
 
162
162
  <style scoped>
163
+ /*
164
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
165
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
166
+ */
163
167
  .vanilla-json-editor {
164
168
  width: 100%;
165
169
  border: 1px solid var(--p-surface-300);
@@ -322,6 +322,10 @@ function getBadgeValue(group: FieldGroup): string | number | null {
322
322
  </template>
323
323
 
324
324
  <style scoped>
325
+ /*
326
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
327
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
328
+ */
325
329
  .field-groups {
326
330
  display: flex;
327
331
  flex-direction: column;
@@ -423,6 +423,10 @@ const showBreadcrumb = computed<boolean>(() => {
423
423
  </template>
424
424
 
425
425
  <style scoped>
426
+ /*
427
+ * Only keep styles here that REQUIRE scoping (:deep, dynamic binding, component-specific overrides).
428
+ * Generic/reusable styles belong in src/styles/ partials (see _forms.scss, _cards.scss, etc.).
429
+ */
426
430
  /* =============================================================================
427
431
  MODERN ADMIN LAYOUT - VSCode/Material-inspired styling
428
432