html, body {
    margin: 0;
    font-family: 'Roboto', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    /* Sigue la paleta de MudBlazor (Primary) en claro y oscuro; el hex es solo el fallback
       mientras el CSS de Mud aún no carga. */
    color: var(--mud-palette-primary, #1565c0);
}

/* Pantalla de carga inicial mientras el runtime de WASM se descarga. */
.cargador-inicial {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    color: #555;
}

.loading-progress-text {
    font-size: 1.1rem;
}

#blazor-error-ui {
    background: #ffe082;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 3000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ── Homologación del grid de Syncfusion con la paleta de MudBlazor (modo oscuro) ──────
   El tema bootstrap5-dark de Syncfusion trae grises fríos que desentonan con la paleta de
   Mud. En vez de duplicar los hex a mano (frágil: hay que mantenerlos en sincronía con el
   PaletteDark de C#), mapeamos el grid a las variables --mud-palette-* que MudBlazor emite y
   VOLTEA SOLO con el tema → homologación automática: si personalizas la paleta en MainLayout,
   el grid la sigue sin tocar este CSS. El gancho body.tema-oscuro lo pone
   window.cambiarTemaSyncfusion (index.html) en el mismo toggle que MudBlazor. */
body.tema-oscuro .e-grid,
body.tema-oscuro .e-grid .e-content,
body.tema-oscuro .e-grid .e-table,
body.tema-oscuro .e-grid .e-rowcell,
body.tema-oscuro .e-grid .e-emptyrow td {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-table-lines);
}

body.tema-oscuro .e-grid .e-gridheader,
body.tema-oscuro .e-grid .e-headercell,
body.tema-oscuro .e-grid .e-headercelldiv,
body.tema-oscuro .e-grid .e-headercontent {
    background-color: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-table-lines);
}

body.tema-oscuro .e-grid .e-altrow .e-rowcell {
    background-color: var(--mud-palette-table-striped);
}

body.tema-oscuro .e-grid .e-row:hover .e-rowcell {
    background-color: var(--mud-palette-table-hover);
}

body.tema-oscuro .e-grid .e-gridpager,
body.tema-oscuro .e-grid .e-pager {
    background-color: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-color: var(--mud-palette-table-lines);
}

/* ── Barra de grid homologada (BarraGrid) ────────────────────────────────────────────────
   Grid de 3 zonas: la búsqueda queda clavada al centro REAL de la barra sin importar cuánto
   pese cada lado. En pantallas angostas se apila en columna. */
.barra-grid {
    display: grid;
    /* minmax(0,1fr): sin el 0, la zona con contenido ancho (p. ej. el botón "Nuevo") no
       puede encogerse por debajo de su contenido y empuja la búsqueda fuera del centro. */
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: .75rem;
}
.barra-grid-zona {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
}
.barra-grid-der {
    justify-content: flex-end;
}
.barra-grid-busqueda {
    min-width: 280px;
    max-width: 380px;
}
@media (max-width: 900px) {
    .barra-grid {
        grid-template-columns: 1fr;
    }
    .barra-grid-busqueda {
        max-width: none;
    }
    .barra-grid-der {
        justify-content: flex-start;
    }
}

/* Filtro embebido en el encabezado de columna (FiltroColumna): campo de texto + chevron con
   los valores distintos. Compacto, tipografía de encabezado y sin ensanchar la columna más
   allá de su contenido. */
.filtro-columna {
    display: flex;
    align-items: center;
    gap: 2px;
    min-width: 90px;
}
.filtro-columna .filtro-columna-texto {
    margin-top: 0;
    flex: 1 1 auto;
}
.filtro-columna .mud-input {
    font-size: .875rem;
    font-weight: 500;
}

/* Encabezados de columna en MODO LIMPIO (parámetro Limpio de FiltroColumna/FiltroColumnaFecha/
   EncabezadosGrid): el título va en versalitas y el filtro (texto en vivo + valores distintos o
   calendario) vive en el desplegable. El ícono se atenúa hasta que hay un filtro activo, y
   entonces el título toma el color de acento (aquí --mud-palette-primary; la plantilla no tiene
   una variable de acento aparte). El modo clásico queda intacto por default. */
.filtro-limpio-titulo {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .72rem;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
}
.filtro-limpio-titulo .mud-icon-root {
    opacity: .4;
}
.filtro-limpio-activo {
    color: var(--mud-palette-primary);
}
.filtro-limpio-activo .mud-icon-root {
    opacity: 1;
}
.filtro-limpio-plano {
    cursor: default;
}

/* Los grids usan TODO el alto disponible del viewport y se reajustan al redimensionar
   la ventana (dvh es dinámico). Con FixedHeader el cuerpo scrollea y los títulos quedan
   fijos. Desglose del descuento (medido en el QA de cps, hallazgo #32/#42): appbar 64 +
   pt-4 del main 16 + BarraGrid 72 + mb-3 12 + reserva del botón "Cargar más" 64 + margen 2
   = 230px. El 290 anterior dejaba ~60px de franja blanca al fondo.
   RE-MIDE: estos offsets corresponden al layout de ESTA app; al clonar o cambiar el chrome,
   vuelve a medir (ver docs/articles/checklist-qa.md §3). */
