# Sunny Systems — Marca e Design System > Guia completo da marca V4 NewBrand26 da Sunny Systems, em um arquivo: regras, tokens, fundações, componentes, padrões, governança, decisões e história. Gerado a partir de `tokens/tokens.json` e de `docs/` no repositório `sunnysystems/brand`. Página em https://ds.sunnysystems.com.br. Gerado em 2026-10-15. Tokens versão 0.2.0. 286 tokens: 268 medido, 14 derivado, 4 proposta. A Sunny Systems é uma empresa brasileira de tecnologia. A marca vigente é a **V4 NewBrand26**, no ar desde 17 de março de 2026. Cinco produtos: RootPilot, ScopeWard, DevXOS, Sunshine e Soberania de IA. Tagline: "Seu parceiro estratégico em tecnologia, do produto à operação." Para consumo por máquina, sem passar por este arquivo: `https://ds.sunnysystems.com.br/tokens.css` (custom properties prontas) e o `tokens.json` do repositório (formato W3C Design Tokens). --- ## Regras que não se negociam 1. **Nunca escreva um hex.** Use `var(--sunny-*)` semântico ou de componente. Primitivo direto só dentro de `tokens/tokens.json`. 2. **O escuro é a fundação, não um tema.** Tudo nasce sobre `color.bg.base` (#1A1A1D). O claro entra com `` e existe para documento, slide e e-mail. 3. **Uma luz só.** O âmbar #FFB61F é a única cor de destaque. Estado usa `color.status.*`, nunca âmbar. Se dois elementos na mesma tela pedem âmbar, um deles não merece. 4. **Tipografia por papel.** Bricolage Grotesque só em título e nunca abaixo de 20px. Inter no corpo, mínimo 16px em web. JetBrains Mono em qualquer texto que o leitor possa copiar: comando, ID, trecho de log. 5. **Radius contido.** 4px em botão e input, 8px em painel e bloco de código, 12px em card, 999px em pill. Nada entre 12 e 999. 6. **Card em repouso não tem sombra.** Card (#1C2020) sobre fundo (#1A1A1D) tem 1.1:1 de contraste: a borda `color.border.subtle` é o único limite visual e não pode ser removida. 7. **Acessível por padrão.** WCAG 2.1 AA é critério de entrada. Foco sempre visível, `focus.outline` 2px âmbar com offset 2px. Estado nunca só por cor. 8. **Valor muda em `tokens/tokens.json`**, nunca no `tokens.css` gerado nem em prosa. Depois rode `node tokens/build.mjs` e `node tokens/check-contrast.mjs`. 9. **Texto em pt-BR**, direto, sem travessão em texto corrido, sem superlativo, sem emoji institucional. Ver a seção de voz. ## Pares de cor proibidos Medidos e reprovados. Não use como texto. | Par | Contraste | |---|---| | Âmbar 500 (#FFB61F) sobre branco | 1.8:1 | | Branco sobre âmbar 500 | 1.8:1 | | Neutral 500 (#5C5C5C) sobre fundo escuro | 2.6:1 | | Neutral 600 (#3A3A3A) sobre fundo escuro | 1.5:1 | Em fundo claro, âmbar em texto é sempre `color.amber.800` (#7E5B14). Sobre botão âmbar, texto é sempre `color.amber.900` (#332C15). ## O que não é mais verdade Se você encontrar isto em algum material, está desatualizado. | Atributo | De onde é | Situação | |---|---|---| | #FFDE59, Plus Jakarta Sans, Geologica, inglês-first | V3, site Framer 2024 a 2025 | Fora do ar desde 17/03/2026 | | #FFC700, Space Grotesk, Tajawal, mascote robô, losangos | V1, 2021 | Histórico | | #F8D347, símbolo de raios | V2, 2023 | Histórico | | Convergence, Aurora, Radiance | Explorações de fevereiro de 2026 | Não adotadas, não usar como referência | | Badge de fundo âmbar sólido | Doc anterior do site | Não está em uso, saiu | --- ## Referência de tokens Três camadas: **primitivo** é o valor em si, **semântico** diz para que serve, **de componente** diz onde entra. Código e Figma usam semântico e de componente. A coluna Valor já vem com os aliases resolvidos até o valor final. A coluna "Aponta para" mostra o token imediato, quando houver. Status: `medido` foi lido do site ou dos arquivos oficiais; `derivado` foi calculado a partir de valores medidos; `proposta` ainda não existe no site e precisa de validação antes de ir para produção. ### color.amber | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.amber.50` | `--sunny-color-amber-50` | `#FFFDF4` | | medido | Usado no gradiente da arte do hero | | `color.amber.100` | `--sunny-color-amber-100` | `#FFF8E6` | | medido | bg-light-accent na doc do site | | `color.amber.200` | `--sunny-color-amber-200` | `#FFE7A8` | | medido | Usado em traços da arte do hero | | `color.amber.300` | `--sunny-color-amber-300` | `#F5D660` | | medido | Amarelo claro oficial | | `color.amber.400` | `--sunny-color-amber-400` | `#F0C840` | | medido | Amarelo oficial; hover do botão primário | | `color.amber.500` | `--sunny-color-amber-500` | `#FFB61F` | | medido | Âmbar oficial; cor principal da marca | | `color.amber.600` | `--sunny-color-amber-600` | `#E5A31B` | | medido | Usado no gradiente de botões e badges de produto | | `color.amber.700` | `--sunny-color-amber-700` | `#C98A12` | | medido | Usado nas faixas da landing do Sunshine | | `color.amber.800` | `--sunny-color-amber-800` | `#7E5B14` | | derivado | Interpolação entre 700 e 900. Único tom de âmbar aprovado como texto sobre branco | | `color.amber.900` | `--sunny-color-amber-900` | `#332C15` | | medido | 'Escuro' oficial; texto sobre âmbar | ### color.neutral | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.neutral.0` | `--sunny-color-neutral-0` | `#FFFFFF` | | medido | Branco; fundo do modo claro | | `color.neutral.50` | `--sunny-color-neutral-50` | `#F7F7F5` | | medido | Card do modo claro | | `color.neutral.100` | `--sunny-color-neutral-100` | `#DFDFDF` | | medido | Texto principal sobre escuro | | `color.neutral.200` | `--sunny-color-neutral-200` | `#BCBCBC` | | derivado | Midpoint entre 100 e 300 | | `color.neutral.300` | `--sunny-color-neutral-300` | `#999999` | | medido | Cinza do 'SYSTEMS' no wordmark | | `color.neutral.400` | `--sunny-color-neutral-400` | `#8F8F8F` | | medido | Texto secundário | | `color.neutral.500` | `--sunny-color-neutral-500` | `#5C5C5C` | | medido | Usado em labels mono do ScopeWard. Não passa AA como texto sobre escuro | | `color.neutral.600` | `--sunny-color-neutral-600` | `#3A3A3A` | | medido | Cinza do 'SUNNY' no wordmark; bordas fortes | | `color.neutral.700` | `--sunny-color-neutral-700` | `#232828` | | medido | Superfície elevada nas páginas de produto | | `color.neutral.800` | `--sunny-color-neutral-800` | `#1C2020` | | medido | Card sobre fundo escuro | | `color.neutral.900` | `--sunny-color-neutral-900` | `#1A1A1D` | | medido | Fundo principal | | `color.neutral.950` | `--sunny-color-neutral-950` | `#0E1113` | | medido | Fundo de terminal nas páginas de produto | | `color.neutral.warm.900` | `--sunny-color-neutral-warm-900` | `#1A150C` | | medido | Barra de título da janela quente | | `color.neutral.warm.950` | `--sunny-color-neutral-warm-950` | `#14110A` | | medido | Corpo da janela quente | ### color.feedback | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.feedback.error.300` | `--sunny-color-feedback-error-300` | `#FF8888` | | medido | Texto de erro nos formulários de lead | | `color.feedback.error.500` | `--sunny-color-feedback-error-500` | `#FF5D5D` | | medido | Borda inválida; --sev-crit no ScopeWard | | `color.feedback.error.700` | `--sunny-color-feedback-error-700` | `#B32D2D` | | derivado | Texto de erro sobre branco | | `color.feedback.success.300` | `--sunny-color-feedback-success-300` | `#9ADFB6` | | derivado | | | `color.feedback.success.500` | `--sunny-color-feedback-success-500` | `#6FCF97` | | medido | --sev-ok no ScopeWard; 'copiado' no DevXOS | | `color.feedback.success.700` | `--sunny-color-feedback-success-700` | `#2E7D4F` | | derivado | | | `color.feedback.warning.300` | `--sunny-color-feedback-warning-300` | `#FFBE8A` | | derivado | | | `color.feedback.warning.500` | `--sunny-color-feedback-warning-500` | `#FF9E54` | | medido | --sev-high no ScopeWard; acento de escrita na topologia do RootPilot | | `color.feedback.warning.700` | `--sunny-color-feedback-warning-700` | `#A85B1E` | | derivado | | | `color.feedback.info.300` | `--sunny-color-feedback-info-300` | `#A9C4DD` | | derivado | | | `color.feedback.info.500` | `--sunny-color-feedback-info-500` | `#7FA6C9` | | medido | --sev-low no ScopeWard | | `color.feedback.info.700` | `--sunny-color-feedback-info-700` | `#3A6A94` | | derivado | | ### color.alpha | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.alpha.white-4` | `--sunny-color-alpha-white-4` | `rgba(255, 255, 255, 0.04)` | | medido | Borda de card | | `color.alpha.white-6` | `--sunny-color-alpha-white-6` | `rgba(255, 255, 255, 0.06)` | | medido | | | `color.alpha.white-8` | `--sunny-color-alpha-white-8` | `rgba(255, 255, 255, 0.08)` | | medido | Borda de card em hover | | `color.alpha.white-12` | `--sunny-color-alpha-white-12` | `rgba(255, 255, 255, 0.12)` | | medido | | | `color.alpha.black-6` | `--sunny-color-alpha-black-6` | `rgba(0, 0, 0, 0.06)` | | proposta | Borda sutil no modo claro | | `color.alpha.amber-4` | `--sunny-color-alpha-amber-4` | `rgba(255, 182, 31, 0.04)` | | medido | | | `color.alpha.amber-7` | `--sunny-color-alpha-amber-7` | `rgba(255, 182, 31, 0.07)` | | medido | Glow do hero | | `color.alpha.amber-10` | `--sunny-color-alpha-amber-10` | `rgba(255, 182, 31, 0.10)` | | medido | Fundo do badge | | `color.alpha.amber-15` | `--sunny-color-alpha-amber-15` | `rgba(255, 182, 31, 0.15)` | | medido | Linha divisória do hero; drop-shadow da ilustração | | `color.alpha.amber-30` | `--sunny-color-alpha-amber-30` | `rgba(255, 182, 31, 0.30)` | | medido | Glow forte | | `color.alpha.ink-92` | `--sunny-color-alpha-ink-92` | `rgba(26, 26, 29, 0.92)` | | medido | Fundo do header ao rolar | | `color.alpha.white-5` | `--sunny-color-alpha-white-5` | `rgba(255, 255, 255, 0.055)` | | medido | Fundo de input em hover | ### color.bg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.bg.base` | `--sunny-color-bg-base` | `#1A1A1D` | `color.neutral.900` | medido | | | `color.bg.card` | `--sunny-color-bg-card` | `#1C2020` | `color.neutral.800` | medido | | | `color.bg.elevated` | `--sunny-color-bg-elevated` | `#232828` | `color.neutral.700` | medido | | | `color.bg.terminal` | `--sunny-color-bg-terminal` | `#0E1113` | `color.neutral.950` | medido | | | `color.bg.header` | `--sunny-color-bg-header` | `rgba(26, 26, 29, 0.92)` | `color.alpha.ink-92` | medido | | | `color.bg.accent-soft` | `--sunny-color-bg-accent-soft` | `rgba(255, 182, 31, 0.10)` | `color.alpha.amber-10` | medido | | ### color.text | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.text.primary` | `--sunny-color-text-primary` | `#DFDFDF` | `color.neutral.100` | medido | | | `color.text.secondary` | `--sunny-color-text-secondary` | `#8F8F8F` | `color.neutral.400` | medido | | | `color.text.inverse` | `--sunny-color-text-inverse` | `#1A1A1D` | `color.neutral.900` | medido | | | `color.text.accent` | `--sunny-color-text-accent` | `#FFB61F` | `color.amber.500` | medido | Destaque em âmbar sobre escuro | | `color.text.accent-soft` | `--sunny-color-text-accent-soft` | `#F5D660` | `color.amber.300` | medido | | | `color.text.on-accent` | `--sunny-color-text-on-accent` | `#332C15` | `color.amber.900` | medido | Texto sobre botão âmbar | ### color.border | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.border.subtle` | `--sunny-color-border-subtle` | `rgba(255, 255, 255, 0.04)` | `color.alpha.white-4` | medido | | | `color.border.default` | `--sunny-color-border-default` | `rgba(255, 255, 255, 0.08)` | `color.alpha.white-8` | medido | | | `color.border.strong` | `--sunny-color-border-strong` | `#3A3A3A` | `color.neutral.600` | medido | Borda do seletor de idioma | | `color.border.accent` | `--sunny-color-border-accent` | `#FFB61F` | `color.amber.500` | medido | | ### color.accent | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.accent.default` | `--sunny-color-accent-default` | `#FFB61F` | `color.amber.500` | medido | | | `color.accent.hover` | `--sunny-color-accent-hover` | `#F0C840` | `color.amber.400` | medido | | | `color.accent.active` | `--sunny-color-accent-active` | `#E5A31B` | `color.amber.600` | derivado | | | `color.accent.soft` | `--sunny-color-accent-soft` | `rgba(255, 182, 31, 0.10)` | `color.alpha.amber-10` | medido | | | `color.accent.glow` | `--sunny-color-accent-glow` | `rgba(255, 182, 31, 0.07)` | `color.alpha.amber-7` | medido | | ### color.focus | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.focus.ring` | `--sunny-color-focus-ring` | `#FFB61F` | `color.amber.500` | medido | outline 2px, offset 2px | ### color.status | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.status.error.text` | `--sunny-color-status-error-text` | `#FF8888` | `color.feedback.error.300` | medido | | | `color.status.error.icon` | `--sunny-color-status-error-icon` | `#FF5D5D` | `color.feedback.error.500` | medido | | | `color.status.error.border` | `--sunny-color-status-error-border` | `#FF5D5D` | `color.feedback.error.500` | medido | | | `color.status.error.bg` | `--sunny-color-status-error-bg` | `rgba(255, 93, 93, 0.06)` | | medido | | | `color.status.success.text` | `--sunny-color-status-success-text` | `#9ADFB6` | `color.feedback.success.300` | derivado | | | `color.status.success.icon` | `--sunny-color-status-success-icon` | `#6FCF97` | `color.feedback.success.500` | medido | | | `color.status.success.border` | `--sunny-color-status-success-border` | `#6FCF97` | `color.feedback.success.500` | medido | | | `color.status.success.bg` | `--sunny-color-status-success-bg` | `rgba(111, 207, 151, 0.08)` | | proposta | | | `color.status.warning.text` | `--sunny-color-status-warning-text` | `#FFBE8A` | `color.feedback.warning.300` | derivado | | | `color.status.warning.icon` | `--sunny-color-status-warning-icon` | `#FF9E54` | `color.feedback.warning.500` | medido | | | `color.status.warning.border` | `--sunny-color-status-warning-border` | `#FF9E54` | `color.feedback.warning.500` | medido | | | `color.status.warning.bg` | `--sunny-color-status-warning-bg` | `rgba(255, 158, 84, 0.08)` | | proposta | | | `color.status.info.text` | `--sunny-color-status-info-text` | `#A9C4DD` | `color.feedback.info.300` | derivado | | | `color.status.info.icon` | `--sunny-color-status-info-icon` | `#7FA6C9` | `color.feedback.info.500` | medido | | | `color.status.info.border` | `--sunny-color-status-info-border` | `#7FA6C9` | `color.feedback.info.500` | medido | | | `color.status.info.bg` | `--sunny-color-status-info-bg` | `rgba(127, 166, 201, 0.08)` | | proposta | | ### color.severity | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `color.severity.critical` | `--sunny-color-severity-critical` | `#FF5D5D` | `color.feedback.error.500` | medido | | | `color.severity.high` | `--sunny-color-severity-high` | `#FF9E54` | `color.feedback.warning.500` | medido | | | `color.severity.medium` | `--sunny-color-severity-medium` | `#F0C840` | `color.amber.400` | medido | | | `color.severity.low` | `--sunny-color-severity-low` | `#7FA6C9` | `color.feedback.info.500` | medido | | | `color.severity.ok` | `--sunny-color-severity-ok` | `#6FCF97` | `color.feedback.success.500` | medido | | ### font.family | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `font.family.display` | `--sunny-font-family-display` | `'Bricolage Grotesque', sans-serif` | | medido | Títulos e wordmark. Eixo opsz 12–96 | | `font.family.body` | `--sunny-font-family-body` | `'Inter', sans-serif` | | medido | Corpo e UI | | `font.family.mono` | `--sunny-font-family-mono` | `'JetBrains Mono', ui-monospace, monospace` | | medido | Código, comandos, IDs. Carregada no site, mas sem token no CSS raiz | ### font.weight | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `font.weight.regular` | `--sunny-font-weight-regular` | `400` | | medido | | | `font.weight.medium` | `--sunny-font-weight-medium` | `500` | | medido | | | `font.weight.semibold` | `--sunny-font-weight-semibold` | `600` | | medido | | | `font.weight.bold` | `--sunny-font-weight-bold` | `700` | | medido | | ### font.size | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `font.size.10` | `--sunny-font-size-10` | `0.625rem` | | medido | | | `font.size.11` | `--sunny-font-size-11` | `0.6875rem` | | medido | | | `font.size.12` | `--sunny-font-size-12` | `0.75rem` | | medido | | | `font.size.13` | `--sunny-font-size-13` | `0.8125rem` | | medido | | | `font.size.14` | `--sunny-font-size-14` | `0.875rem` | | medido | | | `font.size.15` | `--sunny-font-size-15` | `0.9375rem` | | medido | | | `font.size.16` | `--sunny-font-size-16` | `1rem` | | medido | | | `font.size.17` | `--sunny-font-size-17` | `1.0625rem` | | medido | | | `font.size.18` | `--sunny-font-size-18` | `1.125rem` | | medido | | | `font.size.20` | `--sunny-font-size-20` | `1.25rem` | | medido | | | `font.size.22` | `--sunny-font-size-22` | `1.375rem` | | medido | | | `font.size.32` | `--sunny-font-size-32` | `2rem` | | medido | | | `font.size.fluid-sm` | `--sunny-font-size-fluid-sm` | `clamp(1.75rem, 3vw, 2.5rem)` | | medido | Título de seção | | `font.size.fluid-md` | `--sunny-font-size-fluid-md` | `clamp(2rem, 4vw, 3.25rem)` | | medido | | | `font.size.fluid-lg` | `--sunny-font-size-fluid-lg` | `clamp(2.25rem, 4vw, 3.5rem)` | | medido | | | `font.size.fluid-display` | `--sunny-font-size-fluid-display` | `clamp(2.75rem, 5.5vw, 4.25rem)` | | medido | h1 do hero | ### font.line-height | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `font.line-height.tight` | `--sunny-font-line-height-tight` | `1.08` | | medido | Display | | `font.line-height.snug` | `--sunny-font-line-height-snug` | `1.2` | | medido | Títulos | | `font.line-height.normal` | `--sunny-font-line-height-normal` | `1.6` | | medido | Corpo | | `font.line-height.relaxed` | `--sunny-font-line-height-relaxed` | `1.75` | | medido | Descrições longas | ### font.letter-spacing | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `font.letter-spacing.tight` | `--sunny-font-letter-spacing-tight` | `-0.02em` | | medido | Display | | `font.letter-spacing.snug` | `--sunny-font-letter-spacing-snug` | `-0.01em` | | medido | Títulos | | `font.letter-spacing.wide` | `--sunny-font-letter-spacing-wide` | `0.08em` | | medido | Overline e badge | | `font.letter-spacing.wider` | `--sunny-font-letter-spacing-wider` | `0.14em` | | medido | Rótulos em caixa alta | ### type.display | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.display.family` | `--sunny-type-display-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.display.size` | `--sunny-type-display-size` | `clamp(2.75rem, 5.5vw, 4.25rem)` | `font.size.fluid-display` | medido | | | `type.display.weight` | `--sunny-type-display-weight` | `700` | `font.weight.bold` | medido | | | `type.display.line-height` | `--sunny-type-display-line-height` | `1.08` | `font.line-height.tight` | medido | | | `type.display.letter-spacing` | `--sunny-type-display-letter-spacing` | `-0.02em` | `font.letter-spacing.tight` | medido | | ### type.heading-1 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.heading-1.family` | `--sunny-type-heading-1-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.heading-1.size` | `--sunny-type-heading-1-size` | `clamp(2.25rem, 4vw, 3.5rem)` | `font.size.fluid-lg` | medido | | | `type.heading-1.weight` | `--sunny-type-heading-1-weight` | `700` | `font.weight.bold` | medido | | | `type.heading-1.line-height` | `--sunny-type-heading-1-line-height` | `1.2` | `font.line-height.snug` | medido | | | `type.heading-1.letter-spacing` | `--sunny-type-heading-1-letter-spacing` | `-0.01em` | `font.letter-spacing.snug` | medido | | ### type.heading-2 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.heading-2.family` | `--sunny-type-heading-2-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.heading-2.size` | `--sunny-type-heading-2-size` | `clamp(2rem, 4vw, 3.25rem)` | `font.size.fluid-md` | medido | | | `type.heading-2.weight` | `--sunny-type-heading-2-weight` | `700` | `font.weight.bold` | medido | | | `type.heading-2.line-height` | `--sunny-type-heading-2-line-height` | `1.2` | `font.line-height.snug` | medido | | | `type.heading-2.letter-spacing` | `--sunny-type-heading-2-letter-spacing` | `-0.01em` | `font.letter-spacing.snug` | medido | | ### type.heading-3 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.heading-3.family` | `--sunny-type-heading-3-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.heading-3.size` | `--sunny-type-heading-3-size` | `clamp(1.75rem, 3vw, 2.5rem)` | `font.size.fluid-sm` | medido | | | `type.heading-3.weight` | `--sunny-type-heading-3-weight` | `700` | `font.weight.bold` | medido | | | `type.heading-3.line-height` | `--sunny-type-heading-3-line-height` | `1.2` | `font.line-height.snug` | medido | | | `type.heading-3.letter-spacing` | `--sunny-type-heading-3-letter-spacing` | `-0.01em` | `font.letter-spacing.snug` | medido | | ### type.heading-4 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.heading-4.family` | `--sunny-type-heading-4-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.heading-4.size` | `--sunny-type-heading-4-size` | `1.375rem` | `font.size.22` | medido | | | `type.heading-4.weight` | `--sunny-type-heading-4-weight` | `600` | `font.weight.semibold` | medido | | | `type.heading-4.line-height` | `--sunny-type-heading-4-line-height` | `1.2` | `font.line-height.snug` | medido | | | `type.heading-4.letter-spacing` | `--sunny-type-heading-4-letter-spacing` | `0` | | medido | | ### type.heading-5 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.heading-5.family` | `--sunny-type-heading-5-family` | `'Bricolage Grotesque', sans-serif` | `font.family.display` | medido | | | `type.heading-5.size` | `--sunny-type-heading-5-size` | `1.25rem` | `font.size.20` | medido | | | `type.heading-5.weight` | `--sunny-type-heading-5-weight` | `600` | `font.weight.semibold` | medido | | | `type.heading-5.line-height` | `--sunny-type-heading-5-line-height` | `1.2` | `font.line-height.snug` | medido | | | `type.heading-5.letter-spacing` | `--sunny-type-heading-5-letter-spacing` | `0` | | medido | | ### type.body-lg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.body-lg.family` | `--sunny-type-body-lg-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.body-lg.size` | `--sunny-type-body-lg-size` | `1.125rem` | `font.size.18` | medido | | | `type.body-lg.weight` | `--sunny-type-body-lg-weight` | `400` | `font.weight.regular` | medido | | | `type.body-lg.line-height` | `--sunny-type-body-lg-line-height` | `1.75` | `font.line-height.relaxed` | medido | | | `type.body-lg.letter-spacing` | `--sunny-type-body-lg-letter-spacing` | `0` | | medido | | ### type.body | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.body.family` | `--sunny-type-body-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.body.size` | `--sunny-type-body-size` | `1rem` | `font.size.16` | medido | | | `type.body.weight` | `--sunny-type-body-weight` | `400` | `font.weight.regular` | medido | | | `type.body.line-height` | `--sunny-type-body-line-height` | `1.6` | `font.line-height.normal` | medido | | | `type.body.letter-spacing` | `--sunny-type-body-letter-spacing` | `0` | | medido | | ### type.body-sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.body-sm.family` | `--sunny-type-body-sm-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.body-sm.size` | `--sunny-type-body-sm-size` | `0.9375rem` | `font.size.15` | medido | | | `type.body-sm.weight` | `--sunny-type-body-sm-weight` | `400` | `font.weight.regular` | medido | | | `type.body-sm.line-height` | `--sunny-type-body-sm-line-height` | `1.6` | `font.line-height.normal` | medido | | | `type.body-sm.letter-spacing` | `--sunny-type-body-sm-letter-spacing` | `0` | | medido | | ### type.label | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.label.family` | `--sunny-type-label-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.label.size` | `--sunny-type-label-size` | `0.875rem` | `font.size.14` | medido | | | `type.label.weight` | `--sunny-type-label-weight` | `500` | `font.weight.medium` | medido | | | `type.label.line-height` | `--sunny-type-label-line-height` | `1.6` | `font.line-height.normal` | medido | | | `type.label.letter-spacing` | `--sunny-type-label-letter-spacing` | `0` | | medido | | ### type.caption | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.caption.family` | `--sunny-type-caption-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.caption.size` | `--sunny-type-caption-size` | `0.8125rem` | `font.size.13` | medido | | | `type.caption.weight` | `--sunny-type-caption-weight` | `400` | `font.weight.regular` | medido | | | `type.caption.line-height` | `--sunny-type-caption-line-height` | `1.6` | `font.line-height.normal` | medido | | | `type.caption.letter-spacing` | `--sunny-type-caption-letter-spacing` | `0` | | medido | | ### type.overline | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.overline.family` | `--sunny-type-overline-family` | `'Inter', sans-serif` | `font.family.body` | medido | | | `type.overline.size` | `--sunny-type-overline-size` | `0.75rem` | `font.size.12` | medido | | | `type.overline.weight` | `--sunny-type-overline-weight` | `600` | `font.weight.semibold` | medido | | | `type.overline.line-height` | `--sunny-type-overline-line-height` | `1` | | medido | | | `type.overline.letter-spacing` | `--sunny-type-overline-letter-spacing` | `0.08em` | `font.letter-spacing.wide` | medido | | | `type.overline.transform` | `--sunny-type-overline-transform` | `uppercase` | | medido | | ### type.code | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `type.code.family` | `--sunny-type-code-family` | `'JetBrains Mono', ui-monospace, monospace` | `font.family.mono` | medido | | | `type.code.size` | `--sunny-type-code-size` | `0.875rem` | `font.size.14` | medido | | | `type.code.weight` | `--sunny-type-code-weight` | `400` | `font.weight.regular` | medido | | | `type.code.line-height` | `--sunny-type-code-line-height` | `1.6` | `font.line-height.normal` | medido | | | `type.code.letter-spacing` | `--sunny-type-code-letter-spacing` | `0` | | medido | | ### space.1 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.1` | `--sunny-space-1` | `4px` | | medido | | ### space.2 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.2` | `--sunny-space-2` | `8px` | | medido | | ### space.3 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.3` | `--sunny-space-3` | `12px` | | medido | | ### space.4 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.4` | `--sunny-space-4` | `16px` | | medido | | ### space.6 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.6` | `--sunny-space-6` | `24px` | | medido | | ### space.8 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.8` | `--sunny-space-8` | `32px` | | medido | | ### space.12 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.12` | `--sunny-space-12` | `48px` | | medido | | ### space.16 | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.16` | `--sunny-space-16` | `64px` | | medido | | ### space.section | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `space.section` | `--sunny-space-section` | `100px` | | medido | Padding vertical de seção | ### radius.sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `radius.sm` | `--sunny-radius-sm` | `2px` | | medido | Tags pequenas | ### radius.md | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `radius.md` | `--sunny-radius-md` | `4px` | | medido | Botões e inputs | ### radius.lg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `radius.lg` | `--sunny-radius-lg` | `8px` | | medido | Painéis | ### radius.xl | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `radius.xl` | `--sunny-radius-xl` | `12px` | | medido | Cards | ### radius.full | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `radius.full` | `--sunny-radius-full` | `999px` | | medido | Pills | ### shadow.glow-sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `shadow.glow-sm` | `--sunny-shadow-glow-sm` | `0 0 12px rgba(255, 182, 31, 0.40)` | | medido | Glow em ícones e dots | ### shadow.glow-md | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `shadow.glow-md` | `--sunny-shadow-glow-md` | `0 0 30px rgba(255, 182, 31, 0.30), 0 0 60px rgba(255, 182, 31, 0.10)` | | medido | Glow em elementos de destaque | ### shadow.elevation-md | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `shadow.elevation-md` | `--sunny-shadow-elevation-md` | `0 12px 40px rgba(0, 0, 0, 0.35)` | | medido | Cards flutuantes | ### shadow.elevation-lg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `shadow.elevation-lg` | `--sunny-shadow-elevation-lg` | `0 24px 70px rgba(0, 0, 0, 0.50)` | | medido | Modais e mockups | ### blur.header | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `blur.header` | `--sunny-blur-header` | `20px` | | medido | | ### blur.card | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `blur.card` | `--sunny-blur-card` | `24px` | | medido | | ### motion.duration | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `motion.duration.fast` | `--sunny-motion-duration-fast` | `0.15s` | | medido | | | `motion.duration.base` | `--sunny-motion-duration-base` | `0.2s` | | medido | | | `motion.duration.slow` | `--sunny-motion-duration-slow` | `0.3s` | | medido | | ### motion.easing | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `motion.easing.default` | `--sunny-motion-easing-default` | `ease` | | medido | | ### breakpoint.md | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `breakpoint.md` | `--sunny-breakpoint-md` | `768px` | | medido | Menu mobile e grid em uma coluna | ### breakpoint.lg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `breakpoint.lg` | `--sunny-breakpoint-lg` | `1024px` | | medido | | ### breakpoint.container | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `breakpoint.container` | `--sunny-breakpoint-container` | `1200px` | | medido | Largura máxima do conteúdo | ### button.primary | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.primary.bg` | `--sunny-button-primary-bg` | `#FFB61F` | `color.accent.default` | medido | | | `button.primary.fg` | `--sunny-button-primary-fg` | `#332C15` | `color.text.on-accent` | medido | | | `button.primary.bg-hover` | `--sunny-button-primary-bg-hover` | `#F0C840` | `color.accent.hover` | medido | | | `button.primary.bg-active` | `--sunny-button-primary-bg-active` | `#E5A31B` | `color.accent.active` | derivado | | ### button.secondary | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.secondary.bg` | `--sunny-button-secondary-bg` | `transparent` | | medido | | | `button.secondary.fg` | `--sunny-button-secondary-fg` | `#FFB61F` | `color.accent.default` | medido | | | `button.secondary.border` | `--sunny-button-secondary-border` | `1.5px solid #FFB61F` | | medido | | | `button.secondary.bg-hover` | `--sunny-button-secondary-bg-hover` | `#FFB61F` | `color.accent.default` | medido | | | `button.secondary.fg-hover` | `--sunny-button-secondary-fg-hover` | `#332C15` | `color.text.on-accent` | medido | | ### button.padding-y | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.padding-y` | `--sunny-button-padding-y` | `14px` | | medido | | ### button.padding-x | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.padding-x` | `--sunny-button-padding-x` | `32px` | | medido | | ### button.padding-y-sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.padding-y-sm` | `--sunny-button-padding-y-sm` | `10px` | | medido | | ### button.padding-x-sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.padding-x-sm` | `--sunny-button-padding-x-sm` | `24px` | | medido | | ### button.radius | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.radius` | `--sunny-button-radius` | `4px` | `radius.md` | medido | | ### button.font-size | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.font-size` | `--sunny-button-font-size` | `0.9375rem` | `font.size.15` | medido | | ### button.font-size-sm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.font-size-sm` | `--sunny-button-font-size-sm` | `0.8125rem` | `font.size.13` | medido | | ### button.font-weight | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.font-weight` | `--sunny-button-font-weight` | `600` | `font.weight.semibold` | medido | | ### button.gap | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `button.gap` | `--sunny-button-gap` | `8px` | `space.2` | medido | | ### badge.bg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.bg` | `--sunny-badge-bg` | `rgba(255, 182, 31, 0.10)` | `color.accent.soft` | medido | | ### badge.fg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.fg` | `--sunny-badge-fg` | `#FFB61F` | `color.accent.default` | medido | | ### badge.padding-y | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.padding-y` | `--sunny-badge-padding-y` | `6px` | | medido | | ### badge.padding-x | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.padding-x` | `--sunny-badge-padding-x` | `16px` | | medido | | ### badge.radius | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.radius` | `--sunny-badge-radius` | `999px` | `radius.full` | medido | | ### badge.font-size | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.font-size` | `--sunny-badge-font-size` | `0.75rem` | `font.size.12` | medido | | ### badge.letter-spacing | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `badge.letter-spacing` | `--sunny-badge-letter-spacing` | `0.08em` | `font.letter-spacing.wide` | medido | | ### card.bg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.bg` | `--sunny-card-bg` | `#1C2020` | `color.bg.card` | medido | | ### card.border | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.border` | `--sunny-card-border` | `1px solid rgba(255, 255, 255, 0.04)` | | medido | | ### card.border-hover | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.border-hover` | `--sunny-card-border-hover` | `1px solid rgba(255, 255, 255, 0.08)` | | medido | | ### card.radius | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.radius` | `--sunny-card-radius` | `12px` | `radius.xl` | medido | | ### card.padding | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.padding` | `--sunny-card-padding` | `32px` | `space.8` | medido | | ### card.blur | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `card.blur` | `--sunny-card-blur` | `24px` | `blur.card` | medido | | ### input.bg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.bg` | `--sunny-input-bg` | `rgba(255, 255, 255, 0.04)` | `color.alpha.white-4` | medido | | ### input.bg-hover | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.bg-hover` | `--sunny-input-bg-hover` | `rgba(255, 255, 255, 0.055)` | `color.alpha.white-5` | medido | | ### input.bg-focus | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.bg-focus` | `--sunny-input-bg-focus` | `rgba(255, 182, 31, 0.04)` | `color.alpha.amber-4` | medido | | ### input.fg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.fg` | `--sunny-input-fg` | `#FFFFFF` | `color.neutral.0` | medido | O site usa branco puro; proposta é migrar para text.primary | ### input.placeholder | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.placeholder` | `--sunny-input-placeholder` | `#8F8F8F` | `color.text.secondary` | medido | Com opacity 0.65 | ### input.border | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.border` | `--sunny-input-border` | `1px solid rgba(255, 255, 255, 0.08)` | | medido | | ### input.border-focus | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.border-focus` | `--sunny-input-border-focus` | `1px solid #FFB61F` | | medido | | ### input.border-invalid | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.border-invalid` | `--sunny-input-border-invalid` | `1px solid #FF5D5D` | | medido | | ### input.bg-invalid | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.bg-invalid` | `--sunny-input-bg-invalid` | `rgba(255, 93, 93, 0.06)` | `color.status.error.bg` | medido | | ### input.radius | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.radius` | `--sunny-input-radius` | `4px` | `radius.md` | medido | | ### input.padding | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.padding` | `--sunny-input-padding` | `12px 14px` | | medido | 14px horizontal foge da base 4; proposta é 12px 16px | ### input.font-size | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.font-size` | `--sunny-input-font-size` | `0.95rem` | | medido | Fora da escala; proposta é font.size.15 | ### input.label | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.label.family` | `--sunny-input-label-family` | `'JetBrains Mono', ui-monospace, monospace` | `font.family.mono` | medido | | | `input.label.size` | `--sunny-input-label-size` | `0.7rem` | | medido | Fora da escala; proposta é font.size.11 | | `input.label.weight` | `--sunny-input-label-weight` | `600` | `font.weight.semibold` | medido | | | `input.label.letter-spacing` | `--sunny-input-label-letter-spacing` | `0.12em` | | medido | | | `input.label.transform` | `--sunny-input-label-transform` | `uppercase` | | medido | | | `input.label.fg` | `--sunny-input-label-fg` | `#8F8F8F` | `color.text.secondary` | medido | | ### input.error | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.error.fg` | `--sunny-input-error-fg` | `#FF8888` | `color.status.error.text` | medido | | | `input.error.size` | `--sunny-input-error-size` | `0.75rem` | `font.size.12` | medido | | ### input.gap | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `input.gap` | `--sunny-input-gap` | `6px` | | medido | Entre label e campo | ### nav.link | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `nav.link.fg` | `--sunny-nav-link-fg` | `#DFDFDF` | `color.text.primary` | medido | | | `nav.link.fg-hover` | `--sunny-nav-link-fg-hover` | `#FFB61F` | `color.accent.default` | medido | | | `nav.link.underline` | `--sunny-nav-link-underline` | `2px solid #FFB61F` | | medido | | | `nav.link.font-size` | `--sunny-nav-link-font-size` | `0.875rem` | `font.size.14` | medido | | | `nav.link.font-weight` | `--sunny-nav-link-font-weight` | `500` | `font.weight.medium` | medido | | ### nav.gap | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `nav.gap` | `--sunny-nav-gap` | `32px` | `space.8` | medido | | ### focus.outline | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `focus.outline` | `--sunny-focus-outline` | `2px solid #FFB61F` | | medido | | ### focus.offset | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `focus.offset` | `--sunny-focus-offset` | `2px` | | medido | | ### header.bg-scrolled | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `header.bg-scrolled` | `--sunny-header-bg-scrolled` | `rgba(26, 26, 29, 0.92)` | `color.bg.header` | medido | | ### header.blur | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `header.blur` | `--sunny-header-blur` | `20px` | `blur.header` | medido | | ### header.border-bottom | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `header.border-bottom` | `--sunny-header-border-bottom` | `1px solid rgba(255, 182, 31, 0.08)` | | medido | | ### terminal.bg | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.bg` | `--sunny-terminal-bg` | `#0E1113` | `color.bg.terminal` | medido | Corpo da janela | ### terminal.bar | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.bar` | `--sunny-terminal-bar` | `#1A1A1D` | `color.neutral.900` | medido | Barra de título | ### terminal.bg-warm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.bg-warm` | `--sunny-terminal-bg-warm` | `#14110A` | `color.neutral.warm.950` | medido | Corpo da janela, variante quente | ### terminal.bar-warm | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.bar-warm` | `--sunny-terminal-bar-warm` | `#1A150C` | `color.neutral.warm.900` | medido | Barra de título, variante quente | ### terminal.dot-close | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.dot-close` | `--sunny-terminal-dot-close` | `#FF5D5D` | `color.feedback.error.500` | medido | Dot da esquerda. Posicional, não é estado de erro | ### terminal.dot-min | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.dot-min` | `--sunny-terminal-dot-min` | `#FFB61F` | `color.amber.500` | medido | Dot do meio. Posicional, não é aviso | ### terminal.dot-max | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.dot-max` | `--sunny-terminal-dot-max` | `#6FCF97` | `color.feedback.success.500` | medido | Dot da direita. Posicional, não é sucesso | ### terminal.dot-size | Token | Variável CSS | Valor | Aponta para | Status | Nota | |---|---|---|---|---|---| | `terminal.dot-size` | `--sunny-terminal-dot-size` | `11px` | | medido | Diâmetro do dot, igual em ScopeWard, DevXOS e Sunshine | ### Tema claro Sobrescritas aplicadas em `[data-theme="light"]`. O que não está aqui não muda. | Token | Valor no claro | Aponta para | |---|---|---| | `color.bg.base` | `#FFFFFF` | `color.neutral.0` | | `color.bg.card` | `#F7F7F5` | `color.neutral.50` | | `color.bg.elevated` | `#FFFFFF` | `color.neutral.0` | | `color.bg.accent-soft` | `#FFF8E6` | `color.amber.100` | | `color.text.primary` | `#1A1A1D` | `color.neutral.900` | | `color.text.secondary` | `#3A3A3A` | `color.neutral.600` | | `color.text.inverse` | `#DFDFDF` | `color.neutral.100` | | `color.text.accent` | `#7E5B14` | `color.amber.800` | | `color.text.accent-soft` | `#C98A12` | `color.amber.700` | | `color.border.subtle` | `rgba(0, 0, 0, 0.06)` | `color.alpha.black-6` | | `color.border.default` | `#E0DDD8` | | | `color.border.strong` | `#BCBCBC` | `color.neutral.200` | | `color.status.error.text` | `#B32D2D` | `color.feedback.error.700` | | `color.status.success.text` | `#2E7D4F` | `color.feedback.success.700` | | `color.status.warning.text` | `#A85B1E` | `color.feedback.warning.700` | | `color.status.info.text` | `#3A6A94` | `color.feedback.info.700` | ### Aliases de compatibilidade Nomes antigos de `website/src/style.css`, mantidos enquanto o site não migra. Não use em código novo. | Nome antigo | Token novo | Valor | |---|---|---| | `--color-amber` | `color.amber.500` | `#FFB61F` | | `--color-yellow` | `color.amber.400` | `#F0C840` | | `--color-yellow-light` | `color.amber.300` | `#F5D660` | | `--color-dark` | `color.amber.900` | `#332C15` | | `--color-black` | `color.neutral.900` | `#1A1A1D` | | `--color-gray-dark` | `color.neutral.600` | `#3A3A3A` | | `--color-gray-mid` | `color.neutral.400` | `#8F8F8F` | | `--color-gray-light` | `color.neutral.100` | `#DFDFDF` | | `--color-white` | `color.neutral.0` | `#FFFFFF` | | `--bg-dark` | `color.neutral.900` | `#1A1A1D` | | `--bg-dark-card` | `color.neutral.800` | `#1C2020` | | `--bg-dark-elev` | `color.neutral.700` | `#232828` | | `--bg-light` | `color.neutral.0` | `#FFFFFF` | | `--bg-light-card` | `color.neutral.50` | `#F7F7F5` | | `--bg-light-accent` | `color.amber.100` | `#FFF8E6` | | `--space-xs` | `space.1` | `4px` | | `--space-sm` | `space.2` | `8px` | | `--space-md` | `space.3` | `12px` | | `--space-lg` | `space.4` | `16px` | | `--space-xl` | `space.6` | `24px` | | `--space-2xl` | `space.8` | `32px` | | `--space-3xl` | `space.12` | `48px` | | `--space-4xl` | `space.16` | `64px` | | `--radius-sm` | `radius.sm` | `2px` | | `--radius-md` | `radius.md` | `4px` | | `--radius-lg` | `radius.lg` | `8px` | | `--radius-xl` | `radius.xl` | `12px` | | `--radius-full` | `radius.full` | `999px` | | `--font-display` | `font.family.display` | `'Bricolage Grotesque', sans-serif` | | `--font-body` | `font.family.body` | `'Inter', sans-serif` | | `--font-mono` | `font.family.mono` | `'JetBrains Mono', ui-monospace, monospace` | | `--sev-crit` | `color.severity.critical` | `#FF5D5D` | | `--sev-high` | `color.severity.high` | `#FF9E54` | | `--sev-med` | `color.severity.medium` | `#F0C840` | | `--sev-low` | `color.severity.low` | `#7FA6C9` | | `--sev-ok` | `color.severity.ok` | `#6FCF97` | --- ## Fontes da verdade | # | O que | Onde | |---|---|---| | 1 | Tokens, origem de todos os valores | `tokens/tokens.json` no repositório `sunnysystems/brand` | | 2 | Logo, paleta e fontes originais | Google Drive, pasta `_Sunny-NewBrand26` | | 3 | Implementação de referência | `website/src/style.css` | | 4 | Decisões | `docs/decisoes/`, append-only | Em caso de divergência, vence a fonte de número menor. Em setembro de 2026 os tokens foram medidos no site, então os dois batem. --- ## Comece aqui Fonte: `docs/00-comece-aqui.md` Porta de entrada da marca Sunny Systems. Aqui você entende o que existe, como usar e para onde ir. Este guia não substitui as fontes da verdade: ele organiza e aponta para elas. ### O que é Um conjunto de **tokens**, **regras de fundação**, **componentes** e **diretrizes** para que tudo que a Sunny publica pareça vir da mesma empresa: site, landings de produto, Sunshine, slides, propostas comerciais e posts. - **Tokens** são os valores: cor, tipo, espaçamento, radius, sombra. Vivem em `tokens` em três camadas: primitivo, semântico e de componente. - **Fundações** são as regras de uso de cada valor: [cores](#cores), [tipografia](#tipografia), [espaçamento, radius e elevação](#espaco), [logo](#logo), [ícones](#icones), [assets digitais](#assets). - **Componentes** são button, badge, card, input, nav item, header, stat e terminal, com estados, anatomia e acessibilidade. Ver o [índice e maturidade](#componentes). - **Padrões** são [acessibilidade](#acessibilidade) e [voz](#voz). - **Governança** é [como contribuir](#contribuir), [versionamento](#versionamento) e [quem procurar](#quem-procurar). - **Decisões** ficam em [`decisoes/`](#decisoes), registro append-only. ### O que não cobre - UI interna do Sunshine app e dos outros produtos: cada produto tem seu design system de componentes e consome os tokens daqui. O brand define a linguagem, não o componente de tabela. - Copy de produto e conteúdo de marketing. A [voz](#voz) dá o tom, não o texto. - Ícones customizados e ilustração. Ainda sem padrão; ver decisões pendentes. ### Princípios Quatro ideias que desempatam qualquer dúvida de marca. 1. **Dark é a fundação, não um tema.** Tudo nasce sobre `bg.base`. O claro existe para papel, slide e e-mail. 2. **Uma luz só.** O âmbar é a única cor de destaque. Se dois elementos na mesma tela pedem âmbar, um deles não merece. 3. **Semântico antes de valor.** Sempre `text.accent`, nunca `#FFB61F`. É o que faz tema, ajuste de marca e acessibilidade funcionarem de uma vez. 4. **Acessível por padrão.** WCAG 2.1 AA é critério de entrada, não polimento. Par de cor que falha não entra no token, componente sem foco visível não entra no índice. ### Por onde começar, por perfil **Dev** - Precisa de uma cor, espaçamento ou fonte: use a variável em `tokens/tokens.css`. Os nomes antigos do site continuam funcionando pelo bloco de compatibilidade. - Vai montar um botão, badge, card, input ou item de nav: siga a página do componente. Se o componente não existe, veja [contribuir](#contribuir). - Vai mostrar comando, ID ou log: `type.code`, fonte mono. **Marketing e vendas** - Logo: [regras e versões](#logo). Arquivos no Drive, pasta `_Sunny-NewBrand26`. - Slides e propostas: fundo `bg.base`, títulos em Bricolage Grotesque, corpo em Inter, âmbar só em destaque. A escala de slides está no fim de [tipografia](#tipografia). - Texto: [voz](#voz). Direto, técnico, brasileiro, sem travessão. **Produto e design** - Vai criar uma tela nova: comece pelos semânticos e pelos componentes existentes. Cor de estado é `status.*`, nunca âmbar. - Vai propor cor, fonte ou componente novo: abra uma decisão em [`decisoes/`](#decisoes) antes de desenhar. **Todos** - Dúvida "existe X?": este guia, depois o repositório do site. - Dúvida "quem decide?": [quem procurar](#quem-procurar). ### Fontes da verdade Em caso de divergência, a fonte da verdade vence, nesta ordem: | O que | Onde | Observação | |-------|------|------------| | Tokens | `tokens/tokens.json` neste repositório | `tokens.css` é gerado a partir dele | | Logo, paleta e fontes originais | Drive [`_Sunny-NewBrand26`](https://drive.google.com/drive/folders/1XPm1DFLp4ivX1RSUOUy9QWi71l6uSWyS) | .ai, .svg, .pdf, PNG, .ttf | | Implementação de referência | `sunnysystems/website`, `src/style.css` | Importa `tokens.css` desde o [website#14](https://github.com/sunnysystems/website/pull/14), em 15/09/2026. Ainda usa os nomes antigos pelo bloco de compatibilidade | | Decisões | [`docs/decisoes/`](#decisoes) | Append-only | | História | [`historia-da-marca.md`](#historia) | V1 a V4 e explorações | Estado em setembro de 2026: os tokens deste repositório foram **medidos no site**, então hoje os dois batem. A partir da adoção do `tokens.css` pelo site, este repositório passa a ser a origem. Plano em [versionamento](#versionamento). --- ## Fundações: cores Fonte: `docs/fundacoes/cores.md` Fonte da verdade: `tokens/tokens.json`. Os valores abaixo são gerados a partir dele. Em caso de divergência, o arquivo de tokens vence. Cada token tem um status: **medido** foi lido do site ou dos arquivos oficiais do Drive; **derivado** foi calculado a partir de valores medidos; **proposta** ainda não existe no site e aguarda validação. ### Como o sistema funciona Três camadas, como no Omnibus: 1. **Primitivos** são as cores em si, em escala: `color.amber.500`, `color.neutral.800`. 2. **Semânticos** dizem para que a cor serve: `color.text.primary`, `color.bg.card`, `color.accent.hover`. Apontam para primitivos. 3. **De componente** dizem onde entra: `button.primary.bg`, `badge.fg`. Apontam para semânticos. Regra: código e Figma usam **semânticos e de componente**. Primitivo direto só dentro do arquivo de tokens. É o que permite trocar o tema, ou ajustar o âmbar, em um lugar só. ### Âmbar (cor da marca) | Token | Hex | Status | Uso | |-------|-----|--------|-----| | amber.50 | #FFFDF4 | medido | Brilho na arte do hero | | amber.100 | #FFF8E6 | medido | Card de destaque no modo claro | | amber.200 | #FFE7A8 | medido | Traços finos na arte do hero | | amber.300 | #F5D660 | medido | **Amarelo claro oficial.** Texto de destaque suave | | amber.400 | #F0C840 | medido | **Amarelo oficial.** Hover do botão primário, severidade média | | amber.500 | #FFB61F | medido | **Âmbar oficial.** CTAs, destaques, foco, símbolo do logo | | amber.600 | #E5A31B | medido | Estado ativo, gradientes | | amber.700 | #C98A12 | medido | Faixas decorativas | | amber.800 | #7E5B14 | derivado | **Único âmbar aprovado como texto sobre branco** | | amber.900 | #332C15 | medido | **Escuro oficial.** Texto sobre âmbar | Como ler a escala: 50 a 200 são brilhos e fundos claros; 300 a 500 são os tons de marca; 600 a 900 são estados pressionados, texto e contraste. ### Neutros | Token | Hex | Status | Uso | |-------|-----|--------|-----| | neutral.0 | #FFFFFF | medido | Fundo do modo claro | | neutral.50 | #F7F7F5 | medido | Card do modo claro | | neutral.100 | #DFDFDF | medido | Texto principal sobre escuro | | neutral.200 | #BCBCBC | derivado | Bordas fortes no modo claro | | neutral.300 | #999999 | medido | "SYSTEMS" no wordmark | | neutral.400 | #8F8F8F | medido | Texto secundário | | neutral.500 | #5C5C5C | medido | Só decorativo. Não passa AA como texto sobre escuro | | neutral.600 | #3A3A3A | medido | "SUNNY" no wordmark, bordas fortes, texto secundário no claro | | neutral.700 | #232828 | medido | Superfície elevada | | neutral.800 | #1C2020 | medido | Card sobre escuro | | neutral.900 | #1A1A1D | medido | Fundo principal | | neutral.950 | #0E1113 | medido | Fundo de terminal | Atenção: card (800) sobre fundo (900) tem contraste de 1.1:1. A separação de superfície depende da borda `border.subtle`, não da cor. Isso é o site hoje; um ajuste do 800 está na lista de propostas. ### Feedback Proposta consolidada do que as páginas de produto já usam por conta própria. Três tons por estado: **300** para texto sobre escuro, **500** para ícone e borda, **700** para texto sobre claro. | Estado | 300 | 500 | 700 | De onde veio | |--------|-----|-----|-----|--------------| | error | #FF8888 | #FF5D5D | #B32D2D | Formulários de lead e `--sev-crit` | | success | #9ADFB6 | #6FCF97 | #2E7D4F | `--sev-ok` e "copiado" no DevXOS | | warning | #FFBE8A | #FF9E54 | #A85B1E | `--sev-high` e topologia do RootPilot | | info | #A9C4DD | #7FA6C9 | #3A6A94 | `--sev-low` | O 500 de cada estado é medido. Os 300 e 700 são derivados e precisam de validação visual. Por que warning é laranja e não âmbar: o âmbar é a cor da marca e aparece em todo CTA. Se aviso também fosse âmbar, um alerta de custo no Sunshine pareceria um botão. O laranja #FF9E54 já é a severidade alta no ScopeWard, então não é cor nova. Aliases de severidade para ScopeWard e RootPilot: `severity.critical` → error.500, `severity.high` → warning.500, `severity.medium` → amber.400, `severity.low` → info.500, `severity.ok` → success.500. ### Semânticos (tema escuro) | Token | Aponta para | Uso | |-------|-------------|-----| | bg.base | neutral.900 | Fundo da página | | bg.card | neutral.800 | Cards | | bg.elevated | neutral.700 | Popovers, superfícies sobre card | | bg.terminal | neutral.950 | Mockups de terminal | | bg.header | alpha.ink-92 | Header ao rolar, com blur | | text.primary | neutral.100 | Texto corrido e títulos | | text.secondary | neutral.400 | Descrições, legendas | | text.accent | amber.500 | Destaque em âmbar | | text.accent-soft | amber.300 | Destaque suave | | text.on-accent | amber.900 | Texto sobre botão e badge sólido | | border.subtle | alpha.white-4 | Borda de card em repouso | | border.default | alpha.white-8 | Borda de card em hover, inputs | | border.strong | neutral.600 | Seletor de idioma | | accent.default | amber.500 | CTAs | | accent.hover | amber.400 | Hover | | accent.active | amber.600 | Pressionado | | accent.soft | alpha.amber-10 | Fundo de badge | | accent.glow | alpha.amber-7 | Glow do hero | | focus.ring | amber.500 | Outline 2px, offset 2px | ### Tema claro O escuro é a fundação. O claro existe para documentos, slides e e-mail, e entra com `[data-theme="light"]`. As sobrescritas mais importantes: | Token | Escuro | Claro | |-------|--------|-------| | bg.base | neutral.900 | neutral.0 | | bg.card | neutral.800 | neutral.50 | | text.primary | neutral.100 | neutral.900 | | text.secondary | neutral.400 | neutral.600 | | text.accent | amber.500 | **amber.800** | | status.*.text | feedback.*.300 | feedback.*.700 | A troca de `text.accent` para amber.800 no claro é obrigatória: âmbar 500 sobre branco tem 1.8:1 e não serve para texto. Ver [Acessibilidade](#acessibilidade). ### Transparências | Token | Valor | Uso | |-------|-------|-----| | alpha.white-4 | rgba(255,255,255,0.04) | Borda de card | | alpha.white-8 | rgba(255,255,255,0.08) | Borda em hover | | alpha.amber-7 | rgba(255,182,31,0.07) | Glow radial do hero | | alpha.amber-10 | rgba(255,182,31,0.10) | Fundo de badge | | alpha.amber-15 | rgba(255,182,31,0.15) | Linha divisória, drop-shadow da ilustração | | alpha.amber-30 | rgba(255,182,31,0.30) | Glow forte | | alpha.ink-92 | rgba(26,26,29,0.92) | Header ao rolar | ### Faça e evite **Faça** - Use `text.accent` para âmbar em texto. Ele muda de tom sozinho no tema claro. - Use `status.*` para estado. Nunca âmbar para erro ou sucesso. - Use `border.subtle` para separar card de fundo. **Evite** - Hex direto no CSS ou no Figma. Sempre variável. - Âmbar 500 como texto sobre branco ou branco como texto sobre âmbar. - neutral.500 e neutral.600 como texto sobre escuro. - Criar um quinto tom de amarelo. A história da marca já teve quatro. ### Pendências - Validar visualmente os tons 300 e 700 de feedback. - Decidir se bg.card sobe para algo como #1F2426 para separar de bg.base sem depender de borda. - O site importa o `tokens.css` desde 15/09/2026, mas ainda usa os nomes antigos e tem hex escritos direto no CSS. Ver o passo 3 em [Versionamento](#versionamento). --- ## Fundações: tipografia Fonte: `docs/fundacoes/tipografia.md` Fonte da verdade: `tokens/tokens.json`, grupos `font` e `type`. ### Famílias | Papel | Família | Pesos | Carregamento | |-------|---------|-------|--------------| | Display, títulos, wordmark | Bricolage Grotesque | 400, 500, 700 | Google Fonts, eixo `opsz` 12 a 96 | | Corpo, UI, navegação | Inter | 400, 500, 600, 700 | Google Fonts | | Código, comandos, IDs, logs | JetBrains Mono | 400, 500, 600 | Google Fonts | Import único, como o site faz hoje: ```html ``` Fallbacks: `sans-serif` para as duas primeiras, `ui-monospace, monospace` para a mono. Os arquivos .ttf e .otf estão em `Fonts/` na pasta `_Sunny-NewBrand26` do Drive, para slides e documentos offline. **Bricolage Grotesque** tem personalidade e opsz, então fica melhor grande. Não use abaixo de 20px. **Inter** é neutra e feita para tela, então segura o corpo. **JetBrains Mono** é para qualquer coisa que o leitor possa copiar: comando de instalação, ID de recurso, trecho de log. Uma empresa de observabilidade mostra isso o tempo todo, e a doc anterior do site não tinha fonte mono. ### Primitivos **Tamanhos** em rem sobre raiz de 16px: | Token | Valor | Onde aparece no site | |-------|-------|----------------------| | size.12 | 0.75rem | Badge, cookie, rodapé | | size.13 | 0.8125rem | Botão pequeno do header, legendas | | size.14 | 0.875rem | Navegação, labels | | size.15 | 0.9375rem | Botões | | size.16 | 1rem | Corpo | | size.18 | 1.125rem | Descrição do hero | | size.20 | 1.25rem | Título de card | | size.22 | 1.375rem | Título de bloco | | size.fluid-sm | clamp(1.75rem, 3vw, 2.5rem) | Título de seção | | size.fluid-md | clamp(2rem, 4vw, 3.25rem) | Título de CTA | | size.fluid-lg | clamp(2.25rem, 4vw, 3.5rem) | Título de produto | | size.fluid-display | clamp(2.75rem, 5.5vw, 4.25rem) | h1 do hero | Os títulos são fluidos com `clamp`, não trocam por breakpoint. Isso é diferente do Omnibus, que tem um valor mobile e um desktop. Aqui a decisão é manter clamp porque o site já funciona assim e tem menos tokens para manter. **Entrelinha**: tight 1.08 (display), snug 1.2 (títulos), normal 1.6 (corpo), relaxed 1.75 (descrições longas). **Espaçamento de letras**: tight -0.02em (display), snug -0.01em (títulos), wide 0.08em (overline e badge), wider 0.14em (rótulos em caixa alta). ### Estilos semânticos Use estes, não os primitivos. Cada um vira um conjunto de variáveis `--sunny-type--`. | Estilo | Família | Tamanho | Peso | Entrelinha | Letras | Uso | |--------|---------|---------|------|------------|--------|-----| | display | display | fluid-display | 700 | 1.08 | -0.02em | h1 do hero, uma vez por página | | heading-1 | display | fluid-lg | 700 | 1.2 | -0.01em | Título de página de produto | | heading-2 | display | fluid-md | 700 | 1.2 | -0.01em | Título de CTA | | heading-3 | display | fluid-sm | 700 | 1.2 | -0.01em | Título de seção | | heading-4 | display | 22 | 600 | 1.2 | 0 | Título de bloco | | heading-5 | display | 20 | 600 | 1.2 | 0 | Título de card | | body-lg | body | 18 | 400 | 1.75 | 0 | Lead, descrição do hero | | body | body | 16 | 400 | 1.6 | 0 | Corpo padrão | | body-sm | body | 15 | 400 | 1.6 | 0 | Botões, texto denso | | label | body | 14 | 500 | 1.6 | 0 | Navegação, rótulos de campo | | caption | body | 13 | 400 | 1.6 | 0 | Legendas, metadados | | overline | body | 12 | 600 | 1 | 0.08em, caixa alta | Badge, categoria | | code | mono | 14 | 400 | 1.6 | 0 | Comandos, IDs, logs | Exemplo de uso: ```css .hero h1 { font-family: var(--sunny-type-display-family); font-size: var(--sunny-type-display-size); font-weight: var(--sunny-type-display-weight); line-height: var(--sunny-type-display-line-height); letter-spacing: var(--sunny-type-display-letter-spacing); } ``` ### Slides e documentos A escala da doc anterior do site (display 40px, h1 28px, body 12px, caption 9px) era para slides de 16:9 e continua válida **só nesse contexto**. Em web, use a tabela acima. Em slides, a regra é: display e títulos em Bricolage Grotesque, corpo em Inter, nunca abaixo de 11px. ### Faça e evite **Faça** - Um display por página. Ele é o ponto de luz tipográfico. - Mono para qualquer texto copiável. - Mínimo de 16px para corpo em web. **Evite** - Bricolage Grotesque em corpo de texto ou abaixo de 20px. - Mais de dois pesos na mesma tela além do display. - Caixa alta fora de overline e do wordmark. - Recriar o wordmark com texto. Use o arquivo do logo. --- ## Fundações: espaçamento, radius, elevação e movimento Fonte: `docs/fundacoes/espacamento-radius-elevacao.md` Fonte da verdade: `tokens/tokens.json`, grupos `space`, `radius`, `shadow`, `blur`, `motion` e `breakpoint`. ### Espaçamento Base de **4px**. O nome do token é o múltiplo. | Token | Valor | Uso típico | |-------|-------|------------| | space.1 | 4px | Gap mínimo, entre ícone e texto pequeno | | space.2 | 8px | Gap padrão, padding de badge | | space.3 | 12px | Padding de input, gap de linha | | space.4 | 16px | Padding interno de card pequeno | | space.6 | 24px | Padding de card, gap de grid | | space.8 | 32px | Padding de card grande, gap de navegação | | space.12 | 48px | Separação de blocos | | space.16 | 64px | Gap do grid do hero | | space.section | 100px | Padding vertical de seção | Regra: toda medida de layout é múltiplo de 4. Valores quebrados só em ajuste óptico de ícone, e com comentário. O Omnibus usa base 8. A Sunny usa base 4 porque o site já é assim e porque 12px aparece muito em UI densa de produto. Os múltiplos de 8 continuam sendo os preferidos para layout. ### Radius | Token | Valor | Uso | |-------|-------|-----| | radius.sm | 2px | Tags mínimas, barras | | radius.md | 4px | Botões, inputs | | radius.lg | 8px | Painéis, blocos de código | | radius.xl | 12px | Cards | | radius.full | 999px | Badges, pills, avatares | A marca é **contida**: botão com 4px, card com 12px. Não usar 16px ou mais fora de pill. Isso diferencia a V4 do Sunshine app, que usa arredondamento generoso, e é uma decisão a revisitar quando o Sunshine adotar estes tokens. ### Elevação Duas famílias: **glow** em âmbar para destaque, **elevation** em preto para profundidade. | Token | Valor | Uso | |-------|-------|-----| | shadow.glow-sm | 0 0 12px rgba(255,182,31,0.40) | Dots de status, ícones ativos | | shadow.glow-md | 0 0 30px rgba(255,182,31,0.30), 0 0 60px rgba(255,182,31,0.10) | Elemento de destaque do hero | | shadow.elevation-md | 0 12px 40px rgba(0,0,0,0.35) | Cards flutuantes, dropdowns | | shadow.elevation-lg | 0 24px 70px rgba(0,0,0,0.50) | Modais, mockups de tela | Cards em repouso **não têm sombra**. A separação é por `border.subtle`. Glow é raro: um por viewport, no elemento que merece o olhar. ### Glass | Token | Valor | Uso | |-------|-------|-----| | blur.header | 20px | Header ao rolar, sobre `bg.header` | | blur.card | 24px | Cards translúcidos sobre glow | Receita única de glass: fundo `bg.header` ou `alpha.white-4`, `backdrop-filter: blur(var(--sunny-blur-card))`, borda `border.subtle`. Texto sobre glass é sempre `text.primary`; nunca `text.secondary`, porque o fundo varia. ### Movimento | Token | Valor | Uso | |-------|-------|-----| | motion.duration.fast | 0.15s | Transform em hover de botão | | motion.duration.base | 0.2s | Cor, borda, opacidade | | motion.duration.slow | 0.3s | Header, cards, revelações | | motion.easing.default | ease | Tudo | Efeitos do site: particle network no hero, tilt 3D em cards, contadores animados, parallax, shimmer no texto. **Regra**: todo efeito desliga sob `prefers-reduced-motion: reduce`, e todo efeito novo precisa da mesma cláusula. **Estado real em 14/10/2026**: o site cumpre a regra quase toda desde o [website#10](https://github.com/sunnysystems/website/pull/10). Uma regra global no `style.css` encurta os `@keyframes` e as transições dos seis CSS, e cada efeito de `src/effects.ts` sai cedo quando a preferência está ativa. Faltam três efeitos em JavaScript sem guarda: o contador do gauge do ScopeWard (`scopeward/effects.ts`) e a rotação automática dos carrosséis do ScopeWard e do RootPilot. Até 14/09 este texto registrava que a regra não era cumprida, o que valia antes do #10. ### Breakpoints | Token | Valor | O que muda | |-------|-------|------------| | breakpoint.md | 768px | Menu vira mobile, grids viram uma coluna | | breakpoint.lg | 1024px | Grids de quatro viram dois | | breakpoint.container | 1200px | Largura máxima do conteúdo | ### Ícones Página própria: [Ícones](#icones). A proposta de Lucide em todos os produtos está na decisão [0008](#adr-0008). --- ## Fundações: logo Fonte: `docs/fundacoes/logo.md` Arquivos oficiais: pasta [`Logo-Sunny26`](https://drive.google.com/drive/folders/1TgapC-EwxlbKJLc9SnsQexN62SdbCuJo) no Drive, dentro de `_Sunny-NewBrand26`. Neste repositório, `assets/v4/` tem as treze versões em SVG, exportadas do Drive e conferidas com os arquivos de lá em 14/10/2026. ### Anatomia **Símbolo**: semicírculo de sol em âmbar cortado por faixas horizontais irregulares. Lê-se como um nascer do sol visto através de listras. Não tem raios; isso o separa do símbolo V1 e V2. Medido em `assets/v4/Icon-Positive.svg`: as faixas não são paralelas, são cunhas de espessura variável, e as de baixo passam da largura do semicírculo e apoiam em uma base sólida. O viewBox é 380 por 245,52, proporção 1,548:1. É um path único, então o arquivo aceita `fill: currentColor` sem edição. **Wordmark**: "SUNNY" em caixa alta, bold, e "SYSTEMS" em caixa alta, peso light, alinhado à direita sob "SUNNY". No arquivo é desenho em outline, não texto, e as letras não são Bricolage Grotesque: o N tem o topo arredondado. A fonte de origem não está registrada no Drive. Bricolage é para texto ao vivo, nunca para recriar o lockup. A versão anterior deste texto dizia que o wordmark era Bricolage. Cores medidas em `Logo-Hor-Color.svg`: | Elemento | Hex | Token | |----------|-----|-------| | Símbolo | #FFB61F | amber.500 | | SUNNY | #3A3A3A | neutral.600 | | SYSTEMS | #999999 | neutral.300 | ### Versões | Versão | Composição | Fundo | |--------|------------|-------| | Logo Hor Color | Símbolo âmbar + wordmark cinza, horizontal | Branco e claros | | Logo Hor White | Símbolo âmbar + wordmark branco, horizontal | Escuro | | Logo Hor Positive | Tudo escuro | Claros, impressão P&B | | Logo Hor Negative | Tudo claro | Escuros, impressão P&B | | Logo Vert * | Símbolo sobre wordmark, mesmas quatro composições | Quadrados, avatar, capa | | Icon Color / Positive / Negative | Só o símbolo | Favicon, app icon, avatar pequeno | | Name Positive / Negative | Só o wordmark | Rodapé, assinatura | Formatos: .ai, .svg, .pdf e PNG em 1.5x, 2x, 3x e 4x. Medido no `logo-hor-white.png` do site: símbolo #FFB61F, "SUNNY" e "SYSTEMS" em #FFFFFF. A documentação anterior do site descrevia essa versão como "totalmente branca"; não é. A versão toda branca é a Negative. Sobre fundo âmbar, portanto, usar Negative ou Positive, nunca a White, porque o símbolo âmbar some. O oficial é branco: o `Logo-Hor-White.svg` do Drive traz "SUNNY" e "SYSTEMS" em #FFFFFF. O SVG em uso no SunnyNet (`public/sunny-logo-white.svg`), com "SYSTEMS" em #DFDFDF, está errado. ### No site hoje | Contexto | Arquivo | Altura | |----------|---------|--------| | Header | logo-hor-white.png | 28px | | Rodapé | logo-hor-white.png | 22px | | Favicon | favicon-32.png (Icon Color) | 32px | | Apple touch | apple-touch-icon.png | 180px | | Open Graph | og-image.png com Logo Hor White | 1200x630 | | JSON-LD | logo-hor-color.png | | Só há PNG no repositório do site, e o mesmo logo branco está copiado em cinco pastas de produto. Ver pendências. ### Regras **Área de proteção**: mínimo igual à altura do "S" de "SUNNY" em todos os lados. **Tamanho mínimo**: 22px de altura para o horizontal em tela, que é o menor uso no site hoje. Abaixo disso, usar só o Icon. Em impressão, 12mm de altura. **Escolha por espaço**: largo usa o horizontal, quadrado usa o vertical. Pequeno demais para o nome usa só o ícone, e só quando "Sunny Systems" já está no contexto. **Escolha por fundo**: - Fundo escuro: Logo Hor White. - Fundo âmbar: Logo Hor Positive (tudo escuro) ou Negative (tudo claro). - Fundo branco ou claro: Logo Hor Color. - Foto ou gradiente: White, sobre área com contraste; se não houver, colocar um bloco de `bg.base` atrás. - Impressão monocromática: Positive ou Negative. **Não faça** - Alterar cores, inclusive trocar o cinza do wordmark por âmbar. - Distorcer, rotacionar ou espelhar. - Aplicar sombra, glow, contorno ou gradiente sobre o logo. O glow é do fundo, não do logo. - Recriar o wordmark com texto ao vivo. - Usar Logo Hor Color sobre escuro. O cinza #3A3A3A some. - Usar o símbolo V1 ou V2 (raios) em material novo. - Gerar o logo, ou uma variação dele, com IA. - Passar a versão Color para cinza. Se a cor precisa sumir, use Positive ou Negative. ### Em código ```html Sunny Systems Sunny Systems ``` `alt` é sempre "Sunny Systems". Se o logo é link para a home, o `alt` continua "Sunny Systems" e o link recebe `aria-label="Sunny Systems, página inicial"`. ### Pendências - Registrar no Drive a fonte de origem do wordmark. - Substituir os PNG do repositório do site pelos SVG. - Um arquivo por versão no site, referenciado de `/images/`, em vez de cópia por produto. - Gerar a imagem Open Graph com acentos corretos. Regras em [assets digitais](#assets). - Avatar social: proposta na decisão [0009](#adr-0009), Icon Color sobre `bg.base`, sem wordmark. --- ## Fundações: ícones Fonte: `docs/fundacoes/icones.md` **Proposta**, depende da decisão [0008](#adr-0008). Até ela ser aceita, este é o conjunto para site, landing e chrome, e os produtos seguem como estão. São dois tipos: o ícone de interface, que é Lucide, e o ícone de marca, que é o sol. ### Interface - Biblioteca: [Lucide](https://lucide.dev). Uma só, sem misturar. - Traço 1.5px, pontas e junções arredondadas, `fill: none`, `stroke: currentColor`. O Lucide vem com traço 2px; passe 1.5 explicitamente. - Tamanhos: 16px em interface densa, 20px como padrão, 24px para destaque. - Acima de 128px, ícone de conceito vira ilustração. Não use Lucide no hero. Recorte usado no guia, com o nome do ícone no Lucide: | Grupo | Ícones | |-------|--------| | Interface | `menu`, `search`, `x`, `check`, `plus`, `list-filter` | | Ação | `download`, `copy`, `share-2`, `pencil` | | Status | `circle-check`, `triangle-alert`, `circle-x`, `info` | | Produto | `activity`, `terminal`, `shield`, `cloud`, `lock` | Não é a biblioteca inteira. Precisou de outro, use o do Lucide com as mesmas regras. ### Status A cor vem de `color.status..icon`, para success, warning, error e info. Nunca âmbar para erro, aviso ou sucesso ([0004](#adr-0004)). ### Marca O sol, nas três versões de ícone do Drive, em `assets/v4/`: | Arquivo | Cor | Fundo | |---------|-----|-------| | `Icon-Color.svg` | Âmbar #FFB61F | Escuro | | `Icon-Positive.svg` | Cinza #3A3A3A | Claro | | `Icon-Negative.svg` | Branco | Escuro ou âmbar | O sol não ganha versão em traço e não entra na galeria de interface. ### Acessibilidade - Ícone sem texto: `aria-label` no botão ou link que o contém. - Ícone ao lado de texto: `aria-hidden="true"` no SVG. - O alvo de toque continua sendo 44px em mobile, mesmo com ícone de 16px. ### Não faça - Baixar pacote de ícones de outro cliente ou de banco de imagens. - Juntar dois ícones para inventar um terceiro. - Rotacionar, preencher ou esticar. - Gerar ícone com IA. ### Hoje O site usa SVG inline desenhado à mão, com traço fino e sem biblioteca. O Sunshine app usa Lucide. --- ## Fundações: assets digitais Fonte: `docs/fundacoes/assets-digitais.md` **Proposta**, depende da decisão [0009](#adr-0009). Favicon, avatar e ícone de canal usam só o sol. O Open Graph usa o lockup horizontal. Todo arquivo parte de `assets/v4/`, exportado do Drive. | Asset | Tamanho | Versão | Fundo | Hoje | |-------|---------|--------|-------|------| | Favicon | 32px, e 180px no apple-touch | Icon Color | `bg.base` | No ar, `favicon-32.png` | | Avatar social | Quadrado | Icon Color, sem wordmark | `bg.base` | Proposta | | Open Graph | 1200×630 | Logo Hor White | `bg.base` | No ar com acentos errados; gerar de novo | | Capa do YouTube | 16:9. O YouTube recomenda 2560×1440, com área segura de 1546×423 no centro | Logo Hor White sobre foto escura | Foto | Existe uma, com 2903×1633. O arquivo-fonte não foi localizado no Drive | | Ícone do canal | Quadrado | Icon Color | `bg.base` | Proposta | ### Regras - Abaixo de 22px de altura, nunca o horizontal: use o Icon. - Avatar quadrado com cantos suaves. Se a plataforma corta em círculo, o sol cabe inteiro no círculo, com a área de proteção. - Sobre âmbar: Icon Negative ou Positive, nunca Color. - Foto: Logo Hor White sobre área escura da foto. Sem área escura, um bloco de `bg.base` atrás. ### Não faça - Gerar favicon, Open Graph, avatar ou capa com IA. - Redesenhar o logo a partir de screenshot ou de PNG pequeno. - Usar o lockup inteiro em favicon ou avatar. A escolha da versão por fundo e por espaço está em [Logo](#logo). --- ## Componentes: índice e maturidade Fonte: `docs/componentes/README.md` O que existe, onde está implementado e o quanto dá para confiar. O detalhe de cada um, com variantes, estados, anatomia e acessibilidade, está na página do componente. Os componentes aqui são os da **camada de marca**: o que aparece em site, landings, slides e no chrome dos produtos. Componentes internos de produto ficam no produto. ### Índice e maturidade | Componente | Categoria | Maturidade | Implementado em | Tokens | |------------|-----------|------------|-----------------|--------| | [Button](#componente-button) | Atom | Stable | Site, cinco landings | `button.*` | | [Badge](#componente-badge) | Atom | Stable | Site, cinco landings | `badge.*` | | [Card](#componente-card) | Molecule | Stable | Site, cinco landings | `card.*` | | [Input](#componente-input) | Atom | Beta | Landings RootPilot e Soberania | `input.*` | | [Nav item](#componente-nav-item) | Atom | Stable | Header do site | `nav.*` | | [Header](#componente-header) | Organism | Stable | Site, cinco landings | `header.*` | | [Stat](#componente-stat) | Molecule | Stable | Site, cinco landings | Sem token próprio | | [Terminal mockup](#componente-terminal) | Molecule | Beta | ScopeWard, DevXOS, Sunshine | `terminal.*` | | Toast, Alert, Modal, Tabela | | Proposta, sem código | | `color.status.*` | Legenda: **Stable** em produção com valores medidos; **Beta** implementado em um lugar, pode mudar; **Proposta** só documentado. ### Regras comuns - Só tokens semânticos e de componente. Nenhum hex. - Todo estado interativo tem default, hover, focus-visible, active e disabled. Foco é sempre `focus.outline` com `focus.offset`. - Alvo de toque mínimo de 44 por 44px em mobile. - Transições usam `motion.duration.*`; nada anima sob `prefers-reduced-motion`. - Texto vem de props ou i18n, nunca fixo no componente. ### Critérios para entrar no índice Ver [contribuir](#contribuir). Em resumo: variantes, estados, anatomia com medidas, API ou classes, seção de acessibilidade, e código em pelo menos um produto ou rótulo "sem código". --- ## Componente: Button Fonte: `docs/componentes/button.md` **Stable** · Implementado em `website/src/style.css` como `.btn-primary` e `.btn-secondary`. Ação principal ou secundária. Um primário por bloco; o resto é secundário ou link. ### Variantes | Variante | Quando | Fundo | Texto | Borda | |----------|--------|-------|-------|-------| | Primary | A ação que queremos que aconteça | `button.primary.bg` (âmbar) | `button.primary.fg` (amber.900) | nenhuma | | Secondary | Ação alternativa ao lado do primário | transparente | `button.secondary.fg` (âmbar) | 1.5px âmbar | Sem variante destrutiva na camada de marca. Produto que precisar usa `color.status.error.*` e documenta no próprio DS. ### Tamanhos | Tamanho | Altura aprox. | Padding | Fonte | |---------|---------------|---------|-------| | Default | 48px | 14px 32px | body-sm, 15px, 600 | | Small | 40px | 10px 24px | caption, 13px, 600 | Small só no header e em contextos densos. ### Estados | Estado | Primary | Secondary | |--------|---------|-----------| | Default | `accent.default` | borda e texto `accent.default` | | Hover | `accent.hover` (amber.400), `translateY(-1px)` | fundo `accent.default`, texto `text.on-accent` | | Focus-visible | `focus.outline` 2px âmbar, offset 2px | igual | | Active | `accent.active` (amber.600), sem translate | igual ao hover | | Disabled | opacidade 0.5, `cursor: not-allowed`, sem hover | igual | Disabled e active são **proposta**: o site não os define hoje. ### Anatomia - Display inline-flex, `align-items: center`, gap `space.2` entre ícone e texto. - Radius `radius.md` (4px). Não usar pill em botão. - Ícone, quando houver, 16px, à esquerda do texto, `currentColor`. - Largura mínima natural; `fullWidth` só em mobile abaixo de `breakpoint.md`. - Transição: fundo em `motion.duration.base`, transform em `motion.duration.fast`. ### Uso ```html Falar com a Sunny Conheça nossos pilares ``` Em CSS, os tokens: ```css .btn-primary { background: var(--sunny-button-primary-bg); color: var(--sunny-button-primary-fg); padding: var(--sunny-button-padding-y) var(--sunny-button-padding-x); border-radius: var(--sunny-button-radius); font: var(--sunny-button-font-weight) var(--sunny-button-font-size) var(--sunny-font-family-body); } .btn-primary:hover { background: var(--sunny-button-primary-bg-hover); } ``` ### Acessibilidade - Ação de navegação é ``, ação na página é `