/* ===========================================================================
   KW — ILUSTRACIÓN
   ---------------------------------------------------------------------------
   Las clases del sprite `web/templates/_ilustraciones.svg`: escenas, gestos,
   estados del conector y marcadores del mapa.

   ⚠️ Por qué es un archivo aparte y no el final de `kw.css`: la ilustración es
   un JUEGO DE PIEZAS, no reglas de pantalla. La vitrina
   `static/marca/ilustraciones.html` se arma inyectando ESTE archivo entero
   —`web/tests/armar_ilustraciones.py`— así que documentar la ilustración no
   exige copiar nada a mano y la vitrina no puede quedar desfasada del código.
   Si esto viviera dentro de `kw.css` habría que recortarlo con una expresión
   regular, que es exactamente el tipo de espejo que se rompe en silencio.

   ⚠️ Ni un color a mano. Regla #1 de `.claude/skills/marca-kw`: un `#hex` acá
   queda mudo en uno de los dos temas, sin error y sin aviso. Los `--il-*` son
   una CAPA DE NOMBRES sobre `kw-tokens.css`: la ilustración pide «el trazo» o
   «el estado», nunca un azul. El día que cambie un token de marca, cambia acá
   sin tocar una sola `d=` del SVG.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   LAS ESCENAS
   --------------------------------------------------------------------------- */
.il{
  /* la capa de nombres */
  --il-trazo:var(--ink);
  --il-suave:var(--ink-3);
  --il-marca:var(--led);
  --il-cuerpo-fondo:var(--surface-2);
  --il-hueco:var(--surface-3);
  --il-vidrio-fondo:rgba(var(--led-rgb),.16);
  --il-piso-linea:var(--line);
  --il-estado:var(--led);

  --il-grosor:2.1;

  display:block;
  width:100%;
  height:auto;
  overflow:visible;
  fill:none;
  stroke-linecap:round;
  stroke-linejoin:round;
}

/* Las variantes de estado. Se ponen en el <svg> que hospeda el <use> y, como
   son variables CSS, bajan solas al shadow tree del símbolo.
   ⚠️ Un selector descendente NO entra a ese shadow tree: `.il.ok .il-insignia`
   no seleccionaría nada. Por eso todo lo que varía va por variable. */
.il.ok    { --il-estado:var(--ok);    }
.il.warn  { --il-estado:var(--warn);  }
.il.crit  { --il-estado:var(--crit);  }
/* `neutro` NO es un estado apagado: es «no sabemos». Existe porque «sin datos»
   no es «fuera de servicio», y pintarlo de rojo seria afirmar algo que no
   sabemos. Misma regla que ordena `clase()` en mapa.js. */
.il.neutro{ --il-estado:var(--ink-3); }

/* --------------------------------------------------------------- las piezas */
.il-cuerpo{
  fill:var(--il-cuerpo-fondo);
  stroke:var(--il-trazo);
  stroke-width:var(--il-grosor);
}
.il-vidrio{ fill:var(--il-vidrio-fondo); stroke:none; }
.il-linea{ stroke:var(--il-suave); stroke-width:1.5; }
.il-piso{ stroke:var(--il-piso-linea); stroke-width:2; }

/* El corte de la puerta va MÁS FINO que el resto de las líneas interiores. Al
   mismo grosor que la manija cruzaba el carro entero de techo a faldón y se
   leía como una grieta, no como una junta de chapa. */
.il-puerta{ stroke:var(--il-suave); stroke-width:1.1; opacity:.75; }

.il-rueda{
  fill:var(--il-hueco);
  stroke:var(--il-trazo);
  stroke-width:var(--il-grosor);
}
.il-llanta{ fill:none; stroke:var(--il-suave); stroke-width:1.5; }

.il-puerto,
.il-hueco-pieza{
  fill:var(--il-hueco);
  stroke:var(--il-trazo);
  stroke-width:1.7;
}

/* ---------------------------------------------------------------- el poste */
.il-pantalla{
  fill:var(--il-pantalla-fondo, rgba(var(--led-rgb),.18));
  stroke:var(--il-trazo);
  stroke-width:1.7;
}
.il-rayo{ stroke:var(--il-marca); stroke-width:2.1; }
.il-boca{
  fill:var(--il-hueco);
  stroke:var(--il-trazo);
  stroke-width:1.7;
}

/* Poste apagado: NO se repinta regla por regla, se le cambian DOS tokens y
   todo lo que dependa de ellos se apaga solo.
   ⚠️ Al principio solo cambiaba `--il-marca`, así que el rayo se apagaba pero
   la PANTALLA seguía con su fondo azul encendido: un cargador fuera de
   servicio con el display prendido. El azul del fondo no salía de un token
   sino de un `rgba(var(--led-rgb),…)` escrito en la regla, o sea que ninguna
   variante podía alcanzarlo. Por eso ahora pasa por `--il-pantalla-fondo`. */
