h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

/* --- FleetMonitor --- */

:root {
    --fm-bg: #14171c;
    --fm-panel: #1c2129;
    --fm-border: #2b313c;
    --fm-text: #e6e8eb;
    --fm-text-dim: #8b93a1;
    --fm-green: #2ecc71;
    /* Mismo "todo OK" pero apagado -- ver .status-healthy-partial: un cliente sano que igual
       tiene algún equipo desconectado sin "Avisar si se desconecta" (apagado esperado, no un
       problema). Puramente visual, no es un estado nuevo de DeviceStatus. Bien más oscuro que
       --fm-green (no solo menos saturado) para que se note la diferencia de un vistazo -- la
       primera versión de este color (más cerca del verde normal) se veía casi igual, según
       feedback de Ignacio del 2026-09-11. */
    --fm-green-dim: #2f6b48;
    --fm-amber: #f5b942;
    --fm-red: #e5484d;
    --fm-gray: #4b5361;
    --fm-blue: #4a9eff;
    --fm-purple: #a78bfa;
}

.fm-badge-outdated {
    display: inline-block;
    font-size: 0.72rem;
    color: var(--fm-blue);
    border: 1px solid var(--fm-blue);
    border-radius: 999px;
    padding: 1px 8px;
    margin-left: 6px;
}

body {
    background: var(--fm-bg);
    color: var(--fm-text);
    font-family: -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
    margin: 0;
}

.fm-page {
    max-width: 1200px;
    margin: 0 auto;
    padding: 24px 20px 60px;
    width: 100%;
    box-sizing: border-box;
}

/* Contenedor de alto completo (ver MainLayout.razor): nav y footer miden lo que midan de verdad,
   .fm-main ocupa el resto con flex:1, sin que nadie tenga que adivinar en píxeles cuánto miden. */
.fm-app-shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.fm-main {
    flex: 1;
    display: flex;
    flex-direction: column;
}

/* Solo la pantalla principal (Home) y el portal del cliente: con poco contenido (pocos clientes o
   pocos equipos) en una pantalla grande, quedaba todo pegado arriba y un vacío enorme abajo. Antes
   esto calculaba min-height:calc(100vh - Npx) adivinando cuánto miden el nav y el footer -- salía
   mal calibrado (confirmado 2026-09-06, quedaba un vacío exagerado igual). Ahora flex:1 dentro de
   .fm-main hace que ocupe exactamente el espacio real disponible, sin adivinar nada. No molesta
   cuando SÍ hay contenido de sobra (muchos clientes) -- ahí el contenido ya llena flex:1 solo y
   justify-content:center no tiene nada que centrar.  */
.fm-page-center {
    flex: 1;
    /* Simétrico -- .fm-page trae 24px arriba / 60px abajo (pensado para páginas largas que
       scrollean), y esa diferencia quedaba DENTRO de la caja ya centrada, corriendo todo el
       contenido hacia arriba un poco más de lo que debería. */
    padding-top: 32px;
    padding-bottom: 32px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Encabezado de marca de las dos "pantallas de aterrizaje" (Home del admin, Portal del cliente)
   -- ver BrandHero.razor. Resplandor muy sutil en verde de marca detrás del logo (no un cartel,
   apenas una presencia) y una línea fina abajo para separar del resto sin un bloque de color. */
.fm-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 4px 0 28px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--fm-border);
    position: relative;
}

.fm-hero-logo {
    height: 112px;
    width: auto;
    filter: drop-shadow(0 0 32px rgba(141, 198, 63, 0.3));
}

.fm-hero-title {
    margin-top: 14px;
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--fm-text);
}

.fm-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px 8px;
    margin-bottom: 20px;
}

/* El grupo de botones de la derecha (siempre un <div> hijo directo, el <h1> no cuenta) también
   tiene que poder pasar a una segunda línea en vez de desbordar en pantallas angostas — son
   estilos inline repetidos en cada página, así que se ataca desde acá en un solo lugar. */
.fm-header > div {
    flex-wrap: wrap;
}

.fm-header h1 {
    font-size: 1.5rem;
    margin: 0;
}

.fm-breadcrumb {
    color: var(--fm-text-dim);
    font-size: 0.9rem;
    margin-bottom: 4px;
}

.fm-breadcrumb a {
    color: var(--fm-text-dim);
    text-decoration: none;
}

.fm-breadcrumb a:hover {
    color: var(--fm-text);
}

.fm-back-plain {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: var(--fm-text-dim);
    text-decoration: none;
    cursor: pointer;
}

.fm-back-plain:hover {
    color: var(--fm-text);
}

.fm-btn {
    background: var(--fm-panel);
    border: 1px solid var(--fm-border);
    color: var(--fm-text);
    padding: 8px 14px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9rem;
    text-decoration: none;
    display: inline-block;
}

.fm-btn:hover {
    border-color: var(--fm-text-dim);
}

.fm-btn-active {
    background: var(--fm-blue);
    border-color: var(--fm-blue);
    color: #fff;
}

@media print {
    .fm-hide-print {
        display: none !important;
    }
}

