/* ==========================================================================
   Casa Verdezza CRM — panel comercial
   Depende de /shared/greenhouse.css.

   Decisiones propias de esta superficie:
   · Aquí manda la densidad: lo usa el equipo de dirección/administración
     muchas veces al día, en escritorio, para leer y comparar. No se gasta
     espacio en efectos.
   · El movimiento aparece solo al abrir, cerrar, guardar o fallar algo.
   · Por debajo de 768px la tabla se convierte en lista de tarjetas: cinco
     columnas en un teléfono obligan a scroll horizontal, que el brief prohíbe.
   ========================================================================== */

/* ==========================================================================
   Ingreso
   La pantalla, la tarjeta y el lockup de marca son del sistema compartido.
   ========================================================================== */

#login-submit { margin-top: var(--s-8); }
#login-error { margin-top: var(--s-5); }

/* ==========================================================================
   Estructura
   ========================================================================== */

/* El logotipo es un enlace al sitio: como control, cumple el objetivo
   táctil aunque el arte mida 38px. */
.brand { text-decoration: none; gap: var(--s-3); min-height: var(--tap); }
.brand-logo { height: 38px; width: auto; display: block; }
.brand-app {
  padding-left: var(--s-3);
  border-left: 1px solid var(--rule-strong);
  font-family: var(--font-display); font-weight: 600;
  font-size: 1.0625rem; line-height: 1;
  color: var(--accent);
  font-variation-settings: "SOFT" 40, "WONK" 1;
}

.crm-main { max-width: 1220px; margin-inline: auto; padding: var(--s-8) var(--s-6) var(--s-20); }

/* ==========================================================================
   Panorama
   La fila de métricas y el aviso de seguimiento van ANTES del buscador: se
   leen primero porque contestan primero. El buscador es para cuando ya sabes
   a quién buscas; el panorama es para cuando todavía no.
   ========================================================================== */

.overview {
  display: grid;
  gap: var(--s-4);
  margin-bottom: var(--s-8);
  padding-bottom: var(--s-8);
  /* Una regla de 1px separa el panorama del trabajo de lista, en vez de
     meter las métricas en otra caja dentro de la caja. */
  border-bottom: 1px solid var(--rule);
}

/* El aviso de seguimiento reparte: texto a la izquierda, salida a la derecha. */
.followup-strip { align-items: center; gap: var(--s-4); flex-wrap: wrap; }
.followup-strip > span { flex: 1; min-width: 260px; }
.followup-strip strong { display: block; }
.followup-strip .btn { flex: none; background: var(--pane); }

/* --- Próximos ingresos --- */

.upcoming { padding: var(--s-5) var(--s-6) var(--s-6); }
.upcoming .block-head { margin-bottom: var(--s-2); }

.upcoming-list { list-style: none; margin: 0; padding: 0; }
.upcoming-list li + li { border-top: 1px solid var(--rule); }

.upcoming-item {
  width: 100%;
  display: flex; align-items: center; gap: var(--s-5);
  min-height: var(--tap);
  padding: var(--s-3) var(--s-2);
  border: none; background: none;
  font-family: inherit; font-size: var(--t-body); color: inherit;
  text-align: left;
  cursor: pointer; touch-action: manipulation;
  border-radius: var(--r-sm);
  transition: background var(--dur-fast) var(--ease-soft);
}
.upcoming-item:hover { background: var(--pane-soft); }

/* La fecha manda: es una lista ordenada por cuándo, no por quién. */
.upcoming-when { flex: none; width: 128px; display: grid; gap: 1px; }
.upcoming-date { font-weight: 700; }
.upcoming-in { font-size: var(--t-small); color: var(--ink-faint); }

.upcoming-who { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; min-width: 0; }
.upcoming-name { font-weight: 700; }

/* Vacío: el panel pierde la elevación y se convierte en una nota. Una caja
   blanca grande diciendo "no hay nada" compite con las métricas de arriba. */
