:root {
    font-family: system-ui, sans-serif;
    color: #1c2733;
    /* Identidad visual ULL: violeta oficial (https://www.ull.es/portal/marca/color/) */
    --bs-primary: #5c068c;
    --bs-primary-rgb: 92, 6, 140;
    --bs-link-color: #5c068c;
    --bs-link-color-rgb: 92, 6, 140;
    --bs-link-hover-color: #430465;
    --bs-link-hover-color-rgb: 67, 4, 101;
}
body { margin: 0; background: #f5f7fa; display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; }
.bg-ull { background-color: #5c068c; }
.app-main { margin: 1.5rem auto; padding: 0 1rem; }
.btn-primary {
    --bs-btn-bg: #5c068c;
    --bs-btn-border-color: #5c068c;
    --bs-btn-hover-bg: #430465;
    --bs-btn-hover-border-color: #430465;
    --bs-btn-active-bg: #430465;
    --bs-btn-active-border-color: #430465;
    --bs-btn-disabled-bg: #5c068c;
    --bs-btn-disabled-border-color: #5c068c;
}
.alert { padding: .75rem 1rem; border-radius: 6px; margin-bottom: 1rem; }
.alert-ok { background: #e2f5e8; border: 1px solid #7bc794; }
.alert-error { background: #fde8e8; border: 1px solid #e8a0a0; }
/* asp-validation-summary siempre renderiza el div; sin esto se ve una caja vacía cuando no hay errores */
.validation-summary-valid { display: none; }
/* El resumen es la respuesta del último envío al servidor: validacion-bootstrap.js lo oculta cuando la
   validación de cliente bloquea el siguiente, porque ya no describe el estado del formulario. Bootstrap
   trae su propia regla [hidden], pero llega por CDN y esto no debe depender de que cargue. */
.validation-summary-errors[hidden] { display: none; }
/* Ya no hay un `.form` propio: el pago del invitado era su último usuario (#1522) y ahora, como los
   formularios de gestión y la verificación pública, es una card de Bootstrap con form-label y
   form-control/form-select. Se borran las tres reglas que definían la caja, las etiquetas y los
   campos; lo único que sobrevive de aquel bloque es el foco, que nunca fue exclusivo suyo. */
/* Foco unificado en violeta ULL: sustituye el outline negro del navegador y el azul por defecto de Bootstrap (.form-control/.form-select) */
.form-control:focus, .form-select:focus {
    border-color: var(--bs-primary);
    outline: 0;
    box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb), .25);
}
button { padding: .5rem 1rem; border: 0; border-radius: 6px; background: #5c068c; color: #fff; cursor: pointer; font: inherit; }
button.secundario { background: #5b6b7b; }
button.bizum { background: #00bdcd; }
/* Botón compacto de acción (icono) para acciones inline / input-group; el texto va en el tooltip.
   En un input-group se estira a la altura del input (align-items: stretch del propio grupo). */
.btn-flat { display: inline-flex; align-items: center; justify-content: center; gap: .25rem; padding: .375rem .6rem; line-height: 1; }
/* Deshabilitado: se atenúa y deja pasar el hover al <span> contenedor para que su tooltip funcione
   (Bootstrap no dispara tooltips sobre elementos disabled). */
.btn-flat:disabled { pointer-events: none; opacity: .55; }
/* Las acciones de un formulario (Cancelar a la izquierda, enviar a la derecha) ya no llevan clase
   propia: viven en un `card-footer d-flex justify-content-between` con botones `.btn` de Bootstrap.
   Antes había un `.form-acciones` con `order`, así que el orden del DOM daba igual; ahora sí importa
   y Cancelar va primero, que además es el orden de tabulación que ya tenían estos formularios. */
table { width: 100%; border-collapse: collapse; background: #fff; }
th, td { text-align: left; padding: .5rem .75rem; border-bottom: 1px solid #e3e8ee; vertical-align: top; }
th { background: #eef2f6; }

/* Tabla que se apila en pantalla estrecha: en pantalla ancha es una tabla normal; por debajo del
   breakpoint cada fila se convierte en un bloque con etiqueta y valor, para no obligar a desplazar en
   horizontal. Los elementos pasan a display:block, de modo que el navegador pierde la semántica de
   tabla: el marcado repone role="table"/"row"/"cell" y las etiquetas son texto real (.etiqueta-movil),
   no contenido generado con ::before, que los lectores de pantalla no exponen de forma fiable.

   El corte es xl (1199.98px), más alto de lo habitual, porque estas tablas viven dentro de
   _LayoutPanel: el menú lateral se lleva unos 250 px, así que el ancho útil es bastante menor que el de
   la ventana y a 992 px cinco columnas no caben con holgura.

   Tiene que coincidir con las utilidades text-xl-* y flex-xl-* de las celdas: si no coincidieran,
   habría un tramo con la tabla normal y el contenido de las celdas colocado como en móvil. */
.etiqueta-movil { display: none; }
@media (max-width: 1199.98px) {
    .tabla-apilable thead { display: none; }
    .tabla-apilable, .tabla-apilable tbody, .tabla-apilable tr, .tabla-apilable td { display: block; width: 100%; }
    .tabla-apilable tr { border: 1px solid #e3e8ee; border-radius: 8px; margin-bottom: .75rem; padding: .25rem .5rem; }
    .tabla-apilable td { border-bottom: 0; padding: .4rem .25rem; }
    .tabla-apilable td + td { border-top: 1px dashed #eef2f6; }
    /* Celda vacía (p. ej. sin acciones disponibles): no deja un bloque suelto sin contenido. */
    .tabla-apilable td:empty { display: none; }
    .tabla-apilable .etiqueta-movil {
        display: block; font-size: .75rem; text-transform: uppercase; letter-spacing: .04em;
        color: #898781; font-weight: 600; margin-bottom: .1rem;
    }
}

/* Desplegable a juego con un botón .btn-sm. Bootstrap no trae variante pequeña de dropdown, así que
   se replican aquí sus métricas (font-size .875rem y el padding compacto del botón). */
.dropdown-menu-sm { --bs-dropdown-min-width: 9rem; --bs-dropdown-padding-y: .25rem; }
.dropdown-menu-sm .dropdown-item { font-size: .875rem; padding: .25rem .75rem; }

/* Reparto de columnas de Recaudación cuando ya se ve como tabla. Sin fijarlo, el navegador da a
   Persona y Operación todo el ancho que piden sus textos largos y estrangula Acciones, que acaba
   partiendo el botón "Comprobante" en dos líneas. */
@media (min-width: 1200px) {
    .tabla-recaudacion th:nth-child(1) { width: 24%; }  /* Persona */
    .tabla-recaudacion th:nth-child(2) { width: 29%; }  /* Operación */
    .tabla-recaudacion th:nth-child(3) { width: 12%; }  /* Importe */
    .tabla-recaudacion th:nth-child(4) { width: 18%; }  /* Estado */
    .tabla-recaudacion th:nth-child(5) { width: 17%; }  /* Acciones */

    /* Mismo motivo en Tasas (#1538): con siete columnas, sin fijar nada Concepto y Propiedad se
       comen el ancho y estrangulan Colaboración, que es la columna que lleva los formularios. */
    .tabla-tasas th:nth-child(1) { width: 18%; }  /* Concepto */
    .tabla-tasas th:nth-child(2) { width: 10%; }  /* Categoría */
    .tabla-tasas th:nth-child(3) { width: 8%; }   /* Pago único */
    .tabla-tasas th:nth-child(4) { width: 10%; }  /* Importe */
    .tabla-tasas th:nth-child(5) { width: 15%; }  /* Vigencia */
    .tabla-tasas th:nth-child(6) { width: 14%; }  /* Propiedad */
    .tabla-tasas th:nth-child(7) { width: 25%; }  /* Colaboración */
}
/* #1553: la barra superior funciona sin JavaScript con <details>/<summary> nativos en vez de los
   data-bs-toggle="collapse"/"dropdown" de Bootstrap, que sin su JS se quedan cerrados para siempre.
   El navegador abre y cierra solo, con rol de accesibilidad y manejo por teclado; aquí solo se ajusta
   lo que Bootstrap no contempla para <details>. */
.navbar-collapse-details > summary,
details.dropdown > summary {
    list-style: none; /* Firefox: quita el marcador nativo del <summary> */
    cursor: pointer;
}
.navbar-collapse-details > summary::-webkit-details-marker,
details.dropdown > summary::-webkit-details-marker {
    display: none; /* Chrome/Safari/Edge: mismo marcador, otra propiedad */
}
/* Menú de usuario: solo falta enseñar el contenido al abrirse, que es justo lo que decide .show en un
   dropdown con JS y aquí decide el propio <details>. */
details.dropdown[open] > .dropdown-menu { display: block; }
/* Menú principal en móvil: .navbar-collapse ya no lleva la clase .collapse de Bootstrap (la que un
   dropdown con JS abre y cierra añadiendo/quitando .show), así que sin esta regla el contenido se
   vería siempre por debajo del punto de corte. */
@media (max-width: 991.98px) {
    .navbar-collapse-details:not([open]) > .navbar-collapse { display: none; }
}
/* Menú principal en escritorio: navbar-expand-lg ya fuerza display:flex!important sobre
   .navbar-collapse a partir de lg, pero no basta con Chrome 131+, que envuelve el contenido de un
   <details> cerrado en un ::details-content interno oculto con content-visibility (no es lo mismo que
   display:none: un display en el hijo no lo atraviesa). Firefox y Safari, que aún no reconocen el
   selector, descartan la regla entera sin efecto -su ocultado sí es un display:none directo sobre el
   hijo, y el !important de navbar-expand-lg ya lo gana-. */
@media (min-width: 992px) {
    .navbar-collapse-details::details-content { content-visibility: visible !important; }
}
/* `.card` es la de Bootstrap, no una propia: aquí solo se ajusta su paleta con las variables del
   framework. Antes había una regla propia (fondo, borde, radio, padding y margin-top) que colisionaba
   con ella: en la portada, que ya usaba `card` + `card-body` de verdad, se sumaba al padding del cuerpo
   y le metía un margen superior que descuadraba la rejilla. Al no declarar ninguna propiedad —solo
   variables— `card-header`/`card-body`/`card-footer` se comportan como en la documentación.

   El padding ya no está en `.card` sino en `card-body`, así que un bloque que use `.card` necesita el
   `card-body` para tener aire; y el `margin-top: 1rem` que traía la regla propia se sustituye por un
   `mt-3` donde hacía falta (la única que dependía de él era la caja de Verificación).

   `--bs-card-inner-border-radius` no hace falta redefinirlo: Bootstrap lo calcula a partir del radio
   que se fije aquí, así que encabezado y pie redondean solos. */
.card {
    --bs-card-border-color: #e3e8ee;
    --bs-card-border-radius: 8px;
    /* 1.5rem horizontal era el padding de las cajas anteriores; también en el encabezado y el pie
       (`cap`), o quedarían desalineados con el cuerpo, que es lo que ocurre con el 1rem por defecto. */
    --bs-card-spacer-x: 1.5rem;
    --bs-card-cap-padding-x: 1.5rem;
    --bs-card-cap-padding-y: .75rem;
}
/* Menú vertical de las áreas de gestión (Administración / Gestión). Extiende `.card` para el fondo, el
   borde y el radio, y pone su propio padding: no tiene `card-body` porque sus hijos son los enlaces. */
.panel-menu { padding: .75rem; position: sticky; top: 1rem; }
.panel-menu-title { font-size: .95rem; text-transform: uppercase; letter-spacing: .04em; color: #5c068c; margin: .25rem .5rem .75rem; }
.panel-menu .nav-link { display: block; color: #1c2733; border-radius: 6px; padding: .5rem .75rem; text-decoration: none; }
.panel-menu .nav-link:hover { background: #f0e9f5; color: #430465; }
.panel-menu .nav-link.active { background: #5c068c; color: #fff; font-weight: 600; }
.panel-menu .nav-link i { margin-right: .5rem; }
/* Dashboard de gestión: KPI-tiles clicables + tarjetas de gráfico */
.kpi { position: relative; background: #fff; border: 1px solid #e3e8ee; border-radius: 8px; padding: 1rem 1.25rem; }
.kpi:hover { border-color: #d3c2e0; }
.kpi-label { color: #5b6b7b; font-size: .85rem; }
.kpi-icono { color: var(--bs-primary); font-size: 1.15rem; }
.kpi-valor { font-size: 1.75rem; font-weight: 700; line-height: 1.15; color: #1c2733; margin-top: .25rem; }
.kpi-sub { font-size: .8rem; color: #8a8f96; margin-top: .1rem; }
.kpi.alerta { border-color: #e8c48a; background: #fff9ef; }
.kpi.alerta .kpi-sub { color: #8a6d1a; font-weight: 600; }
.grafico-card { background: #fff; border: 1px solid #e3e8ee; border-radius: 8px; padding: 1rem 1.25rem; }
.grafico-titulo { font-size: 1rem; font-weight: 600; margin: 0 0 .75rem; }
.grafico-lienzo { position: relative; height: 260px; }
dl { display: grid; grid-template-columns: max-content 1fr; gap: .25rem 1rem; }
dt { font-weight: 600; }
dd { margin: 0; }
/* Estado como badge (Recaudación y Mis pagos, #1537). Las clases van sobre el nombre canónico de
   EstadoPago, nunca sobre la etiqueta visible, que cambia según la perspectiva del rol. Fondos
   oscurecidos respecto al texto para contraste sobre blanco. No hay variante sin .badge: Mis pagos
   era su único consumidor y pasó a badge con esta historia. */
.badge.estado-Pagado { background-color: #1c7c3c; color: #fff; }
.badge.estado-Pendiente { background-color: #7a5f16; color: #fff; }
.badge.estado-Rechazado, .badge.estado-Expirado { background-color: #a33; color: #fff; }
.badge.estado-Devuelto { background-color: #555; color: #fff; }
