:root {
  --marca: #eb2129;          /* rojo del logo CDS */
  --marca-osc: #a31016;
  --acento: #f2b441;
  --fondo: #f5f5f6;
  --tarjeta: #ffffff;
  --texto: #232021;
  --muted: #7a7274;
  --borde: #e7e2e3;
  --rojo: #c0392b;
  --radio: 14px;
  --sombra: 0 1px 3px rgba(0, 0, 0, 0.08);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--fondo);
  color: var(--texto);
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}

.oculta { display: none !important; }
.muted { color: var(--muted); }
.error { color: var(--rojo); margin-top: 12px; font-size: 15px; }

.vista { min-height: 100dvh; }

/* ---------- login ---------- */
#vista-login {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, #2a2627 0%, #161314 100%);
  padding: 24px;
}
.login-caja {
  background: var(--tarjeta); border-radius: 20px; padding: 36px 28px;
  width: 100%; max-width: 360px; text-align: center;
  box-shadow: 0 10px 40px rgba(0,0,0,0.25);
}
.logo-login {
  width: 100%; max-width: 260px; margin: 4px auto 18px; display: block;
}
.login-caja h1 { font-size: 22px; margin-bottom: 4px; }
.login-caja form { margin-top: 24px; display: grid; gap: 12px; }

input, button { font-family: inherit; font-size: 16px; }

input[type="password"], input[type="text"], input[type="tel"],
input[type="email"], input[type="search"] {
  width: 100%; padding: 14px 16px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); background: #fff; outline: none;
  transition: border-color .15s;
}
input:focus { border-color: var(--marca); }
#input-pin { text-align: center; font-size: 22px; letter-spacing: 6px; }

