/* ==================================================================
   estilo.css — Sistema de diseño Pixelia Norte
   Marca: #096B61 (teal) · #0F8043 (verde) · #002454 (azul noche)
   Industrial, sobrio. Radio 6px, sin degradados, iconos SVG (no emojis).
   ================================================================== */

/* ==================================================================
   PALETA - identidad Pixelia Soluciones (19 ago 2026)
   Los tokens --px-* son los del encargo, con sus valores EXACTOS. Debajo, los
   nombres viejos (--azul, --gris-1...) apuntan a ellos: se usan en linea dentro
   de 15 ficheros PHP y renombrarlos era tocar todos para no ganar nada.

   OJO CON EL CONTRASTE, que aqui esta la unica licencia que me tome:
   el encargo pide "contraste alto" y una interfaz para estar horas delante, y
   a la vez pide #12A99F de fondo con texto blanco. Eso da 2.92:1, cuando AA
   pide 4.5. No se pueden tener las dos cosas. Solucion: NINGUN token del
   encargo cambia de valor; se anaden dos derivados para los sitios donde el
   blanco va ENCIMA del color (boton primario y item activo del menu).
   --px-teal se sigue usando tal cual en barras, graficas, iconos y bordes,
   que es donde el encargo lo luce.
   ================================================================== */
:root {
  /* --- tokens del encargo, sin tocar --- */
  --px-teal:       #12A99F;
  --px-teal-dark:  #068179;   /* como TEXTO 4.75:1. Antes #078C84 = 4.12 */
  --px-teal-soft:  #E7F7F4;
  --px-mint:       #D8F0EA;
  --px-blue:       #1595E8;
  --px-ink:        #18304A;
  --px-text-muted: #63707B;
  --px-surface:    #FFFFFF;
  --px-page:       #F8FBFA;
  --px-border:     #DCEAE7;
  --px-warning:    #D89017;
  --px-danger:     #D95C5C;
  --px-success:    #18A56D;

  /* --- derivados: SOLO donde el blanco va encima del color --- */
  --px-teal-light: #37BDB4;   /* acentos claros, nunca con texto encima */
  --px-teal-solid: #0E8179;   /* blanco encima: 4.74:1, cumple AA */
  --px-teal-press: #0A6058;   /* su hover */

  /* --- derivados de TEXTO ---------------------------------------------
     Misma historia que --px-teal-solid, al reves: el token vivo luce en
     barras, iconos y graficas, pero PUESTO COMO TEXTO no llega a AA.
     Medido sobre el fondo real de cada chapa (el tinte compuesto sobre
     blanco Y sobre --px-page, que es lo que hay debajo segun la pantalla):

       --px-warning #D89017 sobre su chapa .... 2.30:1   NO
       --px-danger  #D95C5C sobre su chapa .... 3.16:1   NO
       --px-teal-solid      sobre su chapa .... 4.08:1   NO
       --px-teal-dark #078C84 sobre blanco .... 4.12:1   NO  (corregido arriba)

     Estos si, con margen sobre los dos fondos: */
  --px-warning-txt: #91600F;  /* chapa ambar 4.68 · blanco 5.41 */
  --px-danger-txt:  #AB4949;  /* chapa roja  4.72 · blanco 5.55 */
  --px-teal-txt:    #0D756E;  /* chapa teal  4.78 · blanco 5.55 */
  --px-warning-big: #C58315;  /* solo cifras >=24px: 3.17 (umbral 3.0) */
  --gris-cabecera:  #66717B;  /* th sobre --px-teal-soft: 4.51 */

  --px-shadow:      0 6px 20px rgba(24, 48, 74, .06);
  --px-shadow-alta: 0 10px 28px rgba(24, 48, 74, .09);

  /* --- nombres antiguos, apuntando a los nuevos --- */
  --azul:        var(--px-teal-solid);
  --azul-osc:    var(--px-teal-press);
  --verde:       var(--px-success);
  --wa:          #25D366;
  --azul-noche:  var(--px-ink);
  --gris-app:    var(--px-page);
  --gris-1:      var(--px-teal-soft);
  --gris-2:      var(--px-border);
  --gris-borde:  #C7DED9;
  --gris-texto:  var(--px-text-muted);
  --gris-suave:  #8593A0;
  --rojo:        var(--px-danger);
  --ambar:       var(--px-warning);
  --radio:       14px;
  --lateral-w:   250px;
  --sombra:      var(--px-shadow);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

/* El carril de la barra de desplazamiento se reserva SIEMPRE, haya scroll o no.
   Sin esto, una pantalla corta (sin barra) y una larga (con barra) tienen
   anchos utiles distintos, y todo lo que va centrado -la cabecera, el menu, el
   contenido- se mueve unos pixeles al pasar de una a otra. Se ve como si los
   componentes no se reutilizaran, cuando son exactamente los mismos: lo que
   cambia es el viewport. Medido en el portal: 1035px sin barra contra 1025px
   con ella, o sea 5px de salto en cada cambio de pantalla.

   Es `overflow-y: scroll` y NO `scrollbar-gutter: stable`, que seria lo
   elegante: se probo primero y el navegador lo computaba como `stable` sin
   reservar nada (innerWidth == clientWidth). Un arreglo que depende de que el
   navegador lo implemente es un arreglo que vuelve a romperse en el navegador
   de al lado. `overflow-y: scroll` reserva el carril en todos.
   No deja franja gris porque el track de esta hoja es transparente (ver la
   regla de scrollbar-color mas abajo): en una pagina corta solo se ve fondo. */
html { overflow-y: scroll; }

body {
  margin: 0;
  font-family: var(--px-texto);
  color: var(--px-ink);
  background: var(--px-page);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------------------
   FONDO DE LA APLICACION
   Tres capas y ninguna imagen: dos neblinas turquesa en esquinas opuestas,
   el grano de papel (el mismo feTurbulence de la portada, para no tener dos
   ruidos distintos) y el color plano debajo. El grano va al 2.5%: por encima
   del 3% empieza a ensuciar el texto de las tablas, que es lo que mas se lee.
   ------------------------------------------------------------------ */
body.app {
  background:
    radial-gradient(circle at 80% 0%,  rgba(18, 169, 159, .10), transparent 32%),
    radial-gradient(circle at 10% 85%, rgba(216, 240, 234, .60), transparent 35%),
    var(--px-page);
  background-attachment: fixed;
}
/* El grano y la marca de agua van en capas fijas propias: como background del
   body se repetirian al desplazar y el ruido "nadaria". */
body.app::before,
body.app::after { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0; }
body.app::before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.86' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='170' height='170' filter='url(%23g)' opacity='.55'/%3E%3C/svg%3E"); opacity: .025; }
/* Marca de agua: PIXELIA enorme, recortada por el borde derecho. Es textura de
   marca, no un texto para leer; por eso al 3.5% y como pseudoelemento, que el
   lector de pantalla no anuncia. */
body.app::after {
  content: "PIXELIA";
  font-weight: 800;
  font-size: clamp(120px, 19vw, 300px);
  letter-spacing: -.04em;
  line-height: 1;
  color: var(--px-teal);
  opacity: .035;
  display: flex; align-items: flex-start; justify-content: flex-end;
  padding-top: 9vh;
  transform: translateX(13%);
  overflow: hidden;
  white-space: nowrap;
}
/* Quien pide mas contraste no quiere decoracion detras del texto. */
@media (prefers-contrast: more) {
  body.app::before, body.app::after { display: none; }
}

a { color: var(--azul); }
/* El selector de archivo no hereda el ancho de los demas campos y se salia
   de su tarjeta en moviles (se ve en pagar.php al subir el comprobante). */
input[type="file"] { max-width: 100%; }
.ico { display: inline-block; vertical-align: middle; flex-shrink: 0; }

/* ----------------------- Marca ----------------------- */
.marca { font-weight: 700; letter-spacing: -0.3px; font-size: 19px; }
.marca span { color: var(--azul); }

/* ==================================================================
   LOGIN
   ================================================================== */
.pantalla-login {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background:
    radial-gradient(1200px 480px at 50% -10%, #064A44 0%, transparent 60%),
    var(--azul-noche);
}
.tarjeta-login {
  width: 100%; max-width: 360px;
  background: #fff;
  border-radius: var(--radio);
  padding: 30px 28px 34px;
  box-shadow: 0 18px 50px rgba(0, 12, 36, .35);
}
.tarjeta-login h1 { margin: 0; font-weight: 800; font-size: 27px; letter-spacing: -.02em; color: var(--px-ink); }
.login-simbolo { display: block; width: 52px; height: 52px; margin-bottom: 12px; }
.subtitulo { margin: 4px 0 22px; color: var(--gris-texto); font-size: 14px; }
/* Aviso de la cookie de sesion: es la unica pagina del sitio que la pone. */
.login-legal { margin: 18px 0 0; font-size: 12px; line-height: 1.45; color: var(--px-text-muted); text-align: center; }
.login-legal a { color: inherit; text-decoration: underline; }

label { display: block; margin: 14px 0 6px; font-size: 13.5px; font-weight: 600; color: var(--px-ink); }
/* Etiqueta que el lector de pantalla anuncia pero no ocupa sitio: para campos
   cuyo titulo ya lo pone la seccion de arriba. */
.visualmente-oculto { position: absolute; width: 1px; height: 1px; margin: -1px;
                      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Estilo base de TODOS los campos de texto (incluye inputs sin atributo type),
   excepto checkbox/radio/file/botones que tienen su propio estilo. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]):not([type="button"]):not([type="range"]):not([type="color"]),
select, textarea {
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid #CFE2DE;
  border-radius: 12px;
  font-size: 15px;
  font-family: inherit;
  color: var(--px-ink);
  /* Un pelo mas calido que el blanco: la tarjeta es blanca y sin esta pizca
     los campos desaparecian dentro de ella. */
  background: #FBFDFC;
  box-sizing: border-box;
  transition: border-color .12s, box-shadow .12s, background .12s;
}
textarea { resize: vertical; min-height: 96px; }
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):hover, select:hover, textarea:hover {
  border-color: rgba(18, 169, 159, .55);
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--px-teal);
  box-shadow: 0 0 0 4px rgba(18, 169, 159, .12);
  background: #fff;
}
input::placeholder, textarea::placeholder { color: #8A979F; }

/* Select: sin flecha nativa, caret propio Pixelia */
select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%238a93a2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  cursor: pointer;
}

/* Input date: indicador de calendario con tono de marca (no el negro nativo) */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  cursor: pointer; opacity: .55;
  filter: invert(16%) sepia(38%) saturate(2200%) hue-rotate(196deg);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* Checkbox / radio: con color de marca, no el gris por defecto */
input[type="checkbox"], input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; margin: 0;
  border: 1.5px solid var(--gris-borde); background: #fff;
  cursor: pointer; flex-shrink: 0; position: relative;
}
input[type="checkbox"] { border-radius: 4px; }
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:checked, input[type="radio"]:checked {
  background: var(--azul); border-color: var(--azul);
}
input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 5px; top: 1.5px;
  width: 5px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
input[type="radio"]:checked::after {
  content: ""; position: absolute; inset: 4px; border-radius: 50%; background: #fff;
}
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible {
  outline: none; box-shadow: 0 0 0 3px rgba(9, 107, 97, .22);
}

/* Input file: boton propio */
input[type="file"] { font-size: 14px; color: var(--gris-texto); }
input[type="file"]::file-selector-button {
  margin-right: 12px; padding: 8px 14px;
  border: 1px solid var(--gris-borde); border-radius: var(--radio);
  background: var(--gris-1); color: var(--azul-noche);
  font-family: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--gris-2); }

/* Scrollbar estilizada (no la nativa) */
* { scrollbar-width: thin; scrollbar-color: var(--gris-borde) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--gris-borde); border-radius: 999px; border: 2px solid var(--gris-app); }
*::-webkit-scrollbar-thumb:hover { background: var(--gris-suave); }
*::-webkit-scrollbar-track { background: transparent; }

.alerta-error {
  background: #fdeceb; color: var(--px-danger-txt);
  border: 1px solid #f3c9c6;
  padding: 10px 12px; border-radius: var(--radio);
  font-size: 14px; margin: 0 0 8px;
}

