﻿/* PegasusChat - backoffice del operador.
   Dos temas del mismo juego de fichas: lo que cambia son los valores, no las reglas.
   El color se define siempre en :root, nunca solo adentro de un bloque de tema. */

:root{
  --bg:#eef2f6; --surface:#fff; --surface-2:#f4f7fa; --surface-3:#e4eaf1;
  --ink:#111a24; --ink-2:#4a5666; --ink-3:#778393;
  --line:#dde4ec; --line-2:#c3ccd8;
  --accent:#0b6f8c; --accent-soft:#dceef5;
  --ok:#0c6b4f; --ok-soft:#dcefe7;
  --warn:#8a5209; --warn-soft:#fbf0dd;
  --danger:#a32c3c; --danger-soft:#fbe6e8;
  --oro:#85610a; --oro-suave:#fbf1d3;   /* GodMode: lo que se ve sin ser miembro */
  --shadow:0 1px 2px rgba(16,24,34,.05), 0 10px 30px -22px rgba(16,24,34,.5);
}
html[data-theme="dark"]{
  --bg:#11161d; --surface:#1a2029; --surface-2:#212934; --surface-3:#2b3441;
  --ink:#e8edf5; --ink-2:#a9b5c5; --ink-3:#7c8899;
  --line:#2a3140; --line-2:#3c4658;
  --accent:#38bdf8; --accent-soft:#123143;
  --ok:#34d399; --ok-soft:#0f3328;
  --warn:#e9b061; --warn-soft:#382c15;
  --danger:#f87a8b; --danger-soft:#3a1a20;
  --oro:#e8c25c; --oro-suave:#322910;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 10px 28px -18px rgba(0,0,0,.9);
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
}
button,input,select,textarea{font:inherit; color:inherit}
/* La bandeja maneja su propio scroll adentro: la pagina no se desplaza nunca. Sin esto
   alcanza un rebote para llevarse el encabezado y el campo de escribir fuera de vista. */
body.shell{overflow:hidden; overscroll-behavior:none}

/* ---------- login ---------- */
.login-wrap{min-height:100vh; min-height:100dvh; display:grid; place-items:center; padding:22px}
.login{
  width:100%; max-width:370px; background:var(--surface); border:1px solid var(--line);
  border-radius:16px; padding:28px 26px; box-shadow:var(--shadow); display:grid; gap:14px;
}
.login h1{margin:0; font-size:20px; font-weight:600}
.login .sub{margin:-8px 0 4px; font-size:13px; color:var(--ink-3)}
.field{display:grid; gap:5px}
.field label{font-size:12px; color:var(--ink-2)}
.field input, .field select{
  padding:10px 12px; border:1px solid var(--line-2); border-radius:9px;
  background:var(--bg); min-height:42px;
}
.field input:focus, .field select:focus{outline:2px solid var(--accent); outline-offset:-1px}
.msg-error{
  background:var(--danger-soft); border:1px solid var(--danger); color:var(--danger);
  border-radius:9px; padding:9px 12px; font-size:13px;
}

