/* ============================================================
   HUF — Componente: Table (.hd-table) — HVL §6.7
   ------------------------------------------------------------
   Reemplaza .table de Bootstrap. La herramienta central del producto:
   fila de 52px, encabezado sticky de 44px, primera columna fija (es la
   columna de identidad del registro), cero zebra, cero líneas
   verticales salvo el borde de la columna fija.
   Ejemplos de uso → docs/hednora-ui-framework-guide.md §Table.
   ============================================================ */

.hd-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    color: var(--hd-theme-text);
}

.hd-table th,
.hd-table td {
    height: var(--hd-size-row);
    padding: 0 var(--hd-space-4);
    text-align: left;
}

.hd-table thead th {
    height: var(--hd-size-header);
    font-size: var(--hd-text-micro);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--hd-theme-text-muted);
    border-bottom: 1px solid var(--hd-color-border);
    position: sticky;
    top: 0;
    background: var(--hd-color-bg-secondary, var(--hd-theme-surface));
    white-space: nowrap;
}

.hd-table tbody tr {
    transition: background var(--hd-motion-standard) var(--hd-ease);
}

/* El separador de fila (HVL §6.7: "solo horizontales, 1px") va en las CELDAS,
   no en la fila. La tabla usa `border-collapse: separate` y en ese modelo el
   navegador ignora el borde de `<tr>` (CSS 2.1 §17.6.1): declarado sobre `tr`
   —como estuvo hasta 2026-09-18— no se pintó nunca, en ninguna tabla.

   Medido con sonda de píxel sobre esta misma hoja: con el borde en `tr`, las 8
   scanlines alrededor del límite entre dos filas son idénticas; moviéndolo a
   `td` aparece la línea. Lo caro no era la estética: en las filas que crecen
   —los chips del modal "Opciones de menú"— sin separador no se ve dónde termina
   un registro, y sus valores se leen como los del grupo siguiente. */
.hd-table tbody > tr > td {
    border-bottom: 1px solid var(--hd-color-border);
}

.hd-table tbody > tr:last-child > td {
    border-bottom: none;
}

/* Filas que crecen: celda anclada arriba en vez de al centro.
   `vertical-align: middle` —el valor que resuelve el navegador por defecto—
   centra cada celda contra la más alta de la fila. Medido en el modal de
   Opciones de menú: en el grupo de 6 chips, "Múltiple / 6 de 6 / 20" queda
   **33px por debajo** del nombre del grupo, a la altura del cuarto chip. El
   ancla de lectura de una fila es su primera línea; acá se anclan todas ahí. */
.hd-table--align-top tbody > tr > td {
    vertical-align: top;
    padding-top: var(--hd-space-3);
    padding-bottom: var(--hd-space-3);
}

.hd-table--hover tbody tr:hover {
    --hd-table-tinte: rgba(148, 163, 184, 0.06);
    background: var(--hd-table-tinte);
}

/* Fila seleccionada: línea de energía de 2px en el borde izquierdo +
   fondo de acento al 8% (HVL §6.7). */
.hd-table tbody tr.is-selected,
.hd-table tbody tr[aria-selected="true"] {
    --hd-table-tinte: rgba(var(--hd-theme-accent-rgb), 0.08);
    background: var(--hd-table-tinte);
    box-shadow: inset 2px 0 0 var(--hd-theme-accent);
}

/* Primera columna fija — columna de identidad del registro (HVL §7.2 zona C:
   "no se mueve"). La clase la pone el motor (js/huf/hd-table.js) cuando la
   tabla desborda de verdad, no la vista: hasta 2026-09-19 el atributo
   `sticky-first` de <hd-table> no lo escribía NINGUNA pantalla, así que estas
   reglas nunca corrieron y sus defectos quedaron latentes. Los dos que
   aparecieron al encenderla: */
.hd-table--sticky-first th:first-child,
.hd-table--sticky-first td:first-child {
    position: sticky;
    left: 0;
    border-right: 1px solid var(--hd-color-border);
}

