---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 46
titulo: "Shell de aplicação — **`estável`** (v0.50) · SH1–SH15 · pattern F6 · suíte `suite-shell.mjs` 68/68 ✓ · render 18/0 · contraste 32/0 · **gate visual aprovado 2026-08-11 — FECHA O BLOCO 6A**"
sequencia: 48 de 98
bytes_do_corpo: 22141
md5_do_corpo: 5da3cf7ce2a1d12fd096d8f2cc7d7822
gerado_por: 06-validacao/geradores/gen-camada-ia.py
nota: fatia GERADA — o corpo abaixo é byte a byte o trecho do canônico; edite o canônico, nunca esta fatia. Canônico inteiro em https://ds.seed.eng.br/01-canonicos/seed-componentes.md
---
## 46. Shell de aplicação — **`estável`** (v0.50) · SH1–SH15 · pattern F6 · suíte `suite-shell.mjs` 68/68 ✓ · render 18/0 · contraste 32/0 · **gate visual aprovado 2026-08-11 — FECHA O BLOCO 6A**

> **Natureza:** pattern de **COMPOSIÇÃO** do F6, não componente novo — consome menu/dropdown
> (§35), tabs (§34), breadcrumb (§36), command palette ⌘K (§39), drawer (§31), avatar (§32),
> badge (§21), lista (§28), central de notificações (§33) e o botão (§1). **Nenhum componente
> nasce aqui.** É a mesma natureza do §33, o primeiro pattern F6 do sistema, e a fronteira que o
> Bloco 5 declarou desde 2026-08-06: *"sidebar/topbar é shell do F6, consome este bloco"*.
>
> **PRINCÍPIO-MÃE, decidido com o Rafael em 2026-08-11: CONTRATO POR REGIÃO, COMPOSIÇÃO LIVRE.**
> As cinco regiões são especificadas até o último detalhe; **qual delas o produto liga, e o que
> coloca dentro, é decisão do projeto do ERP — não do Design System.** *Racional dele, adotado:*
> engessar a composição limita em vez de ajudar, e não gera problema de padronização — o que
> carrega a identidade é cor, tipografia, traço, densidade e comportamento do item ativo, não o
> arranjo das caixas. *O que o DS não abre mão:* **cada região se comporta igual em toda
> composição** (SH14) e **acessibilidade não é opcional em arranjo nenhum** (SH2, SH5, SH7, SH8).
>
> **Escopo do produto, decidido em briefing antes da pesquisa:** o ERP é **web, responsivo,
> desktop-prioritário**, usado pela equipe — escritório como uso principal, campo como uso real.
> O menu **muda por perfil**. A navegação é **por ÁREA DO NEGÓCIO** (processo), não por
> ferramenta. O app nativo do cliente é **fronteira declarada**: quando existir, o DS entrega
> tokens e componentes, nunca layout de navegação, porque brigar com a convenção do iOS e do
> Android é perder. O site institucional é o **bloco 6B**, e nasce mobile-first.
>
> **Base (3 rodadas encadeadas, 2026-08-11):** **R1 canon interno** — o §33 como molde de pattern
> F6; o Bloco 5 inteiro como insumo (o shell não inventa, arruma); MN1 (as quatro saídas
> semânticas) e MN6 (comando indisponível fica visível), que o SH6 precisa distinguir; DW1 (os
> dois regimes do drawer) e CN6 (o precedente de standard); a escala de sobreposição
> 60<65<70<75<80; o §40 (densidade compacta medida em 33px). **R2 mercado e stack** — componente
> Sidebar oficial do shadcn/ui, que é o consumidor real do Lovable, com `SidebarProvider` e os
> três modos `offcanvas`/`icon`/`none`; blocos de sidebar colapsável com `Collapsible` do Radix e
> threading por `border-l`; prática consolidada de SaaS enterprise (topo para contexto global,
> lateral para navegação primária, porque as duas camadas fazem trabalhos diferentes e param de
> disputar espaço); SAP Fiori launchpad shell bar (logo, back, título, busca corporativa,
> notificações, Me Area). **R3 normas e fora-do-circuito** — ARIA11/W3C sobre landmark repetido
> exigindo nome único; MDN sobre `role="navigation"`; `aria-current="page"` como critério AAA de
> baixo custo; o corpus de acessibilidade de SPA (foco preso na navegação após troca de rota é o
> defeito nº 1, e o alvo do foco não pode ser landmark, link nem botão); Material Design
> navigation rail (3–7 destinos, posicionado abaixo da top bar). Consolidado aprovado pelo Rafael
> em 2026-08-11.
>
> **REFERÊNCIA DE ARQUITETURA, e o que dela foi herdado.** O Rafael apresentou um layout de
> referência (`preview-clientes-v2.html`, 58.741 B, md5 `69f00537763e14ef907d2f8130c26a92`) no
> padrão de um produto de mercado, com instrução explícita: **"apenas ideia para entender o
> layout de construção"**. Regra que sai daqui e vale para todo bloco futuro: **de um layout de
> referência herda-se ESTRUTURA e COMPORTAMENTO; cor, tipografia e forma vêm do DS, sempre.**
> *Herdado:* o rail como camada acima da sidebar · a sidebar ser contextual ao rail · árvore de
> quatro níveis com fio de conexão · busca fixa e centralizada com o atalho impresso dentro ·
> seletor de contexto no topo à esquerda · contadores no fim da linha · ações que aparecem no
> hover · densidade compacta. *Descartado por não ser do sistema:* rail preto puro `#000000` (a
> superfície mais escura do DS é `#0B1419`), verde de sucesso `#2DBA7C` (o do DS é turquesa),
> gradiente terminando em `#D94B7D`, badge rosa, e neutros deslocados (`#9AA8B0` onde o DS tem
> `#90A6B3`; `#CBD3D8` onde tem `#ACBECA`) — a mesma deriva de hex digitado que custou as erratas
> E4 e E16 na Fase 5.

