/* ==========================================================
   SIMULADOR DE COBERTURA CCTV — CHIA
   Interfaz clara sobre la paleta de ZW Comunicaciones:
   dorado #E8B118, gris #4E4E4C y blanco. Los colores que se
   agregan (verde, rojo, azul acero, ciruela) son funcionales
   —estado y niveles de norma— y están escogidos para
   complementar la marca, no para competir con ella.
   Todo el color sale de las variables de :root.
   ========================================================== */
:root{
  /* ---- marca ---- */
  --marca:#E8B118;          /* dorado ZW */
  --marca-2:#C9970F;        /* dorado oscuro para bordes y estados activos */
  --marca-txt:#8A6508;      /* dorado legible como texto sobre blanco */
  --marca-suave:#FBF0D4;    /* fondo dorado muy claro */
  --gris:#4E4E4C;           /* gris ZW */
  /* Extremos del degradado de #topbar y #cabecera. Son GRAFITO CON MATIZ FRÍO y
     no el oliva de la marca, y es deliberado: el dorado #E8B118 sobre un oliva
     medio-oscuro se apaga —son vecinos de tono— mientras que sobre un frío
     profundo salta. La barra deja de leerse como barro y el filete dorado de
     abajo, que es lo que dice "esto es de ZW", por fin se ve.
     El gris de marca --gris no se toca: sigue siendo el color de la identidad y
     el que se usa en texto, iconos y equipos existentes. Esto es sólo el fondo
     de una franja, y un fondo no es la marca. */
  --gris-hondo:#1C2027;     /* grafito hondo: tinta de los documentos (css/reporte.css) */
  --gris-alto:#2E343F;      /* extremo claro del mismo grafito */

  /* ---- franja de cabecera (17/08/2026) ----
     El grafito frío cumplía —el dorado saltaba encima— pero era gris, y un gris
     oscuro de ancho completo es lo que trae cualquier plantilla. Esto es VERDE
     PETRÓLEO: el complemento del dorado en el círculo de color, así que el filete
     de --marca de abajo y el botón dorado sin sesión llegan a su máximo contraste
     de tono, no sólo de luz. Y sigue siendo oscuro y sobrio, que es lo que pide
     una barra de trabajo que se mira ocho horas.
     Por qué tokens propios y no cambiar --gris-hondo: ese grafito es la TINTA de
     los documentos (--doc-tinta-2 en css/reporte.css). Teñir la barra no puede
     teñir el acta impresa, así que son dos cosas con dos nombres.
     Las usan #topbar (aquí) y #cabecera (css/admin.css): las dos pantallas son
     gemelas y se cambian de un solo sitio. */
  --barra-alto:#17454B;     /* extremo claro: petróleo medio */
  --barra-hondo:#0B2429;    /* extremo hondo: casi negro verdoso */

  /* ---- superficies ----
     La rampa no es gris neutro: lleva una gota de la calidez del dorado. Un
     gris puro al lado de la marca se ve azulado y apagado, y es lo que hace
     que una interfaz parezca una plantilla sin dueño. Son dos o tres puntos
     de diferencia por canal, no se ven de frente, pero el conjunto se siente
     de una sola pieza.
     --bg es la superficie que flota (tarjetas, barras); --lienzo es el fondo
     sobre el que flota. La regla ya estaba escrita en la sesión anterior pero
     no se ejecutaba: --bg #FFFFFF contra el --lienzo viejo (#F4F3EF) daba
     1,11:1 de contraste de superficie, así que las tarjetas no flotaban solas
     y toda la profundidad la cargaban las sombras. Ahora 1,26:1. */
  --bg:#FFFFFF;
  --bg-2:#FAF8F3;           /* nuevo: fila alterna y hover dentro de una tarjeta, un peldaño
                                entre --bg y --lienzo, no un segundo fondo */
  --lienzo:#E9E5DC;
  --panel:#F8F6F1;
  /* --panel-2 y --panel-3 son relleno de control (segmentados, chips inactivos, tarjeta
     elegida). Antes estaban a 1,06:1 y 1,11:1 de su fondo: un relleno tan cerca del fondo no
     se lee como una pieza, se lee como una mancha. Ahora 1,35:1 y 1,57:1. */
  --panel-2:#E3DED2;
  --panel-3:#D5CEBC;
  --line:#D8D1C1;
  --line-2:#9A9079;         /* antes 1,9:1 contra su fondo, por debajo del mínimo AA de 3:1
                                para borde de componente. Ahora 3,16:1 */

  /* ---- texto ---- */
  --text:#26251F;
  --muted:#625F55;          /* 5,1:1 sobre --lienzo */
  --muted-2:#726E60;        /* antes no cumplía AA como texto (3,55:1 sobre blanco). Ahora
                                5,1:1, pero SÓLO sobre --bg y --panel: sobre --lienzo o
                                --panel-2 el contraste vuelve a caer por debajo de 4,5:1, así
                                que no se usa ahí */

  /* ---- colores funcionales ---- */
  --ok:#2F7A4C;             /* 5,2:1 */
  --alerta:#C0392B;
  --pend:#C97A15;           /* antes era literalmente el mismo píxel que --marca (#E8B118):
                                "cámara nueva propuesta", "verificación por confirmar" y
                                "Observación · 62 px/m" (--dori-3) se pintaban idénticos y el
                                dorado significaba tres cosas a la vez. Se desata del dorado */
  --pend-txt:#8A4B00;       /* nuevo: texto legible de estado "pendiente" sobre --warn-bg */
  --ptz:#4A6488;            /* azul acero: cabezales PTZ */
  --ptz-bg:#E9EEF5;         /* nuevo: fondo derivado para chips/etiquetas de PTZ, para que
                                admin.css no tenga que escribir el azulado a mano */
  --lpr:#8E4468;            /* ciruela: lectura de placa */
  --limite:#B0332A;         /* rojo del límite municipal: antes casi el mismo rojo que
                                --alerta (#D93B32 contra #C0392B) para dos significados
                                opuestos, cartografía contra alarma. Baja a un rojo más hondo
                                para distinguirse de la alarma de un vistazo */
  --dori-1:#2E7D5B;         /* identificación */
  --dori-2:#3D7EA6;         /* reconocimiento */
  --dori-3:#A87F2E;         /* observación: mismo motivo que --pend, se desata del dorado */
  --dori-4:#7E7A70;         /* detección */

  /* ---- texto sobre acentos ---- */
  --on-marca:#2B2200;
  --on-gris:#FFFFFF;

  /* ---- avisos ----
     Fondos recalibrados para pisar bien la rampa nueva de superficies. Los textos
     (--warn-txt/--bad-txt/--ok-txt) ya cumplían AA y no se tocan. */
  --warn-bg:#FBF0D4;
  --warn-txt:#7A5A06;
  --bad-bg:#FAE9E6;
  --bad-txt:#95291D;
  --ok-bg:#E4F0E9;
  --ok-txt:#276B41;

  /* ---- compatibilidad con nombres anteriores ----
     Quedan como alias para que ningún color se rompa si un módulo
     todavía pide el nombre viejo. El cian ya no existe: apunta al dorado. */
  --cyan:var(--marca);
  --amber:var(--marca);
  --danger:var(--alerta);
  --violet:var(--ptz);
  --verde:var(--ok);
  --rojo-limite:var(--limite);
  --on-cyan:var(--on-marca);
  --on-amber:var(--on-marca);
  --on-muted:var(--on-gris);
  --warn-bad-txt:var(--bad-txt);
  --warn-ok-txt:var(--ok-txt);

  /* ---- medidas ----
     Escala de radios de verdad, no siete valores sueltos. Cada paso es para
     algo: xs sellos y etiquetas, sm controles, md tarjetas, lg diálogos,
     full píldoras. Mezclarlos al azar es de las cosas que más delatan que
     nadie decidió nada. */
  /* ---- sistema de componentes (17/08/2026) ----
     Antes convivían cuatro escalas de botón sin que ninguna fuera la buena, y
     ninguna declaraba altura en escritorio: la caja dependía de la métrica de la
     fuente del sistema, así que dos botones de la misma fila salían desiguales.
     Ahora la altura se declara y hay tres tamaños, no cuatro escalas sueltas. */
  --h-sm:28px;              /* controles dentro de una barra o una fila de lista */
  --h-md:34px;              /* el tamaño normal: acciones de panel */
  --h-lg:40px;              /* dedo: lo impone la banda táctil, no se usa a mano */
  /* Espaciado. Cinco pasos y ninguno intermedio: en cuanto se admite un 10 o un
     14 «porque quedaba mejor», la columna deja de tener ritmo. */
  --e1:4px; --e2:8px; --e3:12px; --e4:16px; --e5:24px;

  /* ---- tipografía ----
     UNA SOLA REGLA, y de ella sale toda la personalidad que se puede tener sin
     comprar una fuente: LA MONOESPACIADA SIGNIFICA «ESTO ES UNA MEDIDA».
     Metros, hilos, azimut, coordenadas y el número de punto van en mono con
     cifras tabulares, así una columna de sesenta filas alinea sola y el ojo
     compara sin leer. Nada más la usa —ni los títulos, ni los rótulos— y por eso
     el número resalta: es lo único mono de la pantalla. */
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;

  /* ---- medidor de segmentos ----
     La pieza que da carácter. Cuenta las tres cosas que esta herramienta cuenta
     de verdad: hilos de un cable, puertos de un splitter y las cinco preguntas
     esenciales de la visita. */
  --tick-off:#CFC7B4;       /* segmento apagado */
  --placa:#EFEAE0;          /* fondo de la placa del número de punto */

  --r-xs:5px;
  --r-sm:8px;
  --r-md:12px;
  --r-lg:16px;
  --r-full:999px;
  /* Nombres anteriores, para que ninguna regla vieja se quede sin radio */
  --radius:var(--r-md);
  --radius-sm:var(--r-sm);

  --w-izq:300px;
  --w-der:410px;
  --h-top:46px;

  /* ---- elevación ----
     Cada nivel son DOS sombras: una de contacto, corta y apretada, que ancla
     la pieza al fondo, y otra ambiental, ancha y difusa, que da el aire. Una
     sola sombra difusa es lo que se ve gomoso y barato. El tono no es negro
     puro sino el gris de la marca, para que la luz de toda la pantalla venga
     del mismo sitio. */
  --sombra-0:0 1px 1px rgba(60,56,44,.04);
  --sombra-1:0 1px 2px rgba(60,56,44,.07), 0 2px 6px rgba(60,56,44,.05);
  --sombra-2:0 1px 2px rgba(60,56,44,.08), 0 6px 16px rgba(60,56,44,.09);
  --sombra-3:0 2px 4px rgba(60,56,44,.10), 0 16px 40px rgba(60,56,44,.16);
  /* Realce interior: una línea de luz de un píxel arriba. Es lo que hace que
     un botón se sienta una pieza física y no un rectángulo pintado. */
  --luz:inset 0 1px 0 rgba(255,255,255,.7);
  --sombra:var(--sombra-1);
  --sombra-alta:var(--sombra-3);

  /* ---- movimiento ----
     Una sola curva para todo. Ease-out: arranca rápido y frena, que es como
     se mueven las cosas de verdad. */
  --curva:cubic-bezier(.2,.7,.3,1);
  --rapido:.12s var(--curva);

  /* ---- apilamiento ----
     Todo lo que flota tiene su nivel declarado aquí. Antes los controles del
     mapa y los de Leaflet empataban en 1000 y el orden visual dependía del
     orden del DOM: por eso el selector de capas tapaba el buscador. Con #map
     en su propio contexto (--z-mapa), Leaflet entero queda por debajo. */
  --z-mapa:0;
  --z-ctl-mapa:10;      /* controles propios sobre el mapa */
  --z-ctl-alto:20;      /* el buscador, que al abrirse tapa a los demás */
  --z-pliega:30;
  --z-lateral:2000;     /* editor como cajón lateral (pantallas medianas) */
  --z-cajon:2400;       /* cajones del celular */
  --z-menu:2500;
  --z-barra:2600;       /* barra inferior del celular */
  --z-modal:3000;
  --z-doc:4000;         /* visor del reporte/acta imprimible, hoy en css/reporte.css con el
                            número escrito a mano; §3 exige que todo lo que flota lo declare
                            aquí */
  --z-toast:5000;
  --z-bloqueo:9000;     /* aviso de recursos que no cargaron */
}

*{box-sizing:border-box;}
/* El `display:none` que el navegador le da a [hidden] es de la hoja del propio
   navegador, así que CUALQUIER regla nuestra con display lo gana y el elemento
   se sigue viendo aunque lleve el atributo. Pasó con el botón de sesión y con
   los botones del panel de administración. */
[hidden]{display:none !important;}
html,body{height:100%;margin:0;overflow:hidden;}
body{
  background:var(--bg);
  color:var(--text);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Inter,Arial,sans-serif;
  font-size:13px;
  line-height:1.45;
}
::-webkit-scrollbar{width:10px;height:10px;}
::-webkit-scrollbar-track{background:var(--panel-2);}
::-webkit-scrollbar-thumb{background:var(--line-2);border-radius:5px;border:2px solid var(--panel-2);}
::-webkit-scrollbar-thumb:hover{background:var(--muted-2);}
@media (prefers-reduced-motion:reduce){ *{transition:none !important;animation:none !important;} }

/* ---------- ESQUELETO ---------- */
#shell{display:flex;flex-direction:column;height:100vh;height:100dvh;overflow:hidden;}

/* La barra es de la marca, no blanca. Una franja blanca con una raya de color
   arriba es lo que sale por defecto en cualquier plantilla; el gris ZW con el
   filo dorado abajo le pone cara al producto y es la misma cabecera que usa el
   panel de administración, así que las dos pantallas se ven de la misma casa.
   El degradado va de --barra-alto a --barra-hondo: verde petróleo, el
   complemento del dorado. Antes era el oliva de la marca (el dorado se apagaba
   encima: son vecinos de tono) y después un grafito frío, que cumplía pero era
   gris. Sobre petróleo el filete dorado de abajo salta al máximo, que es
   exactamente lo que tiene que hacer. Dos extremos reales y no un plano, o la
   franja se lee como barro; pero sin pasarse, o parece un botón de los años
   dos mil. */
#topbar{
  flex:0 0 auto;height:var(--h-top);display:flex;align-items:center;gap:10px;
  padding:0 12px;color:var(--on-gris);
  background:linear-gradient(180deg,var(--barra-alto),var(--barra-hondo));
  border-bottom:2px solid var(--marca);
  box-shadow:var(--sombra-2);
  position:relative;z-index:1;   /* la sombra tiene que caer sobre los paneles */
}
#topbar .marca{display:flex;align-items:baseline;gap:8px;min-width:0;}
#topbar h1{font-size:14px;margin:0;font-weight:650;letter-spacing:.15px;white-space:nowrap;
  color:var(--on-gris);min-width:0;overflow:hidden;text-overflow:ellipsis;}