.il-apagado{
  --il-marca:var(--il-suave);
  --il-pantalla-fondo:var(--il-hueco);
}

/* ---------------------------------------------------------------- el cable */
/* En oscuro el cable va gris claro y no blanco: blanco puro era lo más
   brillante del dibujo y se robaba la mirada del carro. */
.il-cable{ stroke:var(--il-cable, var(--il-trazo)); stroke-width:3.4; }
:root[data-tema="oscuro"]{ --il-cable:var(--ink-3); }

/* El arco de energía: un guion que recorre el cable. Es lo ÚNICO que se mueve
   en toda la ilustración — si se mueve algo más, la pantalla parece un juego
   en vez de una app que está cobrando plata. */
.il-flujo{
  stroke:var(--il-marca);
  stroke-width:3.4;
  opacity:var(--il-flujo-op, 1);
  animation:il-correr 1.5s linear infinite;
  stroke-dasharray:9 26;
}
@keyframes il-correr{ to{ stroke-dashoffset:-35; } }

@media (prefers-reduced-motion:reduce){
  /* ⚠️ Con la variable, no un `.9` fijo: el fijo pisaba `il-quieto` y, con
     movimiento reducido, un cable SIN energía (terminada) salía como cargando. */
  .il-flujo{ animation:none; stroke-dasharray:none; opacity:calc(var(--il-flujo-op, 1) * .9); }
}

/* Un cable conectado pero SIN energía. No es otro cable: es el mismo apagado.
   Va como variable y no como `.il-quieto .il-flujo{…}` por lo del shadow tree. */
.il-quieto{ --il-flujo-op:0; }

/* ---------------------------------------------------------------- el gesto */
.il-guia{
  stroke:var(--il-marca);
  stroke-width:2.1;
  stroke-dasharray:5 5;
}
.il-guia-punta{ stroke:var(--il-marca); stroke-width:2.1; fill:none; }

/* La diana sobre la tapa de carga: el destino del gesto. Sin ella el conector
   y el carro son dos objetos sueltos; con ella son una instrucción. */
.il-diana{
  fill:none;
  stroke:var(--il-marca);
  stroke-width:1.7;
  stroke-dasharray:3 4.5;
  opacity:.9;
}

/* -------------------------------------------------------------- la insignia
   ⚠️⚠️ ESTE ES EL CASO PELIGROSO DE TODO EL ARCHIVO. Es un círculo RELLENO con
   el color semántico y un glifo encima. En OSCURO los semánticos son CLAROS
   (`--ok` es #3DD68C, pensado como tinta sobre negro): un glifo blanco encima
   daría 1,9:1 y se vería como un círculo verde vacío — exactamente la trampa
   de `.vivo` y `.perf-av` que ya mordió dos veces (`marca-kw §1`).

   El glifo va con `--ground`, el fondo de la página: en oscuro es casi negro,
   en claro es blanco. O sea que SIEMPRE está en el extremo opuesto del
   semántico de ese mismo tema. Es el único token que se autocorrige. */
.il-insignia-fondo{ fill:var(--il-estado); stroke:none; }
.il-insignia-trazo{
  fill:none;
  stroke:var(--ground);
  stroke-width:2.6;
}
.il-insignia-punto{ fill:var(--ground); stroke:none; }

/* --------------------------- el carro y el cargador MODERNOS (2026-10-27)
   «Esos carros tan horribles… como hechos con plastilina.» Superficies con
   degradado y filo fino en vez de contorno grueso; vidrio oscuro; luces LED
   del color de la fase. Los degradados están en el sprite (`#il-g-*`) y sus
   colores, acá, por TEMA: en claro un carro perla, en oscuro uno grafito.
   ⚠️ Todo sale de tokens de `kw-tokens.css`; ni un color escrito a mano. */
