/* Tema oscuro de SurfAbogados.
 *
 * Los componentes no llevan ni un color literal: todo pasa por variables
 * semanticas. El tema claro seria otro bloque de variables, sin tocar nada mas.
 *
 * Cuatro decisiones que en una aplicacion que se mira ocho horas no son estetica:
 *   - ni negro puro ni blanco puro, que juntos producen halo y cansan al leer
 *     texto denso;
 *   - contraste AA (4,5:1) en todo el texto normal;
 *   - foco siempre visible, porque esta gente viene de manejar la aplicacion
 *     anterior a teclas F3..F17 y va a seguir tabulando;
 *   - jerarquia por elevacion y no por lineas, que en oscuro se emborronan.
 */

:root,
:root[data-tema="oscuro"] {
  --fondo: #14161a;
  --fondo-elevado: #1c1f25;
  --fondo-elevado-2: #23272e;
  --fondo-hover: #2a2f37;

  --texto: #e7e9ee;        /* blanco roto: 13.8:1 sobre el fondo */
  --texto-tenue: #a2a9b6;  /* 6.5:1, sigue cumpliendo AA */
  --texto-debil: #7b8291;  /* solo para texto de apoyo grande */

  --borde: #313742;
  --borde-fuerte: #434b59;

  --acento: #6ea8fe;
  --acento-fuerte: #8fc0ff;
  --acento-tenue: #1d3252;
  --sobre-acento: #0b1220;

  --exito: #5dd39e;
  --aviso: #e8c468;
  --peligro: #f3757a;
  --peligro-tenue: #3a1f24;
  --texto-peligro: #ffd9db;  /* sobre --peligro-tenue */

  /* Escala de espaciado: estos cinco valores y ninguno mas.
   *
   * Todo margen, relleno y hueco de rejilla sale de aqui. Antes habia
   * veintitantas medidas distintas —0.35rem, 0.45rem, 0.6rem, 0.7rem, 0.9rem…—
   * que nadie eligio: se fueron poniendo a ojo y a ojo se parecen sin llegar a
   * ser iguales, que es justo lo que hace que una pantalla densa se lea
   * desordenada. Con cinco pasos la distancia entre dos cosas significa algo:
   *   4  dentro de un control (icono y su texto, casilla y su rotulo)
   *   8  entre controles hermanos de una misma fila
   *   16 entre filas o bloques de un mismo panel
   *   24 entre paneles
   *   32 hueco grande, para lo que se mira aparte
   * Si algo pide un valor intermedio, casi siempre es que pertenece a otro
   * escalon. Van en px y no en rem porque son distancias, no texto: no deben
   * crecer al subir el cuerpo de letra.
   */
  --esp-4: 4px;
  --esp-8: 8px;
  --esp-16: 16px;
  --esp-24: 24px;
  --esp-32: 32px;

  --radio: 8px;
  --sombra: 0 1px 2px rgb(0 0 0 / 0.4), 0 4px 12px rgb(0 0 0 / 0.25);
  --fuente: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --fuente-mono: ui-monospace, "Cascadia Code", Consolas, monospace;
}

*,
*::before,
*::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--fondo);
  color: var(--texto);
  font-family: var(--fuente);
  font-size: 15px;
  line-height: 1.5;
}

a { color: var(--acento); text-decoration: none; }
a:hover { color: var(--acento-fuerte); text-decoration: underline; }

/* Foco: nunca se quita, y con contraste propio para que se vea sobre
 * cualquiera de las superficies. El grosor y la separacion del trazo son del
 * dibujo del borde, no de la escala de espaciado. */
:focus-visible {
  outline: 2px solid var(--acento-fuerte);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --- estructura ---------------------------------------------------------
 * La columna izquierda y, a su derecha, la del contenido.
 *
 * `flex` y no una rejilla de dos pistas: en las pantallas sin sesion no se
 * pinta el `<aside>`, y asi la columna de contenido se queda con todo el ancho
 * sin una regla que lo diga. Con `grid-template-columns` la unica hija caeria
 * en la primera pista, o sea con el ancho de la lateral.
 */

.armazon { display: flex; align-items: flex-start; min-height: 100vh; }

/* La lateral se queda quieta y desplaza por dentro: el menu tiene once
 * entradas y ademas aloja el panel del asistente, asi que es lo bastante alta
 * como para que perderla al bajar fuera una molestia. El ancho es un dibujo,
 * no un paso de la escala de espaciado —como el `width` del panel derecho del
 * asistente—, y sale de que el panel de contexto quepa sin apreturas. */
.lateral {
  flex: 0 0 19rem;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--esp-16);
  padding: var(--esp-16);
  background: var(--fondo-elevado);
  border-right: 1px solid var(--borde);
}

/* `min-width: 0` no es adorno: sin el, una tabla ancha estira la columna y
 * empuja la lateral fuera de la pantalla en vez de desplazar dentro de si. */
.columna { flex: 1; min-width: 0; }

/* El nombre de la aplicacion y el del despacho, anclados arriba de la columna.
 * La lateral es la que se queda quieta y desplaza por dentro; con la marca
 * `sticky` el menu y lo que cuelga debajo desfilan bajo ella y el rotulo no se
 * va con ellos. Es el simetrico del `.lateral-pie` del fondo: mismos margenes
 * negativos para alcanzar los bordes y un fondo opaco que tapa lo que pasa por
 * debajo. Sin borde inferior: el hueco que deja el relleno ya separa. */
.lateral-marca {
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
  position: sticky;
  top: calc(var(--esp-16) * -1);
  margin: calc(var(--esp-16) * -1) calc(var(--esp-16) * -1) 0;
  padding: var(--esp-16);
  background: var(--fondo-elevado);
}

.lateral .marca {
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--texto);
}
.lateral .marca:hover { text-decoration: none; }

/* El despacho, debajo del nombre: aqui es el subtitulo de la marca, no una
 * pastilla mas de una barra de iconos. */
.lateral .despacho { color: var(--texto-tenue); font-size: 0.8rem; }

/* El plegable nace `open` y en ancho no se ve que sea un plegable: el
 * disparador se esconde y lo que queda es el `<nav>`. Quien lo cierra en
 * estrecho es `lateral.js`. */
.lateral-plegable > summary {
  display: none;
  padding: var(--esp-4) var(--esp-8);
  border-radius: var(--radio);
  cursor: pointer;
  color: var(--texto-tenue);
}
.lateral-plegable > summary:hover { background: var(--fondo-hover); color: var(--texto); }

.lateral nav { display: flex; flex-direction: column; gap: var(--esp-4); }

.lateral nav a {
  padding: var(--esp-4) var(--esp-8);
  border-radius: var(--radio);
  color: var(--texto-tenue);
}
.lateral nav a:hover { background: var(--fondo-hover); color: var(--texto); text-decoration: none; }
.lateral nav a.activo { background: var(--acento-tenue); color: var(--acento-fuerte); }

/* El usuario, anclado al fondo de la columna. El `auto` de arriba lo baja
 * cuando el menu no llena la pantalla; `sticky` es lo que lo mantiene a la
 * vista cuando si la llena —la llena el panel del asistente—, que antes se
 * quedaba debajo del pliegue.
 *
 * Los margenes negativos anulan el relleno de `.lateral` para que la franja
 * llegue a sus tres bordes: sin ellos el contenido, al desplazarse, asomaria
 * por los lados y por debajo del fondo opaco. Y como `sticky` fija la caja de
 * margen, el `bottom` negativo compensa el margen de abajo; con `bottom: 0` la
 * franja se pararia 16px por encima del borde. */
.lateral-pie {
  margin: auto calc(var(--esp-16) * -1) calc(var(--esp-16) * -1);
  position: sticky;
  bottom: calc(var(--esp-16) * -1);
  padding: var(--esp-8) var(--esp-16);
  background: var(--fondo-elevado);
  border-top: 1px solid var(--borde);
}
.lateral-pie .menu-acciones { display: flex; }

/* El disparador no lleva `.boton`: aqui no es un boton dentro de una barra,
 * es la fila entera, y una caja con borde alrededor del nombre competia con
 * la del menu de encima. Se realza al pasar por encima, como las entradas del
 * menu, que es lo que dice que se pulsa.
 *
 * `.menu-acciones` va en el selector para ganarle a `.menu-acciones summary`,
 * que centra su contenido y esta mas abajo en el fichero: alli el disparador
 * es un cuadrado con un icono dentro, y aqui es una fila cuyo rotulo empieza
 * a la izquierda, en la misma vertical que las entradas del menu. */
.lateral-pie .menu-acciones summary {
  flex: 1;
  gap: var(--esp-8);
  justify-content: flex-start;
  padding: var(--esp-8);
  border-radius: var(--radio);
}
.lateral-pie .menu-acciones summary:hover { background: var(--fondo-hover); }

/* El nombre deja de ser tenue: aqui es el rotulo de la fila y no una etiqueta
 * de apoyo, y el circulo de al lado ya pone el contraste. */
.lateral-pie .quien { color: var(--texto); }

/* La inicial en su circulo. El tamano es una medida de dibujo, como el ancho
 * de la lateral, y no un paso de la escala de espaciado. */
.lateral-pie .inicial {
  flex: none;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--acento-tenue);
  color: var(--acento-fuerte);
  font-size: 0.8rem;
  font-weight: 600;
}

/* Un desplegable que se abre hacia arriba, para el submenu del fondo de la
 * lateral: es el `.menu-acciones` de siempre con el panel al otro lado. */
.menu-acciones.hacia-arriba > .menu-acciones-lista {
  top: auto;
  bottom: calc(100% + var(--esp-8));
  right: auto;
  left: 0;
}

/* La fila de arriba: solo la campanita, y solo sobre el contenido. Va a la
 * derecha porque a la izquierda ya no hay nada que anunciar —el nombre, el
 * despacho y la cuenta estan en la lateral—. */
.barra-superior {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--esp-8);
  padding: var(--esp-8) var(--esp-24);
  border-bottom: 1px solid var(--borde);
}

main { padding: var(--esp-24); max-width: 1440px; margin: 0 auto; }

/* En estrecho la lateral deja de ser una columna y pasa a ser la primera fila.
 * El menu se pliega —`lateral.js` cierra el `<details>` y aqui aparece su
 * disparador—, pero lo que la pantalla haya colgado debajo sigue a la vista:
 * esta fuera del plegable a proposito. El corte es el mismo que usa el
 * asistente para juntar sus columnas. */
@media (max-width: 60rem) {
  /* `align-items` vuelve a `stretch`: en columna el eje transversal es el
   * horizontal, y con `flex-start` la lateral se encogia al ancho de su texto
   * en vez de ocupar la fila entera. */
  .armazon { flex-direction: column; align-items: stretch; }
  .lateral {
    flex: none;
    width: auto;
    position: static;
    height: auto;
    overflow: visible;
    border-right: none;
    border-bottom: 1px solid var(--borde);
  }
  /* `list-item` y no `block`: lo que devuelve el triangulo, que es lo unico
   * que dice que «Menú» se abre. */
  .lateral-plegable > summary { display: list-item; }
  /* La marca deja de anclarse: aqui la lateral es la primera fila y no hay
   * ventana que desplazar por dentro. Vuelve al flujo como el pie; el margen
   * negativo de arriba se quita y los de los lados se quedan para que siga
   * llegando a los bordes. */
  .lateral-marca {
    position: static;
    margin: 0 calc(var(--esp-16) * -1) 0;
  }
  /* Ya no hay fondo de columna que alcanzar ni desplazamiento del que
   * escaparse: el pie vuelve al flujo. Los margenes negativos de los lados se
   * quedan, que la franja sigue llegando a los bordes. */
  .lateral-pie {
    position: static;
    margin: 0 calc(var(--esp-16) * -1) calc(var(--esp-16) * -1);
  }
  /* Y su submenu deja de abrirse hacia arriba: aqui la lateral es la primera
   * fila y encima no queda ventana, asi que el panel se salia de la pantalla. */
  .menu-acciones.hacia-arriba > .menu-acciones-lista {
    top: calc(100% + var(--esp-8));
    bottom: auto;
  }
}

h1 { font-size: 1.35rem; margin: 0 0 var(--esp-16); font-weight: 600; }
h2 { font-size: 1.1rem; margin: var(--esp-24) 0 var(--esp-8); font-weight: 600; }

/* El subtitulo pertenece al titulo: sube contra el y deja el hueco de panel
 * debajo, no dos huecos iguales que lo dejarian suelto entre los dos. */
.subtitulo { color: var(--texto-tenue); margin: calc(var(--esp-8) * -1) 0 var(--esp-24); }

/* --- tarjetas --- */

.tarjeta {
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: var(--esp-16);
  box-shadow: var(--sombra);
}

.rejilla-tarjetas {
  display: grid;
  gap: var(--esp-16);
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}

/* --- tablas: elevacion y resalte de fila, sin franjas alternas --- */

.tabla-envoltorio {
  overflow-x: auto;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--fondo-elevado);
}

table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }

th {
  text-align: left;
  padding: var(--esp-8) var(--esp-16);
  background: var(--fondo-elevado-2);
  color: var(--texto-tenue);
  font-weight: 600;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--borde);
  white-space: nowrap;
}

/* Cabecera que ordena. La llevan la relación de personas (`usuario/partes.html`)
 * y la de facturas (`usuario/facturas.html`); las otras dos tablas de la misma
 * macro de personas son lupas y se abren para elegir a alguien, no para leer la
 * agenda por columnas.
 *
 * El rótulo **no se pinta de enlace**: sigue siendo la cabecera —mismo color y
 * mismas versalitas que las columnas que no ordenan— y lo que dice que se puede
 * pulsar es la flecha, más el subrayado y el realce al pasar por encima. En azul
 * de enlace, siete cabeceras seguidas se leen como una fila de botones. */
th > .ordenar {
  display: inline-flex;
  align-items: baseline;
  gap: var(--esp-4);
  color: inherit;
}
th > .ordenar:hover { color: var(--texto); }
th > .ordenar.activa { color: var(--texto); }

/* La flecha ocupa su sitio esté o no ordenando por esa columna —y con el mismo
 * ancho las tres, que no miden igual—: si apareciera al pulsar, la cabecera
 * entera daría un salto de columna cada vez. */
th > .ordenar .flecha {
  display: inline-block;
  width: 0.8em;
  text-align: center;
  font-size: 0.9em;
  opacity: 0.4;
}
th > .ordenar:hover .flecha { opacity: 0.8; }
th > .ordenar.activa .flecha { opacity: 1; color: var(--acento-fuerte); }

td { padding: var(--esp-8) var(--esp-16); border-bottom: 1px solid var(--borde); }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--fondo-hover); }

.vacio { padding: var(--esp-32); text-align: center; color: var(--texto-tenue); }

/* Para el lector de pantalla y para nadie mas. Se usaba en el asistente sin
 * estar declarada, o sea que el rotulo que se queria esconder salia en
 * pantalla. `clip-path` y no `display:none`: escondido del todo no lo lee
 * nadie, que es justo lo contrario de lo que se busca. */
