/* ===================================================================
   Portal web del residente (Fase 8.2).

   Todo lo de aqui se construye SOLO con los tokens de `tokens.css`. Ningun
   color, tamano ni espacio literal: es lo que permite que la Fase 9 sea
   cambiar valores en un archivo y no auditar hojas de estilo.

   Sin framework CSS. Son ~8 pantallas con formularios y listas; traer
   Tailwind o Bootstrap para eso agrega una cadena de build a un proyecto
   cuyo punto era no salir de Python (seccion 3).
   ========================================================================== */

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

body, h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--f-familia);
  font-size: var(--t-base);
  line-height: var(--l-normal);
  color: var(--c-texto);
  background: var(--c-fondo-sutil);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

img, svg { max-width: 100%; display: block; }

button, input, select, textarea { font: inherit; color: inherit; }

a { color: inherit; text-decoration-color: var(--c-texto-terciario); }

/* Foco visible siempre. Quitarlo "porque se ve feo" deja sin navegacion a
   quien usa teclado o lector de pantalla. */
:focus-visible {
  outline: 2px solid var(--c-acento);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* --- Estructura ----------------------------------------------------------

   Tres rangos y un solo HTML (ver `templates/residentes/base.html` y la
   seccion "Tres rangos" al final de este archivo):

     telefono   (< 48rem)   columna de ancho movil, navegacion al pie.
     tablet     (48-64rem)  la app toma el ancho menos los margenes y la
                            navegacion sube a una barra horizontal.
     escritorio (>= 64rem)  lateral fija de 15rem y contenido a lo ancho.

   Hasta 48rem la app es la columna de siempre: en el telefono ocupa todo y no
   lleva adorno, y de 40 a 48rem se despega del borde y se lee como una
   tarjeta, porque una tira pegada al borde de una ventana de 700px se ve rota.
   Lo que ya no se hace es sostener esa columna en un monitor: era la pantalla
   del telefono estirada al centro, con el 80 % del espacio vacio.            */
.app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  max-width: var(--ancho-app);
  margin-inline: auto;
  background: var(--c-fondo);
}

@media (min-width: 40rem) {
  body { background: var(--c-lienzo); padding: var(--s-8) var(--s-4); }

  .app {
    min-height: calc(100vh - var(--s-8) * 2);
    border: 1px solid var(--c-borde);
    border-radius: var(--r-lg);
    overflow: hidden;
    /* Sombra minima: separa la tarjeta del lienzo sin llamar la atencion.
       La jerarquia la hacen la tipografia y el espaciado (seccion 10).    */
    box-shadow: var(--sombra-media);
  }
}

/* Armazon interno. En telefono y tablet es una columna —navegacion arriba o
   abajo y el contenido debajo—; en escritorio pasa a fila y la lateral se
   sienta a la izquierda del area de trabajo. La barra inferior NO va aqui
   dentro: cuelga de `.app`, para quedar pegada al borde de la ventana.      */
.portal {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

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

.encabezado {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-borde);
  background: var(--c-fondo);
  position: sticky;
  top: 0;
  z-index: 10;
}

.encabezado__marca {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-weight: var(--p-semibold);
  font-size: var(--t-sm);
  letter-spacing: var(--e-titulo);
}

.encabezado__logo { height: 1.5rem; width: auto; }

/* Acceso al perfil desde el telefono: la residencia activa y un icono, en un
   objetivo de la altura de toque completa. La barra de abajo son los cinco
   destinos del dia a dia y Perfil no es uno; sin este enlace la pantalla no se
   alcanza desde ningun lado del telefono. */
.encabezado__perfil {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--alto-toque);
  color: var(--c-texto-terciario);
  text-decoration: none;
}

.encabezado__perfil:hover { color: var(--c-texto); }

.encabezado__icono { width: 1.25rem; height: 1.25rem; flex: none; }

/* --- Marca del cliente ---------------------------------------------------

   El logo es `static/cliente/logo.svg`, servido como <img>: el de cada cliente
   trae sus propios colores y no hereda los de la pagina. El de APTO que viene
   por defecto cambia de verde con el tema por un <style> dentro del propio
   SVG. Solo se fija la altura; el ancho lo da el archivo.                     */

.contenido {
  flex: 1;
  padding: var(--s-6) var(--s-5) var(--s-16);
}

/* --- Navegacion principal ------------------------------------------------

   Una sola lista de destinos en dos formas (`partials/navegacion.html` pinta
   las dos y aqui se decide cual se ve):

     `--barra`    al pie, en el telefono. El pulgar llega abajo, no arriba.
     `--lateral`  con icono + texto en cuanto hay ancho: barra horizontal
                  arriba en tablet, columna fija a la izquierda en escritorio.

   Lo comun —el item, su estado activo y el icono— vive fuera de las dos
   variantes; lo que cambia es la caja.                                      */
.navegacion__item {
  min-height: var(--alto-toque);
  font-size: var(--t-xs);
  color: var(--c-texto-terciario);
  text-decoration: none;
  transition: color var(--transicion), background var(--transicion);
}

.navegacion__item[aria-current="page"] { color: var(--c-texto); font-weight: var(--p-medio); }

.navegacion__icono { width: 1.375rem; height: 1.375rem; flex: none; }

/* Barra inferior (telefono). */
.navegacion--barra {
  position: sticky;
  bottom: 0;
  display: grid;
  grid-auto-flow: column;
  /* minmax(0, ...) y no 1fr: con 1fr el minimo de cada columna es su
     contenido, y "Reservas" o "Reportes" a 320px empujaban la barra fuera
     de la pantalla. */
  grid-auto-columns: minmax(0, 1fr);
  border-top: 1px solid var(--c-borde);
  background: color-mix(in srgb, var(--c-fondo) 92%, transparent);
  backdrop-filter: blur(12px);
  /* El area segura del sistema (la barra de gestos de iOS) no debe tapar el
     ultimo renglon de iconos. */
  padding-bottom: env(safe-area-inset-bottom);
}

/* El envoltorio de los cinco destinos no debe formar caja en esta variante:
   `contents` lo borra del layout y los enlaces vuelven a ser hijos directos de
   la rejilla de cinco columnas. Asi la lista es una sola en el HTML.        */
.navegacion--barra .navegacion__grupo { display: contents; }

.navegacion--barra .navegacion__item {
  display: grid;
  place-items: center;
  gap: var(--s-1);
  padding: var(--s-2) var(--s-1);
  text-align: center;
}

/* La lateral aparece a partir de 48rem (ver "Tres rangos"). */
.navegacion--lateral { display: none; }

/* --- Tipografia ---------------------------------------------------------- */
/* El titulo de pantalla lleva la voz de la marca (fuente ancha, tokens.css);
   el resto del texto sigue en la familia de lectura. */
h1, .titulo {
  font-family: var(--f-titulo);
  font-stretch: var(--f-titulo-anchura);
}

.titulo {
  font-size: var(--t-2xl);
  font-weight: var(--p-semibold);
  line-height: var(--l-ajustado);
  letter-spacing: var(--e-titulo);
}

.subtitulo {
  font-size: var(--t-xl);
  font-weight: var(--p-semibold);
  line-height: var(--l-ajustado);
  letter-spacing: var(--e-titulo);
}

.seccion-titulo {
  font-size: var(--t-sm);
  font-weight: var(--p-semibold);
  color: var(--c-texto-terciario);
  margin-bottom: var(--s-3);
}

.texto-secundario { color: var(--c-texto-secundario); font-size: var(--t-sm); }
.texto-terciario  { color: var(--c-texto-terciario);  font-size: var(--t-sm); }

/* La cifra que el residente vino a ver. Es lo unico en la pantalla con este
   peso visual, y por eso funciona. */
.cifra {
  font-size: var(--t-3xl);
  font-weight: var(--p-semibold);
  line-height: var(--l-ajustado);
  letter-spacing: var(--e-cifra);
  font-variant-numeric: tabular-nums;
}

