/* =====================================================================
   CIELO AZUL AUTISMO — Sistema de diseño
   Derivado del logotipo: la nube-infinito azul con su estela rosa,
   naranja y verde, y el morado del descriptor.
   ===================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@600;700;800&family=Inter:wght@400;500;600&display=swap');

:root {
  /* --- Colores de marca, tomados del logotipo ---
     El azul del logo es luminoso: sirve para superficies, iconos y acentos,
     pero no alcanza 4.5:1 con texto blanco encima. Para botones y enlaces se
     usa --azul-accion, que es el mismo tono oscurecido hasta cumplir WCAG AA. */
  --azul-marca: #26A9E0;      /* azul de la nube-infinito */
  --azul-accion: #17739F;     /* texto/botón: 5.26:1 sobre blanco */
  --azul-profundo: #12557E;   /* encabezados y texto de marca */
  --azul-medio: #1B87BC;      /* bordes y estados intermedios */
  --azul-suave: #E4F3FB;      /* fondos de selección */
  --morado: #6B4E9E;          /* del descriptor "Autismo, vida y prosperidad" */
  --rosa: #E9498E;
  --naranja: #F49A3A;
  --verde: #A9C64B;

  /* --- Neutros --- */
  --fondo: #F4F8FB;
  --superficie: #FFFFFF;
  --superficie-alt: #FAFCFE;
  --borde: #E3EDF4;
  --borde-fuerte: #CFDFEA;
  --texto: #26333D;
  --texto-tenue: #6B7C89;

  /* --- Semánticos (fondo tenue + texto oscuro: mejor contraste) --- */
  --exito-fondo: #E6F5EC;   --exito-texto: #1B7A45;
  --aviso-fondo: #FDF1DC;   --aviso-texto: #8A5A08;
  --alerta-fondo: #FCE7EF;  --alerta-texto: #B02160;
  --neutro-fondo: #EEF3F7;  --neutro-texto: #55666F;

  --fuente-display: 'Montserrat', system-ui, sans-serif;
  --fuente-cuerpo: 'Inter', system-ui, sans-serif;

  --radio: 14px;
  --radio-sm: 9px;

  /* Alto de la barra de estela. Es una variable porque el armazón tiene que
     descontarla para no desbordar la ventana, y el tema líquido la apaga. */
  --alto-estela: 4px;
  --sombra: 0 1px 2px rgba(18, 85, 126, .06), 0 6px 18px rgba(18, 85, 126, .06);
  --sombra-fuerte: 0 10px 32px rgba(18, 85, 126, .14);
  --estela: linear-gradient(90deg, var(--rosa) 0%, var(--naranja) 28%, var(--verde) 56%, var(--azul-marca) 100%);
}

body {
  font-family: var(--fuente-cuerpo);
  background-color: var(--fondo);
  color: var(--texto);
  font-size: .94rem;
}

h1, h2, h3, h4, h5, h6, .brand-font {
  font-family: var(--fuente-display);
  color: var(--azul-profundo);
  font-weight: 700;
  letter-spacing: -.01em;
}

a { color: var(--azul-accion); text-decoration: none; }
a:hover { color: var(--azul-profundo); text-decoration: underline; }

/* La estela del logo, como firma de la aplicación */
.barra-estela {
  height: var(--alto-estela);
  background: var(--estela);
}

/* ---------- Layout ---------- */

/* El descuento de la estela no es un detalle: la barra mide 4px y va por encima
   del armazón, así que con `min-height: 100vh` el documento medía siempre 4px
   más que la ventana y TODAS las pantallas del sistema salían con barra de
   desplazamiento aunque su contenido cupiera de sobra. Se descuenta en vez de
   fijar el alto para que las páginas largas sigan creciendo con normalidad. */
.app-shell { display: flex; min-height: calc(100vh - var(--alto-estela)); }

.app-sidebar {
  width: 264px;
  flex-shrink: 0;
  background: var(--superficie);
  border-right: 1px solid var(--borde);
  display: flex;
  flex-direction: column;
}

.app-sidebar .brand {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: 1.1rem 1.25rem;
  border-bottom: 1px solid var(--borde);
}

.app-sidebar .brand img { width: 40px; height: 40px; flex-shrink: 0; }

.brand-texto { line-height: 1.05; }

.brand-nombre {
  font-family: var(--fuente-display);
  font-weight: 800;
  font-size: 1.02rem;
  color: var(--azul-marca);
  letter-spacing: .02em;
}

.brand-descriptor {
  font-family: var(--fuente-display);
  font-weight: 600;
  font-size: .53rem;
  color: var(--morado);
  letter-spacing: .06em;
  text-transform: uppercase;
}

.app-sidebar .nav { padding: .75rem .6rem; gap: 2px; }

.app-sidebar .nav-link {
  color: var(--texto);
  padding: .55rem .75rem;
  border-radius: var(--radio-sm);
  display: flex;
  align-items: center;
  gap: .7rem;
  font-weight: 500;
  font-size: .89rem;
  transition: background-color .15s ease, color .15s ease;
}

.app-sidebar .nav-link i {
  width: 1.15rem;
  text-align: center;
  color: var(--texto-tenue);
  transition: color .15s ease;
}

.app-sidebar .nav-link:hover { background-color: var(--superficie-alt); color: var(--azul-profundo); text-decoration: none; }
.app-sidebar .nav-link:hover i { color: var(--azul-medio); }

.app-sidebar .nav-link.active {
  background-color: var(--azul-suave);
  color: var(--azul-profundo);
  font-weight: 600;
}
.app-sidebar .nav-link.active i { color: var(--azul-marca); }

.sidebar-pie {
  margin-top: auto;
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--borde);
  font-size: .72rem;
  color: var(--texto-tenue);
}

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.app-topbar {
  background: var(--superficie);
  border-bottom: 1px solid var(--borde);
  padding: .8rem 1.75rem;
  position: sticky;
  top: 0;
  z-index: 1020;
}

.app-topbar h1 { font-size: 1.15rem; margin: 0; }

.usuario-chip {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .3rem .6rem .3rem .35rem;
  border: 1px solid var(--borde);
  border-radius: 999px;
  background: var(--superficie-alt);
}

.usuario-avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--azul-suave);
  color: var(--azul-profundo);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .8rem;
}

.usuario-nombre { font-size: .82rem; font-weight: 600; line-height: 1.1; }
.usuario-rol { font-size: .68rem; color: var(--texto-tenue); line-height: 1.1; }

.app-content { padding: 1.6rem 1.75rem 2.5rem; }

/* ---------- Componentes ---------- */
.card {
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  background: var(--superficie);
}

.card-body { padding: 1.15rem 1.25rem; }

.btn { font-weight: 600; border-radius: var(--radio-sm); font-size: .86rem; }
.btn-sm { font-size: .8rem; }

.btn-primary {
  background-color: var(--azul-accion);
  border-color: var(--azul-accion);
  box-shadow: 0 1px 2px rgba(18, 85, 126, .18);
}
.btn-primary:hover, .btn-primary:focus {
  background-color: var(--azul-profundo);
  border-color: var(--azul-profundo);
}

.btn-outline-primary { color: var(--azul-accion); border-color: var(--borde-fuerte); background: var(--superficie); }
.btn-outline-primary:hover { background-color: var(--azul-suave); border-color: var(--azul-marca); color: var(--azul-profundo); }

.btn-outline-secondary { color: var(--texto-tenue); border-color: var(--borde-fuerte); }
.btn-outline-secondary:hover { background: var(--superficie-alt); color: var(--texto); border-color: var(--borde-fuerte); }

