Ruy May — Design System
§01 Tokens
01
Tokens Foundation
CSS custom properties — la fuente de verdad de todo el sistema visual
Colores de Marca
Paleta oficial Ruy May, derivada del Manual de Identidad Visual (RMC-7)
--brand-primary
#3B8E91 — Teal Ruy May
--brand-secondary
#C9E8DA — Verde Menta
--brand-dark
#0D1F20 — Teal Oscuro
--brand-white
#FFFFFF — Blanco
--brand-text
#2D2D2D — Texto principal
--brand-primary:   #3B8E91;
--brand-secondary: #C9E8DA;
--brand-dark:      #0D1F20;
--brand-white:     #FFFFFF;
--brand-text:      #2D2D2D;
Colores Semánticos
Estados de feedback: éxito, advertencia, error e información
--color-success
#2E7D32
--color-warning
#F57C00
--color-danger
#C62828
--color-info
#3B8E91
--color-success: #2E7D32;
--color-warning: #F57C00;
--color-danger:  #C62828;
--color-info:    #3B8E91;
Status de Cirugía (7 estados)
Tokens cromáticos para el ciclo de vida de una cirugía en el sistema RMC
--status-pending
#9E9E9E — Pendiente
--status-planning
#92680A — En Planeación
--status-confirmed
#3B8E91 — Confirmada
--status-rescheduled
#6D28D9 — Reprogramada
--status-in-progress
#F57C00 — En Curso
--status-completed
#2E7D32 — Completada
--status-cancelled
#C62828 — Cancelada
--status-planning:    #92680A;
--status-pending:     #9E9E9E;
--status-confirmed:   #3B8E91;  /* brand-primary */
--status-rescheduled: #6D28D9;
--status-in-progress: #F57C00;
--status-completed:   #2E7D32;
--status-cancelled:   #C62828;
Escala de Espaciado
Base 4px — de --space-1 (4px) a --space-12 (48px)
--space-1 · 4px
--space-2 · 8px
--space-3 · 12px
--space-4 · 16px
--space-6 · 24px
--space-8 · 32px
--space-10 · 40px
--space-12 · 48px
--space-1: 4px;   --space-2: 8px;   --space-3: 12px;
--space-4: 16px;  --space-5: 20px;  --space-6: 24px;
--space-8: 32px;  --space-10: 40px; --space-12: 48px;
Sombras
3 niveles de elevación coherentes con la estética del brand
--shadow-sm
--shadow-md
--shadow-lg
--shadow-xl
--shadow-sm: 0 1px 3px rgba(13,31,32,0.08);
--shadow-md: 0 4px 6px rgba(13,31,32,0.07);
--shadow-lg: 0 10px 15px rgba(13,31,32,0.08);
--shadow-xl: 0 20px 25px rgba(13,31,32,0.10);
02
Tipografía
Poppins (títulos, labels) · Inter (cuerpo, inputs, tablas)
Escala de Títulos — Poppins
h1 · 36px · 700

Ruy May

h2 · 30px · 700

Implantes de Traumatología

h3 · 24px · 600

Roadmap de Cirugías

h4 · 20px · 600

Formulario Interno

h5 · 18px · 600
Catálogo de Médicos
h6 · 16px · 600
Detalles de cirugía
<h1>Título H1</h1>
<h2>Título H2</h2>
<h3>Título H3</h3>
Estilos de cuerpo — Inter

Body Large — Descripción principal del procedimiento quirúrgico

Body Regular — Texto estándar de la interfaz para entradas de formulario y tablas

Body Small — Texto secundario, notas y observaciones del formulario

Caption — Texto auxiliar, fechas, metadatos de la cirugía

Label — Etiqueta de campo de formulario

Overline — Sección de navegación

<p class="body-lg">Body Large</p>
<p class="body-md">Body Regular</p>
<p class="body-sm">Body Small</p>
<p class="caption">Caption</p>
<p class="label">Label</p>
<p class="overline">Overline</p>
Utilidades de color tipográfico

text-brand — Color primario teal

text-muted — Texto secundario gris

text-danger — Error o acción destructiva

text-success — Confirmación o éxito

text-warning — Advertencia o atención

