/* =========================================
     TIPOGRAFÍA (Hanken Grotesk + Geist, autohospedadas desde Google Fonts
     para no depender de un dominio externo bajo el CSP estricto del sitio —
     mismo patrón que Satoshi antes. Reemplaza a Satoshi por completo como
     parte del rediseño calcado del mockup de Stitch, ver AUDITORIA/CHANGELOG.
     Geist se usa solo para textos "label" chicos/técnicos, calcando el
     mismo uso que tenía en el design system de Stitch.)
     ========================================= */
  @font-face {
    font-family: "Hanken Grotesk";
    src: url("files/fonts/HankenGrotesk-400.woff2") format("woff2");
    font-weight: 400; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Hanken Grotesk";
    src: url("files/fonts/HankenGrotesk-500.woff2") format("woff2");
    font-weight: 500; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Hanken Grotesk";
    src: url("files/fonts/HankenGrotesk-600.woff2") format("woff2");
    font-weight: 600; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Hanken Grotesk";
    src: url("files/fonts/HankenGrotesk-700.woff2") format("woff2");
    font-weight: 700; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Geist";
    src: url("files/fonts/Geist-400.woff2") format("woff2");
    font-weight: 400; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Geist";
    src: url("files/fonts/Geist-500.woff2") format("woff2");
    font-weight: 500; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Geist";
    src: url("files/fonts/Geist-600.woff2") format("woff2");
    font-weight: 600; font-display: swap; font-style: normal;
  }
  @font-face {
    font-family: "Geist";
    src: url("files/fonts/Geist-700.woff2") format("woff2");
    font-weight: 700; font-display: swap; font-style: normal;
  }

  /* Íconos: Material Symbols (variable font) reemplazando a Lucide, igual
     que en el mockup de Stitch. Autohospedado por el mismo motivo que las
     fuentes de texto (CSP: font-src 'self'). Es un solo archivo de ~4MB
     (cubre miles de glifos) pero se cachea una sola vez en el navegador. */
  @font-face {
    font-family: "Material Symbols Outlined";
    src: url("files/fonts/MaterialSymbolsOutlined.woff2") format("woff2");
    font-weight: 100 700; font-display: block; font-style: normal;
  }
  .material-symbols-outlined {
    font-family: "Material Symbols Outlined";
    font-weight: normal; font-style: normal;
    font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none;
    display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr;
    -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased;
    font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    vertical-align: middle;
  }

