/* DISEÑO DE EDNA — extraído VERBATIM de plataforma-perritos-house.html
   NO EDITAR A MANO. Se regenera con ./extraer-diseno.sh
   Si hay que corregir una alineación, se corrige en la maqueta y se
   vuelve a extraer. Editar aquí reabre la deriva que esto cierra. */

/* =====================================================================
   1. RESET Y BASE
   ===================================================================== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{color-scheme:light}
html{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
body{
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
  background:var(--gris-piedra);
  color:var(--morado);
  font-size:14px;
  line-height:1.45;
  min-height:100vh;
}
img{display:block;max-width:100%}
button{font-family:inherit;cursor:pointer;color:inherit}
input,select,textarea{font-family:inherit;color:var(--morado)}
input,select,textarea,option{background-color:var(--blanco)}
input[type="color"]{background-color:transparent}
ul,ol{list-style:none}
a{color:inherit;text-decoration:none}
svg{display:block}

/* =====================================================================
   2. TOKENS DE DISEÑO — PALETA OBLIGATORIA (no se amplía)
   ===================================================================== */
:root{
  --amarillo:#FEC800;
  --verde:#97D10A;
  --morado:#2B1734;
  --blanco:#FFFFFF;
  --gris-piedra:#F5F5F3;
  --gris-borde:#E8E5E0;
  --texto-suave:#6B6B6B;
  /* Único color de riesgo, autorizado por Edna el 22-sep-2026 ("ponlos porque son
     indicadores de riesgo"). Úsalo SOLO para: chip Vencido, chip de severidad Alta,
     y flechas de variación cuando el cambio representa más riesgo (gasto que sube,
     cobranza pendiente que baja). Nada más lleva rojo — ni bordes, ni títulos, ni
     totales. No se amplía ni se deriva un segundo tono. */
  --rojo:#B3261E;

  /* radios y sombra — no son color, son medida */
  --r-sm:6px;
  --r-md:8px;
  --r-lg:12px;
  --r-pill:999px;
  --sombra-card:0 1px 2px rgba(0,0,0,.04);

  /* ritmo vertical 4/8/12/16/24/32/48 */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px; --sp-7:48px;
  /* ===== LISTAS DESPLEGABLES PROPIAS ==============================
   El panel que se abre al picar un <select> lo dibuja el sistema
   operativo: fondo blanco de sistema, resaltado azul, tipografía ajena.
   No hay CSS que lo alcance. Por eso el <select> se queda guardando el
   valor (para que todo el código siga funcionando igual) y encima se
   dibuja esta lista, que sí es de la casa. */
.lista-caja{position:relative}
.lista-nativa{position:absolute;opacity:0;pointer-events:none;width:100%;height:100%;
  left:0;top:0;margin:0}
.lista-btn{display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;
  padding:9px 12px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  font-size:14px;font-family:inherit;color:var(--morado);background:var(--blanco);
  cursor:pointer;text-align:left;transition:border-color .16s ease,background .16s ease}
.lista-btn:hover{border-color:var(--amarillo);background:var(--realce)}
.lista-btn[aria-expanded="true"]{border-color:var(--amarillo);
  box-shadow:0 0 0 3px rgba(254,200,0,.22)}
.lista-btn .txt{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lista-btn .v{width:13px;height:13px;flex:none;transition:transform .2s ease}
.lista-btn[aria-expanded="true"] .v{transform:rotate(180deg)}
.lista-btn:disabled{opacity:.55;cursor:not-allowed;background:var(--gris-piedra)}
.lista-panel{position:absolute;z-index:60;left:0;right:0;top:calc(100% + 5px);
  background:var(--blanco);border:1px solid var(--gris-borde);border-radius:var(--r-md);
  box-shadow:0 12px 30px rgba(43,23,52,.16);padding:5px;max-height:260px;overflow-y:auto}
.lista-panel[hidden]{display:none}
.lista-op{display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;
  padding:9px 11px;border:0;border-radius:8px;background:none;font:inherit;font-size:14px;
  color:var(--morado);text-align:left;cursor:pointer;transition:background .12s ease}
.lista-op:hover,.lista-op:focus-visible{background:var(--realce);outline:none}
.lista-op.elegida{background:var(--realce-fuerte);font-weight:600}
.lista-op .pal{width:14px;flex:none;color:var(--morado);opacity:0}
.lista-op.elegida .pal{opacity:1}

/* Todo lo que se puede picar se ilumina. Antes muchos botones no daban
   ninguna señal y parecían decorado. */
.card-accion,.filtro-chip,.periodo-pill,.tab,.btn-accion,.vista-pill,
[role="button"]:not(.btn):not(.btn-primario):not(.btn-secundario){transition:background .16s ease,color .16s ease,border-color .16s ease}
.card-accion:hover,.card-accion:focus-visible{background:var(--realce);color:var(--morado);
  border-radius:8px;outline:none}
.filtro-chip:not(.activo):hover,.periodo-pill:not(.activa):hover,
.tab:not(.activo):hover{background:var(--realce);color:var(--morado)}
.btn-accion:hover{background:var(--realce);color:var(--morado)}
tbody tr[onclick]:hover td,tbody tr[role="button"]:hover td{background:var(--realce)}
.m1-mascota-card:hover,.m2-tabla-mascotas tbody tr:hover td{background:var(--realce)}
.actividad-fila[onclick]:hover,.mp-fila[onclick]:hover{background:var(--realce);border-radius:9px}

/* ===== CELDAS DE ALTO FIJO EN LA FICHA DEL CLIENTE ==============
   La tarjeta mide lo que mide: si hay más contenido no crece, se va al
   botón de Ver más. Misma regla del tablero. */
#m1-ficha .m1-mascotas-fila{min-height:186px}

/* ── LAS MASCOTAS DEL CLIENTE: TAMAÑO FIJO Y CENTRADAS ──────────────────────
   Edna, 29 oct 2026: «si sólo tienen un perrito debe de estar centrado, al
   igual que si tiene dos; el máximo de mascotas a mostrar en el expediente son
   3, las demás se van a ver más, y todas alineadas».
   Las tarjetas eran `flex:1 1 calc(25% …)`: con una sola mascota la tarjeta se
   estiraba a media fila y con dos quedaban dos recuadros enormes, cada ficha
   con un tamaño distinto según cuántos perritos tenga la familia. Con
   `flex-grow:0` la tarjeta mide siempre lo mismo —un cuarto de la fila— y
   `justify-content:center` pone en el medio lo que no llene.
   El tope de 3 ya estaba en `MAX_TARJETAS` de `m1-ficha-ph.js`; con la celda
   de «Agregar mascota» son cuatro piezas, que es justo una fila llena.
   Sólo PH: `#m1-mascotas-fila` no existe en la maqueta de PMedic. */
#m1-ficha .m1-mascotas-fila{justify-content:center}
#m1-ficha .m1-mascotas-fila > .m1-mascota-card,
#m1-ficha .m1-mascotas-fila > .m1-mascota-agregar{
  flex:0 1 calc(25% - var(--sp-3))}
#m1-ficha .card[data-pest="comunicacion"] .tabla{display:block;max-height:252px;overflow:hidden}
#m1-ficha .card[data-pest="comunicacion"] .tabla thead,
#m1-ficha .card[data-pest="comunicacion"] .tabla tbody{display:table;width:100%;table-layout:fixed}
#m1-ficha .m1-notas-lista{max-height:170px;overflow:hidden}
#m1-ficha .m1-comprobantes{margin-top:var(--hueco)}
.masc-perfiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));
  gap:var(--hueco)}
.masc-perfiles .m1-mascota-card{flex:none;width:auto}

.th-borrar{width:32px;height:32px;border-radius:9px;border:1px solid var(--gris-borde);
  background:var(--blanco);color:var(--texto-suave);cursor:pointer;display:inline-flex;
  align-items:center;justify-content:center;gap:3px;padding:0 5px;transition:.16s;position:relative}
.th-borrar svg{width:16px;height:16px;flex:none}
.th-borrar:disabled{opacity:.42;cursor:not-allowed}
.th-borrar.con-seleccion{border-color:var(--rojo);color:var(--rojo);background:rgba(179,38,30,.07);
  width:auto;min-width:42px}
.th-borrar.con-seleccion:hover{background:var(--rojo);color:#fff;border-color:var(--rojo)}
.th-borrar .n{font-size:11.5px;font-weight:700;line-height:1}
.tabla th.col-sel{width:52px;padding-top:6px;padding-bottom:6px}

/* La cifra de "Servicios este año" iba pegada a la derecha y quedaba
   lamiendo la columna de Estado de cuenta. Va centrada bajo su encabezado.
   La cuarta columna se corre a la quinta en modo editar, porque ahí se
   inserta la casilla de selección. */
#m1-tabla-clientes th.col-servicios{text-align:center}
#m1-tabla-clientes tbody td:nth-child(4){text-align:center}
#m1-tabla-clientes.modo-editar tbody td:nth-child(4){text-align:left}
#m1-tabla-clientes.modo-editar tbody td:nth-child(5){text-align:center}

/* REGLA DE DISTANCIAS ENTRE CELDAS
     Una sola medida para TODO el aire que hay entre tarjetas: entre columnas,
     entre filas, y entre tarjetas apiladas dentro de una columna. Si alguna
     vez hay que separarlas más o menos, se cambia aquí y se mueve todo junto.
     Antes había dos medidas revueltas — 12 px entre columnas y 16 px entre
     filas — y por eso el hueco de abajo se veía más grande que el de al lado. */
  --hueco:12px;
  /* REALCE DE LO PICABLE
     Un solo tono para decir "esto se puede picar", en toda la plataforma:
     morado claro de la familia del morado de Perritos House (#5C3A6B).
     Antes había gris de sistema en unas partes y amarillo en otras. */
  --realce:rgba(92,58,107,.11);
  --realce-fuerte:rgba(92,58,107,.18);
  /* Decisión de Edna (6 oct): el texto de "Ver más" y "Editar" va en el
     amarillo de marca, tal cual. Queda anotado que sobre blanco mide
     1.56:1 — por debajo del mínimo legible — por si algún día se quiere
     revisar. El token existe para poder cambiarlo en un solo lugar. */
  --amarillo-texto:var(--amarillo);
}

/* =====================================================================
   3. TIPOGRAFÍA — escala fija, sin fuentes externas
   ===================================================================== */
.tipo-display{font-size:32px;font-weight:700;line-height:1.2;letter-spacing:-.01em}
.tipo-h1{font-size:24px;font-weight:700;line-height:1.25}
.tipo-h2{font-size:18px;font-weight:600;line-height:1.3}
.tipo-cuerpo{font-size:14px;font-weight:400;line-height:1.5}
.tipo-label{font-size:12px;font-weight:500;letter-spacing:.02em;text-transform:uppercase}
.tipo-dato{font-size:28px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.15}
.suave{color:var(--texto-suave)}

/* =====================================================================
   4. LAYOUT — SIDEBAR (240px, idéntico en todas las vistas)
   ===================================================================== */
.app{display:flex;min-height:100vh}

.sidebar{
  width:240px;min-width:240px;
  background:var(--morado);
  color:var(--blanco);
  display:flex;flex-direction:column;
  padding:var(--sp-5) var(--sp-4) var(--sp-4);
  position:fixed;top:0;left:0;bottom:0;
  overflow-y:auto;
}
.sidebar-brand{
  margin:calc(var(--sp-5) * -1) calc(var(--sp-4) * -1) var(--sp-5);
  padding:var(--sp-5) var(--sp-4) var(--sp-4);
  background:var(--blanco);
  border-bottom:3px solid var(--amarillo);
  text-align:center;
}
.sidebar-brand .sidebar-logo-placa{background:none;padding:0;border-radius:0;box-shadow:none;margin:0 auto;width:100%}
.sidebar-brand .sidebar-logo-img{width:100%;max-width:168px;height:auto;margin:0 auto;display:block}
.sidebar-brand .lema{
  font-size:10.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--morado);opacity:.75;margin-top:var(--sp-2);
}

/* .sidebar-logo (ícono + wordmark): definida en la sección 34 */

.sidebar-nav{flex:1;display:flex;flex-direction:column;gap:2px}
.nav-item{
  display:flex;align-items:center;gap:var(--sp-3);
  padding:10px 12px;border-radius:var(--r-md);
  color:rgba(255,255,255,.7);
  font-size:14px;font-weight:500;
  background:transparent;border:none;width:100%;text-align:left;
  transition:background .12s,color .12s,opacity .12s}
.nav-item svg.icon{width:18px;height:18px;flex:none;color:currentColor}
.nav-item:hover{color:#fff;background:rgba(255,255,255,.08)}
.nav-item.activo{background:var(--amarillo);color:var(--morado);opacity:1}
.nav-item.activo:hover{background:var(--amarillo)}

/* .sidebar-soporte: definida en la sección 35 (píldora con borde) */

.sidebar-cierre{
  margin-top:var(--sp-4);
  background:var(--blanco);color:var(--morado);
  border-radius:var(--r-lg);
  padding:var(--sp-4);
  position:relative;overflow:hidden;
}
.sidebar-cierre .icon-huella{width:20px;height:20px;color:var(--verde);margin-bottom:var(--sp-3)}
.sidebar-cierre p{font-size:14px;font-weight:600;line-height:1.35}
.sidebar-cierre .marca-pie{
  margin-top:var(--sp-4);font-size:10px;font-weight:600;letter-spacing:.08em;
  color:var(--texto-suave);line-height:1.6;text-transform:uppercase;
}

/* =====================================================================
   5. LAYOUT — TOPBAR
   ===================================================================== */
.main{flex:1;margin-left:240px;display:flex;flex-direction:column;min-height:100vh}

.topbar{
  background:var(--blanco);
  border-bottom:1px solid var(--gris-borde);
  padding:10px var(--sp-6);
  min-height:64px;                 /* alto mínimo, no fijo: con cuatro pestañas
                                      y la firma, el contenido se envolvía y se
                                      salía por arriba de los 64 px */
  display:flex;align-items:center;justify-content:space-between;
  position:sticky;top:0;z-index:20;
  gap:var(--sp-4);flex-wrap:wrap;
}
.topbar-izq{display:flex;flex-direction:column;gap:2px;min-width:0}
.breadcrumb{font-size:13px;color:var(--texto-suave);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.breadcrumb b{color:var(--morado);font-weight:600}
.topbar-nota{
  font-family:'Segoe Script','Bradley Hand','Snell Roundhand',cursive;
  font-style:italic;
  font-size:13px;color:var(--verde);
  display:flex;align-items:center;gap:4px;
}
.topbar-nota svg.icon{width:13px;height:13px;color:var(--verde)}

.topbar-der{display:flex;align-items:center;gap:var(--sp-4);flex:0 1 auto;min-width:0;
  flex-wrap:wrap;justify-content:flex-end;align-content:center}
.vista-switch{flex-wrap:wrap}
@media (max-width:1180px){ .topbar-nota{display:none} }

/* UNA SOLA PASTILLA: igual que .filtro-chip de Gestión de clientes.
   Antes estos conmutadores vivían dentro de una caja gris con las
   opciones pegadas, así que leían como UN control partido en cuatro y no
   como cuatro pastillas. Sin la caja y con el mismo hueco de .filtros,
   cada opción es su propia pastilla, con su borde y su fondo blanco. */
.vista-switch{display:flex;gap:8px;background:none;padding:0;border-radius:0;flex-wrap:wrap;align-items:center}
/* Las de la barra de arriba van más grandes que las de un filtro: viven en
   un renglón de 64px y con 12px quedaban chicas y descentradas, con hueco
   arriba y abajo. Mismo lenguaje, otro tamaño. */
.vista-pill{
  display:inline-flex;align-items:center;justify-content:center;width:auto;white-space:nowrap;cursor:pointer;
  padding:9px 18px;border-radius:var(--r-pill);border:1px solid var(--gris-borde);
  font-family:inherit;font-size:13.5px;font-weight:600;line-height:1.2;
  background:var(--blanco);color:var(--morado);
  transition:background .16s ease,color .16s ease,border-color .16s ease;
}
.vista-pill.activa{background:var(--amarillo);color:var(--morado);border-color:var(--amarillo)}
.vista-pill:not(.activa):hover{border-color:var(--amarillo);background:var(--realce)}
.vista-pill.activa:hover{filter:brightness(.97)}

.topbar-fecha{text-align:right;font-size:12px;color:var(--texto-suave);line-height:1.4;white-space:nowrap}
.topbar-fecha b{display:block;color:var(--morado);font-weight:600;font-size:13px}

/* =====================================================================
   6. LAYOUT — CONTENIDO
   ===================================================================== */
.contenido{padding:var(--sp-6);flex:1}
.modulo{display:none}
.modulo.activo{display:block}
.modulo-header{margin-bottom:var(--sp-5)}
.modulo-header .tipo-h1{margin-bottom:2px}

.en-construccion{
  border:1px dashed var(--gris-borde);border-radius:var(--r-lg);
  background:var(--blanco);
  padding:var(--sp-7) var(--sp-5);text-align:center;color:var(--texto-suave);
}
.en-construccion svg.icon{width:32px;height:32px;color:var(--gris-borde);margin:0 auto var(--sp-3)}
.en-construccion b{color:var(--morado);display:block;font-size:16px;margin-bottom:6px}

/* =====================================================================
   7. ICONOS — sprite de línea, sin emoji
   ===================================================================== */
.icon-sprite{position:absolute;width:0;height:0;overflow:hidden}
.icon{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}

/* =====================================================================
   8. COMPONENTE — CARD
   ===================================================================== */
.card{
  background:var(--blanco);
  border:1px solid var(--gris-borde);
  border-radius:var(--r-lg);
  padding:var(--sp-5);
  box-shadow:var(--sombra-card);
}
/* El hueco entre celdas NO se pone aqui. Ver "EL HUECO LO PONE EL
   CONTENEDOR" al final de la hoja. */
/* ESTE ERA EL DESFASE.
   `.card + .card` le pone margen de arriba a toda tarjeta que tenga otra
   tarjeta por hermana — y dentro de una rejilla eso incluye a la segunda y
   la tercera de la MISMA FILA. Resultado: la primera arrancaba pegada al
   borde de la fila y las de al lado 12 px más abajo, con sus bordes de
   abajo igual de corridos. Se veía como un hueco desigual, pero era que las
   tarjetas no empezaban a la misma altura.
   El margen solo tiene sentido cuando las tarjetas se apilan en un
   contenedor sin `gap`. En cualquier rejilla o columna con hueco propio,
   sobra. */
.card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--sp-4);gap:var(--sp-3)}
.card-head .tipo-h2{color:var(--morado)}
.card-accion{
  font-size:12px;font-weight:600;color:var(--amarillo-texto);
  background:none;border:none;display:inline-flex;flex:none;width:auto;align-items:center;gap:4px;
}
.card-accion svg.icon{width:13px;height:13px}
.card-accion:hover{text-decoration:underline}
.card-vacio{color:var(--texto-suave);font-size:13px;padding:var(--sp-4) 0;text-align:center}

.col{display:flex;flex-direction:column;gap:var(--hueco)}
/* align-items:stretch (no "start"): las tarjetas de una misma fila deben
   estirarse a la altura de la fila para que los encabezados y bordes
   inferiores cuadren entre sí (antes quedaban a su altura natural y se veían
   escalonadas). gap/margin reducidos de --sp-4 a --sp-3: filas y tarjetas más
   pegadas, sin quedar apretadas. */
.grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
/* CELDAS A LA PAR
   Dos quejas que parecían opuestas: "están desfasadas" y "hay un hueco en
   blanco". La respuesta no es encoger unas ni estirar otras, es que todas
   midan lo mismo y el contenido se reparta en el alto en vez de apelotonarse
   arriba y dejar un bloque vacío al final. */
#m0 .grid-3 > .card,#m0 .grid-2 > .card,
#m1 .grid-3 > .card,#m1 .grid-2 > .card{display:flex;flex-direction:column}
#m0 .grid-3 > .card > .card-head,#m0 .grid-2 > .card > .card-head,
#m1 .grid-3 > .card > .card-head,#m1 .grid-2 > .card > .card-head{flex:none}
/* las barras y las listas se estiran y se reparten */
#m0 .grid-3 .barra-h,#m0 .grid-2 .barra-h,
#m1 .grid-3 .barra-h,#m1 .grid-2 .barra-h{flex:1 1 auto;justify-content:space-between}
/* Incidencias de la semana es la tarjeta de referencia de su fila: sus cinco
   renglones marcan el alto y las otras dos se reparten dentro de ese mismo
   alto, sin estirarse más ni quedarse cortas. */
#m0 .inc-fila{flex:1 1 auto;min-height:0}
#m0 .grid-3 > .card > .barra-h{min-height:0}
#m0 .grid-3 .barra-h-fila{flex:1 1 auto;min-height:0}
#m0 .m0-tabla-cobranza{margin-bottom:0}
#m0 #m0-actividades{flex:1 1 auto;display:flex;flex-direction:column;justify-content:space-between}
#m0 .anillo-grid{flex:1 1 auto;align-content:center}
#m1 .m1-mascotas-fila{flex:none}
#m1 .grid-3 > .card > .campo-fila{flex:1 1 auto}
/* CELDAS A LA PAR · regla general
   Las tarjetas de una misma fila YA medían lo mismo: la rejilla las estira.
   Lo que se veía disparejo era el contenido — unas llenaban su caja y otras
   se apelotonaban arriba dejando un bloque en blanco abajo, y eso se lee
   como "esta celda es más chica". Esto reparte el contenido en el alto que
   la fila ya le dio, y ahora aplica a TODOS los módulos, no sólo al tablero
   y a Clientes, que era donde estaba resuelto. */
.card > .card-head{min-height:34px;align-items:center;flex:none}
/* una lista de barras reparte sus renglones en vez de amontonarlos arriba */
.card > .barra-h{display:flex;flex-direction:column;justify-content:space-between}
/* una tabla dentro de una tarjeta estirada ocupa el alto que le toca */
.card > .tabla{height:100%}
/* lo que no debe estirarse: cifras sueltas, chips y pies de tarjeta */
.card > .card-vacio,
.card > .vacio-filtro{flex:none}
.grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
.grid-2-1{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
/* La evolución de la cobranza se queda con dos de las tres columnas: en una
   sola los doce meses no caben y la gráfica se salía de su tarjeta.
   Antigüedad de saldos se quitó; su dato vive en los recordatorios. */
/* Media pantalla: dejó de abarcar dos columnas cuando Historial de pagos
   pasó a ocupar la otra mitad. */
.m8-evolucion{min-width:0}
/* El pie de Calidad: el periodo y el botón que abre el año */
/* Evidencia de la incidencia: miniaturas de lo que se sube */
.ri-evidencias{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.ri-evidencias img{width:62px;height:62px;object-fit:cover;border-radius:9px;
  border:1px solid var(--gris-borde);display:block}
.ri-evidencias .sin{font-size:12px;color:var(--texto-suave)}
.ri-evidencias .vid{width:62px;height:62px;border-radius:9px;border:1px solid var(--gris-borde);
  background:var(--gris-piedra);display:flex;align-items:center;justify-content:center;
  font-size:11px;color:var(--texto-suave)}
.cal-pie-barra{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-4);
  padding-top:var(--sp-3);border-top:1px solid var(--gris-borde)}
.cal-pie-barra .card-accion{margin-left:auto}
/* Calidad en 12 meses: anillo grande a la izquierda, la serie a la derecha */
.ca-bloque{display:grid;grid-template-columns:minmax(0,210px) minmax(0,1fr);gap:var(--sp-5);
  align-items:center;padding:var(--sp-5) 0;border-bottom:1px solid var(--gris-borde)}
.ca-bloque:last-of-type{border-bottom:0}
.ca-izq{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
.ca-izq .tit{font-size:12.5px;font-weight:700;color:var(--morado)}
.ca-izq .pie{font-size:11.5px;color:var(--texto-suave);line-height:1.35}
.ca-der{min-width:0}
.ca-tendencia{display:flex;gap:var(--sp-3);flex-wrap:wrap;margin-top:10px;font-size:12px;
  color:var(--texto-suave)}
.ca-tendencia b{color:var(--morado)}
.ca-tendencia .sube{color:#4F7A00;font-weight:700}
.ca-tendencia .baja{color:#B3261E;font-weight:700}
@media (max-width:760px){.ca-bloque{grid-template-columns:minmax(0,1fr)}}
/* Anillo grande: para las donas que mandan en su tarjeta. El tamaño del
   número va aquí porque .anillo .centro span:first-child lo fija a 14px y
   le gana a cualquier font-size escrito en el HTML. */
.anillo.grande{width:208px;height:208px;flex:none}
.anillo.grande .centro span:first-child{font-size:34px;line-height:1.05}
.anillo.grande .centro span:nth-child(2){font-size:11.5px}
.anillo.mediano{width:168px;height:168px;flex:none}
.anillo.mediano .centro span:first-child{font-size:22px;line-height:1.1}
.anillo.mediano .centro span:nth-child(2){font-size:10.5px}
/* los valores a un lado, pero sin competirle de tamaño al círculo */
.dona-wrap.grande{align-items:center;gap:var(--sp-5);justify-content:center}
.dona-wrap.grande .dona-leyenda{flex:0 1 200px;min-width:0}
/* Dona al centro con los valores debajo: el círculo manda y la leyenda se
   lee como una fila de datos, no como una lista al margen. */
.dona-centrada{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--sp-4);flex:1 1 auto;padding:var(--sp-3) 0}
.dona-abajo{display:grid;grid-template-columns:repeat(auto-fit,minmax(104px,1fr));
  gap:var(--sp-2) var(--sp-3);width:100%}
/* Sin cuadro: cada entrada es su punto de color, su nombre y su cifra. La
   caja gris los convertía en siete tarjetitas que competían con el anillo,
   que es lo que de verdad hay que leer. */
.dona-abajo .it{display:flex;flex-direction:column;align-items:center;gap:2px;text-align:center;
  padding:6px 4px;border-radius:0;background:none}
.dona-abajo .et{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--texto-suave);
  line-height:1.2}
.dona-abajo .et i{width:9px;height:9px;border-radius:50%;flex:none;display:block}
.dona-abajo .num{font-size:19px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.dona-abajo .pct{font-size:11.5px;color:var(--texto-suave);font-variant-numeric:tabular-nums}
/* Celdas pareadas: en vez de dos columnas que crecen cada una por su lado,
   una sola rejilla donde las tarjetas van de dos en dos. Así la de la
   derecha mide lo mismo que la de su izquierda y ninguna se encoge ni se
   mueve de lugar cuando le falta contenido. */
.grid-pareado{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);
  gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
.grid-pareado.mitades{grid-template-columns:repeat(2,minmax(0,1fr))}
.grid-pareado>.card{margin-bottom:0;display:flex;flex-direction:column;min-width:0}
.grid-pareado>.card>.card-head{flex:none}
/* Las dos rejillas del módulo eran hermanas sin separación: la de abajo se
   pegaba a la de arriba. Mismo hueco por dentro que por fuera. */
/* Una tarjeta y una rejilla son vecinas tan seguido como dos tarjetas: sin
   esto, "Inventario general" quedaba pegado a "Movimientos recientes" y a
   "Alertas y próximos a vencer". Mismo hueco que entre dos tarjetas. */
@media (max-width:900px){.grid-pareado{grid-template-columns:minmax(0,1fr)}}

/* =====================================================================
   9. COMPONENTE — CHIP
   ===================================================================== */
/* inline-block, no flex: un inline-flex anidado dentro de un bloque que a su
   vez es hijo flex (.m2-header-info{flex:1}) se estira al ancho completo en
   algunos motores de render aunque tenga width:auto — inline-block es
   robusto en cualquier anidamiento (verificado). */
.chip{
  display:inline-block;width:auto;vertical-align:middle;
  border-radius:var(--r-pill);padding:4px 10px;
  font-size:12px;font-weight:600;line-height:1.3;white-space:nowrap;
}
.chip-dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:currentColor;vertical-align:middle;margin-right:5px}
.chip-positivo{background:rgba(151,209,10,.15);color:var(--verde)}
.chip-positivo .chip-dot{background:var(--verde)}
.chip-aviso{background:rgba(254,200,0,.2);color:var(--morado)}
.chip-aviso .chip-dot{background:var(--amarillo)}
.chip-negativo{background:rgba(43,23,52,.1);color:var(--morado)}
.chip-negativo .chip-dot{background:var(--morado)}

/* =====================================================================
   10. COMPONENTE — TABLA
   ===================================================================== */
.tabla{width:100%;border-collapse:collapse}
.tabla thead th{
  font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);text-align:left;padding-bottom:8px;
  border-bottom:1px solid var(--gris-borde);
}
.tabla tbody td{padding:12px 0;border-bottom:1px solid var(--gris-borde);font-size:14px;vertical-align:middle}
.tabla tbody tr:last-child td{border-bottom:none}
.tabla .num{text-align:right;font-variant-numeric:tabular-nums}
.tabla .fecha{text-align:left;white-space:nowrap;font-variant-numeric:tabular-nums}
.tabla th.num{text-align:right}
.tabla th.fecha{text-align:left}
.tabla td + td,.tabla th + th{padding-left:var(--sp-3)}

/* =====================================================================
   11. COMPONENTE — BOTONES
   ===================================================================== */
.btn{
  display:inline-flex;flex:none;width:auto;align-items:center;justify-content:center;gap:8px;
  border-radius:var(--r-md);padding:10px 16px;font-size:14px;font-weight:600;
  border:1px solid transparent;transition:opacity .12s,background .12s;white-space:nowrap;
}
.btn svg.icon{width:16px;height:16px}
.btn-primario{background:var(--amarillo);color:var(--morado)}
.btn-primario:hover{opacity:.9}
.btn-primario:focus-visible{outline:2px solid var(--morado);outline-offset:2px}
.btn-secundario{background:transparent;border-color:var(--morado);color:var(--morado)}
.btn-secundario:hover{background:rgba(43,23,52,.05)}
.btn-secundario:focus-visible{outline:2px solid var(--morado);outline-offset:2px}
.btn-bloque{width:100%;justify-content:flex-start}
.btn-sm{padding:7px 12px;font-size:13px;border-radius:var(--r-sm)}

/* =====================================================================
   12. COMPONENTE — KPI CARD
   ===================================================================== */
.kpi{background:var(--blanco);border:1px solid var(--gris-borde);border-radius:var(--r-lg);
  padding:var(--sp-4) var(--sp-5);box-shadow:var(--sombra-card)}
.kpi .icon-cont{width:24px;height:24px;color:var(--morado);margin-bottom:var(--sp-3)}
.kpi .tipo-dato{color:var(--morado);display:flex;align-items:baseline;gap:6px}
.kpi .tipo-dato small{font-size:14px;font-weight:600;color:var(--texto-suave)}
.kpi .tipo-label{color:var(--texto-suave);margin-top:6px;display:block}
.kpi .kpi-delta{font-size:12px;font-weight:600;margin-top:8px;display:flex;align-items:center;gap:4px}
.kpi .kpi-delta.up{color:var(--verde)}
.kpi .kpi-delta.down{color:var(--morado)}
.kpi-delta svg.icon{width:12px;height:12px;flex:none}

/* =====================================================================
   13. COMPONENTE — TABS
   ===================================================================== */
/* Todo lo que sirve para filtrar va en pastilla: las pestañas de la ficha
   son un filtro más, así que se ven igual que los chips de las listas y que
   el conmutador de periodo. Antes eran subrayados y rompían el patrón. */
.tabs{display:flex;gap:8px;margin-bottom:var(--sp-5);flex-wrap:wrap;
  background:none;border:0;border-radius:0;padding:0}
.tab{
  display:inline-flex;align-items:center;width:auto;white-space:nowrap;
  padding:6px 14px;border-radius:var(--r-pill);
  font-family:inherit;font-size:12px;font-weight:600;color:var(--morado);
  background:var(--blanco);border:1px solid var(--gris-borde);cursor:pointer;
  transition:background .16s ease,color .16s ease,border-color .16s ease;
}
.tab:not(.activo):hover{border-color:var(--amarillo);background:var(--realce)}
.tab.activo{background:var(--amarillo);border-color:var(--amarillo);color:var(--morado)}
.tab.activo:hover{filter:brightness(.97)}

/* =====================================================================
   14. COMPONENTE — CAMPO / FORM
   ===================================================================== */
.campo-fila{display:flex;align-items:flex-start;gap:var(--sp-3);padding:9px 0}
.campo-fila + .campo-fila{border-top:1px solid var(--gris-borde)}
.campo-fila svg.icon{width:16px;height:16px;color:var(--texto-suave);flex:none;margin-top:2px}
.campo-fila .campo-label{font-size:12px;color:var(--texto-suave);width:120px;flex:none}
.campo-fila .campo-valor{font-size:14px;color:var(--morado);font-weight:500;flex:1}

.input,.select{
  display:block;box-sizing:border-box;
  width:100%;padding:9px 12px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  font-size:14px;font-family:inherit;color:var(--morado);background:var(--blanco);
}
.input:focus,.select:focus{outline:2px solid var(--amarillo);outline-offset:0;border-color:var(--amarillo)}
/* LAS LISTAS DESPLEGABLES
   Un <select> sin tocar lo pinta el sistema operativo: fondo gris, flecha
   gris, esquinas ajenas. Por eso se veían como una pieza de otro diseño.
   Con appearance:none se apaga esa piel y se dibuja la nuestra: mismo
   fondo, mismo borde, misma tipografía y una flecha en morado de marca. */
select,select.input,select.select{
  -webkit-appearance:none;-moz-appearance:none;appearance:none;
  display:block;box-sizing:border-box;width:100%;
  padding:9px 34px 9px 12px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  font-size:14px;font-family:inherit;color:var(--morado);background-color:var(--blanco);
  cursor:pointer;line-height:1.4;
  background-image:url("data:image/svg+xml,<svg%20xmlns="http://www.w3.org/2000/svg"%20viewBox="0%200%2024%2024"%20fill="none"%20stroke="%232B1734"%20stroke-width="2.2"%20stroke-linecap="round"%20stroke-linejoin="round"><polyline%20points="6%209%2012%2015%2018%209"/></svg>");
  background-repeat:no-repeat;background-position:right 11px center;background-size:13px;
}
select:hover{border-color:var(--amarillo)}
select:focus{outline:2px solid var(--amarillo);outline-offset:0;border-color:var(--amarillo)}
select:disabled{opacity:.55;cursor:not-allowed;background-color:var(--gris-piedra)}
select::-ms-expand{display:none}
select option{color:var(--morado);background:var(--blanco)}
.campo-form{display:block}
.campo-form label{display:block;font-size:12px;font-weight:600;color:var(--texto-suave);margin-bottom:6px}
.campo-form .input,.campo-form .select{display:block;box-sizing:border-box}

/* =====================================================================
   15. GRID HELPERS ADICIONALES
   ===================================================================== */
.grid-kpi3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-3);margin-bottom:var(--sp-3)}
.grid-kpi4{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--hueco);margin-bottom:var(--hueco)}
.grid-kpi5{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:var(--hueco);margin-bottom:var(--hueco)}
/* El delta con ícono ("25% vs. mes anterior") es más largo que el texto
   plano de sus 4 vecinas ("39% del total") y envolvía a 2 líneas dentro de
   la misma tarjeta angosta de grid-kpi5 (verificado en render aislado) —
   se reduce el tamaño SOLO aquí (no toca .kpi-delta base, usado en
   M0/M3/M4/M7/M8/M9) y se fuerza una sola línea. */
