/* ===========================================================================
   CRM de prospecting — Creative Socio
   Implementación del design system v1.0 sobre esta aplicación.

   NINGÚN TAMAÑO, ESPACIO, RADIO NI COLOR SE ESCRIBE A MANO: todos salen de
   un token `--cs-*` de tokens.css. Si hace falta un valor que no está, se
   agrega al archivo de tokens; no se inventa aquí. Esta regla es el archivo
   entero: la versión anterior declaraba alias sobre los tokens y después
   seguía midiendo en `.45rem` y `.72rem`, así que el sistema estaba
   enlazado pero no aplicado.

   Las únicas cifras crudas que quedan son constantes de plataforma o del
   propio design system, y van dichas donde aparecen: las alturas de botón
   pequeño y grande (36/56 px), los 49 pt de la tab bar de iOS, los 20 px
   de una casilla nativa y los 6 px del punto de un badge.

   CÓMO SE LLAMA CADA COSA
   El código de esta carpeta va en español, así que los componentes del
   design system —que la página de referencia nombra en inglés— viven aquí
   con nombre español. Es la misma pieza, no una variante:

   | design system   | aquí              | dónde se usa                  |
   |-----------------|-------------------|-------------------------------|
   | .card           | .panel            | todo bloque de contenido      |
   | .btn-secondary  | .btn              | acción neutra (el default)    |
   | .btn-primary    | .btn-primario     | la acción principal del bloque|
   | .btn-danger     | .btn-rojo         | destructivo                   |
   | .field          | .campo / <label>  | etiqueta arriba, campo abajo  |
   | .badge          | .tag              | estado de un prospecto        |
   | .metric         | .metrica          | cifra de tablero              |
   | .table-wrap     | .tabla-wrap       | tabla con marco y radio       |
   | .banner         | .aviso            | algo que hay que saber ya     |
   | .empty          | .vacio            | pantalla sin resultados       |
   | .shell-top/-nav | .barra-superior / | armazón: cabezal negro y menú |
   |                 | .menu-lateral     | lateral de 260px              |
   | .page-head      | .cabeza-pagina    | título de vista + acción      |
   | .list-row       | .fila-lista       | clave arriba, valor debajo    |
   =========================================================================== */

/* ===========================================================================
   1. BASE
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* `hidden` manda sobre cualquier `display` de este archivo.
 *
 * El navegador trae `[hidden] { display: none }`, pero con especificidad
 * (0,1,0) y desde la hoja del navegador: CUALQUIER regla de autor que
 * declare `display` le gana. `.login { display: grid }` era una de esas,
 * y por eso el panel de login se quedaba encima de la app después de
 * entrar aunque el JS le pusiera `hidden = true`. */
[hidden] { display: none !important; }

/* Tamaño de letra ajustable.
   Todo mide en rem contra esta raíz, así que mover `--escala` mueve la
   interfaz entera —tablas, botones, tabbar, cabezal— y no solo el texto
   suelto. La escala la guarda ui.js en el navegador. */
html {
  font-size: calc(16px * var(--escala, 1));
  -webkit-text-size-adjust: 100%;
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--cs-bg);
  color: var(--cs-text);
  font-family: var(--cs-font-body);
  font-size: var(--cs-text-base);
  font-weight: var(--cs-weight-regular);
  line-height: var(--cs-leading-normal);
  -webkit-font-smoothing: antialiased;
  /* cv11 da la `l` con cola y ss01 la `a` de un piso: las dos existen
     para que 1/l/I no se confundan en una tabla de teléfonos. */
  font-feature-settings: "cv11", "ss01";
}

/* Titulares: Sofia Pro Bold. El cuerpo hereda Inter de <body>.

   `font-style: normal` explícito + `font-synthesis: weight` — sin esto,
   Safari sintetiza una itálica falsa sobre "sofia-pro-variable" al pedir
   peso 700. Es un bug conocido de WebKit con fuentes variables: confunde
   qué estilos hay disponibles y de tapa sintetiza el que falta. */
h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--cs-font-display);
  font-weight: var(--cs-weight-bold);
  font-style: normal;
  font-synthesis: weight;
  /* "sofia-pro-variable" trae un eje slnt (0–10) además del wght. Safari
     lo resuelve mal cuando solo se pide font-weight: aunque el default
     del eje es 0 (recto) y el @font-face declara font-style:normal, el
     titular sale en itálica — se confirmó bajando el .woff2 real e
     inspeccionando el fvar con fontTools. Fijar el eje a mano es lo
     único que lo corrige. */
  font-variation-settings: "wght" 700, "slnt" 0;
  letter-spacing: var(--cs-tracking-display);
  line-height: var(--cs-leading-snug);
}

/* La escala de display del design system, tal cual. */
h1 { font-size: var(--cs-text-3xl); }
h2 { font-size: var(--cs-text-2xl); }
h3 { font-size: var(--cs-text-xl); letter-spacing: -0.01em; }
h4 { font-size: var(--cs-text-lg); letter-spacing: -0.01em; }

p { margin: 0; }

a { color: var(--cs-text-link); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Foco visible siempre: nunca `outline: none` sin reemplazo. */
:focus-visible {
  outline: none;
  box-shadow: var(--cs-focus-ring);
  border-radius: var(--cs-radius-sm);
}

blockquote { margin: 0; }

/* ===========================================================================
   2. TIPOGRAFÍA DE APOYO
   =========================================================================== */

.tenue  { color: var(--cs-text-secondary); }
.debil  { color: var(--cs-text-muted); font-size: var(--cs-text-sm); }
.micro  { color: var(--cs-text-muted); font-size: var(--cs-text-xs); }
.lede   { max-width: var(--cs-prose-max); color: var(--cs-text-secondary);
          line-height: var(--cs-leading-relaxed); }

/* Cifras: tabulares para que una columna de scores quede alineada. */
.num, .mono { font-variant-numeric: tabular-nums lining-nums; }
.mono { font-family: var(--cs-font-mono); font-size: var(--cs-text-sm); }

/* Un negocio cuyo sitio no es suyo — sin web, solo Instagram, o una
   página muerta de business.site. No es un error de datos: es la razón
   por la que está en la lista, así que se ve. */
.alerta { color: var(--cs-amber); font-weight: var(--cs-weight-semibold); }

/* Color de estado en un texto suelto. Existen para que ninguna plantilla
   tenga que escribir `style="color:var(--cs-red)"`: el color va en la
   hoja, no repartido por seis archivos de JavaScript. */
.t-rojo  { color: var(--cs-red); }
.t-verde { color: var(--cs-green); }
.t-ambar { color: var(--cs-amber); }

/* ===========================================================================
   3. ARMAZÓN — cabezal negro y menú lateral
   El patrón "Shell con menú lateral" del design system. El cabezal es la
   única superficie negra grande de la aplicación; el activo del menú se
   marca con relleno gris MÁS una barra negra de 4px a la izquierda: dos
   señales, no una, para que quien tenga baja visión distinga la barra
   aunque el gris se le pierda.
   =========================================================================== */

.app { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }

.barra-superior {
  position: sticky; top: 0; z-index: 60;
  display: flex; align-items: center; gap: var(--cs-space-3);
  min-height: var(--cs-topbar-height);
  padding: 0 var(--cs-space-5);
  padding-top: env(safe-area-inset-top);
  /* `--cs-tope-bg` y no `--cs-ink` directo: es el único punto donde un tema
     puede cambiar el cabezal sin tocar este archivo. En sobrio vale --cs-ink,
     que es lo de siempre. */
  background: var(--cs-tope-bg);
  color: var(--cs-tope-texto);
}

.marca {
  font-family: var(--cs-font-display);
  font-weight: var(--cs-weight-bold);
  font-style: normal;
  font-variation-settings: "wght" 700, "slnt" 0;
  font-size: var(--cs-text-base);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cs-tope-texto);
  white-space: nowrap;
}

/* Los controles del cabezal viven sobre tinta: contorno translúcido en
   vez del gris de los botones normales, que ahí no se vería. */

.btn-tope {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 36px; padding: 0 var(--cs-space-4);
  font-family: inherit; font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  color: var(--cs-tope-texto); background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.28); border-radius: var(--cs-radius-full);
  cursor: pointer; white-space: nowrap;
  transition: background var(--cs-duration-fast) var(--cs-ease);
}
.btn-tope:hover { background: rgba(255, 255, 255, 0.14); }
.btn-tope:disabled { opacity: 0.35; cursor: default; }
.btn-tope-icono { width: 36px; padding: 0; line-height: 1; }

/* El botón que abre el menú lateral en pantallas chicas. */
.abrir-menu { display: none; }

.app-cuerpo {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: var(--cs-sidebar-width) 1fr;
  align-items: start;
  min-height: 0;
}

.menu-lateral {
  position: sticky; top: var(--cs-topbar-height);
  height: calc(100dvh - var(--cs-topbar-height));
  overflow-y: auto;
  padding: var(--cs-space-4) 0 var(--cs-space-6);
  background: var(--cs-menu-bg);
  border-right: 1px solid var(--cs-border);
}

.menu-grupo {
  padding: var(--cs-space-4) var(--cs-space-5) var(--cs-space-2);
  font-size: var(--cs-text-xs); font-weight: var(--cs-weight-semibold);
  color: var(--cs-text-muted); letter-spacing: 0.04em; text-transform: uppercase;
}

.menu-item {
  display: flex; align-items: center; gap: var(--cs-space-3);
  min-height: var(--cs-tap-target);
  padding: 0 var(--cs-space-5);
  font-size: var(--cs-text-base); color: var(--cs-text);
  border-left: 4px solid transparent;
  text-decoration: none;
  transition: background var(--cs-duration-fast) var(--cs-ease);
}
.menu-item:hover { background: var(--cs-bg-subtle); text-decoration: none; }
.menu-item.activo {
  background: var(--cs-menu-activo-bg);
  border-left-color: var(--cs-menu-activo-marca);
  font-weight: var(--cs-weight-semibold);
}
.menu-item .icono { width: 1.25rem; height: 1.25rem; color: var(--cs-text-muted); }
.menu-item.activo .icono { color: var(--cs-text); }

