@omnizap-system/omnizap 2.6.0 → 2.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.env.example +58 -13
  2. package/.github/workflows/ci.yml +5 -5
  3. package/.github/workflows/codeql.yml +1 -1
  4. package/.github/workflows/db-migration-check.yml +2 -2
  5. package/.github/workflows/dependency-review.yml +1 -1
  6. package/.github/workflows/deploy.yml +2 -2
  7. package/.github/workflows/release.yml +2 -2
  8. package/.github/workflows/security-attest-provenance.yml +2 -2
  9. package/.github/workflows/security-gitleaks.yml +13 -4
  10. package/.github/workflows/security-runner-hardening.yml +2 -2
  11. package/.github/workflows/security-scorecard.yml +1 -1
  12. package/.github/workflows/security-zap-baseline.yml +1 -1
  13. package/.github/workflows/security-zap-full-scan.yml +2 -1
  14. package/.github/workflows/security-zizmor.yml +1 -1
  15. package/.github/workflows/wiki-sync.yml +1 -1
  16. package/.gitleaksignore +9 -0
  17. package/CODE_OF_CONDUCT.md +2 -2
  18. package/GEMINI.md +64 -0
  19. package/README.md +52 -82
  20. package/SECURITY.md +1 -1
  21. package/app/config/index.js +2 -0
  22. package/app/configParts/adminIdentity.js +5 -5
  23. package/app/configParts/baileysConfig.js +230 -58
  24. package/app/configParts/groupUtils.js +5 -0
  25. package/app/configParts/messagePersistenceService.js +145 -4
  26. package/app/configParts/sessionConfig.js +157 -0
  27. package/app/connection/baileysCompatibility.test.js +1 -1
  28. package/app/connection/groupOwnerWriteStateResolver.js +109 -0
  29. package/app/connection/socketController.js +660 -158
  30. package/app/connection/socketController.multiSession.test.js +108 -0
  31. package/app/controllers/messageController.js +1 -1
  32. package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
  33. package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
  34. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
  35. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
  36. package/app/controllers/messageProcessingPipeline.js +93 -13
  37. package/app/controllers/messageProcessingPipeline.test.js +200 -0
  38. package/app/modules/adminModule/AGENT.md +1 -1
  39. package/app/modules/adminModule/commandConfig.json +3318 -1347
  40. package/app/modules/adminModule/groupCommandHandlers.js +858 -15
  41. package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
  42. package/app/modules/adminModule/groupWarningRepository.js +152 -0
  43. package/app/modules/aiModule/AGENT.md +47 -30
  44. package/app/modules/aiModule/aiConfigRuntime.js +1 -0
  45. package/app/modules/aiModule/catCommand.js +135 -27
  46. package/app/modules/aiModule/commandConfig.json +114 -28
  47. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
  48. package/app/modules/gameModule/AGENT.md +1 -1
  49. package/app/modules/gameModule/commandConfig.json +29 -0
  50. package/app/modules/menuModule/AGENT.md +1 -1
  51. package/app/modules/menuModule/commandConfig.json +45 -10
  52. package/app/modules/menuModule/menuCatalogService.js +190 -0
  53. package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
  54. package/app/modules/menuModule/menuDynamicService.js +511 -0
  55. package/app/modules/menuModule/menuDynamicService.test.js +141 -0
  56. package/app/modules/menuModule/menus.js +36 -5
  57. package/app/modules/playModule/AGENT.md +10 -5
  58. package/app/modules/playModule/commandConfig.json +140 -12
  59. package/app/modules/playModule/playCommand.js +1 -1417
  60. package/app/modules/playModule/playCommandConstants.js +80 -0
  61. package/app/modules/playModule/playCommandCore.js +361 -0
  62. package/app/modules/playModule/playCommandHandlers.js +41 -0
  63. package/app/modules/playModule/playCommandMediaClient.js +1872 -0
  64. package/app/modules/playModule/playConfigRuntime.js +245 -4
  65. package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
  66. package/app/modules/quoteModule/AGENT.md +1 -1
  67. package/app/modules/quoteModule/commandConfig.json +29 -0
  68. package/app/modules/quoteModule/quoteCommand.js +3 -2
  69. package/app/modules/rpgPokemonModule/AGENT.md +1 -1
  70. package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
  71. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
  72. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
  73. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
  74. package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
  75. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
  76. package/app/modules/statsModule/AGENT.md +1 -1
  77. package/app/modules/statsModule/commandConfig.json +58 -0
  78. package/app/modules/statsModule/rankingCommon.js +5 -4
  79. package/app/modules/stickerModule/AGENT.md +1 -1
  80. package/app/modules/stickerModule/addStickerMetadata.js +4 -3
  81. package/app/modules/stickerModule/commandConfig.json +145 -0
  82. package/app/modules/stickerModule/stickerCommand.js +1 -1
  83. package/app/modules/stickerPackModule/AGENT.md +1 -1
  84. package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
  85. package/app/modules/stickerPackModule/commandConfig.json +29 -0
  86. package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
  87. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
  88. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
  89. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
  90. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
  91. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
  92. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
  93. package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
  94. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
  95. package/app/modules/stickerPackModule/stickerPackService.js +13 -6
  96. package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
  97. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
  98. package/app/modules/systemMetricsModule/AGENT.md +1 -1
  99. package/app/modules/systemMetricsModule/commandConfig.json +29 -0
  100. package/app/modules/systemMetricsModule/pingCommand.js +6 -5
  101. package/app/modules/tiktokModule/AGENT.md +1 -1
  102. package/app/modules/tiktokModule/commandConfig.json +29 -0
  103. package/app/modules/tiktokModule/tiktokCommand.js +2 -1
  104. package/app/modules/userModule/AGENT.md +1 -1
  105. package/app/modules/userModule/commandConfig.json +29 -0
  106. package/app/modules/userModule/userCommand.js +72 -23
  107. package/app/modules/waifuPicsModule/AGENT.md +57 -27
  108. package/app/modules/waifuPicsModule/commandConfig.json +87 -0
  109. package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
  110. package/app/observability/metrics.js +136 -0
  111. package/app/services/ai/commandConfigEnrichmentService.js +229 -47
  112. package/app/services/ai/conversationRouterService.js +4 -3
  113. package/app/services/ai/geminiService.js +132 -7
  114. package/app/services/ai/geminiService.test.js +59 -2
  115. package/app/services/ai/globalModuleAiHelpService.js +3 -2
  116. package/app/services/ai/messageCommandExecutionService.js +2 -1
  117. package/app/services/ai/moduleAiHelpCoreService.js +45 -14
  118. package/app/services/ai/moduleToolExecutorService.js +3 -2
  119. package/app/services/ai/moduleToolRegistryService.js +2 -1
  120. package/app/services/ai/toolCandidateSelectorService.js +6 -5
  121. package/app/services/auth/googleWebLinkService.js +3 -2
  122. package/app/services/auth/whatsappLoginLinkService.js +3 -2
  123. package/app/services/external/pokeApiService.js +4 -3
  124. package/app/services/group/groupMetadataService.js +24 -1
  125. package/app/services/infra/dbWriteQueue.js +57 -26
  126. package/app/services/infra/featureFlagService.js +2 -1
  127. package/app/services/messaging/captchaService.js +3 -2
  128. package/app/services/messaging/newsBroadcastService.js +846 -29
  129. package/app/services/multiSession/assignmentBalancerService.js +457 -0
  130. package/app/services/multiSession/groupOwnershipRepository.js +381 -0
  131. package/app/services/multiSession/groupOwnershipService.js +890 -0
  132. package/app/services/multiSession/groupOwnershipService.test.js +309 -0
  133. package/app/services/multiSession/sessionRegistryService.js +293 -0
  134. package/app/services/sticker/stickerFocusService.js +11 -10
  135. package/app/store/aiPromptStore.js +36 -19
  136. package/app/store/conversationSessionStore.js +7 -6
  137. package/app/store/groupConfigStore.js +41 -5
  138. package/app/store/premiumUserStore.js +21 -7
  139. package/app/utils/antiLink/antiLinkModule.js +352 -16
  140. package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
  141. package/app/workers/aiLearningWorker.js +6 -5
  142. package/app/workers/commandConfigEnrichmentWorker.js +4 -3
  143. package/database/index.js +14 -8
  144. package/database/migrations/20260307_d0_hardening_down.sql +1 -1
  145. package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
  146. package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
  147. package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
  148. package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
  149. package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
  150. package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
  151. package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
  152. package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
  153. package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
  154. package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
  155. package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
  156. package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
  157. package/database/schema.sql +102 -1
  158. package/docker-compose.yml +4 -1
  159. package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
  160. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
  161. package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
  162. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
  163. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
  164. package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
  165. package/docs/security/omnizap-static-security-headers.conf +25 -0
  166. package/docs/wiki/Home.md +1 -1
  167. package/ecosystem.prod.config.cjs +32 -12
  168. package/index.js +57 -23
  169. package/observability/alert-rules.yml +20 -0
  170. package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
  171. package/observability/mysql-setup.sql +4 -4
  172. package/observability/system-admin-observability.md +26 -0
  173. package/package.json +20 -6
  174. package/public/apple-touch-icon.png +0 -0
  175. package/public/comandos/commands-catalog.json +2853 -3326
  176. package/public/favicon-16x16.png +0 -0
  177. package/public/favicon-32x32.png +0 -0
  178. package/public/favicon.ico +0 -0
  179. package/public/js/apps/apiDocsApp.js +3 -2
  180. package/public/js/apps/commandsReactApp.js +280 -99
  181. package/public/js/apps/createPackApp.js +11 -10
  182. package/public/js/apps/homeReactApp.js +181 -130
  183. package/public/js/apps/loginReactApp.js +1 -1
  184. package/public/js/apps/stickersApp.js +263 -110
  185. package/public/js/apps/termsReactApp.js +73 -24
  186. package/public/js/apps/userApp.js +4 -3
  187. package/public/js/apps/userPasswordResetReactApp.js +406 -0
  188. package/public/js/apps/userReactApp.js +355 -280
  189. package/public/js/apps/userSystemAdmReactApp.js +1506 -0
  190. package/public/pages/api-docs.html +1 -1
  191. package/public/pages/aup.html +2 -2
  192. package/public/pages/dpa.html +3 -3
  193. package/public/pages/licenca.html +4 -4
  194. package/public/pages/login.html +1 -1
  195. package/public/pages/notice-and-takedown.html +2 -2
  196. package/public/pages/politica-de-privacidade.html +6 -6
  197. package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
  198. package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
  199. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
  200. package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
  201. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
  202. package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
  203. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
  204. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
  205. package/public/pages/stickers-admin.html +1 -1
  206. package/public/pages/stickers-create.html +1 -1
  207. package/public/pages/stickers.html +6 -6
  208. package/public/pages/suboperadores.html +2 -2
  209. package/public/pages/termos-de-uso-texto-integral.html +6 -6
  210. package/public/pages/termos-de-uso.html +3 -3
  211. package/public/pages/user-password-reset.html +4 -5
  212. package/public/pages/user-systemadm.html +9 -463
  213. package/public/pages/user.html +2 -2
  214. package/scripts/clear-whatsapp-session.sh +123 -0
  215. package/scripts/core-ai-mode.mjs +163 -0
  216. package/scripts/deploy.sh +11 -1
  217. package/scripts/email-broadcast-terms-update.mjs +2 -1
  218. package/scripts/enrich-command-config-ux-openai.mjs +492 -0
  219. package/scripts/generate-commands-catalog.mjs +166 -2
  220. package/scripts/generate-module-agents.mjs +2 -1
  221. package/scripts/generate-seo-satellite-pages.mjs +5 -4
  222. package/scripts/github-deploy-notify.mjs +2 -1
  223. package/scripts/github-release-notify.mjs +25 -10
  224. package/scripts/new-whatsapp-session.sh +317 -0
  225. package/scripts/release.sh +2 -19
  226. package/scripts/security-smoketest.mjs +6 -5
  227. package/scripts/security-web-surface-check.mjs +218 -0
  228. package/scripts/sticker-catalog-loadtest.mjs +5 -4
  229. package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
  230. package/server/auth/jwt/webJwtService.js +1 -1
  231. package/server/auth/stickerCatalogAuthContext.js +2 -1
  232. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
  233. package/server/auth/userPassword/userPasswordAuthService.js +2 -1
  234. package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
  235. package/server/auth/webAccount/webAccountHandlers.js +9 -10
  236. package/server/controllers/admin/adminPanelHandlers.js +267 -16
  237. package/server/controllers/admin/systemAdminController.js +267 -0
  238. package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
  239. package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
  240. package/server/controllers/sticker/stickerCatalogController.js +23 -36
  241. package/server/controllers/system/contactController.js +9 -17
  242. package/server/controllers/system/githubController.js +3 -2
  243. package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
  244. package/server/controllers/system/systemController.js +254 -1
  245. package/server/controllers/system/systemMetricsController.js +2 -1
  246. package/server/controllers/userController.js +6 -0
  247. package/server/email/emailTemplateService.js +5 -3
  248. package/server/http/httpServer.js +11 -6
  249. package/server/middleware/rateLimit.js +2 -1
  250. package/server/middleware/securityHeaders.js +20 -1
  251. package/server/routes/admin/systemAdminRouter.js +6 -0
  252. package/server/routes/indexRouter.js +30 -6
  253. package/server/routes/observability/grafanaProxyRouter.js +254 -0
  254. package/server/routes/static/staticPageRouter.js +27 -1
  255. package/server/utils/publicContact.js +31 -0
  256. package/utils/time/timeModule.js +135 -0
  257. package/utils/time/timeModule.test.js +65 -0
  258. package/utils/whatsapp/contactEnv.js +39 -0
  259. package/vite.config.mjs +7 -1
  260. package/public/assets/images/brand-icon-192.png +0 -0
  261. package/scripts/sync-readme-snapshot.mjs +0 -133
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import React, { useEffect, useMemo, useState } from 'react';
2
3
  import { createRoot } from 'react-dom/client';