.fm-empty {
    color: var(--fm-text-dim);
    padding: 40px 0;
}

.fm-grid {
    /* Flex en vez de grid con auto-fill: con menos tarjetas que columnas, un grid deja el resto
       de la fila vacía a la derecha (columnas "fantasma" del auto-fill). Flex + wrap + centrado
       agrupa las tarjetas que haya (1 o 10) en el medio de la pantalla, sin ese hueco. */
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 16px;
}

.fm-card {
    background: var(--fm-panel);
    border: 1px solid var(--fm-border);
    border-left: 5px solid var(--fm-gray);
    border-radius: 10px;
    padding: 16px;
    text-decoration: none;
    color: var(--fm-text);
    display: block;
    transition: transform 0.1s ease;
    flex: 1 1 220px;
    max-width: 320px;
}

.fm-card:hover {
    transform: translateY(-2px);
    border-color: var(--fm-text-dim);
}

.fm-card.status-healthy { border-left-color: var(--fm-green); }
/* Sano, pero con algún equipo desconectado "esperado" (sin alerta) -- mismo verde, más apagado,
   para notar de un vistazo que no está el 100% de la flota arriba sin que parezca un problema. */
.fm-card.status-healthy-partial { border-left-color: var(--fm-green-dim); }
.fm-card.status-warning { border-left-color: var(--fm-amber); }
.fm-card.status-offline { border-left-color: var(--fm-red); }
.fm-card.status-empty { border-left-color: var(--fm-gray); }
/* Un "siempre prendido" caído: mismo rojo que offline, pero con un contorno completo -- tiene
   que notarse aunque el resto de las tarjetas del cliente estén en verde al lado. */
.fm-card.status-critical { border-left-color: var(--fm-red); box-shadow: 0 0 0 1px var(--fm-red); }

/* Marca fija de "equipo crítico" (ej. servidor) tal cual está configurado en su ficha
   (AlwaysAlertOnDisconnect) -- visible siempre, esté online o no, para identificar de un vistazo
   cuáles son servidores/críticos en la grilla de un cliente sin tener que entrar a cada ficha.
   El contorno sigue el color del ESTADO ACTUAL (no siempre rojo, corregido 2026-09-12 -- un
   servidor sano marcado como crítico no tiene por qué verse como si tuviera un problema). El
   verde de "OK" es más saturado que el borde normal para que igual se note que está marcado. */
.fm-card.fm-card-flagged-critical { box-shadow: 0 0 0 1px var(--fm-red); }
.fm-card.fm-card-flagged-critical.status-healthy { box-shadow: 0 0 0 1px #22e06b; }
.fm-card.fm-card-flagged-critical.status-healthy-partial { box-shadow: 0 0 0 1px var(--fm-green); }
.fm-card.fm-card-flagged-critical.status-warning { box-shadow: 0 0 0 1px var(--fm-amber); }
.fm-card.fm-card-flagged-critical.status-offline { box-shadow: 0 0 0 1px var(--fm-red); }

.fm-card-title {
    font-weight: 600;
    font-size: 1.05rem;
    margin-bottom: 6px;
}

.fm-plan-stars {
    font-size: 0.85rem;
    letter-spacing: 1px;
    color: var(--fm-amber);
    margin-left: 4px;
    vertical-align: 1px;
}

.fm-btn-locked {
    opacity: 0.55;
    cursor: default;
}

.fm-plan-upsell {
    border-left: 3px solid var(--fm-purple);
}

.fm-plan-feature-on {
    color: var(--fm-text);
}

.fm-plan-feature-off {
    color: var(--fm-text-dim);
}

.fm-card-sub {
    color: var(--fm-text-dim);
    font-size: 0.85rem;
}

.fm-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 6px;
}

.fm-dot.status-healthy { background: var(--fm-green); }
.fm-dot.status-healthy-partial { background: var(--fm-green-dim); }
.fm-dot.status-warning { background: var(--fm-amber); }
.fm-dot.status-offline { background: var(--fm-red); }
.fm-dot.status-critical { background: var(--fm-red); }

.fm-metric-row {
    display: flex;
    justify-content: space-between;
    font-size: 0.85rem;
    color: var(--fm-text-dim);
    margin-top: 4px;
}

.fm-metric-row span:last-child {
    color: var(--fm-text);
}

/* Encabezado de sección para agrupar tarjetas por tema (Estado en vivo, Mantenimiento, Sistema,
   Seguridad, ...) sin sacar ninguna de pantalla -- ver DeviceDetail.razor. El primero de la
   página no necesita el espacio de arriba, por eso :first-child lo achica. */
.fm-section-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--fm-text);
    margin: 28px 0 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--fm-border);
}

.fm-section-title:first-child {
    margin-top: 0;
}

/* Resalte breve de la tarjeta a la que se salta desde "Puntos a revisar" (fmJumpTo en App.razor). */
.fm-flash {
    animation: fm-flash-pulse 2.2s ease-out;
}

@keyframes fm-flash-pulse {
    0%, 60% { box-shadow: 0 0 0 3px var(--fm-amber); }
    100% { box-shadow: 0 0 0 3px transparent; }
}