.sr-solo {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- formularios --- */

form.pila { display: flex; flex-direction: column; gap: var(--esp-16); }

label { display: block; font-size: 0.85rem; color: var(--texto-tenue); margin-bottom: var(--esp-4); }

input[type="text"],
input[type="password"],
input[type="email"],
input[type="search"],
input[type="number"],
input[type="date"],
select,
textarea {
  width: 100%;
  padding: var(--esp-8);
  background: var(--fondo);
  color: var(--texto);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  font: inherit;
}

input::placeholder, textarea::placeholder { color: var(--texto-debil); }

input:focus, select:focus, textarea:focus {
  border-color: var(--acento);
  outline: 2px solid var(--acento-fuerte);
  outline-offset: 1px;
}

input:disabled, select:disabled {
  background: var(--fondo-elevado-2);
  color: var(--texto-debil);
  cursor: not-allowed;
}

fieldset { border: 1px solid var(--borde); border-radius: var(--radio); padding: var(--esp-16); }
legend { color: var(--texto-tenue); font-size: 0.85rem; padding: 0 var(--esp-8); }

.rejilla-campos {
  display: grid;
  gap: var(--esp-16);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

/* --- pestanas ---------------------------------------------------------
 * Los botones modales de la aplicacion anterior son aqui pestanas de la misma
 * pantalla, y solo para lo que es una coleccion aparte: los datos del
 * expediente se ven enteros sin cambiar de pestaña.
 */

.pestanas {
  display: flex;
  align-items: stretch;
  gap: var(--esp-4);
  margin-bottom: var(--esp-16);
  border-bottom: 1px solid var(--borde);
  /* Son mas pestañas de las que caben en una pantalla estrecha; la barra
   * scrollea en vez de partirse en dos filas. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  scrollbar-color: var(--borde-fuerte) transparent;
}

.pestanas a {
  display: inline-flex;
  align-items: center;
  gap: var(--esp-4);
  /* El -1px monta la pestaña sobre la linea de la barra; es el grosor del
   * borde, no un margen. */
  margin: 0 0 -1px;
  padding: var(--esp-8) var(--esp-16);
  border-bottom: 2px solid transparent;
  color: var(--texto-tenue);
  font-size: 0.9rem;
  white-space: nowrap;
}

.pestanas a:hover {
  background: var(--fondo-hover);
  color: var(--texto);
  text-decoration: none;
}

.pestanas a.activo { color: var(--acento-fuerte); border-bottom-color: var(--acento); }

/* --- ficha densa ------------------------------------------------------
 * Esta gente viene de una pantalla de escritorio donde el expediente entero
 * cabia sin bajar, con la etiqueta al lado del campo y no encima. Los renglones
 * de abajo reproducen ese reparto sin cambiar ni tipografia ni colores: son las
 * mismas variables y los mismos controles que en el resto.
 *
 * Hubo una `.rejilla-ficha` de dos columnas —datos del asunto a la izquierda,
 * control a la derecha—. Ya no: la columna de control se quedo en tres campos
 * porque codigo y estado se leen en el titulo, y esos tres bajaron con los
 * demas. Sin segunda columna la rejilla no repartia nada.
 */

.titulo-panel {
  margin: 0 0 var(--esp-16);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texto-debil);
}

/* La cabecera del panel: el titulo a la izquierda y, a su derecha, los datos que
 * situan al expediente —alta, posicion, situacion—. Son de una linea y se leen
 * de un vistazo, asi que no gastan renglon propio: aprovechan el hueco que el
 * titulo dejaba vacio hasta el borde de la tarjeta. */
.cabecera-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--esp-8) var(--esp-24);
  margin-bottom: var(--esp-16);
}
/* El margen inferior lo pone ya la cabecera. */
.cabecera-panel > .titulo-panel { margin: 0; }

.datos-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--esp-4) var(--esp-16);
}
/* Rotulo y dato no se separan al plegarse: cada par cae entero a la linea de
 * abajo o no cae ninguno. */
.dato-suelto {
  display: inline-flex;
  align-items: baseline;
  gap: var(--esp-8);
}
.dato-suelto > .rotulo { font-size: 0.82rem; color: var(--texto-tenue); }
.dato-suelto > .dato { font-size: 0.92rem; }

.fila-densa {
  display: grid;
  grid-template-columns: minmax(7rem, 1fr) 2.6fr;
  gap: var(--esp-4) var(--esp-8);
  align-items: center;
  margin-bottom: var(--esp-8);
}
/* El alta pone aqui un `label`; la ficha, que es de consulta, un rotulo suelto:
 * no hay control al que apuntar. Se ven igual porque son la misma fila. */
.fila-densa > label,
.fila-densa > .rotulo {
  margin: 0;
  text-align: right;
  font-size: 0.82rem;
  line-height: 1.3;
}
.fila-densa > .rotulo { color: var(--texto-tenue); }

/* El dato, en el hueco del campo y con la misma altura, para que una ficha de
 * consulta y otra de alta no se lean como dos pantallas distintas. */
.fila-densa > .dato {
  min-width: 0;
  font-size: 0.92rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.nota { margin: 0; font-size: 0.8rem; color: var(--texto-tenue); }

/* La aclaracion cuelga del campo, no de la etiqueta. */
.fila-densa > .nota { grid-column: 2; }

/* En movil no hay dos columnas que repartir: etiqueta encima, como siempre. */
@media (max-width: 640px) {
  .fila-densa { grid-template-columns: 1fr; }
  .fila-densa > label,
  .fila-densa > .rotulo { text-align: left; }
  .fila-densa > .nota { grid-column: 1; }
}

/* Un texto largo guardado tal cual se escribio: los saltos de linea del usuario
 * son suyos y se respetan. */
.texto-largo { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }

.rejilla-pie {
  display: grid;
  gap: var(--esp-24);
  grid-template-columns: 1fr;
  /* Arriba y no centradas: las dos columnas tienen distinto numero de renglones
   * y centrandolas los rotulos de una caian entre los de la otra. */
  align-items: start;
}
@media (min-width: 860px) {
  .rejilla-pie { grid-template-columns: 1fr 1fr; }
}

.rejilla-importes {
  display: grid;
  gap: var(--esp-8);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* El economico de la ficha es el ultimo renglon de la identificacion, no un
 * panel aparte: las cuatro cifras **siempre** en el mismo renglon. Con
 * `auto-fit` se partian en dos renglones en cuanto la tarjeta se estrechaba, y
 * cada renglon de mas empujaba las pestañas hacia abajo. Son cuatro cifras
 * cortas: caben en cuatro columnas que se encogen. */
.rejilla-importes.en-fila {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
/* En el movil las cuatro columnas bajan de 5rem y una cuantia larga se sale de
 * su hueco: alli, y solo alli, dos y dos. */
@media (max-width: 480px) {
  .rejilla-importes.en-fila { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Sin marco: el recuadro de cada cifra solo añadia alto —borde mas relleno— y
 * el rotulo ya separa un importe del siguiente. Rotulo y cifra a la derecha,
 * uno encima del otro: sin marco que los encuadre, lo que alinea la columna es
 * el canto derecho, el mismo por el que se comparan los numeros. */
.importe {
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
  text-align: right;
}
/* Los importes del alta: renglones normales, uno debajo de otro, con la cifra en
 * una caja estrecha. Cuatro numeros del mismo asunto se leen y se comparan en
 * columna; repartidos en dos, la cuantia y las costas caian una al lado de otra
 * y habia que buscar cual era cual. Es `.rejilla-importes` —dos fichas por
 * renglon— lo que se queda para la ficha, que solo los enseña. */
.columna-importes > .fila-densa > input {
  max-width: 12rem;
  text-align: right;
  font-family: var(--fuente-mono);
}

.importe label, .importe .rotulo-importe { margin: 0; }
.importe .rotulo-importe { font-size: 0.82rem; color: var(--texto-tenue); }
/* Cifras alineadas a la derecha y en monoespaciada: se comparan en columna. */
.importe input, .importe .cifra { text-align: right; font-family: var(--fuente-mono); }

/* Botonera al pie del formulario, siempre a la vista aunque el alta sea larga. */
.barra-acciones {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--esp-8);
  flex-wrap: wrap;
  margin-top: var(--esp-16);
  padding: var(--esp-8) var(--esp-16);
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: 0 -4px 20px rgb(0 0 0 / 0.35);
}

/* La casilla maestra de una columna de casillas: marca y desmarca las de abajo.
 *
 * **Sin JavaScript no se enseña.** No es un campo del formulario —no tiene
 * `name`, no se envia—, sino un gesto que solo existe si hay quien lo atienda;
 * una casilla que no hace nada al pulsarla engaña mas que una que falta. La
 * marca `con-js` la pone `formulario.js` en la raiz. */
.marca-todo { display: none; }
.con-js .marca-todo {
  display: flex; align-items: center; gap: var(--esp-4);
  margin: 0; font-weight: normal;
}

/* Entre una casilla y su rotulo, 4; entre una opcion y la siguiente, 16: si
 * fueran parecidos no se sabria que texto va con que casilla. */
.opciones { display: flex; flex-wrap: wrap; gap: var(--esp-16); }
.opciones label {
  display: flex; align-items: center; gap: var(--esp-4);
  margin: 0; color: var(--texto); font-size: 0.9rem;
}

/* --- el logo del despacho ---------------------------------------------
 * El hueco de la ficha del despacho. Se pinta **siempre**, con logo o sin el:
 * un marco vacio dice que ahi va una imagen y que hoy no hay ninguna, que es
 * justo lo que quien administra necesita saber de un vistazo.
 *
 * Medidas fijas para que el hueco no salte de tamaño segun la imagen que se
 * suba, y `contain` para que ninguna se deforme: son logos de proporciones
 * distintas y el marco es uno solo. */
.logo-despacho {
  display: flex; align-items: flex-start; gap: var(--esp-16); flex-wrap: wrap;
}

.logo-hueco {
  display: flex; align-items: center; justify-content: center;
  width: 14rem; height: 7rem; padding: var(--esp-8);
  background: var(--fondo-elevado-2);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
}

.logo-hueco img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* Al lado del hueco mientras quepan los dos, y debajo cuando no: `18rem` es lo
 * que necesita el renglon de elegir fichero para no partirse. */
.logo-mandos {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--esp-8); flex: 1 1 18rem; max-width: 34rem;
}

/* --- buscador con lupa ------------------------------------------------
 * Un desplegable de miles de fichas no se recorre: se teclea. El campo tiene la
 * misma altura y el mismo borde que el resto de controles de la ficha densa,
 * porque es uno mas de la columna y no puede leerse como otra cosa.
 */

.buscador { position: relative; min-width: 0; }

/* Campo y lupa, pegados y con un solo borde entre los dos. La caja es ademas la
 * referencia de la lista: cuelga del campo, y no del bloque entero —que incluye
 * la linea de pista de debajo y la dejaba flotando a media pantalla del texto
 * que la ha producido. */
.buscador-caja { position: relative; display: flex; }
.buscador-caja > .buscador-entrada { min-width: 0; border-radius: var(--radio) 0 0 var(--radio); }

.buscador-lupa {
  flex: none;
  padding: 0 var(--esp-8);
  border-radius: 0 var(--radio) var(--radio) 0;
  border-left: none;
  color: var(--texto-tenue);
}
.buscador-lupa:hover { color: var(--texto); }

/* Mientras hay texto que no corresponde a nadie el campo lo avisa, sin llegar a
 * pintarlo como error: todavia se esta escribiendo. */
.buscador--pendiente .buscador-entrada { border-color: var(--aviso); }

/* El «buscando…» va dentro de la caja, contra el borde derecho del campo, y no
 * en un renglon debajo: ahi caia en el mismo sitio que la lista —que esta
 * abierta justo mientras se teclea, que es cuando el indicador asoma— y le
 * tapaba la primera sugerencia. Sobre lo escrito, si el texto llega hasta aqui,
 * el degradado lo desvanece en vez de cortarlo con un canto. */
.buscador-caja > .indicador {
  position: absolute;
  top: 50%;
  right: var(--esp-8);
  transform: translateY(-50%);
  z-index: 1;
  padding-left: var(--esp-16);
  background: linear-gradient(to right, transparent, var(--fondo) var(--esp-16));
  pointer-events: none;
}
/* Con lupa el borde derecho del campo es el de ella: el indicador se aparta. */
.buscador-caja:has(> .buscador-lupa) > .indicador { right: 2.6rem; }

/* El aviso —lo escrito todavia no es nadie— flota bajo la caja en vez de
 * ocupar sitio en la fila. Con su renglon reservado, cada buscador media 19px
 * mas que un campo normal: entre dos cajas de identificacion habia 27 y entre
 * dos de control 8, y las dos columnas de la ficha no marcaban el mismo
 * renglon. Fuera del flujo el buscador mide lo que un `input`, y lo que separa
 * las cajas es el margen de la fila y nada mas.
 *
 * Flota, y no entra y sale del flujo, porque asomar empujaria hacia abajo el
 * formulario entero —lo mismo que la lista—. Tapa a ratos la fila siguiente, y
 * no a la lista: el aviso sale al salir del campo, y para entonces la lista ya
 * esta cerrada. */
.buscador-pista {
  position: absolute;
  top: 100%;
  left: 0;
  /* Lo ancho que sea el aviso y no lo ancho que sea el campo: encima de la fila
   * siguiente, tapa lo justo. */
  width: max-content;
  max-width: 100%;
  z-index: 21;
  margin-top: var(--esp-4);
  background: var(--fondo-elevado-2);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  /* Se pone sobre la fila de abajo: que el clic siga llegando a lo que hay
   * debajo. */
  pointer-events: none;
}

/* --- la pista de un campo ---------------------------------------------------
 *
 * El renglon donde un campo dice lo suyo, y **el unico sitio donde lo dice**:
 * la burbuja del navegador se calla (ver `formulario.js`). Vale para cualquier
 * campo y no solo para el buscador, que es de donde salio: el `min="1"` de un
 * `<input type="number">` corriente tiene que quejarse igual que un
 * autocompletado a medias, y con la misma pinta.
 *
 * **Vacia no ocupa.** `display: none` mientras no haya nada que decir, que es
 * lo que evita el hueco reservado bajo cada campo. El elemento **sigue estando
 * en el documento** —lo pinta la plantilla, o lo pone `formulario.js` al
 * montar— porque el `aria-describedby` que lo nombra tiene que apuntar a algo
 * que exista antes de que haya nada escrito; lo que cambia es el texto, nunca
 * el elemento.
 */
.campo-pista {
  padding: var(--esp-4) var(--esp-8);
  overflow-wrap: anywhere;
}
.campo-pista:empty { display: none; }

/* El reproche, que no es lo mismo que la ayuda. La ayuda —el detalle de lo que
 * se ha elegido— se queda con el color tenue de `.nota`; esto se pinta en
 * ambar, **y ademas lleva `aria-invalid` en el campo**, que es lo que lo dice
 * sin color. Ver `.fila--vencida`: aqui tampoco informa el color solo. */
.campo-pista--mal { color: var(--aviso); }


/* La lista flota sobre la ficha: si empujara, cada tecla movería el formulario
 * entero hacia abajo. */
.buscador-lista {
  position: absolute;
  z-index: 20;
  top: 100%;
  left: 0;
  right: 0;
  margin: var(--esp-4) 0 0;
  padding: var(--esp-4);
  max-height: 17rem;
  overflow-y: auto;
  list-style: none;
  background: var(--fondo-elevado-2);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  scrollbar-width: thin;
  scrollbar-color: var(--borde-fuerte) transparent;
}

.buscador-opcion {
  display: flex;
  gap: var(--esp-16);
  align-items: baseline;
  justify-content: space-between;
  padding: var(--esp-4) var(--esp-8);
  border-radius: 6px;
  cursor: pointer;
}
/* Teclado y raton resaltan igual: la fila marcada es una sola, venga de donde
 * venga. */
.buscador-opcion:hover,
.buscador-opcion[aria-selected="true"] { background: var(--acento-tenue); }

.buscador-nombre { min-width: 0; overflow-wrap: anywhere; }
.buscador-detalle { flex: none; color: var(--texto-tenue); font-size: 0.8rem; }
.buscador-vacio { padding: var(--esp-8); color: var(--texto-tenue); font-size: 0.88rem; }

.buscador-fila { cursor: pointer; }

/* --- destinatarios de un correo ---------------------------------------
 * Las direcciones del «Para», la copia y la copia oculta, cada una en su
 * etiqueta. Debajo, escondido, el campo de texto con todas separadas por punto
 * y coma: es lo que se envia, y sin JavaScript es lo que se ve. Ver
 * `estaticos/destinatarios.js`.
 *
 * La caja imita a un `input` —mismo borde, mismo radio, mismo fondo— porque en
 * la columna de la ficha es uno mas y leerse como otra cosa la desordenaria.
 * Lo unico que la distingue es que crece hacia abajo cuando hay muchos.
 */

.destinatarios {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-4);
  padding: var(--esp-4);
  background: var(--fondo);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
}
/* Un `display` puesto por el autor le gana al `hidden` del navegador, y esta
 * caja nace escondida —la ensena el guion al montarla—: sin esta linea se veria
 * desde el primer momento, con el campo de texto debajo y las dos cosas a la
 * vez. `.buscador` no lo necesita porque no declara `display`. */
.destinatarios[hidden] { display: none; }

/* El foco lo tiene el hueco de escribir, pero lo que el usuario ve como campo es
 * la caja entera: el anillo se pinta **en ella**, con el mismo grosor y el mismo
 * color que en cualquier `input`. Lo que no se hace es apagarle el suyo al campo
 * de dentro —apagar un anillo de foco deja sin rastro a quien tabula—: ese campo
 * no tiene borde ni fondo propios, asi que su anillo cae justo sobre el de la
 * caja y se ve uno solo. */
.destinatarios:focus-within {
  border-color: var(--acento);
  outline: 2px solid var(--acento-fuerte);
  outline-offset: 1px;
}

/* `contents`: la lista no pinta nada por su cuenta y sus etiquetas participan
 * en la misma linea que el hueco de escribir y la lupa. Con una caja propia,
 * las etiquetas se apilaban encima del campo en vez de fluir con el. */
.destinatarios-lista { display: contents; list-style: none; margin: 0; padding: 0; }

.destinatarios .etiqueta {
  display: inline-flex;
  align-items: center;
  gap: var(--esp-4);
  margin: 0;
  padding: var(--esp-4) var(--esp-8);
  font-size: 0.85rem;
}

.etiqueta-quitar {
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
}
.etiqueta-quitar:hover { opacity: 1; }

/* El hueco de escribir: sin borde ni fondo propios, porque el borde ya lo pone
 * la caja. `flex: 1` para que ocupe lo que sobre y quepan las etiquetas antes. */
.destinatarios-entrada {
  flex: 1 1 12rem;
  min-width: 8rem;
  width: auto;
  padding: var(--esp-4);
  border: none;
  background: none;
}

/* La lupa, sin el borde pegado del buscador: aqui no hay campo a su izquierda
 * del que colgar, esta dentro de la caja. */
.destinatarios > .buscador-lupa {
  border: none;
  border-radius: var(--radio);
  background: none;
  padding: var(--esp-4) var(--esp-8);
}

/* --- dialogos ---------------------------------------------------------
 * `dialog` nativo: el foco atrapado y la tecla Esc los pone el navegador, y no
 * hacen falta ni capa ni guiones para simularlos.
 */

.dialogo {
  width: min(46rem, 92vw);
  padding: var(--esp-16) var(--esp-24) var(--esp-24);
  background: var(--fondo-elevado);
  color: var(--texto);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
}
.dialogo::backdrop { background: rgb(0 0 0 / 0.6); }

/* La confirmacion es angosta a proposito: son dos renglones y dos botones, y
 * ancha se lee como un panel en vez de como una pregunta. */
.dialogo-confirmar { width: min(30rem, 92vw); }
.confirmacion-cuerpo { margin: var(--esp-8) 0 var(--esp-24); }
/* Los dos botones a la derecha, y **el de seguir el ultimo**: se lee de
 * izquierda a derecha, y lo ultimo antes de pulsar es lo que se va a hacer. */
.confirmacion-pie {
  display: flex;
  justify-content: flex-end;
  gap: var(--esp-8);
}

.dialogo-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-16);
  margin-bottom: var(--esp-16);
}
.dialogo-cerrar { padding: var(--esp-4) var(--esp-8); line-height: 1; }