/* ---------- botones ---------- */
.btn {
  border: none; border-radius: var(--radio); padding: 13px 18px;
  font-weight: 600; cursor: pointer; transition: opacity .15s, transform .05s;
}
.btn:active { transform: scale(0.98); }
.btn-primario { background: var(--marca); color: #fff; }
.btn-secundario { background: var(--acento); color: #3d2c00; width: 100%; margin-top: 14px; }
.btn-grande { padding: 15px; font-size: 17px; }
.btn-fantasma {
  background: none; border: none; color: var(--marca); font-size: 16px;
  font-weight: 600; cursor: pointer; padding: 8px 10px; border-radius: 10px;
}
.btn-fantasma:active { background: rgba(235,33,41,0.08); }
.btn-fantasma2 {
  background: none; border: 1.5px solid var(--borde); color: var(--muted);
}

/* ---------- pantalla de entrada: la nota y los enlaces de las tres puertas ---------- */
/* 🏠 Estas cuatro reglas VIVÍAN SUELTAS en un `<style>` de `index.html`, con una nota que
   decía «al mergear, mudarlas a `app.css`»: se habían escrito ahí porque el día que nacieron
   otra sesión tenía este archivo tomado. El merge ya pasó hace rato y seguían ahí, con la
   nota pidiendo algo que nadie hacía. Mudadas el 26-ago; no hay ninguna razón de diseño para
   que estuvieran aparte. */
.login-nota { font-size: 14px; opacity: .8; margin: 0 0 4px; text-align: left; }
.login-enlaces {
  margin-top: 18px; display: flex; gap: 16px; justify-content: center;
  flex-wrap: wrap; font-size: 14px;
}
.login-enlaces a { color: inherit; opacity: .7; text-decoration: underline; }
.login-enlaces a:hover { opacity: 1; }

/* ---------- barra superior ---------- */
.barra {
  background: var(--tarjeta); color: var(--texto);
  padding: calc(env(safe-area-inset-top) + 12px) 16px 12px;
  display: flex; align-items: center; justify-content: space-between;
  position: sticky; top: 0; z-index: 10;
  border-bottom: 1px solid var(--borde);
  box-shadow: var(--sombra);
}
.barra-titulo { display: flex; align-items: center; gap: 10px; }

/* Franja superior sticky de la sesión: fecha centrada + tira de sesiones del día. */
.sesion-topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--tarjeta); border-bottom: 1px solid var(--borde); box-shadow: var(--sombra);
  padding-top: env(safe-area-inset-top);
}
/* Fecha + flechas: cambiar de día sin salir de la sesión (pide volver a "‹ Sesiones" primero). */
.snav-fecha-row { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 6px 12px 0; }
.snav-fecha {
  text-align: center; text-transform: capitalize;
  font-size: 13px; font-weight: 700; color: var(--marca-osc);
}
.snav-dia-btn {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px;
  border: 1.5px solid var(--borde); background: #fff; color: var(--marca);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.snav-dia-btn:active { background: #fdecec; }
/* Tira única de sesión: ‹ Sesiones (izq) + chips de todas las sesiones del día (centro).
   La sesión actual va más grande y seleccionada; sustituye la vieja tarjeta de info. */
.barra-sesion { position: static; box-shadow: none; border-bottom: 0; padding-top: 8px; }
.barra-sesion { gap: 10px; justify-content: flex-start; align-items: stretch; }
.barra-sesion #btn-volver { flex: 0 0 auto; align-self: center; white-space: nowrap; }
.snav-chips {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  justify-content: safe center;
  overflow-x: auto; scrollbar-width: none; padding: 2px 2px 4px;
}
.snav-chips::-webkit-scrollbar { display: none; }
.snav-chip {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 15px; border-radius: 12px; border: 1.5px solid var(--borde); background: #fff;
  cursor: pointer; line-height: 1.15; white-space: nowrap;
}
/* Todos los chips muestran el detalle completo: hora – hora, nombre y estado.
   Sin recorte de nombre: el chip crece a lo ancho y la tira scrollea si hace falta. */
.snav-hora { font-weight: 700; font-size: 13.5px; color: var(--texto); }
.snav-horafin { display: inline; }
.snav-nombre { font-size: 13px; color: var(--texto); }
.snav-l2 { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 3px; }
.snav-estado { display: inline-block; font-size: 10.5px; padding: 2px 9px; }
/* Código de reserva: visible en TODOS los chips, al lado del estado */
.snav-codigo { display: inline-block; font-size: 11px; font-weight: 700; color: var(--marca-osc); letter-spacing: .3px; white-space: nowrap; }
/* El chip del paquete va al lado del código de reserva y tiene que LEERSE DISTINTO: son dos
   códigos en la misma línea y confundirlos es exactamente el error que hay que evitar. */
.snav-paquete { color: var(--muted); font-weight: 600; margin-left: 4px; }
/* La sesión que se está viendo: un poco más grande y resaltada. */
.snav-chip.sel {
  padding: 8px 18px; border-width: 2px; border-color: var(--marca);
  box-shadow: 0 1px 6px rgba(235, 33, 41, .18);
}
.snav-chip.sel .snav-hora { font-size: 15.5px; }
.snav-chip.sel .snav-nombre { font-size: 14.5px; font-weight: 700; }
/* Chip fijado: la sesión abierta, aunque no sea del día que se está mirando en la tira. */
.snav-chip-fijo { background: #fff8f0; }
.snav-fecha-chip {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px;
  color: var(--marca-osc); background: #fdecec; padding: 1px 7px; border-radius: 999px;
  margin-bottom: 1px;
}
.logo-barra { height: 17px; display: block; }
.barra-tag {
  background: var(--marca); color: #fff; font-weight: 700; font-size: 11px;
  letter-spacing: 0.8px; padding: 3px 8px; border-radius: 7px;
}

/* ---------- navegación de fecha ---------- */
.fecha-nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 6px; gap: 8px;
}
.btn-nav {
  width: 44px; height: 44px; border-radius: 12px; border: 1.5px solid var(--borde);
  background: var(--tarjeta); font-size: 24px; color: var(--marca);
  cursor: pointer; line-height: 1;
}
.fecha-centro { text-align: center; flex: 1; }
.fecha-label { font-weight: 700; font-size: 17px; text-transform: capitalize; }
.btn-hoy {
  background: none; border: none; color: var(--marca);
  font-size: 13px; cursor: pointer; text-decoration: underline; margin-top: 2px;
}

/* ---------- contenido ---------- */
.contenido {
  padding: 12px 16px calc(env(safe-area-inset-bottom) + 32px);
  max-width: 680px; margin: 0 auto;
}

/* ---------- tarjetas de sesión ---------- */
.tarjeta-sesion {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 16px; margin-bottom: 12px; cursor: pointer; border: 1.5px solid transparent;
  transition: border-color .15s;
}
.tarjeta-sesion:active { border-color: var(--marca); }
.ts-fecha { font-weight: 700; font-size: 15px; text-transform: capitalize; color: var(--marca-osc); margin-bottom: 6px; }
.ts-fila1 { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ts-hora { font-weight: 800; font-size: 18px; }
.ts-fila2 { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.ts-nombre { margin-top: 8px; font-size: 15px; color: var(--muted); }
.ts-registrados { margin-top: 10px; font-size: 14px; font-weight: 600; color: var(--marca); }

.chip {
  font-size: 13px; font-weight: 600; padding: 4px 10px; border-radius: 999px;
  background: #fdecec; color: var(--marca-osc);
}
.chip-servicio { background: #fdf3dd; color: #8a6100; }

.badge { font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px; }
.badge-CONFIRMADA { background: #e3f4e8; color: #1e7d3c; }
/* ⚰️ FINALIZADA ya NO es un estado: salió del select el 14-ago y cero filas la llevan. La
   regla NO se borra igual, y no es olvido — es la misma distinción que del lado del server:
   dejar de ESPERAR la palabra no es dejar de ENTENDERLA. `badgeEstado` pinta genéricamente el
   crudo que venga (`badge-${estado}`), sin consultar ninguna lista; si un restore, una fila
   vieja reimportada o una escritura directa devuelven FINALIZADA, sin esta línea el badge sale
   sin color — no roto, pero ilegible justo cuando alguien está mirando por qué apareció.
   Gris pizarra: neutro, distinto del verde de CONFIRMADA y del gris tachado de CANCELADA. */
.badge-FINALIZADA { background: #dfe3e8; color: #47535f; }
.badge-PENDIENTE { background: #fdf3dd; color: #8a6100; }
.badge-HOLD { background: #e8eaf6; color: #3f51b5; }
.badge-POSPUESTA { background: #f1e9f7; color: #6b4a8a; }
.badge-ESCALADA { background: #fdeaea; color: var(--rojo); }
.badge-CANCELADA { background: #eee; color: #888; text-decoration: line-through; }

/* B5 · las etiquetas del GLOSARIO (la palabra que lee un humano). Conviven con las de arriba
   a propósito: las `badge-XXXX` son el crudo del select de NocoDB y siguen siendo el fallback
   cuando un payload no trae `etiqueta`. Los colores heredan el código que el estudio ya
   aprendió —verde = apartada, ámbar = falta algo, gris = no hay nada que hacer— para que la
   traducción no obligue además a reaprender la pantalla.
   Minúscula (no MAYÚSCULAS como el crudo): es una palabra, no una constante. */
.badge-glosario { font-weight: 700; letter-spacing: 0; }
.be-sin-confirmacion { background: #fdf3dd; color: #8a6100; }
.be-sin-deposito     { background: #ede2fe; color: #5b3aa8; }   /* mismo lila que la opción en NocoDB */
.be-confirmada       { background: #e3f4e8; color: #1e7d3c; }
/* Con deuda es LA accionable de la casa: rojo, el único que pide que alguien haga algo hoy. */
.be-con-deuda        { background: #fdeaea; color: var(--rojo); }
/* Cerrada = no queda nada que hacer. El gris pizarra que FINALIZADA tenía. */
.be-cerrada          { background: #dfe3e8; color: #47535f; }
/* ⛔ Acá vivió `.be-sin-cerrar`, el azul de la séptima etiqueta. Tiziano la VETÓ el 14-ago:
   esas sesiones van al limbo SIN etiqueta. Sin etiqueta no hay badge de glosario que colorear:
   se pintaban con el crudo (`.badge-FINALIZADA`) mientras el crudo existió; desde que la
   palabra salió del select no queda nada que pintar y responde `.badge-sin-estado` —la raya. */
.be-pospuesta        { background: #f1e9f7; color: #6b4a8a; }
.be-cancelada        { background: #eee; color: #888; text-decoration: line-through; }

/* LA RAYA · ni etiqueta ni crudo (el limbo desde que FINALIZADA salió del select). NO es un
   estado: es la ausencia deliberada de uno, así que NO lleva color del código de estados —
   sin relleno, gris apagado, apenas un contorno. Tiene que verse (el hueco es información),
   pero no puede parecerse a un badge más, o sería la séptima etiqueta por la puerta de atrás.
   Lo que se lee de esa sesión lo dice el dinero en el resto de la fila. */
.badge-sin-estado    { background: transparent; color: var(--muted); box-shadow: inset 0 0 0 1px #dfe3e8; font-weight: 600; }

.vacio {
  text-align: center; color: var(--muted); padding: 48px 16px; font-size: 15px;
}

/* ---------- detalle de sesión ---------- */
.sesion-info {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 16px; margin-bottom: 20px;
}
.si-fecha {
  text-align: right; font-size: 13px; font-weight: 700;
  color: var(--marca-osc); text-transform: capitalize;
}
.si-centro {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 6px 0 2px;
}
.si-que { font-size: 20px; font-weight: 800; text-transform: uppercase; letter-spacing: .4px; }
.si-quien { font-size: 17px; font-weight: 700; }
.si-hora { font-size: 16px; font-weight: 600; }
.seccion-titulo {
  font-size: 14px; text-transform: uppercase; letter-spacing: 0.6px;
  color: var(--muted); margin: 20px 0 10px; display: flex; align-items: center; gap: 8px;
}
.pill {
  background: var(--marca); color: #fff; font-size: 12px;
  padding: 2px 9px; border-radius: 999px;
}

.lista-asistentes { list-style: none; }
/* «Personas Asistentes» COMPACTA (Tiziano, 16-oct-2026: «esta demasiado grande»): menos alto por persona (relleno, letra y botones más chicos); sigue estando todo — nombre, instrumento, hora, teléfono y los tres botones. */
.lista-asistentes li {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 6px 8px 6px 11px; margin-bottom: 5px;
  display: flex; align-items: center; justify-content: space-between; gap: 4px;
}
.asis-datos { min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 8px; }   /* el instrumento y la hora/teléfono van en el mismo renglón (debajo del nombre) si caben; si no, uno bajo el otro */
.asis-nombre { font-weight: 600; font-size: 15px; line-height: 1.25; flex: 1 1 100%; }
.asis-instr { font-size: 11.5px; line-height: 1.25; color: var(--marca); margin-top: 0; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.asis-meta { font-size: 12px; line-height: 1.25; color: var(--muted); margin-top: 0; }
.lista-asistentes li .btn-quitar, .lista-asistentes li .btn-editar, .lista-asistentes li .btn-foto-cara { padding: 3px 6px; font-size: 17px; line-height: 1.2; }
.btn-quitar {
  background: none; border: none; color: #c4bdbe; font-size: 20px;
  cursor: pointer; padding: 6px 10px; border-radius: 8px; flex-shrink: 0;
}
.btn-quitar:active { color: var(--rojo); background: #fdeaea; }
/* «Deshacer» un crédito aplicado (16-sep-2026), en la lista de pagos. Es texto, no un
   glifo como la ✕ de arriba: necesita su propio botón, chico y con borde, para no
   confundirse con un link ni con la ✕. */
.btn-deshacer-credito {
  background: none; border: 1px solid var(--borde); color: var(--marca);
  font-size: 12px; font-weight: 600; cursor: pointer; padding: 5px 10px;
  border-radius: 999px; flex-shrink: 0; white-space: nowrap;
}
.btn-deshacer-credito:active { color: #fff; background: var(--marca); }
.btn-deshacer-credito:disabled { opacity: .5; cursor: default; }
.btn-editar {
  background: none; border: none; color: #c4bdbe; font-size: 19px;
  cursor: pointer; padding: 6px 10px; border-radius: 8px; flex-shrink: 0;
}
.btn-editar:active { color: var(--marca); background: #fdecec; }
/* 📷 La foto de la cara, en el renglón de quien ya entró. Solo con la cámara prendida (la
   app le pone `.oculta` si no), y apagado mientras se calcula la foto de esa ficha. */
.btn-foto-cara {
  background: none; border: none; font-size: 19px;
  cursor: pointer; padding: 6px 10px; border-radius: 8px; flex-shrink: 0;
}
.btn-foto-cara:active { background: #fdecec; }
.btn-foto-cara:disabled { opacity: 0.35; cursor: default; }
/* Dentro de un renglon de busqueda o de propuesta el 📷 comparte sitio con «Registrar», que es
   ancho: se aprieta un poco para no empujar el nombre. NO esta medido en el celular del estudio
   ni en la PC del mostrador: se midio leyendo, no mirando. */
.resultado .btn-foto-cara { padding: 6px 6px; }

/* ---------- búsqueda ---------- */
#resultados-busqueda { margin-top: 10px; }
.resultado {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 12px 14px; margin-bottom: 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.res-datos { min-width: 0; }
.res-nombre { font-weight: 600; }
.res-meta { font-size: 13px; color: var(--muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.btn-registrar {
  background: var(--marca); color: #fff; border: none; border-radius: 10px;
  padding: 10px 16px; font-weight: 600; cursor: pointer; flex-shrink: 0;
}
.btn-registrar:disabled { opacity: 0.5; }
.sin-resultados { color: var(--muted); font-size: 14px; padding: 10px 4px; }

/* ---------- 📷 la cámara del check-in ---------- */
/* El recuadro del video, el cartel que avisa, y el renglón APAGADO de quien ya está
   registrado. Poco más: las propuestas se pintan con `.resultado`, el MISMO renglón de la
   búsqueda por nombre, para que el gesto de confirmar sea el que ya existe. */
.fila-entrada-botones { display: flex; gap: 8px; flex-wrap: wrap; }
.cam-caja {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 10px; margin-top: 10px;
}
/* El marco pone la foto quieta ENCIMA del video, del mismo tamaño y recortada igual. El
   video no se esconde nunca: la foto lo tapa mientras se calcula y se va. */
.cam-marco { position: relative; max-width: 420px; }
.cam-video {
  width: 100%; max-width: 420px; border-radius: 10px; display: block;
  background: #111; aspect-ratio: 4 / 3; object-fit: cover;
}
.cam-lienzo {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  border-radius: 10px; background: #111; object-fit: cover;
}
/* 🔍 Alejar y acercar, encima del video, abajo a la derecha. Van por encima de la foto quieta
   para que no salten de sitio mientras se calcula. Ver `zoomDeLaPista` en app.js. */
.cam-zoom {
  position: absolute; right: 8px; bottom: 8px; z-index: 2;
  display: flex; gap: 8px;
}
.cam-zoom-btn {
  width: 44px; height: 44px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(0, 0, 0, 0.55); color: #fff; font-size: 26px; font-weight: 700;
  line-height: 1; display: flex; align-items: center; justify-content: center;
}
.cam-zoom-btn:active { transform: scale(0.94); }
.cam-zoom-btn:disabled { opacity: 0.35; cursor: default; }
/* Lo que pasó con la última foto. No es roja y no da instrucciones: dice lo que pasó. */
.cam-foto-linea { font-size: 14px; font-weight: 600; margin-top: 6px; min-height: 18px; }
.cam-aviso {
  font-size: 13px; color: var(--muted); line-height: 1.4; margin-top: 8px;
}
.cam-estado { font-size: 13px; color: var(--muted); margin-top: 6px; min-height: 17px; }
/* Ya está en la lista de la sesión: se ve, y se ve que ya está. No se esconde — que salga
   apagada es información («ésa ya entró»); esconderla haría creer que no se la reconoció. */
.resultado.res-ya-esta { opacity: 0.55; }
/* El rótulo de las propuestas. NUNCA afirma nada: pregunta. Ver `pintarPropuestas`. */
.cam-rotulo {
  font-size: 13px; color: var(--muted); font-weight: 600;
  margin: 10px 4px 6px; text-transform: uppercase; letter-spacing: 0.4px;
}

/* ---------- 📷 la entrada por cámara en «Dar entrada» (pantalla/app/23-camara-entrada.js) ---------- */
/* Todo es de esta caja: el renglón de quien la cámara reconoció es `.resultado`, el MISMO de la búsqueda; lo único propio es lo que
   se le pone alrededor. NO esta medido en la computadora del estudio ni en un celular: se escribio leyendo, no mirando. */
.ec-caja {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 10px; margin-top: 10px;
}
.ec-estado { font-size: 13px; color: var(--muted); font-weight: 600; }
.ec-contestando {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin-top: 8px; padding: 8px 10px; border-radius: 10px; background: var(--fondo); font-size: 14px;
}
.ec-renglon { margin-bottom: 8px; }
.ec-renglon .resultado { margin-bottom: 4px; }
.ec-segundo { font-size: 13px; color: var(--muted); margin: 0 4px 4px; }
.ec-acciones { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 0; }
.ec-desconocido {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra); padding: 10px 12px;
}
.ec-desconocido.ec-activo { outline: 2px solid var(--marca); }
.ec-carita { width: 96px; height: 96px; object-fit: cover; border-radius: 10px; display: block; margin-bottom: 6px; background: #111; }
.ec-dato { font-size: 14px; font-weight: 600; }

/* ---------- form persona nueva ---------- */
.form-nueva {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 18px 16px; margin-top: 14px; display: grid; gap: 10px;
}
.form-nueva h3 { font-size: 16px; margin-bottom: 2px; }
.np-proveedor { display: flex; align-items: center; gap: 10px; font-size: 16px; margin-top: 6px; cursor: pointer; }
.np-proveedor input { width: 22px; height: 22px; margin: 0; flex: none; }
.np-label {
  font-size: 13px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.5px; margin-top: 6px;
}
/* Barra fija de saldo (vista de sesión): el número que importa, siempre visible */
.saldo-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--tarjeta); border-top: 2px solid var(--borde);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 16px calc(env(safe-area-inset-bottom) + 10px);
  box-shadow: 0 -2px 10px rgba(0, 0, 0, .07); font-size: 14px;
}
.sb-item { color: var(--muted); white-space: nowrap; }
.sb-item b { color: var(--texto); margin-left: 4px; }
.sb-saldo { font-weight: 800; white-space: nowrap; }
.sb-saldo.saldo-deuda { color: var(--rojo); }
.sb-saldo.saldo-favor, .sb-saldo.saldo-ok { color: #1f8a4c; }
.sb-saldo.saldo-falta { color: #b26a00; }
.sb-saldo.saldo-cancelada { color: var(--muted); }
@media (max-width: 430px) {
  .saldo-bar { font-size: 13px; gap: 8px; }
  .saldo-bar .sb-item:nth-of-type(2) { display: none; }   /* en angosto: solo Total y Saldo */
}
#vista-sesion .contenido { padding-bottom: calc(env(safe-area-inset-bottom) + 92px); }
/* Al "asomarse" con ‹ › a un día sin sesiones, la tira queda vacía (la sesión de abajo no se toca). */
.snav-sin-sesiones { color: var(--muted); font-size: 13px; padding: 6px 4px; }

/* «Canceladas (N)»: las sesiones canceladas del día van detrás de un renglón cerrado (12-oct-2026).
   Una flecha dibujada con bordes: apunta a la derecha cerrado y baja al abrir. Sirve igual al
   resumen de la lista (<details>) que al botón de la tira. */
.canceladas-flecha {
  display: inline-block; width: 0; height: 0; flex: 0 0 auto;
  border-style: solid; border-width: 5px 0 5px 7px;
  border-color: transparent transparent transparent currentColor;
  transition: transform .15s;
}
.canceladas-desp[open] > .canceladas-resumen .canceladas-flecha,
.snav-canc[aria-expanded="true"] .canceladas-flecha { transform: rotate(90deg); }
.canceladas-desp { margin-top: 4px; }
.canceladas-resumen {
  display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 10px 4px;
  cursor: pointer; font-weight: 700; font-size: 15px; color: var(--muted);
  list-style: none; user-select: none;
}
.canceladas-resumen::-webkit-details-marker { display: none; }
.canceladas-lista { padding-top: 4px; }
.snav-canc {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 8px; align-self: center;
  min-height: 44px; padding: 8px 14px; border-radius: 12px; border: 1.5px dashed var(--borde);
  background: transparent; color: var(--muted); font: inherit; font-size: 13px; font-weight: 700;
  cursor: pointer; white-space: nowrap;
}
.snav-canc[aria-disabled="true"] { cursor: default; opacity: .75; }
.canceladas-resumen:focus-visible, .snav-canc:focus-visible {
  outline: 2px solid var(--marca); outline-offset: 2px; border-radius: 8px;
}

/* Botón de sugerencia (ej. "usar N (check-in)" en Personas) */
.btn-sug {
  border: 1.5px dashed var(--marca); background: #fdecec; color: var(--marca-osc);
  border-radius: 999px; padding: 7px 12px; font-size: 13px; font-weight: 600;
  cursor: pointer; align-self: center;
}

/* Sugerencia de line-up del proyecto (cargar los de la última vez de un toque) */
.sug-proyecto {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: #fdf3dd; border: 1.5px solid #e6cf8f; border-radius: 12px;
  padding: 10px 12px; margin-bottom: 10px;
}
.sug-proyecto .sug-txt { flex: 1 1 180px; font-size: 13px; line-height: 1.4; color: #6b4e00; }
.sug-proyecto .sug-pers { white-space: nowrap; }
.sug-proyecto .sug-acc { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.sug-cargar {
  background: var(--marca); color: #fff; border: 0; border-radius: 999px;
  padding: 7px 14px; font-size: 13px; font-weight: 700; cursor: pointer; white-space: nowrap;
}
.sug-x { background: transparent; border: 0; color: #8a6100; font-size: 16px; cursor: pointer; padding: 2px 6px; line-height: 1; }

/* Chips pequeños (staff bajo "Atendió") */
.chips-mini { margin-top: 6px; }
.chips-mini .chip-opcion { font-size: 12px; padding: 5px 10px; }

.cumple-campo { display: flex; align-items: center; gap: 10px; }
.cumple-campo input { width: 5.5em; text-align: center; }
.cumple-sep { font-size: 22px; font-weight: 700; color: var(--muted); }

.chips-sel { display: flex; flex-wrap: wrap; gap: 7px; }
/* Formulario de persona (check-in): Instrumento y Género en columnas parejas, 2 en el celular (el número lo da el ancho), y el título de cada bloque separado de lo de arriba (19-oct-2026). Las de la sesión (`#ds-instrumento`) no cambian. */
.np-label-bloque { margin-top: 16px; }
#np-instrumento, #np-genero { display: grid; grid-template-columns: repeat(auto-fill, minmax(135px, 1fr)); gap: 7px; }
#np-instrumento .chip-opcion, #np-genero .chip-opcion { width: 100%; min-width: 0; text-align: left; overflow-wrap: break-word; }
.chip-opcion {
  border: 1.5px solid var(--borde); background: #fff; color: var(--texto);
  font-size: 14px; padding: 7px 13px; border-radius: 999px; cursor: pointer;
}
.chip-opcion.sel {
  background: var(--marca); border-color: var(--marca); color: #fff; font-weight: 600;
}
.form-nueva textarea {
  width: 100%; padding: 12px 14px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); font-family: inherit; font-size: 16px;
  resize: vertical; outline: none;
}
.form-nueva textarea:focus { border-color: var(--marca); }
/* 📷 El botón de tirarle la foto a la persona que se está creando. No es el 📷 pelado de un
   renglón: acá no hay renglón donde quepa un icono solo, y un botón con su texto es lo que se
   entiende en una lista de campos. Apagado mientras se calcula esa foto. */
.btn-foto-nueva { justify-self: start; }
.btn-foto-nueva:disabled { opacity: 0.5; cursor: default; }
/* Lo que pasó con la foto del formulario. Misma voz que `.cam-foto-linea`: dice lo que pasó,
   no da instrucciones y no es roja. */
.np-foto-linea { font-size: 14px; font-weight: 600; min-height: 18px; margin-top: -4px; }
input[type="date"] {
  width: 100%; padding: 12px 14px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); background: #fff; outline: none;
  font-family: inherit; font-size: 16px; -webkit-appearance: none; appearance: none;
}
input[type="date"]:focus { border-color: var(--marca); }
.fila-botones { display: grid; grid-template-columns: 1fr 1.6fr; gap: 10px; margin-top: 4px; }

/* ---------- toast ---------- */
.toast {
  position: fixed; bottom: calc(env(safe-area-inset-bottom) + 20px);
  left: 50%; transform: translateX(-50%);
  background: var(--texto); color: #fff; padding: 12px 20px;
  border-radius: 999px; font-size: 15px; font-weight: 500;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3); z-index: 100;
  max-width: 90vw; text-align: center;
}
.toast.toast-error { background: var(--rojo); }

/* ---------- franja del MODO DESVÍO ----------
   🔴 Va ARRIBA, fija y a todo el ancho, empujando el contenido hacia abajo — no es un toast
   que se va solo. El estado que describe dura horas y afecta a TODO lo que la persona vaya
   a hacer: un aviso que desaparece a los tres segundos deja a quien llegó tarde trabajando
   sin saberlo. Ámbar y no rojo: la app FUNCIONA para mirar, que es la mitad del trabajo;
   pintarla de rojo diría «está caída» y la gente dejaría de usarla para consultar. */
.franja-desvio {
  position: sticky; top: 0; z-index: 90;
  background: #8a5a00; color: #fff;
  padding: 10px 14px; font-size: 14px; line-height: 1.35; text-align: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.25);
}
.franja-desvio strong { font-weight: 700; }

/* ---------- barra: acciones ---------- */
.barra-acciones { display: flex; align-items: center; gap: 2px; }
/* «Salir» va con palabra y no con ícono a propósito: en una barra que ya tiene siete íconos,
   un octavo símbolo no se lee — y un botón que no se encuentra es como no tenerlo (que es el
   estado del que venimos). Va en gris y no en el rojo de la marca para que se vea sin competir
   con las acciones que se usan todo el día, y `nowrap` porque es lo único con texto acá. */
.btn-salir {
  color: var(--muted); font-size: 13px; padding: 6px 9px;
  border: 1.5px solid var(--borde); border-radius: 999px; white-space: nowrap;
}
.btn-salir:active { background: rgba(235, 33, 41, 0.08); color: var(--marca); }

/* 🔴 EN EL TELÉFONO LA BARRA ENVUELVE, y esto NO es cosmético — arregla algo que ya estaba
   roto ANTES del botón «Salir». Medido en un viewport real de 375 px: la barra necesita
   537 px y sólo tiene 375, así que **se salía 162 px y la página scrolleaba al costado**;
   los últimos botones —el chip del nombre y el de gasto— quedaban fuera de pantalla. Los
   ocho botones están SIEMPRE (ninguno se oculta para el que no es admin: el PIN se pide al
   apretarlos), así que le pasa a cualquiera con un teléfono.
   Con «Salir» eran 212 px, y el botón nuevo caía en x=497: invisible, o sea inútil — que es
   exactamente el estado del que veníamos.
   👉 Con `wrap` la página deja de irse al costado (0 px) y todo queda alcanzable. Cuesta una
   fila: la barra pasa de 85 a 130 px de alto en móvil. Es un cambio VISIBLE y deliberado.
   Sólo aplica en pantallas chicas: de 768 px para arriba no hay desborde y esto no hace nada. */
@media (max-width: 640px) {
  .barra { flex-wrap: wrap; }
  .barra-acciones { flex-wrap: wrap; justify-content: flex-end; }
}

/* ---------- 🔒 el home de administración ---------- */

/* La barra reparte con `space-between`. Las demás vistas tienen tres hijos (volver · rótulo ·
   ↻), y el menú no tiene nada que refrescar: sin este hueco el rótulo se iría contra el borde
   derecho y quedaría descolgado de todas las otras pantallas. Mide como un `.btn-fantasma`
   de un ícono, que es lo que reemplaza. */
.barra-hueco { display: block; width: 36px; flex: 0 0 auto; }

/* Dos columnas también en 375 px: con una sola, las ocho tarjetas no entran en pantalla y el
   menú deja de ser un menú —habría que scrollear para saber qué hay—, que es justo el problema
   del que veníamos.
   📏 MEDIDO en el navegador, no supuesto: a 375 px las tarjetas salen de 167×111 y la octava
   termina en y=564. Entran LAS OCHO sin scrollear, y sobran 100 px hasta en la pantalla más
   baja que se usa (375×667). El menú se ve entero de un vistazo, que es todo el punto. */
.adm-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px; margin-top: 4px;
}
.adm-tile {
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: var(--radio);
  box-shadow: var(--sombra); padding: 14px 12px; cursor: pointer;
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  text-align: left; color: var(--texto); font-family: inherit;
  transition: border-color .15s, transform .05s;
}
.adm-tile:active { border-color: var(--marca); transform: scale(0.98); }
.adm-icono { font-size: 24px; line-height: 1.1; }
/* `nowrap` NO: los nombres largos («Cuentas abiertas», «Reporte mensual») tienen que poder
   partirse en dos líneas. Cortarlos con puntos suspensivos en un menú sería esconder
   justamente lo que el menú existe para mostrar. */
.adm-nombre { font-size: 15px; font-weight: 700; line-height: 1.25; }
/* La segunda línea dice QUÉ es cada cosa. Existe porque el menú lo van a usar Rosi y Tiziano,
   no quien escribió la app: «Trabajos» o «Cuadre» no se explican solos, y ocho íconos sueltos
   en una barra era exactamente el estado ilegible que Tiziano pidió arreglar. */
.adm-nota { font-size: 11.5px; color: var(--muted); line-height: 1.3; }

/* ---------- datos de sesión / form genérico ---------- */
.form-datos {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 18px 16px; display: grid; gap: 8px;
}
.campo-label {
  font-size: 13px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.5px; margin-top: 6px;
}
.form-datos textarea {
  width: 100%; padding: 12px 14px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); font-family: inherit; font-size: 16px;
  resize: vertical; outline: none;
}
.form-datos textarea:focus { border-color: var(--marca); }
.form-datos .btn { margin-top: 10px; }
/* 🔒 "Atendió" bajo llave: el técnico con credencial no lo elige, se lo pone el servidor.
   Se ve como un DATO, no como un campo apagado: un input gris invita a pelearse con él. */
.ds-atendio-fijo {
  margin: 6px 0 0; font-size: 14.5px; font-weight: 600; color: var(--texto);
}
/* Del calendario: solo lectura. `pre-wrap` respeta los saltos de línea que escribió quien
   reservó; el texto entra con textContent, así que nunca se interpreta como HTML. */
.ds-calendario { margin: 0 0 10px; }
.ds-calendario .campo-label { display: block; }
.ds-calendario-texto {
  margin: 4px 0 0; font-size: 14px; color: var(--texto); white-space: pre-wrap;
  overflow-wrap: anywhere; max-width: 560px;
}
/* campos cortos no deben ocupar todo el ancho */
#ds-personas { max-width: 200px; }
#ds-atendio { max-width: 360px; }
input[type="number"] {
  width: 100%; padding: 14px 16px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); background: #fff; outline: none; font-size: 16px;
}
input[type="number"]:focus { border-color: var(--marca); }
/* quitar las flechitas (spinner) de los campos numéricos -> entrada 100% manual */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
select {
  width: 100%; padding: 14px 16px; border: 1.5px solid var(--borde);
  border-radius: var(--radio); background: #fff; outline: none;
  font-family: inherit; font-size: 16px; -webkit-appearance: none; appearance: none;
}
select:focus { border-color: var(--marca); }

/* ---------- cuenta: renglones grandes ---------- */
/* La cuenta se lee como un recibo: una tarjeta, un artículo bajo el otro */
.cuenta-config { display: flex; gap: 10px 14px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.cc-hint { font-size: 12.5px; color: var(--muted); max-width: 360px; line-height: 1.35; }
/* La ayuda de la sala va al lado del cuadro de Horas (no en una línea aparte),
   para que la lista de la cuenta suba. En pantallas angostas cae debajo. */
.cuenta-config .cc-hint { flex: 1 1 170px; margin: 0; max-width: none; }
.cc-campo { display: flex; flex-direction: column; gap: 4px; }
.cc-campo span { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }
.cc-campo input {
  width: 74px; padding: 10px 12px; border: 1.5px solid var(--borde);
  border-radius: 10px; font-size: 16px; outline: none;
}
.cc-campo input:focus { border-color: var(--marca); }

.lista-cuenta {
  list-style: none;
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  overflow: hidden;
}
/* tabla: Artículo · Cantidad · Precio · Total · (quitar) */
.cuenta-head, .renglon, .cuenta-totalrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px 86px 88px;
  align-items: center; gap: 8px;
  padding: 1px 12px;                 /* ultra compacto, estilo hoja de cálculo */
}
.cuenta-head { border-bottom: 2px solid var(--borde); }
.cuenta-head span { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); }
.cuenta-head span:nth-child(2) { text-align: center; }
.cuenta-head span:nth-child(3), .cuenta-head span:nth-child(4) { text-align: right; }
.renglon { border-bottom: 1px solid var(--borde); }
.renglon:last-child { border-bottom: none; }
.ren-art { font-weight: 500; font-size: 14.5px; word-break: break-word; }
.ren-activo { background: #fff8f0; }                     /* fila con cantidad = está sumando */
.ren-activo .ren-art { font-weight: 700; }
.cuenta-grupo-btn { cursor: pointer; user-select: none; }
.cg-flecha { color: var(--muted); display: inline-block; width: 12px; }
.cg-n { color: var(--muted); font-weight: 600; text-transform: none; letter-spacing: 0; }
.cuenta-grupo {
  padding: 5px 12px 3px; font-size: 11px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase; color: var(--marca-osc); background: #faf6f6;
  border-top: 1px solid var(--borde); border-bottom: 1px solid var(--borde);
}
.cuenta-totalrow {
  border-top: 2px solid var(--texto); font-weight: 800; padding: 9px 12px;
}
#cuenta-buscar { margin: 10px 0 8px; }
.cuenta-buscar-row { display: flex; gap: 8px; align-items: center; margin: 10px 0 8px; }
.cuenta-buscar-row #cuenta-buscar { flex: 1; margin: 0; }
.btn-item-libre {
  flex: 0 0 auto; border: 1.5px dashed var(--marca); background: #fdecec; color: var(--marca-osc);
  border-radius: 10px; padding: 0 12px; font-size: 13px; font-weight: 600; cursor: pointer;
  white-space: nowrap;
}
/* Ítem libre: adicional de precio variable sin catálogo (picadera, pila del colmado, etc.) */
.form-item-libre {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 12px; margin-bottom: 10px; display: grid; gap: 8px;
}
.form-item-libre input {
  width: 100%; padding: 10px 12px; border: 1.5px solid var(--borde);
  border-radius: 10px; font-size: 15px; outline: none;
}
.form-item-libre input:focus { border-color: var(--marca); }
.il-acciones { display: flex; justify-content: flex-end; gap: 8px; }
/* Nota/aclaración del ítem libre, debajo del título (los renglones de catálogo no la usan) */
.ren-nota { display: block; font-size: 11.5px; color: var(--muted); font-weight: 400; margin-top: 1px; }
/* REPETIDO: el mismo producto con más de un renglón en la misma cuenta. Pasó de verdad
   (sesiones 63, 160 y 211). Cada renglón va en su propia línea para conservar su casilla y
   poder borrarse; esto es lo que hace que las dos líneas se lean como UNA repetición —y
   probablemente un error— y no como dos artículos distintos que casualmente se llaman igual.
   La barra va por `inset box-shadow` y NO por `border-left`: un borde de verdad correría el
   contenido 3px y rompería la alineación de la grilla con las filas de al lado. */
.renglon.renglon-dup { box-shadow: inset 3px 0 0 #d98324; background: #fff4e2; }
.ren-dup { display: block; font-size: 11.5px; font-weight: 700; color: #8a4b00; margin-top: 1px; }
/* .renglon .ren-cant (0,2,0) gana a la regla global input[type=number] (0,1,1) */
.renglon .ren-cant {
  width: 100%; padding: 3px 4px; border: 1.5px solid var(--borde);
  border-radius: 7px; text-align: center; font-size: 15px; outline: none;
}
.renglon .ren-cant:focus { border-color: var(--marca); }
.renglon .ren-cant::placeholder { color: #c9c2c2; font-size: 12px; }
/* Celda de cantidad: la casilla y, al lado, qué es lo que se escribió (h de horas, u de unidades).
   Los in-ears llevan DOS casillas —unidades y horas— apiladas, porque la columna es angosta. */
.ren-cel-cant { display: flex; align-items: center; justify-content: center; gap: 3px; }
.ren-cel-cant .ren-cant { min-width: 0; }
/* Los in-ears: los DOS recuadros en línea, unidades a la izquierda de las horas. */
.ren-cel-dos .ren-cant, .ren-cel-dos .ren-horas-input { flex: 1; min-width: 0; }
.renglon .ren-horas-input {
  width: 100%; padding: 3px 4px; border: 1.5px solid var(--borde);
  border-radius: 7px; text-align: center; font-size: 15px; outline: none;
}
.renglon .ren-horas-input:focus { border-color: var(--marca); }
.renglon .ren-horas-input::placeholder { color: #c9c2c2; font-size: 12px; }
.ren-horas {
  font-size: 10px; line-height: 1.1; color: var(--muted); white-space: nowrap;
}
/* El precio y su unidad van SIEMPRE en la misma línea — pedido de Tiziano, 26-ago:
   «en esta seccion pon la /h al lado del monto». Se partían en dos renglones porque
   «RD$ 2,000 /h» mide 85 px (12,5 px de fuente en móvil: 77 px) y la columna tenía 78/66,
   así que rompía por el espacio de antes del «/h». Los de 3 cifras («RD$ 500 /h») entraban:
   por eso la sección se veía despareja, unas filas en una línea y otras en dos.
   👉 Por eso la columna es 86/78 px y no menos: entra hasta «RD$ 9,999 /h» (85,5 / 77,5 px).
   ⚠️ El techo real es ése. Un precio POR HORA de 5 cifras («RD$ 20,500 /h» = 93 px) no entra
   y, con el nowrap, se saldría por la izquierda en vez de partirse. Hoy no existe ninguno
   —SINGLE READY son 20.500 pero es precio FIJO, sin /h—; si algún día lo hay, subir la columna.
   🔑 Y el ancho tiene que ser FIJO: cada renglón es su propio grid, así que las columnas solo
   se alinean entre filas porque miden lo mismo. Con `max-content` cada fila se mediría sola
   y la tabla se desalinearía. */
.ren-precio { text-align: right; color: var(--muted); font-size: 14px; white-space: nowrap; }
/* PRECIO LIBRE: un producto del Catálogo sin precio se cobra con el monto que se escribe acá
   (la regla vive en `precio_del_renglon`, server.py). Ocupa la misma columna que el precio en
   texto —86 px, 78 en móvil—, así que la fuente baja igual que `.ren-precio` en la media. */
.renglon .ren-precio-libre {
  width: 100%; min-width: 0; padding: 3px 4px; border: 1.5px solid var(--borde);
  border-radius: 7px; text-align: right; font-size: 14px; outline: none;
}
.renglon .ren-precio-libre:focus { border-color: var(--marca); }
.renglon .ren-precio-libre::placeholder { color: #c9c2c2; font-size: 12px; }
.ren-total { text-align: right; font-weight: 800; white-space: nowrap; }

/* Móvil: misma fila única pero más apretada (el nombre hace wrap, como en una hoja) */
@media (max-width: 640px) {
  .cuenta-head, .renglon, .cuenta-totalrow {
    grid-template-columns: minmax(0, 1fr) 72px 78px 80px;
    /* gap 4 y no 6: los 6 px que devuelve son para la columna del NOMBRE, que es de donde
       salieron los 12 px que se llevó el precio. Sin esto el nombre cae a 83 px y cuatro
       de las once filas de GRABACIÓN crecen un renglón (la lista pasa de 459 a 523 px);
       con esto queda en 89 px y crece UNA sola. Medido en 375 px, no estimado. */
    gap: 4px; padding-left: 10px; padding-right: 10px;
  }
  .ren-art { font-size: 13.5px; }
  .ren-precio, .renglon .ren-precio-libre { font-size: 12.5px; }
  /* 13 y no 14: la columna TOTAL mide 80 px y «RD$ 20,500» en negrita de 14 px pide 84,3 —
     o sea que ya se DESBORDABA, y como `.ren-total` tiene `white-space: nowrap` no se partía:
     se salía por la izquierda, encima del precio, EN SILENCIO. Y no es un total inventado:
     SINGLE READY solo son RD$ 20.500. A 13 px pide 78,3 y entra, con sitio hasta «RD$ 99,999».
     🔑 Se baja la fuente en vez de ensanchar la columna a propósito: ensanchar le sacaba los
     6 px a la columna del NOMBRE, y eso le costaba un renglón entero a varias filas. Esto no
     le cuesta ni un píxel a nadie. En escritorio la columna son 88 px y ya entraba: no se toca.
     (Aplica también a la fila del gran total, que usa esta misma clase.) */
  .ren-total { font-size: 13px; }
}
.renglon-auto { background: #fafafa; }
.renglon-auto .ren-art { color: var(--marca-osc); }
.ren-cant-auto { text-align: center; font-size: 11px; color: var(--muted); text-transform: uppercase; }

/* ---------- picker de catálogo ---------- */
.panel-catalogo {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 14px; margin-top: 12px; display: grid; gap: 10px;
}
.cat-chips { display: flex; flex-wrap: wrap; gap: 7px; }
/* sin scroll interno: la página baja normal */
.cat-lista { display: grid; gap: 18px; }
.cat-grupo { display: grid; gap: 8px; }
.cat-grupo-titulo {
  font-size: 12px; font-weight: 800; letter-spacing: 0.8px; text-transform: uppercase;
  color: var(--marca-osc); background: #fdecec; padding: 6px 12px;
  border-radius: 999px; justify-self: start;
}
.cat-grid { display: grid; gap: 8px; }
.cat-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px; border: 1.5px solid var(--borde); border-radius: var(--radio);
}
.cat-item .btn-registrar { flex-shrink: 0; }
.cat-datos { min-width: 0; }
.cat-nombre { font-weight: 700; font-size: 16px; }
.cat-meta { font-size: 13px; color: var(--muted); margin-top: 2px; }
.cat-add { display: flex; align-items: flex-end; gap: 8px; }
.cat-campo { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.cat-campo span { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
/* '.cat-add .cat-qty' (0,2,0) gana a la regla global input[type=number] (0,1,1) */
.cat-add .cat-qty {
  width: 58px; flex-shrink: 0; padding: 11px 6px; border: 1.5px solid var(--borde);
  border-radius: 10px; text-align: center; font-size: 16px; outline: none;
}
.cat-add .cat-qty:focus { border-color: var(--marca); }
.cat-add .btn-registrar { flex: 1; }

/* ---------- modal ---------- */
.modal-fondo {
  position: fixed; inset: 0; background: rgba(0,0,0,0.5);
  display: flex; align-items: center; justify-content: center;
  z-index: 200; padding: 24px;
}
.modal-caja {
  background: var(--tarjeta); border-radius: 18px; padding: 24px;
  width: 100%; max-width: 340px; display: grid; gap: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.modal-caja h3 { font-size: 17px; }
#admin-pin { text-align: center; font-size: 20px; letter-spacing: 4px; }

/* ---------- pagos ---------- */
.pagos-resumen {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 14px 16px; margin-bottom: 10px;
}
.pr-linea { display: flex; justify-content: space-between; align-items: baseline; padding: 4px 0; font-size: 15px; }
.pr-linea span { color: var(--muted); }
.pr-desc-row { gap: 10px; }
.pr-desc-label { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.pr-desc-label input {
  flex: 1; min-width: 0; padding: 7px 8px; border: 1.5px solid var(--borde);
  border-radius: 8px; font-size: 14px; outline: none;
}
.pr-desc-monto { display: flex; align-items: center; color: #1e7d3c; font-weight: 700; white-space: nowrap; }
.pr-desc-monto input {
  width: 84px; padding: 7px 8px; border: 1.5px solid var(--borde); border-radius: 8px;
  font-size: 15px; text-align: right; outline: none; color: #1e7d3c; font-weight: 700;
}
.pr-desc-label input:focus, .pr-desc-monto input:focus { border-color: var(--marca); }
.pr-saldo { margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--borde); font-size: 18px; font-weight: 800; text-align: right; }
.saldo-deuda { color: var(--marca-osc); }
.saldo-favor { color: #1e7d3c; }
.saldo-ok { color: #1e7d3c; }
.saldo-falta { color: #b26a00; }
.saldo-cancelada { color: var(--muted); }
.lista-pagos { list-style: none; margin-bottom: 12px; }
.pago-item {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 12px 14px; margin-bottom: 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.pago-datos { min-width: 0; }
.pago-monto { font-weight: 700; font-size: 16px; }
.pago-meta { font-size: 13px; color: var(--muted); margin-top: 2px; }
/* El estado de un pago que NO está confirmado ("sin verificar", "rechazado"), al lado del
   monto. Se llamaba `.pago-pv` («por verificar») y también vestía a los rechazados. */
.pago-estado {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  background: #fdf3dd; color: #8a6100; padding: 2px 7px; border-radius: 999px; margin-left: 4px;
}
/* De dónde salió el pago: vía, quién lo tomó, quién lo confirmó, código de comprobante.
   Envuelve en vez de desbordar — en el celular estas líneas son largas. */
.pago-origen {
  font-size: 12px; color: var(--muted); margin-top: 3px; line-height: 1.35;
  overflow-wrap: anywhere;
}
/* Pago que NO entró por la app (WhatsApp, calendario): no se puede anular desde acá. */
.pago-externo { border-left: 3px solid var(--borde); }
/* Pago ANULADO. La fila se conserva a propósito —anular es marcar, nunca borrar— así que
   tiene que verse y a la vez no confundirse con la plata que sí cuenta: se apaga, y el
   monto va tachado. */
.pago-anulado { opacity: .55; }
.pago-anulado .pago-monto { text-decoration: line-through; }
.pago-anulado .pago-estado { background: #fbe9e9; color: #9a2b2b; }
.pago-tag {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  background: #eef3fd; color: #2b5199; padding: 2px 7px; border-radius: 999px; margin-left: 4px;
}
/* ⛔ Acá vivió `.btn-confirmar-pago`, el ✓ verde de la lista de pagos. Murió con su botón en
   el B4.1: verificar una transferencia exige que un admin abra el banco, y eso vive en
   Telegram. Se quita el estilo con el botón para que nadie lo encuentre suelto y crea que
   solo falta volver a pintarlo. */
.form-pago {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 16px; display: grid; gap: 12px;
}
.pago-metodos { display: grid; gap: 10px; }
.pago-metodo { display: flex; align-items: center; gap: 10px; }
.pm-label { flex: 0 0 108px; font-weight: 700; }
.pm-spacer { flex: 0 0 128px; }   /* hueco invisible para alinear el monto de Efectivo */
.pm-monto {
  flex: 1; min-width: 0; padding: 12px; border: 1.5px solid var(--borde);
  border-radius: 10px; font-size: 16px; outline: none; text-align: right;
}
.pm-monto:focus { border-color: var(--marca); }
.pm-banco {
  flex: 0 0 128px; padding: 12px 10px; border: 1.5px solid var(--borde);
  border-radius: 10px; font-size: 15px; outline: none; background: #fff;
}
/* Qué va a ser el próximo pago (depósito o pago). Es un AVISO, no un control: la regla es
   posicional y la decide el servidor, así que acá no hay nada que marcar. */
/* 🪦 Acá vivían `.pago-tipo`, `.pago-tipo-deposito` y `.pago-tipo-pago`: el recuadro que
   anunciaba qué iba a ser el próximo pago. Lo borró Tiziano el 26/27-ago («Borralo» / «Borrala»),
   y el `<div id="pg-tipo">` se fue con ellas. */

/* ---------- inventario ---------- */
.lista-inventario { list-style: none; margin-bottom: 8px; }
.inv-item {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 16px; margin-bottom: 10px;
  display: flex; align-items: center; gap: 12px;
}
.inv-datos { flex: 1; min-width: 0; }
.inv-nombre { font-weight: 700; font-size: 17px; }
.inv-meta { font-size: 13px; color: var(--muted); margin-top: 3px; }
.inv-stock {
  font-weight: 800; font-size: 22px; min-width: 48px; text-align: center;
  color: #1e7d3c;
}
.inv-stock.inv-bajo { color: var(--rojo); }

@media (min-width: 700px) {
  body { font-size: 17px; }
  .contenido { padding-top: 20px; max-width: 1200px; }
  .ren-titulo, .inv-nombre { font-size: 18px; }

  /* Multi-columna en pantalla ancha: se ajusta solo (hasta ~4 columnas).
     En celular sigue 1 columna porque este bloque no aplica. */
  #lista-sesiones,
  .canceladas-lista,
  .cat-grid,
  #lista-inventario,
  .lista-asistentes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
    align-items: start;
  }

  /* «Canceladas (N)» ocupa la fila entera de la cuadrícula; sus tarjetas, otra cuadrícula igual */
  #lista-sesiones > .canceladas-desp { grid-column: 1 / -1; }

  /* dentro de la grilla, el gap maneja el espaciado (sin doble margen) */
  #lista-sesiones .tarjeta-sesion,
  .lista-asistentes li,
  #lista-inventario .inv-item { margin-bottom: 0; }
}

/* Computadora: la sesión y sus datos, lado a lado (en celular siguen apilados) */
@media (min-width: 820px) {
  .sesion-top {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 22px;
    align-items: start;
  }
  /* las dos columnas arrancan a la misma altura */
  .sesion-top .bloque-titulo { margin-top: 0; }
  /* Cuenta y Pagos lado a lado (dejan de apilarse) */
  .sesion-cuenta {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    gap: 22px;
    align-items: start;
  }
  .bloque-cuenta .seccion-titulo, .bloque-pagos .seccion-titulo { margin-top: 10px; }
}

/* Pantalla grande: tablero de 3 columnas — Cuenta | Personas | Datos (nada de espacio muerto) */
@media (min-width: 1200px) {
  #vista-sesion .contenido {
    max-width: 1720px;
    display: grid;
    grid-template-columns: 1.25fr 1fr 1fr;   /* Cuenta (ancha) | Personas | Datos */
    gap: 16px 26px;
    align-items: start;
  }
  .sesion-top { display: contents; }            /* sus 2 bloques pasan a ser columnas 2 (Personas) y 3 (Datos) */
  .sesion-cuenta { display: block; }            /* columna 1: Cuenta arriba, Pagos debajo */
  .bloque-cuenta .seccion-titulo:first-child { margin-top: 0; }

  /* 🔴 «Cancelada · Cerrada» (Tiziano, 21-sep-2026, hallazgo del testigo sobre 78d1a32): SIN
     esto, el letrero queda como el primer ítem del grid de 3 columnas de acá arriba —una sola
     celda, la de la izquierda— y `text-align: center` solo centra el TEXTO dentro de esa
     celda angosta, no la caja dentro de la página. Con `grid-column: 1 / -1` el letrero
     atraviesa las tres columnas como una fila propia; el resto (Cuenta | Personas | Datos)
     se sigue acomodando debajo, en la fila siguiente, sin tocar nada de eso. */
  #letrero-bloqueo { grid-column: 1 / -1; }
}

/* ---------- reporte mensual ---------- */
.mes-nav {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 6px; gap: 8px;
}
.mes-label { font-weight: 700; font-size: 17px; flex: 1; text-align: center; }

.rep-hero {
  background: var(--marca); color: #fff; border-radius: var(--radio);
  padding: 20px; text-align: center; box-shadow: var(--sombra);
}
.rep-hero-label { font-size: 13px; opacity: .9; }
.rep-hero-monto { font-size: 34px; font-weight: 800; margin: 4px 0 14px; }
.rep-metodos {
  display: flex; justify-content: space-around; gap: 8px;
  border-top: 1px solid rgba(255,255,255,.25); padding-top: 12px;
}
.rep-metodos span { display: flex; flex-direction: column; font-size: 12px; opacity: .92; }
.rep-metodos b { font-size: 16px; font-weight: 700; }

.rep-cards { display: flex; gap: 10px; margin-top: 12px; }
.rep-card {
  flex: 1; background: var(--tarjeta); border-radius: var(--radio);
  box-shadow: var(--sombra); padding: 12px; text-align: center;
}
.rep-card span { display: block; font-size: 12px; color: var(--muted); }
.rep-card b { display: block; font-size: 18px; font-weight: 700; margin-top: 4px; }
.rep-gasto { color: var(--rojo); }

.rep-lista { list-style: none; }
.rep-row {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 14px; margin-bottom: 8px;
}
.rep-row-main { display: flex; flex-direction: column; min-width: 0; }
.rep-row-t { font-weight: 600; font-size: 15px; }
.rep-row-sub { font-size: 13px; color: var(--muted); margin-top: 2px; }
.rep-row-monto { font-size: 16px; font-weight: 700; white-space: nowrap; }
.rep-saldo { color: var(--rojo); font-weight: 600; }

/* Los renglones que van ENTRE los conteos: el egreso que salió del cajón y el descuadre que
   dejó un conteo. Van sangrados y con la raya roja a la izquierda para que se lean como lo
   que son —cosas que pasaron entre dos mediciones— y no como un conteo más. */
.linea-egreso, .linea-descuadre { margin-left: 28px; border-left: 4px solid #c0392b; }
.linea-descuadre { background: #fdecec; }

.rep-badge {
  font-size: 10px; font-weight: 700; padding: 1px 7px; border-radius: 999px;
  margin-left: 6px; vertical-align: middle; text-transform: uppercase; letter-spacing: .3px;
}
.rep-badge-estudio { background: #fdecec; color: var(--marca-osc); }
.rep-badge-natalia { background: #eef3ff; color: #2b53a8; }
/* CANCELADA / POSPUESTA con saldo: gris, no rojo. No es una deuda que se persiga; es algo
   que un humano tiene que mirar. Ver ESTADOS_NO_COBRABLES en server.py. */
.rep-badge-cerrada { background: #ecebeb; color: #6b6365; }

.rep-grupo {
  font-weight: 800; font-size: 13px; letter-spacing: .4px; text-transform: uppercase;
  color: var(--marca-osc); margin: 26px 0 4px; padding-bottom: 6px;
  border-bottom: 2px solid var(--borde);
}
.rep-grupo:first-child { margin-top: 4px; }
.rep-grupo-deuda { color: var(--rojo); border-bottom-color: #f3c9c4; }
.pill-deuda { background: var(--rojo); }
.pill-cerrada { background: #8b8285; }
.rep-nota { font-size: 12px; color: var(--muted); margin: -2px 0 8px; }

.rep-det { margin: 0; }
.rep-sum {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px;
}
.rep-sum::-webkit-details-marker { display: none; }
.rep-sum::after {
  content: "▸"; margin-left: auto; color: var(--muted);
  transition: transform .15s ease; font-weight: 400;
}
details[open] .rep-sum::after { transform: rotate(90deg); }

/* 🔴 UNA SOLA COLUMNA EN EL TELÉFONO, y está MEDIDO a 390 px: en dos columnas la fila mide
   150 px, el valor («6 sesiones · 18 h») mide 107 y el `gap` 8, así que al nombre le quedan
   35 px — y «Sin técnico» necesita 67. **En dos columnas el nombre NO ENTRA de ninguna
   manera**: no es un `overflow` mal puesto, es que el ancho no existe. En una columna la fila
   mide 342 px y sobran 227 para el nombre.
   El precio son 47 px de alto, y se pagan donde no duelen: desde este trabajo el resumen va
   DEBAJO de la rejilla, o sea fuera del primer pantallazo. Arriba habría sido impagable. */
.rep-resumen-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
/* 480 px es el ancho a partir del cual entran dos columnas sin recortar. La fila necesita
   182 px = 67 (nombre) + 8 (`gap`) + 107 (valor), y la columna necesita esos 182 más los
   24 del `padding` lateral de `.rep-mini`: 206 px. Los 206 se alcanzan a los 454 px de
   viewport (2×206 + 10 de `gap` + 32 del `padding` de `.contenido`); a 480 la columna mide
   219 y sobran 13. Antes de 454, dos columnas vuelven a recortar. */
@media (min-width: 480px) {
  .rep-resumen-cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.rep-mini {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 10px 12px;
}
.rep-mini-titulo {
  font-size: 11px; text-transform: uppercase; letter-spacing: .3px;
  color: var(--muted); font-weight: 700; margin-bottom: 6px;
}
.rep-mini-fila {
  display: flex; justify-content: space-between; gap: 8px; align-items: baseline;
  font-size: 13px; padding: 3px 0; border-top: 1px solid var(--borde);
}
.rep-mini-fila:first-of-type { border-top: none; }
/* 🔴 EL NOMBRE NO SE RECORTA. Estaba recortado EN PRODUCCIÓN y se midió a 390 px: la caja
   del rótulo medía 35 px contra 43-46 px de texto, así que «Por técnico» decía «Ric…»,
   «Tiz…», «And…», y «Sin técnico» se leía «Sin…». El bloque que existe para decir DE QUIÉN
   es el mes no decía de quién es el mes.
   La causa era la pareja: el rótulo llevaba `overflow:hidden; text-overflow:ellipsis;
   white-space:nowrap` y el `<b>` de al lado —también `nowrap`— no podía encogerse, así que
   se quedaba con todo el ancho y el único que cedía era el nombre.
   👉 Se le saca el recorte al rótulo: si un nombre no entra, BAJA DE LÍNEA. Un nombre en dos
   líneas se lee; un nombre cortado es otro nombre. El `<b>` conserva su `nowrap` (una cifra
   partida en dos líneas sí sería ilegible) y ahora además `flex-shrink: 0`, que es lo que ya
   hacía de hecho — escrito, para que no dependa de un efecto lateral del `nowrap`.
   ⚠️ Esto SOLO no alcanzaba: con dos columnas el nombre bajaba de línea partido por la mitad
   («Andr / es»). Quien de verdad arregla el recorte es la columna única de arriba; esto es la
   red por si algún día aparece un nombre más largo que la fila entera. */
.rep-mini-fila span { color: var(--texto); min-width: 0; overflow-wrap: anywhere; }
.rep-mini-fila b { white-space: nowrap; flex-shrink: 0; }
.rep-mini-vacio { color: var(--muted); font-size: 13px; }
@media (min-width: 820px) { .rep-resumen-cols { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ---------- reparto del mes ----------
   Reusa todo lo de arriba (`mes-nav`, `rep-row*`, `rep-mini*`, `seccion-titulo`). Lo único
   propio son tres cosas: la columna del nombre, la raya del corte y el hueco. */

/* El nombre del técnico va donde el reporte pone el monto, y con el mismo peso en las CUATRO
   filas — con acta, sin acta, con promesa y sin promesa. Lo que cambia entre ellas es el
   VERBO de arriba («atendió» / «le toca»), no el tamaño del nombre. */
.rep-quien { display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.rep-verbo { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .3px; }
.rep-nombre { font-size: 16px; font-weight: 700; white-space: nowrap; }

/* 🔴 LA RAYA DEL CORTE: la frontera entre lo que ya pasó y lo que falta. La decide el
   SERVIDOR (campo `paso`) — acá sólo se dibuja. Va una sola vez en el mes, y en un mes
   entero pasado o entero futuro no va ninguna. */
.rep-corte {
  display: flex; align-items: center; gap: 10px;
  margin: 22px 0 6px; font-size: 12px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .4px; font-weight: 700;
}
.rep-corte::before, .rep-corte::after {
  content: ""; flex: 1; height: 2px; background: var(--borde);
}

/* El hueco: «— sin técnico —» (nadie se comprometió todavía) o «— sin acta —» (la sesión
   pasó y nadie firmó). Color de AVISO, no de error: falta un dato, no se rompió nada.
   ⚠️ NO usa `var(--acento)` (#f2b441) tal cual: ese amarillo es el del logo y está pensado
   para FONDOS, no para texto — sobre blanco da menos de 2:1 y el rótulo más importante de la
   fila sería el menos legible. Se usa su versión oscura, que se lee como el mismo aviso. */
.rep-hueco { color: #9a6200; font-weight: 700; }

/* ---------- EL VISTAZO DEL MES: la rejilla ----------
   Copiada en forma de `public/tablero.html` (`.tb-mes-cab` / `.tb-mes-dias` / `.tb-mes-dia`):
   siete columnas, semana desde el LUNES, y la celda de hoy pintada. Prefijo `rep-` propio y
   no `tb-`: el tablero es OTRA pantalla, y compartir clases entre dos pantallas hace que
   arreglar una rompa la otra sin que nadie lo vea. Esa lección ya está escrita en
   `tablero.html` con `tb-mes-dia` vs `tb-dia`. */
.rep-grilla-cab, .rep-grilla {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px;
}
.rep-grilla-cab span {
  font-size: 10px; font-weight: 600; letter-spacing: .06em;
  color: var(--muted); text-transform: uppercase; text-align: center;
}
.rep-grilla { margin-top: 2px; align-items: start; }
/* `align-items: start` en la rejilla: sin él, un día con cuatro chips estira a TODOS los de
   su fila y el mes gana alto por la peor casilla de cada semana. */
.rep-g-dia {
  border-radius: 8px; padding: 2px 1px 4px; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.rep-g-dia-hoy { background: #fdecec; }
/* Los blancos del arranque van VACÍOS, no con los días del mes vecino: el panel sólo trae el
   mes pedido, así que esos días saldrían siempre sin chips —mintiendo— y encima justo donde
   el ojo entra a la rejilla. El JS ya los pinta sin contenido; esto es la red por si alguien
   les mete un número. Misma decisión, y mismo motivo, que `.cal-hueco`. */
.rep-g-blanco { visibility: hidden; }
.rep-g-n {
  font-size: 11px; font-weight: 600; line-height: 1.2; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.rep-g-dia-hoy .rep-g-n { color: var(--marca-osc); font-weight: 800; }
.rep-g-chips { display: flex; flex-direction: column; gap: 2px; width: 100%; min-width: 0; }

/* EL CHIP. Los cuatro estados se separan por RELLENO y BORDE, no por color solo:
       relleno  = ya pasó        punteado = falta
   y eso reemplaza a la raya del corte de la lista, porque la rejilla ya marca hoy.
   🔴 Dentro va el NOMBRE, no la inicial: una inicial obliga a aprenderse una leyenda de
   personas. A 390 px la columna mide ~47 px y a 10 px entran 5-6 caracteres; el resto lo
   recorta el CSS —no el JS—, así que en una pantalla ancha no se recorta nada y el nombre
   entero viaja siempre en el `title`. */
.rep-chip {
  display: block; box-sizing: border-box; width: 100%; min-width: 0;
  font-size: 10px; line-height: 1.4; padding: 0 2px; border-radius: 4px;
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  border: 1px solid transparent;
}
.rep-chip-acta { background: #ecebeb; color: #4a4344; }
/* El mismo ámbar del rótulo «— sin acta —» de la lista (`.rep-hueco`): un solo aviso, un
   solo color. Sobre #fff3d6, el #9a6200 pasa de 5:1. */
.rep-chip-sin-acta { background: #fff3d6; color: #9a6200; font-weight: 700; }
.rep-chip-toca { background: #fff; border: 1px dashed #b7afb0; color: #6b6365; }
.rep-chip-sin-tecnico { background: #fff; border: 1px dashed #c08c2a; color: #9a6200; font-weight: 700; }
/* La marca de la PROMESA ROTA. En el chip se pinta el ACTA —quien realmente atendió—, así
   que sin esta marca el vistazo mentiría por omisión. Los dos nombres van en la lista. */
.rep-chip-marca { font-style: normal; font-weight: 800; }
/* El chip es un BOTÓN (lleva a la sesión). Esto lo deja con la cara del rótulo de antes:
   sin la fuente, el margen ni la sangría propios del botón. El texto se recorta en los dos
   hijos y no en el botón, porque `text-overflow` sobre un `<button>` no lo respetan todos
   los navegadores. */
button.rep-chip {
  font-family: inherit; margin: 0; cursor: pointer; appearance: none; -webkit-appearance: none;
  -webkit-tap-highlight-color: transparent;
}
button.rep-chip:focus-visible, .rep-ir:focus-visible { outline: 2px solid var(--marca); outline-offset: 1px; }
/* La HORA arriba y el NOMBRE debajo (teléfono: ~39 px de texto por columna). */
.rep-chip-h, .rep-chip-n {
  display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rep-chip-h { font-weight: 400; font-variant-numeric: tabular-nums; }
/* La fila de la lista se toca entera; el «›» es la misma acción para teclado y lector. */
.rep-row-ir { cursor: pointer; }
.rep-ir {
  flex: none; border: none; background: none; font-family: inherit; cursor: pointer;
  font-size: 22px; line-height: 1; color: var(--marca-osc); min-width: 32px; min-height: 32px;
  padding: 0 2px; -webkit-tap-highlight-color: transparent;
}
.rep-grilla-ley {
  display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap;
  font-size: 11px; color: var(--muted); padding-top: 6px;
}
.rep-grilla-ley span { display: flex; align-items: center; gap: 4px; }
.rep-grilla-ley .rep-chip { display: block; width: 14px; height: 11px; flex: none; padding: 0; }

/* ---------- EL DETALLE, PLEGADO ----------
   Mecanismo copiado de `tablero.html`: `grid-template-rows: 1fr → 0fr`. Abierta, la fila se
   mide sola; cerrada, se puede animar hasta cero. Y si un navegador no supiera animar `fr`,
   `0fr` igual MIDE cero: se pliega de golpe, pero nunca se queda a medio cerrar.
   `user-select: none` y el resaltado transparente NO son cosmética: el contenido del botón es
   TEXTO, y sin ellos el toque en el teléfono selecciona la palabra y saca el menú de copiar
   en vez de plegar. */
.rep-detalle { margin-top: 10px; }
.rep-plegar {
  display: flex; align-items: center; gap: 7px; width: 100%;
  border: none; background: none; font-family: inherit; cursor: pointer;
  padding: 8px 2px; font-size: 13px; font-weight: 700; color: var(--marca-osc);
  user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
}
/* 11 px: a 9 el triángulo mide 4 px de ancho y no se lee como «esto se abre». */
.rep-chev { font-size: 11px; line-height: 1; color: var(--marca); opacity: .75;
  transition: transform .22s ease; }
.rep-plegado .rep-chev { transform: rotate(-90deg); }
.rep-cuerpo { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .22s ease; }
.rep-plegado .rep-cuerpo { grid-template-rows: 0fr; }
.rep-adentro { overflow: hidden; min-height: 0; }
/* El primer título de día ya no necesita el margen de arriba: lo pone el panel. */
.rep-adentro .seccion-titulo:first-child { margin-top: 2px; }
@media (prefers-reduced-motion: reduce) {
  .rep-cuerpo, .rep-chev { transition: none; }
}

/* ---------- EL PANEL EN COMPUTADORA ----------
   🔴 QUÉ PIDIÓ TIZIANO, textual: *«el panel, que se vea bien en computadora»*. Y antes,
   sobre el teléfono: *«revise y si en el telefono se ve bien»* — o sea que la pantalla
   chica está APROBADA Y CONGELADA. Por eso el ensanche entero vive dentro de este
   `@media`: por debajo de 1100 px no existe una sola declaración de acá.

   El panel no estaba roto: estaba MIDIENDO EL ANCHO EQUIVOCADO. En el teléfono no había
   espacio y el chip se apretó a 10 px de fuente en una columna de 47. En la computadora
   sobra: a 1920×1080 quedaban 336 px de blanco abajo y 720 px de ancho sin usar, con esos
   mismos chips estirados a 163 px para un texto de 39.

   ⚠️ EL CORTE VA EN 1100, no en 1024: así la tableta de 1024 queda EXACTAMENTE como está.
   ⚠️ Y `max-width` va a 1440 y no más: un calendario de siete columnas muy anchas cuesta
   recorrido de ojo entre lunes y domingo.

   🪤 LA POSICIÓN DE ESTE BLOQUE ES OBLIGATORIA, y no es estética: `bloque_css` en
   `tests/test_panel_reparto.py` corta el CSS con `CSS.index(selector + " {")`, o sea la
   PRIMERA aparición. Puesto antes de `.rep-chip`, las pruebas de los cuatro estados
   leerían la regla equivocada y dirían que sí sin haber mirado la regla que importa. */
@media (min-width: 1100px) {
  #vista-reparto .contenido { max-width: 1440px; }
  .rep-grilla-cab, .rep-grilla { gap: 6px; }
  /* 🔑 EL `min-height` NO ES ADORNO. En un mes cargado no hace nada (agosto se pasa solo
     por contenido). En uno liviano sí: septiembre a 1920×1080 quedaba con 326 px de blanco
     debajo y con esto queda con 27. REPARTE lo que sobra; nunca empuja. */
  .rep-grilla { min-height: calc(100vh - 400px); align-content: stretch; align-items: stretch; }
  .rep-grilla-cab span { font-size: 12px; }
  .rep-g-dia {
    align-items: stretch; padding: 6px 6px 8px; gap: 4px;
    border: 1px solid var(--borde); border-radius: 8px; background: var(--tarjeta);
  }
  /* 🔴 SE REDECLARA A PROPÓSITO. La regla base vive más arriba; como `.rep-g-dia` se pinta
     acá y queda DESPUÉS con la misma especificidad, sin esta línea el día de hoy pierde su
     fondo rosado — medido: pasaba de rgb(253,236,236) a blanco. */
  .rep-g-dia-hoy { background: #fdecec; border-color: #f0bcbc; }
  .rep-g-n { font-size: 13px; text-align: left; }
  /* A la IZQUIERDA, no centrado: es lo que hace legible un nombre en una casilla ancha.
     Sí, el guion del hueco queda a la izquierda en vez de centrado. Se acepta. */
  .rep-chip { font-size: 13px; line-height: 1.75; padding: 0 8px; text-align: left; border-radius: 5px; }
  /* En computadora hora y nombre van en UNA línea: sobra el ancho. */
  .rep-chip { display: flex; align-items: baseline; gap: 6px; }
  .rep-chip-h { flex: none; }
  .rep-chip-n { flex: 1 1 auto; }
  .rep-grilla-ley { font-size: 12px; padding-top: 10px; }
  .rep-grilla-ley .rep-chip { width: 18px; height: 13px; }
}

/* ---------- conversaciones (lista) ---------- */
.lista-conversaciones { list-style: none; margin-top: 12px; }
.conv-item {
  background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 12px 14px; margin-bottom: 8px; cursor: pointer;
}
.conv-item:active { border-color: var(--marca); }
.conv-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.conv-nombre { font-weight: 700; font-size: 15px; }
.conv-fecha { font-size: 12px; color: var(--muted); white-space: nowrap; }
.conv-ultimo {
  font-size: 14px; color: var(--texto); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.conv-meta { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* ---------- chat (burbujas) ---------- */
.chat-titulo { font-weight: 700; font-size: 16px; margin-left: 4px; }
/* Nombre arriba, teléfono debajo, pegados a la derecha. `flex: 1 1 0` + `min-width: 0` para
   que en un teléfono (la barra hace `wrap` bajo 640 px) un nombre largo parta en renglones
   dentro de su sitio en vez de tirar la cabecera a una fila aparte debajo del «‹ Conversaciones». */
.chat-cabecera { flex: 1 1 0; min-width: 0; margin-left: 12px; text-align: right; }
.chat-cabecera .chat-titulo { overflow-wrap: anywhere; }
.chat-telefono {
  font-size: 13px; color: var(--muted); margin-top: 2px; margin-left: 4px;
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.chat-mensajes {
  padding: 14px 16px calc(env(safe-area-inset-bottom) + 24px);
  display: flex; flex-direction: column; gap: 8px;
}

/* ---------- quién atiende la conversación + escribirle al cliente ---------- */
/* Encabezado y estado se pegan JUNTOS: dos sticky con top:0 hermanos hacen que el
   segundo desaparezca detrás del primero (mismo patrón que .sesion-topbar). */
.chat-topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--tarjeta); box-shadow: var(--sombra);
  padding-top: env(safe-area-inset-top);
}
.barra-chat { position: static; box-shadow: none; padding-top: 12px; }
.chat-estado {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 16px; background: #fff; border-top: 1px solid var(--borde);
}
.chat-estado-tomada { background: #fff8e8; border-bottom-color: var(--acento); }
.ce-texto { flex: 1; font-size: 13px; color: var(--muted); min-width: 190px; }
.chat-estado-tomada .ce-texto { color: var(--texto); font-weight: 600; }
.ce-btn {
  border: 1px solid var(--borde); background: #fff; color: var(--texto);
  border-radius: 999px; padding: 6px 13px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ce-btn:hover { border-color: var(--marca); color: var(--marca); }
.ce-btn:disabled { opacity: .5; cursor: default; }
.ce-btn-soltar:hover { border-color: var(--muted); color: var(--muted); }

/* El compositor va fijo abajo: el chat es largo y escribir no debe obligar a hacer scroll. */
.chat-enviar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; gap: 8px; align-items: flex-end;
  padding: 10px 16px calc(env(safe-area-inset-bottom) + 10px);
  background: #fff; border-top: 1px solid var(--borde);
}
.chat-enviar textarea {
  flex: 1; resize: none; max-height: 120px;
  padding: 9px 12px; border: 1px solid var(--borde); border-radius: var(--radio);
  font: inherit; font-size: 15px; color: var(--texto); background: var(--fondo);
}
.chat-enviar textarea:focus { outline: none; border-color: var(--marca); background: #fff; }
.chat-enviar textarea:disabled { opacity: .6; }
.chat-enviar .btn { padding: 9px 16px; white-space: nowrap; }

/* 📷 El botón de la foto, al lado de la caja de texto. Cuadrado y del alto del textarea
   vacío: se pulsa con el pulgar sin apuntar. */
.ce-foto-btn {
  flex: 0 0 auto; width: 40px; height: 40px; padding: 0;
  border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--fondo); font-size: 19px; line-height: 1; cursor: pointer;
}
.ce-foto-btn:hover:not(:disabled) { border-color: var(--marca); background: #fff; }
.ce-foto-btn:disabled { opacity: .5; cursor: default; }

/* La vista previa: lo que se va a mandar, antes de mandarlo. */
.ce-foto-caja {
  position: sticky; bottom: 0; z-index: 6;
  display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap;
  padding: 10px 16px; background: #fff8e8;
  border-top: 1px solid var(--acento); border-bottom: 1px solid var(--acento);
}
.ce-foto-prev {
  width: 68px; height: 68px; object-fit: cover; flex: 0 0 auto;
  border-radius: var(--radio); border: 1px solid var(--borde); background: var(--fondo);
}
.ce-foto-datos { flex: 1; min-width: 170px; display: flex; flex-direction: column; gap: 5px; }
.ce-foto-nombre { font-size: 13px; font-weight: 600; color: var(--texto); overflow-wrap: anywhere; }
.ce-foto-peso { font-size: 12px; color: var(--muted); }
.ce-foto-rotulo {
  width: 100%; padding: 7px 10px; border: 1px solid var(--borde);
  border-radius: var(--radio); font: inherit; font-size: 14px;
  color: var(--texto); background: #fff;
}
.ce-foto-rotulo:focus { outline: none; border-color: var(--marca); }
.ce-foto-acciones { display: flex; gap: 8px; align-items: center; flex: 0 0 auto; }
.ce-foto-acciones .btn { padding: 9px 14px; white-space: nowrap; }

/* Qué pasó con la foto. Tres caras, y la que importa es la del medio: cuando NO salió, se
   lee el motivo que escribió el servidor, no un aspa roja. */
.ce-foto-estado {
  margin: 0; padding: 9px 16px;
  font-size: 13px; line-height: 1.45; color: var(--texto);
  background: var(--fondo); border-top: 1px solid var(--borde);
  position: sticky; bottom: 0; z-index: 4; overflow-wrap: anywhere;
}
.ce-foto-estado-malo { background: #fdecec; border-top-color: #e0a3a3; }
.ce-foto-estado-bueno { background: #eaf6ec; border-top-color: #9ec9a6; }
.ce-aviso {
  margin: 0; padding: 9px 16px calc(env(safe-area-inset-bottom) + 12px);
  background: #fdf1d6; border-top: 1px solid var(--acento);
  font-size: 13px; line-height: 1.4; color: var(--texto);
  position: sticky; bottom: 0; z-index: 4;
}
.chat-burbuja {
  max-width: 80%; padding: 9px 12px; border-radius: 16px;
  box-shadow: var(--sombra); word-wrap: break-word; overflow-wrap: anywhere;
}
.chat-usuario { align-self: flex-start; background: #fff; border-bottom-left-radius: 4px; }
.chat-natalia {
  align-self: flex-end; background: #fde3e4; border-bottom-right-radius: 4px;
}
.chat-dia { text-align: center; margin: 8px 0 2px; }
.chat-dia span {
  display: inline-block; background: rgba(0, 0, 0, .07); color: var(--muted);
  font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 999px;
}
.chat-texto { font-size: 15px; white-space: pre-wrap; line-height: 1.35; }
.chat-hora { font-size: 11px; color: var(--muted); margin-top: 4px; text-align: right; }
.chat-check { margin-left: 5px; letter-spacing: -2px; font-size: 12px; }
.chat-check.leido { color: #34b7f1; }   /* ✓✓ azul = leído */
.chat-check.fallo { letter-spacing: 0; }

.chat-comp { max-width: 78%; }
.chat-comp-cap { font-size: 12px; font-weight: 700; color: var(--marca-osc); margin-bottom: 6px; }
.chat-img {
  display: block; width: 100%; max-width: 240px; border-radius: 10px;
  border: 1px solid var(--borde); background: var(--fondo);
}
.chat-comp-texto { margin-top: 6px; }   /* caption que vino junto con la imagen */
.chat-comp-meta { font-size: 12px; color: var(--muted); margin-top: 6px; }
.chat-comp-estado { font-size: 12px; font-weight: 600; margin-top: 4px; color: var(--muted); }
.chat-comp-estado.est-rechazado { color: var(--rojo); }
.chat-comp-estado.est-confirmado { color: #1f8a4c; }
.chat-comp-estado.est-por-verificar { color: var(--acento); }
.chat-comp-link {
  display: inline-block; margin-top: 6px; font-size: 13px; font-weight: 600;
  color: var(--marca); text-decoration: none;
}
/* La FOTO SALIENTE: la que el estudio le manda al cliente desde el chat. Se ve como una foto,
   no como el link crudo que guarda la tabla (ver `burbujaFoto` en app.js). */
.chat-foto { max-width: 78%; }
.chat-foto-cap { font-size: 12px; font-weight: 700; color: var(--marca-osc); margin-bottom: 6px; }
.chat-foto-rotulo { margin-top: 6px; }   /* el pie de foto que escribió quien la mandó */
/* 🔑 Cuando la imagen no carga, el navegador pinta el `alt` ACÁ DENTRO — el aviso y la
   dirección. Por eso esta caja conserva alto y borde en vez de colapsar a nada: un hueco
   mudo es justo lo que no se quiere. */
.chat-foto-img { min-height: 44px; font-size: 12px; color: var(--muted); word-break: break-all; }

/* La NOTA DE VOZ: el reproductor va DENTRO de la burbuja de siempre, debajo de lo que la
   máquina entendió, para que quien lea una transcripción dudosa pueda oír el original sin
   salir del chat (ver `reproductorVozHTML` en app.js). Una fila sin audio no dibuja nada de
   esto: la burbuja se ve exactamente como antes. */
.chat-voz { margin-top: 8px; }
.chat-voz-cap { font-size: 12px; font-weight: 700; color: var(--marca-osc); margin-bottom: 4px; }
.chat-voz-audio { display: block; width: 100%; max-width: 260px; height: 34px; }

@media (min-width: 820px) { .chat-burbuja { max-width: 60%; } }

@media (min-width: 820px) {
  .rep-cards { gap: 16px; }
}

/* Crédito a favor (cancelaciones vía Natalia) */
.pr-credito { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin: 6px 0; padding: 6px 10px; border-radius: 8px;
  background: #eaf7ee; color: #1b6b34; font-size: 14px; }
.btn-credito { border: 0; border-radius: 8px; padding: 6px 12px; font-weight: 600;
  background: #1b9e4b; color: #fff; cursor: pointer; }
.btn-credito:disabled { background: #b7c7bd; cursor: default; }

/* ---------- Trabajos sin calendario (producción / mezcla-master) ---------- */
/* Cliente: buscador arriba (rellena los campos) + nombre/teléfono a mano abajo. */
.tr-cliente { display: grid; gap: 8px; }
@media (min-width: 560px) { .tr-cliente { grid-template-columns: 2fr 1fr; } }
#tr-resultados:not(:empty) { margin: 6px 0 2px; }
.trab-row { cursor: pointer; }
.trab-row:active { background: #fbf6f6; }
.trab-saldado { color: #1f8a4c; font-size: 14px; }

/* ---------- Cerrar la cuenta (la segunda dimensión de una sesión) ---------- */
/* El botón vive donde ya está el trabajo: debajo del saldo, en el panel de Pagos. Cuando la
   cuenta cuadra, cerrar es UN TOQUE; solo cuando falta o sobra dinero pide una decisión. */
.btn-cerrar-cuenta {
  width: 100%; margin-top: 10px; border: 0; border-radius: 10px; padding: 11px 12px;
  font-size: 15px; font-weight: 700; cursor: pointer;
  background: var(--texto); color: #fff;
}
.btn-cerrar-cuenta:active { opacity: 0.85; }
/* Cuenta ya cerrada: deja de ser una acción y pasa a ser un dato (se puede tocar para ver
   quién y cuándo, y ahí adentro está reabrir). */
.btn-cerrar-cuenta.cerrada {
  background: #eaf7ee; color: #1b6b34; border: 1px solid #bfe3cb; font-weight: 600;
}
/* Fase 1: no se puede cerrar todavía. El botón no se esconde — dice qué falta. */
.btn-cerrar-cuenta.bloqueada { background: #f3efe6; color: #8a6d1f; border: 1px solid #e6dcc2; }

.modal-caja-ancha { max-width: 420px; }

/* Las cuatro cifras: alineadas a la derecha y en tabular, para que se comparen de un vistazo.
   La diferencia va separada por una línea, como en una cuenta de papel. */
.cierre-cifras { display: grid; gap: 6px; font-size: 15px; }
.cierre-cifras .cf {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
}
.cierre-cifras .cf span { color: var(--muted); }
.cierre-cifras .cf b { font-variant-numeric: tabular-nums; font-weight: 700; }
.cierre-cifras .cf-dif {
  border-top: 1px solid var(--borde); padding-top: 8px; margin-top: 2px; font-size: 17px;
}
.cierre-cifras .cf-dif span { color: var(--texto); font-weight: 700; }
.cierre-cifras .cf-dif b { font-size: 19px; }

.cierre-veredicto {
  border-radius: 10px; padding: 10px 12px; font-size: 14px; line-height: 1.35;
  background: var(--fondo); color: var(--texto);
}
.cierre-veredicto.v-deuda { background: #fdeceb; color: #8e2018; }
.cierre-veredicto.v-cuadra { background: #eaf7ee; color: #1b6b34; }
.cierre-veredicto.v-sobra { background: #fff6e2; color: #8a5b00; }
.cierre-veredicto.v-bloqueada { background: #f3efe6; color: #7a5f16; }
.cierre-veredicto.v-cerrada { background: #eef1f4; color: #3d4750; }
.cierre-veredicto b { display: block; margin-bottom: 2px; }

.cierre-nota-label { font-size: 13px; color: var(--muted); }
#cierre-nota { width: 100%; font: inherit; padding: 8px 10px; border: 1px solid var(--borde);
  border-radius: 10px; resize: vertical; }

/* Botones apilados: en la rama del sobrante son dos decisiones distintas, no un sí/no, y
   ponerlas lado a lado invita a pulsar la de la derecha sin leer. */
.cierre-acciones { display: grid; gap: 8px; }
.cierre-acciones .btn { width: 100%; }
.btn-cierre-peligro { background: #b6821a; color: #fff; }

/* ---------- Cuentas abiertas (la lista sin filtro de día) ---------- */
/* 🪦 Acá vivían `.cuentas-entrada`, `.cue-ico`, `.cue-txt` y `.cue-flecha`: los recuadros que
   las dos listas tenían en el HOME. Se borraron el 26-ago junto con ese bloque, cuando las dos
   se mudaron al área de admin y pasaron a entrarse por un botón de la barra. Estaban con CERO
   usos en `index.html` y en `app.js` — comprobado antes de sacarlas, no supuesto. */

/* 🪦 Acá vivían `.cuentas-resumen` y `.cur-*` (las píldoras de arriba), `.cta-*` (la fila de «Cuentas abiertas») y más abajo `.pv-*` (la fila de «Sin verificar»). Finanzas pieza 6 (15-oct-2026) las borró: desde las piezas 2 y 3 ninguna pantalla las pinta (`#cuentas-resumen` sigue siendo el id del contenedor; la clase no). */

/* ---------- P22: el aviso espejo — RETIRADO el 18-ago-2026 ----------
   Acá vivían `.pg-aviso` y sus `.pg-av-*` (el recuadro ámbar entre la lista de pagos y el
   formulario). Se fueron con el bloque: repetía con menos detalle lo que la lista de pagos
   ya dice. Quedan huérfanas y por eso se borran — nada más las usa. */

/* ---------- P21: "el monto no cabe" ---------- */
.cabe-texto { font-size: 14.5px; line-height: 1.4; margin-bottom: 10px; }
.cabe-salida {
  background: var(--fondo); border-radius: 10px; padding: 10px 12px;
  font-size: 13.5px; line-height: 1.35; margin: 10px 0;
}

/* 🪦 Y acá vivía `.entradas-trabajo`, la rejilla que las ponía lado a lado en el home. Misma
   mudanza del 26-ago, mismos cero usos. */

/* Contador de la bandeja: si hay algo esperando, se ve sin abrir nada.
   📌 27-ago: se mudó de 🧾 a 🔒. El botón 🧾 se fue de la barra al menú de admin, y el globito
   se quedó en el home porque ahí es donde AVISA — pegado ahora a la puerta única. El mismo
   número se repite adentro, sobre la tarjeta «Sin verificar», con `.cue-badge-tile`.
   🔑 Sólo se pinta con sesión de admin viva — ver `pintarBadgePorVerificar` en `app.js`. */
#btn-admin { position: relative; }
.cue-badge {
  position: absolute; top: 1px; right: 1px;
  min-width: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--marca); color: #fff; font-size: 10.5px; font-weight: 800;
  line-height: 16px; text-align: center;
}
/* El del menú NO se pega a una esquina: va en línea, después del nombre. Sobre una tarjeta
   de 150 px una esquina absoluta queda lejísimos del texto que califica y se lee como un
   adorno; pegado a «Sin verificar» se lee como lo que es, la cuenta de esa bandeja. */
.cue-badge-tile { position: static; display: inline-block; margin-left: 6px; }

/* ---------- P29: el dinero en la tarjeta del día ---------- */
.ts-fila3 {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-top: 6px; flex-wrap: wrap;
}
.ts-dinero {
  font-size: 13.5px; font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ts-d-deuda { color: var(--rojo); }
.ts-d-ok { color: #1f8a4c; }
.ts-d-sobra { color: #8a5b00; }
/* Fase 1: ni verde ni rojo. No hay veredicto que dar — sólo lo que hay. */
.ts-d-sena { color: #7a5f16; font-weight: 600; }
.ts-d-vacia { color: var(--muted); font-weight: 600; }

/* ---------- Crédito: el caso "no se puede saber" ---------- */
/* Verde = hay dinero del cliente listo para usar. Gris = información, no una buena noticia:
   "no se puede saber" y "no se puede aplicar todavía" no son un premio, y pintarlos de verde
   los haría leer como si lo fueran. Sin rojo tampoco: no hay nada roto ni urgente. */
.pr-credito.cred-aviso {
  background: #f1f0ee; color: #5c5550; align-items: flex-start;
  font-size: 13px; line-height: 1.35;
}
.pr-credito.cred-aviso .btn-credito { background: #c4bdb7; }

/* ---------- Crédito: ni verde de caja ni rojo de deuda ---------- */
/* Es plata de los clientes guardada en la casa: no es ingreso ni deuda. Color propio para
   que nadie la lea como una de las dos. */
.pago-tag-credito { background: #eef0ff; color: #3b3f8f; }
.rep-grupo-credito { background: #eef0ff; color: #2f337a; }
.rep-credito-monto { color: #3b3f8f; }
.pill-credito { background: #3b3f8f; }

/* Movimientos del crédito: otorgado y usado se distinguen de un vistazo. */
.rep-badge-otorgado { background: #eaf7ee; color: #1b6b34; }
.rep-badge-usado { background: #eef0ff; color: #3b3f8f; }
/* El libro no se pudo leer: NO hay cifras. Se ve como lo que es — un hueco, no un cero. */
.rep-nota-roto {
  background: #fdeceb; border: 1.5px solid #f3c9c6; color: #8e2018;
  border-radius: 10px; padding: 10px 12px;
}

/* ---------- Panel de tomas: quién está atendiendo qué ---------- */
.panel-tomas { background: #fff; border-radius: 12px; padding: 10px 12px; margin-bottom: 12px;
  box-shadow: 0 1px 3px rgba(0,0,0,.08); }
.pt-encabezado { display: flex; align-items: center; justify-content: space-between; }
.pt-titulo { font-weight: 700; font-size: .82rem; letter-spacing: .04em; text-transform: uppercase;
  color: #555; }
.pt-cuerpo { margin-top: 6px; }
/* "Nadie atiende nada" es el estado NORMAL: en gris tranquilo, no como una alarma. */
.pt-nadie { color: #777; font-size: .9rem; padding: 6px 0; }
/* "No se pudo saber" es otra cosa muy distinta, y se ve distinta. */
.pt-roto { background: #fdeceb; border: 1.5px solid #f3c9c6; color: #8e2018;
  border-radius: 10px; padding: 9px 11px; font-size: .9rem; }
.pt-fila { display: flex; width: 100%; align-items: center; justify-content: space-between;
  gap: 10px; padding: 9px 4px; background: none; border: 0; border-top: 1px solid #f0f0f0;
  text-align: left; cursor: pointer; font: inherit; }
.pt-fila:first-child { border-top: 0; }
.pt-fila-main { display: flex; flex-direction: column; min-width: 0; }
.pt-quien { font-weight: 700; color: #222; }
.pt-sub { color: #888; font-size: .82rem; }
.pt-resta { color: #3b3f8f; font-size: .82rem; white-space: nowrap; }
.pt-resta-poco { color: #b3261e; font-weight: 700; }

/* ---------- Aprendizaje de Natalia: pestañas + panel de fichas ----------
   Pensada para pantalla ANCHA (Tiziano, 23-sep: «mucha información a la vez»): en celular
   sigue funcionando, apilada de arriba a abajo (ver el @media de más abajo para lo ancho). */
.apr-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.apr-tab {
  font: inherit; font-size: .86rem; font-weight: 600; color: var(--muted);
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 999px;
  padding: 7px 14px; cursor: pointer;
}
.apr-tab-activa { color: #fff; background: var(--marca); border-color: var(--marca); }
.apr-panel.oculta { display: none; }
.apr-vacio { color: var(--muted); font-size: .92rem; padding: 14px 2px; line-height: 1.4; }
.apr-vacio code { background: var(--fondo); border-radius: 4px; padding: 1px 5px; }

#apr-buscar {
  width: 100%; padding: 10px 12px; border: 1.5px solid var(--borde); border-radius: 10px;
  font-size: 1rem; margin-bottom: 10px;
}
.apr-resultados { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.apr-res-fila {
  display: flex; flex-direction: column; gap: 2px; text-align: left; font: inherit;
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 10px;
  padding: 10px 12px; cursor: pointer;
}
.apr-res-fila:active { border-color: var(--marca); }
.apr-res-nombre { font-weight: 700; }
.apr-res-meta { color: var(--muted); font-size: .82rem; }
.apr-res-pend { color: var(--marca-osc); font-size: .82rem; font-weight: 700; }
.apr-vacio-busq { color: var(--muted); font-size: .88rem; padding: 8px 2px; }
.apr-roto {
  background: #fdeceb; border: 1.5px solid #f3c9c6; color: #8e2018;
  border-radius: 10px; padding: 10px 12px; font-size: .9rem;
}

.apr-ficha.oculta { display: none; }
.apr-ficha {
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: var(--radio);
  padding: 14px 16px;
}
.apr-ficha-nombre { font-size: 1.15rem; font-weight: 800; margin-bottom: 2px; }
.apr-ficha-dup {
  background: #fff4e0; border: 1.5px solid #f2c98a; color: #8a5a00;
  border-radius: 8px; padding: 6px 10px; font-size: .84rem; margin: 8px 0; font-weight: 700;
}
.apr-grupo { margin-top: 14px; }
.apr-grupo-titulo {
  font-size: .78rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 6px;
}
.apr-campo { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0;
  border-top: 1px solid #f0eeee; font-size: .9rem; }
.apr-campo:first-child { border-top: 0; }
.apr-campo-k { color: var(--muted); }
.apr-campo-v { text-align: right; word-break: break-word; }
.apr-marca-ve { color: #1e7d3c; }
.apr-marca-no-ve { color: var(--muted); }
.apr-marca-no-escribe { color: var(--muted); font-style: italic; }
.apr-asi-te-ve {
  white-space: pre-wrap; background: var(--fondo); border-radius: 8px; padding: 10px 12px;
  font-size: .88rem; line-height: 1.4; margin-top: 6px;
}

/* Pantalla ancha: la ficha en columnas (contacto | perfil | pendientes) en vez de un solo
   listón largo — el pedido de Tiziano de ver mucha información a la vez. */
@media (min-width: 900px) {
  .apr-ficha { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px 28px; }
  .apr-ficha-nombre, .apr-ficha-dup { grid-column: 1 / -1; }
}

/* ---------- Lecciones: filtro (propuestas/aprobadas), tarjetas, editor inline ---------- */
.apr-subtabs { display: flex; gap: 6px; margin-bottom: 12px; }
.apr-subtab {
  font: inherit; font-size: .82rem; font-weight: 600; color: var(--muted);
  background: none; border: 1.5px solid var(--borde); border-radius: 999px;
  padding: 5px 12px; cursor: pointer;
}
.apr-subtab-activa { color: var(--texto); background: var(--fondo); border-color: var(--texto); }

.apr-tarjetas { display: flex; flex-direction: column; gap: 12px; }

.apr-tarjeta {
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: var(--radio);
  padding: 14px 16px;
}
.apr-tarjeta-cab { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
.apr-chip {
  font-size: .78rem; font-weight: 700; color: #fff; background: var(--marca);
  border-radius: 999px; padding: 3px 10px;
}
.apr-meta { font-size: .78rem; color: var(--muted); }
/* Texto largo LEGIBLE: tamaño de lectura, sin cortar, con más interlineado que el resto de
   la app — es lo que Tiziano va a leer con más atención de toda la pantalla. */
.apr-texto {
  font-size: 1rem; line-height: 1.55; white-space: pre-wrap; word-break: break-word;
  margin: 6px 0;
}
.apr-aviso-precio {
  background: #fff4e0; border: 1.5px solid #f2c98a; color: #8a5a00;
  border-radius: 8px; padding: 6px 10px; font-size: .84rem; font-weight: 700; margin: 8px 0;
}
.apr-enlace-chat { display: inline-block; font-size: .84rem; margin: 4px 0 8px; }
.apr-tarjeta-botones { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.apr-tarjeta-error.oculta, .apr-tarjeta-editor.oculta { display: none; }
.apr-tarjeta-error {
  margin-top: 8px; font-size: .86rem; color: var(--rojo); display: flex;
  align-items: center; gap: 8px; flex-wrap: wrap;
}

.apr-tarjeta-editor {
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--borde);
  display: flex; flex-direction: column; gap: 6px;
}
.apr-editor-label { font-size: .78rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .03em; }
.apr-editor-propuesto {
  font-size: .92rem; line-height: 1.45; white-space: pre-wrap; word-break: break-word;
  background: var(--fondo); border-radius: 8px; padding: 8px 10px; color: var(--muted);
}
.apr-editor-texto {
  width: 100%; font: inherit; font-size: 1rem; line-height: 1.5; padding: 8px 10px;
  border: 1.5px solid var(--borde); border-radius: 8px; resize: vertical;
}
.apr-editor-alcance, .apr-editor-motivo, .apr-editor-motivo-retiro {
  font: inherit; font-size: .95rem; padding: 8px 10px; border: 1.5px solid var(--borde);
  border-radius: 8px;
}
.apr-editor-nota { font-size: .86rem; color: var(--muted); }
.apr-editor-botones { display: flex; gap: 8px; margin-top: 4px; }

/* Pantalla ancha: varias tarjetas a la vista a la vez (Tiziano, 23-sep: «mucha información
   a la vez») — dos columnas de tarjetas en vez de un listón único; el texto sigue con su
   propio ancho de lectura cómodo dentro de cada tarjeta. En celular sigue en 1 columna. */
@media (min-width: 900px) {
  .apr-tarjetas { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));
    gap: 14px; align-items: start; }
}

/* ---------- Cambios de ficha: una fila horizontal por cambio, agrupadas por cliente ----------
   🔴 DEBE VERSE IGUAL QUE LA MAQUETA APROBADA (`maquetas/cambios-ficha-v6.html`) — nota de
   Tiziano, 5-oct-2026: «agrega una nota para que cuando vayan a construir "Cambios en la
   Ficha" verifiquen que se vea igual como se ve el mockup». Cada regla de abajo viene de una
   regla de la maqueta; si se cambia una, se abre la maqueta al lado y se compara. */
/* El panel entero es la `.pagina` de la maqueta: columna con 16px entre barra, encabezado y lista,
   y la MISMA tipografía base (16px / 1.4) — la App agranda el `body` a 17px desde 700px de ancho y
   sin esto todo lo que hereda tamaño o interlineado saldría distinto al de la maqueta. */
#apr-panel-fichas-cambios {
  display: flex; flex-direction: column; gap: 16px; font-size: 16px; line-height: 1.4;
}
.apr-cambios-barra { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.apr-cambios-barra input.apr-cambios-buscar {
  flex: 1 1 260px; width: auto; min-width: 0; font: inherit; padding: 10px 12px;
  border: 1.5px solid var(--borde); border-radius: 10px; background: var(--tarjeta); color: var(--texto);
}
.apr-cambios-cuenta { font-size: .86rem; color: var(--muted); }
.apr-cambios-cuenta b { color: var(--texto); }

/* encabezado de columnas: solo en pantalla ancha. La fila y el encabezado comparten la rejilla */
.apr-cols, .apr-fila {
  display: grid; grid-template-columns: minmax(170px, 1fr) minmax(0, 1.6fr) minmax(0, 2fr) auto;
  gap: 24px; align-items: start;
}
.apr-cols {
  padding: 0 18px; font-size: .72rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}

.apr-cambios-lista { display: flex; flex-direction: column; gap: 10px; }
.apr-cliente-grupo { display: flex; flex-direction: column; gap: 8px; }
.apr-cliente-nombre { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 6px 4px 0; }
.apr-cliente-nombre strong { font-size: 1.05rem; font-weight: 800; }
.apr-cliente-nombre span { font-size: .8rem; color: var(--muted); }
.apr-cliente-nombre .apr-cliente-tel {
  font-size: .95rem; font-weight: 600; color: var(--texto); font-variant-numeric: tabular-nums;
}
.apr-cliente-nombre .apr-cliente-tel-no { font-weight: 400; color: var(--muted); font-style: italic; }
.apr-cliente-nombre .apr-cliente-aviso { color: var(--marca-osc); font-weight: 600; }
.apr-cliente-nombre a { font-size: .82rem; font-weight: 600; color: var(--marca); text-decoration: none; margin-left: auto; }
.apr-cliente-nombre a:hover { text-decoration: underline; }

/* El nombre del cliente se toca para abrir su ficha ahí mismo (maqueta
   `disenos/registro-cambios-ficha/maqueta-v8-ficha-en-sitio.html`). La `<strong>` va dentro del botón. */
.apr-nombre-btn { font: inherit; color: var(--texto); background: none; border: none; padding: 2px 6px; margin: -2px -6px;
  border-radius: 8px; cursor: pointer; text-align: start; white-space: normal; display: inline-flex; align-items: center; gap: 6px; }
.apr-nombre-btn::after { content: "▸"; font-size: .8rem; color: var(--muted); }
.apr-nombre-btn[aria-expanded="true"]::after { content: "▾"; color: var(--marca); }
.apr-nombre-btn:hover { background: var(--tarjeta); text-decoration: underline; text-decoration-color: var(--marca); text-underline-offset: 3px; }
.apr-nombre-btn:focus-visible { outline: 3px solid var(--acento, #f2b441); outline-offset: 2px; }

.apr-fila {
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: var(--radio);
  padding: 16px 18px;
}
.apr-fila > div { min-width: 0; }
.apr-fila-campo { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.apr-fila-fecha { font-size: .78rem; color: var(--muted); }

/* las etiquetas de columna dentro de la fila: solo se ven cuando la fila se apila (angosto) */
.apr-etq {
  display: none; font-size: .7rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 3px;
}
.apr-valor { font-size: .95rem; word-break: break-word; }
.apr-valor-vacio { color: var(--muted); font-style: italic; }
.apr-celda-propuesto { background: #fff7e3; border-radius: 10px; padding: 8px 10px; }
/* el cuadro rojo CHICO alrededor del valor de hoy (no de toda la columna) */
.apr-celda-alerta {
  display: inline-block; max-width: 100%; background: #fdeceb; border: 1.5px solid #f3c9c6;
  border-radius: 8px; padding: 3px 8px;
}
.apr-aviso-cambio { font-size: .76rem; line-height: 1.3; color: var(--marca-osc); margin-top: 5px; }
.apr-frase { font-size: .85rem; color: var(--muted); margin-top: 6px; }
.apr-frase button {
  font: inherit; font-size: .78rem; font-weight: 600; color: var(--muted); background: none;
  border: 1.5px solid var(--borde); border-radius: 8px; padding: 2px 8px; margin-left: 6px; cursor: pointer;
}

/* el valor propuesto, editable en la misma fila */
.apr-editable {
  display: block; width: 100%; font: inherit; font-size: .95rem; font-weight: 700; color: var(--texto);
  background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 8px; padding: 7px 9px;
  resize: vertical; min-height: 38px; line-height: 1.35;
}
select.apr-editable { resize: none; appearance: auto; -webkit-appearance: auto; }
.apr-editable:focus-visible { outline: 3px solid var(--acento); outline-offset: 1px; }
.apr-editable::placeholder { font-weight: 400; color: var(--muted); }
.apr-editado-nota {
  display: flex; gap: 10px; align-items: center; font-size: .78rem; color: var(--marca-osc); margin-top: 6px;
}
.apr-editado-nota button {
  font: inherit; font-size: .78rem; font-weight: 600; color: var(--muted); background: none;
  border: none; text-decoration: underline; cursor: pointer; padding: 0;
}

/* botones de la fila */
.apr-fila-botones { display: flex; flex-direction: column; gap: 6px; min-width: 150px; }
.apr-fila .btn {
  font-size: .88rem; font-weight: 700; line-height: inherit; border-radius: 10px; padding: 9px 14px; white-space: nowrap;
  border-width: 1.5px; border-style: solid; border-color: transparent;
}
.apr-fila .btn-fantasma2 { border-color: var(--borde); }
.apr-fila .btn-primario:hover:not([disabled]) { background: var(--marca-osc); }
.apr-fila .btn-fantasma2:hover:not([disabled]) { border-color: var(--muted); color: var(--texto); }
.apr-fila .btn:focus-visible, .apr-cambios-buscar:focus-visible { outline: 3px solid var(--acento); outline-offset: 2px; }
.apr-fila .btn[disabled] { opacity: .4; cursor: not-allowed; }
.apr-fila .btn:active { transform: none; }   /* la App encoge los botones al pulsar; la maqueta no */

/* la franja de «Descartar» y el error viven DENTRO de la fila, a todo lo ancho */
.apr-fila-descartar, .apr-fila-error { grid-column: 1 / -1; }
.apr-fila-descartar {
  padding-top: 10px; border-top: 1px dashed var(--borde); display: flex; flex-direction: column; gap: 6px;
}
.apr-fila-error { font-size: .86rem; color: var(--rojo); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* decidida: el servidor lo confirmó */
.apr-fila-hecha { opacity: .45; }
.apr-fila-hecha .apr-fila-botones { visibility: hidden; }
.apr-fila-hecha .apr-editable { pointer-events: none; }

/* ---------- Preguntas libres: una fila de pregunta + respuesta opcional ---------- */
.apr-chip-pregunta { background: #3d5a80; }
.apr-pregunta-texto { font-size: .98rem; }
.apr-fila-pregunta input.apr-editor-respuesta {
  width: 100%; font: inherit; padding: 9px 11px; border: 1.5px solid var(--borde);
  border-radius: 10px; color: var(--texto); background: var(--tarjeta);
}

/* angosto: las filas se apilan, y las etiquetas de columna aparecen dentro de la fila */
@media (max-width: 900px) {
  .apr-cols { display: none; }
  .apr-fila, .apr-fila-pregunta { grid-template-columns: 1fr; gap: 14px; }
  .apr-etq { display: block; }
  .apr-fila-botones { flex-direction: row; flex-wrap: wrap; min-width: 0; }
  .apr-cliente-nombre a { margin-left: 0; }
}

/* ---------- Resumen: el selector de rango y las tablas ---------- */
.apr-resumen-rango {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 16px;
}
.apr-resumen-rango input[type="date"] {
  font: inherit; font-size: .92rem; padding: 6px 8px; border: 1.5px solid var(--borde);
  border-radius: 8px;
}
.apr-tabla-resumen {
  width: 100%; border-collapse: collapse; font-size: .88rem; margin-bottom: 6px;
}
.apr-tabla-resumen th, .apr-tabla-resumen td {
  text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--borde);
}
.apr-tabla-resumen th { color: var(--muted); font-weight: 700; font-size: .76rem;
  text-transform: uppercase; letter-spacing: .02em; }
.apr-tabla-resumen td:not(:first-child), .apr-tabla-resumen th:not(:first-child) {
  text-align: right;
}
/* Celular: la tabla se desliza en horizontal en vez de aplastar columnas ilegibles. */
@media (max-width: 640px) {
  .apr-tabla-resumen { display: block; overflow-x: auto; white-space: nowrap; }
}

/* Historial de tomas de una conversación */
.ht-det { background: #fff; border-top: 1px solid #eee; }
.ht-sum { cursor: pointer; padding: 8px 14px; font-size: .82rem; color: #666; font-weight: 600; }
.ht-cuerpo { padding: 0 14px 10px; }
.ht-lista { list-style: none; margin: 0; padding: 0; }
.ht-fila { display: flex; gap: 8px; padding: 5px 0; border-top: 1px solid #f4f4f4;
  font-size: .85rem; }
.ht-cuando { color: #999; white-space: nowrap; }
.ht-mas { font-size: .8rem; padding: 4px 0; }

/* ---------- B3: el letrero que espera el comprobante ---------- */
/* Va POR ENCIMA de los demás modales (200) a propósito. Los dos bloqueos —éste y
   `modal-vacia`— son hermanos en <body> y con el mismo z-index ganaría el orden del HTML,
   no el que de verdad bloquea. El apilado ya lo impide `frenarSalidaVacia()`; esto es el
   cinturón por si algún día aparece una cuarta puerta. */
.modal-comprobante { z-index: 210; }
.modal-comprobante .modal-caja { border-top: 5px solid #eb2129; }
/* Llegó: el letrero se apaga solo, pero antes se ve POR QUÉ se apagó. Un bloqueo que
   desaparece sin explicación deja al técnico sin saber si puede seguir o si falló algo. */
.modal-comprobante.comp-llego .modal-caja { border-top-color: #1f8a44; }
.modal-comprobante.comp-llego #comp-titulo { color: #1f8a44; }
/* Con el comprobante ya recibido, "✕ El comprobante no llegó" contradice al título — y en los
   ~2 s que el letrero tarda en apagarse solo, un dedo apurado anularía un pago cuyo
   comprobante acaba de entrar.
   🔴 Se esconde por CSS, NO tocando el botón: `pintarLetrero` no puede meterse con
   `#comp-acciones` (ver la línea roja de este bloque — un repintado no puede quitarle al
   técnico la única salida). Así el botón sigue existiendo y habilitado, y si esta clase
   fallara el resultado sería la ✕ VISIBLE, que es el lado seguro del error. */
.modal-comprobante.comp-llego #comp-acciones { display: none; }
/* No se pudo comprobar: ni "llegó" ni "no llegó" — NO SE SABE, y se ve distinto de los dos. */
.modal-comprobante.comp-nose .modal-caja { border-top-color: #b8860b; }
.modal-comprobante.comp-nose #comp-titulo { color: #8a6300; }
.comp-regla {
  font-size: 12.5px; line-height: 1.35; opacity: .85; margin-top: 2px;
}

/* ---------- «Cancelada · Cerrada» (Tiziano, 19-sep-2026; centrado 21-sep-2026): el letrero
   que apaga la cuenta. Pedido de Tiziano: el texto salía pegado al lado izquierdo del
   letrero (alineación por omisión); ahora va centrado dentro de su caja. -- */
.letrero-bloqueo {
  margin: 10px 14px 0; padding: 10px 14px; border-radius: 8px;
  background: #fdecea; color: #611a15; border: 1px solid #f3b4ac;
  font-size: .88rem; font-weight: 600; line-height: 1.4;
  text-align: center;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   LA CAJA CHICA · el conteo de efectivo y el registro de gastos
   ══════════════════════════════════════════════════════════════════════════════════════ */

.conteo-caja {
  max-width: 520px;
  margin: 0 auto;
  padding: 24px 16px 48px;
}

.conteo-titulo {
  font-size: 1.35rem;
  margin: 0 0 4px;
}

.conteo-motivo {
  color: #666;
  margin: 0 0 20px;
  font-size: .95rem;
}

.conteo-tabla {
  width: 100%;
  border-collapse: collapse;
}

.conteo-tabla th,
.conteo-tabla td {
  padding: 8px 6px;
  border-bottom: 1px solid #eee;
  text-align: right;
}

.conteo-tabla thead th {
  font-size: .75rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #888;
  border-bottom: 2px solid #ddd;
}

.conteo-tabla .ct-den { text-align: left; }

/* La cantidad es lo ÚNICO que la persona escribe. Se le da todo el peso visual: el subtotal
   y el total son resultados, no campos. */
.conteo-tabla input {
  width: 100%;
  max-width: 88px;
  padding: 10px 8px;
  font-size: 1.05rem;
  text-align: right;
  border: 1px solid #ccc;
  border-radius: 8px;
  /* Teclado numérico en el celular y sin las flechitas, que en una tabla de diez filas son
     un imán para tocarlas sin querer. */
  -moz-appearance: textfield;
}

.conteo-tabla input::-webkit-outer-spin-button,
.conteo-tabla input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.conteo-tabla input:focus {
  outline: none;
  border-color: #eb2129;
  box-shadow: 0 0 0 3px rgba(235, 33, 41, .12);
}

/* Una fila en cero se apaga: con diez filas siempre presentes, lo que tiene valor tiene que
   saltar a la vista. */
.conteo-tabla tr.ct-vacia .ct-sub { color: #bbb; }

.conteo-tabla tfoot th {
  padding-top: 14px;
  font-size: 1.05rem;
  border-bottom: none;
}

.ct-total {
  font-size: 1.35rem;
  font-variant-numeric: tabular-nums;
}

.conteo-tabla .ct-sub { font-variant-numeric: tabular-nums; }

/* El aviso de diferencia. Amarillo y no rojo, a propósito: SUGIERE volver a contar, no
   acusa a nadie y no bloquea. Un rojo de alarma sobre algo que al principio va a estar mal
   seguido se aprende a ignorar en una semana. */
.conteo-aviso {
  margin: 16px 0 0;
  padding: 12px 14px;
  border-radius: 10px;
  background: #fff6d8;
  border: 1px solid #f0d98a;
  color: #6b5200;
  font-size: .95rem;
  line-height: 1.4;
}

/* ⚠️ EL NOMBRE ES HISTÓRICO Y EL ÚNICO USUARIO DE HOY ES OTRO. Estas tres reglas nacieron
   para «la caja está vacía» del conteo, que se borró el 4-sep-2026; quien las usa ahora es
   **«no costó nada: me lo regalaron»** de la pantalla de COMPRA (`#co-regalo-si`), que es un
   mecanismo distinto con su propia guarda (`exigir_costo_declarado`) y sigue vivo.
   🔴 Borrarlas creyendo que son del conteo deja sin estilo el bloque del regalo.
   Neutro y no rojo, a propósito: no acusa a nadie ni avisa de un error — pide que se diga qué
   pasó, ANTES de apretar. El rojo es para lo que ya salió mal. */
.conteo-vacia {
  margin: 16px 0 0;
  padding: 12px 14px;
  border-radius: 10px;
  background: #f4f6f8;
  border: 1px solid #d5dbe1;
}

.conteo-vacia-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1.35;
  color: #22303c;
}

/* Grande a propósito: esto se toca de noche, con el celular en una mano. */
.conteo-vacia-check input {
  width: 22px;
  height: 22px;
  flex: none;
  margin-top: 1px;
}

.conteo-vacia-nota {
  margin: 8px 0 0 32px;
  font-size: .85rem;
  line-height: 1.4;
  color: #5b6b7a;
}

/* «sin total» donde iría un monto. En letra normal y gris: un RD$0,00 ahí sería una cifra
   que nadie midió, y de eso se trata todo este arreglo. */
.rep-sin-dato {
  font-weight: 400;
  font-style: italic;
  color: #8a97a3;
}

/* Acá había un `#conteo-guardar:disabled`, y se fue con la casilla de «la caja está vacía»
   el 4-sep-2026: era ella la única que apagaba este botón. Hoy nada lo deshabilita —el envío
   se serializa con `caja.guardando`, no con el atributo—, así que la regla no pintaba nada.
   Si mañana alguien vuelve a deshabilitarlo, la regla vuelve con él. */
#conteo-guardar { margin-top: 20px; }

#vista-gasto .campo-label { margin-top: 14px; }

#vista-gasto input,
#vista-gasto select {
  width: 100%;
  padding: 12px 10px;
  font-size: 1rem;
  border: 1px solid #ccc;
  border-radius: 8px;
}

#vista-gasto .fila-botones { margin-top: 24px; }
/* =========================================================================
   EL CUADRE DIARIO DE CAJA + EL REPORTE DE CUADRES

   🔴 Bloque nuevo, agregado AL FINAL a propósito: otras dos sesiones estaban
   editando este archivo el mismo día y añadir al final es lo único que no
   puede pisar una regla ajena.

   🔑 La idea de color de todo esto: **hay tres formas de NO SABER y ninguna
   puede parecerse a «cuadró»**. Un «no se puede comparar» pintado de verde
   sería una ausencia disfrazada de dato — que es la familia de errores de
   esta casa (el exit code 0 que se lee «pasó», el tablero vacío que se lee
   «libre»). Por eso `cuadre-duda` es ÁMBAR y no gris: el gris se lee como
   «nada que ver acá», y acá sí hay algo que ver.
   ========================================================================= */

/* El límite de alcance, arriba de las dos pantallas. No es decorativo:
   alguien va a echar de menos las transferencias y tiene que encontrar el
   porqué en la pantalla misma, no en un archivo que nadie va a abrir. */
.cuadre-limite {
  background: #fdecec; border-left: 4px solid var(--marca);
  border-radius: 8px; padding: 10px 12px; margin-bottom: 14px;
  font-size: 13px; line-height: 1.45; color: var(--texto);
}

.cuadre-aviso {
  background: #fffaf0; border-left: 4px solid var(--acento);
  border-radius: 8px; padding: 10px 12px; margin: 10px 0;
  font-size: 13px; line-height: 1.45;
}
.cuadre-aviso.cuadre-mal { background: #fdecec; border-left-color: var(--rojo); }

.cuadre-nota-chica {
  font-size: 12.5px; line-height: 1.4; color: var(--muted); margin: 6px 0 10px;
}

/* La resta, que es la planilla de papel de Rosi hecha pantalla. */
.cuadre-caja {
  background: var(--tarjeta); border: 1px solid var(--borde);
  border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 6px 14px; margin: 10px 0;
}
.cuadre-linea {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 9px 0; font-size: 15px; border-bottom: 1px solid var(--borde);
}
.cuadre-linea:last-child { border-bottom: none; }
.cuadre-linea > span { color: var(--muted); }
.cuadre-linea > b { white-space: nowrap; font-variant-numeric: tabular-nums; }
.cuadre-resta > b { color: var(--rojo); }
.cuadre-total { font-weight: 700; }
.cuadre-total > span { color: var(--texto); font-weight: 600; }
.cuadre-total > b { font-size: 17px; }

.cuadre-veredicto {
  text-align: center; font-weight: 700; font-size: 16px;
  padding: 10px; border-radius: 10px; margin: 4px 0 2px;
}

/* Los tres estados, y la diferencia entre ellos es el punto entero.
   ✅ cuadra   → verde: se pudo comparar Y coincidió.
   🔴 no cuadra → rojo: se pudo comparar y NO coincidió.
   ⚠️ duda      → ámbar: NO SE PUDO COMPARAR. No es un fracaso ni un éxito:
                  es que falta un dato, y tiene su propio color para que
                  nadie lo lea como ninguno de los otros dos. */
.cuadre-ok { background: #eaf6ec; color: #1e6b32; }
.cuadre-mal { background: #fdecec; color: var(--marca-osc); }
.cuadre-duda { background: #fff5e0; color: #8a6300; }

/* En una fila del reporte los mismos tres colores van como badge chico. */
.rep-badge.cuadre-ok, .rep-badge.cuadre-mal, .rep-badge.cuadre-duda {
  font-size: 11px; padding: 1px 7px; border-radius: 999px;
}

.cuadre-cerrar-caja {
  background: var(--tarjeta); border: 1px solid var(--borde);
  border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 14px; margin-top: 14px;
}
.cuadre-cerrar-caja input { width: 100%; margin-bottom: 10px; }
.cuadre-cerrar-caja .btn { width: 100%; }
.cuadre-cerrar-caja .cuadre-nota-chica { margin: 10px 0 0; }

/* El día que YA se cuadró: quién lo cuadró, y ningún botón que lo vuelva a ofrecer.
   Verde y sin acción — es un hecho consumado, no algo que haya que hacer. */
.cuadre-cerrado {
  background: var(--tarjeta); border: 1px solid var(--borde);
  border-left: 3px solid #1e6b32;   /* el mismo verde del veredicto «cuadra» */
  border-radius: var(--radio); box-shadow: var(--sombra);
  padding: 14px; margin-top: 14px;
}
.cuadre-cerrado-t { font-size: 15px; margin-bottom: 6px; }
.cuadre-cerrado .cuadre-nota-chica { margin: 6px 0 0; }

/* ---------- 🔒/👤 LA FIRMA — quién hizo cada acto de caja, y con qué respaldo ----------
   🔴 EL PUNTO DEL COLOR NO ES DECORAR: es que **una firma verificada y una declarada no
   se puedan confundir de un vistazo**. Rosi mira esta lista de reojo; si las dos se ven
   igual, la distinción existe en la base y no en la cabeza de nadie — que es como si no
   existiera. Mismo criterio que el 🔒 del chip de arriba a la derecha. */
.firma { white-space: nowrap; }
.firma-ok { color: var(--texto); }
.firma-declarada { color: #8a6d1f; }
.firma-rara { color: var(--rojo); }


/* ---------- 🗓 el calendario del home ----------
   Pedido de Tiziano: saltar de un día a otro con UN clic. La fecha es el botón que lo abre;
   las flechas ‹ › se quedan porque «mañana» sigue siendo un clic sin abrir nada.
   Todo lo de acá va prefijado `cal-` a propósito: convive con `fecha-nav`, que es de otra
   mano, y así se ve de un vistazo qué es del calendario y qué no. */
.fecha-zona { position: relative; }

/* La fecha pasó de rótulo a botón: se le saca la piel de botón y se le deja la de texto,
   pero con un asa visible (▾) para que se note que abre algo. */
button.fecha-label {
  background: none; border: none; font-family: inherit; color: var(--texto);
  cursor: pointer; padding: 2px 6px; border-radius: 8px; width: 100%;
}
button.fecha-label::after { content: " ▾"; font-size: 12px; color: var(--muted); }
button.fecha-label[aria-expanded="true"] { background: var(--fondo); }
button.fecha-label[aria-expanded="true"]::after { content: " ▴"; }

.cal-panel {
  position: absolute; top: 100%; left: 8px; right: 8px; z-index: 20;
  background: var(--tarjeta); border: 1.5px solid var(--borde);
  border-radius: var(--radio); box-shadow: 0 6px 22px rgba(0, 0, 0, .16);
  padding: 10px 10px 12px; max-width: 420px; margin: 4px auto 0;
}
.cal-cab { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.cal-mes-btn {
  width: 40px; height: 40px; flex: 0 0 auto; border-radius: 10px;
  border: 1.5px solid var(--borde); background: var(--tarjeta);
  font-size: 20px; line-height: 1; color: var(--marca); cursor: pointer;
}
/* Sin `text-transform: capitalize`: `mesBonito()` ya capitaliza la primera letra y sólo esa.
   Con capitalize saldría «Agosto De 2026» — cada palabra en mayúscula, incluido el «de». */
.cal-mes-titulo {
  flex: 1; text-align: center; font-weight: 700; font-size: 15px;
}
.cal-dow, .cal-grilla { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-dow {
  margin-top: 8px; font-size: 11px; font-weight: 700; color: var(--muted);
  text-align: center; letter-spacing: .5px;
}
.cal-grilla { margin-top: 2px; }

/* Los huecos del arranque van VACÍOS, no con los días del mes vecino. Un número de otro mes
   se vería sin punto aunque ese día tenga sesiones —el marcador sólo trae el mes pedido—, y
   un marcador que miente una vez deja de servir para siempre. */
.cal-hueco { visibility: hidden; }

.cal-dia {
  position: relative; aspect-ratio: 1 / 1; min-height: 40px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; border: 1.5px solid transparent; border-radius: 10px;
  background: none; font-family: inherit; font-size: 15px; color: var(--texto);
  cursor: pointer; padding: 0;
}
.cal-dia:hover { background: var(--fondo); }
.cal-dia.hoy { border-color: var(--marca); font-weight: 800; color: var(--marca); }
.cal-dia.sel { background: var(--marca); color: #fff; font-weight: 800; border-color: var(--marca); }

/* El punto: «este día tiene algo». Es un dato, no un adorno — antes del calendario nadie se
   asomaba a un día vacío porque llegar costaba clics; ahora saltar es gratis y caer en un día
   vacío pasa a ser lo normal. */
.cal-punto {
  width: 5px; height: 5px; border-radius: 50%; background: var(--marca);
}
.cal-dia.sel .cal-punto { background: #fff; }
/* Reservado SIEMPRE, tenga punto o no: si el hueco apareciera sólo en los días marcados, los
   números bailarían de posición entre una celda y la de al lado. */
.cal-punto-hueco { width: 5px; height: 5px; }

.cal-aviso {
  margin-top: 8px; padding: 6px 8px; border-radius: 8px;
  background: #fdf3e3; color: #8a5a00; font-size: 12px; text-align: center;
}

@media (max-width: 400px) {
  .cal-panel { left: 4px; right: 4px; padding: 8px 6px 10px; }
  .cal-dia { min-height: 38px; font-size: 14px; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   EL EQUIPO (solo admin) — la pantalla desde la que se registra a la gente de la casa,
   y el cartel del código de registro.

   🏠 Estas reglas nacieron sueltas en un `<style>` de `index.html`, igual que las cuatro
   del login de más arriba y por el mismo motivo: el día que se escribieron, este archivo
   estaba tomado por otra sesión. Mudadas acá al integrar la rama, el 27-ago; el `<style>`
   de `index.html` ya no existe y no vuelve.

   Todo va prefijado `eq-` / `cod-` / `acc-` para que no choque con nada.
   ══════════════════════════════════════════════════════════════════════════════════════ */
.eq-intro { max-width: none; margin-bottom: 14px; }
.eq-viejo { font-size: 13px; color: var(--rojo); margin-bottom: 12px; }
/* Los desajustes entre la tabla y las dos listas de nombres de NocoDB. Va ARRIBA de la
   lista del equipo a propósito: es lo que hay que hacer, no un pie de página. */
.eq-desajustes { margin-bottom: 14px; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--borde); background: var(--tarjeta); }
.eq-desajuste { font-size: 13px; line-height: 1.45; margin-bottom: 6px; }
.eq-desajuste-grave { color: var(--rojo); font-weight: 600; }
.eq-desajuste-pie { font-size: 12px; opacity: .75; margin-top: 8px; line-height: 1.4; }
.eq-grupo { margin-top: 18px; }
.eq-grupo-tit { font-size: 12.5px; text-transform: uppercase; letter-spacing: .06em;
                color: var(--muted); margin-bottom: 8px; }
.eq-fila { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
           padding: 12px 0; border-bottom: 1px solid var(--borde); }
.eq-datos { flex: 1 1 180px; min-width: 0; }
.eq-nombre { font-weight: 600; font-size: 15px; }
.eq-sub { font-size: 13px; color: var(--muted); margin-top: 3px; }
.eq-chips { display: inline-flex; gap: 6px; flex-wrap: wrap; margin-left: 6px;
            vertical-align: middle; }
.eq-chip { font-size: 11px; padding: 2px 7px; border-radius: 999px;
           background: #f1f1f4; color: #555; white-space: nowrap; }
.eq-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.eq-btn { font-size: 13px; padding: 8px 12px; border-radius: 9px; cursor: pointer;
          border: 1px solid var(--borde); background: #fff; white-space: nowrap; }
.eq-btn:disabled { opacity: .5; cursor: default; }
.eq-btn-1 { border-color: var(--rojo); color: var(--rojo); font-weight: 600; }
.eq-btn-quitar { color: var(--rojo); }
.eq-apagada { opacity: .55; }
/* Etapa 9: el editor de rol, casillas y módulos dentro de la ficha. Cada módulo es una fila con su nombre y su lista; el área de toque mide 44 px y nada pasa del ancho de la ficha. */
.eq-editor { margin-top: 10px; max-width: 100%; }
.eq-editor label { display: block; margin: 6px 0; font-size: 14px; }
.eq-editor select { max-width: 100%; box-sizing: border-box; min-height: 44px; font-size: 16px; }
.eq-editor .eq-mod-fila { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; min-height: 44px; }
.eq-editor .eq-mod-nombre { flex: 1 1 150px; min-width: 0; }
.eq-editor .eq-mod-fila select { flex: 0 1 220px; min-width: 0; }
.eq-editor .eq-mod-tit { margin-top: 12px; line-height: 1.45; }
/* Etapa 7b: la opción de anular el código que tiene ahora (cartel de «Se le perdió»). La fila entera es el área de toque. */
.eq-barra-nueva { margin: 0 0 14px; }
.eq-barra-nueva .eq-btn { min-height: 44px; }
/* 🔑 Pieza 11: «Persona nueva» y «Cambiar mi contraseña» van en una fila (en el celular, en dos). */
#vista-equipo .eq-barra-nueva { display: flex; flex-wrap: wrap; gap: 8px; }
/* 🔑 Pieza 11: «Cambiar mi contraseña» solo en la pestaña «Equipo» (como los bloques: lo esconde la pestaña elegida). */
#vista-equipo[data-pestana="matriz"] #btn-mi-contrasena, #vista-equipo[data-pestana="puertas"] #btn-mi-contrasena,
#vista-equipo[data-pestana="historial"] #btn-mi-contrasena { display: none; }
.pn-campo { display: block; margin: 10px 0; font-size: 14px; font-weight: 600; }
.pn-campo input, .pn-campo select { display: block; width: 100%; box-sizing: border-box; min-height: 44px; margin-top: 4px; font-size: 16px; }
#pn-explica { min-height: 4.4em; }          /* el texto más largo cabe sin que el cartel salte al cambiar de rol */
.pn-listas { font-size: 13px; line-height: 1.45; margin: 8px 0; padding: 8px 10px; border-left: 3px solid var(--naranja, #d98a00); }
.otc-opcion { display: flex; align-items: center; gap: 10px; min-height: 44px; font-size: 15px; font-weight: 600; cursor: pointer; }
.otc-opcion input { width: 22px; height: 22px; flex: none; }
#otc-explica { min-height: 5.4em; }   /* el texto más largo cabe sin que el cartel salte al marcar la casilla */

/* 🪪 «Quién puede qué» (Credenciales, etapa 2: SOLO apariencia). La caja se desplaza en horizontal y la página no:
   a 400 px la tabla (ancha) corre dentro de `.eq-matriz-caja`. La primera columna se queda quieta para saber de quién es cada fila. */
#eq-matriz { margin-top: 26px; }
#eq-matriz .eq-sub { line-height: 1.45; margin-bottom: 12px; }
.eq-permiso { line-height: 1.4; }
.eq-matriz-caja { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch;
  border: 1px solid var(--borde); border-radius: 12px; background: var(--tarjeta); }
.eq-matriz { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13.5px; }
.eq-matriz th, .eq-matriz td { padding: 9px 6px; text-align: center; vertical-align: middle;
  border-bottom: 1px solid var(--borde); background: var(--tarjeta); }
.eq-matriz tr:last-child td { border-bottom: 0; }
.eq-matriz th { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--muted); line-height: 1.25; min-width: 70px; max-width: 120px; background: var(--fondo);
  border-bottom: 2px solid var(--borde); }
.eq-matriz td { white-space: nowrap; }
.eq-matriz th:first-child, .eq-matriz td:first-child { text-align: left; position: sticky; left: 0; z-index: 1;
  min-width: 108px; font-weight: 600; }
.eq-matriz th:first-child { z-index: 2; }
.eq-matriz th:nth-child(2), .eq-matriz td:nth-child(2) { text-align: left; white-space: normal; min-width: 92px; }
.eq-matriz td:first-child { box-shadow: 1px 0 0 var(--borde); }
.eq-matriz .eq-v-no { color: var(--muted); }
.eq-matriz .eq-v-si { font-weight: 700; }
.eq-matriz .eq-v-dudoso { color: var(--rojo); font-style: italic; }
.eq-matriz tr.eq-apagada td { background: var(--fondo); }

/* 🚪 Credenciales, etapa 3: las puertas especiales y los agentes (solo lectura). Una tarjeta por puerta; el estado lleva su color. */
#eq-puertas { margin-top: 26px; }
#eq-puertas > .eq-sub { line-height: 1.45; margin-bottom: 12px; }
.eq-puerta { border: 1px solid var(--borde); border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; background: var(--card, #fff); }
.eq-puerta .eq-sub { line-height: 1.45; }
.eq-puerta-cab { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 4px 12px; }
.eq-puerta-tit { font-weight: 700; font-size: 15px; }
.eq-puerta-estado { font-size: 13px; font-weight: 700; }
#eq-puertas .eq-v-no { color: var(--muted); }
#eq-puertas .eq-v-dudoso { color: var(--rojo); font-style: italic; }
/* 🚪 Credenciales, pieza 10 («Puertas y agentes en cuadrícula»): las tarjetas en cuadrícula (una columna en el celular, varias en pantalla
   grande) y lo técnico plegado bajo «Ver el detalle técnico». SOLO bajo #vista-equipo. El aviso de «no se pudo mirar» va fuera de la cuadrícula. */
#vista-equipo #eq-puertas .eq-puertas-cuadricula { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; align-items: start; }
#vista-equipo #eq-puertas .eq-puertas-cuadricula > .eq-puerta { margin-bottom: 0; min-width: 0; }
#vista-equipo #eq-puertas .eq-puerta-detalle { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 4px; }
#vista-equipo #eq-puertas .eq-puerta-detalle > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; color: var(--accent); font-size: 13px; font-weight: 600; }
#vista-equipo #eq-puertas .eq-puerta-detalle .eq-sub { margin: 6px 0 0; overflow-wrap: anywhere; }
/* 🧾 El historial de cambios del equipo (etapa 5) */
#eq-historial { margin-top: 26px; }
#eq-historial .eq-sub { line-height: 1.45; margin-bottom: 8px; }
#eq-historial .eq-v-dudoso { color: var(--rojo); font-style: italic; }
.eq-cambio { font-size: 13.5px; line-height: 1.4; padding: 8px 0; border-bottom: 1px solid var(--borde); overflow-wrap: anywhere; }
/* 🧾 Pieza 11: la tabla del historial (como la maqueta). La caja la desliza si no cabe (el celular); la fecha no parte; «Qué cambió» sí puede partirse. */
#vista-equipo .eq-hist-caja { overflow-x: auto; max-width: 100%; background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 10px; }
#vista-equipo .eq-hist-tabla { width: 100%; border-collapse: collapse; font-size: 13.5px; line-height: 1.4; }
#vista-equipo .eq-hist-tabla th, #vista-equipo .eq-hist-tabla td { padding: 9px 10px; border-bottom: 1px solid var(--borde); text-align: left; vertical-align: top; }
#vista-equipo .eq-hist-tabla th { font-size: 12.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; }
#vista-equipo .eq-hist-tabla td:first-child { white-space: nowrap; }
#vista-equipo .eq-hist-tabla td.izq { min-width: 180px; overflow-wrap: anywhere; }
#vista-equipo .eq-hist-tabla tr:last-child td { border-bottom: 0; }

/* 🎨 Credenciales, pieza 1 («el tema»): los colores, la tarjeta, la píldora y el botón de la maqueta
   `maqueta-credenciales.html`, SOLO dentro de #vista-equipo. El resto de la App (Registro, Personas,
   Finanzas…) no ve nada de esto: las variables viven en esa sección y no en :root.
   Las variables con nombre de la App (--fondo, --tarjeta, --borde, --muted, --texto, --rojo, --marca)
   se vuelven alias de las de la maqueta, así las reglas viejas de «el equipo» toman el tema sin reescribirse.
   Toda regla de este bloque empieza por #vista-equipo: lo vigila tests/test_credenciales_tema.py.
   El modo oscuro de la maqueta y las fuentes Archivo / IBM Plex no vienen aquí (pieza 15). */
#vista-equipo {
  --bg: #f2f4f3; --panel: #ffffff; --ink: #15211e; --soft: #5b6a66; --line: #d6ddda;
  --accent: #0d6b5b; --accent-ink: #ffffff; --accent-soft: #dcefea;
  --ok: #1f7a45; --ok-soft: #dff2e6; --warn: #9a6200; --warn-soft: #fbeed2;
  --bad: #b3372b; --bad-soft: #f9e0dc; --info: #2c5aa0; --info-soft: #e0e9f7;
  --fondo: var(--bg); --tarjeta: var(--panel); --texto: var(--ink); --muted: var(--soft);
  --borde: var(--line); --rojo: var(--bad); --marca: var(--accent);
  background: var(--bg); color: var(--ink);
}
#vista-equipo .barra-tag { background: var(--accent); color: var(--accent-ink); }
#vista-equipo .contenido { max-width: 1120px; }
#vista-equipo .eq-cabecera { padding: 6px 0 4px; }
#vista-equipo .eq-titulo-pagina { font-size: 1.5rem; font-weight: 700; line-height: 1.2; margin: 0 0 4px; }
#vista-equipo .eq-titulo-pagina-sub { color: var(--soft); font-size: 0.9rem; line-height: 1.45; max-width: 72ch; margin: 0 0 14px; }
#vista-equipo .eq-btn { background: var(--panel); color: var(--ink); border-color: var(--line); border-radius: 8px; }
#vista-equipo .eq-btn-1 { border-color: var(--accent); color: var(--accent); }
#vista-equipo .eq-chip { background: var(--bg); color: var(--soft); border: 1px solid var(--line); }
#vista-equipo .eq-matriz-caja { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; }

/* 🗂️ Credenciales, pieza 2 («las cuatro pestañas»): la barra de pestañas de la maqueta y la regla que enseña UN bloque a la vez.
   SOLO bajo #vista-equipo. Lo que cada bloque pinta no cambia: lo decide su propio código. Lo que se ve lo dice `data-pestana`
   de la sección; los otros tres bloques se esconden por CSS, aunque su pintura les quite la clase `oculta`.
   Toda regla de este bloque empieza por #vista-equipo: lo vigila tests/test_credenciales_pestanas.py. */
#vista-equipo .eq-pestanas { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px; margin: 14px 0 18px; }
#vista-equipo .eq-pestanas button { font: inherit; font-size: 14px; font-weight: 500; white-space: nowrap; min-height: 44px;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink); padding: 8px 14px; border-radius: 999px; cursor: pointer; }
#vista-equipo .eq-pestanas button[aria-selected="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
#vista-equipo .eq-pestanas button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#vista-equipo[data-pestana="equipo"] #eq-matriz, #vista-equipo[data-pestana="equipo"] #eq-puertas, #vista-equipo[data-pestana="equipo"] #eq-historial,
#vista-equipo[data-pestana="matriz"] #eq-lista, #vista-equipo[data-pestana="matriz"] #eq-puertas, #vista-equipo[data-pestana="matriz"] #eq-historial,
#vista-equipo[data-pestana="puertas"] #eq-lista, #vista-equipo[data-pestana="puertas"] #eq-matriz, #vista-equipo[data-pestana="puertas"] #eq-historial,
#vista-equipo[data-pestana="historial"] #eq-lista, #vista-equipo[data-pestana="historial"] #eq-matriz, #vista-equipo[data-pestana="historial"] #eq-puertas { display: none; }
#vista-equipo #eq-matriz, #vista-equipo #eq-puertas, #vista-equipo #eq-historial { margin-top: 0; }

/* 🗂️ Credenciales, pieza 3 («lista a la izquierda, ficha a la derecha»): las tarjetas de persona a la izquierda (300 px), la ficha de la elegida a la
   derecha, y la frase de quién da permisos. SOLO bajo #vista-equipo; a 375 px la ficha va debajo de la lista (como la maqueta). Toda regla de este bloque
   empieza por #vista-equipo: lo vigila tests/test_credenciales_lista_ficha.py. */
#vista-equipo .eq-quien-da { font-size: 14px; color: var(--soft); line-height: 1.45; max-width: 72ch; margin: 0 0 12px; }
#vista-equipo .eq-split { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 760px) { #vista-equipo .eq-split { grid-template-columns: minmax(0, 1fr); } }
#vista-equipo .eq-tarjetas { min-width: 0; }
#vista-equipo .eq-tarjetas .eq-grupo { margin-top: 0; }
#vista-equipo .eq-tarjetas .eq-grupo + .eq-grupo { margin-top: 14px; }
#vista-equipo .eq-tarjetas .eq-grupo-tit { margin-bottom: 6px; }
#vista-equipo .eq-persona { display: block; width: 100%; box-sizing: border-box; min-height: 44px; text-align: left; font: inherit; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; cursor: pointer; }
#vista-equipo .eq-persona:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#vista-equipo .eq-persona-sel { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
#vista-equipo .eq-persona-cab { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
#vista-equipo .eq-persona-nombre { font-weight: 600; font-size: 15px; }
#vista-equipo .eq-persona-linea { display: block; font-size: 13px; color: var(--soft); margin-top: 4px; }
#vista-equipo .eq-pill { font-size: 12px; font-weight: 600; padding: 2px 9px; border-radius: 999px; white-space: nowrap; }
#vista-equipo .eq-pill-admin { background: var(--info-soft); color: var(--info); }
#vista-equipo .eq-pill-pasante { background: var(--warn-soft); color: var(--warn); }
#vista-equipo .eq-pill-tecnico { background: var(--bg); color: var(--soft); border: 1px solid var(--line); }
#vista-equipo .eq-pill-sin { background: var(--bad-soft); color: var(--bad); }
#vista-equipo .eq-persona.eq-apagada { opacity: .6; }
#vista-equipo .eq-ficha-caja { min-width: 0; }
#vista-equipo .eq-fila.eq-ficha { display: block; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 16px; min-width: 0; }
#vista-equipo .eq-ficha .eq-datos { min-width: 0; }
#vista-equipo .eq-ficha .eq-acciones { margin-top: 12px; }
#vista-equipo .eq-ficha .eq-ficha-yo { margin-top: 6px; }

/* 🗂️ Credenciales, pieza 4 («la ficha por secciones»): «Entrar» y «Contraseña» como en la maqueta. Un renglón por cosa (texto a la izquierda, el control a la
   derecha), el interruptor de «Puede entrar» y las píldoras. Todo bajo #vista-equipo: lo vigila tests/test_credenciales_ficha_secciones.py. */
#vista-equipo .eq-seccion { margin-top: 16px; }
#vista-equipo .eq-seccion-tit { font-size: 12.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--soft); font-weight: 600; margin-bottom: 2px; }
#vista-equipo .eq-renglon { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 10px 0; border-top: 1px solid var(--line); }
#vista-equipo .eq-renglon-txt { flex: 1 1 220px; min-width: 0; }
#vista-equipo .eq-renglon-tit { font-weight: 600; font-size: 14.5px; }
#vista-equipo .eq-renglon-ctl { flex: 0 0 auto; }
#vista-equipo .eq-seccion-acc { padding: 10px 0 0; }
#vista-equipo .eq-seccion > .eq-permiso { border-top: 1px solid var(--line); padding-top: 8px; }
#vista-equipo .eq-switch { position: relative; width: 46px; height: 26px; padding: 0; border-radius: 999px; border: 1px solid var(--line); background: var(--line); cursor: pointer; }
#vista-equipo .eq-switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #ffffff; transition: transform .15s; }
#vista-equipo .eq-switch[aria-checked="true"] { background: var(--accent); border-color: var(--accent); }
#vista-equipo .eq-switch[aria-checked="true"]::after { transform: translateX(20px); }
#vista-equipo .eq-switch:disabled { opacity: .5; cursor: default; }
#vista-equipo .eq-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#vista-equipo .eq-pill-ok { background: var(--ok-soft); color: var(--ok); }
#vista-equipo .eq-pill-info { background: var(--info-soft); color: var(--info); }
#vista-equipo #btn-persona-nueva { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 600; }

/* 🔑 Credenciales, pieza 5 («la clave dentro de la ficha»): la contraseña de registro se ve en una caja dentro de la ficha, no en un cartel.
   Todo bajo #vista-equipo: lo vigila tests/test_credenciales_clave_en_la_ficha.py. */
#vista-equipo .eq-codigo { margin-top: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg); display: flex; flex-direction: column; gap: 10px; }
#vista-equipo .eq-codigo-tit { font-weight: 600; font-size: 14.5px; }
#vista-equipo .eq-codigo-anular { display: flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 600; cursor: pointer; }
#vista-equipo .eq-codigo-anular input { width: 22px; height: 22px; flex: none; margin: 0; }
#vista-equipo .eq-codigo-botones { display: flex; flex-wrap: wrap; gap: 8px; }
#vista-equipo .eq-codigo-botones .eq-btn { min-height: 44px; }
#vista-equipo .eq-codigo-valor { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 26px; font-weight: 700; letter-spacing: .14em; text-align: center; padding: 14px 10px; border-radius: 10px; background: var(--panel); border: 1px dashed var(--accent); user-select: all; overflow-wrap: anywhere; }
#vista-equipo .eq-codigo-aviso { font-size: 13.5px; }

/* El código, que es lo único que hay que poder leer y dictar sin equivocarse. */
.cod-valor { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
             font-size: 34px; font-weight: 700; letter-spacing: .22em;
             text-align: center; margin: 18px 0 12px; padding: 14px 8px;
             background: #f6f6f8; border-radius: 12px; user-select: all;
             word-break: break-all; }
.cod-copiar { width: 100%; margin-bottom: 14px; }
.cod-aviso { font-size: 14px; line-height: 1.4; margin-bottom: 12px; color: var(--rojo); }
.cod-comollega { font-size: 13.5px; line-height: 1.45; margin-bottom: 12px; }
.cod-vence { font-size: 12.5px; color: var(--muted); margin-bottom: 16px; }

/* ---------- Ficha de cliente: editar en el sitio (6-oct-2026) ----------
   Maqueta aprobada: `disenos/registro-ficha-cliente/maqueta-v2-aprobada.html`. El aspecto de la
   ficha NO cambia: el valor editable es un `.apr-fe` dentro del mismo `.apr-campo-v`.
   🔴 EN REPOSO NO HAY NINGUNA REGLA NUEVA QUE TOQUE LA DISPOSICIÓN (columnas, filas, nombre):
   lo vigila `tests/test_ficha_editar_aspecto.py` comparando lo aplicado contra 2be4dce. La barra
   solo se ubica arriba a la derecha cuando se ve (`.apr-ed-activa`), y fuera del flujo de la
   rejilla, para que no mueva ningún grupo. */
.apr-fe-caja { display: inline-grid; vertical-align: baseline; max-width: 100%; }
.apr-fe-caja::after { content: attr(data-valor); white-space: pre-wrap; visibility: hidden; grid-area: 1 / 1;
  padding: 2px 6px; font: inherit; word-break: break-word; }
textarea.apr-fe { grid-area: 1 / 1; width: 100%; min-width: 0; resize: none; overflow: hidden; font: inherit; color: inherit;
  text-align: inherit; background: none; border: 0; border-radius: 6px; padding: 2px 6px; margin: 0; outline: none;
  white-space: pre-wrap; word-break: break-word; cursor: text; }
.apr-fe-caja { margin: -2px -6px; }
.apr-fe:hover { background: var(--fondo); }
.apr-fe:focus { background: var(--tarjeta); box-shadow: 0 0 0 2px var(--acento, #f2b441); text-align: left; }
.apr-fe::placeholder { color: var(--muted); opacity: 1; }
.apr-fe:disabled { opacity: .6; cursor: progress; }
.apr-fe-cambiado, .apr-fe-cambiado:hover { background: #fff7e3; }
select.apr-fe { font: inherit; color: inherit; background: none; border: 0; border-radius: 6px; appearance: none; -webkit-appearance: none;
  text-align: right; max-width: 100%; padding: 2px 6px; margin: -2px -6px; cursor: pointer; }
.apr-ed-barra { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; margin: 6px 0; }
.apr-ed-barra[hidden] { display: none; }
.apr-ed-barra .btn { padding: 7px 14px; font-size: .84rem; border-radius: 10px; font-weight: 700; }
.apr-ed-barra button[hidden] { display: none; }
.apr-ed-estado { font-size: .82rem; color: var(--muted); }
.apr-ed-estado.apr-ed-cambios { color: var(--marca-osc); font-weight: 600; }
.apr-ed-estado.apr-ed-guardado { color: #1e7d3c; font-weight: 600; }
.apr-ed-estado.apr-ed-error { color: #8e2018; font-weight: 600; }
/* La ficha abierta dentro de «Cambios de ficha»: la misma ficha, con borde de la marca y su barra
   (estado, Deshacer, Guardar, Cerrar) siempre a la vista arriba a la derecha. */
.apr-ficha-sitio { border-color: var(--marca); }
@media (min-width: 900px) {
  .apr-ficha-sitio { position: relative; }
  .apr-ficha-sitio .apr-ed-barra { position: absolute; top: 12px; right: 16px; margin: 0; max-width: 60%; }
  .apr-ficha-sitio .apr-ficha-nombre { padding-right: 40%; }
}
@media (min-width: 900px) {
  .apr-ficha-editable.apr-ed-activa { position: relative; }
  .apr-ficha-editable.apr-ed-activa .apr-ed-barra { position: absolute; top: 12px; right: 16px; margin: 0; max-width: 60%; }
  .apr-ficha-editable.apr-ed-activa .apr-ficha-nombre { padding-right: 40%; }
}

/* ---------- 🏠 la página de inicio (Registro / Proyectos) ----------
   🔴 QUE SE VEA IGUAL QUE LA MAQUETA que Tiziano aprobó (`maquetas/inicio-v1.html`). Lo vigila
   `tests/test_inicio_maqueta.py`: resuelve la cascada de las dos hojas y compara lo que queda
   aplicado. Las diferencias que hay están declaradas ahí, una por una, con su razón.
   Se escribió con las mismas reglas de la maqueta y nombres con prefijo `inicio-` (la App ya
   tiene `.barra`, `.error`, `h1`… y no se les cambia nada). La barra es la `.barra` de siempre.

   🔑 Tipografía: la maqueta pedía «Bricolage Grotesque» y «Figtree» a Google Fonts. Acá van las
   letras del sistema, las mismas de toda la App: la App no carga NADA de fuera (ni una fuente,
   ni un script) y esta página es lo primero que ve cada persona al entrar; pedirle una fuente
   a un tercero la haría esperar, y sin conexión caería a la del sistema igual. */
:root {
  --inicio-proyectos: #0f7c74;
  --inicio-facturas: #1f5fa8;
  --inicio-personas: #5b4bb5;
  --inicio-display: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#vista-inicio { font: 15px/1.5 var(--inicio-display); }
#vista-inicio .logo-barra { max-width: 70vw; }
.inicio-main {
  max-width: 52rem; margin: 0 auto; padding-inline: 16px; padding-block: 2.5rem 4rem;
  display: flex; flex-direction: column; gap: 1.6rem;
}
.inicio-saludo h1 { font: 700 clamp(1.6rem,4vw,2.2rem)/1.15 var(--inicio-display); margin: 0; text-wrap: balance; }
.inicio-saludo p { margin: .3rem 0 0; color: var(--muted); }
.inicio-opciones { display: grid; grid-template-columns: repeat(auto-fit,minmax(15rem,1fr)); gap: 1rem; }
a.inicio-opcion {
  display: flex; flex-direction: column; gap: .7rem; text-decoration: none; color: inherit;
  background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 16px; padding: 1.4rem;
  min-height: 12rem; transition: transform .15s,box-shadow .15s,border-color .15s;
}
a.inicio-opcion[href]:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgb(0 0 0 / .08); }
@media (prefers-reduced-motion: reduce) {
  a.inicio-opcion { transition: none; }
  a.inicio-opcion[href]:hover { transform: none; }
}
.inicio-icono { width: 3rem; height: 3rem; border-radius: 12px; display: grid; place-items: center; color: #fff; }
.inicio-icono svg { width: 1.6rem; height: 1.6rem; }
.inicio-opcion h2 { font: 700 1.4rem var(--inicio-display); margin: 0; }
.inicio-opcion p { margin: 0; color: var(--muted); }
.inicio-ir { margin-top: auto; font-weight: 600; }
/* El color de cada tarjeta (la maqueta lo pasa con `--color`; acá va escrito, para que la prueba lo mida). */
.inicio-registro .inicio-icono { background: var(--marca); }
.inicio-registro .inicio-ir { color: var(--marca); }
a.inicio-registro[href]:hover { border-color: var(--marca); }
a.inicio-registro:focus-visible { outline: 3px solid var(--marca); outline-offset: 3px; }
.inicio-proyectos .inicio-icono { background: var(--inicio-proyectos); }
.inicio-proyectos .inicio-ir { color: var(--inicio-proyectos); }
a.inicio-proyectos[href]:hover { border-color: var(--inicio-proyectos); }
a.inicio-proyectos:focus-visible { outline: 3px solid var(--inicio-proyectos); outline-offset: 3px; }
.inicio-facturas .inicio-icono { background: var(--inicio-facturas); }
.inicio-facturas .inicio-ir { color: var(--inicio-facturas); }
a.inicio-facturas[href]:hover { border-color: var(--inicio-facturas); }
a.inicio-facturas:focus-visible { outline: 3px solid var(--inicio-facturas); outline-offset: 3px; }
.inicio-personas .inicio-icono { background: var(--inicio-personas); }
.inicio-personas .inicio-ir { color: var(--inicio-personas); }
a.inicio-personas[href]:hover { border-color: var(--inicio-personas); }
a.inicio-personas:focus-visible { outline: 3px solid var(--inicio-personas); outline-offset: 3px; }
/* Lo que la maqueta no tenía: el estado de las tarjetas que dicen algo más (`pintarInicio`). */
a.inicio-opcion .inicio-nota { color: var(--muted); font-size: 14px; }
a.inicio-opcion[aria-disabled="true"] { background: var(--fondo); border-style: dashed; cursor: default; }
a.inicio-opcion[aria-disabled="true"] .inicio-icono { background: var(--muted); }
a.inicio-opcion[aria-disabled="true"] .inicio-ir { color: var(--muted); font-weight: 400; }
a.inicio-opcion[aria-busy="true"] { cursor: progress; }

/* ---------- 👥 portal «Personas» (parte 1: ver) ----------
   QUE SE VEA IGUAL QUE LA MAQUETA aprobada (`disenos/registro-portal-personas/maqueta-aprobada.html`): la fila ancha de
   ocho columnas, el encabezado con el orden, la búsqueda arriba y el pie. La ficha NO tiene reglas propias: es la de
   «Fichas» del Aprendizaje (`.apr-ficha`, `.apr-grupo`, `.apr-campo`), puesta debajo de su fila. */
.per-pagina { max-width: 1320px; margin: 0 auto; padding: 18px 20px 40px; display: flex; flex-direction: column; gap: 14px; }
.per-cab { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.per-cab h1 { font-size: 1.35rem; font-weight: 800; margin: 0; }
.per-buscar { flex: 1 1 280px; min-width: 0; font: inherit; padding: 10px 12px; border: 1.5px solid var(--borde); border-radius: 10px; background: var(--tarjeta); color: var(--texto); }
.per-buscar:focus-visible, .per-orden:focus-visible, .per-fila:focus-visible, .per-orden-btn:focus-visible { outline: 3px solid var(--acento); outline-offset: 2px; }
.per-orden-btn { font-size: .86rem; font-weight: 700; padding: 8px 14px; border-radius: 10px; white-space: nowrap; }
.per-cuenta { font-size: .86rem; color: var(--muted); }
.per-cols, .per-fila { display: grid; grid-template-columns: minmax(140px, 1.5fr) minmax(105px, 1fr) minmax(140px, 1.5fr) minmax(90px, 1fr) 100px 60px 105px 80px; gap: 14px; align-items: center; }
.per-cols { padding: 0 16px; font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.per-orden { font: inherit; font-weight: 700; letter-spacing: inherit; text-transform: inherit; color: var(--texto); background: none; border: none; padding: 0; cursor: pointer; text-align: left; }
.per-orden span { color: var(--marca); }
.per-orden[data-orden]:hover { color: var(--marca); }
.per-lista { display: flex; flex-direction: column; gap: 6px; }
.per-fila { width: 100%; text-align: left; font: inherit; color: inherit; background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 12px; padding: 11px 16px; cursor: pointer; }
.per-fila:hover { border-color: var(--muted); }
.per-fila[aria-expanded="true"] { border-color: var(--marca); }
.per-fila > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .93rem; }
.per-fila .per-nom { font-weight: 700; }
.per-fila .per-num { font-variant-numeric: tabular-nums; }
.per-vacio { color: var(--muted); font-style: italic; }
.per-etq { display: none; }
.per-pie { text-align: center; font-size: .84rem; color: var(--muted); padding: 10px 0; }
.per-pie .btn { margin-left: 8px; }
.per-ficha-cerrar { display: flex; justify-content: flex-end; margin: 6px 0; }
.per-valor-vacio { color: var(--muted); font-style: italic; }
.per-valor-largo { white-space: pre-wrap; }
@media (max-width: 900px) {
  .per-cols { display: none; }
  .per-fila { grid-template-columns: 1fr 1fr; gap: 6px 14px; }
  .per-fila > span { white-space: normal; }
  .per-etq { display: block; font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
}

/* 👥 portal «Personas», parte 2: «+ Nueva persona», el aviso de lo que pasó con la lista y las listas de opciones de la ficha. */
.per-nueva { font-size: .86rem; font-weight: 700; padding: 8px 14px; border-radius: 10px; white-space: nowrap; }
.per-aviso { background: var(--cambio, #fff7e3); border: 1.5px solid var(--acento); border-radius: 10px; padding: 10px 12px; font-size: .9rem; }
.per-multi { display: inline-flex; flex-wrap: wrap; gap: 4px 12px; justify-content: flex-end; }
.per-chk { display: inline-flex; align-items: center; gap: 4px; font-size: .88rem; white-space: nowrap; cursor: pointer; }
/* Listas de casillas de la ficha (Instrumento, Género; 19-oct-2026): el título arriba y las casillas en columnas parejas, del mismo ancho y pegadas a la izquierda
   (antes `.per-multi` era un renglón corrido pegado a la derecha y cada renglón salía de un largo). El número de columnas lo da el ancho: 2 en el celular. */
.apr-campo[data-multi] { flex-direction: column; gap: 8px; }
.apr-campo[data-multi] .apr-campo-v { text-align: left; }
.apr-campo[data-multi] .per-multi { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 6px 12px; justify-content: stretch; }
.apr-campo[data-multi] .per-chk { display: flex; align-items: flex-start; white-space: normal; overflow-wrap: anywhere; min-width: 0; }
.apr-campo[data-multi] .per-chk input { flex: none; margin: 2px 4px 0 0; }
.per-ficha > .apr-vacio-busq, .per-ficha > .apr-roto { grid-column: 1 / -1; }
/* «Por resolver» dentro de Personas: un renglón por grupo de fichas que parecen la misma persona. */
.per-cab-lista { display: contents; }
.per-pr-btn { font-size: .86rem; font-weight: 700; padding: 8px 14px; border-radius: 10px; white-space: nowrap; }
.per-pr-btn[aria-pressed="true"] { border-color: var(--marca); color: var(--marca); }
.per-pr { display: flex; flex-direction: column; gap: 12px; }
.per-pr-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.per-pr-cab h2, .per-pr-sub { font-size: 1.1rem; font-weight: 800; margin: 0; }
.per-pr-ayuda { margin: 0; font-size: .9rem; color: var(--muted); }
.per-pr-lista { display: flex; flex-direction: column; gap: 10px; }
.per-pr-reng { background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 12px; padding: 12px 16px; display: flex; flex-direction: column; gap: 10px; }
.per-pr-tit { font-size: .93rem; overflow-wrap: anywhere; }
.per-pr-fichas { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }
.per-pr-ficha { border: 1px solid var(--borde); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 3px; font-size: .9rem; min-width: 0; overflow-wrap: anywhere; }
.per-pr-nom { font-weight: 700; }
.per-pr-puerta-rojo { border-color: var(--rojo); border-left-width: 6px; }
.per-pr-puerta-amarillo { border-color: var(--acento); border-left-width: 6px; background: var(--cambio, #fff7e3); }
.per-pr-etiqueta { display: block; font-weight: 800; }
.per-pr-etq { color: var(--muted); }
.per-pr-ficha .btn { align-self: flex-start; margin-top: 6px; font-size: .84rem; padding: 6px 12px; }
.per-pr-acciones { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: .84rem; color: var(--muted); }
/* «Qué habría hecho»: una línea por renglón, con la frase a la izquierda y el número a la derecha. */
.per-qh-fila { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: .93rem; overflow-wrap: anywhere; }
.per-qh-fila b { font-size: 1.05rem; white-space: nowrap; }
.per-qh-sub { padding-left: 16px; font-size: .86rem; color: var(--muted); }
/* «Borradas»: una fila por ficha guardada aparte: nombre, cuándo, quién y «Devolver». En 375 px la fila se parte en varias líneas. */
.per-bo-fila { background: var(--tarjeta); border: 1.5px solid var(--borde); border-radius: 12px; padding: 12px 16px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; min-width: 0; }
.per-bo-nom { font-weight: 700; flex: 1 1 180px; min-width: 0; overflow-wrap: anywhere; }
.per-bo-cuando, .per-bo-quien { font-size: .86rem; color: var(--muted); overflow-wrap: anywhere; }
.per-bo-fila .btn { margin-left: auto; }


/* «Unir con otra…» dentro de la ficha del portal «Personas» (parte E5). La caja ocupa todo el ancho de la ficha (que es una rejilla). */
.per-unir { grid-column: 1 / -1; margin-top: 12px; border-radius: 10px; padding: 12px 14px; font-size: .9rem; display: flex; flex-direction: column; gap: 10px;
  background: var(--cambio, #fff7e3); border: 1.5px solid var(--acento); }
.per-unir ul { margin-left: 18px; }
.per-unir-fila { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.per-unir-buscar { flex: 1 1 220px; min-width: 0; font: inherit; padding: 8px 10px; border: 1.5px solid var(--borde); border-radius: 8px; background: var(--tarjeta); color: var(--texto); }
.per-unir-buscar:focus-visible { outline: 3px solid var(--acento); outline-offset: 2px; }
.per-unir-lista { display: flex; flex-direction: column; gap: 6px; }
.per-unir-pista { font-size: .84rem; color: var(--muted); }
.per-unir-op { font: inherit; text-align: left; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; background: var(--tarjeta); border: 1.5px solid var(--borde);
  border-radius: 8px; padding: 8px 10px; cursor: pointer; color: var(--texto); overflow-wrap: anywhere; }
.per-unir-op:hover:not([disabled]) { border-color: var(--marca); }
.per-unir-op:focus-visible { outline: 3px solid var(--acento); outline-offset: 2px; }
.per-unir-op span { font-size: .84rem; color: var(--muted); white-space: pre-wrap; }
.per-unir-op-puesta { border-color: var(--marca); box-shadow: inset 0 0 0 1px var(--marca); }
.per-unir-rango { font-style: normal; font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--marca-osc); }
.per-unir-choque { display: flex; flex-direction: column; gap: 6px; border-radius: 10px; padding: 10px 12px; background: var(--tarjeta); }
.per-unir-choque-falta { border: 1.5px solid var(--marca); }
.per-unir-choque-listo { border: 1.5px solid #9fd3ae; }
.per-unir-choque-tit { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.per-unir-estado { font-size: .78rem; font-weight: 700; }
.per-unir-choque-falta .per-unir-estado { color: var(--marca-osc); }
.per-unir-choque-listo .per-unir-estado { color: #1e7d3c; }
.per-unir-k { color: var(--muted); }
.per-unir-suma li { overflow-wrap: anywhere; white-space: pre-wrap; }
.per-unir-uniendo { font-weight: 700; color: var(--marca-osc); }
.per-unir .apr-roto { margin: 0; }

/* 🗑 BORRAR la ficha (P5 de `disenos/registro-borrar-fichas/DISENO.md`): el botón rojo «Borrar», la caja de revisión («Sí, borrar» solo sin paradas)
   y el aviso «Borrada» con «Deshacer». Prefijo `per-borr`. El rojo es el de la App para lo que no se deshace fácil; cabe en las dos temas. */
.per-borr-btn { color: var(--peligro, #9b1c1c); border: 1.5px solid var(--peligro, #9b1c1c); background: var(--tarjeta); }
.per-borr-btn:disabled { opacity: .5; cursor: default; }
.per-borr-si { background: var(--peligro, #9b1c1c); color: #fff; border-color: var(--peligro, #9b1c1c); }
.per-borr { grid-column: 1 / -1; margin-top: 12px; border-radius: 10px; padding: 12px 14px; font-size: .9rem; display: flex; flex-direction: column; gap: 10px;
  background: var(--tarjeta); border: 1.5px solid var(--peligro, #9b1c1c); }
.per-borr-fila { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.per-borr-razones { margin-left: 18px; display: flex; flex-direction: column; gap: 4px; }
.per-borr .apr-roto { margin: 0; }
.per-borr-uniendo { font-weight: 700; color: var(--marca-osc); }
.per-borr-aviso:not(.oculta) { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@media (max-width: 600px) {
  .per-borr-fila .btn { flex: 1 1 auto; }
}

/* 🎸 La tarjeta «Proveedores» del inicio: mismas reglas que las otras, con su color (el morado de la nota musical). */
:root { --inicio-proveedores: #6a3d9a; }
.inicio-proveedores .inicio-icono { background: var(--inicio-proveedores); }
.inicio-proveedores .inicio-ir { color: var(--inicio-proveedores); }
a.inicio-proveedores[href]:hover { border-color: var(--inicio-proveedores); }
a.inicio-proveedores:focus-visible { outline: 3px solid var(--inicio-proveedores); outline-offset: 3px; }
/* 🎸 PROVEEDORES (pieza 4: solo ver). La vara es la maqueta que Tiziano aprobó el 14-oct-2026 («solo el módulo, para computadora»): una barra con el buscador y el contador a la derecha, y una tabla
   de cinco columnas con una línea fina entre filas. Usa las variables de la App (`--tarjeta`, `--borde`, `--muted`, `--marca`); en el teléfono (≤ 900 px) cada fila es una tarjeta con sus etiquetas. */
.prov-vista { background: var(--fondo); }
.prov-vista .barra-titulo { flex-wrap: wrap; row-gap: 6px; min-width: 0; }   /* a 320 px la barra de la App (‹ Inicio + logo + etiqueta) mide 368 px y empujaba la página: medido el 16-oct-2026 en Chrome headless */
.prov-pagina { max-width: 1180px; margin: 0 auto; padding-inline: 16px; padding-block: 18px 48px; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.prov-pagina h1 { font-size: 1.4rem; font-weight: 700; }
.prov-sub { color: var(--muted); font-size: .9rem; margin-top: 2px; }
.prov-arriba { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.prov-pagina input.prov-buscar { flex: 1 1 16em; width: auto; max-width: 480px; min-width: 0; font: inherit; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--borde); background: var(--tarjeta); color: var(--texto); }
.prov-pagina input.prov-buscar:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }
.prov-total { margin-left: auto; color: var(--muted); font-size: .9rem; }
.prov-tabla { background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 12px; overflow-x: auto; }
.prov-tabla table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.prov-tabla th { text-align: left; font-size: .74rem; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); font-weight: 600; padding: 9px 12px; border-bottom: 2px solid var(--borde); white-space: nowrap; }
.prov-tabla td { padding: 10px 12px; border-bottom: 1px solid var(--borde); vertical-align: middle; }
.prov-tabla tbody tr:last-child td { border-bottom: 0; }
.prov-c-nombre { font-weight: 700; }
.prov-c-precio_referencia { font-variant-numeric: tabular-nums; white-space: nowrap; }
.prov-sin { color: var(--muted); }
.prov-pie { color: var(--muted); font-size: .9rem; }
.prov-pie:empty { display: none; }
.prov-pagina .apr-roto .btn-fantasma2 { margin-left: 8px; }
@media (max-width: 900px) {
  .prov-pagina input.prov-buscar { flex-basis: 100%; max-width: none; }
  .prov-total { margin-left: 0; }
  .prov-tabla { border: 0; background: none; overflow-x: visible; }
  .prov-tabla thead { display: none; }
  .prov-tabla table, .prov-tabla tbody { display: block; }
  .prov-tabla tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px 14px; background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 12px; padding: 12px; margin-bottom: 10px; }
  .prov-tabla td { display: block; padding: 0; border: 0; min-width: 0; overflow-wrap: anywhere; }
  .prov-tabla td::before { content: attr(data-label); display: block; margin-bottom: 2px; font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
  .prov-tabla td.prov-c-nombre { grid-column: 1 / -1; }
  .prov-tabla td.prov-c-nombre::before { display: none; }
}
/* ---------- 📣 Mercadeo (pieza 4: solo ver) ----------
   La tarjeta del inicio y la página de Mercadeo salen de las de siempre (`.inicio-opcion`, `.inicio-main`); la lista y el buscador reusan los de «Personas»
   (`.apr-roto`, `.btn-fantasma2`, generales) y copian la apariencia del buscador, el pie y lo vacío de «Personas» con nombres propios (`mer-`), para no depender de sus reglas. La lista de Mercadeo es de SOLO VER: sus filas
   no son botones (no hay cursor de mano ni borde que reaccione). */
:root { --inicio-mercadeo: #b4532a; }
.inicio-mercadeo .inicio-icono { background: var(--inicio-mercadeo); }
.inicio-mercadeo .inicio-ir { color: var(--inicio-mercadeo); }
a.inicio-mercadeo[href]:hover { border-color: var(--inicio-mercadeo); }
a.inicio-mercadeo:focus-visible { outline: 3px solid var(--inicio-mercadeo); outline-offset: 3px; }
/* 🪪 La tarjeta «Credenciales» del inicio: mismas reglas que las otras, con su color. */
:root { --inicio-credenciales: #8a5a00; }
.inicio-credenciales .inicio-icono { background: var(--inicio-credenciales); }
.inicio-credenciales .inicio-ir { color: var(--inicio-credenciales); }
a.inicio-credenciales[href]:hover { border-color: var(--inicio-credenciales); }
a.inicio-credenciales:focus-visible { outline: 3px solid var(--inicio-credenciales); outline-offset: 3px; }
/* 💵 La tarjeta «Finanzas y administración» del inicio: mismas reglas que las otras, con el verde de la maqueta de Finanzas (`--fin-accent`, #0d6b5b). Hasta el 16-oct-2026 no tenía ninguna: su ícono salía blanco sobre blanco y su «Entrar a finanzas →» sin color. */
:root { --inicio-finanzas: #0d6b5b; }
.inicio-finanzas .inicio-icono { background: var(--inicio-finanzas); }
.inicio-finanzas .inicio-ir { color: var(--inicio-finanzas); }
a.inicio-finanzas[href]:hover { border-color: var(--inicio-finanzas); }
a.inicio-finanzas:focus-visible { outline: 3px solid var(--inicio-finanzas); outline-offset: 3px; }
/* 📣 MERCADEO SE VE COMO LA MAQUETA APROBADA (14-oct-2026; Tiziano: «Dale, y lo mismo esta pasando con Mercadeo», colores «como la maqueta»).
   La vara es `maquetas/mercadeo-v1.html` y la vigila `tests/test_mercadeo_maqueta.py`: compara, propiedad por propiedad, lo que queda aplicado a cada pieza de la maqueta con lo que queda aplicado a la
   pieza equivalente de la App; lo que difiere está declarado allí con su razón. Los colores y las letras son de la maqueta (verde, Archivo + IBM Plex Sans) y viven SOLO en las vistas de Mercadeo:
   las letras se piden desde `.mer-pagina` y la portada, nunca desde `body`, así el resto de la App sigue con la letra del sistema (la prueba lo exige). */
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 500 700; font-display: swap;
  src: url(/fuentes/Archivo-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans"; font-style: normal; font-weight: 400 600; font-display: swap;
  src: url(/fuentes/IBMPlexSans-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
:root {
  --mer-bg: #f2f4f3; --mer-panel: #ffffff; --mer-ink: #15211e; --mer-soft: #5b6a66; --mer-line: #d6ddda;
  --mer-accent: #0d6b5b; --mer-accent-ink: #ffffff; --mer-accent-soft: #dcefea;
  --mer-ok: #1f7a45; --mer-ok-soft: #dff2e6; --mer-warn: #9a6200; --mer-warn-soft: #fbeed2; --mer-bad: #b3372b; --mer-bad-soft: #f9e0dc;
  --mer-info: #2c5aa0; --mer-info-soft: #e0e9f7;
  --mer-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --mer-body: "IBM Plex Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
}
.mer-vista { background: var(--mer-bg); min-height: 100dvh; } /* `dvh`, no `vh`: igual que `.vista` y `.fin-vista` (en el iPhone `vh` mide más que la pantalla visible) */
.mer-pagina {
  max-width: 1120px; margin: 0 auto; padding-inline: 16px; padding-block: 18px 48px; display: flex; flex-direction: column; gap: 16px; min-width: 0;
  font-family: var(--mer-body); font-size: 15px; line-height: 1.45; color: var(--mer-ink);
}
.mer-pagina h1, .mer-pagina h2, .mer-pagina h3 { font-family: var(--mer-display); margin: 0; text-wrap: balance; }
.mer-pagina h1 { font-size: 1.5rem; font-weight: 700; }
.mer-pagina h2 { font-size: 1.15rem; font-weight: 600; }
.mer-pagina h3 { font-size: 1rem; font-weight: 600; }
.mer-pagina p { margin: 0; }
.mer-pagina button:focus-visible, .mer-pagina input:focus-visible { outline: 2px solid var(--mer-accent); outline-offset: 2px; }
.mer-top { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; }
.mer-sub { color: var(--mer-soft); font-size: .9rem; }
.mer-aviso { background: var(--mer-warn-soft); color: var(--mer-warn); border-radius: 8px; padding: 8px 12px; font-size: .87rem; }
/* «Pausar todo el mercadeo» se VE pero está apagado: hoy no hay nada que pausar, y el interruptor no promete lo que no hace. */
.mer-pausa-caja { display: flex; flex-direction: column; gap: 2px; }
.mer-pausa { display: flex; align-items: center; gap: 8px; font-size: .9rem; }
.mer-pausa-caja .mer-sub { font-size: .8rem; }
.mer-nav { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px; }
.mer-sec { font: inherit; font-weight: 500; white-space: nowrap; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); padding: 8px 12px; border-radius: 999px; cursor: pointer; }
.mer-sec[aria-selected="true"] { background: var(--mer-accent); color: var(--mer-accent-ink); border-color: var(--mer-accent); }
/* Las secciones que todavía no existen: apagadas (no se pueden tocar) y con «Próximamente». */
.mer-sec-apagada { background: var(--mer-bg); color: var(--mer-soft); cursor: default; }
.mer-pronto { font-size: .72rem; font-weight: 600; margin-left: 4px; }
.mer-cuerpo { display: flex; flex-direction: column; gap: 30px; }
.mer-seccion { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.mer-btn { font: inherit; font-weight: 600; border-radius: 8px; padding: 8px 14px; cursor: pointer; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); }
.mer-btn-si, .mer-pastilla[aria-pressed="true"] { background: var(--mer-accent); color: var(--mer-accent-ink); border-color: var(--mer-accent); }
.mer-btn:disabled { cursor: default; opacity: .6; }
.mer-pie-caja .mer-btn, .apr-roto .mer-btn, .mer-grupos-nota .mer-btn { margin-left: 8px; }
.mer-pagina .apr-roto { background: var(--mer-bad-soft); color: var(--mer-bad); border-radius: 10px; }
.mer-busca { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
/* `input.` delante: las reglas de campo de la App (`input[type=…]`) son más específicas que una clase sola y le ponían su borde, su relleno y su ancho. */
.mer-pagina input.mer-buscar-caja { flex: 1; width: auto; min-width: 12em; font: inherit; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); transition: none; }
.mer-pagina input.mer-buscar-caja#mer-grupo-nombre { min-width: 10em; }
.mer-vacio { color: var(--mer-soft); font-style: italic; }
.mer-pie-caja { font-size: .9rem; color: var(--mer-soft); }
.mer-pastillas { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.mer-pastillas:empty { display: none; }
.mer-totales { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.mer-totales:empty { display: none; }
.mer-kpi { background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 12px; }
.mer-kpi b { display: block; font-family: var(--mer-display); font-size: 1.5rem; font-variant-numeric: tabular-nums; }
.mer-kpi span { color: var(--mer-soft); font-size: .82rem; overflow-wrap: anywhere; }
.mer-nota { grid-column: 1 / -1; font-size: .86rem; color: var(--mer-soft); }
/* La lista es UNA tabla con borde redondeado y una línea fina entre filas (la maqueta). Cada fila sigue siendo de SOLO VER: no es un botón. */
.mer-tabla { overflow-x: auto; background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; font-size: .9rem; font-variant-numeric: tabular-nums; }   /* el tamaño y los números alineados los pone la <table> de la maqueta a sus celdas: aquí los hereda cada celda */
.mer-cols, .mer-fila { display: grid; grid-template-columns: minmax(140px, 1.5fr) minmax(105px, 1fr) minmax(140px, 1.5fr) minmax(90px, 1fr) 70px 110px; column-gap: 24px; align-items: center; padding: 9px 12px; border-bottom: 1px solid var(--mer-line); }
.mer-cols { font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mer-soft); font-weight: 600; }
.mer-cols > span, .mer-fila > span { min-width: 0; white-space: nowrap; text-align: left; }
.mer-lista > .mer-fila:last-child, .led-lista > .led-fila:last-child { border-bottom: 0; }
.mer-fila > span { overflow: hidden; text-overflow: ellipsis; }
.mer-fila .mer-nom { font-weight: 700; }
.mer-cols > span.mer-der, .mer-fila > span.mer-der, .led-cols > span.mer-der, .led-fila > span.mer-der { text-align: right; }
.mer-etq { display: none; }
/* Teléfono: una fila ancha de seis columnas no cabe; cada persona pasa a ser una tarjeta de dos columnas con sus etiquetas, y nada se sale de la pantalla. */
@media (max-width: 900px) {
  .mer-cols { display: none; }
  .mer-fila { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 14px; }
  .mer-fila > span { white-space: normal; overflow-wrap: anywhere; }
  .mer-fila .mer-nom { grid-column: 1 / -1; }
  .mer-fila > span.mer-der { text-align: left; }
  .mer-etq { display: block; margin-bottom: 3px; font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--mer-soft); }
}
/* Grupos guardados (pieza 6), con la forma de la maqueta: una tarjeta con el nombre y «Guardar» arriba y, debajo, un renglón por grupo con dos botones (abrir y «Borrar»); «Borrar» pregunta dentro del mismo renglón. */
.mer-grupos { display: flex; flex-direction: column; gap: 10px; background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 14px; min-width: 0; }
.mer-grupos-ayuda { color: var(--mer-soft); font-size: .9rem; }
.mer-grupos-lista:empty { display: none; }
.mer-grupos-lista { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.mer-grupos-nota { font-size: .9rem; color: var(--mer-soft); overflow-wrap: anywhere; }
.mer-grupos-error { color: var(--mer-bad); }
.mer-grupo { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; justify-content: space-between; min-width: 0; border: 1px solid var(--mer-line); border-radius: 8px; padding: 8px 10px; }
.mer-grupo-abrir { text-align: left; min-width: 0; }
.mer-grupo-abrir:disabled { cursor: default; opacity: .7; }
.mer-grupo-nom { font-weight: 700; overflow-wrap: anywhere; }
.mer-grupo-cuenta::before { content: " · "; }
.mer-grupo-filtro { display: block; color: var(--mer-soft); font-size: .9rem; overflow-wrap: anywhere; }
.mer-grupo-quiere { min-width: 0; overflow-wrap: anywhere; }
.mer-grupo-botones { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.mer-grupo-nuevo { display: flex; flex-direction: column; gap: 6px; }
.mer-grupo-resumen { font-size: .8rem; color: var(--mer-soft); overflow-wrap: anywhere; }
.mer-grupo-nuevo-fila { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.mer-grupo-aviso { font-size: .9rem; font-weight: 700; color: var(--mer-soft); overflow-wrap: anywhere; }
.mer-grupo-aviso.mer-aviso-error { color: var(--mer-bad); }
/* En un teléfono la barra no cabe con el botón «‹ Mercadeo», el logo y la etiqueta: se quita la etiqueta (el título de la página ya dice dónde estás) y el logo puede encogerse. */
@media (max-width: 430px) {
  .mer-barra .barra-tag { display: none; }
  .mer-barra .barra-titulo { min-width: 0; }
  .mer-barra .logo-barra { max-width: 50vw; height: auto; max-height: 17px; }
}

/* Los grupos van en una columna al LADO de la lista en pantalla ancha (Tiziano, 16-oct-2026: «Los grupos de Mercadeo/Persona tienes que ponerlo en un lateral de esa pagina»). Desde 1120 px: más angosto, la tabla (que a 900 px se vuelve tarjetas) quedaría
   a medias y con barra de lado. En el marcado los grupos siguen DESPUÉS de la lista; en el celular (≤ 600 px) pasan ARRIBA con `order` y en compacto (menos relleno, ayuda más chica). */
.mer-con-lateral { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.mer-con-lateral > #mer-principal { min-width: 0; }
@media (min-width: 1120px) {
  .mer-con-lateral { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 14px; align-items: start; }
}
@media (max-width: 600px) {
  .mer-con-lateral > .mer-grupos { order: -1; padding: 10px; gap: 8px; }
  .mer-con-lateral .mer-grupos-ayuda { font-size: .8rem; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }   /* la frase de ayuda se corta a dos renglones en el celular: es lo que hace compacto el cuadro */
}

/* ---------- 📣 Leads (pieza 2: solo ver) ----------
   La vista «Leads» reusa la página, la barra de secciones, la tabla, el pie y lo vacío de Mercadeo (`mer-`); lo propio lleva `led-`. Sus filas son de SOLO VER (no son botones). Nada fija un ancho en píxeles: en un teléfono la fila pasa a tarjeta. */
.led-calculando:empty { display: none; }
.led-calculando { display: flex; flex-direction: column; gap: 8px; background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 14px; font-size: .9rem; color: var(--mer-soft); }
.led-calculando b { color: var(--mer-ink); }
.led-calculando::after { content: ""; display: block; height: 4px; border-radius: 2px; background: linear-gradient(90deg, var(--mer-line) 0 35%, var(--mer-accent) 35% 65%, var(--mer-line) 65% 100%); background-size: 300% 100%; animation: led-pasa 1.6s linear infinite; }
@keyframes led-pasa { from { background-position: 100% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .led-calculando::after { animation: none; } }
.led-etapas:empty { display: none; }
.led-etapas { background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 14px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.led-nota { color: var(--mer-soft); font-size: .9rem; }
.led-barras { display: flex; flex-direction: column; gap: 10px; }
.led-barra { display: flex; flex-wrap: nowrap; gap: 8px 14px; align-items: center; }
.led-barra-nom { flex: 0 0 13.5em; min-width: 0; overflow-wrap: anywhere; }
.led-barra-pista { flex: 1; min-width: 0; }
.led-barra-relleno { display: block; height: 14px; border-radius: 4px; background: var(--mer-accent); }
.led-barra-n { flex: 0 0 2.5em; text-align: right; font-variant-numeric: tabular-nums; }
.led-total { font-size: .9rem; color: var(--mer-soft); margin: 0 0 6px; }
.led-total:empty { display: none; }
.led-cols, .led-fila { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, .9fr) minmax(0, .7fr); column-gap: 24px; align-items: center; padding: 9px 12px; border-bottom: 1px solid var(--mer-line); }
.led-cols { font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mer-soft); font-weight: 600; }
.led-cols > span { white-space: nowrap; text-align: left; }
.led-fila > span { min-width: 0; overflow-wrap: anywhere; text-align: left; }
.led-quien { display: flex; flex-direction: column; gap: 3px; }
.led-nombre { font-weight: 700; }
.led-tel { font-variant-numeric: tabular-nums; color: var(--mer-soft); font-size: .86rem; }
.led-marcas { display: flex; flex-wrap: wrap; gap: 6px; }
.led-marca { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: .78rem; font-weight: 600; white-space: nowrap; background: var(--mer-bg); color: var(--mer-soft); border: 1px solid var(--mer-line); }
.led-marca-baja { background: var(--mer-bad-soft); color: var(--mer-bad); border: 0; }
.led-etapa { font-weight: 700; }
#led-pie > div + div { margin-top: 4px; }
@media (max-width: 900px) {
  .led-cols { display: none; }
  .led-fila { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 14px; }
  .led-fila .led-quien { grid-column: 1 / -1; }
  .led-fila > span.mer-der { text-align: left; }
}
/* 📣 MERCADEO · EMBUDO (pieza P-EMB; 22-oct-2026): la tabla de la lista ordenada por el servidor. Las barras de las cuentas, el «Calculando…» y el total
   reutilizan las reglas de Leads (`.led-barras`, `.led-calculando`, `.led-total`); aquí solo va la rejilla de la lista, de cinco columnas. */
.emb-lista > .emb-fila:last-child { border-bottom: 0; }
.emb-cols, .emb-fila { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 2fr); column-gap: 24px; align-items: center; padding: 9px 12px; border-bottom: 1px solid var(--mer-line); }
.emb-cols { font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mer-soft); font-weight: 600; }
.emb-cols > span { white-space: nowrap; text-align: left; }
.emb-fila > span { min-width: 0; overflow-wrap: anywhere; text-align: left; }
.emb-fila .led-quien { display: flex; flex-direction: column; gap: 3px; }
.emb-sin-dato { color: var(--mer-soft); font-style: italic; }
/* La línea del seguimiento (P-SEG, 23-oct-2026): una sola línea por fila, debajo de las columnas. El texto lo arma el servidor; aquí solo se pinta. */
.emb-fila > .emb-seguimiento { grid-column: 1 / -1; color: var(--mer-soft); font-size: .84rem; padding-top: 2px; }
@media (max-width: 900px) {
  .emb-cols { display: none; }
  .emb-fila { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 14px; }
  .emb-fila .led-quien { grid-column: 1 / -1; }
  .emb-fila > .emb-motivo, .emb-fila > .emb-seguimiento { grid-column: 1 / -1; }
}


/* ⚙️ MERCADEO · CONFIGURACIÓN Y PAUSA (Campañas, pieza A1; 15-oct-2026). La vara es la maqueta del diseño (`maquetas/mercadeo-campanas-v1.html`, copia de `disenos/mercadeo-campanas/maqueta.html`) y la vigila
   `tests/test_mercadeo_ajustes_maqueta.py`: la tarjeta, la rejilla, los campos, el cartel rojo de la pausa y el historial se comparan, propiedad por propiedad, con la maqueta. */
.mer-aviso-pausa { background: var(--mer-bad-soft); color: var(--mer-bad); border-radius: 8px; padding: 8px 12px; font-size: .87rem; }
.mer-card { background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 14px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.mer-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.mer-pagina input.mer-campo { font: inherit; padding: 6px 8px; border-radius: 6px; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); width: auto; transition: none; }
.mer-pagina input.mer-campo-n { width: 4em; }
.mer-pagina input.mer-campo-nn { width: 5em; }
.mer-dias { display: flex; flex-wrap: wrap; gap: 6px 12px; }
.mer-dias label { display: inline-flex; align-items: center; gap: 4px; }
.mer-botonera { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
#aju-resultado.mer-aviso-error { color: var(--mer-bad); font-weight: 700; }
.mer-hist { border-collapse: collapse; width: 100%; }
.mer-hist td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--mer-line); white-space: nowrap; }
.mer-hist tr:last-child td { border-bottom: 0; }

/* 📣 MERCADEO · CAMPAÑAS (Campañas, pieza A2; 16-oct-2026). La vara es la misma maqueta (`maquetas/mercadeo-campanas-v1.html`, sección «Campañas») y la vigila `tests/test_mercadeo_campanas_maqueta.py`:
   la tabla de campañas, las pastillas de estado, la tarjeta «Nueva campaña», la lista congelada y el globo con el texto del mensaje se comparan, propiedad por propiedad, con la maqueta. */
.mer-fila-sep { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; justify-content: space-between; }
.camp-t { border-collapse: collapse; width: 100%; }
.camp-t th, .camp-t td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--mer-line); white-space: nowrap; }
.camp-t th { font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; color: var(--mer-soft); font-weight: 600; }
.camp-t tr:last-child td { border-bottom: 0; }
.camp-t td.num, .camp-t th.num { text-align: right; }
.camp-acciones .mer-btn { padding: 4px 10px; }
.camp-pill { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: .78rem; font-weight: 600; white-space: nowrap; }
.camp-ok { background: var(--mer-ok-soft); color: var(--mer-ok); }
.camp-warn { background: var(--mer-warn-soft); color: var(--mer-warn); }
.camp-bad { background: var(--mer-bad-soft); color: var(--mer-bad); }
.camp-gris { background: var(--mer-bg); color: var(--mer-soft); border: 1px solid var(--mer-line); }
.camp-roto { color: var(--mer-bad); font-size: .86rem; }
.mer-variables { display: contents; }
.mer-msg { background: var(--mer-accent-soft); border-radius: 10px 10px 10px 2px; padding: 10px 12px; max-width: 46ch; font-size: .93rem; overflow-wrap: anywhere; }
.mer-pagina select.mer-campo { font: inherit; padding: 6px 8px; border-radius: 6px; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); max-width: 100%; }
.mer-pagina input.mer-campo[type=text], .mer-pagina input.mer-campo[type=date] { width: auto; max-width: 100%; }
#camp-resultado.mer-aviso-error { color: var(--mer-bad); font-weight: 700; }

/* El cuadro «Mercadeo» de la ficha de Personas (pieza 3 de las anotaciones): ocupa todo el ancho de la ficha (que es una rejilla). */
.per-mer { grid-column: 1 / -1; margin-top: 14px; }
.per-mer-titulo { font-size: .78rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.per-mer-fila { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; border-top: 1px solid #f0eeee; font-size: .9rem; }
.per-mer-titulo + .per-mer-fila { border-top: 0; }
.per-mer-k { color: var(--muted); }
.per-mer-v { text-align: right; word-break: break-word; }
.per-mer-vacio { color: var(--muted); font-style: italic; }
.per-mer-p-baja { color: #8e2018; }
.per-mer-p-si { color: #1e7d3c; }
.per-mer-dudoso { color: #8e2018; font-weight: 700; }
.per-mer-botones { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.per-mer .btn { padding: 7px 14px; font-size: .84rem; border-radius: 10px; font-weight: 700; }
.per-mer-baja { border-color: #8e2018; color: #8e2018; }
.per-mer-msg { margin-top: 8px; font-size: .88rem; font-weight: 600; }
.per-mer-ok { color: #1e7d3c; }
.per-mer-error { color: #8e2018; }
.per-mer-form { margin-top: 8px; display: flex; flex-direction: column; gap: 8px; font-size: .9rem; }
.per-mer-lbl { display: flex; flex-direction: column; gap: 3px; color: var(--muted); font-size: .82rem; }
.per-mer-campo { font: inherit; color: var(--texto); padding: 8px 10px; border: 1.5px solid var(--borde); border-radius: 8px; background: var(--tarjeta); max-width: 420px; }
.per-mer-campo:focus-visible { outline: 3px solid var(--acento); outline-offset: 2px; }

/* 📐 FINANZAS Y ADMINISTRACIÓN SE VE COMO LA MAQUETA APROBADA (14-oct-2026; Tiziano: «en credenciales lo que veo no se ve igual que en el mockup», colores y letras «como la maqueta»: opción A).
   La vara es `maquetas/finanzas-v1.html` y la vigila `tests/test_finanzas_maqueta.py`: compara, propiedad por propiedad, lo que queda aplicado a cada pieza de la maqueta con lo que queda aplicado a la pieza
   equivalente de la App; lo que difiere está declarado allí con su razón. Este bloque trae SOLO las piezas que ya usa una pantalla (hoy «Cuentas abiertas», «Transferencias sin verificar» y «Reporte mensual»); las demás piezas de la maqueta (la entrada de la portada)
   llegan con la pantalla que las use. Los colores y las letras son los de la maqueta y viven SOLO bajo `.fin-vista`: las letras se piden desde `.fin-pagina`, nunca desde `body`
   (la prueba lo exige), y los archivos de letra son los mismos que ya declara el bloque de Mercadeo (más arriba: no se declaran dos veces). Ninguna clase `rep-*`, `cta-*` ni `pv-*` se toca aquí. */
:root {
  --fin-bg: #f2f4f3; --fin-panel: #ffffff; --fin-ink: #15211e; --fin-soft: #5b6a66; --fin-line: #d6ddda;
  --fin-accent: #0d6b5b; --fin-accent-ink: #ffffff; --fin-accent-soft: #dcefea;
  --fin-ok: #1f7a45; --fin-ok-soft: #dff2e6; --fin-warn: #9a6200; --fin-warn-soft: #fbeed2; --fin-bad: #b3372b; --fin-bad-soft: #f9e0dc;
  --fin-info: #2c5aa0; --fin-info-soft: #e0e9f7;
  --fin-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --fin-body: "IBM Plex Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
}
/* `100dvh`, no `100vh`: es la unidad de `.vista` (más arriba). Con `vh` la vista le ganaba a `.vista` por venir después y en el iPhone, con la barra del navegador a la vista, medía más que la pantalla. */
.fin-vista { background: var(--fin-bg); min-height: 100dvh; }
.fin-pagina {
  max-width: 1080px; margin: 0 auto; padding-inline: 16px; padding-block: 18px 48px; display: flex; flex-direction: column; gap: 16px; min-width: 0;
  font-family: var(--fin-body); font-size: 15px; line-height: 1.45; color: var(--fin-ink);
}
.fin-pagina h1, .fin-pagina h2, .fin-pagina h3 { font-family: var(--fin-display); margin: 0; text-wrap: balance; }
.fin-pagina h2 { font-size: 1.1rem; font-weight: 600; }
.fin-pagina p { margin: 0; }
.fin-pagina button:focus-visible { outline: 2px solid var(--fin-accent); outline-offset: 2px; }
.fin-sub { color: var(--fin-soft); font-size: .9rem; max-width: 72ch; }
.fin-sec { display: flex; flex-direction: column; gap: 14px; }
.fin-fila { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.fin-sep { justify-content: space-between; }
.fin-volver { font: inherit; align-self: flex-start; border: 0; background: none; color: var(--fin-accent); font-weight: 600; cursor: pointer; padding: 4px 0; }
.fin-btn { font: inherit; font-weight: 600; border-radius: 8px; padding: 6px 12px; cursor: pointer; border: 1px solid var(--fin-line); background: var(--fin-panel); color: var(--fin-ink); white-space: nowrap; }
.fin-btn-si { background: var(--fin-accent); color: var(--fin-accent-ink); border-color: var(--fin-accent); }
.fin-pill { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: .78rem; font-weight: 600; white-space: nowrap; }
.fin-ok { background: var(--fin-ok-soft); color: var(--fin-ok); } .fin-warn { background: var(--fin-warn-soft); color: var(--fin-warn); }
.fin-bad { background: var(--fin-bad-soft); color: var(--fin-bad); } .fin-info { background: var(--fin-info-soft); color: var(--fin-info); }
.fin-gris { background: var(--fin-bg); color: var(--fin-soft); border: 1px solid var(--fin-line); }
.fin-lista { list-style: none; margin: 0; padding: 0; background: var(--fin-panel); border: 1px solid var(--fin-line); border-radius: 10px; }
.fin-lista li { display: flex; gap: 12px; justify-content: space-between; align-items: flex-start; padding: 10px 12px; border-bottom: 1px solid var(--fin-line); min-width: 0; }
.fin-lista li:last-child { border-bottom: 0; }
.fin-lista .fin-datos { min-width: 0; display: flex; flex-direction: column; gap: 2px; overflow-wrap: anywhere; }
.fin-lista .fin-datos small { color: var(--fin-soft); font-size: .82rem; }
.fin-cod { font-family: ui-monospace, Menlo, monospace; font-size: .8rem; color: var(--fin-soft); }
.fin-lista b.fin-m { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Lo que la App tiene y la maqueta no dibuja: la fila que se puede tocar (abre la sesión) y los avisos de «cargando», «vacío» y «error». */
.fin-lista li.fin-toca { cursor: pointer; }
.fin-lista li.fin-vacio { color: var(--fin-soft); justify-content: center; }
/* Reporte mensual (pieza 4): título de bloque, nota, aviso, selector de mes, héroe, tarjetas y cajitas de la maqueta. */
.fin-pagina h3 { font-size: 1rem; font-weight: 600; }
/* 🔽 Secciones plegables del Reporte (16-oct-2026): `armarPliegues` (13-reportes.js) pone `fin-pleg` a cada título, `fin-plegada` al que está cerrado y `fin-pleg-oculto` a lo que esconde. Flechita que gira; nacen abiertas. */
.fin-pleg { cursor: pointer; display: flex; align-items: center; gap: 8px; border-radius: 6px; user-select: none; }
.fin-pleg::before { content: ""; flex: 0 0 auto; width: 7px; height: 7px; border-right: 2px solid var(--fin-soft); border-bottom: 2px solid var(--fin-soft); transform: rotate(45deg); margin: 0 3px 0 2px; }
.fin-pleg.fin-plegada::before { transform: rotate(-45deg); }
.fin-pleg:hover::before { border-color: var(--fin-accent); }
.fin-pleg:focus-visible { outline: 2px solid var(--fin-accent); outline-offset: 2px; }
.fin-pleg-oculto { display: none !important; }
.fin-hoy { font-size: .82rem; color: var(--fin-soft); }
.fin-aviso { background: var(--fin-warn-soft); color: var(--fin-warn); border-radius: 8px; padding: 8px 12px; font-size: .87rem; }
/* A1 (22-oct-2026): las acciones de una transferencia sin verificar (buscar la reserva, ligar,
   verificar, rechazar). Van en su propia línea, así que la lista envuelve — es la única
   diferencia de FORMA con la maqueta, y está declarada en `tests/test_finanzas_maqueta.py`. */
.fin-lista li.fin-con-acciones { flex-wrap: wrap; }
.fin-acciones { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.fin-acciones .fin-buscar { font: inherit; min-width: 0; flex: 1 1 14ch; border: 1px solid var(--fin-line); background: var(--fin-panel); color: var(--fin-ink); border-radius: 8px; padding: 6px 10px; }
.fin-acciones .fin-btn-buscar { flex: 0 0 auto; }
.fin-acciones .fin-resultados { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 6px; }
.fin-acciones .fin-resultado { font: inherit; text-align: left; flex: 1 1 100%; border: 1px solid var(--fin-line); background: var(--fin-panel); color: var(--fin-ink); border-radius: 8px; padding: 6px 10px; cursor: pointer; }
.fin-acciones .fin-monto-pedido { font: inherit; min-width: 0; flex: 1 1 14ch; border: 1px solid var(--fin-line); background: var(--fin-panel); color: var(--fin-ink); border-radius: 8px; padding: 6px 10px; }
.fin-acciones .fin-monto-dicho { flex: 1 1 100%; font-size: .85rem; color: var(--fin-soft); }
.fin-acciones .fin-btn-si:disabled { opacity: .5; cursor: not-allowed; }
.fin-acciones .fin-acciones-aviso { flex: 1 1 100%; margin: 0; font-size: .82rem; color: var(--fin-soft); overflow-wrap: anywhere; }
/* El pago que trajo el aviso de Telegram (`#conv=<tel>&pago=<id>`): se marca para encontrarlo. */
.fin-lista li.fin-destacada { outline: 2px solid var(--fin-warn); outline-offset: -2px; }
.fin-mes { display: flex; gap: 10px; align-items: center; }
.fin-mes .fin-mes-btn { font: inherit; border: 1px solid var(--fin-line); background: var(--fin-panel); color: var(--fin-ink); border-radius: 8px; padding: 4px 10px; cursor: pointer; }
.fin-mes b { font-family: var(--fin-display); min-width: 9ch; text-align: center; }
.fin-heroe { background: var(--fin-panel); border: 1px solid var(--fin-line); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 6px; }
.fin-heroe .fin-monto { font-family: var(--fin-display); font-size: 2.1rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.fin-tarjetas { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.fin-tj { background: var(--fin-panel); border: 1px solid var(--fin-line); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fin-tj span { font-size: .82rem; color: var(--fin-soft); } .fin-tj b { font-family: var(--fin-display); font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.fin-mini { background: var(--fin-panel); border: 1px solid var(--fin-line); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fin-mini .fin-t { font-size: .74rem; letter-spacing: .05em; text-transform: uppercase; color: var(--fin-soft); font-weight: 600; }
.fin-mini div { display: flex; justify-content: space-between; gap: 10px; font-size: .9rem; overflow-wrap: anywhere; }
.fin-mini b { font-variant-numeric: tabular-nums; }
/* La portada del módulo (pieza 5): título y frase de arriba, y las tres entradas con su cifra (`#v-inicio` de la maqueta). */
.fin-pagina h1 { font-size: 1.5rem; font-weight: 700; }
.fin-top { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; }
.fin-entradas { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.fin-entrada { font: inherit; text-align: left; background: var(--fin-panel); border: 1px solid var(--fin-line); border-radius: 12px; padding: 16px; cursor: pointer; color: var(--fin-ink); display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.fin-entrada:hover { border-color: var(--fin-accent); }
.fin-entrada .fin-cifra { font-family: var(--fin-display); font-size: 1.7rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.fin-entrada .fin-ir { color: var(--fin-accent); font-weight: 600; font-size: .9rem; }

/* 📣 MERCADEO · REDES SOCIALES · CALENDARIO (Redes, pieza C1; 16-oct-2026). La vara es la misma maqueta (`maquetas/mercadeo-redes-v1.html`, pestaña «Calendario»): la semana de siete días, las piezas con su pastilla
   de estado, la leyenda, y las tarjetas «Nueva pieza» y «Marcar publicada». Las pastillas de estado se pintan según el id de estado que manda el servidor (`redes-est-<id>`); un id que esta hoja no conozca sale gris. */
.redes-fila { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.redes-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.redes-tab { font: inherit; font-weight: 600; border: 0; border-bottom: 3px solid transparent; background: none; color: var(--mer-soft); padding: 6px 4px; cursor: pointer; }
.redes-tab[aria-selected="true"] { color: var(--mer-ink); border-bottom-color: var(--mer-accent); }
.redes-tab:disabled { cursor: default; opacity: .7; }
.redes-semana { display: grid; gap: 8px; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.redes-dia { background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 8px; display: flex; flex-direction: column; gap: 6px; min-width: 0; min-height: 120px; }
.mer-pagina .redes-dia > b { font-family: var(--mer-display); font-size: .85rem; }
.redes-hoy { border-color: var(--mer-accent); }
.redes-pieza { border-radius: 6px; padding: 6px; font-size: .8rem; background: var(--mer-bg); display: flex; flex-direction: column; gap: 3px; overflow-wrap: anywhere; }
.redes-wa { border-left: 3px solid var(--mer-ok); }
.redes-botones { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-top: 3px; }
.redes-botones .mer-btn { padding: 3px 8px; font-size: .78rem; }
.redes-propuestas { display: flex; flex-direction: column; gap: 6px; margin: 6px 0; min-width: 0; }
.redes-propuestas.oculta { display: none; }
#redes-prop-lista { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
#redes-prop-lista .redes-prop { border: 1px dashed var(--mer-line); }
.redes-pill { display: inline-block; align-self: flex-start; max-width: 100%; border-radius: 999px; padding: 2px 9px; font-size: .78rem; font-weight: 600; background: var(--mer-bg); color: var(--mer-soft); border: 1px solid var(--mer-line); }
.redes-est-produccion { background: var(--mer-info-soft); color: var(--mer-info); border-color: transparent; }
.redes-est-pendiente { background: var(--mer-warn-soft); color: var(--mer-warn); border-color: transparent; }
.redes-est-aprobada { background: var(--mer-ok-soft); color: var(--mer-ok); border-color: transparent; }
.redes-texto { min-height: 64px; width: 100%; }
.redes-enlace { flex: 1 1 14rem; min-width: 0; max-width: 100%; }
#redes-resultado.mer-aviso-error { color: var(--mer-bad); font-weight: 700; }
@media (max-width: 760px) { .redes-semana { grid-template-columns: 1fr; } .redes-dia { min-height: 0; } }
.mer-pagina textarea.mer-campo { font: inherit; padding: 8px; border-radius: 6px; border: 1px solid var(--mer-line); background: var(--mer-panel); color: var(--mer-ink); width: 100%; box-sizing: border-box; }

/* 📣 MERCADEO · REDES SOCIALES · COMENTARIOS Y RESEÑAS (Redes, pieza R1-M; 17-oct-2026). La bandeja de SOLO VER: una tarjeta por comentario, con quién, de qué red, en qué estado, el texto y la publicación donde se
   dejó. Las pastillas de red y de estado reutilizan `.redes-pill`; un id de estado o de red que esta hoja no conozca sale gris. */
.coment-lista { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.coment-item { background: var(--mer-panel); border: 1px solid var(--mer-line); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 5px; min-width: 0; overflow-wrap: anywhere; }
.coment-cabeza { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; }
.coment-texto { white-space: pre-wrap; }
.coment-est-sin_responder { background: var(--mer-warn-soft); color: var(--mer-warn); border-color: transparent; }
.coment-est-respondido_fuera { background: var(--mer-ok-soft); color: var(--mer-ok); border-color: transparent; }
.coment-roto { margin: 0 0 6px; color: var(--mer-bad); font-weight: 700; }
#coment-avisos { margin-top: 8px; }

/* 📣 MERCADEO · APROBACIONES (Campañas, pieza A3; 16-oct-2026). La vara es la misma maqueta (`maquetas/mercadeo-campanas-v1.html`, pestaña «Aprobaciones»): una tarjeta por campaña con su pastilla de modo, el resumen,
   el ejemplo del mensaje y los botones; la de «mensaje por mensaje» lleva la tabla con «Aprobar» y «Quitar» en cada fila. Las pastillas ya existen (`.camp-pill`); aquí solo se suma la azul de «Completa». */
.aprob-lista { display: flex; flex-direction: column; gap: 16px; }
.camp-info { background: var(--mer-info-soft); color: var(--mer-info); }
.aprob-t td.aprob-texto { white-space: normal; min-width: 14rem; }
.aprob-t td.aprob-texto .mer-msg { display: inline-block; }
/* 📣 MERCADEO · FLUJOS (Flujos F1; 20-oct-2026): la tabla de flujos es la de las campañas (`.camp-t`); las celdas que llevan frases (el cuándo y el estado con quién y cuándo) se parten en renglones para que la tabla quepa; los números y los botones no. */
.flu-t td { white-space: normal; }
.flu-t td.num { white-space: nowrap; }
.flu-t td.camp-acciones { white-space: normal; min-width: 8rem; }      /* (F2) con la columna «Última revisión» la tabla ya no cabe si los botones van en una sola línea: se apilan */
.flu-t td:first-child { min-width: 11rem; }
.flu-t td.flu-rev { min-width: 9rem; }
#aprob-resultado.mer-aviso-error { color: var(--mer-bad); font-weight: 700; }
/* En el teléfono la tabla de mensajes no se desplaza de lado (los botones quedarían fuera de la vista): cada mensaje es un bloque, con su persona, su texto, su estado y sus botones uno debajo del otro. */
@media (max-width: 760px) {
  .aprob-t thead { display: none; }
  .aprob-t, .aprob-t tbody, .aprob-t tr, .aprob-t td { display: block; }
  .aprob-t tr { padding: 10px 12px; border-bottom: 1px solid var(--mer-line); }
  .aprob-t tr:last-child { border-bottom: 0; }
  .aprob-t td, .aprob-t tr:last-child td { border: 0; padding: 3px 0; white-space: normal; }
  .aprob-t td.aprob-texto { min-width: 0; }
}
/* El globito rojo de «Aprobaciones» en la barra de Mercadeo (maqueta: `nav button .n`). Lo pinta `aprobPintarGlobito` con el número de pendientes de la lectura de la sección. */
.mer-sec .mer-n { display: inline-block; min-width: 1.4em; text-align: center; margin-left: 6px; border-radius: 999px; background: var(--mer-bad); color: #fff; font-size: .75rem; padding: 0 5px; }

/* 📣 MERCADEO · CAMPAÑAS COMO CARPETA (Campañas, pieza MC1; 18-oct-2026). Una tarjeta por campaña (la carpeta de un lanzamiento) con su nombre, su objetivo, su «del … al …» y, debajo, un bloque por medio con sus piezas.
   Las pastillas de estado reutilizan `.camp-pill` (mensajes de WhatsApp) y `.redes-pill` (publicaciones). */
.par-lista { display: flex; flex-direction: column; gap: 12px; }
.par-card { gap: 8px; }
.par-cabeza { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: flex-start; justify-content: space-between; }
.par-botones { display: flex; flex-wrap: wrap; gap: 6px; }
.par-botones .mer-btn { padding: 4px 10px; }
.par-medio { border-top: 1px solid var(--mer-line); padding-top: 8px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.par-pieza { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; overflow-wrap: anywhere; }
.par-roto { margin: 0; color: var(--mer-bad); font-weight: 700; }
#par-resultado.mer-aviso-error { color: var(--mer-bad); font-weight: 700; }
/* ---------- 🤖 Natalia (pieza A2: la tarjeta, la portada y los ajustes) ----------
   Diseño aprobado el 16-oct-2026 (`disenos/natalia-configuracion/maqueta.html`). La tarjeta del inicio copia a las otras; la portada y los ajustes usan nombres propios (`nat-`) para no depender de las reglas de Mercadeo ni de Proveedores. */
:root { --inicio-natalia: #b4235a; --nat-ok: #1f7a45; --nat-ok-suave: #dff2e6; --nat-aviso-suave: #fdf1d6; }
.inicio-natalia .inicio-icono { background: var(--inicio-natalia); }
.inicio-natalia .inicio-ir { color: var(--inicio-natalia); }
a.inicio-natalia[href]:hover { border-color: var(--inicio-natalia); }
a.inicio-natalia:focus-visible { outline: 3px solid var(--inicio-natalia); outline-offset: 3px; }
.nat-vista { background: var(--fondo); }
.nat-vista .barra-titulo { flex-wrap: wrap; row-gap: 6px; min-width: 0; }
.nat-pagina { max-width: 52rem; margin: 0 auto; padding-inline: 16px; padding-block: 18px 48px; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.nat-pagina h1 { font-size: clamp(1.4rem, 4vw, 1.9rem); font-weight: 700; line-height: 1.15; text-wrap: balance; }
.nat-sub { color: var(--muted); margin-top: 2px; }
.nat-entradas { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; }
.nat-entrada { font: inherit; text-align: left; display: flex; flex-direction: column; gap: .6rem; background: var(--tarjeta); border: 1px solid var(--borde); border-radius: 16px; padding: 1.2rem; min-height: 9rem; color: inherit; cursor: pointer; }
.nat-entrada:hover { border-color: var(--inicio-natalia); }
.nat-entrada:focus-visible { outline: 3px solid var(--inicio-natalia); outline-offset: 3px; }
.nat-entrada h3 { font-size: 1.3rem; }
.nat-entrada-que { color: var(--muted); font-size: .95rem; }
.nat-ir { margin-top: auto; font-weight: 600; color: var(--inicio-natalia); }
.nat-lista { display: flex; flex-direction: column; gap: 16px; }
.nat-grupo { background: var(--tarjeta); border-radius: var(--radio); box-shadow: var(--sombra); padding: 16px; display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.nat-grupo h2 { font-size: .95rem; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; }
.nat-ajuste { border-top: 1px solid var(--borde); padding-top: 12px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.nat-grupo h2 + .nat-ajuste { border-top: 0; padding-top: 0; }
.nat-nombre { font-weight: 600; overflow-wrap: anywhere; }
.nat-valor { font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.nat-fila { display: flex; gap: 8px 12px; align-items: center; flex-wrap: wrap; }
.nat-entre { justify-content: space-between; }
.nat-que, .nat-limites, .nat-quien, .nat-nota { font-size: .9rem; color: var(--muted); overflow-wrap: anywhere; }
.nat-malo { color: var(--rojo); }
.nat-btn { font: inherit; font-weight: 600; font-size: .9rem; border-radius: var(--radio); padding: 6px 12px; cursor: pointer; border: 1.5px solid var(--borde); background: transparent; color: var(--texto); }
.nat-btn:disabled { opacity: .55; cursor: not-allowed; }
.nat-btn-si { background: var(--marca); border-color: var(--marca); color: #fff; }
.nat-editor { background: #fbf7f7; border: 1.5px solid var(--inicio-natalia); border-radius: var(--radio); padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.nat-campo { display: flex; align-items: center; gap: 8px; }
.nat-campo span { font-weight: 700; }
.nat-input { font: inherit; font-size: 1.2rem; font-weight: 700; padding: 10px 12px; border: 1.5px solid var(--borde); border-radius: 12px; width: 10rem; max-width: 100%; background: #fff; color: var(--texto); }
.nat-error { color: var(--rojo); font-size: .9rem; min-height: 1.2em; }
.nat-aviso { border-radius: 12px; padding: 10px 14px; font-size: .95rem; color: #fff; background: var(--nat-ok); }
.nat-aviso-malo { background: var(--rojo); }
.nat-det summary { cursor: pointer; font-weight: 600; font-size: .9rem; color: var(--inicio-natalia); }
.nat-historial { list-style: none; display: flex; flex-direction: column; gap: 8px; font-size: .9rem; margin-top: 8px; }
.nat-historial li { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; }
.nat-cuando { color: var(--muted); font-variant-numeric: tabular-nums; }
.nat-pie { color: var(--muted); font-size: .9rem; }
.nat-pie:empty { display: none; }
.nat-pagina .apr-roto .btn-fantasma2 { margin-left: 8px; }
@media (max-width: 480px) { .nat-historial li { grid-template-columns: 1fr; } }
/* 📄 Natalia · Documentos (pieza A3). Reutiliza `.nat-grupo`, `.nat-fila`, `.nat-nota` y `.nat-malo`; aquí solo lo propio. */
.nat-doc { border-top: 1px solid var(--borde); padding-top: 12px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.nat-grupo h2 + .nat-doc { border-top: 0; padding-top: 0; }
.nat-doc-nombre { font-weight: 600; overflow-wrap: anywhere; min-width: 0; }
.nat-doc-enlace { color: var(--marca); font-weight: 600; text-decoration: none; overflow-wrap: anywhere; }
.nat-doc-enlace:hover { text-decoration: underline; }
.nat-doc-enlace:focus-visible { outline: 3px solid var(--inicio-natalia); outline-offset: 2px; }
.nat-pill { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: .78rem; font-weight: 600; max-width: 100%; overflow-wrap: anywhere; }
.nat-pill-ok { background: var(--nat-ok-suave); color: var(--nat-ok); }
.nat-pill-av { background: var(--nat-aviso-suave); color: #7a5200; }
.nat-pill-mal { background: #f8dcd8; color: var(--rojo); }
.nat-doc-avisos { list-style: none; display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
/* 📄 Natalia · Documentos · bajar y sustituir (piezas A5 y A6). Reutiliza `.nat-btn`, `.nat-editor`, `.nat-aviso` y `.nat-historial`. */
.nat-doc-botones { margin-top: 6px; }
.nat-editor + .nat-fila, .nat-doc-botones + .nat-editor { margin-top: 6px; }
/* 🎨 Credenciales, pieza 9 («Quién puede qué» con el estilo de la maqueta): ✓ y raya, píldoras de Proyectos, «Pasante» / «Sin acceso» junto al nombre.
   SOLO bajo #vista-equipo. El texto de cada celda sigue siendo el de siempre (sí, no, completo, solo ver, el nombre): aquí se oculta con font-size 0
   y se dibuja el ✓ o la raya. Lo oculto lo siguen leyendo los lectores de pantalla, así que «sí» y «no» no se pierden.
   Toda regla de este bloque empieza por #vista-equipo: lo vigila tests/test_credenciales_maqueta_matriz.py. */
#vista-equipo .eq-m-marca { font-size: 0; }
#vista-equipo .eq-m-marca::before { font-size: 15px; font-weight: 700; line-height: 1; }
#vista-equipo .eq-m-si::before { content: "\2713"; color: var(--ok); }
#vista-equipo .eq-m-no::before { content: "\2014"; color: var(--line); font-weight: 400; }
#vista-equipo .eq-m-recortada::before { content: "\2014"; color: var(--line); font-weight: 400; }
#vista-equipo .eq-m-pildora { display: inline-block; border-radius: 999px; padding: 2px 9px; font-size: 12px; font-weight: 600; white-space: nowrap; }
#vista-equipo .eq-m-pildora-ok { background: var(--ok-soft); color: var(--ok); }
#vista-equipo .eq-m-pildora-info { background: var(--info-soft); color: var(--info); }
#vista-equipo .eq-m-dudoso { color: var(--bad); font-style: italic; }
#vista-equipo .eq-m-persona[data-pildora]::after { content: attr(data-pildora); display: inline-block; margin-left: 8px; padding: 1px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; white-space: nowrap; vertical-align: 1px; background: var(--info-soft); color: var(--info); }
#vista-equipo .eq-m-persona[data-pildora-tono="warn"]::after { background: var(--warn-soft); color: var(--warn); }
#vista-equipo .eq-m-persona[data-pildora-tono="bad"]::after { background: var(--bad-soft); color: var(--bad); }
#vista-equipo .eq-m-nota { margin-top: 10px; }
