---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 71
titulo: "HV1 — a RESPOSTA AO PONTEIRO e o PRESSIONADO DISTINTO · regra transversal (2026-08-19, sétima parte) · `validacao/guarda-resposta-ponteiro.mjs`"
sequencia: 77 de 98
bytes_do_corpo: 12805
md5_do_corpo: dcc00badafdad2f7a1153d2d855ceb00
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
---
## 71. HV1 — a RESPOSTA AO PONTEIRO e o PRESSIONADO DISTINTO · regra transversal (2026-08-19, sétima parte) · `validacao/guarda-resposta-ponteiro.mjs`

> **Escrito em 2026-08-19.** Esta seção existe porque **o Rafael recusou uma pergunta que eu não devia
> ter feito** — e a recusa é uma correção de método, não de gosto.

### 71.1 A pergunta que criou o contrato

Na folha do gate v13.5 eu registrei um achado e o classifiquei como *"decisão de aparência, e aparência
é sua"*: o sino e o botão de menu (☰) da barra superior do `tela-shell` **não mudavam nada quando o
mouse passava em cima**. O Rafael respondeu:

> *"me questiono, nao deveria existir uma ação/efeito para cada tipo para existir essa diferenciação?
> o que o mercado sugere? pesquise e aplique, nao é decisao minha."*

> **A lição, e ela é sobre a fronteira entre gosto e engenharia:** eu tratei como *preferência* uma
> pergunta que a **pesquisa** responde. A regra deste projeto já dizia *"pergunta que a pesquisa
> responde não é pergunta"* — e eu a violei empurrando para o gate uma decisão que tem **canon de
> mercado convergente, resposta verificável e norma aplicável**.
> **Aparência é do Rafael. CONVENÇÃO DE INTERAÇÃO é pesquisa.** Distinguir as duas é o trabalho.

### 71.2 O RITO de três rodadas, com as fontes

| rodada | fonte | o que ela estabelece |
|---|---|---|
| **R1 canon** | Material Design 3 — *state layers* | estado é um **véu** com **opacidade por estado**: camadas **distintas**, não a mesma |
| **R1 canon** | Adobe Spectrum — *states registry* | `hover` e `down` (pressionado) são **estados INDEPENDENTES** |
| **R1 canon** | eBay Playbook | **hover 8%, press 12%** — o pressionado é o sobrevoo **mais 4%**; a mudança tem de ser *"subtle and distinct"* e *"consistent across components"* |
| **R2 mercado** | Sainsbury's Design System | seis estados de fundação, com **pressed** separado de hover, os dois "a darker shade of the brand colour" — mesma direção monotônica |
| **R2 mercado** | Carbon (IBM) | estado interativo tem **nome de token de propósito** (`layer-hover`, `background-hover`, `field-hover`), não valor solto |
| **R2 stack** | **shadcn/ui — o stack de produção do ERP da SEED** | define `hover:` em todas as variantes de botão e **não define `active:`**. *O stack mais usado do mercado **subespecifica o pressionado** — e este acervo herdou isso* |
| **R3 normas** | WCAG 2.2 | **a WCAG NÃO exige estado de sobrevoo**: *"WCAG does not require user interface components to have hover states"* |
| **R3 normas** | SC 1.4.3 e SC 1.4.11 | **se o estado existe**, a tinta tem de manter o piso de contraste contra o **NOVO** fundo: ≥4,5 com texto, ≥3,0 se for só ícone |

> **A conclusão separa o que é norma do que é convenção — e é essa separação que o contrato carrega:**
> **HV1-a** e **HV1-b** são **convenção de mercado**, canon convergente em cinco fontes, logo decisão de
> **engenharia**. **HV1-c é NORMA**, e é uma obrigação que só nasce **porque** se acrescentou o estado:
> *quem cria um fundo novo cria a obrigação de medir o contraste sobre ele.*
> É por isso que as três moram na **mesma** guarda: separá-las permitiria acrescentar hover e esquecer o
> contraste dele — que é exatamente a pendência **CT-P7**, aberta na parte anterior.

### 71.3 O contrato

| # | Cláusula | Régua | Natureza |
|---|---|---|---|
| **HV1-a** | O controle **ativo** responde ao ponteiro | a captura do elemento sob `:hover` **difere** da captura em repouso | convenção |
| **HV1-b** | O **pressionado** é distinto do sobrevoo | a captura sob `:active` **difere** da captura sob `:hover` | convenção |
| **HV1-c** | A **tinta sobrevive** ao fundo novo | `color` × fundo resolvido ≥ **3,0** (só ícone, SC 1.4.11) ou **≥4,5** (com texto, SC 1.4.3), no sobrevoo **e** no pressionado | **norma** |

