/* ═══════════════════════════════════════════════════════════════════════════
   fnadigital.co · TEMA «SALA DE CONTROL NOCTURNA»
   Re-viste el micrositio existente sin tocar su HTML ni su JS.

   Cómo funciona: el sitio expresa casi todo su color a través de un puñado de
   variables (--negro, --carbon, --ocre…), incluso desde JavaScript
   (app.js y grafo-app.js escriben `fill:var(--ocre)` en los SVG). Basta
   redefinir esas variables para que el tema entero cambie de piel, incluidos
   los gráficos que se pintan en runtime. Este archivo se carga DESPUÉS del
   <style> en línea de index.html: misma especificidad, gana el orden.
   ═══════════════════════════════════════════════════════════════════════════ */

@import url("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wdth,wght@12..96,75..100,300..800&family=Inter+Tight:ital,wght@0,300..700;1,400..500&family=Martian+Mono:wdth,wght@75..112.5,300..700&display=swap");

/* ══════════════════════ 1 · TOKENS ══════════════════════ */

:root {
  /* Paleta canónica del tema — validada en modo oscuro sobre #0d1117.
     Estos valores son los de las MARCAS (rellenos, barras, puntos): no se
     tocan. Las derivadas -txt de más abajo existen sólo para texto pequeño. */
  --fondo: #06080d;
  --superficie: #0d1117;
  --superficie2: #141b24;
  --superficie3: #1a222c;
  --pipeline: #2aa3bd;   /* cian  · lo prospectivo */
  --historico: #b0862a;  /* ámbar · lo verificado  */
  --alerta: #c94434;     /* rojo  · indicios       */
  --exito: #2a8f70;      /* verde · adjudicado     */

  /* Derivadas para TEXTO. El sitio usa los acentos a 9–11px en mayúsculas
     (chips, kickers, badges): a ese tamaño el valor canónico se queda corto
     de contraste. Cada derivada se aclaró hasta pasar 4.5:1 sobre #0d1117
     conservando el tono. El par alerta↔histórico sigue siendo distinguible
     sólo con etiqueta de texto: NUNCA codificar estado sólo por color. */
  --pipeline-txt: #45c3dd;   /* 9.2:1 */
  --historico-txt: #c9a03f;  /* 7.9:1 */
  --alerta-txt: #de6249;     /* 5.4:1 */
  --exito-txt: #33a081;      /* 6.0:1 */

  --texto: #e6edf5;
  --texto2: #8b9bb0;
  --texto3: #5a6b80;         /* decorativo: no usar para texto corrido */

  /* ── Remapeo de las variables que el sitio ya usa ──
     El nombre viejo se conserva; sólo cambia a qué apunta. */
  --negro: var(--fondo);          /* fondo de página y borde de los nodos del grafo */
  --carbon: var(--superficie);    /* tarjetas, celdas, casos, drawer */
  --tinta: var(--superficie2);    /* hover de fila, inputs, conmutadores */
  --tinta2: var(--superficie3);   /* thead pegajoso, cabecera del drawer, pistas de barra */
  --tinta-fuerte: #f2f7fd;        /* titulares: un punto por encima del cuerpo */

  --hueso: var(--texto);
  /* --gris2 NO se mapea a --texto3: el sitio lo usa para objetos de contrato,
     periodos y captions reales, no para adorno. A #5a6b80 daba 3.5:1. */
  --gris: var(--texto2);          /* 6.7:1 */
  --gris2: #788ba3;               /* 5.5:1 */

  --linea: rgba(120, 160, 200, .14);
  --linea2: rgba(120, 160, 200, .07);

  /* --ocre es el acento identitario del sitio y aparece sobre todo como texto;
     --ocre-op es el que llena barras y áreas, y ahí sí manda el valor canónico.
     De ahí que la versión "opaca" sea más apagada que la de texto: es al revés
     que en el tema claro, y es intencional. */
  --ocre: var(--historico-txt);
  --ocre-op: var(--historico);

  --alta: var(--alerta-txt);
  --media: #c4932f;
  --baja: var(--exito-txt);

  --serif: "Bricolage Grotesque", "Inter Tight", system-ui, sans-serif;
  --sans: "Inter Tight", system-ui, -apple-system, sans-serif;
  --mono: "Martian Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Sombras largas y suaves: una sola fuente de luz, alta y fría. */
  --elev-1: 0 1px 0 rgba(150, 190, 230, .045) inset, 0 10px 24px -14px rgba(0, 0, 0, .9);
  --elev-2: 0 1px 0 rgba(150, 190, 230, .06) inset, 0 28px 64px -28px rgba(0, 0, 0, .95);
  --radio: 4px;

  color-scheme: dark; /* controles nativos, autocompletado y barras del SO en oscuro */
}