#topbar h1 .corto{display:none;}
#btn-sesion .corto{display:none;}
#topbar .sub{font-size:11px;color:rgba(255,255,255,.62);white-space:nowrap;}
#topbar .sep{flex:1;}

/* Botones sobre la barra oscura: fondo translúcido en vez de un borde duro.
   Un botón blanco con borde gris sobre fondo oscuro se ve como un parche. */
#topbar button{
  background:rgba(255,255,255,.10);border-color:rgba(255,255,255,.18);
  color:rgba(255,255,255,.92);box-shadow:none;
}
#topbar button:hover{background:rgba(255,255,255,.20);border-color:rgba(255,255,255,.34);color:#fff;}
#topbar button:active{background:rgba(0,0,0,.14);}
#topbar button:focus-visible{outline-color:var(--marca);}
/* Sin sesión el botón se pone dorado: es la única señal de que lo que se
   edite no se va a guardar en ninguna parte. Aquí sí conviene que grite. */
#btn-sesion.warn{
  background:var(--marca);border-color:var(--marca);color:var(--on-marca);
  box-shadow:var(--luz),0 1px 2px rgba(60,56,44,.25);
}
#btn-sesion.warn:hover{background:#F2BE28;border-color:#F2BE28;color:var(--on-marca);}

#save-ind{
  font-size:10.5px;white-space:nowrap;display:flex;align-items:center;gap:7px;
  border:1px solid rgba(255,255,255,.16);border-radius:var(--r-full);
  padding:4px 11px;background:rgba(0,0,0,.16);color:rgba(255,255,255,.80);
  /* Con tope: "Guardado en el servidor 07:02 a.m." empujaba deshacer, rehacer
     y ayuda fuera de la barra en pantallas medianas. */
  max-width:34ch;cursor:pointer;transition:background var(--rapido),border-color var(--rapido);
}
#save-ind:hover{background:rgba(0,0,0,.26);border-color:rgba(255,255,255,.28);}
#save-ind #save-txt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* El punto lleva un halo de su propio color: a 7 px, un círculo plano sobre
   fondo oscuro se pierde, y este punto es el estado del guardado. */
#save-ind .dot{
  width:7px;height:7px;border-radius:50%;background:var(--ok);flex:none;
  box-shadow:0 0 0 3px rgba(62,142,90,.30);
}
#save-ind.warn{border-color:rgba(232,177,24,.55);color:#FBE7B4;background:rgba(232,177,24,.16);}
#save-ind.warn .dot{background:var(--marca);box-shadow:0 0 0 3px rgba(232,177,24,.32);}
#save-ind.err{border-color:rgba(192,57,43,.60);color:#FBD5D0;background:rgba(192,57,43,.22);}
#save-ind.err .dot{background:#E8635A;box-shadow:0 0 0 3px rgba(192,57,43,.38);}

#app{
  flex:1 1 auto;min-height:0;display:grid;
  grid-template-columns:var(--w-izq) 5px minmax(0,1fr) 5px var(--w-der);
}
/* `#app.sin-editor` se quitó: la clase no la ponía nadie desde el primer commit.
   Ocultar el editor se resuelve con `.der-plegado`, que sí está conectado. */

/* El lienzo va un punto más oscuro que las tarjetas que lleva encima. Antes
   eran blanco sobre casi blanco y por eso nada parecía estar por encima de
   nada: todo se leía como una sola hoja impresa. */
.zona{background:var(--lienzo);min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;}
/* Cada zona con su columna fija: si no, al ocultar un panel la rejilla recoloca
   sola las demás y el mapa se va a una columna de ancho cero. */
#panel-izq{grid-column:1;border-right:1px solid var(--line);}
#split-izq{grid-column:2;}
#map-wrap{grid-column:3;}
#split-der{grid-column:4;}
#panel-der{grid-column:5;border-left:1px solid var(--line);}

.splitter{background:var(--line);cursor:col-resize;position:relative;}
.splitter::after{content:'';position:absolute;inset:0 -3px;}
.splitter:hover,.splitter.activo{background:var(--marca);}

/* ---------- CONTROLES BASE ---------- */
/* Un botón se siente físico por tres cosas: la línea de luz de arriba, una
   sombra de contacto que lo separa del fondo, y que al pulsarlo se hunda de
   verdad (1 px abajo y sin sombra). Sin eso queda un rectángulo pintado, que
   es el aspecto que tiene todo lo que nadie revisó. */
button{
  /* La altura se DECLARA. Antes salía del padding más la métrica de la fuente,
     así que un `button` y un `.small` en la misma fila no coincidían nunca y la
     columna de acciones se veía irregular. Con `min-height` y el contenido
     centrado, dos botones de la misma clase miden lo mismo en cualquier equipo. */
  font-family:inherit;cursor:pointer;border:1px solid var(--line-2);
  background:var(--bg);color:var(--text);border-radius:var(--r-sm);
  min-height:var(--h-md);
  display:inline-flex;align-items:center;justify-content:center;gap:var(--e1);
  padding:0 var(--e3);font-size:12px;font-weight:600;line-height:1.2;
  box-shadow:var(--luz),var(--sombra-0);
  transition:background var(--rapido),border-color var(--rapido),
             box-shadow var(--rapido),transform var(--rapido),color var(--rapido);
}
button:hover{border-color:var(--line-2);background:var(--panel);box-shadow:var(--luz),var(--sombra-1);}
button:active{transform:translateY(1px);box-shadow:inset 0 1px 3px rgba(60,56,44,.12);}
button:focus-visible{outline:2px solid var(--marca-2);outline-offset:2px;}

button.primary{
  background:linear-gradient(180deg,#F0BC2A 0%,var(--marca) 55%,#DFA80F 100%);
  color:var(--on-marca);border-color:var(--marca-2);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),0 1px 2px rgba(140,100,10,.28);
}
button.primary:hover{
  background:linear-gradient(180deg,#F5C63C 0%,#EEB81C 55%,#E3AC12 100%);
  border-color:var(--marca-2);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),0 2px 8px rgba(140,100,10,.30);
}
button.primary:active{box-shadow:inset 0 2px 5px rgba(120,86,8,.32);}
button.primary.active{background:var(--gris);border-color:var(--gris);color:var(--on-gris);}

button.alt{
  background:linear-gradient(180deg,#5C5C58 0%,var(--gris) 100%);
  color:var(--on-gris);border-color:#3E3E3C;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 1px 2px rgba(43,43,42,.28);
}
button.alt:hover{background:linear-gradient(180deg,#68685F 0%,#565653 100%);border-color:#3E3E3C;}

button.ghost{background:transparent;box-shadow:none;border-color:transparent;}
button.ghost:hover{background:var(--panel-2);border-color:var(--line);box-shadow:none;}
button.ghost.active{background:var(--gris);color:var(--on-gris);border-color:var(--gris);}
/* Tres tamaños y ninguno más. `.small` ya no es «un poco más bajo», es la altura
   de barra; `.icon` es cuadrado de la misma altura, así que un botón de texto y
   uno de icono puestos uno al lado del otro coinciden, que antes era imposible
   porque `.icon` fijaba su propio `line-height`. */
button.small{min-height:var(--h-sm);padding:0 var(--e2);font-size:11.5px;}
button.icon{min-height:var(--h-md);min-width:var(--h-md);padding:0 var(--e2);font-size:12px;}
button.icon.small{min-height:var(--h-sm);min-width:var(--h-sm);padding:0 var(--e1);}

/* UN SOLO PATRÓN PARA LLENAR UNA FILA. Antes convivían `flex:1` por CSS y
   `width:100%` en línea desde el JS, y como el segundo iba en botones `.small`,
   la fila de abajo salía más baja que la de arriba. Se pone la clase al
   contenedor y sus botones se reparten; nadie vuelve a escribir un ancho. */
.fila-acciones{display:flex;gap:var(--e2);align-items:stretch;}
.fila-acciones > button{flex:1 1 0;min-width:0;}
.fila-acciones > button.fijo{flex:0 0 auto;}
button.danger-btn{color:var(--alerta);border-color:transparent;background:transparent;box-shadow:none;}
button.danger-btn:hover{background:var(--bad-bg);border-color:var(--alerta);box-shadow:none;}
button[disabled]{opacity:.45;cursor:not-allowed;box-shadow:none;}
button[disabled]:hover{border-color:var(--line-2);background:var(--bg);box-shadow:none;}
button[disabled]:active{transform:none;}

/* Los campos van HUNDIDOS: sombra hacia dentro. Es lo contrario del botón, y
   es lo que hace que se lean como un hueco donde se escribe sin necesidad de
   ningún rótulo que lo explique. */
/* `password` y `email` van en la lista: hasta que se agregaron, el campo de
   contraseña del diálogo de entrar salía con el ancho por defecto del
   navegador y quedaba visiblemente más angosto que el de usuario, justo
   encima. Un formulario con los campos descuadrados es de lo primero que se
   nota y de lo último que se mira. */
select,input[type=text],input[type=password],input[type=email],
input[type=number],input[type=search],textarea{
  width:100%;background:var(--bg);border:1px solid var(--line-2);
  color:var(--text);border-radius:var(--r-sm);padding:8px 9px;
  font-size:12.5px;font-family:inherit;
  box-shadow:inset 0 1px 2px rgba(60,56,44,.06);
  transition:border-color var(--rapido),box-shadow var(--rapido);
}
input:hover,select:hover,textarea:hover{border-color:var(--muted-2);}
input:focus,select:focus,textarea:focus{
  outline:none;border-color:var(--marca-2);
  box-shadow:inset 0 1px 2px rgba(60,56,44,.05),0 0 0 3px rgba(232,177,24,.28);
}
input[type=range]{width:100%;accent-color:var(--marca-2);height:20px;}
input[type=checkbox]{accent-color:var(--marca-2);margin:0;}
textarea{resize:vertical;min-height:56px;line-height:1.5;}
::placeholder{color:var(--muted-2);}

label.check{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--muted);cursor:pointer;user-select:none;}
label.check:hover{color:var(--text);}

.field{margin-top:12px;}
.field > label{
  display:flex;justify-content:space-between;align-items:baseline;gap:8px;
  font-size:10.5px;color:var(--muted);text-transform:uppercase;
  letter-spacing:.5px;margin-bottom:5px;font-weight:700;
}
.field > label .val{color:var(--marca-txt);font-weight:700;text-transform:none;letter-spacing:0;font-size:11.5px;}
.row2{display:flex;gap:10px;}
.row2 > .field{flex:1;min-width:0;}
.hint-txt{font-size:10.5px;color:var(--muted);margin-top:5px;line-height:1.5;}

.slider-row{display:flex;align-items:center;gap:9px;}
.slider-row input[type=range]{flex:1;min-width:0;}
.slider-row .num{
  flex:0 0 66px;width:66px;text-align:right;padding:6px 7px;font-size:12px;
  font-variant-numeric:tabular-nums;
}
.slider-row .num[disabled]{opacity:.55;background:var(--panel-2);}

/* El grupo va hundido y la opción elegida sale a flote encima. Es la misma
   idea del interruptor físico y se entiende sin leer nada. */
.seg{
  display:flex;border:1px solid var(--line-2);border-radius:var(--r-sm);
  overflow:hidden;background:var(--panel-2);
  box-shadow:inset 0 1px 2px rgba(60,56,44,.07);
}
.seg button{
  flex:1;border:none;border-radius:0;background:transparent;padding:7px 6px;
  font-size:11.5px;color:var(--muted);box-shadow:none;
}
.seg button + button{border-left:1px solid var(--line);}
.seg button:hover{background:rgba(255,255,255,.6);color:var(--text);box-shadow:none;}
.seg button:active{transform:none;}
.seg button.on{
  background:var(--marca);color:var(--on-marca);font-weight:700;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4),0 1px 3px rgba(140,100,10,.30);
}
.seg button.on.exist{
  background:var(--gris);color:var(--on-gris);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 1px 3px rgba(43,43,42,.30);
}

.chip{
  display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line-2);
  border-radius:var(--r-full);padding:5px 11px;font-size:11px;color:var(--muted);
  cursor:pointer;user-select:none;background:var(--bg);
  box-shadow:var(--luz),var(--sombra-0);
  transition:background var(--rapido),border-color var(--rapido),
             color var(--rapido),box-shadow var(--rapido);
}
.chip:hover{border-color:var(--muted-2);color:var(--text);box-shadow:var(--luz),var(--sombra-1);}
.chip:active{box-shadow:inset 0 1px 3px rgba(60,56,44,.12);}
.chip .cdot{width:8px;height:8px;border-radius:50%;background:currentColor;flex:none;}
/* Encendido lleva un aro del color de la marca, no solo un fondo pálido: en
   una fila de seis filtros hay que poder ver de un vistazo cuáles están on. */
