:root{
  /* Paleta de marca (logo nuevo): #F2F6F7 fondo, #0C2A50 azul principal,
     #617389 gris/azulado secundario. --azul-osc y los "-cl" (tints claros)
     estan derivados de esos tres para hover/headings y fondos de badges. */
  --azul: #0C2A50;
  --azul-osc: #091E3A;
  --azul-cl: #DDE1E6;
  --verde: #2E8B57;
  --verde-cl: #E4F4EC;
  --naranja: #C9772B;
  --naranja-cl: #FBEEE0;
  --gris: #617389;
  --gris-cl: #EFF1F3;
  --borde: #E2E5EA;
  --blanco: #FFFFFF;
  --sombra: 0 2px 10px rgba(12,42,80,0.08);
  /* Superficies: usadas por body, tarjetas/modales y texto principal, para
     que el modo oscuro (mas abajo) pueda pisarlas todas de una sola vez. */
  --fondo: #F2F6F7;
  --superficie: #FFFFFF;
  --superficie-input: #FBFCFE;
  --texto: #1B2430;
  --texto-label: #374151;
}
*{box-sizing:border-box;}
/* Los navegadores NO le pasan el font-family del body a button/input/select/
   textarea por defecto (usan la fuente nativa del sistema operativo, que no
   es la misma que el resto del texto) -- por eso, sin esta regla, cada boton
   nuevo se termina viendo con una tipografia distinta al resto de la app a
   menos que alguien se acuerde de agregarle "font-family:inherit" a mano.
   Con esto queda garantizado en un solo lugar: toda la app usa siempre la
   misma fuente (la del body de arriba), y lo unico que puede variar entre
   textos es el peso (bold), el tamano o el estilo (italica), nunca la
   familia tipografica en si. */
button, input, select, textarea, optgroup{ font-family:inherit; }
/* En mobile (sobre todo Android/WebKit), al tocar un boton el navegador
   pinta un flash de highlight rectangular por default, sin importar el
   border-radius del boton -- se nota feo en botones redondos como el "+"
   del FAB. Se desactiva ese highlight nativo en todos lados y se deja el
   feedback al toque en manos de :active (transform:scale, cambios de fondo,
   etc), que si respeta la forma real del elemento. */
button, a, .avatar-edit-wrap, .card-boton, .feed-item, .fam-post, .fam-card-clickeable{ -webkit-tap-highlight-color: transparent; }
/* min-height:100% en html + 100vh en body para que el color de fondo (clave
   en modo oscuro) cubra toda la pantalla aunque el contenido de la pestaña
   sea corto y no llegue a llenar el alto del viewport. overflow-y:scroll +
   scrollbar-gutter:stable reservan el ancho de la barra de scroll siempre
   (haya o no contenido suficiente para scrollear): sin esto, las pestañas
   sin scroll quedaban un poco mas anchas que las que si lo tenian, y como
   .wrap se centra con margin:0 auto, las cards se veian con mas aire de un
   lado que del otro (mas notorio en el panel de responsable). */
html{ background:var(--fondo); min-height:100%; overflow-y:scroll; scrollbar-gutter:stable; }
body{
  margin:0; min-height:100vh; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background:var(--fondo); color:var(--texto);
}

/* Accesibilidad: tamano de letra configurable (persiste por dispositivo).
   Usamos zoom en vez de reescribir cada font-size, para que escale todo el
   diseno (texto, iconos, espaciados) de forma proporcional y consistente. */
body.letra-grande{ zoom:1.15; }

/* Accesibilidad: modo oscuro (azul noche, no negro puro). La clase se pone
   en <html> (no en <body>): asi la variable --fondo tambien le llega al
   propio <html>, que es quien de verdad cubre todo el viewport cuando el
   contenido de una pestania es mas corto que la pantalla (si la clase
   estuviera solo en body, el html de atras quedaba blanco en esos casos,
   como pasaba en el panel de responsables). Como casi todo el CSS ya esta
   escrito en base a estas variables, con pisarlas en :root/html alcanza
   para que se propague a los 3 paneles, tarjetas, modales, inputs y la
   pildora de navegacion. */
html.modo-oscuro{
  --azul-osc: #8FC1EA;
  --azul-cl: #17324A;
  --verde-cl: #113328;
  --naranja-cl: #3A2A18;
  --gris: #93A1B5;
  --gris-cl: #17293C;
  --borde: #24384F;
  --fondo: #0B1A2B;
  --superficie: #122437;
  --superficie-input: #0F2033;
  --texto: #E7ECF2;
  --texto-label: #B7C2D0;
}
html.modo-oscuro .card,
html.modo-oscuro .modal,
html.modo-oscuro .acc-section,
html.modo-oscuro .fam-card,
html.modo-oscuro .fam-post,
html.modo-oscuro .mensajes-layout,
html.modo-oscuro .bottom-nav-inner,
html.modo-oscuro .login-demo-lista button,
html.modo-oscuro .perfil-datos-card,
html.modo-oscuro .btn-lapiz-perfil,
html.modo-oscuro .btn-like-wrap{
  background:var(--superficie);
}
html.modo-oscuro .perfil-datos-card .fila span:last-child{ color:var(--texto); }
/* La sombra difuminada de la pildora y del "+" esta pensada en tonos
   azulados de fondo claro (rgba(20,40,70,x)): contra el fondo oscuro
   (--fondo/--superficie, ya de por si azul muy oscuro) practicamente no se
   nota. En oscuro se usa una sombra neutra en negro, bien difuminada, para
   que la pildora y el "+" sigan leyendose "flotando" arriba del contenido. */
html.modo-oscuro .bottom-nav-inner{ box-shadow:0 12px 32px rgba(0,0,0,.5), 0 3px 12px rgba(0,0,0,.35); }
html.modo-oscuro .fab-btn{ box-shadow:0 5px 18px rgba(0,0,0,.55); }
/* Excepcion puntual: .bottom-nav button.active usa var(--azul) (que se
   mantiene igual en oscuro, para no perder la identidad de marca), asi que
   necesita un valor mas claro aparte para que el texto se siga leyendo. */