/* Cifras contables: numeros tabulares (todos del mismo ancho) para que las
   columnas de dinero y fechas se lean en vertical. `.cifra-tabla` la pone
   experiencia.js en las celdas que son un monto o una fecha. */
.monto,
.cifra-tabla {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

.cifra-tabla { text-align: right; white-space: nowrap; }

.pila     > * + * { margin-top: var(--s-4); }
.pila-sm  > * + * { margin-top: var(--s-2); }
.pila-lg  > * + * { margin-top: var(--s-8); }

/* --- Tarjeta ------------------------------------------------------------- */
.tarjeta {
  background: var(--c-fondo-elevado);
  border: 1px solid var(--c-borde);
  border-radius: var(--r-lg);
  box-shadow: var(--sombra-sutil);
  padding: var(--s-5);
}

.tarjeta--plana { background: var(--c-fondo-sutil); border-color: transparent; }

/* --- Lista --------------------------------------------------------------- */
.lista {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--c-borde);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-fondo-elevado);
}

.lista__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  min-height: var(--alto-toque);
}

.lista__item + .lista__item { border-top: 1px solid var(--c-borde); }

.lista__item--enlace { text-decoration: none; transition: background var(--transicion); }
.lista__item--enlace:hover { background: var(--c-acento-suave); }

.lista__principal { font-weight: var(--p-medio); }

/* Variante para un item que no es fila (autor + fecha, texto, adjunto): el
   hilo de comentarios de un ticket, por ejemplo. */
.lista__item--comentario {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
}

/* --- Botones ------------------------------------------------------------- */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--alto-toque);
  padding: var(--s-3) var(--s-5);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-size: var(--t-base);
  /* Semibold (2026-10-20): en Jakarta el 500 se leia delgado y el boton se
     confundia con el texto de al lado. */
  font-weight: var(--p-semibold);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transicion), border-color var(--transicion);
}

/* La accion primaria usa el verde SOLIDO, no el de texto: son dos tokens
   distintos porque el relleno tiene que contrastar con lo que lleva encima y
   el acento con el fondo de la pagina. Ver la nota en `tokens.css`.      */
.boton--primario {
  background: var(--c-acento-solido);
  color: var(--c-acento-solido-texto);
}
.boton--primario:hover:not(:disabled) { background: var(--c-acento-solido-hover); }

.boton--secundario {
  background: transparent;
  /* 1.5px: con 1px el contorno casi no se veia sobre las tarjetas de color. */
  border-width: 1.5px;
  border-color: var(--c-borde-fuerte);
  color: var(--c-texto);
}
.boton--secundario:hover:not(:disabled) { background: var(--c-acento-suave); }

/* Azul: es interactivo (regla del sistema). En gris se leia como texto corriente. */
.boton--texto { background: transparent; padding-inline: var(--s-2); color: var(--c-acento); }

.boton--critico { background: transparent; border-width: 1.5px; border-color: var(--c-borde-fuerte); color: var(--c-critico); }

.boton--ancho { width: 100%; }

/* Acciones de una fila de tabla (2026-10-08): un primario compacto para LA
   accion de la fila y un boton de icono («⋮») que abre las demas. Cada fila
   repite su primario, asi que es compacto y no compite con el primario de
   la pantalla. */
.btn-primary-sm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  height: 2rem;
  padding: 0 var(--s-3);
  border: 0;
  border-radius: var(--r-sm);
  background: var(--c-acento-solido);
  color: var(--c-acento-solido-texto);
  font: inherit;
  font-size: var(--t-xs);
  font-weight: var(--p-semibold);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.btn-primary-sm:hover { background: var(--c-acento-solido-hover); }

.btn-icon {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-texto-secundario);
  font-size: var(--t-lg);
  line-height: 1;
  cursor: pointer;
  list-style: none;
}

.btn-icon:hover { border-color: var(--c-borde); background: var(--c-fondo-sutil); color: var(--c-texto); }

.acciones-fila {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-2);
}

/* El menu es un `popover` nativo: se dibuja por encima de todo (una tabla
   que rueda en horizontal no lo recorta) y cierra solo con un clic afuera o
   Escape. experiencia.js lo coloca bajo su boton. */
.menu-fila__lista {
  position: fixed;
  inset: auto;
  min-width: 11rem;
  margin: 0;
  padding: var(--s-1);
  list-style: none;
  border: 1px solid var(--c-borde);
  border-radius: var(--r-md);
  background: var(--c-fondo-elevado);
  box-shadow: var(--sombra-elevada);
  text-align: left;
}

.menu-fila__lista a,
.menu-fila__lista button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 2.25rem;
  padding: 0 var(--s-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-texto);
  font: inherit;
  font-size: var(--t-sm);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

/* Formularios dentro de las acciones de una fila o del menu «⋮» (aprobar,
   rechazar con motivo): no rompen la fila. Comunes a todas las areas. */
.acciones-fila form,
.menu-fila__lista li > form { display: contents; }
.menu-fila__lista .menu-fila__critica,
.menu-fila__lista .menu-fila__critica:hover { color: var(--c-critico); }
.menu-fila__lista li > form.menu-fila__formulario {
  display: grid;
  gap: var(--s-2);
  margin-top: var(--s-1);
  padding: var(--s-2) var(--s-3) var(--s-1);
  border-top: 1px solid var(--c-borde);
}
.menu-fila__formulario label { color: var(--c-texto-secundario); font-size: var(--t-xs); }
.menu-fila__formulario input {
  min-width: 14rem;
  height: 2.25rem;
  padding: 0 var(--s-3);
  border: 1px solid var(--c-borde-fuerte);
  border-radius: var(--r-sm);
  background: var(--c-fondo-elevado);
  color: var(--c-texto);
  font: inherit;
  font-size: var(--t-sm);
}
.menu-fila__lista .menu-fila__formulario button { justify-content: center; border: 1px solid var(--c-borde-fuerte); }

/* Cifras de cabecera (saldo, desglose, totales de planilla o factura): una
   fila de tarjetas. Comun a Cobros y a Planilla/Gastos. */
.resumen-cifras {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s-4);
  margin: 0;
}

.resumen-cifras > div {
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--c-borde);
  border-radius: var(--r-md);
  background: var(--c-fondo-elevado);
  box-shadow: var(--sombra-sutil);
}

.resumen-cifras dt { color: var(--c-texto-secundario); font-size: var(--t-xs); }

.resumen-cifras dd {
  margin: var(--s-1) 0 0;
  font-size: var(--t-lg);
  font-weight: var(--p-semibold);
  font-variant-numeric: tabular-nums;
}

.resumen-cifras .resumen-cifras__principal dd { font-size: var(--t-xl); }
.resumen-cifras dd .etiqueta { margin-left: var(--s-2); vertical-align: middle; }

.menu-fila__nota { padding: var(--s-2) var(--s-3); color: var(--c-texto-terciario); font-size: var(--t-xs); }

.menu-fila__lista a:hover,
.menu-fila__lista button:hover { background: var(--c-fondo-sutil); }

.boton:disabled { opacity: 0.45; cursor: not-allowed; }

/* --- Formularios --------------------------------------------------------- */
.campo { display: flex; flex-direction: column; gap: var(--s-2); }

.campo__etiqueta {
  font-size: var(--t-sm);
  font-weight: var(--p-medio);
  color: var(--c-texto-secundario);
}

.campo__control {
  width: 100%;
  min-height: var(--alto-toque);
  padding: var(--s-3) var(--s-4);
  background: var(--c-fondo);
  border: 1px solid var(--c-borde-fuerte);
  border-radius: var(--r-md);
  transition: border-color var(--transicion);
}

