/*
 * UiMetadata.Grid — design tokens
 *
 * Override any --grid-* variable in your theme file to customize the look.
 * Every token falls back to a sensible light-mode default so the grid works
 * out-of-the-box in any project that hasn't defined its own theme.
 *
 * Consuming projects that already ship a design system (e.g. EcoTrack)
 * only need to map their existing vars:
 *
 *   :root {
 *     --grid-header-bg      : var(--table-header-bg);
 *     --grid-row-hover      : var(--table-row-hover);
 *     --grid-btn-primary-bg : linear-gradient(135deg, var(--color-primary-light), var(--color-primary-strong));
 *     ...
 *   }
 */

/* ── Design tokens ──────────────────────────────────────────────────────── */
:root {
    /* Radius */
    --grid-radius-sm: 6px;
    --grid-radius-md: 8px;
    --grid-radius-lg: 12px;
    --grid-radius-pill: 50px;
    /* Alto compartido por TODOS los controles de la barra de arriba del grid
       (input de búsqueda, select/dropdown de filas, "+ Crear" y sus
       versiones ícono en mobile) — un solo número para que ninguno quede
       más alto o más bajo que el resto de la fila. */
    --grid-control-h: 2.75rem;
    /* Spacing */
    --grid-gap-xs: 0.4rem;
    --grid-gap-sm: 0.5rem;
    --grid-gap-md: 1rem;
    /* Typography */
    --grid-font-size-sm: 0.875rem;
    --grid-font-size-md: 0.92rem;
    --grid-font-size-base: 0.95rem;
    --grid-font-size-lg: 1.3rem;
    --grid-font-size-h2: 1.8rem;
    /* Text */
    --grid-text-main: var(--text-main, #111827);
    --grid-text-muted: var(--text-muted, #6b7280);
    --grid-text-on-btn: var(--text-on-accent, #ffffff);
    /* Surfaces */
    --grid-surface: var(--bg-card, #ffffff);
    --grid-surface-alt: var(--bg-elevated, #f9fafb);
    --grid-border: var(--border-soft, #e5e7eb);
    --grid-border-input: var(--border-strong, #d1d5db);
    /* Table */
    --grid-table-surface: var(--table-surface, #ffffff);
    --grid-table-shadow: var(--table-shadow, 0 4px 12px rgba(0,0,0,.05));
    --grid-table-header-bg: var(--table-header-bg, linear-gradient(135deg,#2563eb,#1d4ed8));
    --grid-table-header-text: var(--text-on-accent, #ffffff);
    --grid-table-row-bg: var(--table-row-bg, transparent);
    --grid-table-row-alt: var(--table-row-alt, #f9fafb);
    --grid-table-row-hover: var(--table-row-hover, #e0f2fe);
    --grid-table-cell-icon-shadow: var(--table-cell-icon-shadow, none);
    --grid-table-border-badge: var(--table-border-badge, 1px solid #6b7280);
    
    /* Modal */
    --grid-modal-overlay: rgba(0,0,0,.5);
    --grid-modal-surface: var(--modal-surface, #ffffff);
    --grid-modal-shadow: var(--modal-shadow, 0 8px 25px rgba(0,0,0,.15));
    --grid-modal-footer-bg: var(--modal-footer-bg, transparent);
    --grid-modal-width: 500px;
    --grid-modal-max-h: 95%;
    /* Inputs */
    --grid-input-bg: var(--input-bg, #ffffff);
    --grid-input-border: var(--input-border, #d1d5db);
    --grid-input-border-focus: var(--input-border-strong, #2563eb);
    --grid-input-shadow-focus: var(--input-shadow-focus, 0 0 0 3px rgba(37,99,235,.2));
    --grid-select-option-bg: var(--select-option-bg, #ffffff);
    --grid-select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M5 7.5 10 12.5 15 7.5' stroke='currentColor' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    /* Buttons — primary (create / save / back) */
    --grid-btn-primary-bg: var(--interactive-accent-glow, linear-gradient(135deg,#60a5fa,#2563eb));
    --grid-btn-primary-shadow: var(--button-shadow-soft, 0 3px 10px rgba(37,99,235,.3));
    --grid-btn-primary-shadow-hover: var(--button-shadow-strong, 0 5px 15px rgba(37,99,235,.4));
    /* Buttons — secondary (cancel) */
    --grid-btn-secondary-bg: var(--filter-bg, #d1d5db);
    --grid-btn-secondary-bg-hover: var(--hover-bg, #9ca3af);
    /* Buttons — danger (delete) */
    --grid-btn-danger-bg: var(--color-danger, #dc2626);
    --grid-btn-danger-bg-full: linear-gradient(135deg,#ff4d4d,#d32f2f);
    /* Buttons — success (import) */
    --grid-btn-success-bg: linear-gradient(135deg, var(--color-secondary-light, #4ade80), var(--color-secondary, #16a34a));
    /* Pagination */
    --grid-pagination-bg: var(--table-header-bg, linear-gradient(135deg,#60a5fa,#2563eb));
    --grid-pagination-bg-dark: #0C2442;
    --grid-pagination-bg-active: linear-gradient(135deg,#2563eb,#1d4ed8);
    --grid-pagination-btn-size: 38px;
    /* Bool icons */
    --grid-icon-true: var(--color-success, #16a34a);
    --grid-icon-false: var(--color-danger, #dc2626);
    --grid-bool-icon-size: 34px;
    /* Switch */
    --grid-switch-width: 44px;
    --grid-switch-height: 24px;
    --grid-switch-thumb-size: 18px;
    --grid-switch-off: var(--border-soft, #d1d5db);
    --grid-switch-on: var(--color-primary, #2563eb);
    --grid-switch-thumb: #ffffff;
    /* Subgrid */
    --grid-subgrid-border: var(--border-soft, #dddddd);
    --grid-subgrid-row-hover: var(--hover-bg, #f1f1f1);
    --grid-subgrid-header-bg: var(--filter-bg, #f7f7f7);
    --grid-subgrid-cell-color: var(--text-main, #333333);
    --grid-subgrid-max-h: 200px;
    /* Validation */
    --grid-error-border: var(--error-border-strong, #dc3545);
    --grid-error-outline: var(--error-outline, 0 0 0 .2rem rgba(220,53,69,.25));
    --grid-error-text: var(--error-text, #dc3545);
    /* Action column width */
    --grid-action-col: 40px;
    /* Inputs — sombra sutil de reposo (no la de foco, ver --grid-input-shadow-focus) */
    --grid-input-shadow: 0 1px 2px rgba(0,0,0,.04);
}

/* ── Utility ────────────────────────────────────────────────────────────── */
.partial-container { margin: 15px 0; }
.hidden { display: none !important; }

/* ── Headings ───────────────────────────────────────────────────────────── */
h2 {
    text-align   : center;
    font-size    : var(--grid-font-size-h2);
    font-weight  : 600;
    margin-bottom: var(--grid-gap-md);
    color        : var(--grid-text-main);
}

/* ── Table controls ─────────────────────────────────────────────────────── */
.table-controls {
    display        : flex;
    justify-content: space-between;
    margin-bottom  : var(--grid-gap-md);
    flex-wrap      : wrap;
    gap            : var(--grid-gap-md);
}

.left-controls  { display: flex; align-items: center; gap: var(--grid-gap-sm); flex-wrap: wrap; }
/* flex-wrap:wrap — bug real encontrado tras el fix de font-size (16px fijo,
   más ancho que los ~12.9px de antes): sin wrap, "+ Crear" + buscador +
   filas por página no entraban en una fila angosta (modal o móvil) y el
   texto quedaba cortado en seco en vez de acomodarse en más de una línea. */
.right-controls { display: flex; align-items: center; gap: var(--grid-gap-sm); flex-wrap: wrap; }

/* Selector de filas por página como menú contextual (ícono + "N filas" + ▾)
   — el <select> nativo se ve distinto al resto de los controles custom del
   grid, así que este dropdown propio encaja mejor con el resto de la app.
   El <select> real (#rowsPerPage-...) sigue en el DOM pero oculto: es la
   fuente de verdad que lee grid.js. Mismo --grid-control-h que el input de
   búsqueda, para que ningún control quede más alto/bajo que otro en la fila. */
/* position:relative + overflow VISIBLE a propósito: el panel (abajo) es
   descendiente con position:absolute y un ancestro con overflow:hidden lo
   recortaría igual sin importar el z-index. El colapso animado en mobile
   (ver @media) va en .rows-per-page-toggle, NO acá, por eso mismo. */
.rows-per-page-dropdown { position: relative; height: var(--grid-control-h); flex-shrink: 0; }

.rows-per-page-toggle {
    display      : flex;
    align-items  : center;
    gap          : 0.4rem;
    height       : 100%;
    box-sizing   : border-box;
    padding      : 0 0.9rem;
    border       : 1px solid var(--grid-border-input);
    border-radius: var(--grid-radius-md);
    background   : var(--grid-input-bg);
    color        : var(--grid-text-main);
    font-size    : var(--grid-font-size-md);
    box-shadow   : var(--grid-input-shadow);
    white-space  : nowrap;
    cursor       : pointer;
}

.rows-per-page-toggle:hover { background: var(--grid-tab-hover-bg, rgba(0,0,0,.04)); }
.rows-per-page-caret { font-size: 0.75rem; color: var(--grid-text-muted); }

.rows-per-page-panel {
    display      : none;
    position     : absolute;
    top          : calc(100% + 4px);
    right        : 0;
    z-index      : 20;
    min-width    : 140px;
    padding      : 0.3rem;
    border       : 1px solid var(--grid-border-input);
    border-radius: var(--grid-radius-md);
    background   : var(--grid-modal-surface, #ffffff);
    box-shadow   : var(--grid-modal-shadow, 0 8px 25px rgba(0,0,0,.15));
}

.rows-per-page-panel.open { display: flex; flex-direction: column; gap: 2px; }

.rows-per-page-option {
    padding      : 0.4rem 0.6rem;
    border       : none;
    border-radius: var(--grid-radius-sm);
    background   : transparent;
    color        : var(--grid-text-main);
    font-size    : var(--grid-font-size-md);
    text-align   : left;
    cursor       : pointer;
}

.rows-per-page-option:hover { background: var(--grid-tab-hover-bg, rgba(0,0,0,.04)); }

.rows-per-page-option.active {
    background : var(--grid-btn-primary-bg);
    color      : var(--grid-text-on-btn);
    font-weight: 500;
}

/* Solo existen en mobile — la versión "completa" de cada uno (.create-btn,
   .import-btn —también usado tal cual por el botón de Exportar de
   Transaction, ver TransactionController.ExtraToolbarHtml—, .search-box
   siempre visible) es la que se usa en desktop. El @media (max-width: 599px)
   de más abajo es el que realmente los muestra. */
.create-btn-icon,
.import-btn-icon,
.mobile-search-toggle,
.mobile-search-close {
    display: none;
}


/* ── Primary action buttons (create / import / back) ───────────────────── */
.create-btn,
.import-btn,
.back-btn {
    display        : inline-flex;
    align-items    : center;
    justify-content: center;
    /* Ícono (UiIcons, ver ActionButtonModel/_GridControls.cshtml) + texto —
       sin esto quedaban pegados, sin el respiro que sí tenía el emoji suelto
       (que llevaba su propio espacio en el string). */
    gap            : 0.4rem;
    /* height fijo (no min-height) + box-sizing:border-box — con solo
       padding vertical, "+ Crear" quedaba más bajo que el buscador y el
       menú de filas (ambos usan --grid-control-h). Mismo alto que el
       resto de los controles de la fila, en vez de dejar que el propio
       texto/padding lo determine. */
    height         : var(--grid-control-h);
    box-sizing     : border-box;
    background     : var(--grid-btn-primary-bg);
    color          : var(--grid-text-on-btn);
    padding        : 0 1.4rem;
    border         : none;
    border-radius  : var(--grid-radius-pill);
    cursor         : pointer;
    font-weight    : 500;
    box-shadow     : var(--grid-btn-primary-shadow);
    transition     : all .3s ease;
}

.import-btn { background: var(--grid-btn-success-bg); }

.create-btn:hover,
.import-btn:hover,
.back-btn:hover {
    transform : translateY(-2px);
    box-shadow: var(--grid-btn-primary-shadow-hover);
}

/* .toggle-inline y el resto de controles genéricos (switch, botones de
   acción) ahora viven en UiMetadata.Controls/wwwroot/css/controls.css. */

/* ── Search + rows-per-page controls ───────────────────────────────────── */
/* type="text" a propósito, no "input" a secas — de lo contrario esto también
   agranda los checkboxes del dropdown de columnas (.search-field-option),
   que viven dentro de .right-controls y se inflaban a 2.55rem de alto cada
   uno con padding/borde propios de un input de texto. */
/* ── Búsqueda + selector de columnas, como un solo control ──────────────── */
/* .search-box ya NO dibuja nada propio (ni borde, ni fondo, ni flex) — los
   dos intentos anteriores (borde compartido con overflow:hidden, luego
   medio borde cada uno) terminaban viéndose como dos cajas pegadas con
   doble sombra. Ahora hay un solo elemento con estilo real: el input (con
   su pill normal de .right-controls, sin tocar). El toggle flota DENTRO de
   ese padding-right extra, sin borde ni fondo propio — por eso el conjunto
   se ve como un único control, no dos. */
.search-box { position: relative; }

.search-box input[type="text"] { width: 100%; padding-right: 2.4rem; }

.search-box .search-field-dropdown {
    position : absolute;
    top      : 0;
    right    : 0;
    height   : 100%;
}

/* ✕ limpiar búsqueda: flota a la derecha del input, antes del ▾ de columnas
   (si existe, va justo a su izquierda). Solo se ve con texto escrito. */
.search-clear {
    display        : none;
    position       : absolute;
    top            : 0;
    right          : 0.4rem;
    height         : 100%;
    width          : 1.6rem;
    padding        : 0;
    border         : none;
    background     : transparent;
    color          : var(--grid-text-muted);
    cursor         : pointer;
    align-items    : center;
    justify-content: center;
}

.search-field-dropdown ~ .search-clear { right: 2.4rem; }
.search-box.has-value .search-clear    { display: flex; }
.search-clear:hover                    { color: var(--grid-text-main); }
.search-box.has-value:has(.search-field-dropdown) input[type="text"] { padding-right: 4.2rem; }
.search-box.has-value:not(:has(.search-field-dropdown)) input[type="text"] { padding-right: 2.2rem; }

.right-controls input[type="text"],
.right-controls select {
    box-sizing  : border-box;
    min-height  : var(--grid-control-h);
    padding     : 0.65rem 0.9rem;
    border      : 1px solid var(--grid-border-input);
    border-radius: var(--grid-radius-md);
    /* 16px fijo (no el token en rem) — con html{font-size:14px} de
       common.css, var(--grid-font-size-md) renderiza en ~12.9px reales,
       por debajo del mínimo que evita el auto-zoom de iOS Safari al hacer
       foco. Fix puntual (Fase 2, decisión A) — no se tocó el root font-size
       global para no afectar el resto de la app. Ver
       responsive-audit-report.md, hallazgo B3. */
    font-size   : 16px;
    background  : var(--grid-input-bg);
    color       : var(--grid-text-main);
    box-shadow  : var(--grid-input-shadow);
    transition  : border-color .2s ease, box-shadow .2s ease, background .2s ease;
}

.right-controls select,
.ui-modal-content select,
.subgrid-container td select {
    appearance        : none;
    -webkit-appearance: none;
    -moz-appearance   : none;
    padding-right     : 2.75rem;
    background        : var(--grid-input-bg) var(--grid-select-arrow) no-repeat calc(100% - 14px) 50% / 16px 16px !important;
}

.right-controls input::placeholder { color: var(--grid-text-muted); }

.right-controls option,
.ui-modal-content option,
.subgrid-container option {
    background: var(--grid-select-option-bg);
    color     : var(--grid-text-main);
}

/* ── Barra de filtros desplegables (_GridFilters.cshtml) ────────────────────
   Mismo tratamiento que los select de .right-controls/.ui-modal-content:
   appearance:none + flecha propia, y color/fondo explícitos en <option> — sin esto
   el popup abierto usa el chrome del sistema y, en tema oscuro, queda texto blanco
   sobre fondo blanco (las opciones no se ven). */
.grid-filters {
    display  : flex;
    flex-wrap: wrap;
    gap      : 1rem;
    margin   : 0 0 1rem;
}

.grid-filter {
    display: grid;
    gap    : 0.3rem;
    min-width: 150px;
}

.grid-filter-label {
    font-size: 0.8rem;
    color    : var(--grid-text-muted);
}

.grid-filters select {
    appearance        : none;
    -webkit-appearance: none;
    -moz-appearance   : none;
    box-sizing        : border-box;
    min-height        : var(--grid-control-h);
    padding           : 0.5rem 2.75rem 0.5rem 0.9rem;
    border            : 1px solid var(--grid-border-input);
    border-radius     : var(--grid-radius-md);
    /* 16px fijo: evita el auto-zoom de iOS Safari al hacer foco (ver .right-controls). */
    font-size         : 16px;
    color             : var(--grid-text-main);
    background        : var(--grid-input-bg) var(--grid-select-arrow) no-repeat calc(100% - 14px) 50% / 16px 16px;
    cursor            : pointer;
}

.grid-filters select:focus {
    outline     : none;
    border-color: var(--grid-input-border-focus);
    box-shadow  : var(--grid-input-shadow-focus);
}

.grid-filters option {
    background: var(--grid-select-option-bg);
    color     : var(--grid-text-main);
}

@media (max-width: 599px) {
    .grid-filter { flex: 1 1 140px; }
}

/* ── Dropdown de columnas del buscador (filtro por varias a la vez) ──────── */
.search-field-dropdown { position: relative; height: 100%; }

/* Solo el ícono ▾, sin texto "Columnas" — antes era un botón ancho suelto al
   lado del input, con su propio borde/padding. Ahora flota transparente
   sobre el padding-right que le dejó el input (ver .search-box), sin borde
   ni fondo propio, para que el conjunto se lea como un solo control. */
.search-field-toggle {
    height        : 100%;
    width         : 2.4rem;
    padding       : 0;
    border        : none;
    border-radius : var(--grid-radius-md);
    background    : transparent;
    color          : var(--grid-text-muted);
    font-size      : large;
    cursor         : pointer;
}

.search-field-toggle:hover { color: var(--grid-text-main); }

.search-field-panel {
    display      : none;
    position     : absolute;
    top          : calc(100% + 4px);
    right        : 0;
    z-index      : 20;
    min-width    : 180px;
    max-height   : 260px;
    overflow-y   : auto;
    padding      : 0.3rem;
    border       : 1px solid var(--grid-border-input);
    border-radius: var(--grid-radius-md);
    background   : var(--grid-modal-surface, #ffffff);
    box-shadow   : var(--grid-modal-shadow, 0 8px 25px rgba(0,0,0,.15));
}

.search-field-panel.open { display: flex; flex-direction: column; gap: 2px; }

.search-field-option {
    display     : flex;
    align-items : center;
    gap         : 8px;
    padding     : 0.4rem 0.5rem;
    border-radius: var(--grid-radius-sm);
    font-size   : var(--grid-font-size-md);
    line-height : 1.1;
    color       : var(--grid-text-main);
    cursor      : pointer;
}

.search-field-option input[type="checkbox"] {
    margin: 0;
}

.search-field-option:hover { background: var(--grid-tab-hover-bg, rgba(0,0,0,.04)); }

/* "Seleccionar todo": separado de las columnas con una línea. */
.search-field-all {
    margin-bottom : 2px;
    padding-bottom: 0.5rem;
    border-bottom : 1px solid var(--grid-border-input);
    border-radius : var(--grid-radius-sm) var(--grid-radius-sm) 0 0;
    font-weight   : 600;
}

/* ── Table ──────────────────────────────────────────────────────────────── */
.table {
    border-radius: var(--grid-radius-lg);
    overflow     : hidden;
    border       : 1px solid var(--grid-border);
    box-shadow   : var(--grid-table-shadow);
    background   : var(--grid-table-surface);
}

.table-header,
.table-row {
    display              : grid;
    grid-template-columns: var(--grid-template-columns, repeat(auto-fit,minmax(140px,1fr)));
    /* Sin esto, columnas angostas (ej. con el ocultamiento progresivo activo)
       quedaban con el texto pegado sin separación visible entre celdas
       vecinas — "NombreActivo" en vez de "Nombre  Activo". */
    gap                   : var(--grid-gap-sm, 0.5rem);
    padding               : 0.75rem 1rem;
    align-items           : center;
    text-align            : center;
    box-sizing            : border-box;
}

.table-row {
    min-height  : 3.7rem;
    padding     : 0.10rem 1rem;
}

.table-header {
    background : var(--grid-table-header-bg);
    color      : var(--grid-table-header-text);
    font-weight: bold;
}

/* ── Orden por columna (click en el header, "como Excel") ────────────────
   Solo en las columnas de datos reales — las de acción (__details, __delete,
   __rowaction) usan .details-col en el header, no .table-cell, así que
   nunca caen acá (ver initSortableColumns en grid.js). El ícono cambia de
   ambos triángulos (sin ordenar) a solo ▲ o ▼ vía clases que agrega/saca JS al clickear. */
.table-header .table-cell.sortable-column {
    display    : flex;
    align-items: center;
    justify-content: center;
    gap        : 0.3rem;
    cursor     : pointer;
    user-select: none;
}

.table-header .table-cell.sortable-column:hover { background: rgba(255, 255, 255, .12); }

.sort-indicator {
    display    : inline-flex;
    align-items: center;
    flex-shrink: 0;
    opacity    : .55;
}

/* SVG en línea (ver _Grid.cshtml): dos triángulos; el activo se enciende y el otro se apaga. */
.sort-indicator svg { width: 0.55rem; height: 0.9rem; fill: currentColor; }
.sort-indicator .sort-up,
.sort-indicator .sort-down { opacity: .85; }

.table-header .table-cell.sortable-column.sorted-asc .sort-indicator,
.table-header .table-cell.sortable-column.sorted-desc .sort-indicator {
    opacity: 1;
}

.table-header .table-cell.sortable-column.sorted-asc .sort-down,
.table-header .table-cell.sortable-column.sorted-desc .sort-up { opacity: .2; }

.table-row {
    color: var(--grid-text-main);
}

/* No existía ninguna regla base para .table-cell — sin overflow/white-space,
   cuando una columna se achica (minmax(0,1fr) permite reducirla hasta 0) el
   texto no se ajusta a su caja: se desborda VISUALMENTE encima de la celda
   vecina en vez de recortarse, dando la sensación de columnas "pegadas"
   ("NombreActivo") aunque el gap entre tracks esté bien puesto — el gap
   separa los tracks, no evita que el contenido se derrame fuera del suyo.
   overflow:hidden + ellipsis es el tratamiento estándar de tabla angosta:
   trunca con "…" en vez de solaparse; con el ocultamiento progresivo
   (GridPriority) las columnas que sí quedan visibles rara vez llegan a
   activar la elipsis, ya que el propio algoritmo las mantiene por encima
   del umbral legible. */
.table-cell {
    overflow     : hidden;
    text-overflow: ellipsis;
    white-space  : nowrap;
}

/* Placeholder "—" de un valor vacío (ver _Grid.cshtml) — más apagado que el
   texto normal, para que se lea como "no hay dato" y no como contenido
   real desalineado o una celda rota. */
.table-cell-empty { color: var(--grid-text-muted, #6b7280); }

/* Celda de un campo bool (ver _Grid.cshtml + _BoolIcon.cshtml) — nunca tuvo
   una regla propia, solo la de .table-cell de arriba (block, sin centrar).
   El ícono (34px, ver --grid-bool-icon-size) quedaba pegado al borde
   izquierdo en vez de centrado en la columna. */
.table-cell-icon {
    display        : flex;
    align-items    : center;
    justify-content: center;
}

.table-row:nth-child(even) { background-color: var(--grid-table-row-alt); }

.table-row:hover {
    background-color: var(--grid-table-row-hover);
    cursor          : pointer;
}

    .table-row.row-deleted {
        opacity: 0.5;
    }

        .table-row.row-deleted .table-cell {
            text-decoration: line-through;
        }

.details-col { width: var(--grid-action-col); }

/* ── Ocultamiento progresivo de columnas (patrón "FooTable") ─────────────
   Ver GridPriorityAttribute (UiMetadata.Contracts), grid.js
   (recalcResponsiveColumns) y responsive-audit-report.md. Solo aparecen en
   el DOM cuando el grid realmente tiene columnas [GridPriority] Y el ancho
   disponible obliga a ocultar alguna — en cualquier otro grid, esta caja no
   se crea nunca. */
.row-expand-toggle {
    display        : flex;
    align-items    : center;
    justify-content: center;
    width          : 100%;
    height         : 100%;
    padding        : 0;
    border         : none;
    border-radius  : var(--grid-radius-sm);
    background     : transparent;
    color          : var(--grid-text-muted);
    /* 1.1rem, no 0.75rem — el glyph quedaba casi invisible, sobre todo con
       el color muted. Sigue siendo el mismo ancho de columna (40px, igual
       que las acciones) — lo que cambia es que el ícono realmente se ve. */
    font-size      : 1.65rem;
    line-height    : 1;
    transition     : background-color .15s ease, color .15s ease;
}

button.row-expand-toggle {
    cursor: pointer;
}

button.row-expand-toggle:hover {
    background: var(--grid-table-row-hover);
    color     : var(--grid-text-main);
}

.table-row-detail {
    display              : none; /* grid.js lo cambia a "grid" al expandir */
    grid-template-columns: repeat(auto-fit, minmax(1, 1fr));
    gap                  : 0.3rem 1rem;
    padding              : 0.6rem 1rem 0.9rem calc(1rem + var(--grid-action-col));
    background           : var(--grid-table-row-alt);
    border-top           : 1px dashed var(--grid-border);
}

.table-row-detail-item { display: flex; gap: 0.35rem; font-size: var(--grid-font-size-sm); }
.table-row-detail-label { color: var(--grid-text-muted); font-weight: 600; white-space: nowrap; }
.table-row-detail-value { color: var(--grid-text-main); }

/* ── Acciones compactas en móvil (menú contextual) ───────────────────────
   Debajo de 599px (breakpoint móvil acordado) las columnas de acción
   (editar/eliminar/acción custom) se reemplazan por una sola columna: un
   botón ⋮ que abre .grid-actions-menu, o la acción directa si la fila tiene
   una sola disponible. Lo arma grid.js (updateRowActionsCell /
   openGridActionsMenu) leyendo los botones que la fila ya trae renderizados,
   así los permisos por fila (CanOpenModal/CanDeleteRow/CanRowAction) se
   respetan solos y cada opción dispara el botón original. */
.row-actions-cell {
    display        : flex;
    align-items    : center;
    justify-content: center;
}

.row-actions-trigger {
    display        : inline-flex;
    align-items    : center;
    justify-content: center;
    min-width      : 44px;
    min-height     : 44px;
    padding        : 0;
    border         : none;
    border-radius  : var(--grid-radius-sm);
    background     : transparent;
    color          : var(--grid-text-main);
    font-size      : 1.35rem;
    line-height    : 1;
    cursor         : pointer;
}

.row-actions-trigger:hover,
.row-actions-trigger[aria-expanded="true"] { background: var(--grid-table-row-hover); }

/* position:fixed y colgado de <body>, no dentro de la fila: .table y
   .table-cell tienen overflow:hidden y recortarían un menú absoluto. */
.grid-actions-menu {
    position     : fixed;
    z-index      : 10000;
    min-width    : 200px;
    padding      : 0.35rem;
    border       : 1px solid var(--grid-border);
    border-radius: var(--grid-radius-md);
    background   : var(--grid-modal-surface);
    box-shadow   : var(--grid-modal-shadow);
}

.grid-actions-menu-item {
    display      : flex;
    align-items  : center;
    gap          : 0.75rem;
    width        : 100%;
    min-height   : 44px;
    padding      : 0 0.85rem;
    border       : none;
    border-radius: var(--grid-radius-sm);
    background   : transparent;
    color        : var(--grid-text-main);
    font-size    : 1rem;
    text-align   : left;
    cursor       : pointer;
}

.grid-actions-menu-item:hover { background: var(--grid-table-row-hover); }
.grid-actions-menu-icon       { width: 1.5rem; text-align: center; }

/* .table-badge y .bool-icon (_BoolIcon.cshtml) ahora viven en
   UiMetadata.Elements/wwwroot/css/elements.css. */

/* El overlay/contenedor/cabecera/acciones del modal (.ui-modal, .ui-modal-content,
   .modal-header-custom, .modal-actions, .cancel-btn/.save-btn/.btn-clear)
   ahora viven en UiMetadata.Modal/wwwroot/css/modal.css. */

/* ── Modal inputs ───────────────────────────────────────────────────────── */
/* Sin input[type="date"] — ya no existe ninguno (ver _DateInput.cshtml,
   ahora type="text" + flatpickr); ese selector ya cubre tanto el input real
   (.ui-date-input) como el alt-input visible que crea flatpickr (también
   type="text" por default). */
.ui-modal-content input[type="text"],
.ui-modal-content input[type="number"],
.ui-modal-content select,
.ui-modal-content textarea {
    width        : 100%;
    padding      : 0.3rem 0.8rem;
    margin-bottom: 0.1rem;
    border       : 1px solid var(--grid-input-border);
    border-radius: var(--grid-radius-md);
    /* 16px fijo — mismo motivo que .right-controls arriba: var(--grid-font-size-base)
       renderiza en ~13.3px reales con el root de 14px de common.css, por
       debajo del umbral que evita el zoom automático de iOS Safari en
       cualquier input de un modal de alta/edición. */
    font-size    : 16px;
    font-family  : inherit; /* <textarea> por default cae a monospace en la mayoría de los navegadores */
    background   : var(--grid-input-bg);
    color        : var(--grid-text-main);
    box-shadow   : var(--grid-input-shadow);
    transition   : border-color .2s ease, box-shadow .2s ease;
}

.ui-modal-content textarea { resize: vertical; }

/* Sin input[type="number"] — ya no existe ninguno (_NumberInput.cshtml
   ahora es type="text" + .ui-number-input, ver elements.js), así que ni el
   ocultamiento de flechitas de stepper nativas ni el selector de arriba
   (input[type="text"]) necesitan ningún caso especial: el input real ya
   nace sin flechitas propias del navegador, y el estilo de texto normal ya
   le alcanza. */

.ui-modal-content input:focus,
.ui-modal-content select:focus,
.ui-modal-content textarea:focus {
    outline     : none;
    border-color: var(--grid-input-border-focus);
    box-shadow  : var(--grid-input-shadow-focus);
}

.ui-modal-content textarea { resize: vertical; min-height: 80px; }

.ui-modal-content label {
    display      : block;
    margin-bottom: 0.3rem;
    font-weight  : 500;
    font-size    : var(--grid-font-size-md);
    color        : var(--grid-text-main);
}

.form-field { margin-bottom: 0.6rem; }

/* Campo booleano (interruptor, _Switch.cshtml): etiqueta a la izquierda y el interruptor en el extremo
   derecho, en una sola línea. Antes quedaban apilados y pegados a la izquierda. */
.form-field:has(> .switch-wrapper) {
    display        : flex;
    align-items    : center;
    justify-content: space-between;
    gap            : 1rem;
    padding        : 0.2rem 0;
}

.form-field:has(> .switch-wrapper) > label { margin-bottom: 0; }

/* LockedFields sobre select/checkbox/radio (ver openGridRowDetails en grid.js)
   — deliberadamente NO usa el atributo disabled: un campo disabled no viaja
   en el FormData al guardar, así que perdía su valor en el submit. Esto
   bloquea la interacción a mano dejando el campo habilitado. */
.field-locked {
    pointer-events: none;
    opacity: 0.65;
    background: var(--grid-input-bg-disabled, rgba(148, 163, 184, .15));
}

/* Ícono "?" junto al label ([FieldHintAttribute]) — tooltip nativo (title),
   sin JS: a diferencia de placeholder, queda disponible aunque el campo ya
   tenga texto escrito. */
.field-hint {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    margin-left: 4px;
    border-radius: 50%;
    background: var(--grid-text-muted, #999);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    cursor: help;
    user-select: none;
}

/* .cancel-btn/.save-btn/.btn-clear ahora viven en
   UiMetadata.Modal/wwwroot/css/modal.css. Botones de acción
   (.btn-action/.btn-add/.btn-delete) y el switch booleano (.switch/.slider)
   ahora viven en UiMetadata.Controls/wwwroot/css/controls.css. */

/* ── Subgrid (lists inside modal) ───────────────────────────────────────── */
/* Sin overflow-x — se probó agregarlo (Fase 3 del audit responsive) pero
   sumaba una segunda barra de scroll (horizontal + vertical a la vez)
   dentro de un modal que ya scrollea verticalmente, sensación de "todo
   scrollea" que no convenció. Revertido a como estaba: solo overflow-y. El
   overflow horizontal real de una fila ancha (hallazgo B2) queda pendiente
   de una solución que no sea agregar scroll. */
.subgrid-container {
    width        : 100%;
    max-height   : var(--grid-subgrid-max-h);
    overflow-y   : auto;
    margin-top   : 0;
    border       : 1px solid var(--grid-subgrid-border);
    border-radius: var(--grid-radius-sm);
}

.subgrid-container table {
    width          : 100%;
    border-collapse: collapse;
    font-size      : var(--grid-font-size-base);
}

.subgrid-container th,
.subgrid-container td {
    padding      : 0 8px;
    border-bottom: 1px solid var(--grid-border);
    text-align   : left;
    white-space  : nowrap;
    color        : var(--grid-text-main);
}

/* Padding vertical fijo aquí (no en los botones) para que la altura de las filas
   de participantes sea siempre la misma, tengan o no botones de editar/eliminar.
   Solo en tbody — la fila del <select> "añadir participante" (tfoot) no se toca. */
.subgrid-container tbody td {
    padding: 10px 8px;
}

.subgrid-container th {
    padding         : 5px 15px;
    background-color: var(--grid-subgrid-header-bg);
    font-weight     : 600;
}

.subgrid-container tr:hover    { background-color: var(--grid-subgrid-row-hover); }
.subgrid-container td select   { margin: 5px 0; font-size: 16px; }

.subgrid-container .cell-value {
    display: inline-block;
    width  : 100%;
    color  : var(--grid-subgrid-cell-color);
}

.subgrid-container .btn-action { cursor: pointer; text-decoration: none; }

.addRelation select { width: 70%; }

/* ── Validation ─────────────────────────────────────────────────────────── */
.field-validation-error {
    display   : block;
    margin-top: 5px;
    font-size : var(--grid-font-size-sm);
    color     : var(--grid-error-text);
}

.field-validation-valid { display: none; }

.input-validation-error {
    border-color: var(--grid-error-border) !important;
    box-shadow  : var(--grid-error-outline);
}

.subgrid-row-error { border: 2px solid var(--grid-error-border) !important; }

/* ── Pagination ─────────────────────────────────────────────────────────── */
.pagination {
    display        : flex;
    align-items    : center;
    justify-content: center;
    gap            : var(--grid-gap-xs);
    margin-top     : var(--grid-gap-sm);
}

.pagination-button {
    display        : inline-flex;
    align-items    : center;
    justify-content: center;
    width          : var(--grid-pagination-btn-size);
    height         : var(--grid-pagination-btn-size);
    padding        : 6px;
    border         : none;
    border-radius  : var(--grid-radius-sm);
    background     : var(--grid-pagination-bg-dark);
    color          : var(--grid-text-on-btn);
    cursor         : pointer;
    transition     : background-color .2s ease, transform .1s ease;
}

.pagination-button:disabled { opacity: .4; cursor: default; }
.pagination-button.active   { background: var(--grid-pagination-bg-active); }

.pagination-icon {
    width : 100%;
    height: 100%;
}

.pagination-info { font-size: var(--grid-font-size-sm); color: var(--grid-text-main); }

/* .confirm-overlay/.confirm-modal ahora viven en
   UiMetadata.Modal/wwwroot/css/modal.css, con un consumidor real
   (confirmDialog() en confirm.js) — antes eran CSS sin JS que lo usara. */

/* ── Misc ────────────────────────────────────────────────────────────────── */
.bi-upload { font-size: 20px; }

/* ── Responsive (Fase 3 — ver responsive-audit-report.md) ──────────────────
   Breakpoints acordados en Fase 2: móvil ≤599px, tablet 600-1023px, desktop
   ≥1024px. Desktop-first a propósito (decisión de Fase 2, no mobile-first):
   las reglas base de arriba asumen desktop, esto solo las sobreescribe hacia
   abajo — nada cambia en escritorio. */
@media (max-width: 1023px) {
    /* Zona táctil ≥44px en el botón de paginación — 38px por defecto
       (--grid-pagination-btn-size) queda corto en tablet/móvil. Redefinir la
       custom property dentro del media query es válido (no es lo mismo que
       usar var() DENTRO de la condición del @media, que ningún navegador
       soporta) — todo lo que consume el token vía var(--grid-pagination-btn-size)
       se actualiza solo. Ver hallazgo I1. */
    :root {
        --grid-pagination-btn-size: 44px;
    }
}

@media (max-width: 599px) {
    /* ── "+ Crear" como ícono, a la izquierda ────────────────────────────
       En desktop .create-btn sigue inline con texto, como siempre. Acá se
       oculta y en su lugar se ve .create-btn-icon (mismo botón, mismo
       handler, solo "+") — al ser del mismo tamaño que el ícono de lupa,
       "+ Crear" y el buscador entran en una sola fila sin necesidad de un
       FAB flotante (iteración anterior, descartada: con todo en íconos ya
       sobra ancho). */
    .create-btn { display: none; }

    /* Mismo criterio que "+ Crear": en mobile solo el ícono, nunca el texto
       completo — ver .import-btn-icon más abajo (mismo botón/handler, y
       reusado tal cual por el ícono de Exportar de Transaction, que
       comparte la clase .import-btn en su versión de texto). */
    .import-btn { display: none; }

    .create-btn-icon,
    .import-btn-icon {
        display        : flex;
        align-items    : center;
        justify-content: center;
        flex-shrink    : 0;
        box-sizing     : border-box;
        width          : var(--grid-control-h);
        height         : var(--grid-control-h);
        padding        : 0;
        border         : none;
        border-radius  : 50%;
        background     : var(--grid-btn-primary-bg);
        color           : var(--grid-text-on-btn);
        box-shadow      : var(--grid-btn-primary-shadow);
        cursor          : pointer;
        transition      : opacity .15s ease;
    }

    /* Mismo verde/success que su contraparte de escritorio (.import-btn,
       regla de arriba del @media) — si no, en mobile pierde la distinción
       visual entre "crear" (primary) e "importar/exportar" (success). */
    .import-btn-icon { background: var(--grid-btn-success-bg); }

    /* Se desvanecen mientras se busca (ver .table-controls.search-expanded
       abajo) — solo para no competir visualmente con el buscador, ya NO
       hace falta que también achiquen su ancho (ver por qué en el comentario
       grande de acá abajo): siguen ocupando su lugar en el flujo, nomás
       invisibles. */
    .table-controls.search-expanded .create-btn-icon,
    .table-controls.search-expanded .import-btn-icon {
        opacity       : 0;
        pointer-events: none;
    }

    /* ── Buscador colapsable ──────────────────────────────────────────────
       La versión anterior animaba el max-width de TRES elementos a la vez
       dentro de la misma fila flex (lupa achicándose + menú de filas
       achicándose + buscador creciendo) — flexbox recalcula el layout de
       todos en cada frame en función de los demás, y esa interdependencia
       se sentía "rara"/entrecortada en vez de un solo movimiento limpio.
       Ahora .search-box es un overlay position:absolute sobre TODO
       .right-controls (que a su vez es flex:1, así siempre tiene el ancho
       completo disponible ya reservado, no algo que cambia mientras se
       anima) — es la ÚNICA caja que anima su ancho, sin nada más
       compitiendo por espacio en el mismo instante. Lupa y menú de filas
       ya no cambian de tamaño: solo se desvanecen (opacity) donde están. */
    .right-controls {
        position       : relative;
        flex           : 1 1 auto;
        justify-content: flex-end;
        min-width      : 0;
    }

    .mobile-search-toggle,
    .rows-per-page-toggle {
        flex-shrink: 0;
        transition : opacity .15s ease;
    }

    .mobile-search-toggle {
        display        : flex;
        align-items    : center;
        justify-content: center;
        box-sizing     : border-box;
        width          : var(--grid-control-h);
        height         : var(--grid-control-h);
        padding        : 0;
        border         : 1px solid var(--grid-border-input);
        border-radius  : var(--grid-radius-md);
        background     : var(--grid-input-bg);
        color          : var(--grid-text-main);
        font-size      : 1.1rem;
        box-shadow     : var(--grid-input-shadow);
        cursor         : pointer;
    }

    .table-controls.search-expanded .mobile-search-toggle,
    .table-controls.search-expanded .rows-per-page-toggle {
        opacity       : 0;
        pointer-events: none;
    }

    /* pointer-events también en el WRAPPER (.rows-per-page-dropdown), no
       solo en el botón de adentro (.rows-per-page-toggle, arriba): el
       wrapper es position:relative (positioned) y va después del buscador
       en el HTML, así que sin esto pinta ENCIMA del buscador expandido y
       se queda con los clics de esa zona — tapando en silencio el ▾ de
       columnas que vive debajo, dentro de .search-box, aunque el wrapper
       en sí no tenga ningún contenido visible propio. */
    .table-controls.search-expanded .rows-per-page-dropdown {
        pointer-events: none;
    }

    .search-box {
        display       : flex;
        position      : absolute;
        top           : 0;
        right         : 0;
        bottom        : 0;
        /* right:0 (no left:0/inset) a propósito — la lupa vive pegada al
           borde derecho (justify-content:flex-end en .right-controls), así
           que el buscador tiene que crecer HACIA LA IZQUIERDA desde ese
           mismo borde al abrirse, no aparecer pegado a la izquierda de la
           fila (se vería como si arrancara de la nada, lejos del ícono que
           tocaste). */
        max-width     : 0;
        opacity       : 0;
        overflow      : hidden;
        pointer-events: none;
        /* opacity con transition-delay al abrir (ver la regla de
           .table-controls.search-expanded .search-box) — el input aparece
           recién cuando la caja ya casi terminó de crecer, no de golpe
           mientras todavía se está abriendo. */
        transition    : max-width .32s cubic-bezier(.25,.1,.25,1), opacity .2s ease;
    }

    .table-controls.search-expanded .search-box {
        max-width       : 100%;
        opacity         : 1;
        transition-delay: 0s, .16s;
        pointer-events  : auto;
        /* overflow no es animable, así que este cambio es instantáneo al
           expandir (no espera a que termine la transición de max-width) —
           sin esto, el panel de checkboxes de columnas (.search-field-panel,
           position:absolute DENTRO de .search-box) queda recortado por el
           overflow:hidden de acá arriba y no se ve nunca al abrirlo. */
        overflow        : visible;
    }

    /* padding-left para el botón ✕ (ver abajo), que en desktop no existe
       (padding normal de .right-controls input ya alcanza). */
    .table-controls.search-expanded .search-box input[type="text"] {
        padding-left: 2.4rem;
    }

    .mobile-search-close {
        display        : none;
        position       : absolute;
        top            : 0;
        left           : 0;
        height         : 100%;
        width          : 2.4rem;
        align-items    : center;
        justify-content: center;
        border         : none;
        background     : transparent;
        color          : var(--grid-text-muted);
        cursor         : pointer;
    }

    .table-controls.search-expanded .mobile-search-close { display: flex; }

    .table-header,
    .table-row {
        padding: 0.60rem 0;
    }

    /* Tipografía más chica en tablas: iPhone 13 mini (375px) / 14 Pro (390px)
       dejan ~76-81px por columna con 3 columnas de datos, y "Descripción" +
       su ícono de orden (~90px a 14px) no entraba. El header es un flex
       centrado con overflow:hidden, así que lo que no cabe se recortaba por
       AMBOS lados ("escripción"); tamaño menor + "safe center" (si igual no
       cabe, recorta solo el final, nunca el inicio). Las filas bajan un poco
       también para que importes/fechas no se corten con "…". */
    .table-header { font-size: 0.82rem; }

    .table-header .table-cell.sortable-column {
        gap            : 0.15rem;
        justify-content: safe center;
    }

    .sort-indicator svg { width: 0.5rem; height: 0.8rem; }

    .table-row { font-size: 0.9rem; }

    /* Texto libre (descripciones, nombres): hasta DOS renglones en vez de cortarse con "…" en el
       primero. Las filas ya miden 3.7rem como mínimo, así que dos líneas caben sin crecer.
       Solo las celdas de texto (.table-cell-text): importes, fechas e íconos siguen en una línea. */
    .table-row .table-cell.table-cell-text {
        display           : -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp        : 2;
        white-space       : normal;
        overflow-wrap     : anywhere;
        line-height       : 1.25;
    }

    /* La flecha de _SignIndicator (svg con width/height como atributo, 18px)
       y su margen inline (4px) — CSS gana sobre el atributo de tamaño; el
       margin es inline, de ahí el !important. Acotado a ESTA clase (antes
       era ".table-row .table-cell svg", que de paso achicaba CUALQUIER otro
       SVG en una celda — ej. .bool-icon, ver _BoolIcon.cshtml, quedaba en
       13px en vez de sus 34px, casi invisible en la columna "Activo"). */
    .table-row .table-cell .sign-indicator-icon {
        width       : 13px;
        height      : 13px;
        margin-right: 2px !important;
    }
}