.upcoming.is-empty {
  background: transparent;
  border-style: dashed;
  box-shadow: none;
  padding: var(--s-4) var(--s-5);
}
.upcoming.is-empty .block-head { margin-bottom: var(--s-1); }
.upcoming-empty { color: var(--ink-faint); font-size: var(--t-small); }

@media (max-width: 560px) {
  .overview { margin-bottom: var(--s-6); padding-bottom: var(--s-6); }
  .upcoming { padding: var(--s-4) var(--s-5) var(--s-5); }
  .upcoming-item { flex-direction: column; align-items: flex-start; gap: var(--s-1); padding-block: var(--s-3); }
  .upcoming-when { width: auto; display: flex; align-items: baseline; gap: var(--s-3); }
  .followup-strip .btn { width: 100%; }
}

/* ==========================================================================
   Búsqueda y filtros de etapa
   ========================================================================== */

.toolbar { margin-bottom: var(--s-5); }

/* El buscador es del sistema; el CRM solo le pone límite de ancho, porque
   un campo de búsqueda de 1200px invita a escribir una frase, no un nombre. */
.search-field { max-width: 440px; margin-bottom: var(--s-5); }

.filters-label { margin-bottom: var(--s-3); }
.filters { display: flex; gap: var(--s-2); flex-wrap: wrap; }

/* `.count` y `.is-zero` VIVIAN AQUI y ahora estan en `/shared`, colgando de
   `.segment`: Family necesito lo mismo y dos copias de una pieza acaban
   divergiendo. Lo que sigue siendo decision de esta pantalla es ENSENAR las
   etapas vacias — el pipeline se lee entero — y eso lo dice el marcado al
   poner `is-zero`, no el componente. */

/* ==========================================================================
   Tabla de prospectos
   ========================================================================== */

/* La tabla (.data-table), su colapso a tarjetas por debajo de 768px y la
   acción de fila (.btn-row) son del sistema. Aquí solo qué dice cada columna. */
.table-card { overflow: hidden; }
.data-table tbody tr { cursor: pointer; }

.cell-name { font-weight: 700; font-size: var(--t-body-lg); }
.cell-contact, .cell-source { color: var(--ink-soft); }
/* Sin capitalize: romperia "WhatsApp". El texto ya llega listo desde el JS. */
.cell-date { color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ==========================================================================
   Etapas del pipeline
   El color dice en qué punto está cada prospecto, para poder barrer la tabla
   sin leer: ámbar = recién llegado, exige acción · verde tenue = calificando
   azul de confianza = trato activo · verde sólido = ingresó · rojo = cerrado.
   ========================================================================== */

.badge.contacto { background: var(--clay-wash); color: var(--clay); }
/* Azul-verdoso, no oro. Con la migración de marca `--trust` pasó a ser el
   oro del manual, y las cuatro etapas de trato activo quedaron del mismo
   color que "Contacto" (terracota) — la tabla dejó de poder barrerse sin
   leer, que es justo para lo que existe este código de color. */
.badge.asesoria, .badge.visita, .badge.propuesta, .badge.negociacion {
  background: var(--teal-wash); color: var(--teal);
}
.badge.ingreso { background: var(--sage); color: var(--paper); }
.badge.descartado { background: var(--alert-wash); color: var(--alert); }

/* ==========================================================================
   Panel de detalle
   ========================================================================== */

.detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--s-4); }
/* Quién es y en qué punto está, juntos y arriba del todo: la etapa estaba
   solo dentro del <select>, así que había que mirar un control de edición
   para leer un dato. */
.detail-id { display: flex; align-items: flex-start; gap: var(--s-4); min-width: 0; }
.detail-id .avatar { margin-top: 2px; }
.detail-head h2 { font-size: var(--t-h2); line-height: 1.18; }
.detail-badges { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-3); }

.detail-meta {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5); align-items: center;
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  color: var(--ink-soft); font-size: var(--t-small);
}
.detail-meta span { display: inline-flex; align-items: center; gap: 6px; }
.detail-meta a { font-weight: 700; text-decoration: none; }
.detail-meta a:hover { text-decoration: underline; }

