Aurora · client · fase 1
Retintada de producto · apps/client

La familia
completa de la puerta

El shell aurora, la placa y los tokens ya están construidos y validados. Esto no es un rediseño: es vestir con ellos las siete rutas de auth que faltan del client, resolver de verdad las dos que sí piden diseño —las cajas de OTP y la checklist de contraseña— y llegar hasta el otro lado de la puerta: el sidebar y el topbar a los que se entra. Todo a 1440 y a 390.

7 rutas · 10 pantallas OTP y checklist en vivo 1440 + 390 Placa solo en /activate Cero colores nuevos
Retintada, no rediseño
01 — el encargo

AuroraShell, BrandPlate y los tokens --mogos-* ya viven en packages/ui y corren en local. Las dos puertas de /login y el regreso de Google están hechos. Lo que falta son siete rutas del client que hoy siguen siendo un formulario centrado sobre bg-background, sin marca, con el isotipo de 36×32 flotando arriba a la derecha.

El tono es «puerta», no «formulario»: entrar a Mogos es cruzar un umbral. Por eso estas pantallas heredan el shell en vez de inventar el suyo, y por eso la placa «Importamos futuro» aparece exactamente donde se abre una sesión — una sola vez en las siete.

Medidas ya calibradas Salieron de medir el CSS de la pieza publicada, no de inventarlas. Se respetan.
6 px
etiqueta → campo
.f-lb
14 px
campo → siguiente etiqueta
.f-in
11 px
radio de campo · padding 11/13 · texto 13
.f-in
46 × 3
la regla degradada · la firma de la casa, la misma de los correos
.f-rule
409 px
columna de formulario sobre un marco de 920
920 − 46 % − (44+44)
46 %
panel aurora · en móvil colapsa a banda de 180 px
.pane
Cómo leer las maquetas

Las escenas de escritorio miden 920 px y representan un viewport de 1440: lo real es la proporción, no el número. 409 sobre 920 es el 44.5 % que el formulario ocupa a 1440. Las escenas móviles miden 390 px y son 1:1.

Cuatro cosas que el código dijo
02 — inventario

Antes de dibujar se leyeron las siete rutas. Cuatro hallazgos cambiaron el encargo, y quedan acá escritos porque el encargo original no los contemplaba.

01 Los OTP ya son cajitas — y hay tres

/verify-otp y /verify-whatsapp-otp maquetan seis <input> pegados a mano, con focus:ring-brand-500 — o sea el azul del producto #3765c0, no el celeste de la marca. /forgot-password usa el InputOTP de shadcn que ya vive en packages/ui.

El trabajo no es inventar la caja: es elegir una y matar dos. Converge todo en el InputOTP de packages/ui, retintado.

02 La checklist ya existe y ya marca en vivo

password-requirements.tsx corre sobre usePasswordValidation y pinta bg-green-100 / text-green-600 / text-gray-500: tres valores de plantilla Tailwind fuera de la paleta.

El comportamiento ya era el correcto. Lo que cambia es la tinta — y el gray-500 a 12 px sobre blanco da ~4.6:1, que no llega a AA en ese tamaño.

03 Siete rutas no son siete pantallas

/register son 2 pasos · /activate son 3 estadios · /forgot-password son 3 pasos (correo → OTP → contraseña) — o sea que ya carga OTP y contraseña, algo que el contrato de fase no decía · /complete-profile son 5 pasos más confirmación.

Se dibujan las siete rutas más los sub-pasos que cambian de forma: diez pantallas. Un paso que repite el patrón anterior no gana escena, gana una regla escrita.

04 La placa de /register cae en un formulario

register/page.tsx:112 hace router.push('/verify-otp?email=…'). Ahí no se abre ninguna sesión: se celebraría «Importamos futuro» para descubrir detrás otra caja de OTP.

La placa sale de /register. De estas siete rutas queda únicamente en /activate. La placa marca una puerta, no un envío — esa es toda la regla, y aplicarla es lo que la vuelve real.

Una caja por dígito
03 — diseño real