/* El tamaño de letra y la salida, al final del menú. `.menu-salir` es un
   <button> con la cara de un enlace del menú: sin esto hereda el fondo y
   el borde del botón del navegador. */
.menu-escala {
  display: flex; align-items: center; gap: var(--cs-space-2);
  min-height: var(--cs-tap-target);
  padding: 0 var(--cs-space-5);
  font-size: var(--cs-text-base); color: var(--cs-text);
}
.menu-escala > span { flex: 1 1 auto; }
.btn-escala {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--cs-tap-target); height: var(--cs-tap-target);
  font-family: inherit; font-weight: var(--cs-weight-semibold); line-height: 1;
  color: var(--cs-text); background: var(--cs-bg);
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-full);
  cursor: pointer;
}
.btn-escala:hover { background: var(--cs-bg-subtle); }
.btn-escala:disabled { opacity: 0.35; cursor: default; }
.btn-escala.a-menos { font-size: var(--cs-text-xs); }
.btn-escala.a-mas   { font-size: var(--cs-text-lg); }
.menu-salir {
  width: 100%; font-family: inherit; text-align: left;
  background: none; border-top: 0; border-right: 0; border-bottom: 0;
  cursor: pointer;
}

/* El lienzo de trabajo va sobre gris: las tarjetas blancas con borde se
   despegan de él sin necesidad de sombra. El sistema es plano. */
main {
  min-width: 0;
  padding: var(--cs-space-6);
  background: var(--cs-bg-subtle);
  min-height: calc(100dvh - var(--cs-topbar-height));
}
.contenido { max-width: var(--cs-content-max); margin: 0 auto; }

/* Cabecera de vista: título grande a la izquierda, acción a la derecha. */
.cabeza-pagina {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cs-space-4); flex-wrap: wrap;
  margin-bottom: var(--cs-space-5);
}
.cabeza-pagina h1 { font-size: var(--cs-text-3xl); }
.cabeza-pagina .sub { margin-top: var(--cs-space-2); color: var(--cs-text-secondary); font-size: var(--cs-text-sm); }
.cabeza-pagina-acciones { display: flex; align-items: center; gap: var(--cs-space-3); flex-wrap: wrap; }

/* El velo que oscurece el contenido cuando el menú se abre en teléfono. */
.velo {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(16, 16, 16, 0.4);
}

/* ===========================================================================
   4. DISPOSICIÓN
   =========================================================================== */

.fila  { display: flex; flex-wrap: wrap; gap: var(--cs-space-3); align-items: center; }
.pila  { display: flex; flex-direction: column; gap: var(--cs-space-4); }
.crece { flex: 1 1 auto; min-width: 0; }
.rejilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--cs-space-4); }

/* Barra de filtros: cada control con su etiqueta encima, en una rejilla
   que se reparte sola. En flex se descuadraban —un <select> toma el ancho
   de su opción más larga, y "10032 — Washington Heights sur (1046)"
   arrastraba la fila entera. */
.filtros { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--cs-space-4); align-items: end; }
.filtros .ancho-2 { grid-column: span 2; }

/* Paginación: centrada, con el contador entre los dos saltos. */
.paginacion { display: flex; justify-content: center; align-items: center; gap: var(--cs-space-4); margin: var(--cs-space-5) 0 var(--cs-space-6); }

/* ===========================================================================
   5. PANELES (design system: .card)
   Plano: la jerarquía la da el borde y el relleno, nunca la sombra ni un
   color por tipo de panel. El sistema reserva el color para estado; antes
   cada panel tenía su propio borde de color (auditoría ámbar, reseñas
   rojo…) y eso era decoración, no estado.
   =========================================================================== */

.panel {
  background: var(--cs-bg);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  padding: var(--cs-space-5);
  margin-bottom: var(--cs-space-4);
}
/* Dentro de una tarjeta el título baja un escalón de la escala: el h2 de
   28px es para una sección de la página, no para el rótulo de un bloque.
   Vale igual cuando `colapsables()` lo mete dentro de un <summary>. */
.panel h2 { font-size: var(--cs-text-xl); }
/* Lo que venga debajo del título se separa de él, sea lo que sea. Antes
   solo había regla para `h2 + p`: una tabla, una rejilla o un aviso justo
   debajo del h2 quedaban pegados a su borde inferior. */
.panel > h2 + *, .panel > h3 + * { margin-top: var(--cs-space-4); }
.panel > h2 + p, .panel > h3 + p { margin-top: var(--cs-space-2); }

/* Subtítulo dentro de un panel: cuerpo, no display. Un h3 en Sofia Pro
   dentro de una tarjeta compite con el h2 que ya la titula. */
.panel h3, .sub-titulo {
  font-family: var(--cs-font-body);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--cs-text-muted);
  margin-bottom: var(--cs-space-2);
}

/* ---------- Paneles colapsables ----------
   Los arma `colapsables()` en ui.js envolviendo cada .panel en <details>.
   Se usa <details> nativo y no una clase propia porque trae gratis el
   teclado, el lector de pantalla y el "buscar en la página" del navegador,
   que abre el panel cerrado donde está la coincidencia. */
.panel > summary, .plegable > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: var(--cs-space-3);
  min-height: var(--cs-tap-target);
  margin: calc(var(--cs-space-2) * -1) 0;
  -webkit-tap-highlight-color: transparent;
}
.panel > summary::-webkit-details-marker,
.plegable > summary::-webkit-details-marker { display: none; }
.panel > summary h2, .plegable > summary > :is(h2, .fila) { flex: 1 1 auto; }
.plegable > summary > .fila { margin: 0; }

/* El icono de cada panel. Mide en `em` y hereda el color del summary: así
   sigue la escala de letra de `--escala` sin una regla propia, y no se
   queda gris cuando el título se oscurece al pasar el puntero.
   Gray 400 es el tono para iconos —no pasa AA como texto, pero aquí nunca
   carga significado solo: el título va al lado. Abierto sube a --cs-text
   para que la sección en la que estás trabajando se distinga de la pila. */
.panel > summary .panel-icono, .plegable > summary .panel-icono {
  flex: 0 0 auto;
  /* Del alto del título que acompaña: el h2 del panel mide --cs-text-xl y
     un icono más chico se leía como una viñeta perdida al lado de Sofia
     Pro en negrita. El trazo sube a 1.75 por lo mismo: a 1.5 se veía
     desteñido contra el peso del título. */
  width: var(--cs-text-2xl); height: var(--cs-text-2xl);
  stroke-width: 1.75;
  color: var(--cs-text-muted);
  transition: color var(--cs-duration-fast) var(--cs-ease);
}
.panel[open] > summary .panel-icono, .plegable[open] > summary .panel-icono,
.panel > summary:hover .panel-icono, .plegable > summary:hover .panel-icono { color: var(--cs-text); }
.panel > summary::after, .plegable > summary::after {
  content: ''; flex: 0 0 auto; width: 0.5rem; height: 0.5rem;
  border-right: 2px solid var(--cs-text-muted); border-bottom: 2px solid var(--cs-text-muted);
  transform: rotate(-45deg);
  transition: transform var(--cs-duration-fast) var(--cs-ease);
  margin-right: var(--cs-space-1);
}
.panel[open] > summary::after, .plegable[open] > summary::after { transform: rotate(45deg); }
.panel > summary:hover::after, .plegable > summary:hover::after { border-color: var(--cs-text); }
.panel-cuerpo { padding-top: var(--cs-space-4); }
/* El primer hijo del cuerpo ya tiene el aire del padding; un margin-top
   propio (muchos lo traen escrito en línea) lo duplicaba. */
.panel-cuerpo > :first-child { margin-top: 0 !important; }

/* Los <details> sueltos dentro de un panel (correcciones, "por qué está
   en la lista") comparten el acento del resumen sin ser paneles. */
.panel details:not(.plegable) > summary {
  cursor: pointer; list-style: none;
  min-height: var(--cs-tap-target);
  display: flex; align-items: center; gap: var(--cs-space-2);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  color: var(--cs-text-secondary);
}
.panel details:not(.plegable) > summary::-webkit-details-marker { display: none; }
/* `display: flex` en el summary borra el triángulo nativo, y sin nada en
   su lugar el resumen parecía un rótulo muerto. La misma flecha que usan
   los paneles, en chico. */
.panel details:not(.plegable) > summary::before {
  content: ''; flex: 0 0 auto;
  width: 0.4rem; height: 0.4rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--cs-duration-fast) var(--cs-ease);
}
.panel details:not(.plegable)[open] > summary::before { transform: rotate(45deg); }
.panel details:not(.plegable) > summary:hover { color: var(--cs-text); }

/* ===========================================================================
   6. BOTONES
   Píldora, 44px de alto, peso 600. El negro es la acción principal; el
   gris, todo lo demás. 44px no es estética: es el mínimo táctil de iOS y
   mucho de esto se toca de pie en la calle.
   =========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--cs-space-2);
  min-height: var(--cs-tap-target);
  padding: 0 var(--cs-space-5);
  font-family: var(--cs-font-body); font-size: var(--cs-text-base);
  font-weight: var(--cs-weight-semibold);
  border: 1px solid transparent; border-radius: var(--cs-radius-full);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  /* El default del sistema es el secundario: relleno gris, tinta negra. */
  background: var(--cs-bg-active); color: var(--cs-text);
  transition: background var(--cs-duration-fast) var(--cs-ease),
              color var(--cs-duration-fast) var(--cs-ease),
              border-color var(--cs-duration-fast) var(--cs-ease);
}
.btn:hover { background: var(--cs-border); text-decoration: none; color: var(--cs-text); }

.btn-primario { background: var(--cs-accion); color: var(--cs-accion-texto); }
.btn-primario:hover { background: var(--cs-accion-hover); color: var(--cs-accion-texto); }

.btn-contorno { background: transparent; color: var(--cs-text); border-color: var(--cs-border-strong); }
.btn-contorno:hover { background: var(--cs-bg-active); }

.btn-fantasma { background: transparent; color: var(--cs-text); }
.btn-fantasma:hover { background: var(--cs-bg-active); }

