structra-ui 0.1.23 → 0.1.25

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 (3) hide show
  1. package/README.md +29 -7
  2. package/package.json +22 -26
  3. package/structra-ui.css +939 -0
package/README.md CHANGED
@@ -6,16 +6,40 @@ Biblioteca **Angular** da stack **Structra** para interfaces consistentes: compo
6
6
 
7
7
  ## Instalação
8
8
 
9
- Para instalar a Structra UI em um projeto Angular, use:
9
+ Com **npm 7 ou superior**, um comando instala a lib e resolve os **peer dependencies** obrigatórios na raiz do projeto (Angular, Material, CDK, Router, AG Grid, RxJS, Zone.js):
10
10
 
11
11
  ```bash
12
- npm install structra-ui ag-grid-angular ag-grid-community
12
+ npm install structra-ui
13
13
  ```
14
14
 
15
+ Se usar **npm 6 ou anterior**, instale explicitamente os mesmos pacotes e versões indicados em `peerDependencies` no `package.json` do npm.
16
+
15
17
  **Compatibilidade**
16
18
 
17
- - **Angular:** **21**; peers `@angular/*` em **21.2.7** (versão exata; sem `>=`). Não há suporte para Angular 22.
18
- - **AG Grid** (grades): peers **`^35.0.0`**. Obrigatório se usar grades; caso contrário pode instalar `structra-ui` e gerenciar avisos de peers opcionais.
19
+ - **Angular 21** (`^21.2.7` nos peers): sem suporte para Angular 22.
20
+ - **Material e CDK** obrigatórios; **Router** obrigatório; **AG Grid** obrigatório; **RxJS** e **Zone.js** obrigatórios nada é opcional no `package.json` da lib.
21
+
22
+ ## Estilos globais (obrigatório)
23
+
24
+ O pacote inclui **`structra-ui.css`** (tema StructraLab: tokens, Material prebuilt, AG Grid, CDK/overlays). Sem este arquivo a UI fica sem estilos.
25
+
26
+ **Opção A — `angular.json` (recomendado):** em `projects.<app>.architect.build.options.styles`, acrescente **no início** da lista:
27
+
28
+ ```json
29
+ "styles": [
30
+ "node_modules/structra-ui/structra-ui.css"
31
+ ]
32
+ ```
33
+
34
+ **Opção B — `main.ts`:** antes de `bootstrapApplication`:
35
+
36
+ ```ts
37
+ import 'structra-ui/styles';
38
+ ```
39
+
40
+ (equivalente a `import 'structra-ui/structra-ui.css';`. Exige `moduleResolution` compatível com `exports` do npm, por exemplo `bundler` ou `node16`.)
41
+
42
+ **AG Grid 35+:** registe os módulos Community uma vez na app (ex. `ModuleRegistry.registerModules([AllCommunityModule])` em `main.ts`).
19
43
 
20
44
  **Importar componentes:** `import { TextFieldComponent } from 'structra-ui';` e use em `imports: [TextFieldComponent, …]` do `@Component`. No `tsconfig.json` da app, prefira `"moduleResolution": "bundler"` ou `"node16"` para o Node resolver o campo `exports` do pacote.
21
45
 
@@ -28,7 +52,7 @@ npm run lib:build
28
52
  # ou: npx ng build structra-ui
29
53
  ```
30
54
 
31
- gera `dist/structra-ui/`, pronto para `npm pack` / `npm publish`. O `package.json` gerado em `dist/structra-ui/` **preserva** `peerDependencies` e `dependencies` definidos em `projects/structra-ui/package.json` (incluindo Angular, AG Grid e `tslib`).
55
+ gera `dist/structra-ui/` (JavaScript + tipos + **`structra-ui.css`**), pronto para `npm pack` / `npm publish`. O CSS é gerado a partir de `src/styles.scss` do monorepo no passo `npm run lib:styles`.
32
56
 
33
57
  ## Uso
34
58
 
@@ -36,8 +60,6 @@ gera `dist/structra-ui/`, pronto para `npm pack` / `npm publish`. O `package.jso
36
60
  import { STRUCTRA_UI, BaseButtonComponent } from 'structra-ui';
