// vita-core.jsx — design tokens, Vita personalities, icons, small UI atoms // Brand: VITA — teal #0F766E. Paleta en src/design/tokens.ts // ── Theme: mapea los tokens del núcleo a las claves que ya usan las pantallas ── // Los colores NO viven aquí: viven en src/design/tokens.ts (tipado, testeado). // Esta función es un adaptador: traduce la paleta al vocabulario heredado // (bg0, surfaceSolid, stroke, accent…) para no reescribir 30 archivos de golpe. // A medida que las pantallas migren, consumirán `t.paleta` directamente. function getTheme(dark, accent, accentDeep) { const D = (window.VitaCore && window.VitaCore.diseno) || null; const p = D ? D.paleta(!!dark) : null; if (!p) { // Respaldo mínimo si el bundle del núcleo no cargó. return { dark: !!dark, bg0: '#F8FAFC', bg1: '#F8FAFC', bg2: '#FFFFFF', surface: '#FFFFFF', surfaceSolid: '#FFFFFF', stroke: '#E2E8F0', strokeStrong: '#CBD5E1', text: '#1E293B', textSoft: '#475569', muted: '#64748B', accent: '#0F766E', accentDeep: '#115E59', coral: '#DC2626', green: '#16A34A', onAccent: '#FFFFFF', shadow: '0 2px 8px rgba(15,23,42,0.08)' }; } // La persona (cálida/serena/coach) ya NO cambia el color de marca: VITA // tiene una identidad única. La persona sólo afecta al tono de voz. // Se aceptan los argumentos por compatibilidad, pero se ignoran. void accent; void accentDeep; return { dark: !!dark, paleta: p, espaciado: D.espaciado, radio: D.radio, sombra: D.sombra, // ── vocabulario heredado ── bg0: p.bg, bg1: p.bg, bg2: p.surface, surface: p.surface, surfaceSolid: p.surfaceRaised, stroke: p.border, strokeStrong: p.borderStrong, text: p.text, textSoft: p.textMuted, muted: p.textMuted, accent: p.primary, accentDeep: p.primaryDark, coral: p.danger, green: p.success, amber: p.warning, secondary: p.secondary, chatUser: p.chatUser, chatSystem: p.chatSystem, onAccent: p.onPrimary, shadow: D.sombra.md, }; } // ── Vita personalities (the "variations" the user can explore) ─── const VITA_PERSONAS = { // ── Voz original de Vita ── calida: { id: 'calida', name: 'Cálida', tagline: 'Voz femenina · cercana y empática', genero: 'femenino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Cercana y empática, con el criterio de una profesional de la salud.', voiceHint: 'cálida y cercana', voice: { rate: 0.97, pitch: 1.06 }, persona: 'Tu personalidad es CÁLIDA: cercana, empática y humana, con el criterio y la seriedad de una profesional de la salud. Validas las emociones del paciente con naturalidad, sin exagerar. Tuteas siempre.', }, serena: { id: 'serena', name: 'Serena', tagline: 'Voz femenina · calmada y tranquilizadora', genero: 'femenino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Voz pausada que reduce la ansiedad. Habla despacio, con suavidad y mucha contención.', voiceHint: 'pausada y suave', voice: { rate: 0.9, pitch: 1.0 }, persona: 'Tu personalidad es SERENA: pausada, suave y tranquilizadora. Bajas la ansiedad del paciente con frases cortas, calmadas y contenedoras. Transmites seguridad y paz. Tuteas siempre.', }, coach: { id: 'coach', name: 'Coach', tagline: 'Voz femenina · motivadora y de longevidad', genero: 'femenino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Te impulsa con energía a mejorar tus hábitos y bajar tu edad biológica.', voiceHint: 'enérgica y motivadora', voice: { rate: 1.0, pitch: 1.02 }, persona: 'Tu personalidad es COACH: motivadora y orientada a la longevidad. Impulsas al paciente a mejorar sus hábitos con energía medida, sin regañar ni exagerar. Enmarcas todo como progreso. Tuteas siempre.', }, // ── Voces profesionales ── (se muestran sólo si su voz está configurada // en el servidor; ver ELEVENLABS_VOICE_ID_* en api/tts.js) profesional: { id: 'profesional', name: 'Profesional', tagline: 'Voz masculina · neutra y profesional', genero: 'masculino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Sobrio y preciso, como un médico en consulta. Va al punto, con respeto.', voiceHint: 'neutra y profesional', voice: { rate: 0.97, pitch: 0.82 }, persona: 'Tu personalidad es PROFESIONAL: sobrio, preciso y neutro, como un médico con experiencia en consulta. Eres respetuoso y claro, y vas al punto sin adornos. Tuteas siempre.', }, cercano: { id: 'cercano', name: 'Cercano', tagline: 'Voz masculina · cálida y tranquila', genero: 'masculino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Cálido y tranquilo, con la confianza de un médico de familia.', voiceHint: 'cálida y tranquila', voice: { rate: 0.97, pitch: 0.86 }, persona: 'Tu personalidad es CERCANA: cálido y tranquilo, con la confianza de un médico de familia que conoce bien a sus pacientes, sin perder el profesionalismo. Tuteas siempre.', }, clinica: { id: 'clinica', name: 'Clínica', tagline: 'Voz femenina · neutra y profesional', genero: 'femenino', accent: '#0F766E', accentDeep: '#115E59', desc: 'Clara, ordenada y serena, como una profesional de la salud en consulta.', voiceHint: 'neutra y clara', voice: { rate: 0.97, pitch: 1.0 }, persona: 'Tu personalidad es CLÍNICA: clara, ordenada y neutra, como una profesional de la salud en consulta. Explicas con calma y precisión. Tuteas siempre.', }, }; // ── Icons (simple geometric paths only) ───────────────────────── const Icon = { mic: (p) => ( ), send: (p) => ( ), sun: (p) => ( ), moon: (p) => ( ), check: (p) => ( ), sparkle: (p) => ( ), pulse: (p) => ( ), heart: (p) => ( ), chevron: (p) => ( ), shield: (p) => ( ), x: (p) => ( ), volume: (p) => ( ), volumeOff: (p) => ( ), mail: (p) => ( ), lock: (p) => ( ), user: (p) => ( ), eye: (p) => ( ), eyeOff: (p) => ( ), faceid: (p) => ( ), phone: (p) => ( ), food: (p) => ( ), animo: (p) => ( ), doc: (p) => ( ), clip: (p) => ( ), plus: (p) => ( ), home: (p) => ( ), alert: (p) => ( ), calendar: (p) => ( ), pill: (p) => ( ), lab: (p) => ( ), bell: (p) => ( ), upload: (p) => ( ), camera: (p) => ( ), scan: (p) => ( ), card: (p) => ( ), refresh: (p) => ( ), arrowRight: (p) => ( ), users: (p) => ( ), swap: (p) => ( ), child: (p) => ( ), logout: (p) => ( ), consent: (p) => ( ), video: (p) => ( ), brain: (p) => ( ), pin: (p) => ( ), star: (p) => ( ), clock: (p) => ( ), grid: (p) => ( ), route: (p) => ( ), droplet: (p) => ( ), flame: (p) => ( ), sunrise: (p) => ( ), sundial: (p) => ( ), walk: (p) => ( ), stethoscope: (p) => ( ), }; // ── Brand wordmark + pulse mark ───────────────────────────────── function VITAMark({ t, size = 16, withWord = true }) { return (
{Icon.pulse({ s: size, c: t.onAccent, w: 2.4 })}
{withWord && ( VITA )}
); } // ── helpers ───────────────────────────────────────────────────── function hexA(hex, a) { const h = hex.replace('#', ''); const r = parseInt(h.substring(0, 2), 16); const g = parseInt(h.substring(2, 4), 16); const b = parseInt(h.substring(4, 6), 16); return `rgba(${r},${g},${b},${a})`; } Object.assign(window, { getTheme, VITA_PERSONAS, Icon, VITAMark, hexA });