.btn-rojo { background: var(--cs-red); color: var(--cs-white); }
.btn-rojo:hover { background: var(--cs-red-hover); color: var(--cs-white); }

/* Verde de acción, no decorativo: en Triage y Rutas comunica "confirmado,
   se avanza", que es estado. Es el mismo verde de `cliente`. */
.btn-verde { background: var(--cs-green); color: var(--cs-white); }
.btn-verde:hover { background: var(--cs-green); color: var(--cs-white); filter: brightness(0.92); }

.btn:disabled, .btn.desactivado {
  background: var(--cs-bg-active); color: var(--cs-text-muted);
  border-color: transparent; cursor: not-allowed; filter: none;
}

.btn-sm { min-height: 36px; padding: 0 var(--cs-space-4); font-size: var(--cs-text-sm); }
.btn-lg { min-height: 56px; padding: 0 var(--cs-space-6); font-size: var(--cs-text-lg); }
.btn-bloque { width: 100%; }

/* Botón de solo icono: 44px de área aunque el trazo mida 20.
   El texto se va al title y al aria-label, así que el lector de pantalla
   sigue diciendo qué hace. */
.btn-icono {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--cs-tap-target); height: var(--cs-tap-target);
  padding: 0; background: transparent;
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-full);
  color: var(--cs-text-secondary); cursor: pointer;
  transition: background var(--cs-duration-fast) var(--cs-ease),
              color var(--cs-duration-fast) var(--cs-ease),
              border-color var(--cs-duration-fast) var(--cs-ease);
}
.btn-icono:hover { background: var(--cs-bg-active); color: var(--cs-text); }
.btn-icono .icono { width: 1.25rem; height: 1.25rem; }
.btn-icono-rojo:hover { background: var(--cs-red); border-color: var(--cs-red); color: var(--cs-white); }

/* Iconos inline (Lucide, trazo 2px vía currentColor). */
.icono { width: 1em; height: 1em; stroke: currentColor; fill: none; vertical-align: -0.15em; flex: none; }

/* ===========================================================================
   7. FORMULARIOS
   La etiqueta va SIEMPRE encima del campo, nunca dentro como placeholder:
   el placeholder desaparece al escribir y la persona pierde la referencia.
   El <label> que envuelve un control se convierte solo en ese patrón, así
   que las plantillas no tienen que aprender una clase nueva.
   =========================================================================== */

.campo,
label:has(> input:not([type="checkbox"]):not([type="radio"])),
label:has(> select),
label:has(> textarea) {
  display: flex; flex-direction: column; gap: var(--cs-space-2);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  color: var(--cs-text);
}
.campo > .debil, .campo > .micro,
label > .debil, label > .micro { font-weight: var(--cs-weight-regular); }

input, select, textarea {
  width: 100%; min-width: 0;
  min-height: var(--cs-tap-target);
  padding: var(--cs-space-3) var(--cs-space-4);
  font-family: var(--cs-font-body); font-size: var(--cs-text-base);
  font-weight: var(--cs-weight-regular);
  color: var(--cs-text); background: var(--cs-bg);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-md);
  transition: border-color var(--cs-duration-fast) var(--cs-ease);
}
textarea { min-height: 110px; resize: vertical; line-height: var(--cs-leading-normal); }
input::placeholder, textarea::placeholder { color: var(--cs-text-muted); }
input:hover, select:hover, textarea:hover { border-color: var(--cs-border-strong); }

/* El foco es negro, no azul: el azul es el color del enlace y de la
   información, y un anillo azul en cada campo lo gasta. */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--cs-focus);
  box-shadow: 0 0 0 1px var(--cs-focus);
}
input[aria-invalid="true"] { border-color: var(--cs-red); box-shadow: 0 0 0 1px var(--cs-red); }
input:disabled, select:disabled, textarea:disabled {
  background: var(--cs-bg-subtle); color: var(--cs-text-muted); cursor: not-allowed;
}

/* La flecha va dibujada: `appearance:none` quita la nativa y con ella el
   indicador de que esto se puede desplegar.
   El max-width es imprescindible — un <select> toma de ancho el de su
   opción más larga, y "10032 — Washington Heights sur (1046)" es
   larguísima: en el teléfono el control se salía del panel. */
select {
  appearance: none; -webkit-appearance: none;
  max-width: 100%;
  /* La flecha ocupa 12px a 12px del borde: 32px de reserva la despejan
     sin comerle ancho al texto. Con los 48px de --cs-space-7 que pide la
     página de referencia, "Solo prospectables" se cortaba en el filtro
     de Universo — ahí el control es angosto y la etiqueta, larga. */
  padding-right: var(--cs-space-6);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23101010' stroke-width='1.8' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--cs-space-3) center;
}

/* Casilla: la etiqueta es la fila entera, no solo el cuadrito de 20px. */
.check, label:has(> input[type="checkbox"]) {
  display: flex; align-items: center; gap: var(--cs-space-3);
  min-height: var(--cs-tap-target);
  font-size: var(--cs-text-base); font-weight: var(--cs-weight-regular);
  cursor: pointer;
}
input[type="checkbox"], input[type="radio"] {
  width: 20px; height: 20px; min-height: 0; min-width: 0;
  margin: 0; padding: 0; flex: none;
  accent-color: var(--cs-accion);
}

/* Un grupo de opciones excluyentes que se toca con el pulgar: los radios
   nativos son de 20px y aquí hay que acertarles de pie en la calle. */
.opciones { display: flex; gap: var(--cs-space-2); }
.opciones label {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: center;
  min-height: var(--cs-tap-target); padding: 0 var(--cs-space-2);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-medium);
  text-align: center;
  background: var(--cs-bg); color: var(--cs-text-secondary);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-md);
  cursor: pointer;
  transition: background var(--cs-duration-fast) var(--cs-ease),
              border-color var(--cs-duration-fast) var(--cs-ease);
}
.opciones input { position: absolute; opacity: 0; pointer-events: none; }
.opciones label:hover { border-color: var(--cs-border-strong); }
.opciones label:has(input:checked) {
  background: var(--cs-accion); border-color: var(--cs-accion); color: var(--cs-accion-texto);
  font-weight: var(--cs-weight-semibold);
}
/* "—" es "todavía no respondida", no una respuesta.
   Con el relleno de tinta de arriba, las señales sin contestar se
   veían como decisiones tomadas con el máximo énfasis de la
   página. El negro queda reservado para haber elegido algo. */
.opciones label:has(input[value=""]:checked) {
  background: var(--cs-bg-active); border-color: var(--cs-border-strong);
  color: var(--cs-text-muted); font-weight: var(--cs-weight-medium);
}

.error { color: var(--cs-red); font-size: var(--cs-text-sm); font-weight: var(--cs-weight-medium); }
.ayuda { color: var(--cs-text-muted); font-size: var(--cs-text-xs); font-weight: var(--cs-weight-regular); }

/* ===========================================================================
   8. ETIQUETAS DE ESTADO (design system: .badge)
   Nueve etapas, nueve matices. Un estado no es decoración: es el dato que
   más se consulta de un prospecto, así que el color aquí comunica y no
   adorna —que es justo lo que el design system reserva para el color.

   Antes las cinco primeras eran grises que se oscurecían. Con la palabra
   al lado se leía bien, pero el mismo color viaja al marcador del mapa,
   donde no hay palabra: ahí "auditado", "contactado" y "conversación"
   quedaban a 2.18:1 y 1.15:1 entre sí, o sea el mismo punto negro tres
   veces. El mapa es donde el estado más importa —decide a quién visitas
   hoy— y era donde peor se distinguía.

   La progresión sigue leyéndose en orden: frío al entrar (gris, azul),
   trabajo en curso al medio (violeta, ámbar, teal), calor al cerrar
   (naranja, verde), y el cliente con relleno pleno porque es el único
   estado que ya no es una promesa. "Descartado" no es un paso más
   adelante sino una salida, y se ve hueco.

   `mapa.js` repite estos mismos valores en los marcadores; si aquí
   cambia uno, allá también.
   =========================================================================== */

.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: var(--cs-space-1) var(--cs-space-3);
  border: 1px solid transparent; border-radius: var(--cs-radius-sm);
  font-size: var(--cs-text-xs); font-weight: var(--cs-weight-semibold);
  line-height: 1.5; white-space: nowrap;
}
.tag::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

.e-cantera      { background: var(--cs-est-cantera-bg);      color: var(--cs-est-cantera-txt);      border-color: var(--cs-border); }
.e-shortlist    { background: var(--cs-est-shortlist-bg);    color: var(--cs-est-shortlist-txt); }
.e-auditado     { background: var(--cs-est-auditado-bg);     color: var(--cs-est-auditado-txt); }
.e-contactado   { background: var(--cs-est-contactado-bg);   color: var(--cs-est-contactado-txt); }
.e-conversacion { background: var(--cs-est-conversacion-bg); color: var(--cs-est-conversacion-txt); }
.e-propuesta    { background: var(--cs-est-propuesta-bg);    color: var(--cs-est-propuesta-txt); }
.e-piloto       { background: var(--cs-est-piloto-bg);       color: var(--cs-est-piloto-txt); }
/* El único con relleno pleno: es el final del embudo y el único estado
   que ya no es una promesa. Que pese más que los demás es el punto. */
.e-cliente      { background: var(--cs-est-cliente-bg);      color: var(--cs-est-cliente-txt); }
.e-descartado   { background: transparent; color: var(--cs-text-muted); border-color: var(--cs-border-strong); }
/* Cerrado no es peligro, es apagado: gris, no rojo. El rojo además
   colapsaba contra el ámbar de contactado en deuteranopia (ΔE 1.2).
   El tachado es la señal que NO depende del color, y es la que separa
   "cerró el local" de "yo lo descarté". */
.e-sin_interes   { background: transparent; color: var(--cs-text-muted); border: 1px dashed var(--cs-border-strong); }
/* Habló con el dueño y dijo que no: salida del embudo como descartado, pero
   con borde discontinuo para separar "yo lo descarté" de "él me dijo que no". */
.e-cerrado      { background: var(--cs-est-cerrado-bg); color: var(--cs-est-cerrado-txt); text-decoration: line-through; }