.campo__control:focus { border-color: var(--c-acento); outline-offset: 1px; }
/* El placeholder por defecto del navegador (#757575) da 3.7:1 sobre el campo
   oscuro. El terciario da 5.5 en claro y 5.0 en oscuro; `opacity: 1` porque
   Firefox lo atenua por su cuenta. Global: el panel tambien pinta inputs
   sin `.campo__control` (buscador, filtros).                              */
::placeholder { color: var(--c-texto-terciario); opacity: 1; }
/* Sin esto el <fieldset> lleva el borde `groove` del navegador, un gris que
   no es de ningun tema (casi blanco sobre el oscuro). */
fieldset { border: 1px solid var(--c-borde); border-radius: var(--r-md); }

.campo__ayuda { font-size: var(--t-sm); color: var(--c-texto-terciario); }
.campo__error { font-size: var(--t-sm); color: var(--c-critico); }

/* Casilla de un solo caracter para el OTP: seis digitos separados se teclean
   sin errores y se leen de un vistazo. `inputmode` abre el teclado numerico
   en el telefono, que es donde se va a usar. */
.otp {
  display: flex;
  gap: var(--s-2);
  justify-content: center;
}

.otp__digito {
  width: 2.75rem;
  height: 3.5rem;
  text-align: center;
  font-size: var(--t-xl);
  font-weight: var(--p-semibold);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--c-borde-fuerte);
  border-radius: var(--r-md);
  background: var(--c-fondo);
}

/* El formulario de verificacion (CU-02) manda el codigo como un solo campo de
   texto, no seis inputs separados; esta variante lo hace LEER como un OTP
   (grande, centrado, con aire entre digitos) sin cambiar el widget. */
.campo--otp .campo__control {
  text-align: center;
  font-size: var(--t-2xl);
  font-weight: var(--p-semibold);
  letter-spacing: 0.5em;
  font-variant-numeric: tabular-nums;
  /* Compensa la letra final, que si no queda pegada al borde derecho. */
  padding-right: calc(var(--s-4) + 0.5em);
}

/* --- Etiquetas de estado -------------------------------------------------
   Color + TEXTO, nunca color solo: cerca del 8 % de los hombres no
   distingue rojo de verde, y el estado de una cuota no puede depender de
   eso.                                                                     */
/* Insignia compacta (2026-10-08): 4px 10px, radio 16px, 12px de letra y un
   punto de 6px del color del estado. `.badge` es el mismo componente con el
   nombre que pidio el dueno; `.etiqueta` es el que ya usan las plantillas.
   El punto no reemplaza al texto: la insignia dice "Vencida" con todas sus
   letras; el punto permite barrer una columna de cuarenta filas.          */
.etiqueta,
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem;
  border-radius: 1rem;
  font-size: 0.75rem;
  font-weight: var(--p-medio);
  line-height: 1.125rem;
  white-space: nowrap;
}

.etiqueta--positiva::before,
.etiqueta--atencion::before,
.etiqueta--critica::before,
.etiqueta--info::before,
.badge-dot {
  content: "";
  flex: none;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: var(--r-full);
  background: currentColor;
}

.etiqueta--neutra                     { background: var(--c-fondo-sutil);    color: var(--c-texto-secundario); }
.etiqueta--positiva, .badge--exito    { background: var(--c-positivo-suave); color: var(--c-positivo); }
.etiqueta--atencion, .badge--alerta   { background: var(--c-atencion-suave); color: var(--c-atencion); }
.etiqueta--critica,  .badge--peligro  { background: var(--c-critico-suave);  color: var(--c-critico); }
/* En curso (apps/panel/tonos.py): el azul de la interfaz, 6.4:1 en claro. */
.etiqueta--info                       { background: var(--c-acento-suave);   color: var(--c-acento); }
.etiqueta--positiva::before, .badge--exito .badge-dot   { background: var(--c-positivo-punto); }
.etiqueta--atencion::before, .badge--alerta .badge-dot  { background: var(--c-atencion-punto); }
.etiqueta--critica::before,  .badge--peligro .badge-dot { background: var(--c-critico-punto); }

/* --- Mensajes ------------------------------------------------------------ */
.aviso {
  padding: var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--c-borde);
  font-size: var(--t-sm);
}

.aviso--error    { background: var(--c-critico-suave);  border-color: transparent; color: var(--c-critico); }
.aviso--exito    { background: var(--c-positivo-suave); border-color: transparent; color: var(--c-positivo); }
.aviso--atencion { background: var(--c-atencion-suave); border-color: transparent; color: var(--c-atencion); }

/* --- Estado vacio --------------------------------------------------------
   Una pantalla vacia sin explicacion se lee como un error. */
.vacio {
  text-align: center;
  padding: var(--s-12) var(--s-5);
  color: var(--c-texto-terciario);
}

.vacio__titulo { font-weight: var(--p-medio); color: var(--c-texto-secundario); margin-bottom: var(--s-2); }

/* --- Ilustraciones -------------------------------------------------------
   Dibujos planos con la paleta de la marca: `partials/ilustracion.html`
   (escenas de los estados vacios) y `panel/partials/dibujo_inmueble.html`
   (tipo de inmueble). Solo tokens: en oscuro las paredes toman el color de la
   tarjeta y el halo el Acuario suave oscuro. Contorno `currentColor` de 1.5.
   En un vacio va centrada y pequena, arriba de la frase: acompana, no compite. */
.ilustracion { display: block; width: 7.5rem; height: 5rem; margin: 0 auto var(--s-3); color: var(--c-texto-secundario); }
.dibujo-inmueble { display: block; width: 7.5rem; height: 5rem; }
.di-halo { fill: var(--c-acento-suave); }
/* Profundidad plana: suelo y sombras en el color del contorno a opacidad baja,
   segundo plano tenue; asi funcionan igual en claro y en oscuro. */
