/* public/assets/css/components/tabla.css
   Componente: tabla de datos generica para listados de entidades
   (usuarios y las que se vayan anadiendo en el futuro). Dos formas
   de uso:
   1) Estatica: el propio PHP pinta <table class="app-tabla">... (ver
      .app-tabla-acciones para la celda de botones).
   2) Dinamica (buscador + paginacion por AJAX, ver
      js/components/tabla-datos.js y css/components/buscador.css): el PHP
      solo pinta un contenedor vacio (data-tabla-datos) y el motor JS
      genera el <table> con estas mismas clases a partir del JSON que
      devuelve el endpoint del listado (columnas/filas/acciones/paginacion).
      Inspirado en TablaV2 de CONSULTORIA (motor de tabla modular ya
      probado en produccion) y alineado con el mismo componente ya en
      produccion en CANAL_DENUNCIAS (cabecera fija tipo tarjeta + columnas
      ordenables + arrastrar-para-desplazar), portado a JS vanilla con la
      paleta propia.

   Mobile-first (06_ESTILO_FRONT.md): la base es la vista de tarjetas
   apiladas (una fila = una tarjeta con pares etiqueta:valor via
   data-label), pensada para movil; a partir de 761px se "revierte" a la
   tabla real con thead/scroll horizontal (.app-tabla-wrap), y a partir de
   1025px el texto crece un paso. Mismo resultado visual en cada ancho que
   la version desktop-first anterior. */

/* .app-tabla-wrap tiene su PROPIO scroll vertical (overflow-y:auto): la
   tabla ocupa el maximo espacio disponible en pantalla sin que la PAGINA
   llegue a hacer scroll (peticion explicita del usuario) - el scroll queda
   siempre acotado a la propia tabla. En una pantalla de listado con
   bodyClass="app-usuarios-listado-page" la altura real la marca la cadena
   flex de mas abajo (app-main -> app-section -> app-panel -> app-tabla-datos
   -> app-tabla-wrap, todos flex:1/min-height:0), que estira la tabla hasta
   llenar el hueco entre cabecera y footer; sin ese bodyClass (listados
   estaticos cortos, p.ej. /aplicaciones-cliente) el max-height de la media
   query de abajo actua como tope razonable de reserva. */
.app-tabla-wrap {
    width: 100%;
    overflow-x: visible;
    overflow-y: auto;
    max-height: none;
    border: 0;
    border-radius: var(--app-radius-md);
}
@media (min-width: 761px) {
    .app-tabla-wrap {
        overflow-x: auto;
        /* calc(.../var(--app-escala-compacta)): compensa el "zoom" compacto de
           base.css para que el tope siga siendo un 65% real de la pantalla
           visible, no del viewport sin escalar. Solo se aplica cuando la
           cadena flex de mas abajo no fija ya una altura propia (ver el
           comentario de arriba). */
        max-height: calc(65vh / var(--app-escala-compacta));
        border: 1px solid var(--app-border-soft);
        /* "Arrastrar para desplazar" (ver tabla-datos.js): cursor de mano
           abierta invitando al gesto, cambia a "agarrando" mientras se
           arrastra de verdad (clase añadida/quitada por JS al superar el
           umbral de movimiento). Solo en desktop -movil ya desplaza con el
           dedo de forma nativa, sin necesitar este gesto-, y solo cuando
           puede haber scroll horizontal real (el propio overflow-x:auto de
           esta media query). */
        cursor: grab;
    }
    .app-tabla-wrap-arrastrando { cursor: grabbing; }
}

/* Pantallas de listado con buscador (p.ej. /usuarios): se activa solo con
   este bodyClass, no afecta a otras pantallas que tambien usan .app-panel
   (Mi perfil, formularios...).

   body solo tiene min-height (base.css): sin un tope real, si el listado
   pesa mas que la pantalla el propio body crece y aparece el scroll de
   PAGINA en vez de quedarse contenido en .app-tabla-wrap (la barra de
   scroll salia pegada al borde derecho del navegador, no dentro de la
   tabla). Altura real fija (compensada con --app-escala-compacta) +
   overflow:hidden, mismo patron ya usado en body.app-chat-home-page/
   body.app-chat-page (ver chat.css) y body.auth-login-page (auth.css): asi
   cualquier desbordamiento se resuelve SIEMPRE dentro de la cadena flex de
   abajo, nunca en el body. */