.chip.on{
  color:var(--marca-txt);border-color:var(--marca-2);background:var(--marca-suave);font-weight:650;
  box-shadow:0 0 0 2px rgba(232,177,24,.22);
}
.chip.on.exist{border-color:var(--gris);background:var(--panel-3);}
.chip.on.dori{border-color:var(--dori-2);background:#EAF1F5;}
.chip.on.cable{border-color:var(--marca-2);background:var(--marca-suave);}
/* Las tres capas de la planta externa llevan el color con el que se dibujan en
   el mapa: el filtro y la línea tienen que ser reconocibles como lo mismo. */
.chip.on.troncal{border-color:#2F6F8F;background:var(--ptz-bg);color:#265B76;}
.chip.on.nodos{border-color:var(--marca-2);background:var(--marca-suave);}
.chip.on.mascara,.chip.on.limite{border-color:var(--limite);background:var(--bad-bg);}

/* ---------- horario de grabación ---------- */
.hr-barra{
  position:relative;height:16px;border-radius:4px;background:var(--panel-3);
  border:1px solid var(--line);overflow:hidden;margin-top:8px;
}
.hr-barra i{position:absolute;top:0;bottom:0;display:block;}
.hr-reglas{display:flex;justify-content:space-between;font-size:9px;color:var(--muted-2);margin-top:2px;}
.hr-lista{display:flex;flex-direction:column;gap:6px;margin-top:8px;}
.hr-fila{display:flex;gap:5px;align-items:center;}
.hr-fila input[type=time]{
  flex:0 0 88px;background:var(--bg);border:1px solid var(--line-2);border-radius:var(--radius-sm);
  color:var(--text);padding:6px 7px;font-size:12px;font-family:inherit;
}
.hr-fila .a{font-size:11px;color:var(--muted);}
.hr-fila select{flex:1;min-width:0;font-size:11.5px;padding:6px 6px;}
.hr-fila button{flex:0 0 auto;padding:4px 7px;}
@media (max-width:820px){
  .hr-fila{flex-wrap:wrap;}
  .hr-fila select{flex:1 0 44%;}
}

/* Atajos de notas: escribir en el celular parado en la calle es lo que más cuesta */
.notas-rapidas{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px;}
.notas-rapidas .chip{padding:5px 9px;font-size:10.5px;line-height:1.3;text-align:left;}
.notas-rapidas .chip:active{background:var(--marca);color:var(--on-marca);}

.swatches{display:flex;gap:7px;flex-wrap:wrap;}
.swatch{width:22px;height:22px;border-radius:50%;cursor:pointer;border:2px solid var(--line);}
.swatch:hover{border-color:var(--muted);}
.swatch.active{border-color:var(--gris);box-shadow:0 0 0 2px var(--marca-suave);}

.menu{
  position:absolute;min-width:240px;background:var(--bg);
  border:1px solid rgba(60,56,44,.14);border-radius:var(--r-md);
  padding:5px;display:none;z-index:var(--z-menu);box-shadow:var(--sombra-3);
}
.menu.show{display:block;animation:modal-entra .14s var(--curva);}
.menu button{display:block;width:100%;text-align:left;border:none;background:transparent;padding:8px 10px;
  border-radius:var(--r-sm);font-weight:500;font-size:12px;box-shadow:none;}
.menu button:hover{background:var(--panel-2);box-shadow:none;}
.menu button:active{transform:none;}
.menu button.danger-item{color:var(--alerta);}
.menu button.danger-item:hover{background:var(--bad-bg);}
.menu-sep{height:1px;background:var(--line);margin:5px 2px;}
.menu-lbl{font-size:9.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted-2);padding:6px 10px 3px 10px;font-weight:700;}

/* ---------- PANEL IZQUIERDO ---------- */
/* Cabecera y pie son barras fijas: llevan sombra hacia el contenido que se
   desplaza por debajo, para que se note qué está anclado y qué se mueve. */
.panel-head{
  flex:0 0 auto;padding:10px 12px;display:flex;flex-direction:column;gap:9px;
  background:var(--bg);border-bottom:1px solid var(--line);
  box-shadow:0 1px 3px rgba(60,56,44,.05);position:relative;z-index:2;
}
.sede-row{display:flex;gap:6px;align-items:center;}
.sede-row select{flex:1;min-width:0;}
/* Crear, renombrar y eliminar sede son iconos sueltos: sin un contorno en
   reposo se leen como texto decorativo y nadie descubre que se pueden pulsar.
   Fantasma sí, invisible no. */
.sede-row button.icon.ghost{
  border-color:var(--line);background:var(--bg);color:var(--muted);
  box-shadow:var(--sombra-0);
}
.sede-row button.icon.ghost:hover{
  border-color:var(--marca-2);background:var(--marca-suave);color:var(--marca-txt);
}
.sede-row button#btn-sede-del:hover{
  border-color:var(--alerta);background:var(--bad-bg);color:var(--bad-txt);
}
#add-row{display:flex;gap:8px;}
#add-row button{flex:1;white-space:nowrap;}

/* La pestaña activa es la hoja de encima: fondo blanco continuo con el panel,
   subrayado dorado grueso y el resto hundido en el lienzo. El fondo pálido de
   antes hacía justo lo contrario —marcaba la activa como una casilla resaltada
   dentro de una barra blanca— y por eso costaba ver dónde estabas. */
/* Un poco de aire a los lados: pegada al borde, la primera pestaña parecía
   cortada por el panel en vez de empezar ahí. */
.tabs{flex:0 0 auto;display:flex;padding:0 var(--e1);
  border-bottom:1px solid var(--line);background:var(--panel-2);}
.tabs button{
  /* `min-width:0` es obligatorio con flex:1: sin él, `min-width:auto` impide que
     un botón se encoja por debajo de su texto y cinco pestañas revientan los
     300 px del panel. Con él, las columnas son iguales de verdad. */
  flex:1 1 0;min-width:0;border:none;border-radius:0;background:transparent;color:var(--muted);
  /* La letra sigue al panel (17/08/2026). Las columnas ya ocupaban toda la
     franja, pero el rótulo no: a 460 px de panel eran 90 px de columna con 33 a
     55 px de texto de 10 px, o sea cinco palabritas perdidas en una barra ancha,
     que es lo que se ve como espacio desaprovechado. El tamaño sale de --w-izq
     —la misma variable que mueve el tirador—, así que no hace falta ni JS ni
     consultas de contenedor: 10 px hasta 355 px de panel y 12,5 px desde 445.
     El techo de 12,5 px no es capricho: por encima, COBERTURA ya no cabe en su
     columna ni siquiera con el panel abierto del todo. */
  font-size:clamp(10px, calc(var(--w-izq) * .028), 12.5px);
  padding:9px 3px;text-transform:uppercase;
  letter-spacing:clamp(.2px, calc(var(--w-izq) * .0016), .7px);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  box-shadow:inset 0 -2px 0 transparent;font-weight:700;
  transition:background var(--rapido),color var(--rapido),box-shadow var(--rapido);
}
.tabs button:hover{color:var(--text);background:rgba(255,255,255,.55);box-shadow:inset 0 -2px 0 var(--line-2);}
.tabs button:active{transform:none;}
.tabs button.on{
  color:var(--gris);background:var(--bg);
  box-shadow:inset 0 -2px 0 var(--marca),inset 0 1px 0 rgba(255,255,255,.9);
}
/* El contador va como número volado y no como píldora: la píldora costaba unos
   20 px por pestaña y con cinco pestañas en 300 px eso es la diferencia entre
   caber y no caber. Sigue leyéndose porque va en el dorado de la marca. */
.tabs button .badge-n{
  display:inline;margin-left:3px;background:none;padding:0;
  /* En em, para que crezca con el rótulo cuando se ensancha el panel */
  font-size:.86em;color:var(--marca-txt);font-weight:800;vertical-align:super;
  font-variant-numeric:tabular-nums;
}
.tabs button.on .badge-n{color:var(--marca-2);}

.tabpanel{flex:1 1 auto;min-height:0;display:none;flex-direction:column;overflow:hidden;}
.tabpanel.on{display:flex;}
.scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;padding:10px 12px 22px 12px;}

/* Las cuatro cifras del proyecto. El color no va en un filete de 2 px arriba
   —que a esa altura se lee como una raya suelta— sino en una barra al costado
   que arranca del propio número: el ojo asocia el color con la cifra y no con
   el borde de la caja. */
.stats{display:flex;gap:6px;align-items:stretch;}
.stat{
  flex:1;min-width:0;position:relative;overflow:hidden;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-md);
  padding:7px 7px 7px 10px;box-shadow:var(--sombra-0);
}
.stat::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--line-2);
}
.stat .n{
  font-family:var(--mono);
  font-size:16px;font-weight:700;color:var(--gris);
  font-variant-numeric:tabular-nums;letter-spacing:-.4px;line-height:1.15;
}
/* El rótulo se parte en dos renglones POR EL ESPACIO, nunca dentro de la
   palabra. Con `overflow:hidden` en la tarjeta y cuatro tarjetas en 300 px,
   «POR CONFIRMAR» se cortaba en seco a «POR CONFIRMA», que parece un fallo de
   datos y no de espacio; y partiéndolo por cualquier sitio salía «CONFIRM/AR»,
   que es peor. Vale más una tarjeta un renglón más alta que un rótulo roto. */
.stat .l{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.2px;
  font-weight:600;line-height:1.15;white-space:normal;hyphens:none;}
.stat.new::before{background:var(--marca);}
.stat.new .n{color:var(--marca-txt);}
.stat.exist .n{color:var(--muted);}
.stat.ptz::before{background:var(--ptz);}
.stat.ptz .n{color:var(--ptz);}
.stat.pend::before{background:var(--marca-2);}
.stat.pend .n{color:var(--warn-txt);}

.filtros{display:flex;flex-wrap:wrap;gap:6px;}
#filtros-linea{display:flex;gap:8px;}
#filtros-linea select{flex:1;min-width:0;}

.sec-titulo{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);
  font-weight:700;margin:16px 0 7px 0;display:flex;align-items:center;gap:8px;
}
.sec-titulo::after{content:'';flex:1;height:1px;background:var(--line);}
.sec-titulo:first-child{margin-top:0;}

/* barra de selección múltiple */
/* La barra de selección la comparten la lista de cámaras (#sel-bar, que está
   en el HTML) y las listas de la pestaña Cableado (#cable-sel-bar, que se
   genera con el resto del panel). Misma pinta porque es el mismo gesto. */
#sel-bar, #cable-sel-bar{
  display:none;align-items:center;gap:6px;background:var(--marca-suave);
  border:1px solid var(--marca-2);border-radius:var(--radius-sm);padding:6px 8px;margin-bottom:8px;
}
#sel-bar.show, #cable-sel-bar.show{display:flex;}
#sel-bar .txt, #cable-sel-bar span{flex:0 1 auto;min-width:0;font-size:11.5px;color:var(--gris);}
#sel-bar .txt{flex:1;}
#cable-sel-bar .sep{flex:1;}
#sel-bar .txt b, #cable-sel-bar b{font-size:13px;}
/* Los botones de la barra de selección usan `.small` como todos: eran una cuarta
   escala sin nombre (5/8 px, 11 px) que nadie había declarado en ningún sitio. */
#sel-bar button, #cable-sel-bar button{min-height:var(--h-sm);padding:0 var(--e2);font-size:11px;}

/* lista de cámaras */
#cam-list{
  display:flex;flex-direction:column;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:var(--sombra-0);overflow:hidden;
}
/* Dentro de la tarjeta de la lista, el rótulo de sede es una banda separadora
   y no un texto suelto: si va sin fondo, con las filas pegadas parece el
   nombre de la primera cámara. */
.sede-group-head{
  display:flex;align-items:center;gap:8px;padding:7px 10px 6px 10px;
  font-size:10px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);font-weight:700;
  background:var(--panel-2);border-bottom:1px solid var(--line);
}
.sede-group-head + .cam-row{border-top-left-radius:0;border-top-right-radius:0;}
.sede-group-head .line{flex:1;height:1px;background:var(--line-2);}
/* Cincuenta y ocho filas, cada una con su borde de 1 px y su separación, se
   leen como cincuenta y ocho cajas y no como una lista: el ojo tiene que
   saltar un marco por renglón. Van pegadas dentro de una sola superficie,
   separadas por un filete, que es como se ve una lista de verdad. El borde
   solo aparece cuando la fila está elegida o marcada, y entonces sí significa
   algo. */
