/* Componentes reutilizables entre pantallas: tarjetas, etiquetas, barras y tablas. */

/* ---- Tarjeta ------------------------------------------------------------------------ */

.card {
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
}

.card__head {
    padding: var(--space-4) var(--space-6);
    border-bottom: 1px solid var(--outline-variant);
}

/* Cabecera de tarjeta con una acción a la derecha del título, como .page-head--row pero a
   escala de tarjeta — la usa el historial de visitas, con "Agendar visita" junto al título. */
.card__head--row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}

.card__body { padding: var(--space-6); }

/* ---- Indicadores -------------------------------------------------------------------- */

/*
 * Tira de métricas (§5.4), MOBILE-FIRST (§4.1).
 *
 * Base = móvil: carrusel horizontal con anclaje, tal como pide §4.2 para la ficha 360º
 * ("Métricas en carrusel horizontal"). Cuatro tarjetas de 104px apiladas ocupaban una pantalla
 * entera de 360px y empujaban el contenido real bajo el pliegue.
 *
 * El carrusel NO desborda la página: `overflow-x: auto` hace del contenedor su propio
 * scrollport, que es justo la diferencia que marca §4.3 -- scroll horizontal en un lienzo, sí;
 * en una tabla de datos, nunca. Los `margin`/`padding` negativos hacen que la tira sangre hasta
 * el borde de la pantalla (el gesto de arrastre arranca en el borde) sin que la primera tarjeta
 * pierda su alineación con el resto del contenido.
 *
 * `grid-auto-columns: 74%` deja asomar el borde de la siguiente tarjeta: es lo que dice "esto
 * se arrastra" sin necesidad de puntos ni flechas.
 */
.stats {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(170px, 74%);
    gap: var(--space-4);
    margin-inline: calc(var(--space-3) * -1);
    padding-inline: var(--space-3);
    /* Sitio para la sombra de la tarjeta, que un scrollport recorta. */
    padding-bottom: var(--space-2);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
}

.stats::-webkit-scrollbar { display: none; }

.stats > * { scroll-snap-align: start; }

/* Tablet vertical: 2×2, la composición que pide §4.2 bajo `lg`. Sin carrusel. */
@media (min-width: 768px) {
    .stats {
        grid-auto-flow: row;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        margin-inline: 0;
        padding-inline: 0;
        padding-bottom: 0;
        overflow-x: visible;
        scroll-snap-type: none;
    }
}

/* Escritorio: la rejilla elástica de siempre, sin cambio respecto a antes de la tanda 82. */
@media (min-width: 1024px) {
    .stats { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
}

/*
 * Altura pareja garantizada, no heredada de la rejilla.
 *
 * display:flex + justify-content:flex-end alinea las etiquetas por abajo aunque una tarjeta
 * tenga pista y otra no. Sin esto, la fila queda visualmente rota en cuanto un texto ocupa
 * dos líneas — que es exactamente lo que pasa al traducir a inglés.
 */
.stat {
    display: flex;
    flex-direction: column;
    min-height: 104px;
    padding: var(--space-4) var(--space-6);
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
}

.stat__label { margin-top: auto; }

.stat__hint {
    margin-top: var(--space-1);
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
}

/* La pista va debajo de la etiqueta, así que la etiqueta deja de ser lo último. */
.stat:has(.stat__hint) .stat__label { margin-top: auto; }

/* Cifra grande de un KPI: es el único uso legítimo de --text-display (§2.2). */
.stat__value {
    font: var(--text-display);
    letter-spacing: var(--tracking-display);
    font-variant-numeric: tabular-nums;
}

/* Rótulo de grupo en mayúsculas: el único uso legítimo que le queda a 11px. */
.stat__label {
    font: var(--text-overline);
    letter-spacing: var(--tracking-overline);
    text-transform: uppercase;
    color: var(--on-surface-variant);
}

.stat--alert .stat__value { color: var(--error); }

/*
 * Valor que es TEXTO y no una cifra: un estado, el nombre de una etapa, una fecha.
 *
 * --text-display existe para el KPI numérico de un panel a ancho de página (§2.2), donde dos o
 * tres glifos mandan sobre la tarjeta. Una palabra o una fecha a ese tamaño se come el ancho
 * entero y se parte en dos líneas en cuanto la superficie es estrecha -- el diálogo de 680px
 * del recorrido del lead, la columna de 720px del asistente de conversión. Lo que sobra no es
 * el componente, es el escalón: un titular se sigue leyendo como dato destacado frente a la
 * etiqueta de 11px que lleva debajo.
 *
 * No se toca font-variant-numeric a propósito: se hereda de .stat__value, y una fecha también
 * quiere cifras de ancho fijo o los dígitos bailan al cambiar de registro.
 */
.stat--text .stat__value {
    font: var(--text-title-lg);
    letter-spacing: var(--tracking-title-lg);
}

/* ---- Etiqueta de clasificación (RF-07) ---------------------------------------------- */

.tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    /* Altura fija y no padding: ver la nota de --control-sm en tokens.css. */
    height: var(--control-xs);
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    /* Píldora = --text-label (§2.2/§5.5). El line-height va DESPUÉS del shorthand `font`,
       que lo reescribiría: dentro de una altura fija de --control-sm queremos 1. */
    font: var(--text-label);
    line-height: 1;
    letter-spacing: var(--tracking-label);
    background: var(--surface-container);
    color: var(--on-surface-variant);
    white-space: nowrap;
}

.tag__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    /* El color concreto lo pone la vista desde el dato del tenant, vía --tag-color. */
    background: var(--tag-color, var(--outline));
}

.tag-filter {
    display: flex;
    flex-wrap: wrap;
    /* align-items: center es lo que impide que los chips se estiren a la altura de la fila. */
    align-items: center;
    gap: var(--space-2);
}

.tag-filter .tag {
    cursor: pointer;
    border: 1px solid var(--outline-variant);
    background: var(--surface-container-lowest);
    /* El borde entra dentro de la altura: sin esto, los chips con borde miden 2px más que
       los de la tabla y las dos filas dejan de casar. */
    box-sizing: border-box;
    /*
     * Objetivo táctil (§4.4): dentro de `.tag-filter` el chip ES pulsable (filtro de "Mi
     * espacio", de la cartera...), a diferencia de `.tag` a secas, que también se usa como
     * badge de solo lectura en una decena de vistas y no debe crecer. Base = móvil con
     * --control-touch; a partir de `md` recupera --control-xs, mismo patrón que
     * .view-switch__tab en projects.css.
     */
    height: var(--control-touch);
}

@media (min-width: 768px) {
    .tag-filter .tag { height: var(--control-xs); }
}

.tag-filter .tag:hover {
    background: var(--surface-container);
    text-decoration: none;
}

.tag-filter .tag.is-active {
    background: var(--secondary-fixed);
    border-color: var(--secondary-fixed-dim);
    color: var(--on-secondary-fixed);
    font-weight: 600;
}

/* Fila de chips genérica: mismo layout que .project-tags (projects.css), reutilizable fuera de
   la cartera de proyectos — líneas de servicio (RF-25/RF-30, 3.12) en la lista y el tablero de
   Oportunidades, que no tiene su propia hoja para esto. align-items: center es la regla de
   siempre para todo contenedor flex de controles/pastillas. */
.chip-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-1);
}

/* ---- Estado ------------------------------------------------------------------------- */

.status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    white-space: nowrap;
}

.status__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.status--pending  .status__dot { background: var(--status-pending); }
.status--progress .status__dot { background: var(--status-progress); }
.status--blocked  .status__dot { background: var(--status-blocked); }
.status--review   .status__dot { background: var(--status-review); }
.status--done     .status__dot { background: var(--status-done); }

.status--blocked { color: var(--error); font-weight: 600; }

/* Severidad "Crítica" de un riesgo (5.1, RF-51): el único de los cuatro tonos del semáforo
   que necesita distinguirse con más fuerza que un simple color de texto -- fondo al 10% del
   color de estado, mismo criterio que el design system fija para "Status Pills". */
.status--critical {
    background: var(--error-container);
    color: var(--on-error-container);
    font-weight: 700;
    padding: 2px var(--space-2);
    border-radius: var(--radius-full);
}

.status--critical .status__dot { background: var(--status-blocked); }

/* Estado vacío simple dentro de una tarjeta ("sin fechas todavía", "sin riesgos todavía"...):
   nueva, para no repetir style="padding: var(--space-6)" en cada vista -- ya había varias
   copias de ese mismo valor suelto en Detail.cshtml antes de esta regla. */
.card__empty {
    padding: var(--space-6);
}

/* ---- Barra de avance ---------------------------------------------------------------- */