Seis cajas de 44 × 48 separadas por 8 px. 44 es el piso de área táctil, y la separación es lo único que deja leer cuál caja tiene el foco: sin costura, seis inputs se leen como un solo campo y el cursor no dice en qué dígito estás. Radio 11, padding y foco idénticos a los del resto de campos — la caja de OTP no es un widget aparte, es el mismo campo repetido seis veces.

Avance automático al escribir · borrado hacia atrás que salta a la caja anterior cuando la actual ya está vacía · pegado de los seis dígitos de golpe desde cualquier caja, no solo la primera (hoy solo la primera lo acepta).

Demo vivafunciona Escribe, pega un código de 6 dígitos, borra hacia atrás. 123456 entra; cualquier otro da error.
El código ingresado es inválido o ha expirado.
El reenvío es un elemento, no dos

Hoy hay un botón que cambia de texto y a veces otro al lado. Acá es uno solo con dos estados: deshabilitado muestra «Reenviar en 45 s» con la cuenta bajando, y a cero se convierte en «Reenviar código» activo. El número va en tabular-nums para que el texto no baile cada segundo — sin eso, «Reenviar en 9 s» y «Reenviar en 45 s» tienen anchos distintos y la línea salta.

El aro de la izquierda solo existe mientras corre la cuenta: es la única pista de que el botón está esperando y no roto.

El estado real viaja en un aria-live="polite" — «Código completo», «Verificando…», el error. Las cajas por sí solas no le cuentan nada a un lector de pantalla.

Los seis estados Incluye la versión noche, porque /forgot-password del admin también tiene paso de código.
Vacío
Borde --line sobre blanco. Ningún foco automático: robarle el cursor a alguien que llegó leyendo es hostil.
49
Escribiendo
La caja activa toma --celeste-deep, halo de 3 px al 18 % y sube 1 px. El avance es automático.
123456
Completo
El grupo entero toma el borde celeste y el botón se habilita. La confirmación es del grupo, no de la última caja.
111111
Código inválido o expirado.
Error
Sacudida de 300 ms, mensaje debajo y foco devuelto al primer dígito — no al último, que es donde el error dejó el cursor.
123456
Verificando
Grupo a 0.55 y sin eventos; el spinner vive en el botón. Nunca la placa: esto es un envío, no una puerta.
123456
Noche
Fondo rgba(1,18,58,.52), borde --line-onmarino, foco en --celeste (no en celeste-deep: sobre marino se apaga).
Requisitos que se marcan solos
04 — diseño real

Seis reglas que se marcan mientras escribes, no al enviar. El comportamiento ya existía en usePasswordValidation; lo que cambia es que el disco cambia de color, no solo el ícono — a 11 px un tick verde sobre gris claro es un detalle que se pierde, un disco que se llena no.

La sexta regla —«Ambas contraseñas coinciden»— solo se evalúa cuando el campo de confirmación tiene algo. Marcarla en rojo mientras el campo está vacío es regañar a alguien por no haber terminado de escribir.

Demo vivafunciona Escribe una contraseña y confírmala. Los discos responden en cada tecla.
Debe tener una longitud de 8 a 32 caracteres
Debe tener al menos 1 letra mayúscula
Debe tener al menos 1 letra minúscula
Debe tener al menos 1 número
Debe tener al menos un carácter especial
Ambas contraseñas coinciden
Los tres estados del disco

Pendiente — disco --line-soft, guion en --ink-soft. Es una tarea por hacer, no un fallo: no se pinta de rojo lo que todavía nadie intentó.

Cumplida — disco --state-success-soft, tick en --state-success, entrando con --ease-spring en 240 ms. El rebote es lo que se ve por el rabillo del ojo mientras escribes.

Fallida — solo la de coincidencia, y solo cuando hay algo que comparar: disco --state-danger-soft, aspa en --rojo, texto en --rojo-deep.

Bajo prefers-reduced-motion el estado cambia igual, sin el rebote. La información nunca depende de la animación.