/* =========================================
     VARIABLES GLOBALES (Colores y Radios)
     ========================================= */
  :root {
    /* Paleta calcada de TailAdmin (tailwind.config.js: primary/boxdark/bodydark/meta-*),
       manteniendo los mismos nombres de variable de Loyka para que todo el
       resto de este archivo se retematice solo con este bloque.
       --loyka-terracota quedó con el azul "primary" de TailAdmin de fábrica
       y nunca se cambió por el terracota real de la marca (el naranja quemado
       del logo, #B3461B — ver public/files/logo-header.png). Se ajusta acá a
       un tono derivado de ese mismo color pero un poco más claro/saturado
       para que sirva de texto/ícono legible sobre el fondo oscuro (el del
       logo, muy fiel al original, no pasa el contraste mínimo como texto). */
    /* 2026-07-28: paleta reemplazada por la del design system "Loyka
       Enterprise System" generado en Stitch (mismos nombres de variable de
       siempre, para no tener que tocar el resto del archivo). Los acentos
       (terracota/ocre/oliva) son los tonos "container" (vivid) del mockup;
       bg/card-bg/text son sus tokens surface/on-surface. --loyka-text-muted
       y --loyka-border NO son el on-surface-variant/outline literal de
       Stitch (esos salieron con un tinte cálido/naranja que no combinaba
       con el resto, que es frío) — se derivaron a mano en la misma familia
       fría de --loyka-text para que no desentonen. --loyka-danger y
       --loyka-warning se dejaron sin tocar a propósito: Stitch no define un
       equivalente vívido utilizable como fondo de botón/alerta sin perder
       legibilidad (su "error" es una pareja texto-claro/fondo-oscuro tipo
       Material, y este archivo usa una sola variable para ambos usos). */
    --loyka-terracota: #FF6B2C;  /* primary-container de Stitch */
    --loyka-ocre: #3192FC;       /* secondary-container de Stitch */
    --loyka-oliva: #00B065;      /* tertiary-container de Stitch */
    --loyka-danger: #DC3545;     /* sin cambios — ver nota arriba */
    --loyka-warning: #FFBA00;    /* sin cambios — ver nota arriba */
    --loyka-bg: #0B1326;         /* surface/background de Stitch */
    --loyka-card-bg: #171F33;    /* surface-container de Stitch */
    --loyka-container-bg: var(--loyka-bg); /* fondo de .box (contenedor grande) — separado de --loyka-card-bg para que las tarjetas de adentro siempre contrasten con su contenedor */
    --loyka-text: #DAE2FD;       /* on-surface de Stitch */
    --loyka-text-muted: #8D97BD; /* derivado, ver nota arriba */
    --loyka-border: #262F4D;     /* derivado, ver nota arriba */
    --loyka-red-glow: rgba(0, 176, 101, 0.18);
    --loyka-orange: var(--accent);
    --accent: var(--loyka-oliva);

    /* Radios estructurales — más chicos, como en la referencia */
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
  }

  /* =========================================
     CONFIGURACIÓN BASE APP NATIVA
     ========================================= */
  * { 
    -webkit-tap-highlight-color: transparent; 
    -webkit-touch-callout: none;
    cursor: default; 
  }

  input, textarea { 
    caret-color: auto !important; 
    cursor: text !important;
  }

  button, .button, a, .loyka-card, .tabs li a, .panel-handler, label, .sidebar-link {
    cursor: pointer !important;
    -webkit-user-select: none !important; 
    user-select: none !important;
  }

  select, .select, .select select {
    pointer-events: auto !important;
    user-select: auto !important;
    -webkit-user-select: auto !important;
  }

  *:focus, *:active { outline: none !important; }
  .button:focus, .button:active, .input:focus, .select select:focus, .textarea:focus {
    box-shadow: none !important;
  }
  .loyka-card:focus, .loyka-card:active { outline: none !important; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); }

  body {
    background-color: var(--loyka-bg);
    color: var(--loyka-text);
    padding-bottom: 20px;
    font-family: 'Hanken Grotesk', sans-serif;
    position: relative;
  }

  /* Geist para textos "label": mayúsculas chicas/técnicas (encabezados de
     tabla, etiquetas de KPI, pills de estado) — mismo rol que tenía en el
     design system de Stitch (label-sm/label-md usaban Geist, el resto Hanken
     Grotesk). */
  .table thead th, .panel-hero-label, .panel-mini-label, .loyka-stat-label,
  .panel-nota, .section-title, .panel-pill {
    font-family: 'Geist', sans-serif;
  }

  body::before {
    content: ""; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
    pointer-events: none; z-index: -2; 
    background-image: url('https://lh3.googleusercontent.com/d/1XVrlMvrtz2TF5pbkASFlOCv9o6jq9tpm');
    background-repeat: no-repeat; background-position: center center;
    background-size: 50%; opacity: 0.03; 
  }

  body::after {
    content: ""; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
    pointer-events: none; z-index: -1; 
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.04'/%3E%3C/svg%3E");
    background-color: rgba(0, 176, 101, 0.02);
  }

  /* =========================================
     SECCIONES Y PANELES
     ========================================= */
  .section-app { 
    display: none; 
    animation: fadeIn 0.3s ease; 
  }
  .section-app.is-active { display: block; }
  @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

  #pantalla-login {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: var(--loyka-bg); z-index: 9999; 
    display: flex; flex-direction: column; justify-content: center; align-items: center;
    padding: 20px; transition: opacity 0.5s ease;
  }

  .panel-sheet {
    position: fixed; bottom: -100%; left: 0; width: 100%; 
    background: white; border-radius: 30px 30px 0 0; 
    z-index: 2000; transition: bottom 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    max-height: 90vh; overflow-y: auto;
  }
  .panel-sheet.is-active { bottom: 0; }
  .panel-handler { width: 40px; height: 4px; background: #ddd; border-radius: 10px; margin: 15px auto; }
  .panel-overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(0,0,0,0.4); display: none; z-index: 1999;
  }
  .panel-overlay.is-active { display: block; }
  .modal { z-index: 3000; } 

  /* =========================================
     EASTER EGGS
     ========================================= */
  .spin-picante { animation: spinFire 0.8s ease-in-out; filter: drop-shadow(0 0 10px #d9411e) saturate(150%); }
  @keyframes spinFire { 0% { transform: rotate(0deg) scale(1); } 50% { transform: rotate(180deg) scale(1.2); } 100% { transform: rotate(360deg) scale(1); } }
  .aji-volador { position: fixed; font-size: 5rem; z-index: 9999; pointer-events: none; animation: volar 1.5s cubic-bezier(0.25, 1, 0.5, 1) forwards; }
  @keyframes volar { 0% { transform: translate(-10vw, 110vh) rotate(-45deg); opacity: 1; } 100% { transform: translate(110vw, -10vh) rotate(360deg); opacity: 0; } }

  /* =========================================
     SCROLLBARS Y UI POLISH
     ========================================= */
  ::-webkit-scrollbar { width: 6px; height: 6px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: var(--loyka-border); border-radius: 10px; }
  ::-webkit-scrollbar-thumb:hover { background: var(--loyka-text-muted); }

  input[type=number]::-webkit-inner-spin-button,
  input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
  input[type=number] { -moz-appearance: textfield; appearance: textfield; }

  /* ==========================================
     TEMA OSCURO BASE Y ELEMENTOS BULMA
     ========================================== */
  html, html.dark-mode { background-color: var(--loyka-bg) !important; color-scheme: dark; } 
  
  .dark-mode {
    body, #pantalla-login { background-color: var(--loyka-bg) !important; color: var(--loyka-text) !important; }
    
    .panel-sheet, .modal-card-body, .modal-card-head, .modal-card-foot, .modal-card,
    .box, .card-gasto, .stat-card, .has-background-light, .has-background-white {
      background-color: var(--loyka-card-bg) !important; 
      border-color: var(--loyka-border) !important;
      color: var(--loyka-text) !important;
    }

    .box, .card-gasto, .stat-card {
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2) !important; 
      border-radius: var(--radius-md) !important;
    }

    .title, .label, strong, .has-text-dark, .has-text-black, .has-text-grey-dark, .insumo-name { color: #FFFFFF !important; }
    .help, .has-text-grey, .has-text-grey-light { color: var(--loyka-text-muted) !important; }
    .section-title { color: var(--accent) !important; }

    .input, .select select, .textarea {
      background-color: #181818 !important; border-color: var(--loyka-border) !important; 
      color: var(--loyka-text) !important; border-radius: var(--radius-sm) !important; box-shadow: none !important; transition: all 0.2s ease;
    }
    .input::placeholder, .textarea::placeholder { color: #666666 !important; }
    select option { background-color: #181818; color: var(--loyka-text); }
    
    .input:focus, .select select:focus, .textarea:focus,
    .input:active, .select select:active, .textarea:active {
      border-color: var(--loyka-orange) !important;
      box-shadow: inset 0 1px 2px rgba(0,0,0,0.1), 0 0 0 1px var(--loyka-orange), 0 0 15px var(--loyka-red-glow) !important;
    }

    .table, .table th, .table td { background-color: transparent !important; border-color: var(--loyka-border) !important; color: var(--loyka-text) !important; box-shadow: none !important; }
    .table thead th, .table thead tr { background-color: var(--loyka-card-bg) !important; color: var(--loyka-text-muted) !important; }
    .table.is-striped tbody tr:nth-child(even) { background-color: #181818 !important; }
    .table.is-hoverable tbody tr:hover { background-color: #242424 !important; }

    /* Tablas más espaciosas y con encabezado más discreto (todas las tablas
       de la app usan la misma clase .table de Bulma, así que este único
       cambio se ve reflejado en toda la app). */
    .table:not(.is-narrow) td, .table:not(.is-narrow) th { padding: 0.85em 1em !important; }
    .table thead th { font-size: 0.68rem !important; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700 !important; border-bottom-width: 2px !important; }
    .table.is-narrow td, .table.is-narrow th { padding: 0.55em 0.75em !important; }

    .has-text-primary, .has-text-info, .has-text-link, .has-text-info-dark, .has-text-link-dark { color: var(--loyka-ocre) !important; }
    .has-text-success, .has-text-success-dark { color: var(--loyka-oliva) !important; }
    .has-text-danger, .has-text-danger-dark { color: var(--loyka-danger) !important; }
    .has-text-warning, .has-text-warning-dark { color: var(--loyka-warning) !important; }

    .has-background-primary, .has-background-info, .has-background-link, .tag.is-primary, .tag.is-info, .tag.is-link, .button.is-primary, .button.is-info, .button.is-link { background-color: var(--loyka-ocre) !important; color: #fff !important; border-color: transparent !important; }
    .has-background-success, .tag.is-success, .button.is-success { background-color: var(--loyka-oliva) !important; color: #fff !important; border-color: transparent !important; }
    .has-background-danger, .tag.is-danger, .button.is-danger { background-color: var(--loyka-danger) !important; color: #fff !important; border-color: transparent !important; }
    .has-background-warning, .tag.is-warning, .button.is-warning { background-color: var(--loyka-warning) !important; color: #1C2434 !important; border-color: transparent !important; }

    .has-background-primary-light, .has-background-info-light, .has-background-link-light, .notification.is-info.is-light { background-color: rgba(37, 154, 230, 0.12) !important; border-color: transparent !important; }
    .has-background-success-light, .notification.is-success.is-light { background-color: rgba(16, 185, 129, 0.12) !important; border-color: transparent !important; }
    .has-background-danger-light, .notification.is-danger.is-light { background-color: rgba(220, 53, 69, 0.12) !important; border-color: transparent !important; }
    .has-background-warning-light, .notification.is-warning.is-light { background-color: rgba(255, 186, 0, 0.15) !important; border-color: transparent !important; }

    .button.is-light, .tag.is-light, .notification.is-light { background-color: #2A2A2A !important; color: var(--loyka-text) !important; border-color: var(--loyka-border) !important; }
    .button.is-info.is-light, .button.is-primary.is-light, .button.is-link.is-light, .tag.is-info.is-light, .tag.is-primary.is-light { background-color: rgba(37, 154, 230, 0.15) !important; color: var(--loyka-ocre) !important; border-color: transparent !important; }
    .button.is-success.is-light, .tag.is-success.is-light { background-color: rgba(16, 185, 129, 0.15) !important; color: var(--loyka-oliva) !important; border-color: transparent !important; }
    .button.is-danger.is-light, .tag.is-danger.is-light { background-color: rgba(220, 53, 69, 0.15) !important; color: var(--loyka-danger) !important; border-color: transparent !important; }
    .button.is-warning.is-light, .tag.is-warning.is-light { background-color: rgba(255, 186, 0, 0.18) !important; color: var(--loyka-warning) !important; border-color: transparent !important; }

    .button.is-info.is-light:hover, .button.is-primary.is-light:hover { background-color: var(--loyka-ocre) !important; color: #fff !important; }
    .button.is-success.is-light:hover { background-color: var(--loyka-oliva) !important; color: #fff !important; }
    .button.is-danger.is-light:hover { background-color: var(--loyka-danger) !important; color: #fff !important; }
    .button.is-warning.is-light:hover { background-color: var(--loyka-warning) !important; color: #1C2434 !important; }
    .button.is-outlined { background-color: transparent !important; color: var(--loyka-text) !important; border-color: var(--loyka-border) !important; }
    .button.is-outlined:hover { background-color: #2A2A2A !important; color: #fff !important; }

    .tabs.is-toggle.is-fullwidth a { background-color: #181818 !important; border-color: var(--loyka-border) !important; color: var(--loyka-text-muted) !important; border-radius: var(--radius-sm); }
    .tabs.is-toggle.is-fullwidth li.is-active a { background-color: var(--loyka-orange) !important; border-color: var(--loyka-orange) !important; color: #fff !important; }
    [style*="border: 1px"], [style*="border-top: 1px"] { border-color: var(--loyka-border) !important; }
    [style*="color: #"] { color: var(--loyka-text) !important; }

    .drag-handle { background-color: transparent !important; border-color: transparent !important; }
    .drag-handle:hover { background-color: rgba(255,255,255,0.1) !important; }
    .sortable-ghost { background-color: rgba(255,255,255,0.05); }
    .autocomplete-dropdown { background-color: #1f2937; border-color: #374151; box-shadow: 0 8px 20px rgba(0,0,0,0.4); }
    .autocomplete-item { border-bottom: 1px solid #374151; color: #f3f4f6; }
    .autocomplete-item:hover { background-color: #374151; color: #fff; }
    .skeleton-line { background-color: #2d2d2d; }
  }
  
  /* ==========================================
     LAYOUT Y COMPONENTES
     ========================================== */
  .loyka-app-layout {
    display: flex;
    align-items: stretch;
    min-height: 100vh;
  }
  .loyka-sidebar {
    width: 260px; flex-shrink: 0; display: none; flex-direction: column;
    /* position:fixed (no sticky): el sidebar nunca se mueve ni participa en
       el alto de .loyka-app-layout. Con sticky, aunque el contenido del menú
       (los links + el pie de usuario) es corto, la caja igual reservaba un
       viewport completo (height:100vh) para poder "pegarse" — eso hacía que
       una página con poco contenido quedara estirada a 100vh de más, y que
       al llegar al final del scroll el sidebar se despegara y se corriera
       junto con la página. Con fixed, el contenido principal simplemente le
       deja el espacio con margin-left (ver .loyka-main-content) y el sidebar
       queda quieto siempre. */
    position: fixed; top: 0; left: 0; height: 100vh;
    /* position:fixed crea su propio contexto de apilamiento aunque z-index
       quede en "auto" — sin ponerle uno explícito acá, ese contexto completo
       (con todo lo de adentro, incluido el panel de notificaciones) se
       compara con el resto de la página solo por orden en el HTML, y pierde
       contra cualquier elemento posicionado de #page-content (ej. el .select
       de Bulma) por venir antes en el documento. Con z-index explícito acá,
       ya no importa el orden: gana por valor. */
    z-index: 10;
    padding: 20px 14px; border-right: 1px solid var(--loyka-border);
  }
  /* #main-nav es hijo directo del sidebar (que es flex column): crece para
     empujar .loyka-sidebar-bottom (saludo/logout/widget) hasta el fondo, y es
     el único que scrollea (no el sidebar completo) para que overflow-y:auto
     no le recorte en x al panel de notificaciones, que necesita "escaparse"
     del ancho del sidebar (ver .loyka-notif-panel). min-height:0 es necesario
     para que un hijo flex-grow pueda encogerse y scrollear en vez de estirar
     el contenedor. */
  /* overscroll-behavior: contain evita que, al llegar al límite del scroll
     del menú, el gesto siga encadenándose hacia la página de atrás (y
     viceversa) — se nota sobre todo con touch en el celular. */
  #main-nav { flex-grow: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  #main-nav::-webkit-scrollbar { width: 4px; }
  #main-nav::-webkit-scrollbar-thumb { background: #374151; border-radius: 10px; }

  .loyka-main-content {
    flex-grow: 1;
    min-width: 0;
    padding: 24px;
  }

  /* Fundido corto al cambiar de sección (navegación SPA en auth.js) */
  #page-content { transition: opacity 0.15s ease; }
  #page-content.is-loading { opacity: 0; }

  .sidebar-section-label {
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.8px; font-weight: 700;
    color: var(--loyka-text-muted); opacity: 0.7; padding: 0 16px; margin-bottom: 10px;
  }
  .sidebar-link { display: flex; align-items: center; gap: 12px; padding: 10px 16px; border-radius: 8px; color: var(--loyka-text-muted); font-weight: 600; transition: all 0.2s ease; background: transparent; border: 1px solid transparent; margin-bottom: 2px; }
  .sidebar-link:hover, .sidebar-link.is-active-nav { background: var(--loyka-card-bg); color: var(--loyka-text); border-color: var(--loyka-border); }
  .sidebar-link .material-symbols-outlined { font-size: 20px; }
  .sidebar-link.is-active-nav .material-symbols-outlined { color: var(--accent); }

  /* Logo integrado arriba del sidebar: mismo ancho que el panel, en vez de
     vivir en una barra superior aparte (así se ven como un solo bloque). */
  .loyka-sidebar .loyka-brand { padding: 2px 0 18px 0; }
  .loyka-sidebar .loyka-brand .loyka-badge-logo { width: 100%; height: auto; }

  /* Nombre + fila de acciones (configuración, correo, usuarios, cerrar
     sesión), al fondo del sidebar. */
  .loyka-sidebar-bottom {
    border-top: 1px solid var(--loyka-border); margin-top: 14px; padding-top: 14px;
    display: flex; flex-direction: column; gap: 10px;
  }
  .loyka-account-header { display: flex; align-items: center; gap: 10px; min-width: 0; }
  .loyka-account-name {
    margin: 0; font-size: 0.85rem; color: var(--loyka-text); font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .loyka-account-actions { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
  /* Ancho fijo e igual para los 5 (antes flex:1 en los 5, pero los 2 que
     viven adentro de .loyka-notif-wrapper terminaban más angostos que los
     otros 3 — un caso raro de flexbox anidado con flex-basis:0% que no vale
     la pena perseguir. Con ancho fijo no hay ambigüedad posible, y
     justify-content:space-between en el contenedor los reparte parejo en
     todo el ancho, como antes. */
  .loyka-account-actions .btn-loyka-icon { flex: 0 0 auto; width: 34px; justify-content: center; }

  /* Avatar de perfil: foto (img) o iniciales (span) — mismo tamaño y forma
     para que se puedan intercambiar sin saltos de layout. Tamaño por
     defecto pensado para la barra lateral; .is-small lo achica para la
     tabla de Usuarios y .is-large para el tab de Configuración. */
  .loyka-avatar {
    width: 36px; height: 36px; border-radius: 999px; flex-shrink: 0;
    object-fit: cover; display: flex; align-items: center; justify-content: center;
  }
  .loyka-avatar-iniciales {
    background: rgba(0, 176, 101, 0.18); color: var(--accent);
    font-weight: 700; font-size: 0.8rem; letter-spacing: 0.3px;
  }
  .loyka-avatar.is-small { width: 28px; height: 28px; font-size: 0.68rem; }
  .loyka-avatar.is-large { width: 72px; height: 72px; font-size: 1.3rem; }

  /* Campanita de correo nuevo: botón + badge + panel desplegable, anclados
     al wrapper (position:relative) para que el panel "flote" sobre el resto
     del sidebar en vez de empujar el layout. */
  .loyka-notif-wrapper { position: relative; flex: 0 0 auto; display: flex; }
  .loyka-notif-badge {
    display: none; position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px;
    background: var(--accent); color: #fff; border-radius: 999px;
    font-size: 0.65rem; font-weight: 700; line-height: 16px; text-align: center; padding: 0 3px;
  }
  .loyka-notif-badge.is-visible { display: block; }
  .loyka-notif-panel {
    /* min() en vez de 360px fijos: al vivir dentro del sidebar (260px, mobile
       y desktop) o del wrapper del FAB, es position:absolute y puede
       desbordar el ancho de su contenedor sin que nada lo corte -- en
       desktop no se nota porque el viewport sobra, pero en mobile sí se sale
       de la pantalla, y con el sidebar abierto el body bloquea el scroll
       (ver bloquearScrollBody en helpers.js) así que ni se puede desplazar
       para ver la parte cortada. */
    display: none; position: absolute; bottom: calc(100% + 8px); left: 0;
    width: min(360px, calc(100vw - 40px));
    max-height: 440px; overflow-y: auto; overflow-x: hidden; background: var(--loyka-card-bg);
    border: 1px solid var(--loyka-border); border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); z-index: 40; padding: 10px;
  }
  .loyka-notif-panel.is-active { display: block; }
  .loyka-notif-panel-header {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.6px; font-weight: 700;
    color: var(--loyka-text-muted); opacity: 0.85; margin: 14px 0 6px 0; padding: 0 2px;
  }
  .loyka-notif-panel-header:first-child { margin-top: 0; }
  /* Contador junto al título de cada sección: mismo look que .panel-pill del
     Dashboard (ver loyka-stat-icon/.panel-pill), para que el panel se sienta
     parte de la misma interfaz en vez de un componente aparte. */
  .loyka-notif-panel-count {
    display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px;
    padding: 0 5px; border-radius: 999px; background: rgba(220, 53, 69, 0.18); color: var(--loyka-danger);
    font-size: 0.68rem; font-weight: 800; letter-spacing: normal; text-transform: none;
  }
  .loyka-notif-item {
    display: flex; align-items: flex-start; gap: 10px; padding: 8px; border-radius: 8px; margin-bottom: 2px;
  }
  .loyka-notif-item:hover { background: rgba(255, 255, 255, 0.06); }
  /* Chip de ícono con color por categoría — mismo patrón que .loyka-stat-icon
     de las tarjetas del Dashboard, solo que compacto para caber en una fila. */
  .loyka-notif-icon {
    display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 30px; height: 30px;
    border-radius: 8px; margin-top: 1px; background: rgba(0, 176, 101, 0.14); color: var(--accent);
  }
  .loyka-notif-icon .material-symbols-outlined { font-size: 16px; }
  .loyka-notif-icon.is-success, .loyka-stat-icon.is-success { background: rgba(16, 185, 129, 0.16); color: var(--loyka-oliva); }
  .loyka-notif-icon.is-ocre, .loyka-stat-icon.is-ocre { background: rgba(37, 154, 230, 0.18); color: var(--loyka-ocre); }
  .loyka-notif-icon.is-warning, .loyka-stat-icon.is-warning { background: rgba(255, 186, 0, 0.16); color: var(--loyka-warning); }
  .loyka-notif-icon.is-danger, .loyka-stat-icon.is-danger { background: rgba(220, 53, 69, 0.16); color: var(--loyka-danger); }
  .loyka-notif-body { min-width: 0; flex-grow: 1; }
  .loyka-notif-item .loyka-notif-remitente {
    display: block; font-weight: 600; font-size: 0.8rem; color: var(--loyka-text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .loyka-notif-item .loyka-notif-asunto {
    display: block; font-size: 0.75rem; color: var(--loyka-text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Sin opacity: 0.7 -- ya empujaba el contraste de --loyka-text-muted (que
     por sí solo pasa cómodo en el resto de la app) bajo el mínimo AA para
     texto chico (quedaba en ~4.1:1). */
  .loyka-notif-item .loyka-notif-fecha { font-size: 0.68rem; color: var(--loyka-text-muted); }
  .loyka-notif-empty {
    display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
    padding: 24px 12px; color: var(--loyka-text-muted);
  }
  .loyka-notif-empty .material-symbols-outlined { font-size: 26px; opacity: 0.5; }

  /* Barra mínima solo-mobile: el logo ES el botón de menú (tocarlo
     abre/cierra el sidebar, ver .loyka-brand-toggle) -- nada de gesto de
     deslizar desde el borde para abrir: choca con el gesto nativo de
     "volver atrás" de Android, que intercepta cualquier swipe que arranque
     cerca del borde (sí se mantiene el de cerrar deslizando hacia la
     izquierda, que no arranca del borde -- ver habilitarGestoCerrarSidebarMobile
     en helpers.js). En desktop el logo real vive arriba del sidebar, así
     que esta barra queda oculta (.is-hidden-desktop). */
  .loyka-mobile-topbar {
    display: flex; align-items: center; padding: 10px 16px;
    background: rgba(18, 18, 18, 0.8); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--loyka-border); position: sticky; top: 0;
    /* Tiene que quedar POR ENCIMA del drawer del sidebar (z-index:3000) y su
       overlay (2999) -- si no, con el drawer abierto (que arranca en
       top:0;left:0, la misma esquina que el logo) el propio contenido del
       sidebar le tapa el botón y no se puede volver a tocar para cerrarlo. */
    z-index: 3100;
  }
  .loyka-mobile-topbar .loyka-badge-logo { height: 67.5px; width: auto; }
  /* Reset de <button>: que se vea y se comporte como el logo solo, sin
     look de botón (fondo/borde), pero siga siendo un elemento realmente
     interactivo (foco de teclado, anunciado por lectores de pantalla). */
  .loyka-brand-toggle {
    background: none; border: none; padding: 0; margin: 0; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  /* Barra de navegación inferior (solo mobile) -- calcada del mockup de
     Stitch: 4 destinos fijos + botón central elevado ("+") que abre el
     drawer completo del sidebar en vez de duplicar el menú entero acá.
     z-index bajo, a propósito: cuando el drawer/overlay del sidebar están
     abiertos (z-index 2999/3000, ver más abajo) deben quedar POR ENCIMA de
     esta barra, no competir con ella. */
  .loyka-bottom-nav {
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
    display: flex; justify-content: space-around; align-items: center;
    height: 76px; padding: 0 8px;
    background: var(--loyka-card-bg); border-top: 1px solid var(--loyka-border);
  }
  .loyka-bottom-nav-link {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    color: var(--loyka-text-muted); font-size: 0.65rem; font-weight: 600;
    padding: 6px 10px;
  }
  .loyka-bottom-nav-link .material-symbols-outlined { font-size: 24px; }
  .loyka-bottom-nav-link.is-active-nav { color: var(--accent); }
  .loyka-bottom-nav-link.is-active-nav .material-symbols-outlined { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
  .loyka-bottom-nav-fab-wrap { position: relative; top: -24px; }
  .loyka-bottom-nav-fab {
    width: 56px; height: 56px; border-radius: 999px; border: none;
    background: var(--accent); color: #1C2434;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35); cursor: pointer;
    transition: transform 0.15s ease;
  }
  .loyka-bottom-nav-fab:active { transform: scale(0.94); }
  .loyka-bottom-nav-fab .material-symbols-outlined { font-size: 28px; }

  @media (max-width: 1023px) {
    /* Deja espacio abajo para que la barra fija no tape el final del
       contenido de cada página -- acotado a las páginas que realmente
       tienen #bottom-nav (por ahora solo index.html/gestión; venta-rapida.html
       no lo trae y no necesita el padding extra). */
    body:has(#bottom-nav) { padding-bottom: 92px; }
  }

  @media (max-width: 1023px) {
    .loyka-sidebar.is-mobile-active {
      display: flex !important; position: fixed; top: 0; left: 0; height: 100vh;
      z-index: 3000; background: var(--loyka-bg); padding: 20px 10px 20px 20px;
      width: 260px; box-shadow: 4px 0 15px rgba(0,0,0,0.5);
    }
    /* El logo grande de acá arriba es solo para desktop (ver comentario en
       .loyka-mobile-topbar): en mobile el drawer es fixed;top:0;left:0, la
       misma esquina que la topbar (z-index 3100, por encima a propósito
       para que el hamburger siga clickeable) -- sin ocultarlo, este logo
       quedaba tapado/cortado por la topbar apenas se abría el sidebar.
       El logo chico de la topbar ya cumple ese rol en mobile. */
    .loyka-sidebar .loyka-brand { display: none; }
    .sidebar-overlay { display: none; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); z-index: 2999; }
    .sidebar-overlay.is-active { display: block; }
  }
  @media (min-width: 1024px) {
    .loyka-sidebar { display: flex; }
    .is-hidden-desktop { display: none !important; }
    /* Compensa que el sidebar (fixed) ya no reserva su espacio dentro del
       flex de .loyka-app-layout — mismo ancho que .loyka-sidebar. Va en
       #page-content (por id, no por .loyka-main-content): cada página
       (inicio.html, ventas.html, etc.) repite esa misma clase en su propio
       <main> raíz, que auth.js inyecta ADENTRO de #page-content — si el
       margin fuera por clase, se aplicaría dos veces (anidado). */
    #page-content { margin-left: 260px; }
  }

  /* .section-app ya no existe en el DOM (quedó de antes de que el ruteo
     pasara a cargar cada página como fragmento HTML vía fetch, ver
     loadPage() en auth.js) — el selector de abajo era muerto, por eso la
     tarjeta principal de cada página no tenía borde visible y se perdía
     contra el fondo (se notaba mucho en páginas con poco contenido, tipo
     Clientes o Lotes: quedaba un choclón oscuro sin límite claro). */
  .loyka-main-content .box {
    background-color: var(--loyka-container-bg) !important;
    border-radius: 10px !important;
    /* --loyka-border (#2E3A47) es casi el mismo tono que loyka-card-bg
       (#24303F) — como borde de tarjeta quedaba invisible. Un borde claro
       translúcido se nota sin importar el bg de atrás (no depende de que
       haya suficiente diferencia entre dos oscuros), que es como se suele
       separar tarjetas en temas oscuros. */
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35) !important;
  }

  .form-header .title { display: flex; align-items: center; justify-content: center; gap: 12px; color: #f3f4f6 !important; font-weight: 700 !important; margin-bottom: 0.5rem !important; }
  .form-header .title .material-symbols-outlined { font-size: 28px; color: var(--loyka-orange); filter: drop-shadow(0 0 8px var(--loyka-red-glow)); }
  .form-header .subtitle { color: #9ca3af; margin-top: 0 !important; font-size: 0.9rem; }

  .drag-handle { cursor: grab; padding: 4px; border-radius: 6px; transition: background 0.2s; display: inline-flex; align-items: center; justify-content: center; }
  .drag-handle:hover { background-color: rgba(0,0,0,0.05); }
  .drag-handle:active { cursor: grabbing !important; }
  .sortable-ghost { opacity: 0.4; transform: scale(0.98); background-color: rgba(0,0,0,0.05); border-radius: var(--radius-md); }

  .btn-loyka-primary {
    background-color: var(--accent); border: none; color: #fff; font-weight: 600;
    border-radius: var(--radius-sm); transition: all 0.3s ease; display: inline-flex;
    align-items: center; justify-content: center; gap: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
  }
  .btn-loyka-primary:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); background-color: #2C3AAE; color: #fff !important; }
  .btn-loyka-primary.is-loading::after { border-color: transparent transparent #fff #fff !important; }

  .tabla-scroll { border: 1px solid var(--loyka-border); border-radius: var(--radius-md); overflow: hidden; }
  .tabla-scroll .table { margin-bottom: 0 !important; }
  
  .button.is-small .material-symbols-outlined, .lucide-icon-small { font-size: 16px !important; }
  .button.is-medium .material-symbols-outlined { font-size: 20px !important; }

  .loyka-badge-logo {
    display: block; height: 50.4px; width: auto; border-radius: var(--radius-sm);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
  }


  .btn-loyka-outline {
    background: transparent; border: 1px solid #444; color: #e0e0e0; border-radius: var(--radius-sm);
    padding: 6px 12px; font-size: 0.8rem; font-weight: 600; cursor: pointer; display: flex;
    align-items: center; gap: 6px; transition: all 0.2s ease; font-family: 'Satoshi', sans-serif;
  }
  .btn-loyka-outline:hover { background: #2e2e2e; border-color: #666; color: #fff; }
  .btn-loyka-icon { padding: 6px; }
  .btn-loyka-outline .material-symbols-outlined { font-size: 16px; }

  /* Lenguaje de tarjeta "plano": sin brillos ni gradientes, radio chico,
     sombra apenas insinuada — se nota, pero no compite con el contenido. */
  .loyka-card {
    background: var(--loyka-card-bg); border-radius: 8px; border: 1px solid var(--loyka-border);
    padding: 20px; cursor: pointer; transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
    display: flex; flex-direction: column;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  }
  .loyka-card:hover { transform: translateY(-2px); border-color: var(--accent); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25); }
  /* Un transform en la tarjeta crea un nuevo contexto de posicionamiento para
     cualquier descendiente position:fixed (como .insumo-menu-dropdown), así
     que mientras el menú está abierto se anula: si no, el menú terminaba
     posicionado relativo a la tarjeta en vez de a la pantalla (pasaba con el
     mouse encima, y en iOS con el :hover que queda "pegado" tras un tap). */
  .loyka-card.tiene-menu-abierto { transform: none !important; }
  .loyka-card-icon {
    margin-bottom: 14px; display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 8px; background: rgba(0, 176, 101, 0.14); color: var(--accent);
  }
  .loyka-card-icon .material-symbols-outlined { font-size: 20px; }
  .loyka-card-title { font-size: 0.9rem; font-weight: 700; color: var(--loyka-text); margin-bottom: 4px; }
  .loyka-card-desc { font-size: 0.8rem; color: var(--loyka-text-muted); line-height: 1.5; margin: 0; }

  /* Variante compacta: misma tarjeta, menos aire, para grillas con muchos ítems (ej. Bodega). */
  .loyka-card-compact { padding: 14px; }
  .loyka-card-compact .loyka-card-title { font-size: 0.78rem; margin-bottom: 4px; }
  .loyka-card-compact .loyka-card-desc { font-size: 0.74rem; line-height: 1.35; }
  .loyka-card-compact .tag { font-size: 0.65rem; padding: 2px 8px; }

  /* Layout maestro-detalle de Recetas: mismo patrón flex que .vr-pos
     (Venta Rápida), pero Recetas vive DENTRO del app shell (con sidebar),
     no en una página standalone como Venta Rápida -- por eso el breakpoint
     no puede copiar el de .vr-pos tal cual. El sidebar mete margin-left:260px
     a #page-content recién a partir de 1024px (ver esa media query más abajo
     en este archivo), así que si esta fila arrancara en 900px, el panel de
     detalle se ANGOSTA de golpe apenas la ventana llega a 1024px -- justo lo
     opuesto a lo esperado al agrandar la ventana. 1100px da margen para que,
     con sidebar + panel, el detalle siga teniendo un ancho usable. */
  .recetas-layout { display: flex; flex-direction: column; gap: 20px; margin-top: 16px; }
  @media (min-width: 1100px) {
    .recetas-layout { flex-direction: row; align-items: flex-start; }
    /* Basis en px (no %) a propósito: con un split porcentual (60/40) el
       panel de detalle quedaba angosto justo en el borde del breakpoint (ver
       nota de arriba) -- la fila de un insumo (label + cantidad + unidad +
       botón eliminar) necesita ~380px cómodos para que el input de cantidad
       no se aplaste. La grilla de tarjetas (.loyka-grid) reflowea sola con
       auto-fit/minmax(260px,1fr), así que puede ceder ese espacio sin romperse. */
    .recetas-lista { flex: 1 1 300px; min-width: 280px; }
    .recetas-detalle { flex: 1 1 420px; min-width: 380px; position: sticky; top: 90px; }
  }
  .recetas-detalle {
    background: var(--loyka-card-bg); border: 1px solid var(--loyka-border);
    border-radius: var(--radius-md); padding: 20px;
    /* Sin esto, un formulario de edición largo (muchos insumos) puede
       extenderse más allá del viewport y dejar el botón Guardar bajo el
       pliegue -- con sticky + max-height, el panel scrollea internamente. */
    max-height: calc(100vh - 110px); overflow-y: auto;
  }

  .loyka-card.is-seleccionada { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

  /* Cabecera de tarjeta con título + botones en flujo normal (no flotando
     encima), para que un nombre largo nunca quede tapado por los botones. */
  .insumo-card-header, .proveedor-card-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; margin-bottom: 6px; }
  .insumo-card-header .loyka-card-title, .proveedor-card-header .loyka-card-title { flex: 1; min-width: 0; margin-bottom: 0; }

  .insumo-menu, .proveedor-menu { position: relative; flex-shrink: 0; }
  .insumo-menu .btn-toggle-menu-insumo, .proveedor-menu .btn-toggle-menu-proveedor { padding: 0 8px; }
  /* position: fixed (no absolute) a propósito: la tarjeta (.loyka-card) tiene
     overflow: hidden para recortar su brillo decorativo en las esquinas, y
     eso recortaba este menú también apenas se salía del borde de la tarjeta.
     Con fixed, el top/right se calculan en JS al abrirlo (ver gestion.js,
     proveedores.js). */
  .insumo-menu-dropdown, .proveedor-menu-dropdown {
    display: none; position: fixed; z-index: 50;
    background: var(--loyka-card-bg); border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4); min-width: 180px; padding: 4px;
  }
  .insumo-menu-dropdown.is-active, .proveedor-menu-dropdown.is-active { display: block; }
  .insumo-menu-item, .proveedor-menu-item {
    display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
    background: none; border: none; padding: 8px 10px; border-radius: var(--radius-sm);
    font-size: 0.78rem; color: var(--loyka-text); cursor: pointer;
  }
  .insumo-menu-item:hover, .proveedor-menu-item:hover { background: rgba(255, 255, 255, 0.06); }
  .insumo-menu-item.has-text-danger:hover, .proveedor-menu-item.has-text-danger:hover { background: rgba(220, 53, 69, 0.12); }

  .proveedor-checklist { max-height: 180px; overflow-y: auto; border: 1px solid var(--loyka-border); border-radius: var(--radius-sm); padding: 8px; }

  /* =========================================
     TOAST Y TABLAS MÓVILES (CON NESTING)
     ========================================= */
  #toast-container { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 99999; display: flex; flex-direction: column; gap: 10px; pointer-events: none; width: 90%; max-width: 400px; }
  .loyka-toast { padding: 12px 20px; border-radius: 50px; color: white; font-weight: 600; font-size: 0.9rem; display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.3); animation: slideUpToast 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; text-align: center; }
  .loyka-toast.is-success { background: linear-gradient(135deg, var(--loyka-oliva), #0B815A); }
  .loyka-toast.is-danger { background: linear-gradient(135deg, var(--loyka-danger), #A3232F); }
  .loyka-toast.is-warning { background: linear-gradient(135deg, var(--loyka-warning), #B38300); color: #1C2434; }
  .loyka-toast.is-info { background: linear-gradient(135deg, var(--loyka-ocre), #1A73B3); color: #fff; }
  .loyka-toast.fade-out { animation: fadeOutToast 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }

  @keyframes slideUpToast { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes fadeOutToast { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(20px); } }

  /* =========================================
     REPORTAR BUG (BOTONES FLOTANTES)
     ========================================= */
  /* A propósito discretos: opacidad baja en reposo, suben al pasar el mouse.
     Van sueltos sobre el viewport (no dentro del sidebar, a diferencia de
     los otros íconos de acción) porque así los pidió el usuario: que no se
     vean mucho. */
  .loyka-fab {
    width: 40px; height: 40px; border-radius: 999px;
    display: flex; align-items: center; justify-content: center;
    background: var(--loyka-card-bg); border: 1px solid var(--loyka-border);
    color: var(--loyka-text-muted); opacity: 0.55; cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); transition: opacity 0.2s, color 0.2s;
  }
  .loyka-fab:hover { opacity: 1; color: var(--accent); }
  .loyka-fab .material-symbols-outlined { font-size: 18px; }

  .loyka-fab-right { position: fixed; bottom: 20px; right: 20px; z-index: 45; }

  /* .loyka-sidebar es fixed, 260px de ancho, pero solo VISIBLE desde
     1024px (ver .loyka-sidebar / @media min-width:1024px más abajo). Bajo
     1024px el sidebar está fuera de pantalla salvo que esté abierto, así
     que left:20px es seguro; desde 1024px hay que correrse a la derecha
     del sidebar (260px + 20px de aire) para no quedar tapado bajo su fila
     de acciones (.loyka-account-actions). */
  .loyka-fab-wrapper-left { position: fixed; bottom: 20px; left: 20px; z-index: 45; }
  @media (min-width: 1024px) {
    .loyka-fab-wrapper-left { left: 280px; }
  }
  /* Bajo 1024px, "bottom: 20px" cae justo encima de .loyka-bottom-nav (fija,
     76px de alto) y los tapa -- se suben justo debajo de .loyka-mobile-topbar
     (87.5px de alto: 67.5px del logo + 10px de padding arriba/abajo) en vez
     de abajo. El panel de reportes (comparte .loyka-notif-panel con los
     paneles del sidebar, que sí abren hacia arriba porque viven abajo) tiene
     que abrir hacia ABAJO acá porque ahora el botón está arriba. */
  @media (max-width: 1023px) {
    .loyka-fab-right, .loyka-fab-wrapper-left { bottom: auto; top: 96px; }
    .loyka-fab-wrapper-left .loyka-notif-panel { bottom: auto; top: calc(100% + 8px); }
  }
  /* Texto del reporte: a diferencia de .loyka-notif-asunto (una línea con
     ellipsis, pensada para un asunto de correo corto), acá el texto puede
     ser largo y necesita leerse completo. */
  .loyka-reporte-bug-texto {
    font-size: 0.78rem; color: var(--loyka-text); white-space: normal;
    overflow-wrap: break-word; margin: 2px 0 4px 0;
  }
  .loyka-reporte-bug-acciones { display: flex; gap: 6px; margin-top: 2px; }

  @media screen and (max-width: 768px) {
    .tabla-scroll {
      border: none !important; background: transparent !important; overflow-x: visible !important;
      
      table:not(.no-cards) {
        background: transparent !important; display: block;
        
        thead { display: none; }
        tbody { display: block; }
        
        tbody tr {
          display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 12px; padding: 16px; margin-bottom: 16px;
          border-radius: var(--radius-lg); background-color: #fff; border: 1px solid #f0f0f0;
          box-shadow: 0 4px 12px rgba(0,0,0,0.05); position: relative;
        }

        .dark-mode & tbody tr { background-color: #1f2937 !important; border-color: #374151 !important; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }

        tbody td { display: flex; flex-direction: column; justify-content: center; padding: 0 !important; border: none !important; }
        tbody td:first-child { grid-column: 1 / -1; margin-bottom: 8px; align-items: flex-start !important; text-align: left !important; }
        tbody td:last-child {
          grid-column: 1 / -1; display: flex; flex-direction: row; justify-content: flex-end; align-items: center;
          flex-wrap: wrap; gap: 8px; margin-top: 8px; padding-top: 14px !important; border-top: 1px solid #f0f0f0 !important;
        }

        .dark-mode & tbody td:last-child { border-top-color: #374151 !important; }
        
        tbody td:nth-child(3):not(:last-child) { align-items: flex-end !important; text-align: right !important; }
        tbody td.has-text-centered, tbody td.has-text-right { text-align: inherit !important; }
        tbody td:first-child:last-child { align-items: center !important; text-align: center !important; border-top: none !important; padding: 16px !important; margin: 0 !important; }

        tfoot { display: block; }
        tfoot tr { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-radius: var(--radius-md); background: #fdfdfd; margin-bottom: 8px; border: 1px solid #f0f0f0; }
        
        .dark-mode & tfoot tr { background-color: #1f2937 !important; border-color: #374151 !important; }
        tfoot td { display: block; border: none !important; padding: 0 !important; }
        tfoot td[colspan] { text-align: left !important; flex-grow: 1; }
      }
    }
  }

  /* =========================================
     OTROS COMPONENTES
     ========================================= */
  .autocomplete-dropdown {
    display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 100;
    max-height: 200px; overflow-y: auto; border: 1px solid #dbdbdb; border-radius: var(--radius-sm);
    margin-top: 4px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); background: #fff;
  }
  .autocomplete-item { padding: 8px 12px; cursor: pointer; border-bottom: 1px solid #eee; transition: background 0.2s; font-size: 0.85rem; display: flex; align-items: center; gap: 8px; }
  .autocomplete-item:last-child { border-bottom: none; }
  .autocomplete-item:hover { background-color: #f5f5f5; color: var(--loyka-orange); font-weight: bold; }

  .skeleton-line { background-color: #e0e0e0; border-radius: 4px; animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
  @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
  .skeleton-row-venta td { padding: 12px 8px !important; }
  .skeleton-row-anotacion { animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite; }

  .offline-banner { display: none; position: sticky; top: 85px; background-color: var(--loyka-warning); color: #1C2434; text-align: center; padding: 8px; font-size: 0.8rem; z-index: 1040; }
  .lucide-spin { animation: spin 1.5s linear infinite; }
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

  .card-gasto { background: white; border-radius: 15px; padding: 15px; margin-bottom: 15px; box-shadow: 0 4px 10px rgba(0,0,0,0.05); border: 1px solid #f0f0f0; }
  .section-title { font-size: 0.85rem; font-weight: 700; color: var(--accent); text-transform: uppercase; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
  .row-insumo { display: flex; gap: 4px; margin-bottom: 10px; padding-bottom: 10px; align-items: flex-end; width: 100%; border-bottom: 1px solid #d0d0d0; }
  .row-insumo:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
  .insumo-info { flex: 0 0 60%; width: 60%; box-sizing: border-box; padding-right: 4px; }
  .input-cant { flex: 0 0 40%; width: 40%; box-sizing: border-box; }
  .insumo-name { font-size: 0.8rem; font-weight: 600; color: #4a4a4a; display: block; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* =========================================
     FORZAR ESPACIADO Y AIRE AL GRID
     ========================================= */
  .section-app,
  .section-app .box,
  .loyka-main-content .box {
    padding: 1.5rem !important;
    box-sizing: border-box !important;
  }

  .loyka-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    padding: 0.5rem !important;
    margin: 0 auto !important;
    width: 100% !important;
  }

  /* =========================================
     VENTAS: FORMULARIO + CARRITO EN COLUMNAS
     ========================================= */
  /* minmax(0, …) en vez de fracciones a secas — mismo motivo que
     .dashboard-charts-grid más abajo: sin el mínimo en 0 explícito, un
     hijo con contenido "ancho" (nombre de producto largo, etc.) puede
     empujar la columna más ancha que el espacio real disponible. */
  .venta-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; }
  @media (min-width: 900px) {
    .venta-grid { grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); align-items: start; }
    .venta-grid-cart { position: sticky; top: 110px; }
  }
  .venta-cart-box { border: 1px solid var(--loyka-border); background: var(--loyka-card-bg) !important; }

  /* =========================================
     DASHBOARD: GRÁFICOS (Chart.js)
     ========================================= */
  /* minmax(0, 1fr) en vez de 1fr a secas: un track "1fr" a secas respeta el
     ancho mínimo de contenido de lo que tenga adentro (min-width:auto, el
     mismo default de flex) — acá adentro vive un <canvas> de Chart.js que
     antes de que el resize responsive corra mide 300px fijos, así que el
     track (y la tarjeta, y todo lo que viene después) no podía angostarse
     más que eso y se salía del viewport en celular. minmax(0, 1fr) anula
     ese mínimo implícito. */
  .dashboard-charts-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; margin-top: 8px; }
  @media (min-width: 1024px) { .dashboard-charts-grid { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: stretch; } }
  .loyka-chart-card { margin: 0 !important; display: flex; flex-direction: column; min-width: 0; }
  .loyka-chart-canvas-wrap { position: relative; height: 280px; flex-grow: 1; min-width: 0; }

  /* Mismo tratamiento "glass" que .loyka-stat-card (ver comentario ahí).
     Necesita ganarle en especificidad a ".dark-mode .box" (que fija
     background/border-radius/box-shadow con !important más arriba en este
     archivo) porque el HTML combina ambas clases: class="box loyka-chart-card". */
  .dark-mode .box.loyka-chart-card {
    background: rgba(23, 31, 51, 0.7) !important;
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
    border-radius: 14px !important;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28) !important;
  }

  /* =========================================
     DASHBOARD: ESTADO FINANCIERO / RENDIMIENTO GLOBAL
     ========================================= */
  .dashboard-panels-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; margin-top: 8px; }
  @media (min-width: 1024px) { .dashboard-panels-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; } }

  /* Fila de estadísticas arriba del Dashboard — el resumen "de un vistazo",
     antes de entrar en gráficos y detalle. */
  .dashboard-stats-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; margin-bottom: 28px; }
  /* Tratamiento "glass" calcado literal del mockup de Stitch (.glass-panel
     en su HTML original: rgba(23,31,51,0.7) + blur(8px) — 23,31,51 es
     exactamente --loyka-card-bg / #171F33 en rgb, a 70% de opacidad). */
  .loyka-stat-card {
    background: rgba(23, 31, 51, 0.7); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 14px;
    padding: 22px; box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
    transition: transform 0.15s ease, border-color 0.15s ease;
  }
  .loyka-stat-card:hover { transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.16); }
  /* Chip neutro + ícono relleno (FILL 1), calcado de las KPI cards de
     Stitch (bg-surface-container-highest + font-variation-settings FILL 1)
     — antes el chip llevaba el color de acento como fondo teñido; Stitch
     deja el fondo neutro y el color vive solo en el ícono. */
  .loyka-stat-icon {
    display: flex; align-items: center; justify-content: center; width: 48px; height: 48px;
    border-radius: 12px; background: #2d3449; color: var(--accent); margin-bottom: 16px;
  }
  .loyka-stat-icon .material-symbols-outlined { font-size: 22px; font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
  .loyka-stat-icon.is-success { color: var(--loyka-oliva); }
  .loyka-stat-icon.is-ocre { color: var(--loyka-ocre); }
  .loyka-stat-value { font-size: 2.25rem; font-weight: 700; letter-spacing: -0.02em; color: var(--loyka-text); line-height: 1.2; }
  .loyka-stat-value.has-text-danger { color: var(--loyka-danger) !important; }
  .loyka-stat-label { font-size: 0.78rem; color: var(--loyka-text-muted); font-weight: 600; margin-top: 4px; }
  .loyka-stat-trend { display: inline-flex; align-items: center; gap: 4px; font-size: 0.75rem; font-weight: 700; margin-top: 10px; }
  .loyka-stat-trend.is-up { color: var(--loyka-oliva); }
  .loyka-stat-trend.is-down { color: var(--loyka-danger); }
  .loyka-stat-trend .material-symbols-outlined { font-size: 14px; }

  .panel-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
  .panel-card-header h3 { margin: 0; }
  .panel-pill {
    display: inline-flex; align-items: center; gap: 4px; padding: 4px 12px;
    border-radius: 999px; font-size: 0.75rem; font-weight: 700; white-space: nowrap;
  }
  .panel-pill.is-good { background: rgba(16, 185, 129, 0.18); color: var(--loyka-oliva); }
  .panel-pill.is-bad { background: rgba(220, 53, 69, 0.18); color: var(--loyka-danger); }

  .panel-hero-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--loyka-text-muted); font-weight: 700; }
  .panel-hero-value { font-size: 2rem; font-weight: 800; color: var(--loyka-text); line-height: 1.2; margin: 4px 0 12px; }
  .panel-alerta-linea { font-size: 0.85rem; color: var(--loyka-warning); font-weight: 600; display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
  .panel-alerta-linea .material-symbols-outlined { font-size: 15px; }

  .panel-mini-boxes { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin: 16px 0; }
  .panel-mini-box {
    background: rgba(255, 255, 255, 0.04); border: 1px solid var(--loyka-border);
    border-radius: 10px; padding: 10px 12px; text-align: left;
    display: flex; align-items: center; gap: 8px;
    transition: transform 0.15s ease, border-color 0.15s ease;
  }
  .panel-mini-box:hover { transform: translateY(-2px); border-color: var(--accent); }
  .panel-mini-icon {
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    width: 32px; height: 32px; border-radius: 9px;
    background: #2d3449; color: var(--accent);
  }
  .panel-mini-icon .material-symbols-outlined { font-size: 16px; font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
  .panel-mini-icon.is-success { color: var(--loyka-oliva); }
  .panel-mini-icon.is-ocre { color: var(--loyka-ocre); }
  .panel-mini-box .panel-mini-label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.4px; color: var(--loyka-text-muted); font-weight: 700; }
  /* Antes 1.15rem: con un monto largo ($ millones, 7+ dígitos) no cabía en
     una sola línea dentro de estas cajas angostas y quedaba partido a la
     mitad (ver overflow-wrap más abajo) — más chico entra cómodo. */
  .panel-mini-box .panel-mini-value { font-size: 0.95rem; font-weight: 800; margin-top: 2px; }
  /* El span que envuelve label+valor es un hijo flex sin min-width:0 (el
     default es "auto", que no deja que un hijo flex se achique más allá del
     ancho de su contenido) — con un monto largo tipo "$2.133.326" eso hacía
     que el texto se saliera de la caja en vez de partirse en dos líneas. */
  .panel-mini-box span:not(.panel-mini-icon) { min-width: 0; overflow-wrap: break-word; }

  .panel-divider { border-top: 1px solid var(--loyka-border); margin: 16px 0; }
  .panel-flex-row { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
  .panel-flex-row .panel-hero-label { margin-bottom: 2px; }
  .panel-nota { font-size: 0.7rem; color: var(--loyka-text-muted); }

  .panel-progress-track { background: var(--loyka-border); border-radius: 999px; height: 8px; overflow: hidden; margin: 8px 0 20px; }
  .panel-progress-fill { background: var(--loyka-oliva); height: 100%; border-radius: 999px; transition: width 0.4s ease; }

  .producto-stock-row {
    display: flex; justify-content: space-between; align-items: center;
    padding: 12px 4px; border-bottom: 1px solid var(--loyka-border); cursor: pointer;
  }
  .producto-stock-row:last-child { border-bottom: none; }
  .producto-stock-row .producto-nombre { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 0.85rem; }
  .producto-stock-row .producto-lotes-count { color: var(--loyka-text-muted); font-weight: 400; font-size: 0.75rem; }
  .producto-stock-row .producto-stock-badge { display: flex; align-items: center; gap: 8px; }
  .producto-stock-row .material-symbols-outlined.chevron { font-size: 16px; transition: transform 0.2s ease; color: var(--loyka-text-muted); }
  .producto-stock-row.is-open .material-symbols-outlined.chevron { transform: rotate(180deg); }
  .producto-stock-detalle { display: none; padding: 4px 4px 12px 26px; }
  .producto-stock-detalle.is-open { display: block; }
  .producto-stock-detalle .lote-linea { display: flex; justify-content: space-between; font-size: 0.78rem; color: var(--loyka-text-muted); padding: 3px 0; }

  /* Tarjeta por lote del panel de Stock — más rica que .lote-linea (que
     solo tiene código + unidades, usada en el desglose viejo de Inicio):
     acá entra valor, antigüedad, estimación de días restantes, el botón
     de mermar y el historial de mermas si tiene. */
  .stock-lote-item {
    border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
    padding: 12px 14px; margin: 8px 0;
  }
  .stock-lote-header {
    display: flex; justify-content: space-between; align-items: center;
    gap: 10px; font-size: 0.85rem; margin-bottom: 8px;
  }
  .stock-lote-datos {
    display: flex; gap: 16px; flex-wrap: wrap;
    font-size: 0.78rem; color: var(--loyka-text-muted);
  }
  .stock-lote-mermas { margin-top: 8px; border-top: 1px solid var(--loyka-border); padding-top: 8px; }

  .form-header {
    text-align: center;
    padding-top: 1rem !important;
    margin-bottom: 2rem !important;
  }

/* ==========================================
   VENTA RÁPIDA (public/venta-rapida.html)
   ========================================== */
.vr-topbar-title { font-weight: 700; font-size: 1rem; color: var(--loyka-text); flex-grow: 1; }
#vr-root { max-width: 900px; margin: 0 auto; }

/* Barra "volver + título", siempre visible (mobile Y desktop) a diferencia
   de .loyka-mobile-topbar (is-hidden-desktop, solo hamburger+logo): a
   diferencia de gestión (rutas de nivel superior, sin drill-down), acá hay
   pantallas anidadas (sesión → grilla) que necesitan un botón de volver
   visible siempre, no solo en mobile. Vive dentro de #vr-main (no de
   #vr-root) para sobrevivir los reemplazos de innerHTML de cada pantalla. */
.vr-content-header { display: flex; align-items: center; gap: 12px; max-width: 900px; margin: 0 auto 16px auto; }

/* El sidebar de Venta Rápida reutiliza .loyka-sidebar tal cual (mismo look
   Y mismo comportamiento que gestión: fijo y siempre visible desde 1024px,
   drawer superpuesto bajo eso) -- sin overrides propios, para que ambos
   modos queden configurados exactamente igual. Solo #vr-main necesita el
   margin-left que gestión le da a #page-content (ver
   "@media min-width:1024px" más arriba) porque acá no hay un
   #page-content intermedio inyectado por rutas. */
@media (min-width: 1024px) {
  #vr-main { margin-left: 260px; }
}

.vr-producto-row {
  border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
  padding: 12px 14px; margin-bottom: 10px; background: var(--loyka-card-bg);
}
.vr-producto-detalle { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--loyka-border); }
.vr-foto-preview { margin-bottom: 8px; }
.vr-foto-thumb { width: 72px; height: 72px; object-fit: cover; border-radius: var(--radius-md); }
.vr-lista-sesiones { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.vr-lista-sesiones .loyka-card { padding: 16px 18px; }

.vr-pos { display: flex; flex-direction: column; gap: 20px; }
@media (min-width: 900px) {
  .vr-pos { flex-direction: row; align-items: flex-start; }
  .vr-pos-grid { flex: 1 1 60%; }
  .vr-carrito { flex: 1 1 40%; position: sticky; top: 90px; }
}
.vr-pos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px;
}
.vr-tile {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 12px;
  background: var(--loyka-card-bg); border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
  cursor: pointer; text-align: center;
}
.vr-tile:active { transform: scale(0.97); border-color: var(--accent); }
.vr-tile-foto { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--radius-md); }
.vr-tile-nombre { font-weight: 700; font-size: 0.9rem; color: var(--loyka-text); }
.vr-tile-precio { font-size: 0.85rem; color: var(--loyka-text-muted); }

.vr-carrito {
  background: var(--loyka-card-bg); border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
  padding: 16px;
}
.vr-carrito-titulo { font-weight: 700; margin-bottom: 10px; color: var(--loyka-text); }
.vr-carrito-lista { display: flex; flex-direction: column; gap: 8px; max-height: 40vh; overflow-y: auto; }
.vr-carrito-item {
  display: grid; grid-template-columns: 1fr auto; gap: 4px; align-items: center;
  padding: 8px 0; border-bottom: 1px solid var(--loyka-border);
}
.vr-carrito-item-nombre { font-weight: 600; color: var(--loyka-text); grid-column: 1 / 2; }
.vr-carrito-item-subtotal { font-weight: 700; color: var(--loyka-text); grid-column: 2 / 3; text-align: right; }
.vr-carrito-item-controles { grid-column: 1 / 3; display: flex; align-items: center; gap: 8px; }
.vr-carrito-item-cantidad { font-weight: 700; min-width: 20px; text-align: center; }
/* .is-small de Bulma da ~28-30px, bajo el mínimo recomendado de 44px para un
   blanco táctil -- y son justo los botones que se tocan repetidamente
   durante una venta en vivo en una feria. Un mal-toque acá afecta el total
   cobrado, así que se agranda solo acá (no en toda la app) en vez de subir
   a .is-normal/.is-medium (que también agranda la tipografía de más). */
.vr-btn-menos, .vr-btn-mas, .vr-btn-quitar { min-width: 44px; min-height: 44px; }

/* Total en tipografía grande y alto contraste: pensado para mostrárselo
   al cliente, reemplazando el rol de una boleta/pantalla de caja registradora. */
.vr-carrito-total {
  display: flex; justify-content: space-between; align-items: center;
  margin: 16px 0; padding: 16px 0; border-top: 2px solid var(--loyka-border);
  font-size: 1.6rem; font-weight: 800; color: var(--loyka-text);
}
.vr-carrito-total-monto { color: var(--loyka-oliva); }

.vr-historial-titulo { font-weight: 700; font-size: 1.1rem; color: var(--loyka-text); margin-bottom: 4px; }
.vr-historial-total { font-size: 1.2rem; font-weight: 800; color: var(--loyka-oliva); margin-bottom: 16px; }
.vr-historial-lista { display: flex; flex-direction: column; gap: 10px; }
.vr-historial-item {
  background: var(--loyka-card-bg); border: 1px solid var(--loyka-border); border-radius: var(--radius-md);
  padding: 12px 14px;
}
.vr-historial-item-cabecera { display: flex; justify-content: space-between; font-weight: 700; color: var(--loyka-text); margin-bottom: 6px; }
.vr-historial-item-detalle { font-size: 0.8rem; color: var(--loyka-text-muted); }

/* ==========================================
   COTIZACIONES: VISTA IMPRIMIBLE (public/cotizacion-imprimir.html)
   ========================================== */
.ci-toolbar { display: flex; justify-content: center; padding: 20px; }
.ci-hoja {
  max-width: 800px; margin: 0 auto 40px auto; padding: 40px;
  background: var(--loyka-card-bg); border: 1px solid var(--loyka-border);
  border-radius: var(--radius-md); color: var(--loyka-text);
}
.ci-header { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; border-bottom: 2px solid var(--loyka-border); padding-bottom: 20px; }
.ci-logo { width: 120px; height: auto; }
.ci-header-info h1 { font-size: 1.4rem; font-weight: 800; margin: 0; }
.ci-header-info p { color: var(--loyka-text-muted); margin: 4px 0 0 0; }
.ci-cliente { margin-bottom: 20px; font-size: 1.05rem; }
.ci-tabla { margin-bottom: 20px; }
.ci-total {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 1.3rem; font-weight: 800; padding-top: 12px; border-top: 2px solid var(--loyka-border);
}

/* Al imprimir: forzar fondo blanco / texto negro (la app es dark-mode-only)
   y ocultar cualquier elemento que no sea el documento en sí (botón de
   imprimir, pantallas de carga/error). */
@media print {
  .no-print { display: none !important; }
  .dark-mode body, body, .ci-hoja { background: #fff !important; color: #111 !important; }
  .ci-hoja { border: none; padding: 0; box-shadow: none; max-width: 100%; }
  .ci-header-info p, .ci-total { color: #111 !important; }
  /* Beat .dark-mode .table / .dark-mode .table thead th (specificity 0,2,0 /
     0,2,2): sin esto el ítem de la cotización imprime con texto casi blanco
     sobre fondo blanco (o el header con la caja navy oscura de la app). */
  .dark-mode .ci-hoja .table, .dark-mode .ci-hoja .table th, .dark-mode .ci-hoja .table td { background-color: #fff !important; color: #111 !important; }
  .dark-mode .ci-hoja .table thead th, .dark-mode .ci-hoja .table thead tr { background-color: #f5f5f5 !important; color: #111 !important; }
  /* .tabla-scroll usa overflow:hidden en pantalla (para el borde redondeado);
     en papel no existe el scroll, así que si la tabla no entra en el ancho
     mejor dejarla desbordar/reflowear que perder columnas silenciosamente. */
  .ci-hoja .tabla-scroll { overflow: visible; }
}