<span class="text-brand">Teal primario</span>
<span class="text-muted">Gris secundario</span>
<span class="text-danger">Error</span>
<span class="text-success">Éxito</span>
03
Botones
5 variantes × 3 tamaños × estados interactivos
Variantes
Primary, Secondary, Destructive, Ghost, Outline
<button class="btn btn-primary">Guardar cirugía</button>
<button class="btn btn-secondary">Cancelar</button>
<button class="btn btn-destructive">Eliminar</button>
<button class="btn btn-ghost">Ver detalle</button>
<button class="btn btn-outline">Exportar</button>
Tamaños
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-md">Medium (default)</button>
<button class="btn btn-primary btn-lg">Large</button>
Estados especiales
<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-primary btn-loading">Guardando...</button>
<button class="btn btn-icon btn-sm"><i data-lucide="pencil"></i></button>
<button class="btn btn-primary">
  <i data-lucide="plus"></i> Nueva cirugía
</button>
04
Formularios
Inputs, selects, checkboxes, toggles y form-group
Estados de input-text
Este campo es requerido
<!-- Default -->
<input type="text" placeholder="Nombre del paciente" />
<!-- Error -->
<input type="text" class="input-error" />
<span class="form-error">Este campo es requerido</span>
<!-- Disabled -->
<input type="text" disabled />
Input especiales
<!-- Búsqueda -->
<div class="input-wrapper input-search-wrapper">
  <span class="input-icon-left"><i data-lucide="search"></i></span>
  <input type="search" placeholder="Buscar..." />
</div>

<!-- Select -->
<div class="select-wrapper">
  <select><option>Hospital</option></select>
</div>
Input de moneda
Con prefijo $, separador de miles automático y centavos. También cubre inputs con sufijo de unidad.
$ MXN
Ejemplo: 12,500.00
$
kg
$
Ingresa un monto válido
<div class="form-group">
  <label class="form-label">Monto</label>
  <div class="input-addon-wrapper">
    <span class="input-addon input-addon-left">$</span>
    <input type="text" class="input-currency"
           oninput="formatCurrency(this)" placeholder="0.00" />
    <span class="input-addon input-addon-right">MXN</span>
  </div>
</div>

/* Con sufijo de unidad */
<div class="input-addon-wrapper">
  <input type="number" />
  <span class="input-addon input-addon-right">kg</span>
</div>
Textarea
Máximo 500 caracteres
<div class="form-group">
  <label class="form-label">Observaciones</label>
  <textarea rows="3" placeholder="Notas..."></textarea>
  <span class="form-helper">Máximo 500 caracteres</span>
</div>
Checkbox, Radio y Toggle
Asistencia técnica: Sí
Notificaciones: Off
<label class="checkbox-wrapper">
  <input type="checkbox" checked />
  <label>Asistencia técnica</label>
</label>

<div class="toggle-wrapper">
  <label class="toggle-switch">
    <input type="checkbox" checked />
    <span class="toggle-slider"></span>
  </label>
  <span class="toggle-label">Activado</span>
</div>
05
Badges y Etiquetas
Badges semánticos, status de cirugía, tags removibles y avatares
Badges semánticos
Éxito Advertencia Error Información Neutro
<span class="badge badge-success">Éxito</span>
<span class="badge badge-warning">Advertencia</span>
<span class="badge badge-danger">Error</span>
<span class="badge badge-info">Información</span>
<span class="badge badge-neutral">Neutro</span>
Badge Status — Cirugías (7 estados)
Pendiente En Planeación Confirmada Reprogramada En Curso Completada Cancelada
<span class="badge-status badge-status-planning">En Planeación</span>
<span class="badge-status badge-status-pending">Pendiente</span>
<span class="badge-status badge-status-confirmed">Confirmada</span>
<span class="badge-status badge-status-rescheduled">Reprogramada</span>
<span class="badge-status badge-status-in-progress">En Curso</span>
<span class="badge-status badge-status-completed">Completada</span>
<span class="badge-status badge-status-cancelled">Cancelada</span>
Stickers de tarjeta quirúrgica
Chips compactos que aparecen en las cards de cirugía para identificar marca, distribuidor y asistencia técnica. Se agrupan en .list-stickers.
LEPINE Lepine México Asistencia
STRYKER Stryker MX Sin asistencia
<div class="list-stickers">
  <span class="sticker sticker-brand">LEPINE</span>
  <span class="sticker sticker-distributor">Lepine México</span>
  <span class="sticker sticker-assist-yes">Asistencia</span>
  <span class="sticker sticker-assist-no">Sin asistencia</span>
