Files
soft_usite/public/umind.html
T
Lizandro GuarnizoandClaude Opus 5 3ceb61c035 feat(umind): Umi, la mascota, y un solo vocabulario en toda la interfaz
La mascota. Umi sale del logo, no es un dibujo aparte: su cuerpo es la "u" del
monograma y el punto del logo pasa a ser su antena, así que símbolo y personaje
son la misma forma vista dos veces. Por eso puede estar al lado del logo sin
competirle.

Tiene estados, y no son decoración: cada pantalla vacía dice algo distinto y la
cara lo dice antes que el texto. Dormida cuando todavía no pasó nada, buscando
cuando falta cargarle información, contenta cuando no hay errores, alerta
cuando algo se rompió. Los ojos toman el color de la superficie de atrás en vez
de ser blancos, así se apoya sobre cualquier tarjeta y en modo oscuro no quedan
dos puntos flotando.

Las pantallas vacías. Había una buena y ocho que decían "Sin canales
configurados." y nada más — el usuario quedaba resolviendo solo qué significa
eso y qué hacer. Ahora las ocho explican qué va ahí y por qué importa: "No está
atendiendo en ningún lado", "Todavía no sabe nada de tu negocio".

El vocabulario. La misma cosa tenía dos nombres según la pantalla: tenant y
espacio, tool y herramienta. Un producto que se llama distinto a sí mismo en
cada lugar se siente como varios productos pegados. Queda: espacio, agente,
herramienta, fuente. Y "al AI" pasa a "a la IA", que además es el género que ya
usaba el resto del panel.

Y la barra de scroll de las pestañas, que se veía gris y gruesa sobre el
contenido: en escritorio las siete entran holgadas y no hacía falta, en móvil
siguen deslizándose pero sin la barra encima.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 19:19:01 -05:00