/* Al saltar a una sección desde .fm-jump-nav, que el título no quede tapado por la barra fija. */
[id^="sec-"] {
    scroll-margin-top: 56px;
}

.fm-section-title {
    scroll-margin-top: 56px;
}

/* Accesos rápidos a las secciones de una pantalla larga (Administración del cliente): una fila de
   botones chicos que se desliza a los costados en el celular y queda fija arriba al bajar. */
.fm-jump-nav {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 0;
    margin-bottom: 8px;
    background: var(--fm-bg);
}

/* En el celular los botones se acomodan en varias filas (como los demás botones) y no quedan fijos: una barra fija de varias filas taparía la pantalla. */
@media (max-width: 700px) {
    .fm-jump-nav {
        position: static;
        gap: 6px;
    }

    .fm-jump-nav a {
        padding: 5px 10px;
        font-size: 0.8rem;
    }
}

.fm-jump-nav a {
    flex: 0 0 auto;
    padding: 6px 12px;
    border: 1px solid var(--fm-border);
    border-radius: 999px;
    font-size: 0.85rem;
    color: var(--fm-text);
    text-decoration: none;
    white-space: nowrap;
}

.fm-jump-nav a:hover {
    background: var(--fm-panel);
}

@media print {
    .fm-jump-nav { display: none; }
}

.fm-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 12px;
    margin-top: 20px;
}

.fm-detail-tile {
    background: var(--fm-panel);
    border: 1px solid var(--fm-border);
    border-radius: 10px;
    padding: 14px;
    /* Sin esto, un grid item toma el ancho intrínseco de su contenido más largo (ej. una ruta de
       archivo sin espacios como "C:\...\msedgewebview2.exe") en vez de encogerse al ancho de su
       columna -- eso empuja TODO el grid (y con eso la página entera en mobile) a desbordar hacia
       los costados. Ver caso real 2026-09-19: el detalle de "Intentos de acceso fallidos" con rutas
       largas corría el celular entero de margen. */
    min-width: 0;
    overflow-wrap: anywhere;
}

.fm-detail-tile .fm-label {
    color: var(--fm-text-dim);
    font-size: 0.8rem;
    margin-bottom: 4px;
}

/* Markdown del análisis con IA (ver AiAnalysis.razor) -- Claude devuelve #/##/**/- según el
   prompt del sistema, renderizado acá con Markdig. Reusa las mismas variables de color que el
   resto del tablero, así que ya sale bien tanto en pantalla (paleta oscura) como en el PDF/impreso
   (la sección @media print de más abajo redefine esas mismas variables a la paleta clara). */
.fm-ai-analysis {
    line-height: 1.6;
}

.fm-ai-analysis h1 {
    font-size: 1.3rem;
    margin: 0 0 14px;
}

.fm-ai-analysis h2 {
    font-size: 1.05rem;
    color: var(--fm-blue);
    margin: 22px 0 10px;
    border-bottom: 1px solid var(--fm-border);
    padding-bottom: 6px;
}

.fm-ai-analysis h2:first-child {
    margin-top: 0;
}

.fm-ai-analysis p {
    margin: 0 0 12px;
}

.fm-ai-analysis ul {
    margin: 0 0 14px;
    padding-left: 22px;
}

.fm-ai-analysis li {
    margin-bottom: 8px;
}

.fm-ai-analysis strong {
    color: var(--fm-text);
}

.fm-ai-analysis table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 16px;
    font-size: 0.88rem;
}

.fm-ai-analysis th,
.fm-ai-analysis td {
    border: 1px solid var(--fm-border);
    padding: 6px 9px;
    text-align: left;
    vertical-align: top;
}

.fm-ai-analysis th {
    background: var(--fm-bg);
    font-weight: 600;
}

.fm-ai-analysis tr {
    break-inside: avoid;
}

@media (max-width: 700px) {
    .fm-ai-analysis table {
        display: block;
        overflow-x: auto;
    }
}

.fm-ai-analysis code {
    background: var(--fm-bg);
    border: 1px solid var(--fm-border);
    border-radius: 4px;
    padding: 1px 5px;
    font-size: 0.85em;
}

/* Dos desplegables lado a lado (energía: con corriente / con batería). minmax(0,1fr) y no 1fr: el ancho natural de un <select> empujaba la grilla (y la página entera)
   hacia afuera en el celular (2026-10-22). En pantallas chicas se apilan. */
.fm-power-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 6px;
}
.fm-power-pair select { width: 100%; min-width: 0; }
.fm-detail-tile select { max-width: 100%; }
@media (max-width: 700px) {
    .fm-power-pair { grid-template-columns: minmax(0, 1fr); }
}

.fm-detail-tile .fm-value {
    font-size: 1.2rem;
    font-weight: 600;
}

.fm-detail-tile .fm-value a {
    color: var(--fm-blue);
    text-decoration: none;
}

.fm-detail-tile .fm-value a:hover {
    text-decoration: underline;
}