/* ══════════════════════ 2 · BASE Y ATMÓSFERA ══════════════════════ */

html { background: var(--fondo); }

body {
  background: var(--fondo);
  color: var(--texto);
  /* En oscuro el texto "engorda" ópticamente; el antialiasing en escala de
     grises lo devuelve al peso que tenía en papel. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Grano de sensor. En el tema claro el ruido multiplicaba (oscurecía la fibra
   del papel); sobre #06080d multiplicar no produce nada visible porque el
   fondo ya es casi negro. Aquí el ruido se convierte en motas BLANCAS con
   alfa derivado de la luminancia (feColorMatrix) y se compone en `screen`,
   que sobre negro sí levanta. Opacidad muy baja: se percibe, no se ve. */
body::before {
  opacity: .07;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 .32 .32 .32 0 -.24'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}

/* Luz ambiental: la sala tiene volumen. Cuatro focos —cian arriba a la
   izquierda (lo que viene), ámbar abajo a la derecha (lo verificado), un
   relleno frío al centro y una viñeta que cierra los bordes. */
body::after {
  background:
    radial-gradient(58% 42% at 14% -6%, rgba(42, 163, 189, .11), transparent 68%),
    radial-gradient(52% 40% at 92% 8%, rgba(176, 134, 42, .055), transparent 70%),
    radial-gradient(80% 55% at 50% 108%, rgba(176, 134, 42, .05), transparent 72%),
    radial-gradient(120% 90% at 50% 40%, rgba(30, 52, 78, .18), transparent 70%),
    radial-gradient(140% 110% at 50% 50%, transparent 45%, rgba(0, 0, 0, .55));
  animation: sala-respira 26s ease-in-out infinite;
}

@keyframes sala-respira {
  0%, 100% { opacity: .88; }
  50% { opacity: 1; }
}

::selection { background: rgba(42, 163, 189, .28); color: #fff; }

/* Foco visible en todo elemento operable (contrato de accesibilidad §3.5). */
:focus-visible {
  outline: 2px solid var(--pipeline-txt);
  outline-offset: 2px;
}

/* Barras de desplazamiento propias del tema, incluidas las de .tabla-env */
* { scrollbar-width: thin; scrollbar-color: rgba(120, 160, 200, .22) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(120, 160, 200, .2);
  border: 3px solid transparent;
  background-clip: padding-box;
  border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(120, 160, 200, .34); background-clip: padding-box; }

/* ══════════════════════ 3 · TIPOGRAFÍA ══════════════════════ */

h1.titulo {
  font-weight: 600;
  font-stretch: 88%;          /* Bricolage tiene eje wdth 75–100: el titular se comprime sin perder tensión */
  letter-spacing: -.03em;
  font-optical-sizing: auto;
}
/* Bricolage Grotesque no trae itálica: sin esto el navegador la sintetiza
   inclinando los glifos. Se diferencia por ancho y color, no por inclinación. */
h1.titulo em { font-style: normal; font-weight: 400; font-stretch: 100%; }

h2.sec, .mapa-titular h2, #drawer h3 {
  font-weight: 500;
  font-stretch: 92%;
  letter-spacing: -.02em;
  font-optical-sizing: auto;
}

/* Alivio de peso: sobre fondo oscuro un 700 se empasta. Inter Tight es
   variable, así que 550/600 existen de verdad y no son una interpolación falsa. */
b, strong, .prov, .g-nom, .rec .nm, .caso h4, .carta h3 { font-weight: 550; }
.cifra .n, .mapa-hero .big, .vgrupo .val, .caso .pts, .rec .tot { font-weight: 500; }
.mapa-lede b, .mapa-titular b, .aviso b { font-weight: 600; }

/* Martian Mono es MUCHO más ancha que Courier Prime y las columnas de la
   tabla tienen anchos fijos en píxeles. Se estrecha por el eje wdth en vez de
   bajar el cuerpo, que es lo que costaría legibilidad. */
.kicker, .ficha dt, .ficha dd, .tab, .cifra .n, .conteo, thead th, td.num, td.ref,
.chip, .caso .pts, .caso .r, .caso .v, .caso .bd b, .g-meta, .g-val,
.conmuta button, .mercado h4, .m-emp .of, .derrota .flecha,
.vgrupo .val, .vgrupo .cab .tp, .vm-badge, .vm-v,
.rec .meta, .rec .badge, .rec .tot, .mapa-hero .big, .mapa-hint,
.mapa-sueltos .tit, .suelto .pt, .suelto .ix,
#tip .t, #tip .n, .campo dt, .campo dd.mono, .btn-exp,
input.busca, select.filtro, .chart text {
  font-stretch: 78%;
  font-variant-numeric: tabular-nums;
}

/* El monoespaciado en mayúsculas ya trae mucho ritmo: menos tracking que en papel. */
.kicker, .ficha dt, thead th, .chip, .tab { letter-spacing: .09em; }

.sub, .sec-nota, .mapa-titular p { color: var(--texto2); }

/* ══════════════════════ 4 · SUPERFICIES Y PROFUNDIDAD ══════════════════════ */

/* Cada superficie es un plano iluminado desde arriba: filo claro en el borde
   superior (inset) y sombra larga hacia abajo. Nunca una caja plana con marco. */
.carta, .tabla-env, .vgrupo, .rec, .derrota, .mapa-lienzo, .aviso,
.cifras, .ficha, .casos, .mercados, #red-svg, .mapa-hero {
  border-radius: var(--radio);
  box-shadow: var(--elev-1);
}
/* Los contenedores en rejilla dibujan sus filetes con `gap` + fondo: hay que
   recortar a los hijos o las esquinas redondeadas se ven mordidas. */
.cifras, .ficha, .casos, .mercados, #red-svg, .mapa-hero { overflow: hidden; }

.carta, .mapa-lienzo, .tabla-env { box-shadow: var(--elev-2); }

.carta, .cifra, .caso, .mercado, .vgrupo, .rec, .grupo, .mapa-hero .h,
.ficha div, .derrota { background: var(--carbon); }
.ficha div { background: var(--superficie); }

.caso:hover, .rec:hover, tbody tr:hover { background: var(--superficie2); }

.mapa-lienzo {
  background:
    radial-gradient(96% 78% at 50% -14%, rgba(42, 163, 189, .09), transparent 62%),
    radial-gradient(120% 100% at 50% 100%, rgba(0, 0, 0, .5), transparent 60%),
    var(--superficie);
  box-shadow: var(--elev-2), 0 0 0 1px rgba(120, 160, 200, .05) inset;
}

.mapa-hero .h { background: linear-gradient(180deg, var(--superficie2), var(--superficie)); }
/* El resplandor de esquina de las cifras hero: es la "luz que sale del dato".
   Nada de `filter:blur` y el núcleo hundido en la esquina: la celda recorta con
   overflow, así que lo único que asoma debe ser la cola del degradado. Con el
   núcleo centrado, el recorte deja un canto recto que parece un fallo de
   render en vez de una luz. */
.mapa-hero .h::after {
  filter: none;
  width: 210px; height: 210px;
  right: -105px; bottom: -105px;
  background: radial-gradient(circle, color-mix(in srgb, var(--historico) 34%, transparent), transparent 62%);
}
.mapa-hero .h.alarma::after {
  background: radial-gradient(circle, color-mix(in srgb, var(--alerta) 34%, transparent), transparent 62%);
}

.aviso {
  background: linear-gradient(90deg, rgba(176, 134, 42, .10), rgba(176, 134, 42, .02) 42%, transparent);
  border-left: 2px solid var(--ocre-op);
  color: var(--texto2);
}

.suelto { background: var(--superficie); box-shadow: var(--elev-1); border-radius: 3px; }
/* El monograma va sobre un punto de tono medio: necesita texto casi negro. */
.suelto .pt { color: #080b11; }

/* ══════════════════════ 5 · CROMO: NAV, TABLA, TIP, DRAWER ══════════════════════ */

/* Estaba fijado en el hueso del tema claro; con el fondo nuevo quedaba como
   una banda blanca flotando. */
nav.tabs {
  background: rgba(6, 8, 13, .78);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  box-shadow: 0 1px 0 var(--linea2), 0 16px 30px -24px rgba(0, 0, 0, .9);
}
.tab[aria-selected="true"] {
  color: var(--ocre);
  border-bottom-color: var(--ocre);
  /* la pestaña activa no cambia de color: se enciende */
  text-shadow: 0 0 18px rgba(201, 160, 63, .45);
}

thead th {
  background: var(--superficie3);
  color: var(--gris2);
  box-shadow: 0 1px 0 var(--linea);
}
tbody tr { border-bottom-color: var(--linea2); }

input.busca, select.filtro {
  background: var(--superficie2);
  color: var(--texto);
  box-shadow: 0 1px 0 rgba(150, 190, 230, .04) inset;
  border-radius: 3px;
}
input.busca::placeholder { color: var(--texto3); }
input.busca:focus, select.filtro:focus {
  outline: 1px solid var(--pipeline);
  border-color: var(--pipeline);
  box-shadow: 0 0 0 3px rgba(42, 163, 189, .14);
}

.conmuta button { background: var(--superficie2); border-radius: 3px; }
.conmuta button.on { box-shadow: 0 0 18px -6px rgba(201, 160, 63, .5); }

#tip {
  background: rgba(20, 27, 36, .96);
  border: 1px solid rgba(120, 160, 200, .2);
  border-radius: var(--radio);
  color: var(--texto);
  backdrop-filter: blur(10px);
  box-shadow: 0 24px 56px -18px rgba(0, 0, 0, .95), 0 0 0 1px rgba(0, 0, 0, .5);
}
#tip .n { color: var(--tinta-fuerte); }

#drawer {
  background: var(--superficie);
  box-shadow: -40px 0 90px -30px rgba(0, 0, 0, .95), -1px 0 0 var(--linea);
}
#drawer .top {
  background: rgba(20, 27, 36, .94);
  backdrop-filter: blur(12px);
}
#backdrop { background: rgba(3, 5, 9, .72); backdrop-filter: blur(2px); }

