Sistema de Ícones — migração lucide-react → unplugin-icons
lucide-react removido por completo e substituído por unplugin-icons apoiado em três datasets Iconify (@iconify-json/lucide, @iconify-json/simple-icons, @iconify-json/mdi) mais uma coleção custom lida via FileSystemIconLoader de app/icons/custom/. Cada ícone agora resolve para um componente SVG inline em build-time — zero fetch em runtime, SSR-safe no Cloudflare Workers, e o chunk manual vendor-lucide foi descontinuado.
API de uso por dataset:import Trophy from "~icons/lucide/trophy" para ícones genéricos de UI, ~icons/simple-icons/<name> para logos de marca (WhatsApp, Facebook, X, Instagram, TikTok), ~icons/mdi/<name> para esportes e equivalentes a emojis, e ~icons/custom/<name> para SVGs próprios em app/icons/custom/ (auto-discovered). Naming kebab-case obrigatório (AlarmClock → alarm-clock, XCircle → x-circle).
Tipo IconComponent substitui LucideIcon em todo o codebase via app/types/icon.ts (superset de SVGProps<SVGSVGElement> com alias legacy de size). unplugin-icons não suporta a prop size do Lucide — codemod scripts/migrate-icon-size-prop.mjs converteu 471 ocorrências de size={X} para width={X} height={X}.
Registry string-driven em app/icons/registry.ts para configs que referenciam ícones por string (ex: icon: "mdi:soccer") consumidos via <Icon name="..." /> ou <SmartIcon icon={...} /> (smart dispatch que renderiza o ícone registrado ou cai no texto literal — preserva configs legados com emoji).
Exceções aceitáveis para SVG inline: spinners/loaders animados customizados, checkmarks de success animados, indicadores visuais brand-specific que não existem em nenhum dataset Iconify, e seals de regulação (ANJL, Anatel, Compulsafe) servidos via <img> apontando para public/assets/seals/.
Migração automatizada via codemods em scripts/: migrate-lucide-to-unplugin-icons.mjs (converte imports nomeados em default imports kebab-case, ordenado via biome check --write), migrate-icon-size-prop.mjs (size → width/height em JSX) e migrate-emoji-icons.mjs (emoji literais → IconName registrado). Fix posterior em toKebabCase para acrônimos consecutivos (XCircle → x-circle, antes virava xcircle quebrado).
Novo widget sidebar-buttons substitui o VipHighlightButton hardcoded por um sistema config-driven com catálogo typed (closed enum) de 8 intents: casino, sports, tournaments, missions, referral, rewards, mini-games, promotions. Cada intent tem rota canônica + i18n key + ícone default (Lucide) em app/widgets/sidebar-buttons/intents.ts — brand customiza só o visual (label, icon, image, color, gradient, sublabel, badge), nunca a rota. Para CTAs one-off fora do catálogo, brand usa customItems (label + href diretos); para UI dedicada, há o special sponsor-cta.
3 variants visuais disponíveis: colored (pilha vertical full-width com gradient diagonal — mostra bônus dinâmico do referral), gradient (pills compactas com gradient horizontal accent → muted, single-line, look 7k legado) e grid (3-col tile grid com decoration watermark, look Vera). variant: null desliga o widget na brand.
Hierarquia de override de cor em 3 tiers: gradient: [from, to] (tupla, override completo) > color: "#hex" (só accent) > theme tokens brand-aware (bg-sidebar-button-bg). Sem override per-item, cada brand vê o widget pintado automaticamente nas suas próprias cores via tokens do tema.
Wiring no SidebarNarrow.tsx lê sidebarButtonsConfig e delega pro <SidebarButtons />. O VipHighlightButton foi removido — não há callers remanescentes.
Reorg do app/config/ em 14 subpastas semânticas (theme/, layout/, widgets/, sections/, catalog/, routes/, analytics/, features/, scripts/, legal/, seo/, payments/, gamification/, sports/). Imports passam a usar caminho completo sem o sufixo .config: ~/config/theme/colors, ~/config/layout/composition, ~/config/widgets/sidebar-buttons, ~/config/routes/paths. Mesmo reorg replicado nos 13 brand overrides — mantém o lookup do brandOverridesPlugin em sincronia file-replacement.
Brand resolver compartilhado (vite-plugins/brand-resolver.mjs) consolida três blocos existsSync(overrides/...) duplicados (Vite plugin, app/router/routes.ts em vite-node, tailwind.config.js em PostCSS) em uma única source of truth: toBrandOverrideKey, findBrandOverride, resolveBrandFile.
Asset dedup: fortune-fruits.mp4 e fortune-snake.mp4 movidos para public/assets/thumbs/ no base; cópias idênticas removidas de 6 brand overrides (validado por md5).
Bump @cactus-agents/i18n para 0.71.0 com as keys do namespace layout:sidebar-buttons.* nos 4 locales (pt-br, pt, es, en).