/* ══════════════════════════════════════════════════════════════════════════════
   PDRS RESPONSIVE MOBILE CSS
   Archivo centralizado de responsividad para todo el sistema.
   Se carga como ÚLTIMO stylesheet para ganar por cascada sin !important.
   Usa prefijos de especificidad (body, html) donde sea necesario.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────────────────────
   1. TABLAS Card Stack Pattern
   Cada <tr> se convierte en una tarjeta apilada con labels automáticos.
   El script responsive-tables.js inyecta data-label en cada <td>.
   Exclusiones:
     - .legal-table, .print-table (opt-out por clase)
     - descendientes de .container (paginas legales tipo privacy.html):
       `:not(.container *)` matchea "no es descendiente de .container".
       El intento anterior `body :not(.container) table` era buggy porque
       :not(.container) solo pide UN intermedio non-container, y siempre
       hay uno (.section, .doc-content), asi que las tablas legales
       heredaban el card-stack.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    /* --- Romper layout de tabla → bloques normales ---
       Resetea TODAS las propiedades de tabla que módulos CSS
       (finance-fixed-control.css, etc.) pueden tener.
       Sin esto, overflow:hidden, border-collapse:separate,
       border-radius en celdas, etc. rompen el card-stack. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) {
        display: block;
        width: 100%;
        overflow: visible;
        border-collapse: collapse;
        border-spacing: 0;
        border-radius: 0;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody {
        display: block;
        width: 100%;
        background: none;
    }

    /* --- Ocultar headers --- */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) thead {
        display: none;
    }

    /* --- Cada fila = tarjeta --- */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody tr {
        display: block;
        width: 100%;
        margin-bottom: 10px;
        border: 1px solid var(--color-border, #e5e5e5);
        border-radius: 10px;
        padding: 10px 14px;
        background: var(--color-surface, #ffffff);
        transition: none;
    }
    html.dark table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody tr {
        border-color: var(--color-border, #333);
        background: var(--color-surface, #1c1c1c);
    }

    /* --- Cada celda = fila flex con label --- */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td {
        display: flex;
        width: 100%;
        box-sizing: border-box;
        justify-content: space-between;
        align-items: baseline;
        padding: 5px 0;
        border: none;
        border-bottom: 1px solid var(--color-border, #f0f0f0);
        border-radius: 0;
        text-align: right;
        vertical-align: initial;
        font-size: 0.8125rem;
        gap: 8px;
        min-width: 0;
        overflow-wrap: anywhere;
    }
    html.dark table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td {
        border-bottom-color: rgba(255, 255, 255, 0.06);
    }

    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td:last-child {
        border-bottom: none;
    }

    /* Filas de empty-state (colspan > 1 o clase .empty-state-cell):
       en desktop ocupan toda la fila con contenido centrado. En
       card-stack mobile no deben renderizar el patron label-izq /
       valor-der (no hay UN valor concreto: es un mensaje global de
       la tabla). Ademas la fila padre ya trae borde+padding propio;
       la <td> debe simplemente centrar el contenido a full width. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td[colspan]:not([colspan="1"]),
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.empty-state-cell {
        display: block;
        justify-content: center;
        text-align: center;
        padding: 20px 12px;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td[colspan]:not([colspan="1"])::before,
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.empty-state-cell::before {
        display: none;
    }

    /* Wrappers semanticos que emite el renderer:
       - .plan-cell / .status-cell: chip + subtitulo apilados
       - .vigencia-panel: panel gris tipo tooltip
       - .cell-action-btn: boton de accion chico
       En card-stack se alinean flush right sin depender de mx-auto
       heredado del desktop. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .plan-cell,
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .status-cell {
        align-items: flex-end;
        margin-left: auto;
        text-align: right;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .vigencia-panel {
        margin-left: auto;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .cell-action-btn {
        margin-left: auto;
    }

    /* Configuracion de Planes -- el drawer usa max-w-2xl con p-4 en
       el overlay y contenido que en desktop se distribuye en grid 2-col.
       En mobile el overlay lo dejamos fullscreen (generic .fixed.inset-0
       ya lo hace); dentro de las cards el flex row Precio [Exento|Precio]
       + input desborda porque el toggle group tiene ancho fijo y el
       input flex-1 queda comprimido. Ademas el header Tabs (Individual /
       Planes Grupales / Becas y Planes Especiales) tiene `px-6` (24px)
       y `flex` sin wrap -> los pills largos empujan la fila fuera del
       viewport (aunque overflow:hidden del modal recorta, no se ven
       las ultimas tabs). */
    body #plan-config-modal {
        padding: 0;
    }
    body #plan-config-modal .plan-config-drawer {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
    }
    body #plan-config-modal .plan-config-header,
    body #plan-config-modal .plan-config-tabs {
        padding-left: 12px;
        padding-right: 12px;
    }
    body #plan-config-modal .plan-config-tab-content {
        padding-left: 12px;
        padding-right: 12px;
    }
    /* Tabs: scroll horizontal suave sin scrollbar visible. */
    body #plan-config-modal .plan-config-tabs {
        overflow-x: auto;
        scrollbar-width: none;
    }
    body #plan-config-modal .plan-config-tabs::-webkit-scrollbar {
        display: none;
    }
    body #plan-config-modal .plan-config-tab {
        flex-shrink: 0;
        white-space: nowrap;
    }
    /* Cards internas: Precio+Vigencia en 1 col para no comprimir. */
    body #plan-config-modal .plan-card-row {
        grid-template-columns: 1fr;
    }
    /* Fila Precio [Exento|Precio][input] se apila para que el input
       no salga del card. */
    body #plan-config-modal .plan-price-input-row {
        flex-wrap: wrap;
        row-gap: 6px;
    }
    body #plan-config-modal .plan-price-input-row > input.group-plan-price {
        flex: 1 1 100%;
        border-radius: 0.5rem;
        border-left: 1px solid var(--color-border, #e5e5e5);
    }
    /* Vigencia radios: wrap si no caben en un renglon. */
    body #plan-config-modal .plan-vigencia-row {
        flex-wrap: wrap;
        row-gap: 6px;
    }
    /* Footer: los botones Cancelar/Guardar (Tailwind flex justify-end)
       ya son cubiertos por la regla generica de modales; nada extra. */


    /* Categoria/Descripcion: en card-stack el icono decorativo estorba
       y el bloque de texto debe ir flush right para respetar el patron
       LABEL-izq / VALOR-der. Ambas reglas aprovechan las clases
       semanticas emitidas por el renderer (.category-cell*). */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-desc-cell {
        padding-left: 0;
        text-align: right;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-desc-cell .category-cell {
        justify-content: flex-end;
        gap: 0;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-desc-cell .category-cell__icon {
        display: none;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-desc-cell .category-cell__text {
        text-align: right;
        align-items: flex-end;
    }

    /* Finance -- botones internos que en desktop viven centrados con
       `margin: 0 auto`: .actions-menu (three-dots) usada tanto en la
       tabla de Constantes (.fixed-actions-cell) como en la de
       Transacciones (<td style="text-align:center">), y .pin-btn del
       Fijar/Desfijar (.fixed-pin-cell). En el flex del card-stack ese
       margen auto los centra en el row en lugar de pegarlos al borde
       derecho. Fix global (no depende de la clase del td): siempre
       que .actions-menu o .pin-btn esten dentro de un td en mobile,
       forzar margin-left:auto para flush right. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .actions-menu,
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td .pin-btn {
        margin: 0 0 0 auto;
    }

    /* Label generado por data-label. white-space:nowrap para evitar
       que overflow-wrap:anywhere del td parta labels cortos ('PLAN'
       -> 'PLA/N', 'SOCIO' -> 'SOC/IO'). Los labels son cortos por
       diseño -- si algun label largo no cabe, se elipsiza. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td::before {
        content: attr(data-label);
        font-weight: 600;
        font-size: 0.75rem;
        color: var(--color-text-muted, #737373);
        text-align: left;
        flex-shrink: 0;
        max-width: 45%;
        min-width: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        word-break: break-word;
    }

    /* Ocultar filas skeleton */
    body table tbody tr[aria-hidden="true"] {
        display: none;
    }

    /* Overflow wrapper ya no necesita scroll horizontal (card-stack) */
    body .overflow-x-auto,
    body .table-responsive {
        overflow-x: visible;
    }
    /* Tests/splits tables se mantienen como tablas horizontales con scroll */
    body .overflow-x-auto:has(> .tests-table),
    body .overflow-x-auto:has(> .splits-table) {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    /* Compact styling para tests/splits tables en mobile (tablas horizontales) */
    .tests-table th, .tests-table td,
    .splits-table th, .splits-table td {
        padding: 0.375rem 0.5rem;
        white-space: nowrap;
        font-size: 0.75rem;
    }

    /* Los <td> con `style="text-align:center"` inline (heredado del
       desktop) alinean al medio el contenido; en mobile debe ir a la
       derecha para respetar el patron label izq / valor der.
       .fixed-day-cell y .fixed-toggle-cell tambien tienen text-align
       center para centrar los inline-blocks internos en desktop, y
       aca los volvemos a right para el card-stack mobile. */
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td[style*="text-align"],
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-day-cell,
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) tbody td.fixed-toggle-cell {
        text-align: right;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   2. MODALES Fullscreen en móvil
   Todos los patrones de modal del sistema pasan a ocupar toda la pantalla.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* --- Patrón Tailwind: fixed inset-0 ... > div.rounded-2xl --- */
    body .fixed.inset-0 {
        padding: 0;
        align-items: stretch;
    }
    body .fixed.inset-0 > div {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
        margin: 0;
    }
    body .fixed.inset-0 > div > .sticky {
        border-radius: 0;
    }

    /* --- Patrón invoicing: inv-modal-overlay > inv-modal --- */
    body .inv-modal-overlay {
        padding: 0;
        align-items: stretch;
    }
    body .inv-modal-overlay .inv-modal {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
    }
    body .inv-modal-overlay .inv-modal-header {
        border-radius: 0;
    }
    body .inv-modal-overlay .inv-modal-footer {
        border-radius: 0;
    }

    /* --- Patrón invoicing: modal-overlay genérico --- */
    body .modal-overlay {
        padding: 0;
        align-items: stretch;
    }
    body .modal-overlay > div {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
    }

    /* --- Patrón superadmin: sa-modal-overlay > sa-modal --- */
    body .sa-modal-overlay {
        padding: 0;
        align-items: stretch;
    }
    body .sa-modal-overlay .sa-modal {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
        padding: 20px 16px;
    }
    body .sa-modal-overlay .sa-modal.wide {
        max-width: 100%;
    }

    /* --- Patrón settings: msg-modal --- */
    body .msg-modal {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
    }

    /* --- Patrón crew: crew-modal-overlay > crew-modal --- */
    body .crew-modal-overlay {
        padding: 0;
        align-items: stretch;
    }
    body .crew-modal-overlay .crew-modal {
        max-width: 100%;
        width: 100%;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
    }

    /* --- Patrón support: tk-modal-overlay > tk-modal --- */
    body .tk-modal-overlay .tk-modal {
        max-width: 100%;
        width: 100%;
        border-radius: 0;
    }

    /* --- Patrón finance: confirm-overlay > confirm-modal --- */
    body .confirm-overlay .confirm-modal {
        max-width: 100%;
        width: 100%;
        border-radius: 0;
    }

    /* --- Reducir padding interno de modales --- */
    body .fixed.inset-0 form,
    body .fixed.inset-0 .px-7 {
        padding-left: 16px;
        padding-right: 16px;
    }
    body .inv-modal-body {
        padding: 1rem;
    }
    body .inv-modal-header,
    body .inv-modal-footer {
        padding-left: 1rem;
        padding-right: 1rem;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   3. FORMULARIOS Colapso a una columna
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Grids de Tailwind: grid-cols-2 / grid-cols-3 → 1 columna */
    body .grid.grid-cols-2 {
        grid-template-columns: 1fr;
    }
    body .grid.grid-cols-3 {
        grid-template-columns: 1fr;
    }

    /* SuperAdmin: .form-row (grid 2 cols) */
    body .sa-modal .form-row {
        grid-template-columns: 1fr;
    }

    /* Invoicing: accordion content */
    body .inv-accordion-content {
        grid-template-columns: 1fr;
        padding: 0.75rem 1rem;
    }
    body .inv-accordion-content.three-cols {
        grid-template-columns: 1fr;
    }

    /* Invoicing: inner grids */
    body .inv-inner-grid {
        grid-template-columns: 1fr;
    }

    /* Touch targets solo inputs de texto, selects y textareas.
       Se excluyen checkbox, radio, color, range para no distorsionarlos. */
    /* Excepcion touch-target: inputs dentro de .filters-bar quedan a
       la misma altura/fuente que los botones dropdown (h-10 = 40px,
       text-sm = 14px) para no romper la consistencia visual de la
       fila de filtros. La regla generica de 44px/16px se aplica al
       resto de inputs. */
    body .filters-bar input[type="text"],
    body .filters-bar input[type="search"] {
        min-height: 40px;
        height: 40px;
        font-size: 0.875rem;
    }

    body input[type="text"],
    body input[type="email"],
    body input[type="password"],
    body input[type="tel"],
    body input[type="url"],
    body input[type="number"],
    body input[type="search"],
    body input[type="date"],
    body input[type="datetime-local"],
    body input[type="month"],
    body input[type="week"],
    body input[type="time"],
    body input:not([type]),
    body select,
    body textarea {
        min-height: 44px;
        font-size: 16px; /* Previene zoom en iOS */
    }

    /* Botones de accion en modales de confirmacion: en desktop van
       lado a lado (row). En mobile mantenemos row y reparten 50%/50%
       -- apilar full-width se sentia como formulario en vez de dialogo
       de decision rapida. Los form-actions de SuperAdmin (formularios
       largos) si se apilan porque son campos + submit. */
    body .confirm-actions {
        flex-direction: row;
        gap: 8px;
    }
    body .confirm-btn {
        flex: 1 1 0;
        min-width: 0;
    }
    body .sa-modal .form-actions {
        flex-direction: column;
    }
    body .sa-modal .form-actions button {
        width: 100%;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   4. PESTAÑAS Scroll horizontal con snap
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    /* --- SuperAdmin tabs --- */
    body .sa-tabs {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        padding: 0 12px;
        gap: 0;
    }
    body .sa-tabs::-webkit-scrollbar {
        display: none;
    }
    body .sa-tab {
        padding: 10px 14px;
        font-size: 13px;
        scroll-snap-align: start;
        flex-shrink: 0;
    }

    /* --- Invoicing main tabs --- */
    body .inv-main-tab {
        padding-bottom: 10px;
        font-size: 0.8rem;
        flex-shrink: 0;
    }

    /* --- Page tabs (finance/attendance/members-profile). Todos usan
       nav[aria-label="Tabs"] con Tailwind gap-6 (24px) + icon text-xl
       (20px) + text-base (16px). En 375px viewport 3 tabs con icono +
       gap grande NO caben; el ultimo se corta ("Analíticas e Info",
       "Notificaciones WA/TG", etc). Fix: compactar. */
    body nav[aria-label="Tabs"] {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        gap: 14px;
        padding-bottom: 1px;
    }
    body nav[aria-label="Tabs"]::-webkit-scrollbar {
        display: none;
    }
    body nav[aria-label="Tabs"] button {
        flex-shrink: 0;
        scroll-snap-align: start;
        font-size: 0.75rem;
        white-space: nowrap;
        padding-left: 2px;
        padding-right: 2px;
    }
    /* Iconos mas chicos para dar aire al label sin ocuparlo. */
    body nav[aria-label="Tabs"] button .material-symbols-outlined {
        font-size: 16px;
    }

    /* --- Members profile: detail tabs --- */
    body #profile-detail-tabs,
    body [id*="profile-tabs"],
    body .profile-tabs {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
    }
    body #profile-detail-tabs::-webkit-scrollbar,
    body [id*="profile-tabs"]::-webkit-scrollbar,
    body .profile-tabs::-webkit-scrollbar {
        display: none;
    }

    /* --- Crew manager / Inventory modal tabs --- */
    body #crew-modal-tabs,
    body #inv-modal-tabs {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    body #crew-modal-tabs::-webkit-scrollbar,
    body #inv-modal-tabs::-webkit-scrollbar {
        display: none;
    }

    /* --- Modal tab buttons --- */
    body .modal-tab-btn {
        padding: 8px 10px;
        font-size: 0.75rem;
        gap: 4px;
    }

    /* --- Plan config tabs --- */
    body .plan-config-tab {
        padding: 8px 12px;
        font-size: 0.75rem;
    }

    /* --- Exoneration mode tabs --- */
    body .exo-mode-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }
    body .exo-mode-tabs::-webkit-scrollbar {
        display: none;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   5. FILTROS Stack vertical
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Finance: filters-bar */
    body .filters-bar {
        grid-template-columns: 1fr;
        padding: 12px;
        gap: 10px;
    }

    body .filter-group {
        min-width: 0;
    }

    /* Invoicing: filters container -- 2 columnas en movil */
    body .inv-filters {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
        align-items: end;
        padding: 0.75rem 1rem;
    }
    body .inv-filters > * {
        width: auto;
        min-width: 0;
    }
    body .inv-filters .inv-filter-search {
        grid-column: 1 / -1;
    }
    /* Boton "limpiar" (x) igualado a la altura de un input, no estirado */
    body .inv-filter-reset-btn {
        width: auto;
        height: calc(0.475rem * 2 + 0.8125rem * 1.5 + 2px);
        margin-bottom: 0;
        align-self: end;
    }

    /* Invoicing: botones de header (Nuevo Documento, Eventos, Backup, Config) en 2 columnas */
    body .inv-header-actions {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 0.5rem;
        width: 100%;
    }
    body .inv-header-actions > .inv-btn {
        width: 100%;
        min-width: 0;
        justify-content: center;
    }

    /* Invoicing: header en columna en movil para que las tabs usen todo el ancho */
    body .inv-section-header {
        flex-direction: column;
        align-items: stretch;
        padding: 0.875rem 1rem;
        gap: 0.75rem;
    }

    /* Invoicing: status tabs -- una fila, tabs equidistribuidos ocupando todo el ancho */
    body .inv-status-tabs {
        display: flex;
        gap: 0.25rem;
        width: 100%;
    }
    body .inv-status-tabs .inv-tab {
        flex: 1 1 0;
        min-width: 0;
        padding: 0.55rem 0.5rem;
        font-size: 0.8125rem;
        text-align: center;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   6. ACTION BARS Botones específicos
   Selectores concretos por ID/clase, NO Tailwind utilities genéricos.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Members profile: header buttons → full width */
    body #btn-add-member,
    body #btn-export-members,
    body #btn-import-members {
        flex: 1 1 calc(50% - 4px);
        justify-content: center;
    }

    /* Fixed control header container (finance) */
    body #fixed-control-header-container {
        flex-direction: column;
        align-items: flex-start;
        gap: 8px;
    }

    /* Invoicing: fila de items apilada por responsive-tables.js.
       Semanticamente es un form, no una tabla de datos, entonces los labels
       de todas las celdas deben alinearse. Solucion sin numeros magicos:
       - <tr> es un grid de 2 columnas: [label: ancho del mas largo] [input: resto]
       - cada <td> hace subgrid + span completo -> hereda las 2 columnas del padre
       - el ::before (label) va a col 1, el input/select a col 2
       El navegador calcula automaticamente el ancho de col 1 como el max-content
       de todos los labels en esa <tr>. Si cambia un label, todo se realinea solo. */
    body #items-tbody tr {
        display: grid;
        grid-template-columns: minmax(6rem, max-content) 1fr;
        column-gap: 12px;
    }
    body #items-tbody td {
        display: grid;
        grid-template-columns: subgrid;
        grid-column: 1 / -1;
        align-items: center;
    }
    body #items-tbody td::before {
        grid-column: 1;
        max-width: none;
        width: auto;
    }
    body #items-tbody td input,
    body #items-tbody td select {
        grid-column: 2;
        width: 100%;
        max-width: none;
        min-width: 0;
        box-sizing: border-box;
    }

    /* Invoicing: modal footer -- grid 2 columnas para aprovechar el ancho */
    body .inv-modal-footer {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 0.5rem;
    }
    body .inv-modal-footer button,
    body .inv-modal-footer a {
        width: 100%;
        min-width: 0;
        justify-content: center;
        text-align: center;
    }
    /* Spacer heredado (flex:1 para layout desktop) no aporta en grid movil */
    body .inv-modal-footer .inv-modal-footer-spacer {
        display: none;
    }
    /* Orden pedido: fila 1 = Datos de Prueba + Generar, fila 2 = Cancelar + Vista Previa */
    body .inv-modal-footer #btn-fill-test-de { order: 1; }
    body .inv-modal-footer #btn-generate-de  { order: 2; }
    body .inv-modal-footer .close-inv-modal  { order: 3; }
    body .inv-modal-footer #btn-preview-xml  { order: 4; }
    /* Modal de configuracion: Guardar (primary) a la derecha, Cancelar a la izquierda */
    body .inv-modal-footer #btn-save-config  { order: 5; }
    /* En prod (sin boton Datos de Prueba), Generar ocupa la fila entera */
    body[data-sifen-env="prod"] .inv-modal-footer #btn-generate-de {
        grid-column: 1 / -1;
    }
    /* Modal de eventos: Datos de Prueba ocupa fila completa arriba,
       Generar XML + Cancelar quedan lado a lado abajo */
    body .inv-modal-footer #btn-fill-test-event {
        grid-column: 1 / -1;
    }

    /* Comunicaciones -> Envios: layout desktop es grid 3fr/2fr (lista de
       facturas | panel de envio). En movil el grid inline pisa el ancho de
       ambos paneles y el derecho se recorta. Marker semantico + stack. */
    body .comms-envios-grid,
    body .comms-config-grid {
        grid-template-columns: 1fr;
        gap: 1rem;
    }
    /* Grid generico 2col de forms de facturacion + SMTP form especifico
       (usa selector propio, no clase generica, por eso lo listamos aparte). */
    body .inv-form-2col,
    body #form-smtp-config {
        grid-template-columns: 1fr;
        gap: 0.75rem;
    }

    /* Fila de acciones al pie de forms: flex-wrap deja que los botones vayan
       lado a lado si caben, o se apilen si no. `flex: 1 1 auto` + `min-width:
       max-content` respeta el ancho intrinseco del label (white-space:nowrap)
       -> nada se corta. Si al pasar a nueva linea sobra espacio, el boton
       crece a ancho completo. Predecible en todos los browsers. */
    body .inv-form-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }
    body .inv-form-actions > .inv-btn {
        flex: 1 1 auto;
        min-width: max-content;
        justify-content: center;
    }

    /* Modifier: en el grid SMTP+Plantillas, en movil las Plantillas van
       arriba (mas usadas para el usuario final). Reorden solo scoped a ese
       grid especifico, no toca .comms-config-grid del otro row (WA+Email). */
    body .comms-config-grid--templates-first > :nth-child(1) { order: 2; }
    body .comms-config-grid--templates-first > :nth-child(2) { order: 1; }

    /* Barra de tabs principales (SIFEN/Portal/Comunicaciones) -- en movil los
       3 tabs no entran en el ancho, "Comunicaciones" se corta y no habia forma
       de scrollear. Habilitamos scroll horizontal con snap y ocultamos el
       scrollbar (patron estandar para pestañas horizontales moviles). */
    body .inv-main-tabs-bar {
        overflow-x: auto;
        flex-wrap: nowrap;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        scroll-snap-type: x proximity;
    }
    body .inv-main-tabs-bar::-webkit-scrollbar {
        display: none;
    }
    body .inv-main-tabs-bar > .inv-main-tab {
        flex: 0 0 auto;
        scroll-snap-align: start;
    }

    /* Portal de Socios: encabezado de seccion con titulo + descripcion + boton
       principal. En desktop es una fila (space-between); en movil el boton
       comprimia la descripcion a 3 lineas mal cortadas. Stack vertical con
       el boton a ancho completo abajo. Marker semantico para no depender de
       heuristicas de inline flex. */
    body .inv-section-title-row {
        flex-direction: column;
        align-items: stretch;
        gap: 0.75rem;
    }
    body .inv-section-title-row > .inv-btn {
        width: 100%;
        justify-content: center;
    }

    /* Backup modal (pdrs-backup-modal): el render usa inline flex con min-width
       130-160px por select y align-items:end. En ancho movil los selects no
       entran en una fila y quedan flotando raro (labels a la derecha). En
       movil forzamos stack vertical, campos a 100% del ancho y selects que
       llenan su cell. Todo scoped al custom element para no tocar otros modales. */
    body pdrs-backup-modal [data-range-group] {
        flex-direction: column;
        align-items: stretch;
    }
    body pdrs-backup-modal [data-range-group] > div,
    body pdrs-backup-modal [data-range-field] {
        width: 100%;
    }
    body pdrs-backup-modal [data-range-field="month"],
    body pdrs-backup-modal [data-range-field="custom"] {
        flex-direction: row;
    }
    body pdrs-backup-modal [data-range-field="month"] > div,
    body pdrs-backup-modal [data-range-field="custom"] > div {
        flex: 1 1 0;
        min-width: 0;
    }
    body pdrs-backup-modal [data-range-group] select,
    body pdrs-backup-modal [data-range-group] input {
        width: 100%;
        min-width: 0;
        box-sizing: border-box;
    }

    /* SA modal footer */
    body .sa-modal .form-actions {
        flex-direction: column;
    }
    body .sa-modal .form-actions button {
        width: 100%;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   7. KPI CARDS / STATS GRIDS
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 480px) {

    /* Invoicing KPI grid -- 5 tarjetas: 2x2 + la ultima ocupa fila entera */
    body .inv-kpi-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 0.625rem;
    }
    body .inv-kpi-grid > .inv-kpi-card:last-child {
        grid-column: 1 / -1;
    }

    /* SuperAdmin KPIs */
    body .sa-kpis {
        grid-template-columns: repeat(2, 1fr);
        gap: 0.75rem;
    }
}