### 46.1 Decisões SH1–SH15

> **O contrato de montagem de tela (ex-SH16) é LEI DO SISTEMA e vive no `seed-composicao.md`
> §1 (CP1)** — canvas `surface-subtle`, peça `surface-raised` + `radius-lg` + par sombra+anel,
> calha `sp-3`, nada encosta em nada. **A exceção nomeada do rail foi SUPERSEDIDA no gate de
> 2026-08-15** (*"um bloco montado como os outros, todos independentes, igual o ClickUp"*): o
> rail é peça sobre o canvas como as demais — radius-lg, calha nos quatro lados, sem borda
> (a própria cor é a fronteira: 5,82/8,62 claro · 2,70/1,82 escuro contra o canvas). Registro
> completo no CP1 do `seed-composicao.md` v1.4. O shell é a primeira instância
> do contrato, não a dona dele (supersede SUP-1, 2026-08-14; fecha a errata E-CF-03 — o
> cabeçalho desta seção dizia "SH1–SH14" com a tabela terminando em SH15).

| # | Decisão | Porquê | Descartado |
|---|---|---|---|
| **SH1** | **Cinco regiões nomeadas: rail · topbar · sidebar contextual · conteúdo · painel lateral.** Obrigatórias: **conteúdo** + **ao menos uma região de navegação**. As demais o produto liga conforme a tarefa | Composição é escolha de tarefa, não de identidade. O §33 já opera assim: não obriga ninguém a ter central de notificações — diz que, **se** tiver, é assim | Composição fixa em N arranjos canônicos (engessa arquitetura de produto de dentro do DS) · nenhuma região obrigatória (tela sem navegação nem landmark é beco sem saída) |
| **SH2** | **Toda região de navegação é landmark com NOME ACESSÍVEL ÚNICO**, e o nome **não contém a palavra "navegação"** — o leitor de tela já anuncia o papel. Nomes canônicos: "Áreas" (rail) · "Seções" (sidebar) · "Trilha" (breadcrumb) · "Conta" (menu do avatar) | ARIA11/W3C: landmark repetido exige nome único e significativo. O shell tem **três a quatro** `nav` simultâneos — sem nome, o usuário de leitor de tela recebe uma lista de navegações idênticas e não tem critério para escolher | `nav` anônimo · nome contendo "navegação" (redundância verbosa) · nomes iguais em regiões diferentes |
| **SH3** | **RAIL — contrato:** destinos de topo · **3 a 12** · **largura 80px** · ícone do set §45 **+ rótulo sempre visível, ≤9 caracteres por palavra** · um ativo por vez · ordem estável · **altura total, à esquerda da topbar** | O Material limita a 3–7, mas calibrado para tablet, com o rail substituindo a barra inferior; num ERP de desktop o rail é a espinha do produto. **Teto de 12 declarado como calibrado aqui, NÃO derivado de norma.** **Largura e limite de caracteres são MEDIDOS** (`medir-rail.mjs`): Montserrat 9px caixa-alta mede **7,01px por caractere**; um rail de 64px tem 52px úteis e comporta 7 caracteres — três dos seis rótulos de exemplo transbordavam. 80px dão 68px úteis = **9 caracteres**. *O rail cedeu de 64 para 80px porque "Comercial" (9) é nome legítimo de área de ERP — quem tem de caber é o negócio.* Rótulo truncado não é rótulo, logo o limite recai sobre a **palavra**. Altura total porque o rail é o nível MAIS ALTO de navegação — ficar dentro da moldura da topbar contradiz a hierarquia que ele representa | Rail só com ícone (rótulo em tooltip não é descoberto; o §45 mede glifos a 24px, não a 24px sem contexto) · rail abaixo da topbar (a posição que o Material recomenda, semanticamente errada aqui) · teto de 7 (herdaria calibração de outro contexto — o erro da errata E7) |
| **SH4** | **SIDEBAR — contrato:** árvore de **até 4 níveis**, contextual à região acima. Quatro travas: **(a)** um ramo aberto por vez · **(b)** o ramo do item ativo abre sozinho ao carregar · **(c)** em modo estreito, níveis 2+ abrem em **flyout** · **(d)** quinto nível vira **tabs §34 dentro da tela** | O teto de 2 níveis foi proposto e **derrubado pelo Rafael com contraexemplo** (*Financeiro → Faturamento → Faturas emitidas*), e a referência confirma 4 na prática. As travas existem porque profundidade sem elas vira parede de 60 linhas. O flyout é **disclosure de links**, nunca `role="menu"` — distinção que o MN1 pagou caro para estabelecer | Árvore livre sem travas · nível 3 como navegação secundária dentro da página (solução de Fiori e Carbon; cai porque *explorar é ver a estrutura sem entrar nela*, e navegação secundária só aparece depois de já ter chegado) |
| **SH5** | **Item ativo: `aria-current="page"` + marca que SOBREVIVE AO GRAYSCALE** — barra lateral de 3px mais peso tipográfico, nunca só fundo colorido | Indicar o item atual exige as duas coisas: destaque visual e `aria-current` no link. E o **DF4** faz do grayscale gate estrutural do sistema — fundo colorido sozinho morre em cinza e em mono impresso | Só fundo colorido · só `aria-current` (invisível para quem enxerga) · negrito sozinho (some em densidade compacta) |
| **SH6** | **Navegação por perfil OMITE o item; ação indisponível MOSTRA com motivo** | O **MN6** decidiu que comando indisponível fica visível, com motivo, porque *"menu é inventário de comandos"*. Navegação é outra coisa: mostrar "Faturamento" a quem não pode entrar não ajuda ninguém **e revela a estrutura interna da empresa**. A distinção preserva o MN6 no domínio dele | Item bloqueado na sidebar (ruído permanente + vazamento organizacional) · omitir também na ação (o usuário não entende por que a operação falhou) |
| **SH7** | **Troca de rota move o foco para o CONTEÚDO** (`tabindex="-1"`, nunca o landmark em si), com **live region persistente** anunciando a tela | É o defeito nº 1 de aplicação de página única: o foco fica preso na navegação, o conteúdo troca e o usuário de leitor de tela não sabe. O alvo do foco **não pode** ser landmark, link nem botão — as três quebram por evidência documentada. O DS já tem o protocolo de live region no §1.13 | Não fazer nada (o comportamento padrão, e é o defeito) · focar o `main` como landmark (lê o conteúdo inteiro) · focar o primeiro link (some do fluxo de tabulação ao receber `tabindex="-1"`) |
| **SH8** | **Skip link como PRIMEIRO elemento focável**, visível ao receber foco | WCAG 2.4.1. Num ERP com dezenas de itens de menu, tabular por toda a navegação a cada tela é inviável — e o SH4 permite quatro níveis | Skip link permanentemente oculto (existe e não funciona) |
| **SH9** | **BUSCA fixa e centralizada na topbar, com o ATALHO IMPRESSO DENTRO DO CAMPO.** Ela abre a command palette §39 — é a mesma busca, com dois caminhos de entrada. **Escopo: navega, não consulta dado** | *Supersede da decisão anterior deste consolidado, que tirava o campo e deixava só o atalho.* O campo torna o atalho **descoberto por quem lê**, em vez de decorado por quem foi treinado — e a referência do Rafael mostrou isso antes de a spec ser escrita. Busca de registro depende de índice no ERP: é produto, não DS | Só o atalho (aposta em treinamento) · campo que não abre o §39 (dois mecanismos de busca, duas fontes de verdade) · busca de registro no shell (fronteira de produto) |
| **SH10** | **TOPBAR — contrato de três zonas:** identidade e contexto à **esquerda** · busca ao **centro** · ações globais e conta à **direita**. Slots nomeados; o produto escolhe o que entra. **O título da tela vive no CONTEÚDO, não na topbar** | Prática consolidada de produto enterprise: topo para contexto global, lateral para navegação primária — assim as duas camadas param de disputar o mesmo espaço. O Fiori põe o título na shell bar e paga com uma barra que faz duas coisas | Título na topbar (duplica o `h1` do conteúdo e cria duas fontes de verdade sobre onde o usuário está) · topbar com conteúdo livre (vira depósito) |
| **SH11** | **Seletor de contexto existe, no topo à esquerda** | Estava reservado e desligado por falta de decisão de produto; a referência do Rafael decide que existe | Seletor dentro da sidebar (some quando a sidebar some) · nascer sem ele (redesenho depois) |
| **SH12** | **Em tela estreita, rail e sidebar colapsam num ÚNICO drawer §31 em regime MODAL** | O CN6 escolheu **standard** porque o caso é *consultar sem sair da tela*. Navegação é o oposto: você escolhe e sai. Em tela estreita o drawer cobre o conteúdo — página interativa atrás seria mentira semântica, e o APG só admite `aria-modal` quando o fundo está de fato bloqueado | Drawer standard (incoerente com a tarefa) · rail persistente no celular (come 64 dos 360px) · sidebar espremida (não vira app, vira ERP ruim no celular) |
| **SH13** | **PAINEL LATERAL de detalhe: drawer §31 em regime STANDARD** — inspecionar um registro sem sair da lista | Aqui o caso **é** consulta lado a lado: ler → navegar à fonte → comparar. É o caso central que criou o regime standard no DW1 e que o CN6 já exerceu | Modal (perde o contexto da lista, que é justamente o que motivou o painel) · navegação para tela cheia (perde a posição de rolagem e a seleção) |
| **SH15** | **CHROME NÃO SEGUE O TEMA.** A superfície do rail e a tinta sobre ela são **fixas nos dois temas** — desde a CP-P3 (2026-08-14) a superfície é o gradiente `--seed-rail-background` (`turquesa-700 → turquesa-800`, CP20 adotado no gate G2) com tinta branca, e o item ativo é a **pílula clara** `turquesa-100` com tinta `turquesa-900` (SH15-b) | **Achado da medição, não do desenho.** O rail consumia `surface-inverse`, que significa *"o oposto do tema"*: no escuro ele virava uma barra **clara** (`#F2F6F9`) dentro de uma interface escura, e o rótulo sobre o item ativo media **1,48**. O rail não quer ser o oposto do tema — quer ser estruturalmente escuro **nos dois**, como o chrome de aplicação que ele é. É o simétrico do **DG12** da Fase 5 (*tinta sobre dado não segue o tema, porque o objeto contrastado é claro nos dois modos*). Medido no estado atual: branco sobre os **dois extremos do gradiente** 6,32/9,37 · pílula 5,31/7,87 de fronteira · tinta da pílula 11,37. *(Errata **E-CF-05** fechada na v0.66: esta linha ainda descrevia o valor da era `cinza-900` — "e o item ativo usa `#006C62` fixo" — duas gerações atrás do artefato: a E-CF-04 consolidou o parágrafo do §46.2 e esqueceu esta linha. A REGRA nunca mudou; o VALOR mudou duas vezes: cinza-900 → turquesa-700 (v6.3) → gradiente (CP-P3).)* | `surface-inverse` (inverte por definição — era o defeito) · rail claro no claro e escuro no escuro (perde a âncora visual que faz o chrome ser reconhecível entre temas) |
| **SH14** | **Uma região NUNCA faz o trabalho de outra.** Se rail e sidebar coexistem, o rail é destino de topo e a sidebar é contexto | Duas navegações com o mesmo papel deixam o usuário de leitor de tela sem critério de escolha — quebra o SH2 por dentro. É a trava que permite a composição ser livre sem virar deriva | Sidebar como segundo rail · rail com itens de contexto |