/* 1. El fondo tiene que ser OPACO. `background: inherit` tomaba el de la fila,
      que es `transparent` salvo en las tres filas de estado —y esas son una
      tinta al 6%—: medido, `rgba(0, 0, 0, 0)`. Al deslizar, las demás columnas
      pasaban POR DEBAJO del nombre del producto y se leían encima de él.
      La tinta de estado se pinta como CAPA sobre el opaco (`background-image`)
      y no en su lugar, porque si no la primera celda de una fila en alerta
      quedaría de otro color que el resto de su fila. `--hd-table-tinte` la
      hereda la celda desde su `<tr>`, para no repetir los valores. */
.hd-table--sticky-first td:first-child {
    background-color: var(--hd-theme-surface);
    background-image: linear-gradient(var(--hd-table-tinte, transparent) 0 100%);
}

/* 2. El encabezado ya es sticky por arriba. Donde las dos fijaciones se cruzan
      —la celda de la esquina— gana la que esté más alta; sin z-index gana la
      última del DOM, que es la celda del cuerpo, y el encabezado desaparecía
      debajo de ella al deslizar. */
.hd-table--sticky-first td:first-child { z-index: 1; }
.hd-table--sticky-first thead th { z-index: 2; }
.hd-table--sticky-first thead th:first-child { z-index: 3; }

/* Primera columna = objeto principal, siempre clicable (HVL §7.2 zona C,
   §11.1 #23). Sin esto, cada fila necesitaría un botón propio solo para
   "ver detalle" — la afordancia vive en la columna que ya identifica el
   registro. */
.hd-table--row-link tbody td:first-child {
    cursor: pointer;
}

.hd-table--row-link tbody tr:hover td:first-child {
    color: var(--hd-theme-accent-text);
    text-decoration: underline;
}

/* Estados de fila. Tinte muy tenue: la fila sigue siendo legible y el
   estado ya está escrito en su badge — el color acompaña, nunca informa
   solo (HVL §5.1, el color no es el único portador de significado).

     is-alert → exige atención ya (inventario agotado, pago rechazado)
     is-warn  → se acerca al umbral (stock bajo, suscripción por vencer)
     is-done  → esta fila ya está resuelta, no vuelvas sobre ella

   `is-done` es el estado de las tablas en las que el operador avanza
   fila por fila y necesita ver de un vistazo cuánto le falta (toma de
   inventario). Es distinto de `is-selected`: seleccionada significa
   "sobre esta voy a actuar", resuelta significa "de esta ya no". Por eso
   no lleva línea de energía — la energía es para lo activo (HVL §4.2).

   OJO: hasta 2026-08-05 estas tres reglas iban precedidas de un
   `.hd-table` suelto que las convertía en selectores descendientes
   (`.hd-table .hd-table tbody tr.is-alert`), así que no se aplicaban en
   ninguna tabla de primer nivel.

   La tinta va además en `--hd-table-tinte` y no solo en `background`: la
   primera columna fija necesita pintarla COMO CAPA sobre un fondo opaco (ver
   `.hd-table--sticky-first` arriba), y declarar el color en un solo sitio es lo
   que evita que las dos copias se separen. */
.hd-table tbody tr.is-alert { --hd-table-tinte: rgba(239, 68, 68, 0.06); background: var(--hd-table-tinte); }
.hd-table tbody tr.is-warn  { --hd-table-tinte: rgba(245, 158, 11, 0.06); background: var(--hd-table-tinte); }
.hd-table tbody tr.is-done  { --hd-table-tinte: rgba(34, 197, 94, 0.06); background: var(--hd-table-tinte); }

/* Fila de "aquí no hay nada" DENTRO de una tabla: la que se usa cuando la
   tabla es pequeña y forma parte de un panel mayor, donde un estado vacío
   a página completa (§6.7) no cabe — las salidas de caja de un turno sin
   gastos, por ejemplo. hd-table.js ya la excluye del ordenamiento. */