.detail-section { margin-top: var(--s-8); padding-top: var(--s-6); border-top: 1px solid var(--rule); }
.detail-section > h3 {
  display: flex; align-items: center; gap: var(--s-2);
  margin-bottom: var(--s-4);
  font-family: var(--font-body); font-weight: 700;
  font-size: var(--t-micro); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-soft);
  font-variation-settings: normal;
}
.detail-section > h3 .icon { width: 17px; height: 17px; color: var(--accent); }

/* Rejilla de dos columnas, no flex: con flex, un valor corto quedaba en la
   misma línea que su etiqueta y uno largo ("Necesidades") saltaba abajo, así
   que la lista se leía como si fueran dos tipos de dato distintos. */
.kv-list { display: grid; gap: var(--s-3); margin: 0; }
.kv {
  display: grid;
  grid-template-columns: minmax(0, 210px) 1fr;
  gap: var(--s-2) var(--s-4);
  font-size: var(--t-small);
}
.kv dt { color: var(--ink-faint); font-weight: 700; }
.kv dd { color: var(--ink); }

@media (max-width: 480px) {
  .kv { grid-template-columns: 1fr; gap: 2px; }
}

/* Bitácora: append-only, lo más reciente arriba. Usa la línea de tiempo del
   sistema; aquí solo el tono de cada tipo de gestión. */
.timeline .tag { text-transform: capitalize; letter-spacing: 0.02em; }

/* Conversión a residente: acción poco frecuente e irreversible. Va enmarcada
   y con confirmación en dos pasos (ver app.js). */
.convert-box {
  background: var(--pane-soft);
  border: 1.5px solid var(--rule-strong);
  border-radius: var(--r-md);
  padding: var(--s-5);
}
.convert-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-4); }
#convert-step-2 .notice { margin-top: var(--s-5); }

/* ==========================================================================
   Responsive — 320 / 375 / 414 / 768 / 1024 / 1280+
   ========================================================================== */

@media (max-width: 1024px) {
  .crm-main { padding: var(--s-6) var(--s-4) var(--s-16); }
}

@media (max-width: 768px) {
  .search-field { max-width: none; }
}

@media (max-width: 560px) {
  #logout-btn { white-space: nowrap; }
  .sheet { padding: var(--s-5) var(--s-5) var(--s-16); }
  .detail-head h2 { font-size: var(--t-h3); }
  .detail-id { gap: var(--s-3); }
  .detail-id .avatar { width: 40px; height: 40px; font-size: 1rem; }
  .convert-actions .btn { width: 100%; }
}

/* A 380px las píldoras se parten; una tira deslizable es preferible a romper
   el texto de cada etiqueta. */
@media (max-width: 380px) {
  .filters {
    flex-wrap: nowrap; overflow-x: auto;
    padding-bottom: var(--s-2);
    scrollbar-width: thin; -webkit-overflow-scrolling: touch;
  }
  .filters .segment { flex: none; }
}

/* ==========================================================================
   WHATSAPP SIN CONTESTAR — composición y vocabulario de dominio.

   Todo lo que se ve aquí lo pinta `/shared`: el panel (`.pane`), el encabezado
   de bloque, las etiquetas, los botones, el aviso y la hoja. Lo de abajo es
   solo DÓNDE va cada cosa en esta pantalla y qué significa "fuera de la
   ventana" — que es vocabulario de este dominio y de ningún otro.

   Nada de esto sube a `shared/` mientras lo use una sola superficie.
   ========================================================================== */

.wa-pendientes, .wa-list, .wa-item { min-width: 0; }
.wa-list { list-style: none; margin: 0; padding: 0; }

.wa-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) 0;
  border-top: 1px solid var(--rule);
}
.wa-item:first-child { border-top: 0; }

.wa-item-main { min-width: 0; }