.progress {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.progress__track {
    flex: 1;
    min-width: 56px;
    max-width: 110px;
    height: 5px;
    border-radius: var(--radius-sm);
    background: var(--surface-container-high);
    overflow: hidden;
}

.progress__fill {
    height: 100%;
    background: var(--status-progress);
}

.progress__fill--done { background: var(--status-done); }

.progress__value {
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    font-variant-numeric: tabular-nums;
    color: var(--on-surface-variant);
    min-width: 32px;
    text-align: right;
}

/* ---- Tabla -------------------------------------------------------------------------- */

.table-wrap { overflow-x: auto; }

/*
 * El cuerpo de tabla sube de 13.5px a 14px (--text-body-md): es el suelo de contenido de §2.2 y
 * el cambio más visible de la fase 2, porque esta regla la comparten TODAS las tablas de la app.
 */
.table {
    width: 100%;
    border-collapse: collapse;
    font: var(--text-body-md);
}

/* Cabecera de tabla en --text-overline (§5.3): 11px legítimo, va en mayúsculas. */
.table th {
    text-align: left;
    padding: var(--space-2) var(--space-6);
    background: var(--surface-container-low);
    border-bottom: 1px solid var(--outline-variant);
    font: var(--text-overline);
    letter-spacing: var(--tracking-overline);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    white-space: nowrap;
}

.table th:first-child { border-top-left-radius: var(--radius-lg); }
.table th:last-child { border-top-right-radius: var(--radius-lg); }

/*
 * vertical-align: top, no middle (bug real reportado por el usuario en /Access, con captura de
 * pantalla): cuando una celda de la fila crece de alto -- los roles/permisos de Access
 * envolviendo a más de una línea, la nota de un riesgo/incidencia, el <details> de un hito --
 * "middle" centra las demás celdas de esa misma fila (nombre, correo, severidad...) dentro de una
 * altura de fila mayor que la de las filas vecinas, así que el texto de una fila alta queda a
 * distinta altura relativa que el de una fila corta: el efecto "desfasado" que describió el
 * usuario. Con "top" cada celda arranca siempre en el borde superior de su fila, con
 * independencia de cuánto crezca cualquier celda vecina -- consistente entre filas de distinta
 * altura. Sin efecto visible en ninguna tabla de filas uniformes de una sola línea (Board,
 * Calendar, Services, Sources...): con contenido de una sola línea, top y middle coinciden porque
 * no hay espacio sobrante que repartir dentro de la celda.
 */
.table td {
    padding: var(--space-2) var(--space-6);
    border-bottom: 1px solid var(--surface-container);
    vertical-align: top;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-container-low); }

.table .numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ---- Columna de lectura -------------------------------------------------------------- */

/*
 * Techo de lectura de 1440px (§8.1) aplicado a una REGIÓN y no a la página entera.
 *
 * Lo necesita una pantalla híbrida: /Opportunities es plantilla D (el Kanban comercial manda y
 * arranca activo, y su contenido es el eje horizontal), pero su panel de Lista es plantilla A y
 * a 2400px una tabla de siete columnas queda huérfana. Alineada a la izquierda y no centrada,
 * para que la tabla arranque en la misma vertical que la cabecera de página de arriba.
 */
.reading-column {
    max-width: min(1440px, 100%);
}

/* ---- Tabla de datos (§5.3) ---------------------------------------------------------- */

/*
 * `.table--data` es el modificador de las tablas de LISTADO (plantilla A de §3.2), no de toda
 * tabla de la aplicación: una tabla incrustada en una tarjeta de ficha o en un formulario no
 * quiere cabecera pegajosa ni primera columna a 16px. Se aplica junto a `.table`, así que todo
 * lo de arriba sigue vigente y esto solo añade lo que pide §5.3.
 *
 * Los divisores bajan a --outline-subtle, que es el token que §5.3 nombra literalmente. La
 * ausencia de bordes verticales ya venía de serie (nunca hubo border-left/right en .table).
 */
.table--data tbody td {
    border-bottom-color: var(--outline-subtle);
}

/*
 * Cabecera pegajosa.
 *
 * El scrollport es la PÁGINA, no un contenedor propio: por eso el envoltorio de estas tablas
 * es `.table-wrap--data`, que renuncia al overflow. Un `overflow-x: auto` convierte al
 * envoltorio en contenedor de scroll también en vertical (la especificación fuerza el eje
 * contrario de `visible` a `auto`), y dentro de un contenedor que nunca hace scroll vertical
 * una cabecera `sticky` no se pega a nada: se queda quieta encima de su tabla y parece que la
 * regla no funciona. Con el techo de 1440px de §8.1 y las 4-8 columnas de estos listados, el
 * scroll horizontal que el envoltorio daba deja de hacer falta -- y §9 lo lista como ❌
 * explícito para una tabla de datos. Bajo `md` la tabla pasa a tarjetas (§4.3), que es la
 * tanda 82.
 *
 * --z-raised, no --z-sticky: la cabecera tiene que pasar POR DEBAJO de la barra de filtros
 * pegajosa (que sí está en --z-sticky) y de la barra superior.
 */
.table-wrap--data { overflow: visible; }

.table--data thead th {
    position: sticky;
    top: var(--topbar-height);
    z-index: var(--z-raised);
}

/*
 * Con barra de filtros pegajosa delante, la cabecera se pega justo debajo de ella.
 *
 * El combinador de hermano general evita tener que marcar la tabla con una clase extra desde
 * cada vista: la barra de filtros y la tarjeta de la tabla son hermanas dentro de
 * `.content__inner` en las cuatro pantallas con filtro. `--filters-height` la declara
 * `.filters` en forms.css; el valor de reserva está aquí por si el orden de hojas cambiara.
 */
.filters--sticky ~ .card .table--data thead th,
.filters--sticky ~ .table-wrap--data .table--data thead th,
.filters--sticky ~ * .card .table--data thead th {
    top: calc(var(--topbar-height) + var(--filters-height, 56px));
}

/*
 * Primera columna = identidad, en --text-title-md (§5.3). Se apoya en `.project-name`, que es
 * la clase que ya marcaba la celda o el enlace de identidad en las 14 pantallas de listado, en
 * vez de en `td:first-child`: una primera celda lleva además código, etiquetas y notas, y subir
 * el tipo a la celda entera se los llevaría por delante.
 */
.table--data .project-name {
    /* --text-title-md no tiene tracking propio en tokens.css: el escalon no lo declara. */
    font: var(--text-title-md);
}

/* Metadato dentro de la celda de identidad: vuelve al escalón de metadato (§3.3, nivel 4/5). */
.table--data td.project-name .muted,
.table--data td.project-name .project-code,
.table--data .project-name + .muted {
    font: var(--text-body-sm);
}

/*
 * Importes: a la derecha, en --font-mono y con cifras tabulares (§5.3). Va como clase propia y
 * no sobre `.numeric`, porque `.numeric` también la llevan fechas y recuentos, que no son
 * importes y no quieren monoespaciado.
 */
.table .cell-amount {
    text-align: right;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Más de una acción por fila (por ejemplo "Editar" junto a un formulario de archivar/
   desarchivar, Views/Services/Index.cshtml): sin esto, el <form> --que es un bloque-- fuerza un
   salto de línea y separa las dos acciones en vez de alinearlas. align-items: center es la
   regla de siempre para todo contenedor flex de controles. */
.row-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
}

/* Objetivo táctil de ".link-button" dentro de una fila (§4.4): sin `height` propia cae a la
   caja del texto (medido: 18-20px en /Stages y /Funnels, muy por debajo del mínimo). Móvil
   primero, generalizado desde la regla que nació scopeada a #agreements-table en board.css:
   nace a altura táctil y baja a densidad de puntero a partir de `md`, donde deja de ser el
   único control fino de la fila. Aplica a las trece pantallas de plantilla E (.master-layout)
   de golpe, no una por una. */
.row-actions .link-button {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-touch);
}

@media (min-width: 768px) {
    .row-actions .link-button {
        min-height: var(--control-sm);
    }
}

/* ---- Tabla de datos → tarjetas apiladas (§4.3, tanda 82) ----------------------------- */