.btn-outline-danger { color: #C43060; border-color: #F0CEDC; }
.btn-outline-danger:hover { background-color: var(--alerta-fondo); border-color: #E4A9C1; color: #93194E; }

/* Insignias con fondo tenue: legibles y sobrias */
.badge { font-weight: 600; font-size: .72rem; padding: .35em .6em; border-radius: 999px; }
.badge-activo    { background-color: var(--exito-fondo)  !important; color: var(--exito-texto)  !important; }
.badge-pendiente { background-color: var(--aviso-fondo)  !important; color: var(--aviso-texto)  !important; }
.badge-vencido   { background-color: var(--alerta-fondo) !important; color: var(--alerta-texto) !important; }
.badge-inactivo  { background-color: var(--neutro-fondo) !important; color: var(--neutro-texto) !important; }

/* ===========================================================================
   TABLAS
   ===========================================================================

   Cada tabla de este sistema es una lista de personas, o de cosas que le
   pasaron a una persona. Su trabajo es siempre el mismo: encontrar una fila y
   compararla con las demás. Todo lo de aquí sale de esas dos cosas.

   ENCONTRAR
   El nombre no se va de la vista (ver .tabla-datos, más abajo) y la fila
   señalada se marca sin ambigüedad. El hover que traía —#FAFCFE sobre blanco,
   1.01:1 contra el fondo— era invisible; quien recorre una tabla de veinte
   filas con el dedo en el trackpad necesita ver dónde está.

   COMPARAR
   Cifras tabulares en toda la tabla. Con las proporcionales el "1" es más
   angosto que el "8", así que $1,111.00 y $8,888.00 no alinean sus decimales y
   dejan de poder leerse en columna. Es el cambio más barato y el que más se
   nota en un sistema lleno de importes y porcentajes.

   LO QUE NO LLEVA
   Ni cebra —compite con el hover por decir lo mismo—, ni la estela del
   logotipo, ni bordes gruesos, ni esquinas redondeadas en las celdas. La marca
   ya está en la cabecera de la página; aquí dentro estorbaría la lectura, que
   es a lo único que ha venido esta pantalla.
   =========================================================================== */

.table {
  --bs-table-hover-bg: transparent;   /* el hover se pinta abajo, con más presencia */
  margin-bottom: 0;
  border-color: var(--borde);

  /* Cifras de ancho fijo. Va en la tabla entera y no sólo en las columnas
     numéricas porque las fechas y las horas también son cifras que se leen en
     columna: 09:05 debajo de 11:40 tiene que alinear los dos puntos. */
  font-variant-numeric: tabular-nums;
}

.table > thead > tr > th {
  font-family: var(--fuente-display);
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--texto-tenue);
  font-weight: 700;
  white-space: nowrap;          /* un encabezado partido en dos renglones desalinea toda la columna */
  background: var(--superficie);
  border-bottom: 1px solid var(--borde-fuerte);
  padding: .6rem .75rem;
}

.table > tbody > tr > td {
  border-color: var(--borde);
  vertical-align: middle;
  padding: .6rem .75rem;
}

/* La última fila sin línea: la del contenedor ya está ahí y dos seguidas se ven
   como un error. */
.table > tbody > tr:last-child > td { border-bottom: 0; }

/* El hover marca la fila entera y le pone un filo a la izquierda. El filo se
   hace con box-shadow y no con border para no mover el contenido un píxel al
   entrar y salir, que es lo que produce el temblor al recorrer una lista. */
.table.table-hover > tbody > tr { transition: background-color .12s ease; }

.table.table-hover > tbody > tr:hover > td {
  background-color: var(--azul-suave);
}

.table.table-hover > tbody > tr:hover > td:first-child {
  box-shadow: inset 2px 0 0 var(--azul-accion);
}

/* Quien navega con teclado tiene que ver la fila igual que quien usa el ratón:
   :focus-within cubre la fila que contiene el botón o el enlace enfocado. */
.table > tbody > tr:focus-within > td {
  background-color: var(--azul-suave);
}

.table > tbody > tr:focus-within > td:first-child {
  box-shadow: inset 2px 0 0 var(--azul-accion);
}

/* Números a la derecha, y con la misma sangría que su encabezado. Bootstrap ya
   trae .text-end; esto es para que el encabezado la herede sin repetirla. */
.table > thead > tr > th.text-end,
.table > tbody > tr > td.text-end { padding-right: .75rem; }

/* Una celda vacía se lee como "no cargó"; el guion dice "no hay dato". Sólo
   entra donde el servidor no escribió nada — las vistas que ya imprimen "—" no
   se ven afectadas. */
.table > tbody > tr > td:empty::after {
  content: "—";
  color: var(--texto-tenue);
}

/* ---------------------------------------------------------------------------
   Tablas de datos: la columna de identidad se queda quieta
   ---------------------------------------------------------------------------
   En todas estas tablas la primera columna es de quién es la fila. Al
   desplazarse a la derecha para ver el saldo o la hora, el nombre se iba y
   había que volver a la izquierda para saber a quién se estaba mirando.

   Se activa con .tabla-datos y no en todas las tablas porque las de resumen y
   totales —dos o tres columnas, sin desplazamiento— no lo necesitan, y fijar
   ahí una columna sólo añadiría una línea que no separa nada.
   --------------------------------------------------------------------------- */

/* El `:not([colspan])` no es una precaución teórica: en Adeudos cada familia
   trae debajo una fila de detalle que es un solo `<td colspan="8">` con un
   panel dentro. Sin esta exclusión esa banda entera se volvía columna fija —un
   panel pegado al borde izquierdo— y además perdía su fondo propio. Una celda
   que abarca varias columnas no es la columna ancla de nada. */
.tabla-datos > thead > tr > th:first-child:not([colspan]),
.tabla-datos > tbody > tr > td:first-child:not([colspan]) {
  position: sticky;
  left: 0;
  z-index: 2;
  /* Opaco a la fuerza: si dejara pasar el fondo, las columnas que se desplazan
     por debajo se leerían a través del nombre. */
  background-color: var(--superficie);
}

.tabla-datos > thead > tr > th:first-child:not([colspan]) { z-index: 3; }

/* El hover y el foco tienen que pintar también la celda fija, o la fila
   señalada aparecería cortada justo en la columna que más se mira. */
.tabla-datos.table-hover > tbody > tr:hover > td:first-child:not([colspan]),
.tabla-datos > tbody > tr:focus-within > td:first-child:not([colspan]) {
  background-color: var(--azul-suave);
}

/* La línea que separa la columna fija sólo aparece cuando hay algo corriendo
   por debajo. Se consigue con un degradado anclado al contenido (`local`): con
   el desplazamiento a cero queda fuera de vista, y asoma al empezar a mover. */
.tabla-fija-sombra {
  background:
    linear-gradient(to right, rgba(18, 85, 126, .10), rgba(18, 85, 126, 0)) 0 0 / 12px 100% no-repeat local;
}

/* ---------------------------------------------------------------------------
   Aviso de que hay más a la derecha
   ---------------------------------------------------------------------------
   Sin esto, una tabla que se desplaza parece una tabla que termina ahí. El
   degradado se ancla al contenido con `local`, así que se desvanece solo al
   llegar al final: no dice "hay más" cuando ya no lo hay.
   --------------------------------------------------------------------------- */

.table-responsive {
  background:
    linear-gradient(to left, var(--superficie) 40%, rgba(255, 255, 255, 0)) 100% 0 / 32px 100% no-repeat local,
    radial-gradient(farthest-side at 100% 50%, rgba(18, 85, 126, .13), rgba(18, 85, 126, 0)) 100% 0 / 12px 100% no-repeat scroll;
}

/* ---------------------------------------------------------------------------
   Tablas largas: el encabezado se queda
   ---------------------------------------------------------------------------
   Sólo donde de verdad hay cientos de filas. Acotar la altura crea un segundo
   desplazamiento dentro de la página, y eso molesta más de lo que ayuda en una
   tabla de diez filas.
   --------------------------------------------------------------------------- */

/* La altura se calcula contra la ventana, no en una fracción fija. Con 70vh
   siempre sobraba o faltaba: en un portátil de 768px de alto la tabla se
   quedaba corta y la página seguía desplazándose, y en un monitor grande
   desperdiciaba un tercio de la pantalla. El descuento cubre el encabezado de
   la aplicación, la cabecera de la tarjeta y la fila de filtros. */
.tabla-alta { max-height: var(--alto-tabla, 70vh); }

/* -----------------------------------------------------------------------------
   Reportes: que quepan sin desplazar la página
   -----------------------------------------------------------------------------
   El objetivo es que sólo se desplace la tabla. Si además se desplaza la página,
   quien busca una fila tiene que decidir cuál de los dos mover, y siempre elige
   mal la primera vez.
   -------------------------------------------------------------------------- */

.reporte-panel .reporte-filtros {
  padding: .6rem .75rem;
  border-bottom: 1px solid var(--borde);
}

.reporte-panel .reporte-filtros .form-label { margin-bottom: .15rem; font-size: .72rem; }

/* EL ALTO DE LA TABLA NO SE CALCULA CON UNA CONSTANTE, SE REPARTE
   Lo intenté primero restando un número fijo a 100vh y no puede funcionar: el
   espacio que hay por encima de la tabla depende de en cuántos renglones caen
   los filtros, y eso cambia con el ancho de la ventana y con cada reporte —el
   de alumnos tiene cinco filtros y el del buzón dos—. Medido, iba de 312px a
   375px sólo entre dos tamaños de ventana.

   Con flex la pregunta desaparece: el panel se acota contra la ventana y la
   tabla se queda con lo que sobre, sea cual sea el alto de los filtros. La
   única constante es lo que hay por encima y por debajo del panel —el
   encabezado de la aplicación y el relleno del contenido—, que sí es estable
   porque no depende de lo que haya dentro. */
.reporte-panel {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 11rem);
}

.reporte-panel .tabla-alta {
  flex: 1 1 auto;
  /* Sin esto un elemento flex no baja de su contenido y el acotado no surte
     efecto: es la línea que hace que todo lo anterior funcione. */
  min-height: 0;
  max-height: none;
}