Los tres estados, congelados Lo que hoy es bg-green-100 y text-gray-500, traducido a la paleta.
Debe tener al menos 1 número
Debe tener al menos 1 mayúscula
Pendiente
Disco --line-soft, guion en --ink-soft. Es una tarea por hacer, no un fallo — no se pinta de rojo lo que nadie intentó.
Debe tener al menos 1 número
Debe tener al menos 1 mayúscula
Cumplida
Disco --state-success-soft, tick en --state-success, entrando con --ease-spring en 240 ms.
Debe tener al menos 1 número
Ambas contraseñas coinciden
Fallida
Solo la de coincidencia, y solo con algo que comparar: disco --state-danger-soft, aspa en --rojo, texto en --rojo-deep.
Las siete puertas a 1440
05 — diez pantallas

Todas heredan el split: formulario claro a la izquierda, panel aurora al 46 % a la derecha. El panel no cambia de una ruta a otra — ese es el punto. Lo que cambia es lo que se pide, y la marca queda constante detrás de todo el trayecto.

/register · paso 1 de 2retinte Los datos. El registro es el único de los siete que trae OAuth: Google entra acá y en ningún otro lado.
Paso 1 de 2
Regístrate
Comencemos. Completa los detalles a continuación para crear tu cuenta.
Nombre
Ingresa tu nombre
Apellido
Ingresa tu apellido
Correo electrónico
Ingresa tu correo electrónico
Número de teléfono
+58
Ingresa tu número de teléfono
Acepto los Términos y Condiciones
Quiero recibir notificaciones
o
¿Ya tienes cuenta? Inicia sesión
/register · paso 2 de 2retinte sin placa Acá vivía la placa en el contrato original. Sale: este botón lleva a /verify-otp, no a una sesión.
Paso 2 de 2
Regístrate
Para finalizar, crea una contraseña segura que cumpla con los requisitos de seguridad.
Contraseña
••••••••••
Confirma tu contraseña
••••••••
Debe tener una longitud de 8 a 32 caracteres
Debe tener al menos 1 letra mayúscula
Debe tener al menos 1 letra minúscula
Debe tener al menos 1 número
Debe tener al menos un carácter especial
Ambas contraseñas coinciden
¿Ya tienes cuenta? Inicia sesión
/verify-otpcajas nuevas El correo va enmascarado — maskEmail() ya existe. Mostrarlo entero en una pantalla de verificación es regalar la mitad del par.
Paso 1 de 4
Código OTP
Introduce el código enviado a a•••••z@gmail.com. Si no lo encuentras, revisa spam o vuelve a enviarlo.
Código de 6 dígitos
492713
¿Correo equivocado? Volver al registro
/verify-whatsapp-otpcajas nuevas Misma caja, mismo reenvío. Solo cambia por dónde llegó el código — y eso se dice, no se dibuja distinto.
Paso 2 de 4
Verificar WhatsApp
Introduce el código enviado a ••••••4821. Si no lo encuentras, verifica que recibiste el mensaje por WhatsApp.
Código enviado por WhatsApp
Código de 6 dígitos
70
Volver al inicio de sesión
/forgot-password · paso 1 de 3retinte Un campo y un botón. La aurora es lo que impide que una pantalla de una sola línea se sienta abandonada.
Paso 1 de 3
¿Olvidaste tu contraseña?
Introduce el correo electrónico vinculado a tu cuenta y te enviaremos un código para recuperar el acceso.
Correo electrónico
ana@puertoflete.com
Volver al inicio de sesión
/forgot-password · paso 2 de 3cajas nuevas El paso que el contrato de fase no tenía anotado: recuperar contraseña también pide un código.
Paso 2 de 3
Revisa tu correo
Ingresa el código de 6 dígitos que recibiste en a•••••a@puertoflete.com.
Correo enviado exitosamente. Si no lo recibes en unos minutos, revisa tu carpeta de spam.
Código de verificación
318
Volver
/reset-passwordchecklist nueva Es también el paso 3 de /forgot-password: una sola pantalla sirve a las dos entradas.
Paso 3 de 3
Nueva contraseña
Crea una contraseña segura para tu cuenta. La usarás para iniciar sesión a partir de ahora.
Contraseña
•••••••••••
Confirma tu contraseña
•••••••••••
Debe tener una longitud de 8 a 32 caracteres
Debe tener al menos 1 letra mayúscula
Debe tener al menos 1 letra minúscula
Debe tener al menos 1 número
Debe tener al menos un carácter especial
Ambas contraseñas coinciden
/activate · bienvenidaretinte Sin número de paso: la bienvenida no es un paso, es la explicación de por qué hay pasos.
¡Bienvenido de vuelta!
Mogos tiene una nueva versión. Para mantener tu cuenta segura, necesitamos que confirmes tu identidad y crees una nueva contraseña.
Te enviaremos un código de 6 dígitos a:
ana@puertoflete.com
¿No es tu correo? Contáctanos
/activate · paso 2 de 2la única con placa Acá sí se abre sesión: al guardar la contraseña la cuenta queda activa y se entra. Es la única puerta de las siete.
Dispara la placa con su piso de 1.4 s y la deja ver el destino.
Paso 2 de 2
Crea tu contraseña
Crea una contraseña para tu cuenta. La usarás para iniciar sesión a partir de ahora.
Contraseña
••••••••••••
Confirma tu contraseña
••••••••••••
Debe tener una longitud de 8 a 32 caracteres
Debe tener al menos 1 letra mayúscula
Debe tener al menos 1 letra minúscula
Debe tener al menos 1 número
Debe tener al menos un carácter especial
Ambas contraseñas coinciden
/complete-profileshell + tinta fase 1 · alcance parcial Cinco pasos, stepper propio y mapa. Acá entra el shell y la tinta; el stepper y el mapa tienen su propia fase.
4
Agrega tu dirección
Necesitamos tu dirección para poder gestionar tus envíos.
Para garantizar la calidad y seguridad de nuestros servicios de envío, necesitamos verificar tu información.
Saltar
Por qué /complete-profile no lleva placa

