/**
 * DVERGENT — Mobile UX (sesión 2/5: MobileLauncher)
 * SPEC: docs/specs/SPEC_MOBILE_UX.md §3.1, §3.3, §4.1, §5, §8.
 *
 * Convenciones:
 *   - Namespace `.mobile-launcher__*` reservado al Launcher (esta sesión).
 *   - Namespace `.mobile-shell` reservado al wrapper que aplica el modo móvil.
 *   - Solo se utilizan CSS variables ya declaradas en theme.css. Sin literales
 *     de color (DP-039 — todo color del proyecto pasa por --accent-* / --bg-* /
 *     --text-*).  <<< OJO: los espacios alrededor de las barras NO son estética.
 *     Escrito pegado (`--accent-*` seguido de `/`) forma la secuencia de CIERRE
 *     de comentario: este bloque terminaba aquí, en la línea 9, y las líneas
 *     10-14 quedaban sueltas como CSS. El parser las tomaba como el preludio de
 *     una regla y se tragaba TODO hasta la primera `{` — o sea el `@media` de
 *     activación móvil entero (sidebar/header ocultos en el shell del launcher,
 *     el fix del desbordamiento horizontal del WebView Android, y el ocultado
 *     del botón de chat IA). Verificado con el parser real del navegador: 0
 *     reglas con `data-mobile-shell` sobrevivían. Mismo patrón que el backtick
 *     dentro de un template literal (CLAUDE.md §7): un carácter mata el bloque.
 *   - Activo SOLO bajo `<600px`. Tablet (≥600) y desktop (≥1024) no se ven
 *     afectados — el sidebar/dashboard actuales siguen funcionando.
 *   - Tap targets ≥48px (SPEC §8.2 / Material).
 *   - Respeta `prefers-reduced-motion`.
 *   - `--mano-lateral` en la regla base de una franja (barra, buscador, lista,
 *     pie…) es su separación lateral de siempre. En la ventana media (bloque
 *     final) se le suma la columna centrada. Cada franja la declara en su
 *     propia regla: heredada valdría la de la franja que la contiene.
 */

/* =====================================================
   Activación condicional — viewport <600px o handheld Android (Sunmi L3)
   Bug 4 (sesión fix tpv,core,docs 2026-04-29): el Sunmi L3 reporta ~720px
   pero es un handheld táctil. Coherente con _isMobileViewport() en app.js.
   ===================================================== */
@media (max-width: 599px),
       (max-width: 820px) and (pointer: coarse) {

    /* Cuando #appView lleva data-mobile-shell="launcher", ocultamos el sidebar
       y el header del ERP — el Launcher ocupa todo el viewport. */
    #appView.app[data-mobile-shell="launcher"] > .sidebar,
    #appView.app[data-mobile-shell="launcher"] > .main > .header,
    #appView.app[data-mobile-shell="launcher"] > .main > .mobile-module-tabs,
    #appView.app[data-mobile-shell="launcher"] > .main > .content {
        display: none !important;
    }

    /* El contenedor principal pasa a ser el Launcher dentro de .main */
    #appView.app[data-mobile-shell="launcher"] > .main {
        padding: 0;
        margin: 0;
        width: 100%;
        max-width: 100%;
        background: var(--bg-primary);
    }

    /* Bug B (2026-05-26): cuando estamos en móvil DENTRO de un módulo (no en
       launcher), también ocultamos sidebar + cabecera global del ERP + tabs
       horizontales desktop. Necesario porque flow `forceLegacy=true` de
       _tpvMobileSwitchToTab (DP-134) renderiza el layout desktop en
       #moduleContent — sin este fix se veía la cabecera "Boqueria SLU > TPV ☀
       ? 🔔99+ MA" + tabs horizontales (Facturación/TPV/RRHH/Info...) que
       desbordan el viewport del L3. La vuelta al launcher se hace por el
       botón Home flotante (#mobileHomeBtn) gestionado por _syncMobileHomeButton.
       El selector :not([data-mobile-shell]) evita aplicar esto al launcher
       (cubierto por las reglas de arriba) y a futuros shell modes. */
    #appView.app:not([data-mobile-shell]) > .sidebar,
    #appView.app:not([data-mobile-shell]) > .main > .header,
    #appView.app:not([data-mobile-shell]) > .main > .mobile-module-tabs {
        display: none !important;
    }
    #appView.app:not([data-mobile-shell]) > .main {
        padding: 0;
        margin: 0;
        width: 100%;
        max-width: 100%;
    }

    /* Defensa global anti-overflow horizontal en handhelds Android.
     * Algunos WebView Android calculan 100vw incluyendo la scrollbar y
     * provocan desbordamiento horizontal de 16-20px. */
    html, body { overflow-x: hidden; max-width: 100vw; }

    /* Bug E (2026-05-26): el botón flotante del chat IA (#agentChatBtn, esquina
       inferior derecha) tapa contenido valioso en el L3 sin aportar al flow del
       TPV (escaneo + tap directo en grid). Adri: "no vas a estar hablando todo
       el día — el TPV está hecho para escanear o seleccionar los 12 botones de
       pantalla". El chat IA queda como feature de excepción accesible desde el
       Dashboard móvil del módulo cuando haga falta una consulta puntual. La
       regla anula también el styling responsive del propio agent-chat.js. */
    #agentChatBtn {
        display: none !important;
    }
    /* El panel completo del chat (cuando se abre desde fuera) también se oculta
       para evitar que ocupe la pantalla del L3 — si en el futuro queremos chat
       en móvil, se reactivará con su propia pantalla full-screen dedicada. */
    body.agent-chat-open #agentChatPanel {
        display: none !important;
    }
}

/* =====================================================
   Mobile shell — contenedor del Launcher
   Estilos siempre cargados: el componente puede haberse renderizado
   y luego el viewport haber pasado a tablet (mobile-launcher.js
   destruye el contenido en ese caso, pero por seguridad mantenemos
   los estilos válidos para cualquier tamaño).
   ===================================================== */
.mobile-launcher {
    /* 2026-05-28 (Adri drill2/3 fix task #16/#18): position fixed + inset 0 +
       z-index alto para cubrir TODO el shell desktop residual (header, tabs
       "Dashboard | Clientes | Proveedores", sidebar, etc.). El z-index 50
       anterior no bastaba porque la tab-nav del shell desktop tiene su propio
       stacking. Subido a 999 — bajo modal-overlay (2000) pero sobre todo el
       resto de UI. */
    position: fixed;
    inset: 0;
    z-index: 999;
    width: 100vw;
    height: 100dvh;
    min-height: 100vh;            /* fallback para WebView que no soporten dvh */
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    box-sizing: border-box;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
/* 2026-05-28 (drill3 task #18): el contenedor host también debe ser overlay
   para que el Launcher quede aislado del flow del shell desktop. */
#mobileLauncherHost {
    position: fixed !important;
    inset: 0 !important;
    z-index: 998 !important;
    pointer-events: auto;
}
.mobile-launcher *,
.mobile-launcher *::before,
.mobile-launcher *::after { box-sizing: border-box; }

/* Medidas del Launcher que comparten la cabecera, el menú del avatar (que se
   monta en <body>), la rejilla de 2 columnas (≤ 360 px) y la de 4 de la
   ventana media (al final del fichero): una sola fuente para cada una. */
:root {
    --mano-launcher-lateral: 24px;          /* relleno lateral de la cabecera */
    --mano-launcher-menu-saliente: 8px;     /* lo que el menú sobresale del avatar */
    --mano-launcher-icono: 72px;
    --mano-launcher-modulo-relleno: 4px;    /* relleno del botón de módulo */
    --mano-launcher-celda: 120px;           /* celda fija de la rejilla */
    --mano-launcher-hueco: 24px;            /* hueco entre celdas fijas */
}

/* ── Cabecera ── */
.mobile-launcher__header {
    /* 2026-05-28 (Adri auditoría L3 task #6): el avatar se cortaba por la
     * derecha en el L3 — aumentado padding-right de 20→24px y se reduce el
     * tamaño del botón avatar de 44→40px (suficiente touch target Material
     * mínimo, garantiza que el círculo completo cabe en 360px CSS viewport).
     * Padding-top mantenido en safe-area+32px (status bar Android 14 ~28px). */
    padding: 32px var(--mano-launcher-lateral) 16px;
    padding-top: calc(env(safe-area-inset-top, 0px) + 32px);
    padding-right: calc(env(safe-area-inset-right, 0px) + var(--mano-launcher-lateral));
    padding-left: calc(env(safe-area-inset-left, 0px) + var(--mano-launcher-lateral));
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

.mobile-launcher__brand {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
    min-width: 0;
}

.mobile-launcher__greeting {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.mobile-launcher__title {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mobile-launcher__user-btn {
    /* Salida del Launcher (logout / volver al holding) — SPEC §4.1: cerrar sesión
       es la única salida cuando el usuario tiene 0 o 1 módulo de negocio.
       2026-05-28 (Adri auditoría L3 task #6): reducido de 44→40px para evitar
       corte por la derecha en el L3 + font-size 14px para mejor legibilidad
       de las iniciales (1-2 letras devueltas por _userInitials). */
    appearance: none;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    border-radius: var(--radius-full);
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex: 0 0 40px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
}

.mobile-launcher__user-btn:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

/* 2026-05-26: mini-dropdown del avatar del Launcher móvil. Aparece bajo el
   avatar (esquina superior derecha) con Reiniciar/Apagar Sunmi (si Device
   Owner) + Cerrar sesión. Sustituye al dropdown desktop que estaba oculto
   en móvil. */
.mobile-launcher__menu {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 76px);
    /* Sobresale --mano-launcher-menu-saliente a la derecha del avatar (16 px del borde). */
    right: calc(env(safe-area-inset-right, 0px) + var(--mano-launcher-lateral) - var(--mano-launcher-menu-saliente));
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 6px;
    display: flex;
    flex-direction: column;
    min-width: 220px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.3);
    z-index: 10000;
}
.mobile-launcher__menu-item {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    padding: 12px 14px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    text-align: left;
    width: 100%;
}
.mobile-launcher__menu-item:active {
    background: var(--bg-tertiary);
}
.mobile-launcher__menu-item--danger {
    color: var(--accent-red, #ef4444);
}
.mobile-launcher__menu-sep {
    height: 1px;
    background: var(--border-primary);
    margin: 4px 8px;
}

/* ── Grid 3×N ── */
.mobile-launcher__grid {
    flex: 1;
    padding: 16px 16px 32px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    column-gap: 16px;
    row-gap: 24px;
    align-content: start;
    /* 2026-05-28 (Adri auditoría L3 task #6): justify-items:center asegura que
       cada card queda centrada en su celda — con 1fr las celdas son anchas y
       el contenido se ve descentrado ópticamente entre col 1 y col 2 si los
       paddings izq/der del grid no son simétricos al ojo del usuario. */
    justify-items: center;
    overflow-y: auto;            /* SPEC §4.1: scroll vertical si >9 módulos */
    -webkit-overflow-scrolling: touch;
}

/* Bug A (2026-05-26): en viewport <=360px CSS (Sunmi L3 portrait ~324px), el
   grid de 3 columnas no admite los nombres largos (Proveedores, Fabricación,
   Facturación, Informes) — quedan truncados y la tercera columna se sale del
   viewport por la derecha. Pasar a 2 columnas garantiza ~140px por celda para
   icono 72px + label completo sin elipsis.
   2026-05-28 (Adri drill2 fix #16): además usar cells de ancho FIJO 120px y
   justify-content:center para que los 2 cards queden visualmente centrados en
   el viewport sin sesgo óptico — antes con 1fr cada cell tomaba 158px y los
   iconos quedaban descentrados respecto al eje vertical de la pantalla. */
@media (max-width: 360px) {
    .mobile-launcher__grid {
        grid-template-columns: repeat(2, var(--mano-launcher-celda));
        column-gap: var(--mano-launcher-hueco);
        justify-content: center;
    }
}

/* Caso 2-3 módulos — centrado horizontalmente. SPEC §4.1.
   Aplicado vía data-attr en el JS — evita renderizar markup distinto. */
.mobile-launcher__grid[data-count="1"],
.mobile-launcher__grid[data-count="2"],
.mobile-launcher__grid[data-count="3"] {
    grid-template-columns: repeat(var(--mobile-launcher-cols, 3), 88px);
    justify-content: center;
}
.mobile-launcher__grid[data-count="1"] { --mobile-launcher-cols: 1; }
.mobile-launcher__grid[data-count="2"] { --mobile-launcher-cols: 2; }
.mobile-launcher__grid[data-count="3"] { --mobile-launcher-cols: 3; }

/* ── Tarjeta de módulo ── */
.mobile-launcher__module {
    appearance: none;
    background: transparent;
    border: 0;
    padding: var(--mano-launcher-modulo-relleno);
    color: inherit;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    /* Tap target real ≥48px (icono 72 + label) — supera el mínimo Material 48dp. */
    min-height: 48px;
}

.mobile-launcher__module:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 4px;
    border-radius: var(--radius-lg);
}

.mobile-launcher__icon {
    width: var(--mano-launcher-icono);
    height: var(--mano-launcher-icono);
    border-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    /* Fallback para un data-color sin variante (ahí NO hay fondo de color, así que
       la tinta tiene que ser la del tema). El `#ffffff` que había aquí era el fijo:
       sobre los fondos claros del tema dark daba 1.8:1 en el icono — por debajo del
       3:1 de WCAG 1.4.11 — y el tema dark es el POR DEFECTO. Cada variante declara
       ahora su propio par -contrast (ver theme.css § tinta sobre rellenos). */
    color: var(--text-primary);
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s var(--ease-out);
}

.mobile-launcher__icon > svg {
    width: 32px;
    height: 32px;
    stroke: currentColor;
    stroke-width: 2;
}

.mobile-launcher__module:active .mobile-launcher__icon {
    transform: scale(0.96);
}

/* ── v6 · MOVIMIENTO (2026-08-22): entrada escalonada de la rejilla (índice --i que
   pone _renderModuleCard) y «la luz va hacia el icono» al tocarlo (.is-launching,
   160 ms antes de switchModule). ── */
.mobile-launcher__module {
    animation: launcherPop 0.3s var(--ease-out) both;
    animation-delay: calc(var(--i, 0) * 35ms);
}
@keyframes launcherPop {
    from { opacity: 0; transform: translateY(10px) scale(0.94); }
    to   { opacity: 1; transform: none; }
}
.mobile-launcher__module.is-launching .mobile-launcher__icon {
    transform: scale(1.08);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent-fill) 35%, transparent),
                0 0 24px color-mix(in srgb, var(--accent-fill) 55%, transparent);
    transition: transform 0.16s var(--ease-spring), box-shadow 0.16s var(--ease-out);
}

.mobile-launcher__label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Diferenciación cromática por módulo ──
   Usa --accent-* del proyecto (SPEC §5). Coincide con el mockup launcher.html.
   Cada variante declara SU par -contrast: el fondo es un token conmutado (claro en
   dark, oscuro en light), así que la tinta tiene que conmutar con él. Antes solo
   'primary'/'green'/los gradientes declaraban color y el resto heredaba un blanco
   fijo: icono a 1.8:1 sobre azul/naranja/cian y ~1.2:1 sobre el lima de 'indigo'
   en el tema por defecto. */
.mobile-launcher__icon[data-color="primary"]   { background: var(--accent-fill);   color: var(--accent-fill-contrast); }
.mobile-launcher__icon[data-color="blue"]      { background: var(--accent-blue);   color: var(--accent-blue-contrast); }
.mobile-launcher__icon[data-color="green"]     { background: var(--accent-fill);   color: var(--accent-fill-contrast); }
.mobile-launcher__icon[data-color="orange"]    { background: var(--accent-orange); color: var(--accent-orange-contrast); }
.mobile-launcher__icon[data-color="red"]       { background: var(--accent-red);    color: var(--accent-red-contrast); }
.mobile-launcher__icon[data-color="purple"]    { background: var(--accent-purple); color: var(--accent-purple-contrast); }
.mobile-launcher__icon[data-color="indigo"]    { background: var(--accent-indigo); color: var(--accent-indigo-contrast); }
.mobile-launcher__icon[data-color="cyan"]      { background: var(--accent-cyan);   color: var(--accent-cyan-contrast); }
.mobile-launcher__icon[data-color="gradient"]  { background: var(--accent-gradient); color: var(--accent-contrast); }
.mobile-launcher__icon[data-color="bluegrad"]  { background: linear-gradient(135deg, var(--accent-blue), var(--accent-primary)); color: var(--accent-contrast); }
/* Gradiente naranja→rojo: la tinta del naranja cumple en los DOS extremos
   (9.2:1 sobre el naranja, 6.0:1 sobre el rojo); la del rojo no lo haría. */
.mobile-launcher__icon[data-color="orangegrad"]{ background: linear-gradient(135deg, var(--accent-orange), var(--accent-red)); color: var(--accent-orange-contrast); }
.mobile-launcher__icon[data-color="greengrad"] { background: linear-gradient(135deg, var(--accent-green), var(--accent-blue)); color: var(--accent-contrast); }

/* ── Empty state — 0 módulos permitidos. SPEC §4.1. ── */
.mobile-launcher__empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 40px 24px;
    text-align: center;
}

.mobile-launcher__empty-icon {
    width: 64px;
    height: 64px;
    border-radius: var(--radius-full);
    background: var(--bg-tertiary);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
}

.mobile-launcher__empty-icon > svg {
    width: 28px;
    height: 28px;
}

.mobile-launcher__empty-title {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}

.mobile-launcher__empty-text {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.5;
    max-width: 280px;
}

.mobile-launcher__empty-action {
    appearance: none;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    border: 0;
    padding: 12px 20px;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    min-height: 48px;
    margin-top: 8px;
}

.mobile-launcher__empty-action:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

/* ── prefers-reduced-motion: anular transformaciones. SPEC §8.4 ── */
@media (prefers-reduced-motion: reduce) {
    .mobile-launcher__icon,
    .mobile-launcher__module:active .mobile-launcher__icon,
    .mobile-launcher__module.is-launching .mobile-launcher__icon {
        transition: none;
        transform: none;
        box-shadow: var(--shadow-sm);
    }
    .mobile-launcher__module { animation: none; }
}

/* =====================================================
   Mobile slide-down — sesión 3/5 (gesto + contenedor del panel)
   SPEC: docs/specs/SPEC_MOBILE_UX.md §3.2, §4.2, §4.3, §6.1, §8.4.
   Namespace `.mobile-slidedown__*` reservado al slide-down.
   El componente vive sobre <body> (fixed) — no depende del shell del
   Launcher (que ocupa #appView). Se activa solo cuando hay módulo.
   ===================================================== */

.mobile-slidedown {
    position: fixed;
    inset: 0;
    z-index: 1100;
    pointer-events: none;        /* el root no captura mientras está cerrado */
}

.mobile-slidedown.is-open,
.mobile-slidedown.is-closing {
    pointer-events: auto;
}

/* ── Backdrop --bg-overlay (SPEC §4.3) ── */
.mobile-slidedown__backdrop {
    position: absolute;
    inset: 0;
    background: var(--bg-overlay);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.mobile-slidedown.is-open .mobile-slidedown__backdrop  { opacity: 1; }
.mobile-slidedown.is-closing .mobile-slidedown__backdrop { opacity: 0; }

/* ── Panel: ancho 92%, top 8pt, radius 18pt, fondo --bg-primary ── */
.mobile-slidedown__panel {
    position: absolute;
    top: 8px;
    --mano-lateral: 4%;
    left: var(--mano-lateral);
    right: var(--mano-lateral);
    background: var(--bg-primary);
    border: 1px solid var(--border-primary);
    border-radius: 18px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
    padding: 16px 14px 10px;
    display: flex;
    flex-direction: column;
    /* Estado base: oculto arriba — slide-down 300ms (SPEC §4.3, §8.4). */
    transform: translateY(-110%);
    transition: transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
    will-change: transform;
}
.mobile-slidedown.is-open .mobile-slidedown__panel    { transform: translateY(0); }
.mobile-slidedown.is-closing .mobile-slidedown__panel { transform: translateY(-110%); }

/* ── Título "Acciones {módulo}" — 14px medium ── */
.mobile-slidedown__title {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    margin: 0 0 12px;
    text-align: left;
}

/* ── Grid 2×3 de atajos (66×66pt cada uno) ── */
.mobile-slidedown__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: auto;
    gap: 12px;
}

.mobile-slidedown__action {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    font-family: inherit;
    cursor: pointer;
    padding: 4px 2px;
    border-radius: 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    -webkit-tap-highlight-color: transparent;
    min-height: 48px;            /* tap target Material */
}
.mobile-slidedown__action:hover { background: var(--bg-hover); }
.mobile-slidedown__action:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

.mobile-slidedown__tile {
    width: 66px;
    height: 66px;
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
}
.mobile-slidedown__tile > svg { width: 28px; height: 28px; stroke: currentColor; stroke-width: 2; }

/* Variantes cromáticas (opcional `color` del shortcut; default = bg-tertiary).
   --accent-contrast es la tinta del LIMA: encima de azul/naranja/rojo era el token
   equivocado y solo colaba por casualidad. Cada relleno usa ya su propio par. */
.mobile-slidedown__tile[data-color="blue"]    { background: var(--accent-blue);    border-color: transparent; color: var(--accent-blue-contrast); }
.mobile-slidedown__tile[data-color="primary"] { background: var(--accent-fill);    border-color: transparent; color: var(--accent-fill-contrast); }
.mobile-slidedown__tile[data-color="green"]   { background: var(--accent-fill);    border-color: transparent; color: var(--accent-fill-contrast); }
.mobile-slidedown__tile[data-color="orange"]  { background: var(--accent-orange);  border-color: transparent; color: var(--accent-orange-contrast); }
.mobile-slidedown__tile[data-color="red"]     { background: var(--accent-red);     border-color: transparent; color: var(--accent-red-contrast); }
.mobile-slidedown__tile[data-color="gradient"]{ background: var(--accent-gradient); border-color: transparent; color: var(--accent-contrast); }

.mobile-slidedown__label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Huecos vacíos — atajos no registrados todavía ── */
.mobile-slidedown__placeholder-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 4px 2px;
    pointer-events: none;
}
.mobile-slidedown__placeholder {
    width: 66px;
    height: 66px;
    border-radius: 16px;
    border: 1.5px dashed var(--border-primary);
    background: transparent;
    opacity: 0.4;
}