.di-suelo { fill: currentColor; opacity: 0.06; }
.di-sombra { fill: currentColor; opacity: 0.14; }
.di-lejos { fill: currentColor; opacity: 0.08; }
.di-pared, .di-muro, .di-techo, .di-agua, .di-sello, .di-pantalla { stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.di-pared { fill: var(--c-fondo-elevado); }
.di-muro { fill: var(--c-fondo-sutil); }
.di-techo { fill: var(--c-etiqueta-marca); }
.di-vidrio { fill: var(--c-acento-vivo); }
.di-vidrio-2 { fill: var(--c-acento); }
.di-luz, .di-chispa { fill: var(--c-etiqueta-marca); }
.di-puerta, .di-mango { fill: var(--c-barra-marca); }
.di-mango { stroke: currentColor; stroke-width: 1.5; }
.di-copa { fill: var(--c-acento-vivo); opacity: 0.55; }
.di-calle { fill: var(--c-borde); }
.di-pantalla { fill: var(--c-acento-suave); }
.di-agua { fill: var(--c-acento-vivo); }
.di-sello { fill: var(--c-acento-solido); }
.di-qr { fill: currentColor; }
/* Trazos sueltos: todos de 1.5 y con remates redondos. El check y el signo de
   la alerta van a 2 porque son glifos dentro de una forma, no contorno. */
.di-trazo, .di-reja, .di-linea, .di-ola, .di-brillo, .di-sello-marca { fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.di-trazo { stroke: currentColor; }
.di-reja { stroke: var(--c-acento); }
.di-linea { stroke: var(--c-fondo-elevado); stroke-dasharray: 6 5; }
.di-ola { stroke: var(--c-fondo-elevado); }
.di-brillo { stroke: var(--c-acento-solido-texto); opacity: 0.8; }
.di-sello-marca { stroke: var(--c-acento-solido-texto); stroke-width: 2; }
/* Piezas de las escenas: renglones de un documento, el palomeo chico, el ojo
   del QR, el marco de la ventana y el signo de la
   busqueda vacia. */
.di-renglon { fill: currentColor; opacity: 0.25; }
/* Reportes vacio: renglones por llenar y el lapiz. */
.di-vacio { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-dasharray: 3 3; stroke-linecap: round; opacity: 0.6; }
.di-lapiz { fill: var(--c-barra-marca); stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.di-check { fill: none; stroke: var(--c-acento-solido-texto); stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.di-qr-ojo { fill: var(--c-acento-suave); }
.di-marco { fill: none; stroke: var(--c-fondo-elevado); stroke-width: 1; }
.di-pregunta { fill: none; stroke: var(--c-acento-vivo); stroke-width: 2; stroke-linecap: round; }

/* --- QR ------------------------------------------------------------------
   El PNG lo genera el backend (`qr.imagen_png`), no una libreria JS: asi la
   imagen que el residente comparte por WhatsApp es exactamente la misma que
   ve en pantalla, y la web no necesita su propia libreria de QR.           */
.qr {
  display: grid;
  place-items: center;
  gap: var(--s-4);
  padding: var(--s-6);
  /* No crece con la columna: el QR mide lo que mide, y una caja blanca de
     700px alrededor de una imagen de 240 no lo hace mas escaneable. En el
     telefono este tope no llega a notarse. */
  max-width: 22rem;
  margin-inline: auto;
  background: var(--c-fondo-qr);  /* el QR necesita fondo blanco real para escanear */
  border-radius: var(--r-lg);
  border: 1px solid var(--c-borde);
}

/* Alto automatico: el PNG lleva debajo el nombre, el dia y la hora de la
   visita, asi que ya no es cuadrado. */
.qr__imagen { width: 15rem; height: auto; image-rendering: pixelated; }

/* Cuenta regresiva de la ventana corta del QR (seccion 7.3). Se muestra
   porque un codigo que caduca en minutos y no lo dice genera un reclamo. */
.qr__vigencia {
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
  color: var(--c-texto-secundario);
}

.qr__vigencia--por-vencer { color: var(--c-atencion); font-weight: var(--p-medio); }

/* --- HTMX ----------------------------------------------------------------
   Indicador de carga. `htmx-request` lo pone HTMX solo mientras la peticion
   esta en vuelo.                                                           */
.indicador { display: none; }
.htmx-request .indicador { display: inline-flex; }
.htmx-request .indicador-oculta { visibility: hidden; }

/* Utilidad para texto solo de lector de pantalla. */
.solo-lectores {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Utilidades de layout --------------------------------------------------
   Lo minimo para no repetir `style=""` en las plantillas: alineacion, filas
   flex y espaciado suelto que no forma parte de la escala de `.pila*`. Cada
   una vale por un `style=""` que existia antes; nada nuevo se inventa aqui,
   se nombra lo que ya estaba en linea. */
.centrado         { text-align: center; }
.texto-izquierda  { text-align: left; }
.texto-derecha    { text-align: right; }
.sin-margen       { margin: 0; }
.sin-subrayado    { text-decoration: none; }
.flex-1           { flex: 1; }
.fuente-tabular   { font-family: var(--f-tabular); }

.mt-3  { margin-top: var(--s-3); }
.mt-5  { margin-top: var(--s-5); }
.mt-8  { margin-top: var(--s-8); }
.mb-6  { margin-bottom: var(--s-6); }
.pt-8  { padding-top: var(--s-8); }
.pt-16 { padding-top: var(--s-16); }

/* Fila flex simple (icono/monto + boton) y su variante con los extremos
   separados (titulo + etiqueta de estado). `--inicio` alinea arriba en vez de
   al centro, para cuando el segundo elemento es mas alto que una linea. */
.fila {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.fila-entre {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
}

.fila-entre--inicio { align-items: flex-start; }

/* Fila que baja a la linea siguiente cuando no cabe (paginacion, campo +
   boton en un telefono de 320px). */
.fila--ajustable { flex-wrap: wrap; }

/* Fragmento de codigo en linea (`manage.py seed_condominio`), en las pantallas
   de aprovisionamiento (`tenants/`). */
.codigo {
  font-family: var(--f-tabular);
  font-size: var(--t-sm);
  background: var(--c-fondo-sutil);
  padding: 0.1em 0.4em;
  border-radius: var(--r-sm);
}

/* Imagen adjunta a un aviso (CU-25): ancho completo, esquina suave, aire
   arriba y abajo del texto que la rodea. */
.noticia__imagen {
  width: 100%;
  border-radius: var(--r-md);
  margin-block: var(--s-3);
}

/* --- Pantallas de acceso --------------------------------------------------

   Layout propio, sin el encabezado pegajoso ni la barra de navegacion: quien
   todavia no se identifico no tiene a donde navegar, y mostrarle el armazon
   completo detras de un formulario de una linea hace que la pantalla parezca
   cargada a medias.

   El formulario se centra verticalmente. Es lo unico que hay que hacer aqui.  */
.acceso {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-6);
  /* Marca Apto (2026-10-19): el campo de bandas del isotipo, como en la
     landing, reemplaza a la portada velada. En el telefono es una franja
     arriba; desde 64rem, la mitad izquierda de la pantalla. La identidad del
     condominio (logo y nombre) sigue encima de la caja. */
  background: var(--c-fondo-sutil);
  padding: calc(var(--s-8) + 5rem) var(--s-5) var(--s-8);
}

.acceso::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 5rem;
  background: url("../img/apto-logo.afd3d5f30551.svg") center 40% / cover no-repeat;
}

/* El wordmark firma el producto sobre el campo de bandas, en una placa blanca
   para que la mandarina no se pierda sobre el rojo de las bandas. */
.acceso::after {
  content: "";
  position: absolute;
  top: var(--s-4);
  left: var(--s-4);
  width: 5.5rem;
  height: 2.25rem;
  border-radius: var(--r-md);
  background: var(--c-fondo-elevado) url("../img/apto-wordmark.239794ed142a.svg") center / 4rem auto no-repeat;
  box-shadow: var(--sombra-elevada);
}

@media (min-width: 64rem) {
  .acceso { padding: var(--s-8) var(--s-8) var(--s-8) calc(45% + var(--s-8)); }

  .acceso::before {
    position: fixed;
    inset: 0 auto 0 0;
    width: 45%;
    height: auto;
    background-position: center;
  }

  .acceso::after {
    position: fixed;
    top: var(--s-8);
    left: var(--s-8);
    width: 8rem;
    height: 3.25rem;
    background-size: 6rem auto;
  }
}

/* Solo el logo, sin texto al lado, y al mismo ancho que la caja del formulario:
   es lo primero que se ve del producto y compite con nada. El alto maximo
   evita que un logo cuadrado se coma media pantalla en el telefono. */
.acceso__marca {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  width: 100%;
  max-width: 24rem;
}

/* El isotipo va solo, sin el nombre dentro del dibujo, asi que el nombre se
   escribe al lado: un cuadrado suelto no dice a que condominio se esta
   entrando, que es lo unico que esta pantalla tiene que dejar claro.     */
.acceso__nombre {
  font-size: var(--t-lg);
  font-weight: var(--p-semibold);
  letter-spacing: var(--e-titulo);
  text-wrap: balance;
}

.acceso__logo {
  /* Alto fijo y ancho automatico: el SVG de la marca solo trae `viewBox`, y
     con el alto libre el navegador lo estira al ancho disponible. */
  width: auto;
  height: 3rem;
  flex: none;
  max-width: 100%;
  object-fit: contain;
}

/* La caja SI es una tarjeta.

   Antes era un formulario suelto sobre la portada velada, y se leia como una
   pagina a medio cargar: sin un borde que la contenga, los campos flotan
   sobre una foto y nada dice donde empieza y donde termina lo que hay que
   llenar. La tarjeta tambien resuelve el caso de la portada clara, donde el
   velo solo no alcanzaba para sostener el contraste del texto.            */
.acceso__caja {
  width: 100%;
  max-width: 24rem;
  padding: var(--s-8) var(--s-6);
  border: 1px solid var(--c-borde);
  border-radius: var(--r-lg);
  background: var(--c-fondo-elevado);
  box-shadow: var(--sombra-elevada);
}

/* El titulo no se pega al primer campo: es el renglon que dice a donde se
   esta entrando, y con 16px de separacion se lee como la etiqueta del campo
   de arriba en vez de como el titulo de la pantalla.                      */
.acceso__caja > .titulo { margin-bottom: var(--s-2); }
.acceso__caja > .titulo + form { margin-top: var(--s-6); }

.acceso__nota {
  text-align: center;
  text-wrap: balance;
}

.acceso__pie {
  font-size: var(--t-xs);
  color: var(--c-texto-terciario);
  letter-spacing: var(--e-titulo);
}

/* La caja de acceso no se apoya en la tarjeta de la app: es una pantalla
   completa, sin el margen del lienzo, o el campo de bandas deja una franja
   del lienzo al pie. */
body:has(.acceso) { padding: 0; background: var(--c-fondo-sutil); }

/* --- Pie de pagina --------------------------------------------------------
   Comun a las dos superficies (`templates/partials/pie.html`). Copyright a
   nombre del condominio y "Powered by Oasys Corporations" con enlace. Es la
   linea mas discreta de la pantalla: terciario, tamano xs, sin fondo propio.
   En las pantallas de acceso (`pie--acceso`) va centrado y sin borde, porque
   ahi no hay armazon del que colgarse.                                     */
.pie {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-5) var(--s-5) var(--s-6);
  border-top: 1px solid var(--c-borde);
  font-size: var(--t-xs);
  color: var(--c-texto-terciario);
  letter-spacing: var(--e-titulo);
}

.pie__enlace {
  color: var(--c-texto-secundario);
  font-weight: var(--p-medio);
  text-decoration: none;
  transition: color var(--transicion);
}

.pie__enlace:hover { color: var(--c-acento); text-decoration: underline; }

.pie--acceso {
  justify-content: center;
  text-align: center;
  border-top: 0;
  padding: 0;
}

/* --- Modal --------------------------------------------------------------
   <dialog> nativo (`templates/partials/modal_confirmar.html`). Reemplaza a
   `confirm()` y `alert()` del navegador, que no siguen el tema ni la marca y
   en el telefono se ven como un error del sistema.                          */
.modal {
  width: min(100% - var(--s-8), 24rem);
  padding: 0;
  border: 1px solid var(--c-borde);
  border-radius: var(--r-lg);
  background: var(--c-fondo-elevado);
  color: var(--c-texto);
  box-shadow: var(--sombra-elevada);
}

.modal::backdrop {
  background: var(--c-velo-modal);
  backdrop-filter: blur(2px);
}

.modal__cuerpo { display: grid; gap: var(--s-4); padding: var(--s-6); }

.modal__titulo {
  font-size: var(--t-lg);
  font-weight: var(--p-semibold);
  line-height: var(--l-ajustado);
  letter-spacing: var(--e-titulo);
}

.modal__texto { color: var(--c-texto-secundario); }

.modal__acciones {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--s-3);
}

/* Modal de exito (`partials/mensajes.html`): centrado, con la ilustracion
   «al dia» y el titulo en la voz de la marca. Entra con una escala corta;
   con movimiento reducido, sin animacion. */
.modal--exito .modal__cuerpo { justify-items: center; text-align: center; padding-top: var(--s-5); }
.modal--exito .modal__titulo {
  font-family: var(--f-titulo);
  font-stretch: var(--f-titulo-anchura);
  font-size: var(--t-xl);
}
.modal--exito .modal__texto { display: grid; gap: var(--s-1); }
.modal--exito .modal__texto p { margin: 0; }
.modal--exito .modal__acciones { justify-content: center; width: 100%; }
.modal--exito .modal__acciones .boton { min-width: 10rem; }
.modal__ilustracion { width: 8rem; height: auto; }
.modal--exito[open] { animation: modal-entra 180ms ease-out; }
@keyframes modal-entra { from { opacity: 0; transform: scale(0.96); } }
@media (prefers-reduced-motion: reduce) { .modal--exito[open] { animation: none; } }

@media (max-width: 40rem) {
  .modal__acciones .boton { flex: 1; }
}

/* --- Carga --------------------------------------------------------------
   Tres piezas: el girador suelto (`.cargando`), el boton en curso
   (`.boton--cargando`, lo pone apto.js al enviar y evita el doble envio) y
   la barra superior mientras HTMX tiene una peticion en vuelo
   (`body.cargando`). Con `prefers-reduced-motion` tokens.css frena la
   animacion y queda un anillo fijo, que sigue diciendo "en curso".        */
@keyframes girar { to { transform: rotate(360deg); } }
@keyframes barrer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* El body usa la misma clase para la barra superior; nunca debe recibir
   las dimensiones ni la rotacion del indicador individual. */
.cargando:not(body) {
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--r-full);
  animation: girar 700ms linear infinite;
  vertical-align: -0.25em;
}

.boton { --c-girador: var(--c-texto); }
.boton--primario { --c-girador: var(--c-acento-solido-texto); }
.boton--critico { --c-girador: var(--c-critico); }

.boton--cargando {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}

.boton--cargando::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid var(--c-girador);
  border-right-color: transparent;
  border-radius: var(--r-full);
  animation: girar 700ms linear infinite;
}