/* ---------- botones ---------- */
.btn{
  border:1px solid var(--line-2); background:var(--surface); color:var(--ink-2);
  border-radius:9px; padding:8px 14px; cursor:pointer; white-space:nowrap; min-height:38px;
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
}
.btn:hover:not(:disabled){border-color:var(--accent); color:var(--accent)}
.btn.pri{background:var(--accent); border-color:var(--accent); color:#fff; font-weight:500}
.btn.pri:hover:not(:disabled){opacity:.9; color:#fff}
.btn.dgr{border-color:var(--danger); color:var(--danger)}
.btn:disabled{opacity:.5; cursor:default}
.btn.wide{width:100%}
.spin{
  width:13px; height:13px; border-radius:50%; flex:none;
  border:2px solid currentColor; border-top-color:transparent; animation:sp .7s linear infinite;
}
@keyframes sp{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spin{animation:none}}

/* ---------- estructura ---------- */
/* Cuatro hijos, cuatro columnas. Con tres, la ficha caia a una segunda fila y
   partia la pantalla al medio. */
/* El orden importa: 100vh es el respaldo y 100dvh la buena, asi que va segunda. Al
   reves gana 100vh, que en el celular mide la pantalla CON las barras del navegador
   escondidas — o sea mas alto que lo que se ve. La app quedaba mas grande que la
   pantalla, la pagina entera se desplazaba, y al bajar se iban el encabezado y el
   campo para escribir. */
.app{height:100vh; height:100dvh; display:grid;
     grid-template-columns:56px 300px minmax(0,1fr) 250px;
     grid-template-rows:100%; overflow:hidden}
.rail{
  background:var(--surface-3); border-right:1px solid var(--line);
  display:flex; flex-direction:column; align-items:center; gap:8px; padding:10px 0;
}
.rail .sp{flex:1}
.rico{
  width:38px; height:38px; border-radius:10px; display:grid; place-items:center;
  color:var(--ink-3); cursor:pointer; position:relative; border:none; background:none;
}
/* Sin esto, el display:grid de arriba le gana al atributo hidden: los iconos de las zonas
   que el operador no tiene (db/54) y el de instalar seguian a la vista. */
.rico[hidden]{display:none}
.rico:hover{background:var(--surface-2); color:var(--ink)}
.rico.on{background:var(--accent); color:#fff}
.rico svg{width:19px; height:19px}
.cnt{
  position:absolute; top:1px; right:1px; min-width:17px; height:17px; padding:0 4px;
  border-radius:99px; font-size:10px; font-weight:600; display:grid; place-items:center;
  background:var(--danger); color:#fff;
}
.cnt.soft{background:var(--surface); color:var(--ink-2); border:1px solid var(--line-2)}
/* El aviso de la cola. Hueco y ambar contra el rojo lleno del sin leer, porque son dos
   cosas distintas: el rojo se apaga mirando y este no —la conversacion no es de nadie
   todavia—, se apaga cuando alguien la toma o la cierra. Mismo tamaño y mismo lugar: lo
   unico que cambia es lo que promete. */
.cnt.espera{background:var(--warn-soft); color:var(--warn); border:1px solid var(--warn)}
.av{
  width:34px; height:34px; border-radius:50%; background:var(--accent); color:#fff;
  display:grid; place-items:center; font-size:11px; font-weight:600; flex:none;
}
.av.gray{background:var(--surface-2); color:var(--ink-2); border:1px solid var(--line)}

.col{display:flex; flex-direction:column; min-width:0; border-right:1px solid var(--line);
     background:var(--surface); overflow:hidden}
.col:last-child{border-right:none}
.colhead{padding:11px 14px; border-bottom:1px solid var(--line); background:var(--surface-2); flex:none}
.brand{font-weight:600; font-size:14px}
.brand small{display:block; font-weight:400; color:var(--ink-3); font-size:11.5px}
/* El filtro de la bandeja: UN desplegable, en toda pantalla. Antes eran pestañas en
   el escritorio y un desplegable en el celular — dos controles para lo mismo, que hay
   que mantener y probar dos veces. */
/* Es propio y no un <select> porque cada opcion lleva su globito rojo, y adentro de un
   <option> no entra mas que texto. Se comporta igual: una linea a la vista y la lista
   al tocarla. */
.tabsel{position:relative; margin:0 10px 9px}
.tabcara{
  display:flex; align-items:center; gap:8px; width:100%; padding:8px 11px;
  border:1px solid var(--line-2); border-radius:8px; background:var(--bg); color:var(--ink);
  font:inherit; font-size:13px; text-align:left; cursor:pointer;
}
.tabcara:focus-visible{outline:2px solid var(--accent); outline-offset:-1px}
.tabtxt{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.tabflecha{width:15px; height:15px; flex:none; color:var(--ink-3)}
/* El globito va en el flujo, no pegado a una esquina como el de la barra lateral. */
.tabcnt{position:static; flex:none}

/* ⚠️ Esto tiene que estar. `hidden` esconde por la hoja del navegador, que dice
   display:none, y CUALQUIER display que escriba uno le gana — asi que un .tablista con
   display:grid se marcaba como cerrada y se seguia viendo: el desplegable no cerraba con
   nada. Lo mismo el globito en cero. Vale para todo lo que se apague con `hidden` y
   ademas traiga display propio. */
.tablista[hidden], .tabcnt[hidden], .buscahilo[hidden]{display:none}
.tablista{
  position:absolute; z-index:40; left:0; right:0; top:calc(100% + 4px); padding:5px;
  background:var(--surface); border:1px solid var(--line); border-radius:10px;
  box-shadow:0 14px 32px -18px rgba(16,24,34,.65); display:grid; gap:2px;
}
.tabopc{
  display:flex; align-items:center; gap:8px; width:100%; padding:7px 9px; border:none;
  border-radius:7px; background:none; color:var(--ink); font:inherit; font-size:13px;
  text-align:left; cursor:pointer;
}
.tabopc:hover{background:var(--surface-2)}
.tabopc.on{color:var(--accent); font-weight:600}

/* La busqueda de la bandeja. Arriba de todo y siempre visible: es lo primero que se
   usa cuando alguien llama preguntando por lo suyo. */
/* Los cuatro controles de la columna —busqueda, estado, sucursal y etiqueta— llevan
   la MISMA separacion. La busqueda tenia 0 abajo y quedaba pegada al filtro de estado,
   como si fueran un solo bloque y los otros dos otra cosa. */
.buscabar{position:relative; display:flex; align-items:center; padding:9px 10px}
.buscabar svg{position:absolute; left:20px; width:15px; height:15px; color:var(--ink-3); pointer-events:none}
.buscabar input{
  width:100%; padding:8px 30px 8px 32px; border:1px solid var(--line-2); border-radius:8px;
  background:var(--bg); color:var(--ink); font:inherit; font-size:13px; -webkit-appearance:none;
}
.buscabar input:focus{outline:2px solid var(--accent); outline-offset:-1px}
.buscabar input::-webkit-search-cancel-button{display:none}

/* De donde salio la coincidencia. Chiquito y al final del renglon: es una nota al
   pie de lo que se muestra, no un dato mas de la conversacion. */
.rdonde{
  display:inline-block; margin-left:6px; padding:0 5px; border-radius:5px;
  background:var(--surface-2); color:var(--ink-3); font-size:10.5px; white-space:nowrap;
}
.buscax{
  position:absolute; right:19px; border:none; background:none; color:var(--ink-3);
  font-size:17px; line-height:1; cursor:pointer; padding:2px 4px; border-radius:6px;
}
.buscax:hover{color:var(--ink); background:var(--surface-2)}
.buscapista{margin-top:-6px; padding:0 12px 9px; font-size:11.5px; color:var(--ink-3)}

/* El menu del clip. Va posicionado desde el codigo y flota sobre todo: el clip vive
   al pie de la pantalla, dentro de una caja con overflow, y un menu comun quedaria
   recortado justo donde hay que tocarlo. */
.clipmenu{
  position:fixed; z-index:60; background:var(--surface); border:1px solid var(--line);
  border-radius:11px; box-shadow:0 12px 30px -16px rgba(16,24,34,.6); padding:5px;
  display:grid; gap:2px; min-width:186px;
}
.clipmenu button{
  display:flex; align-items:center; gap:9px; width:100%; text-align:left; border:none;
  background:none; color:var(--ink); font:inherit; font-size:13px; padding:8px 10px;
  border-radius:8px; cursor:pointer;
}
.clipmenu button:hover{background:var(--surface-2); color:var(--accent)}
.clipmenu svg{color:var(--ink-3); flex:none}
.clipmenu button:hover svg{color:var(--accent)}

/* El contador del tope de caracteres. Vive arriba del campo, alineado a la derecha, y
   solo aparece cerca del limite. */
.tope{padding:0 15px 5px; font-size:11.5px; color:var(--ink-3); text-align:right}
.tope[hidden]{display:none}
.tope.pasado{color:var(--danger); font-weight:600}
/* Y el campo se marca tambien: el cartel esta arriba y la vista esta en lo que se
   escribe. */
.composer textarea.pasado{border-color:var(--danger); background:var(--danger-soft)}

/* Los links del mensaje, como botones debajo del texto: uno por link (15/9). */
.msg .links{display:flex; flex-direction:column; gap:6px; margin-top:8px}
.msg .linkbtn{
  display:flex; align-items:center; min-height:36px; padding:7px 11px;
  border:1px solid var(--line-2); border-radius:9px; background:var(--surface);
  color:var(--accent); font-size:13px; font-weight:600; text-decoration:none;
  overflow-wrap:anywhere;
}
.msg .linkbtn:hover{border-color:var(--accent)}
.msg .linkbtn:focus-visible{outline:2px solid var(--accent); outline-offset:1px}
.msg .evento{margin-top:6px; padding:6px 10px; border-radius:8px; background:var(--surface-2);
             color:var(--ink-2); font-size:12.5px}

/* El visor de adjuntos. Ocupa la pantalla entera y el fondo es opaco a proposito: lo
   que se esta mirando suele ser un estudio o una orden, y el panel de atras compitiendo
   por la atencion no ayuda a leerlo. */
.visor{
  position:fixed; inset:0; z-index:80; background:rgba(9,14,20,.86);
  display:flex; flex-direction:column;
}
.vhead{
  display:flex; align-items:center; gap:10px; padding:10px 14px; color:#fff;
  background:rgba(0,0,0,.35); flex:none;
}
.vnom{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
      font-size:13px; font-weight:600}
.vbtn{
  flex:none; border:1px solid rgba(255,255,255,.35); background:none; color:#fff;
  font:inherit; font-size:12.5px; padding:5px 11px; border-radius:8px; cursor:pointer;
  text-decoration:none;
}
.vbtn:hover{background:rgba(255,255,255,.14)}
.vbtn svg{width:17px; height:17px; display:block}
.vcuerpo{flex:1; min-height:0; display:flex; align-items:center; justify-content:center; padding:14px}
.vcuerpo img{max-width:100%; max-height:100%; object-fit:contain; border-radius:6px}
/* El PDF necesita alto propio: dentro de un flex, un iframe sin medidas colapsa. */
.vcuerpo iframe{width:100%; height:100%; border:none; border-radius:6px; background:#fff}

/* "Escribiendo" en el renglon de la bandeja, donde va la vista previa: es el mismo
   lugar donde despues aparece lo que la persona termino de escribir. */
.rprev.tecleando{color:var(--accent); font-style:italic}

/* El corte de "mensajes no leidos", como en cualquier chat: una linea con la etiqueta
   en el medio, arriba del primero que el operador no vio. */
.nuevos{
  display:flex; align-items:center; gap:9px; margin:6px 2px 2px; color:var(--accent);
  font-size:11.5px; font-weight:600;
}
.nuevos:before, .nuevos:after{content:""; flex:1; height:1px; background:var(--accent); opacity:.35}

/* La lupa de adentro de la conversacion. Es una barra que EMPUJA el hilo en vez de
   flotar encima: tapar mensajes justo cuando se los esta buscando no tiene sentido. */
.buscahilo{
  display:flex; align-items:center; gap:6px; padding:7px 10px; flex:none;
  border-bottom:1px solid var(--line); background:var(--surface-2);
}
.buscahilo input{
  flex:1; min-width:0; padding:6px 10px; border:1px solid var(--line-2); border-radius:7px;
  background:var(--surface); color:var(--ink); font:inherit; font-size:13px; -webkit-appearance:none;
}
.buscahilo input:focus{outline:2px solid var(--accent); outline-offset:-1px}
.buscahilo .cuenta{font-size:12px; color:var(--ink-3); white-space:nowrap; min-width:52px; text-align:center}
.buscahilo button{
  border:1px solid var(--line-2); background:var(--surface); color:var(--ink-2);
  border-radius:7px; cursor:pointer; width:26px; height:26px; line-height:1; flex:none;
}
.buscahilo button:hover:not(:disabled){border-color:var(--accent); color:var(--accent)}
.buscahilo button:disabled{opacity:.4; cursor:default}

mark.hit{background:var(--warn-soft); color:inherit; border-radius:3px; padding:0 1px}
.rprev mark.hit{background:var(--accent-soft); color:var(--accent); font-weight:600}
mark.hit.foco{background:var(--accent); color:#fff}

/* ---------- buscador de operadores ---------- */
.picker{border:1px solid var(--line); border-radius:8px; max-height:190px; overflow-y:auto;
        background:var(--bg); margin-top:6px}
.pick{padding:8px 12px; font-size:13px; cursor:pointer; border-bottom:1px solid var(--line)}
.pick:last-child{border-bottom:none}
.pick:hover{background:var(--surface-2)}
.pick.on{background:var(--accent-soft); color:var(--accent); font-weight:600}
.pick.vacio{color:var(--ink-3); cursor:default; font-style:italic}
.pick.vacio:hover{background:none}

.rows{flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch}
.row{
  display:grid; grid-template-columns:34px 1fr auto; gap:10px; padding:11px 14px;
  border-bottom:1px solid var(--line); cursor:pointer; align-items:start;
}
.row:hover{background:var(--surface-2)}
.row.on{background:var(--accent-soft)}
/* GodMode (db/55, 21/9): las conversaciones internas de las que no es miembro, en dorado.
   Solo las ve quien tiene GodMode, asi que a nadie mas le aparece este color. */
.row.supervision{background:var(--oro-suave)}
.row.supervision:hover{background:var(--oro-suave); filter:brightness(.97)}
.row.supervision.on{outline:2px solid var(--oro); outline-offset:-2px}
.row.supervision .rname{color:var(--oro)}
.rname{font-weight:600; font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.rprev{color:var(--ink-3); font-size:12px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* Buscando, el renglon deja de ser una linea: se muestra el pedazo que coincidio y
   con una sola linea recortada lo resaltado suele quedar justo afuera, que es lo
   unico que habia que mostrar. Dos lineas alcanzan y el renglon no crece de mas. */
.row.hallada .rprev{
  white-space:normal; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  line-height:1.35;
}
.row.hallada .rdonde{display:block; margin:3px 0 0; width:-moz-fit-content; width:fit-content}
.rmeta{text-align:right; display:grid; gap:4px; justify-items:end}
.rtime{font-size:11px; color:var(--ink-3)}
/* Iniciales del responsable y numero rojo, uno al lado del otro. */
.rchips{display:flex; gap:4px; align-items:center}
.rtime.hot{color:var(--danger); font-weight:600}
.chip{
  font-size:10.5px; padding:1px 7px; border-radius:99px; border:1px solid var(--line-2);
  color:var(--ink-3); white-space:nowrap; display:inline-block;
}
.chip.acc{border-color:var(--accent); color:var(--accent); background:var(--accent-soft)}
.chip.warn{border-color:var(--warn); color:var(--warn); background:var(--warn-soft)}
.chip.dgr{border-color:var(--danger); color:var(--danger); background:var(--danger-soft)}
.chip.oro{border-color:var(--oro); color:var(--oro); background:var(--surface)}
.unread{background:var(--danger); color:#fff; border-color:var(--danger); font-weight:600}

/* ---------- conversacion ---------- */
/*  ⚠️ El encabezado se PARTE EN DOS FILAS cuando no entra, y esa es la unica razon del
    flex-wrap y del ancho minimo de abajo.

    Antes las acciones eran intocables (flex:none) y el bloque del nombre podia encogerse
    hasta cero, asi que en un telefono ganaban siempre los botones: quedaba el nombre en
    una letra y el subtitulo desbordado por debajo de "Transferir" y "Cerrar", pisandolos.
    Con un minimo de verdad para el nombre, el que no entra es el grupo de botones y baja
    a su propia fila.

    Se hace por desborde y no por @media a proposito: el encabezado del chat interno
    lleva un solo boton y no tiene por que gastar una fila, y aca arriba los botones
    cambian segun el estado de la conversacion. La regla se adapta sola a los dos. */
.chead{
  padding:10px 15px; border-bottom:1px solid var(--line); background:var(--surface-2);
  display:flex; flex-wrap:wrap; gap:10px; align-items:center; flex:none;
}
.chead .ident{flex:1; min-width:130px}
.chead .who{font-weight:600; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/*  El subtitulo se corta igual que el nombre. Sin esto envuelve en varias lineas y, en un
    bloque angosto, se sale de su caja en vez de crecer: el texto termina dibujado encima
    de los botones. */
.chead .sub{
  color:var(--ink-3); font-size:11.5px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.chead .acts{margin-left:auto; display:flex; gap:6px; flex:none}
.back{display:none}

.thread{flex:1; overflow-y:auto; padding:16px; background:var(--bg);
        display:flex; flex-direction:column; gap:8px; -webkit-overflow-scrolling:touch}
.msg{
  max-width:74%; padding:8px 12px; border-radius:13px; font-size:13.5px;
  border:1px solid var(--line); background:var(--surface); word-wrap:break-word;
  overflow-wrap:anywhere; animation:in .16s ease-out;
}
@keyframes in{from{opacity:0; transform:translateY(5px)} to{opacity:1; transform:none}}
@media (prefers-reduced-motion:reduce){.msg{animation:none}}
.msg .who{display:block; font-size:10.5px; color:var(--ink-3); margin-bottom:2px}
.msg .tm{font-size:10px; color:var(--ink-3); margin-left:8px}
/* El acuse de lo que escribio el operador: el paciente ve el suyo aparte, en su chat
   (db/42). Un tilde apagado mientras esta sin leer, dos en color cuando lo abrio — la
   diferencia se ve de un vistazo, sin tener que leer la etiqueta. */
.msg .seen{
  display:flex; align-items:center; justify-content:flex-end; gap:4px;
  font-size:10px; color:var(--ink-3); margin-top:4px;
}
.msg .seen .ck{height:13px; flex:none; fill:none; stroke:currentColor;
               stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round}
.msg .seen .one{width:9px}
.msg .seen .two{width:13px; display:none}
.msg .seen.read{color:var(--accent)}
.msg .seen.read .one{display:none}
.msg .seen.read .two{display:block}
/* Mientras viaja no hay tilde: no hay nada que confirmar todavia. */
.msg.sending .seen .ck, .msg.failed .seen{visibility:hidden}
.msg.them{align-self:flex-start; border-bottom-left-radius:4px}
.msg.mine{align-self:flex-end; background:var(--accent-soft); border-color:var(--accent);
          border-bottom-right-radius:4px}
.msg.mine.sending{opacity:.6}
.msg.mine.failed{border-color:var(--danger); background:var(--danger-soft)}
.msg.note{align-self:flex-end; background:var(--warn-soft); border-color:var(--warn);
          border-style:dashed}
.msg.note .who{color:var(--warn)}
.msg.bot{align-self:flex-start; background:var(--surface-2); border-style:dashed; opacity:.92}
/* Las lineas de sistema del chat interno («armo el grupo», «agrego a», «cerro el grupo»)
   en negrita (15/9, Martin). Las del hilo del paciente quedan como estaban. */
.msg.sys.int{font-weight:600}
.msg.sys{align-self:center; background:none; border:none; color:var(--ink-3); font-size:11.5px;
         text-align:center; max-width:90%}
.daysep{align-self:center; font-size:11px; color:var(--ink-3)}

/* «Escribiendo»: al pie del hilo, como una burbuja mas. Asi empuja la conversacion
   hacia arriba igual que el mensaje que esta por llegar, y la vista no salta. */
.typing{
  align-self:flex-start; display:flex; align-items:center; gap:4px;
  padding:10px 13px; border-radius:14px; border-bottom-left-radius:4px;
  border:1px solid var(--line); background:var(--surface); width:fit-content;
}
.typing i{
  width:6px; height:6px; border-radius:50%; background:var(--ink-3); display:block;
  animation:puntos 1.25s ease-in-out infinite;
}
.typing i:nth-child(2){animation-delay:.16s}
.typing i:nth-child(3){animation-delay:.32s}
@keyframes puntos{
  0%,60%,100%{opacity:.28; transform:translateY(0)}
  30%        {opacity:1;   transform:translateY(-3px)}
}
@media (prefers-reduced-motion:reduce){.typing i{animation:none; opacity:.6}}
.botcap{
  align-self:center; font-size:10.5px; color:var(--ink-3); letter-spacing:.06em;
  text-transform:uppercase; border-top:1px solid var(--line); width:100%;
  text-align:center; padding-top:8px;
}
.retry{color:var(--danger); text-decoration:underline; cursor:pointer; font-size:11px; margin-left:6px}

.quick{display:flex; gap:6px; padding:9px 15px 0; flex-wrap:wrap;
       background:var(--bg); flex:none; max-height:84px; overflow-y:auto}
.qc{
  font-size:11.5px; padding:3px 10px; border-radius:99px; border:1px solid var(--line-2);
  color:var(--ink-2); background:var(--surface); cursor:pointer;
}
.qc:hover{border-color:var(--accent); color:var(--accent)}
.composer{
  display:flex; gap:8px; align-items:flex-end; padding:11px 15px;
  border-top:1px solid var(--line); background:var(--surface); flex:none;
  padding-bottom:calc(11px + env(safe-area-inset-bottom));
}
.composer textarea{
  flex:1; resize:none; font-size:14px; line-height:1.4; padding:9px 12px; min-height:40px;
  max-height:130px; border:1px solid var(--line-2); border-radius:10px; background:var(--bg);
}
.composer textarea:focus{outline:2px solid var(--accent); outline-offset:-1px}
.composer.note textarea{background:var(--warn-soft); border-color:var(--warn)}

.side{padding:14px; display:flex; flex-direction:column; gap:14px; overflow-y:auto;
      background:var(--surface); border-left:1px solid var(--line); min-width:0}
.sidename{font-weight:600; font-size:14px}
/* Solo aparece cuando la ficha es un panel encima de todo — ver el bloque responsive.
   En pantalla ancha la ficha es una columna mas y no hay nada que cerrar. */
.side .cerrar{
  display:none; position:absolute; top:10px; right:10px; width:30px; height:30px;
  align-items:center; justify-content:center; border-radius:8px; border:1px solid var(--line-2);
  background:var(--surface-2); color:var(--ink-2); cursor:pointer; z-index:2;
}
.side .cerrar:hover{color:var(--ink); border-color:var(--accent)}
.side{position:relative}
.sublab{font-size:10.5px; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-3)}
.kv{display:grid; gap:5px; font-size:12px}
.kv div{display:flex; justify-content:space-between; gap:10px}
.kv span{color:var(--ink-3)}
.kv b{font-weight:500; text-align:right; word-break:break-all}

.empty{flex:1; display:grid; place-items:center; background:var(--bg); color:var(--ink-3);
       font-size:13px; padding:24px; text-align:center}

/* ---------- skeleton ---------- */
.skel{background:var(--surface-3); border-radius:5px; height:10px; animation:pulse 1.2s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1} 50%{opacity:.5}}
@media (prefers-reduced-motion:reduce){.skel{animation:none}}

/* ---------- avisos ---------- */
.toasts{position:fixed; left:50%; bottom:22px; transform:translateX(-50%); display:grid;
        gap:8px; z-index:60; width:max-content; max-width:92vw}
.toast{
  background:var(--surface); border:1px solid var(--line-2); border-left:3px solid var(--accent);
  border-radius:10px; padding:10px 14px; font-size:13px; box-shadow:var(--shadow);
  animation:up .2s ease-out;
}
.toast.err{border-left-color:var(--danger)}
@keyframes up{from{opacity:0; transform:translateY(8px)} to{opacity:1; transform:none}}

/* ---------- modal ---------- */
.veil{
  position:fixed; inset:0; background:rgba(8,12,18,.45); display:grid; place-items:center;
  z-index:70; padding:18px; animation:fade .15s ease-out;
}
@keyframes fade{from{opacity:0} to{opacity:1}}
.modal{
  width:100%; max-width:420px; background:var(--surface); border:1px solid var(--line-2);
  border-radius:14px; box-shadow:var(--shadow); overflow:hidden;
}
.mhead{padding:14px 17px; border-bottom:1px solid var(--line); font-weight:600; font-size:14px}
.mbody{padding:16px 17px; display:grid; gap:13px; font-size:13px}
.mbody textarea{
  min-height:80px; resize:vertical; padding:9px 12px; border:1px solid var(--line-2);
  border-radius:9px; background:var(--bg); font-size:13.5px;
}
.mfoot{padding:12px 17px; border-top:1px solid var(--line); display:flex; gap:8px;
       justify-content:flex-end; background:var(--surface-2); flex-wrap:wrap}
.menu{position:absolute; left:56px; bottom:56px; width:230px; z-index:65;
      background:var(--surface); border:1px solid var(--line-2); border-radius:11px;
      box-shadow:var(--shadow); overflow:hidden}
.menu .mt{padding:9px 13px; border-bottom:1px solid var(--line); font-size:10.5px;
          letter-spacing:.06em; text-transform:uppercase; color:var(--ink-3)}
.menu .mi{padding:9px 13px; font-size:13px; cursor:pointer; display:flex;
          justify-content:space-between; gap:10px; align-items:center}
.menu .mi:hover{background:var(--surface-2)}
.menu .mi.on{color:var(--accent); font-weight:600}

/* ---------- responsive ----------
   En pantalla angosta no hay tres columnas: hay una vista por vez. */

/* El boton de la ficha solo hace falta cuando la ficha no entra al costado (15/9, Martin).
   Con pantalla ancha esta siempre a la vista y el boton no hace nada. El corte es el mismo
   que la oculta abajo. */
@media (min-width:1101px){
  #btnFicha{display:none}
  /* Sin ficha que mostrar —chat interno, o ninguna conversacion de paciente abierta— la
     columna de la derecha no ocupa lugar: quedaba una franja en blanco al costado
     (16/9, Martin). */
  body.sin-ficha .app{grid-template-columns:56px 300px minmax(0,1fr)}
  body.sin-ficha .side{display:none}
}
@media (max-width:1100px){
  .app{grid-template-columns:56px 280px minmax(0,1fr)}
  .side{display:none}
  .side.show{display:flex; position:fixed; right:0; top:0; bottom:0; width:280px; z-index:50;
             box-shadow:var(--shadow)}
  /* Abierta como panel, la ficha tapa el encabezado del chat — y ahi vive el boton que
     la abrio. Sin una salida propia, quien la despliega queda encerrado. */
  .side.show .cerrar{display:inline-flex}
}
@media (max-width:760px){
  .app{grid-template-columns:1fr; grid-template-rows:1fr}
  .rail{
    position:fixed; bottom:0; left:0; right:0; top:auto; height:56px; z-index:40;
    flex-direction:row; justify-content:space-around; border-right:none;
    border-top:1px solid var(--line); padding:6px 8px;
    padding-bottom:calc(6px + env(safe-area-inset-bottom));
  }
  .rail .sp{display:none}
  .col{grid-column:1; grid-row:1}
  .col.lista{display:flex; padding-bottom:var(--barra-alto, 56px)}
  .col.chat{display:none}
  body.viendo .col.lista{display:none}
  /* La barra de abajo es fija y flota sobre la columna. Sin reservarle el alto, el
     campo para escribir queda debajo de los iconos y no se puede tocar. */
  body.viendo .col.chat{display:flex; padding-bottom:var(--barra-alto, calc(56px + env(safe-area-inset-bottom)))}
  .back{display:inline-flex}
  .side.show{width:100%}
  /* El area segura ya la reserva la columna: repetirla aca la contaria dos veces. */
  .composer{padding-bottom:11px}
  .msg{max-width:88%}
  .menu{left:8px; right:8px; bottom:66px; width:auto}
}

/* ---------- chat interno ----------
   Vive en las mismas columnas que la bandeja de pacientes y se turna con ella: son
   dos zonas, no dos filtros de lo mismo. */
.ihead{display:flex; gap:8px; padding:10px 12px; border-bottom:1px solid var(--line)}

/* La seccion «Archivados» del chat interno: un renglon plegable debajo de la bandeja. */
.isec{
  display:flex; align-items:center; gap:8px; width:100%; padding:10px 14px;
  background:var(--surface-2); border:none; border-bottom:1px solid var(--line);
  color:var(--ink-2); font:inherit; font-size:12px; font-weight:600; text-align:left; cursor:pointer;
  letter-spacing:.02em;
}
.isec:hover{color:var(--ink)}
.isec:focus-visible{outline:2px solid var(--accent); outline-offset:-2px}
.isec svg{width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:1.8;
          transition:transform .15s}
.isec.open svg{transform:rotate(90deg)}
.isec .t{flex:1}
.isec .n{color:var(--ink-3); font-weight:500}
@media (prefers-reduced-motion: reduce){ .isec svg{transition:none} }

/* Grupo cerrado: en lugar de la caja de escribir, el por que. */
.icerrada{
  padding:12px 16px; border-top:1px solid var(--line); background:var(--surface-2);
  color:var(--ink-3); font-size:12.5px; text-align:center;
}
.ihead input{
  flex:1; min-width:0; padding:8px 11px; border:1px solid var(--line-2); border-radius:9px;
  background:var(--bg); font-size:13px; color:var(--ink);
}
.ihead .btn{padding:8px 10px}

/* Una fila de grupo se distingue de un 1-a-1 sin leer: la inicial es cuadrada. */
.row .av.grp{border-radius:7px}

/* ---------- adjuntos ---------- */
.adjunto{
  display:flex; align-items:center; gap:9px; margin:0 14px 8px; padding:8px 11px;
  border:1px solid var(--line-2); border-radius:10px; background:var(--surface-2); font-size:12.5px;
}
.adjunto svg{width:16px; height:16px; flex:none; color:var(--ink-3)}
.adjunto .nom{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.adjunto .quitar{cursor:pointer; color:var(--ink-3); font-size:16px; line-height:1; padding:0 3px}
.adjunto .quitar:hover{color:var(--danger)}

/* El adjunto dentro de la burbuja: se ve que es un archivo antes de leer el nombre. */
.msg .file{
  display:flex; align-items:center; gap:8px; margin-top:5px; padding:7px 10px;
  border:1px solid var(--line-2); border-radius:9px; background:var(--surface);
  color:inherit; text-decoration:none; font-size:12.5px;
}
.msg .file:hover{border-color:var(--accent)}
.msg .file svg{width:16px; height:16px; flex:none; color:var(--accent)}
.msg .file .nom{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.msg .file .peso{flex:none; font-size:11px; color:var(--ink-3)}

/* Una imagen se ve, no se anuncia. El alto maximo evita que una foto vertical de
   telefono ocupe el hilo entero. */
.msg .foto{display:block; margin-top:5px; border-radius:9px; overflow:hidden; line-height:0}
.msg .foto img{
  display:block; max-width:100%; max-height:280px; width:auto; height:auto;
  background:var(--surface-2);
}

/* ---------- miembros y vistos ---------- */
.mpick{display:grid; gap:8px}
/* El nombre del grupo tambien: es type=text, y sin esta regla caia en el fondo blanco del
   navegador con la letra clara del tema oscuro — ilegible. */
.mpick input[type=search],
.mpick input[type=text]{
  padding:9px 12px; border:1px solid var(--line-2); border-radius:9px; background:var(--bg);
  font-size:13.5px; color:var(--ink);
}
.mpick .lista2{max-height:210px; overflow:auto; border:1px solid var(--line); border-radius:9px}
.mpick .op{display:flex; align-items:center; gap:10px; padding:7px 11px; cursor:pointer; font-size:13px}
.mpick .op:hover{background:var(--surface-2)}
.mpick .op input{margin:0}
.mpick .cuenta{font-size:11.5px; color:var(--ink-3)}
.mchips{display:flex; flex-wrap:wrap; gap:6px}
.mchip{
  display:inline-flex; align-items:center; gap:6px; padding:4px 9px; font-size:12px;
  border:1px solid var(--line-2); border-radius:999px; background:var(--surface-2);
}
.mchip b{cursor:pointer; color:var(--ink-3); font-weight:400}
.mchip b:hover{color:var(--danger)}

.miembros{display:grid; gap:2px; max-height:300px; overflow:auto}
.miembro{display:flex; align-items:center; gap:9px; padding:8px 4px; font-size:13px}
.miembro .nm{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.miembro .tag{font-size:10.5px; letter-spacing:.05em; text-transform:uppercase; color:var(--accent)}
.miembro .tag.out{color:var(--ink-3)}
.miembro .btn{padding:4px 9px; font-size:11.5px}

.vistos{display:grid; gap:1px; font-size:13px}
.vistos .v{display:flex; justify-content:space-between; gap:12px; padding:7px 2px}
.vistos .v span:last-child{color:var(--ink-3); font-size:11.5px; white-space:nowrap}
.vistos .v.no span:last-child{color:var(--warn)}
.msg .seen.link{cursor:pointer}
.msg .seen.link:hover{text-decoration:underline}

/* ---------- filtro de sucursal ----------
   Un desplegable con buscador, no un <select>: con cuarenta sucursales un select
   nativo obliga a scrollear a ciegas. Cruza con las pestañas de estado. */
.sucbar{position:relative; padding:0 10px 9px; flex:none}
.sucsel{
  width:100%; display:flex; align-items:center; gap:8px; justify-content:space-between;
  padding:8px 11px; border:1px solid var(--line-2); border-radius:8px;
  background:var(--bg); color:var(--ink-2); font-size:12.5px; cursor:pointer; min-height:38px;
}
.sucsel:hover{border-color:var(--accent); color:var(--accent)}
.sucsel span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.sucsel svg{width:15px; height:15px; flex:none}
.sucsel.filtrando{border-color:var(--accent); color:var(--accent); font-weight:600}

.sucpop{
  position:absolute; left:10px; right:10px; top:calc(100% - 4px); z-index:60;
  background:var(--surface); border:1px solid var(--line-2); border-radius:10px;
  box-shadow:var(--shadow); overflow:hidden;
}
.sucpop input{
  width:100%; border:none; border-bottom:1px solid var(--line); padding:10px 12px;
  background:var(--surface); font-size:13px; color:var(--ink);
}
.sucpop input:focus{outline:2px solid var(--accent); outline-offset:-2px}
.suclista{max-height:230px; overflow-y:auto}
.sucit{padding:9px 12px; font-size:13px; cursor:pointer; display:flex;
       justify-content:space-between; gap:10px; align-items:center}
.sucit:hover{background:var(--surface-2)}
.sucit.on{color:var(--accent); font-weight:600; background:var(--accent-soft)}
.sucit.sep{border-top:1px solid var(--line)}
.sucit.vacio{color:var(--ink-3); font-style:italic; cursor:default}
.sucit.vacio:hover{background:none}

/* La sucursal en la fila de la bandeja: dato de contexto, no titulo. */
.rsuc{font-size:10.5px; color:var(--ink-3); white-space:nowrap; overflow:hidden;
      text-overflow:ellipsis}

/* ---------- interruptores ----------
   Convencion del proyecto: lo que se prende y se apaga va con INTERRUPTOR, no con
   casilla. Un interruptor dice el estado de lejos —esta prendido o no— y una casilla
   obliga a mirar si hay un tilde adentro de un cuadradito de 13 px.

   Se hace restilando el propio <input type="checkbox"> en vez de inventar un
   componente: el marcado no cambia, el teclado y los lectores de pantalla siguen
   funcionando solos, y toda casilla dentro de un .chk queda convertida sin tocarla
   —las que ya estan y las que se agreguen—.

   ⚠️ Y DESDE EL 11/9 VA TAMBIEN EN EL SELECTOR DE OPERADORES DEL CHAT INTERNO, que
   es una seleccion y no un ajuste. El comentario de aca decia lo contrario —que una
   casilla de elegir filas tiene que seguir siendo casilla— y Martin decidio que no:
   el principio del proyecto es que TODA casilla sea un interruptor, sin excepciones
   que despues hay que recordar. Queda dicho para que nadie lo "corrija" de vuelta. */
.chk{display:flex; gap:10px; align-items:center; font-size:13.5px; color:var(--ink-2);
     cursor:pointer; user-select:none}

.chk input[type="checkbox"],
.mpick .op input[type="checkbox"]{
  appearance:none; -webkit-appearance:none; margin:0; flex:none; cursor:pointer;
  width:36px; height:21px; min-height:0; border-radius:999px;
  background:var(--surface-3); border:1px solid var(--line-2);
  position:relative; transition:background-color .16s ease, border-color .16s ease;
}
.chk input[type="checkbox"]::after,
.mpick .op input[type="checkbox"]::after{
  content:""; position:absolute; top:2px; left:2px; width:15px; height:15px;
  border-radius:50%; background:var(--surface);
  box-shadow:0 1px 2px rgba(16,24,34,.35);
  transition:transform .16s cubic-bezier(.2,.8,.3,1);
}
.chk input[type="checkbox"]:checked,
.mpick .op input[type="checkbox"]:checked{background:var(--accent); border-color:var(--accent)}
.chk input[type="checkbox"]:checked::after,
.mpick .op input[type="checkbox"]:checked::after{transform:translateX(15px)}
.chk input[type="checkbox"]:focus-visible,
.mpick .op input[type="checkbox"]:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.chk input[type="checkbox"]:disabled{opacity:.5; cursor:default}
.chk input[type="checkbox"]:disabled + *,
.chk:has(input:disabled){cursor:default}

@media (prefers-reduced-motion:reduce){
  .chk input[type="checkbox"],
  .chk input[type="checkbox"]::after{transition:none}
}

/* ---------- etiquetas ----------
   Diez colores fijos, y la etiqueta guarda el INDICE (0..9), no el color.

   Es lo que impide que una etiqueta quede ilegible: cada indice tiene su par de
   valores para tema claro y para tema oscuro, los dos elegidos para que el texto
   contraste contra su propio fondo. Con un color libre elegido por el cliente eso
   no se puede garantizar — el amarillo que se lee sobre blanco desaparece sobre
   negro, y al reves.

   Y como el dato es un indice, corregir un tono es tocar estas lineas: quedan
   corregidas todas las etiquetas de todos los clientes sin migrar una fila. */
:root{
  --etq0-bg:#fbe3e6; --etq0-fg:#9b2233;   /* rojo    */
  --etq1-bg:#fbe7d9; --etq1-fg:#9a4a12;   /* naranja */
  --etq2-bg:#faf0cf; --etq2-fg:#7d5c07;   /* ambar   */
  --etq3-bg:#dff0e2; --etq3-fg:#1d6b39;   /* verde   */
  --etq4-bg:#d6efec; --etq4-fg:#12645d;   /* teal    */
  --etq5-bg:#d9eef7; --etq5-fg:#0f5f7d;   /* celeste */
  --etq6-bg:#dde5f8; --etq6-fg:#27458f;   /* azul    */
  --etq7-bg:#e6e0f7; --etq7-fg:#4b348c;   /* violeta */
  --etq8-bg:#fadeeb; --etq8-fg:#93245c;   /* rosa    */
  --etq9-bg:#e4e8ed; --etq9-fg:#465361;   /* gris    */
}
html[data-theme="dark"]{
  --etq0-bg:#40191f; --etq0-fg:#f7a8b3;
  --etq1-bg:#3d2413; --etq1-fg:#f0b184;
  --etq2-bg:#3a3110; --etq2-fg:#e5cb72;
  --etq3-bg:#153021; --etq3-fg:#7fd6a0;
  --etq4-bg:#0f2f2d; --etq4-fg:#6fd3c9;
  --etq5-bg:#11303c; --etq5-fg:#78cbe8;
  --etq6-bg:#1b2749; --etq6-fg:#9db4f2;
  --etq7-bg:#281f47; --etq7-fg:#b7a5f0;
  --etq8-bg:#3b1a2c; --etq8-fg:#eda2c6;
  --etq9-bg:#252c35; --etq9-fg:#aab6c4;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --etq0-bg:#40191f; --etq0-fg:#f7a8b3;
    --etq1-bg:#3d2413; --etq1-fg:#f0b184;
    --etq2-bg:#3a3110; --etq2-fg:#e5cb72;
    --etq3-bg:#153021; --etq3-fg:#7fd6a0;
    --etq4-bg:#0f2f2d; --etq4-fg:#6fd3c9;
    --etq5-bg:#11303c; --etq5-fg:#78cbe8;
    --etq6-bg:#1b2749; --etq6-fg:#9db4f2;
    --etq7-bg:#281f47; --etq7-fg:#b7a5f0;
    --etq8-bg:#3b1a2c; --etq8-fg:#eda2c6;
    --etq9-bg:#252c35; --etq9-fg:#aab6c4;
  }
}

.etq{
  display:inline-flex; align-items:center; gap:5px; padding:2px 9px; border-radius:999px;
  font-size:11.5px; font-weight:600; line-height:1.5; white-space:nowrap; max-width:100%;
  overflow:hidden; text-overflow:ellipsis;
}
.etq.c0{background:var(--etq0-bg); color:var(--etq0-fg)}
.etq.c1{background:var(--etq1-bg); color:var(--etq1-fg)}
.etq.c2{background:var(--etq2-bg); color:var(--etq2-fg)}
.etq.c3{background:var(--etq3-bg); color:var(--etq3-fg)}
.etq.c4{background:var(--etq4-bg); color:var(--etq4-fg)}
.etq.c5{background:var(--etq5-bg); color:var(--etq5-fg)}
.etq.c6{background:var(--etq6-bg); color:var(--etq6-fg)}
.etq.c7{background:var(--etq7-bg); color:var(--etq7-fg)}
.etq.c8{background:var(--etq8-bg); color:var(--etq8-fg)}
.etq.c9{background:var(--etq9-bg); color:var(--etq9-fg)}

/* Apagada: la que se aplica con un clic y la que se saca con otro. El estado se lee
   por relleno y no solo por opacidad, que en una lista de diez se vuelve adivinanza. */
.etq.off{background:transparent; box-shadow:inset 0 0 0 1px currentColor; opacity:.75}

.etqs{display:flex; gap:5px; flex-wrap:wrap; align-items:center}
button.etq{border:0; cursor:pointer; font-family:inherit}

/* El selector de color del ABM: los diez, y el elegido con un anillo. */
.paleta{display:flex; gap:7px; flex-wrap:wrap}
.paleta button{
  width:28px; height:28px; border-radius:50%; border:1px solid rgba(0,0,0,.12);
  cursor:pointer; padding:0;
}
.paleta button[aria-pressed="true"]{outline:2px solid var(--accent); outline-offset:2px}
.paleta button.c0{background:var(--etq0-fg)}
.paleta button.c1{background:var(--etq1-fg)}
.paleta button.c2{background:var(--etq2-fg)}
.paleta button.c3{background:var(--etq3-fg)}
.paleta button.c4{background:var(--etq4-fg)}
.paleta button.c5{background:var(--etq5-fg)}
.paleta button.c6{background:var(--etq6-fg)}
.paleta button.c7{background:var(--etq7-fg)}
.paleta button.c8{background:var(--etq8-fg)}
.paleta button.c9{background:var(--etq9-fg)}
/* La barra del filtro por etiqueta, arriba de la lista. Misma caja que la de
   sucursal para que las dos se lean como el mismo control. */
/* El pie del desplegable de etiquetas: la salida rapida cuando hay varias marcadas
   y destildarlas de a una seria tedioso. */
.etqpie{padding:0 10px 10px; display:flex}
.etqpie .btn{width:100%}