.hd-table tbody tr.hd-table__empty-row td {
    text-align: center;
    padding: var(--hd-space-4);
}

.hd-table tbody tr.hd-table__empty-row:hover {
    background: none;
}

/* Celdas de conteo: centradas y con numeral tabular, para comparar de
   una pasada vertical sin que los dígitos bailen. */
.hd-table__cell--count {
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* Números alineados a la derecha, tabulares (HVL §6.7). Aplicar en la
   celda correspondiente. `nowrap` porque un importe partido en dos líneas
   ("−\n$22.000") deja de ser una cifra comparable de un vistazo, que es lo
   único que justifica alinearlos a la derecha. */
.hd-table__cell--numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Acciones de fila: última columna, alineadas a la derecha. El
   contenido son .hd-btn--ghost .hd-btn--sm CON texto (HVL §5.5 regla 5:
   una acción se nombra, nunca solo-ícono) — ningún estilo propio aquí,
   solo la alineación del contenedor. El menú "Más" de overflow no
   existe todavía: se construye cuando una tabla real de la migración lo
   necesite (HVL §6, regla de 3+ repeticiones). */
.hd-table__cell--actions {
    text-align: right;
    white-space: nowrap;
}

/* Cada acción que muta estado va en su propio <form> (es un POST con
   antiforgery, no un enlace). Un <form> es de bloque, así que dos acciones
   se apilaban una debajo de otra y doblaban la altura de la fila —52px se
   iban a 72, rompiendo la densidad de HVL §7.4. En esta celda el formulario
   es el vehículo del POST, no un bloque de composición. */
.hd-table__cell--actions form {
    display: inline-block;
}

/* ── Grupo plegable dentro de la tabla ─────────────────────────
   Vehículo: <hd-table-group> + slots -meta / -actions.

   Un listado agrupado por un eje del dominio (categoría de menú, sede,
   día) es UNA tabla con un <tbody> por grupo, no una tabla por grupo:
   así el encabezado de columnas se declara una vez y —lo importante—
   todas las categorías comparten la misma geometría de columnas, que es
   lo que permite recorrer la columna de precios y comparar. Medido en
   Menú: con una tabla por grupo, el mismo precio caía en tres posiciones
   distintas según la categoría. */
.hd-table__group-row > td {
    height: auto;
    padding: var(--hd-space-3) var(--hd-space-4);
    background: var(--hd-color-bg-secondary, var(--hd-theme-surface));
    border-bottom: 1px solid var(--hd-color-border);
}

/* El primer grupo no repite el separador del encabezado de la tabla:
   serían dos líneas de 1px pegadas (HVL §5.2). */
.hd-table__group:first-of-type .hd-table__group-row > td {
    border-top: none;
}

.hd-table__group + .hd-table__group .hd-table__group-row > td {
    border-top: 1px solid var(--hd-color-border);
}

.hd-table__group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--hd-space-3);
}

/* El área de plegado es todo el encabezado menos las acciones, no un
   chevron de 18px. */
.hd-table__group-toggle {
    display: flex;
    align-items: center;
    gap: var(--hd-space-2);
    flex: 1;
    min-width: 0;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    color: inherit;
    font: inherit;
}

.hd-table__group-chevron {
    flex-shrink: 0;
    color: var(--hd-theme-text-muted);
    transition: transform var(--hd-motion-standard) var(--hd-ease);
}

.hd-table__group.is-collapsed .hd-table__group-chevron {
    transform: rotate(-90deg);
}

/* `min-width` impide que el nombre se reduzca a una inicial: los badges
   conservan su tamaño y el nombre era el único elemento encogible — a
   390px se leía "C...". El grupo se identifica por su nombre. */