.dialogo-cuerpo {
  max-height: min(24rem, 55vh);
  overflow-y: auto;
  margin: var(--esp-16) 0 var(--esp-8);
}
/* Cabecera de tabla fija: en una lista larga se pierde de vista a la tercera fila. */
.dialogo-cuerpo th { position: sticky; top: 0; z-index: 1; }

/* --- botones --- */

.boton, button {
  display: inline-flex;
  align-items: center;
  gap: var(--esp-8);
  padding: var(--esp-8) var(--esp-16);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  background: var(--fondo-elevado-2);
  color: var(--texto);
  font: inherit;
  cursor: pointer;
}
.boton:hover, button:hover { background: var(--fondo-hover); text-decoration: none; }

.boton.primario, button.primario {
  background: var(--acento);
  border-color: var(--acento);
  color: var(--sobre-acento);
  font-weight: 600;
}
.boton.primario:hover, button.primario:hover { background: var(--acento-fuerte); }

.boton.peligro, button.peligro { color: var(--peligro); border-color: var(--peligro); background: transparent; }
.boton.peligro:hover, button.peligro:hover { background: var(--peligro-tenue); }

/* Boton de solo icono, para la columna de acciones de una tabla. Ahi el rotulo
 * se repite en cada fila —«Modificar», «Borrar», «Modificar»…— y acaba pesando
 * mas que el dato que acompana; el dibujo dice lo mismo en un cuadrado. El
 * rotulo no desaparece, se aparta: va en title y en aria-label, que es lo que
 * leen el lector de pantalla y el que se para encima. Cuadrado, para que las
 * dos acciones midan igual aunque una diga mas que la otra. */
.boton.icono, button.icono {
  padding: var(--esp-8);
  color: var(--texto-tenue);
}
.boton.icono:hover, button.icono:hover { color: var(--texto); }
.boton.icono.peligro, button.icono.peligro { color: var(--peligro); }
.boton.icono svg, button.icono svg { display: block; }

.acciones { display: flex; gap: var(--esp-8); align-items: center; flex-wrap: wrap; }
.acciones.derecha { justify-content: flex-end; }
/* Dentro de una tabla no se parten en dos renglones: una columna se ensancha
 * hasta lo que mide su celda mas ancha, y dos botones apilados hacen la fila
 * mas alta a cambio de nada. */
td.acciones { flex-wrap: nowrap; }

/* Menú de acciones «⋮»: las acciones frecuentes van a la vista y las demás se
 * pliegan detrás de un botón de tres puntos. Es un `<details>` y no un
 * desplegable con JavaScript, para que siga funcionando sin él: se abre y se
 * cierra solo, y quien no cargue los scripts ve la lista igualmente.

 * El disparador es el `summary`, y la lista cuelga de él como un panel que
 * flota debajo, alineado a su borde derecho. El `<details>` es `inline-flex`
 * para comportarse en la barra como un botón más, y el `summary` se pinta
 * como un cuadrado de icono. Dos detalles que evitan que el «⋮» se mueva al
 * abrir: el `summary` nace como `list-item` —su caja con marcador desplaza el
 * contenido y cambia de tamaño según el estado—, así que se le fija
 * `display: flex` y se suprime el marcador de las dos maneras; y la lista es
 * `absolute`, de modo que al desplegarse no empuja a nada ni altera la altura
 * de la barra. */
.menu-acciones { position: relative; display: inline-flex; align-items: center; }
.menu-acciones summary {
  display: flex;
  align-items: center;
  justify-content: center;
  list-style: none;
  cursor: pointer;
}
.menu-acciones summary::marker,
.menu-acciones summary::-webkit-details-marker { content: none; display: none; }
.menu-acciones-lista {
  position: absolute;
  right: 0;
  top: calc(100% + var(--esp-8));
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
  padding: var(--esp-8);
  min-width: 12rem;
  background: var(--fondo-elevado-2);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
}
/* Cada fila del menú llena el panel y deja su rótulo a la izquierda; el botón
 * del formulario hace lo propio dentro de su fila. */
.menu-acciones-lista .boton { justify-content: flex-start; }
.menu-acciones-lista form { margin: 0; display: flex; }
.menu-acciones-lista form button { flex: 1; justify-content: flex-start; }
/* Un separador dentro del panel, para apartar lo que cierra la sesion de lo
 * que se hace a diario y que no se pulse de paso. */
.menu-acciones-lista hr {
  margin: var(--esp-4) 0;
  border: 0;
  border-top: 1px solid var(--borde);
}
/* La opcion apagada ocupa su sitio sin ser pulsable, igual que el salto de
 * pagina que no lleva a ninguna parte. */
.menu-acciones-lista [aria-disabled="true"] {
  color: var(--texto-debil);
  background: transparent;
  cursor: default;
  pointer-events: none;
}

/* Formulario de una sola fila, para editar un dato dentro de una celda. */
.en-linea { display: flex; gap: var(--esp-4); align-items: center; margin: 0; }
.en-linea input { margin: 0; min-width: 12rem; }
.en-linea button { padding: var(--esp-4) var(--esp-8); font-size: 0.85rem; }
/* Un dato que falta y hace falta: aqui, quien no puede recuperar la contrasena. */
.campo-vacio { border-color: var(--aviso); }
.campo-vacio::placeholder { color: var(--aviso); }

.barra {
  display: flex; gap: var(--esp-16); align-items: center;
  justify-content: space-between; margin-bottom: var(--esp-16); flex-wrap: wrap;
}

/* --- recados ----------------------------------------------------------------
 *
 * Lo que la pantalla dice despues de una accion. Se llamaba `.aviso`, que es el
 * nombre de la tarea con vencimiento: dos cosas distintas con la misma palabra.
 * Ver `app/web/recados.py`.
 */

.recado {
  padding: var(--esp-8) var(--esp-16);
  border-radius: var(--radio);
  border: 1px solid var(--borde-fuerte);
  background: var(--fondo-elevado);
  margin-bottom: var(--esp-16);
  /* La inversa, cuando la hay, a la derecha y en la misma linea que el texto:
   * es la salida de lo que se acaba de leer, no otro parrafo. */
  display: flex;
  align-items: center;
  gap: var(--esp-16);
}
.recado-texto { flex: 1; min-width: 0; }
.recado-accion { margin: 0; flex: none; }

.recado.error {
  border-color: var(--peligro);
  background: var(--peligro-tenue);
  color: var(--texto-peligro);
}
.recado.exito { border-color: var(--exito); color: var(--exito); }
.recado.atencion { border-color: var(--aviso); color: var(--aviso); }

/* Sin recados no hay caja, ni margen, ni hueco: el contenedor va siempre en el
 * documento porque es el destino del `hx-swap-oob`, no porque haya algo que
 * enseñar. */
#recados:empty { display: none; }

/* --- etiquetas de rol --- */

.etiqueta {
  display: inline-block;
  padding: 0 var(--esp-8);
  margin-right: var(--esp-4);
  border-radius: 999px;
  background: var(--acento-tenue);
  color: var(--acento-fuerte);
  font-size: 0.75rem;
  white-space: nowrap;
}

.etiqueta--atencion { background: transparent; border: 1px solid var(--aviso); color: var(--aviso); }
.etiqueta--apagada { background: transparent; border: 1px solid var(--borde-fuerte); color: var(--texto-debil); }
.etiqueta--vencida { background: var(--peligro-tenue); color: var(--texto-peligro); }

/* --- el indice del archivo documental ------------------------------------ */
/* Dos iconos por celda: troceado (apagado) y embebido (acento). El color
   acompaña, no informa: lo que dice de verdad es el `aria-label` de cada
   `span[role="img"]`. */
.indice-iconos { display: inline-flex; align-items: center; gap: var(--esp-4); }
.indice-icono { display: inline-flex; align-items: center; color: var(--texto-debil); }
.indice-icono--embebido { color: var(--acento); }

/* La fila de un aviso al que ya le paso la fecha.
 *
 * El original la pintaba de amarillo entera y nada mas. Aqui va un filo a la
 * izquierda y un fondo apenas insinuado, **y ademas la etiqueta que lo dice con
 * palabras**: un color solo no lo distingue quien no lo ve, y sobre una captura
 * en blanco y negro —o impresa— desaparece. El color acompaña, no informa.
 *
 * `box-shadow` y no `border-left`: un borde en la primera celda desplaza su
 * contenido y descuadra la columna de casillas respecto de la cabecera.
 */
.fila--vencida > td { background: var(--peligro-tenue); }
.fila--vencida > td:first-child { box-shadow: inset 3px 0 0 var(--peligro); }

.mono { font-family: var(--fuente-mono); font-size: 0.85rem; color: var(--texto-tenue); }

/* --- notificaciones --- */

/* La campanita vive en `.barra-superior` y se comporta como un boton mas de
 * esa fila. El desplegable es el `.menu-acciones` de siempre —un `<details>`,
 * que se abre sin JavaScript—; lo propio de aqui es el numero y el panel, que
 * es mas ancho porque un titulo con su fecha no cabe en las 12rem del «⋮». */
.campana { display: inline-flex; align-items: center; }
.campana summary { position: relative; border-color: transparent; background: var(--fondo-elevado); }

/* El numero de sin leer, encima del icono. El par de colores es el de
 * `.boton.primario`, que es el unico fondo lleno de la casa y el que tiene
 * medido su contraste. Las medidas son de dibujo —la caja de un texto de
 * 0.7rem— y por eso no salen de la escala `--esp-*`, igual que el `3px` de
 * `.fila--vencida`. Solo se pinta si hay alguno: una insignia con un cero es
 * ruido que ademas pide que la mires. */
.campana-cuenta {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 1.15rem;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--acento);
  color: var(--sobre-acento);
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.15rem;
  text-align: center;
}

/* Tope de alto y su barra: veinte sin leer no pueden empujar el desplegable
 * fuera de la pantalla. */
.campana-lista {
  min-width: 22rem;
  max-width: 26rem;
  max-height: min(24rem, 60vh);
  overflow-y: auto;
  overflow-x: hidden;
}

/* Cada renglon es un formulario, no un enlace: pulsarlo marca la notificacion
 * como leida y salta a lo que cuenta, y eso escribe. El boton llena la fila y
 * apila sus tres lineas a la izquierda, que es como se lee un renglon de
 * bandeja y no como se lee un boton. */