/*
 * EL PROBLEMA QUE RESUELVE ESTE BLOQUE, medido y no supuesto.
 *
 * Una tabla de listado pide unos 930px de ancho mínimo (min-content) y `.table-wrap--data`
 * renunció al `overflow` en la tanda 76 para que la cabecera pegajosa funcionara -- decisión
 * correcta para su problema, pero que deja a la tabla EMPUJANDO LA PÁGINA cuando no cabe. A
 * 1024px la página desbordaba 192px; a 360px, 573px. §9 lo lista como ❌ explícito.
 *
 * §4.3 del design system manda convertir la tabla en tarjetas bajo `md` (768). Eso arregla el
 * móvil y deja roto el tramo de 768 a ~1250, donde las tarjetas ya no aplican y la tabla sigue
 * sin caber. CRITERIO DECIDIDO EN ESTA TANDA, en tres tramos y no en dos:
 *
 *   < md (768)      Tarjetas apiladas. No hay tabla, así que no hay nada que desborde.
 *   md → 1304      Tabla con COLUMNAS PRIORITARIAS: se ocultan las marcadas `data-col="xl"`.
 *                   Es la respuesta literal de §4.2 ("Tabla con 4 columnas prioritarias"),
 *                   extendida más allá de `lg` porque a 1024px la tabla completa tampoco cabe
 *                   -- 720px de contenido frente a 930 de tabla.
 *   ≥ 1304         Tabla completa, exactamente la de hoy. 976px de contenido para 930 de tabla.
 *
 * Por qué NO se resolvió devolviendo el `overflow-x` al envoltorio bajo `xl`: volvería a
 * romper la cabecera pegajosa (un contenedor con overflow en un eje fuerza `auto` en el otro,
 * y dentro de un contenedor que no hace scroll vertical un `sticky` no se pega a nada -- el
 * hallazgo de la tanda 76), y además §9 prohíbe el scroll horizontal en una tabla de DATOS,
 * no solo en un móvil.
 *
 * Por qué la frontera de tarjetas se queda en `md` y no sube: la suite E2E corre a 1280×720 y
 * ahí tiene que seguir viendo una TABLA, no tarjetas -- subir la frontera por encima de ese
 * ancho la rompería entera. Lo que sí cambió en la tanda 83 es la OTRA frontera, la de la tabla
 * completa, que pasa de 1280 a 1304 (ver el bloque de `--bp-xl-table` más abajo): a 1280 se ve
 * la tabla de columnas prioritarias, y ningún test de la suite depende del contenido de una
 * columna marcada `data-col="xl"`.
 *
 * TODO ESTO ES MOBILE-FIRST: la tarjeta es el estado BASE (sin `@media`) y la tabla se
 * reconstruye hacia arriba con `min-width`. Ni una `max-width` nueva.
 */

/* Base = móvil: la tabla deja de ser tabla. La cabecera desaparece; su texto viaja en el
   `data-label` de cada celda, que es lo que se pinta como rótulo del metadato. */
.table--data,
.table--data > thead,
.table--data > tbody,
.table--data > tbody > tr,
.table--data > tbody > tr > td { display: block; }

.table--data > thead { display: none; }

/* La fila es la tarjeta. Sin `overflow: hidden`: un menú o un chip pueden asomar. */
.table--data > tbody > tr {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
}

.table--data > tbody > tr:last-child { margin-bottom: 0; }

.table--data > tbody > tr > td {
    padding: 0;
    border-bottom: 0;
    /*
     * RED DE SEGURIDAD DE LA TARJETA, y el hueco real que dejaba la tanda 82: `anywhere` solo
     * se declaraba dentro del bloque de `md` (el tramo intermedio), así que en tarjeta —el
     * estado BASE, el de 360px— una cadena larga sin espacios no tenía dónde partir. Un correo
     * de /Users, una ruta de /Tracking o un asunto de /Support sin un solo espacio empujaban la
     * tarjeta, y con ella la página, en el ancho más estrecho de los seis.
     *
     * `anywhere` y no `break-word`, por el mismo motivo de siempre: es el único de los dos que
     * además REDUCE el ancho mínimo de la caja, y aquí eso importa porque el metadato es un
     * contenedor flex —una palabra indivisible fija el `min-width: auto` de su ítem y ni el
     * `space-between` ni el `gap` pueden con ella—.
     */
    overflow-wrap: anywhere;
}

/* Clave arriba, en title-md (§4.3). `.table--data .project-name` ya daba ese escalón al enlace
   de identidad; esto cubre también las celdas donde el nombre es texto suelto. */
.table--data > tbody > tr > td:first-child {
    font-size: var(--text-title-md-size);
    line-height: var(--text-title-md-lh);
    font-weight: 600;
    /* Sin `color`: el heredado ya es --on-surface, y declararlo aquí pisaría un `.muted` de la
       propia celda con más especificidad de la que le corresponde. */
}

/*
 * OBJETIVO TÁCTIL DEL TÍTULO DE LA TARJETA (§4.4), y la decisión declarada de a quién se le da.
 *
 * Hallazgo del coordinador midiendo /Customers a 360px: los iconos y los avatares ya tenían su
 * área de 44px por pseudo-elemento (layout.css), pero el enlace de título de la tarjeta medía
 * 22px de alto. DECISIÓN: EL OBJETIVO LO DA EL ENLACE, NO LA FILA ENTERA. La tarjeta parece la
 * unidad de toque natural, pero varias pantallas no tienen un único destino por fila —/Access y
 * /Users no navegan a ninguna ficha, /Reports cierra la tarjeta con tres acciones distintas—,
 * así que hacer la fila clicable obligaría a inventar un destino donde no lo hay, o a que la
 * misma tarjeta fuera pulsable en unas pantallas y no en otras. El enlace, en cambio, existe
 * exactamente donde hay adónde ir.
 *
 * Mecanismo: pseudo-elemento, EL MISMO que ya usan `.icon-button` y `.avatar`, y no
 * `min-height`. Un `min-height` obliga a cambiar el `display` del <a> —un elemento en línea lo
 * ignora— y ese cambio sí mueve la maquetación: hay celdas de identidad donde el enlace tiene
 * hermanos en línea que pasarían a otra línea. La banda de 44px se centra sobre la caja del
 * enlace y no ocupa sitio en el flujo.
 */
.table--data > tbody > tr > td:first-child a { position: relative; }

.table--data > tbody > tr > td:first-child a::after {
    content: "";
    position: absolute;
    inset: 50% 0 auto 0;
    transform: translateY(-50%);
    height: var(--control-touch);
}

/*
 * Metadato: rótulo a la izquierda, valor a la derecha, los dos en la misma línea. El rótulo
 * sale de `attr(data-label)`, que la vista copia del `<th>` correspondiente -- sin él, una
 * tarjeta sería una pila de valores sueltos ("Marta Ruiz", "45%", "12 jun") sin decir de qué.
 */
.table--data > tbody > tr > td:not(:first-child) {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    /* Tamaño y no el atajo `font:`: el atajo arrastra `font-family` y le quitaría la
       monoespaciada a `.cell-amount`, que es una celda de importe como cualquier otra. */
    font-size: var(--text-body-sm-size);
    line-height: var(--text-body-sm-lh);
    text-align: right;
}

.table--data > tbody > tr > td:not(:first-child)[data-label]::before {
    content: attr(data-label);
    flex: none;
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    color: var(--on-surface-muted);
    text-align: left;
}

/* La acción principal, abajo a la derecha y separada por una regla: es el cierre de la tarjeta
   que pide §4.3, no un metadato más. La marca la vista con `data-cell="actions"`. */
.table--data > tbody > tr > td[data-cell="actions"] {
    justify-content: flex-end;
    margin-top: var(--space-1);
    padding-top: var(--space-3);
    border-top: 1px solid var(--outline-subtle);
}

.table--data > tbody > tr > td[data-cell="actions"]::before { content: none; }

/*
 * En tarjeta, las acciones se envuelven. `.row-actions` es `inline-flex` sin envoltura porque
 * en una fila de tabla de escritorio dos acciones en dos líneas descuadran la altura de la
 * fila; en una tarjeta de 328px no hay tal fila que descuadrar, y /Reports (tres exportaciones
 * más "Editar") o /Users (varios formularios por fila) no caben en una sola línea. Sin esto,
 * la tarjeta desborda por su cierre, que es justo la parte que no se mira.
 */
.table--data > tbody > tr > td[data-cell="actions"] .row-actions { flex-wrap: wrap; }

/*
 * Celda de bloque: un resumen de auditoría, una nota de parte de horas, la lista de
 * competencias de una persona. No es un valor corto que quepa a la derecha de su rótulo, así
 * que en la tarjeta va a línea completa con el rótulo encima.
 */
.table--data > tbody > tr > td[data-cell="block"] {
    display: block;
    text-align: left;
}

.table--data > tbody > tr > td[data-cell="block"][data-label]::before {
    display: block;
    margin-bottom: var(--space-1);
}