html.modo-oscuro .bottom-nav button.active{ color:#8FC1EA; }

body.login-bg{
  min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center;
  background: linear-gradient(160deg, #0C2A50 0%, #091E3A 60%, #050F1D 100%);
  padding:20px;
}
/* Animacion de apertura de la pantalla de ingreso: simple y corta, se
   dispara sola al cargar la pagina (no hace falta JS, el card no se oculta
   nunca despues). */
@keyframes entradaLogin{
  from{ opacity:0; transform:translateY(16px) scale(.98); }
  to{ opacity:1; transform:translateY(0) scale(1); }
}
.login-card{ background:#fff; border-radius:16px; padding:32px 28px; width:100%; max-width:380px; box-shadow:0 20px 50px rgba(0,0,0,.25); animation: entradaLogin .5s ease-out; }
.login-logo{ display:flex; align-items:center; gap:10px; margin-bottom:4px; }
.login-logo h1{ font-size:22px; margin:0; color:var(--azul-osc); }
.login-sub{ font-size:13px; color:var(--gris); margin:0 0 18px; }
.login-error{ color:#B3261E; font-size:12.5px; margin-top:8px; min-height:16px; }
.login-demo{ margin-top:20px; background:var(--azul-cl); border-radius:10px; padding:12px 14px; font-size:12px; color:#333; max-height:260px; overflow-y:auto; }
.login-demo p{ margin:0 0 8px; }
.login-demo ul{ margin:0; padding-left:0; }
.login-demo code{ background:#fff; padding:1px 5px; border-radius:4px; font-size:11.5px; }
.login-demo-lista{ list-style:none; display:flex; flex-direction:column; gap:5px; }
.login-demo-lista li{ margin:0; }
.login-demo-lista button{
  width:100%; text-align:left; background:#fff; border:1px solid var(--borde); border-radius:8px;
  padding:7px 10px; cursor:pointer; font-family:inherit; display:flex; flex-direction:column; gap:1px;
}
.login-demo-lista button:hover{ background:var(--gris-cl); border-color:var(--azul); }
.login-demo-lista button b{ font-size:12px; color:var(--azul-osc); }
.login-demo-lista button span{ font-size:11px; color:var(--gris); }

label{ display:block; font-size:12.5px; font-weight:600; color:var(--texto-label); margin:12px 0 4px; }
input[type=text], input[type=password], input[type=date], input[type=file], input[type=email], input[type=tel], input[type=number], textarea, select{
  width:100%; padding:10px 12px; border:1px solid var(--borde); border-radius:9px;
  /* 16px minimo a proposito: por debajo de eso, Safari/iOS hace zoom solo al
     tocar el campo (lo interpreta como que el sitio no esta pensado para
     mobile) y despues el layout queda con zoom hasta que se saca a mano. */
  font-size:16px;
  font-family:inherit; background:var(--superficie-input); color:var(--texto);
}
textarea{ resize:vertical; min-height:70px; }
/* Checkbox nativo, pero con el mismo modelo/color que el resto de la app
   (antes se dejaba el checkbox tal cual lo dibuja el navegador -- sin
   accent-color -- en varios checklists: usuarios y sus casillas de tildar
   para borrado masivo, cursos a cargo de un docente, alumnos de una tarea o
   publicacion, participantes de un grupo nuevo. Se notaba sobre todo en modo
   oscuro, pero el problema real era que nunca tomaba el celeste de la app,
   no el modo oscuro en si). accent-color tinie tanto el tilde como el
   cuadrado sin tildar, y lo respeta tambien el modo oscuro sin hacer falta
   una regla aparte. */
input[type="checkbox"]{ width:auto; flex-shrink:0; transform:scale(1.2); accent-color:var(--azul); cursor:pointer; }
/* Menu de acciones custom (Usuarios: "Eliminar", "Asignar X/s a...", "Quitar
   X a..."), en vez de un <select> nativo: el popup nativo de un select no se
   puede acotar en ancho ni hacer wrappear con CSS de forma confiable entre
   navegadores, asi que con opciones largas ("Asignar Guaraní/s a usuario/s
   seleccionado/s") se salia de la pantalla (peor con letra aumentada). Con
   una lista propia (mismo look que .fab-menu) el ancho queda acotado
   (max-width) y el texto wrappea normal como cualquier texto, asi nunca se
   sale de los limites sea cual sea el zoom. Ver alternarMenuAccionesUsuarios
   / ejecutarAccionBulkUsuarios en app.js. */
.menu-acciones{ position:relative; display:inline-block; }
.menu-acciones-boton{ display:inline-flex; align-items:center; gap:6px; }
.menu-acciones-boton svg{ flex-shrink:0; transition:transform .15s ease; }
.menu-acciones-lista{
  position:absolute; top:calc(100% + 6px); left:0; z-index:30;
  display:flex; flex-direction:column; gap:2px;
  background:var(--superficie); border:1px solid var(--borde); border-radius:12px; padding:6px;
  box-shadow:var(--sombra); width:max-content; max-width:min(300px, 90vw);
}
.menu-acciones-item{
  display:block; width:100%; text-align:left; background:none; border:none; padding:9px 12px;
  font-size:13px; font-weight:600; line-height:1.35; color:var(--texto-label);
  border-radius:8px; cursor:pointer; font-family:inherit; white-space:normal;
}
.menu-acciones-item:hover{ background:var(--gris-cl); }
.menu-acciones-item:active{ transform:scale(.98); }

/* Icono de lupa de fondo en los inputs de busqueda, para que se reconozcan
   como tales aun cuando el placeholder no entra completo (ej. con letra
   aumentada -- ver body.letra-grande mas arriba -- adentro de una fila
   angosta junto a un select de curso). Convencion ya existente en el HTML:
   todos comparten "uscar" en su id (buscarX, chatBuscarConversacion,
   grupoBuscarParticipante), asi no hace falta tocar cada uno a mano. */
input[id*="uscar"]{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23617389' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:11px center;
  background-size:15px 15px;
  padding-left:34px;
}
html.modo-oscuro input[id*="uscar"]{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2393A1B5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E");
}

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:6px; border:none; border-radius:9px; padding:10px 18px;
  font-size:13.5px; font-weight:600; cursor:pointer; transition:.15s;
}
.btn-primary{ background:var(--azul); color:#fff; }
.btn-primary:hover{ background:var(--azul-osc); }
.btn-outline{ background:var(--superficie); border:1px solid var(--borde); color:var(--texto-label); }
.btn-outline:hover{ background:var(--gris-cl); }
.btn-outline.active{ background:var(--azul-cl); border-color:var(--azul); color:var(--azul-osc); }
/* Variante roja para "Eliminar publicación" cuando lo ve preceptoria (ver
   feedItemPublicacion/detallePublicacionHtml en app.js): a diferencia de
   quien sube su propia publicacion, preceptoria puede borrar publicaciones
   ajenas, asi que el boton tiene que notarse bien para que quede claro que
   es una accion destructiva. */
.btn-outline-danger{ background:var(--superficie); border:1px solid #B3261E; color:#B3261E; }
.btn-outline-danger:hover{ background:#B3261E; color:#fff; }
.btn-sm{ padding:6px 12px; font-size:12.5px; }
.btn-block{ width:100%; margin-top:16px; }

.topbar{
  display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap;
  background: var(--azul); color:#fff; padding:14px 24px; position:relative; row-gap:6px;
}
/* En mobile, 24px de aire a los costados dejaba la foto de perfil (el
   circulo de .topbar-avatar-btn, adentro de .topbar-right) con un espacio
   grande hasta el borde de la pantalla. Se achica en mobile para que quede
   mas esquinada -- aplica a los 3 paneles porque .topbar es compartido. */
@media (max-width:640px){
  .topbar{ padding:12px 14px; }
}
.brand{ display:flex; align-items:center; gap:10px; font-weight:700; font-size:19px; letter-spacing:.2px;}
.brand small{ display:block; font-weight:400; font-size:11px; opacity:.8; letter-spacing:.3px; }
/* La pildora de abajo ya no lleva texto debajo de los iconos (ver
   comentario junto a .bottom-nav): el nombre de la pestania activa se
   muestra aca en su lugar, centrado y chico (mismo criterio en los 3
   paneles, ver actualizarTituloTopbarActivo en app.js). */
/* A pedido, mas grande: el tamano que antes solo se veia con letra
   aumentada (zoom:1.15 sobre la base de 12.5px). Como letra aumentada sigue
   aplicando encima de este tamano ya mas grande, "aumentada" termina un
   poco mas grande todavia que este "por defecto" nuevo -- mismo criterio
   que se uso para la pildora de preceptoria (ver mas abajo). */
.topbar-titulo{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  font-size:14.5px; font-weight:700; color:#fff; opacity:.92; text-align:center;
  max-width:38%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; pointer-events:none;
}
.topbar-right{ display:flex; align-items:center; gap:8px 14px; font-size:13px; flex-wrap:wrap; justify-content:flex-end; }
.topbar-right button{ background:rgba(255,255,255,.15); border:none; color:#fff; padding:7px 14px; border-radius:8px; cursor:pointer; font-size:12.5px; font-weight:600; }
.topbar-right button:hover{ background:rgba(255,255,255,.28); }
/* "Mi perfil" (docente y responsable) es un circulito con la foto de
   perfil (o las iniciales, si no eligieron ninguna) en vez de un boton de
   texto -- el contenido lo arma actualizarAvatarTopbar() en JS. */
.topbar-right button.topbar-avatar-btn{
  padding:0; width:34px; height:34px; border-radius:50%; overflow:hidden; flex-shrink:0;
  display:flex; align-items:center; justify-content:center; background:rgba(255,255,255,.18);
  border:2px solid rgba(255,255,255,.5);
  opacity:1; transition:opacity .18s ease;
}
.topbar-avatar-btn:hover{ border-color:#fff; }
/* OJO: de los 4 botones de avatar (uno por rol) solo UNO es relevante en
   toda la sesion -- los otros 3 quedan con .hide para siempre y nunca se
   les saca. Si esta regla les aplicara a los 4 (como pasaba antes), los 3
   irrelevantes seguirian ocupando su ancho en el flex de .topbar-right
   (display:flex, aunque invisibles) y correrian al que si importa lejos del
   borde -- por eso hace falta tambien .avatar-activo (lo agrega JS en el
   boton del rol actual, ver USUARIO.rol en el init) para el mismo mecanismo
   que .bottom-nav.hide/.fab.hide: se ocultan junto con la pildora al entrar
   a un chat/perfil/configuracion (ver ocultarNavAlEntrarAConfig en app.js)
   -- fade en vez de corte seco, pero solo para el boton que de verdad se
   usa. Los otros 3 caen en la regla generica ".hide{ display:none }" y no
   ocupan lugar. */
.topbar-right button.topbar-avatar-btn.avatar-activo.hide{ display:flex !important; opacity:0; pointer-events:none; }
.topbar-avatar-btn .avatar-circle{ width:100% !important; height:100% !important; border:none; box-shadow:none; font-size:14px; margin:0; }

/* "Cerrar sesion" ya no vive en el banner: ahora esta abajo de todo en
   Mi perfil (docente/responsable) y en Configuracion (direccion/preceptoria),
   como un link discreto en rojo (no un boton mas, para no competir en
   jerarquia visual con "Guardar cambios"). */
.btn-cerrar-sesion{
  background:none; border:none; color:#B3261E; font-size:13px; font-weight:600;
  cursor:pointer; padding:10px; font-family:inherit;
}
.btn-cerrar-sesion:hover{ text-decoration:underline; }

/* Saludo del responsable: antes vivia embebido en el banner azul superior
   (obligaba a una segunda fila en pantallas angostas, alargando el
   banner); ahora es parte del contenido de su panel, arriba del feed, para
   que el banner se mantenga siempre en una sola fila (solo logo + avatar). */
.familia-saludo{ text-align:center; margin-bottom:14px; }
.familia-saludo h3{ margin:0; font-size:17px; color:var(--azul-osc); }
.familia-saludo p{ margin:2px 0 0; font-size:12.5px; color:var(--gris); }

.wrap{ max-width:1180px; margin:0 auto; padding:24px; }
.hide{ display:none !important; }
.loading{ text-align:center; color:var(--gris); padding:60px 20px; font-size:14px; }

/* Animacion de apertura: simple y corta (no mas de medio segundo), una sola
   vez al abrir la app (ver reproducirEntradaSuave en app.js, que agrega y
   despues saca la clase .entrada-suave para que no se repita al cambiar de
   pestania). El topbar no se oculta nunca despues de cargar, asi que su
   animacion se puede dejar fija en el selector sin re-disparar sola. */
@keyframes entradaTopbar{
  from{ opacity:0; transform:translateY(-10px); }
  to{ opacity:1; transform:translateY(0); }
}
.topbar{ animation: entradaTopbar .4s ease-out; }

@keyframes entradaSuave{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:1; transform:translateY(0); }
}
.entrada-suave{ animation: entradaSuave .45s ease-out; }

.card{ background:#fff; border:1px solid var(--borde); border-radius:14px; padding:20px 22px; box-shadow:var(--sombra); margin-bottom:20px; }
.card h2{ margin:0 0 4px; font-size:17px; color:var(--azul-osc); }
/* Un <label> (margin-top:12px de por si, ver la regla general de "label" mas
   abajo) como PRIMER hijo de una card no colapsa ese margen contra el
   padding-top de la card (los margenes de un hijo nunca colapsan con el
   padding del padre) -- se suman, asi que el aire de arriba terminaba siendo
   padding + margin (32px) mientras que abajo quedaba solo el padding (20px),
   una asimetria bien notoria (ej. las cards de "Editar mis datos", "Cambiar
   contraseña" y "Accesibilidad" de Mi perfil). Sacando ese margen redundante
   en el primer label, arriba y abajo quedan parejos. */
.card > label:first-child{ margin-top:0; }
.card .sub{ margin:0 0 16px; font-size:13px; color:var(--gris); }
.row-actions{ margin-top:14px; display:flex; gap:10px; flex-wrap:wrap; }

label.switch-row{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  font-weight:400; font-size:13.5px; color:var(--texto); cursor:pointer; margin-top:6px;
}
label.switch-row input[type="checkbox"]{ transform:scale(1.25); }

/* Base de ".date" (usada suelta en varias cards para "Publico X", fechas,
   etc): sin esto heredaba el tamano por defecto del navegador, mas grande
   que el texto de la descripcion de al lado. .fam-card .date de mas abajo
   pisa esto con un tamano propio, todavia mas chico. */
.date{ font-size:12.8px; color:var(--gris); }
.feed-item{ border:1px solid var(--borde); border-radius:11px; padding:14px 16px; margin-bottom:12px; box-shadow:var(--sombra); }
.feed-item .meta{ display:flex; flex-wrap:wrap; justify-content:space-between; align-items:center; font-size:12px; color:var(--gris); margin-bottom:4px; gap:4px 8px; }
.meta-derecha{ display:flex; flex-wrap:wrap; align-items:center; gap:4px 6px; justify-content:flex-end; }
.feed-item h4{ margin:0 0 4px; font-size:14.5px; }
.feed-item p{ margin:0; font-size:13.5px; color:var(--texto); line-height:1.45; }
.progress-bar{ height:7px; background:var(--gris-cl); border-radius:99px; margin-top:10px; overflow:hidden; }
.progress-bar > div{ height:100%; background:var(--verde); }
.progress-label{ font-size:11.5px; color:var(--gris); margin-top:4px; }
.badge{ font-size:11px; font-weight:700; padding:2px 9px; border-radius:99px; }
.badge-aut{ background:var(--naranja-cl); color:var(--naranja); }
.badge-pub{ background:var(--verde-cl); color:var(--verde); }
.badge-ev{ background:var(--naranja-cl); color:var(--naranja); }
.badge-prov{ background:var(--gris-cl); color:var(--gris); }
.badge-curso{ background:var(--azul); color:#fff; font-size:10px; font-weight:700; padding:2px 8px; border-radius:99px; white-space:nowrap; }

.cal-day{ display:flex; gap:10px; padding:8px 0; border-bottom:1px solid var(--borde); }
.cal-date{ width:42px; text-align:center; }
.cal-date b{ display:block; font-size:16px; color:var(--azul-osc); }
.cal-date span{ font-size:10px; color:var(--gris); text-transform:uppercase; }
.cal-info h5{ margin:0 0 2px; font-size:12.8px; }
.cal-info p{ margin:0; font-size:11.5px; color:var(--gris); }
.empty{ text-align:center; color:var(--gris); font-size:12.5px; padding:30px 10px; }

/* Calendario convencional (mes completo), solo se usa en la card de escritorio del docente */
.cal-header-nav{ display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; }
.cal-header-nav h4{ margin:0; font-size:15px; color:var(--azul-osc); text-transform:capitalize; }
.cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:4px; }
.cal-dow{ text-align:center; font-size:10px; font-weight:700; color:var(--gris); text-transform:uppercase; padding-bottom:4px; }
.cal-cell{
  aspect-ratio:1/1; display:flex; align-items:center; justify-content:center; position:relative;
  border-radius:8px; font-size:12.5px; color:var(--texto);
}
.cal-cell.cal-otro-mes{ visibility:hidden; }
.cal-cell.cal-hoy{ background:var(--azul-cl); font-weight:700; color:var(--azul); }
html.modo-oscuro .cal-cell.cal-hoy{ color:var(--azul-osc); }
.cal-cell .cal-punto{ width:5px; height:5px; border-radius:50%; background:var(--naranja); position:absolute; bottom:5px; }
.cal-mes-eventos{ margin-top:12px; border-top:1px solid var(--borde); padding-top:8px; max-height:220px; overflow-y:auto; }
.cal-agregar-evento{ display:flex; gap:6px; margin-top:10px; padding-top:10px; border-top:1px solid var(--borde); flex-wrap:wrap; }
.cal-agregar-evento input{ flex:1; min-width:110px; margin:0; }
.cal-agregar-evento select{ flex:1 1 130px; min-width:110px; margin:0; }

/* Panel de responsable: mismo ancho y disposicion de siempre (tipo app,
   columna angosta centrada), pero sin ningun marco/tarjeta alrededor que lo
   haga ver como si estuviera superpuesto sobre la pagina -- el header, el
   cuerpo y la barra de abajo quedan directo contra el fondo, igual que en
   los demas paneles. */
/* width:100% (no vw): .screen vive adentro de #viewFamilia.wrap, que ya
   tiene su propio padding simetrico (ver .wrap). Antes usaba max-width:94vw,
   relativo al viewport en vez de a ese padding -- en pantallas angostas el
   94vw podia terminar siendo MAS ancho que el espacio real que le dejaba el
   padding del padre, y el navegador lo desbordaba para un lado (quedaba con
   mas aire de un lado que del otro). Con 100% del contenedor padre, el
   centrado es siempre simetrico sin importar el ancho de pantalla. */
.screen{
  width:100%; max-width:390px; margin:20px auto 40px;
}
.app-body{ padding:14px 14px 10px; background:var(--fondo); }
/* Nav flotante tipo "pildora": componente unico para los 3 paneles (no solo
   el de responsables). Separada del borde de la pantalla (flota, no queda
   pegada), fondo blanco, muy redondeada, con sombra, con los iconos arriba
   de la pildora, siempre en una sola fila (nunca se corta ni se scrollea
   adentro). Ya no lleva texto debajo de cada icono (.nav-label queda oculto
   siempre): el nombre de la pestania activa se muestra en el banner de
   arriba en su lugar (ver #topbarTituloActivo / actualizarTituloTopbarActivo
   en app.js).
   Por defecto es grande -- se estira bastante cerca de los bordes de la
   pantalla, para que se note bien y sea comoda de tocar -- pero si una
   escuela tiene mas botones de los que entran asi de grandes (ej. preceptoria,
   que suma "Usuarios"), JS (actualizarCompactoNav) le agrega la clase
   .nav-compacta, que la achica para que entre. Aparte, al scrollear (ver
   body.fab-compacto mas abajo) se achica todavia mas para dejarle lugar al
   "+" al lado. */
.bottom-nav{
  position:fixed; left:0; right:0; bottom:16px; z-index:20;
  display:flex; justify-content:center; pointer-events:none;
  opacity:1; transition:transform .22s ease, opacity .18s ease;
}
/* Mismo mecanismo que .modal-bg.hide (ver mas abajo): .bottom-nav.hide es mas
   especifico que el .hide generico (display:none + !important), asi que lo
   pisa solo aca -- en vez de desaparecer de golpe al entrar a un chat/perfil/
   configuracion (ver ocultarNavAlEntrarAConfig en app.js), se desvanece con
   un fade. Sigue sin poder tocarse mientras esta oculta (pointer-events:none,
   en el propio contendor Y en .bottom-nav-inner, que normalmente lo reactiva). */
.bottom-nav.hide{ display:flex !important; opacity:0; pointer-events:none; }
.bottom-nav.hide .bottom-nav-inner{ pointer-events:none; }
.bottom-nav-inner{
  pointer-events:auto; display:flex; align-items:center; justify-content:center; gap:4px; flex-wrap:nowrap;
  background:#fff; border:1px solid var(--borde); border-radius:999px; padding:6px;
  box-shadow:0 12px 30px rgba(20,40,70,.2), 0 3px 10px rgba(20,40,70,.1);
  max-width:94vw; transition:transform .22s ease, gap .22s ease;
  /* Salvavidas: JS (actualizarCompactoNav) es quien decide si la pildora
     grande entra o hay que achicarla (.nav-compacta), pero si por lo que sea
     ese calculo llegara a quedar un frame atrasado, que los botones que no
     entran queden recortados adentro del ovalo en vez de "romperlo" y
     desparramarse visualmente afuera de sus limites. */
  overflow:hidden;
}
.bottom-nav button{
  position:relative; flex-shrink:0; border:none; background:transparent; padding:0 20px;
  font-size:9.5px; font-weight:700; color:var(--gris); cursor:pointer; border-radius:999px;
  display:flex; align-items:center; justify-content:center; font-family:inherit;
  height:52px; /* generosa a proposito, con margen de sobra para que ni con
    letra aumentada (zoom, ver body.letra-grande) el icono quede recortado */
  transition:padding .22s ease, height .22s ease, background .15s ease;
}
.bottom-nav button:hover{ background:var(--gris-cl); }
.bottom-nav button.active{ color:var(--azul); background:var(--azul-cl); }
.bottom-nav button.active:hover{ background:var(--azul-cl); }
.bottom-nav svg{ width:19px; height:19px; flex-shrink:0; }
.bottom-nav .nav-badge{ top:2px; right:8px; }
.nav-label{ display:none; }
/* Modo compacto: la pildora grande de arriba no entraba (mas botones de los
   que caben, o pantalla angosta + letra aumentada). Achica el padding lateral
   y junta los botones entre si (gap:0). */
.bottom-nav-inner.nav-compacta{ gap:0; }
.bottom-nav-inner.nav-compacta button{ padding:0 8px; height:37px; }
/* actualizarCompactoNav (app.js) prueba si la pildora grande entra sacandole y
   poniendole .nav-compacta para medir su ancho "sin comprimir": sin esto, esa
   prueba queda animada (por las transiciones de arriba) y el ResizeObserver
   que vigila el tamano de la pildora se vuelve a disparar a mitad de esa
   animacion, deshace y repite la prueba de nuevo, y asi para siempre -- la
   pildora quedaba titilando/haciendo zoom en bucle, sobre todo en preceptoria
   (su pildora de 6 botones es la que mas rebota justo en el limite de ancho).
   Mientras dura la prueba (un instante, ver JS) se desactiva toda transicion
   para que sea instantanea y no genere ningun resize intermedio. */
.nav-midiendo, .nav-midiendo *{ transition:none !important; }
/* En PC la pildora se ve chica comparada con el resto de la pantalla: la
   agrandamos (mas padding e iconos mas grandes). */
@media (min-width:1000px){
  .bottom-nav{ bottom:24px; }
  .bottom-nav-inner{ padding:10px; gap:6px; }
  .bottom-nav button{ padding:0 26px; height:64px; /* icono 25 + margen de sobra */ }
  .bottom-nav-inner.nav-compacta{ gap:2px; }
  .bottom-nav-inner.nav-compacta button{ padding:0 11px; height:43px; }
  .bottom-nav svg{ width:25px; height:25px; }
}
/* Preceptoria tiene un boton mas que el resto (Usuarios): su pildora es la
   mas ancha de todas, y es la unica que nunca entra en fab-compacto (nunca
   comparte lugar con el "+", ver permiteCompacto en actualizarFabPorScroll),
   asi que puede quedarse siempre grande. En vez de dejar que caiga en
   .nav-compacta (que ademas de angostar tambien baja la altura y los iconos
   se ven chicos), se le achica el aire entre botones para que los 6 entren
   sin recortarse. Ademas, a pedido, queda mas grande que las demas pildoras:
   alto/icono propios (no los genericos de .bottom-nav de mas arriba), del
   tamano que antes solo se veia con letra aumentada (zoom:1.15 sobre la
   base). Como letra aumentada sigue aplicando ENCIMA de este tamano ya mas
   grande, "aumentada" termina un poco mas grande todavia que este "por
   defecto" nuevo, que es lo que se pidio. */
body.nav-preceptoria .bottom-nav-inner{ gap:0; }
body.nav-preceptoria .bottom-nav button{ padding:0 13px; height:60px; }
body.nav-preceptoria .bottom-nav svg{ width:22px; height:22px; }
/* Salvavidas extremo (ej. letra aumentada en un telefono muy angosto): si ni
   asi entra y JS igual tiene que recurrir a .nav-compacta, que se achique
   normal (sin esto, la regla de arriba -- mas especifica -- le ganaria a
   .nav-compacta y le impediria angostarse mas). Altura e icono si se dejan
   caer a los genericos de .nav-compacta (37px/19px): es el ultimo recurso
   para que entre, no tiene que seguir viendose "grande". */
body.nav-preceptoria .bottom-nav-inner.nav-compacta button{ padding:0 8px; height:37px; }
body.nav-preceptoria .bottom-nav-inner.nav-compacta svg{ width:19px; height:19px; }
@media (min-width:1000px){
  body.nav-preceptoria .bottom-nav-inner{ gap:2px; }
  body.nav-preceptoria .bottom-nav button{ padding:0 18px; height:74px; }
  body.nav-preceptoria .bottom-nav svg{ width:29px; height:29px; }
  body.nav-preceptoria .bottom-nav-inner.nav-compacta button{ padding:0 11px; height:43px; }
  body.nav-preceptoria .bottom-nav-inner.nav-compacta svg{ width:25px; height:25px; }
}

/* Panel de responsable estilo Instagram: el banner de arriba queda fijo en
   su lugar (la pildora de abajo ya es fixed por defecto, ver .bottom-nav), y
   el contenido de en medio scrollea con el scroll normal de la pagina (asi
   la barra de scroll del navegador queda pegada al borde real de la
   pantalla, no flotando en el medio). El padding real que compensa la altura
   del banner y de la pildora se calcula por JS (ajustarLayoutFamilia), estos
   valores son solo un punto de partida hasta que corre el JS. Se activa con
   una clase en <body> (solo para el rol familia) para no afectar en nada a
   los paneles de docente/admin. */
body.modo-familia .topbar{ position:fixed; top:0; left:0; right:0; z-index:20; }
body.modo-familia #viewFamilia, body.modo-familia #viewPerfilFamilia{ padding-top:106px; padding-bottom:90px; }
/* #viewMensajes no necesita una regla propia aca: mientras esta abierta
   siempre tiene la clase "mensajes-pantalla" en el body (ver mas abajo),
   que fija su padding-top exacto por JS (ajustarLayoutMensajes), para los
   3 paneles por igual. */
@media (min-width:640px){
  body.modo-familia #viewFamilia, body.modo-familia #viewPerfilFamilia{ padding-top:64px; }
}

.fam-card{ background:#fff; border:1px solid var(--borde); border-radius:13px; padding:13px 14px; margin-bottom:11px; box-shadow:var(--sombra); }
.fam-card .top{ display:flex; justify-content:space-between; align-items:center; margin-bottom:6px; }
.fam-card h4{ margin:0; font-size:13.5px; }
.fam-card p{ margin:0 0 8px; font-size:12.8px; color:var(--texto); line-height:1.4; }
.fam-card .date{ font-size:11px; color:var(--gris); }
.chip{ font-size:10.5px; font-weight:700; padding:2px 8px; border-radius:99px; }
.chip-leido{ background:var(--verde-cl); color:var(--verde); }
.chip-nuevo{ background:var(--azul-cl); color:var(--azul); }
html.modo-oscuro .chip-nuevo{ color:var(--azul-osc); }
.chip-firma{ background:var(--naranja-cl); color:var(--naranja); }
.fam-btn{ width:100%; border:none; border-radius:9px; padding:9px; font-size:12.5px; font-weight:700; cursor:pointer; margin-top:4px; }
.fam-btn.primary{ background:var(--azul); color:#fff; }
.fam-btn.done{ background:var(--verde-cl); color:var(--verde); }
.fam-btn.outline{ background:var(--superficie); border:1px solid var(--borde); color:var(--azul-osc); }
.fam-btn:disabled{ opacity:.6; cursor:default; }

/* Aparicion/desaparicion con una transicion breve (fade del fondo + un "pop"
   sutil de la tarjeta) en vez del corte seco de siempre. No hace falta tocar
   ninguna de las mas de 20 funciones que abren/cierran cada modal puntual:
   .modal-bg.hide es mas especifico que el .hide generico (usado en cientos
   de otros lugares sin animacion, y con !important), asi que esta regla lo
   pisa solo para los popups -- se cambia el mecanismo de ocultamiento de
   display:none a opacity+pointer-events (sigue estando "invisible" e
   inaccesible al click, pero ahora se puede animar). */
.modal-bg{
  position:fixed; inset:0; background:rgba(10,20,40,.45); display:flex; align-items:center; justify-content:center; z-index:50;
  opacity:1; transition:opacity .18s ease;
}
.modal-bg.hide{ display:flex !important; opacity:0; pointer-events:none; }
.modal{
  background:#fff; border-radius:16px; padding:22px; width:320px; max-width:90vw; box-shadow:0 12px 32px rgba(12,32,60,.22); position:relative;
  transform:scale(1) translateY(0); transition:transform .2s cubic-bezier(.32,1.3,.64,1);
}
.modal-bg.hide .modal{ transform:scale(.93) translateY(10px); }
.modal h3{ margin:0 0 4px; font-size:16px; padding-right:26px; }
.modal p{ margin:0 0 12px; font-size:12.8px; color:var(--gris); }
/* Cruz para cerrar arriba a la derecha: reemplaza al boton "Cerrar"/"Cancelar"
   que antes quedaba abajo a la izquierda, junto (o en vez) de la accion
   principal (ver .modal-actions). */
.modal-x{
  position:absolute; top:14px; right:14px; width:26px; height:26px; border-radius:50%; flex-shrink:0;
  border:none; background:var(--gris-cl); color:var(--texto-label); cursor:pointer;
  display:flex; align-items:center; justify-content:center; padding:0;
}
.modal-x:hover{ background:var(--borde); }
.modal-x svg{ width:13px; height:13px; }
html.modo-oscuro .modal-x{ background:rgba(255,255,255,.1); color:var(--texto); }
html.modo-oscuro .modal-x:hover{ background:rgba(255,255,255,.18); }
/* Recorte cuadrado (con zoom) de la foto de perfil: visor de tamaño fijo
   (debe matchear RECORTE_FOTO_VIEWPORT en app.js) con overflow oculto; la
   imagen adentro se posiciona/escala por JS via transform + width/height.
   La guia visual es un circulo inscripto en el cuadrado (el avatar se
   muestra circular en toda la app): recortar-foto-mascara oscurece todo lo
   que queda afuera (truco del box-shadow con spread enorme, recortado por
   overflow:hidden del visor) y recortar-foto-grid dibuja una cuadricula de
   referencia adentro. Ambos son solo visuales (pointer-events:none), los
   gestos de arrastre/zoom se manejan en el visor mismo. */
.recortar-foto-viewport{
  position:relative; width:260px; height:260px; margin:14px auto 16px;
  overflow:hidden; border-radius:12px; border:1px solid var(--borde); background:#111;
  touch-action:none; cursor:grab; user-select:none;
}
.recortar-foto-viewport:active{ cursor:grabbing; }
.recortar-foto-viewport img{
  position:absolute; top:0; left:0; max-width:none; pointer-events:none; user-select:none;
}
.recortar-foto-mascara{
  position:absolute; inset:0; border-radius:50%; pointer-events:none;
  box-shadow:0 0 0 9999px rgba(8,16,32,.62); border:2px solid rgba(255,255,255,.9);
}
.recortar-foto-grid{
  position:absolute; inset:0; border-radius:50%; pointer-events:none; overflow:hidden;
}
.recortar-foto-grid span{ position:absolute; background:rgba(255,255,255,.55); }
.recortar-foto-grid span:nth-child(1){ left:33.333%; top:0; width:1px; height:100%; }
.recortar-foto-grid span:nth-child(2){ left:66.666%; top:0; width:1px; height:100%; }
.recortar-foto-grid span:nth-child(3){ top:33.333%; left:0; height:1px; width:100%; }
.recortar-foto-grid span:nth-child(4){ top:66.666%; left:0; height:1px; width:100%; }
/* "Nuevo chat/grupo": cabecera apilada (grid con ambos hijos en la misma
   celda 1/1) para que el subtitulo y el campo Asunto ocupen siempre el mismo
   lugar. La altura reservada queda fija (la del mas alto de los dos, ya que
   el grid mide a ambos para el sizing aunque uno este con opacity:0 -- a
   diferencia de display:none, que si sacaria del calculo), asi mostrar u
   ocultar el Asunto nunca empuja la lista de Participantes de mas abajo. El
   cambio entre uno y otro se anima como un despliegue desde el centro
   (transform-origin:center, escala + fade). Ver actualizarVisibilidadAsuntoGrupo
   en app.js, que ahora solo togglea la clase .mostrando-asunto aca. */
.nuevo-grupo-cabecera{ position:relative; display:grid; }
.nuevo-grupo-cabecera > *{ grid-area:1 / 1; }
.nuevo-grupo-cabecera .sub,
.nuevo-grupo-cabecera .asunto-grupo{
  transform-origin:center; transition:opacity .22s ease, transform .22s ease;
}
.nuevo-grupo-cabecera .asunto-grupo{
  display:flex; flex-direction:column; justify-content:center;
  opacity:0; transform:scale(.82); pointer-events:none;
}
.nuevo-grupo-cabecera .asunto-grupo label{ margin:0 0 4px; }
.nuevo-grupo-cabecera .asunto-grupo input{ margin:0; }
.nuevo-grupo-cabecera.mostrando-asunto .sub{
  opacity:0; transform:scale(.9); pointer-events:none;
}
.nuevo-grupo-cabecera.mostrando-asunto .asunto-grupo{
  opacity:1; transform:scale(1); pointer-events:auto;
}
canvas{ border:1.5px dashed #C7CDD6; border-radius:10px; background:#FBFCFE; touch-action:none; width:100%; }
.modal-actions{ display:flex; gap:8px; margin-top:12px; flex-wrap:wrap; }
.toast{
  /* bottom:100px, no 24px: mismo offset que .undo-snackbar (ver mas abajo)
     para quedar siempre por encima de la pildora de navegacion flotante y
     el "+" -- antes se superponia con la pildora y quedaba medio molesto. */
  position:fixed; bottom:100px; left:50%; transform:translateX(-50%); background:#1B2430; color:#fff;
  padding:10px 18px; border-radius:9px; font-size:13px; opacity:0; transition:.25s; pointer-events:none; z-index:60;
}
.toast.show{ opacity:1; }

/* Snackbar de "deshacer" (avisos del panel de responsable, ver swipe-item
   mas abajo): queda por encima de la pildora flotante (bottom:100px, mismo
   offset que usa el "+" en .fab) para no taparla ni que lo tape. */
.undo-snackbar{
  position:fixed; left:50%; bottom:100px; transform:translateX(-50%);
  display:flex; align-items:center; gap:14px; background:#1B2430; color:#fff;
  padding:12px 16px; border-radius:11px; font-size:13px; box-shadow:0 6px 18px rgba(20,40,70,.28);
  z-index:55; max-width:90vw;
}
.undo-snackbar button{
  background:none; border:none; color:var(--azul-cl,#8ab4f8); font-weight:700; font-size:13px;
  cursor:pointer; font-family:inherit; flex-shrink:0; padding:2px;
}
.undo-snackbar button:hover{ text-decoration:underline; }

/* Deslizar hacia la izquierda para eliminar un aviso (solo pestania Avisos
   del panel de responsable). .swipe-item recorta el fondo rojo que asoma
   detras a medida que se arrastra .swipe-contenido; con cierta resistencia
   (ver SWIPE_UMBRAL en JS) para que no se borre con un toque minimo. */
.swipe-item{ position:relative; overflow:hidden; border-radius:13px; margin-bottom:11px; }
.swipe-item .fam-card{ margin-bottom:0; border-radius:13px; }
.swipe-fondo-borrar{
  position:absolute; inset:0; background:#B3261E; color:#fff;
  display:flex; align-items:center; justify-content:flex-end; padding-right:22px;
  font-weight:700; font-size:13px; border-radius:13px;
}
.swipe-contenido{
  position:relative; background:var(--fondo, #F4F6F9); touch-action:pan-y;
}
.swipe-contenido.swipe-arrastrando{ transition:none; }
.swipe-contenido.swipe-volviendo{ transition:transform .2s ease; }
.swipe-contenido.swipe-saliendo{ transition:transform .2s ease, opacity .2s ease; }

.planilla-asistencia-row{}
.planilla-asistencia-row label{ font-weight:400; }
.planilla-asistencia-row .row-actions{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.planilla-asistencia-row select{ font-weight:400; width:auto; flex:1; min-width:140px; }

/* flex-wrap + min-width:0 son necesarios para que un nombre+email largo (o
   la letra agrandada de accesibilidad, que achica el ancho disponible en la
   practica) empuje los botones de Editar/Eliminar a una linea nueva en vez
   de superponerlos o cortarlos. */
.familia-row{ display:flex; align-items:center; justify-content:space-between; gap:8px 10px; padding:9px 0; border-bottom:1px solid var(--borde); font-size:13px; flex-wrap:wrap; }
.familia-row:last-child{ border-bottom:none; }
.familia-row .quien{ display:flex; align-items:center; gap:8px; min-width:0; flex:1 1 180px; }
.familia-row .quien span{ overflow-wrap:anywhere; }
.familia-row select{ width:auto; padding:5px 8px; font-size:12.5px; }

.casa-dot{ width:11px; height:11px; border-radius:50%; display:inline-block; flex-shrink:0; }
.casa-badge{ display:inline-flex; align-items:center; gap:6px; font-size:12.5px; font-weight:700; padding:4px 11px; border-radius:99px; color:#fff; }

/* Publicaciones (feed estilo red social): una foto sola se ve grande, varias
   fotos arman una grilla tipo carrusel, y el enlace se muestra como chip. */
.pub-foto-unica{ width:100%; display:block; max-height:280px; object-fit:cover; border-radius:10px; background:var(--gris-cl); margin:6px 0; }
.pub-fotos-grid{ display:grid; gap:6px; margin:6px 0; }
.pub-fotos-grid-2{ grid-template-columns:repeat(2, 1fr); }
.pub-fotos-grid-3{ grid-template-columns:repeat(3, 1fr); }
.pub-fotos-grid-4{ grid-template-columns:repeat(2, 1fr); }
.pub-fotos-grid img{ width:100%; height:100%; aspect-ratio:1/1; object-fit:cover; border-radius:8px; background:var(--gris-cl); display:block; }
.pub-foto-unica, .pub-fotos-grid img{ cursor:pointer; }

/* Lightbox de fotos: fondo oscurecido y difuminado, foto centrada, flechas a
   los costados, cruz arriba a la derecha y una barra abajo con la cantidad
   de fotos y el boton de descarga. */
#lightboxFotos{
  position:fixed; inset:0; z-index:80; display:flex; align-items:center; justify-content:center;
  background:rgba(8,14,26,.86); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  opacity:1; transition:opacity .18s ease;
}
#lightboxFotos.hide{ display:flex !important; opacity:0; pointer-events:none; }
#lightboxFotos img{
  max-width:90vw; max-height:80vh; object-fit:contain; border-radius:6px;
  transform:scale(1); transition:transform .2s cubic-bezier(.32,1.3,.64,1);
}
#lightboxFotos.hide img{ transform:scale(.94); }
.lightbox-cerrar{
  position:absolute; top:16px; right:18px; background:rgba(255,255,255,.12); border:none; color:#fff;
  font-size:26px; line-height:1; width:40px; height:40px; border-radius:50%; cursor:pointer;
}
.lightbox-cerrar:hover{ background:rgba(255,255,255,.22); }
.lightbox-flecha{
  position:absolute; top:50%; transform:translateY(-50%); background:rgba(255,255,255,.12); border:none; color:#fff;
  font-size:18px; width:44px; height:44px; border-radius:50%; cursor:pointer;
}
.lightbox-flecha:hover{ background:rgba(255,255,255,.22); }
.lightbox-flecha-izq{ left:14px; }
.lightbox-flecha-der{ right:14px; }
.lightbox-barra{
  position:absolute; bottom:18px; left:0; right:0; display:flex; align-items:center; justify-content:center; gap:14px;
  color:#fff; font-size:12.8px;
}
/* El fondo de este boton queda blanco siempre (a proposito, para que se
   destaque igual sobre cualquier foto), tanto en modo claro como oscuro --
   pero el texto/icono venia de .btn-outline (color:var(--texto-label)), que
   en modo oscuro pasa a ser un gris claro: texto claro sobre fondo blanco,
   practicamente ilegible. Color fijo y oscuro aca, independiente del tema. */
.lightbox-barra .btn{ background:rgba(255,255,255,.9); color:#1B2430; }
@media (max-width:640px){
  .lightbox-flecha{ width:38px; height:38px; font-size:16px; }
  .lightbox-cerrar{ width:36px; height:36px; font-size:22px; top:10px; right:10px; }
}
.pub-enlace{
  display:inline-flex; align-items:center; gap:6px; margin-top:6px; padding:7px 12px;
  background:var(--azul-cl); color:var(--azul); border-radius:8px; font-size:12.5px; font-weight:700; text-decoration:none;
}
.pub-enlace:hover{ background:var(--azul); color:#fff; }
html.modo-oscuro .pub-enlace{ color:var(--azul-osc); }

/* "Ver mas" (texto largo de una publicacion, ver TEXTO_PUB_LIMITE en app.js)
   y el corazon de "me gusta". */
.ver-mas-link{ color:var(--azul); font-weight:700; text-decoration:none; white-space:nowrap; }
.ver-mas-link:hover{ text-decoration:underline; }
.autor-pub-link{ color:inherit; text-decoration:none; font-weight:700; }
.autor-pub-link:hover{ text-decoration:underline; }
/* El corazon y el numero de likes van pegados pero son dos botones aparte:
   tocar el corazon da/saca el like, tocar el numero abre "Le gusta a..."
   (ver botonLikeHtml/abrirLikesPublicacion en app.js). */
.btn-like-wrap{ display:inline-flex; align-items:stretch; border:1px solid var(--borde); border-radius:999px; overflow:hidden; background:#fff; }
.btn-like{
  display:inline-flex; align-items:center; gap:5px; border:none; background:transparent;
  color:var(--gris); padding:6px 10px; font-size:12.5px; font-weight:700; cursor:pointer; font-family:inherit;
  transition: color .25s ease;
}
.btn-like:hover{ background:var(--gris-cl); }
.btn-like.activo{ color:#B3261E; }
/* El corazon del SVG siempre tiene fill (ver botonLikeHtml en app.js), pero
   arranca transparente y se "rellena" de a poco con el mismo color que el
   contorno (currentColor, que ya pasa de gris a rojo via transition arriba)
   cuando se activa el like. */
.btn-like svg path{ fill-opacity:0; transition: fill-opacity .3s ease; }
.btn-like.activo svg path{ fill-opacity:1; }
/* "Pop" al tocar el corazon: mismo truco que el "+" (ver @keyframes fabPop),
   se achica de golpe y rebota mas alla de su tamano normal antes de
   asentarse (ver animarLikePop en app.js, que agrega y saca esta clase). */
@keyframes likePop{
  0%{ transform:scale(1); }
  35%{ transform:scale(.8); }
  70%{ transform:scale(1.22); }
  100%{ transform:scale(1); }
}
.btn-like.like-pop{ animation:likePop .38s cubic-bezier(.34,1.2,.64,1); }
.btn-like-contador{
  border:none; border-left:1px solid var(--borde); background:transparent; color:var(--gris);
  padding:6px 12px 6px 8px; font-size:12.5px; font-weight:700; cursor:pointer; font-family:inherit;
}
.btn-like-contador:hover{ background:var(--gris-cl); }
.btn-like-contador-vacio{ cursor:default; }
.btn-like-contador-vacio:hover{ background:transparent; }
/* Fotitos apiladas de los ultimos 3 en dar like, al lado del contador
   (ver avataresLikeHtml en app.js). Se superponen con margen negativo, cada
   una con un borde blanco para que se distingan entre si. Un poco mas
   grandes en mobile, y bastante mas grandes en desktop. */
.avatares-likes{ display:inline-flex; align-items:center; margin-left:7px; cursor:pointer; }
/* avatarHtml() pone width/height como estilo inline (segun el "tamano" que
   se le pasa) -- un estilo inline le gana en prioridad a cualquier regla de
   hoja de estilos, asi que hace falta !important aca para poder agrandar el
   avatar mas alla del tamano con el que se genero. */
.avatares-likes .avatar-circle{
  width:24px !important; height:24px !important; margin-bottom:0; margin-left:-9px; border:2px solid #fff; box-shadow:none; font-size:10px;
}
.avatares-likes .avatar-circle:first-child{ margin-left:0; }
@media (min-width:1000px){
  .avatares-likes{ margin-left:9px; }
  .avatares-likes .avatar-circle{ width:32px !important; height:32px !important; margin-left:-12px; border:2.5px solid #fff; font-size:13px; }
}
/* Foto de perfil de quien publico, entre "Publico" y su nombre. */
.autor-pub-avatar{ display:inline-flex; vertical-align:middle; margin:0 6px; position:relative; top:-1px; cursor:pointer; text-decoration:none; }
/* Un poco mas grande que las fotitos de like (.avatares-likes): es la foto
   de quien publico, tiene que notarse mas que la de los que dieron like.
   Mismo motivo para el !important que en .avatares-likes: avatarHtml() pone
   el tamano como estilo inline, que le gana a una regla de CSS comun. */
.autor-pub-avatar .avatar-circle{ width:24px !important; height:24px !important; margin-bottom:0; border:none; box-shadow:none; font-size:10px; }
@media (min-width:1000px){
  .autor-pub-avatar .avatar-circle{ width:34px !important; height:34px !important; font-size:13px; }
}
.fila-like{ display:flex; align-items:center; gap:10px; padding:8px 0; border-bottom:1px solid var(--borde); font-size:13px; }
.fila-like:last-child{ border-bottom:none; }

/* Vista de detalle de una publicacion (modal): autor con avatar, nombre y rol. */
.detalle-pub-autor{ display:flex; align-items:center; gap:10px; }
.detalle-pub-autor-nombre{ font-weight:700; font-size:12.8px; }
.detalle-pub-autor-rol{ font-size:11.5px; color:var(--gris); }

.fam-post{ background:#fff; border:1px solid var(--borde); border-radius:13px; padding:13px 14px; margin-bottom:11px; box-shadow:var(--sombra); }
.fam-post .meta{ display:flex; justify-content:space-between; align-items:center; font-size:11px; color:var(--gris); margin-bottom:6px; }
.fam-post p{ margin:0 0 4px; font-size:12.8px; color:var(--texto); line-height:1.4; }

/* Notificaciones: mismo look que .fam-card, con un acento a la izquierda
   mientras esta sin leer. */
.fam-card-no-leida{ border-left:3px solid var(--azul); }
.fam-card-clickeable{ cursor:pointer; }
.fam-card-clickeable:active{ background:var(--fondo-hover, #f3f5f8); }

/* Badge chiquito de "no leidos", tanto en los botones del bottom-nav del
   responsable como al lado del nombre en la lista de conversaciones. */
.nav-badge{
  position:absolute; top:2px; right:14px; min-width:15px; height:15px; padding:0 3px; border-radius:99px;
  background:#D64545; color:#fff; font-size:9.5px; font-weight:700; line-height:15px; text-align:center;
}
.chat-badge-inline{
  display:inline-block; min-width:16px; height:16px; padding:0 4px; border-radius:99px;
  background:#D64545; color:#fff; font-size:10px; font-weight:700; line-height:16px; text-align:center;
}
.chat-row{ cursor:pointer; align-items:flex-start; padding-left:16px; padding-right:16px; }
/* Avatar (o icono de grupo) al lado del nombre en la lista de conversaciones:
   el mismo .avatar-circle que se usa en los headers de perfil, pero sin el
   borde/sombra/margen pensados para un avatar grande y centrado. */
.chat-row .avatar-circle{ flex-shrink:0; margin-bottom:0; border:none; box-shadow:none; font-size:13px; }
.chat-row:hover{ background:var(--gris-cl); }
.chat-row-activa{ background:var(--azul-cl); }
.chat-row-rol{
  display:inline-block; margin-left:6px; padding:1px 7px; border-radius:99px; background:var(--azul-cl);
  color:var(--azul-osc); font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.3px; vertical-align:middle;
}
/* Apellidos de los integrantes de un grupo, al lado del asunto (ver
   integrantesGrupoTxt en app.js, que ya limita el largo con un "+N"). En la
   version desktop la columna de la lista es angosta y fija (320px, ver
   .mensajes-lista-wrap), asi que titulo + apellidos + chip "Grupo" no
   siempre entran en una sola linea: se trunca con "..." la parte de los
   apellidos (lo unico de largo variable) en vez de mandar el chip a una
   linea aparte, para que quede siempre a la derecha como en el resto de las
   filas. Con letra aumentada (bastante menos espacio disponible en la
   practica) se permite volver a wrapear en vez de truncar, para no perder
   informacion. */
.chat-row .quien-con-meta .quien-linea{ flex-wrap:nowrap; }
/* El nombre es el unico elemento de largo variable sin tope (los demas --rol,
   contador de no leidos-- son cortos y de largo fijo): si el nombre no cede
   lugar, un nombre largo ("Familia Fernandez (Emma Fernandez)") desborda su
   propia caja sin que nada lo detenga -- como el desborde no se recorta ni
   empuja a los vecinos (son flex siblings, no bloques normales), el texto
   sobrante queda flotando visualmente ENCIMA de la hora (chat-row-fecha, a la
   derecha de toda la fila) y el chip de rol termina recortado contra el borde
   de la card. Dandole flex-shrink/min-width/ellipsis al nombre, es EL que se
   achica y trunca primero, dejando siempre visible el chip de rol completo y
   sin invadir el espacio de la hora. */
.chat-row-nombre{
  /* flex-grow en 0 a proposito (antes era 1): el nombre no debe estirarse a
     ocupar el espacio libre de la fila, sino quedar pegado a su propio ancho
     de contenido para que lo que le sigue (apellidos del grupo, o curso +
     alumno/a de una conversacion 1 a 1 -- ver chat-row-integrantes) vaya
     inmediatamente despues y no termine flotando centrado en el medio de la
     fila. flex-shrink sigue en 1: si hace falta, el nombre igual se achica y
     trunca con "...", que es lo que este comentario original buscaba evitar. */
  flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.chat-row .chat-row-rol, .chat-row .chat-badge-inline{ flex-shrink:0; }
.chat-row-integrantes{
  margin-left:6px; font-size:11.5px; font-weight:400; color:var(--gris);
  /* Mismo motivo que chat-row-nombre de arriba: sin flex-grow, para que
     quede pegada seguido del nombre/asunto en vez de centrada en la fila. */
  flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
body.letra-grande .chat-row .quien-con-meta .quien-linea{ flex-wrap:wrap; }
body.letra-grande .chat-row-nombre{ flex:0 1 auto; overflow:visible; text-overflow:clip; white-space:normal; }
body.letra-grande .chat-row-integrantes{ flex:0 1 auto; overflow:visible; text-overflow:clip; white-space:normal; }
.chat-row-fecha{ flex-shrink:0; font-size:11px; color:var(--gris); white-space:nowrap; padding-top:2px; }

/* Hilo de chat: burbujas alineadas a la derecha para lo mio, a la izquierda
   para lo del otro lado (como cualquier chat). */
.chat-hilo{ max-height:50vh; overflow-y:auto; padding:4px 2px; display:flex; flex-direction:column; gap:8px; }
.chat-msg{ display:flex; flex-direction:column; max-width:78%; }
.chat-msg.chat-mio{ align-self:flex-end; align-items:flex-end; }
.chat-msg.chat-otro{ align-self:flex-start; align-items:flex-start; }
.chat-burbuja{ padding:8px 12px; border-radius:14px; font-size:13px; line-height:1.4; word-break:break-word; }
.chat-mio .chat-burbuja{ background:var(--azul); color:#fff; border-bottom-right-radius:4px; }
.chat-otro .chat-burbuja{ background:var(--gris-cl); color:var(--texto); border-bottom-left-radius:4px; }
.chat-hora{ font-size:10px; color:var(--gris); margin-top:2px; }
/* Separador de dia entre mensajes (ver chatThreadHtml/etiquetaFechaChat en
   app.js): una pildora centrada, sin alinearse a izquierda/derecha como los
   .chat-msg -- por eso es una clase aparte, no un .chat-msg mas. */
.chat-separador-fecha{ display:flex; justify-content:center; margin:4px 0; }
.chat-separador-fecha span{
  background:var(--gris-cl); color:var(--gris); font-size:11px; font-weight:700;
  padding:4px 12px; border-radius:999px;
}
/* Fija abajo de .mensajes-hilo (fuera del area que scrollea), asi siempre
   esta a la vista sin tener que bajar el scroll del hilo de mensajes. */
.chat-input-row{ display:flex; gap:8px; padding:12px 16px; border-top:1px solid var(--borde); flex-shrink:0; }
.chat-input-row input{ flex:1; margin:0; }

/* Pantalla dedicada de Mensajes (compartida por los 3 paneles): lista de
   conversaciones a la izquierda, hilo activo a la derecha, con marcos
   redondeados como el resto de la app (tambien en mobile, no queda pegada a
   los bordes). La pildora de navegacion se mantiene fija abajo (no hay
   boton "Volver": los iconos de la pildora llevan a cada seccion). La misma
   barra de titulo (.mensajes-header) se reutiliza en la pantalla de
   Configuracion de direccion. */
.mensajes-header{ display:flex; align-items:center; gap:8px 12px; margin-bottom:14px; flex-wrap:wrap; }
.mensajes-header h2{ margin:0; font-size:18px; color:var(--azul-osc); }
/* Variante para headers con "Volver" + titulo centrado en el medio del
   banner (ej "Tus publicaciones guardadas"): antes el titulo se centraba con
   position:absolute + left:50% ignorando por completo el ancho del boton
   "Volver", asi que en pantallas angostas el titulo terminaba superpuesto
   con el boton. Con grid de 3 columnas (1fr / auto / 1fr) el titulo queda
   centrado en el ancho TOTAL del banner (columnas 1 y 3 son iguales, aunque
   la 3ra quede vacia) sin invadir nunca la columna del boton; si aun asi no
   entrara en una pantalla muy angosta, corta con puntos suspensivos en vez
   de superponerse. */
.mensajes-header-centrado{ display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px 12px; }
.mensajes-header-centrado > *:first-child{ grid-column:1; justify-self:start; }
.mensajes-header-centrado > h2{ grid-column:2; justify-self:center; font-size:16px; line-height:1.25; text-align:center; max-width:100%; }
/* Headers de "Mi perfil" (docente/direccion/proveedor/familia): 4 botones en
   el DOM (Volver, Volver sin guardar, h2, Guardar cambios) pero solo 2
   visibles a la vez segun el modo -- los otros dos tienen .hide (display:none,
   no participan del grid). :first-child/:last-child se fijan por posicion en
   el DOM, no por visibilidad, asi que siempre apuntan al boton correcto sin
   importar cual de los dos este oculto en cada modo. El que quede visible sin
   posicion explicita (Volver sin guardar) cae solo en la columna 1 libre por
   auto-placement. */
.mensajes-header-centrado > *:last-child{ grid-column:3; justify-self:end; }
/* "Volver sin guardar" (modo edicion de Mi perfil) no es :first-child en el
   DOM -- ver comentario arriba -- asi que no hereda el justify-self:start
   de esa regla. Sin nada explicito, el default de grid es justify-self:stretch,
   y como cae en la columna 1 (1fr), quedaba estirado ocupando todo el ancho
   disponible en vez de su tamano normal de boton (mas notorio en desktop,
   donde esa columna es bien ancha). */
#btnVolverSinGuardarPerfilAdmin, #btnVolverSinGuardarPerfilProveedor,
#btnVolverSinGuardarPerfilDocente, #btnVolverSinGuardarPerfilFamilia{
  justify-self:start;
}

/* Llega hasta el fondo de la pantalla (la pildora de navegacion flota
   encima, superpuesta, en vez de dejarle un hueco reservado abajo: por eso
   #viewMensajes no tiene padding-bottom, a diferencia de las demas vistas). */
.mensajes-layout{
  display:flex; height:calc(100vh - 160px); min-height:360px; border:1px solid var(--borde);
  border-radius:16px; overflow:hidden; background:#fff; box-shadow:var(--sombra);
}
/* Como en WhatsApp Desktop: la lista de chats y el hilo entre las dos tienen
   que llenar todo el ancho disponible siempre (nada de aire de sobra a los
   costados), pero NO en partes iguales -- la lista va en una proporcion fija
   del ancho total (40%, ver flex-basis) con un piso y un techo en px para
   que no quede ridiculamente angosta en una pantalla chica ni exagerada en
   un monitor gigante; el hilo (.mensajes-hilo, flex:1 mas abajo) se queda
   con TODO el resto, sea cual sea. */
.mensajes-lista-wrap{ flex:0 1 40%; min-width:280px; max-width:480px; border-right:1px solid var(--borde); display:flex; flex-direction:column; min-height:0; }
.mensajes-lista-buscar{ flex-shrink:0; padding:12px 16px 4px; }
.mensajes-lista-buscar input{ margin:0; }
/* El padding horizontal antes vivia aca (en el contenedor), asi que el fondo
   de hover/activo de cada fila (ver .chat-row-activa y .chat-row:hover) le
   quedaba corto contra los dos bordes -- no llegaba ni al izquierdo ni al
   derecho, se notaba un margen de "sobra" a los costados. Se saca de aca y
   se pasa a .chat-row (mas abajo) para que sea la FILA la que tenga el
   padding: su fondo (que ocupa toda la fila) ahora si llega justo hasta los
   dos bordes del panel, y el contenido de adentro (avatar, nombre, etc)
   mantiene el mismo respiro de siempre. */
.mensajes-lista{ flex:1; overflow-y:auto; padding:0; min-height:0; }
.mensajes-hilo{ flex:1; display:flex; flex-direction:column; min-width:0; }
.mensajes-hilo-header{ display:flex; align-items:center; gap:10px; padding:12px 16px; border-bottom:1px solid var(--borde); flex-shrink:0; }
.mensajes-hilo-header h3{ margin:0; font-size:15px; }
#btnVolverHiloMensajes{ flex-shrink:0; }
/* padding-right mas chico + margin-right: asi la barra de scroll del hilo
   queda un poco separada del borde redondeado del marco (.mensajes-layout),
   en vez de pegada justo en el filo donde el border-radius la recorta. */
.mensajes-hilo-cuerpo{ flex:1; display:flex; flex-direction:column; padding:14px 16px 14px 16px; margin-right:6px; overflow-y:auto; min-height:0; }
/* .chat-hilo hereda "overflow-y:auto; max-height:50vh" de su regla base
   (pensada para el preview corto de un chat dentro de otra pantalla), pero
   ese "max-height" fijo mas el overflow propio hacian que, en una
   conversacion larga, TERMINARA scrolleando el .chat-hilo por dentro Y el
   .mensajes-hilo-cuerpo que lo contiene al mismo tiempo -- dos scrollbars
   compitiendo, y la de adentro quedaba pegada justo sobre los mensajes
   propios (alineados a la derecha). El unico que tiene que scrollear es
   el contenedor de afuera, asi que se anula el overflow y el limite de
   alto del de adentro. */
.mensajes-hilo-cuerpo .chat-hilo{ flex:1; max-height:none; overflow:visible; }
.mensajes-hilo-cuerpo .empty{ margin:auto; }

@media (max-width: 720px){
  .mensajes-layout{ height:calc(100vh - 140px); border-radius:16px; }
  /* flex-basis (no "width") es lo que manda el ancho principal de un item
     flex en fila -- con la regla de base de mas arriba (flex:0 1 34%), un
     "width:100%" aca quedaria pisado y en mobile la lista seguiria angosta.
     max-width:none saca el techo de 420px de la regla de base, que en mobile
     no tiene sentido (mobile solo muestra la lista O el hilo, nunca los dos
     lado a lado, ver mensajes-mostrando-hilo mas abajo). */
  .mensajes-lista-wrap{ flex:0 1 100%; max-width:none; border-right:none; }
  .mensajes-layout:not(.mensajes-mostrando-hilo) .mensajes-hilo{ display:none; }
  .mensajes-layout.mensajes-mostrando-hilo .mensajes-lista-wrap{ display:none; }
}

/* Mientras la pantalla de Mensajes esta abierta (docente, direccion o
   responsable), el fondo de la pagina -- topbar incluido -- queda fijo: no
   se puede scrollear la pagina entera para llegar al cuadro de escribir.
   #viewMensajes se saca del flujo normal y pasa a ocupar el alto restante
   de la pantalla como una columna flex; adentro, lo unico que scrollea es
   la lista de conversaciones (.mensajes-lista) o el cuerpo del chat
   (.mensajes-hilo-cuerpo), nunca la pagina. El padding-top exacto (para no
   quedar tapado por el topbar) lo calcula ajustarLayoutMensajes() en JS,
   midiendo el alto real del topbar (que puede variar por el rol, el ancho
   de pantalla o el zoom de accesibilidad). */
body.mensajes-pantalla{ overflow:hidden; }
html.mensajes-pantalla{ overflow:hidden; }

/* Igual que mensajes-pantalla arriba, pero para cualquier popup (modal-bg o
   el lightbox de fotos): mientras esta abierto, el fondo no debe poder
   scrollearse. La clase la prende/apaga un observer generico en JS (ver
   inicializarBloqueoScrollPopups en app.js). */
body.popup-abierto{ overflow:hidden; }
html.popup-abierto{ overflow:hidden; }
body.mensajes-pantalla .topbar{ position:fixed; top:0; left:0; right:0; z-index:20; }
body.mensajes-pantalla #viewMensajes{
  position:fixed; left:0; right:0; top:0; bottom:0; display:flex; flex-direction:column;
  max-width:none; margin:0; padding:70px 24px 0;
}
body.mensajes-pantalla .mensajes-header{ flex-shrink:0; }
body.mensajes-pantalla .mensajes-layout{ flex:1; min-height:0; height:auto; }
@media (max-width: 720px){
  body.mensajes-pantalla #viewMensajes{ padding:70px 12px 0; }
}

.perfil-header{ display:flex; flex-direction:column; align-items:center; padding:18px 10px 6px; text-align:center; position:relative; }
/* Lapiz arriba a la derecha de la card de "Mi perfil": abre el formulario de
   edicion (nombre, vinculo, etc), que por defecto queda oculto para que la
   pantalla arranque mostrando solo los datos, prolija, sin inputs sueltos. */
.btn-lapiz-perfil{
  position:absolute; top:10px; right:10px; width:34px; height:34px; border-radius:50%;
  border:1px solid var(--borde); background:#fff; display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--gris);
}
.btn-lapiz-perfil:hover{ background:var(--gris-cl); color:var(--azul); }
.perfil-datos-card{ background:#fff; border:1px solid var(--borde); border-radius:14px; padding:14px 16px; margin:0 0 14px; box-shadow:var(--sombra); }
/* Avatar editable (solo en modo edicion de Mi perfil, ver avatarEditableHtml
   en app.js, usado por igual en los 4 roles): el overlay (oscurecido + blur
   sutil + lapiz) queda SIEMPRE visible mientras se esta en modo edicion, sin
   depender de pasar el mouse por encima -- asi se entiende de entrada, sin
   necesidad de descubrirlo, que la foto se puede tocar para cambiarla. Antes
   dependia de "@media (hover:hover)" (solo se revelaba al hacer hover, en
   desktop) vs "@media (hover:none)" (siempre visible, en touch): quedaba
   inconsistente segun el dispositivo con el que se probara, aunque el
   componente es identico en los 4 paneles. */
.avatar-edit-wrap{ position:relative; display:inline-block; border-radius:50%; border:none; background:none; padding:0; cursor:pointer; margin-bottom:6px; line-height:0; }
/* El circulo de adentro (.avatar-circle) trae su propio margin-bottom para
   cuando se usa suelto (Mi perfil en modo lectura); aca ese margen sobraba y
   agrandaba la caja del boton mas alla de la foto, corriendo el overlay
   (inset:0 cubre TODA la caja del boton, no solo la foto) hacia abajo y
   haciendo que se vea chico y desalineado respecto del marco circular. */
.avatar-edit-wrap .avatar-circle{ margin-bottom:0; }
.avatar-edit-overlay{
  position:absolute; inset:0; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background:rgba(10,20,35,.3); backdrop-filter:blur(1px); -webkit-backdrop-filter:blur(1px);
  color:#fff; opacity:1;
}
.perfil-datos-card .fila{ display:flex; justify-content:space-between; gap:10px; padding:7px 0; border-bottom:1px solid var(--borde); font-size:13px; }
.perfil-datos-card .fila:last-child{ border-bottom:none; }
.perfil-datos-card .fila span:first-child{ color:var(--gris); }
.perfil-datos-card .fila span:last-child{ font-weight:600; text-align:right; }
.avatar-circle{
  width:78px; height:78px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:26px; font-weight:700; color:#fff; overflow:hidden; margin-bottom:10px; border:3px solid #fff; box-shadow:0 2px 10px rgba(0,0,0,.15);
}
.avatar-circle img{ width:100%; height:100%; object-fit:cover; }
/* Avatar clickeable (Mi perfil): abre el popup para elegir/sacar la foto. */
.avatar-clickable{ border-radius:50%; transition:opacity .15s; }
.avatar-clickable:hover{ opacity:.82; }
.perfil-header h4{ margin:0 0 2px; font-size:15px; }
.perfil-header p{ margin:0; font-size:12px; color:var(--gris); }
.perfil-seccion{ padding:20px; }
/* Mismo motivo que ".card > label:first-child" de mas arriba: el label
   arranca justo despues del h2 de la card (panel de responsable) y su
   margin-top se sumaba de mas al padding, desbalanceando arriba vs abajo. */
.perfil-seccion h2 + label{ margin-top:0; }
.perfil-seccion label{ margin:10px 0 4px; }
/* Card que en realidad es un boton (ej. "Publicaciones guardadas", que abre
   una pantalla aparte): se le resetean los estilos por defecto de <button>
   para que se vea identica a una .card comun, con una fila title+flecha. */
.card-boton{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  cursor:pointer; font-family:inherit; color:inherit; text-align:left;
  transition:background .15s ease, transform .1s ease;
}
.card-boton:hover{ background:var(--gris-cl); }
.card-boton:active{ transform:scale(.99); }
.card-boton h2{ margin:0; }
.card-boton-flecha{ color:var(--gris); flex-shrink:0; }
.avatar-upload-row{ display:flex; align-items:center; gap:10px; margin-top:6px; }
.avatar-upload-row input[type=file]{ font-size:11.5px; }

.seccion-titulo{ font-size:12px; text-transform:uppercase; letter-spacing:.4px; color:var(--gris); margin:18px 0 10px; }
.seccion-titulo:first-child{ margin-top:2px; }

.acc-section{ background:#fff; border:1px solid var(--borde); border-radius:14px; box-shadow:var(--sombra); margin-bottom:16px; overflow:hidden; }
.acc-header{
  width:100%; display:flex; align-items:center; justify-content:space-between; gap:10px;
  background:none; border:none; padding:16px 20px; cursor:pointer; text-align:left; font-family:inherit;
}
.acc-header:hover{ background:var(--gris-cl); }
.acc-header-titulo{ display:block; font-size:15.5px; font-weight:700; color:var(--azul-osc); }
.acc-header-sub-txt{ display:block; font-size:12px; font-weight:400; color:var(--gris); margin-top:2px; }
.acc-arrow{ display:inline-block; font-size:13px; color:var(--gris); transition:transform .15s; flex-shrink:0; }
.acc-header.abierta .acc-arrow{ transform:rotate(90deg); }
/* El alto real de un acordeon puede ser cualquier cosa (un formulario chico,
   o una lista larga de documentos/avisos), asi que no se anima con un
   max-height fijo (podria recortar contenido si crece de mas). toggleAccordion()
   en app.js mide el scrollHeight real al abrir/cerrar y anima hasta ese
   numero exacto -- por eso alcanza con declarar la transicion aca, sin
   ningun max-height de base (queda "none" hasta que JS lo pisa). */
.acc-body{ padding:0 20px 20px; overflow:hidden; transition:max-height .3s ease; }

.acc-section-sub{ border:1px solid var(--borde); border-radius:10px; margin-top:14px; overflow:hidden; }
.acc-section-sub .acc-header{ padding:11px 14px; }
.acc-section-sub .acc-header-titulo{ font-size:13px; }
.acc-section-sub .acc-body{ padding:0 14px 14px; }

/* Dropdown "Mostrar" (filtro de curso en Inicio, docente/direccion): antes
   era un <select> nativo, cuyo popup de opciones lo dibuja el sistema
   operativo y no se puede animar. Se reemplaza por un boton + lista propia
   (mismos datos, mismo onchange logico) para poder darle una animacion de
   despliegue acorde al resto de la app (mismo estilo pop que el menu del
   FAB: nace pegado arriba, encogido, y crece hasta su tamano real). */
.filtro-dropdown{ position:relative; }
.filtro-dropdown-btn{
  width:100%; display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:10px 12px; border:1px solid var(--borde); border-radius:9px; background:var(--superficie-input);
  font-size:15px; font-family:inherit; color:var(--texto); cursor:pointer; text-align:left;
}
.filtro-dropdown-chevron{ flex-shrink:0; color:var(--gris); transition:transform .22s cubic-bezier(.34,1.35,.64,1); }
.filtro-dropdown.filtro-dropdown-abierto .filtro-dropdown-chevron{ transform:rotate(180deg); }
.filtro-dropdown-menu{
  position:absolute; left:0; right:0; top:calc(100% + 6px); z-index:5;
  background:var(--superficie); border:1px solid var(--borde); border-radius:10px; box-shadow:var(--sombra);
  padding:6px; max-height:260px; overflow-y:auto;
  transform-origin:top center; transform:scaleY(.85) translateY(-4px); opacity:0; pointer-events:none;
  transition:transform .18s cubic-bezier(.34,1.35,.64,1), opacity .14s ease;
}
.filtro-dropdown.filtro-dropdown-abierto .filtro-dropdown-menu{ transform:scaleY(1) translateY(0); opacity:1; pointer-events:auto; }
.filtro-dropdown-item{
  display:block; width:100%; text-align:left; padding:9px 10px; border:none; background:none;
  border-radius:7px; font-size:13.5px; font-family:inherit; color:var(--texto); cursor:pointer;
}
.filtro-dropdown-item:hover{ background:var(--gris-cl); }
.filtro-dropdown-item.activo{ background:var(--azul-cl); color:var(--azul); font-weight:600; }
/* En oscuro, --azul se mantiene igual a proposito (identidad de marca, ver
   html.modo-oscuro mas arriba), pero eso deja texto azul muy oscuro sobre un
   fondo (--azul-cl en oscuro) que tambien es azul oscuro: casi no se lee.
   --azul-osc SI se remapea a un celeste claro en oscuro (misma excepcion que
   usa .bottom-nav button.active), asi que sirve para el texto aca tambien. */
html.modo-oscuro .filtro-dropdown-item.activo{ color:var(--azul-osc); }

/* Transicion al cambiar de pestania (Inicio/Pedidos/Avisos/Mas, etc): la
   pestania que queda a la vista entra con un fade + deslizamiento sutil en
   vez de aparecer de golpe. Se dispara agregando .tab-fade-in justo despues
   de sacarle el .hide (ver animarCambioPestania en app.js); al ser una
   animation (no transition) no importa el estado previo de opacity. */
@keyframes tabFadeIn{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:translateY(0); } }
.tab-fade-in{ animation:tabFadeIn .22s ease; }

.admin-user-row .quien{ align-items:flex-start; flex-direction:column; gap:2px; }
.admin-user-row .quien-linea{ display:flex; align-items:center; gap:6px 8px; flex-wrap:wrap; min-width:0; }
.meta-chica{ font-size:11px; color:var(--gris); }
.quien-con-meta{ align-items:flex-start !important; flex-direction:column; gap:2px; }
.quien-con-meta .quien-linea{ display:flex; align-items:center; gap:6px 8px; flex-wrap:wrap; min-width:0; }

/* Boton flotante "+": atajo para crear (publicacion, tarea, usuario, etc) sin
   tener que ir a buscar el acordeon correspondiente. Solo docente y direccion.
   Por defecto flota arriba de la pildora (nunca se superponen). Al scrollear
   la ventana principal, se agrega body.fab-compacto: el + se achica un poco
   y se desliza a la derecha de la pildora (que tambien se achica un toque
   para dejarle lugar), en vez de quedar montado arriba. */
.fab{
  position:fixed; right:20px; bottom:100px; z-index:45;
  display:flex; flex-direction:column; align-items:flex-end; gap:10px;
  transition: right .22s ease, bottom .22s ease, opacity .18s ease;
  opacity:1;
  /* El contenedor no tiene fondo ni bordes propios, pero SI ocupa una caja de
     layout real: como transform:scale (ver .fab-menu) no achica la caja, el
     .fab-menu "cerrado" sigue midiendo su alto/ancho completo (varios items)
     aunque sea invisible. Sin este pointer-events:none, esa zona invisible
     tapaba toques en el contenido de abajo (ej. las cards de la pestania
     Usuarios en preceptoria, donde el + queda siempre fijo arriba). Se
     reactiva puntualmente en .fab-btn (siempre) y en .fab-menu solo mientras
     esta abierto (ver mas abajo, ya estaba bien resuelto ahi). */
  pointer-events:none;
}
/* Mismo mecanismo que .bottom-nav.hide/.modal-bg.hide: pisa el .hide generico
   (display:none) para poder animar la desaparicion con un fade en vez de un
   corte seco, cada vez que el + se oculta/reaparece junto con la pildora (ver
   ocultarNavAlEntrarAConfig/mostrarNavAlSalirDeConfig en app.js). */
.fab.hide{ display:flex !important; opacity:0; pointer-events:none; }
.fab.hide .fab-btn{ pointer-events:none; }
.fab-btn{
  width:56px; height:56px; border-radius:50%; background:var(--azul); color:#fff; border:none;
  cursor:pointer; box-shadow:0 6px 18px rgba(20,40,70,.28); line-height:1; display:flex; align-items:center; justify-content:center;
  transition: width .22s ease, height .22s ease, transform .1s ease;
  pointer-events:auto;
}
.fab-btn:active{ transform:scale(.93); }
/* "Pop" al tocar el +: se achica de golpe y rebota mas alla de su tamano
   normal antes de asentarse, para que se sienta la apertura del menu (ver
   alternarFabMenu en app.js, que agrega y saca esta clase). */
@keyframes fabPop{
  0%{ transform:scale(1); }
  35%{ transform:scale(.86); }
  70%{ transform:scale(1.08); }
  100%{ transform:scale(1); }
}
.fab-btn.fab-pop{ animation:fabPop .38s cubic-bezier(.34,1.2,.64,1); }
/* El "+" es un SVG (no el caracter de texto): un glifo de fuente nunca queda
   perfectamente centrado en su propio recuadro segun la tipografia, un SVG
   dentro de un boton con flex centrado si. */
.fab-btn svg{ width:46%; height:46%; flex-shrink:0; }
.fab-btn:hover{ background:var(--azul-osc); }
body.fab-compacto .fab{ right:10px; bottom:24px; }
body.fab-compacto .fab-btn{ width:44px; height:44px; }
/* Al scrollear, el + pasa a flotar al lado de la pildora: los dos tienen que
   quedar del mismo alto y alineados. En vez de achicar la pildora entera con
   un transform:scale (que no da un alto exacto y desalinea contra el +, que
   tiene un tamano fijo en px), se le esconde el texto a los botones (quedan
   solo los iconos, como en .nav-compacta) y se le fija una altura de boton
   que, sumada al padding del marco (.bottom-nav-inner), da exactamente el
   mismo alto que el circulo del + (44px en mobile, 52px en PC). */
body.fab-compacto .bottom-nav-inner .nav-label{ max-height:0; opacity:0; }
/* Al scrollear la pildora no solo se achica: se ESTIRA para ocupar todo el
   ancho libre a la izquierda del + (ver el "left" del bloque de mas abajo),
   y cada boton pasa a ser un segmento flexible de ancho IGUAL (flex:1 1 0,
   en vez de su ancho natural fijo) para repartirse ese ancho entre todos, sin
   dejar aire de sobra de un lado. */
body.fab-compacto .bottom-nav-inner{ gap:0; }
body.fab-compacto .bottom-nav button{ flex:1 1 0; padding:0 4px; gap:0; height:32px; }
@media (max-width:720px){
  /* En mobile, cuando el + pasa a flotar al lado de la pildora (fab-compacto),
     la pildora deja de centrarse por el flex del contenedor padre (.bottom-nav)
     y pasa a fixed ella misma, anclada por los DOS lados: contra el borde
     izquierdo de la pantalla (con el mismo margen de 10px que el + tiene del
     lado derecho, ver .fab mas arriba) y contra el borde derecho con un
     "right" que ya descuenta el ancho del + (44px), su propio margen (10px)
     y un aire fijo entre los dos (8px): 10+44+8 = 62px. Al quedar anclada por
     los dos lados a la vez, el ancho sale solo (ocupa todo lo que hay entre
     el borde de la pantalla y el +, ver flex:1 1 0 de arriba) y los dos
     quedan siempre pegados como un solo conjunto, sin importar el viewport.
     Antes se centraba la pildora entera (ancho automatico, chico) y se la
     corria con un translateX que combinaba vw + un porcentaje propio para
     dejar su borde izquierdo a 10px del borde de la pantalla. En la practica
     ese calculo (basado en 50vw) podia quedar corrido -- por ejemplo si el
     navegador reserva lugar para una scrollbar, vw no siempre coincide
     exactamente con el ancho visible real -- y la pildora terminaba
     recortada contra el borde izquierdo, ademas de dejar (al ser chica) un
     hueco grande hasta el +. Anclar los dos bordes directamente evita las
     dos cosas. */
  body.fab-compacto .bottom-nav-inner{
    position:fixed; left:10px; right:62px; bottom:16px; z-index:20; transform:none;
    transition:left .22s ease, right .22s ease, bottom .22s ease;
  }
  /* .fab queda a 24px del piso al scrollear (regla de arriba); .bottom-nav
     por defecto esta a 16px (ver .bottom-nav mas arriba): sin este ajuste
     quedaban 8px desalineados entre si. */
  body.fab-compacto .fab{ bottom:16px; }
}
/* El menu de opciones "sale" de atras del boton +: arranca achicado y
   pegado a la esquina inferior derecha (transform-origin), y crece hasta su
   tamano normal con un rebote sutil, como si hubiera estado escondido ahi.
   Ya no se usa .hide para mostrarlo/ocultarlo (no se puede animar desde
   display:none): alternarFabMenu()/cerrarFabMenu() en app.js togglean la
   clase .fab-menu-abierto en su lugar. Mientras esta cerrado sigue en el DOM
   pero invisible y sin poder recibir clicks (pointer-events:none). */
.fab-menu{
  display:flex; flex-direction:column; gap:4px; background:var(--superficie); border:1px solid var(--borde); border-radius:12px; padding:8px; box-shadow:var(--sombra); min-width:210px; position:relative; z-index:46;
  transform-origin:bottom right; transform:scale(.3) translateY(14px); opacity:0; pointer-events:none;
  transition:transform .24s cubic-bezier(.34,1.35,.64,1), opacity .16s ease;
}
.fab-menu.fab-menu-abierto{ transform:scale(1) translateY(0); opacity:1; pointer-events:auto; }
.fab-menu-item{
  text-align:left; background:none; border:none; padding:9px 12px; font-size:13px; font-weight:600; color:var(--texto-label);
  border-radius:8px; cursor:pointer; font-family:inherit; transition:transform .1s ease;
}
.fab-menu-item:hover{ background:var(--gris-cl); }
.fab-menu-item:active{ transform:scale(.97); }
/* Al abrir el menu del +, se desenfoca el fondo (igual que un modal) para
   que las opciones queden claramente arriba de todo lo demas. El blur entra
   en transicion (arranca en 0 y llega a su valor final) en vez de aparecer
   de golpe -- misma logica que el menu: ya no se usa .hide, sino la clase
   .fab-backdrop-abierto. */
.fab-backdrop{
  position:fixed; inset:0; z-index:40; background:rgba(9,30,58,.28);
  backdrop-filter:blur(0); -webkit-backdrop-filter:blur(0);
  opacity:0; pointer-events:none;
  transition:opacity .2s ease, backdrop-filter .2s ease, -webkit-backdrop-filter .2s ease;
}
.fab-backdrop.fab-backdrop-abierto{
  backdrop-filter:blur(2.5px); -webkit-backdrop-filter:blur(2.5px);
  opacity:1; pointer-events:auto;
}
@media (min-width:1000px){
  /* En PC el + tambien se ve chico comparado con el resto de la pantalla:
     bastante mas grande que antes (68px), para que no quede perdido en todo
     el espacio vacio alrededor. */
  .fab-btn{ width:92px; height:92px; }
  body.fab-compacto .fab-btn{ width:64px; height:64px; }
  /* La pildora, al scrollear, caia en la regla generica de mas arriba
     (pensada para mobile: height:32px) -- un salto enorme respecto del
     tamano grande de PC (64px, ver "En PC la pildora se ve chica..." mas
     arriba) que se sentia roto en vez de una animacion sutil. En PC alcanza
     con un achique chico, solo para que se note que la pagina "esta viva"
     al scrollear -- no hace falta compactarla tanto como en mobile (ahi si
     hace falta, para dejarle lugar al + al lado; en PC el + no se mueve al
     lado de la pildora, se queda flotando donde estaba). */
  body.fab-compacto .bottom-nav-inner{ gap:4px; }
  body.fab-compacto .bottom-nav button{ padding:0 16px; height:54px; }
}

.lista-firmas{ margin-top:10px; border-top:1px solid var(--borde); padding-top:8px; }
.firma-item{ display:flex; align-items:center; justify-content:space-between; gap:8px; padding:5px 0; font-size:12px; }
.firma-item span{ color:var(--gris); }
.firma-item button{ flex-shrink:0; }

/* Docente y admin trabajan sobre todo desde una PC: en pantallas anchas
   organizamos el contenido de cada pestaña en 2 columnas explicitas
   (.panel-col). Los wrappers no producen ninguna caja en pantallas angostas
   (display:contents), asi que ahi todo cae en una sola columna, sin ningun
   cambio (el panel de familia no se toca, se sigue usando sobre todo desde
   el celular). */
.panel-cols, .panel-cols > .panel-col{ display:contents; }
@media (min-width:1000px){
  #viewAdmin.wrap, #viewMensajes.wrap, #viewProveedor.wrap{ max-width:1500px; }
  #viewDocente.wrap{ max-width:1100px; }
  .panel-cols{ display:flex; align-items:flex-start; gap:20px; }
  .panel-cols > .panel-col{ display:block; flex:1; min-width:0; }
  /* Proveedor: el formulario para publicar queda mas angosto y fijo a la
     izquierda, el feed de sus publicaciones ocupa el resto del ancho. */
  .panel-col-prov-form{ flex:0.7; position:sticky; top:20px; }
  .panel-col-prov-feed{ flex:1.3; }
}

/* Pestañas de docente y direccion: los paneles quedan bien separados de la
   pildora flotante de abajo, que ahora es fixed en todos los paneles (no
   solo en el de responsables). #viewMensajes queda afuera a proposito: ahi
   la pildora flota superpuesta sobre la card en vez de dejarle un hueco
   reservado (ver .mensajes-layout). */
#viewDocente, #viewAdmin, #viewAdminConfig, #viewPerfilDocente, #viewPerfilAdmin{ padding-bottom:90px; }
#viewMensajes{ padding-bottom:20px; }
@media (min-width:1000px){
  /* En PC la pildora es mas grande (ver .bottom-nav mas arriba), asi que
     necesita un poco mas de aire abajo (se habia quedado afuera
     #viewPerfilAdmin, con la misma pildora que el resto). */
  #viewDocente, #viewAdmin, #viewAdminConfig, #viewPerfilDocente, #viewPerfilAdmin{ padding-bottom:110px; }
}
/* Preceptoria: su pildora es mas alta que la del resto (ver body.nav-preceptoria
   .bottom-nav button mas arriba, 60px/74px vs 52px/64px) Y nunca se achica al
   scrollear (nunca entra en fab-compacto, ver permiteCompacto en app.js) --
   el padding-bottom fijo de arriba, calibrado contra la pildora regular
   (que ademas se achica), se quedaba corto para #viewAdmin (la unica vista
   donde la pildora de preceptoria realmente flota visible; en Configuración
   y Mi perfil queda oculta, ahi el padding de arriba no importa). Solo se
   pisa para preceptoria, el resto de los paneles no se toca. */
body.nav-preceptoria #viewAdmin{ padding-bottom:98px; }
@media (min-width:1000px){
  body.nav-preceptoria #viewAdmin{ padding-bottom:130px; }
}
