@botuyo/chat-widget-standalone 1.0.21 → 1.0.32

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 (51) hide show
  1. package/dist/Avatar3D-B2RkgErq.js +9 -0
  2. package/dist/Avatar3D-B2RkgErq.js.map +1 -0
  3. package/dist/ShadowChatWidget.d.ts +25 -0
  4. package/dist/ShadowChatWidget.d.ts.map +1 -0
  5. package/dist/botuyo-chat.es.js +34 -33
  6. package/dist/botuyo-chat.es.js.map +1 -1
  7. package/dist/botuyo-chat.umd.js +1 -1
  8. package/dist/botuyo-chat.umd.js.map +1 -1
  9. package/dist/{chunk-audio-C0i6pIL6.js → chunk-audio-Bp2hdKWD.js} +2 -2
  10. package/dist/{chunk-audio-C0i6pIL6.js.map → chunk-audio-Bp2hdKWD.js.map} +1 -1
  11. package/dist/chunk-chat-ui-NkAhBejH.js +128 -0
  12. package/dist/chunk-chat-ui-NkAhBejH.js.map +1 -0
  13. package/dist/{chunk-gallery-8F2X2Wky.js → chunk-gallery-Csq9S6yg.js} +2 -2
  14. package/dist/{chunk-gallery-8F2X2Wky.js.map → chunk-gallery-Csq9S6yg.js.map} +1 -1
  15. package/dist/{chunk-markdown-C7alTngS.js → chunk-markdown-QS0MJc8h.js} +2 -2
  16. package/dist/{chunk-markdown-C7alTngS.js.map → chunk-markdown-QS0MJc8h.js.map} +1 -1
  17. package/dist/src/chat-widget/ChatWidget.d.ts +1 -0
  18. package/dist/src/chat-widget/ChatWidget.d.ts.map +1 -1
  19. package/dist/src/chat-widget/components/Avatar3D.d.ts +23 -0
  20. package/dist/src/chat-widget/components/Avatar3D.d.ts.map +1 -0
  21. package/dist/src/chat-widget/components/ChatWindow.d.ts +3 -1
  22. package/dist/src/chat-widget/components/ChatWindow.d.ts.map +1 -1
  23. package/dist/src/chat-widget/components/VoiceCallOverlay.d.ts +5 -1
  24. package/dist/src/chat-widget/components/VoiceCallOverlay.d.ts.map +1 -1
  25. package/dist/src/chat-widget/hooks/useChatSocket.d.ts +1 -0
  26. package/dist/src/chat-widget/hooks/useChatSocket.d.ts.map +1 -1
  27. package/dist/src/chat-widget/hooks/useChatState.d.ts +1 -1
  28. package/dist/src/chat-widget/hooks/useChatState.d.ts.map +1 -1
  29. package/dist/src/chat-widget/hooks/useChatWidget.d.ts +1 -0
  30. package/dist/src/chat-widget/hooks/useChatWidget.d.ts.map +1 -1
  31. package/dist/src/chat-widget/hooks/useDarkMode.d.ts.map +1 -1
  32. package/dist/src/chat-widget/hooks/useNotifications.d.ts.map +1 -1
  33. package/dist/src/chat-widget/hooks/useWidgetTheme.d.ts +1 -1
  34. package/dist/src/chat-widget/i18n/LanguageContext.d.ts.map +1 -1
  35. package/dist/src/chat-widget/types/index.d.ts +8 -2
  36. package/dist/src/chat-widget/types/index.d.ts.map +1 -1
  37. package/dist/src/chat-widget/types/socket.d.ts +2 -0
  38. package/dist/src/chat-widget/types/socket.d.ts.map +1 -1
  39. package/dist/src/chat-widget/utils/storage.d.ts +4 -3
  40. package/dist/src/chat-widget/utils/storage.d.ts.map +1 -1
  41. package/dist/src/chat-widget/utils/theme.d.ts +2 -2
  42. package/dist/src/chat-widget/utils/theme.d.ts.map +1 -1
  43. package/dist/src/chat-widget/utils/theme.examples.d.ts +2 -2
  44. package/dist/src/chat-widget/utils/theme.examples.d.ts.map +1 -1
  45. package/dist/standalone.d.ts +16 -2
  46. package/dist/standalone.d.ts.map +1 -1
  47. package/dist/stats-umd.html +1 -1
  48. package/dist/stats.html +1 -1
  49. package/package.json +7 -2
  50. package/dist/chunk-chat-ui-_0LmcZf0.js +0 -123
  51. package/dist/chunk-chat-ui-_0LmcZf0.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-chat-ui-NkAhBejH.js","sources":["../src/chat-widget/i18n/translations.ts","../src/chat-widget/i18n/LanguageContext.tsx","../src/chat-widget/i18n/useTranslations.ts","../node_modules/lucide-react/dist/esm/shared/src/utils.js","../node_modules/lucide-react/dist/esm/defaultAttributes.js","../node_modules/lucide-react/dist/esm/Icon.js","../node_modules/lucide-react/dist/esm/createLucideIcon.js","../node_modules/lucide-react/dist/esm/icons/arrow-right.js","../node_modules/lucide-react/dist/esm/icons/check-check.js","../node_modules/lucide-react/dist/esm/icons/chevron-left.js","../node_modules/lucide-react/dist/esm/icons/chevron-right.js","../node_modules/lucide-react/dist/esm/icons/circle-alert.js","../node_modules/lucide-react/dist/esm/icons/download.js","../node_modules/lucide-react/dist/esm/icons/external-link.js","../node_modules/lucide-react/dist/esm/icons/file.js","../node_modules/lucide-react/dist/esm/icons/heart.js","../node_modules/lucide-react/dist/esm/icons/image.js","../node_modules/lucide-react/dist/esm/icons/keyboard.js","../node_modules/lucide-react/dist/esm/icons/loader-circle.js","../node_modules/lucide-react/dist/esm/icons/map-pin.js","../node_modules/lucide-react/dist/esm/icons/message-circle.js","../node_modules/lucide-react/dist/esm/icons/mic-off.js","../node_modules/lucide-react/dist/esm/icons/mic.js","../node_modules/lucide-react/dist/esm/icons/pause.js","../node_modules/lucide-react/dist/esm/icons/phone-off.js","../node_modules/lucide-react/dist/esm/icons/phone.js","../node_modules/lucide-react/dist/esm/icons/play.js","../node_modules/lucide-react/dist/esm/icons/plus.js","../node_modules/lucide-react/dist/esm/icons/rotate-cw.js","../node_modules/lucide-react/dist/esm/icons/send.js","../node_modules/lucide-react/dist/esm/icons/shield-check.js","../node_modules/lucide-react/dist/esm/icons/trash-2.js","../node_modules/lucide-react/dist/esm/icons/volume-2.js","../node_modules/lucide-react/dist/esm/icons/x.js","../node_modules/lucide-react/dist/esm/icons/zoom-in.js","../node_modules/clsx/dist/clsx.mjs","../node_modules/tailwind-merge/dist/bundle-mjs.mjs","../src/lib/utils.ts","../src/chat-widget/utils/theme.ts","../src/chat-widget/contexts/AnimationContext.tsx","../src/chat-widget/utils/logger.ts","../src/chat-widget/utils/defaultAssets.ts","../node_modules/@tanstack/virtual-core/dist/esm/utils.js","../node_modules/@tanstack/virtual-core/dist/esm/index.js","../node_modules/@tanstack/react-virtual/dist/esm/index.js","../src/chat-widget/components/MessageBubble.tsx","../src/chat-widget/components/TypingIndicator.tsx","../src/chat-widget/utils/dateUtils.ts","../src/chat-widget/components/MessageList.tsx","../src/chat-widget/utils/fileValidation.ts","../src/chat-widget/components/InputArea.tsx","../src/chat-widget/utils/performance.ts","../src/chat-widget/hooks/useIsMobile.ts","../src/chat-widget/hooks/useDynamicHeight.ts","../src/chat-widget/components/VoiceCallOverlay.tsx","../src/chat-widget/components/ChatWindow.tsx","../src/chat-widget/hooks/useFocusTrap.ts"],"sourcesContent":["/**\r\n * Sistema de internacionalización del Chat Widget\r\n * Idiomas soportados: español, inglés, portugués, francés\r\n */\r\n\r\nexport const translations = {\r\n es: {\r\n // Estado de conexión\r\n online: 'En línea',\r\n offline: 'Desconectado',\r\n connecting: 'Conectando...',\r\n\r\n // Footer\r\n con_amor_paseo_libre: 'Con ❤️ por BotUyo',\r\n\r\n // Input area\r\n preview: 'Vista previa',\r\n fotos: 'Fotos',\r\n ubicacion: 'Ubicación',\r\n input_placeholder: 'Escribe un mensaje...',\r\n send: 'Enviar',\r\n attach_photo: 'Adjuntar foto',\r\n attach_location: 'Compartir ubicación',\r\n recording: 'Grabando...',\r\n\r\n // Errores\r\n rate_limit_exceeded: 'Has enviado demasiados mensajes. Espera un momento.',\r\n connection_error: 'Error de conexión',\r\n file_too_large: 'Archivo demasiado grande',\r\n invalid_file: 'Tipo de archivo no válido',\r\n\r\n // Extracted (común)\r\n extracted: {\r\n assistant: 'Asistente',\r\n anterior: 'Anterior',\r\n siguiente: 'Siguiente',\r\n cerrar: 'Cerrar',\r\n cerrar_chat: 'Cerrar chat',\r\n abrir_chat: 'Abrir chat',\r\n ver_ubicacion: 'Ver ubicación',\r\n },\r\n\r\n // Accesibilidad (A11y)\r\n accessibility: {\r\n closeChat: 'Cerrar ventana de chat',\r\n closeChatHint: 'Presiona Escape para cerrar',\r\n chatMessages: 'Mensajes del chat',\r\n messageHistory: 'Historial de mensajes',\r\n dialogDescription:\r\n 'Ventana de chat con {{botName}}. Presiona Escape para cerrar. Usa Ctrl+Enter para enviar mensajes.',\r\n sendMessage: 'Enviar mensaje',\r\n sendMessageHint: 'Presiona Enter o Ctrl+Enter para enviar',\r\n typeMessage: 'Escribe tu mensaje aquí',\r\n botMessage: 'Mensaje del asistente',\r\n userMessage: 'Tu mensaje',\r\n messageFrom: 'Mensaje de {{sender}}',\r\n messageTime: 'Enviado {{time}}',\r\n newMessage: 'Nuevo mensaje recibido',\r\n },\r\n },\r\n en: {\r\n // Connection status\r\n online: 'Online',\r\n offline: 'Offline',\r\n connecting: 'Connecting...',\r\n\r\n // Footer\r\n con_amor_paseo_libre: 'With ❤️ by BotUyo',\r\n\r\n // Input area\r\n preview: 'Preview',\r\n fotos: 'Photos',\r\n ubicacion: 'Location',\r\n input_placeholder: 'Type a message...',\r\n send: 'Send',\r\n attach_photo: 'Attach photo',\r\n attach_location: 'Share location',\r\n recording: 'Recording...',\r\n\r\n // Errors\r\n rate_limit_exceeded: 'You have sent too many messages. Please wait.',\r\n connection_error: 'Connection error',\r\n file_too_large: 'File too large',\r\n invalid_file: 'Invalid file type',\r\n\r\n // Extracted (common)\r\n extracted: {\r\n assistant: 'Assistant',\r\n anterior: 'Previous',\r\n siguiente: 'Next',\r\n cerrar: 'Close',\r\n cerrar_chat: 'Close chat',\r\n abrir_chat: 'Open chat',\r\n ver_ubicacion: 'View location',\r\n },\r\n\r\n // Accessibility (A11y)\r\n accessibility: {\r\n closeChat: 'Close chat window',\r\n closeChatHint: 'Press Escape to close',\r\n chatMessages: 'Chat messages',\r\n messageHistory: 'Message history',\r\n dialogDescription:\r\n 'Chat window with {{botName}}. Press Escape to close. Use Ctrl+Enter to send messages.',\r\n sendMessage: 'Send message',\r\n sendMessageHint: 'Press Enter or Ctrl+Enter to send',\r\n typeMessage: 'Type your message here',\r\n botMessage: 'Assistant message',\r\n userMessage: 'Your message',\r\n messageFrom: 'Message from {{sender}}',\r\n messageTime: 'Sent {{time}}',\r\n newMessage: 'New message received',\r\n },\r\n },\r\n pt: {\r\n // Estado da conexão\r\n online: 'Online',\r\n offline: 'Desconectado',\r\n connecting: 'Conectando...',\r\n\r\n // Rodapé\r\n con_amor_paseo_libre: 'Com ❤️ por BotUyo',\r\n\r\n // Área de entrada\r\n preview: 'Visualizar',\r\n fotos: 'Fotos',\r\n ubicacion: 'Localização',\r\n input_placeholder: 'Digite uma mensagem...',\r\n send: 'Enviar',\r\n attach_photo: 'Anexar foto',\r\n attach_location: 'Compartilhar localização',\r\n recording: 'Gravando...',\r\n\r\n // Erros\r\n rate_limit_exceeded: 'Você enviou muitas mensagens. Aguarde um momento.',\r\n connection_error: 'Erro de conexão',\r\n file_too_large: 'Arquivo muito grande',\r\n invalid_file: 'Tipo de arquivo inválido',\r\n\r\n // Extraído (comum)\r\n extracted: {\r\n assistant: 'Assistente',\r\n anterior: 'Anterior',\r\n siguiente: 'Próximo',\r\n cerrar: 'Fechar',\r\n cerrar_chat: 'Fechar chat',\r\n abrir_chat: 'Abrir chat',\r\n ver_ubicacion: 'Ver localização',\r\n },\r\n\r\n // Acessibilidade (A11y)\r\n accessibility: {\r\n closeChat: 'Fechar janela de chat',\r\n closeChatHint: 'Pressione Escape para fechar',\r\n chatMessages: 'Mensagens do chat',\r\n messageHistory: 'Histórico de mensagens',\r\n dialogDescription:\r\n 'Janela de chat com {{botName}}. Pressione Escape para fechar. Use Ctrl+Enter para enviar mensagens.',\r\n sendMessage: 'Enviar mensagem',\r\n sendMessageHint: 'Pressione Enter ou Ctrl+Enter para enviar',\r\n typeMessage: 'Digite sua mensagem aqui',\r\n botMessage: 'Mensagem do assistente',\r\n userMessage: 'Sua mensagem',\r\n messageFrom: 'Mensagem de {{sender}}',\r\n messageTime: 'Enviado {{time}}',\r\n newMessage: 'Nova mensagem recebida',\r\n },\r\n },\r\n fr: {\r\n // État de connexion\r\n online: 'En ligne',\r\n offline: 'Déconnecté',\r\n connecting: 'Connexion...',\r\n\r\n // Pied de page\r\n con_amor_paseo_libre: 'Avec ❤️ par BotUyo',\r\n\r\n // Zone de saisie\r\n preview: 'Aperçu',\r\n fotos: 'Photos',\r\n ubicacion: 'Emplacement',\r\n input_placeholder: 'Tapez un message...',\r\n send: 'Envoyer',\r\n attach_photo: 'Joindre une photo',\r\n attach_location: 'Partager la localisation',\r\n recording: 'Enregistrement...',\r\n\r\n // Erreurs\r\n rate_limit_exceeded: 'Vous avez envoyé trop de messages. Veuillez patienter.',\r\n connection_error: 'Erreur de connexion',\r\n file_too_large: 'Fichier trop volumineux',\r\n invalid_file: 'Type de fichier invalide',\r\n\r\n // Extrait (commun)\r\n extracted: {\r\n assistant: 'Assistant',\r\n anterior: 'Précédent',\r\n siguiente: 'Suivant',\r\n cerrar: 'Fermer',\r\n cerrar_chat: 'Fermer le chat',\r\n abrir_chat: 'Ouvrir le chat',\r\n ver_ubicacion: \"Voir l'emplacement\",\r\n },\r\n\r\n // Accessibilité (A11y)\r\n accessibility: {\r\n closeChat: 'Fermer la fenêtre de chat',\r\n closeChatHint: 'Appuyez sur Échap pour fermer',\r\n chatMessages: 'Messages du chat',\r\n messageHistory: 'Historique des messages',\r\n dialogDescription:\r\n 'Fenêtre de chat avec {{botName}}. Appuyez sur Échap pour fermer. Utilisez Ctrl+Entrée pour envoyer des messages.',\r\n sendMessage: 'Envoyer un message',\r\n sendMessageHint: 'Appuyez sur Entrée ou Ctrl+Entrée pour envoyer',\r\n typeMessage: 'Tapez votre message ici',\r\n botMessage: \"Message de l'assistant\",\r\n userMessage: 'Votre message',\r\n messageFrom: 'Message de {{sender}}',\r\n messageTime: 'Envoyé {{time}}',\r\n newMessage: 'Nouveau message reçu',\r\n },\r\n },\r\n}\r\n\r\nexport type SupportedLocale = keyof typeof translations\r\n\r\n// Detección automática de idioma\r\nexport function detectLanguage(): SupportedLocale {\r\n if (typeof navigator === 'undefined') return 'es'\r\n\r\n const browserLang = navigator.language.split('-')[0] as SupportedLocale\r\n return translations[browserLang] ? browserLang : 'es'\r\n}\r\n","/**\r\n * Contexto de idioma para el Chat Widget\r\n * Permite cambio dinámico de idioma con persistencia en localStorage\r\n */\r\n\r\nimport { createContext, useContext, useState, useEffect, type ReactNode } from 'react'\r\nimport { type SupportedLocale, detectLanguage } from './translations'\r\n\r\ninterface LanguageContextType {\r\n locale: SupportedLocale\r\n setLocale: (locale: SupportedLocale) => void\r\n}\r\n\r\nconst defaultContext: LanguageContextType = {\r\n locale: detectLanguage(),\r\n setLocale: () => {},\r\n}\r\n\r\nconst LanguageContext = createContext<LanguageContextType>(defaultContext)\r\n\r\nconst LOCALE_STORAGE_KEY = 'botuyo-chat-locale'\r\n\r\ninterface LanguageProviderProps {\r\n children: ReactNode\r\n defaultLocale?: SupportedLocale\r\n}\r\n\r\n/**\r\n * Provider de idioma con detección automática y persistencia\r\n *\r\n * @example\r\n * <LanguageProvider>\r\n * <ChatWidget />\r\n * </LanguageProvider>\r\n */\r\nexport function LanguageProvider({ children, defaultLocale }: LanguageProviderProps) {\r\n const [locale, setLocaleState] = useState<SupportedLocale>(() => {\r\n // 1. Prioridad a prop defaultLocale\r\n if (defaultLocale) return defaultLocale\r\n\r\n // 2. Segundo, intentar desde localStorage\r\n if (typeof window !== 'undefined') {\r\n const stored = localStorage.getItem(LOCALE_STORAGE_KEY) as SupportedLocale | null\r\n if (stored) return stored\r\n }\r\n\r\n // 3. Finalmente, detección automática del navegador\r\n return detectLanguage()\r\n })\r\n\r\n const setLocale = (newLocale: SupportedLocale) => {\r\n // Validar que el locale sea soportado\r\n const supportedLocales: SupportedLocale[] = ['es', 'en', 'pt', 'fr']\r\n if (!supportedLocales.includes(newLocale)) {\r\n console.warn(`[BotUyo] Locale \"${newLocale}\" no es soportado. Manteniendo \"${locale}\"`)\r\n return\r\n }\r\n\r\n setLocaleState(newLocale)\r\n if (typeof window !== 'undefined') {\r\n localStorage.setItem(LOCALE_STORAGE_KEY, newLocale)\r\n }\r\n }\r\n\r\n // Efecto para manejar cambios del idioma del navegador\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || defaultLocale) return\r\n\r\n const handleLanguageChange = () => {\r\n const stored = localStorage.getItem(LOCALE_STORAGE_KEY)\r\n if (!stored) {\r\n // Si no hay preferencia guardada, actualizar con idioma del navegador\r\n setLocaleState(detectLanguage())\r\n }\r\n }\r\n\r\n window.addEventListener('languagechange', handleLanguageChange)\r\n return () => window.removeEventListener('languagechange', handleLanguageChange)\r\n }, [defaultLocale])\r\n\r\n return (\r\n <LanguageContext.Provider value={{ locale, setLocale }}>{children}</LanguageContext.Provider>\r\n )\r\n}\r\n\r\n/**\r\n * Hook para acceder al idioma actual del widget\r\n *\r\n * @example\r\n * const { locale, setLocale } = useLanguage()\r\n * setLocale('en') // Cambiar a inglés\r\n */\r\nexport function useLanguage() {\r\n const context = useContext(LanguageContext)\r\n // Return safe defaults if no provider (e.g. duplicate context from code-split chunks)\r\n return context ?? defaultContext\r\n}\r\n","/**\r\n * Hook de internacionalización para el Chat Widget\r\n * Sistema multi-idioma con detección automática y contexto global\r\n */\r\n\r\nimport { useCallback } from 'react'\r\nimport { translations, type SupportedLocale } from './translations'\r\nimport { useLanguage } from './LanguageContext'\r\n\r\n// Función helper para obtener valor anidado\r\nfunction getNestedValue(obj: any, path: string): string {\r\n return path.split('.').reduce((current, key) => current?.[key], obj) || path\r\n}\r\n\r\n/**\r\n * Hook para acceder a las traducciones con soporte multi-idioma\r\n * Usa el contexto global de idioma automáticamente\r\n *\r\n * @example\r\n * const { t, setLocale, currentLocale } = useTranslations()\r\n * t('online') // 'En línea' (si locale es 'es')\r\n * t('extracted.cerrar') // 'Cerrar'\r\n * setLocale('en') // Cambiar a inglés\r\n */\r\nexport function useTranslations(namespace?: string) {\r\n const { locale: currentLocale, setLocale } = useLanguage()\r\n\r\n const t = useCallback(\r\n (key: string): string => {\r\n const messages = translations[currentLocale]\r\n const fullKey = namespace ? `${namespace}.${key}` : key\r\n const translation = getNestedValue(messages, fullKey)\r\n return translation || key\r\n },\r\n [currentLocale, namespace]\r\n )\r\n\r\n return {\r\n t,\r\n setLocale,\r\n currentLocale,\r\n }\r\n}\r\n\r\n/**\r\n * Función para obtener traducción directamente sin hook\r\n * Útil para uso fuera de componentes\r\n */\r\nexport function t(key: string, locale: SupportedLocale = 'es'): string {\r\n return getNestedValue(translations[locale], key) || key\r\n}\r\n\r\nexport default useTranslations\r\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && array.indexOf(className) === index;\n}).join(\" \");\n\nexport { mergeClasses, toKebabCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { mergeClasses } from './shared/src/utils.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => {\n return createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n );\n }\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses, toKebabCase } from './shared/src/utils.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),\n ...props\n })\n );\n Component.displayName = `${iconName}`;\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ArrowRight = createLucideIcon(\"ArrowRight\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"m12 5 7 7-7 7\", key: \"xquz4c\" }]\n]);\n\nexport { ArrowRight as default };\n//# sourceMappingURL=arrow-right.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CheckCheck = createLucideIcon(\"CheckCheck\", [\n [\"path\", { d: \"M18 6 7 17l-5-5\", key: \"116fxf\" }],\n [\"path\", { d: \"m22 10-7.5 7.5L13 16\", key: \"ke71qq\" }]\n]);\n\nexport { CheckCheck as default };\n//# sourceMappingURL=check-check.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronLeft = createLucideIcon(\"ChevronLeft\", [\n [\"path\", { d: \"m15 18-6-6 6-6\", key: \"1wnfg3\" }]\n]);\n\nexport { ChevronLeft as default };\n//# sourceMappingURL=chevron-left.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronRight = createLucideIcon(\"ChevronRight\", [\n [\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]\n]);\n\nexport { ChevronRight as default };\n//# sourceMappingURL=chevron-right.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"CircleAlert\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Download = createLucideIcon(\"Download\", [\n [\"path\", { d: \"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\", key: \"ih7n3h\" }],\n [\"polyline\", { points: \"7 10 12 15 17 10\", key: \"2ggqvy\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"15\", y2: \"3\", key: \"1vk2je\" }]\n]);\n\nexport { Download as default };\n//# sourceMappingURL=download.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ExternalLink = createLucideIcon(\"ExternalLink\", [\n [\"path\", { d: \"M15 3h6v6\", key: \"1q9fwt\" }],\n [\"path\", { d: \"M10 14 21 3\", key: \"gplh6r\" }],\n [\"path\", { d: \"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\", key: \"a6xqqp\" }]\n]);\n\nexport { ExternalLink as default };\n//# sourceMappingURL=external-link.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst File = createLucideIcon(\"File\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }]\n]);\n\nexport { File as default };\n//# sourceMappingURL=file.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Heart = createLucideIcon(\"Heart\", [\n [\n \"path\",\n {\n d: \"M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z\",\n key: \"c3ymky\"\n }\n ]\n]);\n\nexport { Heart as default };\n//# sourceMappingURL=heart.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Image = createLucideIcon(\"Image\", [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", ry: \"2\", key: \"1m3agn\" }],\n [\"circle\", { cx: \"9\", cy: \"9\", r: \"2\", key: \"af1f0g\" }],\n [\"path\", { d: \"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\", key: \"1xmnt7\" }]\n]);\n\nexport { Image as default };\n//# sourceMappingURL=image.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Keyboard = createLucideIcon(\"Keyboard\", [\n [\"path\", { d: \"M10 8h.01\", key: \"1r9ogq\" }],\n [\"path\", { d: \"M12 12h.01\", key: \"1mp3jc\" }],\n [\"path\", { d: \"M14 8h.01\", key: \"1primd\" }],\n [\"path\", { d: \"M16 12h.01\", key: \"1l6xoz\" }],\n [\"path\", { d: \"M18 8h.01\", key: \"emo2bl\" }],\n [\"path\", { d: \"M6 8h.01\", key: \"x9i8wu\" }],\n [\"path\", { d: \"M7 16h10\", key: \"wp8him\" }],\n [\"path\", { d: \"M8 12h.01\", key: \"czm47f\" }],\n [\"rect\", { width: \"20\", height: \"16\", x: \"2\", y: \"4\", rx: \"2\", key: \"18n3k1\" }]\n]);\n\nexport { Keyboard as default };\n//# sourceMappingURL=keyboard.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst LoaderCircle = createLucideIcon(\"LoaderCircle\", [\n [\"path\", { d: \"M21 12a9 9 0 1 1-6.219-8.56\", key: \"13zald\" }]\n]);\n\nexport { LoaderCircle as default };\n//# sourceMappingURL=loader-circle.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst MapPin = createLucideIcon(\"MapPin\", [\n [\"path\", { d: \"M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z\", key: \"2oe9fu\" }],\n [\"circle\", { cx: \"12\", cy: \"10\", r: \"3\", key: \"ilqhr7\" }]\n]);\n\nexport { MapPin as default };\n//# sourceMappingURL=map-pin.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst MessageCircle = createLucideIcon(\"MessageCircle\", [\n [\"path\", { d: \"M7.9 20A9 9 0 1 0 4 16.1L2 22Z\", key: \"vv11sd\" }]\n]);\n\nexport { MessageCircle as default };\n//# sourceMappingURL=message-circle.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst MicOff = createLucideIcon(\"MicOff\", [\n [\"line\", { x1: \"2\", x2: \"22\", y1: \"2\", y2: \"22\", key: \"a6p6uj\" }],\n [\"path\", { d: \"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2\", key: \"80xlxr\" }],\n [\"path\", { d: \"M5 10v2a7 7 0 0 0 12 5\", key: \"p2k8kg\" }],\n [\"path\", { d: \"M15 9.34V5a3 3 0 0 0-5.68-1.33\", key: \"1gzdoj\" }],\n [\"path\", { d: \"M9 9v3a3 3 0 0 0 5.12 2.12\", key: \"r2i35w\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"19\", y2: \"22\", key: \"x3vr5v\" }]\n]);\n\nexport { MicOff as default };\n//# sourceMappingURL=mic-off.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Mic = createLucideIcon(\"Mic\", [\n [\"path\", { d: \"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\", key: \"131961\" }],\n [\"path\", { d: \"M19 10v2a7 7 0 0 1-14 0v-2\", key: \"1vc78b\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"19\", y2: \"22\", key: \"x3vr5v\" }]\n]);\n\nexport { Mic as default };\n//# sourceMappingURL=mic.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Pause = createLucideIcon(\"Pause\", [\n [\"rect\", { x: \"14\", y: \"4\", width: \"4\", height: \"16\", rx: \"1\", key: \"zuxfzm\" }],\n [\"rect\", { x: \"6\", y: \"4\", width: \"4\", height: \"16\", rx: \"1\", key: \"1okwgv\" }]\n]);\n\nexport { Pause as default };\n//# sourceMappingURL=pause.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst PhoneOff = createLucideIcon(\"PhoneOff\", [\n [\n \"path\",\n {\n d: \"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67m-2.67-3.34a19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91\",\n key: \"z86iuo\"\n }\n ],\n [\"line\", { x1: \"22\", x2: \"2\", y1: \"2\", y2: \"22\", key: \"11kh81\" }]\n]);\n\nexport { PhoneOff as default };\n//# sourceMappingURL=phone-off.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Phone = createLucideIcon(\"Phone\", [\n [\n \"path\",\n {\n d: \"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\",\n key: \"foiqr5\"\n }\n ]\n]);\n\nexport { Phone as default };\n//# sourceMappingURL=phone.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Play = createLucideIcon(\"Play\", [\n [\"polygon\", { points: \"6 3 20 12 6 21 6 3\", key: \"1oa8hb\" }]\n]);\n\nexport { Play as default };\n//# sourceMappingURL=play.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Plus = createLucideIcon(\"Plus\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n]);\n\nexport { Plus as default };\n//# sourceMappingURL=plus.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst RotateCw = createLucideIcon(\"RotateCw\", [\n [\"path\", { d: \"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\", key: \"1p45f6\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }]\n]);\n\nexport { RotateCw as default };\n//# sourceMappingURL=rotate-cw.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Send = createLucideIcon(\"Send\", [\n [\"path\", { d: \"m22 2-7 20-4-9-9-4Z\", key: \"1q3vgg\" }],\n [\"path\", { d: \"M22 2 11 13\", key: \"nzbqef\" }]\n]);\n\nexport { Send as default };\n//# sourceMappingURL=send.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ShieldCheck = createLucideIcon(\"ShieldCheck\", [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ],\n [\"path\", { d: \"m9 12 2 2 4-4\", key: \"dzmm74\" }]\n]);\n\nexport { ShieldCheck as default };\n//# sourceMappingURL=shield-check.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash2 = createLucideIcon(\"Trash2\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }],\n [\"line\", { x1: \"10\", x2: \"10\", y1: \"11\", y2: \"17\", key: \"1uufr5\" }],\n [\"line\", { x1: \"14\", x2: \"14\", y1: \"11\", y2: \"17\", key: \"xtxkd\" }]\n]);\n\nexport { Trash2 as default };\n//# sourceMappingURL=trash-2.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Volume2 = createLucideIcon(\"Volume2\", [\n [\"polygon\", { points: \"11 5 6 9 2 9 2 15 6 15 11 19 11 5\", key: \"16drj5\" }],\n [\"path\", { d: \"M15.54 8.46a5 5 0 0 1 0 7.07\", key: \"ltjumu\" }],\n [\"path\", { d: \"M19.07 4.93a10 10 0 0 1 0 14.14\", key: \"1kegas\" }]\n]);\n\nexport { Volume2 as default };\n//# sourceMappingURL=volume-2.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst X = createLucideIcon(\"X\", [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n]);\n\nexport { X as default };\n//# sourceMappingURL=x.js.map\n","/**\n * @license lucide-react v0.400.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ZoomIn = createLucideIcon(\"ZoomIn\", [\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }],\n [\"line\", { x1: \"21\", x2: \"16.65\", y1: \"21\", y2: \"16.65\", key: \"13gj7c\" }],\n [\"line\", { x1: \"11\", x2: \"11\", y1: \"8\", y2: \"14\", key: \"1vmskp\" }],\n [\"line\", { x1: \"8\", x2: \"14\", y1: \"11\", y2: \"11\", key: \"durymu\" }]\n]);\n\nexport { ZoomIn as default };\n//# sourceMappingURL=zoom-in.js.map\n","function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;","/**\n * Concatenates two arrays faster than the array spread operator.\n */\nconst concatArrays = (array1, array2) => {\n // Pre-allocate for better V8 optimization\n const combinedArray = new Array(array1.length + array2.length);\n for (let i = 0; i < array1.length; i++) {\n combinedArray[i] = array1[i];\n }\n for (let i = 0; i < array2.length; i++) {\n combinedArray[array1.length + i] = array2[i];\n }\n return combinedArray;\n};\n\n// Factory function ensures consistent object shapes\nconst createClassValidatorObject = (classGroupId, validator) => ({\n classGroupId,\n validator\n});\n// Factory ensures consistent ClassPartObject shape\nconst createClassPartObject = (nextPart = new Map(), validators = null, classGroupId) => ({\n nextPart,\n validators,\n classGroupId\n});\nconst CLASS_PART_SEPARATOR = '-';\nconst EMPTY_CONFLICTS = [];\n// I use two dots here because one dot is used as prefix for class groups in plugins\nconst ARBITRARY_PROPERTY_PREFIX = 'arbitrary..';\nconst createClassGroupUtils = config => {\n const classMap = createClassMap(config);\n const {\n conflictingClassGroups,\n conflictingClassGroupModifiers\n } = config;\n const getClassGroupId = className => {\n if (className.startsWith('[') && className.endsWith(']')) {\n return getGroupIdForArbitraryProperty(className);\n }\n const classParts = className.split(CLASS_PART_SEPARATOR);\n // Classes like `-inset-1` produce an empty string as first classPart. We assume that classes for negative values are used correctly and skip it.\n const startIndex = classParts[0] === '' && classParts.length > 1 ? 1 : 0;\n return getGroupRecursive(classParts, startIndex, classMap);\n };\n const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => {\n if (hasPostfixModifier) {\n const modifierConflicts = conflictingClassGroupModifiers[classGroupId];\n const baseConflicts = conflictingClassGroups[classGroupId];\n if (modifierConflicts) {\n if (baseConflicts) {\n // Merge base conflicts with modifier conflicts\n return concatArrays(baseConflicts, modifierConflicts);\n }\n // Only modifier conflicts\n return modifierConflicts;\n }\n // Fall back to without postfix if no modifier conflicts\n return baseConflicts || EMPTY_CONFLICTS;\n }\n return conflictingClassGroups[classGroupId] || EMPTY_CONFLICTS;\n };\n return {\n getClassGroupId,\n getConflictingClassGroupIds\n };\n};\nconst getGroupRecursive = (classParts, startIndex, classPartObject) => {\n const classPathsLength = classParts.length - startIndex;\n if (classPathsLength === 0) {\n return classPartObject.classGroupId;\n }\n const currentClassPart = classParts[startIndex];\n const nextClassPartObject = classPartObject.nextPart.get(currentClassPart);\n if (nextClassPartObject) {\n const result = getGroupRecursive(classParts, startIndex + 1, nextClassPartObject);\n if (result) return result;\n }\n const validators = classPartObject.validators;\n if (validators === null) {\n return undefined;\n }\n // Build classRest string efficiently by joining from startIndex onwards\n const classRest = startIndex === 0 ? classParts.join(CLASS_PART_SEPARATOR) : classParts.slice(startIndex).join(CLASS_PART_SEPARATOR);\n const validatorsLength = validators.length;\n for (let i = 0; i < validatorsLength; i++) {\n const validatorObj = validators[i];\n if (validatorObj.validator(classRest)) {\n return validatorObj.classGroupId;\n }\n }\n return undefined;\n};\n/**\n * Get the class group ID for an arbitrary property.\n *\n * @param className - The class name to get the group ID for. Is expected to be string starting with `[` and ending with `]`.\n */\nconst getGroupIdForArbitraryProperty = className => className.slice(1, -1).indexOf(':') === -1 ? undefined : (() => {\n const content = className.slice(1, -1);\n const colonIndex = content.indexOf(':');\n const property = content.slice(0, colonIndex);\n return property ? ARBITRARY_PROPERTY_PREFIX + property : undefined;\n})();\n/**\n * Exported for testing only\n */\nconst createClassMap = config => {\n const {\n theme,\n classGroups\n } = config;\n return processClassGroups(classGroups, theme);\n};\n// Split into separate functions to maintain monomorphic call sites\nconst processClassGroups = (classGroups, theme) => {\n const classMap = createClassPartObject();\n for (const classGroupId in classGroups) {\n const group = classGroups[classGroupId];\n processClassesRecursively(group, classMap, classGroupId, theme);\n }\n return classMap;\n};\nconst processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => {\n const len = classGroup.length;\n for (let i = 0; i < len; i++) {\n const classDefinition = classGroup[i];\n processClassDefinition(classDefinition, classPartObject, classGroupId, theme);\n }\n};\n// Split into separate functions for each type to maintain monomorphic call sites\nconst processClassDefinition = (classDefinition, classPartObject, classGroupId, theme) => {\n if (typeof classDefinition === 'string') {\n processStringDefinition(classDefinition, classPartObject, classGroupId);\n return;\n }\n if (typeof classDefinition === 'function') {\n processFunctionDefinition(classDefinition, classPartObject, classGroupId, theme);\n return;\n }\n processObjectDefinition(classDefinition, classPartObject, classGroupId, theme);\n};\nconst processStringDefinition = (classDefinition, classPartObject, classGroupId) => {\n const classPartObjectToEdit = classDefinition === '' ? classPartObject : getPart(classPartObject, classDefinition);\n classPartObjectToEdit.classGroupId = classGroupId;\n};\nconst processFunctionDefinition = (classDefinition, classPartObject, classGroupId, theme) => {\n if (isThemeGetter(classDefinition)) {\n processClassesRecursively(classDefinition(theme), classPartObject, classGroupId, theme);\n return;\n }\n if (classPartObject.validators === null) {\n classPartObject.validators = [];\n }\n classPartObject.validators.push(createClassValidatorObject(classGroupId, classDefinition));\n};\nconst processObjectDefinition = (classDefinition, classPartObject, classGroupId, theme) => {\n const entries = Object.entries(classDefinition);\n const len = entries.length;\n for (let i = 0; i < len; i++) {\n const [key, value] = entries[i];\n processClassesRecursively(value, getPart(classPartObject, key), classGroupId, theme);\n }\n};\nconst getPart = (classPartObject, path) => {\n let current = classPartObject;\n const parts = path.split(CLASS_PART_SEPARATOR);\n const len = parts.length;\n for (let i = 0; i < len; i++) {\n const part = parts[i];\n let next = current.nextPart.get(part);\n if (!next) {\n next = createClassPartObject();\n current.nextPart.set(part, next);\n }\n current = next;\n }\n return current;\n};\n// Type guard maintains monomorphic check\nconst isThemeGetter = func => 'isThemeGetter' in func && func.isThemeGetter === true;\n\n// LRU cache implementation using plain objects for simplicity\nconst createLruCache = maxCacheSize => {\n if (maxCacheSize < 1) {\n return {\n get: () => undefined,\n set: () => {}\n };\n }\n let cacheSize = 0;\n let cache = Object.create(null);\n let previousCache = Object.create(null);\n const update = (key, value) => {\n cache[key] = value;\n cacheSize++;\n if (cacheSize > maxCacheSize) {\n cacheSize = 0;\n previousCache = cache;\n cache = Object.create(null);\n }\n };\n return {\n get(key) {\n let value = cache[key];\n if (value !== undefined) {\n return value;\n }\n if ((value = previousCache[key]) !== undefined) {\n update(key, value);\n return value;\n }\n },\n set(key, value) {\n if (key in cache) {\n cache[key] = value;\n } else {\n update(key, value);\n }\n }\n };\n};\nconst IMPORTANT_MODIFIER = '!';\nconst MODIFIER_SEPARATOR = ':';\nconst EMPTY_MODIFIERS = [];\n// Pre-allocated result object shape for consistency\nconst createResultObject = (modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition, isExternal) => ({\n modifiers,\n hasImportantModifier,\n baseClassName,\n maybePostfixModifierPosition,\n isExternal\n});\nconst createParseClassName = config => {\n const {\n prefix,\n experimentalParseClassName\n } = config;\n /**\n * Parse class name into parts.\n *\n * Inspired by `splitAtTopLevelOnly` used in Tailwind CSS\n * @see https://github.com/tailwindlabs/tailwindcss/blob/v3.2.2/src/util/splitAtTopLevelOnly.js\n */\n let parseClassName = className => {\n // Use simple array with push for better performance\n const modifiers = [];\n let bracketDepth = 0;\n let parenDepth = 0;\n let modifierStart = 0;\n let postfixModifierPosition;\n const len = className.length;\n for (let index = 0; index < len; index++) {\n const currentCharacter = className[index];\n if (bracketDepth === 0 && parenDepth === 0) {\n if (currentCharacter === MODIFIER_SEPARATOR) {\n modifiers.push(className.slice(modifierStart, index));\n modifierStart = index + 1;\n continue;\n }\n if (currentCharacter === '/') {\n postfixModifierPosition = index;\n continue;\n }\n }\n if (currentCharacter === '[') bracketDepth++;else if (currentCharacter === ']') bracketDepth--;else if (currentCharacter === '(') parenDepth++;else if (currentCharacter === ')') parenDepth--;\n }\n const baseClassNameWithImportantModifier = modifiers.length === 0 ? className : className.slice(modifierStart);\n // Inline important modifier check\n let baseClassName = baseClassNameWithImportantModifier;\n let hasImportantModifier = false;\n if (baseClassNameWithImportantModifier.endsWith(IMPORTANT_MODIFIER)) {\n baseClassName = baseClassNameWithImportantModifier.slice(0, -1);\n hasImportantModifier = true;\n } else if (\n /**\n * In Tailwind CSS v3 the important modifier was at the start of the base class name. This is still supported for legacy reasons.\n * @see https://github.com/dcastil/tailwind-merge/issues/513#issuecomment-2614029864\n */\n baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER)) {\n baseClassName = baseClassNameWithImportantModifier.slice(1);\n hasImportantModifier = true;\n }\n const maybePostfixModifierPosition = postfixModifierPosition && postfixModifierPosition > modifierStart ? postfixModifierPosition - modifierStart : undefined;\n return createResultObject(modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition);\n };\n if (prefix) {\n const fullPrefix = prefix + MODIFIER_SEPARATOR;\n const parseClassNameOriginal = parseClassName;\n parseClassName = className => className.startsWith(fullPrefix) ? parseClassNameOriginal(className.slice(fullPrefix.length)) : createResultObject(EMPTY_MODIFIERS, false, className, undefined, true);\n }\n if (experimentalParseClassName) {\n const parseClassNameOriginal = parseClassName;\n parseClassName = className => experimentalParseClassName({\n className,\n parseClassName: parseClassNameOriginal\n });\n }\n return parseClassName;\n};\n\n/**\n * Sorts modifiers according to following schema:\n * - Predefined modifiers are sorted alphabetically\n * - When an arbitrary variant appears, it must be preserved which modifiers are before and after it\n */\nconst createSortModifiers = config => {\n // Pre-compute weights for all known modifiers for O(1) comparison\n const modifierWeights = new Map();\n // Assign weights to sensitive modifiers (highest priority, but preserve order)\n config.orderSensitiveModifiers.forEach((mod, index) => {\n modifierWeights.set(mod, 1000000 + index); // High weights for sensitive mods\n });\n return modifiers => {\n const result = [];\n let currentSegment = [];\n // Process modifiers in one pass\n for (let i = 0; i < modifiers.length; i++) {\n const modifier = modifiers[i];\n // Check if modifier is sensitive (starts with '[' or in orderSensitiveModifiers)\n const isArbitrary = modifier[0] === '[';\n const isOrderSensitive = modifierWeights.has(modifier);\n if (isArbitrary || isOrderSensitive) {\n // Sort and flush current segment alphabetically\n if (currentSegment.length > 0) {\n currentSegment.sort();\n result.push(...currentSegment);\n currentSegment = [];\n }\n result.push(modifier);\n } else {\n // Regular modifier - add to current segment for batch sorting\n currentSegment.push(modifier);\n }\n }\n // Sort and add any remaining segment items\n if (currentSegment.length > 0) {\n currentSegment.sort();\n result.push(...currentSegment);\n }\n return result;\n };\n};\nconst createConfigUtils = config => ({\n cache: createLruCache(config.cacheSize),\n parseClassName: createParseClassName(config),\n sortModifiers: createSortModifiers(config),\n ...createClassGroupUtils(config)\n});\nconst SPLIT_CLASSES_REGEX = /\\s+/;\nconst mergeClassList = (classList, configUtils) => {\n const {\n parseClassName,\n getClassGroupId,\n getConflictingClassGroupIds,\n sortModifiers\n } = configUtils;\n /**\n * Set of classGroupIds in following format:\n * `{importantModifier}{variantModifiers}{classGroupId}`\n * @example 'float'\n * @example 'hover:focus:bg-color'\n * @example 'md:!pr'\n */\n const classGroupsInConflict = [];\n const classNames = classList.trim().split(SPLIT_CLASSES_REGEX);\n let result = '';\n for (let index = classNames.length - 1; index >= 0; index -= 1) {\n const originalClassName = classNames[index];\n const {\n isExternal,\n modifiers,\n hasImportantModifier,\n baseClassName,\n maybePostfixModifierPosition\n } = parseClassName(originalClassName);\n if (isExternal) {\n result = originalClassName + (result.length > 0 ? ' ' + result : result);\n continue;\n }\n let hasPostfixModifier = !!maybePostfixModifierPosition;\n let classGroupId = getClassGroupId(hasPostfixModifier ? baseClassName.substring(0, maybePostfixModifierPosition) : baseClassName);\n if (!classGroupId) {\n if (!hasPostfixModifier) {\n // Not a Tailwind class\n result = originalClassName + (result.length > 0 ? ' ' + result : result);\n continue;\n }\n classGroupId = getClassGroupId(baseClassName);\n if (!classGroupId) {\n // Not a Tailwind class\n result = originalClassName + (result.length > 0 ? ' ' + result : result);\n continue;\n }\n hasPostfixModifier = false;\n }\n // Fast path: skip sorting for empty or single modifier\n const variantModifier = modifiers.length === 0 ? '' : modifiers.length === 1 ? modifiers[0] : sortModifiers(modifiers).join(':');\n const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier;\n const classId = modifierId + classGroupId;\n if (classGroupsInConflict.indexOf(classId) > -1) {\n // Tailwind class omitted due to conflict\n continue;\n }\n classGroupsInConflict.push(classId);\n const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier);\n for (let i = 0; i < conflictGroups.length; ++i) {\n const group = conflictGroups[i];\n classGroupsInConflict.push(modifierId + group);\n }\n // Tailwind class not in conflict\n result = originalClassName + (result.length > 0 ? ' ' + result : result);\n }\n return result;\n};\n\n/**\n * The code in this file is copied from https://github.com/lukeed/clsx and modified to suit the needs of tailwind-merge better.\n *\n * Specifically:\n * - Runtime code from https://github.com/lukeed/clsx/blob/v1.2.1/src/index.js\n * - TypeScript types from https://github.com/lukeed/clsx/blob/v1.2.1/clsx.d.ts\n *\n * Original code has MIT license: Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)\n */\nconst twJoin = (...classLists) => {\n let index = 0;\n let argument;\n let resolvedValue;\n let string = '';\n while (index < classLists.length) {\n if (argument = classLists[index++]) {\n if (resolvedValue = toValue(argument)) {\n string && (string += ' ');\n string += resolvedValue;\n }\n }\n }\n return string;\n};\nconst toValue = mix => {\n // Fast path for strings\n if (typeof mix === 'string') {\n return mix;\n }\n let resolvedValue;\n let string = '';\n for (let k = 0; k < mix.length; k++) {\n if (mix[k]) {\n if (resolvedValue = toValue(mix[k])) {\n string && (string += ' ');\n string += resolvedValue;\n }\n }\n }\n return string;\n};\nconst createTailwindMerge = (createConfigFirst, ...createConfigRest) => {\n let configUtils;\n let cacheGet;\n let cacheSet;\n let functionToCall;\n const initTailwindMerge = classList => {\n const config = createConfigRest.reduce((previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig), createConfigFirst());\n configUtils = createConfigUtils(config);\n cacheGet = configUtils.cache.get;\n cacheSet = configUtils.cache.set;\n functionToCall = tailwindMerge;\n return tailwindMerge(classList);\n };\n const tailwindMerge = classList => {\n const cachedResult = cacheGet(classList);\n if (cachedResult) {\n return cachedResult;\n }\n const result = mergeClassList(classList, configUtils);\n cacheSet(classList, result);\n return result;\n };\n functionToCall = initTailwindMerge;\n return (...args) => functionToCall(twJoin(...args));\n};\nconst fallbackThemeArr = [];\nconst fromTheme = key => {\n const themeGetter = theme => theme[key] || fallbackThemeArr;\n themeGetter.isThemeGetter = true;\n return themeGetter;\n};\nconst arbitraryValueRegex = /^\\[(?:(\\w[\\w-]*):)?(.+)\\]$/i;\nconst arbitraryVariableRegex = /^\\((?:(\\w[\\w-]*):)?(.+)\\)$/i;\nconst fractionRegex = /^\\d+\\/\\d+$/;\nconst tshirtUnitRegex = /^(\\d+(\\.\\d+)?)?(xs|sm|md|lg|xl)$/;\nconst lengthUnitRegex = /\\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\\b(calc|min|max|clamp)\\(.+\\)|^0$/;\nconst colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\\(.+\\)$/;\n// Shadow always begins with x and y offset separated by underscore optionally prepended by inset\nconst shadowRegex = /^(inset_)?-?((\\d+)?\\.?(\\d+)[a-z]+|0)_-?((\\d+)?\\.?(\\d+)[a-z]+|0)/;\nconst imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\\(.+\\)$/;\nconst isFraction = value => fractionRegex.test(value);\nconst isNumber = value => !!value && !Number.isNaN(Number(value));\nconst isInteger = value => !!value && Number.isInteger(Number(value));\nconst isPercent = value => value.endsWith('%') && isNumber(value.slice(0, -1));\nconst isTshirtSize = value => tshirtUnitRegex.test(value);\nconst isAny = () => true;\nconst isLengthOnly = value =>\n// `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.\n// For example, `hsl(0 0% 0%)` would be classified as a length without this check.\n// I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.\nlengthUnitRegex.test(value) && !colorFunctionRegex.test(value);\nconst isNever = () => false;\nconst isShadow = value => shadowRegex.test(value);\nconst isImage = value => imageRegex.test(value);\nconst isAnyNonArbitrary = value => !isArbitraryValue(value) && !isArbitraryVariable(value);\nconst isArbitrarySize = value => getIsArbitraryValue(value, isLabelSize, isNever);\nconst isArbitraryValue = value => arbitraryValueRegex.test(value);\nconst isArbitraryLength = value => getIsArbitraryValue(value, isLabelLength, isLengthOnly);\nconst isArbitraryNumber = value => getIsArbitraryValue(value, isLabelNumber, isNumber);\nconst isArbitraryPosition = value => getIsArbitraryValue(value, isLabelPosition, isNever);\nconst isArbitraryImage = value => getIsArbitraryValue(value, isLabelImage, isImage);\nconst isArbitraryShadow = value => getIsArbitraryValue(value, isLabelShadow, isShadow);\nconst isArbitraryVariable = value => arbitraryVariableRegex.test(value);\nconst isArbitraryVariableLength = value => getIsArbitraryVariable(value, isLabelLength);\nconst isArbitraryVariableFamilyName = value => getIsArbitraryVariable(value, isLabelFamilyName);\nconst isArbitraryVariablePosition = value => getIsArbitraryVariable(value, isLabelPosition);\nconst isArbitraryVariableSize = value => getIsArbitraryVariable(value, isLabelSize);\nconst isArbitraryVariableImage = value => getIsArbitraryVariable(value, isLabelImage);\nconst isArbitraryVariableShadow = value => getIsArbitraryVariable(value, isLabelShadow, true);\n// Helpers\nconst getIsArbitraryValue = (value, testLabel, testValue) => {\n const result = arbitraryValueRegex.exec(value);\n if (result) {\n if (result[1]) {\n return testLabel(result[1]);\n }\n return testValue(result[2]);\n }\n return false;\n};\nconst getIsArbitraryVariable = (value, testLabel, shouldMatchNoLabel = false) => {\n const result = arbitraryVariableRegex.exec(value);\n if (result) {\n if (result[1]) {\n return testLabel(result[1]);\n }\n return shouldMatchNoLabel;\n }\n return false;\n};\n// Labels\nconst isLabelPosition = label => label === 'position' || label === 'percentage';\nconst isLabelImage = label => label === 'image' || label === 'url';\nconst isLabelSize = label => label === 'length' || label === 'size' || label === 'bg-size';\nconst isLabelLength = label => label === 'length';\nconst isLabelNumber = label => label === 'number';\nconst isLabelFamilyName = label => label === 'family-name';\nconst isLabelShadow = label => label === 'shadow';\nconst validators = /*#__PURE__*/Object.defineProperty({\n __proto__: null,\n isAny,\n isAnyNonArbitrary,\n isArbitraryImage,\n isArbitraryLength,\n isArbitraryNumber,\n isArbitraryPosition,\n isArbitraryShadow,\n isArbitrarySize,\n isArbitraryValue,\n isArbitraryVariable,\n isArbitraryVariableFamilyName,\n isArbitraryVariableImage,\n isArbitraryVariableLength,\n isArbitraryVariablePosition,\n isArbitraryVariableShadow,\n isArbitraryVariableSize,\n isFraction,\n isInteger,\n isNumber,\n isPercent,\n isTshirtSize\n}, Symbol.toStringTag, {\n value: 'Module'\n});\nconst getDefaultConfig = () => {\n /**\n * Theme getters for theme variable namespaces\n * @see https://tailwindcss.com/docs/theme#theme-variable-namespaces\n */\n /***/\n const themeColor = fromTheme('color');\n const themeFont = fromTheme('font');\n const themeText = fromTheme('text');\n const themeFontWeight = fromTheme('font-weight');\n const themeTracking = fromTheme('tracking');\n const themeLeading = fromTheme('leading');\n const themeBreakpoint = fromTheme('breakpoint');\n const themeContainer = fromTheme('container');\n const themeSpacing = fromTheme('spacing');\n const themeRadius = fromTheme('radius');\n const themeShadow = fromTheme('shadow');\n const themeInsetShadow = fromTheme('inset-shadow');\n const themeTextShadow = fromTheme('text-shadow');\n const themeDropShadow = fromTheme('drop-shadow');\n const themeBlur = fromTheme('blur');\n const themePerspective = fromTheme('perspective');\n const themeAspect = fromTheme('aspect');\n const themeEase = fromTheme('ease');\n const themeAnimate = fromTheme('animate');\n /**\n * Helpers to avoid repeating the same scales\n *\n * We use functions that create a new array every time they're called instead of static arrays.\n * This ensures that users who modify any scale by mutating the array (e.g. with `array.push(element)`) don't accidentally mutate arrays in other parts of the config.\n */\n /***/\n const scaleBreak = () => ['auto', 'avoid', 'all', 'avoid-page', 'page', 'left', 'right', 'column'];\n const scalePosition = () => ['center', 'top', 'bottom', 'left', 'right', 'top-left',\n // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378\n 'left-top', 'top-right',\n // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378\n 'right-top', 'bottom-right',\n // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378\n 'right-bottom', 'bottom-left',\n // Deprecated since Tailwind CSS v4.1.0, see https://github.com/tailwindlabs/tailwindcss/pull/17378\n 'left-bottom'];\n const scalePositionWithArbitrary = () => [...scalePosition(), isArbitraryVariable, isArbitraryValue];\n const scaleOverflow = () => ['auto', 'hidden', 'clip', 'visible', 'scroll'];\n const scaleOverscroll = () => ['auto', 'contain', 'none'];\n const scaleUnambiguousSpacing = () => [isArbitraryVariable, isArbitraryValue, themeSpacing];\n const scaleInset = () => [isFraction, 'full', 'auto', ...scaleUnambiguousSpacing()];\n const scaleGridTemplateColsRows = () => [isInteger, 'none', 'subgrid', isArbitraryVariable, isArbitraryValue];\n const scaleGridColRowStartAndEnd = () => ['auto', {\n span: ['full', isInteger, isArbitraryVariable, isArbitraryValue]\n }, isInteger, isArbitraryVariable, isArbitraryValue];\n const scaleGridColRowStartOrEnd = () => [isInteger, 'auto', isArbitraryVariable, isArbitraryValue];\n const scaleGridAutoColsRows = () => ['auto', 'min', 'max', 'fr', isArbitraryVariable, isArbitraryValue];\n const scaleAlignPrimaryAxis = () => ['start', 'end', 'center', 'between', 'around', 'evenly', 'stretch', 'baseline', 'center-safe', 'end-safe'];\n const scaleAlignSecondaryAxis = () => ['start', 'end', 'center', 'stretch', 'center-safe', 'end-safe'];\n const scaleMargin = () => ['auto', ...scaleUnambiguousSpacing()];\n const scaleSizing = () => [isFraction, 'auto', 'full', 'dvw', 'dvh', 'lvw', 'lvh', 'svw', 'svh', 'min', 'max', 'fit', ...scaleUnambiguousSpacing()];\n const scaleColor = () => [themeColor, isArbitraryVariable, isArbitraryValue];\n const scaleBgPosition = () => [...scalePosition(), isArbitraryVariablePosition, isArbitraryPosition, {\n position: [isArbitraryVariable, isArbitraryValue]\n }];\n const scaleBgRepeat = () => ['no-repeat', {\n repeat: ['', 'x', 'y', 'space', 'round']\n }];\n const scaleBgSize = () => ['auto', 'cover', 'contain', isArbitraryVariableSize, isArbitrarySize, {\n size: [isArbitraryVariable, isArbitraryValue]\n }];\n const scaleGradientStopPosition = () => [isPercent, isArbitraryVariableLength, isArbitraryLength];\n const scaleRadius = () => [\n // Deprecated since Tailwind CSS v4.0.0\n '', 'none', 'full', themeRadius, isArbitraryVariable, isArbitraryValue];\n const scaleBorderWidth = () => ['', isNumber, isArbitraryVariableLength, isArbitraryLength];\n const scaleLineStyle = () => ['solid', 'dashed', 'dotted', 'double'];\n const scaleBlendMode = () => ['normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'];\n const scaleMaskImagePosition = () => [isNumber, isPercent, isArbitraryVariablePosition, isArbitraryPosition];\n const scaleBlur = () => [\n // Deprecated since Tailwind CSS v4.0.0\n '', 'none', themeBlur, isArbitraryVariable, isArbitraryValue];\n const scaleRotate = () => ['none', isNumber, isArbitraryVariable, isArbitraryValue];\n const scaleScale = () => ['none', isNumber, isArbitraryVariable, isArbitraryValue];\n const scaleSkew = () => [isNumber, isArbitraryVariable, isArbitraryValue];\n const scaleTranslate = () => [isFraction, 'full', ...scaleUnambiguousSpacing()];\n return {\n cacheSize: 500,\n theme: {\n animate: ['spin', 'ping', 'pulse', 'bounce'],\n aspect: ['video'],\n blur: [isTshirtSize],\n breakpoint: [isTshirtSize],\n color: [isAny],\n container: [isTshirtSize],\n 'drop-shadow': [isTshirtSize],\n ease: ['in', 'out', 'in-out'],\n font: [isAnyNonArbitrary],\n 'font-weight': ['thin', 'extralight', 'light', 'normal', 'medium', 'semibold', 'bold', 'extrabold', 'black'],\n 'inset-shadow': [isTshirtSize],\n leading: ['none', 'tight', 'snug', 'normal', 'relaxed', 'loose'],\n perspective: ['dramatic', 'near', 'normal', 'midrange', 'distant', 'none'],\n radius: [isTshirtSize],\n shadow: [isTshirtSize],\n spacing: ['px', isNumber],\n text: [isTshirtSize],\n 'text-shadow': [isTshirtSize],\n tracking: ['tighter', 'tight', 'normal', 'wide', 'wider', 'widest']\n },\n classGroups: {\n // --------------\n // --- Layout ---\n // --------------\n /**\n * Aspect Ratio\n * @see https://tailwindcss.com/docs/aspect-ratio\n */\n aspect: [{\n aspect: ['auto', 'square', isFraction, isArbitraryValue, isArbitraryVariable, themeAspect]\n }],\n /**\n * Container\n * @see https://tailwindcss.com/docs/container\n * @deprecated since Tailwind CSS v4.0.0\n */\n container: ['container'],\n /**\n * Columns\n * @see https://tailwindcss.com/docs/columns\n */\n columns: [{\n columns: [isNumber, isArbitraryValue, isArbitraryVariable, themeContainer]\n }],\n /**\n * Break After\n * @see https://tailwindcss.com/docs/break-after\n */\n 'break-after': [{\n 'break-after': scaleBreak()\n }],\n /**\n * Break Before\n * @see https://tailwindcss.com/docs/break-before\n */\n 'break-before': [{\n 'break-before': scaleBreak()\n }],\n /**\n * Break Inside\n * @see https://tailwindcss.com/docs/break-inside\n */\n 'break-inside': [{\n 'break-inside': ['auto', 'avoid', 'avoid-page', 'avoid-column']\n }],\n /**\n * Box Decoration Break\n * @see https://tailwindcss.com/docs/box-decoration-break\n */\n 'box-decoration': [{\n 'box-decoration': ['slice', 'clone']\n }],\n /**\n * Box Sizing\n * @see https://tailwindcss.com/docs/box-sizing\n */\n box: [{\n box: ['border', 'content']\n }],\n /**\n * Display\n * @see https://tailwindcss.com/docs/display\n */\n display: ['block', 'inline-block', 'inline', 'flex', 'inline-flex', 'table', 'inline-table', 'table-caption', 'table-cell', 'table-column', 'table-column-group', 'table-footer-group', 'table-header-group', 'table-row-group', 'table-row', 'flow-root', 'grid', 'inline-grid', 'contents', 'list-item', 'hidden'],\n /**\n * Screen Reader Only\n * @see https://tailwindcss.com/docs/display#screen-reader-only\n */\n sr: ['sr-only', 'not-sr-only'],\n /**\n * Floats\n * @see https://tailwindcss.com/docs/float\n */\n float: [{\n float: ['right', 'left', 'none', 'start', 'end']\n }],\n /**\n * Clear\n * @see https://tailwindcss.com/docs/clear\n */\n clear: [{\n clear: ['left', 'right', 'both', 'none', 'start', 'end']\n }],\n /**\n * Isolation\n * @see https://tailwindcss.com/docs/isolation\n */\n isolation: ['isolate', 'isolation-auto'],\n /**\n * Object Fit\n * @see https://tailwindcss.com/docs/object-fit\n */\n 'object-fit': [{\n object: ['contain', 'cover', 'fill', 'none', 'scale-down']\n }],\n /**\n * Object Position\n * @see https://tailwindcss.com/docs/object-position\n */\n 'object-position': [{\n object: scalePositionWithArbitrary()\n }],\n /**\n * Overflow\n * @see https://tailwindcss.com/docs/overflow\n */\n overflow: [{\n overflow: scaleOverflow()\n }],\n /**\n * Overflow X\n * @see https://tailwindcss.com/docs/overflow\n */\n 'overflow-x': [{\n 'overflow-x': scaleOverflow()\n }],\n /**\n * Overflow Y\n * @see https://tailwindcss.com/docs/overflow\n */\n 'overflow-y': [{\n 'overflow-y': scaleOverflow()\n }],\n /**\n * Overscroll Behavior\n * @see https://tailwindcss.com/docs/overscroll-behavior\n */\n overscroll: [{\n overscroll: scaleOverscroll()\n }],\n /**\n * Overscroll Behavior X\n * @see https://tailwindcss.com/docs/overscroll-behavior\n */\n 'overscroll-x': [{\n 'overscroll-x': scaleOverscroll()\n }],\n /**\n * Overscroll Behavior Y\n * @see https://tailwindcss.com/docs/overscroll-behavior\n */\n 'overscroll-y': [{\n 'overscroll-y': scaleOverscroll()\n }],\n /**\n * Position\n * @see https://tailwindcss.com/docs/position\n */\n position: ['static', 'fixed', 'absolute', 'relative', 'sticky'],\n /**\n * Top / Right / Bottom / Left\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n inset: [{\n inset: scaleInset()\n }],\n /**\n * Right / Left\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n 'inset-x': [{\n 'inset-x': scaleInset()\n }],\n /**\n * Top / Bottom\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n 'inset-y': [{\n 'inset-y': scaleInset()\n }],\n /**\n * Start\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n start: [{\n start: scaleInset()\n }],\n /**\n * End\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n end: [{\n end: scaleInset()\n }],\n /**\n * Top\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n top: [{\n top: scaleInset()\n }],\n /**\n * Right\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n right: [{\n right: scaleInset()\n }],\n /**\n * Bottom\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n bottom: [{\n bottom: scaleInset()\n }],\n /**\n * Left\n * @see https://tailwindcss.com/docs/top-right-bottom-left\n */\n left: [{\n left: scaleInset()\n }],\n /**\n * Visibility\n * @see https://tailwindcss.com/docs/visibility\n */\n visibility: ['visible', 'invisible', 'collapse'],\n /**\n * Z-Index\n * @see https://tailwindcss.com/docs/z-index\n */\n z: [{\n z: [isInteger, 'auto', isArbitraryVariable, isArbitraryValue]\n }],\n // ------------------------\n // --- Flexbox and Grid ---\n // ------------------------\n /**\n * Flex Basis\n * @see https://tailwindcss.com/docs/flex-basis\n */\n basis: [{\n basis: [isFraction, 'full', 'auto', themeContainer, ...scaleUnambiguousSpacing()]\n }],\n /**\n * Flex Direction\n * @see https://tailwindcss.com/docs/flex-direction\n */\n 'flex-direction': [{\n flex: ['row', 'row-reverse', 'col', 'col-reverse']\n }],\n /**\n * Flex Wrap\n * @see https://tailwindcss.com/docs/flex-wrap\n */\n 'flex-wrap': [{\n flex: ['nowrap', 'wrap', 'wrap-reverse']\n }],\n /**\n * Flex\n * @see https://tailwindcss.com/docs/flex\n */\n flex: [{\n flex: [isNumber, isFraction, 'auto', 'initial', 'none', isArbitraryValue]\n }],\n /**\n * Flex Grow\n * @see https://tailwindcss.com/docs/flex-grow\n */\n grow: [{\n grow: ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Flex Shrink\n * @see https://tailwindcss.com/docs/flex-shrink\n */\n shrink: [{\n shrink: ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Order\n * @see https://tailwindcss.com/docs/order\n */\n order: [{\n order: [isInteger, 'first', 'last', 'none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Grid Template Columns\n * @see https://tailwindcss.com/docs/grid-template-columns\n */\n 'grid-cols': [{\n 'grid-cols': scaleGridTemplateColsRows()\n }],\n /**\n * Grid Column Start / End\n * @see https://tailwindcss.com/docs/grid-column\n */\n 'col-start-end': [{\n col: scaleGridColRowStartAndEnd()\n }],\n /**\n * Grid Column Start\n * @see https://tailwindcss.com/docs/grid-column\n */\n 'col-start': [{\n 'col-start': scaleGridColRowStartOrEnd()\n }],\n /**\n * Grid Column End\n * @see https://tailwindcss.com/docs/grid-column\n */\n 'col-end': [{\n 'col-end': scaleGridColRowStartOrEnd()\n }],\n /**\n * Grid Template Rows\n * @see https://tailwindcss.com/docs/grid-template-rows\n */\n 'grid-rows': [{\n 'grid-rows': scaleGridTemplateColsRows()\n }],\n /**\n * Grid Row Start / End\n * @see https://tailwindcss.com/docs/grid-row\n */\n 'row-start-end': [{\n row: scaleGridColRowStartAndEnd()\n }],\n /**\n * Grid Row Start\n * @see https://tailwindcss.com/docs/grid-row\n */\n 'row-start': [{\n 'row-start': scaleGridColRowStartOrEnd()\n }],\n /**\n * Grid Row End\n * @see https://tailwindcss.com/docs/grid-row\n */\n 'row-end': [{\n 'row-end': scaleGridColRowStartOrEnd()\n }],\n /**\n * Grid Auto Flow\n * @see https://tailwindcss.com/docs/grid-auto-flow\n */\n 'grid-flow': [{\n 'grid-flow': ['row', 'col', 'dense', 'row-dense', 'col-dense']\n }],\n /**\n * Grid Auto Columns\n * @see https://tailwindcss.com/docs/grid-auto-columns\n */\n 'auto-cols': [{\n 'auto-cols': scaleGridAutoColsRows()\n }],\n /**\n * Grid Auto Rows\n * @see https://tailwindcss.com/docs/grid-auto-rows\n */\n 'auto-rows': [{\n 'auto-rows': scaleGridAutoColsRows()\n }],\n /**\n * Gap\n * @see https://tailwindcss.com/docs/gap\n */\n gap: [{\n gap: scaleUnambiguousSpacing()\n }],\n /**\n * Gap X\n * @see https://tailwindcss.com/docs/gap\n */\n 'gap-x': [{\n 'gap-x': scaleUnambiguousSpacing()\n }],\n /**\n * Gap Y\n * @see https://tailwindcss.com/docs/gap\n */\n 'gap-y': [{\n 'gap-y': scaleUnambiguousSpacing()\n }],\n /**\n * Justify Content\n * @see https://tailwindcss.com/docs/justify-content\n */\n 'justify-content': [{\n justify: [...scaleAlignPrimaryAxis(), 'normal']\n }],\n /**\n * Justify Items\n * @see https://tailwindcss.com/docs/justify-items\n */\n 'justify-items': [{\n 'justify-items': [...scaleAlignSecondaryAxis(), 'normal']\n }],\n /**\n * Justify Self\n * @see https://tailwindcss.com/docs/justify-self\n */\n 'justify-self': [{\n 'justify-self': ['auto', ...scaleAlignSecondaryAxis()]\n }],\n /**\n * Align Content\n * @see https://tailwindcss.com/docs/align-content\n */\n 'align-content': [{\n content: ['normal', ...scaleAlignPrimaryAxis()]\n }],\n /**\n * Align Items\n * @see https://tailwindcss.com/docs/align-items\n */\n 'align-items': [{\n items: [...scaleAlignSecondaryAxis(), {\n baseline: ['', 'last']\n }]\n }],\n /**\n * Align Self\n * @see https://tailwindcss.com/docs/align-self\n */\n 'align-self': [{\n self: ['auto', ...scaleAlignSecondaryAxis(), {\n baseline: ['', 'last']\n }]\n }],\n /**\n * Place Content\n * @see https://tailwindcss.com/docs/place-content\n */\n 'place-content': [{\n 'place-content': scaleAlignPrimaryAxis()\n }],\n /**\n * Place Items\n * @see https://tailwindcss.com/docs/place-items\n */\n 'place-items': [{\n 'place-items': [...scaleAlignSecondaryAxis(), 'baseline']\n }],\n /**\n * Place Self\n * @see https://tailwindcss.com/docs/place-self\n */\n 'place-self': [{\n 'place-self': ['auto', ...scaleAlignSecondaryAxis()]\n }],\n // Spacing\n /**\n * Padding\n * @see https://tailwindcss.com/docs/padding\n */\n p: [{\n p: scaleUnambiguousSpacing()\n }],\n /**\n * Padding X\n * @see https://tailwindcss.com/docs/padding\n */\n px: [{\n px: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Y\n * @see https://tailwindcss.com/docs/padding\n */\n py: [{\n py: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Start\n * @see https://tailwindcss.com/docs/padding\n */\n ps: [{\n ps: scaleUnambiguousSpacing()\n }],\n /**\n * Padding End\n * @see https://tailwindcss.com/docs/padding\n */\n pe: [{\n pe: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Top\n * @see https://tailwindcss.com/docs/padding\n */\n pt: [{\n pt: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Right\n * @see https://tailwindcss.com/docs/padding\n */\n pr: [{\n pr: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Bottom\n * @see https://tailwindcss.com/docs/padding\n */\n pb: [{\n pb: scaleUnambiguousSpacing()\n }],\n /**\n * Padding Left\n * @see https://tailwindcss.com/docs/padding\n */\n pl: [{\n pl: scaleUnambiguousSpacing()\n }],\n /**\n * Margin\n * @see https://tailwindcss.com/docs/margin\n */\n m: [{\n m: scaleMargin()\n }],\n /**\n * Margin X\n * @see https://tailwindcss.com/docs/margin\n */\n mx: [{\n mx: scaleMargin()\n }],\n /**\n * Margin Y\n * @see https://tailwindcss.com/docs/margin\n */\n my: [{\n my: scaleMargin()\n }],\n /**\n * Margin Start\n * @see https://tailwindcss.com/docs/margin\n */\n ms: [{\n ms: scaleMargin()\n }],\n /**\n * Margin End\n * @see https://tailwindcss.com/docs/margin\n */\n me: [{\n me: scaleMargin()\n }],\n /**\n * Margin Top\n * @see https://tailwindcss.com/docs/margin\n */\n mt: [{\n mt: scaleMargin()\n }],\n /**\n * Margin Right\n * @see https://tailwindcss.com/docs/margin\n */\n mr: [{\n mr: scaleMargin()\n }],\n /**\n * Margin Bottom\n * @see https://tailwindcss.com/docs/margin\n */\n mb: [{\n mb: scaleMargin()\n }],\n /**\n * Margin Left\n * @see https://tailwindcss.com/docs/margin\n */\n ml: [{\n ml: scaleMargin()\n }],\n /**\n * Space Between X\n * @see https://tailwindcss.com/docs/margin#adding-space-between-children\n */\n 'space-x': [{\n 'space-x': scaleUnambiguousSpacing()\n }],\n /**\n * Space Between X Reverse\n * @see https://tailwindcss.com/docs/margin#adding-space-between-children\n */\n 'space-x-reverse': ['space-x-reverse'],\n /**\n * Space Between Y\n * @see https://tailwindcss.com/docs/margin#adding-space-between-children\n */\n 'space-y': [{\n 'space-y': scaleUnambiguousSpacing()\n }],\n /**\n * Space Between Y Reverse\n * @see https://tailwindcss.com/docs/margin#adding-space-between-children\n */\n 'space-y-reverse': ['space-y-reverse'],\n // --------------\n // --- Sizing ---\n // --------------\n /**\n * Size\n * @see https://tailwindcss.com/docs/width#setting-both-width-and-height\n */\n size: [{\n size: scaleSizing()\n }],\n /**\n * Width\n * @see https://tailwindcss.com/docs/width\n */\n w: [{\n w: [themeContainer, 'screen', ...scaleSizing()]\n }],\n /**\n * Min-Width\n * @see https://tailwindcss.com/docs/min-width\n */\n 'min-w': [{\n 'min-w': [themeContainer, 'screen', /** Deprecated. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */\n 'none', ...scaleSizing()]\n }],\n /**\n * Max-Width\n * @see https://tailwindcss.com/docs/max-width\n */\n 'max-w': [{\n 'max-w': [themeContainer, 'screen', 'none', /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */\n 'prose', /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */\n {\n screen: [themeBreakpoint]\n }, ...scaleSizing()]\n }],\n /**\n * Height\n * @see https://tailwindcss.com/docs/height\n */\n h: [{\n h: ['screen', 'lh', ...scaleSizing()]\n }],\n /**\n * Min-Height\n * @see https://tailwindcss.com/docs/min-height\n */\n 'min-h': [{\n 'min-h': ['screen', 'lh', 'none', ...scaleSizing()]\n }],\n /**\n * Max-Height\n * @see https://tailwindcss.com/docs/max-height\n */\n 'max-h': [{\n 'max-h': ['screen', 'lh', ...scaleSizing()]\n }],\n // ------------------\n // --- Typography ---\n // ------------------\n /**\n * Font Size\n * @see https://tailwindcss.com/docs/font-size\n */\n 'font-size': [{\n text: ['base', themeText, isArbitraryVariableLength, isArbitraryLength]\n }],\n /**\n * Font Smoothing\n * @see https://tailwindcss.com/docs/font-smoothing\n */\n 'font-smoothing': ['antialiased', 'subpixel-antialiased'],\n /**\n * Font Style\n * @see https://tailwindcss.com/docs/font-style\n */\n 'font-style': ['italic', 'not-italic'],\n /**\n * Font Weight\n * @see https://tailwindcss.com/docs/font-weight\n */\n 'font-weight': [{\n font: [themeFontWeight, isArbitraryVariable, isArbitraryNumber]\n }],\n /**\n * Font Stretch\n * @see https://tailwindcss.com/docs/font-stretch\n */\n 'font-stretch': [{\n 'font-stretch': ['ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded', isPercent, isArbitraryValue]\n }],\n /**\n * Font Family\n * @see https://tailwindcss.com/docs/font-family\n */\n 'font-family': [{\n font: [isArbitraryVariableFamilyName, isArbitraryValue, themeFont]\n }],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-normal': ['normal-nums'],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-ordinal': ['ordinal'],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-slashed-zero': ['slashed-zero'],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-figure': ['lining-nums', 'oldstyle-nums'],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-spacing': ['proportional-nums', 'tabular-nums'],\n /**\n * Font Variant Numeric\n * @see https://tailwindcss.com/docs/font-variant-numeric\n */\n 'fvn-fraction': ['diagonal-fractions', 'stacked-fractions'],\n /**\n * Letter Spacing\n * @see https://tailwindcss.com/docs/letter-spacing\n */\n tracking: [{\n tracking: [themeTracking, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Line Clamp\n * @see https://tailwindcss.com/docs/line-clamp\n */\n 'line-clamp': [{\n 'line-clamp': [isNumber, 'none', isArbitraryVariable, isArbitraryNumber]\n }],\n /**\n * Line Height\n * @see https://tailwindcss.com/docs/line-height\n */\n leading: [{\n leading: [/** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */\n themeLeading, ...scaleUnambiguousSpacing()]\n }],\n /**\n * List Style Image\n * @see https://tailwindcss.com/docs/list-style-image\n */\n 'list-image': [{\n 'list-image': ['none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * List Style Position\n * @see https://tailwindcss.com/docs/list-style-position\n */\n 'list-style-position': [{\n list: ['inside', 'outside']\n }],\n /**\n * List Style Type\n * @see https://tailwindcss.com/docs/list-style-type\n */\n 'list-style-type': [{\n list: ['disc', 'decimal', 'none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Text Alignment\n * @see https://tailwindcss.com/docs/text-align\n */\n 'text-alignment': [{\n text: ['left', 'center', 'right', 'justify', 'start', 'end']\n }],\n /**\n * Placeholder Color\n * @deprecated since Tailwind CSS v3.0.0\n * @see https://v3.tailwindcss.com/docs/placeholder-color\n */\n 'placeholder-color': [{\n placeholder: scaleColor()\n }],\n /**\n * Text Color\n * @see https://tailwindcss.com/docs/text-color\n */\n 'text-color': [{\n text: scaleColor()\n }],\n /**\n * Text Decoration\n * @see https://tailwindcss.com/docs/text-decoration\n */\n 'text-decoration': ['underline', 'overline', 'line-through', 'no-underline'],\n /**\n * Text Decoration Style\n * @see https://tailwindcss.com/docs/text-decoration-style\n */\n 'text-decoration-style': [{\n decoration: [...scaleLineStyle(), 'wavy']\n }],\n /**\n * Text Decoration Thickness\n * @see https://tailwindcss.com/docs/text-decoration-thickness\n */\n 'text-decoration-thickness': [{\n decoration: [isNumber, 'from-font', 'auto', isArbitraryVariable, isArbitraryLength]\n }],\n /**\n * Text Decoration Color\n * @see https://tailwindcss.com/docs/text-decoration-color\n */\n 'text-decoration-color': [{\n decoration: scaleColor()\n }],\n /**\n * Text Underline Offset\n * @see https://tailwindcss.com/docs/text-underline-offset\n */\n 'underline-offset': [{\n 'underline-offset': [isNumber, 'auto', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Text Transform\n * @see https://tailwindcss.com/docs/text-transform\n */\n 'text-transform': ['uppercase', 'lowercase', 'capitalize', 'normal-case'],\n /**\n * Text Overflow\n * @see https://tailwindcss.com/docs/text-overflow\n */\n 'text-overflow': ['truncate', 'text-ellipsis', 'text-clip'],\n /**\n * Text Wrap\n * @see https://tailwindcss.com/docs/text-wrap\n */\n 'text-wrap': [{\n text: ['wrap', 'nowrap', 'balance', 'pretty']\n }],\n /**\n * Text Indent\n * @see https://tailwindcss.com/docs/text-indent\n */\n indent: [{\n indent: scaleUnambiguousSpacing()\n }],\n /**\n * Vertical Alignment\n * @see https://tailwindcss.com/docs/vertical-align\n */\n 'vertical-align': [{\n align: ['baseline', 'top', 'middle', 'bottom', 'text-top', 'text-bottom', 'sub', 'super', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Whitespace\n * @see https://tailwindcss.com/docs/whitespace\n */\n whitespace: [{\n whitespace: ['normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'break-spaces']\n }],\n /**\n * Word Break\n * @see https://tailwindcss.com/docs/word-break\n */\n break: [{\n break: ['normal', 'words', 'all', 'keep']\n }],\n /**\n * Overflow Wrap\n * @see https://tailwindcss.com/docs/overflow-wrap\n */\n wrap: [{\n wrap: ['break-word', 'anywhere', 'normal']\n }],\n /**\n * Hyphens\n * @see https://tailwindcss.com/docs/hyphens\n */\n hyphens: [{\n hyphens: ['none', 'manual', 'auto']\n }],\n /**\n * Content\n * @see https://tailwindcss.com/docs/content\n */\n content: [{\n content: ['none', isArbitraryVariable, isArbitraryValue]\n }],\n // -------------------\n // --- Backgrounds ---\n // -------------------\n /**\n * Background Attachment\n * @see https://tailwindcss.com/docs/background-attachment\n */\n 'bg-attachment': [{\n bg: ['fixed', 'local', 'scroll']\n }],\n /**\n * Background Clip\n * @see https://tailwindcss.com/docs/background-clip\n */\n 'bg-clip': [{\n 'bg-clip': ['border', 'padding', 'content', 'text']\n }],\n /**\n * Background Origin\n * @see https://tailwindcss.com/docs/background-origin\n */\n 'bg-origin': [{\n 'bg-origin': ['border', 'padding', 'content']\n }],\n /**\n * Background Position\n * @see https://tailwindcss.com/docs/background-position\n */\n 'bg-position': [{\n bg: scaleBgPosition()\n }],\n /**\n * Background Repeat\n * @see https://tailwindcss.com/docs/background-repeat\n */\n 'bg-repeat': [{\n bg: scaleBgRepeat()\n }],\n /**\n * Background Size\n * @see https://tailwindcss.com/docs/background-size\n */\n 'bg-size': [{\n bg: scaleBgSize()\n }],\n /**\n * Background Image\n * @see https://tailwindcss.com/docs/background-image\n */\n 'bg-image': [{\n bg: ['none', {\n linear: [{\n to: ['t', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl']\n }, isInteger, isArbitraryVariable, isArbitraryValue],\n radial: ['', isArbitraryVariable, isArbitraryValue],\n conic: [isInteger, isArbitraryVariable, isArbitraryValue]\n }, isArbitraryVariableImage, isArbitraryImage]\n }],\n /**\n * Background Color\n * @see https://tailwindcss.com/docs/background-color\n */\n 'bg-color': [{\n bg: scaleColor()\n }],\n /**\n * Gradient Color Stops From Position\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-from-pos': [{\n from: scaleGradientStopPosition()\n }],\n /**\n * Gradient Color Stops Via Position\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-via-pos': [{\n via: scaleGradientStopPosition()\n }],\n /**\n * Gradient Color Stops To Position\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-to-pos': [{\n to: scaleGradientStopPosition()\n }],\n /**\n * Gradient Color Stops From\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-from': [{\n from: scaleColor()\n }],\n /**\n * Gradient Color Stops Via\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-via': [{\n via: scaleColor()\n }],\n /**\n * Gradient Color Stops To\n * @see https://tailwindcss.com/docs/gradient-color-stops\n */\n 'gradient-to': [{\n to: scaleColor()\n }],\n // ---------------\n // --- Borders ---\n // ---------------\n /**\n * Border Radius\n * @see https://tailwindcss.com/docs/border-radius\n */\n rounded: [{\n rounded: scaleRadius()\n }],\n /**\n * Border Radius Start\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-s': [{\n 'rounded-s': scaleRadius()\n }],\n /**\n * Border Radius End\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-e': [{\n 'rounded-e': scaleRadius()\n }],\n /**\n * Border Radius Top\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-t': [{\n 'rounded-t': scaleRadius()\n }],\n /**\n * Border Radius Right\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-r': [{\n 'rounded-r': scaleRadius()\n }],\n /**\n * Border Radius Bottom\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-b': [{\n 'rounded-b': scaleRadius()\n }],\n /**\n * Border Radius Left\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-l': [{\n 'rounded-l': scaleRadius()\n }],\n /**\n * Border Radius Start Start\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-ss': [{\n 'rounded-ss': scaleRadius()\n }],\n /**\n * Border Radius Start End\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-se': [{\n 'rounded-se': scaleRadius()\n }],\n /**\n * Border Radius End End\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-ee': [{\n 'rounded-ee': scaleRadius()\n }],\n /**\n * Border Radius End Start\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-es': [{\n 'rounded-es': scaleRadius()\n }],\n /**\n * Border Radius Top Left\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-tl': [{\n 'rounded-tl': scaleRadius()\n }],\n /**\n * Border Radius Top Right\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-tr': [{\n 'rounded-tr': scaleRadius()\n }],\n /**\n * Border Radius Bottom Right\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-br': [{\n 'rounded-br': scaleRadius()\n }],\n /**\n * Border Radius Bottom Left\n * @see https://tailwindcss.com/docs/border-radius\n */\n 'rounded-bl': [{\n 'rounded-bl': scaleRadius()\n }],\n /**\n * Border Width\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w': [{\n border: scaleBorderWidth()\n }],\n /**\n * Border Width X\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-x': [{\n 'border-x': scaleBorderWidth()\n }],\n /**\n * Border Width Y\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-y': [{\n 'border-y': scaleBorderWidth()\n }],\n /**\n * Border Width Start\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-s': [{\n 'border-s': scaleBorderWidth()\n }],\n /**\n * Border Width End\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-e': [{\n 'border-e': scaleBorderWidth()\n }],\n /**\n * Border Width Top\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-t': [{\n 'border-t': scaleBorderWidth()\n }],\n /**\n * Border Width Right\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-r': [{\n 'border-r': scaleBorderWidth()\n }],\n /**\n * Border Width Bottom\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-b': [{\n 'border-b': scaleBorderWidth()\n }],\n /**\n * Border Width Left\n * @see https://tailwindcss.com/docs/border-width\n */\n 'border-w-l': [{\n 'border-l': scaleBorderWidth()\n }],\n /**\n * Divide Width X\n * @see https://tailwindcss.com/docs/border-width#between-children\n */\n 'divide-x': [{\n 'divide-x': scaleBorderWidth()\n }],\n /**\n * Divide Width X Reverse\n * @see https://tailwindcss.com/docs/border-width#between-children\n */\n 'divide-x-reverse': ['divide-x-reverse'],\n /**\n * Divide Width Y\n * @see https://tailwindcss.com/docs/border-width#between-children\n */\n 'divide-y': [{\n 'divide-y': scaleBorderWidth()\n }],\n /**\n * Divide Width Y Reverse\n * @see https://tailwindcss.com/docs/border-width#between-children\n */\n 'divide-y-reverse': ['divide-y-reverse'],\n /**\n * Border Style\n * @see https://tailwindcss.com/docs/border-style\n */\n 'border-style': [{\n border: [...scaleLineStyle(), 'hidden', 'none']\n }],\n /**\n * Divide Style\n * @see https://tailwindcss.com/docs/border-style#setting-the-divider-style\n */\n 'divide-style': [{\n divide: [...scaleLineStyle(), 'hidden', 'none']\n }],\n /**\n * Border Color\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color': [{\n border: scaleColor()\n }],\n /**\n * Border Color X\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-x': [{\n 'border-x': scaleColor()\n }],\n /**\n * Border Color Y\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-y': [{\n 'border-y': scaleColor()\n }],\n /**\n * Border Color S\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-s': [{\n 'border-s': scaleColor()\n }],\n /**\n * Border Color E\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-e': [{\n 'border-e': scaleColor()\n }],\n /**\n * Border Color Top\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-t': [{\n 'border-t': scaleColor()\n }],\n /**\n * Border Color Right\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-r': [{\n 'border-r': scaleColor()\n }],\n /**\n * Border Color Bottom\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-b': [{\n 'border-b': scaleColor()\n }],\n /**\n * Border Color Left\n * @see https://tailwindcss.com/docs/border-color\n */\n 'border-color-l': [{\n 'border-l': scaleColor()\n }],\n /**\n * Divide Color\n * @see https://tailwindcss.com/docs/divide-color\n */\n 'divide-color': [{\n divide: scaleColor()\n }],\n /**\n * Outline Style\n * @see https://tailwindcss.com/docs/outline-style\n */\n 'outline-style': [{\n outline: [...scaleLineStyle(), 'none', 'hidden']\n }],\n /**\n * Outline Offset\n * @see https://tailwindcss.com/docs/outline-offset\n */\n 'outline-offset': [{\n 'outline-offset': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Outline Width\n * @see https://tailwindcss.com/docs/outline-width\n */\n 'outline-w': [{\n outline: ['', isNumber, isArbitraryVariableLength, isArbitraryLength]\n }],\n /**\n * Outline Color\n * @see https://tailwindcss.com/docs/outline-color\n */\n 'outline-color': [{\n outline: scaleColor()\n }],\n // ---------------\n // --- Effects ---\n // ---------------\n /**\n * Box Shadow\n * @see https://tailwindcss.com/docs/box-shadow\n */\n shadow: [{\n shadow: [\n // Deprecated since Tailwind CSS v4.0.0\n '', 'none', themeShadow, isArbitraryVariableShadow, isArbitraryShadow]\n }],\n /**\n * Box Shadow Color\n * @see https://tailwindcss.com/docs/box-shadow#setting-the-shadow-color\n */\n 'shadow-color': [{\n shadow: scaleColor()\n }],\n /**\n * Inset Box Shadow\n * @see https://tailwindcss.com/docs/box-shadow#adding-an-inset-shadow\n */\n 'inset-shadow': [{\n 'inset-shadow': ['none', themeInsetShadow, isArbitraryVariableShadow, isArbitraryShadow]\n }],\n /**\n * Inset Box Shadow Color\n * @see https://tailwindcss.com/docs/box-shadow#setting-the-inset-shadow-color\n */\n 'inset-shadow-color': [{\n 'inset-shadow': scaleColor()\n }],\n /**\n * Ring Width\n * @see https://tailwindcss.com/docs/box-shadow#adding-a-ring\n */\n 'ring-w': [{\n ring: scaleBorderWidth()\n }],\n /**\n * Ring Width Inset\n * @see https://v3.tailwindcss.com/docs/ring-width#inset-rings\n * @deprecated since Tailwind CSS v4.0.0\n * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158\n */\n 'ring-w-inset': ['ring-inset'],\n /**\n * Ring Color\n * @see https://tailwindcss.com/docs/box-shadow#setting-the-ring-color\n */\n 'ring-color': [{\n ring: scaleColor()\n }],\n /**\n * Ring Offset Width\n * @see https://v3.tailwindcss.com/docs/ring-offset-width\n * @deprecated since Tailwind CSS v4.0.0\n * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158\n */\n 'ring-offset-w': [{\n 'ring-offset': [isNumber, isArbitraryLength]\n }],\n /**\n * Ring Offset Color\n * @see https://v3.tailwindcss.com/docs/ring-offset-color\n * @deprecated since Tailwind CSS v4.0.0\n * @see https://github.com/tailwindlabs/tailwindcss/blob/v4.0.0/packages/tailwindcss/src/utilities.ts#L4158\n */\n 'ring-offset-color': [{\n 'ring-offset': scaleColor()\n }],\n /**\n * Inset Ring Width\n * @see https://tailwindcss.com/docs/box-shadow#adding-an-inset-ring\n */\n 'inset-ring-w': [{\n 'inset-ring': scaleBorderWidth()\n }],\n /**\n * Inset Ring Color\n * @see https://tailwindcss.com/docs/box-shadow#setting-the-inset-ring-color\n */\n 'inset-ring-color': [{\n 'inset-ring': scaleColor()\n }],\n /**\n * Text Shadow\n * @see https://tailwindcss.com/docs/text-shadow\n */\n 'text-shadow': [{\n 'text-shadow': ['none', themeTextShadow, isArbitraryVariableShadow, isArbitraryShadow]\n }],\n /**\n * Text Shadow Color\n * @see https://tailwindcss.com/docs/text-shadow#setting-the-shadow-color\n */\n 'text-shadow-color': [{\n 'text-shadow': scaleColor()\n }],\n /**\n * Opacity\n * @see https://tailwindcss.com/docs/opacity\n */\n opacity: [{\n opacity: [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Mix Blend Mode\n * @see https://tailwindcss.com/docs/mix-blend-mode\n */\n 'mix-blend': [{\n 'mix-blend': [...scaleBlendMode(), 'plus-darker', 'plus-lighter']\n }],\n /**\n * Background Blend Mode\n * @see https://tailwindcss.com/docs/background-blend-mode\n */\n 'bg-blend': [{\n 'bg-blend': scaleBlendMode()\n }],\n /**\n * Mask Clip\n * @see https://tailwindcss.com/docs/mask-clip\n */\n 'mask-clip': [{\n 'mask-clip': ['border', 'padding', 'content', 'fill', 'stroke', 'view']\n }, 'mask-no-clip'],\n /**\n * Mask Composite\n * @see https://tailwindcss.com/docs/mask-composite\n */\n 'mask-composite': [{\n mask: ['add', 'subtract', 'intersect', 'exclude']\n }],\n /**\n * Mask Image\n * @see https://tailwindcss.com/docs/mask-image\n */\n 'mask-image-linear-pos': [{\n 'mask-linear': [isNumber]\n }],\n 'mask-image-linear-from-pos': [{\n 'mask-linear-from': scaleMaskImagePosition()\n }],\n 'mask-image-linear-to-pos': [{\n 'mask-linear-to': scaleMaskImagePosition()\n }],\n 'mask-image-linear-from-color': [{\n 'mask-linear-from': scaleColor()\n }],\n 'mask-image-linear-to-color': [{\n 'mask-linear-to': scaleColor()\n }],\n 'mask-image-t-from-pos': [{\n 'mask-t-from': scaleMaskImagePosition()\n }],\n 'mask-image-t-to-pos': [{\n 'mask-t-to': scaleMaskImagePosition()\n }],\n 'mask-image-t-from-color': [{\n 'mask-t-from': scaleColor()\n }],\n 'mask-image-t-to-color': [{\n 'mask-t-to': scaleColor()\n }],\n 'mask-image-r-from-pos': [{\n 'mask-r-from': scaleMaskImagePosition()\n }],\n 'mask-image-r-to-pos': [{\n 'mask-r-to': scaleMaskImagePosition()\n }],\n 'mask-image-r-from-color': [{\n 'mask-r-from': scaleColor()\n }],\n 'mask-image-r-to-color': [{\n 'mask-r-to': scaleColor()\n }],\n 'mask-image-b-from-pos': [{\n 'mask-b-from': scaleMaskImagePosition()\n }],\n 'mask-image-b-to-pos': [{\n 'mask-b-to': scaleMaskImagePosition()\n }],\n 'mask-image-b-from-color': [{\n 'mask-b-from': scaleColor()\n }],\n 'mask-image-b-to-color': [{\n 'mask-b-to': scaleColor()\n }],\n 'mask-image-l-from-pos': [{\n 'mask-l-from': scaleMaskImagePosition()\n }],\n 'mask-image-l-to-pos': [{\n 'mask-l-to': scaleMaskImagePosition()\n }],\n 'mask-image-l-from-color': [{\n 'mask-l-from': scaleColor()\n }],\n 'mask-image-l-to-color': [{\n 'mask-l-to': scaleColor()\n }],\n 'mask-image-x-from-pos': [{\n 'mask-x-from': scaleMaskImagePosition()\n }],\n 'mask-image-x-to-pos': [{\n 'mask-x-to': scaleMaskImagePosition()\n }],\n 'mask-image-x-from-color': [{\n 'mask-x-from': scaleColor()\n }],\n 'mask-image-x-to-color': [{\n 'mask-x-to': scaleColor()\n }],\n 'mask-image-y-from-pos': [{\n 'mask-y-from': scaleMaskImagePosition()\n }],\n 'mask-image-y-to-pos': [{\n 'mask-y-to': scaleMaskImagePosition()\n }],\n 'mask-image-y-from-color': [{\n 'mask-y-from': scaleColor()\n }],\n 'mask-image-y-to-color': [{\n 'mask-y-to': scaleColor()\n }],\n 'mask-image-radial': [{\n 'mask-radial': [isArbitraryVariable, isArbitraryValue]\n }],\n 'mask-image-radial-from-pos': [{\n 'mask-radial-from': scaleMaskImagePosition()\n }],\n 'mask-image-radial-to-pos': [{\n 'mask-radial-to': scaleMaskImagePosition()\n }],\n 'mask-image-radial-from-color': [{\n 'mask-radial-from': scaleColor()\n }],\n 'mask-image-radial-to-color': [{\n 'mask-radial-to': scaleColor()\n }],\n 'mask-image-radial-shape': [{\n 'mask-radial': ['circle', 'ellipse']\n }],\n 'mask-image-radial-size': [{\n 'mask-radial': [{\n closest: ['side', 'corner'],\n farthest: ['side', 'corner']\n }]\n }],\n 'mask-image-radial-pos': [{\n 'mask-radial-at': scalePosition()\n }],\n 'mask-image-conic-pos': [{\n 'mask-conic': [isNumber]\n }],\n 'mask-image-conic-from-pos': [{\n 'mask-conic-from': scaleMaskImagePosition()\n }],\n 'mask-image-conic-to-pos': [{\n 'mask-conic-to': scaleMaskImagePosition()\n }],\n 'mask-image-conic-from-color': [{\n 'mask-conic-from': scaleColor()\n }],\n 'mask-image-conic-to-color': [{\n 'mask-conic-to': scaleColor()\n }],\n /**\n * Mask Mode\n * @see https://tailwindcss.com/docs/mask-mode\n */\n 'mask-mode': [{\n mask: ['alpha', 'luminance', 'match']\n }],\n /**\n * Mask Origin\n * @see https://tailwindcss.com/docs/mask-origin\n */\n 'mask-origin': [{\n 'mask-origin': ['border', 'padding', 'content', 'fill', 'stroke', 'view']\n }],\n /**\n * Mask Position\n * @see https://tailwindcss.com/docs/mask-position\n */\n 'mask-position': [{\n mask: scaleBgPosition()\n }],\n /**\n * Mask Repeat\n * @see https://tailwindcss.com/docs/mask-repeat\n */\n 'mask-repeat': [{\n mask: scaleBgRepeat()\n }],\n /**\n * Mask Size\n * @see https://tailwindcss.com/docs/mask-size\n */\n 'mask-size': [{\n mask: scaleBgSize()\n }],\n /**\n * Mask Type\n * @see https://tailwindcss.com/docs/mask-type\n */\n 'mask-type': [{\n 'mask-type': ['alpha', 'luminance']\n }],\n /**\n * Mask Image\n * @see https://tailwindcss.com/docs/mask-image\n */\n 'mask-image': [{\n mask: ['none', isArbitraryVariable, isArbitraryValue]\n }],\n // ---------------\n // --- Filters ---\n // ---------------\n /**\n * Filter\n * @see https://tailwindcss.com/docs/filter\n */\n filter: [{\n filter: [\n // Deprecated since Tailwind CSS v3.0.0\n '', 'none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Blur\n * @see https://tailwindcss.com/docs/blur\n */\n blur: [{\n blur: scaleBlur()\n }],\n /**\n * Brightness\n * @see https://tailwindcss.com/docs/brightness\n */\n brightness: [{\n brightness: [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Contrast\n * @see https://tailwindcss.com/docs/contrast\n */\n contrast: [{\n contrast: [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Drop Shadow\n * @see https://tailwindcss.com/docs/drop-shadow\n */\n 'drop-shadow': [{\n 'drop-shadow': [\n // Deprecated since Tailwind CSS v4.0.0\n '', 'none', themeDropShadow, isArbitraryVariableShadow, isArbitraryShadow]\n }],\n /**\n * Drop Shadow Color\n * @see https://tailwindcss.com/docs/filter-drop-shadow#setting-the-shadow-color\n */\n 'drop-shadow-color': [{\n 'drop-shadow': scaleColor()\n }],\n /**\n * Grayscale\n * @see https://tailwindcss.com/docs/grayscale\n */\n grayscale: [{\n grayscale: ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Hue Rotate\n * @see https://tailwindcss.com/docs/hue-rotate\n */\n 'hue-rotate': [{\n 'hue-rotate': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Invert\n * @see https://tailwindcss.com/docs/invert\n */\n invert: [{\n invert: ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Saturate\n * @see https://tailwindcss.com/docs/saturate\n */\n saturate: [{\n saturate: [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Sepia\n * @see https://tailwindcss.com/docs/sepia\n */\n sepia: [{\n sepia: ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Filter\n * @see https://tailwindcss.com/docs/backdrop-filter\n */\n 'backdrop-filter': [{\n 'backdrop-filter': [\n // Deprecated since Tailwind CSS v3.0.0\n '', 'none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Blur\n * @see https://tailwindcss.com/docs/backdrop-blur\n */\n 'backdrop-blur': [{\n 'backdrop-blur': scaleBlur()\n }],\n /**\n * Backdrop Brightness\n * @see https://tailwindcss.com/docs/backdrop-brightness\n */\n 'backdrop-brightness': [{\n 'backdrop-brightness': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Contrast\n * @see https://tailwindcss.com/docs/backdrop-contrast\n */\n 'backdrop-contrast': [{\n 'backdrop-contrast': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Grayscale\n * @see https://tailwindcss.com/docs/backdrop-grayscale\n */\n 'backdrop-grayscale': [{\n 'backdrop-grayscale': ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Hue Rotate\n * @see https://tailwindcss.com/docs/backdrop-hue-rotate\n */\n 'backdrop-hue-rotate': [{\n 'backdrop-hue-rotate': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Invert\n * @see https://tailwindcss.com/docs/backdrop-invert\n */\n 'backdrop-invert': [{\n 'backdrop-invert': ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Opacity\n * @see https://tailwindcss.com/docs/backdrop-opacity\n */\n 'backdrop-opacity': [{\n 'backdrop-opacity': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Saturate\n * @see https://tailwindcss.com/docs/backdrop-saturate\n */\n 'backdrop-saturate': [{\n 'backdrop-saturate': [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Backdrop Sepia\n * @see https://tailwindcss.com/docs/backdrop-sepia\n */\n 'backdrop-sepia': [{\n 'backdrop-sepia': ['', isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n // --------------\n // --- Tables ---\n // --------------\n /**\n * Border Collapse\n * @see https://tailwindcss.com/docs/border-collapse\n */\n 'border-collapse': [{\n border: ['collapse', 'separate']\n }],\n /**\n * Border Spacing\n * @see https://tailwindcss.com/docs/border-spacing\n */\n 'border-spacing': [{\n 'border-spacing': scaleUnambiguousSpacing()\n }],\n /**\n * Border Spacing X\n * @see https://tailwindcss.com/docs/border-spacing\n */\n 'border-spacing-x': [{\n 'border-spacing-x': scaleUnambiguousSpacing()\n }],\n /**\n * Border Spacing Y\n * @see https://tailwindcss.com/docs/border-spacing\n */\n 'border-spacing-y': [{\n 'border-spacing-y': scaleUnambiguousSpacing()\n }],\n /**\n * Table Layout\n * @see https://tailwindcss.com/docs/table-layout\n */\n 'table-layout': [{\n table: ['auto', 'fixed']\n }],\n /**\n * Caption Side\n * @see https://tailwindcss.com/docs/caption-side\n */\n caption: [{\n caption: ['top', 'bottom']\n }],\n // ---------------------------------\n // --- Transitions and Animation ---\n // ---------------------------------\n /**\n * Transition Property\n * @see https://tailwindcss.com/docs/transition-property\n */\n transition: [{\n transition: ['', 'all', 'colors', 'opacity', 'shadow', 'transform', 'none', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Transition Behavior\n * @see https://tailwindcss.com/docs/transition-behavior\n */\n 'transition-behavior': [{\n transition: ['normal', 'discrete']\n }],\n /**\n * Transition Duration\n * @see https://tailwindcss.com/docs/transition-duration\n */\n duration: [{\n duration: [isNumber, 'initial', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Transition Timing Function\n * @see https://tailwindcss.com/docs/transition-timing-function\n */\n ease: [{\n ease: ['linear', 'initial', themeEase, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Transition Delay\n * @see https://tailwindcss.com/docs/transition-delay\n */\n delay: [{\n delay: [isNumber, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Animation\n * @see https://tailwindcss.com/docs/animation\n */\n animate: [{\n animate: ['none', themeAnimate, isArbitraryVariable, isArbitraryValue]\n }],\n // ------------------\n // --- Transforms ---\n // ------------------\n /**\n * Backface Visibility\n * @see https://tailwindcss.com/docs/backface-visibility\n */\n backface: [{\n backface: ['hidden', 'visible']\n }],\n /**\n * Perspective\n * @see https://tailwindcss.com/docs/perspective\n */\n perspective: [{\n perspective: [themePerspective, isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Perspective Origin\n * @see https://tailwindcss.com/docs/perspective-origin\n */\n 'perspective-origin': [{\n 'perspective-origin': scalePositionWithArbitrary()\n }],\n /**\n * Rotate\n * @see https://tailwindcss.com/docs/rotate\n */\n rotate: [{\n rotate: scaleRotate()\n }],\n /**\n * Rotate X\n * @see https://tailwindcss.com/docs/rotate\n */\n 'rotate-x': [{\n 'rotate-x': scaleRotate()\n }],\n /**\n * Rotate Y\n * @see https://tailwindcss.com/docs/rotate\n */\n 'rotate-y': [{\n 'rotate-y': scaleRotate()\n }],\n /**\n * Rotate Z\n * @see https://tailwindcss.com/docs/rotate\n */\n 'rotate-z': [{\n 'rotate-z': scaleRotate()\n }],\n /**\n * Scale\n * @see https://tailwindcss.com/docs/scale\n */\n scale: [{\n scale: scaleScale()\n }],\n /**\n * Scale X\n * @see https://tailwindcss.com/docs/scale\n */\n 'scale-x': [{\n 'scale-x': scaleScale()\n }],\n /**\n * Scale Y\n * @see https://tailwindcss.com/docs/scale\n */\n 'scale-y': [{\n 'scale-y': scaleScale()\n }],\n /**\n * Scale Z\n * @see https://tailwindcss.com/docs/scale\n */\n 'scale-z': [{\n 'scale-z': scaleScale()\n }],\n /**\n * Scale 3D\n * @see https://tailwindcss.com/docs/scale\n */\n 'scale-3d': ['scale-3d'],\n /**\n * Skew\n * @see https://tailwindcss.com/docs/skew\n */\n skew: [{\n skew: scaleSkew()\n }],\n /**\n * Skew X\n * @see https://tailwindcss.com/docs/skew\n */\n 'skew-x': [{\n 'skew-x': scaleSkew()\n }],\n /**\n * Skew Y\n * @see https://tailwindcss.com/docs/skew\n */\n 'skew-y': [{\n 'skew-y': scaleSkew()\n }],\n /**\n * Transform\n * @see https://tailwindcss.com/docs/transform\n */\n transform: [{\n transform: [isArbitraryVariable, isArbitraryValue, '', 'none', 'gpu', 'cpu']\n }],\n /**\n * Transform Origin\n * @see https://tailwindcss.com/docs/transform-origin\n */\n 'transform-origin': [{\n origin: scalePositionWithArbitrary()\n }],\n /**\n * Transform Style\n * @see https://tailwindcss.com/docs/transform-style\n */\n 'transform-style': [{\n transform: ['3d', 'flat']\n }],\n /**\n * Translate\n * @see https://tailwindcss.com/docs/translate\n */\n translate: [{\n translate: scaleTranslate()\n }],\n /**\n * Translate X\n * @see https://tailwindcss.com/docs/translate\n */\n 'translate-x': [{\n 'translate-x': scaleTranslate()\n }],\n /**\n * Translate Y\n * @see https://tailwindcss.com/docs/translate\n */\n 'translate-y': [{\n 'translate-y': scaleTranslate()\n }],\n /**\n * Translate Z\n * @see https://tailwindcss.com/docs/translate\n */\n 'translate-z': [{\n 'translate-z': scaleTranslate()\n }],\n /**\n * Translate None\n * @see https://tailwindcss.com/docs/translate\n */\n 'translate-none': ['translate-none'],\n // ---------------------\n // --- Interactivity ---\n // ---------------------\n /**\n * Accent Color\n * @see https://tailwindcss.com/docs/accent-color\n */\n accent: [{\n accent: scaleColor()\n }],\n /**\n * Appearance\n * @see https://tailwindcss.com/docs/appearance\n */\n appearance: [{\n appearance: ['none', 'auto']\n }],\n /**\n * Caret Color\n * @see https://tailwindcss.com/docs/just-in-time-mode#caret-color-utilities\n */\n 'caret-color': [{\n caret: scaleColor()\n }],\n /**\n * Color Scheme\n * @see https://tailwindcss.com/docs/color-scheme\n */\n 'color-scheme': [{\n scheme: ['normal', 'dark', 'light', 'light-dark', 'only-dark', 'only-light']\n }],\n /**\n * Cursor\n * @see https://tailwindcss.com/docs/cursor\n */\n cursor: [{\n cursor: ['auto', 'default', 'pointer', 'wait', 'text', 'move', 'help', 'not-allowed', 'none', 'context-menu', 'progress', 'cell', 'crosshair', 'vertical-text', 'alias', 'copy', 'no-drop', 'grab', 'grabbing', 'all-scroll', 'col-resize', 'row-resize', 'n-resize', 'e-resize', 's-resize', 'w-resize', 'ne-resize', 'nw-resize', 'se-resize', 'sw-resize', 'ew-resize', 'ns-resize', 'nesw-resize', 'nwse-resize', 'zoom-in', 'zoom-out', isArbitraryVariable, isArbitraryValue]\n }],\n /**\n * Field Sizing\n * @see https://tailwindcss.com/docs/field-sizing\n */\n 'field-sizing': [{\n 'field-sizing': ['fixed', 'content']\n }],\n /**\n * Pointer Events\n * @see https://tailwindcss.com/docs/pointer-events\n */\n 'pointer-events': [{\n 'pointer-events': ['auto', 'none']\n }],\n /**\n * Resize\n * @see https://tailwindcss.com/docs/resize\n */\n resize: [{\n resize: ['none', '', 'y', 'x']\n }],\n /**\n * Scroll Behavior\n * @see https://tailwindcss.com/docs/scroll-behavior\n */\n 'scroll-behavior': [{\n scroll: ['auto', 'smooth']\n }],\n /**\n * Scroll Margin\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-m': [{\n 'scroll-m': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin X\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-mx': [{\n 'scroll-mx': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Y\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-my': [{\n 'scroll-my': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Start\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-ms': [{\n 'scroll-ms': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin End\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-me': [{\n 'scroll-me': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Top\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-mt': [{\n 'scroll-mt': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Right\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-mr': [{\n 'scroll-mr': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Bottom\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-mb': [{\n 'scroll-mb': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Margin Left\n * @see https://tailwindcss.com/docs/scroll-margin\n */\n 'scroll-ml': [{\n 'scroll-ml': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-p': [{\n 'scroll-p': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding X\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-px': [{\n 'scroll-px': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Y\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-py': [{\n 'scroll-py': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Start\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-ps': [{\n 'scroll-ps': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding End\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-pe': [{\n 'scroll-pe': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Top\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-pt': [{\n 'scroll-pt': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Right\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-pr': [{\n 'scroll-pr': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Bottom\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-pb': [{\n 'scroll-pb': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Padding Left\n * @see https://tailwindcss.com/docs/scroll-padding\n */\n 'scroll-pl': [{\n 'scroll-pl': scaleUnambiguousSpacing()\n }],\n /**\n * Scroll Snap Align\n * @see https://tailwindcss.com/docs/scroll-snap-align\n */\n 'snap-align': [{\n snap: ['start', 'end', 'center', 'align-none']\n }],\n /**\n * Scroll Snap Stop\n * @see https://tailwindcss.com/docs/scroll-snap-stop\n */\n 'snap-stop': [{\n snap: ['normal', 'always']\n }],\n /**\n * Scroll Snap Type\n * @see https://tailwindcss.com/docs/scroll-snap-type\n */\n 'snap-type': [{\n snap: ['none', 'x', 'y', 'both']\n }],\n /**\n * Scroll Snap Type Strictness\n * @see https://tailwindcss.com/docs/scroll-snap-type\n */\n 'snap-strictness': [{\n snap: ['mandatory', 'proximity']\n }],\n /**\n * Touch Action\n * @see https://tailwindcss.com/docs/touch-action\n */\n touch: [{\n touch: ['auto', 'none', 'manipulation']\n }],\n /**\n * Touch Action X\n * @see https://tailwindcss.com/docs/touch-action\n */\n 'touch-x': [{\n 'touch-pan': ['x', 'left', 'right']\n }],\n /**\n * Touch Action Y\n * @see https://tailwindcss.com/docs/touch-action\n */\n 'touch-y': [{\n 'touch-pan': ['y', 'up', 'down']\n }],\n /**\n * Touch Action Pinch Zoom\n * @see https://tailwindcss.com/docs/touch-action\n */\n 'touch-pz': ['touch-pinch-zoom'],\n /**\n * User Select\n * @see https://tailwindcss.com/docs/user-select\n */\n select: [{\n select: ['none', 'text', 'all', 'auto']\n }],\n /**\n * Will Change\n * @see https://tailwindcss.com/docs/will-change\n */\n 'will-change': [{\n 'will-change': ['auto', 'scroll', 'contents', 'transform', isArbitraryVariable, isArbitraryValue]\n }],\n // -----------\n // --- SVG ---\n // -----------\n /**\n * Fill\n * @see https://tailwindcss.com/docs/fill\n */\n fill: [{\n fill: ['none', ...scaleColor()]\n }],\n /**\n * Stroke Width\n * @see https://tailwindcss.com/docs/stroke-width\n */\n 'stroke-w': [{\n stroke: [isNumber, isArbitraryVariableLength, isArbitraryLength, isArbitraryNumber]\n }],\n /**\n * Stroke\n * @see https://tailwindcss.com/docs/stroke\n */\n stroke: [{\n stroke: ['none', ...scaleColor()]\n }],\n // ---------------------\n // --- Accessibility ---\n // ---------------------\n /**\n * Forced Color Adjust\n * @see https://tailwindcss.com/docs/forced-color-adjust\n */\n 'forced-color-adjust': [{\n 'forced-color-adjust': ['auto', 'none']\n }]\n },\n conflictingClassGroups: {\n overflow: ['overflow-x', 'overflow-y'],\n overscroll: ['overscroll-x', 'overscroll-y'],\n inset: ['inset-x', 'inset-y', 'start', 'end', 'top', 'right', 'bottom', 'left'],\n 'inset-x': ['right', 'left'],\n 'inset-y': ['top', 'bottom'],\n flex: ['basis', 'grow', 'shrink'],\n gap: ['gap-x', 'gap-y'],\n p: ['px', 'py', 'ps', 'pe', 'pt', 'pr', 'pb', 'pl'],\n px: ['pr', 'pl'],\n py: ['pt', 'pb'],\n m: ['mx', 'my', 'ms', 'me', 'mt', 'mr', 'mb', 'ml'],\n mx: ['mr', 'ml'],\n my: ['mt', 'mb'],\n size: ['w', 'h'],\n 'font-size': ['leading'],\n 'fvn-normal': ['fvn-ordinal', 'fvn-slashed-zero', 'fvn-figure', 'fvn-spacing', 'fvn-fraction'],\n 'fvn-ordinal': ['fvn-normal'],\n 'fvn-slashed-zero': ['fvn-normal'],\n 'fvn-figure': ['fvn-normal'],\n 'fvn-spacing': ['fvn-normal'],\n 'fvn-fraction': ['fvn-normal'],\n 'line-clamp': ['display', 'overflow'],\n rounded: ['rounded-s', 'rounded-e', 'rounded-t', 'rounded-r', 'rounded-b', 'rounded-l', 'rounded-ss', 'rounded-se', 'rounded-ee', 'rounded-es', 'rounded-tl', 'rounded-tr', 'rounded-br', 'rounded-bl'],\n 'rounded-s': ['rounded-ss', 'rounded-es'],\n 'rounded-e': ['rounded-se', 'rounded-ee'],\n 'rounded-t': ['rounded-tl', 'rounded-tr'],\n 'rounded-r': ['rounded-tr', 'rounded-br'],\n 'rounded-b': ['rounded-br', 'rounded-bl'],\n 'rounded-l': ['rounded-tl', 'rounded-bl'],\n 'border-spacing': ['border-spacing-x', 'border-spacing-y'],\n 'border-w': ['border-w-x', 'border-w-y', 'border-w-s', 'border-w-e', 'border-w-t', 'border-w-r', 'border-w-b', 'border-w-l'],\n 'border-w-x': ['border-w-r', 'border-w-l'],\n 'border-w-y': ['border-w-t', 'border-w-b'],\n 'border-color': ['border-color-x', 'border-color-y', 'border-color-s', 'border-color-e', 'border-color-t', 'border-color-r', 'border-color-b', 'border-color-l'],\n 'border-color-x': ['border-color-r', 'border-color-l'],\n 'border-color-y': ['border-color-t', 'border-color-b'],\n translate: ['translate-x', 'translate-y', 'translate-none'],\n 'translate-none': ['translate', 'translate-x', 'translate-y', 'translate-z'],\n 'scroll-m': ['scroll-mx', 'scroll-my', 'scroll-ms', 'scroll-me', 'scroll-mt', 'scroll-mr', 'scroll-mb', 'scroll-ml'],\n 'scroll-mx': ['scroll-mr', 'scroll-ml'],\n 'scroll-my': ['scroll-mt', 'scroll-mb'],\n 'scroll-p': ['scroll-px', 'scroll-py', 'scroll-ps', 'scroll-pe', 'scroll-pt', 'scroll-pr', 'scroll-pb', 'scroll-pl'],\n 'scroll-px': ['scroll-pr', 'scroll-pl'],\n 'scroll-py': ['scroll-pt', 'scroll-pb'],\n touch: ['touch-x', 'touch-y', 'touch-pz'],\n 'touch-x': ['touch'],\n 'touch-y': ['touch'],\n 'touch-pz': ['touch']\n },\n conflictingClassGroupModifiers: {\n 'font-size': ['leading']\n },\n orderSensitiveModifiers: ['*', '**', 'after', 'backdrop', 'before', 'details-content', 'file', 'first-letter', 'first-line', 'marker', 'placeholder', 'selection']\n };\n};\n\n/**\n * @param baseConfig Config where other config will be merged into. This object will be mutated.\n * @param configExtension Partial config to merge into the `baseConfig`.\n */\nconst mergeConfigs = (baseConfig, {\n cacheSize,\n prefix,\n experimentalParseClassName,\n extend = {},\n override = {}\n}) => {\n overrideProperty(baseConfig, 'cacheSize', cacheSize);\n overrideProperty(baseConfig, 'prefix', prefix);\n overrideProperty(baseConfig, 'experimentalParseClassName', experimentalParseClassName);\n overrideConfigProperties(baseConfig.theme, override.theme);\n overrideConfigProperties(baseConfig.classGroups, override.classGroups);\n overrideConfigProperties(baseConfig.conflictingClassGroups, override.conflictingClassGroups);\n overrideConfigProperties(baseConfig.conflictingClassGroupModifiers, override.conflictingClassGroupModifiers);\n overrideProperty(baseConfig, 'orderSensitiveModifiers', override.orderSensitiveModifiers);\n mergeConfigProperties(baseConfig.theme, extend.theme);\n mergeConfigProperties(baseConfig.classGroups, extend.classGroups);\n mergeConfigProperties(baseConfig.conflictingClassGroups, extend.conflictingClassGroups);\n mergeConfigProperties(baseConfig.conflictingClassGroupModifiers, extend.conflictingClassGroupModifiers);\n mergeArrayProperties(baseConfig, extend, 'orderSensitiveModifiers');\n return baseConfig;\n};\nconst overrideProperty = (baseObject, overrideKey, overrideValue) => {\n if (overrideValue !== undefined) {\n baseObject[overrideKey] = overrideValue;\n }\n};\nconst overrideConfigProperties = (baseObject, overrideObject) => {\n if (overrideObject) {\n for (const key in overrideObject) {\n overrideProperty(baseObject, key, overrideObject[key]);\n }\n }\n};\nconst mergeConfigProperties = (baseObject, mergeObject) => {\n if (mergeObject) {\n for (const key in mergeObject) {\n mergeArrayProperties(baseObject, mergeObject, key);\n }\n }\n};\nconst mergeArrayProperties = (baseObject, mergeObject, key) => {\n const mergeValue = mergeObject[key];\n if (mergeValue !== undefined) {\n baseObject[key] = baseObject[key] ? baseObject[key].concat(mergeValue) : mergeValue;\n }\n};\nconst extendTailwindMerge = (configExtension, ...createConfig) => typeof configExtension === 'function' ? createTailwindMerge(getDefaultConfig, configExtension, ...createConfig) : createTailwindMerge(() => mergeConfigs(getDefaultConfig(), configExtension), ...createConfig);\nconst twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);\nexport { createTailwindMerge, extendTailwindMerge, fromTheme, getDefaultConfig, mergeConfigs, twJoin, twMerge, validators };\n//# sourceMappingURL=bundle-mjs.mjs.map\n","import { clsx, type ClassValue } from 'clsx'\r\nimport { twMerge } from 'tailwind-merge'\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * Sistema de Temas y CSS Variables\r\n *\r\n * Este módulo centraliza toda la gestión de temas del widget.\r\n * Exporta temas predefinidos, utilidades y constantes.\r\n */\r\n\r\nimport { ChatTheme } from '../types'\r\n\r\n/**\r\n * ===================================\r\n * CSS VARIABLES (HSL Format)\r\n * ===================================\r\n */\r\n\r\nexport interface CSSVariables {\r\n background: string // Fondo principal\r\n foreground: string // Texto principal\r\n card: string // Fondo de tarjetas\r\n cardForeground: string // Texto en tarjetas\r\n primary: string // Color primario\r\n primaryForeground: string // Texto sobre primario\r\n muted: string // Fondos atenuados\r\n mutedForeground: string // Texto atenuado\r\n border: string // Bordes\r\n destructive: string // Color de error\r\n radius: string // Radio de bordes\r\n\r\n // Design System - Spacing\r\n spacing1?: string // 0.25rem (4px) - Extra small\r\n spacing2?: string // 0.5rem (8px) - Small\r\n spacing3?: string // 0.75rem (12px) - Medium small\r\n spacing4?: string // 1rem (16px) - Medium (default)\r\n spacing5?: string // 1.25rem (20px) - Medium large\r\n spacing6?: string // 1.5rem (24px) - Large\r\n spacing8?: string // 2rem (32px) - Extra large\r\n}\r\n\r\n/**\r\n * Valores CSS por defecto (Light Mode - BotUyo)\r\n */\r\nexport const DEFAULT_CSS_VARIABLES: CSSVariables = {\r\n background: '0 0% 100%', // Blanco\r\n foreground: '240 10% 3.9%', // Negro azulado\r\n card: '0 0% 100%', // Blanco\r\n cardForeground: '240 10% 3.9%', // Negro azulado\r\n primary: '160 84% 39%', // Verde BotUyo\r\n primaryForeground: '0 0% 100%', // Blanco\r\n muted: '240 4.8% 95.9%', // Gris claro\r\n mutedForeground: '240 3.8% 46.1%', // Gris oscuro\r\n border: '240 5.9% 90%', // Gris borde\r\n destructive: '0 84.2% 60.2%', // Rojo\r\n radius: '0.5rem', // 8px\r\n\r\n // Design System - Spacing\r\n spacing1: '0.25rem', // 4px\r\n spacing2: '0.5rem', // 8px\r\n spacing3: '0.75rem', // 12px\r\n spacing4: '1rem', // 16px (default)\r\n spacing5: '0.75rem', // 12px (padding default)\r\n spacing6: '1.5rem', // 24px\r\n spacing8: '2rem', // 32px\r\n}\r\n\r\n/**\r\n * Valores CSS para Dark Mode\r\n */\r\nexport const DARK_CSS_VARIABLES: CSSVariables = {\r\n background: '240 10% 3.9%', // Fondo oscuro\r\n foreground: '0 0% 98%', // Texto claro\r\n card: '240 10% 10%', // Tarjetas oscuras\r\n cardForeground: '0 0% 98%', // Texto claro\r\n primary: '160 84% 39%', // Verde BotUyo\r\n primaryForeground: '0 0% 100%', // Blanco\r\n muted: '240 3.7% 15.9%', // Gris oscuro\r\n mutedForeground: '240 5% 64.9%', // Gris claro\r\n border: '240 3.7% 15.9%', // Bordes oscuros\r\n destructive: '0 63% 31%', // Rojo oscuro\r\n radius: '0.5rem', // 8px\r\n\r\n // Design System - Spacing (mismo que light)\r\n spacing1: '0.25rem',\r\n spacing2: '0.5rem',\r\n spacing3: '0.75rem',\r\n spacing4: '1rem',\r\n spacing5: '0.75rem',\r\n spacing6: '1.5rem',\r\n spacing8: '2rem',\r\n}\r\n\r\n/**\r\n * ===================================\r\n * TEMAS PREDEFINIDOS\r\n * ===================================\r\n *\r\n * Cada tema está diseñado para ser visualmente único y distintivo.\r\n * Los usuarios pueden personalizar cualquier valor, y el sistema de merge\r\n * garantiza que los valores faltantes se completen con defaults.\r\n */\r\n\r\n/**\r\n * TEMA DEFAULT - BotUyo (Verde Fresco)\r\n * Tema por defecto cuando no se envía configuración\r\n */\r\nexport const DEFAULT_THEME: Required<\r\n Omit<\r\n ChatTheme,\r\n | 'avatars'\r\n | 'emotion'\r\n | 'starterPrompt'\r\n | 'launcherBorderRadius'\r\n | 'borderRadius'\r\n | 'bubbleStyles'\r\n | 'promptPersistence'\r\n | 'avatarScale'\r\n | 'showPromptAvatar'\r\n | 'height'\r\n | 'bottom'\r\n | 'defaultLocale'\r\n | 'animations'\r\n | 'effects'\r\n | 'avatar3dUrl'\r\n >\r\n> = {\r\n primaryColor: 'hsl(160, 84%, 39%)',\r\n botName: 'BotUyo',\r\n logoUrl: '',\r\n position: 'bottom-right',\r\n welcomeMessage: '¡Hola! ¿En qué puedo ayudarte?',\r\n inputPlaceholder: 'Escribe un mensaje...',\r\n cssVariables: DEFAULT_CSS_VARIABLES,\r\n isHidden: false,\r\n}\r\n\r\n/**\r\n * TEMA OCEAN - Azul Profundo\r\n * Diseño profesional y corporativo con tonos azules\r\n */\r\nexport const OCEAN_THEME: ChatTheme = {\r\n primaryColor: 'hsl(211, 100%, 50%)',\r\n botName: 'Ocean Assistant',\r\n welcomeMessage: 'Bienvenido, ¿cómo puedo ayudarte?',\r\n cssVariables: {\r\n background: '210 25% 98%',\r\n foreground: '210 50% 10%',\r\n card: '210 20% 97%',\r\n cardForeground: '210 50% 10%',\r\n primary: '211 100% 50%',\r\n primaryForeground: '0 0% 100%',\r\n muted: '210 20% 95%',\r\n mutedForeground: '210 15% 40%',\r\n border: '210 20% 88%',\r\n destructive: '0 84% 60%',\r\n radius: '0.75rem',\r\n spacing5: '1rem', // 16px - más espacioso\r\n },\r\n}\r\n\r\n/**\r\n * TEMA SUNSET - Naranja Cálido\r\n * Diseño energético y amigable con tonos cálidos\r\n */\r\nexport const SUNSET_THEME: ChatTheme = {\r\n primaryColor: 'hsl(24, 95%, 53%)',\r\n botName: 'Sunset Helper',\r\n welcomeMessage: '👋 ¡Hola! Estoy aquí para ayudarte',\r\n inputPlaceholder: '¿Qué necesitas?',\r\n cssVariables: {\r\n background: '30 40% 98%',\r\n foreground: '20 30% 15%',\r\n card: '30 35% 96%',\r\n cardForeground: '20 30% 15%',\r\n primary: '24 95% 53%',\r\n primaryForeground: '0 0% 100%',\r\n muted: '30 25% 94%',\r\n mutedForeground: '20 15% 35%',\r\n border: '30 20% 85%',\r\n destructive: '0 84% 60%',\r\n radius: '1.25rem', // Bordes muy redondeados\r\n spacing3: '1rem', // 16px - gaps más amplios\r\n spacing5: '1.25rem', // 20px - padding generoso\r\n },\r\n}\r\n\r\n/**\r\n * TEMA MIDNIGHT - Negro Premium\r\n * Diseño oscuro y minimalista de alto contraste\r\n */\r\nexport const MIDNIGHT_THEME: ChatTheme = {\r\n primaryColor: 'hsl(0, 0%, 100%)',\r\n botName: 'Midnight AI',\r\n welcomeMessage: 'Hello.',\r\n inputPlaceholder: 'Type a message...',\r\n cssVariables: {\r\n background: '0 0% 7%',\r\n foreground: '0 0% 98%',\r\n card: '0 0% 10%',\r\n cardForeground: '0 0% 98%',\r\n primary: '0 0% 100%',\r\n primaryForeground: '0 0% 0%',\r\n muted: '0 0% 15%',\r\n mutedForeground: '0 0% 70%',\r\n border: '0 0% 20%',\r\n destructive: '0 84% 60%',\r\n radius: '0.25rem', // Bordes cuadrados\r\n spacing1: '0.125rem', // 2px - muy compacto\r\n spacing2: '0.25rem', // 4px\r\n spacing3: '0.5rem', // 8px\r\n spacing5: '0.625rem', // 10px - muy compacto\r\n },\r\n}\r\n\r\n/**\r\n * TEMA NATURE - Verde Bosque\r\n * Diseño natural y relajante\r\n */\r\nexport const NATURE_THEME: ChatTheme = {\r\n primaryColor: 'hsl(142, 71%, 45%)',\r\n botName: 'Nature Guide',\r\n welcomeMessage: '🌿 ¡Hola! ¿En qué puedo asistirte?',\r\n cssVariables: {\r\n background: '140 30% 97%',\r\n foreground: '140 40% 15%',\r\n card: '140 25% 95%',\r\n cardForeground: '140 40% 15%',\r\n primary: '142 71% 45%',\r\n primaryForeground: '0 0% 100%',\r\n muted: '140 20% 92%',\r\n mutedForeground: '140 15% 35%',\r\n border: '140 20% 85%',\r\n destructive: '0 84% 60%',\r\n radius: '0.875rem',\r\n },\r\n}\r\n\r\n/**\r\n * ===================================\r\n * UTILIDADES\r\n * ===================================\r\n */\r\n\r\n/**\r\n * Sistema de Merge de Temas con Prioridades\r\n *\r\n * PRIORIDAD (de mayor a menor):\r\n * 1. Tema del proyecto (userTheme) - Lo que el usuario define en su código\r\n * 2. Tema del socket (socketTheme) - Lo que viene de la API/configuración remota\r\n * 3. Tema por defecto (DEFAULT_THEME) - Valores fallback\r\n *\r\n * El merge es PROFUNDO para cssVariables, garantizando que cada propiedad\r\n * individual se complete con su fallback correspondiente.\r\n */\r\nexport function mergeThemeWithDefaults(\r\n userTheme?: Partial<ChatTheme>,\r\n socketTheme?: Partial<ChatTheme>\r\n): Required<\r\n Omit<\r\n ChatTheme,\r\n | 'avatars'\r\n | 'emotion'\r\n | 'starterPrompt'\r\n | 'launcherBorderRadius'\r\n | 'borderRadius'\r\n | 'bubbleStyles'\r\n | 'promptPersistence'\r\n | 'avatarScale'\r\n | 'showPromptAvatar'\r\n | 'height'\r\n | 'bottom'\r\n | 'defaultLocale'\r\n | 'animations'\r\n | 'effects'\r\n | 'avatar3dUrl'\r\n >\r\n> {\r\n // Merge de cssVariables con prioridad: user > socket > default\r\n const mergedCssVariables: CSSVariables = {\r\n ...DEFAULT_CSS_VARIABLES,\r\n ...(socketTheme?.cssVariables || {}),\r\n ...(userTheme?.cssVariables || {}),\r\n }\r\n\r\n return {\r\n primaryColor:\r\n userTheme?.primaryColor || socketTheme?.primaryColor || DEFAULT_THEME.primaryColor,\r\n botName: userTheme?.botName || socketTheme?.botName || DEFAULT_THEME.botName,\r\n logoUrl: userTheme?.logoUrl || socketTheme?.logoUrl || DEFAULT_THEME.logoUrl,\r\n position: userTheme?.position || socketTheme?.position || DEFAULT_THEME.position,\r\n welcomeMessage:\r\n userTheme?.welcomeMessage || socketTheme?.welcomeMessage || DEFAULT_THEME.welcomeMessage,\r\n inputPlaceholder:\r\n userTheme?.inputPlaceholder ||\r\n socketTheme?.inputPlaceholder ||\r\n DEFAULT_THEME.inputPlaceholder,\r\n cssVariables: mergedCssVariables,\r\n isHidden: userTheme?.isHidden ?? socketTheme?.isHidden ?? false,\r\n }\r\n}\r\n\r\n/**\r\n * Obtiene el color primario con fallback\r\n */\r\nexport function getPrimaryColor(options: { primaryColor?: string }): string {\r\n return options.primaryColor || DEFAULT_THEME.primaryColor\r\n}\r\n\r\n/**\r\n * Convierte variables CSS a un objeto de estilos inline\r\n */\r\nexport function cssVariablesToInlineStyles(\r\n variables: Partial<CSSVariables>\r\n): Record<string, string> {\r\n const merged = { ...DEFAULT_CSS_VARIABLES, ...variables }\r\n return {\r\n '--background': merged.background,\r\n '--foreground': merged.foreground,\r\n '--card': merged.card,\r\n '--card-foreground': merged.cardForeground,\r\n '--primary': merged.primary,\r\n '--primary-foreground': merged.primaryForeground,\r\n '--muted': merged.muted,\r\n '--muted-foreground': merged.mutedForeground,\r\n '--border': merged.border,\r\n '--destructive': merged.destructive,\r\n '--radius': merged.radius,\r\n }\r\n}\r\n\r\n/**\r\n * Genera estilos de color sólidos desde variables CSS\r\n */\r\nexport function getSolidStyles(variables?: Partial<CSSVariables>) {\r\n const vars = { ...DEFAULT_CSS_VARIABLES, ...variables }\r\n return {\r\n background: `hsl(${vars.background})`,\r\n foreground: `hsl(${vars.foreground})`,\r\n card: `hsl(${vars.card})`,\r\n cardForeground: `hsl(${vars.cardForeground})`,\r\n primary: `hsl(${vars.primary})`,\r\n primaryForeground: `hsl(${vars.primaryForeground})`,\r\n muted: `hsl(${vars.muted})`,\r\n mutedForeground: `hsl(${vars.mutedForeground})`,\r\n border: `hsl(${vars.border})`,\r\n destructive: `hsl(${vars.destructive})`,\r\n }\r\n}\r\n\r\n/**\r\n * Retorna el tema completo con fallbacks aplicados\r\n */\r\nexport function getMergedTheme(theme: ChatTheme = {}): ChatTheme {\r\n return theme\r\n}\r\n","'use client'\r\n\r\nimport { createContext, useContext, useMemo, type ReactNode } from 'react'\r\nimport type { AnimationConfig, EffectsConfig } from '../types'\r\n\r\n/**\r\n * Default animation configuration - all premium features enabled\r\n */\r\nexport const defaultAnimationConfig: Required<AnimationConfig> = {\r\n enabled: true,\r\n messageEntry: 'spring',\r\n typingIndicator: 'wave',\r\n buttonEffects: true,\r\n smoothScroll: true,\r\n speedMultiplier: 1,\r\n staggerDelay: 50,\r\n windowTransitions: true,\r\n launcherPulse: true,\r\n}\r\n\r\n/**\r\n * Default effects configuration - premium effects enabled\r\n */\r\nexport const defaultEffectsConfig: Required<EffectsConfig> = {\r\n glassmorphism: true,\r\n gradients: true,\r\n softShadows: true,\r\n glowEffects: true,\r\n particles: false, // Off by default for performance\r\n soundEffects: false, // Off by default for accessibility\r\n hapticFeedback: true,\r\n shimmerLoading: true,\r\n hoverLift: true,\r\n}\r\n\r\n// -- Contexts --\r\nconst AnimationContext = createContext<Required<AnimationConfig>>(defaultAnimationConfig)\r\nconst EffectsContext = createContext<Required<EffectsConfig>>(defaultEffectsConfig)\r\n\r\nexport interface PremiumConfigProviderProps {\r\n children: ReactNode\r\n animations?: AnimationConfig\r\n effects?: EffectsConfig\r\n}\r\n\r\n/**\r\n * Provider for premium animation and effects configuration\r\n * Wraps components to give them access to animation/effects settings\r\n */\r\nexport function PremiumConfigProvider({\r\n children,\r\n animations,\r\n effects,\r\n}: PremiumConfigProviderProps) {\r\n // Merge with defaults\r\n const animationValue = useMemo(\r\n () => ({\r\n ...defaultAnimationConfig,\r\n ...animations,\r\n }),\r\n [animations]\r\n )\r\n\r\n const effectsValue = useMemo(\r\n () => ({\r\n ...defaultEffectsConfig,\r\n ...effects,\r\n }),\r\n [effects]\r\n )\r\n\r\n return (\r\n <AnimationContext.Provider value={animationValue}>\r\n <EffectsContext.Provider value={effectsValue}>\r\n {children}\r\n </EffectsContext.Provider>\r\n </AnimationContext.Provider>\r\n )\r\n}\r\n\r\n// -- Hooks --\r\n\r\n/**\r\n * Access animation configuration\r\n * @returns Current animation config with all defaults applied\r\n */\r\nexport function useAnimations(): Required<AnimationConfig> {\r\n return useContext(AnimationContext)\r\n}\r\n\r\n/**\r\n * Access effects configuration\r\n * @returns Current effects config with all defaults applied\r\n */\r\nexport function useEffects(): Required<EffectsConfig> {\r\n return useContext(EffectsContext)\r\n}\r\n\r\n/**\r\n * Check if animations are globally enabled\r\n */\r\nexport function useAnimationsEnabled(): boolean {\r\n const config = useContext(AnimationContext)\r\n return config.enabled\r\n}\r\n\r\n/**\r\n * Get animation duration with speed multiplier applied\r\n * @param baseDuration - Base duration in ms\r\n * @returns Adjusted duration\r\n */\r\nexport function useAnimationDuration(baseDuration: number): number {\r\n const config = useContext(AnimationContext)\r\n if (!config.enabled) return 0\r\n return baseDuration * config.speedMultiplier\r\n}\r\n\r\n/**\r\n * Get CSS class for message entry animation based on config\r\n */\r\nexport function useMessageEntryClass(): string {\r\n const config = useContext(AnimationContext)\r\n if (!config.enabled || config.messageEntry === 'none') return ''\r\n \r\n const classMap: Record<string, string> = {\r\n slide: 'animate-message-slide',\r\n fade: 'animate-message-fade',\r\n scale: 'animate-message-scale',\r\n spring: 'animate-message-spring',\r\n }\r\n \r\n return classMap[config.messageEntry] || 'animate-message-spring'\r\n}\r\n\r\n/**\r\n * Get CSS class for typing indicator animation based on config\r\n */\r\nexport function useTypingIndicatorClass(): string {\r\n const config = useContext(AnimationContext)\r\n if (!config.enabled || config.typingIndicator === 'none') return ''\r\n \r\n const classMap: Record<string, string> = {\r\n dots: 'animate-typing-dots',\r\n wave: 'animate-typing-wave',\r\n pulse: 'animate-typing-pulse',\r\n }\r\n \r\n return classMap[config.typingIndicator] || 'animate-typing-wave'\r\n}\r\n\r\n/**\r\n * Get stagger delay for sequential animations\r\n * @param index - Item index in sequence\r\n * @returns Delay in ms\r\n */\r\nexport function useStaggerDelay(index: number): number {\r\n const config = useContext(AnimationContext)\r\n if (!config.enabled) return 0\r\n return index * config.staggerDelay * config.speedMultiplier\r\n}\r\n\r\n/**\r\n * Hook for applying premium effects based on config\r\n */\r\nexport function usePremiumEffects() {\r\n const effects = useContext(EffectsContext)\r\n \r\n return {\r\n // Class generators\r\n getGlassClass: () => effects.glassmorphism ? 'backdrop-blur-md bg-white/80 dark:bg-black/80' : '',\r\n getShadowClass: () => effects.softShadows ? 'shadow-soft-xl' : 'shadow-md',\r\n getGlowClass: () => effects.glowEffects ? 'hover:shadow-primary/20' : '',\r\n getHoverLiftClass: () => effects.hoverLift ? 'hover:-translate-y-1 hover:shadow-lg transition-all' : '',\r\n getGradientClass: () => effects.gradients ? 'bg-gradient-to-br from-primary/10 to-transparent' : '',\r\n getShimmerClass: () => effects.shimmerLoading ? 'animate-shimmer' : 'animate-pulse',\r\n \r\n // Actions\r\n triggerHaptic: () => {\r\n if (effects.hapticFeedback && 'vibrate' in navigator) {\r\n navigator.vibrate(10)\r\n }\r\n },\r\n playSound: (type: 'send' | 'receive' | 'notification') => {\r\n if (!effects.soundEffects) return\r\n // Sound effects would be implemented here\r\n console.log(`[Sound] ${type}`)\r\n },\r\n triggerParticles: (element: HTMLElement) => {\r\n if (!effects.particles) return\r\n // Particle effect would be implemented here\r\n console.log('[Particles] triggered on', element)\r\n },\r\n }\r\n}\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * Centralized logger with DEBUG flag for production builds\r\n *\r\n * Principio: Single Responsibility - solo gestionar logging\r\n */\r\n\r\ninterface Logger {\r\n log: (message: string, ...args: any[]) => void\r\n warn: (message: string, ...args: any[]) => void\r\n error: (message: string, ...args: any[]) => void\r\n debug: (message: string, ...args: any[]) => void\r\n info: (message: string, ...args: any[]) => void\r\n}\r\n\r\n/**\r\n * Determina si el modo DEBUG está activo\r\n * - En desarrollo: siempre activo\r\n * - En producción: solo si window.DEBUG = true\r\n */\r\nfunction isDebugEnabled(): boolean {\r\n if (typeof window === 'undefined') return false\r\n\r\n // Modo desarrollo (verificar modo DEV de Vite)\r\n const isDev = typeof import.meta !== 'undefined' && (import.meta as any).env?.DEV === true\r\n\r\n if (isDev) return true\r\n\r\n // Producción: verificar flag global\r\n return !!(window as any).DEBUG\r\n}\r\n\r\n/**\r\n * Logger centralizado con control de DEBUG\r\n *\r\n * Uso:\r\n * - import { logger } from '@/chat-widget/utils/logger'\r\n * - logger.log('[Component]', 'mensaje')\r\n * - logger.error('[Error]', error)\r\n *\r\n * Habilitar en producción:\r\n * - window.DEBUG = true (en consola del navegador)\r\n */\r\nexport const logger: Logger = {\r\n log: (message: string, ...args: any[]) => {\r\n if (isDebugEnabled()) {\r\n console.log(`[BotUyo] ${message}`, ...args)\r\n }\r\n },\r\n\r\n warn: (message: string, ...args: any[]) => {\r\n if (isDebugEnabled()) {\r\n console.warn(`[BotUyo] ${message}`, ...args)\r\n }\r\n },\r\n\r\n error: (message: string, ...args: any[]) => {\r\n // Errores siempre se muestran\r\n console.error(`[BotUyo] ${message}`, ...args)\r\n },\r\n\r\n debug: (message: string, ...args: any[]) => {\r\n if (isDebugEnabled()) {\r\n console.debug(`[BotUyo] ${message}`, ...args)\r\n }\r\n },\r\n\r\n info: (message: string, ...args: any[]) => {\r\n if (isDebugEnabled()) {\r\n console.info(`[BotUyo] ${message}`, ...args)\r\n }\r\n },\r\n}\r\n\r\n/**\r\n * Alternativa silenciosa para testing\r\n */\r\nexport const silentLogger: Logger = {\r\n log: () => {},\r\n warn: () => {},\r\n error: () => {},\r\n debug: () => {},\r\n info: () => {},\r\n}\r\n","/**\n * @package @botuyo/chat-widget\n * Default assets bundled inline to avoid external dependencies\n *\n * These are fallback values when the client doesn't provide custom assets.\n * All assets are embedded as data URLs or inline content to work regardless\n * of the hosting environment.\n */\n\n/**\n * Default bot avatar as an inline SVG data URL\n * Simple friendly bot icon in a circular format\n */\nexport const DEFAULT_AVATAR_URL = `data:image/svg+xml,${encodeURIComponent(`\n<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" width=\"64\" height=\"64\">\n <defs>\n <linearGradient id=\"bg\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" style=\"stop-color:#10b981\"/>\n <stop offset=\"100%\" style=\"stop-color:#059669\"/>\n </linearGradient>\n </defs>\n <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"url(#bg)\"/>\n <rect x=\"16\" y=\"20\" width=\"32\" height=\"24\" rx=\"4\" fill=\"white\"/>\n <circle cx=\"24\" cy=\"30\" r=\"3\" fill=\"#10b981\"/>\n <circle cx=\"40\" cy=\"30\" r=\"3\" fill=\"#10b981\"/>\n <rect x=\"22\" y=\"36\" width=\"20\" height=\"3\" rx=\"1.5\" fill=\"#10b981\"/>\n <rect x=\"28\" y=\"12\" width=\"8\" height=\"8\" rx=\"2\" fill=\"white\"/>\n</svg>\n`)}`\n\n/**\n * Notification sound as base64-encoded WAV\n * Simple short \"ding\" sound (minimal file size)\n * Generated programmatically - a brief 440Hz tone\n */\nexport const DEFAULT_NOTIFICATION_SOUND_URL = createNotificationSoundDataUrl()\n\n/**\n * Creates a simple notification beep sound as a data URL\n * Uses Web Audio API compatible format\n */\nfunction createNotificationSoundDataUrl(): string {\n // Simple WAV header + 440Hz sine wave for 150ms at 8kHz sample rate\n // This creates a ~1.2KB audio file\n const sampleRate = 8000\n const duration = 0.15\n const frequency = 880 // Higher pitched, pleasant \"ding\"\n const numSamples = Math.floor(sampleRate * duration)\n\n // WAV file structure\n const bytesPerSample = 2\n const dataSize = numSamples * bytesPerSample\n const fileSize = 44 + dataSize\n\n const buffer = new ArrayBuffer(fileSize)\n const view = new DataView(buffer)\n\n // RIFF header\n writeString(view, 0, 'RIFF')\n view.setUint32(4, fileSize - 8, true)\n writeString(view, 8, 'WAVE')\n\n // fmt chunk\n writeString(view, 12, 'fmt ')\n view.setUint32(16, 16, true) // chunk size\n view.setUint16(20, 1, true) // PCM format\n view.setUint16(22, 1, true) // mono\n view.setUint32(24, sampleRate, true)\n view.setUint32(28, sampleRate * bytesPerSample, true) // byte rate\n view.setUint16(32, bytesPerSample, true) // block align\n view.setUint16(34, 16, true) // bits per sample\n\n // data chunk\n writeString(view, 36, 'data')\n view.setUint32(40, dataSize, true)\n\n // Generate sine wave with fade out\n for (let i = 0; i < numSamples; i++) {\n const t = i / sampleRate\n const fadeOut = 1 - i / numSamples // Linear fade out\n const sample = Math.sin(2 * Math.PI * frequency * t) * fadeOut * 0.5 * 32767\n view.setInt16(44 + i * bytesPerSample, sample, true)\n }\n\n // Convert to base64\n const bytes = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i])\n }\n\n return `data:audio/wav;base64,${btoa(binary)}`\n}\n\nfunction writeString(view: DataView, offset: number, string: string): void {\n for (let i = 0; i < string.length; i++) {\n view.setUint8(offset + i, string.charCodeAt(i))\n }\n}\n","function memo(getDeps, fn, opts) {\n let deps = opts.initialDeps ?? [];\n let result;\n let isInitial = true;\n function memoizedFunction() {\n var _a, _b, _c;\n let depTime;\n if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();\n const newDeps = getDeps();\n const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);\n if (!depsChanged) {\n return result;\n }\n deps = newDeps;\n let resultTime;\n if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();\n result = fn(...newDeps);\n if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {\n const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;\n const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;\n const resultFpsPercentage = resultEndTime / 16;\n const pad = (str, num) => {\n str = String(str);\n while (str.length < num) {\n str = \" \" + str;\n }\n return str;\n };\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120)\n )}deg 100% 31%);`,\n opts == null ? void 0 : opts.key\n );\n }\n if ((opts == null ? void 0 : opts.onChange) && !(isInitial && opts.skipInitialOnChange)) {\n opts.onChange(result);\n }\n isInitial = false;\n return result;\n }\n memoizedFunction.updateDeps = (newDeps) => {\n deps = newDeps;\n };\n return memoizedFunction;\n}\nfunction notUndefined(value, msg) {\n if (value === void 0) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : \"\"}`);\n } else {\n return value;\n }\n}\nconst approxEqual = (a, b) => Math.abs(a - b) < 1.01;\nconst debounce = (targetWindow, fn, ms) => {\n let timeoutId;\n return function(...args) {\n targetWindow.clearTimeout(timeoutId);\n timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);\n };\n};\nexport {\n approxEqual,\n debounce,\n memo,\n notUndefined\n};\n//# sourceMappingURL=utils.js.map\n","import { debounce, memo, notUndefined, approxEqual } from \"./utils.js\";\nconst getRect = (element) => {\n const { offsetWidth, offsetHeight } = element;\n return { width: offsetWidth, height: offsetHeight };\n};\nconst defaultKeyExtractor = (index) => index;\nconst defaultRangeExtractor = (range) => {\n const start = Math.max(range.startIndex - range.overscan, 0);\n const end = Math.min(range.endIndex + range.overscan, range.count - 1);\n const arr = [];\n for (let i = start; i <= end; i++) {\n arr.push(i);\n }\n return arr;\n};\nconst observeElementRect = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n const handler = (rect) => {\n const { width, height } = rect;\n cb({ width: Math.round(width), height: Math.round(height) });\n };\n handler(getRect(element));\n if (!targetWindow.ResizeObserver) {\n return () => {\n };\n }\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\n const entry = entries[0];\n if (entry == null ? void 0 : entry.borderBoxSize) {\n const box = entry.borderBoxSize[0];\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize });\n return;\n }\n }\n handler(getRect(element));\n };\n instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();\n });\n observer.observe(element, { box: \"border-box\" });\n return () => {\n observer.unobserve(element);\n };\n};\nconst addEventListenerOptions = {\n passive: true\n};\nconst observeWindowRect = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight });\n };\n handler();\n element.addEventListener(\"resize\", handler, addEventListenerOptions);\n return () => {\n element.removeEventListener(\"resize\", handler);\n };\n};\nconst supportsScrollend = typeof window == \"undefined\" ? true : \"onscrollend\" in window;\nconst observeElementOffset = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n let offset = 0;\n const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(\n targetWindow,\n () => {\n cb(offset, false);\n },\n instance.options.isScrollingResetDelay\n );\n const createHandler = (isScrolling) => () => {\n const { horizontal, isRtl } = instance.options;\n offset = horizontal ? element[\"scrollLeft\"] * (isRtl && -1 || 1) : element[\"scrollTop\"];\n fallback();\n cb(offset, isScrolling);\n };\n const handler = createHandler(true);\n const endHandler = createHandler(false);\n element.addEventListener(\"scroll\", handler, addEventListenerOptions);\n const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;\n if (registerScrollendEvent) {\n element.addEventListener(\"scrollend\", endHandler, addEventListenerOptions);\n }\n return () => {\n element.removeEventListener(\"scroll\", handler);\n if (registerScrollendEvent) {\n element.removeEventListener(\"scrollend\", endHandler);\n }\n };\n};\nconst observeWindowOffset = (instance, cb) => {\n const element = instance.scrollElement;\n if (!element) {\n return;\n }\n const targetWindow = instance.targetWindow;\n if (!targetWindow) {\n return;\n }\n let offset = 0;\n const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(\n targetWindow,\n () => {\n cb(offset, false);\n },\n instance.options.isScrollingResetDelay\n );\n const createHandler = (isScrolling) => () => {\n offset = element[instance.options.horizontal ? \"scrollX\" : \"scrollY\"];\n fallback();\n cb(offset, isScrolling);\n };\n const handler = createHandler(true);\n const endHandler = createHandler(false);\n element.addEventListener(\"scroll\", handler, addEventListenerOptions);\n const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;\n if (registerScrollendEvent) {\n element.addEventListener(\"scrollend\", endHandler, addEventListenerOptions);\n }\n return () => {\n element.removeEventListener(\"scroll\", handler);\n if (registerScrollendEvent) {\n element.removeEventListener(\"scrollend\", endHandler);\n }\n };\n};\nconst measureElement = (element, entry, instance) => {\n if (entry == null ? void 0 : entry.borderBoxSize) {\n const box = entry.borderBoxSize[0];\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? \"inlineSize\" : \"blockSize\"]\n );\n return size;\n }\n }\n return element[instance.options.horizontal ? \"offsetWidth\" : \"offsetHeight\"];\n};\nconst windowScroll = (offset, {\n adjustments = 0,\n behavior\n}, instance) => {\n var _a, _b;\n const toOffset = offset + adjustments;\n (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {\n [instance.options.horizontal ? \"left\" : \"top\"]: toOffset,\n behavior\n });\n};\nconst elementScroll = (offset, {\n adjustments = 0,\n behavior\n}, instance) => {\n var _a, _b;\n const toOffset = offset + adjustments;\n (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {\n [instance.options.horizontal ? \"left\" : \"top\"]: toOffset,\n behavior\n });\n};\nclass Virtualizer {\n constructor(opts) {\n this.unsubs = [];\n this.scrollElement = null;\n this.targetWindow = null;\n this.isScrolling = false;\n this.currentScrollToIndex = null;\n this.measurementsCache = [];\n this.itemSizeCache = /* @__PURE__ */ new Map();\n this.laneAssignments = /* @__PURE__ */ new Map();\n this.pendingMeasuredCacheIndexes = [];\n this.prevLanes = void 0;\n this.lanesChangedFlag = false;\n this.lanesSettling = false;\n this.scrollRect = null;\n this.scrollOffset = null;\n this.scrollDirection = null;\n this.scrollAdjustments = 0;\n this.elementsCache = /* @__PURE__ */ new Map();\n this.observer = /* @__PURE__ */ (() => {\n let _ro = null;\n const get = () => {\n if (_ro) {\n return _ro;\n }\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null;\n }\n return _ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n this._measureElement(entry.target, entry);\n };\n this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();\n });\n });\n };\n return {\n disconnect: () => {\n var _a;\n (_a = get()) == null ? void 0 : _a.disconnect();\n _ro = null;\n },\n observe: (target) => {\n var _a;\n return (_a = get()) == null ? void 0 : _a.observe(target, { box: \"border-box\" });\n },\n unobserve: (target) => {\n var _a;\n return (_a = get()) == null ? void 0 : _a.unobserve(target);\n }\n };\n })();\n this.range = null;\n this.setOptions = (opts2) => {\n Object.entries(opts2).forEach(([key, value]) => {\n if (typeof value === \"undefined\") delete opts2[key];\n });\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {\n },\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n gap: 0,\n indexAttribute: \"data-index\",\n initialMeasurementsCache: [],\n lanes: 1,\n isScrollingResetDelay: 150,\n enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\n ...opts2\n };\n };\n this.notify = (sync) => {\n var _a, _b;\n (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);\n };\n this.maybeNotify = memo(\n () => {\n this.calculateRange();\n return [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null\n ];\n },\n (isScrolling) => {\n this.notify(isScrolling);\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"maybeNotify\",\n debug: () => this.options.debug,\n initialDeps: [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null\n ]\n }\n );\n this.cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d());\n this.unsubs = [];\n this.observer.disconnect();\n this.scrollElement = null;\n this.targetWindow = null;\n };\n this._didMount = () => {\n return () => {\n this.cleanup();\n };\n };\n this._willUpdate = () => {\n var _a;\n const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;\n if (this.scrollElement !== scrollElement) {\n this.cleanup();\n if (!scrollElement) {\n this.maybeNotify();\n return;\n }\n this.scrollElement = scrollElement;\n if (this.scrollElement && \"ownerDocument\" in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView;\n } else {\n this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;\n }\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached);\n });\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect;\n this.maybeNotify();\n })\n );\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset, isScrolling) => {\n this.scrollAdjustments = 0;\n this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? \"forward\" : \"backward\" : null;\n this.scrollOffset = offset;\n this.isScrolling = isScrolling;\n this.maybeNotify();\n })\n );\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: void 0,\n behavior: void 0\n });\n }\n };\n this.getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null;\n return 0;\n }\n this.scrollRect = this.scrollRect ?? this.options.initialRect;\n return this.scrollRect[this.options.horizontal ? \"width\" : \"height\"];\n };\n this.getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null;\n return 0;\n }\n this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === \"function\" ? this.options.initialOffset() : this.options.initialOffset);\n return this.scrollOffset;\n };\n this.getFurthestMeasurement = (measurements, index) => {\n const furthestMeasurementsFound = /* @__PURE__ */ new Map();\n const furthestMeasurements = /* @__PURE__ */ new Map();\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m];\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue;\n }\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane\n );\n if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {\n furthestMeasurements.set(measurement.lane, measurement);\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true);\n }\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break;\n }\n }\n return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => {\n if (a.end === b.end) {\n return a.index - b.index;\n }\n return a.end - b.end;\n })[0] : void 0;\n };\n this.getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged = this.prevLanes !== void 0 && this.prevLanes !== lanes;\n if (lanesChanged) {\n this.lanesChangedFlag = true;\n }\n this.prevLanes = lanes;\n this.pendingMeasuredCacheIndexes = [];\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes\n };\n },\n {\n key: false\n }\n );\n this.getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey, enabled, lanes }, itemSizeCache) => {\n if (!enabled) {\n this.measurementsCache = [];\n this.itemSizeCache.clear();\n this.laneAssignments.clear();\n return [];\n }\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index);\n }\n }\n }\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false;\n this.lanesSettling = true;\n this.measurementsCache = [];\n this.itemSizeCache.clear();\n this.laneAssignments.clear();\n this.pendingMeasuredCacheIndexes = [];\n }\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache;\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size);\n });\n }\n const min = this.lanesSettling ? 0 : this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;\n this.pendingMeasuredCacheIndexes = [];\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false;\n }\n const measurements = this.measurementsCache.slice(0, min);\n const laneLastIndex = new Array(lanes).fill(\n void 0\n );\n for (let m = 0; m < min; m++) {\n const item = measurements[m];\n if (item) {\n laneLastIndex[item.lane] = m;\n }\n }\n for (let i = min; i < count; i++) {\n const key = getItemKey(i);\n const cachedLane = this.laneAssignments.get(i);\n let lane;\n let start;\n if (cachedLane !== void 0 && this.options.lanes > 1) {\n lane = cachedLane;\n const prevIndex = laneLastIndex[lane];\n const prevInLane = prevIndex !== void 0 ? measurements[prevIndex] : void 0;\n start = prevInLane ? prevInLane.end + this.options.gap : paddingStart + scrollMargin;\n } else {\n const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);\n start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;\n lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane);\n }\n }\n const measuredSize = itemSizeCache.get(key);\n const size = typeof measuredSize === \"number\" ? measuredSize : this.options.estimateSize(i);\n const end = start + size;\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane\n };\n laneLastIndex[lane] = i;\n }\n this.measurementsCache = measurements;\n return measurements;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getMeasurements\",\n debug: () => this.options.debug\n }\n );\n this.calculateRange = memo(\n () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes\n }) : null;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"calculateRange\",\n debug: () => this.options.debug\n }\n );\n this.getVirtualIndexes = memo(\n () => {\n let startIndex = null;\n let endIndex = null;\n const range = this.calculateRange();\n if (range) {\n startIndex = range.startIndex;\n endIndex = range.endIndex;\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex\n ];\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null ? [] : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count\n });\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getVirtualIndexes\",\n debug: () => this.options.debug\n }\n );\n this.indexFromElement = (node) => {\n const attributeName = this.options.indexAttribute;\n const indexStr = node.getAttribute(attributeName);\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`\n );\n return -1;\n }\n return parseInt(indexStr, 10);\n };\n this._measureElement = (node, entry) => {\n const index = this.indexFromElement(node);\n const item = this.measurementsCache[index];\n if (!item) {\n return;\n }\n const key = item.key;\n const prevNode = this.elementsCache.get(key);\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode);\n }\n this.observer.observe(node);\n this.elementsCache.set(key, node);\n }\n if (node.isConnected) {\n this.resizeItem(index, this.options.measureElement(node, entry, this));\n }\n };\n this.resizeItem = (index, size) => {\n const item = this.measurementsCache[index];\n if (!item) {\n return;\n }\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size;\n const delta = size - itemSize;\n if (delta !== 0) {\n if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {\n if (process.env.NODE_ENV !== \"production\" && this.options.debug) {\n console.info(\"correction\", delta);\n }\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: this.scrollAdjustments += delta,\n behavior: void 0\n });\n }\n this.pendingMeasuredCacheIndexes.push(item.index);\n this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));\n this.notify(false);\n }\n };\n this.measureElement = (node) => {\n if (!node) {\n this.elementsCache.forEach((cached, key) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached);\n this.elementsCache.delete(key);\n }\n });\n return;\n }\n this._measureElement(node, void 0);\n };\n this.getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems = [];\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k];\n const measurement = measurements[i];\n virtualItems.push(measurement);\n }\n return virtualItems;\n },\n {\n key: process.env.NODE_ENV !== \"production\" && \"getVirtualItems\",\n debug: () => this.options.debug\n }\n );\n this.getVirtualItemForOffset = (offset) => {\n const measurements = this.getMeasurements();\n if (measurements.length === 0) {\n return void 0;\n }\n return notUndefined(\n measurements[findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index) => notUndefined(measurements[index]).start,\n offset\n )]\n );\n };\n this.getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0;\n if (\"scrollHeight\" in this.scrollElement) {\n return this.options.horizontal ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth : this.scrollElement.scrollHeight - this.scrollElement.clientHeight;\n } else {\n const doc = this.scrollElement.document.documentElement;\n return this.options.horizontal ? doc.scrollWidth - this.scrollElement.innerWidth : doc.scrollHeight - this.scrollElement.innerHeight;\n }\n };\n this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {\n if (!this.scrollElement) return 0;\n const size = this.getSize();\n const scrollOffset = this.getScrollOffset();\n if (align === \"auto\") {\n align = toOffset >= scrollOffset + size ? \"end\" : \"start\";\n }\n if (align === \"center\") {\n toOffset += (itemSize - size) / 2;\n } else if (align === \"end\") {\n toOffset -= size;\n }\n const maxOffset = this.getMaxScrollOffset();\n return Math.max(Math.min(maxOffset, toOffset), 0);\n };\n this.getOffsetForIndex = (index, align = \"auto\") => {\n index = Math.max(0, Math.min(index, this.options.count - 1));\n const item = this.measurementsCache[index];\n if (!item) {\n return void 0;\n }\n const size = this.getSize();\n const scrollOffset = this.getScrollOffset();\n if (align === \"auto\") {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = \"end\";\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = \"start\";\n } else {\n return [scrollOffset, align];\n }\n }\n if (align === \"end\" && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align];\n }\n const toOffset = align === \"end\" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align\n ];\n };\n this.isDynamicMode = () => this.elementsCache.size > 0;\n this.scrollToOffset = (toOffset, { align = \"start\", behavior } = {}) => {\n if (behavior === \"smooth\" && this.isDynamicMode()) {\n console.warn(\n \"The `smooth` scroll behavior is not fully supported with dynamic size.\"\n );\n }\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: void 0,\n behavior\n });\n };\n this.scrollToIndex = (index, { align: initialAlign = \"auto\", behavior } = {}) => {\n if (behavior === \"smooth\" && this.isDynamicMode()) {\n console.warn(\n \"The `smooth` scroll behavior is not fully supported with dynamic size.\"\n );\n }\n index = Math.max(0, Math.min(index, this.options.count - 1));\n this.currentScrollToIndex = index;\n let attempts = 0;\n const maxAttempts = 10;\n const tryScroll = (currentAlign) => {\n if (!this.targetWindow) return;\n const offsetInfo = this.getOffsetForIndex(index, currentAlign);\n if (!offsetInfo) {\n console.warn(\"Failed to get offset for index:\", index);\n return;\n }\n const [offset, align] = offsetInfo;\n this._scrollToOffset(offset, { adjustments: void 0, behavior });\n this.targetWindow.requestAnimationFrame(() => {\n const verify = () => {\n if (this.currentScrollToIndex !== index) return;\n const currentOffset = this.getScrollOffset();\n const afterInfo = this.getOffsetForIndex(index, align);\n if (!afterInfo) {\n console.warn(\"Failed to get offset for index:\", index);\n return;\n }\n if (!approxEqual(afterInfo[0], currentOffset)) {\n scheduleRetry(align);\n }\n };\n if (this.isDynamicMode()) {\n this.targetWindow.requestAnimationFrame(verify);\n } else {\n verify();\n }\n });\n };\n const scheduleRetry = (align) => {\n if (!this.targetWindow) return;\n if (this.currentScrollToIndex !== index) return;\n attempts++;\n if (attempts < maxAttempts) {\n if (process.env.NODE_ENV !== \"production\" && this.options.debug) {\n console.info(\"Schedule retry\", attempts, maxAttempts);\n }\n this.targetWindow.requestAnimationFrame(() => tryScroll(align));\n } else {\n console.warn(\n `Failed to scroll to index ${index} after ${maxAttempts} attempts.`\n );\n }\n };\n tryScroll(initialAlign);\n };\n this.scrollBy = (delta, { behavior } = {}) => {\n if (behavior === \"smooth\" && this.isDynamicMode()) {\n console.warn(\n \"The `smooth` scroll behavior is not fully supported with dynamic size.\"\n );\n }\n this._scrollToOffset(this.getScrollOffset() + delta, {\n adjustments: void 0,\n behavior\n });\n };\n this.getTotalSize = () => {\n var _a;\n const measurements = this.getMeasurements();\n let end;\n if (measurements.length === 0) {\n end = this.options.paddingStart;\n } else if (this.options.lanes === 1) {\n end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;\n } else {\n const endByLane = Array(this.options.lanes).fill(null);\n let endIndex = measurements.length - 1;\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex];\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end;\n }\n endIndex--;\n }\n end = Math.max(...endByLane.filter((val) => val !== null));\n }\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0\n );\n };\n this._scrollToOffset = (offset, {\n adjustments,\n behavior\n }) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this);\n };\n this.measure = () => {\n this.itemSizeCache = /* @__PURE__ */ new Map();\n this.laneAssignments = /* @__PURE__ */ new Map();\n this.notify(false);\n };\n this.setOptions(opts);\n }\n}\nconst findNearestBinarySearch = (low, high, getCurrentValue, value) => {\n while (low <= high) {\n const middle = (low + high) / 2 | 0;\n const currentValue = getCurrentValue(middle);\n if (currentValue < value) {\n low = middle + 1;\n } else if (currentValue > value) {\n high = middle - 1;\n } else {\n return middle;\n }\n }\n if (low > 0) {\n return low - 1;\n } else {\n return 0;\n }\n};\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes\n}) {\n const lastIndex = measurements.length - 1;\n const getOffset = (index) => measurements[index].start;\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex\n };\n }\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset\n );\n let endIndex = startIndex;\n if (lanes === 1) {\n while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {\n endIndex++;\n }\n } else if (lanes > 1) {\n const endPerLane = Array(lanes).fill(0);\n while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {\n const item = measurements[endIndex];\n endPerLane[item.lane] = item.end;\n endIndex++;\n }\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize);\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex];\n startPerLane[item.lane] = item.start;\n startIndex--;\n }\n startIndex = Math.max(0, startIndex - startIndex % lanes);\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));\n }\n return { startIndex, endIndex };\n}\nexport {\n Virtualizer,\n approxEqual,\n debounce,\n defaultKeyExtractor,\n defaultRangeExtractor,\n elementScroll,\n measureElement,\n memo,\n notUndefined,\n observeElementOffset,\n observeElementRect,\n observeWindowOffset,\n observeWindowRect,\n windowScroll\n};\n//# sourceMappingURL=index.js.map\n","import * as React from \"react\";\nimport { flushSync } from \"react-dom\";\nimport { Virtualizer, elementScroll, observeElementOffset, observeElementRect, windowScroll, observeWindowOffset, observeWindowRect } from \"@tanstack/virtual-core\";\nexport * from \"@tanstack/virtual-core\";\nconst useIsomorphicLayoutEffect = typeof document !== \"undefined\" ? React.useLayoutEffect : React.useEffect;\nfunction useVirtualizerBase({\n useFlushSync = true,\n ...options\n}) {\n const rerender = React.useReducer(() => ({}), {})[1];\n const resolvedOptions = {\n ...options,\n onChange: (instance2, sync) => {\n var _a;\n if (useFlushSync && sync) {\n flushSync(rerender);\n } else {\n rerender();\n }\n (_a = options.onChange) == null ? void 0 : _a.call(options, instance2, sync);\n }\n };\n const [instance] = React.useState(\n () => new Virtualizer(resolvedOptions)\n );\n instance.setOptions(resolvedOptions);\n useIsomorphicLayoutEffect(() => {\n return instance._didMount();\n }, []);\n useIsomorphicLayoutEffect(() => {\n return instance._willUpdate();\n });\n return instance;\n}\nfunction useVirtualizer(options) {\n return useVirtualizerBase({\n observeElementRect,\n observeElementOffset,\n scrollToFn: elementScroll,\n ...options\n });\n}\nfunction useWindowVirtualizer(options) {\n return useVirtualizerBase({\n getScrollElement: () => typeof document !== \"undefined\" ? window : null,\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n initialOffset: () => typeof document !== \"undefined\" ? window.scrollY : 0,\n ...options\n });\n}\nexport {\n useVirtualizer,\n useWindowVirtualizer\n};\n//# sourceMappingURL=index.js.map\n","'use client'\r\n\r\nimport { useMemo, lazy, Suspense, memo } from 'react'\r\nimport { useTranslations } from '@/chat-widget/i18n'\r\nimport ReactMarkdown from 'react-markdown'\r\nimport remarkGfm from 'remark-gfm'\r\nimport rehypeSanitize from 'rehype-sanitize'\r\nimport { CheckCheck, MapPin, ExternalLink, ArrowRight, FileIcon, Download } from './Icons'\r\nimport { cn } from '@/lib/utils'\r\nimport { getPrimaryColor } from '../utils/theme'\r\nimport { useMessageEntryClass } from '../contexts/AnimationContext'\r\nimport type {\r\n ChatMessage,\r\n BubbleStyles,\r\n TextMessage,\r\n AudioMessage,\r\n ImageMessage,\r\n LocationMessage,\r\n FileMessage,\r\n} from '../types'\r\nimport type { EmotionAvatarMap } from './Launcher'\r\n\r\n// Lazy load componentes pesados\r\nconst AudioPlayer = lazy(() => import('./AudioPlayer').then(m => ({ default: m.AudioPlayer })))\r\nconst Gallery = lazy(() => import('./Gallery').then(m => ({ default: m.Gallery })))\r\n\r\nexport interface MessageBubbleProps {\r\n message: ChatMessage\r\n primaryColor?: string\r\n botAvatar?: string\r\n botName?: string\r\n styles?: BubbleStyles\r\n avatars?: EmotionAvatarMap\r\n isFirst?: boolean\r\n isLast?: boolean\r\n index?: number // For stagger animation\r\n}\r\n\r\nexport const MessageBubble = memo(\r\n function MessageBubble({\r\n message,\r\n primaryColor,\r\n botAvatar,\r\n botName = 'BotUyo',\r\n avatars,\r\n isFirst = true,\r\n isLast = true,\r\n index = 0,\r\n }: MessageBubbleProps) {\r\n const { t } = useTranslations('extracted')\r\n const isUser = message.sender === 'user'\r\n const isSystem = message.type === 'system' || message.sender === 'system'\r\n const isBot = !isUser && !isSystem\r\n\r\n const brandColor = getPrimaryColor({ primaryColor })\r\n \r\n // Premium animation hooks\r\n const messageEntryClass = useMessageEntryClass()\r\n // Note: usePremiumEffects available for future enhancements (hover lift, haptics, etc.)\r\n\r\n // --- AVATAR LOGIC ---\r\n const currentAvatar = useMemo(() => {\r\n if (isUser) return null\r\n if (message.type === 'text') {\r\n const textMsg = message as TextMessage\r\n if (textMsg.emotion && avatars?.[textMsg.emotion as keyof EmotionAvatarMap]) {\r\n return avatars[textMsg.emotion as keyof EmotionAvatarMap]\r\n }\r\n }\r\n return botAvatar\r\n }, [message, avatars, botAvatar, isUser])\r\n\r\n const formatTime = (date: Date | string) => {\r\n const dateObj = new Date(date)\r\n return isNaN(dateObj.getTime())\r\n ? ''\r\n : dateObj.toLocaleTimeString([], {\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n hour12: false,\r\n })\r\n }\r\n\r\n // --- RENDERERS FOR MARKDOWN ---\r\n const RenderLink = ({ href, children }: any) => {\r\n if (!href) return null\r\n const textContent = String(children).toLowerCase()\r\n const isCTA =\r\n textContent.includes('reservar') ||\r\n textContent.includes('ver') ||\r\n textContent.includes('pagar')\r\n const isGoogleMaps = href.includes('maps.google') || href.includes('goo.gl')\r\n\r\n if (isGoogleMaps) {\r\n return (\r\n <a\r\n href={href}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"block my-2 no-underline group\"\r\n >\r\n <span\r\n className=\"flex items-center gap-3 p-3 border rounded-xl shadow-sm group-hover:border-primary/30 transition-all\"\r\n style={{ backgroundColor: 'hsl(var(--card))', borderColor: 'hsl(var(--border))' }}\r\n >\r\n <span\r\n className=\"flex-shrink-0 p-2 rounded-full\"\r\n style={{ backgroundColor: `${brandColor}1a`, color: brandColor }}\r\n >\r\n <MapPin size={16} strokeWidth={2.5} />\r\n </span>\r\n <span className=\"flex flex-col min-w-0 flex-1 text-[11px] font-bold text-foreground leading-tight uppercase tracking-tight\">\r\n {t('ver_ubicacion')}\r\n </span>\r\n <ExternalLink\r\n size={12}\r\n className=\"text-muted-foreground/40 group-hover:text-primary\"\r\n />\r\n </span>\r\n </a>\r\n )\r\n }\r\n\r\n if (isCTA) {\r\n return (\r\n <a\r\n href={href}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"inline-flex items-center justify-center gap-2 px-5 py-2.5 mt-2 text-[11px] font-black w-full sm:w-auto rounded-xl shadow-md uppercase tracking-widest transition-transform active:scale-95 text-white\"\r\n style={{ backgroundColor: brandColor }}\r\n >\r\n {children} <ArrowRight size={14} />\r\n </a>\r\n )\r\n }\r\n\r\n return (\r\n <a\r\n href={href}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"font-bold underline decoration-primary/30 hover:decoration-primary transition-all\"\r\n style={{ color: isUser ? 'inherit' : brandColor }}\r\n >\r\n {children}\r\n </a>\r\n )\r\n }\r\n\r\n const RenderImage = ({ src, alt }: any) => {\r\n if (!src) return null\r\n return (\r\n <Suspense\r\n fallback={\r\n <div className=\"my-3 animate-pulse\">\r\n <div className=\"w-full h-48 bg-muted rounded-xl\" />\r\n </div>\r\n }\r\n >\r\n <Gallery images={[{ src, alt }]} radius=\"rounded-xl\" />\r\n </Suspense>\r\n )\r\n }\r\n\r\n // --- CONTENT SWITCHER ---\r\n const renderContent = () => {\r\n switch (message.type) {\r\n case 'audio':\r\n return (\r\n <Suspense\r\n fallback={\r\n <div className=\"flex items-center gap-3 py-1 min-w-[200px] animate-pulse\">\r\n <div className=\"w-8 h-8 rounded-full bg-muted\" />\r\n <div className=\"flex-1 space-y-1\">\r\n <div className=\"h-1 w-full bg-muted rounded-full\" />\r\n </div>\r\n </div>\r\n }\r\n >\r\n <AudioPlayer\r\n url={(message as AudioMessage).content}\r\n isBot={isBot}\r\n primaryColor={primaryColor}\r\n />\r\n </Suspense>\r\n )\r\n\r\n case 'image': {\r\n const imgMsg = message as ImageMessage\r\n return (\r\n <Suspense\r\n fallback={\r\n <div className=\"my-3 animate-pulse\">\r\n <div className=\"w-full h-48 bg-muted rounded-xl\" />\r\n </div>\r\n }\r\n >\r\n <Gallery\r\n images={[\r\n {\r\n src: imgMsg.imageUrl || (imgMsg as any).content,\r\n alt: imgMsg.altText || 'Imagen',\r\n },\r\n ]}\r\n radius=\"rounded-xl\"\r\n />\r\n </Suspense>\r\n )\r\n }\r\n\r\n case 'location': {\r\n const locMsg = message as LocationMessage\r\n return (\r\n <RenderLink\r\n href={`https://www.google.com/maps/search/?api=1&query=${locMsg.latitude},${locMsg.longitude}`}\r\n >\r\n Ver ubicación\r\n </RenderLink>\r\n )\r\n }\r\n\r\n case 'file': {\r\n const fileMsg = message as FileMessage\r\n const fileExtension = fileMsg.fileName?.split('.').pop()?.toLowerCase() || ''\r\n const fileSize = fileMsg.fileSize\r\n ? `${(fileMsg.fileSize / 1024 / 1024).toFixed(2)} MB`\r\n : ''\r\n\r\n return (\r\n <a\r\n href={fileMsg.fileUrl}\r\n download={fileMsg.fileName}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"flex items-center gap-3 p-3 border rounded-xl transition-all hover:scale-[1.02] group\"\r\n style={{\r\n backgroundColor: isUser ? 'rgba(255,255,255,0.1)' : 'hsl(var(--muted))',\r\n borderColor: isUser ? 'rgba(255,255,255,0.2)' : 'hsl(var(--border))',\r\n }}\r\n >\r\n <div\r\n className=\"flex items-center justify-center w-10 h-10 rounded-lg shrink-0\"\r\n style={{\r\n backgroundColor: isUser ? 'rgba(255,255,255,0.2)' : `${brandColor}1a`,\r\n color: isUser ? 'white' : brandColor,\r\n }}\r\n >\r\n <FileIcon size={20} strokeWidth={2.5} />\r\n </div>\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"text-sm font-bold truncate\">{fileMsg.fileName}</p>\r\n {fileSize && (\r\n <p className=\"text-xs opacity-60 mt-0.5\">\r\n {fileExtension?.toUpperCase()} • {fileSize}\r\n </p>\r\n )}\r\n </div>\r\n <Download\r\n size={18}\r\n className=\"shrink-0 opacity-60 group-hover:opacity-100 transition-opacity\"\r\n />\r\n </a>\r\n )\r\n }\r\n\r\n default:\r\n return (\r\n <div\r\n className={cn(\r\n 'prose prose-sm max-w-none break-words leading-relaxed dark:prose-invert',\r\n isUser ? 'text-primary-foreground prose-p:text-white' : 'text-foreground'\r\n )}\r\n >\r\n <ReactMarkdown\r\n remarkPlugins={[remarkGfm]}\r\n rehypePlugins={[\r\n [\r\n rehypeSanitize,\r\n {\r\n tagNames: ['p', 'a', 'img', 'strong', 'em', 'ul', 'ol', 'li', 'br', 'span'],\r\n attributes: {\r\n a: ['href', 'target', 'rel'],\r\n img: ['src', 'alt'],\r\n span: ['className'],\r\n },\r\n protocols: {\r\n a: { href: ['http', 'https', 'mailto', 'tel'] },\r\n img: { src: ['http', 'https', 'data'] },\r\n },\r\n },\r\n ],\r\n ]}\r\n components={{\r\n a: RenderLink,\r\n img: RenderImage,\r\n p: ({ children }) => <p className=\"mb-0 last:mb-0\">{children}</p>,\r\n }}\r\n >\r\n {(message as TextMessage).content || ''}\r\n </ReactMarkdown>\r\n </div>\r\n )\r\n }\r\n }\r\n\r\n if (isSystem) {\r\n return (\r\n <div className=\"flex justify-center my-4 animate-in fade-in zoom-in-95 w-full\">\r\n <span\r\n className=\"px-3 py-1 border rounded-full text-[9px] font-black uppercase tracking-widest\"\r\n style={{\r\n backgroundColor: 'hsl(var(--muted))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--muted-foreground))',\r\n }}\r\n >\r\n {(message as TextMessage).content}\r\n </span>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n 'flex w-full mb-0.5 group',\r\n messageEntryClass, // Configurable animation\r\n isUser ? 'justify-end' : 'justify-start gap-3',\r\n isFirst && 'mt-3',\r\n isLast && 'mb-3'\r\n )}\r\n style={{\r\n animationDelay: `${index * 50}ms`,\r\n }}\r\n >\r\n {/* AVATAR BOT */}\r\n {!isUser && (\r\n <div className=\"w-9 shrink-0 flex flex-col justify-end pb-1\">\r\n {isLast ? (\r\n <div\r\n className=\"h-9 w-9 rounded-full overflow-hidden border shadow-sm\"\r\n style={{\r\n borderColor: 'hsl(var(--border))',\r\n backgroundColor: 'hsl(var(--background))',\r\n }}\r\n >\r\n {currentAvatar ? (\r\n <img src={currentAvatar} alt={botName} className=\"h-full w-full object-cover\" />\r\n ) : (\r\n <div\r\n className=\"h-full w-full flex items-center justify-center text-white text-[10px] font-black uppercase\"\r\n style={{ backgroundColor: brandColor }}\r\n >\r\n {botName.charAt(0)}\r\n </div>\r\n )}\r\n </div>\r\n ) : (\r\n <div className=\"w-9\" />\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* BURBUJA */}\r\n <div\r\n className={cn(\r\n 'max-w-[85%] shadow-sm transition-all duration-300 relative',\r\n isUser ? 'text-primary-foreground' : 'border',\r\n // Bordes inteligentes\r\n isUser\r\n ? cn(\r\n 'rounded-[18px]',\r\n isFirst && 'rounded-tr-[4px]',\r\n !isLast && 'rounded-br-[4px]',\r\n !isFirst && !isLast && 'rounded-r-[4px]'\r\n )\r\n : cn(\r\n 'rounded-[18px]',\r\n isFirst && 'rounded-tl-[4px]',\r\n !isLast && 'rounded-bl-[4px]',\r\n !isFirst && !isLast && 'rounded-l-[4px]'\r\n )\r\n )}\r\n style={\r\n isUser\r\n ? {\r\n padding: 'var(--spacing-4) var(--spacing-5)',\r\n backgroundColor: brandColor,\r\n boxShadow: isLast ? `0 8px 20px -6px ${brandColor}33` : 'none',\r\n }\r\n : {\r\n padding: 'var(--spacing-4) var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border) / 0.6)',\r\n color: 'hsl(var(--foreground))',\r\n }\r\n }\r\n >\r\n {renderContent()}\r\n\r\n {/* FOOTER */}\r\n {isLast && (\r\n <div\r\n className={cn(\r\n 'flex items-center gap-1 mt-1.5 opacity-50 select-none text-[9px]',\r\n isUser ? 'justify-end' : 'justify-start'\r\n )}\r\n >\r\n <span className=\"font-bold tabular-nums uppercase tracking-tighter\">\r\n {formatTime(message.timestamp)}\r\n </span>\r\n {isUser && <CheckCheck className=\"h-2.5 w-2.5\" />}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n )\r\n },\r\n (prevProps, nextProps) => {\r\n // Custom comparator: solo re-render si cambió algo relevante\r\n if (prevProps.message.id !== nextProps.message.id) return false\r\n if (prevProps.message.timestamp !== nextProps.message.timestamp) return false\r\n if (prevProps.primaryColor !== nextProps.primaryColor) return false\r\n if (prevProps.botAvatar !== nextProps.botAvatar) return false\r\n if (prevProps.botName !== nextProps.botName) return false\r\n if (prevProps.isFirst !== nextProps.isFirst) return false\r\n if (prevProps.isLast !== nextProps.isLast) return false\r\n\r\n // Comparar styles profundamente si existe\r\n if (JSON.stringify(prevProps.styles) !== JSON.stringify(nextProps.styles)) return false\r\n\r\n return true // No re-renderizar\r\n }\r\n)\r\n","'use client'\r\n\r\nimport { memo } from 'react'\r\nimport { cn } from '@/lib/utils'\r\n\r\nexport const TypingIndicator = memo(function TypingIndicator() {\r\n return (\r\n <div\r\n className={cn(\r\n 'flex items-center self-start animate-in fade-in duration-200',\r\n 'max-w-[85%] sm:max-w-[75%]'\r\n )}\r\n >\r\n <div\r\n className=\"border rounded-[18px] rounded-tl-[4px] px-4 py-3 shadow-soft-sm\"\r\n style={{\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n }}\r\n >\r\n <div className=\"flex items-center gap-1.5\">\r\n {[0, 1, 2].map(i => (\r\n <span\r\n key={i}\r\n className=\"h-1.5 w-1.5 rounded-full animate-bounce\"\r\n style={{\r\n backgroundColor: 'hsl(var(--primary) / 0.4)',\r\n animationDelay: `${i * 150}ms`,\r\n animationDuration: '800ms',\r\n }}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n})\r\n","/**\r\n * Utilidades de formateo de fechas usando Intl nativo\r\n * Reemplaza date-fns para reducir el bundle\r\n */\r\n\r\n/**\r\n * Formatea una fecha en formato corto (día de mes, HH:mm)\r\n */\r\nexport function formatShort(date: Date): string {\r\n return new Intl.DateTimeFormat('es-ES', {\r\n day: 'numeric',\r\n month: 'long',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n }).format(date)\r\n}\r\n\r\n/**\r\n * Verifica si una fecha es hoy\r\n */\r\nexport function isToday(date: Date): boolean {\r\n const today = new Date()\r\n return (\r\n date.getDate() === today.getDate() &&\r\n date.getMonth() === today.getMonth() &&\r\n date.getFullYear() === today.getFullYear()\r\n )\r\n}\r\n\r\n/**\r\n * Verifica si una fecha fue ayer\r\n */\r\nexport function isYesterday(date: Date): boolean {\r\n const yesterday = new Date()\r\n yesterday.setDate(yesterday.getDate() - 1)\r\n return (\r\n date.getDate() === yesterday.getDate() &&\r\n date.getMonth() === yesterday.getMonth() &&\r\n date.getFullYear() === yesterday.getFullYear()\r\n )\r\n}\r\n\r\n/**\r\n * Calcula la diferencia en minutos entre dos fechas\r\n */\r\nexport function differenceInMinutes(laterDate: Date, earlierDate: Date): number {\r\n const diffMs = laterDate.getTime() - earlierDate.getTime()\r\n return Math.floor(diffMs / 1000 / 60)\r\n}\r\n\r\n/**\r\n * Formatea la hora en formato HH:mm\r\n */\r\nexport function formatTime(date: Date): string {\r\n return new Intl.DateTimeFormat('es-ES', {\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n }).format(date)\r\n}\r\n\r\n/**\r\n * Formatea fecha completa con día, mes y hora\r\n */\r\nexport function formatFull(date: Date): string {\r\n return new Intl.DateTimeFormat('es-ES', {\r\n day: 'numeric',\r\n month: 'long',\r\n year: 'numeric',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n }).format(date)\r\n}\r\n\r\n/**\r\n * Formatea fecha relativa (Hoy, Ayer, o fecha)\r\n */\r\nexport function formatRelative(date: Date): string {\r\n if (isToday(date)) {\r\n return `Hoy, ${formatTime(date)}`\r\n }\r\n if (isYesterday(date)) {\r\n return `Ayer, ${formatTime(date)}`\r\n }\r\n return formatShort(date)\r\n}\r\n","'use client'\r\n\r\nimport React, { useRef, useEffect, useState, memo } from 'react'\r\nimport { useVirtualizer } from '@tanstack/react-virtual'\r\nimport type { BubbleStyles, ChatMessage } from '../types'\r\nimport { MessageBubble } from './MessageBubble'\r\nimport { TypingIndicator } from './TypingIndicator'\r\nimport { getPrimaryColor } from '../utils/theme'\r\nimport type { EmotionAvatarMap } from './Launcher'\r\nimport { formatRelative, differenceInMinutes } from '../utils/dateUtils'\r\n\r\n// Umbral para activar virtualización (mejora rendimiento con >100 mensajes)\r\nconst VIRTUALIZATION_THRESHOLD = 100\r\n\r\nexport interface MessageListProps {\r\n messages: ChatMessage[]\r\n isTyping: boolean\r\n welcomeMessage?: string\r\n primaryColor?: string\r\n logoUrl?: string\r\n botName?: string\r\n bubbleStyles?: BubbleStyles\r\n avatars?: EmotionAvatarMap\r\n}\r\n\r\nexport const MessageList = memo(\r\n function MessageList({\r\n messages,\r\n isTyping,\r\n welcomeMessage = '¡Hola! ¿En qué puedo ayudarte?',\r\n primaryColor,\r\n logoUrl,\r\n botName = 'BotUyo',\r\n bubbleStyles,\r\n avatars,\r\n }: MessageListProps) {\r\n const messagesEndRef = useRef<HTMLDivElement>(null)\r\n const containerRef = useRef<HTMLDivElement>(null)\r\n const [isReady, setIsReady] = useState(false)\r\n const [logoError, setLogoError] = useState(false)\r\n const bgColor = getPrimaryColor({ primaryColor })\r\n\r\n // Virtualización activada solo si hay muchos mensajes\r\n const shouldVirtualize = messages.length > VIRTUALIZATION_THRESHOLD\r\n\r\n // Configuración del virtualizador\r\n const virtualizer = useVirtualizer({\r\n count: messages.length,\r\n getScrollElement: () => containerRef.current,\r\n estimateSize: () => 80, // Altura estimada por mensaje\r\n overscan: 5, // Pre-renderizar 5 items extra\r\n enabled: shouldVirtualize,\r\n })\r\n\r\n // Hidratación segura para Next.js\r\n useEffect(() => {\r\n setIsReady(true)\r\n }, [])\r\n\r\n /**\r\n * 📜 LÓGICA DE SCROLL INTELIGENTE\r\n * Se dispara cuando cambian los mensajes o el bot está escribiendo.\r\n */\r\n useEffect(() => {\r\n if (isReady && (messages.length > 0 || isTyping)) {\r\n const timer = setTimeout(() => {\r\n if (shouldVirtualize) {\r\n // Con virtualización: scroll al último índice\r\n virtualizer.scrollToIndex(messages.length - 1, {\r\n align: 'end',\r\n behavior: messages.length <= 1 ? 'auto' : 'smooth',\r\n })\r\n } else {\r\n // Sin virtualización: scroll tradicional\r\n messagesEndRef.current?.scrollIntoView({\r\n behavior: messages.length <= 1 ? 'auto' : 'smooth',\r\n block: 'end',\r\n })\r\n }\r\n }, 100)\r\n return () => clearTimeout(timer)\r\n }\r\n }, [messages.length, isTyping, isReady, shouldVirtualize, virtualizer])\r\n\r\n /**\r\n * 📅 FORMATEO DE SEPARADORES DE FECHA\r\n */\r\n const getSeparatorLabel = (date: any) => {\r\n const d = new Date(date)\r\n if (isNaN(d.getTime())) return ''\r\n return formatRelative(d)\r\n }\r\n\r\n if (!isReady) return <div className=\"flex-1 bg-background\" />\r\n\r\n // Renderizado con virtualización para listas grandes\r\n if (shouldVirtualize) {\r\n return (\r\n <div\r\n ref={containerRef}\r\n className=\"flex-1 overflow-y-auto scroll-smooth bg-background/50 scrollbar-none\"\r\n style={{ padding: 'var(--spacing-5)' }}\r\n >\r\n <div\r\n style={{\r\n height: `${virtualizer.getTotalSize()}px`,\r\n width: '100%',\r\n position: 'relative',\r\n }}\r\n >\r\n {virtualizer.getVirtualItems().map(virtualRow => {\r\n const message = messages[virtualRow.index]\r\n const index = virtualRow.index\r\n const prev = messages[index - 1]\r\n const next = messages[index + 1]\r\n\r\n const showDateSeparator =\r\n prev &&\r\n differenceInMinutes(new Date(message.timestamp), new Date(prev.timestamp)) > 15\r\n\r\n const isSameAsPrev =\r\n prev &&\r\n prev.sender === message.sender &&\r\n differenceInMinutes(new Date(message.timestamp), new Date(prev.timestamp)) < 5 &&\r\n !showDateSeparator\r\n\r\n const isSameAsNext =\r\n next &&\r\n next.sender === message.sender &&\r\n differenceInMinutes(new Date(next.timestamp), new Date(message.timestamp)) < 5\r\n\r\n return (\r\n <div\r\n key={virtualRow.key}\r\n style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n transform: `translateY(${virtualRow.start}px)`,\r\n }}\r\n >\r\n {showDateSeparator && (\r\n <div className=\"flex justify-center my-8 animate-in fade-in zoom-in-95\">\r\n <span className=\"px-4 py-1.5 bg-muted/40 backdrop-blur-md rounded-full text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em] border border-border/50 shadow-sm\">\r\n {getSeparatorLabel(message.timestamp)}\r\n </span>\r\n </div>\r\n )}\r\n\r\n <MessageBubble\r\n message={message}\r\n primaryColor={primaryColor}\r\n botAvatar={logoUrl}\r\n botName={botName}\r\n styles={bubbleStyles}\r\n avatars={avatars}\r\n isFirst={!isSameAsPrev}\r\n isLast={!isSameAsNext}\r\n />\r\n </div>\r\n )\r\n })}\r\n </div>\r\n {isTyping && (\r\n <div className=\"flex items-end gap-3 mt-4 mb-2 animate-in fade-in slide-in-from-left-4 duration-500\">\r\n <div className=\"w-8 h-8 rounded-xl bg-muted/60 border border-border/50 flex items-center justify-center shrink-0 shadow-soft-sm\">\r\n <div className=\"flex gap-[2px]\">\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce [animation-delay:-0.3s]\" />\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce [animation-delay:-0.15s]\" />\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce\" />\r\n </div>\r\n </div>\r\n <TypingIndicator />\r\n </div>\r\n )}\r\n </div>\r\n )\r\n }\r\n\r\n // Renderizado tradicional para listas pequeñas\r\n return (\r\n <div\r\n ref={containerRef}\r\n className=\"flex-1 overflow-y-auto scroll-smooth p-4 bg-background/50 scrollbar-none\"\r\n >\r\n <div className=\"min-h-full flex flex-col justify-end\">\r\n {/* === ESTADO VACÍO / BIENVENIDA PREMIUM === */}\r\n {messages.length === 0 && (\r\n <div className=\"flex-1 flex flex-col items-center justify-center py-16 text-center animate-in fade-in zoom-in-95 duration-1000\">\r\n <div className=\"relative h-24 w-24 mb-6\">\r\n <div className=\"absolute inset-0 bg-primary/20 rounded-full animate-pulse blur-2xl\" />\r\n <div className=\"relative h-full w-full rounded-[28px] border-2 border-primary/20 overflow-hidden bg-card shadow-soft-2xl transition-transform hover:scale-105 duration-500\">\r\n {logoError ? (\r\n <div\r\n className=\"h-full w-full flex items-center justify-center text-3xl\"\r\n style={{ backgroundColor: bgColor }}\r\n >\r\n 👋\r\n </div>\r\n ) : logoUrl ? (\r\n <img\r\n src={logoUrl}\r\n className=\"object-cover h-full w-full\"\r\n alt={botName}\r\n onError={() => setLogoError(true)}\r\n />\r\n ) : (\r\n <div\r\n className=\"h-full w-full flex items-center justify-center text-3xl\"\r\n style={{ backgroundColor: bgColor }}\r\n >\r\n 👋\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n <div className=\"space-y-2\">\r\n <h3 className=\"font-black text-xl text-foreground uppercase tracking-tighter italic\">\r\n {botName}\r\n </h3>\r\n <p className=\"text-[12px] font-bold text-muted-foreground italic px-10 leading-relaxed opacity-60\">\r\n \"{welcomeMessage}\"\r\n </p>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* === LISTADO DE MENSAJES CON ESTRATEGIA DE ACUMULACIÓN === */}\r\n <div className=\"flex flex-col\" style={{ gap: 'var(--spacing-3)' }}>\r\n {messages.map((message, index) => {\r\n const prev = messages[index - 1]\r\n const next = messages[index + 1]\r\n\r\n // 1. Mostrar separador si pasaron más de 15 min desde el anterior\r\n const showDateSeparator =\r\n prev &&\r\n differenceInMinutes(new Date(message.timestamp), new Date(prev.timestamp)) > 15\r\n\r\n // 2. Lógica para pegar mensajes (Mismo autor + ventana < 5 min)\r\n const isSameAsPrev =\r\n prev &&\r\n prev.sender === message.sender &&\r\n differenceInMinutes(new Date(message.timestamp), new Date(prev.timestamp)) < 5 &&\r\n !showDateSeparator\r\n\r\n const isSameAsNext =\r\n next &&\r\n next.sender === message.sender &&\r\n differenceInMinutes(new Date(next.timestamp), new Date(message.timestamp)) < 5\r\n\r\n return (\r\n <React.Fragment key={message.id || `msg-${index}`}>\r\n {showDateSeparator && (\r\n <div className=\"flex justify-center my-8 animate-in fade-in zoom-in-95\">\r\n <span className=\"px-4 py-1.5 bg-muted/40 backdrop-blur-md rounded-full text-[10px] font-black text-muted-foreground uppercase tracking-[0.2em] border border-border/50 shadow-sm\">\r\n {getSeparatorLabel(message.timestamp)}\r\n </span>\r\n </div>\r\n )}\r\n\r\n <MessageBubble\r\n message={message}\r\n primaryColor={primaryColor}\r\n botAvatar={logoUrl}\r\n botName={botName}\r\n styles={bubbleStyles}\r\n avatars={avatars}\r\n // Props de acumulación para MessageBubble\r\n isFirst={!isSameAsPrev}\r\n isLast={!isSameAsNext}\r\n />\r\n </React.Fragment>\r\n )\r\n })}\r\n </div>\r\n\r\n {/* Espaciador final para evitar que el input tape el último mensaje */}\r\n <div ref={messagesEndRef} className=\"h-6 shrink-0\" />\r\n {/* INDICADOR DE ESCRITURA (AVATAR + ONDAS) */}\r\n </div>\r\n {isTyping && (\r\n <div className=\"flex items-end gap-3 mt-4 mb-2 animate-in fade-in slide-in-from-left-4 duration-500\">\r\n <div className=\"w-8 h-8 rounded-xl bg-muted/60 border border-border/50 flex items-center justify-center shrink-0 shadow-soft-sm\">\r\n <div className=\"flex gap-[2px]\">\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce [animation-delay:-0.3s]\" />\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce [animation-delay:-0.15s]\" />\r\n <span className=\"w-1 h-1 bg-primary/50 rounded-full animate-bounce\" />\r\n </div>\r\n </div>\r\n <TypingIndicator />\r\n </div>\r\n )}\r\n </div>\r\n )\r\n },\r\n (prevProps, nextProps) => {\r\n // Custom comparator: reducir re-renders innecesarios\r\n if (prevProps.messages.length !== nextProps.messages.length) return false\r\n if (prevProps.isTyping !== nextProps.isTyping) return false\r\n if (prevProps.primaryColor !== nextProps.primaryColor) return false\r\n if (prevProps.botName !== nextProps.botName) return false\r\n if (prevProps.logoUrl !== nextProps.logoUrl) return false\r\n\r\n // Comparar último mensaje por ID para detectar cambios\r\n const prevLast = prevProps.messages[prevProps.messages.length - 1]\r\n const nextLast = nextProps.messages[nextProps.messages.length - 1]\r\n if (prevLast?.id !== nextLast?.id) return false\r\n\r\n return true // No re-renderizar\r\n }\r\n)\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * File validation utilities with magic bytes verification\r\n *\r\n * Validates file types by checking magic bytes (file signatures)\r\n * to prevent MIME type spoofing and detect corrupted files.\r\n */\r\n\r\n/**\r\n * Magic bytes (file signatures) for common file types\r\n * First few bytes that identify the file format\r\n */\r\nconst MAGIC_BYTES = {\r\n 'image/jpeg': [0xff, 0xd8, 0xff],\r\n 'image/png': [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],\r\n 'image/webp': [0x52, 0x49, 0x46, 0x46], // RIFF\r\n 'image/gif': [0x47, 0x49, 0x46, 0x38], // GIF8\r\n 'audio/mpeg': [0xff, 0xfb], // MP3\r\n 'audio/wav': [0x52, 0x49, 0x46, 0x46], // RIFF\r\n 'audio/webm': [0x1a, 0x45, 0xdf, 0xa3],\r\n 'audio/ogg': [0x4f, 0x67, 0x67, 0x53], // OggS\r\n} as const\r\n\r\n/**\r\n * Validates a file by checking its magic bytes against expected signature\r\n *\r\n * @param file - File to validate\r\n * @returns Promise<boolean> - true if file matches expected type, false otherwise\r\n *\r\n * @example\r\n * const isValid = await validateFileType(file)\r\n * if (!isValid) {\r\n * alert('El archivo está corrupto o no es del tipo indicado')\r\n * }\r\n */\r\nexport async function validateFileType(file: File): Promise<boolean> {\r\n try {\r\n // Get magic bytes for expected MIME type\r\n const expectedBytes = MAGIC_BYTES[file.type as keyof typeof MAGIC_BYTES]\r\n\r\n if (!expectedBytes) {\r\n // Type not in our validation list, allow it\r\n return true\r\n }\r\n\r\n // Read first 12 bytes of the file\r\n const buffer = await file.slice(0, 12).arrayBuffer()\r\n const bytes = new Uint8Array(buffer)\r\n\r\n // Compare with expected magic bytes\r\n return expectedBytes.every((byte, index) => bytes[index] === byte)\r\n } catch (error) {\r\n // If validation fails, reject the file for security\r\n console.error('File validation error:', error)\r\n return false\r\n }\r\n}\r\n\r\n/**\r\n * Validates file size against maximum allowed\r\n *\r\n * @param file - File to validate\r\n * @param maxSizeMB - Maximum size in megabytes (default: 10MB)\r\n * @returns boolean - true if file is within size limit\r\n *\r\n * @example\r\n * if (!validateFileSize(file, 5)) {\r\n * alert('El archivo es demasiado grande. Máximo 5MB')\r\n * }\r\n */\r\nexport function validateFileSize(file: File, maxSizeMB: number = 10): boolean {\r\n const maxSizeBytes = maxSizeMB * 1024 * 1024\r\n return file.size <= maxSizeBytes\r\n}\r\n\r\n/**\r\n * Validates file extension matches allowed list\r\n *\r\n * @param file - File to validate\r\n * @param allowedExtensions - Array of allowed extensions (e.g., ['jpg', 'png'])\r\n * @returns boolean - true if extension is allowed\r\n *\r\n * @example\r\n * if (!validateFileExtension(file, ['jpg', 'png', 'webp'])) {\r\n * alert('Solo se permiten imágenes JPG, PNG o WebP')\r\n * }\r\n */\r\nexport function validateFileExtension(file: File, allowedExtensions: string[]): boolean {\r\n const extension = file.name.split('.').pop()?.toLowerCase()\r\n if (!extension) return false\r\n\r\n return allowedExtensions.includes(extension)\r\n}\r\n\r\n/**\r\n * Comprehensive file validation combining all checks\r\n *\r\n * @param file - File to validate\r\n * @param options - Validation options\r\n * @returns Promise<ValidationResult> - Validation result with details\r\n *\r\n * @example\r\n * const result = await validateFile(file, {\r\n * maxSizeMB: 5,\r\n * allowedExtensions: ['jpg', 'png'],\r\n * checkMagicBytes: true\r\n * })\r\n *\r\n * if (!result.valid) {\r\n * alert(result.error)\r\n * }\r\n */\r\nexport interface FileValidationOptions {\r\n maxSizeMB?: number\r\n allowedExtensions?: string[]\r\n checkMagicBytes?: boolean\r\n}\r\n\r\nexport interface ValidationResult {\r\n valid: boolean\r\n error?: string\r\n}\r\n\r\nexport async function validateFile(\r\n file: File,\r\n options: FileValidationOptions = {}\r\n): Promise<ValidationResult> {\r\n const { maxSizeMB = 10, allowedExtensions, checkMagicBytes = true } = options\r\n\r\n // Check file size\r\n if (!validateFileSize(file, maxSizeMB)) {\r\n return {\r\n valid: false,\r\n error: `El archivo es demasiado grande. Máximo ${maxSizeMB}MB`,\r\n }\r\n }\r\n\r\n // Check file extension\r\n if (allowedExtensions && !validateFileExtension(file, allowedExtensions)) {\r\n return {\r\n valid: false,\r\n error: `Extensión no permitida. Solo: ${allowedExtensions.join(', ')}`,\r\n }\r\n }\r\n\r\n // Check magic bytes\r\n if (checkMagicBytes) {\r\n const isValid = await validateFileType(file)\r\n if (!isValid) {\r\n return {\r\n valid: false,\r\n error: 'El archivo está corrupto o no es del tipo indicado',\r\n }\r\n }\r\n }\r\n\r\n return { valid: true }\r\n}\r\n","'use client'\r\n\r\nimport { useState, useRef, useMemo } from 'react'\r\nimport { useTranslations } from '@/chat-widget/i18n'\r\nimport type { MediaConfig } from '../types'\r\nimport { Send, ImageIcon, Loader2, Plus, MapPin, Mic, X, Trash2, FileIcon, Phone } from './Icons'\r\nimport { cn } from '@/lib/utils'\r\nimport { getPrimaryColor } from '../utils/theme'\r\nimport { logger } from '../utils/logger'\r\nimport { validateFile } from '../utils/fileValidation'\r\n\r\n// --- CONFIGURACIÓN ---\r\nconst MAX_CHARS = 1000\r\nconst DEFAULT_MEDIA_CONFIG: MediaConfig = {\r\n enableImages: true,\r\n enableAudio: true,\r\n enableFiles: true,\r\n enableLocation: true,\r\n allowedFileTypes: ['jpg', 'jpeg', 'png', 'webp', 'gif', 'pdf', 'doc', 'docx', 'txt', 'zip'],\r\n maxFileSizeMB: 10,\r\n}\r\n\r\n// --- INTERFACES ---\r\nexport interface Attachment {\r\n type: 'image' | 'audio' | 'file'\r\n file: File\r\n previewUrl?: string\r\n}\r\n\r\nexport interface InputAreaProps {\r\n isConnected: boolean\r\n placeholder?: string\r\n primaryColor?: string\r\n mediaConfig?: MediaConfig\r\n onSendMessage: (message: string) => void\r\n onSendAttachment?: (file: File, type: 'image' | 'audio' | 'file') => void\r\n onSendLocation?: (location: { latitude: number; longitude: number }) => void\r\n onVoiceCall?: () => void // Voice call callback\r\n}\r\n\r\nexport function InputArea({\r\n isConnected,\r\n placeholder = 'Escribe un mensaje...',\r\n primaryColor,\r\n mediaConfig,\r\n onSendMessage,\r\n onSendAttachment,\r\n onSendLocation,\r\n onVoiceCall,\r\n}: InputAreaProps) {\r\n const { t } = useTranslations()\r\n const [inputValue, setInputValue] = useState('')\r\n const [isMenuOpen, setIsMenuOpen] = useState(false)\r\n const [isRecording, setIsRecording] = useState(false)\r\n const [recordingTime, setRecordingTime] = useState(0)\r\n const [attachment, setAttachment] = useState<Attachment | null>(null)\r\n const [isCompressing, setIsCompressing] = useState(false)\r\n const [isLoadingLocation, setIsLoadingLocation] = useState(false)\r\n\r\n const textareaRef = useRef<HTMLTextAreaElement>(null)\r\n const fileInputRef = useRef<HTMLInputElement>(null)\r\n const imageInputRef = useRef<HTMLInputElement>(null)\r\n const mediaRecorderRef = useRef<MediaRecorder | null>(null)\r\n const audioChunksRef = useRef<Blob[]>([])\r\n const timerRef = useRef<NodeJS.Timeout | null>(null)\r\n\r\n const brandColor = getPrimaryColor({ primaryColor })\r\n\r\n // Fusionar configuración de medios con valores por defecto\r\n const config = useMemo(() => ({ ...DEFAULT_MEDIA_CONFIG, ...mediaConfig }), [mediaConfig])\r\n\r\n // Verificar si hay alguna funcionalidad multimedia habilitada\r\n const hasMediaFeatures = useMemo(\r\n () => config.enableImages || config.enableAudio || config.enableFiles || config.enableLocation,\r\n [config]\r\n )\r\n\r\n // 🔥 LÓGICA DE ENVÍO CORREGIDA\r\n const handleSend = () => {\r\n const trimmedValue = inputValue.trim()\r\n\r\n if (attachment) {\r\n onSendAttachment?.(attachment.file, attachment.type)\r\n setAttachment(null)\r\n setInputValue('')\r\n } else if (trimmedValue && isConnected) {\r\n onSendMessage(trimmedValue)\r\n setInputValue('')\r\n }\r\n\r\n // Resetear altura del textarea\r\n if (textareaRef.current) {\r\n textareaRef.current.style.height = '40px'\r\n }\r\n }\r\n\r\n // 🔥 CAPTURA DE ENTER Y CTRL+ENTER (Accesibilidad mejorada)\r\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\r\n // Enter sin modificadores: enviar mensaje\r\n if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey) {\r\n e.preventDefault()\r\n handleSend()\r\n }\r\n // Ctrl+Enter o Cmd+Enter: enviar mensaje (alternativa)\r\n else if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {\r\n e.preventDefault()\r\n handleSend()\r\n }\r\n // Shift+Enter: nueva línea (comportamiento por defecto, no hacer nada)\r\n }\r\n\r\n const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\r\n const val = e.target.value.slice(0, MAX_CHARS)\r\n setInputValue(val)\r\n\r\n // Auto-resize\r\n if (textareaRef.current) {\r\n textareaRef.current.style.height = '40px'\r\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 120)}px`\r\n }\r\n }\r\n\r\n const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const file = e.target.files?.[0]\r\n if (!file) return\r\n setIsMenuOpen(false)\r\n\r\n // Validar archivo con magic bytes\r\n const validationResult = await validateFile(file, {\r\n maxSizeMB: config.maxFileSizeMB || 10,\r\n allowedExtensions: config.allowedFileTypes || [\r\n 'jpg',\r\n 'jpeg',\r\n 'png',\r\n 'webp',\r\n 'gif',\r\n 'pdf',\r\n 'doc',\r\n 'docx',\r\n 'txt',\r\n 'zip',\r\n ],\r\n checkMagicBytes: true,\r\n })\r\n\r\n if (!validationResult.valid) {\r\n alert(validationResult.error || 'Archivo no válido')\r\n return\r\n }\r\n\r\n // Si es imagen y la compresión está habilitada, comprimir\r\n if (file.type.startsWith('image/') && config.enableImages) {\r\n setIsCompressing(true)\r\n try {\r\n // Lazy load browser-image-compression\r\n const { default: imageCompression } = await import('browser-image-compression')\r\n\r\n const options = {\r\n maxSizeMB: 0.8,\r\n maxWidthOrHeight: 1200,\r\n useWebWorker: true,\r\n }\r\n const compressedFile = await imageCompression(file, options)\r\n setAttachment({\r\n type: 'image',\r\n file: compressedFile,\r\n previewUrl: URL.createObjectURL(compressedFile),\r\n })\r\n } catch (error) {\r\n logger.error('Image compression failed:', error)\r\n // Fallback: usar imagen original sin comprimir\r\n setAttachment({\r\n type: 'image',\r\n file,\r\n previewUrl: URL.createObjectURL(file),\r\n })\r\n } finally {\r\n setIsCompressing(false)\r\n }\r\n } else {\r\n // Archivo general (PDF, DOC, etc.)\r\n setAttachment({\r\n type: 'file',\r\n file,\r\n previewUrl: '',\r\n })\r\n }\r\n }\r\n\r\n const startRecording = async () => {\r\n if (!isConnected) return\r\n try {\r\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true })\r\n const mediaRecorder = new MediaRecorder(stream)\r\n mediaRecorderRef.current = mediaRecorder\r\n audioChunksRef.current = []\r\n mediaRecorder.ondataavailable = e => audioChunksRef.current.push(e.data)\r\n mediaRecorder.onstop = () => {\r\n const audioFile = new File([new Blob(audioChunksRef.current)], 'voice.webm', {\r\n type: 'audio/webm',\r\n })\r\n onSendAttachment?.(audioFile, 'audio')\r\n }\r\n mediaRecorder.start()\r\n setIsRecording(true)\r\n timerRef.current = setInterval(() => setRecordingTime(v => v + 1), 1000)\r\n } catch {\r\n alert('Micrófono denegado o no disponible')\r\n }\r\n }\r\n\r\n const stopRecording = async (send: boolean) => {\r\n if (mediaRecorderRef.current) {\r\n if (!send) mediaRecorderRef.current.onstop = null\r\n mediaRecorderRef.current.stop()\r\n mediaRecorderRef.current.stream.getTracks().forEach(t => t.stop())\r\n }\r\n if (timerRef.current) clearInterval(timerRef.current)\r\n setIsRecording(false)\r\n setRecordingTime(0)\r\n\r\n // Validar archivo de audio antes de enviar\r\n if (send && audioChunksRef.current.length > 0) {\r\n const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' })\r\n const audioFile = new File([audioBlob], `audio-${Date.now()}.webm`, {\r\n type: 'audio/webm',\r\n })\r\n\r\n // Validar archivo de audio (ahora async)\r\n const validation = await validateFile(audioFile, { maxSizeMB: 10 })\r\n if (!validation.valid) {\r\n logger.error('Audio validation failed:', validation.error)\r\n alert(validation.error)\r\n audioChunksRef.current = []\r\n return\r\n }\r\n\r\n // Si es válido, enviar\r\n onSendAttachment?.(audioFile, 'audio')\r\n audioChunksRef.current = []\r\n }\r\n }\r\n\r\n return (\r\n <div className=\"relative\">\r\n {/* PREVIEW DE ADJUNTO */}\r\n {(attachment || isCompressing) && (\r\n <div\r\n className=\"absolute bottom-full left-0 mb-2 p-2 rounded-2xl border shadow-soft-2xl animate-in slide-in-from-bottom-2 z-50\"\r\n style={{\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n }}\r\n >\r\n <div className=\"relative w-16 h-16\">\r\n {isCompressing ? (\r\n <div className=\"w-full h-full flex flex-col items-center justify-center bg-muted rounded-xl\">\r\n <Loader2 className=\"animate-spin text-primary h-5 w-5\" />\r\n </div>\r\n ) : attachment?.type === 'image' ? (\r\n <>\r\n <img\r\n src={attachment?.previewUrl}\r\n className=\"w-full h-full object-cover rounded-xl border\"\r\n alt={t('preview')}\r\n />\r\n <button\r\n onClick={() => setAttachment(null)}\r\n className=\"absolute -top-1.5 -right-1.5 bg-destructive text-white rounded-full p-1 shadow-md hover:scale-105\"\r\n >\r\n <X size={10} strokeWidth={3} />\r\n </button>\r\n </>\r\n ) : (\r\n <>\r\n <div className=\"w-full h-full flex flex-col items-center justify-center bg-muted rounded-xl border\">\r\n <FileIcon className=\"text-primary h-6 w-6\" />\r\n <span className=\"text-[8px] mt-1 font-bold truncate max-w-[60px]\">\r\n {attachment?.file.name}\r\n </span>\r\n </div>\r\n <button\r\n onClick={() => setAttachment(null)}\r\n className=\"absolute -top-1.5 -right-1.5 bg-destructive text-white rounded-full p-1 shadow-md hover:scale-105\"\r\n >\r\n <X size={10} strokeWidth={3} />\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Input de imágenes */}\r\n <input\r\n type=\"file\"\r\n accept=\"image/*\"\r\n className=\"hidden\"\r\n ref={imageInputRef}\r\n onChange={handleFileSelect}\r\n />\r\n\r\n {/* Input de archivos generales */}\r\n <input\r\n type=\"file\"\r\n accept={config.allowedFileTypes?.map(ext => `.${ext}`).join(',')}\r\n className=\"hidden\"\r\n ref={fileInputRef}\r\n onChange={handleFileSelect}\r\n />\r\n\r\n <div className=\"flex items-center max-w-full\" style={{ gap: 'var(--spacing-3)' }}>\r\n {/* BOTÓN PLUS / MENÚ */}\r\n {hasMediaFeatures && onSendAttachment && (\r\n <div className=\"relative shrink-0\">\r\n {isMenuOpen && (\r\n <div\r\n className=\"absolute bottom-full left-0 flex flex-col animate-in fade-in slide-in-from-bottom-2 duration-300 z-[60]\"\r\n style={{ marginBottom: 'var(--spacing-2)', gap: 'var(--spacing-2)' }}\r\n >\r\n {/* Opción: Imágenes */}\r\n {config.enableImages && (\r\n <button\r\n onClick={() => imageInputRef.current?.click()}\r\n className=\"flex items-center border shadow-soft-2xl rounded-2xl transition-colors text-[10px] font-black uppercase tracking-widest\"\r\n style={{\r\n gap: 'var(--spacing-3)',\r\n padding: 'var(--spacing-3) var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--card-foreground))',\r\n }}\r\n >\r\n <ImageIcon size={18} className=\"text-blue-500\" /> {t('fotos')}\r\n </button>\r\n )}\r\n\r\n {/* Opción: Archivos */}\r\n {config.enableFiles && (\r\n <button\r\n onClick={() => fileInputRef.current?.click()}\r\n className=\"flex items-center border shadow-soft-2xl rounded-2xl transition-colors text-[10px] font-black uppercase tracking-widest\"\r\n style={{\r\n gap: 'var(--spacing-3)',\r\n padding: 'var(--spacing-3) var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--card-foreground))',\r\n }}\r\n >\r\n <FileIcon size={18} className=\"text-purple-500\" /> Archivos\r\n </button>\r\n )}\r\n\r\n {/* Opción: Ubicación */}\r\n {config.enableLocation && onSendLocation && (\r\n <button\r\n onClick={() => {\r\n setIsLoadingLocation(true)\r\n navigator.geolocation.getCurrentPosition(\r\n pos => {\r\n onSendLocation?.({\r\n latitude: pos.coords.latitude,\r\n longitude: pos.coords.longitude,\r\n })\r\n setIsLoadingLocation(false)\r\n setIsMenuOpen(false)\r\n },\r\n () => setIsLoadingLocation(false)\r\n )\r\n }}\r\n className=\"flex items-center border shadow-soft-2xl rounded-2xl transition-colors text-[10px] font-black uppercase tracking-widest\"\r\n style={{\r\n gap: 'var(--spacing-3)',\r\n padding: 'var(--spacing-3) var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--card-foreground))',\r\n }}\r\n >\r\n {isLoadingLocation ? (\r\n <Loader2 size={18} className=\"animate-spin\" />\r\n ) : (\r\n <MapPin size={18} className=\"text-emerald-500\" />\r\n )}{' '}\r\n {t('ubicacion')}\r\n </button>\r\n )}\r\n\r\n {/* Opción: Llamada de Voz */}\r\n {config.enableVoice && onVoiceCall && (\r\n <button\r\n onClick={() => {\r\n onVoiceCall?.()\r\n setIsMenuOpen(false)\r\n }}\r\n className=\"flex items-center border shadow-soft-2xl rounded-2xl transition-colors text-[10px] font-black uppercase tracking-widest\"\r\n style={{\r\n gap: 'var(--spacing-3)',\r\n padding: 'var(--spacing-3) var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--card))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--card-foreground))',\r\n }}\r\n >\r\n <Phone size={18} className=\"text-amber-500\" /> Llamar\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n <button\r\n onClick={() => setIsMenuOpen(!isMenuOpen)}\r\n className={cn(\r\n 'h-10 w-10 rounded-full flex items-center justify-center transition-all shadow-sm z-10',\r\n isMenuOpen\r\n ? 'bg-muted text-foreground rotate-45'\r\n : 'bg-muted/50 text-muted-foreground hover:bg-muted'\r\n )}\r\n >\r\n <Plus size={22} strokeWidth={2.5} />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* ÁREA DE TEXTO / GRABACIÓN */}\r\n <div\r\n className={cn(\r\n 'flex-1 relative flex items-center min-w-0 rounded-[24px] border px-4 transition-all shadow-inner',\r\n isRecording ? 'h-[44px]' : 'min-h-[40px] max-h-[120px]'\r\n )}\r\n style={{\r\n backgroundColor: isRecording ? 'hsl(var(--destructive) / 0.05)' : 'hsl(var(--muted))',\r\n borderColor: isRecording ? 'hsl(var(--destructive))' : 'hsl(var(--border))',\r\n }}\r\n >\r\n {isRecording ? (\r\n <div\r\n className=\"flex items-center w-full animate-in zoom-in-95\"\r\n style={{ gap: 'var(--spacing-4)' }}\r\n >\r\n <button\r\n onClick={() => stopRecording(false)}\r\n className=\"text-destructive/50 hover:text-destructive\"\r\n >\r\n <Trash2 size={18} />\r\n </button>\r\n <div className=\"flex-1 flex items-center\" style={{ gap: 'var(--spacing-2)' }}>\r\n <div className=\"flex gap-[3px]\">\r\n {[1, 2, 3, 4].map(i => (\r\n <span\r\n key={i}\r\n className=\"w-[3px] h-3 bg-destructive/60 rounded-full animate-pulse\"\r\n style={{ animationDelay: `${i * 0.15}s` }}\r\n />\r\n ))}\r\n </div>\r\n <span className=\"text-destructive font-black text-[11px] tabular-nums\">\r\n {Math.floor(recordingTime / 60)}:\r\n {(recordingTime % 60).toString().padStart(2, '0')}\r\n </span>\r\n </div>\r\n <button\r\n onClick={() => stopRecording(true)}\r\n className=\"w-7 h-7 rounded-full bg-destructive flex items-center justify-center text-white shadow-lg\"\r\n >\r\n <Send size={12} fill=\"currentColor\" />\r\n </button>\r\n </div>\r\n ) : (\r\n <div className=\"w-full relative flex items-center\">\r\n <textarea\r\n ref={textareaRef}\r\n rows={1}\r\n value={inputValue}\r\n onKeyDown={handleKeyDown}\r\n onChange={handleInputChange}\r\n onFocus={() => setIsMenuOpen(false)}\r\n placeholder={placeholder}\r\n aria-label={t('accessibility.typeMessage')}\r\n aria-describedby=\"send-message-hint\"\r\n aria-invalid={inputValue.length > MAX_CHARS}\r\n disabled={!isConnected}\r\n className=\"w-full bg-transparent text-sm py-2.5 outline-none resize-none overflow-hidden leading-tight pr-8 scrollbar-none disabled:opacity-50\"\r\n style={{\r\n scrollbarWidth: 'none',\r\n msOverflowStyle: 'none',\r\n color: 'hsl(var(--foreground))',\r\n }}\r\n />\r\n {/* Hint oculto para lectores de pantalla */}\r\n <span id=\"send-message-hint\" className=\"sr-only\">\r\n {t('accessibility.sendMessageHint')}\r\n </span>\r\n {inputValue.length > MAX_CHARS * 0.8 && (\r\n <span\r\n className={cn(\r\n 'absolute right-0 text-[9px] font-bold tabular-nums',\r\n inputValue.length >= MAX_CHARS ? 'text-destructive' : 'text-muted-foreground/40'\r\n )}\r\n >\r\n {MAX_CHARS - inputValue.length}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* BOTÓN DE ACCIÓN */}\r\n {!isRecording && (\r\n <>\r\n {inputValue.trim() || attachment ? (\r\n <button\r\n onClick={handleSend}\r\n disabled={!isConnected || (isCompressing && !!attachment)}\r\n className=\"h-10 w-10 rounded-full flex items-center justify-center transition-all active:scale-90 shadow-md shadow-primary/20 shrink-0 disabled:opacity-30 disabled:grayscale\"\r\n style={{ backgroundColor: brandColor }}\r\n >\r\n <Send size={18} className=\"text-white ml-0.5 fill-current\" />\r\n </button>\r\n ) : config.enableAudio && onSendAttachment ? (\r\n <button\r\n onClick={startRecording}\r\n disabled={!isConnected}\r\n className=\"h-10 w-10 rounded-full flex items-center justify-center transition-all active:scale-90 shadow-md shadow-primary/20 shrink-0 disabled:opacity-30 disabled:grayscale\"\r\n style={{ backgroundColor: brandColor }}\r\n >\r\n <Mic size={20} strokeWidth={2.5} className=\"text-white\" />\r\n </button>\r\n ) : (\r\n <button\r\n onClick={handleSend}\r\n disabled={!isConnected}\r\n className=\"h-10 w-10 rounded-full flex items-center justify-center transition-all active:scale-90 shadow-md shadow-primary/20 shrink-0 disabled:opacity-30 disabled:grayscale\"\r\n style={{ backgroundColor: brandColor }}\r\n >\r\n <Send size={18} className=\"text-white ml-0.5 fill-current\" />\r\n </button>\r\n )}\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n )\r\n}\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * Performance utilities - throttle, debounce, lazy loading\r\n *\r\n * Principio: Single Responsibility - solo optimizaciones de rendimiento\r\n */\r\n\r\n/**\r\n * Throttle: limita la ejecución a una vez por intervalo\r\n * Útil para eventos frecuentes como scroll, resize, typing\r\n *\r\n * @example\r\n * const handleScroll = throttle(() => console.log('scroll'), 250)\r\n * window.addEventListener('scroll', handleScroll)\r\n */\r\nexport function throttle<T extends (...args: any[]) => any>(\r\n func: T,\r\n delay: number\r\n): (...args: Parameters<T>) => void {\r\n let lastCall = 0\r\n let timeoutId: NodeJS.Timeout | null = null\r\n\r\n return function throttled(...args: Parameters<T>) {\r\n const now = Date.now()\r\n const timeSinceLastCall = now - lastCall\r\n\r\n const execute = () => {\r\n lastCall = now\r\n func(...args)\r\n }\r\n\r\n if (timeSinceLastCall >= delay) {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n timeoutId = null\r\n }\r\n execute()\r\n } else if (!timeoutId) {\r\n timeoutId = setTimeout(() => {\r\n execute()\r\n timeoutId = null\r\n }, delay - timeSinceLastCall)\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Debounce: retrasa la ejecución hasta que pasen N ms sin nuevas llamadas\r\n * Útil para input search, auto-save, validación\r\n *\r\n * @example\r\n * const handleSearch = debounce((query) => fetchResults(query), 300)\r\n * input.addEventListener('input', (e) => handleSearch(e.target.value))\r\n */\r\nexport function debounce<T extends (...args: any[]) => any>(\r\n func: T,\r\n delay: number\r\n): (...args: Parameters<T>) => void {\r\n let timeoutId: NodeJS.Timeout | null = null\r\n\r\n return function debounced(...args: Parameters<T>) {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n }\r\n\r\n timeoutId = setTimeout(() => {\r\n func(...args)\r\n timeoutId = null\r\n }, delay)\r\n }\r\n}\r\n\r\n/**\r\n * Memoización simple para cálculos costosos\r\n *\r\n * @example\r\n * const expensiveCalc = memoize((n: number) => fibonacci(n))\r\n */\r\nexport function memoize<T extends (...args: any[]) => any>(func: T): T {\r\n const cache = new Map<string, ReturnType<T>>()\r\n\r\n return ((...args: Parameters<T>) => {\r\n const key = JSON.stringify(args)\r\n\r\n if (cache.has(key)) {\r\n return cache.get(key)!\r\n }\r\n\r\n const result = func(...args)\r\n cache.set(key, result)\r\n return result\r\n }) as T\r\n}\r\n\r\n/**\r\n * RequestAnimationFrame throttle para animaciones suaves\r\n */\r\nexport function rafThrottle<T extends (...args: any[]) => any>(\r\n func: T\r\n): (...args: Parameters<T>) => void {\r\n let rafId: number | null = null\r\n\r\n return function throttled(...args: Parameters<T>) {\r\n if (rafId !== null) return\r\n\r\n rafId = requestAnimationFrame(() => {\r\n func(...args)\r\n rafId = null\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * Batch de operaciones para reducir re-renders\r\n * Acumula llamadas y ejecuta todas juntas\r\n *\r\n * @example\r\n * const batchedUpdate = createBatcher((items) => {\r\n * setState(prev => [...prev, ...items])\r\n * }, 50)\r\n */\r\nexport function createBatcher<T>(\r\n callback: (items: T[]) => void,\r\n delay: number = 50\r\n): (item: T) => void {\r\n let batch: T[] = []\r\n let timeoutId: NodeJS.Timeout | null = null\r\n\r\n return function addToBatch(item: T) {\r\n batch.push(item)\r\n\r\n if (timeoutId) clearTimeout(timeoutId)\r\n\r\n timeoutId = setTimeout(() => {\r\n callback([...batch])\r\n batch = []\r\n timeoutId = null\r\n }, delay)\r\n }\r\n}\r\n\r\n/**\r\n * Intersection Observer para lazy loading\r\n */\r\nexport function createLazyLoader(\r\n callback: (entry: IntersectionObserverEntry) => void,\r\n options?: IntersectionObserverInit\r\n): IntersectionObserver {\r\n return new IntersectionObserver(entries => {\r\n entries.forEach(entry => {\r\n if (entry.isIntersecting) {\r\n callback(entry)\r\n }\r\n })\r\n }, options)\r\n}\r\n","import { useState, useEffect } from 'react'\r\nimport { throttle } from '../utils/performance'\r\n\r\nexport function useIsMobile(breakpoint = 640) {\r\n const [isMobile, setIsMobile] = useState(() => {\r\n // Cálculo inicial solo si estamos en browser\r\n if (typeof window === 'undefined') return false\r\n return window.innerWidth < breakpoint\r\n })\r\n\r\n useEffect(() => {\r\n // Throttle: max 1 check cada 250ms para evitar re-renders excesivos\r\n const checkMobile = throttle(() => {\r\n setIsMobile(window.innerWidth < breakpoint)\r\n }, 250)\r\n\r\n window.addEventListener('resize', checkMobile)\r\n return () => window.removeEventListener('resize', checkMobile)\r\n }, [breakpoint])\r\n\r\n return isMobile\r\n}\r\n","'use client'\r\n\r\nimport { useState, useEffect, useCallback } from 'react'\r\nimport { useIsMobile } from './useIsMobile'\r\n\r\ninterface DynamicHeightOptions {\r\n isOpen: boolean\r\n headerHeight?: number\r\n marginTop?: number\r\n height?: string // Altura personalizada (ej: '600px', '80vh')\r\n bottom?: string // Distancia desde bottom (ej: '24px', '1.5rem')\r\n}\r\n\r\nconst DESKTOP_MAX_HEIGHT = 700\r\nconst DESKTOP_MIN_HEIGHT = 500\r\nconst DESKTOP_MARGIN_TOP = 64 // 4rem\r\nconst DEFAULT_BOTTOM = '24px'\r\n\r\nexport function useDynamicHeight({ isOpen, height, bottom }: DynamicHeightOptions) {\r\n const isMobile = useIsMobile()\r\n const [dynamicHeight, setDynamicHeight] = useState<React.CSSProperties>({})\r\n\r\n const calculateHeight = useCallback(() => {\r\n if (isMobile) {\r\n // En móvil, usamos el visual viewport para ajustarnos al teclado\r\n const updateMobileHeight = () => {\r\n if (window.visualViewport) {\r\n setDynamicHeight({\r\n height: `${window.visualViewport.height}px`,\r\n width: '100%',\r\n top: `${window.visualViewport.offsetTop}px`,\r\n left: '0px',\r\n bottom: 'auto',\r\n right: 'auto',\r\n transform: 'none',\r\n })\r\n } else {\r\n // Fallback para navegadores sin visualViewport\r\n setDynamicHeight({\r\n height: '100dvh',\r\n width: '100%',\r\n top: '0px',\r\n left: '0px',\r\n })\r\n }\r\n }\r\n\r\n updateMobileHeight()\r\n window.visualViewport?.addEventListener('resize', updateMobileHeight)\r\n window.visualViewport?.addEventListener('scroll', updateMobileHeight)\r\n\r\n return () => {\r\n window.visualViewport?.removeEventListener('resize', updateMobileHeight)\r\n window.visualViewport?.removeEventListener('scroll', updateMobileHeight)\r\n }\r\n } else {\r\n // En desktop, usar altura personalizada o calcular dinámicamente\r\n // Solo usamos bottom - el widget crece hacia arriba\r\n const bottomPx = parseFloat(bottom || DEFAULT_BOTTOM) || 24\r\n // Calcular la altura máxima disponible desde bottom hasta el margen superior\r\n const maxAvailableHeight = window.innerHeight - DESKTOP_MARGIN_TOP - bottomPx\r\n \r\n if (height) {\r\n // Si hay altura personalizada, usarla pero limitar al máximo disponible\r\n const heightValue = parseFloat(height) || DESKTOP_MAX_HEIGHT\r\n const clampedHeight = Math.min(heightValue, maxAvailableHeight)\r\n \r\n setDynamicHeight({\r\n height: `${clampedHeight}px`,\r\n maxHeight: `${maxAvailableHeight}px`,\r\n bottom: bottom || DEFAULT_BOTTOM,\r\n })\r\n } else {\r\n // Calcular altura disponible dinámicamente\r\n const calculatedHeight = Math.min(\r\n DESKTOP_MAX_HEIGHT,\r\n Math.max(DESKTOP_MIN_HEIGHT, maxAvailableHeight)\r\n )\r\n\r\n setDynamicHeight({\r\n height: `${calculatedHeight}px`,\r\n maxHeight: `${maxAvailableHeight}px`,\r\n bottom: bottom || DEFAULT_BOTTOM,\r\n })\r\n }\r\n }\r\n }, [isMobile, height, bottom])\r\n\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const cleanup = calculateHeight()\r\n\r\n window.addEventListener('resize', calculateHeight)\r\n\r\n return () => {\r\n window.removeEventListener('resize', calculateHeight)\r\n if (cleanup) cleanup()\r\n }\r\n }, [isOpen, calculateHeight])\r\n\r\n return dynamicHeight\r\n}\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * Voice Call Overlay Component\r\n *\r\n * Real-time voice call overlay using Gemini Live API via Socket.IO.\r\n * Sends raw PCM 16kHz audio chunks and receives PCM 24kHz audio responses.\r\n *\r\n * Flow: User Mic (PCM 16kHz) → Socket.IO → Backend → Gemini Live API → \r\n * PCM 24kHz audio → Socket.IO → Web Audio API playback\r\n */\r\n\r\n'use client'\r\n\r\nimport { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, Component, type ReactNode } from 'react'\r\nimport { cn } from '@/lib/utils'\r\nimport { PhoneOff, Mic, MicOff, Volume2, Keyboard, Send } from 'lucide-react'\r\nimport ReactMarkdown from 'react-markdown'\r\nimport remarkGfm from 'remark-gfm'\r\nimport rehypeSanitize from 'rehype-sanitize'\r\nimport type { EmotionAvatarMap } from './Launcher'\r\nimport { DEFAULT_AVATAR_URL } from '../utils/defaultAssets'\r\n\r\n// Lazy-loaded 3D avatar — separate chunk, 0KB impact on main bundle\r\nconst Avatar3D = lazy(() => import('./Avatar3D'))\r\n\r\n/** Configurable voice call overlay options */\r\nexport interface VoiceOverlayConfig {\r\n /** Background color of the overlay. Default: '#0a0a0a' */\r\n backgroundColor?: string\r\n /** Glow color when listening. Default: '#10b981' (emerald) */\r\n listeningColor?: string\r\n /** Glow color when speaking. Default: uses primaryColor */\r\n speakingColor?: string\r\n /** Glow color when thinking. Default: '#a855f7' (purple) */\r\n thinkingColor?: string\r\n /** Show emojis for emotions when no avatar is provided. Default: true */\r\n showEmojis?: boolean\r\n /** Show the emotion text label on the avatar/header. Default: true */\r\n showEmotionLabel?: boolean\r\n /** Show waveform bars visualizer. Default: true */\r\n showWaveform?: boolean\r\n /** Show the \"Gemini Live\" badge. Default: true */\r\n showBadge?: boolean\r\n /** Custom badge text. Default: 'Gemini Live' */\r\n badgeText?: string\r\n /** Custom emoji map overrides. Merged with defaults. */\r\n emotionEmojis?: Partial<Record<string, string>>\r\n /** Custom status labels per state */\r\n statusLabels?: Partial<Record<CallState, string>>\r\n /** Avatar orb size in px. Default: 128 */\r\n orbSize?: number\r\n /** Scale factor when speaking. Default: 1.08 */\r\n speakingScale?: number\r\n /** Scale factor when thinking. Default: 0.95 */\r\n thinkingScale?: number\r\n /** URL to a .vrm/.glb 3D model. When set, replaces 2D avatar with 3D. */\r\n avatar3dUrl?: string\r\n}\r\n\r\ninterface VoiceCallOverlayProps {\r\n isOpen: boolean\r\n onClose: () => void\r\n primaryColor?: string\r\n getSocket?: () => any\r\n avatars?: EmotionAvatarMap\r\n logoUrl?: string\r\n /** URL to a .vrm/.glb 3D model for the avatar */\r\n avatar3dUrl?: string\r\n /** Voice overlay configuration for full customizability */\r\n voiceConfig?: VoiceOverlayConfig\r\n /** Callback to persist voice transcripts to the main chat history */\r\n onAddMessage?: (message: { sender: 'user' | 'bot'; content: string }) => void\r\n}\r\n\r\ntype CallState = 'idle' | 'connecting' | 'listening' | 'speaking' | 'thinking'\r\n\r\ninterface VoiceEntry {\r\n role: 'user' | 'bot'\r\n text: string\r\n}\r\n\r\nconst DEFAULT_EMOTION_EMOJIS: Record<string, string> = {\r\n happy: '😊', wink: '😉', thinking: '🤔', sad: '😢', excited: '🤩',\r\n love: '❤️', laugh: '😄', surprised: '😲', angry: '😠', confused: '😕',\r\n sorry: '😔', default: '💬',\r\n}\r\n\r\nconst DEFAULT_STATUS_LABELS: Record<CallState, string> = {\r\n idle: 'Llamada de voz',\r\n connecting: 'Conectando...',\r\n listening: 'Escuchando...',\r\n thinking: 'Pensando...',\r\n speaking: 'Hablando...',\r\n}\r\n\r\n/** Sanitize config for voice transcript markdown */\r\nconst voiceSanitizeSchema = {\r\n tagNames: ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li', 'br', 'span', 'code'],\r\n attributes: {\r\n a: ['href', 'target', 'rel'],\r\n span: ['className'],\r\n code: ['className'],\r\n },\r\n protocols: {\r\n a: { href: ['http', 'https', 'mailto', 'tel'] },\r\n },\r\n}\r\n\r\nconst INPUT_SAMPLE_RATE = 16000\r\nconst OUTPUT_SAMPLE_RATE = 24000\r\n\r\n// Inline AudioWorklet processor for PCM capture at 16kHz\r\nconst AUDIO_PROCESSOR_CODE = `\r\nclass VoicePCMProcessor extends AudioWorkletProcessor {\r\n constructor() {\r\n super();\r\n this.buffer = new Float32Array(1600); // 100ms at 16kHz\r\n this.bufferIndex = 0;\r\n }\r\n process(inputs) {\r\n const input = inputs[0]?.[0];\r\n if (!input) return true;\r\n for (let i = 0; i < input.length; i++) {\r\n this.buffer[this.bufferIndex++] = input[i];\r\n if (this.bufferIndex >= 1600) {\r\n // Convert Float32 → Int16 PCM\r\n const int16 = new Int16Array(1600);\r\n for (let j = 0; j < 1600; j++) {\r\n const s = Math.max(-1, Math.min(1, this.buffer[j]));\r\n int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF;\r\n }\r\n this.port.postMessage(int16.buffer, [int16.buffer]);\r\n this.buffer = new Float32Array(1600);\r\n this.bufferIndex = 0;\r\n }\r\n }\r\n return true;\r\n }\r\n}\r\nregisterProcessor('voice-pcm-processor', VoicePCMProcessor);\r\n`\r\n\r\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\r\n const bytes = new Uint8Array(buffer)\r\n let binary = ''\r\n for (let i = 0; i < bytes.byteLength; i++) {\r\n binary += String.fromCharCode(bytes[i])\r\n }\r\n return btoa(binary)\r\n}\r\n\r\nfunction base64ToFloat32(base64: string): Float32Array {\r\n const binary = atob(base64)\r\n const bytes = new Uint8Array(binary.length)\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i)\r\n }\r\n const int16 = new Int16Array(bytes.buffer)\r\n const float32 = new Float32Array(int16.length)\r\n for (let i = 0; i < int16.length; i++) {\r\n float32[i] = int16[i] / 0x8000\r\n }\r\n return float32\r\n}\r\n\r\n// ═══════════════════════════════════════\r\n// AVATAR ORB — Emotion-reactive centerpiece for voice calls\r\n// ═══════════════════════════════════════\r\ninterface AvatarOrbProps {\r\n avatars?: EmotionAvatarMap\r\n logoUrl?: string\r\n avatar3dUrl?: string\r\n emotion: string | null\r\n callState: CallState\r\n audioLevel: number\r\n config: Required_VoiceOverlayConfig\r\n}\r\n\r\n/** Resolved config with all defaults applied */\r\ntype Required_VoiceOverlayConfig = {\r\n backgroundColor: string\r\n listeningColor: string\r\n speakingColor: string\r\n thinkingColor: string\r\n showEmojis: boolean\r\n showEmotionLabel: boolean\r\n showWaveform: boolean\r\n showBadge: boolean\r\n badgeText: string\r\n emotionEmojis: Record<string, string>\r\n statusLabels: Record<CallState, string>\r\n orbSize: number\r\n speakingScale: number\r\n thinkingScale: number\r\n avatar3dUrl?: string\r\n}\r\n\r\nfunction resolveVoiceConfig(cfg?: VoiceOverlayConfig, primaryColor = '#10b981'): Required_VoiceOverlayConfig {\r\n return {\r\n backgroundColor: cfg?.backgroundColor ?? '#0a0a0a',\r\n listeningColor: cfg?.listeningColor ?? '#10b981',\r\n speakingColor: cfg?.speakingColor ?? primaryColor,\r\n thinkingColor: cfg?.thinkingColor ?? '#a855f7',\r\n showEmojis: cfg?.showEmojis ?? true,\r\n showEmotionLabel: cfg?.showEmotionLabel ?? true,\r\n showWaveform: cfg?.showWaveform ?? true,\r\n showBadge: cfg?.showBadge ?? false,\r\n badgeText: cfg?.badgeText ?? '',\r\n emotionEmojis: { ...DEFAULT_EMOTION_EMOJIS, ...(cfg?.emotionEmojis as Record<string, string> | undefined) },\r\n statusLabels: { ...DEFAULT_STATUS_LABELS, ...(cfg?.statusLabels as Record<CallState, string> | undefined) },\r\n orbSize: cfg?.orbSize ?? 128,\r\n speakingScale: cfg?.speakingScale ?? 1.08,\r\n thinkingScale: cfg?.thinkingScale ?? 0.95,\r\n avatar3dUrl: cfg?.avatar3dUrl,\r\n }\r\n}\r\n\r\n/** Error boundary for Avatar3D — falls back silently when Three.js fails */\r\nclass Avatar3DErrorBoundary extends Component<\r\n { children: ReactNode; onError: () => void },\r\n { hasError: boolean }\r\n> {\r\n constructor(props: { children: ReactNode; onError: () => void }) {\r\n super(props)\r\n this.state = { hasError: false }\r\n }\r\n static getDerivedStateFromError() {\r\n return { hasError: true }\r\n }\r\n componentDidCatch(error: Error) {\r\n console.warn('[Avatar3D] Three.js failed, falling back to 2D orb:', error.message)\r\n this.props.onError()\r\n }\r\n render() {\r\n if (this.state.hasError) return null\r\n return this.props.children\r\n }\r\n}\r\n\r\nfunction AvatarOrb({ avatars, logoUrl, avatar3dUrl, emotion, callState, audioLevel, config }: AvatarOrbProps) {\r\n const hasAvatars = avatars && Object.keys(avatars).length > 0\r\n const hasLogo = !!logoUrl\r\n const [avatar3dFailed, setAvatar3dFailed] = useState(false)\r\n\r\n // ── ALL HOOKS MUST BE CALLED BEFORE ANY CONDITIONAL RETURNS ──\r\n // Resolve avatar URL from emotion — same logic as Launcher\r\n const avatarUrl = useMemo(() => {\r\n if (!hasAvatars && !hasLogo) return null\r\n if (hasAvatars) {\r\n const emotionKey = (emotion || 'default') as keyof EmotionAvatarMap\r\n return avatars![emotionKey] || avatars!.default || logoUrl || DEFAULT_AVATAR_URL\r\n }\r\n return logoUrl || DEFAULT_AVATAR_URL\r\n }, [hasAvatars, hasLogo, avatars, emotion, logoUrl])\r\n\r\n const isActive = callState === 'listening' || callState === 'speaking'\r\n const glowColor = callState === 'speaking' ? config.speakingColor\r\n : callState === 'thinking' ? config.thinkingColor\r\n : callState === 'listening' ? config.listeningColor\r\n : '#ffffff20'\r\n\r\n const scale = callState === 'speaking' ? config.speakingScale\r\n : callState === 'thinking' ? config.thinkingScale\r\n : 1\r\n\r\n const orbPx = config.orbSize\r\n\r\n // ── 3D AVATAR PATH (lazy loaded, with graceful fallback) ──\r\n if (avatar3dUrl && !avatar3dFailed) {\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4\">\r\n <Avatar3DErrorBoundary onError={() => setAvatar3dFailed(true)}>\r\n <Suspense\r\n fallback={\r\n <div\r\n className=\"rounded-full flex items-center justify-center animate-pulse\"\r\n style={{\r\n width: `${config.orbSize}px`,\r\n height: `${config.orbSize}px`,\r\n background: `radial-gradient(circle at 35% 35%, ${config.speakingColor}40, ${config.speakingColor}10 60%, transparent 80%)`,\r\n boxShadow: `0 0 30px ${config.speakingColor}15`,\r\n }}\r\n />\r\n }\r\n >\r\n <Avatar3D\r\n modelUrl={avatar3dUrl}\r\n emotion={emotion}\r\n callState={callState}\r\n audioLevel={audioLevel}\r\n primaryColor={config.speakingColor}\r\n size={config.orbSize}\r\n />\r\n </Suspense>\r\n </Avatar3DErrorBoundary>\r\n {config.showWaveform && (\r\n <WaveformBars\r\n isActive={callState === 'listening' || callState === 'speaking'}\r\n audioLevel={audioLevel}\r\n color={callState === 'speaking' ? config.speakingColor : callState === 'thinking' ? config.thinkingColor : config.listeningColor}\r\n />\r\n )}\r\n </div>\r\n )\r\n }\r\n\r\n // If no avatar configured, show premium animated orb\r\n if (!avatarUrl) {\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-6\">\r\n {/* Orbital rings */}\r\n <div className=\"relative\" style={{ width: `${orbPx + 48}px`, height: `${orbPx + 48}px` }}>\r\n {/* Outer orbit */}\r\n <div\r\n className=\"absolute inset-0 rounded-full\"\r\n style={{\r\n border: `1.5px solid ${glowColor}20`,\r\n animation: isActive ? 'spin 8s linear infinite' : 'none',\r\n }}\r\n />\r\n {/* Middle orbit */}\r\n <div\r\n className=\"absolute rounded-full\"\r\n style={{\r\n inset: '12px',\r\n border: `1px solid ${glowColor}15`,\r\n animation: isActive ? 'spin 12s linear infinite reverse' : 'none',\r\n }}\r\n />\r\n {/* Center orb */}\r\n <div\r\n className=\"absolute rounded-full flex items-center justify-center\"\r\n style={{\r\n inset: '24px',\r\n background: `radial-gradient(circle at 35% 35%, ${glowColor}40, ${glowColor}10 60%, transparent 80%)`,\r\n boxShadow: isActive\r\n ? `0 0 60px ${glowColor}35, 0 0 120px ${glowColor}15, inset 0 0 40px ${glowColor}10`\r\n : `0 0 30px ${glowColor}15`,\r\n transform: `scale(${scale})`,\r\n transition: 'all 0.5s cubic-bezier(0.4, 0, 0.2, 1)',\r\n }}\r\n >\r\n {/* Inner glow dot */}\r\n <div\r\n className=\"rounded-full\"\r\n style={{\r\n width: `${orbPx * 0.35}px`,\r\n height: `${orbPx * 0.35}px`,\r\n background: `radial-gradient(circle, ${glowColor}90, ${glowColor}40)`,\r\n boxShadow: `0 0 20px ${glowColor}60`,\r\n animation: isActive ? 'pulse 2s ease-in-out infinite' : 'none',\r\n }}\r\n />\r\n </div>\r\n {/* Orbiting dots */}\r\n {isActive && [0, 1, 2].map(i => (\r\n <div\r\n key={i}\r\n className=\"absolute rounded-full\"\r\n style={{\r\n width: '4px',\r\n height: '4px',\r\n backgroundColor: glowColor,\r\n opacity: 0.6,\r\n top: '50%',\r\n left: '50%',\r\n transform: `rotate(${i * 120 + (Date.now() / 20) % 360}deg) translateX(${(orbPx + 48) / 2}px)`,\r\n animation: `spin ${6 + i * 2}s linear infinite`,\r\n boxShadow: `0 0 6px ${glowColor}`,\r\n }}\r\n />\r\n ))}\r\n </div>\r\n {/* Waveform bars */}\r\n {config.showWaveform && (\r\n <WaveformBars isActive={isActive} audioLevel={audioLevel} color={glowColor} />\r\n )}\r\n </div>\r\n )\r\n }\r\n\r\n // Avatar orb with emotion switching\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4\">\r\n {/* Outer glow ring */}\r\n <div\r\n className={cn(\r\n 'relative rounded-full flex items-center justify-center',\r\n 'transition-all duration-500 ease-out',\r\n )}\r\n style={{\r\n width: `${orbPx}px`,\r\n height: `${orbPx}px`,\r\n boxShadow: isActive\r\n ? `0 0 0 4px ${glowColor}40, 0 0 30px ${glowColor}30, 0 0 60px ${glowColor}15`\r\n : `0 0 0 2px ${glowColor}20`,\r\n transform: `scale(${scale})`,\r\n }}\r\n >\r\n {/* Avatar image */}\r\n <img\r\n src={avatarUrl}\r\n alt=\"Bot avatar\"\r\n className={cn(\r\n 'h-full w-full rounded-full object-cover',\r\n 'transition-all duration-300',\r\n callState === 'thinking' && 'opacity-80',\r\n )}\r\n style={{\r\n boxShadow: callState === 'listening'\r\n ? `0 0 0 2px ${config.listeningColor}80`\r\n : callState === 'speaking'\r\n ? `0 0 0 2px ${config.speakingColor}80`\r\n : 'none',\r\n }}\r\n />\r\n {/* Emotion label overlay */}\r\n {config.showEmotionLabel && emotion && (\r\n <div className=\"absolute -bottom-1 left-1/2 -translate-x-1/2 px-2 py-0.5 rounded-full bg-black/70 backdrop-blur-sm text-[10px] font-bold text-white whitespace-nowrap\">\r\n {config.showEmojis && (config.emotionEmojis[emotion] || '💬')} {emotion}\r\n </div>\r\n )}\r\n </div>\r\n {/* Waveform bars */}\r\n {config.showWaveform && (\r\n <WaveformBars isActive={isActive} audioLevel={audioLevel} color={glowColor} />\r\n )}\r\n </div>\r\n )\r\n}\r\n\r\n/** Reusable waveform bars component — premium style */\r\nfunction WaveformBars({ isActive, audioLevel, color }: { isActive: boolean; audioLevel: number; color: string }) {\r\n return (\r\n <div className=\"flex items-center gap-[3px] h-10\">\r\n {Array.from({ length: 12 }).map((_, i) => {\r\n const center = 5.5\r\n const dist = Math.abs(i - center) / center\r\n const h = isActive\r\n ? Math.max(4, audioLevel * 40 * (1 - dist * 0.5) * (0.5 + Math.sin(Date.now() / 100 + i * 0.8) * 0.5))\r\n : 4\r\n return (\r\n <div key={i} className=\"rounded-full transition-all duration-100\"\r\n style={{\r\n width: '3px',\r\n height: `${h}px`,\r\n backgroundColor: color,\r\n opacity: isActive ? 0.7 - dist * 0.3 : 0.2,\r\n }} />\r\n )\r\n })}\r\n </div>\r\n )\r\n}\r\n\r\nexport function VoiceCallOverlay({\r\n isOpen,\r\n onClose,\r\n primaryColor = '#10b981',\r\n getSocket,\r\n avatars,\r\n logoUrl,\r\n avatar3dUrl,\r\n voiceConfig,\r\n onAddMessage,\r\n}: VoiceCallOverlayProps) {\r\n // Resolve all config defaults once\r\n const cfg = useMemo(() => resolveVoiceConfig(voiceConfig, primaryColor), [voiceConfig, primaryColor])\r\n\r\n const [callState, setCallState] = useState<CallState>('idle')\r\n const [duration, setDuration] = useState(0)\r\n const [isMuted, setIsMuted] = useState(false)\r\n const [audioLevel, setAudioLevel] = useState(0)\r\n const [currentEmotion, setCurrentEmotion] = useState<string | null>(null)\r\n const [conversation, setConversation] = useState<VoiceEntry[]>([])\r\n const [showTextInput, setShowTextInput] = useState(false)\r\n const [textInputValue, setTextInputValue] = useState('')\r\n\r\n const timerRef = useRef<NodeJS.Timeout | null>(null)\r\n const analyserRef = useRef<AnalyserNode | null>(null)\r\n const streamRef = useRef<MediaStream | null>(null)\r\n const audioCtxRef = useRef<AudioContext | null>(null)\r\n const workletNodeRef = useRef<AudioWorkletNode | null>(null)\r\n const animFrameRef = useRef<number>(0)\r\n const socketListenersRef = useRef(false)\r\n const processorUrlRef = useRef<string | null>(null)\r\n const conversationEndRef = useRef<HTMLDivElement>(null)\r\n\r\n // Audio playback — gapless scheduling\r\n const playbackCtxRef = useRef<AudioContext | null>(null)\r\n const audioQueueRef = useRef<Float32Array[]>([])\r\n const isPlayingRef = useRef(false)\r\n const nextPlayTimeRef = useRef(0) // Schedule cursor for gapless playback\r\n const activeSourcesRef = useRef<AudioBufferSourceNode[]>([])\r\n\r\n // Format duration as MM:SS\r\n const formatDuration = useCallback((seconds: number): string => {\r\n const mins = Math.floor(seconds / 60)\r\n const secs = seconds % 60\r\n return `${mins}:${secs.toString().padStart(2, '0')}`\r\n }, [])\r\n\r\n // ═══════════════════════════════════════\r\n // AUDIO PLAYBACK — Gapless PCM 24kHz scheduling\r\n // ═══════════════════════════════════════\r\n const scheduleChunks = useCallback(() => {\r\n if (audioQueueRef.current.length === 0) return\r\n\r\n if (!playbackCtxRef.current || playbackCtxRef.current.state === 'closed') {\r\n playbackCtxRef.current = new AudioContext({ sampleRate: OUTPUT_SAMPLE_RATE })\r\n }\r\n\r\n const ctx = playbackCtxRef.current\r\n isPlayingRef.current = true\r\n setCallState('speaking')\r\n\r\n // Ensure the schedule cursor is at least \"now\"\r\n const now = ctx.currentTime\r\n if (nextPlayTimeRef.current < now) {\r\n nextPlayTimeRef.current = now\r\n }\r\n\r\n // Schedule all queued chunks back-to-back\r\n while (audioQueueRef.current.length > 0) {\r\n const float32Data = audioQueueRef.current.shift()!\r\n const buffer = ctx.createBuffer(1, float32Data.length, OUTPUT_SAMPLE_RATE)\r\n buffer.getChannelData(0).set(float32Data)\r\n\r\n const source = ctx.createBufferSource()\r\n source.buffer = buffer\r\n source.connect(ctx.destination)\r\n source.start(nextPlayTimeRef.current)\r\n\r\n // Track active sources for cleanup on interrupt\r\n activeSourcesRef.current.push(source)\r\n source.onended = () => {\r\n activeSourcesRef.current = activeSourcesRef.current.filter(s => s !== source)\r\n // When the last source finishes and no more queued → back to listening\r\n if (activeSourcesRef.current.length === 0 && audioQueueRef.current.length === 0) {\r\n isPlayingRef.current = false\r\n setCallState(prev => prev === 'speaking' ? 'listening' : prev)\r\n }\r\n }\r\n\r\n // Advance cursor by chunk duration (samples / sampleRate)\r\n nextPlayTimeRef.current += float32Data.length / OUTPUT_SAMPLE_RATE\r\n }\r\n }, [])\r\n\r\n // ═══════════════════════════════════════\r\n // SOCKET EVENT LISTENERS\r\n // ═══════════════════════════════════════\r\n const voiceListenersRef = useRef<{\r\n voiceReady?: (d: any) => void\r\n voiceAudioChunk?: (d: any) => void\r\n voiceInterrupted?: () => void\r\n voiceTurnComplete?: () => void\r\n voiceError?: (d: any) => void\r\n voiceEmotion?: (d: any) => void\r\n voiceUserTranscript?: (d: any) => void\r\n voiceModelTranscript?: (d: any) => void\r\n voiceModelThinking?: () => void\r\n }>({})\r\n\r\n const setupSocketListeners = useCallback(() => {\r\n const socket = getSocket?.()\r\n if (!socket || socketListenersRef.current) return\r\n\r\n const onVoiceReady = () => {\r\n setCallState('listening')\r\n }\r\n\r\n const onVoiceAudioChunk = (data: { data: string; sampleRate?: number }) => {\r\n if (!data?.data) return\r\n const pcmFloat32 = base64ToFloat32(data.data)\r\n audioQueueRef.current.push(pcmFloat32)\r\n // Schedule immediately — gapless scheduling handles timing\r\n scheduleChunks()\r\n }\r\n\r\n const onVoiceInterrupted = () => {\r\n // Barge-in: stop all scheduled sources + clear queue\r\n activeSourcesRef.current.forEach(s => { try { s.stop() } catch {} })\r\n activeSourcesRef.current = []\r\n audioQueueRef.current.length = 0\r\n nextPlayTimeRef.current = 0\r\n isPlayingRef.current = false\r\n setCallState('listening')\r\n }\r\n\r\n const onVoiceTurnComplete = () => {\r\n // Model finished speaking, playback may still be in queue\r\n }\r\n\r\n const onVoiceError = (data: any) => {\r\n console.error('[VoiceCall] Voice error:', data)\r\n }\r\n\r\n const onVoiceEmotion = (data: { emotion: string }) => {\r\n if (data?.emotion) {\r\n setCurrentEmotion(data.emotion)\r\n setTimeout(() => setCurrentEmotion(prev => prev === data.emotion ? null : prev), 4000)\r\n }\r\n }\r\n\r\n const onVoiceUserTranscript = (data: { text: string }) => {\r\n if (!data?.text) return\r\n setConversation(prev => {\r\n if (prev.length > 0 && prev[prev.length - 1].role === 'user') {\r\n const updated = [...prev]\r\n const existing = updated[updated.length - 1].text\r\n // Add space between fragments if neither ends/starts with one\r\n const needsSpace = existing.length > 0 && !existing.endsWith(' ') && !data.text.startsWith(' ')\r\n updated[updated.length - 1] = { ...updated[updated.length - 1], text: existing + (needsSpace ? ' ' : '') + data.text }\r\n return updated\r\n }\r\n return [...prev, { role: 'user', text: data.text }]\r\n })\r\n }\r\n\r\n const onVoiceModelTranscript = (data: { text: string }) => {\r\n if (!data?.text) return\r\n setConversation(prev => {\r\n if (prev.length > 0 && prev[prev.length - 1].role === 'bot') {\r\n const updated = [...prev]\r\n const existing = updated[updated.length - 1].text\r\n // Add space between fragments if neither ends/starts with one\r\n const needsSpace = existing.length > 0 && !existing.endsWith(' ') && !data.text.startsWith(' ')\r\n updated[updated.length - 1] = { ...updated[updated.length - 1], text: existing + (needsSpace ? ' ' : '') + data.text }\r\n return updated\r\n }\r\n return [...prev, { role: 'bot', text: data.text }]\r\n })\r\n }\r\n\r\n const onVoiceModelThinking = () => {\r\n setCallState('thinking')\r\n }\r\n\r\n voiceListenersRef.current = {\r\n voiceReady: onVoiceReady,\r\n voiceAudioChunk: onVoiceAudioChunk,\r\n voiceInterrupted: onVoiceInterrupted,\r\n voiceTurnComplete: onVoiceTurnComplete,\r\n voiceError: onVoiceError,\r\n voiceEmotion: onVoiceEmotion,\r\n voiceUserTranscript: onVoiceUserTranscript,\r\n voiceModelTranscript: onVoiceModelTranscript,\r\n voiceModelThinking: onVoiceModelThinking,\r\n }\r\n\r\n socket.on('voice_ready', onVoiceReady)\r\n socket.on('voice_audio_chunk', onVoiceAudioChunk)\r\n socket.on('voice_interrupted', onVoiceInterrupted)\r\n socket.on('voice_turn_complete', onVoiceTurnComplete)\r\n socket.on('voice_error', onVoiceError)\r\n socket.on('voice_emotion', onVoiceEmotion)\r\n socket.on('voice_user_transcript', onVoiceUserTranscript)\r\n socket.on('voice_model_transcript', onVoiceModelTranscript)\r\n socket.on('voice_model_thinking', onVoiceModelThinking)\r\n\r\n socketListenersRef.current = true\r\n }, [getSocket, scheduleChunks])\r\n\r\n const removeSocketListeners = useCallback(() => {\r\n const socket = getSocket?.()\r\n if (!socket || !socketListenersRef.current) return\r\n\r\n const l = voiceListenersRef.current\r\n if (l.voiceReady) socket.off('voice_ready', l.voiceReady)\r\n if (l.voiceAudioChunk) socket.off('voice_audio_chunk', l.voiceAudioChunk)\r\n if (l.voiceInterrupted) socket.off('voice_interrupted', l.voiceInterrupted)\r\n if (l.voiceTurnComplete) socket.off('voice_turn_complete', l.voiceTurnComplete)\r\n if (l.voiceError) socket.off('voice_error', l.voiceError)\r\n if (l.voiceEmotion) socket.off('voice_emotion', l.voiceEmotion)\r\n if (l.voiceUserTranscript) socket.off('voice_user_transcript', l.voiceUserTranscript)\r\n if (l.voiceModelTranscript) socket.off('voice_model_transcript', l.voiceModelTranscript)\r\n if (l.voiceModelThinking) socket.off('voice_model_thinking', l.voiceModelThinking)\r\n\r\n voiceListenersRef.current = {}\r\n socketListenersRef.current = false\r\n }, [getSocket])\r\n\r\n // ═══════════════════════════════════════\r\n // MIC CAPTURE — PCM 16kHz via AudioWorklet\r\n // ═══════════════════════════════════════\r\n const startMicCapture = useCallback(async () => {\r\n const socket = getSocket?.()\r\n if (!socket) return\r\n\r\n const stream = await navigator.mediaDevices.getUserMedia({\r\n audio: {\r\n sampleRate: INPUT_SAMPLE_RATE,\r\n channelCount: 1,\r\n echoCancellation: true,\r\n noiseSuppression: true,\r\n autoGainControl: true,\r\n },\r\n })\r\n streamRef.current = stream\r\n\r\n const ctx = new AudioContext({ sampleRate: INPUT_SAMPLE_RATE })\r\n audioCtxRef.current = ctx\r\n const source = ctx.createMediaStreamSource(stream)\r\n\r\n // Analyser for visualization\r\n const analyser = ctx.createAnalyser()\r\n analyser.fftSize = 256\r\n source.connect(analyser)\r\n analyserRef.current = analyser\r\n\r\n // Create processor URL\r\n if (!processorUrlRef.current) {\r\n const blob = new Blob([AUDIO_PROCESSOR_CODE], { type: 'application/javascript' })\r\n processorUrlRef.current = URL.createObjectURL(blob)\r\n }\r\n\r\n await ctx.audioWorklet.addModule(processorUrlRef.current)\r\n const workletNode = new AudioWorkletNode(ctx, 'voice-pcm-processor')\r\n workletNodeRef.current = workletNode\r\n\r\n // Send PCM chunks to Socket.IO\r\n workletNode.port.onmessage = (e: MessageEvent<ArrayBuffer>) => {\r\n if (socket.connected && !isMuted) {\r\n const base64 = arrayBufferToBase64(e.data)\r\n socket.emit('voice_audio_chunk', { data: base64 })\r\n }\r\n }\r\n\r\n source.connect(workletNode)\r\n\r\n // Start visualization loop\r\n const updateLevel = () => {\r\n if (!analyserRef.current) return\r\n const data = new Uint8Array(analyserRef.current.frequencyBinCount)\r\n analyserRef.current.getByteFrequencyData(data)\r\n const avg = data.reduce((a, b) => a + b, 0) / data.length\r\n setAudioLevel(avg / 255)\r\n animFrameRef.current = requestAnimationFrame(updateLevel)\r\n }\r\n updateLevel()\r\n }, [getSocket, isMuted])\r\n\r\n const stopMicCapture = useCallback(() => {\r\n cancelAnimationFrame(animFrameRef.current)\r\n workletNodeRef.current?.disconnect()\r\n workletNodeRef.current = null\r\n streamRef.current?.getTracks().forEach(t => t.stop())\r\n streamRef.current = null\r\n audioCtxRef.current?.close()\r\n audioCtxRef.current = null\r\n analyserRef.current = null\r\n setAudioLevel(0)\r\n }, [])\r\n\r\n // ═══════════════════════════════════════\r\n // CALL LIFECYCLE\r\n // ═══════════════════════════════════════\r\n const startCall = useCallback(async () => {\r\n const socket = getSocket?.()\r\n if (!socket?.connected) {\r\n console.error('[VoiceCall] Socket not connected')\r\n return\r\n }\r\n\r\n setCallState('connecting')\r\n setDuration(0)\r\n setConversation([])\r\n setCurrentEmotion(null)\r\n audioQueueRef.current = []\r\n\r\n // Setup listeners first\r\n setupSocketListeners()\r\n\r\n // Start mic capture\r\n try {\r\n await startMicCapture()\r\n } catch (err) {\r\n console.error('[VoiceCall] Mic error:', err)\r\n setCallState('idle')\r\n return\r\n }\r\n\r\n // Tell backend to create Gemini Live session\r\n socket.emit('voice_start', { language: 'es-AR', voice: 'Kore' })\r\n\r\n // Timer\r\n timerRef.current = setInterval(() => {\r\n setDuration(prev => prev + 1)\r\n }, 1000)\r\n }, [getSocket, setupSocketListeners, startMicCapture])\r\n\r\n const endCall = useCallback(() => {\r\n // Stop mic\r\n stopMicCapture()\r\n\r\n // Stop all scheduled audio sources\r\n activeSourcesRef.current.forEach(s => { try { s.stop() } catch {} })\r\n activeSourcesRef.current = []\r\n audioQueueRef.current = []\r\n nextPlayTimeRef.current = 0\r\n isPlayingRef.current = false\r\n playbackCtxRef.current?.close()\r\n playbackCtxRef.current = null\r\n\r\n // Stop timer\r\n if (timerRef.current) {\r\n clearInterval(timerRef.current)\r\n timerRef.current = null\r\n }\r\n\r\n // Notify backend\r\n const socket = getSocket?.()\r\n if (socket?.connected) socket.emit('voice_stop')\r\n\r\n // Persist voice transcripts to main chat history\r\n if (onAddMessage && conversation.length > 0) {\r\n conversation.forEach(entry => {\r\n onAddMessage({\r\n sender: entry.role === 'user' ? 'user' : 'bot',\r\n content: entry.text,\r\n })\r\n })\r\n }\r\n\r\n // Cleanup\r\n removeSocketListeners()\r\n setCallState('idle')\r\n setAudioLevel(0)\r\n setDuration(0)\r\n setIsMuted(false)\r\n setConversation([])\r\n\r\n onClose()\r\n }, [getSocket, stopMicCapture, removeSocketListeners, onClose, onAddMessage, conversation])\r\n\r\n const toggleMute = useCallback(() => {\r\n setIsMuted(prev => !prev)\r\n }, [])\r\n\r\n /** Send typed text to the voice session via socket */\r\n const sendTextInput = useCallback(() => {\r\n const text = textInputValue.trim()\r\n if (!text) return\r\n const socket = getSocket?.()\r\n if (!socket?.connected) return\r\n\r\n socket.emit('voice_text_input', { text })\r\n setTextInputValue('')\r\n setShowTextInput(false)\r\n }, [textInputValue, getSocket])\r\n\r\n // Start call when overlay opens\r\n useEffect(() => {\r\n if (isOpen && callState === 'idle') {\r\n startCall()\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [isOpen])\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n stopMicCapture()\r\n if (timerRef.current) clearInterval(timerRef.current)\r\n removeSocketListeners()\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [])\r\n\r\n if (!isOpen) return null\r\n\r\n // Derive state-based colors\r\n const stateColor = callState === 'speaking' ? cfg.speakingColor\r\n : callState === 'thinking' ? cfg.thinkingColor\r\n : callState === 'listening' ? cfg.listeningColor\r\n : primaryColor\r\n\r\n return (\r\n <div\r\n className={cn(\r\n 'absolute inset-0 z-50 flex flex-col overflow-hidden',\r\n 'animate-in fade-in duration-300'\r\n )}\r\n style={{ backgroundColor: '#0a0a0f', borderRadius: 'inherit' }}\r\n >\r\n {/* Ambient gradient mesh background */}\r\n <div className=\"absolute inset-0 pointer-events-none\" style={{ overflow: 'hidden' }}>\r\n <div\r\n className=\"absolute rounded-full\"\r\n style={{\r\n width: '300px',\r\n height: '300px',\r\n top: '-80px',\r\n right: '-60px',\r\n background: `radial-gradient(circle, ${stateColor}18 0%, transparent 70%)`,\r\n transition: 'background 1.5s ease',\r\n filter: 'blur(40px)',\r\n }}\r\n />\r\n <div\r\n className=\"absolute rounded-full\"\r\n style={{\r\n width: '250px',\r\n height: '250px',\r\n bottom: '-40px',\r\n left: '-50px',\r\n background: `radial-gradient(circle, ${cfg.thinkingColor}12 0%, transparent 70%)`,\r\n filter: 'blur(50px)',\r\n }}\r\n />\r\n <div\r\n className=\"absolute rounded-full\"\r\n style={{\r\n width: '200px',\r\n height: '200px',\r\n top: '40%',\r\n left: '50%',\r\n transform: 'translateX(-50%)',\r\n background: `radial-gradient(circle, ${stateColor}10 0%, transparent 70%)`,\r\n transition: 'background 1.5s ease',\r\n filter: 'blur(60px)',\r\n }}\r\n />\r\n </div>\r\n\r\n {/* Header — glassmorphism bar */}\r\n <div\r\n className=\"relative flex items-center justify-between\"\r\n style={{\r\n background: 'rgba(255,255,255,0.03)',\r\n borderBottom: '1px solid rgba(255,255,255,0.06)',\r\n padding: '16px 24px',\r\n paddingTop: '20px',\r\n }}\r\n >\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"relative\">\r\n <div\r\n className=\"h-2.5 w-2.5 rounded-full\"\r\n style={{\r\n backgroundColor: stateColor,\r\n boxShadow: `0 0 8px ${stateColor}80`,\r\n animation: callState !== 'idle' ? 'pulse 2s ease-in-out infinite' : 'none',\r\n }}\r\n />\r\n </div>\r\n <span style={{ color: 'rgba(255,255,255,0.8)', fontSize: '13px', fontWeight: 500, letterSpacing: '-0.01em' }}>\r\n {cfg.statusLabels[callState] || callState}\r\n </span>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n {cfg.showEmotionLabel && currentEmotion && (\r\n <span\r\n style={{\r\n fontSize: '11px',\r\n padding: '2px 10px',\r\n borderRadius: '20px',\r\n background: `${stateColor}15`,\r\n border: `1px solid ${stateColor}25`,\r\n color: stateColor,\r\n fontWeight: 600,\r\n }}\r\n >\r\n {cfg.showEmojis && (cfg.emotionEmojis[currentEmotion] || '💬')} {currentEmotion}\r\n </span>\r\n )}\r\n <span style={{\r\n fontSize: '13px',\r\n fontFamily: 'ui-monospace, monospace',\r\n color: 'rgba(255,255,255,0.4)',\r\n fontVariantNumeric: 'tabular-nums',\r\n }}>\r\n {formatDuration(duration)}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n {/* Badge — only if explicitly enabled */}\r\n {cfg.showBadge && cfg.badgeText && (\r\n <div style={{ display: 'flex', justifyContent: 'center', padding: '8px 0' }}>\r\n <span style={{\r\n padding: '4px 14px',\r\n borderRadius: '20px',\r\n fontSize: '11px',\r\n fontWeight: 700,\r\n background: `linear-gradient(135deg, ${primaryColor}, ${cfg.thinkingColor})`,\r\n color: 'white',\r\n }}>\r\n {cfg.badgeText}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Main content — Avatar always on top + last 2 messages below */}\r\n <div className=\"relative flex-1 overflow-y-auto px-5 py-4\" style={{ scrollbarWidth: 'none' }}>\r\n <div className=\"flex flex-col items-center justify-start h-full gap-4\">\r\n {/* Avatar — always visible */}\r\n <AvatarOrb\r\n avatars={avatars}\r\n logoUrl={logoUrl}\r\n avatar3dUrl={avatar3dUrl || cfg.avatar3dUrl}\r\n emotion={currentEmotion}\r\n callState={callState}\r\n audioLevel={audioLevel}\r\n config={cfg}\r\n />\r\n\r\n {/* Last 2 conversation entries */}\r\n {conversation.length > 0 && (\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', width: '100%' }}>\r\n {conversation.slice(-2).map((entry, i) => (\r\n <div\r\n key={i}\r\n style={{\r\n maxWidth: '85%',\r\n padding: '10px 14px',\r\n borderRadius: entry.role === 'user' ? '16px 16px 4px 16px' : '16px 16px 16px 4px',\r\n fontSize: '13.5px',\r\n lineHeight: 1.5,\r\n color: 'white',\r\n marginLeft: entry.role === 'user' ? 'auto' : '0',\r\n marginRight: entry.role === 'user' ? '0' : 'auto',\r\n backgroundColor: entry.role === 'user'\r\n ? 'rgba(255,255,255,0.08)'\r\n : `${primaryColor}25`,\r\n backdropFilter: 'blur(8px)',\r\n border: entry.role === 'user'\r\n ? '1px solid rgba(255,255,255,0.08)'\r\n : `1px solid ${primaryColor}20`,\r\n }}\r\n >\r\n <ReactMarkdown\r\n remarkPlugins={[remarkGfm]}\r\n rehypePlugins={[[rehypeSanitize, voiceSanitizeSchema]]}\r\n components={{\r\n p: ({ children }) => <p style={{ margin: 0 }}>{children}</p>,\r\n a: ({ href, children }) => (\r\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" style={{ color: primaryColor, textDecoration: 'underline' }}>\r\n {children}\r\n </a>\r\n ),\r\n strong: ({ children }) => <strong style={{ fontWeight: 600 }}>{children}</strong>,\r\n em: ({ children }) => <em>{children}</em>,\r\n ul: ({ children }) => <ul style={{ margin: '4px 0', paddingLeft: '18px' }}>{children}</ul>,\r\n ol: ({ children }) => <ol style={{ margin: '4px 0', paddingLeft: '18px' }}>{children}</ol>,\r\n li: ({ children }) => <li style={{ marginBottom: '2px' }}>{children}</li>,\r\n code: ({ children }) => (\r\n <code style={{ background: 'rgba(255,255,255,0.1)', padding: '0 4px', borderRadius: '3px', fontSize: '12px' }}>\r\n {children}\r\n </code>\r\n ),\r\n }}\r\n >\r\n {entry.text}\r\n </ReactMarkdown>\r\n </div>\r\n ))}\r\n <div ref={conversationEndRef} />\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Status pill */}\r\n <div style={{ textAlign: 'center', paddingBottom: '12px' }}>\r\n <span style={{\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n padding: '4px 16px',\r\n borderRadius: '20px',\r\n fontSize: '11px',\r\n fontWeight: 500,\r\n color: 'rgba(255,255,255,0.35)',\r\n background: 'rgba(255,255,255,0.04)',\r\n border: '1px solid rgba(255,255,255,0.06)',\r\n letterSpacing: '0.02em',\r\n }}>\r\n {isMuted ? (\r\n <><MicOff style={{ width: '12px', height: '12px' }} /> Micrófono silenciado</>\r\n ) : callState === 'thinking' ? (\r\n 'Procesando...'\r\n ) : callState === 'speaking' ? (\r\n <><Volume2 style={{ width: '12px', height: '12px' }} /> Respuesta de voz</>\r\n ) : (\r\n 'Habla cuando quieras'\r\n )}\r\n </span>\r\n </div>\r\n\r\n {/* Controls — glassmorphism bar */}\r\n <div\r\n style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '20px',\r\n paddingBottom: '28px',\r\n paddingTop: '8px',\r\n }}\r\n >\r\n {/* Mute button */}\r\n <button\r\n onClick={toggleMute}\r\n style={{\r\n width: '52px',\r\n height: '52px',\r\n borderRadius: '50%',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: 'all 0.2s',\r\n backgroundColor: isMuted ? 'rgba(239,68,68,0.15)' : 'rgba(255,255,255,0.08)',\r\n color: isMuted ? '#f87171' : 'rgba(255,255,255,0.7)',\r\n backdropFilter: 'blur(12px)',\r\n border: `1px solid ${isMuted ? 'rgba(239,68,68,0.2)' : 'rgba(255,255,255,0.08)'}`,\r\n }}\r\n aria-label={isMuted ? 'Activar micrófono' : 'Silenciar micrófono'}\r\n >\r\n {isMuted ? <MicOff style={{ width: '22px', height: '22px' }} /> : <Mic style={{ width: '22px', height: '22px' }} />}\r\n </button>\r\n\r\n {/* End call button — prominent red */}\r\n <button\r\n onClick={endCall}\r\n style={{\r\n width: '64px',\r\n height: '64px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n backgroundColor: '#ef4444',\r\n color: 'white',\r\n boxShadow: '0 4px 24px rgba(239,68,68,0.4), 0 0 0 4px rgba(239,68,68,0.1)',\r\n transition: 'all 0.2s',\r\n }}\r\n aria-label=\"Finalizar llamada\"\r\n >\r\n <PhoneOff style={{ width: '26px', height: '26px' }} />\r\n </button>\r\n\r\n {/* Speaker indicator */}\r\n <div\r\n style={{\r\n width: '52px',\r\n height: '52px',\r\n borderRadius: '50%',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n backgroundColor: callState === 'speaking' ? `${cfg.listeningColor}15` : 'rgba(255,255,255,0.08)',\r\n color: callState === 'speaking' ? cfg.listeningColor : 'rgba(255,255,255,0.5)',\r\n border: `1px solid ${callState === 'speaking' ? `${cfg.listeningColor}25` : 'rgba(255,255,255,0.08)'}`,\r\n transition: 'all 0.3s',\r\n }}\r\n >\r\n <Volume2 style={{ width: '22px', height: '22px' }} />\r\n </div>\r\n\r\n {/* Keyboard button */}\r\n <button\r\n onClick={() => setShowTextInput(prev => !prev)}\r\n style={{\r\n width: '52px',\r\n height: '52px',\r\n borderRadius: '50%',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: 'all 0.2s',\r\n backgroundColor: showTextInput ? `${primaryColor}20` : 'rgba(255,255,255,0.08)',\r\n color: showTextInput ? primaryColor : 'rgba(255,255,255,0.5)',\r\n border: `1px solid ${showTextInput ? `${primaryColor}30` : 'rgba(255,255,255,0.08)'}`,\r\n }}\r\n aria-label=\"Escribir texto\"\r\n >\r\n <Keyboard style={{ width: '20px', height: '20px' }} />\r\n </button>\r\n </div>\r\n\r\n {/* Text input fallback — for structured data */}\r\n {showTextInput && (\r\n <div style={{\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n padding: '8px 20px 20px',\r\n }}>\r\n <input\r\n type=\"text\"\r\n value={textInputValue}\r\n onChange={e => setTextInputValue(e.target.value)}\r\n onKeyDown={e => e.key === 'Enter' && sendTextInput()}\r\n placeholder=\"Escribí email, teléfono, etc.\"\r\n autoFocus\r\n style={{\r\n flex: 1,\r\n padding: '10px 14px',\r\n borderRadius: '12px',\r\n border: '1px solid rgba(255,255,255,0.12)',\r\n background: 'rgba(255,255,255,0.06)',\r\n color: 'white',\r\n fontSize: '13px',\r\n outline: 'none',\r\n backdropFilter: 'blur(8px)',\r\n }}\r\n />\r\n <button\r\n onClick={sendTextInput}\r\n disabled={!textInputValue.trim()}\r\n style={{\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n cursor: textInputValue.trim() ? 'pointer' : 'default',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n backgroundColor: textInputValue.trim() ? primaryColor : 'rgba(255,255,255,0.06)',\r\n color: textInputValue.trim() ? 'white' : 'rgba(255,255,255,0.2)',\r\n transition: 'all 0.2s',\r\n }}\r\n aria-label=\"Enviar texto\"\r\n >\r\n <Send style={{ width: '16px', height: '16px' }} />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* CSS keyframes for orbital animations */}\r\n <style>{`\r\n @keyframes spin {\r\n from { transform: rotate(0deg); }\r\n to { transform: rotate(360deg); }\r\n }\r\n @keyframes pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.7; transform: scale(0.95); }\r\n }\r\n `}</style>\r\n </div>\r\n )\r\n}\r\n","'use client'\r\n\r\nimport { useEffect, useState } from 'react'\r\nimport { useTranslations } from '@/chat-widget/i18n'\r\nimport { X, ShieldCheck, Heart, Phone } from './Icons'\r\nimport { cn } from '@/lib/utils'\r\nimport type { BubbleStyles, ChatMessage, MediaConfig } from '../types'\r\nimport { MessageList } from './MessageList'\r\nimport { InputArea } from './InputArea'\r\nimport { getPrimaryColor } from '../utils/theme'\r\nimport { useIsMobile } from '../hooks/useIsMobile'\r\nimport { useDynamicHeight } from '../hooks/useDynamicHeight'\r\nimport { useFocusTrap } from '../hooks/useFocusTrap'\r\nimport { EmotionAvatarMap } from './Launcher'\r\nimport { DEFAULT_AVATAR_URL } from '../utils/defaultAssets'\r\nimport { VoiceCallOverlay } from './VoiceCallOverlay'\r\n\r\nexport interface ChatWindowProps {\r\n isOpen: boolean\r\n isConnected: boolean\r\n isTyping: boolean\r\n messages: ChatMessage[]\r\n botName?: string\r\n logoUrl?: string\r\n welcomeMessage?: string\r\n inputPlaceholder?: string\r\n primaryColor?: string\r\n borderRadius?: string\r\n mediaConfig?: MediaConfig\r\n onClose: () => void\r\n onSendMessage: (message: string) => void\r\n position?: 'bottom-right' | 'bottom-left'\r\n bubbleStyles?: BubbleStyles\r\n avatars?: EmotionAvatarMap\r\n onSendAttachment?: (file: File, type: 'image' | 'audio' | 'file') => void\r\n onSendLocation?: (location: { latitude: number; longitude: number }) => void\r\n getSocket?: () => any\r\n onAddVoiceMessage?: (message: { sender: 'user' | 'bot'; content: string }) => void\r\n /** URL to a .vrm/.glb 3D model for voice call avatar */\r\n avatar3dUrl?: string\r\n theme?: import('../types').ChatTheme\r\n}\r\n\r\nexport function ChatWindow({\r\n isOpen,\r\n isConnected,\r\n isTyping,\r\n messages,\r\n botName = 'BotUyo',\r\n logoUrl,\r\n welcomeMessage,\r\n inputPlaceholder,\r\n primaryColor,\r\n mediaConfig,\r\n onClose,\r\n onSendMessage,\r\n bubbleStyles,\r\n avatars,\r\n onSendAttachment,\r\n onSendLocation,\r\n getSocket,\r\n onAddVoiceMessage,\r\n avatar3dUrl,\r\n theme,\r\n}: ChatWindowProps) {\r\n const [logoError, setLogoError] = useState(false)\r\n const [showVoiceOverlay, setShowVoiceOverlay] = useState(false)\r\n const { t } = useTranslations()\r\n const isMobile = useIsMobile()\r\n const themePrimary = getPrimaryColor({ primaryColor })\r\n const dynamicHeightStyles = useDynamicHeight({\r\n isOpen,\r\n height: theme?.height,\r\n bottom: theme?.bottom,\r\n })\r\n\r\n // Focus trap para accesibilidad\r\n const dialogRef = useFocusTrap({\r\n enabled: isOpen,\r\n onEscape: onClose,\r\n })\r\n\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n if (isMobile) {\r\n document.body.style.overflow = 'hidden'\r\n document.body.style.position = 'fixed'\r\n document.body.style.width = '100%'\r\n }\r\n\r\n return () => {\r\n document.body.style.overflow = ''\r\n document.body.style.position = ''\r\n document.body.style.width = ''\r\n }\r\n }, [isOpen, isMobile])\r\n\r\n if (!isOpen) return null\r\n\r\n const isBottomLeft = theme?.position === 'bottom-left'\r\n\r\n return (\r\n <>\r\n {/* Descripción oculta para lectores de pantalla */}\r\n <div id=\"chat-window-description\" className=\"sr-only\">\r\n {t('accessibility.dialogDescription')}\r\n </div>\r\n\r\n <div\r\n ref={dialogRef}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby=\"chat-window-title\"\r\n aria-describedby=\"chat-window-description\"\r\n tabIndex={-1}\r\n className={cn(\r\n 'flex flex-col overflow-hidden transition-all duration-500 ease-[cubic-bezier(0.16,1,0.3,1)]',\r\n 'text-foreground z-[9999]',\r\n\r\n // 💻 DESKTOP: ANCHO Y ALTO CONTROLADO CON MARGEN DEL TECHO\r\n !isMobile && [\r\n 'fixed',\r\n isBottomLeft ? 'left-6' : 'right-6',\r\n 'w-[350px] min-w-[350px] max-w-[350px]',\r\n 'rounded-[32px] border shadow-soft-2xl',\r\n 'animate-in fade-in zoom-in-95',\r\n isBottomLeft ? 'slide-in-from-bottom-10' : 'slide-in-from-bottom-10',\r\n ],\r\n\r\n // 📱 MOBILE: Full pantalla ajustada al viewport real\r\n isMobile && ['fixed inset-0 w-full']\r\n )}\r\n style={{\r\n // useDynamicHeight already calculates height, maxHeight, and bottom correctly\r\n ...dynamicHeightStyles,\r\n // 🎨 CSS VARIABLES - Los temas se aplican automáticamente\r\n backgroundColor: 'hsl(var(--background))',\r\n borderColor: 'hsl(var(--border))',\r\n color: 'hsl(var(--foreground))',\r\n }}\r\n >\r\n {/* --- HEADER --- */}\r\n <header\r\n className=\"relative shrink-0 border-b z-20\"\r\n style={{\r\n padding: 'var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--background) / 0.9)',\r\n borderColor: 'hsl(var(--border))',\r\n backdropFilter: 'blur(24px)',\r\n }}\r\n >\r\n <div className=\"flex items-center justify-between\">\r\n <div className=\"flex items-center gap-3\">\r\n <div className=\"relative\">\r\n <div className=\"h-10 w-10 rounded-2xl overflow-hidden bg-primary/10 border-2 border-background shadow-soft-sm\">\r\n {logoError ? (\r\n <div className=\"h-full w-full flex items-center justify-center bg-muted text-muted-foreground\">\r\n <svg\r\n className=\"w-5 h-5\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\"\r\n >\r\n <path\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n strokeWidth={2}\r\n d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\"\r\n />\r\n </svg>\r\n </div>\r\n ) : (\r\n <img\r\n src={logoUrl || DEFAULT_AVATAR_URL}\r\n alt={botName}\r\n className=\"h-full w-full object-cover\"\r\n onError={() => setLogoError(true)}\r\n />\r\n )}\r\n </div>\r\n <div\r\n className={cn(\r\n 'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full border-2 border-background',\r\n isConnected ? 'bg-emerald-500' : 'bg-amber-500 animate-pulse'\r\n )}\r\n />\r\n </div>\r\n\r\n <div className=\"flex flex-col\">\r\n <div className=\"flex items-center gap-1\">\r\n <span\r\n id=\"chat-window-title\"\r\n className=\"font-black text-xs uppercase tracking-tight text-foreground\"\r\n >\r\n {botName}\r\n </span>\r\n <ShieldCheck className=\"h-3 w-3 text-primary fill-primary/10\" />\r\n </div>\r\n <div id=\"chat-window-description\" className=\"flex items-center gap-1.5 mt-0.5\">\r\n <span className=\"flex h-1 w-1 rounded-full bg-emerald-500\" />\r\n <span className=\"text-[9px] font-black text-muted-foreground uppercase tracking-[0.1em]\">\r\n {isConnected ? t('online') : t('offline')}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-2\">\r\n {/* Voice Call Button - shows only when enableVoice is true in mediaConfig (premium) */}\r\n {mediaConfig?.enableVoice && (\r\n <button\r\n onClick={() => setShowVoiceOverlay(true)}\r\n aria-label=\"Iniciar llamada de voz\"\r\n title=\"Llamar\"\r\n className=\"h-8 w-8 flex items-center justify-center rounded-full bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-600 transition-all active:scale-90 focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2\"\r\n >\r\n <Phone className=\"h-4 w-4\" aria-hidden=\"true\" />\r\n </button>\r\n )}\r\n\r\n <button\r\n onClick={onClose}\r\n aria-label={t('accessibility.closeChat')}\r\n title=\"Esc\"\r\n className=\"h-8 w-8 flex items-center justify-center rounded-full bg-muted/60 hover:bg-muted text-foreground transition-all active:scale-90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2\"\r\n >\r\n <X className=\"h-4 w-4\" aria-hidden=\"true\" />\r\n </button>\r\n </div>\r\n </div>\r\n </header>\r\n\r\n {/* --- CHAT CONTENT --- */}\r\n <main\r\n role=\"region\"\r\n aria-label={t('accessibility.chatMessages')}\r\n className=\"flex-1 min-h-0 relative flex flex-col\"\r\n style={{\r\n padding: 'var(--spacing-5)',\r\n backgroundColor: 'hsl(var(--muted))',\r\n }}\r\n >\r\n <MessageList\r\n messages={messages}\r\n isTyping={isTyping}\r\n welcomeMessage={welcomeMessage}\r\n primaryColor={primaryColor}\r\n logoUrl={logoUrl}\r\n botName={botName}\r\n bubbleStyles={bubbleStyles}\r\n avatars={avatars}\r\n />\r\n <div className=\"absolute top-0 left-0 right-0 h-6 bg-gradient-to-b from-background/10 to-transparent pointer-events-none\" />\r\n </main>\r\n\r\n {/* --- FOOTER --- */}\r\n <footer\r\n className=\"border-t\"\r\n style={{\r\n paddingTop: 'var(--spacing-5)',\r\n paddingLeft: 'var(--spacing-5)',\r\n paddingRight: 'var(--spacing-5)',\r\n paddingBottom: isMobile\r\n ? 'max(var(--spacing-3), env(safe-area-inset-bottom))'\r\n : 'var(--spacing-3)',\r\n backgroundColor: 'hsl(var(--background))',\r\n borderColor: 'hsl(var(--border))',\r\n }}\r\n >\r\n <InputArea\r\n isConnected={isConnected}\r\n placeholder={inputPlaceholder}\r\n primaryColor={themePrimary}\r\n mediaConfig={mediaConfig}\r\n onSendMessage={onSendMessage}\r\n onSendAttachment={onSendAttachment}\r\n onSendLocation={onSendLocation}\r\n onVoiceCall={mediaConfig?.enableVoice ? () => setShowVoiceOverlay(true) : undefined}\r\n />\r\n\r\n <div\r\n className=\"flex items-center justify-center gap-1 opacity-25 select-none\"\r\n style={{\r\n marginTop: 'var(--spacing-2)',\r\n paddingBottom: 'var(--spacing-1)',\r\n }}\r\n >\r\n <Heart className=\"h-2 w-2 text-primary fill-primary\" />\r\n <span className=\"text-[7px] font-bold uppercase tracking-[0.2em]\">\r\n {t('con_amor_paseo_libre')}\r\n </span>\r\n </div>\r\n </footer>\r\n\r\n {/* Voice Call Overlay */}\r\n <VoiceCallOverlay \r\n isOpen={showVoiceOverlay} \r\n onClose={() => setShowVoiceOverlay(false)}\r\n primaryColor={themePrimary}\r\n avatars={avatars}\r\n logoUrl={logoUrl}\r\n avatar3dUrl={avatar3dUrl}\r\n getSocket={getSocket}\r\n onAddMessage={onAddVoiceMessage}\r\n />\r\n </div>\r\n </>\r\n )\r\n}\r\n","/**\r\n * @package @botuyo/chat-widget\r\n * Focus management hook for accessible dialogs\r\n *\r\n * Principio: Single Responsibility - solo gestionar el foco del teclado\r\n */\r\n\r\nimport { useEffect, useRef } from 'react'\r\n\r\ninterface UseFocusTrapOptions {\r\n /** Si el trap está activo */\r\n enabled: boolean\r\n /** Elemento al que retornar el foco al desactivar */\r\n returnFocusRef?: React.RefObject<HTMLElement>\r\n /** Callback al cerrar con Escape */\r\n onEscape?: () => void\r\n}\r\n\r\n/**\r\n * Hook para atrapar el foco dentro de un contenedor (dialog, modal)\r\n *\r\n * Características:\r\n * - Previene que Tab salga del contenedor\r\n * - Retorna el foco al elemento anterior al cerrar\r\n * - Cierra con tecla Escape\r\n * - Compatible con lectores de pantalla\r\n *\r\n * @example\r\n * const containerRef = useFocusTrap({\r\n * enabled: isOpen,\r\n * onEscape: handleClose\r\n * })\r\n *\r\n * return <div ref={containerRef}>...</div>\r\n */\r\nexport function useFocusTrap({ enabled, returnFocusRef, onEscape }: UseFocusTrapOptions) {\r\n const containerRef = useRef<HTMLDivElement>(null)\r\n const previousActiveElementRef = useRef<HTMLElement | null>(null)\r\n\r\n useEffect(() => {\r\n if (!enabled) return\r\n\r\n // Guardar elemento activo antes de abrir\r\n previousActiveElementRef.current = document.activeElement as HTMLElement\r\n\r\n // Capturar returnFocusRef.current al inicio para evitar stale closure\r\n const returnTarget = returnFocusRef?.current\r\n\r\n // Enfocar el contenedor al abrir\r\n const container = containerRef.current\r\n if (!container) return\r\n\r\n // Pequeño delay para asegurar que el DOM está listo\r\n const focusTimeout = setTimeout(() => {\r\n // Buscar primer elemento focusable\r\n const focusable = container.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n if (focusable.length > 0) {\r\n focusable[0].focus()\r\n } else {\r\n container.focus()\r\n }\r\n }, 100)\r\n\r\n // Handler para atrapar el foco con Tab\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (!container) return\r\n\r\n // Escape para cerrar\r\n if (e.key === 'Escape') {\r\n onEscape?.()\r\n return\r\n }\r\n\r\n // Tab cycling\r\n if (e.key === 'Tab') {\r\n const focusableElements = container.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n\r\n if (focusableElements.length === 0) return\r\n\r\n const firstElement = focusableElements[0]\r\n const lastElement = focusableElements[focusableElements.length - 1]\r\n\r\n // Shift + Tab en el primero → ir al último\r\n if (e.shiftKey && document.activeElement === firstElement) {\r\n e.preventDefault()\r\n lastElement.focus()\r\n }\r\n // Tab en el último → ir al primero\r\n else if (!e.shiftKey && document.activeElement === lastElement) {\r\n e.preventDefault()\r\n firstElement.focus()\r\n }\r\n }\r\n }\r\n\r\n document.addEventListener('keydown', handleKeyDown)\r\n\r\n return () => {\r\n clearTimeout(focusTimeout)\r\n document.removeEventListener('keydown', handleKeyDown)\r\n\r\n // Retornar foco al elemento capturado al inicio\r\n const targetToFocus = returnTarget || previousActiveElementRef.current\r\n if (targetToFocus && typeof targetToFocus.focus === 'function') {\r\n targetToFocus.focus()\r\n }\r\n }\r\n }, [enabled, onEscape, returnFocusRef])\r\n\r\n return containerRef\r\n}\r\n"],"names":["translations","es","online","offline","connecting","con_amor_paseo_libre","preview","fotos","ubicacion","input_placeholder","send","attach_photo","attach_location","recording","rate_limit_exceeded","connection_error","file_too_large","invalid_file","extracted","assistant","anterior","siguiente","cerrar","cerrar_chat","abrir_chat","ver_ubicacion","accessibility","closeChat","closeChatHint","chatMessages","messageHistory","dialogDescription","sendMessage","sendMessageHint","typeMessage","botMessage","userMessage","messageFrom","messageTime","newMessage","en","pt","fr","detectLanguage","navigator","browserLang","language","split","defaultContext","locale","setLocale","LanguageContext","createContext","LOCALE_STORAGE_KEY","LanguageProvider","children","defaultLocale","setLocaleState","useState","window","stored","localStorage","getItem","useEffect","handleLanguageChange","addEventListener","removeEventListener","jsx","Provider","value","newLocale","includes","setItem","console","warn","useLanguage","useContext","useTranslations","namespace","currentLocale","t","useCallback","key","obj","path","reduce","current","mergeClasses","classes","filter","className","index","array","Boolean","indexOf","join","defaultAttributes","xmlns","width","height","viewBox","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","Icon","forwardRef","color","size","absoluteStrokeWidth","iconNode","rest","ref","createElement","Number","map","tag","attrs","Array","isArray","createLucideIcon","iconName","Component","props","string","replace","toLowerCase","displayName","ArrowRight","d","CheckCheck","ChevronLeft","ChevronRight","CircleAlert","cx","cy","r","x1","x2","y1","y2","Download","points","ExternalLink","File","Heart","Image","x","y","rx","ry","Keyboard","LoaderCircle","MapPin","MessageCircle","MicOff","Mic","Pause","PhoneOff","Phone","Play","Plus","RotateCw","Send","ShieldCheck","Trash2","Volume2","X","ZoomIn","e","f","n","o","length","createClassPartObject","nextPart","Map","validators","classGroupId","CLASS_PART_SEPARATOR","EMPTY_CONFLICTS","createClassGroupUtils","config","classMap","createClassMap","conflictingClassGroups","conflictingClassGroupModifiers","getClassGroupId","startsWith","endsWith","getGroupIdForArbitraryProperty","classParts","startIndex","getGroupRecursive","getConflictingClassGroupIds","hasPostfixModifier","modifierConflicts","baseConflicts","array1","array2","combinedArray","i","concatArrays","classPartObject","currentClassPart","nextClassPartObject","get","result","classRest","slice","validatorsLength","validatorObj","validator","content","colonIndex","property","theme","classGroups","processClassGroups","group","processClassesRecursively","classGroup","len","classDefinition","processClassDefinition","processObjectDefinition","processFunctionDefinition","processStringDefinition","getPart","isThemeGetter","push","createClassValidatorObject","entries","Object","parts","part","next","set","func","createLruCache","maxCacheSize","cacheSize","cache","create","previousCache","update","EMPTY_MODIFIERS","createResultObject","modifiers","hasImportantModifier","baseClassName","maybePostfixModifierPosition","isExternal","createParseClassName","prefix","experimentalParseClassName","parseClassName","postfixModifierPosition","bracketDepth","parenDepth","modifierStart","currentCharacter","baseClassNameWithImportantModifier","fullPrefix","parseClassNameOriginal","createSortModifiers","modifierWeights","orderSensitiveModifiers","forEach","mod","currentSegment","modifier","isArbitrary","isOrderSensitive","has","sort","SPLIT_CLASSES_REGEX","toValue","mix","resolvedValue","k","fallbackThemeArr","fromTheme","themeGetter","arbitraryValueRegex","arbitraryVariableRegex","fractionRegex","tshirtUnitRegex","lengthUnitRegex","colorFunctionRegex","shadowRegex","imageRegex","isFraction","test","isNumber","isNaN","isInteger","isPercent","isTshirtSize","isAny","isLengthOnly","isNever","isShadow","isImage","isAnyNonArbitrary","isArbitraryValue","isArbitraryVariable","isArbitrarySize","getIsArbitraryValue","isLabelSize","isArbitraryLength","isLabelLength","isArbitraryNumber","isLabelNumber","isArbitraryPosition","isLabelPosition","isArbitraryImage","isLabelImage","isArbitraryShadow","isLabelShadow","isArbitraryVariableLength","getIsArbitraryVariable","isArbitraryVariableFamilyName","isLabelFamilyName","isArbitraryVariablePosition","isArbitraryVariableSize","isArbitraryVariableImage","isArbitraryVariableShadow","testLabel","testValue","exec","shouldMatchNoLabel","label","twMerge","createConfigFirst","createConfigRest","configUtils","cacheGet","cacheSet","functionToCall","tailwindMerge","classList","cachedResult","sortModifiers","classGroupsInConflict","classNames","trim","originalClassName","substring","variantModifier","modifierId","classId","conflictGroups","mergeClassList","previousConfig","createConfigCurrent","createConfigUtils","args","classLists","argument","twJoin","themeColor","themeFont","themeText","themeFontWeight","themeTracking","themeLeading","themeBreakpoint","themeContainer","themeSpacing","themeRadius","themeShadow","themeInsetShadow","themeTextShadow","themeDropShadow","themeBlur","themePerspective","themeAspect","themeEase","themeAnimate","scalePositionWithArbitrary","scaleUnambiguousSpacing","scaleInset","scaleGridTemplateColsRows","scaleGridColRowStartAndEnd","span","scaleGridColRowStartOrEnd","scaleGridAutoColsRows","scaleMargin","scaleSizing","scaleColor","scaleBgPosition","position","scaleBgSize","scaleGradientStopPosition","scaleRadius","scaleBorderWidth","scaleMaskImagePosition","scaleBlur","scaleRotate","scaleScale","scaleSkew","scaleTranslate","animate","aspect","blur","breakpoint","container","ease","font","leading","perspective","radius","shadow","spacing","text","tracking","columns","box","display","sr","float","clear","isolation","object","overflow","overscroll","inset","start","end","top","right","bottom","left","visibility","z","basis","flex","grow","shrink","order","col","row","gap","justify","items","baseline","self","p","px","py","ps","pe","pr","pb","pl","m","mx","my","ms","me","mt","mr","mb","ml","w","screen","h","list","placeholder","decoration","indent","align","whitespace","break","wrap","hyphens","bg","repeat","linear","to","radial","conic","from","via","rounded","border","divide","outline","ring","opacity","mask","closest","farthest","brightness","contrast","grayscale","invert","saturate","sepia","table","caption","transition","duration","delay","backface","rotate","scale","skew","transform","origin","translate","accent","appearance","caret","scheme","cursor","resize","scroll","snap","touch","select","cn","inputs","arguments","clsx","DEFAULT_CSS_VARIABLES","background","foreground","card","cardForeground","primary","primaryForeground","muted","mutedForeground","destructive","spacing1","spacing2","spacing3","spacing4","spacing5","spacing6","spacing8","DEFAULT_THEME","mergeThemeWithDefaults","userTheme","socketTheme","mergedCssVariables","cssVariables","primaryColor","botName","logoUrl","welcomeMessage","inputPlaceholder","isHidden","getPrimaryColor","options","defaultAnimationConfig","enabled","messageEntry","typingIndicator","buttonEffects","smoothScroll","speedMultiplier","staggerDelay","windowTransitions","launcherPulse","defaultEffectsConfig","glassmorphism","gradients","softShadows","glowEffects","particles","soundEffects","hapticFeedback","shimmerLoading","hoverLift","AnimationContext","EffectsContext","PremiumConfigProvider","animations","effects","animationValue","useMemo","effectsValue","useAnimations","usePremiumEffects","getGlassClass","getShadowClass","getGlowClass","getHoverLiftClass","getGradientClass","getShimmerClass","triggerHaptic","vibrate","playSound","type","log","triggerParticles","element","isDebugEnabled","DEBUG","logger","message","error","debug","info","DEFAULT_AVATAR_URL","encodeURIComponent","DEFAULT_NOTIFICATION_SOUND_URL","numSamples","Math","floor","sampleRate","dataSize","fileSize","buffer","ArrayBuffer","view","DataView","writeString","setUint32","setUint16","fadeOut","sample","sin","PI","setInt16","bytes","Uint8Array","binary","String","fromCharCode","btoa","createNotificationSoundDataUrl","offset","setUint8","charCodeAt","memo","getDeps","fn","opts","deps","initialDeps","isInitial","memoizedFunction","_a","_b","_c","depTime","call","Date","now","newDeps","some","dep","resultTime","depEndTime","round","resultEndTime","resultFpsPercentage","pad","str","num","max","min","onChange","skipInitialOnChange","updateDeps","notUndefined","msg","Error","debounce","targetWindow","timeoutId","clearTimeout","setTimeout","apply","this","getRect","offsetWidth","offsetHeight","defaultKeyExtractor","defaultRangeExtractor","range","overscan","endIndex","count","arr","observeElementRect","instance","cb","scrollElement","handler","rect","ResizeObserver","observer","run","entry","borderBoxSize","inlineSize","blockSize","useAnimationFrameWithResizeObserver","requestAnimationFrame","observe","unobserve","addEventListenerOptions","passive","supportsScrollend","observeElementOffset","fallback","useScrollendEvent","isScrollingResetDelay","createHandler","isScrolling","horizontal","isRtl","endHandler","registerScrollendEvent","measureElement","elementScroll","adjustments","behavior","toOffset","scrollTo","Virtualizer","constructor","unsubs","currentScrollToIndex","measurementsCache","itemSizeCache","laneAssignments","pendingMeasuredCacheIndexes","prevLanes","lanesChangedFlag","lanesSettling","scrollRect","scrollOffset","scrollDirection","scrollAdjustments","elementsCache","_ro","_measureElement","target","disconnect","setOptions","opts2","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","scrollMargin","indexAttribute","initialMeasurementsCache","lanes","notify","sync","maybeNotify","calculateRange","cleanup","_didMount","_willUpdate","getScrollElement","ownerDocument","defaultView","cached","getScrollOffset","_scrollToOffset","getSize","getFurthestMeasurement","measurements","furthestMeasurementsFound","furthestMeasurements","measurement","lane","previousFurthestMeasurement","values","a","b","getMeasurementOptions","getMeasurements","keys","delete","item","laneLastIndex","cachedLane","prevIndex","prevInLane","furthestMeasurement","measuredSize","estimateSize","outerSize","lastIndex","findNearestBinarySearch","endPerLane","pos","startPerLane","getVirtualIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","prevNode","isConnected","resizeItem","delta","shouldAdjustScrollPositionOnItemSizeChange","getVirtualItems","indexes","virtualItems","getVirtualItemForOffset","getMaxScrollOffset","scrollWidth","clientWidth","scrollHeight","clientHeight","doc","document","documentElement","innerWidth","innerHeight","getOffsetForAlignment","itemSize","maxOffset","getOffsetForIndex","isDynamicMode","scrollToOffset","scrollToIndex","initialAlign","attempts","tryScroll","currentAlign","offsetInfo","verify","currentOffset","afterInfo","abs","scheduleRetry","scrollBy","getTotalSize","endByLane","val","scrollToFn","measure","low","high","getCurrentValue","middle","currentValue","useIsomorphicLayoutEffect","React","useLayoutEffect","AudioPlayer","lazy","import","then","default","Gallery","MessageBubble","botAvatar","avatars","isFirst","isLast","isUser","sender","isSystem","isBot","brandColor","messageEntryClass","slide","fade","spring","useMessageEntryClass","currentAvatar","textMsg","emotion","RenderLink","href","textContent","isCTA","rel","jsxs","style","backgroundColor","borderColor","RenderImage","src","alt","Suspense","images","animationDelay","charAt","padding","boxShadow","url","imgMsg","imageUrl","altText","locMsg","latitude","longitude","fileMsg","fileExtension","fileName","pop","toFixed","fileUrl","download","FileIcon","toUpperCase","ReactMarkdown","remarkPlugins","remarkGfm","rehypePlugins","rehypeSanitize","tagNames","attributes","img","protocols","components","renderContent","date","dateObj","getTime","toLocaleTimeString","hour","minute","hour12","formatTime","timestamp","prevProps","nextProps","id","JSON","stringify","styles","TypingIndicator","animationDuration","differenceInMinutes","laterDate","earlierDate","diffMs","Intl","DateTimeFormat","format","MessageList","messages","isTyping","bubbleStyles","messagesEndRef","useRef","containerRef","isReady","setIsReady","logoError","setLogoError","bgColor","shouldVirtualize","virtualizer","useFlushSync","rerender","useReducer","resolvedOptions","instance2","flushSync","useVirtualizerBase","timer","scrollIntoView","block","getSeparatorLabel","today","getDate","getMonth","getFullYear","isToday","yesterday","setDate","isYesterday","day","month","formatShort","formatRelative","virtualRow","prev","showDateSeparator","isSameAsPrev","isSameAsNext","onError","Fragment","prevLast","nextLast","MAGIC_BYTES","async","validateFile","file","maxSizeMB","allowedExtensions","checkMagicBytes","maxSizeBytes","validateFileSize","valid","extension","name","validateFileExtension","isValid","expectedBytes","arrayBuffer","every","byte","validateFileType","MAX_CHARS","DEFAULT_MEDIA_CONFIG","enableImages","enableAudio","enableFiles","enableLocation","allowedFileTypes","maxFileSizeMB","InputArea","mediaConfig","onSendMessage","onSendAttachment","onSendLocation","onVoiceCall","inputValue","setInputValue","isMenuOpen","setIsMenuOpen","isRecording","setIsRecording","recordingTime","setRecordingTime","attachment","setAttachment","isCompressing","setIsCompressing","isLoadingLocation","setIsLoadingLocation","textareaRef","fileInputRef","imageInputRef","mediaRecorderRef","audioChunksRef","timerRef","hasMediaFeatures","handleSend","trimmedValue","handleFileSelect","files","validationResult","imageCompression","maxWidthOrHeight","useWebWorker","compressedFile","previewUrl","URL","createObjectURL","alert","stopRecording","onstop","stop","stream","getTracks","clearInterval","audioBlob","Blob","audioFile","validation","Loader2","onClick","accept","ext","marginBottom","click","ImageIcon","geolocation","getCurrentPosition","coords","enableVoice","toString","padStart","rows","onKeyDown","shiftKey","ctrlKey","metaKey","preventDefault","onFocus","disabled","scrollbarWidth","msOverflowStyle","mediaDevices","getUserMedia","audio","mediaRecorder","MediaRecorder","ondataavailable","data","setInterval","v","throttle","lastCall","timeSinceLastCall","execute","useIsMobile","isMobile","setIsMobile","checkMobile","DEFAULT_BOTTOM","Avatar3D","DEFAULT_EMOTION_EMOJIS","happy","wink","thinking","sad","excited","love","laugh","surprised","angry","confused","sorry","DEFAULT_STATUS_LABELS","idle","listening","speaking","voiceSanitizeSchema","code","OUTPUT_SAMPLE_RATE","Avatar3DErrorBoundary","super","state","hasError","getDerivedStateFromError","componentDidCatch","render","AvatarOrb","avatar3dUrl","callState","audioLevel","hasAvatars","hasLogo","avatar3dFailed","setAvatar3dFailed","avatarUrl","isActive","glowColor","speakingColor","thinkingColor","listeningColor","speakingScale","thinkingScale","orbPx","orbSize","modelUrl","showWaveform","WaveformBars","showEmotionLabel","showEmojis","emotionEmojis","animation","_","dist","VoiceCallOverlay","isOpen","onClose","getSocket","voiceConfig","onAddMessage","cfg","showBadge","badgeText","statusLabels","resolveVoiceConfig","setCallState","setDuration","isMuted","setIsMuted","setAudioLevel","currentEmotion","setCurrentEmotion","conversation","setConversation","showTextInput","setShowTextInput","textInputValue","setTextInputValue","analyserRef","streamRef","audioCtxRef","workletNodeRef","animFrameRef","socketListenersRef","processorUrlRef","conversationEndRef","playbackCtxRef","audioQueueRef","isPlayingRef","nextPlayTimeRef","activeSourcesRef","formatDuration","seconds","scheduleChunks","AudioContext","ctx","currentTime","float32Data","shift","createBuffer","getChannelData","source","createBufferSource","connect","destination","onended","s","voiceListenersRef","setupSocketListeners","socket","onVoiceReady","onVoiceAudioChunk","pcmFloat32","base64","atob","int16","Int16Array","float32","Float32Array","base64ToFloat32","onVoiceInterrupted","onVoiceTurnComplete","onVoiceError","onVoiceEmotion","onVoiceUserTranscript","role","updated","existing","needsSpace","onVoiceModelTranscript","onVoiceModelThinking","voiceReady","voiceAudioChunk","voiceInterrupted","voiceTurnComplete","voiceError","voiceEmotion","voiceUserTranscript","voiceModelTranscript","voiceModelThinking","on","removeSocketListeners","l","off","startMicCapture","channelCount","echoCancellation","noiseSuppression","autoGainControl","createMediaStreamSource","analyser","createAnalyser","fftSize","blob","audioWorklet","addModule","workletNode","AudioWorkletNode","port","onmessage","connected","byteLength","arrayBufferToBase64","emit","updateLevel","frequencyBinCount","getByteFrequencyData","avg","stopMicCapture","cancelAnimationFrame","close","startCall","err","voice","endCall","toggleMute","sendTextInput","stateColor","borderRadius","borderBottom","paddingTop","fontSize","fontWeight","letterSpacing","fontFamily","fontVariantNumeric","justifyContent","flexDirection","maxWidth","lineHeight","marginLeft","marginRight","backdropFilter","margin","textDecoration","strong","em","ul","paddingLeft","ol","li","textAlign","paddingBottom","alignItems","autoFocus","ChatWindow","onAddVoiceMessage","showVoiceOverlay","setShowVoiceOverlay","themePrimary","dynamicHeightStyles","dynamicHeight","setDynamicHeight","calculateHeight","updateMobileHeight","visualViewport","offsetTop","bottomPx","parseFloat","maxAvailableHeight","heightValue","clampedHeight","maxHeight","calculatedHeight","useDynamicHeight","dialogRef","returnFocusRef","onEscape","previousActiveElementRef","activeElement","returnTarget","focusTimeout","focusable","querySelectorAll","focus","handleKeyDown","focusableElements","firstElement","lastElement","targetToFocus","useFocusTrap","body","isBottomLeft","tabIndex","title","paddingRight","marginTop"],"mappings":"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","x_google_ignoreList":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,42,43,44]}