/* md → : vuelve a ser una tabla, con las columnas prioritarias. */
@media (min-width: 768px) {
    .table--data { display: table; }
    .table--data > thead { display: table-header-group; }
    .table--data > tbody { display: table-row-group; }

    .table--data > tbody > tr {
        display: table-row;
        gap: 0;
        padding: 0;
        margin-bottom: 0;
        background: none;
        border: 0;
        border-radius: 0;
    }

    .table--data > tbody > tr > td,
    .table--data > tbody > tr > td:not(:first-child),
    .table--data > tbody > tr > td[data-cell="actions"],
    .table--data > tbody > tr > td[data-cell="block"] {
        display: table-cell;
        padding: var(--space-2) var(--space-6);
        margin-top: 0;
        padding-top: var(--space-2);
        border-top: 0;
        border-bottom: 1px solid var(--outline-subtle);
        font-size: var(--text-body-md-size);
        line-height: var(--text-body-md-lh);
        text-align: left;
    }

    /*
     * `:not(.project-name)`: la celda de identidad conserva su title-md de siempre (regla
     * `.table--data .project-name`, §5.3). Sin la exclusión, esta regla —más específica— se lo
     * llevaría por delante en escritorio, que es justo la jerarquía que ganó la tanda 76.
     */
    .table--data > tbody > tr > td:first-child:not(.project-name) {
        font-size: var(--text-body-md-size);
        line-height: var(--text-body-md-lh);
        font-weight: 400;
    }

    /*
     * EL RÓTULO DE TARJETA SE RETIRA CON EL CAMINO COMPLETO, Y ES CORRECCIÓN DE CASCADA, NO
     * ESTILO -- exactamente la misma trampa que ya obligó a escribir así las columnas
     * `data-col="xl"` más abajo, y que aquí se coló.
     *
     * Quien PINTA el rótulo es `... > td:not(:first-child)[data-label]::before`, que vale
     * (0,3,4). Esta regla, escrita como `... > td::before`, valía (0,1,4) y PERDÍA SIEMPRE,
     * estuviera donde estuviera y en el bloque que fuera: una `@media` no añade especificidad.
     * El resultado en escritorio era el rótulo de la tarjeta pegado al valor de la tabla --
     * "ClienteClínicas Sanvital", "GestorDiego Peña", "Estado ● En curso" (captura del usuario
     * en /Projects a ~1650px).
     *
     * Con los tres selectores al mismo peso que los que pintan, empatan en especificidad y manda
     * el último, que es este. El genérico se conserva para cualquier `::before` de celda que no
     * venga de un `data-label`.
     */
    .table--data > tbody > tr > td::before,
    .table--data > tbody > tr > td:not(:first-child)[data-label]::before,
    .table--data > tbody > tr > td[data-cell="block"][data-label]::before { content: none; }

    /* Puntero: el área táctil del título sobra, y una banda invisible de 44px sobre una fila de
       tabla robaría el clic a la celda de al lado. Se retira en la misma frontera que todo lo
       demás de §4.4. */
    .table--data > tbody > tr > td:first-child a::after { content: none; }
    .table--data > tbody > tr:last-child > td { border-bottom: 0; }

    /* Las celdas numéricas recuperan su alineación de siempre, que la regla de arriba pisa. */
    .table--data > tbody > tr > td.numeric,
    .table--data > tbody > tr > td.cell-amount { text-align: right; }

    /*
     * RED DE SEGURIDAD del tramo intermedio, y la razón de que el criterio no dependa de haber
     * elegido bien las columnas prioritarias de cada una de las once pantallas: mientras la
     * tabla no tenga sitio de sobra (bajo `xl`) se le permite partir palabras. `anywhere`, y no
     * `break-word`, porque es el único valor que además REDUCE el ancho mínimo de la columna en
     * el cálculo de la tabla -- con `break-word` el navegador sigue reservando la palabra
     * entera. Una cabecera en dos líneas es preferible a una página que desborda.
     */
    .table--data th { white-space: normal; }
    .table--data td { overflow-wrap: anywhere; }
}

/*
 * Columna de solo escritorio ancho. Oculta de base (tarjeta) y en el tramo intermedio (tabla
 * con columnas prioritarias); vuelve en `xl`. Se aplica al `<th>` y al `<td>` a la vez, que es
 * la única forma de que la cabecera y el cuerpo no se descuadren.
 *
 * VA AQUÍ, DESPUÉS DEL BLOQUE DE `md`, Y ESCRITA CON EL CAMINO COMPLETO, POR CASCADA -- no es
 * estilo, es corrección. Escrita como `.table--data [data-col="xl"]` valía (0,2,0) y perdía
 * contra `.table--data > tbody > tr > td:not(:first-child)`, que vale (0,2,3): la columna no se
 * habría ocultado en móvil. Y colocada ANTES del bloque de `md`, ese bloque la habría vuelto a
 * enseñar por orden de aparición a igualdad de especificidad. Con el camino completo y en esta
 * posición, las dos reglas empatan en especificidad y manda la última: oculta hasta `xl`.
 */
.table--data > thead > tr > th[data-col="xl"],
.table--data > tbody > tr > td[data-col="xl"] { display: none; }

/*
 * Tabla completa. LA FRONTERA ES 1304px Y NO 1280, Y ES UNA CORRECCIÓN MEDIDA, NO UN GUSTO.
 *
 * Hallazgo del coordinador verificando la tanda 82 en un navegador real: a 1280px exactos
 * quedaban 4px de desbordamiento. La causa es que una `@media` casa contra el ancho del
 * VIEWPORT (1280), mientras que el contenido dispone del ancho del cliente —1265, porque la
 * barra de scroll clásica se lleva 15—. Justo en la frontera aparecía la tabla completa en un
 * hueco 15px más estrecho del que la consulta suponía.
 *
 * 1304 = `--bp-xl` (1280) + 24 de holgura de barra de scroll; el valor está declarado como
 * `--bp-xl-table` en tokens.css, junto a la escala, para que nadie lo lea como un séptimo
 * breakpoint ad-hoc. 24 y no 15: Windows y Linux usan 15-17px según el tema, y los 4px medidos
 * caben de sobra dentro de esa holgura. Es el único número de este bloque que no sale de la
 * escala de §4.1, y no se mueve a ella a propósito: no es un breakpoint de diseño, es la misma
 * frontera `xl` corregida por un detalle de implementación del navegador.
 *
 * Consecuencia buscada: a 1280 —que es el ancho al que corre la suite E2E— se ve la tabla de
 * columnas prioritarias, no la completa. Ningún test depende del contenido de una columna
 * marcada `data-col="xl"` (comprobado con `grep` en la tanda 82), así que la suite no cambia de
 * resultado; lo que cambia es que a ese ancho la página deja de desbordar.
 */
@media (min-width: 1304px) {
    .table--data > thead > tr > th[data-col="xl"],
    .table--data > tbody > tr > td[data-col="xl"] { display: table-cell; }

    .table--data th { white-space: nowrap; }

    /* Camino completo, y no `.table--data td`, POR CASCADA: la red de seguridad ya se declara
       en la regla base de la celda de tarjeta —que vale (0,1,3)— y un selector de (0,1,1) no
       habría podido deshacerla aquí. Con el mismo peso manda la última, que es esta. */
    .table--data > tbody > tr > td { overflow-wrap: normal; }

    /* Y las acciones vuelven a una sola línea: aquí sí hay una fila de tabla cuya altura
       descuadraría un salto. Entre `md` y `xl` se quedan envueltas a propósito -- una celda de
       acciones que no cabe ensancha la tabla, y esa tabla no tiene scroll propio. */
    .table--data > tbody > tr > td[data-cell="actions"] .row-actions { flex-wrap: nowrap; }
}

/* ---- Aviso --------------------------------------------------------------------------- */

/*
 * Base que faltaba: docenas de vistas ya escriben <p class="notice">, y forms.css trae la
 * variante .notice--ok, pero la clase de la que parte nunca se había declarado — el mensaje de
 * error se veía como texto plano sin ningún aviso visual. .notice--ok, cargada después por
 * forms.css, gana en las tres propiedades que sobrescribe.
 */
.notice {
    padding: var(--space-2) var(--space-4);
    border-left: 3px solid var(--error);
    border-radius: var(--radius-sm);
    background: var(--error-container);
    color: var(--on-error-container);
    font: var(--text-body-md);
}

/*
 * Aviso que no impide seguir. .notice a secas es rojo de error y frena; esta variante es
 * ámbar y solo llama la atención — la usa el asistente de conversión (RF-30) para el contraste
 * entre el importe vendido y el de la propuesta aceptada, que no es un fallo sino una
 * discrepancia que alguien tiene que mirar antes de convertir.
 */
.notice--warn {
    border-left-color: var(--status-review);
    background: var(--surface-container-low);
    color: var(--on-surface);
}

.notice--warn p:last-child { margin-bottom: 0; }

/* ---- Tip de arrastre (Views/Shared/_Tip.cshtml) --------------------------------------- */

/*
 * Icono de bombilla + texto pequeño, tono instructivo. Componente compartido: los cuatro sitios
 * que lo usan hoy (Views/Projects/Detail.cshtml -- vista Lista, Kanban, Gantt y panel de
 * Asignar) son los únicos gestos de arrastre sin ninguna otra pista visual en la interfaz.
 * `align-items: flex-start` en vez de `center` porque el texto del Gantt es largo y puede
 * envolver a dos líneas; el icono se alinea con la primera con un pequeño ajuste óptico.
 */