body.cargando::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 100%;
  height: 3px;
  background: var(--c-acento);
  animation: barrer 1s linear infinite;
}

/* --- Inicio ---------------------------------------------------------------
   En escritorio, dos columnas: a la izquierda lo que se HACE —el saldo y el
   codigo para una visita—, a la derecha lo que se CONSULTA. La proporcion
   1.4/1 le da a la cifra el ancho que su peso pide sin dejar la derecha como
   una tira. En el telefono es la pila de siempre, y como el orden del HTML ya
   es ese, apilarse no cambia nada.                                          */
.inicio {
  display: grid;
  gap: var(--s-8);
  align-items: start;
}

/* ==========================================================================
   Tres rangos

   El portal se uso siempre desde el telefono, y por eso se diseno como una
   columna de 28rem. En un monitor esa misma columna era la pantalla del
   telefono estirada al centro, con el 80 % del espacio vacio. Aqui estan los
   dos escalones que lo arreglan, sin tocar el telefono:

     48rem  la app toma el ancho menos los margenes y la navegacion sube a una
            barra horizontal con icono + texto. El encabezado se va: lo que
            decia viaja dentro de esa barra.
     64rem  la barra se convierte en lateral fija de 15rem —marca, residencia,
            los cinco destinos, Perfil y Salir— y el contenido se ensancha
            hasta 72rem con aire alrededor.

   Todo lo que cambia es la caja. Ni un color, ni un tamano de letra, ni una
   pantalla que exista solo en escritorio: es la misma informacion y las mismas
   plantillas.

   Las reglas que tocan clases compartidas con el panel (`.pie`, `.boton--ancho`)
   van acotadas al armazon del portal: `app.css` lo carga tambien el panel.
   ========================================================================== */