**Componente INATIVO está ISENTO e sai CONTADO.** Controle `disabled`/`aria-disabled` **não deve**
responder ao ponteiro — exigir-lhe resposta seria exigir mentira. É a mesma isenção que a SC 1.4.3 e a
SC 1.4.11 dão ao componente inativo.

**Fronteira declarada, e é DECISÃO, não economia: a guarda roda a 1440px.** `:hover` é capacidade de
**ponteiro**; em aparelho de toque não existe sobrevoo, e a forma correta de tratar isso em CSS é
`@media (hover: hover)`. Medir sobrevoo numa janela de 390px de navegador de mesa mediria uma situação
que o usuário de celular nunca vive. Cobrir toque é medir **outra coisa** — o pressionado por toque — e
é a pendência **HV-P2**.

### 71.4 O JUIZ É O PIXEL — e isso foi comprado com um defeito de instrumento

A primeira versão da guarda julgava por `getComputedStyle`: montava uma assinatura com as propriedades
que pintam e reprovava quando ela não mudava. **Na primeira execução sobre o acervo, a própria guarda se
desmentiu:** o `button.linha-abrir` do `tela-tabela` saiu com assinatura **idêntica** entre repouso e
sobrevoo, e as duas capturas do elemento eram **diferentes**. A resposta visual estava fora do alcance da
assinatura — no fundo do **ancestral** (`tr:hover` pinta a linha inteira), em `::before`/`::after` e em
descendentes mais fundos que o primeiro nível.

> **LIÇÃO, e ela vale para toda guarda desta casa: propriedade computada do ELEMENTO não descreve a
> APARÊNCIA do elemento.** O que o usuário vê é a composição — ancestral, pseudo-elemento, descendente,
> empilhamento. A assinatura mede o que o CSS **declara** no nó; o contrato fala do que a tela
> **mostra**. **Quando o contrato é sobre aparência, o juiz é o pixel.**

A guarda captura o elemento nos **três** estados e compara os **bytes**. A assinatura de estilo continua
sendo calculada, mas virou **diagnóstico**, e conta dois casos que o pixel sozinho não sabe nomear:
**"declarou e não aparece"** (regra de hover que o olho não vê) e **"apareceu e não declarou"**.

⚠ **O REPOUSO é medido com o ponteiro FORA DA PÁGINA**, em `(-5, -5)`, e isso foi **verificado**: ali
`document.querySelectorAll(':hover')` devolve **zero** elementos, enquanto o canto inferior esquerdo do
`tela-shell` deixa **2** e o canto superior direito deixa **3**. *Repouso medido com o ponteiro dentro
da página não é repouso.*

### 71.5 O CENSO — o tamanho real do problema, medido

**1.410 controles ATIVOS, 51 arquivos, 2 temas, 1440px, 1.410 medições efetivas, 4.230 capturas:**

| cláusula | reprovações | proporção |
|---|---|---|
| **HV1-a** — sem nenhuma resposta ao ponteiro | **619** | **44%** dos controles ativos |
| **HV1-b** — pressionado indistinguível do sobrevoo | **1.350** | **96%** |
| **HV1-c** — contraste abaixo do piso no estado novo | **90** | **6%** — e estes são **violação de norma HOJE** |

**Placar: 0 PASS · 90 FAIL · 12 `[n/a]`.** *Nenhum dos 51 arquivos passa.* E isso confirma, com número,
o que a rodada R2 previu: **o stack de mercado subespecifica o pressionado, e o acervo herdou.**

As classes mais frequentes, para que a fila de trabalho já esteja pronta:
**HV1-a** — `button` (174) · `button.seed-btn` (72) · `summary` (48) · `button.no` (26) · `button.b-larg` (24).
**HV1-b** — `button` (196) · `button.seed-btn` (120) · `button.btn` (88) · `button.icell` (68) · `summary` (48).
**HV1-c** — `button.page-btn` (28) · `button.btn` (22) · `button.linha-abrir` (20) · `button.acc-trigger` (12) · `button.btn-focus` (4) · `button.pg-btn` (2) · `button.fachada` (2).

### 71.6 A GRAMÁTICA — HV1-d, e os dois tokens que nasceram

**Gêmeos de token vão a v1.18.** Dois semânticos de **propósito**, **sem nenhum hex novo**: os valores
são os da escala de superfície que o acervo já pratica.

| token | claro | escuro | propósito |
|---|---|---|---|
| `--seed-action-neutral-hover` | `#F2F6F9` | `#141D23` | sobrevoo de controle **neutro**, sobre qualquer superfície neutra |
| `--seed-action-neutral-active` | `#E3EBF0` | `#0B1419` | **pressionado** de controle neutro — um passo **adiante**, na mesma direção |