/* Grillas de dos columnas para agrupar tiles de administración anchos (facturación, Telegram,
   etc.) sin dejar franjas vacías a los costados en pantallas grandes. */
.fm-two-col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    align-items: start;
}

@media (max-width: 860px) {
    .fm-two-col {
        grid-template-columns: 1fr;
    }
}

/* Variante "mampostería" de .fm-two-col para tiles de altura MUY dispareja e independientes
   entre sí (ej. Configuración: "Reportes por email" es mucho más alto que "Resumen automático
   por cliente") -- con grid normal, la fila entera queda tan alta como el tile más alto de esa
   fila, dejando un hueco vacío debajo del tile corto antes de que empiece la fila siguiente
   (reportado por el usuario 2026-09-13, viendo justo ese hueco en /configuracion). Con columnas
   CSS en cambio, cada tile fluye al lugar que le toca sin esperar a su par de fila -- ya no hace
   falta que compartan fila para acomodarse bien. No reemplaza a .fm-two-col en general porque ahí
   también se usa para pares que SÍ deben quedar alineados uno al lado del otro (ej. los gráficos
   de métricas en DeviceDetail), donde el reflow de columnas no aportaría nada. */
.fm-masonry-two-col {
    column-count: 2;
    column-gap: 20px;
}

.fm-masonry-two-col > * {
    break-inside: avoid;
    margin-bottom: 20px;
}

@media (max-width: 860px) {
    .fm-masonry-two-col {
        column-count: 1;
    }
}

/* Checkboxes de alertas en cuadrícula: varias opciones por fila en vez de una lista larga
   apilada. El texto de ayuda de las opciones no obvias vive en el atributo title (tooltip
   nativo al pasar el mouse) en vez de un párrafo aparte, para no ocupar espacio siempre. */
.fm-check-grid {
    display: grid;
    /* min(280px, 100%): en un recuadro más angosto que 280px (Mantenimiento rápido de la ficha del equipo) la columna se achica al ancho del recuadro en vez de
       salirse por el costado. */
    grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
    gap: 4px 24px;
}

.fm-check {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    padding: 8px 0;
}

.fm-summary-tile {
    cursor: pointer;
    transition: border-color 0.15s;
}

.fm-summary-tile:hover {
    border-color: var(--fm-blue);
}

.fm-summary-tile-active {
    border-color: var(--fm-blue);
}

.fm-issue-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.fm-issue-list a {
    color: var(--fm-blue);
    text-decoration: none;
    font-size: 0.9rem;
}

.fm-issue-list a:hover {
    text-decoration: underline;
}

.fm-wallboard-client-link {
    color: var(--fm-text);
    text-decoration: none;
}

/* --- Manual / guías --- */

.fm-manual {
    max-width: 760px;
}

.fm-manual .fm-lede {
    color: var(--fm-text-dim);
    max-width: 68ch;
    margin: 0 0 24px;
}

.fm-toc {
    margin: 0 0 32px;
}

.fm-toc ol {
    margin: 10px 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 6px 20px;
}

.fm-toc a {
    display: flex;
    gap: 10px;
    text-decoration: none;
    color: var(--fm-text);
    font-size: 0.92rem;
}

.fm-toc a:hover {
    color: var(--fm-blue);
}

.fm-toc .fm-n {
    font-family: Consolas, "Courier New", monospace;
    color: var(--fm-text-dim);
    width: 1.6em;
    flex-shrink: 0;
}

.fm-chapter {
    margin-top: 36px;
    padding-top: 20px;
    border-top: 1px solid var(--fm-border);
}

.fm-chapter:first-of-type {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.fm-chapter-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 14px;
}

.fm-chapter-num {
    font-family: Consolas, "Courier New", monospace;
    font-weight: 700;
    font-size: 1.3rem;
    color: var(--fm-blue);
}

.fm-manual h2 {
    font-size: 1.15rem;
    margin: 0;
}

.fm-manual h3 {
    font-size: 0.98rem;
    margin: 20px 0 8px;
}

.fm-manual p {
    margin: 0 0 12px;
    max-width: 68ch;
}

.fm-manual ul, .fm-manual ol.fm-steps {
    margin: 0 0 12px;
    padding-left: 22px;
}

.fm-manual li {
    margin-bottom: 6px;
    max-width: 64ch;
}

.fm-code {
    font-family: Consolas, "Courier New", monospace;
    font-size: 0.85rem;
    background: var(--fm-bg);
    border: 1px solid var(--fm-border);
    border-radius: 8px;
    padding: 12px 14px;
    overflow-x: auto;
    margin: 0 0 14px;
    white-space: pre;
    color: #cddbe8;
}

.fm-inline-code {
    font-family: Consolas, "Courier New", monospace;
    font-size: 0.88em;
    background: var(--fm-bg);
    border: 1px solid var(--fm-border);
    border-radius: 4px;
    padding: 0.05em 0.4em;
    color: #cddbe8;
}

.fm-menu-path {
    font-family: Consolas, "Courier New", monospace;
    font-size: 0.9rem;
    background: var(--fm-bg);
    border: 1px solid var(--fm-border);
    border-radius: 8px;
    padding: 10px 14px;
    margin: 0 0 12px;
}