.cam-row{
  display:flex;align-items:center;gap:8px;padding:7px 8px;
  cursor:pointer;background:var(--bg);
  border:1px solid transparent;border-bottom-color:var(--line);
  border-left:3px solid transparent;
  transition:background var(--rapido),border-color var(--rapido),box-shadow var(--rapido);
}
.cam-row:first-child{border-top-left-radius:var(--r-sm);border-top-right-radius:var(--r-sm);}
.cam-row:last-child{border-bottom-color:transparent;
  border-bottom-left-radius:var(--r-sm);border-bottom-right-radius:var(--r-sm);}
.cam-row:hover{background:var(--panel);}
.cam-row.sel{
  border-color:var(--marca-2);border-left-color:var(--marca);background:var(--marca-suave);
  border-radius:var(--r-sm);box-shadow:var(--sombra-1);position:relative;z-index:1;
}
.cam-row.marcada{border-left-color:var(--gris);background:var(--panel-2);}
.cam-row .dot{width:9px;height:9px;border-radius:50%;flex:none;border:1px solid rgba(43,43,42,.25);}
.cam-row.exist .dot{background:transparent !important;border:1.5px dashed var(--muted);}
.cam-row .dot.rombo-mini{border-radius:2px;transform:rotate(45deg);background:var(--marca);}
/* El número de punto va en una placa, como la chapa numerada de un poste: es el
   identificador que se dice por radio y el que sale en el reporte, no un adorno
   de lista. Mono y tabular para que la columna alinee con sesenta filas. */
.cam-row .idx{
  font-family:var(--mono);font-size:10px;font-variant-numeric:tabular-nums;
  color:var(--muted);flex:none;min-width:22px;text-align:center;
  background:var(--placa);border-radius:var(--r-xs);padding:2px 4px;
  border:1px solid var(--line);
}
.cam-row.sel .idx{background:var(--marca-suave);border-color:var(--marca-2);color:var(--marca-txt);}
.cam-row .nm{flex:1;min-width:0;font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cam-row.exist .nm{font-weight:500;color:var(--muted);}
.cam-row .tp{
  flex:none;font-size:9px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);
  border:1px solid var(--line);border-radius:var(--r-xs);padding:1px 5px;background:var(--panel-2);
  font-weight:600;
}
/* Cuando lo que lleva la celda es una MEDIDA —metros de un tendido, hilos— deja
   de ser una etiqueta y pasa a mono tabular, que es la regla tipográfica única
   del proyecto: la mono significa «esto se puede medir». */
.cam-row .tp.med{font-family:var(--mono);text-transform:none;letter-spacing:0;
  background:none;border-color:transparent;color:var(--text);font-size:10.5px;
  font-variant-numeric:tabular-nums;}
.cam-row .sem{width:9px;height:9px;border-radius:50%;flex:none;
  box-shadow:0 0 0 1.5px rgba(255,255,255,.9),0 1px 2px rgba(60,56,44,.25);}
.empty-state{color:var(--muted);text-align:center;padding:30px 18px;font-size:12px;line-height:1.7;}
.empty-state b{color:var(--text);display:block;margin-bottom:6px;font-size:12.5px;}

.panel-foot{
  flex:0 0 auto;padding:9px 12px;border-top:1px solid var(--line);
  display:flex;gap:6px;align-items:center;position:relative;z-index:2;background:var(--bg);
  box-shadow:0 -1px 3px rgba(60,56,44,.05);
}
.panel-foot > button,.panel-foot .menu-wrap{flex:1;min-width:0;}
.panel-foot button{width:100%;white-space:nowrap;}
/* Reporte, Acta y Datos son las tres salidas del trabajo: no pueden verse como
   texto suelto. Aunque en el HTML sean `ghost`, aquí recuperan cuerpo. */
.panel-foot > button.ghost,.panel-foot .menu-wrap > button.ghost{
  background:var(--bg);border-color:var(--line-2);box-shadow:var(--luz),var(--sombra-0);
}
.panel-foot > button.ghost:hover,.panel-foot .menu-wrap > button.ghost:hover{
  background:var(--panel);border-color:var(--marca-2);color:var(--marca-txt);
  box-shadow:var(--luz),var(--sombra-1);
}
.menu-wrap{position:relative;display:flex;}
.menu-wrap .menu{bottom:calc(100% + 8px);right:0;}

/* cableado */
#cable-acciones{display:flex;gap:8px;margin-top:10px;}
#cable-acciones button{flex:1;}
#ruta-list{
  display:flex;flex-direction:column;
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:var(--sombra-0);overflow:hidden;
}
#ruta-list:empty{display:none;}

/* análisis */
.legend{display:flex;flex-direction:column;gap:6px;}
.legend-item{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--muted);line-height:1.4;}
.legend-chip{width:13px;height:13px;border-radius:3px;flex:none;border:1px solid rgba(43,43,42,.15);}
.metrics{display:grid;grid-template-columns:1fr 1fr;gap:8px;}
.metric{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-md);
  padding:8px 10px;box-shadow:var(--sombra-0);}
.metric .mv{font-family:var(--mono);font-size:15px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.3px;}
.metric .ml{font-size:9.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.4px;}
.metric.blind .mv{color:var(--alerta);}
.metric.single .mv{color:var(--marca-txt);}
.metric.multi .mv{color:var(--dori-2);}
.metric.zone .mv{color:var(--text);}
.nota{font-size:11px;color:var(--muted);line-height:1.55;}
.nota b{color:var(--text);}

/* ---------- PANEL DERECHO ---------- */
/* Centrado exacto en un panel tan alto y angosto deja el mensaje flotando en
   mitad de la nada. Un poco por encima del centro es donde el ojo lo busca.
   El halo dorado es apenas perceptible y evita que el panel vacío se lea como
   una zona que no cargó. */
#ed-vacio{
  flex:1;display:flex;align-items:center;justify-content:center;
  padding:26px 26px 22vh 26px;text-align:center;
  color:var(--muted);font-size:12px;line-height:1.7;
  background:radial-gradient(120% 55% at 50% 34%,var(--marca-suave) 0%,transparent 62%);
}
#ed-vacio > div{max-width:290px;}
#ed-vacio b{display:block;color:var(--text);margin-bottom:7px;font-size:13px;}
/* El dibujo va tenue a propósito: acompaña, no compite con lo que sí importa
   cuando hay algo seleccionado. */
.ed-vacio-icono{width:82px;height:82px;display:block;margin:0 auto 14px auto;opacity:.9;}
.ed-vacio-icono .cono{fill:var(--marca-suave);stroke:var(--marca-2);stroke-width:2;
  stroke-linejoin:round;opacity:.75;}
.ed-vacio-icono .base{fill:var(--bg);stroke:var(--gris);stroke-width:2.5;}
.ed-vacio-icono .lente{fill:var(--gris);}
#ed-wrap{flex:1 1 auto;min-height:0;display:none;flex-direction:column;overflow:hidden;}
#ed-wrap.on{display:flex;}
#ed-head{flex:0 0 auto;padding:10px 12px;border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:9px;background:var(--bg);}
.ed-title{display:flex;align-items:center;gap:8px;}
.ed-title .idx{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;font-weight:700;
  background:var(--marca);border-radius:6px;padding:3px 7px;flex:none;color:var(--on-marca);
}
.ed-title input{flex:1;min-width:0;font-weight:600;font-size:13px;}
.ed-title input[disabled]{background:var(--panel-2);color:var(--gris);}
.ed-title button{flex:none;}
.ed-acciones{display:flex;gap:6px;align-items:center;}
.ed-acciones .seg{flex:1;}
.ed-acciones .sep{flex:1;}
.ed-tabs{flex:0 0 auto;display:flex;border-bottom:1px solid var(--line);background:var(--panel-2);}
.ed-tabs button{
  flex:1;border:none;border-radius:0;background:transparent;color:var(--muted);
  padding:8px 3px;font-size:10.5px;text-transform:uppercase;letter-spacing:.5px;
  box-shadow:inset 0 -2px 0 transparent;font-weight:700;
  transition:background var(--rapido),color var(--rapido),box-shadow var(--rapido);
}
.ed-tabs button:hover{color:var(--text);background:rgba(255,255,255,.55);box-shadow:inset 0 -2px 0 var(--line-2);}
.ed-tabs button:active{transform:none;}
.ed-tabs button.on{
  color:var(--gris);background:var(--bg);
  box-shadow:inset 0 -2px 0 var(--marca),inset 0 1px 0 rgba(255,255,255,.9);
}
.ed-tabs button .pt{display:inline-block;width:6px;height:6px;border-radius:50%;margin-left:4px;vertical-align:middle;}
.ed-panel{display:none;}
.ed-panel.on{display:block;}
.card-actions{
  display:flex;justify-content:space-between;align-items:center;
  margin-top:14px;padding-top:10px;border-top:1px solid var(--line);
}
/* Las coordenadas son datos que se copian a mano a un formulario: fondo
   hundido y monoespaciado, como una consola. */
.coords{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;
  color:var(--muted);margin-top:10px;background:var(--panel-2);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:8px 10px;line-height:1.7;
  box-shadow:inset 0 1px 2px rgba(60,56,44,.05);
}
.coords b{color:var(--text);font-weight:600;}
.aviso-fuera{
  margin-top:10px;font-size:11px;line-height:1.5;color:var(--bad-txt);
  border-left:3px solid var(--alerta);background:var(--bad-bg);padding:7px 9px;border-radius:0 6px 6px 0;
}
.aviso-cable{
  margin-top:10px;font-size:11px;line-height:1.5;color:var(--warn-txt);
  border-left:3px solid var(--marca-2);background:var(--warn-bg);padding:7px 9px;border-radius:0 6px 6px 0;
}

/* ---------- VERIFICACION EN SITIO ---------- */
.chk-lista{display:flex;flex-direction:column;gap:8px;margin-top:4px;}
.chk-row{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-md);
  padding:9px 10px;box-shadow:var(--sombra-0);}
