zark-design 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -3
- package/templates/README.md.hbs +567 -1
- package/templates/_shared/tokens.css.hbs +55 -1
- package/templates/html/components.css +553 -1
- package/templates/html/showcase.html.hbs +386 -71
- package/templates/jsx/App.example.jsx.hbs +1 -1
- package/templates/jsx/components.css +553 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zark-design",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Design system scaffolder anti-cara-de-IA. `npx zark-design init` gera um DS completo a partir da sua cor primária (paleta 50→900 via HSL) ou usa o preset ZARK. Regras explícitas pra IA: sem pill, sem rounded extremo, sem travessão em copy, sem brand color dominante. HTML + JSX side-by-side. Dark mode nativo. Sem dependência runtime.",
|
|
3
|
+
"version": "3.3.0",
|
|
4
|
+
"description": "Design system scaffolder anti-cara-de-IA. `npx zark-design init` gera um DS completo a partir da sua cor primária (paleta 50→900 via HSL) ou usa o preset ZARK. Regras explícitas pra IA: sem pill, sem rounded extremo, sem travessão em copy, sem brand color dominante, sem glow/shine/gradiente, botões fiéis aos padrões canônicos. Inclui paleta validada de data viz (8 slots categoricos CVD-safe, sequential, diverging, status) + receitas de estados (skeleton, tooltip, tabela, meter, sparkline). HTML + JSX side-by-side. Dark mode nativo. Sem dependência runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"zark-design": "bin/cli.js"
|
|
@@ -24,7 +24,12 @@
|
|
|
24
24
|
"anti-ai-look",
|
|
25
25
|
"palette-generator",
|
|
26
26
|
"dark-mode",
|
|
27
|
-
"brand-agnostic"
|
|
27
|
+
"brand-agnostic",
|
|
28
|
+
"data-viz",
|
|
29
|
+
"dataviz",
|
|
30
|
+
"charts",
|
|
31
|
+
"cvd-safe",
|
|
32
|
+
"categorical-palette"
|
|
28
33
|
],
|
|
29
34
|
"author": "Maycon Jordan",
|
|
30
35
|
"license": "MIT",
|
package/templates/README.md.hbs
CHANGED
|
@@ -13,10 +13,12 @@ Este design system existe pra **fugir do "cara de IA"**. Se você é uma IA gera
|
|
|
13
13
|
### Visual
|
|
14
14
|
- ❌ **Nada de pill como indicador.** Tag, badge, chip, toggle: raio máximo `var(--r-md)` (6px). Pill (`border-radius: 999px`, `9999px`, `--r-pill`) está banido. Único uso de raio 50%: **avatar circular** e **status dot** (8px).
|
|
15
15
|
- ❌ **Nada de bordas extremamente arredondadas.** Cards, panels, modals: raio máximo `var(--r-2xl)` (16px) pra modal, `var(--r-xl)` (12px) pra card grande, `var(--r-lg)` (8px) pra card padrão. Botões: `var(--r-md)` (6px), nunca mais. Se você está pensando em `border-radius: 24px+`, **pare**.
|
|
16
|
-
- ❌ **Nada de
|
|
16
|
+
- ❌ **Nada de glow, shine, drop-shadow colorido, gradiente colorido, glassmorphism, neon, blur exagerado.** Assinaturas óbvias de UI gerada por IA. Sombra é warm (`rgba(20, 17, 12, ...)`), 1 camada, discreta. Sem `filter: drop-shadow(0 0 12px brand-500)`. Sem `text-shadow` colorido. Sem `backdrop-filter: blur()` como decoração.
|
|
17
17
|
- ❌ **Brand color dominante.** A cor de marca (`var(--brand-500)`) só aparece em: CTA primário, focus ring, link, ícone-acento. Nunca como background de tela inteira, hero, card. Use neutros warm pro grosso (`--paper`, `--canvas`, `--surface`).
|
|
18
18
|
- ❌ **Hex hardcoded** (`#f56f10`, `#3B82F6`). SEMPRE `var(--brand-500)` ou variável do token.
|
|
19
19
|
- ❌ **Border-radius percentual aleatório** (`30%`, `40%`). Só `50%` pra círculos geométricos.
|
|
20
|
+
- ❌ **Botão inflado, botão gigante, botão com gradiente ou brilho.** Botão é `.btn` + variante + tamanho. Ponto. Ver seção "Fidelidade aos padrões de botão" abaixo.
|
|
21
|
+
- ❌ **Container arredondado grande com padding grande e sombra pesada.** Esse combo é o "cara de landing page gerada por IA". Card ZARK tem hairline 1px + `--shadow-sm` + raio ≤ 12px.
|
|
20
22
|
|
|
21
23
|
### Copy / texto gerado
|
|
22
24
|
- ❌ **NUNCA use travessão (—) ou en-dash (–) em texto da UI ou copy gerada.** É a assinatura mais óbvia de texto de IA. Use:
|
|
@@ -258,6 +260,63 @@ function Dashboard() {
|
|
|
258
260
|
|
|
259
261
|
---
|
|
260
262
|
|
|
263
|
+
## Fidelidade aos padrões de botão
|
|
264
|
+
|
|
265
|
+
> Botão é o componente mais copiado errado. Aqui a IA usa **o que existe**, não inventa variante nova.
|
|
266
|
+
|
|
267
|
+
### Variantes canônicas (as únicas permitidas)
|
|
268
|
+
|
|
269
|
+
| Classe | Uso |
|
|
270
|
+
|---|---|
|
|
271
|
+
| `.btn-primary` | **UMA** ação principal do bloco/modal/página. Brand color no bg. |
|
|
272
|
+
| `.btn-secondary` | Ação alternativa lado a lado do primary. Surface + hairline. |
|
|
273
|
+
| `.btn-soft` | Ação secundária sem competir visualmente. `--brand-50` bg, `--brand-700` texto. |
|
|
274
|
+
| `.btn-ghost` | Ação terciária, discreta. Sem bg, sem borda até hover. |
|
|
275
|
+
| `.btn-danger` | Ação destrutiva. Texto vermelho em fundo branco, hover vermelho suave. |
|
|
276
|
+
|
|
277
|
+
### Tamanhos canônicos (as únicas permitidas)
|
|
278
|
+
|
|
279
|
+
| Classe | Altura | Uso |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| `.btn-xs` | 22px | Dentro de tabela, chip menu, breadcrumb. |
|
|
282
|
+
| `.btn-sm` | 28px | Botão dentro de card compacto. |
|
|
283
|
+
| `.btn-md` | 32px | **Padrão.** 95% dos casos. |
|
|
284
|
+
| `.btn-lg` | 40px | Formulário grande, modal principal. |
|
|
285
|
+
|
|
286
|
+
Sem `xl`, `2xl`, `huge`. Sem `w-full` gigante. Sem `py-6`, `py-8`.
|
|
287
|
+
|
|
288
|
+
### Regras rígidas
|
|
289
|
+
- ❌ **Nunca invente uma variante nova** (`btn-gradient`, `btn-glow`, `btn-outline-primary`, `btn-3d`, `btn-hero`). Se você acha que precisa, você não precisa.
|
|
290
|
+
- ❌ **Nunca 2 primários no mesmo bloco.** UM primário. Outros são secondary, soft, ghost.
|
|
291
|
+
- ❌ **Nunca botão com gradiente colorido**, glow, box-shadow colorido, `text-shadow`, `filter: drop-shadow`.
|
|
292
|
+
- ❌ **Nunca botão com ícone gigante ou emoji-hero**. Ícone de botão é 14px `.btn-md`, 12px `.btn-sm`.
|
|
293
|
+
- ❌ **Nunca botão com raio > `var(--r-lg)` (8px)**. `.btn-md` é 6px, `.btn-lg` é 8px. Chega.
|
|
294
|
+
- ❌ **Nunca botão sem uma das classes de tamanho** (`.btn-xs/sm/md/lg`). Isso não é opção; é obrigatório.
|
|
295
|
+
- ✅ Ícone à esquerda ou direita: `<button class="btn btn-primary btn-md"><svg>…</svg> Salvar</button>`. Gap padrão 6px vem da classe.
|
|
296
|
+
- ✅ Loading: `<button class="btn btn-primary btn-md" disabled><span class="spinner"></span> Salvando…</button>`. Spinner CSS já existe.
|
|
297
|
+
|
|
298
|
+
### Exemplo do que NÃO fazer
|
|
299
|
+
|
|
300
|
+
```html
|
|
301
|
+
<!-- ❌ HORROR: variante inventada, gigante, gradiente, glow -->
|
|
302
|
+
<button style="background: linear-gradient(90deg, #f56f10, #ff8f30);
|
|
303
|
+
color: white; padding: 16px 32px; border-radius: 999px;
|
|
304
|
+
font-size: 20px; box-shadow: 0 0 24px #f56f10;
|
|
305
|
+
font-weight: 800; text-transform: uppercase;
|
|
306
|
+
letter-spacing: 0.1em;">
|
|
307
|
+
✨ COMEÇAR AGORA
|
|
308
|
+
</button>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Cara-de-IA em 8 sinais: gradient, pill (999px), padding inflado, fonte grande, glow shadow, uppercase, letter-spacing marketing, emoji de foguete/estrela em CTA.
|
|
312
|
+
|
|
313
|
+
```html
|
|
314
|
+
<!-- ✅ CERTO -->
|
|
315
|
+
<button class="btn btn-primary btn-md">Começar</button>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
261
320
|
## Receitas prontas (copy-paste, HTML)
|
|
262
321
|
|
|
263
322
|
> Padrões testados em produção. Comece daqui em vez de inventar do zero.
|
|
@@ -413,6 +472,488 @@ Quando a IA gera **labels de botão, mensagens, placeholders, títulos**:
|
|
|
413
472
|
|
|
414
473
|
---
|
|
415
474
|
|
|
475
|
+
## Componentes avançados (v3.3)
|
|
476
|
+
|
|
477
|
+
> Padrões maiores, derivados de referências externas de qualidade e adaptados pra identidade ZARK. Todos ficam em `components.css` e podem ser usados direto em HTML puro.
|
|
478
|
+
|
|
479
|
+
### 1. UserDropdown (`.zk-user-menu`)
|
|
480
|
+
|
|
481
|
+
Menu de usuário rico com avatar trigger, header (avatar + nome + username + status badge), grupos separados por hairline, itens com ícone + label + right-content (badge, avatar, ícone).
|
|
482
|
+
|
|
483
|
+
```html
|
|
484
|
+
<div class="zk-user-menu">
|
|
485
|
+
<button class="zk-user-menu-trigger">
|
|
486
|
+
<img src="avatar.jpg" alt="Voce"/>
|
|
487
|
+
</button>
|
|
488
|
+
|
|
489
|
+
<div class="zk-user-menu-panel">
|
|
490
|
+
<div class="head">
|
|
491
|
+
<div class="avatar"><img src="avatar.jpg" alt=""/></div>
|
|
492
|
+
<div class="who">
|
|
493
|
+
<div class="name">Maycon Jordan</div>
|
|
494
|
+
<div class="handle">@mayconj</div>
|
|
495
|
+
</div>
|
|
496
|
+
<span class="status-badge online">Online</span>
|
|
497
|
+
</div>
|
|
498
|
+
|
|
499
|
+
<div class="zk-user-menu-sep"></div>
|
|
500
|
+
|
|
501
|
+
<div class="zk-user-menu-group">
|
|
502
|
+
<button class="zk-user-menu-item">
|
|
503
|
+
<span class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 4-6 8-6s8 2 8 6"/></svg></span>
|
|
504
|
+
<span class="label">Seu perfil</span>
|
|
505
|
+
</button>
|
|
506
|
+
<button class="zk-user-menu-item">
|
|
507
|
+
<span class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M12 3v3M12 18v3M3 12h3M18 12h3"/></svg></span>
|
|
508
|
+
<span class="label">Preferências</span>
|
|
509
|
+
</button>
|
|
510
|
+
</div>
|
|
511
|
+
|
|
512
|
+
<div class="zk-user-menu-sep"></div>
|
|
513
|
+
|
|
514
|
+
<div class="zk-user-menu-group">
|
|
515
|
+
<button class="zk-user-menu-item is-brand">
|
|
516
|
+
<span class="icon"><svg viewBox="0 0 24 24"><polygon points="12 2 15 9 22 9 17 14 19 21 12 17 5 21 7 14 2 9 9 9 12 2"/></svg></span>
|
|
517
|
+
<span class="label">Upgrade Pro</span>
|
|
518
|
+
<span class="badge-off">20% off</span>
|
|
519
|
+
</button>
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
<div class="zk-user-menu-sep"></div>
|
|
523
|
+
|
|
524
|
+
<div class="zk-user-menu-group">
|
|
525
|
+
<button class="zk-user-menu-item is-danger">
|
|
526
|
+
<span class="icon"><svg viewBox="0 0 24 24"><path d="M9 3v18M15 3v18M3 9h18M3 15h18"/></svg></span>
|
|
527
|
+
<span class="label">Sair</span>
|
|
528
|
+
</button>
|
|
529
|
+
</div>
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Regras:** avatar circular sempre (50%). Status badge mono uppercase raio-xs. Sem backdrop-blur, sem drop-shadow-xl. Grupos separados por hairline `--line-100`.
|
|
535
|
+
|
|
536
|
+
**Interação:** abre no click do trigger via JS (toggle da classe `.is-open` na panel, ou lib de headless UI se em React). CSS já cobre estados hover + focus.
|
|
537
|
+
|
|
538
|
+
### 2. ToolbarDock (`.zk-dock`)
|
|
539
|
+
|
|
540
|
+
Dock flutuante estilo Vercel-inspired: pill horizontal com ícones circulares, badges de notificação, botões de toggle. Versão light (default) e dark (`.zk-dock.dark`).
|
|
541
|
+
|
|
542
|
+
```html
|
|
543
|
+
<!-- Dock light -->
|
|
544
|
+
<div class="zk-dock">
|
|
545
|
+
<button class="zk-dock-btn" aria-label="Comentar">
|
|
546
|
+
<svg viewBox="0 0 24 24"><path d="M4 6h16v10H8l-4 4V6z"/></svg>
|
|
547
|
+
</button>
|
|
548
|
+
<button class="zk-dock-btn" aria-label="Inbox">
|
|
549
|
+
<svg viewBox="0 0 24 24"><path d="M4 4h16v10l-4 4H8l-4-4V4z"/></svg>
|
|
550
|
+
<span class="dot"></span>
|
|
551
|
+
</button>
|
|
552
|
+
<div class="zk-dock-sep"></div>
|
|
553
|
+
<button class="zk-dock-btn" aria-label="Compartilhar">
|
|
554
|
+
<svg viewBox="0 0 24 24"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.5" y1="10.5" x2="15.5" y2="6.5"/><line x1="8.5" y1="13.5" x2="15.5" y2="17.5"/></svg>
|
|
555
|
+
</button>
|
|
556
|
+
<button class="zk-dock-btn" aria-label="Menu">
|
|
557
|
+
<svg viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></svg>
|
|
558
|
+
</button>
|
|
559
|
+
</div>
|
|
560
|
+
|
|
561
|
+
<!-- Dock dark (mesmo layout, adiciona .dark) -->
|
|
562
|
+
<div class="zk-dock dark">
|
|
563
|
+
<!-- mesmos botões -->
|
|
564
|
+
</div>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Regras:** container `--r-lg` (8px), **nunca pill 999px**. Ícones 18px em botão 32x32 com `--r-md`. Notification dot 6px em brand-500 com border do surface. Separador vertical hairline. Sem backdrop-blur decorativo.
|
|
568
|
+
|
|
569
|
+
**Extensão:** pra ter collapse animado + tooltip rail que desliza (como o Vercel-style original), embrulhe o dock num React Motion. Comportamento é opcional; visual estático já dá o benefício.
|
|
570
|
+
|
|
571
|
+
### 3. ChartCard (`.zk-chart-card`)
|
|
572
|
+
|
|
573
|
+
Card 356px com viz area de 180px em cima + body embaixo. Barras SVG mudam de altura no hover (CSS transitions). Grid sutil hairline com radial mask.
|
|
574
|
+
|
|
575
|
+
```html
|
|
576
|
+
<div class="zk-chart-card">
|
|
577
|
+
<div class="zk-chart-card-viz">
|
|
578
|
+
<div class="tags">
|
|
579
|
+
<span class="tag"><span class="dot" style="background:var(--viz-cat-1)"></span>+15,2%</span>
|
|
580
|
+
<span class="tag"><span class="dot" style="background:var(--viz-cat-8)"></span>+18,7%</span>
|
|
581
|
+
</div>
|
|
582
|
+
<svg viewBox="0 0 356 180">
|
|
583
|
+
<!-- barras: on hover expandem via CSS transition (defina y/height diferentes em .zk-chart-card:hover rect) -->
|
|
584
|
+
<rect x="40" y="110" width="15" height="20" fill="var(--viz-cat-8)" rx="2"/>
|
|
585
|
+
<rect x="60" y="90" width="15" height="20" fill="var(--viz-cat-1)" rx="2"/>
|
|
586
|
+
<rect x="80" y="70" width="15" height="40" fill="var(--viz-cat-1)" rx="2"/>
|
|
587
|
+
<rect x="100" y="80" width="15" height="30" fill="var(--viz-cat-1)" rx="2"/>
|
|
588
|
+
<rect x="120" y="110" width="15" height="30" fill="var(--viz-cat-8)" rx="2"/>
|
|
589
|
+
<rect x="140" y="60" width="15" height="50" fill="var(--viz-cat-1)" rx="2"/>
|
|
590
|
+
<rect x="160" y="80" width="15" height="30" fill="var(--viz-cat-1)" rx="2"/>
|
|
591
|
+
<rect x="180" y="110" width="15" height="20" fill="var(--viz-cat-8)" rx="2"/>
|
|
592
|
+
</svg>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="zk-chart-card-body">
|
|
595
|
+
<div class="title">Novos leads</div>
|
|
596
|
+
<div class="desc">Últimos 7 dias · 142 no total</div>
|
|
597
|
+
</div>
|
|
598
|
+
</div>
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
**Regras:** raio `--r-xl` (12px), hairline, shadow-sm. Cores das barras SEMPRE via `--viz-cat-*` (nunca hardcode). Grid pattern sutil (`--line-100`) com radial mask. Transition ≤ 400ms.
|
|
602
|
+
|
|
603
|
+
**Anti-pattern (o que a referência tinha e não copiamos):** gradient radial colorido de background, `backdrop-blur-sm` decorativo nos tags. Removidos: warm/hairline resolve.
|
|
604
|
+
|
|
605
|
+
### 4. OrbitCard (`.zk-orbit-card`)
|
|
606
|
+
|
|
607
|
+
Card KPI com órbita de dots concêntricos, valor total no centro, breakdown de 2 métricas embaixo. Fade gradient neutro pra transitar viz → body.
|
|
608
|
+
|
|
609
|
+
```html
|
|
610
|
+
<div class="zk-orbit-card">
|
|
611
|
+
<div class="zk-orbit-card-viz">
|
|
612
|
+
<svg viewBox="0 0 320 272">
|
|
613
|
+
<!-- Anel externo: 32 dots em raio 130 -->
|
|
614
|
+
<!-- Anel interno: 24 dots em raio 100 -->
|
|
615
|
+
<!-- (na prática você gera com JS ou pré-calcula os cx/cy) -->
|
|
616
|
+
<circle cx="160" cy="6" r="4" fill="var(--viz-cat-1)"/>
|
|
617
|
+
<circle cx="185.4" cy="9.1" r="4" fill="var(--viz-cat-1)"/>
|
|
618
|
+
<!-- ...restante dos dots... -->
|
|
619
|
+
<circle cx="160" cy="36" r="4" fill="var(--viz-cat-4)"/>
|
|
620
|
+
<!-- ...anel interno... -->
|
|
621
|
+
</svg>
|
|
622
|
+
<div class="center">
|
|
623
|
+
<div class="kicker">Total</div>
|
|
624
|
+
<div class="value">R$ 2.125</div>
|
|
625
|
+
</div>
|
|
626
|
+
<div class="fade"></div>
|
|
627
|
+
</div>
|
|
628
|
+
<div class="zk-orbit-card-body">
|
|
629
|
+
<div class="zk-orbit-card-metrics">
|
|
630
|
+
<div class="zk-orbit-card-metric">
|
|
631
|
+
<div class="head">
|
|
632
|
+
<div class="bar" style="background:var(--viz-cat-1)"></div>
|
|
633
|
+
<div class="label">Bônus</div>
|
|
634
|
+
</div>
|
|
635
|
+
<div class="value">R$ 1.250</div>
|
|
636
|
+
<div class="delta">+15,2%</div>
|
|
637
|
+
</div>
|
|
638
|
+
<div class="zk-orbit-card-metric">
|
|
639
|
+
<div class="head">
|
|
640
|
+
<div class="bar" style="background:var(--viz-cat-4)"></div>
|
|
641
|
+
<div class="label">Incentivos</div>
|
|
642
|
+
</div>
|
|
643
|
+
<div class="value">R$ 875</div>
|
|
644
|
+
<div class="delta">+8,7%</div>
|
|
645
|
+
</div>
|
|
646
|
+
</div>
|
|
647
|
+
<button class="btn btn-secondary btn-md" style="width:100%">Ver detalhes</button>
|
|
648
|
+
</div>
|
|
649
|
+
</div>
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Regras:** dots via `--viz-cat-*` (blue + green por padrão). Valor central em display font (Space Grotesk), `--fs-4xl`. Fade usa gradient neutro (`transparent → var(--surface)`), **nunca cor colorida**. Botão inferior é `.btn-secondary` (não inflado, não gigante).
|
|
653
|
+
|
|
654
|
+
**Anti-pattern:** a referência usava `backdrop-blur-[2px]`, `bg-blue-400/10`, `bg-green-400/10` como decoração. Substituímos por dots com `opacity: 0.6` e fade gradient neutro. Efeito visual similar, cara-de-IA removido.
|
|
655
|
+
|
|
656
|
+
### 5. WheelPicker (`.zk-wheel-picker`)
|
|
657
|
+
|
|
658
|
+
Radial time picker: input central redondo + wheel de 8 wedges com atalhos de +/- tempo. Wheel aparece no hover, some quando o input ganha foco (deixa você digitar).
|
|
659
|
+
|
|
660
|
+
```html
|
|
661
|
+
<div class="zk-wheel-picker">
|
|
662
|
+
<!-- Wheel de wedges (aparece no hover) -->
|
|
663
|
+
<div class="zk-wheel-picker-wheel">
|
|
664
|
+
<svg viewBox="0 0 360 360">
|
|
665
|
+
<!-- 4 wedges positivos (top) -->
|
|
666
|
+
<g class="wedge-group">
|
|
667
|
+
<path class="wedge pos" d="M180 180 L180 20 A160 160 0 0 1 293 67 Z"/>
|
|
668
|
+
<text class="wedge-label pos" x="235" y="45">+2h</text>
|
|
669
|
+
</g>
|
|
670
|
+
<g class="wedge-group">
|
|
671
|
+
<path class="wedge pos" d="M180 180 L293 67 A160 160 0 0 1 340 180 Z"/>
|
|
672
|
+
<text class="wedge-label pos" x="315" y="115">+1h</text>
|
|
673
|
+
</g>
|
|
674
|
+
<g class="wedge-group">
|
|
675
|
+
<path class="wedge pos" d="M180 180 L340 180 A160 160 0 0 1 293 293 Z"/>
|
|
676
|
+
<text class="wedge-label pos" x="315" y="245">+30m</text>
|
|
677
|
+
</g>
|
|
678
|
+
<g class="wedge-group">
|
|
679
|
+
<path class="wedge pos" d="M180 180 L293 293 A160 160 0 0 1 180 340 Z"/>
|
|
680
|
+
<text class="wedge-label pos" x="235" y="315">+15m</text>
|
|
681
|
+
</g>
|
|
682
|
+
<!-- 4 wedges negativos (bottom) -->
|
|
683
|
+
<g class="wedge-group">
|
|
684
|
+
<path class="wedge" d="M180 180 L180 340 A160 160 0 0 1 67 293 Z"/>
|
|
685
|
+
<text class="wedge-label" x="125" y="315">-15m</text>
|
|
686
|
+
</g>
|
|
687
|
+
<g class="wedge-group">
|
|
688
|
+
<path class="wedge" d="M180 180 L67 293 A160 160 0 0 1 20 180 Z"/>
|
|
689
|
+
<text class="wedge-label" x="45" y="245">-30m</text>
|
|
690
|
+
</g>
|
|
691
|
+
<g class="wedge-group">
|
|
692
|
+
<path class="wedge" d="M180 180 L20 180 A160 160 0 0 1 67 67 Z"/>
|
|
693
|
+
<text class="wedge-label" x="45" y="115">-1h</text>
|
|
694
|
+
</g>
|
|
695
|
+
<g class="wedge-group">
|
|
696
|
+
<path class="wedge" d="M180 180 L67 67 A160 160 0 0 1 180 20 Z"/>
|
|
697
|
+
<text class="wedge-label" x="125" y="45">-2h</text>
|
|
698
|
+
</g>
|
|
699
|
+
</svg>
|
|
700
|
+
</div>
|
|
701
|
+
|
|
702
|
+
<!-- Input central -->
|
|
703
|
+
<div class="zk-wheel-picker-input">
|
|
704
|
+
<input type="text" value="09:00" placeholder="HH:MM"/>
|
|
705
|
+
</div>
|
|
706
|
+
</div>
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
**Regras:** input central em `--r-md` (**nunca pill 999px** como a referência tinha). Wheel wedges com stroke da cor `--paper` pra criar gaps visuais. `.wedge.pos` usa `--brand-*`, `.wedge` neutra usa `--ink-*`. Font do valor em display font (Space Grotesk), `--fs-2xl`. Sem drop-shadow-xl.
|
|
710
|
+
|
|
711
|
+
**Interação:** wheel aparece via CSS `.zk-wheel-picker:hover` (opacity + scale + rotate). Sem lib. Pra ligar o click de cada wedge ao valor do input, adicione JS handler que ajusta minutos.
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
## Data viz (gráficos, KPIs, tabelas)
|
|
716
|
+
|
|
717
|
+
> Regras derivadas de método validado. Se você é IA gerando dashboard, siga na ordem abaixo. Cor vem por último.
|
|
718
|
+
|
|
719
|
+
### 1. Decida a forma ANTES de escolher cor
|
|
720
|
+
|
|
721
|
+
| Os dados são… | Use | NÃO use |
|
|
722
|
+
|---|---|---|
|
|
723
|
+
| Um número atual (+ trend) | `.stat` (StatCard: value + delta + sparkline) | Um bar chart de 1 barra |
|
|
724
|
+
| 3 a 6 KPIs em fila | KPI row de `.stat` | Grouped bar |
|
|
725
|
+
| A one number que o dashboard lidera | Hero figure (≥48px, mesma fonte do resto) | — |
|
|
726
|
+
| Uma razão contra limite | Meter (barra com progresso, mesma cor) | Pie de 2 fatias |
|
|
727
|
+
| Mais de ~7 categorias com significado | Tabela (ou tabela + chart) | Mais cores |
|
|
728
|
+
|
|
729
|
+
Se um chart *é* certo, escolha por trabalho:
|
|
730
|
+
|
|
731
|
+
| Trabalho | Forma default | Cor |
|
|
732
|
+
|---|---|---|
|
|
733
|
+
| Comparar magnitude (low→high) | bar / column (heatmap pra grid) | sequential (1 hue) |
|
|
734
|
+
| Trend ao longo do tempo | line (area pra 1 série) | sequential ou 1 categorical |
|
|
735
|
+
| Distinguir séries distintas | grouped/stacked bar, multi-line | **categorical** |
|
|
736
|
+
| Uma série é o ponto, resto é contexto | **emphasis** (1 destacada, resto cinza) | 1 hue + cinza |
|
|
737
|
+
| Acima/abaixo de baseline; delta a target | diverging bar, line vs baseline | diverging |
|
|
738
|
+
| Part-to-whole | stacked bar (horizontal se muitas categorias) | categorical |
|
|
739
|
+
|
|
740
|
+
### 2. Aplique as regras não-negociáveis
|
|
741
|
+
|
|
742
|
+
- **Uma escala Y só.** Nunca dual-axis (dois eixos Y na mesma view). Duas medidas de escalas diferentes = 2 charts, small multiples, ou index 100 na origem.
|
|
743
|
+
- **Cor segue a entidade, não o rank.** Filtrar remove série; sobrevivente mantém sua cor. Nunca recolor-on-filter.
|
|
744
|
+
- **8 slots categóricos, ordenados por CVD-safety.** O 9º nunca é gerado; vira "Outros" ou small multiples.
|
|
745
|
+
- **Sequential = 1 hue, mais-é-escuro.** Nunca rainbow. Nunca ramp em categoria nominal.
|
|
746
|
+
- **Diverging = 2 hues opostos + neutro cinza no meio.** blue↔red, blue↔orange (nunca blue↔aqua: ambos frios).
|
|
747
|
+
- **Status colors são reservados.** Sucess/warning/critical nunca viram "série 4". Sempre ícone + label, cor nunca sozinha.
|
|
748
|
+
|
|
749
|
+
### 3. Paleta ZARK de data viz (tokens novos)
|
|
750
|
+
|
|
751
|
+
Categorical — os 8 slots, na ordem obrigatória. Slot 1 é o default pra 1 série; nunca cicla:
|
|
752
|
+
|
|
753
|
+
| Slot | Hue | Light (`--paper`) | Dark (`--bg-void`) |
|
|
754
|
+
|---|---|---|---|
|
|
755
|
+
| 1 | blue | `#2a78d6` | `#3987e5` |
|
|
756
|
+
| 2 | aqua | `#1baf7a` | `#199e70` |
|
|
757
|
+
| 3 | yellow | `#eda100` | `#c98500` |
|
|
758
|
+
| 4 | green | `#008300` | `#008300` |
|
|
759
|
+
| 5 | violet | `#4a3aa7` | `#9085e9` |
|
|
760
|
+
| 6 | red | `#e34948` | `#e66767` |
|
|
761
|
+
| 7 | magenta | `#e87ba4` | `#d55181` |
|
|
762
|
+
| 8 | orange (viz) | `#eb6834` | `#d95926` |
|
|
763
|
+
|
|
764
|
+
Tokens: `--viz-cat-1` até `--viz-cat-8` (definidos em `tokens.css`).
|
|
765
|
+
|
|
766
|
+
> **Importante.** O laranja do slot 8 (`--viz-cat-8`) NÃO é o brand ember `--brand-500` (#f56f10). São cores diferentes. A ember é *reservada* pra CTA/focus/link e **nunca é cor de série**. Se você renderiza um chart com uma série ember, você confunde a marca.
|
|
767
|
+
|
|
768
|
+
Sequential (blue, light→dark) — pra magnitude contínua (heatmap, choropleth, ordinal ramp):
|
|
769
|
+
|
|
770
|
+
| Step | Hex | Uso |
|
|
771
|
+
|---|---|---|
|
|
772
|
+
| 100 | `#cde2fb` | valor perto de zero (recessivo) |
|
|
773
|
+
| 200 | `#9ec5f4` | |
|
|
774
|
+
| 300 | `#6da7ec` | |
|
|
775
|
+
| 400 | `#3987e5` | |
|
|
776
|
+
| 500 | `#256abf` | valor médio |
|
|
777
|
+
| 600 | `#184f95` | |
|
|
778
|
+
| 700 | `#0d366b` | valor alto |
|
|
779
|
+
|
|
780
|
+
Tokens: `--viz-seq-100` … `--viz-seq-700`.
|
|
781
|
+
|
|
782
|
+
Diverging: usa slots `--viz-cat-1` (blue = positivo) ↔ `--viz-cat-6` (red = negativo) + `--line-100` (neutro do próprio ZARK) no meio.
|
|
783
|
+
|
|
784
|
+
Status: reusa os tokens semânticos ZARK (`--success-500`, `--warning-500`, `--danger-500`, `--info-500`). **Sempre com ícone + label.** Nunca cor sozinha.
|
|
785
|
+
|
|
786
|
+
### 4. Marcas (specs de renderização)
|
|
787
|
+
|
|
788
|
+
- **Traços finos.** Line 2px, marker ≥8px, bar-end com raio 4px arredondado só no topo (ancorado à baseline).
|
|
789
|
+
- **2px de gap surface entre fills.** Stacked bar segments E adjacent bars. Nunca border escuro pra separar.
|
|
790
|
+
- **Grid/eixos = hairlines sólidos.** 1px, cor `--line-200` (light) / `--line-300` (dark). Nunca tracejado (parece "projeção").
|
|
791
|
+
- **Labels seletivos.** Direct label o endpoint / o extremo / a série que importa. **Legenda sempre presente pra ≥ 2 séries** (nenhuma pra 1 — o título nomeia a série). Nunca número em todo ponto.
|
|
792
|
+
- **Texto usa tokens de ink**, nunca a cor da série. Valor/label/legenda ficam em `--ink-700` / `--ink-500` / `--ink-400`. A cor identifica; o texto não repete.
|
|
793
|
+
- **Sem dual-axis.** (Anti-pattern #1.)
|
|
794
|
+
- **Sem `overflow: hidden` cortando label dentro de bar.** Se label não cabe, joga fora do bar ou pra tooltip.
|
|
795
|
+
|
|
796
|
+
### 5. Interação padrão
|
|
797
|
+
|
|
798
|
+
- Line/area → **crosshair + tooltip** ao passar o mouse.
|
|
799
|
+
- Bar/dot/cell → tooltip per-mark.
|
|
800
|
+
- Hit area ≥ 24px (não o tamanho visual do mark).
|
|
801
|
+
- Filters ficam em UMA linha acima de TODOS os charts. Nunca dentro do card do chart.
|
|
802
|
+
- Skeleton flash em refetch: NÃO. Mantém o render anterior a 60% opacity até o novo chegar.
|
|
803
|
+
|
|
804
|
+
### 6. Anti-patterns (checar TODO chart contra)
|
|
805
|
+
|
|
806
|
+
- ❌ **Dual-axis** (2 escalas Y). Corrige com 2 charts ou index 100.
|
|
807
|
+
- ❌ **Recolor-on-filter.** Cor segue entidade.
|
|
808
|
+
- ❌ **9ª cor gerada.** Vira "Outros".
|
|
809
|
+
- ❌ **Ramp de valor em categoria nominal.** 1 série = 1 cor (slot 1).
|
|
810
|
+
- ❌ **Rainbow sequential.** 1 hue, light→dark.
|
|
811
|
+
- ❌ **Hue no meio do diverging** ou 2 hues frios como polos.
|
|
812
|
+
- ❌ **Status color como série 4** ou série color como status.
|
|
813
|
+
- ❌ **1-bar bar chart** ou **2-slice pie**. Use stat tile.
|
|
814
|
+
- ❌ **Donut/pie pra comparar valores próximos.** Use bar.
|
|
815
|
+
- ❌ **Grid pesado, bar grosso, sem breathing room.** Reads loud.
|
|
816
|
+
- ❌ **Tracejado** em grid ou axis. Solid hairline.
|
|
817
|
+
- ❌ **Número em cada ponto.** Direct label seletivo + tooltip.
|
|
818
|
+
- ❌ **Display font ou serif no hero figure.** Usa a mesma sans do sistema.
|
|
819
|
+
- ❌ **`tabular-nums` em número grande.** Só em coluna de tabela e ticks de eixo.
|
|
820
|
+
- ❌ **Texture on by default.** Só opt-in (a11y, print, forced-colors), 45°/135° apenas.
|
|
821
|
+
- ❌ **Tooltip como único jeito de ler valor.** Tem que ter label OU tabela.
|
|
822
|
+
|
|
823
|
+
### 7. Bibliotecas recomendadas
|
|
824
|
+
|
|
825
|
+
Sem preferência dogmática — a IA escolhe conforme stack:
|
|
826
|
+
|
|
827
|
+
- **React (recomendado):** `recharts` (leve, declarativo, defaults sanos) ou `visx` (mais controle, low-level).
|
|
828
|
+
- **HTML/vanilla:** `chart.js` (aceitável se cuidar da config) ou D3 direto pra controle total.
|
|
829
|
+
- **Se stack é Blade/Django/Rails:** renderize server-side um SVG, ou use `chart.js` via CDN.
|
|
830
|
+
- **Nunca:** Highcharts (licença), ApexCharts (defaults barulhentos), qualquer lib que renderiza 3D por default.
|
|
831
|
+
|
|
832
|
+
Configuração obrigatória em qualquer lib:
|
|
833
|
+
- Grid: hairline `--line-200`, sem dash.
|
|
834
|
+
- Fonte: mesma do sistema (`var(--font-sans)`).
|
|
835
|
+
- Cores: sempre via CSS custom properties (`--viz-cat-*`), nunca hex hardcoded no config.
|
|
836
|
+
- Sem animação > 400ms na entrada. Sem "bounce" ou "elastic".
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## Estados que faltavam (loading, skeleton, tooltip, tabela)
|
|
841
|
+
|
|
842
|
+
### Loading state (skeleton, warm)
|
|
843
|
+
|
|
844
|
+
Skeleton usa cor de fundo `--line-100` com animação sutil (shimmer 1200ms, contida). Sem gradiente colorido.
|
|
845
|
+
|
|
846
|
+
```html
|
|
847
|
+
<div class="panel">
|
|
848
|
+
<div class="panel-head">
|
|
849
|
+
<div class="panel-title" style="background:var(--line-100); color:transparent; border-radius:var(--r-sm); width:180px;">···</div>
|
|
850
|
+
</div>
|
|
851
|
+
<div class="panel-body">
|
|
852
|
+
<div style="height:12px; background:var(--line-100); border-radius:var(--r-xs); margin-bottom:8px;"></div>
|
|
853
|
+
<div style="height:12px; background:var(--line-100); border-radius:var(--r-xs); width:80%;"></div>
|
|
854
|
+
</div>
|
|
855
|
+
</div>
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Regra:** skeleton só em first-load. Refetch de dados mantém render anterior a `opacity: 0.6`. Nunca "skeleton flash" no meio da sessão.
|
|
859
|
+
|
|
860
|
+
### Tooltip (hover simples)
|
|
861
|
+
|
|
862
|
+
Sem lib. Sem framework. `title` HTML nativo pra tooltips secos. Pra tooltips ricos (chart, KPI com detalhamento), use um `div` absoluto com estas specs:
|
|
863
|
+
|
|
864
|
+
```css
|
|
865
|
+
.zk-tooltip {
|
|
866
|
+
position: absolute;
|
|
867
|
+
background: var(--surface);
|
|
868
|
+
border: 1px solid var(--line-300);
|
|
869
|
+
border-radius: var(--r-sm);
|
|
870
|
+
padding: 8px 12px;
|
|
871
|
+
font-size: var(--fs-sm);
|
|
872
|
+
color: var(--ink-700);
|
|
873
|
+
box-shadow: var(--shadow-md);
|
|
874
|
+
pointer-events: none;
|
|
875
|
+
max-width: 280px;
|
|
876
|
+
line-height: 1.4;
|
|
877
|
+
}
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
**Regra:** tooltip enhance, nunca gate. Toda informação em tooltip tem que estar OU visível OU na tabela.
|
|
881
|
+
|
|
882
|
+
### Tabela (companion do chart)
|
|
883
|
+
|
|
884
|
+
Todo chart tem uma tabela-view equivalente. Padrão:
|
|
885
|
+
|
|
886
|
+
```html
|
|
887
|
+
<table class="zk-table">
|
|
888
|
+
<thead>
|
|
889
|
+
<tr>
|
|
890
|
+
<th>Período</th>
|
|
891
|
+
<th class="num">Concluídas</th>
|
|
892
|
+
<th class="num">Meta</th>
|
|
893
|
+
<th class="num">Δ</th>
|
|
894
|
+
</tr>
|
|
895
|
+
</thead>
|
|
896
|
+
<tbody>
|
|
897
|
+
<tr><td>Jun/26</td><td class="num">128</td><td class="num">120</td><td class="num pos">+8</td></tr>
|
|
898
|
+
<tr><td>Jul/26</td><td class="num">142</td><td class="num">130</td><td class="num pos">+12</td></tr>
|
|
899
|
+
</tbody>
|
|
900
|
+
</table>
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
Specs (adicione ao `components.css` se ainda não tem):
|
|
904
|
+
|
|
905
|
+
- Fonte tabular apenas em coluna numérica (`.num { font-variant-numeric: tabular-nums; text-align: right; }`).
|
|
906
|
+
- Hairline `--line-200` entre linhas (sem zebra, sem grid vertical).
|
|
907
|
+
- Header em `--ink-500`, uppercase, `--fs-xs`, `--ls-widest`.
|
|
908
|
+
- Delta positivo em `--success-700`, negativo em `--danger-700`. Nunca cor sozinha, sempre com sinal (+/-).
|
|
909
|
+
- Densidade: `.zk-table-dense` (linha 32px) vs default (linha 44px).
|
|
910
|
+
|
|
911
|
+
### Meter (barra de ratio contra limite)
|
|
912
|
+
|
|
913
|
+
Pra "12 de 20 usada", "3.2GB de 5GB". Progresso é sempre **1 hue**, light track + dark fill:
|
|
914
|
+
|
|
915
|
+
```html
|
|
916
|
+
<div style="display:flex; flex-direction:column; gap:6px; max-width:320px;">
|
|
917
|
+
<div style="display:flex; justify-content:space-between; font-size:var(--fs-sm);">
|
|
918
|
+
<span>Uso de storage</span>
|
|
919
|
+
<span style="color:var(--ink-500);"><b>3.2 GB</b> de 5 GB</span>
|
|
920
|
+
</div>
|
|
921
|
+
<div style="height:6px; background:var(--line-100); border-radius:var(--r-xs); overflow:hidden;">
|
|
922
|
+
<div style="height:100%; width:64%; background:var(--brand-500); border-radius:var(--r-xs);"></div>
|
|
923
|
+
</div>
|
|
924
|
+
</div>
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Cor do fill:
|
|
928
|
+
- Uso normal (< 80%): `--brand-500` ou `--info-500`.
|
|
929
|
+
- Perto do limite (80–95%): `--warning-500`.
|
|
930
|
+
- Estourou / crítico (≥ 95%): `--danger-500`.
|
|
931
|
+
|
|
932
|
+
Cor troca só quando cruza threshold. Nunca gradiente.
|
|
933
|
+
|
|
934
|
+
### Sparkline (dentro de StatCard)
|
|
935
|
+
|
|
936
|
+
Sparkline é a única exceção onde chart entra dentro de card. Inline SVG, linha 1.5px, sem eixos, sem grid, sem legenda. Só a curva.
|
|
937
|
+
|
|
938
|
+
```html
|
|
939
|
+
<div class="stat">
|
|
940
|
+
<div class="stat-head">
|
|
941
|
+
<span class="stat-label">CONCLUÍDAS · SEMANA</span>
|
|
942
|
+
</div>
|
|
943
|
+
<div class="stat-value">142</div>
|
|
944
|
+
<div class="stat-sub">+12 vs anterior</div>
|
|
945
|
+
<svg viewBox="0 0 100 30" style="width:100%; height:24px; margin-top:8px;">
|
|
946
|
+
<polyline points="0,25 15,20 30,22 45,15 60,10 75,12 90,6 100,4"
|
|
947
|
+
fill="none" stroke="var(--brand-500)" stroke-width="1.5"
|
|
948
|
+
stroke-linecap="round" stroke-linejoin="round"/>
|
|
949
|
+
</svg>
|
|
950
|
+
</div>
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
Regra: sparkline usa 1 cor (`--brand-500` OU `--viz-cat-1` se está em contexto de chart section), nunca área preenchida colorida, nunca marcador em cada ponto.
|
|
954
|
+
|
|
955
|
+
---
|
|
956
|
+
|
|
416
957
|
## Dark mode
|
|
417
958
|
|
|
418
959
|
Toggle automático via OS, ou manual:
|
|
@@ -441,18 +982,43 @@ A cor de marca (`--brand-500`) **NUNCA muda no dark mode** — é assinatura da
|
|
|
441
982
|
- ❌ Raio > `var(--r-2xl)` (16px) em qualquer componente.
|
|
442
983
|
- ❌ Borda > 1px em UI normal.
|
|
443
984
|
|
|
985
|
+
**Efeitos (anti-cara-de-IA)**
|
|
986
|
+
- ❌ Glow / halo (`box-shadow: 0 0 Xpx <cor>`, `filter: drop-shadow(0 0 X <cor>)`).
|
|
987
|
+
- ❌ Shine / brilho decorativo (linhas brilhantes, sparkle, "glass reflection").
|
|
988
|
+
- ❌ Gradiente colorido em botão, card, hero, background.
|
|
989
|
+
- ❌ `text-shadow` colorido.
|
|
990
|
+
- ❌ `backdrop-filter: blur()` como decoração (só em modal overlay leve, ≤ 8px).
|
|
991
|
+
- ❌ Sombras frias `rgba(0,0,0,...)`. Use warm `rgba(20,17,12,...)`.
|
|
992
|
+
|
|
993
|
+
**Botão (regra própria)**
|
|
994
|
+
- ❌ Variante inventada (`btn-gradient`, `btn-glow`, `btn-hero`, `btn-3d`). Só as 5 canônicas.
|
|
995
|
+
- ❌ Tamanho fora de xs/sm/md/lg. Sem `xl`, `w-full` inflado, `py-8`.
|
|
996
|
+
- ❌ 2 botões `primary` no mesmo bloco. UM primário.
|
|
997
|
+
- ❌ Emoji ou ícone gigante como CTA principal.
|
|
998
|
+
|
|
444
999
|
**Texto / copy**
|
|
445
1000
|
- ❌ Travessão (—) ou en-dash (–) em qualquer texto da UI/copy.
|
|
446
1001
|
- ❌ Emoji em label de botão, título de campo, título de página.
|
|
447
1002
|
- ❌ Frase > 12 palavras em UI.
|
|
448
1003
|
- ❌ Vocabulário de marketing IA: "transforme", "potencialize", "descubra", "experimente".
|
|
449
1004
|
|
|
1005
|
+
**Data viz**
|
|
1006
|
+
- ❌ Dual-axis (duas escalas Y).
|
|
1007
|
+
- ❌ Recolor-on-filter. Cor segue entidade.
|
|
1008
|
+
- ❌ 9ª cor gerada além dos 8 slots categóricos.
|
|
1009
|
+
- ❌ Rainbow em sequential. 1 hue, light→dark.
|
|
1010
|
+
- ❌ Status color como série de dado. Reservados.
|
|
1011
|
+
- ❌ Brand ember `--brand-500` como cor de série. É acento, não categoria.
|
|
1012
|
+
- ❌ Chart 3D, animação bounce, tooltip pesado com sombra colorida.
|
|
1013
|
+
|
|
450
1014
|
**Tipografia**
|
|
451
1015
|
- ❌ {{fonts.display}} em UI body. Só títulos h1/h2/h3, modal titles, brand.
|
|
452
1016
|
- ❌ {{fonts.ui}} em h1 grande de página — display font é {{fonts.display}}.
|
|
1017
|
+
- ❌ Display/serif no hero figure de chart. Mesma sans do resto.
|
|
453
1018
|
|
|
454
1019
|
**Motion**
|
|
455
1020
|
- ❌ Animação > 280ms em microinterações.
|
|
1021
|
+
- ❌ Animação > 400ms em entrada de chart.
|
|
456
1022
|
- ❌ Bounce/elastic em UI — só `--ease-spring` em entradas de modal.
|
|
457
1023
|
|
|
458
1024
|
---
|