/* ==== css/styles.css ==== */
/* Inter, servida por nosotros (1.62). Estaba en jsdelivr, y esa hoja
   era lo primero que el navegador esperaba antes de pintar nada: otro
   dominio, otra conexión, y en cada visita. Sólo latín y latín
   extendido, que es todo lo que esta app escribe; los archivos son los
   mismos de @fontsource-variable/inter@5 (licencia OFL). */
@font-face{font-family:'Inter Variable';font-style:normal;font-display:swap;font-weight:100 900;
  src:url(fonts/inter-latin-ext.woff2) format('woff2-variations');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Inter Variable';font-style:normal;font-display:swap;font-weight:100 900;
  src:url(fonts/inter-latin.woff2) format('woff2-variations');
  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}
/* =============================================================
   Mercatoria Online — estilos base (Identidad + UI Holded)
   Barra superior oscura, sidebar claro de módulos, pestañas
   contextuales píldora, tarjetas flotantes y bordes suaves.
   Tipografía: Inter (titulares y texto/datos).
   ============================================================= */
:root{
  --orange:#F16A30; --orange-600:#DA531D; --amber:#FFB43B; --lime:#C6BC3C;
  --ink:#42424a; --ink-700:#36363c; --warm:#E8E8E3; --warm-2:#f4f2ee;
  --brand-grad:linear-gradient(90deg,#C6BC3C 0%,#FFB43B 50%,#F16A30 100%);
  --brand-grad-v:linear-gradient(180deg,#C6BC3C 0%,#FFB43B 48%,#F16A30 100%);

  --bg:#F2F0EC; --surface:#ffffff; --lighter:#FBFAF8; --rule:#E4DFD6; --steel:#6E6E76;
  --text:#45454d; --muted:#6E6E76; --navy:#3d3d43; --white:#fff;

  --ok:#5f7a12; --ok-bg:#F1F4D9; --warn:#9A5B10; --warn-bg:#FCEEDA;
  --danger:#C0431E; --danger-bg:#FBE6DD; --info:#4F4F56; --info-bg:#EFEEEB;
  /* Servicio: no mueve inventario, así que no comparte color con nada
     que sí lo haga. El gris de --info lo dejaba a medio camino entre
     "otro" y "apagado"; el violeta se distingue de un vistazo. */
  --svc:#6B4BA8; --svc-bg:#EFE9FB;

  /* ---------- Movimiento ----------
     Tres curvas, no más, y ninguna inventada: son las dos que la app ya
     usaba —el `fadeUp` de las tarjetas y el rebote del glider— más una
     recta para el pulsado. Tenerlas con nombre es lo que evita que cada
     regla nueva elija su propia duración a ojo, que es como se llega a
     veinte animaciones que no se parecen entre sí.

     · --ease      entra y frena. Lo normal.
     · --ease-pop  pasa un pelo de largo y vuelve. Para lo que aparece
                   o crece: el glider, un icono al señalarlo.
     · --ease-tap  el pulsado. Tiene que ser inmediato o se siente lento.

     Y las duraciones por tamaño del cambio: cuanto más pequeño el
     movimiento, más corto. Un icono que tarda lo mismo que un panel
     entero se siente pesado. */
  --ease:.2s cubic-bezier(.2,.7,.2,1);
  --ease-pop:.24s cubic-bezier(.34,1.28,.42,1);
  --ease-tap:.09s cubic-bezier(.4,0,.6,1);

  --radius:20px; --radius-sm:14px; --radius-xs:8px; --topbar-h:56px;
  --shadow:0 1px 3px rgba(80,60,40,.06);
  --shadow-lg:0 2px 4px rgba(80,60,40,.07),0 12px 28px rgba(120,80,40,.09);
  --sidebar-w:236px;
  --font-head:"Inter Variable","Inter",system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
  --font-body:"Inter Variable","Inter",system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
*{scrollbar-width:thin;scrollbar-color:var(--rule) transparent}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background-color:var(--rule);border-radius:99px;border:2px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background-color:var(--muted);border:2px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-corner{background:transparent}
body{font-family:var(--font-body);color:var(--text);font-size:14px;line-height:1.55;
  background:var(--bg);}
h1,h2,h3,h4{margin:0;color:var(--ink);font-weight:700;font-family:var(--font-head);letter-spacing:-.015em}
a{color:var(--orange-600);text-decoration:none}
code{background:var(--warm-2);padding:1px 7px;border-radius:7px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.85em;color:var(--ink)}
[hidden]{display:none !important}

@media (prefers-reduced-motion: no-preference){
  @keyframes fadeUp{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
  .kpi,.page-head{animation:fadeUp .4s cubic-bezier(.2,.7,.2,1) both}
  @keyframes fadeIn{from{opacity:0}to{opacity:1}}
  .card{animation:fadeIn .4s ease both}
}

/* ---------- Marca / imagotipo ---------- */
.brand-mark{display:inline-flex}
.brand-mark svg{display:block}
.brand-word{font-family:var(--font-head);font-weight:800;line-height:1;display:flex;flex-direction:column;gap:2px}
.brand-word span{font-size:9px;font-weight:700;letter-spacing:.32em;color:var(--orange);margin-left:1px}

/* ---------- Buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:7px;justify-content:center;border:1px solid transparent;
  border-radius:var(--radius-sm);padding:9px 16px;font-size:13px;font-weight:700;cursor:pointer;background:#fff;
  color:var(--text);font-family:var(--font-body);
  transition:background var(--ease),border-color var(--ease),box-shadow var(--ease),transform var(--ease)}
/* El primario ya crecía de sombra al señalarlo pero se quedaba clavado
   en el sitio, que es la mitad del gesto. Un píxel arriba basta: lo que
   se lee no es el píxel, es que la sombra y la posición cuentan lo
   mismo. Y al pulsar baja del todo, rápido. */
.btn:hover{transform:translateY(-1px)}
.btn:active{transform:translateY(1px);transition:transform var(--ease-tap)}
.btn svg{width:16px;height:16px}
.btn-primary{background:var(--orange-600);color:#fff;box-shadow:0 3px 10px rgba(218,83,29,.30)}
.btn-primary:hover{background:#c4471a;box-shadow:0 6px 16px rgba(218,83,29,.34)}
.btn-ghost{background:#fff;border-color:var(--rule);color:var(--steel);box-shadow:0 1px 2px rgba(80,60,40,.04)}
.btn-ghost:hover{background:var(--warm-2);color:var(--ink)}
.btn-danger{background:#fff;border-color:var(--danger);color:var(--danger)}
.btn-danger:hover{background:var(--danger-bg)}
/* El anillo de foco de los botones lo pintaba el navegador (negro, cuadrado)
   y cantaba dentro de un modal. Mismo halo naranja que ya usan los campos. */
.btn:focus-visible{outline:none;box-shadow:0 0 0 4px rgba(241,106,48,.28)}
.btn-primary:focus-visible{box-shadow:0 3px 10px rgba(218,83,29,.30),0 0 0 4px rgba(241,106,48,.28)}
.btn-sm{padding:6px 13px;font-size:12px;border-radius:var(--radius-xs)}
.btn-block{width:100%;margin-top:4px}
/* ---------- Iconos con los que se pincha ----------
   Antes no tenían **ninguna** transición: el fondo y el color saltaban
   de golpe mientras los botones normales sí acompañaban el cambio. De
   ahí que se sintieran rígidos; no era falta de animación, era una
   incoherencia.

   Tres cosas y ninguna más:
   · el fondo aparece acompañado, no de golpe;
   · el dibujo crece un pelo al señalarlo — que reaccione **el icono** y
     no sólo su caja es lo que hace que parezca vivo;
   · al pulsar se hunde, rápido. Un pulsado con retardo se siente roto.

   Se mueve el `svg` y no el botón: mover la caja desplaza lo de al lado
   en una fila de cinco iconos pegados. */
.icon-btn{background:none;border:none;color:var(--steel);cursor:pointer;padding:7px;
  border-radius:var(--radius-xs);display:inline-flex;
  transition:background var(--ease),color var(--ease)}
.icon-btn svg{transition:transform var(--ease-pop)}
.icon-btn:hover{background:var(--warm-2);color:var(--ink)}
.icon-btn:hover svg{transform:scale(1.14)}
.icon-btn:active{transition:background var(--ease-tap),color var(--ease-tap)}
.icon-btn:active svg{transform:scale(.92);transition:transform var(--ease-tap)}
/* Los iconos no tenían foco visible y los botones sí: quien navega con
   el teclado se quedaba sin saber dónde estaba. Mismo anillo. */
.icon-btn:focus-visible{outline:none;background:var(--warm-2);color:var(--ink);
  box-shadow:0 0 0 3px rgba(241,106,48,.28)}

/* ---------- Los iconos que se mueven por dentro ----------
   Crecer un pelo lo hace vivo, pero es el mismo gesto para los
   veintitantos. Aquí el icono mueve **su propia pieza**, y esa pieza
   dice lo que hace el botón: la tapa de la papelera se levanta, la hoja
   sale de la impresora, la aguja del reloj avanza. Cuando el movimiento
   no significa nada —`cancel`, `invoices`— no se pone: media docena de
   piezas girando sin motivo es ruido, no modernidad.

   La idea es de las bibliotecas de iconos animados (Iconly y compañía).
   Los trazados **no**: se venden con licencia, vienen en Lottie y harían
   falta un reproductor y un JSON por icono. Aquí el icono ya está en el
   HTML, así que basta con una clase en la pieza y una regla. Es el mismo
   criterio que con `accounting`, que se trajo el trazado y dejó fuera el
   React.

   Las piezas se marcan con una clase `i-…` en `MO.icons`, y el que las
   mueve es el botón que las contiene. `transform-box:view-box` es
   obligatorio: sin él el origen del giro es la esquina del lienzo y la
   tapa sale volando en diagonal. Los orígenes van en unidades de la
   rejilla de 24, que es la de todos. */
.i-tapa,.i-lupa,.i-aguja,.i-pupila,.i-vuelta,.i-punta,.i-camion,
.i-sube,.i-baja,.i-barre,.i-polvo,.i-entra,.i-sale,.i-campana,.i-hoja{
  transform-box:view-box;transform-origin:center;transition:transform var(--ease-pop)}
.i-tapa{transform-origin:4px 6px}      /* la bisagra, no el centro */
.i-lupa{transform-origin:11px 11px}    /* el cristal */
.i-aguja,.i-pupila,.i-vuelta{transform-origin:12px 12px}
.i-barre{transform-origin:19px 5px}    /* la mano que agarra el palo */
.i-campana{transform-origin:12px 4px}  /* cuelga de arriba */

/* Un solo prefijo para todos: el botón que sea, señalado o con el foco
   del teclado. En `:where` para no subir la especificidad y que el
   bloque de movimiento reducido pueda desactivarlo sin `!important`. */
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-tapa{transform:rotate(-10deg) translateY(-1px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-lupa{transform:rotate(-14deg)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-aguja{transform:rotate(45deg)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-pupila{transform:scale(1.3)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-vuelta{transform:rotate(-40deg)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-punta{transform:translateX(-1.4px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-camion{transform:translateX(1.3px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-sube{transform:translate(.9px,-.9px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-baja{transform:translate(-.9px,.9px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-barre{transform:rotate(-7deg)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-polvo{transform:translate(-1.2px,-1.2px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-entra{transform:translateY(-1.2px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-sale{transform:translateY(1.6px)}
:where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible) .i-hoja{transform:translate(1.1px,1.1px)}
/* La campana es la excepción: sonar es oscilar, y una oscilación no cabe
   en un estado final. Va y vuelve; no se queda torcida. */
@keyframes campanea{
  0%{transform:rotate(0)}22%{transform:rotate(11deg)}45%{transform:rotate(-8deg)}
  70%{transform:rotate(5deg)}100%{transform:rotate(0)}}
.notif-btn:is(:hover,:focus-visible) .i-campana{animation:campanea .55s ease-in-out}

/* ---------- Login ---------- */
/* El degradado de marca queda en una franja, no a pantalla completa: la
   primera impresión se parece a lo que viene después. */
.login-screen{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--bg);padding:20px}
.login-screen::before{content:"";position:absolute;left:0;right:0;top:0;height:6px;background:var(--brand-grad)}
.login-card{background:#fff;border:1px solid var(--rule);border-radius:var(--radius);
  box-shadow:0 2px 4px rgba(80,60,40,.07),0 18px 44px rgba(120,80,40,.12);width:100%;max-width:410px;padding:40px 36px}
.login-brand{display:flex;align-items:center;gap:14px;margin-bottom:30px}
.login-brand h1{font-size:23px;color:var(--ink)}
.login-brand p{margin:3px 0 0;color:var(--orange);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase}
#login-form label,#reset-password-form label{display:block;font-size:12.5px;font-weight:600;color:var(--steel);margin-bottom:15px}
#login-form input,#reset-password-form input{width:100%;margin-top:6px;padding:12px 14px;border:1px solid var(--rule);border-radius:var(--radius-sm);font-size:14px;color:var(--text);font-family:var(--font-body);background:#fff;transition:border-color .15s,box-shadow .15s}
#login-form input:focus,#reset-password-form input:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.14)}
.pw-field{position:relative;display:block}
.pw-field input{padding-right:44px}
.pw-toggle{position:absolute;right:6px;top:calc(50% + 3px);transform:translateY(-50%);background:none;border:none;
  color:var(--muted);cursor:pointer;padding:6px;border-radius:9px;display:inline-flex;transition:color .15s,background .15s}
.pw-toggle:hover{color:var(--ink);background:var(--warm-2)}
.pw-toggle .eye-off{display:none}
.pw-toggle.on{color:var(--orange-600)}
.pw-toggle.on .eye{display:none}
.pw-toggle.on .eye-off{display:block}
.login-error{background:var(--danger-bg);color:var(--danger);padding:9px 12px;border-radius:12px;font-size:12.5px;margin:0 0 12px}
.login-hint{margin:20px 0 0;font-size:12px;color:var(--muted);text-align:center;line-height:1.6}
.login-check{display:block;margin:10px auto 0;background:none;border:none;cursor:pointer;
  font-family:var(--font-body);font-size:12px;font-weight:600;color:var(--orange-600);
  text-decoration:underline;text-underline-offset:3px}
.login-diag{margin-top:12px;background:var(--warm-2);border-radius:14px;padding:10px 12px;
  font-size:12px;color:var(--text);line-height:1.5}
.ld-row{display:flex;gap:8px;align-items:baseline;padding:2px 0}
.ld-row small{color:var(--muted)}
.ld-mark{flex:none;width:14px;font-weight:800}
.ld-row.ok .ld-mark{color:var(--ok)}
.ld-row.mal{color:var(--danger)}
.ld-row.mal .ld-mark{color:var(--danger)}
.ld-row.mal small{color:var(--danger)}

/* ---------- App shell ---------- */
.app{display:flex;flex-direction:column;min-height:100vh}
.topbar{display:flex;align-items:center;gap:14px;height:var(--topbar-h);padding:0 22px;background:var(--ink);
  color:#ececed;position:sticky;top:0;z-index:30}
.topbar-brand{display:flex;align-items:center;gap:11px}
.topbar-brand .brand-word{color:#fff;font-size:16px}
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:12px}
/* Arriba a la derecha sólo queda quién eres y la campana. El botón
   flotante de "+" repetía el "Nuevo" que ya está en cada pantalla, y el
   correo y el rol se saben de memoria a los dos días: ocupaban media
   barra para no decir nada. */
.user-name{color:#fff;font-size:13px;font-weight:600;max-width:220px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;padding:6px 10px;border-radius:11px}
/* Sólo se ve pinchable si de verdad lleva a algún sitio: quien no puede
   entrar en Usuarios lo ve como texto y no lo intenta. */
.user-name.clickable{cursor:pointer;transition:background .15s}
.user-name.clickable:hover{background:rgba(255,255,255,.14)}
/* Título de pantalla en la barra superior, detrás del imagotipo. */
.topbar-sep{width:1px;height:22px;background:rgba(255,255,255,.16);flex:none}
.topbar-title{font-size:15px;font-weight:700;color:#fff;white-space:nowrap}
#menu-toggle{color:#fff;display:none}
#menu-toggle:hover{background:rgba(255,255,255,.12)}

.app-body{display:flex;flex:1;min-height:0}
.sidebar{width:var(--sidebar-w);flex-shrink:0;background:#fff;border-right:1px solid var(--rule);
  display:flex;flex-direction:column;position:sticky;top:var(--topbar-h);height:calc(100vh - var(--topbar-h))}
.nav{flex:1;overflow-y:auto;padding:16px 14px}
.nav{position:relative}
.nav-item{position:relative;z-index:1;display:flex;align-items:center;gap:12px;padding:11px 14px;border-radius:var(--radius-sm);color:var(--steel);
  cursor:pointer;font-size:14px;font-weight:600;margin-bottom:4px;transition:color .15s}
.nav-item svg{flex-shrink:0;opacity:.8}
/* El hover **no pinta recuadro**: sólo aclara el texto. Un fondo gris
   que aparece y desaparece bajo el cursor es el mismo parche que
   quitamos de las pestañas, y encima se queda ahí mientras la pastilla
   viaja — que era justo lo que se veía al cambiar de módulo. El único
   fondo de esta lista es la pastilla activa. */
.nav-item:hover{color:var(--ink)}
.nav:not(.con-glider) .nav-item:hover{background:var(--warm-2)}
.nav-item.active{color:var(--orange-600)}
.nav:not(.con-glider) .nav-item.active{background:rgba(241,106,48,.12)}
.nav-item.active svg{opacity:1;color:var(--orange-600)}
/* ---------- Secciones del módulo abierto ----------
   La pastilla marca **el destino**: en un módulo con varias secciones
   va en la sección, y el módulo sólo se ve abierto (texto más oscuro y
   el ángulo girado). Poner pastilla en los dos sería señalar dos sitios
   para decir dónde estás. */
.nav-item.abierto{color:var(--ink)}
/* El ángulo del acordeón gira con la misma curva que la pastilla: es el
   mismo gesto —algo que se abre— y compartir curva es lo que hace que
   la barra lateral se sienta de una pieza. */
.nav-caret{margin-left:auto;opacity:.55;transition:transform var(--ease-pop)}
.nav-item.abierto .nav-caret{transform:rotate(90deg);opacity:.85}
/* La línea de la izquierda hace de sangría: dice "esto cuelga de lo de
   arriba" sin gastar el espacio de un icono por fila. */
/* Con el icono delante, la sangría se acorta para que "Puntos de venta"
   y "Plantilla factura" sigan cabiendo en una línea. */
.nav-subs{position:relative;margin:2px 0 10px 14px;padding-left:8px;
  border-left:1px solid var(--rule)}
.nav-sub{position:relative;z-index:1;display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:var(--radius-sm);
  color:var(--steel);font-size:13.5px;font-weight:600;cursor:pointer;transition:color .15s}
.nav-sub svg{flex-shrink:0;opacity:.75}
.nav-sub.active svg{opacity:1}
.nav-sub:hover{color:var(--ink)}
.nav-subs:not(.con-glider) .nav-sub:hover{background:var(--warm-2)}
.nav-sub.active{color:var(--orange-600)}
.nav-subs:not(.con-glider) .nav-sub.active{background:rgba(241,106,48,.12)}
/* Salir vive aquí abajo, encima de la versión: es lo último que se
   hace en el día y no tiene por qué estar al lado de la campana,
   compitiendo por el mismo rincón con lo que sí se usa a todas horas. */
.sidebar-foot{padding:8px 14px 12px;border-top:1px solid var(--rule);font-size:11px;color:var(--muted);
  display:flex;flex-direction:column;gap:6px;align-items:stretch}
.sidebar-foot #app-version{text-align:center}
/* Salir se lee como un elemento más del menú —mismo alto, misma sangría,
   mismo icono a la izquierda— y no como un botón enmarcado que compite
   con la navegación. El rojo aparece sólo al pasar por encima: avisa de
   lo que hace sin gritarlo todo el día desde una esquina. */
.logout-btn{display:flex;align-items:center;gap:12px;width:100%;padding:10px 14px;border:none;
  background:none;border-radius:14px;color:var(--steel);font-size:13.5px;font-weight:600;
  font-family:var(--font-body);cursor:pointer;transition:background .15s,color .15s}
.logout-btn svg{flex-shrink:0;opacity:.8}
.logout-btn:hover{background:var(--danger-bg);color:var(--danger)}
.logout-btn:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(241,106,48,.28)}

.main{flex:1;display:flex;flex-direction:column;min-width:0}
/* El título de pantalla vive en la barra superior desde la 1.33. */
.subnav{display:none;align-items:center;gap:18px;padding:0 32px;height:56px;
  background:rgba(255,255,255,.78);backdrop-filter:blur(14px);border-bottom:1px solid var(--rule);
  position:sticky;top:var(--topbar-h);z-index:20}
.subnav #page-title{font-size:17px;white-space:nowrap}
.subtabs{display:flex;gap:8px;overflow-x:auto;position:relative}
.subtab{padding:7px 15px;border-radius:20px;font-size:13px;font-weight:600;color:var(--steel);white-space:nowrap;
  transition:color .15s;position:relative;z-index:1}
.subtab:hover{color:var(--ink)}
.subtab.active{color:#fff}
.subtabs:not(.con-glider) .subtab.active{background:var(--orange-600);box-shadow:0 3px 9px rgba(218,83,29,.28)}

/* ---------- La pastilla que viaja ----------
   Una por grupo de pestañas, en vez de un recuadro por pestaña. Al
   cambiar de pestaña se desplaza; antes se desvanecía una y aparecía
   otra, y a medio camino se veían las dos. Ver js/glider.js. */
.glider{position:absolute;left:0;top:0;pointer-events:none;opacity:0;
  transition:transform .34s cubic-bezier(.34,1.28,.42,1),
             width .34s cubic-bezier(.34,1.28,.42,1),
             height .2s ease, opacity .18s ease}
.glider-visible > .glider{opacity:1}
/* Al colocarla por primera vez no se desliza desde la esquina. */
.glider.glider-quieto{transition:none}
.g-clara{background:#fff;border-radius:12px;box-shadow:0 2px 6px rgba(80,60,40,.1)}
.g-fuerte{background:var(--orange-600);border-radius:20px;box-shadow:0 3px 9px rgba(218,83,29,.28)}
.g-suave{background:rgba(241,106,48,.12);border-radius:14px}
/* El texto de la pestaña que llega espera a que llegue la pastilla.
   Sin esto, la letra se pone blanca de golpe y pasa un tercio de
   segundo en blanco sobre fondo claro: ilegible justo cuando la estás
   mirando. La que se va pierde el blanco de inmediato, que para eso se
   está yendo. */
.con-glider .subtab{transition:color .09s}
.con-glider .subtab.active{transition:color .16s .17s}
.con-glider .pill.active,
.con-glider .nav-item.active{transition:color .16s .12s}
@media (prefers-reduced-motion: reduce){
  .glider{transition:opacity .18s ease}
  .con-glider .subtab.active,.con-glider .pill.active,
  .con-glider .nav-item.active{transition:none}
  /* Quien pide menos movimiento no pierde información: el fondo y el
     color del icono siguen cambiando —eso es lo que dice "estoy aquí"—;
     lo que se va es el crecer y el hundirse, que es lo decorativo. */
  .icon-btn svg,.icon-btn:hover svg,.icon-btn:active svg{transform:none;transition:none}
  .btn:hover,.btn:active{transform:none}
  .nav-caret{transition:none}
  /* Y las piezas de dentro se quedan quietas: la tapa no se levanta y la
     campana no suena. Mismo prefijo que las enciende, para desactivarlas
     por orden en el archivo y no a base de `!important`. */
  :where(.icon-btn,.btn,.nav-item,.nav-sub,.notif-btn):is(:hover,:focus-visible)
    :is(.i-tapa,.i-lupa,.i-aguja,.i-pupila,.i-vuelta,.i-punta,.i-camion,
        .i-sube,.i-baja,.i-barre,.i-polvo,.i-entra,.i-sale,.i-campana,.i-hoja){
    transform:none;animation:none}
}


.view{padding:28px 32px;max-width:1600px;width:100%}

/* ---------- Page header ---------- */
.page-head{display:flex;align-items:flex-end;gap:16px;margin-bottom:24px;flex-wrap:wrap}
.page-head .titles h3{font-size:22px}
.page-head .titles p{margin:6px 0 0;color:var(--muted);font-size:13px;max-width:680px}
.page-head .actions{margin-left:auto;display:flex;gap:10px}

/* ---------- Cards ---------- */
.card{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);box-shadow:var(--shadow);transition:box-shadow .2s,transform .2s}
.card:hover{box-shadow:var(--shadow-lg)}
.card-pad{padding:20px}
.card-head{padding:18px 22px;border-bottom:1px solid var(--rule);display:flex;align-items:center;gap:10px}
.card-head h4{font-size:15px}
.card-head .sub{color:var(--muted);font-size:12px;font-weight:600;margin-left:auto}

/* KPI grid */
.kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-bottom:24px}
.kpi{background:var(--surface);border:1px solid var(--rule);border-radius:var(--radius);padding:20px;box-shadow:var(--shadow);transition:box-shadow .2s,transform .2s}
.kpi:hover{box-shadow:var(--shadow-lg);transform:translateY(-3px)}
.kpi .kpi-ico{width:40px;height:40px;border-radius:14px;display:flex;align-items:center;justify-content:center;background:var(--warm-2);color:var(--orange);margin-bottom:14px}
.kpi .kpi-val{font-size:26px;font-weight:800;color:var(--ink);line-height:1.05;font-family:var(--font-head)}
.kpi .kpi-lbl{color:var(--muted);font-size:12px;margin-top:4px}
.kpi.accent-ok .kpi-ico{background:var(--ok-bg);color:var(--ok)}
.kpi.accent-warn .kpi-ico{background:var(--warn-bg);color:var(--warn)}
.kpi.accent-info .kpi-ico{background:var(--warm-2);color:var(--orange)}
.kpi.accent-danger .kpi-ico{background:var(--danger-bg);color:var(--danger)}


/* ---------- Tables ---------- */
.table-wrap{overflow-x:auto}
table.data{width:100%;border-collapse:collapse;font-size:13px}
table.data th{text-align:left;background:transparent;color:var(--muted);font-weight:700;font-size:11.5px;text-transform:uppercase;letter-spacing:.02em;padding:12px 18px;border-bottom:1px solid var(--rule);white-space:nowrap}
table.data td{padding:14px 18px;border-bottom:1px solid #f4f1ec;vertical-align:middle}
table.data tbody tr:last-child td{border-bottom:none}
table.data tbody tr{transition:background .12s}
table.data tbody tr:hover{background:#fbf8f4}
/* Una fila que se abre al pincharla tiene que parecerlo antes de que
   nadie lo intente: cambia el cursor y el fondo se marca un poco más
   que el del resto. Sin eso es una función que sólo conoce quien la
   descubrió por accidente. */
table.data tbody tr.fila-pincha{cursor:pointer}
table.data tbody tr.fila-pincha:hover{background:var(--warm-2)}
/* Cabecera pinchable: agrupa por esa columna (js/tablesort.js). La
   flecha sólo se ve al pasar por encima o cuando la columna manda; si
   estuviera siempre, seis columnas serían seis flechas compitiendo con
   los títulos. */
table.data th.th-sortable{cursor:pointer;user-select:none}
table.data th.th-sortable:hover,table.data th.is-sorted{color:var(--orange-600)}
table.data th.th-sortable:focus-visible{outline:none;color:var(--orange-600);
  box-shadow:inset 0 0 0 2px rgba(241,106,48,.3);border-radius:8px}
.th-sort{display:inline-block;margin-left:6px;font-size:11px;opacity:0;transition:opacity .12s}
table.data th.th-sortable:hover .th-sort{opacity:.5}
table.data th.is-sorted .th-sort{opacity:1}
/* Donde cambia el valor, una línea más marcada: se ve el bloque sin
   tener que leer la columna. */
table.data tbody tr.grp-start>td{border-top:1px solid var(--warm)}

/* Barra de la tabla: buscador, contador y páginas (js/tabletools.js).
   Va pegada a la izquierda con `sticky` porque vive dentro del
   contenedor que hace scroll horizontal: si no, al mirar la última
   columna el buscador se iría de la pantalla. */
.tbl-tools{position:sticky;left:0;display:flex;align-items:center;gap:12px;
  padding:10px 16px;border-bottom:1px solid var(--rule)}
.tbl-q{flex:1;max-width:320px;padding:8px 12px;border:1px solid var(--rule);
  border-radius:var(--radius-sm);font-size:13px;font-family:var(--font-body);
  color:var(--ink);background:#fff;transition:border-color .15s,box-shadow .15s}
.tbl-q:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.13)}
.tbl-count{color:var(--muted);font-size:12px;font-weight:600;white-space:nowrap}
.tbl-pager{margin-left:auto;display:flex;align-items:center;gap:8px}
.tbl-page{font-size:12px;color:var(--steel);font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;
  display:inline-flex;align-items:center;gap:5px}
/* ---------- Los controles de la barra de tabla ----------
   Son cuatro y tienen que verse como una familia: el buscador, la
   casilla de página, el selector de tamaño y las dos flechas. Comparten
   borde, fondo, radio y el anillo naranja al enfocarlos; sólo cambian de
   tamaño.

   **28 px de alto los cuatro.** Es lo que mide `.tbl-nav`, y si la
   casilla de página fuera más baja que sus flechas el grupo ‹ 12 › se
   vería descuadrado.

   Lo del desplegable es lo que se salía del diseño: `.msel-trigger`
   sólo recibe borde y fondo dentro de `.ctl-scope` o `.form-row`, y una
   barra de tabla no es ninguna de las dos. Sin eso quedaba como un
   botón del navegador, con su borde negro. Aquí se le da lo mismo que
   al resto, en pequeño — heredar de `.form-row` no valía: eso lo pondría
   al 100% de ancho y con 11 px de relleno. */
.tbl-goto,.tbl-tam .msel-trigger{
  height:28px;border:1px solid var(--rule);border-radius:9px;background-color:#fff;
  font-family:var(--font-body);font-size:12px;font-weight:700;color:var(--ink);
  transition:border-color var(--ease),box-shadow var(--ease)}
/* La casilla de la página: ancho de tres cifras, que es lo que cabe en
   una lista de verdad. Sin las flechitas del navegador — ya hay dos
   flechas al lado y tres seguidas confunden. */
.tbl-goto{width:46px;padding:0 6px;text-align:center;
  font-variant-numeric:tabular-nums;-moz-appearance:textfield;appearance:textfield}
.tbl-goto::-webkit-outer-spin-button,.tbl-goto::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.tbl-goto:hover{border-color:var(--steel)}
.tbl-goto:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.15)}
/* Cuántas filas por página. Va pegado al recuento, a la izquierda: se
   lee "1–20 de 340, por página 20", que es una frase. */
.tbl-tam{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);font-weight:600;white-space:nowrap}
.tbl-tam .msel-trigger{min-width:58px;padding:0 26px 0 10px;
  /* El chevron más cerca del borde: a esta escala los 12 px de un
     formulario dejan al número descolgado a la izquierda. */
  background-position:right 8px center}
.tbl-tam .msel-trigger:hover{border-color:var(--steel)}
/* Un `<select>` sin sustituir todavía —el instante antes de que
   `select.js` lo enganche— no debe verse como el del navegador. */
.tbl-tam select{height:28px;border:1px solid var(--rule);border-radius:9px;background:#fff;
  font-family:var(--font-body);font-size:12px;font-weight:700;color:var(--ink);padding:0 6px}
.tbl-nav{width:28px;height:28px;flex:none;border:1px solid var(--rule);background:#fff;
  border-radius:9px;cursor:pointer;color:var(--ink);font-size:15px;line-height:1;
  font-family:var(--font-body)}
.tbl-nav:hover:not(:disabled){border-color:var(--orange);color:var(--orange-600)}
.tbl-nav:disabled{opacity:.35;cursor:default}
/* La última fila del cuerpo puede estar escondida por la paginación;
   el borde de abajo lo pierde la última que se ve. */
table.data tbody tr.tt-last td{border-bottom:none}
/* El paginador de servidor va debajo de la tabla, no encima. */
.tbl-tools-foot{border-bottom:none;border-top:1px solid var(--rule)}

table.data td.num,table.data th.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
table.data td.num{font-weight:600;font-size:14px;letter-spacing:.01em;color:var(--ink);font-family:var(--font-body)}
.row-actions{display:flex;gap:6px;justify-content:flex-end}
.prod-thumb{display:block;width:34px;height:34px;border-radius:8px;object-fit:cover;background:var(--warm-2);border:1px solid var(--rule)}
.prod-thumb-empty{background:var(--warm-2)}

/* ---------- Dropzone (imagen de producto) ---------- */
.dropzone{border:1.5px dashed var(--rule);border-radius:14px;background:var(--lighter);padding:26px 16px;text-align:center;cursor:pointer;transition:border-color .15s,background .15s}
.dropzone:hover,.dropzone.dropzone-over{border-color:var(--orange);background:var(--warm-2)}
.dropzone-icon{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:50%;border:1.5px solid var(--rule);font-size:16px;color:var(--steel);margin-bottom:8px}
.dropzone-title{margin:0;font-size:13.5px;font-weight:600;color:var(--text)}
.dropzone-sub{margin:4px 0 0;font-size:12px;color:var(--muted)}
.dropzone-preview-img{display:block;max-height:110px;max-width:220px;margin:0 auto;object-fit:contain;background:#fff;border:1px solid var(--rule);border-radius:10px;padding:6px}
.dropzone-preview-actions{display:flex;gap:8px;justify-content:center;margin-top:12px}

/* ---------- Badges ---------- */
.badge{display:inline-block;padding:3px 11px;border-radius:20px;font-size:11px;font-weight:700}
.badge.ok{background:var(--ok-bg);color:var(--ok)}
.badge.warn{background:var(--warn-bg);color:var(--warn)}
.badge.danger{background:var(--danger-bg);color:var(--danger)}
.badge.info{background:var(--info-bg);color:var(--info)}
.badge.mut{background:var(--warm-2);color:var(--steel)}
.badge.svc{background:var(--svc-bg);color:var(--svc)}

.mv-in{color:var(--ok);font-weight:700}
.mv-out{color:var(--danger);font-weight:700}
.mv-res{color:var(--warn);font-weight:700}

/* ---------- Avatar / chip ---------- */
.avatar{width:30px;height:30px;border-radius:12px;display:inline-flex;align-items:center;justify-content:center;
  font-weight:800;font-size:12px;color:#fff;flex-shrink:0;font-family:var(--font-head)}
/* La misma medida y el mismo redondeo que el de iniciales: al mezclar
   en una lista gente con foto y sin ella, las filas no bailan.
   `object-fit` por si alguna foto antigua no vino ya cuadrada. */
.avatar-foto{object-fit:cover;background:var(--warm-2)}
.cell-id{display:flex;align-items:center;gap:10px}
/* El chip de la barra de arriba, más pequeño que el de una tabla. */
.user-chip{display:inline-flex}
.user-chip .avatar{width:26px;height:26px;border-radius:10px;font-size:11px}
/* La foto grande del perfil, la que se elige y se ve al cambiarla. */
.perfil-foto{width:96px;height:96px;border-radius:28px;object-fit:cover;
  display:block;background:var(--warm-2);border:1px solid var(--rule)}
.perfil-fila{display:flex;align-items:center;gap:18px;margin-bottom:6px}
.perfil-fila .avatar{width:96px;height:96px;border-radius:28px;font-size:34px}
.dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:7px;vertical-align:middle}
.dot.ok{background:var(--ok)} .dot.warn{background:var(--amber)} .dot.danger{background:var(--danger)} .dot.info{background:var(--steel)}

/* ---------- Empty / placeholder ---------- */
.placeholder{max-width:620px}
.placeholder .ph-ico{width:56px;height:56px;border-radius:18px;background:var(--warm-2);color:var(--orange);display:flex;align-items:center;justify-content:center;margin-bottom:16px}
.placeholder h3{font-size:19px}
.placeholder p{color:var(--muted);font-size:13.5px;margin:8px 0 0;line-height:1.65}
.ph-note{margin-top:18px;padding:15px 17px;background:var(--lighter);border-left:3px solid var(--orange);border-radius:12px;font-size:12.5px;color:var(--steel)}
.ph-note b{color:var(--ink)}

/* Diálogo de confirmación (MO.ui.confirmModal). La pregunta va en cuerpo
   normal, legible de un vistazo; lo que venga detrás baja a .ph-note como
   matiz o consecuencia. */
.confirm-lead{margin:2px 0 0;font-size:15px;line-height:1.55;color:var(--text)}

/* ---------- Controles de formulario ----------
   REGLA: todo campo de entrada de la app —da igual si vive en un modal,
   en una barra de filtros o en una tarjeta— usa este mismo aspecto.
   Nunca se dejan los controles nativos del navegador: desentonan con
   el resto de la interfaz y cada navegador los pinta distinto.
   Para que un contenedor nuevo herede el estilo, añade su selector
   a la lista de .ctl-scope de abajo. */
.ctl-scope input:not([type=checkbox]):not([type=radio]):not([type=file]),
.ctl-scope select,
.ctl-scope textarea,
.ctl-scope .msel-trigger,
.ctl-scope .mdate-trigger,
.form-row input:not([type=checkbox]):not([type=radio]):not([type=file]),
.form-row select,
.form-row textarea,
.form-row .msel-trigger,
.form-row .mdate-trigger{
  width:100%;padding:11px 13px;border:1px solid var(--rule);border-radius:13px;
  font-size:13.5px;font-family:var(--font-body);color:var(--ink);
  /* background-color, no el atajo `background`: el atajo borraría el
     chevron que .msel-trigger pone como background-image. */
  background-color:#fff;
  transition:border-color .15s,box-shadow .15s}
.ctl-scope input:focus,.ctl-scope select:focus,.ctl-scope textarea:focus,
.form-row input:focus,.form-row select:focus,.form-row textarea:focus{
  outline:none;border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.13)}
.ctl-scope textarea,.form-row textarea{resize:vertical}
.ctl-scope select:disabled,.form-row select:disabled,
.ctl-scope input:disabled,.form-row input:disabled{background:var(--warm-2);color:var(--muted);cursor:not-allowed}

/* ---------- Desplegables (js/select.js) ----------
   REGLA: la lista que abre un <select> nativo la pinta el sistema
   operativo y el CSS no la alcanza. Por eso cada <select> se sustituye
   por este control: el original queda oculto dentro de .msel para que
   `.value` siga funcionando, y lo visible es .msel-trigger + .msel-pop.
   No hace falta llamar a nada: js/select.js los detecta solo. */
.msel{position:relative}
.msel select{display:none}
.msel-trigger{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  text-align:left;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2383838b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;padding-right:34px}
.msel-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-label.is-placeholder{color:var(--muted)}
.msel.is-open .msel-trigger{border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.13)}
.msel-trigger:disabled{background-color:var(--warm-2);color:var(--muted);cursor:not-allowed}

/* Posición fija y colgando de <body>: cada .card crea un contexto de
   apilamiento (lleva animation), así que dentro de la tarjeta la lista
   quedaría recortada por mucho z-index que se le diera. js/select.js
   calcula left/top/width al abrir. */
.msel-pop{position:fixed;z-index:80;
  background:#fff;border:1px solid var(--rule);border-radius:var(--radius-sm);
  box-shadow:0 12px 28px rgba(80,60,40,.14);padding:4px}
/* Sólo desplaza la lista: el buscador queda fijo arriba. */
.msel-list{max-height:240px;overflow:auto}
.msel-search{padding:2px 2px 6px;border-bottom:1px solid var(--rule);margin-bottom:4px}
.msel-search-input{width:100%;padding:8px 11px;border:1px solid var(--rule);border-radius:10px;
  font-size:13px;font-family:var(--font-body);color:var(--ink);background:#fff}
.msel-search-input:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.13)}
.msel-opt{padding:8px 11px;font-size:13px;border-radius:var(--radius-xs);cursor:pointer;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-opt:hover,.msel-opt.is-active{background:var(--warm-2)}
.msel-opt[aria-selected=true]{color:var(--orange-600);font-weight:700}
.msel-opt[data-disabled]{color:var(--muted);cursor:not-allowed}
.msel-group{padding:7px 11px 3px;font-size:10.5px;font-weight:800;text-transform:uppercase;
  letter-spacing:.05em;color:var(--steel)}
.msel-empty{padding:8px 11px;font-size:13px;color:var(--muted)}

/* ---------- Selector de fecha (js/datepicker.js) ----------
   REGLA: igual que con los <select>, el calendario de un
   <input type="date"> lo pinta el navegador y el CSS no lo alcanza.
   El input queda oculto dentro de .mdate conservando su valor ISO y lo
   visible es .mdate-trigger + .mdate-pop. */
.mdate{position:relative}
.mdate input[type=date]{display:none}
.mdate-trigger{
  display:flex;align-items:center;text-align:left;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%2383838b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;padding-right:36px}
.mdate-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mdate-label.is-placeholder{color:var(--muted)}
.mdate-trigger:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.13)}
.mdate-trigger:disabled{background-color:var(--warm-2);color:var(--muted);cursor:not-allowed}

.mdate-pop{position:fixed;z-index:80;width:266px;padding:10px;
  background:#fff;border:1px solid var(--rule);border-radius:var(--radius-sm);
  box-shadow:0 12px 28px rgba(80,60,40,.14)}
.mdate-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
.mdate-title{font-size:13px;font-weight:800;color:var(--ink);display:flex;gap:4px}
/* El mes y el año del título se pinchan para saltar de nivel. Se ven
   como texto y no como botones —el calendario ya tiene bastantes—, pero
   reaccionan al señalarlos: si no, nadie descubre que se pueden pulsar. */
.mdate-salto{border:none;background:none;cursor:pointer;padding:2px 6px;border-radius:var(--radius-xs);
  font-family:var(--font-body);font-size:13px;font-weight:800;color:var(--ink);
  transition:background var(--ease),color var(--ease)}
.mdate-salto:hover{background:var(--warm-2);color:var(--orange-600)}
.mdate-salto:focus-visible{outline:none;background:var(--warm-2);color:var(--orange-600);
  box-shadow:0 0 0 3px rgba(241,106,48,.28)}
/* Meses y años: cuatro por fila —doce en tres filas, que es como se lee
   un año— y celdas más altas, porque llevan texto ("Sep", "2029") y no
   un número de dos cifras.

   Van con doble clase a propósito: `.mdate-grid` define las siete
   columnas del calendario y está **más abajo en el archivo**, así que a
   igualdad de especificidad ganaría él y los meses saldrían de siete en
   siete. Con `.mdate-grid.mdate-meses` el orden deja de importar. */
.mdate-grid.mdate-meses,.mdate-grid.mdate-anios{grid-template-columns:repeat(4,1fr);gap:4px}
.mdate-meses .mdate-cell,.mdate-anios .mdate-cell{padding:10px 0;font-size:12.5px}
.mdate-nav{border:none;background:none;cursor:pointer;color:var(--steel);
  font-size:19px;line-height:1;padding:2px 9px;border-radius:9px}
.mdate-nav:hover{background:var(--warm-2);color:var(--ink)}
.mdate-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.mdate-dows span{text-align:center;font-size:10.5px;font-weight:800;color:var(--steel);padding:4px 0}
.mdate-cell{border:none;background:none;cursor:pointer;font-family:var(--font-body);
  font-size:12.5px;color:var(--ink);padding:7px 0;border-radius:9px}
.mdate-cell.is-empty{cursor:default}
.mdate-cell:not(.is-empty):hover{background:var(--warm-2)}
.mdate-cell.is-today{font-weight:800;color:var(--orange-600)}
.mdate-cell.is-selected{background:var(--orange);color:#fff;font-weight:800}
.mdate-foot{display:flex;justify-content:space-between;gap:8px;margin-top:8px;
  padding-top:8px;border-top:1px solid var(--rule)}

.form-row{margin-bottom:15px}
.form-row.two{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.form-row label{display:block;font-size:12px;font-weight:600;color:var(--steel);margin-bottom:6px}

/* ---------- Modal ---------- */
.modal{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;padding:20px}
.modal-backdrop{position:absolute;inset:0;background:rgba(60,45,30,.34);backdrop-filter:blur(3px)}
.modal-card{position:relative;background:#fff;border-radius:var(--radius);box-shadow:0 30px 90px rgba(60,40,20,.34);width:100%;max-width:490px;max-height:90vh;overflow:auto}
.modal-card.wide{max-width:1180px}
.modal-head{display:flex;align-items:center;padding:18px 22px;border-bottom:1px solid var(--rule)}
.modal-head h3{font-size:16px}
.modal-head .icon-btn{margin-left:auto}
.modal-body{padding:22px}
.modal-foot{display:flex;justify-content:flex-end;gap:10px;margin-top:22px}
/* Lo que no es "cerrar esto" va al otro extremo: Duplicar abre otra
   ficha, no cierra ésta, y puesto junto a Guardar se pulsa sin querer. */
.modal-foot .foot-izq{margin-right:auto}

/* ---------- Toast ---------- */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:80;background:var(--ink);color:#fff;padding:12px 22px;border-radius:15px;font-size:13px;box-shadow:0 12px 36px rgba(60,40,20,.30);font-weight:600}
.toast.ok{background:var(--ok)}
.toast.err{background:var(--danger)}

/* ---------- Print surface (facturas/compras/transferencias) ----------
   En pantalla: modal chico centrado, igual de familia visual que
   .modal. Al imprimir (@media print): el documento sale a tamaño
   completo, sin el "chrome" del modal. */
#doc-print-root{display:none}
body.doc-preview{overflow:hidden}
body.doc-preview #doc-print-root{
  display:flex;
  position:fixed;
  inset:0;
  z-index:90;
  align-items:center;
  justify-content:center;
  padding:20px;
}
#doc-print-root .doc-preview-backdrop{
  position:absolute;
  inset:0;
  background:rgba(30,24,18,.45);
}
#doc-print-root .doc-preview-card{
  position:relative;
  z-index:1;
  width:100%;
  max-width:780px;
  max-height:88vh;
  display:flex;
  flex-direction:column;
  background:#ecebe8;
  border-radius:20px;
  box-shadow:0 30px 80px rgba(0,0,0,.35);
  overflow:hidden;
}
#doc-print-root .doc-preview-chrome{
  display:flex;
  justify-content:flex-end;
  gap:10px;
  padding:12px 16px;
  background:#fff;
  border-bottom:1px solid #e2e2e2;
}
#doc-print-root .doc-preview-stage{
  overflow:auto;
  padding:16px;
}
#doc-print-root .doc-preview-stage .doc-body{
  max-width:none;
  margin:0 auto;
  background:#fff;
  border:1px solid #d8d8d8;
  box-shadow:0 8px 24px rgba(0,0,0,.08);
  padding:12px;
}
@media print{
  body.doc-preview{background:#fff;overflow:visible}
  body.doc-preview > *{display:none !important}
  body.doc-preview #doc-print-root{
    display:block !important;
    position:static;
    inset:auto;
    padding:0;
  }
  body.doc-preview #doc-print-root .doc-preview-backdrop{display:none !important}
  body.doc-preview #doc-print-root .doc-preview-card{
    position:static;
    max-width:none;
    max-height:none;
    background:#fff;
    border-radius:0;
    box-shadow:none;
    overflow:visible;
  }
  body.doc-preview #doc-print-root .doc-preview-chrome{display:none !important}
  body.doc-preview #doc-print-root .doc-preview-stage{
    overflow:visible;
    padding:0;
  }
  body.doc-preview #doc-print-root .doc-preview-stage .doc-body{
    max-width:none;
    margin:0;
    border:none;
    box-shadow:none;
    padding:0;
  }
}

/* ---------- Responsive ---------- */
@media(max-width:920px){.kpi-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:760px){
  .sidebar{position:fixed;z-index:50;left:0;top:var(--topbar-h);transform:translateX(-100%);transition:transform .2s;box-shadow:0 0 40px rgba(0,0,0,.25)}
  .sidebar.open{transform:translateX(0)}
  #menu-toggle{display:inline-flex}
  .user-name{display:none}
  .view{padding:20px}
  .subnav{padding:0 20px}
}
/* Ancho intermedio: formularios de dos columnas (ver .form-cols). */
.modal-card.medium{max-width:820px}
/* Formulario en dos columnas. Un alta con catorce campos en una sola
   columna obliga a hacer scroll dentro del modal, y lo que queda fuera
   —la foto, las cuentas— se olvida. Al partirlo en dos el recuadro
   queda casi cuadrado y se ve entero de una vez. */
.form-cols{display:grid;grid-template-columns:1fr 1fr;gap:0 22px}
.form-col{min-width:0}
@media(max-width:720px){.form-cols{grid-template-columns:1fr}}


/* =============================================================
   Panel 1.33 — rótulo arriba, cifra grande, comparación debajo.
   Sólo aplica a .kpi-grid.kpi-lead (el Panel): los KPI del panel de
   Contabilidad son muchos y pequeños y siguen con su formato.
   ============================================================= */
.kpi-lead .kpi{padding:18px 20px}
.kpi-lead .kpi:hover{transform:none}
.kpi-top{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:12px;font-weight:600}
.kpi-top svg{margin-left:auto;flex:none;opacity:.45}
.kpi-lead .kpi-val{font-size:34px;letter-spacing:-.02em;margin-top:8px;font-variant-numeric:tabular-nums}
.kpi-lead .kpi.is-alert .kpi-val{color:var(--danger)}
.kpi-delta{margin-top:6px;font-size:12.5px;font-weight:600;color:var(--muted)}
.kpi-delta.up{color:var(--ok)}
.kpi-delta.bad{color:var(--danger)}
.kpi-delta.warn{color:var(--warn)}

/* Línea secundaria: lo que hay que tener a mano pero no es lo primero. */
.panel-strip{display:flex;align-items:baseline;gap:10px;margin:10px 2px 20px;font-size:12.5px;color:var(--muted)}
.panel-strip b{color:var(--text);font-weight:700;font-variant-numeric:tabular-nums}
.panel-strip .right{margin-left:auto}

/* La fecha del día, encima de las cifras. Se llama `panel-dia` porque
   `panel-bar` ya era del panel de Contabilidad (`charts.css`, que carga
   después y lo alinea a la derecha): el rediseño reutilizó el nombre sin
   saberlo y la fecha se iba al otro lado. */
.panel-dia{display:flex;align-items:center;gap:12px;margin-bottom:16px}
.panel-dia p{margin:0;font-size:13px;color:var(--muted)}

/* Dos columnas: lo que hay que atender, y la tendencia al lado. */
.panel-cols{display:grid;grid-template-columns:1.12fr 1fr;gap:20px}
@media(max-width:1100px){.panel-cols{grid-template-columns:1fr}}

/* Lo que hay que atender hoy. Cada fila lleva el dato con el que se
   decide y lleva a la pantalla donde se resuelve. */
.today-row{display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  padding:13px 20px;border:none;border-bottom:1px solid #F1EDE6;background:none;
  cursor:pointer;font-family:var(--font-body);transition:background .12s}
.today-row:last-child{border-bottom:none}
.today-row:hover{background:var(--lighter)}
.today-row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px rgba(241,106,48,.28)}
.today-row .dot{margin-right:0;flex:none}
.today-t{font-size:13.5px;font-weight:600;color:var(--ink)}
.today-m{font-size:13px;color:var(--muted)}
.today-v{margin-left:auto;font-size:13.5px;font-weight:700;color:var(--text);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.today-v.bad{color:var(--danger)}
.today-row>svg:last-child{flex:none;opacity:.4;color:var(--steel)}
.today-ok{padding:26px 20px;text-align:center;font-size:13px;color:var(--muted)}
.chart-foot{display:flex;align-items:baseline;gap:8px;margin-top:12px;padding-top:12px;
  border-top:1px solid #F1EDE6;font-size:12.5px;color:var(--muted)}
.chart-foot b{color:var(--text);font-weight:700;font-variant-numeric:tabular-nums}
.chart-foot .right{margin-left:auto;font-weight:600}

/* La densidad compacta se quitó en la 1.33.1 por ser un interruptor
   escondido y global. Volvió en la 1.64 como una de las tres vistas de
   cada tabla larga (js/vistas.js): a la vista, junto al buscador, y
   por pantalla. */

/* La barra de "hay una versión nueva" (js/actualizacion.js): abajo,
   encima de todo, y no se va sola. */
.nueva-version{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:60;display:flex;align-items:center;gap:14px;
  max-width:calc(100% - 32px);padding:10px 12px 10px 16px;border-radius:14px;background:var(--ink);color:#fff;font-size:13px;
  box-shadow:0 10px 30px rgba(0,0,0,.25)}
.nueva-version .btn{white-space:nowrap}

/* ---------- Punto de venta ----------
   Dos columnas: a la izquierda se busca o se escanea; a la derecha
   está el ticket que se arma. El total y "Cobrar" son lo más grande de
   la pantalla porque son lo único que se mira con el cliente delante. */
.pos-grid{display:grid;grid-template-columns:1.25fr 1fr;gap:16px;align-items:start}
@media(max-width:1000px){.pos-grid{grid-template-columns:1fr}}
.pos-terminal-wrap .msel-trigger{width:auto;min-width:180px;padding:9px 34px 9px 13px}
.pos-lbl{display:block;font-size:12px;font-weight:600;color:var(--steel);margin-bottom:6px}
.pos-input{width:100%;font-size:16px;padding:11px 13px;border:1px solid var(--rule);border-radius:12px;
  background:var(--lighter);font-family:var(--font-body);color:var(--ink)}
.pos-input:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.16);background:#fff}
.pos-buscar-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
/* El conmutador de vista: tres iconos, el elegido en naranja. */
.pos-vistas{display:inline-flex;gap:2px;padding:2px;border:1px solid var(--rule);border-radius:10px;background:#fff}
.pos-vista{display:inline-flex;align-items:center;justify-content:center;width:30px;height:26px;border:none;border-radius:8px;
  background:none;color:var(--steel);cursor:pointer;transition:background .12s,color .12s}
.pos-vista:hover{color:var(--ink);background:var(--warm-2)}
.pos-vista.on{background:rgba(241,106,48,.12);color:var(--orange-600)}
.pos-lista{margin-top:10px;max-height:60vh;overflow:auto;display:flex;flex-direction:column;gap:4px}
/* Tarjetas: la foto manda, y el precio va grande porque es lo que se
   lee con el cliente delante. */
.pos-lista.vista-tarjetas{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:8px}
.pos-card{display:flex;flex-direction:column;gap:6px;padding:8px;border:1px solid var(--rule);border-radius:12px;background:#fff;
  cursor:pointer;text-align:left;font-family:var(--font-body);color:var(--ink);transition:border-color .12s,box-shadow .12s,transform .12s}
.pos-card:hover,.pos-card:focus-visible{border-color:var(--orange);box-shadow:0 4px 12px rgba(80,60,40,.08);outline:none;transform:translateY(-1px)}
.pos-card.sin{opacity:.55}
.pos-card-img{display:block;aspect-ratio:1;border-radius:9px;overflow:hidden;background:var(--warm-2)}
.pos-card-img img{display:block;width:100%;height:100%;object-fit:cover}
.pos-card-sin{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:22px;font-weight:800;color:var(--steel);opacity:.5}
.pos-card-n{font-size:12.5px;font-weight:600;line-height:1.25;min-height:2.5em;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.pos-card-f{display:flex;align-items:baseline;justify-content:space-between;gap:6px}
.pos-card-p{font-size:14px;font-weight:800;font-variant-numeric:tabular-nums}
.pos-card-s{font-size:11px;color:var(--muted);white-space:nowrap}
/* Compacta: filas de una línea, sin aire, para catálogos largos. */
.pos-lista.vista-compacta{gap:0}
.pos-row{display:grid;grid-template-columns:1fr auto auto auto;gap:10px;align-items:center;width:100%;text-align:left;
  padding:5px 8px;border:none;border-bottom:1px solid #F1EDE6;background:none;cursor:pointer;
  font-family:var(--font-body);font-size:12.5px;color:var(--ink)}
.pos-row:hover,.pos-row:focus-visible{background:var(--lighter);outline:none}
.pos-row.sin{opacity:.55}
.pos-row-n{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
.pos-row-c{font-size:11px;color:var(--muted)}
.pos-row-s{font-size:11.5px;color:var(--muted);white-space:nowrap;min-width:60px;text-align:right}
.pos-row-p{font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;min-width:64px;text-align:right}
.pos-item{display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;width:100%;text-align:left;
  padding:9px 12px;border:1px solid transparent;border-radius:12px;background:none;cursor:pointer;
  font-family:var(--font-body);font-size:13.5px;color:var(--ink);transition:background .12s,border-color .12s}
.pos-item:hover,.pos-item:focus-visible{background:var(--lighter);border-color:var(--rule);outline:none}
.pos-item.sin{opacity:.55}
.pos-item-n code{font-size:11px;color:var(--muted);margin-left:6px}
.pos-item-s{font-size:12px;color:var(--muted);white-space:nowrap}
.pos-item-p{font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.pos-vacio{padding:18px 12px;text-align:center;font-size:13px;color:var(--muted)}
.pos-ticket-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.pos-lineas{display:flex;flex-direction:column;gap:6px;min-height:120px;max-height:48vh;overflow:auto}
.pos-linea{display:grid;grid-template-columns:1fr auto auto auto;gap:10px;align-items:center;
  padding:8px 6px 8px 10px;border-radius:12px;background:var(--lighter)}
.pos-linea.pasa{background:var(--danger-bg)}
.pos-linea-n{font-size:13.5px;font-weight:600;color:var(--ink);min-width:0;overflow-wrap:anywhere}
.pos-linea-n small{display:block;font-weight:500;color:var(--muted)}
.pos-linea-n em{display:block;font-style:normal;font-size:12px;color:var(--danger);font-weight:600}
.pos-linea-q{display:flex;align-items:center;gap:2px}
.pos-linea-q input{width:52px;text-align:center;font-size:14px;font-weight:700;padding:6px 4px;
  border:1px solid var(--rule);border-radius:10px;background:#fff;font-family:var(--font-body);color:var(--ink)}
.pos-linea-q input:focus{outline:none;border-color:var(--orange)}
.pos-linea-q .icon-btn{font-size:18px;line-height:1;padding:5px 8px}
.pos-linea-t{font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap;min-width:70px;text-align:right}
.pos-total{display:flex;align-items:baseline;justify-content:space-between;margin-top:14px;padding-top:12px;
  border-top:2px solid var(--rule)}
.pos-total span{font-size:13px;font-weight:600;color:var(--steel)}
.pos-total strong{font-size:30px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.pos-cobrar{width:100%;margin-top:12px;padding:14px;font-size:17px;border-radius:14px}
.pos-ultima{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:12px;
  padding:10px 12px;border-radius:12px;background:var(--ok-bg);color:var(--ok);font-size:13px}
.pos-ventas-head{display:flex;align-items:center;gap:10px;padding:14px 20px 4px}
.pos-apertura{max-width:520px}
.pos-apertura h4{margin:0 0 6px;font-size:16px}
.pos-apertura .ph-note{margin:0 0 16px}
/* Cobrar: el método se elige con tres botones grandes, no con una lista. */
.pos-metodos{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:16px}
.pos-metodo{padding:12px 8px;border:1.5px solid var(--rule);border-radius:12px;background:#fff;cursor:pointer;
  font-family:var(--font-body);font-size:13.5px;font-weight:600;color:var(--steel);transition:all .12s}
.pos-metodo:hover{border-color:var(--orange);color:var(--ink)}
.pos-metodo.on{border-color:var(--orange);background:rgba(241,106,48,.08);color:var(--orange-600)}
.pos-rapidos{display:flex;flex-wrap:wrap;gap:6px;margin:-6px 0 12px}
.pos-cambio{display:flex;align-items:baseline;justify-content:space-between;padding:12px 14px;border-radius:12px;
  background:var(--lighter);margin-bottom:12px}
.pos-cambio span{font-size:12.5px;font-weight:600;color:var(--steel)}
.pos-cambio strong{font-size:24px;font-weight:800;color:var(--ok);font-variant-numeric:tabular-nums}
.pos-cambio strong.falta{color:var(--danger)}
.pos-resumen td:first-child{color:var(--steel)}
.pos-arqueo{margin-top:14px;padding:14px 16px;border-radius:12px;background:var(--lighter)}
.pos-arqueo>div{display:flex;justify-content:space-between;align-items:baseline;padding:3px 0}
.pos-arqueo span{font-size:12.5px;font-weight:600;color:var(--steel)}
.pos-arqueo strong{font-size:18px;font-variant-numeric:tabular-nums}
.pos-arqueo p{margin:8px 0 0;font-weight:700}
.pos-arqueo.ok{background:var(--ok-bg)}.pos-arqueo.ok p{color:var(--ok)}
.pos-arqueo.falta{background:var(--danger-bg)}.pos-arqueo.falta p,.pos-arqueo.falta strong{color:var(--danger)}
.pos-arqueo.sobra{background:var(--warn-bg)}.pos-arqueo.sobra p{color:var(--warn)}

/* ---------- Tres vistas para cualquier tabla larga (js/vistas.js) ----------
   Cómoda es la tabla tal cual. Las otras dos son clases sobre la misma
   tabla: nada se rehace, los botones de cada fila son los mismos. */
.tbl-vistas{display:inline-flex;gap:2px;padding:2px;border:1px solid var(--rule);border-radius:10px;background:#fff;margin-left:auto}
.tbl-vista{display:inline-flex;align-items:center;justify-content:center;width:30px;height:26px;border:none;border-radius:8px;
  background:none;color:var(--steel);cursor:pointer;transition:background .12s,color .12s}
.tbl-vista:hover{color:var(--ink);background:var(--warm-2)}
.tbl-vista.on{background:rgba(241,106,48,.12);color:var(--orange-600)}
.tbl-tools-solo-vistas{padding:6px 12px;justify-content:flex-end}

/* Compacta: menos aire, letra un punto menor. */
table.data.vista-compacta{font-size:12.5px}
table.data.vista-compacta th{padding:7px 12px;font-size:11px}
table.data.vista-compacta td{padding:6px 12px}
table.data.vista-compacta .icon-btn{padding:4px}
table.data.vista-compacta .badge{padding:2px 8px;font-size:10.5px}
/* La ficha con foto es lo que da alto a la fila: en compacta, chica. */
table.data.vista-compacta .avatar{width:22px;height:22px;border-radius:8px;font-size:9px}
table.data.vista-compacta .cell-id{gap:7px}
table.data.vista-compacta .row-actions .icon-btn,table.data.vista-compacta .row-menu-btn{padding:3px 5px}
/* En tarjetas, la foto del título va grande: es lo que se reconoce. */

/* Tarjetas: cada fila es una tarjeta; cada celda, "etiqueta: valor"
   con la etiqueta sacada de la cabecera (data-label). La primera
   celda es el título; la última, si es de acciones, va abajo a la
   derecha sin etiqueta. */
table.data.vista-tarjetas{display:block}
table.data.vista-tarjetas thead{display:none}
table.data.vista-tarjetas tbody{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:12px;padding:14px 16px}
/* La tarjeta: una fila en flex con salto. La foto (si la hay) y el
   título van en la primera línea; el resto, una celda por línea. */
table.data.vista-tarjetas tbody tr{display:flex;flex-wrap:wrap;align-items:flex-start;padding:12px 14px;
  border:1px solid var(--rule);border-radius:12px;background:#fff;transition:border-color .12s,box-shadow .12s}
table.data.vista-tarjetas tbody tr:hover{background:#fff;border-color:var(--orange);box-shadow:0 4px 12px rgba(80,60,40,.08)}
table.data.vista-tarjetas tbody tr[hidden]{display:none!important}
table.data.vista-tarjetas tbody tr.tt-nada,table.data.vista-tarjetas tbody tr.total{grid-column:1/-1}
/* Cada celda: etiqueta a la izquierda, valor a la derecha, y el valor
   fluye y salta de línea si es largo (nombre + unidad + insignia). */
table.data.vista-tarjetas td{flex:0 0 100%;display:grid;grid-template-columns:minmax(72px,30%) 1fr;gap:2px 10px;
  align-items:baseline;padding:3px 0;border:none;text-align:left;min-width:0;white-space:normal}
table.data.vista-tarjetas td::before{content:attr(data-label);font-size:10.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.02em;color:var(--muted);overflow-wrap:anywhere}
table.data.vista-tarjetas td>.tv{min-width:0;overflow-wrap:anywhere;line-height:1.4}
table.data.vista-tarjetas td.num>.tv{text-align:right;font-variant-numeric:tabular-nums}
table.data.vista-tarjetas td[data-label=""]{grid-template-columns:1fr}
table.data.vista-tarjetas td[data-label=""]::before{display:none}
/* El título: grande, arriba, con la foto al lado si la fila la tiene. */
table.data.vista-tarjetas td[data-rol="titulo"]{order:-1;flex:1 1 60%;display:block;font-size:14px;font-weight:700;
  padding:0 0 8px;margin-bottom:6px;border-bottom:1px solid #F1EDE6;align-self:stretch}
table.data.vista-tarjetas td[data-rol="titulo"]::before{display:none}
table.data.vista-tarjetas td[data-rol="titulo"]>.tv{text-align:left}
table.data.vista-tarjetas td[data-rol="foto"]{order:-2;flex:0 0 auto;display:block;padding:0 10px 8px 0;margin-bottom:6px;
  border-bottom:1px solid #F1EDE6;align-self:stretch}
table.data.vista-tarjetas td[data-rol="foto"]::before{display:none}
table.data.vista-tarjetas td[data-rol="foto"] .prod-thumb,table.data.vista-tarjetas td[data-rol="foto"] img{width:48px;height:48px;border-radius:10px}
/* Las acciones, abajo a la derecha, sin etiqueta. */
table.data.vista-tarjetas td[data-rol="acciones"]{display:block;padding-top:8px;margin-top:auto}
table.data.vista-tarjetas td[data-rol="acciones"]>.tv{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:4px}
table.data.vista-tarjetas td[data-rol="acciones"]::before{display:none}
table.data.vista-tarjetas .row-actions{justify-content:flex-end}
table.data.vista-tarjetas td.empty-cell{display:block;text-align:center}
table.data.vista-tarjetas td:first-child .avatar{width:40px;height:40px;font-size:14px}

/* ==== css/charts.css ==== */
/* =============================================================
   Estilos de gráficos del dashboard (complemento de styles.css)
   ============================================================= */

.card-pad{padding:14px 16px}
.card .sub{color:var(--muted);font-size:11.5px;font-weight:600}
.card-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}

/* SVG de tendencia */
.c-svg{width:100%;height:auto;display:block}
.c-grid{stroke:var(--rule);stroke-width:1;shape-rendering:crispEdges;opacity:.7}
.c-axis{fill:var(--muted);font-size:10.5px;font-family:inherit}
.c-line{fill:none;stroke:var(--orange);stroke-width:2.5;stroke-linejoin:round;stroke-linecap:round}
.c-dot{fill:#fff;stroke:var(--orange);stroke-width:2}
.c-cross{stroke:var(--orange);stroke-width:1;stroke-dasharray:3 3;opacity:.6}
.c-hot{cursor:crosshair}
.chart-empty{color:var(--muted);font-size:12.5px;padding:24px;text-align:center}

/* Barras horizontales */
.hbars{display:flex;flex-direction:column;gap:12px;padding:14px 16px}
.hbar-top{display:flex;align-items:center;gap:8px;margin-bottom:5px}
.hbar-lbl{font-size:12.5px;color:var(--text);font-weight:600;flex:1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hbar-val{font-size:12px;color:var(--navy);font-weight:700;font-variant-numeric:tabular-nums}
.hbar-track{height:9px;background:var(--lighter);border-radius:6px;overflow:hidden}
.hbar-fill{height:100%;border-radius:6px;transition:width .35s ease}
.hbar-fill.tone-info{background:var(--orange)}
.hbar-fill.tone-ok{background:var(--ok)}
.hbar-fill.tone-warn{background:var(--warn)}
.hbar-fill.tone-danger{background:var(--danger)}

/* Tooltip flotante */
.chart-tip{
  position:fixed;z-index:60;pointer-events:none;background:var(--navy);color:#fff;
  font-size:12px;line-height:1.35;padding:7px 10px;border-radius:8px;max-width:220px;
  box-shadow:0 6px 20px rgba(20,35,60,.25);
}
.chart-tip strong{color:#fff}

/* KPIs: barra de acento superior por tono (además del color del icono) */
.kpi{position:relative;overflow:hidden}
.kpi::before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--brand-grad-v)}
.kpi.accent-ok::before{background:var(--ok)}
.kpi.accent-warn::before{background:var(--amber)}
.kpi.accent-info::before{background:var(--brand-grad-v)}
.kpi.accent-danger::before{background:var(--orange)}

/* Selects y checks dentro de formularios del modal */
.form-row select{width:100%;padding:9px 11px;border:1px solid var(--rule);
  border-radius:var(--radius-sm);font-size:13.5px;background:#fff;color:var(--text)}
.form-row select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(47,91,150,.14)}
.form-row label.check{display:flex;align-items:center;gap:8px;font-weight:600;color:var(--steel);
  margin:0;cursor:pointer}
.form-row label.check input{width:auto;margin:0}

/* Editor de líneas de documento */
.li-label{display:block;font-size:12px;font-weight:600;color:var(--steel);margin:4px 0 6px}
.li-rows{display:flex;flex-direction:column;gap:8px}
.li-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* Cantidad por encima del stock disponible: el campo se tiñe y el motivo
   baja a una segunda línea, en vez de esconderse en un `title`. */
.li-row input.li-over{border-color:var(--danger);background-color:var(--danger-bg);color:var(--danger);font-weight:600}
.li-row input.li-over:focus{border-color:var(--danger);box-shadow:0 0 0 4px rgba(192,67,30,.16)}
.li-stock-hint{flex:0 0 100%;margin:-2px 34px 0 0;text-align:right;font-size:12px;color:var(--danger)}
.li-row .li-prod-wrap{flex:1;min-width:0;position:relative}
.li-row .msel-trigger,.li-row input{padding:8px 10px;border:1px solid var(--rule);
  border-radius:var(--radius-sm);font-size:13px;background-color:#fff;color:var(--text)}
/* El desplegable dentro de una línea mantiene el tamaño compacto. */
.li-row .msel{flex:0 0 auto}
.li-row .msel-trigger{padding-right:30px;background-position:right 9px center}
.li-row .li-prod-input{width:100%}
.li-row input[type=number]{width:92px}
.li-row .li-del{color:var(--danger);flex:0 0 auto}
.li-add{margin-top:10px}

/* Fija y colgando de <body>, como .msel-pop: dentro de la fila quedaba
   detrás de las líneas siguientes y recortada por el `overflow` del
   modal. `position:absolute` + z-index no lo arregla, porque la .card
   lleva animación y eso abre un contexto de apilamiento del que no se
   puede salir. js/lineItems.js calcula left/top/width al abrir. */
.li-prod-pop{position:fixed;z-index:80;
  max-height:220px;overflow:auto;background:#fff;border:1px solid var(--rule);
  border-radius:var(--radius-sm);box-shadow:0 12px 28px rgba(60,40,20,.14)}
.li-prod-opt{padding:8px 12px;font-size:13px;cursor:pointer}
.li-prod-opt:hover{background:var(--warm-2)}
.li-prod-empty{padding:8px 12px;font-size:13px;color:var(--muted)}

/* Combobox de búsqueda genérico (Cliente, Proveedor, etc.) */
.combo-wrap{position:relative}
.combo-input{width:100%;padding:9px 11px;border:1px solid var(--rule);
  border-radius:var(--radius-sm);font-size:13.5px;background:#fff;color:var(--text)}
.combo-input:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(47,91,150,.14)}
/* Igual que .li-prod-pop y .msel-pop: fuera de la tarjeta, fija, y
   colocada por js/combobox.js al abrir. */
/* La caja del panel flotante: la comparten el desplegable, las
   sugerencias de etiquetas y la paleta de color. Estaba atada sólo a
   `.combo-pop`, y el panel de color salió sin fondo ni sombra hasta que
   se le dio su nombre aquí. */
.combo-pop,.color-pop{position:fixed;z-index:80;
  max-height:220px;overflow:auto;background:#fff;border:1px solid var(--rule);
  border-radius:var(--radius-sm);box-shadow:0 12px 28px rgba(60,40,20,.14)}
.color-pop{max-height:none}
.combo-opt{padding:8px 12px;font-size:13px;cursor:pointer}
.combo-opt:hover{background:var(--warm-2)}
.combo-opt-add{color:var(--orange-600);font-weight:600;border-top:1px solid var(--rule)}
.combo-empty{padding:8px 12px;font-size:13px;color:var(--muted)}

/* Tabla compacta en modales de detalle */
.data.mini{font-size:12.5px;margin:6px 0 4px}
.data.mini th,.data.mini td{padding:6px 8px}
.data.mini tr.row-changed{background:#fff3ef}
.data.mini tr.row-changed td:first-child{font-weight:700}
/* REGLA: todo control dentro de una tabla compacta hereda la identidad de
   la app en formato reducido, sin tener que acordarse de poner clase. Es la
   tercera vía de .ctl-scope / .form-row, para celdas donde un control de
   40px de alto haría la fila enorme. */
.mini-input,
.data.mini input:not([type=checkbox]):not([type=radio]):not([type=file]),
.data.mini textarea,
.data.mini .combo-input,
.data.mini .msel-trigger,
.data.mini .mdate-trigger{
  padding:7px 9px;border:1px solid var(--rule);border-radius:9px;font-size:12.5px;
  font-family:var(--font-body);width:100%;color:var(--ink);background-color:#fff;
  transition:border-color .15s,box-shadow .15s}
.mini-input:focus,
.data.mini input:focus,.data.mini textarea:focus,.data.mini .combo-input:focus,
.data.mini .msel-trigger:focus,.data.mini .mdate-trigger:focus{
  outline:none;border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.13)}
.data.mini .msel-trigger,.data.mini .mdate-trigger{
  padding-right:28px;background-position:right 8px center}
input[type=number].mini-input,.data.mini input[type=number]{text-align:right}
.data.mini label.check{font-size:12.5px;color:var(--steel);gap:6px}

/* Plan de cuentas: punto de color por tipo + nombre con icono */
.acct-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:8px;flex:0 0 auto}
.acct-table td:first-child{white-space:nowrap}
.acct-name{display:inline-flex;align-items:center;gap:7px;font-weight:700;color:var(--ink)}
.acct-name svg{flex:0 0 auto;color:var(--steel)}
.color-input{width:100%;height:42px;padding:3px;border:1px solid var(--rule);border-radius:13px;cursor:pointer;background:#fff}

/* Libro Mayor: árbol de cuentas plegable y saltos cuenta -> asiento */
.acct-toggle{border:0;background:none;cursor:pointer;padding:0;width:14px;line-height:1;
  color:var(--steel);font-size:11px;flex:0 0 auto}
.acct-toggle:hover{color:var(--orange)}
.acct-toggle-spacer{display:inline-block;width:14px;flex:0 0 auto}
.acct-row-click{cursor:pointer}
.acct-row-click:hover{background:var(--warm-2)}
.acct-row-click.is-parent .acct-name{font-weight:800}
.acct-entry-link{cursor:pointer;color:var(--orange-600);font-weight:700}
.acct-entry-link:hover{text-decoration:underline}

/* Libro de una cuenta: buscador + paginación dentro del modal */
.ledger-tools{display:flex;align-items:center;gap:12px;margin:14px 0 10px}
.ledger-tools input{flex:1 1 auto;min-width:0}
.ledger-count{flex:0 0 auto;font-size:12px;color:var(--steel);white-space:nowrap}
.pager{display:flex;align-items:center;justify-content:center;gap:8px;margin-top:12px}
.pager-info{font-size:12.5px;color:var(--steel);min-width:130px;text-align:center}
.pager .btn[disabled]{opacity:.4;cursor:not-allowed}
/* Línea de asiento manual: el combobox de cuenta ocupa toda la celda */
.ml-acct{width:100%}

/* ---------- Barra de filtros de listados ----------
   REGLA: los filtros de cualquier listado se montan con esta estructura
   —.filters-card > .filters-grid (con .ctl-scope) y la escoba como último
   elemento— para que todos los listados se vean y se usen igual.

   Rejilla, no flex: con flex la última fila estira sus campos y dejan de
   medir lo mismo que los de arriba. Aquí todas las celdas son iguales y la
   escoba ocupa la siguiente, detrás del último filtro. */
.filters-card{padding:14px 16px}
.filters-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));
  gap:12px;align-items:end}
.filters-grid label{display:block;font-size:11.5px;font-weight:600;color:var(--steel);margin-bottom:5px}
/* Todos los controles de la barra con la misma altura. */
.filters-grid input,.filters-grid .msel-trigger,.filters-grid .mdate-trigger{height:40px}
/* La escoba se alinea con los campos, no con sus etiquetas. */
.filters-clear{align-self:end;justify-self:start;width:40px;height:40px;
  align-items:center;justify-content:center;border:1px solid transparent}
.filters-clear.has-filters{color:var(--orange);background:var(--warm-2);border-color:var(--rule)}

/* Etiquetas de factura. Sin color elegido, el gris de siempre; con él,
   el propio color como texto sobre un velo suyo — se reconoce de lejos
   sin gritar más que el resto de la fila (js/ui.js, 1.74). */
.tag-chip{display:inline-block;padding:2px 8px;margin:0 4px 2px 0;border-radius:999px;
  background:var(--warm-2);color:var(--steel);font-size:11px;font-weight:700;white-space:nowrap}
.tag-chip.tag-color{background:color-mix(in srgb, var(--tag) 14%, transparent);color:var(--tag)}
/* Elegir el color de una etiqueta: la lista de las que se usan. */
.tags-lista{display:flex;flex-direction:column;gap:4px;max-height:60vh;overflow:auto}
.tags-fila{display:flex;align-items:center;gap:12px;padding:8px 4px;border-bottom:1px solid #F1EDE6}
.tags-fila:last-child{border-bottom:none}
.tags-fila>.tag-chip{flex:none;font-size:12px;padding:3px 10px}

/* ---------- Pasos de un documento largo (js/views/invoices.js) ----------
   El formulario de factura pedía nueve cosas seguidas —cliente, almacén,
   pedido, etiquetas, tarifa, líneas, descuento, totales, notas— en una
   tira sin cortes. Nada estaba mal puesto; sencillamente no se veía
   dónde acababa una pregunta y empezaba otra.

   Ahora va por pasos, y el color **no decora: ordena**. Los tres
   primeros toman las tres paradas del degradado de la marca
   (lima -> ámbar -> naranja, el mismo de `--brand-grad-v`), así que el
   color dice en qué punto del proceso estás y avanza siempre en el
   mismo sentido. El cuarto —lo que se imprime en el papel— queda en
   gris a propósito: no forma parte del dinero, y darle un color de la
   rampa sería decir que sí.

   Esto respeta la regla de la casa (`docs/interfaz.md`: "el color sólo
   aparece cuando el valor significa algo"). Cuatro colores elegidos por
   gusto habrían sido decoración; éstos son una secuencia. El estado
   —rojo de sobrepasar stock, verde de cobrado— sigue siendo suyo y no
   compite, porque vive dentro de los campos, no en el borde. */
.doc-step{position:relative;margin:0 0 14px;padding:13px 14px;
  background:var(--lighter);border:1px solid var(--rule);
  border-left:3px solid var(--rule);border-radius:var(--radius-sm)}
/* El último campo de un bloque no arrastra su margen contra el borde. */
.doc-step > .form-row:last-child{margin-bottom:0}

/* Sin rótulo ni número: los campos ya dicen lo que son —Cliente,
   Almacén, Tarifa, Descuento—, y un título encima nombraba dos veces lo
   mismo. El bloque separa; el color ordena. */
.doc-step.s1{border-left-color:var(--lime)}
.doc-step.s2{border-left-color:var(--amber)}
.doc-step.s3{border-left-color:var(--orange)}
.doc-step.s4{border-left-color:var(--rule)}

/* El paso del dinero es el que se lee de un vistazo: fondo blanco para
   que los totales no compitan con el gris de los demás. */
.doc-step.s3{background:var(--surface)}
/* Y ahí dentro el resumen pierde su marco: dos recuadros concéntricos
   son un borde que no separa nada. Basta una raya y aire. */
.doc-step .doc-summary{border:0;border-top:1px solid var(--rule);border-radius:0;
  margin:12px 0 0;padding:10px 2px 0}

/* Pantalla de facturación: número, cabecera de líneas, resumen y notas */
.doc-number-preview{padding:8px 12px;margin-bottom:12px;border-radius:10px;background:var(--warm-2);
  color:var(--steel);font-size:13px}
.doc-number-preview strong{color:var(--ink);font-size:15px;margin-left:4px}
.doc-number-preview small{color:var(--muted)}
/* Espeja el flex de .li-row para que los rótulos caigan sobre su campo. */
.li-head{display:flex;gap:8px;padding:0 2px 4px;font-size:11.5px;color:var(--steel);font-weight:700}
.li-head span:first-child{flex:1;min-width:0}
.li-head span:not(:first-child){width:92px;flex:0 0 auto;text-align:right}
.li-head span:last-child{width:32px}
.doc-summary{margin:12px 0;padding:10px 12px;border:1px solid var(--rule);border-radius:12px}
.doc-summary .acc-row.total{border-top:1px solid var(--rule);margin-top:4px;padding-top:6px;font-size:15px}
.doc-notes{margin-top:12px;padding-top:8px;border-top:1px solid var(--rule)}
.doc-notes strong{display:block;font-size:12px;color:var(--steel);margin-bottom:2px}
.doc-notes p{margin:0;white-space:pre-line;font-size:13px}

/* Matriz de roles y permisos */
.perm-table th:not(:first-child),.perm-table td:not(:first-child){text-align:center}
.perm-group td{background:var(--warm-2);font-weight:700;font-size:11px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--steel);padding:7px 8px}
.perm-cell{text-align:center}
.perm-yes{color:var(--ok);font-weight:800}
.perm-no{color:var(--muted)}
.meta-line{display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--rule)}
.meta-line span{color:var(--muted);font-size:12.5px}
.meta-line strong{color:var(--navy);font-size:12.5px}
.doc-total{text-align:right;padding:10px 2px 2px;font-size:14px;color:var(--navy)}
.doc-total strong{font-size:16px}

/* Encabezados de sección y notas */
.sec-h{margin:22px 0 12px;font-size:13px;text-transform:uppercase;letter-spacing:.04em;color:var(--steel)}
.sec-h:first-child{margin-top:4px}
.note-small{color:var(--muted);font-size:12px;margin-top:16px;line-height:1.6}
.empty-cell{text-align:center;color:var(--muted);padding:26px}

/* Filtros píldora segmentados */
.pills{display:inline-flex;gap:6px;background:var(--warm-2);padding:4px;border-radius:16px;flex-wrap:wrap;
  position:relative}
.pill{padding:7px 14px;border-radius:12px;font-size:12.5px;font-weight:700;color:var(--steel);
  background:transparent;border:none;cursor:pointer;font-family:var(--font-body);transition:color .15s;
  position:relative;z-index:1}
.pill:hover{color:var(--ink)}
/* El fondo blanco de la activa ya no lo pinta ella: lo pinta el glider,
   que es uno solo y se desplaza (js/glider.js). Si el JS no llegara a
   cargar, esto sigue marcando cuál está activa por color. */
.pill.active{color:var(--orange-600)}
.pills:not(.con-glider) .pill.active{background:#fff;box-shadow:0 2px 6px rgba(80,60,40,.1)}

/* Iconos de acción rápida junto al menú de fila (⋯) */
td:has(.row-actions){text-align:right}
.row-actions{display:inline-flex;align-items:center;gap:2px}
.row-action-btn.tone-primary{color:var(--orange-600)}
.row-action-btn.tone-primary:hover{background:var(--orange-50,var(--warm-2));color:var(--orange-600)}
.row-action-btn.tone-ok{color:var(--ok)}
.row-action-btn.tone-ok:hover{background:var(--ok-bg);color:var(--ok)}
.row-action-btn.tone-danger{color:var(--danger)}
.row-action-btn.tone-danger:hover{background:var(--danger-bg);color:var(--danger)}

/* Menú de acciones por fila (⋯) */
td:has(.rowmenu){text-align:right}
.rowmenu{position:relative;display:inline-flex}
.rowmenu-btn{color:var(--steel)}
.rowmenu-btn:hover{color:var(--ink);background:var(--warm-2)}
.rowmenu-pop{position:fixed;z-index:70;background:#fff;border:1px solid var(--rule);border-radius:14px;
  box-shadow:var(--shadow-lg);padding:6px;min-width:160px;display:flex;flex-direction:column;gap:2px}
.rowmenu-item{text-align:left;background:none;border:none;cursor:pointer;font-family:var(--font-body);
  font-size:13px;font-weight:600;color:var(--text);padding:9px 12px;border-radius:10px;transition:background .12s,color .12s}
.rowmenu-item:hover{background:var(--warm-2)}
.rowmenu-item.primary{color:var(--orange-600)}
.rowmenu-item.danger{color:var(--danger)}

/* Stepper de estados de documento */
.stepper{display:flex;align-items:center;gap:0;margin:6px 0 14px;flex-wrap:wrap}
.step{display:flex;align-items:center;gap:8px}
.step-dot{width:24px;height:24px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:800;background:var(--warm-2);color:var(--muted)}
.step-lbl{font-size:12.5px;font-weight:600;color:var(--muted)}
.step.done .step-dot{background:var(--ok-bg);color:var(--ok)}
.step.done .step-lbl{color:var(--ink)}
.step.current .step-dot{background:var(--orange);color:#fff;box-shadow:0 3px 9px rgba(241,106,48,.35)}
.step.current .step-lbl{color:var(--orange-600);font-weight:700}
.step-line{flex:1;min-width:22px;height:2px;background:var(--rule);margin:0 8px;border-radius:2px}
.step-line.on{background:var(--ok)}
.step-note{font-size:12px;color:var(--danger);font-weight:600;margin-bottom:10px}

/* Resumen contable (filas clave/valor) */
.acc-row{display:flex;justify-content:space-between;padding:9px 0;border-bottom:1px solid var(--rule)}
.acc-row span{color:var(--muted)}
.acc-row strong{color:var(--navy)}
.acc-row:last-child{border-bottom:none}

/* ---------- Panel de contabilidad configurable ----------
   La barra con "Personalizar" va arriba a la derecha, fuera del flujo
   de datos: es una acción sobre la pantalla, no una cifra más. */
.panel-bar{display:flex;justify-content:flex-end;margin-bottom:6px}
.panel-widget{margin-top:16px}
.panel-widget .note-small{margin-bottom:12px}
/* Dos tablas del mismo peso (por cobrar / por pagar). .grid-2 reparte
   1.4fr/1fr, que aquí daría a entender que una importa más. */
.panel-split{display:grid;grid-template-columns:1fr 1fr;gap:20px}
@media(max-width:920px){.panel-split{grid-template-columns:1fr}}
.panel-opts{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:4px 16px}
.panel-opts label.check{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:500;
  color:var(--ink);padding:6px 8px;border-radius:10px;cursor:pointer}
.panel-opts label.check:hover{background:var(--warm-2)}
.panel-opts label.check input{width:auto;margin:0;accent-color:var(--orange)}

/* Leyenda de series de un gráfico */
.chart-legend{display:flex;gap:16px;margin-bottom:8px;font-size:12px;color:var(--steel);font-weight:600}
.chart-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:6px}

/* Fila de totales de una tabla de datos */
.data tr.total td{font-weight:800;color:var(--ink);border-top:1px solid var(--rule)}

/* Contador de cada pestaña de tipo (Productos 12 / Servicios 3) */
/* El almacén con su color (js/ui.js). El color es el **canto** del
   nombre —un `inset` que se redondea con él y va pegado al texto—, no
   una barra suelta al lado: eso se leía como una viñeta más. Y un velo
   del mismo color de fondo, apenas un 8%, que ata las dos cosas. */
.wh{display:inline-flex;align-items:center;min-width:0;padding:2px 8px 2px 7px;
  border-left:3px solid var(--wh, var(--muted));
  /* Recto por donde toca el color y redondeado por el otro lado: se lee
     como el canto de una ficha, no como una barra puesta al lado. */
  border-radius:0 6px 6px 0;
  background:color-mix(in srgb, var(--wh, transparent) 9%, transparent)}
.wh>span{min-width:0;overflow-wrap:anywhere}
.wh-solo{width:14px;height:18px;padding:0}
/* En las píldoras, el canto es el del propio botón. */
.pill.wh-pill{padding-left:12px;border-left:3px solid var(--wh, var(--muted));border-radius:0 12px 12px 0}
.pill-count{display:inline-block;margin-left:5px;padding:0 6px;border-radius:9px;
  background:rgba(0,0,0,.06);font-size:11px;font-weight:700}
.pill.active .pill-count{background:var(--warm-2);color:var(--orange-600)}

/* ---------- Avisos (campana de la barra superior) ----------
   El panel cuelga de <body> con MO.floatPop: la barra es sticky y
   recortaría la lista dentro de ella. */
/* La campana es un icono más aunque no lleve la clase: mismo gesto y
   mismas curvas que el resto (ver el bloque de `.icon-btn`). */
.notif-btn{position:relative;background:rgba(255,255,255,.14);border:none;color:#fff;cursor:pointer;
  width:36px;height:36px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--ease)}
.notif-btn svg{transition:transform var(--ease-pop)}
.notif-btn:hover{background:rgba(255,255,255,.26)}
.notif-btn:hover svg{transform:scale(1.12)}
.notif-btn:active svg{transform:scale(.92);transition:transform var(--ease-tap)}
.notif-btn:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(241,106,48,.5)}
@media (prefers-reduced-motion: reduce){
  .notif-btn svg,.notif-btn:hover svg,.notif-btn:active svg{transform:none;transition:none}
}
.notif-count{position:absolute;top:-3px;right:-3px;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--orange);color:#fff;font-size:10.5px;font-weight:800;line-height:18px;
  box-shadow:0 0 0 2px var(--ink)}
.notif-pop{position:fixed;z-index:60;width:360px;max-width:calc(100vw - 16px);background:#fff;
  border:1px solid var(--rule);border-radius:16px;box-shadow:var(--shadow-lg);overflow:hidden}
.notif-head{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:12px 14px;border-bottom:1px solid var(--rule);color:var(--ink)}
.notif-list{max-height:min(60vh,440px);overflow:auto}
.notif-empty{padding:26px 18px;color:var(--muted);font-size:12.5px;text-align:center;line-height:1.6}
.notif-acciones{display:flex;gap:6px}
/* El nivel se ve en una banda a la izquierda, no sólo en el punto. Un
   círculo de 9 px hay que ir a buscarlo; con la lista llena lo que se
   quiere es separar de un vistazo lo urgente de lo que sólo informa.
   Es la misma banda que ordena los bloques de la factura.

   La banda y el fondo dicen cosas distintas y por eso no se pisan: la
   banda dice QUÉ es el aviso, el fondo dice si ya lo viste. Mezclarlos
   —tintar el fondo según el nivel— dejaría sin señal a lo no leído.

   El relleno de `.notif-main` baja de 14 a 11 para que el texto siga
   empezando donde empezaba: la banda ocupa los 3 que faltan. */
.notif-item{display:flex;align-items:flex-start;border-bottom:1px solid var(--rule);
  border-left:3px solid var(--info)}
.notif-item.tone-warn{border-left-color:var(--amber)}
.notif-item.tone-danger{border-left-color:var(--danger)}
.notif-item:last-child{border-bottom:none}
.notif-item:hover{background:var(--warm-2)}
.notif-main{display:flex;gap:10px;flex:1;min-width:0;text-align:left;background:none;border:none;
  cursor:pointer;padding:11px 4px 11px 11px;font-family:var(--font-body)}
/* El aspa está siempre visible, no sólo al pasar el ratón: en un móvil
   no hay ratón y un botón que sólo aparece al pasar por encima no
   existe. Discreta, y se enciende al tocarla. */
.notif-del{flex:none;background:none;border:none;cursor:pointer;color:var(--muted);
  padding:12px 12px 12px 6px;display:inline-flex;border-radius:10px;transition:color .15s,background .15s}
.notif-del:hover{color:var(--danger);background:var(--danger-bg)}
/* El no leído se marca con fondo, no sólo con negrita: con quince
   avisos seguidos la negrita sola no se distingue de un vistazo. */
.notif-item.unread{background:var(--lighter)}
.notif-item.unread .notif-title{font-weight:800;color:var(--ink)}
.notif-empty + .notif-head,.notif-head + .notif-empty{border-top:none}
.notif-dot{flex:none;width:9px;height:9px;border-radius:50%;margin-top:5px;background:var(--info)}
.notif-dot.tone-warn{background:var(--amber)}
.notif-dot.tone-danger{background:var(--danger)}
.notif-text{display:flex;flex-direction:column;gap:2px;min-width:0}
.notif-title{font-size:13px;font-weight:600;color:var(--ink)}
.notif-body{font-size:12px;color:var(--steel);line-height:1.45}
.notif-when{font-size:11px;color:var(--muted);margin-top:2px}

/* ---------- Accesos de una persona (Usuarios → Accesos) ----------
   Dos columnas de grupos: veintitrés pantallas en una tira obligarían a
   bajar para ver si falta algo, y lo que se viene a hacer aquí es
   comparar de un vistazo. Cada línea dice de dónde viene lo que se ve
   —por su rol, añadido, quitado—: sin eso, quien abra esto dentro de
   seis meses no sabe si algo está marcado porque alguien lo decidió o
   porque el rol lo trae. */
.acc-acciones{display:flex;justify-content:flex-end;margin:0 0 10px}
.acc-cuerpo{columns:2;column-gap:22px}
.acc-grupo{break-inside:avoid;margin:0 0 14px}
.acc-grupo h5{margin:0 0 6px;font-size:11px;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;color:var(--steel);border-bottom:1px solid var(--rule);padding-bottom:4px}
.acc-linea{display:flex;align-items:center;gap:8px;margin:0;padding:5px 4px;
  border-radius:var(--radius-xs);font-weight:400;cursor:pointer;
  transition:background var(--ease)}
.acc-linea:hover{background:var(--warm-2)}
.acc-nombre{flex:1;font-size:13px;color:var(--ink)}
/* El origen a la derecha y en su sitio fijo: alineado, la columna se lee
   sola y se ve de un golpe qué se ha tocado en esta persona. */
.acc-origen{flex:none;min-width:74px;text-align:right}
.acc-origen .badge{font-size:10px;padding:2px 6px}
@media (max-width:720px){.acc-cuerpo{columns:1}}

/* ---------- Editor de líneas de un módulo ---------- */
.mi-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:10px}
.mi-total{font-size:13px;font-weight:800;color:var(--ink)}

/* ---------- Factura Módulo: QR de entrega y cajas ---------- */
.mod-delivery{display:flex;gap:16px;align-items:flex-start;background:var(--lighter);
  border:1px solid var(--rule);border-radius:16px;padding:14px}
.mod-qr svg{display:block;border-radius:8px}
.mod-delivery-text{min-width:0}
.mod-delivery-text p{margin:0 0 6px}
/* La url completa se enseña por si el QR no se puede escanear (pantalla
   rota, cámara mala): se copia a mano y funciona igual. */
.mod-url{word-break:break-all;color:var(--muted);font-size:11px}
/* Imprimir las etiquetas de un tramo de cajas. Va encima de la tabla y
   fuera de ella: dentro, sus campos dejarían a la tabla sin buscador ni
   páginas (ver js/tabletools.js). */
.et-tramo{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 10px;
  font-size:12.5px;color:var(--steel)}
.et-tramo input{width:84px;padding:6px 8px}

/* ---------- Acuse de entrega (pantalla pública) ---------- */
.dlv-lead{color:var(--steel);font-size:13.5px;margin:0 0 14px}
.dlv-mods{border:1px solid var(--rule);border-radius:14px;overflow:hidden;margin-bottom:16px}
.dlv-mods-head{background:var(--warm-2);padding:8px 12px;font-size:12px;font-weight:800;color:var(--ink)}
.dlv-mod{display:flex;align-items:center;gap:10px;padding:8px 12px;border-top:1px solid var(--rule);font-size:13px}
.dlv-mod span{color:var(--steel)}
.dlv-form label{display:block;font-size:12.5px;font-weight:600;color:var(--steel);margin-bottom:14px}
.dlv-form input{width:100%;margin-top:6px;padding:12px 14px;border:1px solid var(--rule);border-radius:14px;
  font-size:14px;color:var(--text);font-family:var(--font-body);background:#fff}
.dlv-form input:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 4px rgba(241,106,48,.14)}
.dlv-note{margin:16px 0 0;font-size:11.5px;color:var(--muted);text-align:center;line-height:1.6}
.dlv-ok{text-align:center;padding:10px 0}
.dlv-ok svg{color:var(--ok)}
.dlv-ok h3{margin:10px 0 8px;font-size:19px}
.dlv-ok p{margin:0 0 4px;color:var(--steel);font-size:13.5px}
.dlv-when{color:var(--muted) !important;font-size:12px !important;margin-top:8px !important}

/* ---------- Explicaciones ("?") ----------
   Discreto al lado de la etiqueta: quien ya sabe lo que es el campo ni
   lo ve, y quien no, lo tiene a un clic. Nunca un párrafo suelto. */
.hint{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;
  width:16px;height:16px;padding:0;margin-left:5px;border-radius:50%;
  border:1px solid var(--rule);background:var(--warm-2);color:var(--steel);
  font-family:var(--font-body);font-size:10.5px;font-weight:800;line-height:1;cursor:pointer;
  transition:background .15s,color .15s,border-color .15s}
.hint:hover{background:var(--orange);border-color:var(--orange);color:#fff}
.hint:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(241,106,48,.28)}
.hint-pop{position:fixed;z-index:70;max-width:300px;background:var(--ink);color:#f4f2ee;
  padding:10px 12px;border-radius:12px;font-size:12px;line-height:1.5;
  box-shadow:0 10px 30px rgba(60,40,20,.28)}
/* En un título de modal el "?" va un punto más grande, para que no
   quede diminuto al lado de una tipografía de 16px. */
.modal-head .hint{width:18px;height:18px;font-size:11px;margin-left:8px}

.perm-table .perm-cell input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--orange);cursor:pointer}

/* ---------- Avisos por correo: persona a la izquierda, sus avisos a
   la derecha ----------
   Antes era una matriz usuario × tipo. Una matriz crece a lo ancho, y
   a lo ancho la pantalla se acaba: con nueve tipos ya había que hacer
   scroll horizontal, y cada tipo nuevo empeoraba el problema para
   siempre. Aquí las dos listas crecen hacia abajo, que es donde hay
   sitio, y los tipos van agrupados por asunto. */
.subs-layout{display:grid;grid-template-columns:264px 1fr;
  border:1px solid var(--rule);border-radius:14px;overflow:hidden;background:var(--surface)}
.subs-users{border-right:1px solid var(--rule);background:var(--lighter);
  max-height:560px;overflow:auto}
.subs-search{padding:10px;border-bottom:1px solid var(--rule)}
.subs-user{display:flex;align-items:center;gap:10px;width:100%;padding:10px 12px;
  background:none;border:none;border-bottom:1px solid var(--rule);cursor:pointer;text-align:left;
  font-family:var(--font-body);color:var(--ink)}
.subs-user:hover{background:var(--warm-2)}
.subs-user.is-sel{background:var(--surface);box-shadow:inset 3px 0 0 var(--orange)}
.subs-user .su-name{flex:1;min-width:0;font-size:13px;font-weight:700;line-height:1.3}
.subs-user .su-name small{display:block;font-weight:500;color:var(--muted);font-size:11px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.su-count{flex:none;min-width:22px;height:22px;padding:0 6px;border-radius:11px;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:11px;font-weight:800;background:var(--orange);color:#fff}
.su-count.is-zero{background:transparent;color:var(--muted);font-weight:600}
.subs-empty{padding:14px;color:var(--muted);font-size:13px}

.subs-detail{padding:14px 16px;max-height:560px;overflow:auto}
.subs-detail-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding-bottom:12px;border-bottom:1px solid var(--rule);margin-bottom:6px}
.subs-detail-head strong{display:block;font-size:14px}
.subs-detail-head small{color:var(--muted);font-size:12px}
.subs-group{padding:12px 0;border-bottom:1px solid var(--rule)}
.subs-group:last-child{border-bottom:none;padding-bottom:0}
.sg-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:6px}
.sg-head span{font-size:11px;font-weight:800;color:var(--steel);
  text-transform:uppercase;letter-spacing:.03em}
.lnk{background:none;border:none;padding:2px 6px;border-radius:8px;cursor:pointer;
  font-family:var(--font-body);font-size:11px;font-weight:700;color:var(--orange-600)}
.lnk:hover{background:var(--warm-2)}
.subs-topic{display:flex;align-items:center;gap:10px;border-radius:10px;padding:2px 6px}
.subs-topic:hover{background:var(--lighter)}
.subs-topic:hover .st-all{opacity:1}
.st-main{display:flex;align-items:center;gap:10px;flex:1;min-width:0;cursor:pointer;padding:6px 0;font-size:13px}
.st-main input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--orange);cursor:pointer;flex:none}
.st-main small{color:var(--muted);font-size:12px}
/* Se ve siempre, apagado: un botón que sólo aparece al pasar por
   encima no lo encuentra quien no sabe que está. */
.st-all{opacity:.5;flex:none;background:none;border:none;padding:3px 8px;border-radius:8px;cursor:pointer;
  font-family:var(--font-body);font-size:11px;font-weight:700;color:var(--steel)}
.st-all:hover,.st-all:focus-visible{opacity:1;background:var(--warm-2);color:var(--orange-600)}
@media (max-width:820px){
  .subs-layout{grid-template-columns:1fr}
  .subs-users{border-right:none;border-bottom:1px solid var(--rule);max-height:240px}
}

/* ---------- Vencimiento de un lote ----------
   La fecha y su etiqueta van una encima de otra. En la misma línea la
   etiqueta se leía como parte de la fecha ("12/08/2026 Vence ya"), y con
   varias filas seguidas la columna era una tira de texto sin forma. */
.exp-cell{display:inline-flex;flex-direction:column;align-items:flex-start;gap:5px;line-height:1.25}
.exp-cell .exp-date{font-variant-numeric:tabular-nums;white-space:nowrap}
.exp-cell .badge{font-size:10.5px;padding:2px 9px}
.data.mini .exp-cell{gap:4px}
/* La celda de vencimiento se pincha para corregirla. No se disfraza de
   botón —cien filas serían cien botones, y el ruido taparía lo que hay
   que mirar— pero tampoco se esconde: la fecha va subrayada de puntos y
   al señalarla se levanta el fondo. El margen negativo compensa el
   relleno, para que la fila no crezca por llevar un control dentro. */
.exp-edit{display:inline-block;text-align:left;padding:3px 7px;margin:-3px -7px;
  border:0;border-radius:9px;background:none;font:inherit;color:inherit;cursor:pointer;
  transition:background-color var(--ease)}
.exp-edit .exp-date{border-bottom:1px dotted var(--rule)}
.exp-edit:is(:hover,:focus-visible){background-color:var(--warm-2)}
.exp-edit:is(:hover,:focus-visible) .exp-date{border-bottom-color:var(--steel)}

/* Inventario en pestañas: cada panel manda en su espacio. */
.inv-pane{margin-top:4px}

/* ---------- Manual de uso ----------
   Una ficha por cuaderno: a la izquierda qué es, a la derecha cuánto
   pesa y qué hacer con él. En el móvil se apila, porque dos columnas
   de 40 mm no son dos columnas. */
.man-ficha{display:flex;align-items:center;gap:16px;margin-bottom:10px}
.man-ficha .man-txt{flex:1;min-width:0}
.man-ficha .man-lado{display:flex;align-items:center;gap:14px;flex:none}
/* El de tu puesto se distingue sin gritar: la franja de marca a la
   izquierda, que es el mismo recurso que usa el resto de la app para
   decir "esto es lo tuyo". */
.man-ficha.man-mio{border-left:3px solid var(--orange)}
@media (max-width:720px){
  .man-ficha{flex-direction:column;align-items:stretch}
  .man-ficha .man-lado{justify-content:space-between}
}
/* El detalle de un documento con seis datos de cabecera: en dos
   columnas, que en una tira se leía como una lista de la compra. */
.meta-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 24px;margin-bottom:12px}
@media(max-width:640px){.meta-grid{grid-template-columns:1fr}}

/* Selector de etiquetas (js/tagsinput.js). Las fichas puestas y el
   campo viven en la misma caja, que se ve como cualquier otro campo del
   formulario: el `datalist` del navegador se veía como lo que era, un
   panel del sistema en medio de la app. */
.tags-input{display:flex;flex-wrap:wrap;align-items:center;gap:6px;width:100%;
  padding:7px 10px;border:1px solid var(--rule);border-radius:13px;background:#fff;
  transition:border-color .15s,box-shadow .15s}
.tags-input:focus-within{border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.13)}
.tags-puestas{display:contents}
.tags-input .tag-chip{margin:0;display:inline-flex;align-items:center;gap:4px;font-size:11.5px}
.tag-x{border:none;background:none;padding:0 0 0 2px;cursor:pointer;color:inherit;
  font-size:13px;line-height:1;opacity:.6}
.tag-x:hover{opacity:1}
.tags-campo{flex:1;min-width:120px;border:none;outline:none;background:none;
  font-family:var(--font-body);font-size:13.5px;color:var(--ink);padding:2px 0}
/* Las sugerencias son las del panel de siempre, con su ficha dentro. */
.combo-opt .tag-chip{margin:0}

/* Selector de color (js/color.js). El botón enseña el color puesto; la
   paleta entera vive en el panel flotante de siempre. */
.color-btn{width:38px;height:26px;border-radius:8px;border:1px solid var(--rule);cursor:pointer;
  padding:0 8px;font:inherit;font-size:11px;font-weight:700;color:var(--steel);
  box-shadow:0 0 0 1px rgba(80,60,40,.10) inset;transition:transform .12s}
.color-btn:hover{transform:translateY(-1px)}
.color-btn.color-vacio{width:auto;min-width:38px;background:var(--warm-2)}
.color-pop{padding:10px;width:max-content}
.color-rejilla{display:grid;grid-template-columns:repeat(12,18px);gap:3px}
.color-cuadro{width:18px;height:18px;border-radius:4px;border:2px solid transparent;cursor:pointer;padding:0;
  box-shadow:0 0 0 1px rgba(80,60,40,.12) inset}
.color-cuadro:hover{transform:scale(1.15)}
.color-cuadro.on{border-color:var(--ink);box-shadow:0 0 0 2px #fff inset}
.color-quitar{display:block;width:100%;margin-bottom:8px;padding:6px 10px;border:1px solid var(--rule);
  border-radius:9px;background:#fff;cursor:pointer;font:inherit;font-size:12px;font-weight:700;color:var(--steel)}
.color-quitar:hover{background:var(--warm-2);color:var(--ink)}
.color-hex{display:flex;align-items:center;gap:8px;margin-top:10px;padding-top:9px;border-top:1px solid var(--rule)}
.color-hex label{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.02em}
.color-hex-campo{flex:1;min-width:0;padding:6px 9px;border:1px solid var(--rule);border-radius:9px;
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.5px;color:var(--ink);background:#fff}
.color-hex-campo:focus{outline:none;border-color:var(--orange);box-shadow:0 0 0 3px rgba(241,106,48,.13)}