.grid-kpi5 .kpi-delta{font-size:11px;white-space:nowrap}
.filtros{display:flex;gap:8px;margin-bottom:var(--sp-4);flex-wrap:wrap}
/* El botón de editar va en la misma fila que los filtros, al final y
   solo: arriba al centro competía con el de alta. */
.filtros .btn-editar-lista{margin-left:auto;border-radius:10px;padding:7px 14px;font-size:13.5px}
/* Nada se sale de su tarjeta: los encabezados se envuelven y el texto
   largo de una tabla parte renglón en vez de empujar la tabla a lo ancho.
   Era lo que pasaba en Campañas activas y en Avisos de clientes vencidos. */
.card-head{flex-wrap:wrap}
.card .tipo-h2{overflow-wrap:anywhere;min-width:0}
/* OJO: aquí NO va table-layout:auto. Esta regla (.card .tabla) le gana en
   especificidad a .tabla-cobranza, .tabla-ventas, .m6-tabla-inventario y
   al resto de las tablas que piden table-layout:fixed con % por columna,
   así que las devolvía a "auto". Y con auto, una celda con white-space:
   nowrap empuja la tabla más allá de la tarjeta y el botón de la última
   columna queda recortado por el borde. "auto" ya es el valor inicial de
   la propiedad: no declararlo deja intactas las tablas que no piden nada
   y respeta a las que sí. */
.card .tabla{width:100%}
.card .tabla th,.card .tabla td{overflow-wrap:anywhere}
.card .inc-texto b,.card .inc-texto span{overflow-wrap:anywhere}

/* UNA SOLA PASTILLA EN TODA LA PLATAFORMA
   Había tres estados "seleccionado" distintos: morado en los filtros de
   lista, amarillo en los conmutadores de periodo y en las vistas, y otro en
   las pestañas. Lo seleccionado va SIEMPRE en amarillo con texto morado,
   que es lo que ya hacen la barra de arriba y el menú lateral. */
.filtro-chip{
  display:inline-flex;align-items:center;width:auto;cursor:pointer;
  padding:6px 14px;border-radius:var(--r-pill);border:1px solid var(--gris-borde);
  font-size:12px;font-weight:600;color:var(--morado);background:var(--blanco);
  font-family:inherit;transition:background .16s ease,border-color .16s ease,color .16s ease;
}
.filtro-chip.activo{background:var(--amarillo);border-color:var(--amarillo);color:var(--morado)}
.filtro-chip:not(.activo):hover{border-color:var(--amarillo);background:var(--realce)}
.filtro-chip.activo:hover{filter:brightness(.97)}
.buscador{display:flex;align-items:center;gap:8px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  padding:9px 12px;background:var(--blanco);flex:1;max-width:320px}
.buscador svg.icon{width:16px;height:16px;color:var(--texto-suave)}
.buscador input{border:none;outline:none;font-size:14px;flex:1;width:100%;min-width:0;font-family:inherit;color:var(--morado);background:transparent}

/* =====================================================================
   16. GRÁFICAS — SVG/CSS puro, sin librerías
   ===================================================================== */
.barra-h{display:flex;flex-direction:column;gap:var(--sp-3)}
.barra-h-fila{display:grid;grid-template-columns:120px minmax(0,1fr) 56px;align-items:center;gap:10px}
.barra-h-label{font-size:13px;color:var(--morado)}
.barra-h-pista{height:8px;background:var(--gris-piedra);border-radius:var(--r-pill);overflow:hidden}
.barra-h-valor{height:100%;background:var(--amarillo);border-radius:var(--r-pill)}
.barra-h-num{font-size:13px;font-weight:600;text-align:right;font-variant-numeric:tabular-nums;color:var(--morado)}

.progreso{display:flex;flex-direction:column;gap:6px}
.progreso-cabeza{display:flex;justify-content:space-between;font-size:13px}
.progreso-pista{height:6px;background:var(--gris-piedra);border-radius:var(--r-pill);overflow:hidden}
.progreso-valor{height:100%;background:var(--verde);border-radius:var(--r-pill)}

.dona-wrap{display:flex;align-items:center;gap:var(--sp-5)}
.dona-leyenda{display:flex;flex-direction:column;gap:8px;flex:1}
.dona-item{display:flex;align-items:center;gap:8px;font-size:13px}
.dona-punto{width:10px;height:10px;border-radius:50%;flex:none}

/* =====================================================================
   99. RESPONSIVE MÍNIMO (la maqueta se presenta en laptop; esto evita
       ruptura visible si la ventana no es 1440)
   ===================================================================== */
@media (max-width:1280px){
  .grid-3{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .grid-kpi4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .grid-kpi5{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* =====================================================================
   17. MÓDULO 2 — MASCOTAS (específico, replica referencia PawCare)
   ===================================================================== */
/* Lista/ficha dentro de la misma seccion, mismo patron que M1
   (.m1-panel/.m1-panel.activo + m1MostrarLista()/m1AbrirCliente()). */
.m2-panel{display:none}
.m2-panel.activo{display:block}
.m2-tabla-mascotas tbody tr{cursor:pointer}
.m2-header{display:flex;align-items:center;gap:var(--sp-5);margin-bottom:var(--sp-5);flex-wrap:wrap}
.m2-avatar{width:96px;height:96px;border-radius:50%;object-fit:cover;border:3px solid var(--blanco);box-shadow:var(--sombra-card);flex:none}
/* Version generica del avatar (iniciales, para los 17 perritos sin foto
   real) -- misma caja que .m2-avatar (aplicadas juntas en el HTML), solo
   agrega el centrado del texto y el tinte. */
.m2-gen-avatar-ini{display:flex;align-items:center;justify-content:center;
  background:rgba(43,23,52,.10);overflow:hidden}
.m2-silueta{width:48px;height:48px;color:var(--morado);opacity:.38;flex:none}
.m2-header-info{flex:1;min-width:200px}
.m2-header-info .tipo-h1{display:inline-block;margin-right:var(--sp-3);vertical-align:middle}
.m2-header-info .chip{vertical-align:middle}
.m2-header-info .suave{margin-top:4px;font-size:14px}
.m2-header .btn{margin-left:auto}

/* Proporción tras quitar la tarjeta vertical de foto (22-sep, tanda M2): la
   columna derecha ya no necesita sostener una foto grande, así que se
   angosta y el ancho recuperado se reparte entre izquierda (tabla de
   Vacunas y salud a 4 columnas + franja de 4 celdas, necesita más aire) y
   centro (algo más ancha también). 1.15 : 1 : 0.85 en vez de 1 : 1 : 1.5. */
.m2-grid{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr) minmax(0,.8fr);gap:var(--sp-4);align-items:start}

.m2-temperamento{line-height:1.55}

/* Franja de 4 celdas (Alergias/Medicamentos/Restricciones/Observaciones)
   debajo de la tabla de Vacunas y salud — antes eran campo-fila sueltas en
   gris, ahora con el mismo peso visual que la tabla de arriba (label chico
   en mayúsculas, valor en semibold morado) para que un cuidador lo vea de
   un golpe. Flexbox, no grid anidado (bug §4.2 del traspaso). */
/* Divisor como elemento propio (no border-right en el flex item): con
   border-right directo en una celda flex:1 el texto largo (MEDICAMENTOS,
   OBSERVACIONES) se desbordaba sobre la celda vecina en WeasyPrint en vez
   de encogerse/partirse — verificado, no es apreciación. .m2-salud-info
   además pasa de flex-column a bloque simple (label/valor apilados por
   default de bloque) para no anidar un tercer nivel de flex. */
.m2-salud-franja{display:flex;align-items:flex-start;margin-top:var(--sp-3);padding-top:var(--sp-3);border-top:1px solid var(--gris-borde);flex-wrap:wrap;gap:var(--sp-3) 0}
.m2-salud-celda{flex:1;min-width:0;display:flex;align-items:flex-start;gap:6px}
.m2-salud-div{width:1px;align-self:stretch;background:var(--gris-borde);flex:none;margin:0 var(--sp-2)}
.m2-salud-celda svg.icon{width:15px;height:15px;color:var(--morado);flex:none;margin-top:2px}
.m2-salud-info{min-width:0}
.m2-salud-label{display:block;font-size:10.5px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--texto-suave);margin-bottom:2px;overflow-wrap:break-word;white-space:nowrap}
.m2-salud-valor{display:block;font-size:13.5px;font-weight:600;color:var(--morado);overflow-wrap:break-word}

.m2-alimentacion{
  display:flex;gap:var(--sp-3);align-items:flex-start;flex:1;min-width:0;
  background:rgba(151,209,10,.08);border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4);
}
.m2-alimentacion svg.icon{width:18px;height:18px;color:var(--verde);flex:none;margin-top:2px}
.m2-alimentacion b{display:block;font-size:14px;color:var(--morado)}
.m2-alimentacion span{font-size:13px;color:var(--texto-suave)}

/* Observaciones al lado de Alimentación, mismo componente en gris neutro.
   Fila con flexbox (no grid anidado dentro de .grid-2-1 > .card). */
.m2-info-2col{display:flex;gap:var(--sp-3);margin-top:var(--sp-2);flex-wrap:wrap}
/* Sus dos columnas lado a lado no caben en un telefono: medido a 390 px se
   salian 38 px de la tarjeta y «Alimentacion» y «Observaciones» quedaban
   cortadas. Con flex-wrap se ponen una debajo de la otra en vez de
   empujar fuera de la caja, y en escritorio no cambia nada porque ahi
   caben. El minimo evita que se partan en tiras antes de envolver. */
.m2-info-2col > *{flex:1 1 180px;min-width:0}
.m2-obs-caja{
  display:flex;gap:var(--sp-3);align-items:flex-start;flex:1 1 180px;min-width:0;
  background:var(--gris-piedra);border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4);
}
/* El `min-width:0` de arriba deja encoger la caja, pero su hijo -- el bloque
   que lleva el titulo y el texto -- no lo tenia, y es el que empujaba: medido
   a 390 px se salia 38 px de la tarjeta y a 1440 todavia 11. Es el mismo
   patron de flexbox de siempre: con `flex:1` a secas un hijo no baja de su
   ancho de contenido. Y la base de 180 px es lo que hace que estas cajas se
   pongan una debajo de otra en un telefono en vez de salirse. */
.m2-obs-caja > div{min-width:0}
.m2-obs-caja b{overflow-wrap:anywhere}
.m2-obs-caja svg.icon{width:18px;height:18px;color:var(--texto-suave);flex:none;margin-top:2px}
.m2-obs-caja b{display:block;font-size:14px;color:var(--morado)}
.m2-obs-caja span{font-size:13px;color:var(--texto-suave)}

.m2-servicio-fila{display:flex;align-items:center;gap:var(--sp-3);padding:9px 0}
.m2-servicio-fila + .m2-servicio-fila{border-top:1px solid var(--gris-borde)}
.m2-servicio-fila svg.icon{width:17px;height:17px;color:var(--texto-suave);flex:none}
.m2-servicio-fila .nombre{flex:1;font-size:14px;color:var(--morado);font-weight:500}

.m2-col-der{display:flex;flex-direction:column;gap:var(--hueco)}
/* .m2-acciones ya no comparte fila con una foto (se quitó la tarjeta
   vertical): ancho fijo de 150px cambiado por 100% para que se estire al
   ancho completo de la columna derecha (align-items:stretch heredado de
   .m2-col-der), igual que la tarjeta de Comunicación reciente debajo. */
.m2-acciones{display:flex;flex-direction:column;gap:8px}
.btn-accion{
  display:flex;align-items:center;gap:10px;
  background:var(--blanco);border:1px solid var(--gris-borde);border-radius:var(--r-md);
  padding:11px 12px;font-size:12.5px;font-weight:600;color:var(--morado);
  box-shadow:var(--sombra-card);text-align:left;
}
.btn-accion svg.icon{width:15px;height:15px;color:var(--morado);flex:none}
.btn-accion:hover{background:rgba(43,23,52,.05)}
.btn-accion:focus-visible{outline:2px solid var(--amarillo);outline-offset:1px}

/* =====================================================================
   18. MÓDULO 0 — DASHBOARD EJECUTIVO (específico)
   ===================================================================== */
/* Cobranza pendiente: columna Cliente demasiado angosta partia "Familia X"
   a 2 lineas en 4 de 5 filas (Torres/Rojas/Mendoza/Castillo) -- mismo
   remedio ya usado en .m3-tabla-espera/.m4-tabla-asistencia/.m5-tabla-
   incidencias: table-layout:fixed + % explicito por columna. A diferencia
   de esas tablas, aqui ademas hace falta white-space:nowrap en la celda
   Cliente (el problema no es una palabra sin espacio que no cabe, es que
   "Familia X" SI tiene un espacio natural para partir -- con solo el %
   de columna seguiria partiendose ahi). */
/* Tres columnas, no cuatro. Los días vencidos ya los dice el chip de
   estado ("Vencido" / "Por vencer"), así que la columna sólo servía para
   robarle ancho a Monto: con 15% el encabezado se partía en "mo/nto" y
   "Días venc." en "s/b ... nc". Fuera la columna, los encabezados ya no
   se parten (nowrap, no break-word) y Estado se centra en su columna. */
.m0-tabla-cobranza{table-layout:fixed}
.m0-tabla-cobranza th:nth-child(1),.m0-tabla-cobranza td:nth-child(1){width:42%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.m0-tabla-cobranza th:nth-child(2),.m0-tabla-cobranza td:nth-child(2){width:26%;white-space:nowrap}
.m0-tabla-cobranza th:nth-child(3),.m0-tabla-cobranza td:nth-child(3){width:32%;white-space:nowrap;text-align:center}
.m0-tabla-cobranza thead th{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:2px}
.m0-tabla-cobranza td .chip{vertical-align:middle}

.kpi-meta{margin-top:10px}
.kpi-meta .progreso-pista{margin-top:6px}

.fin-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--sp-4)}
.fin-item{padding:var(--sp-3) 0}
.fin-item .tipo-label{color:var(--texto-suave);display:block;margin-bottom:6px}
.fin-item .tipo-dato{font-size:22px}
.fin-item.neg .tipo-dato{color:var(--morado)}

.inc-fila{display:flex;align-items:center;gap:var(--sp-3);padding:10px 0}
.inc-fila + .inc-fila{border-top:1px solid var(--gris-borde)}
.inc-fila svg.icon{width:17px;height:17px;color:var(--texto-suave);flex:none}
/* min-width:0 es lo que le permite encogerse: con `flex:1` a secas, un
   hijo flex no baja de su ancho de contenido y empuja al chip de al lado
   fuera de la tarjeta. Medido: 11 px fuera en el tablero. */
.inc-fila .inc-texto{flex:1;min-width:0}
.inc-fila .inc-texto b{display:block;font-size:13.5px;color:var(--morado);font-weight:600}
.inc-fila .inc-texto span{font-size:12.5px;color:var(--texto-suave)}

/* =====================================================================
   19. MÓDULO 1 — CLIENTES (específico)
   ===================================================================== */
/* Encabezado de la lista con CTA "Nuevo cliente" -- mismo patron que
   .m3-encabezado/.m5-encabezado (header + boton, header con margin-bottom:0).
   flex-wrap:nowrap desde el inicio (bug ya documentado 4 veces en
   TRASPASO-UX.md #4.4 -- flex anidado con hijos que no envuelven bien). */
.m1-lista-encabezado{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);flex-wrap:nowrap;margin-bottom:var(--sp-4)}
.m1-header{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-5);flex-wrap:wrap}
.m1-avatar{
  width:72px;height:72px;border-radius:50%;flex:none;
  background:var(--morado);color:var(--blanco);
  display:flex;align-items:center;justify-content:center;
  font-size:22px;font-weight:700;letter-spacing:.02em;
  border:3px solid var(--blanco);box-shadow:var(--sombra-card);
}
.m1-header-info{flex:1;min-width:200px}
.m1-header-info .tipo-h1{display:inline-block;margin-right:var(--sp-3);vertical-align:middle}
.m1-header .btn{margin-left:auto}

.stat-grid{display:flex;flex-direction:column;gap:var(--sp-3)}
.stat-box{
  display:flex;align-items:center;gap:var(--sp-3);
  background:var(--gris-piedra);border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);
}
.stat-box svg.icon{width:20px;height:20px;color:var(--morado);flex:none}
.stat-box .stat-valor{font-size:20px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.stat-box .stat-valor.alerta{color:var(--morado)}
.stat-box .stat-label{font-size:11px;color:var(--texto-suave);text-transform:uppercase;letter-spacing:.03em}
.quote-box{
  margin-top:var(--sp-4);padding:var(--sp-4);border-left:3px solid var(--amarillo);
  font-size:13px;font-style:italic;color:var(--texto-suave);
}

/* ---- 19b. M1 — lista de clientes / ficha (subvistas dentro de #m1) ---- */
.m1-panel{display:none}
.m1-panel.activo{display:block}
.breadcrumb-link{cursor:pointer}
.breadcrumb-link:hover{text-decoration:underline;color:var(--morado)}
.tabla-clicable tbody tr{cursor:pointer}
.tabla-clicable tbody tr{transition:background .16s ease}
.tabla-clicable tbody tr:hover td{background:var(--realce)}
.m7-anios{display:flex;align-items:center;gap:8px;margin-left:auto}
.m7-anios .m3-semana-nav-flecha:disabled{opacity:.35;cursor:not-allowed}
.m7-anios .m3-semana-nav-texto{min-width:54px}
/* el realce de una fila no termina en pico: se redondea en los extremos */
.tabla-clicable tbody tr:hover td:first-child{border-radius:9px 0 0 9px}
.tabla-clicable tbody tr:hover td:last-child{border-radius:0 9px 9px 0}
.inc-fila[role="button"],.inc-fila[onclick]{cursor:pointer;border-radius:10px;
  margin-inline:calc(-1 * var(--sp-3));padding-inline:var(--sp-3);
  transition:background .18s ease}
/* Filas clicables: el realce era un rectángulo gris de esquinas rectas que
   se leía como una caja pegada encima. Ahora es un tinte cálido de la marca,
   redondeado y sangrado hacia afuera, que se lee como "este renglón está
   vivo" en vez de como un cuadro. */
#m0 .m0-incidencias{flex:1 1 auto;display:flex;flex-direction:column}
#m0 .inc-fila{cursor:pointer;border-radius:10px;
  margin-inline:calc(-1 * var(--sp-3));padding-inline:var(--sp-3);
  transition:background .18s ease,transform .18s ease}
#m0 .inc-fila:hover,#m0 .inc-fila:focus-visible,
.inc-fila[role="button"]:hover,.inc-fila[onclick]:hover{background:var(--realce);outline:none}
#m0 .inc-fila:hover .inc-texto b,#m0 .inc-fila:focus-visible .inc-texto b{color:var(--morado)}
#m0 .inc-fila:active{transform:scale(.995)}
.m1-header-acciones{display:flex;gap:var(--sp-3);align-items:center}
.m1-estado-destacado{
  display:flex;align-items:center;gap:var(--sp-3);
  background:rgba(151,209,10,.15);border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-3);
}
.m1-estado-destacado .icon-badge{margin-bottom:0}
.stat-label-mini{font-size:11px;color:var(--texto-suave);text-transform:uppercase;letter-spacing:.03em;margin-bottom:2px}
.stat-valor-grande{font-size:28px;font-weight:700;color:var(--morado);line-height:1;font-variant-numeric:tabular-nums}
.stat-fila-2{display:flex;gap:var(--sp-3)}
.stat-fila-2 .stat-box{flex:1}
.m1-al-corriente{
  display:flex;align-items:center;gap:6px;margin-top:var(--sp-3);
  font-size:12.5px;font-weight:600;color:var(--verde);
}
.m1-al-corriente svg.icon{width:15px;height:15px;flex:none}
.m1-mascotas-fila{display:flex;flex-wrap:wrap;gap:var(--sp-3)}
.m1-mascota-card{
  flex:1 1 calc(25% - var(--sp-3));min-width:110px;text-align:left;cursor:pointer;
  border:1px solid var(--gris-borde);border-radius:var(--r-md);padding:var(--sp-3);background:var(--blanco);
  display:flex;flex-direction:column;
}
/* El chip de nivel bajaba o subía según si la raza cabía en uno o en dos
   renglones ("Golden Retriever" contra "Maltés"). Empujado al fondo, los
   cuatro quedan siempre a la misma altura. */
.m1-mascota-card .chip{margin-top:auto;align-self:flex-start}
.m1-mascota-raza{min-height:2.4em}
.m1-mascota-card:hover{border-color:var(--morado)}
.m1-mascota-foto{width:100%;height:104px;aspect-ratio:1;border-radius:var(--r-sm);object-fit:cover;margin-bottom:var(--sp-3)}
.m1-mascota-avatar{
  width:100%;height:104px;aspect-ratio:1;border-radius:var(--r-sm);margin-bottom:var(--sp-3);
  display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:700;color:var(--morado);
}
.m1-mascota-avatar.tinte-verde{background:rgba(151,209,10,.20)}
.m1-mascota-avatar.tinte-amarillo{background:rgba(254,200,0,.20)}
/* El tercer tinte. El avatar de iniciales reparte por nombre entre tres —el
   mismo reparto de M02/M04/M05, para que la misma mascota tenga siempre el
   mismo color— y aqui solo habia dos declarados: una de cada tres salia sin
   fondo. Mismo valor que `.m4-avatar-mini.tinte-morado`, que ya lo resolvio. */
.m1-mascota-avatar.tinte-morado{background:rgba(43,23,52,.16)}
.m1-mascota-nombre{font-size:14px;font-weight:700;color:var(--morado)}
.m1-mascota-raza{font-size:12px;color:var(--texto-suave);margin:2px 0 var(--sp-3)}
.m1-mascota-agregar{
  flex:1 1 calc(25% - var(--sp-3));min-width:110px;min-height:150px;cursor:pointer;
  border:1px dashed var(--gris-borde);border-radius:var(--r-md);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  color:var(--texto-suave);font-size:13px;font-weight:600;
}
.m1-mascota-agregar:hover{border-color:var(--morado);color:var(--morado)}
.m1-agregar-icono{
  width:32px;height:32px;border-radius:50%;border:2px solid var(--gris-borde);
  display:flex;align-items:center;justify-content:center;flex:none;
}
.m1-agregar-icono svg.icon{width:16px;height:16px}
.barra-h-label-icono{display:flex;align-items:center;gap:6px}
.barra-h-label-icono svg.icon{width:14px;height:14px;color:var(--texto-suave);flex:none}
.m1-canal{display:inline-flex;align-items:center;gap:6px}
.m1-canal svg.icon{width:15px;height:15px;flex:none;color:var(--texto-suave)}
/* El ícono de WhatsApp usa stroke="#97D10A" como atributo XML literal (no
   var(--verde) por CSS de clase ni por style= en línea): en este motor
   WeasyPrint el stroke="currentColor" de un <path> no resuelve un color
   puesto por selector de clase en su ancestro, y var() tampoco se evalúa
   dentro de un atributo style="" en línea — mismo bug de fondo que el de
   stroke ya documentado en TRASPASO-UX.md §4, aplicado aquí a "color".
   Verificado con render aislado antes de esta entrega. */
.m1-notas{background:rgba(254,200,0,.10)}
.m1-notas-cuerpo{display:flex;gap:var(--sp-3);align-items:flex-start}
.m1-notas-cuerpo svg.icon{width:22px;height:22px;color:var(--morado);flex:none;margin-top:2px}
.m1-notas-lista{list-style:disc;padding-left:18px;display:flex;flex-direction:column;gap:6px;font-size:13.5px;color:var(--morado)}

/* =====================================================================
   20. MÓDULO 3 — AGENDA / CALENDARIO (reutilizado en M11 Marketing)
   ===================================================================== */
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
.cal-dow{font-size:10px;font-weight:600;text-transform:uppercase;color:var(--texto-suave);text-align:center;padding-bottom:6px}
.cal-day{
  aspect-ratio:1;min-height:64px;border-radius:var(--r-sm);border:1px solid var(--gris-borde);
  padding:6px;font-size:12px;color:var(--morado);position:relative;
}
.cal-day.vacio{border-color:transparent}
.cal-day.hoy{border-color:var(--amarillo);border-width:2px;font-weight:700}
.cal-day .puntos{position:absolute;bottom:6px;left:6px;display:flex;gap:3px}
.cal-day .punto{width:5px;height:5px;border-radius:50%;background:var(--amarillo)}
.cal-leyenda{display:flex;gap:var(--sp-4);margin-top:var(--sp-4);font-size:12px;color:var(--texto-suave)}
.cal-leyenda .item{display:flex;align-items:center;gap:6px}
.cal-leyenda .punto{width:8px;height:8px;border-radius:50%}

/* =====================================================================
   21. MÓDULO 5 — INCIDENCIAS: marcador de evidencia (sin imagen real)
   ===================================================================== */
.evidencia-marcador{
  display:inline-flex;flex:none;width:auto;align-items:center;gap:6px;
  background:var(--gris-piedra);border:1px solid var(--gris-borde);border-radius:var(--r-sm);
  padding:5px 10px;font-size:12px;font-weight:600;color:var(--texto-suave);
}
.evidencia-marcador svg.icon{width:14px;height:14px}

/* =====================================================================
   22. MÓDULO 8 — COBRANZA: antigüedad de saldos
   ===================================================================== */
.aging-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-3);margin-top:var(--sp-2)}
.aging-item{text-align:center;background:var(--gris-piedra);border-radius:var(--r-md);padding:var(--sp-3)}
.aging-item .tipo-dato{font-size:20px}
.aging-item .tipo-label{color:var(--texto-suave);margin-top:4px;font-size:10px}
.cuenta-cliente{padding:var(--sp-3) 0}
.cuenta-cliente + .cuenta-cliente{border-top:1px solid var(--gris-borde)}
.cuenta-cliente .fila-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}
.cuenta-cliente .nombre{font-size:13.5px;font-weight:600;color:var(--morado)}
.cuenta-cliente .monto{font-size:13.5px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.cuenta-cliente .sub{font-size:12px;color:var(--texto-suave);display:flex;justify-content:space-between}

/* =====================================================================
   23. MÓDULO 9 — GASTOS: dona SVG
   ===================================================================== */
.grid-1-2{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.6fr);gap:var(--hueco);align-items:start;margin-bottom:var(--hueco)}

/* =====================================================================
   24. MÓDULO 10 — COMUNICACIÓN: plantillas WhatsApp
   ===================================================================== */
.plantilla{background:var(--gris-piedra);border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4)}
.plantilla + .plantilla{margin-top:var(--sp-3)}
.plantilla .nombre{font-size:13px;font-weight:600;color:var(--morado);margin-bottom:6px}
.plantilla .burbuja{
  background:var(--blanco);border-radius:var(--r-md);padding:10px 12px;
  font-size:12.5px;color:var(--morado);border:1px solid var(--gris-borde);
}

/* =====================================================================
   25. MÓDULO 12 — RESCATES Y ADOPCIONES: tarjeta con marcador de foto
   ===================================================================== */
.adopcion-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-4)}
.adopcion-card{border:1px solid var(--gris-borde);border-radius:var(--r-lg);overflow:hidden;background:var(--blanco)}
.adopcion-foto{
  height:140px;background:var(--morado);
  display:flex;align-items:center;justify-content:center;
}
.adopcion-foto svg.icon{width:36px;height:36px;color:var(--amarillo)}
.adopcion-body{padding:var(--sp-4)}
.adopcion-body .nombre{font-size:16px;font-weight:700;color:var(--morado);margin-bottom:2px}
.adopcion-body .meta{font-size:12.5px;color:var(--texto-suave);margin-bottom:var(--sp-3)}
.adopcion-body .btn{width:100%}