@media (max-width: 360px) {
    body .sa-kpis {
        grid-template-columns: 1fr;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   8. LAYOUT GENERAL Padding, typography, spacing
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    /* Secciones card */
    body section.rounded-xl {
        border-radius: 8px;
    }

    /* Settings layout */
    body .settings-layout {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 480px) {

    /* Badges y chips más compactos */
    body .plan-card-pill {
        font-size: 0.625rem;
        padding: 1px 6px;
    }

    body .plan-count-badge {
        min-width: 16px;
        height: 16px;
        font-size: 0.625rem;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   9. ATTENDANCE Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .attendance-stats {
        grid-template-columns: repeat(2, 1fr);
    }

    body .attendance-controls {
        flex-direction: column;
    }
}

@media (max-width: 480px) {
    body .attendance-stats {
        grid-template-columns: 1fr;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   10. CREW MANAGER Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .crew-grid {
        grid-template-columns: 1fr;
    }

    body .crew-form-grid {
        grid-template-columns: 1fr;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   11. LABORATORY Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .lab-stats {
        grid-template-columns: repeat(2, 1fr);
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   12. INVENTORY Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .inv-form-grid {
        grid-template-columns: 1fr;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   13. FACTURAS PORTAL Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .portal-filters {
        flex-direction: column;
    }
    body .portal-filters > * {
        width: 100%;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   14. SCROLLBAR & TOUCH IMPROVEMENTS
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    /* Scrollbar más delgado en móvil */
    * {
        scrollbar-width: thin;
    }
    ::-webkit-scrollbar {
        width: 4px;
        height: 4px;
    }

    /* Mejorar touch */
    body {
        touch-action: manipulation;
    }

    /* Prevenir text selection accidental en elementos interactivos */
    body button,
    body .sa-tab,
    body .inv-main-tab,
    body nav[aria-label="Tabs"] button {
        -webkit-user-select: none;
        user-select: none;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   15. SUPPORT Ajustes específicos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .ticket-grid {
        grid-template-columns: 1fr;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   16. DROPDOWNS Selectores específicos por ID
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* User dropdown en navbar: mantener la posicion natural (absolute
       top-full right-0) del componente. El bottom-sheet forzado
       causaba que al abrirlo aparezca abajo de la pantalla en vez de
       debajo del avatar del usuario -- confuso porque parecia que
       nada pasaba al hacer tap. Aca solo cap max-height por si el menu
       queda cerca del borde inferior del viewport. */
    body #pdrs-user-menu {
        max-height: calc(100vh - 120px);
        overflow-y: auto;
    }

    /* Bell dropdown: el default es position:absolute anclado a
       .bell-wrapper (chico y NO pegado al borde derecho del viewport --
       el avatar del usuario esta a su derecha). Con right:8px absolute
       el panel salia desplazado a la izquierda del boton y solapaba con
       otros elementos, por lo que al tapear la campana "parecia que no
       pasaba nada". Fix de raiz: escapar a coordenadas de viewport con
       position:fixed anclado al ancho completo debajo del header sticky.
       El arrow decorativo se oculta porque ya no puede apuntar al icono. */
    body .bell-dropdown {
        position: fixed;
        top: 64px;
        right: 8px;
        left: auto;
        width: min(340px, calc(100vw - 16px));
        max-width: none;
        max-height: 60vh;
    }
    /* .bell-list ya tiene flex:1 + overflow-y:auto, asi que con la
       altura del panel acotada el scroll interno queda automatico. */
    body .bell-dropdown::before {
        display: none;
    }

    /* Attendance filter dropdowns */
    body #filter-shift-dropdown .absolute,
    body #filter-category-dropdown .absolute {
        min-width: 100%;
    }

    /* Lab filter dropdown */
    body #lab-filter-category-dropdown .absolute {
        min-width: 100%;
    }

    /* Finance family/becado dropdowns */
    body #family-form-owner-dropdown,
    body #family-form-member-dropdown,
    body #becado-member-dropdown {
        max-height: 50vh;
        overflow-y: auto;
    }

    /* Inventory responsible dropdown */
    body #inv-f-responsible-dropdown {
        max-height: 50vh;
        overflow-y: auto;
    }

    /* Members-profile: fila de filtros (Categoria / Estado / Huellas).
       El markup usa flex-nowrap + overflow-x-auto, que en mobile deja
       las 3 pills apretadas contra el borde izquierdo con scroll
       horizontal, cortando "Huellas" fuera de vista. Ademas los botones
       tienen width fijo (w-[165px], w-[135px]) que no se adapta.
       Fix: convertir la fila a grid 3-col uniforme y liberar los
       botones para que ocupen el 100% de su celda. */
    body .members-filter-row {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
        overflow-x: visible;
    }
    body .members-filter-row > div {
        min-width: 0;
        flex-shrink: 1;
        width: 100%;
    }
    /* El wrapper .filters-clear-wrap (label invisible + boton chico)
       existe para conservar altura y simetria en desktop. En mobile
       el boton pasa a full-width de la celda del grid para ocupar la
       otra mitad de la fila igual que un filtro comun. */
    body .members-filter-row > .filters-clear-wrap > button {
        width: 100%;
    }
    body #filter-category-btn,
    body #filter-status-btn,
    body #filter-biometric-btn,
    body #filter-rfid-btn,
    body #filter-finance-btn {
        width: 100%;
    }
    /* Los menus desplegables de esos filtros usan position:absolute con
       w-full (relativo al wrapper). Al comprimir el boton a 100% de
       columna, el menu se queda tambien angosto; min-width asegura que
       las opciones ("Todos los estados", "Master D", etc) no se corten. */
    body #filter-category-menu,
    body #filter-status-menu,
    body #filter-biometric-menu,
    body #filter-rfid-menu,
    body #filter-finance-menu {
        min-width: 180px;
    }

    /* Finance -- .filters-bar de Transacciones (Mes/Año/Tipo/Frecuencia/
       Categoria/Factura + boton clear + toggle "Ocultar Cuota Social").
       El markup es `flex flex-wrap gap-3` con cada filtro `.flex-1
       min-w-[120px]`. En mobile eso deja anchos irregulares: si el
       ultimo filtro sobra el row, wrap desalineado, y el toggle
       "Ocultar Cuota Social" o el boton "close" toman todo el ancho
       sobrante y quedan enormes. Fix: grid 2-col uniforme; boton
       clear y toggle final ocupan la fila completa al final. */
    body .filters-bar {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
        align-items: end;
    }
    body .filters-bar > div,
    body .filters-bar > button {
        min-width: 0;
        flex: unset;
        width: 100%;
    }
    /* Botones sueltos (clear filtros) van a nivel de row junto a un
       div `<label>+<input/button>`; sin altura explicita quedan a
       distinta altura y desalineados verticalmente. Anclar a 40px
       para que compartan linea de base con los campos vecinos. */
    body .filters-bar > button {
        height: 40px;
    }
    body .filters-bar > #btn-clear-filters,
    body .filters-bar > div:has(#filter-hide-dues) {
        grid-column: 1 / -1;
    }

    /* Wrapper del boton "limpiar filtros" en la vista Cuota Social/Pagos.
       En desktop es un chip de 40px (w-10); en mobile ocupa toda su
       celda del grid para pararse a la altura de los demas filtros. */
    body .filters-bar > .filters-clear-wrap {
        width: 100%;
        justify-content: stretch;
    }
    body .filters-bar > .filters-clear-wrap > button {
        width: 100%;
        height: 40px;
    }

    /* Pill tabs de Cuota Social (Pagos/Estado/Grupales/Becas): grid
       2x2 uniforme para no depender del wrap flex + flex-1 que en
       desktop reparte segun min-content del texto. */
    body .cuota-pill-group {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    body .cuota-pill-group > button {
        flex: unset;
        min-width: 0;
        width: 100%;
        height: 40px;
        padding-top: 0;
        padding-bottom: 0;
        align-self: stretch;
    }
    body .cuota-pill-group > button > span:last-child {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* KPI cards de Cuota/Pagos (Total Recaudado, Plan Individual, Planes
       Grupales, Becados, Socios en Deuda). El HTML usa grid-cols-2
       sm:grid-cols-5 para mostrar 2-col en mobile, pero la regla global
       de la seccion 3 (.grid.grid-cols-2 -> 1fr) lo devuelve a 1-col.
       Fix: reafirmar 2-col para esta grid especifica (identificada por
       la clase .kpi-cards-cuota) y hacer que la 5a card (impar) ocupe
       la fila completa para que no quede sola desbalanceada. */
    body .kpi-cards-cuota.grid.grid-cols-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    body .kpi-cards-cuota > .kpi-card--wide {
        grid-column: 1 / -1;
    }
    /* En 2-col mobile cada card queda muy angosto. Icono w-11 + gap +
       padding + texto uppercase con tracking-wider hace que labels
       largos ("TOTAL RECAUDADO", "SOCIOS EN DEUDA") wrappeen en 3
       lineas y el valor "Gs. 300.000" tambien wrappee.
       Fix: ocultar icono decorativo (redundante con el label) y dar
       todo el ancho al texto, con label chico single-line-friendly y
       valor sin wrap. Cards ganan altura consistente entre si. */
    body .kpi-cards-cuota > div.kpi-card {
        padding: 12px;
        gap: 0;
        min-width: 0;
    }
    body .kpi-cards-cuota > div.kpi-card > div:first-child {
        display: none;
    }
    body .kpi-cards-cuota > div.kpi-card > div:last-child {
        min-width: 0;
        flex: 1 1 auto;
        width: 100%;
    }
    body .kpi-cards-cuota > div.kpi-card > div:last-child > p:first-child {
        letter-spacing: 0;
        font-size: 0.7rem;
        white-space: normal;
    }
    body .kpi-cards-cuota > div.kpi-card > div:last-child > p:last-child {
        font-size: 1.125rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Estado de Socios -- la tabla usa `min-w-[950px]` (Tailwind
       arbitraria, NO compilada por lo cual no aporta) junto con
       `table-layout:fixed` inline y un colgroup con widths %. En
       card-stack mobile display:block cancela el layout de tabla,
       pero table-layout:fixed sigue en efecto y las columnas del
       colgroup empujan el ancho renderizado a >viewport, tapando
       las cards KPI a la derecha ("PLAN" wrappea a "PLA / N" en el
       card angosto resultante). Fix: neutralizar table-layout y
       colgroup en mobile, y anclar el wrapper .overflow-x-auto a
       100% del contenedor. */
    body .overflow-x-auto {
        max-width: 100%;
        min-width: 0;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) {
        table-layout: auto;
        min-width: 0;
    }
    body table:not(.legal-table):not(.print-table):not(.tests-table):not(.splits-table):not(.md-table):not(.container *) colgroup {
        display: none;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   18. CHARTS / CANVAS Contenedores responsivos
   Chart.js necesita height explícito, solo limitamos overflow.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    /* Chart containers limitar altura pero NO forzar height: auto en canvas.
       overflow: visible para no cortar leyendas/tooltips de Chart.js que
       renderiza fuera del canvas. max-height subido a 360 para leyendas. */
    body .chart-container,
    body .chart-card {
        min-height: 200px;
        max-height: 360px;
        overflow: visible;
    }

    /* Evitar overflow horizontal de canvas */
    body .chart-container canvas,
    body .chart-card canvas {
        max-width: 100%;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   19. IFRAMES Responsivos
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    body iframe {
        width: 100%;
        max-width: 100%;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   20. PRIVACY / LEGAL Tablas con scroll horizontal (no card-stack)
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Privacy/legal: tablas mantienen su layout nativo y ganan scroll
       horizontal si desbordan. El card-stack ya no las alcanza -- ver
       exclusion `:not(.container *)` en la seccion 1. */
    body .container table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        font-size: 0.8rem;
    }

    /* Privacy: tabs */
    body .container .tabs {
        overflow-x: auto;
        scrollbar-width: none;
    }
    body .container .tabs::-webkit-scrollbar {
        display: none;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   21. MEMBER DETAIL Grid de datos del perfil completo
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .md-hero__inner {
        flex-direction: column;
        text-align: center;
    }

    body .md-section__body .grid {
        grid-template-columns: 1fr;
    }

    body .md-back-btn,
    body .md-print-btn {
        font-size: 0.8125rem;
        padding: 8px 12px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   22. MAX-WIDTH CONTAINERS Padding lateral
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .max-w-7xl,
    body .max-w-6xl,
    body .max-w-5xl,
    body .max-w-4xl {
        padding-left: 12px;
        padding-right: 12px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   23. SLIDERS / RANGE INPUTS
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body input[type="range"] {
        width: 100%;
        min-height: 44px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   24. COLLAPSIBLES Padding reducido
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    body .collapse-content {
        padding: 10px 12px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   25. SETTINGS / BACKUP Flex containers con selects inline
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Backup range groups: flex → column */
    body [data-range-group] {
        flex-direction: column;
        align-items: stretch;
    }

    /* Wipe inputs (settings, backup modal). min-width:0 anula los
       inline min-width:XXXpx que rompian el layout en 375px. */
    body .wipe-input {
        width: 100%;
        min-width: 0;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   26. SUPERADMIN Filtros de logs/historial
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* SA filter rows (email logs, payment history, pending) */
    body .sa-filter-row,
    body .sa-filters {
        flex-direction: column;
        gap: 8px;
    }
    body .sa-filter-row > *,
    body .sa-filters > * {
        width: 100%;
    }

    /* SA inputs with inline min-width. min-width:0 anula el inline
       min-width:220px de los filters que forzaba scroll horizontal. */
    body .sa-input,
    body .sa-select {
        width: 100%;
        min-width: 0;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   27. PAGINATION Flex-wrap para muchos botones
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Inventory pagination */
    body #inv-pagination {
        flex-wrap: wrap;
        justify-content: center;
        gap: 4px;
    }

    /* Support / superadmin pagination */
    body #tickets-pagination {
        flex-wrap: wrap;
        gap: 6px;
    }
    body .tk-page-btn {
        min-width: 32px;
        min-height: 32px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   28. ATTENDANCE IFRAME Altura inicial para mobile
   El JS adjustIframeHeight() la recalcula después de cargar,
   pero el 950px inline causa salto visual.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {

    body #notificationsFrame {
        height: auto;
        min-height: 400px;
    }

    /* Invoicing: contenedor scrolleable con max-height 400px + card-stack
       interno causa doble scroll anidado. En mobile card-stack ya no
       necesita el clip vertical -- soltar max-height. */
    body .inv-doc-table-scroll {
        max-height: none;
        overflow-y: visible;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   29. TOUCH TARGETS Minimo tap area para checkboxes y radios en punteros
   gruesos (touch). WCAG recomienda 44x44; se usa 24 como fisico + margin
   inflado para expandir el area efectiva sin desalinear layouts que
   asumen tamano nativo (~13-16px).
   ───────────────────────────────────────────────────────────────────────────── */

@media (pointer: coarse) {
    /* Excluir inputs visualmente ocultos usados como patron
       toggle/switch (opacity:0 + width:0 con UI real en el ::before
       del slider). Forzarles min-size 20x20 rompe la geometria
       absoluta del switch y deforma el interruptor.

       Patrones custom del proyecto: .toggle (attendance-notifications),
       .switch (finance-fixed-control), .shift-dest-check. La deteccion
       es por wrapper porque el input en si no lleva clase.

       Regla positiva mas robusta: solo aplicar min-size cuando el input
       NO tiene un ancestro con clases de switch/toggle conocidas. Con
       :where() para no bumpear la especificidad. */
    input[type="checkbox"]:not([hidden]):not(.shift-dest-check),
    input[type="radio"] {
        min-width: 20px;
        min-height: 20px;
        cursor: pointer;
    }
    /* Overwrite: inputs dentro de wrappers .toggle / .switch vuelven
       a 0x0 (patron visually-hidden). */
    :where(.toggle, .switch) > input[type="checkbox"] {
        min-width: 0;
        min-height: 0;
    }

    /* Labels envolventes agregan padding tap-area sin cambiar visual.
       Excluir wrappers de switches custom porque tienen su propia
       geometria (width:38px height:20px) y el min-height:32px + flex
       les cambia el eje y desalinea el thumb.
       display:flex (block-level), NO inline-flex: si es inline-flex los
       labels fluyen en la misma linea en cualquier form donde el markup
       espera stacking vertical (ej. modal de exportar inventario). */
    label:has(> input[type="checkbox"]):not(.toggle):not(.switch),
    label:has(> input[type="radio"]) {
        min-height: 32px;
        display: flex;
        align-items: center;
        gap: 8px;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   30. NAVBAR Mobile - evitar overflow horizontal de la fila de acciones.

   Causa raíz: en <pdrs-navbar> la barra derecha usa
   `flex items-center gap-4` con hasta 5-6 hijos (menu, theme, bell,
   settings, divider, user avatar). En viewports ≤ 640px la suma de
   40px por icono + gap-4 (16px) + logo (~108px) + px-6 del header
   (48px) supera 375-412px de ancho de pantalla, empujando el botón
   de usuario ("admin") fuera del eje del contenido y forzando scroll
   horizontal a nivel de <html> a pesar de `overflow-x:hidden` en body.

   Fix de raíz: compactar la fila de acciones en mobile - reducir
   gap y padding de iconos, ocultar el divisor decorativo, y quitar
   el margen del divisor cuando queda oculto - para que quepa dentro
   del viewport sin necesidad de scroll ni de recortes.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

    /* Padding lateral del header más chico que el px-6 (24px) por defecto. */
    body pdrs-navbar header[role="banner"] {
        padding-left: 12px;
        padding-right: 12px;
    }

    /* Ocultar el icono de settings del navbar top: ya vive dentro del
       burger menu como link "Configuración", asi que en mobile es
       redundante y roba espacio horizontal a los demas (bell, avatar).
       El theme toggle se mantiene visible porque no vive en el burger. */
    body pdrs-navbar header[role="banner"] a[title="Configuración"] {
        display: none;
    }

    /* Fila de acciones (contenedor directo con gap-4) → gap chico. */
    body pdrs-navbar header[role="banner"] > div > div.flex.items-center.gap-4 {
        gap: 4px;
    }

    /* Iconos: reducir padding p-2 (8px) → 4px en mobile. */
    body pdrs-navbar header[role="banner"] #pdrs-mobile-menu-btn,
    body pdrs-navbar header[role="banner"] #theme-toggle,
    body pdrs-navbar header[role="banner"] #pdrs-bell-btn,
    body pdrs-navbar header[role="banner"] a[title="Configuración"] {
        padding: 4px;
    }

    /* Divisor vertical decorativo entre acciones y user menu:
       en mobile no aporta información y su margen (mx-2 = 16px)
       come espacio crítico. Ocultarlo por completo. */
    body pdrs-navbar header[role="banner"] .h-8.w-\[1px\] {
        display: none;
    }

    /* Botón del usuario: eliminar padding del btn-tight para que
       el avatar quede pegado al borde derecho sin comer ancho extra. */
    body pdrs-navbar header[role="banner"] #pdrs-user-btn {
        padding-left: 0;
        padding-right: 0;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   31. HTML Root - clamp final anti-scroll horizontal.

   body ya tiene overflow-x:hidden, pero elementos sticky y algunos
   browsers móviles (Brave/Chromium con URL bar dinámica) pueden
   propagar el ancho de contenido al elemento raíz cuando body está
   dentro de un layout flex-col con min-h-screen. Fijar overflow-x
   en <html> cierra ese camino de propagación sin afectar el scroll
   vertical normal.
   ───────────────────────────────────────────────────────────────────────────── */

html {
    overflow-x: clip;
}


/* ─────────────────────────────────────────────────────────────────────────────
   32b. FABS - no tapar contenido en mobile.

   Causa raiz: los botones flotantes (.speed-dial, .ai-chat-fab, back-to-top)
   viven en position:fixed a bottom:2rem right:2rem y en mobile cubren la
   columna derecha de las cards ("Efectivo" -> "Efec", "Gs. 300.000" ->
   "Gs. 300.0", "Plan Individual" -> "Plan Individ", el 3-dots de
   "Acciones", los links del footer, etc). padding-bottom en body solo
   deja espacio DESPUES del ultimo contenido; el FAB sigue tapando el
   contenido a mitad del scroll.

   Fix de raiz: reservar un gutter permanente en el eje X del contenedor
   <main> para que ninguna card comparta columna con el FAB. El FAB queda
   flotando en su gutter propio, siempre sobre fondo. Ademas el body sigue
   con padding-bottom para el pie de pagina y el FAB se encoge. */
@media (max-width: 640px) {
    /* En paginas con FAB agregamos padding-bottom para que el usuario
       pueda scrollear el ultimo contenido por ENCIMA del FAB. NO
       tocar padding-right de <main>: eso robaba ancho a las tablas y
       cards (screenshots del usuario mostraban 64px de espacio muerto
       a la derecha). Aceptamos que el FAB se superponga levemente al
       contenido mientras haya scroll disponible; con padding-bottom
       suficiente el usuario siempre puede desplazar cualquier valor
       importante fuera de la zona del FAB. */
    body:has(.speed-dial, .ai-chat-fab) {
        padding-bottom: 96px;
        scroll-padding-bottom: 96px;
    }
    .speed-dial,
    body:has(#speed-dial) .ai-chat-fab {
        right: 8px;
        bottom: 12px;
    }
    body:has(#speed-dial) .speed-dial {
        bottom: 76px;
    }
    .fab {
        width: 2.75rem;
        height: 2.75rem;
    }
}


/* ─────────────────────────────────────────────────────────────────────────────
   32f. Page header actions - grid uniforme en mobile.

   Causa raiz: los headers de finance / attendance / members-profile usan
   `flex flex-wrap gap-3` con botones que tienen labels de distinto largo
   ("Generar Reportes" vs "Generar/Importar Backups" vs "Configuración
   Muelle"). flex-wrap acomoda por intrinsic-width, produciendo filas
   desparejas: a veces 1 boton solo full-width, a veces 2 chicos + 1
   grande en otra fila. Se ve desordenado.

   Fix: sobre <=640px la .page-header-actions pasa a `display: grid`
   con 2 columnas iguales y gap uniforme. Si el numero total de botones
   es impar, el ultimo hijo ocupa las 2 columnas para no dejar una
   celda hueca (grid-column: 1 / -1 via :nth-child(odd):last-child). */
@media (max-width: 640px) {
    body .page-header-actions {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        width: 100%;
    }
    body .page-header-actions > * {
        min-width: 0;
        justify-content: center;
        width: auto;
    }
    /* Los wrappers de dropdown (.relative) contienen un <button> con
       ancho fijo `w-[170px]` / `w-[150px]` / `w-[190px]` en Tailwind.
       En mobile hay que dejarlos estirar a full-width dentro de la celda
       del grid para que la distribucion sea uniforme. */
    body .page-header-actions > .relative,
    body .page-header-actions > .relative > button,
    body .page-header-actions > button,
    body .page-header-actions > label.btn {
        width: 100%;
        max-width: 100%;
    }
    /* Cantidad impar de hijos: el ultimo se estira a full-width. */
    body .page-header-actions > *:nth-child(odd):last-child {
        grid-column: 1 / -1;
    }
    /* Marker semantico: el control 'limpiar filtros' siempre abarca
       las 2 columnas para que quede como un CTA reset dedicado, sin
       depender de la paridad total de items. */
    body .page-header-actions > .filters-clear {
        grid-column: 1 / -1;
    }
    /* En viewports muy angostos (< ~360px) o si un boton solo no cabe
       en 1 columna (label muy largo), stack vertical seguro. */
}
@media (max-width: 380px) {
    body .page-header-actions {
        grid-template-columns: 1fr;
    }
    body .page-header-actions > *:nth-child(odd):last-child {
        grid-column: auto;
    }
}


/* Nota: pill tabs de cuotas (Pagos/Estado/Grupales/Becas) ahora
   viven en el HTML como `flex flex-wrap md:flex-nowrap` con
   `flex-1 md:flex-none` en cada boton -- el 2x2 en mobile lo hace
   el layout nativo, sin override CSS. */


/* Attendance stats KPI (6 tarjetas): Total Socios, Turno Mañana, Turno
   Tarde, En el salón, En el agua, Fuera del club. El HTML usa
   `grid-cols-3 md:grid-cols-3 lg:grid-cols-6` pensando que Tailwind
   ya cubre mobile, PERO en este archivo existe una regla global
   (seccion 3, ~L266) `body .grid.grid-cols-3 { grid-template-columns: 1fr }`
   que colapsa cualquier grid-cols-3 a una sola columna en mobile.
   Resultado: 6 tarjetas apiladas verticalmente, ocupan toda la pantalla.
   Fix: reafirmar 3 columnas para este grid especifico (identificado por
   la combinacion md:grid-cols-3 lg:grid-cols-6 propia de la stats-grid),
   con padding/fuente/icono compactados para caber en 375px. */
@media (max-width: 640px) {
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 8px;
    }
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 > div {
        padding: 8px;
        height: auto;
        min-height: 92px;
        gap: 6px;
    }
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 p.whitespace-nowrap {
        white-space: normal;
        font-size: 0.6rem;
        line-height: 1.15;
    }
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 p.text-2xl {
        font-size: 1.25rem;
    }
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 .material-symbols-outlined {
        font-size: 14px;
    }
    body .grid.grid-cols-3.md\:grid-cols-3.lg\:grid-cols-6 p.text-xs.mt-1 {
        font-size: 0.55rem;
        line-height: 1.1;
    }
}

/* ─────────────────────────────────────────────────────────────────────────────
   32c. MODALES -- markers semanticos para filas de acciones.

   Contrato:
   - .modal-actions : fila de botones de accion (Cancelar/Guardar/etc)
     en cualquier modal. Emitida en el markup del modal.
   - .modal-inline-add : fila input + boton para el patron 'agregar'
     (categorias personalizadas, biometric id, etc).

   Antes esto vivia con selectores de Tailwind-utility como identificador
   (body [id$='-modal'] .flex.gap-2), fragil y sobre-amplio (capturaba
   cualquier .flex.gap-2 dentro de un modal, sea o no una fila de
   acciones). Ahora la intencion vive en el markup y el CSS solo aplica
   layout mobile a esos markers.

   Desktop se deja como default -- los contenedores mantienen sus clases
   Tailwind (flex, justify-end, gap-2) y renderizan como siempre. */
@media (max-width: 640px) {
    body .modal-actions {
        flex-wrap: wrap;
        justify-content: stretch;
        gap: 8px;
    }
    /* flex-basis calc(50% - 4px) fuerza máx. 2 columnas en mobile:
       - 1-2 botones → fila única, se estiran al 50%.
       - 3 botones → 2+1 (el tercero ocupa fila completa).
       - 4 botones → 2×2.
       Evita el bug previo (min-width:0 + flex:1 1 0) que dejaba todos
       los botones en una sola fila apretándose hasta cortar el texto. */
    body .modal-actions > .btn,
    body .modal-actions > button {
        flex: 1 1 calc(50% - 4px);
        min-width: 0;
        justify-content: center;
    }

    body .modal-inline-add {
        flex-wrap: wrap;
        gap: 8px;
    }
    body .modal-inline-add > input,
    body .modal-inline-add > .btn,
    body .modal-inline-add > button {
        flex: 1 1 0;
        min-width: 0;
    }
    body .modal-inline-add > .btn,
    body .modal-inline-add > button {
        justify-content: center;
    }
}

/* ─────────────────────────────────────────────────────────────────────────────
   32. ATTENDANCE Turnos - card-stack en mobile.

   Causa raiz: en attendance.html las filas de "Turno Mañana / Tarde" son
   CSS grid con columnas fijas 50px + 2fr + 4x1fr. En 375px de viewport
   las 6 columnas colapsan: los headers "NOMBRE / ID HUELLA / ENTRADA /
   SALIDA / TIEMPO" se solapan y wrappean; el nombre y la categoria del
   socio se apilan en 3 lineas; los timestamps quedan cortados o
   invisibles porque el .list-headers de arriba tampoco cabe.

   Fix de raiz: transformar cada .member-row en tarjeta apilada
   (avatar en esquina, nombre a la derecha, datos como filas con
   label izquierda via ::before). Ocultar el .list-headers, que en
   ese modo no aporta info.
   ───────────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
    body .list-headers { display: none; }

    body .member-row {
        display: grid;
        grid-template-columns: 44px 1fr;
        grid-template-areas:
            "avatar name"
            "cells  cells";
        gap: 8px 12px;
        padding: 12px 14px;
        align-items: start;
    }
    body .member-row .mr-avatar { grid-area: avatar; margin: 0; }
    body .member-row .mr-name   { grid-area: name; min-width: 0; }
    body .member-row .mr-name > .flex { row-gap: 4px; }

    /* Contenedor virtual de los 4 mr-cell: no existe en el DOM.
       Los seleccionamos por data-role y los promovemos al mismo grid
       item (cells) con display:contents no funciona en grid; usamos
       en su lugar column-span. */
    body .member-row .mr-cell {
        grid-column: 1 / -1;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        padding: 6px 0;
        border-top: 1px solid var(--color-border, rgba(255,255,255,0.06));
        text-align: right;
        min-width: 0;
    }
    body .member-row .mr-cell::before {
        content: attr(data-label);
        font-size: 0.7rem;
        font-weight: 700;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--color-text-muted, #a1a1aa);
        text-align: left;
        white-space: nowrap;
    }
    /* Mobile: replica DIRECTA de las 2 columnas del desktop (Entrada
       / Salida) dentro de la tarjeta. Ocultar las celdas separadas
       del card-stack (que no muestran todos los detalles) y mostrar
       el bloque .mr-sessions que contiene los MISMOS stacks pre-
       renderizados, con todos los iconos, colores y badges intactos. */
    body .member-row .mr-cell[data-role="entry"],
    body .member-row .mr-cell[data-role="exit"] {
        display: none;
    }
    body .member-row .mr-sessions {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 4px 12px;
        padding: 8px 0 0;
        border-top: 1px solid var(--color-border, rgba(255,255,255,0.06));
        min-width: 0;
    }
    body .member-row .mr-sessions-col {
        min-width: 0;
        display: flex;
        flex-direction: column;
        gap: 2px;
    }
    body .member-row .mr-sessions-col-label {
        font-size: 0.7rem;
        font-weight: 700;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--color-text-muted, #a1a1aa);
        text-align: center;
        padding-bottom: 2px;
        border-bottom: 1px solid var(--color-border, rgba(255,255,255,0.06));
    }
    body .member-row .mr-sessions-stack {
        display: flex;
        flex-direction: column;
        gap: 1px;
        min-width: 0;
    }
    /* Los sub-divs pre-renderizados usan grid grid-cols-3 con icono
       en cell 1 (justify-self:end), tiempo en cell 2 y cell 3 vacia.
       En la columna angosta del mobile (~140px) las 3 cells de ~47px
       separaban visualmente al icono del tiempo (icono en cell 1 -
       right side, tiempo en cell 2 - middle) haciendo que parezcan en
       lineas distintas. Override: forzar layout FLEX (icon + tiempo
       en la misma linea, centrados) para el patron water. */
    body .member-row .mr-sessions-stack > div {
        font-size: 0.72rem;
        padding: 1px 0;
        min-width: 0;
        overflow: visible;
    }
    /* Los sub-divs pre-renderizados de water segments ya usan
       flex items-center justify-center gap-1.5 desde el renderer,
       asi que no hay override de layout aca. Solo iconos mas chicos. */
    body .member-row .mr-sessions-stack > div * {
        min-width: 0;
    }
    body .member-row .mr-sessions-stack .material-symbols-outlined {
        font-size: 12px;
    }
}

/* Desktop: ocultar el bloque .mr-sessions mobile-only. Las columnas
   originales Entrada/Salida del member-row se mantienen. */
@media (min-width: 641px) {
    .member-row .mr-sessions {
        display: none;
    }
}