/* Los bloques que apagaste en Configuración. No es seguridad —los datos
   los sigue guardando `exigir_sesion()` en cada endpoint— es tu pantalla:
   quitar de la vista lo que no usas. El servidor los nombra en
   <html data-apagado="…">. */
.e-vencido      { background: var(--cs-red-bg); color: var(--cs-red); }

/* La etiqueta de la cabecera de la ficha es un <select>: el estado es lo
   que más se toca y estaba enterrado en un panel colapsado. Conserva las
   clases .e-* para conservar su color, y crece a 44px porque ahora es un
   control, no un adorno. */
.tag-select {
  appearance: none; -webkit-appearance: none;
  width: auto; min-height: 36px;
  padding: 0 var(--cs-space-6) 0 var(--cs-space-3);
  /* Borde siempre visible, no solo al pasar el cursor: `cantera` se pinta
     sobre gris-50, que contra el gris de la mesa es casi el mismo tono, y
     sin marco la etiqueta parecía texto suelto en vez de un desplegable.
     El color del texto y del relleno los sigue poniendo la clase .e-*. */
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-sm);
  font-size: var(--cs-text-xs); font-weight: var(--cs-weight-semibold);
  cursor: pointer;
  background-repeat: no-repeat;
  background-position: right var(--cs-space-3) center;
  background-size: 10px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='currentColor' stroke-width='1.8' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
}
.tag-select:hover { border-color: var(--cs-border-strong); }
.tag-select:focus { outline: none; box-shadow: var(--cs-focus-ring); }

/* ===========================================================================
   9. MÉTRICAS (design system: .metric)
   La cifra manda: Sofia Pro grande, etiqueta pequeña arriba, variación
   debajo. El orden importa — la etiqueta primero prepara la lectura del
   número, y el número es lo que se recuerda.
   =========================================================================== */

/* El mismo margen inferior que `.panel`, y por la misma razón: la rejilla
   de métricas es un bloque del flujo vertical como cualquier otro. Sin
   esto solo tenía separación quien se la escribiera a mano, así que Hoy
   la parcheaba con space-5, Metas con space-6, y Clientes y Pantallas se
   quedaban pegados al panel de abajo — sin borde entre medio, la primera
   tarjeta del panel parece parte de la fila de métricas.
   Un ritmo vertical que depende de acordarse no es un ritmo. */
.metricas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--cs-space-4);
  margin-bottom: var(--cs-space-4);
}

.metrica {
  background: var(--cs-bg);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  padding: var(--cs-space-5);
}
.metrica-k { font-size: var(--cs-text-sm); font-weight: var(--cs-weight-medium); color: var(--cs-text-secondary); }
.metrica-v {
  margin-top: var(--cs-space-2);
  font-family: var(--cs-font-display); font-size: var(--cs-text-4xl);
  font-weight: var(--cs-weight-bold); font-style: normal;
  font-variation-settings: "wght" 700, "slnt" 0;
  letter-spacing: var(--cs-tracking-display); line-height: 1.05;
  font-variant-numeric: tabular-nums lining-nums;
}
.metrica-v .de { font-family: var(--cs-font-body); font-size: var(--cs-text-lg);
                 font-weight: var(--cs-weight-medium); color: var(--cs-text-muted); }
.metrica-d { margin-top: var(--cs-space-2); font-size: var(--cs-text-sm); color: var(--cs-text-muted); }
.metrica-d.sube { color: var(--cs-green); }
.metrica-d.baja { color: var(--cs-red); }

/* Progreso contra una meta. Negro mientras falta, verde cuando llegó:
   el color aparece solo para decir algo, no para dibujar la barra. */
.barra-meta {
  height: 6px; margin-top: var(--cs-space-3);
  background: var(--cs-border); border-radius: var(--cs-radius-full); overflow: hidden;
}
.barra-meta > div { height: 100%; background: var(--cs-accion); border-radius: var(--cs-radius-full); }
.barra-meta.lograda > div { background: var(--cs-green); }

/* ===========================================================================
   10. TABLAS
   El identificador va en negrita con el dato de apoyo debajo, no en una
   columna aparte: ahorra ancho y se lee mejor en teléfono.
   =========================================================================== */

.tabla-wrap {
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  overflow: hidden;
  background: var(--cs-bg);
  margin-bottom: var(--cs-space-4);
}
.tabla-scroll { overflow-x: auto; }

table { width: 100%; border-collapse: collapse; font-size: var(--cs-text-sm); }
thead th {
  text-align: left;
  padding: var(--cs-space-3) var(--cs-space-4);
  background: var(--cs-bg-subtle);
  font-weight: var(--cs-weight-semibold); color: var(--cs-text-secondary);
  white-space: nowrap;
  border-bottom: 1px solid var(--cs-border);
}
tbody td {
  padding: var(--cs-space-4);
  border-bottom: 1px solid var(--cs-border);
  vertical-align: middle;
}
tbody tr:last-child td { border-bottom: 0; }
/* Un rótulo de grupo dentro de una tabla (las familias de Servicios). */
tbody tr.fila-grupo th {
  padding: var(--cs-space-4) var(--cs-space-4) var(--cs-space-2);
  text-align: left; font-size: var(--cs-text-xs); font-weight: var(--cs-weight-semibold);
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--cs-text-secondary);
  background: var(--cs-bg-subtle); border-bottom: 1px solid var(--cs-border);
}
tbody tr[data-id]:hover { background: var(--cs-bg-subtle); cursor: pointer; }
th.der, td.der { text-align: right; font-variant-numeric: tabular-nums lining-nums; }

.celda-titulo { font-weight: var(--cs-weight-semibold); color: var(--cs-text); }
.celda-sub { margin-top: 2px; color: var(--cs-text-muted); font-size: var(--cs-text-xs); }

/* Tabla sin marco, para listas dentro de un panel que ya tiene el suyo. */
.tabla-desnuda { border: 0; border-radius: 0; margin-bottom: 0; }

/* ===========================================================================
   11. AVISOS (design system: .banner)
   Para algo que la persona debe saber ahora mismo. El badge dice el estado
   de un registro; el aviso interrumpe.
   =========================================================================== */

.aviso {
  display: flex; align-items: flex-start; gap: var(--cs-space-3);
  padding: var(--cs-space-4);
  border-radius: var(--cs-radius-md);
  font-size: var(--cs-text-sm); line-height: var(--cs-leading-relaxed);
  color: var(--cs-text);
  margin-bottom: var(--cs-space-4);
}
.aviso b { display: block; font-weight: var(--cs-weight-semibold); margin-bottom: 2px; }
/* Un aviso puede ser el enlace a lo que hay que resolver. Sigue siendo un
   aviso, no un enlace: ni azul ni subrayado. */
a.aviso, a.aviso:hover { color: var(--cs-text); text-decoration: none; }
.aviso-punto {
  width: 20px; height: 20px; border-radius: 50%; flex: none; margin-top: 1px;
  display: grid; place-items: center;
  color: var(--cs-white); font-size: 12px; font-weight: var(--cs-weight-bold);
}
.aviso-info    { background: var(--cs-blue-bg); }
.aviso-info    .aviso-punto { background: var(--cs-blue); }
.aviso-exito   { background: var(--cs-green-bg); }
.aviso-exito   .aviso-punto { background: var(--cs-green); }
.aviso-alerta  { background: var(--cs-amber-bg); }
.aviso-alerta  .aviso-punto { background: var(--cs-amber); }
.aviso-peligro { background: var(--cs-red-bg); }
.aviso-peligro .aviso-punto { background: var(--cs-red); }

/* ===========================================================================
   12. VACÍO Y CARGA
   Una pantalla vacía es una invitación a hacer algo, no una disculpa.
   =========================================================================== */

.vacio {
  text-align: center;
  padding: var(--cs-space-8) var(--cs-space-5);
  border: 1px dashed var(--cs-border-strong);
  border-radius: var(--cs-radius-lg);
  background: var(--cs-bg);
  margin-bottom: var(--cs-space-4);
}
.vacio h3 { font-family: var(--cs-font-display); font-size: var(--cs-text-xl); }
.vacio p {
  max-width: 44ch; margin: var(--cs-space-2) auto var(--cs-space-5);
  color: var(--cs-text-secondary); font-size: var(--cs-text-sm);
}
.vacio p:last-child { margin-bottom: 0; }

/* Dentro de una tabla el vacío es una celda, no una tarjeta: sin marco
   propio o quedaría un recuadro punteado dentro de otro recuadro. */
td.vacio, td.cargando { border: 0; background: transparent; }

.cargando { padding: var(--cs-space-6); text-align: center; color: var(--cs-text-muted); font-size: var(--cs-text-sm); }

/* ===========================================================================
   13. TOAST
   =========================================================================== */

.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: max(var(--cs-space-5), env(safe-area-inset-bottom));
  z-index: 100;
  padding: var(--cs-space-3) var(--cs-space-5);
  background: var(--cs-accion); color: var(--cs-accion-texto);
  border-radius: var(--cs-radius-full);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-medium);
  box-shadow: var(--cs-shadow-modal);
}
.toast.err { background: var(--cs-red); }

/* ===========================================================================
   14. PIEZAS PROPIAS DEL CRM
   =========================================================================== */

/* ---------- Score: la barrita comunica magnitud más rápido que el número.
   El relleno es negro por defecto; verde y ámbar solo cuando el score
   cruza un umbral que significa algo. ---------- */
.score {
  display: inline-flex; align-items: center; gap: var(--cs-space-2);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  font-variant-numeric: tabular-nums lining-nums;
}
.score-barra {
  display: inline-block; width: 44px; height: 6px;
  background: var(--cs-border); border-radius: var(--cs-radius-full); overflow: hidden;
}
/* Tinta, no gris. Con `--cs-gray-400` sobre `--cs-gray-200` el relleno daba
   1.69:1 contra su propio canal: invisible. Y como los umbrales son los
   percentiles reales (p90/p75), tres de cada cuatro filas caen justo en ese
   estado sin clase — la barra volvía a no decir nada, ahora por lo bajo. */