@media (max-width: 991.98px) {
  /* En pantalla angosta los filtros ocupan varios renglones y acotar dejaría la
     tabla en una rendija. Ahí es más honesto que la página se desplace. */
  .reporte-panel { max-height: none; }
  .reporte-panel .tabla-alta { flex: 0 1 auto; }
}

.tabla-alta > .table > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: 4;
}

.tabla-alta > .tabla-datos > thead > tr > th:first-child { z-index: 5; }

/* Densidad compacta para listas de muchas filas, sin bajar de lo que un dedo
   puede acertar en una tablet. */
.table-sm > thead > tr > th,
.table-sm > tbody > tr > td { padding: .4rem .6rem; }

@media (max-width: 575.98px) {
  .table > thead > tr > th,
  .table > tbody > tr > td { padding: .5rem .55rem; }
}

@media (prefers-reduced-motion: reduce) {
  .table.table-hover > tbody > tr { transition: none; }
}

.form-control, .form-select {
  border-color: var(--borde-fuerte);
  border-radius: var(--radio-sm);
  font-size: .88rem;
}
.form-control:focus, .form-select:focus {
  border-color: var(--azul-marca);
  box-shadow: 0 0 0 .2rem rgba(38, 169, 224, .18);
}
.form-label { font-weight: 600; font-size: .82rem; color: var(--texto); margin-bottom: .3rem; }
.form-check-input:checked { background-color: var(--azul-marca); border-color: var(--azul-marca); }

.progress { background-color: var(--neutro-fondo); border-radius: 999px; }
.progress-bar { background-color: var(--azul-marca); }

.alert { border-radius: var(--radio); border: 1px solid transparent; font-size: .88rem; }
.alert-primary { background-color: var(--azul-suave); border-color: #C7E7F7; color: var(--azul-profundo); }
.alert-success { background-color: var(--exito-fondo); border-color: #BFE5CD; color: var(--exito-texto); }
.alert-danger  { background-color: var(--alerta-fondo); border-color: #F3C9DA; color: var(--alerta-texto); }
.alert-secondary { background-color: var(--neutro-fondo); border-color: var(--borde); color: var(--texto-tenue); }

/* Tarjeta de indicador del Dashboard, con la estela como acento superior */
.kpi { position: relative; overflow: hidden; }
.kpi::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--estela);
  opacity: .9;
}

/* Contenedor de gráficas: reserva la altura para no provocar saltos de layout */
.grafica-caja { position: relative; height: 260px; }
.grafica-caja canvas { max-height: 260px; }

a.kpi { color: inherit; }
a.kpi:hover { border-color: var(--azul-marca); box-shadow: var(--sombra-fuerte); }

/* ---------- Lista de pacientes con selección (seguimiento) ---------- */
.lista-pacientes,
.lista-seleccionable {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 62vh;
  overflow-y: auto;
  border-top: 1px solid var(--borde);
}

.item-paciente,
.item-lista {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .7rem 1.25rem;
  border-bottom: 1px solid var(--borde);
  color: var(--texto);
  text-decoration: none;
  transition: background-color .12s ease;
}

.item-paciente:hover, .item-lista:hover { background-color: var(--superficie-alt); color: var(--texto); text-decoration: none; }

.item-paciente.activo,
.item-lista.activo {
  background-color: var(--azul-suave);
  box-shadow: inset 3px 0 0 var(--azul-marca);
}

.item-avatar {
  width: 34px; height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--neutro-fondo);
  color: var(--azul-profundo);
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .78rem;
}

.item-paciente.activo .item-avatar,
.item-lista.activo .item-avatar { background: var(--superficie); }

.item-datos { flex: 1; min-width: 0; }
.item-nombre { display: block; font-weight: 600; font-size: .88rem; }
.item-meta { display: block; font-size: .76rem; color: var(--neutro-texto); }
.item-estado { display: flex; align-items: center; flex-shrink: 0; }

.resumen-dato {
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  padding: .5rem .7rem;
  background: var(--superficie-alt);
  display: flex;
  flex-direction: column;
}

.lista-archivos { list-style: none; margin: 0; padding: 0; }

.lista-archivos li {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--borde);
}

.lista-archivos li:last-child { border-bottom: 0; }
.min-width-0 { min-width: 0; }

/* ---------- Identificación de salones por color ---------- */
.salon-chip { display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap; }

.salon-punto {
  width: .7rem; height: .7rem;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  box-shadow: 0 0 0 2px var(--superficie), 0 0 0 3px rgba(18, 85, 126, .12);
}

.salon-card { transition: transform .15s ease, box-shadow .15s ease; }
.salon-card:hover { transform: translateY(-2px); box-shadow: var(--sombra-fuerte); }

/* Cabecera de cada salón dentro del pase de lista.

   Se queda pegada arriba al bajar porque la lista de un salón puede pasar de
   la pantalla, y sin ella se pierde de vista en qué aula se está marcando —que
   es lo único que hace que la lista tenga sentido—. */
.pase-salon-cabecera {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: .5rem .9rem;
  background: var(--fondo-suave, #f3f7fa);
  border-top: 1px solid var(--borde, rgba(18, 85, 126, .12));
  border-bottom: 1px solid var(--borde, rgba(18, 85, 126, .12));
}

/* El primer salón no necesita raya por arriba: ya la pone el encabezado de la
   tarjeta, y dos juntas se leen como una franja gruesa. */
.pase-salon-cabecera:first-of-type { border-top: 0; }

/* ---------- Calendario de la agenda ---------- */
.calendario-mes { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px; }

.calendario-encabezado {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--texto-tenue);
  text-align: center;
  padding: .45rem 0;
}