/* ==================================================================
   BOTONES
   ================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: clamp(5px, .55vw, 8px);
  padding: clamp(8px, .75vw, 9px) clamp(10px, 1.1vw, 14px);
  border: 1px solid transparent;
  border-radius: var(--radio);
  font-size: clamp(12.5px, 1.05vw, 14px); font-weight: 600;
  font-family: inherit;
  cursor: pointer; text-decoration: none;
  white-space: nowrap;
  /* NO "min-width: 0": el rotulo no envuelve, asi que encoger el boton solo
     hace que el texto se derrame fuera de su fondo. Quien cede es la FILA
     (flex-wrap en .form-acciones, .pie-form, .comp-func, .panel-cab). */
  flex-shrink: 0;
  max-width: 100%;
}
/* NADA de overflow:hidden aqui: probado, recortaba rotulos cortos como
   "Copiar" en TODAS las anchuras. El boton ya mengua con el clamp de arriba;
   si no cabe, quien tiene que ceder es la fila que lo contiene (flex-wrap). */
.btn svg { flex-shrink: 0; }
/* Primario con profundidad: gradiente leve + brillo interior + sombra suave.
   Nada metalico ni llamativo: el brillo de arriba solo evita que se vea plano.

   OJO con las paradas: con blanco encima manda LA MAS CLARA, no la de enmedio.
   La original arrancaba en #16AFA5, que da 2.72:1 — por debajo incluso de
   --px-teal, del que CLAUDE.md ya avisa que nunca lleve blanco. Ahora las tres
   pasan AA y la mas clara (#11837C) da 4.60:1. */