Cuando alguien llega acá la sesión ya existe — entró por Google o acaba de verificar su correo. Es un formulario, no una puerta. Poner «Importamos futuro» al guardar una dirección gasta el único gesto que la marca tiene reservado para el momento en que se abre el acceso.

Las mismas puertas a 390
06 — responsive

El split no se apila entero. El panel colapsa a una banda de 180 px de piso que conserva los dos glows, el monograma y el eslogan; el formulario queda debajo, en claro. La banda usa min-height, nunca height fija: a 180 px planos el panel recortaba su propio contenido y el eslogan perdía el borde superior.

En el producto el orden del DOM es flex-col-reverse: el formulario va primero y la banda se pinta encima. Así el teclado y el lector de pantalla llegan al primer campo sin cruzar la decoración, mientras el ojo sí ve la marca arriba.

Desplázate en horizontal Siete marcos a 390 px, 1:1 con el viewport real.
Importamos futuro
Paso 1 de 2
Regístrate
Comencemos. Completa los detalles a continuación para crear tu cuenta.
Nombre
Nombre
Apellido
Apellido
Correo electrónico
Ingresa tu correo
Número de teléfono
+58
Tu número
Acepto los Términos y Condiciones
o
Importamos futuro
Paso 2 de 2
Regístrate
Para finalizar, crea una contraseña segura.
Contraseña
••••••••••
Confirma tu contraseña
••••••••••
Longitud de 8 a 32 caracteres
Al menos 1 letra mayúscula
Al menos 1 letra minúscula
Al menos 1 número
Al menos un carácter especial
Ambas contraseñas coinciden
Importamos futuro
Paso 1 de 4
Código OTP
Introduce el código enviado a a•••••z@gmail.com.
Código de 6 dígitos
492713
¿Correo equivocado? Volver al registro
Importamos futuro
Paso 2 de 3
Revisa tu correo
Ingresa el código de 6 dígitos que te enviamos.
Correo enviado. Si no lo recibes, revisa tu carpeta de spam.
Código de verificación
111111
El código ingresado es inválido o ha expirado.
Volver
Importamos futuro
Paso 3 de 3
Nueva contraseña
Crea una contraseña segura para tu cuenta.
Contraseña
•••••••••••
Confirma tu contraseña
•••••••••••
Longitud de 8 a 32 caracteres
Al menos 1 letra mayúscula
Al menos 1 letra minúscula
Al menos 1 número
Al menos un carácter especial
Ambas contraseñas coinciden
Importamos futuro
Paso 2 de 2
Crea tu contraseña
La usarás para iniciar sesión a partir de ahora.
Contraseña
••••••••••••
Confirma tu contraseña
••••••••••••
Longitud de 8 a 32 caracteres
Al menos 1 letra mayúscula
Al menos 1 número
Ambas contraseñas coinciden
La placa cubre la pantalla completa
Importamos futuro
4
Agrega tu dirección
Necesitamos tu dirección para poder gestionar tus envíos.
Saltar
Las tres que no ganan marco

