@font-face{font-family:'Poppins';font-weight:600;src:url('/public/brand/poppins-600.woff2') format('woff2');font-display:swap}
@font-face{font-family:'Poppins';font-weight:700;src:url('/public/brand/poppins-700.woff2') format('woff2');font-display:swap}
/* Texto y cifras del sistema: IBM Plex Sans (05-sep-2026, decisión de Alejandro en el lienzo "Tipografía del
   sistema": opción A). Un solo archivo VARIABLE (pesos 100–700) del subconjunto latin (ñ, acentos, ¿¡, €):
   lo que caiga fuera (≤ ⚠ → flechas) baja a Segoe UI por el stack, sin tofu. Empaquetada en public/brand
   (OFL 1.1, licencia al lado) como Poppins: sin internet se ve igual. */
@font-face{font-family:'IBM Plex Sans';font-style:normal;font-weight:100 700;src:url('/public/brand/ibm-plex-sans.woff2') format('woff2');font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* Tema: variables CSS. Modo Claro por defecto, Modo Oscuro con [data-theme="oscuro"].
   Paleta: naranja = acción/ubicación; navy-slate (--violet) = 2º color de marca (del logo);
   el morado estructural se retiró (headers de tabla claros + acento).
   Claro SIN blanco puro (pedido 05-jul: menos deslumbre): toda la rampa de claros baja un
   escalón (#fff→#f3f4f6, etc.) y los bordes se recalibran para seguir viéndose sobre las
   superficies atenuadas. El blanco #fff queda solo donde es contenido (fotos de producto, ticket).
   04-sep (pedido Alejandro: "el Modo Claro necesito que se incline más al gris, el blanco le quita
   ciertas características visuales"): la rampa baja OTRO escalón — superficie #f3f4f6→#e1e3e8,
   controles #edeff2→#d4d8df, fondo #e8eaee→#d2d6dd — con bordes más firmes, --muted un punto más
   oscuro y sombras algo más presentes para que tarjetas y paneles sigan despegándose del fondo. */
:root{
  /* 07-sep (pedido Alejandro: "que el Modo Claro se vea más grisáceo"): la rampa baja OTRO escalón —
     fondo #d2d6dd→#c6cad1, superficie #e1e3e8→#d5d8dd, controles #d4d8df→#c8ccd3 — bordes y hover en proporción. */
  --bg:#c6cad1; --surface:#d5d8dd; --surface-2:#c8ccd3; --text:#1f2430; --muted:#464c5b;
  --border:#aab1bd; --border-hover:#8892a4; --accent:#ee8c2a; --accent-ink:#14181f; --violet:#33456e;
  --row-hover:#c2c7d1; --th-bg:#c7ccd6; --th-text:#33456e;
  --shadow-sm:0 1px 2px rgba(16,24,40,.08);
  --shadow-md:0 1px 2px rgba(16,24,40,.09),0 2px 8px rgba(16,24,40,.12);
  --shadow:var(--shadow-sm);
  --ok:#157347; --no:#b02a1e; --accent-text:#c2410c; --info:#156c8a; --focus:#33456e;
  /* Identidad de cada moneda (chips .cur-*). Tokens PROPIOS y no --ok/--accent: el verde del dólar
     no debe leerse como "correcto" ni el chip de una moneda como algo clicable (el naranja es la
     acción de marca). Por eso COP va en púrpura y no en ámbar. */
  --cur-usd:#0f7a4d; --cur-ves:#1f5fa8; --cur-cop:#6d3fa8;
  /* Botones (14-ago, decisión Alejandro): UN solo frame (el del "+Nuevo") y el color según la
     intención — naranja acción principal · slate acciones normales · rojo destructivas. */
  --btn-sec:#33456e; --btn-sec-hover:#3f5484; --btn-sec-ink:#fff;
  --btn-no-ink:#fff;
  /* Sistema de botones 05-sep (lienzo "Botones y Monedas": primario G Aurora + resto A Sólido con relieve):
     borde-filo del secundario, rampa clara del peligro y el brillo interior del nivel Sutil / chips. */
  --btn-sec-borde:#26365a; --no-claro:#c9372a; --no-borde:#8f2117; --sutil-brillo:rgba(255,255,255,.6); --inp-sombra:rgba(16,24,40,.08);
  --icon-1:#667085; --icon-2:#98a2b3;
  --ring:0 0 0 3px rgba(238,140,42,.20);
  --r-ctl:9px; --r-card:10px; --r-modal:14px;   /* 8→9 (05-sep, propuesta A) */
  /* (05-sep) IBM Plex Sans delante; Segoe UI queda de respaldo para los glifos que el subconjunto no trae. */
  --font-ui:'IBM Plex Sans',"Segoe UI Variable Text","Segoe UI",system-ui,-apple-system,sans-serif;
  --font-display:'IBM Plex Sans',"Segoe UI Variable Display","Segoe UI",system-ui,sans-serif;
  /* Encabezados/títulos en Poppins (pedido 2026-08-11: tipografía más notable y llamativa).
     La fuente YA viene empaquetada para el wordmark (600/700) — cero assets nuevos, offline igual. */
  --font-head:'Poppins',"Segoe UI Variable Display","Segoe UI",system-ui,sans-serif;
  --font-mono:"Cascadia Code",Consolas,monospace;
  color-scheme:light;
}
[data-theme="oscuro"]{
  --bg:#14161b; --surface:#1d2026; --surface-2:#252932; --text:#eceef2; --muted:#9aa3b2;
  --border:#343947; --border-hover:#4a5164; --accent:#ee8c2a; --accent-ink:#14161c; --violet:#93a7d4;
  --row-hover:#2a3040; --th-bg:#232e47; --th-text:#b9c6e4;
  --shadow-sm:0 1px 2px rgba(0,0,0,.35);
  --shadow-md:0 1px 2px rgba(0,0,0,.3),0 2px 10px rgba(0,0,0,.35);
  --ok:#34d399; --no:#f0655a; --accent-text:#f29b3f; --info:#6cc6e6; --focus:#93a7d4;
  --cur-usd:#3ddc97; --cur-ves:#7fb4f5; --cur-cop:#c3a2f5;
  --btn-sec:#3a4a6f; --btn-sec-hover:#485a85; --btn-sec-ink:#e8ecf5;
  --btn-no-ink:#14161c;
  --btn-sec-borde:#2c3a5c; --no-claro:#f47b71; --no-borde:#c94c42; --sutil-brillo:rgba(255,255,255,.06); --inp-sombra:rgba(0,0,0,.28);
  --icon-1:#8b94a6; --icon-2:#5f6779;
  --ring:0 0 0 3px rgba(242,155,63,.28);
  color-scheme:dark;
}

*{box-sizing:border-box}
html,body{margin:0;height:100%}
/* Base 15px (pedido 2026-08-11: fuentes más notables — antes 14px): sube TODO lo que hereda
   (tablas, inputs, botones) un escalón de visibilidad sin tocar la densidad de filas. */
body{font-family:var(--font-ui);background:var(--bg);color:var(--text);font-size:15px;line-height:1.45;-webkit-font-smoothing:antialiased}
/* Foco visible (solo navegación por teclado) con el slate de marca */
:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
::selection{background:rgba(238,140,42,.3)}
/* Controles nativos en paleta de marca (checks, radios, date-pickers, scrollbars vía color-scheme) */
input[type="checkbox"],input[type="radio"]{accent-color:var(--accent);width:15px;height:15px}
/* Microfeedback: transición uniforme de componentes interactivos */
.btn-primary,.btn-ghost,.btn-danger,.btn-tema,.chip,.toggle,.btn-edit,.btn-del,.inp,select.inp{transition:background-color .12s ease,border-color .12s ease,color .12s ease,box-shadow .12s ease}

/* Iconos mono de 16px (reemplazan emojis en botones/cromo) */
.ic16{width:16px;height:16px;fill:currentColor;vertical-align:-3px;margin-right:5px;flex:none}
.btn-edit .ic16,.btn-del .ic16{margin-right:0;vertical-align:-2px}
.vm-head .ic16{width:18px;height:18px;fill:#fff;margin-right:2px}

/* Buscador con lupa integrada */
.search-wrap{position:relative;display:inline-flex;flex:0 1 380px;min-width:220px}
.search-wrap .ic16{position:absolute;left:10px;top:50%;transform:translateY(-50%);margin:0;fill:var(--muted);pointer-events:none}
.search-wrap .inp{flex:1;width:100%;min-width:0;padding-left:32px}

/* Spinner de carga en el botón que disparó la petición HTMX */
button.htmx-request{pointer-events:none;opacity:.75}
button.htmx-request::after{content:"";display:inline-block;width:11px;height:11px;margin-left:7px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:ex-spin .6s linear infinite;vertical-align:-1px}
@keyframes ex-spin{to{transform:rotate(1turn)}}

/* Toasts (avisos flotantes; window.toast en app.js) */
.toast-host{position:fixed;right:18px;top:64px;z-index:60;display:flex;flex-direction:column;gap:8px}
.toast{background:var(--surface);border:1px solid var(--border);border-left:3px solid var(--ok);border-radius:var(--r-card);padding:10px 14px;font-size:14px;color:var(--text);box-shadow:var(--shadow-md);animation:toast-in .18s ease}
.toast.err{border-left-color:var(--no)}
@keyframes toast-in{from{opacity:0;transform:translateY(6px)}to{opacity:1}}

.app{display:flex;flex-direction:column;height:100vh}

/* Barra superior: mismo gradiente azul oscuro del INICIO (login/saludo) en todo el frame.
   Sobre ese fondo el texto va en blanco SIEMPRE — el gradiente es oscuro en tema claro y oscuro,
   así que estos colores se fijan aquí y no dependen de las variables del tema. Tamaños +10%. */
.appbar{display:flex;align-items:center;gap:14px;padding:9px 24px;border-bottom:1px solid rgba(255,255,255,.09);
  background:radial-gradient(1100px 700px at 75% -10%,#22335c 0%,#0c1730 60%,#0a1226 100%)}
.appbar-title{font-size:20px;margin:0;font-weight:600;letter-spacing:0;color:#fff;font-family:var(--font-head)}
/* El chip navy de la marca sobraba: el frame entero ya es navy. */
.brand{display:inline-flex;align-items:center;justify-content:center;background:transparent;border-radius:10px;padding:4px 2px}
.appbar .btn-tema{background:rgba(255,255,255,.10);color:#fff;border-color:rgba(255,255,255,.22)}
.appbar .btn-tema:hover{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.38)}
/* Pie del membrete (29-ago-2026, pedido Alejandro): nombre de ESTA caja + versión instalada, abajo a la derecha.
   El bloque derecho se estira a la altura del membrete: Salir arriba, el rótulo abajo, ambos pegados a la
   derecha. Mide lo mismo que el bloque de marca (33 + 4 + 11 = 48 px) → la barra no crece. Paleta del tagline. */
.appbar-der{display:flex;flex-direction:column;align-items:flex-end;justify-content:space-between;align-self:stretch;gap:4px}
.appbar-acc{display:flex;align-items:center;gap:6px}
/* Alternador de tema del membrete (09-sep, pedido Alejandro): SOLO en el teléfono; en la PC el tema se cambia en Ajustes.
   Muestra la luna en modo claro (lo que vas a activar) y el sol en modo oscuro. */
.tema-movil{display:none;padding:6px 8px}
.tema-movil .ic16{margin:0;vertical-align:-2px}
.tema-movil .tm-sun{display:none}
[data-theme="oscuro"] .tema-movil .tm-sun{display:inline}
[data-theme="oscuro"] .tema-movil .tm-moon{display:none}
.appbar-pie{display:inline-flex;align-items:baseline;gap:5px;font-family:var(--font-head);font-size:11px;line-height:1;white-space:nowrap;color:rgba(255,255,255,.5)}
.appbar-pie b{font-weight:600;color:#b9c6e4;letter-spacing:.04em}
.appbar-pie i{font-style:normal;color:rgba(255,255,255,.35)}
.appbar-pie .v{font-weight:600;letter-spacing:.02em}
.exlogo{display:inline-flex;align-items:flex-end;line-height:1}
.ex-exy{height:26px;width:auto;display:block}
/* 🛟 Aviso del SALVAVIDAS (20-sep-2026): «tienes trabajo sin aplicar aquí». Aparece arriba del
   formulario del módulo, nunca tapa nada y espera a que el usuario decida — restaurar por su
   cuenta sería otra forma de perderle el trabajo que tenga en pantalla. */
.borrador-aviso{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 12px;padding:10px 14px;
  background:rgba(238,140,42,.12);border:1px solid var(--accent);border-left-width:4px;border-radius:var(--r-card);
  font-size:13.5px;color:var(--text)}
.borrador-aviso .ba-ico{font-size:17px;line-height:1}
.borrador-aviso .ba-txt{flex:1;min-width:200px}
.borrador-aviso button{padding:5px 12px;font-size:13px}
.ex-nol{font-family:'Poppins',sans-serif;font-weight:600;font-size:22px;color:#E2882C;margin-left:2px;line-height:1;position:relative;top:-2px;display:inline-flex;align-items:flex-end}
/* La «o» del wordmark ES el símbolo de la Singularidad (Ruta 1 · Núcleo, elegida por Alejandro el
   19-sep-2026): núcleo macizo + órbita −24° + satélite posado. La caja mide 0,62em × 1em sobre el
   cuerpo de «nol», así que escala sola con el font-size — membrete (22px) y login (34px) sin un solo
   número por pantalla. overflow:visible porque la órbita desborda a propósito; los 0,085em de margen
   le dan aire ante la n y la l. El núcleo va siempre en el naranja de marca; órbita y satélite siguen
   al TEMA, salvo en la barra superior, que es navy en los dos. */
.ex-nol{--ex-orb:#5b6579;--ex-sat:#16264f}
[data-theme="oscuro"] .ex-nol{--ex-orb:#c4ccd8;--ex-sat:#f4f7fc}
.appbar .ex-nol{--ex-orb:#c4ccd8;--ex-sat:#f4f7fc}
.ex-o{width:.62em;height:1em;flex-shrink:0;margin:0 .085em;overflow:visible;display:block}
.ex-o-orb{stroke:var(--ex-orb)}
.ex-o-nuc{fill:#E2882C}
/* El satélite no se coloca con cx/cy sino con offset-path sobre la elipse completa (en unidades del
   viewBox, así que escala con el símbolo). En reposo va al 100 % del recorrido = posado arriba a la
   derecha. La capa .det va DETRÁS del núcleo y la .del DELANTE; en reposo manda la de delante. */
.ex-o-sat{fill:var(--ex-sat);offset-rotate:0deg;offset-distance:100%;
  offset-path:path('M68.46 40.92A41 15.5 -24 0 1 -6.46 74.28A41 15.5 -24 0 1 68.46 40.92')}
.ex-o-sat.det{opacity:0}
/* En la copia del destello el símbolo se blanquea como las letras (si no, la «o» se queda apagada
   mientras la banda de luz cruza el wordmark). */
.brillo-top .ex-o-nuc{fill:#fff3de}
.brillo-top .ex-o-orb{stroke:#fff}
.brillo-top .ex-o-sat{fill:#fff}
.ex-soft{font-family:'Poppins',sans-serif;font-weight:600;font-size:15px;color:#dbe4f7;margin-left:8px;letter-spacing:.01em;align-self:center;line-height:1}
.ex-erp{font-family:'Poppins',sans-serif;font-weight:700;font-size:12px;color:#fff;background:var(--accent);border-radius:5px;padding:2px 7px;margin-left:9px;letter-spacing:.05em;align-self:center}
/* Edición Exynol Lite: chip "LITE" junto al ERP, en el violeta del tagline ULTRACODE (el ERP ya es naranja); blanco sobre #9333ea 5,3:1 AA en ambos temas */
.ex-lite{font-family:'Poppins',sans-serif;font-weight:700;font-size:12px;color:#fff;background:#9333ea;border-radius:5px;padding:2px 7px;margin-left:6px;letter-spacing:.05em;align-self:center}
.brand-login{padding:20px;margin:0 0 6px}
.brand-login .ex-exy{height:40px}
.brand-login .ex-nol{font-size:34px;margin-left:3px;top:-3px}
.brand-login .ex-erp{font-size:15px;padding:2px 9px;margin-left:11px}
.brand-login .ex-lite{font-size:15px;padding:2px 9px;margin-left:8px}
/* PRESENTACIÓN del wordmark (20-sep-2026, la del lienzo «Logos y animaciones» que Alejandro aprobó):
   «Exy» se descubre, suben la n y la l, NACE el núcleo, se traza la órbita, el satélite da UNA vuelta y
   se posa, y entra el chip ERP. Corre UNA SOLA VEZ (no en bucle como en el lienzo) y solo en las
   pantallas de acceso: el splash ya tiene su propia animación de arranque y el membrete es un membrete.
   Los 6,5 s del lienzo se conservan como reloj de los porcentajes. */
.brand-login .ex-exy{animation:ex-p-exy 6.5s ease-out 1 both}
.brand-login .ex-n{animation:ex-p-n 6.5s ease-out 1 both}
.brand-login .ex-l{animation:ex-p-l 6.5s ease-out 1 both}
.brand-login .ex-o-nuc{animation:ex-p-nuc 6.5s ease-out 1 both;transform-box:fill-box;transform-origin:center}
.brand-login .ex-o-orb{animation:ex-p-orb 6.5s ease-in-out 1 both;stroke-dasharray:95.4}
.brand-login .ex-o-sat{animation:ex-p-sat 6.5s cubic-bezier(.45,0,.55,1) 1 both}
.brand-login .ex-o-sat.del{animation:ex-p-sat 6.5s cubic-bezier(.45,0,.55,1) 1 both,ex-p-del 6.5s linear 1 both}
.brand-login .ex-o-sat.det{animation:ex-p-sat 6.5s cubic-bezier(.45,0,.55,1) 1 both,ex-p-det 6.5s linear 1 both}
.brand-login .ex-erp,.brand-login .ex-lite{animation:ex-p-chip 6.5s ease-out 1 both}
@keyframes ex-p-exy{0%{clip-path:inset(0 100% 0 0)}11%,100%{clip-path:inset(0 0 0 0)}}
@keyframes ex-p-n{0%,7%{transform:translateY(.28em);opacity:0}15%,100%{transform:none;opacity:1}}
@keyframes ex-p-l{0%,11%{transform:translateY(.28em);opacity:0}19%,100%{transform:none;opacity:1}}
@keyframes ex-p-nuc{0%,12%{transform:scale(0)}20%{transform:scale(1.16)}25%,100%{transform:scale(1)}}
@keyframes ex-p-orb{0%,20%{stroke-dashoffset:95.4}40%,100%{stroke-dashoffset:0}}
@keyframes ex-p-sat{0%,22%{offset-distance:0%}56%,100%{offset-distance:100%}}
/* Las dos capas se turnan a media vuelta: delante en la primera mitad, detrás en la segunda, delante al posarse */
@keyframes ex-p-del{0%,21%{opacity:0}22%,39%{opacity:1}39.01%,55.99%{opacity:0}56%,100%{opacity:1}}
@keyframes ex-p-det{0%,39%{opacity:0}39.01%,55.99%{opacity:1}56%,100%{opacity:0}}
@keyframes ex-p-chip{0%,58%{opacity:0;transform:translateX(-10px)}68%,100%{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .brand-login .ex-exy,.brand-login .ex-n,.brand-login .ex-l,.brand-login .ex-o-nuc,
  .brand-login .ex-o-orb,.brand-login .ex-o-sat,.brand-login .ex-erp,.brand-login .ex-lite{animation:none}
  .brand-login .ex-o-orb{stroke-dasharray:none}
}
/* Tagline bajo el wordmark: "Impulsado por" en texto normal + SOLO "ULTRACODE" en pixel-art 3D
   (morado franco #c084fc/#9333ea). El alto del SVG manda; el ancho escala con el viewBox. */
.exbrand{display:inline-flex;flex-direction:column;align-items:center;gap:4px}
.ex-tag{display:inline-flex;align-items:center;gap:6px;line-height:0}
.ex-tag-txt{font-family:'Poppins',sans-serif;font-weight:600;font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:#b9c6e4;line-height:1}
.ex-tag-pix{display:block;line-height:0}
.ex-tag svg{display:block;height:10px;width:auto}
.brand-login .exbrand{gap:8px}
.brand-login .ex-tag{gap:8px}
.brand-login .ex-tag-txt{font-size:12px}
.brand-login .ex-tag svg{height:14px}
/* DESTELLO del wordmark (03-sep-2026, "Opción A · destello lineal" elegida por Alejandro en el lienzo
   Brillo Exynol): .brillo-base es el wordmark real; .brillo-top una copia en blanco apilada encima y
   recortada por una máscara en banda (105°) que barre de derecha a izquierda en el 11 % de un ciclo
   de 10 s (≈1,1 s de destello, 8,9 s de reposo). El brillo sigue las letras y los badges, no el fondo.
   Ambas capas repiten la columna flex del .exbrand para medir exactamente lo mismo. */
.exbrand{position:relative}
.brillo-base,.brillo-top{display:inline-flex;flex-direction:column;align-items:center;gap:4px}
.brand-login .brillo-base,.brand-login .brillo-top{gap:8px}
.brillo-top{position:absolute;inset:0;pointer-events:none;
  -webkit-mask:linear-gradient(105deg,transparent 42%,#000 50%,transparent 58%) 160% 0/260% 100% no-repeat;
  mask:linear-gradient(105deg,transparent 42%,#000 50%,transparent 58%) 160% 0/260% 100% no-repeat;
  animation:ex-destello 10s linear infinite}
.brillo-top .ex-exy{filter:brightness(1.9) saturate(.4)}
.brillo-top .ex-nol{color:#fff3de}
.brillo-top .ex-soft{color:#fff}
.brillo-top .ex-erp{background:#ffd6a8}
.brillo-top .ex-lite{background:#e9d5ff}
.brillo-top .ex-tag-txt{color:#fff}
.brillo-top .ex-tag svg g{fill:#e9d5ff}
@keyframes ex-destello{0%{-webkit-mask-position:160% 0;mask-position:160% 0}11%{-webkit-mask-position:-60% 0;mask-position:-60% 0}100%{-webkit-mask-position:-60% 0;mask-position:-60% 0}}
/* En las pantallas de acceso con TEMA CLARO la tarjeta es blanca y el "Exy" es oscuro: una copia
   blanqueada no brilla, se lava. Ahí el destello se apaga; en la barra (siempre navy) y en el tema
   oscuro sí corre. */
[data-theme="claro"] .brand-login .brillo-top{display:none}
@media (prefers-reduced-motion:reduce){.brillo-top,.med-glint{display:none}}
/* En tema claro las tarjetas de acceso (login/setup/licencia) son blancas: el texto baja a slate */
[data-theme="claro"] .login-wrap .ex-tag-txt{color:#5b6c94}

/* Launcher: banda horizontal de iconos grandes = navegación principal (reemplaza al sidebar) */
.launcher{display:flex;gap:4px;flex-wrap:wrap;align-items:flex-start;padding:6px 16px;background:var(--surface);border-bottom:1px solid var(--border)}
.tile{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:76px;padding:8px 10px;border-radius:var(--r-card);color:var(--text);text-decoration:none;border:1px solid transparent;transition:background .12s,border-color .12s}
.tile .ic{width:29px;height:29px;display:inline-flex;align-items:center;justify-content:center;flex:none}
.tile .ic svg{width:29px;height:29px;display:block;overflow:visible}
.tile .lbl{font-size:12px;font-weight:600;text-align:center;line-height:1.15;white-space:nowrap}
/* Iconos del launcher: monocromos en reposo (duotono de VALOR, no de matiz); el color aparece al hover/activo */
.ic-b{fill:var(--icon-1)}
.ic-a{fill:var(--icon-2)}
.tile:hover{background:var(--surface-2);border-color:var(--border)}
.tile:hover .ic-b{fill:var(--violet)}
.tile:hover .ic-a{fill:var(--accent)}
.tile.active{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
.tile.active .ic-b{fill:var(--accent-ink)}
/* Activo (29-ago-2026): acentos en BLANCO. Con tinta al 72 % sobre el cuerpo en tinta, las piezas interiores (flecha de
   Devoluciones, moneda de Cuentas, renglones de Ventas y Auditoría) desaparecían — lo notó Alejandro en la demo de gestos. */
.tile.active .ic-a{fill:rgba(255,255,255,.92)}

/* ── Gestos del launcher (29-ago-2026, pedido Alejandro: "una animación en cada icono de cada módulo al ser
   seleccionado"; eligió "gesto propio" sobre la variante uniforme — demo en exynol-negocio/launcher-gestos).
   Cada icono mueve las piezas que su propio dibujo sugiere; los ganchos son las clases por pieza de NAV_ICONS
   (layout.js). DISPARO: al ATERRIZAR — el tile llega con .active en la página nueva y la animación corre UNA vez.
   El launcher es su propio grupo de view-transition (más abajo), así que se queda quieto mientras el contenido se
   desliza; --g0 es el respiro para que el gesto arranque cuando esa transición (.27s) ya asentó. En el clic mismo,
   solo un acuse (:active encoge el icono). Solo transform/opacity: compositado, como el patrón Exy.
   transform-box:fill-box mide el origen sobre la propia pieza (bisagra de la tapa, base de la barra, centro de la
   órbita); el overflow:visible del svg (arriba) es porque la tapa gira y la moneda cae fuera del viewBox. */
.tile .gest{transform-box:fill-box;transform-origin:center}
.tile:active .ic{transform:scale(.9);transition:transform .08s}
@media (prefers-reduced-motion: no-preference){
  .tile.active{--g0:.2s;animation:g-pop .3s var(--g0) cubic-bezier(.2,.8,.3,1.15) both}
  .tile.active .vt-tk{animation:g-up .42s var(--g0) cubic-bezier(.2,.8,.3,1.15) both}
  .tile.active .vt-l1{transform-origin:0 50%;animation:g-print .26s calc(var(--g0) + .14s) ease-out both}
  .tile.active .vt-l2{transform-origin:0 50%;animation:g-print .26s calc(var(--g0) + .24s) ease-out both}
  .tile.active .inv-lid{transform-origin:0 100%;animation:g-lid .52s var(--g0) cubic-bezier(.2,.8,.3,1.1) both}
  .tile.active .cp-svg{animation:g-cart .48s var(--g0) cubic-bezier(.2,.8,.3,1.15) both}
  .tile.active .cp-w1{animation:g-wheel .48s calc(var(--g0) + .04s) ease-out both}
  .tile.active .cp-w2{animation:g-wheel .48s calc(var(--g0) + .12s) ease-out both}
  .tile.active .dv-arrow{animation:g-back .42s var(--g0) cubic-bezier(.2,.8,.3,1.2) both}
  .tile.active .cu-coin{animation:g-coin .62s var(--g0) ease-out both}
  .tile.active .cl-2{animation:g-arrive .38s var(--g0) cubic-bezier(.2,.8,.3,1.15) both}
  .tile.active .pv-svg{animation:g-truck .52s var(--g0) cubic-bezier(.2,.8,.3,1.15) both}
  .tile.active .pv-w1{animation:g-wheel .52s calc(var(--g0) + .06s) ease-out both}
  .tile.active .pv-w2{animation:g-wheel .52s calc(var(--g0) + .14s) ease-out both}
  .tile.active .rp-1{transform-origin:50% 100%;animation:g-grow .42s var(--g0) cubic-bezier(.2,.8,.3,1.2) both}
  .tile.active .rp-2{transform-origin:50% 100%;animation:g-grow .42s calc(var(--g0) + .09s) cubic-bezier(.2,.8,.3,1.2) both}
  .tile.active .rp-3{transform-origin:50% 100%;animation:g-grow .42s calc(var(--g0) + .18s) cubic-bezier(.2,.8,.3,1.2) both}
  .tile.active .mk-1{animation:g-tick-down .56s var(--g0) ease-in-out both}
  .tile.active .mk-2{animation:g-tick-up .56s calc(var(--g0) + .07s) ease-in-out both}
  .tile.active .mk-3{animation:g-tick-down .56s calc(var(--g0) + .14s) ease-in-out both}
  .tile.active .au-clip{animation:g-press .32s var(--g0) ease-out both}
  .tile.active .au-l1{transform-origin:0 50%;animation:g-print .24s calc(var(--g0) + .08s) ease-out both}
  .tile.active .au-l2{transform-origin:0 50%;animation:g-print .24s calc(var(--g0) + .2s) ease-out both}
  .tile.active .ai-orbit{animation:g-orbit .7s var(--g0) cubic-bezier(.3,.7,.3,1) both}
  .tile.active .ai-core{animation:g-pulse .7s var(--g0) ease-in-out both}
  .tile.active .cf-k1{animation:g-knob-r .48s var(--g0) ease-in-out both}
  .tile.active .cf-k2{animation:g-knob-l .48s calc(var(--g0) + .07s) ease-in-out both}
  .tile.active .cf-k3{animation:g-knob-r .48s calc(var(--g0) + .14s) ease-in-out both}
}
@keyframes g-pop{0%{transform:scale(1)}40%{transform:scale(1.05)}100%{transform:scale(1)}}
@keyframes g-up{0%{transform:translateY(5px);opacity:.55}100%{transform:none;opacity:1}}
@keyframes g-print{0%{transform:scaleX(0)}100%{transform:scaleX(1)}}
@keyframes g-lid{0%{transform:rotate(0)}42%{transform:rotate(-22deg)}100%{transform:rotate(0)}}
@keyframes g-cart{0%{transform:translateX(-3px) rotate(-4deg)}60%{transform:translateX(.8px) rotate(1deg)}100%{transform:none}}
@keyframes g-wheel{0%{transform:none}45%{transform:translateY(-1.6px)}100%{transform:none}}
@keyframes g-back{0%{transform:none}45%{transform:translateX(-4.5px)}80%{transform:translateX(.9px)}100%{transform:none}}
@keyframes g-coin{0%{transform:translateY(-8px) scaleX(.15);opacity:0}30%{transform:translateY(-4px) scaleX(1);opacity:1}48%{transform:translateY(-1px) scaleX(.2)}66%{transform:translateY(1.3px) scaleX(1)}82%{transform:translateY(-.6px) scaleX(.85)}100%{transform:none}}
@keyframes g-arrive{0%{transform:translateX(5px);opacity:0}100%{transform:none;opacity:1}}
@keyframes g-truck{0%{transform:translateX(-4px)}65%{transform:translateX(1px)}100%{transform:none}}
@keyframes g-grow{0%{transform:scaleY(0)}100%{transform:scaleY(1)}}
@keyframes g-tick-up{0%{transform:none}50%{transform:translateY(-2.4px)}100%{transform:none}}
@keyframes g-tick-down{0%{transform:none}50%{transform:translateY(2px)}100%{transform:none}}
@keyframes g-press{0%{transform:translateY(-1.6px)}60%{transform:translateY(.4px)}100%{transform:none}}
@keyframes g-orbit{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
@keyframes g-pulse{0%{transform:scale(1)}45%{transform:scale(1.32)}100%{transform:scale(1)}}
@keyframes g-knob-r{0%{transform:none}50%{transform:translateX(4px)}100%{transform:none}}
@keyframes g-knob-l{0%{transform:none}50%{transform:translateX(-4px)}100%{transform:none}}

.spacer{flex:1}
.btn-tema{background:var(--btn-sec);color:var(--btn-sec-ink);border:none;border-radius:var(--r-ctl);padding:8px 16px;cursor:pointer;font-size:14px;font-weight:600}
.btn-tema:hover{background:var(--btn-sec-hover)}
/* Selector de tema (Claro/Oscuro) en Configuración */
.tema-opts{display:inline-flex;gap:8px}
.btn-tema.active{background:var(--accent);color:var(--accent-ink);border-color:var(--accent);font-weight:600}

.content{flex:1;padding:16px 22px;overflow:auto}
.toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap;min-height:38px}
/* Los buscadores de toolbar no se estiran a pantalla completa */
.toolbar .inp.grow,.toolbar input[type="search"]{flex:0 1 380px;min-width:220px}
/* Celdas de rango de fechas del toolbar (Ventas): etiqueta al lado, compactas */
.tb-fecha{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);white-space:nowrap}
.tb-fecha .inp{width:140px}
.chips{display:flex;gap:6px;flex-wrap:wrap}
.chip{background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:6px 14px;cursor:pointer;color:var(--text);font-size:13.5px;font-weight:600;box-shadow:inset 0 1px 0 var(--sutil-brillo)}
.chip:hover{border-color:var(--border-hover)}
.chip.active{background:var(--violet);color:#fff;border-color:var(--violet);box-shadow:inset 0 1px 0 rgba(255,255,255,.18)}
[data-theme="oscuro"] .chip.active{color:#14161b}
/* ─── BOTONES (05-sep-2026, decisión de Alejandro en el lienzo "Botones y Monedas"): PRIMARIO de la propuesta G
   "Aurora" — degradado naranja→coral de la marca (el del header de la Caja y Exynol AI) que se desplaza al pasar,
   con halo del mismo color — y el RESTO de la propuesta A "Sólido con relieve": secundario slate con brillo
   arriba y sombra corta, nivel SUTIL para lo neutro (Cancelar/Limpiar/Cerrar/Quitar/No), peligro con relieve.
   Todos llevan borde de 1px (transparente en el primario) y padding 7/15 en vez de 8/16: mismo tamaño exterior
   que antes, así ninguna fila ni pie se mueve. */
.btn-primary{background-color:var(--accent);background-image:linear-gradient(115deg,#ffa53f 0%,#ee8c2a 45%,#f2705a 100%);background-size:200% 100%;background-position:0 0;color:var(--accent-ink);border:1px solid transparent;border-radius:var(--r-ctl);padding:7px 15px;font-weight:600;cursor:pointer;box-shadow:0 4px 12px rgba(238,140,42,.32);transition:background-position .25s ease,box-shadow .14s ease,transform .08s ease,color .12s ease}
.btn-primary:hover{background-position:100% 0;box-shadow:0 6px 16px rgba(242,112,90,.38)}
.btn-primary:active{transform:translateY(1px);box-shadow:0 2px 6px rgba(238,140,42,.35)}
.btn-primary:disabled{background-image:none;background-color:var(--border);color:var(--muted);opacity:1;cursor:not-allowed;box-shadow:none;transform:none}

.grid{width:100%;border-collapse:collapse;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);overflow:hidden;box-shadow:var(--shadow)}
/* Reportes → Existencias por umbral: checkboxes Ver mínimos / promedios / máximos (pedido 03-ago) */
.rep-chks{display:inline-flex;gap:8px;align-items:center;padding:5px 8px;border:1px solid var(--border);border-radius:var(--r-ctl);background:var(--surface)}
.rep-chk{display:inline-flex;gap:6px;align-items:center;font-size:14px;font-weight:600;cursor:pointer;white-space:nowrap;padding:3px 10px;border-radius:999px}
.rep-chk input{margin:0;cursor:pointer}
/* Cada casilla pintada con su banda (pedido 06-ago): Mín roja · Prom amarilla · Máx verde —
   la misma paleta del editor de producto; pastel pleno en claro, translúcido en oscuro. */
.rep-chk-minimo{background:#ffc7ce;color:#9c0006}
.rep-chk-promedio{background:#fff9b2;color:#9c8000}
.rep-chk-maximo{background:#c6efce;color:#006100}
.rep-chk-minimo input{accent-color:#9c0006}
.rep-chk-promedio input{accent-color:#9c8000}
.rep-chk-maximo input{accent-color:#006100}
[data-theme="oscuro"] .rep-chk-minimo{background:rgba(156,0,6,.38);color:#ffb3ba}
[data-theme="oscuro"] .rep-chk-promedio{background:rgba(156,128,0,.33);color:#ffe98a}
[data-theme="oscuro"] .rep-chk-maximo{background:rgba(0,97,0,.38);color:#8ee6a8}
[data-theme="oscuro"] .rep-chk-minimo input{accent-color:#ffb3ba}
[data-theme="oscuro"] .rep-chk-promedio input{accent-color:#ffe98a}
[data-theme="oscuro"] .rep-chk-maximo input{accent-color:#8ee6a8}

/* Inventario (pedido 03-ago): el nombre del producto NUNCA se parte en varias líneas — cada fila
   es una sola línea y la tabla scrollea horizontal dentro de su contenedor si no cabe.
   El wrapper vive FUERA de #tabla (los swaps htmx reemplazan la tabla, el scroll sobrevive). */
/* 04-sep (rendimiento): el "chrome" de tarjeta (borde, radio, sombra) va en el WRAPPER y no en la
   tabla: border-radius + overflow:hidden sobre una tabla de 873 filas obligaba a recortar toda la tabla
   en cada paso de scroll (200 ms por frame medidos; 50 ms sin ese recorte). El wrapper ya recorta por
   ser el scroller, así que el resultado visual es el mismo. */
.tabla-scroll{overflow-x:auto;border:1px solid var(--border);border-radius:var(--r-card);box-shadow:var(--shadow);background:var(--surface)}
.tabla-scroll .grid{width:max-content;min-width:100%;border:0;border-radius:0;box-shadow:none;overflow:visible}
/* Centinela de la carga por tandas del inventario (#inv-mas): una fila discreta con un giro. */
.inv-mas td{text-align:center;color:var(--muted);font-size:13px;padding:10px 12px}
.inv-giro{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:-2px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:inv-giro .8s linear infinite}
@keyframes inv-giro{to{transform:rotate(360deg)}}
.tabla-scroll .grid th,.tabla-scroll .grid td{white-space:nowrap}
/* Barra horizontal FLOTANTE de la tabla del inventario (03-sep, pedido Alejandro; corregido el mismo día:
   la quería en la ZONA INFERIOR, no arriba): con 870 fichas la barra nativa queda al final de la tabla;
   esta réplica va justo DEBAJO de la tabla con position:sticky; bottom:0 → mientras la tabla siga más
   abajo se queda pegada al borde inferior de la pantalla y, al llegar al final, se acomoda en su sitio.
   Sincronizada con la real en los dos sentidos (app.js invScrollBarra). Solo aparece si la tabla
   desborda a lo ancho; entonces la barra nativa del wrapper se oculta (no dos barras al final). */
/* 04-sep (pedido Alejandro: "que se integre un frame en esa parte inferior únicamente para la barra"):
   la barra ya no flota como una línea encima de las filas; va dentro de un MARCO propio, un dock opaco
   pegado al borde inferior del área de contenido, a todo el ancho (los márgenes negativos son el
   padding de .content), con sombra hacia arriba, rótulo a la izquierda y la pista de scroll a la
   derecha (pulgar grueso y redondeado; naranja al pasar el mouse). Al final de la tabla se acomoda en
   su sitio (sticky). El JS lo muestra con display:flex solo si la tabla desborda. bottom:-16px porque el
   sticky se mide contra la caja de contenido de .content y su padding inferior es 16px: con 0 quedaba
   una franja de 16px por debajo del marco con filas asomando. */
.tabla-scroll-fija{position:sticky;bottom:-16px;z-index:3;display:none;align-items:center;gap:14px;margin:10px -22px -16px;padding:8px 22px;background:var(--surface);border-top:1px solid var(--border);box-shadow:0 -8px 18px rgba(0,0,0,.10)}
[data-theme="oscuro"] .tabla-scroll-fija{box-shadow:0 -8px 18px rgba(0,0,0,.4)}
.tsf-rotulo{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;letter-spacing:.2px;color:var(--muted);white-space:nowrap;user-select:none}
.tsf-track{flex:1;min-width:0;overflow-x:auto;overflow-y:hidden;height:14px;border-radius:7px}
.tsf-track>div{height:1px}
.tsf-track::-webkit-scrollbar{height:14px}
.tsf-track::-webkit-scrollbar-track{background:var(--surface-2);border:1px solid var(--border);border-radius:7px}
.tsf-track::-webkit-scrollbar-thumb{background:var(--muted);border:3px solid var(--surface-2);border-radius:7px}
.tsf-track::-webkit-scrollbar-thumb:hover{background:var(--accent)}
.tabla-scroll.sin-barra{scrollbar-width:none}
.tabla-scroll.sin-barra::-webkit-scrollbar{display:none}

/* Header de tabla: tinte suave + texto de marca (adiós bloque morado sólido) */
.grid th{background:var(--th-bg);color:var(--th-text);text-align:left;padding:8px 12px;font-size:12.5px;text-transform:uppercase;letter-spacing:.04em;font-weight:700;border-bottom:2px solid var(--violet);font-family:var(--font-head)}
/* Lupa de autofiltro por columna (Inventario, pedido 06-ago — como el autofiltro del Excel).
   El input hereda el uppercase del th → se resetea; con filtro activo la lupa tinta de violeta. */
.th-flt{display:inline-flex;align-items:center;gap:5px}
.th-lupa{background:none;border:none;padding:0;cursor:pointer;color:inherit;opacity:.45;line-height:0}
.th-lupa:hover{opacity:1}
.th-flt.on .th-lupa{opacity:1;color:var(--violet)}
.th-lupa .ic16{width:13px;height:13px}
.th-filtro{font-size:12px;padding:3px 7px;min-width:110px;max-width:160px;font-weight:400;text-transform:none;letter-spacing:normal}
/* Menú de autofiltro tipo Excel en los encabezados del inventario (04-sep, pedido Alejandro). Vive fuera
   de la tabla (#th-menu, position:fixed) y se arma por JS para la columna pulsada. */
.th-lbl{white-space:nowrap}
.th-ord{font-size:9px;color:var(--accent-text);margin-left:1px}
.th-flt.sorted .th-lbl{color:var(--accent-text)}
.th-menu{position:fixed;z-index:60;width:290px;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);box-shadow:var(--shadow-md);padding:6px;font-size:13px;font-weight:400;text-transform:none;letter-spacing:normal;color:var(--text);font-family:var(--font-ui)}
.thm-tit{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);padding:4px 8px 6px}
.thm-it{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:0;padding:6px 8px;border-radius:6px;cursor:pointer;color:var(--text);font:inherit}
.thm-it:hover{background:var(--surface-2)}
.thm-it.on{color:var(--accent-text);font-weight:600}
.thm-ic{width:14px;text-align:center;font-size:11px;color:var(--muted);flex:none}
.thm-it.on .thm-ic{color:var(--accent-text)}
.thm-sep{border-top:1px solid var(--border);margin:6px 0}
.thm-buscar{width:100%;font-size:13px;padding:5px 8px;margin-bottom:6px;font-weight:400;text-transform:none;letter-spacing:normal}
.th-menu[hidden]{display:none}
.thm-lista{flex:0 1 auto;min-height:60px;max-height:260px;overflow:auto;padding:2px 4px}
.thm-lista label{display:flex;gap:8px;align-items:center;padding:3px 4px;border-radius:5px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.thm-lista label:hover{background:var(--surface-2)}
.thm-lista label.todo{font-weight:600;border-bottom:1px dashed var(--border);border-radius:0;margin-bottom:3px;padding-bottom:5px}
.thm-lista input[type="checkbox"]{flex:none;margin:0}
.thm-mas{color:var(--muted);font-size:12px;padding:6px 8px}
.grid td{padding:6px 12px;border-top:1px solid var(--border)}
/* Anchos gobernados: columnas de contenido acotado fijas, la columna elástica (Nombre) absorbe el resto */
.grid th.c-xs{width:80px}
.grid th.c-sm{width:110px}
.grid th.c-md{width:150px}
.grid th.c-lg{width:200px}
.grid td.num,.grid th.num{white-space:nowrap}
/* Números de tabla con peso medio (pedido tipografía 2026-08-11): las cifras son lo que el ojo
   busca en un ERP — medio paso más de grosor las levanta sin gritar como una negrita plena. */
.grid td.num{font-weight:500;font-variant-numeric:tabular-nums}
.grid tbody tr:hover{background:var(--row-hover)}
.grid .num{text-align:right;font-variant-numeric:tabular-nums}
.grid .mono{font-family:var(--font-mono);color:var(--muted);font-size:13px}
.grid .nombre{font-weight:600}
.grid tfoot td{border-top:1px solid var(--border);background:var(--surface)}

.muted{color:var(--muted)}
.ok{color:var(--ok);font-weight:600}
.no{color:var(--no);font-weight:600}
/* Estado vacío rico: icono del módulo atenuado + título + pista */
.vacio{text-align:center;color:var(--muted);padding:44px 20px}
.vacio .vz-ic{display:block;margin:0 auto 10px}
.vacio .vz-ic svg{width:40px;height:40px;opacity:.45}
.vacio .vz-ic .ic-b{fill:var(--icon-1)}
.vacio .vz-ic .ic-a{fill:var(--icon-2)}
.vacio b{display:block;color:var(--text);font-size:14px;margin-bottom:2px}
.badge{display:inline-block;padding:2px 9px;border-radius:20px;font-size:11px;font-weight:700;border:1px solid transparent}
.b-prod{background:color-mix(in srgb,var(--violet) 14%,transparent);color:var(--violet);border-color:color-mix(in srgb,var(--violet) 28%,transparent)}
.b-serv{background:rgba(37,150,190,.16);color:var(--info);border-color:rgba(37,150,190,.3)}
.b-com{background:rgba(238,140,42,.12);color:var(--accent-text);border-color:rgba(238,140,42,.3)}
.tabla-foot{color:var(--muted);font-size:11px}
.tabla-foot .hint{float:right;opacity:.7}
code{background:var(--surface-2);padding:2px 6px;border-radius:5px}

/* --- Edición inline estilo Excel --- */
.cell{cursor:pointer;position:relative}
.cell:hover{box-shadow:inset 0 0 0 2px var(--accent)}
td.editing{padding:2px 6px}
.cell-input{width:100%;box-sizing:border-box;border:1px solid var(--accent);border-radius:5px;padding:4px 8px;background:var(--surface);color:var(--text);font:inherit}
.cell-input:focus{outline:none;box-shadow:var(--ring)}
.num .cell-input{text-align:right}
/* Lector vivo bajo el input de un precio gravable: "= 116,00 con I.V.A." mientras se teclea la base.
   position:absolute para NO alterar la altura de la fila (el ancho uniforme de fila es un requisito). */
td.editing{position:relative}
.cell-hint{position:absolute;right:6px;top:100%;z-index:5;margin-top:2px;padding:2px 7px;border-radius:5px;
  background:var(--surface-2);border:1px solid var(--border);color:var(--muted);font-size:11px;white-space:nowrap;
  box-shadow:0 4px 12px rgba(0,0,0,.16)}

/* Precio de MOSTRADOR (I.V.A. incluido) en el inventario: marca discreta que distingue un gravable de
   un exento sin robar ancho ni partir la fila en dos líneas. El número sigue siendo el único grande.
   line-height:0 + top en vez de vertical-align:super — "super" AGRANDA la caja de línea y dejaba las
   filas gravables 1px más altas que las exentas (la altura uniforme de fila es un requisito). */
/* ⚠️ El content va en DOS strings: "\00a0c/IVA" en uno solo hacía que la 'c' se consumiera como
   sexto dígito HEX del escape (\00a0c = U+0A0C, un carácter gurmukhi) → se renderizaba "□/IVA"
   con tofu. Bug cosmético preexistente cazado en la tanda tipográfica 2026-08-11. */
.pv-iva::after{content:"\00a0" "c/IVA";font-size:10px;font-weight:600;letter-spacing:.02em;color:var(--muted);
  position:relative;top:-.45em;line-height:0;opacity:.85}

/* Toggle de estado (Disponible/Agotado, Activo/Inactivo): punto-semáforo + anillo al hover = "soy un botón" */
.toggle{position:relative;border:none;border-radius:20px;padding:3px 11px 3px 21px;font-weight:600;font-size:12px;cursor:pointer}
.toggle::before{content:"";position:absolute;left:9px;top:50%;margin-top:-3px;width:6px;height:6px;border-radius:50%;background:currentColor}
.toggle:hover{box-shadow:inset 0 0 0 1px currentColor;filter:none}
.toggle.on{background:rgba(25,135,84,.16);color:var(--ok)}
.toggle.off{background:rgba(192,57,43,.16);color:var(--no)}
/* En oscuro las alfas calculadas para fondo blanco sobresaturan: bajarlas */
[data-theme="oscuro"] .toggle.on{background:rgba(52,211,153,.13)}
[data-theme="oscuro"] .toggle.off{background:rgba(240,101,90,.13)}
.toggle:hover{filter:brightness(1.08)}

/* Acciones por fila: lado a lado (apiladas duplicaban la altura de la fila) */
.acciones{text-align:center;width:72px;white-space:nowrap}
.btn-del{background:transparent;border:none;cursor:pointer;font-size:13px;opacity:.55;border-radius:6px;padding:3px 6px;line-height:1}
.btn-del:hover{opacity:1;background:rgba(192,57,43,.14)}
.btn-edit{background:transparent;border:none;cursor:pointer;font-size:13px;opacity:.55;border-radius:6px;padding:3px 6px;line-height:1}
.btn-edit:hover{opacity:1;background:rgba(238,140,42,.16)}

/* Editor de producto (UserForm) */
.prod-modal{width:min(860px,96vw)}
/* El editor DEBE poder scrollear (el .vm-body genérico esconde el overflow — en pantallas bajas las
   casillas de abajo quedaban inalcanzables, pedido Alejandro 2026-08-01) + botón ⛶ para maximizar. */
.prod-modal .vm-body{overflow-y:auto}
/* Umbrales de existencia SIEMPRE coloreados con su banda (Mínima roja · Promedio/Reorden amarillas ·
   Máxima verde), número incluido. Variantes translúcidas en tema oscuro (el pastel pleno ciega). */
.prod-modal .inp.exist-min{background:#ffc7ce;color:#9c0006;font-weight:600}
.prod-modal .inp.exist-prom{background:#fff9b2;color:#9c8000;font-weight:600}
.prod-modal .inp.exist-max{background:#c6efce;color:#006100;font-weight:600}
[data-theme="oscuro"] .prod-modal .inp.exist-min{background:rgba(156,0,6,.38);color:#ffb3ba}
[data-theme="oscuro"] .prod-modal .inp.exist-prom{background:rgba(156,128,0,.33);color:#ffe98a}
[data-theme="oscuro"] .prod-modal .inp.exist-max{background:rgba(0,97,0,.38);color:#8ee6a8}
/* Imagen referencial: preview en el editor + espacio en la Caja */
.prod-img-prev{width:126px;height:126px;object-fit:contain;border:1px solid var(--border);border-radius:var(--r-card);background:#fff;flex:none}
.prod-img-prev.sin-img{background:var(--surface-2);border-style:dashed}
/* Captura arriba (no centrada): las celdas quedan a la par del tope de la imagen (ajuste 03-jul) */
.v-add-wrap{display:flex;gap:14px;align-items:flex-start}
.v-add-rows{flex:1;min-width:0}
/* Imagen referencial en la Caja: CUADRADA y protagonista. El margen negativo la sube a la franja
   del título "Agregar producto" para que las líneas del segmento queden casi a ras del cuadro. */
.v-img-box{width:160px;height:160px;flex:none;display:flex;align-items:center;justify-content:center;border:1px dashed var(--border);border-radius:var(--r-card);background:var(--surface-2);overflow:hidden;margin-top:-27px}
/* Fila ÚNICA de captura: Artículo elástico (la celda más larga), el resto compacto para que
   TODO quepa en una línea incluso con el selector "Vender" visible (fraccionables). */
.v-add-linea{gap:6px}
.v-add-linea .btn-primary,.v-add-linea .btn-ghost{padding-left:11px;padding-right:11px}
.v-fld-art{flex:999 1 240px;min-width:220px}
/* El <select> de Artículo llena TODA la celda (por defecto se dimensiona por su contenido) →
   la celda se ve realmente larga y el borde del botón "+ Nuevo Producto" calza con el del select */
.v-fld-art #producto-wrap,.v-fld-art #cproducto-wrap{display:block;width:100%}
.v-fld-art #producto-wrap select,.v-fld-art #cproducto-wrap select{width:100%}
/* ─── COMBO DE ARTÍCULO PROPIO de la Caja (05-sep): el <select> #v-producto queda como estado oculto (1×1, sin
   opacidad: Playwright y el escáner lo siguen viendo) y el combo .v-combo pinta nombre + cápsula «N Exist.» ─── */
.v-fld-art #producto-wrap,.v-fld-art #cproducto-wrap{position:absolute;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;left:0;bottom:0}
.v-fld-art{position:relative}
.v-combo{position:relative;width:100%}
.v-combo-btn{width:100%;display:flex;align-items:center;gap:8px;text-align:left;cursor:pointer;padding-right:28px;position:relative;font-weight:600;font:inherit;font-weight:600}
.v-combo-btn .v-combo-txt{flex:1;min-width:0;display:flex;align-items:center;gap:8px;overflow:hidden}
.v-combo-nom{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.v-combo-chev{position:absolute;right:10px;top:50%;transform:translateY(-50%);color:#999;font-size:12px;line-height:1}
.v-combo-list{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:30;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);box-shadow:var(--shadow-md);padding:6px;display:flex;flex-direction:column;gap:6px;min-width:min(640px,calc(100vw - 48px))}
.v-combo-list[hidden]{display:none}
.v-combo-q{width:100%;height:32px;font-weight:400}
/* Búsqueda Alfabética | Coincidente (05-sep): alternador junto a cada buscador y sombreado de lo buscado */
.v-combo-top{display:flex;align-items:center;gap:6px}
.v-combo-top .v-combo-q{flex:1;width:auto;min-width:0}
.seg-bus{flex:none}
.seg-bus button{padding:3px 8px;font-size:11.5px}
mark.hl{background:color-mix(in srgb,var(--accent) 40%,transparent);color:inherit;border-radius:3px;padding:0 1px}
.v-combo-items{max-height:min(46vh,380px);overflow:auto}
.v-combo-it{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 8px;border-radius:7px;cursor:pointer;font-size:14px}
.v-combo-it:hover,.v-combo-it.sel{background:var(--row-hover)}
.v-combo-it.off{opacity:.5;cursor:not-allowed}
.v-combo-it .cat-stock{flex:none}
.v-combo-vacio{padding:10px;color:var(--muted);font-size:13px}
.v-combo-tipo{flex:none;font-size:11px;font-weight:600;color:var(--muted);border:1px solid var(--border);border-radius:999px;padding:1px 8px;text-transform:capitalize}
.fn-row .v-combo-btn{height:34px}
.v-lbl-row{display:flex;align-items:flex-end;gap:10px;width:100%}
.v-lbl-row .btn-primary{margin-left:auto;height:22px;padding:1px 10px;font-size:11px;display:inline-flex;align-items:center;white-space:nowrap;box-shadow:0 2px 5px rgba(238,140,42,.3)}
.v-add-linea .inp.num{width:82px}
.v-add-linea .inp-cod{width:114px}
.v-add-linea #v-inv-filtro{width:112px;padding-left:8px;padding-right:22px;background-position:right 7px center}
/* Tarifa: el valor centrado en la celda (P.V.P / P.V.M), con el chevron más pegado al borde */
.v-add-linea #v-tarifa{width:76px;text-align:center;text-align-last:center;padding-left:8px;padding-right:24px;background-position:right 7px center}
.v-add-linea #v-tipoventa{width:92px}
/* Compras: Costo actual / Costo promedio (solo lectura). Sin existencia previa el promedio "arranca" en
   esta compra: borde punteado como seña (el title lo explica). */
.v-add-linea #l-costo-act,.v-add-linea #l-costo-prom{width:96px}
#l-costo-prom.c-prom-arranca{border-style:dashed}
.v-add-linea .disp-hint{min-width:0;font-size:11px;align-self:auto}
.v-img-box img{display:none;max-width:100%;max-height:100%;object-fit:contain;background:#fff}
.v-img-box.con-img{border-style:solid;background:#fff}
.v-img-box.con-img img{display:block}
.v-img-box.con-img #v-img-ph{display:none}
#v-img-ph{font-size:11px;text-align:center;padding:4px}
.prod-modal .vm-body #prod-msg:not(:empty){margin:0 20px 8px}
.prod-modal .fld .inp.num{width:120px}

/* Formulario de alta (+ Nuevo) */
.form-nuevo{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:14px;margin-bottom:14px;box-shadow:var(--shadow-md)}
/* flex-end: inputs con label y botones sin label comparten la LÍNEA BASE (nada flota a media altura) */
.fn-row{display:flex;gap:8px;align-items:flex-end;flex-wrap:wrap;row-gap:10px}
.fn-row .inp,.fn-row select.inp{height:34px}
.fn-row .btn-primary,.fn-row .btn-ghost{height:34px;display:inline-flex;align-items:center}
.vm-sec .fn-row + .fn-row{margin-top:10px}
.inp{background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-ctl);padding:8px 10px;color:var(--text);font:inherit;box-shadow:inset 0 1px 2px var(--inp-sombra)}
.inp:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.inp::placeholder{color:var(--muted);opacity:1}
.inp.grow{flex:1;min-width:180px}
.inp.num{width:110px;text-align:right}
/* Selects (comboboxes) con aspecto de botón: borde definido, chevron propio, hover de marca */
select.inp{appearance:none;-webkit-appearance:none;cursor:pointer;font-weight:600;padding-right:30px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat:no-repeat;background-position:right 10px center}
select.inp:hover{border-color:var(--border-hover)}
select.inp:focus{border-color:var(--accent);box-shadow:var(--ring)}
.inp:disabled{opacity:.45;cursor:not-allowed}

/* Pantalla de Configuración: grid de cards en 2 columnas (adiós media pantalla vacía) */
/* Ajustes en ACORDEÓN (11-sep-2026, opción C del lienzo «Ajustes reagrupado» de Alejandro): UNA columna a todo lo ancho,
   cinco grupos con índice pegado arriba, cada frame es un <details> con cabecera (título · resumen · chevron) y mide lo
   que su contenido; los campos del form en rejilla de tres con la ayuda debajo; Guardar pegado abajo. */
.cfg-page{display:flex;flex-direction:column;gap:12px;max-width:none}
.cfg-form{display:contents}
.cfg-nav{display:flex;gap:8px;flex-wrap:wrap;position:sticky;top:-16px;z-index:5;background:var(--bg);padding:16px 0 10px;margin:-16px 0 -2px}
.cfg-nav .chip{padding:5px 13px;font-size:13px;text-decoration:none}
.cfg-grupo{font-family:var(--font-head);font-weight:700;font-size:12.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin:10px 0 -2px 2px;display:flex;align-items:center;gap:10px;scroll-margin-top:64px}
.cfg-grupo::after{content:"";flex:1;height:1px;background:var(--border)}
.cfg-acc-item{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);box-shadow:var(--shadow-md);min-width:0}
.cfg-acc-item>summary{list-style:none;display:flex;align-items:center;gap:14px;padding:12px 18px;cursor:pointer;user-select:none;border-radius:var(--r-card)}
.cfg-acc-item>summary::-webkit-details-marker{display:none}
.cfg-acc-item>summary:hover{background:var(--row-hover)}
.cfg-acc-item>summary .vm-sec-t{margin:0;flex:none;min-width:250px}
.cfg-acc-item .acc-res{flex:1;min-width:0;font-size:13px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cfg-acc-item .acc-chev{flex:none;color:var(--muted);display:flex;transition:transform .15s}
.cfg-acc-item[open]>summary .acc-chev{transform:rotate(180deg)}
.cfg-acc-item[open]>summary{border-bottom:1px solid var(--border);border-radius:var(--r-card) var(--r-card) 0 0}
.cfg-acc-item.acc-animando{will-change:height}
.cfg-acc-item .acc-chev{transition:transform .24s cubic-bezier(.2,.7,.2,1)}
.cfg-acc-item .cfg-card,.cfg-acc-item>div>.cfg-card{border:0;box-shadow:none;border-radius:0;background:transparent;padding:12px 18px 16px}
.cfg-acc-item .cfg-card>.vm-sec-t{display:none}
.cfg-filas{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px 24px;align-items:start}
.cfg-filas.dos{grid-template-columns:repeat(2,minmax(0,1fr))}
.cfg-filas .fld-row{display:flex;flex-direction:column;align-items:stretch;gap:5px;margin:0}
.cfg-filas .fld-row>span:first-child{font-size:12.5px;font-weight:600}
.cfg-filas .fld-row.ancho{grid-column:1/-1}
.fld-help{font-size:12px;color:var(--muted);line-height:1.35}
.cfg-nota{margin:10px 0 0;font-size:13px;color:var(--muted);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.cfg-acc .cfg-card .fld-row>.btn-primary,.cfg-acc .cfg-card .fld-row>.btn-ghost,.cfg-acc .cfg-card .fld-row>.btn-danger{justify-self:start}
.cfg-acc .cfg-card .fld-row>.inp{max-width:560px}
.cfg-dos-col{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 28px;align-items:start}
@media (max-width:900px){.cfg-filas,.cfg-filas.dos,.cfg-dos-col{grid-template-columns:1fr}.cfg-acc-item .acc-res{display:none}.cfg-acc-item>summary .vm-sec-t{min-width:0}}
.cfg-grid{display:flex;flex-direction:column;gap:16px;min-width:0}
.cfg-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:16px 18px;box-shadow:var(--shadow-md);margin:0;min-width:0}
.cfg-card .vm-sec-t{margin-bottom:10px}
.cfg-actions{position:sticky;bottom:-16px;z-index:5;display:flex;justify-content:flex-end;gap:8px;padding:10px 0 16px;background:linear-gradient(to top,var(--bg) 75%,transparent);margin:0 0 -16px}
.cfg-msg{margin:0}
.fld-row{display:grid;grid-template-columns:180px 1fr;align-items:center;gap:12px;margin-bottom:10px;font-size:14px;color:var(--muted)}
.fld-row .inp{width:100%}
.cfg-ok{background:rgba(25,135,84,.14);color:var(--ok);border-radius:7px;padding:9px 12px;margin:0 0 14px;font-weight:600}
.cfg-err{background:rgba(192,57,43,.14);color:var(--no)}

/* Respaldos (card en Configuración) */
.resp-estado{margin:0 0 12px;font-size:13px}
.resp-ok{color:var(--ok);font-weight:600}
.resp-warn{color:var(--accent-text);font-weight:600}
.resp-err{color:var(--no);font-weight:600}
.resp-tabla{width:100%;border-collapse:collapse;margin-top:12px;font-size:13px}
.resp-tabla th{text-align:left;color:var(--muted);font-weight:600;padding:4px 8px;border-bottom:1px solid var(--border)}
.resp-tabla td{padding:5px 8px;border-bottom:1px solid var(--border)}
.resp-tabla .num{text-align:right}
.resp-pie{margin:12px 0 0;font-size:12px;word-break:break-all}

/* Caja (Ventas): correlativo, disponible en vivo, color de tarifa PVP/PVM */
.prox-venta{align-self:center;color:var(--muted);font-size:13px}
.disp-hint{align-self:center;font-size:13px;color:var(--muted);min-width:120px}
.disp-hint.no{color:var(--no);font-weight:600}
.tar-pvp{background:rgba(25,135,84,.16) !important}
.tar-pvm{background:rgba(13,110,253,.18) !important}
[data-theme="oscuro"] .tar-pvm{background:rgba(110,168,254,.26) !important}

/* Formulario MODAL de venta (estilo UserForm de Excel) */
.venta-modal{border:none;border-radius:var(--r-modal);padding:0;width:min(1280px,96vw);max-height:92vh;background:var(--surface);color:var(--text);box-shadow:0 24px 70px rgba(0,0,0,.4)}
.venta-modal.maximized{width:100vw;height:100vh;max-width:100vw;max-height:100vh;border-radius:0}
.venta-modal.maximized .vm-head{border-radius:0}
.venta-modal.maximized form{height:100vh;max-height:100vh}
.inp-cod{width:150px;font-family:var(--font-mono)}
/* El valor escaneado va en mono, pero la invitación al usuario vuelve a la voz de la app */
.inp-cod::placeholder{font-family:var(--font-ui);letter-spacing:0}
.venta-modal::backdrop{background:rgba(0,0,0,.5)}
.venta-modal form{display:flex;flex-direction:column;max-height:92vh}
/* Header del modal en el navy del logo = misma marca del chip .brand (blanco 13.7:1 AA) */
.vm-head{display:flex;align-items:center;gap:12px;padding:14px 20px;background:linear-gradient(135deg,#1d2c50,#0c1730);color:#fff;border-radius:var(--r-modal) var(--r-modal) 0 0;position:relative;overflow:hidden}
/* Membrete «Exy flotante» (06-sep): el patrón del appbar inyectado por app.js en cada .vm-head; los
   hijos reales quedan por encima (el patrón es absolute z-index 0, pointer-events none). */
.vm-head > *:not(.exy-pat){position:relative;z-index:1}
.exy-pat-head{opacity:.06;--exy-dx:42px;--exy-dy:-42px}
.exy-pat-head img{width:29px}
.exy-pat-head .exy-pat-roll{animation-duration:12s}
.vm-head h2{margin:0;font-size:18px;font-family:var(--font-head);font-weight:600}
.vm-head .prox-venta{color:#fff;opacity:.9;font-size:13px}
.vm-head .vm-spacer{flex:1}
.vm-x{background:rgba(255,255,255,.18);color:#fff;border:none;border-radius:8px;width:30px;height:30px;cursor:pointer;font-size:14px}
.vm-x:hover{background:rgba(255,255,255,.3)}
.vm-body{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden;padding:0}
.vm-sec{padding:14px 20px;border-bottom:1px solid var(--border)}
.vm-sec-t{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-bottom:8px;font-weight:700;font-family:var(--font-head)}
/* Layout del modal: fila superior (datos | tasas) + agregar + fila inferior (detalle | resumen fijado) */
.vm-row-top{display:flex;align-items:stretch}
.vm-row-top>.vm-sec{flex:1;border-bottom:1px solid var(--border)}
.vm-row-top>.vm-sec:first-child{flex:1.5;border-right:1px solid var(--border)}
.vm-row-bottom{display:flex;flex:1;min-height:0;align-items:stretch}
.vm-detalle{flex:1;min-width:0;overflow:auto;border-right:1px solid var(--border)}
/* Resumen + pago + acciones: PANEL FIJO en la esquina inferior derecha (ajuste 3).
   El "pegado abajo" va con margin-top:auto en .vm-tot y NO con justify-content:flex-end (19-ago):
   con flex-end, el contenido que no cabía desbordaba por ARRIBA hacia territorio NO scrolleable
   (scrollHeight ni lo cuenta) y "Subtotal:" se pintaba sobre la sección vecina sin que el
   overflow pudiera atraparlo. Con margin-auto el look es idéntico cuando sobra espacio, y cuando
   falta el desborde cae hacia ABAJO, donde el overflow-y:auto sí da scroll y todo queda accesible. */
.vm-foot{width:400px;flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:10px;padding:14px 20px;background:var(--surface-2);border-radius:0 0 var(--r-modal) 0;overflow:hidden}
/* Totales SIEMPRE arriba y quietos (pedido Alejandro: "el Subtotal, IVA y TOTAL se quedan en su
   lugar"). El scroll de los extremos vive DENTRO del cajón (.pago-body), no en el .vm-foot, así el
   pie nunca desborda y los totales no se van de vista al abrir el cajón. */
.vm-foot>.vm-tot{flex:none}
.vm-tot{display:flex;flex-direction:column;align-items:flex-end;gap:3px;text-align:right}
.vm-tot span{color:var(--muted);font-size:14px}
.vm-tot b{color:var(--text);font-variant-numeric:tabular-nums}
/* EL número de la app: etiqueta pequeña + cifra 28px */
.vm-tot .big{display:flex;align-items:baseline;gap:8px}
.vm-tot .tot-lbl{font-size:12px;font-weight:700;letter-spacing:.06em;color:var(--muted)}
.vm-tot .big b{font-size:28px;letter-spacing:-.02em;color:var(--accent-text);font-family:var(--font-display)}
.vm-btns{display:flex;gap:8px;justify-content:flex-end}
/* En los editores (producto/cliente) el pie NO es la columna de 400px de la Caja: es una BARRA
   a lo ancho — nota a la izquierda, botones abajo a la DERECHA (pedido de Alejandro 03-jul). */
.prod-modal .vm-foot,.cli-modal .vm-foot{width:auto;flex-direction:row;align-items:center;border-radius:0 0 var(--r-modal) var(--r-modal)}
/* En los diálogos tipo kardex (Comandas, Mesas, cuenta de mesa — Fase C) el pie tampoco es la
   columna de 400px de la Caja: es una BARRA a lo ancho, si no los botones se salen del dialog. */
.kardex-modal .vm-foot{width:auto;flex-direction:row;align-items:center;border-radius:0 0 var(--r-modal) var(--r-modal)}
/* Checkbox "Imprimir recibo al guardar" (encima de los botones de la Caja) */
.vm-print-auto{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);cursor:pointer;user-select:none}
/* Marcador "Factura con I.V.A." del modal de compras (mismo trato visual) */
.vm-iva{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--muted);cursor:pointer;user-select:none}
/* MsgBox Sí/No (estilo UserForm) */
.msgbox{border:none;border-radius:var(--r-modal);padding:22px 24px;min-width:340px;max-width:min(92vw,560px);background:var(--surface);color:var(--text);box-shadow:0 24px 70px rgba(0,0,0,.4)}
.msgbox::backdrop{background:rgba(0,0,0,.5)}
.msgbox-txt{margin:0 0 16px;font-size:15px;white-space:pre-line;line-height:1.45}
/* Aviso de un solo botón (23-sep-2026): reemplaza al alert() nativo con el mismo molde del msgbox. */
.msgbox-aviso .vm-btns{justify-content:flex-end}

/* ── EN VIVO (23-sep-2026, pedido de Alejandro; variantes que ÉL eligió sobre el lienzo de animaciones) ──
   B1 · Deslizar y resaltar: la fila nueva baja desde la cabecera pintada de verde y el color se apaga solo (~2 s).
   A3 · Destello + conteo: la TARJETA del KPI parpadea en verde (sube) o rojo (baja) con un aro, la cifra cuenta hasta la
   nueva (public/vivo.js) y una etiqueta dice cuánto cambió. C2 · Pulso en la barra afectada: lo dibuja Chart.js (views/reportes.js). */
@keyframes vivoFila{0%{transform:translateY(-38%);opacity:.55;background:rgba(21,115,71,.28)}18%{transform:none;opacity:1;background:rgba(21,115,71,.28)}100%{background:transparent}}
tr.vivo-fila>td{animation:vivoFila 2.3s cubic-bezier(.2,.7,.2,1) both}
@keyframes vivoSube{0%{color:var(--ok)}72%{color:var(--ok)}100%{color:inherit}}
@keyframes vivoBaja{0%{color:var(--no)}72%{color:var(--no)}100%{color:inherit}}
.kpi-val.vivo-sube{animation:vivoSube 1.9s ease}
.kpi-val.vivo-baja{animation:vivoBaja 1.9s ease}
@keyframes vivoKpiSube{0%{box-shadow:0 0 0 0 rgba(21,115,71,0)}22%{background-color:rgba(21,115,71,.22);box-shadow:0 0 0 3px rgba(21,115,71,.35)}100%{box-shadow:0 0 0 0 rgba(21,115,71,0)}}
@keyframes vivoKpiBaja{0%{box-shadow:0 0 0 0 rgba(176,42,30,0)}22%{background-color:rgba(176,42,30,.2);box-shadow:0 0 0 3px rgba(176,42,30,.35)}100%{box-shadow:0 0 0 0 rgba(176,42,30,0)}}
.kpi{position:relative}
.kpi.vivo-sube{animation:vivoKpiSube 1.9s ease}
.kpi.vivo-baja{animation:vivoKpiBaja 1.9s ease}
@keyframes vivoChip{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
.vivo-delta{position:absolute;top:8px;right:10px;font-family:var(--font-head);font-size:11px;font-weight:700;padding:2px 8px;border-radius:999px;font-variant-numeric:tabular-nums;animation:vivoChip .35s ease both;transition:opacity .45s}
.vivo-delta.up{background:rgba(21,115,71,.14);color:var(--ok)}
.vivo-delta.down{background:rgba(176,42,30,.12);color:var(--no)}
.vivo-delta.se-va{opacity:0}
@media (prefers-reduced-motion:reduce){tr.vivo-fila>td,.kpi-val.vivo-sube,.kpi-val.vivo-baja,.kpi.vivo-sube,.kpi.vivo-baja,.vivo-delta{animation:none}}

/* ── Modo móvil del administrador (23-sep-2026): página de elección y pie con el modo ── */
.mov-card{max-width:440px}
.mov-opciones{display:flex;flex-direction:column;gap:12px;margin:18px 0 6px}
.mov-op{display:flex;flex-direction:column;align-items:flex-start;gap:4px;text-align:left;padding:14px 16px;border:1.5px solid var(--border);border-radius:var(--r-card);background:var(--surface);color:var(--text);cursor:pointer;font:inherit;position:relative}
.mov-op:hover,.mov-op:focus-visible{border-color:var(--accent-text,#ea580c);outline:none;box-shadow:var(--shadow-md)}
.mov-op.activa{border-color:var(--accent-text,#ea580c)}
.mov-op-t{font-family:var(--font-head);font-weight:700;font-size:17px}
.mov-op-d{color:var(--muted);font-size:13px;line-height:1.4}
.mov-op-actual{position:absolute;top:10px;right:12px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--accent-text,#ea580c)}
.pie-movil{display:inline-block;padding:1px 8px;border-radius:999px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:11px;text-decoration:none;letter-spacing:.04em}
.pie-movil.ver{background:rgba(234,88,12,.85)}
.chip.chip-solo-ver{background:rgba(234,88,12,.14);color:var(--accent-text,#ea580c);font-weight:700;text-decoration:none}
/* En el teléfono: tablas anchas deslizables, KPIs a dos columnas, barras de filtros que se envuelven */
.tbl-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
.tbl-scroll>table.grid{min-width:640px}
.tbl-scroll>#audit-list{min-width:1180px}   /* Auditoría lleva columnas fijas: sin ancho, el Detalle se aplasta y estira la fila */
.tbl-scroll>#ventas-list{min-width:760px}
body[data-movil] .content{padding:10px 10px 24px}
body[data-movil] .kpis{gap:8px}
body[data-movil] .kpi{flex:1 1 calc(50% - 8px);padding:10px 12px}
body[data-movil] .toolbar{flex-wrap:wrap;gap:6px}
body[data-movil] .rep-scroll{overflow-x:auto}

/* ── Fotos por código de barras (23-sep-2026): rejilla de aprobación ── */
.fe-intro{max-width:900px;line-height:1.5}
.fe-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:10px 0}
.fe-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px;margin:10px 0 18px}
.fe-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:10px;display:flex;flex-direction:column;gap:8px;box-shadow:var(--shadow-md);min-width:0}
.fe-img{position:relative;aspect-ratio:1/1;background:#fff;border-radius:8px;overflow:hidden;display:flex;align-items:center;justify-content:center;border:1px solid var(--border)}
.fe-img img{width:100%;height:100%;object-fit:contain;display:block;opacity:0;transition:opacity .35s ease}
.fe-img.fe-lista img{opacity:1}
.fe-img.fe-sin img{display:none}
.fe-espera,.fe-sinfoto{position:absolute;inset:0;display:none;align-items:center;justify-content:center;text-align:center;padding:12px;font-size:12px;color:var(--muted)}
.fe-img.fe-cargando .fe-espera{display:flex}
.fe-img.fe-cargando::after{content:'';position:absolute;bottom:10px;width:22px;height:22px;border-radius:50%;border:3px solid rgba(234,88,12,.25);border-top-color:#ea580c;animation:feGiro .9s linear infinite}
@keyframes feGiro{to{transform:rotate(360deg)}}
.fe-img.fe-sin .fe-sinfoto{display:flex;background:var(--bg)}
.fe-img.fe-sin~.fe-aviso,.fe-img.fe-sin~.fe-acciones .fe-usar{display:none}
.fe-info{display:flex;flex-direction:column;gap:2px;min-width:0}
.fe-info b{font-size:13px;line-height:1.3;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.fe-info .mono{font-size:12px}
.fe-aviso{margin:0;font-size:11px;color:var(--accent-text,#c2410c);background:rgba(234,88,12,.1);border-radius:6px;padding:4px 8px;line-height:1.35}
.fe-acciones{display:flex;gap:6px;margin-top:auto}
.fe-acciones .btn-primary,.fe-acciones .btn-ghost{flex:1;justify-content:center}
.fe-estado{margin:0;font-size:12px;color:var(--ok)}
.fe-descartada .fe-estado{color:var(--muted)}
.fe-card.fe-usada,.fe-card.fe-descartada{opacity:.85}
@media (max-width:720px){.fe-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.fe-card{padding:8px}}
.msgbox .vm-btns .btn-primary,.msgbox .vm-btns .btn-ghost{min-width:72px;justify-content:center}
.vm-pago{display:flex;align-items:center;justify-content:flex-start;gap:10px;flex-wrap:wrap;width:100%;padding-top:10px;border-top:1px dashed var(--border)}
.vm-pago .inp{width:auto}
/* Monedas como mini-tabla: una fila por moneda, cifras alineadas a la derecha para comparar de un vistazo */
.vm-monedas{display:flex;flex-direction:column;gap:6px;width:100%}
/* Combo de moneda: el icono va FUERA del <select> (un select no admite marcado dentro). */
.sel-mon{display:inline-flex;align-items:center}
.vm-mon{display:flex;align-items:center;gap:8px;cursor:pointer}
.vm-mon b{margin-left:auto;font-variant-numeric:tabular-nums;font-size:17px;color:var(--accent-text);font-weight:700}
/* Etiquetas de formulario más presentes (12→12.5px y seminegrita). El peso NO debe contagiar a los
   inputs (font:inherit los heredaría): se les repone 400 — salvo los select, que ya eran 600. */
.fld{display:flex;flex-direction:column;font-size:12.5px;font-weight:600;color:var(--muted);gap:3px}
.fld .inp:not(select){font-weight:400}
/* Celda de TASA POR INVENTARIO (multi-inventario S2): va junto a las tasas del día, separada por un
   filete para que se lea "estas son las globales · esta es la de A2". El nombre del inventario en
   tinta plena (es lo que la identifica); la etiqueta del par, apagada como las demás. */
.fld-inv{padding-left:10px;border-left:2px solid var(--border);white-space:nowrap}
.fld-inv b{color:var(--text);font-weight:600}
/* Input HEREDANDO: vacío, con la tasa prestada de placeholder. El borde punteado dice "esto no lo
   declaraste tú" sin tener que leer — al teclear una tasa propia el borde se vuelve sólido solo.
   El placeholder va en tinta normal (no itálica: ensanchaba el número y lo cortaba a 110px). */
.inp-hereda{border-style:dashed}
/* Etiqueta-botón que alterna el modo del descuento (% / monto fiat) */
.lbl-tog{align-self:flex-start;background:none;border:none;padding:0;margin:0;font:inherit;font-size:12px;color:var(--text);cursor:pointer;text-decoration:underline dotted;text-underline-offset:2px}
.lbl-tog:hover{color:var(--accent)}
/* FRAME ÚNICO de botón (14-ago): mismo relleno sólido, alto, radio y peso que el "+Nuevo" —
   se acabaron los botones "fantasma". Solo cambia el color por intención (slate = normal). */
.btn-ghost{background:linear-gradient(180deg,var(--btn-sec-hover) 0%,var(--btn-sec) 100%);border:1px solid var(--btn-sec-borde);border-radius:var(--r-ctl);padding:7px 15px;cursor:pointer;color:var(--btn-sec-ink);font-weight:600;text-decoration:none;display:inline-flex;align-items:center;gap:4px;box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 1px 2px rgba(16,24,40,.18);transition:background-color .12s ease,box-shadow .12s ease,transform .08s ease,border-color .12s ease}
.btn-ghost:hover{background:var(--btn-sec-hover);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 2px 6px rgba(16,24,40,.22)}
.btn-ghost:active{box-shadow:inset 0 2px 4px rgba(0,0,0,.3);transform:translateY(1px)}
.btn-ghost .ic16{fill:currentColor}
/* Nivel SUTIL (propuesta A): Cancelar / Limpiar / Cerrar / Quitar / No — lo que no hace nada por sí mismo deja
   de competir en slate con "Guardar cotización" o "Nuevo Cliente": fondo de control, borde, brillo arriba. */
.btn-ghost.btn-sutil{background:var(--surface-2);color:var(--text);border-color:var(--border);box-shadow:inset 0 1px 0 var(--sutil-brillo),0 1px 1px rgba(16,24,40,.08)}
.btn-ghost.btn-sutil:hover{background:var(--surface);border-color:var(--border-hover);box-shadow:inset 0 1px 0 var(--sutil-brillo),0 1px 2px rgba(16,24,40,.1)}
.btn-ghost.btn-sutil:active{box-shadow:inset 0 2px 4px rgba(16,24,40,.12)}
.btn-ghost.btn-sutil .ic16{fill:var(--icon-1)}
/* Acciones destructivas (Anular, Condonar): rojo contenido, se enciende al hover */
.btn-danger{background:linear-gradient(180deg,var(--no-claro) 0%,var(--no) 100%);border:1px solid var(--no-borde);border-radius:var(--r-ctl);padding:7px 15px;cursor:pointer;color:var(--btn-no-ink);font-weight:600;box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(16,24,40,.18);transition:box-shadow .12s ease,transform .08s ease}
.btn-danger:hover{background:var(--no);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 2px 6px rgba(16,24,40,.22)}
.btn-danger:active{box-shadow:inset 0 2px 4px rgba(0,0,0,.3);transform:translateY(1px)}
.fn-row .btn-danger{height:34px;display:inline-flex;align-items:center}

/* Etiquetas del modal de venta (ajuste 2a): los labels de CAMPO en texto pleno,
   pero los rótulos de sección (overlines) retroceden para no competir con los datos */
.venta-modal .vm-sec-t{color:var(--muted);font-weight:600;letter-spacing:.08em}
.venta-modal .fld{color:var(--text)}
.venta-modal .vm-tot span{color:var(--text)}
/* Pie de la Caja/Compras en pantallas BAJAS (feedback 19-ago): a ~768px de alto el panel de 400px
   no cabía con todo (totales + pago + monedas + botones) y el desborde salía por arriba — el
   "Subtotal:" quedaba fuera del frame en la caja real (1366×768). Se compacta lo justo para que
   quepa holgado; el overflow-y del .vm-foot queda de red para cualquier extremo que aún no quepa.
   Solo los modales maximizados (venta/compras): los de pie-barra no usan la columna de 400px. */
@media (max-height:860px){
  .venta-modal.maximized .vm-foot{padding:10px 16px;gap:5px}
  .venta-modal.maximized .vm-tot{gap:2px}
  .venta-modal.maximized .vm-tot .big b{font-size:22px}
  .venta-modal.maximized .vm-pago{padding-top:6px;gap:6px 8px}
  .venta-modal.maximized #v-credito-info{font-size:12px}
  .venta-modal.maximized .vm-monedas{gap:4px}
  /* (19-ago, 2ª vuelta) Con VARIOS inventarios las secciones de arriba crecen (celda de tasa por
     inventario que envuelve la fila + selector del filtro) y le roban alto al pie: se recupera
     en los paddings de sección. (28-ago) La imagen vuelve a crecer SIN devolver ese alto: los
     márgenes negativos hacen que aporte al flujo lo mismo que la caja de 104px que reemplaza
     (138−27−7=104) — ocupa la franja del título y el padding inferior, que a su derecha están
     vacíos, sin empujar el Detalle ni el pie. */
  .venta-modal.maximized .vm-sec{padding:7px 20px}   /* 08-sep: −6 px de alto que se van al cajón (él: «extiende un poco más el cajón») */
  .venta-modal.maximized .vm-sec-t{margin-bottom:5px}
  .venta-modal.maximized .v-img-box{width:138px;height:138px;margin-bottom:-7px}
  .venta-modal.maximized .vm-head{padding:8px 20px}
  /* El modo MIXTO suma Contado + info de crédito (+87px reales medidos): los campos del pago
     pasan a label-al-lado y la mini-tabla de monedas se aprieta un poco — pero SIGUE vertical:
     en fila, tres montos reales (12.000,00…) no caben en 400px y la cifra se corta. */
  .venta-modal.maximized .vm-monedas{gap:3px}
  .venta-modal.maximized .vm-mon b{font-size:15px}
  .venta-modal.maximized .vm-pago .fld{flex-direction:row;align-items:center;gap:6px}
  .venta-modal.maximized .vm-pago{font-size:13px}
  /* Un panel un poco más ANCHO envuelve el pago en menos líneas (medido: mixto pasaba 14px). */
  .venta-modal.maximized .vm-foot{width:520px}   /* 07-sep: 520 en todas las alturas (regla de abajo); aquí solo por claridad */
  .venta-modal.maximized .vm-btns .btn-primary,.venta-modal.maximized .vm-btns .btn-ghost{padding:6px 13px}
}

/* Modal "Exportar Inventario" (15-ago): filtros en rejilla compacta + pie con formato de salida */
.exp-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px}
.exp-grid .inp{width:100%}
.exp-pie{display:flex;gap:10px;align-items:center;margin-top:18px}

/* Multi-inventario + visor "Ver en" (15-ago) */
/* Frame de inventarios JUSTO ENCIMA de la tabla (feedback Alejandro, ajustado 15-ago: debajo se
   perdía con inventarios largos): pestañas estilo Excel — radio hacia ARRIBA, apoyadas al borde
   inferior, "mirando" a la tabla que viene debajo; la activa en violeta como los chips — + el
   Valor de inventario en la misma franja. El "+" del final = la hoja nueva del Excel (gestión). */
.vi-frame{display:flex;align-items:center;gap:14px;row-gap:8px;flex-wrap:wrap;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:8px 16px;margin:2px 0 12px;box-shadow:var(--shadow-md)}
.vi-frame .vi-spacer{flex:1}
.inv-tabs{display:flex;align-items:stretch;gap:3px;flex-wrap:wrap}
.tab-inv{padding:6px 16px;border:1px solid var(--border);border-bottom:none;border-radius:10px 10px 0 0;background:transparent;color:var(--muted);font-size:13px;font-weight:600;cursor:pointer;display:inline-flex;align-items:center;gap:6px}
.tab-inv:hover{color:var(--text);border-color:var(--border-hover)}
.tab-inv.active{background:var(--violet);color:#fff;border-color:var(--violet)}
[data-theme="oscuro"] .tab-inv.active{color:#14161b}
.tab-inv.active .cur{color:inherit}
/* Iconos en las pestañas (29-ago-2026, pedido Alejandro): mismo set duotono del launcher (tabIcon en layout.js) a
   16 px. Reposo: tonos de icono; hover: violeta+naranja como los tiles; activa: cuerpo en el color del texto de la
   pestaña (blanco en claro, tinta en oscuro → currentColor) y acento naranja — en oscuro la pestaña activa es azul
   claro y el naranja de marca se funde con ella, así que ahí el acento va en naranja quemado. */
.tab-inv .tic{width:16px;height:16px;display:inline-flex;flex:none}
.tab-inv .tic svg{width:16px;height:16px;display:block}
/* Pestañas grandes. 06-sep: Reportes +25 % (8/20 px, 16 px, iconos 20). 07-sep (pedido Alejandro): Reportes baja un 10 %
   (7/18 px, 14.4 px, iconos 18) y las pestañas de Ventas y de Cuentas adoptan ese MISMO tamaño (clase tabs-md). */
.rep-tabs .tab-inv,.tabs-md .tab-inv{padding:7px 18px;font-size:14.4px;gap:7px}
.rep-tabs .tab-inv .tic,.rep-tabs .tab-inv .tic svg,.tabs-md .tab-inv .tic,.tabs-md .tab-inv .tic svg{width:18px;height:18px}
.tab-inv:hover .ic-b{fill:var(--violet)}
.tab-inv:hover .ic-a{fill:var(--accent)}
.tab-inv.active .ic-b{fill:currentColor}
.tab-inv.active .ic-a{fill:var(--accent)}
[data-theme="oscuro"] .tab-inv.active .ic-a{fill:#a33a0c}
.tab-inv-plus{font-size:15px;padding:6px 12px;border-style:dashed}
.inv-nombre{width:200px;font-weight:600}
.chips-ver{align-items:center}
.chips-ver .ver-lbl{font-size:12.5px;font-weight:600;color:var(--muted);margin-right:2px}
.chips-ver .ver-nota{font-size:11.5px;color:var(--muted);font-style:italic;margin-left:4px}
/* Celdas en modo visor: fondo apenas tintado = "esto es referencial, no editable" */
.pv-ref{background:color-mix(in srgb,var(--accent) 5%,transparent)}
.vi-item b + b{margin-left:8px}
.btn-inv-del{padding:2px 10px;font-size:12px;height:auto}
/* Gestor de CATEGORÍAS (03-sep): filas nombre editable · conteo · acción; el botón etiqueta del header y del editor */
.cat-row{display:grid;grid-template-columns:1fr 110px auto;align-items:center;gap:12px;margin-bottom:8px;font-size:14px}
.cat-row .inp{width:100%}
.cat-nombre{display:flex;align-items:center;gap:8px}
.cat-n{text-align:right;white-space:nowrap}
.cat-mover{display:inline-flex;gap:6px;align-items:center;margin:0}
.cat-mover .inp{width:auto;max-width:200px;padding:3px 8px;font-size:12.5px}
.cat-resumen{margin:0 0 12px}
.cat-lista{max-height:46vh;overflow:auto;padding-right:4px}
.th-cats{margin-left:2px}
.btn-cats{align-self:flex-end;white-space:nowrap}

/* Reportes: KPIs + tarjeta de gráfico */
.kpis{display:flex;gap:12px;flex-wrap:wrap;margin:16px 0}
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:14px 18px;box-shadow:var(--shadow-md);min-width:0;flex:1 1 160px;container-type:inline-size;display:flex;flex-direction:column;justify-content:space-between}
.kpi.pct{flex:.62 1 110px}
.kpi.pct .kpi-val{font-size:clamp(16px,18cqw,26px)}
.kpi-lbl{color:var(--muted);font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;font-family:var(--font-head)}
.kpi-val{font-size:clamp(16px,11cqw,26px);font-weight:700;margin-top:6px;letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-family:var(--font-display)}
/* Código de moneda atenuado: la cifra manda, el "COP" acompaña */
.cur{font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.03em;margin-right:2px}
/* CHIP de moneda EXTRANJERA (14-ago): la base del negocio se queda con el .cur neutro de arriba y
   solo las otras monedas se pintan — el color señala "esto no está en tu moneda", no adorna.
   La cifra NUNCA se tiñe (decisión de Alejandro): el chip lleva el color, el número queda en tinta
   normal y los tabular-nums siguen alineados columna a columna.
   ⚠ ALTURA: line-height 1 + padding chico para que el chip quepa DENTRO de la caja de línea de
   15px/1.45 y las filas no crezcan ni 1px (misma trampa que costó el marcador c/IVA el 11-ago:
   vertical-align:super agrandaba la línea). Medir alturas de fila al tocar esto. */
.cur-usd,.cur-ves,.cur-cop{display:inline-block;padding:2px 6px;border-radius:20px;font-size:11px;font-weight:700;line-height:1;letter-spacing:.02em;border:1px solid transparent;margin-right:4px;vertical-align:1px}
.cur-usd{background:color-mix(in srgb,var(--cur-usd) 14%,transparent);color:var(--cur-usd);border-color:color-mix(in srgb,var(--cur-usd) 32%,transparent)}
.cur-ves{background:color-mix(in srgb,var(--cur-ves) 14%,transparent);color:var(--cur-ves);border-color:color-mix(in srgb,var(--cur-ves) 32%,transparent)}
.cur-cop{background:color-mix(in srgb,var(--cur-cop) 14%,transparent);color:var(--cur-cop);border-color:color-mix(in srgb,var(--cur-cop) 32%,transparent)}
/* ─── MONEDA DIBUJADA (05-sep, lienzo "Botones y Monedas": ficha A junto a los combos, en "Cobrar en" y en el setup).
   El color sale de los tokens --cur-* (claro y oscuro); la neutra "Todas" va en gris de icono. ─── */
.coin{flex:none;vertical-align:middle;display:inline-block}
.coin[hidden]{display:none}
.coin .coin-d{fill:color-mix(in srgb,var(--cur-usd) 16%,transparent);stroke:color-mix(in srgb,var(--cur-usd) 45%,transparent);stroke-width:1.4}
.coin .coin-t{fill:var(--cur-usd);font-family:var(--font-ui);font-weight:700}
.coin .coin-p{fill:var(--cur-usd)}
.coin-ves .coin-d{fill:color-mix(in srgb,var(--cur-ves) 16%,transparent);stroke:color-mix(in srgb,var(--cur-ves) 45%,transparent)}
.coin-ves .coin-t{fill:var(--cur-ves)}
.coin-cop .coin-d{fill:color-mix(in srgb,var(--cur-cop) 16%,transparent);stroke:color-mix(in srgb,var(--cur-cop) 45%,transparent)}
.coin-cop .coin-t{fill:var(--cur-cop)}
.coin-all .coin-d{fill:color-mix(in srgb,var(--icon-1) 16%,transparent);stroke:color-mix(in srgb,var(--icon-1) 45%,transparent)}
.coin-all .coin-p{fill:var(--icon-1)}
/* Ranura del combo (integración 1): las 4 fichas, se ve la del valor elegido */
.coin-slot{display:inline-flex;align-items:center;margin-right:6px}
/* Inventario: chips "Ver en:" con ficha + código; pestañas, barra de valor y kardex con la ficha delante */
.chips-ver .chip{display:inline-flex;align-items:center;gap:5px}
.tab-inv .coin{vertical-align:-3px;margin-left:2px}
.vi-item .coin{vertical-align:-3px;margin-right:2px}
.vm-mon .coin{margin-right:0}
.setup-mon .mon-sim{display:inline-flex;align-items:center;justify-content:center;height:30px}
.kpi-val .cur{font-size:13px}
.kpi-val .cur-usd,.kpi-val .cur-ves,.kpi-val .cur-cop{font-size:12px;vertical-align:4px}
.kpi-val .kpi-n{font-size:12px;font-weight:400}
.rep-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:16px 18px;box-shadow:var(--shadow-md);margin-bottom:18px;height:420px}
.rep-h{margin:24px 0 10px;font-size:17px;font-weight:600;font-family:var(--font-head)}
/* Reportes en PESTAÑAS (27-ago, pedido Alejandro): las mismas pestañas estilo Excel del Inventario y
   Cuentas, apoyadas en una línea; cada panel trae su gráfica (salvo Top productos, decisión suya) en
   moneda BASE. Los paneles inactivos siguen en el DOM (hidden): el export y las suites leen la página
   entera. El panel de existencias (.rep-exist) vive bajo la barra Exportar, solo con ese aspecto. */
.rep-tabs{margin:18px 0 0;padding:0 6px;border-bottom:1px solid var(--border)}
.rep-panel{padding-top:14px}
.rep-panel[hidden]{display:none}
.rep-panel > .rep-h:first-child{margin-top:4px}
.rep-card-sm{height:320px}
/* Gráfica de Generales con VENTANA de 15 movimientos (03-sep, pedido Alejandro): #rep-scroll ocupa el
   área de la tarjeta y desplaza en horizontal; #rep-scroll-inner se ensancha (n/15) desde reportes.js
   y el canvas responsive lo sigue. Con scroll activo, el interior cede 18 px a la barra. */
.rep-scroll{position:absolute;inset:16px 18px;overflow-x:auto;overflow-y:hidden}
.rep-scroll-inner{height:100%;min-width:100%;position:relative}
.rep-scroll.con-scroll .rep-scroll-inner{height:calc(100% - 18px)}
.rep-vacio{height:100%;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:14px}
.rep-exist{margin-top:6px}
.rep-exist .rep-h{margin-top:12px}
.rep-nota{margin:0 0 10px;font-size:13px}
/* Chips ▲/▼ % de variación por período (12-sep, «Alternativa B» de Alejandro): mismo molde que .merc-delta del Mercado
   Cambiario. En la gráfica se dibujan en el canvas bajo el eje (plugin repDeltas de views/reportes.js) y la tarjeta crece
   32 px para darles sitio sin robárselo a las barras; en la tabla van en la columna «vs. anterior». */
.rep-card.con-deltas{height:452px}
.rep-nota-deltas{margin-top:-8px}
.rep-delta{display:inline-block;font-size:12.5px;font-weight:700;padding:1px 8px;border-radius:10px;white-space:nowrap;line-height:1.45}
.rep-delta.up{color:var(--ok);background:rgba(38,166,91,.14)}
.rep-delta.down{color:var(--no);background:rgba(220,53,69,.12)}
.rep-delta.eq{color:var(--info);background:rgba(124,181,236,.16)}
.rep-delta.curso{background:transparent;border:1px dashed currentColor;padding:0 7px}
.rep-curso{font-size:11px;font-weight:400;margin-left:6px}
.rep-n{display:inline-flex;align-items:center;gap:6px;margin-left:10px;vertical-align:middle}
.rep-n .ver-lbl{font-size:12.5px;font-weight:600;color:var(--muted)}
.rep-n .chip{padding:3px 11px;font-size:12.5px;line-height:1.3}

/* ── Patrón de marca "Exy" en deriva vertical (14-ago, del fondo del video promo de MagisBot) ──
   Dos bloques idénticos apilados dentro de .exy-pat-roll; translateY 0→-50% en loop lineal =
   deriva continua sin costura. Solo transform (compositado): cero layout/paint por frame.
   El patrón vive sobre los frames NAVY (login/licencia/setup + appbar), que son oscuros en ambos
   temas → el glifo va en blanco fijo y NO necesita variantes de tema. */
.exy-pat{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
/* La deriva recorre EXACTAMENTE un período del tresbolillo (dx=px/2, dy=−px/2, 45° alineados con
   la rotación del glifo): al cerrar el ciclo el patrón coincide consigo mismo — sin costura. */
.exy-pat-roll{position:absolute;left:0;top:0;animation:exy-deriva 14s linear infinite}
.exy-pat img{position:absolute;transform:rotate(-45deg)}
/* 15-ago: glifo y pitch al 80% (−20%, pedido Alejandro) → ~56% más logos, look más recurrente.
   dx/dy = px/2 del preset de layout.js (152 login · 120 appbar) — romper esa pareja descose el loop. */
.exy-pat-login{opacity:.06;--exy-dx:76px;--exy-dy:-76px}
.exy-pat-login img{width:69px}
.exy-pat-appbar{opacity:.05;--exy-dx:60px;--exy-dy:-60px}
.exy-pat-appbar .exy-pat-roll{animation-duration:11s}
.exy-pat-appbar img{width:34px}
@keyframes exy-deriva{from{transform:translate(0,0)}to{transform:translate(var(--exy-dx),var(--exy-dy))}}
@media (prefers-reduced-motion: reduce){.exy-pat-roll{animation:none}}
/* Los hijos reales del frame quedan SOBRE el patrón (que es absolute con z-index 0). */
.appbar{position:relative}
/* .toast-host queda FUERA (19-sep): vive dentro del membrete y esta regla le pisaba el position:fixed → con 2+ avisos
   el membrete crecía (70 → 162 px) y empujaba toda la pantalla hacia abajo en cada venta. */
.appbar > *:not(.exy-pat):not(.toast-host){position:relative;z-index:1}
.login-wrap > *:not(.exy-pat){position:relative;z-index:1}

/* Login: portada de marca (fondo navy del logo + tarjeta elevada) */
.login-wrap{min-height:100vh;position:relative;display:flex;align-items:center;justify-content:center;background:radial-gradient(1100px 700px at 75% -10%,#22335c 0%,#0c1730 60%,#0a1226 100%)}
.login-card{background:var(--surface);border:none;border-top:3px solid var(--accent);border-radius:16px;box-shadow:0 20px 50px rgba(2,8,20,.45),0 2px 8px rgba(2,8,20,.3);padding:32px;width:360px;display:flex;flex-direction:column;gap:12px}
.login-ver{font-size:11px;color:var(--muted);text-align:center;margin:4px 0 0}
.login-card .inp{width:100%}
.login-card .btn-primary{width:100%;padding:10px}
.login-error{background:rgba(192,57,43,.14);color:var(--no);border-radius:7px;padding:8px 10px;margin:0;font-size:13px;text-align:center}
/* Teléfonos emparejados (11-sep): la página de espera del teléfono (views/emparejar.js) */
/* ¿Olvidó su clave?, datos fiscales de la licencia y clave temporal (12-sep-2026) */
.login-link{font-size:12.5px;text-align:center;color:var(--muted);text-decoration:underline;text-underline-offset:2px}
.login-link:hover{color:var(--accent-text)}
.rec-card{width:min(420px,calc(100vw - 32px))}
.rec-tit{margin:0;font-size:18px;text-align:center;font-family:var(--font-head)}
.rec-pasos{margin:0;padding-left:20px;font-size:13px;line-height:1.45;display:flex;flex-direction:column;gap:6px}
.rec-equipo{font-family:var(--font-mono);font-weight:700;letter-spacing:.06em;white-space:nowrap}
.rec-codigo{text-transform:uppercase;letter-spacing:.08em}
.rec-ok{margin:0;font-size:14px;text-align:center;color:var(--ok)}
.rec-ir{text-align:center;text-decoration:none}
.inp.inp-bloq{background:rgba(127,127,127,.12);cursor:not-allowed}
.setup-fiscal{margin:0;font-size:12.5px;line-height:1.4;padding:8px 10px;border-radius:8px;background:rgba(238,140,42,.10);border-left:3px solid var(--accent)}
.fiscal-nota{margin:0}
.mi-clave-forzado{margin-bottom:8px}
.mi-clave-salir{margin-top:8px}
.login-card.emp-card{width:min(400px,calc(100vw - 32px));gap:14px}
.emp-t{font-family:'Poppins',sans-serif;font-weight:700;font-size:19px;line-height:1.2;margin:0;text-align:center}
.emp-p{margin:0;font-size:13.5px;line-height:1.45;color:var(--muted);text-align:center}
.emp-codigo{font-family:'IBM Plex Mono',ui-monospace,Consolas,monospace;font-size:40px;font-weight:700;letter-spacing:.14em;text-align:center;color:var(--accent);margin:2px 0;user-select:all}
.emp-nombre{display:flex;gap:6px;margin:0}
.emp-nombre .inp{flex:1;min-width:0}
.emp-nombre .btn-ghost{white-space:nowrap}
.emp-estado{display:flex;align-items:center;justify-content:center;gap:8px;margin:0;font-size:12.5px;color:var(--muted);text-align:center}
.emp-spin{flex:none;width:14px;height:14px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:emp-spin 1s linear infinite}
@keyframes emp-spin{to{transform:rotate(360deg)}}
.emp-volver{text-align:center;text-decoration:none}

/* ─── Asistente de configuración inicial (/setup, wizard de onboarding del primer arranque) ───
   Misma escena del login (login-wrap + login-card) con la tarjeta más ancha y 3 pasos. */
.setup-card{width:560px;max-width:calc(100vw - 32px);gap:13px}
.setup-sub{margin:-4px 0 0;text-align:center;color:var(--muted);font-size:13px}
.setup-pasos{display:flex;gap:6px;justify-content:center;list-style:none;margin:2px 0 2px;padding:0}
.setup-pasos li{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--muted);padding:4px 12px 4px 5px;border-radius:999px;border:1px solid var(--border);transition:color .15s,border-color .15s}
.setup-pasos li .n{display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;border-radius:50%;background:var(--surface-2);font-size:11px;transition:background-color .15s,color .15s}
.setup-pasos li.activo{color:var(--accent-text);border-color:var(--accent)}
.setup-pasos li.activo .n{background:var(--accent);color:var(--accent-ink)}
.setup-pasos li.hecho{color:var(--ok);border-color:var(--ok)}
.setup-pasos li.hecho .n{background:var(--ok);color:#fff}
.setup-paso{border:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px;min-width:0}
.setup-paso[hidden]{display:none}
.setup-fld{display:flex;flex-direction:column;gap:4px}
.setup-fld>span,.setup-fld-tit{font-size:12px;font-weight:600;color:var(--muted)}
.setup-fld b{color:var(--accent-text)}
.setup-fld i{font-weight:400;font-style:normal;color:var(--muted);opacity:.8}
.setup-grid2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.setup-hint{font-size:12px;color:var(--muted);margin:-4px 0 0;line-height:1.35}
.setup-monedas{display:flex;gap:8px}
/* Rubros del negocio: mismas tarjetas de las monedas, en rejilla 2×2 (4 opciones con texto largo) */
.setup-rubros{flex-wrap:wrap;margin-bottom:10px}
.setup-rubros .setup-mon{flex:1 1 42%}
.setup-rubros .mon-nom{font-size:13px}
.setup-rubros .mon-cod{text-align:center}
.setup-mon{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;gap:1px;padding:10px 8px 8px;border:1px solid var(--border);border-radius:var(--r-card);cursor:pointer;transition:border-color .12s,background-color .12s,box-shadow .12s}
.setup-mon:hover{border-color:var(--border-hover)}
.setup-mon input{position:absolute;opacity:0;pointer-events:none}
.setup-mon:has(input:checked){border-color:var(--accent);background:var(--surface-2);box-shadow:var(--ring)}
.setup-mon .mon-sim{font-family:var(--font-display);font-weight:700;font-size:20px;color:var(--violet)}
.setup-mon .mon-nom{font-size:12px;font-weight:600}
.setup-mon .mon-cod{font-size:11px;color:var(--muted)}
.setup-iva{max-width:140px}
.setup-nav{display:flex;gap:8px;margin-top:2px}
.setup-nav .btn-primary{flex:1;padding:10px}
.setup-nav .btn-ghost{flex:0 0 auto}

/* Costo derivado (solo lectura) */
.costo-cell{color:var(--muted)}

/* ─── Heatmap de UTILIDAD (bandas exactas del Excel, Sub AplicarColorUtilidad) ───
   ≤0 sin color · 0–20 rojo · 20–35 naranja · 35–50 amarillo · 50–100 verde · >100 azul */
.util-cell{font-variant-numeric:tabular-nums}
.util-r{color:#9c0006;background:#ffc7ce}
.util-o{color:#9c5700;background:#ffe0b2}
.util-y{color:#9c8000;background:#fff9b2}
.util-g{color:#006100;background:#c6efce}
.util-b{color:#002060;background:#bdd7ee}
[data-theme="oscuro"] .util-r{color:#ffb3ba;background:rgba(156,0,6,.30)}
[data-theme="oscuro"] .util-o{color:#ffd28a;background:rgba(156,87,0,.28)}
[data-theme="oscuro"] .util-y{color:#ffe98a;background:rgba(156,128,0,.24)}
[data-theme="oscuro"] .util-g{color:#8ee6a8;background:rgba(0,97,0,.30)}
[data-theme="oscuro"] .util-b{color:#a9c9f5;background:rgba(0,32,96,.45)}
/* Tile MARGEN de Reportes teñido con las mismas bandas (03-sep, pedido Alejandro): el rótulo hereda la tinta */
.kpi.util-r .kpi-lbl,.kpi.util-o .kpi-lbl,.kpi.util-y .kpi-lbl,.kpi.util-g .kpi-lbl,.kpi.util-b .kpi-lbl{color:inherit;opacity:.8}
/* MEDALLAS del Top productos (03-sep-2026, pedido Alejandro): oro / plata / bronce para los 3 primeros,
   disco metálico con aro claro y numeral, y el MISMO destello lineal del wordmark (banda que barre cada
   10 s, escalonado 0,22 s entre medallas). Autocontenidas: se ven igual en tema claro y oscuro. */
.medalla{position:relative;display:inline-flex;width:22px;height:22px;border-radius:50%;align-items:center;justify-content:center;font:700 11px/1 var(--font-head);overflow:hidden;vertical-align:middle;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.55),0 1px 2px rgba(0,0,0,.28)}
.medalla .n{position:relative;z-index:1}
.medalla.oro{background:radial-gradient(circle at 35% 28%,#fff3c4 0%,#f4c453 38%,#cf9a1e 76%,#a8760f 100%);color:#4a3200}
.medalla.plata{background:radial-gradient(circle at 35% 28%,#ffffff 0%,#e4e8ee 38%,#aeb6c4 76%,#8a93a3 100%);color:#2e3440}
.medalla.bronce{background:radial-gradient(circle at 35% 28%,#ffddbd 0%,#dfa475 38%,#b8733c 76%,#8f5527 100%);color:#3d2208}
.med-glint{position:absolute;inset:0;background:linear-gradient(115deg,transparent 38%,rgba(255,255,255,.9) 50%,transparent 62%) 160% 0/260% 100% no-repeat;animation:med-destello 10s linear infinite}
.medalla.plata .med-glint{animation-delay:.22s}
.medalla.bronce .med-glint{animation-delay:.44s}
@keyframes med-destello{0%{background-position:160% 0}9%{background-position:-60% 0}100%{background-position:-60% 0}}

/* ─── Semáforo de EXISTENCIA (formato condicional del Kardex del Excel) ───
   rojo ≤ mín · amarillo dentro de la banda promedio [prom, reorden] · verde ≥ máx */
.ex-r{color:#c62324;background:#f4d3d3}
.ex-y{color:#8a6800;background:#ffffcc}
.ex-g{color:#354f10;background:#c6efce}
[data-theme="oscuro"] .ex-r{color:#ff9d9d;background:rgba(198,35,36,.28)}
[data-theme="oscuro"] .ex-y{color:#ffe98a;background:rgba(204,153,0,.22)}
[data-theme="oscuro"] .ex-g{color:#8ee6a8;background:rgba(53,79,16,.45)}

/* Header-toggle de las columnas de utilidad (alternar % ↔ moneda) */
.th-utog{background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;text-transform:inherit;letter-spacing:inherit;cursor:pointer;text-decoration:underline dotted;text-underline-offset:3px;white-space:nowrap}
.th-utog:hover{color:var(--accent-text)}
/* El mismo alternador, pero en la barra del catálogo del inventario (08-sep): ahí no es un encabezado de
   tabla, así que se le pone cuerpo de control (borde, fondo) y se le quita el subrayado de puntos. */
.inv-cat-utog{flex:none;white-space:nowrap;font:600 12.5px/1 var(--font-ui);color:var(--text);padding:6px 11px;border:1px solid var(--border);border-radius:20px;background:var(--surface-2);text-decoration:none;box-shadow:inset 0 1px 0 var(--sutil-brillo)}
.inv-cat-utog:hover{border-color:var(--border-hover);color:var(--text)}
.inv-cat-utog:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* Filas de compras clicables (abren el detalle) */
.compra-row{cursor:pointer}

/* Valor de inventario (colores pedidos: título naranja · costo rojo · P.V.P verde · P.V.M azul oscuro) */
.vi-bar{display:flex;align-items:baseline;gap:20px;flex-wrap:wrap;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);padding:10px 16px;margin-bottom:14px;box-shadow:var(--shadow)}
.vi-t{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--accent-text)}
.vi-item{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
.vi-item b{font-size:16px;margin-left:6px;font-variant-numeric:tabular-nums;color:inherit;font-weight:700}
.vi-costo{color:var(--no)}
.vi-pvp{color:var(--ok)}
.vi-pvm{color:#002060}
[data-theme="oscuro"] .vi-pvm{color:#a9c9f5}
/* Dentro del modal del kardex la barra va "plana" (sin card dentro de card) */
.vi-plana{border:none;box-shadow:none;padding:0;margin:0;background:transparent;width:100%}

/* Kardex como modal: por defecto ocupa TODO el ancho de la pantalla; ⛶ lo extiende a toda la altura */
.kardex-modal{width:100vw;max-width:100vw;border-radius:0}
.kardex-modal .vm-head{border-radius:0}
.kardex-modal .vm-body{display:block;overflow:auto;padding:0 0 8px;max-height:calc(92vh - 60px)}
.kardex-modal.maximized{width:100vw;height:100vh;max-height:100vh;margin:0}
.kardex-modal.maximized .vm-body{max-height:calc(100vh - 60px)}
/* Las reglas genéricas ".venta-modal form" y ".venta-modal.maximized form" (pensadas para el ÚNICO form
   de la Caja) no aplican a los forms de fila del kardex: ni columna, ni height:100vh al maximizar. */
.kardex-modal form.fn-row{flex-direction:row;align-items:flex-end;max-height:none;height:auto}

/* Kardex: existencia clicable + panel de movimientos */
.kardex-link{cursor:pointer;text-decoration:underline dotted;text-underline-offset:3px}
.kardex-link:hover{box-shadow:inset 0 0 0 2px var(--accent)}
.kardex{margin-top:18px}
.kardex-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.kardex-head .spacer{flex:1}
.kardex-saldo{color:var(--muted);font-size:13px}
.kardex-saldo b{color:var(--text)}
.kardex-tbl th{font-size:11px}
.mov-ent{color:var(--ok);font-weight:600}
.mov-sal{color:var(--no);font-weight:600}
.kardex-ajuste{margin-top:12px;border-top:1px dashed var(--border);padding-top:12px;align-items:center}

/* Venta anulada */
.badge.b-no{background:rgba(192,57,43,.16);color:var(--no)}
.fila-anulada{opacity:.55}
.fila-anulada td.num,.fila-anulada td.mono{text-decoration:line-through}

/* Devoluciones (parciales) */
.badge.b-warn{background:rgba(238,140,42,.18);color:var(--accent-text)}
.badge.b-ok{background:rgba(39,174,96,.16);color:var(--ok)}
.dev-hist{margin-top:12px;border-top:1px dashed var(--border);padding-top:10px}
.dev-hist>b{font-size:13px}
.dev-list{margin:6px 0 0;padding-left:18px;font-size:13px;color:var(--muted)}
.dev-list li{margin:2px 0}
.dev-list b{color:var(--no)}

/* ═══ MOVIMIENTO (pedido 05-jul): ruleta entre módulos · modales que emergen · bienvenida ═══
   Todo respeta prefers-reduced-motion: con "reducir movimiento" activo en Windows no hay animación. */

/* ─── Ruleta entre módulos: View Transitions ENTRE PÁGINAS (Chromium del Electron) ───
   El cromo (appbar + launcher) lleva nombre propio → queda quieto; solo el CONTENIDO rota como
   tarjeta de carrusel. La dirección (izq/der) sigue el ORDEN de los tiles: app.js la guarda al
   clicar y el <head> de la página siguiente la repone como html[data-nav-dir] (ver layout.js).
   Sin dirección (F5, atrás, redirects) el cambio es un fundido sobrio. */
@media (prefers-reduced-motion: no-preference){
  @view-transition{navigation:auto}
  .appbar{view-transition-name:appbar}
  .launcher{view-transition-name:launcher}
  .content{view-transition-name:contenido}
  ::view-transition-old(contenido){animation:vt-fundido-sale .18s ease both}
  ::view-transition-new(contenido){animation:vt-fundido-entra .18s ease both}
  html[data-nav-dir="der"]::view-transition-old(contenido){animation:vt-sale-izq .27s cubic-bezier(.3,.7,.35,1) both}
  html[data-nav-dir="der"]::view-transition-new(contenido){animation:vt-entra-der .27s cubic-bezier(.3,.7,.35,1) both}
  html[data-nav-dir="izq"]::view-transition-old(contenido){animation:vt-sale-der .27s cubic-bezier(.3,.7,.35,1) both}
  html[data-nav-dir="izq"]::view-transition-new(contenido){animation:vt-entra-izq .27s cubic-bezier(.3,.7,.35,1) both}
}
@keyframes vt-fundido-sale{to{opacity:0}}
@keyframes vt-fundido-entra{from{opacity:0}}
@keyframes vt-sale-izq{to{opacity:0;transform:perspective(1400px) translateX(-72px) rotateY(10deg)}}
@keyframes vt-entra-der{from{opacity:0;transform:perspective(1400px) translateX(72px) rotateY(-10deg)}}
@keyframes vt-sale-der{to{opacity:0;transform:perspective(1400px) translateX(72px) rotateY(-10deg)}}
@keyframes vt-entra-izq{from{opacity:0;transform:perspective(1400px) translateX(-72px) rotateY(10deg)}}
/* Motor sin View Transitions: al menos el contenido ENTRA con vida (no aparece de golpe) */
@supports not (view-transition-name: none){
  @media (prefers-reduced-motion: no-preference){
    .content{animation:vt-fundido-entra .2s ease}
  }
}

/* ─── Modales que EMERGEN del control que los abre ───
   app.js parchea showModal(): fija transform-origin en el punto del último click y aplica
   .dlg-anim → el dialog crece desde el botón/fila que lo generó (y el velo se funde).
   Los formularios inline de alta (+ Nuevo) entran con el mismo gesto. */
@media (prefers-reduced-motion: no-preference){
  dialog.dlg-anim{animation:dlg-pop .2s cubic-bezier(.2,.85,.3,1.02)}
  dialog.dlg-anim::backdrop{animation:dlg-velo .2s ease}
  .form-nuevo{animation:sube-suave .18s ease}
}
@keyframes dlg-pop{from{opacity:0;transform:scale(.55)}}
@keyframes dlg-velo{from{opacity:0}}
@keyframes sube-suave{from{opacity:0;transform:translateY(6px)}}

/* ─── Bienvenida post-login (views/login.js → paginaBienvenida) ───
   Mismo telón navy de la portada; saludo escalonado que se recoge solo antes de entrar al ERP. */
.saludo-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;background:radial-gradient(1100px 700px at 75% -10%,#22335c 0%,#0c1730 60%,#0a1226 100%)}
.saludo{display:flex;flex-direction:column;align-items:center;gap:16px;text-align:center;padding:24px}
.saludo-hola{color:#b9c6e4;font-size:14px;letter-spacing:.16em;text-transform:uppercase;font-weight:600;margin:0}
.saludo-nombre{color:#fff;font-family:'Poppins',sans-serif;font-weight:700;font-size:clamp(28px,5vw,44px);line-height:1.12;letter-spacing:-.01em;margin:0;max-width:80vw;overflow-wrap:break-word;word-break:break-word}
.saludo-linea{width:64px;height:4px;border-radius:2px;background:var(--accent)}
@media (prefers-reduced-motion: no-preference){
  .saludo>*{animation:saludo-sube .5s cubic-bezier(.2,.7,.3,1) both}
  .saludo>:nth-child(2){animation-delay:.12s}
  .saludo>:nth-child(3){animation-delay:.24s}
  .saludo>:nth-child(4){animation-delay:.36s}
  .saludo{animation:saludo-out .3s ease 1.4s both}
}
@keyframes saludo-sube{from{opacity:0;transform:translateY(14px)}}
@keyframes saludo-out{to{opacity:0;transform:translateY(-8px)}}

/* ═══ Reportes: barra de exportación · drill-down · badges de banda de existencia ═══ */
.rep-export{display:flex;align-items:center;gap:8px;margin:2px 0 14px;flex-wrap:wrap}
.rep-export .inp{padding:6px 10px}
.rep-export .chip{display:inline-flex;align-items:center;font-weight:600;padding:6px 12px}
.rep-export .chip .ic16{margin-right:6px}
.rep-export .chip.active .ic16 path{fill:currentColor}
/* MODO de la gráfica de Generales (22-sep, pedido de Alejandro: «dar a notar con letras del naranja principal del
   sistema si se está en modo mes, semana o día»): barra encima de la tarjeta con el modo en naranja, qué es cada
   barra y «Volver» a la derecha — antes el botón flotaba sobre la gráfica. */
.rep-modo{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-height:30px;margin:4px 2px 8px}
.rep-modo-t{color:var(--accent-text);font:800 15px var(--font-head);letter-spacing:.05em;text-transform:uppercase;white-space:nowrap}
.rep-modo-c{color:var(--muted);font-size:13px}
.rep-volver{font-size:12px;padding:4px 10px}
.rep-card{position:relative}
.ex-badge{display:inline-block;padding:2px 9px;border-radius:999px;font-size:11px;font-weight:700;line-height:1.5;white-space:nowrap}
.ex-min{background:#fde2e2;color:#9c0006}
.ex-prom{background:#e3f4e1;color:#1f7a34}
.ex-max{background:#e2ecfb;color:#284f9e}
.ex-int{background:var(--surface-2);color:var(--muted)}
.row-anulada{opacity:.55}
:root[data-theme="oscuro"] .ex-min{background:#3a1e22;color:#f3a9a9}
:root[data-theme="oscuro"] .ex-prom{background:#1e3324;color:#a9d9b5}
:root[data-theme="oscuro"] .ex-max{background:#1e2c46;color:#a9c9f5}

/* ─── Licencia: activación, bloqueo y banner de gracia ─── */
.lic-card{width:420px;max-width:calc(100vw - 32px);gap:13px}
.lic-cod{text-align:center;letter-spacing:2px;font-weight:600;text-transform:uppercase;font-size:16px}
.lic-candado{display:flex;justify-content:center;color:var(--accent-text);margin:2px 0 -2px}
.lic-titulo{margin:0;text-align:center;font-size:19px}
.lic-msg{margin:0;text-align:center;color:var(--muted);font-size:13px;line-height:1.45}
.lic-contacto{margin:2px 0 0;text-align:center;color:var(--muted);font-size:12px}
.lic-banner{background:rgba(242,155,63,.16);color:var(--accent-text);border-bottom:1px solid rgba(242,155,63,.35);padding:7px 16px;text-align:center;font-size:13px;font-weight:600}

/* ── Repetido en el carrito (pedido de Alejandro, 17-ago) ─────────────────────────────────────────
   Al agregar un artículo que YA está en la lista se suma en su renglón; el renglón destella un
   momento y debajo de la tabla queda dicho qué pasó. El color va en rgba del acento y no en un
   token sólido: así el destello funciona igual en claro y en oscuro sin definirlo dos veces. */
.fila-fusion>td{animation:fusion-flash 1.8s ease-out 1}
@keyframes fusion-flash{0%{background:rgba(238,140,42,.30)}70%{background:rgba(238,140,42,.14)}100%{background:transparent}}
.vm-fusion{margin:6px 2px 0;font-size:12.5px;color:var(--accent-text)}

/* ── Re-precio sugerido en Compras (pedido de Alejandro, 21-ago) ─────────────────────────────────
   El aviso vivo bajo la fila de captura toma las bandas del heatmap de utilidad (util-r/o/y/g/b,
   con su variante oscura ya definida); vacío conserva el renglón (min-height) para que aparecer y
   desaparecer no haga saltar el modal. La fila .c-reprecio cuelga de su línea del detalle. */
.c-util-aviso{min-height:20px;margin-top:6px;font-size:12.5px;padding:2px 8px;border-radius:6px;display:inline-block}
.c-util-aviso:empty{padding:2px 0}
.c-reprecio td{border-top:0;padding-top:0;padding-bottom:8px;font-size:12.5px}
.c-rep-btn{padding:2px 10px;font-size:12px}
.c-rep-chip{padding:2px 8px;border-radius:6px;font-size:12px}

/* ── Ajuste masivo de precios (modal, 24-ago) ────────────────────────────────────────────────────
   La tabla de preview y el historial comparten .ajp-t (compacta, números a la derecha); los chips
   de precio nuevo reusan las bandas util-* del heatmap. Los checkboxes P.V.P./P.V.M. se alinean a
   la base de los .fld vecinos (flex-end del .fn-row + padding que compensa el label de arriba). */
.ajp-form{align-items:flex-end;flex-wrap:wrap}
.ajp-chks{display:flex;gap:12px;padding-bottom:9px}
.ajp-chk{display:flex;align-items:center;gap:5px;font-size:13.5px;white-space:nowrap;cursor:pointer}
.ajp-sum{margin:14px 0 2px}
.ajp-t{width:100%;border-collapse:collapse;font-size:13px;margin:8px 0 2px}
.ajp-t th,.ajp-t td{padding:4px 8px;border-bottom:1px solid var(--border);text-align:left}
.ajp-t th{color:var(--th-text);background:var(--th-bg)}
.ajp-t .num{text-align:right;white-space:nowrap}
.ajp-t .viejo,.ajp-res .viejo{color:var(--muted)}
.ajp-res .btn-primary{margin-top:10px}
.ajp-h{margin:18px 0 4px;font-size:15px}

/* ─── MODO CATÁLOGO de la Caja (05-sep-2026; lienzo "Caja Modo Catálogo" aprobado por Alejandro) ───
   Conmutador Formulario | Catálogo en la cabecera del modal (.seg, sobre el navy del header) y, en
   modo catálogo, el cuerpo pasa a REJILLA de 2 columnas: catálogo (buscador + chips + tarjetas por
   tandas) a la izquierda y el detalle + pie de siempre apilados a la derecha. Los campos de la fila
   de captura siguen en el DOM (ocultos): las tarjetas los manejan y todo el JS de la caja sigue igual. */
.seg{display:inline-flex;background:rgba(255,255,255,.12);border-radius:8px;padding:3px;gap:3px;margin-left:8px}
.seg button{border:0;border-radius:6px;padding:5px 12px;font:inherit;font-size:13px;font-weight:600;color:#fff;background:transparent;cursor:pointer;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.seg button:hover{background:rgba(255,255,255,.14)}
.seg button.on{background:var(--accent);color:var(--accent-ink)}
.vm-head .seg .ic16{fill:currentColor;width:14px;height:14px;margin:0}
.v-add-wrap[hidden]{display:none}
.v-cat{display:flex;flex-direction:column;flex:1;min-height:0}
.v-cat[hidden]{display:none}
/* 🪤 08-sep: la barra NO cabía en una línea. Medido a 1366×768 con la Caja maximizada: la columna del Catálogo
   da 805 px y las piezas suman 990 (buscador 240 mínimo + «Nuevo Producto» 156 + Alfabética|Coincidente 168 +
   contador 74 + S/M/L 89 + visor de monedas 190 + huecos). Ya ANTES del botón se salían 17 px y el visor (USD)
   (VES)(COP) del 07-sep quedaba cortado por el borde. Con flex-wrap nada se pierde: lo que no entra baja a una
   segunda línea (row-gap corto para que cueste lo menos posible de rejilla). */
.v-cat-top{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;margin-bottom:8px}
.v-cat-buscar{flex:0 1 460px;min-width:240px}
/* «Nuevo Producto» del Catálogo (08-sep): pegado al buscador, sin estirarse ni partir el rótulo. */
.v-cat-top .v-cat-nuevo{flex:none;white-space:nowrap}
.v-cat-buscar .inp{height:34px}
.v-cat-conteo{font-size:12.5px;white-space:nowrap}
/* Barra de categorías: nombres ORIGINALES en una fila que se desplaza (rueda del mouse / arrastre de la barra) */
.v-cat-chips{margin-bottom:6px;flex:none;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;padding-bottom:6px;scrollbar-width:thin;scrollbar-color:var(--border-hover) var(--surface-2)}
.v-cat-chips::-webkit-scrollbar{height:8px}
.v-cat-chips::-webkit-scrollbar-track{background:var(--surface-2);border-radius:6px}
.v-cat-chips::-webkit-scrollbar-thumb{background:var(--border-hover);border-radius:6px}
.v-cat-chips::-webkit-scrollbar-thumb:hover{background:var(--accent)}
.v-cat-chips .chip{padding:5px 12px;font-size:13px;white-space:nowrap}
.v-cat-chips .chip[hidden]{display:none}
.v-cat-scroll{flex:1;min-height:0;overflow:auto;padding:2px 2px 12px}
/* Columnas FIJAS por tamaño (decisión 05-sep): S 5 · M 4 · L 3 — a 1366 px la existencia y el contador caben */
.v-cat-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
.cat-card{display:flex;flex-direction:column;border:1px solid var(--border);border-radius:var(--r-card);background:var(--surface);overflow:hidden;box-shadow:var(--shadow-sm)}
.cat-card:hover{border-color:var(--border-hover);box-shadow:var(--shadow-md)}
/* La foto va sobre BLANCO aunque el tema sea oscuro: es contenido (fotos de producto), como en .v-img-box */
.cat-foto{height:118px;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:6px;flex:none}
.cat-foto img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.cat-sinfoto{display:flex;flex-direction:column;align-items:center;gap:4px;color:var(--icon-2);font-size:11px}
.cat-sinfoto i{font-style:normal}
.cat-info{padding:8px 8px 9px;display:flex;flex-direction:column;gap:4px;flex:1}
.cat-nombre{font-size:12.5px;font-weight:600;line-height:1.25;height:31px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}   /* 2 líneas con puntos suspensivos: un nombre de 3 líneas ya no se corta a media letra */
.cat-marca{font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cat-fila{display:flex;align-items:baseline;justify-content:space-between;gap:6px;margin-top:2px}
.cat-precio b{font-size:15px;font-variant-numeric:tabular-nums}
/* Rótulo de tarifa a la IZQUIERDA del precio (14-sep): "P.V.P COP 26.000". Verde P.V.P / azul P.V.M,
   los mismos colores que el select de tarifa del modo Formulario (.tar-pvp / .tar-pvm). */
.cat-tar-lbl{display:inline-block;font-size:10px;font-weight:600;letter-spacing:.02em;line-height:1.5;padding:0 4px;margin-right:4px;border-radius:3px;vertical-align:1px}
.cat-tar-lbl.pvp{background:rgba(25,135,84,.16);color:#198754}
.cat-tar-lbl.pvm{background:rgba(13,110,253,.18);color:#0d6efd}
.cat-tar-lbl.falta{background:rgba(238,140,42,.18);color:#c26a10}
[data-theme="oscuro"] .cat-tar-lbl.falta{color:#eb9d4a}
[data-theme="oscuro"] .cat-tar-lbl.pvp{color:#4ec98a}
[data-theme="oscuro"] .cat-tar-lbl.pvm{color:#6ea8fe}
/* La tarifa cambia lo que se COBRA: su segmentado se marca con el color de la tarifa activa, no con
   el gris de los mandos de vista (tamaño, moneda) que tiene al lado. */
.seg-tar button.on[data-tar="pvp"]{background:rgba(25,135,84,.16);color:#198754}
.seg-tar button.on[data-tar="pvm"]{background:rgba(13,110,253,.18);color:#0d6efd}
[data-theme="oscuro"] .seg-tar button.on[data-tar="pvp"]{color:#4ec98a}
[data-theme="oscuro"] .seg-tar button.on[data-tar="pvm"]{color:#6ea8fe}
.cat-stock{display:inline-block;padding:2px 7px;border-radius:20px;font-size:11px;font-weight:700;line-height:1.3;border:1px solid transparent;white-space:nowrap}
.cat-stock.ok{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 30%,transparent)}
.cat-stock.bajo{background:color-mix(in srgb,var(--accent) 18%,transparent);color:var(--accent-text);border-color:color-mix(in srgb,var(--accent) 40%,transparent)}
.cat-stock.no{background:color-mix(in srgb,var(--no) 14%,transparent);color:var(--no);border-color:color-mix(in srgb,var(--no) 30%,transparent)}
.cat-accion{margin-top:auto;padding-top:4px}
.cat-add{height:34px;width:100%;font-size:13.5px;padding:0 10px;display:inline-flex;align-items:center;justify-content:center;gap:6px}
/* Contador −/+ del artículo que YA está en el carrito (mismo slate de los botones normales) */
.cat-stepper{display:flex;align-items:center;justify-content:space-between;border-radius:var(--r-ctl);background:linear-gradient(180deg,var(--btn-sec-hover) 0%,var(--btn-sec) 100%);border:1px solid var(--btn-sec-borde);color:var(--btn-sec-ink);height:34px;overflow:hidden;box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 1px 2px rgba(16,24,40,.18)}
.cat-stepper button{border:0;background:transparent;color:inherit;width:40px;height:34px;font-size:18px;cursor:pointer;font-family:inherit;line-height:1}
.cat-stepper button:hover{background:rgba(255,255,255,.14)}
.cat-stepper b{font-size:14px;font-variant-numeric:tabular-nums}
.cat-nodisp{display:block;text-align:center;font-size:12px;color:var(--muted);padding:8px 0}
.v-cat-mas{text-align:center;padding:10px;color:var(--muted);font-size:12px}
.v-cat-mas[hidden]{display:none}
/* Cuerpo del modal en modo catálogo: rejilla — fila superior (datos | tasas) a lo ancho; debajo,
   catálogo (izq) | detalle + pie apilados (der, 440px como el pie compacto). */
.venta-modal.modo-cat .vm-body{display:grid;grid-template-columns:minmax(0,1fr) 440px;grid-template-rows:auto minmax(0,1fr)}
.venta-modal.modo-cat #v-row-top{grid-column:1/-1}
.venta-modal.modo-cat #v-sec-agregar{grid-column:1;grid-row:2;display:flex;flex-direction:column;min-height:0;border-bottom:0;border-right:1px solid var(--border);padding-bottom:0}
.venta-modal.modo-cat #v-sec-agregar .v-add-wrap{display:none}
.venta-modal.modo-cat .vm-row-bottom{grid-column:2;grid-row:2;flex-direction:column;min-height:0}
.venta-modal.modo-cat .vm-detalle{flex:1;min-height:0;border-right:0;border-bottom:1px solid var(--border)}
/* Padding lateral más corto SOLO aquí: la tabla del detalle (Artículo + Cant/Precio/Subtotal sin partir +
   papelera) mide ~406px y con los 20px de siempre no cabía en la columna de 440 → barra horizontal. */
.venta-modal.modo-cat .vm-detalle{padding-left:12px;padding-right:12px;overflow-x:hidden}
/* 07-sep (v3): el pie mide su contenido — plegado = totales + ficha (el Detalle recupera el alto); la regla vive con el cajón v3 al final. */
.venta-modal.modo-cat .vm-foot{width:auto;flex:none;height:auto;max-height:none}
/* Detalle compacto en la columna angosta: sin Tarifa ni Desc. (siguen en el carrito, solo no se pintan) */
.venta-modal.modo-cat .vm-detalle .grid th:nth-child(2),.venta-modal.modo-cat .vm-detalle .grid td:nth-child(2),
.venta-modal.modo-cat .vm-detalle .grid th:nth-child(5),.venta-modal.modo-cat .vm-detalle .grid td:nth-child(5){display:none}
.venta-modal.modo-cat .vm-detalle .grid{font-size:13px}
.venta-modal.modo-cat .vm-detalle .grid td{padding:5px 8px}
.venta-modal.modo-cat .vm-detalle .grid th{padding:6px 8px}
@media (max-height:860px){
  .venta-modal.maximized.modo-cat .vm-foot{width:auto}
  .venta-modal.maximized.modo-cat #v-sec-agregar{padding-bottom:0}
}

/* ─── CANTIDAD Y DESCUENTO EDITABLES + ZOOM + TAMAÑO DE TARJETA (05-sep, pedido de Alejandro tras probar el catálogo) ─── */
/* Detalle (los dos modos): − N + y descuento % editables en la fila */
.det-step{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:7px;overflow:hidden;background:var(--surface-2);vertical-align:middle}
.det-step button{border:0;background:transparent;color:var(--text);width:22px;height:24px;font-size:15px;line-height:1;cursor:pointer;font-family:inherit;padding:0}
.det-step button:hover{background:var(--row-hover)}
.det-qty{width:46px;height:24px;border:0;background:transparent;text-align:center;font:inherit;font-size:13px;font-variant-numeric:tabular-nums;color:var(--text);padding:0 2px}
.det-qty:focus{outline:none;background:var(--surface);box-shadow:inset 0 0 0 2px var(--accent)}
.det-pct{width:46px;border:1px solid var(--border);border-radius:7px;background:var(--surface-2);text-align:right;padding:0 4px;margin-right:2px;vertical-align:middle}
.grid td.det-cant,.grid td.det-desc{white-space:nowrap}
/* Precio a mano (22-sep): con «Editar precios» la celda Precio del Detalle se escribe; el renglón tocado queda en
   naranja con ✎, y el campo Precio de la fila de captura se enmarca en naranja para decir que ya se puede escribir. */
.det-precio{width:92px;border:1px solid var(--border);border-radius:7px;background:var(--surface-2);text-align:right;padding:0 6px;vertical-align:middle}
.det-precio.manual,.det-manual{color:var(--accent-text);font-weight:700}
.det-manual{margin-right:4px;font-size:12px}
#v-precio.v-precio-abierto{border-color:var(--accent);box-shadow:var(--ring)}
/* Tarjeta: contador libre + Agregar + descuento; ya en la venta el contador va en slate */
.cat-accion{margin-top:auto;padding-top:4px;display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.cat-step{display:flex;align-items:center;border:1px solid var(--border);border-radius:var(--r-ctl);overflow:hidden;background:var(--surface-2);height:32px;flex:none}
.cat-step button{border:0;background:transparent;color:var(--text);width:24px;height:32px;font-size:16px;cursor:pointer;font-family:inherit;line-height:1;padding:0}
.cat-step button:hover{background:var(--row-hover)}
.cat-step .cat-qty{width:32px;height:30px;border:0;background:transparent;text-align:center;font:inherit;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--text);padding:0}
.cat-step .cat-qty:focus{outline:none;box-shadow:inset 0 0 0 2px var(--accent)}
.cat-step.en{background:linear-gradient(180deg,var(--btn-sec-hover) 0%,var(--btn-sec) 100%);border-color:var(--btn-sec-borde);box-shadow:inset 0 1px 0 rgba(255,255,255,.16),0 1px 2px rgba(16,24,40,.18)}
.cat-step.en button,.cat-step.en .cat-qty{color:var(--btn-sec-ink)}
.cat-step.en button:hover{background:rgba(255,255,255,.14)}
.cat-accion .cat-add,.cz-acciones .cat-add{flex:0 0 auto;width:auto;min-width:0;height:32px;padding:0 8px;font-size:12.5px;gap:3px}   /* width:auto: la regla base .cat-add lo ponía a 100 % y bajaba de fila */
.cat-add-ic{font-weight:700;font-size:15px;line-height:1}
.cat-en{flex:1;font-size:12px;font-weight:600;color:var(--ok);text-align:center;white-space:nowrap}
.cat-desc{display:flex;align-items:center;gap:4px;font-size:11.5px;color:var(--muted);width:100%}
.cat-desc .cat-pct{width:46px;height:24px;border:1px solid var(--border);border-radius:7px;background:var(--surface-2);text-align:right;font:inherit;font-size:12px;padding:0 4px;color:var(--text)}
.cat-desc .cat-pct:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
/* Lupa sobre la foto (aparece al pasar) */
.cat-foto{position:relative}
.cat-lupa{position:absolute;right:6px;top:6px;width:24px;height:24px;border-radius:7px;background:rgba(31,36,48,.55);color:#fff;display:inline-flex;align-items:center;justify-content:center;opacity:0;transition:opacity .12s ease;pointer-events:none}
.cat-card:hover .cat-lupa{opacity:1}
/* Zoom: foto grande + datos + la misma zona de acción */
.cat-zoom .cz-body{display:flex;gap:18px;padding:16px 20px;overflow:auto}
.cz-foto{width:380px;height:380px;flex:none;background:#fff;border-radius:var(--r-card);display:flex;align-items:center;justify-content:center;border:1px solid var(--border);padding:8px}
.cz-foto img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.cz-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:8px;align-items:flex-start}
.cz-nombre{font-size:16px;font-weight:600;line-height:1.3}
.cz-precio b{font-size:24px;font-variant-numeric:tabular-nums;font-family:var(--font-display)}
.cz-acciones{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:6px;width:100%}
.cz-acciones .cat-add{flex:0 0 auto;height:36px;padding:0 18px}
.cz-acciones .cat-desc{width:auto}
/* Tamaño de tarjeta S/M/L (segmentado claro, en el panel; el .seg del header es para el navy) */
.seg-tam{background:var(--surface-2);border:1px solid var(--border);margin-left:0;padding:2px;border-radius:7px}
.seg-tam button{color:var(--muted);padding:3px 9px;font-size:12px;border-radius:5px}
.seg-tam button:hover{background:var(--row-hover);color:var(--text)}
.seg-tam button.on{background:var(--violet);color:#fff}
[data-theme="oscuro"] .seg-tam button.on{color:#14161b}
.v-cat-grid.tam-s{grid-template-columns:repeat(5,minmax(0,1fr));gap:10px}
.v-cat-grid.tam-s .cat-foto{height:100px}
.v-cat-grid.tam-s .cat-add-txt{display:none}
/* En S (5 columnas) precio y existencia no caben en una línea: la etiqueta baja a la siguiente */
.v-cat-grid.tam-s .cat-fila{flex-wrap:wrap;gap:2px 6px}
.v-cat-grid.tam-s .cat-precio b{font-size:14px}
.v-cat-grid.tam-l{grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.v-cat-grid.tam-l .cat-foto{height:190px}
/* En modo catálogo el Detalle gana ancho (500) y muestra Desc.; solo se esconde Tarifa */
.venta-modal.modo-cat .vm-body{grid-template-columns:minmax(0,1fr) 520px}
/* Celdas más apretadas en la columna: con − N + y el descuento editable la tabla mide ~475px */
.venta-modal.modo-cat .vm-detalle .grid td{padding:5px 6px}
.venta-modal.modo-cat .vm-detalle .grid th{padding:6px 6px}
.venta-modal.modo-cat .vm-detalle .grid th:nth-child(5),.venta-modal.modo-cat .vm-detalle .grid td:nth-child(5){display:table-cell}

/* ─── MÉTODO DE PAGO como FICHAS (05-sep, propuesta B; la elegida en naranja). El <select> queda como estado oculto ─── */
.mp-sel{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden;left:0;bottom:0}
#v-metodo-wrap,#c-metodo-wrap{position:relative}
.mp-bar{display:flex;gap:8px;overflow-x:auto;scrollbar-width:thin;padding-bottom:2px;max-width:100%}
.mp-ficha{flex:none;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;width:96px;height:62px;border-radius:10px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font:600 11.5px/1.15 var(--font-ui);text-align:center;box-shadow:inset 0 1px 0 var(--sutil-brillo);cursor:pointer;padding:0 6px;transition:border-color .12s ease,box-shadow .12s ease}
.mp-ficha .ic{color:var(--muted);display:inline-flex}
.mp-ficha .ic svg{width:22px;height:22px}
.mp-ficha:hover{border-color:var(--border-hover)}
.mp-ficha.on{background-color:var(--accent);background-image:linear-gradient(115deg,#ffa53f 0%,#ee8c2a 45%,#f2705a 100%);border-color:transparent;color:var(--accent-ink);box-shadow:0 3px 10px rgba(238,140,42,.3)}
.mp-ficha.on .ic{color:inherit}
.mp-ficha:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* ─── Iconos de categoría (05-sep): botón por fila del gestor + rejilla de SOLO iconos; chips y hueco de foto del catálogo ─── */
.cat-row{grid-template-columns:auto 1fr 110px auto}
.cat-ico-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--border);background:var(--surface-2);color:var(--violet);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;flex:none;padding:0}
.cat-ico-btn.vacio{border-style:dashed;color:var(--muted)}
.cat-ico-btn:hover{border-color:var(--border-hover)}
#cat-dialog .vm-body{position:relative}
.cat-ico-pop{position:absolute;z-index:40;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-card);box-shadow:var(--shadow-md);padding:10px;width:392px;display:flex;flex-direction:column;gap:8px}
.cat-ico-pop[hidden]{display:none}
.cat-ico-grid{display:grid;grid-template-columns:repeat(9,1fr);gap:6px}
.cat-ico-grid button{height:36px;border-radius:8px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}
.cat-ico-grid button:hover{border-color:var(--border-hover);color:var(--violet)}
.cat-ico-grid button.on{border-color:var(--violet);background:color-mix(in srgb,var(--violet) 16%,transparent);color:var(--violet)}
.cat-ico-pie{display:flex;align-items:center;gap:10px;font-size:12px}
.v-cat-chips .chip{display:inline-flex;align-items:center;gap:6px}
.v-cat-chips .chip svg.ico-cat{width:15px;height:15px;flex:none}
.cat-sinfoto-ico svg.ico-cat{width:44px;height:44px;color:var(--violet);opacity:.8}
/* En la Caja maximizada el .fld va en fila (rótulo a la izquierda): la barra de fichas debe poder encoger y hacer scroll */
.venta-modal.maximized .vm-pago #v-metodo-wrap{flex:1 1 100%;min-width:0;flex-direction:column;align-items:stretch;gap:4px}   /* rótulo ARRIBA: así las 4 fichas (408 px) caben en la columna sin scroll */
#v-metodo-wrap .mp-bar,#c-metodo-wrap .mp-bar{flex:1;min-width:0}

/* ─── Vencimientos (06-sep-2026, opción B «Lotes al comprar»): semáforo de la columna Vence, cápsula de la Caja y modal Lotes ─── */
.badge.b-yel{background:rgba(212,160,23,.22);color:#7a5a00}
[data-theme="oscuro"] .badge.b-yel{background:rgba(212,160,23,.26);color:#f0cf6a}
.badge.b-mut{background:rgba(74,80,95,.12);color:var(--muted)}
/* AUDITORÍA (22-sep, pedido de Alejandro: «reajustar y ordenar las celdas… desalineadas y desiguales»): columnas de
   ancho FIJO y una sola línea en todo menos el Detalle, que es el único que se reparte en renglones. Lo que no cabe
   (una referencia larga, un usuario largo) se corta con «…» y se lee entero al pasar el ratón (title). */
#audit-list{table-layout:fixed}
#audit-list col.au-c-fecha{width:112px}
#audit-list col.au-c-hora{width:108px}
#audit-list col.au-c-accion{width:196px}
#audit-list col.au-c-ref{width:132px}
#audit-list col.au-c-monto{width:156px}
#audit-list col.au-c-usr{width:168px}
#audit-list td{vertical-align:middle;line-height:1.4;padding-top:8px;padding-bottom:8px}
#audit-list td:not(.au-det){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#audit-list td.au-fecha,#audit-list td.au-hora{font-variant-numeric:tabular-nums}
#audit-list td.au-hora{color:var(--muted)}
#audit-list td.au-det{overflow-wrap:anywhere}
#audit-list .badge{max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;letter-spacing:.02em}
.vence-cell{white-space:nowrap}
.cat-stock.medio{background:rgba(212,160,23,.2);color:#7a5a00;border-color:rgba(212,160,23,.45)}
[data-theme="oscuro"] .cat-stock.medio{color:#f0cf6a}
.cap-vence{margin-left:4px}
.cat-vence:empty{display:none}
.v-add-linea .inp-lote{width:96px}
.v-add-linea .inp-vence{width:138px;padding-right:6px}
.lotes-tbl .inp{height:30px;padding:0 8px;font-size:12.5px}
.lotes-tbl .inp-lote{width:110px}
.lotes-tbl .inp-vence{width:138px;padding-right:4px}
.lotes-tbl .inp-cnt{width:84px}
.lote-conteo{display:inline-flex;gap:4px;align-items:center}
.lote-ori{font-size:10.5px;color:var(--muted);display:block;white-space:nowrap}
.lote-sin td{background:var(--surface-2)}
.vi-vence{display:inline-flex;gap:6px;align-items:center;margin-right:14px}
.v-add-linea .fn-br{flex-basis:100%;height:0;margin:0;padding:0}

/* KPI del reporte «Por vencer» (06-sep, Setup 2): 4 tarjetas con subtítulo y color de banda */
.kpis-vence .kpi{position:relative;border-left:4px solid var(--border)}
.kpis-vence .kpi-sub{font-size:11.5px;margin-top:3px;line-height:1.25}
.kpi.vk-no{border-left-color:var(--no)}
.kpi.vk-warn{border-left-color:var(--accent)}
.kpi.vk-yel{border-left-color:#d4a017}
.kpi.vk-mut{border-left-color:var(--muted)}
.kpi.vk-no .kpi-val{color:var(--no)}
.kpi.vk-warn .kpi-val{color:var(--accent-text)}
.kpi.vk-yel .kpi-val{color:#7a5a00}
[data-theme="oscuro"] .kpi.vk-yel .kpi-val{color:#f0cf6a}

/* Compras (06-sep, pedido Alejandro): Lote/Vencimiento/I.V.A. por línea ocultos hasta activar el toggle */
#compra-dialog:not(.avz) .c-avz{display:none}
.c-avz-tog{align-self:flex-end}
.c-avz-tog.on{background:var(--violet);color:#fff;border-color:var(--violet)}
.c-avz-tog.on .ic16{fill:#fff}
/* Combo de Producto de +Nueva Compra un ~20% más corto (no debe acaparar toda la fila) */
#compra-dialog .v-fld-art{flex:4 1 190px;min-width:180px;max-width:460px}

/* ─── Cajón de pago deslizable (06-sep, pedido Alejandro): totales FUERA (siempre visibles) y lo de
   cobrar/pagar en un cajón que se asoma desde la esquina inferior derecha; la ficha es su cabecera ─── */
/* CAJÓN: la ficha (lengüeta) va SIEMPRE justo debajo de los totales (pedido v2) — plegada o abierta
   no se mueve, solo se despliega su cuerpo hacia abajo. ABIERTO crece (flex:1) y su cuerpo hace
   scroll interno si el modo (mixto) no cabe en pantallas bajas como la caja 1366×768; así los
   totales de arriba y el botón Guardar de abajo nunca se van de vista. */
.pago-cajon{width:100%;display:flex;flex-direction:column;overflow:hidden;flex:none;min-height:0}
.pago-cajon.abierto{flex:1 1 auto}
.pago-ficha{display:flex;align-items:center;gap:9px;width:100%;padding:9px 14px;border:0;border-radius:11px;cursor:pointer;color:#14181f;font-weight:700;font-size:14px;font-family:var(--font-display);background-image:linear-gradient(115deg,#ffa53f 0%,#ee8c2a 45%,#f2705a 100%);box-shadow:0 2px 8px rgba(238,140,42,.3)}
.pago-ficha .pf-ic{width:20px;height:20px;flex:none}
.pago-ficha .pf-txt{margin-right:auto}
.pago-ficha .pf-chev{width:18px;height:18px;flex:none;transition:transform .2s ease}
.pago-ficha:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.pago-cajon.abierto .pago-ficha{border-radius:11px 11px 0 0}
.pago-cajon:not(.abierto) .pago-ficha .pf-chev{transform:rotate(180deg)}
.pago-body{overflow-y:auto;flex:1 1 auto;min-height:0;max-height:900px;opacity:1;transform:translateY(0) scale(1);transform-origin:bottom right;transition:max-height .22s ease,opacity .18s ease,transform .22s ease;background:var(--surface-2);border:1px solid var(--border);border-top:0;border-radius:0 0 11px 11px;padding:10px 14px;display:flex;flex-direction:column;align-items:flex-end;gap:8px}
/* Los botones se quedan pegados al fondo del cajón: si el cuerpo hace scroll (mixto en pantalla
   baja), "Guardar" sigue siempre a la vista. El fondo tapa lo que scrollea por detrás. */
.pago-body .vm-btns{position:sticky;bottom:-10px;z-index:1;background:var(--surface-2);width:100%;padding:8px 0 2px;margin-top:2px}
/* Sombra sutil arriba de los botones: avisa que hay controles scrolleando por detrás (mixto en
   pantalla baja). Solo cuando el cuerpo realmente scrollea. */
.pago-body{scrollbar-width:thin}
.pago-body .vm-btns::before{content:"";position:absolute;left:0;right:0;top:-10px;height:10px;pointer-events:none;background:linear-gradient(to top,var(--surface-2),transparent)}
.pago-cajon:not(.abierto) .pago-body{max-height:0;opacity:0;transform:translateY(10px) scale(.96);padding-top:0;padding-bottom:0;border-color:transparent}
.pago-body .vm-pago{border-top:0;padding-top:0}
@media (prefers-reduced-motion: reduce){.pago-body{transition:none}.pago-ficha .pf-chev{transition:none}}
/* Forma de pago: control segmentado unificado (venta y compra) */
.seg-fld{flex-direction:row!important;align-items:center;gap:8px}
.seg-pago{display:inline-flex;border:1px solid var(--border);border-radius:9px;overflow:hidden;background:var(--surface-2);box-shadow:inset 0 1px 0 var(--sutil-brillo)}
.seg-pago button{border:0;background:transparent;padding:6px 13px;font-size:12.5px;font-weight:600;color:var(--muted);cursor:pointer;font-family:var(--font-ui)}
.seg-pago button.on{background:var(--violet);color:#fff}
[data-theme="oscuro"] .seg-pago button.on{color:#14161b}

/* ─── CAJÓN v3 (07-sep, pedido Alejandro tras tocar la v2): UNA columna en su orden — Forma de pago · Moneda de Pago +
   casillas · Método + fichas en una fila · (contado/abonado del mixto) · imprimir/IVA · botones —, la FICHA-LENGÜETA SIEMPRE
   ABAJO del pie y el cuerpo desplegándose hacia ARRIBA, completo, sin barra de scroll (también a 1366×768). El pie de los
   modales maximizados queda en 520 px (las 4 fichas y los 4 botones caben en una fila) y se compactan totales, filas de
   moneda, fichas (44 px) y botones para que el peor caso (mixto) quepa entre los totales y la ficha. En el modo Catálogo
   de la Caja el pie mide lo que mide: plegado = totales + ficha → el Detalle recupera todo el alto (el fin del pedido). ─── */
.venta-modal.maximized .vm-foot{width:520px;padding:4px 16px 5px;gap:4px}
.venta-modal.maximized .vm-tot{gap:0}
.venta-modal.maximized .vm-tot span{font-size:13.5px;line-height:1.2}
.venta-modal.maximized .vm-tot .big{gap:6px}
.venta-modal.maximized .vm-tot .big b{font-size:22px;line-height:1.1}
/* La ficha ABAJO: el cajón va al fondo del pie (margin-top:auto) y se pinta invertido (column-reverse: cuerpo arriba,
   ficha abajo). Abierto crece hacia arriba; el espacio que sobre queda entre los totales y el cuerpo. */
.pago-cajon{margin-top:auto;flex-direction:column-reverse}
.pago-cajon.abierto{flex:1 1 auto;min-height:0}
.pago-ficha{padding:5px 14px;border-radius:11px}
.pago-cajon.abierto .pago-ficha{border-radius:0 0 11px 11px}
.pago-cajon:not(.abierto) .pago-ficha .pf-chev{transform:none}
.pago-cajon.abierto .pago-ficha .pf-chev{transform:rotate(180deg)}
.pago-body{flex:0 1 auto;min-height:0;border:1px solid var(--border);border-bottom:0;border-radius:11px 11px 0 0;padding:calc(4px + var(--aire, 16px) / 4) 12px calc(5px + var(--aire, 16px) / 4);gap:4px;transform-origin:bottom right;align-items:stretch}
.pago-cajon:not(.abierto) .pago-body{padding-top:0;padding-bottom:0;border-color:transparent}
.pago-body .vm-pago{display:flex;flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:4px;padding-top:0;border-top:0;width:100%}
.pago-body .vm-pago .seg-fld{flex-direction:row;align-items:center;gap:8px;width:100%}
.seg-pago button{padding:4px 12px}
.pago-cajon{--aire:16px}   /* 0.92: aire ENTRE secciones (16 = ≈ +20 % sobre la 0.90); app.js lo reduce solo si el cuerpo no cabe */
.pago-lbl{font-size:12px;font-weight:600;color:var(--text);line-height:1.1;margin-top:calc(2px + var(--aire, 16px))}
.pago-body .vm-monedas{gap:2px;width:100%}
.pago-body .vm-mon{min-height:19px;font-size:13px}
.venta-modal.maximized .pago-body .vm-mon b{font-size:14px}
.pago-body #v-metodo-wrap,.pago-body #c-metodo-wrap{flex:none;width:100%;flex-direction:column;align-items:stretch;gap:3px}
.pago-body #v-metodo-wrap .mp-bar,.pago-body #c-metodo-wrap .mp-bar{flex:none;flex-wrap:nowrap;gap:6px;overflow:visible;padding-bottom:0;width:100%}
.pago-body .mp-ficha{height:54px;width:auto;flex:1 1 0;max-width:112px;min-width:78px;gap:4px;font-size:11px;padding:0 4px}   /* 0.93: +10 % arriba y abajo (44→54) */
.pago-body .mp-ficha .ic svg{width:18px;height:18px}
.pago-body #v-contado-wrap,.pago-body #c-contado-wrap,.pago-body #v-propina-wrap{flex:none;width:100%;flex-direction:row;align-items:center;gap:6px;flex-wrap:wrap}
.pago-body #v-monto-contado,.pago-body #c-monto-contado,.pago-body #v-propina{max-width:120px;flex:1 1 90px;min-width:80px}
.pago-body #v-credito-info,.pago-body #c-deuda-aviso,.pago-body #v-apagar{font-size:12px;line-height:1.25;width:100%}
.pago-body .vm-print-auto,.pago-body .vm-iva{margin-top:2px;font-size:12.5px}
.pago-body .vm-btns{position:static;padding:calc(2px + var(--aire, 16px) * .75) 0 0;margin:0;width:100%}
.pago-body .vm-btns::before{display:none}
.pago-body .vm-btns .btn-primary,.pago-body .vm-btns .btn-ghost{padding:4px 12px}
.pago-body #v-cot-msg:empty{display:none}
/* Compras: el aviso del re-precio deja de RESERVAR un renglón bajo la fila de captura (va arriba a la derecha, junto al
   título «Agregar producto», sin ocupar alto): ese renglón es justo lo que le faltaba al cajón en mixto a 768 px. */
#compra-dialog .vm-sec:has(#c-util-aviso){position:relative}
#compra-dialog .c-util-aviso{position:absolute;top:8px;right:20px;min-height:0;margin:0;max-width:62%;text-align:right;white-space:normal;line-height:1.2}
/* Compactación medida por bloques (07-sep): la regla del media ≤860 (.venta-modal.maximized .vm-pago) ponía gap 6 y
   padding-top 6 → aquí con más especificidad; inputs de contado/abonado/propina a 28 px; filas de moneda a 20 px. */
.venta-modal.maximized .pago-body .vm-pago{gap:3px;padding-top:0}
.venta-modal.maximized .pago-body .vm-monedas{gap:2px}
.venta-modal.maximized .pago-body .vm-mon{min-height:20px}
.pago-body #v-contado-wrap .inp,.pago-body #c-contado-wrap .inp,.pago-body #v-propina-wrap .inp{height:28px;padding:3px 8px}
.pago-body .vm-print-auto,.pago-body .vm-iva{margin-top:calc(1px + var(--aire, 16px))}
/* «Factura en esta moneda» (21-sep, pedido de Alejandro) comparte renglón con el rótulo «Moneda de Pago:»:
   ese hueco ya estaba vacío, es donde se elige la moneda, y así la casilla no le cuesta un renglón al cajón.
   🪤 Aquí vivió un rato `.vm-print-row .vm-print-auto ~ .vm-print-auto{margin-top:2px}`, de cuando la casilla
   nueva iba en la fila de imprimir y la hacía envolver: al mudarla a este renglón la regla dejó de hacer falta
   y solo levantaba «Guardar en digital» 7,5 px sobre «Imprimir recibo» — desnivel que Alejandro vio a ojo. Las
   dos casillas de esa fila comparten el mismo margen de arriba y se quedan así. */
.pago-lbl-fila{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.vm-fact-pago{display:flex;align-items:center;gap:5px;font-size:12px;font-weight:400;color:var(--muted);cursor:pointer;user-select:none}
.vm-fact-pago input{margin:0}
/* «Datos de la venta» en UNA línea: la Nota cede ancho (crece igual) y «Permitir sobregiro» sube a su derecha → el pie de
   la Caja gana ~35 px de alto para el cajón. */
.venta-modal.maximized #v-row-top .fld.grow{flex:1 1 130px;min-width:130px}
.venta-modal.maximized #v-row-top .fld.grow .inp.grow{flex:none;width:100%;min-width:0}
/* 0.92: el aire es GRADUADO (--aire, 16 px máx.): si el cuerpo no cabe (p. ej. 2 inventarios a 768 px en mixto), app.js
   baja --aire justo lo necesario (cada px de aire son ~3,75 px de alto) en vez de saltar a compacto. */
/* Modo Catálogo de la Caja: el pie mide su contenido (plegado: totales + ficha; abierto: + el cajón completo) */
.venta-modal.modo-cat .vm-foot{width:auto;flex:none;height:auto;max-height:none}

/* ─── INVENTARIO EN MODO CATÁLOGO (07-sep-2026, pedido Alejandro: la misma alternancia Tabla | Catálogo de
   +Nueva venta). Cada tarjeta trae TODOS los datos de la fila; la foto se agrega o cambia pulsando el marco;
   tamaños S/M/L/XL con columnas que se ajustan al ancho (auto-fill); la barra de categorías va encima. ─── */
.inv-vista{margin-left:0}
.inv-vista button{display:inline-flex;align-items:center;gap:5px}
.inv-vista button .ic16{width:14px;height:14px;margin:0;fill:currentColor}
.tabla-scroll .inv-cat-tabla{width:100%;min-width:0;table-layout:fixed}
.inv-cat-tabla thead{display:none}   /* el estado del autofiltro/orden sigue ahí (inputs), sin pintarse */
.tabla-scroll .inv-cat-tabla td{white-space:normal}
.inv-cat-tabla .inv-cat-row>td{padding:12px 14px 6px;background:var(--surface)}
.inv-cat-tabla .inv-cat-row:hover>td{background:var(--surface)}
.inv-cat-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px}
/* Barra de categorías: nombres completos en una fila que se desplaza (como en la Caja) + el gestor al final */
.inv-cat-chips{flex:1 1 640px;min-width:0;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;padding-bottom:6px;scrollbar-width:thin;scrollbar-color:var(--border-hover) var(--surface-2);align-items:center}
.inv-cat-chips::-webkit-scrollbar{height:8px}
.inv-cat-chips::-webkit-scrollbar-track{background:var(--surface-2);border-radius:6px}
.inv-cat-chips::-webkit-scrollbar-thumb{background:var(--border-hover);border-radius:6px}
.inv-cat-chips .chip{padding:5px 12px;font-size:13px;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;flex:none}
.inv-cat-chips .chip svg.ico-cat{width:15px;height:15px;flex:none}
.inv-cat-gear{flex:none;padding:5px 9px;margin-left:2px}
.inv-cat-gear .ic16{margin:0}
.inv-cat-n{font-size:12px;white-space:nowrap}
.inv-cat-orden{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;color:var(--muted);white-space:nowrap}
.inv-cat-orden .inp{height:32px;padding:0 6px;font-size:12px;width:auto;max-width:150px}
.inv-cat-top .spacer{flex:0 0 0}   /* 0.92: todo el ancho sobrante va a la barra de categorías */
/* Columnas FIJAS por tamaño (decisión Alejandro 07-sep, como en la Caja): S 6 · M 5 · L 4 · XL 3, en cualquier ancho */
.inv-cat-grid{display:grid;gap:12px;grid-template-columns:repeat(5,minmax(0,1fr))}
.inv-cat-grid.tam-s{grid-template-columns:repeat(6,minmax(0,1fr));gap:10px}
.inv-cat-grid.tam-l{grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}
.inv-cat-grid.tam-xl{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.ic-card{display:flex;flex-direction:column;border:1px solid var(--border);border-radius:var(--r-card);background:var(--surface);overflow:hidden;box-shadow:var(--shadow-sm)}
.ic-card:hover{border-color:var(--border-hover);box-shadow:var(--shadow-md)}
.ic-card.ic-cargando .ic-foto{opacity:.45}
/* La foto va sobre BLANCO aunque el tema sea oscuro: es contenido (fotos de producto), como en la Caja */
.ic-foto{position:relative;height:150px;background:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:6px;flex:none;border-bottom:1px solid var(--border)}
.inv-cat-grid.tam-s .ic-foto{height:112px}
.inv-cat-grid.tam-l .ic-foto{height:200px}
.inv-cat-grid.tam-xl .ic-foto{height:250px}
.ic-foto img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.ic-foto .cat-sinfoto{font-size:11px}
.ic-foto-cta{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;gap:6px;padding:5px 8px;background:rgba(31,36,48,.72);color:#fff;font-size:11.5px;font-weight:600;opacity:0;transition:opacity .12s ease;pointer-events:none}
.ic-foto-cta i{font-style:normal}
.ic-foto-cta svg{flex:none}
.ic-foto:hover .ic-foto-cta,.ic-sinfoto .ic-foto-cta{opacity:1}
.ic-sinfoto .ic-foto-cta{background:color-mix(in srgb,var(--violet) 80%,transparent)}
.ic-foto-x{position:absolute;right:6px;top:6px;width:24px;height:24px;border-radius:7px;border:0;background:rgba(31,36,48,.6);color:#fff;font-size:13px;cursor:pointer;opacity:0;transition:opacity .12s ease;display:inline-flex;align-items:center;justify-content:center;padding:0;line-height:1}
.ic-foto:hover .ic-foto-x{opacity:1}
.ic-foto-x:hover{background:var(--no)}
.ic-info{padding:8px 10px 10px;display:flex;flex-direction:column;gap:5px;flex:1;font-size:12.5px}
.ic-l1{display:flex;align-items:center;justify-content:space-between;gap:6px}
.ic-cod{font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ic-nombre{font-size:13px;font-weight:600;line-height:1.25;height:33px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.ic-sub{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:11.5px;color:var(--muted);min-width:0}
.ic-sub>span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-flex;align-items:center;gap:4px;min-width:0}
.ic-sub svg.ico-cat{width:13px;height:13px;flex:none}
.ic-precios{display:flex;flex-direction:column;gap:2px;margin-top:2px}
.ic-p{display:flex;align-items:center;gap:6px;white-space:nowrap}
.ic-k{font-size:10.5px;font-weight:700;letter-spacing:.05em;color:var(--muted);width:38px;flex:none}
.ic-v{font-variant-numeric:tabular-nums;font-weight:600;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.ic-v .cur{margin-right:3px}
.ic-costo{font-weight:500}
.ic-util{font-size:11px;font-weight:700;padding:1px 6px;border-radius:5px;flex:none;font-variant-numeric:tabular-nums}
.ic-fila{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:2px}
.ic-exist{border:1px solid var(--border);background:var(--surface-2);border-radius:20px;padding:2px 9px;font-size:11.5px;font-weight:600;cursor:pointer;color:var(--text);font-family:inherit;text-decoration:none;line-height:1.4}
.ic-exist b{font-variant-numeric:tabular-nums}
.ic-exist.ex-r,.ic-exist.ex-y,.ic-exist.ex-g{border-color:transparent}
.ic-exist.kardex-link:hover{box-shadow:inset 0 0 0 2px var(--accent)}
span.ic-exist{cursor:default}
.ic-vence{display:inline-flex;align-items:center;text-decoration:none}
.ic-vence .badge{cursor:pointer}
.ic-vence.kardex-link:hover{box-shadow:none}
.ic-vence.kardex-link:hover .badge{box-shadow:inset 0 0 0 2px var(--accent)}
.ic-tog .toggle{font-size:11px;padding:2px 9px 2px 19px}
.ic-acc{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-top:auto;padding-top:4px}
.ic-btn{height:28px;padding:0 10px;font-size:12px;display:inline-flex;align-items:center;gap:4px}
.ic-btn .ic16{margin:0;width:14px;height:14px}
.ic-del{opacity:.55}
.inv-mas.inv-cat-mas{grid-column:1/-1;text-align:center;color:var(--muted);font-size:12.5px;padding:12px}
.inv-cat-vacio{grid-column:1/-1;text-align:center;padding:28px 10px;color:var(--muted);display:flex;flex-direction:column;gap:4px}
.inv-cat-vacio b{color:var(--text);font-size:14px}
/* S: sin la utilidad junto al precio (no cabe) · XL: texto un punto más grande */
.inv-cat-grid.tam-s .ic-p .ic-util{display:none}
.inv-cat-grid.tam-s .ic-k{width:34px}
.inv-cat-grid.tam-s .ic-info{padding:7px 8px 8px}
.inv-cat-grid.tam-xl .ic-nombre{font-size:14px;height:36px}
.inv-cat-grid.tam-xl .ic-info{font-size:13.5px}
/* ─── «EDICIÓN GENERAL» del inventario (07-sep, decisión de Alejandro: Tabla y Catálogo nacen en solo lectura; un botón
   abre la edición en la vista actual, como la "Modificación Masiva" del Excel). El botón en naranja Aurora cuando está
   activo y un aro naranja alrededor del inventario mientras se edita. ─── */
.inv-edit-btn{gap:6px}
.inv-edit-btn.on{background-color:var(--accent);background-image:linear-gradient(115deg,#ffa53f 0%,#ee8c2a 45%,#f2705a 100%);color:var(--accent-ink);border-color:transparent;box-shadow:0 3px 10px rgba(238,140,42,.3)}
.inv-edit-btn.on .ic16{fill:currentColor}
.tabla-scroll:has(#tabla[data-edit="1"]){box-shadow:0 0 0 2px var(--accent),var(--shadow)}
/* Píldoras de Estado / I.V.A. en solo lectura: mismo look, sin gesto */
.toggle.tog-static{cursor:default;pointer-events:none}
/* Tarjeta en solo lectura: el marco de la foto no es un botón */
.ic-foto.ic-ro{cursor:default}
/* Tarjeta en edición: campos en línea */
.ic-inp{height:26px;padding:2px 6px;font-size:12.5px;width:100%;min-width:0;border-radius:6px;font-weight:500}
.ic-inp.num{text-align:right;font-variant-numeric:tabular-nums}
.ic-inp-nombre{font-weight:600}
.ic-nombre-ed{height:auto;display:block;overflow:visible;-webkit-line-clamp:unset}
.ic-l1 .ic-inp-cod{width:auto;flex:1 1 80px;font-size:11.5px;height:24px}
.ic-sub .ic-inp-marca{width:auto;flex:1 1 70px;font-size:11.5px;height:24px}
.ic-v-ed{display:inline-flex;align-items:center;gap:3px;flex:1;min-width:0}
.ic-v-ed .ic-inp{flex:1 1 60px;width:auto}
.ic-util-inp{width:66px;flex:none;padding:2px 4px}
.ic-edit .ic-p{gap:5px}
.inv-cat-grid.tam-s .ic-edit .ic-util-inp{display:none}
/* Precio y utilidad en la misma línea: sin spinners de number (se comían el ancho) y basis mínimos claros */
.ic-inp[type="number"]{appearance:textfield;-moz-appearance:textfield}
.ic-inp[type="number"]::-webkit-outer-spin-button,.ic-inp[type="number"]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.ic-v-ed .ic-inp{flex:1 1 44px;min-width:44px;padding:2px 5px}
.ic-util-inp{width:58px;min-width:58px;padding:2px 4px}
.ic-edit .ic-k{width:34px}

/* ─── «Precio COP (coin)» → ver el precio en OTRA moneda al clic (07-sep, pedido Alejandro, 2ª forma): el rótulo cicla
   COP → USD → VES → COP; mientras la vista no es la moneda propia, un overlay sobre la celda muestra el precio convertido
   con la tasa del día y el campo queda en solo lectura (conserva el valor real). Al agregar vuelve a la moneda propia. ─── */
.v-fld-precio{position:relative}
.v-pv-lbl{cursor:pointer;user-select:none;display:inline-flex;align-items:center;gap:4px}
.v-pv-lbl:hover #v-precio-mon{text-decoration:underline dotted;text-underline-offset:3px}
.v-pv-coin{display:inline-flex;line-height:0}
.v-pv-coin .coin{margin:0;display:block}
.v-pv-otra{position:absolute;left:0;bottom:0;display:none;align-items:center;justify-content:flex-end;padding:0 10px;box-sizing:border-box;border-radius:var(--r-ctl);border:1px solid var(--accent);background:var(--surface);color:var(--accent-text);font-weight:700;font-variant-numeric:tabular-nums;font-size:14px;cursor:pointer;box-shadow:var(--ring);z-index:2;white-space:nowrap}
.v-pv-ro{opacity:.35}
/* Visor de moneda del modo Catálogo: (USD) (VES) (COP), COP por defecto; solo pinta, se agrega en la base */
.cat-ver button{display:inline-flex;align-items:center;gap:4px}
.cat-ver .coin{margin:0}
.cat-ref{font-style:normal;font-weight:400;color:var(--muted);margin-right:2px}

/* ─── Ajuste MASIVO de existencias (07-sep, pedido Alejandro): lista de la vista con la celda «Real (contada)» ─── */
.aje-scroll{max-height:52vh;overflow:auto;margin-top:10px}
.aje-t td{padding:5px 8px;vertical-align:middle}
.aje-t .aje-inp{width:112px;text-align:right;height:30px;padding:3px 8px}
.aje-t tr.aje-cambia td{background:color-mix(in srgb,var(--accent) 12%,transparent)}
.aje-resumen{font-weight:600;white-space:nowrap;padding-bottom:9px}
/* Documento digital (07-sep, pedido Alejandro): los dos checkbox del cajón en una fila y el estado «✓ PDF guardado · Abrir carpeta · Descargar». */
.vm-print-row{display:flex;flex-wrap:wrap;align-items:center;gap:0 14px}
.dig-estado{font-size:12.5px;display:inline-flex;flex-wrap:wrap;align-items:center;gap:0 5px}
.dig-link{font:inherit;font-size:12.5px;color:var(--violet);background:none;border:none;padding:0;cursor:pointer;text-decoration:underline dotted;text-underline-offset:3px}
.dig-link:hover{color:var(--accent)}
/* Segmentados «Formato» y «Destino» del guardado en digital (08-sep, pedido de Alejandro): salen SOLO con la casilla
   «Guardar en digital al guardar» marcada y son dos alternadores de UNA opción, con el mismo molde que el
   «Forma de pago» (.seg-pago) para que la Caja hable un solo idioma: |PDF|Imagen| y |Guardar en carpeta|Guardar en
   Destino|. Ocupan su propia línea, alineados a la derecha como el resto del cajón. */
.dig-opts{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:6px;width:100%}
/* 🪤 SIN esta regla los segmentados NO se escondían: el atributo hidden solo apaga el elemento por la hoja del
   navegador ([hidden]{display:none}), y la regla de arriba —más específica— la pisaba. Se veían SIEMPRE, con la
   casilla marcada o no (lo reportó Alejandro el 08-sep). El resto de clases del proyecto que usan hidden ya
   llevaban la suya (.v-combo-list, .th-menu, .cat-ico-pop, .setup-paso, .v-cat…). */
.dig-opts[hidden]{display:none}
/* Separación propia, con un mínimo garantizado (5 px arriba, 3 abajo) que el auto-apretado del cajón NO puede
   quitar: él pidió que no quedaran pegadas a las casillas ni a los botones de abajo. Con aire disponible crece. */
.pago-body .dig-opts{margin-top:calc(5px + var(--aire, 16px) * .45);margin-bottom:calc(3px + var(--aire, 16px) * .25)}
.dig-opts .seg-dig{max-width:100%}
.seg-dig button{padding:5px 11px;font-size:12px}
/* Ajuste de existencias (07-sep, pedido Alejandro): botón ⛶ que extiende el modal a toda la pantalla; la lista toma el alto sobrante. */
#aje-dialog{max-width:940px}
#aje-dialog.maximized{max-width:100vw}
#aje-dialog.maximized .vm-body{display:flex;flex-direction:column;height:calc(100vh - 60px);max-height:none}
#aje-dialog.maximized #aje-body{display:flex;flex-direction:column;flex:1;min-height:0}
#aje-dialog.maximized #aje-form{display:flex;flex-direction:column;flex:1;min-height:0;height:auto;max-height:none}
#aje-dialog.maximized .aje-scroll{flex:1;min-height:0;max-height:none}

/* ─── Card «Usuarios de caja móvil» (Ajustes, 09-sep-2026) ─── */
.usu-lista{display:flex;flex-direction:column;margin:8px 0 4px}
.usu-row{display:flex;align-items:center;flex-wrap:wrap;gap:6px 10px;padding:7px 0;border-bottom:1px solid var(--border)}
.usu-row:last-child{border-bottom:0}
.usu-nom{min-width:120px}
.usu-off .usu-nom{opacity:.55;text-decoration:line-through}
.usu-nota{font-size:12px}
.usu-inline{display:inline-flex;align-items:center;gap:6px;margin:0}
.usu-row .btn-ghost,.usu-row .btn-primary,.usu-clave summary{padding:4px 10px;font-size:12.5px}
.usu-clave{display:inline-block}
.usu-clave summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:var(--r-ctl);background:var(--surface-2);font-weight:600}
.usu-clave summary::-webkit-details-marker{display:none}
.usu-clave[open] summary{margin-bottom:6px}
/* Teléfonos emparejados (11-sep): la card de Ajustes */
.disp-cod{font-family:'IBM Plex Mono',ui-monospace,Consolas,monospace;font-weight:700;font-size:15px;letter-spacing:.08em;background:var(--surface-2);border:1px solid var(--border);border-radius:var(--r-ctl);padding:3px 9px;white-space:nowrap}
.disp-row .inp-sm{width:180px;padding:4px 8px;font-size:12.5px}
.disp-info{font-size:12.5px}
.disp-pend{background:rgba(238,140,42,.07);border-radius:8px;padding-left:6px;padding-right:6px}
.disp-vacio{margin:8px 0 4px}
.disp-refrescar{padding:3px 9px;font-size:12px;margin-left:6px;vertical-align:baseline}
#disp-card .resp-pie{word-break:normal;overflow-wrap:break-word}
.usu-clave .inp{width:150px;padding:5px 8px}
.usu-nuevo{margin-top:10px;padding-top:10px;border-top:1px dashed var(--border)}

/* ═══ TELÉFONO (09-sep-2026, «Exynol en el teléfono», primer paso): hasta 720 px el sistema se acomoda a una
   pantalla angosta. Es el MISMO servidor y las MISMAS pantallas (un usuario de caja móvil entra por el navegador
   del teléfono en el Wi-Fi del negocio, como una caja en red); solo cambia cómo se distribuyen. Sin cámara: el
   buscador, las categorías y el modo Catálogo hacen el trabajo del lector de barras (decisión de Alejandro). ═══ */
@media (max-width:720px){
  .appbar{padding:6px 10px;gap:8px}
  .appbar .ex-tag,.appbar .ex-soft{display:none}
  .appbar .ex-exy{height:22px}
  .appbar-title{font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
  .appbar .btn-tema{padding:6px 9px;font-size:12px}
  .tema-movil{display:inline-flex;align-items:center;justify-content:center}
  .appbar-pie{font-size:10px}
  .launcher{flex-wrap:nowrap;overflow-x:auto;padding:4px 8px;gap:2px;scrollbar-width:none}
  .launcher::-webkit-scrollbar{display:none}
  .tile{min-width:64px;padding:6px 6px}
  .tile .ic,.tile .ic svg{width:24px;height:24px}
  .tile .lbl{font-size:11px}
  .content{padding:10px}
  .toolbar{gap:6px;margin-bottom:8px}
  .inp,select.inp{font-size:16px}   /* con letra ≥ 16 px iOS no hace zoom al enfocar un campo */
  .tabla-scroll{max-width:100%}
  /* La Caja a pantalla completa, en UNA columna que se desplaza; en Catálogo las tarjetas primero, a dos por fila,
     y debajo los datos de la venta, el Detalle y el cajón Cobrar. */
  .venta-modal,.venta-modal.maximized{width:100vw;max-width:100vw;height:100vh;max-height:100vh;border-radius:0}
  .venta-modal form,.venta-modal.maximized form{max-height:100vh;height:100vh}
  .venta-modal .vm-head{padding:8px 10px;gap:6px;flex-wrap:wrap;border-radius:0}
  .venta-modal .vm-head h2{font-size:16px}
  .venta-modal .prox-venta{font-size:12px}
  .venta-modal .seg{margin-left:0}
  .venta-modal .vm-body{display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch}
  .venta-modal .vm-sec{padding:8px 10px}
  .venta-modal .vm-row-top{display:flex;flex-direction:column;flex:none}
  .venta-modal .vm-row-top .vm-sec:nth-child(2){display:none}   /* Tasas del día: en el teléfono valen las fijadas en la PC */
  .venta-modal .fn-row .fld{flex:1 1 45%;min-width:0}
  .venta-modal .v-add-wrap{flex-direction:column;gap:8px}
  .venta-modal .v-img-box{display:none}
  .venta-modal.modo-cat .vm-body{display:flex;flex-direction:column}
  /* Su lienzo (09-sep): el catálogo ocupa la pantalla (al menos 4 tarjetas a la vista: fotos más bajas y solo tamaño M),
     y debajo, al desplazar, Datos de la venta, Detalle y el cajón Cobrar. */
  .venta-modal.modo-cat #v-sec-agregar{order:-1;border-right:0;border-bottom:1px solid var(--border);flex:none;height:calc(100vh - 56px);min-height:640px;max-height:none}
  .venta-modal .v-cat-grid .cat-foto{height:96px}
  .venta-modal #cat-tam{display:none}
  /* El cajón Cobrar no puede quedar pegado al borde: la barra del navegador del teléfono lo tapaba. Aire al final del
     cuerpo (más la zona segura del teléfono) para que suba entero al desplazar. */
  .venta-modal .vm-body::after{content:"";display:block;flex:none;height:calc(120px + env(safe-area-inset-bottom, 0px))}
  /* Su lienzo (09-sep): en modo Catálogo el buscador vive en la cabecera del modal, en su propia fila y a todo el ancho,
     con la ✕ al lado (el espaciador deja de crecer para que el buscador ocupe la fila). */
  .venta-modal .vm-head .v-cat-buscar{flex:1 1 200px;min-width:0}
  .venta-modal.modo-cat .vm-head .vm-spacer{flex:0 0 0}
  .venta-modal .vm-head .v-cat-buscar .inp{height:38px;width:100%}
  .venta-modal.modo-cat .vm-row-bottom{flex:none;display:flex;flex-direction:column}
  .v-cat-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .v-cat-top{gap:6px 8px}
  .v-cat-top .inp{min-width:0;flex:1 1 160px}
  .venta-modal .vm-foot,.venta-modal.maximized .vm-foot{width:100%;padding:8px 10px}
  .venta-modal .vm-detalle .grid{font-size:12.5px}
  .venta-modal .vm-detalle{padding-left:6px;padding-right:6px}
  .pago-body .vm-pago{gap:4px}
  .cfg-page{display:flex;flex-direction:column}
  .usu-row .usu-nom{min-width:0;flex:1 1 100%}
}

/* ─── GASTOS (10-sep-2026): detalle del gasto, formulario del modal y ajustes de teléfono ─── */
.gasto-det th{width:150px;text-align:left;color:var(--muted);font-weight:600;font-size:12.5px;vertical-align:top;background:transparent;text-transform:none;letter-spacing:0}
.gasto-det td,.gasto-det th{padding:6px 12px;border-top:1px solid var(--border)}
.gasto-form .fn-row .fld.grow{flex:1 1 240px}
#gastos-list .row-anulada td{opacity:.6}
@media (max-width:720px){
  .gasto-form .fn-row .fld{flex:1 1 45%;min-width:0}
  .gasto-form .fn-row .fld.grow{flex:1 1 100%}
  .gasto-form .fn-row .btn-primary{flex:1 1 100%;justify-content:center}
  #gastos-toolbar select.inp{max-width:48%}
  #gdet-dialog .vi-bar{flex-wrap:wrap;gap:6px}
  .gasto-form .fn-row .inp,.gasto-form .fn-row select.inp{height:40px}   /* con letra de 16 px los 34 px cortaban el texto de los selectores */
}

/* ─── COMPRAS 0.109 (10-sep): modo Catálogo, panel de imagen, interruptor Lote/Venc./I.V.A. y stepper del detalle ─── */
.c-sec-tit{display:flex;align-items:center;gap:12px}
.c-sec-tit>span:first-child{flex:none}
/* Interruptor (switch) — reemplaza al botón «Lote / Venc. / I.V.A.» */
.sw{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-size:12px;font-weight:600;color:var(--muted);margin-left:14px;text-transform:none;letter-spacing:0;position:relative;user-select:none;font-family:var(--font-ui)}
.sw input{position:absolute;opacity:0;width:0;height:0;margin:0}
.sw-track{width:36px;height:20px;border-radius:20px;background:var(--border-hover);position:relative;transition:background .15s ease;flex:none;box-shadow:inset 0 1px 2px rgba(0,0,0,.18)}
.sw-knob{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:left .15s ease;box-shadow:0 1px 2px rgba(0,0,0,.3)}
.sw input:checked+.sw-track{background:var(--accent)}
.sw input:checked+.sw-track .sw-knob{left:18px}
.sw input:focus-visible+.sw-track{box-shadow:var(--ring)}
.sw input:checked~.sw-lbl{color:var(--text)}
.sw:hover .sw-lbl{color:var(--text)}
/* Panel de imagen: el rótulo «Sin imagen» se esconde con foto (la regla de la Caja apuntaba a #v-img-ph) */
.v-img-box.con-img .img-ph{display:none}
/* 11-sep, su lienzo de Compras (x 1146 · y 228 a 1366×768): el cuadro baja 14 px y entra 62 px desde el borde derecho
   (19 px bajo el borde de la sección y 82 px del derecho); solo en Compras, la Caja conserva el suyo. */
#c-img-box{margin-top:-13px;margin-right:62px}
/* Modo Catálogo del modal de Compras: misma rejilla que la Caja (catálogo izq · detalle + pie der) */
.venta-modal.modo-cat #c-row-top{grid-column:1/-1}
.venta-modal.modo-cat #c-sec-agregar{grid-column:1;grid-row:2;display:flex;flex-direction:column;min-height:0;border-bottom:0;border-right:1px solid var(--border);padding-bottom:0}
.venta-modal.modo-cat #c-sec-agregar .v-add-wrap{display:none}
/* El detalle de Compras es Producto · Cant. · Costo u. · I.V.A. % · Subtotal · papelera: en la columna angosta se esconde
   la tasa (4ª), no la cantidad ni el subtotal (la regla genérica de la Caja esconde la 2ª y la 5ª). */
#compra-dialog.modo-cat .vm-detalle .grid th:nth-child(2),#compra-dialog.modo-cat .vm-detalle .grid td:nth-child(2),
#compra-dialog.modo-cat .vm-detalle .grid th:nth-child(5),#compra-dialog.modo-cat .vm-detalle .grid td:nth-child(5){display:table-cell}
#compra-dialog.modo-cat .vm-detalle .grid th:nth-child(4),#compra-dialog.modo-cat .vm-detalle .grid td:nth-child(4){display:none}
#compra-dialog .cat-precio{font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#compra-dialog .cat-precio b{font-size:13px;color:var(--text)}
#compra-dialog .cat-costo .cat-pct{width:82px;text-align:right}
@media (max-height:860px){ .venta-modal.maximized.modo-cat #c-sec-agregar{padding-bottom:0} }

/* Compras 0.110: Lote · Vence · I.V.A. % por tarjeta del Catálogo, solo con el interruptor encendido */
#compra-dialog:not(.avz) .cat-avz{display:none}
#compra-dialog .cat-avz>span{flex:none;width:46px}
#compra-dialog .cat-avz .cat-pct{flex:1;min-width:0;width:auto;text-align:left}
#compra-dialog .cat-avz .cc-vence{font-size:11px;padding:0 2px}
#compra-dialog .cat-avz .cc-iva{flex:none;width:54px;text-align:right}

/* ─── Mi clave (0.111, 10-sep): botón en el membrete y página ─── */
.appbar .btn-clave{display:inline-flex;align-items:center;gap:6px;text-decoration:none}
.mi-clave{max-width:480px;margin:8px auto 0}
.mi-clave .cfg-card{display:flex;flex-direction:column;gap:12px}
.mi-clave .cfg-ok{margin:0}
.mi-clave-form{display:flex;flex-direction:column;gap:12px}
.mi-clave-btns{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:4px 0 0}
.mi-clave a.btn-ghost,.mi-clave a.btn-primary{text-decoration:none;display:inline-flex;align-items:center;gap:6px}
.usu-regla{margin:0 0 10px;font-size:13px}
@media (max-width:720px){ .appbar .btn-clave .lbl-clave{display:none} }

/* ── Leer factura con Exynol AI (Claude Vision, 16-sep-2026): pantalla de revisión en +Nueva Compra ── */
.cf-modal{width:min(1180px,96vw)}
.cf-body{padding:14px 20px;overflow:auto}
.cf-cab .fn-row{align-items:flex-start}
.cf-leido{display:block;font-size:12px;margin-top:3px}
.cf-cuadre{margin:12px 0;padding:10px 14px;border-radius:10px;font-size:14px;border:1px solid var(--border);background:var(--surface)}
.cf-cuadre.ok{border-color:#2e9e5b;background:rgba(46,158,91,.12)}
.cf-cuadre.no{border-color:#c0392b;background:rgba(192,57,43,.12)}
.cf-cuadre.sin{border-color:#c9a227;background:rgba(201,162,39,.12)}
.cf-tabla td{vertical-align:top}
.cf-tabla .inp{padding:6px 8px;min-height:0}
.cf-tabla .num .inp{max-width:110px;text-align:right}
.cf-desc{font-weight:600}
.cf-cod{font-size:11.5px;font-family:var(--font-mono,monospace)}
.cf-aviso{font-size:11.5px;color:#c0392b;margin-top:2px}
.cf-est{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:12px;white-space:nowrap}
.cf-est.ok{background:#c6efce;color:#006100}
.cf-est.med{background:#dbeafe;color:#1e3a8a}
.cf-est.dud{background:#fff9b2;color:#9c8000}
.cf-est.no{background:#ffc7ce;color:#9c0006}
.cf-prod{position:relative;min-width:260px}
.cf-prod .cf-q{width:100%}
.cf-lista{position:absolute;left:0;right:0;top:100%;z-index:30;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.25);max-height:240px;overflow:auto}
.cf-it{padding:6px 10px;cursor:pointer;display:flex;flex-direction:column;gap:1px;font-size:13px}
.cf-it:hover{background:color-mix(in srgb,var(--accent) 18%,transparent)}
.cf-btns{margin-top:12px;justify-content:flex-end}
.c-ia-btn{margin-left:10px}
[data-theme="oscuro"] .cf-est.ok{color:#c6efce;background:rgba(0,97,0,.35)}
[data-theme="oscuro"] .cf-est.med{color:#dbeafe;background:rgba(30,58,138,.45)}
[data-theme="oscuro"] .cf-est.dud{color:#ffe98a;background:rgba(156,128,0,.24)}
[data-theme="oscuro"] .cf-est.no{color:#ffb3ba;background:rgba(156,0,6,.30)}
/* [hidden] dentro de .vm-btns (display:flex) perdía contra el display del botón: se fuerza (la trampa del 07-sep). */
.cf-btns [hidden]{display:none !important}
/* Botón «Leer factura» (16-sep, pedido de Alejandro: que se DESTAQUE con el icono de Exynol AI). El SVG del
   asistente no trae tamaño (es el del launcher, que lo dimensiona .tile): aquí se le da uno y el color de la marca. */
/* Vive en la cabecera OSCURA del modal (navy en los dos temas): pastilla oscura con borde luminoso, el
   orbital de Exynol AI en blanco + naranja de la marca, y el rótulo en dos renglones (Leer factura · Exynol AI). */
.c-ia-btn{display:inline-flex;align-items:center;gap:8px;padding:5px 14px 5px 10px;color:#fff;font-weight:700;border:1px solid rgba(255,255,255,.35);border-radius:999px;background:linear-gradient(135deg,#2b3d72 0%,#3f5aa6 55%,#5a3f8f 100%);box-shadow:0 0 0 1px rgba(255,255,255,.06) inset,0 4px 14px rgba(0,0,0,.35);text-shadow:0 1px 1px rgba(0,0,0,.35)}
.c-ia-btn:hover{background:linear-gradient(135deg,#34489a 0%,#4d6bc4 55%,#6d4bb0 100%);border-color:rgba(255,255,255,.6);box-shadow:0 0 0 1px rgba(255,255,255,.1) inset,0 6px 18px rgba(0,0,0,.4)}
.c-ia-btn:active{transform:translateY(1px)}
.c-ia-btn svg{width:22px;height:22px;overflow:visible;flex:none;filter:drop-shadow(0 0 4px rgba(255,255,255,.35))}
.c-ia-btn .ic-b{fill:rgba(255,255,255,.9)}
.c-ia-btn .ic-a{fill:var(--accent)}
.c-ia-btn .txt{display:flex;flex-direction:column;align-items:flex-start;line-height:1.05}
.c-ia-btn small{font-size:9.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;opacity:.8;margin-top:2px}
.cf-modal .vm-head h2 svg{width:24px;height:24px;margin-right:8px;overflow:visible;flex:none}
.cf-modal .vm-head h2 .ic-b{fill:rgba(255,255,255,.85)}
.cf-modal .vm-head h2 .ic-a{fill:var(--accent)}

/* ─── COMPRAS · celdas de utilidad y precio de venta (17-sep-2026, lienzo «Compras · Utilidad y precios», B v2) ───
   Bloques «Costo» y «Precio de venta» en la fila de captura: rótulo · «Actual …» · campo + chip ▲/▼ (= 0 % si no
   cambia). Detalle con encabezados cortos, producto a dos líneas y columnas «Precio De Venta» / «Util.%». En modo
   Catálogo las tarjetas llevan filas Costo / P.V.P / segundo precio y el detalle esconde esas columnas. */
#compra-dialog .c-blk{display:flex;gap:6px;align-items:flex-end;padding:9px 8px 9px;border:1px solid var(--border);border-radius:8px;background:var(--surface-2);position:relative}
#compra-dialog .c-blk-t{position:absolute;left:10px;top:-8px;font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);background:var(--surface-2);padding:0 4px;line-height:1.2}
#compra-dialog .c-blk .fld{font-size:12px}
#compra-dialog .c-blk .inp[readonly]{background:var(--surface)}
#compra-dialog .c-cel{gap:2px}
#compra-dialog .c-cel-l{font-size:12.5px;font-weight:600;color:var(--text);line-height:1.2;white-space:nowrap;display:inline-flex;align-items:center;gap:4px}
#compra-dialog .c-cel-l .cat-tar-lbl{margin:0;vertical-align:0}
#compra-dialog .c-cel-act{font-size:11px;font-weight:500;color:var(--muted);line-height:1.35;white-space:nowrap}
#compra-dialog .c-cel-act b{font-weight:600;color:var(--text);font-variant-numeric:tabular-nums}
#compra-dialog .c-cel-act b.ic-util{font-size:10.5px;padding:0 5px;border-radius:5px;line-height:1.5}
#compra-dialog .c-cel-act b.ic-util:not([class*="util-"]){background:transparent;padding:0}
#compra-dialog .v-add-linea .inp.c-precio-inp{width:84px;font-weight:600}
#compra-dialog .v-add-linea .inp.c-util-inp{width:76px;font-weight:700;text-align:right}
#compra-dialog .c-util-wrap{display:flex;align-items:center;gap:4px}
#compra-dialog .v-add-linea .btn-primary{padding-left:10px;padding-right:10px}
.c-delta{display:inline-block;font-size:11.5px;font-weight:700;padding:1px 6px;border-radius:10px;white-space:nowrap;line-height:1.45;font-variant-numeric:tabular-nums}
.c-delta.up{color:var(--ok);background:rgba(38,166,91,.14)}
.c-delta.down{color:var(--no);background:rgba(220,53,69,.12)}
.c-delta.eq{color:var(--info);background:rgba(124,181,236,.16)}
.c-delta-s{font-size:10.5px;padding:0 5px}
.c-delta[hidden]{display:none}
/* detalle */
#compra-dialog .vm-detalle .grid th{text-transform:none;letter-spacing:.01em}
#compra-dialog .vm-detalle .grid td,#compra-dialog .vm-detalle .grid th{padding-left:6px;padding-right:6px}
#compra-dialog:not(.modo-cat) .vm-detalle .grid td.c-prod{max-width:176px}
#compra-dialog .vm-detalle .grid td.c-prod .c-prod-n{font-size:12.5px;line-height:1.25;white-space:normal;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
#compra-dialog .vm-detalle .grid td.c-pv,#compra-dialog .vm-detalle .grid td.c-ut{white-space:nowrap;line-height:1.7;font-size:12.5px;font-variant-numeric:tabular-nums;vertical-align:middle}
#compra-dialog .vm-detalle .grid td.c-pv b{font-weight:600;font-size:13px}
#compra-dialog .vm-detalle .grid .c-pv-r{display:inline-flex;align-items:center;gap:4px}
#compra-dialog .vm-detalle .grid .c-pv-r .cat-tar-lbl{margin:0;min-width:38px;text-align:center}
#compra-dialog .vm-detalle .grid .c-antes{font-size:11px;color:var(--muted);font-weight:400;text-decoration:line-through}
#compra-dialog .vm-detalle .grid td.c-ut .ic-util{display:inline-block;min-width:52px;text-align:right;margin:0;font-size:10.5px;padding:0 5px;box-sizing:border-box}
#compra-dialog .vm-detalle .grid td.c-ut .c-delta-s{display:inline-block;min-width:52px;text-align:left}
#compra-dialog:not(.modo-cat) .c-pv-mini{display:none}
#compra-dialog.modo-cat .vm-detalle .grid th:nth-child(6),#compra-dialog.modo-cat .vm-detalle .grid td:nth-child(6),
#compra-dialog.modo-cat .vm-detalle .grid th:nth-child(7),#compra-dialog.modo-cat .vm-detalle .grid td:nth-child(7){display:none}
#compra-dialog .c-pv-mini{font-size:10.5px;color:var(--muted);line-height:1.6;white-space:nowrap;margin-top:2px}
#compra-dialog .c-pv-mini b{color:var(--text);font-weight:600}
#compra-dialog .c-pv-mini .ic-util{font-size:10px;padding:0 4px;margin:0}
#compra-dialog .c-pv-mini .c-delta-s{font-size:10px;padding:0 4px}
#compra-dialog .c-pv-mini .cat-tar-lbl{margin:0 2px 0 0}
/* catálogo: filas Costo / P.V.P / segundo precio en la tarjeta */
#compra-dialog .cat-desc.c-cd{align-items:center;gap:5px;margin-top:3px}
#compra-dialog .c-cd-l{display:flex;flex-direction:column;line-height:1.15;min-width:58px;flex:none}
#compra-dialog .c-cd-l i{font-style:normal;font-size:10px;color:var(--muted);white-space:nowrap}
#compra-dialog .c-cd-l .cat-tar-lbl{margin:0;align-self:flex-start}
#compra-dialog .cat-desc .cat-pct.c-cd-inp{width:64px;flex:none;text-align:right}
#compra-dialog .cat-desc .ic-util{font-size:10.5px;padding:0 4px;margin:0;flex:none}
#compra-dialog .cat-desc .ic-util[hidden]{display:none}
#compra-dialog .v-cat-grid.tam-s .c-cd-l i{display:none}
#compra-dialog .v-add-linea #l-costo{width:84px;font-weight:600}   /* el costo de la factura, del ancho de los precios (la clase la asertan los tests) */

/* Lista de Ventas · columna «Caja» (18-sep-2026): el mostrador o la caja móvil que registró la venta, con su icono. */
#ventas-list .td-caja{white-space:nowrap;max-width:240px;overflow:hidden;text-overflow:ellipsis}
/* Columna «Hora» (22-sep-2026): hh:mm a. m./p. m. como Auditoría; cifras de ancho fijo para que las filas se alineen. */
#ventas-list .td-hora{white-space:nowrap;font-variant-numeric:tabular-nums}
#ventas-list .v-caja{display:inline-flex;align-items:center;gap:5px;vertical-align:middle}
#ventas-list .v-caja svg{width:14px;height:14px;margin:0;vertical-align:0;opacity:.65}
/* Barra de Ventas con los selectores Vendedor y Caja (18-sep): Desde/Hasta viajan JUNTOS (nunca uno en cada renglón), los selectores se acotan y el buscador cede ancho para que los filtros quepan en un renglón a 1366 px. */
.tb-fechas{display:inline-flex;align-items:center;gap:8px;flex:none}
.tb-filtros .sel-vend select{max-width:200px;text-overflow:ellipsis}
.tb-filtros:has(.sel-caja) .search-wrap{flex-basis:250px}

/* Editor de producto · recargo de unidad/fracción en tres lecturas (18-sep-2026): celda + lecturas al lado. */
.mk-fld{flex:0 1 auto}
.mk-wrap{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.mk-wrap>.inp{width:118px;flex:none}
.mk-lect{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12px;font-weight:400;text-transform:none;letter-spacing:0}
.mk-chip{display:inline-block;padding:2px 7px;border-radius:999px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-variant-numeric:tabular-nums;white-space:nowrap}
.mk-chip.mk-precio{font-weight:600}
.mk-nota{color:var(--muted);white-space:nowrap}
.mk-nota.mk-mal{color:var(--danger,#b3261e);white-space:normal}

/* Caja · «Vender» Entero | Unidad | Fracción (18-sep-2026): segmentado de las tarjetas del Catálogo, del zoom y del Formulario; solo en productos fraccionables. */
.seg-tv{margin-left:0;display:inline-flex;max-width:100%}
.seg-tv button{padding:3px 8px;font-size:11.5px;white-space:nowrap;flex:1 1 auto;justify-content:center}
.seg-tv button[hidden]{display:none!important}
.cat-tv{margin:4px 0 2px}
.cat-tv[hidden]{display:none!important}
.cat-tv .seg-tv{display:flex;width:100%}
.v-cat-grid.tam-s .cat-tv .seg-tv button{padding:2px 3px;font-size:10.5px}
.cz-precio .seg-tv{margin-left:10px;vertical-align:middle}
/* Teléfono: la tarjeta mide ~150 px — letra y relleno mínimos para que Entero | Unidad | Fracción quepan sin recortarse. */
@media (max-width:720px){.cat-fila{flex-wrap:wrap;gap:2px 6px}.cat-tv .seg-tv{padding:2px;gap:1px}.cat-tv .seg-tv button{padding:4px 1px;font-size:10.5px;min-width:0;letter-spacing:-.1px}}
#v-tv-wrap .seg-tv button{padding:6px 7px;font-size:12px}   /* compacto: la fila de captura debe seguir cabiendo en UN renglón a 1366 px */

/* Ajustes · «Sonidos y animaciones» (18-sep-2026): la fila de botones Probar. */
.son-probar{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:4px 0 12px}

/* «Procesado» (19-sep-2026): confirmación central al guardar venta/cotización. Reusa .msgbox (mismo fondo oscuro). */
.msgbox-ok{text-align:center;min-width:360px;padding:26px 28px 22px}
.msgbox-ok .mok-ico{position:relative;width:72px;height:72px;margin:0 auto 12px}
.msgbox-ok .mok-ico svg{position:absolute;inset:0;width:100%;height:100%;display:block;overflow:visible}
.msgbox-ok .mok-fondo{position:absolute;inset:5px;border-radius:50%;background:color-mix(in srgb,var(--ok) 14%,transparent)}
.msgbox-ok .mok-giro{transform:rotate(-90deg)}   /* el aro arranca a las 12, como el punto */
.msgbox-ok .mok-aro{fill:none;stroke:var(--ok);stroke-width:3;stroke-linecap:round;stroke-dasharray:164;stroke-dashoffset:0}
.msgbox-ok .mok-v{fill:none;stroke:var(--ok);stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:40;stroke-dashoffset:0}
.msgbox-ok .mok-orb{position:absolute;inset:0;opacity:0}   /* quieto = sin punto: el estado final es el de reposo */
.msgbox-ok .mok-punto{position:absolute;left:50%;top:0;width:10px;height:10px;margin-left:-5px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 4px color-mix(in srgb,var(--accent) 26%,transparent)}
.msgbox-ok .mok-tit{margin:0;font-size:19px;font-weight:700;font-family:var(--font-display)}
.msgbox-ok .mok-det{margin:4px 0 0;color:var(--muted);font-size:14px;font-variant-numeric:tabular-nums}
.msgbox-ok .mok-preg{margin:16px 0 0;font-size:15px}
.msgbox-ok .vm-btns{justify-content:center;margin-top:16px}
.msgbox-ok .vm-btns .btn-primary,.msgbox-ok .vm-btns .btn-ghost{min-width:96px}
/* APERTURA DE CAJA al vender (22-sep-2026): el aviso de «+Nueva venta» (Abrir caja · Ver productos · Cancelar) con
   el fondo de apertura editable, y la franja del MODO VISUALIZACIÓN dentro de la Caja. */
.msgbox-caja{max-width:560px}
.msgbox-caja .caja-ap-tit{display:flex;align-items:center;gap:6px;margin:0 0 6px;font-size:18px;font-weight:700;font-family:var(--font-display)}
.msgbox-caja .caja-ap-tit .ic16{width:20px;height:20px;fill:var(--accent)}
.msgbox-caja .caja-ap-txt{margin:0 0 14px}
.msgbox-caja .caja-ap-fondo{margin:4px 0 0}
.msgbox-caja .caja-ap-fondo .inp{width:120px}
.msgbox-caja .caja-ap-nota{margin:6px 0 0;font-size:12px}
.msgbox-caja .caja-ap-err{margin:8px 0 0;color:var(--no);font-size:13px;font-weight:600}
.msgbox-caja .caja-ap-err:empty{display:none}
.msgbox-caja .vm-btns{margin-top:16px;flex-wrap:wrap}
.modo-vista{flex:none;display:flex;align-items:center;gap:10px;padding:8px 16px;background:color-mix(in srgb,var(--accent) 16%,var(--surface));border-bottom:2px solid var(--accent);font-size:13.5px}
.modo-vista[hidden]{display:none}
.modo-vista>span{flex:1}
.modo-vista .ic16{width:20px;height:20px;fill:var(--accent-text);margin-right:0}
/* ÓRBITA (variante C del lienzo «Procesado animado», elegida por Alejandro el 19-sep): el punto da UNA vuelta dejando
   el aro dibujado (misma curva y misma duración: 0,62 s), se funde, aparece el fondo y se traza el visto. Una sola vez.
   Apagada con «reducir movimiento» o con el interruptor de animaciones de Ajustes (.sin-anim): queda el visto quieto. */
@media (prefers-reduced-motion:no-preference){
  .msgbox-ok[open]:not(.sin-anim){animation:mok-entra .18s ease-out}
  .msgbox-ok[open]:not(.sin-anim) .mok-aro{animation:mok-aro .62s cubic-bezier(.5,0,.3,1) backwards}
  .msgbox-ok[open]:not(.sin-anim) .mok-orb{animation:mok-orb .775s backwards}
  .msgbox-ok[open]:not(.sin-anim) .mok-fondo{animation:mok-fondo .3s .5s ease-out backwards}
  .msgbox-ok[open]:not(.sin-anim) .mok-v{animation:mok-visto .3s .6s ease-out backwards}
  @keyframes mok-entra{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}
  @keyframes mok-aro{from{stroke-dashoffset:164}to{stroke-dashoffset:0}}
  @keyframes mok-orb{0%{transform:rotate(0deg);opacity:1;animation-timing-function:cubic-bezier(.5,0,.3,1)}80%{transform:rotate(360deg);opacity:1}100%{transform:rotate(360deg);opacity:0}}
  @keyframes mok-fondo{from{opacity:0}to{opacity:1}}
  @keyframes mok-visto{from{stroke-dashoffset:40}to{stroke-dashoffset:0}}
}
@media (max-width:720px){.msgbox-ok{min-width:0;width:min(340px,88vw)}}

/* Cuentas (19-sep-2026): el detalle de una cuenta es una VENTANA aparte, no un bloque debajo de la tabla. */
.cuenta-modal{width:min(1080px,96vw);padding:16px 18px 18px;overflow:auto}
.cuenta-modal .kardex{margin-top:0}
.cuenta-modal .kardex-head{flex-wrap:wrap;row-gap:6px}
/* Como en .kardex-modal: la regla «.venta-modal form» (columna, pensada para el único form de la Caja) no aplica al
   form de fila del abono — sin esto quedaba apilado y pegado a la derecha. */
.cuenta-modal form.fn-row{flex-direction:row;align-items:flex-end;flex-wrap:wrap;max-height:none;height:auto;gap:10px}
.cuenta-modal form.fn-row .fld.grow{flex:1 1 220px}
@media (max-width:720px){.cuenta-modal{width:100vw;max-width:100vw;max-height:100vh;border-radius:0;padding:12px}}

/* FICHA de cliente / proveedor (19-sep-2026): ventana con los campos rotulados, para crear y para modificar. */
.ficha-modal{width:min(640px,96vw)}
.ficha-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 14px}
.ficha-grid .ficha-ancho{grid-column:1 / -1}
.ficha-grid .inp{width:100%;box-sizing:border-box}
.ficha-grid .fld-help{font-weight:400}
.ficha-modal .vm-body{display:block;overflow:auto;max-height:calc(92vh - 130px)}
.ficha-modal .vm-sec:last-child{border-bottom:none}
.ficha-modal h2 .ic16{vertical-align:-2px;margin-right:6px}
@media (max-width:720px){.ficha-modal{width:100vw;max-width:100vw;border-radius:0}.ficha-grid{grid-template-columns:1fr}}
/* «✕ Cerrar» fijo arriba a la derecha de la ventana (la cabecera envuelve en dos renglones y lo arrastraba abajo). */
.cuenta-modal .kardex-head{position:relative;padding-right:112px}
.cuenta-modal .kardex-head>button:last-child{position:absolute;top:-2px;right:0}