.btn-primario {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg, #11837C 0%, #0E8179 45%, #0A6058 100%);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .22);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .24),
    inset 0 -1px 0 rgba(0, 75, 70, .14),
    0 6px 14px rgba(7, 140, 132, .20);
  transition: transform .1s, box-shadow .12s;
}
.btn-primario::before {
  content: ""; position: absolute; inset: 1px; border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,.13), transparent 45%);
  pointer-events: none;
}
.btn-primario:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), 0 9px 20px rgba(7, 140, 132, .25);
}
.btn-primario:active {
  transform: translateY(0);
  box-shadow: inset 0 2px 5px rgba(0, 70, 66, .20), 0 3px 8px rgba(7, 140, 132, .16);
}
.btn-secundario { background: #fff; color: var(--azul-noche); border-color: var(--gris-borde); }
.btn-secundario:hover { background: var(--gris-1); }
/* --px-success es el verde de las chapas y las barras; con BLANCO encima da
   3.16:1, asi que el boton usa su version de fondo. */
.btn-verde { background: #148759; color: #fff; }
.btn-verde:hover { background: #0C6A38; }
/* --wa es el verde de la marca de WhatsApp (#25D366) y con blanco encima da
   1.98:1: es un verde para manchas, no para llevar texto. El boton usa una
   version mas oscura del mismo verde (4.58:1); el icono lo sigue identificando. */
.btn-wsp { background: #188741; color: #fff; }
.btn-wsp:hover { background: #126832; }
.btn-peligro { background: #fff; color: var(--px-danger-txt); border-color: #e7b9b6; }
.btn-peligro:hover { background: #fdeceb; }
/* 30px de alto se quedaba corto para el pulgar; 32 es el minimo del que ya
   parten .btn-icono y los chips. */
.btn-mini { padding: 7px 11px; font-size: 13px; min-height: 32px; }
/* min-* y no width: la caja tiene que poder crecer si el icono es mas grande.
   Con solo padding, un icono de 18px + 7+7 daba 32 y el de WhatsApp (36) se
   salia y se recortaba. 32px es ademas la diana minima comoda. */
.btn-icono {
  padding: 7px; border-radius: var(--radio);
  background: transparent; border: 1px solid transparent; color: var(--gris-texto);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; min-height: 32px;
}
.btn-icono:hover { background: var(--gris-1); color: var(--azul-noche); }
.btn-icono.peligro:hover { background: #fdeceb; color: var(--px-danger-txt); }

/* Boton de login (form sin clase .btn) */
.tarjeta-login button[type="submit"] {
  margin-top: 22px; width: 100%; padding: 12px 16px;
  background: linear-gradient(135deg, #11837C 0%, #0E8179 45%, #0A6058 100%);
  color: #fff; border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 12px; font-size: 15px; font-weight: 600; cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.24), 0 6px 14px rgba(7, 140, 132, .20);
}
.tarjeta-login button[type="submit"]:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28), 0 9px 20px rgba(7, 140, 132, .25);
}

/* ==================================================================
   SHELL: lateral + topbar + contenido
   ================================================================== */
.app { display: block; }

.lateral {
  position: fixed; top: 0; left: 0; bottom: 0;
  width: var(--lateral-w);
  /* Clara, no azul marino: el oscuro se reserva para texto e iconos. */
  background: #F3FAF8;
  border-right: 1px solid var(--px-border);
  color: var(--px-ink);
  display: flex; flex-direction: column;
  z-index: 30;
}
.lateral-marca { padding: 20px 18px 16px; display: flex; align-items: center; gap: 10px; }
.lateral-marca .marca { color: var(--px-ink); }
.lateral-marca .marca span { color: var(--px-teal-dark); }
/* El distintivo: la P en un cuadrado de esquinas suaves. Sin imagen, para no
   depender de un fichero que puede faltar al desplegar. */
/* El simbolo oficial ocupa el mismo hueco que ocupaba la P dibujada. */
.marca-simbolo { width: 32px; height: 32px; flex-shrink: 0; display: block; }

.lateral-nav { flex: 1; padding: 4px 12px 12px; overflow-y: auto; }
.nav-item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; margin-bottom: 3px;
  border-radius: 10px;
  color: var(--px-ink);
  text-decoration: none; font-size: 14.5px; font-weight: 500;
}
.nav-item .ico { color: var(--px-text-muted); }
.nav-item:hover { background: var(--px-teal-soft); }
.nav-item:hover .ico { color: var(--px-teal-dark); }
/* Activo: teal solido y blanco encima. Va --px-teal-solid y no el --px-teal del
   encargo porque ese deja el blanco en 2.92:1, y esta es la etiqueta que se
   mira cada vez que se cambia de pantalla. */
.nav-item.es-activo { background: var(--px-teal-solid); color: #fff; font-weight: 600; }
.nav-item.es-activo .ico { color: #fff; }

/* ---------- Carpetas del menu ----------
   <details> nativo: abre y cierra sin JS. El JS solo recuerda como lo dejaste.
   La flecha gira, los enlaces de dentro se sangran y llevan una guia vertical
   para que se vea a simple vista que cuelgan de su carpeta. */
.nav-grupo { margin-bottom: 2px; }
.nav-grupo-cab {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: 10px;
  font-size: 13px; font-weight: 700; letter-spacing: .02em;
  color: var(--px-text-muted); text-transform: uppercase;
  cursor: pointer; list-style: none; user-select: none;
}
.nav-grupo-cab::-webkit-details-marker { display: none; }
.nav-grupo-cab:hover { background: var(--px-teal-soft); color: var(--px-ink); }
.nav-grupo-cab .ico { color: var(--px-text-muted); }
.nav-grupo-flecha { margin-left: auto; flex-shrink: 0; transition: transform .18s ease; }
.nav-grupo[open] > .nav-grupo-cab .nav-grupo-flecha { transform: rotate(90deg); }
.nav-grupo[open] > .nav-grupo-cab { color: var(--px-ink); }
/* El punto solo aparece cuando la carpeta esta CERRADA y hay algo activo
   dentro: sin el, cerrarla te deja sin saber donde estabas. */
.nav-grupo-punto { width: 6px; height: 6px; border-radius: 50%; background: var(--px-teal); display: none; }
.nav-grupo:not([open]):has(.nav-item.es-activo) .nav-grupo-punto { display: block; }

.nav-grupo-items {
  margin: 2px 0 6px 21px; padding-left: 11px;
  border-left: 1.5px solid var(--px-border);
  display: flex; flex-direction: column; gap: 2px;
}
.nav-grupo-items .nav-item { padding: 8px 10px; font-size: 14px; }

.lateral-pie { padding: 12px; border-top: 1px solid var(--px-border); }
.usuario-mini { display: flex; align-items: center; gap: 10px; padding: 6px 6px 10px; }
.avatar {
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--px-teal-solid); color: #fff;
  display: grid; place-items: center; font-weight: 700; flex-shrink: 0;
}
.usuario-datos { display: flex; flex-direction: column; min-width: 0; }
.usuario-datos strong { font-size: 13.5px; color: var(--px-ink);
                        white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rol-badge {
  align-self: flex-start; margin-top: 2px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 7px; border-radius: 999px;
}
.rol-admin { background: var(--px-teal-soft); color: #06655F; }
.rol-vendedor { background: #EAF4FD; color: #0C5E96; }
.nav-salir {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 10px;
  color: var(--px-text-muted); text-decoration: none; font-size: 14px; font-weight: 500;
}
.nav-salir:hover { background: var(--px-teal-soft); color: var(--px-ink); }

.principal {
  margin-left: var(--lateral-w);
  min-height: 100vh;
  display: flex; flex-direction: column;
}
/* Sin fondo propio: deja ver la textura de la pagina. Al desplazar se vuelve
   solida con desenfoque, para que el contenido no se lea a traves del titulo. */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 14px;
  /* El contenido va centrado con max-width 1400 (.contenido); la topbar ocupa
     todo el ancho para que su fondo difuminado sea a sangre. Para que el TITULO
     caiga en la misma vertical que los paneles, el relleno lateral replica ese
     centrado: (ancho - 1400)/2 + 30. Cuando cabe entero, max() deja los 30px. */
  padding: 22px max(30px, calc((100% - 1400px) / 2 + 30px)) 16px;
  background: rgba(248, 251, 250, .82);
  backdrop-filter: blur(10px) saturate(130%);
  -webkit-backdrop-filter: blur(10px) saturate(130%);
}
.topbar-tit { flex: 1; min-width: 0; }
.topbar-tit h1 { margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -.02em; color: var(--px-ink); }
.topbar-tit p { margin: 3px 0 0; font-size: 14px; color: var(--px-text-muted); }
.topbar-accion { display: flex; gap: 10px; }
.btn-menu { display: none; cursor: pointer; color: var(--azul-noche); }

.contenido { flex: 1; padding: 6px 30px 48px; width: 100%; max-width: 1400px; margin: 0 auto; }

/* Feed de actividad */
.feed { list-style: none; margin: 0; padding: 0; }
.feed li { display: flex; align-items: center; gap: 12px; padding: 11px 16px; border-bottom: 1px solid var(--gris-2); }
.feed li:last-child { border-bottom: 0; }
.feed-ico { width: 30px; height: 30px; border-radius: var(--radio); background: var(--gris-1); color: var(--gris-suave); display: grid; place-items: center; flex-shrink: 0; }
.feed-txt { flex: 1; font-size: 13.5px; min-width: 0; }
/* Cuando la fecha es en realidad un enlace ("Ver"), 19x18 no es una diana:
   se le da alto y area de toque sin cambiar como se ve el texto. */
.feed-fecha { font-size: 12px; white-space: nowrap; }
a.feed-fecha { display: inline-flex; align-items: center; min-height: 32px; padding: 0 6px;
               margin-right: -6px; font-weight: 600; }
.feed.compacto li { padding: 9px 0; }

/* Accesos rapidos */
/* REGLA DE LA CASA: en las rejillas va SIEMPRE minmax(0, 1fr), nunca "1fr"
   pelado. "1fr" equivale a minmax(auto, 1fr) y ese 'auto' no baja del ancho
   MINIMO del contenido: bastaba un placeholder largo dentro de un campo para
   que la columna se quedase clavada en 350px dentro de un movil de 375 y
   empujara la pagina entera de lado. Con el minimo en 0, la columna encoge. */
/* Las baldosas reparten el alto del panel en vez de amontonarse arriba y
   dejar un bloque muerto de ~256px al pie junto al feed de actividad. Se acotan
   para que no se inflen absurdamente y el aire sobrante queda repartido. */
.accesos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
           grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 10px;
           flex: 1; max-height: 300px; margin: auto 0; }
.acceso {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 16px 10px; border: 1px solid var(--gris-2); border-radius: var(--radio);
  color: var(--azul-noche); text-decoration: none; font-size: 13px; font-weight: 600;
  background: var(--gris-1);
}
.acceso:hover { border-color: var(--azul); color: var(--azul); background: #fff; }
.acceso .ico { color: var(--azul); }
.mini-tit { display: flex; align-items: center; gap: 7px; font-size: 12.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--px-text-muted); margin: 20px 0 4px; }

/* ==================================================================
   COMPONENTES
   ================================================================== */
/* Tarjetas KPI */
/* ---------------------------------------------------------------------------
   TARJETAS KPI — FLUIDAS
   Regla de la casa: los elementos se adaptan a la pantalla, NO al reves. Las
   cuatro tarjetas se quedan EN SU LINEA y ENCOGEN; no envuelven dejando una
   huerfana abajo ni se estiran a pantalla completa comiendose el alto que
   necesitan el embudo y las tablas (en el movil eso empujaba lo importante
   fuera de la vista).
   Como funciona: auto-fit con un minimo pequeno = cuatro pistas caben hasta muy
   abajo; y como auto-fit COLAPSA las pistas vacias, las rejillas de dos
   tarjetas (cotizador, cupones) siguen saliendo a dos anchas sin tocar nada.
   Todas las medidas van en clamp(): crecen y menguan de forma continua con el
   ancho en vez de dar saltos en un punto de ruptura.
   --------------------------------------------------------------------------- */
.grid-kpi {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 118px), 1fr));
  gap: clamp(8px, .9vw, 18px);
  margin-bottom: clamp(14px, 1.6vw, 24px);
}
/* Con CUATRO tarjetas se fija la rejilla a 4 columnas que encogen: auto-fit por
   si solo daba repartos de 3+1 en anchos intermedios, que es justo lo que no
   queremos. Con dos tarjetas (cotizador, cupones) manda la regla de arriba. */
.grid-kpi:has(.kpi:nth-child(4)) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Con DOS tarjetas, auto-fit colapsa las pistas vacias y las dos que quedan se
   estiran al 50%: la misma tarjeta media 655px en Cotizador y 321px en Pagos.
   Se topan al tamano que tienen en las paginas de cuatro. */
.grid-kpi:has(.kpi:nth-child(2)):not(:has(.kpi:nth-child(3))) {
  grid-template-columns: repeat(2, minmax(0, 340px));
}
/* En el movil, 2x2 compacto: a partir de aqui cuatro en linea ya no serian
   legibles con importes como "$1,630.00" dentro. */
@media (max-width: 520px) {
  .grid-kpi:has(.kpi:nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.kpi {
  background: var(--px-surface); border: 1px solid var(--px-border);
  border-radius: clamp(11px, 1vw, 16px);
  padding: clamp(11px, 1.15vw, 22px) clamp(12px, 1.25vw, 24px);
  display: flex; align-items: center; gap: clamp(9px, .85vw, 16px);
  box-shadow: var(--px-shadow);
  transition: box-shadow .15s, transform .15s;
  min-width: 0;                 /* sin esto la tarjeta no baja de su contenido */
}
.kpi > * { min-width: 0; }
.kpi:hover { box-shadow: var(--px-shadow-alta); transform: translateY(-1px); }
.kpi .chip { width: clamp(30px, 2.6vw, 48px); height: clamp(30px, 2.6vw, 48px);
             border-radius: clamp(9px, .8vw, 13px);
             display: grid; place-items: center; flex-shrink: 0; }
/* El icono llega con width/height en el propio SVG: el CSS manda sobre ellos. */
.kpi .chip svg { width: clamp(15px, 1.35vw, 24px); height: auto; }
/* Fondos de icono en tonos suaves; el icono en su version oscura para que se
   lea sobre el pastel. El token vivo se reserva a barras y graficas. */
.chip.azul   { background: var(--px-teal-soft); color: #06655F; }
.chip.verde  { background: #E4F6EE; color: #0B7A4F; }
.chip.noche  { background: #EAF4FD; color: #0C5E96; }
.chip.ambar  { background: #FFF4DF; color: #9A6410; }
.chip.rojo   { background: #FDECEC; color: #A93F3F; }
.kpi .num { font-size: clamp(17px, 1.75vw, 30px); font-weight: 800; line-height: 1.05;
            letter-spacing: -.02em; color: var(--px-ink); }
.kpi .lab { font-size: clamp(10.5px, .82vw, 13.5px); color: var(--px-text-muted);
            margin-top: clamp(2px, .3vw, 5px); line-height: 1.25; }

/* Paneles / tarjetas de contenido */
.panel {
  background: var(--px-surface); border: 1px solid var(--px-border);
  border-radius: 18px; box-shadow: var(--px-shadow);
  margin-bottom: 20px;
}
.panel-cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: clamp(8px, .8vw, 12px); flex-wrap: wrap;   /* titulo + boton bajan en vez de desbordar */
  padding: clamp(13px, 1.3vw, 18px) clamp(14px, 1.6vw, 24px) clamp(11px, 1vw, 14px);
  border-bottom: 1px solid var(--px-border);
}
.panel-cab h2 { margin: 0; font-size: 16px; font-weight: 700; color: var(--px-ink);
                display: flex; align-items: center; gap: 10px; }
.panel-cab h2 .ico { color: var(--px-teal-dark); }
.panel-cuerpo { padding: clamp(14px, 1.5vw, 22px) clamp(14px, 1.6vw, 24px); }
.panel-cuerpo.sin-pad { padding: 0; }

/* REGLA DE LA CASA: los paneles hermanos de una misma fila CIERRAN A LA MISMA
   ALTURA. Antes, con align-items:start, "Datos del sistema" (950px) quedaba
   junto a "Funcionalidades" (444px) y se veia torcido. Los anchos si son
   distintos a proposito (2fr / 1fr). */
.layout-2col { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
               gap: 20px; align-items: stretch; }
.layout-2col > section, .layout-2col > .col-apilada { min-width: 0; display: flex; flex-direction: column; }
.layout-2col > section > .panel-cuerpo { flex: 1; }

/* Tablas */
/* .tabla-wrap ya deslizaba de lado, pero no servia de nada: con width:100% la
   tabla NUNCA es mas ancha que el hueco, asi que en vez de deslizarse encoge
   las columnas hasta partir las palabras. Medido a 390px: "Firmar / subir
   contrato" caia en 78px y tres renglones, y "Saldo 50% contra entrega" en 52px
   y cuatro. Con un ancho minimo la tabla vuelve a ser mas ancha que la pantalla
   y entonces SI se desliza, que era la intencion desde el principio. */
.tabla-wrap { width: 100%; overflow-x: auto; }
@media (max-width: 760px) {
  .tabla-wrap > .tabla,
  .panel-cuerpo > .tabla { min-width: 580px; }
  /* Una pista de que hay mas a la derecha: sin esto nadie descubre que desliza. */
  .tabla-wrap, .panel-cuerpo > .tabla {
    background:
      linear-gradient(to right, var(--px-surface) 30%, rgba(255,255,255,0)) left / 28px 100% no-repeat,
      linear-gradient(to left,  var(--px-surface) 30%, rgba(255,255,255,0)) right / 28px 100% no-repeat,
      radial-gradient(farthest-side at 0 50%, rgba(24,48,74,.10), transparent) left / 12px 100% no-repeat,
      radial-gradient(farthest-side at 100% 50%, rgba(24,48,74,.10), transparent) right / 12px 100% no-repeat;
    background-attachment: local, local, scroll, scroll;
  }
}
table.tabla { width: 100%; border-collapse: collapse; font-size: 14px; }
.tabla th, .tabla td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--gris-2); }
/* La cabecera va sobre --gris-1 (el teal suave), no sobre blanco: con
   --gris-suave encima daba 2.85:1 y a 12px en versalitas se leia mal. */
.tabla th {
  font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--gris-cabecera); font-weight: 700; background: var(--gris-1);
}
.tabla tbody tr:hover { background: #F7FAF8; }
/* RED DE SEGURIDAD: una .tabla sin su .tabla-wrap se salia del panel en vez de
   deslizarse dentro (paso en sistema.php y en clientes/ver.php). Con esto, aunque
   alguien olvide el envoltorio, la tabla queda contenida. */
.panel-cuerpo > .tabla { display: block; overflow-x: auto; max-width: 100%; }

/* La ultima fila no lleva raya: si no, cruza recta por encima de la esquina
   redondeada del panel y la caja parece "cortada" abajo. */
.panel-cuerpo.sin-pad .tabla tbody tr:last-child td { border-bottom: 0; }
.tabla td.acciones { text-align: right; white-space: nowrap; }
/* `secundario` significa "texto de apoyo" en TODA la aplicacion: se usa 294
   veces en 42 ficheros. Estaba definida SOLO dentro de .tabla, asi que fuera de
   una tabla no hacia nada y el texto salia con el color y el tamano del
   principal. Se define suelta con el color, y la variante de tabla conserva su
   tamano menor. No se le pone font-size aqui a proposito: hay sitios que ya la
   usan a 14 y 15px y encogerlos ahora moveria maquetas que hoy estan bien. */
.secundario { color: var(--gris-texto); }
.tabla .secundario { font-size: 13px; }

/* Alineacion de las columnas de cifras. `class="num"` se usa 72 veces en celdas
   de tabla y solo estaba definida bajo .kpi, donde significa otra cosa (el
   tamano de una cifra grande). Sin esto los importes salian alineados a la
   izquierda y no se podian comparar de un vistazo. */
.tabla th.num, .tabla td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Badges de estado */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; font-weight: 600;
  /* Hay chapas que son enlaces (el saldo de cambios del portal, por ejemplo):
     sin esto salen subrayadas y parecen texto roto dentro de la pastilla. */
  text-decoration: none;
  padding: 3px 9px; border-radius: 999px;
  border: 1px solid transparent;
}

/* Una chapa que ademas es enlace es una DIANA: a 3px de relleno se queda en 24px
   de alto y en un movil hay que apuntar. Se le da aire solo cuando es <a>, para
   no engordar las cientos de chapas que solo informan. */
a.badge { padding-top: 7px; padding-bottom: 7px; min-height: 32px; }
a.badge:hover { text-decoration: none; filter: brightness(.96); }
/* El color de la chapa es el de TEXTO, no el token vivo: a 12px el ambar
   original daba 2.30:1, y el ambar es justo el que marca lo urgente. */
.badge-azul  { background: rgba(9, 107, 97, .1);  color: var(--px-teal-txt); }
.badge-verde { background: rgba(15, 128, 67, .12); color: #0B6B5F; }
.badge-gris  { background: var(--gris-1); color: var(--gris-texto); border-color: var(--gris-2); }
.badge-ambar { background: rgba(183, 110, 0, .12); color: var(--px-warning-txt); }
.badge-rojo  { background: rgba(179, 38, 30, .1);  color: var(--px-danger-txt); }

/* Estado vacio */
.vacio {
  text-align: center; padding: 46px 20px; color: var(--gris-texto);
}
.vacio .ico { color: var(--gris-borde); margin-bottom: 10px; }
.vacio h3 { margin: 0 0 4px; font-size: 16px; color: var(--azul-noche); }
.vacio p { margin: 0 0 16px; font-size: 14px; }

/* Embudo de leads por estado */
.embudo-fila { display: flex; align-items: center; gap: 12px; padding: 7px 0; }
/* La etiqueta toma el color de su estado por variable, con el texto en tinta
   para que se lea: el turquesa nunca es el UNICO indicador, siempre va con su
   nombre escrito al lado. */
.embudo-etq {
  width: 132px; flex-shrink: 0; text-align: center;
  padding: 5px 10px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; color: var(--px-ink);
  background: color-mix(in srgb, var(--c) 18%, #fff);
  border: 1px solid color-mix(in srgb, var(--c) 34%, #fff);
}
.embudo-barra { flex: 1; height: 9px; background: var(--px-teal-soft); border-radius: 999px; overflow: hidden; }
.embudo-barra span { display: block; height: 100%; border-radius: 999px; }
.embudo-num { width: 30px; text-align: right; font-size: 15px; font-weight: 700; color: var(--px-ink); }

/* Notas / avisos */
.nota {
  background: #fff; border: 1px solid var(--gris-2);
  border-left: 3px solid var(--verde);
  padding: 12px 14px; border-radius: var(--radio);
  color: var(--gris-texto); font-size: 14px;
}
.nota.azul { border-left-color: var(--azul); }
.aviso-ok {
  background: #E4F1EC; color: #0B6B5F; border: 1px solid #BFE0D6;
  padding: 10px 14px; border-radius: var(--radio); font-size: 14px; margin-bottom: 16px;
}

/* Campo de password de la boveda (revelar) */
.pw-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pw-row input { flex: 1; min-width: 160px; }
.pw-claro {
  font-family: var(--px-mono); font-size: 13px;
  background: #fff7e6; border: 1px solid #ffd98a; color: var(--ambar);
  padding: 6px 10px; border-radius: var(--radio); user-select: all; word-break: break-all;
}

/* ==================================================================
   TIENDA (catalogo publico de sistemas)
   ================================================================== */
.tienda-hero { max-width: 1200px; margin: 0 auto; padding: 30px 24px 6px; }
.tienda-hero h1 { margin: 0 0 6px; font-weight: 800; font-size: 30px; letter-spacing: -.02em; color: var(--px-ink); }
.tienda-hero p { margin: 0; color: var(--gris-texto); }
.tienda-filtros { max-width: 1200px; margin: 0 auto; padding: 14px 24px; display: flex; gap: 8px; flex-wrap: wrap; }
.tienda-grid { max-width: 1200px; margin: 0 auto; padding: 8px 24px 50px; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 20px; }
.tienda-card { background: #fff; border: 1px solid var(--gris-2); border-radius: 10px; overflow: hidden; box-shadow: var(--sombra); display: flex; flex-direction: column; }
.tc-foto { height: 150px; background: linear-gradient(135deg, #064A44, #002454); background-size: cover; background-position: center; position: relative; display: grid; place-items: center; color: rgba(255,255,255,.35); }
.tc-desc { position: absolute; top: 10px; right: 10px; background: var(--verde); color: #fff; font-weight: 700; font-size: 12px; padding: 3px 9px; border-radius: 999px; }
.tc-body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.tc-body h3 { margin: 2px 0; font-size: 16px; color: var(--azul-noche); }
.tc-precio { font-size: 20px; font-weight: 700; color: var(--azul-noche); }
.tc-precio .tachado { font-size: 13px; color: var(--px-text-muted); text-decoration: line-through; font-weight: 400; margin-left: 6px; }
.tc-acc { display: flex; gap: 8px; margin-top: auto; padding-top: 6px; }
.tienda-pie { background: var(--azul-noche); color: rgba(255,255,255,.8); font-size: 13px; }
.tienda-pie .cont { max-width: 1200px; margin: 0 auto; padding: 18px 24px; text-align: center; }

/* Resultados de busqueda de contacto (modal enviar catalogo) */
.res-contacto { margin-top: 6px; }
.res-item { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 9px 10px; background: #fff; border: 1px solid var(--gris-2); border-radius: var(--radio); margin-bottom: 4px; cursor: pointer; font-family: inherit; font-size: 13.5px; }
.res-item:hover { background: var(--gris-1); border-color: var(--azul); }

/* Catalogo interactivo con carrito */
.cmp-wrap { max-width: 1200px; margin: 0 auto; padding: 8px 24px 50px; display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 24px; align-items: start; }
.cmp-h { font-size: 16px; color: var(--azul-noche); margin: 22px 0 12px; display: flex; align-items: center; gap: 8px; }
.cmp-h:first-child { margin-top: 4px; }
/* El armador se comparte con la TIENDA publica, donde .cmp-wrap centra a 1200px
   con su propio relleno. Dentro de Norte ya centra .contenido (1400px), asi que
   ese segundo contenedor sangraba el bloque ~94px respecto al panel de arriba.
   Aqui se neutraliza; la rejilla de dos columnas se conserva. */
.contenido .cmp-wrap { max-width: none; margin: 0; padding: 0; }

.cmp-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: 14px; }
.cmp-card { background: #fff; border: 1px solid var(--gris-2); border-radius: 8px; overflow: hidden; box-shadow: var(--sombra); }
.cmp-card-foto { height: 110px; background: linear-gradient(135deg, #064A44, #002454); background-size: cover; background-position: center; display: grid; place-items: center; color: rgba(255,255,255,.35); }
.cmp-card-b { padding: 12px 14px; display: flex; flex-direction: column; gap: 7px; }
.cmp-card-b strong { font-size: 14.5px; color: var(--azul-noche); }
.cmp-precio { font-weight: 700; color: var(--azul-noche); }
.cmp-planes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.cmp-list { display: flex; flex-direction: column; gap: 8px; }
.cmp-row { background: #fff; border: 1px solid var(--gris-2); border-radius: 8px; padding: 12px 14px; display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.cmp-row-acc { display: flex; align-items: center; gap: 12px; white-space: nowrap; }
.cmp-cart { position: sticky; top: 18px; }
.cmp-cart-items { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.cmp-cart-row { display: flex; justify-content: space-between; gap: 10px; align-items: center; border-bottom: 1px dashed var(--gris-2); padding-bottom: 5px; font-size: 13.5px; }
.cmp-cart-row:last-child { border-bottom: none; padding-bottom: 0; }
.cmp-cart-row .secundario { text-transform: capitalize; }
/* Totales e items del resumen (compartido: tienda + armar oferta) */
.cmp-totales { border-top: 1px solid var(--gris-2); padding-top: 8px; margin-top: 8px; }
.cmp-tl { display: flex; justify-content: space-between; font-size: 13px; padding: 2px 0; color: var(--gris-texto); }
.cmp-tl.desc { color: #0B6B5F; }
.cmp-totales .cmp-total { display: flex; justify-content: space-between; border-top: 1px solid var(--gris-2); margin-top: 6px; padding-top: 8px; font-size: 16px; color: var(--azul-noche); font-weight: 700; }
.r-item { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; padding: 3px 0; border-bottom: 1px dashed var(--gris-2); }
.r-item:last-child { border-bottom: none; }
.r-item .ri-incl { color: #0B6B5F; font-size: 11px; }
@media (max-width: 860px) { .cmp-wrap { grid-template-columns: minmax(0, 1fr); } .cmp-cart { position: static; } }

/* Ficha publica del sistema */
.ficha { max-width: 980px; margin: 0 auto; padding: 24px; }
.ficha-cab { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; align-items: start; }
.ficha-foto { height: 260px; border-radius: 10px; background: linear-gradient(135deg, #064A44, #002454); background-size: cover; background-position: center; }
.ficha h1 { margin: 6px 0; font-weight: 800; font-size: 28px; line-height: 1.15; letter-spacing: -.02em; color: var(--px-ink); }
@media (max-width: 760px) { .ficha-cab { grid-template-columns: minmax(0, 1fr); } }

/* Composicion de cotizacion */
.comp-add { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
/* min-width:300px fijo impedia encoger: dentro de la columna estrecha de
   sistema.php (1fr de una rejilla 2fr/1fr) el formulario se salia del panel.
   Ahora envuelve y el desplegable baja a su propia linea cuando no cabe. */
/* "flex: 1" es "1 1 0%": sin base, al compartir linea con otro control el
   formulario se colapsaba a 76px y el boton (que lleva overflow:hidden por su
   brillo) salia con el rotulo cortado. Con base 220px pide una linea entera
   cuando no cabe, gracias al flex-wrap del contenedor. */
.comp-func { display: flex; flex-wrap: wrap; gap: 8px; flex: 1 1 220px; min-width: 0; }
.comp-func select { flex: 1 1 160px; min-width: 0; }

/* Pestañas */
/* Las pestanas se deslizan DENTRO de su tira cuando no caben (movil), en vez
   de desbordar y arrastrar toda la pagina de lado. El relleno tambien mengua,
   asi que muchas veces ya no hace falta deslizar. */
.tabs {
  display: flex; gap: 4px; border-bottom: 1px solid var(--gris-2); margin-bottom: 22px;
  overflow-x: auto; scrollbar-width: thin; -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { height: 3px; }
.tabs::-webkit-scrollbar-thumb { background: var(--px-border); border-radius: 3px; }
.tab {
  padding: clamp(8px, .85vw, 10px) clamp(10px, 1.25vw, 16px);
  text-decoration: none; font-size: clamp(12.5px, 1.05vw, 14px); font-weight: 600;
  color: var(--gris-texto); border-bottom: 2px solid transparent; margin-bottom: -1px;
  white-space: nowrap; flex-shrink: 0;
}
.tab:hover { color: var(--azul-noche); }
/* El fondo de la app lleva neblina teal, asi que --azul aqui no cae sobre
   blanco puro y se queda en 4.26. El subrayado si puede seguir en --azul:
   una linea no es texto y le basta con 3:1. */
.tab.activo { color: var(--px-teal-txt); border-bottom-color: var(--azul); }

/* Pistas y codigo inline */
/* --gris-suave da 3.14:1 sobre blanco: vale de icono, no de texto. */
.pista { font-weight: 400; font-size: 12.5px; color: var(--px-text-muted); }
code {
  font-family: var(--px-mono);
  font-size: 12.5px; background: var(--gris-1); color: var(--px-teal-txt);
  padding: 1px 6px; border-radius: 4px; border: 1px solid var(--gris-2);
}

/* Filas de formulario */
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 18px; }
.form-grid .col-full { grid-column: 1 / -1; }
.campo { display: flex; flex-direction: column; }
.campo label { margin: 0 0 5px; }
/* Las filas de acciones bajan de linea antes que desbordar; y en pantalla
   estrecha el boton ocupa el ancho completo, que es mas facil de pulsar que
   uno diminuto con el rotulo recortado. */
.form-acciones { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; margin-top: 20px; }
@media (max-width: 480px) {
  .form-acciones > .btn, .pie-form > .btn { flex: 1 1 100%; }
}

/* ==================================================================
   LEADS: toolbar, buscador, chips, kanban, tarjetas, modal
   ================================================================== */
.leads-toolbar {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 16px;
}
/* Barra de filtros generica de tablas: cualquier listado la usa con marcado,
   el JS de app.js hace el resto. Vive pegada encima de su panel. */
.tabla-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--px-surface); border: 1px solid var(--px-border);
  border-radius: 14px; padding: 10px 14px; margin-bottom: 14px;
  box-shadow: var(--px-shadow);
}
.tabla-toolbar select {
  width: auto; min-width: 160px; max-width: 260px;
  padding-top: 8px; padding-bottom: 8px;
}
.fila-sin-resultados td {
  text-align: center; color: var(--px-text-muted); padding: 26px 16px !important;
}

/* 260 medido, no a ojo: el placeholder "Ultimos digitos del telefono..." ocupa
   203px, y la caja se come 38 de sangria (la lupa) + 14 + 2 de borde = 54.
   Por debajo de esto la FILA envuelve; el campo no encoge y no se corta. */
.buscador { position: relative; flex: 1; min-width: 260px; max-width: 380px; }
.buscador .ico { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--gris-suave); pointer-events: none; }
.buscador input { padding-left: 38px !important; }

.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip-filtro {
  padding: 7px 12px; border: 1px solid var(--gris-borde); border-radius: 999px;
  background: #fff; font-size: 13px; font-weight: 600; color: var(--gris-texto);
  cursor: pointer; display: inline-flex; align-items: center; gap: 7px;
}
.chip-filtro:hover { background: var(--gris-1); }
.chip-filtro.activo { background: var(--azul-noche); color: #fff; border-color: var(--azul-noche); }
.chip-filtro .punto { width: 8px; height: 8px; border-radius: 50%; }
.toolbar-sep { flex: 1; }

/* Kanban */
/* Las columnas cierran TODAS a la misma altura (stretch, no flex-start). Antes
   una columna con 9 leads media 760px y la de al lado 102px: se veia irregular
   y, peor, la columna corta era una zona de arrastre diminuta donde costaba
   soltar la tarjeta. Con la misma altura, se puede soltar en cualquier punto. */
.kanban { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 12px; align-items: stretch; }
.col-kanban {
  flex: 0 0 clamp(200px, 20vw, 252px); background: #e8edf4; border: 1px solid var(--gris-2);
  border-radius: 8px; display: flex; flex-direction: column;
  height: calc(100vh - 240px); min-height: 320px;
}
.col-cab { display: flex; align-items: center; justify-content: space-between; padding: 11px 12px; }
.col-cab .tit { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 13px; }
.col-cab .pin { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.col-cuenta { font-size: 12px; font-weight: 700; color: var(--gris-texto); background: #fff; border: 1px solid var(--gris-2); border-radius: 999px; padding: 1px 9px; }
/* Las tarjetas que no se ven no se calculan.

   Con 300 leads reales el Kanban manda 1.3 MB de HTML y 9.325 nodos, y las 264
   tarjetas de "Contactado" se maquetan TODAS aunque solo se vean cinco. Eso
   bloquea el hilo principal 242 ms, y durante ese rato el navegador ya ha
   pintado una primera maqueta -la estrecha, con los filtros en tres filas- que
   luego recoloca: es el salto que se ve al entrar (CLS medido 0,708).

   Medido con 337 tarjetas: recolocar la pantalla pasa de 69 ms a 24 ms, y cinco
   reflujos seguidos de 39 ms a 19 ms.

   `contain-intrinsic-size` NO es opcional: sin el, el navegador da alto 0 a lo
   que no ha medido y la barra de desplazamiento de la columna salta al bajar.
   El valor es el alto tipico de una tarjeta. */
.col-cuerpo > * { content-visibility: auto; contain-intrinsic-size: auto 118px; }

.col-cuerpo { padding: 0 10px 10px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 8px; min-height: 56px; }
.col-cuerpo.drag-sobre { background: rgba(9, 107, 97, .07); outline: 2px dashed var(--azul); outline-offset: -5px; border-radius: 6px; }

.lead-card {
  background: #fff; border: 1px solid var(--gris-2); border-radius: 6px;
  padding: 10px 11px; cursor: grab; box-shadow: var(--sombra);
}
.lead-card:active { cursor: grabbing; }
.lead-card.arrastrando { opacity: .45; }
.lead-card.oculto { display: none; }
.lead-card.resaltado { outline: 2px solid var(--verde); outline-offset: 0; }
.lead-card .negocio { font-weight: 700; font-size: 13.5px; margin-bottom: 5px; }
.lead-card .tel { font-family: var(--px-mono); font-size: 12.5px; color: var(--gris-texto); display: flex; align-items: center; gap: 7px; }
.lead-card .card-pie { display: flex; align-items: center; justify-content: space-between; margin-top: 9px; gap: 6px; }
.lead-card .card-acc { display: flex; gap: 2px; }

/* El punto se ve de 10px pero se PULSA en 26: el color va en un ::before y el
   boton guarda su area de toque. Un blanco de 10x10 no lo acierta nadie. */
.num-dot { width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
           display: inline-flex; align-items: center; justify-content: center;
           cursor: pointer; border: 0; padding: 0; background: transparent; }
.num-dot::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--gris-suave); }
/* Bajo .num-dot el color va al ::before (el boton es solo area de toque); las
   clases num-* SUELTAS -los puntitos del menu de descartar, que son spans-
   siguen pintandose como siempre, en su propio fondo. */
.num-dot.num-sin_verificar::before { background: var(--gris-suave); }
.num-dot.num-valido::before        { background: var(--verde); }
.num-dot.num-equivocado::before    { background: var(--ambar); }
.num-dot.num-no_existe::before     { background: var(--rojo); }
.num-dot:hover { background: var(--gris-1); }
.num-sin_verificar { background: var(--gris-suave); }
.num-valido        { background: var(--verde); }
.num-equivocado    { background: var(--ambar); }
.num-no_existe     { background: var(--rojo); }
/* ...y el boton se queda sin fondo pese a llevar la misma clase. */
button.num-dot { background: transparent; }

/* Como TEXTO el verde de marca no llega: va el mismo verde oscurecido que
   usan .btn-wsp y .w-btn-3. */
.btn-wa { color: #188741; position: relative; }
.btn-wa:hover { background: rgba(37, 211, 102, .15); }
/* El contador de mensajes (.wa-n) lo crea leads.js y no tenia NINGUNA regla:
   salia como un numero suelto pegado al icono, y de paso ensanchaba el boton
   hasta recortar el propio icono. Va donde se esperaba desde el principio, en
   la esquina, y fuera del flujo para que no empuje nada. */
.wa-n {
  position: absolute; top: -2px; right: -2px;
  min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: #188741; color: #fff;
  font-size: 10px; font-weight: 700; line-height: 15px; text-align: center;
  border: 1.5px solid var(--px-surface);
}
.btn-descartar { color: var(--px-danger-txt); }
.btn-descartar:hover { background: #fdeceb; }

/* Menu de descarte rapido (popover) */
.menu-descartar {
  position: fixed; z-index: 60; display: none;
  background: #fff; border: 1px solid var(--gris-borde); border-radius: var(--radio);
  box-shadow: 0 12px 32px rgba(0, 12, 36, .2); padding: 6px; min-width: 196px;
}
.menu-descartar.abierto { display: block; }
.menu-descartar .tit-menu { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--px-text-muted); padding: 4px 10px 6px; }
.menu-descartar button {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; background: none; border: 0; border-radius: 5px;
  font-family: inherit; font-size: 13.5px; font-weight: 500; color: var(--azul-noche);
  cursor: pointer; text-align: left;
}
.menu-descartar button:hover { background: var(--gris-1); }
.menu-descartar .punto { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }

/* Bitacora de interacciones */
.bitacora { margin-top: 18px; border-top: 1px solid var(--gris-2); padding-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.bita-item { border-left: 2px solid var(--gris-2); padding: 2px 0 2px 12px; }
.bita-cab { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bita-txt { font-size: 14px; margin: 5px 0 3px; }
.bita-autor { font-size: 12px; }

/* Modal propio (sin dialogos nativos) */
.modal-fondo {
  position: fixed; inset: 0; background: rgba(0, 18, 46, .55);
  display: none; align-items: flex-start; justify-content: center;
  z-index: 50; padding: 42px 16px; overflow-y: auto;
}
.modal-fondo.abierto { display: flex; }
.modal { background: #fff; border-radius: 8px; width: 100%; max-width: 560px; box-shadow: 0 24px 70px rgba(0, 12, 36, .4); }
.modal-cab { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid var(--gris-2); }
.modal-cab h3 { margin: 0; font-size: 16px; display: flex; align-items: center; gap: 9px; }
.modal-cuerpo { padding: 20px; }
.modal-cerrar { background: none; border: 0; cursor: pointer; color: var(--px-danger-txt); padding: 4px; display: inline-flex; border-radius: var(--radio); }
.modal-cerrar:hover { color: #8e1d17; background: #fdeceb; }

/* --- Dialogo de confirmar / avisar (window.confirmar) -------------------
   Sustituye al confirm() del navegador, que sacaba un cuadro del sistema
   operativo: botones de Windows, sin decir de que sistema venia y sin
   distinguir "quitar una imagen" de "borrar la boveda entera". */
.modal-pie {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 14px 20px; border-top: 1px solid var(--gris-2);
  background: var(--px-page); border-radius: 0 0 8px 8px;
}
.dialogo { max-width: 430px; }
.dialogo-txt { margin: 0; color: var(--px-ink); line-height: 1.5; font-size: 14.5px; }
/* En el destructivo el titulo va en rojo: la diferencia entre borrar y
   guardar no puede quedarse solo en el texto del boton. */
.dialogo-peligro .modal-cab h3 { color: var(--px-danger-txt); }
.dialogo-peligro .modal-cab { border-bottom-color: #F0D5D3; }
@media (max-width: 480px) {
  /* Apilados y a lo ancho: en un movil dos botones de 90px uno al lado del
     otro son dos dianas de pulgar demasiado juntas. */
  .modal-pie { flex-direction: column-reverse; }
  .modal-pie .btn { width: 100%; justify-content: center; }
}

/* ==================================================================
   RESPONSIVE
   ================================================================== */
@media (max-width: 860px) {
  .lateral { transform: translateX(-100%); transition: transform .2s ease; box-shadow: 0 0 40px rgba(0,0,0,.3); }
  .toggle-menu:checked ~ .lateral { transform: translateX(0); }
  .principal { margin-left: 0; }
  .btn-menu { display: inline-flex; }
  .layout-2col { grid-template-columns: minmax(0, 1fr); }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  /* Topbar apila el titulo y las acciones para no aplastar el titulo */
  .topbar { flex-wrap: wrap; padding: 12px 14px; }   /* igual que .contenido */
  .topbar-accion { width: 100%; flex-wrap: wrap; }
  .contenido { padding: 18px 14px 32px; }
  .cmp-wrap { padding-left: 14px; padding-right: 14px; }
}

/* ===== Armador de paquetes compartido (tienda + armar oferta) ===== */
.cb-toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.cb-toolbar .buscador { min-width: 180px; }
.cb-toolbar select { width: auto; }
.cb-soloincl { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--gris-texto); white-space: nowrap; cursor: pointer; }
.cb-soloincl input { width: auto; }
.cb-base { display: flex; align-items: center; justify-content: space-between; gap: 12px; background: rgba(11,132,120,.08); border: 1px solid #BFE0D6; border-radius: 8px; padding: 12px 14px; margin: 4px 0 16px; }
.cb-base strong { color: var(--azul-noche); }
.badge-incl { background: rgba(15,128,67,.14); color: #0B6B5F; }
.cb-func.cb-sel { border-color: var(--azul); background: rgba(9,107,97,.04); }
.cb-toggle.cb-on, .cb-plan-btn.cb-on { background: var(--azul); color: #fff; border-color: var(--azul); }
.cb-func[hidden] { display: none; }

/* El atributo hidden debe ganar a display:grid/flex de las tarjetas/listas */
[hidden] { display: none !important; }

/* ------------------------------------------------------------------
   Vista previa de las formas de pago (Cobros): los cinco huecos tal
   como salen en la ficha publica, para ver de un vistazo que falta.
   ------------------------------------------------------------------ */
.mp-previa { margin: 0 0 18px; }
.mp-previa-et { font-size: 12px; color: var(--gris-texto); margin-bottom: 8px; }
.mp-previa-caja { max-width: 340px; border: 1px solid var(--gris-2); border-radius: 14px;
                  padding: 14px 16px 16px; background: #fff; }
.mp-previa-tit { display: flex; align-items: center; gap: 8px; font-size: 11.5px; font-weight: 700;
                 text-transform: uppercase; letter-spacing: .06em; color: var(--azul-noche);
                 margin-bottom: 10px; }
.mp-previa-tit .ico { color: var(--verde); }
.mp-huecos { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.mp-hueco { aspect-ratio: 1; border: 1px solid var(--gris-2); border-radius: 8px; background: #fff;
            display: grid; place-items: center; padding: 4px; overflow: hidden; }
.mp-hueco img { max-width: 100%; max-height: 100%; object-fit: contain; }
.mp-hueco.es-vacio { border-style: dashed; border-color: #CBD8D3; background: #F7FAF8; }
.mp-hueco.es-vacio span { font-size: 12px; color: var(--px-text-muted); }
.mp-previa-nota { font-size: 11.5px; color: var(--gris-texto); margin-top: 10px; }
.mp-previa-btn { margin-top: 10px; border: 1px solid var(--gris-borde); border-radius: 8px;
                 padding: 9px 12px; text-align: center; font-size: 12.5px; font-weight: 700;
                 color: var(--azul-noche); display: flex; align-items: center; justify-content: center; gap: 7px; }
.mp-previa-btn.es-vacio { border-style: dashed; color: var(--px-text-muted); font-weight: 500; }
.mp-previa-btn em { font-style: normal; font-size: 11.5px; color: var(--px-text-muted); }

/* ==================================================================
   DETALLE DE REGISTRO - el patron de las pantallas de detalle
   (proyectos hoy; clientes, leads y lo que venga, despues).
   Tres piezas: el indicador de etapas, las secciones del formulario y el
   panel resumen lateral. Nada de esto sabe de proyectos: son componentes.
   ================================================================== */

/* ---- Indicador de etapas (Cotizacion -> Aprobacion -> Desarrollo -> Entrega) ---- */
.flujo { display: flex; align-items: flex-start; column-gap: 12px;
         background: var(--px-surface); border: 1px solid rgba(18, 169, 159, .14);
         border-radius: 16px; padding: clamp(14px, 1.5vw, 20px) clamp(14px, 1.7vw, 24px) clamp(12px, 1.2vw, 16px);
         margin-bottom: 20px;
         box-shadow: 0 8px 28px rgba(24, 48, 74, .07); }
/* min-width:0 es la clave: con "flex:1" a secas cada paso se quedaba anclado a
   su ancho MINIMO por contenido, asi que el paso con la palabra mas larga
   ("Negociacion") robaba sitio a los demas y los cinco dejaban de ser iguales.
   En movil ademas la fila se salia por la derecha de la tarjeta blanca. */
.flujo-paso { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
              align-items: flex-start; position: relative; }
@media (max-width: 520px) {
  /* Con 5 pasos, envolver dejaria uno huerfano: se apila en vertical. */
  .flujo { flex-wrap: wrap; row-gap: 14px; }
  .flujo-paso { flex: 1 1 100%; }
  .flujo-paso::after { display: none; }
}
.flujo-n { width: 30px; height: 30px; border-radius: 50%;
           display: grid; place-items: center;
           font-size: 13.5px; font-weight: 700;
           background: #EEF4F2; color: var(--px-text-muted);
           border: 2px solid transparent; }
.flujo-et { margin-top: 8px; font-size: 14px; font-weight: 700; color: var(--px-text-muted); }
.flujo-sub { font-size: 12.5px; color: var(--px-text-muted); margin-top: 1px; }
/* La linea que une un paso con el siguiente. Punteada mientras este pendiente. */
.flujo-paso::after { content: ""; position: absolute; top: 14px; left: 42px; right: 14px;
                     border-top: 2px dashed var(--px-border); }
.flujo-paso:last-child::after { display: none; }
.flujo-paso.hecho .flujo-n { background: var(--px-teal-soft); color: #06655F; }
.flujo-paso.hecho::after { border-top-style: solid; border-top-color: var(--px-teal-light); }
.flujo-paso.actual .flujo-n { background: var(--px-teal-solid); color: #fff; }
.flujo-paso.actual .flujo-et { color: var(--px-ink); }
.flujo-paso.actual .flujo-sub { color: var(--px-teal-dark); font-weight: 600; }

/* ---- Secciones dentro de un formulario ---- */
.form-seccion { display: flex; align-items: flex-start; gap: 12px;
                margin: 26px 0 4px; }
.form-seccion:first-child { margin-top: 0; }
.form-seccion .chip-seccion { width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
                              background: var(--px-teal-soft); color: var(--px-teal-dark);
                              display: grid; place-items: center; }
.form-seccion h3 { margin: 0; font-size: 15.5px; font-weight: 700; color: var(--px-teal-dark); }
.form-seccion p { margin: 1px 0 0; font-size: 13px; color: var(--px-text-muted); }

/* ---- Dos columnas: formulario + resumen lateral ---- */
.detalle-2col { display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
                gap: 20px; align-items: start; margin-bottom: 20px; }
@media (max-width: 1100px) { .detalle-2col { grid-template-columns: minmax(0, 1fr); } }

/* Envoltorio para apilar varios paneles dentro de UNA columna de la rejilla:
   evita que un tercer panel caiga a una fila nueva y deje la de al lado vacia. */
.col-apilada { display: flex; flex-direction: column; gap: 20px; min-width: 0; }

/* El resumen: datos de un vistazo, con mas jerarquia que la tarjeta del form. */
.resumen-lateral { position: sticky; top: 90px; }
.resumen-caja { background: var(--px-surface); border: 1px solid rgba(18, 169, 159, .14);
                border-radius: 16px; padding: 18px; box-shadow: 0 8px 28px rgba(24, 48, 74, .07); }
.resumen-tit { display: flex; align-items: center; gap: 10px; margin: 0 0 14px;
               font-size: 15px; font-weight: 700; color: var(--px-ink); }
.resumen-tit .ico { color: var(--px-teal-dark); }
.resumen-dato { display: flex; align-items: center; justify-content: space-between; gap: 12px;
                border: 1px solid var(--px-border); border-radius: 13px;
                padding: 14px 16px; margin-bottom: 10px; background: #FBFDFC; }
.resumen-dato .lab { font-size: 12.5px; color: var(--px-text-muted); margin-bottom: 3px; }
.resumen-dato .num { font-size: 21px; font-weight: 800; letter-spacing: -.02em; color: var(--px-ink); line-height: 1.1; }
.resumen-dato .num.chico { font-size: 17px; }
.resumen-dato .ico-caja { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
                          background: var(--px-teal-soft); color: var(--px-teal-dark);
                          display: grid; place-items: center; }
.resumen-nota { display: flex; gap: 8px; font-size: 12.5px; line-height: 1.4;
                color: var(--px-text-muted); background: var(--px-teal-soft);
                border-radius: 10px; padding: 9px 11px; margin: -4px 0 10px; }
.resumen-pie { display: flex; align-items: center; justify-content: space-between; gap: 10px;
               padding: 4px 4px 0; font-size: 13px; color: var(--px-text-muted); }
.resumen-pie strong { display: block; color: var(--px-ink); font-size: 13.5px; }

/* ---- Pie de acciones del formulario ---- */
.pie-form { display: flex; justify-content: flex-end; gap: 10px; align-items: center;
            flex-wrap: wrap;   /* con varios botones, bajan en vez de desbordar */
            margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--px-border); }

/* ==================================================================
   PANEL PRINCIPAL (rediseno 19 ago 2026, sobre el mockup aprobado)
   ================================================================== */
/* La tendencia bajo cada KPI: sube (verde), baja (rojo), igual (gris). */
.kpi-tend { display: flex; align-items: center; gap: 4px; margin-top: clamp(3px, .45vw, 7px);
            font-size: clamp(9.5px, .72vw, 12px); font-weight: 600; color: var(--px-text-muted);
            line-height: 1.25; }
.kpi-tend svg { width: clamp(10px, .85vw, 13px); height: auto; flex-shrink: 0; }
.kpi-tend .ico { flex-shrink: 0; }
.kpi-tend.sube  { color: #0B7A4F; }
.kpi-tend.baja  { color: #A93F3F; }
.kpi-tend.baja .ico { transform: rotate(90deg); }
.kpi-tend.igual { color: var(--px-text-muted); }
.kpi-tend.punto i { width: 7px; height: 7px; border-radius: 50%;
                    background: var(--px-warning); display: inline-block; }

/* El selector de periodo de la cabecera: compacto, no un campo de formulario. */
.sel-periodo select { width: auto; min-height: 40px; padding: 8px 34px 8px 14px;
                      font-size: 13.5px; font-weight: 600; background-color: #fff; }

/* Las dos filas del panel usan .detalle-2col, pero alli la segunda columna es
   un RESUMEN lateral (mas estrecho y pegajoso). En el panel son dos paneles
   IGUALES, asi que aqui se corrige: mismas dos columnas y misma altura.
   Antes heredaban 1fr/360px + align-items:start y salian descuadrados
   (403x465 junto a 360x355), que es justo lo que se ve torcido. */
.panel-2col { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
.panel-2col > section { min-width: 0; display: flex; flex-direction: column; }
/* El cuerpo estira para que los dos paneles cierren a la misma altura, y ademas
   se vuelve columna para poder repartir el aire de dentro (ver .accesos). */
.panel-2col > section > .panel-cuerpo { flex: 1; display: flex; flex-direction: column; }
/* ESTA regla DEBE ir despues de la de arriba: las media queries NO suman
   especificidad, asi que la @media de .detalle-2col (mas arriba en el fichero)
   perdia contra .panel-2col y el panel se quedaba a DOS columnas hasta en un
   movil de 390px. Se repite aqui, al final, para que gane. */
@media (max-width: 1100px) { .panel-2col { grid-template-columns: minmax(0, 1fr); } }

/* ---- Embudo comercial ---- */
/* El embudo se adapta a SU PANEL, no a la pantalla: en el escritorio el panel
   ocupa media columna, asi que a 1112px de ventana la caja de conversion (200px
   fijos) mas los rotulos dejaban la barra en CERO pixeles aunque sobrara
   pantalla. Con una consulta de contenedor, la caja baja debajo cuando el panel
   se estrecha, sin importar lo ancha que sea la ventana.
   (Mismo patron que la ficha de la web publica; ver web.css.) */
/* OJO: container-type va en el PANEL (el padre), nunca en .embudo-caja: un
   elemento no puede responder a su propia consulta de contenedor. */
.panel-embudo { container-type: inline-size; }
.embudo-caja > .embudo-barras { min-width: 0; }
.embudo-caja { display: grid; grid-template-columns: minmax(0, 1fr) minmax(160px, 200px);
               gap: clamp(12px, 1.4vw, 20px); }
/* Cuando el panel se estrecha, la caja de conversion baja debajo y la barra
   recupera todo el ancho. Da igual lo grande que sea la pantalla. */
@container (max-width: 580px) { .embudo-caja { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 700px)     { .embudo-caja { grid-template-columns: minmax(0, 1fr); } }
/* Los rotulos ceden antes que la barra: la barra ES el dato. */
.emb2-fila { display: grid; grid-template-columns: minmax(0, 92px) minmax(46px, 1fr) auto auto;
             align-items: center; gap: clamp(6px, .7vw, 10px); padding: 6px 0; }
.emb2-etq { font-size: clamp(11.5px, 1vw, 13px); font-weight: 600; color: var(--px-ink);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.emb2-pista { min-width: 0; }
/* La barra con el canto derecho en bisel: lee como embudo sin dibujar uno. */
.emb2-barra { display: block; height: 26px; border-radius: 3px 0 0 3px;
              clip-path: polygon(0 0, 100% 0, calc(100% - 13px) 100%, 0 100%);
              transition: width .25s ease; }
.emb2-num { text-align: right; font-size: clamp(13px, 1.1vw, 15px); color: var(--px-ink); min-width: 20px; }
.emb2-pct { font-size: clamp(11px, .95vw, 12.5px); color: var(--px-text-muted); text-align: right; min-width: 42px; }

/* "Otras etapas": plegado nativo, sin JS. */
.otras-etapas { margin-top: 12px; border: 1px solid var(--px-border); border-radius: 12px; }
.otras-etapas summary { display: flex; align-items: center; justify-content: space-between;
                        padding: 10px 14px; cursor: pointer; list-style: none;
                        font-size: 13.5px; font-weight: 600; color: var(--px-text-muted);
                        user-select: none; }
.otras-etapas summary::-webkit-details-marker { display: none; }
.otras-etapas summary svg { transition: transform .15s; }
.otras-etapas[open] summary svg { transform: rotate(180deg); }
.chips-etapas { display: flex; flex-wrap: wrap; gap: 8px; padding: 2px 14px 12px; }
.chip-etapa { display: inline-flex; align-items: center; gap: 7px;
              border: 1px solid var(--px-border); border-radius: 999px;
              padding: 5px 12px; font-size: 12.5px; color: var(--px-text-muted);
              background: #FBFDFC; }
.chip-etapa i { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.chip-etapa strong { color: var(--px-ink); }

/* La caja de conversion, a la derecha del embudo. */
.conv-caja { position: relative; border: 1px solid var(--px-border); border-radius: 14px;
             background: #FBFDFC; padding: 18px; text-align: left; }
.conv-caja .lab { font-size: 12.5px; color: var(--px-text-muted); }
.conv-num { font-size: 34px; font-weight: 800; letter-spacing: -.02em;
            color: var(--px-teal-dark); margin: 4px 0 6px; }
.conv-caja p { margin: 0; font-size: 13px; line-height: 1.45; color: var(--px-text-muted); }
.conv-ico { position: absolute; right: 14px; bottom: 14px;
            width: 44px; height: 44px; border-radius: 50%;
            background: var(--px-teal-soft); color: var(--px-teal-dark);
            display: grid; place-items: center; }

/* ---- Atencion requerida ---- */
/* gap 0 a proposito: el divisor es el borde derecho de la primera celda, y con
   12px de hueco caia 6px a la izquierda del centro real. Con las dos columnas
   pegadas, la raya SI parte el bloque por la mitad; el aire va en el padding. */
.atencion-stats { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0;
                  margin-bottom: 14px; }
.atencion-stats > div { text-align: center; padding: 10px 14px 12px; }
.atencion-stats.tres { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* La raya va ENTRE columnas: con :first-child solo salia una, y con tres
   cifras la del medio quedaba pegada a la de la derecha. */
.atencion-stats > div + div { border-left: 1px solid var(--px-border); }
.atencion-stats .lab { font-size: 12.5px; color: var(--px-text-muted); margin-bottom: 4px; }
.atencion-stats .num { font-size: 30px; font-weight: 800; letter-spacing: -.02em;
                       color: var(--px-ink); }
/* A 30px el umbral baja a 3.0, pero --px-warning se queda en 2.65 igual. */
.atencion-stats .num.aviso { color: var(--px-warning-big); }
.vacio.chico { padding: 18px 12px 10px; }
.vacio.chico h3 { margin: 8px 0 4px; }

/* ---- Actividad ---- */
.feed-mas { display: block; text-align: center; padding: 12px 16px;
            border-top: 1px solid var(--px-border);
            font-size: 13.5px; font-weight: 600; color: var(--px-teal-dark); }
.feed-mas:hover { background: var(--px-teal-soft); text-decoration: none; }
.feed-paginas { display: flex; align-items: center; justify-content: space-between;
                gap: 12px; padding: 12px 16px; border-top: 1px solid var(--px-border); }

/* ==================================================================
   TRANSICIONES ENTRE PANTALLAS
   Norte sigue siendo PHP con recarga entera: no hay SPA ni framework, y no
   hace falta. Con @view-transition el navegador funde una pantalla con la
   siguiente el solo, y a las partes que llevan view-transition-name (el
   lateral y la barra de titulo) las trata como el MISMO elemento en las dos
   paginas, asi que ni parpadean ni saltan: se quedan quietas mientras cambia
   lo de dentro. Cero JavaScript.

   Donde no exista (Firefox, Safari viejo) no pasa nada: la regla se ignora y
   la navegacion es la de siempre.
   ================================================================== */
@view-transition { navigation: auto; }

.lateral  { view-transition-name: lateral; }
.topbar   { view-transition-name: barra-titulo; }
.contenido { view-transition-name: contenido; }

/* Solo el contenido se funde, y rapido: 180ms es el limite por debajo del cual
   se percibe como "instantaneo pero suave". Mas lento estorba a quien trabaja
   ocho horas aqui. */
::view-transition-old(contenido) { animation: px-sale .12s ease-in both; }
::view-transition-new(contenido) { animation: px-entra .18s ease-out both; }
@keyframes px-sale  { to { opacity: 0; transform: translateY(-4px); } }
@keyframes px-entra { from { opacity: 0; transform: translateY(6px); } }

/* El lateral y el titulo no se animan: cambiar de pantalla no debe moverlos. */
::view-transition-group(lateral),
::view-transition-group(barra-titulo) { animation: none; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(contenido),
  ::view-transition-new(contenido) { animation: none; }
}


/* =====================================================================
   REPORTES — inteligencia comercial (20 ago 2026)
   Graficas en SVG servidas desde PHP: sin librerias ni CDN.
   ===================================================================== */
.rep-filtros {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  background: #fff; border: 1px solid var(--px-border); border-radius: var(--radio);
  padding: 12px 14px; margin-bottom: 18px; box-shadow: var(--px-shadow);
}
.rep-campo {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--px-border); border-radius: 9px;
  padding: 0 10px; background: #fff; color: var(--px-text-muted);
  transition: border-color .15s, box-shadow .15s;
}
.rep-campo:focus-within { border-color: var(--px-teal-dark); box-shadow: 0 0 0 3px var(--px-teal-soft); }
.rep-campo select {
  border: 0; background: transparent; padding: 9px 2px 9px 0;
  font: inherit; font-size: 14px; color: var(--px-ink); cursor: pointer;
  max-width: 220px;
}
.rep-campo select:focus { outline: none; }
.rep-fechas { display: inline-flex; align-items: center; gap: 6px; }
.rep-fechas.oculto { display: none; }
.rep-fechas input[type="date"] {
  border: 1px solid var(--px-border); border-radius: 9px; padding: 8px 10px;
  font: inherit; font-size: 14px; color: var(--px-ink); background: #fff;
}
.rep-fechas input[type="date"]:focus {
  outline: none; border-color: var(--px-teal-dark); box-shadow: 0 0 0 3px var(--px-teal-soft);
}
.rep-guion { color: var(--px-text-muted); }
.rep-exportar { display: inline-flex; gap: 8px; margin-left: auto; }
.rep-exportar .btn { gap: 7px; }

/* Rejilla: curva ancha + embudo estrecho; debajo, tabla ancha + ideas. */
/* Los anchos SI son distintos a proposito (la curva necesita mas sitio que el
   embudo), pero los paneles de una misma fila tienen que CERRAR A LA MISMA
   ALTURA: con align-items:start quedaban 387px junto a 296px y se veia torcido. */
.rep-grid { display: grid; grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr);
            gap: 18px; align-items: stretch; }
.rep-grid > .panel { margin: 0; display: flex; flex-direction: column; }
.rep-grid > .panel > .panel-cuerpo { flex: 1; }
/* minmax(0, 1fr) y NO "1fr": "1fr" no baja del ancho minimo del contenido, asi
   que la columna se quedaba en 671px dentro de un movil de 375 y empujaba la
   pagina entera. Con el minimo en 0 la columna si encoge. */
@media (max-width: 1080px) { .rep-grid { grid-template-columns: minmax(0, 1fr); } }

.rep-cab-der { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.rep-leyenda { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--px-text-muted); }
.rep-leyenda i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.rep-gran select {
  border: 1px solid var(--px-border); border-radius: 8px; padding: 6px 9px;
  font: inherit; font-size: 13px; color: var(--px-ink); background: #fff; cursor: pointer;
}
.rep-gran select:focus { outline: none; border-color: var(--px-teal-dark); }

/* Sin overflow:visible. Los rotulos de los ejes YA caben dentro del viewBox
   (para eso estan los margenes ml/mb), y dejarlo visible hacia que el dibujo
   pintase fuera de su caja y empujara el ancho de la pagina en el movil. */
.rep-svg { width: 100%; height: auto; display: block; }

.rep-guia { stroke: var(--px-border); stroke-width: 1; }
.rep-eje  { font-size: 11px; fill: var(--px-text-muted); font-family: inherit; }
.rep-pie {
  margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--px-border);
  font-size: 12.5px; color: var(--px-text-muted); line-height: 1.6;
}
.rep-pie.sin-borde { border-top: 0; margin: 0; padding: 12px 16px 14px; }
.rep-pie strong { color: var(--px-ink); font-weight: 700; }

/* Embudo: trapecios apilados, cifra encima y porcentaje al lado. */
.rep-embudo { display: flex; flex-direction: column; gap: 3px; }
.rep-etapa { position: relative; display: flex; align-items: center; }
.rep-trapecio { width: calc(100% - 62px); height: 46px; display: block; }
.rep-etapa-txt {
  position: absolute; left: 0; width: calc(100% - 62px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 46px; line-height: 1.15; pointer-events: none;
}
/* El color lo pone color_texto_sobre() en linea, calculado por luminancia:
   heredar es lo correcto aqui, no fijar un color que puede no contrastar. */
.rep-etapa-nom { font-size: 11.5px; font-weight: 600; color: inherit; }
.rep-etapa-n { font-size: 17px; font-weight: 800; color: inherit; }
.rep-etapa-pct {
  position: absolute; right: 0; width: 56px; text-align: right;
  font-size: 14px; font-weight: 700; color: var(--px-ink);
}
.rep-otras { margin-top: 14px; }
.rep-otras > summary {
  cursor: pointer; font-size: 13px; color: var(--px-text-muted);
  padding: 6px 0; list-style: none; display: flex; align-items: center; gap: 6px;
}
.rep-otras > summary::-webkit-details-marker { display: none; }
.rep-otras > summary::before { content: '▸'; transition: transform .15s; display: inline-block; }
.rep-otras[open] > summary::before { transform: rotate(90deg); }
.rep-otras-lista { display: flex; flex-wrap: wrap; gap: 6px; padding-top: 6px; }

/* Tabla de categorias */
.tabla-rep tr.fila-top { background: var(--px-teal-soft); }
.rep-conv { display: flex; align-items: center; gap: 9px; }
.rep-conv strong { min-width: 34px; }
.rep-conv .embudo-barra { width: 68px; flex-shrink: 0; }
/* .embudo-barra span no trae color propio (en el resto de Norte se le pasa en
   linea). Aqui la barra siempre significa lo mismo, asi que el color va fijo. */
.rep-conv .embudo-barra span { background: var(--px-teal); }
.rep-spark { width: 60px; height: 20px; display: block; }

/* Ideas accionables */
.rep-ideas { display: flex; flex-direction: column; gap: 10px; }
.rep-idea {
  display: flex; gap: 11px; align-items: flex-start;
  border: 1px solid var(--px-border); border-radius: 11px; padding: 12px 13px; background: #fff;
}
.rep-idea p { margin: 3px 0 0; font-size: 13px; color: var(--px-text-muted); line-height: 1.5; }
.rep-idea strong { font-size: 13.5px; color: var(--px-ink); line-height: 1.35; display: block; }
.rep-idea-ico {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.rep-idea.bien  .rep-idea-ico { background: #E4F6EE; color: #0B7A4F; }
.rep-idea.info  .rep-idea-ico { background: #EAF4FD; color: #0C5E96; }
.rep-idea.aviso .rep-idea-ico { background: #FFF4DF; color: #9A6410; }
.rep-ver { margin-top: 14px; }

@media (max-width: 640px) {
  .rep-filtros { gap: 8px; }
  .rep-exportar { margin-left: 0; width: 100%; }
  .rep-exportar .btn { flex: 1; justify-content: center; }
  .rep-campo select { max-width: 100%; }
  .rep-etapa-nom { font-size: 10.5px; }
}

/* ===== INTEGRACIONES (20 ago 2026) ===== */
.int-grupo { margin: 22px 0 12px; font-size: 13px; font-weight: 800; letter-spacing: .04em;
             text-transform: uppercase; color: var(--px-text-muted); }
.int-grupo:first-of-type { margin-top: 4px; }
.int-rejilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
               gap: 18px; align-items: stretch; margin-bottom: 8px; }
.int-rejilla > .panel { margin: 0; display: flex; flex-direction: column; }
.int-rejilla > .panel > .panel-cuerpo { flex: 1; display: flex; flex-direction: column; }
.int-tarjeta form { display: flex; flex-direction: column; flex: 1; }
.int-ayuda { margin: 0 0 12px; font-size: 13px; line-height: 1.5; color: var(--px-text-muted); }
/* El icono no encoge; el texto va SIEMPRE envuelto en un elemento (un <span>).
   Prosa suelta aqui dentro se parte en varios items flex y sale desordenada. */
.int-aviso { margin: 0 0 12px; padding: 8px 10px; border-radius: 9px; font-size: 12.5px;
             background: var(--px-teal-soft); color: #06655F; display: flex; gap: 7px; align-items: flex-start; }
.int-aviso > svg { flex: none; margin-top: 1px; }
.int-aviso > span { min-width: 0; }
.int-pie { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: auto;
           padding-top: 14px; border-top: 1px solid var(--px-border); }
.int-switch { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px;
              font-weight: 600; color: var(--px-ink); cursor: pointer; }
.int-switch input { width: 16px; height: 16px; accent-color: var(--px-teal-dark); }
.int-pie select { width: auto; min-height: 38px; font-size: 13px; }
.int-pie .btn { margin-left: auto; }
.int-falta { margin: 10px 0 0; font-size: 12.5px; color: #9A6410;
             display: flex; gap: 6px; align-items: flex-start; }

/* ===== Galeria de la ficha (admin) ===== */
/* Tope de 300px por columna: con "1fr" una sola imagen se estiraba a todo el
   ancho del panel y salia una miniatura gigantesca. */
.gal-admin { display: grid; gap: 14px; margin-bottom: 18px;
             grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 300px)); }
.gal-admin-item { border: 1px solid var(--px-border); border-radius: 12px; overflow: hidden;
                  background: #fff; display: flex; flex-direction: column; }
.gal-admin-item img { width: 100%; aspect-ratio: 8 / 5; object-fit: cover;
                      object-position: top center; display: block; background: var(--px-teal-soft); }
.gal-admin-datos { padding: 10px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.gal-admin-form { display: flex; gap: 6px; align-items: center; }
.gal-admin-form input { flex: 1 1 auto; min-width: 0; font-size: 13px; min-height: 34px; }
.gal-admin-acc { display: flex; gap: 6px; margin-top: auto; }
.gal-admin-acc form { display: inline-flex; }
.gal-admin-acc button[disabled] { opacity: .3; cursor: not-allowed; }
.gal-admin-subir { border-top: 1px solid var(--px-border); padding-top: 16px; }

/* Elegir capturas dibujadas. La rejilla encoge las fichas en vez de tirarlas
   abajo: en el movil siguen siendo dos por linea, mas pequenas. */
.gal-genera { border-top: 1px solid var(--px-border); padding-top: 16px; margin-bottom: 18px; }
.gal-genera h3 { margin: 0 0 4px; font-size: 15px; font-weight: 800; color: var(--px-ink); }
/* Repartos limpios: 4, 2+2 o una por linea. Con auto-fit salia 3+1 en los
   anchos intermedios y la cuarta se quedaba sola en su fila, que canta mucho.
   Las @media van DESPUES de la regla base: misma especificidad, gana la ultima. */
.gal-genera-rejilla { display: grid; gap: clamp(8px, 1.4vw, 14px); margin-bottom: 14px;
  grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gal-genera-op { display: flex; flex-direction: column; min-width: 0; cursor: pointer;
  border: 1px solid var(--px-border); border-radius: 12px; overflow: hidden; background: #fff;
  transition: border-color .15s, box-shadow .15s; }
.gal-genera-op:hover { border-color: var(--px-teal-dark); }
.gal-genera-op:focus-within { outline: 2px solid var(--px-teal-solid); outline-offset: 2px; }
.gal-genera-op img { width: 100%; aspect-ratio: 8 / 5; object-fit: cover; display: block;
  background: var(--px-teal-soft); border-bottom: 1px solid var(--px-border); }
.gal-genera-pie { display: flex; gap: 8px; padding: 10px; align-items: flex-start; min-width: 0; }
.gal-genera-pie input { margin-top: 2px; flex: none; accent-color: var(--px-teal-solid); }
.gal-genera-pie > span { min-width: 0; }
.gal-genera-pie strong { display: block; font-size: clamp(12.5px, 1.1vw, 13.5px); color: var(--px-ink); }
.gal-genera-pie em { display: block; font-style: normal; font-size: 12px; color: var(--px-text-muted);
  line-height: 1.35; }
.gal-genera-op.esta { border-color: var(--px-teal); background: var(--px-teal-soft); }
.gal-genera-op.esta img { opacity: .55; }
@media (max-width: 1100px) { .gal-genera-rejilla { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .gal-genera-rejilla { grid-template-columns: minmax(0, 1fr); } }

/* ==================================================================
   Editor de un sistema base: "Lo que se vende", contadores y la vista
   previa del buscador.
   ================================================================== */
.se-vende .panel-cab h2 .ico { color: var(--px-teal-dark); }
.sv-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.sv-dato {
  display: flex; flex-direction: column; gap: 3px;
  padding: 14px 16px; border: 1px solid var(--gris-2); border-radius: 10px;
  background: var(--px-surface); min-width: 0;
}
/* El precio de la tienda es EL numero: el que paga el cliente. Se distingue
   del resto a proposito, porque el de al lado se le parece y no es lo mismo. */
.sv-cobra { border-color: #BFE3D3; background: linear-gradient(180deg, #F2FBF6, var(--px-surface)); }
.sv-lab { font-size: 12px; font-weight: 700; text-transform: uppercase;
          letter-spacing: .04em; color: var(--px-text-muted); }
.sv-num { font-size: clamp(20px, 2.2vw, 27px); font-weight: 800;
          letter-spacing: -.02em; color: var(--px-ink); line-height: 1.1; }
.sv-cobra .sv-num { color: #0F8043; }
/* La referencia interna va en gris: no es dinero que entre ni salga. */
.sv-ref { color: var(--px-text-muted) !important; }
.sv-pie { font-size: 12px; color: var(--px-text-muted); line-height: 1.4; }
.sv-anillo {
  margin: 14px 0 0; padding: 10px 13px; border-radius: 8px;
  background: var(--px-teal-soft); color: var(--px-ink);
  font-size: 13px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.sv-anillo .ico { color: var(--px-teal-dark); flex-shrink: 0; }
/* Un latido corto al recalcular: sin el, cambiar una cifra al otro lado de la
   pantalla pasa desapercibido. */
.sv-late .sv-num { transition: none; animation: sv-late .6s ease; }
@keyframes sv-late { 0% { background: var(--px-teal-soft); } 100% { background: transparent; } }
@media (prefers-reduced-motion: reduce) { .sv-late .sv-num { animation: none; } }

.sv-incluida {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: #0B6B5F; background: rgba(15, 128, 67, .12);
  padding: 1px 6px; border-radius: 999px; margin-left: 6px;
}

/* Contador de caracteres, pegado a su etiqueta. */
.cuenta {
  font-size: 11px; font-weight: 600; color: var(--px-text-muted);
  background: var(--gris-1); border-radius: 999px; padding: 1px 7px; margin-left: 6px;
}
/* Pasarse del limite no invalida el campo: solo avisa de que el buscador
   cortara. Por eso ambar y no rojo. */
.cuenta-larga { color: var(--px-warning-txt); background: rgba(183, 110, 0, .12); }
.cuenta-corta { color: var(--px-text-muted); }

/* Vista previa del resultado en el buscador. */
.serp { margin-top: 18px; }
.serp-rot {
  display: flex; align-items: center; gap: 6px; margin-bottom: 7px;
  font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--px-text-muted);
}
.serp-caja {
  border: 1px solid var(--gris-2); border-radius: 10px;
  padding: 14px 16px; background: var(--px-surface); max-width: 620px;
}
.serp-url { font-size: 12.5px; color: var(--px-text-muted); margin-bottom: 3px; word-break: break-all; }
/* El azul del enlace de un buscador NO es el teal de la marca: la vista previa
   miente si se pinta con la paleta de Pixelia en vez de con la de Google. */
.serp-tit {
  font-size: 18px; line-height: 1.3; color: #1A0DAB; margin-bottom: 3px;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.serp-desc {
  font-size: 13.5px; line-height: 1.55; color: #4D5156;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
/* La celda de la chapa no crece: el nombre es lo que tiene que ceder. */
.sv-cel-incl { width: 1%; white-space: nowrap; text-align: right; }
.sv-cel-incl .sv-incluida { margin-left: 0; }

/* "En sistemas" desplegable: el numero solo no basta para decidir si se puede
   tocar un precio o borrar la funcionalidad. */
.usos > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 5px;
  min-height: 32px; color: var(--px-teal-txt); font-size: 13px;
}
.usos > summary::-webkit-details-marker { display: none; }
.usos > summary::after {
  content: ""; width: 6px; height: 6px; border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor; transform: rotate(45deg) translateY(-2px);
  transition: transform .15s;
}
.usos[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
.usos ul { margin: 4px 0 0; padding: 0 0 0 14px; font-size: 13px; }
.usos li { margin: 2px 0; }
@media (prefers-reduced-motion: reduce) { .usos > summary::after { transition: none; } }

/* ==================================================================
   Solicitudes de cambio: el detalle del panel (modules/cambios/ver.php)
   Lo que se publica aqui lo lee el cliente en su portal, asi que la
   pantalla se parece a la suya a proposito.
   ================================================================== */
.cb-datos { margin: 14px 0 0; padding: 12px 0 0; border-top: 1px solid var(--px-border); }
.cb-datos > div { display: flex; justify-content: space-between; gap: 12px;
                  padding: 6px 0; font-size: 13.5px; }
.cb-datos dt { color: var(--px-text-muted); flex-shrink: 0; }
.cb-datos dd { margin: 0; text-align: right; color: var(--px-ink); min-width: 0; }

.cb-sep { border-top: 1px solid var(--px-border); margin: 18px 0; }
.cb-sub { margin: 0 0 10px; font-size: 14px; font-weight: 700; color: var(--px-ink);
          display: flex; align-items: center; gap: 8px; }

.cb-estado { display: flex; align-items: center; gap: 10px; font-size: 13px;
             color: var(--px-text-muted); flex-wrap: wrap; }
.cb-estado select { padding: 6px 28px 6px 10px; font-size: 13px; }

/* Una evidencia: miniatura + texto + quitar. La miniatura NO encoge y el
   texto lleva min-width:0, que es lo unico que impide que una URL larga
   ensanche la fila entera. */
.cb-evs { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.cb-ev { display: flex; align-items: flex-start; gap: 11px;
         border: 1px solid var(--px-border); border-radius: 11px;
         padding: 10px; background: #FBFDFC; }
.cb-ev-txt { flex: 1; min-width: 0; font-size: 13.5px; line-height: 1.45; }
.cb-ev-txt b { display: block; color: var(--px-ink); margin-bottom: 2px; }
.cb-ev-txt p { margin: 0 0 4px; color: var(--px-text-muted); }
.cb-ev-txt a { font-size: 12.5px; word-break: break-all; }
.cb-ev-quitar { flex-shrink: 0; }
.cb-ev-img { display: block; flex-shrink: 0; width: 76px; height: 56px;
             border-radius: 8px; overflow: hidden; border: 1px solid var(--px-border);
             background: var(--px-page); }
.cb-ev-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Suelta (la captura que manda el cliente) se ve entera, no recortada. */
.cb-ev-img.es-suelta { width: auto; height: auto; max-width: 100%; margin: 0 0 12px; }
.cb-ev-img.es-suelta img { height: auto; max-height: 260px; object-fit: contain; }

@media (max-width: 520px) {
  .cb-datos > div { flex-direction: column; gap: 2px; }
  .cb-datos dd { text-align: left; }
}

/* ---- Avance publicado (modules/proyectos/ver.php) ---- */
.av-hitos { list-style: none; margin: 0 0 4px; padding: 0; display: grid; gap: 10px; }
.av-hito { border: 1px solid var(--px-border); border-radius: 11px; padding: 11px 13px;
           background: #FBFDFC; font-size: 13.5px; }
/* Lo interno se ve distinto de un vistazo: confundirlo con lo publicado es
   creer que el cliente esta al dia cuando no lo esta. */
.av-hito.es-interno { background: repeating-linear-gradient(135deg, #F7F9F8 0 8px, #FBFDFC 8px 16px);
                     border-style: dashed; }
.av-hito-cab { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 4px; }
.av-hito-f { font-size: 12px; color: var(--px-text-muted); font-variant-numeric: tabular-nums; }
.av-hito b { display: block; color: var(--px-ink); }
.av-hito p { margin: 3px 0 0; color: var(--px-text-muted); line-height: 1.45; }
.av-quitar { margin-left: auto; }


/* ==================================================================
   El aviso flotante y la vuelta al sitio
   ------------------------------------------------------------------
   Dos quejas que resultaron ser la misma: «no hay retroalimentacion» y
   «me devuelve arriba de la pagina». El aviso se pintaba al principio
   del contenido, asi que al restaurar el scroll el usuario dejaba de
   verlo. Por eso el aviso se despega del documento y va donde SI se
   mira, y por eso puede irse solo sin llevarse la informacion.
   ================================================================== */
.flash-flota {
  position: fixed;
  top: 18px;
  right: 18px;
  z-index: 60;                 /* por encima del contenido, por debajo del dialogo */
  max-width: min(420px, calc(100vw - 36px));
  margin: 0;
  box-shadow: 0 6px 24px rgba(0, 36, 84, .16);
  animation: flash-entra .22s ease-out;
}
@keyframes flash-entra {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
.flash-flota.se-va { opacity: 0; transform: translateY(-8px); transition: opacity .3s, transform .3s; }

/* En movil ocupa el ancho y va abajo: arriba tapa la cabecera. */
@media (max-width: 640px) {
  .flash-flota { top: auto; bottom: 14px; left: 14px; right: 14px; max-width: none; }
}

/* Quien pide menos movimiento no lo tiene. */
@media (prefers-reduced-motion: reduce) {
  .flash-flota { animation: none; }
  .flash-flota.se-va { transition: none; }
}