</div>
Tags / Chips removibles
Hospital Ángeles Dr. Martínez Prótesis cadera
<span class="tag">
  Hospital Ángeles
  <button class="tag-remove">
    <i data-lucide="x"></i>
  </button>
</span>
Avatar
RM JM AL DR
<span class="avatar avatar-sm">RM</span>
<span class="avatar avatar-md">JM</span>
<span class="avatar avatar-lg">AL</span>
07
Cards
Cards base, KPI cards, surgery cards, stat items y empty state
Card variantes
Card Default

Contenedor estándar con sombra y borde radius.

Card Highlighted

Borde teal — para destacar contenido relevante.

Card Dark

Fondo oscuro brand para fondos de dashboard.

<div class="card">
  <div class="card-header"><span class="card-title">Título</span></div>
  <div class="card-body">...contenido</div>
  <div class="card-footer">...acciones</div>
</div>

<div class="card card-highlighted">...</div>
<div class="card card-dark">...</div>
KPI Cards
Cards métricas para el dashboard: ícono + valor + label + tendencia
48
Cirugías este mes
+12% vs mes anterior
7
Cirugías pendientes
−3 vs semana pasada
94%
Tasa de éxito
+2% este trimestre
<div class="kpi-card">
  <div class="kpi-icon"><i data-lucide="calendar-check"></i></div>
  <div class="kpi-value">48</div>
  <div class="kpi-label">Cirugías este mes</div>
  <div class="kpi-delta kpi-delta-up">+12%</div>
</div>
Surgery Card
Card del Roadmap de cirugías
Mar 18, 2026 — 07:30
Prótesis total de cadera
Confirmada
Dr. Carlos Martínez
Hospital Ángeles Tijuana
Implante acetabular + cabeza femoral
ZIMMER BIOMET Zimmer MX Asistencia
Mar 16, 2026 — 09:00
Reemplazo rodilla derecha
En Curso
Dra. Ana Flores
IMSS Clínica 8
LEPINE Lepine México Sin asistencia
<div class="surgery-card">
  <div class="surgery-card-header">
    <div>
      <div class="surgery-card-date">Mar 18, 2026 — 07:30</div>
      <div class="surgery-card-procedure">Prótesis cadera</div>
    </div>
    <span class="badge-status badge-status-confirmed">Confirmada</span>
  </div>
  <div class="surgery-card-meta">
    <div class="surgery-meta-item"><i data-lucide="user"></i> Dr. Martínez</div>
    <div class="surgery-meta-item"><i data-lucide="building-2"></i> Hospital Ángeles TJ</div>
  </div>
  <div class="list-stickers">
    <span class="sticker sticker-brand">ZIMMER BIOMET</span>
    <span class="sticker sticker-distributor">Zimmer MX</span>
    <span class="sticker sticker-assist-yes">Asistencia</span>
    <!-- o sticker-assist-no para sin asistencia -->
  </div>
  <div class="surgery-card-footer">...</div>
</div>
Stat Item y Empty State
Médico
Dr. Carlos Martínez
Hospital
Ángeles Tijuana
Folio
#CX-2026-048
Paquetería
FedEx Express
Sin cirugías programadas
No hay cirugías para la fecha seleccionada. Crea una nueva para comenzar.
<div class="stat-item">
  <div class="stat-label">Médico</div>
  <div class="stat-value">Dr. Carlos Martínez</div>
</div>

<div class="empty-state">
  <div class="empty-state-icon"><i data-lucide="calendar-x"></i></div>
  <div class="empty-state-title">Sin resultados</div>
  <div class="empty-state-description">Descripción...</div>
  <button class="btn btn-primary btn-sm">CTA</button>