@media (min-width: 48rem) {
  /* La columna se suelta: el ancho lo da la ventana menos los margenes que
     `body` ya pone desde 40rem. */
  .app { max-width: none; }

  /* El encabezado desaparece en cuanto hay lateral: marca y residencia activa
     viajan dentro de ella, y dejarlo seria el mismo logo dos veces en la misma
     pantalla. No se sustituye por una barra de titulo porque cada pantalla ya
     abre con su <h1> —y la de inicio no lleva titulo a proposito, para que el
     saldo sea lo unico con peso.

     Con `:has`, para que las pantallas sin navegacion (condominio suspendido,
     sin condominio) conserven su encabezado y no queden sin marca. */
  .portal:has(.navegacion--lateral) .encabezado { display: none; }

  .navegacion--barra { display: none; }

  /* Barra horizontal arriba: marca, residencia y el pie de la lista en la
     primera linea; los cinco destinos en la segunda, que es donde se leen de
     un vistazo sin competir con nada. */
  .navegacion--lateral {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s-2) var(--s-4);
    padding: var(--s-3) var(--s-5);
    background: var(--c-fondo-sutil);
    border-bottom: 1px solid var(--c-borde);
  }

  .navegacion__marca {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    min-height: var(--alto-toque);
    margin-right: auto;
    color: inherit;
    text-decoration: none;
  }

  /* Solo se acota la caja; el archivo del cliente pone la forma y los colores.
     `object-fit` cubre el caso del logo cuadrado, que con la altura libre se
     comeria la lateral entera. */
  .navegacion__logo {
    width: 100%;
    max-width: 9rem;
    max-height: 2rem;
    height: auto;
    object-fit: contain;
    object-position: left center;
  }

  .navegacion__condominio {
    font-size: var(--t-sm);
    font-weight: var(--p-semibold);
    letter-spacing: var(--e-titulo);
  }

  .navegacion__grupo {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s-1);
  }

  .navegacion__grupo--destinos {
    order: 3;
    width: 100%;
    padding-top: var(--s-2);
    border-top: 1px solid var(--c-borde);
  }

  .navegacion--lateral .navegacion__item {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-md);
    font-size: var(--t-sm);
    color: var(--c-texto-secundario);
  }

  .navegacion--lateral .navegacion__item:hover {
    background: var(--c-acento-suave);
    color: var(--c-texto);
  }

  /* El activo lleva fondo Y peso, no solo color: sobre crema, el texto
     secundario y el normal no se distinguen de un vistazo. Mismo criterio que
     el panel. */
  .navegacion--lateral .navegacion__item[aria-current="page"] {
    background: var(--c-acento-suave);
    color: var(--c-texto);
  }

  .navegacion--lateral .navegacion__icono { width: 1.25rem; height: 1.25rem; }

  /* Salir es un boton dentro de un formulario —cerrar sesion por GET lo
     dispara cualquier precarga—, pero tiene que leerse como un item mas. */
  .navegacion__item--boton {
    width: 100%;
    background: none;
    border: 0;
    cursor: pointer;
    text-align: left;
  }

  /* Contenido: ancho de lectura, centrado en lo que queda de ventana y con
     aire. Sin el tope, una lista de cuatro filas ocupaba 900px y seguir una
     fila de izquierda a derecha pedia el dedo en la pantalla. */
  .contenido {
    width: 100%;
    max-width: 56rem;
    margin-inline: auto;
    padding: var(--s-8) var(--s-6) var(--s-12);
  }

  /* Cada pantalla envuelve lo suyo en un `.pila-lg`: las listas aguantan
     56rem; el texto seguido, los formularios y las pantallas de detalle se
     quedan en el ancho de lectura de los tokens (44rem, ~70 caracteres) con
     `.portal__lectura`. */
  .contenido > .pila-lg,
  .contenido > .portal__avisos {
    max-width: 56rem;
    margin-inline: auto;
  }

  .contenido > .portal__lectura { max-width: var(--ancho-contenido); }

  /* El boton de ancho completo es la respuesta correcta en un telefono de
     375px y ninguna a partir de aqui: a 700px deja de leerse como un boton. */
  .contenido .boton--ancho { width: auto; }

  /* El pie acompana al contenido, no a la ventana. Acotado al portal: el panel
     tiene su propio armazon y el mismo `.pie`. */
  .portal__principal > .pie {
    width: 100%;
    max-width: 56rem;
    margin-inline: auto;
    padding-inline: var(--s-6);
  }
}

@media (min-width: 64rem) {
  /* Pantalla completa, sin margenes ni tarjeta: con una lateral fija el
     armazon ES la ventana. Mismo criterio que el panel. */
  body { padding: 0; background: var(--c-fondo); }

  .app {
    max-width: none;
    min-height: 100vh;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    /* Sin esto la lateral no se puede quedar pegada arriba: un ancestro con
       `overflow: hidden` anula `position: sticky`. */
    overflow: visible;
  }

  .portal { flex-direction: row; align-items: flex-start; }

  /* Lateral fija: se queda quieta mientras el contenido rueda. En una lista
     larga, subir a buscar el menu es el movimiento que mas se repite. */
  .navegacion--lateral {
    flex: none;
    width: 15rem;
    align-self: flex-start;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-6);
    padding: var(--s-6) var(--s-4);
    border-bottom: 0;
    border-right: 1px solid var(--c-borde);
  }

  .navegacion__marca {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s-3);
    margin-right: 0;
  }

  .navegacion__logo { max-width: 11rem; max-height: 3rem; }

  .navegacion__condominio { font-size: var(--t-base); }

  /* La etiqueta no se estira al ancho de la lateral: es una etiqueta, no una
     barra. */
  .navegacion__residencia { align-self: flex-start; }

  .navegacion__grupo {
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-1);
  }

  .navegacion__grupo--destinos {
    order: 0;
    width: auto;
    padding-top: 0;
    border-top: 0;
  }

  /* Perfil y Salir al fondo: son el final de la lista, no un destino mas. */
  .navegacion__grupo--pie {
    margin-top: auto;
    padding-top: var(--s-3);
    border-top: 1px solid var(--c-borde);
  }

  .portal__principal { min-height: 100vh; }

  .contenido {
    max-width: 72rem;
    padding: var(--s-10) var(--s-10) var(--s-16);
  }

  .portal__principal > .pie {
    max-width: 72rem;
    padding-inline: var(--s-10);
  }

  /* La unica pantalla que usa las 72rem completas. El resto se queda en el
     maximo de lectura de arriba. */
  .inicio { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
}

/* Control compartido para mostrar la contraseña en los accesos. */
.campo__contrasena {
  position: relative;
}

.campo__contrasena > input {
  padding-inline-end: 3rem;
}

.campo__ver-contrasena {
  position: absolute;
  inset-inline-end: var(--s-1);
  top: 50%;
  transform: translateY(-50%);
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--c-texto-secundario);
  cursor: pointer;
}

.campo__ver-contrasena[hidden],
.campo__ojo-tachado {
  display: none;
}

.campo__ver-contrasena:hover {
  color: var(--c-acento);
}

.campo__ver-contrasena--visible .campo__ojo-tachado {
  display: block;
}

/* Validación propia, compartida entre panel y portal. */
.campo__error:empty { display: none; }

/* Catálogo de amenidades: tarjetas accesibles con o sin fotografía. */
.amenidades { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr)); gap:1rem; list-style:none; padding:0; }
.amenidad { display:flex; flex-direction:column; padding:0; overflow:hidden; height:100%; text-decoration:none; color:inherit; }
.amenidad__foto { display:block; width:100%; height:11rem; object-fit:cover; }
.amenidad__foto--detalle { height:clamp(11rem,30vw,20rem); border-radius:var(--r-lg); }
.amenidad__portada { display:grid; place-items:center; height:8rem; font-size:3rem; background:var(--c-fondo-sutil); color:var(--c-acento); }
.amenidad__contenido, .amenidad__accion { padding:1rem; }
.amenidad__accion { margin-top:auto; font-weight:600; color:var(--c-acento); }

/* Contacto de la administracion (residentes/partials/contacto_administracion.html):
   llamar y escribir son acciones, van en azul. */
.contacto-administracion a { color: var(--c-acento); }
/* =========================================================================
   Controles de formulario con la marca (2026-10-21)
   Globales: panel y portal, sin tocar cada plantilla. Tres piezas:
   desplegable (`select`), selector de fecha y hora (`js/selector-fecha.js`)
   y zona de archivo (`apto.js`, seccion 5).
   ========================================================================= */