.campana-fila { margin: 0; display: flex; }
.campana-fila button {
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--esp-4);
  text-align: left;
  border-color: transparent;
  background: transparent;
  min-width: 0;
}
.campana-fila button:hover { background: var(--fondo-hover); }
.campana-titulo {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
/* El detalle, a un renglon: el desplegable no es sitio para parrafos. */
.campana-texto {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Sin leer se marca **dos veces**: el filo de la izquierda y el titulo en texto
 * pleno. El color acompana, no informa —el mismo argumento que `.fila--vencida`;
 * aqui lo que lo dice con palabras es la etiqueta de la bandeja. */
.campana-fila--sin-leer button {
  box-shadow: inset 3px 0 0 var(--acento);
  color: var(--texto);
}

/* El pie del panel se separa con una linea: arriba esta lo que ha pasado y
 * abajo que hacer con ello. */
.campana-pie {
  display: flex;
  gap: var(--esp-8);
  padding-top: var(--esp-8);
  margin-top: var(--esp-4);
  border-top: 1px solid var(--borde);
}
.campana-pie form { margin: 0; display: flex; flex: 1; }
.campana-pie form button { flex: 1; }

/* --- el banner de los recordatorios vencidos --- */
/*
 * La pantalla brusca de la casa. La campanita esta a un lado y hay que mirarla;
 * esto ocupa el ancho de la columna, va **por encima de la fila de arriba** —lo
 * primero del contenido— y es lo unico pegado arriba: al bajar por la pagina se
 * queda el y se va la campanita, que es lo que se pide de algo que solo aparece
 * cuando un aviso vence.
 *
 * **Los colores son los del vencido que ya existe** —`--peligro-tenue` de fondo,
 * `--peligro` de filo, `--texto-peligro` encima—, los mismos de `.fila--vencida`
 * y `.etiqueta--vencida`. Un cuarto rojo inventado para esto le diria al que
 * mira que es otra cosa, y es la misma.
 *
 * Y se marca dos veces, como el aviso vencido de la lista: el color **y** las
 * palabras de la cabecera. Un color solo no lo distingue quien no lo ve.
 */
.banner-recordatorios {
  position: sticky;
  top: 0;
  z-index: 20;
  padding: var(--esp-8) var(--esp-24);
  background: var(--peligro-tenue);
  border-bottom: 1px solid var(--peligro);
  /* El filo de arriba lo cierra por su lado, que no tiene nada encima: pegado
   * al borde de la ventana, sin el se derramaria hacia fuera. */
  box-shadow: inset 0 3px 0 var(--peligro);
  color: var(--texto-peligro);
}

.banner-cabecera {
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  margin-bottom: var(--esp-8);
}
.banner-titulo { flex: 1; font-size: 0.88rem; }
/* El boton de vaciarlo entero, a la derecha y separado de las aspas de cada
 * renglon: son dos gestos distintos y no conviene que se toquen. */
.banner-descartar-todos { margin: 0; }

.banner-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
}

.banner-fila {
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  /* `min-width: 0` en la fila y en el boton: sin el, un asunto largo estira el
   * flex y saca el aspa fuera de la pantalla en vez de recortarse. */
  min-width: 0;
}

.banner-abrir { margin: 0; display: flex; flex: 1; min-width: 0; }
.banner-abrir button {
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  min-width: 0;
  padding: var(--esp-4) var(--esp-8);
  text-align: left;
  border-color: transparent;
  background: transparent;
  color: var(--texto-peligro);
}
.banner-abrir button:hover { background: var(--fondo-hover); }

.banner-asunto { font-weight: 600; }
/* El detalle, a un renglon: el banner es un cartel, no la bandeja. */
.banner-asunto,
.banner-texto {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.banner-texto { color: var(--texto-peligro); opacity: 0.75; }

.banner-hora { white-space: nowrap; color: var(--texto-peligro); opacity: 0.75; }

.banner-quitar { margin: 0; }
.banner-quitar button {
  border-color: transparent;
  background: transparent;
  color: var(--texto-peligro);
  line-height: 1;
}
.banner-quitar button:hover { background: var(--fondo-hover); }

.banner-pie { margin: var(--esp-8) 0 0; color: var(--texto-peligro); opacity: 0.85; }
.banner-pie a { color: var(--texto-peligro); text-decoration: underline; }

/* El titulo dentro de la bandeja: es un boton porque abrirlo escribe, pero se
 * lee como el enlace que ocupa su sitio en cualquier otra tabla. */
.titulo-notificacion {
  padding: 0;
  border-color: transparent;
  background: transparent;
  color: var(--acento);
  font-weight: 600;
}
.titulo-notificacion:hover { background: transparent; text-decoration: underline; }

/* El renglon sin leer de la bandeja. Gemela de `.fila--vencida` y con el mismo
 * motivo tecnico: `box-shadow` y no `border-left`, que en la primera celda
 * desplaza el contenido y descuadra la columna respecto de la cabecera. */
.fila--sin-leer > td:first-child { box-shadow: inset 3px 0 0 var(--acento); }

/* El codigo de un expediente cuando enlaza a su ficha. Es un entero, y los
 * primeros de un despacho miden una cifra: un «7» suelto es una diana de cuatro
 * pixeles, y fallar el clic en una lista de cuarenta renglones pasa todos los
 * dias. Se le reserva el ancho de cinco cifras —lo que la serie acabara
 * midiendo— y el enlace ocupa ese hueco entero, blanco incluido, porque lo que
 * se pulsa es la caja y no el texto. Los blancos caen a la izquierda, asi que la
 * columna queda cuadrada por la derecha, que es como se leen los numeros. Es un
 * minimo y no un ancho fijo: un codigo de seis cifras se enseña con las seis. */
.enlace-codigo {
  display: inline-block;
  min-width: 5ch;
  text-align: right;
}
/* Su columna, que no gasta mas de lo que mide el numero: lo que tiene que crecer
 * es lo que se lee al lado. */
.col-id { width: 1%; white-space: nowrap; }

/* Texto recortado en una celda: el «…» dice que hay más y el cursor de ayuda
 * dice que el resto sale al posarse encima, en el `title`. */
.recortado { cursor: help; }

/* --- detalle plegado dentro de una tabla --- */
/* Lo usa la traza de peticiones: los cuerpos son largos y casi nunca se miran,
 * asi que ocupan su propia fila y nacen cerrados. Sin JavaScript: `details` lo
 * abre y lo cierra el navegador. */

.detalle summary {
  cursor: pointer;
  color: var(--texto-tenue);
  font-size: 0.85rem;
}
.detalle summary:hover { color: var(--texto); }
.detalle dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--esp-4) var(--esp-16);
  margin: var(--esp-8) 0 0;
}
.detalle dt { color: var(--texto-debil); white-space: nowrap; }
.detalle dd { margin: 0; min-width: 0; }
.detalle pre {
  margin: 0;
  padding: var(--esp-8);
  border-radius: var(--radio);
  background: var(--fondo-elevado-2);
  /* Se parte y ademas se puede desplazar: una linea de JSON sin espacios no se
   * parte sola y ensancharia la tabla entera. */
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 16rem;
  overflow: auto;
}

/* Indicador de HTMX: invisible salvo mientras hay peticion en vuelo. Se oculta
 * con opacidad y no con display para que no descoloque la barra al aparecer. */
.indicador { opacity: 0; transition: opacity 0.15s ease-in; }
.htmx-request .indicador,
.htmx-request.indicador { opacity: 1; }

/* --- entrada --- */

.pantalla-centrada {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--esp-24);
}
.caja-entrada { width: 100%; max-width: 380px; }
.caja-entrada h1 { text-align: center; }
.caja-entrada .subtitulo { text-align: center; }
/* Enlaces de debajo de la caja: recuperar la contrasena, volver a entrar. */
.pie-caja {
  text-align: center;
  margin: var(--esp-16) 0 0;
  font-size: 0.9rem;
  color: var(--texto-tenue);
}
/* Dentro de la tarjeta va pegado al formulario, no separado como los de fuera. */
.tarjeta .pie-caja { margin-top: var(--esp-8); }

/* --- tablero de inicio ------------------------------------------------
 * Tres bandas: los numeros, el cuerpo y el contexto del pie. La jerarquia la
 * marcan la elevacion de la tarjeta y el tamaño de la cifra, no lineas ni
 * colores nuevos: aqui no entra ni un color que no este ya arriba.
 */

.rejilla-metricas {
  display: grid;
  gap: var(--esp-16);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-bottom: var(--esp-24);
}

.metrica { display: flex; flex-direction: column; gap: var(--esp-4); }

/* Mismo rotulo que el de un panel de la ficha: son la misma clase de titulo. */
.rotulo-metrica {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texto-debil);
}

/* Monoespaciada porque son cifras que se comparan en columna, como los importes
 * de la ficha. */
.cifra-metrica { font-family: var(--fuente-mono); font-size: 1.9rem; line-height: 1.1; font-weight: 700; }
.pie-metrica { font-size: 0.8rem; color: var(--texto-tenue); }

.metrica--atencion .cifra-metrica { color: var(--aviso); }

/* Una métrica que además lleva a su pantalla. Hereda el color del texto en vez
 * del de enlace, por lo mismo que `.tarjeta-expediente`: teñir de azul la
 * tarjeta entera la haría parecer otra cosa que las de al lado, cuando lo único
 * que cambia es que ésta se puede pinchar. Lo dice el marco al pasar por encima. */
a.metrica { color: var(--texto); }
a.metrica:hover {
  border-color: var(--acento);
  background: var(--fondo-elevado-2);
  text-decoration: none;
  color: var(--texto);
}

/* Cuatro columnas y el importe ocupando dos: una cifra en euros no cabe en el
 * mismo ancho que un contador de dos digitos. Solo cuando hay cuatro columnas
 * que repartir: en estrecho, un `span 2` se inventaria una columna de mas. */
@media (min-width: 900px) {
  .rejilla-metricas { grid-template-columns: repeat(4, 1fr); }
  .metrica--ancha { grid-column: span 2; }
}

/* `minmax(0, …)` y no `1fr` a secas en las dos rejillas de aqui: dentro va una
 * tabla, y una columna de rejilla mide por defecto lo que mida su contenido sin
 * partir. Con `1fr` la tabla ensancha la columna, la columna ensancha la pagina
 * y en movil se scrollea la pantalla entera en vez de la tabla, que es la que
 * sabe hacerlo sola. */
.rejilla-tablero {
  display: grid;
  gap: var(--esp-24);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 1000px) {
  /* Dos tercios para lo que se atiende, uno para lo que ha pasado. El mismo
   * reparto que la ficha, por lo mismo: la columna estrecha se ojea. */
  .rejilla-tablero { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
}

.columna-tablero { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--esp-24); }

/* Dos por fila y no tres: son fichas de un vistazo, con el nombre del cliente
 * entero. La rejilla general de tarjetas admite una mas y las estrecha. */
.rejilla-recientes { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

/* La tarjeta entera es el enlace: en un tablero se pincha el expediente, no una
 * palabra dentro de el. */
.tarjeta-expediente {
  display: flex;
  flex-direction: column;
  gap: var(--esp-4);
  color: var(--texto);
}
.tarjeta-expediente:hover {
  border-color: var(--acento);
  background: var(--fondo-elevado-2);
  text-decoration: none;
  color: var(--texto);
}
.tarjeta-expediente .cabecera-tarjeta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-8);
}
.tarjeta-expediente .codigo { font-size: 1.05rem; font-weight: 600; color: var(--texto); }
.tarjeta-expediente .dato-tarjeta { overflow-wrap: anywhere; }

/* Linea de tiempo: un hilo y un punto por hito. El punto queda centrado sobre el
 * hilo —los dos a 5px del borde—, y su color dice que clase de hito es. */
.linea-tiempo {
  position: relative;
  margin: 0;
  padding: 0 0 0 var(--esp-24);
  list-style: none;
}
.linea-tiempo::before {
  content: "";
  position: absolute;
  left: 4px;
  top: var(--esp-8);
  bottom: var(--esp-8);
  width: 2px;
  background: var(--borde);
}

.hito { position: relative; display: flex; flex-direction: column; gap: var(--esp-4); }
.hito + .hito { margin-top: var(--esp-16); }
.hito::before {
  content: "";
  position: absolute;
  left: calc(var(--esp-24) * -1);
  top: 5px;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: var(--fondo-elevado);
  border: 2px solid var(--borde-fuerte);
}
.hito--alta::before { border-color: var(--acento); }
.hito--fin::before { border-color: var(--exito); }

.hito .cuando { font-size: 0.75rem; color: var(--texto-debil); }
.hito .titulo-hito { font-size: 0.92rem; font-weight: 600; }

/* Esquema procesal: el guion del procedimiento, en arbol.
 *
 * La sangria sale de `--nivel`, que pinta la plantilla en cada paso, multiplicada
 * por la medida de la escala. Es la unica forma de que el sangrado salga de un
 * dato de la fila sin escribir una clase por nivel ni un `style` con pixeles.
 *
 * El hilo de la izquierda es un borde del propio paso y no un pseudoelemento
 * suelto: asi se desplaza con la sangria y se ve de donde cuelga cada rama.
 */
.arbol { margin: 0; padding: 0; list-style: none; }

/* La raiz: el tipo de esquema procesal, de donde cuelga todo lo demas. Va fuera
 * del `<ol>` —el arrastre solo mira dentro— y por eso lo que la ata al arbol es
 * el hilo de la izquierda, el mismo borde que llevan los pasos. */
.raiz-esquema {
  display: flex;
  align-items: baseline;
  gap: var(--esp-8);
  flex-wrap: wrap;
  padding: var(--esp-8);
  background: var(--fondo-elevado-2);
  border-left: 2px solid var(--acento);
}
.raiz-nombre { font-weight: 600; }

/* Lo que cuelga de la raiz, sea el arbol o el aviso de que esta vacio: un
 * escalon, la misma medida que separa un nivel del siguiente. */
.arbol--colgado { margin-top: var(--esp-4); margin-left: var(--esp-24); }

/* Cambiar el tipo es lo excepcional: cerrado ocupa un renglon. */
.cambiar-raiz { margin-top: var(--esp-8); }
.cambiar-raiz > summary { cursor: pointer; font-size: 0.85rem; color: var(--texto-tenue); }
.cambiar-raiz > summary:hover { color: var(--texto); }

/* Los dos formularios cortos que viven dentro de una pestaña de la ficha: el
 * tipo de esquema y el reparto de acceso. Un par de campos y su boton, sin la
 * barra pegajosa del alta, que aqui seria una botonera para dos datos. Anchos de
 * campo y no de pantalla: un desplegable de 90 caracteres no se lee mejor. */
.elegir-raiz,
.dar-acceso { margin-top: var(--esp-16); max-width: 34rem; }
.elegir-raiz > .acciones,
.dar-acceso > .acciones { margin-top: var(--esp-8); }

.paso {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--esp-16);
  margin-left: calc(var(--nivel, 0) * var(--esp-24));
  padding: var(--esp-8);
  border-left: 2px solid var(--borde);
  background: var(--fondo-elevado);
}
.paso + .paso { margin-top: var(--esp-4); }
.paso:hover { background: var(--fondo-hover); }
/* Un paso sangrado cuelga de algo: se marca el hilo para que se vea la rama. */
.paso:not([data-nivel="0"]) { border-left-color: var(--borde-fuerte); }

.paso-texto { display: flex; flex-direction: column; gap: var(--esp-4); min-width: 0; }
.paso .cuando { font-size: 0.75rem; color: var(--texto-debil); }
.paso-descripcion { overflow-wrap: anywhere; }

/* Cuatro botones estrechos: son flechas, no rotulos, y en una lista larga
 * repetirlos anchos convierte la columna derecha en una pared. */
.paso-acciones { display: flex; gap: var(--esp-4); flex-shrink: 0; }
.paso-acciones button {
  padding: var(--esp-4) var(--esp-8);
  line-height: 1;
  background: var(--fondo-elevado-2);
  color: var(--texto-tenue);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  cursor: pointer;
}
.paso-acciones button:hover:not(:disabled) { color: var(--texto); border-color: var(--borde-fuerte); }
/* Deshabilitado y no escondido: que el boton siga ocupando su sitio es lo que
 * evita que las flechas bailen de columna entre un renglon y el siguiente. */
.paso-acciones button:disabled { opacity: 0.35; cursor: default; }

