/* ==========================================================================
   Pypper · Tema "soft" — piloto sobre la vista Panel
   Se carga DESPUÉS de styles.css y solo redefine tokens y apariencia.
   No cambia ningún id, clase ni estructura: app.js sigue funcionando igual.
   Para volver al tema anterior basta con quitar su <link> de index.html.
   Paleta tomada de platafromavoicebot/dashboard (1).html.
   ========================================================================== */

@import url("./fonts/jakarta.css");

:root{
  /* Acento del template */
  --brand:      #FD3244;
  --brand-2:    #D31E2F;
  --brand-ink:  #D31E2F;
  --brand-bg:   #FFF2F2;
  --brand-rim:  #FFDCDE;

  /* Neutros cálidos: el gris frío original chocaba con el rojo coral */
  --ink:        #14100F;
  --ink-2:      #2A2422;
  --muted:      #8B8380;
  --faint:      #A9A2A0;
  --line:       rgba(20,16,15,.09);
  --line-2:     rgba(20,16,15,.14);

  --surface:    rgba(255,255,255,.80);
  --surface-2:  rgba(255,255,255,.55);
  --surface-3:  rgba(255,255,255,.42);

  --nav:        transparent;
  --on-nav:     var(--ink-2);
  --on-nav-2:   var(--muted);

  /* Radios grandes: pill en botones, 20-26px en tarjetas */
  --r-sm: 12px; --r: 14px; --r-lg: 22px; --r-xl: 26px;

  /* Sombras difusas, sin bordes duros */
  --sh-1: 0 1px 2px rgba(60,20,20,.03);
  --sh-2: 0 2px 4px rgba(60,20,20,.03), 0 12px 28px rgba(60,20,20,.05);
  --sh-3: 0 10px 24px rgba(60,20,20,.08), 0 30px 60px rgba(30,10,10,.10);

  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* El template es claro por diseño: el gradiente cálido no traduce a oscuro.
   Se fija el esquema claro para que el navegador no invierta los neutros. */
:root{ color-scheme: light; }

body{
  font-family: var(--font);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  /* Gradiente cálido: los tres colores del logotipo en la esquina inferior
     derecha (morado -> rojo -> naranja), casi blanco arriba a la izquierda.
     Es lo que da carácter; sin esto es un dashboard genérico.
     La geometría y el alcance no cambian respecto a la versión de un solo
     color: del 38% en adelante las paradas están en la misma posición y con
     la misma mezcla con blanco (64%, 79%, 89%, 97%), así que el campo claro
     donde vive el contenido se ve igual. Lo único que cambia es el matiz de
     la banda saturada de la esquina. */
  background:
    radial-gradient(135% 115% at 103% 106%,
      #AE3A8D 0%, #FD3244 10%, #FD6144 20%, #FEA898 28%,
      #FEC6BC 38%, #FFDED8 56%, #FFEEEA 74%, #FFFAF9 100%)
    fixed;
}

/* ---------- Cáscara: una sola columna, sin barra lateral ---------- */
.app{
  display: block;
  min-height: 100vh;
  padding: 18px clamp(14px,2.2vw,26px) 0;
}
.main{ padding: 0 0 64px; max-width: 1440px; margin: 0 auto; }

/* ---------- Barra superior ---------- */
.topbar{
  display: flex;
  align-items: center;
  gap: 18px;
  max-width: 1440px;
  margin: 0 auto 26px;
  flex-wrap: wrap;
  /* Los menús desplegables se metían DEBAJO de las tarjetas. El z-index: 60 de
     .nav-drop no servía de nada porque el `backdrop-filter` de .nav-list crea un
     contexto de apilamiento y lo encierra ahí dentro; hacia afuera, .nav-list
     compite con .panel y .stat (que también llevan backdrop-filter, y por eso
     pintan como si fueran z-index: 0) y las tarjetas ganan por venir después en
     el DOM. Posicionar la barra entera la saca de esa competencia.
     70 la deja por encima de todo el contenido y por debajo de los modales (80)
     y del toast (100), que viven fuera de .app. */
  position: relative;
  z-index: 70;
}

.brand{ padding: 0; gap: 12px; flex: none; }

/* Los dos logotipos usan versiones -2x.png: los originales son lienzos enormes
   (2400x2400 y 1750x813) con mucho aire transparente alrededor, y reducirlos 40
   veces en el navegador emborronaba los trazos finos. Estas copias vienen
   recortadas a la tinta y rasterizadas a exactamente el doble del tamaño de uso
   (122x48 y 226x60), así que el navegador solo baja 2:1 y el trazo queda nítido
   igual en pantalla normal que en retina.
   Al estar recortados a la tinta se dimensionan solo por `height`: con
   `width: auto` la proporción sale del propio archivo y no hay forma de que se
   deformen al cambiar de tamaño. */
.brand-logo{
  height: 24px;
  width: auto;
  flex: none;
  border-radius: 0;
  box-shadow: none;
}

/* Lockup "| pypper / BANCOPPEL · COBRANZA" que sustituye al texto .brand-txt. */
.brand-lockup{
  height: 30px;
  width: auto;
  flex: none;
  display: block;
}

/* En pantallas chicas basta con bajar la altura: el ancho se reajusta solo. */
@media (max-width: 560px){
  .brand{ gap: 10px; }
  .brand-logo{ height: 20px; }
  .brand-lockup{ height: 25px; }
}

/* Contenedor pill de las pestañas */
.nav-list{
  flex-direction: row;
  align-items: center;
  gap: 3px;
  background: rgba(255,255,255,.45);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 999px;
  padding: 5px;
  box-shadow: var(--sh-1);
}

.nav-item{
  width: auto;
  border-radius: 999px;
  padding: 9px 15px;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
  transition: background .2s, color .2s;
}
.nav-item svg{ opacity: .7; }
.nav-item:hover{ background: rgba(255,255,255,.85); color: var(--ink); }
.nav-item:hover svg{ opacity: 1; }

/* Al entrar a una pestaña se llena de color: negro como ancla visual */
.nav-item.is-active{
  background: var(--ink);
  color: #fff;
  font-weight: 600;
  box-shadow: none;
}
.nav-item.is-active svg{ color: #fff; opacity: 1; }
/* La barrita lateral del tema anterior no aplica en horizontal */
.nav-item.is-active::before{ display: none; }

/* ---------- Grupos desplegables ---------- */
/* Sin JavaScript: el menú se revela al pasar el cursor y se cierra al salir.
   Así no hay que tocar app.js, que engancha por clase .nav-item.
   La apertura por teclado y por toque se resuelve más abajo, en .nav-drop. */
.nav-group{ position: relative; }

.nav-group-btn{
  display: flex; align-items: center; gap: 6px;
  border: none; background: none; cursor: pointer;
  border-radius: 999px; padding: 9px 13px 9px 15px;
  font-family: var(--font); font-size: 13px; font-weight: 500;
  color: var(--ink-2); white-space: nowrap;
  transition: background .2s, color .2s;
}
.nav-group-btn:hover{ background: rgba(255,255,255,.85); color: var(--ink); }
.nav-group-btn .chev{ width: 14px; height: 14px; opacity: .6; transition: transform .2s; }
.nav-group:hover .chev, .nav-group:has(:focus-visible) .chev{ transform: rotate(180deg); }

/* Si la vista abierta está dentro del grupo, el grupo se pinta también:
   si no, al entrar a "Configuración" no habría ninguna pestaña marcada. */
.nav-group:has(.nav-item.is-active) > .nav-group-btn{
  background: var(--ink); color: #fff; font-weight: 600;
}
.nav-group:has(.nav-item.is-active) > .nav-group-btn .chev{ opacity: 1; }

.nav-drop{
  position: absolute;
  top: calc(100% + 9px);
  left: 0;
  min-width: 216px;
  display: flex; flex-direction: column; gap: 2px;
  background: rgba(255,255,255,.94);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-radius: var(--r-lg);
  padding: 7px;
  box-shadow: var(--sh-3);
  opacity: 0; visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .18s, transform .18s, visibility .18s;
  z-index: 60;
}
/* Puente invisible sobre los 9px de hueco entre el botón y el menú: sin él, al
   bajar el cursor hacia las opciones se pierde el :hover y el menú se cierra.
   Solo existe con el menú abierto (cuando está cerrado hereda visibility). */
.nav-drop::before{
  content: "";
  position: absolute;
  left: 0; right: 0; top: -9px; height: 9px;
}

/* Ratón: se despliega al pasar encima y se cierra al salir. */
.nav-group:hover > .nav-drop{
  opacity: 1; visibility: visible; transform: none;
}
/* Teclado: :focus-visible (no :focus-within) es la clave. El clic del ratón deja
   el foco en el botón pero NO activa :focus-visible, así que el menú ya no se
   queda pegado al hacer clic; tabular sí lo abre. */
.nav-group:has(:focus-visible) > .nav-drop{
  opacity: 1; visibility: visible; transform: none;
}
/* Táctil: sin cursor no hay hover, y ahí el tap que deja el menú abierto sí es
   el comportamiento correcto. */
@media (hover: none){
  .nav-group:focus-within > .nav-drop{
    opacity: 1; visibility: visible; transform: none;
  }
  .nav-group:focus-within .chev{ transform: rotate(180deg); }
}
.nav-drop .nav-item{
  width: 100%;
  border-radius: var(--r-sm);
  justify-content: flex-start;
}

/* ---------- Sesión: avatar y menú, al extremo derecho ---------- */
/* Reusa .nav-group y .nav-drop a propósito. Con eso hereda gratis las tres
   formas de apertura (hover, teclado, táctil) y, sobre todo, el arreglo de
   apilamiento explicado arriba en .topbar: un componente nuevo habría vuelto a
   caer bajo las tarjetas por el mismo backdrop-filter. Lo único propio es la
   alineación por la derecha, porque aquí el disparador vive en el borde. */
.sesion{ flex: none; margin-left: 6px; }
.sesion-btn{ padding: 3px; border-radius: 999px; }
.sesion .nav-drop{ left: auto; right: 0; min-width: 208px; }

/* Quién eres: encabezado del menú, no una opción. Separado por una línea para
   que no se lea como algo que se puede clicar. */
.sesion-quien{
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 12px 11px;
  margin-bottom: 5px;
  border-bottom: 1px solid var(--line);
}
.sesion-quien strong{ font-size: 13.5px; font-weight: 600; color: var(--ink); }
.sesion-quien span{ font-size: 11.5px; font-weight: 500; color: var(--muted); }

/* Mismo aspecto que .nav-item dentro del menú, con clase propia: app.js hace
   $$('.nav-item').forEach(b => b.onclick = () => navegar(b.dataset.view)), y
   este botón no abre ninguna vista. */
.sesion-item{
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  border: none; background: none; cursor: pointer;
  border-radius: var(--r-sm);
  padding: 9px 12px;
  font-family: var(--font); font-size: 13px; font-weight: 500;
  color: var(--ink-2); text-align: left;
  transition: background .2s, color .2s;
}
.sesion-item:hover{ background: rgba(20,16,15,.05); color: var(--ink); }
.sesion-item svg{ width: 17px; height: 17px; flex: none; opacity: .7; }

/* ---------- Estado del agente, a la derecha ---------- */
.nav-foot{
  margin: 0 0 0 auto;
  padding: 0;
  border-top: none;
  align-items: flex-end;
  flex: none;
}
.agent-state{ color: var(--ink); font-weight: 600; font-size: 12.5px; }
.agent-meta{ color: var(--muted); font-size: 11.5px; }

@media (max-width: 1180px){
  .nav-item{ padding: 9px 12px; font-size: 12.5px; }
  .nav-item svg{ display: none; }   /* el texto importa más que el ícono */
}
@media (max-width: 860px){
  .topbar{ gap: 12px; }
  .nav-list{ order: 3; width: 100%; overflow-x: auto; justify-content: flex-start; }
  .nav-foot{ margin-left: auto; }
}

/* ---------- Encabezado de vista ---------- */
.view-head h1{
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -.035em;
}
.view-head .sub{ color: var(--muted); font-weight: 500; }

/* ---------- Botones: pill completo ---------- */
.btn{
  border-radius: 999px;
  font-family: var(--font);
  font-weight: 600;
  border: none;
  transition: transform .18s, box-shadow .2s, background .2s;
}
.btn:hover{ transform: translateY(-1px); }
.btn-primary{
  background: var(--ink);
  color: #fff;
  box-shadow: 0 6px 18px rgba(20,10,10,.18);
}
.btn-primary:hover{ background: var(--brand); }

/* ---------- KPIs: números gigantes contra labels chiquitos ---------- */
.stats{ gap: 15px; }

.stat{
  background: var(--surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: none;
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2);
  padding: 22px 22px 20px;   /* mucho aire adentro */
}
.stat .k{
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0;
}
.stat .v{
  font-size: 46px;           /* el truco para que el KPI grite sin saturar */
  font-weight: 700;
  letter-spacing: -.045em;
  line-height: 1;
  margin-top: 10px;
}
.stat .v.accent{ color: var(--brand); }
/* min-height en vez del &nbsp; que antes reservaba el renglón: si el texto se
   queda vacío la tarjeta ya no se encoge, y no depende de un carácter invisible. */
.stat .d{ font-size: 11.5px; color: var(--muted); font-weight: 500; min-height: 15px; }

/* ---------- Tarjetas ---------- */
.cols{ gap: 15px; }

.panel{
  background: var(--surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: none;
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2);
  padding: 20px;
}
.panel-head h2{ font-size: 16px; font-weight: 600; letter-spacing: -.01em; }

.tag{
  border-radius: 999px;
  background: rgba(255,255,255,.75);
  border: none;
  color: var(--ink-2);
  font-weight: 600;
}
.link{ color: var(--brand); font-weight: 600; }

/* ---------- Panel: rango, sello de actualización y tarjeta clicable ---------- */
.segmented.sm{ padding: 3px; }
.segmented.sm .seg{ padding: 5px 11px; font-size: 12px; }

/* Fila de filtros: encima de lo que gobierna, no dentro del encabezado. El sello
   se va al extremo opuesto para que no se lea como parte del control. */
.viewbar{
  display: flex; align-items: center; gap: 12px;
  margin: -8px 0 14px;
  flex-wrap: wrap;
}
.viewbar .stamp{ margin-left: auto; }

/* Todos los controles de la fila miden lo mismo y comparten línea central.
   .segmented arrastra un margin-bottom:16px de su uso original en Llamar (suelto
   encima del formulario) que aquí lo levantaba 8px sobre los demás: dentro de un
   flex centrado, un margen inferior descuadra la caja entera. */
.viewbar > *{ margin-top: 0; margin-bottom: 0; }
.viewbar .segmented,
.viewbar .search,
.viewbar .filtro,
.viewbar .f.inline select{ height: 36px; box-sizing: border-box; }
.viewbar .segmented .seg{ display: flex; align-items: center; }
/* La etiqueta "Registros" se pega a su select en vez de flotar a media distancia. */
.viewbar .f.inline{ gap: 7px; }

.stamp{ font-size: 11.5px; color: var(--faint); white-space: nowrap; }

.head-inline{ display: flex; align-items: center; gap: 10px; }

/* La tarjeta de llamadas en curso lleva a En vivo. El botón "Ver en vivo" de
   adentro es el control accesible de verdad; esto solo amplía el área de clic. */
.card-link{ cursor: pointer; transition: box-shadow .2s, transform .2s; }
.card-link:hover{ box-shadow: var(--sh-3); transform: translateY(-1px); }

/* ---------- Gráfica de actividad ---------- */
/* Una sola serie (llamadas por cubeta), así que no lleva leyenda: el título de la
   tarjeta la nombra. El color es el acento de la marca, validado a 3:1 contra la
   superficie de la tarjeta. Eje y recessivo, rejilla apenas insinuada. */
.chart{ display: flex; gap: 10px; padding: 6px 2px 0; }

.chart-y{
  display: flex; flex-direction: column; justify-content: space-between;
  height: 132px; padding-bottom: 20px;
  font-size: 10.5px; color: var(--faint); font-variant-numeric: tabular-nums;
}
.chart-plot{
  flex: 1; display: flex; align-items: flex-end; gap: 3px;
  height: 132px; padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
  position: relative;
}
.chart-plot .col{
  flex: 1; min-width: 0; height: 100%;
  display: flex; align-items: flex-end; justify-content: center;
  position: relative;
}
.chart-plot .bar{
  width: 100%; max-width: 26px;
  background: #FD3244;
  border-radius: 4px 4px 0 0;      /* topes redondeados, base anclada a la línea */
  min-height: 0;
  transition: opacity .15s;
}
/* Cubeta en cero: un tope de 2px sobre la línea base para que se lea "hubo cero"
   y no "no hay dato". */
.chart-plot .bar.is-zero{ height: 2px; background: var(--line-2); border-radius: 2px; }

.chart-plot .col.is-now .bar{ box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--brand-rim); }
.chart-plot .col:hover .bar{ opacity: .78; }

.chart-plot .xlab{
  position: absolute; bottom: -18px; left: 50%; transform: translateX(-50%);
  font-size: 10.5px; color: var(--faint); font-variant-numeric: tabular-nums;
  white-space: nowrap; pointer-events: none;
}

/* Tooltip por cubeta, en CSS: el área de hover es la columna completa, más ancha
   que la barra, así no hay que apuntarle a una barra de 3px de alto. */
.chart-plot .tip{
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 1px;
  background: var(--ink); color: #fff;
  border-radius: 10px; padding: 7px 10px;
  font-size: 11px; line-height: 1.35; white-space: nowrap;
  opacity: 0; visibility: hidden; transition: opacity .12s, visibility .12s;
  box-shadow: var(--sh-2); z-index: 5; pointer-events: none;
}
.chart-plot .tip strong{ font-size: 12.5px; font-weight: 650; }
.chart-plot .col:hover .tip{ opacity: 1; visibility: visible; }
/* Las columnas de los extremos abren el tooltip hacia adentro para que no se
   salga de la tarjeta. */
.chart-plot .col:first-child .tip{ left: 0; transform: none; }
.chart-plot .col:last-child .tip{ left: auto; right: 0; transform: none; }

/* La ficha de confirmación reutiliza .lead-card, que está pensada para vivir
   dentro del recuadro de resultado del formulario: dentro del modal sobra su
   borde superior y le falta el respiro lateral que traen las demás secciones. */
#cfBody{ padding: 16px 20px 20px; overflow-y: auto; }
#cfBody .lead-card{ margin-top: 0; border-top: none; padding-top: 0; }
#cfBody .lead-head strong{ opacity: 1; color: var(--muted); }
#cfBody .lead-grid{ gap: 8px 18px; }
#cfBody .lead-grid dd.vacio{ color: var(--brand-ink); font-weight: 600; }

/* ---------- Cartera ---------- */
.table-wrap:has(> #cartTable){ max-height: calc(100vh - 420px); min-height: 240px; overflow: auto; }
#cartTable thead th{ background: #FDF4F3; }
#cartTable tbody tr{ cursor: pointer; }
#cartTable tbody tr:focus-visible{ outline: 2px solid var(--brand); outline-offset: -2px; }
#cartTable tbody tr:hover .link{ text-decoration: underline; }
/* El monto con recargo en coral: es la cifra que se evita llamando a tiempo. */
#cartTable .recargo{ color: var(--brand-ink); font-weight: 600; }

/* La ficha va a dos columnas en pantalla ancha: cuatro bloques apilados obligaban
   a hacer scroll dentro del modal para ver el pago, que es lo que más importa. */
#cuBody{ padding: 16px 20px 20px; overflow-y: auto; }
.cuenta-cols{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 8px 26px;
}
#cuBody .lead-card{ margin-top: 0; border-top: none; padding-top: 0; }
#cuBody .lead-head strong{ opacity: 1; color: var(--muted); }

/* La previsualización de lo que dirá el agente: se lee como una frase, no como
   una ficha de datos, porque de eso se trata revisarla. */
.guion-prev{
  margin-top: 18px; padding: 14px 16px;
  background: var(--brand-bg); border: 1px solid var(--brand-rim);
  border-radius: var(--r-lg);
}
.guion-prev p{
  margin: 8px 0 6px; font-size: 14px; line-height: 1.6; color: var(--ink);
}
.guion-prev b{ font-weight: 650; color: var(--brand-ink); }
.guion-prev .hint{ font-size: 11.5px; color: var(--muted); }

/* Las dos tarjetas del Panel se leen como un par, así que van del mismo alto.
   .cols trae `align-items: start` de styles.css —correcto en Análisis y en
   Configuración, donde las columnas no tienen por qué medir igual—, por eso el
   ajuste va acotado a esta vista. El listado de adentro crece para que el estado
   vacío quede centrado y no pegado arriba. */
.view[data-view="dashboard"] .cols{ align-items: stretch; }
.view[data-view="dashboard"] .cols > .panel{ display: flex; flex-direction: column; }
.view[data-view="dashboard"] #dashLive,
.view[data-view="dashboard"] #dashRecent{ flex: 1; justify-content: center; }

/* ---------- Modales ---------- */
/* La tarjeta usaba --surface, que en este tema es blanco al 80%: sobre el fondo
   claro se transparentaba y el texto de atrás se leía a través del diálogo. En una
   ventana donde se revisa qué se va a publicar eso es inaceptable, así que va
   opaca. El velo de atrás sí sigue translúcido, que es lo que da la sensación de
   capa. */
.modal-card{
  background: #FFFCFB;
  border-color: rgba(20,16,15,.06);
}
.modal-card .modal-head,
.modal-card .modal-foot{ background: #FFF8F7; }
/* El velo, un poco más presente: con el degradado cálido detrás, el gris estándar
   casi no se notaba. */
.modal-backdrop{ background: rgba(40,18,16,.34); }

/* ---------- Publicación del guion ---------- */
/* La nota ocupa el ancho que queda y los botones se van a la derecha: es un pie
   de modal, no una fila de formulario. */
.pub-nota{ flex: 1; min-width: 240px; }
.pub-nota > span{ font-size: 12px; color: var(--muted); white-space: nowrap; }
.pub-nota input{
  flex: 1; font-family: var(--font); font-size: 13px;
  background: var(--surface); border: 1px solid var(--line-2);
  border-radius: 10px; padding: 8px 12px; color: var(--ink);
}
.pub-nota input:focus{ outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-rim); }
#publishModal .modal-foot{ gap: 14px; }
#publishModal .foot-btns{ display: flex; gap: 8px; flex: none; }
#pubBody .diff{ margin: 0; }

/* ---------- Historial ---------- */
/* Controles de la barra de filtros: antes el buscador llevaba sus estilos en un
   style="" dentro del HTML, así que no seguía los tokens del tema. */
.viewbar .search,
.viewbar .filtro{
  font-family: var(--font); font-size: 13px; color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 10px;
  padding: 8px 12px; height: 36px;
}
.viewbar .search{ width: 230px; }
.viewbar .search::placeholder{ color: var(--faint); }
.viewbar .filtro{ cursor: pointer; padding-right: 30px; appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path d='m6 8.5 4 4 4-4' fill='none' stroke='%238B8380' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 16px;
}
.viewbar .search:focus,
.viewbar .filtro:focus{ outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-rim); }
.viewbar .f.inline > span{ font-size: 12px; color: var(--muted); }
.viewbar .f.inline select{ height: 36px; }

/* El encabezado ya era sticky, pero .table-wrap no tenía altura: sin contenedor
   que haga scroll, no hay nada a lo que pegarse y se iba con la página. Con el
   alto acotado, los encabezados se quedan visibles al recorrer los registros. */
.table-wrap:has(> #histTable){
  max-height: calc(100vh - 300px);
  min-height: 260px;
  overflow: auto;
}
#histTable thead th{ background: #FDF4F3; }   /* opaco: si es translúcido, las filas se ven pasar por detrás */

/* Columnas ordenables */
.table.sortable th[data-orden]{ cursor: pointer; user-select: none; position: sticky; }
.table.sortable th[data-orden]:hover{ color: var(--ink); }
.table.sortable th[data-orden]::after{
  content: "↕"; margin-left: 6px; opacity: .28; font-size: 11px;
}
.table.sortable th.is-sorted{ color: var(--ink); }
.table.sortable th.is-sorted.asc::after { content: "↑"; opacity: .9; }
.table.sortable th.is-sorted.desc::after{ content: "↓"; opacity: .9; }
.table.sortable th[data-orden]:focus-visible{ outline: 2px solid var(--brand); outline-offset: -2px; }

/* El renglón entero abre el detalle */
#histTable tbody tr{ cursor: pointer; }
#histTable tbody tr:focus-visible{ outline: 2px solid var(--brand); outline-offset: -2px; }
#histTable tbody tr:hover .link{ text-decoration: underline; }

/* ---------- En vivo ---------- */
/* El botón queda a la derecha del renglón, después del cronómetro. */
.live-item{ position: relative; }
.live-open{
  margin-left: 4px; flex: none;
  font-size: 12.5px; white-space: nowrap;
}
.live-list.lg .live-item{ gap: 14px; }

/* Puntos de "sigue hablando" al final de la transcripción en curso: sin esto no
   se distingue una llamada que avanza de una que se quedó callada. */
.b-esperando{
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 11px 14px; border-radius: var(--r-lg);
  background: var(--surface-2);
}
.b-esperando span{
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--faint);
  animation: esperando 1.25s ease-in-out infinite;
}
.b-esperando span:nth-child(2){ animation-delay: .18s; }
.b-esperando span:nth-child(3){ animation-delay: .36s; }
@keyframes esperando{
  0%, 60%, 100%{ opacity: .28; transform: translateY(0); }
  30%          { opacity: .95; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce){
  .b-esperando span{ animation: none; opacity: .55; }
}

/* ---------- Formulario de llamada por grupos ---------- */
/* Eran diez campos en una rejilla plana: para saber qué iba junto con qué había
   que leerlos todos. Ahora van en <fieldset> por función, que además le da
   contexto al lector de pantalla ("Cliente: teléfono") en vez de leer diez
   etiquetas sueltas. */
.fgroup{ border: none; margin: 0; padding: 0; min-width: 0; }
.fgroup > legend{
  display: block; width: 100%; float: left;   /* float: el legend nativo no acepta bloque en todos los motores */
  padding: 18px 18px 0;
  font-size: 12.5px; font-weight: 650; color: var(--ink);
  letter-spacing: -.01em;
}
.fgroup > legend em{
  font-style: normal; font-weight: 480; color: var(--faint);
  font-size: 11.5px; margin-left: 8px;
}
.fgroup > .fields{ clear: both; padding-top: 12px; }
/* Separador entre grupos, no marco alrededor de cada uno: con tres recuadros
   anidados dentro de la tarjeta la vista se llenaba de líneas. */
.fgroup + .fgroup{ border-top: 1px solid var(--line); }
.fgroup + .fgroup > legend{ padding-top: 16px; }

/* Rejilla de 4 columnas fija en vez de auto-fit: así las columnas se alinean
   entre los tres grupos y el formulario se lee como una sola cuadrícula.
   Con auto-fit, un grupo de 3 campos estiraba cada uno a un tercio del ancho y
   "Días de atraso" acababa midiendo 450px. */
.fgroup .fields{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
.fgroup .f.wide{ grid-column: span 2; }        /* los nombres completos no caben en una columna */
@media (max-width: 1180px){
  .fgroup .fields{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 860px){
  .fgroup .fields{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px){
  .fgroup .fields{ grid-template-columns: 1fr; }
  .fgroup .f.wide{ grid-column: auto; }
}

/* ---------- Deslizadores de Configuración ---------- */
/* La barra venía en --surface-3 (blanco al 42%), que sobre el fondo claro del tema
   casi desaparecía: no se veía el recorrido y el control parecía un punto suelto.
   En negro el trazo se lee de un vistazo y el tirador coral resalta encima.
   El background del input cubre Chrome/Safari/Edge; Firefox pinta su propia
   pista, por eso va también ::-moz-range-track. No se toca la altura de la
   pista en webkit para no descentrar el tirador. */
.range-row input[type=range]{ background: var(--ink); }
.range-row input[type=range]::-moz-range-track{
  background: var(--ink); height: 5px; border-radius: 99px;
}
/* Anillo del tirador en blanco sólido: sobre negro, el blanco translúcido de
   --surface dejaba el borde a medias. */
.range-row input[type=range]::-webkit-slider-thumb{ border-color: #fff; }
.range-row input[type=range]::-moz-range-thumb{ border-color: #fff; }

/* ---------- Estados de error y validación ---------- */
.empty.is-error strong{ color: var(--brand-ink); }
.empty.is-error .btn{ margin-top: 10px; }

.ferr{
  font-size: 11.5px; font-weight: 550; color: var(--brand-ink); line-height: 1.35;
  /* flex-start, no center: con el mensaje en dos renglones el "!" se iba al medio
     y quedaba colgando en su propia línea. */
  display: flex; align-items: flex-start; gap: 5px;
}
.ferr::before{ content: "!"; font-weight: 700; flex: none; }
.f.has-error input,
.f.has-error select{ border-color: var(--brand); background: var(--brand-bg); }
.f.has-error input:focus{ box-shadow: 0 0 0 3px var(--brand-rim); }

/* El pulso de En vivo cuando se cae la conexión: el punto verde mintiendo era
   peor que no tener indicador. */
.pulse-tag.is-down{ color: var(--brand-ink); }
.pulse-tag.is-down .dot{ background: var(--brand); animation: none; }

@media (prefers-reduced-motion: reduce){
  .btn:hover{ transform: none; }
  .card-link:hover{ transform: none; }
}

/* ==========================================================================
   GRABACIONES
   Antes era una cuadrícula de tarjetas, cada una con el reproductor NATIVO del
   navegador dentro: un bloque gris de Chrome, cuadrado y con su menú de tres
   puntos, repetido 24 veces dentro de un sistema de coral, vidrio y esquinas
   de 22px. Ocupaba el 40% de cada tarjeta y mostraba "0:00 / 0:00", que además
   era falso: con preload="none" el navegador no sabe la duración hasta que le
   das play.

   Ahora es una LISTA. Las tarjetas sirven para objetos distintos entre sí;
   aquí todos los elementos son iguales, se leen en orden cronológico y lo que
   uno quiere es compararlos. En filas caben tres veces más y las columnas se
   alinean, que es lo que permite comparar de un vistazo.
   ========================================================================== */
.gr-lista{ display: flex; flex-direction: column; gap: 22px; }

/* Encabezado de día. La fecha se repetía en las 24 tarjetas; agrupando, se
   dice una vez y de paso da estructura al scroll. */
.gr-dia{
  display: flex; align-items: baseline; gap: 10px;
  padding: 0 4px 2px;
}
.gr-dia h3{ font-size: 13px; font-weight: 700; letter-spacing: -.01em; color: var(--ink); }
.gr-dia span{ font-size: 11.5px; font-weight: 500; color: var(--muted); }

.gr-grupo{
  background: var(--surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-2);
  overflow: hidden;
}

/* ---------- la fila ---------- */
.gr{
  position: relative;
  display: grid;
  /* El resumen se queda con el espacio sobrante: en la versión anterior ese
     hueco central estaba vacío y no había forma de saber qué pasó en una
     llamada sin reproducirla entera. */
  grid-template-columns: 38px minmax(150px, 210px) minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 14px;
  padding: 13px 16px 13px 18px;
  border-top: 1px solid var(--line);
  transition: background .15s;
}
.gr:first-child{ border-top: none; }
.gr:hover{ background: rgba(255,255,255,.55); }

/* Franja de resultado. La jerarquía que faltaba: nada distinguía una llamada de
   4 minutos de una de 20 segundos.
   Solo se pinta cuando el resultado DICE algo. "Contactado" es el 90% de las
   filas: dárselo también a él convertía el borde en una pared naranja que no
   informaba de nada y encima se leía como advertencia. Marcar todo es no
   marcar nada. */
.gr::before{
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: transparent;
}
.gr.r-promesa::before{ background: #1D9E75; }
.gr.r-sinacuerdo::before{ background: var(--brand); }
.gr.r-colgo::before{ background: #E5A100; }

/* Una promesa de pago es el resultado que importa: se nota sin leer. */
.gr.r-promesa{ background: rgba(29,158,117,.045); }
.gr.r-promesa .gr-nombre{ font-weight: 700; }

/* Las llamadas que no llegaron a nada se apagan en lugar de esconderse: siguen
   ahí para el conteo, pero dejan de competir por la atención. */
.gr.es-ruido{ opacity: .52; }
.gr.es-ruido:hover{ opacity: 1; }

/* ---------- botón de play ---------- */
.gr-play{
  width: 38px; height: 38px; border: none; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ink); color: #fff; cursor: pointer;
  transition: background .18s, transform .12s, box-shadow .18s;
  box-shadow: 0 2px 8px rgba(20,10,10,.16);
}
.gr-play:hover{ background: var(--brand); box-shadow: 0 4px 14px rgba(253,50,68,.3); }
.gr-play:active{ transform: scale(.94); }
.gr-play:focus-visible{ outline: 2px solid var(--brand); outline-offset: 2px; }
.gr-play svg{ width: 15px; height: 15px; fill: currentColor; }
.gr-play .icono-pausa{ display: none; }
.gr.sonando .gr-play{ background: var(--brand); }
.gr.sonando .gr-play .icono-play{ display: none; }
.gr.sonando .gr-play .icono-pausa{ display: block; }
.gr-play:disabled{ opacity: .35; cursor: default; box-shadow: none; }

/* ---------- datos ---------- */
.gr-quien{ min-width: 0; }
.gr-nombre{
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gr-tel{
  font-size: 11.5px; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.gr-tel em{ font-style: normal; color: var(--faint); }

/* Qué pasó en la llamada, en una línea. Si no cabe, se corta: es un anzuelo
   para decidir cuál escuchar, no el resumen completo —ese está al expandir. */
.gr-resumen{
  font-size: 12px; font-weight: 500; line-height: 1.4; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.gr-cifras{
  display: flex; align-items: baseline; gap: 10px;
  font-size: 12px; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums;   /* los tiempos se alinean en columna */
  white-space: nowrap;
}
.gr-cifras b{ color: var(--ink-2); font-weight: 640; }

.gr-abrir{
  width: 30px; height: 30px; border: none; border-radius: 999px;
  background: none; color: var(--muted); cursor: pointer;
  display: grid; place-items: center; transition: background .15s, color .15s, transform .2s;
}
.gr-abrir:hover{ background: rgba(20,16,15,.06); color: var(--ink); }
.gr-abrir:focus-visible{ outline: 2px solid var(--brand); outline-offset: -2px; }
.gr-abrir svg{ width: 16px; height: 16px; }
.gr.abierta .gr-abrir{ transform: rotate(180deg); }

/* ---------- barra de reproducción ----------
   Solo aparece en la fila que suena. En reposo la fila es información; en
   reproducción se convierte en control, sin ocupar sitio el resto del tiempo. */
.gr-reproductor{
  grid-column: 1 / -1;
  display: none;
  align-items: center; gap: 12px;
  padding: 4px 2px 2px;
}
.gr.sonando .gr-reproductor{ display: flex; }

.gr-barra{
  flex: 1; height: 22px; display: flex; align-items: center;
  cursor: pointer; touch-action: none;
}
.gr-barra i{
  display: block; width: 100%; height: 4px; border-radius: 99px;
  background: var(--line-2); position: relative;
}
.gr-barra i b{
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: var(--brand); border-radius: 99px;
}
.gr-barra i b::after{
  content: ""; position: absolute; right: -5px; top: 50%;
  width: 10px; height: 10px; margin-top: -5px;
  background: var(--brand); border-radius: 999px;
  box-shadow: 0 1px 4px rgba(253,50,68,.5);
}
.gr-tiempo{
  font-size: 11.5px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.gr-mando{
  border: none; background: rgba(20,16,15,.05); cursor: pointer;
  border-radius: 999px; padding: 4px 9px;
  font-family: var(--font); font-size: 11px; font-weight: 640; color: var(--ink-2);
  transition: background .15s, color .15s;
}
.gr-mando:hover{ background: rgba(20,16,15,.1); color: var(--ink); }
.gr-mando:focus-visible{ outline: 2px solid var(--brand); outline-offset: 1px; }
.gr-mando svg{ width: 13px; height: 13px; display: block; }
/* El enlace de descarga usa el mismo botón; sin esto heredaría el subrayado y
   el color de acento de .link. */
a.gr-mando{ display: inline-flex; align-items: center; text-decoration: none; padding: 5px 8px; }
.gr-mando.vel{ min-width: 38px; }

/* ---------- transcripción sincronizada ---------- */
.gr-texto{
  grid-column: 1 / -1;
  display: none;
  margin-top: 6px;
  max-height: 300px; overflow-y: auto;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.gr.abierta .gr-texto{ display: block; }
.gr-turno{
  display: flex; gap: 10px; align-items: flex-start;
  padding: 6px 9px; border-radius: 10px;
  cursor: pointer;
  transition: background .18s;
}
.gr-turno:hover{ background: rgba(20,16,15,.045); }
/* El turno que se está oyendo ahora. Es lo que convierte esto de "un archivero
   de mp3" en "revisar la gestión": se escucha y se lee a la vez. */
.gr-turno.ahora{ background: var(--brand-bg); }
.gr-turno .seg{
  font-size: 10.5px; font-weight: 640; color: var(--faint);
  font-variant-numeric: tabular-nums; padding-top: 2px; min-width: 34px;
}
.gr-turno .quien{
  font-size: 11px; font-weight: 700; min-width: 58px; padding-top: 1px;
  color: var(--muted);
}
.gr-turno.agente .quien{ color: var(--brand-ink); }
.gr-turno .dice{ font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }

/* El resumen es lo primero que se cae: es contexto, no dato. */
@media (max-width: 1180px){
  .gr{ grid-template-columns: 38px minmax(0, 1fr) auto auto auto; }
  .gr-resumen{ display: none; }
}
@media (max-width: 760px){
  .gr{ grid-template-columns: 34px minmax(0,1fr) auto; gap: 10px; padding: 12px 12px 12px 15px; }
  .gr-cifras{ grid-column: 2 / -1; gap: 8px; font-size: 11.5px; }
  .gr-play{ width: 34px; height: 34px; }
}