/* Ampliación 22-sep-2026 (solicitud #43, decisión de Fernando): "El Corazón
   de Fica" — tarjetas con foto, historia destacada, embudo, gráfica mensual
   y dona de tipos de rescate. Los bloques que existían antes en esta misma
   pantalla (tabla "Rescates recientes", "Perritos en adopción", "Solicitudes
   de adopción") se retiran de la vista por decisión explícita de Fernando:
   "no se graba con la tabla — se hace la vista". .adopcion-grid/.adopcion-card
   de arriba quedan sin uso pero no se borran (mismo criterio que
   .sidebar-logo/.icon/.marca — ver sección 34: limpiar código muerto no vale
   el riesgo con el reloj corriendo). */
.rescate-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-4)}
.rescate-card{border:1px solid var(--gris-borde);border-radius:var(--r-lg);overflow:hidden;background:var(--blanco)}
.rescate-foto{width:100%;height:140px;object-fit:cover;display:block}
.rescate-body{padding:var(--sp-4)}
.rescate-body .nombre{font-size:16px;font-weight:700;color:var(--morado);margin-bottom:2px}
.rescate-body .raza{font-size:12.5px;color:var(--texto-suave);margin-bottom:12px}
.rescate-body .pie{display:flex;flex-wrap:nowrap;align-items:center;justify-content:space-between;gap:8px}
.rescate-body .fecha-rescate{font-size:11px;color:var(--texto-suave);white-space:nowrap}

.historia-destacada{display:flex;flex-wrap:nowrap;gap:var(--sp-5)}
.historia-foto{width:280px;height:260px;flex:none;object-fit:cover;border-radius:var(--r-lg)}
.historia-cuerpo{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}
.historia-nombre{font-size:20px;font-weight:700;color:var(--morado)}
.historia-cita{font-size:15px;color:var(--morado);line-height:1.55;font-style:italic;margin:6px 0 10px}
.historia-firma{font-size:12.5px;color:var(--texto-suave);font-weight:600}

.embudo{display:flex;flex-direction:column;gap:var(--sp-3)}
.embudo-fila{width:100%}
.embudo-fila .cabeza{display:flex;flex-wrap:nowrap;justify-content:space-between;font-size:13px;color:var(--morado);margin-bottom:6px}
.embudo-pista{width:100%;height:34px;background:var(--gris-piedra);border-radius:var(--r-md);display:flex;justify-content:center}
.embudo-valor{height:100%;border-radius:var(--r-md);background:var(--morado);display:flex;align-items:center;justify-content:center;color:var(--blanco);font-size:12px;font-weight:700}

.meses-grid{display:flex;flex-wrap:nowrap;align-items:flex-end;justify-content:space-between;gap:10px;height:150px;margin-top:6px}
.mes-col{display:flex;flex-direction:column;align-items:center;justify-content:flex-end;flex:1;height:100%}
.mes-barra{width:28px;background:var(--verde);border-radius:6px 6px 0 0}
.mes-valor{font-size:12px;font-weight:700;color:var(--morado);margin-bottom:6px}
.mes-label{font-size:11px;color:var(--texto-suave);margin-top:8px}

/* =====================================================================
   26. VISTA AYUDANTE (específico)
   ===================================================================== */
.check-fila{display:flex;align-items:center;gap:var(--sp-3);padding:11px 0}
.check-fila + .check-fila{border-top:1px solid var(--gris-borde)}
.check-box{
  width:20px;height:20px;border-radius:5px;border:2px solid var(--gris-borde);flex:none;
  display:flex;align-items:center;justify-content:center;
}
.check-fila.hecho .check-box{background:var(--verde);border-color:var(--verde)}
.check-fila.hecho .check-box svg.icon{width:12px;height:12px;color:var(--blanco)}
.check-fila .check-texto{flex:1}
.check-fila .check-texto b{display:block;font-size:14px;color:var(--morado);font-weight:600}
.check-fila.hecho .check-texto b{text-decoration:line-through;color:var(--texto-suave)}
.check-fila .check-texto span{font-size:12.5px;color:var(--texto-suave)}

.grid-4{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--hueco);margin-bottom:var(--hueco)}
.mascota-compacta{border:1px solid var(--gris-borde);border-radius:var(--r-lg);padding:var(--sp-4);background:var(--blanco)}
.mascota-compacta .m-avatar{
  width:44px;height:44px;border-radius:50%;background:var(--morado);color:var(--blanco);
  display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;margin-bottom:var(--sp-3);
}
.mascota-compacta .m-nombre{font-size:15px;font-weight:700;color:var(--morado)}
.mascota-compacta .m-meta{font-size:12px;color:var(--texto-suave);margin:2px 0 var(--sp-3)}

/* flexbox, no CSS grid: un grid anidado dentro de una celda de otro grid
   (.grid-2-1 > .card > .form-grid) colapsa su ancho en algunos motores de
   render — flex es robusto en el mismo anidamiento y se ve idéntico. */
/* Los controles de un mismo renglón cierran a la misma altura aunque una
   etiqueta ocupe dos líneas y su vecina una. Antes "Hora de salida de los
   avisos del día" partía en dos y empujaba su desplegable abajo, mientras
   "Canal preferido" se quedaba arriba: dos cajas del mismo renglón a
   alturas distintas. El campo pasa a columna y el control se pega al pie. */
/* `start`, no `stretch`. Con stretch cada campo crece hasta la altura del mas
   alto de su renglon, y como el campo de abajo lleva `margin-top:auto`, el
   control se iba al fondo de esa altura prestada: en el alta, «Temperamento»
   quedaba a 180 px de su propia etiqueta porque al lado estaba la foto con su
   recuadro de vista previa. Es la misma decision que ya se tomo para `.campo`
   —§11, «align-content:start»— sólo que esta rejilla es de flex y se le habia
   escapado. Medido en el formulario de alta, 20-oct. */
.form-grid{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:start}
.form-grid .campo-form{flex:1 1 calc(50% - var(--sp-4));min-width:160px;
  display:flex;flex-direction:column}
.form-grid .campo-form > label{margin-bottom:6px}
.form-grid .campo-form > .input,.form-grid .campo-form > .select,
.form-grid .campo-form > select,.form-grid .campo-form > textarea,
.form-grid .campo-form > .busca-caja{margin-top:0}
.form-full{flex:1 1 100%}

/* =====================================================================
   27. CHIP DE RIESGO (rojo, uso restringido — ver comentario en :root)
   ===================================================================== */
.chip-riesgo{background:rgba(179,38,30,.13);color:var(--rojo)}
.chip-riesgo .chip-dot{background:var(--rojo)}

/* =====================================================================
   28. SALUDO — encabezado M0
   ===================================================================== */
.saludo{margin-bottom:var(--sp-5)}
.saludo h1{font-size:30px;font-weight:700;color:var(--morado);line-height:1.2}
.saludo .sub{color:var(--texto-suave);margin-top:4px;font-size:15px}
.saludo .raya{width:56px;height:4px;background:var(--amarillo);border-radius:2px;margin-top:12px}

/* =====================================================================
   29. INSIGNIA DE ÍCONO EN CÍRCULO DE TINTE
   ===================================================================== */
/* ICONOS ROTOS — la causa
   Las formas de dentro de cada ícono (653 en la plataforma, 73 de ellas
   <rect>) llevan también class="icon". En SVG2, width y height son
   propiedades de geometría: CUALQUIER regla que medía ".icon" le cambiaba
   el tamaño al rectángulo de adentro. Por eso el calendario, la palomita de
   completados, la gráfica de ventas y los de gastos salían partidos o fuera
   de su círculo. Esas 38 reglas ahora miden solo el <svg>. La insignia
   crece de 44 a 48 px para que el dibujo respire. */
.icon-badge{width:48px;height:48px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;margin-bottom:var(--sp-3);flex:none}
.icon-badge > svg{width:24px;height:24px;color:var(--morado);stroke-width:2;flex:none}
/* El icono iba siempre en morado, y sobre el tinte morado quedaba morado
   sobre morado: se veía sucio y no se distinguía la figura. Ahora el fondo
   es más claro y el trazo del icono es un tono profundo del MISMO color del
   tinte, que es lo que lo hace legible. */
.icon-badge.tinte-amarillo{background:rgba(254,200,0,.22)}
.icon-badge.tinte-amarillo .icon{color:#7A5E00}
.icon-badge.tinte-verde{background:rgba(151,209,10,.22)}
.icon-badge.tinte-verde .icon{color:#456E00}
.icon-badge.tinte-morado{background:rgba(92,58,107,.15)}
.icon-badge.tinte-morado .icon{color:#5C3A6B}
.icon-badge.tinte-ambar{background:rgba(168,124,0,.17)}
.icon-badge.tinte-lila{background:rgba(154,123,168,.20)}
.icon-badge.tinte-lila .icon{color:#6B4A7C}
.icon-badge.tinte-oliva{background:rgba(95,140,6,.18)}
.icon-badge.tinte-oliva .icon{color:#3F5E00}
.icon-badge.tinte-ambar .icon{color:#7C5A00}

/* KPI con insignia: header en fila (ícono a la izq, contenido a la der. en tarjetas
   de Resumen financiero) o insignia arriba (tarjetas de KPI principales) */
.kpi-delta.bien{color:var(--verde)}
.kpi-delta.mal{color:var(--rojo)}

.fin-tile{display:flex;gap:var(--sp-3);align-items:flex-start}
.fin-tile .icon-badge{margin-bottom:0}
.fin-tile .fin-tile-body .tipo-dato{font-size:22px}
.fin-tile .fin-tile-body .tipo-label{display:block;margin-top:2px;color:var(--texto-suave)}
.fin-tile .fin-tile-body .kpi-delta{margin-top:6px;font-size:12px}

/* =====================================================================
   30. SPARKLINE — mini barras crecientes (CSS puro, sin librerías)
   ===================================================================== */
.sparkline{display:flex;align-items:flex-end;gap:3px;height:26px;margin-top:8px}
.sparkline .barra{width:5px;background:var(--morado);opacity:.30;border-radius:2px}
.sparkline .barra.actual{opacity:1;background:var(--amarillo)}

/* =====================================================================
   31. ANILLOS — Ocupación por servicio (SVG, stroke-dasharray)
   ===================================================================== */
.anillo-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-4)}
.anillo-item{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px}
.anillo{position:relative;width:96px;height:96px}
.anillo svg{width:100%;height:100%;transform:rotate(-90deg)}
.anillo .pista{fill:none;stroke:var(--gris-borde);stroke-width:9}
.anillo .valor{fill:none;stroke-width:9;stroke-linecap:round}
.anillo .centro{
  position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;
  font-size:19px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums;
}
.anillo-item .servicio{font-size:13px;font-weight:600;color:var(--morado)}
.anillo-item .fraccion{font-size:12px;color:var(--texto-suave)}

/* Conmutador de periodo (Hoy/Semana/Mes/Año) — mismo lenguaje visual que
   .vista-pill del topbar (activa = fondo amarillo, texto morado), pero es una
   clase independiente: .vista-pill lo controla setVista() por selector global
   (document.querySelectorAll('.vista-pill')) y reusar esa clase aquí haría que
   cambiar de vista (Dirección/Administración/Ayudante) le quitara "activa" a
   este selector sin querer. Va en su propia fila (no dentro de .card-head):
   junto al título "Ocupación por servicio" las 4 opciones no caben en una
   sola línea sin partir el título — separarlo evita tocar el ancho de
   .card-head (compartida) y mantiene los 3 encabezados de la fila idénticos
   (solo título, misma altura que sus vecinos). */
.periodo-switch-fila{display:flex;justify-content:flex-end;margin-bottom:var(--sp-3)}
.periodo-switch{display:flex;flex:none;gap:8px;background:none;padding:0;border-radius:0;flex-wrap:wrap}
.periodo-pill{
  display:inline-flex;align-items:center;justify-content:center;width:auto;white-space:nowrap;
  padding:6px 14px;border-radius:var(--r-pill);border:1px solid var(--gris-borde);
  font-family:inherit;font-size:12px;font-weight:600;line-height:1.2;
  background:var(--blanco);color:var(--morado);cursor:pointer;
  transition:background .16s ease,color .16s ease,border-color .16s ease;
}
.periodo-pill:focus-visible{outline:2px solid var(--morado);outline-offset:1px}
.periodo-pill.activa{background:var(--amarillo);color:var(--morado);border-color:var(--amarillo)}
.periodo-pill:not(.activa):hover{border-color:var(--amarillo);background:var(--realce)}
.periodo-pill.activa:hover{filter:brightness(.97)}

/* =====================================================================
   32. PRÓXIMAS ACTIVIDADES
   ===================================================================== */
.actividad-fila{display:flex;align-items:center;gap:var(--sp-3);padding:10px 0}
.actividad-fila + .actividad-fila{border-top:1px solid var(--gris-borde)}
.actividad-fila .icon-badge{margin-bottom:0;width:36px;height:36px}
.actividad-fila .icon-badge svg.icon{width:18px;height:18px;stroke-width:2.1}
.actividad-fila .hora{font-size:13px;font-weight:700;color:var(--morado);width:44px;flex:none;font-variant-numeric:tabular-nums}
.actividad-fila .act-texto b{display:block;font-size:14px;color:var(--morado);font-weight:600}
.actividad-fila .act-texto span{font-size:12.5px;color:var(--texto-suave)}

/* =====================================================================
   33. MODALES — mismo sistema (card blanca, radio 12, borde E8E5E0)
   ===================================================================== */
.modal-backdrop{
  position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(43,23,52,.45);
  display:none;align-items:center;justify-content:center;padding:32px;z-index:300;
}
.modal-backdrop.abierto{display:flex}
.modal-caja{
  background:var(--blanco);border:1px solid var(--gris-borde);border-radius:var(--r-lg);
  max-width:680px;width:100%;max-height:82vh;overflow:auto;
  box-shadow:0 12px 32px rgba(0,0,0,.18);
}
.modal-header{
  display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);
  padding:18px 22px;border-bottom:1px solid var(--gris-borde);
  position:sticky;top:0;background:var(--blanco);
}
.modal-header .tipo-h2{margin:0}
.modal-cerrar{
  display:inline-flex;flex:none;width:28px;height:28px;align-items:center;justify-content:center;
  border-radius:50%;color:var(--morado);font-size:18px;line-height:1;cursor:pointer;
}
.modal-cerrar:hover{background:rgba(43,23,52,.07)}
.modal-body{padding:20px 22px}
.modal-body .card-vacio{padding:0}
body.modal-abierto{overflow:hidden}

/* =====================================================================
   34. LOGO — huella + wordmark (sidebar)
   ===================================================================== */
.sidebar-logo{display:flex;align-items:center;gap:var(--sp-3)}
.sidebar-logo svg.icon{width:40px;height:40px;color:var(--amarillo);flex:none}
.sidebar-logo .marca{font-size:17px;font-weight:700;line-height:1.15}
/* .sidebar-logo/svg.icon/.marca ya no se usan (reemplazados por el logo real
   abajo) pero se dejan sin tocar -- limpiar codigo muerto no vale el riesgo
   con el reloj corriendo. Logo real del cliente, JPEG incrustado como data
   URI, sobre placa blanca -- mismo --r-lg (12px) que .card, sin inventar
   un radio nuevo. */
.sidebar-logo-placa{
  width:160px;
  margin:0 auto var(--sp-3);
  background:#FFFFFF;
  border-radius:var(--r-lg);
  padding:14px;
  display:flex;
  align-items:center;
  justify-content:center;
}
.sidebar-logo-img{
  width:100%;
  height:auto;
  display:block;
}

/* =====================================================================
   35. PÍLDORA DE AYUDA
   ===================================================================== */
.sidebar-soporte{
  display:flex;align-items:center;gap:8px;
  margin-top:var(--sp-4);padding:10px 14px;
  border:1px solid rgba(255,255,255,.18);border-radius:var(--r-pill);
  font-size:12px;color:rgba(255,255,255,.75);
}
.sidebar-soporte svg.icon{width:15px;height:15px;flex:none}

/* =====================================================================
   36. MÓDULO 3 — AGENDA SEMANAL (específico)
   ===================================================================== */
.m3-encabezado{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);flex-wrap:wrap;margin-bottom:var(--sp-4)}
.m3-encabezado .btn{flex:none}
/* Editar deja de competir de tú a tú con el CTA: sube a un engrane chico
   encima de "Agendar servicio", que es lo que de verdad se pica a diario. */
.m3-cab-acciones{display:flex;flex-direction:column;align-items:flex-end;gap:8px;flex:none}
.m3-engrane{width:34px;height:34px;border-radius:50%;flex:none;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--gris-borde);background:var(--blanco);color:var(--morado);
  transition:background .16s ease,border-color .16s ease}
.m3-engrane svg.icon{width:17px;height:17px}
.m3-menu-caja{position:relative;flex:none}
.m3-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:186px;
  background:var(--blanco);border:1px solid var(--gris-borde);border-radius:10px;
  box-shadow:0 8px 20px rgba(43,23,52,.14);overflow:hidden;padding:4px}
.m3-menu button{display:block;width:100%;text-align:left;border:0;background:none;
  padding:9px 12px;border-radius:7px;font:inherit;font-size:13px;font-weight:600;
  color:var(--morado);cursor:pointer}
.m3-menu button:hover{background:var(--realce)}
.m3-menu-caja{position:relative;flex:none}
.m3-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:186px;
  background:var(--blanco);border:1px solid var(--gris-borde);border-radius:10px;
  box-shadow:0 8px 20px rgba(43,23,52,.14);overflow:hidden;padding:4px}
.m3-menu button{display:block;width:100%;text-align:left;border:0;background:none;
  padding:9px 12px;border-radius:7px;font:inherit;font-size:13px;font-weight:600;
  color:var(--morado);cursor:pointer}
.m3-menu button:hover{background:var(--realce)}
.m3-engrane:hover{border-color:var(--amarillo);background:var(--realce)}
.m3-encabezado .modulo-header{flex:1 1 320px}

.m3-controles{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;margin-bottom:var(--sp-3)}
/* nowrap adentro de cada grupo: si no cabe, el grupo completo baja de línea
   (m3-controles sí es flex-wrap), en vez de partir un pill del otro. */
.m3-vistas{display:flex;gap:8px;flex-wrap:nowrap}
.m3-semana-nav{display:flex;align-items:center;gap:var(--sp-3);margin-left:auto;flex:0 0 auto;width:225px;justify-content:flex-start}
.m3-semana-nav-flecha{
  display:flex;flex:none;width:28px;height:28px;align-items:center;justify-content:center;
  border-radius:50%;border:1px solid var(--gris-borde);background:var(--blanco);color:var(--morado);
}
/* display:flex, no inline-flex: en el motor de verificación (WeasyPrint), un
   inline-flex de tamaño fijo con border-radius:50% dentro de un padre flex se
   duplicaba en un círculo fantasma desalineado (aislado y confirmado con una
   prueba separada) — flex (blockificado igual como flex-item) da un solo
   círculo, centrado con el texto de la fecha. */
.m3-semana-nav-flecha:hover{border-color:var(--morado)}
.m3-semana-nav-flecha svg.icon{width:14px;height:14px}
.m3-semana-nav-texto{font-size:13.5px;font-weight:600;color:var(--morado);white-space:nowrap}
.m3-select-servicios{display:inline-block;width:auto;min-width:170px;flex:none;font-size:13px;padding:8px 12px;margin-left:var(--sp-4)}

/* Calendario semanal: filas armadas con flexbox, no CSS Grid anidado.
   Motivo (TRASPASO-UX.md §4.2): un display:grid dentro de la celda de OTRO
   grid (.grid-2-1 > .col > .card) colapsa su ancho en este motor cuando
   además mezcla filas de altura variable. Aquí cada .m3-hora-fila tiene
   altura fija e idéntica (con o sin bloque adentro), así que ni siquiera
   entra en el escenario de riesgo — pero se usa flex de todos modos, ya
   verificado en el resto del archivo (.form-grid, etc). */
.m3-semana{display:flex;flex-direction:column}
.m3-semana-fila{display:flex;align-items:stretch}
.m3-semana-hora-col{width:44px;flex:none}
.m3-semana-dia-col{flex:1 1 0;min-width:0}
.m3-semana-head{padding-bottom:8px;margin-bottom:2px;border-bottom:1px solid var(--gris-borde)}
.m3-dia-cabeza{display:flex;flex-direction:column;align-items:center;gap:4px}
.m3-dia-nombre{font-size:10px;font-weight:600;text-transform:uppercase;color:var(--texto-suave)}
.m3-dia-num{
  width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;color:var(--morado);
}
.m3-dia-num.hoy{background:var(--morado);color:var(--blanco)}

/* ENCIMADOS: cada bloque pedía height:100% de un renglón de 38 px fijos,
   así que dos citas en la misma hora se montaban una sobre otra y se salían
   al renglón de abajo. El renglón pasa a tener alto MÍNIMO y la celda se
   vuelve una columna: dos citas se reparten el espacio y el renglón crece
   lo necesario. Es la corrección que ya se había hecho en PMedic. */
.m3-hora-fila{min-height:38px;border-top:1px solid var(--gris-borde)}
/* La hora va EN MEDIO de su renglón, no montada sobre la línea de arriba:
   el translateY(-6px) la subía justo encima del borde. */
.m3-hora-label{
  height:100%;display:flex;align-items:center;justify-content:flex-end;
  padding-right:8px;font-size:10.5px;color:var(--texto-suave);line-height:1;
}
.m3-dia-celda{min-height:38px;padding:2px;border-left:1px solid var(--gris-borde);
  display:flex;flex-direction:column;gap:2px}

.m3-bloque{
  min-height:32px;width:100%;flex:1 1 auto;border-radius:5px;padding:3px 6px;
  overflow:hidden;cursor:pointer;color:var(--morado);box-sizing:border-box;
}
.m3-bloque b{display:block;font-size:10.5px;font-weight:700;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.m3-bloque span{display:block;font-size:9px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.m3-bloque:hover{opacity:.85}
.m3-bloque.activo{outline:2px solid var(--morado);outline-offset:1px}

/* Seis tipos de servicio — Decisión B del CMO (22-sep-2026): dentro de la
   paleta cerrada, sin azul/lila/rosa/gris de la referencia. */
.m3-tipo-guarderia{background:var(--amarillo)}
.m3-tipo-grooming{background:rgba(254,200,0,.15);border:1px solid rgba(254,200,0,.5)}
.m3-tipo-paseo{background:var(--verde)}
.m3-tipo-entrenamiento{background:rgba(151,209,10,.15);border:1px solid rgba(151,209,10,.5)}
.m3-tipo-consulta{background:var(--morado);color:var(--blanco)}
.m3-tipo-otro{background:var(--gris-borde);border:1px solid rgba(107,107,107,.3)}

.m3-leyenda-barra{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
  margin-top:var(--sp-4);padding-top:var(--sp-3);border-top:1px solid var(--gris-borde)}
.m3-leyenda-barra .tit{font-size:11px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--texto-suave);font-weight:700}
.m3-leyenda-barra .acciones{margin-left:auto;display:flex;gap:var(--sp-2)}
.m3-leyenda .dur{margin-left:5px;color:var(--texto-suave);opacity:.75;font-size:11px}
/* Editor de la leyenda: color, nombre, duración y precio de cada servicio */
.lg-fila{display:flex;align-items:center;gap:var(--sp-2);padding:9px 0;flex-wrap:wrap;
  border-bottom:1px solid var(--gris-borde)}
.lg-fila:last-child{border-bottom:0}
.lg-fila.nueva{background:var(--gris-piedra);border-radius:10px;padding:10px;border-bottom:0;
  margin-top:var(--sp-2)}
.lg-color{width:34px;height:34px;flex:none;padding:0;border:1px solid var(--gris-borde);
  border-radius:9px;background:none;cursor:pointer}
.lg-nombre{flex:1 1 150px;min-width:0}
.lg-dur,.lg-precio{flex:0 0 86px}
.lg-staff{flex:1 1 150px;min-width:0}
.lg-quitar{flex:none;width:30px;height:30px;border-radius:8px;border:1px solid var(--gris-borde);
  background:var(--blanco);color:var(--texto-suave);font:inherit;cursor:pointer;line-height:1}
.lg-quitar:hover{border-color:var(--rojo);color:var(--rojo)}
.lg-pie{display:flex;justify-content:flex-start;margin-top:var(--sp-3)}
.lg-seccion{font-size:11px;letter-spacing:.05em;text-transform:uppercase;font-weight:700;
  color:var(--morado);padding-bottom:6px;margin-bottom:var(--sp-3);
  border-bottom:1px solid var(--gris-borde)}
#modal-leyenda .lg-seccion + .campo-ayuda{margin-top:0}
#modal-leyenda .modal-body > .lg-seccion ~ .lg-seccion{margin-top:var(--sp-5)}
.lg-cab{display:flex;gap:var(--sp-2);padding-bottom:6px;font-size:11px;letter-spacing:.04em;
  text-transform:uppercase;color:var(--texto-suave)}
.lg-cab span:nth-child(1){flex:none;width:34px}
.lg-cab span:nth-child(2){flex:1 1 150px}
.lg-cab span:nth-child(3),.lg-cab span:nth-child(4){flex:0 0 86px}
.lg-cab span:nth-child(5){flex:1 1 150px}
.m3-leyenda{display:flex;gap:var(--sp-4);flex-wrap:wrap;margin-top:var(--sp-4);font-size:12px;color:var(--texto-suave)}
.m3-leyenda .item{display:flex;align-items:center;gap:6px;white-space:nowrap}
/* nowrap por entrada: si no cabe, toda la fila hace wrap como conjunto
   (m3-leyenda ya tiene flex-wrap:wrap) en vez de partir "Paseo grupal" o
   "Consulta veterinaria" a la mitad de una palabra. */
.m3-leyenda .sw{width:11px;height:11px;border-radius:3px;flex:none;box-sizing:border-box}

/* Panel de detalle */
.m3-detalle{position:relative;display:flex;flex-direction:column;min-height:560px}
.m3-detalle .m3-det-panel{flex:1 1 auto}
.m3-detalle .campo-fila{flex:0 0 auto}
.m3-cerrar{
  position:absolute;top:var(--sp-4);right:var(--sp-4);width:24px;height:24px;flex:none;
  display:inline-flex;align-items:center;justify-content:center;border-radius:50%;color:var(--texto-suave);
}
.m3-cerrar:hover{background:var(--gris-piedra);color:var(--morado)}
.m3-cerrar svg.icon{width:14px;height:14px}
.m3-detalle-header{display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-4);padding-right:var(--sp-6)}
.m3-detalle-avatar,.m3-detalle-avatar-ini{
  width:60px;height:60px;border-radius:50%;flex:none;
  border:3px solid var(--blanco);box-shadow:var(--sombra-card);
}
.m3-detalle-avatar{object-fit:cover}
.m3-detalle-avatar-ini{display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:var(--morado)}
.m3-detalle-id .tipo-h2{font-size:16px}
.m3-detalle-id .chip{margin-top:6px}
.m3-detalle-tabs{margin-bottom:var(--sp-3);flex-wrap:nowrap}
/* Variante angosta: 4 pestañas (Detalles/Cliente/Historial/Notas) en el panel
   de detalle de M3, que es más angosto que otros paneles con .tabs. Dos
   causas, aisladas por separado con pruebas mínimas:
   1. Con el padding/margen genérico de .tab no caben en una fila y "Notas"
      se parte a un segundo renglón — se reduce SOLO aquí (no se toca .tab
      global, que sigue sirviendo a M1/M2/etc.) el padding horizontal y el
      margen entre pestañas; tipografía y color intactos.
   2. Aun con las 4 cabiendo de sobra en el ancho real del panel (~377px de
      contenido, y las 4 pestañas miden ~316px con este padding — 60px de
      margen), .tabs hereda flex-wrap:wrap del sistema y el motor de
      verificación (WeasyPrint 67.0) fuerza igual un wrap del 4° elemento en
      este contexto de grid-item — reproducido en aislado, desaparece con
      flex-wrap:nowrap. Con las 4 pestañas fijas y cortas de este panel
      nowrap es además el comportamiento correcto (nunca deben partirse). */
.m3-detalle-tabs .tab{padding:10px 2px;margin-right:10px}
.m3-detalle-acciones{display:flex;gap:8px;margin-top:var(--sp-4);flex-wrap:wrap}
.m3-detalle-acciones .btn{flex:1 1 auto;justify-content:center;padding:9px 8px;font-size:12.5px}
.btn-riesgo{background:transparent;border-color:var(--rojo);color:var(--rojo)}
.btn-riesgo:hover{background:rgba(179,38,30,.06)}
.m3-oculto{display:none}

/* Próximos servicios de hoy — fila con avatar mini de iniciales */
.m3-hoy-fila{display:flex;align-items:center;gap:var(--sp-3);padding:9px 0}
.m3-hoy-fila + .m3-hoy-fila{border-top:1px solid var(--gris-borde)}
.m3-hoy-hora{font-size:12px;color:var(--texto-suave);flex:none;width:44px}
.m3-avatar-mini{
  width:32px;height:32px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:var(--morado);
}
/* Sus tres tintes. La fila de «Próximos servicios de hoy» los pide por clase
   —`'m3-avatar-mini ' + (d.tinte || 'tinte-verde')`— y aquí no había ninguno
   declarado: el círculo salía transparente y las iniciales flotaban sobre el
   fondo de la tarjeta. Tercer avatar con el mismo agujero; mismos valores que
   `.m4-avatar-mini`, que es el único que los tenía los tres. */
.m3-avatar-mini.tinte-verde{background:rgba(151,209,10,.20)}
.m3-avatar-mini.tinte-amarillo{background:rgba(254,200,0,.20)}
.m3-avatar-mini.tinte-morado{background:rgba(43,23,52,.16)}
.m3-hoy-texto{flex:1;min-width:0}
.m3-hoy-texto b{display:block;font-size:13.5px;color:var(--morado);font-weight:600}
.m3-hoy-texto span{font-size:12px;color:var(--texto-suave)}

/* Lista de espera: table-layout fijo para que las columnas nunca empujen
   la tarjeta más allá de su ancho (la tabla base es table-layout:auto y
   el botón de acción la desbordaba en tarjetas angostas de grid-3). */
.m3-tabla-espera{table-layout:fixed}
.m3-tabla-espera th:nth-child(1),.m3-tabla-espera td:nth-child(1):not([colspan]){width:15%}
.m3-tabla-espera th:nth-child(2),.m3-tabla-espera td:nth-child(2){width:30%}
.m3-tabla-espera th:nth-child(3),.m3-tabla-espera td:nth-child(3){width:16%}
.m3-tabla-espera th:nth-child(4),.m3-tabla-espera td:nth-child(4){width:19%}
.m3-tabla-espera th:nth-child(5),.m3-tabla-espera td:nth-child(5){width:20%}
/* Nombres de mascota: siempre cortos y de una sola palabra — se fuerza una
   sola línea para que no se partan tipo "Rock/y" (feo e innecesario). */
.m3-tabla-espera td:nth-child(1):not([colspan]){white-space:nowrap}
/* Y el `:not([colspan])` de las dos reglas de arriba es lo que deja respirar
   al renglon de «no hay nada»: ese td cruza las cinco columnas y, por ser
   tambien :nth-child(1), heredaba el 15% de ancho y el nowrap de la columna
   de nombres. La frase salia cortada por la derecha — el mismo defecto de
   texto cortado de siempre, esta vez metido por el aviso que explica que la
   lista de espera no existe. Una celda que cruza la tabla es una frase, no un
   valor de columna. */