/* --- Desplegable -----------------------------------------------------------
   El 2026-10-21 la mejora con `appearance: base-select` no aplicaba en
   ningun navegador: un marcador de conflicto de merge (`=======`) quedo justo
   encima y el parser de CSS se trago el `@supports` entero como el bloque de
   una regla invalida. Ademas no habia base para los navegadores sin
   base-select (Firefox, Safari): ahi seguia la flecha nativa.

   Capa 1, todos los navegadores: `appearance: none` y un chevron propio
   dibujado con dos degradados del token de texto (un data-URI no puede leer
   tokens y romperia el tema oscuro). La caja (borde, radio, alto, foco) es la
   de los inputs y va con especificidad cero (:where): las reglas de panel.css
   y panel-negocio.css la siguen ajustando como hoy.

   Lo que dibuja la flecha (imagen de fondo y relleno a la derecha) va con mas
   especificidad que esas reglas (`:root body select...`, 0-3-2) porque varias
   usan el atajo `background:` o `padding:` y la borrarian.                 */
:where(select) {
  min-height: var(--alto-toque);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--c-borde-fuerte);
  border-radius: var(--r-md);
  background-color: var(--c-fondo);
  color: var(--c-texto);
  cursor: pointer;
  transition: border-color var(--transicion);
}
:where(select):hover:not(:disabled) { border-color: var(--c-texto-secundario); }
:where(select):focus-visible { border-color: var(--c-acento); outline: 2px solid var(--c-acento); outline-offset: 1px; }
:where(select):disabled { cursor: not-allowed; opacity: 0.6; }
:where(select)[aria-invalid="true"] { border-color: var(--c-critico); }

:root body select:not([multiple]):not([size]) {
  -webkit-appearance: none;
  appearance: none;
  padding-inline-end: calc(var(--s-4) + 1rem);
  background-image:
    linear-gradient(45deg, transparent calc(50% - 0.75px), var(--c-texto-secundario) calc(50% - 0.75px), var(--c-texto-secundario) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(135deg, transparent calc(50% - 0.75px), var(--c-texto-secundario) calc(50% - 0.75px), var(--c-texto-secundario) calc(50% + 0.75px), transparent calc(50% + 0.75px));
  background-position: right calc(var(--s-3) + 0.3rem) center, right var(--s-3) center;
  background-size: 0.3125rem 0.3125rem;
  background-repeat: no-repeat;
}
/* La lista nativa de los navegadores sin base-select toma estos colores
   (Firefox en Windows y Linux); sin esto, en oscuro sale blanca. */
option, optgroup { background-color: var(--c-fondo-elevado); color: var(--c-texto); }

/* Capa 2: donde hay base-select (Chromium 135+) tambien se pinta la lista. */
@supports (appearance: base-select) {
  :root body select:not([multiple]):not([size]),
  ::picker(select) { appearance: base-select; }

  :root body select:not([multiple]):not([size]) {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    padding-inline-end: var(--s-3);
    background-image: none;
  }

  /* Chevron de trazo, del color del texto, que gira al abrir. */
  select::picker-icon {
    content: "";
    flex: none;
    width: 1rem;
    height: 1rem;
    margin-inline-start: auto;
    background: var(--c-texto-secundario);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: rotate var(--transicion);
  }
  select:open::picker-icon { rotate: 180deg; }
  select:open { border-color: var(--c-acento); }

  /* La lista: una superficie elevada del sistema, al menos tan ancha como
     el control y con scroll propio si las opciones no caben. */
  ::picker(select) {
    min-width: anchor-size(width);
    max-height: min(20rem, 60vh);
    overflow-y: auto;
    margin-block: var(--s-1);
    padding: var(--s-1);
    border: 1px solid var(--c-borde);
    border-radius: var(--r-md);
    background: var(--c-fondo-elevado);
    color: var(--c-texto);
    box-shadow: var(--sombra-elevada);
  }

  /* Opciones de 40px como minimo: se tocan con el dedo sin errar. */
  option {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    min-height: 2.5rem;
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-sm);
    background: transparent;
    font-size: var(--t-sm);
    white-space: nowrap;
    cursor: pointer;
  }
  option:hover,
  option:focus-visible {
    outline: 0;
    background: var(--c-fondo-sutil);
  }
  option:checked { font-weight: var(--p-semibold); color: var(--c-acento); background: var(--c-acento-suave); }
  option::checkmark { order: 1; margin-inline-start: auto; color: var(--c-acento); }
  option:disabled { color: var(--c-texto-terciario); cursor: not-allowed; }
  option:disabled:hover { background: transparent; }

  @media (prefers-reduced-motion: reduce) {
    select::picker-icon { transition: none; }
  }
}

/* --- Selector de fecha y hora (js/selector-fecha.js) ----------------------
   El input real sigue en el formulario con su valor ISO; queda oculto a la
   vista (no `display: none`: validacion.js tiene que poder enfocarlo y el
   script pasa ese foco al boton). Sin JavaScript nada de esto aplica.     */
/* !important a proposito: es un "solo lectores" y tiene que ganarle a las
   reglas de inputs del panel (0-5-1), que le daban ancho completo y hacian
   desbordar la pagina en el telefono. */
.selector-fecha__nativo {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  min-width: 0 !important;
  min-height: 0 !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.selector-fecha__boton {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  min-height: var(--alto-toque);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--c-borde-fuerte);
  border-radius: var(--r-md);
  background: var(--c-fondo);
  color: var(--c-texto);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: border-color var(--transicion);
}
.selector-fecha__boton:hover:not(:disabled) { border-color: var(--c-texto-secundario); }
.selector-fecha__boton:focus-visible,
.selector-fecha__boton[aria-expanded="true"] { border-color: var(--c-acento); outline: 2px solid var(--c-acento); outline-offset: 1px; }
.selector-fecha__boton[aria-invalid="true"] { border-color: var(--c-critico); }
.selector-fecha__boton:disabled { cursor: not-allowed; opacity: 0.6; }
.selector-fecha__boton svg { flex: none; width: 1.125rem; height: 1.125rem; color: var(--c-texto-secundario); }
.selector-fecha__texto { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.selector-fecha__texto--vacio { color: var(--c-texto-terciario); }
/* Barra de filtros del panel: control denso de 36px como sus vecinos. */
.cuerpo-panel :is(.filtros, .filtros-negocio) .selector-fecha__boton {
  flex: 1 1 10rem;
  width: auto;
  min-width: 9.5rem;
  min-height: var(--alto-control);
  height: var(--alto-control);
  padding-block: 0;
  padding-inline: var(--s-3);
  font-size: var(--t-sm);
}

.selector-fecha__pop {
  position: fixed;
  inset: auto;
  z-index: 1000;
  margin: 0;
  padding: var(--s-3);
  width: max-content;
  max-width: calc(100vw - 2 * var(--s-4));
  border: 1px solid var(--c-borde);
  border-radius: var(--r-lg);
  background: var(--c-fondo-elevado);
  color: var(--c-texto);
  box-shadow: var(--sombra-elevada);
  font-size: var(--t-sm);
}
.selector-fecha__pop:not(:popover-open):not(.selector-fecha__pop--abierto) { display: none; }
.selector-fecha__pop::backdrop { background: transparent; }
.selector-fecha__cuerpo { display: flex; gap: var(--s-3); align-items: stretch; }

.selector-fecha__cabecera { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); margin-bottom: var(--s-2); }
.selector-fecha__mes { font-weight: var(--p-semibold); font-size: var(--t-base); }
.selector-fecha__nav,
.selector-fecha__pie button {
  display: inline-grid;
  place-items: center;
  min-width: 2.25rem;
  height: 2.25rem;
  padding: 0 var(--s-2);
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--c-texto-secundario);
  font: inherit;
  cursor: pointer;
}
.selector-fecha__nav svg { width: 1.125rem; height: 1.125rem; }
.selector-fecha__nav:hover,
.selector-fecha__pie button:hover { background: var(--c-fondo-sutil); color: var(--c-texto); }
.selector-fecha__nav:focus-visible,
.selector-fecha__pie button:focus-visible { outline: 2px solid var(--c-acento); outline-offset: 1px; }