.tip {
    display: flex;
    align-items: flex-start;
    gap: var(--space-1);
    margin: var(--space-1) 0 var(--space-4);
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
}

.tip__icon {
    margin-top: 1px;
    color: var(--on-surface-variant);
}

/* ---- Botones ------------------------------------------------------------------------ */

.button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px var(--space-4);
    border-radius: var(--radius);
    border: 1px solid transparent;
    /* El rótulo del botón mantiene sus 13px, ahora tomados del escalón body-sm, sobre la
       familia de etiqueta y con el peso 600 que ya tenía. No baja a --text-label (12px):
       la fase 2 sube suelos, no los baja. */
    font-family: var(--font-label);
    font-size: var(--text-body-sm-size);
    line-height: var(--text-body-sm-lh);
    font-weight: 600;
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-standard),
                border-color var(--duration-fast) var(--ease-standard);
}

.button:hover { text-decoration: none; }

.button--primary {
    background: var(--secondary);
    color: var(--on-secondary);
}

.button--primary:hover { background: var(--secondary-container); color: var(--on-secondary); }

.button--ghost {
    background: var(--surface-container);
    border-color: var(--outline-variant);
    color: var(--primary);
}

.button--ghost:hover { background: var(--surface-container-high); color: var(--primary); }

/*
 * Tira de acciones hermanas del mismo peso, con un solo contorno alrededor y separadores finos
 * entre ellas (maqueta docs/design-refs/11-informes.png: "Exportar PDF | Excel | CSV").
 *
 * Existe porque tres botones fantasma sueltos, uno al lado de otro, se leen como tres decisiones
 * distintas: agrupados dicen "esto es una sola cosa —exportar— en tres formatos", y dejan que el
 * único primario de la pantalla destaque de verdad. Primer consumidor: /Reports/Design.
 */
.segmented {
    display: inline-flex;
    align-items: center;
    padding: 2px;
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
}

.segmented__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    /* Altura explícita, nunca derivada del padding: es la misma pastilla que el resto de
       controles de la interfaz. El mínimo táctil lo pone la regla de más abajo. */
    height: var(--control-sm);
    padding: 0 var(--space-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    font-family: var(--font-label);
    font-size: var(--text-body-sm-size);
    font-weight: 600;
    color: var(--on-surface-variant);
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-standard),
                color var(--duration-fast) var(--ease-standard);
}

/* Separador entre items: un borde en el elemento, no un <div> vacío en el marcado. */
.segmented__item + .segmented__item {
    box-shadow: -1px 0 0 0 var(--outline-variant);
}

.segmented__item:hover {
    background: var(--surface-container-low);
    color: var(--primary);
}

/*
 * Base = móvil (§4.1): solo el icono. Tres rótulos completos ("Exportar a PDF/Excel/CSV") miden
 * 423px medidos, y a 360 sacaban la cabecera fuera de la pantalla. El nombre accesible no se
 * pierde: cada botón lleva su `aria-label`. El rótulo vuelve a partir de `md`, más abajo.
 */
.segmented__label { display: none; }

/* ---- Plantilla B · Ficha 360º (§3.2) -------------------------------------------------- */

/*
 * Sección de ficha: la salida de §5.4 ("una tarjeta no anida a otra tarjeta").
 *
 * Antes, cada bloque de la ficha de proyecto era una `.page-head` con `<h2>` seguida de una
 * `.card` hermana, y dentro de esa tarjeta volvían a aparecer tarjetas, tablas y estados
 * vacíos con su propio marco. El resultado eran marcos dentro de marcos y ninguna jerarquía
 * legible. Una sección NO tiene fondo ni borde: se separa de la anterior con una regla y se
 * anuncia con un overline, exactamente como pide §5.4.
 *
 * El `id` se conserva en la propia sección (no en una cabecera suelta) para que las pestañas
 * de la barra superior sigan desplazándose hasta aquí — romper esos anclajes reabriría los
 * enlaces muertos que la tanda 52 vino a cerrar.
 */
.detail-section {
    margin-top: var(--space-8);
    padding-top: var(--space-6);
    border-top: 1px solid var(--outline-variant);
    /* La pestaña de la barra superior desplaza hasta aquí: sin esto, el topbar pegajoso tapa
       el título de la sección recién alcanzada. */
    scroll-margin-top: calc(var(--topbar-height) + var(--space-4));
}

.detail-section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

/* Rótulo de familia de la sección. 11px legítimo (§2.2): va en mayúsculas. */
.detail-section__overline {
    display: block;
    margin: 0 0 var(--space-1);
    font: var(--text-overline);
    letter-spacing: var(--tracking-overline);
    text-transform: uppercase;
    color: var(--on-surface-variant);
}

/* Nivel 4 de §3.3: el título de sección nunca compite con el `title-xl` de la cabecera. */
.detail-section__title {
    margin: 0;
    font: var(--text-title-lg);
}

/* Contador junto al título de sección (número de contactos, de visitas...): metadato, no
   parte del título, así que no hereda su peso ni su tamaño. */
.detail-section__title .label {
    margin-left: var(--space-2);
    color: var(--on-surface-variant);
}

.detail-section__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* Línea de resumen de una sección (p. ej. el total de gastos), no un párrafo de cabecera. */
.detail-section__meta {
    margin: 0 0 var(--space-4);
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
}

/* Estado vacío corto dentro de una sección. Equivale a `.card__empty`, sin el marco. */
.detail-section__empty {
    margin: 0;
    padding: var(--space-4) 0 var(--space-6);
    font: var(--text-body-md);
    color: var(--on-surface-variant);
}

/*
 * Cuerpo con marco propio SOLO donde el contenido no es una tabla ni una lista con divisores
 * (el reparto por estado canónico, por ejemplo). Es el sustituto de la `.card` retirada, sin
 * volver a anidar tarjetas dentro.
 */
.detail-section__panel {
    padding: var(--space-6);
    background: var(--surface-container-lowest);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
}

/*
 * Banda de metadatos (§3.2 plantilla B).
 *
 * Sustituye a la columna lateral `.detail-aside` que esto era hasta esta tanda. El motivo es de
 * coste de espacio, medido en vivo por el usuario sobre /Projects/Detail: seis campos cortos no
 * justifican reservar 320px de ancho a lo largo de TODA la ficha, porque ese ancho no lo paga el
 * lateral -- lo paga el contenido principal, que se estrecha, más el hueco muerto que queda bajo
 * la más corta de las dos columnas.
 *
 * Peso visual deliberadamente bajo (§3.3): los metadatos son nivel 4 -- identidad, no estado --
 * así que la banda NO lleva marco de tarjeta ni fondo propio, solo dos filetes que la acotan.
 * El color saturado y la tipografía grande siguen siendo exclusivos de la tira de métricas, que
 * es el nivel 2 y lo único con derecho a ellos.
 *
 * Mobile-first: apilada por defecto y en banda a partir de --bp-md (768px), con `auto-fit` para
 * que el número de columnas lo fije el ancho disponible y no un recuento fijo -- estas tres
 * fichas pintan entre cinco y ocho pares según qué campos vengan informados.
 */
.detail-meta {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    padding: var(--space-4) 0;
    border-top: 1px solid var(--outline-subtle);
    border-bottom: 1px solid var(--outline-subtle);
}

@media (min-width: 768px) {
    .detail-meta {
        grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
        gap: var(--space-4) var(--space-8);
    }
}

.detail-meta__row {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

/*
 * Un par cuyo valor son varias píldoras (etiquetas, servicios, filiales) ocupa el doble de
 * ancho: en una sola celda la lista se parte en una píldora por línea y la banda crece de alto,
 * que es justo lo que este cambio venía a evitar.
 */
@media (min-width: 768px) {
    .detail-meta__row--wide {
        grid-column: span 2;
    }
}

.detail-meta__label {
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--on-surface-muted);
}

.detail-meta__value {
    font: var(--text-body-md);
    color: var(--on-surface);
    overflow-wrap: anywhere;
}

/* Píldoras dentro de la banda: envuelven en varias líneas sin desbordar la celda. */
.detail-meta__chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1);
}

/*
 * Primera sección de una ficha: sin regla ni margen superior, para que arranque pegada a lo que
 * tiene encima (hoy la banda de metadatos, que ya cierra con su propio filete). La regla separa
 * secciones HERMANAS; sobre la primera no separa nada y solo duplica el divisor de arriba.
 */
.detail-section--flush {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}


/* ---- Plantilla C · Tablero (§3.2) ---------------------------------------------------- */