.fm-menu-path .fm-arrow {
    color: var(--fm-text-dim);
    margin: 0 6px;
}

.fm-menu-path .fm-val {
    color: var(--fm-blue);
}

.fm-callout {
    border: 1px solid var(--fm-border);
    border-left: 3px solid var(--fm-blue);
    background: var(--fm-panel);
    border-radius: 0 8px 8px 0;
    padding: 12px 16px;
    margin: 0 0 14px;
}

.fm-callout p:last-child {
    margin-bottom: 0;
}

.fm-callout .fm-callout-label {
    font-family: Consolas, "Courier New", monospace;
    font-size: 0.72rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    margin-bottom: 4px;
    display: block;
    color: var(--fm-blue);
}

.fm-callout.fm-tip {
    border-left-color: var(--fm-green);
}

.fm-callout.fm-tip .fm-callout-label {
    color: var(--fm-green);
}

.fm-callout.fm-warn {
    border-left-color: var(--fm-amber);
}

.fm-callout.fm-warn .fm-callout-label {
    color: var(--fm-amber);
}

/* Legajo del equipo: ficha tipo "documento formal" (datos de inventario/recuperación), a
   diferencia de .fm-kv que es para instrucciones técnicas con la clave en monoespaciada. */
.fm-legajo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0 32px;
}

.fm-legajo-field {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--fm-border);
}

.fm-legajo-field .fm-legajo-label {
    color: var(--fm-text-dim);
}

.fm-legajo-field .fm-legajo-value {
    font-weight: 600;
    text-align: right;
}

.fm-kv {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 6px 16px;
    margin: 0 0 14px;
    font-size: 0.92rem;
}

.fm-kv dt {
    font-family: Consolas, "Courier New", monospace;
    color: var(--fm-text-dim);
    white-space: nowrap;
}

.fm-kv dd {
    margin: 0;
    max-width: 56ch;
}

/* Letterhead de impresión: oculto en pantalla, la portada de la app ya cumple ese rol ahí.
   El logo va como <img> de un SVG con su propio fondo sólido (no CSS background), así que
   imprime siempre aunque el navegador tenga desactivado "Gráficos de fondo". */
.fm-print-letterhead {
    display: none;
}

/* Contenido que solo tiene sentido en el PDF/impreso (ej. el resumen ejecutivo del informe) —
   inverso de .fm-hide-print. En pantalla no aporta nada porque la vista semáforo ya cumple ese
   rol de forma interactiva. */
.fm-print-only {
    display: none;
}

/* Separador entre documentos distintos impresos/exportados juntos (ver InformeYRecibo.razor) --
   sin efecto en pantalla (altura 0), fuerza el salto de página solo al imprimir/exportar PDF. */
.fm-print-page-break {
    page-break-before: always;
    break-before: page;
}