.score-relleno { display: block; height: 100%; background: var(--cs-accion); border-radius: var(--cs-radius-full); }
.score-medio .score-relleno { background: var(--cs-amber); }
.score-alto  .score-relleno { background: var(--cs-green); }

.estrellas { color: var(--cs-amber); letter-spacing: -1px; }

/* ---------- Filas de detalle (design system: .list-row) ----------
   Clave arriba, valor debajo, todo el bloque tocable. Funciona igual bien
   con 4 campos que con 40. */
.filas { border-top: 1px solid var(--cs-border); }
.fila-lista {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--cs-space-4);
  min-height: var(--cs-tap-target);
  padding: var(--cs-space-4) 0;
  border-bottom: 1px solid var(--cs-border);
  color: inherit; text-decoration: none;
}
.fila-lista:hover { text-decoration: none; }
.fila-lista .k { font-weight: var(--cs-weight-semibold); font-size: var(--cs-text-base); }
.fila-lista .v { margin-top: 2px; color: var(--cs-text-muted); font-size: var(--cs-text-base); }
.fila-lista .chev { color: var(--cs-text-muted); flex: none; }

/* ---------- Triage: un mazo de cartas, no una tabla ---------- */
.triage { max-width: 560px; margin: 0 auto; }
.triage-progreso {
  text-align: center; color: var(--cs-text-muted);
  font-size: var(--cs-text-sm); margin-bottom: var(--cs-space-4);
}
.triage-nombre {
  font-family: var(--cs-font-display); font-size: var(--cs-text-2xl);
  font-weight: var(--cs-weight-bold); font-style: normal;
  font-variation-settings: "wght" 700, "slnt" 0;
  letter-spacing: var(--cs-tracking-display); line-height: var(--cs-leading-snug);
}
.triage-meta { margin-top: var(--cs-space-2); color: var(--cs-text-secondary); font-size: var(--cs-text-sm); }

.motivos { list-style: none; padding: 0; margin: var(--cs-space-4) 0 0; }
.motivos li {
  display: flex; gap: var(--cs-space-2);
  padding: var(--cs-space-2) 0;
  font-size: var(--cs-text-sm); color: var(--cs-text-secondary);
  border-top: 1px solid var(--cs-border);
}
.motivos li::before { content: "+"; color: var(--cs-green); font-weight: var(--cs-weight-bold); flex: none; }
.motivos li.pendiente::before { content: "?"; color: var(--cs-amber); }

.triage-acciones { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--cs-space-2); }
.triage-acciones .btn {
  flex-direction: column; gap: 2px;
  min-height: 64px; padding: var(--cs-space-2) var(--cs-space-1);
  font-size: var(--cs-text-sm);
}
.tecla { font-size: var(--cs-text-xs); font-weight: var(--cs-weight-regular); opacity: 0.65; font-family: var(--cs-font-mono); }

/* ---------- Los dos embeds, en Triage y en la Ficha ----------
   Misma pieza en las dos vistas, así que mismas reglas: apilados en
   teléfono y lado a lado en escritorio. Se cambió flex con `wrap` por
   grid porque el reparto por wrap dependía de un `flex-basis` que había
   que adivinar contra el ancho del panel —560px en Triage, el ancho de
   la ficha en la otra—, y el punto de quiebre caía en sitios distintos
   en cada vista. Con grid el corte es uno solo y es el mismo del resto
   del armazón: 760px.

   Un <iframe> mide 300px de ancho intrínseco y como hijo de grid respeta
   ese mínimo, así que `min-width: 0` sigue siendo imprescindible: sin él
   una columna de 1fr no baja de 300px y las dos se salen del panel. */
.triage-mapas, .ubicacion-mapas {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--cs-space-4);
  align-items: stretch;
  margin-top: var(--cs-space-4);
}

.triage-streetview, .ubicacion-embed {
  width: 100%; min-width: 0; height: 240px;
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-md);
}

@media (min-width: 761px) {
  .triage-mapas, .ubicacion-mapas { grid-template-columns: 1fr 1fr; }
}

/* ---------- Ubicación en la ficha ----------
   El Street View de Google a veces tiene años. Cuando hay foto del día
   ocupa exactamente el mismo hueco: el ojo compara mejor si nada se
   mueve de sitio.

   La rejilla y el tamaño de los embeds los pone la regla compartida con
   Triage, más arriba. Acá solo queda lo propio de la ficha: la columna
   que envuelve la vista con su botón de foto debajo. */
.ubicacion-vista { display: flex; flex-direction: column; gap: var(--cs-space-3); min-width: 0; }
.ubicacion-vista .ubicacion-embed { object-fit: cover; }
/* El <label> hace de botón del input file, que va oculto: el control
   nativo no se puede estilar y en el teléfono se ve fuera de lugar. */
.ubicacion-acciones label.btn { cursor: pointer; }

/* ---------- Pipeline kanban ---------- */
.kanban { display: flex; gap: var(--cs-space-4); overflow-x: auto; padding-bottom: var(--cs-space-2); }
.columna {
  flex: 0 0 260px;
  background: var(--cs-bg);
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-lg);
  overflow: hidden;
}
.columna-cabeza {
  display: flex; align-items: center; justify-content: space-between; gap: var(--cs-space-2);
  padding: var(--cs-space-3) var(--cs-space-4);
  background: var(--cs-bg-subtle);
  border-bottom: 1px solid var(--cs-border);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-semibold);
  color: var(--cs-text-secondary);
}
.columna-conteo { font-variant-numeric: tabular-nums; color: var(--cs-text-muted); }
.columna-cuerpo { padding: var(--cs-space-3); min-height: 120px; max-height: 65vh; overflow-y: auto; }
.tarjeta {
  background: var(--cs-bg);
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-md);
  padding: var(--cs-space-3); margin-bottom: var(--cs-space-2);
  cursor: grab; font-size: var(--cs-text-sm);
}
.tarjeta:hover { border-color: var(--cs-border-strong); }
.tarjeta:active { cursor: grabbing; }
.tarjeta.arrastrando { opacity: 0.4; }
.columna.destino { outline: 2px dashed var(--cs-accion); outline-offset: -3px; }

/* ---------- Auditoría: las señales ---------- */
.senal { padding: var(--cs-space-4) 0; border-bottom: 1px solid var(--cs-border); }
.senal:last-of-type { border-bottom: 0; }
.senal-texto { font-size: var(--cs-text-base); font-weight: var(--cs-weight-medium); }
.senal-nota { margin: var(--cs-space-1) 0 var(--cs-space-3); color: var(--cs-text-muted); font-size: var(--cs-text-sm); }

/* ---------- Citas de reseña ---------- */
.cita {
  padding: var(--cs-space-3) var(--cs-space-4);
  margin-bottom: var(--cs-space-3);
  background: var(--cs-bg-subtle);
  border-left: 3px solid var(--cs-border-strong);
  border-radius: 0 var(--cs-radius-md) var(--cs-radius-md) 0;
  font-size: var(--cs-text-sm);
}
.cita-meta { margin-top: var(--cs-space-2); color: var(--cs-text-muted); font-size: var(--cs-text-xs); }

/* ---------- Notas del negocio ----------
   Una bitácora: cada nota es una tarjeta sin marco, separada por una línea,
   con la fecha arriba. El texto sale de `markdown()` en ui.js. */
.notas-lista { margin-top: var(--cs-space-5); }
.nota { padding: var(--cs-space-4) 0; border-top: 1px solid var(--cs-border); }
.nota-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--cs-space-2);
  font-size: var(--cs-text-xs); color: var(--cs-text-muted);
  margin-bottom: var(--cs-space-2);
}

/* El Markdown pintado. Ancho de lectura y el ritmo del cuerpo: una nota se
   lee de corrido. Los títulos arrancan en h4 (ver `markdown()`). */
.md { max-width: var(--cs-prose-max); overflow-wrap: anywhere; }
.md > * + * { margin-top: var(--cs-space-3); }
.md :is(h4, h5, h6) { font-weight: var(--cs-weight-semibold); }
/* Tres tamaños distintos: con el mismo para los tres, ## y ### se veían
   iguales a # y no servía de nada escribirlos. */
.md h4 { font-size: var(--cs-text-xl); }
.md h5 { font-size: var(--cs-text-lg); }
.md h6 { font-size: var(--cs-text-base); color: var(--cs-text-secondary); }
.md ul, .md ol { margin-bottom: 0; padding-left: var(--cs-space-5); }
.md li + li { margin-top: var(--cs-space-1); }
.md li.md-tarea { list-style: none; margin-left: calc(var(--cs-space-5) * -1); }
.md blockquote {
  margin-left: 0; padding-left: var(--cs-space-4);
  border-left: 3px solid var(--cs-border-strong); color: var(--cs-text-secondary);
}
.md code {
  font-family: var(--cs-font-mono); font-size: 0.9em;
  padding: 0 var(--cs-space-1); border-radius: var(--cs-radius-sm);
  background: var(--cs-bg-subtle);
}
.md hr { border: 0; border-top: 1px solid var(--cs-border); }
.md a { text-decoration: underline; }

/* ---------- Horario ---------- */
.tabla-horario { border-collapse: collapse; width: auto; }
.tabla-horario th, .tabla-horario td {
  padding: var(--cs-space-2) var(--cs-space-5) var(--cs-space-2) 0;
  text-align: left; font-size: var(--cs-text-sm); border: 0;
}
.tabla-horario th { font-weight: var(--cs-weight-semibold); white-space: nowrap; }
.tabla-horario tr.hoy th, .tabla-horario tr.hoy td { color: var(--cs-text); font-weight: var(--cs-weight-semibold); }

/* ---------- Mapa ---------- */
#mapa {
  height: 68dvh; min-height: 320px;
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-lg);
  background: var(--cs-bg-active);
  overflow: hidden;
}
.leyenda { display: flex; flex-wrap: wrap; gap: var(--cs-space-4); margin-top: var(--cs-space-3); }
.leyenda span { display: inline-flex; align-items: center; gap: 6px; font-size: var(--cs-text-xs); color: var(--cs-text-secondary); }
.leyenda i { width: 9px; height: 9px; border-radius: 50%; border: 1px solid var(--cs-border-strong); }
/* Lo que cambia el dibujo y no los datos: va aparte de los filtros para
   que no parezca que necesita "Actualizar mapa". */
