Ir ao conteúdo
SEED engenharia

Tokens

2. Camada 1 — Primitivos

seed-tokens.md v1.40 · §02seção 3 de 2302-camada-1-primitivos.md · MD5 2b940971

Em uma frase: Camada 1: rampas de 10 stops geradas em OKLCH com os hex de marca ancorados exatos, mais tipografia, espaço, raio, movimento e elevação.

Vocabulário desta seção: rampa · stop · OKLCH

2.1 Rampas tonais (o coração da entrega)#

Cada cor de marca virou uma rampa de 10 stops (50→900). Método, para auditoria e regeneração futura:

  • Espaço de cor OKLCH (perceptualmente uniforme): garante que "400" tenha o mesmo peso visual em qualquer rampa.
  • Curva de luminosidade compartilhada entre todas as rampas (L 0.972 no stop 50 → 0.294 no 900), com chroma em sino (pico no meio, dessaturando nas pontas).
  • Âncora automática: cada hex canônico de marca foi cravado EXATO (sem alteração de um dígito) no stop cuja luminosidade da curva é a mais próxima da sua luminosidade real. Os demais stops são interpolados.
  • Calibração funcional: o stop 600 de cada rampa foi verificado (e ajustado quando preciso) para contraste ≥ 4.5:1 com branco — é o stop que serve botões e texto funcional.
  • Monotonicidade verificada: luminosidade estritamente decrescente em todas as rampas (a v1 do algoritmo produzia inversões; corrigido).
Rampa 50 100 200 300 400 500 600 700 800 900
turquesa #E8FBF7 #CDF3EC #9CE4D8 #66D1C2 #11B0A0 ⚓ #00A192 #098475 ⚓ #006C62 #005048 #00352F
amarelo #FFF6D2 #FDEA9E #FAD61D ⚓ #DABA00 #BDA100 #A28A00 #877200 #6D5C00 #504300 #352C00
dourado #FFF4E4 #FFE6C0 #FECA76 #F9B11C ⚓ #D49400 #B67F00 #986900 #7B5500 #5B3E00 #3D2800
azul #ECF4FC ⚓ #CDF1FF #96E0FD #53C2E9 ⚓ #01B3E0 #0099C1 #007FA1 #006783 #004C61 #003241
cinza #F2F6F9 #E3EBF0 #C8D6DF #ACBECA #90A6B3 #788F9D #617683 ⚓ #4D606C #38464F #242E34
vermelho #FFF2F1 #FFE2DF #FFC2BD #FF9C95 #FC6F6A #D94545 ⚓ #C6393B #A5272A #7A1C1E #521112

⚓ = hex canônico de marca, preservado exato. Pantones (do Manual 2018, confirmados): Turquesa 3275C · Amarelo 115C · Verde 327C · Cinza 5487C · Dourado 7409C · Azul 2985C · Azul-claro 656C. CMYK no marca-seed.md.

2.1-b Branco e preto — as duas âncoras neutras (v1.35, MR-C = B)#

Além das rampas, o sistema tem duas âncoras neutras sem rampa: --seed-branco #FFFFFF (a segunda cor primária da marca) e --seed-preto #000000, o preto puro da impressão P&B (o mono-positivo da marca-seed.md §5.1). O --seed-preto nasceu na v1.35 por resposta dele à MR-P25 (MR-C: B, 2026-09-30): os arquivos monocromáticos oficiais de 03-assets/ pintavam #000001 e #FEFEFE (resíduo de exportação, 1 unidade de diferença por canal, ΔE76 0,40 e 0,35, abaixo do limiar de 2,3) e passam a pintar exatamente #000000 e #FFFFFF. Não é cor de interface: superfície e texto do produto continuam nos semânticos (seed-tokens.md §3).

2.2 Três descobertas estruturais (fatos, não opiniões — medidos em OKLCH)#

  1. O verde institucional #098475 É o turquesa-600. As duas cores "diferentes" da marca são a mesma rampa em stops diferentes — e o 600 é exatamente o stop de ação acessível (4.60:1 com branco). Consequência: o botão primário da SEED em fundo claro é o verde institucional, de graça, sem inventar cor nova. A rampa turquesa tem âncora dupla (400 e 600).
  2. O azul-claro #ECF4FC É o azul-50. Nunca foi uma oitava cor independente; era o primeiro stop da rampa azul. Absorvido como âncora do stop 50 (rampa azul tem âncora dupla: 50 e 300).
  3. O turquesa principal #11B0A0 é um stop 400, não 500. Sua luminosidade real (OKLCH L 0.712) o coloca no 400. Implicação prática de acessibilidade documentada na §5.