/* ── Handle inferior 30×3pt opacity 0.5 (SPEC §4.3) ── */
.mobile-slidedown__handle {
    width: 30px;
    height: 3px;
    border-radius: 9999px;
    background: var(--text-primary);
    opacity: 0.5;
    margin: 14px auto 4px;
}

/* ── prefers-reduced-motion: fade-in 150ms en lugar de slide (SPEC §4.3 / §8.4) ── */
@media (prefers-reduced-motion: reduce) {
    .mobile-slidedown__panel {
        transform: none;
        opacity: 0;
        transition: opacity 150ms ease-out;
        will-change: opacity;
    }
    .mobile-slidedown.is-open .mobile-slidedown__panel    { opacity: 1; transform: none; }
    .mobile-slidedown.is-closing .mobile-slidedown__panel { opacity: 0; transform: none; }
    .mobile-slidedown__backdrop                            { transition: opacity 150ms ease-out; }
}

/* =====================================================
   Indicador de gesto disponible (SPEC §4.2):
   barra fina 3pt × 30pt anclada bajo la top bar (44pt),
   opacity 0.4, fade-out a los 2s desde la entrada al módulo.
   ===================================================== */
.mobile-slidedown__hint {
    position: fixed;
    top: 47px;                   /* 44pt top bar + 3pt margen */
    left: 50%;
    transform: translateX(-50%);
    width: 30px;
    height: 3px;
    border-radius: 9999px;
    background: var(--text-primary);
    opacity: 0;
    pointer-events: none;
    z-index: 1099;               /* bajo el panel pero sobre el contenido */
    transition: opacity 240ms ease-out;
}
.mobile-slidedown__hint.is-visible { opacity: 0.4; }

@media (prefers-reduced-motion: reduce) {
    .mobile-slidedown__hint { transition: none; }
}

/* =====================================================
   TPV Mobile Dashboard — sesión 4/5 (Dashboard del módulo TPV en móvil)
   SPEC: docs/specs/SPEC_MOBILE_UX.md §3.3, §6.1.
   Overlay full-screen sobre el contenido del módulo TPV en viewport <600px.
   Activado tras swipe-down → tap "Dashboard" en el slide-down (sesión 3).
   Namespace `.tpv-mobile-dashboard__*` reservado a esta vista.
   ===================================================== */

.tpv-mobile-dashboard {
    position: fixed;
    inset: 0;
    z-index: 1050;               /* sobre .content (~10) y bajo modales (1100+) */
    background: var(--bg-primary);
    color: var(--text-primary);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    flex-direction: column;
}

/* Tablet/desktop: si por error queda un nodo en el DOM, lo ocultamos.
   La lógica JS (tpvRenderMobileDashboard) se invoca desde el slide-down,
   que solo está activo bajo 600px — pero la defensa CSS evita ruido. */
/* Bug 4 (sesión fix 2026-04-29): el media query de "desktop arranca aquí" tiene
 * que ser coherente con _isMobileViewport() en app.js — handhelds Android tipo
 * Sunmi L3 reportan ≥600px y necesitan pointer:coarse para seguir en móvil.
 * Esta regla solo se aplica cuando NO estamos en handheld:
 *   - viewport > 820px (cualquier dispositivo a partir de tablet grande), O
 *   - viewport 600-820px con pointer:fine (tablets con teclado/stylus). */
@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .tpv-mobile-dashboard { display: none !important; }
}

/* ── Top bar ── */
.tpv-mobile-dashboard__topbar {
    position: sticky;
    top: 0;
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    z-index: 2;
}

.tpv-mobile-dashboard__back {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-dashboard__back:hover { background: var(--bg-hover); }
.tpv-mobile-dashboard__back:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.tpv-mobile-dashboard__back > svg { width: 24px; height: 24px; }

.tpv-mobile-dashboard__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.tpv-mobile-dashboard__title-sub {
    color: var(--text-secondary);
    font-weight: 500;
}
.tpv-mobile-dashboard__topbar-spacer {
    width: 44px;
    height: 44px;
}

/* ── Sub-toggle Tienda / Restaurante (posición prominente, SPEC §6.1) ── */
.tpv-mobile-dashboard__mode {
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral);
}

.tpv-mobile-dashboard__section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 0 0 8px;
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S2a + drill fix (Adri auditoría L3 task #10/#15)
   Resumen del día — UNA card contenedora grande con 3 KPIs internos.
   Antes eran 3 cards separadas. Adri en drill: "el resumen tiene que
   tener la misma estetica que el Top Cajeros" → patrón card-única con
   contenido en grid.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-dashboard__resumen {
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral) 8px;
}
.tpv-mobile-dashboard__resumen-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 14px 12px;
}
.tpv-mobile-dashboard__resumen-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}
.tpv-mobile-dashboard__resumen-kpi {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    text-align: center;
    /* Separadores visuales sutiles entre KPIs */
    border-right: 1px solid var(--border-primary);
    padding: 0 4px;
}
.tpv-mobile-dashboard__resumen-kpi:last-child {
    border-right: 0;
}
.tpv-mobile-dashboard__resumen-kpi .value {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
    letter-spacing: -0.01em;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-dashboard__resumen-kpi .label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
}
.tpv-mobile-dashboard__resumen.is-loading .tpv-mobile-dashboard__resumen-kpi .value {
    opacity: 0.35;
}

/* 2026-05-28 (drill2+3 fix #16/#18): icon-as-image dentro de cards Dashboard.
   El logo Shopify llena el `__access-ico` completo (56px) en lugar de un SVG
   pequeño centrado. Adri en drill3 captura 5: "el logo de Shopify está
   superpuesto, tiene que sustituirse y meter un tamaño más grande". */