.calendario-dia {
  display: block;
  min-height: 98px;
  padding: .45rem .55rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  color: var(--texto);
  text-decoration: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.calendario-dia:hover { border-color: var(--azul-marca); box-shadow: var(--sombra); text-decoration: none; color: var(--texto); }
.calendario-dia .numero { font-family: var(--fuente-display); font-weight: 700; font-size: .85rem; }
.calendario-dia.fuera-mes { background: var(--superficie-alt); color: var(--texto-tenue); }
.calendario-dia.es-hoy { border-color: var(--azul-marca); box-shadow: inset 0 0 0 1px var(--azul-marca); }

.calendario-evento {
  font-size: .71rem;
  line-height: 1.35;
  margin-top: 2px;
  padding-left: .45rem;
  border-left: 2px solid var(--azul-marca);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Vista por horas */
.franja-hora { display: flex; gap: 1rem; border-top: 1px solid var(--borde); padding: .55rem 0; }
.franja-hora:first-child { border-top: 0; }
.franja-etiqueta { width: 74px; flex-shrink: 0; text-align: center; }
.franja-etiqueta > div:first-child { font-family: var(--fuente-display); color: var(--azul-profundo); }
.franja-contenido { flex: 1; min-width: 0; }

.sesion-item {
  border: 1px solid var(--borde);
  border-left: 3px solid var(--azul-marca);
  border-radius: var(--radio-sm);
  padding: .65rem .8rem;
  margin-bottom: .5rem;
  background: var(--superficie);
}

/* "lunes 27 de julio" -> "Lunes 27 de julio" (sólo la primera letra) */
.dia-titulo { text-transform: lowercase; }
.dia-titulo::first-letter { text-transform: uppercase; }

/* ---------- Pantalla de acceso ---------- */
.login-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  background: var(--superficie);
}

.login-marca {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 1.25rem;
  padding: 3rem;
  background:
    radial-gradient(1100px 520px at 15% 10%, rgba(255,255,255,.28), transparent 60%),
    linear-gradient(150deg, var(--azul-marca) 0%, #1E8FC4 45%, var(--azul-profundo) 100%);
  color: #fff;
  overflow: hidden;
  text-align: center;
}

.login-marca::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 6px;
  background: var(--estela);
}

.login-marca img { width: 190px; max-width: 60%; filter: drop-shadow(0 12px 28px rgba(0,0,0,.22)); }
.login-marca h1 { color: #fff; font-size: 2rem; font-weight: 800; letter-spacing: .01em; margin: 0; }
.login-marca p { max-width: 34ch; color: rgba(255,255,255,.9); margin: 0; }

.login-panel { display: flex; align-items: center; justify-content: center; padding: 2.5rem; }
.login-card { width: 100%; max-width: 380px; }
.login-card .brand-font { font-size: 1.5rem; }

.login-titulo { font-size: 1.5rem; margin: 0 0 .15rem; color: var(--azul-profundo); }
.login-subtitulo { font-size: .88rem; }
.login-ayuda { font-size: .76rem; }

/* El isotipo pequeño sólo aparece cuando el panel de marca se encoge. */
.login-logo-movil { width: 64px; display: block; margin: 0 auto 1.25rem; }

/* 44px de lado: el mínimo táctil. El btn de Bootstrap se queda en 38 y este
   botón se pulsa con el pulgar, muchas veces a oscuras y con prisa. */
.boton-ver-password {
  min-width: 44px;
  min-height: 44px;
  border-color: var(--borde-fuerte);
  color: var(--texto-tenue);
}

.boton-ver-password:hover,
.boton-ver-password:focus-visible {
  background: var(--azul-suave);
  border-color: var(--azul-medio);
  color: var(--azul-accion);
}

/* Con el botón dentro del input-group, el campo pierde su esquina derecha; se
   devuelve al botón para que el grupo se lea como una sola pieza. */
.input-group > .boton-ver-password {
  border-top-right-radius: var(--radio-sm);
  border-bottom-right-radius: var(--radio-sm);
}

/* El icono del candado y el del usuario van sobre blanco, como el campo: con el
   gris de Bootstrap el grupo parecía deshabilitado. */
.login-card .input-group-text { background: var(--superficie); border-color: var(--borde-fuerte); }

.aviso-mayusculas {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin: 0 0 .9rem;
  padding: .45rem .65rem;
  border-radius: var(--radio-sm);
  background: var(--aviso-fondo);
  color: var(--aviso-texto);   /* 4.5:1 sobre su fondo */
  font-size: .82rem;
}

/* 48px: el botón principal de la pantalla, con sitio de sobra para el giro
   sin que el texto se mueva al aparecer. */
.boton-entrar {
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
}

.boton-entrar.cargando { cursor: progress; }

/* Bootstrap baja la opacidad de los deshabilitados hasta un gris que no llega a
   4.5:1. Mientras carga, el botón sigue siendo texto blanco sobre azul. */
.boton-entrar:disabled { opacity: 1; }

@media (max-width: 900px) {
  .login-shell { grid-template-columns: 1fr; }
  .login-marca { padding: 2.25rem 1.5rem; gap: .9rem; }
  .login-marca img { width: 110px; }
  .login-marca h1 { font-size: 1.5rem; }
  /* Con el panel de marca visible arriba, el isotipo pequeño sobra. */
  .login-logo-movil { display: none; }
  .login-panel { padding: 1.75rem 1.25rem 2.5rem; }
}

/* Quien prefiere menos movimiento no debería ver el giro del botón. El estado
   sigue comunicándose: el botón dice "Entrando…" y queda deshabilitado. */
@media (prefers-reduced-motion: reduce) {
  .boton-entrar .spinner-border { animation: none; opacity: .6; }
}

/* ---------- Documentos imprimibles (recibos y reportes) ---------- */
.recibo { border-color: var(--borde-fuerte) !important; }

.recibo-encabezado {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  padding-bottom: 1rem;
  margin-bottom: 1rem;
  border-bottom: 2px solid var(--azul-suave);
}

.recibo-marca { display: flex; align-items: center; gap: .75rem; }
.recibo-marca img { width: 46px; height: 46px; }

@media print {
  .app-sidebar, .app-topbar, .barra-estela, .d-print-none, .alert-dismissible { display: none !important; }
  .app-content { padding: 0; }
  body { background: #fff; font-size: 12px; }
  .recibo { border: 1px solid #999 !important; box-shadow: none !important; max-width: 100% !important; }
}

/* Foco visible para accesibilidad WCAG AA */
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, .nav-link:focus-visible {
  outline: 3px solid var(--azul-marca);
  outline-offset: 2px;
}

@media (max-width: 768px) {
  .app-sidebar {
    position: fixed;
    z-index: 1040;
    height: 100%;
    transform: translateX(-100%);
    transition: transform .2s ease;
    box-shadow: var(--sombra-fuerte);
  }
  .app-sidebar.mostrar { transform: translateX(0); }
  .app-content { padding: 1.1rem; }
  .calendario-dia { min-height: 62px; }
  .calendario-evento { display: none; }
}

/* ---------------------------------------------------------------------------
   Avisos accionables del tablero
   --------------------------------------------------------------------------- */
.lista-pendientes {
    list-style: none;
    padding-left: 0;
}

.lista-pendientes li {
    display: flex;
    gap: .65rem;
    align-items: flex-start;
    padding: .55rem 0;
    border-bottom: 1px solid var(--borde);
}

.lista-pendientes li:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

.lista-pendientes li > i {
    color: var(--azul-accion);
    margin-top: .2rem;
}

.lista-pendientes a {
    color: var(--azul-accion);
    text-decoration: none;
}

.lista-pendientes a:hover,
.lista-pendientes a:focus-visible {
    text-decoration: underline;
}

/* Cartera por familia */
.fila-familia > td {
    background: var(--superficie-alt);
}

.caja-cobro {
    background: var(--superficie-alt);
    border: 1px solid var(--borde);
    border-radius: .6rem;
    padding: .85rem;
}

/* ---------------------------------------------------------------------------
   Mi perfil y solicitudes de actualización de datos
   --------------------------------------------------------------------------- */

/* El chip de usuario es un enlace a "Mi perfil": tiene que verse pulsable. */
a.usuario-chip {
    color: var(--texto);
    text-decoration: none;
    transition: border-color .15s ease, background .15s ease;
}

a.usuario-chip:hover,
a.usuario-chip:focus-visible {
    border-color: var(--azul-medio);
    background: var(--azul-suave);
}

.ficha-perfil::before {
    content: "";
    display: block;
    height: 4px;
    background: var(--estela);
}

.avatar-perfil {
    width: 58px; height: 58px;
    flex: 0 0 58px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--azul-suave);
    color: var(--azul-profundo);
    font-family: var(--fuente-display);
    font-weight: 700;
    font-size: 1.35rem;
}

.lista-datos > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .45rem 0;
    border-bottom: 1px solid var(--borde);
}

.lista-datos > div:last-child { border-bottom: 0; }

.lista-datos dt {
    font-weight: 500;
    /* Etiqueta de dato, no texto decorativo: necesita el gris que sí llega a AA. */
    color: var(--neutro-texto);
    font-size: .85rem;
}

.lista-datos dd {
    margin: 0;
    text-align: right;
    font-size: .9rem;
    overflow-wrap: anywhere;
}

/* --neutro-texto y no --texto-tenue: el valor anterior es texto normal y con el
   gris tenue se queda en 4.31:1, por debajo del mínimo AA. */
.tabla-cambios .valor-anterior { color: var(--neutro-texto); text-decoration: line-through; }
.tabla-cambios .valor-propuesto { color: var(--exito-texto); font-weight: 600; }

/* ---------------------------------------------------------------------------
   Tablas anchas en pantallas chicas

   Ninguna tabla puede empujar el ancho de la página: en móvil se desplazan
   dentro de su propio contenedor. Para las tablas de DataTables el scroll va
   sobre la columna que envuelve la tabla (.dt-row > .col-*) y no sobre todo el
   wrapper, para que el buscador y la paginación se queden en su sitio.
   --------------------------------------------------------------------------- */
.dataTables_wrapper .dt-row > [class*="col-"] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Deja respirar la barra de scroll para que no tape la última fila. */
.table-responsive,
.dataTables_wrapper .dt-row > [class*="col-"] {
    padding-bottom: 2px;
}

/* Sin esto la tabla se comprime hasta romper las columnas en vez de desplazarse. */
.table-responsive > .table,
.dataTables_wrapper table.dataTable {
    min-width: 34rem;
}

/* Exención al mínimo: tablas de dos o tres columnas (resúmenes, totales, diffs) y
   tablas que reducen columnas en pantallas chicas, donde el mínimo sobraría. */
.table-responsive > .table.tabla-angosta,
.dataTables_wrapper table.dataTable.tabla-angosta {
    min-width: 0;
}

/* ---------------------------------------------------------------------------
   Buzón de material faltante, quejas y sugerencias
   --------------------------------------------------------------------------- */
.caja-envio {
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    padding: .85rem 1rem;
    background: var(--superficie-alt);
}

.caja-envio legend {
    float: none;
    width: auto;
    font-weight: 600;
    color: var(--texto);
}

/* El mensaje se captura en un textarea: se respetan los saltos de línea al leerlo. */
.mensaje-cuerpo {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.lista-buzon > article {
    padding: .85rem 0;
    border-bottom: 1px solid var(--borde);
}

.lista-buzon > article:last-child { border-bottom: 0; padding-bottom: 0; }

/* ---------------------------------------------------------------------------
   Ficha del panel de detalle (lista maestro-detalle)
   --------------------------------------------------------------------------- */
.ficha-detalle .lista-datos { margin-bottom: 0; }

.lista-simple {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: .88rem;
}

.lista-simple > li {
    padding: .35rem 0;
    border-bottom: 1px solid var(--borde);
}

.lista-simple > li:last-child { border-bottom: 0; }

.lista-simple > li::before {
    content: "";
    display: inline-block;
    width: .35rem; height: .35rem;
    border-radius: 50%;
    background: var(--azul-marca);
    margin-right: .5rem;
    vertical-align: middle;
}

/* El avatar del salón muestra su color en lugar de iniciales. */
.item-avatar .salon-punto { width: .95rem; height: .95rem; box-shadow: none; }

/* El buscador de DataTables va alineado a la derecha con el label en línea; en
   pantallas muy angostas esa combinación se sale unos píxeles del contenedor. */
@media (max-width: 575.98px) {
    .dataTables_wrapper .dataTables_filter,
    .dataTables_wrapper .dataTables_length {
        text-align: left;
    }

    .dataTables_wrapper .dataTables_filter label,
    .dataTables_wrapper .dataTables_length label {
        display: block;
        width: 100%;
    }

    /* !important porque dataTables.bootstrap5 declara
       "div.dataTables_wrapper div.dataTables_filter input" con más especificidad. */
    .dataTables_wrapper .dataTables_filter input {
        display: block !important;
        width: 100% !important;
        margin-left: 0 !important;
        margin-top: .25rem;
    }
}

/* =============================================================================
   Notificaciones — campana de la barra superior y bandeja
   ============================================================================= */

/* 38px de lado. Queda por debajo del ideal táctil de 44, pero ya es el control
   más grande de la barra superior —los demás miden 29— y subirlo a 44 lo haría
   sobresalir de una fila que no se rediseña aquí. El destino real del toque es
   el panel, donde cada entrada sí pasa de 44px de alto. */
.campana-boton {
  width: 38px;
  height: 38px;
  display: inline-grid;
  place-items: center;
}

.campana-insignia {
  font-size: .65rem;
  padding: .2rem .35rem;
  min-width: 1.15rem;
}

.campana-panel {
  width: min(22rem, calc(100vw - 1.5rem));
  padding: 0;
  overflow: hidden;
}

/* El desplazamiento vive dentro del panel: sin este tope, doce avisos hacen que
   el menú desborde la pantalla en un teléfono y no haya forma de llegar al pie. */
.campana-lista {
  max-height: min(24rem, 60vh);
  overflow-y: auto;
}

.campana-item {
  display: flex;
  gap: .65rem;
  align-items: flex-start;
  padding: .7rem 1rem;
  white-space: normal;   /* dropdown-item de Bootstrap fuerza nowrap */
  min-height: 44px;
}

.campana-item-nueva {
  background: var(--azul-suave);
}

.campana-icono {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--superficie-alt);
  color: var(--azul-accion);
  font-size: .8rem;
}

.campana-texto { min-width: 0; }   /* deja que el texto se recorte en vez de ensanchar el panel */

.campana-titulo {
  display: block;
  font-weight: 600;
  font-size: .87rem;
  line-height: 1.3;
}

.campana-mensaje {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: .8rem;
  color: var(--texto-tenue);
  line-height: 1.4;
}

.campana-fecha {
  display: block;
  font-size: .72rem;
  color: var(--texto-tenue);
  margin-top: .15rem;
}

/* --- Bandeja completa --- */

.lista-notificaciones { display: grid; gap: .6rem; }

.notificacion {
  display: flex;
  gap: .85rem;
  align-items: flex-start;
  padding: .9rem 1rem;
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: .6rem;
}

/* La barra lateral azul, y no sólo el fondo, distingue lo no leído: el color de
   fondo por sí solo no basta para quien no percibe ese contraste. La insignia
   "Sin leer" del marcado dice lo mismo en texto. */
.notificacion-nueva {
  border-left: 4px solid var(--azul-accion);
  background: var(--azul-suave);
}

.notificacion-icono {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--superficie-alt);
  color: var(--azul-accion);
}

.notificacion-cuerpo { flex: 1 1 auto; min-width: 0; }

.notificacion-titulo {
  font-weight: 600;
  color: var(--azul-profundo);
  line-height: 1.35;
}

.notificacion-mensaje {
  color: var(--texto-tenue);
  font-size: .92rem;
  line-height: 1.5;
  overflow-wrap: anywhere;   /* un nombre largo no debe desbordar en móvil */
}

.notificacion-accion { flex: 0 0 auto; }

@media (max-width: 575.98px) {
  .notificacion {
    flex-wrap: wrap;
    padding: .8rem;
  }

  /* El botón pasa a ocupar el ancho completo bajo el texto: al lado, en 320px,
     comprimiría el mensaje a dos palabras por línea. */
  .notificacion-accion {
    flex: 1 0 100%;
    display: flex;
    justify-content: flex-end;
    margin-top: .5rem;
  }

  /* 44px es el mínimo táctil. Aquí sí se cumple sin pelear con nada: el botón
     está en el contenido, no en la barra superior, y tiene la fila para él solo.
     btn-sm de Bootstrap deja 29px, que es un blanco difícil de acertar con el
     pulgar — y esta es la pantalla que usan las familias. */
  .notificacion-accion .btn {
    min-height: 44px;
    padding-inline: 1rem;
  }
}

/* =============================================================================
   Barra que ofrece activar los avisos push
   ============================================================================= */

/* Sin margen lateral: las dos barras viven dentro del dashboard, que ya trae el
   suyo desde .app-content. Cuando estaban al pie del layout necesitaban el
   propio para alinearse con el contenido. */
.barra-avisos {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin: 0 0 1rem;
  padding: .85rem 1rem;
  border: 1px solid var(--azul-medio);
  border-radius: var(--radio-sm);
  background: var(--azul-suave);
  color: var(--texto);
}

.barra-avisos > .fa-bell { color: var(--azul-accion); }

.barra-avisos-texto { flex: 1 1 16rem; font-size: .88rem; line-height: 1.45; }

/* 44px es el mínimo táctil; el btn-sm de Bootstrap se queda en 31. */
.barra-avisos .btn { min-height: 44px; padding-inline: 1rem; }

@media (max-width: 575.98px) {
  /* Los dos botones comparten la fila de abajo, cada uno con su mitad: al lado
     del texto, en 320px, quedaban de dos palabras por línea. */
  .barra-avisos .btn { flex: 1 1 40%; }
}

/* Barra de instalación. Comparte el aspecto de la de avisos pero con el tono
   neutro: instalar es una sugerencia, no algo que haga falta atender. */
.barra-instalar {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin: 0 0 1rem;
  padding: .85rem 1rem;
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-sm);
  background: var(--superficie-alt);
  color: var(--texto);
}