body.app-usuarios-listado-page {
    height: calc(100vh / var(--app-escala-compacta));
    overflow: hidden;
}
body.app-usuarios-listado-page .app-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    height: 100%;
}
body.app-usuarios-listado-page .app-main > .app-section {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    height: 100%;
}
body.app-usuarios-listado-page .app-main > .app-section > .app-panel {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
/* .app-tabla-datos es el contenedor vacio que pinta el PHP (data-tabla-datos);
   tabla-datos.js rellena su interior con su propio .app-tabla-wrap. Los dos
   tienen que ser flex:1/min-height:0 en cadena para que el scroll quede
   acotado al segundo (el que de verdad tiene la tabla) y no a la pagina. */
body.app-usuarios-listado-page .app-tabla-datos {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
/* Mientras espera la respuesta del listado (ver tabla-datos.js), la tabla
   anterior se atenua en vez de desaparecer de golpe: feedback de que el
   buscador si esta reaccionando, aunque tarde un poco. */
.app-tabla-datos-cargando { opacity: .5; pointer-events: none; transition: opacity .15s ease; }

body.app-usuarios-listado-page .app-tabla-wrap {
    flex: 1;
    min-height: 0;
    max-height: none;
}

.app-tabla {
    display: block;
    width: 100%;
    min-width: 0;
    border-collapse: collapse;
    font-size: var(--app-text-xs);
}
@media (min-width: 761px) {
    .app-tabla { display: revert; min-width: 640px; }
}
@media (min-width: 1025px) {
    .app-tabla { font-size: var(--app-text-sm); }
}

.app-tabla thead { display: none; }
.app-tabla tbody { display: block; }
@media (min-width: 761px) {
    .app-tabla thead { display: revert; }
    .app-tabla tbody { display: revert; }
}

.app-tabla tr {
    display: block;
    width: 100%;
    margin-bottom: var(--app-space-md);
    padding: var(--app-space-sm) var(--app-space-md);
    border: 1px solid var(--app-border-soft);
    border-radius: var(--app-radius-md);
    background: var(--app-surface);
    box-shadow: var(--app-shadow-soft);
}
@media (min-width: 761px) {
    .app-tabla tr { display: revert; margin-bottom: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
}

.app-tabla th,
.app-tabla td {
    display: block;
    width: 100%;
    padding: var(--app-space-sm) 0;
    text-align: left;
    border-bottom: 1px dashed var(--app-border-soft);
    white-space: normal;
    word-break: break-word;
}
@media (min-width: 761px) {
    .app-tabla th,
    .app-tabla td {
        display: revert;
        width: auto;
        padding: var(--app-space-md) var(--app-space-md);
        border-bottom: 1px solid var(--app-border-soft);
        white-space: nowrap;
        word-break: normal;
    }
}

.app-tabla thead th {
    /* Cabecera de columnas pegajosa DENTRO de .app-tabla-wrap (que tiene su
       propio scroll vertical, ver el comentario de arriba): sigue visible
       mientras se recorren las filas. No entra en conflicto con el sticky
       de .app-tabla-cabecera (titulo+buscador, mas abajo en este fichero):
       son dos contextos de scroll distintos, uno el de la pagina (que en la
       practica no llega a moverse en un listado con bodyClass, ver arriba)
       y otro el del propio .app-tabla-wrap. */
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--app-surface);
    color: var(--app-text-soft);
    font-size: var(--app-text-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    box-shadow: 0 1px 0 var(--app-border-soft);
}

/* Cabecera ordenable (ver tabla-datos.js, columna con "ordenable":true):
   mismo tratamiento de cursor/hover que cualquier control clicable de la
   app, para que se lea como interactiva sin necesitar mas explicacion. */
.app-tabla-th-ordenable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.app-tabla-th-ordenable:hover { color: var(--app-primary-dark); }
.app-tabla-orden-flecha { display: inline-block; font-size: var(--app-text-xs); color: var(--app-primary); }
.app-tabla-orden-flecha-neutra { color: var(--app-text-muted); opacity: .6; }

.app-tabla tbody tr:hover {
    background: rgba(var(--app-primary-rgb), 0.04);
}

.app-tabla td:last-child { border-bottom: 0; }
@media (min-width: 761px) {
    .app-tabla tbody tr:last-child td { border-bottom: 0; }
}

/* Doble click en una celda copia su valor (ver tabla-datos.js). */
.app-tabla tbody td.app-tabla-celda-copiada {
    background-color: rgba(var(--app-primary-rgb), 0.18) !important;
    cursor: copy;
}

.app-tabla-enlace {
    color: var(--app-primary-dark);
    font-weight: 700;
    text-decoration: none;
}
.app-tabla-enlace:hover { text-decoration: underline; }

.app-tabla-acciones,
.app-tabla-acciones-celda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--app-space-sm);
    white-space: nowrap;
}
.app-tabla-acciones-celda { padding-left: 0 !important; }
@media (min-width: 761px) {
    .app-tabla-acciones-celda { padding-left: var(--app-space-md) !important; }
}

.app-tabla-vacio {
    padding: var(--app-space-xl) var(--app-space-md);
    text-align: center;
    color: var(--app-text-soft);
}

.app-badge {
    display: inline-flex;
    align-items: center;
    padding: .25rem .65rem;
    border-radius: 999px;
    font-size: var(--app-text-2xs);
    font-weight: 700;
}
.app-badge-activo { background: var(--app-success-soft); color: #047857; }
.app-badge-inactivo { background: var(--app-danger-soft); color: #be123c; }
/* Estado intermedio (p. ej. "sin comprobar") y estado informativo de marca:
   solo tokens de base.css, el texto va en --app-text/--app-primary-dark para
   mantener el contraste sobre el fondo suave. */
.app-badge-aviso { background: var(--app-warning-soft); color: var(--app-text); box-shadow: inset 0 0 0 1px var(--app-warning); }
.app-badge-info { background: var(--app-info-soft); color: var(--app-primary-dark); }

.app-button-sm { min-height: 34px; padding: 0 var(--app-space-md); font-size: var(--app-text-xs); }
.app-button-danger { background: var(--app-danger); box-shadow: none; }
.app-button-danger:hover { background: #c22a3a; box-shadow: none; }
/* .app-button-secondary fija color/border en azul de marca (--app-primary);
   sin esta regla, un boton "secondary danger" quedaba con fondo rojo solido
   pero texto y borde azules, ilegible. Mismo tono #be123c ya usado para
   texto legible sobre --app-danger-soft en esta misma hoja (ver
   .app-badge-inactivo). */
.app-button-secondary.app-button-danger { background: var(--app-danger-soft); color: #be123c; border-color: var(--app-danger); }
.app-button-secondary.app-button-danger:hover { background: var(--app-danger-soft); border-color: #c22a3a; color: #c22a3a; }

/* Titulo + boton "Buscar" de un listado (/usuarios, /aplicaciones-cliente):
   sticky justo debajo de la miga de pan mientras se hace scroll, para poder
   buscar siempre aunque el listado sea largo. Va como hermana de .app-panel
   dentro de .app-section (no dentro del panel, que tiene overflow:hidden
   para el triangulo decorativo, ver panel-form.css), asi el sticky funciona
   sin interferencias. Mismo lenguaje visual que .app-panel: radio, padding
   y borde identicos, para que se lea como "la misma familia de tarjeta" en
   vez de una caja aparte con su propio estilo. Sin margin-bottom propio: el
   espaciado hasta .app-panel ya lo da el "gap" de .app-section (base.css).
   --app-migas-altura la publica header-nav.js (altura real de la barra de
   migas); en paginas sin miga de pan el respaldo "0px" hace que se pegue
   justo debajo de la cabecera fija. Fondo solido (--app-surface): necesario
   para no dejar ver la tabla pasando por debajo una vez pegada. */
.app-tabla-cabecera {
    position: sticky;
    top: calc(var(--app-header-height) + var(--app-migas-altura, 0px));
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--app-space-md);
    flex-wrap: wrap;
    background: var(--app-surface);
    border: 1px solid rgba(var(--app-primary-rgb), 0.14);
    border-radius: var(--app-radius-lg);
    padding: var(--app-space-lg);
    box-shadow: var(--app-shadow-soft);
}

/* Boton "Pantalla completa" (ver tabla-datos.js, data-tabla-pantalla-completa):
   icono cuadrado neutro (outline de marca), para no competir visualmente con
   el boton solido "Buscar"/acciones primarias de .app-tabla-cabecera. Valido
   para cualquier tabla presente o futura que use este componente, no solo
   /usuarios. */
.app-tabla-boton-completa {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 36px;
    min-height: 36px;
    padding: 0;
    border-radius: var(--app-radius-sm);
    border: 1.5px solid var(--app-primary);
    background: var(--app-surface);
    color: var(--app-primary-dark);
    cursor: pointer;
    transition: background .15s ease, transform .15s ease;
}
.app-tabla-boton-completa:hover { background: rgba(var(--app-primary-rgb), 0.08); transform: translateY(-1px); }
.app-tabla-boton-completa-icono-contraer { display: none; }

/* Pantalla completa activa (clase anadida por tabla-datos.js sobre el
   .app-section que envuelve la cabecera+panel de la tabla): la seccion pasa
   a cubrir todo el viewport como una superposicion, para maximizar la tabla
   sin salir de la pantalla actual. La cadena flex interna (panel -> datos ->
   wrap) es la MISMA que ya usan las paginas de listado (ver el bloque
   body.app-usuarios-listado-page de arriba), aqui forzada aunque la pantalla
   no tenga ese bodyClass, para que cualquier tabla (con o sin buscador AJAX)
   pueda entrar en pantalla completa. */
.app-tabla-pantalla-completa-activa {
    position: fixed;
    inset: 0;
    z-index: 150;
    display: flex;
    flex-direction: column;
    gap: var(--app-space-lg);
    padding: var(--app-space-lg);
    margin: 0;
    background: var(--app-bg);
    overflow: hidden;
}
.app-tabla-pantalla-completa-activa .app-tabla-cabecera { position: relative; top: 0; }
.app-tabla-pantalla-completa-activa .app-panel,
.app-tabla-pantalla-completa-activa .app-tabla-datos {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
.app-tabla-pantalla-completa-activa .app-tabla-wrap {
    flex: 1;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
}
.app-tabla-pantalla-completa-activa .app-tabla-boton-completa-icono-expandir { display: none; }
.app-tabla-pantalla-completa-activa .app-tabla-boton-completa-icono-contraer { display: block; }

/* Mientras una tabla esta en pantalla completa, el fondo de la pagina no
   debe poder desplazarse por detras del overlay (belt-and-suspenders: el
   overlay ya cubre todo el viewport, esto evita ademas cualquier "rebote"
   de scroll en movil). */
body.app-tabla-pantalla-completa-bloqueo { overflow: hidden; }

/* Paginador: contador de registros + botones de pagina, generado por
   tabla-datos.js junto con la tabla. */
.app-tabla-paginador {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--app-space-sm);
    margin-top: var(--app-space-md);
    font-size: .84rem;
    color: var(--app-text-soft);
}

.app-tabla-paginador-botones { display: flex; gap: var(--app-space-xs); flex-wrap: wrap; }

.app-tabla-pagina {
    border: 1px solid var(--app-border);
    background: var(--app-surface);
    color: var(--app-primary-dark);
    border-radius: var(--app-radius-sm);
    padding: var(--app-space-xs) var(--app-space-md);
    font-weight: 600;
    font-size: .82rem;
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.app-tabla-pagina:hover { background: rgba(var(--app-primary-rgb), 0.08); }
.app-tabla-pagina.activa {
    background: linear-gradient(rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.22)), var(--app-gradient);
    border-color: transparent;
    color: var(--app-on-primary);
}

.app-tabla-pagina-puntos {
    display: inline-flex;
    align-items: center;
    padding: var(--app-space-xs) var(--app-space-xs);
    color: var(--app-text-muted);
    font-weight: 700;
}

.app-tabla td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: var(--app-space-xs);
    color: var(--app-primary-dark);
    font-weight: 700;
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .02em;
}
.app-tabla-acciones-celda::before { display: none; }
@media (min-width: 761px) {
    .app-tabla td::before { content: none; display: none; }
}

/* Aviso informativo como pie de tabla (ver .alert/.alert-info de base.css):
   separacion de la tabla de arriba, sin margen inferior (es el ultimo
   elemento de la tarjeta). */
.app-tabla-pie-aviso { margin-top: var(--app-space-md); margin-bottom: 0; }