/verify-whatsapp-otp es idéntica a /verify-otp salvo el texto y la píldora de canal · /forgot-password paso 1 es un campo y un botón, el caso más simple del sistema · /activate bienvenida es el mismo bloque de texto más el correo en un campo de solo lectura. Dibujarlas sería repetir, no diseñar.

La regla que las cubre: bajo 768 px toda ruta de auth es banda de 180 px + formulario en claro, con 22 px de margen lateral y el botón a ancho completo. La caja de OTP no se encoge — 6×44 + 5×8 = 304 px caben de sobra en los 346 útiles.

El otro lado de la puerta
07 — sidebar y topbar

Una puerta sin destino no se puede juzgar. La placa se levanta y lo que queda detrás es esto: sidebar a la izquierda, topbar arriba. Entra en la misma pieza porque es donde el retinte tiene que aterrizar — si la puerta es marino y el destino es genérico, la marca dura 1.4 segundos.

Y hay una trampa concreta: el estado activo del sidebar no puede pintarse con --primary. Ese token es #3765c0, el azul del producto, y remapearlo repinta las dos apps enteras. El activo se marca con superficie --celeste-soft, tinta marino y una barra de 3 px con --grad-marca — la misma regla degradada de los correos, puesta de canto.

Escritorio · 1440retinte Nav real de client-sidebar.tsx: cinco grupos, catorce destinos, ni uno inventado.
Todas las rutas Dashboard/Resumen
AC
Hola, Ana
Esto es lo que se movió desde tu última visita.
En tránsito
12
+3 esta semana
En aduanas
4
2 con retraso
En almacén
28
Cantón · Shenzhen
Por pagar
2
Vence en 3 días
GuíaRutaEstadoETA
MG-24817Cantón → La GuairaEn tránsito12 ago
MG-24803Shenzhen → La GuairaEn aduanas08 ago
MG-24796Miami → CaracasPor pagar10 ago
MG-24771Cantón → Puerto CabelloEntregado02 ago
MG-24754Yiwu → La GuairaEn tránsito19 ago
Móvil · 390retinte El sidebar no se convierte en cajón: bajo 768 px manda MobileShell, con sus cuatro pestañas y el FAB entre la segunda y la tercera.
Todas AC
Hola, Ana
Esto es lo que se movió.
En tránsito
12
+3 esta semana
En aduanas
4
2 con retraso
En almacén
28
Cantón
Por pagar
2
Vence pronto
MG-24817Cantón → La GuairaEn tránsito
MG-24803Shenzhen → La GuairaEn aduanas
MG-24796Miami → CaracasPor pagar
MG-24771Cantón → Puerto CabelloEntregado
Todas AC
Hola, Ana
La placa acaba de levantarse de acá.
En tránsito
12
+3 esta semana
Por pagar
2
Vence pronto
MG-24817Cantón → La GuairaEn tránsito
MG-24803Shenzhen → La GuairaEn aduanas
MG-24796Miami → CaracasPor pagar
Lo que ve alguien que acaba de activar su cuenta desde el teléfono.
El activo, sin tocar --primary