.barra-instalar > .fa-mobile-screen-button { color: var(--azul-accion); }

.barra-instalar-texto { flex: 1 1 16rem; font-size: .88rem; line-height: 1.45; }

/* El icono de Compartir de iOS va dentro del texto: sin él, "toca Compartir"
   obliga a buscar cuál de los botones de Safari es. */
.barra-instalar-texto .fa-arrow-up-from-bracket { color: var(--azul-accion); }

.barra-instalar .btn { min-height: 44px; padding-inline: 1rem; }

@media (max-width: 575.98px) {
  .barra-instalar .btn { flex: 1 1 40%; }
}

/* Entrevista de seguimiento: pares etiqueta/respuesta de la vista de lectura. */
.entrevista-datos { display: grid; grid-template-columns: minmax(11rem, 18rem) 1fr; gap: .35rem 1rem; margin: 0; }
.entrevista-datos dt { font-size: .82rem; color: var(--texto-tenue); font-weight: 500; }
/* Las respuestas son párrafos escritos a mano: se respetan sus saltos de línea
   y se parten las palabras largas para que no desborden en móvil. */
.entrevista-datos dd { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }

@media (max-width: 575.98px) {
  /* En una columna: con 11rem de etiqueta, a la respuesta le quedaban dos
     palabras por línea. */
  .entrevista-datos { grid-template-columns: 1fr; gap: .1rem; }
  .entrevista-datos dd { margin-bottom: .65rem; }
}

/* El logotipo completo del panel de marca. Va sobre el degradado azul, así que
   se le pone un fondo blanco redondeado: el texto morado del descriptor no
   contrasta contra ese azul. */
.login-logotipo {
  width: min(320px, 78%);
  height: auto;
  background: #fff;
  padding: 1.25rem 1.5rem;
  border-radius: var(--radio);
  box-shadow: 0 12px 32px rgba(0,0,0,.16);
}

/* =============================================================================
   Horario semanal de los salones
   ============================================================================= */

/* El color del salón entra por variable desde la vista: es dato del centro, no
   una decisión de diseño, y así la hoja no tiene que conocer los seis. */
.salon-horario { border-top: 4px solid var(--salon-color, var(--azul-accion)); overflow: hidden; }

.salon-horario-cabecera {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  padding: .85rem 1rem;
  background: var(--superficie-alt);
  border-bottom: 1px solid var(--borde);
}

.salon-horario-nombre {
  font-family: var(--fuente-display);
  font-size: 1rem;
  letter-spacing: .04em;
  color: var(--salon-color, var(--azul-accion));
}

.salon-horario-terapeuta { font-size: .78rem; letter-spacing: .04em; color: var(--texto-tenue); }

.salon-horario-tabla { table-layout: fixed; }

.salon-horario-tabla th {
  width: 20%;
  text-align: center;
  font-size: .7rem;
}