.btn-exp { border-radius: 3px; }
.btn-exp:hover { box-shadow: 0 0 20px -6px rgba(201, 160, 63, .55); }

footer { color: var(--gris2); }

/* ══════════════════════ 6 · GRÁFICOS Y GRAFO ══════════════════════ */

.chart text { fill: var(--gris2); }
.eje { stroke: var(--linea); }
.barra:hover { opacity: 1; filter: brightness(1.25); }

/* Los nodos del grafo se dibujan con un borde del color de fondo para
   separarse entre sí: en oscuro eso ya funciona, pero se les añade una caída
   suave para que floten sobre el lienzo en vez de estar pegados a él. */
#grafo .nodo circle { filter: drop-shadow(0 3px 8px rgba(0, 0, 0, .6)); }
#grafo .nodo text { paint-order: stroke; }
.mapa-hint {
  background: rgba(13, 17, 23, .82);
  border-color: var(--linea);
  border-radius: 3px;
  backdrop-filter: blur(6px);
}
.g-punto { box-shadow: 0 0 0 4px rgba(201, 160, 63, .14), 0 0 16px rgba(201, 160, 63, .35); }

/* ══════════════════════ 7 · SEMÁNTICA DEL TEMA ══════════════════════ */

/* ── .vivo · halo de cifra encendida ──────────────────────────────────
   Se cuelga de cualquier contenedor con una cifra que "está pasando".
   El halo se pinta en un ::after con z-index negativo: dentro del contexto
   de apilamiento que crea el propio .vivo, eso lo sitúa ENCIMA del fondo del
   elemento y DEBAJO de su texto — que es justo lo que hace falta para que
   funcione también sobre una tarjeta con fondo propio.
   Retinta con la clase de eje: .vivo.pipeline / .vivo.historico / … */