.chk-row .q{display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:7px;}
.chk-row .q .t{font-size:12.5px;font-weight:700;}
.chk-row .q .a{font-size:10px;color:var(--muted-2);}
.chk-seg{display:flex;gap:6px;}
.chk-seg button{
  flex:1;padding:7px 4px;font-size:11.5px;color:var(--muted);
  background:var(--bg);border:1px solid var(--line-2);border-radius:6px;
}
.chk-seg button:hover{color:var(--text);border-color:var(--muted);}
.chk-seg button.on.si{background:var(--ok);border-color:var(--ok);color:#fff;}
.chk-seg button.on.no{background:var(--alerta);border-color:var(--alerta);color:#fff;}
.chk-seg button.on.pend{background:var(--marca);border-color:var(--marca-2);color:var(--on-marca);}
/* Cuatro respuestas en rejilla: en 390 px puestas en fila quedan a 85 px y
   "Hay que poner" no cabe sin partirse. */
.chk-seg.cuatro{display:grid;grid-template-columns:1fr 1fr;}
.chk-seg button.on.pide{background:var(--marca-2);border-color:var(--marca-2);color:var(--on-marca);}
.chk-seg button.on.neutro{background:var(--gris);border-color:var(--gris);color:#fff;}
.chk-row .chk-num{width:100%;}
.chk-medida{display:flex;gap:6px;}
.chk-dim{flex:1;display:flex;flex-direction:column;gap:3px;}
.chk-dim > span{font-size:10px;color:var(--muted-2);}
.chk-dim input{width:100%;text-align:center;}
.chk-estado{
  margin-top:12px;display:flex;align-items:center;gap:9px;background:var(--bg);
  border:1px solid var(--line);border-radius:var(--r-md);padding:10px 11px;
  box-shadow:var(--sombra-0);
}
.chk-estado .bola{width:11px;height:11px;border-radius:50%;flex:none;}
.chk-estado .txt{flex:1;min-width:0;}
.chk-estado .txt .e{font-size:12.5px;font-weight:700;}
.chk-estado .txt .r{font-size:10.5px;color:var(--muted);}
.chk-sello{font-size:11px;color:var(--ok-txt);margin-top:9px;display:flex;align-items:center;gap:8px;
  background:var(--ok-bg);border-radius:6px;padding:7px 9px;}
.chk-sello .sep{flex:1;}

/* ---------- PLANEACION DE LA RED ---------- */
#red-acciones{display:flex;gap:6px;margin-top:9px;}
#red-acciones button{flex:1;}
.red-param{margin-top:10px;background:var(--bg);border:1px solid var(--line);
  border-radius:var(--r-md);padding:9px 11px;box-shadow:var(--sombra-0);}
.red-param > summary{list-style:none;cursor:pointer;font-size:11px;font-weight:700;
  text-transform:uppercase;letter-spacing:.4px;color:var(--gris);}
.red-param > summary::-webkit-details-marker{display:none;}
/* El centro de monitoreo se distingue del resto de nodos: es único en el proyecto */
.nodo-icon.centro .anillo{
  display:block;width:16px;height:16px;border-radius:50%;
  background:var(--bg);border:3px solid var(--marca);box-shadow:0 0 0 1px var(--gris),var(--sombra);
}
/* Un nodo sugerido va hueco: recuerda que hay que moverlo al poste real */
.nodo-icon.sug .rombo{background:var(--bg);border:2px solid var(--dori-2);}

/* ---------- PERMISOS Y CUMPLIMIENTO ---------- */
.norm-grupo{margin-top:9px;}
.norm-grupo > b{font-size:11px;color:var(--gris);text-transform:uppercase;letter-spacing:.4px;}
.norm-req{
  background:var(--bg);border:1px solid var(--line);border-left:3px solid var(--ok);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;padding:7px 9px;margin-top:6px;
  display:flex;flex-direction:column;gap:2px;
}
/* Ámbar cuando la norma no está verificada: lo que el reporte no puede respaldar
   tiene que verse distinto también en pantalla. */
.norm-req.pend{border-left-color:var(--marca-2);}
.norm-req .t{font-size:12px;font-weight:700;}
.norm-req .f{font-size:10px;color:var(--marca-txt);}
.norm-req .d{font-size:10.5px;color:var(--muted);}

/* ---------- FICHAS TECNICAS ---------- */
.spec-block,.ptz-block{
  margin-top:12px;background:var(--bg);border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:10px 11px;
}
.ptz-block{border-color:var(--ptz);}
.ptz-block.lpr-spec{border-color:var(--lpr);}
.spec-block .sb-title{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);
  font-weight:700;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;gap:6px;
}
.ptz-block .sb-title{
  font-size:9.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--ptz);font-weight:700;margin-bottom:8px;
}
.ptz-block .field:first-of-type{margin-top:4px;}
.spec-chips{display:flex;flex-wrap:wrap;gap:5px;}
.spec-chip{font-size:10.5px;background:var(--panel);border:1px solid var(--line);border-radius:5px;padding:2px 7px;color:var(--muted);}
.spec-chip b{color:var(--text);font-weight:700;}
.dori-table{width:100%;border-collapse:collapse;font-size:11px;}
.dori-table td{padding:3.5px 0;border-bottom:1px solid var(--panel-2);}
.dori-table tr:last-child td{border-bottom:none;}
.dori-table td.k{color:var(--muted);}
.dori-table td.v{text-align:right;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:700;}
.dori-bar{height:6px;border-radius:3px;margin-top:7px;display:flex;overflow:hidden;border:1px solid var(--line);}
.dori-bar i{display:block;height:100%;}
.warn{margin-top:9px;font-size:11px;line-height:1.5;border-left:3px solid var(--marca-2);
  padding:6px 9px;color:var(--warn-txt);background:var(--warn-bg);border-radius:0 5px 5px 0;}
.warn.bad{border-left-color:var(--alerta);color:var(--bad-txt);background:var(--bad-bg);}
.warn.ok{border-left-color:var(--ok);color:var(--ok-txt);background:var(--ok-bg);}
.profile-svg{width:100%;height:auto;display:block;margin-top:8px;border-radius:6px;border:1px solid var(--line);}
.ref-note{font-size:10px;color:var(--muted);margin-top:8px;line-height:1.5;}

/* ---------- MAPA ---------- */
#map-wrap{position:relative;min-width:0;overflow:hidden;}
/* z-index propio: convierte el mapa en contexto de apilamiento y con eso todos
   los controles de Leaflet (que van en 1000 dentro de su propio CSS) quedan
   confinados por debajo de los controles de la aplicación. Sin esta línea,
   cualquier ajuste de posición se vuelve a romper al expandirse un control. */
#map{width:100%;height:100%;background:var(--panel-2);position:relative;z-index:var(--z-mapa);}
.leaflet-container{font-family:inherit;background:var(--panel-2);}
.leaflet-control-attribution{font-size:9px !important;background:rgba(255,255,255,.85) !important;color:var(--muted) !important;}
.leaflet-control-attribution a{color:var(--marca-txt) !important;}
.leaflet-bar a{background:var(--bg) !important;color:var(--gris) !important;border-color:var(--line) !important;}
.leaflet-bar a:hover{background:var(--marca-suave) !important;}
.leaflet-control-layers{background:var(--bg) !important;color:var(--text) !important;border:1px solid var(--line) !important;border-radius:8px !important;}
.leaflet-control-scale-line{
  background:rgba(255,255,255,.88) !important;color:var(--gris) !important;
  border-color:var(--gris) !important;font-size:10px !important;
}

/* Franja libre entre las convenciones y la columna de botones de campo. Arriba
   no cabe: esa banda ya la ocupan el mapa base y la escala a la izquierda y el
   buscador a la derecha, y el aviso se montaba encima de alguno de los dos según
   el ancho de la ventana. */
#hint{
  position:absolute;top:auto;bottom:56px;left:12px;right:76px;text-align:center;
  background:var(--gris);border:1px solid var(--gris);color:#fff;
  padding:8px 16px;border-radius:20px;font-size:12px;font-weight:600;
  z-index:var(--z-ctl-mapa);display:none;pointer-events:none;white-space:normal;box-shadow:var(--sombra-alta);
}
#hint.show{display:block;}
#hint.exist-mode{background:var(--marca);color:var(--on-marca);border-color:var(--marca-2);}

#search-box{position:absolute;top:12px;right:12px;z-index:var(--z-ctl-alto);width:min(340px,50%);}
/* En escritorio el buscador está siempre abierto y la lupa no hace falta */
#btn-buscar{display:none;}
#btn-buscar-cerrar{display:none;}
#search-box.cargando .sb-row::after{
  content:'';position:absolute;left:0;right:0;bottom:-3px;height:2px;border-radius:2px;
  background:linear-gradient(90deg,var(--marca) 30%,transparent 30%);
  background-size:200% 100%;animation:buscando 1s linear infinite;
}
@keyframes buscando{ from{background-position:200% 0;} to{background-position:-100% 0;} }
#search-box .sb-row{display:flex;gap:6px;position:relative;}
#search-box input{
  background:rgba(255,255,255,.97);border:1px solid var(--line-2);
  padding:9px 12px;border-radius:8px;font-size:12px;box-shadow:var(--sombra);
}
#search-results{
  margin-top:5px;background:var(--bg);border:1px solid var(--line);
  border-radius:8px;overflow:hidden;max-height:280px;overflow-y:auto;display:none;
  box-shadow:var(--sombra-alta);
}
#search-results.show{display:block;}
.sr-item{padding:8px 10px;font-size:11.5px;cursor:pointer;border-bottom:1px solid var(--line);color:var(--muted);}
.sr-item:last-child{border-bottom:none;}
.sr-item:hover,.sr-item.activo{background:var(--marca-suave);color:var(--text);}
.sr-item b{color:var(--text);font-weight:700;}
.sr-item .tipo{color:var(--muted-2);}
.sr-item .aqui{color:var(--marca-txt);font-weight:600;}
.sr-item .lejos{color:var(--muted);}
.sr-item.info{cursor:default;color:var(--muted);background:var(--panel);font-size:11px;}
.sr-item.info:hover{background:var(--panel);}

/* Columna de la esquina superior izquierda. Los hijos son hermanos de un flex,
   así que no hay forma de que se solapen entre ellos ni de que haya que
   inventar un "top" que esquive al vecino. */
#ctl-tl{
  position:absolute;top:10px;left:10px;z-index:var(--z-ctl-mapa);
  display:flex;flex-direction:column;align-items:flex-start;gap:6px;max-width:calc(100% - 20px);
}
.ctl-btn{
  background:var(--bg);border:1px solid var(--line-2);box-shadow:var(--sombra);
  border-radius:8px;padding:7px 11px;font-size:11.5px;font-weight:600;color:var(--gris);
  display:flex;align-items:center;gap:6px;white-space:nowrap;
}
.ctl-btn:hover{background:var(--marca-suave);border-color:var(--marca-2);}
#map-info{
  display:flex;gap:6px;align-items:center;
  background:rgba(255,255,255,.92);border:1px solid var(--line);border-radius:8px;
  padding:5px 9px;font-size:10px;color:var(--muted);font-variant-numeric:tabular-nums;box-shadow:var(--sombra);
}
#map-legend{
  position:absolute;bottom:12px;left:12px;z-index:var(--z-ctl-mapa);
  background:rgba(255,255,255,.95);border:1px solid var(--line);
  border-radius:var(--radius);padding:9px 11px;font-size:10.5px;color:var(--muted);
  max-width:260px;max-height:44vh;overflow:auto;box-shadow:var(--sombra);
}
#map-legend > summary{
  list-style:none;cursor:pointer;user-select:none;font-size:9.5px;text-transform:uppercase;
  letter-spacing:.6px;color:var(--gris);font-weight:700;display:flex;align-items:center;gap:8px;
}
#map-legend > summary::-webkit-details-marker{display:none;}
#map-legend > summary::after{content:'⌄';margin-left:auto;transition:transform .15s;}
#map-legend[open] > summary::after{transform:rotate(180deg);}
#map-legend[open] > summary{margin-bottom:7px;}
.lg-row{display:flex;align-items:center;gap:7px;padding:2px 0;margin-top:4px;
  line-height:1.35;font-size:10.5px;color:var(--muted);}
.lg-sw{width:17px;height:9px;border-radius:2px;flex:none;border:1px solid rgba(43,43,42,.12);}
/* Las clases sueltas .dash/.limite/.rombo de la leyenda escrita a mano se
   quitaron: desde que la leyenda se genera desde CCTV.Convenciones.TABLA, la
   forma llega siempre con prefijo (.f-linea, .f-rombo…) y estas no las produce
   nadie. */