.wa-quien {
  margin: 0 0 var(--s-1);
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}

/* El último mensaje, recortado a una línea: es una pista para decidir a quién
   abrir primero, no el contenido. Quien quiera leerlo, abre. */
.wa-ultimo {
  margin: 0;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 46ch;
}

.wa-item-side {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-shrink: 0;
}

/* La espera es el dato que ordena la lista, así que se lee sin buscarla. Y a
   partir de un día se marca: no en rojo —nadie ha hecho nada mal— sino en
   terracota, que en este sistema es "esto ya necesita una decisión". */
.wa-espera { font-size: var(--t-small); color: var(--ink-faint); white-space: nowrap; }
.wa-espera.is-viejo { color: var(--clay); font-weight: 700; }

/* FUERA DE LA VENTANA no es un error. Es que la respuesta dejó de ser un
   WhatsApp y pasó a ser una llamada, y por eso la etiqueta dice "llamar" en
   vez de "vencido": una etiqueta que nombra el problema deja al lector
   buscando la solución. */
.tag.is-fuera { background: var(--clay-wash); color: var(--clay); }
.wa-item.is-fuera .wa-ultimo { color: var(--ink-faint); }

/* ---------------------------------------------------- El hilo, en la hoja */

.wa-ficha { margin: 0 0 var(--s-4); }

.wa-hilo {
  list-style: none;
  margin: 0 0 var(--s-6);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.wa-msg {
  background: var(--paper-sunk);
  border-radius: 18px;
  padding: var(--s-3) var(--s-4);
  max-width: 88%;
}
.wa-msg p { margin: 0; }

/* Lo nuestro, alineado al otro lado y en el verde de marca suave. Es la única
   pista visual del hilo, y con dos colores basta: un hilo de chat con avatares
   y burbujas de colores sería decorar una bandeja de trabajo. */
.wa-msg.is-mio {
  margin-left: auto;
  background: var(--sage-wash);
}

.wa-meta {
  margin-top: var(--s-1) !important;
  font-size: var(--t-small);
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}

/* Lo que mandó el sistema se distingue de lo que escribió una persona. Sin
   esto, quien lee el hilo no sabe si el hogar contestó o fue el automático. */
.wa-auto {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--teal);
}

/* Un mensaje que NO salió. En terracota y con su motivo: si el equipo cree que
   contestó y no salió, la familia queda esperando y nadie lo sabe. */
.wa-fallo { color: var(--clay); font-weight: 700; }

.wa-form { margin-top: var(--s-2); }
.wa-cerrada { margin-top: var(--s-2); }

/* En un teléfono la fila se apila: con el número, la etiqueta y el botón en
   horizontal no cabe nada y el último mensaje desaparece. */
@media (max-width: 620px) {
  .wa-item { flex-direction: column; align-items: stretch; }
  .wa-item-side { justify-content: space-between; }
  .wa-msg { max-width: 100%; }

  /* EN UN TELÉFONO EL ÚLTIMO MENSAJE ENVUELVE, no se corta en una línea.
  
     Y no es solo estética. Con `white-space: nowrap` el ancho MÍNIMO INTRÍNSECO
     de este párrafo es el del texto entero —se midió: 752px— y eso empuja a toda
     la página, no solo a este bloque: la rejilla de métricas pasaba a dos
     columnas y la pantalla entera desbordaba a 494px en un viewport de 390.
     `overflow: hidden` recorta lo que se PINTA; no cambia lo que el elemento
     pide al calcular el ancho.

     Al envolver, el mínimo pasa a ser la palabra más larga, y dos líneas de
     contexto se leen mejor que una cortada. En pantalla ancha sí se corta,
     porque allí la fila entera cabe y una sola línea ordena el listado. */
  .wa-ultimo {
    white-space: normal;
    max-width: 100%;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow-wrap: anywhere;
  }
}