:root{
  --il-chapa-1:var(--ground);   --il-chapa-2:var(--surface-3);
  --il-cristal-1:var(--deep-2); --il-cristal-2:var(--deep);
  --il-rin-1:var(--ground);     --il-rin-2:var(--ink-eco);
  --il-negro:var(--ink);        --il-pieza:var(--ink-2);
  --il-filo:var(--ink-3);       --il-brillo:var(--ground);
  --il-brillo-op:.95;           --il-sombra:var(--ink);   --il-sombra-op:.12;
  --il-goma-borde:transparent;
  /* la pintura del carro: azul de la marca, más claro arriba (la luz) */
  --il-pintura-1:color-mix(in srgb,var(--led) 62%,var(--ground));
  --il-pintura-2:var(--led);
  --il-pintura-brillo:var(--ground);
  --il-led-nucleo:var(--ground);
  --il-otro-1:var(--ink-eco);   --il-otro-2:var(--ink-3);
  /* Los colores de ESTADO del dibujo: el sólido (insignia, batería, con su
     símbolo encima) y la LUZ (aura, piso, luces, flujo). En claro, la luz sale
     de los pines del mapa, que son vivos a propósito: el verde de texto
     (`--ok`, #0B6B3C) es oscuro para que se lea, y como luz se veía apagado.
     Así el mapa y los dibujos dicen «libre» con el mismo verde. */
  --il-ok:var(--pin-libre);     --il-ok-luz:var(--pin-libre-brillo);
  --il-warn:var(--pin-ocupado); --il-warn-luz:var(--pin-ocupado);
  --il-crit:var(--crit);        --il-crit-luz:var(--pin-fuera);
}
:root[data-tema="oscuro"]{
  --il-chapa-1:var(--ink-eco);  --il-chapa-2:var(--surface-2);
  --il-cristal-1:var(--deep-2); --il-cristal-2:var(--ground);
  --il-rin-1:var(--ink-2);      --il-rin-2:var(--ink-eco);
  --il-negro:var(--ground);     --il-pieza:var(--ink-eco);
  --il-filo:var(--ink-3);       --il-brillo:var(--ink-2);
  --il-brillo-op:.3;            --il-sombra:var(--ground); --il-sombra-op:.85;
  --il-goma-borde:var(--ink-eco);
  --il-pintura-1:var(--led);
  --il-pintura-2:color-mix(in srgb,var(--led) 70%,var(--deep));
  --il-pintura-brillo:var(--ink);
  --il-led-nucleo:var(--ink);
  --il-otro-1:var(--ink-3);     --il-otro-2:var(--surface-3);
  --il-ok:var(--ok);            --il-ok-luz:var(--ok);
  --il-warn:var(--warn);        --il-warn-luz:var(--warn);
  --il-crit:var(--crit);        --il-crit-luz:var(--crit);
}
.il-g-chapa-1{ stop-color:var(--il-chapa-1); }
.il-g-chapa-2{ stop-color:var(--il-chapa-2); }
.il-g-cristal-1{ stop-color:var(--il-cristal-1); }
.il-g-cristal-2{ stop-color:var(--il-cristal-2); }
.il-g-rin-1{ stop-color:var(--il-rin-1); }
.il-g-rin-2{ stop-color:var(--il-rin-2); }
.il-chapa{ fill:url(#il-g-chapa); stroke:var(--il-filo); stroke-opacity:.45; stroke-width:.9; }
.il-cristal{ fill:url(#il-g-cristal); stroke:none; }
.il-reflejo{ fill:var(--il-brillo); opacity:.16; stroke:none; }
.il-pilar{ fill:none; stroke:var(--il-filo); stroke-opacity:.45; stroke-width:1.6; }
.il-veta{ fill:none; stroke:var(--il-brillo); stroke-opacity:var(--il-brillo-op); stroke-width:1.1;
  stroke-linecap:round; }
.il-junta{ fill:none; stroke:var(--il-filo); stroke-opacity:.4; stroke-width:.8; }
.il-manija{ fill:var(--il-filo); opacity:.55; stroke:none; }
.il-negro{ fill:var(--il-negro); stroke:none; }
.il-pieza{ fill:var(--il-pieza); stroke:none; }
.il-goma{ stroke:var(--il-goma-borde); stroke-width:1; }
.il-rin{ fill:url(#il-g-rin); stroke:none; }
.il-rayos{ fill:none; stroke:var(--il-negro); stroke-width:1.8; stroke-linecap:round; opacity:.8; }
.il-tuerca{ fill:var(--il-rin-1); stroke:none; }
.il-led{ fill:none; stroke:var(--il-marca); stroke-width:2.2; stroke-linecap:round; }
.il-led-halo{ fill:none; stroke:var(--il-marca); stroke-width:6.5; stroke-linecap:round; opacity:.3; }
/* el núcleo casi blanco es lo que hace que una luz BRILLE y no sea una raya de color */
.il-led-nucleo{ fill:none; stroke:var(--il-led-nucleo); stroke-width:.8; stroke-linecap:round; opacity:.85; }
.il-g-pintura-1{ stop-color:var(--il-pintura-1); }
.il-g-pintura-2{ stop-color:var(--il-pintura-2); }
.il-g-otro-1{ stop-color:var(--il-otro-1); }
.il-g-otro-2{ stop-color:var(--il-otro-2); }
/* El carro: perla o grafito (la chapa), y el de OTRA persona en gris. */
.il-carro{ fill:var(--il-carro-relleno, url(#il-g-chapa)); stroke:var(--il-filo);
  stroke-opacity:.45; stroke-width:.9; }
.il-pintura{ fill:url(#il-g-pintura); stroke:var(--deep); stroke-opacity:.5; stroke-width:.9; }
.il-veta-pintura{ stroke:var(--il-pintura-brillo); stroke-opacity:.6; stroke-width:1.2; }
.il-junta-pintura{ stroke:var(--deep-2); stroke-opacity:.4; }
.il-manija-pintura{ fill:var(--il-pintura-brillo); opacity:.6; }
.il-pinza{ fill:none; stroke:var(--il-marca); stroke-width:2.4; stroke-linecap:round; }
.il-bahia{ fill:var(--il-luz, var(--il-estado)); opacity:.24; stroke:none; }
.il-bahia-linea{ fill:none; stroke:var(--il-luz, var(--il-estado)); stroke-width:2; stroke-linecap:round; opacity:.75; }
/* ⭐ EL COLOR DE CADA ESTADO (2026-10-27: «no veo las diferencias en cada
   carro… era más verde cuando se conectaba»). Cada escena trae su tono adentro,
   así que se distingue sola, en cualquier pantalla. */
.il-tono-marca{ --il-marca:var(--led); --il-estado:var(--led); --il-luz:var(--led); }
.il-tono-ok   { --il-marca:var(--il-ok-luz); --il-estado:var(--il-ok); --il-luz:var(--il-ok-luz); }
.il-tono-warn { --il-marca:var(--il-warn-luz); --il-estado:var(--il-warn); --il-luz:var(--il-warn-luz); }
.il-tono-crit { --il-estado:var(--il-crit); --il-luz:var(--il-crit-luz); }
.il-tono-neutro{ --il-estado:var(--ink-3); --il-luz:var(--ink-3); }
/* el carro de OTRA persona (ocupado): gris, no el azul de «el suyo» */
.il-otro{ --il-carro-relleno:url(#il-g-otro); }
/* EL AURA del carro: se prende por escena. `@property` le da el 0 por omisión
   (apagada) a los carros que no la prenden. */
@property --il-aura-op{ syntax:'<number>'; inherits:true; initial-value:0; }
.il-aura{ fill:none; stroke:var(--il-luz, var(--il-estado)); stroke-width:7; stroke-linejoin:round;
  opacity:var(--il-aura-op); }
.il-bajo{ fill:none; stroke:var(--il-luz, var(--il-estado)); stroke-width:3.2; stroke-linecap:round;
  opacity:calc(var(--il-aura-op) * 1.5); }
.il-aura-si{ --il-aura-op:.42; }
/* ⚠️ QUIETA (2026-11-02). Latía animando la VARIABLE, que hereda todo el dibujo del
   carro y del poste: el navegador recalculaba y repintaba la escena entera en cada
   cuadro, la animación más cara de la app, y en la pantalla que se mira mientras
   carga. Lo que está vivo ya lo dicen la energía que corre por el cable, las ondas
   del piso y el cometa del anillo. La clase se queda para no tocar el dibujo. */
.il-aura-late{ --il-aura-op:.42; }
/* la batería sobre el techo */
.il-bateria{ fill:var(--il-chapa-1); stroke:var(--il-filo); stroke-opacity:.7; stroke-width:1.3; }
.il-bateria-polo{ fill:var(--il-filo); stroke:none; }
.il-bateria-carga{ fill:var(--il-estado); stroke:none; }
.il-bateria-punta{ animation:il-senal 1.6s ease-in-out infinite; }
.il-bateria-rayo{ fill:var(--ground); stroke:none; }
.il-insignia-relleno{ fill:var(--ground); stroke:none; }
/* el conector que se ACERCA al carro (el gemelo de `il-sale`). ⚠️ TRES veces y
   quieto (2026-11-02): latía sin fin en la pantalla de pagar, mientras la persona lee
   montos y textos de dinero. Tres vueltas enseñan el gesto; después estorban. */
.il-acerca{ animation:il-acerca 2.2s cubic-bezier(.45,0,.25,1) 3; }
@keyframes il-acerca{ 0%,15%{ transform:translateX(0); } 55%,80%{ transform:translateX(6px); }
  100%{ transform:translateX(0); } }
@media (prefers-reduced-motion:reduce){
  .il-aura-late,.il-bateria-punta,.il-acerca{ animation:none; }
}
/* Los vacíos y los errores (`vc-*`, 2026-10-28) */
.vc-fantasma{ fill:none; stroke:var(--il-filo); stroke-width:1.6; stroke-dasharray:4 4;
  stroke-linecap:round; opacity:.6; vector-effect:non-scaling-stroke; }
.vc-renglon{ fill:none; stroke:var(--il-filo); stroke-width:2.4; stroke-linecap:round; opacity:.35; }
.vc-troquel{ fill:none; stroke:var(--il-filo); stroke-width:1.6; stroke-dasharray:3 3.4;
  opacity:.55; }
.vc-eslabon{ fill:none; stroke:var(--il-filo); stroke-width:6.5; opacity:.8; }
.vc-marca-estado{ fill:none; stroke:var(--il-estado); stroke-width:6; stroke-linecap:round;
  stroke-linejoin:round; }
.vc-blanco{ fill:var(--il-pintura-brillo); opacity:.92; stroke:none; }
.vc-modulo{ fill:var(--led); stroke:none; }
.vc-chispa{ fill:none; stroke:var(--il-luz, var(--il-estado)); stroke-width:2.4; stroke-linecap:round; }
.vc-chico{ stroke-width:2.2; }
/* ⭐ MOVIMIENTO, SOMBRAS Y CONTORNOS (2026-10-28: «genere los efectos,
   movimientos, contornos, sombras, animaciones… como un senior»).
   Las reglas: el movimiento DICE algo (energía, espera, error, «todavía no»),
   es corto o muy lento —nunca rápido y en bucle—, una cosa a la vez por
   escena, y con `prefers-reduced-motion` se apaga y el dibujo queda quieto y
   legible. Dentro de un `<symbol>`: `transform-box:fill-box` para girar o
   escalar desde la pieza, o `view-box` con el origen en coordenadas del
   dibujo; y lo que tiene que latir a través del `<use>` va por VARIABLE
   (`--il-aura-op`), porque los selectores no cruzan esa frontera. */

/* las insignias con volumen: sombra de contacto abajo y brillo arriba */
.il-insignia-sombra{ fill:var(--il-sombra); opacity:calc(var(--il-sombra-op) * 1.6); stroke:none; }
.il-insignia-brillo{ fill:none; stroke:var(--il-led-nucleo); stroke-width:1.6; stroke-linecap:round;
  opacity:.4; }
/* el visto se dibuja al aparecer */
.il-dibuja{ stroke-dasharray:1; stroke-dashoffset:1; animation:il-dibuja .5s cubic-bezier(.65,0,.35,1) .35s forwards; }
@keyframes il-dibuja{ to{ stroke-dashoffset:0; } }
/* la manecilla del reloj gira: esperar es esperar */
.il-manecilla{ transform-box:view-box; transform-origin:248px 24px; animation:il-gira 6s linear infinite; }
@keyframes il-gira{ to{ transform:rotate(360deg); } }
/* las luces del carro y del cargador se encienden con el aura (cargando, iniciando) */
.il-led-halo{ opacity:calc(.3 + var(--il-aura-op, 0) * .9); }
/* la onda en el piso mientras carga: la energía sale del cargador */
.il-onda{ fill:none; stroke:var(--il-luz, var(--il-estado)); stroke-width:1.4; opacity:0;
  transform-box:fill-box; transform-origin:center; animation:il-onda 2.6s ease-out infinite; }
.il-onda-2{ animation-delay:1.3s; }
@keyframes il-onda{ 0%{ transform:scale(.55); opacity:.6; } 100%{ transform:scale(1.12); opacity:0; } }
/* la batería se llena al aparecer */
.il-bateria-carga{ transform-box:fill-box; transform-origin:left center;
  animation:il-llena .9s cubic-bezier(.22,1,.36,1) .15s both; }
.il-bateria-punta{ animation:il-llena .9s cubic-bezier(.22,1,.36,1) .15s both,
  il-senal 1.6s ease-in-out 1.1s infinite; }
@keyframes il-llena{ from{ transform:scaleX(0); } to{ transform:scaleX(1); } }
/* la tarjeta rechazada tiembla UNA vez */
.il-sacude{ animation:il-sacude .5s cubic-bezier(.36,.07,.19,.97) .25s both; }
@keyframes il-sacude{ 15%,85%{ transform:translateX(-2px); } 30%,70%{ transform:translateX(3.5px); }
  45%,55%{ transform:translateX(-3.5px); } 100%{ transform:none; } }
/* la diana de «conecte» late: ahí va el conector */
.il-diana-late{ transform-box:fill-box; transform-origin:center; animation:il-diana 1.8s ease-in-out 3; }
@keyframes il-diana{ 50%{ transform:scale(1.18); opacity:.45; } }
/* el brillo del techo, más tenue que el del hombro */
.il-veta-techo{ stroke-opacity:calc(var(--il-brillo-op) * .7); }
/* ⚠️ LOS DIBUJOS DE LOS VACÍOS, QUIETOS (2-nov-2026, agente C). Flotaban sin
   parar (4,2 s) y la campana se mecía cada 5 s: un vacío no está vivo ni cargando,
   y lo que se mueve solo sin un estado que lo justifique delata una pantalla hecha
   de afán (pulir-pantallas, animar.md §3-bis: bucle infinito → quieto). Las clases
   se quedan porque el sprite las usa; solo dejan de moverse. */
.il-flota,.il-flota-sombra,.il-campana{ animation:none; }
@media (prefers-reduced-motion:reduce){
  .il-dibuja{ animation:none; stroke-dashoffset:0; }
  .il-manecilla,.il-onda,.il-bateria-carga,.il-bateria-punta,.il-sacude,.il-diana-late,
  .il-flota,.il-flota-sombra,.il-campana{ animation:none; }
  .il-onda{ display:none; }
}

/* el flujo del cable con su resplandor: misma animación, más ancho y tenue */
.il-flujo-halo{ stroke-width:8; opacity:calc(var(--il-flujo-op, 1) * .25); }
.il-sombra{ fill:var(--il-sombra); opacity:var(--il-sombra-op); stroke:none; }

/* ------------------------------------- las escenas de la carga (2026-10-27)
   INICIANDO: tres ondas que se encienden en orden, de adentro hacia afuera,
   como el «buscando señal» de un teléfono. DESCONECTAR: el conector se aleja
   del carro y vuelve. TERMINADA: el sello entra con un rebote corto.
   ⚠️ Solo `opacity` y `transform` dentro del símbolo, nada que cambie la
   geometría: el `<use>` clona y el clon hereda la animación. */
.il-senal{ fill:none; stroke:var(--il-marca); stroke-width:2.2; opacity:.18;
  animation:il-senal 1.8s ease-in-out infinite; }
.il-senal-2{ animation-delay:.25s; }
.il-senal-3{ animation-delay:.5s; }
.il-senal-punto{ fill:var(--il-marca); stroke:none; }
@keyframes il-senal{ 0%,100%{ opacity:.18; } 35%{ opacity:1; } 70%{ opacity:.18; } }
.il-sale{ animation:il-sale 2.2s cubic-bezier(.45,0,.25,1) 3; }   /* tres veces, como su gemelo `il-acerca` */
@keyframes il-sale{ 0%,15%{ transform:translateX(0); } 55%,80%{ transform:translateX(-6px); }
  100%{ transform:translateX(0); } }
.il-sello{ transform-box:fill-box; transform-origin:center;
  animation:il-sello .42s cubic-bezier(.34,1.56,.64,1) both .15s; }
@keyframes il-sello{ from{ transform:scale(.3); opacity:0; } to{ transform:scale(1); opacity:1; } }
@media (prefers-reduced-motion:reduce){
  .il-senal{ animation:none; opacity:.85; }
  .il-sale,.il-sello{ animation:none; }
}

/* ===========================================================================
   LOS MARCADORES DEL MAPA
   ---------------------------------------------------------------------------
   ⚠️⚠️ ESTOS NO SIGUEN EL TEMA DE LA APP, y es a propósito. `kw-tokens.css`
   deja los `--pin-*` FUERA del bloque claro: el pin se tiene que despegar de
   la TESELA, y la tesela la elige la persona en el selector de capas de
   Leaflet (`body.fondo-claro`), que es una cosa distinta del tema de la app.
   Un pin que se aclara cuando la app se aclara desaparece sobre un mapa claro.

   El pin tiene TRES RANURAS y no más (`referencias-kw/references/
   patrones-de-interfaz.md`): color del cuerpo = DISPONIBILIDAD, número
   adentro = cuántos conectores, insignia encima = fuera de servicio.
   =========================================================================== */
.mk{
  display:block;
  overflow:visible;
  fill:none;
  stroke-linecap:round;
  stroke-linejoin:round;
  /* ⚠️ SIN `--mk-color` aquí (quitado el 2026-11-02). Estaba declarada en `.mk` y PISABA la que
     hereda del padre: `mapa.js` pinta `<svg class="mk">` sin clase de estado y el estado lo pone
     `.mapa-pin.fuera` / `.kwcl-*` (kw.css). Con la declaración aquí, TODO pin salía verde: un punto
     fuera de servicio se veía igual que uno con cupo (revisión de diseño, grave B1). El verde queda
     como respaldo donde se usa (`.mk-cuerpo`), y las clases de abajo siguen sirviendo cuando el
     estado va en el propio svg (la hoja de `armar_ilustraciones.py`). */
}
.mk.libre    { --mk-color:var(--pin-libre);    }
.mk.ocupado  { --mk-color:var(--pin-ocupado);  }
.mk.fuera    { --mk-color:var(--pin-fuera);    }
.mk.sindatos { --mk-color:var(--pin-sindatos); }

.mk-cuerpo{
  fill:var(--mk-color, var(--pin-libre));
  stroke:var(--mk-borde, var(--mapa-pin-borde));
  stroke-width:2;
  /* El pin «sin datos» va con el halo PUNTEADO. Dice «esto está incompleto»
     sin gastar la insignia de encima, que queda libre para «fuera de
     servicio». Era `border-style:dashed` cuando el pin era un div. */
  stroke-dasharray:var(--mk-guion, none);
}
.mk-insignia{ fill:var(--pin-fuera); stroke:var(--mapa-pin-borde); stroke-width:1.6; }
.mk-insignia-trazo{ fill:none; stroke:var(--mapa-pin-borde); stroke-width:1.8; }

/* El anillo del pin suelto: MISMO mecanismo que `.mk-grupo-riel`/`.mk-grupo-anillo`
   (pathLength="100", así que el porcentaje entra directo por `--mk-libres`), pero
   en blanco translúcido en vez de gris — el riel gris de `#mk-grupo` se apoya en un
   cuerpo azul constante; acá el cuerpo CAMBIA de color por estado (incluido el
   gris de «sin datos», donde un riel gris se volvería invisible). El blanco
   funciona sobre los cuatro tonos de estado por la misma razón que el número de
   adentro ya es blanco: `kw.css` los oscureció justo para que un blanco encima
   se lea. */
.mk-pin-riel{
  fill:none;
  stroke:rgba(255,255,255,.32);
  stroke-width:3;
  /* «Sin datos» dice lo mismo acá que en el globo: el riel PUNTEADO es la
     diferencia entre «cero libres» (riel entero) y «no sabemos» (riel a
     guiones). Lo activa `.mapa-pin.sindatos` con `--mk-pin-riel-guion`. */
  stroke-dasharray:var(--mk-pin-riel-guion, none);
}
.mk-pin-anillo{
  fill:none;
  stroke:var(--pin-libre-brillo);
  stroke-width:3;
  /* `butt`, no `round`: con remate redondo un arco de 0 % igual pinta un punto,
     y ese es justo el caso («ocupado» u «sin datos») donde el anillo tiene que
     quedarse callado. Mismo razonamiento que `.mk-grupo-anillo`. */
  stroke-linecap:butt;
  stroke-dasharray:var(--mk-libres, 0) 100;
}

/* ------------------------------------------------------------- el agrupado
   ✅ El anillo se adopta de EVX por decisión del estudio: hoy el globo
   agrupado de KW dice «3 puntos» pero NO dice cuántos están libres, que es
   justo lo que se pregunta antes de manejar hasta allá. */

/* ⚠️⚠️ EL CUERPO DEL GLOBO NO LLEVA LA DISPONIBILIDAD — la lleva el anillo.
   Estaba en verde (`--mk-color`) y el resultado era un grupo con CERO
   conectores libres pintado de verde: el relleno decía «disponible» y el
   anillo decía «ninguno», y de lejos gana el relleno, que es el 90 % de la
   tinta. Va en `--deep`, el azul profundo de marca, que además vale igual en
   los dos temas y por lo tanto es seguro sobre teselas. */
.mk-grupo-fondo{
  fill:var(--pin-grupo);
  /* `--mk-borde` deja que el mapa cambie el halo sin tocar esta regla: sobre
     teselas claras el blanco se pierde y `body.fondo-claro` lo oscurece. */
  stroke:var(--mk-borde, var(--mapa-pin-borde));
  stroke-width:2;
}
/* El riel es la porción NO disponible; el anillo, la disponible. Juntos dicen
   «cuántos de cuántos» sin una sola cifra extra — un donut de dos colores, no
   un progreso contra un fondo neutro.
   ⚠️ Antes el riel era gris translúcido siempre, «lo que falta» sin decir por
   qué falta. El negocio pidió que lo ocupado se viera de OTRO color, no como
   telón de fondo del verde: ahora el riel es `--pin-ocupado` (el mismo ámbar
   del pin individual «ocupado») por defecto.
   El riel PUNTEADO sigue siendo aparte: «cero libres, confirmado» (riel ámbar
   entero) y «no sabemos» (riel gris a guiones) se verían IGUAL si los dos
   fueran ámbar sin más, y no son lo mismo. `.kwcl-sindatos` cambia el COLOR
   del riel a gris además del guion, con `--mk-riel-color` — tiene que ir en
   variable y no en un selector anidado tipo `.kwcl-sindatos .mk-grupo-riel`
   porque el anillo vive en el shadow tree que crea `<use>`, donde un selector
   descendente no entra pero una variable heredada sí (mismo aviso de arriba). */
.mk-grupo-riel{
  fill:none;
  stroke:var(--mk-riel-color, var(--pin-ocupado));
  stroke-width:4;
  opacity:.85;
  stroke-dasharray:var(--mk-riel-guion, none);
}
.mk-grupo-anillo{
  fill:none;
  stroke:var(--pin-libre);
  stroke-width:4;
  /* ⚠️ `butt`, NO `round`. Con remate redondo un guion de longitud CERO igual
     pinta su remate: el grupo con 0 libres mostraba un punto verde, o sea que
     el único caso en que el anillo tenía que callarse era justo el que
     hablaba. Con `butt`, 0 % no dibuja nada. */
  stroke-linecap:butt;
  /* En centésimas del perímetro, gracias a `pathLength="100"` en el símbolo:
     con eso `--mk-libres:60` es literalmente «60 % libres» y nadie calcula
     2·π·r. Si algún día cambia el radio, el anillo sigue solo. */
  stroke-dasharray:var(--mk-libres, 60) 100;
}

/* ===========================================================================
   LOS GESTOS
   Lo que la persona TIENE QUE HACER, no lo que pasó.
   =========================================================================== */
.ge{
  display:block;
  fill:none;
  stroke-linecap:round;
  stroke-linejoin:round;
  --il-trazo:var(--ink);
  --il-marca:var(--led);
}
.ge-trazo  { stroke:var(--il-trazo); stroke-width:1.9; fill:none; }
.ge-marca  { stroke:var(--il-marca); stroke-width:1.9; fill:none; }
/* Los cuatro pasos de «Así se carga» (2026-10-27): rellenos de color. */
.ge-cable{ fill:none; stroke:var(--il-pieza); stroke-width:2.6; stroke-linecap:round; }
.ge-pantalla{ fill:var(--surface); stroke:none; }
.ge-luz{ fill:none; stroke:var(--il-marca); stroke-width:1.8; stroke-linecap:round; }
.ge-luz-halo{ fill:none; stroke:var(--il-marca); stroke-width:5; stroke-linecap:round; opacity:.25; }
.ge-banda{ fill:var(--deep-2); opacity:.55; stroke:none; }
.ge-chip{ fill:var(--il-pintura-brillo); opacity:.85; stroke:none; }
.ge-ondas{ fill:none; stroke:var(--il-pintura-brillo); stroke-width:1.6; stroke-linecap:round; opacity:.9; }
.ge-lleno{ fill:var(--ok); stroke:none; }
.ge-visto{ fill:none; stroke:var(--ground); stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; }
.ge-relleno{ fill:var(--il-marca); stroke:none; }
/* los cuadritos del QR: son <rect>, van rellenos y sin trazo */
.ge-marca[x]{ fill:var(--il-marca); stroke:none; }

/* ===========================================================================
   LOS ESTADOS DEL CONECTOR
   Uno por cada valor de `ConnectorStatus` — los DIEZ, no los cuatro que se
   suelen dibujar. `PREPARING` y los dos `SUSPENDED_*` son estados normalísimos
   del ciclo de StatusNotification de OCPP 1.6; sin ícono propio terminan
   cayendo todos en «cargando», que es mentira, o en «falla», que es peor.

   El color va por FAMILIA, no uno por estado: diez colores no se aprenden.
   =========================================================================== */
.es{
  display:block;
  fill:none;
  stroke-linecap:round;
  stroke-linejoin:round;
  --il-estado:var(--led);
}
.es.ok    { --il-estado:var(--ok);    }
.es.warn  { --il-estado:var(--warn);  }
.es.crit  { --il-estado:var(--crit);  }
.es.neutro{ --il-estado:var(--ink-3); }

/* ⚠️ DENTRO DE UNA PASTILLA el ícono NO elige color: hereda el de la pastilla.
   Los colores de `.pill.ok/.warn/.crit/.gris/.info` están MEDIDOS en contraste
   contra su propio fondo teñido, en los dos temas — la `.pill.ok` se pinta con
   `rgba(--ok-rgb,.09)` encima de la superficie y ahí el texto queda más cerca
   del fondo justo donde es más chico. Un ícono que pidiera `var(--ok)` por su
   cuenta se saldría de esa medición sin que nada avise. Es el mismo gesto que
   ya hace `.dot` con `background:currentColor`. */
.pill .es{ --il-estado:currentColor; flex:none; }

.es-trazo{ fill:none; stroke:var(--il-estado); stroke-width:1.8; }
.es-relleno{ fill:var(--il-estado); stroke:none; }
.es-relleno-trazo{
  fill:var(--il-estado);
  stroke:var(--il-estado);
  stroke-width:1.6;
}
.es-punteado{ stroke-dasharray:3 3.2; }