1317 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>uMind — U-SITE</title>
<meta name="description" content="El asistente que responde por tu negocio en WhatsApp, Telegram y tu sitio. No adivina: busca en tu información." />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96'%3E%3Crect width='96' height='96' rx='22' fill='%238eb02f'/%3E%3Cpath d='M32,42 V58 A14,14 0 0 0 60,58 V42' fill='none' stroke='%23fff' stroke-width='10' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M60,58 V64' fill='none' stroke='%23fff' stroke-width='10' stroke-linecap='round'/%3E%3Ccircle cx='60' cy='28' r='7' fill='%23fff'/%3E%3C/svg%3E" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Sora:wght@400;600;800&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" />
<style>
/* ── Sistema ───────────────────────────────────────────────────────────────
Página de un solo mundo visual: oscura, como el sitio de U-SITE. Todo color
se declara explícitamente para que no dependa del tema del navegador.
Dos acentos con trabajos distintos y sin mezclarse:
cian = la máquina (proceso, latencia, vectores)
lima = tu información y lo que salió bien (verde de marca U-SITE) */
:root {
--void: #05070D;
--ground: #080B14;
--panel: #0D1220;
--panel-2: #121A2B;
--line: #1B2437;
--line-soft: #141C2C;
--text: #E6EDF7;
--text-soft: #8C9BB5;
--text-dim: #58657E;
--cyan: #3DDCE8;
--cyan-deep: #1B94A6;
--lime: #A9D340;
--lime-deep: #8EB02F;
--amber: #E0AF4A;
--display: "Sora", "Trebuchet MS", sans-serif;
--body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--ground);
color: var(--text);
font-family: var(--body);
font-size: 16.5px;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* Retícula de fondo: la rejilla de un plano técnico, muy tenue. */
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 0;
background-image:
linear-gradient(var(--line-soft) 1px, transparent 1px),
linear-gradient(90deg, var(--line-soft) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 20%, transparent 75%);
opacity: 0.55;
}
/* Grano muy leve: sin él, los degradés oscuros bandean en pantallas de
8 bits y el panel se ve a plástico en vez de a vidrio. */
body::after {
content: "";
position: fixed;
inset: 0;
z-index: 2;
pointer-events: none;
opacity: 0.035;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23g)'/></svg>");
}
/* ── Revelado al hacer scroll ────────────────────────────────────────────
Los bloques entran cuando aparecen en pantalla — no todos a la vez, ni
siempre, sólo la primera vez que se muestran. */
[data-revela] {
opacity: 0;
transform: translateY(20px);
transition: opacity .7s cubic-bezier(.16,.8,.24,1), transform .7s cubic-bezier(.16,.8,.24,1);
transition-delay: var(--retraso, 0ms);
}
[data-revela].visto { opacity: 1; transform: none; }
.capa { position: relative; z-index: 1; }
.marco { max-width: 1140px; margin: 0 auto; padding: 0 24px; }
/* ── Tipografía ─────────────────────────────────────────────────────────── */
h1, h2, h3 {
font-family: var(--display);
margin: 0;
letter-spacing: -0.03em;
text-wrap: balance;
line-height: 1.04;
}
h1 { font-size: clamp(2.25rem, 4.6vw, 3.4rem); font-weight: 800; }
h2 { font-size: clamp(1.75rem, 3.4vw, 2.6rem); font-weight: 800; }
h3 { font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.35; }
p { margin: 0; }
strong { font-weight: 600; color: var(--text); }
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--mono);
font-size: 0.71rem;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--cyan);
}
.eyebrow::before {
content: "";
width: 22px;
height: 1px;
background: var(--cyan);
opacity: 0.7;
}
.plomo { color: var(--text-soft); font-size: 1.12rem; }
/* ── Barra superior ─────────────────────────────────────────────────────── */
.barra {
display: flex;
align-items: center;
gap: 12px;
padding: 22px 0;
border-bottom: 1px solid var(--line-soft);
}
.logo {
width: 30px; height: 30px;
border-radius: 8px;
background: linear-gradient(140deg, var(--lime), var(--lime-deep));
display: grid; place-items: center;
overflow: hidden;
}
.logo svg { width: 100%; height: 100%; display: block; }
.logo-txt { font-family: var(--display); font-weight: 600; letter-spacing: -0.02em; }
.chip {
font-family: var(--mono);
font-size: 0.66rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--cyan);
border: 1px solid rgba(61, 220, 232, 0.3);
background: rgba(61, 220, 232, 0.07);
padding: 3px 9px;
border-radius: 999px;
}
.barra-fin { margin-left: auto; font-family: var(--mono); font-size: 0.72rem; color: var(--text-dim); }
/* ── Escenario: fondo animado detrás de la nav y la portada ────────────────
Un campo de puntos que deriva despacio, como el espacio vectorial del que
habla la página, pero ambiental — sin buscar nada todavía. Eso lo hace
luego, explícito, el mapa de la sección "mecánica". Acá es sólo clima. */
.escenario {
position: relative;
overflow: hidden;
border-radius: 0 0 22px 22px;
}
.campo {
position: absolute;
inset: 0;
z-index: 0;
display: block;
width: 100%;
height: 100%;
-webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
}
/* Mancha de luz que sigue el cursor — sutil, se apaga sola en touch. */
.foco {
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
opacity: 0;
transition: opacity .4s ease;
background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 20%),
rgba(61, 220, 232, 0.09), rgba(169, 211, 64, 0.05) 46%, transparent 72%);
}
.escenario.con-foco .foco { opacity: 1; }
.escenario > .barra,
.escenario > .portada { position: relative; z-index: 1; }
@media (hover: none) { .foco { display: none; } }
/* ── Portada ────────────────────────────────────────────────────────────── */
.portada {
display: grid;
gap: 48px;
padding: 72px 0 56px;
align-items: center;
}
@media (min-width: 980px) {
.portada { grid-template-columns: 1fr 1.05fr; gap: 60px; padding: 80px 0 76px; }
}
.portada h1 { margin-top: 20px; }
.portada h1 em { font-style: normal; color: var(--cyan); }
.portada .plomo { margin-top: 22px; max-width: 31rem; }
.acciones { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }
.btn {
display: inline-flex;
align-items: center;
gap: 9px;
padding: 13px 22px;
border-radius: 10px;
font-family: var(--display);
font-weight: 600;
font-size: 0.95rem;
text-decoration: none;
border: 1px solid transparent;
transition: transform .15s ease, box-shadow .2s ease, border-color .2s ease, color .2s ease;
}
.btn-solido {
background: var(--lime);
color: #06180A;
box-shadow: 0 10px 34px -14px rgba(169, 211, 64, 0.7);
}
.btn-solido:hover { transform: translateY(-2px); box-shadow: 0 16px 42px -14px rgba(169, 211, 64, 0.8); }
.btn-linea { color: var(--text); border-color: var(--line); }
.btn-linea:hover { border-color: var(--cyan); color: var(--cyan); }
a:focus-visible, button:focus-visible {
outline: 2px solid var(--cyan);
outline-offset: 3px;
border-radius: 8px;
}
.sello {
display: flex;
flex-wrap: wrap;
gap: 18px;
margin-top: 34px;
font-family: var(--mono);
font-size: 0.72rem;
color: var(--text-dim);
}
.sello span { display: inline-flex; align-items: center; gap: 7px; }
.sello span::before {
content: "";
width: 5px; height: 5px;
border-radius: 50%;
background: var(--lime);
box-shadow: 0 0 8px var(--lime);
}
/* ── Traza: el corazón de la página ─────────────────────────────────────
Un chatbot cualquiera improvisa. uMind hace un recorrido concreto por tu
información, y ese recorrido es lo que se muestra acá. */
.traza {
position: relative;
background: linear-gradient(180deg, var(--panel) 0%, var(--void) 100%);
border: 1px solid var(--line);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 40px 90px -50px rgba(61, 220, 232, 0.45);
}
/* Barrido de escaneo: una línea que recorre el panel, como si el proceso
siguiera activo aunque la traza ya haya terminado de escribirse. */
.traza::after {
content: "";
position: absolute;
left: 0; right: 0; top: 0;
height: 90px;
background: linear-gradient(180deg, rgba(61, 220, 232, 0.1), transparent);
transform: translateY(-100%);
animation: barrido 7s ease-in-out infinite;
animation-delay: 3.6s;
pointer-events: none;
}
@keyframes barrido {
0% { transform: translateY(-100%); }
30% { transform: translateY(520%); }
100% { transform: translateY(520%); }
}
.traza-barra {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
background: var(--panel-2);
border-bottom: 1px solid var(--line);
font-family: var(--mono);
font-size: 0.7rem;
color: var(--text-dim);
}
.pulso {
width: 7px; height: 7px;
border-radius: 50%;
background: var(--lime);
box-shadow: 0 0 0 0 rgba(169, 211, 64, 0.6);
animation: pulso 2.4s infinite;
}
@keyframes pulso {
0% { box-shadow: 0 0 0 0 rgba(169, 211, 64, 0.5); }
70% { box-shadow: 0 0 0 9px rgba(169, 211, 64, 0); }
100% { box-shadow: 0 0 0 0 rgba(169, 211, 64, 0); }
}
.traza-cuerpo { padding: 14px 16px 18px; font-family: var(--mono); font-size: 0.79rem; }
.paso {
display: grid;
grid-template-columns: 1fr auto;
gap: 6px 14px;
padding: 8px 0;
border-bottom: 1px dashed var(--line-soft);
opacity: 0;
transform: translateY(6px);
}
.paso.on { opacity: 1; transform: none; transition: opacity .35s ease, transform .35s ease; }
.paso:last-of-type { border-bottom: 0; }
.paso-nombre { color: var(--text); display: flex; align-items: center; gap: 9px; }
.paso-nombre b { font-weight: 500; }
.marca-paso { color: var(--cyan); font-weight: 500; }
.ms { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.detalle {
grid-column: 1 / -1;
padding-left: 22px;
color: var(--text-soft);
display: grid;
gap: 3px;
}
.frag { display: flex; justify-content: space-between; gap: 12px; }
.frag em { font-style: normal; color: var(--lime); }
.frag-nombre { color: var(--text-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.salida {
margin-top: 14px;
padding: 14px 15px;
background: rgba(169, 211, 64, 0.06);
border: 1px solid rgba(169, 211, 64, 0.25);
border-radius: 11px;
font-family: var(--body);
font-size: 0.92rem;
line-height: 1.55;
color: var(--text);
opacity: 0;
transform: translateY(6px);
}
.salida.on { opacity: 1; transform: none; transition: opacity .4s ease, transform .4s ease; }
.umi-mini {
width: 17px;
height: 17px;
vertical-align: -3px;
margin-right: 5px;
color: var(--lime);
}
.salida-rotulo {
display: block;
font-family: var(--mono);
font-size: 0.65rem;
letter-spacing: 0.13em;
text-transform: uppercase;
color: var(--lime);
margin-bottom: 7px;
}
.cursor {
display: inline-block;
width: 7px;
height: 1em;
background: var(--lime);
vertical-align: -2px;
animation: parpadeo 1s steps(2) infinite;
}
@keyframes parpadeo { 50% { opacity: 0; } }
/* ── Secciones ──────────────────────────────────────────────────────────── */
section { padding: 84px 0; border-top: 1px solid var(--line-soft); }
.cabeza { max-width: 36rem; display: grid; gap: 16px; }
.rejilla { display: grid; gap: 1px; margin-top: 48px; background: var(--line-soft); border: 1px solid var(--line-soft); border-radius: 14px; overflow: hidden; }
@media (min-width: 820px) { .rejilla.tres { grid-template-columns: repeat(3, 1fr); } }
.celda {
background: var(--ground);
padding: 26px 24px;
display: grid;
gap: 9px;
align-content: start;
transition: background .2s ease;
}
.celda:hover { background: var(--panel); }
.celda p { color: var(--text-soft); font-size: 0.95rem; }
.celda .clave { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--cyan); }
.duo { display: grid; gap: 44px; align-items: center; }
@media (min-width: 980px) { .duo { grid-template-columns: 1fr 1fr; gap: 64px; } }
.duo.espejo > :first-child { order: 2; }
@media (max-width: 979px) { .duo.espejo > :first-child { order: 0; } }
.texto-bloque { display: grid; gap: 18px; }
.texto-bloque p { color: var(--text-soft); }
/* ── Mapa vectorial ─────────────────────────────────────────────────────── */
.mapa {
position: relative;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 16px;
overflow: hidden;
aspect-ratio: 4 / 3;
transform: perspective(900px) rotateX(0deg) rotateY(0deg);
transition: transform .25s ease, border-color .25s ease;
will-change: transform;
}
@media (hover: hover) and (pointer: fine) {
.mapa:hover { border-color: rgba(61, 220, 232, 0.4); }
}
.mapa canvas { display: block; width: 100%; height: 100%; }
.mapa-pie {
position: absolute;
left: 0; right: 0; bottom: 0;
padding: 11px 15px;
font-family: var(--mono);
font-size: 0.68rem;
color: var(--text-dim);
background: linear-gradient(0deg, var(--panel) 30%, transparent);
display: flex;
justify-content: space-between;
gap: 12px;
}
.mapa-pie em { font-style: normal; color: var(--lime); }
/* ── Tabla de fuentes ───────────────────────────────────────────────────── */
.tabla {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 14px;
overflow: hidden;
}
.tabla-cab {
display: flex; align-items: center; gap: 8px;
padding: 12px 16px;
border-bottom: 1px solid var(--line);
font-family: var(--mono);
font-size: 0.68rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text-dim);
}
.fila {
display: flex; align-items: center; justify-content: space-between;
gap: 14px;
padding: 14px 16px;
border-bottom: 1px solid var(--line-soft);
}
.fila:last-child { border-bottom: 0; }
.fila-nombre { font-size: 0.92rem; }
.fila-sub { font-family: var(--mono); font-size: 0.68rem; color: var(--text-dim); margin-top: 2px; }
.estado { font-family: var(--mono); font-size: 0.69rem; white-space: nowrap; }
.ok { color: var(--lime); }
.viejo { color: var(--amber); }
/* ── Métricas ───────────────────────────────────────────────────────────── */
.metricas { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line-soft); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; }
.metrica { background: var(--panel); padding: 22px; display: grid; gap: 5px; }
.metrica .n { font-family: var(--display); font-weight: 800; font-size: 2rem; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.metrica .n.cyan { color: var(--cyan); }
.metrica .n.lima { color: var(--lime); }
.metrica .t { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-dim); line-height: 1.5; }
/* ── Cierre ─────────────────────────────────────────────────────────────── */
.cierre {
margin: 0 0 80px;
padding: 68px 32px;
text-align: center;
background:
radial-gradient(ellipse 60% 100% at 50% 0%, rgba(61, 220, 232, 0.1), transparent 70%),
var(--panel);
border: 1px solid var(--line);
border-radius: 22px;
}
.cierre p { margin: 18px auto 0; max-width: 32rem; color: var(--text-soft); }
.cierre .acciones { justify-content: center; }
footer {
padding: 34px 0 46px;
border-top: 1px solid var(--line-soft);
font-family: var(--mono);
font-size: 0.71rem;
color: var(--text-dim);
display: flex;
flex-wrap: wrap;
gap: 10px 20px;
justify-content: space-between;
}
footer a { color: var(--text-soft); text-decoration: none; }
footer a:hover { color: var(--cyan); }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after {
animation-duration: .001ms !important;
animation-iteration-count: 1 !important;
transition-duration: .001ms !important;
}
.paso, .salida { opacity: 1 !important; transform: none !important; }
[data-revela] { opacity: 1 !important; transform: none !important; }
.campo, .foco, .traza::after { display: none !important; }
.mapa { transform: none !important; }
}
/* Pantallas chicas: el escenario no necesita tanto aire arriba, y el campo
de fondo se apaga antes para no competir con el texto. */
@media (max-width: 640px) {
.campo { -webkit-mask-image: linear-gradient(to bottom, #000 40%, transparent 78%);
mask-image: linear-gradient(to bottom, #000 40%, transparent 78%); }
.portada { padding-top: 44px; }
}
</style>
</head>
<body>
<div class="capa">
<div class="marco">
<div class="escenario" id="escenario">
<!-- Umi vive en el mismo archivo que la usa: una promo tiene que poder
copiarse a cualquier lado sin arrastrar dependencias. -->
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
<symbol id="umi" viewBox="0 0 120 120">
<circle cx="60" cy="26" r="6" fill="currentColor" />
<line x1="60" y1="32" x2="60" y2="44" stroke="currentColor" stroke-width="4" stroke-linecap="round" />
<path d="M30,46 V76 A30,30 0 0 0 90,76 V46 Z" fill="currentColor" />
<circle cx="47" cy="66" r="6" fill="var(--panel)" />
<circle cx="73" cy="66" r="6" fill="var(--panel)" />
<circle cx="48" cy="67" r="3" fill="#11150F" />
<circle cx="74" cy="67" r="3" fill="#11150F" />
</symbol>
</svg>
<canvas id="campo" class="campo" aria-hidden="true"></canvas>
<div class="foco" id="foco" aria-hidden="true"></div>
<nav class="barra">
<div class="logo"><svg viewBox="0 0 96 96" aria-hidden="true"><path d="M32,42 V58 A14,14 0 0 0 60,58 V42" fill="none" stroke="#06180A" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/><path d="M60,58 V64" fill="none" stroke="#06180A" stroke-width="10" stroke-linecap="round"/><circle cx="60" cy="28" r="7" fill="#06180A"/></svg></div>
<div class="logo-txt">uMind</div>
<div class="chip">IA aplicada</div>
<div class="barra-fin">U&#8209;SITE</div>
</nav>
<!-- ── Portada ──────────────────────────────────────────────────── -->
<div class="portada">
<div>
<div class="eyebrow">Asistente conversacional</div>
<h1>No improvisa.<br /><em>Busca en tu información</em> y después contesta.</h1>
<p class="plomo">
uMind atiende WhatsApp, Telegram y tu sitio con lo que vos le cargaste:
tus precios, tus condiciones, tus horarios. Cada respuesta sale de un
fragmento tuyo, no de lo que el modelo cree recordar.
</p>
<div class="acciones">
<a class="btn btn-solido" href="mailto:soporte@u-site.app?subject=Quiero%20activar%20uMind">Quiero activarlo</a>
<a class="btn btn-linea" href="#mecanica">Ver cómo funciona</a>
</div>
<div class="sello">
<span>Notas de voz</span>
<span>Fotos y PDF</span>
<span>Respuestas con fuente</span>
</div>
</div>
<!-- El recorrido real de una consulta, con sus tiempos. -->
<div class="traza" id="traza">
<div class="traza-barra">
<span class="pulso"></span>
<span>consulta en vivo</span>
<span style="margin-left:auto">whatsapp &middot; 23:41</span>
</div>
<div class="traza-cuerpo">
<div class="paso" data-i="0">
<div class="paso-nombre"><span class="marca-paso">&rsaquo;</span> <b>Mensaje entrante</b></div>
<div class="ms">nota de voz &middot; 0:07</div>
</div>
<div class="paso" data-i="1">
<div class="paso-nombre"><span class="marca-paso">&rsaquo;</span> <b>Audio a texto</b></div>
<div class="ms">1.4 s</div>
<div class="detalle">&ldquo;¿hacen envíos a Chía y cuánto sale el combo de dos?&rdquo;</div>
</div>
<div class="paso" data-i="2">
<div class="paso-nombre"><span class="marca-paso">&rsaquo;</span> <b>Consulta a vector</b></div>
<div class="ms">1536 dim &middot; 89 ms</div>
</div>
<div class="paso" data-i="3">
<div class="paso-nombre"><span class="marca-paso">&rsaquo;</span> <b>Búsqueda en tu conocimiento</b></div>
<div class="ms">3 de 68 &middot; 24 ms</div>
<div class="detalle">
<div class="frag"><span class="frag-nombre">lista-precios-marzo.pdf</span> <em>0.91</em></div>
<div class="frag"><span class="frag-nombre">Horarios y zonas de entrega</span> <em>0.87</em></div>
<div class="frag"><span class="frag-nombre">tunegocio.com/envios</span> <em>0.79</em></div>
</div>
</div>
<div class="paso" data-i="4">
<div class="paso-nombre"><span class="marca-paso">&rsaquo;</span> <b>Respuesta generada</b></div>
<div class="ms">1.1 s</div>
</div>
<div class="salida" id="salida">
<span class="salida-rotulo">
<svg class="umi-mini" viewBox="0 0 120 120" aria-hidden="true"><use href="#umi" /></svg>
Lo que recibe tu cliente
</span>
<span id="texto-salida"></span><span class="cursor" id="cursor"></span>
</div>
</div>
</div>
</div>
</div>
<!-- ── Mecánica ───────────────────────────────────────────────────── -->
<section id="mecanica">
<div class="duo">
<div class="texto-bloque" data-revela style="--retraso:0ms">
<div class="eyebrow">Por qué no inventa</div>
<h2>Tu información, convertida en algo que se puede buscar</h2>
<p>
Cuando cargás una fuente, uMind la parte en fragmentos y convierte cada uno
en un vector: una posición en un espacio donde lo que significa parecido
queda cerca.
</p>
<p>
Cuando llega una pregunta, hace lo mismo con la pregunta y se queda con los
fragmentos <strong>más cercanos</strong>. El modelo redacta la respuesta,
pero solo con eso. Si tu información no lo dice, no lo dice.
</p>
<p>
Es la diferencia entre un asistente que suena bien y uno en el que podés
confiar el precio.
</p>
</div>
<div class="mapa" data-revela style="--retraso:140ms">
<canvas id="lienzo" aria-label="Representación del espacio vectorial: la consulta encuentra los fragmentos más cercanos"></canvas>
<div class="mapa-pie">
<span>espacio vectorial &middot; 68 fragmentos</span>
<span><em>3 vecinos</em> más cercanos</span>
</div>
</div>
</div>
</section>
<!-- ── Fuentes ────────────────────────────────────────────────────── -->
<section>
<div class="cabeza" data-revela>
<div class="eyebrow">Carga de conocimiento</div>
<h2>Tres formas de enseñarle, ninguna técnica</h2>
<p class="plomo" style="font-size:1rem">
Sin entrenar modelos ni escribir reglas. Se carga información y contesta con eso.
</p>
</div>
<div class="rejilla tres" data-revela style="--retraso:90ms">
<div class="celda">
<div class="clave">Escribir</div>
<h3>Lo que solo sabés vos</h3>
<p>
Horarios reales, a qué zonas no llegás, la respuesta que das quince veces
por día. Lo más valioso de tu negocio no está en ningún documento: acá lo
escribís una vez y queda.
</p>
</div>
<div class="celda">
<div class="clave">Subir</div>
<h3>Los archivos que ya tenés</h3>
<p>
PDF, Word, texto, o una foto del papel. La lista de precios, las condiciones
de garantía, la tabla de tallas. Se leen solos, incluso escaneados.
</p>
</div>
<div class="celda">
<div class="clave">Conectar</div>
<h3>Tu sitio web</h3>
<p>
Lee tu página entera y aprende de ahí. Y la vuelve a leer sola cada semana,
así que cuando cambiás un precio, deja de dar el viejo.
</p>
</div>
</div>
</section>
<!-- ── Frescura ───────────────────────────────────────────────────── -->
<section>
<div class="duo espejo">
<div class="texto-bloque" data-revela style="--retraso:0ms">
<div class="eyebrow">Trazabilidad</div>
<h2>Sabés de cuándo es cada cosa que sabe</h2>
<p>
El riesgo de un asistente no es que falle: es que conteste con la información
del año pasado y suene igual de seguro. Por eso cada fuente lleva la fecha en
que se leyó por última vez, y la que se puso vieja se marca sola.
</p>
<p>
Un botón la actualiza en el momento. Tu sitio se relee solo todas las semanas,
de madrugada.
</p>
</div>
<div class="tabla" data-revela style="--retraso:140ms">
<div class="tabla-cab">base de conocimiento &middot; agente principal</div>
<div class="fila">
<div>
<div class="fila-nombre">Horarios y zonas de entrega</div>
<div class="fila-sub">nota &middot; 2 fragmentos</div>
</div>
<div class="estado ok">leído ayer</div>
</div>
<div class="fila">
<div>
<div class="fila-nombre">lista-precios-marzo.pdf</div>
<div class="fila-sub">archivo &middot; 18 fragmentos</div>
</div>
<div class="estado ok">leído hace 4 días</div>
</div>
<div class="fila">
<div>
<div class="fila-nombre">tunegocio.com</div>
<div class="fila-sub">sitio &middot; 42 fragmentos &middot; auto</div>
</div>
<div class="estado ok">leído hoy</div>
</div>
<div class="fila">
<div>
<div class="fila-nombre">condiciones-garantia.docx</div>
<div class="fila-sub">archivo &middot; 6 fragmentos</div>
</div>
<div class="estado viejo">leído hace 3 meses</div>
</div>
</div>
</div>
</section>
<!-- ── Entradas ───────────────────────────────────────────────────── -->
<section>
<div class="cabeza" data-revela>
<div class="eyebrow">Entradas</div>
<h2>Tus clientes no escriben prolijo</h2>
<p class="plomo" style="font-size:1rem">
Mandan audios caminando por la calle, fotos del producto y la factura en PDF.
uMind convierte todo eso en texto antes de responder.
</p>
</div>
<div class="rejilla tres" data-revela style="--retraso:90ms">
<div class="celda">
<div class="clave">Audio</div>
<h3>Notas de voz</h3>
<p>Se transcriben con Whisper y entran a la conversación como si las hubieran escrito. Sin pedirle a nadie que las repita.</p>
</div>
<div class="celda">
<div class="clave">Imagen</div>
<h3>Fotos y capturas</h3>
<p>OCR sobre lo que mandan: el comprobante de pago, la etiqueta del producto, la pantalla del error.</p>
</div>
<div class="celda">
<div class="clave">Archivo</div>
<h3>PDF y Word</h3>
<p>Abre el adjunto, lee lo que hay adentro y responde sobre eso — con el nombre del archivo y lo que la persona escribió al lado.</p>
</div>
</div>
</section>
<!-- ── Canales y control ──────────────────────────────────────────── -->
<section>
<div class="duo">
<div class="texto-bloque" data-revela style="--retraso:0ms">
<div class="eyebrow">Canales y control</div>
<h2>El mismo asistente en los tres lados</h2>
<p>
<strong>WhatsApp</strong> con tu número de siempre, <strong>Telegram</strong>
con tu propio bot, y una <strong>burbuja en tu web</strong> que se instala con
una línea de código. Lo que aprende en uno lo sabe en todos.
</p>
<p>
Desde el panel ves todas las conversaciones y qué contestó en cada una. Si algo
no te gustó, corregís el conocimiento y desde ese momento responde distinto.
Cuando hace falta una persona, lo dice y te pasa la conversación.
</p>
</div>
<div class="metricas" data-revela style="--retraso:140ms" id="metricas">
<div class="metrica">
<div class="n" data-cuenta="312">0</div>
<div class="t">consultas respondidas<br />últimos 7 días</div>
</div>
<div class="metrica">
<div class="n cyan" data-cuenta="41" data-sufijo="&#8239;%">0</div>
<div class="t">fuera del horario<br />de atención</div>
</div>
<div class="metrica">
<div class="n lima" data-cuenta="57">0</div>
<div class="t">notas de voz<br />entendidas</div>
</div>
<div class="metrica">
<div class="n" data-cuenta="9">0</div>
<div class="t">pasadas a<br />una persona</div>
</div>
</div>
</div>
</section>
<!-- ── Cierre ─────────────────────────────────────────────────────── -->
<div class="cierre" data-revela>
<div class="eyebrow" style="justify-content:center">Puesta en marcha</div>
<h2 style="margin-top:16px">Lo dejamos andando con tu información</h2>
<p>
Cargamos lo que ya tenés, lo conectamos a tu WhatsApp y lo probás con tus propias
preguntas antes de que lo vea un cliente.
</p>
<div class="acciones">
<a class="btn btn-solido" href="mailto:soporte@u-site.app?subject=Quiero%20activar%20uMind">Quiero activarlo</a>
<a class="btn btn-linea" href="https://u-site.app">Conocer U&#8209;SITE</a>
</div>
</div>
<footer>
<span>uMind &middot; producto de <a href="https://u-site.app">U&#8209;SITE S.A.S BIC</a></span>
<span>soporte@u-site.app</span>
</footer>
</div>
</div>
<script>
"use strict";
var quieto = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
var toco = window.matchMedia("(hover: none)").matches;
/* ── Titular: decodificación ────────────────────────────────────────────
Cada nodo de texto del h1 se resuelve de izquierda a derecha, como una
transmisión que se sintoniza. Una vez, al cargar, nunca más — repetirlo
por sección sería ruido, acá es la apertura de la página. */
(function () {
var h1 = document.querySelector(".portada h1");
if (!h1 || quieto) return;
var GLIFOS = "01AEIOU#/·-_{}<>";
var nodos = [];
(function juntar(nodo) {
for (var i = 0; i < nodo.childNodes.length; i++) {
var hijo = nodo.childNodes[i];
if (hijo.nodeType === 3 && hijo.textContent.trim() !== "") nodos.push(hijo);
else if (hijo.nodeType === 1) juntar(hijo);
}
})(h1);
var VELOCIDAD = 13; // ms por carácter de retraso entre letras
var acumulado = 0;
nodos.forEach(function (nodo) {
var original = nodo.textContent;
var largo = original.length;
for (var i = 0; i < largo; i++) {
(function (indice) {
var retraso = acumulado + indice * VELOCIDAD;
var vueltas = 5;
var paso = 0;
function tick() {
var actual = nodo.textContent.split("");
if (paso < vueltas) {
actual[indice] = original[indice] === " " ? " " : GLIFOS[(Math.random() * GLIFOS.length) | 0];
nodo.textContent = actual.join("");
paso++;
setTimeout(tick, 34);
} else {
actual[indice] = original[indice];
nodo.textContent = actual.join("");
}
}
// Arranca en blanco (no en texto final) para que el efecto se vea.
setTimeout(function () {
var relleno = nodo.textContent.split("");
relleno[indice] = original[indice] === " " ? " " : GLIFOS[0];
nodo.textContent = relleno.join("");
tick();
}, retraso);
})(i);
}
acumulado += largo * VELOCIDAD + 60;
});
// Mientras decodifica, todos los nodos parten en blanco para que no se
// vea el texto final "de golpe" antes de que arranque la animación.
nodos.forEach(function (nodo) { nodo.textContent = nodo.textContent.replace(/[^\s]/g, " "); });
})();
/* ── Campo ambiental ─────────────────────────────────────────────────────
Puntos que derivan despacio detrás de la portada: el mismo lenguaje visual
del mapa vectorial de más abajo, pero acá sin buscar nada — es sólo el
clima de la página, no la demostración. */
(function () {
var lienzo = document.getElementById("campo");
var escenario = document.getElementById("escenario");
var foco = document.getElementById("foco");
if (!lienzo || !escenario) return;
var ctx = lienzo.getContext("2d");
var puntos = [];
var caja = { w: 0, h: 0 };
function medir() {
var r = escenario.getBoundingClientRect();
var dpr = Math.min(window.devicePixelRatio || 1, 1.6);
caja.w = r.width; caja.h = r.height;
lienzo.width = Math.max(1, Math.round(caja.w * dpr));
lienzo.height = Math.max(1, Math.round(caja.h * dpr));
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
function sembrar() {
var densidad = caja.w < 640 ? 15000 : 9000;
var n = Math.max(24, Math.min(70, Math.round((caja.w * caja.h) / densidad)));
puntos = [];
for (var i = 0; i < n; i++) {
puntos.push({
x: Math.random() * caja.w,
y: Math.random() * caja.h,
vx: (Math.random() - 0.5) * 0.10,
vy: (Math.random() - 0.5) * 0.10,
r: 1 + Math.random() * 1.3
});
}
}
var RADIO_ENLACE = 118;
function pintar() {
ctx.clearRect(0, 0, caja.w, caja.h);
for (var i = 0; i < puntos.length; i++) {
var a = puntos[i];
a.x += a.vx; a.y += a.vy;
if (a.x < -20) a.x = caja.w + 20; if (a.x > caja.w + 20) a.x = -20;
if (a.y < -20) a.y = caja.h + 20; if (a.y > caja.h + 20) a.y = -20;
for (var j = i + 1; j < puntos.length; j++) {
var b = puntos[j];
var dx = a.x - b.x, dy = a.y - b.y;
var d = Math.sqrt(dx * dx + dy * dy);
if (d < RADIO_ENLACE) {
ctx.strokeStyle = "rgba(140, 155, 181, " + (0.12 * (1 - d / RADIO_ENLACE)) + ")";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(a.x, a.y);
ctx.lineTo(b.x, b.y);
ctx.stroke();
}
}
}
for (var k = 0; k < puntos.length; k++) {
var p = puntos[k];
ctx.beginPath();
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fillStyle = "rgba(150, 168, 196, 0.4)";
ctx.fill();
}
if (!quieto) requestAnimationFrame(pintar);
}
medir(); sembrar();
if (quieto) { pintar(); } else { requestAnimationFrame(pintar); }
var espera1;
window.addEventListener("resize", function () {
clearTimeout(espera1);
espera1 = setTimeout(function () { medir(); sembrar(); if (quieto) pintar(); }, 200);
});
// El foco que sigue el mouse: sólo con puntero fino, y desactivado si el
// usuario pidió menos movimiento.
if (!toco && !quieto && foco) {
escenario.addEventListener("pointermove", function (e) {
var r = escenario.getBoundingClientRect();
var mx = ((e.clientX - r.left) / r.width) * 100;
var my = ((e.clientY - r.top) / r.height) * 100;
escenario.style.setProperty("--mx", mx + "%");
escenario.style.setProperty("--my", my + "%");
escenario.classList.add("con-foco");
});
escenario.addEventListener("pointerleave", function () {
escenario.classList.remove("con-foco");
});
}
})();
/* ── Revelado por scroll ─────────────────────────────────────────────────
Cada bloque marcado con data-revela entra la primera vez que aparece en
pantalla; una vez visto, queda visto — no vuelve a esconderse al subir. */
(function () {
var bloques = document.querySelectorAll("[data-revela]");
if (!bloques.length) return;
if (quieto || typeof IntersectionObserver === "undefined") {
bloques.forEach(function (b) { b.classList.add("visto"); });
return;
}
var obs = new IntersectionObserver(function (entradas) {
entradas.forEach(function (entrada) {
if (entrada.isIntersecting) {
entrada.target.classList.add("visto");
obs.unobserve(entrada.target);
}
});
}, { threshold: 0.16, rootMargin: "0px 0px -8% 0px" });
bloques.forEach(function (b) { obs.observe(b); });
})();
/* ── Métricas: conteo ────────────────────────────────────────────────────
Los números suben desde cero cuando el panel entra en pantalla, una sola
vez — no cuenta de nuevo si el visitante vuelve a pasar por ahí. */
(function () {
var panel = document.getElementById("metricas");
if (!panel) return;
var celdas = panel.querySelectorAll("[data-cuenta]");
function contar() {
celdas.forEach(function (celda) {
var meta = parseInt(celda.getAttribute("data-cuenta"), 10);
var sufijo = celda.getAttribute("data-sufijo") || "";
if (quieto) { celda.textContent = meta + sufijo; return; }
var t0 = performance.now();
var dur = 900;
function paso(ahora) {
var f = Math.min(1, (ahora - t0) / dur);
var f2 = 1 - Math.pow(1 - f, 3);
celda.textContent = Math.round(meta * f2) + sufijo;
if (f < 1) requestAnimationFrame(paso);
}
requestAnimationFrame(paso);
});
}
if (typeof IntersectionObserver === "undefined") { contar(); return; }
var obs2 = new IntersectionObserver(function (entradas) {
entradas.forEach(function (entrada) {
if (entrada.isIntersecting) { contar(); obs2.unobserve(entrada.target); }
});
}, { threshold: 0.4 });
obs2.observe(panel);
})();
/* ── La traza ────────────────────────────────────────────────────────────
Los pasos aparecen con la latencia que dicen mostrar: si la búsqueda dice
24 ms y tarda dos segundos en aparecer, la página se contradice sola. */
(function () {
var pasos = document.querySelectorAll(".paso");
var salida = document.getElementById("salida");
var destino = document.getElementById("texto-salida");
var cursor = document.getElementById("cursor");
var frase =
"Sí, hacemos envíos a Chía: llega al día siguiente y el envío cuesta $12.000. " +
"El combo de dos está en $89.000.";
if (quieto) {
for (var i = 0; i < pasos.length; i++) pasos[i].classList.add("on");
salida.classList.add("on");
destino.textContent = frase;
cursor.style.display = "none";
return;
}
var demoras = [500, 1900, 2400, 2700, 3900];
demoras.forEach(function (ms, i) {
setTimeout(function () { pasos[i].classList.add("on"); }, ms);
});
setTimeout(function () {
salida.classList.add("on");
var n = 0;
var reloj = setInterval(function () {
destino.textContent = frase.slice(0, ++n);
if (n >= frase.length) { clearInterval(reloj); cursor.style.display = "none"; }
}, 22);
}, 4400);
})();
/* ── Mapa vectorial ──────────────────────────────────────────────────────
Canvas y no SVG a mano: son ~70 puntos con posiciones generadas, y
dibujarlos como paths sería una tira de números que nadie puede leer.
Muestra lo que hace el buscador: llega la consulta, se iluminan los tres
fragmentos más cercanos. */
(function () {
var lienzo = document.getElementById("lienzo");
if (!lienzo) return;
var ctx = lienzo.getContext("2d");
var puntos = [];
var consulta = null;
var vecinos = [];
var t0 = 0;
function medir() {
var r = lienzo.getBoundingClientRect();
var dpr = Math.min(window.devicePixelRatio || 1, 2);
lienzo.width = Math.max(1, Math.round(r.width * dpr));
lienzo.height = Math.max(1, Math.round(r.height * dpr));
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
return { w: r.width, h: r.height };
}
var caja = medir();
// Tres racimos: los fragmentos de una misma fuente caen cerca entre sí,
// que es exactamente lo que hace que la búsqueda funcione.
function sembrar() {
puntos = [];
var centros = [
{ x: 0.30, y: 0.34 },
{ x: 0.68, y: 0.30 },
{ x: 0.52, y: 0.70 }
];
for (var c = 0; c < centros.length; c++) {
for (var i = 0; i < 22; i++) {
var a = Math.random() * Math.PI * 2;
var r = Math.pow(Math.random(), 0.6) * 0.17;
puntos.push({
x: (centros[c].x + Math.cos(a) * r) * caja.w,
y: (centros[c].y + Math.sin(a) * r * 1.15) * caja.h,
f: 0.4 + Math.random() * 0.6,
d: Math.random() * Math.PI * 2
});
}
}
}
function lanzarConsulta() {
// La consulta se ubica a cierta distancia de todo: si cae encima de un
// racimo, los tres vecinos quedan pisados y no se ve que los está
// buscando, que es justamente lo que la animación tiene que mostrar.
var minimo = caja.w * 0.11;
for (var intento = 0; intento < 24; intento++) {
consulta = { x: (0.22 + Math.random() * 0.56) * caja.w, y: (0.22 + Math.random() * 0.56) * caja.h };
var masCerca = Infinity;
for (var j = 0; j < puntos.length; j++) {
var ax = puntos[j].x - consulta.x, ay = puntos[j].y - consulta.y;
masCerca = Math.min(masCerca, Math.sqrt(ax * ax + ay * ay));
}
if (masCerca > minimo) break;
}
var orden = puntos
.map(function (p, i) {
var dx = p.x - consulta.x, dy = p.y - consulta.y;
return { i: i, d: dx * dx + dy * dy };
})
.sort(function (a, b) { return a.d - b.d; });
vecinos = [orden[0].i, orden[1].i, orden[2].i];
t0 = performance.now();
}
function pintar(ahora) {
ctx.clearRect(0, 0, caja.w, caja.h);
var fase = (ahora - t0) / 1000;
// Enlaces a los vecinos, dibujados a medida que "viaja" la búsqueda.
if (consulta) {
for (var k = 0; k < vecinos.length; k++) {
var p = puntos[vecinos[k]];
var avance = Math.max(0, Math.min(1, (fase - 0.25 - k * 0.16) * 2.4));
if (avance <= 0) continue;
ctx.beginPath();
ctx.moveTo(consulta.x, consulta.y);
ctx.lineTo(consulta.x + (p.x - consulta.x) * avance, consulta.y + (p.y - consulta.y) * avance);
ctx.strokeStyle = "rgba(169, 211, 64, " + (0.5 * avance) + ")";
ctx.lineWidth = 1;
ctx.stroke();
}
}
for (var i = 0; i < puntos.length; i++) {
var q = puntos[i];
var cerca = consulta && vecinos.indexOf(i) >= 0;
var llego = cerca && fase > 0.25 + vecinos.indexOf(i) * 0.16 + 0.4;
var brillo = 0.30 + Math.sin(ahora / 900 + q.d) * 0.07;
ctx.beginPath();
ctx.arc(q.x, q.y, llego ? 4 : 2, 0, Math.PI * 2);
ctx.fillStyle = llego
? "rgba(169, 211, 64, 0.95)"
: "rgba(150, 168, 196, " + (brillo + q.f * 0.22) + ")";
ctx.fill();
if (llego) {
ctx.beginPath();
ctx.arc(q.x, q.y, 10, 0, Math.PI * 2);
ctx.strokeStyle = "rgba(169, 211, 64, 0.32)";
ctx.lineWidth = 1;
ctx.stroke();
}
}
if (consulta) {
var pulso = 5 + Math.sin(ahora / 220) * 1.4;
ctx.beginPath();
ctx.arc(consulta.x, consulta.y, pulso, 0, Math.PI * 2);
ctx.fillStyle = "rgba(61, 220, 232, 0.95)";
ctx.fill();
ctx.beginPath();
ctx.arc(consulta.x, consulta.y, pulso + 8, 0, Math.PI * 2);
ctx.strokeStyle = "rgba(61, 220, 232, 0.28)";
ctx.lineWidth = 1;
ctx.stroke();
}
if (fase > 4.5) lanzarConsulta();
if (!quieto) requestAnimationFrame(pintar);
}
sembrar();
lanzarConsulta();
if (quieto) {
pintar(performance.now() + 2000);
} else {
requestAnimationFrame(pintar);
}
var espera;
window.addEventListener("resize", function () {
clearTimeout(espera);
espera = setTimeout(function () {
caja = medir();
sembrar();
lanzarConsulta();
if (quieto) pintar(performance.now() + 2000);
}, 180);
});
})();
/* ── Inclinación del panel del mapa ──────────────────────────────────────
Un tilt de un par de grados hacia el cursor — sólo con mouse, nunca en
touch, donde no significa nada y sólo estorbaría el scroll. */
(function () {
if (quieto || toco) return;
var panel = document.querySelector(".mapa");
if (!panel) return;
panel.addEventListener("pointermove", function (e) {
var r = panel.getBoundingClientRect();
var px = (e.clientX - r.left) / r.width - 0.5;
var py = (e.clientY - r.top) / r.height - 0.5;
panel.style.transform = "perspective(900px) rotateX(" + (py * -5) + "deg) rotateY(" + (px * 6) + "deg)";
});
panel.addEventListener("pointerleave", function () {
panel.style.transform = "perspective(900px) rotateX(0deg) rotateY(0deg)";
});
})();
</script>
</body>
</html>