.m3-tabla-espera td[colspan]{white-space:normal;width:auto;text-align:left}
/* table-layout:fixed sí respeta estos % (los bordes de columna caen donde
   deben), pero por default una palabra sin espacio (p. ej. "MASCOTA",
   "Hospedaje") no tiene dónde partir y se derrama visualmente sobre la
   columna vecina en vez de ajustarse — overflow-wrap:break-word en th Y td
   es lo que lo evita, no solo el ancho de columna. */
.m3-tabla-espera thead th{font-size:8.5px;letter-spacing:0;overflow-wrap:break-word;padding-right:2px}
/* ".tabla tbody td" (base, sección 10) tiene más especificidad que un simple
   ".m3-tabla-espera td" (clase+elemento vs clase+elemento+elemento) — por
   eso el override tenía que repetir "tbody" para ganar el mismo nivel y
   luego ganar por orden de aparición (ya verificado con el render). */
.m3-tabla-espera tbody td{font-size:11px;line-height:1.35;padding-right:4px;overflow-wrap:break-word}
.m3-tabla-espera tbody td:last-child{padding-right:0}
.m3-tabla-espera .btn{padding:6px 4px;font-size:10.5px;white-space:normal;text-align:center;width:100%}
/* =====================================================================
   37. MÓDULO 4 — CONTROL DE ASISTENCIA (específico)
   ===================================================================== */
/* Fila de controles (chips de filtro + buscador + botón de filtro +
   "Registrar entrada"): flexbox, no grid, y todo lo "clicable" es
   <span role="button"> — nunca <button> como hijo directo de un
   contenedor flex (bug documentado en TRASPASO-UX.md §4.3). */
.m4-controles{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--sp-3)}
.m4-btn-filtro{padding:10px 12px}
/* .filtros (línea 316) es compartida y otros módulos sí necesitan que
   envuelva internamente; aquí vive anidada como UN solo hijo flex de
   .m4-controles (que también es flex-wrap:wrap) junto al buscador/botón de
   filtro/CTA — sin esto, a ancho de laptop (~1440px) el 4° pill ("Salidas
   hoy") se partía solo a una 2ª línea mientras sus hermanos se quedaban
   arriba (verificado con render aislado). Regla más específica, no toca la
   base: los 4 pills nunca se parten entre sí; si algún día no cupiera nada,
   es .m4-controles quien decide bajar el bloque completo, no .filtros por
   su cuenta. El buscador (línea 325, max-width:320px compartido con
   M1/M2/M8) se acota más aquí para dejar espacio real en la fila.*/
.m4-controles .filtros{flex-wrap:nowrap}
/* flex-wrap:nowrap por sí solo no basta: sin límite de encogimiento, cada
   pill se angosta hasta partir su propia etiqueta a 2 líneas ("En\nestancia")
   en vez de mantenerse como cápsula de una sola línea (visto en render a
   1440px). flex:none + white-space:nowrap fija el ancho natural de cada
   pill; si el bloque completo no cabe, es .m4-controles (flex-wrap:wrap)
   quien baja TODO .filtros a una 2ª línea, nunca un pill suelto. */
.m4-controles .filtro-chip{white-space:nowrap;flex:none}
.m4-controles .buscador{max-width:240px}
/* Alturas de caja desiguales en la fila (pills ~31px vs buscador ~40px vs
   botones ~42px, por padding/font-size distintos de cada componente base) --
   align-items:center centra cada caja pero no las iguala. Se sube el
   padding vertical del pill SOLO aqui (no toca .filtro-chip base, que
   sirve a M1/M8/etc. con su propia altura) hasta emparejar la altura real
   de .buscador/.btn, medido con PIL. */
.m4-controles .filtro-chip{padding:11px 16px}

/* Avatar circular mini (32px) para la columna Mascota de la tabla ancha —
   mismo criterio visual que .m1-mascota-avatar/.m3-avatar-mini, pero con
   las 3 variantes de tinte que esta pantalla necesita (M3 sólo declara 2). */
.m4-mascota-cell{display:flex;align-items:center;gap:8px}
.m4-mascota-foto-mini{width:32px;height:32px;border-radius:50%;object-fit:cover;flex:none}
.m4-avatar-mini{
  width:32px;height:32px;border-radius:50%;flex:none;
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:var(--morado);
}
.m4-avatar-mini.tinte-verde{background:rgba(151,209,10,.20)}
.m4-avatar-mini.tinte-amarillo{background:rgba(254,200,0,.20)}
.m4-avatar-mini.tinte-morado{background:rgba(43,23,52,.16)}

/* Tabla ancha "Entradas y salidas de hoy": 7 columnas de texto + 1 columna
   de sólo-ícono con avatar en la 2ª columna — exactamente el patrón que
   TRASPASO-UX.md marca como propenso a desalinear encabezado/filas o partir
   texto a 2 líneas en WeasyPrint. Mismo remedio ya verificado en
   .m3-tabla-espera: table-layout:fixed + % explícito por columna +
   overflow-wrap:break-word en thead (por si una palabra larga no cupiera) +
   white-space:nowrap en tbody (los valores de esta tabla son siempre cortos
   y de una sola palabra/hora, no deben partirse nunca). */
.m4-tabla-asistencia{table-layout:fixed}
/* Aqui vivia un segundo juego de anchos para .m4-tabla-asistencia, de cuando
   la tabla tenia 8 columnas. El bloque de mas abajo le ganaba por orden,
   asi que no hacia nada salvo esperar a que alguien reordenara la hoja. */
.m4-tabla-asistencia thead th{overflow-wrap:break-word;padding-right:2px}
.m4-tabla-asistencia tbody td{overflow-wrap:break-word;white-space:nowrap}
.m4-tabla-asistencia tbody td:last-child{padding-right:0;white-space:normal;text-align:right}

/* Ocupación en tiempo real: ícono + etiqueta + barra + fracción + %.
   Fila propia en flexbox (no reutiliza el grid interno de .barra-h-fila,
   que sólo trae espacio para un número final, no para "12/20" + "60%") —
   sí reutiliza .barra-h-pista/.barra-h-valor tal cual para la barra. */
.m4-ocup-fila{display:flex;align-items:center;gap:10px;padding:6px 0}
.m4-ocup-icono{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;color:var(--morado)}
.m4-ocup-label{font-size:13px;color:var(--morado);width:82px;flex:none}
.m4-ocup-frac{font-size:12.5px;color:var(--texto-suave);width:48px;text-align:right;flex:none;font-variant-numeric:tabular-nums}
.m4-ocup-pct{font-size:13px;font-weight:700;color:var(--morado);width:38px;text-align:right;flex:none;font-variant-numeric:tabular-nums}

/* Recordatorios y alertas: mismo look que .actividad-fila (M0) pero con
   botón de editar al final — se declara aparte en vez de extender la clase
   compartida para no arriesgar el render ya verificado de M0. */
.m4-recordatorio-fila{display:flex;align-items:center;gap:var(--sp-3);padding:10px 0}
.m4-recordatorio-fila+.m4-recordatorio-fila{border-top:1px solid var(--gris-borde)}
.m4-recordatorio-fila .icon-badge{margin-bottom:0;width:36px;height:36px}
.m4-recordatorio-fila .icon-badge svg.icon{width:18px;height:18px;stroke-width:2.1}
.m4-recordatorio-fila .hora{font-size:13px;font-weight:700;color:var(--morado);width:44px;flex:none;font-variant-numeric:tabular-nums}
.m4-recordatorio-texto{flex:1;min-width:0}
.m4-recordatorio-texto b{display:block;font-size:14px;color:var(--morado);font-weight:600}
.m4-recordatorio-texto span{font-size:12.5px;color:var(--texto-suave)}

/* Perritos en estancia: NO reutiliza .m1-mascota-card tal cual — esa clase
   trae min-width:110px pensado para una fila ancha de 4 columnas (como en
   M1); aquí vive en la columna angosta de .grid-2-1, así que con 4 tarjetas
   de 110px mínimo el 4° elemento no cabía, se iba a su propia línea y, al
   quedar solo con flex-grow:1, se estiraba a todo el ancho de la tarjeta
   (verificado en render aislado). Fila propia sin min-width grande, más
   una altura de avatar reducida (por selector descendiente, sin tocar la
   regla base de .m1-mascota-foto/.m1-mascota-avatar que usa M1). */
.m4-estancia-fila{display:flex;gap:10px}
.m4-estancia-item{flex:1;min-width:0;text-align:center}
.m4-estancia-item .m1-mascota-foto,.m4-estancia-item .m1-mascota-avatar{height:68px;margin-bottom:6px;font-size:15px}
.m4-estancia-item .m1-mascota-nombre{font-size:12.5px}

/* =====================================================================
   38. MÓDULO 5 — GESTIÓN DE INCIDENCIAS (específico)
   ===================================================================== */
/* Encabezado con CTA: mismo patrón que .m3-encabezado — el botón "Registrar
   incidencia" vive pegado al modulo-header (no dentro de la fila de
   filtros), header con margin-bottom:0. Clase propia, se copia el patrón,
   no se reutiliza .m3-encabezado tal cual. */
.m5-encabezado{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);flex-wrap:wrap;margin-bottom:var(--sp-4)}
/* Fila de controles (3 pills de tipo + selector de periodo + buscador):
   mismo remedio ya verificado en M4 (TRASPASO-UX.md, bug de flex
   anidado con white-space:nowrap) — flex, no grid, y flex-wrap:nowrap en
   los pills desde el inicio, para que si algo no cabe sea .m5-controles
   quien baje TODO el bloque a una 2ª línea, nunca un pill suelto. Clases
   propias (no se reutiliza .m3- / .m4- tal cual, se copia el patrón). */
.m5-controles{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--sp-3)}
.m5-controles .filtros{flex-wrap:nowrap}
.m5-controles .filtro-chip{white-space:nowrap;flex:none}
.m5-controles .buscador{max-width:240px}
.m5-select-periodo{display:inline-block;width:auto;min-width:140px;flex:none;font-size:13px;padding:8px 12px}

/* Tabla ancha "Incidencias recientes" (7 columnas + avatar en la 2ª): mismo
   remedio ya verificado en .m3-tabla-espera/.m4-tabla-asistencia —
   table-layout:fixed + % explícito por columna + overflow-wrap:break-word,
   para que encabezado y filas queden alineados y DESCRIPCIÓN (la columna
   más larga) nunca rompa el layout, solo su propio texto. */
.m5-tabla-incidencias{table-layout:fixed}
.m5-tabla-incidencias th:nth-child(1),.m5-tabla-incidencias td:nth-child(1){width:7%}
.m5-tabla-incidencias th:nth-child(2),.m5-tabla-incidencias td:nth-child(2){width:13%}
.m5-tabla-incidencias th:nth-child(3),.m5-tabla-incidencias td:nth-child(3){width:10%}
.m5-tabla-incidencias th:nth-child(4),.m5-tabla-incidencias td:nth-child(4){width:21%}
.m5-tabla-incidencias th:nth-child(5),.m5-tabla-incidencias td:nth-child(5){width:16%}
.m5-tabla-incidencias th:nth-child(6),.m5-tabla-incidencias td:nth-child(6){width:13%}
.m5-tabla-incidencias th:nth-child(7),.m5-tabla-incidencias td:nth-child(7){width:20%}
.m5-tabla-incidencias thead th{overflow-wrap:break-word;padding-right:2px}
.m5-tabla-incidencias tbody td{overflow-wrap:break-word}
/* SEVERIDAD/ESTADO son chips de texto largo ("En seguimiento") dentro de
   columnas angostas — .chip tiene white-space:nowrap (sección 9, base
   compartida), así que overflow-wrap en la celda no basta para evitar que
   el pill se desborde de su columna (verificado en render aislado). Se
   reduce SOLO aquí el tamaño del chip, no la clase base .chip. */