.mapa-ver { display: flex; flex-wrap: wrap; gap: var(--cs-space-5); align-items: end; margin-top: var(--cs-space-4); }
.leyenda .leyenda-grupo { gap: var(--cs-space-3); }
.leyenda .leyenda-muestra { flex: none; background: transparent; border-color: var(--cs-text-secondary); }
/* La cifra bajo el punto. Un halo blanco en vez de caja: se lee sobre
   calles y parques sin tapar el punto de al lado. */
.mapa-cifra { white-space: nowrap; text-shadow: 0 0 2px #FFFFFF, 0 0 2px #FFFFFF, 0 0 3px #FFFFFF; }

/* ---------- Duplicados (vista Datos) ---------- */
.duplicado {
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-md);
  padding: var(--cs-space-4); margin-bottom: var(--cs-space-3);
}

/* ===========================================================================
   15. LOGIN
   =========================================================================== */

.login { display: grid; place-items: center; min-height: 100vh; min-height: 100dvh;
         padding: var(--cs-space-5); background: var(--cs-bg-subtle); }
.login-caja {
  width: 100%; max-width: 380px;
  padding: var(--cs-space-6);
  background: var(--cs-bg);
  border: 1px solid var(--cs-border); border-radius: var(--cs-radius-lg);
  display: flex; flex-direction: column; gap: var(--cs-space-4);
}
.login-caja h1 { font-size: var(--cs-text-2xl); }
.login-sub { margin-top: calc(var(--cs-space-2) * -1); color: var(--cs-text-muted); font-size: var(--cs-text-sm); }

/* ===========================================================================
   16. BARRA DE TABS (solo pantallas chicas)
   En un 6.7" el pulgar no llega arriba sin recolocar el teléfono, así que
   los cinco destinos de campo viven abajo y el resto entra por el menú
   lateral. La barra mide 80px —por encima de los 49pt del sistema— porque
   esto se toca de pie en la calle, a veces con guantes.
   =========================================================================== */

.tabbar { display: none; }

/* ===========================================================================
   17. RESPONSIVE
   =========================================================================== */

@media (max-width: 760px) {
  /* El menú lateral deja de ocupar columna y pasa a ser un cajón. */
  .app-cuerpo { grid-template-columns: 1fr; }
  .abrir-menu { display: inline-flex; }

  .menu-lateral {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 58;
    width: min(320px, 86vw); height: 100dvh;
    padding-top: calc(var(--cs-space-4) + env(safe-area-inset-top));
    transform: translateX(-100%);
    transition: transform var(--cs-duration-base) var(--cs-ease);
    box-shadow: var(--cs-shadow-modal);
  }
  .menu-lateral.abierta { transform: translateX(0); }
  .menu-item { min-height: 52px; }

  main {
    padding: var(--cs-space-4);
    /* Que el último panel no quede tapado por la barra de tabs: los 80px
       de la barra más un respiro. El hueco se reserva aunque la barra
       esté escondida — si el padding cambiara con ella, el contenido
       saltaría en cada scroll. */
    padding-bottom: calc(80px + var(--cs-space-4) + env(safe-area-inset-bottom));
    min-height: auto;
  }

  .panel { padding: var(--cs-space-4); }
  .cabeza-pagina h1 { font-size: var(--cs-text-2xl); }
  .metrica { padding: var(--cs-space-4); }
  .metrica-v { font-size: var(--cs-text-3xl); }
  .triage-acciones { grid-template-columns: repeat(2, 1fr); }

  /* La tabla es lo que más se lee de pie en la calle: se aprieta el
     relleno, no la letra. */
  thead th { padding: var(--cs-space-2) var(--cs-space-3); }
  tbody td { padding: var(--cs-space-3); }
  .ocultar-movil { display: none; }

  /* Dos filtros por fila, con la búsqueda a lo ancho.
     `auto-fit` con mínimo de 190px cae a una sola columna en 390px, y
     siete filtros en fila única empujaban la tabla media pantalla hacia
     abajo. A dos columnas caben en cuatro filas y el primer resultado
     vuelve a estar cerca: en la calle, filtrar y ver es un mismo gesto. */
  .filtros { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--cs-space-3); }

  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: grid; grid-template-columns: repeat(6, 1fr);
    background: var(--cs-bg); border-top: 1px solid var(--cs-border);
    /* El indicador de inicio del iPhone se come la última franja: sin
       esto, el tab de más abajo queda debajo de la barra del sistema. */
    padding-bottom: env(safe-area-inset-bottom);
    /* Se esconde al bajar y vuelve al subir; lo conmuta `app.js`.
       Con `transform` y no con `bottom` porque mover una barra fija por
       su posición reflowea la página en cada cuadro: en un teléfono de
       gama media eso se ve a saltos. El transform va en la GPU. */
    transition: transform var(--cs-duration-base) var(--cs-ease);
    will-change: transform;
  }
  /* El 100% incluye el padding de la safe area, así que la barra sale
     entera de la pantalla y no deja una franja blanca flotando abajo. */
  .tabbar.oculta { transform: translateY(100%); }

  .tabbar a, .tabbar-mas {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--cs-space-1);
    min-height: 80px; padding: var(--cs-space-1);
    font-family: var(--cs-font-body);
    font-size: var(--cs-text-xs); font-weight: var(--cs-weight-medium);
    color: var(--cs-text-muted); background: none; border: 0;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .tabbar a:hover { text-decoration: none; }
  .tabbar a.activo, .tabbar-mas[aria-expanded="true"] { color: var(--cs-text); font-weight: var(--cs-weight-semibold); }
  .tabbar-i { width: 2rem; height: 2rem; }
}

@media (min-width: 761px) {
  /* En escritorio el cajón nunca está abierto ni hay velo que cerrar. */
  .velo { display: none !important; }
}

/* Safari hace zoom al enfocar cualquier campo de menos de 16px, y ese zoom
   no se deshace solo: la vista queda corrida el resto de la sesión. 16px
   es el umbral exacto, no una preferencia estética. Con la escala grande
   el max() sube, pero nunca baja de ahí. */
@media (max-width: 640px) {
  input, select, textarea { font-size: max(16px, var(--cs-text-base)); }
}

/* ===========================================================================
   18. IMPRESIÓN
   La ficha tiene un botón "Imprimir auditoría": lo que sale del papel es
   el expediente del negocio, no la aplicación. Fuera el armazón, fuera los
   controles, y los paneles colapsados se abren —en pantalla se cierran
   para llegar antes a la auditoría; en papel se quiere todo.
   =========================================================================== */

/* Lo que solo tiene sentido en papel: en pantalla ya se ve en su campo
   editable (las notas de un proyecto, por ejemplo). */
.solo-imprimir { display: none; }

@media print {
  .barra-superior, .menu-lateral, .tabbar, .velo, .toast,
  .btn, .btn-icono, .cabeza-pagina-acciones { display: none !important; }

  /* Controles de pantalla: buscadores, altas, selects de trabajo. */
  .no-imprimir { display: none !important; }
  .solo-imprimir { display: block !important; }
  /* Una tabla ancha —la comparación de un proyecto con varios
     competidores— no puede quedar cortada en el borde de la hoja por el
     scroll. `.tabla-scroll` es el que scrollea, pero es `.tabla-wrap` el
     que la encierra con `overflow: hidden` para redondearle la esquina
     en pantalla (línea 708): sin soltarlo también, seguía recortando las
     columnas de más a la derecha aunque `.tabla-scroll` ya no scrolleara. */
  .tabla-scroll, .tabla-wrap { overflow: visible !important; }

  /* La comparación es la razón de imprimir un proyecto, y una columna por
     competidor no entra de pie en una carta vertical. `page:` la aísla en
     una página con nombre: solo ESA tabla imprime en horizontal, el resto
     del proyecto —y la auditoría, y la propuesta, que comparten esta hoja
     de estilos— sigue en vertical. */
  .tabla-comparacion { page: comparacion; }
  .tabla-comparacion table { font-size: 8.5px; table-layout: fixed; width: 100%; }
  .tabla-comparacion th, .tabla-comparacion td { padding: 3px 6px; word-break: break-word; }
  .tabla-comparacion thead th:first-child, .tabla-comparacion tbody th[scope="row"] { width: 18%; }
  .tabla-comparacion tr { break-inside: avoid; }

  /* Los formularios de ALTA no aportan en papel: son campos vacíos. */
  #form-auditoria, #form-actividad, #form-resena, #form-alta { display: none !important; }

  /* El banco de preguntas SÍ va, y solo se le quitan los controles.
     Esta regla decía `form` a secas, y como cada una de las nueve
     preguntas es un <form> (ficha.js:565) con la respuesta guardada
     dentro, "Imprimir auditoría" sacaba una hoja SIN una sola respuesta
     de campo — justo el contenido que el botón promete. */
  .senal textarea, .senal button, .senal input, .senal select { display: none !important; }

  body, main { background: var(--cs-white); }
  main { padding: 0; min-height: 0; }
  .app-cuerpo { display: block; }

  .panel {
    border: 0; border-top: 1px solid var(--cs-border);
    border-radius: 0; padding: var(--cs-space-4) 0; margin: 0;
    break-inside: avoid;
  }
  .panel > summary::after, .plegable > summary::after { display: none; }
  /* El icono orienta al buscar una sección en pantalla; en papel no hay
     nada que buscar y el gris claro sale como una mancha. */
  .panel > summary .panel-icono, .plegable > summary .panel-icono { display: none; }
  /* Un <details> cerrado esconde su contenido desde la hoja del
     navegador; en papel se fuerza abierto. */
  .panel-cuerpo { display: block !important; }

  .tabla-wrap { border-radius: 0; }
  a { color: var(--cs-ink); text-decoration: none; }
}

/* Página con nombre para `.tabla-comparacion` (arriba): un `@page` no se
   anida de forma confiable dentro de `@media print` entre motores, así que
   va aparte. Sin `page:` asignado en ningún elemento, esta regla no le
   cambia el tamaño a nada más. */