.hd-table__group-name {
    flex: 1 1 auto;
    min-width: 7rem;
    font-size: var(--hd-text-base);
    font-weight: 600;
    color: var(--hd-theme-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El hover subraya, no tiñe de acento: pasar el cursor no vuelve "activo"
   al grupo, y el acento está reservado a activo/foco/primaria/en vivo
   (HVL §4.2). Mismo criterio que el hover de .hd-panel-card. */
.hd-table__group-toggle:hover .hd-table__group-name {
    text-decoration: underline;
}

.hd-table__group-toggle:focus-visible {
    outline: var(--hd-focus-ring);
    outline-offset: var(--hd-focus-offset);
    border-radius: var(--hd-radius-sm);
}

.hd-table__group-meta,
.hd-table__group-actions {
    display: flex;
    align-items: center;
    gap: var(--hd-space-2);
}

.hd-table__group-meta {
    flex-wrap: wrap;
}

.hd-table__group-actions {
    flex-shrink: 0;
}

/* Plegado: ocultan las filas del grupo, nunca su encabezado. Es CSS
   sobre una clase y no `style.display` escrito por la pantalla, para que
   el estado viva en el DOM y no en una propiedad inline. */
.hd-table__group.is-collapsed > tr:not(.hd-table__group-row) {
    display: none;
}

/* Celda de identidad: miniatura (o ícono) + nombre, con una segunda línea
   de contexto debajo. Es el patrón de la primera columna en cualquier
   listado con imagen —producto, servicio, colaborador—, y estaba escrito
   con flex en línea en cada pantalla que lo usaba. */
.hd-table__cell-stack {
    display: flex;
    align-items: center;
    gap: var(--hd-space-2);
    min-width: 0;
}

.hd-table__cell-title {
    font-weight: 600;
    color: var(--hd-theme-text);
}

/* La antigua `.hd-table-toolbar` se promovió a componente propio
   `.hd-toolbar` (components/toolbar.css) en la revisión 2 de HVL: la
   barra operativa sirve a cualquier pantalla, tenga tabla o no. */

/* ── Densidad (HVL §6.7) ───────────────────────────────────────
   Compacta 44 · normal 52 (por defecto) · amplia 64. La persiste el
   motor JS por usuario y por pantalla; el CSS solo define los tres
   escalones. El encabezado NO cambia de alto: es chrome, y su altura
   es una constante de la ley (44px). */
.hd-table--density-compact tbody td {
    height: var(--hd-size-row-compact);
}

.hd-table--density-wide tbody td {
    height: var(--hd-size-row-wide);
}

/* ── Ordenamiento por columna (HVL §6.7) ───────────────────────
   El encabezado ordenable es un <button> dentro del <th>, no un <th>
   clicable: un th con onclick no es alcanzable por teclado. */
.hd-table__sort {
    display: inline-flex;
    align-items: center;
    gap: var(--hd-space-1);
    border: none;
    background: transparent;
    padding: 0;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}

.hd-table__sort:focus-visible {
    outline: var(--hd-focus-ring);
    outline-offset: var(--hd-focus-offset);
}

/* El indicador de orden solo aparece en la columna activa; en las demás
   ocupa su espacio en transparente para que el encabezado no salte de
   ancho al ordenar. */
.hd-table__sort-icon {
    opacity: 0;
    transition: opacity var(--hd-motion-standard) var(--hd-ease);
}

.hd-table__sort:hover .hd-table__sort-icon {
    opacity: 0.5;
}

.hd-table th[aria-sort] .hd-table__sort-icon {
    opacity: 1;
}

.hd-table th[aria-sort] .hd-table__sort {
    color: var(--hd-theme-text);
}

.hd-table th[aria-sort="descending"] .hd-table__sort-icon {
    transform: rotate(180deg);
}

/* ── Fila expandible — row details (HVL §6.7) ──────────────────
   Una sola fila abierta a la vez (lo garantiza el motor JS). La fila de
   detalle es un <tr> hermano, no un contenedor dentro de la celda: así
   el detalle puede ocupar todo el ancho sin romper la rejilla de
   columnas. */
/* Toda la fila es la zona de clic (el sombreado de hover ya la cubre
   entera vía .hd-table--hover); el cursor lo confirma en vez de mentir
   con una mano solo sobre el chevron de 18px. */
.hd-table tbody tr:has(> td > .hd-table__expander) {
    cursor: pointer;
}

.hd-table__expander {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--hd-size-control-sm);
    height: var(--hd-size-control-sm);

    /* No cede ancho. En modo ficha la celda es un contenedor flexible, y ahí el
       expansor es un ítem con `flex-shrink: 1` y `min-width: auto`: su mínimo
       es el del ícono, así que se comprime en cuanto un hermano pide espacio.
       Medido a 360px en el catálogo de ejercicios del gimnasio, donde la celda
       lleva miniatura (44px) + nombre largo: el botón quedaba en **30×44**, con
       el alto correcto y el ancho por debajo del mínimo táctil —el defecto que
       más cuesta ver, porque de alto ya se ve bien—. También en Rutinas (42×44)
       y en Usuarios de peluquería.

       Va sin consulta de medios: un control de tamaño fijo no debe encogerse
       nunca. En escritorio la celda es `table-cell` y esto no cambia nada. */
    flex-shrink: 0;
    border: none;
    background: transparent;
    color: var(--hd-theme-text-muted);
    border-radius: var(--hd-radius-sm);
    cursor: pointer;
    transition: transform var(--hd-motion-standard) var(--hd-ease),
                color var(--hd-motion-standard) var(--hd-ease);
}

.hd-table__expander:hover {
    color: var(--hd-theme-text);
}

.hd-table__expander:focus-visible {
    outline: var(--hd-focus-ring);
    outline-offset: var(--hd-focus-offset);
}

/* 180°, no 90°: el ícono es `chevron-down`, así que girarlo un cuarto de
   vuelta lo deja apuntando de lado —sin significar nada— en vez de apuntar
   arriba ("plegar"). Detectado en la verificación de la galería. */
.hd-table__expander[aria-expanded="true"] {
    transform: rotate(180deg);
    color: var(--hd-theme-accent-text);
}

/* La celda que contiene el control de expansión alinea control y texto en una
   sola fila. Sin esto, en una columna estrecha el nombre del registro se parte
   y cae debajo del botón, y la fila crece de alto (visto en Empresas con
   "onelifefitness"). Se resuelve en el componente con `:has()` para que
   ninguna pantalla tenga que acordarse de una clase extra — las vistas no
   escriben clases de componente (HVL §6). */
.hd-table td:has(> .hd-table__expander) {
    white-space: nowrap;
}

.hd-table__details {
    display: none;
}

.hd-table__details.is-open {
    display: table-row;
}

/* Un escalón por debajo de la fila y SIN borde propio: el separador de
   la fila de arriba ya delimita (ley de bordes anidados, HVL §5.2). */
.hd-table tbody > tr.hd-table__details > td {
    border-bottom: none;
}

.hd-table__details > td {
    height: auto;
    padding: var(--hd-space-4) var(--hd-space-4) var(--hd-space-5);
    background: var(--hd-color-inset);
    box-shadow: inset 2px 0 0 var(--hd-theme-accent);
}

/* Estado vacío dentro del cuerpo de la tabla — nunca un encabezado con
   nada debajo (HVL §6.7). Envolver .hd-empty-state en una celda a lo
   ancho de la tabla. */
.hd-table__empty-cell {
    padding: var(--hd-space-6) var(--hd-space-4);
}

/* ── Móvil: lista de fichas (HVL §6.7) ─────────────────────────
   "En móvil la tabla se convierte en lista de fichas, nunca scroll
   horizontal de toda la tabla."

   Hasta 2026-08-06 esto quedaba "por resolver en cada página según su
   propio contenido", y el resultado fue que ninguna de las 26 pantallas
   con <hd-table> lo resolvió: la tabla de /admin/usuarios medía 861px en
   un contenedor de 326 y Estado, Puntos, Registro y Acciones quedaban
   fuera de pantalla, alcanzables solo deslizando a ciegas.

   Ahora la conversión es del COMPONENTE, no de la vista (HVL §6): el
   motor (js/huf/hd-table.js) copia el nombre de cada columna a su celda
   en `data-hd-col` y marca con .hd-table--cards las tablas de 3+
   columnas. Ninguna pantalla escribe una clase ni un @media propio.
   ============================================================ */
@media (max-width: 767.98px) {
    /* En modo ficha no hay columnas que deslizar, así que la primera celda
       deja de fijarse — y con ella se van su fondo opaco y su borde: pintados
       sobre una ficha taparían la tinta de estado de su propia fila y
       dibujarían una línea vertical donde ya no hay columna. */
    .hd-table--sticky-first th:first-child,
    .hd-table--sticky-first td:first-child {
        position: static;
        border-right: none;
    }

    .hd-table--sticky-first td:first-child {
        background-color: transparent;
        background-image: none;
    }

    /* El `nowrap` de la celda con expansor es correcto en una COLUMNA estrecha
       —evita que el nombre caiga debajo del botón— y equivocado en una FICHA,
       donde la celda ya tiene el ancho entero y un nombre largo no tiene dónde
       partirse. Medido a 390px en el catálogo de ejercicios: "abdominal
       completo con brazos por encima de la cabeza (hombre)" hacía una celda de
       658px dentro de una tarjeta de 356 — 302px de nombre fuera de la
       pantalla, que es exactamente el desborde que el modo ficha existe para
       eliminar. */
    .hd-table--cards td:has(> .hd-table__expander) {
        white-space: normal;
    }

    .hd-table--cards,
    .hd-table--cards tbody,
    .hd-table--cards tr {
        display: block;
        width: auto;
    }

    /* El encabezado ya no encabeza nada: su contenido viaja dentro de cada
       celda. Se oculta accesiblemente y no con `display: none` para no
       romper la relación celda↔columna en lectores de pantalla. */
    .hd-table--cards thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }

    /* La ficha ES el registro: panel L2 completo, no una fila con borde
       inferior. El separador de fila deja de tener sentido cuando cada
       fila es una tarjeta suelta. */
    .hd-table--cards tbody tr {
        margin-bottom: var(--hd-space-3);
        padding: var(--hd-space-3) var(--hd-space-4);
        border: 1px solid var(--hd-color-border);
        border-radius: var(--hd-radius-md);
        background: var(--hd-theme-surface);
    }

    .hd-table--cards tbody tr:last-child {
        margin-bottom: 0;
    }

    /* La fila de grupo NO es una ficha: es el rótulo que encabeza el
       bloque de fichas siguiente. Sin esto quedaba como una tarjeta más y
       el listado perdía su agrupación justo donde más se necesita, que es
       donde solo cabe una columna. */
    .hd-table--cards .hd-table__group-row {
        margin: var(--hd-space-4) 0 var(--hd-space-2);
        padding: 0;
        border: none;
        background: none;
    }

    .hd-table--cards .hd-table__group-row > td {
        display: block;
        padding: 0;
        border: none;
        background: none;
    }

    .hd-table--cards .hd-table__group-row > td::before {
        content: none;
    }

    /* Nombre y estado arriba, acciones del grupo debajo: apretados en una
       sola fila de 375px, o se corta el nombre o se cortan los botones. */
    .hd-table--cards .hd-table__group-head {
        flex-wrap: wrap;
    }

    .hd-table--cards .hd-table__group-toggle {
        flex: 1 1 100%;
    }

    .hd-table--cards .hd-table__group-actions {
        margin-left: auto;
    }

    /* Par etiqueta/valor por celda: nombre de la columna a la izquierda,
       dato a la derecha. La altura fija de fila (52px) no aplica —dentro
       de una ficha cada dato ocupa lo que necesita— y por eso la densidad
       tampoco tiene efecto aquí. */
    .hd-table--cards td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--hd-space-4);
        height: auto;
        padding: var(--hd-space-1) 0;
        text-align: right;
    }

    /* El borde de la ficha ya delimita el registro; el separador por celda
       pintaría una línea bajo cada par etiqueta/valor. */
    .hd-table--cards tbody > tr > td {
        border-bottom: none;
    }

    .hd-table--cards td[data-hd-col]::before {
        content: attr(data-hd-col);
        flex-shrink: 0;
        font-size: var(--hd-text-micro);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--hd-theme-text-muted);
        text-align: left;
    }

    /* Primera columna = identidad del registro. En la tabla es la columna
       fija; en la ficha es su título, así que no lleva etiqueta: repetir
       "EMPRESA — demo" sobre el nombre no informa nada. */
    .hd-table--cards td:first-child {
        justify-content: flex-start;
        gap: var(--hd-space-2);
        padding-bottom: var(--hd-space-2);
        font-size: var(--hd-text-title);
        font-weight: 600;
        text-align: left;
    }

    .hd-table--cards td:first-child::before {
        content: none;
    }

    /* Acciones: al pie de la ficha, separadas por línea. Es el bloque que
       hoy queda fuera de pantalla, y el motivo por el que la conversión no
       es cosmética. */
    .hd-table--cards td.hd-table__cell--actions {
        justify-content: flex-end;
        flex-wrap: wrap;
        margin-top: var(--hd-space-2);
        padding-top: var(--hd-space-3);
        border-top: 1px solid var(--hd-color-border);
        white-space: normal;
    }

    .hd-table--cards td.hd-table__cell--actions::before {
        content: none;
    }

    /* Las dos filas que no son registros ocupan la ficha entera y no se
       parean con ninguna columna. Se reafirma `display` con más
       especificidad que `.hd-table--cards tr` porque si no, la fila de
       detalle CERRADA volvería a mostrarse. */
    .hd-table--cards tr.hd-table__details {
        display: none;
    }

    .hd-table--cards tr.hd-table__details.is-open {
        display: block;
    }

    .hd-table--cards tr.hd-table__details > td,
    .hd-table--cards tr.hd-table__empty-row > td {
        display: block;
        text-align: center;
    }

    .hd-table--cards tr.hd-table__empty-row {
        background: transparent;
    }
}