</div>
08
Tablas
Data table con sorting, búsqueda, selección, paginación · Permissions matrix
Data Table completa
Selecciona filas con el checkbox, ordena por columna y usa la barra de búsqueda
Folio Fecha Médico Procedimiento Hospital Estado Acciones
#CX-048 18 Mar 2026 Dr. Martínez Prótesis cadera H. Ángeles TJ Confirmada
#CX-047 16 Mar 2026 Dra. Flores Reemplazo rodilla IMSS Clínica 8 En Curso
#CX-046 14 Mar 2026 Dr. Jiménez Prótesis hombro H. San Vicente Completada
#CX-045 12 Mar 2026 Dr. Vásquez Implante codo ISSTE BC Cancelada
#CX-044 20 Mar 2026 Dra. Romero Prótesis rodilla H. Ángeles TJ En Planeación
<div class="data-table-wrapper">
  <div class="data-table-toolbar">
    <!-- búsqueda + acciones -->
  </div>
  <table class="data-table">
    <thead>
      <tr>
        <th><input type="checkbox" /></th>
        <th class="th-sortable">Folio</th>
        <th>Estado</th>
        <th>Acciones</th>
      </tr>
    </thead>
    <tbody>...filas...</tbody>
  </table>
  <div class="data-table-footer">
    <!-- info + pagination -->
  </div>
</div>
Filter Panel — Panel de filtros colapsable
Se despliega entre el toolbar y la tabla. Los filtros activos aparecen como chips removibles. El botón muestra un badge con el conteo de filtros aplicados.
Folio Fecha Médico Procedimiento Hospital Estado Asistencia
<!-- Toolbar con botón de filtros + badge de conteo -->
<div style="position:relative;display:inline-flex;">
  <button class="btn btn-outline btn-sm" onclick="toggleFilterPanel()">
    <i data-lucide="sliders-horizontal"></i> Filtros
  </button>
  <span class="btn-filter-badge">2</span>  <!-- conteo de filtros activos -->
</div>

<!-- Panel colapsable -->
<div class="filter-panel" id="filterPanel">
  <div class="filter-panel-grid">
    <div class="form-group">
      <label class="form-label">Estado</label>
      <div class="select-wrapper"><select id="fpFilterStatus">...</select></div>
    </div>
    <!-- más campos: fpFilterDoctor, fpFilterHospital, fpFilterDateFrom, fpFilterDateTo, fpFilterTech -->
  </div>
  <div class="filter-panel-actions">
    <button class="btn btn-ghost btn-sm" onclick="clearFilters()">Limpiar filtros</button>
    <button class="btn btn-primary btn-sm" onclick="applyFilters()">Aplicar filtros</button>
  </div>
</div>

<!-- Chips de filtros activos (generados dinámicamente) -->
<div class="filter-active-bar show">
  <span class="filter-active-label">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
    </svg>
    Filtros activos:
  </span>
  <!-- chips inyectados por JS -->
</div>

/* Abrir/cerrar */
filterPanel.classList.toggle('open');

/* Renderizar tabla con datos filtrados */
renderFpTable(fpData.filter(...));
Permissions Matrix
Tabla especial Admin Roles: módulos × permisos (Leer/Crear/Editar/Eliminar)
Módulo Leer Crear Editar Eliminar
Cirugías
Catálogo Médicos
Catálogo Hospitales
Admin Usuarios
<table class="permissions-matrix">
  <thead>
    <tr>
      <th>Módulo</th>
      <th>Leer</th><th>Crear</th>
      <th>Editar</th><th>Eliminar</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Cirugías</td>
      <td><input type="checkbox" checked /></td>
      ...
    </tr>
  </tbody>
</table>
Fechas en tabla (Monospace)
Formato de fechas compacto con iconos y fuente monospace para datos
Usuario Modificado / Creado
Fernando García
28/03/26 14:32
+ 15/03/26 09:15
Sistema Admin
Sin cambios
+ 27/03/26 08:00
<div style="display: flex; flex-direction: column; gap: 0;">
  <div style="display: flex; align-items: center; gap: 6px;">
    <!-- Icono reloj SVG -->
    <svg ...></svg>
    <span class="date-monospace">28/03/26 14:32</span>
  </div>
  <div style="display: flex; align-items: center; gap: 6px;">
    <!-- Símbolo + -->
    <span style="...width: 12px;...">+</span>
    <span class="date-monospace">15/03/26 09:15</span>
  </div>
</div>
09
Overlays y Feedback
Modal, confirm dialog, toast, alert, tooltip, spinner y skeleton
Modal (sm / md / lg)
<!-- Trigger -->
<button onclick="openModal('myModal')">Abrir modal</button>