@page comparacion { size: landscape; margin: 12mm; }

/* ===========================================================================
   FILTRO DE VARIOS VALORES (.multi)
   Un <details> que se comporta como un desplegable de casillas. No es un
   <select multiple>: ese, en el teléfono, es una caja de alto fijo donde un
   toque mal dado borra toda la selección.
   El resumen dice qué hay elegido sin abrirlo, que es lo que un filtro
   cerrado tiene que poder contestar.
   =========================================================================== */

.multi { position: relative; }

/* El resumen imita al <select>: mismo alto, mismo borde, misma flecha
   dibujada. Es un control de filtro más, no un acordeón.

   `details.multi` y no `.multi` a secas: los filtros viven dentro de un
   .panel, y `.panel details > summary` —pensado para los "por qué está en
   la lista"— pesa más y les ponía su flecha y su negrita encima. */
details.multi > summary {
  display: flex; align-items: center;
  min-height: var(--cs-tap-target);
  padding: var(--cs-space-3) var(--cs-space-6) var(--cs-space-3) var(--cs-space-4);
  font-size: var(--cs-text-base); font-weight: var(--cs-weight-regular);
  /* El interlineado de los controles de formulario, no el del cuerpo: con
     el del cuerpo el resumen medía 4px más que el <select> de al lado y la
     fila de filtros quedaba escalonada. */
  line-height: normal;
  color: var(--cs-text); background: var(--cs-bg);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-md);
  cursor: pointer; list-style: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23101010' stroke-width='1.8' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--cs-space-3) center;
}
details.multi > summary::-webkit-details-marker { display: none; }
details.multi > summary::before { content: none; }
details.multi > summary::marker { content: ''; }
details.multi > summary:hover { color: var(--cs-text); border-color: var(--cs-border-strong); }
details.multi[open] > summary { border-color: var(--cs-focus); box-shadow: 0 0 0 1px var(--cs-focus); }

/* Una sola línea: con tres zipcodes elegidos el resumen no puede empujar
   la rejilla de filtros ni partirse en dos renglones. */
.multi-resumen { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Flota por encima en vez de empujar: abrir un filtro no puede mover de
   sitio a los otros seis. */
.multi-caja {
  position: absolute; z-index: 20; top: calc(100% + var(--cs-space-2));
  left: 0; right: 0; min-width: 15rem;
  padding: var(--cs-space-3);
  background: var(--cs-bg);
  border: 1px solid var(--cs-border-strong); border-radius: var(--cs-radius-md);
  box-shadow: var(--cs-shadow-popover);
}
.multi-buscar { margin-bottom: var(--cs-space-2); }

/* 94 rubros no caben en pantalla: la lista scrollea dentro del desplegable
   y la caja de búsqueda se queda arriba, fija. */
.multi-ops { max-height: 17rem; overflow-y: auto; }

.multi-op {
  display: flex; align-items: center; gap: var(--cs-space-3);
  min-height: var(--cs-tap-target);
  padding: 0 var(--cs-space-2);
  font-size: var(--cs-text-base); font-weight: var(--cs-weight-regular);
  border-radius: var(--cs-radius-sm);
  cursor: pointer;
}
.multi-op:hover { background: var(--cs-bg-subtle); }
/* Una sola línea, siempre.
   El desplegable de zipcodes pegaba el barrio completo detrás del número
   —"10033 — Washington Heights (corredor 181)"— y cada opción ocupaba
   cuatro líneas: con cinco zipcodes la lista era ilegible. El nombre
   corto arregla el largo; esto arregla la estructura, para que el
   próximo texto largo no vuelva a partirla. El completo sigue en el
   `title`. */
.multi-texto {
  flex: 1 1 auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.multi-sub { margin-left: var(--cs-space-2); font-size: var(--cs-text-sm); }
/* El conteo a la derecha, tabular, para que las cifras se comparen de un
   vistazo en vez de bailar según el ancho del dígito. */
.multi-n { flex: none; font-variant-numeric: tabular-nums; font-size: var(--cs-text-sm); }

.multi-limpiar { width: 100%; margin-top: var(--cs-space-2); }

/* En el teléfono la caja se sale del panel si hereda el ancho del control:
   se ancla al lado izquierdo y se deja crecer hasta donde haya sitio. */
/* En el teléfono cada filtro de casillas ocupa la fila entera. En media
   columna la caja se salía de la pantalla cuando el filtro caía a la
   derecha, y con la fila entera la caja tiene el ancho del control. */
@media (max-width: 560px) {
  .filtros > [data-multi] { grid-column: 1 / -1; }
  .multi-caja { min-width: 0; }
}

/* La etiqueta de un filtro con una acción a la derecha ("Ordenar A–Z"). */
.campo-cabeza { display: flex; align-items: baseline; justify-content: space-between; gap: var(--cs-space-2); }
/* Parece enlace porque es una acción secundaria sobre la lista, no un
   filtro: el azul es el color del enlace en el sistema. El relleno vertical
   agranda la zona de toque sin cambiar cómo se ve. */
.orden-rubros {
  padding: var(--cs-space-2) 0; margin: calc(-1 * var(--cs-space-2)) 0;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--cs-text-sm); font-weight: var(--cs-weight-regular);
  color: var(--cs-blue); white-space: nowrap;
}
.orden-rubros:hover { color: var(--cs-blue-hover); text-decoration: underline; }

/* --- Selección en lote de la Lista -------------------------------------
   Barra pegada abajo, no arriba: es donde llega el pulgar en un teléfono,
   y así no pelea con el panel de filtros. Solo aparece con el modo de
   selección puesto. */
.barra-lote {
  position: sticky; bottom: 0; z-index: 20;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--cs-space-3);
  padding: var(--cs-space-3) var(--cs-space-4);
  margin-top: var(--cs-space-4);
  background: var(--cs-bg);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-md);
  box-shadow: var(--cs-shadow-popover);
}
.barra-lote input, .barra-lote select { flex: 1 1 10rem; min-width: 0; }
.barra-lote-cuenta { flex: none; font-size: var(--cs-text-sm); }

/* En modo selección la fila entera es el blanco táctil: un cuadrito de
   20 px no se acierta de pie en la calle. El cursor lo dice. */
.en-lote tbody tr { cursor: pointer; }
.fila-elegida > td { background: var(--cs-bg-subtle); }
.fila-elegida > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--cs-blue);
}

/* Casilla con su texto al lado, alineada como un campo más del panel de
   filtros. */
.casilla {
  display: flex; align-items: center; gap: var(--cs-space-2);
  min-height: var(--cs-tap-target);
  font-size: var(--cs-text-sm);
}
.casilla input { width: auto; flex: none; }

/* --- Rubros cruzados y etiquetas en la ficha --------------------------- */
.campo-grupo { margin-top: var(--cs-space-5); }
.etiqueta-campo {
  display: block; margin-bottom: var(--cs-space-2);
  font-size: var(--cs-text-sm); font-weight: var(--cs-weight-medium);
  color: var(--cs-text-muted);
}
.fila-tags {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--cs-space-2);
}
/* La sugerencia se ve como lo que es: algo que todavía no decidiste. */
.tag-sugerido {
  background: transparent;
  border: 1px dashed var(--cs-border-strong);
  color: var(--cs-text-muted);
}
.tag-quitable, .tag-sugerido { display: inline-flex; align-items: center; gap: var(--cs-space-2); }
.tag-x, .tag-si {
  border: 0; background: transparent; cursor: pointer; padding: 0;
  font-size: var(--cs-text-base); line-height: 1; color: inherit;
  /* Un blanco táctil de verdad: estos botones se tocan con el pulgar. */
  min-width: var(--cs-space-5); min-height: var(--cs-space-5);
}
.tag-si { color: var(--cs-green); }
.tag-x:hover { color: var(--cs-red); }

/* La confianza de un hallazgo se lee sin abrir nada: lo oficial y lo
   estimado no pesan igual en una conversación con un dueño. */
.tag-oficial     { background: var(--cs-green-bg);   color: var(--cs-green); }
.tag-secundaria  { background: var(--cs-bg-subtle);     color: var(--cs-text-muted); }
.tag-estimado    { background: var(--cs-amber-bg);color: var(--cs-amber); }
.tag-propio      { background: var(--cs-blue-bg);    color: var(--cs-blue); }

/* ===========================================================================
   CONFIGURACIÓN
   =========================================================================== */

/* Los bloques apagados. La regla se genera desde `data-apagado` del <html>,
   que escribe el servidor con los nombres ya cruzados contra la lista
   blanca de `BLOQUES_APAGABLES`. */
html[data-apagado~="metricas"]        .metricas,
html[data-apagado~="panel-mercado"]   .panel-mercado,
html[data-apagado~="panel-ubicacion"] .panel-ubicacion,
html[data-apagado~="panel-rubros"]    .panel-rubros,
html[data-apagado~="panel-pantallas"] .panel-pantallas,
html[data-apagado~="panel-dinero"]    .panel-dinero,
html[data-apagado~="panel-auditoria"] .panel-auditoria,
html[data-apagado~="panel-actividad"] .panel-actividad,
html[data-apagado~="panel-resenas"]   .panel-resenas,
html[data-apagado~="panel-horario"]   .panel-horario,
html[data-apagado~="panel-notas"]     .panel-notas,
html[data-apagado~="panel-fuentes"]   .panel-fuentes { display: none; }

.temas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--cs-space-4);
  margin-top: var(--cs-space-5);
}

/* Cada tema es un botón, no una tarjeta con un radio escondido: lo que se
   toca es toda la muestra, que en un teléfono es la diferencia entre
   acertar y no. */
.tema {
  display: flex; flex-direction: column; gap: var(--cs-space-2);
  padding: var(--cs-space-4);
  text-align: left;
  background: var(--cs-bg);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-lg);
  cursor: pointer;
  font: inherit; color: var(--cs-text);
  transition: border-color var(--cs-duration-fast) var(--cs-ease);
}
.tema:hover { border-color: var(--cs-border-strong); }
.tema-puesto { border-color: var(--cs-text); border-width: 2px; padding: calc(var(--cs-space-4) - 1px); }

