Color
Una paleta fría entera: el arco cian→azul→violeta como identidad, neutros tintados hacia ese mismo hue y una familia de estado afinada para convivir con el arco. El color no decora: aparece cuando hay algo que decidir.
Tres reglas
La Regla de una Sola Decisión
Una pantalla en reposo tiene como máximo un elemento con relleno de color: la acción que toca tomar ahí. Si hay dos, uno de los dos no era primario.
La Regla del Tenant
Ningún significado puede descansar en el azul. Cada hotel puede reescribir la tríada de marca, así que el significado lo cargan la forma, la posición, el contraste y la palabra; el color lo confirma.
La Regla del Arco Frío
Ningún color entra al sistema si no convive con el arco cian→azul→violeta. Por eso el éxito es teal y no verde hierba, y la advertencia es ámbar apagado y no amarillo de señalización.
Marca
La tríada es la perilla del White Label: el mismo valor en claro y en oscuro, y reescribible por tenant. Las muestras de esta página se pintan con su variable CSS, así que se re-tiñen con el selector de marca de la cabecera. Prueba con «Atardecer» y vuelve.
--brand-cyanFilo de los contenedores, foco en oscuro y glow reservado. Nunca de relleno.--brand-blueEl --primary real y el origen de la rampa de azules.--brand-purpleCierra el arco: gradiente de marca y selección de texto.--brand-darkAncla oscura y hue de los neutros. Para el logo, no de fondo.bg-brand-gradient — reservado al botón brand, el único sitio donde el gradiente toca un componente.Rampa de azul
Toda la rampa sale de --brand-blue por color-mix, con el 600 como ancla exacta. Recolorear la marca re-tinta de una vez el primario, su hover y su active, los enlaces y el anillo de foco.
--blue-50--blue-100--blue-200--blue-400--blue-600--blue-700--blue-800--blue-900Neutros
Once pasos en OKLCH con croma de 0.003 a 0.02 sobre el hue 278, el de Grafito Violado: reemplazan al slate para que ningún gris se sienta prestado de otra paleta. Son constantes; el tema oscuro no invierte la rampa, usa valores propios en los tokens de superficie.
n-50L 0.985n-100L 0.968n-200L 0.925n-300L 0.87n-400L 0.7n-500L 0.55n-600L 0.45n-700L 0.37n-800L 0.27n-900L 0.21n-950L 0.15Superficies y texto
Lo que consumen los componentes. Cada token tiene un valor en claro y otro en oscuro: cambia el tema en la cabecera y mira cómo responden. En claro, n-100 de lienzo, blanco de tarjeta, n-200 de borde y n-900 de texto.
--backgroundFondo de la app--cardTarjetas y paneles--popoverMenús y popovers--mutedLienzo y zonas en reposo--accentHover y fila activa--borderHairline entre superficies--grid-lineRetícula de tablas densas--foregroundTexto--muted-foregroundTexto secundario, ≈5:1--primaryLa acción de la pantalla--ringAnillo de focoEstados: cuatro papeles
Un estado es un conjunto, no un color: relleno, texto con contraste AA sobre el tinte, tinte de superficie y borde del mismo hue. info no tiene color propio: deriva del Azul Operativo, porque «informativo» y «primario» son el mismo registro — por eso es la única familia que cambia con la marca.
Éxito --success-*
base-text-subtle-borderAdvertencia --warning-*
base-text-subtle-borderError y acción destructiva --destructive-*
base-text-subtle-borderInformación --info-*
base-text-subtle-borderEstados en componentes
Badge y Alert ya combinan los cuatro papeles: tinte de fondo, texto AA, borde e icono o punto en el relleno. Son el vocabulario de estado del sistema y se prefieren a cualquier texto coloreado suelto. Cada uno lleva su palabra: la Regla del Tenant pide que el estado se lea sin el color.
Usar los tokens
Cuando el kit no trae la pieza, se pinta con las utilidades semánticas. Un hex literal o un color de Tailwind no cambia con el tema ni con el tenant. Los --wa-* de channels.css no son paleta: reproducen WhatsApp para previsualizar lo que verá el huésped.
// Bien: el token dice el papel y responde a tema y marca
<div className="rounded-[var(--card-radius)] border border-border bg-card p-6">
<p className="text-sm text-muted-foreground">Última sincronización hace 4 min</p>
<p className="text-sm text-success-text">3 reservas importadas</p>
</div>
// Mal: no existe en esta hoja y no re-tematiza
<div className="rounded-xl border-gray-200 bg-white p-6">
<p className="text-sm text-gray-500">Última sincronización hace 4 min</p>
<p className="text-sm text-[#16a34a]">3 reservas importadas</p>
</div>