### 46.2 Anatomia, tokens e fronteiras

**Rail:** largura **80px** (SH3 — medido: 68px úteis = 9 caracteres; "Comercial" cabe); superfície
**fixa nos dois temas** (SH15 — o rail NÃO consome `surface-inverse`, que foi o defeito medido a
1,48), hoje o **gradiente da rampa da marca** via semântico próprio `--seed-rail-background`
(`turquesa-700 #006C62 → turquesa-800 #005048`; CP20 do `seed-composicao.md`, **adotado no gate
G2 de 2026-08-14 e executado na CP-P3** — extremos medidos 6,32/9,37, tinta passa nos dois, nunca
na média); hover e pressionado do item consomem os overlays de chrome do SUP-6
(`--seed-chrome-overlay-hover/-active`, medidos **em composição**: 4,88/6,82 e 4,68/6,50);
ícone 24px do §45 + rótulo em micro-caps; item ativo pela regra do SH5; alvo de toque ≥44px.
*(Errata E-CF-04 fechada na v0.65: este parágrafo dizia 64px, `surface-inverse` e implicava
`cinza-900`. Atualizado de novo na v0.66 pela CP-P3: a redação "gradiente admitido — adoção
pendente de gate visual" ficou falsa após o gate.)*
**Topbar:** altura 60px; `surface-raised` com borda inferior `border-subtle`; z-index **60** (a
mesma faixa de chrome da escala 60<65<70<75<80 fixada no Bloco 4). **Sidebar:** largura 280px,
`surface-page`; indentação progressiva com fio de conexão em `border-subtle`; contador opcional
no fim da linha em mono; linha na densidade **compacta** do §40 (33px medidos), com alvo real de
toque garantido pela linha inteira, como no §28. **Conteúdo:** `main` com `tabindex="-1"` para o
SH7. **Painel lateral:** §31 integral em standard, z-index 65.

**Nenhum par de cor novo** — mas **compor pares medidos separadamente não garante que a
combinação passe**, e o `contraste-shell.py` provou isso: a primeira execução deu **22 PASS ·
8 FAIL**. Correções, todas por medição: o rail deixou de consumir `surface-inverse` (SH15) · o
contador e o *placeholder* saíram de `text-muted` (3,38 e 3,11 no claro) para `text-secondary`
(6,55 e 6,03) · o item ativo da sidebar deixou de ser texto de marca (4,23) e passou a **texto
primário com barra em `text-brand`** — a cor não carrega o estado, quem carrega é a barra e o
peso (SH5) · a sigla do seletor de contexto saiu de branco sobre `surface-brand` (2,71) para
branco sobre `surface-brand-deep` (6,32). Placar final: **32 PASS · 0 FAIL**.

> **PENDÊNCIA SH-P1 — buraco na camada semântica, achado por este bloco.** **Nenhum token
> semântico de borda passa 3:1 contra `surface-raised` no tema claro:** `border-default` mede
> **1,49** e `border-strong` **2,53**. O campo de busca precisa de contorno que o identifique
> como componente (1.4.11), e a única saída medida foi consumir o **primitivo `cinza-500`**
> (3,38 no claro · 4,50 no escuro). Isso é **empréstimo declarado**, não regra nova — e viola a
> lei "componente consome semântico". *A correção certa é um token semântico novo na camada 2*,
> e ela não pertence a este bloco: mexer nos três gêmeos por causa do shell seria decidir a
> camada de tokens dentro de um pattern. Fecha quando a camada 2 for editada por outro motivo,
> pela regra GI2.
>
> **✅ FECHADA em 2026-08-14, pela via prevista (gatilho GI2 + decisão do Rafael: *"vamos
> resolver logo"*):** a camada 2 foi editada pela CP-P3 (gêmeos v1.11) e, na mesma janela, os
> gêmeos v1.12 promovem o empréstimo a semântico — **`--seed-border-interactive`** = `cinza-500`
> `#788F9D` nos dois temas, medido contra as **seis superfícies** onde borda de componente
> aparece (3,38/3,38/3,11 claro · 4,50/5,51/5,05 escuro, todos ≥3,0), slot dark declarado
> (coincidência medida, não invariância). O campo de busca do shell consome o semântico desde o
> preview v0.3 — **nenhum primitivo é mais consumido por exceção no §46**. *Alternativa
> descartada com número:* `cinza-600` também passa (3,21–4,74), mas mudaria a cor RENDERIZADA
> que o gate visual já aprovou, sem motivo — a pendência pedia promoção de expressão, não de
> valor. A metade "separação de peça" já havia fechado no CP17 (par sombra+anel).

**Fora do shell, declarado:** que menus existem e o que há dentro deles (**projeto do ERP**) ·
qual perfil vê o quê (**regra de negócio**) · persistência do estado da sidebar
(**produto — Lovable/Supabase**, mesma fronteira do CN4) · busca de registro (**produto**) ·
dashboard e composição de painel (**bloco 6C**) · site institucional (**bloco 6B**) · app nativo
do cliente (**fora do DS**: tokens e componentes sim, layout de navegação não) · **o que o slot
de IA da topbar abre** (sub-bloco próprio da F6 — o slot existe, o destino não é especificado
aqui).

**Consequência declarada da navegação por PROCESSO:** como o mesmo objeto é alcançável por mais
de um caminho, o **breadcrumb §36 deixa de ser decoração** e passa a responder *por qual caminho
eu cheguei* — é ele que desambigua, não a sidebar.

### 46.3 Os 7 testes

1. **Nenhum par de cor novo**; todos herdados e medidos.
2. **Item ativo nunca depende só de cor** — barra + peso + `aria-current` (SH5).
3. **Grayscale:** rail, sidebar e ativo permanecem legíveis (DF4 como gate estrutural).
4. **Regra do um:** um item ativo por região; uma região por papel (SH14).
5. **Landmarks:** três a quatro `nav` simultâneos, todos com nome único, nenhum contendo a
   palavra "navegação" (SH2).
6. **Troca de rota:** foco no conteúdo e anúncio na live region, sem foco em landmark, link ou
   botão (SH7); skip link é o primeiro focável (SH8).
7. **360px:** rail e sidebar colapsam em drawer modal único; nada transborda; alvos ≥44px (SH12).

*(Estado: **`estável` desde 2026-08-11**, por "aprovo" explícito do Rafael após o gate visual
sobre o preview v0.1. **Quatro camadas cumpridas:** `suite-shell.mjs` **68 PASS · 0 FAIL** —
*prova de que as guardas são reais:* contra um preview com 5 defeitos deliberados, reprova em
**8**; `render-shell.mjs` em Chrome real **18 PASS · 0 FAIL**; `contraste-shell.py` **32 PASS ·
0 FAIL** após as correções que a própria medição exigiu; e o gate visual humano. **Pendência que
o bloco levou consigo: SH-P1**, que é da camada de tokens, não do shell — **fechada em
2026-08-14 pelos gêmeos v1.12** (`border-interactive`; fechamento completo na própria
pendência, acima).)*

---