/* ==========================================================================
   SEGUIMIENTO — composición y vocabulario de dominio.

   Como el bloque de WhatsApp: el panel, las etiquetas, los campos y la hoja los
   pinta `/shared`. Aquí va solo dónde se coloca cada cosa y qué significa
   «vencido» — que es vocabulario comercial y de ningún otro sitio.
   ========================================================================== */

.seguimiento, .seg-list, .seg-item { min-width: 0; }

/* Vacío no se esconde —«todo al día» es información— pero pesa menos. */
.seguimiento.is-empty { background: var(--paper-sunk); box-shadow: none; }
.seg-vacio { margin: 0; color: var(--ink-soft); }

.seg-grupo + .seg-grupo {
  margin-top: var(--s-6);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
}

.seg-grupo h4 {
  margin: 0 0 var(--s-1);
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* La cuenta del grupo, al lado del título y no en un badge de color: el color se
   reserva para lo que está mal, y tres de los cuatro grupos no lo están. */
.seg-cuenta {
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  font-weight: 400;
}

/* La frase que explica el grupo. Existe porque «sin nada apuntado» no se entiende
   solo, y una lista que hay que descifrar se deja de abrir. */
.seg-explica {
  margin: 0 0 var(--s-3);
  font-size: var(--t-small);
  color: var(--ink-faint);
}

/* LO VENCIDO es lo único que se pinta. Y en terracota, no en rojo: nadie está en
   peligro — alguien no hizo lo que dijo, y eso es una decisión pendiente, no una
   urgencia clínica. El rojo de este sistema está reservado para lo otro. */
.seg-grupo.is-vencido h4 { color: var(--clay); }
.seg-grupo.is-vencido .seg-item { border-left: 2px solid var(--clay); padding-left: var(--s-3); }

.seg-list { list-style: none; margin: 0; padding: 0; }

.seg-item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-3) 0;
  border-top: 1px solid var(--rule);
}
.seg-item:first-child { border-top: 0; }

.seg-item-main { min-width: 0; }

.seg-quien {
  margin: 0 0 2px;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}

/* El nombre es un botón que abre la ficha: quien mira esta lista quiere ver con
   quién está hablando antes de decidir qué apuntar. Se pinta como texto y no
   como botón —el botón de la derecha es la acción— pero llega por teclado. */
.seg-nombre {
  background: none;
  border: 0;
  font: inherit;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule-strong);

  /* OBJETIVO TÁCTIL. Un botón con el tamaño de su texto mide unos 25px de alto y
     el mínimo del sistema son 44 (`--tap`). Se consigue con altura mínima y
     centrado, NO agrandando la letra: lo que no cede nunca es el tamaño del
     texto. Es la misma solución que en `.login-forgot`, y por eso se escribe
     igual — dos arreglos distintos para el mismo problema es cómo una interfaz
     empieza a parecer hecha por dos manos.

     El relleno horizontal es cero a propósito: esto vive dentro de una frase,
     junto a la etiqueta de etapa y el asesor, y un botón con relleno lateral se
     separaría de lo que lo acompaña. */
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0;
}
.seg-nombre:hover { color: var(--sage-deep); text-decoration-color: currentColor; }