/* Selector de columnas opcionales (piloto — hd-table.js initColumns). El
   trigger vive fuera de la tabla, alineado a la derecha, mismo lugar donde
   viven hoy los controles de densidad externos. */
.hd-table-columns {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--hd-space-2);
}

.hd-table [data-hd-col-id].is-col-hidden {
    display: none;
}

/* ── Superficie táctil — bajo 992px ─────────────────────────────
   El expansor de fila ya sube solo: mide con `--hd-size-control-sm`, que
   pasa a 44px en este mismo corte (tokens.css). El plegador de grupo no,
   porque su alto sale del renglón: medido 326×24 a 360px, una banda
   ancha pero de la mitad del alto mínimo, y es lo que hay que tocar para
   abrir o cerrar una categoría entera. */
@media (max-width: 991.98px) {
    .hd-table__group-toggle {
        min-height: var(--hd-size-control-sm);
    }
}

/* Glosa: texto de apoyo dentro de una celda — explica el dato de la columna
   de al lado, no es un dato por derecho propio. Nace en el dashboard de
   Inteligencia, donde la columna "Qué hacer" traduce el nombre del segmento
   RFM: "loyalists" no le dice nada a quien no estudió RFM. Va atenuado para
   que no compita con los datos reales de la fila, y en una sola línea: envuelta en
   tres renglones bajaba la tabla de 7 filas visibles a 5 en 1440×900, y la densidad
   de HVL §7.4 se recorta del chrome, nunca de las filas. */
.hd-table__cell--glosa {
    white-space: nowrap;
    color: var(--hd-theme-text-muted);
}