.tpv-mobile-dashboard__access-img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 6px;
    box-sizing: border-box;
    display: block;
}
/* Card del logo Shopify: fondo blanco para contraste con el logo verde */
.tpv-mobile-dashboard__access-ico:has(.tpv-mobile-dashboard__access-img) {
    background: #ffffff !important;
    box-shadow: 0 4px 12px rgba(150, 191, 72, 0.3);
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S2a — Top Cajeros de hoy
   Card horizontal: foto cuadrada bordes redondeados (izq) + nombre + €
   facturado hoy + lista 3 productos top vendidos.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-dashboard__cajeros {
    --mano-lateral: 16px;
    padding: 8px var(--mano-lateral) 24px;
}
.tpv-mobile-dashboard__cajeros-empty {
    background: var(--bg-secondary);
    border: 1px dashed var(--border-primary);
    border-radius: 12px;
    padding: 18px 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    color: var(--text-secondary);
    font-size: 13px;
}
.tpv-mobile-dashboard__cajeros-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.tpv-mobile-dashboard__cajero {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 10px 12px;
    display: grid;
    grid-template-columns: 48px 1fr;
    gap: 12px;
    align-items: start;
}
.tpv-mobile-dashboard__cajero-foto {
    width: 48px;
    height: 48px;
    border-radius: 10px;        /* cuadrado bordes redondeados — pidió Adri */
    object-fit: cover;
    background: var(--bg-tertiary);
    display: block;
}
.tpv-mobile-dashboard__cajero-foto.is-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-primary);
    font-size: 16px;
    font-weight: 700;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    letter-spacing: -0.01em;
}
.tpv-mobile-dashboard__cajero-body {
    min-width: 0;               /* permite que ellipsis funcione en hijos */
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.tpv-mobile-dashboard__cajero-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    min-width: 0;
}
.tpv-mobile-dashboard__cajero-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1;
}
.tpv-mobile-dashboard__cajero-total {
    font-size: 14px;
    font-weight: 700;
    color: var(--accent-primary);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.tpv-mobile-dashboard__cajero-prods {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 12px;
    color: var(--text-secondary);
}
.tpv-mobile-dashboard__cajero-prods li {
    display: flex;
    gap: 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-dashboard__cajero-prods .qty {
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.tpv-mobile-dashboard__cajero-prods .is-empty {
    color: var(--text-secondary);
    opacity: 0.6;
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S2b (Adri auditoría L3 task #11)
   Buscar tickets — overlay full-screen mobile unificado.
   Reemplaza Buscar + Reimprimir + Devolver del Dashboard como
   cards separadas. Cada ticket en la lista expande sus acciones
   contextuales (reimprimir / devolver / pasar a factura).
   ════════════════════════════════════════════════════════ */
.tpv-mobile-buscar {
    position: fixed;
    inset: 0;
    z-index: 1080;                  /* sobre Dashboard (1050) y bajo modales (2000+) */
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
}

.tpv-mobile-buscar__topbar {
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    flex: 0 0 auto;
    padding-top: env(safe-area-inset-top, 0px);
    height: calc(44px + env(safe-area-inset-top, 0px));
}
.tpv-mobile-buscar__back,
.tpv-mobile-buscar__refresh,
.tpv-mobile-buscar__dashboard {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-buscar__back:active,
.tpv-mobile-buscar__refresh:active,
.tpv-mobile-buscar__dashboard:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-buscar__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
}

.tpv-mobile-buscar__searchbar {
    --mano-lateral: 12px;
    padding: 10px var(--mano-lateral);
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.tpv-mobile-buscar__input {
    width: 100%;
    height: 40px;
    border-radius: 10px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    padding: 0 12px;
    font-family: inherit;
    font-size: 14px;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-buscar__input:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 1px;
    border-color: var(--accent-blue);
}

.tpv-mobile-buscar__loading,
.tpv-mobile-buscar__empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    color: var(--text-secondary);
    font-size: 13px;
    padding: 32px;
    text-align: center;
}

.tpv-mobile-buscar__list {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 4px var(--mano-lateral) 24px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tpv-mobile-buscar__card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    overflow: hidden;
    transition: border-color 120ms ease;
    /* Hotfix 2026-07-06: __list es a la vez scroll container (flex:1 → altura
       definida) y flex column. Con overflow:hidden el min-height automático de
       la card computa a 0 (css-flexbox §4.5) y flex-shrink APLASTA las ~50
       cards a franjas de 2-20px en vez de hacer scroll (solo visible con >~9
       tickets — por eso no se vio en pruebas). flex-shrink:0 = altura
       intrínseca y la lista scrollea. Mismo patrón ya defendido en
       factura/fab-mobile-list__row vía min-height:64px. */
    flex-shrink: 0;
}
.tpv-mobile-buscar__card.is-expanded {
    border-color: var(--accent-primary);
}

.tpv-mobile-buscar__card-head {
    appearance: none;
    width: 100%;
    background: transparent;
    border: 0;
    padding: 10px 14px 4px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    color: var(--text-primary);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
}
.tpv-mobile-buscar__card-head-left {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.tpv-mobile-buscar__numero {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.tpv-mobile-buscar__badge {
    font-size: 10px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 9999px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.tpv-mobile-buscar__badge.is-abonado {
    background: rgba(239, 68, 68, 0.15);
    color: #ef4444;
}
.tpv-mobile-buscar__badge.is-abono {
    background: rgba(245, 158, 11, 0.15);
    color: #f59e0b;
}
.tpv-mobile-buscar__badge.is-factura {
    background: color-mix(in srgb, var(--accent-green) 15%, transparent);
    color: var(--accent-green);
}
.tpv-mobile-buscar__badge.is-anulado {
    background: rgba(107, 114, 128, 0.2);
    color: #6b7280;
}

.tpv-mobile-buscar__total {
    font-size: 15px;
    font-weight: 700;
    color: var(--accent-primary);
    font-variant-numeric: tabular-nums;
}

.tpv-mobile-buscar__card-meta {
    padding: 0 14px 10px;
    font-size: 12px;
    color: var(--text-secondary);
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}
.tpv-mobile-buscar__card-meta .dot {
    opacity: 0.4;
}
.tpv-mobile-buscar__card-meta .cliente {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 50%;
}

.tpv-mobile-buscar__actions {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    padding: 8px 12px 12px;
    border-top: 1px solid var(--border-primary);
    background: var(--bg-tertiary);
}
.tpv-mobile-buscar__action {
    appearance: none;
    background: var(--bg-primary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    border-radius: 10px;
    padding: 10px 4px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    cursor: pointer;
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-buscar__action > svg {
    width: 18px;
    height: 18px;
}
.tpv-mobile-buscar__action:active:not(:disabled) {
    transform: scale(0.97);
    background: var(--bg-tertiary);
}
.tpv-mobile-buscar__action:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
.tpv-mobile-buscar__action.is-danger {
    color: #ef4444;
    border-color: rgba(239, 68, 68, 0.4);
}
.tpv-mobile-buscar__action.is-danger:active:not(:disabled) {
    background: rgba(239, 68, 68, 0.1);
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S3a (Adri auditoría L3 task #13)
   Caja mobile — overlay unificado abrir/cerrar sesión.
   Reemplaza el flow desktop _tpvMobileSwitchToTab('sesiones')
   que llevaba al cajero a una pantalla cargada en modo desktop.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-caja {
    position: fixed;
    inset: 0;
    z-index: 1080;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
}

.tpv-mobile-caja__topbar {
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    flex: 0 0 auto;
    height: calc(44px + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
}
.tpv-mobile-caja__back,
.tpv-mobile-caja__dashboard {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-caja__back:active,
.tpv-mobile-caja__dashboard:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-caja__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
}

.tpv-mobile-caja__loading,
.tpv-mobile-caja__error {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: var(--text-secondary);
    font-size: 14px;
    --mano-lateral: 24px;
    padding: 32px var(--mano-lateral);
    text-align: center;
}
.tpv-mobile-caja__error-title {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}
.tpv-mobile-caja__error-detail {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.4;
    max-width: 360px;
    padding: 8px 12px;
    background: var(--bg-tertiary);
    border-radius: 8px;
    font-family: monospace;
    word-break: break-word;
}

.tpv-mobile-caja__section {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral) calc(24px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.tpv-mobile-caja__intro {
    font-size: 14px;
    color: var(--text-secondary);
    line-height: 1.4;
    margin: 0;
}

.tpv-mobile-caja__caja-num {
    font-size: 13px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    margin: 0;
}

.tpv-mobile-caja__label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    display: block;
    margin: 4px 0 6px;
}

.tpv-mobile-caja__input-big {
    width: 100%;
    height: 56px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    padding: 0 14px;
    font-variant-numeric: tabular-nums;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-caja__input-big:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 1px;
    border-color: var(--accent-blue);
}

.tpv-mobile-caja__hint {
    color: var(--text-secondary);
    font-size: 11px;
    line-height: 1.4;
    display: block;
    margin-top: 6px;
}

.tpv-mobile-caja__kpis {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}
.tpv-mobile-caja__kpi {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 10px 6px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    text-align: center;
}
.tpv-mobile-caja__kpi .value {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-caja__kpi .label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 500;
}

.tpv-mobile-caja__section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 8px 0 4px;
}

.tpv-mobile-caja__metodos {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    overflow: hidden;
    /* Barrido 2026-07-03: hijo directo de __section (scroll container flex column
       con flex:1). Con overflow:hidden su min-height automático computa a 0
       (css-flexbox §4.5) y colapsaría a franja al llenarse la pantalla de cierre.
       Mismo patrón que .tpv-mobile-buscar__card. */
    flex-shrink: 0;
}
.tpv-mobile-caja__metodos li {
    padding: 10px 14px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    border-bottom: 1px solid var(--border-primary);
}
.tpv-mobile-caja__metodos li:last-child {
    border-bottom: 0;
}
.tpv-mobile-caja__metodo-name {
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-caja__metodo-name small {
    color: var(--text-secondary);
    font-size: 11px;
    font-weight: 500;
}
.tpv-mobile-caja__metodo-total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    flex: 0 0 auto;
}

.tpv-mobile-caja__arqueo {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.tpv-mobile-caja__esperado {
    margin: 0;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 13px;
    color: var(--text-secondary);
}
.tpv-mobile-caja__esperado strong {
    color: var(--text-primary);
    font-size: 16px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tpv-mobile-caja__action-primary,
.tpv-mobile-caja__action-danger {
    appearance: none;
    width: 100%;
    height: 56px;
    border-radius: 14px;
    border: 0;
    color: #ffffff;
    font-family: inherit;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms ease;
    margin-top: 8px;
}
.tpv-mobile-caja__action-primary {
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--accent-fill) 25%, transparent);
}
.tpv-mobile-caja__action-danger {
    background: #ef4444;
    box-shadow: 0 4px 12px rgba(239, 68, 68, 0.25);
}
.tpv-mobile-caja__action-primary:active,
.tpv-mobile-caja__action-danger:active {
    transform: translateY(1px);
}
.tpv-mobile-caja__action-primary > svg,
.tpv-mobile-caja__action-danger > svg {
    width: 18px;
    height: 18px;
}

/* 2026-05-29 (Adri task #29) — Botón "Histórico cierres" dentro de Caja
   (admin only). Estilo secundario, outlined, separado del CTA principal. */
.tpv-mobile-caja__action-secondary {
    appearance: none;
    --mano-lateral: 12px;
    width: calc(100% - 2 * var(--mano-lateral));
    margin: 12px var(--mano-lateral);
    padding: 14px 16px;
    background: transparent;
    border: 1.5px solid var(--border-primary);
    border-radius: 12px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-caja__action-secondary:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-caja__action-secondary > svg {
    width: 18px;
    height: 18px;
    opacity: 0.8;
}

/* ════════════════════════════════════════════════════════
   2026-05-29 (Adri task #29) — Histórico cierres overlay
   Multi-select con checkbox + footer fijo "Enviar email (N)"
   ════════════════════════════════════════════════════════ */
.tpv-mobile-hist {
    position: fixed;
    inset: 0;
    z-index: 1090;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-hist__topbar {
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    flex: 0 0 auto;
    height: calc(48px + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
}
.tpv-mobile-hist__back {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.tpv-mobile-hist__back:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-hist__title {
    font-size: 16px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
}
.tpv-mobile-hist__spacer {
    width: 44px;
    height: 44px;
}
.tpv-mobile-hist__toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    --mano-lateral: 14px;
    padding: 10px var(--mano-lateral);
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-secondary, #1a1a1a);
    flex: 0 0 auto;
}
.tpv-mobile-hist__select-all {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--accent-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 8px;
    border-radius: 8px;
}
.tpv-mobile-hist__select-all:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-hist__select-all > svg {
    width: 16px;
    height: 16px;
}
.tpv-mobile-hist__count {
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.tpv-mobile-hist__scroll {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 8px var(--mano-lateral) 100px;
}
.tpv-mobile-hist__list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.tpv-mobile-hist__card {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px;
    background: var(--bg-secondary, #1a1a1a);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    cursor: pointer;
    transition: border-color 120ms ease, background 120ms ease;
}
.tpv-mobile-hist__card:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-hist__card.is-checked {
    border-color: var(--accent-primary);
    background: color-mix(in srgb, var(--accent-primary) 8%, transparent);
}
.tpv-mobile-hist__checkbox {
    width: 22px;
    height: 22px;
    margin-top: 2px;
    accent-color: var(--accent-primary);
    flex: 0 0 auto;
    cursor: pointer;
}
.tpv-mobile-hist__card-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.tpv-mobile-hist__card-row1 {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.tpv-mobile-hist__fecha {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    text-transform: capitalize;
}
.tpv-mobile-hist__total {
    font-size: 15px;
    font-weight: 700;
    color: var(--accent-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.tpv-mobile-hist__card-row2 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    font-size: 12px;
    color: var(--text-secondary);
}
.tpv-mobile-hist__dot {
    color: var(--text-tertiary, var(--text-secondary));
    opacity: 0.6;
}
.tpv-mobile-hist__cuadra {
    color: var(--accent-green);
    font-weight: 600;
}
.tpv-mobile-hist__descuadre {
    color: #ef4444;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.tpv-mobile-hist__card-actions {
    display: flex;
    gap: 8px;
    margin-top: 4px;
}
.tpv-mobile-hist__mini {
    appearance: none;
    padding: 6px 10px;
    background: var(--bg-tertiary);
    border: 0;
    border-radius: 8px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-hist__mini:active {
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
}
.tpv-mobile-hist__mini > svg {
    width: 14px;
    height: 14px;
}
.tpv-mobile-hist__loading,
.tpv-mobile-hist__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 60px 24px;
    color: var(--text-secondary);
    text-align: center;
    font-size: 14px;
}
.tpv-mobile-hist__loading > svg {
    animation: tpv-hist-spin 1s linear infinite;
}
@keyframes tpv-hist-spin {
    to { transform: rotate(360deg); }
}
.tpv-mobile-hist__footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) calc(12px + env(safe-area-inset-bottom, 0px));
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    z-index: 1;
}
.tpv-mobile-hist__send-btn {
    appearance: none;
    width: 100%;
    height: 52px;
    background: var(--accent-fill);
    border: 0;
    border-radius: 12px;
    color: var(--accent-fill-contrast);
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--accent-fill) 30%, transparent);
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-hist__send-btn:active {
    transform: translateY(1px);
}
.tpv-mobile-hist__send-btn > svg {
    width: 18px;
    height: 18px;
}

/* 2026-05-29 (Adri task #30) — Visor PDF inline en WebView Sunmi L3.
   window.open('_blank') no funciona en el WebView, así que el PDF se carga
   con fetch + Blob URL y se muestra dentro de un iframe overlay full-screen. */
.tpv-mobile-hist-pdf {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: #ffffff;
    display: flex;
    flex-direction: column;
}
.tpv-mobile-hist-pdf__topbar {
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    background: var(--bg-primary);
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-primary);
    flex: 0 0 auto;
    height: calc(48px + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
}
.tpv-mobile-hist-pdf__back,
.tpv-mobile-hist-pdf__download {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-hist-pdf__back:active,
.tpv-mobile-hist-pdf__download:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-hist-pdf__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    color: var(--text-primary);
}
.tpv-mobile-hist-pdf__frame {
    flex: 1;
    width: 100%;
    border: 0;
    background: #ffffff;
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S3b-1 (Adri auditoría L3 task #14)
   Etiquetado mobile — overlay 1-col scrolleable.
   Flujo 3 pasos: Producto → Lote → Peso/Imprimir.
   Reusa handlers existentes (tpvEtiqGenerar, tpvEtiqCalcPreview)
   con UI mobile-first.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-etiq {
    position: fixed;
    inset: 0;
    z-index: 1080;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
}

.tpv-mobile-etiq__topbar {
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    flex: 0 0 auto;
    height: calc(44px + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
}
.tpv-mobile-etiq__back,
.tpv-mobile-etiq__dashboard {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-etiq__back:active,
.tpv-mobile-etiq__dashboard:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-etiq__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
}

.tpv-mobile-etiq__body {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral) calc(24px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.tpv-mobile-etiq__section {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tpv-mobile-etiq__step {
    margin: 0 0 4px;
    font-size: 11px;
    font-weight: 700;
    color: var(--accent-primary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.tpv-mobile-etiq__step.is-disabled {
    color: var(--text-secondary);
    opacity: 0.5;
}

.tpv-mobile-etiq__search {
    width: 100%;
    height: 44px;
    border-radius: 10px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    padding: 0 14px;
    font-family: inherit;
    font-size: 14px;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-etiq__search:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 1px;
    border-color: var(--accent-blue);
}

.tpv-mobile-etiq__results {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    overflow: hidden;
    max-height: 280px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Barrido 2026-07-03: con overflow-y:auto el min-height automático computa a 0
       (css-flexbox §4.5). Su cadena de ancestros flex (__section → __body flex:1)
       sufre presión de altura cuando el teclado Android reduce el viewport en pleno
       flujo de búsqueda → los resultados colapsaban a franja. */
    flex-shrink: 0;
}
.tpv-mobile-etiq__result {
    appearance: none;
    width: 100%;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--border-primary);
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: left;
    color: var(--text-primary);
    font-family: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-etiq__result:last-child { border-bottom: 0; }
.tpv-mobile-etiq__result:active { background: var(--bg-tertiary); }
.tpv-mobile-etiq__result-name {
    font-size: 14px;
    font-weight: 600;
}
.tpv-mobile-etiq__result-meta {
    font-size: 11px;
    color: var(--text-secondary);
    font-family: monospace;
}
.tpv-mobile-etiq__loading,
.tpv-mobile-etiq__empty {
    padding: 14px;
    color: var(--text-secondary);
    font-size: 13px;
    text-align: center;
}

.tpv-mobile-etiq__selected {
    background: var(--bg-secondary);
    border: 1px solid var(--accent-primary);
    border-radius: 12px;
    padding: 10px 38px 10px 12px;
    position: relative;
}
.tpv-mobile-etiq__selected-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.3;
}
.tpv-mobile-etiq__selected-meta {
    font-size: 11px;
    color: var(--text-secondary);
    margin-top: 4px;
}
.tpv-mobile-etiq__clear {
    appearance: none;
    background: var(--bg-tertiary);
    border: 0;
    width: 28px;
    height: 28px;
    border-radius: 9999px;
    color: var(--text-secondary);
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.tpv-mobile-etiq__empty-block {
    background: var(--bg-secondary);
    border: 1px dashed var(--border-primary);
    border-radius: 12px;
    padding: 18px 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    color: var(--text-secondary);
    font-size: 12px;
    text-align: center;
    line-height: 1.4;
}

.tpv-mobile-etiq__lotes {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.tpv-mobile-etiq__lote {
    appearance: none;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 10px 12px;
    text-align: left;
    color: var(--text-primary);
    font-family: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: border-color 120ms ease;
}
.tpv-mobile-etiq__lote.is-selected {
    border-color: var(--accent-primary);
    background: var(--bg-tertiary);
}
.tpv-mobile-etiq__lote-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}
.tpv-mobile-etiq__lote-num {
    font-size: 13px;
    font-weight: 700;
}
.tpv-mobile-etiq__lote-stock {
    font-size: 11px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 9999px;
    background: color-mix(in srgb, var(--accent-green) 15%, transparent);
    color: var(--accent-green);
}
.tpv-mobile-etiq__lote-stock.is-low {
    background: rgba(239, 68, 68, 0.15);
    color: #ef4444;
}
.tpv-mobile-etiq__lote-meta {
    font-size: 11px;
    color: var(--text-secondary);
}

.tpv-mobile-etiq__form {
    display: flex;
    flex-direction: column;
}
.tpv-mobile-etiq__label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin: 0 0 4px;
}
.tpv-mobile-etiq__input-big {
    width: 100%;
    height: 56px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 22px;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
    padding: 0 14px;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-etiq__input-num {
    width: 100%;
    height: 44px;
    border-radius: 10px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 16px;
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
    padding: 0 14px;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-etiq__input-big:focus,
.tpv-mobile-etiq__input-num:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 1px;
    border-color: var(--accent-blue);
}

.tpv-mobile-etiq__preview {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px;
    min-height: 80px;
}
.tpv-mobile-etiq__preview-empty {
    margin: 0;
    color: var(--text-secondary);
    font-size: 12px;
    text-align: center;
}

.tpv-mobile-etiq__hint {
    margin: 0;
    color: var(--text-secondary);
    font-size: 12px;
    line-height: 1.4;
    text-align: center;
    padding: 8px;
}

.tpv-mobile-etiq__action-primary {
    appearance: none;
    width: 100%;
    height: 56px;
    border-radius: 14px;
    border: 0;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    font-family: inherit;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    -webkit-tap-highlight-color: transparent;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--accent-fill) 25%, transparent);
    margin-top: 8px;
}
.tpv-mobile-etiq__action-primary:active {
    transform: translateY(1px);
}
.tpv-mobile-etiq__action-primary > svg {
    width: 18px;
    height: 18px;
}

.tpv-mobile-etiq__loading-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1090;
    pointer-events: none;
}
.tpv-mobile-etiq__loading-overlay > svg {
    width: 32px;
    height: 32px;
    color: #ffffff;
    animation: tpvMobileEtiqSpin 800ms linear infinite;
}
@keyframes tpvMobileEtiqSpin {
    to { transform: rotate(360deg); }
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S3b-2 (Adri auditoría L3 task #14)
   Configuración TPV mobile — wrapper que ENVUELVE el render
   desktop tpvRenderConfig() con topbar mobile + botón Dashboard.
   El form interno ya usa el fix CSS de DP-132 (@media max-720)
   que colapsa los grids 2-col → 1-col en el L3.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-config {
    position: fixed;
    inset: 0;
    z-index: 1080;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
}

.tpv-mobile-config__topbar {
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    flex: 0 0 auto;
    height: calc(44px + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
}
.tpv-mobile-config__back,
.tpv-mobile-config__dashboard {
    appearance: none;
    background: transparent;
    border: 0;
    width: 44px;
    height: 44px;
    border-radius: 9999px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-config__back:active,
.tpv-mobile-config__dashboard:active {
    background: var(--bg-tertiary);
}
.tpv-mobile-config__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
}

.tpv-mobile-config__body {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 12px var(--mano-lateral) calc(24px + env(safe-area-inset-bottom, 0px));
}

/* Override CSS para el form desktop renderizado dentro del overlay:
   sin card outer (el overlay ya es full-screen), sin max-width:700px. */
.tpv-mobile-config__body > .card {
    margin: 0 !important;
    max-width: none !important;
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
}
.tpv-mobile-config__body > .card > .card-header {
    /* Ocultar el header desktop "Configuración del TPV" — ya está en la topbar mobile */
    display: none;
}
.tpv-mobile-config__body > .card > .card-body {
    padding: 0 !important;
}
.tpv-mobile-config__loading {
    padding: 40px 16px;
    text-align: center;
    color: var(--text-secondary);
    font-size: 14px;
}

/* HOTFIX 4 (2026-05-29) — En mobile, las acciones del form de Configuración
   (Guardar + Verificar email) iban side-by-side con display:flex inline; en
   viewport ~360px (Sunmi L3) los dos botones se comprimían y "Guardar" podía
   quedar truncado o no visible al hacer scroll. Stack vertical y full-width
   garantizan que ambos sean claramente clicables. */
.tpv-mobile-config__body form .btn,
.tpv-mobile-config__body form button[type="submit"] {
    width: 100%;
    min-height: 48px;
    justify-content: center;
}
.tpv-mobile-config__body form > div[style*="display:flex"] {
    flex-direction: column !important;
    gap: 10px !important;
}

.tpv-mobile-dashboard__mode-toggle {
    display: grid;
    grid-template-columns: 1fr 1fr;
    background: var(--bg-tertiary);
    border-radius: 14px;
    padding: 4px;
    border: 1px solid var(--border-primary);
}

.tpv-mobile-dashboard__mode-toggle button {
    appearance: none;
    height: 52px;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    border-radius: 11px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    -webkit-tap-highlight-color: transparent;
    transition: color 180ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.tpv-mobile-dashboard__mode-toggle button > svg {
    width: 22px;
    height: 22px;
    flex: 0 0 22px;
}
.tpv-mobile-dashboard__mode-toggle button[aria-pressed="true"] {
    background: var(--bg-primary);
    color: var(--text-primary);
    box-shadow: var(--shadow-sm, 0 2px 6px rgba(0, 0, 0, 0.18));
}
.tpv-mobile-dashboard__mode-toggle button:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

/* ── Sección "Operaciones" — grid 3×N de accesos ── */
.tpv-mobile-dashboard__accesses {
    --mano-lateral: 16px;
    padding: 4px var(--mano-lateral) 24px;
    flex: 1;
}

.tpv-mobile-dashboard__grid {
    /* 2026-05-28 (Adri drill3 fix #18): cambio de 3 cols a 2 cols con cards
       más grandes — Adri quiere 6 iconos por sección pero más grandes y con
       mejor proporción estética. Grid 2-col + cards más altas (108px) +
       iconos 48px en lugar de 36px. Sin recuadro gris (sin border + sin bg). */
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

.tpv-mobile-dashboard__access {
    appearance: none;
    /* 2026-05-28 (Adri drill3 fix #18): sin recuadro gris ni border —
       fondo negro nítido del viewport. Padding generoso para que el icono
       respire. Adri lo pidió "estilo NVidia WebGL". */
    background: transparent;
    border: 0;
    border-radius: 12px;
    padding: 8px 6px;
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    min-height: 96px;
    position: relative;
}
.tpv-mobile-dashboard__access:hover { background: var(--bg-tertiary); }
.tpv-mobile-dashboard__access:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}
.tpv-mobile-dashboard__access:active {
    transform: scale(0.95);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* Marker visual para accesos restringidos a admin (punto naranja) */
.tpv-mobile-dashboard__access.is-admin-only::after {
    content: "";
    position: absolute;
    top: 8px;
    right: 8px;
    width: 6px;
    height: 6px;
    border-radius: 9999px;
    background: var(--accent-orange);
}

.tpv-mobile-dashboard__access-ico {
    /* 2026-05-28 (drill3 fix #18): icono más grande (56→48px) con SVG 28px.
       Aumenta visibilidad táctil del cajero, da más presencia visual. */
    width: 56px;
    height: 56px;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.tpv-mobile-dashboard__access-ico > svg {
    width: 28px;
    height: 28px;
    stroke: currentColor;
    stroke-width: 2;
}
.tpv-mobile-dashboard__access-ico[data-color="blue"]    { background: var(--accent-blue); }
.tpv-mobile-dashboard__access-ico[data-color="green"]   { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.tpv-mobile-dashboard__access-ico[data-color="red"]     { background: var(--accent-red); }
.tpv-mobile-dashboard__access-ico[data-color="orange"]  { background: var(--accent-orange); }
.tpv-mobile-dashboard__access-ico[data-color="purple"]  { background: var(--accent-fill); color: var(--accent-fill-contrast); }

.tpv-mobile-dashboard__access-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Hint de leyenda al pie (solo se muestra si hay accesos admin-only) ── */
.tpv-mobile-dashboard__hint {
    --mano-lateral: 16px;
    padding: 4px var(--mano-lateral) 16px;
    margin: 0;
    font-size: 11px;
    color: var(--text-secondary);
    text-align: center;
}
.tpv-mobile-dashboard__dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 9999px;
    background: var(--accent-orange);
    vertical-align: middle;
    margin-right: 4px;
}

@media (prefers-reduced-motion: reduce) {
    .tpv-mobile-dashboard__access:active { transform: none; transition: none; }
    .tpv-mobile-dashboard__mode-toggle button { transition: none; }
}

/* =====================================================
   TPV — Pantalla principal de venta en móvil (sesión 5/5 mobile UX)
   SPEC: docs/specs/SPEC_MOBILE_UX.md §4.2 + §6.1.
   Mockup: docs/specs/mobile-ux-mockups/module-tpv-venta.html.
   ===================================================== */

.tpv-mobile-venta {
    position: fixed;
    inset: 0;
    /* Bug 3 (sesión fix 2026-04-29): subimos z-index 60 → 999 para asegurar
     * que la vista móvil queda sobre cualquier sidebar/header/dropdown del
     * shell desktop residual cuando el shell no se desmonta limpiamente.
     * Bajo modal-overlay (1000) y mobile-slidedown (1100). */
    z-index: 999;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* ── Top bar 44pt: casa | TPV · Caja N | dashboard | persona ──
   DP-131 (2026-05-11): grid ampliado a 4 columnas para acomodar el botón
   Dashboard del módulo TPV (icon: layout-grid) entre el título y el botón
   cliente. La pantalla de venta móvil tapaba la franja del slide-down
   (`shared/mobile-slidedown.js` zona y=44..74), bloqueando acceso al
   Dashboard / Configuración / Tickets / etc. desde el L3 / móvil. */
/* 2026-05-28 S1 (Adri auditoría L3): topbar ELIMINADA del DOM por el render.
   Mantengo la clase con display:none por si algún snippet legacy intenta
   montarla — defensa-en-profundidad. Único acceso al Dashboard TPV (home,
   cliente, caja, configuración, etc.) ahora es swipe-down → mobile-slidedown
   → cards del Dashboard. */
.tpv-mobile-venta__topbar {
    display: none;
}
.tpv-mobile-venta__topbar--legacy {
    height: 44px;
    padding: 0 6px;
    display: grid;
    grid-template-columns: 44px 1fr 44px 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    position: relative;
    flex: 0 0 auto;
}
.tpv-mobile-venta__topbar-btn {
    width: 44px;
    height: 44px;
    /* Bug 3 (sesión fix 2026-04-29): borde sutil + fondo ligero para que el
     * botón casa sea VISIBLE incluso si el icono Lucide tarda en renderizarse
     * o el iOS Safari renderiza el SVG con stroke muy fino. Antes era
     * background: transparent + border: 0 → invisible hasta hover. */
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.tpv-mobile-venta__topbar-btn:hover { background: var(--bg-hover); }
.tpv-mobile-venta__topbar-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.tpv-mobile-venta__topbar-btn.is-assigned {
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
}
.tpv-mobile-venta__topbar-btn.is-assigned:hover { background: var(--accent-fill); opacity: 0.9; }
.tpv-mobile-venta__persona-fill {
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.01em;
}
.tpv-mobile-venta__topbar-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: center;
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-venta__topbar-title small {
    color: var(--text-secondary);
    font-weight: 500;
}

/* 2026-05-28 S2a fix (Adri auditoría L3): gesture-hint ELIMINADO visualmente.
   El swipe-down conflicta con la notification shade de Android (que captura
   primero todos los gestos desde y=0). Reemplazado por chip-Dashboard visible
   en la fila de categorías. El listener del slide-down queda activo como
   fallback silencioso pero sin pista visual para no engañar al usuario. */
.tpv-mobile-venta__gesture-hint {
    display: none;
}
.tpv-mobile-venta__gesture-hint.is-fading { opacity: 0; }

/* ── Tira de cliente: solo si hay cliente asignado ── */
.tpv-mobile-venta__client-strip {
    height: 28px;
    --mano-lateral: 16px;
    padding: 0 var(--mano-lateral);
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-primary);
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-secondary);
    flex: 0 0 auto;
}
.tpv-mobile-venta__client-label { font-weight: 500; }
.tpv-mobile-venta__client-name {
    color: var(--text-primary);
    font-weight: 500;
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
}
.tpv-mobile-venta__client-clear {
    margin-left: auto;
    background: transparent;
    border: 0;
    width: 24px;
    height: 24px;
    border-radius: 9999px;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-venta__client-clear:hover { background: var(--bg-hover); color: var(--text-primary); }

/* ── Cuerpo: input EAN + lista + total + COBRAR ── */
.tpv-mobile-venta__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.tpv-mobile-venta__ean-row {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral);
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.tpv-mobile-venta__ean {
    width: 100%;
    height: 44px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 500;
    padding: 0 14px;
    font-variant-numeric: tabular-nums;
    -webkit-appearance: none;
    appearance: none;
}
.tpv-mobile-venta__ean::placeholder { color: var(--text-secondary); }
.tpv-mobile-venta__ean:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
    border-color: var(--accent-blue);
}

/* ── Bug 5 + SPEC v1.2 §6.1: catalog (chips + grid productos rápidos) ──
   2026-05-28 S1 (Adri auditoría L3): max-height cap RETIRADO. Ahora el
   catálogo toma todo el espacio disponible (`flex: 1 1 auto`) porque la cesta
   está oculta por defecto. Cuando el operario toca "Ver cesta", se aplica
   `.is-hidden` que oculta el catálogo y el espacio pasa a `.__lines.is-visible`.
   Con esto en el L3 caben 5+ filas × 3 cols de productos en lugar de 2 filas. */
.tpv-mobile-venta__catalog {
    flex: 1 1 auto;
    --mano-lateral: 12px;
    padding: 0 var(--mano-lateral) 8px;
    border-bottom: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.tpv-mobile-venta__catalog.is-hidden {
    display: none;
}
.tpv-mobile-venta__chips {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    /* 2026-05-26: padding-inline 12px añadido — el primer chip ("Todos")
       quedaba pegado al borde izquierdo de la pantalla en el Sunmi L3 sin
       margen visual, rompiendo la simetría con el resto del catálogo. */
    padding: 6px 12px;
    flex: 0 0 auto;
    scrollbar-width: none;
}
.tpv-mobile-venta__chips::-webkit-scrollbar { display: none; }
.tpv-mobile-venta__chip {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 14px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}
.tpv-mobile-venta__chip.is-active {
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
}

/* 2026-05-28 S2a fix (Adri auditoría L3): chip-Dashboard al inicio de la fila
   de categorías. Distinto visualmente de los chips de filtro (cuadrado, no
   pildora; color accent fijo) para indicar que es ACCIÓN, no FILTRO. Reemplaza
   al swipe-down que conflictaba con la notification shade de Android. */
.tpv-mobile-venta__chip--dashboard {
    width: 36px;
    padding: 0;
    border-radius: 10px;            /* cuadrado redondeado, no pildora */
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 36px;
}
.tpv-mobile-venta__chip--dashboard:active {
    transform: scale(0.94);
}
.tpv-mobile-venta__chip--dashboard > svg {
    width: 18px;
    height: 18px;
    stroke-width: 2.2;
}

.tpv-mobile-venta__product-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* 2026-05-28 (Adri drill2 fix #16): grid-auto-rows fijo para que TODOS los
       botones de producto sean del MISMO tamaño, sin importar la categoría
       activa. Antes con 1 producto en categoría "Jamón" el botón se estiraba
       a toda la altura disponible (default minmax 1fr). Adri pidió ~12 botones
       visibles → 4 filas × 3 cols con altura unificada ~108px (cabe en L3 720px).
       overflow-y permite scroll cuando hay más de 12. */
    grid-auto-rows: 108px;
    gap: 8px;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 4px 0 8px;
    flex: 1 1 auto;
    min-height: 0;
    align-content: start;
}
.tpv-mobile-venta__product-grid.is-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    font-size: 13px;
    gap: 6px;
    padding: 20px 0;
}
.tpv-mobile-venta__product {
    /* 2026-05-28 (Adri drill2 fix #16): altura controlada por grid-auto-rows
       (108px). Quitado min-height para que la celda mande. */
    border-radius: 10px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    padding: 8px 6px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: space-between;
    gap: 4px;
    text-align: left;
    font-family: inherit;
    overflow: hidden;
}
.tpv-mobile-venta__product:active {
    background: var(--bg-tertiary);
    transform: scale(0.97);
}

/* ════════════════════════════════════════════════════════
   2026-05-29 — Render foto producto en tile TPV + modal detalle mobile
   (Adri reporta "no cargan las fotos" tras subir 12 fotos Ramos Boquería).
   Las fotos viven en /uploads/productos/<empresa>/<archivo>.png (endpoint
   autenticado). La columna productos.imagen guarda el path relativo.

   Estrategia:
   - Tile TPV con foto: layout flex-start, imagen ~62px arriba, nombre+precio
     justo debajo. Tipografía ligeramente más pequeña para que quepa en 108px
     de la celda con 4px de padding interno.
   - Tile sin foto: comportamiento previo intacto (justify-content: space-between
     puesto por .tpv-mobile-venta__product base; texto distribuido arriba/abajo).
   - Modal detalle: foto destacada 180px con object-fit:contain y bg neutro
     para que la transparencia del PNG no choque con tema dark.
   - Fallback onerror inline: en tpv.js elimina el <img> y le quita .has-image
     al botón para volver al layout sin imagen. En productos.js oculta el
     wrap entero. Nunca se queda un hueco roto en la UI.
   ════════════════════════════════════════════════════════ */
.tpv-mobile-venta__product.has-image {
    padding: 4px;
    gap: 2px;
    justify-content: flex-start;
}
.tpv-mobile-venta__product-img {
    width: 100%;
    height: 62px;
    object-fit: contain;
    object-position: center;
    border-radius: 6px;
    background: var(--bg-tertiary);
    flex: 0 0 62px;
    pointer-events: none; /* tap atraviesa al botón padre */
}
.tpv-mobile-venta__product.has-image .tpv-mobile-venta__product-name {
    font-size: 11px;
    -webkit-line-clamp: 1;
    line-height: 1.15;
}
.tpv-mobile-venta__product.has-image .tpv-mobile-venta__product-price {
    font-size: 12px;
}

/* Modal detalle producto mobile — foto destacada arriba del listado de KPIs. */
.prod-mobile-detail__img-wrap {
    width: 100%;
    height: 180px;
    background: var(--bg-tertiary);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    margin-bottom: 12px;
}
.prod-mobile-detail__img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    display: block;
}

/* ════════════════════════════════════════════════════════
   2026-05-28 S4-FEATURE (Adri task #17)
   Long-press jiggle iOS + drag&drop reorden de productos.
   - .is-edit-mode en .tpv-mobile-venta → activa jiggle en todas las cells
   - @keyframes jiggle: rotación pequeña alternada (estilo iOS shake)
   - .is-dragging: cell siendo arrastrada (sin animation, opacity reducida)
   - .tpv-mobile-edit-overlay: barra flotante arriba con "Hecho" + "Cancelar"
   ════════════════════════════════════════════════════════ */
@keyframes tpvMobileJiggle {
    0%   { transform: rotate(-1.2deg); }
    50%  { transform: rotate(1.2deg); }
    100% { transform: rotate(-1.2deg); }
}
.is-edit-mode .tpv-mobile-venta__product {
    animation: tpvMobileJiggle 0.22s ease-in-out infinite;
    transform-origin: center center;
    /* Cada cell empieza la animación con un pequeño offset distinto para que
       no todas tiemblen sincronizadas (más natural, como iOS) */
}
.is-edit-mode .tpv-mobile-venta__product:nth-child(2n) {
    animation-delay: -0.11s;
}
.is-edit-mode .tpv-mobile-venta__product:nth-child(3n) {
    animation-delay: -0.07s;
}
.is-edit-mode .tpv-mobile-venta__product:active {
    /* En edit mode el tap NO debe escalar (es drag, no add to cart) */
    transform: scale(1);
}
.is-edit-mode .tpv-mobile-venta__product.is-dragging {
    animation: none;
    transform: scale(1.08);
    opacity: 0.85;
    z-index: 10;
    box-shadow: 0 8px 24px rgba(0,0,0,0.35);
    border-color: var(--accent-primary);
    /* 2026-05-29 FIX (Adri reporta drag no mueve): la card arrastrada
       captura el hit-test de elementFromPoint() del pointermove, por lo
       que SIEMPRE targetCell === d.cellEl y nunca dispara swap. Con
       pointer-events:none la card NO captura el hit-test → elementFromPoint
       devuelve la card debajo y el swap funciona. */
    pointer-events: none;
}
/* 2026-05-29 FIX: touch-action:none en TODAS las cards durante edit mode
   evita que el navegador interprete el drag como scroll vertical y cancele
   el pointermove a medio camino. Sin esto, en touch screens (L3) el drag
   no llega al handler. */
.is-edit-mode .tpv-mobile-venta__product {
    touch-action: none;
}
@media (prefers-reduced-motion: reduce) {
    .is-edit-mode .tpv-mobile-venta__product {
        animation: none;
        outline: 2px dashed var(--accent-primary);
        outline-offset: -3px;
    }
}

/* 2026-06-25 (Adri) — modo edición de categorías (chips superiores) en el Sunmi.
   Reusa @keyframes tpvMobileJiggle. Solo tiemblan los chips de categoría TPV
   (data-cat-tpv="1"); "Todos"/Dashboard/categorías de producto quedan fijos. */
.tpv-mobile-venta__chips.is-cat-edit .tpv-mobile-venta__chip[data-cat-tpv="1"] {
    animation: tpvMobileJiggle 0.22s ease-in-out infinite;
    transform-origin: center center;
    touch-action: none;
}
.tpv-mobile-venta__chips.is-cat-edit .tpv-mobile-venta__chip[data-cat-tpv="1"]:nth-child(2n) {
    animation-delay: -0.11s;
}
.tpv-mobile-venta__chips.is-cat-edit .tpv-mobile-venta__chip[data-cat-tpv="1"]:nth-child(3n) {
    animation-delay: -0.07s;
}
.tpv-mobile-venta__chips.is-cat-edit .tpv-mobile-venta__chip.is-dragging {
    animation: none;
    transform: scale(1.08);
    opacity: 0.85;
    z-index: 10;
    box-shadow: 0 6px 18px rgba(0,0,0,0.35);
    pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
    .tpv-mobile-venta__chips.is-cat-edit .tpv-mobile-venta__chip[data-cat-tpv="1"] {
        animation: none;
        outline: 2px dashed var(--accent-primary);
        outline-offset: -2px;
    }
}

.tpv-mobile-edit-overlay {
    position: fixed;
    top: env(safe-area-inset-top, 0px);
    left: 0;
    right: 0;
    z-index: 1100;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    --mano-lateral: 12px;
    padding: 10px var(--mano-lateral);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.25);
}
.tpv-mobile-edit-overlay__hint {
    flex: 1;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tpv-mobile-edit-overlay__btn {
    appearance: none;
    background: #ffffff;
    /* v6 Volt: fondo blanco fijo → tinta del contraste de relleno (casi negro con
       matiz lima). El acento lima puro daría ~1.3:1 sobre blanco. */
    color: var(--accent-fill-contrast);
    border: 0;
    border-radius: 8px;
    padding: 6px 14px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    flex: 0 0 auto;
}
.tpv-mobile-edit-overlay__btn:active {
    transform: scale(0.96);
}
.tpv-mobile-edit-overlay__btn--ghost {
    background: color-mix(in srgb, var(--accent-fill-contrast) 12%, transparent);
    color: var(--accent-fill-contrast);
    border: 1px solid color-mix(in srgb, var(--accent-fill-contrast) 35%, transparent);
}
.tpv-mobile-venta__product-name {
    font-size: 12px;
    font-weight: 500;
    line-height: 1.25;
    color: var(--text-primary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.tpv-mobile-venta__product-price {
    font-size: 13px;
    font-weight: 700;
    color: var(--accent-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tpv-mobile-venta__lines {
    /* 2026-05-28 S1 (Adri auditoría L3): cesta OCULTA por defecto. Solo se
     * muestra cuando se le añade la clase `.is-visible` por el toggle de
     * "Ver cesta". Antes ocupaba siempre el resto del body (flex:1 1 0) — eso
     * robaba espacio al catálogo. Ahora la cesta y el catálogo se excluyen
     * mutuamente y SOLO uno ocupa el espacio principal a la vez. */
    display: none;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 16px;
    padding: 8px var(--mano-lateral);
    flex-direction: column;
    gap: 8px;
}
.tpv-mobile-venta__lines.is-visible {
    display: flex;
    flex: 1 1 0;
}
.tpv-mobile-venta__line {
    display: grid;
    grid-template-columns: 1fr auto auto;
    grid-template-rows: auto auto;
    gap: 4px 12px;
    padding: 12px 14px;
    background: var(--bg-secondary);
    border-radius: 12px;
    border: 1px solid var(--border-primary);
}
.tpv-mobile-venta__line-name {
    grid-column: 1;
    grid-row: 1;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.tpv-mobile-venta__line-meta {
    grid-column: 1;
    grid-row: 2;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.tpv-mobile-venta__line-amount {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.tpv-mobile-venta__line-actions {
    grid-column: 3;
    grid-row: 1 / span 2;
    align-self: center;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.tpv-mobile-venta__line-actions button {
    min-width: 32px;
    height: 32px;
    border-radius: 8px;
    border: 1px solid var(--border-primary);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    cursor: pointer;
    font-size: 16px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 6px;
    -webkit-tap-highlight-color: transparent;
}
.tpv-mobile-venta__line-actions button:hover { background: var(--bg-hover); }
.tpv-mobile-venta__line-actions button:active { transform: translateY(1px); }

.tpv-mobile-venta__empty {
    /* 2026-05-28 (Adri auditoría L3 task #6): ocultar el placeholder del
       carrito cuando no hay líneas — ese hueco "Escanea EAN, busca, o toca
       un producto" robaba ~150px que se pueden destinar a productos rápidos.
       El grid de productos se expande gracias al flex:1 del .__lines vacío. */
    display: none;
}

.tpv-mobile-venta__summary {
    /* 2026-05-28 (Adri auditoría L3 task #6): summary compactado.
       Antes ocupaba ~80px (3 filas Subtotal/IVA/Total con padding generoso).
       Ahora ~50px: filas Subtotal/IVA en 1 fila lateral + Total grande.
       Sin perder información, gana ~30px para productos. */
    --mano-lateral: 16px;
    padding: 8px var(--mano-lateral) 0;
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 0 0 auto;
}
.tpv-mobile-venta__summary-row {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}
.tpv-mobile-venta__summary-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-variant-numeric: tabular-nums;
    margin-top: 2px;
}
.tpv-mobile-venta__summary-total .label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.tpv-mobile-venta__summary-total .value {
    /* Reducido de 28px → 22px — menos visualmente intrusivo pero sigue
       siendo el elemento más prominente del bloque inferior. */
    font-size: 22px;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.02em;
}

/* 2026-05-28 S1 (Adri auditoría L3): botón toggle catálogo/cesta. Visible
   solo si hay líneas (sin líneas no hay cesta que mostrar). Compacto —
   ocupa una sola fila entre el bloque IVA y el TOTAL. */
.tpv-mobile-venta__toggle-cesta {
    appearance: none;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    border-radius: 8px;
    padding: 6px 10px;
    margin-top: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    width: 100%;
}
.tpv-mobile-venta__toggle-cesta[aria-pressed="true"] {
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
}
.tpv-mobile-venta__toggle-cesta:active {
    transform: scale(0.98);
}
.tpv-mobile-venta__toggle-cesta > svg {
    width: 14px;
    height: 14px;
}

.tpv-mobile-venta__pay-row {
    /* 2026-05-26: padding-bottom incluye safe-area-inset-bottom para que la
       gesture bar de Android 14 (Sunmi L3) y el home indicator de iOS no
       tapen el botón Cobrar. Antes era padding fijo `20px` y el botón quedaba
       semioculto en el L3 vertical.
       2026-05-28 (Adri auditoría L3 task #6): padding-top reducido 12→8px
       y padding-bottom base 20→12px. Total ~30px menos en el bloque inferior. */
    --mano-lateral: 16px;
    padding: 8px var(--mano-lateral) calc(12px + env(safe-area-inset-bottom, 0px));
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.tpv-mobile-venta__pay {
    /* 2026-05-28 (Adri auditoría L3 task #6): altura reducida 56→48px y
       font-size 17→15px. Touch target sigue por encima del mínimo Material
       (48px). Sin perder protagonismo visual gracias al fondo verde sólido
       y al shadow. Gana ~10px más para el catálogo de productos. */
    width: 100%;
    height: 48px;
    border-radius: 12px;
    border: 0;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    cursor: pointer;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--accent-fill) 25%, transparent);
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms ease;
}
.tpv-mobile-venta__pay:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    box-shadow: none;
}
.tpv-mobile-venta__pay:focus-visible { outline: 3px solid var(--accent-blue); outline-offset: 2px; }
.tpv-mobile-venta__pay:active:not(:disabled) { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
    .tpv-mobile-venta__gesture-hint { transition: none; }
    .tpv-mobile-venta__pay:active:not(:disabled) { transform: none; transition: none; }
    .tpv-mobile-venta__line-actions button:active { transform: none; }
}

/* =====================================================
   ALMACÉN MÓVIL — Sesión 6/5 mobile UX
   SPEC: docs/specs/SPEC_MOBILE_UX.md §3.2 §4.2 §6.2 §8.1.
   Namespace `.almacen-mobile-stock__*` (pantalla principal — lista de stock)
   y `.almacen-mobile-dashboard__*` (Dashboard del módulo) calcados del patrón
   validado en TPV. Las defensas globales (overflow-x:hidden, safe-area-inset)
   ya están aplicadas en bloque .tpv-mobile-* / html,body — no se duplican aquí.
   ===================================================== */

/* ── Dashboard del módulo Almacén ── */
.almacen-mobile-dashboard {
    position: fixed;
    inset: 0;
    z-index: 1050;               /* sobre .content (~10) y bajo modales (1100+) */
    background: var(--bg-primary);
    color: var(--text-primary);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    flex-direction: column;
}

/* Defensa CSS: si por error queda un nodo en el DOM, lo ocultamos en
   tablet/desktop. Coherente con _isMobileViewport: handhelds Android (Sunmi L3
   ~720px + pointer:coarse) siguen mostrándolo. */
@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .almacen-mobile-dashboard { display: none !important; }
}

.almacen-mobile-dashboard__topbar {
    position: sticky;
    top: 0;
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    z-index: 2;
}

.almacen-mobile-dashboard__back {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.almacen-mobile-dashboard__back:hover { background: var(--bg-hover); }
.almacen-mobile-dashboard__back:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.almacen-mobile-dashboard__back > svg { width: 24px; height: 24px; }

.almacen-mobile-dashboard__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.almacen-mobile-dashboard__title-sub {
    color: var(--text-secondary);
    font-weight: 500;
}
.almacen-mobile-dashboard__topbar-spacer {
    width: 44px;
    height: 44px;
}

.almacen-mobile-dashboard__accesses {
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral);
    flex: 1;
}

.almacen-mobile-dashboard__section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 0 0 12px;
}

.almacen-mobile-dashboard__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.almacen-mobile-dashboard__access {
    appearance: none;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    padding: 14px 8px 10px;
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    min-height: 92px;
    position: relative;
}
.almacen-mobile-dashboard__access:hover { background: var(--bg-tertiary); }
.almacen-mobile-dashboard__access:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}
.almacen-mobile-dashboard__access:active {
    transform: scale(0.98);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.almacen-mobile-dashboard__access-ico {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
}
.almacen-mobile-dashboard__access-ico > svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 2;
}
.almacen-mobile-dashboard__access-ico[data-color="blue"]    { background: var(--accent-blue); }
.almacen-mobile-dashboard__access-ico[data-color="green"]   { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.almacen-mobile-dashboard__access-ico[data-color="red"]     { background: var(--accent-red); }
.almacen-mobile-dashboard__access-ico[data-color="orange"]  { background: var(--accent-orange); }
.almacen-mobile-dashboard__access-ico[data-color="purple"]  { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.almacen-mobile-dashboard__access-ico[data-color="primary"] { background: var(--accent-fill); color: var(--accent-fill-contrast); }

.almacen-mobile-dashboard__access-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .almacen-mobile-dashboard__access:active { transform: none; transition: none; }
}

/* ── Pantalla principal — lista de stock ── */
.almacen-mobile-stock {
    position: fixed;
    inset: 0;
    /* Mismo z-index que .tpv-mobile-venta (Bug 3 fix-mobile-ux-bugs):
     * 999 sobre cualquier sidebar/header residual del shell desktop. */
    z-index: 999;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

.almacen-mobile-stock__topbar {
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    position: relative;
    flex: 0 0 auto;
}
.almacen-mobile-stock__topbar-btn {
    width: 44px;
    height: 44px;
    /* Bug 3 (fix-mobile-ux-bugs): borde sutil + fondo ligero para visibilidad
     * en iPhone Safari mientras Lucide renderiza el icono. */
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.almacen-mobile-stock__topbar-btn:hover { background: var(--bg-hover); }
.almacen-mobile-stock__topbar-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.almacen-mobile-stock__topbar-spacer {
    width: 44px;
    height: 44px;
}
.almacen-mobile-stock__topbar-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: center;
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.almacen-mobile-stock__topbar-title small {
    color: var(--text-secondary);
    font-weight: 500;
}

/* Indicador de gesto (mismo patrón que TPV — fade-out a 8s desde JS) */
.almacen-mobile-stock__gesture-hint {
    position: absolute;
    top: calc(env(safe-area-inset-top, 0px) + 44px + 4px);
    left: 50%;
    transform: translateX(-50%);
    width: 30px;
    height: 3px;
    border-radius: 9999px;
    background: var(--text-primary);
    opacity: 0.4;
    z-index: 5;
    pointer-events: none;
    transition: opacity 600ms ease;
}
.almacen-mobile-stock__gesture-hint.is-fading { opacity: 0; }

.almacen-mobile-stock__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.almacen-mobile-stock__ean-row {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral);
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.almacen-mobile-stock__ean {
    width: 100%;
    height: 44px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 500;
    padding: 0 14px;
    font-variant-numeric: tabular-nums;
    -webkit-appearance: none;
    appearance: none;
}
.almacen-mobile-stock__ean::placeholder { color: var(--text-secondary); }
.almacen-mobile-stock__ean:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
    border-color: var(--accent-blue);
}

/* Catalog: chips horizontales + grid 3xN */
.almacen-mobile-stock__catalog {
    flex: 1 1 auto;
    --mano-lateral: 12px;
    padding: 0 var(--mano-lateral) 8px;
    border-bottom: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.almacen-mobile-stock__chips {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 6px 0;
    flex: 0 0 auto;
    scrollbar-width: none;
}
.almacen-mobile-stock__chips::-webkit-scrollbar { display: none; }
.almacen-mobile-stock__chip {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 14px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}
.almacen-mobile-stock__chip.is-active {
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
}

.almacen-mobile-stock__product-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 4px 0 8px;
    flex: 1 1 auto;
    min-height: 0;
}
.almacen-mobile-stock__product-grid.is-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    font-size: 13px;
    gap: 6px;
    padding: 20px 0;
}
.almacen-mobile-stock__product {
    min-height: 86px;
    border-radius: 10px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    padding: 8px 6px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: space-between;
    gap: 4px;
    text-align: left;
    font-family: inherit;
}
.almacen-mobile-stock__product:active {
    background: var(--bg-tertiary);
    transform: scale(0.97);
}
.almacen-mobile-stock__product.is-low {
    border-color: var(--accent-red);
}
.almacen-mobile-stock__product-name {
    font-size: 12px;
    font-weight: 500;
    line-height: 1.25;
    color: var(--text-primary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.almacen-mobile-stock__product-stock {
    font-size: 11px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.almacen-mobile-stock__product-price {
    font-size: 13px;
    font-weight: 700;
    color: var(--accent-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Footer: stock total + valoración (sin botón COBRAR — esto es Almacén) */
.almacen-mobile-stock__footer {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) 20px;
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 0 0 auto;
}
.almacen-mobile-stock__footer-row {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.almacen-mobile-stock__footer-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-variant-numeric: tabular-nums;
    margin-top: 4px;
}
.almacen-mobile-stock__footer-total .label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.almacen-mobile-stock__footer-total .value {
    font-size: 22px;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.02em;
}

/* Modal de detalle de producto (lotes + precintos) */
.modal.almacen-mobile-detail .almacen-mobile-detail__kpis {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin: 8px 0 16px;
}
.modal.almacen-mobile-detail .almacen-mobile-detail__kpis > div {
    background: var(--bg-secondary);
    border-radius: 10px;
    padding: 10px 8px;
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.modal.almacen-mobile-detail .almacen-mobile-detail__kpis .label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.modal.almacen-mobile-detail .almacen-mobile-detail__kpis .value {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.almacen-mobile-detail__lots {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 12px;
}
.almacen-mobile-detail__lot {
    background: var(--bg-tertiary);
    border-radius: 8px;
    border-left: 3px solid var(--border-primary);
    padding: 8px 10px;
    font-size: 13px;
}
.almacen-mobile-detail__lot[data-color="red"]    { border-left-color: var(--accent-red); }
.almacen-mobile-detail__lot[data-color="orange"] { border-left-color: var(--accent-orange); }
.almacen-mobile-detail__empty {
    color: var(--text-secondary);
    font-size: 12px;
    margin: 0 0 8px;
    font-style: italic;
}

/* Modal selector de almacén */
.modal.almacen-mobile-selector .modal-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.almacen-mobile-selector__opt {
    appearance: none;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-radius: 10px;
    padding: 12px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    -webkit-tap-highlight-color: transparent;
}
.almacen-mobile-selector__opt:hover { background: var(--bg-hover); }
.almacen-mobile-selector__opt.is-active {
    border-color: var(--accent-primary);
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
}
.almacen-mobile-selector__opt > svg { flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
    .almacen-mobile-stock__gesture-hint { transition: none; }
    .almacen-mobile-stock__product:active { transform: none; transition: none; }
}

/* =====================================================
   FACTURACIÓN MÓVIL — Sesión 7 mobile UX
   SPEC: docs/specs/SPEC_MOBILE_UX.md §3.2 §4.2 §6.3 §8.1.
   Namespace `.factura-mobile-list__*` (pantalla principal — lista de
   facturas) y `.factura-mobile-dashboard__*` (Dashboard del módulo)
   calcados del patrón validado en Almacén/TPV. Diferencia clave: la
   lista es vertical (filas con badge de estado + total), no grid 3xN.
   Las defensas globales (overflow-x, safe-area) ya están en .tpv-mobile-*
   / html,body — no se duplican.
   ===================================================== */

/* ── Dashboard del módulo Facturación ── */
.factura-mobile-dashboard {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: var(--bg-primary);
    color: var(--text-primary);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    flex-direction: column;
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .factura-mobile-dashboard { display: none !important; }
}

.factura-mobile-dashboard__topbar {
    position: sticky;
    top: 0;
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    z-index: 2;
}

.factura-mobile-dashboard__back {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.factura-mobile-dashboard__back:hover { background: var(--bg-hover); }
.factura-mobile-dashboard__back:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.factura-mobile-dashboard__back > svg { width: 24px; height: 24px; }

.factura-mobile-dashboard__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.factura-mobile-dashboard__title-sub {
    color: var(--text-secondary);
    font-weight: 500;
}
.factura-mobile-dashboard__topbar-spacer {
    width: 44px;
    height: 44px;
}

.factura-mobile-dashboard__accesses {
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral);
    flex: 1;
}

.factura-mobile-dashboard__section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 0 0 12px;
}

.factura-mobile-dashboard__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.factura-mobile-dashboard__access {
    appearance: none;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    padding: 14px 8px 10px;
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    min-height: 92px;
    position: relative;
}
.factura-mobile-dashboard__access:hover { background: var(--bg-tertiary); }
.factura-mobile-dashboard__access:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}
.factura-mobile-dashboard__access:active {
    transform: scale(0.98);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.factura-mobile-dashboard__access-ico {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
}
.factura-mobile-dashboard__access-ico > svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 2;
}
.factura-mobile-dashboard__access-ico[data-color="blue"]    { background: var(--accent-blue); }
.factura-mobile-dashboard__access-ico[data-color="green"]   { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.factura-mobile-dashboard__access-ico[data-color="red"]     { background: var(--accent-red); }
.factura-mobile-dashboard__access-ico[data-color="orange"]  { background: var(--accent-orange); }
.factura-mobile-dashboard__access-ico[data-color="purple"]  { background: var(--accent-purple, var(--accent-primary)); }
.factura-mobile-dashboard__access-ico[data-color="primary"] { background: var(--accent-fill); color: var(--accent-fill-contrast); }

.factura-mobile-dashboard__access-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .factura-mobile-dashboard__access:active { transform: none; transition: none; }
}

/* ── Pantalla principal — lista de facturas ── */
.factura-mobile-list {
    position: fixed;
    inset: 0;
    /* Mismo z-index que .almacen-mobile-stock / .tpv-mobile-venta
     * (Bug 3 fix-mobile-ux-bugs): 999 sobre cualquier sidebar/header
     * residual del shell desktop. */
    z-index: 999;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .factura-mobile-list { display: none !important; }
}

.factura-mobile-list__topbar {
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    position: relative;
    flex: 0 0 auto;
}
.factura-mobile-list__topbar-btn {
    width: 44px;
    height: 44px;
    /* Bug 3 (fix-mobile-ux-bugs): borde sutil + fondo ligero para
     * visibilidad en iPhone Safari mientras Lucide renderiza el icono. */
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.factura-mobile-list__topbar-btn:hover { background: var(--bg-hover); }
.factura-mobile-list__topbar-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.factura-mobile-list__topbar-spacer {
    width: 44px;
    height: 44px;
}
.factura-mobile-list__topbar-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: center;
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.factura-mobile-list__topbar-title small {
    color: var(--text-secondary);
    font-weight: 500;
}

/* Indicador de gesto (mismo patrón que TPV/Almacén — fade-out 8s) */
.factura-mobile-list__gesture-hint {
    position: absolute;
    top: calc(env(safe-area-inset-top, 0px) + 44px + 4px);
    left: 50%;
    transform: translateX(-50%);
    width: 30px;
    height: 3px;
    border-radius: 9999px;
    background: var(--text-primary);
    opacity: 0.4;
    z-index: 5;
    pointer-events: none;
    transition: opacity 600ms ease;
}
.factura-mobile-list__gesture-hint.is-fading { opacity: 0; }

.factura-mobile-list__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Buscador */
.factura-mobile-list__search-row {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) 8px;
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.factura-mobile-list__search {
    width: 100%;
    height: 44px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 500;
    padding: 0 14px;
    -webkit-appearance: none;
    appearance: none;
}
.factura-mobile-list__search::placeholder { color: var(--text-secondary); }
.factura-mobile-list__search:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
    border-color: var(--accent-blue);
}

/* Chips de estado */
.factura-mobile-list__chips {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 16px;
    padding: 4px var(--mano-lateral) 8px;
    flex: 0 0 auto;
    scrollbar-width: none;
}
.factura-mobile-list__chips::-webkit-scrollbar { display: none; }
.factura-mobile-list__chip {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 14px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}
.factura-mobile-list__chip.is-active {
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
}

/* Lista de facturas */
.factura-mobile-list__rows {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 4px var(--mano-lateral) 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
}
.factura-mobile-list__empty {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    font-size: 13px;
    gap: 6px;
    padding: 20px 0;
}

.factura-mobile-list__row {
    appearance: none;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    align-items: center;
    text-align: left;
    font-family: inherit;
    min-height: 64px;
}
.factura-mobile-list__row:active {
    background: var(--bg-tertiary);
    transform: scale(0.99);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.factura-mobile-list__row:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

.factura-mobile-list__row-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.factura-mobile-list__row-numero {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.factura-mobile-list__row-cliente {
    font-size: 12px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.factura-mobile-list__row-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    /* Bug 1 fix-mobile-ux-bugs: cualquier botón con monto monetario debe
     * llevar min-width: max-content para que el € no se trunque. */
    min-width: max-content;
}
.factura-mobile-list__row-total {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    min-width: max-content;
}
.factura-mobile-list__row-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* Badge de estado por color */
.factura-mobile-list__row-estado {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 9999px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    border: 1px solid var(--border-primary);
}
.factura-mobile-list__row-estado[data-estado="emitida"] {
    background: rgba(245, 158, 11, 0.12);
    color: var(--accent-orange);
    border-color: var(--accent-orange);
}
.factura-mobile-list__row-estado[data-estado="cobrada"] {
    background: color-mix(in srgb, var(--accent-green) 12%, transparent);
    color: var(--accent-green);
    border-color: var(--accent-green);
}
.factura-mobile-list__row-estado[data-estado="anulada"] {
    background: rgba(239, 68, 68, 0.12);
    color: var(--accent-red);
    border-color: var(--accent-red);
}
.factura-mobile-list__row-estado[data-estado="borrador"] {
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-secondary);
    border-color: var(--border-primary);
}
.factura-mobile-list__row-estado[data-estado="rectificada"] {
    background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
    color: var(--accent-blue);
    border-color: var(--accent-blue);
}
.factura-mobile-list__row-retraso {
    color: var(--accent-red);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Footer del mes */
.factura-mobile-list__footer {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) 20px;
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 0 0 auto;
}
.factura-mobile-list__footer-row {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.factura-mobile-list__footer-pendiente {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-variant-numeric: tabular-nums;
    margin-top: 4px;
}
.factura-mobile-list__footer-pendiente .label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.factura-mobile-list__footer-pendiente .value {
    font-size: 22px;
    font-weight: 700;
    color: var(--accent-orange);
    letter-spacing: -0.02em;
    /* min-width: max-content evita que el € se trunque (Bug 1). */
    min-width: max-content;
}

/* Modal de detalle de factura — KPIs + líneas + cobros + botón cobrar */
.modal.factura-mobile-detail .factura-mobile-detail__kpis {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin: 8px 0 16px;
}
.modal.factura-mobile-detail .factura-mobile-detail__kpis > div {
    background: var(--bg-secondary);
    border-radius: 10px;
    padding: 10px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.modal.factura-mobile-detail .factura-mobile-detail__kpis .label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.modal.factura-mobile-detail .factura-mobile-detail__kpis .value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.factura-mobile-detail__lineas {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
    max-height: 30vh;
    overflow-y: auto;
}
.factura-mobile-detail__lin {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    background: var(--bg-tertiary);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
}
.factura-mobile-detail__lin-desc {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
}
.factura-mobile-detail__lin-tot {
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    min-width: max-content;
}
.factura-mobile-detail__cobros {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
}
.factura-mobile-detail__cobro {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: color-mix(in srgb, var(--accent-green) 8%, transparent);
    border-left: 3px solid var(--accent-green);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.factura-mobile-detail__empty {
    color: var(--text-secondary);
    font-size: 12px;
    margin: 0 0 8px;
    font-style: italic;
}
.factura-mobile-detail__cobrar {
    width: 100%;
    min-height: 48px;
    /* Bug 1 fix-mobile-ux-bugs: botones con € deben llevar min-width:
     * max-content. Aquí el botón es full-width pero conservamos el
     * patrón por si el texto se internacionaliza. */
    min-width: max-content;
    margin-top: 8px;
}

/* Modal de registrar cobro */
.modal.factura-mobile-cobro .factura-mobile-cobro__importe {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    background: var(--bg-secondary);
    border-radius: 10px;
    padding: 12px 14px;
    margin: 4px 0 12px;
    font-size: 13px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.modal.factura-mobile-cobro .factura-mobile-cobro__importe strong {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
    min-width: max-content;
}
.factura-mobile-cobro__lab {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 10px;
    font-size: 12px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 500;
}
.factura-mobile-cobro__lab > .input {
    width: 100%;
    text-transform: none;
    letter-spacing: normal;
    font-weight: 400;
    color: var(--text-primary);
    font-size: 14px;
}

@media (prefers-reduced-motion: reduce) {
    .factura-mobile-list__gesture-hint { transition: none; }
    .factura-mobile-list__row:active { transform: none; transition: none; }
    .factura-mobile-dashboard__access:active { transform: none; transition: none; }
}

/* =====================================================
 * SESIÓN 8 MOBILE UX — Fabricación móvil (SPEC §6.4)
 * Namespace .fab-mobile-* calcado de .factura-mobile-* / .almacen-mobile-*.
 * Lista vertical (no grid) — las órdenes son ítems de información.
 * ===================================================== */

/* ── Dashboard del módulo (overlay full-screen) ── */
.fab-mobile-dashboard {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow-y: auto;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .fab-mobile-dashboard { display: none !important; }
}

.fab-mobile-dashboard__topbar {
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    z-index: 2;
}

.fab-mobile-dashboard__back {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fab-mobile-dashboard__back:hover { background: var(--bg-hover); }
.fab-mobile-dashboard__back:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.fab-mobile-dashboard__back > svg { width: 24px; height: 24px; }

.fab-mobile-dashboard__title {
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.fab-mobile-dashboard__title-sub {
    color: var(--text-secondary);
    font-weight: 500;
}
.fab-mobile-dashboard__topbar-spacer {
    width: 44px;
    height: 44px;
}

.fab-mobile-dashboard__accesses {
    --mano-lateral: 16px;
    padding: 16px var(--mano-lateral);
    flex: 1;
}

.fab-mobile-dashboard__section-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 0 0 12px;
}

.fab-mobile-dashboard__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.fab-mobile-dashboard__access {
    appearance: none;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    padding: 14px 8px 10px;
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    min-height: 92px;
    position: relative;
}
.fab-mobile-dashboard__access:hover { background: var(--bg-tertiary); }
.fab-mobile-dashboard__access:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}
.fab-mobile-dashboard__access:active {
    transform: scale(0.98);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.fab-mobile-dashboard__access-ico {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
}
.fab-mobile-dashboard__access-ico > svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 2;
}
.fab-mobile-dashboard__access-ico[data-color="blue"]    { background: var(--accent-blue); }
.fab-mobile-dashboard__access-ico[data-color="green"]   { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.fab-mobile-dashboard__access-ico[data-color="red"]     { background: var(--accent-red); }
.fab-mobile-dashboard__access-ico[data-color="orange"]  { background: var(--accent-orange); }
.fab-mobile-dashboard__access-ico[data-color="purple"]  { background: var(--accent-purple, var(--accent-primary)); }
.fab-mobile-dashboard__access-ico[data-color="primary"] { background: var(--accent-fill); color: var(--accent-fill-contrast); }

.fab-mobile-dashboard__access-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: center;
    line-height: 1.2;
    max-width: 84px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Pantalla principal — lista de órdenes ── */
.fab-mobile-list {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .fab-mobile-list { display: none !important; }
}

.fab-mobile-list__topbar {
    height: 44px;
    --mano-lateral: 6px;
    padding: 0 var(--mano-lateral);
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    position: relative;
    flex: 0 0 auto;
}
.fab-mobile-list__topbar-btn {
    width: 44px;
    height: 44px;
    /* Bug 3 fix-mobile-ux-bugs: borde + fondo ligero para visibilidad
     * en iPhone Safari mientras Lucide renderiza el icono. */
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.fab-mobile-list__topbar-btn:hover { background: var(--bg-hover); }
.fab-mobile-list__topbar-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.fab-mobile-list__topbar-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    text-align: center;
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fab-mobile-list__topbar-title small {
    color: var(--text-secondary);
    font-weight: 500;
}

.fab-mobile-list__gesture-hint {
    position: absolute;
    top: calc(env(safe-area-inset-top, 0px) + 44px + 4px);
    left: 50%;
    transform: translateX(-50%);
    width: 30px;
    height: 3px;
    border-radius: 9999px;
    background: var(--text-primary);
    opacity: 0.4;
    z-index: 5;
    pointer-events: none;
    transition: opacity 600ms ease;
}
.fab-mobile-list__gesture-hint.is-fading { opacity: 0; }

.fab-mobile-list__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.fab-mobile-list__search-row {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) 8px;
    background: var(--bg-primary);
    flex: 0 0 auto;
}
.fab-mobile-list__search {
    width: 100%;
    height: 44px;
    border-radius: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
    font-weight: 500;
    padding: 0 14px;
    -webkit-appearance: none;
    appearance: none;
}
.fab-mobile-list__search::placeholder { color: var(--text-secondary); }
.fab-mobile-list__search:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
    border-color: var(--accent-blue);
}

.fab-mobile-list__chips {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 16px;
    padding: 4px var(--mano-lateral) 8px;
    flex: 0 0 auto;
    scrollbar-width: none;
}
.fab-mobile-list__chips::-webkit-scrollbar { display: none; }
.fab-mobile-list__chip {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 14px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}
.fab-mobile-list__chip.is-active {
    background: var(--accent-fill);
    border-color: var(--accent-primary);
    color: var(--accent-fill-contrast);
}

.fab-mobile-list__rows {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 4px var(--mano-lateral) 8px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
}
.fab-mobile-list__empty {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    font-size: 13px;
    gap: 6px;
    padding: 20px 0;
}

.fab-mobile-list__row {
    appearance: none;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    align-items: center;
    text-align: left;
    font-family: inherit;
    min-height: 64px;
}
.fab-mobile-list__row:active {
    background: var(--bg-tertiary);
    transform: scale(0.99);
    transition: transform 80ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.fab-mobile-list__row:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

.fab-mobile-list__row-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.fab-mobile-list__row-numero {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 6px;
}
.fab-mobile-list__row-proceso {
    color: var(--text-secondary);
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.fab-mobile-list__row-producto {
    font-size: 12px;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fab-mobile-list__row-prio[data-prio="alta"] {
    display: inline-flex;
    align-items: center;
    color: var(--accent-red);
}
.fab-mobile-list__row-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    min-width: max-content;
}
.fab-mobile-list__row-fecha {
    font-size: 11px;
    color: var(--text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.fab-mobile-list__row-estado {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 9999px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    border: 1px solid var(--border-primary);
}
.fab-mobile-list__row-estado[data-estado="pendiente"] {
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-secondary);
    border-color: var(--border-primary);
}
.fab-mobile-list__row-estado[data-estado="materiales_ok"] {
    background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
    color: var(--accent-blue);
    border-color: var(--accent-blue);
}
.fab-mobile-list__row-estado[data-estado="en_proceso"] {
    background: rgba(245, 158, 11, 0.12);
    color: var(--accent-orange);
    border-color: var(--accent-orange);
}
.fab-mobile-list__row-estado[data-estado="completado"] {
    background: color-mix(in srgb, var(--accent-green) 12%, transparent);
    color: var(--accent-green);
    border-color: var(--accent-green);
}
.fab-mobile-list__row-estado[data-estado="cancelada"] {
    background: rgba(239, 68, 68, 0.12);
    color: var(--accent-red);
    border-color: var(--accent-red);
}

.fab-mobile-list__footer {
    --mano-lateral: 16px;
    padding: 12px var(--mano-lateral) 20px;
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 0 0 auto;
}
.fab-mobile-list__footer-row {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

/* ── Modal de detalle de orden ── */
.modal.fab-mobile-detail .fab-mobile-detail__kpis {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin: 8px 0 16px;
}
.modal.fab-mobile-detail .fab-mobile-detail__kpis > div {
    background: var(--bg-secondary);
    border-radius: 10px;
    padding: 10px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.modal.fab-mobile-detail .fab-mobile-detail__kpis .label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.modal.fab-mobile-detail .fab-mobile-detail__kpis .value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fab-mobile-detail__lineas {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
    max-height: 25vh;
    overflow-y: auto;
}
.fab-mobile-detail__lin {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    background: var(--bg-tertiary);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
}
.fab-mobile-detail__lin-desc {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 4px;
}
.fab-mobile-detail__lin-tot {
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    min-width: max-content;
}
.fab-mobile-detail__lin-ok {
    color: var(--accent-green);
    display: inline-flex;
    align-items: center;
}
.fab-mobile-detail__lin-pending {
    color: var(--text-secondary);
    display: inline-flex;
    align-items: center;
}
.fab-mobile-detail__cobros {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
    max-height: 22vh;
    overflow-y: auto;
}
.fab-mobile-detail__cobro {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: color-mix(in srgb, var(--accent-primary) 8%, transparent);
    border-left: 3px solid var(--accent-blue);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
/* Modificador NEGATIVO. Faltaba: fabricacion.js pinta la MERMA con la clase base,
   que tiene tinte lima (el color del dinero/OK en este sistema) y barra azul —
   una pérdida de producto se leía como un cobro. Aquí el tinte pasa a rojo y la
   barra al acento rojo, los dos tokens conmutados (dark y light). */
.fab-mobile-detail__cobro--negativo {
    background: var(--danger-bg);
    border-left: 3px solid var(--accent-red);
}
.fab-mobile-detail__empty {
    color: var(--text-secondary);
    font-size: 12px;
    margin: 0 0 8px;
    font-style: italic;
}
.fab-mobile-detail__action {
    width: 100%;
    min-height: 48px;
    min-width: max-content;
    margin-top: 8px;
}
.fab-mobile-detail__action-secondary {
    width: 100%;
    min-height: 44px;
    margin-top: 6px;
}

/* ── Vista trazabilidad (overlay z-index 1060 sobre dashboard 1050) ── */
.fab-mobile-traza {
    position: fixed;
    inset: 0;
    z-index: 1060;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    overflow-y: auto;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .fab-mobile-traza { display: none !important; }
}

.fab-mobile-traza__body {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 0 0 16px;
}
.fab-mobile-traza__actions {
    padding: 0 16px 12px;
    display: flex;
    gap: 8px;
}
.fab-mobile-traza__actions .btn {
    width: 100%;
    min-height: 44px;
}
.fab-mobile-traza__resultado {
    padding: 0 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.fab-mobile-traza__match {
    display: grid;
    grid-template-columns: 36px 1fr;
    gap: 12px;
    align-items: flex-start;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px 14px;
}
.fab-mobile-traza__match-ico {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--accent-blue);
    color: var(--accent-contrast);
    display: flex;
    align-items: center;
    justify-content: center;
}
.fab-mobile-traza__match-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.fab-mobile-traza__match-tipo {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
}
.fab-mobile-traza__match-valor {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    word-break: break-all;
}
.fab-mobile-traza__match .fab-mobile-detail__empty {
    grid-column: 1 / -1;
    margin-top: 8px;
}

.fab-mobile-traza__sugerencias-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin: 0 0 4px;
}
.fab-mobile-traza__sugerencias {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.fab-mobile-traza__sugerencia {
    display: grid;
    grid-template-columns: 80px 1fr;
    gap: 8px;
    background: var(--bg-tertiary);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: 13px;
}
.fab-mobile-traza__sug-tipo {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 10px;
    color: var(--text-secondary);
    font-weight: 600;
    align-self: center;
}
.fab-mobile-traza__sug-valor {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    word-break: break-all;
}

/* =====================================================
   DP-096 + DP-097 (2026-05-13)
   Formularios móviles de Fabricación — patrón mobile-first single column
   reutilizado por la pantalla "Nueva orden" y por el modal "Registrar merma".
   Aprovecha el shell .fab-mobile-traza (header + body scrollable) como
   contenedor full-screen, y añade reglas específicas de form.
   ===================================================== */
.fab-mobile-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-bottom: 24px;
}
.fab-mobile-form .fab-mobile-form__field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.fab-mobile-form .fab-mobile-form__field > label {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--text-secondary);
}
.fab-mobile-form .fab-mobile-form__field > input,
.fab-mobile-form .fab-mobile-form__field > select,
.fab-mobile-form .fab-mobile-form__field > textarea {
    width: 100%;
    min-height: 44px;          /* touch target ≥ 44px */
    padding: 10px 12px;
    border-radius: 10px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 16px;            /* evita zoom iOS al focus */
    font-variant-numeric: tabular-nums;
    box-sizing: border-box;
}
.fab-mobile-form .fab-mobile-form__field > textarea {
    resize: vertical;
    min-height: 72px;
    font-family: inherit;
}
.fab-mobile-form .fab-mobile-form__field > input:focus,
.fab-mobile-form .fab-mobile-form__field > select:focus,
.fab-mobile-form .fab-mobile-form__field > textarea:focus {
    /* Barrido 2026-07-03: var(--accent) no existe en theme.css (var fantasma) —
       outline/background/color-mix quedaban inválidos y la selección era invisible.
       Corregido a --accent-primary (la que usa el resto del archivo). */
    outline: 2px solid var(--accent-primary);
    outline-offset: 1px;
}
.fab-mobile-form .fab-mobile-form__hint {
    font-size: 11px;
    color: var(--text-secondary);
    margin-top: 2px;
}
.fab-mobile-form .fab-mobile-form__readonly {
    padding: 10px 12px;
    border-radius: 10px;
    border: 1px dashed var(--border-primary);
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 14px;
    min-height: 44px;
    display: flex;
    align-items: center;
}
.fab-mobile-form__row2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
@media (max-width: 360px) {
    .fab-mobile-form__row2 {
        grid-template-columns: 1fr;
    }
}
/* Refuerzo: chip seleccionado dentro de un form (selector proceso/escandallo)
   debe destacar más que el chip estado normal */
.fab-mobile-form .fab-mobile-list__chip.is-active {
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    border-color: var(--accent-primary);
}
/* Fila "escandallo" en form (reusa .fab-mobile-list__row pero con marcador
   de selección en el lado derecho via lucide check) */
.fab-mobile-form .fab-mobile-list__row.is-active {
    border-color: var(--accent-primary);
    background: color-mix(in oklab, var(--accent-primary) 8%, var(--bg-secondary));
}

@media (prefers-reduced-motion: reduce) {
    .fab-mobile-list__gesture-hint { transition: none; }
    .fab-mobile-list__row:active { transform: none; transition: none; }
    .fab-mobile-dashboard__access:active { transform: none; transition: none; }
}

/* =====================================================
   DP-098 + DP-099 (2026-05-13)
   PATRÓN BASE QR MÓVIL — .dvergent-mobile-qr-screen
   Shell factorizado reutilizable para todos los flujos QR del módulo
   Fabricación (deshuese fase 1/3, loncheado, troceado, fuet, reembasado) y
   futuros módulos con captura por escaneos sucesivos (Almacén etiquetado,
   Recepción precintos, etc.). NO duplicar este bloque por proceso.

   Estructura (top-down):
     <div class="dvergent-mobile-qr-screen">
        <header .dvergent-mobile-qr-screen__topbar>back + título + fase chip</header>
        <div .dvergent-mobile-qr-screen__body>
            <section .dvergent-mobile-qr-screen__capture>cámara/manual + peso</section>
            <section .dvergent-mobile-qr-screen__kpis>contadores en vivo</section>
            <section .dvergent-mobile-qr-screen__list>items acumulativos</section>
        </div>
        <footer .dvergent-mobile-qr-screen__footer>CTA finalizar full-width</footer>
     </div>

   Overlay z-index 1070 (sobre dashboard 1050 y traza 1060 — no necesita
   estar por encima del camera-scanner modal 10000, que se monta aparte).
   Hereda CSS variables del theme; no introduce variables nuevas (SPEC §5).
   ===================================================== */
.dvergent-mobile-qr-screen {
    position: fixed;
    inset: 0;
    z-index: 1070;
    background: var(--bg-primary);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    -webkit-font-smoothing: antialiased;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    overflow: hidden;
}

@media (min-width: 821px),
       (min-width: 600px) and (pointer: fine) {
    .dvergent-mobile-qr-screen { display: none !important; }
}

.dvergent-mobile-qr-screen__topbar {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: 44px 1fr auto;
    align-items: center;
    gap: 8px;
    --mano-lateral: 12px;
    padding: 8px var(--mano-lateral);
    border-bottom: 1px solid var(--border-primary);
    background: var(--bg-primary);
    min-height: 48px;
}
.dvergent-mobile-qr-screen__back {
    width: 44px;
    height: 44px;
    border: none;
    background: transparent;
    color: var(--text-primary);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.dvergent-mobile-qr-screen__back:active { background: var(--bg-tertiary); }
.dvergent-mobile-qr-screen__title {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dvergent-mobile-qr-screen__title-sub {
    color: var(--text-secondary);
    font-weight: 500;
    font-size: 12px;
}
.dvergent-mobile-qr-screen__phase-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 9999px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: color-mix(in srgb, var(--accent-primary) 12%, transparent);
    color: var(--accent-blue);
    border: 1px solid var(--accent-blue);
    min-width: max-content;
}
.dvergent-mobile-qr-screen__phase-chip[data-fase="1"] { background: rgba(245, 158, 11, 0.12); color: var(--accent-orange); border-color: var(--accent-orange); }
.dvergent-mobile-qr-screen__phase-chip[data-fase="3"] { background: color-mix(in srgb, var(--accent-green) 12%, transparent); color: var(--accent-green); border-color: var(--accent-green); }
.dvergent-mobile-qr-screen__phase-chip[data-fase="iberico"] { background: rgba(239, 68, 68, 0.12); color: var(--accent-red); border-color: var(--accent-red); }

.dvergent-mobile-qr-screen__body {
    flex: 1 1 auto;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
    --mano-lateral: 14px;
    padding: 12px var(--mano-lateral) 16px;
}

/* ── Caja de captura: cámara/manual + peso/báscula ── */
.dvergent-mobile-qr-screen__capture {
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    padding: 12px;
}
.dvergent-mobile-qr-screen__capture-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin: 0;
}
.dvergent-mobile-qr-screen__capture-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    align-items: center;
}
.dvergent-mobile-qr-screen__capture-row > input {
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border-radius: 10px;
    border: 1px solid var(--border-primary);
    background: var(--bg-primary);
    color: var(--text-primary);
    font-size: 16px;
    font-variant-numeric: tabular-nums;
    box-sizing: border-box;
}
.dvergent-mobile-qr-screen__capture-row > input:focus {
    outline: 2px solid var(--accent-blue);
    outline-offset: 1px;
}
.dvergent-mobile-qr-screen__capture-btn {
    min-height: 44px;
    padding: 0 14px;
    border-radius: 10px;
    border: 1px solid var(--accent-blue);
    background: var(--accent-blue);
    color: var(--accent-contrast);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.dvergent-mobile-qr-screen__capture-btn:active { transform: scale(0.98); }
.dvergent-mobile-qr-screen__capture-btn--secondary {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border-color: var(--border-primary);
}
.dvergent-mobile-qr-screen__capture-hint {
    font-size: 11px;
    color: var(--text-secondary);
    margin: 0;
}

/* ── Banner Norma del Ibérico (DP-099) ── */
.dvergent-mobile-qr-screen__iberico {
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid var(--accent-red);
    color: var(--text-primary);
    border-radius: 12px;
    padding: 10px 12px;
    font-size: 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.dvergent-mobile-qr-screen__iberico-title {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-red);
}
.dvergent-mobile-qr-screen__iberico-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 4px 8px;
    font-size: 12px;
}
.dvergent-mobile-qr-screen__iberico-grid b { font-weight: 600; }
.dvergent-mobile-qr-screen__iberico-color {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 1px solid var(--border-primary);
    vertical-align: middle;
    margin-right: 4px;
}
.dvergent-mobile-qr-screen__iberico-color[data-color="negro"]  { background: #111827; }
.dvergent-mobile-qr-screen__iberico-color[data-color="rojo"]   { background: #dc2626; }
.dvergent-mobile-qr-screen__iberico-color[data-color="verde"]  { background: var(--accent-green); }
.dvergent-mobile-qr-screen__iberico-color[data-color="blanco"] { background: #f8fafc; }

/* ── KPIs en vivo ── */
.dvergent-mobile-qr-screen__kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 8px;
}
.dvergent-mobile-qr-screen__kpi {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 8px 10px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.dvergent-mobile-qr-screen__kpi-label {
    font-size: 10px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dvergent-mobile-qr-screen__kpi-value {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dvergent-mobile-qr-screen__kpi[data-tone="ok"] .dvergent-mobile-qr-screen__kpi-value { color: var(--accent-green); }
.dvergent-mobile-qr-screen__kpi[data-tone="warn"] .dvergent-mobile-qr-screen__kpi-value { color: var(--accent-orange); }
.dvergent-mobile-qr-screen__kpi[data-tone="bad"] .dvergent-mobile-qr-screen__kpi-value { color: var(--accent-red); }

/* ── Lista acumulativa de items capturados ── */
.dvergent-mobile-qr-screen__list-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin: 4px 0 0;
}
.dvergent-mobile-qr-screen__list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.dvergent-mobile-qr-screen__list-row {
    display: grid;
    grid-template-columns: 28px 1fr auto;
    gap: 8px;
    align-items: center;
    background: var(--bg-tertiary);
    border-radius: 8px;
    padding: 8px 10px;
    font-size: 13px;
    min-height: 44px;
}
.dvergent-mobile-qr-screen__list-row[data-state="ok"] { border-left: 3px solid var(--accent-green); padding-left: 7px; }
.dvergent-mobile-qr-screen__list-row[data-state="ko"] { border-left: 3px solid var(--accent-red); padding-left: 7px; }
.dvergent-mobile-qr-screen__list-row[data-state="pending"] { border-left: 3px solid var(--accent-orange); padding-left: 7px; }
.dvergent-mobile-qr-screen__list-num {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.dvergent-mobile-qr-screen__list-main {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}
.dvergent-mobile-qr-screen__list-primary {
    color: var(--text-primary);
    font-weight: 600;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dvergent-mobile-qr-screen__list-secondary {
    color: var(--text-secondary);
    font-size: 11px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dvergent-mobile-qr-screen__list-side {
    color: var(--text-primary);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    min-width: max-content;
}
.dvergent-mobile-qr-screen__list-empty {
    color: var(--text-secondary);
    font-size: 12px;
    font-style: italic;
    padding: 8px 0;
    text-align: center;
}

/* ── Footer fijo con CTA principal ── */
.dvergent-mobile-qr-screen__footer {
    flex: 0 0 auto;
    --mano-lateral: 14px;
    padding: 10px var(--mano-lateral) calc(env(safe-area-inset-bottom, 0px) + 12px);
    background: var(--bg-primary);
    border-top: 1px solid var(--border-primary);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.dvergent-mobile-qr-screen__cta {
    width: 100%;
    min-height: 52px;
    padding: 0 16px;
    border-radius: 12px;
    border: none;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.dvergent-mobile-qr-screen__cta:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}
.dvergent-mobile-qr-screen__cta:not(:disabled):active { transform: scale(0.99); }
.dvergent-mobile-qr-screen__cta--secondary {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border-primary);
    min-height: 44px;
    font-size: 14px;
    font-weight: 600;
}

/* ── Selector de proceso QR (5 cards 2-col grid) ── */
.dvergent-mobile-qr-selector {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    --mano-lateral: 14px;
    padding: 16px var(--mano-lateral);
}
.dvergent-mobile-qr-selector__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 18px 12px;
    border-radius: 16px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    min-height: 120px;
    text-align: center;
}
.dvergent-mobile-qr-selector__card:active { transform: scale(0.98); background: var(--bg-tertiary); }
.dvergent-mobile-qr-selector__card-ico {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: var(--accent-blue);
    color: var(--accent-contrast);
    display: flex;
    align-items: center;
    justify-content: center;
}
.dvergent-mobile-qr-selector__card-ico[data-color="orange"]  { background: var(--accent-orange); }
.dvergent-mobile-qr-selector__card-ico[data-color="purple"]  { background: #8b5cf6; }
.dvergent-mobile-qr-selector__card-ico[data-color="green"]   { background: var(--accent-green); }
.dvergent-mobile-qr-selector__card-ico[data-color="primary"] { background: var(--accent-primary, var(--accent-blue)); }
.dvergent-mobile-qr-selector__card-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}
.dvergent-mobile-qr-selector__card-hint {
    font-size: 11px;
    color: var(--text-secondary);
    line-height: 1.3;
}

/* Orden a fabricar — selector previo a la sub-pantalla */
.dvergent-mobile-qr-screen__orden-selector {
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.dvergent-mobile-qr-screen__orden-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    align-items: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    text-align: left;
    color: var(--text-primary);
    font-family: inherit;
    min-height: 64px;
}
.dvergent-mobile-qr-screen__orden-row:active { background: var(--bg-tertiary); }

@media (prefers-reduced-motion: reduce) {
    .dvergent-mobile-qr-screen__back:active,
    .dvergent-mobile-qr-screen__cta:not(:disabled):active,
    .dvergent-mobile-qr-selector__card:active,
    .dvergent-mobile-qr-screen__orden-row:active { transform: none; }
}

/* =====================================================
   Bug D (sesión fix-mobile-ux-bugs-v2 2026-04-30)
   FAB botón casa global — visible en cualquier módulo móvil que NO tenga
   su propia top bar con botón casa. Inyectado por app.js::_ensureMobileHomeButton.
   Los 4 módulos con top bar propia (TPV, Almacén, Facturación, Fabricación)
   lo OCULTAN cuando su vista está activa, vía body[data-mobile-module-shell].
   ===================================================== */
.mobile-home-btn {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    left: calc(env(safe-area-inset-left, 0px) + 12px);
    width: 48px;
    height: 48px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 998;                /* bajo modal-overlay (1000) y mobile-slidedown (1100) */
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
    -webkit-tap-highlight-color: transparent;
    padding: 0;
    appearance: none;
}
.mobile-home-btn:active { transform: scale(0.94); background: var(--bg-tertiary); }
.mobile-home-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: 2px; }

/* Cuando un módulo monta su propia vista móvil con top bar (TPV, Almacén,
   Facturación, Fabricación), ocultamos el FAB para evitar duplicación con el
   botón casa de su top bar. Detección por:
   - data-mobile-module-shell explícito en el body (TPV lo marca tras sesión fix).
   - presencia del DOM de la vista móvil del módulo via :has() (resto). */
body[data-mobile-module-shell] .mobile-home-btn,
body:has(#tpvMobileVentaRoot) .mobile-home-btn,
body:has(.tpv-mobile-venta) .mobile-home-btn,
body:has(.almacen-mobile-stock) .mobile-home-btn,
body:has(.almacen-mobile-dashboard) .mobile-home-btn,
body:has(.factura-mobile-list) .mobile-home-btn,
body:has(.factura-mobile-dashboard) .mobile-home-btn,
body:has(.fab-mobile-list) .mobile-home-btn,
body:has(.fab-mobile-dashboard) .mobile-home-btn,
body:has(.dvergent-mobile-qr-screen) .mobile-home-btn,
body:has(#tpvMobileDashboardRoot) .mobile-home-btn,
body:has(.ch-mobile-fichaje) .mobile-home-btn,
body:has(.ch-mobile-dashboard) .mobile-home-btn,
body:has(.prod-mobile-list) .mobile-home-btn,
body:has(.prod-mobile-dashboard) .mobile-home-btn,
body:has(.cli-mobile-list) .mobile-home-btn,
body:has(.cli-mobile-dashboard) .mobile-home-btn,
body:has(.cal-mobile-list) .mobile-home-btn,
body:has(.cal-mobile-dashboard) .mobile-home-btn,
body:has(.prov-mobile-list) .mobile-home-btn,
body:has(.prov-mobile-dashboard) .mobile-home-btn,
body:has(.cumpl-mobile-list) .mobile-home-btn,
body:has(.cumpl-mobile-dashboard) .mobile-home-btn,
body:has(.sop-mobile-list) .mobile-home-btn,
body:has(.sop-mobile-dashboard) .mobile-home-btn,
body:has(.rrhh-mobile-list) .mobile-home-btn,
body:has(.rrhh-mobile-dashboard) .mobile-home-btn { display: none !important; }

/* =====================================================
   Sesión C-Alto (2026-04-30) — bloque base factorizado
   .dvergent-mobile-screen-* / .dvergent-mobile-dashboard-*

   Origen: las sesiones 5–8 (TPV, Almacén, Facturación, Fabricación)
   replicaron el mismo patrón con namespaces propios
   (.tpv-mobile-*, .almacen-mobile-*, .factura-mobile-*, .fab-mobile-*),
   duplicando ~250 líneas de CSS por módulo. Al sumar 4 módulos más
   (Control Horario, Productos, Clientes, Calidad) la duplicación
   crecería linealmente.

   Solución (decisión sesión C-Alto): los 4 módulos NUEVOS usan estas
   clases base. Solo declaran sus overrides específicos en namespaces
   propios (.ch-mobile-fichaje, .prod-mobile-list, .cli-mobile-list,
   .cal-mobile-list) — colores de chips, badges de estado, layouts
   especiales. Reduce ~700 líneas vs replicar el patrón.

   Decisión consciente: NO se migran los 4 módulos previos en esta
   sesión. Refactor pendiente registrado como DP-105 en TECH_DEBT.md.
   ===================================================== */

.dvergent-mobile-screen {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: var(--bg-primary);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    -webkit-tap-highlight-color: transparent;
    box-sizing: border-box;
}
.dvergent-mobile-screen *,
.dvergent-mobile-screen *::before,
.dvergent-mobile-screen *::after { box-sizing: border-box; }

.dvergent-mobile-screen__topbar {
    flex: 0 0 auto;
    height: 44px;
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    --mano-lateral: 8px;
    padding: 0 var(--mano-lateral);
    background: var(--bg-primary);
    border-bottom: 1px solid var(--border-primary);
    position: relative;
}
.dvergent-mobile-screen__topbar-btn {
    width: 44px; height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 9999px;
    color: var(--text-primary);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.dvergent-mobile-screen__topbar-btn:hover { background: var(--bg-hover); }
.dvergent-mobile-screen__topbar-btn:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.dvergent-mobile-screen__topbar-spacer { width: 44px; height: 44px; }
.dvergent-mobile-screen__topbar-title {
    text-align: center;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    line-height: 1.2;
}
.dvergent-mobile-screen__topbar-title small {
    font-weight: 400;
    color: var(--text-secondary);
    font-size: 13px;
    margin-left: 2px;
}

.dvergent-mobile-screen__gesture-hint {
    position: absolute;
    top: 47px; left: 50%;
    transform: translateX(-50%);
    width: 30px; height: 3px;
    background: var(--text-secondary);
    border-radius: 2px;
    opacity: 0.4;
    pointer-events: none;
    transition: opacity 1s ease-out;
    z-index: 1;
}
.dvergent-mobile-screen__gesture-hint.is-fading { opacity: 0; }

.dvergent-mobile-screen__body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.dvergent-mobile-screen__search-row {
    flex: 0 0 auto;
    --mano-lateral: 12px;
    padding: 12px var(--mano-lateral) 8px;
    background: var(--bg-primary);
}
.dvergent-mobile-screen__search {
    width: 100%;
    height: 44px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    border-radius: 12px;
    padding: 0 16px;
    font-size: 15px;
    -webkit-appearance: none;
    appearance: none;
    font-family: inherit;
}
.dvergent-mobile-screen__search::placeholder { color: var(--text-secondary); }
.dvergent-mobile-screen__search:focus {
    outline: none;
    border-color: var(--accent-blue);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-primary) 15%, transparent);
}

.dvergent-mobile-screen__chips {
    flex: 0 0 auto;
    display: flex;
    gap: 8px;
    --mano-lateral: 12px;
    padding: 0 var(--mano-lateral) 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.dvergent-mobile-screen__chips::-webkit-scrollbar { display: none; }
.dvergent-mobile-screen__chip {
    flex: 0 0 auto;
    height: 36px;
    padding: 0 14px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: 4px;
}
.dvergent-mobile-screen__chip.is-active {
    background: var(--accent-blue);
    border-color: var(--accent-blue);
    color: var(--accent-contrast);
}

.dvergent-mobile-screen__list {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    --mano-lateral: 12px;
    padding: 4px var(--mano-lateral) 12px;
}
.dvergent-mobile-screen__empty {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px;
    padding: 32px 12px;
    color: var(--text-secondary);
    font-size: 14px;
}
.dvergent-mobile-screen__row {
    display: flex; align-items: center; gap: 12px;
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px;
    margin-bottom: 8px;
    cursor: pointer;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
    color: var(--text-primary);
    font-family: inherit;
}
.dvergent-mobile-screen__row:active {
    background: var(--bg-tertiary);
    transform: scale(0.99);
    transition: transform 80ms ease-out;
}
.dvergent-mobile-screen__row:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.dvergent-mobile-screen__row-main {
    flex: 1 1 auto;
    display: flex; flex-direction: column;
    min-width: 0;
    gap: 2px;
}
.dvergent-mobile-screen__row-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dvergent-mobile-screen__row-sub {
    font-size: 12px;
    color: var(--text-secondary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dvergent-mobile-screen__row-side {
    flex: 0 0 auto;
    display: flex; flex-direction: column;
    align-items: flex-end;
    gap: 4px;
}
.dvergent-mobile-screen__badge {
    display: inline-flex; align-items: center;
    padding: 2px 8px;
    border-radius: 9999px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    white-space: nowrap;
    border: 1px solid transparent;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
}

.dvergent-mobile-screen__footer {
    flex: 0 0 auto;
    --mano-lateral: 16px;
    padding: 10px var(--mano-lateral);
    border-top: 1px solid var(--border-primary);
    background: var(--bg-secondary);
    display: flex; flex-direction: column;
    gap: 4px;
}
.dvergent-mobile-screen__footer-row {
    display: flex; justify-content: space-between; align-items: center;
    font-size: 13px;
    color: var(--text-secondary);
}
.dvergent-mobile-screen__footer-row strong {
    color: var(--text-primary);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.dvergent-mobile-screen__fab {
    position: absolute;
    right: calc(env(safe-area-inset-right, 0px) + 16px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 80px);
    width: 56px; height: 56px;
    border-radius: 9999px;
    border: none;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
    cursor: pointer;
    z-index: 5;
    -webkit-tap-highlight-color: transparent;
    padding: 0;
}
.dvergent-mobile-screen__fab:active { transform: scale(0.94); }

/* Dashboard del módulo (overlay full-screen sobre la pantalla principal) */
.dvergent-mobile-dashboard {
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: var(--bg-primary);
    display: flex; flex-direction: column;
    overflow: hidden;
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
}
.dvergent-mobile-dashboard *,
.dvergent-mobile-dashboard *::before,
.dvergent-mobile-dashboard *::after { box-sizing: border-box; }
.dvergent-mobile-dashboard__topbar {
    flex: 0 0 auto;
    height: 44px;
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    --mano-lateral: 8px;
    padding: 0 var(--mano-lateral);
    border-bottom: 1px solid var(--border-primary);
}
.dvergent-mobile-dashboard__back {
    width: 44px; height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 9999px;
    color: var(--text-primary);
    cursor: pointer;
    padding: 0;
}
.dvergent-mobile-dashboard__back:hover { background: var(--bg-hover); }
.dvergent-mobile-dashboard__back:focus-visible { outline: 2px solid var(--accent-blue); outline-offset: -2px; }
.dvergent-mobile-dashboard__topbar-spacer { width: 44px; height: 44px; }
.dvergent-mobile-dashboard__title {
    text-align: center;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dvergent-mobile-dashboard__title-sub {
    font-weight: 400;
    color: var(--text-secondary);
    font-size: 13px;
}
.dvergent-mobile-dashboard__accesses {
    flex: 1 1 auto;
    overflow-y: auto;
    --mano-lateral: 12px;
    padding: 16px var(--mano-lateral);
}
.dvergent-mobile-dashboard__section-label {
    margin: 4px 4px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.dvergent-mobile-dashboard__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}
.dvergent-mobile-dashboard__access {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px;
    min-height: 88px;
    padding: 14px 10px;
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    text-align: center;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
}
.dvergent-mobile-dashboard__access:hover { background: var(--bg-tertiary); }
.dvergent-mobile-dashboard__access:focus-visible {
    outline: 2px solid var(--accent-blue); outline-offset: -2px;
}
.dvergent-mobile-dashboard__access:active {
    transform: scale(0.98);
    transition: transform 80ms ease-out;
}
.dvergent-mobile-dashboard__access-ico {
    width: 44px; height: 44px;
    border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--accent-contrast);
    background: var(--accent-primary);
}
.dvergent-mobile-dashboard__access-ico > svg { width: 22px; height: 22px; stroke: currentColor; stroke-width: 2; }
.dvergent-mobile-dashboard__access-ico[data-color="blue"]    { background: var(--accent-blue); }
.dvergent-mobile-dashboard__access-ico[data-color="green"]   { background: var(--accent-green); }
.dvergent-mobile-dashboard__access-ico[data-color="red"]     { background: var(--accent-red); }
.dvergent-mobile-dashboard__access-ico[data-color="orange"]  { background: var(--accent-orange); }
.dvergent-mobile-dashboard__access-ico[data-color="purple"]  { background: var(--accent-purple, var(--accent-primary)); }
.dvergent-mobile-dashboard__access-ico[data-color="primary"] { background: var(--accent-primary); }
.dvergent-mobile-dashboard__access-ico[data-color="indigo"]  { background: var(--accent-indigo, var(--accent-primary)); }
.dvergent-mobile-dashboard__access-ico[data-color="cyan"]    { background: var(--accent-cyan, var(--accent-blue)); }
.dvergent-mobile-dashboard__access-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    line-height: 1.2;
}

@media (prefers-reduced-motion: reduce) {
    .dvergent-mobile-screen__gesture-hint { transition: none; }
    .dvergent-mobile-screen__row:active { transform: none; transition: none; }
    .dvergent-mobile-dashboard__access:active { transform: none; transition: none; }
    .dvergent-mobile-screen__fab:active { transform: none; }
}

/* =====================================================
   Overrides específicos por módulo (sesión C-Alto)
   Solo lo que se desvía del patrón base — colores de badges por estado,
   layouts especiales (botón gigante de fichar), botones de acción.
   ===================================================== */

/* ── Control Horario — pantalla de fichaje (botón GIGANTE central) ── */
.ch-mobile-fichaje__hero {
    flex: 1 1 auto;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    --mano-lateral: 16px;
    padding: 20px var(--mano-lateral);
    gap: 18px;
    text-align: center;
}
.ch-mobile-fichaje__hello {
    font-size: 14px; color: var(--text-secondary);
    margin: 0;
}
.ch-mobile-fichaje__hello strong { color: var(--text-primary); font-weight: 600; }
.ch-mobile-fichaje__btn {
    width: 220px; height: 220px;
    border-radius: 9999px;
    border: 6px solid var(--bg-secondary);
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px;
    cursor: pointer;
    box-shadow: 0 12px 30px rgba(0,0,0,0.25);
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
    padding: 0;
    transition: transform 0.15s ease-out, background 0.2s ease-out;
}
.ch-mobile-fichaje__btn[data-tipo="salida"] { background: var(--accent-orange); }
.ch-mobile-fichaje__btn[data-disabled="true"] {
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    cursor: not-allowed;
    box-shadow: none;
}
.ch-mobile-fichaje__btn:active:not([data-disabled="true"]) { transform: scale(0.96); }
.ch-mobile-fichaje__btn-ico { width: 64px; height: 64px; }
.ch-mobile-fichaje__btn-ico > svg { width: 64px; height: 64px; stroke-width: 2.5; }
.ch-mobile-fichaje__btn-label {
    font-size: 22px; font-weight: 700; letter-spacing: 0.5px;
    text-transform: uppercase;
}
.ch-mobile-fichaje__btn-sub {
    font-size: 12px; opacity: 0.85; font-weight: 500;
}
.ch-mobile-fichaje__estado {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    width: 100%; max-width: 320px;
    padding: 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
}
.ch-mobile-fichaje__estado-cell {
    display: flex; flex-direction: column;
    gap: 2px;
    text-align: left;
}
.ch-mobile-fichaje__estado-cell .label {
    font-size: 11px; color: var(--text-secondary);
    text-transform: uppercase; letter-spacing: 0.4px;
}
.ch-mobile-fichaje__estado-cell .value {
    font-size: 16px; font-weight: 600; color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.ch-mobile-fichaje__warn {
    margin: 0; padding: 10px 14px;
    background: rgba(245, 158, 11, 0.12);
    color: var(--accent-orange);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 10px;
    font-size: 12px; max-width: 320px; text-align: center;
}

/* ── Productos — overrides de lista ── */
.prod-mobile-list__row-stock { font-size: 13px; font-weight: 600; }
.prod-mobile-list__row-stock[data-bajo="true"] { color: var(--accent-red); }
.prod-mobile-list__row-stock[data-bajo="false"] { color: var(--text-primary); }
.prod-mobile-list__badge[data-tipo="materia_prima"] { background: rgba(59,130,246,0.15); color: var(--accent-blue); border-color: rgba(59,130,246,0.3); }
.prod-mobile-list__badge[data-tipo="acabado"]       { background: color-mix(in srgb, var(--accent-green) 15%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.prod-mobile-list__badge[data-tipo="servicio"]      { background: rgba(168,85,247,0.15); color: var(--accent-purple, var(--accent-primary)); border-color: rgba(168,85,247,0.3); }
.prod-mobile-list__alergeno-chip {
    display: inline-flex; align-items: center;
    padding: 4px 10px; border-radius: 9999px;
    background: rgba(239, 68, 68, 0.12);
    color: #991b1b;
    border: 1px solid rgba(239, 68, 68, 0.3);
    font-size: 12px; font-weight: 600;
    margin: 2px 4px 2px 0;
}

/* ── Clientes — saldo coloreado + botones rápidos ── */
.cli-mobile-list__saldo[data-pendiente="true"] {
    color: var(--accent-red); font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.cli-mobile-list__saldo[data-pendiente="false"] {
    color: var(--text-secondary); font-weight: 500;
    font-variant-numeric: tabular-nums;
}
.cli-mobile-list__quick {
    display: flex; gap: 6px; margin-top: 4px;
}
.cli-mobile-list__quick-btn {
    flex: 0 0 auto;
    height: 32px; padding: 0 12px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 12px; font-weight: 600;
    display: inline-flex; align-items: center; gap: 4px;
    text-decoration: none;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.cli-mobile-list__quick-btn[data-disabled="true"] {
    opacity: 0.4; pointer-events: none;
}
.cli-mobile-list__quick-btn[data-color="green"] { background: color-mix(in srgb, var(--accent-green) 12%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.cli-mobile-list__quick-btn[data-color="blue"]  { background: rgba(59,130,246,0.12); color: var(--accent-blue);  border-color: rgba(59,130,246,0.3); }

/* ── Calidad — gravedad/estado de incidencias ── */
.cal-mobile-list__row-grav[data-grav="critica"] { background: rgba(220,38,38,0.18); color: #DC2626; border-color: rgba(220,38,38,0.4); }
.cal-mobile-list__row-grav[data-grav="alta"]    { background: rgba(239,68,68,0.15);  color: #EF4444; border-color: rgba(239,68,68,0.3); }
.cal-mobile-list__row-grav[data-grav="moderada"]{ background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.cal-mobile-list__row-grav[data-grav="leve"]    { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.cal-mobile-list__row-estado[data-estado="abierta"]  { background: rgba(239,68,68,0.15);  color: #EF4444; border-color: rgba(239,68,68,0.3); }
.cal-mobile-list__row-estado[data-estado="en_curso"] { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.cal-mobile-list__row-estado[data-estado="cerrada"]  { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.cal-mobile-list__row-tipo {
    font-size: 11px; color: var(--text-secondary);
    text-transform: uppercase; letter-spacing: 0.3px;
}

/* Modal detalle compartido — estilo coherente con .fab-mobile-detail */
.dvergent-mobile-detail__kpis {
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
    margin-bottom: 12px;
}
.dvergent-mobile-detail__kpis > div {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 8px 10px;
    display: flex; flex-direction: column; gap: 2px;
}
.dvergent-mobile-detail__kpis .label {
    font-size: 11px; color: var(--text-secondary);
    text-transform: uppercase; letter-spacing: 0.4px;
}
.dvergent-mobile-detail__kpis .value {
    font-size: 14px; font-weight: 600; color: var(--text-primary);
    font-variant-numeric: tabular-nums; word-break: break-word;
}
.dvergent-mobile-detail__action {
    width: 100%; min-height: 48px;
    margin-top: 12px;
    font-size: 15px; font-weight: 600;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.dvergent-mobile-detail__action-secondary {
    width: 100%; min-height: 44px;
    margin-top: 8px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border-primary);
    font-size: 14px;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.dvergent-mobile-detail__empty {
    text-align: center;
    color: var(--text-secondary);
    font-size: 13px;
    padding: 12px 0;
}

/* =====================================================
   Sesión C-Medio (2026-04-30) — Overrides específicos
   por módulo (Proveedores, Cumplimiento, Soporte, RRHH).
   Reusa el bloque base .dvergent-mobile-screen-* / .dvergent-mobile-dashboard-*
   factorizado en C-Alto. Solo modifiers (chips, badges por estado,
   layouts especiales como avatar de empleado).
   ===================================================== */

/* ── Proveedores — botones rápidos tap-to-call/email (calcado de Clientes) ── */
.prov-mobile-list__quick {
    display: flex; gap: 6px; margin-top: 4px;
}
.prov-mobile-list__quick-btn {
    flex: 0 0 auto;
    height: 32px; padding: 0 12px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 12px; font-weight: 600;
    display: inline-flex; align-items: center; gap: 4px;
    text-decoration: none;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.prov-mobile-list__quick-btn[data-disabled="true"] {
    opacity: 0.4; pointer-events: none;
}
.prov-mobile-list__quick-btn[data-color="green"] { background: color-mix(in srgb, var(--accent-green) 12%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.prov-mobile-list__quick-btn[data-color="blue"]  { background: rgba(59,130,246,0.12); color: var(--accent-blue);  border-color: rgba(59,130,246,0.3); }

/* ── Cumplimiento — estado checklist + items de ejecución ── */
.cumpl-mobile-list__row-estado[data-estado="pendiente"]  { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.cumpl-mobile-list__row-estado[data-estado="en_curso"]   { background: rgba(59,130,246,0.15); color: var(--accent-blue);   border-color: rgba(59,130,246,0.3); }
.cumpl-mobile-list__row-estado[data-estado="completado"] { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green);  border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.cumpl-mobile-list__row-estado[data-estado="cerrada"]    { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green);  border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.cumpl-mobile-list__progreso {
    display: inline-flex; align-items: center;
    margin-top: 4px;
    padding: 2px 8px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 11px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    font-variant-numeric: tabular-nums;
}
.cumpl-mobile-list__progreso[data-pct="100"] {
    background: color-mix(in srgb, var(--accent-green) 15%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent);
}
.cumpl-mobile-list__items {
    display: flex; flex-direction: column; gap: 8px;
    margin-top: 8px;
}
.cumpl-mobile-list__item {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 10px;
    display: flex; flex-direction: column; gap: 6px;
}
.cumpl-mobile-list__item-text {
    font-size: 13px;
    color: var(--text-primary);
    line-height: 1.4;
}
.cumpl-mobile-list__item-radios {
    display: flex; gap: 6px; flex-wrap: wrap;
}
.cumpl-mobile-list__radio {
    flex: 1 1 auto;
    min-height: 36px;
    padding: 0 10px;
    border-radius: 9999px;
    border: 1px solid var(--border-primary);
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 12px; font-weight: 600;
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.cumpl-mobile-list__radio[disabled] { opacity: 0.4; pointer-events: none; }
.cumpl-mobile-list__radio.is-active[data-color="green"] { background: var(--accent-green); color: var(--accent-contrast); border-color: var(--accent-green); }
.cumpl-mobile-list__radio.is-active[data-color="red"]   { background: var(--accent-red);   color: var(--accent-contrast); border-color: var(--accent-red); }
.cumpl-mobile-list__radio.is-active[data-color="gray"]  { background: var(--text-secondary); color: var(--bg-primary); border-color: var(--text-secondary); }

/* ── Soporte — prioridad + estado de ticket ── */
.sop-mobile-list__row-prio[data-prio="critica"] { background: rgba(220,38,38,0.18); color: #DC2626; border-color: rgba(220,38,38,0.4); }
.sop-mobile-list__row-prio[data-prio="alta"]    { background: rgba(239,68,68,0.15); color: #EF4444; border-color: rgba(239,68,68,0.3); }
.sop-mobile-list__row-prio[data-prio="media"]   { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.sop-mobile-list__row-prio[data-prio="baja"]    { background: color-mix(in srgb, var(--accent-green) 15%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.sop-mobile-list__row-estado[data-estado="abierto"]            { background: rgba(239,68,68,0.15); color: #EF4444; border-color: rgba(239,68,68,0.3); }
.sop-mobile-list__row-estado[data-estado="en_progreso"]        { background: rgba(59,130,246,0.15); color: var(--accent-blue); border-color: rgba(59,130,246,0.3); }
.sop-mobile-list__row-estado[data-estado="esperando_usuario"]  { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.sop-mobile-list__row-estado[data-estado="resuelto"]           { background: color-mix(in srgb, var(--accent-green) 15%, transparent); color: var(--accent-green); border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.sop-mobile-list__row-estado[data-estado="cerrado"]            { background: var(--bg-tertiary); color: var(--text-secondary); }
.sop-mobile-list__hist {
    display: flex; flex-direction: column; gap: 6px;
}
.sop-mobile-list__hist-entry {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 8px;
    padding: 8px 10px;
}
.sop-mobile-list__hist-entry[data-tipo="cambio_estado"] { border-left: 3px solid var(--accent-blue); }
.sop-mobile-list__hist-entry[data-tipo="solucion"]      { border-left: 3px solid var(--accent-green); }
.sop-mobile-list__hist-entry[data-tipo="asignacion"]    { border-left: 3px solid var(--accent-orange); }
.sop-mobile-list__alerta {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 10px;
    margin-bottom: 8px;
}
.sop-mobile-list__alerta[data-sev="critical"] { border-left: 4px solid var(--accent-red); }
.sop-mobile-list__alerta[data-sev="warning"]  { border-left: 4px solid var(--accent-orange); }
.sop-mobile-list__alerta[data-sev="info"]     { border-left: 4px solid var(--accent-blue); }

/* ── RRHH — ficha empleado con avatar + lista nóminas ── */
.rrhh-mobile-list__ficha {
    --mano-lateral: 12px;
    padding: 12px var(--mano-lateral);
}
.rrhh-mobile-list__hero {
    display: flex; align-items: center; gap: 12px;
    padding: 14px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 14px;
    margin-bottom: 12px;
}
.rrhh-mobile-list__avatar {
    width: 64px; height: 64px;
    border-radius: 9999px;
    overflow: hidden;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 26px; font-weight: 700;
}
.rrhh-mobile-list__avatar img {
    width: 100%; height: 100%; object-fit: cover;
}
.rrhh-mobile-list__nominas {
    display: flex; flex-direction: column; gap: 6px;
}
.rrhh-mobile-list__nomina {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
    padding: 10px 12px;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    color: var(--text-primary);
    font-family: inherit;
    width: 100%;
}
.rrhh-mobile-list__nomina:hover { background: var(--bg-tertiary); }
.rrhh-mobile-list__nomina:active { transform: scale(0.99); }

/* =====================================================
   Sesión C-Bajo (SPEC §6.13–6.17) — modifiers para los 5 módulos
   restantes: Configuración, Marketing, Patrimonio, Informes, Ayuda.
   Reusan el bloque base .dvergent-mobile-screen-* / .dvergent-mobile-dashboard-*.
   Solo se declaran los desvíos del patrón.
   ===================================================== */

/* Badge color helper — reusable por todos los módulos C-Bajo */
.dvergent-mobile-screen__badge[data-c="green"]  { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green);  border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.dvergent-mobile-screen__badge[data-c="red"]    { background: rgba(239,68,68,0.15);  color: var(--accent-red);    border-color: rgba(239,68,68,0.3); }
.dvergent-mobile-screen__badge[data-c="blue"]   { background: rgba(59,130,246,0.15); color: var(--accent-blue);   border-color: rgba(59,130,246,0.3); }
.dvergent-mobile-screen__badge[data-c="orange"] { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }

/* body:has — ocultar botón casa global cuando estos overlays están montados */
body:has(.cfg-mobile-list) .mobile-home-btn,
body:has(.cfg-mobile-dashboard) .mobile-home-btn,
body:has(.mkt-mobile-list) .mobile-home-btn,
body:has(.mkt-mobile-dashboard) .mobile-home-btn,
body:has(.pat-mobile-list) .mobile-home-btn,
body:has(.pat-mobile-dashboard) .mobile-home-btn,
body:has(.inf-mobile-list) .mobile-home-btn,
body:has(.inf-mobile-dashboard) .mobile-home-btn,
body:has(.ay-mobile-list) .mobile-home-btn,
body:has(.ay-mobile-dashboard) .mobile-home-btn { display: none !important; }

/* ── Configuración móvil — secciones colapsables (lista solo lectura) ── */
.cfg-mobile-list__sec {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    margin-bottom: 8px;
    overflow: hidden;
}
.cfg-mobile-list__sec.is-flash {
    box-shadow: 0 0 0 2px var(--accent-blue);
    transition: box-shadow 1s ease-out;
}
.cfg-mobile-list__sec-summary {
    list-style: none;
    display: flex; align-items: center; gap: 12px;
    padding: 12px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.cfg-mobile-list__sec-summary::-webkit-details-marker { display: none; }
.cfg-mobile-list__sec-ico {
    flex: 0 0 36px;
    width: 36px; height: 36px;
    border-radius: 10px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bg-tertiary);
    color: var(--accent-primary);
}
.cfg-mobile-list__sec-main {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column; gap: 2px;
}
.cfg-mobile-list__sec-title {
    font-size: 14px; font-weight: 600;
    color: var(--text-primary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cfg-mobile-list__sec-sub {
    font-size: 12px; color: var(--text-secondary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cfg-mobile-list__sec-chev {
    flex: 0 0 auto;
    color: var(--text-secondary);
    transition: transform 200ms ease-out;
}
.cfg-mobile-list__sec[open] > .cfg-mobile-list__sec-summary .cfg-mobile-list__sec-chev {
    transform: rotate(180deg);
}
.cfg-mobile-list__sec-body {
    padding: 0 12px 12px;
    border-top: 1px solid var(--border-primary);
}
.cfg-mobile-list__row {
    padding: 8px 0;
    border-bottom: 1px dashed var(--border-primary);
    font-size: 13px;
    color: var(--text-primary);
}
.cfg-mobile-list__row:last-child { border-bottom: none; }
.cfg-mobile-list__info {
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.5;
}
.cfg-mobile-list__chips-mod {
    display: flex; flex-wrap: wrap; gap: 6px;
    padding-top: 4px;
}
.cfg-mobile-list__chip-mod {
    display: inline-flex; align-items: center;
    padding: 4px 10px;
    border-radius: 9999px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 12px;
    border: 1px solid var(--border-primary);
}
/* Pantalla de bloqueo (rol no admin para Configuración / no holding_admin para Patrimonio) */
.cfg-mobile-list__blocked {
    flex: 1 1 auto;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 12px;
    padding: 32px 24px;
    text-align: center;
}
.cfg-mobile-list__blocked-ico {
    width: 64px; height: 64px;
    border-radius: 9999px;
    background: var(--bg-tertiary);
    color: var(--accent-red);
    display: inline-flex; align-items: center; justify-content: center;
}
.cfg-mobile-list__blocked h3 {
    margin: 0;
    color: var(--text-primary);
    font-size: 18px;
}
.cfg-mobile-list__blocked p {
    margin: 0;
    color: var(--text-secondary);
    font-size: 14px;
    max-width: 320px;
    line-height: 1.4;
}
.cfg-mobile-list__blocked-btn {
    margin-top: 8px;
    padding: 12px 22px;
    border-radius: 9999px;
    border: none;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
    min-height: 48px;
}
.cfg-mobile-list__blocked-btn:active { transform: scale(0.97); }

/* ── Marketing móvil — métricas inline + estado + botón acción ── */
.mkt-mobile-list__metrics {
    display: flex; flex-wrap: wrap; gap: 8px;
    margin-top: 6px;
}
.mkt-mobile-list__metric {
    display: inline-flex; align-items: center;
    padding: 3px 8px;
    border-radius: 6px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 11px;
}
.mkt-mobile-list__metric strong {
    color: var(--text-secondary);
    font-weight: 500;
    margin-right: 4px;
    text-transform: uppercase;
    font-size: 10px;
    letter-spacing: 0.3px;
}
.mkt-mobile-list__estado[data-estado="activa"]    { background: color-mix(in srgb, var(--accent-green) 15%, transparent);  color: var(--accent-green);  border-color: color-mix(in srgb, var(--accent-green) 30%, transparent); }
.mkt-mobile-list__estado[data-estado="pausada"]   { background: rgba(245,158,11,0.15); color: var(--accent-orange); border-color: rgba(245,158,11,0.3); }
.mkt-mobile-list__estado[data-estado="archivada"] { background: rgba(107,114,128,0.18); color: var(--text-secondary); border-color: rgba(107,114,128,0.4); }
.mkt-mobile-list__estado[data-estado="eliminada"] { background: rgba(239,68,68,0.15);  color: var(--accent-red);    border-color: rgba(239,68,68,0.3); }
.mkt-mobile-list__action-btn {
    display: inline-flex; align-items: center; gap: 6px;
    width: 100%;
    justify-content: center;
    padding: 12px 16px;
    border-radius: 12px;
    border: none;
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
    min-height: 48px;
}
.mkt-mobile-list__action-btn[data-color="orange"] { background: var(--accent-orange); }
.mkt-mobile-list__action-btn[data-color="green"]  { background: var(--accent-fill); color: var(--accent-fill-contrast); }
.mkt-mobile-list__action-btn:active { transform: scale(0.98); }

/* ── Patrimonio móvil — hero + posiciones + P&L coloreado + allocation ── */
.pat-mobile-list__sec {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 14px;
    margin-bottom: 10px;
}
.pat-mobile-list__sec-title {
    margin: 0 0 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.pat-mobile-list__hero {
    text-align: center;
    padding: 8px 0 4px;
}
.pat-mobile-list__hero-total {
    font-size: 32px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    margin-bottom: 8px;
}
.pat-mobile-list__hero-row {
    display: flex; justify-content: space-around;
    gap: 12px;
}
.pat-mobile-list__hero-cell {
    display: flex; flex-direction: column;
    align-items: center;
    gap: 2px;
}
.pat-mobile-list__hero-cell .label {
    font-size: 11px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.pat-mobile-list__hero-cell .value {
    font-size: 15px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.pat-mobile-list__pnl[data-pnl="pos"] { color: var(--accent-green); }
.pat-mobile-list__pnl[data-pnl="neg"] { color: var(--accent-red); }
.pat-mobile-list__pnl small { font-weight: 500; opacity: 0.85; }
.pat-mobile-list__row-val {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.pat-mobile-list__allocation {
    display: flex; flex-direction: column;
    gap: 6px;
}
.pat-mobile-list__alloc-row {
    display: flex; justify-content: space-between;
    font-size: 13px;
    color: var(--text-primary);
}
.pat-mobile-list__alloc-bar {
    height: 6px;
    background: var(--bg-tertiary);
    border-radius: 9999px;
    overflow: hidden;
    margin-bottom: 4px;
}
.pat-mobile-list__alloc-fill {
    display: block;
    height: 100%;
    border-radius: 9999px;
    background: var(--accent-blue);
    min-width: 2px;
    transition: width 300ms ease-out;
}
.pat-mobile-list__alloc-fill[data-tipo="ibkr"] { background: var(--accent-blue); }
.pat-mobile-list__alloc-fill[data-tipo="pv"]   { background: var(--accent-orange); }

/* ── Informes móvil — KPIs grid + sparklines + top productos ── */
.inf-mobile-list__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    padding-bottom: 8px;
}
.inf-mobile-list__kpi {
    display: flex; flex-direction: column;
    gap: 6px;
    padding: 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    text-align: left;
    color: var(--text-primary);
    font-family: inherit;
}
.inf-mobile-list__kpi:active { transform: scale(0.98); }
.inf-mobile-list__kpi-head {
    display: flex; align-items: center; gap: 8px;
}
.inf-mobile-list__kpi-ico {
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 8px;
    background: var(--bg-tertiary);
}
.inf-mobile-list__kpi-label {
    font-size: 12px;
    color: var(--text-secondary);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}
.inf-mobile-list__kpi-value {
    font-size: 22px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.inf-mobile-list__spark {
    display: block;
    width: 100%;
    height: 40px;
    margin-top: 2px;
}
.inf-mobile-list__top {
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 12px;
    padding: 12px;
    margin-top: 10px;
}
.inf-mobile-list__top-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.inf-mobile-list__top-row {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 0;
    border-bottom: 1px dashed var(--border-primary);
    font-size: 13px;
}
.inf-mobile-list__top-row:last-child { border-bottom: none; }
.inf-mobile-list__top-pos {
    width: 22px; height: 22px;
    border-radius: 9999px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px;
    font-weight: 600;
    flex: 0 0 auto;
}
.inf-mobile-list__top-name {
    flex: 1 1 auto;
    color: var(--text-primary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.inf-mobile-list__top-val {
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}
.inf-mobile-list__detail-value {
    font-size: 28px;
    font-weight: 700;
    color: var(--text-primary);
    text-align: center;
    padding: 12px 0 4px;
    font-variant-numeric: tabular-nums;
}

/* ── Ayuda móvil — pasos + vídeo + módulo header ── */
.ay-mobile-list__detail-modulo {
    font-size: 12px;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 10px;
}
.ay-mobile-list__pasos {
    display: flex; flex-direction: column;
    gap: 10px;
}
.ay-mobile-list__paso {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 8px 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-primary);
    border-radius: 10px;
}
.ay-mobile-list__paso-num {
    width: 24px; height: 24px;
    flex: 0 0 auto;
    border-radius: 9999px;
    background: var(--accent-fill);
    color: var(--accent-fill-contrast);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px;
    font-weight: 700;
}
.ay-mobile-list__paso-texto {
    flex: 1 1 auto;
    color: var(--text-primary);
    font-size: 14px;
    line-height: 1.45;
}
.ay-mobile-list__video-btn {
    display: inline-flex; align-items: center; gap: 6px;
    margin-top: 12px;
    padding: 10px 16px;
    border-radius: 10px;
    background: var(--accent-blue);
    color: var(--accent-contrast);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
}
.ay-mobile-list__video-btn:active { transform: scale(0.97); }

/* =====================================================
   DP-132 — Configuración del TPV responsive en handheld (Sunmi L3 ~720px)
   tpvRenderConfig (tpv.js) maqueta el formulario con grids inline
   `grid-template-columns:1fr 1fr` y `2fr 1fr`. En el viewport estrecho
   del L3 esas 2 columnas fuerzan scroll horizontal y cortan los inputs
   (IP/puerto de impresora, SMTP, etc.) → el operario no puede emparejar
   la impresora. Fix: colapsar todos los grids del form a 1 columna.
   No se toca el HTML; el `!important` vence al estilo inline.
   ===================================================== */
@media (max-width: 599px),
       (max-width: 820px) and (pointer: coarse) {
    #tpvConfigForm [style*="grid-template-columns"] {
        grid-template-columns: 1fr !important;
    }
    #tpvConfigForm input,
    #tpvConfigForm select {
        max-width: 100% !important;
        box-sizing: border-box;
    }
}

/* ============================================================================
   Pop-up de producto escaneado — TPV móvil (feature 2026-06-07)
   Tarjeta no-bloqueante top-center sobre la pantalla de venta del L3.
   pointer-events:none → nunca roba foco del input EAN ni taps del cajero.
   z-index 9980: sobre pantalla venta (999), bajo overlays Shopify (9985+).
   ============================================================================ */
/* Iteración 3 (2026-06-07, feedback Adri): disclaimer SOBRIO centrado — foto,
   nombre y precio, altura natural del contenido, sin marcos chillones. El ×N
   se mantiene (spec original: "si lo escaneas otra vez, ×2") pero discreto.
   Sigue pointer-events:none (no bloquea taps ni roba el foco del escáner) y
   se autocierra a los 2,6 s. */
.tpv-scan-popup {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 9980;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: min(84vw, 400px);
    padding: 24px 22px;
    background: #1e293b;
    color: #f8fafc;
    border-radius: 18px;
    box-shadow: 0 14px 48px rgba(0, 0, 0, .55);
    pointer-events: none;
    opacity: 0;
    text-align: center;
}
/* Fix iteración 3 (validado con Adri en L3): la animación de entrada y el
   autocierre van SEPARADOS. Antes un solo keyframe de 2,6 s terminaba en
   opacity:0 con forwards — al re-escanear el mismo producto se actualizaba el
   ×N pero la animación (no reiniciada) ya había dejado la tarjeta invisible →
   "el multiplicador se para en ×2". Ahora: entrada 0,22 s que TERMINA visible;
   el cierre lo gestiona JS (fade por transition + remove). */
.tpv-scan-popup {
    transition: opacity .25s ease;
}
.tpv-scan-popup--in {
    animation: tpvScanPopIn .22s ease-out forwards;
}
@keyframes tpvScanPopIn {
    from { opacity: 0; transform: translate(-50%, -50%) scale(.92); }
    to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.tpv-scan-popup__img {
    width: 96px;
    height: 96px;
    border-radius: 14px;
    object-fit: cover;
    flex-shrink: 0;
    background: #334155;
}
.tpv-scan-popup__img--ph {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #94a3b8;
}
.tpv-scan-popup__info { min-width: 0; width: 100%; }
.tpv-scan-popup__nombre {
    font-size: 18px;
    font-weight: 600;
    line-height: 1.25;
    display: -webkit-box;
    -webkit-line-clamp: 2;          /* máx 2 líneas, luego ellipsis */
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.tpv-scan-popup__precio {
    font-size: 27px;
    color: var(--accent-fill);      /* lima Volt: dato monetario positivo.
                                       El popup tiene superficie oscura fija (#1e293b)
                                       en los dos temas → relleno de marca, no --accent-primary. */
    font-weight: 800;
    margin-top: 4px;
}
.tpv-scan-popup__badge {
    flex-shrink: 0;
    background: #f59e0b;
    color: #1e293b;
    font-size: 21px;
    font-weight: 800;
    padding: 5px 16px;
    border-radius: 999px;
    white-space: nowrap;
    line-height: 1.15;
}
.tpv-scan-popup__badge--pulse {
    animation: tpvScanBadgePulse .35s ease-out;
}
@keyframes tpvScanBadgePulse {
    0%   { transform: scale(1.45); }
    100% { transform: scale(1); }
}

/* =====================================================
   Ventana media — tablets y plegables abiertos en el modo móvil (2026-10-10)

   Qué pantalla se monta lo sigue decidiendo _isMobileViewport() (app.js) con
   sus cinco criterios. Las reglas combinadas de arriba (la activación, las
   defensas «min-width: 821px» y DP-132) no se tocan: cambiarlas es la fase 1
   de plegables y antes hay que medir los terminales. Este bloque solo cambia
   la geometría de las pantallas de mano YA montadas cuando la ventana mide
   600 px o más: tablet en vertical (768, 820), iPhone Duo abierto (626, 669),
   TriFold (792) o un teléfono Android en horizontal que siga en modo móvil.
   Es el tramo «media» de la SPEC Liquid § 2.8; Vanilla no escribe
   data-ventana, así que aquí es una media query.

   · La guarda min-device-aspect-ratio 3/5 deja fuera toda PANTALLA con forma
     de teléfono en vertical (Sunmi L3 y teléfonos, de 0,45 a 0,56) aunque su
     WebView diga que mide 600 px o más y aunque el teclado encoja la ventana:
     el Sunmi se queda siempre en su maqueta compacta. Tablets y plegables
     abiertos, de 0,62 a 0,75. No es el criterio de React, que fuerza
     «compacta» con modo móvil + pantalla ≤ 720 + Android (ViewportProvider):
     CSS no ve el agente de usuario. Con el mismo aparato divergen una tablet
     Android de 600-720 px en vertical y un teléfono Android en horizontal con
     pantalla ≤ 720 (React compacta, aquí media), y una tablet 16:9 de más de
     720 px en vertical (forma 0,5625: React media, aquí compacta). iOS informa
     de la pantalla en vertical aunque se gire: el iPhone en horizontal nunca
     entra aquí. device-aspect-ratio ya no está en Media Queries 4, pero
     Chromium y WebKit la siguen aplicando. Alinear los dos criterios es la
     fase 1, con FLEX3, NYX y L3 medidos.
   · Barras y franjas siguen de borde a borde (fondo, separador y barra de
     scroll en el borde de la pantalla). Su contenido y el de las listas se
     recoge en una columna centrada de --mano-columna-max: cada franja declara
     en su regla base su separación lateral de siempre (--mano-lateral) y aquí
     se le suma --mano-borde-izq / --mano-borde-der. Por debajo de 720 px la
     columna es la ventana entera y solo cambian las rejillas.
   · --mano-borde-izq y --mano-borde-der nunca bajan de la zona segura
     (env safe-area-inset): en horizontal nada se mete bajo el notch o la
     cámara. Donde el contenedor ya se aparta de ella (.dvergent-mobile-screen
     y .dvergent-mobile-dashboard) se suma solo --mano-resto-izq / -der. Lo
     que arranca arriba del todo sin contenedor que se aparte (la hoja del
     slide-down, la pantalla de consumo) baja la zona segura superior.
   · Rejillas: accesos de los Dashboards y botones de producto, 4 columnas;
     tarjetas con texto (selector de etiquetado QR, KPI de Informes), 3; el
     Launcher, 4 celdas fijas centradas.
   · Las hojas (acciones del slide-down, confirmación de consumo) se centran
     con --mano-hoja-max de ancho.
   Columna (720) y hoja (640) son los valores del tramo «media» de
   --liquid-content-max y --liquid-hoja-max en theme.css, que Vanilla no ve
   (cuelgan de [data-ui="liquid"]): si cambian allí, hay que cambiarlos aquí.
   ===================================================== */
@media (min-width: 600px) and (min-device-aspect-ratio: 3/5) {
    :root {
        --mano-columna-max: 720px;
        --mano-hoja-max: 640px;
        --mano-columnas-botones: 4;
        --mano-columnas-tarjetas: 3;
        --mano-borde-izq: max(env(safe-area-inset-left, 0px), (100vw - var(--mano-columna-max)) / 2);
        --mano-borde-der: max(env(safe-area-inset-right, 0px), (100vw - var(--mano-columna-max)) / 2);
        --mano-resto-izq: calc(var(--mano-borde-izq) - env(safe-area-inset-left, 0px));
        --mano-resto-der: calc(var(--mano-borde-der) - env(safe-area-inset-right, 0px));
        /* Launcher: 4 de sus celdas fijas, centradas. La cabecera se alinea con
           ellas: la marca empieza donde el primer icono y el avatar acaba donde
           el último (la sangría es lo que la celda le sobra al icono). */
        --mano-launcher-columnas: 4;
        --mano-launcher-ancho: calc(var(--mano-launcher-columnas) * var(--mano-launcher-celda)
                                    + (var(--mano-launcher-columnas) - 1) * var(--mano-launcher-hueco));
        --mano-launcher-sangria: calc((var(--mano-launcher-celda) - var(--mano-launcher-icono)) / 2);
        --mano-launcher-borde-izq: max(env(safe-area-inset-left, 0px) + var(--mano-launcher-lateral),
                                       (100vw - var(--mano-launcher-ancho)) / 2 + var(--mano-launcher-sangria));
        --mano-launcher-borde-der: max(env(safe-area-inset-right, 0px) + var(--mano-launcher-lateral),
                                       (100vw - var(--mano-launcher-ancho)) / 2 + var(--mano-launcher-sangria));
    }

    /* ── Launcher ── */
    /* La cabecera sigue la columna de 4 celdas con cualquier número de módulos,
       para no saltar al pasar de 3 a 4. Con 1-3 la rejilla es la de siempre
       (celdas de 88 px centradas) y, como en el teléfono, no se alinea con la
       marca. */
    .mobile-launcher__header {
        padding-left: var(--mano-launcher-borde-izq);
        padding-right: var(--mano-launcher-borde-der);
    }
    .mobile-launcher__menu {
        right: calc(var(--mano-launcher-borde-der) - var(--mano-launcher-menu-saliente));
    }
    .mobile-launcher__grid[data-count="many"] {
        grid-template-columns: repeat(var(--mano-launcher-columnas), var(--mano-launcher-celda));
        column-gap: var(--mano-launcher-hueco);
        justify-content: center;
    }
    /* La etiqueta usa la celda entera menos el relleno del botón. */
    .mobile-launcher__grid[data-count="many"] .mobile-launcher__label {
        max-width: calc(var(--mano-launcher-celda) - 2 * var(--mano-launcher-modulo-relleno));
    }

    /* ── Slide-down de acciones: hoja centrada y bajo la barra de estado ──
       Instalada como app (viewport-fit=cover, barra translúcida), la hoja
       empezaba bajo la hora: el margen suma la zona segura a su top de siempre. */
    .mobile-slidedown__panel {
        left: max(var(--mano-lateral), (100% - var(--mano-hoja-max)) / 2);
        right: max(var(--mano-lateral), (100% - var(--mano-hoja-max)) / 2);
        margin-top: env(safe-area-inset-top, 0px);
    }

    /* ── Rejillas ── */
    .tpv-mobile-dashboard__grid,
    .almacen-mobile-dashboard__grid,
    .factura-mobile-dashboard__grid,
    .fab-mobile-dashboard__grid,
    .dvergent-mobile-dashboard__grid,
    .tpv-mobile-venta__product-grid,
    .almacen-mobile-stock__product-grid {
        grid-template-columns: repeat(var(--mano-columnas-botones), minmax(0, 1fr));
    }
    .dvergent-mobile-qr-selector,
    .inf-mobile-list__grid {
        grid-template-columns: repeat(var(--mano-columnas-tarjetas), minmax(0, 1fr));
    }

    /* ── Franjas de borde a borde, contenido en la columna ──
       Toda franja de esta lista declara --mano-lateral en su regla base: si no,
       heredaría el de la franja que la contiene. */
    .tpv-mobile-dashboard__topbar,
    .tpv-mobile-dashboard__mode,
    .tpv-mobile-dashboard__resumen,
    .tpv-mobile-dashboard__cajeros,
    .tpv-mobile-dashboard__accesses,
    .tpv-mobile-dashboard__hint,
    .tpv-mobile-buscar__topbar,
    .tpv-mobile-buscar__searchbar,
    .tpv-mobile-buscar__list,
    .tpv-mobile-caja__topbar,
    .tpv-mobile-caja__section,
    .tpv-mobile-caja__loading,
    .tpv-mobile-caja__error,
    .tpv-mobile-hist__topbar,
    .tpv-mobile-hist__toolbar,
    .tpv-mobile-hist__scroll,
    .tpv-mobile-hist__footer,
    .tpv-mobile-hist-pdf__topbar,
    .tpv-mobile-etiq__topbar,
    .tpv-mobile-etiq__body,
    .tpv-mobile-config__topbar,
    .tpv-mobile-config__body,
    .tpv-mobile-venta__client-strip,
    .tpv-mobile-venta__ean-row,
    .tpv-mobile-venta__catalog,
    .tpv-mobile-venta__lines,
    .tpv-mobile-venta__summary,
    .tpv-mobile-venta__pay-row,
    .tpv-mobile-edit-overlay,
    .almacen-mobile-dashboard__topbar,
    .almacen-mobile-dashboard__accesses,
    .almacen-mobile-stock__topbar,
    .almacen-mobile-stock__ean-row,
    .almacen-mobile-stock__catalog,
    .almacen-mobile-stock__footer,
    .factura-mobile-dashboard__topbar,
    .factura-mobile-dashboard__accesses,
    .factura-mobile-list__topbar,
    .fab-mobile-dashboard__topbar,
    .fab-mobile-dashboard__accesses,
    .fab-mobile-list__topbar,
    .dvergent-mobile-qr-screen__topbar,
    .dvergent-mobile-qr-screen__body,
    .dvergent-mobile-qr-screen__footer,
    .dvergent-mobile-qr-selector,
    /* Facturación y Fabricación: solo los hijos de su cuerpo de lista. En
       Mermas y Nueva orden las mismas filas y chips van dentro de
       .fab-mobile-traza__body, que ya recoge la columna. */
    .factura-mobile-list__body > .factura-mobile-list__search-row,
    .factura-mobile-list__body > .factura-mobile-list__chips,
    .factura-mobile-list__body > .factura-mobile-list__rows,
    .factura-mobile-list__body > .factura-mobile-list__footer,
    .fab-mobile-list__body > .fab-mobile-list__search-row,
    .fab-mobile-list__body > .fab-mobile-list__chips,
    .fab-mobile-list__body > .fab-mobile-list__rows,
    .fab-mobile-list__body > .fab-mobile-list__footer {
        padding-left: calc(var(--mano-lateral) + var(--mano-borde-izq));
        padding-right: calc(var(--mano-lateral) + var(--mano-borde-der));
    }
    /* Su separación lateral es 0: la columna entera la ponen sus hijos. */
    .fab-mobile-traza__body {
        padding-left: var(--mano-borde-izq);
        padding-right: var(--mano-borde-der);
    }
    /* «Histórico de cierres» va suelto en la raíz de Caja, separado por margen. */
    .tpv-mobile-caja__action-secondary {
        width: auto;
        margin-left: calc(var(--mano-lateral) + var(--mano-borde-izq));
        margin-right: calc(var(--mano-lateral) + var(--mano-borde-der));
    }

    /* Bloque base (.dvergent-mobile-screen / .dvergent-mobile-dashboard): el
       contenedor ya se aparta de la zona segura, así que se suma el resto.
       Buscador, chips, lista y pie cuelgan del cuerpo directamente o dentro de
       un envoltorio sin clase que el módulo repinta (los <div id="…Wrap"> de
       clientes.js y proveedores.js, #ayMobileChipsRow de ayuda.js). */
    .dvergent-mobile-screen__topbar,
    .dvergent-mobile-dashboard__topbar,
    .dvergent-mobile-dashboard__accesses,
    .dvergent-mobile-screen__body > .dvergent-mobile-screen__search-row,
    .dvergent-mobile-screen__body > .dvergent-mobile-screen__chips,
    .dvergent-mobile-screen__body > .dvergent-mobile-screen__list,
    .dvergent-mobile-screen__body > .dvergent-mobile-screen__footer,
    .dvergent-mobile-screen__body > div:not([class]) > .dvergent-mobile-screen__search-row,
    .dvergent-mobile-screen__body > div:not([class]) > .dvergent-mobile-screen__chips,
    .dvergent-mobile-screen__body > div:not([class]) > .dvergent-mobile-screen__list,
    .dvergent-mobile-screen__body > div:not([class]) > .dvergent-mobile-screen__footer,
    .dvergent-mobile-screen__body > .rrhh-mobile-list__ficha,
    .dvergent-mobile-screen__body > .ch-mobile-fichaje__hero {
        padding-left: calc(var(--mano-lateral) + var(--mano-resto-izq));
        padding-right: calc(var(--mano-lateral) + var(--mano-resto-der));
    }

    /* Pantallas del TPV pintadas con estilo en línea desde tpv.js. Dependen de
       su marcado y repiten sus rellenos en línea (el `!important` los vence,
       como en DP-132); si ese marcado cambia, dejan de casar sin aviso: lo
       bueno es pasarlas a clases en tpv.js.
       · Shopify (tpvShopifyMobile*Root): el cuerpo hace scroll él mismo y se
         recoge entero; el de la lista de pedidos trae padding:12px. */
    #tpvShopifyMobilePedidoRoot > .dvergent-mobile-screen__body,
    #tpvShopifyMobileLiqRoot > .dvergent-mobile-screen__body,
    #tpvShopifyMobilePayoutRoot > .dvergent-mobile-screen__body,
    #tpvShopifyMobileMapRoot > .dvergent-mobile-screen__body {
        padding-left: var(--mano-resto-izq);
        padding-right: var(--mano-resto-der);
    }
    #tpvShopifyMobileListaRoot > .dvergent-mobile-screen__body {
        padding-left: calc(12px + var(--mano-resto-izq)) !important;
        padding-right: calc(12px + var(--mano-resto-der)) !important;
    }
    /* · Consumo personal (_tpvMobileConsumoRender): cabecera, buscador, aviso
         <p> y lista, en ese orden; aviso de modo en la venta
         (_tpvMobileConsumoBannerInner). La raíz se aparta de la zona segura
         como .dvergent-mobile-screen. */
    #tpvMobileConsumoRoot {
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    #tpvMobileConsumoBanner > div,
    #tpvMobileConsumoRoot > div:first-child,
    #tpvMobileConsumoRoot > div:nth-child(2) {
        padding-left: calc(12px + var(--mano-borde-izq)) !important;
        padding-right: calc(12px + var(--mano-borde-der)) !important;
    }
    #tpvMobileConsumoRoot > p {
        padding-left: calc(16px + var(--mano-borde-izq)) !important;
        padding-right: calc(16px + var(--mano-borde-der)) !important;
    }
    #tpvMobileConsumoRoot > div:last-child {
        padding-left: var(--mano-borde-izq);
        padding-right: var(--mano-borde-der);
    }
    #tpvMobileConsumoConfirm > div {
        max-width: var(--mano-hoja-max);
        margin-left: auto;
        margin-right: auto;
    }
    /* · Peso de la balanza (#tpvMobileVentaPeso): margin:4px 8px. */
    .tpv-mobile-venta__peso {
        margin-left: calc(8px + var(--mano-borde-izq)) !important;
        margin-right: calc(8px + var(--mano-borde-der)) !important;
    }
}