.seg-detalle {
  margin: 0;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* Quién responde por esta familia. Y cuando no hay nadie se dice, en lugar de
   dejar el hueco: un prospecto sin asesor no es de nadie. */
.seg-asesor { font-size: var(--t-small); color: var(--ink-faint); }
.seg-asesor.is-nadie { color: var(--clay); font-weight: 700; }

/* La hoja: dos bloques separados —lo que pasó y lo que sigue— porque son dos
   preguntas y mezclarlas en un solo formulario hace que se conteste una. */
.seg-fieldset {
  border: 1px solid var(--rule);
  border-radius: 18px;
  padding: var(--s-4) var(--s-4) var(--s-2);
  margin: 0 0 var(--s-5);
}
.seg-fieldset legend {
  padding: 0 var(--s-2);
  font-weight: 700;
}

@media (max-width: 620px) {
  .seg-item { flex-direction: column; align-items: stretch; }
}

/* El anuncio que trajo al prospecto: dato de contexto, no urgencia. */
.wa-anuncio { margin: var(--s-1) 0 0; color: var(--ink-soft); overflow-wrap: anywhere; }

/* ==========================================================================
   Configuración de WhatsApp (hoja)
   ========================================================================== */

.wacfg { display: grid; gap: var(--s-6); }
.wacfg-estados { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.wacfg-estado { display: flex; gap: var(--s-3); align-items: flex-start; padding: var(--s-3) var(--s-4); border-radius: var(--r-md); }
.wacfg-estado .icon { flex: none; margin-top: 3px; }
.wacfg-estado.is-ok { background: var(--sage-wash); color: var(--sage-deep); }
/* Lo que falta NO es un error: es algo por declarar. Mismo criterio que el
   chip pendiente — terracota suave, no rojo. */
.wacfg-estado.is-falta { background: var(--clay-wash); color: var(--clay); }
.wacfg-bloque { border-top: 1px solid var(--rule); padding-top: var(--s-5); }
.wacfg-bloque h3 { margin: 0 0 var(--s-3); }
.wacfg-dias { border: 0; padding: 0; margin: var(--s-4) 0; display: flex; flex-wrap: wrap; gap: var(--s-2); }
.wacfg-dias legend { font-weight: 700; margin-bottom: var(--s-2); padding: 0; }
.wacfg-dia {
  min-width: var(--tap); min-height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-1);
  padding: 0 var(--s-3); border: 1.5px solid var(--rule-strong); border-radius: var(--r-pill);
  cursor: pointer;
}
.wacfg-dia input { width: 18px; height: 18px; accent-color: var(--sage); }
.wacfg-dia:has(input:checked) { background: var(--sage-wash); border-color: var(--sage); }
.wacfg-horas { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }
.wacfg-copiable code, .wacfg-plantilla-nombre code { overflow-wrap: anywhere; font-size: var(--t-small); }
.wacfg-plantillas { list-style: none; padding: 0; margin: var(--s-4) 0 0; display: grid; gap: var(--s-4); }
.wacfg-plantillas li { background: var(--paper-sunk); border-radius: var(--r-md); padding: var(--s-4); }
.wacfg-plantillas p { margin: 0 0 var(--s-2); }

/* Gestión dentro de la conversación: asesor y visita. */
.wa-gestion { border-top: 1px solid var(--rule); margin-top: var(--s-6); padding-top: var(--s-5); display: grid; gap: var(--s-4); }
.wa-gestion h3 { margin: 0; }
.wa-gestion-fila { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s-3); }
.wa-gestion-fila .field { flex: 1 1 200px; margin: 0; }
.wa-gestion-sub { font-weight: 700; margin: 0 0 var(--s-3); }
.wa-gestion-horas { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); align-items: end; }
.wa-apuntado { margin: 0; }

/* Acciones de la cabecera: WhatsApp y Campañas, que bajan de línea antes que
   desbordar. */
.page-head-acciones { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }

/* ==========================================================================
   Campañas (hoja)
   ========================================================================== */

.camp { display: grid; gap: var(--s-5); }
.camp-lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-4); }
.camp-item { background: var(--paper-sunk); border-radius: var(--r-md); padding: var(--s-4); }
.camp-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-2); align-items: center; }
.camp-nombre { margin: 0; font-weight: 700; overflow-wrap: anywhere; }
.camp-meta { margin: var(--s-1) 0 var(--s-3); color: var(--ink-soft); overflow-wrap: anywhere; }
.camp-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: var(--s-3); margin-bottom: var(--s-3); }
.camp-cifra { display: grid; gap: 2px; }
.camp-cifra span { color: var(--ink-soft); }
.camp-sin { list-style: none; padding: 0; margin: var(--s-3) 0 0; display: grid; gap: var(--s-2); }
.camp-sin li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-2); overflow-wrap: anywhere; }