/*
 * Rejilla de 12 columnas POR PRIORIDAD DE LECTURA, no por gusto de maquetación: cifras arriba
 * (span 3), gráficos en medio (span 6) y listas abajo (span 12). Es la composición literal que
 * §3.2 asigna a /Dashboard, /Board y /Workspace, las tres únicas pantallas de esta plantilla.
 *
 * Vive aquí y no en dashboard.css por el mismo criterio que .detail-section y .reading-column
 * (plantilla B, tanda 77): el chasis de una plantilla lo comparten varias pantallas, así que su
 * sitio es el fichero de componentes y no la hoja de una de ellas. dashboard.css se queda con
 * lo que solo es del Panel (el puente, la lista de atención, el embudo).
 *
 * MOBILE-FIRST (§4.1): la base es una sola columna —todo apilado— y las columnas se AÑADEN con
 * min-width. Ninguna max-width nueva.
 */
.board-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--space-6);
    /* Una tarjeta de cifra no se estira a la altura de la fila entera. */
    align-items: start;
}

/* Base de 360px: cada bloque ocupa la fila completa, sea cifra, gráfico o lista. */
.board-grid > * { grid-column: span 12; }

/* Tablet vertical: dos cifras por fila. Un gráfico a media fila todavía no cabe. */
@media (min-width: 768px) {
    .board-grid__figure { grid-column: span 6; }
}

/* Escritorio: la rejilla de §3.2 tal cual — 4 cifras, 2 gráficos, listas a fila completa. */
@media (min-width: 1024px) {
    .board-grid__figure { grid-column: span 3; }
    .board-grid__chart { grid-column: span 6; }
    .board-grid__list { grid-column: span 12; }

    /*
     * Cuerpo del tablero: contenido a la izquierda (8) y columna de avisos a la derecha (4),
     * que es la composición de la maqueta aprobada para el Panel. Bajo `lg` no hace falta
     * ninguna regla: los dos caen al `span 12` de la base, que ya es mobile-first.
     */
    .board-grid__main { grid-column: span 8; }
    .board-grid__aside { grid-column: span 4; }
}

/*
 * Dos bloques lado a lado DENTRO de `.board-grid__main`. No puede resolverse con la rejilla de
 * 12 de fuera: al vivir dentro de una columna, los hijos ya no participan de ella. Se parten en
 * dos a partir de `xl` y no de `lg`, porque a 1024px la columna de la izquierda mide unos 640px
 * y dos gráficos de 300px se leen peor que uno debajo del otro.
 */
.board-grid__split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
}

@media (min-width: 1280px) {
    .board-grid__split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/*
 * Nota al pie de la fila de cifras: declara en voz baja lo que la pantalla NO puede enseñar
 * (hoy, la comparativa con el periodo anterior). Es texto de servicio, nunca un dato.
 */
.board-grid__note {
    margin-top: calc(var(--space-4) * -1);
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
}

/*
 * La cifra de un tablero es el MISMO componente que la tira de métricas de una ficha 360º
 * (`.stat`, con su `--alert` y su --text-display): §5.4 pide una tarjeta, no una por pantalla.
 * Aquí solo se le da el sitio en la rejilla; el aspecto ya estaba resuelto más arriba.
 */
.board-grid .stat { height: 100%; }

/*
 * Título de una lista del tablero. Antes cada bloque de /Workspace era una `.page-head` con un
 * `<h2>` dentro —la cabecera de PÁGINA reutilizada tres veces en la misma página, con lo que la
 * pantalla tenía cuatro cabeceras y ninguna jerarquía—. Aquí es lo que §3.3 llama nivel 4: un
 * rótulo de bloque, no una segunda cabecera de pantalla.
 */
.board-grid__list-title {
    margin-bottom: var(--space-4);
    font: var(--text-title-lg);
    letter-spacing: var(--tracking-title-lg);
}

/*
 * Cabecera de bloque con una acción a la derecha ("Ver todos", "Ver calendario completo"). No es
 * la barra de acciones de la pantalla —esa vive en la `.page-head` y solo tiene un primario—,
 * así que lo que va aquí es siempre un `.button--ghost`.
 *
 * `align-items: center` y no `baseline`: la regla de las pastillas de este proyecto. Un botón de
 * 32px junto a un título de 24 se estiraría a la altura de la fila sin ella.
 */
.board-grid__list-head {
    margin-bottom: var(--space-4);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

/* El margen inferior lo pone ya la cabecera; dentro de ella el título no lo necesita. */
.board-grid__list-head .board-grid__list-title { margin-bottom: 0; }


/* ---- Plantilla E · Configuración / maestro (§3.2) ------------------------------------- */

/*
 * Dos columnas en `lg`: lista al 60% y formulario al 40%, apiladas por debajo. El patrón de
 * edición —`?editId=` en la cadena de consulta precargando el formulario de la derecha, página
 * completa y sin diálogo— ya existía en /Services, /Stages y /LossReasons; esta clase no
 * inventa nada, unifica las trece pantallas de configuración a ese patrón y le pone el 60/40
 * exacto que pide §3.2 (el `grid__col--7`/`--5` de antes daba 58/42 y solo por casualidad).
 *
 * `align-items: start` es obligatorio: sin él, la tarjeta del formulario se estira hasta la
 * altura de una tabla de cuarenta filas y el borde inferior queda flotando en el vacío.
 */
.master-layout {
    display: grid;
    /* Sin esta pista explícita, la pista implícita del grid se dimensiona a `max-content` y
       arrastra el ancho natural de la tabla interior (verificado: hasta 937px en /Stages a
       375px de viewport), desbordando la página entera por fuera de `.table-wrap`, que solo
       puede contener el scroll de lo que crece *dentro* de él. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
    align-items: start;
}

@media (min-width: 1024px) {
    .master-layout {
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    }
}

/*
 * Columna del formulario. Apilable: /Access y /Settings tienen dos paneles independientes ahí
 * (conceder rol / conceder permiso, regional / marca), y necesitan la misma separación que da
 * la rejilla entre columnas.
 */
.master-layout__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

/*
 * Pegajosa solo donde hay sitio de sobra: con la lista al lado, el formulario acompaña al
 * scroll en vez de perderse por arriba en un maestro de cuarenta filas. Bajo `lg` las columnas
 * están apiladas y pegar el formulario taparía la lista, así que solo se activa en escritorio.
 */
@media (min-width: 1024px) {
    .master-layout__form {
        position: sticky;
        top: calc(var(--topbar-height) + var(--space-6));
    }
}

/*
 * FORMULARIO EN HOJA BAJO `md` (§4.2: "E · Config -> apilado, formulario en hoja").
 *
 * Lo que faltaba de la plantilla E. Apilar la columna del formulario debajo de la lista deja el
 * alta al final de un maestro de cuarenta filas: hay que recorrer la lista entera para llegar al
 * campo "Nombre", y al pulsar "Editar" en una fila la página salta a un formulario que está
 * fuera de la pantalla y no se ve cambiar. La hoja resuelve las dos cosas.
 *
 * Mismo mecanismo exacto que la hoja de filtros de la tanda 82, hasta en la degradación: el
 * disparador lo fabrica `master-sheet.js` y no el marcado, así que sin JavaScript no existe un
 * botón que no abre nada y la columna del formulario se queda donde siempre, funcionando como
 * el <form> normal que es. La hoja lleva la clase `.dialog`, así que hereda de dialog.css el
 * patrón de hoja inferior sin una regla de posición nueva.
 */
.master-trigger {
    display: flex;
    align-items: center;
    margin-bottom: var(--space-4);
}

.master-trigger__button {
    width: 100%;
    justify-content: center;
    min-height: var(--field-touch);
}

/* La frontera es `md` y no `lg`: §4.2 pide la hoja solo bajo `md`; entre `md` y `lg` el maestro
   se queda apilado, con el formulario debajo de la lista y a la vista. */
@media (min-width: 768px) {
    .master-trigger { display: none; }
}

.master-sheet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}

.master-sheet__title {
    margin: 0;
    font: var(--text-title-lg);
    letter-spacing: var(--tracking-title-lg);
}

/*
 * Dentro de la hoja, la columna del formulario deja de ser una columna: el `sticky` de
 * escritorio no se pega a nada dentro de un modal, y la tarjeta pierde su marco porque la hoja
 * ya ES la superficie elevada. Dos marcos anidados en 360px se comen 32px de ancho útil.
 */
.master-sheet .master-layout__form {
    position: static;
}

.master-sheet .master-layout__form > .card {
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

.master-sheet .master-layout__form > .card > .card__body {
    padding: 0;
}

/* La fila que se está editando (`?editId=`) ya la resalta projects.css con
   `.table tr.is-editing`, así que aquí no hace falta ninguna regla nueva: al unificar las trece
   pantallas a este chasis, las que no marcaban la fila heredan el resaltado sin tocar esa hoja
   (que la tanda 75 dejó verificada al píxel y esta tanda no abre). */

/* ---- Plantilla D: espacio de trabajo (§3.2) ------------------------------------------ */

/*
 * "Ancho completo, barra de herramientas pegajosa, area de scroll propia. La pagina NO hace
 * scroll: lo hace el lienzo."
 *
 * Chasis compartido, no una regla por pantalla: lo usan el Kanban comercial, el triaje de
 * leads, el calendario mensual, la carga por persona y los paneles de Kanban / Hoja de datos /
 * Calendario de la ficha de proyecto.
 *
 * ---------------------------------------------------------------------------------------
 * AVISO IMPORTANTE, PORQUE EL CASO CONTRARIO YA ESTA RESUELTO EN OTRA HOJA
 *
 * La tanda 76 descubrio que una cabecera `sticky` dentro de un contenedor con `overflow` no se
 * pega a nada, y por eso `.table-wrap--data` RENUNCIA al overflow: en una tabla de datos
 * (plantilla A) el scrollport tiene que ser la pagina.
 *
 * Aqui el requisito es el contrario y el caso es otro: un lienzo (plantilla D) SI quiere su
 * propio scrollport. Por eso este chasis se aplica al lienzo y NUNCA al contenedor de un
 * `.table--data`. En /Opportunities, que es la unica pantalla donde A y D conviven en el mismo
 * documento, el viewport se pone en los paneles de Kanban y Hoja de datos y jamas en el panel
 * de Lista, que sigue desplazandose con la pagina y conserva su cabecera pegajosa.
 * ---------------------------------------------------------------------------------------
 */
.canvas__toolbar {
    position: sticky;
    top: var(--topbar-height);
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-4);
    /* Fondo opaco: sin el, el lienzo se leeria por debajo de la barra al desplazar. */
    background: var(--surface);
    padding: var(--space-3) 0;
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--outline-subtle);
}

.canvas__viewport {
    /*
     * Lo que hay por encima del lienzo y no le pertenece: barra superior, cabecera de pagina y
     * barra de herramientas. Es un numero declarado y no una medida del DOM a proposito --
     * derivarlo exigiria JavaScript midiendo en cada resize, y una plantilla no puede depender
     * de eso. Cada pantalla lo ajusta con su propio valor si su cabecera es mas alta o mas
     * baja que la media.
     */
    --canvas-offset: 260px;

    overflow: auto;
    /* Al llegar al final del lienzo, el gesto no sigue arrastrando la pagina de debajo. */
    overscroll-behavior: contain;
}

/*
 * Solo en escritorio. Bajo `lg` la pagina es estrecha y alta, el scroll natural es el de la
 * pagina, y acotar el lienzo a la altura del viewport dejaria dos barras de scroll compitiendo
 * en la misma direccion. Coherente con §4.2, que ya declara que el Gantt y la Hoja de datos no
 * se rediseñan para movil.
 */
@media (min-width: 1024px) {
    .canvas__viewport {
        max-height: calc(100dvh - var(--canvas-offset));
    }
}

/* ---- Plantilla D · el límite declarado en móvil (§4.2, tanda 83) --------------------- */

/*
 * "Bajo `md`, del espacio de trabajo se ofrecen SOLO Lista y Kanban. Gantt y Hoja de datos
 * muestran el aviso «mejor en pantalla grande» con acceso de solo lectura." §4.2 lo dice con
 * todas las letras y añade el motivo: fingir que una carta Gantt de 2.400px funciona en 360
 * es peor que declarar el límite.
 *
 * ESTO NO ES UNA CARENCIA, ES EL SISTEMA, y por eso se dice en la interfaz y no solo en la
 * documentación. Las dos pestañas siguen ahí y siguen abriéndose —acceso, que es lo que pide
 * el requisito—; lo que cambia es que llegan con un aviso encima y sin poder editar.
 *
 * El aviso es un parcial servido por Razor (`Views/Shared/_LargeScreenNotice.cshtml`), así que
 * su texto está en los tres .resx y no lo fabrica ningún módulo. Aquí solo se decide cuándo se
 * ve: SIEMPRE de base, nunca a partir de `md`.
 */
.large-screen-notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-4);
    background: var(--surface-container-low);
    border: 1px solid var(--outline-variant);
    border-left: 3px solid var(--status-review);
    border-radius: var(--radius-lg);
}

