SaldoMais
Carregando…
Documento 05 de 07

Design System

Tokens de design (variáveis CSS), componentes de UI reutilizáveis, convenções de estilo e comportamento responsivo — referência para manter consistência visual ao criar ou modificar telas.

Tokens de cor

Definidos como CSS custom properties em :root em css/index.css. Toda a interface usa exclusivamente essas variáveis — não há valores de cor hardcoded fora delas.

:root {
  /* Backgrounds */
  --bg:     #0b0b0c;                   /* fundo principal */
  --bg-2:   rgba(255,255,255,0.03);    /* camada elevada (sidebar, cabeçalho) */
  --card:   rgba(255,255,255,0.04);    /* cards e painéis */
  --border: rgba(255,255,255,0.08);    /* bordas de todos os elementos */

  /* Tipografia */
  --text:   #f5f5f5;   /* texto primário */
  --muted:  #a1a1aa;   /* texto secundário, labels, legendas */

  /* Semântica */
  --accent: #f59e0b;   /* âmbar — destaque, botão primário, slider thumb */
  --danger: #ef4444;   /* vermelho — erro, limite excedido, ação destrutiva */
  --warn:   #fb923c;   /* laranja — alerta, gasto parcial, acima de 80% */
  --ok:     #22c55e;   /* verde — sucesso, dentro do orçamento */
}
TokenValorUso
--bg#0b0b0cFundo principal da aplicação
--accent#f59e0bDestaque, botão primário, links
--ok#22c55eSucesso, dentro do orçamento
--warn#fb923cAlerta, gasto entre 80–100%
--danger#ef4444Erro, limite excedido
--text#f5f5f5Texto primário
--muted#a1a1aaTexto secundário, labels
PDF: PDF_COLORS em core.js contém os mesmos conceitos em RGB para uso com jsPDF.

Tipografia

Fonte única: Inter (Google Fonts), pesos 400, 500 e 600.

ContextoTamanhoPeso
Título de tela (h2)28px600
Subtítulo de seção (h3)18px600
Label de input14px500
Texto de card14px400
Valor de stat card24px700
Helper / legenda12px400
Atalho de teclado (kbd)10px400

Layout

Estrutura principal

.app (display: flex; height: 100vh)
  ├── aside.sidebar    (width: 230px, fixo)
  └── main.content     (flex: 1, overflow-y: auto)

A sidebar usa backdrop-filter: blur(20px) sobre --bg-2, criando efeito de vidro fosco. Não há scroll na sidebar.

Grid de dashboard

.dashboard-content usa grid-template-columns: 1.2fr 1fr. Colapsa para coluna única em @media (max-width: 768px).

Grid de calculadoras

.calc-grid usa grid-template-columns: 1fr 1fr. Colapsa para coluna única em @media (max-width: 900px).

Card

.card {
  background: var(--card);
  backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 20px;
  transition: all 0.25s ease;
}
.card:hover {
  transform: translateY(-4px);
  border-color: rgba(255,255,255,0.15);
}

Eleva levemente no hover via translateY. Usado como container para formulários, painéis e seções do dashboard.

Stat Card

ClasseDescrição
.stat-cardContainer com flexbox coluna
.stat-labelTexto uppercase, --muted, 13px
.stat-valueValor principal, 24px, bold
.stat-barBarra de progresso (fundo)
.stat-bar-fillPreenchimento com gradiente accent→warn
.stat-subtitleTexto auxiliar, 12px, --muted
O card de "Disponível" tem border-color e background dinâmicos aplicados inline: verde se positivo, vermelho se negativo.

Botões

ClasseAparênciaUso
.btn-primary--accent, texto pretoAção principal
.btn-danger--danger, texto brancoAção destrutiva
.btn-export-pdfTransparente, borda amberExportar PDF
.btn-backupTransparente, borda sutilBackup/restore
.btn-salvar-percentuais--accent, boldSalvar percentuais
.btn-adicionar-cat--accent, boldAdicionar categoria
.btn-editar-cat--accent, texto pretoEditar categoria
.btn-deletar-cat--danger, texto brancoRemover categoria