/* Arrastre. Sin JavaScript no aparece ninguno de estos dos estados. */
.paso[draggable="true"] { cursor: grab; }
.paso--arrastrando { opacity: 0.4; cursor: grabbing; }
.paso--destino { border-left-color: var(--acento); background: var(--acento-tenue); }

/* Banda de contexto al pie: de que va este usuario y hasta donde llega. Ni
 * tarjeta ni titulo, que no es un panel mas: es el margen de la pantalla. */
.pie-tablero {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--esp-8) var(--esp-16);
  margin-top: var(--esp-24);
  padding: var(--esp-8) var(--esp-16);
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  font-size: 0.8rem;
  color: var(--texto-tenue);
}
.pie-tablero .separador-pie { width: 1px; height: 1rem; background: var(--borde-fuerte); }
.pie-tablero .areas-pie { display: flex; align-items: center; gap: var(--esp-4); flex-wrap: wrap; }
.pie-tablero .etiqueta { margin: 0; }

/* --- arbol de documentos ----------------------------------------------
 * La pestaña de documentos, con la forma de un explorador de ficheros: el
 * expediente arriba, sus anexos colgando, y cada actuacion con los suyos.
 *
 * La lista que llega es **plana** y cada linea trae su nivel: la sangria la pone
 * esta hoja con `.nivel-N` y no la estructura del HTML. Tres niveles fijos, que
 * son los que hay: expediente, actuacion, anexo. Anidar `<ul>` obligaria a una
 * macro recursiva de Jinja para algo que no va a crecer.
 */
.arbol-envoltorio {
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  overflow-x: auto;
}
.arbol { list-style: none; margin: 0; padding: var(--esp-8); }

.nodo {
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  padding: var(--esp-4) var(--esp-8);
  border-radius: var(--radio);
  min-width: 0;
}
.nodo:hover { background: var(--fondo-hover); }

/* La escala de espaciado, no una sangria propia: un nivel son 24 px, igual que
 * el sangrado de un paso del esquema. */
.nivel-1 { margin-left: var(--esp-24); }
.nivel-2 { margin-left: calc(var(--esp-24) * 2); }

/* El icono no se encoge cuando el nombre es largo: si se aplasta, la carpeta y
 * el clip dejan de distinguirse, que es justo para lo que estan. */
.icono-nodo { flex-shrink: 0; color: var(--texto-debil); }
.nodo-expediente > .icono-nodo,
.nodo-actuacion > .icono-nodo { color: var(--acento); }

.nodo-rotulo { overflow-wrap: anywhere; }
.nodo-expediente > .nodo-rotulo,
.nodo-actuacion > .nodo-rotulo { font-weight: 600; }

/* Los datos de apoyo —tamaño, fecha, descripcion— se apartan a la derecha para
 * que la columna de nombres se lea de arriba abajo sin saltar. */
.nodo > .nota { flex-shrink: 0; margin-left: auto; }
.nodo > .nota ~ .nota { margin-left: 0; }
.nodo-acciones { flex-shrink: 0; margin-left: var(--esp-8); }

/* El vacio, dentro del arbol, no ocupa los 32 px del `.vacio` general: aqui es
 * un renglon mas de una lista, no una pantalla sin nada. */
.arbol .vacio { padding: var(--esp-4) 0; text-align: left; }

/* --- iter procesal: la familia del expediente -------------------------
 * El mismo arbol que los documentos, con una diferencia: alli los niveles son
 * tres y estan puestos, y aqui son los que tenga la familia. Asi que la sangria
 * sale de `--nivel`, que pinta la plantilla en cada renglon —igual que en los
 * pasos del esquema—, y no de una clase por nivel.
 */
.arbol-iter .nodo { margin-left: calc(var(--nivel, 0) * var(--esp-24)); }
.arbol-iter .nodo > .etiqueta { flex-shrink: 0; margin: 0; }

/* Donde estas. Es el mismo par que subraya la pestaña activa y la opcion activa
 * del menu: fondo tenue del acento y el rotulo en acento fuerte. El fondo va en
 * el renglon y el color solo en el rotulo, para que las notas de la derecha
 * conserven `--texto-tenue`. */
.nodo--actual { background: var(--acento-tenue); }
.nodo--actual > .nodo-rotulo { color: var(--acento-fuerte); font-weight: 600; }

/* El hover no puede borrar el resalte: `.nodo:hover` pesa lo mismo y va despues,
 * asi que el renglon en el que estas se apagaba al pasar el raton por encima. */
.nodo--actual:hover { background: var(--acento-tenue); }

/* `--texto-debil` sobre el fondo del acento se queda por debajo de AA, y el
 * renglon resaltado es justo el que no puede aflojar: el chip de finalizado sube
 * un escalon solo ahi. */
.nodo--actual .etiqueta--apagada { color: var(--texto-tenue); border-color: var(--texto-tenue); }

/* --- la lista de lo que se va a subir ----------------------------------
 * Vive en el dialogo del boton «+». No es un formulario de tres preguntas sino
 * una tabla que se revisa —cuarenta ficheros con su nombre y su descripcion—, y
 * por eso el dialogo ancho: con las 46rem del normal las dos columnas que se
 * teclean quedan en dos dedos cada una.
 */
.dialogo-ancho { width: min(64rem, 96vw); }

/* Los dos botones de elegir, con su nota al lado. */
.zona-elegir {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--esp-8);
  margin-bottom: var(--esp-16);
}

/* Las dos columnas estrechas no gastan mas de lo suyo: lo que tiene que crecer
 * son el nombre y la descripcion, que es lo que se teclea. */
.lista-subida .col-marca { width: 1%; }
.lista-subida .col-tamano { width: 1%; white-space: nowrap; text-align: right; }
.lista-subida input[type="text"] { width: 100%; min-width: 8rem; margin: 0; }
/* La ruta del disco no empuja la tabla a lo ancho: parte por donde haga falta. */
.lista-subida .nombre-disco { overflow-wrap: anywhere; max-width: 18rem; }

/* Lo que no se puede subir. Se queda a la vista, apagado y con el motivo en el
 * hueco de la descripcion: quitarlo de la lista sin decir nada dejaria al
 * usuario contando ficheros para averiguar cual falta. */
.fila-invalida { background: var(--peligro-tenue); }
.fila-invalida .nombre-disco { color: var(--texto-tenue); text-decoration: line-through; }
.fila-invalida .motivo { color: var(--texto-peligro); }

#subir-lote > .acciones { margin-top: var(--esp-8); }

/* --- los dialogos de alto fijo -------------------------------------------
 *
 * **De alto fijo.** El resto de los dialogos crece con lo que traen, y ahi esta
 * bien: lo que llevan dentro es lo que es. Estos no, porque su lista la rehace
 * el filtro a cada pausa: con doscientas filas subian hasta el techo y con
 * ninguna colapsaban, o sea que la ventana crecia y menguaba **bajo el cursor
 * mientras se teclea**, y el campo de buscar se movia de sitio entre una letra y
 * la siguiente.
 *
 * El alto lo pone el dialogo y lo absorbe la lista: cabecera, filtros y pie se
 * quedan con el suyo y el hueco que sobra —o que falta— es el de la tabla, que
 * ya tiene su propio scroll. Con cero resultados queda un hueco vacio, y eso es
 * justo lo que se busca.
 *
 * Es una clase y no un id porque la condicion se repite: la tiene el archivo
 * documental y la tiene la lupa de destinatarios, que se abre con la tabla
 * vacia —la pide al abrirse— y por eso nacia colapsada del alto de su propia
 * cabecera. Cualquier dialogo cuyo cuerpo lo traiga un filtro la lleva.
 *
 * `[open]` y no a secas: `dialog:not([open])` es `display:none` por hoja del
 * navegador, y un `display:flex` sin condicion lo dejaria visible siempre.
 * `min-height: 0` en los que crecen: sin el, un hijo flexible no baja de lo que
 * mide su contenido y la tabla desborda el dialogo en vez de hacer scroll.
 * Y el tope de `.dialogo-cuerpo` se quita aqui dentro y solo aqui: esa clase la
 * comparten otros siete dialogos —partes, origenes, avisos, facturas…— donde el
 * tope de ahora vale.
 */
.dialogo-alto[open] {
  display: flex;
  flex-direction: column;
  height: 85vh;
}
.dialogo-alto .dialogo-cuerpo { flex: 1; min-height: 0; max-height: none; }
/* El archivo documental mete un envoltorio de mas entre el dialogo y la tabla
 * —es el trozo que sustituye HTMX al buscar—, y un intermediario que no crece
 * corta la cadena: el alto tiene que bajar por el hasta la lista. */
#cuerpo-archivo { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* Los nombres de fichero vienen largos —un PDF del BOE trae sesenta caracteres
 * sin un solo espacio— y empujaban la tabla a lo ancho. Parten por donde haga
 * falta, como ya hace la ruta del disco en la lista de al lado. */
.lista-archivo td { overflow-wrap: anywhere; }
/* La fecha, el numero y el tamaño no: partirlos es lo que los dejaba en una
 * columna de cifras sueltas. Lo que puede partir es el nombre, que es lo largo. */
.lista-archivo .col-tamano,
.lista-archivo .mono { white-space: nowrap; }

/* El numero del documento **es** el boton de elegirlo: la columna de «Elegir»
 * repetia el mismo rotulo cuarenta veces al final del renglon, que es el borde
 * que primero se pierde de vista. Aqui va el primero, que es donde no se pierde,
 * y de paso se lee: es el numero que se teclea en el buscador.
 *
 * `.enlace-codigo` le da la caja de un numero que se pulsa —cinco cifras de
 * ancho minimo, cuadrado por la derecha y el blanco tambien pulsable—, y esta
 * clase le quita la caja de boton, porque `.boton, button` le pinta borde y
 * fondo a **todo** `<button>` y aqui lo que tiene que parecer es el enlace que
 * es. Sigue siendo un `<button>` y no un `<a>`: no lleva a ningun sitio, hace
 * algo en esta pantalla. */
.lista-archivo .elegir-id {
  padding: var(--esp-4) var(--esp-8);
  border: 0;
  background: transparent;
  color: var(--acento);
  font-family: var(--fuente-mono);
  font-size: 0.85rem;
}
.lista-archivo .elegir-id:hover {
  color: var(--acento-fuerte);
  text-decoration: underline;
}

/* --- escribirle a un interviniente -------------------------------------
 * La pestaña de intervinientes tiene dos grupos de botones que no hacen lo
 * mismo: cuatro que **añaden** a alguien a la tabla y dos que le **escriben** al
 * que este marcado. Un separador entre los dos, porque seis iconos seguidos se
 * leen como una sola lista de la que hay que acordarse.
 */
.acciones-separador {
  width: 1px;
  align-self: stretch;
  min-height: 1.5rem;
  background: var(--borde-fuerte);
  margin: 0 var(--esp-4);
}

/* La fila elegida, **sin una linea de JavaScript**: el resalte lo pone el propio
 * radio marcado. Es lo que permite que elegir a quien se le escribe funcione
 * igual con el guion cargado y sin el.
 *
 * El color es el mismo `--fondo-hover` del paso del raton, un punto por encima
 * del `--acento-tenue` para que la fila marcada no compita con el foco del
 * teclado, que si tiene que destacar. */
.tabla-elegible tbody tr:has(input[type="radio"]:checked) {
  background: var(--fondo-hover);
}
.tabla-elegible .col-marca { width: 1%; }
/* La celda entera es el rotulo: se elige la fila pulsando en cualquier sitio del
 * nombre y no solo en el circulito, que en una tabla densa es un blanco de tres
 * milimetros. */
.tabla-elegible label { display: block; cursor: pointer; }

/* --- las opciones del dialogo de redaccion -----------------------------
 * Copia, adjuntos y las dos de mas abajo van en `<details>` cerrados. El correo
 * corriente es «para uno, con un texto», y sacar cuatro bloques a la vista seria
 * cobrarle a todo el mundo lo que se usa una vez de cada diez. Cerrado ocupa un
 * renglon, y es el propio elemento el que lo abre: aqui tampoco hay guion.
 */
.opciones-envio {
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  margin-bottom: var(--esp-8);
}
.opciones-envio > summary {
  padding: var(--esp-8) var(--esp-16);
  cursor: pointer;
  color: var(--texto-tenue);
}
.opciones-envio > summary:hover { background: var(--fondo-hover); }
/* Lo de dentro, separado del borde y del renglon de arriba. Las tablas traen su
 * propio `.tabla-envoltorio`, asi que el hueco se le da al bloque entero. */
.opciones-envio > *:not(summary) { margin: var(--esp-8) var(--esp-16); }

/* Un expediente con cuarenta documentos no puede empujar el boton de Enviar
 * fuera de la pantalla: la lista se queda con su alto y desplaza dentro, como
 * hace `.dialogo-cuerpo` con el texto del correo. */
.opciones-envio .tabla-envoltorio { max-height: min(18rem, 40vh); overflow-y: auto; }

/* Las dos columnas estrechas de sus tablas, como en la lista de subida: lo que
 * tiene que crecer es el nombre, que es lo que se lee. */
.opciones-envio .col-marca { width: 1%; text-align: center; }
.opciones-envio .col-tamano { width: 1%; white-space: nowrap; text-align: right; }
/* La celda entera es el rotulo, como en `.tabla-elegible` y por lo mismo: en una
 * tabla densa el cuadradito es un blanco de tres milimetros. Se limita a la
 * tabla —`td label`— para no ganarle a `.casilla`, que va en linea. */
.opciones-envio td label { display: block; cursor: pointer; }

/* Una casilla con su rotulo al lado, en linea. El 4 entre las dos es el mismo
 * que en `.opciones`: casilla y rotulo son una sola cosa y tienen que leerse
 * asi. */
.casilla {
  display: flex;
  align-items: center;
  gap: var(--esp-4);
  font-weight: normal;
  cursor: pointer;
}

/* --- la lupa de destinatarios ------------------------------------------
 * La relacion de personas metida en un dialogo. Trae las **siete** columnas de
 * la pantalla de personas, y con las 64rem de `.dialogo-ancho` no cabian: la
 * tabla salia con scroll horizontal y ademas con el apellido caido al renglon de
 * abajo, o sea lo peor de las dos cosas —se desplaza a lo ancho **y** cada ficha
 * ocupa dos lineas—.
 *
 * Lo que se hace aqui no es darle mas ancho sino **repartirlo**, que es distinto:
 * mas ancho no arregla nada porque un nombre de cinco apellidos y un correo de
 * sesenta caracteres se llevan lo que se les de y vuelven a empujar a los roles
 * fuera de la ventana. Con el reparto, cada columna tiene lo suyo pase lo que
 * pase, y lo que no cabe se recorta con puntos suspensivos y se lee en el globo
 * del `title`. La ultima columna se ve **siempre**, que es lo unico que se pedia.
 */
.lupa-personas { width: min(84rem, 98vw); }

/* `fixed` es lo que hace que la tabla no crezca con lo que trae: los anchos salen
 * del `<colgroup>` y el contenido se acomoda a ellos, en vez de al reves. Es lo
 * que garantiza que no hay nada a la derecha del borde.
 *
 * Y un suelo, porque el reparto por si solo llega demasiado lejos: en porcentaje,
 * una ventana estrecha deja la columna de roles en cuatro dedos y la etiqueta
 * —que no parte, ver `.etiqueta`— se corta. Las 60rem son la medida de eso: por
 * debajo la tabla deja de encoger y es el envoltorio el que desplaza, con su
 * barra a la vista. */
.lupa-personas table { table-layout: fixed; min-width: 60rem; }