.large-screen-notice__icon {
    flex: none;
    color: var(--status-review);
}

.large-screen-notice__title {
    margin: 0;
    /* title-md no tiene `--tracking-*` propio en §2.2: solo title-lg y title-xl lo llevan. */
    font: var(--text-title-md);
}

.large-screen-notice__body {
    margin: var(--space-1) 0 0;
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
}

.large-screen-notice__badge {
    display: inline-flex;
    align-items: center;
    height: var(--control-sm);
    margin-top: var(--space-2);
    padding: 0 var(--space-3);
    border-radius: var(--radius-full);
    background: var(--surface-container-high);
    color: var(--on-surface-variant);
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    /* Chip NO pulsable: --control-md es exactamente para esto desde §4.4, y por eso lleva
       altura explícita en vez de derivarla del padding. */
    white-space: nowrap;
}

@media (min-width: 768px) {
    .large-screen-notice { display: none; }
}

/*
 * Solo lectura del lienzo. La clase la pone `workspace-limits.js` y NUNCA el marcado: sin
 * JavaScript no existe ningún camino de edición en estas dos vistas —el Gantt entero lo pinta
 * `gantt.js`, y la Hoja de datos guarda por `fetch` desde `sheet-view.js`—, así que el módulo
 * es la única capa donde el bloqueo tiene sentido y su ausencia no abre ningún hueco.
 *
 * `pointer-events` sobre los tres gestos de edición del Gantt (arrastrar una barra, arrastrar
 * el asa de dependencia, pulsar una línea para borrarla) y NADA MÁS: expandir/colapsar una
 * fase, el zoom y el resaltado de ruta crítica son lectura y se conservan. NO SE TOCA UNA SOLA
 * MEDIDA DEL GANTT: ni altura de fila, ni posición de barra, ni geometría de dependencias.
 */
.view-panel.is-readonly .gantt__bar,
.view-panel.is-readonly .gantt-deps__handle,
.view-panel.is-readonly .gantt-deps__line {
    pointer-events: none;
    cursor: default;
}

/* ---- Botón: estados `disabled` y `loading` de §5.1 ------------------------------------ */

/*
 * Los dos faltaban. `loading` es el que arregla un fallo real y no una carencia estética: hasta
 * ahora nada impedía pulsar "Guardar" dos veces mientras el servidor procesaba el primer envío,
 * así que se creaban dos filas. Lo aplica `button-loading.js` al botón que dispara el envío.
 *
 * Deliberadamente NO se usa el atributo `disabled` para eso, y el motivo es funcional: un
 * <button disabled> no aporta su `name`/`value` al envío, así que deshabilitarlo dentro del
 * propio evento `submit` rompería cualquier formulario con varios botones de envío
 * (`/Reports/Design` tiene cinco, tres de ellos con `formaction`). Se marca con una clase y
 * `aria-disabled`, y quien impide el segundo envío es el guardián del <form>, no el botón.
 */
.button:disabled,
.button[aria-disabled="true"] {
    opacity: .55;
    cursor: not-allowed;
    pointer-events: none;
}

.button.is-loading {
    position: relative;
    cursor: progress;
    /* Bloquea el segundo clic sin sacar el botón del orden de tabulación ni del envío. */
    pointer-events: none;
    /* Hueco para el indicador, a la derecha del rótulo. Se reserva al entrar en `loading`, así
       que el botón crece 18px mientras espera; el rótulo se queda legible y a pleno contraste,
       que es lo que importa cuando alguien está mirando si su clic ha hecho algo. Atenuar el
       texto no era opción: el rótulo suele ser un nodo de texto suelto junto a un <svg>, y un
       nodo de texto no se puede seleccionar con CSS. */
    padding-right: calc(var(--space-4) + 18px);
}

.button.is-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    right: var(--space-2);
    margin-top: -7px;
    width: 14px;
    height: 14px;
    border-radius: var(--radius-full);
    border: 2px solid currentColor;
    border-top-color: transparent;
    animation: button-spin .7s linear infinite;
}

@keyframes button-spin {
    to { transform: rotate(360deg); }
}


/* ---- Tira de pestañas con scroll horizontal (§4.3) ----------------------------------- */