2.3 Vermelho funcional (adição, não é cor de marca)#

A paleta de 2018 não tem vermelho — mas nenhum sistema digital vive sem estado de erro. Em vez de inventar, formalizamos o #D94545 que o DS digital v1 já usava informalmente em .alert-danger (âncora do stop 500; o hover informal #c63838 morre, substituído pelo vermelho-600 #C6393B gerado). Classificação: cor funcional — proibida em material de marca (posts, capas, propostas), permitida apenas em estados de erro/perigo de interface e dataviz negativa.

2.4 Superfícies do modo escuro#

Quatro superfícies tintadas no hue do cinza da marca (OKLCH h≈235°, o azul-acinzentado do #617683), do fundo ao topo: page #0B1419 · default #141D23 · elevated #1D272D · overlay #273137. Nunca preto puro. Supersede: substituem os hex ad-hoc #0d1f25, #1d3138, #11272f da seção dark do seed-design-system.html v1 (mesma direção estética, agora derivados por método).

2.5 Tipografia#

  • --seed-font-sans: Montserrat (marca e interface; pesos carregados pelo sistema: 400/500/600/700 — o 300 fica no TTF para impresso e o itálico é oblíquo sintético; marca §4.1 pós V-FT2.3/V-FT2.4 = b, 2026-09-15). Regra de legibilidade: texto corrido longo usa Regular com line-height 1.65 — pesos médios em massa ficam monótonos nesta fonte.

  • --seed-font-mono: JetBrains Mono (pesos 400/500/700). Papel exclusivo: dados de medição (kWh, kWp, demanda), identificadores (UC, ART, nº de proposta), código, timestamps, acento em labels micro. Nunca em títulos ou parágrafos. Motivo da escolha: algarismos tabulares nativos (colunas de números alinham), maior nota de acessibilidade entre monos gratuitas, Google Fonts, licença aberta.

  • Escala (herdada do DS v1, mantida — decisão: a escala estava correta, o problema era aplicação): display 64/72 · h1 42 · h2 32 · h3 24 · h4 18 · body-lg 17 · body 14 · small 12 · caption 11 (SemiBold, UPPERCASE, tracking 2px).

  • Escala fluida (v1.2 — mobile/app): os 4 topos da escala respondem ao viewport via clamp(); de h4 para baixo, invariante. Valores: display clamp(2.5rem, 1.9rem + 2.6vw, 4rem) (40→64px) · h1 clamp(1.875rem, 1.58rem + 1.3vw, 2.625rem) (30→42px) · h2 clamp(1.5rem, 1.3rem + 0.87vw, 2rem) (24→32px) · h3 clamp(1.25rem, 1.15rem + 0.43vw, 1.5rem) (20→24px). Interpolação calibrada entre 360px (Android BR mais comum) e 1280px. Regra WCAG 1.4.4 embutida: a fórmula SEMPRE combina termo rem dominante + termo vw — clamp com vw puro não responde ao zoom do navegador e reprova em redimensionamento de texto 200%; o teste de zoom 200% faz parte do preview de cada bloco. Desktop puro pode continuar usando os valores fixos; peças de marketing usam a camada expressiva da Marca v5.0 normalmente.

  • Papéis tipográficos de interface — --seed-txt-* (v1.14, retrofit RV1–RV10, 2026-08-15; documentados aqui na v1.34, TK-P6). Um papel amarra tamanho + peso + altura de linha + espaçamento entre letras num conjunto só: tamanho sem altura de linha deixa o navegador decidir a altura (normal, ~1.2). No gêmeo CSS são quatro variáveis por papel; no JSON, um composto typography por papel no grupo semantic.typography-role (a correspondência entre os dois é o gate G4 da paridade-tokens.py). A escala --seed-fs-* acima continua valendo (site, e-mail, impresso, tipografia fluida); a camada de papel é para interface. O papel de cada um é o que os gêmeos escrevem (comentário do CSS e $description do JSON):

    Papel Variáveis CSS Tamanho · peso · altura de linha · espaçamento Papel escrito nos gêmeos
    titulo-tela --seed-txt-titulo-tela-size · --seed-txt-titulo-tela-weight · --seed-txt-titulo-tela-lh · --seed-txt-titulo-tela-ls 22px · 700 · 1.25 · -0.3px H1 da região de conteúdo. Único por tela — com uma exceção (LC-66, leva 50): o nome do produto que usa o DS sem a marca SEED, acima do cartão das telas fora do shell, usa o papel sem ser heading (marca-seed.md §5.7). (O peso era 800 até a v1.27, SH-P9: a casa não carrega a face 800 e o 800 sempre rendeu 700.)
    titulo-secao --seed-txt-titulo-secao-size · --seed-txt-titulo-secao-weight · --seed-txt-titulo-secao-lh · --seed-txt-titulo-secao-ls 16px · 700 · 1.3 · -0.1px Cabeçalho de peça, de grupo e de painel.
    corpo --seed-txt-corpo-size · --seed-txt-corpo-weight · --seed-txt-corpo-lh · --seed-txt-corpo-ls 14px · 400 · 1.5 · 0px Texto de LEITURA (parágrafo, estado vazio, nota). A altura de linha 1.5 é o piso do SC 1.4.12.
    corpo-denso --seed-txt-corpo-denso-size · --seed-txt-corpo-denso-weight · --seed-txt-corpo-denso-lh · --seed-txt-corpo-denso-ls 14px · 400 · 1.3 · 0px Texto de UI DENSA (célula de tabela, item de lista). Altura de linha apertada por decisão, nunca por omissão; o Carbon usa 1.28 no body-compact-01 pelo mesmo motivo.
    rotulo --seed-txt-rotulo-size · --seed-txt-rotulo-weight · --seed-txt-rotulo-lh · --seed-txt-rotulo-ls 12px · 600 · 1.35 · -0.15px Rótulo de controle, chip, contador, coluna. O espaçamento negativo é ajuste óptico: texto pequeno em peso alto empasta sem ele (medido no produto de referência).
    micro --seed-txt-micro-size · --seed-txt-micro-weight · --seed-txt-micro-lh · --seed-txt-micro-ls 11px · 700 · 1.3 · -0.2px Microrrótulo em caixa alta: rail, caption, cabeçalho de estatística.

    Motivo, como o comentário v1.14 do CSS o registra (números da época, não remedidos aqui): a auditoria-c31.mjs achou, em 21 artefatos, 1.482 nós de texto fora da escala, em 25 tamanhos distintos, e 1.356 nós (46%) com altura de linha normal; seis papéis porque o censo do produto de referência mostrou seis combinações cobrindo 95 de 158 nós.

  • --seed-font-expressive: Caveat (pesos 400/600/700). Papel exclusivo: peça de MARKETING que precise de algo alegórico, fora do normal, festivo. Nunca em interface, nunca em documento técnico, nunca como assinatura padrão de peça de rotina. Token nascido em 2026-08-20 — ver a errata abaixo.

  • Supersede tipográfico: Indie Flower aposentada (tagline manuscrita "Soluções Sustentáveis" sai de cena nas peças novas — decisão de 2026-07-30). Neo Tech aposentada (não tinha papel definido nem uso real).

ERRATA FORMAL — 2026-08-20: o sistema tem TRÊS famílias, não duas#

Esta subseção dizia "Sistema final: 2 famílias, papéis sem sobreposição", e a tabela de decisões do §"Decisões" registrava "3ª família" como alternativa descartada ("necessidade inexistente hoje; decidir se/quando surgir"). A necessidade surgiu e foi decidida pelo Rafael em 2026-08-20, verbatim:

"nós ja temos decisao das 3 fontes canonicas, principal, a secundaria e a terciaria é extritamente para uso do marketing em peças que precise criar algo alegorico, fora do normal, festivo, etc"

Papéis, sem sobreposição: principal Montserrat (marca e interface) · secundária JetBrains Mono (dado, identificador, código) · terciária --seed-font-expressive (marketing alegórico).

Nome do token — e a alternativa descartada. Escolhido --seed-font-expressive em vez de --seed-font-display, que é o terceiro slot convencional dos design systems. Motivo: "display" nomeia tamanho e seria lido como "fonte de título grande", que é exatamente o uso que esta família não tem — a escala de display desta casa é Montserrat. expressive nomeia o propósito, e propósito é o que impede consumo errado. Regra da casa: quando o valor está certo e o propósito não tem nome, o conserto é NOME.

⚠ A família é Caveat por INFERÊNCIA declarada, não por fala dele. Ele decidiu o papel e o escopo; o único canônico que nomeia a terciária é o marca-seed.md v5.0 §4.3, que não está na pasta (pendência MR-P3). Confirmar o nome antes de qualquer peça sair com ela.

⚠ Fronteira que esta errata NÃO abre: a terciária não volta a ser a assinatura manuscrita padrão que a Indie Flower era. A Indie Flower foi aposentada porque a tagline manuscrita aparecia em toda peça; a terciária existe para o excepcional. Trocar a fonte e manter o uso onipresente seria desfazer a decisão de 2026-07-30 com outra letra.

2.6 Spacing, radius#

  • Spacing: base 4px mantida (decisão: já era correta), escala estendida sp-0…sp-24 (0→96px).
  • Radius: sm 4 (chips) · md 8 (controles) · lg 12 (cards) · xl 16 (modais) · full (pills). O DS v1 não tinha escala de radius formal — cada componente inventava a sua; agora é token.

O que o retrofit da v1.14 acrescentou a esta subseção (RV1–RV10, 2026-08-15; documentado aqui na v1.34, TK-P6 — até então só os gêmeos e o §9 o traziam). Nenhum valor abaixo é novo: é a documentação do que os gêmeos emitem desde a v1.14, com o papel que eles escrevem; onde nenhuma fonte escreve papel, está dito.

  • Escala de raio em passo 2 — grupo radius na raiz do JSON. --seed-radius-1 2px · --seed-radius-2 4px · --seed-radius-3 6px · --seed-radius-4 8px · --seed-radius-5 10px · --seed-radius-6 12px · --seed-radius-8 16px (não há passo 7). Motivo escrito nos gêmeos: o 6px era o raio mais usado do acervo (238 ocorrências, pelo comentário do CSS) e não existia na escala; elemento aninhado precisa de raio_externo - padding para não ficar com o canto errado, e por isso a escala tem os meios-passos. No gêmeo CSS os quatro nomes da linha de cima viram apelido dos numéricos, com o mesmo valor, para o consumo existente não quebrar: --seed-radius-sm = var(--seed-radius-2) · --seed-radius-md = var(--seed-radius-4) · --seed-radius-lg = var(--seed-radius-6) · --seed-radius-xl = var(--seed-radius-8); no JSON os quatro seguem com valor literal em dimension.radius. Papel de cada passo: os passos 2, 4, 6 e 8 têm o papel dos apelidos da linha de cima; --seed-radius-1, --seed-radius-3 e --seed-radius-5: papel próprio não registrado.
  • Meios-passos de espaço — grupo spacing-half do JSON. --seed-sp-1-5 6px · --seed-sp-2-5 10px. Papel escrito no CSS: os dois vãos de dentro de controle (ícone-rótulo, chip, célula densa), onde 4px cola e 8px afrouxa. Motivo escrito nos gêmeos: 824 ocorrências de 6px e 417 de 10px fora da escala de passo 4.
  • Altura de controle — grupo control-height do JSON. --seed-control-sm 32px · --seed-control-md 44px · --seed-control-lg 52px; preset compacto --seed-control-sm-compacto 28px · --seed-control-md-compacto 32px · --seed-control-lg-compacto 40px. Motivo escrito nos gêmeos: o DS não tinha token de altura de controle e a auditoria mediu botão de 18px a 608px. O md e o lg nasceram 40px e 48px e foram reconciliados na v1.23 (2026-08-26) com --seed-button-height-* e --seed-field-height-*, que o seed-componentes.md fixa em 32/44/52 (a linha 1.23 do §9 tem a história); o 44 é o fundamento próprio do DS para alvo de toque, mais generoso que o SC 2.5.8. O preset compacto é escala de densidade para tela de dado com mouse, ligado por container query nomeada (CP27), nunca por página, e fica abaixo do alvo de toque de propósito. Papel próprio do sm e do lg: não registrado.

Origem, e o que ela não diz. O comentário do CSS abre o bloco como v1.14 (2026-08-15, retrofit RV1-RV10) e o JSON marca os papéis tipográficos (na subseção de tipografia, acima) como retrofit RV1/RV3; os grupos de raio, meio-passo e altura levam só v1.14. Qual item RV-n corresponde a cada grupo não está registrado em nenhuma fonte deste repositório: RV2 e RV4 a RV9 aparecem zero vezes como texto, o RV10 só como fim da faixa "RV1-RV10", e o único com razão escrita é o RV3 (a paridade-tokens.py, no gate dos papéis: papel sem altura de linha é o buraco por onde o navegador decide); a história anterior ao primeiro commit (fbba442e) não está neste git. A v1.14 tem ainda uma segunda descrição (surface-brand-subtle), registrada na linha 1.14 do §9.

2.7 Motion — dois registros (modelo Carbon)#

  • Produtivo (tarefa; sutil, sai do caminho): 100ms (hover/foco) e 150ms (dropdowns, estados), easing cubic-bezier(0.2, 0, 0.38, 0.9).
  • Expressivo (momentos significativos): 300ms (modais, notificações) e 400ms (transições de tela), easing cubic-bezier(0.4, 0.14, 0.3, 1).
  • Saída — --seed-ease-out = cubic-bezier(.2,.8,.4,1) (v1.23, 2026-08-26). Entradas e revelações de componente: thumb do switch (120ms), toast (160ms), barra de progresso (200ms), modal e drawer. ⚠ Não é apelido do produtivo, e isso foi medido, não suposto: contra o ease-productive a diferença é 36,8% do percurso e 24,9 ms — quase um quadro e meio a 60 Hz. O seed-componentes.md usava este nome quatro vezes sem nunca fixar a curva, e o acervo carregava dois valores; os dois, medidos em 21 instantes de um movimento de 120 ms, diferem 0,3 ms, que é 1/56 de um quadro. ⭐ Dois nomes para a mesma curva; e a curva de verdade diferente era a terceira, que ninguém estava comparando.
  • Acessibilidade embutida no token: com prefers-reduced-motion, durações produtivas zeram e expressivas caem para crossfade de 100ms (regra do Uber Base). Quem consome o token respeita a preferência sem escrever media query.

2.8 Elevação — par superfície+sombra (modelo Atlassian)#

Elevação nunca é só sombra: é o par. surface-raised + shadow-raised (cards) · surface-overlay + shadow-overlay (menus, popovers) · modal usa shadow-modal. Sombras: no tema claro, tintadas no cinza-900 (#242E34, rgba(36,46,52,…)); no tema escuro, preto com opacidade (rgba(0,0,0,0.40) no shadow-raised, 0.50 no shadow-overlay, 0.60 no shadow-modal), porque uma sombra tintada some sobre superfície escura [inferência: não medida]. No dark, a borda sutil assume a separação (sombra sozinha some em fundo escuro). Errata de redação (v1.38, PR-P177): a frase anterior dizia "sombras tintadas no cinza-900, nunca preto", mas as 3 sombras do tema escuro são pretas com opacidade; o texto passa a descrever o que os tokens emitem, e nenhum valor mudou. Existe também surface-sunken para áreas rebaixadas (wells, blocos de código).

2.9 Breakpoints, toque e app (v1.2)#

Breakpoints — escala oficial (alinhada ao Tailwind, stack dos produtos): sm 640 · md 768 · lg 1024 · xl 1280 · 2xl 1536 (px, min-width). Limitação técnica documentada: media query NÃO lê CSS custom property — por isso breakpoint não existe como --seed-* no CSS; as fontes canônicas são o seed-tokens.json (consumo por app nativo e ferramentas) e o theme.screens do Tailwind (consumo pelos produtos web). O corte 960 do HTML v1 fica superseded (§ Supersedes abaixo). Faixa de projeto: mobile <640 · tablet 640–1023 · desktop ≥1024. Pior caso de teste: 360px (largura Android mais comum no Brasil — o mercado é ~80% Android).

Tokens de toque:

--seed-fs-field-touch: 16px; /* fonte mínima de CAMPO em superfície de toque —
  campo <16px dispara zoom automático no iOS Safari ao focar */
@media (pointer: coarse) { /* detector correto: TOQUE, não largura —
  tablet grande também é toque; desktop estreito não é */
  .seed-field__control { font-size: var(--seed-fs-field-touch); }
}

Safe areas (PWA/WebView/app com notch e barra de gesto):

--seed-safe-top: env(safe-area-inset-top);
--seed-safe-bottom: env(safe-area-inset-bottom);
--seed-safe-left: env(safe-area-inset-left);
--seed-safe-right: env(safe-area-inset-right);

Barras fixas (header, tab bar, CTA fixo de rodapé) somam o safe-area ao próprio padding. Requer viewport-fit=cover no meta viewport.

Supersede (v1.2): breakpoints do seed-design-system.html v1.0 (mobile 0–639 / tablet 640–959 / desktop 960+) → escala Tailwind acima. Motivo: os produtos rodam Lovable/Tailwind/shadcn; manter 960 exigiria configuração divergente em todo produto, fricção diária sem ganho. Diferença prática (960→1024) é mínima.

Esc