.vivo {
  position: relative;
  z-index: 0;
  --halo: var(--pipeline);
  text-shadow: 0 0 26px color-mix(in srgb, var(--halo) 40%, transparent);
}
.vivo::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -22% -14%;
  pointer-events: none;
  border-radius: 40%;
  background: radial-gradient(58% 108% at 50% 50%,
    color-mix(in srgb, var(--halo) 30%, transparent), transparent 72%);
  filter: blur(14px);
  animation: halo-late 5.4s ease-in-out infinite;
}
.vivo.pipeline { --halo: var(--pipeline); }
.vivo.historico { --halo: var(--historico); }
.vivo.alerta { --halo: var(--alerta); }
.vivo.exito { --halo: var(--exito); }
/* Un proceso cerrado no brilla: se apaga. */
.vivo.apagado { text-shadow: none; }
.vivo.apagado::after { display: none; }

@keyframes halo-late {
  0%, 100% { opacity: .62; transform: scale(.98); }
  50% { opacity: 1; transform: scale(1.03); }
}

/* ── Estados de proceso ───────────────────────────────────────────────
   El glifo de cabeza no es decoración: duplica en FORMA lo que el color
   dice, porque en deuteranopía el par alerta↔histórico queda a ΔE 7,0.
   Toda etiqueta lleva además su texto ("Vigente", "Cancelado"…). */