/* marcadores */
.cam-icon{
  width:30px;height:30px;border-radius:50%;border:2px solid #FFFFFF;
  display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(43,43,42,.45);
  position:relative;
}
.cam-icon.exist{border-style:dashed;}
.cam-icon svg{width:15px;height:15px;}
.cam-icon .n{
  position:absolute;left:-4px;top:-5px;background:#FFFFFF;color:var(--gris);
  border:1px solid var(--gris);border-radius:9px;padding:0 3.5px;
  font-size:9px;font-weight:700;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;line-height:12px;
}
.cam-icon .sem{
  position:absolute;right:-3px;bottom:-3px;width:10px;height:10px;border-radius:50%;
  border:1.5px solid #FFFFFF;
}
.cam-icon.sel{box-shadow:0 0 0 3px var(--marca),0 2px 7px rgba(43,43,42,.5);}
.aim-handle{width:15px;height:15px;border-radius:50%;border:2px solid #FFFFFF;box-shadow:0 1px 4px rgba(43,43,42,.5);cursor:grab;}
.cam-label{
  background:rgba(255,255,255,.95);border:1px solid var(--line-2);color:var(--text);
  padding:2px 7px;border-radius:5px;font-size:10.5px;font-weight:600;white-space:nowrap;
  box-shadow:0 2px 6px rgba(43,43,42,.25);
}
.cam-label.exist{border-style:dashed;color:var(--muted);}
.cam-label::before{display:none;}
.leaflet-tooltip.cam-hover{
  background:#FFFFFF;border:1px solid var(--marca-2);color:var(--text);
  font-size:11px;line-height:1.5;padding:6px 9px;border-radius:7px;box-shadow:var(--sombra-alta);
}
.leaflet-tooltip.cam-hover b{color:var(--gris);}
.leaflet-tooltip.cam-hover .sm{color:var(--muted);font-size:10px;}
.leaflet-tooltip.cam-hover::before{border-top-color:var(--marca-2);}
.leaflet-popup-content-wrapper{background:var(--bg);color:var(--text);border-radius:8px;border:1px solid var(--line);box-shadow:var(--sombra-alta);}
.leaflet-popup-tip{background:var(--bg);}
.leaflet-popup-content{font-size:12px;line-height:1.55;margin:10px 12px;}
.leaflet-popup-content b{color:var(--gris);}
.leaflet-popup-close-button{color:var(--muted) !important;}
.pop-spec{margin-top:6px;font-size:11px;color:var(--muted);}
.pop-spec b{color:var(--text);}
.pop-acciones{margin-top:8px;display:flex;gap:6px;flex-wrap:wrap;}
/* Los enlaces se ven y se tocan como los botones que tienen al lado */
.pop-acciones a,.ubic-enlaces a{
  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;
  border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:6px 9px;
  font-size:11.5px;font-weight:600;color:var(--text);background:transparent;
}
.pop-acciones a:hover,.ubic-enlaces a:hover{background:var(--panel-2);border-color:var(--marca-2);}
.ubic-enlaces{display:flex;gap:6px;margin-top:8px;}
.ubic-enlaces a,.ubic-enlaces button{flex:1;}
.coverage-overlay{image-rendering:pixelated;image-rendering:crisp-edges;}

/* cableado en el mapa */
.nodo-icon{width:22px;height:22px;display:flex;align-items:center;justify-content:center;}
/* El rombo lleva filo blanco por fuera del borde oscuro. Sobre el satelital, un
   borde oscuro contra un techo oscuro desaparece, y el nodo es justamente el
   punto que alguien tiene que ir a buscar al poste. */
.nodo-icon .rombo{
  width:14px;height:14px;background:var(--marca);border:2px solid var(--gris);
  transform:rotate(45deg);box-shadow:0 0 0 1.5px rgba(255,255,255,.95),0 1px 4px rgba(43,43,42,.55);
}
.nodo-icon.sel .rombo{box-shadow:0 0 0 3px var(--marca-suave),0 1px 4px rgba(43,43,42,.45);border-color:var(--marca-2);}
/* Cuántos cables van por esta cuadra. Es el número que pide el permiso de uso
   del poste, así que se escribe: no puede depender de que quien mire el plano
   alcance a distinguir tres líneas paralelas a un metro y medio de separación. */
.corredor-n{
  position:absolute;transform:translate(-50%,-50%);width:max-content;white-space:nowrap;
  background:var(--gris);color:var(--on-gris);
  font-size:9.5px;font-weight:800;letter-spacing:.2px;
  padding:2px 6px;border-radius:var(--r-full);
  border:1.5px solid rgba(255,255,255,.92);box-shadow:0 1px 4px rgba(43,43,42,.45);
  font-variant-numeric:tabular-nums;
}
.leaflet-tooltip.cable-label{
  background:rgba(255,255,255,.92);border:1px solid var(--line-2);color:var(--gris);
  font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:4px;box-shadow:none;
  font-variant-numeric:tabular-nums;
}
.leaflet-tooltip.cable-label::before{display:none;}
/* La misma pastilla, pero puesta como marcador: el tooltip de Leaflet se planta
   siempre en el centro de la línea y con cables paralelos hay que decidir dónde
   va cada rótulo. `max-content` no es opcional: el icono mide 0×0, así que sin
   eso la caja se queda del ancho del relleno y el texto se sale por un lado. */
.cable-label-m{
  position:absolute;transform:translate(-50%,-50%);width:max-content;
  background:rgba(255,255,255,.92);border:1px solid var(--line-2);color:var(--gris);
  font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:4px;
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
.v-handle{
  width:13px;height:13px;border-radius:50%;background:#FFFFFF;border:2.5px solid var(--marca-2);
  box-shadow:0 1px 3px rgba(43,43,42,.45);cursor:grab;
}
.v-handle.extremo{border-color:var(--gris);background:var(--gris);cursor:default;}
.v-add{
  width:11px;height:11px;border-radius:50%;background:rgba(255,255,255,.75);
  border:2px dashed var(--marca-2);cursor:copy;
}
.v-add:hover{background:var(--marca);}

/* pin de referencia del buscador */
.pin-ref{
  width:16px;height:16px;border-radius:50% 50% 50% 0;background:var(--marca);
  border:2px solid var(--gris);transform:rotate(-45deg);box-shadow:0 3px 8px rgba(43,43,42,.5);
}
.pin-ref::after{
  content:'';position:absolute;left:4px;top:4px;width:4px;height:4px;border-radius:50%;background:var(--gris);
}

/* ---------- MODALES ---------- */
/* El velo lleva desenfoque: separa el diálogo de lo que hay detrás mucho mejor
   que subirle la opacidad, que solo consigue tapar el contexto. */
.modal-back{
  position:fixed;inset:0;background:rgba(38,37,31,.48);z-index:var(--z-modal);
  display:none;align-items:center;justify-content:center;padding:26px;
  backdrop-filter:blur(3px) saturate(.9);
  -webkit-backdrop-filter:blur(3px) saturate(.9);
}
.modal-back.show{display:flex;animation:velo-entra .16s var(--curva);}
/* La puerta de entrada. El velo normal es translúcido y con desenfoque: detrás
   se adivinaba el mapa y las cámaras, que es justo lo que no se puede ver sin
   entrar. Aquí tapa de verdad. */
.modal-back.bloqueo{
  /* Opaco de verdad, y con algo de casa: un halo dorado bajo la tarjeta y la
     trama diagonal muy tenue de la marca. Una tarjeta flotando sola en un
     campo beige vacío es la pantalla de entrar de cualquier cosa; esto es la
     de este proyecto. */
  background:
    radial-gradient(75% 55% at 50% 40%, rgba(232,177,24,.20) 0%, transparent 70%),
    radial-gradient(120% 100% at 50% 50%, transparent 45%, rgba(78,78,76,.10) 100%),
    var(--panel);
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
/* La tarjeta de la puerta pesa más que un diálogo normal: es lo único que hay
   en pantalla y tiene que sostener el peso ella sola. */
.modal-back.bloqueo .modal{
  box-shadow:0 3px 8px rgba(60,56,44,.10),0 28px 70px rgba(60,56,44,.20);
  border-top-width:5px;
}
@keyframes velo-entra{ from{opacity:0;} to{opacity:1;} }
.modal{
  background:var(--bg);border:1px solid rgba(60,56,44,.14);border-radius:var(--r-lg);
  width:100%;max-width:520px;max-height:90vh;overflow-y:auto;padding:19px 21px 21px 21px;
  box-shadow:var(--sombra-3),0 40px 80px rgba(43,43,42,.22);
  border-top:4px solid var(--marca);
  animation:modal-entra .2s var(--curva);
}
/* Sube un pelo al aparecer. Es un detalle de dos décimas que nadie sabe
   nombrar, pero sin él el diálogo aparece de golpe y se siente barato. */
@keyframes modal-entra{ from{opacity:0;transform:translateY(10px) scale(.985);} to{opacity:1;transform:none;} }
.modal.ancho{max-width:820px;}
.modal.angosto{max-width:420px;}
.modal h2{font-size:15.5px;margin:0 0 5px 0;color:var(--gris);font-weight:650;letter-spacing:-.1px;}
.modal .sub{color:var(--muted);font-size:11.5px;margin:0 0 10px 0;line-height:1.55;}
.modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px;}
.modal-actions .sep{flex:1;}
.logo-box{
  display:flex;align-items:center;gap:9px;background:var(--panel);border:1px dashed var(--line-2);
  border-radius:var(--radius-sm);padding:8px 9px;
}
.logo-box img{max-height:38px;max-width:120px;background:#fff;border-radius:4px;padding:2px;border:1px solid var(--line);}
.logo-box .lb-txt{flex:1;min-width:0;font-size:10.5px;color:var(--muted);}

/* edición en masa */
.masa-fila{
  margin-top:12px;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:9px 10px;
}
.masa-fila > label.check{margin-bottom:7px;color:var(--gris);font-weight:600;}
.masa-fila .hint-txt{margin-top:6px;}
.row2 > .masa-fila{flex:1;min-width:0;}

/* catálogo comparativo */
.cat-tools{display:flex;gap:8px;align-items:center;margin-bottom:10px;}
.cat-tabla-wrap{max-height:52vh;overflow:auto;border:1px solid var(--line);border-radius:var(--radius-sm);}
table.cat-tabla{width:100%;border-collapse:collapse;font-size:11px;}
table.cat-tabla th{
  position:sticky;top:0;background:var(--gris);color:#fff;text-align:left;
  padding:7px 8px;font-size:9.5px;text-transform:uppercase;letter-spacing:.4px;
}
table.cat-tabla td{padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:top;color:var(--muted);}
table.cat-tabla tr:hover td{background:var(--marca-suave);color:var(--text);}
table.cat-tabla td b{color:var(--text);}
table.cat-tabla td.num{text-align:right;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}
table.cat-tabla .propio{color:var(--marca-txt);font-weight:700;}

/* atajos */
.kbd-lista{display:grid;grid-template-columns:auto 1fr;gap:7px 12px;font-size:11.5px;align-items:baseline;}
kbd{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px;
  background:var(--panel-2);border:1px solid var(--line-2);border-bottom-width:2px;
  border-radius:5px;padding:2px 6px;white-space:nowrap;color:var(--gris);
}

/* ---------- AVISOS FLOTANTES ---------- */
#toasts{position:fixed;bottom:16px;left:50%;transform:translateX(-50%);z-index:var(--z-toast);display:flex;
  flex-direction:column;gap:8px;align-items:center;pointer-events:none;}
.toast{
  background:linear-gradient(180deg,#57574F 0%,#43433F 100%);
  border-left:4px solid var(--marca);
  color:#fff;border-radius:var(--r-sm);padding:10px 15px;font-size:12px;
  box-shadow:0 2px 6px rgba(43,43,42,.28),0 14px 34px rgba(43,43,42,.28);
  max-width:560px;pointer-events:auto;line-height:1.45;
  transition:opacity .4s var(--curva);
  animation:toast-entra .22s var(--curva);
}
@keyframes toast-entra{ from{opacity:0;transform:translateY(12px);} to{opacity:1;transform:none;} }
.toast.warn{border-left-color:var(--marca);}
.toast.bad{border-left-color:var(--alerta);}
.toast.ok{border-left-color:var(--ok);}
.toast .cerrar{margin-left:10px;color:rgba(255,255,255,.7);cursor:pointer;}

/* aviso de recursos no cargados */
#sin-recursos{
  position:fixed;inset:0;z-index:var(--z-bloqueo);background:var(--bg);color:var(--text);
  display:flex;align-items:center;justify-content:center;padding:30px;text-align:center;
}
#sin-recursos .caja{max-width:560px;border:1px solid var(--alerta);border-radius:12px;padding:22px;background:var(--panel);}
#sin-recursos h2{margin:0 0 10px 0;font-size:16px;color:var(--alerta);}
#sin-recursos p{color:var(--muted);font-size:12.5px;line-height:1.7;margin:0 0 8px 0;}
#sin-recursos code{background:var(--panel-3);padding:2px 6px;border-radius:4px;font-size:11.5px;}

/* ==========================================================
   BOTONES DE CAMPO (GPS y brújula)
   ========================================================== */
/* Columna de la esquina inferior derecha: la píldora del GPS arriba y los
   botones debajo. Antes los dos estaban anclados al mismo bottom y la píldora
   terminaba encima de los botones. */
#ctl-br{
  /* 116 px: el rincón lleva zoom (58), regla (29) y atribución (14) apilados,
     y con 96 px los botones de campo quedaban rozando la atribución. */
  position:absolute;right:12px;bottom:116px;z-index:var(--z-ctl-mapa);
  display:flex;flex-direction:column;align-items:flex-end;gap:8px;
}
/* Los botones de campo (GPS, poner la cámara aquí, apuntar con la brújula)
   sólo existen en aparato táctil. En un portátil los tres estorban y dos hacen
   daño: la brújula no existe, y la geolocalización de escritorio es por IP con
   error de cientos de metros, así que usarla para fijar el poste de una cámara
   mete un error de diseño en el entregable. Encuadrar el mapa ya lo cubren
   "Encuadrar todo Chía" y "Encuadrar la sede activa", con precisión de verdad.
   Se oculta con display:none y NUNCA con hidden, remove() ni disabled: las
   pruebas leen .disabled y el ayudante de solapes descarta lo que no se pinta,
   así que así siguen valiendo sin tocarlas. Las funciones siguen exportadas. */
#campo-botones{display:none;flex-direction:column;gap:8px;}
@media (pointer:coarse),(hover:none){ #campo-botones{display:flex;} }

/* El "?" de atajos de teclado no se oculta por ancho sino por AUSENCIA DE
   TECLADO, que es la pregunta que de verdad importa. Antes vivía en la banda de
   820 px junto a .sub y #btn-proyecto —que sí se ocultan por falta de sitio, que
   es otro motivo— y por eso seguía saliendo en la Tab S6 Lite acostada (1000×600)
   y en cualquier celular en horizontal (844 px). Dos reglas separadas porque son
   dos razones separadas. La tabla de teclas del propio modal se oculta igual. */
@media (hover:none),(pointer:coarse){
  #btn-atajos, #atajos-teclado{display:none;}
}
/* Flotan sobre la foto satelital, así que necesitan una sombra de verdad: con
   la sombra floja de antes se confundían con las nubes del mapa. */
.fab{
  width:44px;height:44px;border-radius:50%;padding:0;
  background:var(--bg);border:1px solid rgba(60,56,44,.18);
  box-shadow:var(--luz),0 2px 5px rgba(43,43,42,.22),0 8px 20px rgba(43,43,42,.14);
  display:flex;align-items:center;justify-content:center;font-size:17px;line-height:1;
}
.fab:hover{
  background:var(--marca-suave);border-color:var(--marca-2);
  box-shadow:var(--luz),0 3px 8px rgba(43,43,42,.26),0 10px 24px rgba(43,43,42,.16);
}
.fab.on{
  background:var(--marca);border-color:var(--marca-2);color:var(--on-marca);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),0 2px 6px rgba(140,100,10,.35),0 8px 20px rgba(43,43,42,.16);
}
.fab[disabled]{opacity:.4;}
#campo-estado{
  max-width:min(260px,62vw);
  background:rgba(255,255,255,.95);border:1px solid var(--line);border-radius:8px;
  padding:6px 9px;font-size:10.5px;color:var(--muted);box-shadow:var(--sombra);display:none;
}
#campo-estado.show{display:block;}
#campo-estado b{color:var(--text);}
#campo-estado .mal{color:var(--bad-txt);}

/* marcador de mi posición */
.yo-punto{
  width:16px;height:16px;border-radius:50%;background:#1D6FE0;
  border:3px solid #fff;box-shadow:0 0 0 1px rgba(29,111,224,.5),0 2px 6px rgba(43,43,42,.4);
}
.yo-punto.viejo{background:var(--muted-2);}