Superficie --celeste-soft, tinta --marino, y una barra de 3 px con --grad-marca pegada al borde izquierdo. Se lee de inmediato y no toma prestado un solo token del producto.

El topbar se apoya, no compite

40 px, fondo --hueso al 90 % con backdrop-filter, una sola línea abajo. La marca ya la carga el sidebar: repetirla arriba sería decir el nombre dos veces en la misma frase.

El FAB es el único degradado

--grad-marca aparece en la app en dos sitios: la barra del activo y el botón de crear. Un degradado que sale en todas partes deja de ser una firma y pasa a ser textura.

Qué lleva placa y qué no
08 — la tabla

«Importamos futuro» es el momento en que se abre la sesión, no un spinner de propósito general. Una regla de una línea: la placa marca una puerta, no un envío de formulario. Aplicada de verdad, deja una sola placa nueva en las siete rutas de esta fase.

RutaPlacaPor qué
client /loginYa hecho. Se abre la sesión.
admin /loginYa hecho. Se abre la sesión.
/auth/callbackYa hecho. Es el regreso de Google — el clic en Google no puede animar nada porque la redirección lo corta.
/activate · paso 2La única nueva. Al guardar la contraseña la cuenta queda activa y se entra.
/register · paso 2NocambioEl contrato original la ponía acá. register/page.tsx:112 navega a /verify-otp: no se abre sesión, se pide otro código.
/register · paso 1NoEs un «Siguiente». Ni siquiera envía nada al servidor.
/verify-otpNoEnvío de formulario. El botón conserva su spinner.
/verify-whatsapp-otpNoIgual: se verifica un dato, no se abre una puerta.
/forgot-password · 1-3NoLos tres pasos son envíos. Celebrar «pedí un código» vacía el gesto.
/reset-passwordNoCambia una credencial y devuelve al login. La puerta viene después.
/complete-profileNoLa sesión ya existe. Es un formulario, no una puerta.
logoutNoLa salida es instantánea. No se anima irse.
El contrato de tiempos, que no es decoración

La placa tiene un piso de 1.4 s y la petición corre en paralelo, así que el tiempo percibido es 1.4 s en vez de 300 ms + 1.4 s. Si la petición falla, la placa se retira en 220 ms y el error aparece bajo el campo con el foco devuelto ahí — nunca queda una celebración colgada sobre algo que no ocurrió.

Se resetea en pageshow: sin eso, volver con el botón atrás revive la página desde bfcache con la placa encima, tapando la puerta. Y bajo prefers-reduced-motion no hay placa: se navega directo y el botón conserva su spinner.

Cicatrices
09 — restricciones con su causa

Una regla sin su porqué es una regla que alguien rompe. Estas seis salieron de romperlas primero, y por eso vienen con la marca de cómo dolió.