Inputs e Selects

input, select {
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,0.03);
  color: var(--text);
}
input:focus, select:focus {
  border-color: rgba(245,158,11,0.5);
  box-shadow: 0 0 0 3px rgba(245,158,11,0.1);
  background: rgba(255,255,255,0.05);
}

O foco usa um anel amber sutil. Em mobile (@media (max-width: 768px)), font-size: 16px é aplicado para evitar zoom automático do iOS.

Barras de progresso

Dois componentes de barra distintos:

  • .stat-bar / .stat-bar-fill — no stat card de "Total Gasto": gradiente accent→warn, animação de width 0.4s.
  • .barra / .barra-fill — barras de status por categoria: cor aplicada inline dinamicamente. Verde < 80% | laranja 80–100% | vermelho > 100%. A barra é limitada a min(percentualGasto, 100) visualmente.

Slider de percentual

.percentual-slider {
  -webkit-appearance: none;
  height: 6px;
  background: rgba(255,255,255,0.08);
}
.percentual-slider::-webkit-slider-thumb {
  width: 16px; height: 16px;
  background: var(--accent);
  box-shadow: 0 2px 8px rgba(245,158,11,0.4);
}

Estilos cross-browser para ::-webkit-slider-thumb e ::-moz-range-thumb. O thumb cresce no hover (scale(1.2)).

Toast de notificação

.notification-toast {
  position: fixed;
  bottom: 20px; right: 20px;
  background: rgba(0,0,0,0.9);
  backdrop-filter: blur(10px);
  opacity: 0; transform: translateY(20px);
  transition: all 0.3s ease;
}
.notification-toast.show {
  opacity: 1; transform: translateY(0);
}

Aparece no canto inferior direito com fade + slide. Desaparece após 2500ms via setTimeout em notificar().

Modais

Os dois modais (#confirmModal e #editarCategoriaModal) compartilham .confirm-modal:

.confirm-modal {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.7);
  backdrop-filter: blur(5px);
  z-index: 9997;
}
.confirm-modal.show {
  display: flex;
  justify-content: center;
  align-items: center;
}

O container interno (.confirm-container) é um card com max-width: 400px e box-shadow profundo.

Loading overlay

.loading-overlay {
  position: fixed; inset: 0;
  background: linear-gradient(135deg, #0b0b0c 0%, #1a1a1e 50%, #0b0b0c 100%);
  z-index: 9999;
  opacity: 0; pointer-events: none;
  transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.loading-overlay.show {
  opacity: 1; pointer-events: auto;
}

Contém logo animado (logoFloat), anel spinner (spinRing) e texto com ellipsis (dotAnimation).

Animações

NomeUsoComportamento
spinRingAnel do loadingRotação 360° infinita, 2s linear
logoFloatLogo do loadingTranslateY -8px + scale 1.05, 3s ease-in-out
fadeInOutTexto do loadingOpacidade 0.6→1→0.6, 1.5s
dotAnimationEllipsis do loadingcontent steps: '' → '.' → '..' → '...'
fadeSlideInResultado das calculadorasopacity 0→1, translateY 10px→0, 0.28s
fadeSlideOutFechamento do resultadoopacity 1→0, translateY 0→-8px, 0.2s

Responsividade

BreakpointMudanças
≤ 900px.dashboard-grid e .calc-grid colapsam para 1 coluna
≤ 768pxSidebar oculta (translateX -100%), mobile header exibido, .dashboard-content colapsa, .nav-shortcut oculto, font-size: 16px nos inputs

Mobile header (#hamburgerBtn + logo) fica fixo no topo com height: 56px. O conteúdo principal tem padding-top: 72px para não ficar sob o header.

Sidebar mobile: abre via .sidebar.open com overlay #sidebarOverlay. Fecha ao clicar no overlay ou em qualquer .nav-btn.

Z-index

Elementoz-index
.loading-overlay9999
.notification-toast9998
.confirm-modal9997
.sidebar (mobile)200
.mobile-header100
.sidebar-overlay99
.calc-table th (sticky)1