/* Nexus · tokens de marca — FUENTE ÚNICA
   Creado 2026-08-27 (sdd/brand-tokens-single-source).

   Antes de este archivo, los tokens estaban definidos TRES veces por separado
   (`main/src/styles.css`, `costeo/index.html`, `portal/src/styles.css`) y
   `plan/index.html` no los definía: usaba hex literales. Los valores coincidían
   por suerte, no por diseño — nada los mantenía sincronizados, y esa era la
   causa estructural de la deriva visual entre módulos
   (`openspec/system-parity-audit-2026-08-27.md` §2.2).

   ── CÓMO SE CARGA ──────────────────────────────────────────────────────────
   Con `<link rel="stylesheet" href="/brand/tokens.css">` desde los CUATRO
   `index.html`, hermano de `/fonts/fonts.css` y con el mismo criterio: es el
   patrón que ya resolvió la tipografía en `47a596b`.

   No es un `@import` desde el CSS de cada módulo porque Costeo y Plan **no
   tienen** archivo CSS —su estilo vive inline en el `<html>`— y un `@import`
   además haría que Vite copiase los tokens dentro de cada bundle, que es
   justo lo que este archivo viene a evitar.

   El `<link>` va ANTES de los estilos del módulo. Las propiedades
   personalizadas de igual especificidad se resuelven por orden de documento,
   así que si algún módulo necesitara sobrescribir un token algún día, debe
   poder. Hoy ninguno lo hace.

   ── REGLA QUE NO HAY QUE RE-DECIDIR ────────────────────────────────────────
   NO volver a declarar estos tokens en el `:root` de un módulo. Ganaría la
   última definición por orden de documento y este archivo quedaría decorativo
   — el mismo modo de fallo silencioso que `CLAUDE.md` §11.1 describe para un
   segundo `@font-face` que anula el `size-adjust`.

   Lo que SÍ es correcto: que un módulo defina tokens PROPIOS, los que solo él
   usa. Hoy `costeo` conserva `--border` y `--accent-gold`; `portal` conserva
   `--line-soft` y `--shadow`. */