/* DOS PROBLEMAS DE LECTURA, LOS DOS DE ESPECIFICIDAD Y CONTRASTE.

   1. El `color: #fff` que llevaba esta cabecera nunca llegaba a aplicarse:
      `.table > thead > tr > th` (0,1,3) le ganaba a `.salon-horario-tabla th`
      (0,1,1) y pintaba el texto en gris tenue. Gris sobre el amarillo del salón
      daba 1.9:1.
   2. Aun en blanco, el amarillo daba 1.96:1, el naranja 2.99 y el verde 3.61,
      cuando el mínimo son 4.5.

   Se resuelven juntos: el selector sube a (0,3,1) para ganar sin `!important`, y
   cada color se oscurece hacia el azul profundo del logotipo hasta que los seis
   pasan. El peor queda en 5.12:1. El tono se reconoce igual —sólo baja de
   luminosidad— y el color a plena fuerza sigue en el filo superior de la tarjeta
   y en el nombre del salón, que es donde se identifica de un vistazo.

   La primera declaración de fondo es el respaldo para navegadores sin
   color-mix. */
.salon-horario .salon-horario-tabla > thead > tr > th {
  background: var(--salon-cabecera, var(--salon-color, var(--azul-accion)));
  color: var(--salon-texto, #14303D);
}

/* La especificidad sube a (0,2,3) a propósito: la densidad compacta de
   `.table-sm > tbody > tr > td` (0,1,3) le ganaba y le encogía el relleno
   vertical. Estas celdas no son celdas de lectura, son la zona donde se sueltan
   los alumnos al arrastrarlos, y ahí el relleno es superficie que hay que
   acertar con el ratón. */
.salon-horario-tabla > tbody > tr > td.salon-horario-celda {
  vertical-align: top;
  padding: .5rem;
  border-left: 1px solid var(--borde);
  transition: background-color .12s ease;
}

/* El destino válido se marca al pasar por encima. Sin esta señal, arrastrar es
   adivinar dónde suelta uno. */
.salon-horario-celda.recibe-soltar { background: var(--azul-suave); box-shadow: inset 0 0 0 2px var(--azul-accion); }

.salon-horario-celda.esta-llena { background: var(--neutro-fondo); }

.salon-alumno {
  display: flex;
  align-items: center;
  gap: .35rem;
  flex-wrap: wrap;
  padding: .3rem .45rem;
  margin-bottom: .3rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  font-size: .82rem;
}

.salon-alumno[draggable="true"] { cursor: grab; }
.salon-alumno.se-arrastra { opacity: .45; cursor: grabbing; }

.salon-alumno-nombre { font-weight: 600; }
.salon-alumno-hora { color: var(--texto-tenue); font-size: .74rem; }

/* El desplegable ocupa su propia línea: es la vía de teclado y táctil, y
   apretujado junto al nombre no se acierta con el pulgar. */
.salon-alumno-mover { flex: 1 1 100%; font-size: .72rem; padding: .15rem .4rem; }

.salon-horario-vacia { color: var(--texto-tenue); text-align: center; padding: .5rem 0; }

.salon-horario-cupo {
  text-align: right;
  font-size: .7rem;
  color: var(--texto-tenue);
  border-top: 1px dashed var(--borde);
  padding-top: .25rem;
  margin-top: .25rem;
}

@media (max-width: 767.98px) {
  /* En móvil la tabla no cabe en cinco columnas legibles; se deja desplazar en
     horizontal dentro de su contenedor en vez de encoger los nombres. */
  .salon-horario-tabla { min-width: 640px; }
}

/* Alta de un alumno dentro de la celda del día. El botón queda al pie de la
   columna, después de los nombres: primero se ve quién está y luego se agrega,
   que es el orden en que se piensa. */
.salon-agregar-boton { font-size: .72rem; padding: .12rem .3rem; margin-top: .2rem; }

.salon-agregar {
  margin-top: .35rem;
  padding: .4rem;
  border: 1px dashed var(--borde-fuerte);
  border-radius: var(--radio-sm);
  background: var(--superficie-alt);
}

.salon-agregar .form-select,
.salon-agregar .form-control { font-size: .72rem; padding: .18rem .4rem; }

.salon-agregar .btn { font-size: .72rem; padding: .2rem .4rem; }

/* La contraseña recién generada. Grande y monoespaciada porque se lee en voz
   alta por teléfono o se copia a mano: aquí confundir una letra cuesta otra
   llamada. Espaciada para que los grupos se distingan de un vistazo. */
.password-generada {
  font-family: 'Courier New', ui-monospace, monospace;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: .12em;
  color: var(--azul-profundo);
  background: var(--azul-suave);
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-sm);
  padding: .6rem .9rem;
  display: inline-block;
  user-select: all;   /* un clic la selecciona entera */
}

/* ---------------------------------------------------------------------------
   Bitácora: el "antes → después" de cada cambio
   ---------------------------------------------------------------------------
   El color hace el trabajo que haría leer dos veces: lo que había, apagado y
   tachado; lo que quedó, en tinta normal. Así se ve qué se movió sin comparar
   cadena contra cadena.
   --------------------------------------------------------------------------- */

.lista-cambios {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: .82rem;
  line-height: 1.5;
}

.lista-cambios .campo {
  color: var(--texto-tenue);
  font-weight: 600;
  margin-right: .35rem;
}

.lista-cambios .campo::after { content: ":"; }

/* Tachado y apagado: el valor viejo tiene que estar —es la mitad del dato— sin
   competir por la atención con el que quedó. */
.lista-cambios .valor-viejo {
  color: var(--texto-tenue);
  text-decoration: line-through;
}

.lista-cambios .flecha { color: var(--azul-medio); margin: 0 .3rem; }

.lista-cambios .valor-nuevo { color: var(--texto); font-weight: 500; }

/* =====================================================================
   ESQUELETOS DE CARGA

   Lo que se enseña mientras algo viaja por la red. Sustituye a los
   giradores: un girador dice "espera" y nada más; un esqueleto dice
   además "va a aparecer una ficha con un título, tres datos y dos
   botones", así que cuando llega el contenido la vista no da un salto
   y el ojo ya sabe dónde mirar.

   Se usan SÓLO donde hay una espera de verdad —el panel que se pide
   por red, la tabla que pagina en el servidor—. Poner un esqueleto
   donde el servidor ya mandó el HTML sería fingir una espera que no
   existe, y encima retrasaría lo que ya estaba listo.
   ===================================================================== */

.esqueleto {
  position: relative;
  overflow: hidden;
  background-color: var(--borde);
  border-radius: var(--radio-sm);

  /* El bloque no debe leerse como contenido: son barras sin significado.
     Quien use lector de pantalla oye el aviso de "Cargando" que va aparte. */
  color: transparent;
  user-select: none;
}

/* El brillo que recorre la barra. Va con transform y no con background-position
   para que lo componga la GPU: son muchas barras a la vez y animar el fondo de
   cada una hace trabajar al hilo principal justo cuando está ocupado con la
   respuesta que se está esperando. */
.esqueleto::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
      90deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .65) 50%,
      rgba(255, 255, 255, 0) 100%);
  animation: esqueleto-brillo 1.4s ease-in-out infinite;
}

@keyframes esqueleto-brillo {
  100% { transform: translateX(100%); }
}

/* Quien pidió menos movimiento no debería recibir un destello recorriendo la
   pantalla cada segundo y medio. La barra se queda quieta y sigue diciendo lo
   mismo: aquí va a haber algo. */
@media (prefers-reduced-motion: reduce) {
  .esqueleto::after { animation: none; }
}

.esqueleto-linea { height: .72rem; margin-bottom: .55rem; }
.esqueleto-linea:last-child { margin-bottom: 0; }

.esqueleto-titulo { height: 1.1rem; width: 45%; margin-bottom: .9rem; }
.esqueleto-corta  { width: 35%; }
.esqueleto-media  { width: 60%; }
.esqueleto-larga  { width: 85%; }