.grid-lleno .mud-table-container {
    max-height: calc(100vh - 230px);
    max-height: calc(100dvh - 230px);
    min-height: 240px;
}

/* Asa de redimensionado de columnas (la instala js/estado-grid.js en los th[data-col]):
   franja invisible en el borde derecho del encabezado con cursor col-resize. */
.grid-redim {
    position: absolute;
    top: 0;
    right: 0;
    width: 6px;
    height: 100%;
    cursor: col-resize;
    user-select: none;
}
.grid-redim:hover {
    background: var(--mud-palette-primary);
    opacity: .35;
}

/* Título de la página centrado ABSOLUTO en el appbar: con spacers flex se corre hacia el
   lado ligero (el grupo derecho pesa más). En pantallas angostas vuelve al flujo normal
   para no encimarse con los botones. Debe ser flex: TituloPagina emite ícono y texto como
   hermanos (antes eran hijos directos de la fila del appbar) — sin flex se apilan en bloque. */
.appbar-titulo {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    white-space: nowrap;
}
@media (max-width: 900px) {
    .appbar-titulo {
        position: static;
        transform: none;
        margin-left: .5rem;
    }
}

/* Badge del centro de notificaciones: chico, con el número centrado (flex) y pegado a la
   campana (el translate por defecto de MudBadge lo manda a la esquina; lo acercamos). */
.badge-notif .mud-badge {
    height: 16px;
    min-width: 16px;
    padding: 0 4px;
    font-size: 0.62rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    transform: translate(15%, -15%) !important;
}

/* ── Tablero Kanban de reportes de bug ──────────────────────────────────────────────────
   Columnas coloreadas por estatus (el color se inyecta por variable --kanban-col*; el alfa en
   hex de 8 dígitos funciona en claro/oscuro), tarjetas con franja de prioridad y hover elevado. */
.kanban-col {
    flex: 1 1 260px;
    min-width: 260px;
    overflow: hidden;
    background-color: var(--kanban-col-suave);
}
.kanban-cabecera {
    border-top: 4px solid var(--kanban-col);
    background-color: var(--kanban-col-media);
}
.kanban-zona {
    /* El tablero también aprovecha el alto completo del viewport (se reajusta solo).
       Homologado al MISMO criterio del grid (offset medido, hallazgo #42): appbar 64 +
       pt-4 del main 16 + BarraGrid 72 + mb-3 12 + cabecera de la columna ~52 + margen ~2
       ≈ 230; aquí la cabecera de la columna ocupa el lugar que en el grid ocupa la reserva
       del botón "Cargar más". El 330 anterior dejaba ~100px de franja blanca al fondo.
       RE-MIDE al clonar o cambiar el chrome (ver docs/articles/checklist-qa.md §3). */
    min-height: calc(100vh - 230px);
    min-height: calc(100dvh - 230px);
    transition: background-color 0.15s ease;
}
.kanban-destino {
    background-color: var(--kanban-col-media);
    outline: 2px dashed var(--kanban-col);
    outline-offset: -6px;
}
.kanban-vacia::after {
    content: "Sin tarjetas";
    display: block;
    text-align: center;
    padding: 28px 0;
    opacity: 0.45;
    font-size: 0.8rem;
}
.kanban-tarjeta {
    border-left: 3px solid var(--kanban-prio, transparent);
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
    background-color: var(--mud-palette-surface);
}
.kanban-tarjeta:hover {
    transform: translateY(-2px);
    box-shadow: var(--mud-elevation-4);
}
.kanban-miniatura {
    width: 48px;
    height: 48px;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid #00000022;
    flex-shrink: 0;
}

/* Columna colapsada: se angosta a una franja vertical con el título rotado y el contador. */
.kanban-col-colapsada {
    flex: 0 0 48px;
    min-width: 48px;
    max-width: 48px;
    cursor: pointer;
}
.kanban-cabecera-vertical {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 6px 0 14px;
    height: 100%;
    min-height: 220px;
}
.kanban-titulo-vertical {
    writing-mode: vertical-rl;
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* Tarjetas de resumen (etiqueta en versalitas + variante destacada con franja del primario).
   Los tintes usan color-mix sobre --mud-palette-surface para seguir el modo oscuro solo. */
.tpl-tarjeta-lbl {
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: .68rem !important;
}
.tpl-tarjeta-destacada {
    border: 1px solid var(--mud-palette-primary);
    background: color-mix(in srgb, var(--mud-palette-primary) 10%, var(--mud-palette-surface));
}

/* Logo de marca en áreas de contenido (Home/Login): el logo negro para tema claro, el
   blanco para tema oscuro. El gancho body.tema-oscuro lo pone MainLayout (cambiarTemaSyncfusion).
   En el appbar (fondo teal) se usa SIEMPRE heimdall-light.svg, sin swap. */
.heimdall-logo-light { display: none; }
.heimdall-logo-dark { display: inline-block; }
body.tema-oscuro .heimdall-logo-light { display: inline-block; }
body.tema-oscuro .heimdall-logo-dark { display: none; }