3
4
  import htm from 'htm';
@@ -7,7 +8,10 @@ const html = htm.bind(React.createElement);
7
8
 
8
9
  const DEFAULT_API_BASE_PATH = '/api';
9
10
  const DEFAULT_LOGIN_PATH = '/login';
11
+ const DEFAULT_PASSWORD_RESET_WEB_PATH = '/user/password-reset';
10
12
  const DEFAULT_FALLBACK_AVATAR = '/assets/images/brand-logo-128.webp';
13
+ const DEFAULT_SUPPORT_WHATSAPP_NUMBER = '';
14
+ const DEFAULT_SUPPORT_WHATSAPP_URL = '/termos-de-uso/';
11
15
 
12
16
  const TABS = [
13
17
  { key: 'summary', label: 'Estatísticas', icon: '📊' },
@@ -16,12 +20,59 @@ const TABS = [
16
20
  { key: 'support', label: 'Suporte', icon: '🎧' },
17
21
  ];
18
22
 
23
+ const shortNum = (value) =>
24
+ new Intl.NumberFormat('pt-BR', {
25
+ notation: Number(value) >= 1000 ? 'compact' : 'standard',
26
+ maximumFractionDigits: 1,
27
+ }).format(Math.max(0, Number(value) || 0));
28
+
29
+ const normalizeRoutePath = (value, fallback) => {
30
+ const raw = String(value || '').trim();
31
+ if (!raw) return fallback;
32
+ if (!raw.startsWith('/')) return fallback;
33
+ if (/^\/\//.test(raw)) return fallback;
34
+ return raw;
35
+ };
36
+
37
+ const normalizePhoneDigits = (value) =>
38
+ String(value || '')
39
+ .replace(/\D+/g, '')
40
+ .slice(0, 15);
41
+
42
+ const buildWhatsappUrl = (value) => {
43
+ const digits = normalizePhoneDigits(value);
44
+ if (!digits) return '';
45
+ return `https://wa.me/${digits}`;
46
+ };
47
+
48
+ const resolveSupportWhatsappUrl = (config) => {
49
+ const explicitUrl = String(config?.supportWhatsappUrl || '').trim();
50
+ if (/^https?:\/\/wa\.me\/\d{8,15}(?:\?.*)?$/i.test(explicitUrl)) return explicitUrl;
51
+ return buildWhatsappUrl(config?.supportWhatsappNumber) || DEFAULT_SUPPORT_WHATSAPP_URL;
52
+ };
53
+
19
54
  const UserApp = ({ config }) => {
20
55
  const [activeTab, setActiveTab] = useState('summary');
21
56
  const [isLoading, setLoading] = useState(true);
22
57
  const [summary, setSummary] = useState(null);
23
58
  const [session, setSession] = useState(null);
24
- const [isSidebarOpen, setSidebarOpen] = useState(false);
59
+ const [isSidebarCollapsed, setSidebarCollapsed] = useState(false);
60
+ const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);
61
+ const [passwordResetBusy, setPasswordResetBusy] = useState(false);
62
+ const [passwordResetError, setPasswordResetError] = useState('');
63
+ const [passwordResetInfo, setPasswordResetInfo] = useState('');
64
+
65
+ // Lock scroll when mobile menu is open
66
+ useEffect(() => {
67
+ if (isMobileMenuOpen) {
68
+ document.body.style.overflow = 'hidden';
69
+ } else {
70
+ document.body.style.overflow = '';
71
+ }
72
+ return () => {
73
+ document.body.style.overflow = '';
74
+ };
75
+ }, [isMobileMenuOpen]);
25
76
 
26
77
  useEffect(() => {
27
78
  const observer =
@@ -82,113 +133,217 @@ const UserApp = ({ config }) => {
82
133
 
83
134
  const rpgInfo = useMemo(() => summary?.rpg || { level: 1, xp: 0, gold: 0, karma: { score: 0, positive: 0, negative: 0 }, pvp: { matches: 0, wins: 0, losses: 0 }, inventory_count: 0, total_pokemons: 0 }, [summary]);
84
135
  const usageInfo = useMemo(() => summary?.usage || { messages: 0, packs: 0, stickers: 0, activity_chart: [], insights: {}, first_message_at: null, last_message_at: null }, [summary]);
136
+ const supportWhatsappUrl = useMemo(() => resolveSupportWhatsappUrl(config), [config.supportWhatsappNumber, config.supportWhatsappUrl]);
85
137
 
86
138
  const daysMember = useMemo(() => {
87
139
  if (!rpgInfo.member_since) return 0;
88
- const diff = new Date() - new Date(rpgInfo.member_since);
140
+ const diff = __timeNow() - new Date(rpgInfo.member_since);
89
141
  return Math.floor(diff / (1000 * 60 * 60 * 24));
90
142
  }, [rpgInfo.member_since]);
91
143
 
92
144
  const handleTabChange = (key) => {
93
145
  setActiveTab(key);
94
- setSidebarOpen(false);
146
+ setMobileMenuOpen(false);
147
+ };
148
+
149
+ const toggleSidebar = () => {
150
+ if (window.innerWidth < 1024) {
151
+ setMobileMenuOpen(!isMobileMenuOpen);
152
+ } else {
153
+ setSidebarCollapsed(!isSidebarCollapsed);
154
+ }
155
+ };
156
+
157
+ const startPasswordResetFlow = async () => {
158
+ if (passwordResetBusy) return;
159
+ setPasswordResetError('');
160
+ setPasswordResetInfo('');
161
+ setPasswordResetBusy(true);
162
+
163
+ try {
164
+ const response = await fetch(`${config.apiBasePath}/auth/password/recovery/session`, {
165
+ method: 'POST',
166
+ credentials: 'include',
167
+ headers: {
168
+ 'Content-Type': 'application/json; charset=utf-8',
169
+ },
170
+ body: JSON.stringify({}),
171
+ });
172
+
173
+ let payload = null;
174
+ try {
175
+ payload = await response.json();
176
+ } catch {
177
+ payload = null;
178
+ }
179
+
180
+ if (!response.ok) {
181
+ throw new Error(payload?.error || `Falha HTTP ${response.status}`);
182
+ }
183
+
184
+ const data = payload?.data || {};
185
+ const sessionToken = String(data?.session_token || '')
186
+ .trim()
187
+ .slice(0, 4096);
188
+ const sessionPath = normalizeRoutePath(data?.session_path, config.passwordResetWebPath || DEFAULT_PASSWORD_RESET_WEB_PATH);
189
+ const targetUrl = new URL(sessionPath, window.location.origin);
190
+ if (sessionToken) {
191
+ targetUrl.searchParams.set('session_token', sessionToken);
192
+ }
193
+
194
+ setPasswordResetInfo('Sessão de redefinição criada. Redirecionando...');
195
+ window.setTimeout(() => {
196
+ window.location.assign(`${targetUrl.pathname}${targetUrl.search}`);
197
+ }, 120);
198
+ } catch (error) {
199
+ setPasswordResetError(error?.message || 'Não foi possível iniciar a redefinição de senha.');
200
+ } finally {
201
+ setPasswordResetBusy(false);
202
+ }
95
203
  };
96
204
 
97
205
  return html`
206
+ <style>
207
+ .sidebar-transition {
208
+ transition:
209
+ width 0.4s cubic-bezier(0.4, 0, 0.2, 1),
210
+ transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
211
+ }
212
+ .content-transition {
213
+ transition: margin-left 0.4s cubic-bezier(0.4, 0, 0.2, 1);
214
+ }
215
+ </style>
216
+
98
217
  <div className="min-h-screen bg-[#020617] text-white font-sans selection:bg-primary selection:text-primary-content overflow-x-hidden">
99
- <div className="fixed inset-0 pointer-events-none overflow-hidden">
218
+ <!-- Background Elements -->
219
+ <div className="fixed inset-0 pointer-events-none overflow-hidden z-0">
100
220
  <div className="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] bg-primary/5 blur-[120px] rounded-full animate-pulse"></div>
101
221
  <div className="absolute bottom-[10%] right-[-5%] w-[30%] h-[30%] bg-secondary/5 blur-[100px] rounded-full"></div>
102
222
  </div>
103
223
 
104
- <!-- Backdrop for mobile sidebar (Solid overlay, no blur) -->
105
- <div onClick=${() => setSidebarOpen(false)} className=${`fixed inset-0 z-[90] bg-[#020617]/90 lg:hidden transition-opacity duration-300 ${isSidebarOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}></div>
224
+ <!-- Backdrop for mobile sidebar -->
225
+ <div onClick=${() => setMobileMenuOpen(false)} className=${`fixed inset-0 z-[50] bg-[#020617]/80 lg:hidden transition-opacity duration-300 ${isMobileMenuOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}></div>
106
226
 
107
227
  <!-- Navbar -->
108
- <header className="sticky top-0 z-50 border-b border-white/5 bg-[#020617]">
109
- <div className="container mx-auto px-4">
228
+ <header className="fixed inset-x-0 top-0 z-[40] border-b border-white/5 bg-[#020617]/80 backdrop-blur-xl">
229
+ <div className="px-4 lg:px-8">
110
230
  <div className="flex h-16 items-center justify-between gap-4">
111
231
  <div className="flex items-center gap-4">
112
- <button onClick=${() => setSidebarOpen(true)} className="lg:hidden btn btn-ghost btn-square btn-sm bg-white/5 border border-white/10 rounded-xl">
113
- <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M4 6h16M4 12h16M4 18h16" /></svg>
232
+ <button onClick=${toggleSidebar} className="btn btn-ghost btn-square btn-sm bg-white/5 border border-white/10 rounded-xl hover:bg-primary/10 hover:text-primary transition-all">
233
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
234
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d=${isSidebarCollapsed ? 'M4 6h16M4 12h16M4 18h16' : 'M4 6h16M4 12h10M4 18h16'} />
235
+ </svg>
114
236
  </button>
115
237
 
116
238
  <a href="/" className="flex items-center gap-2.5 hover:opacity-80 transition-opacity">
117
- <img src="/assets/images/brand-logo-128.webp" className="w-8 h-8 rounded-xl shadow-sm" alt="Logo" />
118
- <span className="text-base sm:text-lg font-black tracking-tight">OmniZap<span className="text-primary">.</span></span>
239
+ <img src="/apple-touch-icon.png" className="w-8 h-8 rounded-xl shadow-sm" alt="Logo" />
240
+ <span className="hidden xs:block text-base sm:text-lg font-black tracking-tight">OmniZap<span className="text-primary">.</span></span>
119
241
  </a>
120
242
  </div>
121
243
 
122
244
  <div className="flex items-center gap-3">
123
- <button onClick=${() => window.location.assign('/login/')} className="btn btn-ghost btn-sm h-9 min-h-0 gap-2 rounded-xl bg-white/5 border border-white/10 hover:bg-error hover:text-white transition-all px-4 font-black text-[10px] uppercase tracking-widest">Sair</button>
245
+ <button onClick=${() => window.location.assign('/login/')} className="btn btn-ghost btn-sm h-10 min-h-0 gap-2 rounded-xl bg-white/5 border border-white/10 hover:bg-error hover:text-white transition-all px-5 font-black text-[10px] uppercase tracking-widest group">
246
+ <span className="hidden sm:inline opacity-50 group-hover:opacity-100">Sair da Conta</span>
247
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" /></svg>
248
+ </button>
124
249
  </div>
125
250
  </div>
126
251
  </div>
127
252
  </header>
128
253
 
129
- <main className="container mx-auto max-w-6xl px-4 py-8 lg:py-16">
130
- <div className="grid lg:grid-cols-[300px_1fr] gap-8 items-start">
131
- <!-- Sidebar Navigation (Drawer on Mobile) -->
132
- <aside className=${`fixed lg:sticky top-0 lg:top-32 left-0 h-full lg:h-auto w-[280px] lg:w-auto z-[100] lg:z-0 bg-[#020617] lg:bg-transparent border-r lg:border-none border-white/10 p-6 lg:p-0 space-y-6 transform transition-transform duration-300 ease-out lg:translate-x-0 ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'} shadow-[20px_0_60px_rgba(0,0,0,0.8)]`}>
133
- <div className="lg:hidden flex items-center justify-between mb-8">
134
- <span className="text-xs font-black uppercase tracking-[0.2em] text-white/30">Navegação</span>
135
- <button onClick=${() => setSidebarOpen(false)} className="btn btn-ghost btn-square btn-xs">
136
- <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
254
+ <div className="flex relative pt-16">
255
+ <!-- Sidebar -->
256
+ <aside className=${`fixed lg:fixed top-0 lg:top-[65px] lg:left-0 h-full lg:h-[calc(100vh-65px)] z-[60] lg:z-30 bg-[#020617] border-r border-white/5 sidebar-transition overflow-y-auto no-scrollbar ${isMobileMenuOpen ? 'translate-x-0 w-[280px]' : '-translate-x-full lg:translate-x-0'} ${isSidebarCollapsed ? 'lg:w-[85px]' : 'lg:w-[280px]'}`}>
257
+ <div className="p-4 flex flex-col h-full">
258
+ <!-- Mobile Header inside Sidebar -->
259
+ <div className="lg:hidden flex items-center justify-between mb-6 px-2">
260
+ <span className="text-[10px] font-black uppercase tracking-[0.2em] text-white/30">Menu do Sistema</span>
261
+ <button onClick=${() => setMobileMenuOpen(false)} className="btn btn-ghost btn-square btn-sm hover:bg-white/5">
262
+ <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M6 18L18 6M6 6l12 12" /></svg>
137
263
  </button>
138
264
  </div>
139
265
 
140
- <div className="hidden lg:block relative group p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 text-center space-y-6 overflow-hidden">
141
- <div className="absolute inset-0 bg-gradient-to-b from-primary/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
142
-
143
- <div className="relative">
144
- <div className="relative inline-block">
145
- <div className="absolute inset-0 bg-primary/20 blur-xl rounded-full animate-pulse"></div>
146
- <img src=${authInfo.image} className="relative w-24 h-24 rounded-[2rem] border-2 border-white/10 p-1.5 object-cover mx-auto shadow-2xl" />
147
- <div className="absolute -bottom-1 -right-1 w-6 h-6 bg-success border-4 border-[#020617] rounded-full"></div>
266
+ <!-- Profile Snippet -->
267
+ <div className=${`mb-6 p-4 rounded-3xl bg-white/[0.03] border border-white/5 transition-all overflow-hidden ${isSidebarCollapsed ? 'items-center px-2' : ''}`}>
268
+ <div className=${`flex items-center gap-4 ${isSidebarCollapsed ? 'flex-col' : ''}`}>
269
+ <div className="relative flex-shrink-0">
270
+ <div className="absolute inset-0 bg-primary/20 blur-lg rounded-full animate-pulse"></div>
271
+ <img src=${authInfo.image} className="relative w-10 h-10 rounded-xl border border-white/10 p-0.5 object-cover" />
272
+ <div className="absolute -bottom-0.5 -right-0.5 w-3 h-3 bg-success border-2 border-[#020617] rounded-full"></div>
148
273
  </div>
274
+ ${!isSidebarCollapsed &&
275
+ html`
276
+ <div className="flex-1 min-w-0">
277
+ <h3 className="text-sm font-black tracking-tight truncate text-white">${session?.user?.name || 'User'}</h3>
278
+ <p className="text-[9px] font-black uppercase text-primary/60 tracking-wider">${summary?.plan_label || 'Plano Free'}</p>
279
+ </div>
280
+ `}
149
281
  </div>
150
-
151
- <div className="relative space-y-1">
152
- <h2 className="text-xl font-black tracking-tight truncate px-2">${session?.user?.name || 'Carregando...'}</h2>
153
- <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-[10px] font-black uppercase tracking-widest">${summary?.plan_label || 'Plano Free'}</div>
154
- </div>
155
-
156
- <div className="relative grid grid-cols-2 gap-2 pt-2">
157
- <div className="p-3 rounded-2xl bg-white/5 border border-white/5 text-center">
158
- <p className="text-[8px] font-black text-white/30 uppercase tracking-widest mb-1">Nível</p>
159
- <p className="text-lg font-black text-primary">${rpgInfo.level}</p>
160
- </div>
161
- <div className="p-3 rounded-2xl bg-white/5 border border-white/5 text-center">
162
- <p className="text-[8px] font-black text-white/30 uppercase tracking-widest mb-1">Gold</p>
163
- <p className="text-lg font-black text-warning">💰 ${rpgInfo.gold}</p>
282
+ ${!isSidebarCollapsed &&
283
+ html`
284
+ <div className="mt-4 pt-4 border-t border-white/5 grid grid-cols-2 gap-2">
285
+ <div className="text-center p-2 rounded-xl bg-white/5">
286
+ <p className="text-[7px] font-black text-white/20 uppercase">Nível</p>
287
+ <p className="text-xs font-black text-primary">${rpgInfo.level}</p>
288
+ </div>
289
+ <div className="text-center p-2 rounded-xl bg-white/5">
290
+ <p className="text-[7px] font-black text-white/20 uppercase">Gold</p>
291
+ <p className="text-xs font-black text-warning">${shortNum(rpgInfo.gold)}</p>
292
+ </div>
164
293
  </div>
165
- </div>
294
+ `}
166
295
  </div>
167
296
 
168
- <nav className="p-2 rounded-[2rem] bg-white/[0.03] border border-white/5 space-y-1">
297
+ <!-- Navigation -->
298
+ <nav className="flex-1 space-y-1.5">
169
299
  ${TABS.map(
170
300
  (tab) => html`
171
- <button onClick=${() => handleTabChange(tab.key)} className=${`w-full flex items-center gap-4 px-6 py-4 rounded-2xl font-black text-xs uppercase tracking-widest transition-all ${activeTab === tab.key ? 'bg-primary text-primary-content shadow-2xl shadow-primary/20 scale-[1.02]' : 'hover:bg-white/5 text-white/40 hover:text-white'}`}>
172
- <span className="text-xl opacity-80">${tab.icon}</span>
173
- ${tab.label}
301
+ <button onClick=${() => handleTabChange(tab.key)} className=${`w-full flex items-center gap-4 px-4 py-3.5 rounded-2xl font-black text-[10px] uppercase tracking-[0.15em] transition-all relative group ${activeTab === tab.key ? 'bg-primary text-primary-content shadow-lg shadow-primary/10' : 'text-white/40 hover:bg-white/5 hover:text-white'}`}>
302
+ <span className=${`text-xl transition-transform duration-500 ${activeTab === tab.key ? 'scale-110' : 'group-hover:scale-110'}`}>${tab.icon}</span>
303
+ <span className=${`transition-all duration-300 ${isSidebarCollapsed ? 'opacity-0 w-0' : 'opacity-100'}`}>${tab.label}</span>
304
+ ${isSidebarCollapsed && activeTab === tab.key && html`<div className="absolute right-0 w-1 h-6 bg-primary rounded-l-full"></div>`}
174
305
  </button>
175
306
  `,
176
307
  )}
177
308
  </nav>
178
- </aside>
179
309
 
180
- <!-- Content Area -->
181
- <div className="space-y-8">
182
- <div data-reveal="fade-up" className="space-y-2 text-center lg:text-left pt-4 lg:pt-0">
183
- <h1 className="text-4xl sm:text-5xl font-black tracking-tighter">Painel do <span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">Usuário</span></h1>
184
- <p className="text-white/40 text-base font-medium">Bem-vindo de volta! Aqui estão suas estatísticas em tempo real.</p>
310
+ <!-- Sidebar Footer -->
311
+ <div className=${`mt-auto pt-6 border-t border-white/5 ${isSidebarCollapsed ? 'text-center' : ''}`}>
312
+ <div className="flex flex-col gap-2">
313
+ <div className=${`flex items-center gap-2 px-3 py-1.5 rounded-lg bg-white/5 border border-white/5 ${isSidebarCollapsed ? 'justify-center' : ''}`}>
314
+ <div className="w-1.5 h-1.5 rounded-full bg-primary animate-pulse"></div>
315
+ ${!isSidebarCollapsed && html`<span className="text-[8px] font-black uppercase tracking-widest text-white/30">v2.6.0 Connected</span>`}
316
+ </div>
317
+ </div>
318
+ </div>
319
+ </div>
320
+ </aside>
321
+
322
+ <!-- Main Content -->
323
+ <main className=${`flex-1 min-w-0 content-transition px-4 lg:px-10 py-8 lg:py-12 ${isSidebarCollapsed ? 'lg:ml-[85px]' : 'lg:ml-[280px]'}`}>
324
+ <div className="max-w-5xl mx-auto space-y-10">
325
+ <div data-reveal="fade-up" className="flex flex-col md:flex-row md:items-end justify-between gap-6">
326
+ <div className="space-y-2">
327
+ <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-[9px] font-black uppercase tracking-widest">Dashboard v3.0</div>
328
+ <h1 className="text-4xl lg:text-6xl font-black tracking-tighter">Painel do <span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">Usuário</span></h1>
329
+ <p className="text-white/40 text-sm font-medium">Gerencie suas estatísticas, conquistas RPG e segurança em um só lugar.</p>
330
+ </div>
331
+ <div className="hidden md:flex items-center gap-4 text-right">
332
+ <div>
333
+ <p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Status da Sessão</p>
334
+ <p className="text-xs font-bold text-success">Encriptada e Ativa</p>
335
+ </div>
336
+ <div className="w-10 h-10 rounded-xl bg-success/10 border border-success/20 flex items-center justify-center text-success">
337
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
338
+ </div>
339
+ </div>
185
340
  </div>
186
341
 
187
- <div data-reveal="fade-up" className="relative p-1 rounded-[3rem] bg-gradient-to-br from-white/10 to-transparent">
188
- <div className="bg-[#020617] rounded-[2.9rem] p-6 lg:p-12 min-h-[500px] overflow-hidden relative">
342
+ <div data-reveal="fade-up" className="relative p-1 rounded-[3.5rem] bg-gradient-to-br from-white/10 via-transparent to-transparent group">
343
+ <div className="bg-[#020617] rounded-[3.4rem] p-6 lg:p-12 min-h-[600px] overflow-hidden relative shadow-2xl">
189
344
  ${isLoading
190
345
  ? html`
191
- <div className="flex flex-col items-center justify-center h-full space-y-6 py-20 animate-in fade-in">
346
+ <div className="flex flex-col items-center justify-center h-full space-y-6 py-32 animate-in fade-in">
192
347
  <div className="relative">
193
348
  <div className="absolute inset-0 bg-primary/20 blur-2xl rounded-full animate-ping"></div>
194
349
  <span className="loading loading-ring w-20 h-20 text-primary relative"></span>
@@ -200,179 +355,131 @@ const UserApp = ({ config }) => {
200
355
  <div className="animate-in fade-in slide-in-from-bottom-8 duration-700">
201
356
  ${activeTab === 'summary' &&
202
357
  html`
203
- <div className="grid gap-10 animate-in fade-in slide-in-from-bottom-8 duration-700">
358
+ <div className="grid gap-10">
204
359
  <!-- Main Metrics Row -->
205
360
  <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
206
- <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-primary/30 transition-colors relative overflow-hidden">
207
- <div className="absolute -right-4 -bottom-4 text-6xl opacity-5">💬</div>
208
- <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-primary transition-colors relative z-10">Total de Mensagens</p>
361
+ <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-primary/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
362
+ <div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">💬</div>
363
+ <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-primary transition-colors relative z-10">Total de Mensagens</p>
209
364
  <p className="text-4xl font-black text-white relative z-10">${usageInfo.messages.toLocaleString()}</p>
210
365
  </div>
211
- <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-emerald-400/30 transition-colors relative overflow-hidden">
212
- <div className="absolute -right-4 -bottom-4 text-6xl opacity-5">🖼️</div>
213
- <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-emerald-400 transition-colors relative z-10">Stickers Criados</p>
366
+ <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-emerald-400/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
367
+ <div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">🖼️</div>
368
+ <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-emerald-400 transition-colors relative z-10">Stickers Criados</p>
214
369
  <p className="text-4xl font-black text-white relative z-10">${usageInfo.stickers.toLocaleString()}</p>
215
370
  </div>
216
- <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group hover:border-warning/30 transition-colors relative overflow-hidden">
217
- <div className="absolute -right-4 -bottom-4 text-6xl opacity-5">📦</div>
218
- <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover:text-warning transition-colors relative z-10">Packs de Stickers</p>
371
+ <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-2 group/card hover:border-warning/30 transition-all hover:bg-white/[0.05] relative overflow-hidden">
372
+ <div className="absolute -right-4 -bottom-4 text-6xl opacity-5 group-hover/card:scale-110 transition-transform">📦</div>
373
+ <p className="text-[10px] font-black uppercase tracking-widest text-white/20 group-hover/card:text-warning transition-colors relative z-10">Packs Ativos</p>
219
374
  <p className="text-4xl font-black text-white relative z-10">${usageInfo.packs}</p>
220
375
  </div>
221
376
  </div>
222
377
 
223
378
  <!-- Deep Insights Grid -->
224
379
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
225
- <div className="p-6 rounded-[2rem] bg-white/[0.02] border border-white/5 space-y-4">
226
- <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30">Comandos</h4>
227
- <div className="space-y-3">
380
+ <div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
381
+ <div className="flex items-center justify-between">
382
+ <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Comandos</h4>
383
+ <span className="text-xs">⌨️</span>
384
+ </div>
385
+ <div className="space-y-3.5">
228
386
  <div className="flex justify-between items-center">
229
- <span className="text-xs font-medium text-white/50">Total Usados</span>
387
+ <span className="text-xs font-medium text-white/40">Total Usados</span>
230
388
  <span className="text-sm font-black">${usageInfo.insights?.commands_total || 0}</span>
231
389
  </div>
232
390
  <div className="flex justify-between items-center">
233
- <span className="text-xs font-medium text-white/50">Favorito</span>
234
- <span className="text-sm font-black text-primary">${usageInfo.insights?.top_command || 'N/D'}</span>
391
+ <span className="text-xs font-medium text-white/40">Favorito</span>
392
+ <span className="text-sm font-black text-primary truncate ml-4">${usageInfo.insights?.top_command || 'N/D'}</span>
235
393
  </div>
236
394
  <div className="flex justify-between items-center">
237
- <span className="text-xs font-medium text-white/50">Uso do Favorito</span>
238
- <span className="text-sm font-black">${usageInfo.insights?.top_command_count || 0}x</span>
395
+ <span className="text-xs font-medium text-white/40">Frequência</span>
396
+ <span className="text-sm font-black">${usageInfo.insights?.top_command_count || 0} execs</span>
239
397
  </div>
240
398
  </div>
241
399
  </div>
242
400
 
243
- <div className="p-6 rounded-[2rem] bg-white/[0.02] border border-white/5 space-y-4">
244
- <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30">Comunidade</h4>
245
- <div className="space-y-3">
401
+ <div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
402
+ <div className="flex items-center justify-between">
403
+ <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Comunidade</h4>
404
+ <span className="text-xs">👥</span>
405
+ </div>
406
+ <div className="space-y-3.5">
246
407
  <div className="flex justify-between items-center">
247
- <span className="text-xs font-medium text-white/50">Grupos Ativos</span>
408
+ <span className="text-xs font-medium text-white/40">Grupos Ativos</span>
248
409
  <span className="text-sm font-black">${usageInfo.insights?.groups_active || 0}</span>
249
410
  </div>
250
411
  <div className="flex justify-between items-center">
251
- <span className="text-xs font-medium text-white/50">Grupo Principal</span>
252
- <span className="text-sm font-black text-emerald-400 truncate max-w-[120px]">${usageInfo.insights?.top_group || 'N/D'}</span>
412
+ <span className="text-xs font-medium text-white/40">Hub Principal</span>
413
+ <span className="text-sm font-black text-emerald-400 truncate ml-4">${usageInfo.insights?.top_group || 'N/D'}</span>
253
414
  </div>
254
415
  <div className="flex justify-between items-center">
255
- <span className="text-xs font-medium text-white/50">Tipo mais comum</span>
256
- <span className="text-sm font-black capitalize">${usageInfo.insights?.top_message_type || 'texto'}</span>
416
+ <span className="text-xs font-medium text-white/40">Perfil Social</span>
417
+ <span className="text-sm font-black capitalize">${usageInfo.insights?.top_message_type || 'Texto'}</span>
257
418
  </div>
258
419
  </div>
259
420
  </div>
260
421
 
261
- <div className="p-6 rounded-[2rem] bg-white/[0.02] border border-white/5 space-y-4">
262
- <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30">Hábito de Uso</h4>
263
- <div className="space-y-3">
422
+ <div className="p-7 rounded-[2.5rem] bg-white/[0.02] border border-white/5 space-y-5 hover:border-white/10 transition-colors group/insight">
423
+ <div className="flex items-center justify-between">
424
+ <h4 className="text-[10px] font-black uppercase tracking-widest text-white/30 group-hover/insight:text-white/50 transition-colors">Hábitos</h4>
425
+ <span className="text-xs">⚡</span>
426
+ </div>
427
+ <div className="space-y-3.5">
264
428
  <div className="flex justify-between items-center">
265
- <span className="text-xs font-medium text-white/50">Horário de Pico</span>
429
+ <span className="text-xs font-medium text-white/40">Pico de Atividade</span>
266
430
  <span className="text-sm font-black">${usageInfo.insights?.active_hour !== null ? usageInfo.insights.active_hour + ':00' : 'N/D'}</span>
267
431
  </div>
268
432
  <div className="flex justify-between items-center">
269
- <span className="text-xs font-medium text-white/50">Média Diária</span>
270
- <span className="text-sm font-black text-info">${usageInfo.insights?.avg_daily || 0} msg</span>
433
+ <span className="text-xs font-medium text-white/40">Engajamento Médio</span>
434
+ <span className="text-sm font-black text-info">${usageInfo.insights?.avg_daily || 0} msgs/dia</span>
271
435
  </div>
272
436
  <div className="flex justify-between items-center">
273
- <span className="text-xs font-medium text-white/50">Karma Atual</span>
274
- <span className="text-sm font-black text-warning">${rpgInfo.karma?.score || 0}</span>
437
+ <span className="text-xs font-medium text-white/40">Reputação Karma</span>
438
+ <span className="text-sm font-black text-warning">${rpgInfo.karma?.score || 0} pts</span>
275
439
  </div>
276
440
  </div>
277
441
  </div>
278
442
  </div>
279
443
 
280
- <!-- Activity Chart -->
281
- ${usageInfo.activity_chart && usageInfo.activity_chart.length > 0
282
- ? html`
283
- <div className="p-8 rounded-[3rem] bg-white/[0.02] border border-white/5 space-y-6">
284
- <h3 className="font-black text-lg flex items-center gap-3">
285
- <span className="text-primary">📈</span>
286
- Fluxo de Mensagens (7 dias)
287
- </h3>
288
- <div className="flex items-end justify-between gap-2 h-40 pt-4 px-2">
289
- ${usageInfo.activity_chart.map((data) => {
290
- const maxCount = Math.max(...usageInfo.activity_chart.map((d) => d.count), 1);
291
- const heightPercent = Math.max((data.count / maxCount) * 100, 5);
292
- return html`
293
- <div key=${data.day} className="flex flex-col items-center gap-2 flex-1 group min-w-0">
294
- <div className="w-full relative flex justify-center h-full items-end">
295
- <div className="w-full max-w-[2rem] bg-primary/20 hover:bg-primary transition-all rounded-t-lg group-hover:shadow-[0_0_20px_rgba(34,197,94,0.4)]" style=${{ height: heightPercent + '%' }}>
296
- <div className="absolute -top-8 left-1/2 -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity bg-white text-[#020617] text-[10px] font-black px-2 py-1 rounded-lg pointer-events-none whitespace-nowrap z-20">${data.count} msgs</div>
297
- </div>
298
- </div>
299
- <span className="text-[8px] font-bold text-white/20 uppercase tracking-tighter truncate w-full text-center">${data.day.split('-').reverse().join('/')}</span>
300
- </div>
301
- `;
302
- })}
303
- </div>
304
- </div>
305
- `
306
- : null}
307
-
308
- <!-- RPG & Social Snippet -->
309
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
310
- <div className="p-8 rounded-[2.5rem] bg-emerald-500/5 border border-emerald-500/10 space-y-4">
311
- <h4 className="text-[10px] font-black uppercase tracking-widest text-emerald-400/40">Engajamento Social</h4>
312
- <div className="grid grid-cols-2 gap-4">
313
- <div className="space-y-1">
314
- <p className="text-[8px] font-black text-white/20 uppercase">Votos Positivos</p>
315
- <p className="text-xl font-black text-emerald-400">+${rpgInfo.karma?.positive || 0}</p>
316
- </div>
317
- <div className="space-y-1">
318
- <p className="text-[8px] font-black text-white/20 uppercase">Votos Negativos</p>
319
- <p className="text-xl font-black text-rose-500">-${rpgInfo.karma?.negative || 0}</p>
320
- </div>
321
- </div>
322
- </div>
323
- <div className="p-8 rounded-[2.5rem] bg-info/5 border border-info/10 space-y-4">
324
- <h4 className="text-[10px] font-black uppercase tracking-widest text-info/40">Exploração</h4>
325
- <div className="grid grid-cols-2 gap-4">
326
- <div className="space-y-1">
327
- <p className="text-[8px] font-black text-white/20 uppercase">Itens Inventário</p>
328
- <p className="text-xl font-black text-white">${rpgInfo.inventory_count || 0}</p>
329
- </div>
330
- <div className="space-y-1">
331
- <p className="text-[8px] font-black text-white/20 uppercase">Pokémons</p>
332
- <p className="text-xl font-black text-white">${rpgInfo.total_pokemons || 0}</p>
333
- </div>
334
- </div>
335
- </div>
336
- </div>
337
-
338
- <!-- Account Details -->
339
- <div className="p-6 sm:p-10 rounded-[2.5rem] sm:rounded-[3rem] bg-primary/5 border border-primary/10 relative overflow-hidden">
340
- <div className="absolute top-[-20%] right-[-10%] w-64 h-64 bg-primary/10 blur-[80px] rounded-full"></div>
341
- <h3 className="relative font-black text-xl mb-8 flex items-center gap-3">
342
- <span className="w-2 h-2 rounded-full bg-primary shadow-[0_0_10px_rgba(34,197,94,0.8)]"></span>
343
- Detalhes da Identidade
444
+ <!-- Details Card -->
445
+ <div className="p-8 lg:p-12 rounded-[3.5rem] bg-white/[0.03] border border-white/5 relative overflow-hidden">
446
+ <div className="absolute top-0 right-0 w-64 h-64 bg-primary/5 blur-[80px] rounded-full -translate-y-1/2 translate-x-1/2"></div>
447
+ <h3 className="relative font-black text-2xl mb-10 flex items-center gap-4">
448
+ <div className="w-10 h-10 rounded-2xl bg-primary/10 flex items-center justify-center text-lg">🪪</div>
449
+ Metadados da Identidade
344
450
  </h3>
345
- <div className="relative grid grid-cols-1 sm:grid-cols-2 gap-y-6 sm:gap-y-8 gap-x-12 border-b border-white/5 pb-8 mb-8">
346
- <div>
347
- <p className="text-[9px] font-black uppercase text-white/20 tracking-[0.2em] mb-1">Endereço de E-mail</p>
348
- <p className="text-sm sm:text-lg font-bold text-white/80 break-all">${session?.user?.email}</p>
451
+
452
+ <div className="relative grid grid-cols-1 sm:grid-cols-2 gap-10 border-b border-white/5 pb-10 mb-10">
453
+ <div className="space-y-1.5">
454
+ <p className="text-[10px] font-black uppercase text-white/20 tracking-widest">E-mail de Autenticação</p>
455
+ <p className="text-lg font-bold text-white/80">${session?.user?.email}</p>
349
456
  </div>
350
- <div>
351
- <p className="text-[9px] font-black uppercase text-white/20 tracking-[0.2em] mb-1">WhatsApp Vinculado</p>
352
- <p className="text-sm sm:text-lg font-bold text-white/80">${summary?.owner_phone ? `+${formatPhone(summary.owner_phone)}` : 'Não vinculado'}</p>
457
+ <div className="space-y-1.5">
458
+ <p className="text-[10px] font-black uppercase text-white/20 tracking-widest">WhatsApp Vinculado</p>
459
+ <p className="text-lg font-bold text-primary">${summary?.owner_phone ? formatPhone(summary.owner_phone) : 'Vincular Conta'}</p>
353
460
  </div>
354
- <div>
355
- <p className="text-[9px] font-black uppercase text-white/20 tracking-[0.2em] mb-1">Última Atividade</p>
356
- <p className="text-sm sm:text-lg font-bold text-white/80">${formatDateTime(summary?.last_seen_at) || 'Ativo agora'}</p>
461
+ <div className="space-y-1.5">
462
+ <p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Última Conexão</p>
463
+ <p className="text-lg font-bold text-white/80">${formatDateTime(summary?.last_seen_at) || 'Online agora'}</p>
357
464
  </div>
358
- <div>
359
- <p className="text-[9px] font-black uppercase text-white/20 tracking-[0.2em] mb-1">Membro Desde</p>
360
- <p className="text-sm sm:text-lg font-bold text-white/80">${formatDateTime(rpgInfo.member_since) || 'Recentemente'}</p>
465
+ <div className="space-y-1.5">
466
+ <p className="text-[10px] font-black uppercase text-white/20 tracking-widest">Membro da Rede Desde</p>
467
+ <p className="text-lg font-bold text-white/80">${formatDateTime(rpgInfo.member_since) || 'Recentemente'}</p>
361
468
  </div>
362
469
  </div>
363
470
 
364
- <div className="relative grid grid-cols-2 sm:grid-cols-3 gap-6">
471
+ <div className="relative grid grid-cols-2 sm:grid-cols-3 gap-8">
365
472
  <div>
366
- <p className="text-[9px] font-black uppercase text-white/20 mb-1">Tempo como Membro</p>
367
- <p className="text-sm font-black text-primary">${daysMember} dias</p>
473
+ <p className="text-[9px] font-black uppercase text-white/20 mb-1">Tempo de Rede</p>
474
+ <p className="text-base font-black text-primary">${daysMember} dias ativos</p>
368
475
  </div>
369
476
  <div>
370
- <p className="text-[9px] font-black uppercase text-white/20 mb-1">Primeira Mensagem</p>
371
- <p className="text-[10px] font-bold text-white/60">${formatDateTime(usageInfo.first_message_at) || 'N/D'}</p>
477
+ <p className="text-[9px] font-black uppercase text-white/20 mb-1">Primeira Interação</p>
478
+ <p className="text-[11px] font-bold text-white/50">${formatDateTime(usageInfo.first_message_at) || 'N/D'}</p>
372
479
  </div>
373
480
  <div>
374
- <p className="text-[9px] font-black uppercase text-white/20 mb-1">Última Mensagem</p>
375
- <p className="text-[10px] font-bold text-white/60">${formatDateTime(usageInfo.last_message_at) || 'N/D'}</p>
481
+ <p className="text-[9px] font-black uppercase text-white/20 mb-1">Última Interação</p>
482
+ <p className="text-[11px] font-bold text-white/50">${formatDateTime(usageInfo.last_message_at) || 'N/D'}</p>
376
483
  </div>
377
484
  </div>
378
485
  </div>
@@ -380,142 +487,107 @@ const UserApp = ({ config }) => {
380
487
  `}
381
488
  ${activeTab === 'rpg' &&
382
489
  html`
383
- <div className="space-y-10 animate-in fade-in slide-in-from-bottom-8 duration-700">
384
- <!-- RPG Header -->
385
- <div className="flex flex-col sm:flex-row gap-6 items-center sm:items-stretch">
386
- <div className="flex-1 p-8 rounded-[3rem] bg-gradient-to-br from-primary/10 to-transparent border border-primary/20 relative overflow-hidden w-full">
387
- <div className="absolute top-0 right-0 p-6 text-6xl opacity-10">⚔️</div>
388
- <h3 className="text-sm font-black uppercase tracking-widest text-primary mb-6">Status do Treinador</h3>
389
- <div className="flex items-baseline gap-4 mb-4">
390
- <span className="text-6xl font-black text-white">${rpgInfo.level}</span>
391
- <span className="text-sm font-bold text-white/40 uppercase tracking-widest">Nível Atual</span>
392
- </div>
393
-
394
- <div className="space-y-2 w-full max-w-sm">
395
- <div className="flex justify-between text-[10px] font-black uppercase tracking-widest text-white/50">
396
- <span>XP Atual: ${rpgInfo.xp}</span>
397
- <span>Próximo Nível</span>
490
+ <div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
491
+ <div className="p-8 rounded-[3rem] bg-gradient-to-br from-primary/10 via-transparent to-transparent border border-primary/20">
492
+ <div className="flex flex-col md:flex-row items-center gap-8">
493
+ <div className="relative">
494
+ <div className="absolute inset-0 bg-primary/20 blur-3xl rounded-full"></div>
495
+ <div className="relative w-32 h-32 rounded-full border-4 border-primary/20 p-2 flex items-center justify-center bg-[#020617]">
496
+ <span className="text-5xl font-black text-white">${rpgInfo.level}</span>
398
497
  </div>
399
- <div className="h-3 w-full bg-[#020617] rounded-full overflow-hidden border border-white/5">
400
- <div className="h-full bg-gradient-to-r from-primary to-emerald-400 rounded-full transition-all duration-1000" style=${{ width: Math.min((rpgInfo.xp / (rpgInfo.level * 100)) * 100, 100) + '%' }}></div>
498
+ <div className="absolute -bottom-2 left-1/2 -translate-x-1/2 bg-primary text-primary-content px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest shadow-xl">Nível</div>
499
+ </div>
500
+ <div className="flex-1 text-center md:text-left space-y-4">
501
+ <h3 className="text-2xl font-black tracking-tight">Status do Treinador</h3>
502
+ <div className="space-y-2">
503
+ <div className="flex justify-between text-[10px] font-black uppercase tracking-widest text-white/40">
504
+ <span>Experiência: ${rpgInfo.xp} XP</span>
505
+ <span>Próximo nível: ${(rpgInfo.level + 1) * 100}</span>
506
+ </div>
507
+ <div className="h-4 w-full bg-white/5 rounded-full overflow-hidden border border-white/5">
508
+ <div className="h-full bg-gradient-to-r from-primary to-emerald-400 transition-all duration-1000" style=${{ width: Math.min((rpgInfo.xp / ((rpgInfo.level + 1) * 100)) * 100, 100) + '%' }}></div>
509
+ </div>
401
510
  </div>
402
511
  </div>
403
- </div>
404
-
405
- <div className="p-8 rounded-[3rem] bg-warning/5 border border-warning/10 flex flex-col justify-center items-center sm:min-w-[200px] w-full sm:w-auto">
406
- <span className="text-4xl mb-4 animate-bounce">💰</span>
407
- <span className="text-4xl font-black text-warning mb-1">${rpgInfo.gold}</span>
408
- <span className="text-[10px] font-black uppercase tracking-widest text-warning/50">Gold Acumulado</span>
512
+ <div className="p-6 rounded-[2.5rem] bg-warning/5 border border-warning/10 text-center min-w-[160px]">
513
+ <p className="text-[9px] font-black uppercase tracking-widest text-warning/50 mb-1">Tesouro</p>
514
+ <p className="text-3xl font-black text-warning">💰 ${shortNum(rpgInfo.gold)}</p>
515
+ </div>
409
516
  </div>
410
517
  </div>
411
518
 
412
- <!-- Pokemon & PvP -->
413
519
  <div className="grid md:grid-cols-2 gap-6">
414
- <!-- Active Pokemon -->
415
- <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-6">
416
- <div className="flex items-center gap-3">
417
- <span className="text-xl">🐉</span>
418
- <h3 className="font-black text-lg">Pokémon Ativo</h3>
419
- </div>
420
-
520
+ <div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-6">
521
+ <h4 className="text-lg font-black flex items-center gap-3">🐉 Pokémon em Destaque</h4>
421
522
  ${rpgInfo.active_pokemon
422
523
  ? html`
423
- <div className="flex items-center gap-6 p-6 rounded-3xl bg-white/5 border border-white/5 group hover:border-primary/30 transition-colors">
524
+ <div className="p-6 rounded-3xl bg-white/5 border border-white/10 flex items-center gap-6 group hover:border-primary/40 transition-all">
424
525
  <div className="relative">
425
- <div className="w-16 h-16 bg-white/10 rounded-full flex items-center justify-center text-3xl">
426
- <img src=${'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/' + (rpgInfo.active_pokemon.is_shiny ? 'shiny/' : '') + rpgInfo.active_pokemon.poke_id + '.png'} alt="Pokemon" className="w-20 h-20 scale-125 object-contain" />
427
- </div>
428
- ${rpgInfo.active_pokemon.is_shiny && html`<div className="absolute -top-2 -right-2 text-warning animate-pulse">✨</div>`}
526
+ <img src=${'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/' + (rpgInfo.active_pokemon.is_shiny ? 'shiny/' : '') + rpgInfo.active_pokemon.poke_id + '.png'} className="w-24 h-24 object-contain drop-shadow-2xl" />
527
+ ${rpgInfo.active_pokemon.is_shiny && html`<div className="absolute top-0 right-0 text-xl animate-pulse">✨</div>`}
429
528
  </div>
430
529
  <div>
431
- <h4 className="text-xl font-black capitalize text-white group-hover:text-primary transition-colors">${rpgInfo.active_pokemon.nickname || 'Desconhecido'}</h4>
432
- <p className="text-xs font-bold text-white/50 uppercase tracking-widest mt-1">Nível ${rpgInfo.active_pokemon.level}</p>
530
+ <h5 className="text-xl font-black capitalize text-white group-hover:text-primary transition-colors">${rpgInfo.active_pokemon.nickname}</h5>
531
+ <p className="text-xs font-bold text-white/40 uppercase tracking-widest">Nível ${rpgInfo.active_pokemon.level}</p>
433
532
  </div>
434
533
  </div>
435
534
  `
436
- : html`
437
- <div className="p-6 text-center rounded-3xl bg-white/5 border border-white/5 border-dashed">
438
- <p className="text-sm font-bold text-white/40">Nenhum Pokémon ativo no momento.</p>
439
- </div>
440
- `}
441
-
442
- <div className="flex items-center justify-between p-4 rounded-2xl bg-white/5">
443
- <span className="text-[10px] font-black uppercase tracking-widest text-white/40">Total Capturados</span>
444
- <span className="text-lg font-black text-white">${rpgInfo.total_pokemons}</span>
445
- </div>
535
+ : html`<div className="p-10 text-center border-2 border-dashed border-white/5 rounded-3xl text-white/20 font-bold">Nenhum Pokémon ativo</div>`}
446
536
  </div>
447
537
 
448
- <!-- PvP Stats -->
449
- <div className="p-8 rounded-[2.5rem] bg-white/[0.03] border border-white/5 space-y-6">
450
- <div className="flex items-center gap-3">
451
- <span className="text-xl">🏆</span>
452
- <h3 className="font-black text-lg">Arena PvP (Semanal)</h3>
453
- </div>
454
-
538
+ <div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-6 text-center">
539
+ <h4 className="text-lg font-black flex items-center gap-3 justify-center">🏆 Arena Competitiva</h4>
455
540
  <div className="grid grid-cols-2 gap-4">
456
- <div className="p-4 rounded-2xl bg-white/5 text-center">
457
- <p className="text-3xl font-black text-white mb-1">${rpgInfo.pvp?.matches || 0}</p>
458
- <p className="text-[9px] font-black uppercase tracking-widest text-white/40">Batalhas</p>
459
- </div>
460
- <div className="p-4 rounded-2xl bg-success/10 border border-success/20 text-center">
461
- <p className="text-3xl font-black text-success mb-1">${rpgInfo.pvp?.matches > 0 ? Math.round(((rpgInfo.pvp?.wins || 0) / rpgInfo.pvp.matches) * 100) : 0}%</p>
462
- <p className="text-[9px] font-black uppercase tracking-widest text-success/60">Vitórias</p>
463
- </div>
464
- <div className="p-4 rounded-2xl bg-info/10 text-center">
465
- <p className="text-xl font-black text-info mb-1">${rpgInfo.pvp?.wins || 0}</p>
466
- <p className="text-[9px] font-black uppercase tracking-widest text-info/60">Ganha</p>
541
+ <div className="bg-white/5 p-5 rounded-3xl">
542
+ <p className="text-2xl font-black text-white">${rpgInfo.pvp?.wins || 0}</p>
543
+ <p className="text-[9px] font-black uppercase text-white/30">Vitórias</p>
467
544
  </div>
468
- <div className="p-4 rounded-2xl bg-error/10 text-center">
469
- <p className="text-xl font-black text-error mb-1">${rpgInfo.pvp?.losses || 0}</p>
470
- <p className="text-[9px] font-black uppercase tracking-widest text-error/60">Perdida</p>
545
+ <div className="bg-white/5 p-5 rounded-3xl">
546
+ <p className="text-2xl font-black text-white">${rpgInfo.pvp?.losses || 0}</p>
547
+ <p className="text-[9px] font-black uppercase text-white/30">Derrotas</p>
471
548
  </div>
472
549
  </div>
550
+ <div className="bg-primary/10 p-4 rounded-2xl border border-primary/20">
551
+ <p className="text-sm font-black text-primary">${rpgInfo.karma?.score || 0} Karma Global</p>
552
+ </div>
473
553
  </div>
474
554
  </div>
475
555
  </div>
476
556
  `}
477
557
  ${activeTab === 'account' &&
478
558
  html`
479
- <div className="space-y-10 max-w-2xl mx-auto lg:mx-0">
480
- <div className="flex items-center gap-6">
481
- <div className="w-16 h-16 rounded-3xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-3xl">🛡️</div>
482
- <div>
483
- <h3 className="text-2xl font-black tracking-tight">Segurança da Conta</h3>
484
- <p className="text-white/40 font-medium text-sm leading-relaxed">Mantenha sua chave de acesso segura e atualizada.</p>
485
- </div>
486
- </div>
487
-
488
- <form className="space-y-6">
489
- <div className="grid sm:grid-cols-2 gap-6">
490
- <div className="space-y-2">
491
- <label className="text-[10px] font-black uppercase tracking-widest text-white/30 ml-4">Nova Senha</label>
492
- <input type="password" placeholder="••••••••" className="w-full h-14 bg-white/5 border border-white/10 rounded-2xl px-6 focus:border-primary outline-none transition-all font-mono" />
559
+ <div className="max-w-xl animate-in fade-in slide-in-from-bottom-4 duration-500">
560
+ <div className="space-y-10">
561
+ <div className="flex items-center gap-6">
562
+ <div className="w-16 h-16 rounded-[2rem] bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center text-3xl shadow-lg">🛡️</div>
563
+ <div>
564
+ <h3 className="text-2xl font-black tracking-tight">Segurança</h3>
565
+ <p className="text-sm text-white/40 font-medium">Proteja seu acesso ao ecossistema OmniZap.</p>
493
566
  </div>
494
- <div className="space-y-2">
495
- <label className="text-[10px] font-black uppercase tracking-widest text-white/30 ml-4">Confirmar</label>
496
- <input type="password" placeholder="••••••••" className="w-full h-14 bg-white/5 border border-white/10 rounded-2xl px-6 focus:border-primary outline-none transition-all font-mono" />
567
+ </div>
568
+ <div className="p-8 rounded-[3rem] bg-white/[0.03] border border-white/5 space-y-8">
569
+ <div className="space-y-4">
570
+ <p className="text-sm text-white/60 leading-relaxed">Para alterar sua senha com segurança, o OmniZap envia um código de verificação para o e-mail vinculado à sua conta.</p>
571
+ <div className="rounded-2xl border border-white/10 bg-white/[0.02] px-4 py-3 text-xs text-white/50">Fluxo: criar sessão de redefinição → receber código por e-mail → confirmar nova senha.</div>
497
572
  </div>
573
+
574
+ <button type="button" className="btn btn-primary btn-block h-14 rounded-2xl font-black uppercase text-[10px] tracking-[0.2em] shadow-xl shadow-primary/20" disabled=${passwordResetBusy} onClick=${startPasswordResetFlow}>${passwordResetBusy ? 'Preparando redefinição...' : 'Alterar Senha com Verificação'}</button>
575
+
576
+ ${passwordResetInfo ? html` <div className="rounded-2xl border border-emerald-400/30 bg-emerald-500/10 px-4 py-3 text-xs font-semibold text-emerald-300">${passwordResetInfo}</div> ` : null} ${passwordResetError ? html` <div className="rounded-2xl border border-red-400/30 bg-red-500/10 px-4 py-3 text-xs font-semibold text-red-300">${passwordResetError}</div> ` : null}
498
577
  </div>
499
- <button className="group relative inline-flex items-center justify-center">
500
- <div className="absolute inset-0 bg-primary/20 blur-xl rounded-xl opacity-0 group-hover:opacity-100 transition-opacity"></div>
501
- <div className="relative bg-primary text-primary-content px-10 py-4 rounded-xl font-black text-[10px] uppercase tracking-[0.2em] shadow-xl hover:scale-105 transition-all">Atualizar Credenciais</div>
502
- </button>
503
- </form>
578
+ </div>
504
579
  </div>
505
580
  `}
506
581
  ${activeTab === 'support' &&
507
582
  html`
508
- <div className="text-center max-w-lg mx-auto py-16 space-y-10 relative">
509
- <div className="absolute inset-0 bg-primary/5 blur-[100px] rounded-full"></div>
510
- <div className="relative w-24 h-24 rounded-[2.5rem] bg-primary/10 border border-primary/20 flex items-center justify-center text-5xl mx-auto shadow-2xl">🎧</div>
511
- <div className="relative space-y-3">
512
- <h3 className="text-3xl font-black tracking-tighter text-white">Canal de Suporte</h3>
513
- <p className="text-white/40 font-medium leading-relaxed">Nosso time de especialistas está pronto para te ajudar com qualquer dúvida técnica ou financeira.</p>
583
+ <div className="py-16 text-center max-w-lg mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
584
+ <div className="relative inline-block mb-10">
585
+ <div className="absolute inset-0 bg-primary/20 blur-[60px] rounded-full animate-pulse"></div>
586
+ <div className="relative w-28 h-28 rounded-[3rem] bg-white/5 border border-white/10 flex items-center justify-center text-5xl shadow-2xl">🎧</div>
514
587
  </div>
515
- <a href="https://wa.me/559591122954" target="_blank" className="relative flex group">
516
- <div className="absolute inset-0 bg-success/20 blur-2xl rounded-2xl group-hover:bg-success/40 transition-all"></div>
517
- <div className="relative w-full bg-success text-white py-5 rounded-2xl font-black text-xs uppercase tracking-[0.3em] shadow-2xl group-hover:scale-[1.02] active:scale-95 transition-all">Iniciar Chat no WhatsApp</div>
518
- </a>
588
+ <h3 className="text-3xl font-black tracking-tighter mb-4">Central de Atendimento</h3>
589
+ <p className="text-white/40 font-medium leading-relaxed mb-10 text-lg">Dúvidas sobre o sistema, planos ou bugs? Fale diretamente com nossa equipe técnica.</p>
590
+ <a href=${supportWhatsappUrl} target="_blank" className="btn btn-primary btn-lg btn-block rounded-[2rem] font-black uppercase text-xs tracking-widest h-16 shadow-2xl shadow-primary/20 hover:scale-[1.02] active:scale-95 transition-all">Iniciar Chat Suporte</a>
519
591
  </div>
520
592
  `}
521
593
  </div>
@@ -523,11 +595,11 @@ const UserApp = ({ config }) => {
523
595
  </div>
524
596
  </div>
525
597
  </div>
526
- </div>
527
- </main>
598
+ </main>
599
+ </div>
528
600
 
529
- <!-- Footer Minimal -->
530
- <footer className="py-12 border-t border-white/5 mt-auto relative z-10 bg-[#020617]">
601
+ <!-- Footer -->
602
+ <footer className="py-12 border-t border-white/5 mt-auto relative z-[70] bg-[#020617]">
531
603
  <div className="container mx-auto px-4 text-center">
532
604
  <p className="text-[10px] font-black uppercase tracking-[0.5em] text-white/10">© 2026 OMNIZAP CORE · SECURE USER ENVIRONMENT</p>
533
605
  </div>
@@ -541,7 +613,10 @@ if (rootElement) {
541
613
  const config = {
542
614
  apiBasePath: rootElement.dataset.apiBasePath || DEFAULT_API_BASE_PATH,
543
615
  loginPath: rootElement.dataset.loginPath || DEFAULT_LOGIN_PATH,
616
+ passwordResetWebPath: normalizeRoutePath(rootElement.dataset.passwordResetWebPath, DEFAULT_PASSWORD_RESET_WEB_PATH),
544
617
  fallbackAvatar: DEFAULT_FALLBACK_AVATAR,
618
+ supportWhatsappNumber: rootElement.dataset.supportWhatsappNumber || DEFAULT_SUPPORT_WHATSAPP_NUMBER,
619
+ supportWhatsappUrl: rootElement.dataset.supportWhatsappUrl || DEFAULT_SUPPORT_WHATSAPP_URL,
545
620
  };
546
621
  createRoot(rootElement).render(html`<${UserApp} config=${config} />`);
547
622
  }