/*
 * "Pestañas → tira con scroll horizontal y desvanecido en los bordes. Nunca se envuelven en
 * dos líneas." Es lo que fija §4.3 y lo que la aplicación no hacía en ninguno de sus tres
 * juegos de pestañas: la barra de `/Projects/Detail` tiene siete, la de `/Board` cuatro y el
 * conmutador de vistas del espacio de trabajo cinco. A 360px ninguna cabe.
 *
 * El desvanecido NO necesita JavaScript ni un "está desbordado" calculado a mano. Se consigue
 * con cuatro degradados de fondo y la propiedad `background-attachment`, en la técnica clásica
 * de sombras de scroll:
 *
 *   - dos degradados TAPA, del color de la superficie, anclados `local`: viajan con el
 *     contenido, así que se sientan encima de la sombra correspondiente mientras el scroll
 *     está en ese extremo y la descubren al separarse;
 *   - dos degradados SOMBRA, anclados `scroll`: se quedan clavados en los bordes de la caja.
 *
 * La consecuencia útil es que, si la tira no desborda, las dos tapas cubren las dos sombras y
 * no se ve absolutamente nada. Por eso el patrón puede aplicarse en TODOS los anchos sin
 * cambiar el escritorio: allí las pestañas caben y el desvanecido nunca aparece.
 *
 * `--strip-bg` es el color de la superficie sobre la que se apoya la tira; cada consumidor lo
 * declara si no es el de por defecto.
 */
.scroll-strip,
.topbar__tabs,
.form-dialog-tabs__strip,
.view-switch {
    --strip-bg: var(--surface-container-lowest);
    flex-wrap: nowrap;
    /* Sin esto una tira dentro de un contenedor flex no encoge por debajo de su contenido y,
       en vez de desplazarse, empuja a sus hermanos fuera de la barra. */
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    /* La barra nativa robaría altura a una tira de 32px y en táctil no se usa: se navega
       arrastrando. El desvanecido es la señal de que hay más a los lados. */
    scrollbar-width: none;
    background-image:
        linear-gradient(to right, var(--strip-bg), transparent var(--space-6)),
        linear-gradient(to left, var(--strip-bg), transparent var(--space-6)),
        linear-gradient(to right, rgba(var(--brand-primary-rgb, 19, 27, 46), .14), transparent var(--space-3)),
        linear-gradient(to left, rgba(var(--brand-primary-rgb, 19, 27, 46), .14), transparent var(--space-3));
    background-position: left center, right center, left center, right center;
    background-repeat: no-repeat;
    background-size: var(--space-6) 100%, var(--space-6) 100%,
                     var(--space-3) 100%, var(--space-3) 100%;
    background-attachment: local, local, scroll, scroll;
}

.scroll-strip::-webkit-scrollbar,
.topbar__tabs::-webkit-scrollbar,
.form-dialog-tabs__strip::-webkit-scrollbar,
.view-switch::-webkit-scrollbar {
    display: none;
}

/*
 * Una pestaña no se encoge ni se parte en dos líneas: si no cabe, la tira se desplaza. Sin
 * esto, `flex` reparte el ancho disponible y "Estructura de trabajo" se lee "Estructura de
 * traba…" en vez de quedar fuera del borde, que es lo que la persona espera arrastrar.
 */
.topbar__tab,
.form-dialog-tabs__tab,
.view-switch__tab {
    flex: 0 0 auto;
    white-space: nowrap;
}


/* ---- Objetivo táctil de los botones (§4.4) ------------------------------------------- */

/*
 * Base = móvil (§4.1). Un `.button` deriva hoy su altura del padding y mide unos 32px: por
 * debajo del mínimo de 44 de §4.4. Aquí crece de verdad —no con un pseudo-elemento— porque un
 * botón con rótulo no tiene por qué mantener su caja pequeña en una pantalla táctil; el que
 * no puede crecer es el icono suelto, y ese va por pseudo-elemento en layout.css.
 *
 * `min-height` y no `height`: hay botones con `height` propia (los de `.filters`, forms.css) y
 * un mínimo mayor gana sin necesidad de perseguir cada excepción.
 *
 * A partir de `md` se devuelve el valor de siempre. El escritorio no cambia: 0 es exactamente
 * lo que valía este `min-height` antes de esta tanda, porque no existía.
 */
.button { min-height: var(--control-touch); }

/* El principal sube a 48 (§4.4): es el que se pulsa con el pulgar sin mirar. */
.button--primary { min-height: var(--field-touch); }

/* Un item de `.segmented` no es un `.button` —no hereda esa regla— pero se pulsa igual. */
.segmented__item { min-height: var(--control-touch); }

@media (min-width: 768px) {
    .button,
    .button--primary {
        min-height: 0;
    }

    .segmented__item { min-height: var(--control-sm); }
    .segmented__label { display: inline; }
}

/* ---- Indice de secciones maestras (maqueta 12-configuracion) --------------------------------
 * Portada de Configuracion: rejilla de enlaces a los maestros del tenant. Es navegacion, no una
 * tarjeta de dato: por eso va en <nav> y sin ninguna cifra al lado -- un contador aqui obligaria
 * a una llamada por maestro solo para pintar la portada. */

.settings-index {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-2);
}

.settings-index__item {
    display: flex;
    align-items: center;
    min-height: var(--control-md);
    padding: var(--space-3);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--on-surface);
    font-family: var(--font-label);
    font-weight: 600;
    text-decoration: none;
    overflow-wrap: anywhere;
}

.settings-index__item:hover {
    border-color: var(--secondary);
    background: var(--surface-container);
}

.settings-index__item:focus-visible {
    outline: 2px solid var(--secondary);
    outline-offset: 2px;
}

/* ---- Chip de variación respecto al periodo anterior (maqueta 01-panel) ---------------
 *
 * Va junto a una cifra de KPI y dice cuánto ha cambiado desde el corte anterior. Se pinta
 * SOLO cuando hay cifra anterior real: la ausencia no tiene aspecto propio porque no se
 * dibuja nada (ver DashboardComparison y Views/Variation.cs).
 *
 * Píldora, así que altura fija y no derivada del padding: la regla de este proyecto sobre
 * cualquier control con forma de pastilla. El contenedor lleva align-items: center por el
 * mismo motivo -- sin él, un chip estrecho se estira a la altura de la fila.
 *
 * Los tres tonos salen de los semánticos ya declarados en tokens.css; ni un hexadecimal.
 */
.stat__chips {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.variation {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    height: var(--control-xs);
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    font: var(--text-label);
    line-height: 1;
    letter-spacing: var(--tracking-label);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.variation--good {
    background: var(--success-container);
    color: var(--on-success-container);
}

.variation--bad {
    background: var(--error-container);
    color: var(--on-error-container);
}

/* Sin movimiento no hay color: gris, ni verde ni rojo. */
.variation--neutral {
    background: var(--surface-container);
    color: var(--on-surface-variant);
}

.variation__arrow {
    font-weight: 700;
}

/*
 * Fila de totales de una tabla de datos (§5.3), estrenada por el desglose economico de una
 * oportunidad (RF-58). Es el PRIMER <tfoot> del producto, asi que el modo tarjeta —que hasta
 * ahora solo contemplaba thead y tbody— no lo cubria: sin estas reglas, un tfoot con
 * `display: table-footer-group` dentro de una tabla puesta en `display: block` deja de casar
 * con las tarjetas de arriba y descuadra el ancho.
 *
 * BASE = MOVIL: el total es una tarjeta mas, distinguida por su fondo y su borde, con el mismo
 * mecanismo de rotulo por `data-label` que las demas. A partir de `md` vuelve a ser una fila de
 * tabla normal, que es lo que pide la maqueta.
 */
.table--data > tfoot,
.table--data > tfoot > tr,
.table--data > tfoot > tr > th,
.table--data > tfoot > tr > td { display: block; }

.table--data > tfoot > tr {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-4);
    background: var(--surface-container);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
}

.table--data > tfoot > tr > th {
    padding: 0;
    text-align: left;
    font-size: var(--text-title-md-size);
    line-height: var(--text-title-md-lh);
}

.table--data > tfoot > tr > td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 0;
    font-size: var(--text-body-sm-size);
    line-height: var(--text-body-sm-lh);
    text-align: right;
}

.table--data > tfoot > tr > td[data-label]::before {
    content: attr(data-label);
    flex: none;
    font: var(--text-label);
    letter-spacing: var(--tracking-label);
    color: var(--on-surface-muted);
    text-align: left;
}

/* Celda de cierre sin contenido (la que empareja con la columna de acciones): en tarjeta no
   pinta nada y ocuparia un hueco vacio en la rejilla. */
.table--data > tfoot > tr > td:empty { display: none; }

@media (min-width: 768px) {
    .table--data > tfoot { display: table-footer-group; }
    .table--data > tfoot > tr { display: table-row; gap: 0; padding: 0; background: none; border: 0; border-radius: 0; }

    .table--data > tfoot > tr > th,
    .table--data > tfoot > tr > td {
        display: table-cell;
        padding: var(--space-2) var(--space-6);
        font-size: var(--text-body-md-size);
        line-height: var(--text-body-md-lh);
    }

    .table--data > tfoot > tr > td { text-align: right; }
    .table--data > tfoot > tr > td[data-label]::before { content: none; }
    .table--data > tfoot > tr > td:empty { display: table-cell; }
}