/* El reparto. Suma 100 y esta medido sobre las 84rem: al correo le tocan unas 40
 * columnas de texto monoespaciado, que es el limite que se le pide; al nombre,
 * de largo la columna que mas se lee, un poco mas; y a los roles lo justo para
 * una etiqueta por renglon. Los cuatro datos cortos —NIF, poblacion, pais y
 * telefono— no dan para mas ni lo necesitan. */
.lupa-personas .col-nombre { width: 24%; }
.lupa-personas .col-nif { width: 9%; }
.lupa-personas .col-poblacion { width: 12%; }
.lupa-personas .col-pais { width: 8%; }
.lupa-personas .col-telefono { width: 11%; }
.lupa-personas .col-correo { width: 24%; }
.lupa-personas .col-roles { width: 12%; }

/* Lo que se sale de su columna se corta ahi, con puntos suspensivos, y no encima
 * de la de al lado: con `fixed` el sobrante no ensancha la celda pero se pinta
 * igual si no se le dice que no. Lo que puede partir —poblacion, pais, las
 * etiquetas de rol— parte por donde haga falta y crece hacia abajo, como ya hace
 * la lista del archivo documental; ahi no se pierde nada. */
.lupa-personas tbody td {
  overflow: hidden;
  text-overflow: ellipsis;
  overflow-wrap: anywhere;
}

/* El nombre, en una linea: es lo que se lee para reconocer a quien se busca, y
 * partido por la mitad hay que leerlo dos veces. Si no cabe, puntos suspensivos
 * y el nombre entero en el globo (`title`, ver `personas_relacion.html`). */
