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).
Rows de Favoritos e Jogos recentes ganham fallback automático: quando o user logado tem menos de 7 itens, a row renderiza no mesmo carrossel um placeholder dashed + divisor "Sugestões" + até 10 jogos sugeridos a 50% de opacidade (sobe pra 100% no hover/focus). A row de "Jogos recentes" passa a aparecer mesmo vazia (antes sumia).
Fonte das sugestões: getSuggestions() novo no GamesCacheService — lê catálogo completo via getAllGames(), ordena por stats cache-only (zero BFF round-trip) e filtra métrica > 0. Favoritos usa players_month (top 10), recentes usa players_today (top 10). Em cold start sem stats, completa com random seeded por dia UTC pra ordem estável dentro do mesmo dia.
Gated pela flag opt-in rowSuggestionsInEmptyStates, ligada em vera-bet-br, 7k-bet-br, cassino-bet-br, betpontobet-bet-br, cl-bet7k-com. Default false nas demais 9 brands para não regredir visual.
Componentes novos: EmptyRowPlaceholder (card dashed com dimensões idênticas ao GameCard — zero layout shift) e SuggestionsDivider (separador vertical "— → Sugestões → —").
FLIP safety mantida no FavoritesRow: o cardElementsRef só registra cards de favoritos reais; sugestões não participam do reflow.
Documentação do widget pattern em architecture/layout-composition.md com nova seção "Widgets — UI opcional embebida em slots". Documenta o pattern { variant: VariantKey | null, items: Item[] }, lista os 5 widgets ativos hoje (sidebar-buttons, topbar-notifications, bottom-notifications, campaign-widget, home-leagues) e detalha o catálogo de 8 intents do sidebar-buttons, as 3 variants e a hierarquia de override (gradient > color > theme tokens).
forking/override-files.md reescrito para refletir a estrutura de 14 subpastas. Nova árvore, tabelas escopo-a-escopo e regra de file-replacement (não deep-merge) chamada explicitamente — brands não devem esperar merge parcial em overrides.
template/layout.md ganhou tabela de Widgets + exemplo de config do sidebar-buttons mostrando uso brand-side com intent + gradient.
Sweep de paths em 18 docs (externa + interna) apontando pra nova estrutura de subpastas: app/config/theme.config.ts → app/config/theme/colors.ts, routes.paths.ts → routes/paths.ts, layout.config.ts → layout/composition.ts, features.config.ts → features/features.ts e equivalentes nos demais escopos. Pure path sweep, sem mudança semântica.