.estado-vigente, .estado-cancelado, .estado-adjudicado {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 9.5px;
  font-stretch: 78%;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 3px 9px;
  border: 1px solid;
  border-radius: 2px;
  white-space: nowrap;
  vertical-align: middle;
}
.estado-vigente::before, .estado-cancelado::before, .estado-adjudicado::before {
  font-size: 8px;
  line-height: 1;
}

.estado-vigente {
  color: var(--pipeline-txt);
  border-color: color-mix(in srgb, var(--pipeline) 45%, transparent);
  background: color-mix(in srgb, var(--pipeline) 13%, transparent);
  box-shadow: 0 0 22px -8px var(--pipeline);
}
.estado-vigente::before { content: "\25CF"; } /* ● */

.estado-adjudicado {
  color: var(--exito-txt);
  border-color: color-mix(in srgb, var(--exito) 45%, transparent);
  background: color-mix(in srgb, var(--exito) 13%, transparent);
}
.estado-adjudicado::before { content: "\25A0"; } /* ■ */

/* Cancelado: rojo, pero SIN luz. Lo que no ocurrió no puede brillar. */
.estado-cancelado {
  color: color-mix(in srgb, var(--alerta-txt) 78%, var(--texto3));
  border-color: color-mix(in srgb, var(--alerta) 34%, transparent);
  background: color-mix(in srgb, var(--alerta) 8%, transparent);
  box-shadow: none;
}
.estado-cancelado::before { content: "\25CB"; } /* ○ */

/* ── Cifras oficiales vs. estimaciones ────────────────────────────────
   Regla dura del proyecto: una estimación jamás puede tener el peso
   tipográfico de una cifra publicada. Aquí se separan por tres ejes a la
   vez —peso, color y el marcador `~`— para que la diferencia sobreviva a
   una captura en blanco y negro.
   OJO: el `~` lo pone el CSS. No lo escribas también en el HTML. */
.cifra-oficial {
  font-family: var(--mono);
  font-weight: 600;
  font-stretch: 78%;
  font-variant-numeric: tabular-nums;
  color: var(--texto);
  letter-spacing: -.01em;
}
.estimado {
  font-family: var(--mono);
  font-weight: 300;
  font-stretch: 78%;
  font-variant-numeric: tabular-nums;
  color: var(--gris2);
  letter-spacing: 0;
}
/* El `~` es información, no adorno: va al mismo nivel de contraste que la cifra. */
.estimado::before {
  content: "~";
  margin-right: .18em;
  color: var(--gris2);
  font-weight: 300;
}
/* El rótulo obligatorio que acompaña a todo bloque de estimaciones. */
.rotulo-estimacion {
  display: block;
  font-family: var(--mono);
  font-size: 9.5px;
  font-stretch: 78%;
  font-weight: 300;
  letter-spacing: .1em;
  text-transform: uppercase;
  /* Este rótulo es la salvaguarda del sitio: no puede quedar en el gris de
     adorno. Va en el gris que sí pasa AA a 9,5px. */
  color: var(--gris2);
  border-left: 1px solid var(--linea);
  padding-left: 9px;
  margin-top: 8px;
  line-height: 1.5;
}

/* Ejes del sitio: cian = prospectivo, ámbar = verificado. */
.eje-pipeline { color: var(--pipeline-txt); }
.eje-historico { color: var(--historico-txt); }

/* ══════════════════════ 8 · MOVIMIENTO CERO ══════════════════════ */
/* Contrato innegociable: con `reduce` no queda ni una animación en pie,
   ni las que este tema añade ni las que ya traía el sitio (.panel, #drawer,
   los hover de las barras). El contenido aparece completo y quieto. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .001ms !important;
    transition-delay: 0s !important;
  }
  html { scroll-behavior: auto !important; }
  body::after { opacity: 1 !important; animation: none !important; }
  .vivo::after { animation: none !important; opacity: .8 !important; transform: none !important; }
  .panel { animation: none !important; opacity: 1 !important; transform: none !important; }
}