/* La muestra enseña los tres colores que definen el tema: fondo, texto y
   acento. Es la única forma honesta de elegir sin probarlos todos. */
.tema-muestra { display: flex; height: 44px; border-radius: var(--cs-radius-md); overflow: hidden;
  border: 1px solid var(--cs-border); }
.tema-muestra > span { flex: 1; }
.tema-nombre { display: flex; align-items: center; gap: var(--cs-space-2);
  font-family: var(--cs-font-display); font-weight: var(--cs-weight-bold);
  font-size: var(--cs-text-lg); }
.tema-de { font-family: var(--cs-font-mono); font-size: var(--cs-text-xs);
  color: var(--cs-text-muted); }
.tema-para { font-size: var(--cs-text-sm); line-height: var(--cs-leading-normal); }

.rejilla-opciones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--cs-space-3);
  margin-top: var(--cs-space-5);
}
.opcion-config {
  display: flex; align-items: flex-start; gap: var(--cs-space-3);
  min-height: var(--cs-tap-target);
  padding: var(--cs-space-3);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-md);
  cursor: pointer;
}
.opcion-config:hover { background: var(--cs-bg-subtle); }
.opcion-config input { margin-top: 2px; flex: none; }
.opcion-config > span { display: flex; flex-direction: column; gap: 2px; }
.opcion-config .debil { font-size: var(--cs-text-sm); }
/* Apagado se lee apagado: la fila entera baja de peso cuando se desmarca. */
.opcion-config:has(input:not(:checked)) { opacity: 0.55; }

/* ===========================================================================
   19. PROPUESTAS
   La de tres opciones de Estrategia/09-Plantilla-Propuesta. En pantalla
   se arma en columnas; en papel sale el documento (.doc-propuesta), que
   solo existe al imprimir.
   =========================================================================== */

.opcion-propuesta {
  display: flex; flex-direction: column; gap: var(--cs-space-3);
  padding: var(--cs-space-4);
  border: 1px solid var(--cs-border);
  border-radius: var(--cs-radius-md);
}
/* La recomendada se distingue por el borde, no por un color nuevo: el
   acento del tema ya dice "esto es lo principal" en el botón primario. */
.opcion-recomendada { border-color: var(--cs-accion); border-width: 2px;
  padding: calc(var(--cs-space-4) - 1px); }

.lineas-propuesta { list-style: none; margin: 0; padding: 0; }
.lineas-propuesta li {
  display: flex; align-items: center; gap: var(--cs-space-3);
  padding: var(--cs-space-2) 0;
  border-bottom: 1px solid var(--cs-border);
}
.lineas-propuesta li:last-child { border-bottom: 0; }

/* El documento. Siempre en claro, como el resto de lo impreso: va a un
   dueño, no a quien tenga puesto el tema oscuro. */
.doc-propuesta { color: var(--cs-ink); font-size: var(--cs-text-base);
  line-height: var(--cs-leading-relaxed); }
.doc-propuesta section { margin-bottom: var(--cs-space-7); break-inside: avoid-page; }
.doc-propuesta h1 { font-size: var(--cs-text-4xl); margin: var(--cs-space-2) 0 var(--cs-space-5); }
.doc-propuesta h2 { font-size: var(--cs-text-2xl); margin-bottom: var(--cs-space-4); }
.doc-propuesta h3 { font-size: var(--cs-text-lg); margin: var(--cs-space-4) 0 var(--cs-space-2); }
.doc-propuesta ul, .doc-propuesta ol { padding-left: var(--cs-space-5); }
.doc-portada { break-after: page; padding-top: var(--cs-space-9); }
.doc-pre { font-size: var(--cs-text-sm); letter-spacing: var(--cs-tracking-wide);
  text-transform: uppercase; color: var(--cs-gray-600); }
.doc-opciones { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--cs-space-4); }
.doc-opcion { border: 1px solid var(--cs-gray-300); border-radius: var(--cs-radius-md);
  padding: var(--cs-space-4); break-inside: avoid; }
.doc-recomendada { border: 2px solid var(--cs-ink); }
.doc-cifra { font-size: var(--cs-text-xl); font-weight: var(--cs-weight-bold); }
.doc-tabla { width: 100%; border-collapse: collapse; margin-bottom: var(--cs-space-4); }
.doc-tabla td { padding: var(--cs-space-2) 0; border-bottom: 1px solid var(--cs-gray-200); }
.doc-pie { margin-top: var(--cs-space-7); padding-top: var(--cs-space-3);
  border-top: 1px solid var(--cs-gray-300); font-size: var(--cs-text-xs); color: var(--cs-gray-600); }

/* ===========================================================================
   20. TRÁFICO
   El contador se usa de pie en la acera, con una mano y sin mirar: dos
   botones que llenan el ancho, con la cifra grande adentro.
   =========================================================================== */

.contador { display: grid; grid-template-columns: 1fr 1fr; gap: var(--cs-space-4);
  margin: var(--cs-space-5) 0 var(--cs-space-3); }
.contador-boton {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--cs-space-2);
  min-height: calc(var(--cs-tap-target) * 3);
  border: 2px solid var(--cs-border-strong); border-radius: var(--cs-radius-lg);
  background: var(--cs-bg-subtle); color: var(--cs-text);
  font-size: var(--cs-text-lg); font-weight: var(--cs-weight-semibold);
  cursor: pointer; touch-action: manipulation; user-select: none;
}
.contador-boton:active { background: var(--cs-bg-active); }
.contador-entra { border-color: var(--cs-accion); }
.contador-cifra { font-family: var(--cs-font-mono); font-size: var(--cs-text-5xl);
  line-height: var(--cs-leading-tight); }

/* El nombre de una fila es un enlace de verdad (pestaña nueva, menú
   contextual), pero se lee como el título de la fila, no como un link. */
a.enlace-fila { color: inherit; }

/* Encabezado que ordena la tabla. Hereda todo del <th>: el botón solo
   existe para que se pueda tocar y leer con lector de pantalla. */
.th-orden {
  display: inline-flex; align-items: center; gap: var(--cs-space-1);
  padding: 0; border: 0; background: none;
  font: inherit; color: inherit; cursor: pointer; white-space: nowrap;
}
th.der .th-orden { flex-direction: row-reverse; }
.th-flecha { color: var(--cs-text-muted); font-size: var(--cs-text-xs); }
.th-flecha::after { content: '↕'; opacity: 0; }
.th-orden:hover .th-flecha::after,
.th-orden:focus-visible .th-flecha::after { opacity: 1; }
th[aria-sort="ascending"] .th-flecha::after { content: '▲'; opacity: 1; }
th[aria-sort="descending"] .th-flecha::after { content: '▼'; opacity: 1; }
th[aria-sort="ascending"], th[aria-sort="descending"] { color: var(--cs-text); }

/* Configuración → Orden de la Ficha: una fila por panel, con sus flechas. */
.lista-orden { list-style: none; margin: var(--cs-space-4) 0 0; padding: 0; }
.lista-orden li { padding: var(--cs-space-2) 0; border-bottom: 1px solid var(--cs-border); }
.lista-orden li:last-child { border-bottom: 0; }
.lista-orden .btn-icono:disabled { opacity: .35; cursor: default; }

/* Referencia de Markdown bajo la caja de notas. Dos columnas iguales: con
   el ancho automático, el código de la izquierda (que no se parte) dejaba
   la columna "Se ve" de tres letras en el teléfono. */
.tabla-md { table-layout: fixed; }
.tabla-md th, .tabla-md td { width: 50%; }
.tabla-md code { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ===========================================================================
   EXPORTAR A PDF (exportarPDF() en ui.js)
   =========================================================================== */

/* Mientras dura la exportación el mapa se dibuja a un tamaño fijo que cabe
   en una carta apaisada con 10 mm de margen (≈ 980 px). Se fija en
   pantalla, no solo en la hoja: el navegador imprime los mosaicos que ya
   pintó Google, y lo que no se pintó sale gris. */
#mapa.mapa-pdf { width: 960px !important; height: 540px !important; min-height: 0; max-width: none; }

@media print {
  /* Solo va lo que la exportación marcó; el resto de la vista, fuera. */
  body.pdf-solo #vista > :not(.pdf-incluir) { display: none !important; }
  body.pdf-solo #vista { page: apaisada; }
  /* Los controles de ver y filtrar no son parte del mapa. La leyenda, sí. */
  body.pdf-solo :is(.filtros, .mapa-ver, .ubicacion-acciones) { display: none !important; }
  body.pdf-solo .leyenda { margin-top: 0; }
  body.pdf-solo #mapa { border-radius: 0; break-inside: avoid; }

  .encabezado-pdf { margin-bottom: var(--cs-space-4); }
  .encabezado-pdf h1 { font-size: var(--cs-text-2xl); }
  .encabezado-pdf p { margin-top: var(--cs-space-1); font-size: var(--cs-text-sm); }
}

/* Aparte del @media por lo mismo que `comparacion`: un @page anidado no es
   confiable entre motores. Safari ignora `size`; ahí se elige la
   orientación en el diálogo. */
@page apaisada { size: landscape; margin: 10mm; }

/* ---------- Cartas con QR ---------- */
.qr-bloque { display: flex; flex-wrap: wrap; gap: var(--cs-space-5); align-items: flex-start; padding: var(--cs-space-4) 0; }
/* Fondo blanco fijo, también en los temas oscuros: un QR sobre fondo oscuro no se escanea. */
.qr-dibujo { width: 168px; flex: none; background: #fff; border: 1px solid var(--cs-border); border-radius: var(--cs-radius-md); line-height: 0; }
.qr-dibujo svg { width: 100%; height: auto; display: block; }
.qr-datos { flex: 1 1 260px; min-width: 0; }
.qr-datos .mono { word-break: break-all; }
.qr-codigo { font-size: var(--cs-text-2xl); font-weight: var(--cs-weight-semibold); letter-spacing: .08em; }
.fila-qr[hidden] { display: none; }
.qr-datos .fila { margin-top: var(--cs-space-3); }
