/* ACTIVE STYLESHEET: backend/static/css/style.css */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

[hidden] {
    display: none !important;
}

/* Aumenta la tipografía global respetando el tamaño base configurado por
   el usuario en el navegador. Todos los valores en rem escalan desde aquí. */
html {
    font-size: calc(100% + 2px);
    overflow-x: hidden;
}

/* El popup nativo de <option> no hereda el tema (fondo/texto propios del
   SO) — sin esto se ve blanco sobre blanco/verde en cualquier <select>
   oscuro de la app, no solo en el Cotizador. Chrome/Firefox de escritorio
   sí respetan background/color en <option>, aunque no el borde/sombra del
   popup (eso lo controla el SO, no es tocable desde CSS). */
select option {
    background: var(--card-bg);
    color: var(--text);
}

/* =============================================================
   CAPA DE TOKENS DE COLOR

   Tres niveles, de abajo hacia arriba:

     1. Primitivos  --nop-*      valores literales de marca. NO se usan
                                 directo en componentes.
     2. Semánticos  --surface-*, --text-*, --border-*, --accent-*,
                    --status-*   lo que describe el ROL del color.
                                 Es lo que se usa en UI nueva.
     3. Alias       --bg, --card-bg, --text, --accent, ...
                                 nombres históricos apuntando al nivel 2,
                                 para que el CSS que ya existe siga
                                 funcionando sin reescribirlo de golpe.

   Reglas:
   - En UI nueva se usan SOLO los semánticos. Los alias existen para que la
     migración sea incremental, no para escribir código nuevo.
   - --border-subtle es decorativo (separadores). Cualquier cosa que sea el
     contorno de un control (input, botón fantasma, checkbox) usa
     --border-control, que garantiza 3:1 contra la superficie.
   - --accent-fill es RELLENO (fondo de botón, con --accent-on encima).
     --accent-ink es TINTA (texto, ícono, borde). No son intercambiables:
     en el tema claro el verde de marca solo da 2.28:1 contra blanco, así
     que como texto se usa --accent-ink, que es más oscuro.
   - El rojo está reservado para --status-danger en los cuatro temas. Ningún
     accent es rojo, justamente para que "rojo = algo está mal" se sostenga.

   Los valores están verificados contra WCAG 2.1: texto >= 4.5:1 contra su
   superficie, bordes de control y colores de estado >= 3:1.
   ============================================================= */

:root {
    /* --- nivel 1: primitivos de marca --- */
    --nop-green-400: #4ADE80;
    --nop-green-500: #22C55E;
    --nop-green-600: #16A34A;
    --nop-green-700: #15803D;
    --nop-amber-400: #FB923C;
    --nop-amber-500: #F97316;
    --nop-amber-600: #EA580C;
    --nop-violet-400: #A78BFA;
    --nop-violet-500: #8B5CF6;
    --nop-violet-600: #7C3AED;

    /* --- medidas (no dependen del tema) --- */
    --radius-lg: 20px;
    --radius-md: 14px;
    --radius-sm: 5px;
    --topbar-height: 72px;
}

/* --- nivel 2: DESIERTO (tema claro) ---
   Espeja los valores de body.light, que es donde vive de verdad el tema
   claro (paleta "Desert", alineada con TUNA-Screen). Este bloque es el
   fallback para el instante previo a que applyTheme() ponga la clase en
   <body>: si acá hubiera otra paleta, la carga arrancaría con un destello
   del color equivocado. Cualquier cambio al tema claro se hace en los dos
   lados o en ninguno. */
:root {
    --surface-base: #E8D8B5;
    --surface-raised: #F5EBD4;
    --surface-sunken: #FDF8EC;
    --surface-nav: #FDF8EC;

    --text-strong: #30291F;
    --text-soft: #6B5E49;
    --text-faint: #6B5E49;

    --border-subtle: #9A8258;
    --border-control: #8B7550;

    --accent-fill: #687A32;
    --accent-fill-hover: #5C6C2C;
    --accent-fill-active: #4E5C25;
    --accent-ink: #4E5C25;
    --accent-on: #FFFFFF;
    --accent-fill-rgb: 104, 122, 50;

    --status-ok: #4E5C25;
    --status-warn: #B66A1F;
    --status-danger: #A63D32;
    --status-info: #3B82C4;

    --green-emphasis: #4E5C25;
    --violet: #8A63D2;
}

/* --- nivel 2: NOCHE (oscuro neutro) ---
   Texto #F2F3F5 en vez de blanco puro: sobre un fondo casi negro el blanco
   #FFFFFF da 20:1 y produce halation (el texto "sangra") en las sesiones
   largas frente a una impresora. */
body.dark {
    --surface-base: #0B0B0C;
    --surface-raised: #1C1D21;
    --surface-sunken: #151517;
    --surface-nav: #0F0F11;

    --text-strong: #F2F3F5;
    --text-soft: #A9ADB4;
    --text-faint: #8A8F97;

    --border-subtle: #2E2F34;
    --border-control: #6A6D73;

    --accent-fill: var(--nop-green-500);
    --accent-fill-hover: var(--nop-green-400);
    --accent-fill-active: var(--nop-green-600);
    --accent-ink: var(--nop-green-400);
    --accent-on: #06280F;
    --accent-fill-rgb: 34, 197, 94;

    --status-ok: var(--nop-green-400);
    --status-warn: #FBBF24;
    --status-danger: #F87171;
    --status-info: #60A5FA;

    --green-emphasis: var(--nop-green-500);
    --violet: var(--nop-violet-400);
}

/* --- nivel 2: NOPAL (verde/slate) --- */
body.green {
    --surface-base: #0B1220;
    --surface-raised: #182238;
    --surface-sunken: #111A2B;
    --surface-nav: #0D1526;

    --text-strong: #F1F5F9;
    --text-soft: #B4C0D0;
    --text-faint: #94A3B8;

    --border-subtle: #24314A;
    --border-control: #59708F;

    --accent-fill: var(--nop-green-500);
    --accent-fill-hover: var(--nop-green-400);
    --accent-fill-active: var(--nop-green-600);
    --accent-ink: var(--nop-green-400);
    --accent-on: #06280F;
    --accent-fill-rgb: 34, 197, 94;

    --status-ok: var(--nop-green-400);
    --status-warn: #FBBF24;
    --status-danger: #F87171;
    --status-info: #60A5FA;

    --green-emphasis: var(--nop-green-500);
    --violet: var(--nop-violet-400);
}

/* --- nivel 2: FORJA (rojo) ---
   El accent es ÁMBAR, no rojo. Antes el accent y el color de error eran el
   mismo #E5484D, así que el botón de acción principal y la alerta de una
   impresora fallando competían visualmente. Las superficies conservan el
   tinte cálido para que el tema siga leyéndose como "el rojo". */
body.red {
    --surface-base: #0F0A09;
    --surface-raised: #261A18;
    --surface-sunken: #1B1211;
    --surface-nav: #171010;

    --text-strong: #F7F0EE;
    --text-soft: #CBB6B1;
    --text-faint: #A99490;

    --border-subtle: #3A2724;
    --border-control: #85605A;

    --accent-fill: var(--nop-amber-500);
    --accent-fill-hover: var(--nop-amber-400);
    --accent-fill-active: var(--nop-amber-600);
    --accent-ink: var(--nop-amber-400);
    --accent-on: #2A1103;
    --accent-fill-rgb: 249, 115, 22;

    --status-ok: var(--nop-green-400);
    /* Empujado hacia rosa-rojo para que no se confunda con el ámbar del
       accent a simple vista. */
    --status-danger: #FF6B81;
    --status-warn: #FBBF24;
    --status-info: #7DB3F5;

    --green-emphasis: var(--nop-green-500);
    --violet: var(--nop-violet-400);
}

/* --- nivel 3: alias históricos ---
   Se declaran para los cuatro temas a la vez: como apuntan a variables y no
   a literales, cada tema resuelve los suyos por la cascada. body.custom
   entra aquí también, y sobreescribe el nivel 2 desde JS (applyTheme). */
:root,
body.dark,
body.green,
body.red,
body.custom {
    --bg: var(--surface-base);
    --card-bg: var(--surface-raised);
    --surface: var(--surface-raised);
    --panel-bg: var(--surface-sunken);
    --sidebar-bg: var(--surface-nav);

    --text: var(--text-strong);
    --text-secondary: var(--text-soft);
    --text-muted: var(--text-faint);
    --black: var(--text-strong);

    --border: var(--border-subtle);

    --accent: var(--accent-fill);
    --accent-hover: var(--accent-fill-hover);
    --accent-active: var(--accent-fill-active);
    --accent-rgb: var(--accent-fill-rgb);

    --green: var(--status-ok);
    --green-dark: var(--green-emphasis);
    --green-rgb: 34, 197, 94;

    --orange: var(--status-warn);
    --orange-light: var(--status-warn);
    /* #FBBF24 -- mismo ámbar que --status-warn en dark/green/red, en rgb
       para poder usarlo con rgba() (ver el recuadro de CNC del sidebar). */
    --orange-rgb: 251, 191, 36;
    --purple: var(--violet);
    --purple-rgb: 139, 92, 246;
}

body {
    font-family: Inter, system-ui, Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    /* Red de seguridad para viewports angostos: evita que un componente que
       todavía no se probó en mobile empuje el ancho de toda la página y
       genere una barra de scroll horizontal. No reemplaza el scroll interno
       propio de .content/tablas/etc., que sigue funcionando igual
       (overflow-x:auto local). */
    overflow-x: hidden;
}

body.light {
    /* Paleta "Desert", alineada con el tema desert de la app TUNA-Screen
       (ui/theme/Color.kt::DesertColors) en vez del blanco/verde-menta que
       tenía antes. Los estados que esa paleta mobile no define (hover,
       "strong", soft/border de badges) se derivan del acento oliva
       (--accent-green) y no son parte del set de colores dado; --purple y
       --state-info tampoco tienen equivalente ahí, así que quedan con el
       valor de siempre. Estas variables solo existen en el tema claro; los
       temas oscuro, verde, rojo y personalizado conservan su paleta. */
    --bg-app: #E8D8B5;
    --bg-surface: #FDF8EC;
    --bg-modal: #FDF8EC;
    --bg-card: #F5EBD4;
    --bg-control: #D8C69D;

    --text-primary: #30291F;
    --text-secondary: #6B5E49;
    --text-muted: #6B5E49;
    /* El crema #FDF8EC de la paleta daba 4.48:1 sobre el oliva --accent-green,
       a un pelo de AA. Blanco puro sube a 4.75:1 y no desalinea nada de
       TUNA-Screen: DesertColors no define un color "sobre acento", este valor
       siempre fue una derivación del lado de NOPAL. */
    --text-on-accent: #FFFFFF;

    --border-soft: #9A8258;
    --border-medium: #9A8258;

    --accent-green: #687A32;
    --accent-green-hover: #5C6C2C;
    --accent-green-soft: #E3E4C9;
    --accent-green-border: #C3C79A;
    --accent-green-strong: #4E5C25;

    --state-success: #4E5C25;
    --state-success-soft: #E3E4C9;
    --state-warning: #B66A1F;
    --state-warning-soft: #F3DFC4;
    --state-danger: #A63D32;
    --state-danger-soft: #F0D8D3;
    --state-info: #3B82C4;
    --state-info-soft: #EAF3FB;
    --state-purple: #8A63D2;
    --state-purple-soft: #F1ECFB;
    --state-orange: #B66A1F;
    --state-orange-soft: #F3DFC4;

    /* Nivel 2 de la capa de tokens: los mismos roles que usan los otros tres
       temas, mapeados a la paleta Desert de arriba. Existe para que un
       componente nuevo pueda escribir var(--surface-raised) y funcionar en
       los cuatro temas sin conocer ni --bg-card ni --card-bg. */
    --surface-base: var(--bg-app);
    --surface-raised: var(--bg-card);
    --surface-sunken: var(--bg-modal);
    --surface-nav: var(--bg-surface);

    --text-strong: var(--text-primary);
    --text-soft: var(--text-secondary);
    --text-faint: var(--text-muted);

    --border-subtle: var(--border-soft);
    /* --border-soft (#9A8258) da 3.1:1 contra --bg-card, justo en el límite y
       solo por poco: para el contorno de un control se usa uno más marcado. */
    --border-control: #8B7550;

    --accent-fill: var(--accent-green);
    --accent-fill-hover: var(--accent-green-hover);
    --accent-fill-active: var(--accent-green-strong);
    --accent-ink: var(--accent-green-strong);
    --accent-on: var(--text-on-accent);
    --accent-fill-rgb: 104, 122, 50;

    --status-ok: var(--state-success);
    --status-warn: var(--state-warning);
    --status-danger: var(--state-danger);
    --status-info: var(--state-info);

    --green-emphasis: var(--accent-green-strong);
    --violet: var(--state-purple);

    /* Compatibilidad con los componentes actuales. */
    --bg: var(--bg-app);
    --sidebar-bg: var(--bg-surface);
    --card-bg: var(--bg-card);
    --panel-bg: var(--bg-modal);
    --border: var(--border-soft);
    --text: var(--text-primary);
    --green: var(--accent-green);
    --green-rgb: 104, 122, 50;
    --green-dark: var(--accent-green-strong);
    --accent: var(--accent-green);
    --accent-rgb: 104, 122, 50;
    --accent-hover: var(--accent-green-hover);
    --accent-active: var(--accent-green-strong);
    --orange: var(--state-warning);
    --orange-light: var(--state-orange);
    /* #B66A1F -- para que el recuadro de CNC del sidebar (rgba(var(--orange-rgb),…))
       use el ámbar apagado de Desert en vez del ámbar saturado fijo de los
       otros temas. */
    --orange-rgb: 182, 106, 31;
    --purple: var(--state-purple);
    --purple-rgb: 138, 99, 210;
    /* --black se usa como texto/fondo de alto contraste (nav lateral,
       botones íconos, .button) -- el valor literal "black" de la paleta
       Kotlin (crema #FDF8EC) quedaba casi blanco sobre el sidebar claro,
       invisible. Antes se resolvía con un ladrillo/terracota fijo,
       aparte de la paleta; ahora toma el mismo color de texto que ya usa
       Desert para todo lo demás (mismo criterio que --black en los otros
       cuatro temas, que también apunta a su --text-strong). */
    --black: var(--text-strong);

    /* --light-wallpaper la fija applyLightWallpaper() según lo elegido en
       Configuración > Apariencia -- el url() de acá es solo el fallback
       para cuando no hay nada guardado todavía. */
    background-image: var(--light-wallpaper, url('../img/fondoClaro1.webp'));
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

body.dark {
    background-image: url('../img/fondo_NOPAL_BLACK.webp');
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

body.green {
    /* --nopal-wallpaper la fija applyNopalWallpaper() según lo elegido en
       Configuración > Apariencia -- el url() de acá es solo el fallback
       (el fondo de siempre) para cuando no hay nada guardado todavía. */
    background-image: var(--nopal-wallpaper, url('../img/fondo_NOPAL_RED.webp'));
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

body.red {
    /* --red-wallpaper la fija applyRedWallpaper() según lo elegido en
       Configuración > Apariencia -- el url() de acá es solo el fallback
       (el fondo de siempre) para cuando no hay nada guardado todavía. */
    background-image: var(--red-wallpaper, url('../img/fondo_NOPAL_GRAY.webp'));
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

button {
    font: inherit;
    cursor: pointer;
}

/* ── Scrollbars: finas, flotantes y semitransparentes en toda la app ── */

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(148, 163, 184, 0.4) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background-color: rgba(148, 163, 184, 0.35);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

*::-webkit-scrollbar-thumb:hover {
    background-color: rgba(148, 163, 184, 0.6);
}

*::-webkit-scrollbar-corner {
    background: transparent;
}

/* ── Flechas nativas de <input type="number">: que sigan el tema activo ── */

input[type="number"] {
    color-scheme: dark;
}

body.light input[type="number"] {
    color-scheme: light;
}

/* ── Shell ── */

.app-shell {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 240px 1fr;
    grid-template-rows: var(--topbar-height) 1fr;
    grid-template-areas:
        "sidebar topbar"
        "sidebar content";
    height: 100vh;
}

/* ── Fondo animado: patrón de circuito que se desliza lentamente hacia arriba ── */

body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: url('../img/motif-circuit.svg');
    background-repeat: repeat;
    background-size: 304px 304px;
    opacity: 0.2;
    animation: circuitDrift 50s linear infinite;
}

/* El SVG trae el trazo en negro (fill-opacity 0.15): sobre temas oscuros
   se invierte a blanco para que el patrón siga siendo visible. */
body.dark::before,
body.green::before,
body.red::before,
body.custom::before {
    filter: invert(1);
}

@keyframes circuitDrift {
    from { background-position: 0 0; }
    to { background-position: 0 -304px; }
}

/* ── Sidebar ── */

.sidebar {
    grid-area: sidebar;
    position: relative;
    background: var(--sidebar-bg);
    padding: 28px 16px;
    display: flex;
    flex-direction: column;
    gap: 32px;
    height: 100%;
    overflow: hidden;
}

/* En el tema Desert el sidebar quedaba un bloque sólido opaco encima del
   fondo temático (wallpaper con textura), tapándolo por completo -- acá se
   le da el mismo vidrio translúcido + blur que ya usan las tarjetas del
   resto de la app. */
body.light .sidebar {
    background: color-mix(in srgb, var(--sidebar-bg) 40%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

/* Fondo oscuro detrás del cajón lateral en mobile (ver @media max-width:
   768px más abajo) — clic/tap sobre él cierra el menú, igual que el botón
   hamburguesa. Sin efecto en escritorio, donde el sidebar es parte fija
   del layout y esta capa nunca se activa. */
.mobile-nav-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 149;
    background: rgba(0, 0, 0, 0.5);
}

.sidebar-logo-gap {
    display: none;
}

.app-shell.sidebar-collapsed .sidebar-logo-gap {
    display: flex;
    flex: 1;
    min-height: 0;
    align-items: flex-start;
    justify-content: center;
    padding-top: 12px;
    overflow: hidden;
}

.sidebar-logo-bg {
    position: relative;
    z-index: 2;
    height: 76px;
    width: auto;
    max-width: none;
    transform: rotate(-90deg);
    opacity: 0.7;
    pointer-events: none;
}

body.dark .sidebar,
body.green .sidebar {
    /* Antes era "transparent" a secas para que el sidebar se fundiera con
       el fondo -- se veía bien con los fondos abstractos originales, pero
       con un wallpaper más detallado (ej. una foto) los botones del menú
       se pierden por completo. El degradado mantiene el mismo efecto de
       "fusión" pero sin sacrificar el contraste del contenido. */
    background: linear-gradient(180deg, rgba(0, 0, 0, .6), transparent);
}

.brand {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 8px;
}

.brand-logo {
    width: auto;
    height: auto;
    max-height: 140px;
    object-fit: contain;
}

.sidebar-toggle-btn {
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border: 1px solid var(--accent);
    border-radius: 8px;
    background: transparent;
    color: var(--accent);
    cursor: pointer;
    transition: background 0.15s ease;
}

.sidebar-toggle-btn:hover {
    background: rgba(var(--accent-rgb), 0.12);
}

.sidebar-toggle-btn svg {
    transition: transform 0.2s ease;
}

/* ── Barra superior global (notificaciones/idioma/usuario) — solo ocupa el
   ancho de .content, el logo/toggle vive en el sidebar como siempre. NO
   confundir con .topbar, que existe por sección dentro de .content y queda
   intacta. ── */

.global-topbar {
    grid-area: topbar;
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 0 20px;
    background: linear-gradient(to left, var(--sidebar-bg) 0%, transparent 100%);
    border-bottom: 1px solid var(--border);
}

body.dark .global-topbar,
body.green .global-topbar {
    background: linear-gradient(to left, var(--card-bg) 0%, transparent 100%);
}

.global-topbar-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

.global-topbar-left {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

/* Botón hamburguesa: abre el cajón lateral (.sidebar) en mobile. Oculto en
   escritorio — el sidebar siempre está visible ahí, no hace falta. Se
   muestra dentro de @media (max-width: 768px) más abajo, junto con el resto
   de los ajustes de layout mobile del shell.
   Selector compuesto (no solo .mobile-nav-toggle-btn): el botón también
   lleva .topbar-icon-btn, que fija display:inline-flex más abajo en este
   mismo archivo -- con la misma especificidad (una sola clase cada uno),
   gana la regla que aparece después, y el botón quedaba visible siempre en
   vez de solo en mobile. */
.topbar-icon-btn.mobile-nav-toggle-btn {
    display: none;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    padding: 0;
}

/* Reloj centrado en la topbar global (independiente de .global-topbar-left/
   -right para no quedar atado al ancho de ninguno de los dos), 10% más
   grande que el resto de las píldoras de la topbar. */
.global-topbar-clock {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
}

.global-topbar-clock .panel-clock {
    pointer-events: auto;
    padding: 9px 18px;
}

.global-topbar-clock .panel-clock svg {
    width: 16.5px;
    height: 16.5px;
}

.global-topbar-clock .panel-clock-text strong {
    font-size: 0.9rem;
}

.global-topbar-clock .panel-clock-text span {
    font-size: 0.7rem;
}


/* ── Sidebar contraída: solo iconos ── */

.app-shell.sidebar-collapsed {
    grid-template-columns: 76px 1fr;
}

.app-shell.sidebar-collapsed .sidebar {
    padding: 28px 10px;
}

.app-shell.sidebar-collapsed .brand {
    justify-content: center;
}

.app-shell.sidebar-collapsed .brand-logo {
    display: none;
}

.app-shell.sidebar-collapsed .sidebar-toggle-btn svg {
    transform: rotate(180deg);
}

/* Contraído: puro ícono, sin la caja redondeada de fondo/borde que sí
   lleva expandido -- se quita background/border/sombra acá para no tener
   que tocar la regla base de .nav-item (que las 3 secciones con color fijo
   de abajo y el estado hover/active en expandido siguen usando). */
.app-shell.sidebar-collapsed .nav-item {
    justify-content: center;
    padding: 12px 8px;
    background: none;
    border-color: transparent;
    box-shadow: none;
}

.app-shell.sidebar-collapsed .nav-item:not(.active):hover,
.app-shell.sidebar-collapsed .nav-item:not(.active):focus-visible {
    background: none;
    border-color: transparent;
    box-shadow: none;
}

/* El activo (genérico, CNC y Láser) trae su propio box-shadow con más
   especificidad que la regla base de arriba en esos dos últimos casos
   ([data-section=...].active empata en especificidad y gana por venir
   después en el archivo) -- se repite acá, explícito, para que no
   sobreviva ningún resplandor contraído. El color del ícono (ver
   .active svg más abajo) ya basta para marcar cuál está activo. */
.app-shell.sidebar-collapsed .nav-item.active,
.app-shell.sidebar-collapsed .nav-item[data-section="cnc"].active,
.app-shell.sidebar-collapsed .nav-item[data-section="laser"].active {
    background: none;
    border-color: transparent;
    box-shadow: none;
}

.app-shell.sidebar-collapsed .nav-item span {
    display: none;
}

/* Contraído, la lista de íconos no necesita el flex:1/scroll interno que
   sí hace falta expandido (ver .nav-list base) -- se ajusta a su propio
   contenido y el logo (.sidebar-logo-gap, también flex:1) se lleva el
   resto del espacio, apareciendo justo debajo de los íconos. */
.app-shell.sidebar-collapsed .nav-list {
    flex: 0 0 auto;
    overflow: visible;
}

/* Ícono liso (ni fondo ni color propio) salvo Impresión 3D/Láser/CNC/
   plugins (su propio color fijo, ver más abajo) y el activo (--accent). */
.app-shell.sidebar-collapsed .nav-item svg {
    color: var(--text-muted);
}

.app-shell.sidebar-collapsed .nav-item.active svg {
    color: var(--accent);
}

.app-shell.sidebar-collapsed .nav-item[data-section="models"] svg {
    color: var(--accent);
}

.app-shell.sidebar-collapsed .nav-item[data-section="cnc"] svg {
    color: var(--orange);
}

.app-shell.sidebar-collapsed .nav-item[data-section="laser"] svg {
    color: var(--purple);
}

.app-shell.sidebar-collapsed .nav-item[data-plugin-nav] svg {
    color: rgb(var(--plugin-nav-rgb));
}

.app-shell.sidebar-collapsed .sidebar-actions-card {
    flex-direction: column;
    justify-content: center;
    /* Con la sidebar angosta (76px) los 3 botones en fila quedaban
       amontonados y minúsculos con el zoom:0.7 base -- en columna entran
       cómodos, y subimos el zoom ~10% (0.7 -> 0.77) para que no se vean
       tan chicos sin volver a desbordar el ancho colapsado. */
    zoom: 0.77;
    /* Sin contorno/tarjeta contraído -- puro ícono, mismo criterio que los
       .nav-item de arriba en este mismo estado. */
    background: none;
    border: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
}

.app-shell.sidebar-collapsed .sidebar .sidebar-actions-card .btn-icon-light {
    background: none;
}

.app-shell.sidebar-collapsed .sidebar .sidebar-actions-card .btn-icon-light:hover {
    background: rgba(255, 255, 255, 0.08);
}

.app-shell.sidebar-collapsed .lang-switch {
    display: none;
}

.nav-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

.nav-category {
    margin-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.nav-category-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 15px;
    border: none;
    background: none;
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
}

.nav-category-chevron {
    flex-shrink: 0;
    transition: transform 0.15s ease;
}

.nav-category.collapsed .nav-category-chevron {
    transform: rotate(-90deg);
}

.nav-category.collapsed .nav-category-items {
    display: none;
}

.nav-category-items {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.nav-item-placeholder {
    cursor: default;
    opacity: 0.5;
    pointer-events: none;
}

.nav-item-soon-badge {
    margin-left: auto;
    padding: 2px 7px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.18);
    color: var(--text-muted);
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    flex-shrink: 0;
}

.app-shell.sidebar-collapsed .nav-category-header {
    display: none;
}

.app-shell.sidebar-collapsed .nav-category.collapsed .nav-category-items {
    display: flex;
}

.app-shell.sidebar-collapsed .nav-item-soon-badge {
    display: none;
}

.app-shell.sidebar-collapsed .nav-item-badge {
    display: none;
}

/* En modo contraído el número no cabe, así que un pulso morado centrado
   sobre el icono indica que esa sección tiene trabajos nuevos en cola. */
.app-shell.sidebar-collapsed .nav-item.has-queue-items::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 36px;
    height: 36px;
    border: 2px solid #a855f7;
    border-radius: 12px;
    pointer-events: none;
    transform: translate(-50%, -50%);
    animation: sidebarQueuePulse 1.6s ease-out infinite;
}

@keyframes sidebarQueuePulse {
    0% {
        opacity: 0.95;
        box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.65);
    }
    70% {
        opacity: 0.35;
        box-shadow: 0 0 0 8px rgba(168, 85, 247, 0);
    }
    100% {
        opacity: 0.9;
        box-shadow: 0 0 0 0 rgba(168, 85, 247, 0);
    }
}

.nav-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 15px;
    border-radius: var(--radius-md);
    color: var(--black);
    background: rgba(var(--accent-rgb), 0.03);
    border: 1px solid var(--border);
    text-align: left;
    font-size: 0.92rem;
    font-weight: 500;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}


.nav-item svg {
    flex-shrink: 0;
}

/* Badge numérico de trabajos en cola (esperando turno, sin contar el que ya
   está corriendo) — Impresión 3D, Láser y CNC. Se oculta por completo con
   [hidden] en vez de mostrar "0" cuando no hay nada en cola. */
.nav-item-badge {
    position: absolute;
    top: 50%;
    right: 10px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    pointer-events: none;
    transform: translateY(-50%);
}

.nav-item:not(.active):hover,
.nav-item:not(.active):focus-visible {
    background: rgba(var(--accent-rgb), 0.08);
    border-color: rgba(var(--accent-rgb), 0.55);
    color: var(--accent);
    box-shadow: 0 0 10px rgba(var(--accent-rgb), 0.18);
}

.nav-item.active {
    background: rgba(var(--accent-rgb), 0.16);
    border-color: var(--accent);
    color: var(--accent);
    box-shadow: 0 0 14px rgba(var(--accent-rgb), 0.35);
}

/* ── CNC y Láser tienen su propio color en el sidebar, no el de acento --
   pero SÍ el de su tema: usan --orange-rgb/--purple-rgb (definidas por
   tema, ver body.light etc. más arriba) en vez de un rgb() fijo. Antes
   estaban fijos al ámbar/violeta del tema oscuro incluso en Desert, que
   define un ámbar mucho más apagado (--orange: #B66A1F) -- se veía
   desentonado contra el resto del sidebar en ese tema. ── */

.nav-item[data-section="cnc"] {
    background: rgba(var(--orange-rgb), 0.08);
    border-color: rgba(var(--orange-rgb), 0.35);
}

.nav-item[data-section="cnc"]:not(.active):hover,
.nav-item[data-section="cnc"]:not(.active):focus-visible {
    background: rgba(var(--orange-rgb), 0.14);
    border-color: rgba(var(--orange-rgb), 0.6);
    color: var(--orange);
    box-shadow: 0 0 10px rgba(var(--orange-rgb), 0.22);
}

.nav-item[data-section="cnc"].active {
    background: rgba(var(--orange-rgb), 0.22);
    border-color: var(--orange);
    color: var(--orange);
    box-shadow: 0 0 14px rgba(var(--orange-rgb), 0.4);
}

.nav-item[data-section="laser"] {
    background: rgba(var(--purple-rgb), 0.08);
    border-color: rgba(var(--purple-rgb), 0.35);
}

.nav-item[data-section="laser"]:not(.active):hover,
.nav-item[data-section="laser"]:not(.active):focus-visible {
    background: rgba(var(--purple-rgb), 0.14);
    border-color: rgba(var(--purple-rgb), 0.6);
    color: var(--purple);
    box-shadow: 0 0 10px rgba(var(--purple-rgb), 0.22);
}

.nav-item[data-section="laser"].active {
    background: rgba(var(--purple-rgb), 0.22);
    border-color: var(--purple);
    color: var(--purple);
    box-shadow: 0 0 14px rgba(var(--purple-rgb), 0.4);
}

/* ── Indicador de plugin en el sidebar ──
   Todo botón que un plugin agrega a sí mismo al sidebar trae
   data-plugin-nav="<id-del-plugin>" (ver mount() en cada frontend/*.js de
   plugins/) sin importar en qué grupo del menú caiga (Cotizador vive en
   "Trabajos", no en "Plugins"). Selecciona por ese atributo -- no por
   data-section, que es la ruta interna de cada plugin (ej. cotizador usa
   "pricing") y no sirve como identificador estable.
   Antes llevaba un puntito de pieza de rompecabezas superpuesto (::after)
   -- a pedido se quitó y en su lugar el ícono del botón se tiñe directo
   con --plugin-nav-rgb (mismo criterio que ya usan Impresión 3D/Láser/CNC
   con --accent/--purple/--orange), tanto expandido como contraído. El
   fallback es el acento del tema para plugins nuevos que no tengan un
   color específico asignado todavía acá abajo. */
.nav-item[data-plugin-nav] {
    --plugin-nav-rgb: var(--accent-rgb);
}
.nav-item[data-plugin-nav] svg {
    color: rgb(var(--plugin-nav-rgb));
}

.nav-item[data-plugin-nav="cotizador"] { --plugin-nav-rgb: 234, 179, 8; }
.nav-item[data-plugin-nav="arduino-accessories"] { --plugin-nav-rgb: 59, 130, 246; }
.nav-item[data-plugin-nav="camera-viewer"] { --plugin-nav-rgb: 236, 72, 153; }
.nav-item[data-plugin-nav="spoolman"] { --plugin-nav-rgb: 20, 184, 166; }

.sidebar-actions-card {
    display: flex;
    align-items: stretch;
    justify-content: center;
    flex-wrap: nowrap;
    gap: 6px;
    margin-top: auto;
    margin-bottom: 6px;
    padding: 6px;
    background: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    border-radius: var(--radius-lg);
    zoom: 0.7;
}

.sidebar-actions-card > * {
    flex: 1;
    min-width: 0;
}

.sidebar .sidebar-actions-card .btn-icon-light {
    width: auto;
    height: auto;
    padding: 9px 6px;
    background: rgba(255, 255, 255, 0.06);
    /* Antes blanco fijo -- invisible en temas claros (Desert). var(--black)
       es el mismo tono de alto contraste que ya usan los ítems del nav. */
    color: var(--black);
    border: none;
    border-radius: 10px;
}

.sidebar .sidebar-actions-card .btn-icon-light:hover {
    background: rgba(255, 255, 255, 0.12);
    opacity: 1;
}

/* Resplandor pulsante en el botón de Configuración -- usa --accent-rgb (no
   un color fijo) para que se adapte solo a cualquiera de los temas. */
.sidebar-settings-btn {
    animation: sidebarSettingsPulse 2.2s ease-in-out infinite;
}

@keyframes sidebarSettingsPulse {
    0%, 100% { box-shadow: 0 0 0 rgba(var(--accent-rgb), 0); }
    50% { box-shadow: 0 0 12px 2px rgba(var(--accent-rgb), 0.65); }
}

@media (prefers-reduced-motion: reduce) {
    .sidebar-settings-btn {
        animation: none;
        box-shadow: 0 0 8px 1px rgba(var(--accent-rgb), 0.45);
    }
}

/* ── Content ── */

.content {
    grid-area: content;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    height: 100%;
    overflow: auto;
}

/* ── Panel de Control (hero superior del dashboard) ──
   Reemplaza la vieja ficha "Host" + gauges de la topbar y el <h1> plano:
   ahora vive dentro de <main>, arriba de la sección "Dispositivos", que
   sigue intacta debajo. La topbar global (plugins/notificaciones/idioma/
   usuario) es un elemento aparte (.global-topbar) y no se toca acá. ── */

.panel-hero {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 20px;
    margin-bottom: 20px;
}

/* Título + subtítulo del panel viven en la topbar global (ver
   .global-topbar-panel-title más abajo) — solo se muestran en la sección
   Inicio, alternado por switchSection(). */

.global-topbar-panel-title {
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-left: 16px;
    min-width: 0;
    line-height: 1.2;
}

.global-topbar-panel-title h1 {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--text);
    white-space: nowrap;
}

.global-topbar-panel-title p {
    font-size: 0.66rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.panel-hero-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    padding-right: 14px;
    margin-right: 4px;
    border-right: 1px solid var(--border);
}

.panel-status-pill {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border-radius: 999px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    cursor: default;
}

.panel-status-pill.panel-status-blink {
    cursor: pointer;
    animation: panelStatusBlink 1.1s ease-in-out infinite;
}

/* Punto discreto (sin parpadeo, no es una emergencia) que indica que hay una
   actualización disponible aunque el sistema esté sano -- así el indicador
   sigue siendo visible/clickeable sin pintar todo el pill de "error". */
.panel-status-pill.panel-status-has-update {
    cursor: pointer;
}

.panel-status-pill.panel-status-has-update::after {
    content: '';
    position: absolute;
    top: -3px;
    right: -3px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--card-bg);
}

@keyframes panelStatusBlink {
    0%, 100% { border-color: #ef4444; box-shadow: 0 0 0 rgba(239, 68, 68, 0); }
    50% { border-color: #ef4444; box-shadow: 0 0 10px rgba(239, 68, 68, 0.55); }
}

@media (prefers-reduced-motion: reduce) {
    .panel-status-pill.panel-status-blink {
        animation: none;
        border-color: #ef4444;
    }
}

.panel-status-popup {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 20;
    min-width: 260px;
    max-width: 320px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35);
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    cursor: default;
    animation: none;
}

.panel-status-popup-header {
    padding: 8px 10px 6px;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.panel-status-popup-item {
    display: flex;
    align-items: center;
    gap: 2px;
    border-radius: var(--radius-sm);
}

.panel-status-popup-item:hover {
    background: rgba(239, 68, 68, 0.12);
}

.panel-status-popup-item-main {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text);
    font-size: 0.78rem;
    text-align: left;
    cursor: pointer;
}

.panel-status-popup-item-main span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.panel-status-popup-item img,
.panel-status-popup-item svg,
.panel-status-popup-update img,
.panel-status-popup-update svg {
    flex-shrink: 0;
    width: 16px;
    height: 16px;
}

.panel-status-popup-dismiss {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    margin-right: 6px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.panel-status-popup-dismiss:hover {
    background: rgba(239, 68, 68, 0.18);
    color: #ef4444;
}

.panel-status-popup-update {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin-top: 4px;
    padding: 8px 10px;
    border: none;
    border-top: 1px solid var(--border);
    border-radius: 0;
    background: transparent;
    color: var(--text);
    font-size: 0.78rem;
    text-align: left;
    cursor: pointer;
}

.panel-status-popup-update:hover {
    background: rgba(var(--accent-rgb), 0.12);
}

.panel-status-popup-update-badge {
    margin-left: auto;
    flex-shrink: 0;
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--accent);
}

.panel-status-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--green);
    box-shadow: 0 0 8px rgba(var(--green-rgb), 0.7);
    flex-shrink: 0;
}

.panel-status-pill.panel-status-warning .panel-status-dot {
    background: var(--orange);
    box-shadow: 0 0 8px rgba(245, 158, 11, 0.6);
}

.panel-status-pill.panel-status-error .panel-status-dot {
    background: #ef4444;
    box-shadow: 0 0 8px rgba(239, 68, 68, 0.6);
}

.panel-status-text {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--text);
}

.panel-clock {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text-muted);
}

.panel-clock-text {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.panel-clock-text strong {
    font-size: 0.82rem;
    color: var(--text);
}

.panel-clock-text span {
    font-size: 0.64rem;
    text-transform: capitalize;
}

/* Ocultar-al-pasar-el-mouse (opcional, ver Configuración > Apariencia y
   UI/UX): truco de grid-template-rows 1fr→0fr para animar una altura que no
   se puede fijar de antemano (el contenido cambia de tamaño según cuántos
   dispositivos/trabajos haya). Sin JS de por medio en la animación misma,
   solo togglea la clase .collapsed. */
.panel-hero-collapsible {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.32s ease;
}

.panel-hero-collapsible.collapsed {
    grid-template-rows: 0fr;
}

.panel-hero-collapsible-inner {
    overflow: hidden;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Vive fuera de .panel-hero-collapsible a propósito -- si estuviera adentro
   desaparecería junto con el resto del contenido al colapsar (overflow:
   hidden + grid-template-rows: 0fr) y no habría forma de volver a
   expandirlo con el mouse. */
.panel-hero-toggle-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 18px;
    margin: -9px 0 8px;
    padding: 0;
    border: none;
    border-radius: 0 0 10px 10px;
    /* Semitransparente de verdad (no un color fijo) -- color-mix con la
       variable del tema activo hace que se vea bien en los 5 temas sin
       hardcodear ningún valor. Amarillo/--orange a propósito: marca visualmente
       el control que colapsa/expande el panel superior. */
    background: color-mix(in srgb, var(--orange) 20%, transparent);
    color: var(--text-secondary);
    cursor: pointer;
    position: relative;
    z-index: 2;
    transition: background 0.15s ease, color 0.15s ease;
}

.panel-hero-toggle-btn:hover {
    background: color-mix(in srgb, var(--orange) 32%, transparent);
    color: var(--text);
}

.panel-hero-toggle-btn svg {
    transition: transform 0.32s ease;
    /* Abierto (estado por defecto, sin .collapsed) = flecha hacia arriba. */
    transform: rotate(180deg);
}

.panel-hero-collapsible.collapsed ~ .panel-hero-toggle-btn svg {
    /* Cerrado = flecha hacia abajo (forma original del SVG, sin rotar). */
    transform: rotate(0deg);
}

.panel-row {
    display: grid;
    gap: 12px;
}

/* Grid único del hero (antes dos filas independientes, panel-row-3 +
   panel-row-2): "Dispositivos conectados" va apilada debajo de "Estado del
   sistema", "Red y conectividad" apilada debajo de "Rendimiento del host",
   y "Trabajos en curso" ocupa las 2 filas como columna alta a la derecha --
   layout pedido explícitamente por el usuario sobre una captura de la app. */
.panel-hero-grid {
    grid-template-columns: 1.1fr 1fr 1.3fr;
    grid-template-rows: auto auto;
    grid-template-areas:
        "estado host trabajos"
        "dispositivos red trabajos";
}

.panel-card-pos-estado { grid-area: estado; }
.panel-card-pos-host { grid-area: host; }
.panel-card-pos-dispositivos { grid-area: dispositivos; }
.panel-card-pos-red { grid-area: red; }
.panel-card-pos-trabajos {
    grid-area: trabajos;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.panel-card-pos-trabajos .panel-jobs-list {
    flex: 1;
    max-height: none;
}

.panel-row-bottom {
    grid-template-columns: 1.4fr 1fr 1fr 1fr;
}

.panel-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px 18px;
    min-width: 0;
}

/* Las fichas del panel superior colapsable usan un tono distinto a
   --card-bg (el mismo que usan las tarjetas de dispositivos más abajo) para
   que se lea como un panel aparte, no como parte de la grilla. */
.panel-hero-collapsible-inner .panel-card {
    background: var(--panel-bg);
}

.panel-card-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--accent);
    margin-bottom: 12px;
}

.panel-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 12px;
}

.panel-card-header .panel-card-title {
    margin-bottom: 0;
}

.panel-see-all-btn {
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    transition: background 0.15s ease, color 0.15s ease;
}

.panel-see-all-btn:hover {
    background: rgba(var(--accent-rgb), 0.12);
    color: var(--accent);
}

/* Estado del sistema — logo hexagonal a la izquierda, filas ícono+label/valor
   apiladas a la derecha (íconos y valores en verde acento, como el resto de
   la ficha; solo el valor de "Salud del sistema" cambia de color si hay
   advertencias/errores). */

.panel-health-body {
    display: flex;
    align-items: center;
    gap: 18px;
}

.panel-health-logo {
    flex-shrink: 0;
    width: 78px;
}

.panel-health-logo img {
    width: 100%;
    height: auto;
    display: block;
    filter: drop-shadow(0 0 10px rgba(var(--accent-rgb), 0.35));
}

.panel-info-grid {
    display: flex;
    flex-direction: column;
    gap: 11px;
    flex: 1;
    min-width: 0;
}

.panel-info-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.panel-info-row svg {
    flex-shrink: 0;
    color: var(--accent);
}

.panel-info-row-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.panel-info-row-label {
    font-size: 0.72rem;
    color: var(--text-muted);
}

.panel-info-row-value {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.panel-info-row-value-warning {
    color: var(--orange);
}

.panel-info-row-value-error {
    color: #ef4444;
}

/* Red y conectividad — grilla 2x2 (etiqueta arriba, valor grande debajo),
   sin íconos por celda, con una línea divisoria entre las dos filas. */

.panel-network-wifi-icon {
    color: var(--accent);
    flex-shrink: 0;
}

.panel-network-grid {
    display: flex;
    flex-direction: column;
}

.panel-network-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    padding: 10px 0;
}

.panel-network-row:first-child {
    border-bottom: 1px solid rgba(148, 163, 184, 0.15);
}

.panel-network-cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.panel-network-label {
    font-size: 0.78rem;
    color: var(--text-muted);
}

.panel-network-value {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Gauges (Rendimiento del host) — mismo lenguaje visual que antes en la
   topbar (anillo SVG con stroke-dashoffset), reutilizado acá. */

.panel-host-gauges {
    display: flex;
    align-items: center;
    justify-content: space-around;
    gap: 8px;
    padding-top: 4px;
}

.panel-load-chart {
    position: relative;
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid rgba(148, 163, 184, 0.15);
    height: 56px;
}

.panel-load-chart:empty {
    display: none;
}

.panel-load-chart-svg {
    width: 100%;
    height: 100%;
    display: block;
    overflow: visible;
}

.panel-load-chart-line {
    fill: none;
    stroke: var(--green-dark);
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.panel-load-chart-area {
    fill: rgba(var(--green-rgb), 0.14);
    stroke: none;
}

.panel-load-chart-empty {
    position: absolute;
    inset: 10px 0 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.7rem;
    color: var(--text-muted);
}

.panel-load-chart-avg {
    position: absolute;
    right: 0;
    bottom: 2px;
    font-size: 0.68rem;
    color: var(--text-muted);
}

.panel-load-chart-avg strong {
    color: var(--text);
    font-weight: 700;
}

.panel-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.panel-gauge-ring {
    position: relative;
    width: 84px;
    height: 84px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.panel-gauge-ring svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.panel-gauge-ring .gauge-value {
    position: relative;
    font-size: 1.3rem;
    font-weight: 800;
    color: var(--text);
}

.panel-gauge-label {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}

.panel-gauge-sub {
    font-size: 0.62rem;
    color: var(--text-muted);
    white-space: nowrap;
}

.gauge-track {
    fill: none;
    stroke: rgba(148, 163, 184, 0.2);
    stroke-width: 8;
}

.gauge-fill {
    fill: none;
    stroke-width: 8;
    stroke-linecap: round;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
    transition: stroke-dashoffset 0.4s ease;
}

.gauge-fill-cpu {
    stroke: var(--green-dark);
}

.gauge-fill-mem {
    stroke: var(--orange);
}

.gauge-fill-disk {
    stroke: var(--purple);
}

.panel-empty-state {
    padding: 20px 0;
    text-align: center;
    font-size: 0.78rem;
    color: var(--text-muted);
}

/* Dispositivos conectados */

.panel-devices-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
}

.panel-device-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 12px 8px;
    border-left: 1px solid rgba(148, 163, 184, 0.18);
}

.panel-device-tile:first-child {
    border-left: none;
}

.panel-device-tile-soon {
    opacity: 0.5;
}

.panel-device-icon {
    color: var(--accent);
    margin-bottom: 2px;
}

.panel-device-icon-img {
    width: 26px;
    height: 26px;
    object-fit: contain;
    display: block;
}

.panel-device-tile strong {
    font-size: 1.56rem;
    font-weight: 800;
    color: var(--text);
}

.panel-device-tile > span {
    font-size: 0.66rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Trabajos en curso */

.panel-jobs-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 190px;
    overflow-y: auto;
}

.panel-job-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
        "icon info progress"
        "icon meta meta"
        "camera camera camera";
    column-gap: 10px;
    row-gap: 4px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    background: var(--panel-bg);
    border: 1px solid var(--border);
    align-items: center;
}

/* Miniatura de la cámara vinculada al dispositivo de este trabajo (ver
   camera-card.js) -- solo existe en el HTML cuando el trabajo trae
   device_type/device_id Y esa máquina tiene una cámara vinculada, así que
   la fila de abajo no ocupa espacio en el caso común (sin cámara). */
.panel-job-camera { grid-area: camera; }
.panel-job-camera:empty { display: none; }
.panel-job-camera .cam-live-wrap { max-height: 90px; }

.panel-job-icon {
    grid-area: icon;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}

.panel-job-icon-laser {
    background: rgba(var(--purple-rgb), 0.14);
    color: var(--purple);
}

.panel-job-icon-cnc {
    background: rgba(245, 158, 11, 0.14);
    color: var(--orange);
}

.panel-job-info {
    grid-area: info;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.panel-job-info strong {
    font-size: 0.82rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.panel-job-info span {
    font-size: 0.68rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.panel-job-progress-ring {
    grid-area: progress;
    position: relative;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: conic-gradient(var(--green-dark) calc(var(--panel-job-progress, 0) * 1%), var(--border) 0);
    flex-shrink: 0;
}

.panel-job-progress-ring::before {
    content: '';
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    background: var(--panel-bg);
}

.panel-job-progress-ring span {
    position: relative;
    font-size: 0.58rem;
    font-weight: 800;
    color: var(--text);
}

.panel-job-meta {
    grid-area: meta;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 0.66rem;
    color: var(--text-muted);
}

.panel-job-meta strong {
    color: var(--text);
    margin-left: 3px;
}

.panel-job-state {
    text-transform: capitalize;
}

/* Fila inferior: alertas / ambiente / consumo / mantenimiento */

.panel-row-bottom .panel-card {
    padding: 14px 16px;
}

.panel-alerts-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
}

.panel-alert-tile {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 6px 8px;
    border-left: 1px solid rgba(148, 163, 184, 0.18);
}

.panel-alert-tile:first-child {
    border-left: none;
}

.panel-alert-tile svg {
    color: var(--text-muted);
    flex-shrink: 0;
}

.panel-alert-icon-img {
    width: 29px;
    height: 29px;
    object-fit: contain;
    display: block;
    flex-shrink: 0;
}

.panel-alert-tile-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1px;
    min-width: 0;
}

.panel-alert-tile strong {
    font-size: 1.1rem;
    font-weight: 800;
    color: var(--text);
    line-height: 1.15;
}

.panel-alert-tile span {
    font-size: 0.6rem;
    color: var(--text-muted);
    text-transform: uppercase;
    white-space: nowrap;
}

.panel-alert-tile-error svg,
.panel-alert-tile-error span {
    color: #ef4444;
}

.panel-alert-tile-warning svg,
.panel-alert-tile-warning span {
    color: var(--orange);
}

.panel-alert-tile-info svg,
.panel-alert-tile-info span {
    color: var(--accent);
}

/* Con 3 columnas iguales, etiquetas como "Advertencias"/"Informativas" (o
   sus equivalentes en otros idiomas) con white-space:nowrap no entran en el
   ancho disponible de un teléfono y se cortan/desbordan. Se apila en una
   lista vertical, igual que el resto de las tarjetas del panel a este
   ancho. */
@media (max-width: 560px) {
    .panel-alerts-row {
        grid-template-columns: 1fr;
    }

    .panel-alert-tile {
        justify-content: flex-start;
        border-left: none;
        border-top: 1px solid rgba(148, 163, 184, 0.18);
        padding: 10px 4px;
    }

    .panel-alert-tile:first-child {
        border-top: none;
    }

    .panel-alert-tile-text {
        align-items: flex-start;
        text-align: left;
    }

    .panel-alert-tile span {
        white-space: normal;
    }
}

.panel-card-mini {
    display: flex;
    align-items: center;
    gap: 12px;
}

.panel-mini-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}

.panel-mini-icon-power {
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}

.panel-mini-icon-maintenance {
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}

.panel-mini-icon-img {
    width: 24px;
    height: 24px;
    object-fit: contain;
    display: block;
}

.panel-mini-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.panel-mini-text span {
    font-size: 0.64rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.panel-mini-text strong {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.topbar-search {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    max-width: 640px;
    background: var(--surface);
    border: 1px solid rgba(0, 0, 0, 0.08);
    padding: 12px 18px;
    border-radius: var(--radius-md);
}

body.dark .topbar-search,
body.green .topbar-search {
    background: var(--surface);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.search-icon {
    color: var(--text-muted);
    flex-shrink: 0;
}

.topbar-search input {
    width: 100%;
    border: none;
    outline: none;
    background: transparent;
    color: var(--text);
    font-size: 0.92rem;
}

.topbar-search input::placeholder {
    color: #aaa;
}

body.dark .topbar-search input::placeholder,
body.green .topbar-search input::placeholder {
    color: #9ca3af;
}

.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    border: none;
    border-radius: var(--radius-sm);
    transition: opacity 0.15s ease;
}

.btn-icon:hover {
    opacity: 0.85;
}

/* ── View Sections ── */

.view-section {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    overflow: auto;
}

.page-header {
    padding: 32px 32px 16px;
    border-bottom: 1px solid #f0f0f0;
}

.page-header h1 {
    font-size: 1.6rem;
    font-weight: 700;
    margin: 0;
    color: var(--text);
}

.main-content {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0;
}

.console-macros-main {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.console-macros-topbar {
    display: flex;
    gap: 20px;
    flex-shrink: 0;
    padding: 24px 32px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.console-macros-header.page-header {
    flex: 1;
    min-width: 0;
    padding: 0;
    border-bottom: none;
}

.console-macros-split {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    flex: 1;
    min-height: 0;
    gap: 20px;
    padding: 0 32px 24px;
}

.console-macros-half {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
    overflow-y: auto;
}

.console-printer-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    flex-shrink: 0;
}

.printer-picker-card {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: var(--card-bg);
    color: var(--text);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.printer-picker-card-status {
    margin-left: auto;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #22c55e;
    flex-shrink: 0;
}

.printer-picker-card.offline .printer-picker-card-status {
    color: var(--text-muted);
}

.printer-picker-card.offline {
    opacity: 0.55;
}

.printer-picker-card.offline svg {
    color: var(--text-muted);
}

.printer-picker-card svg {
    color: #22c55e;
    flex-shrink: 0;
}

.printer-picker-card:hover {
    border-color: rgba(34, 197, 94, 0.35);
}

.printer-picker-card.active {
    background: rgba(34, 197, 94, 0.14);
    border-color: rgba(34, 197, 94, 0.5);
    color: #22c55e;
}

.console-card {
    margin: 0;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.console-macros-half .console-log {
    flex: 1;
    min-height: 100px;
    height: auto;
}

.models-full-section {
    padding: 32px;
}

.models-page-content {
    padding: 24px 32px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.models-view-controls {
    display: flex;
    gap: 8px;
}

.models-page-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) 0.9fr;
    grid-template-rows: minmax(0, 1fr);
    gap: 24px;
    flex: 1;
    min-height: 0;
}

.models-table-panel {
    background: linear-gradient(160deg, rgba(74, 93, 46, 0.22) 0%, rgba(54, 69, 34, 0.16) 55%, rgba(34, 43, 21, 0.15) 100%);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 60px rgba(0,0,0,0.08);
    overflow: hidden;
    border: 1px solid rgba(107, 124, 68, 0.28);
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.gcode-table-panel-inner {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    zoom: 1;
}

/* ── Biblioteca: mismo lenguaje visual de la galería de plugins ── */
#models-section,
#gcode-section {
    --library-surface: rgba(15, 23, 42, 0.76);
    --library-surface-strong: rgba(15, 23, 42, 0.9);
    --library-surface-soft: rgba(30, 41, 59, 0.58);
    --library-border: rgba(var(--accent-rgb), 0.3);
}

#models-section {
    --gcode-line: rgba(34, 197, 94, 0.38);
    --gcode-accent-rgb: 34, 197, 94;
    --gcode-surface: color-mix(in srgb, var(--card-bg) 92%, transparent);
    --gcode-surface-soft: color-mix(in srgb, var(--card-bg) 78%, transparent);
}

.models-modern-preview .preview-card-inner { min-height: calc(100vh - 126px); }
.models-modern-preview .preview-card-header { display: flex; align-items: center; justify-content: space-between; }
.models-modern-preview .preview-expand-btn { width: 34px; height: 34px; display: inline-grid; place-items: center; border: 1px solid var(--gcode-line); border-radius: 8px; background: rgba(var(--accent-rgb), .08); color: var(--accent); cursor: pointer; }
.models-modern-preview .preview-favorite-btn { flex: 0 0 auto; border: 0; background: transparent; color: var(--text-muted); font-size: 1.35rem; cursor: pointer; }
.models-modern-preview .preview-favorite-btn.active { color: #fbbf24; }
.models-preview-description { margin: 8px 0 15px; color: var(--text-muted); font-size: .72rem; line-height: 1.45; }
.models-preview-stage { position: relative; flex: 1; min-height: 390px; margin: 4px 0 14px; border: 1px solid rgba(var(--accent-rgb), .22); border-radius: 12px; overflow: hidden; background: rgba(2, 12, 16, .35); }
.models-preview-stage .preview-image { position: absolute; inset: 0; min-height: 0; border-radius: 0; background-image: linear-gradient(rgba(var(--accent-rgb), .06) 1px, transparent 1px), linear-gradient(90deg, rgba(var(--accent-rgb), .06) 1px, transparent 1px) !important; background-size: 32px 32px !important; }
.models-modern-preview .preview-file-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin: 12px 0; }
.models-modern-preview .preview-file-actions .btn-file-action { min-width: 0; justify-content: center; padding: 7px 8px; font-size: .65rem; }
.models-modern-preview .preview-file-actions .btn-file-action:disabled,
.gcode-modern-preview .preview-file-actions .btn-file-action:disabled { opacity: 0.35; cursor: not-allowed; }
.models-goto-printer { width: 100%; justify-content: center; margin-top: 10px; }
.models-modern-table .model-format-icon { width: 38px; height: 38px; display: inline-grid; place-items: center; border: 1px solid rgba(var(--accent-rgb), .35); border-radius: 8px; background: rgba(var(--accent-rgb), .08); color: var(--accent); font-size: .62rem; font-weight: 800; }

@media (max-width: 560px) {
    .models-modern-preview .preview-file-actions { grid-template-columns: 1fr 1fr; }
}

body.light #models-section,
body.light #gcode-section {
    /* Antes blanco puro fijo -- pensado para el viejo tema claro blanco;
       con Desert (fondo/tarjetas color arena) quedaba una tarjeta blanca
       desentonando del resto. color-mix toma el tono de tarjeta real del
       tema activo. */
    --library-surface: color-mix(in srgb, var(--card-bg) 82%, transparent);
    --library-surface-strong: color-mix(in srgb, var(--card-bg) 94%, transparent);
    --library-surface-soft: color-mix(in srgb, var(--card-bg) 68%, transparent);
}

#models-section .models-page-content,
#gcode-section .models-page-content {
    padding: 28px 32px 40px;
}

#models-section .models-page-layout,
#gcode-section .models-page-layout {
    gap: 18px;
}

#models-section .models-table-panel,
#gcode-section .models-table-panel,
#models-section .models-preview-card,
#gcode-section .gcode-preview-card {
    border: 1px solid var(--library-border);
    background:
        radial-gradient(circle at 88% 5%, rgba(var(--accent-rgb), 0.1), transparent 34%),
        var(--library-surface);
    box-shadow: 0 22px 60px rgba(0, 0, 0, 0.2);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

#models-section .models-table-panel:hover,
#gcode-section .models-table-panel:hover,
#models-section .models-preview-card:hover,
#gcode-section .gcode-preview-card:hover {
    border-color: rgba(var(--accent-rgb), 0.46);
}

.library-page-eyebrow {
    display: block;
    margin-bottom: 7px;
    color: var(--accent);
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.12em;
}

#models-section .models-list-header,
#gcode-section .models-list-header {
    padding: 22px 24px 16px;
    border-bottom-color: rgba(148, 163, 184, 0.14);
}

#models-section .models-list-header h2,
#gcode-section .models-list-header h2 {
    font-size: 1.55rem;
}

#models-section .models-list-header p,
#gcode-section .models-list-header p {
    color: var(--text-muted);
    line-height: 1.5;
}

#models-section .models-list-actions .badge,
#gcode-section .models-list-actions .badge {
    padding: 7px 11px;
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
    text-shadow: none;
}

#models-section .section-search,
#gcode-section .section-search {
    border: 1px solid rgba(148, 163, 184, 0.22);
    border-radius: 11px;
    background: var(--library-surface-strong);
}

#models-section .section-search:focus-within,
#gcode-section .section-search:focus-within {
    border-color: rgba(var(--accent-rgb), 0.68);
    box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.1);
}

#models-section .btn-icon-dark,
#gcode-section .btn-icon-dark,
#models-section .btn-view-toggle,
#gcode-section .btn-view-toggle {
    border-color: rgba(var(--accent-rgb), 0.32);
    background: rgba(var(--accent-rgb), 0.09);
    color: var(--accent);
}

#models-section .btn-icon-dark:hover,
#gcode-section .btn-icon-dark:hover,
#models-section .btn-view-toggle:hover,
#gcode-section .btn-view-toggle:hover,
#models-section .btn-view-toggle-active,
#gcode-section .btn-view-toggle-active {
    border-color: rgba(var(--accent-rgb), 0.58);
    background: rgba(var(--accent-rgb), 0.2);
    color: var(--accent-hover);
}

#models-section .models-breadcrumb-row,
#gcode-section .models-breadcrumb-row {
    padding: 11px 24px;
    border-bottom-color: rgba(148, 163, 184, 0.13);
}

#models-section .models-table thead,
#gcode-section .models-table thead {
    background: rgba(148, 163, 184, 0.07);
}

#models-section .models-table tbody tr,
#gcode-section .models-table tbody tr {
    border-bottom-color: rgba(148, 163, 184, 0.11);
}

#models-section .models-table tbody tr:hover,
#models-section .models-table tbody tr.selected,
#gcode-section .models-table tbody tr:hover,
#gcode-section .models-table tbody tr.selected {
    background: rgba(var(--accent-rgb), 0.12);
}

#models-section .models-table td.model-name svg.green-bg,
#gcode-section .models-table td.model-name svg.green-bg {
    background: linear-gradient(135deg, var(--accent-active), var(--accent));
}

#models-section .models-table td.model-name svg.folder-icon,
#gcode-section .models-table td.model-name svg.folder-icon {
    color: var(--accent);
}

#models-section .models-preview-card,
#gcode-section .gcode-preview-card {
    padding: 22px;
}

#models-section .preview-image,
#gcode-section .gcode-preview-scene,
#gcode-section .preview-meta-grid div {
    border: 1px solid rgba(148, 163, 184, 0.16);
    background: var(--library-surface-strong);
}

#models-section .preview-label,
#gcode-section .preview-label,
#models-section .preview-meta-row svg {
    color: var(--accent);
}

#models-section .preview-expand-btn,
#gcode-section .preview-expand-btn,
#models-section .btn-file-action:not(.btn-file-action-danger),
#gcode-section .btn-file-action:not(.btn-file-action-danger) {
    border-color: rgba(var(--accent-rgb), 0.34);
    background: rgba(var(--accent-rgb), 0.1);
    color: var(--accent);
}

#models-section .btn-file-action:not(.btn-file-action-danger):hover,
#gcode-section .btn-file-action:not(.btn-file-action-danger):hover {
    border-color: rgba(var(--accent-rgb), 0.58);
    background: rgba(var(--accent-rgb), 0.2);
    color: var(--accent-hover);
}

#models-section .preview-tip-card {
    border-color: rgba(var(--accent-rgb), 0.28);
    background: rgba(var(--accent-rgb), 0.09);
}

@media (max-width: 980px) {
    #models-section .models-page-content,
    #gcode-section .models-page-content {
        padding: 20px 16px 32px;
    }
}

.models-list-header {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 28px 32px 16px;
    border-bottom: 1px solid rgba(0,0,0,0.08);
}

.models-list-header-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
}

.models-list-header h2 {
    margin: 0;
    font-size: 1.4rem;
}

.models-list-header p {
    margin: 8px 0 0;
    color: var(--text-muted);
}

.models-list-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.models-list-controls {
    display: flex;
    align-items: center;
    gap: 16px;
}

.models-list-controls .section-search {
    max-width: none;
}

.models-breadcrumb-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 32px;
    font-size: 0.82rem;
    color: var(--text-muted);
    border-bottom: 1px solid rgba(148, 163, 184, 0.15);
}

.bulk-actions-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 32px;
    background: rgba(34, 197, 94, 0.08);
    border-bottom: 1px solid rgba(34, 197, 94, 0.2);
}

.bulk-actions-bar #models-bulk-count,
.bulk-actions-bar #gcode-bulk-count {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--green-dark);
    margin-right: 4px;
}

.bulk-actions-clear-btn {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.78rem;
    cursor: pointer;
    text-decoration: underline;
}

.bulk-actions-clear-btn:hover {
    color: var(--text);
}

.row-select-checkbox,
.select-all-checkbox {
    width: 16px;
    height: 16px;
    cursor: pointer;
}

.models-table th.select-col,
.models-table td.select-col {
    width: 36px;
    padding-right: 0;
}

.breadcrumb-label {
    margin-right: 4px;
}

.breadcrumb-segment {
    background: none;
    border: none;
    padding: 2px 4px;
    font-size: 0.82rem;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 6px;
}

.breadcrumb-segment:hover {
    color: var(--green-dark);
    background: rgba(34, 197, 94, 0.1);
}

.breadcrumb-segment:last-child {
    color: var(--text);
    font-weight: 600;
}

.breadcrumb-sep {
    color: var(--text-muted);
    margin: 0 2px;
}

.folder-actions-cell {
    text-align: right;
    white-space: nowrap;
}

.folder-action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 8px;
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-muted);
    margin-left: 6px;
    transition: background 0.15s ease, color 0.15s ease;
}

.folder-action-btn:hover {
    color: var(--text);
    background: rgba(148, 163, 184, 0.25);
}

.folder-action-btn[data-action="rename"] {
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
}
.folder-action-btn[data-action="rename"]:hover {
    background: rgba(34, 197, 94, 0.22);
    color: #16a34a;
}

.folder-action-btn[data-action="delete"] {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
}
.folder-action-btn[data-action="delete"]:hover {
    background: rgba(239, 68, 68, 0.22);
    color: #dc2626;
}

.uploading-row {
    opacity: 0.7;
    pointer-events: none;
}

.uploading-info {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
}

.upload-progress-track {
    height: 6px;
    max-width: 260px;
    background: rgba(148, 163, 184, 0.25);
    border-radius: 999px;
    overflow: hidden;
}

.upload-progress-fill {
    height: 100%;
    background: var(--green-dark);
    border-radius: 999px;
    transition: width 0.2s ease;
}

.laser-sd-upload-progress {
    position: relative;
    height: 20px;
    max-width: none;
    margin: 0 0 14px;
    background: rgba(34, 197, 94, 0.1);
    border: 1px solid rgba(34, 197, 94, 0.25);
}

.laser-sd-upload-progress .upload-progress-fill {
    background: #22c55e;
}

.upload-progress-label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--text);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

.badge {
    display: inline-flex;
    align-items: center;
    padding: 10px 14px;
    border-radius: 999px;
    background: var(--orange);
    color: #fff;
    font-size: 0.78rem;
    font-weight: 600;
}

.badge-alt {
    background: var(--green);
}

.models-table-wrapper {
    flex: 1;
    min-height: 0;
    overflow-x: auto;
    overflow-y: auto;
}

.models-table {
    width: 100%;
    border-collapse: collapse;
    min-width: 720px;
}

.models-table thead {
    background: rgba(148, 163, 184, 0.08);
}

.models-table th,
.models-table td {
    padding: 18px 20px;
    text-align: left;
    font-size: 0.95rem;
    color: var(--text);
}

.models-table th {
    color: var(--text-muted);
    font-weight: 600;
    letter-spacing: 0.02em;
    border-bottom: 1px solid rgba(148, 163, 184, 0.18);
}

.models-table tbody tr {
    border-bottom: 1px solid rgba(148, 163, 184, 0.12);
    transition: background 0.2s ease;
    cursor: pointer;
}

.models-table tbody tr:hover,
.models-table tbody tr.selected {
    background: rgba(34, 197, 94, 0.1);
}

.models-table td {
    color: var(--text);
}

.models-table td.model-name {
    display: flex;
    align-items: center;
    gap: 14px;
}

.models-table td.model-name svg {
    width: 44px;
    height: 44px;
    border-radius: 14px;
    padding: 10px;
    color: #fff;
    flex-shrink: 0;
}

.models-table td.model-name svg.green-bg {
    background: linear-gradient(135deg, var(--green-dark), var(--green));
}

.models-table td.model-name svg.orange-bg {
    background: linear-gradient(135deg, #fbbf24, var(--orange));
}

.cnc-files-thumb {
    width: 44px;
    height: 44px;
    border-radius: 14px;
    object-fit: cover;
    flex-shrink: 0;
    background: #081410;
}

.models-table tr.folder-row {
    cursor: pointer;
}

.models-table tr.folder-row .model-name {
    padding-left: 20px;
}

.models-table td.model-name svg.folder-icon {
    width: 22px;
    height: 22px;
    padding: 0;
    border-radius: 0;
    background: none;
    color: var(--orange);
}

.folder-file-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    margin-left: 8px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.15);
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 600;
}

.models-table td .tag-pill {
    display: inline-flex;
    align-items: center;
    padding: 6px 10px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.15);
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 600;
}

.models-preview-card {
    position: relative;
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: var(--radius-lg);
    padding: 24px;
    box-shadow: 0 24px 80px rgba(0,0,0,0.20);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    min-height: fit-content;
    overflow: hidden;
    color: var(--text);
}

.models-preview-card::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: url('../img/motif-circuit.svg');
    background-repeat: repeat;
    background-size: 220px 220px;
    filter: invert(1);
    opacity: 0.1;
}

.models-preview-card .preview-card-inner {
    position: relative;
    z-index: 1;
}

.preview-card-inner {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.gcode-preview-card .preview-card-inner {
    flex: 1;
    min-height: 0;
}

.preview-card-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
}

.preview-label {
    display: inline-flex;
    padding: 8px 12px;
    border-radius: 999px;
    background: rgba(34, 197, 94, 0.14);
    color: var(--green-dark);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-weight: 700;
}

.preview-card-header h2 {
    margin: 0;
    font-size: 1.5rem;
}

.model-preview-box {
    display: grid;
    gap: 18px;
}

.preview-image {
    min-height: 260px;
    border-radius: 28px;
    background: linear-gradient(180deg, var(--panel-bg) 0%, var(--card-bg) 100%);
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
}

.preview-image.gcode-mode {
    background: #081410;
}

.preview-image canvas {
    width: 100% !important;
    height: 100% !important;
    display: block;
    position: absolute;
    inset: 0;
}

.preview-image-placeholder {
    color: var(--text);
    font-size: 5rem;
    font-weight: 700;
    opacity: 0.18;
}

.models-preview-card .preview-label {
    display: inline-block;
    padding: 0;
    border-radius: 0;
    background: none;
    color: var(--accent);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 700;
}

.models-preview-card .preview-card-header h2 {
    color: var(--text);
    margin-top: 4px;
}

.preview-expand-btn {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(var(--accent-rgb), 0.35);
    background: rgba(var(--accent-rgb), 0.1);
    color: var(--accent);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease;
}

.preview-expand-btn:hover {
    background: rgba(var(--accent-rgb), 0.22);
}

.preview-title-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.preview-title-row h3 {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.preview-type-pill {
    flex-shrink: 0;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}

.preview-favorite-btn {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border: none;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: color 0.15s ease;
}

.preview-favorite-btn:hover {
    color: rgba(250, 204, 21, 0.6);
}

.preview-favorite-btn.active {
    color: #facc15;
}

.preview-favorite-btn.active svg {
    fill: #facc15;
}

.preview-meta-rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.preview-meta-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.preview-meta-row svg {
    color: var(--accent);
    flex-shrink: 0;
}

.preview-meta-row strong {
    color: var(--text);
    font-weight: 600;
}

.models-preview-card .preview-file-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex-wrap: nowrap;
}

.preview-file-actions-row {
    display: flex;
    gap: 8px;
}

.preview-file-actions-row .btn-file-action {
    flex: 1;
    justify-content: center;
}

.preview-file-actions-full {
    justify-content: center;
    width: 100%;
}

.preview-goto-printer-btn {
    border-color: rgba(96, 165, 250, 0.35);
    background: rgba(96, 165, 250, 0.1);
    color: #60a5fa;
}

.preview-goto-printer-btn:hover {
    background: rgba(96, 165, 250, 0.2);
    border-color: rgba(96, 165, 250, 0.5);
    color: #60a5fa;
}

.preview-tip-card {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px;
    border-radius: var(--radius-md);
    background: rgba(var(--accent-rgb), 0.08);
    border: 1px solid rgba(var(--accent-rgb), 0.25);
}

.preview-tip-icon {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: rgba(var(--accent-rgb), 0.16);
    color: var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.preview-tip-text strong {
    display: block;
    color: var(--accent);
    font-size: 0.85rem;
    margin-bottom: 4px;
}

.preview-tip-text p {
    margin: 0;
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--text-secondary);
}

.settings-grid {
    column-count: 2;
    column-gap: 20px;
    margin: 24px 0 0;
}

.settings-layout {
    display: flex;
    align-items: flex-start;
    gap: 20px;
    padding: 24px 32px 32px;
}

.settings-general-card {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
}

.devices-subtitle {
    color: #22c55e;
}

body.light .devices-subtitle {
    color: #57534e;
}

body.dark .devices-subtitle {
    color: #d1d5db;
}

.settings-right-col {
    flex: 1.6;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.settings-row-pair {
    display: flex;
    align-items: stretch;
    gap: 20px;
    order: 2;
}

.settings-row-pair > .settings-card {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}

.settings-right-col > .settings-card {
    margin-bottom: 0;
}

.settings-grid .settings-card {
    break-inside: avoid;
    margin-bottom: 20px;
}

.settings-card {
    background: var(--panel-bg);
    backdrop-filter: blur(8px);
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: var(--radius-lg);
    padding: 24px;
    box-shadow: 0 20px 60px rgba(0,0,0,0.08);
}

body.dark .settings-card,
body.green .settings-card {
    border-color: rgba(255, 255, 255, 0.08);
}

.usb-ports-settings-card {
    /* Antes navy fijo -- se me había pasado en la primera pasada. Con
       var(--text-muted) ya oscuro en Desert, texto oscuro sobre un fondo
       que seguía oscuro quedaba invisible. */
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    order: 1;
}

.settings-card h2 {
    margin: 0 0 10px;
    font-size: 1.05rem;
}

.settings-card p {
    margin: 0 0 16px;
    color: var(--text-muted);
    line-height: 1.5;
    font-size: 0.82rem;
}

/* ── System stats (impresora modal) ── */

.modal-content.printer-modal-content {
    max-width: 1294px;
    width: 99%;
    height: auto;
    max-height: 97vh;
    overflow: hidden;
    transition: background 0.2s ease;
}

.printer-error-banner {
    margin: 0 24px;
    padding: 16px 20px;
    border-radius: var(--radius-lg);
    background: rgba(127, 29, 29, 0.55);
    border: 1px solid rgba(248, 113, 113, 0.35);
    color: #fecaca;
}

.printer-error-banner-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    color: #f87171;
    margin-bottom: 10px;
}

.printer-error-banner-message {
    margin: 0 0 14px;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.78rem;
    line-height: 1.5;
    color: #fca5a5;
    white-space: pre-wrap;
    word-break: break-word;
}

.printer-error-banner-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.printer-error-banner .btn-file-action-danger {
    background: rgba(239, 68, 68, 0.16);
    border-color: rgba(239, 68, 68, 0.4);
    color: #fca5a5;
}

.printer-error-banner .btn-file-action-danger:hover {
    background: rgba(239, 68, 68, 0.28);
}

.modal-body.printer-modal-body {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    align-items: stretch;
    gap: 6px;
    padding: 6px;
    overflow-y: auto;
}

.printer-modal-column {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
    min-height: 0;
}

/* Lista de archivos + fila de acciones necesitan más ancho que una columna
   de 1/3 -- ocupa el ancho completo de la grilla en la fila donde caiga,
   sin importar en qué posición del customizer quede reordenada. */
.printer-modal-column[data-module="configfiles"] {
    grid-column: 1 / -1;
}

#printer-modal-toolhead,
#printer-modal-temperatures,
#printer-modal-queue,
#printer-modal-configfiles {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.printer-modal-column .temp-card {
    flex: 1;
    min-height: 0;
    max-height: none;
    display: flex;
    flex-direction: column;
}

.printer-modal-column .temp-card-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.printer-modal-topbar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 16px;
    padding: 20px 24px;
    background: rgba(2, 6, 16, 0.55);
    backdrop-filter: blur(6px);
}

.printer-modal-topbar-identity {
    display: flex;
    align-items: center;
    gap: 16px;
    min-width: 0;
}

@media (max-width: 860px) {
    .modal-body.printer-modal-body {
        grid-template-columns: 1fr;
    }

    .printer-modal-topbar {
        grid-template-columns: 1fr;
        align-items: start;
    }

}

.printer-modal-topbar img {
    width: 64px;
    height: 64px;
    object-fit: contain;
    flex-shrink: 0;
}

.printer-modal-topbar-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.printer-modal-topbar-info h2 {
    margin: 0;
    font-size: 1.15rem;
}

.printer-modal-topbar-mcu {
    flex-shrink: 0;
    justify-self: center;
    min-width: 0;
}

.printer-modal-topbar-mcu .system-stats-block-title {
    font-size: 0.7rem;
    margin-bottom: 6px;
}

.printer-modal-topbar-mcu .system-stats-body-mcu-only {
    max-width: none;
    margin: 0;
}

.printer-modal-topbar-mcu .system-stats-rows {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 14px;
}

.printer-modal-topbar-mcu .system-stats-row {
    flex-direction: column;
    gap: 2px;
    font-size: 0.68rem;
    text-align: center;
}

.printer-modal-topbar-mcu .system-stats-row strong {
    text-align: center;
    font-size: 0.78rem;
}

/* Botón de engranaje que abre "Personalizar Módulos", junto al cierre (X)
   del modal de impresora. Reusa .modal-close (tamaño/posición/hover) pero
   necesita mayor especificidad (dos clases) para ganarle a los estilos base
   de .modal-close definidos más abajo en la hoja. */
.modal-close.printer-modal-settings-btn {
    right: 76px;
    background: var(--panel-bg);
    color: var(--text);
    border: 1px solid var(--border);
}

/* ── "Personalizar Módulos": editor de módulos del modal de impresora ── */

.module-customizer-modal-content {
    width: 92%;
    max-width: 760px;
    height: auto;
    max-height: 90vh;
    padding: 32px 28px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    text-align: left;
}

.module-customizer-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    margin-bottom: 22px;
}

.module-customizer-header h2 {
    margin: 0;
    font-size: 1.25rem;
    color: var(--text);
}

.module-customizer-subtitle {
    margin: 0;
    font-size: 0.88rem;
    color: var(--text-muted);
}

.module-customizer-tabs {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    margin-bottom: 24px;
}

.module-customizer-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 92px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--panel-bg);
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.module-customizer-tab:hover {
    color: var(--text);
    border-color: rgba(var(--green-rgb), 0.4);
}

.module-customizer-tab.active {
    border-color: var(--green);
    color: var(--green-dark);
    background: rgba(var(--green-rgb), 0.1);
    box-shadow: 0 0 0 1px rgba(var(--green-rgb), 0.4), 0 0 16px rgba(var(--green-rgb), 0.35);
}

.module-customizer-groups {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    margin-bottom: 22px;
}

@media (max-width: 700px) {
    .module-customizer-groups {
        grid-template-columns: 1fr;
    }
}

.module-customizer-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    background: var(--panel-bg);
}

.module-customizer-group-header h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
}

.module-customizer-group-available .module-customizer-group-header h3 {
    color: var(--green-dark);
}

.module-customizer-group-extra .module-customizer-group-header h3 {
    color: var(--purple);
}

.module-customizer-group-header p {
    margin: 2px 0 0;
    font-size: 0.76rem;
    color: var(--text-muted);
}

.module-customizer-list {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px;
}

.module-customizer-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--card-bg);
    user-select: none;
}

.module-customizer-row-dragging {
    border-color: var(--green);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.25);
    opacity: 0.96;
}

.module-customizer-row-locked {
    opacity: 0.85;
}

.module-customizer-row-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    color: var(--text-muted);
    cursor: grab;
    touch-action: none;
}

.module-customizer-row-handle:active {
    cursor: grabbing;
}

.module-customizer-row-handle-disabled {
    color: var(--border);
    cursor: not-allowed;
}

.module-customizer-row-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    color: var(--text-secondary);
}

.module-customizer-row-label {
    flex: 1;
    min-width: 0;
    font-size: 0.86rem;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.module-customizer-row-toggle {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.module-customizer-checkbox {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    cursor: pointer;
    accent-color: var(--green);
}

.module-customizer-checkbox-green {
    accent-color: var(--green);
}

.module-customizer-checkbox-purple {
    accent-color: var(--purple);
}

.module-customizer-row-lock {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--text-muted);
}

.module-customizer-footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    text-align: center;
}

.module-customizer-reset-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 22px;
    border-radius: 999px;
    border: 1.5px solid var(--green);
    background: transparent;
    color: var(--green-dark);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.module-customizer-reset-btn:hover {
    background: rgba(var(--green-rgb), 0.12);
}

.module-customizer-reset-hint {
    margin: 0;
    font-size: 0.74rem;
    color: var(--text-muted);
}

/* ── Página de Configuración unificada (Configuración + Ayuda fusionadas):
   grupos de tarjetas creados por el usuario, armados en tiempo real por
   applySettingsModulesLayout() en app.js. Reemplaza el layout fijo de 2
   columnas que tenía .settings-layout (retirado) — acá el número de grupos
   y qué tarjeta va en cada uno lo decide el usuario desde "Personalizar". ── */

.settings-modules-groups {
    display: flex;
    flex-direction: column;
    gap: 28px;
    padding: 24px 32px 32px;
}

.settings-module-group-title-row {
    margin-bottom: 14px;
}

.settings-module-group-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--text);
}

.settings-module-group-body {
    column-count: 2;
    column-gap: 20px;
}

.settings-module-group-body > .settings-card {
    break-inside: avoid;
    margin-bottom: 20px;
}

.settings-modules-pool {
    display: none;
}

.settings-module-hidden-by-user {
    display: none !important;
}

@media (max-width: 900px) {
    .settings-module-group-body {
        column-count: 1;
    }
}

/* ── Ayuda: layout en grid (como .plugins-grid, línea ~4549) en vez del
   masonry por columnas de arriba. Se scopea con el id real del contenedor
   (#help-modules-groups) para no tocar #settings-modules-groups ni ninguna
   otra página que reuse .settings-module-group-body/.settings-card — solo
   afecta a Ayuda. auto-fill/minmax ya es responsive por sí solo (baja a 1
   columna en pantallas angostas), no hace falta un @media extra. ── */
#help-modules-groups .settings-module-group-body {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
    gap: 14px;
}

#help-modules-groups .settings-module-group-body > .help-card {
    margin-bottom: 0;
}

/* ── Editor "Personalizar Página de Configuración": grupos dinámicos ── */

.settings-module-customizer-modal-content {
    max-width: 620px;
}

.settings-module-customizer-groups {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-bottom: 16px;
}

.settings-module-customizer-group-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}

.settings-module-customizer-group-name-input {
    flex: 1;
    min-width: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 4px 8px;
    font-size: 0.95rem;
    font-weight: 700;
    font-family: inherit;
    color: var(--text);
}

.settings-module-customizer-group-name-input:hover {
    border-color: var(--border);
}

.settings-module-customizer-group-name-input:focus {
    border-color: var(--green);
    background: var(--card-bg);
    outline: none;
}

.settings-module-customizer-group-delete-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.settings-module-customizer-group-delete-btn:hover {
    color: #ef4444;
    border-color: rgba(239, 68, 68, 0.4);
    background: rgba(239, 68, 68, 0.08);
}

.settings-module-customizer-list {
    min-height: 46px;
}

.settings-module-customizer-list-hint {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    border: 1.5px dashed var(--border);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    font-size: 0.78rem;
    text-align: center;
    padding: 8px;
    pointer-events: none;
}

.settings-module-customizer-add-group-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 12px;
    border-radius: var(--radius-md);
    border: 1.5px dashed var(--border);
    background: transparent;
    color: var(--text-secondary);
    font-size: 0.84rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
    margin-bottom: 22px;
}

.settings-module-customizer-add-group-btn:hover {
    border-color: var(--green);
    color: var(--green-dark);
    background: rgba(var(--green-rgb), 0.08);
}

.system-stats-body {
    display: grid;
    grid-template-columns: 1fr 1fr auto;
    gap: 28px;
    align-items: start;
}

.system-stats-block-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 12px;
}

.system-stats-block-title svg {
    color: var(--green-dark);
    flex-shrink: 0;
}

.system-stats-block-title small {
    font-weight: 500;
    color: var(--text-muted);
}

.system-stats-rows {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.system-stats-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 0.85rem;
}

.system-stats-row span {
    color: var(--text-muted);
}

.system-stats-row strong {
    color: var(--text);
    text-align: right;
}

.system-stats-body-mcu-only {
    grid-template-columns: 1fr;
    max-width: 280px;
    margin: 0 auto;
}

.system-stats-body-mcu-only .system-stats-block-title {
    justify-content: center;
}

@media (max-width: 900px) {
    .system-stats-body {
        grid-template-columns: 1fr;
    }
}

.temp-card {
    border-radius: 16px;
    overflow: hidden;
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.temp-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.06);
    color: var(--text);
    font-weight: 700;
}

.temp-card-header-left {
    display: flex;
    align-items: center;
    gap: 8px;
}

.temp-card-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.temp-preset-pill,
.temp-cool-pill {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    padding: 6px 10px;
    border: none;
    border-radius: 999px;
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.temp-preset-pill {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.temp-cool-pill {
    background: rgba(96, 165, 250, 0.16);
    color: #60a5fa;
}

.temp-preset-pill:hover,
.temp-cool-pill:hover {
    opacity: 0.8;
}

.temp-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.1);
    color: var(--text);
    cursor: pointer;
    transition: transform 0.15s ease, background 0.15s ease;
}

.temp-icon-btn:hover {
    background: rgba(255, 255, 255, 0.18);
}

.temp-icon-btn.collapsed svg {
    transform: rotate(-90deg);
}

.temp-card-body {
    padding: 12px 14px 14px;
    display: grid;
    gap: 12px;
}

.config-actions-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.config-file-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 80px;
    max-height: 280px;
    overflow-y: auto;
}

.config-file-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--panel-bg);
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.config-file-row:hover {
    background: rgba(var(--accent-rgb), 0.1);
    border-color: var(--accent);
}

.config-file-row-name {
    flex: 1;
    min-width: 0;
    font-size: 0.85rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.config-file-row-size {
    flex-shrink: 0;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.temp-table {
    display: grid;
    gap: 8px;
    background: rgba(255, 255, 255, 0.04);
    border-radius: 12px;
    padding: 10px 12px;
}

.temp-table-head {
    display: grid;
    grid-template-columns: 1.6fr 0.8fr 0.8fr 1fr;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
    padding-bottom: 6px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.temp-table-row {
    display: grid;
    grid-template-columns: 1.6fr 0.8fr 0.8fr 1fr;
    align-items: center;
    font-size: 0.85rem;
    padding: 4px 0;
}

.temp-row-name {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text);
    font-weight: 600;
}

.temp-row-icon {
    display: inline-flex;
}

.temp-row-state,
.temp-row-current {
    color: var(--text-muted);
}

.temp-state-arrow {
    font-size: 0.7rem;
}

.temp-state-arrow-up {
    color: #f59e0b;
}

.temp-state-arrow-down {
    color: #60a5fa;
}

.temp-target-input-wrap {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    padding: 4px 8px;
    width: fit-content;
}

.temp-target-input {
    width: 44px;
    border: none;
    background: transparent;
    color: var(--text);
    font-size: 0.85rem;
    text-align: right;
}

.temp-target-input:focus {
    outline: none;
}

.temp-target-unit {
    color: var(--text-muted);
    font-size: 0.78rem;
}

.temp-presets-fields {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 4px 0 20px;
}

.temp-presets-field {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.temp-presets-field label {
    font-size: 0.88rem;
    color: var(--text);
    font-weight: 600;
}

/* ── Mini-tema de la ficha de Temperaturas: ámbar al precalentar, frío al enfriar ── */

.temp-card-warm {
    background: linear-gradient(160deg, rgba(194, 101, 12, 0.55) 0%, rgba(154, 68, 12, 0.6) 55%, rgba(87, 38, 8, 0.65) 100%);
    transition: background 0.5s ease;
}

.temp-card-cool {
    background: linear-gradient(160deg, rgba(96, 165, 250, 0.22) 0%, rgba(59, 110, 200, 0.22) 55%, rgba(15, 23, 42, 0.5) 100%);
    transition: background 0.5s ease;
}

.temp-card-warm .temp-card-header,
.temp-card-cool .temp-card-header {
    background: rgba(255, 255, 255, 0.08);
}

.temp-card-warm .temp-card-header-left,
.temp-card-warm .temp-row-name,
.temp-card-warm .temp-row-state,
.temp-card-warm .temp-row-current,
.temp-card-warm .temp-table-head,
.temp-card-warm .temp-target-unit,
.temp-card-warm .toolhead-position-mode {
    color: #ffedd5;
}

.temp-card-cool .temp-card-header-left,
.temp-card-cool .temp-row-name,
.temp-card-cool .temp-row-state,
.temp-card-cool .temp-row-current,
.temp-card-cool .temp-table-head,
.temp-card-cool .temp-target-unit,
.temp-card-cool .toolhead-position-mode {
    color: #dbeafe;
}

.temp-card-warm .temp-table,
.temp-card-warm .temp-target-input-wrap,
.temp-card-warm .temp-chart-wrap,
.temp-card-warm .temp-icon-btn {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(251, 146, 60, 0.35);
}

.temp-card-cool .temp-table,
.temp-card-cool .temp-target-input-wrap,
.temp-card-cool .temp-chart-wrap,
.temp-card-cool .temp-icon-btn {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(96, 165, 250, 0.35);
}

.temp-card-warm .temp-target-input {
    color: #ffedd5;
}

.temp-card-cool .temp-target-input {
    color: #dbeafe;
}

.temp-card-warm .temp-preset-pill {
    background: rgba(251, 146, 60, 0.35);
    color: #fff7ed;
}

.temp-card-warm .temp-cool-pill {
    background: rgba(255, 255, 255, 0.14);
    color: #ffedd5;
}

.temp-card-cool .temp-cool-pill {
    background: rgba(96, 165, 250, 0.35);
    color: #eff6ff;
}

.temp-card-cool .temp-preset-pill {
    background: rgba(255, 255, 255, 0.14);
    color: #dbeafe;
}

.temp-chart-wrap {
    height: 160px;
    background: rgba(255, 255, 255, 0.04);
    border-radius: 12px;
    padding: 8px;
}

.temp-chart-wrap canvas {
    width: 100%;
    height: 100%;
    display: block;
}

/* ── Toolhead card (impresora) — diseño propio, fiel a la referencia ── */

.toolhead-card {
    position: relative;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
    overflow-x: hidden;
}

.laser-column > .toolhead-card {
    flex: 1;
    min-height: 0;
    max-height: none;
}

.laser-card.toolhead-card {
    /* Antes un navy fijo (rgba(15,23,42,...)), que solo combinaba bien con
       el tema oscuro original -- con temas claros/desert se veía un
       recuadro azul oscuro pegado encima del fondo. color-mix con
       --card-bg sigue siendo un vidrio translúcido pero tomando el color
       de tarjeta del tema activo. */
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.temp-card.toolhead-card {
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    border-color: rgba(34, 197, 94, 0.35);
}

.toolhead-card .temp-card-header {
    background: transparent;
    position: relative;
    overflow: hidden;
}


.toolhead-card .temp-card-header-left,
.toolhead-card .temp-card-header-actions {
    position: relative;
    z-index: 1;
    color: #fff;
}

.toolhead-card .temp-icon-btn {
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
}

.toolhead-card .temp-icon-btn:hover {
    background: rgba(255, 255, 255, 0.26);
}

.toolhead-card .temp-card-body {
    color: #fff;
}

/* Compatibilidad con el patrón de encabezado .card-header-std (fichas del láser) */
.toolhead-card .card-header-std {
    position: relative;
    overflow: hidden;
    margin: -20px -20px 16px;
    padding: 16px 20px;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}


.toolhead-card .card-header-std-icon,
.toolhead-card .card-header-std-title {
    position: relative;
    z-index: 1;
    color: #fff;
}

.toolhead-card .card-collapse-toggle {
    position: relative;
    z-index: 1;
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
}

.toolhead-card .card-collapse-toggle:hover {
    background: rgba(255, 255, 255, 0.26);
}

.toolhead-card,
.toolhead-card .laser-jog-steps-label,
.toolhead-card .laser-fire-label,
.toolhead-card .laser-metrics span {
    color: #fff;
}

.toolhead-card .laser-jog-layout {
    background: rgba(15, 15, 35, 0.28);
    border-color: rgba(255, 255, 255, 0.12);
}

.toolhead-card .laser-jog-side {
    border-left-color: rgba(255, 255, 255, 0.15);
}

.toolhead-card .laser-jog-btn {
    background: rgba(15, 15, 35, 0.32);
    border-color: rgba(34, 197, 94, 0.2);
    color: #4ade80;
}

.toolhead-card .laser-jog-btn:hover {
    background: rgba(34, 197, 94, 0.22);
    border-color: rgba(34, 197, 94, 0.55);
    color: #22c55e;
}

.toolhead-card .laser-jog-slot-home {
    background: rgba(34, 197, 94, 0.28);
    border-color: #22c55e;
    color: #22c55e;
}

.toolhead-card .laser-step-btn {
    background: rgba(15, 15, 35, 0.32);
    border-color: transparent;
    color: rgba(255, 255, 255, 0.75);
}

.toolhead-card .laser-step-btn.active {
    background: rgba(255, 255, 255, 0.18);
    border-color: transparent;
    color: #fff;
}

.toolhead-card .laser-jog-actions .btn-file-action {
    background: rgba(15, 15, 35, 0.32);
    border-color: rgba(255, 255, 255, 0.12);
    color: #fff;
}

.toolhead-card .laser-jog-actions .btn-file-action:hover {
    background: rgba(34, 197, 94, 0.22);
    border-color: rgba(34, 197, 94, 0.4);
}

.toolhead-position-mode {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.85);
}

.toolhead-position-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.toolhead-position-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.toolhead-position-field-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 0 2px;
}

.toolhead-position-letter {
    font-size: 0.72rem;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.75);
}

.toolhead-position-target {
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.6);
}

.toolhead-position-box {
    padding: 10px 10px;
    background: rgba(15, 15, 35, 0.4);
    border: 1px solid rgba(34, 197, 94, 0.4);
    border-radius: var(--radius-md);
    text-align: center;
}

.toolhead-position-value {
    font-size: 1.3rem;
    font-weight: 700;
    color: #4ade80;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.toolhead-jog-row {
    display: flex;
    align-items: center;
    gap: 7px;
}

.toolhead-jog-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1px solid rgba(34, 197, 94, 0.4);
    border-radius: 8px;
    background: rgba(15, 15, 35, 0.4);
    color: #4ade80;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.toolhead-jog-btn:hover {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.7);
    color: #fff;
}

.toolhead-jog-col {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.toolhead-jog-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
    min-width: 0;
}

.toolhead-home-all-btn,
.toolhead-motors-off-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 32px;
    border: none;
    border-radius: 8px;
    color: #fff;
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background 0.15s ease;
}

.toolhead-motors-off-btn {
    width: 44px;
    flex-shrink: 0;
    background: rgba(217, 114, 15, 0.22);
    border: 1px solid rgba(217, 114, 15, 0.6);
    color: #fb923c;
}

.toolhead-motors-off-btn:hover {
    background: rgba(217, 114, 15, 0.34);
}

.toolhead-home-all-btn {
    background: #16a34a;
}

.toolhead-home-all-btn:hover {
    background: #15803d;
}

.toolhead-axis-home-row {
    display: flex;
    gap: 7px;
}

.toolhead-axis-home-row button {
    flex: 1;
    height: 34px;
    font-size: 0.88rem;
    border: 1px solid rgba(34, 197, 94, 0.4);
    border-radius: 8px;
    background: rgba(15, 15, 35, 0.4);
    color: #4ade80;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.toolhead-axis-home-row button:hover {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.7);
    color: #fff;
}

.toolhead-steps-row {
    display: flex;
    background: rgba(15, 15, 35, 0.32);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.toolhead-step-btn {
    flex: 1;
    padding: 7px 0;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease;
}

.toolhead-step-btn.active {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
}

.toolhead-zoffset-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.85);
}

.toolhead-zoffset-buttons {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.toolhead-zoffset-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    border: none;
    border-radius: 8px;
    background: rgba(15, 15, 35, 0.32);
    color: #fff;
    font-size: 0.76rem;
    cursor: pointer;
    transition: background 0.15s ease;
}

.toolhead-zoffset-btn:hover {
    background: rgba(15, 15, 35, 0.5);
}

.toolhead-speed-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.85);
}

.toolhead-speed-badge {
    display: flex;
    align-items: center;
    gap: 4px;
    background: rgba(15, 15, 35, 0.32);
    border-radius: 8px;
    padding: 4px 10px;
    font-weight: 700;
    color: #fff;
}

.toolhead-speed-slider-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.toolhead-speed-slider-row button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: rgba(15, 15, 35, 0.32);
    color: #fff;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
}

.toolhead-speed-slider-row input[type="range"] {
    flex: 1;
    accent-color: #22c55e;
}

.toolhead-speed-ticks {
    display: flex;
    justify-content: space-between;
    padding: 0 34px;
    margin-top: 2px;
    font-size: 0.66rem;
    color: rgba(255, 255, 255, 0.4);
}

@media (max-width: 520px) {
    .temp-table-head,
    .temp-table-row {
        grid-template-columns: 1.4fr 0.6fr 0.7fr 1fr;
        font-size: 0.78rem;
    }
}

.console-card {
    margin: 0 32px 32px;
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    border: 1px solid rgba(255, 255, 255, 0.08);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.console-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.console-font-size-toggle {
    display: flex;
    gap: 4px;
}

.console-font-size-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 6px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.05);
    color: var(--text-muted);
    font-size: 0.7rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.console-font-size-btn:hover {
    background: rgba(34, 197, 94, 0.14);
}

.console-font-size-btn.active {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.4);
    color: #22c55e;
}

.console-log.font-sm {
    font-size: 0.7rem;
}

.console-log.font-lg {
    font-size: 0.98rem;
}

.console-toolbar .settings-select {
    flex: 1;
}

.console-log {
    height: 420px;
    overflow-y: auto;
    padding: 14px 16px;
    background: color-mix(in srgb, var(--card-bg) 40%, transparent);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.82rem;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.console-line {
    display: flex;
    gap: 10px;
    color: var(--text);
}

.console-line-time {
    color: var(--text-muted);
    flex-shrink: 0;
}

.console-line-command {
    color: #22c55e;
}

.console-line-message {
    white-space: pre-wrap;
    word-break: break-word;
}

.console-line-level-warning .console-line-message {
    color: var(--orange);
}

.console-line-level-error .console-line-message {
    color: #ef4444;
}

.console-input-row {
    display: flex;
    gap: 10px;
    padding: 14px 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.console-input-row input {
    flex: 1;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--bg);
    color: var(--text);
    font-family: inherit;
}

.macros-toolbar {
    margin: 0 32px 16px;
    max-width: 320px;
}

.macros-grid {
    margin: 0;
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    align-content: start;
    gap: 10px;
    min-width: 0;
}

.macro-btn {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 64px;
    padding: 12px 8px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    color: var(--text);
    font-size: 0.76rem;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.macro-btn svg {
    color: #22c55e;
}

.macro-btn-face {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.macro-btn-description {
    display: none;
    font-size: 0.72rem;
    font-weight: 500;
    line-height: 1.4;
    color: var(--text);
}

.macro-btn:hover {
    background: rgba(245, 158, 11, 0.18);
    border-color: rgba(245, 158, 11, 0.4);
    transform: translateY(-2px);
}

.macro-btn:hover .macro-btn-face {
    display: none;
}

.macro-btn:hover .macro-btn-description {
    display: block;
}

/* En touch no existe :hover real (algunos navegadores lo "pegan" tras el
   primer tap y otros nunca lo disparan) — sin esto la descripción del macro
   quedaba inalcanzable en mobile, mostrando solo el ícono sin explicación.
   Se muestra siempre la descripción en vez del ícono en dispositivos sin
   hover, que es la información útil cuando no se puede pasar el mouse. */
@media (hover: none) {
    .macro-btn-face {
        display: none;
    }

    .macro-btn-description {
        display: block;
    }
}

.macro-btn.running {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.4);
}

.macro-btn:disabled {
    opacity: 0.6;
    cursor: default;
    transform: none;
}

/* ── Recomendación de pantalla completa ── */
.fullscreen-recommendation {
    position: fixed;
    z-index: 12000;
    top: 10px;
    left: 50%;
    display: flex;
    width: min(690px, calc(100vw - 28px));
    align-items: center;
    gap: 11px;
    padding: 10px 11px 10px 13px;
    border: 1px solid rgba(168,85,247,.55);
    border-radius: 13px;
    background: rgba(12,18,31,.96);
    box-shadow: 0 15px 45px rgba(0,0,0,.42), 0 0 20px rgba(168,85,247,.12);
    transform: translateX(-50%);
    backdrop-filter: blur(12px);
}
.fullscreen-recommendation-icon { display: grid; width: 34px; height: 34px; flex: 0 0 34px; place-items: center; border-radius: 9px; background: rgba(168,85,247,.18); color: #c084fc; }
.fullscreen-recommendation > span:nth-child(2) { display: flex; min-width: 0; flex: 1; flex-direction: column; }
.fullscreen-recommendation strong { color: #f8fafc; font-size: .78rem; }
.fullscreen-recommendation small { margin-top: 2px; color: var(--text-muted); font-size: .66rem; }
.fullscreen-recommendation-action { padding: 8px 11px; border: 1px solid rgba(168,85,247,.55); border-radius: 8px; background: rgba(126,34,206,.25); color: #e9d5ff; font-weight: 700; white-space: nowrap; cursor: pointer; }
.fullscreen-recommendation-action:hover { background: rgba(126,34,206,.45); }
.fullscreen-recommendation-close { width: 28px; height: 28px; border: 0; background: transparent; color: var(--text-muted); font-size: 1.2rem; cursor: pointer; }
@media (max-width: 620px) { .fullscreen-recommendation small { display: none; } .fullscreen-recommendation-action { font-size: .66rem; } }

/* ── Galería de plugins ── */
.plugins-main {
    min-height: 100%;
    padding: 28px 32px 40px;
}

.plugins-page-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 22px;
}

.plugins-page-eyebrow {
    color: #a855f7;
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.12em;
}

.plugins-page-header h1 { margin: 5px 0 6px; color: var(--text); font-size: 1.8rem; }
.plugins-page-header p { margin: 0; color: var(--text-muted); }

.plugins-installed-counter {
    display: flex;
    min-width: 112px;
    align-items: baseline;
    justify-content: center;
    gap: 7px;
    padding: 12px 16px;
    border: 1px solid rgba(168, 85, 247, 0.3);
    border-radius: 14px;
    background: rgba(88, 28, 135, 0.18);
}

.plugins-installed-counter strong { color: #d8b4fe; font-size: 1.35rem; }
.plugins-installed-counter span { color: var(--text-muted); font-size: 0.76rem; }

.plugins-toolbar {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 20px;
}

.plugins-search {
    display: flex;
    width: min(390px, 100%);
    align-items: center;
    gap: 9px;
    padding: 0 13px;
    border: 1px solid rgba(148, 163, 184, 0.22);
    border-radius: 11px;
    background: color-mix(in srgb, var(--card-bg) 68%, transparent);
    color: var(--text-muted);
}

.plugins-search:focus-within { border-color: rgba(168, 85, 247, 0.7); box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.1); }
.plugins-search input { width: 100%; padding: 11px 0; border: 0; outline: 0; background: transparent; color: var(--text); }

.plugins-filter-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.plugins-filter-chip {
    padding: 8px 12px;
    border: 1px solid rgba(148, 163, 184, 0.2);
    border-radius: 999px;
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    color: var(--text-muted);
    cursor: pointer;
}
.plugins-filter-chip:hover, .plugins-filter-chip.active { border-color: rgba(168, 85, 247, 0.55); background: rgba(126, 34, 206, 0.2); color: #e9d5ff; }

.plugins-featured {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(250px, 0.7fr);
    gap: 20px;
    overflow: hidden;
    margin-bottom: 22px;
    padding: 24px;
    border: 1px solid rgba(168, 85, 247, 0.38);
    border-radius: 18px;
    /* Antes un navy/morado sólido fijo -- no seguía el tema (se quedaba
       oscuro incluso en Desert). El brillo morado decorativo usa --purple
       (varía por tema); la superficie base ahora sale de --card-bg. */
    background: radial-gradient(circle at 86% 20%, color-mix(in srgb, var(--purple) 20%, transparent), transparent 34%), color-mix(in srgb, var(--card-bg) 90%, transparent);
}

/* El plugin trae su propia imagen: va de fondo de toda la tarjeta, con un
   degradado encima (mismo --card-bg de siempre) para que el texto de la
   izquierda siga siendo legible sobre la foto. */
.plugins-featured.has-banner-image {
    background-image: linear-gradient(100deg, var(--card-bg) 0%, color-mix(in srgb, var(--card-bg) 88%, transparent) 32%, color-mix(in srgb, var(--card-bg) 35%, transparent) 60%, transparent 88%), var(--plugins-featured-image);
    background-repeat: no-repeat;
    background-position: center right;
    background-size: cover;
}

.plugins-featured-copy { position: relative; z-index: 1; }
.plugins-featured-label { display: inline-flex; margin-bottom: 12px; padding: 5px 9px; border-radius: 999px; background: color-mix(in srgb, var(--purple) 20%, transparent); color: var(--purple); font-size: 0.68rem; font-weight: 800; }
.plugins-featured h2 { margin: 0 0 8px; color: var(--text); font-size: 1.45rem; }
.plugins-featured p { max-width: 650px; margin: 0 0 16px; color: var(--text-muted); line-height: 1.55; }
.plugins-featured-visual { display: grid; place-items: center; }
.plugins-featured-icon { display: grid; width: 118px; height: 118px; place-items: center; border: 1px solid color-mix(in srgb, var(--purple) 35%, transparent); border-radius: 30px; background: color-mix(in srgb, var(--purple) 18%, transparent); color: var(--purple); transform: rotate(-5deg); }

.plugins-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 14px; }
.plugin-card {
    display: flex;
    min-width: 0;
    flex-direction: column;
    padding: 17px;
    border: 1px solid rgba(148, 163, 184, 0.17);
    border-radius: 15px;
    background: color-mix(in srgb, var(--card-bg) 72%, transparent);
    transition: transform 160ms ease, border-color 160ms ease, background 160ms ease;
    cursor: pointer;
}
.plugin-card:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--plugin-accent) 55%, transparent); background: color-mix(in srgb, var(--card-bg) 88%, transparent); }
.plugin-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.plugin-card-icon { display: grid; width: 46px; height: 46px; place-items: center; border: 1px solid color-mix(in srgb, var(--plugin-accent) 45%, transparent); border-radius: 12px; background: color-mix(in srgb, var(--plugin-accent) 15%, transparent); color: var(--plugin-accent); }
.plugin-card-status { padding: 4px 7px; border-radius: 999px; background: rgba(148, 163, 184, 0.12); color: var(--text-muted); font-size: 0.65rem; font-weight: 700; }
.plugin-card-status.is-installed { background: rgba(34, 197, 94, 0.14); color: var(--green); }
.plugin-card h3 { margin: 14px 0 3px; color: var(--text); font-size: 1rem; }
.plugin-card-publisher { color: var(--text-muted); font-size: 0.68rem; }
.plugin-card-description { flex: 1; margin: 11px 0 13px; color: var(--text-muted); font-size: 0.78rem; line-height: 1.5; }
.plugin-card-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 14px; }
.plugin-card-tag { padding: 4px 7px; border-radius: 6px; background: rgba(148, 163, 184, 0.09); color: var(--text-muted); font-size: 0.64rem; }
.plugin-card-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; padding-top: 12px; border-top: 1px solid rgba(148, 163, 184, 0.12); }
.plugin-card-meta { min-width: 0; color: var(--text-muted); font-size: 0.66rem; }
.plugin-card-actions { display: flex; min-width: 0; max-width: 100%; align-items: center; justify-content: flex-end; gap: 8px; }
.plugin-card-actions.has-update { width: 100%; }
.plugin-card-actions.has-update > button { flex: 1 1 0; min-width: 0; }
.plugin-install-btn { min-width: 96px; padding: 8px 12px; border: 1px solid var(--plugin-accent); border-radius: 9px; background: color-mix(in srgb, var(--plugin-accent) 18%, transparent); color: var(--plugin-accent); font-weight: 750; cursor: pointer; }
.plugin-install-btn:hover:not(:disabled) { background: var(--plugin-accent); color: #fff; }
.plugin-install-btn.is-installed { border-color: rgba(239, 68, 68, 0.45); background: rgba(127, 29, 29, 0.15); color: #fca5a5; }
.plugin-install-btn:disabled { border-color: rgba(148, 163, 184, 0.16); background: rgba(148, 163, 184, 0.07); color: var(--text-muted); cursor: not-allowed; }
.plugin-update-btn { min-width: 88px; padding: 8px 12px; border: 1px solid var(--orange); border-radius: 9px; background: color-mix(in srgb, var(--orange) 18%, transparent); color: var(--orange); font-weight: 750; cursor: pointer; }
.plugin-update-btn:hover:not(:disabled) { background: var(--orange); color: #fff; }
.plugin-update-btn:disabled { border-color: rgba(148, 163, 184, 0.16); background: rgba(148, 163, 184, 0.07); color: var(--text-muted); cursor: not-allowed; }
.plugins-loading, .plugins-empty { grid-column: 1 / -1; padding: 60px 20px; text-align: center; color: var(--text-muted); }
.plugins-empty { display: flex; flex-direction: column; gap: 5px; }
.plugins-empty strong { color: var(--text); }

@media (max-width: 760px) {
    .plugins-main { padding: 20px 16px 32px; }
    .plugins-page-header, .plugins-toolbar { align-items: stretch; flex-direction: column; }
    .plugins-installed-counter { align-self: flex-start; }
    .plugins-featured { grid-template-columns: 1fr; }
    .plugins-featured-visual { display: none; }
}

/* ── Editor G-Code ── */
.gcode-editor-main {
    display: flex;
    flex-direction: column;
    gap: 18px;
    height: 100%;
    padding: 24px 32px;
}

.gcode-editor-card {
    display: flex;
    flex: 1;
    min-height: 0;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid rgba(168, 85, 247, 0.35);
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--card-bg) 68%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.gcode-editor-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.gcode-editor-file-meta {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 3px;
}

.gcode-editor-file-meta strong {
    overflow: hidden;
    color: var(--text);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gcode-editor-file-meta span {
    color: var(--text-muted);
    font-size: 0.72rem;
}

.gcode-editor-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.gcode-editor-workspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(300px, 340px);
    flex: 1;
    min-height: 0;
    gap: 12px;
    padding: 12px;
    background: rgba(2, 6, 23, 0.52);
}

#gcode-editor-textarea {
    width: 100%;
    min-height: 420px;
    resize: none;
    padding: 18px;
    border: 0;
    outline: 0;
    background: rgba(2, 6, 23, 0.72);
    color: #d1fae5;
    caret-color: #a855f7;
    font: 500 0.86rem/1.55 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    tab-size: 4;
}

.gcode-analysis-card {
    min-width: 0;
    overflow: auto;
    padding: 18px;
    border: 1px solid rgba(34, 197, 94, 0.28);
    border-radius: 14px;
    background: linear-gradient(155deg, rgba(6, 78, 59, 0.28), rgba(15, 23, 42, 0.94) 52%);
}

.gcode-analysis-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.gcode-analysis-eyebrow {
    color: #34d399;
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.08em;
}

.gcode-analysis-header h2 {
    margin: 3px 0 0;
    color: var(--text);
    font-size: 1rem;
}

.gcode-type-badge {
    flex: 0 0 auto;
    padding: 5px 8px;
    border: 1px solid rgba(148, 163, 184, 0.28);
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.12);
    color: #cbd5e1;
    font-size: 0.68rem;
    font-weight: 800;
}

.gcode-type-badge.is-laser { border-color: rgba(168, 85, 247, 0.55); background: rgba(126, 34, 206, 0.22); color: #d8b4fe; }
.gcode-type-badge.is-print3d { border-color: rgba(59, 130, 246, 0.55); background: rgba(37, 99, 235, 0.2); color: #bfdbfe; }
.gcode-type-badge.is-cnc { border-color: rgba(245, 158, 11, 0.55); background: rgba(180, 83, 9, 0.2); color: #fde68a; }

.gcode-analysis-summary {
    margin: 0 0 14px;
    color: var(--text-muted);
    font-size: 0.78rem;
    line-height: 1.45;
}

.gcode-analysis-details {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.gcode-analysis-item {
    min-width: 0;
    padding: 9px 10px;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 9px;
    background: color-mix(in srgb, var(--card-bg) 62%, transparent);
}

.gcode-analysis-item.is-wide { grid-column: 1 / -1; }
.gcode-analysis-item span { display: block; margin-bottom: 3px; color: var(--text-muted); font-size: 0.66rem; }
.gcode-analysis-item strong { display: block; overflow: hidden; color: #e2e8f0; font-size: 0.76rem; text-overflow: ellipsis; }

.gcode-analysis-signals {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}

.gcode-analysis-signal {
    padding: 4px 7px;
    border-radius: 999px;
    background: rgba(34, 197, 94, 0.1);
    color: #86efac;
    font-size: 0.65rem;
}

#gcode-editor-textarea::placeholder {
    color: var(--text-muted);
}

@media (max-width: 700px) {
    .gcode-editor-main {
        padding: 16px;
    }

    .gcode-editor-toolbar {
        align-items: stretch;
        flex-direction: column;
    }
}

@media (max-width: 1050px) {
    .gcode-editor-workspace { grid-template-columns: 1fr; overflow: auto; }
    #gcode-editor-textarea { min-height: 480px; }
    .gcode-analysis-card { overflow: visible; }
}

.laser-card {
    margin: 0 32px 20px;
    padding: 20px;
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-left: 4px solid var(--green-dark);
}

/* ── Ficha de conexión + ficha de movimiento: acento naranja cuando el
   dispositivo seleccionado es un CNC (en vez del verde de láser) ── */

#laser-connection-card.theme-cnc,
.toolhead-card.theme-cnc {
    border-left-color: var(--orange);
}

#laser-connection-card.theme-cnc .laser-status-dot.online {
    background: var(--orange);
}

.toolhead-card.theme-cnc .laser-console-prompt,
.toolhead-card.theme-cnc #laser-console-active-name {
    color: var(--orange);
}

.toolhead-card.theme-cnc #laser-console-log .console-line-command {
    color: var(--orange);
}

.toolhead-card.theme-cnc .laser-metrics div {
    background: rgba(245, 158, 11, 0.12);
}

.laser-columns {
    display: flex;
    gap: 20px;
    align-items: flex-start;
    margin: 24px 32px 20px 16px;
    height: calc(100% - 44px);
}

/* Columna de Conexión/Cola/Consola a la derecha, Movimiento del cabezal a
   la izquierda — invertido a pedido, sin reordenar el HTML. La de
   Conexión/Cola/Consola se estira para llenar la pantalla (la consola
   absorbe el espacio sobrante); Movimiento del cabezal solo se ajusta a
   su propio contenido, sin estirarse para igualar a la otra columna. */
.laser-columns > .laser-column:first-child {
    order: 2;
    align-self: stretch;
    min-height: 0;
}

.laser-columns > .laser-column:last-child {
    order: 1;
}

.laser-column {
    display: flex;
    flex-direction: column;
    gap: 20px;
    flex: 1;
    min-width: 0;
}

.laser-card-half {
    min-width: 0;
    margin: 0;
}

.laser-card-compact {
    /* Antes zoom:0.7 -- dejaba estos títulos/botones notablemente más
       chicos que el resto de la app (nav, dashboard, etc). Sin zoom,
       coherente con el pedido de tamaño uniforme; el card ya scrollea
       solo si el contenido no entra. */
}

.laser-card-translucent {
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
}

/* Antes esta clase pintaba toda la tarjeta de un morado sólido fijo (var(--purple)
   casi no cambia entre los 4 temas), lo que la dejaba fuera de estilo frente al
   resto de tarjetas oscuras con acento de color (ej. .cnc-card). Ahora usa el
   mismo fondo oscuro que .laser-card y solo el borde izquierdo queda en morado;
   los textos/filas internas ya heredan los estilos base (var(--text), etc.),
   pensados para fondo oscuro, así que no hace falta forzarlos acá.  */
.laser-card-accent {
    border-left-color: var(--purple);
}

@media (max-width: 860px) {
    .laser-columns {
        flex-direction: column;
    }
}

.laser-status-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 600;
    color: var(--text);
}

.laser-status-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #ef4444;
    flex-shrink: 0;
}

.laser-status-dot.online {
    background: #22c55e;
}

.laser-state-pill {
    margin-left: auto;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
}

.laser-state-pill.state-run {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.laser-state-pill.state-hold,
.laser-state-pill.state-paused {
    background: rgba(245, 158, 11, 0.16);
    color: #f59e0b;
}

.laser-state-pill.state-alarm {
    background: rgba(239, 68, 68, 0.16);
    color: #ef4444;
}

.laser-illustration {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 16px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: rgba(255, 255, 255, 0.04);
}

.laser-illustration img {
    width: 100%;
    max-width: 360px;
    height: auto;
    object-fit: contain;
}

.laser-illustration.offline img {
    opacity: 0.4;
    filter: grayscale(0.9);
}

.laser-hub-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}

.laser-hub-tabs {
    flex: 1;
    min-width: 0;
}

.laser-hub-panel {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.laser-host-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.laser-host-row .settings-select {
    flex: 1;
    font-size: 0.8rem;
    padding: 8px 10px;
}

.laser-connection-header {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.laser-connection-summary {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.laser-connection-mode {
    font-size: 0.78rem;
    color: var(--text-muted);
}

.laser-illustration-compact {
    position: relative;
    margin-top: 0;
    flex-shrink: 0;
    width: 42%;
    max-width: 138px;
    cursor: pointer;
}

.laser-illustration-compact img {
    max-width: 100%;
}

.laser-illustration-settings-badge {
    position: absolute;
    bottom: 4px;
    right: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(245, 158, 11, 0.28);
    color: #f59e0b;
    border: 1px solid rgba(245, 158, 11, 0.5);
    pointer-events: none;
    animation: laserSettingsBadgeBlink 2.6s ease-in-out infinite;
}

@keyframes laserSettingsBadgeBlink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.laser-info-compact {
    min-width: 0;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px 12px;
    align-content: start;
    margin-top: 14px;
}

.laser-info-compact-row {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.82rem;
    padding: 3px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.laser-info-compact-row span {
    color: var(--text);
    flex-shrink: 0;
}

.laser-info-compact-row strong {
    color: #22c55e;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    text-align: right;
    word-break: break-word;
    min-width: 0;
}

.laser-metrics {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    margin-top: 16px;
}

.laser-metrics-single {
    grid-template-columns: minmax(0, 1fr);
}

.laser-workarea-stats-row {
    display: flex;
    gap: 10px;
    margin-top: 12px;
}

.laser-workarea-position {
    flex: 1;
    min-width: 0;
    background: rgba(34, 197, 94, 0.1);
    border-radius: var(--radius-md);
    padding: 12px 14px;
}

.laser-workarea-position span {
    display: block;
    color: var(--text-muted);
    font-size: 0.78rem;
}

.laser-workarea-position strong {
    display: block;
    margin-top: 6px;
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-move-to {
    margin: 0;
}

.laser-move-to-fields {
    display: flex;
    gap: 7px;
    margin-top: 6px;
}

.laser-coordinate-field {
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 0;
    height: 30px;
    padding: 0 8px;
    border: 1px solid rgba(34, 197, 94, 0.22);
    border-radius: 8px;
    background: color-mix(in srgb, var(--card-bg) 42%, transparent);
    transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.laser-coordinate-field:focus-within {
    border-color: rgba(34, 197, 94, 0.65);
    background: color-mix(in srgb, var(--card-bg) 62%, transparent);
    box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.1);
}

.laser-coordinate-field b {
    flex: 0 0 auto;
    color: #4ade80;
    font-size: 0.76rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-coordinate-field input {
    width: 100%;
    min-width: 0;
    padding: 0 0 0 6px;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--text);
    font-size: 0.78rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    -moz-appearance: textfield;
    appearance: textfield;
}

.laser-coordinate-field input::placeholder {
    color: color-mix(in srgb, var(--text-muted) 72%, transparent);
}

.laser-coordinate-field input::-webkit-inner-spin-button,
.laser-coordinate-field input::-webkit-outer-spin-button {
    margin: 0;
    appearance: none;
}

.laser-metrics div {
    background: rgba(34, 197, 94, 0.1);
    border-radius: var(--radius-md);
    padding: 12px 14px;
}

.laser-metrics span {
    display: block;
    color: var(--text-muted);
    font-size: 0.78rem;
}

.laser-metrics strong {
    display: block;
    margin-top: 6px;
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

/* ── Consola del láser acoplada al fondo de la ficha de movimiento ── */

#laser-console-card {
    display: flex;
    flex-direction: column;
}

.laser-console-dock {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

#laser-console-card .laser-console-dock .console-log {
    height: 220px;
}

.laser-console-dock-header {
    display: flex;
    align-items: center;
    gap: 8px;
}

.laser-console-dock-header h3 {
    flex: 1;
    min-width: 0;
}

.laser-console-dock-header h3 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

.laser-console-prompt {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    color: #22c55e;
    font-weight: 700;
}

#laser-console-active-name {
    color: #22c55e;
}

.laser-console-dock .console-log {
    height: 140px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-console-dock .console-input-row {
    padding: 0;
    border-top: none;
}

.laser-job-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

#laser-job-controls-panel {
    flex-direction: column;
    width: 100%;
    margin-top: 8px;
}

#laser-job-controls-panel .btn-file-action {
    width: 100%;
    justify-content: center;
    padding: 6px 10px;
    font-size: 0.76rem;
}

#laser-job-progress-panel {
    width: 100%;
    margin-top: 8px;
}

#laser-job-progress-panel span {
    font-size: 0.7rem;
}

.laser-job-toolbar .settings-select {
    flex: 1;
    min-width: 200px;
}

.laser-job-progress {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
}

.laser-job-progress-bar {
    flex: 1;
    height: 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.laser-job-progress-fill {
    height: 100%;
    background: #22c55e;
    width: 0%;
    transition: width 0.3s ease;
}

.laser-job-progress span {
    font-size: 0.8rem;
    color: var(--text-muted);
    white-space: nowrap;
}

.laser-job-error {
    margin: 12px 0 0;
    color: #ef4444;
    font-size: 0.85rem;
}

.laser-job-top-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

.laser-job-top-row #laser-job-controls-panel {
    flex: 0 0 88px;
    margin-top: 0;
}

.laser-job-info-row {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}

.laser-job-thumb {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

.laser-job-thumb img,
.laser-job-thumb svg {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.laser-job-info-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.laser-job-info-filename {
    font-size: 0.9rem;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.laser-job-info-times {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    font-size: 0.72rem;
    color: var(--text-muted);
}

.laser-job-info-times span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.laser-job-info-times strong {
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-job-stats-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-job-stat {
    flex: 1;
    min-width: 110px;
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--text-muted);
    font-size: 0.72rem;
}

.laser-job-stat svg {
    color: #22c55e;
    flex-shrink: 0;
}

.laser-job-stat strong {
    margin-left: auto;
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

/* Panel compacto visible solo durante una grabación administrada por NOPAL. */
.laser-jog-quadrant-job {
    padding: 10px;
}

.laser-job-layout {
    display: grid;
    grid-template-columns: 104px minmax(0, 1fr) 170px;
    gap: 10px;
    min-height: 150px;
}

.laser-job-actions-column,
.laser-job-main,
.laser-job-preview {
    min-width: 0;
    border: 1px solid rgba(34, 197, 94, 0.2);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--card-bg) 34%, transparent);
}

.laser-job-actions-column {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
}

.laser-job-actions-column #laser-job-controls-panel {
    flex: 0 0 auto;
    gap: 8px;
    margin: 0;
}

.laser-job-actions-column #laser-job-controls-panel .btn-file-action {
    min-height: 34px;
    padding: 6px 8px;
}

.laser-job-lines-stat {
    flex: 1;
    min-width: 0;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    padding: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-job-lines-stat strong {
    margin: 6px 0 0 auto;
}

.laser-job-main {
    display: flex;
    flex-direction: column;
    padding: 12px;
}

.laser-job-main .laser-job-info-row:not([hidden]) {
    display: block;
}

.laser-job-main #laser-job-progress-panel {
    margin-top: auto;
}

.laser-job-main .laser-job-stats-row {
    margin-top: 10px;
}

.laser-job-preview {
    padding: 8px;
    overflow: hidden;
}

.laser-job-preview .laser-job-thumb {
    width: 100%;
    height: 100%;
    min-height: 132px;
}

@media (max-width: 700px) {
    .laser-job-layout {
        grid-template-columns: 96px minmax(0, 1fr);
    }

    .laser-job-preview {
        grid-column: 1 / -1;
        min-height: 160px;
    }
}

.laser-card-title {
    margin: 0 0 16px;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

/* ── Encabezado estándar de ficha: ícono + título + [extras] + contraer ── */

.card-header-std {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 16px;
}

.card-header-std-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: #22c55e;
}

.laser-connection-machine-title {
    font-size: 0.8rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    flex-shrink: 0;
    max-width: 45%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-header-std-title {
    flex: 1;
    min-width: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

.laser-gamepad-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border: none;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 600;
    font-family: inherit;
    flex-shrink: 0;
    cursor: pointer;
    transition: background 0.15s ease;
}

.devices-subcard .laser-gamepad-badge {
    margin-top: 10px;
}

.laser-gamepad-badge:hover {
    background: rgba(148, 163, 184, 0.24);
}

.laser-gamepad-badge.connected {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.laser-gamepad-badge.connected:hover {
    background: rgba(34, 197, 94, 0.26);
}

.modal-content.laser-gamepad-modal-content {
    width: 94%;
    max-width: 1280px;
    height: auto;
    max-height: 92vh;
    overflow-y: auto;
    padding: 32px;
    gap: 20px;
    display: flex;
    flex-direction: column;
    border-radius: 24px;
    color: var(--text);
}

.laser-gamepad-close-btn {
    top: 24px;
    right: 24px;
}

.laser-gamepad-header {
    display: flex;
    align-items: center;
    gap: 16px;
}

.laser-gamepad-header-text {
    flex: 1;
    min-width: 0;
}

.laser-gamepad-header-text h2 {
    margin: 0 0 4px;
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #fff;
}

.laser-gamepad-header-text p {
    margin: 0;
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.55);
}

.laser-gamepad-select {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(34, 197, 94, 0.08);
    color: #4ade80;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: default;
}

.laser-gamepad-columns {
    display: grid;
    grid-template-columns: 0.85fr 1.3fr;
    gap: 20px;
    align-items: stretch;
}

.laser-gamepad-panel {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(34, 197, 94, 0.22);
    border-radius: var(--radius-lg);
    padding: 20px;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.laser-gamepad-panel-header {
    display: grid;
    grid-template-columns: 1fr 100px 100px;
    gap: 8px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #4ade80;
    margin-bottom: 14px;
}

.laser-gamepad-panel-header-single {
    display: flex;
    align-items: center;
    gap: 8px;
}

.laser-gamepad-map-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 4px;
}

.laser-gamepad-map-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(34, 197, 94, 0.05);
}

.laser-gamepad-map-row-label {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.86rem;
    font-weight: 600;
    color: #fff;
}

.laser-gamepad-map-row-badge {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    padding: 1px 6px;
    border-radius: 999px;
    border: 1px solid;
    background: transparent;
}

.laser-gamepad-map-row-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    background: rgba(34, 197, 94, 0.14);
    color: #4ade80;
    flex-shrink: 0;
}

.laser-gamepad-map-state {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100px;
    flex-shrink: 0;
    font-size: 0.74rem;
    color: rgba(255, 255, 255, 0.5);
}

.laser-gamepad-map-state-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
    flex-shrink: 0;
}

.laser-gamepad-map-state-dot.assigned {
    background: #22c55e;
    box-shadow: 0 0 5px 1px rgba(34, 197, 94, 0.7);
}

.laser-gamepad-assign-btn {
    width: 100px;
    padding: 6px 0;
    border-radius: 8px;
    border: 1px solid rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.14);
    color: #4ade80;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.15s ease;
}

.laser-gamepad-assign-btn:hover {
    background: rgba(34, 197, 94, 0.2);
}

.laser-gamepad-assign-btn.listening {
    background: rgba(245, 158, 11, 0.22);
    border-color: rgba(245, 158, 11, 0.5);
    color: #f59e0b;
}

/* ── Vista de consola: réplica esquemática del pendant físico ── */

.laser-gamepad-console {
    position: relative;
    background-color: rgba(6, 15, 10, 0.78);
    background-image:
        repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.015) 0, rgba(255, 255, 255, 0.015) 1px, transparent 1px, transparent 3px),
        radial-gradient(ellipse at 30% 20%, rgba(34, 197, 94, 0.1) 0%, transparent 60%);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: var(--radius-lg);
    padding: 26px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.lgc-buttons-col {
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.lgc-screw {
    position: absolute;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.05);
}

.lgc-screw-tl { top: 10px; left: 10px; }
.lgc-screw-tr { top: 10px; right: 10px; }
.lgc-screw-bl { bottom: 10px; left: 10px; }
.lgc-screw-br { bottom: 10px; right: 10px; }

.lgc-row {
    display: flex;
    justify-content: center;
    gap: 26px;
}

.lgc-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: 76px;
}

.lgc-btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 2px solid rgba(34, 197, 94, 0.85);
    background: rgba(34, 197, 94, 0.22);
    color: #eafff1;
    box-shadow: 0 0 10px rgba(34, 197, 94, 0.4);
    transition: box-shadow 0.2s ease, border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}

.lgc-btn-label {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: rgba(255, 255, 255, 0.92);
    text-align: center;
}

.lgc-btn.assigned .lgc-btn-icon {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.32);
    color: #eafff1;
    box-shadow: 0 0 16px 3px rgba(34, 197, 94, 0.65);
}

.lgc-btn.pressed .lgc-btn-icon {
    border-color: #4ade80;
    background: rgba(74, 222, 128, 0.5);
    color: #fff;
    box-shadow: 0 0 20px 6px rgba(74, 222, 128, 0.85);
    transform: scale(1.08);
}

.lgc-btn.assigned .lgc-btn-label {
    color: #4ade80;
}

.lgc-btn-unassignable .lgc-btn-icon {
    opacity: 0.35;
    cursor: default;
}

.lgc-btn-unassignable .lgc-btn-label {
    opacity: 0.35;
}

.lgc-dpad {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    flex-shrink: 0;
}

.lgc-dpad-z-col {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.lgc-dpad-ring {
    position: relative;
    width: 300px;
    height: 300px;
    border-radius: 50%;
    border: 1px solid rgba(34, 197, 94, 0.5);
    background: radial-gradient(circle, rgba(34, 197, 94, 0.1) 0%, transparent 70%);
}

.lgc-dpad-arrow {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #22c55e;
    filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.6));
}

.lgc-dpad-arrow-up { top: 10px; left: 50%; transform: translateX(-50%); }
.lgc-dpad-arrow-down { bottom: 10px; left: 50%; transform: translateX(-50%); }
.lgc-dpad-arrow-left { left: 10px; top: 50%; transform: translateY(-50%); }
.lgc-dpad-arrow-right { right: 10px; top: 50%; transform: translateY(-50%); }

.lgc-dpad-btn {
    position: absolute;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 2px solid rgba(34, 197, 94, 0.65);
    background: rgba(34, 197, 94, 0.16);
    cursor: default;
    transition: box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.lgc-dpad-btn.assigned {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.4);
    box-shadow: 0 0 14px 3px rgba(34, 197, 94, 0.6);
}

.lgc-dpad-btn.pressed {
    border-color: #4ade80;
    background: rgba(74, 222, 128, 0.6);
    box-shadow: 0 0 22px 6px rgba(74, 222, 128, 0.85);
}

.lgc-dpad-up { top: 54px; left: 50%; transform: translateX(-50%); }
.lgc-dpad-down { bottom: 54px; left: 50%; transform: translateX(-50%); }
.lgc-dpad-left { left: 54px; top: 50%; transform: translateY(-50%); }
.lgc-dpad-right { right: 54px; top: 50%; transform: translateY(-50%); }

.lgc-dpad-center {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 66px;
    height: 66px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: rgba(34, 197, 94, 0.9);
}

.laser-gamepad-legend {
    display: flex;
    justify-content: center;
    gap: 20px;
    margin-top: 14px;
    font-size: 0.74rem;
    color: rgba(255, 255, 255, 0.5);
}

.laser-gamepad-legend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.laser-gamepad-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
}

.laser-gamepad-legend-dot.assigned {
    background: #22c55e;
    box-shadow: 0 0 5px 1px rgba(34, 197, 94, 0.7);
}

.laser-gamepad-info-box {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 14px 16px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.2);
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.8rem;
}

.laser-gamepad-info-box svg {
    flex-shrink: 0;
    color: #4ade80;
    margin-top: 1px;
}

.laser-gamepad-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

@media (max-width: 900px) {
    .laser-gamepad-columns {
        grid-template-columns: 1fr;
    }
}

.card-header-std-extras {
    display: flex;
    align-items: center;
    gap: 8px;
}

.card-header-std-note {
    flex-shrink: 0;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.laser-card-accent .card-header-std-note {
    color: rgba(255, 255, 255, 0.75);
}

.card-collapse-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    border: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    cursor: pointer;
    transition: background 0.15s ease, transform 0.2s ease;
}

.card-collapse-toggle:hover {
    background: rgba(255, 255, 255, 0.16);
}

.card-collapse-toggle svg {
    transition: transform 0.2s ease;
}

.card-collapse-toggle.collapsed svg {
    transform: rotate(-90deg);
}

.laser-card-accent .card-header-std-title {
    color: #fff;
}

.laser-card-accent .card-collapse-toggle {
    background: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.85);
}

.card-collapsible.collapsed > *:not(.card-header-std) {
    display: none;
}

/* La ficha de Conexión ahora es un hub con pestañas (Conexión/Cámara/
   Consola/Cola) -- al contraerse solo se ven la barra de pestañas y el
   botón de expandir, el contenido de la pestaña activa se oculta. */
#laser-connection-card.collapsed > .laser-hub-header {
    display: flex;
}

#laser-connection-card.collapsed > .laser-connection-toggle-row {
    display: flex;
}

.laser-connection-toggle-row {
    display: flex;
    justify-content: center;
    margin: 4px -20px -20px;
    padding-bottom: 4px;
}

.laser-connection-toggle-btn {
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: transparent;
    color: var(--green-dark);
}

.laser-connection-toggle-btn:hover {
    background: transparent;
}

.laser-connection-toggle-btn svg {
    transform: rotate(180deg);
}

.laser-connection-toggle-btn.collapsed svg {
    transform: rotate(0deg);
}

.laser-jog-layout {
    display: grid;
    /* Los controles manuales tienen un ancho real de 208px. Esta pista
       incluye sus 14px de padding a cada lado y deja todo el espacio
       restante al mapa, evitando franjas vacías alrededor del jog pad. */
    grid-template-columns: fit-content(236px) minmax(0, 1fr);
    grid-template-areas:
        "manual workarea"
        "controls workarea"
        "job job";
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: 14px;
}

.laser-jog-quadrant-manual { grid-area: manual; }
.laser-jog-quadrant-workarea { grid-area: workarea; }
.laser-jog-quadrant-controls {
    grid-area: controls;
    align-self: start;
}
.laser-jog-quadrant-job { grid-area: job; }

@media (max-width: 700px) {
    .laser-jog-layout {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "manual"
            "controls"
            "workarea"
            "job";
        grid-template-rows: auto;
    }

    .laser-jog-quadrant-job.laser-jog-quadrant-job-full {
        grid-column: 1;
    }
}

/* Cuando hay un trabajo activo, "Controles de máquina" se oculta (ver
   renderLaserJob en app.js) y este cuadrante pasa a ocupar las dos columnas
   de su fila en vez de quedar a la mitad. */
.laser-jog-quadrant-job.laser-jog-quadrant-job-full {
    grid-column: 1 / -1;
}

.laser-jog-quadrant {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px;
    background: rgba(34, 197, 94, 0.06);
    border: 1px solid rgba(34, 197, 94, 0.2);
    border-radius: var(--radius-lg);
    min-width: 0;
}

.laser-jog-quadrant-title {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.laser-jog-quadrant-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.laser-jog-quadrant-header .laser-jog-quadrant-title {
    margin: 0;
}

.laser-jog-quadrant-manual .laser-jog-cross-col {
    margin: 0 auto;
}

.laser-jog-quadrant-manual {
    align-self: start;
    height: fit-content;
}

.laser-jog-quadrant-manual .laser-fire-power,
.laser-jog-quadrant-manual .laser-jog-steps-block {
    width: 208px;
    margin: 0 auto;
}

.laser-jog-quadrant-manual .laser-fire-power-row,
.laser-jog-quadrant-manual .laser-jog-steps {
    width: 100%;
}

.laser-jog-quadrant-manual .laser-fire-power .laser-power-presets,
.laser-jog-quadrant-manual .laser-jog-steps {
    flex: 1;
    min-width: 0;
}

.laser-jog-quadrant-manual .laser-fire-power .laser-power-presets .laser-step-btn,
.laser-jog-quadrant-manual .laser-jog-steps .laser-step-btn {
    flex: 1;
}

.laser-jog-cross-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

.laser-jog-steps-block {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.laser-jog-pad {
    display: grid;
    grid-template-columns: repeat(3, 64px);
    grid-template-rows: repeat(3, 64px);
    grid-template-areas:
        "nw      yplus  ne"
        "xminus  home   xplus"
        "sw      yminus se";
    gap: 8px;
}

.laser-jog-slot-nw { grid-area: nw; }
.laser-jog-slot-yplus { grid-area: yplus; }
.laser-jog-slot-ne { grid-area: ne; }
.laser-jog-slot-xminus { grid-area: xminus; }
.laser-jog-slot-home { grid-area: home; }
.laser-jog-slot-xplus { grid-area: xplus; }
.laser-jog-slot-sw { grid-area: sw; }
.laser-jog-slot-yminus { grid-area: yminus; }
.laser-jog-slot-se { grid-area: se; }

.laser-jog-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(34, 197, 94, 0.22);
    border-radius: 18px;
    background: rgba(255, 255, 255, 0.03);
    color: #4ade80;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
}

.laser-jog-btn:hover {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.55);
    color: #22c55e;
    transform: translateY(-1px);
}

.laser-jog-btn:active {
    transform: scale(0.94);
}

.laser-jog-slot-home {
    background: rgba(34, 197, 94, 0.22);
    color: #22c55e;
    border-color: #22c55e;
    box-shadow: 0 0 16px 2px rgba(34, 197, 94, 0.4);
}

.laser-jog-btn:disabled {
    opacity: 0.35;
    cursor: default;
    transform: none !important;
    background: rgba(255, 255, 255, 0.03) !important;
    color: var(--text-muted) !important;
    border-color: rgba(255, 255, 255, 0.1) !important;
    box-shadow: none !important;
}

.laser-jog-side {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    gap: 10px;
}

.laser-bed-map-viewport {
    position: relative;
    flex: 1;
    min-height: 220px;
    display: flex;
    overflow: auto;
    padding-left: 34px;
    padding-bottom: 22px;
}

.laser-bed-map-axis {
    position: absolute;
    z-index: 2;
    color: var(--text-muted);
    font-size: 0.62rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    pointer-events: none;
}

.laser-bed-map-axis-y {
    top: 0;
    bottom: 22px;
    left: 0;
    width: 30px;
    display: flex;
    flex-direction: column-reverse;
    justify-content: space-between;
}

.laser-bed-map-axis-x {
    left: 34px;
    right: 0;
    bottom: 0;
    height: 18px;
    display: flex;
    justify-content: space-between;
}

.laser-bed-map-axis span {
    white-space: nowrap;
}

.laser-bed-map {
    position: relative;
    width: 100%;
    max-width: none;
    flex: 1;
    aspect-ratio: 1 / 1;
    cursor: crosshair;
    zoom: var(--bed-zoom, 1);
    background-color: rgba(255, 255, 255, 0.03);
    background-image:
        repeating-linear-gradient(0deg, rgba(34, 197, 94, 0.18) 0, rgba(34, 197, 94, 0.18) 1px, transparent 1px, transparent 20%),
        repeating-linear-gradient(90deg, rgba(34, 197, 94, 0.18) 0, rgba(34, 197, 94, 0.18) 1px, transparent 1px, transparent 20%);
    border: 1px solid rgba(34, 197, 94, 0.3);
    border-radius: 0;
    overflow: hidden;
}

.laser-bed-map-zoom-controls {
    position: absolute;
    right: 12px;
    bottom: 34px;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 6px;
    border: 1px solid rgba(34, 197, 94, 0.25);
    border-radius: 9px;
    background: rgba(6, 20, 14, 0.78);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.laser-bed-map-zoom-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 7px;
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(34, 197, 94, 0.1);
    color: #22c55e;
    cursor: pointer;
    transition: background 0.15s ease;
}

.laser-bed-map-zoom-btn svg {
    width: 16px;
    height: 16px;
}

.laser-bed-map-zoom-btn:hover {
    background: rgba(34, 197, 94, 0.2);
}

.laser-bed-map-zoom-btn.active {
    background: #22c55e;
    color: #06140e;
    box-shadow: 0 0 10px 2px rgba(34, 197, 94, 0.5);
}

.laser-bed-map-zoom-label {
    min-width: 44px;
    text-align: center;
    font-size: 0.82rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-bed-map-trace {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    pointer-events: none;
}

#laser-bed-map-trace-line {
    stroke: #22c55e;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    opacity: 0.85;
    filter: drop-shadow(0 0 2px rgba(34, 197, 94, 0.6));
}

.laser-bed-map-dot {
    --laser-marker-color: #22c55e;
    position: absolute;
    z-index: 2;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--laser-marker-color);
    box-shadow: 0 0 6px 2px color-mix(in srgb, var(--laser-marker-color) 55%, transparent);
    transform: translate(-50%, 50%);
    transition: left 0.3s ease, bottom 0.3s ease, background 0.2s ease;
}

.laser-bed-map-dot.shape-cross {
    width: 12px;
    height: 12px;
    background: transparent;
    border-radius: 0;
    box-shadow: none;
}

.laser-bed-map-dot.shape-cross::before,
.laser-bed-map-dot.shape-cross::after {
    content: '';
    position: absolute;
    background: var(--laser-marker-color);
    box-shadow: 0 0 4px 1px color-mix(in srgb, var(--laser-marker-color) 55%, transparent);
}

.laser-bed-map-dot.shape-cross::before {
    left: 50%;
    top: 0;
    bottom: 0;
    width: 2px;
    transform: translateX(-50%);
}

.laser-bed-map-dot.shape-cross::after {
    top: 50%;
    left: 0;
    right: 0;
    height: 2px;
    transform: translateY(-50%);
}

.laser-bed-map-empty {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    text-align: center;
    font-size: 0.62rem;
    color: var(--text-muted);
}

.laser-bed-map-dims {
    font-size: 0.76rem;
    font-weight: 700;
    color: #22c55e;
    text-align: right;
    white-space: nowrap;
}

.laser-bed-map-hover-coords {
    position: absolute;
    bottom: 4px;
    left: 6px;
    z-index: 2;
    font-size: 0.72rem;
    font-weight: 600;
    color: #22c55e;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    pointer-events: none;
}

.laser-jog-z {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
}

.laser-jog-z-label {
    font-weight: 800;
    color: var(--text-muted);
    background: rgba(255, 255, 255, 0.03);
}

.laser-jog-z-btn {
    width: 60px;
    height: 42px;
}

.laser-jog-steps-label {
    font-size: 0.72rem;
    color: var(--text-muted);
}

.laser-jog-steps {
    display: flex;
    gap: 6px;
}

.laser-step-btn {
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 0.82rem;
    cursor: pointer;
}

.laser-step-btn.active {
    background: rgba(34, 197, 94, 0.16);
    border-color: rgba(34, 197, 94, 0.4);
    color: #22c55e;
    font-weight: 700;
}

/* ── Ficha CNC dedicada ("NOPAL CNC") ── */

.cnc-main {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 20px 32px;
}

.cnc-topbar {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    padding: 14px 18px;
    background: var(--card-bg);
    border: 1px solid rgba(245, 158, 11, 0.25);
    border-radius: var(--radius-lg);
}

.cnc-topbar-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1.05rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    flex-shrink: 0;
}

.cnc-state-pill {
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.cnc-state-pill.state-alarm {
    background: rgba(239, 68, 68, 0.18);
    color: #ef4444;
}

.cnc-state-pill.state-run {
    background: rgba(245, 158, 11, 0.18);
    color: var(--orange);
}

.cnc-topbar-selectors {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    flex: 1;
}

.cnc-topbar-field {
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.cnc-topbar-field select {
    padding: 6px 10px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 0.82rem;
    font-weight: 600;
    min-width: 140px;
}

.cnc-topbar-icons {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.cnc-topbar-avatar {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(245, 158, 11, 0.18);
    color: var(--orange);
    font-size: 0.72rem;
    font-weight: 800;
}

.cnc-main-layout {
    display: grid;
    grid-template-columns: minmax(260px, 320px) 1fr;
    gap: 16px;
    align-items: start;
}

.cnc-left-col {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

.cnc-right-col {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

.cnc-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    background: var(--card-bg);
    border: 1px solid rgba(245, 158, 11, 0.2);
    border-radius: var(--radius-lg);
    min-width: 0;
}

.cnc-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.cnc-card-title {
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    color: var(--orange);
}

.cnc-card-header-actions {
    display: flex;
    gap: 6px;
}

.cnc-position-table {
    width: 100%;
    border-collapse: collapse;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-position-table th,
.cnc-position-table td {
    padding: 4px 6px;
    text-align: right;
}

.cnc-position-table thead th {
    font-size: 0.6rem;
    color: var(--text-muted);
    font-weight: 700;
    text-transform: uppercase;
}

.cnc-position-table tbody th {
    text-align: left;
    color: var(--text-muted);
    font-weight: 700;
}

.cnc-position-table tbody td {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

.cnc-position-table tbody td:last-child {
    color: var(--text-muted);
    font-size: 0.85rem;
    font-weight: 600;
}

.cnc-feed-spindle-row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.78rem;
    color: var(--text-muted);
    padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.cnc-feed-spindle-row strong {
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-pin-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.cnc-pin-pill {
    padding: 4px 9px;
    border-radius: 999px;
    font-size: 0.66rem;
    font-weight: 700;
    border: 1px solid rgba(255, 255, 255, 0.12);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-muted);
}

.cnc-pin-pill.active {
    border-color: #ef4444;
    background: rgba(239, 68, 68, 0.18);
    color: #ef4444;
}

.cnc-job-file-row {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--orange);
}

.cnc-job-file-row div {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cnc-job-file-row strong {
    color: var(--text);
    font-size: 0.88rem;
}

.cnc-job-file-row span {
    font-size: 0.68rem;
    color: var(--text-muted);
}

.cnc-job-progress-row {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.72rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-job-progress-row .laser-job-progress-bar {
    flex: 1;
}

.cnc-job-buttons-row {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.cnc-job-buttons-row .btn-file-action,
.cnc-job-buttons-row .laser-step-btn {
    flex: 1;
    justify-content: center;
    text-align: center;
}

.cnc-override-block {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.cnc-override-label {
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.cnc-override-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.cnc-override-row .laser-step-btn {
    flex: 1;
    text-align: center;
}

.cnc-override-value {
    min-width: 46px;
    text-align: center;
    font-weight: 700;
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-zero-row {
    display: flex;
    gap: 8px;
}

.cnc-shift-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.cnc-shift-inputs {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.cnc-shift-inputs label {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.72rem;
    color: var(--text-muted);
}

.cnc-shift-inputs input[type="number"] {
    width: 64px;
    padding: 5px 7px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-shift-auto {
    margin-left: auto;
}

.cnc-spindle-cw-row {
    display: flex;
    gap: 6px;
}

.cnc-spindle-mode-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-muted);
    font-weight: 700;
    font-size: 0.8rem;
    cursor: pointer;
}

.cnc-spindle-mode-btn.active {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.18);
    color: #22c55e;
}

.cnc-rpm-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.cnc-rpm-row input {
    flex: 1;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 0.95rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-rpm-row span {
    font-size: 0.72rem;
    color: var(--text-muted);
}

.cnc-rpm-presets {
    display: flex;
    gap: 6px;
}

.cnc-rpm-presets .laser-step-btn {
    flex: 1;
    text-align: center;
}

.cnc-jog-card {
    align-items: center;
    text-align: center;
}

.cnc-jog-card .cnc-card-header {
    width: 100%;
}

.cnc-feed-mode-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    font-size: 0.7rem;
    color: var(--text-muted);
}

.cnc-feed-mode-group,
.cnc-rapid-group {
    display: flex;
    gap: 6px;
}

.cnc-feed-mode-group .laser-step-btn,
.cnc-rapid-group .laser-step-btn {
    flex: 1;
    text-align: center;
}

.cnc-jog-steps {
    display: flex;
    gap: 6px;
}

.cnc-jog-pad-row {
    display: flex;
    align-items: center;
    gap: 14px;
}

.cnc-jog-z-col {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.cnc-jog-steps-z {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 8px;
}

.cnc-jog-steps-z .laser-step-btn {
    padding: 3px 6px;
    font-size: 0.75rem;
}

.cnc-stop-btn {
    width: 46px;
    height: 46px;
    border-radius: 10px;
    border: none;
    background: #ef4444;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.18);
}

.cnc-stop-btn:hover {
    background: #dc2626;
}

.cnc-rapid-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    font-size: 0.7rem;
    color: var(--text-muted);
}

.cnc-files-card {
    gap: 10px;
}

.cnc-files-search {
    width: 100%;
    padding: 8px 12px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 0.82rem;
}

.cnc-files-table-wrap {
    max-height: 340px;
    overflow-y: auto;
}

.cnc-files-table th,
.cnc-files-table td {
    font-size: 0.78rem;
}

.cnc-files-row {
    cursor: pointer;
}

.cnc-files-row-actions {
    display: flex;
    gap: 4px;
    justify-content: flex-end;
}

.cnc-footer-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 10px 18px;
    background: var(--card-bg);
    border: 1px solid rgba(245, 158, 11, 0.2);
    border-radius: var(--radius-lg);
    font-size: 0.76rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.cnc-footer-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    flex-shrink: 0;
}

.cnc-footer-dot.online {
    background: #22c55e;
}

.cnc-footer-sep {
    opacity: 0.4;
}

.cnc-footer-spacer {
    flex: 1;
}

.cnc-footer-bar strong {
    color: var(--text);
}

.cnc-footer-stop-btn {
    flex-shrink: 0;
}

/* Modo Simple/Avanzado del panel CNC — ver applyCncDashboardMode() en app.js.
   Simple es el estado por defecto (sin atributo o cualquier valor distinto
   de "advanced"): los controles semi-pro quedan ocultos hasta que el
   usuario active el modo Avanzado en Configuración. */
body:not([data-cnc-mode="advanced"]) .cnc-advanced-only {
    display: none;
}

/* Perfil de máquina CNC — ver applyCncMachineProfile() en app.js. Router
   (con husillo real) es el default; en plotter (lápiz/marcador) no aplica
   RPM, dirección de husillo ni sonda montada en husillo. */
body[data-cnc-profile="plotter"] .cnc-router-only {
    display: none;
}

/* Firmware de la placa CNC/láser activa — ver refreshCncStatus()/
   renderLaserStatus() en app.js, que escriben este atributo con el
   "firmware" que devuelve /api/laser/status ("fluidnc" por defecto,
   "marlin" para placas dadas de alta como Marlin). Los controles exclusivos
   de GRBL (desbloquear $X, WCS G54-G59, overrides de feed/spindle en tiempo
   real, pines de límite) no existen en Marlin y se ocultan. La fila con las
   temperaturas de extrusor/cama (caso híbrido: placa Marlin con hotend) usa
   el criterio inverso, .marlin-only, oculta salvo firmware="marlin". */
body[data-machine-firmware="marlin"] .grbl-only {
    display: none;
}

body:not([data-machine-firmware="marlin"]) .cnc-marlin-only {
    display: none;
}

@media (max-width: 1100px) {
    .cnc-main-layout {
        grid-template-columns: 1fr;
    }
}

/* ── Visor CNC: pestañas VISOR / 3D VIEW / SIMULATION ── */

.cnc-viewer-card {
    padding: 0;
    overflow: hidden;
    min-height: 480px;
    flex: 1;
}

.cnc-viewer-tabs {
    display: flex;
    gap: 4px;
    padding: 10px 14px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
}

.cnc-viewer-tab {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    padding: 8px 12px 10px;
    cursor: pointer;
    border-bottom: 2px solid transparent;
}

.cnc-viewer-tab.active {
    color: var(--green-dark);
    border-bottom-color: var(--green-dark);
}

.cnc-viewer-panels {
    position: relative;
    flex: 1;
    min-height: 420px;
    display: flex;
}

.cnc-viewer-panel {
    display: none;
    width: 100%;
    height: 100%;
}

.cnc-viewer-panel.active {
    display: flex;
}

.cnc-visor-canvas-wrap {
    position: relative;
    flex: 1;
    background: #081410;
}

.cnc-visor-canvas {
    position: absolute;
    inset: 0;
}

.cnc-visor-origin-marker {
    /* Antes tenía top/left fijos (decorativo, siempre arriba-izquierda sin
       importar dónde estuviera X0/Y0 real) — ahora la posición la calcula
       updateOriginMarker() en cada frame vía transform: translate(), acá
       solo queda position:absolute como base para ese transform. */
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: none;
}

.cnc-visor-coords {
    position: absolute;
    top: 12px;
    right: 12px;
    display: flex;
    gap: 12px;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.78rem;
    background: rgba(0, 0, 0, 0.4);
    padding: 6px 12px;
    border-radius: 8px;
    pointer-events: none;
}

.cnc-visor-nav-col {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.cnc-visor-legend {
    position: absolute;
    bottom: 12px;
    right: 12px;
    max-width: 220px;
    background: var(--card-bg);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: var(--radius-lg);
    padding: 10px 12px;
}

.cnc-visor-legend-list {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 0.76rem;
    color: var(--text);
}

.cnc-visor-legend-list li {
    display: flex;
    align-items: center;
    gap: 8px;
}

.cnc-visor-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

.cnc-visor-swatch-rapid {
    background: rgba(255, 255, 255, 0.35);
}

.cnc-visor-swatch-cut {
    background: var(--orange);
}

.cnc-visor-swatch-selected {
    background: #fbbf24;
}

.cnc-visor-empty-state {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 20px;
    color: var(--text-muted);
    font-size: 0.85rem;
}

.cnc-viewer-soon {
    margin: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    text-align: center;
    color: var(--text-muted);
    padding: 20px;
    max-width: 320px;
}

/* ── Asistente guiado CNC ── */

.modal-content.cnc-wizard-modal-content {
    width: 90%;
    max-width: 460px;
    height: auto;
    max-height: 85vh;
    overflow-y: auto;
    padding: 28px;
    gap: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.cnc-wizard-steps-indicator {
    display: flex;
    gap: 8px;
    margin-bottom: 6px;
}

.cnc-wizard-step-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.15);
}

.cnc-wizard-step-dot.active {
    background: var(--green-dark);
}

.cnc-wizard-step-dot.done {
    background: rgba(34, 197, 94, 0.5);
}

.cnc-wizard-step {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.cnc-wizard-step-title {
    font-weight: 700;
    font-size: 1rem;
    color: var(--text);
    margin: 0;
}

.cnc-wizard-step-hint {
    font-size: 0.82rem;
    color: var(--text-muted);
    margin: 0;
}

.cnc-wizard-file-list {
    width: 100%;
    max-height: 220px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    text-align: left;
}

.cnc-wizard-file-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius-md);
    cursor: pointer;
    border: 1px solid transparent;
}

.cnc-wizard-file-row:hover {
    background: rgba(255, 255, 255, 0.09);
}

.cnc-wizard-file-row.selected {
    border-color: var(--green-dark);
    background: rgba(34, 197, 94, 0.1);
}

.cnc-wizard-zero-btn {
    width: 100%;
    justify-content: center;
}

.cnc-wizard-unlock-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.cnc-wizard-fit-outer {
    position: relative;
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1;
    background: rgba(255, 255, 255, 0.04);
    border: 1px dashed rgba(255, 255, 255, 0.25);
    border-radius: 8px;
}

.cnc-wizard-fit-inner {
    position: absolute;
    background: rgba(245, 158, 11, 0.35);
    border: 1px solid #f59e0b;
    border-radius: 2px;
}

.cnc-wizard-fit-inner.overflow {
    background: rgba(239, 68, 68, 0.35);
    border-color: #ef4444;
}

.cnc-wizard-fit-text {
    font-size: 0.85rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    color: var(--text);
    margin: 0;
}

.cnc-wizard-fit-ack {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
    color: var(--text-muted);
    text-align: left;
}

/* ── Asistente de configuración del CNC ── */

.cnc-setup-wizard-modal-content {
    max-width: 520px;
}

.cnc-setup-subsection {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 4px;
}

.cnc-setup-subsection-label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    text-align: left;
}

.cnc-setup-zero-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.cnc-setup-zero-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 10px 6px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.03);
    color: var(--text-muted);
    font-size: 0.72rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.cnc-setup-zero-btn:hover {
    background: rgba(255, 255, 255, 0.07);
}

.cnc-setup-zero-btn.active {
    border-color: var(--green-dark);
    background: rgba(34, 197, 94, 0.1);
    color: var(--text);
}

.cnc-setup-zero-dot {
    position: relative;
    width: 34px;
    height: 24px;
    border: 1.5px solid rgba(255, 255, 255, 0.25);
    border-radius: 3px;
}

.cnc-setup-zero-btn.active .cnc-setup-zero-dot {
    border-color: rgba(34, 197, 94, 0.5);
}

.cnc-setup-zero-dot::after {
    content: '';
    position: absolute;
    left: var(--dot-x);
    top: var(--dot-y);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--green-dark);
    transform: translate(-50%, -50%);
}

.cnc-setup-zero-z-switch {
    width: 100%;
}

.cnc-setup-maxz-field {
    width: 100%;
    max-width: 220px;
}

.cnc-setup-type-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
    gap: 8px;
    width: 100%;
}

.cnc-setup-type-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 8px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.03);
    color: var(--text-muted);
    font-size: 0.75rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.cnc-setup-type-card:hover {
    background: rgba(255, 255, 255, 0.07);
}

.cnc-setup-type-card.active {
    border-color: var(--green-dark);
    background: rgba(34, 197, 94, 0.1);
    color: var(--text);
}

.cnc-setup-followup {
    width: 100%;
    margin-top: 4px;
}

.cnc-setup-dim-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.cnc-setup-dim-row input {
    flex: 1;
    min-width: 0;
}

.cnc-setup-summary-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
}

.cnc-setup-summary-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 0.85rem;
    padding: 7px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.cnc-setup-summary-row span:first-child {
    color: var(--text-muted);
}

.cnc-setup-summary-row strong {
    color: var(--text);
    text-align: right;
}

.cnc-viewer-soon strong {
    color: var(--text);
    font-size: 0.95rem;
}

.cnc-viewer-soon p {
    margin: 0;
    font-size: 0.8rem;
}

.laser-jog-actions {
    margin-top: 0;
}

.laser-jog-cross-col .laser-jog-actions .btn-file-action {
    width: 100%;
}

.laser-jog-controls-row {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.laser-fire-group {
    flex: 1;
    min-width: 140px;
    display: flex;
}

.laser-fire-btn-wide,
.laser-air-btn-wide {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 700;
    transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}

.laser-fire-btn-wide {
    border: 1px solid rgba(239, 68, 68, 0.4);
    background: rgba(239, 68, 68, 0.12);
    color: #f87171;
}

.laser-fire-btn-wide:hover {
    background: rgba(239, 68, 68, 0.2);
}

.laser-fire-btn-wide.active {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.2);
    color: #4ade80;
    box-shadow: 0 0 16px 2px rgba(34, 197, 94, 0.35);
    animation: laserFirePulse 1.2s ease-in-out infinite;
}

.laser-spindle-btn-wide {
    border-color: rgba(245, 158, 11, 0.4);
    background: rgba(245, 158, 11, 0.12);
    color: var(--orange);
}

.laser-spindle-btn-wide.active {
    border-color: var(--orange);
    background: rgba(245, 158, 11, 0.22);
    color: #fbbf24;
    box-shadow: 0 0 16px 2px rgba(245, 158, 11, 0.35);
    animation: none;
}

@keyframes laserFirePulse {
    0%, 100% { box-shadow: 0 0 16px 2px rgba(34, 197, 94, 0.35); }
    50% { box-shadow: 0 0 22px 5px rgba(34, 197, 94, 0.2); }
}

.laser-air-btn-wide {
    border: 1px solid rgba(34, 197, 94, 0.4);
    background: rgba(34, 197, 94, 0.14);
    color: #22c55e;
}

.laser-air-btn-wide:hover {
    background: rgba(34, 197, 94, 0.22);
}

.laser-air-btn-wide.active {
    box-shadow: 0 0 16px 2px rgba(34, 197, 94, 0.35);
    animation: laserAirPulse 1.2s ease-in-out infinite;
}

@keyframes laserAirPulse {
    0%, 100% { box-shadow: 0 0 16px 2px rgba(34, 197, 94, 0.35); }
    50% { box-shadow: 0 0 22px 5px rgba(34, 197, 94, 0.2); }
}

.laser-fire-label {
    font-size: 0.8rem;
    font-weight: 700;
}

.laser-fire-power {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.laser-fire-power label {
    font-size: 0.72rem;
    color: var(--text-muted);
}

.laser-fire-power-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.laser-fire-power input {
    width: 72px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    padding: 8px 10px;
    font-size: 0.85rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-power-presets {
    display: flex;
    gap: 6px;
    flex: 1;
}

.laser-power-presets .laser-step-btn {
    flex: 1;
    text-align: center;
}

.laser-card-header-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.laser-card-header-row .laser-card-title {
    margin-bottom: 0;
}

.laser-card-header-row .btn-icon-dark {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
}

.laser-card-subtitle {
    margin: -10px 0 16px;
    color: var(--text-muted);
    font-size: 0.85rem;
}

.modal-content.laser-settings-modal-content {
    width: 92%;
    max-width: 640px;
    height: auto;
    max-height: 85vh;
    padding: 28px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    overflow-y: auto;
}

.laser-settings-modal-header h2 {
    margin: 0 0 6px;
}

/* ── Memoria (SD) del hub del láser -- réplica visual de la referencia del
   usuario, construida sobre tokens y clases ya existentes en NOPAL
   (.card-header-std/.card-collapsible ya genéricos, .gcode-library-search/
   .gcode-select-control/.gcode-toolbar-action/.gcode-primary-action/
   .gcode-view-switch ya definidos para la barra de la biblioteca de G-code
   -- misma apariencia, sin duplicar reglas). Ver renderSdRows/
   applySdListFilters en app.js. ── */

.laser-sd-body {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.laser-sd-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    min-width: 0;
}

.laser-sd-breadcrumb .breadcrumb-segment {
    min-height: 26px;
    padding: 0 10px;
    font-size: 0.68rem;
}

.laser-sd-search-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.laser-sd-search {
    flex: 1;
    min-width: 180px;
}

.laser-sd-type-control select,
.laser-sd-sort-control select {
    max-width: 130px;
}

.laser-sd-actions-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.laser-sd-upload-label {
    cursor: pointer;
}

.laser-sd-more-wrap {
    margin-left: auto;
}

.laser-sd-more-menu-library {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 4px;
    padding-top: 6px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-sd-more-menu-library .settings-select {
    width: 100%;
}

.laser-sd-columns-head,
.laser-sd-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 90px 150px 150px;
    align-items: center;
    gap: 12px;
}

.laser-sd-columns-head {
    padding: 0 12px;
    color: var(--text-muted);
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.laser-sd-col-size,
.laser-sd-col-modified {
    text-align: left;
}

.laser-sd-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 120px;
    max-height: 420px;
    overflow-y: auto;
}

.laser-sd-row {
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid transparent;
    border-radius: 10px;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.laser-sd-row:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(var(--accent-rgb), 0.25);
}

.laser-sd-row-name-col {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.laser-sd-row-icon {
    color: #22c55e;
    flex-shrink: 0;
}

.laser-sd-row-name-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.laser-sd-row-name {
    color: var(--text);
    font-size: 0.85rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
}

.laser-sd-row-name:hover {
    color: #22c55e;
}

.laser-sd-row-meta {
    font-size: 0.68rem;
    color: var(--text-muted);
}

.laser-sd-row-size,
.laser-sd-row-modified {
    flex-shrink: 0;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-sd-row-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.laser-sd-preview-btn.is-disabled {
    opacity: 0.4;
    pointer-events: none;
}

.laser-sd-row-menu-wrap {
    position: relative;
    flex-shrink: 0;
}

.laser-sd-row-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    min-width: 150px;
    padding: 4px;
    background: #1f2937;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}

.laser-sd-row-menu-item {
    padding: 8px 10px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #f8fafc;
    font-size: 0.82rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease;
}

.laser-sd-row-menu-item:hover {
    background: rgba(255, 255, 255, 0.1);
}

.laser-sd-row-menu-item-danger {
    color: #f87171;
}

/* Formatear SD -- ámbar, no rojo: no es "cancelar/eliminar algo puntual",
   es una acción de sistema poco frecuente que además no está confirmada
   contra el firmware (ver laserSdFormatConfirm1). */
.laser-sd-row-menu-item-amber {
    color: #f59e0b;
}

.laser-sd-more-menu-divider {
    height: 1px;
    margin: 4px 2px;
    background: rgba(255, 255, 255, 0.1);
}

/* Buscador: "×" para limpiar (ver laser-sd-search-clear-btn en app.js). */
.laser-sd-search-clear-btn {
    display: none;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    cursor: pointer;
}

.laser-sd-search-clear-btn:not([hidden]) {
    display: inline-flex;
}

.laser-sd-search-clear-btn:hover {
    background: rgba(255, 255, 255, 0.16);
    color: var(--text);
}

/* Fila recién subida (ver highlightSdRecentFile en app.js) -- confirmación
   visual de "esto es lo que se acaba de mandar", pedido explícito del
   usuario para el flujo de "Enviar desde biblioteca". */
.laser-sd-row.is-recent {
    border-color: rgba(34, 197, 94, 0.6);
    background: rgba(34, 197, 94, 0.12);
    transition: background 1.8s ease, border-color 1.8s ease;
}

/* Popup "Enviar desde biblioteca" (ver #laser-sd-library-modal en index.html). */
.laser-sd-library-modal-content {
    width: min(460px, 92vw);
    max-height: 80vh;
    display: flex;
    flex-direction: column;
}

.laser-sd-library-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 320px;
    overflow-y: auto;
    margin: 4px 0 10px;
}

.laser-sd-library-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s ease;
}

.laser-sd-library-row:hover {
    background: rgba(255, 255, 255, 0.06);
}

.laser-sd-library-row input[type="checkbox"] {
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    accent-color: #22c55e;
    cursor: pointer;
}

.laser-sd-library-row-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.82rem;
    color: var(--text);
}

.laser-sd-library-progress {
    margin-bottom: 12px;
}

.laser-sd-library-progress-label {
    margin-bottom: 6px;
    font-size: 0.74rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Vista cuadrícula: mismos datos, tarjetas en vez de filas -- se pierde el
   header de columnas (no aplica a una grilla) y tamaño/modificado pasan a
   texto chico dentro de la tarjeta en vez de columnas propias. */
.laser-sd-list-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
    max-height: 480px;
}

.laser-sd-list-grid .laser-sd-row {
    grid-template-columns: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 16px 10px;
    text-align: center;
}

.laser-sd-list-grid .laser-sd-row-name-col {
    flex-direction: column;
    gap: 6px;
}

.laser-sd-list-grid .laser-sd-row-icon {
    width: 30px;
    height: 30px;
}

.laser-sd-list-grid .laser-sd-row-name {
    white-space: normal;
    text-align: center;
}

.laser-sd-list-grid .laser-sd-row-size,
.laser-sd-list-grid .laser-sd-row-modified {
    font-size: 0.66rem;
}

.laser-sd-list-grid .laser-sd-row-actions {
    justify-content: center;
}

.laser-sd-capacity-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    font-size: 0.72rem;
    color: var(--text-muted);
}

.laser-sd-capacity-count,
.laser-sd-capacity-used,
.laser-sd-capacity-pct {
    flex-shrink: 0;
    white-space: nowrap;
}

.laser-sd-capacity-track {
    flex: 1;
    min-width: 60px;
    height: 5px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.laser-sd-capacity-fill {
    height: 100%;
    border-radius: 999px;
    background: #22c55e;
    transition: width 0.2s ease;
}

.laser-settings-field {
    padding-bottom: 14px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-name-row {
    display: flex;
    gap: 8px;
    margin-top: 6px;
}

.laser-name-row input {
    flex: 1;
    min-width: 0;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    padding: 8px 12px;
    font-size: 0.9rem;
}

.laser-settings-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.laser-settings-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    max-height: 340px;
    overflow-y: auto;
    padding-right: 4px;
}

.laser-settings-item {
    background: rgba(255, 255, 255, 0.05);
    border-radius: 10px;
    padding: 8px 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.laser-settings-item-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.laser-settings-item-label {
    flex-shrink: 0;
    width: 48px;
    font-size: 0.72rem;
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-settings-item-hint {
    margin: 0;
    font-size: 0.68rem;
    line-height: 1.4;
    color: #f59e0b;
}

.laser-settings-item input {
    flex: 1;
    min-width: 0;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    padding: 5px 8px;
    font-size: 0.82rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.laser-settings-item.saved input {
    border-color: rgba(34, 197, 94, 0.6);
}

.theme-presets {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.theme-option-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px;
    border-radius: 14px;
    border: 1px solid rgba(16, 24, 40, 0.08);
    background: rgba(255, 255, 255, 0.06);
    color: var(--text);
    transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
    text-align: left;
}

.theme-option-card:hover,
.theme-option-card.active {
    transform: translateY(-2px);
    border-color: var(--accent);
    background: rgba(255, 255, 255, 0.16);
}

.theme-option-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.82rem;
    font-weight: 700;
}

.theme-option-logo {
    flex-shrink: 0;
}

.theme-option-swatches {
    display: flex;
    gap: 5px;
}

.theme-option-swatch {
    width: 16px;
    height: 16px;
    border-radius: 6px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

/* ── NOPAL Style: la tarjeta pasó de <button> a <div> para poder meter las
   miniaturas de fondo adentro sin anidar un <button> dentro de otro -- el
   div conserva data-theme/.active para que setActiveThemeCard() lo siga
   viendo igual que a las demás tarjetas. ── */
.theme-option-card-nopal { padding: 10px 12px; gap: 8px; }
.theme-option-select {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0;
    border: none;
    background: none;
    color: inherit;
    text-align: left;
    font: inherit;
    cursor: pointer;
    width: 100%;
}
.theme-option-wallpapers { display: flex; gap: 8px; margin-top: 2px; }
.theme-option-wallpaper-thumb {
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.22);
    overflow: hidden;
    cursor: pointer;
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.06);
}
.theme-option-wallpaper-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.theme-option-wallpaper-thumb:hover { border-color: rgba(34, 197, 94, 0.6); }
.theme-option-wallpaper-thumb.active { border-color: #22c55e; box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.25); }
.theme-option-wallpaper-thumb.is-missing img { display: none; }
.theme-option-wallpaper-thumb.is-missing {
    display: grid;
    place-items: center;
    border-style: dashed;
    color: rgba(255, 255, 255, 0.4);
    font-size: 1rem;
    line-height: 1;
}
.theme-option-wallpaper-thumb.is-missing::after { content: '+'; }

.theme-option-card-custom {
    padding: 0;
}

.theme-option-custom-add {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 100%;
    height: 100%;
    min-height: 52px;
    padding: 10px;
    border: 1px dashed rgba(34, 197, 94, 0.4);
    border-radius: 14px;
    background: transparent;
    color: #22c55e;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.theme-option-custom-add:hover {
    background: rgba(34, 197, 94, 0.1);
    border-color: rgba(34, 197, 94, 0.6);
}

.theme-option-custom-body {
    display: flex;
    align-items: stretch;
    gap: 6px;
    padding: 10px 12px;
}

.theme-option-custom-select {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
    border: none;
    background: transparent;
    color: var(--text);
    text-align: left;
    cursor: pointer;
}

.theme-option-custom-actions {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.theme-option-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: none;
    border-radius: 6px;
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.theme-option-icon-btn:hover {
    background: rgba(34, 197, 94, 0.22);
    color: #16a34a;
}

/* El verde brillante pensado para fondo oscuro casi no se ve sobre las
   tarjetas claras de Desert (bajo contraste, icono de recargar "invisible"
   en fichas como Impresoras Marlin/Elegoo/FlashForge/Todos los
   dispositivos). Mismo criterio que .laser-step-btn.active. */
body.light .theme-option-icon-btn {
    color: var(--accent-green-strong);
}

body.light .theme-option-icon-btn:hover {
    color: var(--text-primary);
}

.laser-scan-btn-lg {
    width: 30px;
    height: 30px;
}

.theme-option-icon-btn-danger {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
}

.theme-option-icon-btn-danger:hover {
    background: rgba(239, 68, 68, 0.22);
    color: #dc2626;
}

.theme-option-icon-btn-labeled {
    width: auto;
    height: auto;
    padding: 4px 10px;
    gap: 6px;
    font-size: 0.74rem;
    font-weight: 700;
}

.theme-option-icon-btn-orange {
    background: rgba(245, 158, 11, 0.14);
    color: #f59e0b;
}

.theme-option-icon-btn-orange:hover {
    background: rgba(245, 158, 11, 0.24);
    color: #d97706;
}

.modal-content.custom-theme-modal-content {
    width: 92%;
    max-width: 1180px;
    height: auto;
    max-height: 92vh;
    overflow-y: auto;
    padding: 32px;
    gap: 24px;
    display: flex;
    flex-direction: column;
    border-radius: 24px;
    color: var(--text);
}

.modal-content .custom-theme-close-btn {
    position: absolute;
    top: 24px;
    right: 24px;
    left: auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid rgba(239, 68, 68, 0.45);
    background: rgba(239, 68, 68, 0.1);
    color: #f87171;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease;
}

.custom-theme-close-btn:hover {
    background: rgba(239, 68, 68, 0.22);
}

.custom-theme-header {
    display: flex;
    align-items: center;
    gap: 16px;
}

.custom-theme-header-icon {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.12);
    border: 1px solid rgba(34, 197, 94, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
}

.custom-theme-header h2 {
    margin: 0 0 4px;
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #fff;
}

.custom-theme-header p {
    margin: 0;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.55);
}

.custom-theme-columns {
    display: grid;
    grid-template-columns: 1fr 1.15fr;
    gap: 20px;
    align-items: start;
}

.custom-theme-panel {
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(34, 197, 94, 0.22);
    border-radius: var(--radius-lg);
    padding: 20px;
}

.custom-theme-panel-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #4ade80;
    margin-bottom: 16px;
}

.custom-theme-color-rows {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.custom-theme-color-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.03);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-md);
}

.custom-theme-color-row-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: rgba(34, 197, 94, 0.14);
    color: #4ade80;
    display: flex;
    align-items: center;
    justify-content: center;
}

.custom-theme-color-row-label {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.custom-theme-color-row-label strong {
    font-size: 0.88rem;
    font-weight: 700;
    color: #fff;
}

.custom-theme-color-row-label small {
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.5);
}

.custom-theme-color-swatch {
    flex-shrink: 0;
    width: 44px;
    height: 32px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    background: transparent;
    cursor: pointer;
}

.custom-theme-color-edit-btn {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    background: rgba(255, 255, 255, 0.05);
    color: rgba(255, 255, 255, 0.75);
    cursor: pointer;
    transition: background 0.15s ease;
}

.custom-theme-color-edit-btn:hover {
    background: rgba(255, 255, 255, 0.1);
}

/* ── Mini dashboard de vista previa ── */

.custom-theme-preview {
    --ctp-accent: #8b5cf6;
    --ctp-surface: #1f2937;
    --ctp-text: #f8fafc;
    --ctp-muted: #94a3b8;
    background: var(--ctp-surface);
    border-radius: var(--radius-md);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    color: var(--ctp-text);
}

.ctp-topbar {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.ctp-brand {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    font-weight: 800;
    letter-spacing: 0.02em;
}

.ctp-status {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.7rem;
    color: var(--ctp-muted);
}

.ctp-status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #22c55e;
    box-shadow: 0 0 4px 1px rgba(34, 197, 94, 0.7);
}

.ctp-gauges {
    display: flex;
    gap: 10px;
    margin-left: auto;
}

.ctp-gauge {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 2px solid;
    font-size: 0.6rem;
}

.ctp-gauge span {
    font-size: 0.62rem;
    font-weight: 800;
    line-height: 1;
}

.ctp-gauge small {
    font-size: 0.42rem;
    color: var(--ctp-muted);
    text-transform: uppercase;
}

.ctp-gauge-cpu { border-color: #22c55e; }
.ctp-gauge-mem { border-color: #f59e0b; }
.ctp-gauge-temp { border-color: #ef4444; }

.ctp-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}

.ctp-stat {
    background: rgba(0, 0, 0, 0.2);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    padding: 8px 10px;
}

.ctp-stat span {
    display: block;
    font-size: 0.5rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    margin-bottom: 3px;
}

.ctp-stat strong {
    font-size: 1rem;
    font-weight: 800;
    color: var(--ctp-text);
}

.ctp-stat small {
    display: block;
    font-size: 0.5rem;
    color: var(--ctp-muted);
}

.ctp-stat-green { border-color: rgba(34, 197, 94, 0.35); }
.ctp-stat-green span { color: #4ade80; }
.ctp-stat-orange { background: linear-gradient(160deg, rgba(217, 119, 6, 0.4) 0%, rgba(120, 53, 15, 0.35) 100%); border-color: rgba(217, 119, 6, 0.4); }
.ctp-stat-orange span { color: #fed7aa; }
.ctp-stat-purple { border-color: rgba(168, 85, 247, 0.35); }
.ctp-stat-purple span { color: #c4b5fd; }

.ctp-devices {
    display: flex;
    gap: 10px;
}

.ctp-device {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(0, 0, 0, 0.2);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    padding: 8px 10px;
}

.ctp-device-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.06);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
}

.ctp-device-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.ctp-device-info strong {
    font-size: 0.72rem;
    font-weight: 700;
}

.ctp-device-info span {
    font-size: 0.6rem;
    color: var(--ctp-muted);
}

.ctp-device-state {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.6rem;
    color: var(--ctp-muted);
    flex-shrink: 0;
}

.ctp-device-temps {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 0.58rem;
    color: var(--ctp-muted);
    flex-shrink: 0;
}

.ctp-device-temps b {
    color: var(--ctp-text);
}

.ctp-device-temps b.ctp-warm {
    color: #f59e0b;
}

.ctp-actions {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}

.ctp-action {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 8px 4px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.6rem;
    font-weight: 700;
    cursor: default;
}

.ctp-action-pause {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.4);
    color: #4ade80;
}

.ctp-action-stop {
    background: rgba(239, 68, 68, 0.18);
    border-color: rgba(239, 68, 68, 0.4);
    color: #f87171;
}

/* ── Fondo del dashboard ── */

.custom-theme-bg-columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

.custom-theme-bg-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 24px;
    border: 2px dashed rgba(34, 197, 94, 0.35);
    border-radius: var(--radius-md);
    color: #4ade80;
    text-align: center;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.custom-theme-bg-dropzone:hover,
.custom-theme-bg-dropzone.dragover {
    background: rgba(34, 197, 94, 0.06);
    border-color: rgba(34, 197, 94, 0.6);
}

/* Arrastrar archivos desde el explorador y soltarlos sobre toda la tarjeta
   de una biblioteca (Impresión 3D / Archivos) -- outline en vez de border
   para no correr el layout del toolbar/tabla que ya vive adentro. */
.library-dropzone-active {
    outline: 2px dashed var(--accent);
    outline-offset: -2px;
    background: rgba(var(--accent-rgb), 0.05);
}

.custom-theme-bg-dropzone strong {
    font-size: 0.9rem;
    color: #fff;
}

.custom-theme-bg-dropzone span {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.6);
}

.custom-theme-bg-dropzone small {
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.4);
}

.custom-theme-bg-preview {
    position: relative;
    min-height: 120px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: rgba(255, 255, 255, 0.03);
    background-image: url('../img/motif-circuit.svg');
    background-size: 200px 200px;
    border: 1px solid rgba(34, 197, 94, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
}

.custom-theme-bg-preview-placeholder {
    opacity: 0.7;
}

.custom-theme-bg-preview img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.custom-theme-bg-actions {
    display: flex;
    gap: 10px;
    margin-top: 14px;
}

.custom-theme-bg-change-btn,
.custom-theme-bg-remove-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex: 1;
    padding: 10px;
    border-radius: var(--radius-md);
    font-size: 0.78rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s ease;
}

.custom-theme-bg-change-btn {
    background: rgba(34, 197, 94, 0.14);
    border: 1px solid rgba(34, 197, 94, 0.35);
    color: #4ade80;
}

.custom-theme-bg-change-btn:hover {
    background: rgba(34, 197, 94, 0.24);
}

.custom-theme-bg-remove-btn {
    background: rgba(239, 68, 68, 0.14);
    border: 1px solid rgba(239, 68, 68, 0.35);
    color: #f87171;
}

.custom-theme-bg-remove-btn:hover {
    background: rgba(239, 68, 68, 0.24);
}

/* ── Footer ── */

.custom-theme-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.custom-theme-footer-right {
    display: flex;
    gap: 12px;
}

.custom-theme-reset-btn,
.custom-theme-cancel-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px 20px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.12);
    background: rgba(255, 255, 255, 0.04);
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s ease;
}

.custom-theme-reset-btn:hover,
.custom-theme-cancel-btn:hover {
    background: rgba(255, 255, 255, 0.09);
}

.btn-file-action.custom-theme-save-btn {
    justify-content: center;
    padding: 12px 24px;
    border-radius: var(--radius-md);
    background: #22c55e;
    border: 1px solid #22c55e;
    color: #052e12;
    font-weight: 700;
}

.btn-file-action.custom-theme-save-btn:hover {
    background: #16a34a;
}

@media (max-width: 900px) {
    .custom-theme-columns,
    .custom-theme-bg-columns {
        grid-template-columns: 1fr;
    }

    .ctp-stats,
    .ctp-actions {
        grid-template-columns: repeat(2, 1fr);
    }
}

.modal-content.move-file-modal-content {
    width: 90%;
    max-width: 420px;
    height: auto;
    max-height: 70vh;
    padding: 28px;
    gap: 16px;
    display: flex;
    flex-direction: column;
}

.move-file-modal-content h2 {
    margin: 0;
    font-size: 1.15rem;
}

.move-file-current-name {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.88rem;
}

.move-file-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    padding: 8px 10px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.05);
}

.move-file-folder-list {
    flex: 1;
    min-height: 120px;
    max-height: 260px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-right: 4px;
}

.move-file-folder-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text);
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease;
}

.move-file-folder-row:hover {
    background: rgba(34, 197, 94, 0.14);
}

.move-file-folder-row .folder-icon {
    color: #22c55e;
    flex-shrink: 0;
}

.move-file-confirm-btn {
    justify-content: center;
}

.modal-content.app-confirm-modal-content {
    width: 90%;
    max-width: 400px;
    height: auto;
    max-height: none;
    padding: 28px;
    gap: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.app-confirm-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    margin-bottom: 6px;
    color: var(--green-dark);
    background: rgba(34, 197, 94, 0.14);
}

.app-confirm-icon:empty {
    display: none;
}

/* ── Ícono reutilizable para encabezados de modal (fuera de app-confirm) ── */

.modal-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    flex-shrink: 0;
}

.modal-icon-purple {
    color: #8b5cf6;
    background: rgba(139, 92, 246, 0.16);
}

.modal-icon-blue {
    color: #60a5fa;
    background: rgba(96, 165, 250, 0.16);
}

.modal-icon-orange {
    color: #f59e0b;
    background: rgba(245, 158, 11, 0.16);
}

.modal-icon-green {
    color: #22c55e;
    background: rgba(34, 197, 94, 0.16);
}

.modal-title-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 4px;
}

.modal-title-row h2 {
    margin: 0;
}

.app-confirm-modal-content .modal-icon {
    margin-bottom: 6px;
}

.app-confirm-modal-content h2 {
    margin: 0 0 4px;
    font-size: 1.15rem;
    color: var(--text);
}

.app-confirm-modal-content p {
    margin: 0 0 20px;
    color: var(--text-muted);
    font-size: 0.9rem;
    line-height: 1.5;
}

.app-confirm-actions {
    display: flex;
    justify-content: center;
    gap: 10px;
    width: 100%;
}

.app-confirm-actions .btn-file-action {
    flex: 1;
    justify-content: center;
}

/* ── Modal de logs del sistema (Configuración) ── */

.modal-content.system-logs-modal-content {
    width: 92%;
    max-width: 760px;
    height: auto;
    max-height: 88vh;
    padding: 28px;
    gap: 14px;
    display: flex;
    flex-direction: column;
}

.system-logs-modal-content p {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.85rem;
    line-height: 1.5;
}

.system-logs-modal-content .settings-field {
    margin-bottom: 0;
}

.system-logs-modal-content .console-log {
    flex: 1;
    height: auto;
    min-height: 260px;
}

/* ── Modal "Control del sistema" (servicios systemd + host): mismo lenguaje
   visual verde/glass oscuro que ya usan la Galería de plugins (.plugin-card,
   línea ~4566) y las fichas de Ayuda (#help-modules-groups .help-card, línea
   ~9946) — elegido a pedido explícito del usuario en vez del modal decorado
   con mascotas (cactus1/cactus2.png) que usa "Enviar a impresora". El fondo
   queda vidrio oscuro fijo sin importar el tema activo, así que el texto
   (título, nombres de servicio, subtítulos) se fija a un tono claro fijo acá
   en vez de var(--text) — mismo criterio que #help-modules-groups .help-card
   .card-header-std-title (línea ~9973), si no en tema claro quedaría casi
   invisible sobre este fondo oscuro. ── */

.modal-content.system-control-modal-content {
    width: 92%;
    max-width: 640px;
    height: auto;
    max-height: 88vh;
    padding: 28px;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    background: color-mix(in srgb, var(--card-bg) 72%, transparent);
    border: 1px solid rgba(148, 163, 184, 0.17);
    border-radius: 15px;
    box-shadow: none;
}

.system-control-modal-content .card-header-std {
    margin-bottom: 6px;
}

.system-control-modal-content .card-header-std-title {
    color: #fff;
}

.system-control-modal-content .card-header-std-icon {
    display: grid;
    width: 46px;
    height: 46px;
    place-items: center;
    border: 1px solid color-mix(in srgb, var(--green) 45%, transparent);
    border-radius: 12px;
    background: color-mix(in srgb, var(--green) 15%, transparent);
    color: var(--green);
    flex-shrink: 0;
}

.system-control-subtitle {
    margin: 0 0 18px;
    color: rgba(255, 255, 255, 0.72);
    font-size: 0.85rem;
    line-height: 1.5;
}

.system-control-section + .system-control-section {
    margin-top: 22px;
}

.system-control-section-title {
    margin: 0 0 12px;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.55);
}

.system-control-services-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.system-control-empty {
    margin: 0;
    padding: 16px 0;
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.85rem;
    text-align: center;
}

.system-control-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid rgba(148, 163, 184, 0.17);
    border-radius: 12px;
    background: rgba(148, 163, 184, 0.06);
}

.system-control-status-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: rgba(148, 163, 184, 0.55);
    flex-shrink: 0;
}

/* Verde/rojo fijos (no ligados al tema) por lo mismo que .btn-file-action-danger
   más abajo: son colores semánticos de estado systemd (activo/con error), no
   decoración que deba seguir el acento del tema. */
.system-control-status-dot.is-active {
    background: var(--green);
    box-shadow: 0 0 8px color-mix(in srgb, var(--green) 60%, transparent);
}

.system-control-status-dot.is-failed {
    background: #ef4444;
    box-shadow: 0 0 8px rgba(239, 68, 68, 0.5);
}

.system-control-row-name {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.system-control-row-name strong {
    font-size: 0.86rem;
    font-weight: 600;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.system-control-row-name small {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.5);
    text-transform: capitalize;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.system-control-icon-btn {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 1px solid rgba(148, 163, 184, 0.25);
    border-radius: 8px;
    background: rgba(148, 163, 184, 0.08);
    color: rgba(255, 255, 255, 0.8);
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.system-control-icon-btn:hover {
    background: color-mix(in srgb, var(--green) 20%, transparent);
    border-color: color-mix(in srgb, var(--green) 45%, transparent);
    color: var(--green);
}

.system-control-icon-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Toggle pill — mismo patrón que .aa-switch del plugin de accesorios Arduino
   (arduino-accessories.css), copiado con su propio nombre de clase para no
   depender del CSS de un plugin desde el núcleo de la app. */
.system-control-switch {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
    flex-shrink: 0;
}

.system-control-switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.system-control-switch span {
    position: absolute;
    inset: 0;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.35);
    transition: background 0.15s ease;
}

.system-control-switch span::before {
    content: '';
    position: absolute;
    width: 16px;
    height: 16px;
    left: 3px;
    top: 3px;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.15s ease;
}

.system-control-switch input:checked + span {
    background: var(--green);
}

.system-control-switch input:checked + span::before {
    transform: translateX(18px);
}

.system-control-switch input:disabled + span {
    opacity: 0.5;
    cursor: not-allowed;
}

.system-control-host-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.system-control-host-actions .btn-file-action {
    flex: 1;
    justify-content: center;
    min-width: 160px;
}

/* ── Tipos semánticos (ícono + acento de color) ── */

.app-confirm-type-danger .app-confirm-icon {
    color: #f87171;
    background: rgba(248, 113, 113, 0.16);
}

.app-confirm-type-danger h2 {
    color: #f87171;
}

.app-confirm-type-danger #app-confirm-ok-btn {
    background: #f87171;
    border-color: #f87171;
    color: #fff;
}

.app-confirm-type-warning .app-confirm-icon {
    color: #f59e0b;
    background: rgba(245, 158, 11, 0.16);
}

.app-confirm-type-warning h2 {
    color: #f59e0b;
}

.app-confirm-type-warning #app-confirm-ok-btn {
    background: #f59e0b;
    border-color: #f59e0b;
    color: #fff;
}

.app-confirm-type-success .app-confirm-icon {
    color: #22c55e;
    background: rgba(34, 197, 94, 0.16);
}

.app-confirm-type-success #app-confirm-ok-btn {
    background: #22c55e;
    border-color: #22c55e;
    color: #fff;
}

.app-confirm-type-info .app-confirm-icon {
    color: #60a5fa;
    background: rgba(96, 165, 250, 0.16);
}

.app-confirm-type-info #app-confirm-ok-btn {
    background: #60a5fa;
    border-color: #60a5fa;
    color: #fff;
}

.laser-start-confirm-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.laser-start-confirm-actions .btn-file-action {
    justify-content: center;
}

.laser-start-confirm-copies {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.laser-start-confirm-copies label {
    font-size: 0.88rem;
    color: var(--text-muted);
}

.laser-start-confirm-copies input {
    width: 70px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--surface);
    color: var(--text);
    font-size: 0.9rem;
    text-align: center;
}

body.dark .laser-start-confirm-copies input,
body.green .laser-start-confirm-copies input {
    border-color: rgba(255, 255, 255, 0.1);
}

.laser-start-confirm-row {
    display: flex;
    gap: 10px;
}

.laser-start-confirm-row .btn-file-action {
    flex: 1;
}

.modal-content.printer-send-modal-content {
    width: 94%;
    max-width: 820px;
    height: auto;
    max-height: 92vh;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 32px 108px;
    display: block;
    border-radius: 24px;
    color: var(--text);
}

.printer-send-close-btn {
    z-index: 3;
}

.modal-content .printer-send-cactus {
    position: absolute;
    bottom: 8px;
    top: auto;
    width: 96px;
    height: auto;
    opacity: 0.5;
    filter: drop-shadow(0 0 22px rgba(34, 197, 94, 0.35));
    pointer-events: none;
    z-index: 0;
}

.printer-send-cactus-left {
    left: 12px;
}

.printer-send-cactus-right {
    right: 12px;
}

.printer-send-body {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.printer-send-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 8px;
}

.printer-send-hexagon-icon {
    width: 52px;
    height: 52px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.12);
    border: 1px solid rgba(34, 197, 94, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
}

.printer-send-title-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.printer-send-title-row h2 {
    margin: 0;
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
}

.printer-send-title-white {
    color: #fff;
}

.printer-send-title-green {
    color: #22c55e;
}

.printer-send-title-trace {
    opacity: 0.55;
    flex-shrink: 0;
}

.printer-send-subtitle {
    margin: 0;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.55);
}

.printer-send-file-card {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(34, 197, 94, 0.25);
    border-radius: var(--radius-md);
}

.printer-send-file-icon {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.4);
    background: rgba(34, 197, 94, 0.08);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    color: #22c55e;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.printer-send-file-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.printer-send-file-name {
    font-weight: 700;
    font-size: 0.95rem;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.printer-send-file-details {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.5);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.printer-send-file-thumb {
    flex-shrink: 0;
    width: 64px;
    height: 64px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(0, 0, 0, 0.25);
    overflow: hidden;
    position: relative;
}

.printer-send-file-thumb canvas {
    width: 100% !important;
    height: 100% !important;
}

.printer-send-file-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.printer-send-picker {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 220px;
    overflow-y: auto;
}

.printer-send-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.03);
    color: #fff;
    cursor: pointer;
    text-align: left;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.printer-send-row:hover {
    border-color: rgba(34, 197, 94, 0.4);
}

.printer-send-row.active {
    background: rgba(34, 197, 94, 0.12);
    border-color: rgba(34, 197, 94, 0.55);
}

.printer-send-row.offline {
    opacity: 0.6;
}

.printer-send-row-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.35);
    background: rgba(34, 197, 94, 0.1);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #22c55e;
}

.printer-send-row-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.printer-send-row-name {
    font-weight: 700;
    font-size: 0.88rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.printer-send-row-status {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.74rem;
    color: rgba(255, 255, 255, 0.5);
}

.printer-send-row-status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.printer-send-row.offline .printer-send-row-status {
    color: rgba(255, 255, 255, 0.35);
}

.printer-send-row:not(.offline) .printer-send-row-status {
    color: #22c55e;
}

.printer-send-row.busy .printer-send-row-status {
    color: #f59e0b;
}

.printer-send-row.busy {
    border-color: rgba(245, 158, 11, 0.4);
}

.printer-send-row.busy.active {
    background: rgba(245, 158, 11, 0.1);
    border-color: rgba(245, 158, 11, 0.5);
}

.printer-send-busy-warning {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    margin-bottom: 12px;
    border-radius: var(--radius-md);
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.35);
    color: #fbbf24;
    font-size: 0.8rem;
    line-height: 1.4;
    text-align: left;
}

.printer-send-busy-warning svg {
    flex-shrink: 0;
    margin-top: 1px;
}

.printer-send-row-pill {
    flex-shrink: 0;
    padding: 3px 8px;
    border-radius: 999px;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid rgba(34, 197, 94, 0.4);
    background: rgba(34, 197, 94, 0.14);
    color: #22c55e;
}

.printer-send-row.offline .printer-send-row-pill {
    border-color: rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.45);
}

.printer-send-row-radio {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
}

.printer-send-row.active .printer-send-row-radio {
    border-color: #22c55e;
}

.printer-send-row-radio-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #22c55e;
    opacity: 0;
    transform: scale(0.4);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.printer-send-row.active .printer-send-row-radio-dot {
    opacity: 1;
    transform: scale(1);
}

.printer-send-modes {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.printer-send-mode-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.03);
    color: rgba(255, 255, 255, 0.8);
    cursor: pointer;
    text-align: left;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.printer-send-mode-card svg {
    color: #22c55e;
}

.printer-send-mode-card:hover {
    border-color: rgba(34, 197, 94, 0.4);
}

.printer-send-mode-card.active {
    background: rgba(34, 197, 94, 0.12);
    border-color: rgba(34, 197, 94, 0.55);
}

.printer-send-mode-title {
    font-size: 0.82rem;
    font-weight: 700;
    color: #fff;
}

.printer-send-mode-desc {
    font-size: 0.72rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.5);
}

.printer-send-mode-card.disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.printer-send-mode-card.disabled:hover {
    border-color: rgba(255, 255, 255, 0.1);
}

.printer-send-mode-unavailable {
    font-size: 0.7rem;
    font-weight: 700;
    color: #f59e0b;
}

.printer-send-schedule-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.printer-send-schedule-field label {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.6);
}

.printer-send-schedule-field input {
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.35);
    background: rgba(255, 255, 255, 0.05);
    color: #fff;
    font-size: 0.85rem;
    color-scheme: dark;
}

.printer-send-divider {
    position: relative;
    height: 1px;
    background: rgba(255, 255, 255, 0.12);
    display: flex;
    align-items: center;
    justify-content: center;
}

.printer-send-divider-icon {
    position: absolute;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--card-bg);
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
}

.printer-send-footer {
    margin: 0;
}

.printer-send-primary-btn {
    background: linear-gradient(90deg, #16a34a, #22c55e);
    border: none;
    color: #fff;
    font-weight: 700;
}

.printer-send-primary-btn:hover {
    background: linear-gradient(90deg, #15803d, #16a34a);
    color: #fff;
}

.printer-send-primary-btn:disabled {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.4);
    cursor: not-allowed;
    opacity: 0.7;
}

@media (max-width: 820px) {
    .modal-content.printer-send-modal-content {
        padding: 32px 56px;
    }
    .printer-send-cactus {
        width: 64px;
    }
}

@media (max-width: 560px) {
    .printer-send-modes {
        grid-template-columns: 1fr;
    }
    .printer-send-cactus {
        display: none;
    }
    .modal-content.printer-send-modal-content {
        padding: 24px;
    }
}

.laser-queue-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 200px;
    overflow-y: auto;
}

.cnc-queue-list {
    max-height: 110px;
    overflow-y: auto;
}

.laser-queue-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius-md);
}

.laser-queue-item-name {
    flex: 1;
    min-width: 0;
    color: var(--text);
    font-size: 0.88rem;
    word-break: break-word;
}

.laser-queue-item-thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

.laser-queue-item-thumb img,
.laser-queue-item-thumb svg {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.printer-queue-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.printer-queue-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.printer-queue-item-drag {
    display: flex;
    flex-shrink: 0;
    color: rgba(255, 255, 255, 0.3);
}

.printer-queue-item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.printer-queue-item-name {
    color: var(--text);
    font-size: 0.88rem;
    word-break: break-word;
}

.printer-queue-item-state {
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.45);
}

.printer-queue-active-card {
    margin-bottom: 12px;
}

.printer-queue-active-progress {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
}

.printer-queue-active-progress-bar {
    flex: 1;
    height: 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.printer-queue-active-progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #22c55e, #4ade80);
    border-radius: 999px;
}

.printer-queue-active-progress-pct {
    font-size: 0.78rem;
    font-weight: 700;
    color: #4ade80;
    flex-shrink: 0;
    width: 38px;
}

.printer-queue-summary {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}

.printer-queue-summary > div {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.printer-queue-summary span {
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.45);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.printer-queue-summary strong {
    font-size: 0.86rem;
    color: var(--text);
}

.laser-queue-item-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

.gcode-preview-card {
    background-color: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: var(--radius-lg);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    box-shadow: 0 24px 80px rgba(0,0,0,0.08);
    padding: 24px;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}
.preview-card-header h2 {
    margin: 0;
    font-size: 1.35rem;
}
.preview-card-header p {
    margin: 8px 0 0;
    color: var(--text-muted);
}
.preview-details-panel {
    display: grid;
    gap: 20px;
}
.preview-title-row h3 {
    margin: 0;
    font-size: 1.2rem;
}
.preview-title-row p {
    margin: 8px 0 0;
    color: var(--text-muted);
}
.preview-meta-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}
.preview-meta-grid div {
    background: var(--panel-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
}
.preview-meta-grid span {
    display: block;
    color: var(--text-muted);
    font-size: 0.7rem;
}
.preview-meta-grid strong {
    display: block;
    margin-top: 2px;
    font-size: 0.92rem;
    color: var(--text);
}
.preview-file-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.btn-file-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(34, 197, 94, 0.1);
    color: #22c55e;
    font-size: 0.88rem;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-file-action svg {
    flex-shrink: 0;
}
.btn-file-action:hover {
    background: rgba(34, 197, 94, 0.2);
    border-color: rgba(34, 197, 94, 0.5);
    color: #16a34a;
}
.btn-file-action-danger {
    border-color: rgba(239, 68, 68, 0.3);
    background: rgba(239, 68, 68, 0.1);
    color: #ef4444;
}
.btn-file-action-danger:hover {
    background: rgba(239, 68, 68, 0.2);
    border-color: rgba(239, 68, 68, 0.5);
    color: #dc2626;
}
.btn-file-action-accent {
    border-color: rgba(139, 92, 246, 0.3);
    background: rgba(139, 92, 246, 0.1);
    color: #8b5cf6;
}
.btn-file-action-accent:hover {
    background: rgba(139, 92, 246, 0.2);
    border-color: rgba(139, 92, 246, 0.5);
    color: #7c3aed;
}
/* Convención de color de botones de popup: verde = confirmar/proceder,
   naranja = decisión/alternativa secundaria, rojo = cancelar. */
.btn-file-action-decision {
    border-color: rgba(245, 158, 11, 0.3);
    background: rgba(245, 158, 11, 0.1);
    color: #f59e0b;
}
.btn-file-action-decision:hover {
    background: rgba(245, 158, 11, 0.2);
    border-color: rgba(245, 158, 11, 0.5);
    color: #d97706;
}

.gcode-preview-scene {
    flex: 1;
    min-height: 200px;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: #081410;
    border: 1px solid rgba(34, 197, 94, 0.15);
    position: relative;
}
.gcode-preview-scene .preview-image-placeholder {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.4);
    font-size: 1rem;
    padding: 1.5rem;
    text-align: center;
}
.gcode-preview-scene canvas {
    width: 100% !important;
    height: 100% !important;
    display: block;
}

.settings-select {
    width: 100%;
    padding: 12px 14px;
    border-radius: 14px;
    border: 1px solid rgba(0,0,0,0.08);
    background: var(--bg);
    color: var(--text);
}

.theme-config-card {
    display: grid;
    gap: 10px;
    align-content: start;
}

.settings-switch {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.settings-field {
    margin-bottom: 18px;
}

.settings-field:last-child {
    margin-bottom: 0;
}

.sidebar-order-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

.sidebar-order-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.03);
}

/* Un tinte blanco al 3% es un highlight sutil válido sobre tarjetas
   oscuras, pero sobre el fondo claro de Desert es blanco-sobre-blanco,
   invisible. Estas filas usan --black (el ladrillo/terracota del tema)
   como tinte, con el mismo criterio cálido del resto de Desert. */
body.light .sidebar-order-row {
    background: color-mix(in srgb, var(--black) 10%, transparent);
    border-color: color-mix(in srgb, var(--black) 22%, transparent);
}

body.light .sidebar-order-select {
    background: color-mix(in srgb, var(--black) 8%, transparent);
    border-color: color-mix(in srgb, var(--black) 22%, transparent);
}

.sidebar-order-row-label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.85rem;
    color: var(--text);
}

.sidebar-order-row-label svg {
    color: var(--green-dark);
    flex-shrink: 0;
}

.sidebar-order-select {
    width: 56px;
    padding: 4px 6px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 0.8rem;
    font-weight: 700;
    text-align: center;
}

.settings-uiux-subfield {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.laser-marker-shape-options {
    display: flex;
    gap: 8px;
    margin-top: 10px;
}

.laser-marker-shape-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.03);
    color: var(--text-muted);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.laser-marker-shape-btn:hover {
    color: var(--text);
}

.laser-marker-shape-btn.active {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.4);
    color: var(--green-dark);
}

.laser-marker-color-options {
    display: flex;
    gap: 10px;
    margin-top: 12px;
}

.laser-marker-color-btn {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid transparent;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
    cursor: pointer;
    padding: 0;
    transition: transform 0.15s ease, border-color 0.15s ease;
}

.laser-marker-color-btn:hover {
    transform: scale(1.1);
}

.laser-marker-color-btn.active {
    border-color: var(--text);
    transform: scale(1.12);
}

.laser-marker-settings-row {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-top: 10px;
}

.laser-marker-controls {
    flex: 1;
    min-width: 0;
}

.laser-marker-controls .laser-marker-shape-options,
.laser-marker-controls .laser-marker-color-options {
    margin-top: 0;
}

.laser-marker-controls .laser-marker-color-options {
    margin-top: 12px;
}

.laser-marker-preview {
    position: relative;
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(255, 255, 255, 0.03);
    background-image:
        repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.1) 0, rgba(255, 255, 255, 0.1) 1px, transparent 1px, transparent 33%),
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 0, rgba(255, 255, 255, 0.1) 1px, transparent 1px, transparent 33%);
    border: 1px solid rgba(255, 255, 255, 0.12);
}

.laser-marker-preview-dot {
    --laser-marker-color: #22c55e;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--laser-marker-color);
    box-shadow: 0 0 6px 2px color-mix(in srgb, var(--laser-marker-color) 55%, transparent);
}

.laser-marker-preview-dot.shape-cross {
    width: 16px;
    height: 16px;
    background: transparent;
    border-radius: 0;
    box-shadow: none;
    position: relative;
}

.laser-marker-preview-dot.shape-cross::before,
.laser-marker-preview-dot.shape-cross::after {
    content: '';
    position: absolute;
    background: var(--laser-marker-color);
    box-shadow: 0 0 4px 1px color-mix(in srgb, var(--laser-marker-color) 55%, transparent);
}

.laser-marker-preview-dot.shape-cross::before {
    left: 50%;
    top: 0;
    bottom: 0;
    width: 2px;
    transform: translateX(-50%);
}

.laser-marker-preview-dot.shape-cross::after {
    top: 50%;
    left: 0;
    right: 0;
    height: 2px;
    transform: translateY(-50%);
}

.settings-field-switch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.settings-field-label {
    display: block;
    font-weight: 600;
    color: var(--text);
    font-size: 0.92rem;
    margin-bottom: 4px;
}

.settings-field-switch .settings-field-label {
    margin-bottom: 0;
}

.settings-field-hint {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.8rem;
    line-height: 1.5;
}

.updates-status-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
}

.updates-version {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-weight: 700;
    color: var(--text);
}

/* ── Centro de ayuda: sidebar de categorías + buscador a la izquierda,
   panel de tarjetas grandes a la derecha (ver renderHelpCenter() en app.js
   -- reemplaza el layout viejo de tarjetas personalizables por arrastre).
   Grid de 2 columnas en escritorio, colapsa a 1 columna (sidebar arriba)
   en pantallas angostas. ── */
.help-center-layout {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 24px;
    align-items: start;
}

@media (max-width: 860px) {
    .help-center-layout {
        grid-template-columns: 1fr;
    }
}

.help-sidebar {
    display: flex;
    flex-direction: column;
    gap: 16px;
    position: sticky;
    top: 0;
}

@media (max-width: 860px) {
    .help-sidebar {
        position: static;
    }
}

.help-sidebar-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text-muted);
}

.help-sidebar-search input {
    flex: 1;
    min-width: 0;
    border: none;
    background: transparent;
    color: var(--text);
    font-size: 0.9rem;
    outline: none;
}

.help-category-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.help-category-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    min-height: 44px;
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    background: none;
    color: var(--text-secondary);
    text-align: left;
    cursor: pointer;
    transition: background 140ms ease, border-color 140ms ease;
}

.help-category-item:hover {
    background: var(--card-bg);
}

.help-category-item.active {
    background: rgba(var(--accent-rgb), 0.12);
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
    color: var(--text);
}

.help-category-item-icon {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    color: var(--accent);
}

.help-category-item.coming-soon .help-category-item-icon {
    color: var(--text-muted);
}

.help-category-item-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.help-category-item-title {
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text);
}

.help-category-item-sub {
    font-size: 0.76rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.help-community-box {
    padding: 14px;
    border-radius: var(--radius-md);
    background: var(--card-bg);
    border: 1px solid var(--border);
}

.help-community-title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    margin: 0 0 6px;
}

.help-community-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.82rem;
    color: var(--accent);
    text-decoration: none;
}

.help-community-link:hover {
    text-decoration: underline;
}

.help-panel {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.help-panel-empty {
    color: var(--text-muted);
    padding: 24px 0;
}

/* Tarjeta grande por categoría -- misma apariencia "vidrio oscuro fijo" que
   .plugin-card de la Galería de plugins (línea ~4550), independiente del
   tema (mismo criterio que .laser-card-accent, línea ~6034). */
.help-feature-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 20px;
    background: color-mix(in srgb, var(--card-bg) 72%, transparent);
    border: 1px solid rgba(148, 163, 184, 0.17);
    border-radius: 15px;
    transition: transform 160ms ease, border-color 160ms ease, background 160ms ease;
}

.help-feature-card:hover {
    transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--green) 55%, transparent);
    background: rgba(20, 30, 50, 0.88);
}

.help-feature-card-coming-soon {
    opacity: 0.7;
}

.help-feature-card-top {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.help-feature-card-icon {
    display: grid;
    width: 46px;
    height: 46px;
    flex-shrink: 0;
    place-items: center;
    border: 1px solid color-mix(in srgb, var(--green) 45%, transparent);
    border-radius: 50%;
    background: color-mix(in srgb, var(--green) 15%, transparent);
    color: var(--green);
}

.help-feature-card-heading h2 {
    margin: 0 0 4px;
    font-size: 1.02rem;
    color: #fff;
}

.help-feature-card-heading p {
    margin: 0;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.75);
}

.help-feature-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.help-tag-pill {
    padding: 4px 10px;
    font-size: 0.72rem;
}

.help-feature-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 4px;
}

.help-about-row {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.help-version-badge {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.78rem;
    font-weight: 700;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(34, 197, 94, 0.14);
    color: var(--green-dark);
}

.updates-status-pill-wrap {
    position: relative;
    display: inline-flex;
}

.settings-card.updates-tooltip-open {
    position: relative;
    z-index: 100;
}

.updates-status-pill {
    font-size: 0.75rem;
    font-weight: 700;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
    cursor: default;
}

.updates-status-pill.available {
    cursor: help;
}

.updates-pill-tooltip {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 110;
    min-width: 220px;
    max-width: 300px;
    background: var(--card-bg);
    color: var(--text);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-radius: var(--radius-md);
    padding: 12px 14px;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.28);
}

.updates-status-pill-wrap.show-tooltip .updates-pill-tooltip {
    display: block;
}

.updates-pill-tooltip-title {
    font-size: 0.72rem;
    font-weight: 700;
    color: #f59e0b;
    margin-bottom: 8px;
}

.updates-pill-tooltip ul {
    margin: 0;
    padding-left: 16px;
    display: grid;
    gap: 4px;
}

.updates-pill-tooltip li {
    font-size: 0.76rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    color: var(--text);
}

.updates-status-pill.current {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.updates-status-pill.available {
    background: rgba(245, 158, 11, 0.16);
    color: #f59e0b;
}

.updates-status-pill.unknown,
.updates-status-pill.checking {
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
}

.updates-meta {
    margin: 0 0 16px;
    color: var(--text-muted);
    font-size: 0.78rem;
}

.updates-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.updates-changelog {
    margin-top: 14px;
    padding: 12px 14px;
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.25);
    border-radius: var(--radius-md);
}

.updates-changelog-title {
    font-size: 0.8rem;
    font-weight: 700;
    color: #22c55e;
    margin-bottom: 8px;
}

.updates-changelog ul {
    margin: 0;
    padding-left: 18px;
    display: grid;
    gap: 4px;
}

.updates-changelog li {
    font-size: 0.8rem;
    color: var(--text);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

/* ── Acerca de NOPAL (versión + diagnóstico) ── */
.about-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px 16px;
    margin-bottom: 16px;
}
.about-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.about-field-label { font-size: 0.76rem; color: var(--text-muted); }
.about-field-value {
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--text-strong);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.about-plugins { margin-bottom: 16px; }
.about-plugins-title {
    margin: 0 0 8px;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.about-plugins-list { display: flex; flex-direction: column; gap: 2px; }
.about-plugin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.85rem;
}
.about-plugin-row:last-child { border-bottom: none; }
.about-plugin-name { color: var(--text); }
.about-plugin-version {
    color: var(--text-muted);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.8rem;
}

.update-safety-modal {
    position: fixed;
    inset: 0;
    z-index: 10050;
    display: grid;
    place-items: center;
    padding: 24px;
    background:
        radial-gradient(circle at 50% 35%, rgba(245, 158, 11, 0.12), transparent 38%),
        rgba(2, 6, 14, 0.9);
    backdrop-filter: blur(16px);
}

.update-safety-modal[hidden] {
    display: none;
}

.update-safety-dialog {
    width: min(720px, 100%);
    padding: clamp(24px, 4vw, 42px);
    border: 1px solid rgba(245, 158, 11, 0.55);
    border-radius: 24px;
    background: linear-gradient(145deg, color-mix(in srgb, var(--card-bg) 95%, #f59e0b 5%), var(--card-bg));
    color: var(--text);
    box-shadow: 0 28px 80px rgba(0, 0, 0, 0.55), 0 0 60px rgba(245, 158, 11, 0.08);
}

.update-safety-icon {
    width: 72px;
    height: 72px;
    display: grid;
    place-items: center;
    margin-bottom: 20px;
    border: 1px solid rgba(245, 158, 11, 0.55);
    border-radius: 20px;
    background: rgba(245, 158, 11, 0.12);
    color: #f59e0b;
}

.update-safety-eyebrow {
    margin-bottom: 8px;
    color: #f59e0b;
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.14em;
}

.update-safety-dialog h2 {
    margin: 0;
    font-size: clamp(1.55rem, 3vw, 2.25rem);
    line-height: 1.1;
}

.update-safety-intro {
    margin: 14px 0 22px;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1.6;
}

.update-safety-checks {
    display: grid;
    gap: 10px;
}

.update-safety-checks > div {
    display: grid;
    grid-template-columns: 38px 1fr;
    align-items: center;
    gap: 12px;
    min-height: 58px;
    padding: 10px 14px;
    border: 1px solid color-mix(in srgb, var(--border) 76%, #f59e0b 24%);
    border-radius: 14px;
    background: color-mix(in srgb, var(--card-bg) 88%, transparent);
}

.update-safety-checks span {
    color: #f59e0b;
    font-family: 'SFMono-Regular', Consolas, monospace;
    font-size: 0.78rem;
}

.update-safety-checks strong {
    font-size: 0.94rem;
    line-height: 1.4;
}

.update-safety-confirmation {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-top: 20px;
    padding: 16px;
    border-radius: 14px;
    background: rgba(239, 68, 68, 0.1);
    color: var(--text);
    cursor: pointer;
}

.update-safety-confirmation input {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    margin-top: 1px;
    accent-color: #f59e0b;
}

.update-safety-actions {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    margin-top: 24px;
}

.update-safety-actions button {
    min-height: 46px;
    padding: 0 20px;
    border-radius: 12px;
    font: inherit;
    font-weight: 750;
    cursor: pointer;
}

.update-safety-cancel {
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text);
}

.update-safety-proceed {
    border: 1px solid #f59e0b;
    background: #f59e0b;
    color: #15100a;
}

.update-safety-proceed:disabled {
    opacity: 0.38;
    cursor: not-allowed;
}

@media (max-width: 600px) {
    .update-safety-modal { padding: 12px; }
    .update-safety-dialog { max-height: calc(100dvh - 24px); overflow-y: auto; border-radius: 18px; }
    .update-safety-actions { flex-direction: column-reverse; }
    .update-safety-actions button { width: 100%; }
}

/* ── Explorador moderno de biblioteca G-code ─────────────────────────── */
#gcode-section {
    --gcode-line: rgba(59, 130, 246, 0.4);
    --gcode-accent-rgb: 59, 130, 246;
    --gcode-surface: color-mix(in srgb, var(--card-bg) 92%, transparent);
    --gcode-surface-soft: color-mix(in srgb, var(--card-bg) 78%, transparent);
}

.gcode-library-main { padding: 14px 16px 28px; }

.gcode-library-shell {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(320px, 370px);
    gap: 12px;
    align-items: start;
}

.gcode-library-card,
.gcode-modern-preview {
    min-width: 0;
    border: 1px solid var(--gcode-line);
    border-radius: 18px;
    background:
        linear-gradient(145deg, rgba(var(--accent-rgb), 0.035), transparent 35%),
        var(--gcode-surface);
    box-shadow: 0 18px 55px rgba(0, 0, 0, 0.22);
    backdrop-filter: blur(12px);
}

.gcode-library-card { overflow: hidden; }

.gcode-library-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 22px;
    padding: 24px 28px 12px;
}

.gcode-library-header h1 {
    margin: 0;
    color: var(--text);
    font-size: clamp(1.55rem, 2vw, 2rem);
}

.gcode-library-header p {
    margin: 8px 0 0;
    color: var(--text-muted);
    font-size: 0.9rem;
}

.gcode-library-actions,
.gcode-navigation-buttons,
.gcode-view-switch {
    display: flex;
    align-items: center;
    gap: 8px;
}

.gcode-primary-action,
.gcode-toolbar-action,
.gcode-icon-action,
.gcode-navigation-buttons button,
.gcode-view-switch button {
    min-height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: 1px solid var(--gcode-line);
    border-radius: 9px;
    background: rgba(4, 15, 20, 0.38);
    color: var(--text);
    font: inherit;
    font-size: 0.8rem;
    font-weight: 650;
    cursor: pointer;
    transition: 160ms ease;
}

.gcode-primary-action { padding: 0 15px; border-color: rgba(var(--accent-rgb), 0.72); background: rgba(var(--accent-rgb), 0.17); color: var(--accent); }
.gcode-toolbar-action { padding: 0 14px; }
.gcode-icon-action,
.gcode-navigation-buttons button,
.gcode-view-switch button { width: 39px; padding: 0; }
.gcode-primary-action:hover,
.gcode-toolbar-action:hover,
.gcode-icon-action:hover,
.gcode-navigation-buttons button:hover,
.gcode-view-switch button:hover,
.gcode-view-switch button.active { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.14); }
.gcode-navigation-buttons button:disabled { opacity: 0.32; cursor: default; }

.gcode-navigation-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 28px 14px;
}

.gcode-breadcrumbs {
    min-width: 0;
    display: flex;
    align-items: center;
    overflow-x: auto;
    scrollbar-width: none;
}

.gcode-breadcrumbs .breadcrumb-segment {
    position: relative;
    min-height: 38px;
    padding: 0 17px;
    border: 1px solid rgba(148, 163, 184, 0.18);
    border-right: 0;
    background: color-mix(in srgb, var(--card-bg) 38%, transparent);
    color: var(--text-muted);
    font-size: 0.76rem;
    cursor: pointer;
    white-space: nowrap;
}

.gcode-breadcrumbs .breadcrumb-segment:first-child { border-radius: 9px 0 0 9px; }
.gcode-breadcrumbs .breadcrumb-segment:last-child { border-right: 1px solid var(--gcode-line); border-radius: 0 9px 9px 0; color: var(--accent); }
.gcode-breadcrumbs .breadcrumb-sep { display: none; }
.gcode-disk-free { margin-left: auto; color: var(--text-muted); font-size: 0.72rem; white-space: nowrap; }

.gcode-library-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 28px;
    border-top: 1px solid rgba(148, 163, 184, 0.1);
    border-bottom: 1px solid rgba(148, 163, 184, 0.14);
}

.gcode-library-search {
    width: min(330px, 32vw);
    min-height: 38px;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 0 11px;
    border: 1px solid rgba(148, 163, 184, 0.18);
    border-radius: 9px;
    background: color-mix(in srgb, var(--card-bg) 38%, transparent);
    color: var(--text-muted);
}

.gcode-library-search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.09); }
.gcode-library-search input { min-width: 0; flex: 1; border: 0; outline: 0; background: transparent; color: var(--text); font: inherit; font-size: 0.78rem; }
.gcode-library-search kbd { padding: 2px 5px; border-radius: 4px; background: rgba(148, 163, 184, 0.12); color: var(--text-muted); font-size: 0.62rem; white-space: nowrap; }
.gcode-toolbar-spacer { flex: 1; }

.gcode-select-control {
    min-height: 38px;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 0 10px;
    border: 1px solid rgba(148, 163, 184, 0.18);
    border-radius: 9px;
    background: color-mix(in srgb, var(--card-bg) 38%, transparent);
    color: var(--text-muted);
    font-size: 0.72rem;
}

.gcode-select-control select { max-width: 145px; border: 0; outline: 0; background: transparent; color: var(--text); font: inherit; font-weight: 650; }
.gcode-select-control option { background: var(--card-bg); color: var(--text); }
.gcode-filter-control select { max-width: 86px; }

.gcode-browser-layout { display: grid; grid-template-columns: 205px minmax(0, 1fr); min-height: 630px; }
.gcode-inner-sidebar { border-right: 1px solid rgba(148, 163, 184, 0.13); background: rgba(2, 10, 14, 0.15); }
.gcode-inner-sidebar section { padding: 17px 14px; border-bottom: 1px solid rgba(148, 163, 184, 0.13); }
.gcode-sidebar-heading { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.gcode-sidebar-heading strong { color: var(--text); font-size: 0.77rem; }
.gcode-sidebar-heading button { border: 0; background: transparent; color: var(--accent); font-size: 0.65rem; cursor: pointer; }
.gcode-sidebar-list { display: grid; gap: 5px; }
.gcode-sidebar-item { width: 100%; min-width: 0; display: grid; grid-template-columns: 17px minmax(0, 1fr) auto; align-items: center; gap: 7px; padding: 6px 7px; border: 0; border-radius: 7px; background: transparent; color: var(--text-muted); text-align: left; cursor: pointer; }
.gcode-sidebar-item:hover { background: rgba(var(--accent-rgb), 0.1); color: var(--text); }
.gcode-sidebar-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.7rem; }
.gcode-sidebar-item b { min-width: 21px; padding: 2px 5px; border-radius: 99px; background: rgba(148, 163, 184, 0.12); font-size: 0.58rem; text-align: center; }
.gcode-sidebar-icon { color: var(--accent); }
.gcode-sidebar-empty { display: block; padding: 7px; color: var(--text-muted); font-size: 0.66rem; }

/* ── Árbol de carpetas (barra izquierda, solo fuera de la raíz) ──
   El nombre nunca se trunca -- hace wrap a varias líneas en vez de
   cortarse con ellipsis, a diferencia de la fila horizontal
   (.gcode-folder-card strong, más arriba) que sí lo hace porque ahí el
   ancho de cada tarjeta es fijo y angosto. La indentación por profundidad
   es puramente estructural (cada .gcode-tree-children ya está anidado
   dentro del nodo padre en el DOM real, ver renderLibraryFolderTree en
   app.js) con una línea guía vertical, look de explorador de archivos. ── */
.gcode-folder-tree { display: grid; gap: 2px; }
.gcode-tree-node { display: grid; gap: 2px; }
.gcode-tree-children {
    display: grid;
    gap: 2px;
    margin-left: 9px;
    padding-left: 11px;
    border-left: 1px solid rgba(148, 163, 184, 0.16);
    animation: gcodeTreeReveal 160ms ease;
}
@keyframes gcodeTreeReveal {
    from { opacity: 0; transform: translateY(-2px); }
    to   { opacity: 1; transform: translateY(0); }
}
.gcode-tree-item {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 7px;
    padding: 7px 8px 7px 5px;
    border-radius: 9px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}
.gcode-tree-item:hover { background: rgba(var(--accent-rgb), 0.09); }
.gcode-tree-item.active {
    background: rgba(var(--accent-rgb), 0.15);
}
.gcode-tree-item.active::before {
    content: '';
    position: absolute;
    left: -12px;
    top: 4px;
    bottom: 4px;
    width: 2px;
    border-radius: 2px;
    background: var(--accent);
    box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.6);
}
.gcode-tree-item.active .gcode-tree-name { color: var(--accent); font-weight: 600; }
.gcode-tree-caret,
.gcode-tree-caret-spacer {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    margin-top: 1px;
}
.gcode-tree-caret {
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}
.gcode-tree-caret:hover { background: rgba(var(--accent-rgb), 0.16); color: var(--text); }
.gcode-tree-caret svg { transition: transform 160ms ease; }
.gcode-tree-caret.expanded svg { transform: rotate(-180deg); }
.gcode-tree-folder-icon { flex-shrink: 0; margin-top: 1px; color: var(--text-muted); transition: color 120ms ease; }
.gcode-tree-item:hover .gcode-tree-folder-icon,
.gcode-tree-item.active .gcode-tree-folder-icon { color: var(--accent); }
.gcode-tree-name {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-muted);
    font-size: 0.75rem;
    line-height: 1.35;
    white-space: normal;
    overflow-wrap: anywhere;
}
.gcode-tree-item:hover .gcode-tree-name { color: var(--text); }
.gcode-tree-count {
    flex-shrink: 0;
    margin-top: 1px;
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted);
    font-size: 0.62rem;
    font-variant-numeric: tabular-nums;
}
.gcode-tree-item.active .gcode-tree-count { background: rgba(var(--accent-rgb), 0.2); color: var(--accent); }

.gcode-browser-content { min-width: 0; padding: 12px 14px 10px; position: relative; z-index: 0; overflow: hidden; }
.gcode-browser-content::before {
    content: attr(data-bg-label);
    position: absolute;
    right: 14px;
    bottom: -0.12em;
    z-index: -1;
    font-size: clamp(2.2rem, 5.4vw, 5rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.01em;
    color: rgba(var(--gcode-accent-rgb, var(--accent-rgb)), 0.1);
    white-space: nowrap;
    pointer-events: none;
    user-select: none;
}
.gcode-folder-strip { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(172px, 1fr); gap: 11px; margin-bottom: 14px; padding-bottom: 2px; overflow-x: auto; scrollbar-width: thin; }
.gcode-folder-card {
    min-width: 172px;
    height: 78px;
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr) auto;
    align-items: center;
    gap: 11px;
    padding: 12px 13px;
    border: 1px solid rgba(var(--accent-rgb), 0.16);
    border-radius: 14px;
    background: linear-gradient(155deg, rgba(var(--accent-rgb), 0.07), rgba(var(--accent-rgb), 0.02));
    color: var(--text);
    cursor: pointer;
    text-align: left;
    transition: border-color 140ms ease, background 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}
.gcode-folder-card:hover {
    border-color: rgba(var(--accent-rgb), 0.55);
    background: linear-gradient(155deg, rgba(var(--accent-rgb), 0.14), rgba(var(--accent-rgb), 0.04));
    transform: translateY(-2px);
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.22);
}
/* El ícono va en una placa propia con fondo suave -- antes era un SVG
   suelto flotando sobre el fondo de la tarjeta, se veía plano. */
.gcode-folder-card-icon {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
}
/* El wrapper del nombre+contador NECESITA min-width:0 -- sin esto, un grid
   item no se achica más allá del ancho de su contenido (default
   min-width:auto de CSS Grid), así que el ellipsis de abajo nunca llegaba a
   activarse y el texto largo se salía de la tarjeta, encimándose con la
   siguiente ("Biblioteca de tipografías" tapando a "CATOLICOS"). */
.gcode-folder-card-body { min-width: 0; }
.gcode-folder-card strong { display: block; overflow: hidden; text-overflow: ellipsis; font-size: 0.78rem; font-weight: 650; white-space: nowrap; }
.gcode-folder-card small { display: block; margin-top: 2px; color: var(--text-muted); font-size: 0.65rem; }
.gcode-folder-menu {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: 999px;
    background: rgba(var(--accent-rgb), 0.1);
    color: var(--text-muted);
    transition: background 140ms ease, color 140ms ease;
}
.gcode-folder-card:hover .gcode-folder-menu { background: rgba(var(--accent-rgb), 0.22); color: var(--accent); }

.gcode-modern-table { min-height: 430px; border: 1px solid rgba(148, 163, 184, 0.14); border-radius: 11px; overflow: hidden; }
.gcode-modern-table .models-table { width: 100%; border-collapse: collapse; }
.gcode-modern-table .models-table th { height: 42px; padding: 0 9px; color: var(--text-muted); font-size: 0.63rem; font-weight: 650; text-align: left; }
.gcode-modern-table .models-table td { height: 58px; padding: 6px 9px; border-top: 1px solid rgba(148, 163, 184, 0.12); color: var(--text-muted); font-size: 0.7rem; }
.gcode-modern-table .models-table tr { cursor: pointer; transition: 140ms ease; }
.gcode-modern-table .models-table tbody tr:hover { background: rgba(var(--accent-rgb), 0.055); }
.gcode-modern-table .models-table tbody tr.selected { background: linear-gradient(90deg, rgba(var(--accent-rgb), 0.17), rgba(var(--accent-rgb), 0.055)); box-shadow: inset 0 0 0 1px var(--accent); }
.gcode-modern-table .model-name { min-width: 225px; }
.gcode-modern-table .model-name strong { color: var(--text); font-size: 0.73rem; }
.gcode-modern-table .cnc-files-thumb { width: 38px; height: 38px; border: 1px solid rgba(var(--accent-rgb), 0.38); border-radius: 8px; background: rgba(var(--accent-rgb), 0.06); object-fit: contain; }
.gcode-modern-table .tag-pill { font-size: 0.6rem; }
.gcode-file-favorite { color: #fbbf24; margin-left: 4px; }
.gcode-status-ok { display: inline-grid; place-items: center; width: 18px; height: 18px; border: 1px solid var(--accent); border-radius: 50%; color: var(--accent); font-size: 0.62rem; }
.gcode-row-menu { border: 0; background: transparent; color: var(--text-muted); font-size: 1rem; cursor: pointer; }

.gcode-modern-table.is-grid { border: 0; overflow: visible; }
.gcode-modern-table.is-grid .models-table thead { display: none; }
/* Antes .models-table Y su tbody eran grid container al mismo tiempo: con
   el thead oculto, el tbody quedaba como único item del grid de la tabla
   externa y se confinaba a una sola celda (~190px) -- heredando ese ancho
   angosto a su propio grid interno de tarjetas, que colapsaba a una sola
   columna hacia abajo. Solo el tbody debe ser el grid container real. */
.gcode-modern-table.is-grid .models-table { display: block; }
.gcode-modern-table.is-grid .models-table tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; }
.gcode-modern-table.is-grid .models-table tr { position: relative; min-width: 0; display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: auto; gap: 5px 8px; padding: 10px; border: 1px solid rgba(148, 163, 184, 0.14); border-radius: 11px; background: color-mix(in srgb, var(--card-bg) 24%, transparent); }
.gcode-modern-table.is-grid .models-table td { height: auto; min-width: 0; padding: 0; border: 0; }
.gcode-modern-table.is-grid .select-col,
.gcode-modern-table.is-grid td:last-child { position: absolute; top: 8px; z-index: 2; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 6px; background: color-mix(in srgb, var(--card-bg) 55%, transparent); }
.gcode-modern-table.is-grid .select-col { left: 8px; }
.gcode-modern-table.is-grid td:last-child { right: 8px; }
.gcode-modern-table.is-grid .model-name { grid-column: 1 / -1; grid-row: 1; min-width: 0; display: block; }
.gcode-modern-table.is-grid .model-name strong { display: -webkit-box; margin-top: 6px; overflow: hidden; color: var(--text); font-size: 0.72rem; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.gcode-modern-table.is-grid .cnc-files-thumb { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: contain; }
.gcode-modern-table.is-grid td:nth-child(3) { grid-column: 1 / -1; grid-row: 2; }
.gcode-modern-table.is-grid td:nth-child(4) { grid-column: 1 / span 1; grid-row: 3; }
.gcode-modern-table.is-grid td:nth-child(5) { grid-column: 2 / -1; grid-row: 3; text-align: right; }
.gcode-modern-table.is-grid td:nth-child(6) { grid-column: 1 / -1; grid-row: 4; }
.gcode-modern-table.is-grid td:nth-child(7) { grid-column: 1 / -1; grid-row: 5; text-align: right; }
.gcode-modern-table.is-grid td:nth-child(3),
.gcode-modern-table.is-grid td:nth-child(4),
.gcode-modern-table.is-grid td:nth-child(5),
.gcode-modern-table.is-grid td:nth-child(6),
.gcode-modern-table.is-grid td:nth-child(7) { display: block; overflow: hidden; color: var(--text-muted); font-size: 0.62rem; text-overflow: ellipsis; white-space: nowrap; }

.gcode-pagination { min-height: 45px; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 5px 0; color: var(--text-muted); font-size: 0.66rem; }
.gcode-pagination-pages { display: flex; align-items: center; gap: 5px; }
.gcode-pagination button { min-width: 29px; height: 29px; border: 1px solid rgba(148, 163, 184, 0.18); border-radius: 7px; background: color-mix(in srgb, var(--card-bg) 28%, transparent); color: var(--text); cursor: pointer; }
.gcode-pagination button.active { border-color: var(--accent); color: var(--accent); background: rgba(var(--accent-rgb), 0.13); }
.gcode-pagination button:disabled { opacity: 0.35; cursor: default; }

.gcode-modern-preview { position: sticky; top: 14px; min-height: calc(100vh - 86px); padding: 20px; }
.gcode-modern-preview .preview-card-inner { display: flex; flex-direction: column; min-height: calc(100vh - 126px); }
.gcode-modern-preview .preview-card-header { margin-bottom: 10px; }
.gcode-modern-preview .preview-label { color: var(--accent); font-size: 0.68rem; font-weight: 800; letter-spacing: 0.08em; }
.gcode-preview-name-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.gcode-preview-name-row h2 { min-width: 0; margin: 0; overflow: hidden; color: var(--text); font-size: 1.25rem; text-overflow: ellipsis; white-space: nowrap; }
#gcode-preview-favorite { flex: 0 0 auto; border: 0; background: transparent; color: var(--text-muted); font-size: 1.35rem; cursor: pointer; }
#gcode-preview-favorite.active { color: #fbbf24; }
.gcode-modern-preview #gcode-preview-description { margin: 8px 0 15px; color: var(--text-muted); font-size: 0.72rem; line-height: 1.45; }
.gcode-modern-preview .preview-meta-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.gcode-modern-preview .preview-meta-grid > div { min-width: 0; padding: 9px; border: 1px solid rgba(148, 163, 184, 0.15); border-radius: 8px; background: color-mix(in srgb, var(--card-bg) 25%, transparent); }
.gcode-modern-preview .preview-meta-grid span { display: block; color: var(--text-muted); font-size: 0.6rem; }
.gcode-modern-preview .preview-meta-grid strong { display: block; margin-top: 4px; overflow: hidden; color: var(--text); font-size: 0.68rem; text-overflow: ellipsis; }
.gcode-modern-preview .preview-file-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin: 12px 0; }
.gcode-modern-preview .preview-file-actions .btn-file-action { min-width: 0; justify-content: center; padding: 7px 8px; font-size: 0.65rem; }

.gcode-preview-coordinate-frame {
    position: relative;
    flex: 1;
    min-height: 340px;
    margin: 4px 0 14px 28px;
    border: 1px solid rgba(var(--accent-rgb), 0.2);
    border-radius: 12px;
    background: rgba(2, 12, 16, 0.35);
}
.gcode-preview-scene { position: absolute; inset: 0; overflow: hidden; border-radius: inherit; background-image: linear-gradient(rgba(var(--accent-rgb), .08) 1px, transparent 1px), linear-gradient(90deg, rgba(var(--accent-rgb), .08) 1px, transparent 1px); background-size: 32px 32px; }
.gcode-preview-scene img { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: contain; mix-blend-mode: screen; }
.gcode-preview-ruler-y { position: absolute; top: 0; bottom: 0; left: -28px; width: 25px; display: flex; flex-direction: column; justify-content: space-between; align-items: flex-end; color: var(--text-muted); font-size: 0.5rem; }
.gcode-preview-ruler-y span,
.gcode-preview-ruler-x span { color: var(--accent); font-weight: 800; }
.gcode-preview-ruler-x { position: absolute; left: 0; right: 0; bottom: -22px; display: flex; justify-content: space-between; color: var(--text-muted); font-size: 0.5rem; }
.gcode-preview-ruler-x i,
.gcode-preview-ruler-y i { font-style: normal; }

.gcode-preview-insights { display: grid; grid-template-columns: 1fr 1fr; margin-top: 10px; border: 1px solid rgba(148, 163, 184, 0.15); border-radius: 10px; background: color-mix(in srgb, var(--card-bg) 25%, transparent); }
.gcode-preview-insights > div { padding: 12px 14px; }
.gcode-preview-insights > div + div { border-left: 1px solid rgba(148, 163, 184, 0.15); }
.gcode-preview-insights span { display: block; color: var(--text-muted); font-size: 0.62rem; }
.gcode-preview-insights strong { display: block; margin-top: 4px; color: var(--text); font-size: 0.77rem; }

@media (max-width: 1380px) {
    .gcode-library-shell { grid-template-columns: minmax(0, 1fr) 320px; }
    .gcode-browser-layout { grid-template-columns: 175px minmax(0, 1fr); }
    .gcode-library-actions span { display: none; }
    .gcode-primary-action,
    .gcode-toolbar-action { width: 39px; padding: 0; }
}

@media (max-width: 1120px) {
    .gcode-library-shell { grid-template-columns: 1fr; }
    .gcode-modern-preview { position: relative; top: auto; min-height: 640px; }
    .gcode-modern-preview .preview-card-inner { min-height: 600px; }
}

@media (max-width: 820px) {
    .gcode-library-main { padding: 8px; }
    .gcode-library-header { align-items: flex-start; padding: 18px; }
    .gcode-library-actions { flex-wrap: wrap; justify-content: flex-end; }
    .gcode-navigation-row,
    .gcode-library-toolbar { padding-left: 18px; padding-right: 18px; }
    .gcode-library-toolbar { flex-wrap: wrap; }
    .gcode-library-search { width: 100%; }
    .gcode-toolbar-spacer { display: none; }
    .gcode-browser-layout { grid-template-columns: 1fr; }
    .gcode-inner-sidebar { display: none; }
    .gcode-modern-table .models-table th:nth-child(3),
    .gcode-modern-table .models-table td:nth-child(3),
    .gcode-modern-table .models-table th:nth-child(6),
    .gcode-modern-table .models-table td:nth-child(6) { display: none; }
}

@media (max-width: 560px) {
    .gcode-library-header { display: block; }
    .gcode-library-actions { justify-content: flex-start; margin-top: 14px; }
    .gcode-navigation-row { flex-wrap: wrap; }
    .gcode-breadcrumbs { order: 3; width: 100%; }
    .gcode-disk-free { display: none; }
    .gcode-select-control span { display: none; }
    .gcode-browser-content { padding: 9px; }
    .gcode-modern-table .models-table th:nth-child(4),
    .gcode-modern-table .models-table td:nth-child(4),
    .gcode-modern-table .models-table th:nth-child(5),
    .gcode-modern-table .models-table td:nth-child(5) { display: none; }
    .gcode-modern-preview { padding: 15px; }
    .gcode-modern-preview .preview-file-actions { grid-template-columns: 1fr 1fr; }
}

.devices-subcard {
    margin-top: 16px;
    padding: 16px;
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.devices-subcard-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}

.devices-subcard-header h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text);
    flex: 1;
}

.devices-subcard p {
    margin: 4px 0 12px;
    font-size: 0.8rem;
    color: var(--text-muted);
}

/* Subtítulo interno entre dos listas dentro de la misma tarjeta (ej. puertos
   detectados vs. impresoras Marlin ya registradas). */
.devices-subcard-sublabel {
    margin-top: 16px !important;
    font-weight: 600;
    color: var(--text-secondary) !important;
}

.devices-subcard-title-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
    margin-top: 16px;
}

.devices-subcard-title-row .devices-subcard-sublabel {
    margin-top: 0 !important;
}

.devices-subcard-title-row .btn-file-action {
    flex-shrink: 0;
    padding: 7px 12px;
    font-size: 0.78rem;
}

.marlin-register-inline-fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 120px;
    gap: 10px;
}

.marlin-register-inline-fields[hidden] {
    display: none;
}

@media (max-width: 520px) {
    .marlin-register-inline-fields {
        grid-template-columns: 1fr;
    }

    .devices-subcard-title-row {
        align-items: stretch;
        flex-direction: column;
    }
}

.usb-ports-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tunascreen-code-display {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 12px;
    margin: 12px 0;
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--panel-bg);
}

.tunascreen-code-value {
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: 0.3em;
    color: var(--accent);
}

.tunascreen-code-expiry {
    font-size: 0.82rem;
    color: var(--text-muted);
}

.tunascreen-devices-title {
    margin: 12px 0 6px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted);
}

.device-status-pill {
    font-size: 0.72rem;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 999px;
    flex-shrink: 0;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
}

.device-status-pill.online {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.device-status-pill.offline {
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-muted);
}

.device-status-pill.conflict {
    background: rgba(245, 158, 11, 0.16);
    color: #f59e0b;
}

/* Ajustes > Accesorios: encendido/apagado/desconocido de un accesorio
   individual (ver renderSettingsAccessoriesList en app.js). */
.device-status-pill.on {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.device-status-pill.off {
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-muted);
}

.device-status-pill.unknown {
    background: rgba(245, 158, 11, 0.14);
    color: #f59e0b;
}

/* ── Acciones rápidas (dock del dashboard, ver renderAccessories en app.js) ── */

/* Grilla fija de 3 columnas x 2 filas (6 fichas visibles) -- si hay menos
   de 6 accesorios, los espacios que faltan se rellenan con fichas vacías
   (ver renderAccessories/ACCESSORY_EMPTY_TILE_HTML); si hay más de 6, la
   grilla agrega filas pero el contenedor mantiene su alto fijo (ver
   --accessory-rows / .accessories-list-dense en renderAccessories), así
   que las fichas se achican para seguir entrando todas sin scroll. */
.accessories-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(var(--accessory-rows, 2), 1fr);
    height: 106px;
    gap: 8px;
}

.accessories-list-dense .accessory-item,
.accessories-list-dense .accessory-add-tile,
.accessories-list-dense .accessory-empty-tile {
    padding: 5px 8px;
    gap: 6px;
}

.accessories-list-dense .accessory-item-icon {
    width: 18px;
    height: 18px;
}

.accessories-list-dense .accessory-item-name {
    font-size: 0.68rem;
}

.accessories-list-dense .accessory-item-meta {
    font-size: 0.58rem;
}

.accessories-list-dense .accessory-power-btn {
    width: 18px;
    height: 18px;
}

.accessories-list-dense .accessory-power-btn svg {
    width: 11px;
    height: 11px;
}

.accessories-list-dense .accessory-item-actions .theme-option-icon-btn {
    width: 18px;
    height: 18px;
}

.accessory-empty-tile {
    border: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
    border-radius: var(--radius-lg);
}

.accessory-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 11px;
    background: var(--panel-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}

.accessory-item-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 27px;
    height: 27px;
    border-radius: var(--radius-md);
    background: rgba(var(--accent-rgb), 0.14);
    color: var(--accent);
    flex-shrink: 0;
}

.accessory-item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.accessory-item-name {
    font-weight: 600;
    color: var(--text);
    font-size: 0.8rem;
}

/* Estado activo de una escena doble/múltiple (ver renderAccessories). */
.accessory-item-state-badge {
    margin-left: 5px;
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
    font-size: 0.6rem;
    font-weight: 700;
}

.accessory-item-meta {
    font-size: 0.65rem;
    color: var(--text-muted);
}

.accessory-item-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.accessory-add-tile {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 49px;
    padding: 10px 11px;
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: var(--radius-lg);
    color: var(--text-muted);
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.accessory-add-tile:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.accessory-power-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 1px solid rgba(34, 197, 94, 0.35);
    background: rgba(34, 197, 94, 0.1);
    color: #22c55e;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

.accessory-power-btn:hover {
    background: rgba(34, 197, 94, 0.2);
}

.accessory-power-btn.is-on {
    background: #16a34a;
    border-color: #16a34a;
    color: #fff;
}

.accessory-power-btn:disabled {
    opacity: 0.5;
    cursor: default;
}

.wifi-scan-ip-row {
    display: flex;
    gap: 8px;
    margin: 8px 0 4px;
}

.wifi-scan-ip-row input {
    flex: 1;
    min-width: 0;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.3);
    background: rgba(34, 197, 94, 0.05);
    color: var(--text);
    font-size: 0.82rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}

.wifi-scan-ip-row input:focus {
    outline: none;
    border-color: rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.08);
}

.wifi-scan-ip-row .btn-file-action {
    flex-shrink: 0;
    padding: 8px 14px;
    font-size: 0.82rem;
}

.usb-port-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    transition: background 0.3s ease, border-color 0.3s ease;
}

.usb-port-item-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* Ajustes > Accesorios: mismo .usb-port-item-info de siempre, pero con el
   ícono de tipo (extractor/ventilador/etc) a la izquierda del nombre. */
.usb-port-item-info-with-icon {
    flex-direction: row;
    align-items: center;
    gap: 8px;
}

.usb-port-item-info-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.usb-port-item-info strong {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    color: var(--text);
    font-size: 0.85rem;
}

.usb-port-item-info span {
    font-size: 0.74rem;
    color: var(--text-muted);
}

.usb-port-vidpid {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.72rem;
    color: var(--text-muted);
    flex-shrink: 0;
}

.usb-port-item-new {
    border-color: rgba(34, 197, 94, 0.5);
    animation: usbPortPulse 1.6s ease-in-out 2;
}

@keyframes usbPortPulse {
    0%, 100% { background: rgba(34, 197, 94, 0.12); }
    50% { background: rgba(34, 197, 94, 0.3); }
}

#app-toast-container {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 3000;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 340px;
}

@media (max-width: 400px) {
    /* right:24px + max-width:340px ya no deja margen en los teléfonos más
       angostos (~360px) — se ancla también por la izquierda para que se
       achique en vez de asomarse fuera de pantalla. */
    #app-toast-container {
        left: 12px;
        right: 12px;
        max-width: none;
    }
}

.app-toast {
    background: var(--card-bg);
    color: var(--text);
    border: 1px solid rgba(34, 197, 94, 0.35);
    border-left: 4px solid #22c55e;
    border-radius: 10px;
    padding: 12px 16px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
    font-size: 0.85rem;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.app-toast.visible {
    opacity: 1;
    transform: translateY(0);
}

.app-toast-error {
    border-color: rgba(239, 68, 68, 0.4);
    border-left-color: #ef4444;
}

.app-toast-warning {
    border-color: rgba(245, 158, 11, 0.4);
    border-left-color: #f59e0b;
}

.usb-port-item {
    flex-wrap: wrap;
}

.usb-port-add-btn {
    padding: 6px 12px;
    font-size: 0.78rem;
}

.usb-port-registered {
    display: flex;
    align-items: center;
    gap: 6px;
}

.usb-port-registered-badge {
    font-size: 0.72rem;
    font-weight: 700;
    color: #22c55e;
    background: rgba(34, 197, 94, 0.14);
    padding: 4px 10px;
    border-radius: 999px;
}

/* Firmware ("FluidNC / GRBL" vs "Marlin") de una placa CNC/láser ya
   registrada — ver deviceFirmwareBadgeLabel() en app.js. */
.usb-port-firmware-badge {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-secondary);
    background: var(--panel-bg);
    border: 1px solid var(--border);
    padding: 4px 10px;
    border-radius: 999px;
}

/* ── Modal de clasificación USB/red (nombre + tipo de dispositivo) ── */

.modal-content.usb-classify-modal-content {
    width: 92%;
    max-width: 460px;
    height: auto;
    max-height: 92vh;
    overflow-y: auto;
    padding: 32px;
    display: block;
    text-align: center;
    border-radius: 24px;
    color: var(--text);
}

.usb-classify-close-btn {
    z-index: 3;
}

.usb-classify-step-icon {
    width: 46px;
    height: 46px;
    margin: 0 auto 14px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.usb-classify-step-icon-purple {
    background: rgba(139, 92, 246, 0.14);
    color: #8b5cf6;
}

.usb-classify-hexagon-icon {
    width: 60px;
    height: 60px;
    margin: 0 auto 12px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.usb-classify-title-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.usb-classify-title-row h2 {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.usb-classify-title-white {
    color: var(--text);
}

.usb-classify-title-green,
.usb-classify-title-accent {
    color: #22c55e;
}

.usb-classify-title-trace {
    opacity: 0.5;
    flex-shrink: 0;
}

/* Paso "Nombre para este X" cambia de verde (láser) a naranja (CNC) según
   el tipo elegido en el paso anterior — mismo layout, distinto acento. */
.usb-classify-hexagon-icon-dynamic,
.usb-classify-title-trace-dynamic {
    color: #22c55e;
}

#usb-classify-name-divider {
    background: #22c55e;
}

#usb-classify-step-name.theme-cnc .usb-classify-hexagon-icon-dynamic,
#usb-classify-step-name.theme-cnc .usb-classify-title-trace-dynamic,
#usb-classify-step-name.theme-cnc .usb-classify-title-dynamic,
#usb-classify-step-name.theme-cnc .usb-classify-name-field-dynamic label,
#usb-classify-step-name.theme-cnc .usb-classify-input-icon {
    color: var(--orange);
}

#usb-classify-step-name.theme-cnc #usb-classify-name-divider {
    background: var(--orange);
}

#usb-classify-step-name.theme-cnc .usb-classify-name-field-dynamic input:focus {
    border-color: rgba(245, 158, 11, 0.5);
    background: rgba(245, 158, 11, 0.08);
}

.usb-classify-subtitle {
    margin: 8px 0 0;
    font-size: 0.82rem;
    color: var(--text-muted);
}

.usb-classify-divider {
    width: 40px;
    height: 3px;
    margin: 12px auto 18px;
    border-radius: 999px;
    background: #22c55e;
    opacity: 0.6;
}

.usb-classify-divider-purple {
    background: #8b5cf6;
}

.usb-classify-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0 0 16px;
    text-align: left;
}

.usb-classify-type-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(139, 92, 246, 0.35);
    background: rgba(139, 92, 246, 0.06);
    color: var(--text);
    cursor: pointer;
    text-align: left;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.usb-classify-type-card:hover {
    background: rgba(139, 92, 246, 0.12);
}

.usb-classify-type-card-orange:hover {
    background: rgba(245, 158, 11, 0.14);
}

.usb-classify-type-card-green:hover {
    background: rgba(34, 197, 94, 0.14);
}

.usb-classify-type-card-icon {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(139, 92, 246, 0.16);
    color: #8b5cf6;
}

.usb-classify-type-card-icon-green {
    background: rgba(34, 197, 94, 0.16);
    color: #22c55e;
}

.usb-classify-type-card-icon-orange {
    background: rgba(245, 158, 11, 0.16);
    color: var(--orange);
}

.usb-classify-type-card-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.usb-classify-type-card-title {
    font-size: 0.88rem;
    font-weight: 700;
    color: #8b5cf6;
}

.usb-classify-type-card-green .usb-classify-type-card-title {
    color: #22c55e;
}

.usb-classify-type-card-orange .usb-classify-type-card-title {
    color: var(--orange);
}

.usb-classify-type-card-desc {
    font-size: 0.74rem;
    color: var(--text-muted);
}

.usb-classify-type-card-check {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: #22c55e;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}

.usb-classify-type-card-green {
    border-color: rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.08);
}

.usb-classify-type-card-orange {
    border-color: rgba(245, 158, 11, 0.5);
    background: rgba(245, 158, 11, 0.08);
}

.usb-classify-info-box {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    margin-bottom: 16px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.2);
    color: var(--text-muted);
    font-size: 0.76rem;
    line-height: 1.4;
    text-align: left;
}

.usb-classify-info-box svg {
    flex-shrink: 0;
    margin-top: 1px;
    color: #22c55e;
}

.usb-classify-secondary-btn,
.usb-classify-primary-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 12px 16px;
    border-radius: var(--radius-md);
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
}

.usb-classify-secondary-btn {
    border: 1px solid rgba(34, 197, 94, 0.35);
    background: rgba(34, 197, 94, 0.06);
    color: #22c55e;
}

.usb-classify-secondary-btn:hover {
    background: rgba(34, 197, 94, 0.14);
}

.usb-classify-primary-btn {
    border: none;
    background: linear-gradient(90deg, #8b5cf6, #6d28d9);
    color: #fff;
    margin-bottom: 10px;
}

.usb-classify-primary-btn:hover {
    background: linear-gradient(90deg, #7c3aed, #5b21b6);
}

.usb-classify-primary-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.usb-classify-illustration {
    margin: 16px 0;
    opacity: 0.85;
    width: 100%;
    height: 110px;
    overflow: hidden;
    border-radius: var(--radius-md);
}

.usb-classify-illustration img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

.usb-classify-name-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0 0 14px;
    text-align: left;
}

.usb-classify-name-field label {
    font-size: 0.78rem;
    font-weight: 600;
    color: #22c55e;
}

.usb-classify-name-field input {
    width: 100%;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: rgba(var(--accent-rgb), 0.05);
    color: var(--text);
    font-size: 0.95rem;
}

.usb-classify-name-field input:focus {
    outline: none;
    border-color: rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.08);
}

.usb-classify-name-field select {
    width: 100%;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: rgba(var(--accent-rgb), 0.05);
    color: var(--text);
    font-size: 0.95rem;
    cursor: pointer;
}

.usb-classify-name-field select:focus {
    outline: none;
    border-color: rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.08);
}

.usb-classify-name-field textarea {
    width: 100%;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: rgba(var(--accent-rgb), 0.05);
    color: var(--text);
    font-size: 0.95rem;
    font-family: inherit;
    resize: vertical;
}

.usb-classify-name-field textarea:focus {
    outline: none;
    border-color: rgba(34, 197, 94, 0.5);
    background: rgba(34, 197, 94, 0.08);
}

.usb-classify-input-icon-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

.usb-classify-input-icon {
    position: absolute;
    left: 12px;
    color: #22c55e;
    pointer-events: none;
}

.usb-classify-input-icon-wrap input {
    padding-left: 34px;
}

.usb-classify-input-suffix-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

.usb-classify-input-suffix-wrap input {
    padding-right: 34px;
}

.usb-classify-input-suffix {
    position: absolute;
    right: 12px;
    font-size: 0.76rem;
    color: var(--text-muted);
    pointer-events: none;
}

.usb-classify-name-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 16px;
}

.usb-classify-name-actions .btn-file-action {
    justify-content: center;
}

/* Modal "Nueva escena" del dock del dashboard (ver #scene-modal en
   index.html / openSceneModal en app.js). */
.scene-modal-eyebrow {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #22c55e;
    margin-bottom: 2px;
}

.scene-actions-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 10px;
}

.scene-action-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.scene-action-row select {
    flex: 1;
    min-width: 0;
    padding: 9px 10px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: rgba(var(--accent-rgb), 0.05);
    color: var(--text);
    font-size: 0.85rem;
    cursor: pointer;
}

.scene-action-row input[type="color"] {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    padding: 2px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: transparent;
    cursor: pointer;
}

.scene-action-row .theme-option-icon-btn {
    flex-shrink: 0;
}

.usb-classify-scan-status {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.2);
    color: var(--text-muted);
    font-size: 0.82rem;
}

.usb-classify-scan-spinner {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(34, 197, 94, 0.25);
    border-top-color: #22c55e;
    animation: usbClassifyScanSpin 0.8s linear infinite;
}

@keyframes usbClassifyScanSpin {
    to { transform: rotate(360deg); }
}

.usb-classify-scan-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 0 0 4px;
}

.usb-classify-scan-home {
    grid-column: 1 / -1;
}

.usb-classify-scan-home span {
    display: block;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    background: rgba(var(--accent-rgb), 0.05);
    color: var(--text);
    font-size: 0.9rem;
    text-transform: capitalize;
}

/* ── Modal de desvincular dispositivo ── */

.modal-content.device-unlink-modal-content {
    position: relative;
    width: 92%;
    max-width: 620px;
    height: auto;
    max-height: 92vh;
    overflow-y: auto;
    padding: 32px;
    display: block;
    text-align: center;
    background-color: var(--card-bg);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(239, 68, 68, 0.4);
    border-radius: 24px;
    box-shadow: 0 0 60px rgba(239, 68, 68, 0.12);
    color: var(--text);
}

.modal-content.device-unlink-modal-content::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: url('../img/motif-circuit.svg');
    background-repeat: repeat;
    background-size: 200px 200px;
    filter: invert(1);
    opacity: 0.08;
    border-radius: 24px;
}

.device-unlink-body {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.device-unlink-close-btn {
    z-index: 3;
}

.device-unlink-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

.device-unlink-hexagon-icon {
    width: 64px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.device-unlink-title-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.device-unlink-title-row h2 {
    margin: 0;
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    white-space: nowrap;
}

.device-unlink-title-red { color: #ef4444; }
.device-unlink-title-white { color: var(--text); }
.device-unlink-title-green { color: #22c55e; }

.device-unlink-title-trace {
    opacity: 0.5;
    flex-shrink: 0;
}

.device-unlink-subtitle {
    margin: 0;
    font-size: 0.88rem;
    color: var(--text-muted);
}

.device-unlink-info-card {
    text-align: left;
    padding: 16px;
    border-radius: var(--radius-lg);
    background: rgba(var(--accent-rgb), 0.05);
    border: 1px solid rgba(var(--accent-rgb), 0.25);
}

.device-unlink-info-top {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
}

.device-unlink-icon {
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-md);
    background: rgba(34, 197, 94, 0.1);
    border: 1px solid rgba(34, 197, 94, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
}

.device-unlink-info-name {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.device-unlink-info-name h3 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

.device-unlink-status-pill {
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid rgba(34, 197, 94, 0.4);
    background: rgba(34, 197, 94, 0.14);
    color: #22c55e;
}

.device-unlink-status-pill.offline {
    border-color: rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-muted);
}

.device-unlink-info-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 20px;
    padding-top: 14px;
    border-top: 1px solid rgba(var(--accent-rgb), 0.15);
}

.device-unlink-info-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.device-unlink-info-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.device-unlink-info-item strong {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--text);
}

.device-unlink-warning {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    text-align: left;
    padding: 14px 16px;
    border-radius: var(--radius-lg);
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.3);
}

.device-unlink-warning-icon {
    flex-shrink: 0;
    color: #ef4444;
    margin-top: 1px;
}

.device-unlink-warning-title {
    font-size: 0.8rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #ef4444;
    margin-bottom: 4px;
}

.device-unlink-warning p {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--text-muted);
}

.device-unlink-footer {
    margin: 0;
}

.device-unlink-confirm-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex: 1;
    padding: 12px 16px;
    border-radius: var(--radius-md);
    border: none;
    background: linear-gradient(90deg, #ef4444, #b91c1c);
    color: #fff;
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
}

.device-unlink-confirm-btn:hover {
    background: linear-gradient(90deg, #dc2626, #991b1b);
}

@media (max-width: 640px) {
    .device-unlink-info-grid {
        grid-template-columns: 1fr;
    }
    .printer-send-cactus {
        display: none;
    }
}

.settings-switch input[type="checkbox"] {
    display: none;
}

.switch-slider {
    width: 42px;
    height: 24px;
    border-radius: 999px;
    background: #d1d5db;
    position: relative;
    transition: background 0.2s ease;
}

.settings-switch input[type="checkbox"]:checked + .switch-slider {
    background: var(--green-dark);
}

.switch-slider::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: white;
    transition: transform 0.2s ease;
}

.settings-switch input[type="checkbox"]:checked + .switch-slider::after {
    transform: translateX(18px);
}

.settings-topbar {
    justify-content: space-between;
}

.settings-topbar-title h1 {
    font-size: 1.15rem;
    font-weight: 700;
    margin: 0;
    color: var(--text);
}

.settings-topbar-subtitle {
    margin: 2px 0 0;
    font-size: 0.78rem;
    color: var(--green-dark);
}

.settings-topbar-actions {
    display: flex;
    align-items: center;
    gap: 16px;
}

.settings-status {
    color: var(--text-muted);
    font-size: 0.82rem;
}

.btn-settings-save {
    padding: 8px 16px;
    font-size: 0.82rem;
    border-radius: 6px;
}

@media (max-width: 900px) {
    .settings-grid {
        column-count: 1;
    }
}

.preview-details {
    display: grid;
    gap: 16px;
}

.preview-details h3 {
    margin: 0;
    font-size: 1.15rem;
}

.preview-meta {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.92rem;
}

body.dark .models-table-panel,
body.green .models-table-panel {
    border-color: rgba(107, 124, 68, 0.28);
}

body.dark .models-table th,
body.green .models-table th,
body.dark .models-table td,
body.green .models-table td {
    color: var(--text);
}

body.dark .models-table tbody tr:hover,
body.green .models-table tbody tr:hover,
body.dark .models-table tbody tr.selected,
body.green .models-table tbody tr.selected {
    background: rgba(34, 197, 94, 0.12);
}

.btn-icon-dark {
    width: 44px;
    height: 44px;
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
    border: 1px solid rgba(34, 197, 94, 0.3);
}

.btn-icon-dark:hover {
    background: rgba(34, 197, 94, 0.22);
    color: #16a34a;
    opacity: 1;
}

.btn-icon-light {
    height: 34px;
    padding: 0 10px;
    background: var(--surface);
    color: var(--black);
    border-radius: var(--radius-sm);
}

.theme-toggle {
    width: 34px;
    height: 34px;
    padding: 0;
    justify-content: center;
}

body.dark .btn-icon-light {
    background: #111827;
    color: #f3f4f6;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.btn-icon-light .chevron {
    margin-left: 2px;
    color: var(--text-muted);
}

.upload-wrapper {
    position: relative;
    display: inline-flex;
}

/* ── Main ── */

main {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 32px 32px;
}

/* ── Bottom layout ── */
/* .dashboard-bottom: ver el dock fijo definido más abajo, junto a
   .dashboard-dock-*. */

.recent-section {
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    padding: 24px;
}

.recent-section {
    margin: 0;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.history-split-main {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.history-split-topbar {
    display: flex;
    gap: 20px;
    flex-shrink: 0;
    padding: 24px 32px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.history-split-header.page-header {
    flex: 1;
    min-width: 0;
    padding: 0;
    border-bottom: none;
}

.history-split-body {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    flex: 1;
    min-height: 0;
    gap: 20px;
    padding: 0 32px 24px;
}

.history-split-half {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.laser-history-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 20px;
    background: color-mix(in srgb, var(--card-bg) 55%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-lg);
}

.section-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
    flex-shrink: 0;
}

.recent-section > #models {
    flex: 1;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

.section-title h2 {
    font-size: 1.05rem;
    font-weight: 600;
    flex-shrink: 0;
}

.section-title .view-controls {
    flex-shrink: 0;
}

.section-search {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    max-width: 360px;
    background: var(--surface);
    border: 1px solid rgba(148, 163, 184, 0.2);
    padding: 8px 14px;
    border-radius: var(--radius-md);
}

.section-search input {
    width: 100%;
    border: none;
    outline: none;
    background: transparent;
    color: var(--text);
    font-size: 0.85rem;
}

.section-search input::placeholder {
    color: var(--text-muted);
}

.section-search .search-icon {
    flex-shrink: 0;
}

.btn-menu {
    background: none;
    border: none;
    color: var(--text-muted);
    padding: 4px;
    border-radius: 6px;
}

.btn-menu:hover {
    color: var(--black);
}

/* ── Recent files by printer ── */

.recent-printer-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 18px;
    min-width: 0;
}

#models.list-view .recent-printer-groups {
    grid-template-columns: 1fr;
}

#models.list-view .recent-printer-jobs {
    flex-direction: row;
    flex-wrap: wrap;
}

#models.list-view .recent-job-card {
    flex: 1;
    min-width: 260px;
}

.recent-printer-group {
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    padding: 18px;
}

.recent-printer-group-title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--text);
    margin: 0 0 14px;
}

.recent-printer-jobs {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.recent-job-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px;
    border-radius: var(--radius-md);
    background: rgba(148, 163, 184, 0.08);
    cursor: pointer;
    transition: background 0.15s ease;
}

.recent-job-card:hover {
    background: rgba(148, 163, 184, 0.16);
}

.recent-job-thumb {
    position: relative;
    width: 48px;
    height: 48px;
    border-radius: var(--radius-sm);
    background: rgba(148, 163, 184, 0.18);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    overflow: hidden;
    color: var(--text-muted);
}

.recent-job-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.recent-job-thumb-fallback {
    display: none;
}

.recent-job-thumb:not(:has(img)) .recent-job-thumb-fallback,
.recent-job-thumb.no-thumb .recent-job-thumb-fallback {
    display: block;
}

.recent-job-thumb.no-thumb img {
    display: none;
}

.recent-job-info {
    flex: 1;
    min-width: 0;
}

.recent-job-info .printer-status-line {
    font-size: 0.72rem;
    margin-bottom: 4px;
}

.recent-job-name {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    margin: 0 0 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.recent-job-meta {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.72rem;
    color: var(--text-muted);
}

.empty-state-small {
    padding: 16px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.82rem;
}

.empty-state-small-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.mini-spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(34, 197, 94, 0.25);
    border-top-color: #22c55e;
    animation: miniSpinnerSpin 0.8s linear infinite;
    flex-shrink: 0;
}

@keyframes miniSpinnerSpin {
    to { transform: rotate(360deg); }
}

/* ── Active print queue ── */

/* ── Pila fija del Panel de Control: la cola de impresión activa (toast
   flotante) queda arriba, el dock de Accesorios/Matriz LED abajo del
   todo -- ambos crecen hacia arriba desde el borde inferior sin que haga
   falta calcular la altura del dock a mano. ── */
.dashboard-fixed-stack {
    position: fixed;
    left: 240px;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.app-shell.sidebar-collapsed .dashboard-fixed-stack {
    left: 76px;
}

/* ── Dock fijo: Accesorios + copia en vivo de la Matriz LED (si el plugin
   está instalado). Sin esquinas redondeadas (estilo "bottom sheet"); se
   puede contraer con la pestaña de arriba. ── */
.dashboard-bottom {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.dashboard-dock-handle {
    width: 77px;
    height: 22px;
    flex-shrink: 0;
    margin-bottom: -1px;
    border: 1px solid var(--border);
    border-bottom: none;
    border-radius: 8px 8px 0 0;
    background: var(--card-bg);
    color: var(--text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    animation: dashboardDockHandlePulse 2.2s ease-in-out infinite;
}

.dashboard-dock-handle svg {
    transition: transform 0.2s ease;
}

.dashboard-bottom.collapsed .dashboard-dock-handle svg {
    transform: rotate(180deg);
}

@keyframes dashboardDockHandlePulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.55); }
    50% { box-shadow: 0 0 16px 5px rgba(var(--accent-rgb), 0.55); }
}

.dashboard-dock-body {
    width: 100%;
    display: flex;
    align-items: stretch;
    gap: 17px;
    background: var(--card-bg);
    border-top: 1px solid var(--border);
    padding: 13px 17px;
    max-height: 196px;
    overflow-y: auto;
    transition: max-height 0.2s ease, padding-top 0.2s ease, padding-bottom 0.2s ease, opacity 0.15s ease;
}

.dashboard-bottom.collapsed .dashboard-dock-body {
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    opacity: 0;
    overflow: hidden;
    border-top-color: transparent;
}

.dashboard-dock-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: row;
    gap: 17px;
}

.dashboard-dock-section {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.dashboard-dock-section .section-title {
    margin-bottom: 7px;
}

.dashboard-fixed-stack {
    pointer-events: none;
}

.dashboard-bottom,
.active-print-queue-list .active-print-card {
    pointer-events: auto;
}

.active-print-queue-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
    padding: 12px 24px 0;
}

.dashboard-dock-matrix {
    flex: 0 0 auto;
    width: 280px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    border-left: 1px solid var(--border);
    padding-left: 17px;
}

.dashboard-dock-matrix-label {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    align-self: flex-start;
}

/* "Ticker" de quién mandó los últimos envíos a la Matriz LED (nombre de
   máquina, o el nombre del anuncio si el envío fue manual) -- ver
   loadDashboardMatrixPreview()/get_last_sent_history() en
   screen_service.py. Más reciente a la izquierda; los pills viejos se
   empujan hacia la derecha y se recortan (overflow:hidden) en vez de
   hacer scroll, como un feed de chat en vivo. */
.dashboard-dock-matrix-ticker {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 6px;
    overflow: hidden;
    white-space: nowrap;
}

/* Solo el más reciente (primero) va en verde -- el resto gris, todos con
   la opacidad decreciente que le pone renderDashboardMatrixTicker por
   índice (100/75/50/25%). */
.dashboard-dock-matrix-pill {
    flex-shrink: 0;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 0.62rem;
    font-weight: 700;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    border: 1px solid rgba(255, 255, 255, 0.1);
    animation: dashboardDockMatrixPillIn 0.25s ease;
}

.dashboard-dock-matrix-pill:first-child {
    background: rgba(34, 197, 94, 0.18);
    color: #4ade80;
    border-color: rgba(34, 197, 94, 0.35);
}

@keyframes dashboardDockMatrixPillIn {
    from { opacity: 0; transform: translateX(-8px); }
    to { opacity: 1; transform: translateX(0); }
}

.dashboard-dock-matrix-grid {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(32, minmax(0, 1fr));
    gap: 1px;
    background: #05070c;
    border: 1px solid var(--border);
    padding: 4px;
}

.dashboard-dock-matrix-grid span {
    aspect-ratio: 1 / 1;
    background: #12161f;
    border-radius: 1px;
}

.active-print-card {
    background: var(--card-bg);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    border-radius: var(--radius-lg);
    box-shadow: 0 -8px 40px rgba(0, 0, 0, 0.25), 0 0 40px rgba(var(--accent-rgb), 0.08);
    padding: 20px 24px;
    color: var(--text);
}

.active-print-card.printing {
    background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 18%, var(--card-bg)) 0%, var(--card-bg) 70%);
    border-color: rgba(var(--accent-rgb), 0.4);
}

.active-print-card.paused {
    background: linear-gradient(135deg, color-mix(in srgb, var(--orange) 18%, var(--card-bg)) 0%, var(--card-bg) 70%);
    border-color: rgba(245, 158, 11, 0.4);
}

.active-print-card-title {
    font-size: 0.85rem;
    font-weight: 700;
    margin-bottom: 12px;
    line-height: 1.3;
}

.active-print-body {
    display: grid;
    grid-template-columns: 1.3fr 1.3fr 1fr;
    align-items: center;
    gap: 0;
}

.active-print-col {
    padding: 0 24px;
    border-left: 1px solid rgba(34, 197, 94, 0.25);
}

.active-print-col:first-child {
    padding-left: 0;
    border-left: none;
}

.active-print-col-info {
    display: flex;
    gap: 16px;
}

.active-print-thumb {
    position: relative;
    flex-shrink: 0;
    width: 82px;
    height: 82px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background-color: rgba(255, 255, 255, 0.03);
    background-image:
        repeating-linear-gradient(0deg, rgba(34, 197, 94, 0.16) 0, rgba(34, 197, 94, 0.16) 1px, transparent 1px, transparent 20%),
        repeating-linear-gradient(90deg, rgba(34, 197, 94, 0.16) 0, rgba(34, 197, 94, 0.16) 1px, transparent 1px, transparent 20%);
    border: 1px solid rgba(34, 197, 94, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
}

.active-print-thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.active-print-thumb svg {
    color: rgba(34, 197, 94, 0.5);
}

.active-print-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.active-print-filename {
    font-size: 0.95rem;
    font-weight: 700;
    margin-bottom: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.active-print-meta-row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.78rem;
}

.active-print-meta-row span {
    color: rgba(255, 255, 255, 0.55);
}

.active-print-meta-row strong {
    font-weight: 700;
    color: #fff;
}


.active-print-col-header {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
    margin-bottom: 15px;
}

.active-print-col-ring {
    display: flex;
    flex-direction: column;
}

.active-print-ring-body {
    display: flex;
    align-items: center;
    gap: 17px;
}

.active-print-ring {
    position: relative;
    flex-shrink: 0;
    width: 94px;
    height: 94px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.active-print-ring svg {
    transform: rotate(-90deg);
}

.active-print-ring-track {
    stroke: rgba(255, 255, 255, 0.08);
}

.active-print-ring-fill {
    stroke: #22c55e;
    filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.6));
    transition: stroke-dashoffset 0.3s ease;
}

.active-print-ring-pct {
    position: absolute;
    font-size: 1.1rem;
    font-weight: 800;
    color: #fff;
}

.active-print-ring-stats {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.active-print-stat-row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.78rem;
}

.active-print-stat-row span {
    color: rgba(255, 255, 255, 0.55);
}

.active-print-stat-row strong {
    font-weight: 700;
    color: #fff;
}

.active-print-col-actions {
    display: flex;
    flex-direction: column;
}

.active-print-actions-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-bottom: 8px;
}

.active-print-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 8px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: rgba(255, 255, 255, 0.05);
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}

.active-print-action-btn:hover {
    background: rgba(255, 255, 255, 0.1);
}

.active-print-action-btn:disabled {
    opacity: 0.4;
    cursor: default;
}

.active-print-action-pause {
    background: rgba(34, 197, 94, 0.16);
    border-color: rgba(34, 197, 94, 0.35);
    color: #4ade80;
}

.active-print-action-pause:hover {
    background: rgba(34, 197, 94, 0.26);
}

.active-print-action-stop {
    background: rgba(239, 68, 68, 0.16);
    border-color: rgba(239, 68, 68, 0.35);
    color: #f87171;
}

.active-print-action-stop:hover {
    background: rgba(239, 68, 68, 0.26);
}

.active-print-fullscreen-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 8px;
    border-radius: var(--radius-md);
    border: 1px solid rgba(34, 197, 94, 0.35);
    background: transparent;
    color: #4ade80;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: pointer;
    transition: background 0.15s ease;
}

.active-print-fullscreen-btn:hover {
    background: rgba(34, 197, 94, 0.12);
}

@media (max-width: 1100px) {
    .active-print-body {
        grid-template-columns: 1fr;
        gap: 20px;
    }

    .active-print-col {
        padding: 0;
        border-left: none;
        padding-top: 20px;
        border-top: 1px solid rgba(34, 197, 94, 0.25);
    }

    .active-print-col:first-child {
        padding-top: 0;
        border-top: none;
    }
}

.empty-state {
    grid-column: 1 / -1;
    padding: 32px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
}

/* ── View page (kept for /view route) ── */

.button {
    padding: 12px 20px;
    border: none;
    border-radius: 14px;
    background: var(--black);
    color: #fff;
    cursor: pointer;
    transition: opacity 0.15s ease;
}

.button:hover {
    opacity: 0.85;
}

.button.secondary {
    background: #e2e8f0;
    color: var(--text);
}

header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 24px 32px;
    background: var(--card-bg);
    border-bottom: 1px solid #e2e8f0;
}

.logo {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 1.1rem;
    color: var(--text);
    font-weight: 700;
}

.logo span {
    font-size: 1rem;
    color: #4b5563;
}

.header-actions {
    display: flex;
    gap: 12px;
}

.view-layout {
    display: grid;
    grid-template-columns: 1.2fr 0.8fr;
    gap: 24px;
    align-items: start;
    margin-top: 32px;
    padding: 0 32px 32px;
}

.viewer-panel {
    min-height: 520px;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: #111827;
    display: flex;
    align-items: center;
    justify-content: center;
}

.model-details {
    background: var(--card-bg);
    border-radius: var(--radius-lg);
    padding: 28px;
}

.model-details h2 {
    margin-bottom: 16px;
    font-size: 1.75rem;
}

.model-details p {
    margin-bottom: 12px;
    color: #475569;
}

/* ── Modal ── */

.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1000;
    align-items: center;
    justify-content: center;
}

.modal.active {
    display: flex;
}

.modal-backdrop {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(4px);
}

.modal-content {
    position: relative;
    background: var(--card-bg);
    border-radius: 28px;
    width: 90%;
    max-width: 1000px;
    height: 90vh;
    max-height: 680px;
    display: flex;
    flex-direction: column;
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    box-shadow: 0 0 60px rgba(var(--accent-rgb), 0.12);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
}

.modal-content::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: url('../img/motif-circuit.svg');
    background-repeat: repeat;
    background-size: 200px 200px;
    filter: invert(1);
    opacity: 0.1;
    border-radius: inherit;
}

.modal-content > * {
    position: relative;
    z-index: 1;
}

.modal-close {
    position: absolute;
    top: 24px;
    right: 24px;
    left: auto;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: none;
    background: var(--orange);
    color: white;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    transition: opacity 0.15s ease;
}

.modal-close:hover {
    opacity: 0.85;
}

.printer-config-editor-content {
    padding: 28px;
    gap: 14px;
}

.printer-config-editor-header {
    padding-right: 56px;
}

.printer-config-editor-header h2 {
    margin: 0;
    color: var(--text);
    font-size: 1.05rem;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    word-break: break-all;
}

.printer-config-editor-textarea {
    flex: 1;
    min-height: 0;
    width: 100%;
    resize: none;
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg);
    color: var(--text);
    font: 500 0.86rem/1.55 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    tab-size: 4;
}

.printer-config-editor-textarea:disabled {
    opacity: 0.6;
}

.printer-config-editor-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

.modal-body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 32px;
    padding: 32px;
    flex: 1;
    overflow-y: auto;
}

.modal-viewer {
    background: linear-gradient(135deg, #f0f0f0 0%, #e0e0e0 100%);
    border-radius: 16px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 300px;
    position: relative;
}

.modal-viewer canvas {
    width: 100% !important;
    height: 100% !important;
    display: block;
}

.modal-info {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding-right: 12px;
}

.modal-info h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 24px;
    color: var(--text);
}

.info-group {
    margin-bottom: 20px;
}

.info-group label {
    display: block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.info-group p {
    font-size: 1rem;
    color: var(--text);
    margin: 0;
    word-break: break-word;
}

.modal-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 28px;
}

.btn {
    padding: 14px 24px;
    border: none;
    border-radius: 12px;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s ease, transform 0.1s ease;
    text-align: center;
}

.btn:hover {
    opacity: 0.9;
    transform: translateY(-1px);
}

.btn-primary {
    background: var(--green-dark);
    color: white;
}

.btn-accent {
    background: var(--orange);
    color: white;
}

/* ── Language Selector ── */

.lang-switch {
    display: flex;
    align-items: stretch;
    gap: 6px;
    flex: 2;
    padding: 0;
    background: transparent;
    border-radius: 0;
}

body.dark .lang-switch,
body.green .lang-switch {
    background: transparent;
    border: none;
}

.lang-switch-btn {
    flex: 1;
    min-width: 0;
    height: auto;
    padding: 9px 6px;
    border: none;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.lang-switch-btn:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.12);
}

.lang-switch-btn.active {
    background: #22c55e;
    color: #052e12;
    box-shadow: 0 0 12px rgba(34, 197, 94, 0.5);
}

/* El selector de idioma del topbar combina .topbar-menu-item + .lang-switch-btn
   -- .topbar-menu-item.active (más abajo en este archivo) pisaba el color de
   texto de arriba con var(--accent), que es el mismo verde que este fondo:
   texto invisible. Esta regla, más específica, gana pase lo que pase. */
.topbar-menu-item.lang-switch-btn.active {
    color: #052e12;
}

.lang-switch-btn.active:hover {
    background: #22c55e;
}

/* ── Option Switch (settings button groups) ── */

.option-switch {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px;
    background: var(--surface);
    border-radius: var(--radius-md);
}

body.dark .option-switch,
body.green .option-switch {
    background: #111827;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.option-switch-btn {
    flex: 1;
    min-width: 80px;
    height: 40px;
    padding: 0 12px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.option-switch-btn:hover {
    color: var(--text);
}

.option-switch-btn.active {
    background: rgba(34, 197, 94, 0.18);
    color: var(--green-dark);
}

/* ── View Controls ── */

.view-controls {
    display: flex;
    gap: 4px;
}

.btn-view-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    background: transparent;
    border: 1px solid rgba(148, 163, 184, 0.35);
    border-radius: 8px;
    color: var(--text-muted);
    cursor: pointer;
    transition: all 0.15s ease;
}

.btn-view-toggle:hover {
    background: rgba(148, 163, 184, 0.12);
    color: var(--text);
}

.btn-view-toggle-active {
    background: rgba(34, 197, 94, 0.14);
    border-color: rgba(34, 197, 94, 0.4);
    color: var(--green-dark);
}

/* ── Printers Section ── */

.printers-section {
    margin-bottom: 32px;
}

.printers-section h2 {
    font-size: 1.2rem;
    font-weight: 600;
    margin-bottom: 20px;
    color: var(--text);
    /* Este título vive directo sobre el fondo del Panel (sin tarjeta
       detrás) -- con los temas de fondo personalizable (Desert/NOPAL
       Style/Red/Custom) el fondo puede tener zonas claras donde el texto
       blanco se pierde. La sombra da contraste sin importar qué tan clara
       sea la imagen debajo. */
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7), 0 0 12px rgba(0, 0, 0, 0.4);
}

.printers-section .section-title h2 {
    margin-bottom: 0;
}

.printers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px;
    /* Cada ficha mide lo que su contenido pide. Con el estirado por omisión
       de grid, una sola ficha alta -- por ejemplo la que muestra cámara --
       obligaba a TODAS las de su fila a crecer igual, dejándolas con un
       hueco vacío enorme abajo. */
    align-items: start;
}

.machines-columns {
    display: grid;
    grid-template-columns: repeat(var(--machines-visible-columns, 3), minmax(0, 1fr));
    align-items: start;
    gap: 16px;
}

@media (max-width: 900px) {
    .machines-columns {
        grid-template-columns: 1fr;
    }
}

.machines-column {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.machines-column-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    /* Mismo motivo que .printers-section h2: estas etiquetas de grupo
       viven directo sobre el fondo del Panel, sin tarjeta detrás. */
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7), 0 0 12px rgba(0, 0, 0, 0.4);
}

.machines-column-title-printer {
    color: var(--accent);
}

.machines-column-title-laser {
    color: #8b5cf6;
}

.machines-column-title-cnc {
    color: #f59e0b;
}

/* Carga inicial de dispositivos. Se muestra solo durante el primer sondeo;
   las actualizaciones periódicas conservan las fichas para evitar parpadeo.
   Sin tarjeta ni texto a propósito — solo los círculos, flotando sobre el
   fondo de la sección, coloreados según el tipo de máquina de esa columna.
   (El texto "Cargando dispositivos..." y las barras de esqueleto se retiran
   por ahora; se van a reusar en otro lugar más adelante.) */
.device-column-loading {
    position: relative;
    grid-column: 1 / -1;
    min-height: 120px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.device-loading-orbit {
    position: relative;
    width: 48px;
    height: 48px;
}

.device-loading-orbit span {
    position: absolute;
    inset: 3px;
    border: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
    border-radius: 50%;
    animation: deviceLoadingOrbit 2.1s linear infinite;
}

.device-loading-orbit span:nth-child(2) {
    inset: 10px;
    border-color: color-mix(in srgb, var(--accent) 65%, transparent);
    animation-direction: reverse;
    animation-duration: 1.45s;
}

.device-loading-orbit span::after {
    content: '';
    position: absolute;
    top: -3px;
    left: 50%;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 10px var(--accent);
}

.device-loading-orbit i {
    position: absolute;
    inset: 19px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 70%, transparent);
}

.device-loading-orbit-laser span,
.device-loading-orbit-laser span::after,
.device-loading-orbit-laser i {
    --accent: var(--purple);
}

.device-loading-orbit-cnc span,
.device-loading-orbit-cnc span::after,
.device-loading-orbit-cnc i {
    --accent: var(--orange);
}

.device-loading-lines {
    width: min(150px, 72%);
    display: grid;
    gap: 5px;
    margin-top: 4px;
}

.device-loading-lines i {
    display: block;
    height: 3px;
    border-radius: 999px;
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 55%, transparent), transparent);
    background-size: 200% 100%;
    animation: deviceLoadingLine 1.6s linear infinite;
}

.device-loading-lines i:nth-child(2) { width: 78%; animation-delay: -0.35s; }
.device-loading-lines i:nth-child(3) { width: 54%; animation-delay: -0.7s; }

@keyframes deviceLoadingOrbit {
    to { transform: rotate(360deg); }
}

@keyframes deviceLoadingLine {
    from { background-position: 180% 0; }
    to { background-position: -20% 0; }
}

/* Organizador de columnas: reutiliza las filas e interruptores del editor de
   módulos, pero queda encapsulado al dashboard de dispositivos. */
.device-columns-customizer-modal-content {
    width: min(92%, 620px);
    height: auto;
    max-height: 88vh;
}

.device-columns-customizer-group {
    margin-top: 4px;
}

.device-column-customizer-row {
    min-height: 58px;
}

.device-column-customizer-accent {
    width: 12px;
    height: 12px;
    flex: 0 0 12px;
    border-radius: 4px;
    background: currentColor;
    box-shadow: 0 0 12px currentColor;
}

.device-column-customizer-accent-printer { color: var(--accent); }
.device-column-customizer-accent-laser { color: var(--purple); }
.device-column-customizer-accent-cnc { color: var(--orange); }

@media (prefers-reduced-motion: reduce) {
    .device-loading-orbit span,
    .device-loading-lines i {
        animation: none !important;
    }
}

/* Cada columna es una lista vertical de una sola ficha por fila — nunca
   un mosaico de varias columnas internas, sin importar el modo grid/lista.
   El segundo selector agrega ".list-view" a propósito: sube la
   especificidad a 3 clases para ganarle siempre a ".printers-grid.list-view"
   (repeat(2, 1fr), más abajo en este archivo) — antes empataban en
   especificidad y ganaba esa por venir después en el CSS, rompiendo el
   layout de una sola columna apenas se activaba modo lista. */
.machines-columns .printers-grid,
.machines-columns .printers-grid.list-view {
    grid-template-columns: 1fr;
}

.machines-columns .printers-grid:not(.list-view) .printer-card {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
        "top top"
        "status illustration";
    align-items: start;
    padding: 12px;
    gap: 6px 14px;
}

/* Composición térmica del mosaico 3D: la ficha conserva su tamaño y su
   distribución, pero el color deja de ser una capa plana. El resplandor se
   concentra detrás de las ondas y se desvanece hacia los cuatro bordes. */
.machines-columns .printers-grid:not(.list-view) .printer-card-type-3d.online:not(.error) {
    background: linear-gradient(160deg, var(--panel-bg) 0%, var(--card-bg) 100%);
}

.machines-columns .printers-grid:not(.list-view) .printer-card-type-3d .printer-thermal-layer {
    inset: 0;
    opacity: 1;
    background:
        radial-gradient(
            ellipse 92% 42% at 50% 58%,
            color-mix(in srgb, var(--thermal-color) 24%, transparent) 0%,
            color-mix(in srgb, var(--thermal-color) 10%, transparent) 45%,
            transparent 76%
        );
}

.machines-columns .printers-grid:not(.list-view) .printer-card-type-3d .printer-thermal-waves {
    position: absolute;
    top: 35%;
    left: -5%;
    width: 110%;
    height: 34%;
    opacity: calc(var(--thermal-strength, 0.28) + 0.28);
    filter:
        drop-shadow(0 0 4px currentColor)
        drop-shadow(0 0 11px currentColor)
        drop-shadow(0 0 20px var(--thermal-color));
}

/* Estado desconectado: conserva la misma composición luminosa del mosaico,
   pero usa una señal neutra en gris y evita el fondo rojo/plano de error. */
.machines-columns .printers-grid:not(.list-view) .printer-card.offline {
    opacity: 0.82;
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--panel-bg) 94%, var(--text-muted)) 0%,
        color-mix(in srgb, var(--card-bg) 92%, var(--text-muted)) 100%
    );
}

.machines-columns .printers-grid:not(.list-view) .printer-card.offline .printer-thermal-layer {
    inset: 0;
    opacity: 1;
    background: radial-gradient(
        ellipse 92% 42% at 50% 58%,
        color-mix(in srgb, var(--thermal-color) 18%, transparent) 0%,
        color-mix(in srgb, var(--thermal-color) 8%, transparent) 45%,
        transparent 76%
    );
}

.machines-columns .printers-grid:not(.list-view) .printer-card.offline .printer-thermal-waves {
    position: absolute;
    top: 35%;
    left: -5%;
    width: 110%;
    height: 34%;
    opacity: calc(var(--thermal-strength, 0.32) + 0.24);
    filter:
        drop-shadow(0 0 4px currentColor)
        drop-shadow(0 0 10px currentColor)
        drop-shadow(0 0 18px var(--thermal-color));
}

.printer-thermal-layer.is-thermal-offline .printer-thermal-wave-a {
    animation-duration: 14s;
}

.printer-thermal-layer.is-thermal-offline .printer-thermal-wave-b {
    animation-duration: 18s;
}

.printer-thermal-layer.is-thermal-offline .printer-thermal-wave-c {
    animation-duration: 22s;
}

.machines-columns .printers-grid:not(.list-view) .printer-card-type-3d .printer-status-line {
    width: max-content;
    max-width: 100%;
    padding: 5px 10px;
    border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, currentColor 9%, transparent);
    backdrop-filter: blur(4px);
}

.machines-columns .printers-grid:not(.list-view) .printer-card-type-3d .printer-temps {
    box-shadow: inset 0 1px 0 color-mix(in srgb, var(--border) 72%, transparent);
    background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--card-bg) 28%, transparent));
}

.machines-columns .printers-grid:not(.list-view) .printer-card-top {
    grid-area: top;
}

.machines-columns .printers-grid:not(.list-view) .printer-status-line {
    grid-area: status;
    align-self: center;
}

.machines-columns .printers-grid:not(.list-view) .printer-illustration {
    grid-area: illustration;
    justify-self: end;
    align-self: start;
    padding: 0;
}

.machines-columns .printers-grid:not(.list-view) .printer-temps,
.machines-columns .printers-grid:not(.list-view) .printer-progress {
    grid-column: 1 / -1;
}

.machines-columns .printers-grid:not(.list-view) .printer-illustration img {
    width: 64px;
    height: 64px;
}

.machines-columns .printers-grid:not(.list-view) .printer-name {
    font-size: 0.85rem;
}

.machines-columns .printers-grid:not(.list-view) .printer-name-sub {
    font-size: 0.6rem;
}

/* En modo lista las fichas normales asumen mucho ancho horizontal (varios
   campos en fila con min-width propio) — en una columna angosta eso las
   hacía desbordar y encimarse con la columna vecina. Acá se fuerza a que
   todo pueda achicarse o pasar a una segunda línea dentro de la misma
   ficha, sin salirse nunca del ancho de la columna. */
.machines-columns .printers-grid.list-view .printer-card {
    flex-wrap: wrap;
    overflow: hidden;
    padding: 10px 12px 10px 58px;
    gap: 6px 10px;
}

.machines-columns .printers-grid.list-view .printer-illustration {
    width: 40px;
    height: 40px;
    left: 8px;
}

.machines-columns .printers-grid.list-view .printer-card.printer-card-thumb-right {
    padding: 10px 58px 10px 12px;
}

.machines-columns .printers-grid.list-view .printer-card.printer-card-thumb-right .printer-illustration {
    left: auto;
    right: 8px;
}

.machines-columns .printers-grid.list-view .printer-illustration img {
    width: 40px;
    height: 40px;
}

.machines-columns .printers-grid.list-view .printer-card-top,
.machines-columns .printers-grid.list-view .printer-status-line,
.machines-columns .printers-grid.list-view .printer-temps,
.machines-columns .printers-grid.list-view .printer-temps .temp-item,
.machines-columns .printers-grid.list-view .printer-progress,
.machines-columns .printers-grid.list-view .printer-quick-actions {
    min-width: 0;
}

.machines-columns .printers-grid.list-view .printer-name {
    font-size: 0.85rem;
}

.machines-columns .printers-grid.list-view .printer-name-sub {
    font-size: 0.68rem;
}

.printers-grid.list-view {
    grid-template-columns: repeat(2, 1fr);
}

@media (max-width: 900px) {
    .printers-grid.list-view {
        grid-template-columns: 1fr;
    }
}

.printers-grid.list-view .printer-card {
    position: relative;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    padding: 12px 16px 12px 88px;
}

.printers-grid.list-view .printer-card-top {
    flex: 1;
    min-width: 90px;
}

.printers-grid.list-view .printer-illustration {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    margin-top: 0;
    flex-shrink: 0;
    width: 72px;
    height: 72px;
    padding: 0;
    background: transparent;
    z-index: 2;
    filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.35));
}

.printers-grid.list-view .printer-card.printer-card-thumb-right {
    padding: 12px 88px 12px 16px;
}

.printers-grid.list-view .printer-card.printer-card-thumb-right .printer-illustration {
    left: auto;
    right: 10px;
}

.printers-grid.list-view .printer-illustration img {
    width: 72px;
    height: 72px;
    max-width: none;
}

.printers-grid.list-view .printer-status-line {
    flex-shrink: 0;
    min-width: 90px;
}

.printers-grid.list-view .printer-temps {
    display: flex;
    gap: 10px;
    flex-shrink: 0;
}

.printers-grid.list-view .printer-temps .temp-item {
    min-width: 56px;
}

.printers-grid.list-view .printer-progress {
    flex: 1;
    min-width: 100px;
}

/* La fila de la ficha en modo lista asume bastante ancho horizontal (varios
   campos con min-width propio, igual que ".machines-columns ... list-view"
   más arriba, que ya recibió este mismo ajuste). Fuera de las columnas
   agrupadas por tipo (grid mixto de una sola columna) esto no se corrigió,
   así que en modo lista sin agrupar la ficha desbordaba en un teléfono. */
@media (max-width: 560px) {
    .printers-grid.list-view .printer-card {
        flex-wrap: wrap;
        padding: 12px 16px 12px 80px;
        gap: 8px 10px;
    }

    .printers-grid.list-view .printer-card.printer-card-thumb-right {
        padding: 12px 80px 12px 16px;
    }

    .printers-grid.list-view .printer-illustration,
    .printers-grid.list-view .printer-card.printer-card-thumb-right .printer-illustration {
        width: 56px;
        height: 56px;
    }

    .printers-grid.list-view .printer-illustration img {
        width: 56px;
        height: 56px;
    }

    .printers-grid.list-view .printer-card-top,
    .printers-grid.list-view .printer-status-line,
    .printers-grid.list-view .printer-temps,
    .printers-grid.list-view .printer-temps .temp-item,
    .printers-grid.list-view .printer-progress,
    .printers-grid.list-view .printer-quick-actions {
        min-width: 0;
    }
}

.printer-card {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: var(--panel-bg);
    border-radius: var(--radius-lg);
    border-left: 4px solid transparent;
    padding: 19px;
    box-shadow: 0 1px 8px rgba(0, 0, 0, 0.06);
    transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.2s ease;
    display: flex;
    flex-direction: column;
    gap: 13px;
    cursor: pointer;
}

/* Contenedor de la miniatura de cámara vinculada (ver camera-card.js,
   plugin camera-viewer) -- vacío por default (la mayoría de las tarjetas no
   tienen ninguna cámara vinculada), así que no debe ocupar espacio ni sumar
   el gap del flex column de .printer-card cuando no hay nada montado
   adentro (mismo criterio que .panel-load-chart:empty en el panel de
   inicio). */
.printer-card-camera:empty { display: none; }

/* Tarjetas de cámara en las secciones dedicadas de Láser/CNC (ver
   #laser-modal-camera / #cnc-modal-camera en index.html, montadas desde
   renderLaserHostOptions/renderCncHostOptions) -- ocultas por completo
   (encabezado incluido) cuando el dispositivo activo no tiene cámara
   vinculada, no solo el contenedor interno vacío. */
.laser-card-camera:has(#laser-modal-camera:empty),
.cnc-card-camera:has(#cnc-modal-camera:empty) { display: none; }

/* La pestaña "Cámara" del hub de Conexión del láser (#laser-connection-card)
   se oculta igual que antes se ocultaba toda la tarjeta -- sin cámara
   vinculada al dispositivo activo, no tiene sentido ofrecer esa pestaña. */
#laser-connection-card:has(#laser-modal-camera:empty) .laser-hub-tabs [data-value="camera"] {
    display: none;
}

/* Ondas térmicas: una única capa SVG decorativa por impresora, alimentada
   por las temperaturas reales. Todas las transformaciones corren en CSS y
   no crean ciclos JavaScript adicionales durante el sondeo del dashboard. */
.printer-card > :not(.printer-thermal-layer) {
    position: relative;
    z-index: 1;
}

.printer-thermal-layer {
    position: absolute;
    z-index: 0;
    top: 0;
    right: -8%;
    bottom: 0;
    left: -8%;
    overflow: hidden;
    color: var(--thermal-color, var(--accent));
    opacity: var(--thermal-strength, 0.28);
    pointer-events: none;
    contain: paint;
    transition: color 0.8s ease, opacity 0.8s ease;
}

.printer-thermal-waves {
    width: 100%;
    height: 100%;
    overflow: visible;
    filter: drop-shadow(0 0 5px currentColor);
}

.printer-thermal-wave {
    fill: none;
    stroke: currentColor;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
    transform-box: fill-box;
    transform-origin: center;
    will-change: transform;
}

.printer-thermal-wave-a {
    stroke-width: 2.8;
    opacity: 0.95;
    animation: printerThermalWaveA 60s ease-in-out infinite alternate;
    animation-delay: var(--thermal-delay, 0s);
}

.printer-thermal-wave-b {
    stroke-width: 1.8;
    opacity: 0.62;
    animation: printerThermalWaveB 60s ease-in-out infinite alternate-reverse;
    animation-delay: var(--thermal-delay, 0s);
}

.printer-thermal-wave-c {
    stroke-width: 1.2;
    opacity: 0.42;
    animation: printerThermalWaveC 60s ease-in-out infinite alternate;
    animation-delay: var(--thermal-delay, 0s);
}

/* La temperatura solo cambia --thermal-color (ver más abajo) -- el ciclo de
   la ola es siempre el mismo, sin importar el estado térmico. */

.printer-thermal-layer.is-thermal-error {
    opacity: 0.16;
}

@keyframes printerThermalWaveA {
    from { transform: translate3d(-4%, -2%, 0) scaleY(0.92); }
    to { transform: translate3d(4%, 3%, 0) scaleY(1.08); }
}

@keyframes printerThermalWaveB {
    from { transform: translate3d(5%, 3%, 0) scaleY(1.06); }
    to { transform: translate3d(-5%, -3%, 0) scaleY(0.9); }
}

@keyframes printerThermalWaveC {
    from { transform: translate3d(-3%, 4%, 0) scaleY(0.88); }
    to { transform: translate3d(6%, -4%, 0) scaleY(1.12); }
}

@media (prefers-reduced-motion: reduce) {
    .printer-thermal-wave {
        animation: none !important;
        transform: none !important;
        will-change: auto;
    }
}

.printer-card.printing::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 4px;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    background: linear-gradient(90deg, transparent 0%, var(--card-wave-color, #22c55e) 50%, transparent 100%);
    background-size: 220% 100%;
    animation: cardBorderWave 1.8s linear infinite;
    pointer-events: none;
    z-index: 3;
}

.printer-card-type-3d.printing::before {
    --card-wave-color: #22c55e;
}

.printer-card-type-laser.printing::before {
    --card-wave-color: #8b5cf6;
}

.printer-card-type-cnc.printing::before {
    --card-wave-color: var(--orange);
}

@keyframes cardBorderWave {
    0% { background-position: -120% 0; }
    100% { background-position: 120% 0; }
}

.printer-card:hover {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.09);
    transform: translateY(-2px);
}

.printer-card.offline {
    opacity: 0.7;
}

/* Acento por tipo de máquina */
.printer-card-type-3d {
    border-left-color: #22c55e;
}

/* Marlin comparte la columna de impresoras 3D con Klipper y las marcas de
   red, pero conserva un filo cian inequívoco en el panel y su sección. */
.printer-card-type-3d.printer-card-connection-marlin {
    border-left-color: #22d3ee;
    box-shadow: inset 3px 0 12px rgba(34, 211, 238, 0.12), 0 1px 8px rgba(0, 0, 0, 0.06);
}

.printer-card-type-3d.printer-card-connection-marlin:hover {
    box-shadow: inset 3px 0 15px rgba(34, 211, 238, 0.2), 0 8px 24px rgba(0, 0, 0, 0.09);
}

.printer-card-type-laser {
    border-left-color: #8b5cf6;
}

.printer-card-type-cnc {
    border-left-color: var(--orange);
}

/* Fondo tintado por estado */
.printer-card.printing {
    background: rgba(34, 197, 94, 0.22);
}

.printer-card.paused {
    background: rgba(245, 158, 11, 0.22);
}

.printer-card.heating {
    background: rgba(245, 158, 11, 0.22);
}

.printer-card.error {
    background: rgba(239, 68, 68, 0.22);
}

.printer-card.offline,
.printer-card.offline.error {
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--panel-bg) 95%, var(--text-muted)) 0%,
        color-mix(in srgb, var(--card-bg) 93%, var(--text-muted)) 100%
    );
}

.printer-card.printer-card-warm {
    background: linear-gradient(160deg, rgba(194, 101, 12, 0.28) 0%, rgba(87, 38, 8, 0.32) 100%);
    transition: background 0.5s ease;
}

.printer-card.printer-card-cool {
    background: linear-gradient(160deg, rgba(96, 165, 250, 0.2) 0%, rgba(15, 23, 42, 0.28) 100%);
    transition: background 0.5s ease;
}

.printer-card-warm .temp-value,
.printer-card-warm .printer-name-sub {
    color: #ffedd5;
}

.printer-card-cool .temp-value,
.printer-card-cool .printer-name-sub {
    color: #dbeafe;
}

.printer-card-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
}

.printer-name {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.printer-name-sub {
    font-size: 0.64rem;
    color: var(--text-muted);
    margin: 2px 0 0;
}

.printer-status-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #999;
    flex-shrink: 0;
}

.printer-status-icon.online {
    color: var(--green-dark);
}

.printer-status-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.72rem;
    font-weight: 600;
    color: #999;
}

.printer-status-line.printing {
    color: #22c55e;
}

.printer-status-line.paused {
    color: #f59e0b;
}

.printer-status-line.heating {
    color: #f59e0b;
}

.printer-status-line.error {
    color: #ef4444;
}

.printer-status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #999;
    flex-shrink: 0;
}

.printer-status-dot.printing {
    background: #22c55e;
}

.printer-status-dot.paused {
    background: #f59e0b;
}

.printer-status-dot.heating {
    background: #f59e0b;
}

.printer-status-dot.error {
    background: #ef4444;
}

.printer-illustration {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    min-height: 0;
    padding: 4px 0;
    border-radius: var(--radius-md);
}

.printer-illustration img {
    width: 100%;
    height: 100%;
    max-width: 220px;
    object-fit: contain;
}

/* El apagado va por CONEXIÓN, no por estado de trabajo. Antes lo llevaba
   .printer-illustration-idle -- que es una máquina EN LÍNEA y libre -- así
   que lo de siempre se veía descolorido y lo desconectado a todo color,
   justo al revés. De paso, esa transparencia era la razón por la que las
   ondas se veían ATRAVESANDO la máquina: no estaban encima, se
   transparentaban a través de una imagen a media opacidad. */
.printer-card.offline .printer-illustration img,
.printer-card.offline .printer-illustration-error img {
    opacity: 0.55;
    filter: grayscale(0.9);
}

/* Conectada: la máquina se ve entera y tapa las ondas, que es su lugar. */
.printer-card:not(.offline) .printer-illustration img {
    opacity: 1;
    filter: none;
}

.laser-dashboard-metric {
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 0.76rem;
}

.printer-temps {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

/* Doble extrusor (cama + T0 + T1) -- ver marlinPrinterCardHtml en app.js */
.printer-temps.printer-temps-triple {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.temp-label {
    font-size: 0.68rem;
    color: var(--text-muted);
    margin-bottom: 5px;
}

.temp-value {
    font-size: 1.12rem;
    font-weight: 700;
    color: var(--orange);
}

.temp-unit {
    font-size: 0.68rem;
    color: var(--orange);
    margin-left: 2px;
}

.printer-progress-labels {
    display: flex;
    justify-content: space-between;
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--green-dark);
    margin-bottom: 6px;
}

.temp-progress {
    height: 6px;
    background: rgba(148, 163, 184, 0.25);
    border-radius: 999px;
    overflow: hidden;
}

.temp-progress-fill {
    height: 100%;
    border-radius: 999px;
    background: var(--green-dark);
    transition: width 0.3s ease;
}

/* Botones de pausar/reanudar/cancelar de la tarjeta de impresora Elegoo —
   sin modal de detalle (SDCP no expone jog/homing), así que quedan directo
   en la ficha en vez de en un panel aparte. */
.elegoo-card-actions {
    display: flex;
    gap: 8px;
}

.elegoo-card-action-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 10px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--card-bg);
    color: var(--text);
    font-size: 0.72rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

.elegoo-card-action-btn:hover {
    transform: translateY(-1px);
}

.elegoo-card-action-pause {
    border-color: var(--green-dark);
    color: var(--green-dark);
    background: color-mix(in srgb, var(--green-dark) 14%, transparent);
}

.elegoo-card-action-pause:hover {
    background: color-mix(in srgb, var(--green-dark) 24%, transparent);
}

.elegoo-card-action-cancel {
    border-color: var(--orange);
    color: var(--orange);
    background: color-mix(in srgb, var(--orange) 14%, transparent);
}

.elegoo-card-action-cancel:hover {
    background: color-mix(in srgb, var(--orange) 24%, transparent);
}

.printer-quick-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.printer-quick-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    flex-shrink: 0;
    border: 1px solid rgba(96, 165, 250, 0.35);
    border-radius: 50%;
    background: rgba(96, 165, 250, 0.14);
    color: #60a5fa;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
}

.printer-quick-action-btn:hover {
    background: rgba(96, 165, 250, 0.24);
}

.printer-quick-action-btn-accent {
    border-color: rgba(249, 115, 22, 0.35);
    background: rgba(249, 115, 22, 0.14);
    color: #f97316;
}

.printer-quick-action-btn-accent:hover {
    background: rgba(249, 115, 22, 0.24);
}

.btn {
    padding: 14px 24px;
    border: none;
    border-radius: 12px;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s ease, transform 0.1s ease;
    text-align: center;
}

.btn:hover {
    opacity: 0.9;
    transform: translateY(-1px);
}

.btn-primary {
    background: var(--green-dark);
    color: white;
}

.btn-accent {
    background: var(--orange);
    color: white;
}

/* ── Responsive ── */

@media (max-width: 1100px) {
    .panel-hero-grid {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto auto auto;
        grid-template-areas:
            "estado host"
            "dispositivos red"
            "trabajos trabajos";
    }

    .panel-row-bottom {
        grid-template-columns: 1fr 1fr;
    }
}

@media (max-width: 768px) {
    .app-shell {
        grid-template-columns: 1fr;
    }

    /* ── Sidebar → cajón lateral deslizable ──
       Antes el sidebar completo desaparecía (display:none) sin ninguna
       forma de volver a abrirlo: en mobile la navegación quedaba
       completamente inutilizable. Ahora se convierte en un cajón fijo que
       se desliza desde la izquierda, controlado por el botón hamburguesa
       (#mobile-nav-toggle-btn) y la clase .mobile-nav-open en .app-shell
       (ver app.js). Tocar el fondo oscuro (.mobile-nav-backdrop) o un
       ítem de navegación también lo cierra. */
    .topbar-icon-btn.mobile-nav-toggle-btn {
        display: inline-flex;
    }

    /* El botón de contraer/expandir a modo solo-íconos es una optimización
       de escritorio (más espacio de contenido); en un cajón que ya se
       cierra solo, el modo ícono no aporta nada y complica el layout. */
    .sidebar-toggle-btn {
        display: none;
    }

    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 150;
        width: 82vw;
        max-width: 300px;
        height: 100vh;
        transform: translateX(-100%);
        box-shadow: 10px 0 30px rgba(0, 0, 0, 0.35);
        transition: transform 0.25s ease;
    }

    .app-shell.mobile-nav-open .sidebar {
        transform: translateX(0);
    }

    .app-shell.mobile-nav-open .mobile-nav-backdrop {
        display: block;
    }

    /* La topbar (reloj, notificaciones, idioma, usuario) quedaba visible
       por debajo del fondo oscuro mientras el cajón estaba abierto — se
       veía a través del scrim en vez de desaparecer. Se oculta del todo
       mientras el cajón está abierto; el botón hamburguesa vive dentro de
       ella, pero el cajón ya se puede cerrar tocando el fondo, un ítem de
       navegación o Escape. */
    .app-shell.mobile-nav-open .global-topbar {
        display: none;
    }

    /* Si el usuario dejó guardado el modo "solo íconos" desde escritorio
       (localStorage), estas reglas ganan por orden de cascada (misma
       especificidad, declaradas después) y fuerzan siempre la versión
       expandida con texto dentro del cajón mobile. */
    .app-shell.sidebar-collapsed .sidebar {
        padding: 28px 16px;
    }

    .app-shell.sidebar-collapsed .sidebar-logo-gap {
        display: none;
    }

    .app-shell.sidebar-collapsed .brand-logo {
        display: block;
    }

    .app-shell.sidebar-collapsed .nav-item {
        justify-content: flex-start;
        padding: 11px 15px;
        /* En mobile el cajón siempre se ve "expandido" con texto (ver
           .nav-item span más abajo) aunque localStorage diga "solo
           íconos" -- por eso acá se deshace el ícono liso/monocromo del
           modo contraído de escritorio y vuelven las cajas con color de
           .nav-item / cnc / laser / activo de siempre. */
        background: unset;
        border-color: unset;
        box-shadow: unset;
    }

    .app-shell.sidebar-collapsed .nav-item span {
        display: inline;
    }

    .app-shell.sidebar-collapsed .nav-item svg {
        color: unset;
    }

    .app-shell.sidebar-collapsed .nav-category-header {
        display: flex;
    }

    .app-shell.sidebar-collapsed .nav-category.collapsed .nav-category-items {
        display: none;
    }

    .app-shell.sidebar-collapsed .nav-item-soon-badge,
    .app-shell.sidebar-collapsed .nav-item-badge {
        display: inline-flex;
    }

    .app-shell.sidebar-collapsed .nav-item.has-queue-items::after {
        display: none;
    }

    /* ── Pila fija del Panel: asumía 240px (o 76px contraído) de sidebar
       fijo a la izquierda; con el sidebar convertido en cajón oculto, ese
       hueco quedaba vacío y el dock se veía cortado/corrido fuera de
       pantalla. ── */
    .dashboard-fixed-stack {
        left: 0;
    }

    .app-shell.sidebar-collapsed .dashboard-fixed-stack {
        left: 0;
    }

    .dashboard-dock-body {
        flex-direction: column;
        padding: 14px 16px;
        max-height: 45vh;
    }

    .dashboard-dock-matrix {
        width: auto;
        border-left: none;
        border-top: 1px solid var(--border);
        padding-left: 0;
        padding-top: 14px;
    }

    /* ── Topbar global: compacta lo que no entra en una fila de ~375-420px ── */
    .global-topbar {
        padding: 0 12px;
        gap: 8px;
    }

    .global-topbar-panel-title {
        margin-left: 0;
    }

    .global-topbar-panel-title h1 {
        font-size: 1rem;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .global-topbar-panel-title p {
        display: none;
    }

    .global-topbar-clock {
        display: none;
    }

    .panel-hero-meta {
        padding-right: 0;
        margin-right: 0;
        border-right: none;
    }

    .panel-status-pill {
        padding: 8px 10px;
    }

    .panel-status-text {
        display: none;
    }

    .files-grid {
        grid-template-columns: 1fr;
    }

    .modal-body {
        grid-template-columns: 1fr;
        gap: 20px;
        padding: 20px;
    }

    .modal-content {
        max-height: 90vh;
    }

    .panel-hero-grid {
        grid-template-columns: 1fr;
        grid-template-rows: none;
        grid-template-areas: none;
    }

    .panel-card-pos-trabajos .panel-jobs-list {
        max-height: 190px;
    }

    .panel-row-bottom {
        grid-template-columns: 1fr;
    }

    .panel-devices-row {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ── Modo claro: colores propios de Desert para los pocos textos que
   quedaban con poco contraste ──
   Antes esto era una sombra negra dura (-2px/-2px, sin blur) aplicada a
   una lista enorme de selectores para "salvar" texto blanco/verde brillante
   pensado para fondo oscuro. Con colores ya no válidos (el texto real
   ahora es var(--text)/var(--black), oscuros en Desert) esa sombra se veía
   como un texto duplicado/fantasma. La mayoría de esos selectores ya
   heredan var(--text) correctamente y no necesitan nada especial; acá solo
   quedan los pocos que sí usan un verde/rojo brillante fijo (pensado para
   pop sobre fondo oscuro) con bajo contraste sobre el fondo claro
   (.laser-info-compact-row span ya quedó fijo como var(--text) más arriba,
   junto al resto de esa ficha). */
body.light .laser-step-btn.active,
body.light .btn-file-action,
body.light .laser-air-btn-wide {
    color: var(--accent-green-strong);
}

body.light .laser-fire-btn-wide {
    color: var(--state-danger);
}

/* ── Barra superior: íconos, dropdowns, campana, menú de usuario ── */

.topbar-icon-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 36px;
    padding: 0 10px;
    border: none;
    border-radius: var(--radius-md);
    background: rgba(148, 163, 184, 0.1);
    color: var(--text);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease;
}

.topbar-icon-btn:hover {
    background: rgba(148, 163, 184, 0.2);
}

.topbar-notif-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: #ef4444;
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

.topbar-notif-wrap,
.topbar-lang-wrap,
.topbar-user-wrap {
    position: relative;
}

.topbar-menu-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 200px;
    max-width: 320px;
    padding: 8px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
    z-index: 50;
}

.topbar-menu-header {
    padding: 6px 8px 10px;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
}

.topbar-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 9px 10px;
    border: none;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text);
    font-size: 0.86rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.topbar-menu-item:hover {
    background: rgba(var(--accent-rgb), 0.1);
}

.topbar-menu-item.active {
    color: var(--accent);
    font-weight: 600;
}

.topbar-menu-item-danger {
    color: #ef4444;
}

.topbar-menu-item-danger:hover {
    background: rgba(239, 68, 68, 0.1);
}

.topbar-notif-panel {
    width: 320px;
    max-width: 90vw;
}

.topbar-notif-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 320px;
    overflow-y: auto;
}

.topbar-notif-item {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    width: 100%;
    padding: 8px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    font: inherit;
    font-size: 0.82rem;
    color: var(--text);
    text-align: left;
    cursor: pointer;
}

.topbar-notif-item:hover {
    background: rgba(var(--accent-rgb), 0.1);
}

.topbar-notif-item-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-top: 4px;
    flex-shrink: 0;
}

.topbar-notif-item.severity-error .topbar-notif-item-dot { background: #ef4444; }
.topbar-notif-item.severity-warning .topbar-notif-item-dot { background: #f59e0b; }
.topbar-notif-item.severity-info .topbar-notif-item-dot { background: #3b82f6; }

.topbar-notif-empty {
    padding: 16px 8px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.82rem;
}

.topbar-user-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    padding: 0 10px 0 6px;
    border: none;
    border-radius: var(--radius-md);
    background: rgba(148, 163, 184, 0.1);
    color: var(--text);
    cursor: pointer;
    transition: background 0.15s ease;
}

.topbar-user-btn:hover {
    background: rgba(148, 163, 184, 0.2);
}

.topbar-user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgba(var(--accent-rgb), 0.2);
    color: var(--accent);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    flex-shrink: 0;
}

.topbar-user-name {
    font-size: 0.84rem;
    font-weight: 600;
    max-width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.topbar-menu-user-role {
    padding: 4px 10px 10px;
    font-size: 0.76rem;
    color: var(--text-muted);
    text-transform: capitalize;
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
}

/* ── Overlay de login ── */

.login-overlay {
    position: fixed;
    inset: 0;
    z-index: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(5, 8, 6, 0.72);
    backdrop-filter: blur(6px);
}

.login-card {
    width: 100%;
    max-width: 360px;
    margin: 20px;
    padding: 32px 28px;
    background: var(--card-bg);
    border: 1px solid rgba(var(--accent-rgb), 0.3);
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
    text-align: center;
}

.login-card-logo {
    height: 56px;
    width: auto;
    object-fit: contain;
    margin: 0 auto 16px;
    display: block;
}

/* Selector de idioma del overlay de login/configuración inicial — reusa
   la clase .lang-switch-btn (misma lógica JS que el topbar) pero con sus
   propios colores basados en variables de tema, porque el estilo del
   topbar asume un fondo oscuro fijo y no se ve bien sobre --card-bg claro. */
.login-lang-switch {
    display: flex;
    justify-content: center;
    gap: 6px;
    margin-bottom: 14px;
}

.login-lang-switch .lang-switch-btn {
    flex: 0 0 auto;
    min-width: 48px;
    padding: 6px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--panel-bg);
    color: var(--text-secondary);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.login-lang-switch .lang-switch-btn:hover {
    color: var(--text);
}

.login-lang-switch .lang-switch-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.login-card h2 {
    margin: 0 0 6px;
    font-size: 1.2rem;
    color: var(--text);
}

.login-card-subtitle {
    margin: 0 0 20px;
    font-size: 0.84rem;
    color: var(--text-muted);
}

.login-card form {
    text-align: left;
}

.login-error {
    margin: 4px 0 14px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: rgba(239, 68, 68, 0.12);
    border: 1px solid rgba(239, 68, 68, 0.3);
    color: #ef4444;
    font-size: 0.8rem;
    text-align: center;
}

.login-submit-btn {
    width: 100%;
    justify-content: center;
    margin-top: 4px;
}

@media (max-width: 640px) {
    .topbar-user-name {
        display: none;
    }
}

/* ── Configuración > Usuarios ── */

.users-add-form {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.user-item-role-select {
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--panel-bg);
    color: var(--text);
    font-size: 0.76rem;
    font-family: inherit;
    flex-shrink: 0;
}

.device-status-pill.role-admin {
    background: rgba(139, 92, 246, 0.16);
    color: #8b5cf6;
}

.device-status-pill.role-operador {
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted);
}

/* ── Onboarding tour (spotlight guiado) ── */

.tour-overlay {
    position: fixed;
    inset: 0;
    z-index: 3500;
}

.tour-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
}

.tour-spotlight {
    position: fixed;
    border-radius: var(--radius-md);
    border: 2px solid var(--accent);
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.62);
    pointer-events: none;
    transition: top 0.2s ease, left 0.2s ease, width 0.2s ease, height 0.2s ease;
}

.tour-card {
    position: fixed;
    z-index: 3501;
    width: 320px;
    max-width: calc(100vw - 32px);
    background: var(--card-bg);
    border: 1px solid rgba(var(--accent-rgb), 0.4);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
    padding: 20px;
    transition: top 0.2s ease, left 0.2s ease;
}

.tour-card-counter {
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 8px;
}

.tour-card-title {
    font-size: 1.05rem;
    font-weight: 800;
    color: var(--text);
    margin-bottom: 8px;
}

.tour-card-body {
    font-size: 0.86rem;
    line-height: 1.45;
    color: var(--text-secondary);
    margin-bottom: 18px;
}

.tour-card-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.tour-card-nav {
    display: flex;
    gap: 8px;
}

.tour-btn {
    border: none;
    border-radius: var(--radius-sm);
    padding: 8px 14px;
    font-size: 0.82rem;
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.tour-btn-skip {
    background: transparent;
    color: var(--text-secondary);
    padding-left: 0;
}

.tour-btn-skip:hover {
    color: var(--text);
}

.tour-btn-secondary {
    background: var(--panel-bg);
    color: var(--text);
    border: 1px solid var(--border);
}

.tour-btn-secondary:hover {
    background: var(--border);
}

.tour-btn-secondary:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.tour-btn-primary {
    background: var(--accent);
    color: #fff;
}

.tour-btn-primary:hover {
    background: var(--accent-hover);
}

.tour-btn-primary:active {
    background: var(--accent-active);
}

/* Mostrar/ocultar la miniatura de cámara vinculada de la tarjeta (ver
   ensureCameraToggleButton) -- solo se inyecta cuando el dispositivo tiene
   de verdad una cámara vinculada, mismo estilo que el engranaje de escenas
   LED de abajo para que ambos íconos se sientan parte de la misma familia. */
.printer-card-camera-toggle { width: 30px; height: 30px; flex: 0 0 30px; display: grid; place-items: center; border: 1px solid rgba(148,163,184,.35); border-radius: 9px; background: rgba(15,23,32,.75); color: #94a3b8; cursor: pointer; transition: border-color .15s, background-color .15s, color .15s; }
.printer-card-camera-toggle:not(.is-enabled) { color: #64748b; opacity: .55; }
.printer-card-camera-toggle:not(.is-enabled):hover { border-color: #94a3b8; background: rgba(148,163,184,.13); opacity: .85; }
.printer-card-camera-toggle.is-enabled { border-color: rgba(var(--accent-rgb), .32); background: rgba(7,20,17,.78); color: var(--accent); }
.printer-card-camera-toggle.is-enabled:hover { border-color: var(--accent); background: rgba(var(--accent-rgb), .13); }

/* Configuración de escenas LED por máquina */
.machine-led-settings-btn { width: 30px; height: 30px; flex: 0 0 30px; display: grid; place-items: center; border: 1px solid rgba(148,163,184,.35); border-radius: 9px; background: rgba(15,23,32,.75); color: #94a3b8; cursor: pointer; transition: border-color .15s, background-color .15s, color .15s; }
.machine-led-settings-btn:hover { transform: rotate(18deg); }
.machine-led-settings-btn:not(.is-enabled):hover { border-color: #94a3b8; background: rgba(148,163,184,.13); }
.machine-led-settings-btn.is-enabled { border-color: rgba(34,197,94,.32); background: rgba(7,20,17,.78); color: #55e57d; }
.machine-led-settings-btn.is-enabled:hover { border-color: #22c55e; background: rgba(34,197,94,.13); }
.machine-led-indicator { display: flex; align-items: center; gap: 3px; padding: 5px 7px; flex: 0 0 auto; border: 1px solid rgba(148,163,184,.25); border-radius: 9px; background: rgba(15,23,32,.6); }
.machine-led-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; box-shadow: 0 0 4px currentColor; }
.machine-led-indicator-bars { width: 46px; height: 16px; padding: 0; overflow: hidden; }
.machine-led-bar { display: block; height: 100%; flex-shrink: 0; }
.machine-led-modal { position: fixed; inset: 0; z-index: 10050; display: grid; place-items: center; padding: 20px; background: rgba(1,7,12,.78); backdrop-filter: blur(9px); }
.machine-led-modal[hidden] { display: none; }
.machine-led-dialog { position: relative; width: min(680px, 96vw); max-height: min(850px, 92vh); overflow: auto; padding: 26px; border: 1px solid rgba(34,197,94,.48); border-radius: 24px; background: linear-gradient(145deg, rgba(14,27,31,.98), rgba(8,16,24,.99)); box-shadow: 0 28px 80px rgba(0,0,0,.55), 0 0 40px rgba(34,197,94,.08); color: var(--text); }
.machine-led-close { position: absolute; right: 18px; top: 16px; width: 36px; height: 36px; border: 1px solid rgba(239,68,68,.45); border-radius: 50%; background: rgba(239,68,68,.08); color: #ff6b6b; font-size: 24px; cursor: pointer; }
.machine-led-heading { display: flex; gap: 14px; align-items: center; padding-right: 42px; margin-bottom: 22px; }
.machine-led-tabs { margin-bottom: 18px; }
.machine-led-heading-icon { width: 48px; height: 48px; display: grid; place-items: center; flex: 0 0 48px; border: 1px solid #22c55e; border-radius: 15px; color: #59f17d; background: rgba(34,197,94,.12); font-size: 24px; }
.machine-led-eyebrow { color: #22c55e; font-size: .67rem; letter-spacing: .16em; font-weight: 800; }
.machine-led-heading h2 { margin: 3px 0; font-size: 1.35rem; }
.machine-led-heading p { margin: 0; color: var(--text-secondary); font-size: .85rem; }
.machine-led-loading { padding: 48px; text-align: center; color: var(--text-secondary); }
.machine-led-empty { padding: 34px 20px; border: 1px dashed rgba(34,197,94,.35); border-radius: 18px; text-align: center; background: rgba(34,197,94,.035); }
.machine-led-empty-icon { width: 52px; height: 52px; display: grid; place-items: center; margin: 0 auto 12px; border-radius: 16px; background: rgba(34,197,94,.12); color: #48e270; font-size: 25px; }
.machine-led-empty h3 { margin: 0 0 8px; }
.machine-led-empty p { max-width: 480px; margin: 0 auto 20px; color: var(--text-secondary); line-height: 1.55; }
.machine-led-enable { display: flex; justify-content: space-between; gap: 20px; align-items: center; padding: 15px; border: 1px solid rgba(34,197,94,.28); border-radius: 14px; background: rgba(34,197,94,.055); }
.machine-led-enable span { display: grid; gap: 3px; }
.machine-led-enable small { color: var(--text-secondary); }
.machine-led-enable input { width: 20px; height: 20px; accent-color: #22c55e; }
.machine-led-field { display: grid; gap: 7px; margin-top: 14px; color: var(--text-secondary); font-size: .8rem; }
.machine-led-field select, .machine-led-field input { width: 100%; box-sizing: border-box; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; background: rgba(4,13,20,.72); color: var(--text); }
.machine-led-segment-title { display: flex; justify-content: space-between; margin-top: 22px; color: var(--text); font-size: .86rem; }
.machine-led-segment-title span { color: #55e57d; }
.machine-led-pixels { display: grid; grid-template-columns: repeat(auto-fit, minmax(12px, 1fr)); gap: 5px; margin: 11px 0; }
.machine-led-pixels i { height: 24px; min-width: 10px; border-radius: 5px; background: #26343d; border: 1px solid #3c4c57; }
.machine-led-pixels i.selected { background: #22c55e; border-color: #66ef87; box-shadow: 0 0 10px rgba(34,197,94,.38); }
.machine-led-segment-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.machine-led-protocol-note { margin: 12px 0 0; padding: 10px 12px; border-left: 3px solid #f59e0b; border-radius: 8px; background: rgba(245,158,11,.08); color: #fbbf24; font-size: .78rem; line-height: 1.45; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.machine-led-update-btn { flex-shrink: 0; padding: 6px 12px; border: 1px solid #f59e0b; border-radius: 8px; background: rgba(245,158,11,.16); color: #fbbf24; font-size: .74rem; font-weight: 700; cursor: pointer; white-space: nowrap; }
.machine-led-update-btn:hover { background: rgba(245,158,11,.28); }
.machine-led-colors { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 12px; margin-top: 22px; }
.machine-led-colors > strong { grid-column: 1 / -1; margin-bottom: 3px; }
.machine-led-colors label { display: flex; align-items: center; justify-content: space-between; padding: 9px 11px; border: 1px solid var(--border); border-radius: 10px; color: var(--text-secondary); font-size: .8rem; }
.machine-led-colors input { width: 34px; height: 25px; padding: 0; border: 0; background: transparent; }
.machine-led-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }
.machine-led-primary, .machine-led-secondary { padding: 10px 17px; border-radius: 10px; font-weight: 750; cursor: pointer; }
.machine-led-primary { border: 1px solid #22c55e; background: rgba(34,197,94,.15); color: #55e57d; }
.machine-led-secondary { border: 1px solid var(--border); background: transparent; color: var(--text-secondary); }
.machine-led-primary:disabled { opacity: .5; cursor: wait; }
@media (max-width: 620px) { .machine-led-dialog { padding: 20px 16px; } .machine-led-colors { grid-template-columns: 1fr; } .machine-led-segment-fields { grid-template-columns: 1fr 1fr; } }

/* ── Modal "Actualizar placa" -- dos caminos (descargar a mano / que NOPAL
   lo haga) más el estado en vivo del flasheo automático. ── */
.modal-content.firmware-update-dialog { max-width: 460px; }
.firmware-update-dialog #firmware-update-subtitle { color: var(--text-secondary); font-size: .84rem; margin: 0 0 6px; }
.firmware-update-paths { width: 100%; display: flex; flex-direction: column; gap: 14px; margin-top: 10px; }
.firmware-update-path { border: 1px solid var(--border); border-radius: 14px; padding: 16px; text-align: left; }
.firmware-update-path h3 { margin: 0 0 10px; font-size: .82rem; text-transform: uppercase; letter-spacing: .03em; color: var(--text-secondary); }
.firmware-update-path p { margin: 0 0 12px; font-size: .8rem; color: var(--text-secondary); line-height: 1.5; }
.firmware-update-download-row { display: flex; gap: 8px; flex-wrap: wrap; }
.firmware-update-path-auto { border-color: rgba(34,197,94,.35); background: rgba(34,197,94,.05); }
.firmware-update-divider { display: flex; align-items: center; gap: 10px; color: var(--text-muted); font-size: .72rem; text-transform: uppercase; }
.firmware-update-divider::before, .firmware-update-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.firmware-update-manual-next { margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--border); text-align: left; }
.firmware-update-manual-next ol { margin: 0 0 12px; padding-left: 18px; color: var(--text-secondary); font-size: .78rem; line-height: 1.6; }
.firmware-update-manual-next li { margin-bottom: 4px; }

.firmware-update-status { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 10px 0 4px; width: 100%; }
.firmware-update-ring { position: relative; width: 140px; height: 140px; }
.firmware-update-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.firmware-update-ring-track { fill: none; stroke: rgba(255,255,255,.08); stroke-width: 7; }
.firmware-update-ring-fill {
    fill: none;
    stroke: url(#firmware-ring-gradient);
    stroke-width: 7;
    stroke-linecap: round;
    stroke-dasharray: 264;
    transform-origin: 50px 50px;
}
.firmware-update-ring-text {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    text-align: center;
    font-size: .82rem;
    font-weight: 700;
    color: var(--text);
    padding: 0 18px;
}
.firmware-update-ring-text svg { color: #22c55e; }

.firmware-update-ring.stage-searching .firmware-update-ring-fill { stroke-dashoffset: 190; animation: firmwareRingSpin 1.4s linear infinite; }
.firmware-update-ring.stage-connected .firmware-update-ring-fill { stroke-dashoffset: 130; animation: none; }
.firmware-update-ring.stage-uploading .firmware-update-ring-fill { stroke-dashoffset: 90; animation: firmwareRingSpin 1s linear infinite; }
.firmware-update-ring.stage-done .firmware-update-ring-fill { stroke-dashoffset: 0; animation: none; }
.firmware-update-ring.stage-error .firmware-update-ring-fill { stroke: #ef4444; stroke-dashoffset: 130; animation: none; }
.firmware-update-ring.stage-error .firmware-update-ring-text { color: #ef4444; }

@keyframes firmwareRingSpin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.firmware-update-device-info { display: flex; flex-direction: column; align-items: center; gap: 3px; text-align: center; }
.firmware-update-device-info strong { font-size: .9rem; color: var(--text); }
.firmware-update-device-info span { font-size: .78rem; color: var(--text-secondary); }
.firmware-update-done-label { color: #55e57d; font-weight: 700; }
.firmware-update-error-label { color: #ef4444; }

@media (prefers-reduced-motion: reduce) {
    .firmware-update-ring-fill { animation: none !important; }
}

.material-preheat-dialog {
    width: min(540px, 92vw);
    height: auto;
    max-height: 88vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 28px;
}
.material-preheat-dialog h2 { margin: 4px 0 2px; }
.material-preheat-dialog .material-preheat-list,
.material-preheat-dialog #material-preheat-configure {
    align-self: stretch;
}
.material-preheat-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 20px 0 14px; }
.material-preheat-option { display: grid; grid-template-columns: 1fr auto; gap: 5px 12px; padding: 15px; border: 1px solid var(--border); border-radius: 13px; background: rgba(6,18,25,.72); color: var(--text); text-align: left; cursor: pointer; }
.material-preheat-option:hover { border-color: #f59e0b; background: rgba(245,158,11,.08); }
.material-preheat-option strong { grid-column: 1 / -1; color: #fbbf24; font-size: 1rem; }
.material-preheat-option span { color: var(--text-secondary); font-size: .76rem; }
.material-preheat-option b { color: var(--text); }
.material-preset-editor-list { display: grid; gap: 9px; width: 100%; }
.material-preset-editor-row { display: grid; grid-template-columns: minmax(105px,1.3fr) 1fr 1fr 32px; gap: 8px; align-items: end; padding: 10px; border: 1px solid var(--border); border-radius: 11px; background: rgba(6,18,25,.54); }
.material-preset-editor-row > input, .material-preset-editor-row label { min-width: 0; }
.material-preset-editor-row input { width: 100%; box-sizing: border-box; padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel-bg); color: var(--text); }
.material-preset-editor-row label { display: grid; grid-template-columns: 1fr auto; gap: 4px; position: relative; }
.material-preset-editor-row label span { grid-column: 1 / -1; color: var(--text-secondary); font-size: .66rem; }
.material-preset-editor-row label small { align-self: center; color: var(--text-secondary); }
.material-preset-remove { height: 34px; border: 1px solid rgba(239,68,68,.35); border-radius: 8px; background: rgba(239,68,68,.08); color: #ff6b6b; cursor: pointer; }
.material-preset-add { margin-top: 10px; }
@media (max-width: 620px) { .material-preheat-list { grid-template-columns: 1fr; } .material-preset-editor-row { grid-template-columns: 1fr 1fr 32px; } .material-preset-editor-row > input { grid-column: 1 / -1; } }

/* ── Aviso de bloqueo en celular ── */
/* NOPAL es un dashboard denso (grillas, previews 3D, editores) pensado para
   escritorio/tablet -- en un celular es inutilizable, no solo incómodo. En
   vez de dejar entrar y que se vea roto, se bloquea el acceso y se manda al
   usuario a la app TUNA-Screen, hecha específicamente para pantalla chica.
   Vive fuera de .app-shell, oculto por defecto: solo aparece por debajo de
   640px de ancho (mismo corte que el resto de los media queries del
   archivo), sin necesidad de JS -- así nunca hay un parpadeo de contenido
   antes de que se aplique. */
#mobile-block-overlay {
    display: none;
}

@media (max-width: 640px) {
    #mobile-block-overlay {
        display: flex;
        position: fixed;
        inset: 0;
        z-index: 20000;
        align-items: center;
        justify-content: center;
        padding: 28px 22px;
        background: var(--bg);
    }
    /* La app real queda montada detrás pero inalcanzable -- bloquear scroll
       evita que quede "colgando" debajo del overlay al hacer swipe. */
    body {
        overflow: hidden;
    }
}

.mobile-block-card {
    width: 100%;
    max-width: 360px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 32px 26px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}

.mobile-block-icon {
    width: 56px;
    height: 56px;
    border-radius: var(--radius-md);
    background: rgba(var(--accent-rgb), .12);
    color: var(--accent);
    display: grid;
    place-items: center;
    font-size: 1.6rem;
    margin-bottom: 4px;
}

.mobile-block-card h1 {
    font-size: 1.15rem;
    color: var(--text);
    margin: 0;
}

.mobile-block-card p {
    font-size: .88rem;
    color: var(--text-secondary);
    line-height: 1.5;
    margin: 0;
}

.mobile-block-card .btn {
    width: 100%;
    margin-top: 6px;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* ===========================================================================
   NOPAL Intelligence
   Sin un solo color hardcodeado: todo sale de las variables del tema, para
   que la sección se vea correcta en claro, oscuro, verde, rojo y
   personalizado. El mockup de referencia era verde sobre negro, que es
   simplemente cómo se ve esto con el tema verde oscuro activo.
   =========================================================================== */

.ai-header-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

.ai-conn-pill {
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 600;
    border: 1px solid var(--border-subtle);
    color: var(--text-soft);
    background: var(--surface-sunken);
}
.ai-conn-pill[data-tone="ok"] {
    color: var(--status-ok);
    border-color: var(--status-ok);
    background: rgba(var(--accent-fill-rgb), 0.1);
}

.ai-disabled-notice {
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 24px;
    text-align: center;
    color: var(--text-soft);
}
.ai-disabled-notice p { margin: 0 0 16px; }

/* Rejilla: máquinas arriba a todo lo ancho, asistente y eventos abajo. */
.ai-layout {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    grid-template-areas: "machines machines" "main side";
    gap: 16px;
}
.ai-machines { grid-area: machines; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.ai-main { grid-area: main; min-width: 0; }
.ai-side { grid-area: side; min-width: 0; }

@media (max-width: 1023px) {
    .ai-layout { grid-template-columns: minmax(0, 1fr); grid-template-areas: "machines" "main" "side"; }
}

.ai-card {
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 16px;
}

/* --- Tarjetas de máquina --- */
/* Fichas de máquina del modo IA.

   Todo el color sale del tono del estado (--status-*), incluidos el borde,
   la píldora y los iconos de métricas: así la ficha se ve igual en tema
   claro, oscuro, verde, rojo o IA, que era el pedido explícito. Nada
   hardcodeado.

   La ilustración de la máquina no es decoración: distinguir "TTS 55 PRO" de
   "NOPAL-55-PRO" en una fila de cuatro rectángulos de texto obliga a leer;
   con la foto se reconoce de un golpe. */
.ai-machine-card {
    position: relative;
    background: var(--card-bg);
    border: 1px solid color-mix(in srgb, var(--ai-tone) 35%, var(--border-subtle));
    border-radius: var(--radius-lg);
    padding: 14px 15px 12px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    overflow: hidden;
    /* El tono tiñe apenas el fondo, más fuerte arriba: da profundidad sin
       competir con el fondo del tema. */
    background-image: linear-gradient(160deg, color-mix(in srgb, var(--ai-tone) 12%, transparent), transparent 60%);
    transition: border-color .2s ease, transform .2s ease;
}
.ai-machine-card:hover { transform: translateY(-2px); border-color: var(--ai-tone); }

/* Un solo lugar define el color de cada estado; el resto lo hereda. */
.ai-machine-card { --ai-tone: var(--status-ok); }
.ai-machine-card[data-tone="busy"]  { --ai-tone: var(--status-info); }
.ai-machine-card[data-tone="warn"]  { --ai-tone: var(--status-warn); }
.ai-machine-card[data-tone="error"] { --ai-tone: var(--status-danger); }
.ai-machine-card[data-tone="off"]   { --ai-tone: var(--text-faint); }

.ai-machine-top { display: flex; align-items: center; gap: 11px; min-width: 0; }

.ai-machine-art {
    flex-shrink: 0;
    width: 46px;
    height: 46px;
    border-radius: 12px;
    border: 1px solid color-mix(in srgb, var(--ai-tone) 45%, transparent);
    background: color-mix(in srgb, var(--ai-tone) 10%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.ai-machine-art img { width: 100%; height: 100%; object-fit: cover; }
/* Sin conexión la máquina se ve apagada, no ausente. */
.ai-machine-card[data-tone="off"] .ai-machine-art img { filter: grayscale(1); opacity: .55; }

.ai-machine-id { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.ai-machine-name {
    font-weight: 700;
    font-size: .92rem;
    color: var(--text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ai-machine-pill {
    align-self: flex-start;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .02em;
    padding: 2px 9px;
    border-radius: 999px;
    color: var(--ai-tone);
    border: 1px solid color-mix(in srgb, var(--ai-tone) 45%, transparent);
    background: color-mix(in srgb, var(--ai-tone) 14%, transparent);
}

.ai-machine-detail {
    margin: 0;
    font-size: .78rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-machine-metrics {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    padding-top: 10px;
    border-top: 1px solid var(--border-subtle);
}
.ai-machine-metric {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .76rem;
    font-weight: 600;
    color: var(--text-soft);
    font-variant-numeric: tabular-nums;   /* que no baile al actualizar */
    min-width: 0;
}
.ai-machine-metric svg { color: var(--ai-tone); flex-shrink: 0; }
.ai-machine-metric span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- Conversación --- */
.ai-chat-card { display: flex; flex-direction: column; min-height: 420px; }
.ai-thread {
    flex: 1;
    overflow-y: auto;
    max-height: 460px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px 4px;
}

.ai-msg { max-width: 85%; padding: 10px 14px; border-radius: var(--radius-md); font-size: 0.9rem; line-height: 1.5; }
.ai-msg-user { align-self: flex-end; background: var(--accent-fill); color: var(--accent-on); }
.ai-msg-assistant { align-self: flex-start; background: var(--surface-sunken); color: var(--text-strong); border: 1px solid var(--border-subtle); }
.ai-msg-pending { opacity: 0.65; font-style: italic; }
.ai-msg-text { white-space: pre-wrap; word-break: break-word; }
/* La traza de herramientas consultadas: es lo que hace verificable la
   respuesta, así que se muestra siempre, discreta pero presente. */
.ai-msg-meta { margin-top: 6px; font-size: 0.7rem; color: var(--text-faint); border-top: 1px solid var(--border-subtle); padding-top: 5px; }

.ai-suggestions { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px 0; }
.ai-suggestion {
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    color: var(--text-soft);
    border-radius: 999px;
    padding: 6px 14px;
    font-size: 0.8rem;
    cursor: pointer;
}
.ai-suggestion:hover { border-color: var(--accent-fill); color: var(--accent-ink); }

.ai-composer { display: flex; gap: 8px; align-items: center; }
.ai-question-input {
    flex: 1;
    min-width: 0;
    background: var(--surface-sunken);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-md);
    color: var(--text-strong);
    padding: 11px 14px;
    font-size: 0.9rem;
}
.ai-question-input:focus { outline: none; border-color: var(--accent-fill); }

.ai-send-btn {
    background: var(--accent-fill);
    color: var(--accent-on);
    border: none;
    border-radius: var(--radius-md);
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
}
.ai-send-btn:hover:not(:disabled) { background: var(--accent-fill-hover); }
.ai-send-btn:disabled { opacity: 0.5; cursor: not-allowed; }

.ai-disclaimer { margin: 8px 0 0; font-size: 0.72rem; color: var(--text-faint); text-align: center; }
.ai-empty { color: var(--text-faint); font-size: 0.85rem; text-align: center; padding: 16px 0; margin: 0; }

/* --- Eventos --- */
.ai-events { display: flex; flex-direction: column; gap: 10px; max-height: 460px; overflow-y: auto; }
.ai-event { display: flex; gap: 10px; align-items: flex-start; }
.ai-event-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; background: var(--status-ok); }
.ai-event[data-level="warning"] .ai-event-dot { background: var(--status-warn); }
.ai-event[data-level="error"] .ai-event-dot { background: var(--status-danger); }
.ai-event-body { display: flex; flex-direction: column; min-width: 0; }
.ai-event-message { font-size: 0.82rem; color: var(--text-strong); word-break: break-word; }
.ai-event-meta { font-size: 0.7rem; color: var(--text-faint); }

/* --- Tarjeta de ajustes --- */
.ai-settings-fields { display: flex; flex-direction: column; gap: 14px; margin-top: 14px; }
.ai-field { display: flex; flex-direction: column; gap: 5px; }
.ai-field > span { font-size: 0.85rem; font-weight: 600; color: var(--text-strong); }
.ai-field-hint { font-size: 0.72rem; color: var(--text-faint); }

.ai-text-input {
    background: var(--surface-sunken);
    border: 1px solid var(--border-control);
    border-radius: var(--radius-sm);
    color: var(--text-strong);
    padding: 9px 12px;
    font-size: 0.88rem;
    width: 100%;
}
.ai-text-input:focus { outline: none; border-color: var(--accent-fill); }
.ai-text-input:disabled { opacity: 0.55; cursor: not-allowed; }

/* El aviso de qué datos salen de la red: tiene que verse antes de aceptar,
   no como letra chica después. */
.ai-public-warning {
    background: var(--surface-sunken);
    border: 1px solid var(--status-warn);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
}
.ai-public-warning p { margin: 0 0 8px; font-size: 0.82rem; color: var(--text-strong); }
.ai-public-warning ul { margin: 0 0 10px; padding-left: 20px; font-size: 0.78rem; color: var(--text-soft); }
.ai-public-warning li { margin-bottom: 3px; }
.ai-consent { display: flex; align-items: center; gap: 8px; font-size: 0.82rem; color: var(--text-strong); cursor: pointer; }

.ai-advanced summary { cursor: pointer; font-size: 0.85rem; font-weight: 600; color: var(--text-soft); padding: 6px 0; }
.ai-advanced[open] summary { margin-bottom: 10px; }
.ai-advanced .ai-field { margin-bottom: 10px; }

.ai-settings-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ai-test-result { font-size: 0.8rem; }
.ai-test-result[data-tone="ok"] { color: var(--status-ok); }
.ai-test-result[data-tone="warn"] { color: var(--status-warn); }
.ai-test-result[data-tone="error"] { color: var(--status-danger); }
.ai-test-result[data-tone="pending"] { color: var(--text-faint); }

/* ===========================================================================
   MODO IA
   ---------------------------------------------------------------------------
   Dos interruptores independientes (ver docs/MODO_IA_PLAN.md):

     body.ai              -> la PALETA del modo IA (un tema más, como dark/green/red)
     body[data-ai-active] -> los ELEMENTOS exclusivos del modo IA

   Son ortogonales a propósito. Con la IA encendida y el tema oscuro, la
   píldora y el resto de los elementos siguen ahí, pintados en oscuro. Al
   apagar la IA desaparecen, sin importar el tema. Por eso los elementos NO
   se cuelgan de la clase del tema.
   =========================================================================== */

/* Degradado de marca verde -> cian del logotipo NOPAL Intelligence. Se define
   en :root para que los elementos de IA se vean bien en CUALQUIER tema, y cada
   tema puede ajustarlo si lo necesita. Es color de marca, nunca de estado: una
   máquina con problema se pinta con --status-danger, jamás con esto. */
:root {
    --ai-grad-from: #22C55E;
    --ai-grad-to: #06B6D4;
    --ai-glow: rgba(34, 197, 94, 0.18);
}
body.dark, body.red {
    --ai-grad-from: #4ADE80;
    --ai-grad-to: #22D3EE;
    --ai-glow: rgba(74, 222, 128, 0.14);
}

/* --- La paleta del modo IA ------------------------------------------------
   Claro y frío, tarjetas blancas, acento verde nopal. Mismas variables que
   redefinen dark/green/red/custom: ninguna tarjeta hardcodea un color. */
body.ai {
    /* Blanco dominante, verde y azul del logotipo como acentos, y la arena
       Desert reducida a detalles mínimos (--ai-sand). El fondo aporta el
       ambiente; las superficies se mantienen blancas para que el dato se lea. */
    --surface-base: #F1F6F8;
    --surface-raised: #FFFFFF;
    --surface-sunken: #F7FBFC;
    --surface-nav: #FFFFFF;

    --text-strong: #0D1B26;
    --text-soft: #4E626F;
    --text-faint: #7A8D99;

    --border-subtle: #E2EAEE;
    --border-control: #C0D0D8;

    /* Verde del nopal del logotipo */
    --accent-fill: #16A34A;
    --accent-fill-hover: #15803D;
    --accent-fill-active: #166534;
    --accent-ink: #0F7A38;
    --accent-on: #FFFFFF;
    --accent-fill-rgb: 22, 163, 74;

    --status-ok: #16A34A;
    --status-warn: #C98A2E;
    --status-danger: #EF4444;
    /* Azul del degradado del logotipo, no un azul genérico */
    --status-info: #0EA5E9;

    --green-emphasis: #16A34A;
    --violet: #8B5CF6;

    /* Arena Desert: solo detalles, nunca superficie. Es el guiño al resto de
       la identidad NOPAL dentro de un tema por lo demás frío. */
    --ai-sand: #E7DCC6;
    --ai-sand-soft: #F3EDE1;

    /* --ai-wallpaper la fija applyThemeWallpaper() según lo elegido en
       Configuración > Apariencia -- el url() es solo el respaldo. */
    background-image: var(--ai-wallpaper, url('../img/FONDO1_IA.webp'));
    background-size: cover;
    background-position: center;
    background-attachment: fixed;
    background-repeat: no-repeat;
}

/* Los detalles de arena: separadores y realces sutiles, en dosis pequeñas. */
body.ai .ai-capability-strip { border-color: var(--ai-sand); }
body.ai .ai-capability + .ai-capability { border-left-color: var(--ai-sand); }
body.ai .panel-card-mini { border-top: 2px solid var(--ai-sand-soft); }

/* --- Elementos exclusivos: ocultos salvo con la IA encendida -------------- */
[data-ai-only] { display: none; }
body[data-ai-active="true"] [data-ai-only] { display: revert; }
body[data-ai-active="true"] [data-ai-only].ai-only-flex { display: flex; }

/* Píldora "MODO IA ACTIVADO" de la barra superior */
.ai-mode-pill {
    align-items: center;
    gap: 8px;
    padding: 8px 18px;
    border-radius: 999px;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--ai-grad-to);
    background: linear-gradient(90deg, var(--ai-glow), transparent 60%), var(--surface-raised);
    border: 1px solid var(--ai-grad-from);
}
.ai-mode-pill svg { color: var(--ai-grad-from); flex-shrink: 0; }

/* Ítem "IA activada" del menú lateral: con la IA encendida se vuelve el único
   elemento del nav con relleno de marca — es el indicador de estado, no un
   destino más. */
body[data-ai-active="true"] .nav-item[data-section="ai"] {
    background: linear-gradient(100deg, var(--ai-grad-from), var(--ai-grad-to));
    color: #FFFFFF;
    border-radius: var(--radius-md);
}
body[data-ai-active="true"] .nav-item[data-section="ai"] svg { color: #FFFFFF; }
body[data-ai-active="true"] .nav-item[data-section="ai"]:hover { filter: brightness(1.06); }

/* ── Cortinilla de IA ──────────────────────────────────────────────────────
   Comandos para la sección en la que se está parado, en una cinta que se
   desliza sola. Fija al VIEWPORT, no al flujo del documento -- antes vivía
   como hermana de cada <section> de página, y con las secciones alternando
   display:none/'' quedaba flotando en el hueco que dejaba la sección oculta
   (por eso aparecía encimada con controles del láser, a la mitad de
   Configuración...). Fija, sale de ese flujo por completo: un solo lugar,
   sin importar qué sección esté activa.

   El envoltorio de afuera (.ai-capability-dock) no es visible -- solo
   reserva el ancho del sidebar y centra; mismo patrón de left:240/76px que
   ya usa .dashboard-fixed-stack (el dock de Accesorios/Matriz LED) un poco
   más arriba en este archivo. Va en z-index por encima de ese dock (40) y
   de cualquier contenido de sección, para que nunca quede tapada por nada
   -- y por debajo de los modales reales (3000+), que sí deben cubrirla. */
.ai-capability-dock {
    position: fixed;
    left: 240px;
    right: 0;
    bottom: 18px;
    z-index: 2000;
    justify-content: center;
    padding: 0 24px;
    pointer-events: none;
}
.app-shell.sidebar-collapsed .ai-capability-dock { left: 76px; }
@media (max-width: 768px) {
    /* El sidebar es un cajón flotante en móvil, no ocupa columna. */
    .ai-capability-dock { left: 0; bottom: 12px; padding: 0 16px; }
}

/* El dock de Accesorios/Matriz LED (.dashboard-fixed-stack, ver más arriba
   en este archivo) también vive pegado al fondo, en la misma franja
   horizontal. Con la IA encendida se corre hacia arriba lo que ocupa la
   cortinilla, para que ninguna de las dos tape a la otra -- el pedido
   explícito era que la cortinilla quedara "abajo de todo, sola, sin que
   nada la acompañe", y eso incluye no compartir sitio con este dock. */
body[data-ai-active="true"] .dashboard-fixed-stack { bottom: 78px; }

/* La cortinilla es fixed/fuera del flujo -- no empuja contenido, así que
   cualquier sección cuyo scroll llegue hasta el fondo real de la ventana
   (ej. la vista mosaico de la biblioteca con muchas filas) termina con sus
   últimas tarjetas tapadas por la píldora. Mismos 78px que ya se usan para
   correr .dashboard-fixed-stack -- reserva ese mismo espacio en el scroll
   principal para que el contenido pare antes de llegar a la cortinilla. */
body[data-ai-active="true"] .content { padding-bottom: 78px; }

.ai-capability-strip {
    pointer-events: auto;
    position: relative;
    width: 100%;
    max-width: 860px;
    overflow: hidden;
    padding: 12px 0;
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    box-shadow: 0 14px 34px rgba(0, 0, 0, .2);
    /* Los bordes de la píldora difuminan el texto en vez de cortarlo en
       seco: se nota que la cinta sigue de largo hacia los dos lados. */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}

/* El contenido real se duplica al armarlo en JS (ver aiRenderCapabilityStrip)
   y la cinta se desliza hasta -50%: ahí empieza la segunda copia, idéntica a
   la primera, así que el salto de vuelta a 0% es invisible y el desfile no
   se corta nunca. */
.ai-capability-track {
    display: flex;
    align-items: center;
    gap: 28px;
    width: max-content;
    padding: 0 28px;
    animation: aiCapabilityScroll 34s linear infinite;
}
.ai-capability-strip:hover .ai-capability-track,
.ai-capability-strip:focus-within .ai-capability-track {
    animation-play-state: paused; /* para poder leer y hacer clic sin perseguirla */
}
@keyframes aiCapabilityScroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
    .ai-capability-track { animation: none; }
}

.ai-capability {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    font-size: .82rem;
    color: var(--text-soft);
    white-space: nowrap;
    cursor: pointer;
}
.ai-capability svg { color: var(--ai-grad-from); flex-shrink: 0; }
.ai-capability:hover, .ai-capability:focus-visible { color: var(--text-strong); }
.ai-capability + .ai-capability { border-left: 1px solid var(--border-subtle); padding-left: 28px; }

/* Marca de la barra lateral: con la IA encendida el logotipo pasa a
   NOPAL Intelligence. Si el archivo del logotipo aún no está en
   /static/img/, el degradado del texto mantiene la identidad y nada se rompe. */
body[data-ai-active="true"] .sidebar-ai-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 2px 10px;
}
.sidebar-ai-brand-text {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    background: linear-gradient(90deg, var(--ai-grad-from), var(--ai-grad-to));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* Marca de la barra lateral en modo IA: el logotipo completo cuando hay
   ancho, el isotipo solo cuando la barra está colapsada o en móvil. */
.sidebar-ai-brand-logo { max-width: 100%; height: auto; display: block; }
.sidebar-ai-brand-mark { width: 34px; height: auto; display: none; }
.sidebar.collapsed .sidebar-ai-brand-logo,
.sidebar-collapsed .sidebar-ai-brand-logo { display: none; }
.sidebar.collapsed .sidebar-ai-brand-mark,
.sidebar-collapsed .sidebar-ai-brand-mark { display: block; margin: 0 auto; }

/* Las tarjetas del panel ya heredan la paleta del modo IA por las variables,
   así que aquí solo van los ajustes que el modelo de muestra pide y que las
   variables no cubren: superficie blanca sobre fondo frío y borde más suave. */
body.ai .panel-card {
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    box-shadow: 0 1px 2px rgba(14, 28, 40, 0.04);
}
body.ai .panel-card-mini { align-items: center; }

/* La sección de IA seguía la convención de las demás en el marcado pero no en
   el espaciado: .view-section y .content no traen padding (cada sección paga
   el suyo, ver .page-header), así que el contenido se pegaba a los bordes y
   el título quedaba cortado contra la barra lateral. */
#ai-section > .section-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 32px 32px 16px;
    flex-shrink: 0;
}
#ai-section > .section-header h1 {
    font-size: 1.6rem;
    margin: 0 0 4px;
    color: var(--text-strong);
}
#ai-section > .section-header .section-subtitle {
    margin: 0;
    color: var(--text-soft);
    font-size: .9rem;
}
#ai-section > .ai-layout,
#ai-section > .ai-disabled-notice {
    padding: 0 32px 32px;
}
/* El padding del aviso va por dentro para no perder su fondo y borde. */
#ai-section > .ai-disabled-notice {
    margin: 0 32px 32px;
    padding: 24px;
}
@media (max-width: 767px) {
    #ai-section > .section-header { padding: 20px 16px 12px; }
    #ai-section > .ai-layout { padding: 0 16px 24px; }
    #ai-section > .ai-disabled-notice { margin: 0 16px 24px; }
}

/* --- Registro de IAs guardadas ------------------------------------------- */
.ai-providers { display: flex; flex-direction: column; gap: 10px; margin-bottom: 6px; }
.ai-providers-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ai-providers-title { font-size: .85rem; font-weight: 600; color: var(--text-strong); }
.ai-providers-list { display: flex; flex-direction: column; gap: 8px; }

.ai-provider-row {
    display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--border-control);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    padding: 10px 12px;
}
/* La activa se distingue por el filo, no por el fondo: así la lista se lee
   igual de bien en los cinco temas. */
.ai-provider-row.is-active { border-left-color: var(--accent-fill); }
.ai-provider-info { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.ai-provider-name { font-size: .88rem; font-weight: 600; color: var(--text-strong); display: flex; align-items: center; gap: 8px; }
.ai-provider-meta { font-size: .74rem; color: var(--text-faint); word-break: break-all; }
.ai-provider-badge {
    font-size: .62rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
    color: var(--accent-ink); border: 1px solid var(--accent-fill);
    border-radius: 999px; padding: 1px 7px; white-space: nowrap;
}
.ai-provider-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.ai-form-title { font-size: .85rem; font-weight: 600; color: var(--text-soft); margin: 6px 0 0; }

/* Editor de preguntas rápidas */
.ai-suggestions-editor { display: flex; flex-direction: column; gap: 8px; }
.ai-suggestions-rows { display: flex; flex-direction: column; gap: 6px; }
.ai-suggestion-row { display: flex; gap: 6px; align-items: center; }
.ai-suggestion-row .ai-text-input { flex: 1; min-width: 0; }

/* Acción pendiente de confirmación en el chat. Se distingue del resto de la
   conversación a propósito: no es un mensaje, es algo que espera decisión. */
.ai-pending-action {
    align-self: stretch;
    border: 1px solid var(--status-warn);
    border-left: 3px solid var(--status-warn);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    background: var(--surface-sunken);
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.ai-pending-head { display: flex; align-items: center; gap: 8px; font-size: .82rem; font-weight: 600; color: var(--status-warn); }
.ai-pending-what { margin: 0; font-size: .85rem; color: var(--text-strong); word-break: break-word; }
.ai-pending-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.ai-pending-done { font-size: .85rem; }
.ai-pending-done[data-tone="ok"] { color: var(--status-ok); }
.ai-pending-done[data-tone="error"] { color: var(--status-danger); }
.ai-pending-done[data-tone="muted"] { color: var(--text-faint); }

/* Historial de conversaciones */
.ai-history-list { display: flex; flex-direction: column; gap: 4px; max-height: 260px; overflow-y: auto; }
.ai-history-row { display: flex; align-items: stretch; gap: 4px; border-radius: var(--radius-sm); }
.ai-history-row.is-active { background: var(--surface-sunken); }
.ai-history-open {
    flex: 1; min-width: 0; text-align: left; background: none; border: none; cursor: pointer;
    padding: 7px 8px; display: flex; flex-direction: column; gap: 1px; color: inherit;
}
.ai-history-open:hover { background: var(--surface-sunken); border-radius: var(--radius-sm); }
.ai-history-title { font-size: .82rem; color: var(--text-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ai-history-meta { font-size: .68rem; color: var(--text-faint); }
.ai-history-del {
    background: none; border: none; cursor: pointer; color: var(--text-faint);
    padding: 0 6px; border-radius: var(--radius-sm); flex-shrink: 0;
}
.ai-history-del:hover { color: var(--status-danger); }

/* ===========================================================================
   MODO IA — tratamiento de superficies flotantes
   ---------------------------------------------------------------------------
   Barra lateral en verde y barra de accesorios en el azul de la marca: fondo
   blanco con poca transparencia y degradado, para que el fondo del taller se
   siga viendo por detrás sin que el texto pierda legibilidad. El contorno y
   las letras del título toman el color correspondiente, este último en un
   tono más fuerte para que contraste sobre el blanco.

   Scoped a body.ai: en los otros temas estas barras no cambian.
   =========================================================================== */

body.ai .sidebar {
    background:
        linear-gradient(160deg, rgba(255, 255, 255, 0.94), rgba(255, 255, 255, 0.80));
    border-right: 1px solid var(--ai-grad-from);
    /* Resplandor: el halo conserva la sensación del tema sin tapar el fondo. */
    box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.10), 0 10px 34px rgba(13, 27, 38, 0.10);
    backdrop-filter: blur(6px);
}
body.ai .sidebar .nav-category-header > span {
    /* Tono más fuerte que el acento para que el rótulo se lea sobre blanco. */
    color: #0F7A38;
}

body.ai .dashboard-dock-body,
body.ai .dashboard-dock-section {
    background:
        linear-gradient(160deg, rgba(255, 255, 255, 0.94), rgba(255, 255, 255, 0.80));
    border: 1px solid var(--ai-grad-to);
    border-radius: var(--radius-md);
    box-shadow: 0 0 0 1px rgba(6, 182, 212, 0.10), 0 10px 34px rgba(13, 27, 38, 0.10);
    backdrop-filter: blur(6px);
}
body.ai .dashboard-dock-section .section-title h2 {
    color: #0E7490;   /* cian más oscuro: legible sobre el blanco translúcido */
}

/* --- Pestañas del panel de trabajos ------------------------------------- */
.panel-tabs {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid var(--border-subtle);
    margin-bottom: 10px;
}
.panel-tab {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-faint);
    font-size: .82rem;
    font-weight: 600;
    padding: 6px 10px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.panel-tab:hover { color: var(--text-soft); }
.panel-tab.active { color: var(--accent-ink); border-bottom-color: var(--accent-fill); }
.panel-tab:focus-visible { outline: 2px solid var(--accent-fill); outline-offset: 2px; }
.panel-tab-pane[hidden] { display: none; }

/* Asistente compacto dentro del panel */
.panel-ai-thread { display: flex; flex-direction: column; gap: 8px; max-height: 190px; overflow-y: auto; padding-right: 2px; }
.panel-ai-composer { display: flex; gap: 6px; margin-top: 8px; }
.panel-ai-composer .ai-question-input { padding: 8px 11px; font-size: .84rem; }
.panel-ai-composer .ai-send-btn { width: 36px; height: 36px; }
.panel-ai-suggestions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.panel-ai-suggestions .ai-suggestion { font-size: .74rem; padding: 4px 10px; }

/* El asistente del panel dejaba un hueco grande: el hilo tenía alto fijo y la
   tarjeta es más alta. Ahora el panel ocupa la tarjeta y el hilo crece.

   Pero crecer no puede ser infinito: esta tarjeta abarca las dos filas del
   hero (grid-area: trabajos), así que cada mensaje nuevo estiraba la fila y
   con ella las cuatro tarjetas de la izquierda, que se quedaban vacías y
   enormes. El tope es del hilo, no de la tarjeta: el hilo se estira hasta
   llenar el alto que le dan las tarjetas vecinas y a partir de ahí scrollea
   dentro de sí mismo, sin empujar nada. El tope de la tarjeta es el techo
   duro por si las vecinas también crecieran. */
.panel-card-pos-trabajos { display: flex; flex-direction: column; min-height: 0; max-height: 52vh; }
.panel-tab-pane { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.panel-tab-pane[hidden] { display: none; }
.panel-ai-thread { flex: 1; min-height: 0; max-height: 34vh; overflow-y: auto; }
.panel-jobs-list { flex: 1; min-height: 0; overflow-y: auto; }

/* Respaldo de configuración */
.backup-groups { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
.backup-group { display: flex; gap: 10px; align-items: flex-start; padding: 8px 10px; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); cursor: pointer; }
.backup-group.is-empty { opacity: .5; cursor: not-allowed; }
.backup-group-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.backup-group-label { font-size: .85rem; color: var(--text-strong); display: flex; align-items: center; gap: 8px; }
.backup-group-text small { font-size: .72rem; color: var(--text-faint); }
.backup-sensitive { font-size: .62rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--status-warn); border: 1px solid var(--status-warn); border-radius: 999px; padding: 1px 7px; }

/* Cronómetro de espera tras un límite de cuota del proveedor de IA.
   El aro tiene radio 15.9155 (circunferencia = 100) para que el
   stroke-dashoffset que escribe app.js sea directamente un porcentaje. */
.ai-cooldown {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 10px;
    border: 1px solid var(--status-warn);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--status-warn) 8%, transparent);
}
/* Sin esto el `display: flex` de arriba le gana al [hidden] del navegador
   (una clase tiene más especificidad) y el cronómetro se vería siempre. */
.ai-cooldown[hidden] { display: none; }
.ai-cooldown-dial { position: relative; width: 42px; height: 42px; flex-shrink: 0; }
.ai-cooldown-dial svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ai-cooldown-dial circle { fill: none; stroke-width: 3; }
.ai-cooldown-track { stroke: color-mix(in srgb, var(--status-warn) 25%, transparent); }
.ai-cooldown-progress {
    stroke: var(--status-warn);
    stroke-linecap: round;
    stroke-dasharray: 100;
    stroke-dashoffset: 0;
}
.ai-cooldown-time {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .68rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;  /* que no baile al cambiar de dígito */
    color: var(--status-warn);
}
.ai-cooldown-label { font-size: .8rem; color: var(--text-muted); line-height: 1.35; }

/* Modo de modelo (fijo / automático) y su tabla de niveles. */
.ai-radio-row { display: flex; gap: 18px; flex-wrap: wrap; margin: 4px 0 2px; }
.ai-radio { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-size: .86rem; color: var(--text-soft); }
.ai-radio input { accent-color: var(--accent-fill); cursor: pointer; }
#ai-tier-models[hidden] { display: none; }
#ai-tier-models .ai-field { margin-top: 10px; }

/* Configuración de IA con la capa apagada: todo lo que cuelga del
   interruptor se ve en gris, para que se lea de un vistazo que no está en
   uso. NO se deshabilita: en una instalación nueva hay que poder llenar
   dirección, modelo y clave ANTES de poder encender la capa. */
.ai-settings-body {
    transition: filter .2s ease, opacity .2s ease;
}
.ai-settings-body.is-off {
    filter: grayscale(1);
    opacity: .55;
}
.ai-settings-body.is-off:focus-within {
    /* Al ponerse a configurar vuelve el color: si no, se estaría llenando
       un formulario a ciegas en escala de grises. */
    filter: none;
    opacity: 1;
}

/* Columna de dispositivos que no se pudo cargar. Lleva botón a propósito:
   con el auto-refresco apagado no hay reintento automático, y sin salida
   visible la columna se quedaba muerta hasta recargar la página. */
.device-load-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    text-align: center;
}
.device-load-error button { align-self: center; }

/* Ficha con cámara en vivo: la cámara es la imagen que importa, así que el
   render de la máquina se encoge a icono y se va junto al título. Con las
   dos ilustraciones a tamaño completo la ficha medía el doble de alto y
   ninguna de las dos se leía mejor por ello.

   Se posiciona sobre la esquina en vez de mover el nodo en el DOM: el orden
   de las secciones de la ficha es configurable por el usuario (ver
   printerCardSectionOrder), y reordenar por JS pelearía con esa opción. */
.printer-card.has-live-camera {
    position: relative;
}
.printer-card.has-live-camera .printer-illustration {
    position: absolute;
    top: 10px;
    left: 12px;
    width: 30px;
    height: 30px;
    min-height: 0;
    flex: none;
    padding: 0;
    margin: 0;
    z-index: 2;          /* por encima de las ondas, como el resto */
}
.printer-card.has-live-camera .printer-illustration img {
    width: 100%;
    height: 100%;
    max-width: none;
}
/* Hueco para el icono, para que no se encime con el nombre. */
.printer-card.has-live-camera .printer-card-top {
    padding-left: 38px;
}

/* ── Fichas de dispositivo ────────────────────────────────────────────────
   Medidas tomadas de la referencia visual: la insignia va dentro del bloque
   del nombre, temperaturas y material comparten un solo panel con divisores,
   y los números que importan (progreso, temperatura) van grandes con la
   unidad más chica.

   Todo el color sale de las variables del tema y del tono del estado
   (--dev-tone), que cada estado redefine una vez. */
.dev-card {
    --dev-tone: var(--status-ok);
    position: relative;
    isolation: isolate;
    /* Las ondas térmicas (.printer-thermal-layer) se dibujan a propósito
       un 8% más anchas que la ficha (ver renderThermalLayer) para que el
       recorte de este overflow, no el suyo propio, les dé un borde
       limpio contra las esquinas redondeadas -- sin esto se salían de la
       ficha y cruzaban por encima de las de al lado. */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 18px;
    background: var(--card-bg);
    border: 1px solid var(--border-subtle);
    border-radius: 20px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
    min-width: 0;
    animation: devCardCategoryPulse 4s ease-in-out infinite;
}
.dev-card[data-tone="warn"]   { --dev-tone: var(--status-warn); }
.dev-card[data-tone="danger"] { --dev-tone: var(--status-danger); }
.dev-card[data-tone="off"]    { --dev-tone: var(--text-faint); }

/* Bisel animado por categoría de máquina: cada columna del dashboard fija
   --dev-category con el mismo color que ya usa su encabezado (IMPRESORA
   3D/LÁSER/CNC, ver .machines-column-title-*). Sin columna que lo fije
   (modo mixto, una sola grilla para todo tipo de máquina) el borde cae al
   neutro de siempre -- no hay un atributo de "tipo" uniforme en la ficha
   para colorear ahí sin una columna que lo indique. */
#printers-grid .dev-card { --dev-category: var(--accent); }
#lasers-grid .dev-card { --dev-category: var(--purple); }
#cnc-grid .dev-card { --dev-category: var(--orange); }

@keyframes devCardCategoryPulse {
    0%, 100% { border-color: color-mix(in srgb, var(--dev-category, var(--border-subtle)) 40%, var(--border-subtle)); }
    50%      { border-color: color-mix(in srgb, var(--dev-category, var(--border-subtle)) 90%, var(--border-subtle)); }
}

/* Desconectada: sin pulso de color -- el gris neutro ya dice "no hay nada
   que mirar aquí", animar un color vivo encima de una máquina apagada
   contradice esa lectura. */
.dev-card[data-tone="off"] {
    animation: none;
    border-color: var(--border-subtle);
}

@media (prefers-reduced-motion: reduce) {
    .dev-card {
        animation: none;
        border-color: color-mix(in srgb, var(--dev-category, var(--border-subtle)) 55%, var(--border-subtle));
    }
}

/* Cabecera: la máquina a la izquierda, y a su derecha nombre, tipo e
   insignia apilados -- los tres alineados entre sí, como en la referencia. */
.dev-card-head { display: flex; align-items: flex-start; gap: 13px; min-width: 0; }
.dev-card-id { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; flex: 1; }
.dev-card-name {
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.2;
    /* Sin columna que fije --dev-category (modo mixto, marcas sin migrar)
       cae al texto fuerte de siempre -- ver la nota de devCardCategoryPulse
       más abajo sobre por qué esa variable solo existe en modo grupo. */
    color: var(--dev-category, var(--text-strong));
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}
.dev-card-type { font-size: .82rem; color: var(--text-muted); }
.dev-card-head-right { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.dev-conn { display: inline-flex; color: var(--text-faint); padding: 4px; }
.dev-conn.is-online { color: var(--status-ok); }

/* Imagen de la máquina: protagonista en reposo, miniatura al trabajar. */
.dev-hero { position: relative; display: flex; justify-content: center; padding: 2px 0; }
.dev-art img { display: block; width: 100%; height: 100%; object-fit: contain; }
.dev-hero .dev-art { width: 100%; max-width: 200px; height: 140px; }
.dev-art.is-thumb { width: 62px; height: 62px; flex-shrink: 0; }
.dev-card[data-tone="off"] .dev-art img { filter: grayscale(1); opacity: .5; }

/* Botón "abrir panel" sobre la imagen grande: la ficha entera ya abre el
   panel al hacer clic, esto es solo la señal visual de que ese gesto existe
   -- apagado hasta el hover para no competir con la máquina como
   protagonista. Solo tiene sentido en vista de imagen/cuadrícula: en modo
   lista la miniatura de 40px no tiene espacio (ver más abajo). */
.dev-hero-open-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border-subtle);
    border-radius: 50%;
    background: color-mix(in srgb, var(--card-bg) 75%, transparent);
    color: var(--text-soft);
    opacity: 0;
    cursor: pointer;
    transition: opacity .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.dev-card:hover .dev-hero-open-btn,
.dev-hero-open-btn:focus-visible {
    opacity: 1;
}
.dev-hero-open-btn:hover {
    color: var(--dev-category, var(--text-strong));
    border-color: var(--dev-category, var(--accent-fill));
    box-shadow: 0 0 10px 1px color-mix(in srgb, var(--dev-category, var(--accent-fill)) 55%, transparent);
}

/* Insignia de estado */
.dev-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-top: 3px;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 5px 13px;
    border-radius: 999px;
    color: var(--dev-tone);
    border: 1px solid color-mix(in srgb, var(--dev-tone) 35%, transparent);
    background: color-mix(in srgb, var(--dev-tone) 12%, transparent);
}
.dev-badge::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* Campos etiqueta/valor */
.dev-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.dev-field-label { font-size: .78rem; color: var(--text-muted); }
.dev-field-value {
    font-size: 1rem;
    color: var(--text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Material: nombre a la izquierda, divisor, carrete del color real del
   filamento y sus datos (diámetro/peso) a la derecha -- un dev-field
   normal no tenía dónde meter el icono ni el divisor interno. */
.dev-field-material { grid-column: 1 / -1; gap: 6px; }
.dev-material-row { display: flex; align-items: center; gap: 12px; min-width: 0; }
.dev-material-name {
    flex: 1;
    min-width: 0;
    font-size: 1rem;
    color: var(--text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Centrada en la fila, no de borde a borde -- estirarla al 100% del alto
   se veía pesada/descentrada apenas el lado de los datos crecía a dos
   líneas y el nombre se quedaba en una sola. Alto fijo a juego con el
   icono grande, no con el contenido de al lado. */
.dev-material-divider { align-self: center; width: 1px; height: 44px; background: var(--border-subtle); flex-shrink: 0; }
.dev-material-icon { display: inline-flex; flex-shrink: 0; color: var(--text-faint); }
.dev-material-icon svg { width: 52px; height: 52px; }
.dev-material-specs {
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 1.45rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-strong);
    white-space: nowrap;
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}
.dev-material-specs small { font-size: .72rem; font-weight: 600; margin-left: 3px; color: var(--text-muted); }

/* Progreso */
.dev-progress {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 15px 16px;
    border: 1px solid var(--border-subtle);
    border-radius: 14px;
    background: var(--surface-sunken);
}
.dev-progress-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.dev-progress-pct {
    display: block;
    margin-top: 2px;
    font-size: 2rem;
    font-weight: 700;
    line-height: 1;
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}
.dev-progress-right { text-align: right; }
.dev-progress-remaining {
    display: block;
    margin-top: 2px;
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1;
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}
.dev-progress-track {
    height: 9px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-faint) 22%, transparent);
    overflow: hidden;
}
.dev-progress-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--dev-tone) 70%, transparent), var(--dev-tone));
    transition: width .4s ease;
}

/* Panel de datos: temperaturas arriba, material y capa abajo, todo en una
   sola caja separada por divisores. */
.dev-panel {
    border: 1px solid var(--border-subtle);
    border-radius: 14px;
    background: var(--surface-sunken);
    overflow: hidden;
}
.dev-metrics { display: grid; grid-template-columns: repeat(2, 1fr); }
.dev-metric {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 14px 16px;
    min-width: 0;
}
.dev-metric + .dev-metric { border-left: 1px solid var(--border-subtle); }
/* Al doble: a 14 px estos iconos se leían como un par de rayas sueltas. */
.dev-metric-icon { display: inline-flex; color: var(--dev-tone); flex-shrink: 0; }
.dev-metric-icon svg { width: 28px; height: 28px; }
.dev-metric-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dev-metric-label { font-size: .78rem; color: var(--text-muted); }
.dev-metric-value {
    font-size: 1.45rem;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}
.dev-metric-value small { font-size: .72rem; font-weight: 600; margin-left: 3px; color: var(--text-muted); }
.dev-info { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 16px; padding: 14px 16px; }
/* Un campo solo ocupa la fila entera. El material trae nombres largos
   ("Kingroom AZUL 1.75mm PLA") y a media columna se cortaba a la mitad. */
.dev-info > .dev-field:only-child { grid-column: 1 / -1; }
.dev-metrics + .dev-info { border-top: 1px solid var(--border-subtle); }

/* Acciones */
.dev-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(74px, 1fr)); gap: 9px; margin-top: 2px; }
.dev-action {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 6px;
    border: 1px solid var(--border-subtle);
    border-radius: 14px;
    background: transparent;
    color: var(--text-soft);
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    text-align: center;
    line-height: 1.2;
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.dev-action svg { width: 21px; height: 21px; }
/* El resplandor usa el mismo --dev-category del bisel de la ficha: sin
   columna que lo fije (modo mixto) cae al acento de siempre. */
.dev-action:hover {
    border-color: var(--dev-category, var(--accent-fill));
    color: var(--dev-category, var(--text-strong));
    box-shadow: 0 0 8px 1px color-mix(in srgb, var(--dev-category, var(--accent-fill)) 45%, transparent);
}
/* Las acciones con consecuencia se tiñen del color de su consecuencia. */
.dev-action-ok {
    color: var(--status-ok);
    border-color: color-mix(in srgb, var(--status-ok) 30%, transparent);
    background: color-mix(in srgb, var(--status-ok) 9%, transparent);
}
.dev-action-warn {
    color: var(--status-warn);
    border-color: color-mix(in srgb, var(--status-warn) 30%, transparent);
    background: color-mix(in srgb, var(--status-warn) 9%, transparent);
}
.dev-action-danger {
    color: var(--status-danger);
    border-color: color-mix(in srgb, var(--status-danger) 30%, transparent);
    background: color-mix(in srgb, var(--status-danger) 9%, transparent);
}
.dev-action-primary {
    grid-column: 1 / -1;
    flex-direction: row;
    gap: 9px;
    padding: 14px;
    font-size: .8rem;
    color: #fff;
    background: var(--status-ok);
    border-color: var(--status-ok);
}
.dev-action-primary:hover {
    color: #fff;
    filter: brightness(1.06);
    box-shadow: 0 0 10px 1px color-mix(in srgb, var(--dev-category, var(--status-ok)) 55%, transparent);
}

.dev-camera { border-radius: 14px; overflow: hidden; }

@media (max-width: 520px) {
    .dev-metrics { grid-template-columns: 1fr; }
    .dev-metric + .dev-metric { border-left: none; border-top: 1px solid var(--border-subtle); }
    .dev-info { grid-template-columns: 1fr; }
}

/* Botón e indicador de alertas visuales LED: los inyecta el plugin de
   accesorios en la cabecera de cada ficha (ver decorateMachineCardsWithLedSettings),
   no vienen en el marcado. Acá solo se les da el tamaño de la cabecera nueva. */
.dev-card-head-right .machine-led-settings-btn,
.dev-card-head-right .machine-led-indicator {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    border: none;
    background: none;
    color: var(--text-faint);
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.dev-card-head-right .machine-led-settings-btn:hover {
    color: var(--dev-category, var(--text-strong));
    background: var(--surface-sunken);
    box-shadow: 0 0 8px 1px color-mix(in srgb, var(--dev-category, var(--accent-fill)) 45%, transparent);
}
.dev-card-head-right .machine-led-settings-btn.is-enabled { color: var(--status-ok); }

/* ── Ficha de dispositivo en modo lista ───────────────────────────────────
   El panel tiene un selector de vista y la ficha nueva lo ignoraba: cambiar
   de rejilla a lista no le hacía nada. En lista la ficha se vuelve una fila
   compacta -- la máquina como miniatura, los datos en línea y las acciones
   solo con icono -- porque el punto de esa vista es ver muchas máquinas de
   un vistazo, no cada una en detalle. */
.printers-grid.list-view .dev-card {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
    padding: 12px 14px;
}

/* La imagen pasa a miniatura, esté trabajando o no. */
.printers-grid.list-view .dev-hero { padding: 0; }
.printers-grid.list-view .dev-hero .dev-art,
.printers-grid.list-view .dev-art.is-thumb { width: 40px; height: 40px; max-width: 40px; }
/* Sin espacio para el botón "abrir panel" a 40px, y la fila entera ya es
   igual de clicable en esta vista. */
.printers-grid.list-view .dev-hero-open-btn { display: none; }

/* Identidad en una línea: nombre, tipo e insignia uno al lado del otro. */
.printers-grid.list-view .dev-card-head { flex: 1; min-width: 190px; align-items: center; }
.printers-grid.list-view .dev-card-id { flex-direction: row; align-items: center; gap: 9px; flex-wrap: wrap; }
.printers-grid.list-view .dev-card-name { font-size: .95rem; }
.printers-grid.list-view .dev-card-type { display: none; }
.printers-grid.list-view .dev-badge {
    margin-top: 0;
    padding: 2px 9px;
    font-size: .62rem;
}

/* Datos en línea, sin cajas: en una fila las cajas anidadas solo suman
   bordes que no separan nada. */
.printers-grid.list-view .dev-panel {
    border: none;
    background: none;
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
}
.printers-grid.list-view .dev-metrics { display: flex; gap: 16px; }
.printers-grid.list-view .dev-metric { padding: 0; gap: 7px; }
.printers-grid.list-view .dev-metric + .dev-metric { border-left: none; }
.printers-grid.list-view .dev-metric-value { font-size: .95rem; }
.printers-grid.list-view .dev-metrics + .dev-info { border-top: none; }
.printers-grid.list-view .dev-info { display: flex; gap: 16px; padding: 0; }
.printers-grid.list-view .dev-field-value { font-size: .85rem; }

/* Progreso: sin caja, el número y una barra fina. */
.printers-grid.list-view .dev-progress {
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 0;
    border: none;
    background: none;
    flex: 1;
    min-width: 150px;
}
.printers-grid.list-view .dev-progress-head { flex-direction: row; align-items: center; gap: 8px; }
.printers-grid.list-view .dev-progress-pct { font-size: 1.1rem; margin: 0; }
.printers-grid.list-view .dev-progress-remaining { font-size: .9rem; margin: 0; }
.printers-grid.list-view .dev-progress .dev-field-label { display: none; }
.printers-grid.list-view .dev-progress-track { flex: 1; height: 6px; }

/* Acciones: solo icono. La etiqueta se conserva como title para que se
   siga sabiendo qué hace cada una. */
.printers-grid.list-view .dev-actions {
    display: flex;
    gap: 6px;
    margin: 0;
    flex-shrink: 0;
}
.printers-grid.list-view .dev-action { padding: 9px; border-radius: 11px; }
.printers-grid.list-view .dev-action span { display: none; }
.printers-grid.list-view .dev-action svg { width: 18px; height: 18px; }
.printers-grid.list-view .dev-action-primary { grid-column: auto; }

/* En lista la cámara sí se ve, pero del tamaño de la fila: una miniatura
   al final, no un bloque que rompa el renglón. Ocultarla del todo tenía el
   problema de que la vista compacta es justo donde uno quiere echar el ojo
   rápido a todas las máquinas. */
.printers-grid.list-view .dev-camera {
    display: block;
    width: 132px;
    flex: 0 0 132px;
    margin-left: auto;
    border-radius: 10px;
    overflow: hidden;
}
.printers-grid.list-view .dev-camera .cam-live-wrap { aspect-ratio: 16 / 9; }
/* Los controles superpuestos no caben en una miniatura de fila: quedarían
   encima de toda la imagen. La cámara se sigue viendo; para operarla está
   la vista de rejilla o el propio plugin. */
.printers-grid.list-view .dev-camera .cam-overlay-bar { display: none; }
.printers-grid.list-view .dev-camera .cam-live-badge { transform: scale(.75); transform-origin: top right; }

.dev-card-head-right .printer-card-camera-toggle {
    width: 26px;
    height: 26px;
    flex: 0 0 26px;
    border-radius: 8px;
}
/* Mismo resplandor por categoría que el resto de botones de la ficha --
   sobreescribe el acento fijo del plugin de cámaras solo dentro de la
   cabecera de la ficha, sin tocar su uso en la sección Cámaras. */
.dev-card-head-right .printer-card-camera-toggle:hover,
.dev-card-head-right .printer-card-camera-toggle.is-enabled:hover {
    border-color: var(--dev-category, var(--accent));
    box-shadow: 0 0 8px 1px color-mix(in srgb, var(--dev-category, var(--accent)) 45%, transparent);
}

/* Palomita de estado en la esquina de los botones que son interruptor.
   Apagada se ve como un contorno vacío; encendida se rellena del verde de
   NOPAL. Así el mismo botón dice qué hace y en qué estado está. */
.dev-action { position: relative; }
.dev-action-check {
    position: absolute;
    top: 6px;
    right: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 1px solid color-mix(in srgb, var(--text-faint) 55%, transparent);
    color: transparent;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.dev-action-check.is-on {
    background: var(--status-ok);
    border-color: var(--status-ok);
    color: #fff;
}
.dev-action.is-checked { border-color: color-mix(in srgb, var(--status-ok) 40%, transparent); }

/* Qué imagen se ve: la ficha emite las dos y acá se elige. Hacerlo por CSS
   evita reconstruir la ficha al encender el visor, que era lo que repintaba
   la grilla entera y hacía parpadear las cámaras vecinas. */
.dev-card .dev-art.is-thumb { display: none; }
.dev-card.is-thumb-mode .dev-art.is-thumb { display: block; }
.dev-card.is-thumb-mode .dev-hero { display: none; }

/* Las olas térmicas van al fondo de la ficha, como en las fichas de
   siempre: la capa en el nivel 0 y todo lo demás por encima. */
.dev-card > .printer-thermal-layer { z-index: 0; }
.dev-card > *:not(.printer-thermal-layer) { position: relative; z-index: 1; }