@media print {
    /* Paleta y tipografía del Manual de Marca de Epsilon (v1.0, 2026) — ver
       Epsilon_Manual_de_Marca.docx. Los semáforos de estado (verde/ámbar/rojo) se mantienen
       legibles y separados del verde de marca: ese es un acento puntual (ícono, líneas,
       títulos), no reemplaza al verde "todo OK" que necesita buen contraste en texto chico. */
    :root {
        --fm-bg: #ffffff;
        --fm-panel: #f4f5f7;
        --fm-border: #c9cdd3;
        --fm-text: #14161b;
        --fm-text-dim: #4b5563;
        --fm-green: #15803d;
        --fm-green-dim: #8fc0a3;
        --fm-amber: #9a5b00;
        --fm-red: #b91c1c;
        --fm-gray: #6b7280;
        --fm-blue: #1d4ed8;
        --fm-purple: #7c3aed;
        --brand-green: #8dc63f;
        --brand-ink: #14161b;
        --brand-gray: #9aa0a6;
    }

    body, .fm-page {
        background: #fff !important;
        font-family: 'Poppins', Arial, Helvetica, system-ui, sans-serif;
    }

    h1, h2, h3, .fm-print-title {
        font-family: 'Poppins', Arial, Helvetica, system-ui, sans-serif;
        font-weight: 700;
    }

    .fm-label, .fm-print-brand {
        font-family: 'Poppins', Arial, Helvetica, system-ui, sans-serif;
        font-weight: 500;
    }

    .fm-print-only {
        display: block;
    }

    .fm-print-letterhead {
        display: flex !important;
        align-items: center;
        gap: 14px;
        padding-bottom: 16px;
        margin-bottom: 24px;
        border-bottom: 3px solid var(--brand-green);
    }

    .fm-print-letterhead img {
        height: 40px;
        width: auto;
        flex-shrink: 0;
    }

    .fm-print-letterhead-text {
        flex: 1;
    }

    .fm-print-brand {
        font-size: 0.8rem;
        color: var(--brand-gray);
        letter-spacing: 0.02em;
    }

    .fm-print-title {
        font-size: 1.3rem;
        font-weight: 700;
        color: var(--brand-ink);
    }

    .fm-print-date {
        font-size: 0.8rem;
        color: var(--brand-gray);
        white-space: nowrap;
    }

    .fm-print-summary {
        border-left: 3px solid var(--brand-green);
        background: #f8faf4;
        padding: 14px 18px;
        margin-bottom: 22px;
        border-radius: 0 8px 8px 0;
    }

    .fm-print-summary p {
        margin: 0 0 8px;
        line-height: 1.5;
    }

    .fm-print-summary p:last-child {
        margin-bottom: 0;
    }

    /* Lenguaje editorial tomado de la propuesta comercial (FleetMonitor_Propuesta_Final):
       etiqueta verde en mayúscula + título grande abajo, en vez del look "panel de dashboard"
       que tiene sentido en pantalla oscura pero no en un informe impreso para un dueño de
       negocio. Mismo recurso, aplicado acá a "Resumen ejecutivo" y "Detalle por equipo". */
    .fm-print-eyebrow {
        display: block;
        color: var(--brand-green);
        font-weight: 700;
        font-size: 0.72rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        margin-bottom: 6px;
    }

    .fm-print-headline {
        font-size: 1.15rem;
        font-weight: 700;
        color: var(--brand-ink);
        margin: 0 0 14px;
    }

    /* El puntaje general pasa de tile oscuro a "cifra hero" editorial (mismo recurso que los
       stats "1 panel único / 24-7 / 100%" de la propuesta): el número es el protagonista, la
       tarjeta con fondo y borde no aporta nada sobre papel blanco. */
    .fm-print-score-hero {
        text-align: center;
        margin: 4px 0 26px;
    }

    .fm-print-score-hero .fm-print-score-value {
        font-size: 2.6rem;
        font-weight: 700;
        line-height: 1;
    }

    .fm-print-score-hero .fm-print-score-label {
        font-size: 0.75rem;
        color: var(--brand-gray);
        text-transform: uppercase;
        letter-spacing: 0.06em;
        margin-top: 6px;
    }

    /* Cada equipo pasa de tile oscuro a sección dividida por una línea fina, igual que los
       ítems de la propuesta -- más plano, más "documento", menos "recorte de pantalla". */
    .fm-print-device {
        background: none !important;
        border: none !important;
        border-radius: 0 !important;
        border-bottom: 1px solid var(--fm-border) !important;
        padding: 18px 0 !important;
    }

    .fm-print-device:last-child {
        border-bottom: none !important;
    }

    .fm-print-device h2 {
        color: var(--brand-ink);
    }

    /* Las recomendaciones pierden el fondo semitransparente pensado para tema oscuro; queda
       solo el acento de color a la izquierda, como las citas destacadas de la propuesta. */
    .fm-print-rec {
        background: none !important;
        padding-left: 12px !important;
    }

    .fm-print-rec .fm-print-rec-detail {
        color: var(--fm-text-dim);
    }

    /* Legajo con varios equipos: uno por hoja. No se aplica al último para no dejar una página
       en blanco de más al final. */
    .fm-legajo-pages > .fm-legajo-page:not(:last-child) {
        page-break-after: always;
    }

    .fm-print-footer {
        margin-top: 28px;
        padding-top: 12px;
        border-top: 1px solid var(--fm-border);
        font-size: 0.75rem;
        color: var(--brand-gray);
        text-align: center;
    }

    .fm-manual .fm-toc a {
        color: var(--fm-text);
    }

    /* .fm-code/.fm-inline-code llevan un color de texto fijo pensado para el fondo oscuro de
       pantalla (no una variable) — sin este ajuste quedarían casi ilegibles en papel blanco. */
    .fm-code, .fm-inline-code {
        color: var(--fm-text);
    }
}

.fm-wallboard-client-link:hover {
    text-decoration: underline;
}

.fm-form input {
    background: var(--fm-panel);
    border: 1px solid var(--fm-border);
    color: var(--fm-text);
    padding: 8px 10px;
    border-radius: 6px;
    font-size: 0.9rem;
}

.fm-key-box {
    background: var(--fm-panel);
    border: 1px solid var(--fm-amber);
    border-radius: 8px;
    padding: 14px;
    margin: 16px 0;
    word-break: break-all;
    font-family: Consolas, monospace;
}

table.fm-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 16px;
}

table.fm-table th, table.fm-table td {
    text-align: left;
    padding: 8px 10px;
    border-bottom: 1px solid var(--fm-border);
    font-size: 0.9rem;
}

table.fm-table th {
    color: var(--fm-text-dim);
    font-weight: 500;
}

/* --- Pantalla de reconexión (ver App.razor) --- */

/* Blazor es dueño de este div y a veces le pisa el contenido interno con su propio texto
   default (en inglés, sin estilo) al llegar al estado final "failed" — pasa de verdad, no
   solo en teoría. Por eso queda permanentemente oculto fuera de pantalla: solo se usa como
   señal de estado (las clases que Blazor le agrega), nunca se muestra directamente. El script
   de App.razor lee esas clases y NO muestra ningún aviso al usuario. */
#components-reconnect-modal {
    position: fixed;
    top: -9999px;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