.lupa-personas td.col-nombre {
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* El correo, a cuarenta caracteres —`40ch` es literalmente eso en la columna
 * monoespaciada en que se pinta— o a lo que quepa si la ventana se encoge, y
 * entero en su globo. El recorte necesita el `<span>` que pone la macro: un
 * `max-width` sobre el `<td>` no lo respeta el navegador. */
.lupa-personas .col-correo span {
  display: inline-block;
  max-width: 40ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
/* La pantalla de personas tiene todo el ancho y antes enseñaba el correo
 * entero; desde que se pide limitarlo a cuarenta, se recorta igual que en la
 * lupa —puntos suspensivos y el resto en su globo (`title`, ver
 * `personas_relacion.html`)—. */
#tabla-partes .col-correo span {
  display: inline-block;
  max-width: 40ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* El pie de paginas de la relacion de personas. Va dentro de `#tabla-partes`
 * —que es lo que HTMX reemplaza al buscar— pero fuera de `.tabla-envoltorio`,
 * que desplaza en horizontal y se llevaria los saltos de viaje con una tabla
 * ancha. Ver `usuario/partes.html`. */
.paginador {
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  flex-wrap: wrap;
  margin-top: var(--esp-16);
}

/* El recuento a la izquierda y los cuatro saltos a la derecha. */
.paginador .rotulo {
  margin-right: auto;
  color: var(--texto-tenue);
  font-size: 0.88rem;
}

/* El salto que no lleva a ninguna parte ocupa su sitio, apagado: quitarlo haria
 * bailar a los otros tres cada vez que se llega al principio o al final. */
.paginador [aria-disabled="true"] {
  color: var(--texto-debil);
  background: transparent;
  cursor: default;
  pointer-events: none;
}

/* Los datos cortos no parten aunque no quepan: un telefono en dos renglones se
 * lee como dos numeros. Poblacion y pais si pueden partir, que son palabras. */
.lupa-personas td.mono { white-space: nowrap; }

/* Sin barra a la vista, pero desplazando igual: rueda, teclas y arrastre siguen
 * funcionando, y lo unico que se quita es el dibujo. Se puede porque la lista no
 * acaba nunca en el borde —debajo esta el pie que dice que se hace con ella— y
 * porque la barra partia en dos el lado derecho de una ventana que ocupa casi
 * toda la pantalla.
 *
 * **Solo cuando la tabla cabe entera**, que es lo que asegura el `@media`.
 * `scrollbar-width` no distingue una barra de la otra: quitarla siempre quitaria
 * tambien la de abajo, y una barra escondida encima de columnas que no se ven es
 * justo la trampa que este bloque viene a arreglar. El numero sale de las cuentas
 * y no del gusto: de 1200 en adelante, la ventana mas estrecha que el usuario
 * puede dejar arrastrando la esquina —64rem— tiene 974 px de hueco util, y la
 * tabla no baja de 960. `-webkit-` es para Safari, que aun no entiende lo
 * estandar. */
@media (min-width: 1200px) {
  .lupa-personas .dialogo-cuerpo { scrollbar-width: none; }
  .lupa-personas .dialogo-cuerpo::-webkit-scrollbar { width: 0; height: 0; }
}

/* --- y que el usuario la ajuste ---
 * El tirador de la esquina, con el tamaño de siempre como **techo**: la ventana
 * ya nace ocupando casi toda la pantalla, asi que crecer no es a donde se puede
 * ir; lo que a veces hace falta es lo contrario, encogerla para ver lo que tapa.
 * El suelo son las 64rem del dialogo ancho de siempre, y tampoco es un gusto:
 * es el ancho a partir del cual las siete columnas siguen cabiendo enteras (ver
 * el `@media` de aqui arriba). Encogerla mas no enseñaria menos, enseñaria una
 * barra de scroll debajo.
 *
 * `resize` no hace nada sobre un `overflow: visible`, de ahi el `hidden`; y no
 * recorta nada porque lo que puede desbordar —la lista— desborda dentro de
 * `.dialogo-cuerpo`, que tiene el suyo.
 *
 * Lo que el usuario arrastra se queda en un `style` en linea, o sea que le gana
 * a estas reglas y **no** sobrevive a cerrar el dialogo. Es lo que se quiere de
 * una ventana que se abre para elegir una fila y se cierra: cada vez empieza en
 * el tamaño bueno. */
.lupa-personas[open] {
  resize: both;
  overflow: hidden;
  max-width: min(84rem, 98vw);
  min-width: min(64rem, 92vw);
  max-height: 85vh;
  min-height: 20rem;
}

/* --- los hilos de la pestaña de llamadas y correos ---------------------
 * Un hilo es un `<details>`: cerrado ocupa un renglon y abierto ensena sus
 * mensajes. Sin acordeon de JavaScript, que es lo que el elemento ya hace.
 */
.hilo {
  border: 1px solid var(--borde);
  border-radius: 6px;
  background: var(--fondo-elevado);
  margin-bottom: var(--esp-8);
}
.hilo > summary {
  display: flex;
  align-items: baseline;
  gap: var(--esp-8);
  padding: var(--esp-8) var(--esp-16);
  cursor: pointer;
}
.hilo > summary:hover { background: var(--fondo-hover); }
.hilo-asunto { font-weight: 600; }
/* Fecha y recuento a la derecha, como en el arbol de documentos y por lo mismo:
 * asi la columna de asuntos se lee de arriba abajo sin saltar. */
.hilo > summary > .nota:last-child,
.hilo > summary > .nota:nth-last-child(2) { margin-left: 0; }
.hilo > summary > .nota:nth-last-child(2) { margin-left: auto; }

.mensaje {
  padding: var(--esp-8) var(--esp-16);
  border-top: 1px solid var(--borde);
}
/* Lo que sale del despacho se sangra a la derecha, como en cualquier mensajeria:
 * es lo que distingue de un vistazo lo dicho de lo oido, sin leer la etiqueta.
 * Hoy todo es saliente —no hay ingesta— y por eso la regla es del entrante, que
 * es la excepcion futura. */
.mensaje-entrante { background: var(--fondo-elevado-2); }
.mensaje-cabecera {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--esp-8);
  margin-bottom: var(--esp-4);
}
.mensaje-asunto { margin: 0 0 var(--esp-4); font-weight: 600; }

/* El estado de la entrega, a la derecha de la cabecera del mensaje. Es lo que un
 * envio asincrono le debe al usuario: pulsar Enviar no es que haya salido. */
.estado-envio {
  margin-left: auto;
  font-size: 0.82rem;
  color: var(--texto-tenue);
  white-space: nowrap;
}
.estado-envio.exito { color: var(--exito); }
.estado-envio.peligro { color: var(--peligro); }

/* Los adjuntos que viajaron con el mensaje. Lista sin topos: son dos o tres
 * nombres debajo del texto, y los puntos los leerian como una enumeracion del
 * cuerpo. El tamaño al lado, tenue, que es lo que distingue el escrito de doce
 * folios del acuse de dos lineas. */
.adjuntos-mensaje {
  list-style: none;
  margin: var(--esp-8) 0 0;
  padding: 0;
  font-size: 0.9rem;
}
.adjuntos-mensaje li {
  display: flex;
  align-items: baseline;
  gap: var(--esp-8);
}

/* --- los recordatorios del aviso --------------------------------------
 * Un renglon es «Notificación · 30 · minutos · antes · ✕», todo en una linea y
 * en el orden en que se lee. Los campos no crecen: una antelacion son tres
 * palabras cortas, y estirarlos al ancho de la tarjeta separaria tanto el numero
 * de su unidad que dejarian de leerse juntos.
 */
.recordatorio {
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  flex-wrap: wrap;
  margin-bottom: var(--esp-8);
}
/* `hidden` gana sobre el `display: flex` de arriba, que si no lo pisaria: es el
 * guion quien esconde los renglones vacios, y sin esto no se esconderia ninguno.
 * Sin JavaScript nadie pone el atributo y se ven los cinco, que es lo que hace
 * que la pantalla siga entera. */
.recordatorio[hidden] { display: none; }
.recordatorio select { width: auto; }
/* Lo justo para tres cifras. Un aviso se recuerda dias antes, no mil.
 *
 * El selector lleva el `input[type=...]` y no solo la clase **a proposito**: la
 * regla general de los campos es `input[type="number"] { width: 100% }`, que pesa
 * mas que una clase suelta, y sin esto la casilla se come el renglon entero y lo
 * parte en tres lineas. */
.recordatorio input[type="number"].recordatorio-cantidad {
  width: 5rem;
  flex: 0 0 auto;
}
/* «antes» es la palabra que convierte tres campos en una frase, asi que se pega
 * a la unidad en vez de irse al final de la fila cuando esta envuelve. */
.recordatorio-antes { margin: 0; }

/* Los dos botones **solo sirven con JavaScript** —sin el se anade y se quita
 * escribiendo o borrando la cantidad— asi que se pintan siempre y los ensena
 * esto, colgando de `.con-js`, igual que `.marca-todo`. Un boton que no hace
 * nada al pulsarlo engana mas que uno que falta. */
.recordatorio-quitar,
.recordatorio-anadir { display: none; }
.con-js .recordatorio-quitar,
.con-js .recordatorio-anadir { display: inline-flex; align-items: center; }

.recordatorio-quitar {
  padding: var(--esp-4) var(--esp-8);
  line-height: 1;
  color: var(--texto-tenue);
}
.recordatorio-quitar:hover { color: var(--texto); }

.recordatorio-anadir { margin-top: var(--esp-8); }
/* `hidden` gana: cuando ya estan los cinco a la vista no hay nada que anadir, y
 * el guion lo dice poniendo el atributo. Hace falta decirlo porque la regla de
 * arriba trae un `display` que si no lo pisaria. */
.con-js .recordatorio-anadir[hidden] { display: none; }

/* --- impresion: siempre en claro --------------------------------------
 * Es un despacho que imprime caratulas, escritos y listados. Mandar a la
 * impresora una pantalla oscura gasta toner y sale mal.
 */

@media print {
  :root {
    --fondo: #fff;
    --fondo-elevado: #fff;
    --fondo-elevado-2: #fff;
    --fondo-hover: #fff;
    --texto: #000;
    --texto-tenue: #333;
    --texto-debil: #555;
    --borde: #999;
    --borde-fuerte: #666;
    --sombra: none;
  }

  body { background: #fff; color: #000; font-size: 11pt; }

  .lateral,
  .barra-superior,
  .acciones,
  .barra-acciones,
  .pestanas,
  .barra form,
  .boton,
  button,
  .no-imprimir { display: none !important; }

  /* Sin la lateral no hay dos columnas que repartir: el contenido ocupa la
   * hoja entera y no una pista de la rejilla con un hueco al lado. */
  .armazon { display: block; }

  main { max-width: none; padding: 0; }

  .tarjeta, .tabla-envoltorio { border: 1px solid #999; box-shadow: none; }
  th { background: #eee; color: #000; }
  tbody tr:hover { background: transparent; }

  a { color: #000; text-decoration: none; }
  /* En papel un enlace sin su destino no sirve de nada. */
  main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }

  table { page-break-inside: auto; }
  tr { page-break-inside: avoid; }
  thead { display: table-header-group; }
}

/* --- el asistente -----------------------------------------------------
 * Dos columnas: la conversacion y lo que se ha hecho. **Que va a leer no esta
 * aqui**: vive en la lateral de la web, debajo del menu, que es la columna en
 * la que se elige. Sacandolo de la rejilla el hilo pasa de unos 600 px a casi
 * todo el ancho de `main`.
 *
 * La derecha es un cajon —un `<details>`— que se abre de derecha a izquierda:
 * cerrado deja una lengueta en el filo y abierto entra el panel. En cuanto
 * existe —en cuanto hay algo que mostrar en el—, el cajon **reserva su carril
 * de 20rem** tanto abierto como cerrado: abrirlo y cerrarlo no mueve la
 * conversacion de al lado. El `width` del cajon es quien reserva el carril, no
 * la pista `auto` de la rejilla, y la separacion con el centro va como margen
 * suyo y no como `gap` de la rejilla: asi un cajon con `hidden` —sin contenido
 * aun— no deja ni carril ni hueco. Es lo que hace que «no existe hasta que hay
 * algo en ella» sea cierto de verdad y no solo un titulo que no se pinta.
 *
 * En estrecho, una sola columna y el cajon con `order` detras del hilo: su
 * contenido vuelve a la conversacion sin duplicar un solo nodo.
 */
.asistente {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
}

/* --- la pantalla que ocupa el alto de la ventana --------------------------
 * **La unica de la aplicacion.** En el resto se desplaza la pagina; aqui no,
 * porque de las tres zonas de un chat dos no se pueden ir hacia arriba cuando
 * el hilo crece: el rotulo de la conversacion y el hueco de escribir. Lo que
 * se desplaza es el hilo, y nada mas.
 *
 * La cadena de alturas va entera y no se puede saltar ningun eslabon: la
 * columna toma el alto de la ventana, `main` se queda con lo que sobra despues
 * de la barra de arriba, la rejilla con lo que sobra dentro de `main`, y el
 * hilo con lo que sobra en su pista. Cada uno de esos escalones lleva
 * `min-height: 0`, que es lo que permite a un hijo desplazarse por dentro en
 * vez de estirar a su padre: por defecto un elemento de rejilla o de caja
 * flexible no se encoge por debajo de su contenido, y sin esto la barra de
 * desplazamiento aparecia en la ventana y no en el hilo.
 *
 * La clase la pone la plantilla (`block clase_cuerpo`) y no un `:has()`: donde
 * `:has()` no llegara, la pantalla se quedaria con el recuadro de escribir en
 * mitad de la nada. Ver `usuario/asistente.html`.
 *
 * **En estrecho se apaga sola**, en el mismo corte de 60rem que junta las
 * columnas: alli la lateral es la primera fila y ya no queda ventana que
 * repartir, asi que vuelve a desplazarse la pagina y el recuadro se queda
 * pegado abajo con `position: sticky`.
 */
body.pantalla-asistente .columna {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
body.pantalla-asistente main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Menos hueco arriba y abajo que en el resto de la aplicacion: aqui cada
     pixel de alto es un renglon mas de conversacion. */
  padding: var(--esp-16) var(--esp-24);
}
body.pantalla-asistente .asistente {
  flex: 1;
  min-height: 0;
}
/* La conversacion se estira a su pista; el cajon de la derecha no, que sigue
   midiendo lo que mide su contenido. */
body.pantalla-asistente .asistente-hilo { align-self: stretch; min-height: 0; }
/* Y si lo que se ha hecho es mas largo que la ventana, se desplaza el panel y
   no la pantalla. El tope es un dibujo —la barra de arriba, el hueco de `main`
   y la lengueta—, como el ancho de la lateral. */
body.pantalla-asistente .asistente-hecho {
  max-height: calc(100vh - 10rem);
  overflow-y: auto;
}

/* Dentro de la lateral el panel ya esta sobre una superficie elevada, asi que
 * la caja sobraria: lo que lo separa del menu es un filo y el hueco de panel.
 * Fuera de ahi conserva su recuadro, que es como se pinta el de la derecha. */
.lateral .asistente-contexto {
  background: none;
  border: 0;
  border-top: 1px solid var(--borde);
  border-radius: 0;
  padding: var(--esp-16) 0 0;
}

.asistente-contexto,
.asistente-hecho {
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: var(--esp-16);
}

.asistente-hecho { width: 20rem; }

/* --- el cajon de la derecha -------------------------------------------
 * La derecha es un cajon que se abre de derecha a izquierda: cerrado deja en
 * el filo una lengueta vertical con su rotulo, y al abrirlo entra el panel de
 * 20rem dentro del carril que el propio cajon reserva. La conversacion de al
 * lado, la pista `1fr`, no se mueve.
 *
 * Todo el mecanismo es del navegador: un `<details>`, ni una linea de
 * JavaScript. El deslizamiento va en `::details-content`, el pseudoelemento
 * que envuelve lo que el `<details>` esconde: se le anima el ancho de 0 a
 * 20rem, con `content-visibility` en la misma transicion y marcado
 * `allow-discrete` para que al cerrar el contenido no se apague de golpe a
 * mitad de camino. Donde ese pseudoelemento no exista —un navegador de hace
 * dos anos— la regla entera se descarta y el cajon abre y cierra igual, sin
 * deslizarse: se pierde el adorno, no la funcion.
 *
 * `overflow: clip` es lo que lo hace un cajon y no un panel que se encoge: el
 * `.asistente-hecho` conserva sus 20rem mientras el hueco crece, asi que lo
 * que se ve es el panel entrando entero y no su contenido recolocandose
 * renglon a renglon.
 */
.asistente-cajon {
  /* El carril se reserva aqui, en el cajon y no en la pista de la rejilla:
     con contenido, abierto y cerrado miden lo mismo (20rem) y cerrar no mueve
     la conversacion; sin contenido, el `[hidden]` lo saca del todo y no queda
     hueco. La separacion con el centro tambien vive aqui y no en el `gap`. */
  width: 20rem;
  margin-left: var(--esp-24);
}
.asistente-cajon[hidden] { display: none; }
/* Cerrado, el cajon conserva su carril de 20rem y la lengueta se arrima al
   filo derecho dentro de el; el hueco que queda a su izquierda es el carril
   reservado, no un margen que se pierde. */
.asistente-cajon:not([open]) {
  display: flex;
  justify-content: flex-end;
}

.asistente-lengueta {
  display: flex;
  align-items: center;
  gap: var(--esp-4);
  padding: var(--esp-8) var(--esp-4);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--fondo-elevado);
  color: var(--texto-tenue);
  cursor: pointer;
  white-space: nowrap;
  /* Sin el triangulito del `<details>`: la flecha del cajon ya dice de que
     lado se abre, y son dos marcas para lo mismo. */
  list-style: none;
}
.asistente-lengueta::-webkit-details-marker { display: none; }
.asistente-lengueta .flecha { font-size: 1.1em; line-height: 1; }
.asistente-lengueta:hover { background: var(--fondo-hover); color: var(--texto); }

/* Cerrado el rotulo va de canto: la lengueta queda como una franja vertical
 * arrimada al filo derecho de su carril, en vez de un renglon horizontal que
 * ocuparia el carril entero. La flecha vuelve a la horizontal para que el
 * signo no salga girado con el resto del renglon. */
.asistente-cajon:not([open]) > .asistente-lengueta { writing-mode: vertical-rl; }
.asistente-cajon:not([open]) > .asistente-lengueta .flecha { writing-mode: horizontal-tb; }

/* Abierto la lengueta deja de ser un boton y pasa a ser el renglon de cerrar,
 * arrimado al filo derecho encima del panel. */
.asistente-cajon[open] > .asistente-lengueta {
  justify-content: flex-end;
  background: none;
  border-color: transparent;
  padding: 0 0 var(--esp-4);
  font-size: .85rem;
}
.asistente-cajon:not([open]) .abierto,
.asistente-cajon[open] .cerrado { display: none; }
/* La flecha apunta a donde va el panel: cerrada hacia la izquierda —de ahi
 * viene—, abierta hacia la derecha, que es por donde se va. */
.asistente-cajon[open] .flecha { rotate: 180deg; }

.asistente-cajon::details-content {
  width: 0;
  overflow: clip;
  opacity: 0;
  transition: width .2s ease, opacity .2s ease,
              content-visibility .2s allow-discrete;
}
.asistente-cajon[open]::details-content { width: 20rem; opacity: 1; }

/* «+ Nuevo», la primera linea de la columna. Ancho completo y centrado: es la
 * unica accion del panel, y las conversaciones de antes estan al final de esta
 * misma columna. */
.asistente-nuevo {
  display: block;
  text-align: center;
  padding: var(--esp-8);
  margin-bottom: var(--esp-16);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  color: var(--texto);
  font-size: .9rem;
}
.asistente-nuevo:hover { background: var(--fondo-hover); text-decoration: none; }

.asistente-titulo {
  font-size: 1rem;
  margin: 0 0 var(--esp-8);
}

.asistente-grupo {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--texto-tenue);
  margin: var(--esp-16) 0 var(--esp-4);
}

.asistente-hilos,
.asistente-acciones {
  list-style: none;
  margin: 0;
  padding: 0;
}

.asistente-hilos a {
  display: block;
  padding: var(--esp-4) 0;
  color: var(--texto-tenue);
}
.asistente-hilos a.activo { color: var(--acento-fuerte); }

/* Cada conversación es una fila: el nombre y, al pasar el cursor, el menú de
 * tres puntos junto a él. El nombre se lleva el hueco que sobra y la fila
 * entera es la diana del `:hover`, para que el menú no desaparezca al acercarse
 * a él. */
.asistente-hilo-entrada {
  display: flex;
  align-items: center;
  gap: var(--esp-4);
}
.asistente-hilo-entrada > a {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.asistente-hilo-entrada > a:hover { color: var(--texto); text-decoration: none; }

/* Los tres puntos no existen hasta que se pasa el cursor por la fila; en un
 * menú abierto se quedan, y sin ratón —teclado o lector de pantalla— la
 * puntera los saca siempre para que sigan siendo alcanzables. */
.asistente-hilo-menu { visibility: hidden; }
.asistente-hilo-entrada:hover .asistente-hilo-menu,
.asistente-hilo-entrada:focus-within .asistente-hilo-menu,
.asistente-hilo-menu[open] { visibility: visible; }

/* El desplegable se arrima a la derecha de la columna —el `right: 0` que trae
 * el patrón—, de modo que las opciones quedan enteras dentro de la lateral y no
 * se cortan contra el filo. */
.asistente-hilo-menu .menu-acciones-lista {
  right: 0;
  left: auto;
}

/* La caja de renombrar sustituye al nombre en su propio hueco: ocupa el renglón
 * entero y no lleva botón —Enter graba—. */
.asistente-renombrar-lista {
  flex: 1;
  min-width: 0;
  margin: 0;
}
.asistente-renombrar-lista[hidden] { display: none; }
.asistente-renombrar-lista input {
  width: 100%;
  margin: 0;
  padding: var(--esp-4) var(--esp-8);
  font-size: inherit;
}
.asistente-hilo-nombre[hidden] { display: none; }

/* --- la conversacion: cabecera, hilo y hueco de escribir -------------------
 * Las tres, en una columna. La de en medio es la que se lleva el hueco que
 * sobra y la unica que se desplaza; las otras dos no crecen ni se encogen.
 */
.asistente-hilo {
  display: flex;
  flex-direction: column;
  gap: var(--esp-16);
  min-width: 0;
}

/* La cabecera: el avatar, el rotulo de la conversacion y el «⋮». El rotulo se
   lleva el hueco que sobra y se corta con puntos suspensivos si no cabe, que
   es lo que hace que el menu no se vaya de la pantalla con un titulo largo. */
.asistente-cabecera {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--esp-8);
  padding-bottom: var(--esp-8);
  border-bottom: 1px solid var(--borde);
}

.asistente-avatar {
  display: grid;
  place-items: center;
  width: var(--esp-32);
  height: var(--esp-32);
  border-radius: 50%;
  background: var(--acento-tenue);
  font-size: 1rem;
}

.asistente-rotulo {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* El hilo. `flex: 1` con `min-height: 0` es lo que le da el hueco que sobra y
   le deja desplazarse por dentro en vez de estirar la columna. La barra de
   desplazamiento no se pinta: se sigue pudiendo desplazar, pero sin la barra
   pegada al texto. */
.asistente-mensajes {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--esp-16);
  padding-right: var(--esp-8);
  scrollbar-width: none;
}
.asistente-mensajes::-webkit-scrollbar { width: 0; height: 0; }

/* Lo ultimo que ha llegado entra con un desvanecido corto. Es lo unico que
   suaviza el salto de la pantalla en blanco a la conversacion —el centrado no
   se puede animar—, y de paso hace visible que ha llegado algo cuando se
   estaba mirando otra cosa. */
.asistente-mensajes > :last-child { animation: mensaje-entra .18s ease-out; }
/* Menos el bloque de la espera, que **se sustituye cada pocos segundos** con lo
   que el bucle lleva hecho: desvanecerlo en cada vuelta seria un parpadeo, no
   una entrada. Lo que ahi dice que sigue vivo son los puntitos. */
.asistente-mensajes > .escribiendo { animation: none; }

@keyframes mensaje-entra {
  from { opacity: 0; transform: translateY(var(--esp-8)); }
  to { opacity: 1; transform: none; }
}

.mensaje-ia {
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: var(--esp-16);
  background: var(--fondo-elevado);
}

.mensaje-ia p { margin: 0; white-space: pre-wrap; }

/* **Lo que pregunta el usuario va a la derecha**, en un globo suyo y con el
   color de acento apagado: es la unica marca de quien habla que no hay que
   leer para entenderla. No pasa de 42rem para que una pregunta larga no cruce
   la pantalla entera y siga leyendose como un mensaje y no como un parrafo. */
.mensaje-ia.de-usuario {
  align-self: flex-end;
  max-width: min(42rem, 85%);
  padding: var(--esp-8) var(--esp-16);
  background: var(--acento-tenue);
  border-color: var(--acento-tenue);
  /* La esquina de abajo a la derecha sin redondear: apunta a quien lo dijo. */
  border-radius: var(--radio) var(--radio) 2px var(--radio);
}

/* Las notas del sistema —un escrito que se archivo, un Detener— no son de
   nadie de los dos: van centradas, pequeñas y sin pedir turno. */
.mensaje-ia.de-documento,
.mensaje-ia.de-parada {
  align-self: center;
  padding: var(--esp-4) var(--esp-16);
  background: none;
  color: var(--texto-tenue);
  font-size: .9rem;
}

/* La respuesta de la IA **no lleva caja**, y va a la izquierda. Es lo unico de
   esta pantalla que se lee entero: enmarcada quedaba al mismo nivel que el
   rastro de herramientas de al lado, que es de mirar y no de leer. La
   separacion con lo de arriba y lo de abajo la pone el `gap` de
   `.asistente-mensajes`, no un borde. El tope de ancho es de lectura: unos
   ochenta caracteres por renglon. */
.mensaje-ia.de-asistente {
  align-self: flex-start;
  max-width: 46rem;
  width: 100%;
  border: 0;
  border-radius: 0;
  padding: 0;
  background: none;
}

/* La hilera de iconos que cuelga debajo de cada respuesta de la IA: copiarla y
   mirar de qué fuentes salió. Copiar sólo con JavaScript —`.con-js` lo muestra,
   como las sugerencias—; las fuentes son un `<details>` que funciona sin guión. */
.mensaje-ia-pie {
  display: flex;
  align-items: center;
  gap: var(--esp-4);
  margin-top: var(--esp-8);
}

.copiar-mensaje { display: none; }
.con-js .copiar-mensaje { display: inline-flex; }

/* El icono de copiar se cambia por el visto mientras se confirma la copia. Los
   dos ocupan el mismo sitio: el que no toca se quita del todo. El botón y el
   icono van con su clase completa porque `.boton.icono svg` (más arriba) los
   pinta `block` a todos, y sin la especificidad justa el visto saldría pegado
   a los dos cuadrados. */
.boton.icono.copiar-mensaje .icono-copiado { display: none; }
.boton.icono.copiar-mensaje.copiado .icono-copia { display: none; }
.boton.icono.copiar-mensaje.copiado .icono-copiado { display: block; }
.copiar-mensaje.copiado { color: var(--exito); border-color: var(--exito); }

/* El panel de fuentes flota debajo del icono, igual que el menú de acciones:
   así abrirlo no empuja al mensaje siguiente. */
.mensaje-ia-fuentes { position: relative; display: inline-flex; align-items: center; }
.mensaje-ia-fuentes summary {
  display: flex;
  align-items: center;
  justify-content: center;
  list-style: none;
  cursor: pointer;
}
.mensaje-ia-fuentes summary::marker,
.mensaje-ia-fuentes summary::-webkit-details-marker { content: none; display: none; }
.mensaje-ia-fuentes-lista {
  position: absolute;
  left: 0;
  top: calc(100% + var(--esp-4));
  z-index: 10;
  padding: var(--esp-8) var(--esp-12);
  max-width: calc(100vw - var(--esp-32));
  background: var(--fondo-elevado-2);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
}
.mensaje-ia-fuentes-grupo {
  margin: var(--esp-8) 0 var(--esp-4);
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--texto-debil);
}
.mensaje-ia-fuentes-grupo:first-child { margin-top: 0; }
.mensaje-ia-fuentes-lista ul { margin: 0; padding-left: var(--esp-16); }
/* Cada fuente en un solo renglón: el rótulo no se parte en dos porque el panel
   no alcance. El panel crece hasta el ancho de la ventana, así que un nombre
   largo se corta sólo si no cabe en toda la pantalla. */
.mensaje-ia-fuentes-lista li { margin: 0; white-space: nowrap; }

/* Una cita que no se pudo comprobar (decisión 037). Sólo sale cuando el bucle
   se quedó sin vueltas para pedirle al modelo que la corrigiera, así que es
   raro y tiene que verse: va pegado debajo de la respuesta y en el color de
   atención, no en rojo —la respuesta no está mal, hay una afirmación que no se
   ha podido respaldar—. */
.mensaje-ia-cita-mala {
  margin: var(--esp-8) 0 0;
  padding: var(--esp-8) var(--esp-12);
  font-size: .875rem;
  color: var(--aviso);
  background: var(--fondo-elevado-2);
  border-left: 3px solid var(--aviso);
  border-radius: var(--radio);
}

/* Mientras se espera. El globo lo pone `asistente.js` al mandar el mensaje, lo
   repinta el sondeo con lo que el bucle va haciendo, y lo sustituye la respuesta
   al llegar. Ver `asistente_sonda.html`. */
.mensaje-ia.escribiendo { padding: var(--esp-8) 0; }

.asistente-trabajando {
  margin: 0 0 var(--esp-8);
  color: var(--texto-debil);
}

/* Lo que lleva hecho, una linea por herramienta ejecutada. En pequeño y tenue:
   es el pie de una espera y no la conversacion, y en cuanto llegue la respuesta
   desaparece entero —el rastro de verdad esta en `ia_mensajes` y lo terminal se
   ve en el cajon de la derecha—. */
.asistente-actividad {
  list-style: none;
  margin: 0 0 var(--esp-8);
  padding: 0;
  display: grid;
  gap: var(--esp-4);
  font-size: .8125rem;
  color: var(--texto-debil);
}
.asistente-actividad li {
  display: grid;
  grid-template-columns: 1rem 1fr;
  gap: var(--esp-8);
  margin: 0;
}
.asistente-actividad .marca { color: var(--exito); }
.asistente-actividad .marca.fallo { color: var(--aviso); }

/* Detener, dentro de la propia sonda: es donde se esta mirando mientras se
   espera. Pequeño y sin peso —no es la accion principal de la pantalla, es la
   salida—, y separado de los puntitos para que no parezca parte de ellos. */
.asistente-parar { margin: var(--esp-8) 0 0; }
.asistente-parar button {
  padding: var(--esp-4) var(--esp-8);
  font-size: .8125rem;
  color: var(--texto-tenue);
}

.puntos { display: inline-flex; gap: var(--esp-4); }
.puntos i {
  width: var(--esp-8);
  height: var(--esp-8);
  border-radius: 50%;
  background: var(--texto-debil);
  animation: latido 1.2s infinite ease-in-out;
}
.puntos i:nth-child(2) { animation-delay: .15s; }
.puntos i:nth-child(3) { animation-delay: .3s; }

@keyframes latido {
  0%, 60%, 100% { opacity: .3; transform: none; }
  30% { opacity: 1; transform: translateY(-2px); }
}

/* El Markdown del modelo, ya convertido en HTML por `app/web/marcado.py`. Va con
   los ritmos de la casa y sin `pre-wrap`: los saltos ya son parrafos. */
.marcado p { margin: 0 0 var(--esp-8); white-space: normal; }
.marcado > :last-child { margin-bottom: 0; }
.marcado > :first-child { margin-top: 0; }

.marcado h3,
.marcado h4,
.marcado h5,
.marcado h6 {
  font-size: 1rem;
  margin: var(--esp-16) 0 var(--esp-8);
}

.marcado ul,
.marcado ol { margin: 0 0 var(--esp-8); padding-left: var(--esp-24); }
.marcado li { margin-bottom: var(--esp-4); }

.marcado code {
  background: var(--fondo-elevado-2);
  border-radius: var(--radio);
  padding: 0 var(--esp-4);
}

.marcado pre {
  background: var(--fondo-elevado-2);
  border-radius: var(--radio);
  padding: var(--esp-8);
  margin: 0 0 var(--esp-8);
  overflow-x: auto;
  font-family: var(--fuente-mono);
}
.marcado pre code { background: none; padding: 0; }

/* --- un bloque de codigo con su lenguaje y su boton de copiar --------------
 * El envoltorio existe por dos cosas que el `<pre>` no puede hacer solo, y las
 * dos tienen que quedarse quietas mientras el codigo se desplaza de lado: el
 * rotulo del lenguaje y el boton de copiar. Lo que se desplaza es el `<pre>`,
 * asi que van fuera de el y colocados sobre su esquina.
 *
 * El rotulo sale de `data-lenguaje`, que pone el servidor (`app/web/marcado.py`)
 * y se lee tambien sin JavaScript. El boton lo cuelga `asistente.js`, porque
 * sin guion no copiaria nada.
 */
.bloque-codigo { position: relative; margin: 0 0 var(--esp-8); }
.bloque-codigo > pre {
  margin: 0;
  /* Sitio arriba para el rotulo y el boton, que van encima. */
  padding-top: var(--esp-24);
}
.bloque-codigo::before {
  content: attr(data-lenguaje);
  position: absolute;
  top: var(--esp-4);
  left: var(--esp-8);
  font-size: .75rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--texto-debil);
}
.copiar-codigo {
  position: absolute;
  top: var(--esp-4);
  right: var(--esp-4);
  padding: 0 var(--esp-8);
  font-size: .75rem;
  line-height: 1.6;
  color: var(--texto-tenue);
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  cursor: pointer;
}
.copiar-codigo:hover { background: var(--fondo-hover); color: var(--texto); }

