Files
analiticaNucleo/nuxt4-app/docs/THEME_SYSTEM.md
josedario87 ed08fa8957
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 50s
Docs: Actualizar documentación completa del sistema de temas v2.1
- Actualizado THEME_SYSTEM.md con nuevas variables --brand-cosecha-2/3/4
- Documentadas implementaciones CSS con color-mix() en todas las clases
- Agregada sección 'Mejoras Recientes (v2.1)' en THEME_SYSTEM.md
- Actualizada descripción de Surface en settings.vue (cards grandes, tooltips)
- Mejorada sección 'Alcance del Sistema de Temas' con ejemplos de clases CSS
- Agregado tip sobre cards grandes usando color-mix()
- Versión actualizada a 2.1 | Fecha: 2025-10-31

Todos los componentes ahora responden completamente a cambios de tema
2025-10-31 11:14:20 -06:00

874 lines
22 KiB
Markdown

# Sistema de Temas - Analítica Núcleo
> **Documentación definitiva del sistema de temas personalizable**
> Versión: 2.1 | Última actualización: 2025-10-31
## Índice
1. [Introducción](#introducción)
2. [Arquitectura del Sistema](#arquitectura-del-sistema)
3. [Variables CSS Disponibles](#variables-css-disponibles)
4. [Reglas de Uso Obligatorias](#reglas-de-uso-obligatorias)
5. [Clases Utilitarias](#clases-utilitarias)
6. [Composable useTheme()](#composable-usetheme)
7. [Ejemplos de Uso](#ejemplos-de-uso)
8. [Integración con Nuxt UI](#integración-con-nuxt-ui)
9. [Casos Especiales](#casos-especiales)
10. [Troubleshooting](#troubleshooting)
---
## Introducción
Analítica Núcleo cuenta con un sistema de temas completamente dinámico que permite personalizar todos los colores de la interfaz en tiempo real. Los cambios se aplican instantáneamente a todos los componentes de la aplicación.
**Características principales:**
- ✅ 8 variables de color personalizables
- ✅ 4 temas predefinidos (Café, Azul, Verde, Carbón)
- ✅ Persistencia en localStorage
- ✅ Vista previa en tiempo real
- ✅ Exportar/importar temas en JSON
- ✅ Integración completa con Nuxt UI
---
## Arquitectura del Sistema
### Flujo de Datos
```
Usuario modifica tema en /settings
useTheme() composable
Actualiza variables CSS (--brand-*)
Variables --ui-color-neutral-* mapeadas automáticamente
Todos los componentes se actualizan instantáneamente
```
### Archivos Clave
| Archivo | Propósito |
|---------|-----------|
| `app/assets/css/main.css` | Definición de variables CSS y clases utilitarias |
| `app/composables/useTheme.ts` | Lógica del sistema de temas |
| `app/pages/settings.vue` | Interfaz de configuración |
---
## Variables CSS Disponibles
### Variables Base (`--brand-*`)
Estas variables controlan la apariencia general de la aplicación:
| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--brand-bg` | Fondo principal de la app | `#14100b` |
| `--brand-surface` | Fondos de cards, modales, elementos elevados | `#1f180f` |
| `--brand-border` | Bordes de todos los elementos | `#3a2a16` |
| `--brand-primary` | Color principal para enlaces, títulos destacados | `#e0c080` |
| `--brand-primary-strong` | Variante más intensa del primario | `#c08040` |
| `--brand-accent` | Highlights, elementos de énfasis | `#ffe0a0` |
| `--brand-text` | Texto principal (alta legibilidad) | `#fef9f0` |
| `--brand-text-muted` | Texto secundario, descripciones | `#d8c7a6` |
### Variables Intermedias para Gráficas (`--brand-cosecha-*`)
Estas variables se usan en las gráficas de comparativa de cosechas para diferenciar visualmente múltiples series:
| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--brand-cosecha-2` | Tono intermedio 1 para gráficas de cosechas | `#8b6f47` |
| `--brand-cosecha-3` | Tono intermedio 2 para gráficas de cosechas | `#a0826e` |
| `--brand-cosecha-4` | Tono intermedio 3 para gráficas de cosechas | `#b89968` |
> **Nota:** Estas variables se ajustan automáticamente cuando cambias el tema, manteniendo la armonía visual con los colores primarios.
### Variables de Tipos de Café (`--coffee-*`)
Estas variables se usan para identificar visualmente los tipos de café en gráficas y tablas:
| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--coffee-uva` | Color de identificación para Café Uva | `#a855f7` (Purple) |
| `--coffee-oreado` | Color de identificación para Café Oreado | `#f97316` (Orange) |
| `--coffee-mojado` | Color de identificación para Café Mojado | `#06b6d4` (Cyan) |
| `--coffee-verde` | Color de identificación para Café Verde | `#22c55e` (Green) |
### Variables de Estados (`--status-*`)
Estas variables se usan para indicar estados de pago en tablas y badges:
| Variable | Uso | Ejemplo de valor |
|----------|-----|------------------|
| `--status-pendiente` | Estado de pago pendiente | `#f59e0b` (Amber) |
| `--status-pagado` | Estado pagado completamente | `#10b981` (Emerald) |
| `--status-anulado` | Estado anulado o cancelado | `#6b7280` (Gray) |
### Variables de Nuxt UI (`--ui-color-neutral-*`)
⚠️ **NO uses estas variables directamente**. Están mapeadas automáticamente a `--brand-*` en `main.css`.
**Mapeo actual (NO modificar):**
```css
--ui-color-neutral-50: var(--brand-text); /* Texto más claro */
--ui-color-neutral-100: var(--brand-text-muted); /* Texto secundario */
--ui-color-neutral-200: var(--brand-primary); /* Primario claro */
--ui-color-neutral-300: var(--brand-primary); /* Primario */
--ui-color-neutral-400: var(--brand-primary-strong); /* Primario fuerte */
--ui-color-neutral-500: var(--brand-border); /* Bordes */
--ui-color-neutral-600: var(--brand-border); /* Bordes */
--ui-color-neutral-700: var(--brand-surface); /* Surface */
--ui-color-neutral-800: var(--brand-surface); /* Surface */
--ui-color-neutral-900: var(--brand-bg); /* Fondo más oscuro */
--ui-color-neutral-950: var(--brand-bg); /* Fondo */
```
> **IMPORTANTE:** Nuxt UI usa la escala neutral de forma invertida en dark mode:
> - `neutral-50/100` → Colores claros (texto)
> - `neutral-900/950` → Colores oscuros (fondos)
---
## Reglas de Uso Obligatorias
### ✅ SIEMPRE Hacer
1. **Usar variables CSS en lugar de colores hardcoded:**
```vue
<!-- ✅ CORRECTO -->
<div class="bg-[var(--brand-surface)] text-[var(--brand-text)]">
Contenido
</div>
```
2. **Usar clases utilitarias cuando existan:**
```vue
<!-- ✅ CORRECTO -->
<div class="brand-card">
<h2 class="brand-section-title">Título</h2>
</div>
```
3. **Usar transparencias para hover states:**
```vue
<!-- ✅ CORRECTO -->
<button class="hover:bg-[var(--brand-primary)]/10">
Botón
</button>
```
### ❌ NUNCA Hacer
1. **NO usar colores hardcoded:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[#1f180f] text-[#fef9f0]">
Contenido
</div>
```
2. **NO usar clases gray-scale genéricas:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-gray-900 text-gray-400 border-gray-800">
Contenido
</div>
```
3. **NO mezclar variables con hardcoded:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[#1f180f] text-[var(--brand-text)]">
Contenido
</div>
```
---
## Clases Utilitarias
⚠️ **IMPORTANTE:** Todas las clases utilitarias ahora usan `color-mix()` y variables CSS dinámicas. Esto significa que **todas** responden automáticamente a los cambios de tema.
### `.brand-shell`
Contenedor principal con gradiente radial dinámico.
```vue
<div class="brand-shell">
<!-- Contenido de la página -->
</div>
```
**Implementación CSS:**
```css
.brand-shell {
background: radial-gradient(circle at 20% 20%,
color-mix(in srgb, var(--brand-accent) 8%, transparent), transparent 55%),
radial-gradient(circle at 80% 10%,
color-mix(in srgb, var(--brand-primary-strong) 8%, transparent), transparent 45%),
var(--brand-bg);
}
```
### `.brand-card`
Tarjetas con estilos consistentes (gradiente, borde, sombra). **Ahora completamente dinámicas.**
```vue
<div class="brand-card">
<h3>Título</h3>
<p>Contenido</p>
</div>
```
**Implementación CSS:**
```css
.brand-card {
background: linear-gradient(145deg,
color-mix(in srgb, var(--brand-bg) 95%, transparent),
color-mix(in srgb, var(--brand-surface) 85%, transparent));
border: 1px solid color-mix(in srgb, var(--brand-primary) 12%, transparent);
box-shadow: 0 12px 40px color-mix(in srgb, var(--brand-bg) 55%, transparent);
}
```
### `.brand-divider`
Divisor horizontal decorativo.
```vue
<div class="brand-divider"></div>
```
**Implementación CSS:**
```css
.brand-divider {
border-top: 1px solid color-mix(in srgb, var(--brand-primary) 16%, transparent);
}
```
### `.brand-section-title`
Títulos de sección con color primario.
```vue
<h2 class="brand-section-title">Mi Sección</h2>
```
### `.brand-chip` / `.brand-pill`
Tags o badges pequeños con estilos dinámicos.
```vue
<span class="brand-chip">Estado</span>
<span class="brand-pill">Badge</span>
```
**Implementación CSS:**
```css
.brand-chip {
background: color-mix(in srgb, var(--brand-accent) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--brand-accent) 18%, transparent);
color: var(--brand-accent);
}
.brand-pill {
background: color-mix(in srgb, var(--brand-primary) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--brand-primary) 28%, transparent);
color: var(--brand-primary);
}
```
### `.brand-badge`
Badge con fondo primario sólido.
```vue
<span class="brand-badge">3</span>
```
### `.brand-table`
Estilos para tablas con hover dinámico.
```vue
<table class="brand-table">
<thead>...</thead>
<tbody>...</tbody>
</table>
```
**Implementación CSS:**
```css
.brand-table thead {
background: linear-gradient(90deg,
color-mix(in srgb, var(--brand-surface) 95%, transparent),
color-mix(in srgb, var(--brand-bg) 95%, transparent));
}
.brand-table tbody tr:hover {
background: color-mix(in srgb, var(--brand-accent) 6%, transparent);
}
```
---
## Composable useTheme()
### Importar
```typescript
const {
theme,
applyTheme,
saveTheme,
resetTheme,
exportTheme,
importTheme
} = useTheme()
```
### API
#### `theme` (Ref<ThemeColors>)
Estado reactivo del tema actual.
```typescript
interface ThemeColors {
bg: string
surface: string
border: string
primary: string
primaryStrong: string
accent: string
text: string
textMuted: string
}
```
#### `applyTheme(newTheme?: ThemeColors)`
Aplica el tema a las variables CSS del DOM.
```typescript
applyTheme() // Aplica theme.value actual
applyTheme(customTheme) // Aplica un tema personalizado
```
#### `saveTheme()`
Guarda el tema actual en localStorage.
```typescript
const success = saveTheme()
if (success) {
console.log('Tema guardado')
}
```
#### `resetTheme()`
Resetea al tema por defecto (Café).
```typescript
resetTheme()
```
#### `exportTheme()`
Exporta el tema actual como JSON string.
```typescript
const jsonTheme = exportTheme()
await navigator.clipboard.writeText(jsonTheme)
```
#### `importTheme(jsonString: string, autoSave: boolean = false)`
Importa un tema desde JSON string.
```typescript
const success = importTheme(jsonString, true) // true = guardar automáticamente
```
---
## Ejemplos de Uso
### Ejemplo 1: Card Básica
```vue
<template>
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<template #header>
<h3 class="text-[var(--brand-text)]">Mi Card</h3>
</template>
<p class="text-[var(--brand-text-muted)]">
Descripción del contenido
</p>
</UCard>
</template>
```
### Ejemplo 2: Botón con Hover
```vue
<template>
<button
class="px-4 py-2 rounded-lg bg-[var(--brand-surface)] border border-[var(--brand-border)] text-[var(--brand-text)] hover:bg-[var(--brand-primary)]/10 hover:border-[var(--brand-primary)] transition-colors"
>
Mi Botón
</button>
</template>
```
### Ejemplo 3: Input Personalizado
```vue
<template>
<UInput
v-model="value"
placeholder="Ingresa un valor"
:ui="{
base: 'bg-[var(--brand-surface)] border-[var(--brand-border)] text-[var(--brand-text)]',
placeholder: 'placeholder:text-[var(--brand-text-muted)]'
}"
/>
</template>
```
### Ejemplo 4: Link con Hover
```vue
<template>
<NuxtLink
to="/perfil"
class="text-[var(--brand-accent)] hover:text-[var(--brand-primary)] hover:underline transition-colors"
>
Ver perfil →
</NuxtLink>
</template>
```
### Ejemplo 5: Iconos
```vue
<template>
<UIcon
name="i-lucide-star"
class="size-5 text-[var(--brand-primary)]"
/>
<UIcon
name="i-lucide-info"
class="size-4 text-[var(--brand-accent)]"
/>
</template>
```
### Ejemplo 6: Manipular Tema Programáticamente
```vue
<script setup lang="ts">
const { theme, applyTheme, saveTheme } = useTheme()
// Modificar un color
const cambiarColorPrimario = () => {
theme.value.primary = '#60a5fa'
applyTheme()
saveTheme()
}
// Aplicar tema personalizado completo
const aplicarTemaAzul = () => {
theme.value = {
bg: '#0a0e1a',
surface: '#151a28',
border: '#2d3748',
primary: '#60a5fa',
primaryStrong: '#3b82f6',
accent: '#93c5fd',
text: '#f0f4f8',
textMuted: '#cbd5e1',
// Colores de café (mantener consistentes)
coffeeUva: '#a855f7',
coffeeOreado: '#f97316',
coffeeMojado: '#06b6d4',
coffeeVerde: '#22c55e',
// Colores de estados (mantener consistentes)
statusPendiente: '#f59e0b',
statusPagado: '#10b981',
statusAnulado: '#6b7280'
}
applyTheme()
saveTheme()
}
</script>
<template>
<div>
<button @click="cambiarColorPrimario">Cambiar Primary</button>
<button @click="aplicarTemaAzul">Aplicar Tema Azul</button>
</div>
</template>
```
### Ejemplo 7: Usar Colores de Tipos de Café
```vue
<template>
<!-- Badge para tipo de café -->
<UBadge
:style="{ backgroundColor: 'var(--coffee-uva)', color: 'white' }"
size="sm"
>
Café Uva
</UBadge>
<!-- Indicador visual de tipo -->
<div class="flex items-center gap-2">
<div class="w-3 h-3 rounded-full" style="background: var(--coffee-oreado)"></div>
<span>Café Oreado</span>
</div>
<!-- En gráficas (ejemplo con Chart.js) -->
<script setup>
const chartData = {
datasets: [{
label: 'Uva',
backgroundColor: 'var(--coffee-uva)',
data: [10, 20, 30]
}, {
label: 'Oreado',
backgroundColor: 'var(--coffee-oreado)',
data: [15, 25, 35]
}]
}
</script>
</template>
```
### Ejemplo 8: Usar Colores de Estados
```vue
<template>
<!-- Badge de estado pendiente -->
<UBadge
class="text-[var(--status-pendiente)] bg-[var(--status-pendiente)]/10 border border-[var(--status-pendiente)]/30"
size="sm"
>
Pendiente
</UBadge>
<!-- Badge de estado pagado -->
<UBadge
class="text-[var(--status-pagado)] bg-[var(--status-pagado)]/10 border border-[var(--status-pagado)]/30"
size="sm"
>
Pagado
</UBadge>
<!-- Badge de estado anulado -->
<UBadge
class="text-[var(--status-anulado)] bg-[var(--status-anulado)]/10 border border-[var(--status-anulado)]/30"
size="sm"
>
Anulado
</UBadge>
<!-- Indicador en tabla -->
<td>
<div class="flex items-center gap-2">
<div class="w-2 h-2 rounded-full" :style="{ backgroundColor: 'var(--status-pagado)' }"></div>
<span>Pagado</span>
</div>
</td>
</template>
```
---
## Integración con Nuxt UI
### Componentes que Respetan el Tema Automáticamente
Los siguientes componentes de Nuxt UI **NO necesitan customización** porque usan `--ui-color-neutral-*` internamente:
- `UButton` (con `color="neutral"`)
- `UBadge` (con `color="neutral"`)
- `UInput` (parcialmente)
- `UTextarea` (parcialmente)
- `USelect` (parcialmente)
- Componentes de navegación (sidebar, navbar)
### Componentes que Necesitan `:ui` Prop
Para estos componentes, debes especificar colores explícitamente:
#### UCard
```vue
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
body: { padding: 'p-6' },
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<!-- Contenido -->
</UCard>
```
#### UModal
```vue
<UModal
v-model="isOpen"
:ui="{
background: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
header: { base: 'border-b border-[var(--brand-border)]' }
}"
>
<!-- Contenido -->
</UModal>
```
#### UDropdown
```vue
<UDropdown
:items="items"
:ui="{
background: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]',
item: {
base: 'hover:bg-[var(--brand-primary)]/10'
}
}"
>
<!-- Contenido -->
</UDropdown>
```
---
## Casos Especiales
### Colores Semánticos (Success, Error, Warning)
Para estados semánticos, **SÍ puedes usar colores fijos de Tailwind** porque no forman parte del tema personalizable:
```vue
<template>
<!-- ✅ CORRECTO - Estados semánticos -->
<div class="text-green-400">Operación exitosa</div>
<div class="text-red-400">Error al procesar</div>
<div class="text-yellow-400">Advertencia</div>
<div class="text-blue-400">Información</div>
<!-- Pero el fondo y borde deben respetar el tema -->
<div class="bg-[var(--brand-surface)] border-green-600/30 text-green-400">
Éxito con tema
</div>
</template>
```
### Imágenes y Avatares
```vue
<template>
<!-- Avatar con ring temático -->
<UAvatar
src="/avatar.jpg"
:ui="{
wrapper: 'ring-2 ring-[var(--brand-primary)]/40'
}"
/>
<!-- Imagen con borde -->
<img
src="/logo.png"
class="rounded-full border-2 border-[var(--brand-accent)]/40 shadow-lg shadow-[var(--brand-primary-strong)]/25"
/>
</template>
```
### Gradientes
```vue
<template>
<!-- Gradiente usando variables -->
<div
class="bg-gradient-to-br"
:style="{
'--tw-gradient-from': 'var(--brand-primary)',
'--tw-gradient-to': 'var(--brand-accent)'
}"
>
Contenido con gradiente
</div>
</template>
```
---
## Troubleshooting
### Problema 1: Texto Invisible
**Síntoma:** El texto no se ve en algunos componentes.
**Causa:** Estás usando un color de fondo donde debería ir un color de texto.
**Solución:**
```vue
<!-- ❌ INCORRECTO -->
<div class="bg-[var(--brand-text)] text-[var(--brand-bg)]">
<!-- ✅ CORRECTO -->
<div class="bg-[var(--brand-surface)] text-[var(--brand-text)]">
```
### Problema 2: Componentes No Cambian con el Tema
**Síntoma:** Algunos componentes mantienen colores fijos cuando cambias de tema.
**Causa:** Estás usando colores hardcoded o clases gray-scale.
**Solución:** Reemplaza todos los colores fijos con variables `--brand-*`.
### Problema 3: UCard con Fondo Incorrecto
**Síntoma:** UCard tiene un fondo que no corresponde al tema.
**Causa:** Falta especificar la prop `:ui`.
**Solución:**
```vue
<UCard
:ui="{
base: 'bg-[var(--brand-surface)]',
ring: 'ring-1 ring-[var(--brand-border)]'
}"
>
<!-- Contenido -->
</UCard>
```
### Problema 4: Hover No Se Ve
**Síntoma:** Los hover effects no son visibles.
**Causa:** Estás usando colores sólidos en lugar de transparencias.
**Solución:**
```vue
<!-- ❌ INCORRECTO -->
<button class="hover:bg-[var(--brand-primary)]">
<!-- ✅ CORRECTO -->
<button class="hover:bg-[var(--brand-primary)]/10">
```
---
## Checklist Pre-Commit
Antes de hacer commit, verifica:
- [ ] No hay colores hexadecimales hardcoded (`#ffffff`, `#000000`, etc.)
- [ ] No hay clases gray-scale genéricas (`bg-gray-900`, `text-gray-500`, etc.)
- [ ] Todos los fondos usan `--brand-bg` o `--brand-surface`
- [ ] Todos los bordes usan `--brand-border`
- [ ] Todo el texto usa `--brand-text` o `--brand-text-muted`
- [ ] Los elementos interactivos usan `--brand-primary` o `--brand-accent`
- [ ] Los hover states usan transparencias (`/10`, `/20`, etc.)
- [ ] Se usan clases utilitarias cuando sea posible
---
## Resumen de Comandos Rápidos
```vue
<!-- VARIABLES BASE -->
<!-- Fondos -->
bg-[var(--brand-bg)] <!-- Fondo principal -->
bg-[var(--brand-surface)] <!-- Cards, modales -->
<!-- Bordes -->
border-[var(--brand-border)]
<!-- Texto -->
text-[var(--brand-text)] <!-- Texto principal -->
text-[var(--brand-text-muted)] <!-- Texto secundario -->
<!-- Colores de marca -->
text-[var(--brand-primary)] <!-- Links, títulos -->
text-[var(--brand-accent)] <!-- Highlights -->
bg-[var(--brand-primary-strong)] <!-- Backgrounds intensos -->
<!-- Hover (siempre con transparencia) -->
hover:bg-[var(--brand-primary)]/10
hover:border-[var(--brand-primary)]
hover:text-[var(--brand-accent)]
<!-- VARIABLES DE TIPOS DE CAFÉ -->
<!-- Colores de café -->
bg-[var(--coffee-uva)] <!-- Purple - Café Uva -->
bg-[var(--coffee-oreado)] <!-- Orange - Café Oreado -->
bg-[var(--coffee-mojado)] <!-- Cyan - Café Mojado -->
bg-[var(--coffee-verde)] <!-- Green - Café Verde -->
<!-- Ejemplo en badges -->
<UBadge :style="{ backgroundColor: 'var(--coffee-uva)', color: 'white' }">
Café Uva
</UBadge>
<!-- VARIABLES DE ESTADOS -->
<!-- Colores de estados -->
text-[var(--status-pendiente)] <!-- Amber - Pendiente -->
text-[var(--status-pagado)] <!-- Green - Pagado -->
text-[var(--status-anulado)] <!-- Gray - Anulado -->
<!-- Ejemplo en badges con fondo suave -->
<UBadge class="text-[var(--status-pagado)] bg-[var(--status-pagado)]/10">
Pagado
</UBadge>
```
---
## Notas Finales
- **Nunca modifiques** el mapeo de `--ui-color-neutral-*` en `main.css` sin entender el sistema completamente
- **Siempre usa variables CSS** para mantener la consistencia del tema
- **Prueba todos los temas** después de hacer cambios visuales (Café, Azul, Verde, Carbón)
- **Usa el composable** `useTheme()` para manipulación programática
- **Consulta este documento** ante cualquier duda sobre colores
## Mejoras Recientes (v2.1)
✅ **Todas las clases CSS ahora son completamente dinámicas**
- Las cards grandes (`.brand-card`) responden a cambios de tema
- Los gradientes de fondo (`.brand-shell`) se ajustan automáticamente
- Todas las clases utilitarias usan `color-mix()` con variables CSS
✅ **Nuevas variables para gráficas**
- `--brand-cosecha-2`, `--brand-cosecha-3`, `--brand-cosecha-4`
- Colores intermedios que mantienen armonía con el tema activo
- Usadas en gráficas de comparativa de cosechas
✅ **Eliminación de colores hardcodeados**
- Ya no existe `--brand-bg-secondary` (ahora usa `--brand-surface`)
- Todos los colores RGB/hex hardcodeados fueron reemplazados
- El background de `html/body` ahora usa `var(--brand-bg)`
---
**Mantenido por:** Claude Code para Núcleo Río Frío
**Versión del sistema:** 2.1
**Última revisión:** 2025-10-31