@keyframes fm-spin {
    to { transform: rotate(360deg); }
}

/* Panel "Panorama" -- ver PanoramaView.razor, compartido entre /panorama (admin) y
   /portal/panorama (cliente). Fila de KPIs grandes arriba, hallazgos + dona de estado abajo. */
.fm-panorama-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}

.fm-kpi-card {
    background: var(--fm-panel);
    border: 1px solid var(--fm-border);
    border-radius: 10px;
    padding: 18px;
    text-align: center;
}

.fm-kpi-value {
    font-size: 2.1rem;
    font-weight: 700;
    color: var(--fm-text);
    line-height: 1.1;
}

.fm-kpi-of {
    font-size: 1.2rem;
    font-weight: 400;
    color: var(--fm-text-dim);
}

.fm-kpi-label {
    color: var(--fm-text-dim);
    font-size: 0.8rem;
    margin-top: 6px;
}

.fm-panorama-main {
    display: grid;
    grid-template-columns: 1.6fr 1fr;
    gap: 16px;
    align-items: start;
}

@media (max-width: 800px) {
    .fm-panorama-main { grid-template-columns: 1fr; }
}

.fm-finding-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    text-decoration: none;
    color: var(--fm-text);
    transition: background 0.1s ease;
}

.fm-finding-row:hover {
    background: rgba(255, 255, 255, 0.06);
}

.fm-finding-icon {
    flex-shrink: 0;
}

.fm-finding-text {
    flex: 1;
    font-size: 0.9rem;
}

.fm-finding-device {
    color: var(--fm-text-dim);
    font-weight: 400;
}

.fm-finding-arrow {
    color: var(--fm-text-dim);
    flex-shrink: 0;
}

/* Panorama detallado: cada equipo es un <details> propio -- separador liviano sin JS entre
   equipos, con la franja de arriba (summary) siempre visible y el resto colapsado por defecto
   salvo que el equipo esté crítico/al límite (ver PanoramaView.razor). */
.fm-device-detail {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid var(--fm-border);
    border-radius: 8px;
    padding: 10px 12px;
}

.fm-device-detail summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    font-size: 0.95rem;
}

.fm-device-detail summary::-webkit-details-marker {
    display: none;
}

.fm-device-detail summary::before {
    content: "▸";
    color: var(--fm-text-dim);
    margin-right: 2px;
}

.fm-device-detail[open] summary::before {
    content: "▾";
}

.fm-panorama-donut {
    text-align: center;
}

.fm-donut {
    width: 100%;
    max-width: 220px;
    height: auto;
    margin: 8px auto 4px;
}

.fm-donut-number {
    font-size: 2.4rem;
    font-weight: 700;
    fill: var(--fm-text);
}

.fm-donut-caption {
    font-size: 0.75rem;
    fill: var(--fm-text-dim);
}

.fm-donut-legend {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
    text-align: left;
}

.fm-donut-legend-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
}

.fm-donut-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.fm-donut-legend-count {
    margin-left: auto;
    color: var(--fm-text-dim);
    font-weight: 600;
}

/* Pestaña "Detallado" de Panorama -- ver PanoramaDetailView.razor. */
.fm-panorama-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    align-items: start;
}

.fm-bar-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 14px;
}

.fm-bar-row {
    display: grid;
    grid-template-columns: minmax(90px, auto) 1fr auto;
    align-items: center;
    gap: 10px;
    font-size: 0.85rem;
}

.fm-bar-label {
    color: var(--fm-text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fm-bar-track {
    background: var(--fm-border);
    border-radius: 6px;
    height: 10px;
    overflow: hidden;
}

.fm-bar-fill {
    height: 100%;
    border-radius: 6px;
    min-width: 3px;
}

.fm-bar-count {
    color: var(--fm-text);
    font-weight: 600;
    min-width: 20px;
    text-align: right;
}

/* Gráficos de columnas simples (incidentes por día / por hora) -- ver PanoramaIncidentsInsights.razor. */
.fm-cols {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 90px;
    margin-top: 14px;
}

.fm-col {
    flex: 1;
    min-width: 2px;
    background: var(--fm-amber);
    border-radius: 3px 3px 0 0;
}

.fm-cols-axis {
    display: flex;
    justify-content: space-between;
    margin-top: 4px;
    font-size: 0.7rem;
    color: var(--fm-text-dim);
}

.fm-history-chart {
    display: flex;
    flex-direction: column;
}

.fm-history-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}

.fm-history-stats {
    color: var(--fm-text-dim);
    font-size: 0.78rem;
    white-space: nowrap;
}

.fm-history-svg {
    width: 100%;
    height: 120px;
    margin-top: 8px;
    display: block;
}

.fm-history-svg.fm-sync {
    cursor: crosshair;
    touch-action: pan-y;
}

.fm-cursor-val {
    color: var(--fm-text);
}

.fm-history-gridline {
    stroke: var(--fm-border);
    stroke-width: 1;
}

.fm-history-axis {
    display: flex;
    justify-content: space-between;
    color: var(--fm-text-dim);
    font-size: 0.72rem;
    margin-top: 4px;
}

.fm-panorama-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
}