> **Por que NÃO se reusou `action-ghost-hover`, e o motivo é medido:** no tema escuro ele vale `#1D272D`,
> que é **exatamente** `surface-raised`. Um controle neutro **posado sobre superfície elevada** — a barra
> superior do shell — teria hover **invisível** no escuro. *O token não está errado para o propósito
> dele (botão fantasma sobre a PÁGINA); está errado para este outro propósito.* Consumidores medidos de
> `action-ghost-hover` hoje: **2 arquivos** (`banco-componentes`, `banco-tokens`), nos dois sobre a
> página — nenhum sobre superfície elevada. Nada muda para eles.

**Gramática por família de base:**

| base do controle | `:hover` | `:active` |
|---|---|---|
| superfície **neutra** | `action-neutral-hover` | `action-neutral-active` |
| **marca chapada** (`surface-brand-strong`, o `.avatar`) | `surface-brand-deep` + `text-on-brand-deep` (par medido **6,32** claro / **9,37** escuro) | o **mesmo** fundo + **anel interno** de `text-on-brand-deep` — muda o pixel **sem trocar o fundo**, o que preserva o contraste já medido |
| **rampa da marca** (o `.rail-item`) | `chrome-overlay-hover` | `chrome-overlay-active` — já existiam, véu branco medido **em composição** |

> **Alternativa descartada 1 — véu (`box-shadow: inset`), que é o mecanismo do Material Design 3.**
> Descartada por motivo **medido, não estético**: os instrumentos desta casa leem `background-color` para
> compor contraste (o `fundoResolvido` da guarda HV1 **aborta** em imagem/gradiente, e o
> `contraste-composicao` trata gradiente como caso especial). Um véu tornaria o contraste do estado
> **NÃO MEDÍVEL**. *Trocar um contrato medido por um contrato bonito é o oposto do que este projeto faz.*
> **Alternativa descartada 2 — `action-primary-active` no pressionado do avatar.** Medido: no tema
> escuro ele vale `#11B0A0` e o branco sobre ele mede **2,66** — reprovaria a SC 1.4.11.

### 71.7 O que a execução tocou nesta parte, e o defeito que a guarda pegou EM MIM

Bloco HV1 acrescentado a **`shell-template.html`** (`.topbar button`, `.topbar .avatar`), com os quatro
nomes de token na lista `NOMES` do `gen-shell.py`. **`tela-shell.html` regerado.**

| medida | antes | depois |
|---|---|---|
| HV1-a no `tela-shell`, por tema | **10** | **8** |
| HV1-b no `tela-shell`, por tema | **16** | **12** |
| HV1-c no `tela-shell` | 0 | **0** |
| CT1 no `tela-shell` (regressão) | 8 · 0 | **8 · 0**, 2 temas × 4 estados |

> **A guarda pegou, no mesmo minuto, um defeito que eu acabei de introduzir.** A primeira versão do
> bloco escrevia `.avatar:hover` (especificidade **0,2,0**), que **perde** de
> `.topbar button:hover` (**0,2,1**). Resultado: o avatar recebia o fundo **neutro** e ficava com tinta
> **branca** sobre `#F2F6F9` — a guarda mediu **1,09** contra o piso 4,5 e reprovou na hora.
> `.topbar .avatar` (**0,3,1**) conserta. *Este é o argumento inteiro a favor de a cláusula de contraste
> morar na MESMA guarda que a de resposta ao ponteiro: acrescentar estado é criar fundo novo, e fundo
> novo pede medida — no mesmo passe, não na próxima sessão.*

### 71.8 Pendências

| # | Pendência | Por que fica |
|---|---|---|
| **HV-P4** | **A gramática HV1-d ainda não foi aplicada ao acervo inteiro**: 619 casos de HV1-a e 1.350 de HV1-b seguem abertos fora do `tela-shell` | É mudança transversal em ~34 artefatos e 20 moldes, e cada um exige regeneração **mais** medição de contraste do estado novo. **A fila está pronta e impressa por classe no §71.5** — não é buraco, é lista de trabalho com número. Fazer às pressas produziria o defeito que a guarda acabou de pegar em mim, 34 vezes |
| **HV-P5** | Os **90 casos de HV1-c** são **violação de norma HOJE** e concentram-se em **7 classes** (`page-btn`, `btn`, `linha-abrir`, `acc-trigger`, `btn-focus`, `pg-btn`, `fachada`) | **É a prioridade absoluta da próxima parte**, acima de HV-P4: ali o hover **já existe** e **já mata** o contraste. Sete classes, não 1.350 controles |
| **HV-P1** | `<a href>` sem classe de botão **não entra** na população | link tem convenção própria (sublinhado) e é população inteira diferente |
| **HV-P2** | **toque não é medido** | `:hover` é capacidade de ponteiro; cobrir toque é medir o pressionado por toque, que é outra régua |
| **HV-P3** | a guarda compara **aparência**, não **legibilidade da mudança** | uma diferença de 1 unidade num canal de cor passa em HV1-a e é invisível ao olho. O piso perceptual não existe ainda |

---