Nunca remapear --primary, --primary-foreground ni --ring.
Son el azul del producto — #3765c0 — y viven en cada botón, cada foco y cada tabla de las dos apps. Tocarlos para «que combine con el marino» repinta client y admin enteros en el mismo commit. Los tokens --mogos-* añaden paleta; no sustituyen ninguna.
El CSS de la escena vive en una hoja importada desde globals.css. Nada de <style> dentro del componente.
React 19 hoistea, deduplica y trunca los <style> hijos. En el App Router llegó cortado: las reglas del split se cayeron y el panel aurora colapsó del 46 % a 21.6 % — el ancho que midió su propio contenido. Una hoja importada se carga una vez, en orden, y no puede aplicarse a medias.
Sobre #AAE4F3 la tinta es marino. El texto apagado sobre blanco es #3A4A72.
El celeste es tan claro que el blanco encima no pasa AA — parece que sí hasta que se mide. Marino sobre celeste da 14.57:1. Y el gris de plantilla a 12 px sobre blanco da ~3.5:1: el texto secundario usa --ink-soft, que es marino aclarado, no un gris cualquiera. Contraste medido sobre la superficie pintada, no token contra token.
prefers-reduced-motion apaga las tres capas en movimiento.
Los dos glows y el barrido de ::before. La lista que olvida una es la regresión que nadie ve venir: la escena parece quieta hasta que el tercer plano sigue girando a 44 s por vuelta detrás de un formulario. Nombrar las tres explícitamente es la única defensa — ningún test lo atrapa.
El layout de (auth) no decora nada. Cada puerta pinta su propia superficie.
Hoy los dos layout.tsx posicionan un MogosIcon absoluto arriba a la derecha. Con el shell puesto, ese ícono queda flotando sobre la aurora, a 36×32 y con sus fills quemados. Se va. Cada ruta llega ella misma hasta el borde de la ventana.
Un page.tsx solo compone. La lógica vive en components/auth/.
Y no es una preferencia: el repo tiene un guardia que rechaza lo contrario. /complete-profile ya está en 370 líneas dentro del page.tsx — es exactamente la deuda que este proyecto no agranda.
Contraste medido Cada par sobre la superficie en la que de verdad se pinta. Los dos que fallaron se corrigieron acá, no se anotaron para después.
ParRatioDónde
marino / blanco16.31:1Tinta principal y botón primario del client.
marino / celeste11.73:1El botón del admin. Con tinta blanca daría 1.39:1 — por eso sobre celeste se escribe en marino.
marino / celeste-soft14.57:1Item activo del sidebar y píldora «En tránsito».
ink-soft / blanco8.74:1Todo el texto secundario. Un gris de plantilla daría ~4.6:1 a 12 px.
rojo-deep / blanco7.57:1Errores bajo el campo.
rojo-deep / rojo-soft5.53:1Píldora «Por pagar».
celeste / marino-deep13.14:1El tag de la placa.
on-marino-soft / marino11.57:1La cita del panel aurora.
warning / warning-soft3.11:1corregidoPíldora «En aduanas». No llegaba a AA. Se derivó --state-warning-deep #8A5A105.03:1.
success / success-soft4.49:1corregidoEl tick de la checklist, a un pelo del piso. Se derivó --state-success-deep #2767425.81:1.
Dónde sí vive --muted

#7B88A6 sobre blanco da 3.55:1: sirve para etiquetas en versalita de 9–11 px con tracking-widest, que son señalización, y para nada que alguien tenga que leer. Los contadores del sidebar, las claves de las tarjetas y los encabezados de tabla se pasaron a --ink-soft por eso.

Lo que viene después
10 — fase 2 en adelante

Esta es la fase 1: client. Lo de abajo queda escrito por nombre para que nadie lo dé por hecho ni por olvidado.

Admin · las dos puertas noche

/forgot-password y /reset-password del admin, en variante noche: tarjeta de vidrio de 400 px sobre la aurora completa. Su /forgot-password también tiene paso de código, así que hereda la caja de OTP en su versión oscura — ya diseñada en §03.

El stepper de onboarding

OnboardingStepper, StepSuccessTransition y TrustMessage tienen su propia gramática de progreso. Acá se retintaron; rediseñarlos es trabajo aparte y sale del contrato de «retintada».

El paso de dirección con mapa

Google Maps dentro de /complete-profile: el único punto de las siete rutas donde hay una superficie de terceros. Necesita su propia decisión de encaje, no un retinte.

La tipografía del sistema

Hoy los page.tsx mezclan font-family-display, font-family-sans y utilidades sueltas sin una escala común. Merece una pasada propia — es lo que hace que dos pantallas retintadas igual se sientan distintas.

Los componentes duplicados

actions.ts, los esquemas Zod y password-fields.tsx existen dos veces, uno por app. El shell aurora es la excusa para consolidarlos en packages/ui — pero es refactor, no presentación.

Lo que este proyecto nunca toca

Campos nuevos · pasos nuevos · cualquier cambio en lo que estas rutas envían · la mecánica de auth (Supabase, las server actions, el guardia de returnTo). Esto consolida presentación.

Aurora · client · fase 1 · agosto 2026