<!-- Modal -->
<div class="modal-backdrop" id="myModal">
  <div class="modal modal-md">
    <div class="modal-header">
      <span class="modal-title">Título</span>
      <button class="modal-close" onclick="closeModal('myModal')">
        <i data-lucide="x"></i>
      </button>
    </div>
    <div class="modal-body">...contenido...</div>
    <div class="modal-footer">
      <button class="btn btn-outline">Cancelar</button>
      <button class="btn btn-primary">Guardar</button>
    </div>
  </div>
</div>
Confirm Dialog
<div class="modal-backdrop" id="confirmDialog">
  <div class="modal modal-sm">
    <div class="modal-body">
      <div class="confirm-dialog">
        <div class="confirm-dialog-icon">
          <i data-lucide="alert-triangle"></i>
        </div>
        <div class="confirm-dialog-title">¿Eliminar cirugía?</div>
        <div class="confirm-dialog-body">Esta acción no se puede deshacer.</div>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-outline">Cancelar</button>
      <button class="btn btn-destructive">Eliminar</button>
    </div>
  </div>
</div>
Toast (auto-dismiss 4s)
showToast('success', 'Cirugía guardada', 'Guardado correctamente.');
showToast('error',   'Error',           'Mensaje de error.');
showToast('warning', 'Advertencia',     'Revisa los campos.');
showToast('info',    'Información',     'Folio asignado.');

/* Variantes: toast-success | toast-error | toast-warning | toast-info */
/* Auto-dismiss: 4000ms. Máx 3 toasts apilados. */
Alert — Banner inline
Cirugía confirmada
El equipo quirúrgico ha sido notificado.
Implantes pendientes
No se han seleccionado implantes requeridos.
Error de validación
El campo Hospital es obligatorio.
Modo solo lectura
No tienes permisos para editar este registro.
<div class="alert alert-success">
  <span class="alert-icon"><i data-lucide="check-circle"></i></span>
  <div class="alert-content">
    <div class="alert-title">Cirugía confirmada</div>
    El equipo ha sido notificado.
  </div>
  <!-- Botón dismiss opcional -->
  <button class="alert-dismiss" onclick="this.parentElement.remove()">
    <i data-lucide="x"></i>
  </button>
</div>

/* Variantes: alert-success | alert-warning | alert-error | alert-info */
Tooltip
Información adicional
Aparece arriba
Aparece abajo
Aparece a la derecha
<div class="tooltip-wrapper">
  <button class="btn btn-icon"><i data-lucide="info"></i></button>
  <span class="tooltip-bubble tooltip-top">Tooltip texto</span>
</div>

/* Posiciones: tooltip-top | tooltip-bottom | tooltip-left | tooltip-right */
Loading Spinner
<span class="spinner spinner-sm"></span>
<span class="spinner spinner-md"></span>
<span class="spinner spinner-lg"></span>
<span class="spinner spinner-md spinner-white"></span>
Skeleton
Placeholders animados para estados de carga
FolioMédicoEstado
<!-- Skeleton genérico -->
<div class="skeleton skeleton-text" style="width:80%;"></div>
<div class="skeleton skeleton-title" style="width:60%;"></div>
<div class="skeleton skeleton-circle" style="width:40px;height:40px;"></div>

<!-- Skeleton card completa -->
<div class="skeleton-card">
  <div class="skeleton skeleton-title" style="width:50%;"></div>
  <div class="skeleton skeleton-text" style="width:100%;"></div>
</div>
10
Page Layout
Componentes para estructurar páginas: header, títulos, acciones
Page Header
Encabezado de página con título, subtítulo y acciones
<div class="page-header">
  <div>
    <h1 class="page-title">Gestión de Usuarios</h1>
    <p class="page-subtitle">Administra usuarios...</p>
  </div>
  <div class="page-actions">
    <button class="btn btn-primary btn-sm">...</button>
  </div>
</div>
Form Grid
Layout de dos columnas para formularios en modales
<div class="form-grid">
  <div class="form-group">
    <label>Nombre</label>
    <input type="text" class="input" />
  </div>
  <div class="form-group">
    <label>Apellido</label>
    <input type="text" class="input" />
  </div>
  <div class="form-group form-group--full">
    <label>Email</label>
    <input type="email" class="input" />
  </div>
</div>