/* Las cuatro clases de trozo que marca `_resaltar`. Con las variables
   semanticas de siempre: aqui tampoco hay un color literal. */
.cd-com { color: var(--texto-debil); font-style: italic; }
.cd-txt { color: var(--exito); }
.cd-num { color: var(--aviso); }
.cd-cla { color: var(--acento); }

.marcado blockquote {
  margin: 0 0 var(--esp-8);
  padding-left: var(--esp-8);
  border-left: 3px solid var(--borde);
  color: var(--texto-tenue);
}

.marcado hr { border: 0; border-top: 1px solid var(--borde); margin: var(--esp-16) 0; }

/* Una tabla ancha se desplaza dentro de si misma; si no, empuja la columna del
   hilo y con ella la pantalla entera. */
.marcado table {
  display: block;
  width: max-content;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  margin: 0 0 var(--esp-8);
}
.marcado th,
.marcado td {
  border: 1px solid var(--borde);
  padding: var(--esp-4) var(--esp-8);
  text-align: left;
}

/* Los tres niveles de riesgo, con las variables semanticas que ya existen: */
.punto {
  display: inline-block;
  width: var(--esp-8);
  height: var(--esp-8);
  border-radius: 50%;
  margin-right: var(--esp-4);
}
.punto.verde { background: var(--exito); }
.punto.amarillo { background: var(--aviso); }
.punto.rojo { background: var(--peligro); }

.mensaje-ia.propuesta { border-left: 3px solid var(--aviso); }
.mensaje-ia.propuesta.riesgo-rojo { border-left-color: var(--peligro); }

.propuesta-rotulo { margin-bottom: var(--esp-8) !important; }

.propuesta-args {
  margin: var(--esp-8) 0;
  padding: var(--esp-8);
  background: var(--fondo-elevado-2);
  border-radius: var(--radio);
}
.propuesta-args dt { color: var(--texto-tenue); font-size: .85rem; }
.propuesta-args dd { margin: 0 0 var(--esp-8); white-space: pre-wrap; }

.propuesta-botones { display: flex; gap: var(--esp-8); }

/* --- la pantalla en blanco -------------------------------------------------
 * Sin un solo mensaje esto no es una conversacion vacia: es otra pantalla. El
 * saludo y el recuadro de escribir se ponen **en medio**, que es donde se mira
 * al entrar, y las cuatro sugerencias dicen sin explicar nada que esto se usa
 * escribiendole.
 *
 * El hilo deja de llevarse el hueco que sobra —no hay nada que enseñar— y lo
 * reparte la columna, que centra el grupo entero. Al enviar el primer mensaje
 * llega el mismo fragmento sin la clase y el recuadro se planta abajo. **Es un
 * salto**, no un deslizamiento: `justify-content` no se anima, y hacerlo con
 * translaciones pedia medir la pantalla desde el guion. Lo que suaviza el
 * cambio es que el mensaje entra con su desvanecido.
 */
.asistente-hilo.en-blanco { justify-content: center; }
.asistente-hilo.en-blanco .asistente-mensajes {
  flex: 0 0 auto;
  overflow: visible;
}
/* Con la conversacion en blanco el rotulo no dice nada que no diga el saludo
   de debajo; lo que si hace falta es el «⋮», asi que la cabecera se queda y lo
   que se va es el filo, que sin hilo debajo separaba de nada. */
.asistente-hilo.en-blanco .asistente-cabecera { border-bottom: 0; }

.asistente-bienvenida { text-align: center; padding: var(--esp-16) 0; }
.asistente-saludo {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 600;
}
.asistente-invitacion {
  margin: var(--esp-4) 0 0;
  color: var(--texto-tenue);
}

/* Las sugerencias **solo con JavaScript**: lo unico que hacen es escribir su
   texto en el recuadro, asi que sin guion serian cuatro botones que no hacen
   nada. `.con-js` lo pone `formulario.js` en la raiz del documento. */
.asistente-sugerencias { display: none; }
.con-js .asistente-sugerencias {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--esp-8);
  list-style: none;
  margin: var(--esp-24) auto 0;
  padding: 0;
  max-width: 42rem;
}
.asistente-sugerencia {
  width: 100%;
  height: 100%;
  text-align: left;
  padding: var(--esp-8) var(--esp-16);
  background: var(--fondo-elevado);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  color: var(--texto-tenue);
  font: inherit;
  cursor: pointer;
}
.asistente-sugerencia:hover {
  background: var(--fondo-hover);
  border-color: var(--borde-fuerte);
  color: var(--texto);
}

/* --- el hueco de escribir --------------------------------------------
 * Un recuadro y nada encima: el rotulo del campo va en `aria-label` y lo que
 * se lee es el marcador de posicion, dentro. Debajo, el recordatorio del
 * atajo, que solo es cierto donde el Enter envia.
 *
 * **Anclado abajo.** En ancho lo esta por construccion: es la ultima fila de
 * una columna que ocupa la ventana y el unico que se desplaza es el hilo. En
 * estrecho, donde vuelve a desplazarse la pagina, lo sujeta el `position:
 * sticky` del final de este fichero.
 */
.asistente-decir {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--esp-4);
}

.asistente-caja { position: relative; width: 100%; }
/* El hueco de la derecha es para la flecha: el texto envuelve antes de llegar
   a ella en vez de pasarle por debajo. */
.asistente-caja textarea {
  display: block;
  width: 100%;
  /* La flecha ocupa 32 y se separa 8 del filo: 48 es lo que hay que dejarle
     para que el renglon envuelva antes de llegar y no le pase por debajo. */
  padding-right: calc(var(--esp-32) + var(--esp-16));
  /* **El tope de lo que crece el recuadro, y vive aqui.** Son cinco renglones
     largos; a partir de ahi se desplaza por dentro. Quien lo aplica es
     `asistente.js`, que lo lee de aqui para que la medida no este en dos
     sitios. Sin guion no crece: se queda en los `rows` de la plantilla. */
  max-height: 11rem;
  resize: none;
}

/* Sin guion el Enter no envia, asi que el recordatorio mentiria y no sale. */
.asistente-atajo {
  display: none;
  margin: 0;
  align-self: center;
  font-size: .8rem;
}
.con-js .asistente-atajo { display: block; }

kbd {
  font-family: var(--fuente-mono);
  font-size: .9em;
  padding: 0 var(--esp-4);
  border: 1px solid var(--borde);
  border-radius: 4px;
  background: var(--fondo-elevado-2);
}

/* La flecha, abajo a la derecha del recuadro. Es el `submit` de verdad... y
 * **mientras se espera es el boton de parar**: mismo sitio, mismo tamaño, otro
 * icono y otro rotulo. Que sea el mismo boton y no dos no es ahorro: es que en
 * un chat lo que se pulsa para mandar y lo que se pulsa para cortar estan
 * siempre en el mismo punto de la pantalla.
 *
 * Apagado con el recuadro vacio, y quien lo apaga es `asistente.js` y no una
 * regla de CSS: sin guion tiene que poder pulsarse siempre, porque sin guion
 * es la unica forma de enviar. */
.asistente-flecha {
  position: absolute;
  right: var(--esp-8);
  bottom: var(--esp-8);
  display: grid;
  place-items: center;
  width: var(--esp-32);
  height: var(--esp-32);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--acento);
  color: var(--sobre-acento);
  cursor: pointer;
}
.asistente-flecha:hover { background: var(--acento-fuerte); }
.asistente-flecha:disabled { opacity: .4; cursor: not-allowed; }

/* Los dos iconos ocupan la misma casilla de la rejilla, asi que el boton no
   cambia de tamaño al cambiar de oficio. */
.asistente-flecha .icono-enviar,
.asistente-flecha .icono-parar { grid-area: 1 / 1; }
.asistente-flecha .icono-parar,
.respondiendo .asistente-flecha .icono-enviar { display: none; }
.respondiendo .asistente-flecha .icono-parar { display: block; }
.respondiendo .asistente-flecha { background: var(--peligro); }

.asistente-acciones .accion {
  display: grid;
  gap: var(--esp-4);
  padding: var(--esp-8) 0;
  border-bottom: 1px solid var(--borde);
}

.fila-buscador { display: flex; gap: var(--esp-4); }
.fila-buscador input { flex: 1; min-width: 0; }

@media (max-width: 60rem) {
  .asistente { grid-template-columns: 1fr; row-gap: var(--esp-24); }
  /* El contenido de la derecha vuelve al hilo: justo debajo de la
     conversacion, sin duplicar nada. */
  .asistente-hilo { order: 1; }
  /* Y el cajon deja de abrirse de lado: en una sola columna no hay lado al
     que abrirse, asi que es un plegable mas —ancho completo, rotulo derecho—
     y lo unico que se anima es el desvanecido. Sin carril que reservar, el
     cajon vuelve a medir lo que mide su contenido, abierto o cerrado. */
  .asistente-cajon { order: 2; margin-left: 0; width: auto; }
  .asistente-cajon:not([open]) { display: block; }
  .asistente-hecho { width: auto; }
  .asistente-cajon:not([open]) > .asistente-lengueta { writing-mode: horizontal-tb; }
  .asistente-cajon::details-content,
  .asistente-cajon[open]::details-content { width: auto; }

  /* --- y la pantalla deja de ocupar el alto de la ventana ------------------
   * Aqui la lateral ya no es una columna sino la primera fila, asi que no
   * queda ventana que repartir entre ella y la conversacion: repartirla
   * dejaria el hilo en un par de dedos de alto. Vuelve a desplazarse la
   * pagina, el hilo crece todo lo que quiera...
   */
  body.pantalla-asistente .columna { display: block; height: auto; }
  body.pantalla-asistente main { display: block; }
  body.pantalla-asistente .asistente-hecho { max-height: none; }
  .asistente-mensajes {
    overflow-y: visible;
    padding-right: 0;
  }

  /* ...y el recuadro de escribir se queda pegado abajo, que es lo unico que
     habia que salvar del reparto de alturas. La cabecera si se va con el
     desplazamiento: en un movil, catorce caracteres de rotulo no valen los dos
     dedos de alto que cuestan. */
  .asistente-decir {
    position: sticky;
    bottom: 0;
    z-index: 1;
    background: var(--fondo);
    padding-bottom: var(--esp-8);
  }
}

/* Quien ha pedido que no se mueva nada no ve moverse nada: ni el mensaje que
 * entra, ni los puntitos de la espera, ni el cajon de la derecha. Los puntitos
 * quietos siguen diciendo lo que dicen —estan puestos mientras se espera y
 * desaparecen al llegar la respuesta—, y `role="status"` no depende de que
 * parpadeen. */
@media (prefers-reduced-motion: reduce) {
  .asistente-mensajes > :last-child { animation: none; }
  .puntos i { animation: none; opacity: .6; }
  .asistente-cajon::details-content { transition: none; }
}