/* ==========================================================
   PLEGADO DE LOS PANELES (escritorio)
   ========================================================== */
.pliega{
  position:absolute;top:50%;transform:translateY(-50%);z-index:var(--z-pliega);
  width:18px;height:52px;padding:0;border-radius:0 8px 8px 0;
  background:var(--bg);border:1px solid var(--line-2);border-left:none;
  color:var(--muted);font-size:13px;line-height:1;box-shadow:var(--sombra);
}
.pliega{left:0;}
.pliega.der{right:0;left:auto;border-radius:8px 0 0 8px;border:1px solid var(--line-2);border-right:none;}
.pliega:hover{background:var(--marca-suave);color:var(--gris);}
/* El plegado es cosa de escritorio: en celular los paneles son cajones y la
   rejilla tiene una sola columna. */
@media (min-width:821px){
  #app.izq-plegado{grid-template-columns:0 0 minmax(0,1fr) 5px var(--w-der);}
  #app.izq-plegado #panel-izq,#app.izq-plegado #split-izq{display:none;}
  #app.der-plegado{grid-template-columns:var(--w-izq) 5px minmax(0,1fr) 0 0;}
  #app.der-plegado #panel-der,#app.der-plegado #split-der{display:none;}
  #app.izq-plegado.der-plegado{grid-template-columns:0 0 minmax(0,1fr) 0 0;}
}

/* ==========================================================
   ASISTENTE DE PUNTO
   ========================================================== */
.modal.asistente{max-width:560px;padding:0;display:flex;flex-direction:column;max-height:92vh;}
.as-head{
  display:flex;align-items:center;gap:9px;padding:13px 16px 11px 16px;
  border-bottom:1px solid var(--line);
}
.as-tit{flex:1;min-width:0;display:flex;align-items:center;gap:9px;font-weight:700;font-size:14px;}
.as-tit .idx{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  background:var(--marca);color:var(--on-marca);border-radius:6px;padding:3px 7px;flex:none;
}
.as-pasos{display:flex;gap:4px;padding:0 16px 12px 16px;}
.as-pasos i{flex:1;height:4px;border-radius:2px;background:var(--panel-3);}
.as-pasos i.hecho{background:var(--ok);}
.as-pasos i.actual{background:var(--marca);}
.as-cuerpo{flex:1 1 auto;overflow-y:auto;padding:0 16px 16px 16px;min-height:0;}
.as-cuerpo h3{font-size:13.5px;margin:6px 0 2px 0;color:var(--gris);}
.as-cuerpo .as-ayuda{font-size:11.5px;color:var(--muted);line-height:1.55;margin-bottom:6px;}
.as-pie{
  flex:none;display:flex;gap:8px;align-items:center;padding:12px 16px;
  border-top:1px solid var(--line);background:var(--panel);
}
.as-pie #as-atras{min-width:84px;}
.as-pie #as-saltar{margin-left:auto;}
.as-pie #as-siguiente{min-width:130px;}
.as-falta{
  margin-top:10px;font-size:11.5px;line-height:1.5;color:var(--warn-txt);
  background:var(--warn-bg);border-left:3px solid var(--marca-2);padding:8px 10px;border-radius:0 6px 6px 0;
}
.as-listo{
  margin-top:10px;font-size:11.5px;line-height:1.5;color:var(--ok-txt);
  background:var(--ok-bg);border-left:3px solid var(--ok);padding:8px 10px;border-radius:0 6px 6px 0;
}
.as-resumen{display:flex;flex-direction:column;gap:5px;margin-top:8px;}
.as-resumen .fila{display:flex;gap:8px;align-items:baseline;font-size:12px;}
.as-resumen .fila .k{color:var(--muted);min-width:96px;}
.as-resumen .fila .v{font-weight:600;}
.as-resumen .fila.falta .v{color:var(--bad-txt);}
/* botón grande, pensado para el dedo */
.as-btn-grande{width:100%;padding:13px;font-size:13.5px;margin-top:8px;}

/* contador de lo que falta en la lista */
.cam-row .falta{
  flex:none;font-size:9px;font-weight:700;color:var(--warn-txt);
  background:var(--warn-bg);border:1px solid var(--marca-2);border-radius:9px;padding:0 5px;
}

/* ==========================================================
   SIN SEÑAL
   ========================================================== */
#descarga-barra{height:5px;background:var(--panel-3);border-radius:3px;margin-top:8px;display:none;overflow:hidden;}
#descarga-barra.show{display:block;}
#descarga-barra i{display:block;height:100%;width:0;background:var(--marca);transition:width .2s;}
#save-ind.offline{border-color:var(--muted);background:var(--panel-3);color:var(--gris);}
#save-ind.offline .dot{background:var(--muted);}

/* ==========================================================
   BARRA INFERIOR (celular)
   ========================================================== */
/* La barra inferior es lo único que se toca todo el día en campo: va sobre el
   mapa, así que necesita un fondo casi opaco con desenfoque —para que se vea
   que hay mapa debajo sin que estorbe— y una sombra que la despegue. */
#barra-movil{
  display:none;position:fixed;left:0;right:0;bottom:0;z-index:var(--z-barra);
  background:rgba(255,255,255,.94);border-top:1px solid var(--line);
  backdrop-filter:blur(10px) saturate(1.1);
  -webkit-backdrop-filter:blur(10px) saturate(1.1);
  padding-bottom:env(safe-area-inset-bottom);
  box-shadow:0 -1px 2px rgba(60,56,44,.06),0 -8px 26px rgba(43,43,42,.14);
}
#barra-movil button{
  flex:1;border:none;border-radius:0;background:transparent;color:var(--muted);
  padding:7px 2px 6px 2px;display:flex;flex-direction:column;align-items:center;gap:2px;
  font-size:10px;font-weight:600;position:relative;min-height:52px;box-shadow:none;
}
#barra-movil button:hover{background:transparent;box-shadow:none;}
#barra-movil button:active{transform:none;background:var(--panel-2);}
#barra-movil button .ic{font-size:17px;line-height:1;transition:transform var(--rapido);}
#barra-movil button.on{color:var(--gris);}
/* La pestaña activa levanta su icono un pelo, además del filo dorado. Con el
   pulgar encima del rótulo, el filo de arriba a veces es lo único visible. */
#barra-movil button.on .ic{transform:translateY(-1px);}
#barra-movil button.on::before{
  content:'';position:absolute;top:0;left:18%;right:18%;height:3px;
  background:var(--marca);border-radius:0 0 var(--r-xs) var(--r-xs);
  box-shadow:0 1px 6px rgba(232,177,24,.55);
}
#barra-movil .badge-n{
  position:absolute;top:4px;right:22%;background:var(--marca);color:var(--on-marca);
  border-radius:var(--r-full);padding:0 5px;font-size:9px;font-weight:700;
  box-shadow:0 1px 3px rgba(140,100,10,.35);
}

/* ---------- PANTALLAS MEDIANAS ---------- */
@media (max-width:1180px){
  /* El editor es un cajón fijo, así que sus dos columnas van en cero también al
     plegar. Sin las variantes plegadas, la regla de #app.izq-plegado (que pesa
     más por llevar clase) volvía a reservar los 410 px del editor y el mapa se
     hacía MÁS ANGOSTO al plegar el panel izquierdo. */
  #app,#app.der-plegado{grid-template-columns:var(--w-izq) 5px minmax(0,1fr) 0 0;}
  #app.izq-plegado,#app.izq-plegado.der-plegado{grid-template-columns:0 0 minmax(0,1fr) 0 0;}
  #split-der,#pliega-der{display:none;}
  #panel-der{
    position:fixed;top:var(--h-top);right:0;bottom:0;width:min(430px,92vw);
    z-index:var(--z-lateral);box-shadow:-16px 0 40px rgba(43,43,42,.25);display:none;
  }
  #panel-der.abierto{display:flex;}
}

/* ---------- CELULAR: el mapa manda ---------- */
@media (max-width:820px){
  :root{ --h-top:42px; --h-barra:56px; }
  #shell{overflow:hidden;}
  /* Una sola columna: el mapa ocupa todo y los paneles son cajones */
  #app{grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);}
  #split-izq,#split-der,#pliega-izq,#pliega-der{display:none;}
  #map-wrap{grid-column:1;grid-row:1;}
  #barra-movil{display:flex;}

  #panel-izq,#panel-der{
    position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;
    height:min(72vh,calc(100dvh - var(--h-top) - 20px));
    z-index:var(--z-cajon);border:none;border-top:1px solid var(--line);
    border-radius:16px 16px 0 0;box-shadow:0 -10px 34px rgba(43,43,42,.28);
    transform:translateY(101%);transition:transform .22s ease-out;
    padding-bottom:calc(var(--h-barra) + env(safe-area-inset-bottom));
    display:flex;
  }
  #panel-izq.abierto,#panel-der.abierto{transform:translateY(0);}
  /* Agarradera del cajón */
  #panel-izq::before,#panel-der::before{
    content:'';position:absolute;top:7px;left:50%;transform:translateX(-50%);
    width:44px;height:4px;border-radius:2px;background:var(--line-2);
  }
  #panel-izq .panel-head,#panel-der #ed-head{padding-top:18px;}
  #panel-der{height:min(80vh,calc(100dvh - var(--h-top) - 12px));}

  /* La barra superior se reduce a lo indispensable: marca corta, el guardado
     como punto de color (el texto sale al tocarlo) y deshacer/rehacer. El "?"
     no se pierde: es el botón "Más" de la barra inferior. */
  #topbar{height:var(--h-top);padding:0 8px;gap:6px;flex-wrap:nowrap;}
  #topbar h1{font-size:12.5px;}
  #topbar .marca{overflow:hidden;min-width:0;}
  #topbar h1 .largo{display:none;}
  #topbar h1 .corto{display:inline;}
  #topbar .sub,#btn-proyecto{display:none;}
  /* La sesión no se esconde como los otros dos: saber si lo que uno hace se
     está guardando importa más en campo que en el escritorio. Se reduce a un
     círculo con la inicial, del mismo tamaño que el punto de guardado. */
  #btn-sesion{display:inline-flex;align-items:center;justify-content:center;
              padding:0;width:30px;height:30px;border-radius:50%;flex:0 0 auto;}
  #btn-sesion .largo{display:none;}
  #btn-sesion .corto{display:inline;}
  /* Con sesión, el botón es un estado y basta la inicial. SIN sesión es la
     acción que hay que hacer, y un círculo con una flechita no la pide: ahí
     conserva la palabra "Entrar" aunque ocupe más. */
  #btn-sesion.warn{width:auto;padding:0 11px;border-radius:var(--r-full);}
  #btn-sesion.warn .largo{display:inline;}
  #btn-sesion.warn .corto{display:none;}
  #save-ind{padding:0;width:30px;height:30px;border-radius:50%;justify-content:center;flex:0 0 auto;}
  #save-ind #save-txt{display:none;}

  /* Controles del mapa, lejos de la barra inferior. Los botones suben lo que
     mide el rincón de la regla y la atribución, que se quedan donde están
     porque la atribución de OpenStreetMap tiene que verse siempre. */
  #ctl-br{bottom:calc(var(--h-barra) + env(safe-area-inset-bottom) + 56px);}
  .leaflet-bottom.leaflet-right{bottom:calc(var(--h-barra) + env(safe-area-inset-bottom));}
  #map-legend{bottom:calc(var(--h-barra) + env(safe-area-inset-bottom) + 10px);max-height:34vh;}

  /* El buscador arranca colapsado en una lupa: expandido ocupaba todo el ancho
     de la parte superior del mapa todo el tiempo. */
  #search-box{top:10px;right:10px;left:auto;width:auto;}
  #btn-buscar{display:flex;}
  #search-panel{display:none;}
  #search-box.abierto{left:10px;width:auto;}
  #search-box.abierto #btn-buscar{display:none;}
  #search-box.abierto #search-panel{display:block;}
  #btn-buscar-cerrar{display:block;flex:0 0 auto;}
  /* Con el buscador abierto no cabe nada más arriba: en 390 px el panel llega
     hasta el borde izquierdo y taparía la columna del mapa base. */
  #map-wrap.buscando #ctl-tl{display:none;}
  #search-results{max-height:min(52vh,340px);}

  /* El encabezado del editor no cabe en una línea de 390 px */
  .ed-acciones{flex-wrap:wrap;}
  .ed-acciones .seg{flex:1 0 100%;}
  .ed-acciones button{flex:1;}
  .ed-title input{font-size:13px;}
  /* Las pestañas se deslizan en vez de encogerse hasta ser ilegibles */
  .ed-tabs,.tabs{overflow-x:auto;-webkit-overflow-scrolling:touch;}
  .ed-tabs::-webkit-scrollbar,.tabs::-webkit-scrollbar{height:0;}
  .ed-tabs button,.tabs button{flex:0 0 auto;padding-left:12px;padding-right:12px;white-space:nowrap;}
  /* Abajo a la izquierda: arriba choca con la columna del mapa base y la escala.
     Se corta antes de la columna de botones de campo (right) y queda por encima
     del rincón de la regla gráfica y la atribución (bottom). */
  #hint{top:auto;bottom:calc(var(--h-barra) + env(safe-area-inset-bottom) + 58px);
    left:10px;right:76px;transform:none;text-align:center;white-space:normal;}

  /* Ventanas a pantalla completa */
  .modal-back{padding:0;align-items:flex-end;}
  .modal{max-width:none;max-height:96vh;border-radius:16px 16px 0 0;
    padding-bottom:calc(20px + env(safe-area-inset-bottom));}
  /* La puerta no es una hoja que sube desde abajo: no hay nada detrás de lo
     que asomarse. Va centrada y con aire, como una pantalla de entrada. */
  .modal-back.bloqueo{align-items:center;padding:16px;}
  .modal-back.bloqueo .modal{border-radius:var(--r-lg);padding-bottom:21px;}
  .modal.asistente{height:96vh;max-height:96vh;}
  .as-cuerpo{padding-bottom:8px;}

  /* Documentos: el A4 se reduce para caber en la pantalla */
  #doc-scroll{padding:10px;}
  #doc{width:210mm;transform:scale(var(--esc-doc,.45));transform-origin:top left;
    margin:0;height:calc(297mm * var(--esc-doc,.45) * var(--n-hojas,1));}
  #doc-toolbar{flex-wrap:wrap;}
}