:root {
  /* ── Paleta institucional (Brand Book v2.1) ──────────────────────────── */
  --deep-navy: #2C3E50;      /* titulares y superficies oscuras */
  --charcoal: #4A4A4A;       /* texto de cuerpo sobre superficie clara */
  --brand-blue: #91BDE4;     /* acento: líneas, marcadores de sección */
  --light-blue: #BEE2FC;     /* lavados de fondo, rellenos de gráfico */
  --surface-page: #F9F6F0;   /* fondo de página */
  --warm-cream: var(--surface-page);  /* alias durante la migracion, ver la nota de superficies */
  --warm-tan: #DCC9A6;       /* divisores, bordes de acento */
  --warm-tan-dark: #B8894E;  /* oro de acción */
  /* THE CORAL ALARM RULE: reservado a acciones DESTRUCTIVAS o IRREVERSIBLES. Si un elemento no
     es irreversible, no lleva coral -- ni siquiera un boton de peligro que se pueda deshacer.
     La regla vive en `.agents/context/DESIGN.md:99-100,181-182,250` y la citan `controls.css`
     (:147, :189) y `modals.css` (:365, :431) para justificar por que usan `#A33` en su lugar.
     Este comentario decia "solo el isotipo", que NO era la regla vigente y contradecia a los
     otros cuatro archivos; corregido el 2026-08-30 para describir la restriccion real, no para
     ampliarla. */
  --coral: #F5B7A7;
  /* Los dos siguientes ya se usaban, escritos a mano en las hojas de los modulos: `#1A2332` en
     el hover de `.cta-link` del Connect y como `theme-color` de los cuatro index.html, y
     `#5B8FB0` en el extremo oscuro de tres degradados de avatar. Se promueven a token el
     2026-08-28 por la regla 3.7 -- mismos valores exactos, ningun cambio visual. */
  --deep-navy-dark: #1A2332; /* navy del hover y del theme-color del navegador */
  --brand-blue-deep: #5B8FB0; /* extremo oscuro de los degradados de acento */

  /* ── Primer plano sobre superficie OSCURA ───────────────────────────────
     El par que le faltaba al sistema, y el origen de un defecto real: `body`
     fija `color: var(--charcoal)` para la página crema, y una superficie
     oscura como `.pl-shell` de Costeo cambia el fondo SIN cambiar el primer
     plano. Cualquier icono con `stroke="currentColor"` dentro de ella heredaba
     el color de la superficie equivocada y quedaba invisible (medido: ΔLum 1.1
     en el engranaje de la píldora de usuario).

     `--on-dark-soft` vale exactamente lo que ya usaba a mano el texto vecino
     del nombre de usuario (`costeo/src/app.jsx`), así que adoptarlo no cambia
     ningún color existente: solo le da nombre. */
  --on-dark: rgba(255, 255, 255, 0.92);
  --on-dark-soft: rgba(255, 255, 255, 0.7);

  /* ── Derivados compartidos por dos o más módulos ─────────────────────── */
  /* `--soft-cream`, `--warm-tan-soft` y `--muted` se promovieron desde
     `main/src/styles.css` en sdd/staff-chrome-unification fase A: el chrome compartido
     (`/brand/chrome.css`) los usa para el borde de la cabecera y del pie, el fondo del pie y
     su color de texto. Si el chrome es compartido, sus tokens lo son por definicion. */
  /* ── SUPERFICIES: dos CAPAS, no dos matices del mismo crema ─────────────────
     Medido el 2026-08-30 antes de decidir si sobraba uno: `--warm-cream` tiene 34 usos y TODOS son
     fondo de pagina; `--soft-cream` tiene 5 y todos son superficie ELEVADA -- `select`,
     `.board-card:hover`, `.int-card`, el pie del chrome y un degradado de modal. Estan a distancia
     perceptual 5.4, asi que a ojo son el mismo color, pero la separacion no la lleva el color: el
     pie tiene `border-top`, el hover anade `box-shadow: var(--shadow-lifted)` y el `select` tiene
     borde tan.

     El defecto estaba en el NOMBRE, no en el valor: ninguno de los dos decia su rol, asi que quien
     dudaba cual usar escribia el hex. Es la causa mas probable de las 32 variantes distintas del
     crema que habia en el codigo. Se renombran por rol y se mantienen los nombres viejos como
     ALIAS hasta que migre el ultimo uso -- sin el alias, esto seria un cambio atomico de 39 sitios
     que no se puede verificar por partes.

     REGLA QUE NO HAY QUE RE-DECIDIR: las variantes de tinta se calibran contra `--surface-page`,
     que es la superficie mas OSCURA de la familia crema. No contra `--surface-raised` ni contra
     blanco. Ver la nota de "Primer plano LEGIBLE" mas abajo. */
  --surface-raised: #FBF9F4; /* control, tarjeta, hover, pie */
  --soft-cream: var(--surface-raised);  /* alias durante la migracion */
  --warm-tan-soft: rgba(220, 201, 166, 0.45);
  --muted: #9AA5B1;
  --line: rgba(220, 201, 166, 0.5);
  /* `--tan-wash` se promovió desde `main/src/styles.css` en fase C-bis (2026-08-27): lo usa
     `.header-icon-btn:hover` de `/brand/chrome.css`, que Costeo y Plan enlazan igual que `main`. */
  --tan-wash: rgba(220, 201, 166, 0.18);
  --shadow-lifted: 0 4px 16px rgba(44, 62, 80, 0.06);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* `--t` viene de la MISMA linea del legacy que `--ease` (`Nexus/portal/index.html:122`:
     `--ease: ...; --t-fast: 150ms; --t: 220ms; --t-slow: 360ms;`). Al portar la marca se trajo
     `--ease` y se dejo `--t` atras, y el Connect tiene 9 `transition: ... var(--t) var(--ease)`
     SIN fallback: con la propiedad indefinida, la declaracion `transition` entera es invalida en
     tiempo de valor computado y esas nueve transiciones sencillamente NO EXISTEN en el sistema
     nuevo, mientras si funcionan en produccion. Sin error y sin una linea en consola -- el modo
     de fallo de `--ink-muted` (CLAUDE.md §3.6), esta vez en movimiento.
     `--t-fast` y `--t-slow` NO se declaran: hoy no los usa nadie, y un token sin uso es peso
     muerto con aspecto de sistema. Se anaden el dia que un componente los pida. */
  --t: 220ms;

  /* ── Primer plano LEGIBLE sobre superficie clara ───────────────────────────
     Promovidos en sdd/staff-chrome-unification fase J (2026-08-27), al medir el
     contraste real del chrome antes de extenderlo a Plan. Tres colores que el
     marco usaba como TEXTO no llegaban al 4.5:1 que pide WCAG AA para texto
     normal, medido sobre el fondo que de verdad se pinta detras:

       #9AA5B1 (--muted) sobre --soft-cream ... 2.38:1   pie, "Salir"
       #91BDE4 (--brand-blue) sobre #fff ...... 1.98:1   .user-pill-role
       #B8894E (--warm-tan-dark) sobre crema .. 2.97:1   .nexus-back-pill
       #8C8775 literal sobre --soft-cream ..... 3.42:1   .app-version

     Los cuatro son texto pequeno (0.6-0.75rem), varios en mayusculas, asi que
     el umbral aplicable es 4.5:1 y no el 3:1 de texto grande. El hallazgo
     invierte una suposicion que costo verificar: el hero NAVY de Plan estaba a
     9.61:1, mejor que el chrome crema al que se estaba migrando. Sin estos
     tokens, unificar habria cambiado un problema estetico por uno de lectura.

     Cada valor se obtuvo escalando el ORIGINAL hacia el negro en pasos de 1%
     hasta cruzar 4.5:1 -- se conserva el matiz de marca, solo baja la
     luminosidad. Son variantes de texto: `--muted`, `--brand-blue` y
     `--warm-tan-dark` siguen valiendo tal cual para bordes, rellenos e iconos
     decorativos, donde el umbral es otro. No sustituirlos a ciegas.
     Cada valor se calibro contra `--warm-cream` (#F9F6F0), la superficie mas
     OSCURA de la familia crema, no contra la mas clara: el chrome se pinta
     sobre las tres (#fff en la pildora, --soft-cream en el pie, --warm-cream en
     el cuerpo) y el contraste BAJA cuanto mas oscuro es el fondo. Calibrar
     contra `--soft-cream` daba 4.51:1 ahi y 4.40:1 sobre `--warm-cream`: por
     debajo del umbral justo en la superficie mas comun de la aplicacion.
     Los tres ratios, medidos: */
  --ink-muted: #6A727A;       /* crema 4.53 · soft 4.64 · blanco 4.88 · texto secundario */
  --brand-blue-ink: #58738B;  /* crema 4.59 · soft 4.71 · blanco 4.95 · acento como TEXTO */
  /* #8E693C pasaba contra la superficie crema desnuda (4.60:1), pero el barrido en navegador lo
     midio a 4.37:1 en su uso REAL: el pill "<- Nexus" tiene su propio fondo tan al 18% compuesto
     sobre la barra al 92% sobre el crema, y ese apilado es mas oscuro que el crema solo. Se baja al
     valor que aguanta ese caso -- 5.14:1 sobre crema, 5.27 sobre soft-crema, 5.55 sobre blanco.
     Es la misma leccion que con `--ink-muted`: calibrar contra la superficie mas oscura donde el
     color se va a pintar de verdad, no contra la mas clara. */
  --warm-tan-ink: #846238;    /* crema 5.14 · soft 5.27 · blanco 5.55 · oro como TEXTO */

  /* Anillo de foco del chrome. Un solo valor para los cuatro modulos: antes de
     la fase J, `chrome.css` tenia CERO reglas `:focus-visible` -- ningun control
     del marco de staff (logo, campana, menu admin, pildora, Salir) mostraba
     donde estaba el teclado. */
  /* Se declara como COLOR y se consume con `outline`, no como `box-shadow` de dos anillos: un
     `box-shadow` lo recorta cualquier ancestro con `overflow: hidden` (la pildora, el panel del
     menu admin y la barra de pestanas de Plan lo tienen), y ahi el foco desapareceria justo en los
     controles que mas lo necesitan. `outline` no participa del recorte ni del layout.
     4.60:1 sobre crema -- por encima del 3:1 que WCAG 2.2 pide a un indicador de foco. */
  --focus-ring-color: var(--warm-tan-ink);

  /* ── ESCALA TIPOGRAFICA ──────────────────────────────────────────────────────
     Derivada del uso, no elegida a priori. Antes de esto el archivo tenia 23 tokens y TODOS eran
     de color: cero de tamano, cero de radio. `DESIGN.md` describia la escala en prosa, y una
     descripcion en prosa no la puede consumir ni un `var()` ni un test.

     Medidas que la sustentan (2026-08-30, sobre 1.560 declaraciones con tamano estatico):
     los SEIS roles tipograficos colapsan en TRES niveles. micro (0.66rem) y etiqueta (0.68rem) se
     separan 0.3px: son el mismo paso, los distingue `text-transform`. cuerpo (0.78), enfasis
     (0.80) y dato (0.75) caben todos entre 12 y 12.8px: los distingue el PESO. Solo titular
     (1.25rem) se separa de verdad. El 66% de los usos estaba amontonado entre 11 y 13px.

     Con estos 8 pasos, el 93% de los usos se mueve 1px o menos y solo el 1.8% supera los 2px --
     y 26 de esos 28 son titulares de 26px o mas, asi que el texto de trabajo del staff no se toca.
     Enumerados uno a uno en `openspec/design-system-enforcement/02-spec.md` §0.

     Nombres SEMANTICOS, nunca de valor (`--text-body`, jamas `--font-16`): el valor puede cambiar
     y el rol no. */
  --text-micro:    0.62rem;  /*  9.9px  micro y etiqueta                */
  --text-label:    0.70rem;  /* 11.2px                                  */
  --text-body:     0.78rem;  /* 12.5px  cuerpo, enfasis y dato          */
  --text-body-lg:  0.88rem;  /* 14.1px                                  */
  --text-lead:     1.00rem;  /* 16.0px                                  */
  --text-title:    1.25rem;  /* 20.0px  titular                         */
  --text-title-lg: 1.50rem;  /* 24.0px                                  */
  --text-display:  2.00rem;  /* 32.0px                                  */

  /* ── ESCALA DE RADIOS ────────────────────────────────────────────────────────
     Mismo metodo, sobre 570 usos y 17 valores distintos. Estos 6 pasos dejan el 77% sin mover y
     el 92% dentro de 1px, con un peor caso de 4px.

     CONTRADICE `DESIGN.md`, y el dato manda: ese documento declara `lg 14px`, pero 14px tiene 20
     usos y 10px tiene 73. La escala se deriva de lo que el sistema usa, no de lo que un documento
     dijo que usaria.

     `pill` y `circle` NO son pasos de la escala: son FORMA. Una pildora y un circulo perfecto no
     pertenecen a una progresion de radios, y por eso la guarda los exceptua. */
  --radius-xs:     2px;
  --radius-sm:     6px;   /* 148 usos */
  --radius-md:     8px;   /* 158 usos */
  --radius-lg:    10px;   /*  73 usos */
  --radius-xl:    12px;   /*  43 usos */
  --radius-2xl:   20px;   /*  14 usos */
  --radius-pill: 999px;
  --radius-circle: 50%;

  /* ── ESTADOS ─────────────────────────────────────────────────────────────────
     La causa del desorden de color NO era que sobraran colores: FALTABAN NOMBRES. El sistema nunca
     declaro `--danger`, `--success`, `--warn` ni `--info`, asi que cada persona invento el color
     de nuevo cada vez. Medido el 2026-08-30: 14 rojos de error distintos, 13 verdes, 37 ambar y 30
     azules -- con `#DC3545` de Bootstrap, `#DC2626` de Tailwind y `#E53935` de Material mezclados
     dentro de la misma pantalla.

     Se agrupa por SIGNIFICADO, no por distancia perceptual. Agrupar por distancia daba 57 tokens y
     convertia los 7 rojos en `--danger-1` .. `--danger-7`: bendecir el desorden en vez de cerrarlo,
     y garantizar que el octavo rojo se inventase igual.

     WARN E INFO NO TIENEN COLOR PROPIO, y es deliberado: el ambar y el azul YA existen en la marca.
     Solo el rojo y el verde faltaban de verdad. Reutilizarlos es lo que mantiene la identidad en
     vez de abrir una paleta paralela.

     Las SUPERFICIES se DERIVAN mezclando el ink de su familia con `--surface-page` al 15%, no se
     importan: el candidato natural para `--success-surface` era `#F0FDF4`, que es `green-50` de
     Tailwind, y meter un color ajeno en la ley unica es justo lo que esto viene a cerrar.

     Y el ink NO es siempre el mas usado: `#2E7D5B` aparece 115 veces pero con 4.63 sobre crema
     solo admite un 2% de tinte en su superficie, o sea un fondo indistinguible del crema.
     `#1F5C42` (7.30) admite 15%. El criterio es que el par ink/superficie funcione.

     Contraste medido sobre las tres superficies claras reales -- crema, elevada y blanco:
       danger  6.03 · 6.18 · 6.50    ink sobre su surface 4.78   border sobre crema 3.03
       success 7.30 · 7.48 · 7.87    ink sobre su surface 5.79   border sobre crema 3.02
       warn    5.14 · 5.27 · 5.55    ink sobre su surface 4.52   border sobre crema 3.04
       info   10.18 · 10.44 · 10.98  ink sobre su surface 8.09   border sobre crema 3.02 */
  --danger-ink:      #AA3333;
  --danger-surface:  #EDD9D4;
  --danger-border:   #C67977;
  --success-ink:     #1F5C42;
  --success-surface: #D8DFD6;
  --success-border:  #729784;
  --warn-ink:        var(--warm-tan-ink);   /* el oro de la marca YA es el ambar del sistema */
  --warn-surface:    #EDE7DE;
  --warn-border:     #A48A6A;
  --info-ink:        var(--deep-navy);      /* navy sobre azul claro: el patron de marca tal cual */
  --info-surface:    var(--light-blue);
  --info-border:     #7D91A2;

  /* ── NEUTROS ─────────────────────────────────────────────────────────────────
     Habia 17 grises con 5+ usos, 737 usos en total, y eran GRIS PURO -- `#888888`, `#CCCCCC` --
     dentro de una marca calida de crema y tan. Se sustituyen por 7 pasos tenidos hacia el tono de
     `--warm-tan` (hue 39, saturacion 0.08), conservando la LUMINANCIA EXACTA de cada gris que
     reemplazan.

     Eso es lo que hace el cambio gratis en accesibilidad: el delta maximo de contraste sobre
     `--surface-page` en toda la escala es 0.040, y la mayoria esta por debajo de 0.015.

     El blanco NO se tine: un blanco tenido es un gris, y hay 348 usos que quieren blanco.

     Cada paso lleva escrito PARA QUE SIRVE, y eso es lo que impide el octavo gris: quien necesite
     texto gris ve que solo `-0` y `-1` califican. */
  --neutro-0: #3D3A34;  /* crema 10.50 · texto            */
  --neutro-1: #6B655B;  /* crema  5.34 · texto            */
  --neutro-2: #8E887B;  /* crema  3.28 · borde e icono    */
  --neutro-3: #AEA9A0;  /* crema  2.16 · superficie       */
  --neutro-4: #CFCCC6;  /* crema  1.49 · superficie       */
  --neutro-5: #DFDDD9;  /* crema  1.26 · superficie       */
  --neutro-6: #FFFFFF;  /* crema  1.08 · superficie       */

  /* ── BORDES ──────────────────────────────────────────────────────────────────
     `#E5DDD0` tenia 150 usos y 13 variantes, y NO era token. Es el borde de campo mas usado del
     sistema; sin nombre, cada quien escribia su propia aproximacion. */
  --border-field:  #E5DDD0;  /* 150 usos: borde de input, select, textarea */
  --border-soft:   #EDE8E0;  /*  25 usos: separador tenue                  */
  --border-strong: var(--warm-tan);  /* divisor de acento, ya existia      */

  /* ── PUENTES DEL NOMBRE LEGACY, A RETIRAR ────────────────────────────────────
     `costeo/src/app.jsx` conserva 36 `var(--border)` y 15 `var(--accent-gold)`, los nombres que
     usaba `Nexus/costeo/index.src.html:422-423`. Ninguno de los dos se declaro al portar, y como
     van SIN fallback en estilos inline de React, hoy son 51 declaraciones invalidas: bordes que no
     se pintan y un dorado que cae al color heredado.

     NO se duplica el valor -- cada alias apunta al token vigente, cuyo hex es IDENTICO al del
     legacy (`#E5DDD0` y `#B8894E`), comprobado uno contra otro. Se declaran aqui y no se
     reescriben los 51 usos porque eso son 51 hunks dentro de un archivo de 16.900 lineas que se
     esta editando en paralelo (§10.5), y el alias arregla la pantalla hoy sin ese conflicto.

     COMO SE RETIRA: sustituir `var(--border)` por `var(--border-field)` y `var(--accent-gold)` por
     `var(--warm-tan-dark)` en `costeo/src/app.jsx`, y borrar estas dos lineas. Mientras existan,
     `test/varHuerfanos.test.js` no deja que nadie anada un uso nuevo por otro nombre sin declarar. */
  --border: var(--border-field);
  --accent-gold: var(--warm-tan-dark);
}