.m5-tabla-incidencias .chip{font-size:11px;padding:4px 8px;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.m5-fila.activo td{background:var(--gris-piedra)}

/* Panel de detalle — mismo patrón que .m3-detalle (crece a la altura de la
   columna vía .grid-2-1{align-items:stretch}, ya usado por M3/M4, no se
   toca la regla base). Absorbe la función de "Incidencias por tipo": no es
   una tarjeta aparte. */
.m5-detalle{position:relative}
.m5-detalle .campo-fila{padding:7px 0}
.m5-detalle-header{display:flex;align-items:flex-start;gap:var(--sp-3);margin-bottom:var(--sp-3)}
.m5-detalle-chip{position:absolute;top:var(--sp-5);right:var(--sp-5);flex:none}
.m5-detalle-avatar,.m5-detalle-avatar-ini{
  width:56px;height:56px;border-radius:50%;flex:none;
  border:3px solid var(--blanco);box-shadow:var(--sombra-card);
}
.m5-detalle-avatar{object-fit:cover}
.m5-detalle-avatar-ini{display:flex;align-items:center;justify-content:center;font-size:17px;font-weight:700;color:var(--morado)}
.m5-detalle-id{flex:1;min-width:0}
/* padding-right SOLO en el nombre (1ª línea), no en todo el bloque: el chip
   absoluto solo ocupa el alto de esa línea — reservar el espacio en el
   contenedor completo apretaba también raza/familia en líneas de abajo sin
   necesidad (verificado en render aislado). */
.m5-detalle-id .tipo-h2{font-size:16px;padding-right:112px}
/* Evidencia: fila de marcadores FUERA del flex icono+etiqueta+valor de
   .campo-fila (no anidada como "valor"), para que reciba el ancho completo
   de la tarjeta en vez de competir por espacio dentro de esa fila — con el
   patrón anidado los 3 marcadores se apilaban uno por línea en vez de ir
   lado a lado (verificado en render aislado), inflando la altura del panel
   más de lo necesario. */
/* display:block, NO flex: .evidencia-marcador ya es inline-flex por su cuenta
   (sección 21) — dejarlos fluir como cajas inline dentro de un bloque normal
   evita el motor de flex-wrap por completo. Con flex-wrap:wrap en el
   contenedor los 3 marcadores se apilaban uno por línea con un borde
   duplicado (fragmentación de caja de WeasyPrint, mismo síntoma que el bug
   de los botones de acciones) en vez de ir lado a lado — reproducido y
   confirmado en render aislado. margin en vez de gap: gap no aplica sin
   contenedor flex/grid. */
/* flex-wrap:nowrap, no wrap ni display:block/inline-block: .evidencia-marcador
   (inline-flex, base compartida) SÍ alinea bien ícono+texto adentro, pero en
   este motor no fluye como texto normal junto a sus hermanos (probado:
   inline-block también los apilaba, con el ícono roto a su propia línea
   dentro del marcador). Y flex-wrap:wrap en el padre re-produce el mismo bug
   de fragmentación de caja que ya se vio en .m5-detalle-acciones (borde
   duplicado, un marcador por línea). Con solo 3 marcadores cortos, caben de
   sobra en una sola fila sin envolver — mismo remedio que los botones de
   acciones: flex + nowrap. */
/* float, NO flex: flex-wrap:wrap fragmentaba la caja (borde duplicado) y
   flex-wrap:nowrap encogía los marcadores por debajo de su contenido (el
   texto se partía "1" / "foto" en 2 líneas dentro de su propia caja) y aun
   así el conjunto se salía por el borde derecho de la tarjeta — la caja de
   flex de este motor no respeta flex:none/flex-shrink:0 en este contexto
   (verificado en 3 intentos distintos, todos aislados y confirmados con
   render). float:left es la técnica más básica de CSS, sin motor de flex
   de por medio, y sí coloca los 3 marcadores lado a lado sin encimarse. */
.m5-evidencia-fila{padding:0 0 9px 32px}
.m5-evidencia-fila::after{content:"";display:block;clear:both}
.m5-evidencia-fila .evidencia-marcador{float:left;margin:0 8px 8px 0}
/* flex-wrap:nowrap, no wrap: bug ya documentado en TRASPASO-UX.md #4.3 —
   un flex anidado (esta fila vive dentro de .m5-detalle, que a su vez vive
   estirado por .grid-2-1) con hijos white-space:nowrap (.btn, base
   compartida) y flex-wrap:wrap propio hace que WeasyPrint "parta" el 2º
   botón como huérfano fuera de la tarjeta en vez de ponerlo junto al 1º en
   la misma fila (reproducido y confirmado en render aislado). */
/* Envuelven: con nowrap los dos botones se salian 56 px de la tarjeta en
   cuanto la ventana bajaba de 1440. Medido 14-oct. */
.m5-detalle-acciones{display:flex;gap:8px;margin-top:var(--sp-3);flex-wrap:wrap}
.m5-detalle-acciones .btn{flex:1 1 auto;justify-content:center;padding:9px 8px;font-size:12.5px;white-space:nowrap}

.nav-item{white-space:nowrap}
.nav-item svg{flex:none}

/* 32. MÓDULO 6 — INVENTARIOS (específico)
   Pestañas de categoría: mismo .filtro-chip de siempre, con ícono — igual
   que .m5-controles, flex-wrap:wrap en el contenedor (no nowrap forzado,
   aquí SÍ queremos que las 8 pestañas envuelvan a 2 líneas si no caben,
   no que se corten ni se encimen con nada). */
/* Encabezado de M6 — causa raíz real, encontrada por aislamiento binario,
   no por la hipótesis original del coordinador (flex anidado): CUALQUIER
   .btn-secundario (borde+fondo transparente) que sea ITEM DIRECTO de un
   contenedor flex O grid, sin importar cuántos niveles ni qué tan simple
   el contenedor, sale con un borde fantasma duplicado en este motor —
   reproducido en aislamiento mínimo de una sola línea, y confirmado que
   YA le pasaba también a "Reabastecer" (.btn-secundario.btn-sm) dentro de
   .m2-servicio-fila, algo que nadie había notado porque nunca se hizo zoom
   suficiente — no es nuevo de esta ronda, es preexistente en todo el
   archivo. Además: envolver 2 botones juntos en un solo contenedor con
   ancho automático (flex O grid) subcalcula el ancho combinado (mide solo
   1 de los 2) y produce overflow fuera de la página — probado con
   inline-block, float, y grid con una sola celda "auto"; los tres fallan
   igual. Única combinación que resuelve AMBOS problemas a la vez: grid de
   3 columnas (1fr para el título, auto para cada botón) con CADA botón
   envuelto en su propio <div> plano (ni flex ni grid) que es el que
   participa como item del grid — el <div> absorbe el "ser item de layout"
   (así el motor no le duplica el borde a nada, porque un <div> sin borde
   no tiene borde que duplicar) y el grid mide cada columna auto por
   separado (1 botón por columna, no 2 juntos), evitando el subcálculo.
   No toca `.m5-encabezado` compartida (M3/M5) — este bloque ya no la usa. */
.m6-encabezado{display:grid;grid-template-columns:1fr auto auto;align-items:start;
  gap:var(--sp-4);margin-bottom:var(--sp-4)}
.m6-encabezado-boton{display:block}
.m6-tabs{gap:8px}
.m6-tabs .filtro-chip{gap:6px;white-space:nowrap}
.m6-tabs .filtro-chip svg.icon{width:14px;height:14px;flex:none}
/* Dos chips por renglón (Estado + caducidad) cuando el producto es
   Alimentos/Medicamentos con fecha próxima — flex simple de un solo nivel
   dentro de la celda, sin nowrap forzado, para que envuelva a 2 líneas
   antes que desbordar la columna. */
.m6-estado-cell{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
/* Mismo patrón de tabla angosta ya usado en .m3-tabla-espera/.m4-tabla-asistencia/
   .m5-tabla-incidencias/.m0-tabla-cobranza: table-layout fijo + % explícito
   por columna, para que "Croqueta cachorro 3kg" o "Ambientador neutralizante"
   no partan la columna Producto ni empujen el resto. */
.m6-tabla-inventario{table-layout:fixed}
.m6-tabla-inventario th:nth-child(1),.m6-tabla-inventario td:nth-child(1){width:30%}
.m6-tabla-inventario th:nth-child(2),.m6-tabla-inventario td:nth-child(2){width:19%}
.m6-tabla-inventario th:nth-child(3),.m6-tabla-inventario td:nth-child(3){width:14%}
.m6-tabla-inventario th:nth-child(4),.m6-tabla-inventario td:nth-child(4){width:14%}
.m6-tabla-inventario th:nth-child(5),.m6-tabla-inventario td:nth-child(5){width:23%}
.m6-tabla-inventario thead th{overflow-wrap:break-word}
.m6-tabla-movimientos{table-layout:fixed}
.m6-tabla-movimientos th:nth-child(1),.m6-tabla-movimientos td:nth-child(1){width:14%}
.m6-tabla-movimientos th:nth-child(2),.m6-tabla-movimientos td:nth-child(2){width:34%}
.m6-tabla-movimientos th:nth-child(3),.m6-tabla-movimientos td:nth-child(3){width:16%}
.m6-tabla-movimientos th:nth-child(4),.m6-tabla-movimientos td:nth-child(4){width:11%}
.m6-tabla-movimientos th:nth-child(5),.m6-tabla-movimientos td:nth-child(5){width:25%}
.m6-tabla-movimientos thead th{overflow-wrap:break-word}
/* Cinco movimientos a la vista; los demás están en "Ver más". Doce
   renglones estiraban la tarjeta muy por encima de su vecina. */
#m6-tabla-movimientos tbody tr:nth-child(n+6){display:none}
/* Las alertas son renglones de aviso, no tarjetas: más compactas para que
   las cuatro quepan sin estirar la fila. */
.m6-arriba .inc-fila{padding:7px 0}
.m6-arriba .inc-fila .inc-texto b{font-size:13px}
.m6-arriba .inc-fila .inc-texto span{font-size:11.5px}
.m6-arriba{align-items:stretch}
.m6-arriba > .card{display:flex;flex-direction:column;min-width:0}
/* Los chips de categoría viven DENTRO de la tarjeta, bajo el buscador: así
   dejan de flotar pegados a la tarjeta de arriba y se lee que filtran esta
   tabla y no otra cosa. */
.m6-tabs-dentro{margin:0 0 var(--sp-3)}

/* 33. MÓDULO 7 — VENTAS Y FACTURACIÓN (específico)
   "Ventas por servicio" reusa .barra-h-fila (ya usado en M0/M1) pero con
   una columna más (% además de monto) — modificador local, no toca la
   base de 3 columnas que usan M0/M1. */
.m7-barra-servicio{grid-template-columns:140px minmax(0,1fr) 40px 76px}
.m7-servicio-pct{font-size:12px;color:var(--texto-suave);text-align:right;font-variant-numeric:tabular-nums}
/* Gráfica "Ventas mensuales": envoltura eje+área en flex (nivel 1), el área
   es un bloque normal (position:relative, NO flex) que contiene .meses-grid
   (flex, nivel 2) — flex>bloque>flex, no flex anidado directo en flex, para
   no repetir el bug ya documentado de huérfanos en WeasyPrint. */
.m7-chart-wrap{display:flex;gap:10px;margin-top:4px}
.m7-chart-eje{display:flex;flex-direction:column;justify-content:space-between;height:150px;font-size:10px;color:var(--texto-suave);text-align:right;flex:none;padding-top:2px}
.m7-chart-area{position:relative;flex:1;min-width:0}
.m7-meta-linea{position:absolute;left:0;right:0;border-top:1.5px dashed var(--gris-borde)}
.m7-meses-grid{position:relative}
.m7-meses-grid .mes-valor{white-space:nowrap}
.m7-chart-leyenda{display:flex;gap:16px;margin-top:14px;font-size:12px;color:var(--texto-suave)}
.m7-leyenda-item{display:inline-flex;align-items:center;gap:6px}
.m7-leyenda-punto{width:8px;height:8px;border-radius:50%;flex:none}
.m7-leyenda-linea{width:16px;border-top:1.5px dashed var(--texto-suave);flex:none}
.m7-nota-verde{display:flex;align-items:center;gap:8px;margin-top:var(--sp-3);padding:10px 12px;
  background:rgba(151,209,10,.12);border-radius:var(--r-md);font-size:12.5px;color:var(--morado)}
.m7-nota-verde svg.icon{width:16px;height:16px;color:var(--verde);flex:none}
.m7-nota-verde b{color:var(--verde)}
.m7-rank-badge{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;color:var(--morado);flex:none}
/* .icon-badge.tinte-* está definido, no .m7-rank-badge.tinte-* — se
   confirmó con render que sin esto el círculo queda sin fondo (bug
   encontrado y corregido antes de reportar). */
.m7-rank-badge.tinte-amarillo{background:rgba(254,200,0,.20)}
.m7-rank-badge.tinte-verde{background:rgba(151,209,10,.20)}
.m7-rank-badge.tinte-morado{background:rgba(43,23,52,.16)}

/* --- Dashboard: correcciones de alineación (01-oct-2026) ---
   Los KPI tenían estructuras distintas -- unos con barra de ocupación, otros
   con delta -- así que sus pies quedaban a distinta altura. Se convierten en
   columna flexible y el último renglón se empuja al fondo: así los cuatro
   cierran parejo sin tocar su contenido. */
.grid-kpi4{align-items:stretch}
.grid-kpi4 > .kpi{display:flex;flex-direction:column;justify-content:space-between;height:100%}
.grid-kpi4 > .kpi > .icon-badge{margin-bottom:var(--sp-3)}
.grid-kpi4 > .kpi > .tipo-dato{margin-top:0}
/* el bloque de cierre -- delta o nota de ocupación -- queda pegado al fondo
   sin depender de qué clase use cada tarjeta */
.grid-kpi4 > .kpi > :last-child{margin-top:var(--sp-3)}

/* Mismo criterio para la fila de tres tarjetas: estiran igual y su nota de
   pie se va al fondo, para que los bordes inferiores coincidan. */
.grid-3 > .card{display:flex;flex-direction:column}
.grid-3 > .card > .nota-pie,
.grid-3 > .card > .suave:last-child{margin-top:auto;padding-top:var(--sp-3)}
.grid-3 > .card > .tabla-env,
.grid-3 > .card > .barra-h{flex:1 1 auto}

/* lista de todos los servicios bajo los anillos */
.ocup-todos{margin-top:var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--gris-borde)}
.ocup-todos .et{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);margin-bottom:var(--sp-3)}
.ocup-fila{display:grid;grid-template-columns:minmax(0,1fr) 46px;align-items:center;gap:var(--sp-3);margin-bottom:9px}
.ocup-fila:last-child{margin-bottom:0}
.ocup-nom{font-size:12.5px;color:var(--morado)}
.ocup-pct{font-size:12.5px;font-weight:700;text-align:right;font-variant-numeric:tabular-nums}
.ocup-pista{height:6px;background:#EFEBE4;border-radius:3px;overflow:hidden;margin-top:4px}
.ocup-relleno{height:100%;border-radius:3px;background:var(--verde);transition:width .4s ease}
.ocup-relleno.medio{background:var(--amarillo)}
.ocup-relleno.bajo{background:#C9A227}

/* la meta, ahora editable */
.meta-link{background:none;border:none;padding:0;font:inherit;color:var(--real,#223382);
  cursor:pointer;text-decoration:underline;text-underline-offset:2px;text-decoration-style:dotted}
.meta-link:hover{color:var(--morado)}
.meta-ref{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--sp-2);
  padding:9px 0;border-bottom:1px solid var(--gris-borde);font-size:13px}
.meta-ref:last-child{border-bottom:none}
.meta-ref b{font-variant-numeric:tabular-nums}
.meta-nota{background:#FFF9EC;border-left:3px solid var(--amarillo);border-radius:6px;
  padding:11px 14px;font-size:12.5px;line-height:1.5;margin-top:var(--sp-4)}

.modal-pie{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--gris-borde)}
.btn-pri{padding:9px 16px;border-radius:var(--r-md);border:1px solid var(--morado);
  background:var(--morado);color:#fff;font-size:13px;font-weight:600;cursor:pointer}
.btn-sec{padding:9px 16px;border-radius:var(--r-md);border:1px solid var(--gris-borde);
  background:#fff;color:var(--morado);font-size:13px;font-weight:600;cursor:pointer}
.modal-body .campo-form{margin-bottom:14px}
.modal-body .campo-form label{display:block;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--texto-suave);margin-bottom:6px}
.modal-body .input,.modal-body .select{width:100%;padding:9px 12px;border:1px solid var(--gris-borde);
  border-radius:var(--r-md);font-size:13.5px;font-family:inherit;color:var(--morado);background:#fff}

.btn-vermas{display:flex;align-items:center;justify-content:center;gap:7px;width:100%;
  padding:10px 14px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  background:#fff;color:var(--morado);font-size:13px;font-weight:600;font-family:inherit;cursor:pointer}
.btn-vermas:hover{border-color:var(--amarillo);background:#FFFBF0}
.btn-vermas svg.icon{width:15px;height:15px;color:var(--texto-suave)}
.modal-ancho{max-width:860px;width:94vw}
.anillo-grid-todos{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:var(--sp-4) var(--sp-3)}
@media(max-width:860px){.anillo-grid-todos{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:560px){.anillo-grid-todos{grid-template-columns:repeat(2,minmax(0,1fr))}}
.anillo-grid-todos .anillo{width:84px;height:84px}
.anillo-grid-todos .servicio{font-size:12.5px}

.ocup-barra{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);
  flex-wrap:wrap;margin-bottom:var(--sp-5)}
.btn-editar-cupos{display:inline-flex;align-items:center;gap:6px;padding:8px 14px;
  border:1px solid var(--gris-borde);border-radius:var(--r-md);background:#fff;
  color:var(--morado);font-size:12.5px;font-weight:600;font-family:inherit;cursor:pointer}
.btn-editar-cupos:hover{border-color:var(--amarillo);background:#FFFBF0}
.btn-editar-cupos svg.icon{width:14px;height:14px}
.ocup-pie{margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--gris-borde);font-size:12.5px}
.cupo-fila{display:grid;grid-template-columns:minmax(0,1fr) 92px 74px;align-items:center;
  gap:var(--sp-3);padding:9px 0;border-bottom:1px solid var(--gris-borde)}
.cupo-fila:last-child{border-bottom:none}
.cupo-nom{font-size:13.5px;font-weight:500;color:var(--morado)}
.cupo-fila input{width:100%;padding:7px 10px;border:1px solid var(--gris-borde);border-radius:var(--r-sm);
  font-size:13px;font-family:inherit;text-align:right;color:var(--morado);background:#fff}
.cupo-fila input:focus{outline:none;border-color:var(--amarillo);box-shadow:0 0 0 3px rgba(254,200,0,.22)}
.cupo-ocupado{font-size:12px;color:var(--texto-suave);text-align:right;font-variant-numeric:tabular-nums}
.cupo-cab{display:grid;grid-template-columns:minmax(0,1fr) 92px 74px;gap:var(--sp-3);
  font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);padding-bottom:8px;border-bottom:1px solid var(--gris-borde)}
.cupo-cab span:not(:first-child){text-align:right}

.saludo .nuevos-mes{margin-top:6px;color:var(--morado);font-weight:500}
.saludo .nuevos-mes b{font-weight:700}
.saludo .nuevos-mes.recien{animation:destello 1.4s ease}
@keyframes destello{0%{background:rgba(254,200,0,.45)}100%{background:transparent}}
@media(prefers-reduced-motion:reduce){.saludo .nuevos-mes.recien{animation:none}}

/* Un modal que se abre desde otro modal necesita capa propia: con el mismo
   z-index gana el que esté después en el documento, y el de cupos está antes
   que el de ocupación. */
.modal-backdrop.modal-encima{z-index:320;background:rgba(43,23,52,.55)}
.modal-backdrop.modal-encima .modal-caja{box-shadow:0 18px 44px rgba(0,0,0,.28)}

/* --- Incidencias por mascota, en el Estado del cliente --- */
.m1-inc-bloque{margin:var(--sp-4) 0 var(--sp-4);padding-top:var(--sp-4);border-top:1px solid var(--gris-borde)}
.m1-inc-cab{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--sp-3)}
.m1-inc-cab .et{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--texto-suave)}
.m1-inc-vermas{background:none;border:none;padding:0;font-size:12px;font-weight:600;
  color:var(--amarillo-texto);cursor:pointer;font-family:inherit}
.m1-inc-vermas:hover{text-decoration:underline}
.m1-inc-anillos{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp-3)}
.m1-inc-anillos.grande{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp-4)}
@media(max-width:700px){.m1-inc-anillos.grande{grid-template-columns:repeat(2,minmax(0,1fr))}}
.m1-inc-item{display:flex;flex-direction:column;align-items:center;text-align:center;gap:4px}
.m1-inc-dona{position:relative;width:62px;height:62px}
.m1-inc-anillos.grande .m1-inc-dona{width:86px;height:86px}
.m1-inc-dona svg{width:100%;height:100%;transform:rotate(-90deg)}
.m1-inc-dona .centro{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;color:var(--morado)}
.m1-inc-anillos.grande .m1-inc-dona .centro{font-size:17px}
.m1-inc-nom{font-size:12px;font-weight:600;color:var(--morado);line-height:1.2}
.m1-inc-sub{font-size:10.5px;color:var(--texto-suave);line-height:1.25}
.m1-inc-leyenda{display:flex;gap:var(--sp-3);margin-top:var(--sp-3);flex-wrap:wrap;
  font-size:10.5px;color:var(--texto-suave)}
.m1-inc-leyenda.centrada{justify-content:center;margin-top:var(--sp-5);font-size:12px}
.m1-inc-leyenda span{display:inline-flex;align-items:center;gap:5px}
.pt{width:9px;height:9px;border-radius:50%;display:inline-block;flex:none}
.pt-agresion{background:#B3261E}
.pt-juego{background:#FEC800}
.pt-otra{background:#9A8FA6}
/* la columna de servicios, despegada de los chips de estado */
.tabla th.col-servicios,.tabla td.col-servicios{padding-right:var(--sp-6)}
.tabla th.col-estado,.tabla td.col-estado{padding-left:var(--sp-5)}

.barra-h-num.en-cero{color:#B9B2BD}
.m1-inc-anillos .m1-inc-item{min-width:0}

/* Nivel de agresión: cuatro peldaños, de tranquilo a riesgo. El color no es
   decorativo, lo asigna la regla de incidencias. */
.chip-agresion{border:1px solid transparent}
.chip-agresion[data-nivel="tranquilo"] {background:rgba(76,154,42,.14); color:#3B7A20}
.chip-agresion[data-nivel="tranquilo"] .chip-dot{background:#4C9A2A}
.chip-agresion[data-nivel="vigilar"]   {background:rgba(212,160,23,.18); color:#8A6512}
.chip-agresion[data-nivel="vigilar"] .chip-dot{background:#D4A017}
.chip-agresion[data-nivel="precaucion"]{background:rgba(224,123,0,.16); color:#9C5500}
.chip-agresion[data-nivel="precaucion"] .chip-dot{background:#E07B00}
.chip-agresion[data-nivel="riesgo"]    {background:rgba(179,38,30,.14); color:#8E1E18}
.chip-agresion[data-nivel="riesgo"] .chip-dot{background:#B3261E}
/* El quinto estado: ANTES de poder calcular el nivel. El nivel sale de las
   incidencias registradas y el modulo de Incidencias todavia no esta abierto
   —/api/mascotas contesta `sinModulo: incidencias`—, asi que el chip no tiene
   con que decidir. Hace falta un color para eso, porque las dos salidas sin el
   son malas: sin regla el chip sale sin fondo y parece roto, y de verde seria
   afirmar que el perrito no tiene agresiones cuando lo cierto es que nadie las
   ha podido registrar. Gris malva, el que ella eligio para la causa «Otras». */
.chip-agresion[data-nivel="sin-datos"]{background:rgba(154,143,166,.18); color:#5F5668}
.chip-agresion[data-nivel="sin-datos"] .chip-dot{background:#9A8FA6}

#m1-ficha .card[hidden]{display:none!important}

/* El correo de facturación desbordaba su celda: es una cadena sin espacios. */
.campo-valor{min-width:0;overflow-wrap:anywhere;word-break:break-word}
.campo-fila{padding:6px 0}
.campo-label{flex:0 0 118px;min-width:0}
/* tarjetas más compactas y parejas, para cerrar el hueco de abajo */
#m1-ficha .grid-3 > .card,#m1-ficha .grid-2 > .card{padding:var(--sp-4) var(--sp-5)}
#m1-ficha .card-head{margin-bottom:var(--sp-3)}

/* ---- COMPROBANTES ---- */
.comp-barra{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);
  margin-bottom:var(--sp-4);flex-wrap:wrap}
.comp-resumen{font-size:12.5px;color:var(--texto-suave)}
.comp-resumen b{color:var(--morado);font-variant-numeric:tabular-nums}
.comp-lista{display:grid;grid-template-columns:repeat(auto-fill,minmax(224px,1fr));gap:var(--sp-3)}
.comp-item{border:1px solid var(--gris-borde);border-radius:var(--r-md);overflow:hidden;background:#fff;
  display:flex;flex-direction:column}
.comp-img{height:116px;background:var(--gris-piedra);display:flex;align-items:center;justify-content:center;
  overflow:hidden;border-bottom:1px solid var(--gris-borde)}
.comp-img img{width:100%;height:100%;object-fit:cover;display:block}
.comp-img .sin{font-size:11px;color:var(--texto-suave)}
.comp-cuerpo{padding:10px 12px;display:flex;flex-direction:column;gap:3px;flex:1}
.comp-monto{font-size:16px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.comp-meta{font-size:11.5px;color:var(--texto-suave);line-height:1.35}
.comp-pie{display:flex;align-items:center;gap:6px;margin-top:8px;flex-wrap:wrap}
.comp-accion{background:none;border:none;padding:0;font-size:11.5px;font-weight:600;color:var(--morado);
  cursor:pointer;font-family:inherit}
.comp-accion:hover{text-decoration:underline}
.comp-vacio{padding:26px 14px;text-align:center;color:var(--texto-suave);font-size:13px;
  border:1px dashed var(--gris-borde);border-radius:var(--r-md)}
/* el recibo que se genera */
.recibo{border:1px solid var(--gris-borde);border-radius:var(--r-md);padding:20px;background:#fff;
  max-width:420px;margin:0 auto;font-size:13px}
.recibo h4{margin:0 0 2px;font-size:16px;color:var(--morado)}
.recibo .folio{font-size:11px;color:var(--texto-suave);letter-spacing:.06em;text-transform:uppercase}
.recibo .raya-r{border-top:1px dashed var(--gris-borde);margin:14px 0}
.recibo .ren{display:flex;justify-content:space-between;gap:12px;padding:4px 0}
.recibo .ren span:last-child{font-weight:600;font-variant-numeric:tabular-nums;text-align:right}
.recibo .total{font-size:18px;font-weight:700;color:var(--morado)}
.recibo .pie-r{margin-top:16px;font-size:11px;color:var(--texto-suave);text-align:center;line-height:1.5}


.aviso-fila{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:10px 0;border-bottom:1px solid var(--gris-borde);font-size:13px}
.aviso-fila:last-child{border-bottom:none}


/* La firma de la sesión: quién está operando la cuenta en este momento. */
.firma-sesion{display:inline-flex;align-items:center;gap:8px}
.firma-ini{width:30px;height:30px;border-radius:50%;background:var(--morado);color:#fff;
  display:grid;place-items:center;font-size:11px;font-weight:700;letter-spacing:.02em;flex:none}
.firma-txt{display:flex;flex-direction:column;line-height:1.2}
.firma-txt b{font-size:12.5px;font-weight:600;color:var(--morado)}
.firma-txt span{font-size:10.5px;color:var(--texto-suave)}
.firma-sesion.grande .firma-ini{width:38px;height:38px;font-size:13px}
.firma-sesion.grande .firma-txt b{font-size:14px}
.firma-bloque{margin-top:14px;padding:12px 14px;border:1px solid var(--gris-borde);
  border-radius:var(--r-md);background:var(--gris-piedra);display:flex;align-items:center;
  gap:12px;flex-wrap:wrap}
.firma-et{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--texto-suave)}
.firma-nota{font-size:11.5px;color:var(--texto-suave);flex:1 1 180px}
.comp-firma{font-size:11px;color:var(--texto-suave);line-height:1.4;margin-top:2px}
.comp-firma b{color:var(--morado);font-weight:600}
.comp-bloqueo{font-size:11.5px;color:#8E1E18;background:rgba(179,38,30,.08);
  border-radius:6px;padding:7px 9px;margin-top:6px;line-height:1.4}
.recibo .firmas{display:flex;gap:16px;margin-top:14px;padding-top:12px;border-top:1px dashed var(--gris-borde)}
.recibo .firmas > div{flex:1;font-size:10.5px;color:var(--texto-suave);line-height:1.5}
.recibo .firmas b{display:block;color:var(--morado);font-size:12px;font-weight:600}
@media(max-width:860px){.firma-sesion .firma-txt{display:none}}


#m2-tbody tr[hidden]{display:none!important}
.m2-cuenta{font-size:12px;margin-bottom:8px}
.vacio-filtro{padding:22px 14px;text-align:center;color:var(--texto-suave);font-size:13px;
  border:1px dashed var(--gris-borde);border-radius:var(--r-md);margin-top:10px}
#m2 .filtros .filtro-chip{cursor:pointer}


.nm-previo{margin-top:8px;height:120px;border:1px solid var(--gris-borde);border-radius:var(--r-md);
  background:var(--gris-piedra);display:flex;align-items:center;justify-content:center;overflow:hidden}
.nm-previo img{width:100%;height:100%;object-fit:cover;display:block}
.nm-previo .sin{font-size:11.5px;color:var(--texto-suave)}
.nm-previo .archivo{font-size:12px;color:var(--morado);font-weight:600;padding:0 12px;text-align:center}


.trat-fila{border:1px solid var(--gris-borde);border-radius:var(--r-md);padding:11px 13px;margin-bottom:9px}
.trat-fila:last-child{margin-bottom:0}
.trat-fila.cerrado{opacity:.68;background:var(--gris-piedra)}
.trat-cab{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.trat-motivo{font-size:13.5px;font-weight:600;color:var(--morado)}
.trat-meta{font-size:11.5px;color:var(--texto-suave);line-height:1.45;margin-top:4px}
.trat-alta{background:none;border:none;padding:0;font-size:11.5px;font-weight:600;
  color:var(--morado);cursor:pointer;font-family:inherit}
.trat-alta:hover{text-decoration:underline}
.trat-vacio{font-size:12.5px;color:var(--texto-suave);padding:14px 0}


/* el avatar del expediente se puede cambiar: al acercarse aparece Editar */
.m2-avatar-edit{position:relative;display:flex;align-items:center;justify-content:center;
  cursor:pointer;border-radius:50%;overflow:hidden}
.m2-avatar-edit .capa{position:absolute;inset:0;border-radius:50%;background:rgba(43,23,52,.62);
  color:#fff;display:flex;align-items:center;justify-content:center;gap:5px;
  font-size:11.5px;font-weight:600;opacity:0;transition:opacity .14s}
.m2-avatar-edit:hover .capa,.m2-avatar-edit:focus-visible .capa{opacity:1}
.m2-avatar-edit .capa svg{width:14px;height:14px}
@media(prefers-reduced-motion:reduce){.m2-avatar-edit .capa{transition:none}}

#m2 .card[hidden]{display:none!important}

/* ---- Ficha de mascota: rejilla de dos columnas ------------------------
   Las tres columnas de antes dejaban a Próximos servicios debajo de
   Servicios contratados y al Historial de pagos lejos de Comunicación.
   Con dos columnas y las tarjetas ocultas fuera del flujo, cada pestaña
   se acomoda sola: General llena las dos columnas, Historial deja una
   tarjeta de media página a cada lado. */
/* stretch, no start: Datos de contacto se veía más chiquita que
   Información general estando en la misma fila. */
.m2-fgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
.m2-fgrid>.card{display:flex;flex-direction:column}
/* mismo alto y el contenido repartido, igual que en la ficha del cliente:
   ni desfasadas ni con un bloque en blanco al final */
.m2-fgrid>.card>.card-head{flex:none}
.m2-fgrid>.card>.campo-fila{flex:1 1 auto}
.m2-fgrid>.card>.barra-h,.m2-fgrid>.card>.tabla{flex:1 1 auto}
.m2-fgrid>.card{min-width:0}
.m2-fgrid>.ficha-ancho{grid-column:1 / -1}
.m2-fgrid>.card[hidden]{display:none !important}
@media (max-width:1080px){
  .m2-fgrid{grid-template-columns:minmax(0,1fr)}
  .m2-fgrid>.ficha-ancho{grid-column:auto}
}

/* ---- Alergias y cuidados: celda propia, iconos grandes ----------------
   Vivían apretadas al pie de Vacunas y salud. Son el dato que alguien
   necesita leer de un golpe antes de tocar al perrito, así que salen a
   su propia tarjeta y el icono se ve de lejos. */
.salud-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--sp-3)}
.salud-item{display:flex;gap:var(--sp-3);align-items:center;padding:var(--sp-3);
  border:1px solid var(--gris-borde);border-radius:12px;background:var(--gris-piedra)}
.salud-ico-caja{width:46px;height:46px;flex:none;display:flex;align-items:center;justify-content:center;
  border-radius:12px;background:#fff;border:1px solid var(--gris-borde)}
.salud-ico{width:26px;height:26px;color:var(--morado)}
.salud-item:nth-child(1) .salud-ico{color:var(--rojo)}
.salud-item:nth-child(2) .salud-ico{color:var(--verde)}
.salud-item:nth-child(3) .salud-ico{color:#E07B00}
.salud-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.salud-et{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--texto-suave)}
.salud-val{font-size:14.5px;font-weight:600;color:var(--morado);overflow-wrap:anywhere}

/* ---- Alimentación y observaciones: se editan picándolas -------------- */
.m2-editable{cursor:pointer;border:1px solid transparent;transition:border-color .15s,background .15s}
.m2-editable:hover,.m2-editable:focus-visible{border-color:var(--amarillo);background:#FFFBEA;outline:none}
.m2-editable .m2-lapiz{width:14px;height:14px;color:var(--texto-suave);flex:none;opacity:0;transition:opacity .15s}
.m2-editable:hover .m2-lapiz,.m2-editable:focus-visible .m2-lapiz{opacity:1}


/* ---- Modales nuevos: ayuda al pie del campo y caja angosta ---------- */
.campo-ayuda{display:block;margin-top:5px;font-size:12px;line-height:1.45;color:var(--texto-suave)}
.modal-caja.modal-angosto{max-width:520px}
.modal-aviso{margin-top:var(--sp-3);padding:10px 12px;border-radius:10px;
  background:#FFFBEA;border:1px solid var(--amarillo);font-size:13px;color:var(--morado)}
.modal-body textarea.input{width:100%;resize:vertical;font-family:inherit}

/* ---- Evidencias de tratamiento: recetas y fotos ---------------------- */
.trat-evid{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.trat-evid img{width:52px;height:52px;object-fit:cover;border-radius:8px;border:1px solid var(--gris-borde)}
.trat-adj{background:none;border:1px solid var(--gris-borde);border-radius:8px;cursor:pointer;
  font:inherit;font-size:12.5px;color:var(--morado);padding:5px 10px}
.trat-adj:hover{border-color:var(--amarillo);background:#FFFBEA}
.modal-body input[type="date"].input{width:100%;box-sizing:border-box;font-family:inherit}
.foto-previo{display:flex;align-items:center;justify-content:center;width:120px;height:120px;
  border:1px dashed var(--gris-borde);border-radius:14px;overflow:hidden;background:var(--gris-piedra);
  margin-bottom:var(--sp-3)}
.foto-previo img{width:100%;height:100%;object-fit:cover}
.foto-previo .sin{font-size:12.5px;color:var(--texto-suave)}

/* ---- Modo editar: seleccionar y borrar de las listas ------------------ */
.btn-sec-borde{background:#fff;border:1px solid var(--gris-borde);color:var(--morado);
  display:inline-flex;align-items:center;gap:7px;cursor:pointer;font:inherit}
.btn-sec-borde:hover{border-color:var(--amarillo);background:#FFFBEA}
.btn-sec-borde.activo{border-color:var(--morado);background:var(--morado);color:#fff}
.btn-peligro{background:var(--rojo);color:#fff;border:1px solid var(--rojo);border-radius:10px;
  padding:9px 16px;font:inherit;font-weight:600;cursor:pointer}
.btn-peligro:disabled{opacity:.45;cursor:not-allowed}
.btn-peligro:not(:disabled):hover{background:#8E1E18;border-color:#8E1E18}
.tabla td.col-sel,.tabla th.col-sel{width:34px;padding-right:0}
.tabla td.col-sel input{width:16px;height:16px;cursor:pointer;accent-color:var(--morado)}
.tabla-clicable.modo-editar tbody tr{cursor:default}

/* ---- Agenda: vistas alternas y bloque cancelado ---------------------- */
.m3-vista-alterna{margin-bottom:var(--sp-4)}
/* De la tercera cita de una misma hora en adelante: una tira de color, sin
   texto. Con tres bloques completos en un renglón de 38px la letra salía
   cortada y no se leía ninguno. */
.m3-bloque-tira{min-height:9px;flex:0 0 9px;padding:0;border-radius:3px}
.m3-bloque-tira b,.m3-bloque-tira span{display:none}
.m3-bloque.cancelada{opacity:.45;text-decoration:line-through}
.m3-staff-grupo{margin-bottom:var(--sp-4)}
.m3-staff-cab{display:flex;align-items:center;gap:10px;margin-bottom:var(--sp-2)}
.m3-staff-cab .nom{font-weight:600;color:var(--morado);font-size:14.5px}
.m3-dia-celda .m3-bloque{width:100%}
.m3-det-panel{margin-top:var(--sp-2)}
.m3-libre{display:block;width:100%;height:100%;min-height:26px;border:1px dashed transparent;
  border-radius:8px;background:none;cursor:pointer}
.m3-libre:hover,.m3-libre:focus-visible{border-color:var(--amarillo);background:#FFFBEA;outline:none}

/* ---- Buscador de mascota: escribir dos letras y escoger -------------- */
.busca-caja{position:relative}
.busca-lista{position:absolute;left:0;right:0;top:100%;z-index:5;margin-top:4px;
  max-height:208px;overflow-y:auto;background:#fff;border:1px solid var(--gris-borde);
  border-radius:10px;box-shadow:0 8px 20px rgba(43,23,52,.12)}
.busca-op{display:flex;align-items:center;gap:10px;width:100%;border:0;background:none;
  padding:9px 12px;font:inherit;text-align:left;cursor:pointer;color:var(--morado)}
.busca-op:hover,.busca-op.marcada{background:var(--realce)}
.busca-op .fam{margin-left:auto;font-size:12px;color:var(--texto-suave)}
.busca-vacio{padding:10px 12px;font-size:13px;color:var(--texto-suave)}

/* ---- Calendario chico: los días sin lugar no se pueden picar --------- */
.cal-chico{border:1px solid var(--gris-borde);border-radius:12px;background:#fff;padding:12px}
.cal-cab{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.cal-mes{font-weight:600;font-size:14px;color:var(--morado);text-transform:capitalize}
.cal-flecha{width:30px;height:30px;border:1px solid var(--gris-borde);border-radius:8px;background:#fff;
  cursor:pointer;font:inherit;color:var(--morado);line-height:1}
.cal-flecha:hover{border-color:var(--amarillo);background:#FFFBEA}
.cal-flecha:disabled{opacity:.35;cursor:not-allowed}
.cal-dias,.cal-rejilla{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.cal-dias div{text-align:center;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);font-weight:600;padding:3px 0}
.cal-dia{aspect-ratio:1/1;border:1px solid transparent;border-radius:9px;background:none;cursor:pointer;
  font:inherit;font-size:13px;font-weight:600;color:var(--morado);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:2px;padding:0}
.cal-dia:hover:not(:disabled){background:#FFFBEA;border-color:var(--amarillo)}
.cal-dia:disabled{color:var(--gris-borde);cursor:not-allowed;background:none}
.cal-dia.elegido{background:var(--morado);color:#fff;border-color:var(--morado)}
.cal-dia .punto{width:4px;height:4px;border-radius:50%;background:var(--verde)}
.cal-dia.elegido .punto{background:#fff}
.cal-dia.pocos .punto{background:var(--amarillo)}
.cal-nota{margin-top:8px;font-size:12px;color:var(--texto-suave);line-height:1.45}
.cal-leyenda{display:flex;gap:12px;flex-wrap:wrap;margin-top:8px;font-size:11.5px;color:var(--texto-suave)}
.cal-leyenda span{display:flex;align-items:center;gap:5px}
.cal-leyenda i{width:7px;height:7px;border-radius:50%;display:block}

/* ---- Horas: rejilla de botones, los ocupados dicen por qué ----------- */
.horas-rejilla{display:grid;grid-template-columns:repeat(auto-fill,minmax(118px,1fr));gap:8px}
.hora-btn{border:1px solid var(--gris-borde);border-radius:10px;background:#fff;padding:9px 6px;
  cursor:pointer;font:inherit;text-align:center;color:var(--morado);line-height:1.3}
.hora-btn:hover:not(:disabled){border-color:var(--amarillo);background:#FFFBEA}
.hora-btn.elegida{background:var(--morado);border-color:var(--morado);color:#fff}
.hora-btn:disabled{opacity:.5;cursor:not-allowed;background:var(--gris-piedra)}
.hora-btn b{display:block;font-size:14px}
.hora-btn span{display:block;font-size:10.5px;color:var(--texto-suave)}
.hora-btn.elegida span{color:rgba(255,255,255,.8)}
.horas-vacio{grid-column:1/-1;padding:14px;text-align:center;font-size:13px;color:var(--texto-suave);
  border:1px dashed var(--gris-borde);border-radius:10px}

/* ---- Vista por staff: todas las columnas a la misma altura ----------- */
.m3-staff-grupo .tabla{table-layout:fixed;width:100%}
.m3-staff-grupo .tabla th:nth-child(1),.m3-staff-grupo .tabla td:nth-child(1){width:15%}
.m3-staff-grupo .tabla th:nth-child(2),.m3-staff-grupo .tabla td:nth-child(2){width:17%}
.m3-staff-grupo .tabla th:nth-child(3),.m3-staff-grupo .tabla td:nth-child(3){width:20%}
.m3-staff-grupo .tabla th:nth-child(4),.m3-staff-grupo .tabla td:nth-child(4){width:30%}
.m3-staff-grupo .tabla th:nth-child(5),.m3-staff-grupo .tabla td:nth-child(5){width:18%}
.m3-staff-grupo .tabla td{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m3-staff-grupo .tabla tbody tr{cursor:pointer}
.m3-staff-grupo .tabla tbody tr:hover{background:#FFFBEA}

/* ---- Lista de espera: la fecha ya no se encima con la espera -------- */
.m3-tabla-espera{table-layout:fixed;width:100%}
.m3-tabla-espera th:nth-child(1),.m3-tabla-espera td:nth-child(1){width:20%}
.m3-tabla-espera th:nth-child(2),.m3-tabla-espera td:nth-child(2){width:26%}
.m3-tabla-espera th:nth-child(3),.m3-tabla-espera td:nth-child(3){width:19%}
.m3-tabla-espera th:nth-child(4),.m3-tabla-espera td:nth-child(4){width:15%}
.m3-tabla-espera th:nth-child(5),.m3-tabla-espera td:nth-child(5){width:20%}
.m3-tabla-espera td{vertical-align:middle;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* El pie de la agenda: dos tarjetas a media pantalla cada una. Con tres en
   fila, la lista de espera quedaba en un tercio y sus botones se salían de
   la celda; a la mitad caben enteros. Las dos cierran al mismo alto. */
/* ---- Vista por staff: un directorio, no tablas apiladas -------------
   Una lista más no decía nada que la vista lista no dijera ya; lo que
   faltaba era poder abrir la semana de UNA persona y ver sólo lo suyo. */
.m3-staff-encabezado{display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--sp-4);margin-bottom:var(--sp-4);flex-wrap:wrap}
.m3-staff-rejilla{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:var(--hueco)}
.m3-staff-ficha{display:flex;flex-direction:column;gap:var(--sp-3);padding:var(--sp-4);
  border:1px solid var(--gris-borde);border-radius:var(--r-lg);background:var(--blanco);
  cursor:pointer;text-align:left;font:inherit;color:inherit;box-shadow:var(--sombra-card)}
.m3-staff-ficha:hover{border-color:var(--amarillo);background:var(--realce)}
.m3-staff-cabeza{display:flex;align-items:center;gap:var(--sp-3)}
.m3-staff-foto{width:52px;height:52px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--morado);color:var(--blanco);font-size:17px;font-weight:700;letter-spacing:.02em;
  overflow:hidden;border:3px solid var(--blanco);box-shadow:var(--sombra-card)}
.m3-staff-foto img{width:100%;height:100%;object-fit:cover}
.m3-staff-ident{min-width:0}
.m3-staff-ident b{display:block;font-size:14px;color:var(--morado);font-weight:700}
.m3-staff-ident span{font-size:12px;color:var(--texto-suave)}
.m3-staff-cifras{display:flex;gap:var(--sp-4);flex-wrap:wrap}
.m3-staff-cifra{display:flex;flex-direction:column}
.m3-staff-cifra b{font-size:17px;color:var(--morado);font-variant-numeric:tabular-nums}
.m3-staff-cifra span{font-size:11.5px;color:var(--texto-suave)}
.m3-staff-carga{height:7px;border-radius:999px;background:var(--gris-piedra);overflow:hidden}
.m3-staff-carga i{display:block;height:100%;background:var(--amarillo);border-radius:999px;min-width:3px}
.m3-staff-pie{font-size:12px;color:var(--morado);font-weight:600}
/* Cinta de identidad: cuando la agenda es de una sola persona hay que
   decir de quién es y cómo volver al equipo. Sin esto, las mismas
   tarjetas filtradas parecen las de toda la operación. */
.m3-cinta{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
  padding:11px 14px;margin-bottom:var(--hueco);border-radius:var(--r-md);
  background:var(--realce);border:1px solid var(--amarillo)}
.m3-cinta .m3-staff-foto{width:36px;height:36px;font-size:13px;border-width:2px}
.m3-cinta b{font-size:14px;color:var(--morado)}
.m3-cinta .suave{font-size:12.5px}
.m3-cinta .card-accion{margin-left:auto}
.eq-fila{display:flex;align-items:center;gap:var(--sp-3);padding:10px 0;
  border-bottom:1px solid var(--gris-borde)}
.eq-fila:last-of-type{border-bottom:0}
.eq-fila .nom{flex:1;font-size:13.5px;font-weight:600;color:var(--morado);min-width:0}
.eq-fila .cuenta{font-size:12px;color:var(--texto-suave);white-space:nowrap}
.eq-quitar{flex:none;width:30px;height:30px;border-radius:8px;border:1px solid var(--gris-borde);
  background:var(--blanco);color:var(--texto-suave);font:inherit;cursor:pointer;line-height:1}
.eq-quitar:hover{border-color:var(--rojo);color:var(--rojo)}
.eq-fila .nom{display:flex;flex-direction:column;gap:2px}
.eq-fila .nom .sub{font-size:11.5px;font-weight:500;color:var(--texto-suave)}
.eq-editar{flex:none;border:1px solid var(--gris-borde);background:var(--blanco);color:var(--morado);
  border-radius:8px;padding:5px 11px;font:inherit;font-size:12px;font-weight:600;cursor:pointer}
.eq-editar:hover{border-color:var(--amarillo);background:var(--realce)}
.eq-alta{display:flex;gap:var(--sp-4);align-items:flex-start;flex-wrap:wrap}
.eq-campos{flex:1 1 300px;min-width:0}
.eq-foto-caja{flex:none;width:124px;display:flex;flex-direction:column;align-items:center;gap:6px}
.eq-foto-previa{width:104px;height:104px;border-radius:50%;overflow:hidden;
  border:1px dashed var(--gris-borde);background:var(--gris-piedra);
  display:grid;place-items:center}
.eq-foto-previa img{width:100%;height:100%;object-fit:cover}
.eq-foto-vacia{font-size:11.5px;color:var(--texto-suave)}
.eq-foto-caja .card-accion{width:100%;justify-content:center}
.eq-pie-lista{display:flex;justify-content:flex-start;margin-top:var(--sp-4)}
.eq-volver{display:inline-flex;align-items:center;gap:6px;border:0;background:none;padding:0;
  font:inherit;font-size:12.5px;font-weight:600;color:var(--morado);cursor:pointer}
.eq-volver svg.icon{width:14px;height:14px}
.eq-volver:hover{text-decoration:underline}
.nv-recibo{display:flex;gap:var(--sp-4);align-items:flex-start;flex-wrap:wrap}
.nv-recibo-txt{flex:1 1 240px;min-width:0;display:flex;flex-direction:column;gap:7px}
.nv-recibo-previa{flex:none;width:112px;height:112px;border-radius:var(--r-md);overflow:hidden;
  border:1px dashed var(--gris-borde);background:var(--gris-piedra);display:grid;place-items:center}
.nv-recibo-previa img{width:100%;height:100%;object-fit:cover}
.nv-folio{font-size:13px;color:var(--texto-suave)}
.nv-folio b{color:var(--morado);font-variant-numeric:tabular-nums}
.nv-recibo-acciones{display:flex;gap:8px;flex-wrap:wrap}
/* La gráfica deja el tercio y se queda con dos: con 1/3 de ancho los nueve
   meses salían como rayitas. */
/* La gráfica se achica: ahora comparte columna con Ventas recientes, y lo
   que importa es que las dos columnas cierren a la misma altura. */
.m7-cuerpo{align-items:stretch}
.m7-cuerpo > .col{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.m7-cuerpo > .col > .card{margin-top:0;display:flex;flex-direction:column;min-width:0}
.m7-cuerpo > .col > .card:last-child{flex:1 1 auto;min-height:0}
.m7-cuerpo .m7-chart-eje,.m7-cuerpo .m7-chart-area{height:150px}
.m7-cuerpo .meses-grid{height:150px}
/* El panel de una lista desplegada tiene que pasar POR ENCIMA del
   encabezado pegajoso del modal; si no, "Nueva venta" lo tapa. */
.modal-caja .lista-panel,.modal-caja .busca-lista{z-index:60}
.modal-header{z-index:30}
/* El botón de cobrar cabe en su celda: la columna lo reserva y el botón no
   se estira. */
.m7-tabla-recientes{table-layout:fixed;width:100%}
.m7-tabla-recientes th:last-child,.m7-tabla-recientes td:last-child{width:96px;text-align:right}
.m7-tabla-recientes td{overflow:hidden;text-overflow:ellipsis;vertical-align:middle}
.m7-tabla-recientes .card-accion,.m7-tabla-recientes .btn{white-space:nowrap;flex:none;width:auto}
/* El realce de un renglón picable es el morado del sistema, no un gris */
.tabla-clicable tbody tr:hover td{background:var(--realce)}
/* El canal se reconoce por su marca mucho antes que por su nombre, y así la
   columna deja de partir "WhatsAp/p" en dos renglones. */
/* Cinco columnas en media tarjeta: sin anchos, "MASCOTA" y "CANAL" se
   partían en "MASCOT/A" y "CANA/L". Repartidas, cada encabezado cabe. */
#m5 .grid-pareado.mitades .tabla{table-layout:fixed;width:100%}
#m5 .grid-pareado.mitades .tabla th:nth-child(1),#m5 .grid-pareado.mitades .tabla td:nth-child(1){width:15%}
#m5 .grid-pareado.mitades .tabla th:nth-child(2),#m5 .grid-pareado.mitades .tabla td:nth-child(2){width:17%}
#m5 .grid-pareado.mitades .tabla th:nth-child(3),#m5 .grid-pareado.mitades .tabla td:nth-child(3){width:12%}
/* Estado pasa de 20 % a 23 %: el chip "Confirmado" mide 95 px y en 90 de
   hueco se salia 5 px de la tarjeta a 1440 y 21 px a 1280. Los 3 puntos
   salen de Mensaje, que es prosa y se recorta con puntos. Medido 14-oct. */
/* Estado va en PIXELES, no en porcentaje: lo que tiene que caber es un chip,
   y un chip mide lo que mide -- 95 px el mas largo ("Confirmado") mas su
   hueco. Con 23 % cabia a 1440 y volvia a salirse 8 px a 1280, porque el
   porcentaje encoge con la tarjeta y el chip no. Mensaje se queda sin ancho
   declarado y absorbe lo que sobre: es prosa y se recorta con puntos. */
#m5 .grid-pareado.mitades .tabla th:nth-child(5),#m5 .grid-pareado.mitades .tabla td:nth-child(5){width:112px}
#m5 .grid-pareado.mitades .tabla th{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#m5 .grid-pareado.mitades .tabla td{vertical-align:middle;overflow-wrap:anywhere}
.cm-canal-td{text-align:center}
.cm-canal{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:8px;background:var(--gris-piedra)}
.cm-canal svg{width:15px;height:15px;display:block}
.sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* Dos lecturas de la misma tanda: en qué estado están y de qué son. Lado a
   lado mientras quepan; si no, una debajo de la otra. */
/* auto-fit con un mínimo chico, no dos columnas fijas con media query: la
   media query mira el ANCHO DE VENTANA, así que con el visor en panel
   angosto las apilaba aunque en su tarjeta cupieran de sobra. */
.m5-donas{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--sp-4)}
/* align-items:start, no center: centrar cada columna por su cuenta las
   dejaba a alturas distintas porque sus leyendas miden distinto —una tiene
   tres entradas y la otra dos—. Arrancando ambas arriba, los dos anillos
   quedan en la misma línea. El bloque completo sí se centra en la tarjeta,
   con el margin:auto de abajo. */
.m5-donas{align-items:stretch}
/* La tarjeta de las donas cierra a la altura de su vecina, así que los dos
   anillos se centran en el espacio en vez de quedarse pegados arriba. */
#m5 .grid-pareado.mitades > .card:last-child{justify-content:center}
.m5-donas{margin:auto 0}
/* Las dos columnas arrancan en la misma línea: el rótulo y el anillo
   ocupan lo mismo en las dos, aunque una leyenda sea más larga. */
.m5-donas .dona-centrada{min-width:0;display:flex;flex-direction:column;align-items:center;
  justify-content:flex-start;height:100%;gap:var(--sp-3)}
/* La leyenda arranca justo debajo del anillo en las dos columnas, no
   pegada al fondo. Con margin-top:auto cada leyenda se anclaba abajo, y
   como una tiene tres renglones (siete categorías) y la otra dos (cinco
   estados), el primer renglón de la izquierda quedaba un renglón más
   arriba que el de la derecha. Arrancando ambas en la misma línea, cada
   renglón casa con el de al lado y el sobrante cuelga abajo, que es donde
   no estorba. Los anillos miden lo mismo, así que la línea de arranque es
   la misma sin tener que fijarla a mano. */
.m5-donas .dona-abajo{margin-top:0}
.m5-donas .m5-dona-et{min-height:16px}
/* En media tarjeta, dos anillos a 148px no caben: se achican lo necesario
   para que queden lado a lado en vez de uno encima del otro. */
.m5-donas .anillo.grande{width:100%;max-width:138px;height:auto;aspect-ratio:1;margin:0 auto}
.m5-donas .anillo.grande .centro span:first-child{font-size:20px}
.m5-donas .dona-abajo .it{font-size:11.5px}
/* Tres columnas fijas en las donas del inventario: con auto-fit el número
   de columnas cambiaba con el ancho y una entrada no se podía dejar en una
   casilla concreta. */
/* Cada dona vive ahora en su propia tarjeta, así que la leyenda cabe en
   dos columnas. Eso es además lo que hace cierto el orden que pidió Edna:
   con dos columnas, "debajo de" es exactamente dos lugares más adelante. */
#m6-dona-consumo .dona-abajo,#m6-dona-stock .dona-abajo{grid-template-columns:repeat(2,minmax(0,1fr));
  column-gap:var(--sp-4)}
/* Una sola dona por tarjeta: ocupa todo el ancho y su leyenda baja al pie. */
.m5-donas.una{grid-template-columns:1fr}
.m5-donas.una .dona-centrada{height:100%;justify-content:flex-start}
.m5-donas.una .dona-abajo{margin-top:auto}
.m6-par-donas{align-items:stretch}
.m6-par-donas > .card{display:flex;flex-direction:column;min-width:0}
.m6-par-donas .m5-donas{flex:1 1 auto}
/* El rótulo propio de la dona sobra: ahora lo dice el encabezado. */
#m6-dona-consumo .m5-dona-et,#m6-dona-stock .m5-dona-et{display:none}
.m5-donas .anillo.grande{max-width:196px}
.m5-donas .anillo.grande .centro span:first-child{font-size:30px}
.m5-donas .anillo.grande .centro span:nth-child(2){font-size:10px}
.m5-donas .anillo .pista,.m5-donas .anillo .valor{stroke-width:8.5}
.m5-donas .dona-abajo .it{font-size:10.5px;padding:4px 2px;gap:1px}
.m5-donas .dona-abajo .et{font-size:10.5px;line-height:1.15}
.m5-donas .dona-abajo .et i{width:8px;height:8px}
.m5-donas .dona-abajo .num{font-size:14px}
.m5-donas .dona-abajo .pct{font-size:10.5px}
/* La tarjeta del inventario ocupa todo el ancho, así que ahí los dos
   anillos tienen mucho más espacio que en la media tarjeta de
   Incidencias y pueden crecer bastante más. */
#m6-dona-consumo .anillo.grande,#m6-dona-stock .anillo.grande{max-width:292px}
#m6-dona-consumo .anillo .pista,#m6-dona-consumo .anillo .valor,
#m6-dona-stock .anillo .pista,#m6-dona-stock .anillo .valor{stroke-width:7}
#m6-dona-consumo .anillo.grande .centro span:first-child,
#m6-dona-stock .anillo.grande .centro span:first-child{font-size:44px}
#m6-dona-consumo .anillo.grande .centro span:nth-child(2),
#m6-dona-stock .anillo.grande .centro span:nth-child(2){font-size:11px}
/* Las pastillas de periodo caben en el encabezado de la tarjeta */
.m5-periodo-cab{margin-left:auto;gap:6px}
.m5-periodo-cab .periodo-pill{padding:5px 11px;font-size:11.5px}
.m5-dona-et{display:block;text-align:center;font-size:11px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--texto-suave);margin-bottom:var(--sp-2)}
/* La nota de la entrada se lee en la salida, pero no se toca. */
.as-nota-fija{padding:9px 12px;border-radius:var(--r-md);background:var(--gris-piedra);
  border:1px solid var(--gris-borde);font-size:13.5px;color:var(--morado);line-height:1.45;
  min-height:38px;overflow-wrap:anywhere}

/* La columna derecha cierra exactamente donde cierra el calendario: el
   expediente de la cita se queda con el alto que sobre —y se desliza por
   dentro si su contenido es más largo— y "Servicios por tipo" se sienta
   abajo con su alto natural. Antes el expediente crecía libre y "Servicios
   por tipo" vivía hasta el pie de la pantalla. */
/* Las dos columnas cierran a la misma altura: el calendario se desliza por
   dentro si la semana trae más renglones de los que caben, en vez de
   estirar la fila y dejar a "Servicios por tipo" colgando en el aire. */
#m3-vista-calendario{align-items:stretch}
#m3-vista-calendario > .col{min-width:0}
#m3-vista-calendario > .col > .card{display:flex;flex-direction:column;min-height:0;margin-bottom:0}
#m3-vista-calendario > .col > .card > .m3-semana{flex:1 1 auto;min-height:0;overflow-y:auto}
.m3-col-der{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.m3-col-der > .m3-detalle{flex:1 1 auto;min-height:220px;overflow-y:auto;margin-bottom:0}
.m3-col-der > .m3-card-portipo{flex:none;margin-bottom:0}
/* En media columna la etiqueta de 120px no deja sitio para la barra: se
   angosta aquí nada más, la barra se conserva —es lo que deja comparar— y
   el número queda a la derecha. */
.m3-card-portipo .barra-h{gap:9px}
.m3-card-portipo .barra-h-fila{grid-template-columns:minmax(74px,1fr) minmax(0,1.1fr) 34px;gap:8px}
.m3-card-portipo .barra-h-label{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m3-card-portipo .barra-h-num{font-size:12px}

/* ── LA COLUMNA DERECHA NO MANDA LA ALTURA DE LA FILA ───────────────────────
   El comentario de arriba ya decía la intención —que «Servicios por tipo» se
   desplace dentro en vez de estirar la fila— y no se cumplía. Medido el 27 oct
   2026 con la agenda pintada en 1440 px: la tarjeta de servicios por tipo
   medía 1120 px de alto (39 renglones), la columna derecha subía la fila a
   1275 y el calendario —767 px de contenido— quedaba estirado con aire debajo.
   Edna: «la celda se hace mucho mas larga de lo que debería, tiene que estar
   del tamaño del calendario».
   Faltaba el acotado: `.m3-card-portipo{flex:none}` pide todo su contenido y
   la columna no tenía techo, así que la fila la mandaba ella.
   `height:0; min-height:100%` es lo que hace que un hijo de rejilla NO aporte
   altura a su fila y aun así la llene entera: el alto lo fija el calendario y
   aquí dentro cada tarjeta se desplaza sola. */
#m3-vista-calendario > .m3-col-der{height:0;min-height:100%}
/* QUIEN CEDE SITIO ES LA LISTA, NO LA FICHA. Primer intento, medido: con la
   tarjeta de servicios en `flex:0 1 auto` ganaba el reparto —su base eran
   1120 px contra los 141 del detalle— y el panel del detalle bajó de 143 a
   102 px con el texto recortado dentro. Apretar la ficha de la cita para que
   quepa una lista de barras es al revés de lo que mira recepción.
   Así que el detalle toma su alto natural con un techo del 45 %, y la lista se
   queda con lo que sobre y se desplaza dentro. */
#m3-vista-calendario > .m3-col-der > .m3-detalle{
  flex:0 0 auto;max-height:45%;min-height:0;overflow-y:auto}
/* `0 1 auto`: no crece, sólo encoge. Con `1 1 auto` la tarjeta se estiraba a
   todo lo que sobrara —612 px para DOS barras— en cuanto se limpiaron las 43
   citas de prueba que la hinchaban. El defecto de Edna y su contrario son la
   misma regla mal puesta: una tarjeta que manda sobre la fila y una tarjeta
   que se deja estirar por ella. Aquí pide lo que necesita, y si no cabe se
   desplaza dentro. */
#m3-vista-calendario > .m3-col-der > .m3-card-portipo{
  flex:0 1 auto;min-height:0;max-height:100%;display:flex;flex-direction:column}
#m3-vista-calendario > .m3-col-der > .m3-card-portipo > .barra-h{
  overflow-y:auto;min-height:0}

.m3-pie{align-items:stretch}
.m3-pie > .card{display:flex;flex-direction:column;min-width:0}
.m3-pie > .card > .tabla,.m3-pie > .card > #m3-hoy{flex:1 1 auto}
.m3-pie .m3-tabla-espera .card-accion,.m3-pie .m3-tabla-espera .btn{white-space:nowrap}

/* ---- Hoy: siete renglones a la vista, el resto en "Ver más" --------- */
/* Sin barra de desplazamiento: la barra era lo que cortaba el último
   servicio a la mitad. La tarjeta mide lo que miden sus siete renglones. */
#m3-hoy{max-height:none;overflow:visible}
.li-fila{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--gris-borde)}
.li-fila:last-child{border-bottom:0}
.li-fila .et{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--texto-suave);
  min-width:92px}
.li-fila .val{font-weight:600;color:var(--morado)}

/* ---- Resumen financiero: una fila por cifra, no cuatro mosaicos -------
   En 2x2 dentro de una tarjeta de un tercio de ancho el ícono, el monto,
   la etiqueta y la variación se pisaban. En lista cada cosa tiene su
   columna: ícono, concepto y variación a la izquierda, monto a la
   derecha, alineado por los dígitos. Ocupa el mismo alto. */
.fin-lista{display:flex;flex-direction:column}
.fin-fila{display:flex;align-items:center;gap:var(--sp-3);padding:11px 0;
  border-bottom:1px solid var(--gris-borde)}
.fin-fila:last-child{border-bottom:0}
.fin-fila .icon-badge{margin-bottom:0;width:34px;height:34px;flex:none}
.fin-fila .icon-badge svg.icon{width:17px;height:17px}
.fin-txt{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1 1 auto}
.fin-et{font-size:13px;font-weight:600;color:var(--morado);white-space:nowrap}
.fin-fila .kpi-delta{margin:0;font-size:11.5px;white-space:nowrap}
.fin-monto{font-size:18px;font-weight:700;color:var(--morado);
  font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:auto;text-align:right}

/* ---- Agendar: un paso debajo del otro, sin lugar a dudas ------------- */
.cita-flujo{display:flex;flex-direction:column;gap:var(--sp-4)}
.cita-flujo .campo-form{margin-bottom:0}
.cita-par{display:flex;gap:var(--sp-4);flex-wrap:wrap}
.cita-par .campo-form{flex:1 1 220px;margin-bottom:0}
.cita-flujo label{display:flex;align-items:center;gap:8px}
.cita-flujo .paso{display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;
  border-radius:50%;background:var(--morado);color:#fff;font-size:11px;font-weight:700;flex:none}

/* ---- Lista de espera: legible, y cada renglón abre su ficha ---------- */
.m3-tabla-espera th,.m3-tabla-espera td{font-size:13px}
.m3-tabla-espera th:nth-child(1),.m3-tabla-espera td:nth-child(1){width:19%}
.m3-tabla-espera th:nth-child(2),.m3-tabla-espera td:nth-child(2){width:24%}
.m3-tabla-espera th:nth-child(3),.m3-tabla-espera td:nth-child(3){width:17%}
.m3-tabla-espera th:nth-child(4),.m3-tabla-espera td:nth-child(4){width:14%}
.m3-tabla-espera th:nth-child(5),.m3-tabla-espera td:nth-child(5){width:26%}
.m3-tabla-espera tbody tr{cursor:pointer}
.m3-tabla-espera tbody tr:hover{background:#FFFBEA}
.m3-tabla-espera .dias{font-weight:600;color:var(--morado);font-variant-numeric:tabular-nums}
.m3-tabla-espera .sub{display:block;font-size:11px;color:var(--texto-suave);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.m3-tabla-espera td .btn-sm{font-size:12px;padding:5px 10px;white-space:nowrap}

/* =====================================================================
   VISTA CLIENTE — la misma plataforma, del lado del dueño
   No es un módulo administrativo con menos cosas: es otro oficio. El
   dueño no busca entre tablas, escoge entre sus perritos y ve solo los
   días y horas en que de verdad hay lugar. El motor que decide eso es el
   mismo de la agenda interna, así que lo que aquí se agenda aparece allá.
   ===================================================================== */
.mc-cab{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--sp-4);
  flex-wrap:wrap;margin-bottom:var(--sp-5)}
.mc-familia{display:flex;flex-direction:column;gap:4px}
.mc-familia label{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--texto-suave)}
.mc-familia .input{min-width:230px}

/* La vista del cliente es una sola tarea, no un tablero: se centra en la
   página y se le da ancho de lectura en vez de quedar pegada a la izquierda
   con media pantalla en blanco. */
#mc-agendar,#mc-mios{max-width:880px;margin-inline:auto}
#mc-agendar .mc-tarjeta{padding:clamp(22px,3vw,34px)}
.mc-cab{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap}
.mc-pasos{display:flex;gap:6px;margin-bottom:var(--sp-4)}
.mc-pasos span{height:4px;flex:1;border-radius:2px;background:var(--gris-borde)}
.mc-pasos span.hecho{background:var(--amarillo)}

.mc-tarjeta{max-width:720px}
.mc-opciones{display:grid;grid-template-columns:repeat(auto-fill,minmax(216px,1fr));gap:var(--sp-3)}
.mc-op{display:flex;align-items:center;gap:var(--sp-3);text-align:left;width:100%;
  border:1px solid var(--gris-borde);border-radius:12px;background:#fff;padding:13px;
  cursor:pointer;font:inherit;transition:border-color .15s,background .15s}
.mc-op:hover,.mc-op:focus-visible{border-color:var(--amarillo);background:#FFFBEA;outline:none}
.mc-op.elegida{border-color:var(--morado);background:var(--gris-piedra)}
.mc-op-ini{width:42px;height:42px;border-radius:50%;flex:none;display:flex;align-items:center;
  justify-content:center;font-weight:700;font-size:14px;color:var(--morado)}
.mc-op-foto{width:42px;height:42px;border-radius:50%;object-fit:cover;flex:none}
.mc-op-txt{display:flex;flex-direction:column;gap:2px;min-width:0}
.mc-op-txt b{font-size:14.5px;color:var(--morado)}
.mc-op-txt span{font-size:12.5px;color:var(--texto-suave);overflow-wrap:anywhere}

.mc-resumen-linea{font-size:13px;color:var(--texto-suave);margin-bottom:var(--sp-3)}
.mc-resumen-linea b{color:var(--morado)}
.mc-resumen{display:flex;flex-direction:column;border:1px solid var(--gris-borde);
  border-radius:12px;overflow:hidden}
.mc-resumen .fila{display:flex;justify-content:space-between;gap:var(--sp-3);
  padding:10px 14px;border-bottom:1px solid var(--gris-borde);font-size:13px}
.mc-resumen .fila:last-child{border-bottom:0}
.mc-resumen .fila span:first-child{color:var(--texto-suave)}
.mc-resumen .fila span:last-child{font-weight:600;color:var(--morado);text-align:right}

.mc-listo{display:flex;flex-direction:column;align-items:center;gap:6px;
  text-align:center;padding:var(--sp-4) 0 var(--sp-5)}
.mc-listo-ico{width:52px;height:52px;border-radius:50%;background:var(--verde);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:26px;font-weight:700}

.mc-cita{display:flex;align-items:center;gap:var(--sp-3);padding:12px 0;
  border-bottom:1px solid var(--gris-borde);flex-wrap:wrap}
.mc-cita:last-child{border-bottom:0}
.mc-cita-txt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 170px}
.mc-cita-txt b{font-size:14px;color:var(--morado)}
.mc-cita-txt span{font-size:12.5px;color:var(--texto-suave)}
.mc-cita-acciones{display:flex;gap:6px;margin-left:auto;flex-wrap:wrap}
@media (max-width:760px){
  .mc-familia .input{min-width:0;width:100%}
  .mc-cita-acciones{margin-left:0;width:100%}
}

/* ---- Vista cliente: migas del camino y rango de noches -------------- */
.mc-migas{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:var(--sp-4);font-size:12.5px;color:var(--texto-suave)}
.mc-migas button{border:0;background:none;font:inherit;color:var(--morado);font-weight:600;
  cursor:pointer;padding:0;text-decoration:underline}
.mc-migas .sep{color:var(--gris-borde)}
.mc-rango{margin-top:var(--sp-3);padding:12px 14px;border-radius:10px;background:#FFFBEA;
  border:1px solid var(--amarillo);font-size:13px;color:var(--morado);line-height:1.5}
.mc-rango b{font-weight:700}
.cal-dia.entrada,.cal-dia.salida{background:var(--morado);color:#fff;border-color:var(--morado)}
.cal-dia.entre{background:#FFFBEA;border-color:var(--amarillo)}

/* ---- Ticket del cliente: lo que va a pagar, a la vista -------------
   Un flujo de reserva que esconde el precio hasta el final obliga a
   retroceder cuando la cifra sorprende. Aquí el monto aparece desde que
   se escoge el servicio y se recalcula al cambiar las noches. */
.mc-ticket{position:sticky;top:8px;z-index:3;display:flex;align-items:center;gap:var(--sp-3);
  flex-wrap:wrap;margin-bottom:var(--sp-4);padding:12px 16px;border-radius:12px;
  background:var(--morado);color:#fff;box-shadow:0 6px 18px rgba(43,23,52,.18)}
.mc-ticket .tk-txt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 220px}
.mc-ticket .tk-et{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;opacity:.75}
.mc-ticket .tk-det{font-size:13.5px;font-weight:600}
.mc-ticket .tk-monto{margin-left:auto;text-align:right;font-variant-numeric:tabular-nums}
.mc-ticket .tk-monto b{display:block;font-size:22px;font-weight:700;line-height:1.1}
.mc-ticket .tk-monto span{font-size:11.5px;opacity:.75}
.mc-ticket .tk-nota{flex:1 1 100%;font-size:11.5px;opacity:.75;line-height:1.45;margin-top:2px}
.mc-op-precio{margin-left:auto;text-align:right;flex:none}
.mc-op-precio b{display:block;font-size:15px;color:var(--morado);font-variant-numeric:tabular-nums}
.mc-op-precio span{display:block;font-size:11px;color:var(--texto-suave)}

/* ---- El renglón del total, dentro de la caja del rango -------------- */
.mc-rango>div{margin-bottom:6px}
.mc-rango>div:last-child{margin-bottom:0}
.rango-total{display:flex;align-items:baseline;gap:var(--sp-3);
  padding-top:8px;margin-top:8px;border-top:1px solid var(--amarillo)}
.rango-total>span{font-size:12.5px;color:var(--texto-suave)}
.rango-total>span i{font-style:normal;font-variant-numeric:tabular-nums}
.rango-total>b{margin-left:auto;font-size:19px;font-weight:700;color:var(--morado);
  font-variant-numeric:tabular-nums}

/* ---- Avisos y bloqueos ----------------------------------------------- */
.avisos-barra{display:flex;gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--sp-3);font-size:12.5px}
.avisos-barra span{display:flex;align-items:center;gap:6px;color:var(--texto-suave)}
.avisos-barra b{color:var(--morado);font-variant-numeric:tabular-nums}
.avisos-pie{margin-top:var(--sp-3);padding:10px 12px;border-radius:10px;background:var(--gris-piedra);
  border:1px solid var(--gris-borde);font-size:12px;color:var(--texto-suave);line-height:1.5}
.tabla-avisos,.tabla-bloqueos{table-layout:fixed;width:100%}
.tabla-avisos th,.tabla-avisos td,.tabla-bloqueos th,.tabla-bloqueos td{font-size:12.5px}
.tabla-avisos th:nth-child(1),.tabla-avisos td:nth-child(1){width:21%}
.tabla-avisos th:nth-child(2),.tabla-avisos td:nth-child(2){width:27%}
.tabla-avisos th:nth-child(3),.tabla-avisos td:nth-child(3){width:21%}
.tabla-avisos th:nth-child(4),.tabla-avisos td:nth-child(4){width:18%}
.tabla-avisos th:nth-child(5),.tabla-avisos td:nth-child(5){width:13%}
.tabla-bloqueos th:nth-child(1),.tabla-bloqueos td:nth-child(1){width:20%}
.tabla-bloqueos th:nth-child(2),.tabla-bloqueos td:nth-child(2){width:20%}
.tabla-bloqueos th:nth-child(3),.tabla-bloqueos td:nth-child(3){width:24%}
.tabla-bloqueos th:nth-child(4),.tabla-bloqueos td:nth-child(4){width:26%}
.tabla-bloqueos th:nth-child(5),.tabla-bloqueos td:nth-child(5){width:10%}
.tabla-avisos td,.tabla-bloqueos td{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tabla-avisos tbody tr{cursor:pointer}
.tabla-avisos tbody tr:hover,.tabla-bloqueos tbody tr:hover{background:#FFFBEA}
.av-quitar{border:0;background:none;cursor:pointer;color:var(--rojo);font:inherit;font-size:12.5px;padding:0}
.vm-mensaje{margin-top:var(--sp-3);padding:12px 14px;border-radius:10px;background:var(--gris-piedra);
  border:1px solid var(--gris-borde);font-size:13.5px;color:var(--morado);line-height:1.55;white-space:pre-wrap}

/* ---- Asistencia: columnas fijas para que nada se encime ------------- */
.m4-tabla-asistencia{table-layout:fixed;width:100%}
.m4-tabla-asistencia th,.m4-tabla-asistencia td{font-size:12.5px}
.m4-tabla-asistencia th{white-space:nowrap}
/* Anchos recalculados el 14-oct-2026 contra el contenido real: la columna
   que lleva un chip recibe lo que el chip mide mas su aire, y el sobrante
   se reparte entre las columnas de prosa, que son las que pueden ceder
   porque se recortan con puntos y se siguen leyendo. Antes el %% estaba
   escrito a mano para unos textos que ya cambiaron, y el chip se partia. */
.m4-tabla-asistencia th:nth-child(1),.m4-tabla-asistencia td:nth-child(1){width:14.1%}
.m4-tabla-asistencia th:nth-child(2),.m4-tabla-asistencia td:nth-child(2){width:15.6%}
.m4-tabla-asistencia th:nth-child(3),.m4-tabla-asistencia td:nth-child(3){width:16%}
.m4-tabla-asistencia th:nth-child(4),.m4-tabla-asistencia td:nth-child(4){width:15.1%}
.m4-tabla-asistencia th:nth-child(5),.m4-tabla-asistencia td:nth-child(5){width:15.1%}
.m4-tabla-asistencia th:nth-child(6),.m4-tabla-asistencia td:nth-child(6){width:16.7%}
.m4-tabla-asistencia th:nth-child(7),.m4-tabla-asistencia td:nth-child(7){width:7.3%}
.m4-tabla-asistencia .m4-accion{max-width:100%;overflow:hidden;text-overflow:ellipsis}
.m4-tabla-asistencia td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
.m4-accion{border:1px solid var(--gris-borde);background:#fff;border-radius:8px;cursor:pointer;
  font:inherit;font-size:11.5px;padding:4px 8px;color:var(--morado);white-space:nowrap}
.m4-accion:hover{border-color:var(--amarillo);background:#FFFBEA}
.m4-accion.salida{border-color:var(--verde);color:#3B7A20}
.m4-estancia-fila{display:flex;gap:var(--sp-3);flex-wrap:wrap}
.m4-estancia-item{cursor:pointer}
.m4-pend-fila{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--gris-borde)}
.m4-pend-fila:last-child{border-bottom:0}
.m4-pend-fila .hora{font-variant-numeric:tabular-nums;font-weight:600;color:var(--morado);font-size:13px;min-width:44px}
.m4-pend-txt{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1 1 auto}
.m4-pend-txt b{font-size:13px;color:var(--morado)}
.m4-pend-txt span{font-size:11.5px;color:var(--texto-suave)}
.m4-mes-fila{display:flex;justify-content:space-between;gap:var(--sp-3);padding:8px 0;
  border-bottom:1px solid var(--gris-borde);font-size:13px}
.m4-mes-fila:last-child{border-bottom:0}
.m4-mes-fila span:first-child{color:var(--texto-suave)}
.m4-mes-fila b{color:var(--morado);font-variant-numeric:tabular-nums}
.chip-neutro{background:var(--gris-piedra);color:var(--texto-suave);border:1px solid var(--gris-borde)}
.chip-neutro .chip-dot{background:var(--texto-suave)}

/* ---- Ventas: controles y tabla --------------------------------------- */
.m7-controles{display:flex;gap:var(--sp-3);flex-wrap:wrap;align-items:center;margin-bottom:var(--sp-4)}
.m7-controles .filtros{margin-bottom:0}
.m7-select{min-width:186px}
.m7-buscador{flex:1 1 230px;min-width:200px;margin-bottom:0}
.tabla-ventas{table-layout:fixed;width:100%}
.tabla-ventas th,.tabla-ventas td{font-size:12.5px}
/* Mascota (col 4) sube de 12 % a 15 %: lleva avatar de 32 px MAS el nombre, y
   en 84 px no cabian los dos. Lo que gana sale de Cliente y Concepto, que son
   prosa y se recortan con puntos sin perder el dato. Medido 14-oct-2026. */
.tabla-ventas th:nth-child(1),.tabla-ventas td:nth-child(1){width:8%}
.tabla-ventas th:nth-child(2),.tabla-ventas td:nth-child(2){width:10%}
.tabla-ventas th:nth-child(3),.tabla-ventas td:nth-child(3){width:16%}
.tabla-ventas th:nth-child(4),.tabla-ventas td:nth-child(4){width:15%}
.tabla-ventas th:nth-child(5),.tabla-ventas td:nth-child(5){width:15%}
.tabla-ventas th:nth-child(6),.tabla-ventas td:nth-child(6){width:10%}
.tabla-ventas th:nth-child(7),.tabla-ventas td:nth-child(7){width:13%}
.tabla-ventas th:nth-child(8),.tabla-ventas td:nth-child(8){width:13%}
.tabla-ventas td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
.m7-folio{font-family:'IBM Plex Mono',ui-monospace,monospace;font-size:11.5px;color:var(--texto-suave)}
.m7-rank{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--gris-borde)}
.m7-rank:last-child{border-bottom:0}
.m7-rank .pos{width:22px;height:22px;border-radius:50%;background:var(--gris-piedra);color:var(--morado);
  display:flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:700;flex:none}
.m7-rank .nom{flex:1 1 auto;font-size:13.5px;color:var(--morado);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m7-rank .n{font-variant-numeric:tabular-nums;font-weight:600;color:var(--morado);font-size:13.5px}
/* El botón de cobrar vivía apretado contra el borde de su celda; ahora
   tiene su propio ancho y la columna se lo reserva. */
.m7-cobrar{border:1px solid var(--verde);background:#fff;border-radius:999px;cursor:pointer;
  font:inherit;font-size:11.5px;font-weight:600;padding:4px 12px;color:#3B7A20;white-space:nowrap;
  display:inline-flex;align-items:center;line-height:1.3}
.tabla-ventas td:last-child,.tabla-cobranza td:last-child,
.m8-tabla td:last-child{text-align:right;padding-right:2px;overflow:visible}
.co2-ticket{border:1px solid var(--gris-borde);border-radius:12px;overflow:hidden}
.co2-fila{display:flex;gap:var(--sp-3);padding:10px 14px;font-size:13px;
  border-bottom:1px solid var(--gris-borde)}
.co2-fila:last-child{border-bottom:0;background:var(--gris-piedra);font-weight:700}
.co2-fila .et{min-width:124px;flex:none;color:var(--texto-suave)}
.co2-fila .vl{flex:1;color:var(--morado);font-weight:600;overflow-wrap:anywhere}
.co2-fila.total .et{color:var(--morado)}
.m7-cobrar:hover{background:#F4FBE8}

/* ---- Cobranza --------------------------------------------------------- */
.tabla-cobranza{table-layout:fixed;width:100%}
.tabla-cobranza th,.tabla-cobranza td{font-size:12.5px}
.tabla-cobranza th:nth-child(1),.tabla-cobranza td:nth-child(1){width:10%}
.tabla-cobranza th:nth-child(2),.tabla-cobranza td:nth-child(2){width:15%}
.tabla-cobranza th:nth-child(3),.tabla-cobranza td:nth-child(3){width:11%}
.tabla-cobranza th:nth-child(4),.tabla-cobranza td:nth-child(4){width:16%}
.tabla-cobranza th:nth-child(5),.tabla-cobranza td:nth-child(5){width:10%}
.tabla-cobranza th:nth-child(6),.tabla-cobranza td:nth-child(6){width:12%}
.tabla-cobranza th:nth-child(7),.tabla-cobranza td:nth-child(7){width:12%}
.tabla-cobranza th:nth-child(8),.tabla-cobranza td:nth-child(8){width:14%}
.tabla-cobranza td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
/* Dos botones no caben lado a lado en una columna de tabla: se apilan y
   la columna se queda con el ancho de uno, no de los dos. */
.m8-acc{display:flex;flex-direction:column;align-items:stretch;gap:5px}
.m8-acc > button{width:100%;justify-content:center;white-space:nowrap}
.m8-rec{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-bottom:1px solid var(--gris-borde)}
.m8-rec:last-child{border-bottom:0}
.m8-rec .campana{width:28px;height:28px;border-radius:8px;background:#FDEDEC;color:var(--rojo);flex:none;
  display:flex;align-items:center;justify-content:center}
.m8-rec .campana svg.icon{width:15px;height:15px}
.m8-rec-txt{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1 1 auto}
.m8-rec-txt b{font-size:13px;color:var(--morado)}
.m8-rec-txt span{font-size:11.5px;color:var(--texto-suave);overflow-wrap:anywhere}
.m8-rec-txt .monto{font-size:13px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.m8-estado-fila{display:flex;align-items:center;gap:10px;padding:8px 0}
.m8-estado-fila .et{font-size:12.5px;color:var(--morado);min-width:90px;display:flex;align-items:center;gap:6px}
.m8-estado-fila .et i{width:8px;height:8px;border-radius:50%;display:block}
.m8-estado-fila .pct{font-size:12.5px;font-weight:600;color:var(--morado);min-width:34px;text-align:right;
  font-variant-numeric:tabular-nums}
.m8-metodos{display:block}
/* Las dos tarjetas de la fila se leen igual: anillo centrado y, debajo,
   los valores en un solo renglón centrado. Con auto-fit en rejilla, dos
   entradas se iban a la izquierda y cinco llenaban el ancho: distinta
   altura y distinto eje en tarjetas que van lado a lado. */
#m8-dona .dona-abajo,#m8-metodos .dona-abajo{display:flex;flex-wrap:wrap;
  justify-content:center;align-items:flex-start;gap:var(--sp-2) var(--sp-4);width:100%}
#m8-dona .dona-abajo .it,#m8-metodos .dona-abajo .it{min-width:84px}
#m8-dona .dona-abajo .num,#m8-metodos .dona-abajo .num{font-size:16px}
.m8-metodo{border:1px solid var(--gris-borde);border-radius:10px;padding:10px 12px;background:#fff}
.m8-metodo b{display:block;font-size:13px;color:var(--morado)}
.m8-metodo span{font-size:11.5px;color:var(--texto-suave)}
#m8-historial{flex:1 1 auto;display:flex;flex-direction:column}
.m8-hist-fila{flex:1 1 auto;min-height:32px;display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--gris-borde);font-size:12.5px}
.m8-hist-fila:last-child{border-bottom:0}
.m8-hist-fila .f{color:var(--texto-suave);min-width:52px;font-variant-numeric:tabular-nums}
.m8-hist-fila .c{flex:1 1 auto;color:var(--morado);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m8-hist-fila .m{font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.aging-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3)}
.aging-caja{border:1px solid var(--gris-borde);border-radius:10px;padding:10px 12px;text-align:center}
.aging-caja b{display:block;font-size:17px;color:var(--morado);font-variant-numeric:tabular-nums}
.aging-caja span{font-size:11px;color:var(--texto-suave)}

/* ---- Lo que hay que saber al recibir al perrito --------------------- */
.as-ficha{display:flex;flex-direction:column;gap:8px;margin-top:var(--sp-3);padding:12px 14px;
  border-radius:10px;border:1px solid var(--gris-borde);background:var(--gris-piedra)}
.as-ficha .linea{display:flex;gap:8px;align-items:flex-start;font-size:12.5px;color:var(--morado)}
.as-ficha .linea .et{font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);min-width:104px;flex:none;padding-top:1px}
.as-ficha .linea .vl{flex:1 1 auto;overflow-wrap:anywhere}
.as-ficha .nota-familia{border-left:3px solid var(--amarillo);padding-left:10px;font-style:italic}
.as-ficha .alerta{color:var(--rojo);font-weight:600}
.busca-op .ini{width:26px;height:26px;border-radius:50%;flex:none;display:flex;align-items:center;
  justify-content:center;font-size:10.5px;font-weight:700;color:var(--morado)}
.busca-op .sub{font-size:11.5px;color:var(--texto-suave)}

.m4-periodo{margin-left:auto}
.m4-periodo .periodo-pill{font-size:12px;padding:6px 14px}
.tabla-movs{table-layout:fixed;width:100%}
.tabla-movs th,.tabla-movs td{font-size:12.5px}
.tabla-movs th:nth-child(1),.tabla-movs td:nth-child(1){width:12%}
.tabla-movs th:nth-child(2),.tabla-movs td:nth-child(2){width:20%}
.tabla-movs th:nth-child(3),.tabla-movs td:nth-child(3){width:46%}
.tabla-movs th:nth-child(4),.tabla-movs td:nth-child(4){width:22%}
.tabla-movs td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
.mov-flecha{color:var(--texto-suave);margin:0 5px}
.mov-tipo{display:inline-flex;align-items:center;gap:6px}
.mov-tipo i{width:7px;height:7px;border-radius:50%;display:block;flex:none}
.m4-pend-punto{width:7px;height:7px;border-radius:50%;flex:none;display:block}
/* Movimientos recientes: cinco columnas en una tarjeta angosta. Sin anchos
   explícitos, "Responsable" se estiraba a lo ancho y el movimiento se
   partía en varios renglones. Repartidas a mano, cada dato cabe en su
   línea. Y los renglones respiran para llenar la tarjeta sin hueco abajo. */
.tabla-movs{table-layout:fixed;width:100%}
.tabla-movs th:nth-child(1),.tabla-movs td:nth-child(1){width:12%}
.tabla-movs th:nth-child(2),.tabla-movs td:nth-child(2){width:17%}
.tabla-movs th:nth-child(3),.tabla-movs td:nth-child(3){width:30%}
.tabla-movs th:nth-child(4),.tabla-movs td:nth-child(4){width:23%}
.tabla-movs th:nth-child(5),.tabla-movs td:nth-child(5){width:18%}
.tabla-movs td{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding-top:15px;padding-bottom:15px}
.tabla-movs .mov-tipo{display:flex;align-items:center;gap:7px;min-width:0}
.tabla-movs .mov-tipo i{flex:none;width:8px;height:8px;border-radius:50%;display:block}
/* Pendientes de hoy: seis renglones repartidos, sin hueco al pie */
#m4-pendientes .m4-pend-fila{padding-top:13px;padding-bottom:13px}
/* =====================================================================
   DASHBOARD · CALIDAD
   Cuatro cifras que no estaban porque no había de dónde sacarlas. Ahora
   cada una tiene su fuente: la satisfacción sale de lo que califica el
   cliente, las quejas de una incidencia de tipo Queja, el tiempo de
   respuesta de la cola de mensajes y las incidencias del módulo que ya
   las registra. Si una fuente está vacía, la cifra dice que no hay dato.
   ===================================================================== */
.cal-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:var(--sp-4)}
.cal-caja{display:flex;flex-direction:column;gap:4px;padding:var(--sp-4);border-radius:var(--r-lg);
  border:1px solid var(--gris-borde);background:var(--blanco)}
.cal-et{font-size:11.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--texto-suave)}
.cal-dato{display:flex;align-items:baseline;gap:5px;font-size:28px;font-weight:700;
  color:var(--morado);line-height:1.1;font-variant-numeric:tabular-nums}
.cal-de{font-size:13px;font-weight:600;color:var(--texto-suave)}
.cal-estrellas{display:flex;gap:2px;font-size:15px;line-height:1}
.cal-estrella{color:var(--gris-borde)}
.cal-estrella.on{color:var(--amarillo)}
.cal-pie{font-size:12px;color:var(--texto-suave);line-height:1.4}
.cal-caja .card-accion{align-self:flex-start;margin-top:6px}
.mc-calificar{display:flex;align-items:center;gap:6px;margin-top:6px;flex-wrap:wrap}
.mc-calificar .et{font-size:12px;color:var(--texto-suave)}
.mc-estrella{background:none;border:0;padding:0 1px;font-size:17px;line-height:1;cursor:pointer;
  color:var(--gris-borde);font-family:inherit}
.mc-estrella:hover,.mc-estrella.on{color:var(--amarillo)}
.mc-calificada{font-size:12px;color:var(--verde);font-weight:600}
/* Paquetes prepagados: cuántas visitas lleva usadas cada perrito */
.paq-fila{display:flex;flex-direction:column;gap:5px;padding:11px 0}
.paq-fila + .paq-fila{border-top:1px solid var(--gris-borde)}
.paq-cab{display:flex;align-items:baseline;gap:8px;font-size:13px;flex-wrap:wrap}
.paq-cab b{color:var(--morado);font-weight:600}
.paq-cab .tr{color:var(--texto-suave);font-size:12.5px}
.paq-cab .ses{margin-left:auto;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.paq-barra{height:7px;border-radius:999px;background:var(--gris-piedra);overflow:hidden}
.paq-barra i{display:block;height:100%;border-radius:999px;background:var(--verde);min-width:3px}
.paq-pie{font-size:11.5px;color:var(--texto-suave)}
/* Un renglón de dinero que se puede abrir se comporta como tal */
.fila-clicable{cursor:pointer}
.fila-clicable:hover{background:var(--gris-piedra)}
/* Ventas mensuales: la venta real y la meta, una barra cada una */
.m7-meses-grid .mes-par{display:flex;gap:3px;align-items:flex-end;justify-content:center;
  width:100%;height:100%}
.m7-meses-grid .mes-par i{display:block;width:10px;border-radius:3px 3px 0 0;min-height:2px}
.m7-meses-grid .mes-par .b-real{background:var(--amarillo)}
.m7-meses-grid .mes-par .b-meta{background:var(--verde);opacity:.55}
.m7-meses-grid .mes-label.cumplio{color:var(--verde);font-weight:700}

/* Servicios más vendidos: los nueve, con su barra y su monto */
.m7-rank{display:grid;grid-template-columns:22px minmax(74px,1fr) minmax(0,1.1fr) 76px 30px;
  align-items:center;gap:8px;padding:7px 0}
.m7-rank + .m7-rank{border-top:1px solid var(--gris-borde)}
.m7-rank .pos{font-size:11.5px;font-weight:700;color:var(--texto-suave);text-align:center}
.m7-rank .nom{font-size:13px;color:var(--morado);overflow-wrap:anywhere}
.m7-rank .pista{height:8px;border-radius:999px;background:var(--gris-piedra);overflow:hidden}
.m7-rank .pista i{display:block;height:100%;border-radius:999px;background:var(--amarillo);min-width:2px}
.m7-rank .mt{font-size:12.5px;font-weight:600;color:var(--morado);text-align:right;
  font-variant-numeric:tabular-nums}
.m7-rank .n{font-size:13px;font-weight:700;color:var(--morado);text-align:right;
  font-variant-numeric:tabular-nums}
.m7-rank.sin .nom,.m7-rank.sin .mt,.m7-rank.sin .n{color:var(--texto-suave);opacity:.7}
.m7-rank.sin .pista i{opacity:.3}

/* El chip de la tabla de ventas no se corta ni pierde su redondeo */
.tabla-ventas td .chip{display:inline-flex;align-items:center;border-radius:var(--r-pill);
  padding:3px 9px;font-size:11.5px;white-space:nowrap}
.tabla-ventas td:nth-last-child(2),.tabla-cobranza td:nth-last-child(3){overflow:visible}
.tabla-ventas td{vertical-align:middle}
/* Los filtros del módulo dejan de ser desplegables del sistema: el menú
   gris del navegador no conserva ni la tipografía ni los colores de la
   casa, y aparecía justo en medio de la barra de controles. */
/* 186px cortaban "Todas las formas de pago" en la última sílaba. */
.m7-filtro{width:186px;flex:none}
.m7-filtro:last-of-type{width:232px}
.m7-filtro .input-lista{font-size:13px;padding:8px 28px 8px 12px;cursor:pointer}
.input-lista{cursor:pointer;transition:border-color .16s ease,background .16s ease}
.input-lista:hover{border-color:var(--amarillo);background:var(--realce)}
.busca-caja:has(.busca-lista:not([hidden])) .input-lista{border-color:var(--amarillo);
  box-shadow:0 0 0 3px rgba(254,200,0,.22)}
.busca-caja{position:relative}
/* Las listas que ya eran propias (buscadores y filtros) usan exactamente el
   mismo panel, el mismo realce morado y la misma flecha que las que
   sustituyen a un <select>. Una sola lista en toda la plataforma. */
.busca-flecha{position:absolute;right:11px;top:50%;margin-top:-4px;width:9px;height:9px;
  border-right:2px solid var(--morado);border-bottom:2px solid var(--morado);
  transform:rotate(45deg);pointer-events:none;transition:transform .2s ease;opacity:.75}
.busca-caja:has(.busca-lista:not([hidden])) .busca-flecha{transform:rotate(225deg);margin-top:-1px}
.busca-lista{position:absolute;left:0;right:0;top:calc(100% + 5px);z-index:60;max-height:260px;
  overflow-y:auto;background:var(--blanco);border:1px solid var(--gris-borde);
  border-radius:var(--r-md);box-shadow:0 12px 30px rgba(43,23,52,.16);padding:5px}
.busca-op{display:flex;align-items:center;gap:9px;width:100%;box-sizing:border-box;border:0;
  background:none;border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;
  text-align:left;cursor:pointer;color:var(--morado);transition:background .12s ease}
.busca-op:hover,.busca-op:focus-visible,.busca-op.marcada{background:var(--realce);outline:none}
.busca-op.elegida{background:var(--realce-fuerte);font-weight:600}
.busca-op .fam{margin-left:auto;font-size:12px;color:var(--texto-suave)}

/* ── UN PUNTO DE COLOR EN EL DESPLEGABLE ────────────────────────────────────
   Edna, 29 oct 2026, sobre el selector de temperamento: «hay que cargar los
   colores que se destinaron para cada temperamento para que estén más
   visuales e identificables por color».
   Los colores ya existían desde el 22 oct en `.chip-agresion[data-nivel]` —el
   chip que LEE el nivel— y el desplegable que lo CAPTURA los enseñaba en
   texto gris. El color vivía donde se consulta el dato y no donde se elige,
   que es donde evita equivocarse.
   Se reusa el mismo punto que el chip (`.chip-dot`, 10 px redondo) para que
   elegir «Riesgo» y leer «Riesgo» se vean igual. */
.busca-punto{width:10px;height:10px;border-radius:50%;flex:none}

/* ── CAMPOS QUE SE REPITEN ──────────────────────────────────────────────────
   Edna, 29 oct 2026: «normalmente se capturan entre 2 y 3 vacunas, para que
   consideres agregar un botón o algo para agregar más vacunas. Y
   desparasitaciones».
   Cada fila es una vacuna (o una desparasitación) y lleva su propia aspa para
   quitarla. La columna del aspa es fija y estrecha para que las cajas de texto
   queden alineadas de una fila a otra: con el aspa dentro del flujo, dos filas
   con etiquetas de distinto largo dejaban los campos escalonados. */
.nm-repetible > label{display:block;margin-bottom:6px}
/* FLEX Y NO REJILLA, y el porqué vale la pena. Mi primera versión era
   `grid-template-columns:1fr 1fr 28px` contando dos `<input>` por fila. Medido
   en pantalla: la segunda celda de una vacuna NO es un input — el selector de
   fecha la envuelve en un `div.fecha-caja`—, así que `:has(> .input:only-of-type)`
   casaba, la rejilla pasaba a `1fr 28px` y la caja de «próxima aplicación»
   acababa con 28 px de ancho. Una fila de 20 px no es un campo estrecho: es un
   campo que nadie puede usar.
   Con flex da igual qué sea cada hijo y cuántos haya: todos reparten, y sólo
   el aspa tiene medida fija. */
.nm-rep-cab{display:flex;gap:8px;margin-bottom:4px}
.nm-rep-cab > span{flex:1 1 0;min-width:0;font-size:11px;font-weight:600;
  letter-spacing:.04em;text-transform:uppercase;color:var(--texto-suave)}
/* El hueco del aspa también en la cabecera, para que los rótulos caigan justo
   encima de su campo y no corridos media columna. */
.nm-rep-cab::after{content:'';flex:0 0 26px}
.nm-fila-rep{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.nm-fila-rep > *:not(.nm-quitar){flex:1 1 0;min-width:0}
.nm-fila-rep > *:not(.nm-quitar) .input,
.nm-fila-rep > .input{width:100%;box-sizing:border-box}
.nm-quitar{flex:0 0 26px;width:26px;height:26px;border-radius:50%;
  border:1px solid var(--gris-borde);background:none;color:var(--texto-suave);
  font-size:16px;line-height:1;cursor:pointer;padding:0}
.nm-quitar:hover,.nm-quitar:focus-visible{border-color:var(--morado);
  color:var(--morado);background:var(--realce);outline:none}
/* La primera fila no trae aspa —no se puede quedar sin ninguna—, así que se le
   deja el mismo hueco para que las cajas de una fila y otra queden alineadas. */
.nm-fila-rep:not(:has(.nm-quitar))::after{content:'';flex:0 0 26px}
.nm-mas{margin-top:2px;font-size:13px;padding:6px 12px}
/* A TODO EL ANCHO, y sólo estos dos. Dos intentos antes de acertar, los dos
   por suponer en vez de mirar:
     1 · le puse `form-full` en el marcado. No hizo nada: `.campo-form` trae
         `flex:1 1 calc(50% - 16px)` y gana.
     2 · le puse `grid-column:1 / -1`. Tampoco: medido, `.form-grid` tiene
         `display:flex`, no es una rejilla pese al nombre.
   Lo que manda aquí es el `flex`, así que es ahí donde se dice. Acotado a
   `.nm-repetible` para no cambiarle el ancho a los demás campos de toda la
   plataforma: una fila con dos campos y un aspa necesita el ancho; los otros
   no lo pidieron. */
.form-grid > .campo-form.nm-repetible{flex:1 1 100%}
/* Y con la lista cerrada. Un `<input>` no admite hijos, así que el punto lo
   pone la caja y el texto se corre para dejarle sitio. */
.busca-caja.con-punto > .input-lista{padding-left:32px}
.busca-caja.con-punto::before{content:'';position:absolute;left:13px;top:50%;
  transform:translateY(-50%);width:10px;height:10px;border-radius:50%;
  background:var(--punto);pointer-events:none;z-index:1}
.busca-vacio{padding:10px 12px;font-size:13px;color:var(--texto-suave)}

/* Celdas de una fila: mismo alto exacto, sin importar qué lleve cada una.
   Antes las tarjetas estiraban pero su contenido podía empujar; ahora la
   fila fija el alto y el cuerpo de cada tarjeta se acomoda dentro. */
/* `grid-auto-rows:1fr` era demasiado romo: forzaba el alto de la fila y
   dejaba a las filas pegadas entre sí. Basta con que cada tarjeta sea una
   columna flexible y que su cuerpo crezca; el estirado de la rejilla hace
   el resto, y la separación entre filas vuelve a ser la del contenedor. */
/* Era var(--sp-4) = 16 px: la unica medida de la hoja que no era
   --hueco, y por eso tres filas quedaban separadas 16 y el resto 12.
   El hueco vertical lo pone ahora el contenedor (ver final de hoja). */
.grid-3,.grid-2,.grid-2-1{margin-bottom:0}
.grid-3>.card,.grid-2>.card,.grid-2-1>.card{margin-bottom:0;display:flex;flex-direction:column}
.grid-2-1>.col,.grid-2-1>.m7-col-der{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.grid-2-1>.col>.card,.grid-2-1>.m7-col-der>.card{margin-bottom:0;display:flex;flex-direction:column}
/* el cuerpo de la tarjeta —lo que va después del encabezado— es lo que
   crece para igualar alturas, nunca el encabezado */
.grid-3>.card>.card-head,.grid-2>.card>.card-head,
.grid-2-1 .card>.card-head{flex:none}
.grid-3>.card>.card-head~*:last-child,
.grid-2>.card>.card-head~*:last-child{flex:1 1 auto;min-height:0}
/* Más ancho para la gráfica de la tarjeta: el eje adelgaza y la leyenda
   se encoge para no robarle renglón. */
#m7 .m7-chart-eje{width:34px;font-size:9.5px}
#m7 .m7-chart-wrap{gap:6px}
#m7 .m7-chart-leyenda{gap:10px;margin-top:10px;font-size:10.5px;flex-wrap:wrap}
#m7 .m7-leyenda-punto{width:7px;height:7px}
#m7-meses{gap:2px;justify-content:space-around}

/* El reporte anual va en pantalla aparte: ahí la gráfica puede respirar */
.modal-reporte .modal-caja{max-width:980px}
.m7-chart-grande{gap:12px}
.m7-chart-grande .m7-chart-eje{height:320px;width:48px;font-size:11px}
.m7-chart-grande .m7-chart-area{height:320px}
.m7-chart-grande .meses-grid{height:320px;gap:6px}
.m7-chart-grande .mes-par{gap:5px}
.m7-chart-grande .mes-label{font-size:12px}
.m7-resumen-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--sp-3);margin-top:var(--sp-5)}
.m7-resumen-meta .caja{padding:12px 14px;border:1px solid var(--gris-borde);border-radius:10px}
.m7-resumen-meta .et{display:block;font-size:11px;letter-spacing:.04em;text-transform:uppercase;
  color:var(--texto-suave);margin-bottom:3px}
.m7-resumen-meta .vl{font-size:19px;font-weight:700;color:var(--morado);
  font-variant-numeric:tabular-nums}
.m7-resumen-meta .pie{display:block;font-size:11.5px;color:var(--texto-suave);margin-top:2px}

/* Ventas por servicio: las columnas llenan el ancho de la tarjeta */
.barra-h-fila.con-monto{grid-template-columns:minmax(76px,0.95fr) minmax(0,1.9fr) 40px 74px;gap:8px}
/* La gráfica de cobranza vivía con barras de 28px: diez meses no caben en
   un tercio de pantalla y se salían de la tarjeta. Barras estrechas, y el
   área con el mismo alto que su eje para que los porcentajes tengan
   contra qué medirse. */
#m8-chart-eje,#m8 .m7-chart-area{height:150px}
#m8-meses{gap:4px;height:150px;justify-content:space-around}
#m8-meses .mes-barra{width:14px}
#m8-meses .mes-label{font-size:10px;margin-top:5px}
#m8 .m7-chart-wrap{overflow:hidden}

/* La cifra del centro del anillo no cabía: se ajusta al hueco real que
   deja el trazo y la etiqueta baja de tamaño con ella. */
.anillo .centro{padding:0 8px;text-align:center;line-height:1.15}
.anillo .centro span:first-child{font-size:14px;font-weight:700;white-space:nowrap}
#m8-dona .anillo,#m7-dona .anillo{flex:none}
/* El anillo manda y las cifras bajan al pie, como en Cobranza. */
#m7-dona .dona-centrada{height:100%;justify-content:flex-start}
#m7-dona .anillo.grande{width:100%;max-width:252px;height:auto;aspect-ratio:1;margin:0 auto}
#m7-dona .anillo .pista,#m7-dona .anillo .valor{stroke-width:8}
#m7-dona .anillo.grande .centro span:first-child{font-size:30px}
#m7-dona .dona-abajo{margin-top:auto;grid-template-columns:repeat(auto-fit,minmax(92px,1fr))}
#m7 .grid-2-1 .col > .card:last-child{display:flex;flex-direction:column}
#m7-dona{flex:1 1 auto;display:flex;flex-direction:column}
.dona-wrap{flex-wrap:wrap;row-gap:var(--sp-4)}
.dona-leyenda{min-width:132px}
/* Ventas por servicio: once renglones pegados se leían como un bloque.
   Cada uno respira y se separa con una línea. */
#m7-por-servicio.barra-h{gap:0}
#m7-por-servicio .barra-h-fila{padding:11px 0}
#m7-por-servicio .barra-h-fila + .barra-h-fila{border-top:1px solid var(--gris-borde)}
#m7-por-servicio .barra-h-fila.con-monto{gap:12px}
/* La fila de "Ventas por servicio" tenía tres columnas y el pintor metía
   cuatro cosas: el monto se iba a un segundo renglón, desfasado bajo la
   barra. Esta variante reserva su columna. */
.barra-h-fila.con-monto{grid-template-columns:minmax(84px,1.1fr) minmax(0,1.6fr) 44px 78px}
.barra-h-fila.con-monto .barra-h-label{overflow-wrap:anywhere}
.barra-h-fila.con-monto .m-monto{font-size:13px;font-weight:700;text-align:right;
  color:var(--morado);font-variant-numeric:tabular-nums}
.mp-fila{display:grid;grid-template-columns:30px minmax(96px,1fr) 92px 60px 70px;align-items:center;
  gap:10px;padding:9px 0}
.mp-fila + .mp-fila{border-top:1px solid var(--gris-borde)}
.mp-punto{width:12px;height:12px;border-radius:50%;justify-self:center}
.mp-fila .n{font-size:13px;font-weight:600;color:var(--morado);text-align:right;
  font-variant-numeric:tabular-nums}
.mp-fila .pc{font-size:12.5px;color:var(--texto-suave);text-align:right}
.mp-nuevo{display:grid;grid-template-columns:minmax(0,1fr) 150px auto;gap:var(--sp-3);
  align-items:end;margin-top:var(--sp-4);padding-top:var(--sp-4);
  border-top:1px solid var(--gris-borde)}
.mp-nuevo .btn{font-family:inherit;cursor:pointer}
/* Recordatorios de cobranza: alto fijo, caben tres y el resto en Ver más.
   Antes la tarjeta crecía con la lista y empujaba todo lo de abajo. */
#m8-recordatorios{overflow:visible}
/* Las tres tarjetas de la fila cierran a la misma altura y la gráfica de
   evolución gana alto: con 150px los meses salían como rayitas. */
.m8-fila1,.m8-fila2,.m8-fila3{align-items:stretch}
.m8-fila1 > .card,.m8-fila2 > .card,.m8-fila3 > .card{display:flex;flex-direction:column;min-width:0}
.m8-fila1 > .col{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.m8-fila1 > .col > .card{flex:1 1 0;margin-top:0;display:flex;flex-direction:column;min-height:0}
.m8-fila2 .m8-evolucion .m7-chart-eje,.m8-fila2 .m8-evolucion .m7-chart-area{height:250px}
.m8-fila2 .m8-evolucion .meses-grid{height:250px;align-items:flex-end}
/* El nombre del mes tiene su renglón reservado: con las barras al 100% del
   alto quedaba fuera del marco, que recorta. */
.m8-fila2 .m8-evolucion .mes-col{height:100%;justify-content:flex-end}
.m8-fila2 .m8-evolucion .mes-par{flex:1 1 auto;min-height:0}
.m8-fila2 .m8-evolucion .mes-label{flex:none;margin-top:6px;line-height:1.2;white-space:nowrap}
.m8-filaR{align-items:stretch}
.m8-filaR > .card{display:flex;flex-direction:column;min-width:0}
.m8-fila2 .m8-evolucion .mes-par{display:flex;align-items:flex-end;gap:4px;
  flex:1 1 auto;min-height:0;width:100%;justify-content:center}
.m8-fila2 .m8-evolucion .mes-col{justify-content:flex-end}
.m8-fila2 .m8-evolucion .mes-label{flex:none;margin-top:6px;line-height:1.2}
.m8-b-deber{display:block;width:12px;border-radius:3px 3px 0 0;background:var(--amarillo);min-height:2px}
.m8-b-cobrado{display:block;width:12px;border-radius:3px 3px 0 0;background:var(--verde);min-height:2px}
/* Cobrado vs. por cobrar y Formas de pago: cada una su tarjeta, nunca
   encimadas, y las dos cierran a la misma altura. */
.m8-fila3{align-items:stretch}
/* Arriba, no al centro: las dos leyendas miden distinto y centrar cada
   tarjeta por su cuenta dejaba los anillos a alturas diferentes. */
.m8-fila3 > .card{display:flex;flex-direction:column;min-width:0;justify-content:flex-start}
.m8-fila3 .dona-centrada{flex:0 0 auto;justify-content:flex-start}
.m8-fila3 .dona-wrap{flex-wrap:wrap;gap:var(--sp-4);justify-content:center}
.m8-fila3 .anillo{flex:none}
.m8-fila3 .dona-leyenda{flex:1 1 180px;min-width:0}
/* Estado de cuentas: ahora es un círculo */
#m8-estados .anillo.grande{max-width:132px;margin:0 auto}
/* Cobranza por servicio: etiqueta, barra y número en su propio carril, para
   que el número deje de caer debajo del nombre del servicio. */
#m7-por-servicio .barra-h-fila,#m8-por-servicio .barra-h-fila{
  grid-template-columns:minmax(0,1.6fr) minmax(0,1fr) 40px 72px;gap:10px}
#m7-por-servicio .barra-h-label,#m8-por-servicio .barra-h-label{font-size:12.5px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#m7-por-servicio .barra-h-num,#m8-por-servicio .barra-h-num{font-size:12.5px;
  text-align:right;white-space:nowrap;min-width:0}
#m8-por-servicio .barra-h-fila{
  gap:10px;align-items:center}
#m8-por-servicio .barra-h-label{font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#m8-por-servicio .barra-h-num{text-align:right;white-space:nowrap;font-size:12.5px}
/* La familia abre su desglose; debajo del nombre va cuánto debe en total */
.m8-familia{border:0;background:none;padding:0;font:inherit;text-align:left;cursor:pointer;
  color:var(--morado);font-weight:600;display:flex;flex-direction:column;gap:1px;min-width:0;width:100%}
.m8-familia:hover{text-decoration:underline}
.m8-familia .sub,.m8-tabla-cobranza .sub{display:block;font-size:11px;font-weight:500;
  color:var(--texto-suave);text-decoration:none}
.m8-acuenta{border:1px solid var(--amarillo);background:var(--blanco);border-radius:999px;
  cursor:pointer;font:inherit;font-size:11.5px;font-weight:600;padding:4px 11px;color:var(--morado);
  white-space:nowrap;display:inline-flex;align-items:center;line-height:1.3;margin-left:6px}
.m8-acuenta:hover{background:var(--realce)}
/* Estado de cuentas cierra donde cierra Cobros y pagos, para que lo de
   abajo pueda subir a la altura de la antigüedad de saldos. */
.grid-2-1>.col,.grid-2-1>div:not(.col){align-self:stretch}
#m8-estados{flex:1 1 auto;min-height:0;overflow-y:auto}
.m7-chart-grande .mes-label.futuro{opacity:.45}
/* Resumen financiero: cuatro renglones que llenan la tarjeta. Al quitar
   las dos barras del pie quedaba hueco, así que los renglones se reparten
   el alto en vez de apelotonarse arriba. */
#m0 .fin-lista{flex:1 1 auto;justify-content:space-between}
#m0 .fin-fila{padding:var(--sp-4) 0;flex:1 1 auto}
#m0 .fin-fila:last-child{border-bottom:0}
#m0 .fin-et{font-size:14px}
#m0 .fin-monto{font-size:23px}
#m0 .fin-fila .icon-badge{width:40px;height:40px;margin-bottom:0;flex:none}
#m0 .fin-fila .icon-badge svg.icon{width:20px;height:20px}

/* =====================================================================
   MÓDULO 9 — CONTROL DE GASTOS
   ===================================================================== */
.m9-controles{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;margin-bottom:var(--hueco)}
.m9-controles .periodo-switch{margin-left:auto}
.m9-fila1,.m9-fila2{align-items:stretch}
.m9-fila1 > .card,.m9-fila2 > .card{display:flex;flex-direction:column;min-width:0}
.m9-fila2 > .col{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.m9-fila2 > .col > .card{margin-top:0;display:flex;flex-direction:column;min-width:0}
/* Más chica a propósito: el año completo vive en el Ver más, y al bajar
   el alto, Gastos registrados sube y termina a la par de Gastos por área. */
.m9-chart .m7-chart-eje,.m9-chart .m7-chart-area{height:132px}
.m9-meses{height:132px;align-items:flex-end;gap:6px}
.m9-meses .mes-col{height:100%;justify-content:flex-end}
.m9-meses .mes-label{flex:none;margin-top:5px;line-height:1.2;white-space:nowrap}
/* El año completo, en grande, dentro del modal */
.m9-chart-grande .m7-chart-eje,.m9-chart-grande .m7-chart-area{height:320px}
.m9-chart-grande .meses-grid{height:320px;gap:10px}
.m9-chart-grande .mes-label{font-size:12px}
/* Cada mes es una pila: el alto total es el gasto y los tramos son las
   categorías. Una barra por mes sólo diría cuánto; así dice en qué. */
.m9-pila{display:flex;flex-direction:column-reverse;width:100%;max-width:30px;margin:0 auto;
  border-radius:4px 4px 0 0;overflow:hidden;min-height:3px}
.m9-pila i{display:block;width:100%}
.m9-leyenda{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:var(--sp-4)}
.m9-ley-it{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--texto-suave);white-space:nowrap}
.m9-ley-it i{width:9px;height:9px;border-radius:50%;flex:none;display:block}
.m9-ley-it b{color:var(--morado);font-variant-numeric:tabular-nums}
.m9-cat{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.m9-cat i{width:8px;height:8px;border-radius:50%;flex:none;display:block}
.m9-tabla{table-layout:fixed;width:100%}
/* Anchos recalculados el 14-oct-2026 contra el contenido real: la columna
   que lleva un chip recibe lo que el chip mide mas su aire, y el sobrante
   se reparte entre las columnas de prosa, que son las que pueden ceder
   porque se recortan con puntos y se siguen leyendo. Antes el %% estaba
   escrito a mano para unos textos que ya cambiaron, y el chip se partia. */
.m9-tabla th:nth-child(1),.m9-tabla td:nth-child(1){width:14%}
.m9-tabla th:nth-child(2),.m9-tabla td:nth-child(2){width:18.9%}
.m9-tabla th:nth-child(3),.m9-tabla td:nth-child(3){width:16.4%}
.m9-tabla th:nth-child(4),.m9-tabla td:nth-child(4){width:15.3%}
.m9-tabla th:nth-child(5),.m9-tabla td:nth-child(5){width:13.7%}
.m9-tabla th:nth-child(6),.m9-tabla td:nth-child(6){width:15.6%}
.m9-tabla th:nth-child(7),.m9-tabla td:nth-child(7){width:6.1%;text-align:right}
.m9-tabla td{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m9-tabla tbody tr{cursor:pointer}
.m9-tabla tbody tr:hover td{background:var(--realce)}
.m9-pie{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3);flex-wrap:wrap}
.m9-paginas{display:flex;gap:4px;margin-left:auto;flex-wrap:wrap}
.m9-pag{min-width:28px;height:28px;border-radius:7px;border:1px solid var(--gris-borde);
  background:var(--blanco);color:var(--morado);font:inherit;font-size:12.5px;font-weight:600;cursor:pointer}
.m9-pag:hover:not(:disabled){border-color:var(--amarillo);background:var(--realce)}
.m9-pag.activa{background:var(--amarillo);border-color:var(--amarillo)}
.m9-pag:disabled{opacity:.35;cursor:not-allowed}
.m9-top-fila{display:flex;align-items:center;gap:10px;padding:9px 0;cursor:pointer}
.m9-top-fila + .m9-top-fila{border-top:1px solid var(--gris-borde)}
.m9-top-fila:hover{background:var(--realce)}
.m9-top-n{flex:none;width:21px;height:21px;border-radius:50%;background:var(--gris-piedra);
  display:grid;place-items:center;font-size:11px;font-weight:700;color:var(--morado)}
.m9-top-punto{flex:none;width:9px;height:9px;border-radius:50%;display:block}
.m9-top-txt{flex:1;min-width:0}
.m9-top-txt b{display:block;font-size:13px;color:var(--morado);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.m9-top-txt span{font-size:11.5px;color:var(--texto-suave)}
.m9-top-monto{flex:none;font-size:13.5px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
.m9-avisos > .card{display:flex;flex-direction:column;gap:9px}
.m9-aviso-cab{display:flex;align-items:center;gap:8px;font-size:13.5px;color:var(--morado)}
.m9-aviso-cab svg.icon{width:17px;height:17px;flex:none}
.m9-aviso-txt{font-size:12.5px;color:var(--texto-suave);line-height:1.5}
.m9-aviso-pie{font-size:12px;font-weight:600;color:var(--morado);font-variant-numeric:tabular-nums}
.m9-aviso .card-accion{align-self:flex-start}
.m9-aviso-meta{border-left:3px solid var(--verde)}
.m9-aviso-alerta{border-left:3px solid var(--rojo)}
.m9-aviso-ahorro{border-left:3px solid var(--morado)}
.rg-recibo{display:flex;gap:var(--sp-4);align-items:flex-start;flex-wrap:wrap;margin-top:var(--sp-3)}
.rg-recibo-previa{flex:none;width:104px;height:104px;border-radius:var(--r-md);overflow:hidden;
  border:1px dashed var(--gris-borde);background:var(--gris-piedra);display:grid;place-items:center}
.rg-recibo-previa img{width:100%;height:100%;object-fit:cover}

/* =====================================================================
   MÓDULO 11 — MARKETING
   ===================================================================== */
.mk-fila1,.mk-fila2,.mk-fila3,.mk-fila4{align-items:stretch}
.mk-fila1 > .card,.mk-fila2 > .card,.mk-fila3 > .card,.mk-fila4 > .card{display:flex;flex-direction:column;min-width:0}
.mk-fila2 > .col{display:flex;flex-direction:column;gap:var(--hueco);min-width:0}
.mk-fila2 > .col > .card{margin-top:0;display:flex;flex-direction:column;min-width:0}
.mk-svg{width:100%;height:auto;display:block}
.mk-tabla{table-layout:fixed;width:100%}
/* Anchos recalculados el 14-oct-2026 contra el contenido real: la columna
   que lleva un chip recibe lo que el chip mide mas su aire, y el sobrante
   se reparte entre las columnas de prosa, que son las que pueden ceder
   porque se recortan con puntos y se siguen leyendo. Antes el %% estaba
   escrito a mano para unos textos que ya cambiaron, y el chip se partia. */
.mk-tabla th:nth-child(1),.mk-tabla td:nth-child(1){width:17.9%}
.mk-tabla th:nth-child(2),.mk-tabla td:nth-child(2){width:14.3%}
.mk-tabla th:nth-child(3),.mk-tabla td:nth-child(3){width:14%}
.mk-tabla th:nth-child(4),.mk-tabla td:nth-child(4){width:15.2%}
.mk-tabla th:nth-child(5),.mk-tabla td:nth-child(5){width:17.3%}
.mk-tabla th:nth-child(6),.mk-tabla td:nth-child(6){width:15.2%}
.mk-tabla th:nth-child(7),.mk-tabla td:nth-child(7){width:6.2%;text-align:right}
.mk-tabla td{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mk-tabla tbody tr{cursor:pointer}
.mk-tabla tbody tr:hover td{background:var(--realce)}
.mk-tabla .sub{display:block;font-size:11px;font-weight:500;color:var(--texto-suave)}
.mk-post-red{flex:none;width:24px;height:24px;border-radius:7px;display:grid;place-items:center;
  color:#fff;font-size:11px;font-weight:700}
.mk-posts{display:flex;flex-direction:column;gap:2px}
.mk-post{display:grid;grid-template-columns:24px minmax(0,1fr);grid-template-rows:auto auto;
  gap:2px 9px;align-items:center;padding:8px 0}
.mk-post + .mk-post{border-top:1px solid var(--gris-borde)}
.mk-post .mk-post-red{grid-row:1 / span 2}
.mk-post b{font-size:13px;color:var(--morado);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mk-post span:last-child{font-size:11.5px;color:var(--texto-suave)}
.mk-prox{display:flex;align-items:center;gap:9px;padding:8px 0}
.mk-prox + .mk-prox{border-top:1px solid var(--gris-borde)}
.mk-prox-fecha{flex:none;width:34px;text-align:center;line-height:1.1}
.mk-prox-fecha b{display:block;font-size:15px;font-weight:700;color:var(--morado)}
.mk-prox-fecha span{font-size:9px;letter-spacing:.06em;color:var(--texto-suave)}
.mk-prox-txt{flex:1;min-width:0;font-size:12.5px;color:var(--morado);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.mk-red-fila{display:flex;align-items:center;gap:10px;padding:10px 0}
.mk-red-fila + .mk-red-fila{border-top:1px solid var(--gris-borde)}
.mk-red-txt{flex:1;min-width:0}
.mk-red-txt b{display:block;font-size:13.5px;color:var(--morado)}
.mk-red-txt span{font-size:11.5px;color:var(--texto-suave)}
.mk-red-pct{font-size:14px;font-weight:700;color:var(--morado);font-variant-numeric:tabular-nums}
/* Calendario de contenido: una cuadrícula de mes que no se come la pantalla */
.mk-cal-rejilla{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
.mk-cal-cab{font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--texto-suave);text-align:center;padding-bottom:4px}
.mk-cal-dia{min-height:74px;border:1px solid var(--gris-borde);border-radius:8px;padding:5px;
  background:var(--blanco);display:flex;flex-direction:column;gap:3px;min-width:0}
.mk-cal-dia.vacia{border:0;background:none}
.mk-cal-dia.hoy{border-color:var(--amarillo);border-width:2px}
.mk-cal-dia .num{font-size:11.5px;font-weight:700;color:var(--morado)}
.mk-cal-item{font-size:9.5px;line-height:1.25;border-left:3px solid var(--gris-borde);
  background:var(--gris-piedra);border-radius:4px;padding:2px 4px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;color:var(--morado)}
.mk-cal-item.prog{background:var(--realce);font-style:italic}
.mk-cal-mas{font-size:9.5px;font-weight:700;color:var(--texto-suave)}
@media (max-width:820px){ .mk-cal-dia{min-height:56px} }

/* =====================================================================
   MÓDULO 10 — COMUNICACIÓN CON CLIENTES
   Tres columnas: a quién le escribo, qué nos dijimos y quién es. Es la
   forma de una bandeja, no de un tablero, porque aquí se trabaja.
   ===================================================================== */
.cm-grid{display:grid;grid-template-columns:minmax(0,.95fr) minmax(0,1.5fr) minmax(0,.9fr);
  gap:var(--hueco);align-items:stretch;margin-bottom:var(--hueco)}
.cm-grid > .card{display:flex;flex-direction:column;min-width:0;height:520px;margin-bottom:0}
@media (max-width:1100px){ .cm-grid{grid-template-columns:minmax(0,1fr)}
  .cm-grid > .card{height:auto;max-height:460px} }
.cm-lista{flex:1 1 auto;min-height:0;overflow-y:auto;margin:0 calc(var(--sp-5) * -1);
  padding:0 var(--sp-5)}
.cm-item{display:flex;align-items:flex-start;gap:9px;width:100%;text-align:left;border:0;
  background:none;font:inherit;cursor:pointer;padding:10px 8px;border-radius:10px;margin-bottom:2px}
.cm-item:hover{background:var(--realce)}
.cm-item.activa{background:var(--realce-fuerte)}
.cm-foto{flex:none;width:36px;height:36px;border-radius:50%;object-fit:cover;display:block}
.cm-foto-ini{display:grid;place-items:center;background:var(--morado);color:#fff;
  font-size:12px;font-weight:700}
.cm-foto-g{width:44px;height:44px}
.cm-item-txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.cm-item-txt b{font-size:13px;color:var(--morado);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cm-item-sub{font-size:11px;color:var(--texto-suave)}
.cm-item-ult{font-size:11.5px;color:var(--texto-suave);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cm-item-der{flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
.cm-item-hora{font-size:10.5px;color:var(--texto-suave);white-space:nowrap}
.cm-canal-pt{width:8px;height:8px;border-radius:50%;display:block}
.cm-sinleer{min-width:17px;height:17px;border-radius:999px;background:var(--rojo);color:#fff;
  font-size:10px;font-weight:700;display:grid;place-items:center;padding:0 4px}
.cm-chat-cab{display:flex;align-items:center;gap:10px;padding-bottom:var(--sp-3);
  border-bottom:1px solid var(--gris-borde);margin-bottom:var(--sp-3);flex:none}
.cm-chat-id{flex:1;min-width:0}
.cm-chat-id b{display:block;font-size:14px;color:var(--morado)}
.cm-chat-id span{font-size:11.5px;color:var(--texto-suave)}
.cm-hilo{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:8px;
  padding-right:4px}
.cm-burbuja{max-width:78%;padding:9px 12px;border-radius:12px;display:flex;flex-direction:column;gap:3px}
.cm-burbuja.cliente{align-self:flex-start;background:var(--gris-piedra);border-bottom-left-radius:4px}
.cm-burbuja.casa{align-self:flex-end;background:rgba(151,209,10,.18);border-bottom-right-radius:4px}
.cm-txt{font-size:12.5px;line-height:1.45;color:var(--morado);overflow-wrap:anywhere}
.cm-hora{font-size:10px;color:var(--texto-suave);align-self:flex-end}
.cm-redactar{display:flex;gap:8px;align-items:center;margin-top:var(--sp-3);flex:none}
.cm-redactar .input{flex:1;min-width:0}
.cm-enviar{flex:none;width:38px;height:38px;border-radius:50%;border:0;background:var(--amarillo);
  color:var(--morado);cursor:pointer;display:grid;place-items:center}
.cm-enviar:hover{filter:brightness(.96)}
.cm-enviar svg.icon{width:17px;height:17px}
.cm-col-perfil{overflow-y:auto}
.cm-perfil-cab{display:flex;align-items:center;gap:10px;margin-bottom:var(--sp-3)}
.cm-perfil-cab b{font-size:13.5px;color:var(--morado)}
.cm-plantilla,.cm-regla{display:flex;align-items:center;gap:10px;padding:9px 0}
.cm-plantilla + .cm-plantilla,.cm-regla + .cm-regla{border-top:1px solid var(--gris-borde)}
.cm-plantilla-txt,.cm-regla-txt{flex:1;min-width:0}
.cm-plantilla-txt b,.cm-regla-txt b{display:block;font-size:12.5px;color:var(--morado)}
.cm-plantilla-txt span,.cm-regla-txt span{font-size:11px;color:var(--texto-suave);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.cm-switch{flex:none;width:38px;height:21px;border-radius:999px;border:0;cursor:pointer;
  background:var(--gris-borde);position:relative;transition:background .16s ease}
.cm-switch i{position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;
  background:#fff;transition:left .16s ease;display:block}
.cm-switch.on{background:var(--verde)}
.cm-switch.on i{left:19px}
.cm-pie{align-items:stretch}
.cm-pie > .card{display:flex;flex-direction:column;min-width:0}
#cm-dona .anillo.grande{max-width:122px;margin:0 auto}

/* El rescate sin foto no deja un hueco: lleva la huella de la casa */
.rescate-sinfoto{display:grid;place-items:center;background:var(--gris-piedra);color:var(--morado)}
.rescate-sinfoto svg{width:40%;height:40%;opacity:.45}

/* ═══ CELDAS A LA PAR · regla definitiva ═══════════════════════════════
   Este problema ha vuelto tres veces, y siempre por lo mismo: la regla
   anterior sólo alcanzaba a los contenedores que se llamaban "grid-algo".
   Cada módulo nuevo trajo su propio nombre —.m8-fila1, .m9-fila2, .mk-fila3,
   .cm-grid, .m7-cuerpo— y quedó fuera, así que el hueco en blanco reapareció.

   Esta no depende del nombre del contenedor. Toda tarjeta reparte su
   contenido en el alto que la fila le dio: la rejilla ya las estira a la
   misma altura, lo que se veía disparejo era el contenido apelotonado
   arriba dejando un bloque vacío abajo.

   Va al final de la hoja, así que gana por orden a cualquier regla previa,
   y lo que no debe estirarse (un botón, un aviso, un pie) queda excluido. */
.card{display:flex;flex-direction:column}
.card > :last-child{flex:1 1 auto;min-height:0}
.card > .card-head{flex:none}

/* --- EL HUECO LO PONE EL CONTENEDOR, NUNCA LA CELDA -------------------
   Esta es la regla que faltaba, y es la razon de que el desfase volviera
   cuatro veces. Una celda que se separa a si misma con `margin-top` no
   sabe si su hermana esta ABAJO -- y entonces el margen es el hueco que
   toca -- o AL LADO -- y entonces la hunde 12 px respecto de la primera
   de su fila, que no tiene hermana previa y no lo lleva.

   Medido el 14-oct-2026 sobre los 12 modulos y los 4 perfiles:
   47 filas desalineadas, TODAS exactamente 12 px, el valor de --hueco.
   No eran 47 errores de acomodo: era uno solo, repetido 47 veces.

   De aqui en adelante: ninguna celda lleva margen propio. El hueco
   horizontal es el `gap` de la rejilla; el vertical es el margen entre
   los bloques de primer nivel, que por definicion estan apilados y
   nunca forman fila. Cualquier regla que vuelva a dar `margin-top` a
   una `.card` reabre este error en los 12 modulos a la vez. */
/* 1. Una tarjeta NUNCA lleva margen propio. Dentro de una fila es una
      celda, y un margen suyo la descuadra respecto de sus vecinas. */
.card{margin-top:0;margin-bottom:0}

/* 2. Un bloque de ancho completo si se separa del que sigue: una rejilla
      nunca es celda de una fila, siempre esta apilada. */
[class*="grid-"]{margin-bottom:var(--hueco)}

/* 3. Y lo apilado en el primer nivel se separa de lo anterior. Esta regla
      va DESPUES de la 1 a proposito: le devuelve el margen a la tarjeta
      que si esta apilada -- hija directa del modulo -- sin tocar a las
      que son celda de una fila. Sin `:where()`: con especificidad cero
      cualquier otra regla le gana y el hueco se pierde (comprobado). */
.modulo > * + *,
.contenido > * + *,
[class*="-panel"] > * + *{margin-top:var(--hueco)}

/* --- EL CUERPO USA EL ALTO QUE LA FILA LE DIO ------------------------
   Segunda mitad del mismo problema. Una tarjeta estirada por su fila
   deja el contenido pegado arriba y un bloque en blanco abajo: se lee
   como que la celda esta mal medida, cuando lo que esta mal es que el
   cuerpo no usa el alto que recibio. Medido el 14-oct: 12 tarjetas,
   de 45 px a 374 px de vacio.

   Hay tres formas de cuerpo en esta plataforma y cada una responde
   distinto. Van por forma, no por modulo: un modulo nuevo que use
   cualquiera de las tres queda cubierto sin tocar esta hoja. */

/* 1. el dibujo que ES todo el cuerpo crece con el.
      `:only-child` es lo que lo distingue de un icono: un icono nunca
      es el unico hijo del cuerpo de una tarjeta. */
.card > div:last-child > svg:only-child{height:100%;display:block}

/* 2. el cuerpo sin clase es una lista de renglones: los reparte en vez
      de amontonarlos arriba. */
.card > div:last-child:not([class]){display:flex;flex-direction:column;
  justify-content:space-between}

/* 3. la dona y su leyenda se centran en el alto sobrante. */
.card > .dona-wrap,
.card > .m5-donas,
.card > .anillo-grid{align-content:center;align-items:center}

/* 4. cuando el cuerpo es la leyenda, lo que debe crecer es la grafica
      de arriba, no la leyenda. */
.card > .m9-leyenda:last-child{flex:0 0 auto}

/* 5. un pie -- la franja de cierre con su raya arriba -- no crece: es un
      cierre, no el cuerpo. Si crece, el boton queda flotando a media caja. */
.card > .ocup-todos,
.card > .cal-pie-barra,
.card > .m9-pie{flex:0 0 auto}


/* --- NADA SE CORTA A LA MITAD ----------------------------------------
   Segundo reclamo de Edna, 14-oct: "al final de varias celdas el texto
   esta a punto de salirse o cortado, por lo menos una celda en todos los
   modulos". Medido: 6 chips partidos a la mitad -- "Pagad", "Pendi",
   "Programad" -- en las tablas de M4, M9 y M11, y el chip de Cobranza
   del tablero a 4 px del borde util de su tarjeta contra 24 px del otro
   lado.

   La causa no es el acomodo: las tablas piden mas ancho del que tienen.
   Siete columnas en 699 px, con porcentajes escritos a mano cuando los
   textos eran otros, y `overflow:hidden` en la celda. Cuando el chip no
   cabe, la celda lo rebana -- no lo encoge ni lo envuelve.

   La regla: lo que puede ceder es la PROSA, que se recorta con puntos y
   se sigue leyendo. Una PIEZA -- chip, boton, pastilla -- nunca se corta:
   media palabra dentro de media pildora no se lee como "hay mas texto",
   se lee como un error. Para que quepa sin robarle todo a la prosa, el
   chip dentro de una tabla de datos va en su talla compacta: mismo color,
   mismo radio, menos aire. */
.card .tabla .chip{font-size:11px;padding:3px 8px;line-height:1.25}
.card .tabla .chip .chip-dot{width:5px;height:5px;margin-right:4px}

/* Y cuando el corte toca a la prosa, que se note que es un corte: con
   puntos suspensivos, no a media palabra.

   Una celda recorta con puntos SU PROPIO texto. Si lo que lleva dentro es
   una caja flex -- el punto de color y la categoria, el avatar y el nombre,
   el icono y el movimiento -- el texto de esa caja es un elemento anonimo
   del flex, y ni los puntos de la celda ni los de la caja lo alcanzan: se
   corta en seco, a media palabra ("Administració", "Mantenimier"). Medido:
   12 celdas asi en M4, M7 y M9.

   La caja pasa a composicion en linea. Se ve igual -- punto, aire, texto --
   pero ahora el texto es contenido en linea de un bloque, que es justo lo
   que los puntos suspensivos saben recortar. */
.card .tabla td > .mov-tipo,
.card .tabla td > .m4-mascota-cell,
.card .tabla td > .m9-cat{display:block;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card .tabla td > .mov-tipo > *,
.card .tabla td > .m9-cat > *{display:inline-block;vertical-align:middle;margin-right:6px}

/* --- EL ULTIMO RENGLON NO TERMINA PEGADO AL BORDE --------------------
   Tercer reclamo de Edna, 14-oct: "no se estan respetando los lugares
   dentro de la celda". Medido: 11 tarjetas dejaban 1 px entre el ultimo
   renglon de su tabla y el borde util de la tarjeta -- Cobranza pendiente,
   Lista de espera, Movimiento del dia, Ventas recientes, Campañas activas
   y seis mas. El renglon no estaba cortado, pero terminaba justo sobre el
   borde, y eso se lee como corte.

   Por que pasaba: la tabla se estira para llenar la tarjeta (`height:100%`,
   que es lo que evita el bloque en blanco abajo), y al estirarse reparte el
   alto sobrante entre sus renglones. El ultimo crece hasta el final y su
   borde inferior queda sobre el borde de la tarjeta.

   No se quita el estirado -- sin el vuelve el hueco en blanco -- se le pone
   piso al ultimo renglon: el mismo aire que separa cualquier par de celdas.
   Es lo que hace que un renglon "respete su lugar": tiene aire arriba, aire
   abajo, y no toca el borde de la caja que lo contiene. */
.card .tabla tbody tr:last-child > td{padding-bottom:var(--hueco)}

/* --- DOS CLASES QUE SE USABAN SIN ESTILO -----------------------------
   Las encontro el verificador de clases, no yo al escribirlas. Las dos
   estaban en el marcado y ninguna regla las tocaba, asi que salian como
   texto plano sin que nada avisara. */

/* La frase de personalidad, bajo el nombre en la ficha de la mascota:
   «Alegre, sociable y amante del agua». Es una cita del dueno, no un dato,
   y por eso va en cursiva como `.historia-cita`, que es la misma idea en el
   expediente. Mas suave que el nombre que lleva encima, para que no compita. */
.m1-frase-italica{font-size:14px;color:var(--texto-suave);line-height:1.5;
  font-style:italic;margin:4px 0 0}

/* El resumen de lo que se va a abonar, dentro del modal de abono: lo escribe
   el JS y necesitaba una caja donde caer. Misma caja neutra que `.m2-obs-caja`
   —piedra, radio medio, aire propio— porque es lo mismo: un bloque de lectura
   dentro de un formulario, no un aviso. */
.cita-resumen{background:var(--gris-piedra);border-radius:var(--r-md);
  padding:var(--sp-3) var(--sp-4);font-size:13.5px;line-height:1.5}
.cita-resumen b{color:var(--morado);font-weight:600}

/* --- NADA SE SALE DE SU TARJETA --------------------------------------
   "No se estan respetando los lugares dentro de la celda" (Edna, 14-oct).
   Medido a varios anchos de ventana, que es lo que me faltaba revisar:
   a 1440 px casi todo cuadra, pero la maqueta se mira tambien en paneles
   mas angostos y ahi el contenido empieza a salirse de su caja.

   El caso grave, y este se sale a CUALQUIER ancho: #adm-lista es el
   CONTENEDOR de la lista de avisos de clientes vencidos, pero llevaba la
   clase .inc-fila, que es UN renglon (flex en fila). Al llenarlo por JS
   con varios .aviso-fila, se acomodaban uno al lado del otro en vez de
   apilarse: 870 px de contenido afuera de la tarjeta, a la derecha, donde
   nadie lo ve. La lista se veia corta y en realidad estaba completa,
   fuera de cuadro. */
#adm-lista{display:block}

/* Un correo o un folio no tienen espacios donde partir, asi que empujan su
   caja hasta salirse. Que partan donde sea antes que salirse. */
.card .pf-val,
.card .cm-perfil-dato{overflow-wrap:anywhere;min-width:0}

/* Un dato sin espacios -- un correo, un folio largo -- no empuja su caja:
   parte donde tenga que partir. */
.card .campo-valor,
.card .inc-texto span,
.card .aviso-fila{overflow-wrap:anywhere;min-width:0}
.card .tabla td > .m4-mascota-cell > *{display:inline-block;vertical-align:middle;
  margin-right:8px;flex:none}
.card > .m7-chart-wrap{flex:1 1 auto;min-height:0}
.card > .m7-chart-wrap > svg{height:100%}
.card > .btn:last-child,
.card > .boton:last-child,
.card > .aviso:last-child,
.card > .nota:last-child,
.card > .ayuda:last-child,
.card > p:last-child,
.card > .acciones:last-child,
.card > .pie:last-child{flex:0 0 auto}
.card[hidden]{display:none!important}

/* La tabla de «Tratamientos y servicios» de la ficha. Seis columnas en el
   ancho de una pestaña: sin reparto fijo, «Tratamiento o servicio» se comía
   el espacio y «Próxima cita» salía partida en tres renglones. La emite
   m1-perfil.js, que es de los dos negocios, así que vive en las dos hojas. */
.tabla-tratamientos{table-layout:fixed;width:100%}
.tabla-tratamientos td{vertical-align:middle;overflow-wrap:anywhere}
.tabla-tratamientos th:nth-child(1),.tabla-tratamientos td:nth-child(1){width:26%}
.tabla-tratamientos th:nth-child(2),.tabla-tratamientos td:nth-child(2){width:20%}
.tabla-tratamientos th:nth-child(3),.tabla-tratamientos td:nth-child(3){width:13%}
.tabla-tratamientos th:nth-child(4),.tabla-tratamientos td:nth-child(4){width:10%}
.tabla-tratamientos th:nth-child(5),.tabla-tratamientos td:nth-child(5){width:15%}
.tabla-tratamientos th:nth-child(6),.tabla-tratamientos td:nth-child(6){width:16%}

/* Pagos de la ficha: la lista a la izquierda, el detalle del pago elegido a la
   derecha. Los renglones se pican, así que se ven picables y el elegido se
   queda marcado — sin eso no se sabe cuál detalle se está mirando. */
.fila-pago{cursor:pointer}
.fila-pago:hover td{background:var(--gris-piedra,#F4FBFD)}
.fila-pago.elegida td{background:var(--lavanda,#D6F1F8)}
.fila-pago:focus-visible{outline:2px solid var(--indigo,#017B99);outline-offset:-2px}
.tabla-pagos-ficha{table-layout:fixed;width:100%}
.tabla-pagos-ficha td{vertical-align:middle;overflow-wrap:anywhere}
/* Sin reparto fijo, «Transferencia» se partía en «Transferenci/a» y el folio
   en «R-/10400»: media tarjeta se la llevaba el concepto. Las columnas cortas
   no se parten; la única que puede crecer es el concepto. */
.tabla-pagos-ficha th:nth-child(1),.tabla-pagos-ficha td:nth-child(1){width:15%;white-space:nowrap}
.tabla-pagos-ficha th:nth-child(2),.tabla-pagos-ficha td:nth-child(2){width:15%;white-space:nowrap}
.tabla-pagos-ficha th:nth-child(3),.tabla-pagos-ficha td:nth-child(3){width:28%}
.tabla-pagos-ficha th:nth-child(4),.tabla-pagos-ficha td:nth-child(4){width:17%;white-space:nowrap}
.tabla-pagos-ficha th:nth-child(5),.tabla-pagos-ficha td:nth-child(5){width:12%;white-space:nowrap}
.tabla-pagos-ficha th:nth-child(6),.tabla-pagos-ficha td:nth-child(6){width:13%}
.tabla-pagos-ficha .chip{font-size:11px;padding:3px 8px;white-space:nowrap}
.pf-detalle-pago{display:flex;flex-direction:column}
/* Un dato de muestra se declara donde está, no en una nota al pie que nadie
   lee: si parece dinero de la clínica, alguien lo va a cobrar. */
.aviso-muestra{margin-top:var(--sp-3);padding:8px 11px;border-radius:8px;
  background:var(--ambar-fondo,#FEF0A0);color:var(--ambar-texto,#7A5E00);
  font-size:12px;line-height:1.45}