37
61
  ```
38
62
 
39
- Os estilos globais (tokens, Material, AG Grid, CDK) seguem os do StructraLab; nas aplicações consumidoras importe o `styles.scss` principal do produto ou replique os `@use` de tema conforme a documentação interna.
40
-
41
63
  ## Licença
42
64
 
43
65
  MIT
package/package.json CHANGED
@@ -1,16 +1,30 @@
1
1
  {
2
2
  "name": "structra-ui",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Biblioteca de componentes Angular da StructraLab (UI reutilizável).",
5
5
  "homepage": "https://structralab.com/",
6
6
  "license": "MIT",
7
- "sideEffects": false,
7
+ "sideEffects": [
8
+ "structra-ui.css"
9
+ ],
8
10
  "files": [
9
11
  "fesm2022/",
10
12
  "types/",
13
+ "structra-ui.css",
11
14
  "README.md",
12
15
  "package.json"
13
16
  ],
17
+ "exports": {
18
+ "./structra-ui.css": "./structra-ui.css",
19
+ "./styles": "./structra-ui.css",
20
+ "./package.json": {
21
+ "default": "./package.json"
22
+ },
23
+ ".": {
24
+ "types": "./types/structra-ui.d.ts",
25
+ "default": "./fesm2022/structra-ui.mjs"
26
+ }
27
+ },
14
28
  "keywords": [
15
29
  "angular",
16
30
  "angular21",
@@ -23,27 +37,18 @@
23
37
  "peerDependencies": {
24
38
  "@angular/animations": "^21.2.7",
25
39
  "@angular/common": "^21.2.7",
40
+ "@angular/compiler": "^21.2.7",
26
41
  "@angular/core": "^21.2.7",
27
42
  "@angular/forms": "^21.2.7",
43
+ "@angular/platform-browser": "^21.2.7",
44
+ "@angular/platform-browser-dynamic": "^21.2.7",
28
45
  "@angular/router": "^21.2.7",
29
46
  "@angular/cdk": "^21.2.7",
30
47
  "@angular/material": "^21.2.7",
31
48
  "ag-grid-angular": "^35.0.0",
32
- "ag-grid-community": "^35.0.0"
33
- },
34
- "peerDependenciesMeta": {
35
- "@angular/router": {
36
- "optional": true
37
- },
38
- "@angular/material": {
39
- "optional": true
40
- },
41
- "ag-grid-angular": {
42
- "optional": true
43
- },
44
- "ag-grid-community": {
45
- "optional": true
46
- }
49
+ "ag-grid-community": "^35.0.0",
50
+ "rxjs": "^7.8.0",
51
+ "zone.js": "~0.16.0"
47
52
  },
48
53
  "dependencies": {
49
54
  "tslib": "^2.8.0"
@@ -53,14 +58,5 @@
53
58
  },
54
59
  "module": "fesm2022/structra-ui.mjs",
55
60
  "typings": "types/structra-ui.d.ts",
56
- "exports": {
57
- "./package.json": {
58
- "default": "./package.json"
59
- },
60
- ".": {
61
- "types": "./types/structra-ui.d.ts",
62
- "default": "./fesm2022/structra-ui.mjs"
63
- }
64
- },
65
61
  "type": "module"
66
62
  }
@@ -0,0 +1,939 @@
1
+ @charset "UTF-8";
2
+ /* You can add global styles to this file, and also import other style files */
3
+ @import 'ag-grid-community/styles/ag-grid.css';
4
+ @import 'ag-grid-community/styles/ag-theme-alpine.css';
5
+ @import '@angular/material/prebuilt-themes/indigo-pink.css';
6
+ /**
7
+ * Estilos dos painéis CDK Dialog (`ConfirmDialogService`, `LoadingDialogService` + `libDialogPanelClasses`).
8
+ * Importar uma vez em `styles.scss` (raiz do projecto).
9
+ */
10
+ /**
11
+ * Abertura padrão da lib: fade-in leve do painel + backdrop CDK já faz fade de opacidade;
12
+ * desfoque reforçado no mixin do scrim.
13
+ */
14
+ @keyframes app-lib-dialog-panel-in {
15
+ from {
16
+ opacity: 0;
17
+ transform: translateY(-6px) scale(0.985);
18
+ }
19
+ to {
20
+ opacity: 1;
21
+ transform: translateY(0) scale(1);
22
+ }
23
+ }
24
+ /**
25
+ * Backdrop do `app-dialog` (modal declarativo).
26
+ * Não animar `opacity` no mesmo nó que `backdrop-filter`: em Chromium o desfoque deixa de
27
+ * amostrar o conteúdo por trás e o scrim parece um painel sólido cinzento/branco.
28
+ */
29
+ @keyframes app-lib-dialog-backdrop-enter {
30
+ from {
31
+ backdrop-filter: blur(0);
32
+ -webkit-backdrop-filter: blur(0);
33
+ }
34
+ to {
35
+ backdrop-filter: blur(10px) saturate(1.05);
36
+ -webkit-backdrop-filter: blur(10px) saturate(1.05);
37
+ }
38
+ }
39
+ .cdk-overlay-pane.app-lib-dialog-panel {
40
+ box-sizing: border-box;
41
+ border-radius: 10px;
42
+ border: 1px solid var(--app-color-border-subtle, rgba(26, 47, 69, 0.12));
43
+ background: var(--app-color-surface, #fff);
44
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 12px 28px -8px rgba(26, 47, 69, 0.18);
45
+ max-height: min(88vh, 40rem);
46
+ overflow: auto;
47
+ outline: none;
48
+ animation: app-lib-dialog-panel-in 280ms cubic-bezier(0.22, 1, 0.36, 1) both;
49
+ }
50
+
51
+ @media (prefers-reduced-motion: reduce) {
52
+ .cdk-overlay-pane.app-lib-dialog-panel {
53
+ animation: none;
54
+ }
55
+ .cdk-overlay-backdrop.app-lib-dialog-backdrop {
56
+ transition: opacity 1ms;
57
+ }
58
+ }
59
+ /**
60
+ * O `cdk-dialog-container` tem `tabindex="-1"` e pode receber foco (trap / restauro).
61
+ * Sem isto, o browser desenha muitas vezes um contorno preto à volta do painel inteiro.
62
+ */
63
+ .cdk-overlay-pane.app-lib-dialog-panel .cdk-dialog-container {
64
+ outline: none;
65
+ }
66
+
67
+ .cdk-overlay-backdrop.app-lib-dialog-backdrop {
68
+ background: rgba(26, 47, 69, 0.42);
69
+ backdrop-filter: blur(10px) saturate(1.05);
70
+ -webkit-backdrop-filter: blur(10px) saturate(1.05);
71
+ transition: opacity 400ms cubic-bezier(0.25, 0.8, 0.25, 1), backdrop-filter 380ms ease-out, -webkit-backdrop-filter 380ms ease-out;
72
+ }
73
+
74
+ .cdk-overlay-backdrop.app-lib-dialog-backdrop:not(.cdk-overlay-backdrop-showing) {
75
+ backdrop-filter: blur(0);
76
+ -webkit-backdrop-filter: blur(0);
77
+ }
78
+
79
+ /**
80
+ * Tokens semânticos globais (`--app-color-*`).
81
+ * Cores de erro/validação são fixas e não devem ser sobrescritas por paletas de tema.
82
+ * Temas (`.app-library-theme.theme-*`) sobrescrevem apenas os tokens não marcados como fixos.
83
+ */
84
+ :root {
85
+ /* ——— Validação / estado (fixos, independentes do tema) ——— */
86
+ --app-color-error: #b91c1c;
87
+ --app-color-error-contrast: #ffffff;
88
+ --app-color-error-border: #dc2626;
89
+ --app-color-error-bg-subtle: rgba(185, 28, 28, 0.12);
90
+ /** Fundo da caixa do input em erro: fixo, não segue o tint da primária do tema. */
91
+ --app-color-invalid-input-bg: #fef2f2;
92
+ --app-color-validation-focus-ring: rgba(185, 28, 28, 0.45);
93
+ --app-color-success: #15803d;
94
+ --app-color-warning: #c2410c;
95
+ --app-color-info: #1d4ed8;
96
+ /* ——— Tema por omissão (azul) ——— */
97
+ --app-color-primary: #2b7fd9;
98
+ --app-color-primary-contrast: #ffffff;
99
+ --app-color-primary-muted: rgba(43, 127, 217, 0.14);
100
+ --app-color-secondary: #4a6d8c;
101
+ --app-color-secondary-contrast: #ffffff;
102
+ --app-color-surface: #ffffff;
103
+ /** Fundo da caixa flutuante dos inputs: branco com um toque muito claro da primária. */
104
+ --app-color-surface-alt: color-mix(in srgb, var(--app-color-primary) 7%, #ffffff 93%);
105
+ --app-color-background: #fafbfc;
106
+ --app-color-border: #d4d4d4;
107
+ --app-color-border-strong: #b6cce5;
108
+ --app-color-border-subtle: rgba(26, 47, 69, 0.09);
109
+ --app-color-text-primary: #1a2f45;
110
+ --app-color-text-secondary: #5a7fa3;
111
+ --app-color-text-muted: #6b8299;
112
+ --app-color-placeholder: #737373;
113
+ --app-color-focus-ring: rgba(43, 127, 217, 0.25);
114
+ --app-color-focus-ring-strong: rgba(43, 127, 217, 0.45);
115
+ --app-color-disabled-bg: #f5f5f5;
116
+ --app-color-disabled-text: #737373;
117
+ --app-color-selected-bg: rgba(43, 127, 217, 0.1);
118
+ --app-color-selected-border: #2b7fd9;
119
+ --app-color-hover-bg: rgba(43, 127, 217, 0.08);
120
+ --app-color-hover-bg-strong: rgba(43, 127, 217, 0.12);
121
+ --app-color-active-bg: rgba(43, 127, 217, 0.14);
122
+ /**
123
+ * Realce das listas dropdown (select / multiselect / combobox): ver `_field-colors.scss`
124
+ * no selector `:root, .app-library-theme` — têm de viver nesse escopo para o overlay CDK
125
+ * usar a `--app-color-primary` da paleta activa (`.theme-*`), e não a azul só herdada de `:root`.
126
+ */
127
+ /* Tabs / molduras */
128
+ --app-color-tab-inactive-bg: #f3f6f9;
129
+ --app-color-tab-inactive-border: rgba(182, 204, 229, 0.75);
130
+ --app-color-tab-inactive-text: #51667a;
131
+ --app-color-tab-hover-border: rgba(43, 127, 217, 0.42);
132
+ --app-color-tab-hover-bg: #eef3f8;
133
+ --app-color-tab-shadow: rgba(43, 127, 217, 0.14);
134
+ --app-color-shell-shadow: rgba(26, 47, 69, 0.05);
135
+ /* Navegação / app shell: ver `_field-colors.scss` (`:root, .app-library-theme`) — color-mix + tema activo. */
136
+ /* Sombras / grupos */
137
+ --app-color-elevated-shadow: rgba(43, 127, 217, 0.07);
138
+ --app-color-group-header-hover: rgba(43, 127, 217, 0.06);
139
+ /* Readonly (neutro, estável entre temas claros) */
140
+ --app-color-readonly-bg: #eceff1;
141
+ --app-color-readonly-border: #b0bec5;
142
+ --app-color-readonly-border-focus: #78909c;
143
+ --app-color-readonly-label: #607d8b;
144
+ --app-color-readonly-label-top: #455a64;
145
+ --app-color-readonly-prefix: #78909b;
146
+ --app-color-readonly-input: #37474f;
147
+ --app-color-readonly-focus-ring: rgba(120, 144, 156, 0.28);
148
+ --app-color-readonly-button-bg: #cfd8dc;
149
+ --app-color-readonly-button-border: #90a4ae;
150
+ --app-color-readonly-button-text: #37474f;
151
+ --app-color-readonly-button-focus-ring: rgba(96, 125, 139, 0.35);
152
+ /* Skeleton */
153
+ --app-color-skeleton-track: rgba(26, 47, 69, 0.09);
154
+ --app-color-skeleton-track-strong: rgba(26, 47, 69, 0.12);
155
+ --app-color-skeleton-shine: rgba(255, 255, 255, 0.22);
156
+ /* Empty state / cartão avatar */
157
+ --app-color-empty-border: rgba(26, 47, 69, 0.14);
158
+ --app-color-empty-bg: rgba(243, 246, 249, 0.55);
159
+ --app-color-avatar-gradient-start: rgba(43, 127, 217, 0.14);
160
+ --app-color-avatar-gradient-end: rgba(26, 47, 69, 0.06);
161
+ /* Secondary button hover (claro) */
162
+ --app-color-button-secondary-hover-bg: #e8f0fa;
163
+ /* Prefix genérico (float) hover clear — sem vermelho */
164
+ --app-color-prefix-hover-bg: rgba(90, 127, 163, 0.15);
165
+ /* Painéis flutuantes (dropdown, etc.) */
166
+ --app-color-overlay-shadow: rgba(0, 0, 0, 0.12);
167
+ /**
168
+ * Empilhamento para componentes montados no `document` (fora do `cdk-overlay-container`).
169
+ * Resumo de validação **pinned** acima de drawer / shell mobile / diálogo / toast — erros devem
170
+ * ficar sempre visíveis (ex.: iPhone com menu ou `app-drawer` aberto).
171
+ */
172
+ --app-z-drawer-backdrop: 1100;
173
+ --app-z-drawer-panel: 1101;
174
+ /**
175
+ * Container global do CDK Overlay: tem de ficar **acima** do drawer móvel (1101),
176
+ * senão submenus / listas ligadas ao `document` ficam por baixo do painel lateral.
177
+ */
178
+ --app-z-overlay-container: 1120;
179
+ /** Modal declarativo (`app-dialog`) e painéis CDK Dialog. */
180
+ --app-z-dialog: 1200;
181
+ /** Pilha de toasts (canto superior direito). */
182
+ --app-z-toast: 1300;
183
+ /** Acima de tudo o que listamos acima (drawer, modal, toast). */
184
+ --app-z-validation-summary-pinned: 1400;
185
+ }
186
+
187
+ /**
188
+ * Paletas aplicadas em `.app-library-theme.theme-*`.
189
+ * Não redefinir `--app-color-error*` nem tokens de validação.
190
+ */
191
+ .app-library-theme.theme-green {
192
+ --app-color-primary: #16a34a;
193
+ --app-color-surface-alt: color-mix(in srgb, var(--app-color-primary) 7%, #ffffff 93%);
194
+ --app-color-primary-muted: rgba(22, 163, 74, 0.16);
195
+ --app-color-secondary: #3d6b4f;
196
+ --app-color-border-strong: #86cba0;
197
+ --app-color-focus-ring: rgba(22, 163, 74, 0.28);
198
+ --app-color-focus-ring-strong: rgba(22, 163, 74, 0.42);
199
+ --app-color-selected-bg: rgba(22, 163, 74, 0.12);
200
+ --app-color-selected-border: #16a34a;
201
+ --app-color-hover-bg: rgba(22, 163, 74, 0.07);
202
+ --app-color-hover-bg-strong: rgba(22, 163, 74, 0.12);
203
+ --app-color-active-bg: rgba(22, 163, 74, 0.16);
204
+ --app-color-tab-hover-border: rgba(22, 163, 74, 0.45);
205
+ --app-color-tab-shadow: rgba(22, 163, 74, 0.16);
206
+ --app-color-elevated-shadow: rgba(22, 163, 74, 0.09);
207
+ --app-color-group-header-hover: rgba(22, 163, 74, 0.07);
208
+ --app-color-text-secondary: #3f6b52;
209
+ --app-color-tab-inactive-text: #4a6356;
210
+ --app-color-tab-hover-bg: #ecfdf3;
211
+ --app-color-button-secondary-hover-bg: #dff7e8;
212
+ --app-color-prefix-hover-bg: rgba(63, 107, 82, 0.14);
213
+ --app-color-avatar-gradient-start: rgba(22, 163, 74, 0.18);
214
+ --app-color-avatar-gradient-end: rgba(26, 47, 69, 0.06);
215
+ }
216
+
217
+ .app-library-theme.theme-purple {
218
+ --app-color-primary: #7c3aed;
219
+ --app-color-surface-alt: color-mix(in srgb, var(--app-color-primary) 7%, #ffffff 93%);
220
+ --app-color-primary-muted: rgba(124, 58, 237, 0.16);
221
+ --app-color-secondary: #5b21b6;
222
+ --app-color-border-strong: #c4b5fd;
223
+ --app-color-focus-ring: rgba(124, 58, 237, 0.28);
224
+ --app-color-focus-ring-strong: rgba(124, 58, 237, 0.42);
225
+ --app-color-selected-bg: rgba(124, 58, 237, 0.12);
226
+ --app-color-selected-border: #7c3aed;
227
+ --app-color-hover-bg: rgba(124, 58, 237, 0.08);
228
+ --app-color-hover-bg-strong: rgba(124, 58, 237, 0.14);
229
+ --app-color-active-bg: rgba(124, 58, 237, 0.18);
230
+ --app-color-tab-hover-border: rgba(124, 58, 237, 0.45);
231
+ --app-color-tab-shadow: rgba(124, 58, 237, 0.18);
232
+ --app-color-elevated-shadow: rgba(124, 58, 237, 0.1);
233
+ --app-color-group-header-hover: rgba(124, 58, 237, 0.08);
234
+ --app-color-text-secondary: #6d5a9c;
235
+ --app-color-tab-inactive-text: #5c5678;
236
+ --app-color-tab-hover-bg: #f5f3ff;
237
+ --app-color-button-secondary-hover-bg: #ede9fe;
238
+ --app-color-prefix-hover-bg: rgba(109, 90, 156, 0.14);
239
+ --app-color-avatar-gradient-start: rgba(124, 58, 237, 0.2);
240
+ --app-color-avatar-gradient-end: rgba(26, 47, 69, 0.06);
241
+ }
242
+
243
+ .app-library-theme.theme-orange {
244
+ --app-color-primary: #ea580c;
245
+ --app-color-surface-alt: color-mix(in srgb, var(--app-color-primary) 7%, #ffffff 93%);
246
+ --app-color-primary-muted: rgba(234, 88, 12, 0.16);
247
+ --app-color-secondary: #9a3412;
248
+ --app-color-border-strong: #fdba74;
249
+ --app-color-focus-ring: rgba(234, 88, 12, 0.28);
250
+ --app-color-focus-ring-strong: rgba(234, 88, 12, 0.42);
251
+ --app-color-selected-bg: rgba(234, 88, 12, 0.1);
252
+ --app-color-selected-border: #ea580c;
253
+ --app-color-hover-bg: rgba(234, 88, 12, 0.07);
254
+ --app-color-hover-bg-strong: rgba(234, 88, 12, 0.12);
255
+ --app-color-active-bg: rgba(234, 88, 12, 0.16);
256
+ --app-color-tab-hover-border: rgba(234, 88, 12, 0.45);
257
+ --app-color-tab-shadow: rgba(234, 88, 12, 0.16);
258
+ --app-color-elevated-shadow: rgba(234, 88, 12, 0.09);
259
+ --app-color-group-header-hover: rgba(234, 88, 12, 0.07);
260
+ --app-color-text-secondary: #a16207;
261
+ --app-color-tab-inactive-text: #6b5c4e;
262
+ --app-color-tab-hover-bg: #fff7ed;
263
+ --app-color-button-secondary-hover-bg: #ffedd5;
264
+ --app-color-prefix-hover-bg: rgba(154, 52, 18, 0.12);
265
+ --app-color-avatar-gradient-start: rgba(234, 88, 12, 0.2);
266
+ --app-color-avatar-gradient-end: rgba(26, 47, 69, 0.06);
267
+ }
268
+
269
+ /**
270
+ * Tema «Branco»: UI muito clara, acento cinza-azulado suave (contraste baixo mas legível).
271
+ */
272
+ .app-library-theme.theme-white {
273
+ --app-color-primary: #64748b;
274
+ --app-color-primary-contrast: #ffffff;
275
+ --app-color-primary-muted: rgba(100, 116, 139, 0.14);
276
+ --app-color-secondary: #475569;
277
+ --app-color-secondary-contrast: #ffffff;
278
+ --app-color-surface: #ffffff;
279
+ --app-color-surface-alt: #f8fafc;
280
+ --app-color-background: #fcfcfd;
281
+ --app-color-border: #e2e8f0;
282
+ --app-color-border-strong: #cbd5e1;
283
+ --app-color-border-subtle: rgba(71, 85, 105, 0.08);
284
+ --app-color-text-primary: #1e293b;
285
+ --app-color-text-secondary: #64748b;
286
+ --app-color-text-muted: #94a3b8;
287
+ --app-color-placeholder: #94a3b8;
288
+ --app-color-focus-ring: rgba(100, 116, 139, 0.28);
289
+ --app-color-focus-ring-strong: rgba(100, 116, 139, 0.42);
290
+ --app-color-disabled-bg: #f1f5f9;
291
+ --app-color-disabled-text: #cbd5e1;
292
+ --app-color-selected-bg: rgba(100, 116, 139, 0.1);
293
+ --app-color-selected-border: #64748b;
294
+ --app-color-hover-bg: rgba(100, 116, 139, 0.06);
295
+ --app-color-hover-bg-strong: rgba(100, 116, 139, 0.11);
296
+ --app-color-active-bg: rgba(100, 116, 139, 0.14);
297
+ --app-color-tab-inactive-bg: #f8fafc;
298
+ --app-color-tab-inactive-border: #e2e8f0;
299
+ --app-color-tab-inactive-text: #64748b;
300
+ --app-color-tab-hover-border: rgba(100, 116, 139, 0.35);
301
+ --app-color-tab-hover-bg: #f1f5f9;
302
+ --app-color-tab-shadow: rgba(100, 116, 139, 0.1);
303
+ --app-color-shell-shadow: rgba(30, 41, 59, 0.05);
304
+ --app-color-elevated-shadow: rgba(30, 41, 59, 0.07);
305
+ --app-color-group-header-hover: rgba(100, 116, 139, 0.05);
306
+ --app-color-readonly-bg: #f1f5f9;
307
+ --app-color-readonly-border: #cbd5e1;
308
+ --app-color-readonly-border-focus: #94a3b8;
309
+ --app-color-readonly-label: #64748b;
310
+ --app-color-readonly-label-top: #475569;
311
+ --app-color-readonly-prefix: #94a3b8;
312
+ --app-color-readonly-input: #334155;
313
+ --app-color-readonly-focus-ring: rgba(100, 116, 139, 0.28);
314
+ --app-color-readonly-button-bg: #e2e8f0;
315
+ --app-color-readonly-button-border: #cbd5e1;
316
+ --app-color-readonly-button-text: #334155;
317
+ --app-color-readonly-button-focus-ring: rgba(71, 85, 105, 0.32);
318
+ --app-color-skeleton-track: rgba(100, 116, 139, 0.08);
319
+ --app-color-skeleton-track-strong: rgba(100, 116, 139, 0.12);
320
+ --app-color-skeleton-shine: rgba(255, 255, 255, 0.35);
321
+ --app-color-empty-border: rgba(100, 116, 139, 0.12);
322
+ --app-color-empty-bg: rgba(248, 250, 252, 0.9);
323
+ --app-color-avatar-gradient-start: rgba(100, 116, 139, 0.12);
324
+ --app-color-avatar-gradient-end: rgba(30, 41, 59, 0.05);
325
+ --app-color-button-secondary-hover-bg: #e2e8f0;
326
+ --app-color-prefix-hover-bg: rgba(71, 85, 105, 0.12);
327
+ --app-color-overlay-shadow: rgba(15, 23, 42, 0.12);
328
+ }
329
+
330
+ /**
331
+ * Tema «Cinza»: monocromático neutro, acento zinc/slate.
332
+ */
333
+ .app-library-theme.theme-gray {
334
+ --app-color-primary: #52525b;
335
+ --app-color-primary-contrast: #ffffff;
336
+ --app-color-primary-muted: rgba(82, 82, 91, 0.14);
337
+ --app-color-secondary: #3f3f46;
338
+ --app-color-secondary-contrast: #ffffff;
339
+ --app-color-surface: #fafafa;
340
+ --app-color-surface-alt: #f4f4f5;
341
+ --app-color-background: #f4f4f5;
342
+ --app-color-border: #d4d4d8;
343
+ --app-color-border-strong: #a1a1aa;
344
+ --app-color-border-subtle: rgba(39, 39, 42, 0.09);
345
+ --app-color-text-primary: #18181b;
346
+ --app-color-text-secondary: #52525b;
347
+ --app-color-text-muted: #71717a;
348
+ --app-color-placeholder: #a1a1aa;
349
+ --app-color-focus-ring: rgba(82, 82, 91, 0.28);
350
+ --app-color-focus-ring-strong: rgba(82, 82, 91, 0.42);
351
+ --app-color-disabled-bg: #f4f4f5;
352
+ --app-color-disabled-text: #a1a1aa;
353
+ --app-color-selected-bg: rgba(82, 82, 91, 0.1);
354
+ --app-color-selected-border: #52525b;
355
+ --app-color-hover-bg: rgba(82, 82, 91, 0.07);
356
+ --app-color-hover-bg-strong: rgba(82, 82, 91, 0.12);
357
+ --app-color-active-bg: rgba(82, 82, 91, 0.16);
358
+ --app-color-tab-inactive-bg: #f4f4f5;
359
+ --app-color-tab-inactive-border: #e4e4e7;
360
+ --app-color-tab-inactive-text: #52525b;
361
+ --app-color-tab-hover-border: rgba(82, 82, 91, 0.35);
362
+ --app-color-tab-hover-bg: #e4e4e7;
363
+ --app-color-tab-shadow: rgba(24, 24, 27, 0.1);
364
+ --app-color-shell-shadow: rgba(24, 24, 27, 0.06);
365
+ --app-color-elevated-shadow: rgba(24, 24, 27, 0.08);
366
+ --app-color-group-header-hover: rgba(82, 82, 91, 0.06);
367
+ --app-color-readonly-bg: #e4e4e7;
368
+ --app-color-readonly-border: #a1a1aa;
369
+ --app-color-readonly-border-focus: #71717a;
370
+ --app-color-readonly-label: #52525b;
371
+ --app-color-readonly-label-top: #3f3f46;
372
+ --app-color-readonly-prefix: #71717a;
373
+ --app-color-readonly-input: #27272a;
374
+ --app-color-readonly-focus-ring: rgba(113, 113, 122, 0.28);
375
+ --app-color-readonly-button-bg: #d4d4d8;
376
+ --app-color-readonly-button-border: #a1a1aa;
377
+ --app-color-readonly-button-text: #27272a;
378
+ --app-color-readonly-button-focus-ring: rgba(63, 63, 70, 0.32);
379
+ --app-color-skeleton-track: rgba(82, 82, 91, 0.09);
380
+ --app-color-skeleton-track-strong: rgba(82, 82, 91, 0.13);
381
+ --app-color-skeleton-shine: rgba(255, 255, 255, 0.28);
382
+ --app-color-empty-border: rgba(82, 82, 91, 0.14);
383
+ --app-color-empty-bg: rgba(244, 244, 245, 0.92);
384
+ --app-color-avatar-gradient-start: rgba(82, 82, 91, 0.14);
385
+ --app-color-avatar-gradient-end: rgba(24, 24, 27, 0.06);
386
+ --app-color-button-secondary-hover-bg: #e4e4e7;
387
+ --app-color-prefix-hover-bg: rgba(63, 63, 70, 0.12);
388
+ --app-color-overlay-shadow: rgba(0, 0, 0, 0.16);
389
+ }
390
+
391
+ /**
392
+ * Tema «Sépia»: papel quente, texto e bordas terrosas.
393
+ */
394
+ .app-library-theme.theme-sepia {
395
+ --app-color-primary: #8d6e4b;
396
+ --app-color-primary-contrast: #fffef8;
397
+ --app-color-primary-muted: rgba(141, 110, 75, 0.18);
398
+ --app-color-secondary: #6b5344;
399
+ --app-color-secondary-contrast: #fffef8;
400
+ --app-color-surface: #fffef8;
401
+ --app-color-surface-alt: #faf6ed;
402
+ --app-color-background: #f4efe6;
403
+ --app-color-border: #e5d9c8;
404
+ --app-color-border-strong: #cbb89a;
405
+ --app-color-border-subtle: rgba(61, 48, 40, 0.1);
406
+ --app-color-text-primary: #3d3428;
407
+ --app-color-text-secondary: #6b5a48;
408
+ --app-color-text-muted: #8a7a66;
409
+ --app-color-placeholder: #a89884;
410
+ --app-color-focus-ring: rgba(141, 110, 75, 0.35);
411
+ --app-color-focus-ring-strong: rgba(141, 110, 75, 0.48);
412
+ --app-color-disabled-bg: #f0ebe3;
413
+ --app-color-disabled-text: #b5a896;
414
+ --app-color-selected-bg: rgba(141, 110, 75, 0.12);
415
+ --app-color-selected-border: #8d6e4b;
416
+ --app-color-hover-bg: rgba(141, 110, 75, 0.08);
417
+ --app-color-hover-bg-strong: rgba(141, 110, 75, 0.14);
418
+ --app-color-active-bg: rgba(141, 110, 75, 0.18);
419
+ --app-color-tab-inactive-bg: #faf6ed;
420
+ --app-color-tab-inactive-border: #e8dcc8;
421
+ --app-color-tab-inactive-text: #6b5a48;
422
+ --app-color-tab-hover-border: rgba(141, 110, 75, 0.42);
423
+ --app-color-tab-hover-bg: #f2ebe0;
424
+ --app-color-tab-shadow: rgba(61, 48, 40, 0.12);
425
+ --app-color-shell-shadow: rgba(61, 48, 40, 0.07);
426
+ --app-color-elevated-shadow: rgba(61, 48, 40, 0.1);
427
+ --app-color-group-header-hover: rgba(141, 110, 75, 0.07);
428
+ --app-color-readonly-bg: #efe8dc;
429
+ --app-color-readonly-border: #cbb89a;
430
+ --app-color-readonly-border-focus: #a89884;
431
+ --app-color-readonly-label: #6b5a48;
432
+ --app-color-readonly-label-top: #4a3f35;
433
+ --app-color-readonly-prefix: #8a7a66;
434
+ --app-color-readonly-input: #3d3428;
435
+ --app-color-readonly-focus-ring: rgba(141, 110, 75, 0.32);
436
+ --app-color-readonly-button-bg: #e5d9c8;
437
+ --app-color-readonly-button-border: #cbb89a;
438
+ --app-color-readonly-button-text: #3d3428;
439
+ --app-color-readonly-button-focus-ring: rgba(107, 90, 72, 0.35);
440
+ --app-color-skeleton-track: rgba(141, 110, 75, 0.1);
441
+ --app-color-skeleton-track-strong: rgba(141, 110, 75, 0.14);
442
+ --app-color-skeleton-shine: rgba(255, 254, 248, 0.45);
443
+ --app-color-empty-border: rgba(141, 110, 75, 0.18);
444
+ --app-color-empty-bg: rgba(250, 246, 237, 0.92);
445
+ --app-color-avatar-gradient-start: rgba(141, 110, 75, 0.16);
446
+ --app-color-avatar-gradient-end: rgba(61, 48, 40, 0.06);
447
+ --app-color-button-secondary-hover-bg: #ebe2d4;
448
+ --app-color-prefix-hover-bg: rgba(107, 90, 72, 0.14);
449
+ --app-color-overlay-shadow: rgba(45, 35, 28, 0.18);
450
+ }
451
+
452
+ /**
453
+ * Tema «Preto»: acento quase preto em UI **clara** (superfície branca como nos outros temas).
454
+ * O fundo geral da página / modo escuro fica a cargo do browser (`prefers-color-scheme`), não desta paleta.
455
+ */
456
+ .app-library-theme.theme-black {
457
+ --app-color-primary: #111827;
458
+ --app-color-primary-contrast: #ffffff;
459
+ --app-color-primary-muted: rgba(17, 24, 39, 0.12);
460
+ --app-color-secondary: #374151;
461
+ --app-color-secondary-contrast: #ffffff;
462
+ --app-color-surface: #ffffff;
463
+ --app-color-surface-alt: color-mix(in srgb, var(--app-color-primary) 7%, #ffffff 93%);
464
+ --app-color-background: #fafbfc;
465
+ --app-color-border: #d1d5db;
466
+ --app-color-border-strong: #9ca3af;
467
+ --app-color-border-subtle: rgba(17, 24, 39, 0.08);
468
+ --app-color-text-primary: #111827;
469
+ --app-color-text-secondary: #4b5563;
470
+ --app-color-text-muted: #6b7280;
471
+ --app-color-placeholder: #9ca3af;
472
+ --app-color-focus-ring: rgba(17, 24, 39, 0.22);
473
+ --app-color-focus-ring-strong: rgba(17, 24, 39, 0.38);
474
+ --app-color-disabled-bg: #f3f4f6;
475
+ --app-color-disabled-text: #9ca3af;
476
+ --app-color-selected-bg: rgba(17, 24, 39, 0.08);
477
+ --app-color-selected-border: #111827;
478
+ --app-color-hover-bg: rgba(17, 24, 39, 0.05);
479
+ --app-color-hover-bg-strong: rgba(17, 24, 39, 0.1);
480
+ --app-color-active-bg: rgba(17, 24, 39, 0.14);
481
+ --app-color-tab-inactive-bg: #f3f4f6;
482
+ --app-color-tab-inactive-border: #e5e7eb;
483
+ --app-color-tab-inactive-text: #4b5563;
484
+ --app-color-tab-hover-border: rgba(17, 24, 39, 0.28);
485
+ --app-color-tab-hover-bg: #eceff2;
486
+ --app-color-tab-shadow: rgba(17, 24, 39, 0.1);
487
+ --app-color-shell-shadow: rgba(17, 24, 39, 0.06);
488
+ --app-color-elevated-shadow: rgba(17, 24, 39, 0.08);
489
+ --app-color-group-header-hover: rgba(17, 24, 39, 0.05);
490
+ --app-color-readonly-bg: #eceff1;
491
+ --app-color-readonly-border: #b0bec5;
492
+ --app-color-readonly-border-focus: #78909c;
493
+ --app-color-readonly-label: #607d8b;
494
+ --app-color-readonly-label-top: #455a64;
495
+ --app-color-readonly-prefix: #78909b;
496
+ --app-color-readonly-input: #37474f;
497
+ --app-color-readonly-focus-ring: rgba(120, 144, 156, 0.28);
498
+ --app-color-readonly-button-bg: #cfd8dc;
499
+ --app-color-readonly-button-border: #90a4ae;
500
+ --app-color-readonly-button-text: #37474f;
501
+ --app-color-readonly-button-focus-ring: rgba(96, 125, 139, 0.35);
502
+ --app-color-skeleton-track: rgba(17, 24, 39, 0.08);
503
+ --app-color-skeleton-track-strong: rgba(17, 24, 39, 0.11);
504
+ --app-color-skeleton-shine: rgba(255, 255, 255, 0.22);
505
+ --app-color-empty-border: rgba(17, 24, 39, 0.12);
506
+ --app-color-empty-bg: rgba(243, 244, 246, 0.85);
507
+ --app-color-avatar-gradient-start: rgba(17, 24, 39, 0.12);
508
+ --app-color-avatar-gradient-end: rgba(17, 24, 39, 0.05);
509
+ --app-color-button-secondary-hover-bg: #e5e7eb;
510
+ --app-color-prefix-hover-bg: rgba(75, 85, 99, 0.12);
511
+ --app-color-overlay-shadow: rgba(0, 0, 0, 0.14);
512
+ }
513
+
514
+ /**
515
+ * Ponte: tokens de implementação dos campos (`--ui-field-*`) → tokens semânticos (`--app-color-*`).
516
+ * `:root` mantém compatibilidade quando não há `.app-library-theme`; com o host tematizado,
517
+ * `var(--app-color-*)` resolve nos valores herdados do tema activo.
518
+ */
519
+ :root,
520
+ .app-library-theme {
521
+ --ui-field-float-bg: var(--app-color-surface-alt);
522
+ --ui-field-float-border: var(--app-color-border-strong);
523
+ --ui-field-float-border-focus: var(--app-color-primary);
524
+ --ui-field-float-border-radius: 14px;
525
+ --ui-field-float-label-color: var(--app-color-text-secondary);
526
+ --ui-field-float-label-top-color: var(--app-color-secondary);
527
+ --ui-field-float-label-invalid-color: var(--app-color-error);
528
+ --ui-field-float-input-text: var(--app-color-text-primary);
529
+ --ui-field-float-prefix-color: var(--app-color-text-secondary);
530
+ --ui-field-float-focus-ring: var(--app-color-focus-ring);
531
+ /**
532
+ * Listas dropdown (overlay CDK): `color-mix` com primária/texto aqui para resolver no mesmo
533
+ * elemento que `.app-library-theme.theme-*` (evita realce azul quando o tema é roxo, verde, …).
534
+ */
535
+ --app-color-dropdown-option-selected-bg: color-mix(in srgb, var(--app-color-primary) 12%, #ffffff 88%);
536
+ --app-color-dropdown-option-selected-bg-active: color-mix(
537
+ in srgb,
538
+ var(--app-color-primary) 18%,
539
+ #ffffff 82%
540
+ );
541
+ --app-color-dropdown-option-selected-hover-bg: color-mix(
542
+ in srgb,
543
+ var(--app-color-primary) 16%,
544
+ #ffffff 84%
545
+ );
546
+ /**
547
+ * Navegação por setas / hover: mais tint da primária que o fundo do painel (`surface-alt` ~7%)
548
+ * para o realce ser claramente visível sobre `--ui-field-float-bg`.
549
+ */
550
+ --app-color-dropdown-option-highlight-bg: color-mix(in srgb, var(--app-color-primary) 16%, #ffffff 84%);
551
+ --app-color-dropdown-option-hover-bg: color-mix(in srgb, var(--app-color-primary) 13%, #ffffff 87%);
552
+ --ui-field-input-border: var(--app-color-border);
553
+ --ui-field-input-border-radius: 6px;
554
+ --ui-field-input-bg: var(--app-color-surface);
555
+ --ui-field-input-color: var(--app-color-text-primary);
556
+ --ui-field-input-placeholder: var(--app-color-placeholder);
557
+ --ui-field-input-focus-ring: var(--app-color-primary);
558
+ --ui-field-input-focus-ring-width: 2px;
559
+ --ui-field-input-invalid-border: var(--app-color-error-border);
560
+ --ui-field-input-invalid-placeholder: var(--app-color-error);
561
+ --ui-field-input-invalid-focus-ring: var(--app-color-error);
562
+ --ui-field-input-invalid-focus-halo: var(--app-color-error-bg-subtle);
563
+ --ui-field-invalid-input-bg: var(--app-color-invalid-input-bg);
564
+ --ui-field-input-disabled-bg: var(--app-color-disabled-bg);
565
+ --ui-field-input-disabled-opacity: 0.65;
566
+ --ui-field-label-color: var(--app-color-text-primary);
567
+ --ui-field-required-mark-color: var(--app-color-error);
568
+ --ui-field-error-text-color: var(--app-color-error);
569
+ --ui-field-datepicker-selected-bg: var(--app-color-primary);
570
+ --ui-field-datepicker-selected-fg: var(--app-color-primary-contrast);
571
+ --ui-field-datepicker-today-outline: var(--app-color-primary);
572
+ --ui-field-datepicker-nav-icon: var(--app-color-primary);
573
+ --ui-field-datepicker-period-icon: var(--app-color-secondary);
574
+ --ui-field-datepicker-hover-bg: var(--app-color-hover-bg-strong);
575
+ --ui-field-datepicker-focus-bg: var(--app-color-hover-bg-strong);
576
+ --ui-field-readonly-bg: var(--app-color-readonly-bg);
577
+ --ui-field-readonly-border: var(--app-color-readonly-border);
578
+ --ui-field-readonly-border-focus: var(--app-color-readonly-border-focus);
579
+ --ui-field-readonly-label-color: var(--app-color-readonly-label);
580
+ --ui-field-readonly-label-top-color: var(--app-color-readonly-label-top);
581
+ --ui-field-readonly-prefix-color: var(--app-color-readonly-prefix);
582
+ --ui-field-readonly-input-text: var(--app-color-readonly-input);
583
+ --ui-field-readonly-focus-ring: var(--app-color-readonly-focus-ring);
584
+ --ui-field-readonly-button-bg: var(--app-color-readonly-button-bg);
585
+ --ui-field-readonly-button-border: var(--app-color-readonly-button-border);
586
+ --ui-field-readonly-button-text: var(--app-color-readonly-button-text);
587
+ --ui-field-readonly-button-focus-ring: var(--app-color-readonly-button-focus-ring);
588
+ --ui-form-actions-divider-color: var(--app-color-border);
589
+ --ui-form-group-chevron-locked: var(--app-color-text-muted);
590
+ /**
591
+ * App shell / sidebar / docs: fundo branco como a área principal; o acento fica só no item
592
+ * selecionado/hover (tokens `--app-color-nav-*` / primária). Igual ao drawer mobile.
593
+ */
594
+ --app-color-nav-shell-bg: var(--app-color-surface);
595
+ --app-color-nav-surface: #ffffff;
596
+ --app-color-nav-card-border: color-mix(in srgb, var(--app-color-primary) 32%, #ffffff);
597
+ --app-color-nav-border-subtle: color-mix(in srgb, var(--app-color-primary) 18%, #ffffff);
598
+ --app-color-nav-group-label: var(--app-color-text-muted);
599
+ --app-color-nav-item-text: var(--app-color-text-primary);
600
+ --app-color-nav-icon: var(--app-color-text-secondary);
601
+ --app-color-nav-selected-bg: var(--app-color-selected-bg);
602
+ --app-color-nav-selected-border: var(--app-color-selected-border);
603
+ --app-color-nav-selected-text: var(--app-color-primary);
604
+ --app-color-nav-hover-bg: var(--app-color-hover-bg);
605
+ --app-color-nav-link: var(--app-color-primary);
606
+ --app-color-nav-focus-ring: var(--app-color-focus-ring-strong);
607
+ --app-color-shell-main-bg: var(--app-color-surface);
608
+ }
609
+
610
+ /**
611
+ * Tema do overlay do `MatDatepicker` alinhado às variáveis `--ui-field-*`.
612
+ * O `panelClass` do Angular Material é aplicado no host `mat-calendar`.
613
+ */
614
+ .mat-calendar.ui-field-datepicker-panel {
615
+ --mat-datepicker-calendar-date-selected-state-text-color: var(
616
+ --ui-field-datepicker-selected-fg
617
+ );
618
+ --mat-datepicker-calendar-date-selected-state-background-color: var(
619
+ --ui-field-datepicker-selected-bg
620
+ );
621
+ --mat-datepicker-calendar-date-selected-disabled-state-background-color: color-mix(
622
+ in srgb,
623
+ var(--ui-field-datepicker-selected-bg) 45%,
624
+ transparent
625
+ );
626
+ --mat-datepicker-calendar-date-today-outline-color: var(--ui-field-datepicker-today-outline);
627
+ --mat-datepicker-calendar-date-today-disabled-state-outline-color: var(
628
+ --ui-field-float-border
629
+ );
630
+ --mat-datepicker-calendar-date-today-selected-state-outline-color: var(
631
+ --ui-field-datepicker-selected-fg
632
+ );
633
+ --mat-datepicker-calendar-date-focus-state-background-color: var(
634
+ --ui-field-datepicker-focus-bg
635
+ );
636
+ --mat-datepicker-calendar-date-hover-state-background-color: var(
637
+ --ui-field-datepicker-hover-bg
638
+ );
639
+ --mat-datepicker-calendar-navigation-button-icon-color: var(--ui-field-datepicker-nav-icon);
640
+ --mat-datepicker-calendar-period-button-icon-color: var(--ui-field-datepicker-period-icon);
641
+ --mat-datepicker-calendar-toggle-active-state-icon-color: var(--ui-field-datepicker-nav-icon);
642
+ --mat-datepicker-calendar-date-in-range-state-background-color: var(
643
+ --ui-field-datepicker-hover-bg
644
+ );
645
+ }
646
+ .mat-calendar.ui-field-datepicker-panel .mat-calendar-controls .mat-mdc-icon-button.mat-mdc-button-base {
647
+ --mat-icon-button-icon-color: var(--ui-field-datepicker-nav-icon);
648
+ --mat-icon-button-state-layer-color: var(--ui-field-datepicker-nav-icon);
649
+ }
650
+
651
+ /**
652
+ * Superfície única de navegação (documentação + demo App shell):
653
+ * brand, scroll, seções, links e `app-menu-list` sem cartão duplicado.
654
+ */
655
+ .app-nav-surface {
656
+ display: flex;
657
+ flex-direction: column;
658
+ min-height: 0;
659
+ box-sizing: border-box;
660
+ }
661
+
662
+ .app-nav-surface__brand {
663
+ flex: 0 0 auto;
664
+ display: block;
665
+ margin: 0 0 1rem;
666
+ font-size: 0.95rem;
667
+ font-weight: 700;
668
+ line-height: 1.3;
669
+ color: var(--app-color-text-primary, #1a2f45);
670
+ text-decoration: none;
671
+ white-space: nowrap;
672
+ overflow: hidden;
673
+ text-overflow: ellipsis;
674
+ }
675
+ .app-nav-surface__brand:hover {
676
+ color: var(--app-color-nav-link);
677
+ }
678
+
679
+ .app-nav-surface__scroll {
680
+ flex: 1 1 auto;
681
+ min-height: 0;
682
+ overflow-x: hidden;
683
+ overflow-y: auto;
684
+ -webkit-overflow-scrolling: touch;
685
+ display: flex;
686
+ flex-direction: column;
687
+ gap: 0;
688
+ padding: 0.15rem 0 0.35rem;
689
+ background: transparent;
690
+ border: none;
691
+ border-radius: 0;
692
+ box-sizing: border-box;
693
+ }
694
+
695
+ .app-nav-surface__section {
696
+ flex: 0 0 auto;
697
+ min-width: 0;
698
+ margin: 0;
699
+ padding: 0.75rem 0 0.5rem;
700
+ border-top: 1px solid var(--app-color-border-subtle, rgba(26, 47, 69, 0.08));
701
+ }
702
+ .app-nav-surface__section:first-of-type {
703
+ border-top: none;
704
+ padding-top: 0.35rem;
705
+ }
706
+
707
+ .app-nav-surface__section-title {
708
+ margin: 0 0 0.5rem;
709
+ padding: 0 0.1rem;
710
+ font-size: 0.74rem;
711
+ font-weight: 600;
712
+ letter-spacing: 0.02em;
713
+ text-transform: none;
714
+ color: var(--app-color-text-secondary, #5a7fa3);
715
+ white-space: nowrap;
716
+ overflow: hidden;
717
+ text-overflow: ellipsis;
718
+ }
719
+
720
+ .app-nav-surface__list {
721
+ margin: 0;
722
+ padding: 0;
723
+ list-style: none;
724
+ }
725
+
726
+ .app-nav-surface__list li + li {
727
+ margin-top: 0.08rem;
728
+ }
729
+
730
+ .app-nav-surface__link {
731
+ display: block;
732
+ box-sizing: border-box;
733
+ padding: 0.52rem 0.55rem;
734
+ border: 1px solid transparent;
735
+ border-radius: 8px;
736
+ font-size: 0.93rem;
737
+ color: var(--app-color-text-primary, #1a2f45);
738
+ text-decoration: none;
739
+ line-height: 1.35;
740
+ white-space: nowrap;
741
+ overflow: hidden;
742
+ text-overflow: ellipsis;
743
+ }
744
+ .app-nav-surface__link:hover {
745
+ background: var(--app-color-nav-hover-bg);
746
+ color: var(--app-color-nav-selected-text);
747
+ }
748
+ .app-nav-surface__link:focus-visible {
749
+ outline: 2px solid var(--app-color-nav-focus-ring);
750
+ outline-offset: 1px;
751
+ }
752
+
753
+ .app-nav-surface__link--active {
754
+ font-weight: 600;
755
+ color: var(--app-color-primary, #2b7fd9);
756
+ background: color-mix(in srgb, var(--app-color-primary) 9%, transparent);
757
+ border: 1px solid transparent;
758
+ box-shadow: inset 3px 0 0 0 var(--app-color-primary, #2b7fd9);
759
+ }
760
+
761
+ /* `app-menu-list` na shell: mesma linguagem, sem cartão nem sombra de dropdown. */
762
+ .app-nav-surface app-menu-list .menu-list {
763
+ background: transparent;
764
+ border: none;
765
+ border-radius: 0;
766
+ box-shadow: none;
767
+ max-height: none;
768
+ overflow-x: hidden;
769
+ overflow-y: visible;
770
+ padding: 0.15rem 0 0.35rem;
771
+ gap: 0.08rem;
772
+ }
773
+
774
+ .app-nav-surface app-menu-list .menu-list--dense {
775
+ padding: 0.12rem 0;
776
+ gap: 0;
777
+ }
778
+
779
+ .app-nav-surface app-menu-list .menu-list__group-label {
780
+ font-size: 0.74rem;
781
+ font-weight: 600;
782
+ letter-spacing: 0.02em;
783
+ text-transform: none;
784
+ color: var(--app-color-text-secondary, #5a7fa3);
785
+ padding: 0.75rem 0.55rem 0.5rem;
786
+ margin-top: 0.35rem;
787
+ border-top: 1px solid var(--app-color-border-subtle, rgba(26, 47, 69, 0.08));
788
+ }
789
+
790
+ .app-nav-surface app-menu-list .menu-list > app-menu-group:first-of-type .menu-list__group-label {
791
+ margin-top: 0;
792
+ padding-top: 0.35rem;
793
+ border-top: none;
794
+ }
795
+
796
+ .app-nav-surface app-menu-list .menu-list__label {
797
+ color: var(--app-color-nav-item-text);
798
+ }
799
+
800
+ .app-nav-surface app-menu-list .menu-list__icon {
801
+ color: var(--app-color-nav-icon);
802
+ }
803
+
804
+ .app-nav-surface app-menu-list .menu-list__submenu-chevron {
805
+ color: var(--app-color-nav-icon);
806
+ }
807
+
808
+ .app-nav-surface app-menu-list .menu-list__option:hover:not(.menu-list__option--disabled):not(.menu-list__option--loading) {
809
+ background: var(--app-color-nav-hover-bg);
810
+ }
811
+
812
+ .app-nav-surface app-menu-list .menu-list__option.menu-list__option--active:not(.menu-list__option--selected):not(.menu-list__option--disabled):not(.menu-list__option--loading) {
813
+ background: var(--app-color-nav-hover-bg);
814
+ border-color: transparent;
815
+ box-shadow: none;
816
+ }
817
+
818
+ .app-nav-surface app-menu-list .menu-list__option--selected:not(.menu-list__option--disabled) {
819
+ background: color-mix(in srgb, var(--app-color-primary) 9%, transparent);
820
+ box-shadow: inset 3px 0 0 0 var(--app-color-primary, #2b7fd9);
821
+ border-radius: 8px;
822
+ border: 1px solid transparent;
823
+ }
824
+
825
+ .app-nav-surface app-menu-list .menu-list__option--selected:not(.menu-list__option--disabled) .menu-list__label {
826
+ color: var(--app-color-primary, #2b7fd9);
827
+ font-weight: 600;
828
+ }
829
+
830
+ .app-nav-surface app-menu-list .menu-list__option--selected:not(.menu-list__option--disabled) .menu-list__icon {
831
+ color: var(--app-color-primary, #2b7fd9);
832
+ }
833
+
834
+ .app-nav-surface app-menu-list .menu-list__option:focus-visible {
835
+ outline: 2px solid var(--app-color-nav-focus-ring);
836
+ outline-offset: 1px;
837
+ }
838
+
839
+ /* Demo / shell com texto comprimido: ícones centrados, sem “caixa” permanente. */
840
+ .app-nav-surface app-menu-list .menu-list--compress-text {
841
+ gap: 0.1rem;
842
+ }
843
+
844
+ .app-nav-surface app-menu-list .menu-list--compress-text .menu-list__option {
845
+ border-radius: 8px;
846
+ border-color: transparent;
847
+ }
848
+
849
+ .app-nav-surface app-menu-list .menu-list--compress-text .menu-list__option.menu-list__option--active:not(.menu-list__option--selected):not(.menu-list__option--disabled):not(.menu-list__option--loading) {
850
+ background: color-mix(in srgb, var(--app-color-primary) 5%, transparent);
851
+ border-color: transparent;
852
+ box-shadow: none;
853
+ }
854
+
855
+ @media (max-width: 52rem) {
856
+ .app-nav-surface__brand {
857
+ margin: 0.25rem 0 0.85rem;
858
+ font-size: 1.08rem;
859
+ font-weight: 700;
860
+ letter-spacing: -0.02em;
861
+ }
862
+ }
863
+ /**
864
+ * O tema Material define `z-index: 1000` no `.cdk-overlay-container`, abaixo do drawer
865
+ * (`--app-z-drawer-panel`: 1101) — submenus de `app-menu-list` deixavam de ser visíveis no telemóvel.
866
+ */
867
+ .cdk-overlay-container {
868
+ z-index: var(--app-z-overlay-container, 1120);
869
+ }
870
+
871
+ /**
872
+ * Painéis CDK com tema da lib: o fundo real fica no conteúdo (popover, dropdown, …).
873
+ * Sem `transparent` no wrapper, o flex do `.cdk-overlay-pane` pode mostrar branco por baixo
874
+ * e parecer «fora do tema» face ao resto da página.
875
+ */
876
+ .cdk-overlay-container .cdk-overlay-pane.app-library-theme:not(.app-lib-dialog-panel) {
877
+ background: transparent;
878
+ color: var(--app-color-text-primary, inherit);
879
+ }
880
+
881
+ /* Cadeia de altura: scroll só dentro do app (ex.: docs `main`, home), não no `body`. */
882
+ html {
883
+ height: 100%;
884
+ box-sizing: border-box;
885
+ }
886
+
887
+ html,
888
+ body {
889
+ margin: 0;
890
+ background-color: #ffffff;
891
+ }
892
+
893
+ body {
894
+ height: 100%;
895
+ overflow: hidden;
896
+ box-sizing: border-box;
897
+ }
898
+
899
+ /**
900
+ * Bloqueio de scroll (CDK BlockScrollStrategy + `app-dialog`).
901
+ * `overflow-y: scroll` no `html` foi removido — forçava barra no viewport.
902
+ */
903
+ html.cdk-global-scrollblock {
904
+ position: fixed;
905
+ top: 0;
906
+ left: 0;
907
+ width: 100%;
908
+ min-height: 100%;
909
+ min-height: 100dvh;
910
+ overflow: hidden;
911
+ overscroll-behavior: none;
912
+ }
913
+
914
+ html.cdk-global-scrollblock body {
915
+ overflow: hidden !important;
916
+ }
917
+
918
+ /**
919
+ * Áreas com scroll próprio (ex.: doc) — corta scroll de fundo.
920
+ */
921
+ html.cdk-global-scrollblock [data-app-scroll-lock] {
922
+ overflow: hidden !important;
923
+ overscroll-behavior: none;
924
+ }
925
+
926
+ /**
927
+ * Bloqueio de scroll do `app-dialog` declarativo ({@link lockPageScrollAppDialog}): sem mover o
928
+ * `html` com `position: fixed` + `left`/`top` negativos, para o scrim `position: fixed` alinhar ao
929
+ * viewport real (ver comentário no util).
930
+ */
931
+ html.app-dialog-scroll-lock {
932
+ overflow: hidden !important;
933
+ overscroll-behavior: none;
934
+ }
935
+
936
+ html.app-dialog-scroll-lock body {
937
+ overflow: hidden !important;
938
+ overscroll-behavior: none;
939
+ }