.esqueleto-avatar {
  width: 2.6rem; height: 2.6rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.esqueleto-boton { height: 2rem; width: 6.5rem; border-radius: var(--radio-sm); }

/* Dentro de una tabla la barra hereda el alto del renglón, así que no se le
   pone margen: lo que separa es la propia fila. */
.esqueleto-celda { height: .72rem; margin: .35rem 0; }

/* =====================================================================
   FORMULARIOS DEL INGRESO
   Datos adicionales y carta responsiva.
   ===================================================================== */

/* Los tres pasos del alta. Es una lista ordenada de verdad porque el orden
   es información: no se puede firmar la carta de un alumno que todavía no
   existe. */
.pasos-alta {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  list-style: none;
  counter-reset: paso-alta;
  margin: 0 0 1.25rem;
  padding: 0;
  font-size: .84rem;
}

.pasos-alta li {
  counter-increment: paso-alta;
  display: flex;
  align-items: center;
  gap: .45rem;
  padding: .35rem .8rem .35rem .5rem;
  border: 1px solid var(--borde);
  border-radius: 999px;
  background: var(--superficie);
  color: var(--texto-tenue);
}

.pasos-alta li::before {
  content: counter(paso-alta);
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .72rem;
  background: var(--neutro-fondo);
  color: var(--texto-tenue);
}

.pasos-alta .hecho { border-color: #BFE0CF; color: var(--exito-texto); }
.pasos-alta .hecho::before { content: '✓'; background: var(--exito-fondo); color: var(--exito-texto); }

.pasos-alta .actual {
  border-color: var(--azul-marca);
  background: var(--azul-suave);
  color: var(--azul-profundo);
  font-weight: 600;
}
.pasos-alta .actual::before { background: var(--azul-accion); color: #fff; }

/* Las opciones de un grupo, en fila cuando caben. Con cinco opciones cortas,
   una columna deja media pantalla vacía y obliga a bajar la vista. */
.opciones { display: flex; flex-wrap: wrap; gap: .35rem 1.5rem; }
.opciones .form-check { margin: 0; }

/* Los ocho canales sensoriales. Rejilla y no lista: se marcan de un vistazo
   comparando con la hoja de papel, que también los tiene en bloque. */
.canales {
  display: grid;
  gap: .85rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.canal {
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  padding: .6rem .75rem;
  background: var(--superficie-alt);
}

/* El recuadro de firma. Alto generoso: una firma hecha con el dedo necesita
   sitio, y un recuadro estrecho sale como un garabato apretado. */
.firma-marco {
  position: relative;
  border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-sm);
  background: #fff;
  overflow: hidden;
  max-width: 34rem;
}

.firma-lienzo {
  display: block;
  width: 100%;
  height: 11rem;
  /* Sin esto, arrastrar el dedo dentro del recuadro desplaza la página en vez
     de dibujar, y en una tablet no hay forma de firmar. */
  touch-action: none;
  cursor: crosshair;
}

/* La línea sobre la que se firma, como en el papel. Va debajo del trazo y no
   se imprime con él: es una guía, no parte de la firma. */
.firma-linea {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 2.2rem;
  border-bottom: 1px solid var(--borde-fuerte);
  pointer-events: none;
}

/* La firma guardada, cuando se enseña en el expediente o en la ficha. */
.firma-guardada {
  max-width: 18rem;
  max-height: 5.5rem;
  display: block;
}

/* Los dos formatos del ingreso dentro del expediente */
.rejilla-formatos {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
}

.formato {
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  padding: .85rem 1rem;
  background: var(--superficie-alt);
}

.formato-titulo {
  font-family: var(--fuente-display);
  font-weight: 700;
  color: var(--azul-profundo);
  font-size: .95rem;
  margin-bottom: .3rem;
}

/* ---------------------------------------------------------------------------
   Lista de casillas

   Sustituye a los <select multiple>, donde un clic sin Ctrl borraba el resto
   de la selección sin decir nada. Va en una caja con desplazamiento propio y
   no suelta en el formulario: con veinte padres de familia dados de alta, la
   lista empujaría hacia abajo todo lo que viene después.

   La altura es la misma que tenía el desplegable al que sustituye (size="6"),
   para que el formulario no cambie de forma.
   --------------------------------------------------------------------------- */
.lista-casillas {
  max-height: 11rem;
  overflow-y: auto;
  border: 1px solid var(--bs-border-color, #ced4da);
  border-radius: .375rem;
  padding: .5rem .75rem;
  background: var(--bs-body-bg, #fff);
}

.lista-casillas .form-check {
  margin-bottom: .25rem;
}

.lista-casillas .form-check:last-child {
  margin-bottom: 0;
}

/* Toda la fila es zona de clic, no sólo el cuadrito: en una tablet acertarle
   a un checkbox de 1 rem con el dedo es justo la fricción que hace que alguien
   marque a la persona de al lado. */
.lista-casillas .form-check-label {
  display: block;
  cursor: pointer;
  padding: .1rem 0;
}

/* Los ya vinculados se pintan en el azul de la marca y van arriba: es lo que
   sustituye al desplazamiento automático que hacía el desplegable, para que al
   abrir la ficha se vea de un golpe a quién tiene el alumno. */
.lista-casillas .esta-marcado .form-check-label {
  font-weight: 600;
  color: var(--azul-profundo);
}

/* ---------------------------------------------------------------------------
   Catálogo de reportes

   Antes eran doce tarjetas en una rejilla de tres columnas. Un catálogo se
   consulta sabiendo lo que se busca: lo que hace falta es leer doce nombres de
   corrido, no barrer la pantalla en zigzag. Se cambia por listas compactas,
   una por área, y cabe entero sin desplazarse.

   Las áreas van en columnas a partir de pantalla ancha porque son once bloques
   de uno a tres renglones: en una sola columna dejarían medio ancho vacío.

   Columnas de flujo y no una rejilla: con grid, un área de tres renglones
   estira la fila entera y abre huecos debajo de las de un solo renglón que
   tiene al lado. Así cada bloque cae donde quepa y la lista queda sin agujeros.
   --------------------------------------------------------------------------- */
.catalogo-reportes {
  column-gap: 1.5rem;
}

@media (min-width: 992px) {
  .catalogo-reportes { column-count: 2; }
}

@media (min-width: 1600px) {
  .catalogo-reportes { column-count: 3; }
}

/* Un área nunca se parte entre dos columnas: media lista arriba del todo y la
   otra media al pie de la siguiente columna no se lee como un grupo. */
.catalogo-area {
  break-inside: avoid;
  page-break-inside: avoid;
  margin-bottom: 1rem;
  display: inline-block;
  width: 100%;
}

.catalogo-area-titulo {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--fuente-display);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--texto-tenue);
  margin: 0 0 .35rem .15rem;
}

.catalogo-area-cuenta {
  font-size: .65rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--neutro-texto);
  background: var(--neutro-fondo);
  border-radius: 999px;
  padding: .05rem .4rem;
}

.catalogo-lista {
  border: 1px solid var(--borde);
  border-radius: .5rem;
  overflow: hidden;
  background: var(--superficie);
}

.catalogo-fila {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .55rem .75rem;
  border-color: var(--borde);
  color: var(--texto);
  text-decoration: none;
}

.catalogo-fila:hover,
.catalogo-fila:focus-visible {
  background: var(--superficie-alt);
  color: var(--azul-profundo);
  text-decoration: none;
}

/* El foco se ve por dentro: con outline normal, en una fila pegada al borde de
   la lista el anillo queda cortado por el overflow del contenedor. */
.catalogo-fila:focus-visible {
  outline: 2px solid var(--azul-marca);
  outline-offset: -2px;
}

.catalogo-icono {
  flex: 0 0 1.25rem;
  text-align: center;
  color: var(--azul-marca);
  font-size: .95rem;
}

.catalogo-texto {
  min-width: 0;
  flex: 1 1 auto;
}

.catalogo-nombre {
  display: block;
  font-weight: 600;
  font-size: .9rem;
  line-height: 1.25;
}

/* La descripción se recorta a un renglón: es una ayuda para distinguir dos
   nombres parecidos, no un texto que haya que leer entero. Completa sigue
   estando en el title del enlace y en la propia pantalla del reporte. */
.catalogo-descripcion {
  display: block;
  font-size: .78rem;
  line-height: 1.3;
  color: var(--texto-tenue);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.catalogo-flecha {
  flex: 0 0 auto;
  font-size: .7rem;
  color: var(--borde-fuerte);
}

.catalogo-fila:hover .catalogo-flecha,
.catalogo-fila:focus-visible .catalogo-flecha {
  color: var(--azul-marca);
}

/* ---------------------------------------------------------------------------
   AGENDA · VISTA SEMANAL
   Rejilla de horas por días. El mes sirve para ubicarse; ésta para trabajar,
   y por eso aquí sí caben las sesiones enteras y no un resumen.

   Se desplaza en horizontal cuando no cabe —un teléfono ve tres días y empuja
   hacia el resto, como cualquier calendario— con la columna de las horas fija:
   sin ella, dos dedos de scroll y ya no se sabe si son las nueve o la una.
   --------------------------------------------------------------------------- */

.semana-lienzo { overflow-x: auto; }

/* Rejilla en pantalla ancha, lista por días en el teléfono. Nunca las dos. */
.semana-agenda { display: none; }

@media (max-width: 767.98px) {
  .semana-lienzo { display: none; }
  .semana-agenda { display: block; }
}

.semana-agenda-dia { border-top: 1px solid var(--borde); }
.semana-agenda-dia:first-child { border-top: 0; }
.semana-agenda-dia.es-hoy { background: rgba(38, 169, 224, .05); }

.semana-agenda-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .5rem .85rem .2rem;
  color: var(--azul-profundo);
  text-decoration: none;
}

.semana-agenda-nombre {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .03em;
  text-transform: uppercase;
}

.semana-agenda-cuenta {
  font-size: .7rem;
  color: var(--texto-tenue);
  font-variant-numeric: tabular-nums;
}

.semana-agenda-vacio {
  margin: 0;
  padding: 0 .85rem .5rem;
  font-size: .76rem;
  color: var(--texto-tenue);
}

.semana-agenda-sesion {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-height: 46px;                 /* dedo, no cursor */
  padding: .35rem .85rem;
  border-left: 3px solid var(--salon, var(--azul-medio));
  margin-left: .85rem;
  color: var(--texto);
  text-decoration: none;
}

.semana-agenda-sesion.es-caida { color: var(--neutro-texto); }
.semana-agenda-sesion:active { background: var(--azul-suave); }

.semana-agenda-hora {
  flex: 0 0 auto;
  font-family: var(--fuente-display);
  font-size: .76rem;
  font-variant-numeric: tabular-nums;
  color: var(--texto-tenue);
}

.semana-agenda-quien { flex: 1 1 auto; min-width: 0; font-size: .84rem; }
.semana-agenda-quien > span { font-weight: 600; }
.semana-agenda-quien .esta-cancelada { text-decoration: line-through; }

.semana-agenda-quien small {
  display: block;
  font-size: .72rem;
  color: var(--texto-tenue);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.semana-rejilla {
  display: grid;
  grid-template-columns: 62px repeat(7, minmax(124px, 1fr));
  grid-auto-rows: minmax(42px, auto);
  min-width: 920px;
}

.semana-esquina {
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--superficie);
  border-bottom: 1px solid var(--borde);
}

.semana-cabecera {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1rem;
  padding: .5rem .25rem;
  border-bottom: 1px solid var(--borde);
  border-left: 1px solid var(--borde);
  background: var(--superficie);
  color: var(--texto);
  text-decoration: none;
  position: sticky;
  top: 0;
  z-index: 2;
}

.semana-cabecera:hover,
.semana-cabecera:focus-visible { background: var(--azul-suave); color: var(--azul-profundo); }

.semana-cabecera-dia {
  font-size: .66rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--texto-tenue);
}

.semana-cabecera-numero {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.semana-cabecera.es-hoy { background: var(--azul-suave); }
.semana-cabecera.es-hoy .semana-cabecera-numero,
.semana-cabecera.es-hoy .semana-cabecera-dia { color: var(--azul-profundo); }

.semana-hora {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--superficie);
  border-top: 1px solid var(--borde);
  padding: .35rem .4rem 0 0;
  text-align: right;
  font-family: var(--fuente-display);
  font-size: .72rem;
  font-variant-numeric: tabular-nums;
  color: var(--texto-tenue);
}

.semana-celda {
  border-top: 1px solid var(--borde);
  border-left: 1px solid var(--borde);
  padding: 3px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.semana-celda.es-hoy { background: rgba(38, 169, 224, .04); }

/* La sesión lleva el color de su salón en el filo izquierdo: es el mismo código
   que en el resto del sistema, y de un vistazo se ve si la semana está repartida
   o se amontona en un salón. */
.semana-sesion {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: .3rem;
  padding: .22rem .95rem .22rem .45rem;
  border-radius: var(--radio-sm);
  border-left: 3px solid var(--salon, var(--azul-medio));
  background: var(--superficie-alt);
  color: var(--texto);
  text-decoration: none;
  font-size: .74rem;
  line-height: 1.3;
  min-width: 0;
}

.semana-sesion:hover,
.semana-sesion:focus-visible {
  background: var(--azul-suave);
  color: var(--azul-profundo);
  box-shadow: var(--sombra);
}

.semana-sesion-hora {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: .68rem;
  color: var(--texto-tenue);
}

.semana-sesion-nombre {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.semana-sesion-nombre.esta-cancelada { text-decoration: line-through; }

.semana-sesion.es-firme      { background: var(--exito-fondo); }
.semana-sesion.es-programada { background: var(--superficie-alt); }
.semana-sesion.es-caida      { background: var(--neutro-fondo); color: var(--neutro-texto); }

.semana-sesion-marca {
  position: absolute;
  top: 50%;
  right: .28rem;
  transform: translateY(-50%);
  font-size: .58rem;
  color: var(--aviso-texto);
}

/* ---------------------------------------------------------------------------
   AGENDA · MAPA DE HORAS DEL FORMULARIO DE SOLICITUD
   Las horas del día elegido como fichas que se pueden tocar. Es a la vez el
   informe —qué hay ocupado, qué he pedido ya— y el selector: tocar una la sube
   al reloj del formulario. Antes esto exigía ir a otra pantalla, recorrer las
   catorce horas de la jornada y volver con el hueco memorizado.
   --------------------------------------------------------------------------- */

.mapa-horas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 6px;
  transition: opacity .12s ease;
}

.mapa-horas.esta-cargando { opacity: .45; }

.hora-chip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .05rem;
  min-height: 46px;           /* dedo, no cursor */
  padding: .35rem .5rem;
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  text-align: left;
  cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease;
}

.hora-chip:hover { border-color: var(--azul-marca); }

.hora-chip-hora {
  font-family: var(--fuente-display);
  font-weight: 700;
  font-size: .82rem;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.hora-chip-detalle {
  font-size: .66rem;
  line-height: 1.2;
  color: var(--texto-tenue);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

/* El estado no se fía sólo del color: la ocupada se apaga, la pedida lleva su
   propio texto, y la elegida se marca con un aro además del fondo. */
.hora-chip.es-libre       { background: var(--exito-fondo); border-color: transparent; }
.hora-chip.es-libre .hora-chip-hora { color: var(--exito-texto); }

.hora-chip.es-ocupada     { background: var(--neutro-fondo); border-color: transparent; }
.hora-chip.es-ocupada .hora-chip-hora { color: var(--neutro-texto); }

.hora-chip.es-solicitada  { background: var(--aviso-fondo); border-color: transparent; }
.hora-chip.es-solicitada .hora-chip-hora,
.hora-chip.es-solicitada .hora-chip-detalle { color: var(--aviso-texto); }

.hora-chip.esta-elegida {
  box-shadow: 0 0 0 2px var(--azul-accion);
  border-color: transparent;
}

.mapa-leyenda {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  font-size: .7rem;
  color: var(--texto-tenue);
}

.mapa-leyenda .punto {
  display: inline-block;
  width: .6rem;
  height: .6rem;
  border-radius: 50%;
  margin-right: .25rem;
  vertical-align: baseline;
}

.punto-libre      { background: var(--exito-texto); }
.punto-ocupada    { background: var(--neutro-texto); }
.punto-solicitada { background: var(--aviso-texto); }

.mis-solicitudes > li {
  padding: .4rem 0;
  border-top: 1px solid var(--borde);
}

.mis-solicitudes > li:first-child { border-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .mapa-horas,
  .hora-chip { transition: none; }
}

/* Cómo se cobra el servicio elegido, en el formulario de contratos. No es un
   campo: es lo que el servicio impone, y se lee como un dato, no como algo que
   se pueda tocar. */
.modalidad-servicio {
  font-size: .8rem;
  font-weight: 600;
  color: var(--texto-tenue);
  padding-top: .25rem;
}

.modalidad-servicio.es-por-hora { color: var(--azul-accion); }

/* El hueco pulsable de cada celda de la semana: el cruce de un día con una
   hora. Ocupa lo que sobre —toda la celda si está vacía, la franja de abajo si
   ya tiene sesiones— y se mantiene invisible hasta que se pasa por encima o se
   llega con el tabulador, porque una rejilla con noventa y ocho signos de más
   pintados no se lee. */
.semana-hueco {
  flex: 1 1 auto;
  min-height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radio-sm);
  color: transparent;
  font-size: .7rem;
  text-decoration: none;
  transition: background-color .12s ease, color .12s ease;
}

.semana-celda:hover .semana-hueco {
  background: var(--azul-suave);
  color: var(--azul-accion);
}

.semana-hueco:focus-visible {
  background: var(--azul-suave);
  color: var(--azul-accion);
  outline: 2px solid var(--azul-accion);
  outline-offset: -2px;
}

/* En pantalla táctil no hay "pasar por encima": el hueco se insinúa siempre,
   apenas, para que se sepa que la celda se puede tocar. */
@media (hover: none) {
  .semana-hueco { color: var(--borde-fuerte); }
}

@media (prefers-reduced-motion: reduce) {
  .semana-hueco { transition: none; }
}

/* El selector de "qué agenda estoy mirando", en la barra de la agenda. La
   etiqueta va al lado y no encima para que la fila no crezca de alto y
   descoloque los botones que la acompañan. */
.selector-agenda {
  display: flex;
  align-items: center;
  gap: .4rem;
}

.selector-agenda .form-label {
  white-space: nowrap;
  color: var(--texto-tenue);
}

.selector-agenda .form-select { width: auto; min-width: 9.5rem; }

/* La columna de acciones de la lista de personal: reserva el ancho de los tres
   botones para que la fila de quien todavía no tiene cuenta —que lleva uno más—
   no crezca al doble de alto que el resto. */
.acciones-empleado { width: 8.5rem; }