.selector-fecha__grilla { border-collapse: separate; border-spacing: 2px; }
/* panel.css vuelve `display: block` toda tabla suelta en el telefono. */
:root body table.selector-fecha__grilla.selector-fecha__grilla { display: table; position: static; max-width: none; overflow: visible; }
.selector-fecha__grilla th {
  width: 2.5rem;
  padding-bottom: var(--s-1);
  font-size: var(--t-xs);
  font-weight: var(--p-medio);
  color: var(--c-texto-terciario);
  text-align: center;
}
.selector-fecha__dia {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--r-md);
  text-align: center;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color var(--transicion);
}
.selector-fecha__dia:hover { background: var(--c-fondo-sutil); }
.selector-fecha__dia--fuera { color: var(--c-texto-terciario); }
/* Hoy: anillo azul aunque no este elegido; elegido: relleno azul. */
.selector-fecha__dia[aria-current="date"] { box-shadow: inset 0 0 0 1.5px var(--c-acento); color: var(--c-acento); font-weight: var(--p-semibold); }
.selector-fecha__dia[aria-selected="true"] { background: var(--c-acento-solido); color: var(--c-acento-solido-texto); font-weight: var(--p-semibold); }
.selector-fecha__dia[aria-current="date"][aria-selected="true"] { box-shadow: inset 0 0 0 2px var(--c-acento-solido), inset 0 0 0 3.5px var(--c-acento-solido-texto); }
.selector-fecha__dia[aria-disabled="true"] { color: var(--c-texto-terciario); opacity: 0.45; cursor: not-allowed; background: transparent; }
.selector-fecha__dia:focus-visible,
.selector-fecha__hora:focus-visible { outline: 2px solid var(--c-acento); outline-offset: 1px; }

.selector-fecha__horas {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 6.5rem;
  max-height: 18.5rem;
  overflow-y: auto;
  padding: 3px 3px 3px var(--s-3);
  border-inline-start: 1px solid var(--c-borde);
  scrollbar-width: thin;
}
.selector-fecha__pop--solo-hora .selector-fecha__horas { border: 0; padding-inline-start: 3px; }
.selector-fecha__hora {
  flex: none;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  font-variant-numeric: tabular-nums;
  text-align: center;
  cursor: pointer;
}
.selector-fecha__hora:hover { background: var(--c-fondo-sutil); }
.selector-fecha__hora[aria-selected="true"] { background: var(--c-acento-solido); color: var(--c-acento-solido-texto); font-weight: var(--p-semibold); }
.selector-fecha__hora[aria-disabled="true"] { color: var(--c-texto-terciario); opacity: 0.45; cursor: not-allowed; background: transparent; }

.selector-fecha__pie { display: flex; justify-content: space-between; gap: var(--s-2); margin-top: var(--s-2); padding-top: var(--s-2); border-top: 1px solid var(--c-borde); }
.selector-fecha__pie button { color: var(--c-acento); font-weight: var(--p-medio); }
.selector-fecha__pie button:only-child { margin-inline-start: auto; }

/* Telefono: hoja inferior en vez de globo. Mismo contenido, mas aire. */
.selector-fecha__pop--hoja {
  inset: auto 0 0 0;
  width: 100%;
  max-width: none;
  max-height: 88vh;
  overflow-y: auto;
  padding: var(--s-3) var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom));
  border: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  font-size: var(--t-base);
}
.selector-fecha__pop--hoja::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 0.25rem;
  margin: 0 auto var(--s-3);
  border-radius: var(--r-full);
  background: var(--c-borde-fuerte);
}
.selector-fecha__pop--hoja::backdrop { background: var(--c-velo-modal); }
.selector-fecha__pop--hoja .selector-fecha__cuerpo { flex-direction: column; }
.selector-fecha__pop--hoja .selector-fecha__cuerpo > * { min-width: 0; }
.selector-fecha__pop--hoja .selector-fecha__grilla { width: 100%; }
.selector-fecha__pop--hoja .selector-fecha__grilla th,
.selector-fecha__pop--hoja .selector-fecha__dia { width: auto; height: 2.75rem; }
.selector-fecha__pop--hoja .selector-fecha__horas {
  flex-direction: row;
  width: auto;
  max-height: none;
  overflow-x: auto;
  overflow-y: hidden;
  padding: var(--s-3) 3px var(--s-2);
  border: 0;
  border-top: 1px solid var(--c-borde);
}
.selector-fecha__pop--hoja.selector-fecha__pop--solo-hora .selector-fecha__horas { display: grid; grid-template-columns: repeat(4, 1fr); max-height: 50vh; overflow-y: auto; border: 0; padding-top: 3px; }
.selector-fecha__pop--hoja .selector-fecha__pie button { min-height: var(--alto-toque); }
@media (prefers-reduced-motion: no-preference) {
  .selector-fecha__pop--hoja:popover-open { animation: selector-fecha-subir 180ms cubic-bezier(0.2, 0, 0, 1); }
}
@keyframes selector-fecha-subir { from { transform: translateY(1.5rem); opacity: 0; } }

/* --- Zona de archivo -------------------------------------------------------
   Sin JavaScript: el input nativo con borde punteado y su boton con la marca.
   En el panel, apto.js (seccion 5) lo envuelve en `.zona-soltar` y queda
   estirado e invisible encima de la zona: el clic, el teclado y el soltar un
   archivo los sigue resolviendo el input real, con su etiqueta. El portal
   tiene su `.zona-archivo` propia (portal-producto.css); por eso otro nombre. */
input[type="file"] { max-width: 100%; padding: var(--s-3); border: 1px dashed var(--c-borde); border-radius: var(--r-sm); background: var(--c-fondo-sutil); }
input[type="file"]::file-selector-button { border: 0; border-radius: var(--r-sm); padding: var(--s-2) var(--s-3); margin-right: var(--s-3); background: var(--c-acento-suave); color: var(--c-acento); font: inherit; cursor: pointer; }

.zona-soltar {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  min-height: 5.5rem;
  padding: var(--s-4);
  border: 1.5px dashed var(--c-borde-fuerte);
  border-radius: var(--r-lg);
  background: var(--c-fondo-sutil);
  color: var(--c-texto-secundario);
  transition: border-color var(--transicion), background-color var(--transicion);
}
.zona-soltar:hover { border-color: var(--c-acento); }
.zona-soltar:has(> input:focus-visible) { border-color: var(--c-acento); outline: 2px solid var(--c-acento); outline-offset: 1px; }
.zona-soltar--encima { border-color: var(--c-acento); border-style: solid; background: var(--c-acento-suave); }
.zona-soltar--con-archivo { border-style: solid; border-color: var(--c-borde); background: var(--c-fondo); }
.zona-soltar:has(> input[aria-invalid="true"]) { border-color: var(--c-critico); }
:root body .zona-soltar > input[type="file"] {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
.zona-soltar > input[type="file"]:disabled { cursor: not-allowed; }
.zona-soltar__icono {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--r-md);
  background: var(--c-acento-suave);
  color: var(--c-acento);
}
.zona-soltar__icono svg { width: 1.25rem; height: 1.25rem; }
.zona-soltar__textos { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.zona-soltar__titulo { color: var(--c-texto); font-weight: var(--p-medio); }
.zona-soltar__titulo strong { color: var(--c-acento); font-weight: var(--p-semibold); }
.zona-soltar__detalle { font-size: var(--t-sm); color: var(--c-texto-terciario); }
.zona-soltar__lista { margin: 0; padding: 0; list-style: none; font-size: var(--t-sm); }
.zona-soltar__lista li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--c-texto); }
.zona-soltar__lista span { color: var(--c-texto-terciario); font-variant-numeric: tabular-nums; }