.fm-panorama-tabs .fm-btn.fm-tab-active {
    background: var(--fm-blue);
    border-color: var(--fm-blue);
    color: #fff;
}


/* Detalle de las tarjetas-resumen de la portada (ver HomeTileDetail.razor): en pantalla ancha va debajo de todas las tarjetas; en el
   celular, pegado debajo de la tarjeta que se tocó (ocupa el ancho entero de la grilla). */
.fm-expand-after { margin-bottom: 20px; }
.fm-expand-inline { display: none; }
@media (max-width: 700px) {
    .fm-expand-inline { display: block; grid-column: 1 / -1; }
    .fm-expand-after { display: none; }
}

/* Tarjetas plegables (Acciones programadas, Encendido por red): el título es el resumen y se abre con un toque. */
details > summary.fm-label {
    cursor: pointer;
    list-style: none;
}

details > summary.fm-label::-webkit-details-marker {
    display: none;
}

details > summary.fm-label::before {
    content: "▸ ";
    color: var(--fm-text-dim);
}

details[open] > summary.fm-label::before {
    content: "▾ ";
}


/* Botón flotante "ir al comienzo" (ver App.razor). */
#fm-to-top {
    position: fixed;
    right: 14px;
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    z-index: 50;
    display: none;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border: 1px solid var(--fm-border);
    border-radius: 50%;
    background: var(--fm-panel);
    color: var(--fm-text);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}

#fm-to-top.fm-visible {
    display: flex;
}

@media print {
    #fm-to-top { display: none !important; }
}

/* Secciones que se pueden ocultar un rato (ver App.razor): el título de la sección es el interruptor; no se recuerda al salir de la pantalla. */
[data-fm-collapsible] h2.fm-section-title {
    cursor: pointer;
    position: relative;
    padding-right: 24px;
    user-select: none;
}

[data-fm-collapsible] h2.fm-section-title::after {
    content: "–";
    position: absolute;
    right: 0;
    top: 0;
    color: var(--fm-text-dim);
}

[data-fm-collapsible] h2.fm-section-title.fm-sec-collapsed::after {
    content: "+";
}

[data-fm-collapsible] .fm-sec-hidden {
    display: none !important;
}

/* Pantallas sin títulos de sección (ficha del cliente): se pliegan las tarjetas grandes. */
[data-fm-collapsible] .fm-detail-tile[id^="sec-"] > .fm-label:not(:nth-last-child(-n+2)) {
    cursor: pointer;
    position: relative;
    padding-right: 22px;
}

[data-fm-collapsible] .fm-detail-tile[id^="sec-"] > .fm-label:not(:nth-last-child(-n+2))::after {
    content: "–";
    position: absolute;
    right: 0;
    top: 0;
    color: var(--fm-text-dim);
}

[data-fm-collapsible] .fm-detail-tile.fm-tile-collapsed > *:not(.fm-label) {
    display: none !important;
}

[data-fm-collapsible] .fm-detail-tile.fm-tile-collapsed > .fm-label::after {
    content: "+";
}


/* Enlaces: azul legible sobre el fondo oscuro en toda la aplicación, también los ya visitados (el violeta oscuro del navegador casi no se leía).
   :where() deja la especificidad en cero: cualquier enlace con color propio (clase o estilo) lo conserva. En pantalla solamente; lo impreso no cambia. */
@media screen {
    a:where(:link, :visited) {
        color: var(--fm-blue);
    }
}


/* Celulares: nada puede ensanchar la página ni apretar una columna hasta partir cada palabra (visto en el registro de actividad y en los manuales). */
@media (max-width: 700px) {
    /* Listas "clave / explicación" (manuales): en una sola columna, con la clave arriba y que pueda partirse. */
    .fm-kv {
        grid-template-columns: 1fr;
        gap: 2px 0;
    }

    .fm-kv dt {
        white-space: normal;
        overflow-wrap: anywhere;
        margin-top: 8px;
        font-weight: 600;
    }

    .fm-kv dd {
        max-width: none;
        overflow-wrap: anywhere;
    }

    .fm-inline-code {
        overflow-wrap: anywhere;
    }
}

/* Tablas dentro de un contenedor con desplazamiento horizontal: ancho mínimo para que se desplacen en vez de apretar las columnas. */
table.fm-table {
    min-width: 520px;
}


/* Secciones con algo para revisar (ver DeviceDetail.SectionAlerts): el título y su acceso rápido cambian de color para saber cuál abrir. */
.fm-section-title[data-alert="amber"], .fm-section-title[data-alert="amber"]::before { color: var(--fm-amber); }
.fm-section-title[data-alert="red"], .fm-section-title[data-alert="red"]::before { color: var(--fm-red); }
.fm-section-title[data-alert]::before { content: "⚠ "; }
.fm-jump-nav a[data-alert="amber"] { color: var(--fm-amber); border-color: var(--fm-amber); }
.fm-jump-nav a[data-alert="red"] { color: var(--fm-red); border-color: var(--fm-red); }