/* ---------- DEDO EN VEZ DE MOUSE ----------
   Se aplica tanto por tipo de puntero como por ancho de pantalla: un teléfono
   siempre tiene pantalla angosta, mientras que algunos navegadores no informan
   bien el tipo de puntero. */
@media (pointer:coarse), (max-width:820px){
  button,select,input,.chip,.cam-row,.sr-item{touch-action:manipulation;}
  /* El dedo pide 40 px: se usa el token en vez de repetir el número, que estaba
     escrito seis veces en este bloque y era la razón de que --h-lg naciera sin
     usar. Un valor repetido a mano es un valor que se desincroniza. */
  button{min-height:var(--h-lg);}
  button.small{min-height:36px;}
  button.icon{min-height:var(--h-lg);min-width:var(--h-lg);}
  .chip{padding:8px 13px;font-size:12px;}
  .cam-row{padding:11px 9px;}
  .cam-row .nm{font-size:13px;}
  .chk-seg button{min-height:44px;font-size:12.5px;}
  .seg button{min-height:var(--h-lg);}
  .slider-row input[type=range]{height:34px;}
  .slider-row .num{flex-basis:74px;width:74px;min-height:38px;}
  select,input[type=text],input[type=number],input[type=search]{min-height:var(--h-lg);font-size:16px;}
  /* 16px evita que iOS haga zoom al enfocar un campo */
  textarea{font-size:16px;}
  .swatch{width:30px;height:30px;}
  /* Tiradores del mapa: con el dedo, 13 px no se agarran */
  .aim-handle{width:24px;height:24px;border-width:3px;}
  .v-handle{width:22px;height:22px;border-width:3px;}
  .v-add{width:18px;height:18px;}
  .cam-icon{width:34px;height:34px;}
  .cam-icon .n{font-size:10px;line-height:13px;}
  .leaflet-touch .leaflet-bar a{width:38px;height:38px;line-height:38px;}
  /* Los botones +/- estorban donde el pinch hace lo mismo, y competían por la
     esquina con los botones de campo. Se ocultan por CSS y no quitando el
     control: así sobreviven a la rotación de la tableta sin código de por medio. */
  .leaflet-control-zoom{display:none;}
  .sr-item{min-height:56px;display:flex;flex-direction:column;justify-content:center;}
  .ctl-btn{min-height:var(--h-lg);}
  /* Con el selector de arriba (input[type=search]) no bastaba: #search-box input
     pesa más y dejaba el campo en 12 px, que es lo que hace que iOS acerque la
     página al enfocarlo. */
  #search-box input{font-size:16px;}
}

/* ---------- PANTALLA JUSTA ----------
   Celular en cualquier orientación y tableta acostada (la Tab S6 Lite da
   1000x600, que no entra en la banda de celular pero tiene la misma falta de
   alto). Aquí se va lo que ocupa espacio sin dar información nueva. */
@media (max-width:820px), (max-height:640px){
  /* Las convenciones están duplicadas en la pestaña Capas, así que no se pierde
     nada al esconder la caja del mapa. */
  #map-legend{display:none;}
  /* El rótulo del GPS solo cuando hay algo que decir: con buena señal el dato
     sale en un toque sobre el botón de ubicación. */
  #campo-estado.nivel-normal{display:none;}
  #search-results{max-height:min(40vh,260px);}
}

/* Un chip que sigue encendido pero cuyo efecto no se ve porque otro lo anula:
   se atenúa y su title dice por qué. Es el caso de las bandas DORI cuando se
   apagan los conos, que es donde viven. */
.chip.apagado{opacity:.5;}

/* ---- convenciones generadas desde CCTV.Convenciones.TABLA ----
   La muestra toma su color de la variable --sw que pone el generador en el
   propio elemento: así el mismo HTML sirve para el color de fábrica y para el
   que el usuario eligió, sin repintar reglas. La FORMA la da la clase, porque
   distinguir una línea discontinua de un bloque relleno es lo que hace la
   leyenda legible también impresa en gris. */
.lg-row .lg-tx{flex:1;min-width:0;}
.lg-sw.f-bloque{background:var(--sw);}
.lg-sw.f-linea{background:var(--sw);height:3px;border-radius:2px;}
.lg-sw.f-discontinua{height:0;border-top:3px dashed var(--sw);background:none;}
.lg-sw.f-borde{background:transparent;border:1.5px dashed var(--sw);}
.lg-sw.f-rombo{background:var(--sw);transform:rotate(45deg) scale(.8);}
.lg-col{width:26px;height:22px;padding:0;border:1px solid var(--line);
        border-radius:var(--r-xs);background:none;cursor:pointer;flex:0 0 auto;}
.lg-reset{flex:0 0 auto;}
.lg-reset[disabled]{opacity:.3;cursor:default;}
#colores-pie{display:flex;align-items:center;gap:8px;margin-top:8px;}
#colores-pie .hint-txt{flex:1;margin:0;}

/* La barra de pestañas se desliza SÓLO donde hace falta: la regla vive en la
   banda de pantalla estrecha, más arriba. Aquí estuvo un tiempo sin media query
   y pisaba el `flex:1` del reparto en columnas iguales EN TODOS LOS ANCHOS, así
   que en escritorio las pestañas pasaron a medirse por la longitud de su texto y
   la barra se deslizaba aunque cupieran. Se ve como botones descuadrados. */

/* ---- selección con Mayús sobre las listas ----
   Al hacer Mayús+clic el navegador extiende SU selección de texto en el
   mousedown, antes de que llegue el `click` que marca el rango, y la pinta de
   azul por encima de todo. El marcado funcionaba, pero quedaba el borrón. Estas
   listas son controles, no texto para copiar, así que se comportan como los
   demás controles del proyecto —`label.check`, `.chip` y el resumen de las
   convenciones ya lo hacen— y no se seleccionan.
   El nombre de una cámara se sigue pudiendo copiar desde el editor. */
#cam-list, #ruta-list, #nodo-list, #fuente-list,
.cam-row, .ruta-row, .nodo-row, .sede-group-head{
  -webkit-user-select:none;user-select:none;
}

/* Segunda línea de una fila de lista: el tipo de nodo y su ocupación. Va dentro
   del nombre para que la fila siga siendo una sola columna flexible y no se
   descuadre cuando el texto crece. */
.cam-row .nm .sub2{display:block;font-size:10px;color:var(--muted-2);font-weight:400;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cam-row.lleno{box-shadow:inset 3px 0 0 var(--alerta);}
.cam-row .tp.alerta{color:var(--bad-txt);font-weight:700;}

/* ==========================================================
   MEDIDOR DE SEGMENTOS
   La pieza que le da carácter a esta herramienta, y sale del
   oficio y no de un catálogo de componentes: cuenta las tres
   cosas que aquí se cuentan de verdad —hilos de un cable,
   puertos de un splitter y las cinco preguntas esenciales de la
   visita— con la misma notación que usa un técnico de fibra al
   abrir una mufa.

   Va siempre acompañado de su cifra («5/12 hilos»): el color no
   puede ser el único canal, ni para quien no lo distingue ni
   para quien lo imprime en gris.
   ========================================================== */
.medidor{display:inline-flex;align-items:center;gap:6px;flex:none;}
.medidor .ticks{display:inline-flex;gap:1.5px;}
.medidor i{
  display:block;width:4px;height:11px;border-radius:1px;
  background:var(--tick-off);
  box-shadow:inset 0 0 0 .5px rgba(0,0,0,.12);
}
.medidor .cifra{
  font-family:var(--mono);font-size:10px;color:var(--muted);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* Compacto: dentro de una fila de lista o de un summary plegado */
.medidor.mini i{width:3px;height:9px;}
.medidor.mini .cifra{font-size:9.5px;}

/* Las cinco preguntas esenciales de la visita. Verde confirmado, dorado por
   confirmar, rojo faltante: los mismos tres estados del semáforo del mapa, para
   que panel y plano hablen igual. */
.medidor i.si{background:var(--ok);}
.medidor i.pend{background:var(--marca);}
.medidor i.no{background:var(--alerta);}

/* Puertos de splitter: ocupado en el gris de marca, libre apagado. No lleva
   color porque un puerto no tiene identidad, sólo está o no está usado. */
.medidor i.usado{background:var(--gris);}

/* ---- hilos: código de colores TIA-598-C ----
   El orden azul-naranja-verde-café-gris-blanco-rojo-negro-amarillo-violeta-
   rosa-aguamarina es norma internacional y lo lee de memoria cualquiera que
   haya empalmado fibra. Por eso el segmento no es decorativo: dice QUÉ hilo
   está ocupado, no sólo cuántos. Un hilo libre se apaga a --tick-off. */
.medidor i.h1{background:#1F5FBF;}   /* azul */
.medidor i.h2{background:#E2711D;}   /* naranja */
.medidor i.h3{background:#2E8B45;}   /* verde */
.medidor i.h4{background:#7A4B22;}   /* café */
.medidor i.h5{background:#8C8C8C;}   /* gris */
.medidor i.h6{background:#FFFFFF;box-shadow:inset 0 0 0 .5px var(--line-2);}  /* blanco */
.medidor i.h7{background:#C62828;}   /* rojo */
.medidor i.h8{background:#2B2B2B;}   /* negro */
.medidor i.h9{background:#E8C020;}   /* amarillo */
.medidor i.h10{background:#7B3FA0;}  /* violeta */
.medidor i.h11{background:#E48FB0;}  /* rosa */
.medidor i.h12{background:#5FC9C0;}  /* aguamarina */

/* Los dos medidores de un nodo —hilos y puertos— se apilan a la derecha de la
   fila. Apilados y no en línea: en 300 px una fila con dos medidores y sus dos
   cifras no cabe a lo ancho, y partir la cifra de su medidor los haría
   ilegibles a los dos. */
.med-par{display:flex;flex-direction:column;gap:2px;align-items:flex-end;flex:none;}

/* ==========================================================
   MÓDULOS PLEGABLES
   Cada bloque del panel es un `<details>`: en 300 px de ancho y con sesenta
   puntos, la única forma de que la lista siga a la vista es que lo que se
   consulta se aparte. Nativo y no a mano, para no perder el teclado, el lector
   de pantalla ni el Ctrl+F del navegador.
   ========================================================== */
.modulo{margin:var(--e4) 0 0 0;}
.modulo:first-child{margin-top:0;}
.modulo > summary{
  /* Hereda el aspecto del título de sección que sustituye —versalita fina con
     su filete— y le añade sólo lo justo para que se note que se abre. */
  font-size:9.5px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);
  font-weight:700;display:flex;align-items:center;gap:var(--e2);
  cursor:pointer;user-select:none;list-style:none;
  padding:var(--e1) 0;margin:0 0 var(--e2) 0;
  border-radius:var(--r-xs);
}
.modulo > summary::-webkit-details-marker{display:none;}
/* El filete que ya tenía el título: ocupa lo que sobra y separa el rótulo del
   dato de la derecha. */
.modulo > summary::after{content:'';flex:1;height:1px;background:var(--line);order:2;}
/* La marca de plegado es un signo, no un triángulo: con doce módulos en columna
   una fila de triángulos ensucia más de lo que orienta. */
.modulo > summary::before{
  content:'−';order:3;font-family:var(--mono);font-size:12px;line-height:1;
  color:var(--muted-2);width:14px;text-align:center;flex:none;
}
.modulo:not([open]) > summary::before{content:'+';}
.modulo:not([open]) > summary{color:var(--muted-2);}
.modulo > summary:hover{color:var(--text);background:var(--bg-2);}
.modulo > summary:focus-visible{outline:2px solid var(--marca-2);outline-offset:2px;}
/* Un módulo plegado tiene que seguir informando: el resumen que va en el título
   («6 nodos», «2 de 5 verificado») se queda a la vista aunque el bloque esté
   cerrado. Si hay que abrirlo para saber si tiene algo dentro, no se ahorró
   espacio: se escondió información. */
.modulo > summary .resumen{
  order:4;font-family:var(--mono);font-size:9.5px;letter-spacing:0;
  text-transform:none;color:var(--muted-2);font-weight:600;flex:none;
  font-variant-numeric:tabular-nums;
}
