:root{
  color-scheme:light;
  /* Paleta de Shaker DCN Nutrition (la misma del sitio de pedidos): papel
     crema, tinta casi negra y verde lima como acento de marca. Los NOMBRES de
     los tokens (--brown, --yellow, --orange...) vienen del sistema base y se
     conservan para no tocar cientos de reglas: --brown* = la tinta, --yellow*
     = el lima, --orange = el coral (avisos y cifras destacadas). */
  --brown:#3A342A;
  --brown-deep:#1E1A14;
  --brown-soft:#6B6252;
  --cream:#F3ECDA;
  --cream-2:#F1E7D2;
  --paper:#FBF6EC;
  --yellow:#C6FF3F;
  --yellow-deep:#A6E016;
  --lime-ink:#253000;
  --orange:#F04E23;
  --line:#E7DBC0;
  --line-strong:#D6C8AA;
  --bw:1px;
  --r:10px;
  --r-lg:14px;
  --shadow:0 1px 2px color-mix(in srgb,var(--brown-deep) 6%,transparent), 0 4px 14px color-mix(in srgb,var(--brown-deep) 7%,transparent);
  --shadow-sm:0 1px 2px color-mix(in srgb,var(--brown-deep) 5%,transparent);
  /* Semánticos: mismo significado en cualquier pantalla que los use, en vez
     de que cada una invente su propio rojo/ámbar/verde por separado (varios
     ya existían sueltos — ej. #b3261e en .low-stock-tag — esto les pone
     nombre para reusar, sin tocar lo que ya funciona). */
  --sage:#2F7A4B; --sage-bg:#E4F2E8;
  --amber:#8A6100; --amber-bg:#FBF1DC;
  --danger:#B3261E; --danger-bg:#FBEAE7; --danger-bg-hover:#f7dedd;
  /* Mismo rojo que --danger en modo claro (ya se lee bien ahí) — existe
     aparte porque --danger TAMBIÉN se usa como fondo SÓLIDO con texto
     blanco encima (.low-stock-tag, .offline-banner.is-offline), y ESE uso
     necesita quedarse bien saturado en modo oscuro (aclararlo ahí rompería
     el contraste con el blanco). Este token es solo para texto/borde SOBRE
     --danger-bg (ej. .panel-alert-strip.is-urgent) — el mismo caso que
     --amber/--amber-bg y --sage/--sage-bg ya resolvían, que a --danger se
     le había quedado sin resolver. */
  --danger-on-bg:var(--danger);

  /* Superficie/tinta: la marca (--brown, --cream, --yellow, --orange) NUNCA
     cambia entre modo claro/oscuro — es la identidad de la marca. Lo que sí
     cambia es DÓNDE se para el contenido (--bg/--surface/--surface-2) y de
     qué color es el texto sobre esas superficies (--ink/--ink-soft). El
     sidebar/toast/barra móvil del carrito siguen usando --brown-deep/--cream
     directo a propósito: ya son oscuros de por sí, no tienen "modo" que
     cambiar (mismo criterio que la propuesta de rediseño: "los mismos
     colores de marca, solo los roles de fondo/texto invertidos"). */
  --bg:var(--paper);
  --surface:#fff;
  --surface-2:var(--cream-2);
  --ink:var(--brown-deep);
  --ink-soft:var(--brown-soft);
}
/* Segunda revisión de la escala de superficie (la primera, con saltos de
   5-6% de luminosidad, seguía sin convencer al dueño: "no me gusta, no se
   distingue"). La causa real no era solo la luminosidad — --bg/--surface/
   --surface-2/--amber-bg eran todos, además de oscuros, la MISMA familia
   de color (café/ámbar), así que hasta con distinta luminosidad el ojo los
   lee como "variaciones del mismo café". Dos cambios de fondo, no solo
   subir números:
   1) --line (el borde de .card/.stat) pasa a un café bien más claro y
      visible en vez de apenas un tono más — un borde nítido separa una
      tarjeta de su fondo aunque los rellenos se parezcan, que es la señal
      más confiable en un diseño oscuro (no depender solo de --shadow, que
      ya se sabía que no se nota sobre fondo oscuro).
   2) --amber-bg deja de ser "un café más" y se corre a un tono
      genuinamente más dorado/amarillo (no solo más claro) para que un
      aviso realmente se distinga de una tarjeta normal por color, no solo
      por brillo — y --amber (el texto/borde sobre ese fondo) se redefine
      acá por primera vez: el dorado oscuro de marca (#9A6B12, pensado
      para fondo CLARO) se leía apagado sobre su propio --amber-bg oscuro. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#131109; --surface:#1E1A14; --surface-2:#2C271E;
  --ink:#F3ECDA; --ink-soft:#BDB29D; --line:#4A4335; --line-strong:#6B6252;
  --sage:#7FD9A0; --sage-bg:#1C3324; --amber:#EBC270; --amber-bg:#4A3A12;
  --danger-bg:#3A1D1A; --danger-bg-hover:#4A2420; --danger-on-bg:#F1958E;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.35);
  --shadow-sm:0 1px 3px rgba(0,0,0,.35);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --bg:#131109; --surface:#1E1A14; --surface-2:#2C271E;
    --ink:#F3ECDA; --ink-soft:#BDB29D; --line:#4A4335; --line-strong:#6B6252;
    --sage:#7FD9A0; --sage-bg:#1C3324; --amber:#EBC270; --amber-bg:#4A3A12;
    --danger-bg:#3A1D1A; --danger-bg-hover:#4A2420; --danger-on-bg:#F1958E;
    --shadow:0 1px 2px rgba(0,0,0,.4), 0 4px 16px rgba(0,0,0,.35);
    --shadow-sm:0 1px 3px rgba(0,0,0,.35);
  }
}

/* El carrito SIEMPRE en modo claro, sin importar el sistema operativo del
   celular ni el tema elegido en Configuración — pedido explícito del dueño:
   un vendedor usa el carrito de día, al aire libre (donde un fondo oscuro
   cuesta más de leer con luz de sol, justo lo contrario de para qué sirve
   el modo oscuro), y no tiene forma de cambiarlo él mismo porque el switch
   de Apariencia vive en Configuración, que es solo del administrativo.
   Redefinido en `body:has(...)` (no directo en #cart-app) porque `body`
   toma su propio fondo de --bg ANTES de heredar nada de sus hijos — un
   `#cart-app{--bg:...}` no le llega a `body`, que es su ancestro, no su
   descendiente (mismo patrón ya usado más abajo para .toast-host). */
body:has(#cart-app:not([hidden])),body:has(#almacen-app:not([hidden])){
  color-scheme:light;
  --bg:#FBF6EC; --surface:#fff; --surface-2:#F1E7D2;
  --ink:#1E1A14; --ink-soft:#6B6252; --line:#E7DBC0; --line-strong:#D6C8AA;
  --sage-bg:#E4F2E8; --amber-bg:#FBF1DC; --danger-bg:#FBEAE7; --danger-bg-hover:#f7dedd;
}

[hidden]{display:none !important}
*,*::before,*::after{box-sizing:border-box}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:"Manrope",system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:16px;
  line-height:1.5;
  /* Esto se usa como app, no como página — un doble toque en un botón +/-
     de cantidad, en una fila de la tabla o en cualquier control no debería
     acercar la pantalla (Safari/Chrome móvil lo hacen por defecto en CUALQUIER
     doble toque, sea o no sobre texto). "manipulation" apaga ese gesto sin
     tocar el pellizco para acercar (pinch-zoom) — a diferencia de
     user-scalable=no en el viewport, no le quita a nadie la forma de agrandar
     el texto si de verdad lo necesita. */
  touch-action:manipulation;
}
h1{font-family:"Sora","Manrope",system-ui,sans-serif;font-weight:600;margin:0 0 .6em;color:var(--ink);font-size:1.5rem}
h2{font-family:"Manrope",system-ui,sans-serif;font-weight:700;margin:0 0 .6em;color:var(--ink);font-size:1rem}
h3{font-family:"Manrope",system-ui,sans-serif;font-weight:700;margin:0 0 .5em;color:var(--ink-soft);font-size:.9rem}
/* 1100px se sentía angosto en un monitor de escritorio normal (1400px+) —
   quedaba con un tercio de la pantalla vacío a la derecha, mientras las
   grillas de tarjetas (Insumos, Productos) tenían lugar de sobra para una
   columna más. Subido a 1320px: la mayoría de las pantallas siguen siendo
   grillas/formularios cortos (no texto largo de leer), así que más ancho
   es más contenido útil a la vista, no líneas incómodas de seguir. */
.wrap{width:min(100% - 32px, 1320px);margin-inline:auto;padding-block:24px}
.muted{color:var(--ink-soft);font-size:.9em}

/* ── Estructura de app: sidebar fijo + contenido ── */
.app-shell{display:flex;min-height:100vh;align-items:stretch}
.sidebar{
  width:230px;flex:0 0 230px;background:var(--brown-deep);color:var(--cream);
  display:flex;flex-direction:column;padding:18px 14px;position:sticky;top:0;
  height:100vh;overflow-y:auto;
}
.sidebar-brand{font-family:"Sora",sans-serif;font-weight:600;font-size:1.15rem;padding:6px 10px 18px;display:flex;align-items:center;flex-wrap:wrap;gap:8px}
.sidebar-brand span{display:block;color:var(--yellow);font-weight:400;font-size:.8rem;margin-top:2px;width:100%}
/* El nombre del negocio (editable en Configuración) no hereda el estilo de
   "· Dueño"/"· Carrito" de al lado — mismo tamaño y peso que el resto de la
   marca, sin el salto de línea que sí necesita el sufijo. */
.sidebar-brand .brand-name{display:inline;color:inherit;font-weight:inherit;font-size:inherit;margin-top:0;width:auto}
/* El logo cargado en Configuración se veía chico (28-32px) apretado junto
   al nombre — pedido explícito del dueño, probado dos veces en vivo con su
   logo real (uno ancho tipo "letrero", no cuadrado — object-fit:contain
   lo deja con aire arriba/abajo dentro de su caja, así que la caja tiene
   que ser bien grande para que el logo en sí se note). En el sidebar sube
   a 46px. (Ya NO aparece en el login — sexta vuelta, ver .login-arche-brand
   más abajo; su protagonismo ahora es 100% del sidebar, ver .brand-plate.) */
.brand-logo{height:46px;width:46px;object-fit:contain;border-radius:8px;vertical-align:middle}
.sidebar-nav{display:flex;flex-direction:column;gap:3px;flex:1}
.nav-item{
  background:transparent;border:none;color:var(--cream);text-align:left;
  font:inherit;font-weight:700;padding:10px 12px;border-radius:9px;cursor:pointer;
  display:flex;align-items:center;gap:10px;
  transition:background-color .15s ease,color .15s ease;
}
.nav-item:hover{background:rgba(255,255,255,.08)}
.nav-item.active{background:var(--yellow);color:var(--brown-deep)}
.nav-icon{width:17px;height:17px;flex:0 0 auto;opacity:.85}
.nav-item.active .nav-icon{opacity:1}
.nav-label{flex:1;min-width:0}
/* Cuántas solicitudes de reposición esperan — antes había que ENTRAR a la
   sección para saber si hacía falta atender algo. --danger de marca fija
   (no --danger-bg/--danger de los tokens de superficie, que cambian con el
   tema) porque este pill va sobre el sidebar oscuro, que no cambia nunca. */
.nav-badge{
  position:relative;
  flex:0 0 auto;background:#E5484D;color:#fff;font-size:.72rem;font-weight:700;
  min-width:1.4em;height:1.4em;padding:0 5px;border-radius:999px;
  display:inline-flex;align-items:center;justify-content:center;
  font-variant-numeric:tabular-nums;
  animation:badge-pulse 1.8s ease-in-out infinite;
}
/* Pedido del dueño: la primera versión (solo el número achicándose/
   agrandándose) "no se ve tanto con el fondo" del sidebar oscuro — pidió
   algo que "se vaya agrandando y llenando todo el espacio". Un aro que
   nace del tamaño del badge y crece hacia afuera desvaneciéndose (mismo
   efecto "sonar" que una notificación de mensajería) se nota mucho más
   contra un fondo oscuro que solo escalar el número — y si literalmente
   agrandara el badge en sí, empujaría el texto del menú al lado.
   ::before va DETRÁS del número (z-index) para no taparlo. */
.nav-badge::before{
  content:'';
  position:absolute; inset:0; border-radius:inherit;
  background:#E5484D;
  animation:badge-ring 1.8s cubic-bezier(.2,.6,.35,1) infinite;
  z-index:-1;
}
@keyframes badge-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.18)}}
@keyframes badge-ring{
  0%{transform:scale(1);opacity:.65}
  100%{transform:scale(2.6);opacity:0}
}
@media (prefers-reduced-motion:reduce){.nav-badge,.nav-badge::before{animation:none}}
.nav-group{display:flex;flex-direction:column;gap:3px}
.nav-group + .nav-group{margin-top:14px}
.nav-group-label{
  font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:color-mix(in srgb,var(--cream) 55%,transparent);padding:0 12px;margin:0 0 2px;
  /* Es un <button> (se pliega en el menú del teléfono, ver @media 820px) pero en
     escritorio se ve y se comporta exactamente como la etiqueta de texto que era
     antes — sin fondo/borde nativos de botón, sin cursor de "esto hace algo": ahí
     no se pliega nada, así que no debe parecer interactivo. */
  display:block;width:100%;background:none;border:none;font-family:inherit;text-align:left;
  cursor:default;
}
.nav-group-chevron{display:none}
.sidebar-footer{display:flex;flex-direction:column;gap:8px;padding-top:14px;border-top:1px solid rgba(255,255,255,.15)}
.sidebar-footer .btn{color:var(--cream);border-color:rgba(255,255,255,.3);background:transparent}
.sidebar-footer .btn:hover{background:rgba(255,255,255,.08)}
/* Pie "derechos reservados" — sutil a propósito, no debe competir con Ayuda/
   Salir. En el sidebar (fondo oscuro) va en crema apagado; dentro de
   .login-box (tarjeta clara) se redefine más abajo. */
.sidebar-copyright{margin:2px 0 0;font-size:.68rem;line-height:1.3;text-align:center;color:color-mix(in srgb,var(--cream) 55%,transparent)}
.login-box .sidebar-copyright{color:var(--ink-soft);margin-top:18px}
/* ═══ Login v3.0 (ANALISIS-LOGIN-V3.md) ═══
   Pantalla completa en dos lados: a la izquierda ARCHE (negro y blanco
   fijos, no dependen del tema ni de los colores del negocio); a la derecha
   el NEGOCIO, con su paleta. Solo #login-screen usa esto — bloqueo,
   turno y asistente siguen con .login-box (se ven muchas veces al día).
   Todas las animaciones se apagan con prefers-reduced-motion. */
#login-screen{padding:0}
.login-split{
  position:relative;isolation:isolate;width:100%;height:100vh;overflow:hidden;
  display:flex;flex-direction:column;background:var(--bg);
}
/* iOS: 100vh mide sin la barra de Safari y tapaba el pie de marca. */
@supports (height:100dvh){.login-split{height:100dvh}}
/* Resplandor de la marca del negocio detrás del formulario; se mueve muy
   despacio. Vive en .login-split (overflow:hidden) y no en el panel del
   formulario, que es scrolleable y lo arrastraría con el contenido. */
.login-split::before{
  content:"";position:absolute;inset:-25%;z-index:-1;pointer-events:none;
  background:
    radial-gradient(38% 32% at 78% 18%,color-mix(in srgb,var(--yellow) 20%,transparent),transparent 70%),
    radial-gradient(34% 30% at 22% 86%,color-mix(in srgb,var(--orange) 11%,transparent),transparent 70%);
  animation:lxDrift 22s ease-in-out infinite alternate;
}
@keyframes lxDrift{from{transform:translate3d(-3%,2%,0) rotate(0deg)}to{transform:translate3d(3%,-3%,0) rotate(6deg)}}
.lx-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* Entrada escalonada: cada bloque sube y se enfoca, uno detrás de otro. */
@keyframes lxIn{from{opacity:0;transform:translateY(14px);filter:blur(6px)}to{opacity:1;transform:none;filter:none}}
#login-screen:not([hidden]) .lx-in{animation:lxIn .7s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--i,0) * 75ms + 100ms)}

/* ── Panel de Arche (solo escritorio) ── */
.login-showcase-panel{
  position:relative;overflow:hidden;isolation:isolate;display:none;
  flex-direction:column;justify-content:space-between;gap:24px;padding:36px 44px 40px;
  background:#09090b;color:#fff;
}
.login-showcase-canvas{position:absolute;inset:0;z-index:-1;width:100%;height:100%;display:block}
.lx-show-top{display:flex;align-items:center;justify-content:space-between;gap:16px}
.lx-wordmark{
  width:118px;aspect-ratio:1600/243;background:#fff;
  -webkit-mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
  mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
}
.lx-show-status{
  display:inline-flex;align-items:center;gap:8px;padding:6px 12px;border-radius:999px;
  border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  font-size:.76rem;font-weight:600;color:rgba(255,255,255,.72);
}
.lx-show-status b{font-weight:600}
[data-lx-status] i{
  flex:none;width:7px;height:7px;border-radius:50%;background:#3DDC84;
  animation:lxPing 2.4s ease-out infinite;
}
[data-lx-status].is-off i{background:#FF5D5D;animation:none}
@keyframes lxPing{0%{box-shadow:0 0 0 0 rgba(61,220,132,.55)}70%,100%{box-shadow:0 0 0 7px rgba(61,220,132,0)}}
.login-showcase-copy{max-width:470px}
.lx-eyebrow{margin:0 0 16px;font-size:.72rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.42)}
.lx-eyebrow em{font-style:normal;color:rgba(255,255,255,.78)}
.login-showcase-tagline{
  margin:0;min-height:2.4em;font-family:Sora,Manrope,sans-serif;font-weight:700;
  font-size:clamp(1.6rem,2.5vw,2.4rem);line-height:1.18;letter-spacing:-.028em;color:#fff;
}
/* Cada palabra entra por separado (loginShowcase.js las envuelve). */
.lx-word{
  display:inline-block;opacity:0;transform:translateY(.45em);filter:blur(8px);
  transition:opacity .55s ease,transform .75s cubic-bezier(.16,1,.3,1),filter .55s ease;
  transition-delay:calc(var(--w,0) * 45ms);
}
.lx-word.is-on{opacity:1;transform:none;filter:none}
.lx-word.is-out{opacity:0;transform:translateY(-.35em);filter:blur(6px);transition-delay:calc(var(--w,0) * 18ms)}
.lx-tag-steps{display:flex;gap:6px;margin-top:28px}
.lx-tag-steps span{position:relative;width:34px;height:3px;border-radius:2px;background:rgba(255,255,255,.16);overflow:hidden}
.lx-tag-steps i{position:absolute;inset:0;background:#fff;transform:scaleX(0);transform-origin:left}
.lx-tag-steps .done i{transform:scaleX(1)}
.lx-tag-steps .run i{animation:lxStep var(--dur,4.8s) linear forwards}
@keyframes lxStep{to{transform:scaleX(1)}}
.lx-clock{margin:0;font-family:Sora,Manrope,sans-serif;font-weight:600;font-size:3.2rem;line-height:1;letter-spacing:-.045em;font-variant-numeric:tabular-nums}
.lx-clock small{margin-left:8px;font-size:.95rem;font-weight:600;letter-spacing:0;color:rgba(255,255,255,.55)}
.lx-date{margin:10px 0 0;font-size:.9rem;color:rgba(255,255,255,.55)}

/* ── Panel del negocio ── */
.login-form-panel{
  position:relative;flex:1 1 auto;min-height:0;overflow-y:auto;
  display:flex;flex-direction:column;align-items:center;padding:18px 24px 22px;
}
.lx-meta{flex:none;display:flex;justify-content:center;width:100%}
.lx-meta-pill{
  display:inline-flex;align-items:center;gap:8px;padding:6px 13px;border-radius:999px;
  border:1px solid var(--line);background:color-mix(in srgb,var(--surface) 72%,transparent);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  font-size:.78rem;font-weight:600;color:var(--ink-soft);font-variant-numeric:tabular-nums;
}
.lx-meta-sep{opacity:.5}
/* Mismo truco de antes: los márgenes auto centran el bloque en el espacio
   libre y el pie queda pegado abajo; si no cabe, se achican a 0 y el panel
   se vuelve scrolleable (nunca se encima uno sobre otro). */
.login-form-main{
  margin:auto 0;width:100%;max-width:330px;flex:none;padding:22px 0 10px;
  display:flex;flex-direction:column;align-items:center;text-align:center;
}
.lx-greeting{margin:0 0 6px;font-size:.95rem;font-weight:600;color:var(--ink-soft)}
h1.login-form-brand{margin:0 0 26px;font-size:clamp(1.95rem,4.2vw,2.4rem);font-weight:800;line-height:1.05;letter-spacing:-.032em;text-align:center}
.login-form-panel .instance-line{text-align:center;margin:-16px 0 20px}

/* Selector PIN / Contraseña con una pastilla que se desliza. */
.lx-mode{
  position:relative;display:grid;grid-template-columns:1fr 1fr;width:100%;max-width:252px;
  margin:0 0 22px;padding:4px;border-radius:999px;background:var(--surface-2);border:1px solid var(--line);
}
.lx-mode button{
  position:relative;z-index:1;padding:9px 0;border:0;border-radius:999px;background:none;cursor:pointer;
  font:inherit;font-size:.86rem;font-weight:700;color:var(--ink-soft);transition:color .25s ease;
}
.lx-mode button[aria-checked="true"]{color:var(--ink)}
.lx-mode button:focus-visible{outline:2px solid var(--yellow);outline-offset:2px}
.lx-mode-thumb{
  position:absolute;top:4px;bottom:4px;left:4px;width:calc(50% - 4px);border-radius:999px;
  background:var(--surface);box-shadow:var(--shadow-sm),0 0 0 1px var(--line);
  transition:transform .45s cubic-bezier(.34,1.45,.64,1);
}
.lx-mode[data-mode="keyboard"] .lx-mode-thumb{transform:translateX(100%)}

.login-form-panel .login-form{width:100%}
.login-form-panel .field{max-width:none}
#login-form{max-width:252px;display:flex;flex-direction:column;align-items:center}
#login-form.is-switching{animation:lxSwap .35s cubic-bezier(.16,1,.3,1)}
@keyframes lxSwap{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:none}}
.login-credential-field{width:100%;margin-bottom:12px}
.lx-pass{position:relative}
.lx-pass input{width:100%;padding-left:44px;padding-right:44px;text-align:center;font-size:1.02rem}
.lx-eye{
  position:absolute;right:5px;top:50%;transform:translateY(-50%);width:36px;height:36px;
  display:grid;place-items:center;border:0;border-radius:50%;background:none;color:var(--ink-soft);cursor:pointer;
  transition:background .15s,color .15s;
}
.lx-eye:hover{background:var(--surface-2);color:var(--ink)}
.lx-eye-slash{stroke-dasharray:23;stroke-dashoffset:23;transition:stroke-dashoffset .3s ease}
.lx-eye[aria-pressed="true"] .lx-eye-slash{stroke-dashoffset:0}
.lx-caps{margin:8px 0 0;font-size:.78rem;font-weight:700;color:var(--amber);animation:lxSwap .25s ease}

/* Teclado numérico del PIN. */
.login-pinpad{width:100%;display:flex;flex-direction:column;align-items:center}
.login-pin-dots{display:flex;align-items:center;gap:16px;height:18px}
.pin-dot{
  width:13px;height:13px;border-radius:50%;border:1.5px solid var(--line-strong);
  transition:background .2s ease,border-color .2s ease;
}
.pin-dot.filled{background:var(--yellow);border-color:var(--yellow);animation:lxPop .34s cubic-bezier(.34,1.6,.64,1)}
@keyframes lxPop{0%{transform:scale(.3)}60%{transform:scale(1.28)}100%{transform:scale(1)}}
.login-pin-dots.is-checking .pin-dot{animation:lxWave .9s ease-in-out infinite;animation-delay:calc(var(--d,0) * 110ms)}
@keyframes lxWave{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-7px)}}
.login-pin-dots.is-error .pin-dot{background:var(--danger);border-color:var(--danger)}
.login-pin-dots.is-ok .pin-dot{background:var(--sage);border-color:var(--sage)}
.lx-pin-hint{margin:10px 0 16px;min-height:1.25em;font-size:.8rem;color:var(--ink-soft)}
.pin-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%}
.pin-key{
  position:relative;overflow:hidden;aspect-ratio:1;border-radius:50%;
  display:flex;align-items:center;justify-content:center;cursor:pointer;user-select:none;-webkit-user-select:none;
  background:var(--surface);border:1px solid var(--line);color:var(--ink);
  font-family:Sora,Manrope,sans-serif;font-weight:600;font-size:1.35rem;
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
  transition:transform .14s ease,background .2s ease,border-color .2s ease;
}
.pin-key:hover{background:var(--surface-2);border-color:var(--line-strong)}
.pin-key.is-press{transform:scale(.9)}
.pin-key.ghost{background:none;border-color:transparent;color:var(--ink-soft);font-size:.95rem;font-weight:700}
.pin-key.ghost:hover{background:var(--surface-2);color:var(--ink)}
.lx-ripple{
  position:absolute;width:100%;aspect-ratio:1;border-radius:50%;pointer-events:none;
  background:var(--yellow);opacity:.4;transform:scale(0);animation:lxRipple .55s ease-out forwards;
}
@keyframes lxRipple{to{transform:scale(2.2);opacity:0}}
@media (max-height:720px){
  .pin-grid{gap:10px;max-width:212px}
  .pin-key{font-size:1.2rem}
  .login-form-main{padding-top:12px}
  h1.login-form-brand{margin-bottom:16px}
  .lx-mode{margin-bottom:14px}
  .lx-pin-hint{margin:8px 0 12px}
  .login-social{margin-top:14px}
}

#login-error{width:100%;margin:12px 0 0;animation:lxSwap .3s ease}
#login-form.is-shake{animation:lxShake .5s cubic-bezier(.36,.07,.19,.97)}
@keyframes lxShake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}30%,50%,70%{transform:translateX(-8px)}40%,60%{transform:translateX(8px)}}
#login-form .lx-submit{display:flex;align-items:center;justify-content:center;gap:8px;margin:14px 0 0}
#login-form.is-pin .lx-submit{display:none}
.lx-arrow{transition:transform .25s cubic-bezier(.16,1,.3,1)}
.lx-submit:hover .lx-arrow{transform:translateX(4px)}
.lx-submit:disabled .lx-arrow{display:none}
.login-forgot a{color:var(--ink-soft);font-size:.86rem;text-decoration-color:var(--ink-soft)}
#forgot-form{max-width:300px;text-align:left}
#forgot-form:not([hidden]){animation:lxSwap .35s cubic-bezier(.16,1,.3,1)}
#forgot-form .login-forgot{text-align:center}

.login-social{display:flex;justify-content:center;gap:8px;margin-top:22px}
.login-social-link{
  display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;
  border:1px solid var(--line);color:var(--ink-soft);transition:background .15s,color .15s,border-color .15s,transform .2s;
}
.login-social-link:hover{background:var(--surface-2);color:var(--ink);border-color:var(--line-strong);transform:translateY(-2px)}
/* Pie de marca: lo usan también bloqueo, turno y asistente. */
.login-footer-brand{flex:none;padding-top:22px;display:flex;flex-direction:column;align-items:center;gap:6px}
.login-mark-mono{
  width:108px;aspect-ratio:791/120;background-color:var(--ink-soft);opacity:.85;
  -webkit-mask:url(../img/brand/arche-wordmark.png) center/contain no-repeat;
  mask:url(../img/brand/arche-wordmark.png) center/contain no-repeat;
}
.login-footer-brand .sidebar-copyright{color:var(--ink-soft);margin:0}

@media (min-width:760px){
  .login-split{flex-direction:row}
  .login-showcase-panel{display:flex;flex:1.25;min-height:0}
  .login-form-panel{flex:1;padding:36px 36px 28px}
  .lx-meta{display:none}
  /* En escritorio el panel de Arche ya tiene la marca grande: el pie del
     formulario se queda solo con los derechos. */
  .login-split .login-footer-brand .login-mark-mono{display:none}
}
@media (min-width:1500px){.login-showcase-panel{flex:1.5}}

/* ── Pantalla de carga al entrar y al salir ── */
.access-loading{
  position:fixed;inset:0;z-index:9999;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;
  background:radial-gradient(circle at 50% 42%,#18181c 0,#09090b 62%);color:#fff;
  opacity:0;pointer-events:none;transition:opacity .3s ease;
}
.access-loading.is-visible{opacity:1;pointer-events:auto}
.access-loading-emblem{position:relative;width:104px;aspect-ratio:900/649;margin-bottom:14px}
.access-loading-mark{
  position:absolute;inset:0;background:#fff;clip-path:inset(100% 0 0 0);
  -webkit-mask:url(../img/brand/arche-mark-hd.png) center/contain no-repeat;
  mask:url(../img/brand/arche-mark-hd.png) center/contain no-repeat;
}
/* Los anillos salen del nodo del travesaño de la «A» (50 % / 62 % del logo). */
.access-loading-ring{
  position:absolute;left:50.2%;top:61.6%;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,.7);opacity:0;
}
.access-loading-text{margin:0;font-family:Sora,Manrope,sans-serif;font-size:1.3rem;font-weight:700;letter-spacing:-.02em}
.access-loading-sub{margin:0;font-size:.88rem;color:rgba(255,255,255,.6)}
.access-loading-bar{width:150px;height:2px;margin-top:12px;border-radius:2px;background:rgba(255,255,255,.12);overflow:hidden}
.access-loading-bar i{display:block;width:100%;height:100%;background:#fff;transform:scaleX(0);transform-origin:left}
.access-loading-word{
  position:absolute;bottom:34px;width:84px;aspect-ratio:1600/243;background:rgba(255,255,255,.38);
  -webkit-mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
  mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
}
.access-loading.is-visible .access-loading-mark{animation:lxDraw .85s cubic-bezier(.65,0,.35,1) .05s forwards}
.access-loading.is-visible .access-loading-ring{animation:lxRing 1.7s ease-out .6s infinite}
.access-loading.is-visible .access-loading-ring + .access-loading-ring{animation-delay:1.45s}
.access-loading.is-visible .access-loading-text{animation:lxIn .6s cubic-bezier(.16,1,.3,1) .3s both}
.access-loading.is-visible .access-loading-sub{animation:lxIn .6s cubic-bezier(.16,1,.3,1) .4s both}
.access-loading.is-visible .access-loading-bar i{animation:lxBar 1.05s cubic-bezier(.65,0,.35,1) .1s forwards}
@keyframes lxDraw{to{clip-path:inset(0 0 0 0)}}
@keyframes lxRing{0%{transform:scale(.5);opacity:.9}100%{transform:scale(10);opacity:0}}
@keyframes lxBar{to{transform:scaleX(1)}}

@media (prefers-reduced-motion:reduce){
  .login-split::before,#login-screen:not([hidden]) .lx-in,#login-form.is-switching,#login-form.is-shake,
  .pin-dot.filled,.login-pin-dots.is-checking .pin-dot,[data-lx-status] i,.lx-caps,#login-error,
  #forgot-form:not([hidden]){animation:none}
  .lx-word{transition:none}
  .lx-mode-thumb,.pin-key{transition:none}
  .lx-tag-steps .run i{animation:none;transform:scaleX(1)}
  .access-loading.is-visible .access-loading-mark{animation:none;clip-path:none}
  .access-loading.is-visible .access-loading-ring,.access-loading.is-visible .access-loading-text,
  .access-loading.is-visible .access-loading-sub{animation:none}
  .access-loading.is-visible .access-loading-bar i{animation:none;transform:scaleX(1)}
}
/* Etiqueta de instalación (La Vega / Santo Domingo / San Francisco de
   Macorís) — pedido del dueño para distinguir a simple vista en qué
   instalación está parado, sin tocar el nombre del negocio que ya se
   muestra en grande. Oculta si INSTANCE_LABEL no está configurado (así la
   instalación de siempre no cambia de aspecto sin querer). */
.instance-line{text-align:center;margin:-14px 0 20px}
.sidebar-instance-line{text-align:center;margin:4px 0 0}
.sidebar-instance{
  display:inline-block;padding:2px 9px;border-radius:999px;
  font-size:.68rem;font-weight:700;letter-spacing:.02em;
  background:rgba(255,255,255,.10);color:color-mix(in srgb,var(--cream) 75%,transparent);
}
.app-content{flex:1;min-width:0}

/* Botón de menú (hamburguesa) — solo visible en el menú deslizable móvil del dueño */
.sidebar-toggle{
  display:none;width:38px;height:38px;border-radius:9px;border:none;background:transparent;
  cursor:pointer;flex-direction:column;align-items:center;justify-content:center;gap:5px;flex:0 0 auto;
}
.sidebar-toggle span{
  display:block;width:20px;height:2px;background:var(--cream);border-radius:2px;
  transition:transform .2s ease,opacity .15s ease;
}
/* Hamburguesa → X al abrir: la barra del medio se apaga, las otras dos
   rotan y se corren al centro para formar la cruz — misma señal visual
   que cualquier app nativa de que tocar de nuevo cierra el menú (antes
   se quedaba como hamburguesa sin importar el estado). */
.sidebar.open .sidebar-toggle span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.sidebar.open .sidebar-toggle span:nth-child(2){opacity:0}
.sidebar.open .sidebar-toggle span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
@media (prefers-reduced-motion:reduce){.sidebar-toggle span{transition:none}}
.sidebar-backdrop{display:none}

@media (max-width:820px){
  .app-shell{flex-direction:column}
  .sidebar{
    width:100%;flex:0 0 auto;height:auto;position:sticky;top:0;z-index:20;
    flex-direction:row;align-items:center;padding:10px 12px;overflow-x:auto;
  }
  .sidebar-brand{padding:4px 10px 4px 0;white-space:nowrap}
  .sidebar-brand span{display:inline;margin-left:6px}
  .sidebar-nav{flex-direction:row;flex:none}
  .nav-item{white-space:nowrap;padding:8px 12px}
  .nav-group{flex-direction:row;gap:3px}
  .nav-group + .nav-group{margin-top:0;padding-left:10px;border-left:1px solid rgba(255,255,255,.15)}
  .nav-group-label{display:none}
  .sidebar-footer{flex-direction:row;border-top:none;padding-top:0;margin-left:auto}
  /* Sin espacio de sobra en la barra superior/inferior móvil para un pie
     decorativo — se prioriza Ayuda/Salir. Sigue visible en escritorio; en
     el menú deslizable del dueño se reactiva más abajo (#owner-app), que sí
     tiene el alto sobrante para mostrarlo sin apretar nada. */
  .sidebar-footer .sidebar-copyright{display:none}
  .sidebar-footer .sidebar-instance-line{display:none}

  /* Carrito y almacén en celular: barra de pestañas real abajo (patrón app
     móvil), no una fila que se desliza — pocas secciones (3-4), entran
     perfecto. Mismo tratamiento para los dos: son la misma clase de sesión
     (un empleado con PIN, uso a diario desde el teléfono), a diferencia del
     dueño (9 secciones, menú deslizable aparte, ver #owner-app abajo). */
  #cart-app.app-shell,#almacen-app.app-shell{display:block}
  #cart-app .sidebar,#almacen-app .sidebar{
    /* overflow-y:visible explícito — la regla de escritorio de arriba deja
       .sidebar con overflow-y:auto, y acá nunca se resetea (solo se toca
       overflow-x). Un contenedor con overflow-y:auto/scroll es, en Safari
       de iOS, un caso conocido donde un position:fixed DESCENDIENTE (la
       barra de pestañas de abajo, #cart-tabs, vive DENTRO de este .sidebar)
       deja de fijarse a la pantalla real y en cambio se desplaza pegado al
       contenido — reportado en vivo por el dueño con captura: la barra
       aparecía a mitad de la lista de insumos en vez de quedarse abajo del
       todo. No se reproduce en Chrome/el navegador de pruebas (es
       específico de WebKit/iOS), así que el arreglo es por inspección de
       código, no por captura de pantalla propia. */
    overflow-x:visible;overflow-y:visible;padding:10px 14px;position:sticky;
  }
  #cart-app .sidebar-nav{
    position:fixed;left:0;right:0;bottom:0;z-index:30;
    background:var(--brown-deep);box-shadow:0 -2px 14px rgba(0,0,0,.2);
    padding:6px 6px calc(6px + env(safe-area-inset-bottom));
  }
  #cart-app .nav-group{flex:1;gap:0}
  /* Con 7 pestañas (Pedidos web activo) no entran en 375px: la barra se desliza. */
  #cart-app .sidebar-nav{overflow-x:auto;scrollbar-width:none}
  #cart-app .sidebar-nav::-webkit-scrollbar{display:none}
  #cart-app .sidebar-nav .nav-item{flex:1 0 auto;min-width:56px}
  #cart-app .nav-item{
    flex:1;flex-direction:column;justify-content:center;gap:3px;text-align:center;padding:8px 4px;font-size:.78rem;
    border-radius:10px;white-space:normal;line-height:1.2;
  }
  #cart-app .nav-icon{width:20px;height:20px}
  #cart-app .app-content{padding-bottom:76px}
  /* En "Nueva venta" hay DOS elementos fijos abajo, no uno: la barra de
     pestañas (~70px) y, cuando hay algo en el carrito, la barra flotante
     del total (~50px más arriba). Con solo los 76px de la barra de
     pestañas, el final de la tarjeta — el botón "Confirmar venta" y sobre
     todo el mensaje de error que aparece debajo — quedaba tapado por la
     barra flotante. Probado de verdad en 375px forzando un error de stock:
     el error no se leía completo. */
  #cart-app .view[data-view="pos-venta"]{padding-bottom:96px}

  /* La barra en sí (posición, color, forma) vive fuera de este media query —
     acá solo se decide CUÁNDO se muestra (ver regla .mobile-cart-bar más
     abajo, fuera de @media): en celular y con productos en el carrito. */
  #cart-app .mobile-cart-bar:not([hidden]){display:flex}

  /* Objetivos táctiles más grandes (uso real en celular/tablet) — pero solo
     acá, en pantalla chica. Aplicado siempre (sin @media) esto hacía que la
     interfaz del carrito se viera desproporcionada frente a la del dueño en
     un monitor de escritorio, siendo la misma interfaz de base. */
  #cart-app .product-row{padding:14px 16px}
  #cart-app .product-row .info strong{font-size:1.05rem}
  #cart-app .product-row .qty-controls{gap:14px}
  #cart-app .product-row .qty-controls button{
    width:44px;height:44px;font-size:1.3rem;
  }
  #cart-app .product-row .qty-controls span{font-size:1.1rem;min-width:2em}
  #cart-app .btn-primary{padding:14px 18px;font-size:1.05rem}

  /* Dueño en celular: 9 secciones no caben en una fila ni en una barra de
     pestañas — en vez de eso, la barra superior queda fija (marca + botón de
     menú) y el menú completo (con sus grupos) se desliza desde la izquierda
     como un panel, igual que cualquier app de administración en móvil. */
  #owner-app .sidebar{
    overflow-x:visible;justify-content:space-between;padding:10px 14px;
  }
  #owner-app .sidebar-toggle{display:flex}
  #owner-app .sidebar-backdrop{
    display:block;position:fixed;inset:0;background:rgba(19,17,9,.5);
    z-index:39;opacity:0;pointer-events:none;transition:opacity .2s ease;
  }
  #owner-app .sidebar.open .sidebar-backdrop{opacity:1;pointer-events:auto}
  #owner-app .sidebar-nav{
    position:fixed;top:0;left:0;bottom:0;z-index:40;
    width:min(82vw,300px);flex-direction:column;gap:3px;
    /* padding-bottom generoso a propósito: .sidebar-footer (Ayuda/Salir +
       pie de derechos reservados) es OTRO elemento fixed que se dibuja
       encima de esta misma esquina inferior — sin este espacio reservado,
       "Reportes"/"Configuración" (los últimos ítems del menú) quedaban
       físicamente tapados por el footer y ni haciendo scroll se alcanzaban
       a ver. Encontrado en vivo, desde el celular real. Medido: el footer
       real mide ~149px (más lo que sume env(safe-area-inset-bottom) en un
       iPhone con isla/home indicator) — un padding fijo de 140px se quedaba
       corto por ese margen y tapaba los últimos ~9px de "Configuración"
       incluso con el menú scrolleado hasta el final. Por eso el margen es
       holgado (180px) y crece con la misma safe-area que usa el footer. */
    background:var(--brown-deep);padding:20px 16px calc(180px + env(safe-area-inset-bottom));overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    /* Bug real encontrado en vivo (iPhone): al llegar al final del scroll
       DENTRO del menú y seguir arrastrando, el scroll se quedaba "trabado"
       varios segundos sin responder a nada. Es un problema conocido de iOS
       Safari — un contenedor con scroll propio metido dentro de un padre
       fixed (el body ya está bloqueado por lockBodyScroll en app.js) puede
       colgar el manejo del touch al llegar al límite y "rebotar" buscando
       a quién encadenarle el scroll. overscroll-behavior:contain le dice
       al navegador que el rebote se queda ACÁ, sin buscar más arriba. */
    overscroll-behavior:contain;
    transform:translateX(-100%);transition:transform .25s ease;
    box-shadow:6px 0 24px rgba(0,0,0,.25);
  }
  #owner-app .sidebar.open .sidebar-nav{transform:translateX(0)}
  #owner-app .nav-group{flex-direction:column;gap:3px}
  #owner-app .nav-group + .nav-group{margin-top:14px;padding-left:0;border-left:none}
  /* Con Compras y Reposición sumados esta sesión, el menú del dueño en el teléfono ya
     pasa de 20 secciones — llegar a "Configuración" pedía deslizar bastante. Los 4 grupos
     con nombre (Inventario/Análisis/Catálogo/Negocio) se pliegan como acordeón: uno solo
     abierto a la vez, el que trae la sección donde estás parado (ver app.js) — Panel
     e Historial, el primer grupo SIN nombre, se quedan siempre a la vista, son los de
     todos los días. En escritorio nunca se pliegan (ahí sí hay alto de sobra) — la regla
     de abajo que oculta .nav-item vive DENTRO de este media query a propósito. */
  #owner-app .nav-group-label{
    display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:pointer;
  }
  #owner-app .nav-group-chevron{display:block;width:14px;height:14px;flex:0 0 auto;transition:transform .18s ease}
  #owner-app .nav-group-label[aria-expanded="false"] .nav-group-chevron{transform:rotate(-90deg)}
  #owner-app .nav-group-label[aria-expanded="false"] ~ .nav-item{display:none}
  #owner-app .nav-item{white-space:normal;text-align:left;padding:11px 12px;font-size:.95rem}
  #owner-app .sidebar-footer{
    position:fixed;left:0;bottom:0;z-index:40;width:min(82vw,300px);
    flex-direction:row;flex-wrap:wrap;gap:8px;margin-left:0;background:var(--brown-deep);
    padding:12px 16px calc(12px + env(safe-area-inset-bottom));
    border-top:1px solid rgba(255,255,255,.15);
    transform:translateX(-100%);transition:transform .25s ease;
  }
  #owner-app .sidebar-footer .sidebar-copyright{display:block;flex-basis:100%}
  #owner-app .sidebar-footer .sidebar-instance-line{display:block;flex-basis:100%}
  #owner-app .sidebar.open .sidebar-footer{transform:translateX(0)}

  /* "Ver detalle" en Ubicaciones hace scrollIntoView({block:'start'}) hacia
     este panel — sin esto, el título y el botón "Cerrar" quedan tapados
     bajo la barra de marca sticky (confirmado: el panel terminaba en
     top:0, exactamente detrás de los ~103px de header). scroll-margin-top
     es lo que scrollIntoView respeta para dejar aire arriba del target. */
  #ubicacion-detalle{scroll-margin-top:112px}

  /* Mismo motivo que #ubicacion-detalle arriba: tocar un día del gráfico
     del Panel (dashboard.js selectDay) hace scrollIntoView hacia acá — sin
     este margen, el título del día quedaba tapado detrás de la barra de
     marca sticky. */
  #panel-selected-day-label{scroll-margin-top:112px}
}

.view[hidden]{display:none}
@keyframes viewFadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
.view{animation:viewFadeIn .2s ease}
@media (prefers-reduced-motion:reduce){
  .view,.modal-overlay,.modal-box,.recibo-modal{animation:none!important}
}

.card{
  background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow);padding:20px;margin-bottom:18px;
}
/* Variante de menor peso visual — para lo secundario en una pantalla que ya tiene
   un bloque principal (evita que todo compita por la misma atención) */
.card-quiet{
  background:transparent;border:var(--bw) solid var(--line);border-radius:var(--r-lg);
  box-shadow:none;padding:18px;margin-bottom:18px;
}
/* Reportes: las 4 tablas iban una atrás de otra siempre visibles — mucho
   scroll en celular para llegar a la última. `.report-section` es un
   `<details>` con el aspecto de `.card` (mismo borde/sombra, padding en
   0 para que summary y el cuerpo pongan el suyo por separado) en vez de
   un acordeón hecho a mano con JS — el navegador ya maneja abrir/cerrar
   y el teclado solo. */
.report-section{padding:0}
.report-section > summary{
  cursor:pointer;list-style:none;padding:20px;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
}
.report-section > summary::-webkit-details-marker{display:none}
.report-section > summary h2,.report-section > summary h3{margin:0}
/* Flechita propia en vez del triángulo nativo del navegador (que además
   varía de estilo entre Chrome/Safari) — mismo lenguaje visual que ya usa
   .addon-toggle-icon en Nueva venta: una V que rota 180° al abrir. */
.report-section > summary::after{
  content:'';flex:0 0 auto;width:9px;height:9px;
  border-right:2px solid var(--ink-soft);border-bottom:2px solid var(--ink-soft);
  transform:rotate(45deg);transition:transform .2s ease;
}
.report-section[open] > summary::after{transform:rotate(-135deg)}
@media (prefers-reduced-motion:reduce){.report-section > summary::after{transition:none}}
.report-section-body{padding:0 20px 20px}
.report-section-body button[data-csv]{display:block;margin-bottom:12px}
@media print{
  /* El papel tiene que salir completo — no tiene sentido que algo
     "colapsado en pantalla" desaparezca del reporte impreso. Se fuerza
     visible sin importar el atributo open real. */
  .report-section > summary::after{display:none}
  .report-section > *{display:block !important}
}
.card-quiet h2{color:var(--ink-soft)}
.grid-2{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);gap:18px}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
/* Antes colapsaban a 1 columna junto con el resto del layout de sidebar
   (@820px) — pero esa cifra es sobre CUÁNDO el sidebar se vuelve barra
   superior, no sobre cuándo estas grillas dejan de tener espacio. En una
   tablet real (768px, que es EXACTAMENTE donde el dueño pidió que se vea
   bien) sobraba lugar de sobra para 2 o 3 columnas y aun así caían a 1
   sola, dejando la pantalla mucho más larga de lo necesario. Bajado a
   620px — por debajo de cualquier tablet real, ahí sí hace falta 1 sola
   columna (un teléfono de 5-6", 390-430px). */
@media (max-width:620px){.grid-2{grid-template-columns:1fr}.grid-3{grid-template-columns:1fr}}

/* Ofertas en "Nueva venta": pedido explícito del dueño — antes se veía
   igual que "Vasos" de abajo, y un vendedor apurado en la calle no
   necesariamente se fijaba en que había combos disponibles para ofrecer.
   Fondo e borde con el naranja de marca (el mismo de los botones
   principales) para que salte a la vista apenas se abre la pantalla,
   antes de leer una sola palabra — no un color semántico nuevo, es el
   acento que ya usa el resto de la app para "esto es lo importante". */
.pos-offers-highlight{
  background:var(--cream-2);border:2px solid var(--orange);border-radius:var(--r-lg);
  padding:14px 14px 4px;margin-bottom:18px;
}
.pos-offers-highlight h2{color:var(--orange)}
.pos-offers-highlight .product-row{border-color:var(--orange);background:var(--surface)}
/* Qué incluye el combo, un renglón por producto — antes era una sola
   oración larga ("2 x Vaso 24oz + 2 x Sirop de fresa + 1 x Vaso 12oz")
   que envolvía en varias líneas sin ninguna estructura. Sin viñeta (una
   oferta de 2-3 líneas no necesita el ruido visual de un bullet) — la
   separación ya la da cada uno siendo su propio renglón. */
.offer-items-list{
  list-style:none;margin:2px 0 4px;padding:0;
  font-size:.86em;color:var(--ink-soft);line-height:1.5;
}

.product-list{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}
.product-row{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  border:1px solid var(--line);border-radius:var(--r);padding:10px 14px;background:var(--surface);
  transition:border-color .15s ease;
}
.product-row:hover{border-color:var(--ink-soft)}
.product-row .info{display:flex;flex-direction:column}
.product-row .price{font-weight:700;color:var(--ink)}
.product-row .qty-controls{display:flex;align-items:center;gap:8px}
.product-row .qty-controls button{
  width:28px;height:28px;border-radius:50%;border:1px solid var(--brown);
  background:var(--yellow);font-weight:700;cursor:pointer;transition:transform .1s ease;
}
.product-row .qty-controls button:active{transform:scale(.92)}
.product-row .qty-controls span{min-width:1.5em;text-align:center;font-weight:700;font-variant-numeric:tabular-nums}

/* Adicionales colapsados por default en Nueva venta — feedback real del
   dueño probando desde su celular: con los 4 vasos + 6-7 adicionales
   siempre visibles, la pantalla se sentía con "muchas opciones" de
   entrada. Un adicional tampoco se vende solo (hace falta un vaso ya en
   el carrito), así que ocultarlo hasta pedirlo refuerza esa misma regla. */
.addon-toggle{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  background:var(--bg);border:var(--bw) dashed var(--line);border-radius:var(--r);
  padding:12px 14px;margin:14px 0 4px;font:inherit;font-weight:700;color:var(--ink-soft);
  cursor:pointer;min-height:44px;transition:background-color .15s ease;
}
.addon-toggle:hover{background:var(--surface-2)}
.addon-toggle-icon{display:inline-flex;width:12px;height:12px;transition:transform .2s ease}
.addon-toggle[aria-expanded="true"] .addon-toggle-icon{transform:rotate(180deg)}
#pos-addon-section{margin-top:10px}
@media (prefers-reduced-motion:reduce){.addon-toggle,.addon-toggle-icon{transition:none}}

.cart-items{min-height:60px;margin-bottom:10px}
.cart-item-row{display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px dashed var(--line)}

/* Confirmar recepción de una transferencia (Mi inventario del carrito) —
   mismo espaciado que .cart-item-row, pero con un input editable en vez de
   solo texto: el carrito puede corregir la cantidad si lo que llegó no
   coincide con lo que el almacén anotó. */
.transfer-items{margin:10px 0}
.transfer-item-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:6px 0;border-bottom:1px dashed var(--line)}
.transfer-item-row input{width:90px;text-align:right}
.cart-totals .row{display:flex;justify-content:space-between;padding:4px 0}
.cart-totals strong{color:var(--orange);font-size:1.2em}

.field{margin-bottom:12px;display:flex;flex-direction:column;gap:4px;max-width:320px}
.field label{font-weight:700;font-size:.9em;color:var(--ink-soft)}
/* .field está pensado para un solo input simple (de ahí el max-width) — pero
   también envuelve a los 3 recetarios de insumos (Productos, transferencias,
   pasta suelta), que necesitan todo el ancho de la tarjeta para que cada fila
   (insumo + cantidad + Quitar) entre sin desbordar ni truncar el nombre. */
.field-wide{max-width:none}
/* .field es flex-column con el stretch por defecto — bien para el input/
   .receta-builder, que sí deben ocupar todo el ancho, pero el botón
   "+ Insumo a la receta" (agregado después, como hermano) heredaba ese
   mismo stretch y quedaba gigante, cubriendo toda la tarjeta — más en
   .field-wide, que le sacó el tope de 320px. Encontrado en vivo, pedido
   real: que no ocupe más que lo que su propio texto necesita. */
.field > button{align-self:flex-start}
input,select,textarea{
  font:inherit;padding:8px 10px;border:var(--bw) solid var(--line-strong);border-radius:8px;
  background:var(--surface);color:var(--ink);transition:border-color .15s ease;
}
input:focus,select:focus,textarea:focus{border-color:var(--brown);outline:none}
/* Nombre de cliente autocompletado desde su teléfono (ver pos.js/venta.js)
   — bloqueado a propósito para que no se pueda pisar. Fondo distinto para
   que se note que no es un campo normal editable, sin llegar a verse
   "apagado" como :disabled. */
input[readonly]{background:var(--surface-2);cursor:default}
/* El botón nativo de <input type="file"> (Configuración > Logo) no hereda
   nada de lo anterior — se le da la pinta de .btn.btn-sm a mano en los dos
   prefijos de motor (::file-selector-button estándar, ::-webkit-file-upload-button
   para Chrome/Safari viejos) para que no desentone con el resto del formulario. */
/* Sin ancho propio, el input se queda en el intrinsic default del motor
   (~330px) — apenas alcanza para el botón MÁS el texto nativo "Sin
   archivos seleccionados" (26 caracteres), así que ese texto se cortaba
   a la mitad de una palabra ("Sin archivos...leccionados", encontrado
   en vivo en Configuración). min-width le da el aire que le falta.
   min(420px, 100%) en vez de un 420px fijo: en celular (375px de ancho de
   pantalla) un mínimo fijo de 420px hacía que el input fuera más ancho que
   el propio body y toda la página quedara con scroll horizontal — bug real
   encontrado en vivo (Configuración, iPhone, deslizando a los lados). Con
   el tope al 100% del contenedor, el input sigue pidiendo los 420px donde
   hay espacio (tablet/laptop) pero nunca se pasa del ancho disponible. */
input[type="file"]{border:none;background:none;padding:0;font-size:.9em;min-width:min(420px, 100%)}
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button{
  font:inherit;font-weight:700;padding:7px 14px;border-radius:999px;
  border:var(--bw) solid var(--brown);background:var(--surface);color:var(--ink);
  cursor:pointer;margin-right:10px;transition:background-color .15s ease;
}
input[type="file"]::file-selector-button:hover,
input[type="file"]::-webkit-file-upload-button:hover{background:var(--surface-2)}
/* Anillo de foco solo para navegación por teclado (:focus-visible) — no aparece en
   un clic de mouse normal, así que no le agrega "ruido" visual a la interfaz. */
.btn:focus-visible,.nav-item:focus-visible,.sidebar-toggle:focus-visible,.nav-group-label:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible,
.table tr.row-clickable:focus-visible{
  outline:2px solid var(--orange);outline-offset:2px;
}
/* outline-offset en una fila de tabla queda por fuera de la tabla (afecta a
   la fila de al lado) — con outline hacia adentro alcanza para una fila. */
.table tr.row-clickable:focus-visible{outline-offset:-2px}
/* .f (etiqueta + campo apilados) es una unidad reutilizable — vive tanto
   dentro de .form-inline (varias en fila) como suelta en modales/formularios
   de una sola columna (ej. "Editar carrito"). Por eso su layout base (flex
   en columna) NO puede depender de .form-inline como ancestro — quedó así
   una vez y esa combinación concreta (.f fuera de .form-inline) se renderizó
   como <label> en línea, con la etiqueta y el campo superpuestos. */
.f{display:flex;flex-direction:column;gap:4px}
.f span{font-size:.78em;font-weight:700;color:var(--ink-soft)}
.f input,.f select{width:100%;height:38px}

.form-inline{display:flex;flex-wrap:wrap;gap:14px 12px;align-items:end;margin-bottom:12px}
.form-inline > input,.form-inline > select{flex:1 1 140px;max-width:200px;height:38px}
.form-inline .f{flex:0 1 180px;max-width:200px}
.form-inline .btn{flex:0 0 auto}

/* Filtros de fecha (Historial del dueño, del carrito, Reportes): a ~375px
   de ancho, "Desde" (180-200px) ya no deja lugar para "Hasta" al lado, así
   que "Hasta" salta a su propia fila — pero el botón "Filtrar" (ancho
   intrínseco chico) SÍ entra en esa misma fila y queda apretado justo al
   lado del campo de fecha, y "Limpiar" termina solo, más abajo. Reportado
   en vivo desde el celular ("todo superpuesto"). En vez de dejar que cada
   campo/botón decida su propio ancho y quede donde alcance, .filtro-fecha
   fuerza una sola columna prolija en celular — cada campo y botón usa el
   ancho completo, uno debajo del otro. */
@media (max-width:480px){
  .filtro-fecha{flex-direction:column;align-items:stretch}
  .filtro-fecha .f{flex:1 1 auto;max-width:none}
  .filtro-fecha .btn{flex:1 1 auto;width:100%}
}
.f-check{display:flex;align-items:center;gap:8px;flex:1 1 100%;font-size:.9em;font-weight:700;color:var(--ink-soft);min-height:44px}
.f-check input{width:20px;height:20px;accent-color:var(--orange);flex:none}

.search-input{max-width:280px;margin-bottom:14px}

.btn{
  font:inherit;font-weight:700;padding:11px 20px;border-radius:999px;text-align:center;
  border:var(--bw) solid var(--brown);background:var(--surface);color:var(--ink);cursor:pointer;
  transition:background-color .15s ease, border-color .15s ease, transform .08s ease;
  display:inline-block;text-decoration:none;line-height:1.3;min-height:44px;
}
.btn:hover{background:var(--surface-2)}
/* Todo botón tenía :hover pero ningún feedback al presionarlo — y :hover
   ni siquiera existe en touch (tablet, el dispositivo donde el dueño más
   usa el lado administrativo): sin esto, tocar un botón ahí no daba
   ninguna señal visual hasta que la acción terminaba. Mismo patrón que ya
   usan los +/- del carrito (scale al soltar), aplicado en general. */
.btn:active{transform:scale(.96)}
@media (prefers-reduced-motion:reduce){.btn{transition:background-color .15s ease, border-color .15s ease}.btn:active{transform:none}}
.btn-primary{background:var(--yellow);border-color:var(--yellow-deep);color:var(--lime-ink);font-weight:800}
.btn-primary:hover{background:var(--yellow-deep);border-color:var(--yellow-deep)}
/* .btn-sm no hereda el min-height:44px de .btn a propósito — vive en
   contextos densos (varias por fila/tarjeta: Ver, Anular, Editar...) donde
   forzar 44px se vería inflado; 36px sigue siendo cómodo de tocar ahí. */
.btn-sm{padding:5px 12px;font-size:.85em;min-height:36px}
/* Confirmar venta / Guardar se deshabilitan mientras la petición está en
   vuelo (evita doble clic = doble venta) — pero un botón deshabilitado sin
   estilo propio se ve idéntico al habilitado, así que nadie nota que ya
   registró el clic y puede insistir. */
.btn:disabled{opacity:.55;cursor:not-allowed}
.btn:disabled:hover{background:var(--surface)}
.btn-primary:disabled:hover{background:var(--yellow)}
/* Ícono + texto dentro de un botón (Editar/Eliminar/Ver desglose) — el ícono
   hereda el color del texto vía currentColor, así que no necesita variante
   por estado (hover, primary, etc). */
.btn-icon{display:inline-flex;align-items:center;justify-content:center;width:13px;height:13px;margin-right:6px;vertical-align:-2px;flex:none}
.btn-icon svg{width:100%;height:100%;display:block}

/* Texto en --danger-on-bg: en modo oscuro el rojo de --danger casi no se leía sobre su propio fondo. */
.error{color:var(--danger-on-bg);background:var(--danger-bg);border:1px solid var(--danger);border-radius:8px;padding:8px 12px;margin-top:8px}

.table-scroll{overflow-x:auto;max-width:100%}
.table{width:100%;border-collapse:collapse;table-layout:auto}
/* Ninguna celda envuelve texto — si una columna es larga (ej. receta, empaque),
   la tabla se desplaza horizontalmente (.table-scroll) en vez de estirar la fila
   verticalmente. Antes una celda larga envolvía a varias líneas mientras las demás
   celdas de esa misma fila quedaban centradas en ese espacio, dando la sensación de
   filas "desalineadas" — con nowrap todas las filas miden lo mismo siempre. */
.table th,.table td{text-align:left;padding:10px 18px 10px 10px;border-bottom:1px solid var(--line);white-space:nowrap;vertical-align:middle}
.table th{color:var(--ink-soft);font-size:.85em;text-transform:uppercase;letter-spacing:.03em}
.table tr:hover td{background:var(--bg)}
/* Una columna numérica solo se ve "pegada" a la siguiente si su encabezado no
   comparte la alineación de su valor (encabezado a la izquierda, número a la
   derecha, dentro de una columna angosta) — encabezado y valor van del mismo
   lado, con más aire a la derecha de cada columna numérica. */
.table th.num,.table td.num{text-align:right;font-variant-numeric:tabular-nums;padding-right:22px}
/* Con varias columnas + acciones (Ver/Editar/Eliminar/Imprimir), la tabla
   necesita scroll horizontal en pantallas normales — pero sin ninguna
   pista visual de que hay más a la derecha, los botones de acción quedan
   invisibles (el dueño probó Historial pensando que no existía forma de
   reimprimir una factura — sí existía, solo estaba fuera de vista). La
   última columna (siempre las acciones, en estas 6 tablas) queda fija a
   la derecha con position:sticky, con una sombra sutil a la izquierda
   para separarla del contenido que sigue desplazándose detrás. El fondo
   se pone a mano porque una celda sticky necesita ser opaca (si no,
   se ve el contenido de atrás transparentándose al hacer scroll) — blanco
   para las que viven en .card, --paper para la única que no (el detalle
   de Ubicaciones, que no tiene su propia tarjeta blanca alrededor). */
.table--sticky-actions th:last-child,
.table--sticky-actions td:last-child{
  position:sticky;right:0;background:var(--surface);
  box-shadow:-6px 0 8px -6px color-mix(in srgb,var(--brown-deep) 15%,transparent);
}
.table--sticky-actions tr:hover td:last-child{background:var(--bg)}
#tabla-ubicacion-stock.table--sticky-actions th:last-child,
#tabla-ubicacion-stock.table--sticky-actions td:last-child{background:var(--bg)}
.table td.wrap{white-space:normal;max-width:340px}

/* En celular angosto (≤600px), la columna de acciones sticky ya no alcanza:
   agarrado a la derecha, tapa por completo Fecha/Total/Estado (encontrado
   probando de verdad el Historial del carrito en 360px — el ancho visible
   apenas alcanza para la propia columna de acciones). El scroll horizontal
   con una columna fija deja de ser el patrón correcto en una pantalla tan
   angosta; en su lugar, cada fila se convierte en su propia tarjeta con
   las columnas apiladas (patrón estándar de tabla responsive) — nada de
   esto toca el HTML ni el JS que arma las filas, todo vive en CSS. */
@media (max-width:1100px){
  /* Antes el corte era en 600px, después subido a 820px (el quiebre del
     propio .sidebar) al encontrar que tabla-ubicaciones (solo 3 columnas +
     acciones) mostraba "9" en vez de "9.72" en 768px. Pero 820px TAMPOCO
     alcanzaba: justo arriba de ese punto el sidebar vuelve a ser una
     columna fija de 230px (en vez de barra superior), así que el ancho
     disponible para la tabla en realidad se achica de nuevo entre 821px y
     ~1040px — confirmado en 900px, donde la columna más ancha directamente
     desaparecía tapada por las acciones. Medido con getBoundingClientRect:
     tabla-insumos y tabla-ubicaciones (dos tablas distintas, en ese
     momento) necesitaban exactamente 738px, y ambas encajaban justo a
     partir de 1042px de ventana. 1100px es el mismo tope que ya usa .wrap
     para el ancho de contenido — un solo número con sentido en vez de otro
     más a adivinar. (Insumos y Ubicaciones dejaron de ser tablas en la
     fase 3 del rediseño — pasaron a .products-grid — pero el número sigue
     siendo el correcto para las tablas que quedan: Reportes y el
     historial propio del carrito.) */
  /* Ampliado de .table--sticky-actions a .table en general: el mismo
     problema (columnas que no entran, sin ninguna pista de que hay que
     scrollear) existe en cualquier tabla de varias columnas, tenga o no
     columna de acciones — encontrado en Reportes ("Por ubicación", "Por
     producto", "Por día", 5 columnas cada una) probando de verdad en
     390px: el Total quedaba directamente cortado ("RD$" sin el número). */
  .table{display:block}
  .table thead{display:none}
  .table tbody{display:block}
  .table tr{
    display:block;border:var(--bw) solid var(--line);border-radius:var(--r);
    padding:12px 14px;margin-bottom:10px;
  }
  .table td{
    display:flex;justify-content:space-between;align-items:flex-start;gap:10px;
    padding:5px 0;border:none;position:static;background:none;box-shadow:none;
    text-align:right;white-space:normal;
  }
  /* El nowrap de arriba existe para que una tabla NORMAL no tenga filas
     desalineadas (una celda larga estirando la fila entera mientras las
     demás quedan centradas en ese espacio de más — ver el comentario en
     .table). En tarjeta cada campo ya es su propia fila, así que envolver
     un valor largo (ej. la Receta de un producto) solo hace más alta esa
     fila puntual, sin desalinear nada — y evita que el texto se salga del
     ancho de la tarjeta como pasaba antes con nowrap acá. */
  .table td::before{
    content:attr(data-th);font-weight:700;color:var(--ink-soft);
    font-size:.76em;text-transform:uppercase;letter-spacing:.03em;text-align:left;
  }
  .table td:first-child{
    font-weight:700;font-size:1.05em;color:var(--ink);padding-top:0;
  }
  .table td:first-child::before{display:none}
  /* Una celda de tarjeta es, por defecto, una fila flex de UN solo valor
     (etiqueta a la izquierda vía ::before, valor a la derecha) — funciona
     bien para texto plano. Rendimiento de insumos puso un título/número
     grande (<strong>) MÁS una línea de contexto chica (.cell-subtitle)
     dentro de la misma celda, y ese "space-between" las separaba a los dos
     extremos de la fila en vez de apilarlas (encontrado en vivo: el título
     de la tarjeta quedaba partido en dos). Con :has() se detecta esa forma
     específica y la celda pasa a columna — el resto de las tablas, que
     nunca meten un .cell-subtitle, no se ven afectadas. */
  .table td:has(.cell-subtitle){flex-direction:column;align-items:flex-start;gap:2px}
  .table td.num:has(.cell-subtitle){align-items:flex-end}
  .cell-subtitle{font-size:.85em}
  /* Una celda vacía a propósito (ej. "Aviso" sin nada que avisar en
     Rendimiento de insumos) no debería ocupar una fila entera de tarjeta
     solo para mostrar su etiqueta en mayúsculas sin ningún valor al lado —
     acá, a diferencia de la tabla normal, sí se puede sacar la fila entera
     sin desalinear columnas (cada celda ya es independiente). */
  .table td:empty{display:none}
  /* Solo las tablas CON columna de acciones (.table--sticky-actions) separan
     la última celda como fila de botones, sin label propio y con línea
     divisoria — en una tabla de datos común, la última columna es un dato
     más (ej. "Porciones vendidas") y necesita su label como cualquier otra. */
  .table--sticky-actions td:last-child{
    justify-content:flex-end;flex-wrap:wrap;padding-top:10px;margin-top:2px;
    border-top:1px dashed var(--line);
  }
  .table--sticky-actions td:last-child::before{display:none}
}

/* Productos dejó de ser una <table>. Sin la Receta completa (pedido real
   del dueño: "se ve muy grande... la vemos cuando le demos a desglose" —
   ese desglose ya existe y la muestra mejor, con el costo de cada
   insumo) la tabla bajaba a ~1123px de ancho natural — todavía más de lo
   que .wrap deja disponible (tope fijo de 1100px, sin importar cuán
   ancho sea el monitor), así que la columna de acciones fija seguía
   tapando Costo/Ganancia en reposo, el mismo bug de siempre. En vez de
   perseguir el ancho exacto una vez más, se pasa a una grilla de
   tarjetas compactas — pedido explícito del dueño viendo la pantalla:
   "capaz que van dos o tres productos al lado". Sin tabla, sin columna
   fija, sin ese bug estructural.*/
.products-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px;
}
.product-card{
  background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);padding:14px;display:flex;flex-direction:column;gap:10px;
  transition:transform .15s ease,box-shadow .15s ease;
}
/* Mismo levantamiento sutil que ya tienen las tarjetas .stat (Panel,
   Reportes) — sin esto, la grilla nueva de Productos era la única
   superficie tipo tarjeta de toda la app sin ese detalle, se sentía
   menos terminada al lado de las demás. */
.product-card:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
@media (prefers-reduced-motion:reduce){.product-card{transition:none}.product-card:hover{transform:none}}
.product-card.row-inactive{opacity:.6}
/* Misma idea, para una tarjeta simple .card (ej. Solicitudes ya resuelta —
   rechazada o atendida) — atenuada, ya no hace falta actuar sobre ella. */
.card.row-inactive{opacity:.6}
/* Misma idea que .row-voided en una <table> (atenuado + tachado en el
   total) — acá para una venta anulada dentro de la tarjeta de Historial.
   Clase propia y no un alias de .row-inactive: semánticamente distinto,
   igual que ya está documentado para la versión de tabla más abajo. */
.product-card.row-voided{opacity:.6}
.product-card.row-voided .product-card-stats .value{text-decoration:line-through}
.product-card-header strong{font-size:1.05em;color:var(--ink)}
.product-card-subtitle{margin-top:2px;font-size:.85em}
.product-card-stats{display:flex;flex-direction:column;gap:4px;padding-top:8px;border-top:1px dashed var(--line)}
.product-card-stats > div{display:flex;justify-content:space-between;gap:10px;font-size:.9em}
.product-card-stats .label{color:var(--ink-soft);font-weight:700}
.product-card-stats .value{font-weight:700;font-variant-numeric:tabular-nums}
.product-card-stats .value.low-stock{color:var(--danger)}
.product-card-actions{display:flex;flex-wrap:wrap;gap:6px;padding-top:6px;border-top:1px dashed var(--line)}
.product-card-actions .btn{flex:1 1 auto}

/* Placeholders "esqueleto" (Historial, Reportes) mientras llega la
   respuesta del servidor — ver UI.skeletonRows/skeletonCards en ui.js. Un
   brillo que se desliza de izquierda a derecha sobre un bloque del color de
   fondo, para que se lea como "esto está cargando" y no como una tabla
   vacía o rota. Con prefers-reduced-motion se queda quieto (un bloque
   plano) en vez de deslizarse. */
.skeleton{
  border-radius:6px;height:.9em;
  background:linear-gradient(90deg,var(--surface-2) 25%,var(--line) 50%,var(--surface-2) 75%);
  background-size:200% 100%;animation:skeletonShimmer 1.3s ease-in-out infinite;
}
.skeleton-text{width:100%}
.skeleton-text + .skeleton-text{margin-top:6px}
tr.skeleton-row td{padding-top:14px;padding-bottom:14px}
.skeleton-card{cursor:default}
.skeleton-card:hover{transform:none;box-shadow:var(--shadow-sm)}
@keyframes skeletonShimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
@media (prefers-reduced-motion:reduce){.skeleton{animation:none;background:var(--surface-2)}}

/* Antes era una .card más dentro del flujo normal de la página — al confirmar
   una venta, el recibo "aparecía" en algún punto del documento sin que la
   ventana se moviera ahí, así que en la práctica no se veía ninguna
   confirmación. Ahora es un modal real, centrado y por encima de todo. */
.recibo-modal{
  white-space:pre-wrap;position:fixed;inset:0;margin:auto;z-index:1002;
  width:fit-content;max-width:min(420px,calc(100% - 32px));height:fit-content;max-height:80vh;
  overflow-y:auto;
  animation:modalPopIn .18s cubic-bezier(.2,.8,.2,1);
  /* El fondo oscurecedor se pinta con una sombra de spread enorme en vez de
     un ::before con z-index:-1. Con el ::before, el modal creaba su propio
     contexto de apilado (position:fixed + z-index), así que ese -1 no lo
     mandaba detrás del modal sino entre su FONDO y su contenido: el recuadro
     blanco se veía gris translúcido con la página asomándose, mientras el
     texto y los botones encima se veían bien. Confirmado en pantalla. Una
     box-shadow solo pinta por FUERA de la caja, así que oscurece la página
     sin poder teñir el modal. */
  box-shadow:var(--shadow), 0 0 0 100vmax color-mix(in srgb,var(--brown-deep) 45%,transparent);
}
.recibo-modal pre{font-family:inherit;white-space:pre-wrap;background:var(--bg);padding:12px;border-radius:8px}
.recibo-modal-actions{display:flex;gap:10px;margin-top:14px}
.recibo-modal-actions .btn{flex:1}
.recibo-modal h2{text-align:center}
/* Círculo y palomita que se "dibujan" al confirmar la venta — igual que el
   pop-in del modal, un refuerzo visual breve de "esto salió bien", nunca
   más de medio segundo y desactivable con prefers-reduced-motion. */
.recibo-check{display:block;width:52px;height:52px;margin:0 auto 4px}
.recibo-check-circle{
  fill:none;stroke:var(--sage);stroke-width:2.5;
  stroke-dasharray:151;stroke-dashoffset:151;
  animation:reciboCheckCircle .4s cubic-bezier(.65,0,.45,1) .1s forwards;
}
.recibo-check-mark{
  stroke:var(--sage);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:34;stroke-dashoffset:34;
  animation:reciboCheckMark .25s ease-out .45s forwards;
}
@keyframes reciboCheckCircle{to{stroke-dashoffset:0}}
@keyframes reciboCheckMark{to{stroke-dashoffset:0}}
@media (prefers-reduced-motion:reduce){
  .recibo-check-circle,.recibo-check-mark{animation:none;stroke-dashoffset:0}
}

/* Antes TODAS las tarjetas de estadística (hoy, este mes, reconciliación,
   desglose de producto) eran el mismo bloque sólido color crema — sin
   ninguna jerarquía, todo pesaba igual de un vistazo, sea el dato del día
   o un total de referencia. Ahora .stat es la versión PRIMARIA (blanca,
   número en el naranja de marca, borde fino) para el dato que importa
   ahora mismo (Hoy / el día tocado en la gráfica); .stat-quiet es la
   versión secundaria (fondo crema suave, número más chico y en marrón)
   para contexto de fondo (Este mes) — mismo patrón que un dashboard
   financiero real: el número del momento resalta, el de referencia
   acompaña sin competir. */
.stat{
  background:var(--surface);border:var(--bw) solid var(--line);border-radius:10px;
  padding:14px 12px;text-align:center;transition:transform .15s ease,box-shadow .15s ease;
}
.grid-3 .stat:hover,.grid-2 .stat:hover{transform:translateY(-2px);box-shadow:var(--shadow-sm)}
@media (prefers-reduced-motion:reduce){.stat{transition:none}.grid-3 .stat:hover,.grid-2 .stat:hover{transform:none}}
/* A diferencia de .grid-3 (siempre 3 columnas parejas), esta se usa donde el número
   de tarjetas varía (ej. el almacén central agrega "Enviado a carritos" que un carrito
   normal no tiene) — se acomodan solas sin dejar una columna vacía o angosta. */
.reconciliacion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.stat .label{font-size:.85em;color:var(--ink-soft)}
.stat .value{font-size:1.5em;font-weight:700;color:var(--orange)}
.stat.stat-quiet{background:var(--surface-2);border-color:transparent}
.stat.stat-quiet .value{font-size:1.25em;color:var(--ink)}
/* Sin borde a propósito en modo claro (es la versión "de fondo", no debe
   competir con .stat) — pero en modo oscuro --surface-2 y --bg quedan
   demasiado parecidos entre sí para que "sin borde" se lea como "más
   discreta" en vez de "no se nota". Ahí sí lleva el mismo borde que todo
   lo demás. */
:root[data-theme="dark"] .stat.stat-quiet{border-color:var(--line)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .stat.stat-quiet{border-color:var(--line)}
}

/* Gráfica de barras del Panel — SVG a mano (sin librería), un <rect> por día.
   El tooltip nativo (<title>) da el valor exacto al pasar el mouse sin JS
   extra; la barra de hoy se distingue con el acento naranja de la marca. */
.panel-chart-summary{margin-bottom:10px}
.panel-chart-svg{width:100%;height:auto;display:block;overflow:visible}
.panel-chart-bar rect{fill:var(--cream);transition:fill .15s ease,stroke .15s ease;cursor:pointer}
.panel-chart-bar:hover rect{fill:var(--yellow-deep)}
.panel-chart-bar.is-today rect{fill:var(--orange)}
.panel-chart-bar.is-today:hover rect{fill:var(--brown-soft)}
/* Barra seleccionada (la que puso sus cifras arriba): un contorno propio,
   independiente del color de "hoy", para que ambos estados se distingan
   incluso cuando coinciden (hoy seleccionado). */
.panel-chart-bar.is-selected rect{stroke:var(--brown-deep);stroke-width:2}
.panel-chart-bar:focus-visible rect{outline:2px solid var(--brown-deep);outline-offset:1px}
.panel-chart-bar:focus{outline:none}
.panel-chart-day{font-size:9px;fill:var(--ink-soft);text-anchor:middle;font-family:inherit}
.panel-chart-value{font-size:9px;font-weight:700;fill:var(--ink);text-anchor:middle;font-family:inherit;opacity:0;transition:opacity .15s ease}
.panel-chart-bar:hover .panel-chart-value{opacity:1}
@media (prefers-reduced-motion:reduce){.panel-chart-bar rect,.panel-chart-value{transition:none}}

.panel-stats-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}
.panel-stats-header h2{margin:0}

/* Franja de aviso arriba de todo el Panel — mismo criterio que ya usa el
   aviso de WhatsApp (server/services/lowStockAlertService.js): insumo bajo
   en un carrito es urgente de verdad (rojo), cualquier otro insumo bajo es
   solo "prestale atención" (ámbar) — nunca los dos se ven igual de graves. */
.panel-alert-strip{
  cursor:pointer;
  display:flex;align-items:center;gap:10px;border-radius:var(--r);
  padding:10px 14px;font-weight:700;font-size:.92rem;margin-bottom:16px;
  background:var(--amber-bg);color:var(--amber);border:var(--bw) solid var(--amber);
  animation:alert-pulse-amber 2.4s ease-in-out infinite;
}
.panel-alert-strip.is-urgent{
  background:var(--danger-bg);color:var(--danger-on-bg);border-color:var(--danger-on-bg);
  animation:alert-pulse-danger 1.6s ease-in-out infinite;
}
/* Pedido del dueño: que el aviso de stock bajo "resalte más" y llame la
   atención de verdad en vez de ser un cartel quieto más — un halo que
   respira alrededor de la franja, más rápido y más intenso cuando es
   urgente (urgente) que cuando es solo "prestale atención" (otro insumo). */
@keyframes alert-pulse-amber{
  0%,100%{box-shadow:0 0 0 0 rgba(180,130,20,.32)}
  50%{box-shadow:0 0 0 6px rgba(180,130,20,0)}
}
@keyframes alert-pulse-danger{
  0%,100%{box-shadow:0 0 0 0 rgba(197,60,50,.4)}
  50%{box-shadow:0 0 0 7px rgba(197,60,50,0)}
}
@media (prefers-reduced-motion:reduce){.panel-alert-strip,.panel-alert-strip.is-urgent{animation:none}}

/* El "hero": el único número que de verdad hace falta ver primero al
   entrar (ganancia de hoy, o del día tocado en la gráfica). Los demás
   (facturas, total, promedio) quedan como contexto en .panel-mini-row,
   más chicos, sin competir por la misma atención. */
.panel-hero{
  background:linear-gradient(135deg,var(--orange),var(--yellow-deep));color:#fff;
  border-radius:var(--r-lg);padding:14px 18px;margin-bottom:12px;
}
.panel-hero .label{font-size:.78rem;text-transform:uppercase;letter-spacing:.04em;opacity:.92;font-weight:700}
.panel-hero .value{font-family:"Sora",sans-serif;font-size:2.2rem;font-weight:600;margin-top:2px;line-height:1.2}
.panel-hero .sub{font-size:.86rem;opacity:.92;margin-top:4px}
/* auto-fit en vez de un número fijo de columnas: hoy son siempre 2 tarjetas
   (Facturas, Ventas) y quedan una al lado de la otra a partir de ~320px de
   ancho (150px mínimo cada una); si algún día se agrega una tercera, se
   acomoda sola sin tener que tocar este número. */
.panel-mini-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.panel-mini{background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r);padding:10px 12px;text-align:center}
.panel-mini .label{font-size:.72rem;color:var(--ink-soft)}
.panel-mini .value{font-size:1.08rem;font-weight:700;color:var(--ink)}
/* El recuadro naranja pesaba más en la pantalla que la única cifra que
   tiene adentro, sobre todo en celular con el padding pensado para
   escritorio (reportado en vivo: "abarca toda la pantalla cuando su
   contenido es poco"). Menos padding y una cifra un toque más chica —
   sigue siendo lo primero que se lee, solo que sin tanto aire alrededor. */
@media (max-width:480px){
  .panel-hero{padding:12px 16px}
  .panel-hero .value{font-size:1.7rem}
  .panel-mini-row{gap:8px}
  .panel-mini{padding:8px 10px}
}

.card-header-row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:.6em;flex-wrap:wrap}
/* Clientes es la primera pantalla que mete un <input type="search"> DENTRO
   de un .card-header-row — en celular angosto (~375px) el buscador y
   "Exportar CSV" ya no entraban lado a lado sin apretarse (el buscador
   cortaba su propio placeholder). flex-wrap de arriba ya los apila solo;
   esto además le da a un search-input dentro de este contenedor su propio
   ancho completo cuando apila, en vez de quedar angosto al lado de nada. */
.card-header-row .search-input{flex:1 1 200px;margin-bottom:0}
.card-header-row h2{margin:0}

/* Barra fija con el total corriendo, arriba de la barra de pestañas del
   carrito en celular — Vasos+Adicionales+Recibo se apilan ahí, así que sin
   esto el total queda fuera de vista mientras se arma la venta. Oculta por
   default (incluido escritorio); #cart-app la muestra solo bajo los 820px
   y solo con productos en el carrito (ver la regla junto al resto de ese
   media query, y pos.js para el hidden/texto). Tocarla baja al Recibo. */
.mobile-cart-bar{
  display:none;position:fixed;left:10px;right:10px;
  bottom:calc(70px + env(safe-area-inset-bottom));z-index:25;
  background:var(--brown-deep);color:#fff;border:none;border-radius:12px;
  padding:12px 16px;align-items:center;justify-content:space-between;gap:10px;
  box-shadow:0 4px 16px rgba(0,0,0,.25);font:inherit;cursor:pointer;
  animation:mobileCartBarIn .2s ease;
}
.mobile-cart-bar #pos-mobile-cart-summary{font-weight:700;font-size:1.05rem}
.mobile-cart-bar-cta{display:flex;align-items:center;gap:4px;font-size:.85rem;color:var(--cream);opacity:.9}
.mobile-cart-bar-cta svg{width:12px;height:12px}
@keyframes mobileCartBarIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){.mobile-cart-bar{animation:none}}

.panel-shortcuts{display:flex;gap:10px;flex-wrap:wrap;margin-top:24px}
.low-stock-item{display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px dashed var(--line);font-size:.92em}
.low-stock-item:last-child{border-bottom:none}

.checklist{display:flex;flex-direction:column;gap:2px;margin-bottom:14px}
.checklist label{
  display:flex;align-items:center;gap:10px;padding:12px 10px;border-radius:8px;font-weight:600;
  min-height:44px;
}
.checklist label:hover{background:var(--bg)}
/* La casilla nativa por defecto queda diminuta (13px) al lado de los demás
   controles de la app (círculos +/- de 56px, botones grandes) — se agranda
   y se le da el color de marca en vez de dejarla con el azul de fábrica del
   navegador. El renglón completo ya es clickeable (todo vive dentro del
   <label>), pero la casilla en sí también tenía que notarse y ser fácil de
   tocar por su cuenta. */
.checklist input{width:20px;height:20px;accent-color:var(--orange);flex:none}
.checklist .group-label{
  font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-soft);margin:10px 0 2px;padding:0 10px;
}
.checklist .group-label:first-child{margin-top:0}
/* "Toppings" repite los mismos nombres que Insumos (cada topping se hace de
   su insumo homónimo) — un desplegable cerrado por defecto evita que esa
   lista redundante compita con lo que sí suele hacer falta marcar, sobre
   todo en un celular chico donde ya había que scrollear de más. Mismo
   patrón de flecha que .report-section (Reportes), reusado acá. */
.checklist-more{margin-top:10px;border-top:1px solid var(--line);padding-top:6px}
.checklist-more > summary{
  cursor:pointer;list-style:none;padding:8px 10px;
  display:flex;align-items:center;gap:10px;
  font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-soft);
}
.checklist-more > summary::-webkit-details-marker{display:none}
.checklist-more > summary::after{
  content:'';flex:0 0 auto;width:7px;height:7px;margin-left:auto;
  border-right:2px solid var(--ink-soft);border-bottom:2px solid var(--ink-soft);
  transform:rotate(45deg);transition:transform .18s ease;
}
.checklist-more[open] > summary::after{transform:rotate(-135deg)}
@media (prefers-reduced-motion:reduce){.checklist-more > summary::after{transition:none}}
/* La lista de "Solicitar reposición" ya tenía el dato de qué insumo está
   bajo (mismo `low` que ya pinta rojo en Mi inventario) pero no lo usaba —
   el carrito tenía que ir y volver entre las dos pantallas para saber qué
   marcar. Fondo suave + etiqueta, no solo texto rojo, para que se note
   incluso antes de leer el nombre. */
.checklist label.low-stock-row{background:var(--danger-bg)}
.checklist label.low-stock-row:hover{background:var(--danger-bg-hover)}
.low-stock-tag{
  background:var(--danger);color:#fff;font-size:.7em;font-weight:700;
  padding:2px 7px;border-radius:999px;text-transform:uppercase;letter-spacing:.03em;
}
/* Mismo highlight que el checklist de "Solicitar reposición", aplicado acá a
   una fila de tabla normal (Reportes → Rendimiento de insumos) para marcar
   qué insumo ya se agotó en un punto de venta. */
.table tr.low-stock-row td{background:var(--danger-bg)}
/* Aviso de "no cuadra" en Rendimiento de insumos — a propósito NO es rojo
   como .low-stock-tag: "agotado" es un hecho (llegó a 0), esto es una señal
   más suave de "revisar" que puede darse incluso sin estar agotado. Texto
   normal (no uppercase forzado) porque acá el mensaje es una frase corta,
   no una sola palabra — todo en mayúsculas se leía mal. */
.warn-tag{
  display:inline-block;background:var(--amber-bg);color:var(--amber);font-size:.82em;font-weight:700;
  padding:3px 9px;border-radius:8px;border:1px solid var(--amber);
}
/* Fila con tinte SOLO cuando hay un aviso real que revisar (ver warn-tag)
   — reservado a propósito para ese único caso, no para "agotado" (que ya
   tiene su propia etiqueta abajo y es una condición normal, no un
   problema — pintar de rosado cada fila agotada le restaba peso justo a
   la fila que sí hace falta que salte a la vista). */
.table tr.warn-row td{background:var(--amber-bg)}
/* Fila destacada como BUENA noticia (ej. Analítica: el mejor día/producto)
   — --sage/--sage-bg (verde) ya existían como tokens semánticos reservados
   pero ningún componente los usaba todavía. A propósito NO se reutiliza
   .low-stock-row (rojo) para esto: ese color ya significa "algo anda mal"
   en el resto de la app, usarlo también para "esto vende más" mandaría la
   señal contraria. */
.table tr.best-row td{background:var(--sage-bg)}
.best-tag{
  display:inline-block;background:var(--sage-bg);color:var(--sage);font-size:.7em;font-weight:700;
  padding:2px 7px;border-radius:999px;text-transform:uppercase;letter-spacing:.03em;
}
/* "Agotado" en gris neutro, no en el rojo de alarma de .low-stock-tag —
   es información (se acabó, puede ser exactamente lo esperado), no un
   aviso de que algo salió mal. */
.tag-neutral{
  display:inline-block;background:var(--surface-2);color:var(--ink-soft);font-size:.7em;font-weight:700;
  padding:2px 7px;border-radius:999px;text-transform:uppercase;letter-spacing:.03em;
}
/* Fila que abre un desglose al tocarla (Rendimiento de insumos) — pedido
   explícito del dueño: los dos números resumen no alcanzaban, necesitaba
   poder verificar de dónde salen. Sin botón aparte (ya se le había sacado
   una columna entera por verse recargado) — la fila entera es el control,
   con una pista de texto chica para que se note que hay más. */
.table tr.row-clickable{cursor:pointer;transition:background-color .12s ease}
.table tr.row-clickable:hover td,.table tr.row-clickable:focus-visible td{background:var(--surface-2)}
.table tr.row-clickable:focus-visible{outline:2px solid var(--brown);outline-offset:-2px}
.row-clickable-hint{color:var(--orange);font-weight:700}

.receta-builder{display:flex;flex-direction:column;gap:6px}
.receta-row{display:flex;gap:8px;align-items:center}
/* min-width:0: por defecto un flex item no encoge más allá del ancho de su
   propio contenido (un <select> con una opción larga, ej. "Leche condensada
   (lata)", empuja toda la fila a desbordar en vez de encogerse) — con esto sí
   puede achicarse y el texto se trunca, en vez de generar scroll horizontal
   para llegar al botón "Quitar" en una pantalla angosta. */
.receta-row select{flex:1;min-width:0}
.receta-row input{width:100px;flex:none}
.receta-row button{flex:none}
/* En el modal angosto de celular (max-width:360px, ~316px de contenido con
   padding) el <select> de insumo se achicaba tanto que truncaba a "Vaso 1",
   "Sorbet", "Leche c" — imposible saber cuál insumo es sin abrir el
   desplegable. Se apila: el select se lleva su propia fila entera (donde sí
   entra el nombre completo o casi), cantidad + Quitar comparten la de abajo. */
@media (max-width:600px){
  .receta-row{flex-wrap:wrap}
  .receta-row select{flex:1 1 100%}
  .receta-row input{flex:1}
}

.low-stock{color:var(--danger);font-weight:700}
/* Chips de stock (Solicitudes → "Stock actual ahí") — antes era una oración
   con comas que, con varios insumos, se leía como un bloque único de texto
   ("se mezcla todo", pedido real desde el celular). Cada insumo es ahora su
   propia pastilla con borde — la separación es la FORMA del chip, no un
   signo de puntuación en medio de una oración larga. */
.stock-chip-list{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}
.stock-chip{
  background:var(--surface);border:1px solid var(--line);border-radius:999px;
  padding:3px 10px;font-size:.85em;white-space:nowrap;
}
.stock-chip.low-stock{background:var(--danger-bg);border-color:#f3cdca}
.stock-chip.muted{color:var(--ink-soft);font-weight:400}
/* Aviso genérico chico dentro de una tarjeta — "esto ya pasó, tomalo en
   cuenta antes de repetir la acción" (ej. Solicitudes: una transferencia ya
   en camino). Mismo lenguaje ámbar que el resto de avisos "prestale
   atención, no es urgente" (panel-alert-strip, warn-tag). */
.info-note{
  background:var(--amber-bg);color:var(--amber);border:1px solid var(--amber);
  border-radius:var(--r);padding:8px 12px;font-size:.88em;margin:8px 0;
}
/* Aviso de reconciliación (Ubicaciones > Ver detalle) — antes usaba un
   emoji "⚠" suelto, inconsistente con el resto de la app (íconos SVG a
   mano en currentColor). Mismo triángulo de alerta, ahora vectorial. */
.recon-warning{display:flex;align-items:flex-start;gap:6px;font-size:.9em}
.recon-warning svg{width:14px;height:14px;flex:none;margin-top:.15em}

.threshold-row{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;
  background:var(--surface-2);border-radius:var(--r);padding:10px 14px;margin-bottom:18px;
}
.row-secondary td{color:var(--ink-soft);font-style:italic}
.row-voided td{color:var(--ink-soft);opacity:.6}
.row-voided td.num{text-decoration:line-through}
/* Mismo atenuado que .row-voided (venta anulada), para un insumo/producto
   desactivado — semánticamente distinto (no es un error, es "no ofrecido
   ahora mismo"), por eso es su propia clase y no un alias de esa. */
.row-inactive td{color:var(--ink-soft);opacity:.6}
.badge{
  display:inline-block;padding:2px 9px;border-radius:999px;font-size:.78em;font-weight:700;
}
.badge-voided{background:var(--danger-bg);color:var(--danger)}
.badge-ok{background:var(--cream-2);color:var(--brown)}
.badge-muted{background:var(--surface-2);color:var(--ink-soft)}
.badge-warn{background:var(--amber-bg);color:var(--amber)}
.badge-sage{background:var(--sage-bg);color:var(--sage)}

.login-screen{
  min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;
  padding:20px;
  /* Manchas suaves de marca (amarillo arriba-izq, naranja abajo-der) sobre el
     fondo de papel — es lo primero que ve cualquiera (dueño o carrito), varias
     veces al día, así que vale la pena que no sea un gris/paper plano. */
  background:
    radial-gradient(ellipse 520px 420px at 12% -8%, color-mix(in srgb,var(--yellow) 22%,transparent), transparent 60%),
    radial-gradient(ellipse 480px 400px at 108% 108%, rgba(240,78,35,.10), transparent 60%),
    var(--bg);
}
@keyframes loginBoxIn{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}
.login-box{
  background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow);padding:32px;width:min(100%,380px);
  animation:loginBoxIn .3s cubic-bezier(.2,.8,.2,1);
}
@media (prefers-reduced-motion:reduce){.login-box{animation:none}}
.login-box h1{font-size:1.3rem;text-align:center;margin-bottom:20px}
/* El asistente de primer uso reusa .login-box (mismo marco/sombra/fondo que
   el login) pero necesita más ancho — tres grupos de campos, no un solo
   PIN/contraseña — y sus h2 son títulos de sección, no algo para centrar. */
.setup-box{width:min(100%,560px);text-align:left}
.setup-box h1{text-align:center}
/* Décimoséptima vuelta — pedido explícito: la pantalla de "falta base de
   datos" (lo primero que ve alguien instalando Arche de cero) también
   lleva la marca — mismo logo monocromo del pie del login — y un ícono
   animado en CSS puro (sin JS: son 3 barras/discos apilados, como una
   base de datos armándose) para que no se sienta un formulario pelado. */
#db-setup-screen .setup-mark{
  width:96px;aspect-ratio:791/120;margin:0 auto 22px;background-color:var(--ink-soft);opacity:.8;
  -webkit-mask:url(../img/brand/arche-wordmark.png) center/contain no-repeat;
  mask:url(../img/brand/arche-wordmark.png) center/contain no-repeat;
}
.setup-db-icon{display:flex;flex-direction:column;align-items:center;gap:5px;width:64px;margin:0 auto 20px}
.setup-db-icon i{
  display:block;width:100%;height:11px;border-radius:50%;
  border:2px solid var(--line-strong);background:var(--surface-2);
  animation:setup-db-pulse 1.8s ease-in-out infinite;
}
.setup-db-icon i:nth-child(2){animation-delay:.2s}
.setup-db-icon i:nth-child(3){animation-delay:.4s}
@keyframes setup-db-pulse{0%,100%{opacity:.45;transform:scaleX(.86)}50%{opacity:1;transform:scaleX(1)}}
@media (prefers-reduced-motion:reduce){.setup-db-icon i{animation:none;opacity:.85}}
.btn-spinner{
  display:inline-block;width:15px;height:15px;margin-right:8px;vertical-align:-3px;
  border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.7;
  animation:btn-spin .7s linear infinite;
}
@keyframes btn-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.btn-spinner{animation:none;opacity:.4}}
.field-group{margin-bottom:20px;padding-bottom:18px;border-bottom:1px dashed var(--line)}
.field-group:last-of-type{border-bottom:none;padding-bottom:0;margin-bottom:16px}
.field-group h2{font-size:1rem;margin:0 0 12px}
.btn-block{display:block;width:100%;margin-bottom:10px}

.theme-switch{display:inline-flex;gap:4px;background:var(--bg);border:var(--bw) solid var(--line);border-radius:999px;padding:4px}
.theme-switch-btn{
  font:inherit;font-weight:700;font-size:.85em;padding:7px 14px;border-radius:999px;
  border:none;background:transparent;color:var(--ink-soft);cursor:pointer;min-height:36px;
}
.theme-switch-btn.is-active{background:var(--surface);color:var(--ink);box-shadow:var(--shadow-sm)}
.login-form .field{margin-bottom:14px}
/* Estado de conexión del carrito — visible en cualquier pantalla suya (va
   junto a la marca en el sidebar, no solo en "Nueva venta"), porque vender
   sin conexión pasa cambiando de pantalla igual que cualquier otro día. */
.offline-banner{
  font-size:.78rem;font-weight:700;text-align:center;padding:7px 10px;
  border-radius:8px;margin:0 0 10px;
}
.offline-banner.is-offline{background:var(--danger);color:#fff}
.offline-banner.is-pending{background:var(--yellow);color:var(--brown-deep)}
.offline-banner.is-syncing{background:var(--cream-2);color:var(--brown)}
/* Nombre del empleado logueado (desde v9.53) — vive en .app-content, NO en
   el sidebar: probado en vivo a 375px de ancho (un teléfono real, no los
   ~529px del panel de pruebas) y metido junto a la marca + Ayuda/Salir en
   esa barra ya angosta, el texto se envolvía en varias líneas y rompía el
   header. Acá tiene su propia fila completa, sin competir por espacio con
   ningún botón — y en escritorio (sidebar en columna) simplemente aparece
   como una línea más arriba del contenido, sin necesitar una regla aparte. */
.employee-banner{
  width:min(100% - 32px, 1320px);margin-inline:auto;
  font-size:.82rem;font-weight:600;color:var(--ink-soft);
  padding:10px 0 0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.stat-line{font-size:1.3rem;font-weight:700;color:var(--ink)}
.stat-line.low-stock{color:var(--danger)}

/* ── Toasts ── */
.toast-host{
  position:fixed;top:16px;right:16px;z-index:1000;
  display:flex;flex-direction:column;gap:8px;max-width:320px;
}
.toast{
  background:var(--brown-deep);color:var(--cream);border-radius:10px;padding:12px 16px;
  box-shadow:0 6px 18px rgba(0,0,0,.25);opacity:0;transform:translateY(-8px);
  transition:opacity .2s var(--ease,ease),transform .2s var(--ease,ease);font-weight:600;
}
/* En celular, top:16px cae encima de la barra de marca sticky (que ya es
   naranja/marrón) — el toast se ve pegado al header en vez de flotar como
   notificación propia. Abajo, además, es el patrón más común en apps
   móviles (Android Snackbar). Se corre por encima de la barra de pestañas
   del carrito cuando esa vista está activa, para no taparla. */
@media (max-width:820px){
  .toast-host{top:auto;bottom:16px;left:16px;right:16px;max-width:none}
  .toast{transform:translateY(8px)}
  .toast.show{transform:translateY(0)}
  body:has(#cart-app:not([hidden])) .toast-host,body:has(#almacen-app:not([hidden])) .toast-host{
    bottom:calc(76px + 12px + env(safe-area-inset-bottom));
  }
}
.toast.show{opacity:1;transform:translateY(0)}
.toast-error{background:#7a1f1f}
/* Aviso de llegada (turno) — pedido del dueño: "con un resaltado en verde" */
/* Mismo par sage/sage-bg que ya usan los badges "Confirmada"/"Cerrado por
   el empleado" — encontrado en la auditoría del 22 sept: la primera versión
   ponía texto casi negro fijo sobre var(--sage), que en modo claro es un
   verde medio (#3E7A52) y ahí ese texto no contrastaba bien. */
.toast-success{background:var(--sage-bg);color:var(--sage);font-weight:800}

/* ── Modal de confirmación ── */
@keyframes modalFadeIn{from{opacity:0}to{opacity:1}}
@keyframes modalFadeOut{from{opacity:1}to{opacity:0}}
@keyframes modalPopIn{from{opacity:0;transform:scale(.96) translateY(6px)}to{opacity:1;transform:scale(1) translateY(0)}}
@keyframes modalPopOut{from{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.96) translateY(6px)}}
.modal-overlay{
  position:fixed;inset:0;background:color-mix(in srgb,var(--brown-deep) 45%,transparent);z-index:1001;
  display:flex;align-items:center;justify-content:center;padding:20px;
  animation:modalFadeIn .15s ease;
}
/* Entraba con fade+pop pero se sacaba del DOM de un tirón (sin animación) —
   .closing la agrega justo antes de overlay.remove() (ver closeOverlay() en
   ui.js), para que cerrar se sienta tan cuidado como abrir. */
.modal-overlay.closing{animation:modalFadeOut .15s ease forwards}
.modal-box{
  background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r-lg);
  box-shadow:0 8px 30px color-mix(in srgb,var(--brown-deep) 18%,transparent);padding:22px;max-width:360px;width:100%;
  animation:modalPopIn .18s cubic-bezier(.2,.8,.2,1);
}
.modal-overlay.closing .modal-box{animation:modalPopOut .15s cubic-bezier(.4,0,1,1) forwards}
.modal-box p{margin-bottom:18px;font-weight:600}
.modal-actions{display:flex;gap:10px;justify-content:flex-end}
.prompt-input{width:100%;margin-bottom:8px;resize:vertical}
.prompt-error{color:var(--danger);font-size:.85em;margin:0 0 10px}

/* Modal ancho para desgloses (tabla + gráfica) — Panel por ubicación, costo de producto */
.modal-box-wide{max-width:640px;max-height:85vh;display:flex;flex-direction:column;padding:0}
.modal-box-header{
  display:flex;align-items:center;justify-content:space-between;
  padding:18px 22px;border-bottom:1px solid var(--line);flex:0 0 auto;
}
.modal-box-header h2{margin:0}
.modal-box-close{
  background:transparent;border:none;font-size:1.5rem;line-height:1;color:var(--ink-soft);
  cursor:pointer;padding:0 4px;
}
.modal-box-close:hover{color:var(--ink)}
/* overscroll-behavior:contain por el mismo motivo que #owner-app .sidebar-nav
   (ver ese comentario) — este cuerpo también scrollea dentro de un overlay
   que ahora bloquea el body de la página (ui.js openOverlay/lockBodyScroll),
   mismo riesgo de que iOS trabe el scroll al llegar al final. */
.modal-box-body{padding:18px 22px 22px;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}

/* Fila clicable dentro de una tabla (ej. "por ubicación" en el Panel) —
   affordance visual de que se puede entrar al detalle. */
.table tr.row-clickable{cursor:pointer}
.table tr.row-clickable:hover td{background:var(--surface-2)}

/* Barras de desglose de costo (composición de un producto) */
.cost-bars{display:flex;flex-direction:column;gap:10px;margin:16px 0}
.cost-bar-row{display:grid;grid-template-columns:140px 1fr auto;align-items:center;gap:10px;font-size:.9em}
.cost-bar-track{background:var(--surface-2);border-radius:6px;height:18px;overflow:hidden}
.cost-bar-fill{height:100%;background:var(--orange);border-radius:6px 0 0 6px}
.cost-bar-fill.is-profit{background:#2f8f4e}
.cost-bar-value{font-variant-numeric:tabular-nums;font-weight:700;text-align:right;min-width:70px}

.breakdown-totals{display:flex;justify-content:space-between;gap:16px;margin-top:14px;padding-top:14px;border-top:1px solid var(--line);flex-wrap:wrap}
.breakdown-totals .stat{flex:1;min-width:100px}

/* ── Impresión (Ctrl+P desde Reportes/Historial/Panel) ──────────────────
   No existía ningún ajuste de impresión en toda la app (el único que había
   era el de print.js, para la ventana aparte del recibo) — imprimir
   cualquier pantalla normal salía con el sidebar marrón, botones y demás
   controles de pantalla, sin ningún sentido en papel. Oculta el chrome de
   navegación/acción y deja que el contenido (sobre todo tablas) use toda
   la hoja. */
/* Elementos que solo tienen sentido en papel (ej. el resumen de filtro de
   Reportes, en texto plano en vez del <input type="date"> que no se lee
   bien impreso) — ocultos en pantalla, visibles solo dentro de @media print. */
.print-only{display:none}
@media print{
  .sidebar,.sidebar-backdrop,.sidebar-toggle,.toast-host,.modal-overlay,
  .btn,.nav-icon,.recibo-modal,.no-print{display:none!important}
  .print-only{display:block}
  body{background:#fff}
  .app-shell{display:block}
  .app-content{padding-bottom:0}
  .wrap{width:100%;max-width:none;margin:0;padding:0}
  .card,.card-quiet{box-shadow:none;border:1px solid #ccc;break-inside:avoid}
  /* .product-card (Insumos/Ubicaciones/Historial/Productos desde la fase 3
     del rediseño) es su propia clase, no .card/.card-quiet — sin esto se
     imprimía con su sombra normal de pantalla (gasta tóner sin necesidad,
     se ve como una mancha gris en papel) y sus botones de acción, que ya
     ocultó la regla de .btn de arriba, se llevaban su espacio en blanco. */
  .product-card{box-shadow:none;border:1px solid #ccc;break-inside:avoid}
  .product-card-actions{display:none}
  /* .table-scroll recorta con scroll horizontal en pantalla — en papel eso
     simplemente no se ve, así que en print se deja fluir (con letra más
     chica es más fácil que la tabla completa entre en el ancho de la hoja). */
  .table-scroll{overflow:visible}
  .table{font-size:.85em}
  .table th,.table td{border-bottom-color:#ccc}
  /* .card ya pide break-inside:avoid, pero una tabla larga (Reportes "Por
     día" con un mes completo, por ejemplo) no entra entera en una hoja —
     el navegador rompe la tarjeta igual, y sin esto lo hace a mitad de una
     fila. Con la fila protegida, corta entre filas en su lugar; el
     encabezado se repite solo (comportamiento nativo de <thead> en tablas
     HTML reales, esto solo lo deja explícito). */
  .table tr{break-inside:avoid}
  .table thead{display:table-header-group}
  h1{margin-bottom:4px}
  #reporte-print-meta{color:#555;margin-top:0;margin-bottom:18px;font-size:.9em}
}

#existencias-card{scroll-margin-top:112px}

/* Pestañas dentro de una pantalla (Historial, Tendencias…): en celular se
   deslizan de lado en vez de partirse en dos filas. */
.subtabs{
  display:flex;gap:4px;margin:0 0 16px;border-bottom:1px solid var(--line);
  overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.subtabs::-webkit-scrollbar{display:none}
.subtab{
  font:inherit;font-weight:700;background:none;border:0;border-bottom:3px solid transparent;
  padding:10px 14px;margin-bottom:-1px;cursor:pointer;color:var(--ink-soft);
  white-space:nowrap;flex:0 0 auto;
}
.subtab:hover{color:var(--ink)}
.subtab.active{color:var(--ink);border-bottom-color:var(--yellow)}
.subtab:focus-visible{outline:2px solid var(--orange);outline-offset:2px}

/* Botón de "aviso en N" dentro de una celda de Existencias */
.aviso-btn{
  display:block;margin:0;padding:0;background:none;border:0;cursor:pointer;
  font:inherit;font-size:.78em;color:var(--ink-soft);text-decoration:underline dotted;
}
.aviso-btn:hover{color:var(--ink)}
.aviso-btn:focus-visible{outline:2px solid var(--orange);outline-offset:2px}

/* ═══ Tendencias ═══ */
.chips{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px;-webkit-overflow-scrolling:touch}
.chips::-webkit-scrollbar{display:none}
.chip{
  flex:0 0 auto;font:inherit;font-weight:700;font-size:.88rem;cursor:pointer;
  padding:9px 14px;border-radius:999px;border:var(--bw) solid var(--line);
  background:var(--surface);color:var(--ink);min-height:40px;
}
.chip:hover{background:var(--surface-2)}
.chip.active{background:var(--yellow);border-color:var(--yellow-deep);color:var(--brown-deep)}
.chip:focus-visible,.seg:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.trend-filters{display:flex;flex-direction:column;gap:12px}
.trend-range{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end}
.trend-location{max-width:none}
.trend-location select{max-width:320px}
.trend-summary{margin:0}
[aria-busy="true"] #trend-body{opacity:.55;transition:opacity .15s}

.kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px}
@media (max-width:820px){.kpi-grid{grid-template-columns:repeat(2,1fr)}}
.kpi{background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r);padding:14px 16px;box-shadow:var(--shadow-sm)}
.kpi .label{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-soft)}
.kpi .value{font-size:clamp(1.05rem,4.6vw,1.45rem);font-weight:800;margin:4px 0 2px;font-variant-numeric:tabular-nums;white-space:nowrap}
.kpi-delta{min-height:1.4em}
.delta{
  display:inline-block;font-size:.78rem;font-weight:700;padding:1px 8px;border-radius:999px;
  background:var(--surface-2);color:var(--ink-soft);white-space:nowrap;
}
.delta.is-up{background:var(--sage-bg);color:var(--sage)}
.delta.is-down{background:var(--danger-bg);color:var(--danger-on-bg)}
.delta.is-new{background:var(--amber-bg);color:var(--amber)}

/* Barras verticales (semanas, días de la semana) — HTML/CSS, sin librería */
.vbars{display:flex;align-items:stretch;gap:6px;height:190px}
.vbar{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:4px}
.vbar-val{font-size:.7rem;font-weight:700;color:var(--ink-soft);height:1em;line-height:1;font-variant-numeric:tabular-nums;white-space:nowrap}
.vbar-track{flex:1;width:100%;display:flex;align-items:flex-end;justify-content:center}
.vbar-fill{display:block;width:78%;max-width:44px;min-height:0;background:var(--yellow-deep);border-radius:5px 5px 2px 2px;transition:height .25s}
.vbar-fill.is-best{background:var(--sage)}
.vbar-fill.is-worst{background:var(--amber)}
.vbar-label{font-size:.72rem;color:var(--ink-soft);text-align:center;line-height:1.1;display:flex;flex-direction:column;align-items:center}
.vbar-label b{font-size:.8rem;color:var(--ink)}
.vbar-label small{font-size:.66rem;text-transform:lowercase}
@media (prefers-reduced-motion:reduce){.vbar-fill{transition:none}}

.hl-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}
.hl{background:var(--surface-2);border-radius:var(--r);padding:12px 14px}
.hl .label{font-size:.76rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-soft)}
.hl-value{font-size:1.15rem;font-weight:800;margin:2px 0;overflow-wrap:anywhere}

/* Listas con barra (ranking de carritos, vasos, adicionales) */
.rank-row{padding:10px 0;border-bottom:1px solid var(--line)}
.rank-row:last-child{border-bottom:0}
.rank-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.rank-pos{
  flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
  background:var(--surface-2);font-weight:800;font-size:.8rem;
}
.rank-row:first-child .rank-pos{background:var(--yellow);color:var(--brown-deep)}
.rank-name{flex:1 1 140px;min-width:0;overflow-wrap:anywhere}
.rank-value{font-weight:800;font-variant-numeric:tabular-nums}
.rank-bar{height:8px;border-radius:999px;background:var(--surface-2);margin:8px 0 6px;overflow:hidden}
.rank-bar span{display:block;height:100%;background:var(--yellow-deep);border-radius:999px}
.rank-row:first-child .rank-bar span{background:var(--orange)}
.rank-meta{font-size:.82rem}

/* Tablas de calor: día × hora, carrito × día, semana × carrito */
.heat,.matrix{border-collapse:separate;border-spacing:3px;width:100%;font-variant-numeric:tabular-nums}
.heat th,.matrix th{font-size:.74rem;font-weight:700;color:var(--ink-soft);padding:4px 6px;white-space:nowrap}
.heat thead th,.matrix thead th{text-align:center}
.heat tbody th,.matrix tbody th{text-align:left;position:sticky;left:0;background:var(--surface);z-index:1}
.matrix tbody th{max-width:120px;overflow:hidden;text-overflow:ellipsis}
.heat td,.matrix td{
  text-align:center;border-radius:6px;min-width:38px;height:34px;padding:0 4px;
  font-size:.78rem;background:var(--surface-2);color:var(--ink);
}
.heat td.is-best,.matrix td.is-best{font-weight:800;box-shadow:inset 0 0 0 2px var(--sage)}
.matrix td.is-worst{opacity:.6;font-style:italic}
.matrix td.muted{background:transparent}
.cell-worst-demo{opacity:.6;font-style:italic}
.matrix-notes{margin:12px 0 0;padding-left:1.1em;display:flex;flex-direction:column;gap:6px;font-size:.9rem}

/* Selector segmentado (Más vendidos / Menos vendidos) */
.segmented{display:inline-flex;border:var(--bw) solid var(--line);border-radius:999px;overflow:hidden;background:var(--surface)}
.seg{font:inherit;font-weight:700;font-size:.84rem;background:none;border:0;padding:8px 14px;cursor:pointer;color:var(--ink-soft);min-height:38px}
.seg.active{background:var(--yellow);color:var(--brown-deep)}
@media (max-width:520px){
  .vbars{height:160px;gap:4px}
  .card-header-row{flex-wrap:wrap;gap:10px}
}
@media (max-width:520px){
  .heat,.matrix{border-spacing:2px}
  .heat td,.matrix td{min-width:0;padding:0 1px;font-size:.7rem;height:32px}
  .heat th,.matrix th{padding:4px 2px;font-size:.68rem}
  .matrix tbody th{max-width:76px}
  .heat tbody th{max-width:64px}
}
@media (max-width:520px){
  .matrix thead th{white-space:normal;line-height:1.1;vertical-align:bottom}
  .matrix tbody th{max-width:none;overflow:visible;text-overflow:clip}
}

/* Título de una sección que en pantalla ya dice su pestaña — solo se ve al imprimir */
.print-heading{display:none}
@media print{
  .print-heading{display:block}
  .subtabs{display:none !important}
  [data-subpanel][hidden]{display:block !important}
}

/* Campos de un formulario en dos columnas (una en celular) */
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 14px;align-items:end}
.field-grid .field:last-child:nth-child(odd){grid-column:1 / -1}
@media (max-width:520px){.field-grid{grid-template-columns:1fr}}

/* ═══ Existencias: una tarjeta por insumo, una fila por ubicación ═══ */
.stock-toolbar{display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
.stock-toolbar .search-input{flex:1 1 220px;max-width:340px;margin:0}
.check-inline{display:inline-flex;align-items:center;gap:8px;font-weight:600;cursor:pointer;min-height:40px}
.stock-summary{margin:0 0 14px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pill{display:inline-block;font-size:.78rem;font-weight:700;padding:3px 10px;border-radius:999px;white-space:nowrap}
.pill-danger{background:var(--danger-bg);color:var(--danger-on-bg)}
.pill-ok{background:var(--sage-bg);color:var(--sage)}
.stock-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:14px}
.stock-card{background:var(--surface);border:var(--bw) solid var(--line);border-radius:var(--r);padding:14px 16px}
.stock-card.has-low{border-color:var(--danger-on-bg)}
.stock-card-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:6px}
.stock-card-head h3{margin:0;font-size:1.05rem}
.stock-card-head .pill{margin-left:auto}
.stock-rows{list-style:none;margin:0;padding:0}
.stock-row{
  display:grid;grid-template-columns:1fr auto;grid-template-areas:"loc val" "bar bar" "aviso aviso";
  gap:4px 10px;padding:9px 0;border-top:1px solid var(--line);align-items:baseline;
}
.stock-loc{grid-area:loc;font-size:.88rem;color:var(--ink-soft);font-weight:700;overflow-wrap:anywhere}
.stock-val{grid-area:val;font-size:1.05rem;font-variant-numeric:tabular-nums}
.stock-bar{grid-area:bar;height:7px;border-radius:999px;background:var(--surface-2);overflow:hidden;align-self:center}
.stock-bar span{display:block;height:100%;background:var(--sage);border-radius:999px}
.stock-row .aviso-btn{grid-area:aviso;justify-self:start;text-align:left}
.stock-none{margin:6px 0 0;font-size:.8rem;border-top:1px solid var(--line);padding-top:8px}
.stock-row.is-low .stock-val{color:var(--danger-on-bg)}
.stock-row.is-low .stock-bar span{background:var(--danger)}
.stock-row.is-empty{grid-template-areas:"loc val";opacity:.7}
.field-grid .field input,.field-grid .field select{width:100%;min-width:0}
/* Venta por mayor: en anchos medianos (pantalla dividida, tablet) apilar antes */
@media (max-width:1000px){[data-view="venta"] .grid-2{grid-template-columns:minmax(0,1fr)}}

/* Retoques de la revisión final */
.cart-totals{margin-bottom:14px}
#tabla-empleados td select{min-width:0;max-width:100%;flex:1 1 0}

/* ═══ Shaker: Menú (dueño) ═══ */
.field-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
.field-grid .f{max-width:none}
.menu-toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.menu-toolbar .search-input{flex:1 1 220px;margin-bottom:0}
.menu-toolbar select{height:38px;max-width:260px}
.menu-cost-preview{margin-top:10px;font-size:.88em;font-weight:700;color:var(--ink-soft)}
.badge-warn{white-space:nowrap}
.cat-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px dashed var(--line);flex-wrap:wrap}
.cat-row.is-child{padding-left:32px}
.cat-row-main{display:flex;align-items:center;gap:12px;min-width:0}
.cat-row-actions{display:flex;gap:6px;flex-wrap:wrap}
.cat-thumb{width:44px;height:44px;border-radius:10px;object-fit:cover;flex:none;background:var(--surface-2)}
.cat-thumb-empty{display:inline-flex;align-items:center;justify-content:center;font-size:1.3rem}
.group-card{margin-bottom:14px}
.group-badges{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:6px}
.option-list{display:flex;flex-direction:column;margin-top:10px}
.option-row{display:grid;grid-template-columns:minmax(120px,1.2fr) 100px minmax(0,1.6fr) auto;gap:10px;align-items:center;padding:8px 0;border-top:1px dashed var(--line)}
.option-name{font-weight:700}
.option-price{font-variant-numeric:tabular-nums;font-weight:700}
.option-actions{display:flex;gap:6px}
@media (max-width:700px){
  .option-row{grid-template-columns:1fr auto}
  .option-supply{grid-column:1 / -1;order:3}
  .option-actions{grid-column:1 / -1;order:4}
}

/* ═══ Shaker: ITBIS y propina (Configuración) ═══ */
.tax-setting{display:flex;align-items:flex-end;gap:18px;flex-wrap:wrap;margin-bottom:12px}
.tax-setting .f-check{flex:0 0 220px}
.tax-setting .tax-rate{flex:0 0 140px}

/* ═══ Shaker: punto de venta ═══ */
#cart-app .pos-layout{grid-template-columns:minmax(0,1.6fr) minmax(300px,1fr);align-items:start}
@media (max-width:820px){#cart-app .pos-layout{grid-template-columns:minmax(0,1fr)}}
.pos-layout > *{min-width:0}
.pos-menu{display:flex;flex-direction:column;gap:12px}
.pos-menu .search-input{max-width:none;margin-bottom:0}
.chips-sub .chip{padding:6px 12px;min-height:34px;font-size:.82rem;background:var(--surface-2)}
.chips-sub .chip.active{background:var(--yellow)}
.pos-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(136px,1fr));gap:10px}
.pos-tile{
  position:relative;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-end;gap:4px;
  min-height:104px;padding:12px;text-align:left;font:inherit;cursor:pointer;overflow:hidden;
  border:var(--bw) solid var(--line);border-radius:var(--r);background:var(--surface);color:var(--ink);
  transition:border-color .15s,transform .1s;
}
.pos-tile:hover{border-color:var(--ink-soft)}
.pos-tile:active{transform:scale(.97)}
.pos-tile:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.pos-tile-img{width:calc(100% + 24px);height:64px;margin:-12px -12px 4px;object-fit:cover}
.pos-tile-name{font-weight:700;line-height:1.2;font-size:.95rem}
.pos-tile-price{font-weight:800;font-variant-numeric:tabular-nums;color:var(--ink-soft);font-size:.9rem}
.pos-tile-opt{display:inline-block;margin-left:2px;color:var(--orange);font-weight:800}
.pos-tile-count{
  position:absolute;top:8px;right:8px;min-width:24px;height:24px;padding:0 7px;border-radius:999px;
  background:var(--yellow);color:var(--brown-deep);font-weight:800;font-size:.85rem;display:flex;align-items:center;justify-content:center;
  box-shadow:0 1px 3px rgba(0,0,0,.25);
}
.pos-tile-flag{font-size:.72rem;font-weight:800;color:var(--danger);text-transform:uppercase;letter-spacing:.04em}
.pos-tile-flag.is-low{color:var(--amber)}
.pos-tile.is-out{opacity:.55}
@media (prefers-reduced-motion:reduce){.pos-tile{transition:none}.pos-tile:active{transform:none}}

.cart-line{padding:8px 0;border-bottom:1px dashed var(--line)}
.cart-line-main{display:flex;justify-content:space-between;gap:10px;font-variant-numeric:tabular-nums}
.cart-item-sub{font-size:.85em;color:var(--ink-soft);padding-left:12px}
.cart-item-sub-nested{padding-left:26px}
.cart-line-actions{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:6px}
.cart-line-actions .qty-controls{display:flex;align-items:center;gap:8px}
.cart-line-actions .qty-controls button{
  width:36px;height:36px;border-radius:50%;border:var(--bw) solid var(--line-strong);background:var(--surface);
  font:inherit;font-size:1.2rem;font-weight:800;cursor:pointer;color:var(--ink);
}
.cart-line-actions .qty-controls span{min-width:1.6em;text-align:center;font-weight:700}

/* Hoja de opciones del producto */
.opts-sheet{display:flex;flex-direction:column;gap:14px}
.opts-group{border:var(--bw) solid var(--line);border-radius:var(--r);padding:8px 12px 10px;margin:0}
.opts-group legend{padding:0 6px;font-weight:800}
.opts-hint{font-weight:600;font-size:.8em;color:var(--ink-soft)}
.opts-option{display:flex;align-items:center;gap:10px;min-height:46px;cursor:pointer;border-top:1px dashed var(--line)}
.opts-option:first-of-type{border-top:0}
.opts-option input{width:22px;height:22px;accent-color:var(--orange);flex:none}
.opts-option-name{flex:1;font-weight:600}
.opts-option-price{font-variant-numeric:tabular-nums;font-weight:700;color:var(--ink-soft)}
.opts-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;position:sticky;bottom:0;padding-top:6px}
.opts-footer .qty-controls{display:flex;align-items:center;gap:12px}
.opts-footer .qty-controls button{width:44px;height:44px;border-radius:50%;border:var(--bw) solid var(--line-strong);background:var(--surface);font:inherit;font-size:1.4rem;font-weight:800;cursor:pointer;color:var(--ink)}
.opts-footer .qty-controls span{min-width:1.6em;text-align:center;font-weight:800;font-size:1.1rem}
.opts-footer .btn-primary{flex:1;min-height:48px;font-size:1rem}

/* ═══ Shaker: mesas, cuenta y cocina ═══ */
.tables-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.table-tile{
  display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:4px;min-height:112px;padding:14px;
  text-align:left;font:inherit;cursor:pointer;color:var(--ink);
  border:var(--bw) dashed var(--line-strong);border-radius:var(--r-lg);background:var(--surface);
}
.table-tile:hover{border-color:var(--ink-soft)}
.table-tile:focus-visible{outline:2px solid var(--orange);outline-offset:2px}
.table-tile.is-busy{border-style:solid;border-color:var(--ink);background:var(--surface-2)}
.table-tile.has-ready{border-color:var(--sage);box-shadow:0 0 0 2px var(--sage-bg);animation:readyPulse 1.6s ease-in-out infinite}
@keyframes readyPulse{50%{box-shadow:0 0 0 5px var(--sage-bg)}}
@media (prefers-reduced-motion:reduce){.table-tile.has-ready{animation:none}}
.table-name{font-weight:800;font-size:1.1rem}
.table-total{font-weight:800;font-size:1.25rem;font-variant-numeric:tabular-nums}
.table-meta{font-size:.82rem;color:var(--ink-soft)}
.table-chips{display:flex;flex-wrap:wrap;gap:4px;margin-top:auto}
.table-chip{font-size:.72rem;font-weight:800;padding:2px 8px;border-radius:999px;background:var(--surface);border:var(--bw) solid var(--line-strong);color:var(--ink-soft)}
.table-chip.is-kitchen{background:var(--amber-bg);border-color:transparent;color:var(--amber)}
.table-chip.is-ready{background:var(--sage-bg);border-color:transparent;color:var(--sage)}

.cuenta-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.cuenta-head h1{margin:0}
.cuenta-actions{display:flex;gap:10px;margin-top:12px}
.cuenta-actions .btn{flex:1;min-height:48px}
.cuenta-cancel{margin-top:10px;background:transparent;color:var(--danger)}
.order-line.is-void{opacity:.55}
.order-line.is-void .cart-line-main{text-decoration:line-through}
.order-line.is-ready{background:var(--sage-bg);border-radius:8px;padding-left:8px;padding-right:8px}
.order-status{font-size:.78rem;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-soft)}
.order-status.is-pending{color:var(--orange)}
.order-status.is-kitchen{color:var(--amber)}
.order-status.is-ready{color:var(--sage)}
.pay-total{font-size:2.4rem;font-weight:800;text-align:center;font-variant-numeric:tabular-nums;margin:6px 0 4px}
.recibo-pre{white-space:pre-wrap;font-family:ui-monospace,Menlo,monospace;font-size:.85rem;margin:0 0 14px;max-height:50vh;overflow:auto}

/* Cocina */
.kitchen-board{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px;align-items:start}
.kitchen-ticket{
  display:flex;flex-direction:column;gap:6px;padding:14px;border-radius:var(--r-lg);
  border:2px solid var(--line-strong);background:var(--surface);
}
.kitchen-ticket header{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:1.15rem}
.kitchen-ticket .ticket-time{font-variant-numeric:tabular-nums;font-weight:800}
.kitchen-ticket.is-slow{border-color:var(--amber)}
.kitchen-ticket.is-slow .ticket-time{color:var(--amber)}
.kitchen-ticket.is-late{border-color:var(--danger)}
.kitchen-ticket.is-late .ticket-time{color:var(--danger)}
.kitchen-ticket.is-ready{border-color:var(--sage);background:var(--sage-bg)}
.ticket-sub{font-size:.8rem;color:var(--ink-soft);margin-top:-4px}
.kitchen-ticket ul{list-style:none;margin:6px 0;padding:0;display:flex;flex-direction:column;gap:6px}
.ticket-item{display:grid;grid-template-columns:auto 1fr auto;gap:8px;align-items:start;padding:8px;border-radius:8px;background:var(--surface-2);cursor:pointer;font-size:1.02rem}
.ticket-item.is-preparando{outline:2px solid var(--amber)}
.ticket-item.is-listo{opacity:.55;text-decoration:line-through}
.ticket-qty{font-weight:800}
.ticket-name em{display:block;font-style:normal;font-size:.86em;color:var(--ink-soft)}
.ticket-name em.ticket-note{color:var(--orange);font-weight:700}
.ticket-state{font-size:1.1rem}
.kitchen-ticket footer{display:flex;gap:8px}
.kitchen-ticket footer .btn{flex:1;min-height:46px}
.ticket-hint{margin:0;font-size:.85rem;color:var(--sage);font-weight:700}
.kitchen-board-ready .kitchen-ticket{opacity:.9}

.tables-admin{display:flex;flex-direction:column}
.table-admin-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:8px 0;border-top:1px dashed var(--line);flex-wrap:wrap}
.table-admin-row:first-child{border-top:0}
.table-admin-actions{display:flex;gap:6px}

/* Por vencer / merma */
.expiry-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 0;border-top:1px dashed var(--line);flex-wrap:wrap}
.expiry-row:first-child{border-top:0}
.expiry-when{font-weight:800;font-size:.85rem;color:var(--amber)}
.expiry-row.is-expired .expiry-when{color:var(--danger)}
.expiry-card{border-color:var(--amber)}
.chips-wrap{flex-wrap:wrap;overflow:visible}

/* Preparar */
.prep-preview{margin:6px 0 12px;padding:10px 12px;background:var(--surface-2);border-radius:var(--r)}
.prep-title{font-size:.8rem;font-weight:800;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-soft);margin-bottom:4px}
.prep-row{display:flex;justify-content:space-between;gap:10px;padding:3px 0;font-size:.92rem}
.prep-row.is-short{color:var(--danger)}
.prep-total{border-top:1px dashed var(--line);margin-top:6px;padding-top:6px;font-weight:700}

.pay-split{margin:10px 0;padding:8px 12px;border:var(--bw) solid var(--line);border-radius:var(--r)}
.pay-split summary{cursor:pointer;font-weight:700}
.order-line.is-served .cart-line-main{opacity:.7}

/* Pedidos web */
.web-card{margin-bottom:14px}
.web-meta{margin:6px 0;font-size:.92rem}
.web-lines{border-top:1px dashed var(--line);border-bottom:1px dashed var(--line);margin:10px 0;padding:6px 0}
.web-line{padding:4px 0}
.web-line > strong{margin-right:8px}
.web-line > span{float:right;font-variant-numeric:tabular-nums}
.web-total{font-weight:700;margin-bottom:10px}


/* ═══════════════════════════════════════════════════════════════════
   MARCA — logo de trazo, verde lima como acento, píldoras negras para lo
   seleccionado, papel crema. Hasta acá era el mismo lenguaje "sticker" de
   la página de pedidos vieja (sombra dura con desplazamiento, marcador
   rotado bajo los títulos, franja de cuadros sobre Ayuda/Salir) — pedido
   del dueño, después de usar el sistema un tiempo: "más limpio y sobrio".
   --hard/--hard-hover/--hard-press CONSERVAN el nombre (decenas de reglas
   más abajo ya los usan para "la sombra de lo que se destaca") pero ahora
   apuntan a --shadow/--shadow-sm, la elevación suave que ya existía arriba
   del archivo — un solo lugar para ablandar todo, sin tocar cada regla
   suelta. --btn-edge pasa a transparent (sin el borde grueso oscuro) y
   --checker/la franja de cuadros se elimina más abajo, en .sidebar-footer.
   Va al final a propósito: retoca lo anterior sin tener que tocar cientos
   de reglas sueltas.
   ═══════════════════════════════════════════════════════════════════ */
:root{
  --r:12px;--r-lg:18px;
  --hard:var(--shadow-sm);
  --hard-hover:var(--shadow);
  --hard-press:var(--shadow-sm);
  --btn-edge:transparent;
  --pill-on-bg:var(--brown-deep);--pill-on-fg:var(--yellow);
  --hl:var(--yellow);
}
:root[data-theme="dark"]{
  --pill-on-bg:var(--yellow);--pill-on-fg:var(--lime-ink);
  --hl:color-mix(in srgb,var(--yellow) 30%,transparent);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --pill-on-bg:var(--yellow);--pill-on-fg:var(--lime-ink);
    --hl:color-mix(in srgb,var(--yellow) 30%,transparent);
  }
}
/* El carrito siempre en claro (ver más arriba): que sus acentos también */
body:has(#cart-app:not([hidden])){
  --pill-on-bg:var(--brown-deep);--pill-on-fg:var(--yellow);--hl:var(--yellow);
}

a{color:var(--ink);text-decoration-color:var(--orange);text-underline-offset:3px}
a:hover{text-decoration-thickness:2px}
::selection{background:var(--yellow);color:var(--lime-ink)}

/* Logo de marca en el menú lateral (versión clara, sobre fondo negro).
   Sexta vuelta — pedido explícito: ya no compite con el logo de Arche en
   el login (que ahora vive solo ahí), así que gana protagonismo aquí, que
   es donde el negocio de verdad se ve todo el día (dueño y carrito). Placa
   y logo un poco más grandes que antes (170→210px / 54→68px). */
.sidebar-brand{padding:4px 8px 16px;gap:6px}
.sidebar-brand .brand-plate{display:flex;align-items:center;justify-content:center;width:100%;max-width:210px;padding:10px 14px;background:var(--paper);border-radius:14px}
.sidebar-brand .brand-plate[hidden]{display:none}
.sidebar-brand .brand-mark{display:block;width:100%;height:auto;max-height:68px;object-fit:contain}
/* Sin logo: el nombre del negocio, en grande. Con logo, el nombre queda solo para lectores de pantalla. */
.sidebar-brand .brand-name{font-family:"Sora",sans-serif;font-weight:800;font-size:1.2rem;line-height:1.15;letter-spacing:-.01em;color:var(--cream);width:100%}
.sidebar-brand.has-logo .brand-name{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.sidebar-brand span{margin-top:0}
.sidebar-brand span:not(.brand-name){
  display:inline-block;width:auto;background:var(--yellow);color:var(--lime-ink);
  font-weight:800;font-size:.72rem;letter-spacing:.02em;padding:3px 10px;border-radius:999px;
}
.login-box{border-width:1.5px;box-shadow:var(--hard)}
.login-box h1{font-weight:800;letter-spacing:-.01em}

/* Antes: una franja de cuadros de colores (el borde del hero de la página vieja) sobre
   Ayuda/Salir — el dueño la vio rara ahí. Un separador simple, igual al que ya usa
   .nav-group + .nav-group más arriba. */
.sidebar-footer{border-top:1px solid rgba(255,255,255,.15);padding-top:16px}
.sidebar-footer .btn{border-color:color-mix(in srgb,var(--cream) 35%,transparent);font-weight:700}
.sidebar-footer .btn:hover{background:color-mix(in srgb,var(--cream) 10%,transparent);border-color:var(--yellow);color:var(--yellow)}

/* Menú lateral: activo en lima (sobre negro) — se conserva; el resto respira. Ya no
   lleva sombra con desplazamiento: el propio fondo lima alcanza para distinguirlo. */
.nav-item{border-radius:999px;font-weight:700}
.nav-group-label{letter-spacing:.09em}

/* Títulos: primero un marcador lima grueso y rotado (estilo resaltador),
   después una línea fina debajo — el dueño vio las dos raras. Sin nada
   debajo: el peso tipográfico (800, letter-spacing negativo) ya alcanza
   para distinguir el título. */
.view > h1,.view > .page-head h1,.view > .card-header-row h1{
  font-weight:800;letter-spacing:-.02em;font-size:1.7rem;
}
h2{letter-spacing:-.005em}

/* Botones: borde más suave que el de base (--line-strong en vez de --brown), sin la
   sombra "sticker" con desplazamiento ni el rebote al presionar que tenía el primario
   — vuelve al fondo lima liso + :hover más oscuro ya definidos arriba (línea 669), más
   la marca de presión que ya comparten TODOS los botones (.btn:active{scale(.96)}). */
.btn{border:1.5px solid var(--line-strong)}
.btn:hover{background:var(--surface-2);border-color:var(--ink-soft)}
.btn-primary:disabled,.btn-primary:disabled:hover{background:var(--yellow)}
.btn:focus-visible,.nav-item:focus-visible,.chip:focus-visible,.pos-tile:focus-visible,.table-tile:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid var(--yellow);outline-offset:2px;box-shadow:0 0 0 5px var(--brown-deep)}
input:focus,select:focus,textarea:focus{border-color:var(--brown-deep);box-shadow:0 0 0 3px color-mix(in srgb,var(--yellow) 55%,transparent)}
:root[data-theme="dark"] input:focus,:root[data-theme="dark"] select:focus,:root[data-theme="dark"] textarea:focus{border-color:var(--yellow)}

/* Píldoras seleccionadas: negro con texto lima (página) */
.chip{border:1.5px solid var(--line-strong);font-weight:700}
.chip.active,.chips-sub .chip.active{background:var(--pill-on-bg);border-color:var(--pill-on-bg);color:var(--pill-on-fg)}
.subtab.active{border-bottom-color:var(--brown-deep);box-shadow:0 3px 0 var(--yellow)}
:root[data-theme="dark"] .subtab.active{border-bottom-color:var(--yellow);box-shadow:none}

/* Tarjetas: bordes más definidos, un solo nivel de elevación */
.card{border:1.5px solid var(--line);box-shadow:0 1px 2px color-mix(in srgb,var(--brown-deep) 5%,transparent),0 8px 24px color-mix(in srgb,var(--brown-deep) 5%,transparent)}
.card-quiet{border:1.5px solid var(--line);background:color-mix(in srgb,var(--surface) 55%,transparent)}
.stat{border:1.5px solid var(--line);border-radius:var(--r)}
.stat .value{color:var(--ink);font-family:"Sora","Manrope",sans-serif;font-weight:700}
.stat.stat-quiet{background:var(--surface-2);border-color:var(--line)}
.grid-3 .stat:hover,.grid-2 .stat:hover{transform:none;box-shadow:none}

/* Panel: la cifra principal en negro con lima, como el sello de la página */
.panel-hero{
  background:var(--brown-deep);color:var(--cream);border:2px solid var(--brown-deep);
  border-radius:var(--r-lg);box-shadow:5px 5px 0 var(--yellow);padding:16px 22px;margin:0 6px 16px 0;
}
:root[data-theme="dark"] .panel-hero{border-color:var(--yellow);box-shadow:5px 5px 0 color-mix(in srgb,var(--yellow) 35%,transparent)}
.panel-hero .label{color:var(--yellow);opacity:1;letter-spacing:.08em}
.panel-hero .value{color:#fff;font-weight:800;font-size:2.4rem}
.panel-hero .sub{opacity:.75}
.panel-mini{border:1.5px solid var(--line);border-radius:var(--r)}
.panel-mini .value{font-family:"Sora","Manrope",sans-serif}

/* Venta rápida: mosaicos y botón "+" como en el menú de la página */
.pos-tile{border:1.5px solid var(--line);border-radius:14px;min-height:112px;transition:transform .1s,box-shadow .1s,border-color .12s}
.pos-tile:hover{border-color:var(--brown-deep);transform:translate(-1px,-1px);box-shadow:var(--hard)}
.pos-tile:active{transform:translate(1px,1px);box-shadow:none}
.pos-tile-name{font-weight:700;font-size:.96rem}
.pos-tile-price{color:var(--ink);font-family:"Sora","Manrope",sans-serif;font-size:.92rem;display:flex;align-items:center;gap:6px;width:100%}
.pos-tile:not(.is-out)::after{
  content:"+";position:absolute;right:10px;bottom:10px;width:28px;height:28px;border-radius:50%;
  background:var(--yellow);color:var(--lime-ink);font-weight:800;font-size:1.1rem;line-height:28px;text-align:center;
}
.pos-tile-opt{display:none}
.pos-tile-count{background:var(--brown-deep);color:var(--yellow);box-shadow:none;top:8px;right:8px;z-index:1}
.pos-tile.is-out{background:var(--surface-2)}
@media (prefers-reduced-motion:reduce){.pos-tile:hover,.pos-tile:active{transform:none}}

/* Mesas: libres claras, ocupadas en negro con lima */
.table-tile{border:1.5px solid var(--line-strong);border-style:solid;border-radius:16px;transition:transform .1s,box-shadow .1s}
.table-tile:hover{border-color:var(--brown-deep);transform:translate(-1px,-1px);box-shadow:var(--hard)}
.table-tile .table-name{font-family:"Sora","Manrope",sans-serif;font-weight:700;font-size:1.05rem}
.table-tile .table-meta{color:var(--ink-soft);font-size:.82rem}
.table-tile:not(.is-busy) .table-meta::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--yellow-deep);margin-right:6px;vertical-align:1px}
.table-tile.is-busy{background:var(--brown-deep);border-color:var(--brown-deep);color:var(--cream)}
.table-tile.is-busy .table-meta{color:color-mix(in srgb,var(--cream) 72%,transparent)}
.table-tile.is-busy .table-total{color:var(--yellow);font-family:"Sora","Manrope",sans-serif;font-weight:700}
.table-tile.is-busy:hover{box-shadow:3px 3px 0 var(--yellow)}
@media (prefers-reduced-motion:reduce){.table-tile:hover{transform:none}}

/* Tablas y etiquetas */
.table th{letter-spacing:.07em;font-size:.74rem;font-weight:800}
.badge{font-weight:800;letter-spacing:.01em}
.badge-ok{background:var(--yellow);color:var(--lime-ink)}
.modal-box,.modal-box-wide{border:1.5px solid var(--brown-deep);box-shadow:var(--hard-hover);border-radius:var(--r-lg)}
.toast{border-radius:999px}

/* Celular: la barra inferior del carrito con el mismo lenguaje */
@media (max-width:820px){
  .sidebar-brand .brand-plate{width:auto;padding:4px 8px;border-radius:10px}
  .sidebar-brand .brand-mark{width:auto;max-width:none;height:30px}
  .sidebar-brand .brand-name{font-size:1rem;width:auto}
  .sidebar-brand span:not(.brand-name){display:none}
  .sidebar-footer::before{display:none}
  .sidebar-footer{padding-top:0}
  #cart-app .sidebar-nav .nav-item.active{background:var(--yellow);color:var(--lime-ink)}
}

input[type="checkbox"],input[type="radio"]{accent-color:var(--pill-on-bg)}

/* ═══ Página web (mini CMS): qué sale, textos y fotos ═══ */
.pw-h{margin:22px 0 8px;font-size:.95rem}
.pw-actions{display:flex;align-items:center;gap:14px;margin-top:22px;flex-wrap:wrap}
.pw-cat{padding:0;overflow:hidden}
.pw-cat-head,.pw-sub{display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--surface-2);border-bottom:1px solid var(--line)}
.pw-cat-head h2{margin:0;font-family:"Sora","Manrope",sans-serif;font-size:1.05rem}
.pw-sub{background:transparent;padding:8px 16px 8px 30px;border-top:1px solid var(--line)}
.pw-sub h3{margin:0;font-size:.88rem;color:var(--ink-soft);text-transform:uppercase;letter-spacing:.06em}
.pw-cat-head.is-off h2,.pw-sub.is-off h3{opacity:.55}
.pw-cat-actions{margin-left:auto;display:flex;gap:6px}
.pw-row{display:flex;align-items:center;gap:12px;padding:10px 16px;border-bottom:1px dashed var(--line)}
.pw-row:last-child{border-bottom:0}
.pw-row.is-off .pw-name strong,.pw-row.is-off .pw-thumb{opacity:.5}
.pw-name{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.pw-name .muted{font-size:.82rem}
.pw-thumb{width:40px;height:40px;border-radius:10px;object-fit:cover;flex:none;background:var(--surface-2)}
.pw-thumb--empty{border:1.5px dashed var(--line-strong);background:transparent}
.pw-state{flex:none;white-space:nowrap}
.pw-soldout{display:flex;align-items:center;gap:6px;font-size:.84rem;font-weight:700;white-space:nowrap;cursor:pointer;color:var(--ink-soft)}
.pw-soldout input:checked + span{color:var(--danger-on-bg)}
/* Interruptor: lima cuando el plato sale en la página */
.pw-switch{position:relative;display:inline-block;width:42px;height:24px;flex:none;cursor:pointer}
.pw-switch input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer;z-index:1}
.pw-track{position:absolute;inset:0;border-radius:999px;background:var(--line-strong);transition:background-color .15s}
.pw-track::after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.3);transition:transform .15s}
.pw-switch input:checked + .pw-track{background:var(--brown-deep)}
.pw-switch input:checked + .pw-track::after{transform:translateX(18px);background:var(--yellow)}
:root[data-theme="dark"] .pw-switch input:checked + .pw-track{background:var(--yellow)}
:root[data-theme="dark"] .pw-switch input:checked + .pw-track::after{background:var(--brown-deep)}
.pw-switch input:focus-visible + .pw-track{outline:3px solid var(--yellow);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.pw-track,.pw-track::after{transition:none}}
@media (max-width:700px){
  .pw-row{flex-wrap:wrap}.pw-name{flex:1 1 60%}.pw-cat-head{flex-wrap:wrap}.pw-cat-actions{margin-left:0;width:100%}
}
/* Titulares y etiquetas */
.pw-line{display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:8px;margin-bottom:8px;align-items:center}
.pw-line--pill{grid-template-columns:150px 1fr auto}
.pw-line input.is-accent{background:color-mix(in srgb,var(--yellow) 30%,var(--surface));font-weight:700}
@media (max-width:700px){.pw-line{grid-template-columns:1fr auto}.pw-line input:nth-child(3){grid-column:1}.pw-line--pill{grid-template-columns:1fr auto}.pw-line--pill select{grid-column:1 / -1}}
/* Galería de fotos */
.photo-toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.photo-h{margin:16px 0 8px;font-size:.85rem;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-soft)}
.photo-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px}
.photo-grid--lg{grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}
.photo-cell{position:relative;border:1.5px solid var(--line);border-radius:12px;overflow:hidden;background:var(--surface-2)}
.photo-cell.is-current{border-color:var(--brown-deep);box-shadow:3px 3px 0 var(--yellow)}
.photo-cell img{display:block;width:100%;aspect-ratio:4/3;object-fit:cover}
.photo-pick{display:block;width:100%;padding:0;border:0;background:none;cursor:pointer}
.photo-pick:hover img{filter:brightness(.92)}
.photo-del{position:absolute;top:6px;right:6px;width:26px;height:26px;border-radius:50%;border:0;background:var(--brown-deep);color:#fff;font-weight:800;cursor:pointer;line-height:1}
.photo-del:hover{background:var(--danger)}
.photo-meta{display:block;padding:6px 8px;font-size:.74rem;color:var(--ink-soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.photo-field__row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.photo-field__thumb{width:56px;height:42px;object-fit:cover;border-radius:8px;border:1.5px solid var(--line)}


/* ═══ Configuración → Marca (colores) ═══ */
.brand-presets{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;margin:8px 0 16px}
.brand-preset{display:flex;flex-direction:column;gap:8px;padding:10px;border:1.5px solid var(--line-strong);border-radius:14px;background:var(--surface);cursor:pointer;font:inherit;text-align:left;color:var(--ink)}
.brand-preset:hover{border-color:var(--brown-deep)}
.brand-preset.is-current{border-color:var(--brown-deep);box-shadow:3px 3px 0 var(--yellow)}
.brand-preset strong{font-size:.85rem}
.brand-swatches{display:flex;height:26px;border-radius:8px;overflow:hidden;border:1px solid var(--line)}
.brand-swatches i{flex:1}
.brand-colors{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:14px}
.brand-color{display:flex;flex-direction:column;gap:4px}
.brand-color > span{font-size:.85rem;font-weight:700}
.brand-color small{color:var(--ink-soft);font-size:.78rem;min-height:2.4em;line-height:1.2}
.brand-color-row{display:flex;gap:8px;align-items:center}
.brand-color-row input[type="color"]{width:48px;height:42px;padding:2px;border-radius:10px;border:1.5px solid var(--line-strong);background:var(--surface);cursor:pointer;flex:none}
.brand-color-row input[type="text"]{flex:1;min-width:0;font-family:ui-monospace,Menlo,monospace;text-transform:uppercase}
.brand-notes{margin:12px 0 0;display:flex;flex-direction:column;gap:6px}
.brand-note{padding:8px 12px;border-radius:10px;font-size:.88rem}
.brand-note.is-warn{background:var(--amber-bg);color:var(--amber)}
.brand-note.is-error{background:var(--danger-bg);color:var(--danger-on-bg)}
.brand-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:16px}

.pw-conn{margin:0 0 14px;padding:12px 16px;border-radius:12px;font-size:.92rem;line-height:1.45;border:1.5px solid var(--line)}
.pw-conn.is-ok{background:var(--sage-bg);color:var(--sage);border-color:transparent}
.pw-conn.is-warn{background:var(--amber-bg);color:var(--amber);border-color:transparent}
.pw-conn code{font-size:.85em;background:color-mix(in srgb,var(--ink) 8%,transparent);padding:1px 6px;border-radius:6px}

.pos-extra{margin:2px 0 14px;border:1.5px dashed var(--line-strong);border-radius:12px;padding:8px 12px}
.pos-extra > summary{cursor:pointer;font-weight:700;font-size:.9rem;color:var(--ink-soft);list-style:none}
.pos-extra > summary::-webkit-details-marker{display:none}
.pos-extra > summary::before{content:"＋ ";color:var(--ink)}
.pos-extra[open] > summary::before{content:"－ "}
.pos-extra[open]{padding-bottom:2px}
.pos-extra .field{margin-top:10px}

.pw-mode{display:flex;flex-direction:column;gap:8px;margin:0 0 12px}
.pw-mode-opt{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border:1.5px solid var(--line-strong);border-radius:12px;cursor:pointer}
.pw-mode-opt:has(input:checked){border-color:var(--brown-deep);box-shadow:3px 3px 0 var(--yellow)}
.pw-mode-opt input{margin-top:4px}
.pw-mode-opt small{display:block;color:var(--ink-soft);font-size:.85rem;margin-top:2px;line-height:1.35}

/* Módulos apagados: se esconden sin tocar el atributo hidden (que usan otras pantallas) */
.mod-off{display:none !important}
.mod-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.mod-item{display:flex;gap:12px;align-items:flex-start;padding:10px 12px;border:1.5px solid var(--line);border-radius:12px;background:var(--surface)}
.mod-item.is-on{border-color:var(--brown-deep)}
.mod-item .pw-switch{margin-top:2px}
.mod-item strong{display:block}
.mod-item small{display:block;color:var(--ink-soft);font-size:.85rem;line-height:1.35;margin-top:2px}
.mod-item .mod-req{color:var(--ink-soft);font-size:.78rem;margin-top:3px}
.mod-presets{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 4px}

.pw-line--hours{grid-template-columns:1fr 110px 110px auto;align-items:center}
.pw-line--zone{grid-template-columns:1fr 140px auto}
@media (max-width:700px){.pw-line--hours{grid-template-columns:1fr 1fr auto}.pw-line--hours .chips{grid-column:1 / -1}}

/* Asistente: tipo de negocio */
.setup-choices{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:8px}
.setup-choice{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border:1.5px solid var(--line-strong);border-radius:12px;cursor:pointer;background:var(--surface)}
.setup-choice:has(input:checked){border-color:var(--brown-deep);box-shadow:3px 3px 0 var(--yellow)}
.setup-choice input{margin-top:4px}
.setup-choice small{display:block;color:var(--ink-soft);font-size:.82rem;line-height:1.3;margin-top:2px}

/* Aviso de cuenta (prueba/plan/solo lectura) y enlace de recuperar contraseña */
.account-banner{position:sticky;top:0;z-index:60;display:flex;gap:10px;justify-content:center;align-items:center;padding:8px 40px 8px 14px;background:var(--amber-bg);color:var(--amber);font-size:.9rem;text-align:center;border-bottom:1px solid var(--line-strong)}
.account-banner.is-critical{background:var(--danger-bg);color:var(--danger-on-bg)}
.account-banner button{position:absolute;right:8px;top:50%;transform:translateY(-50%);border:0;background:none;color:inherit;font-size:1.3rem;line-height:1;cursor:pointer;padding:4px 8px}
.login-forgot{margin:12px 0 0;text-align:center;font-size:.9rem}

/* Rol «cocina»: el menú solo lleva a la pantalla de cocina */
#cart-app[data-emp-role="cocina"] .nav-item:not([data-view="pos-cocina"]){display:none}
.return-line{display:flex;gap:10px;align-items:center;padding:8px 0;border-bottom:1px dashed var(--line)}
.return-line input[type=checkbox]{flex:0 0 auto;width:20px;height:20px;margin:0}
.return-name{flex:1 1 auto}
.return-line .return-qty{flex:0 0 6rem;width:6rem;height:auto;border-radius:8px;border:1px solid var(--line-strong);padding:6px 8px;background:var(--surface);color:var(--ink)}
.pos-discount-actions{gap:8px;justify-content:flex-end}
.po-line{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr) minmax(0,1fr) auto;gap:8px;align-items:end;margin-bottom:8px}
.po-line.po-receive{grid-template-columns:minmax(0,2fr) minmax(0,1fr) minmax(0,1fr)}
@media (max-width:640px){.po-line,.po-line.po-receive{grid-template-columns:1fr 1fr}.po-line>:first-child{grid-column:1/-1}}

.pos-tile-wholesale{display:block;font-size:.68rem;color:var(--sage);font-weight:700;margin-top:2px}

/* ═══ Interfaz de trabajo v3.1 (ANALISIS-INTERFAZ-V3.1.md) ═══
   Administrativo y facturación, con la misma línea que el login v3.0:
   barra superior con saludo/fecha/reloj/conexión, pastilla deslizante en el
   menú, cifras que cuentan, Panel con hero + minigráfica y gráfica al ancho
   real, venta con productos escalonados, punto que vuela al recibo y botón
   «Cobrar RD$…». Va al final a propósito: pisa reglas viejas sin tocarlas.
   Todo el movimiento se apaga con prefers-reduced-motion (abajo del todo). */

/* ── Barra superior ── */
.app-topbar{
  width:min(100% - 32px, 1320px);margin-inline:auto;padding:16px 0 4px;
  display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:58px;
}
.app-topbar + .wrap{padding-top:10px}
#cart-app .app-topbar + main.wrap{padding-top:10px}
.app-topbar-date{margin:0;font-size:.9rem;font-weight:700;color:var(--ink-soft)}
.app-topbar-right{display:flex;align-items:center;gap:10px;margin-left:auto}
.ux-status{
  display:inline-flex;align-items:center;gap:7px;padding:5px 11px;border-radius:999px;
  border:1px solid var(--line);background:var(--surface);
  font-size:.76rem;font-weight:700;color:var(--ink-soft);white-space:nowrap;
}
.ux-status i{flex:none;width:7px;height:7px;border-radius:50%;background:#2FBF71;animation:uxPing 2.4s ease-out infinite}
.ux-status.is-off{color:var(--danger-on-bg);border-color:color-mix(in srgb,var(--danger) 45%,var(--line));background:var(--danger-bg)}
.ux-status.is-off i{background:var(--danger);animation:none}
@keyframes uxPing{0%{box-shadow:0 0 0 0 rgba(47,191,113,.5)}70%,100%{box-shadow:0 0 0 7px rgba(47,191,113,0)}}
.ux-clock{font-family:"Sora","Manrope",sans-serif;font-weight:700;font-size:.95rem;color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.ux-who{display:flex;align-items:center;gap:10px;min-width:0}
.ux-avatar{
  flex:none;width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  background:var(--yellow);color:var(--lime-ink);font-family:"Sora","Manrope",sans-serif;font-weight:800;font-size:.9rem;
  box-shadow:0 0 0 3px color-mix(in srgb,var(--yellow) 25%,transparent);
}
.ux-who-text{display:flex;flex-direction:column;min-width:0;line-height:1.2}
.ux-who-text strong{font-size:.95rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ux-who-text .muted{font-size:.78rem;font-weight:600}
@media (max-width:820px){
  .app-topbar{padding:12px 0 0;min-height:0}
  .app-topbar-date{font-size:.82rem}
  .ux-status span{display:none}
  .ux-status{padding:6px}
}

/* ── Menú lateral: pastilla que se desliza hasta la sección activa ── */
.sidebar-nav{position:relative}
.nav-glider{
  position:absolute;top:0;left:0;z-index:0;pointer-events:none;opacity:0;
  background:var(--yellow);border-radius:999px;
  transition:transform .45s cubic-bezier(.34,1.25,.64,1),width .3s ease,height .3s ease,opacity .2s ease;
}
.sidebar-nav.has-glider .nav-glider{opacity:1}
.sidebar-nav .nav-item{position:relative;z-index:1}
.sidebar-nav.has-glider .nav-item.active,
#cart-app .sidebar-nav.has-glider .nav-item.active,#owner-app .sidebar-nav.has-glider .nav-item.active{background:transparent}
.nav-item .nav-icon{transition:transform .2s ease}
.nav-item:hover .nav-icon{transform:translateX(2px)}
.nav-item.active .nav-icon{transform:none}
.sidebar-arche{
  width:70px;aspect-ratio:1600/243;margin:4px auto 0;background:var(--cream);opacity:.45;
  -webkit-mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
  mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
}
@media (max-width:820px){
  .sidebar-footer{border-top:none;padding-top:0}
  .sidebar-footer .sidebar-arche{display:none}
  #owner-app .sidebar-footer .sidebar-arche{display:block;width:70px;flex:none}
}

/* ── Cambio de sección ── */
.view.is-entering{animation:uxViewIn .38s cubic-bezier(.16,1,.3,1)}
@keyframes uxViewIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ── Estados vacíos ── */
.ux-empty{display:flex;align-items:center;gap:14px;padding:10px 2px;text-align:left}
.ux-empty-icon{flex:none;width:44px;height:44px;border-radius:14px;display:grid;place-items:center;background:var(--surface-2);color:var(--ink-soft)}
.ux-empty-icon svg{width:22px;height:22px}
.ux-empty strong{display:block;font-size:.95rem;color:var(--ink)}
.ux-empty span:not(.ux-empty-icon){display:block;font-size:.86rem;color:var(--ink-soft);margin-top:2px}

/* ── Panel del administrativo ── */
.dash-head{display:flex;align-items:flex-end;justify-content:space-between;gap:14px 20px;flex-wrap:wrap;margin-bottom:20px}
.dash-kicker{margin:0;font-size:.72rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft)}
.view > .dash-head h1.dash-title{margin:2px 0 4px;font-size:clamp(1.75rem,3.2vw,2.35rem);font-weight:800;letter-spacing:-.03em;line-height:1.1}
.dash-sub{margin:0;color:var(--ink-soft);font-size:.95rem}
.dash-head .panel-shortcuts{margin-top:0}
.dash-section{margin:26px 0 10px;font-size:1rem}
#owner-app .panel-hero{
  position:relative;overflow:hidden;isolation:isolate;display:flex;align-items:flex-end;justify-content:space-between;gap:20px;
  margin:0 0 12px;padding:22px 24px;border:none;border-radius:20px;color:#fff;
  background:
    radial-gradient(90% 140% at 100% 0%,color-mix(in srgb,var(--yellow) 32%,transparent),transparent 60%),
    radial-gradient(60% 90% at 0% 100%,color-mix(in srgb,var(--orange) 18%,transparent),transparent 70%),
    var(--brown-deep);
  box-shadow:0 18px 40px -22px color-mix(in srgb,var(--brown-deep) 80%,transparent);
}
:root[data-theme="dark"] #owner-app .panel-hero{box-shadow:0 0 0 1px var(--line)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) #owner-app .panel-hero{box-shadow:0 0 0 1px var(--line)}}
/* Un brillo que cruza una sola vez al aparecer. */
#owner-app .panel-hero::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(110deg,transparent 30%,rgba(255,255,255,.09) 45%,transparent 60%);
  transform:translateX(-100%);animation:uxSheen 1.4s .2s cubic-bezier(.65,0,.35,1) forwards;
}
@keyframes uxSheen{to{transform:translateX(100%)}}
.panel-hero-main{min-width:0}
.panel-hero-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
#owner-app .panel-hero .label{font-size:.74rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--yellow)}
#owner-app .panel-hero .value{font-family:"Sora","Manrope",sans-serif;font-size:clamp(2.3rem,4.4vw,3.2rem);font-weight:800;letter-spacing:-.035em;line-height:1.05;margin:8px 0 6px;color:#fff;font-variant-numeric:tabular-nums}
#owner-app .panel-hero .sub{font-size:.84rem;color:rgba(255,255,255,.62);opacity:1}
.panel-hero-delta{font-size:.76rem;font-weight:800;padding:3px 10px;border-radius:999px;background:rgba(255,255,255,.12);color:rgba(255,255,255,.85);white-space:nowrap}
.panel-hero-delta.is-up{color:#86F0A6;background:rgba(61,220,132,.16)}
.panel-hero-delta.is-down{color:#FFA394;background:rgba(255,93,93,.16)}
.panel-hero-spark{flex:none;width:min(40%,300px);height:auto;color:var(--yellow);overflow:visible}
.panel-hero-spark .spark-line{vector-effect:non-scaling-stroke;stroke-dasharray:1;stroke-dashoffset:1;animation:uxDraw 1.1s .15s cubic-bezier(.65,0,.35,1) forwards}
.panel-hero-spark .spark-area{opacity:0;animation:uxFade .8s .7s forwards}
.panel-hero-spark .spark-dot{fill:#fff;stroke:var(--yellow);stroke-width:2.5;transform-box:fill-box;transform-origin:center;animation:uxPop .5s 1s cubic-bezier(.34,1.6,.64,1) both}
@keyframes uxDraw{to{stroke-dashoffset:0}}
@keyframes uxFade{to{opacity:1}}
@keyframes uxPop{from{transform:scale(0)}to{transform:scale(1)}}
@media (max-width:640px){
  #owner-app .panel-hero{flex-direction:column;align-items:stretch;gap:10px;padding:18px}
  .panel-hero-spark{width:100%;max-height:70px}
}
/* Tarjetas con ícono (hoy y este mes). */
#owner-app .panel-mini-row{grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}
#owner-app .panel-mini,#owner-app .ux-stat{
  display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto auto;column-gap:12px;align-items:center;
  text-align:left;padding:14px 16px;border-radius:16px;border:1px solid var(--line);background:var(--surface);
  transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease;
}
#owner-app .panel-mini:hover,#owner-app .ux-stat:hover{transform:translateY(-2px);box-shadow:var(--shadow);border-color:var(--line-strong)}
.ux-stat-icon{
  grid-row:span 2;width:40px;height:40px;border-radius:12px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--yellow) 24%,var(--surface));color:var(--ink);
}
.ux-stat-icon svg{width:20px;height:20px}
#owner-app .panel-mini .label,#owner-app .ux-stat .label{font-size:.78rem;color:var(--ink-soft);align-self:end}
#owner-app .panel-mini .value,#owner-app .ux-stat .value{font-family:"Sora","Manrope",sans-serif;font-size:1.25rem;font-weight:800;color:var(--ink);letter-spacing:-.02em;align-self:start;font-variant-numeric:tabular-nums}
#owner-app #panel-stats-month{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
/* Celular: las 3 cifras del día en una fila compacta (sin ícono) y las del
   mes como lista, una por renglón — antes quedaba una tarjeta huérfana. */
@media (max-width:520px){
  #owner-app .panel-mini-row{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
  #owner-app .panel-mini{grid-template-columns:1fr;row-gap:2px;padding:10px;text-align:center}
  #owner-app .panel-mini .ux-stat-icon{display:none}
  #owner-app .panel-mini .label{font-size:.7rem;align-self:auto}
  #owner-app .panel-mini .value{font-size:.98rem;align-self:auto}
  #owner-app #panel-stats-month{grid-template-columns:1fr;gap:8px}
  #owner-app .ux-stat{padding:12px 14px}
  #owner-app .ux-stat .value{font-size:1.1rem}
}
/* Si la tarjeta "por ubicación" está apagada (un solo local), Bajo stock ocupa todo el ancho. */
#owner-app .view[data-view="panel"] .grid-2:has(> [hidden]){grid-template-columns:1fr}
@media (max-width:820px){
  .sidebar-footer{align-items:center}
  .sidebar-footer .btn-block{margin:0;width:auto;display:inline-flex;align-items:center;justify-content:center;height:38px;line-height:1}
  /* El menú del dueño cerrado (fuera de pantalla) dejaba su sombra asomada
     como una franja gris en el borde izquierdo. */
  #owner-app .sidebar:not(.open) .sidebar-nav,#owner-app .sidebar:not(.open) .sidebar-footer{box-shadow:none}
}
/* Gráfica de 14 días. */
.panel-chart-summary{display:flex;gap:6px 20px;flex-wrap:wrap;margin:0 0 14px;font-size:.92rem}
.panel-chart-summary strong{font-family:"Sora","Manrope",sans-serif}
#owner-app .panel-chart-svg{width:100%;height:auto;display:block;overflow:visible}
#owner-app .panel-chart-bar rect{fill:color-mix(in srgb,var(--yellow) 38%,var(--surface-2));stroke:none;transition:fill .2s ease}
#owner-app .panel-chart-bar:hover rect{fill:color-mix(in srgb,var(--yellow) 70%,var(--surface-2))}
#owner-app .panel-chart-bar.is-today rect{fill:color-mix(in srgb,var(--orange) 55%,var(--surface-2))}
#owner-app .panel-chart-bar.is-selected rect{fill:var(--yellow);stroke:none}
#owner-app .panel-chart-bar.is-today.is-selected rect{fill:var(--orange)}
#owner-app .panel-chart-bar.is-selected .panel-chart-day{fill:var(--ink);font-weight:800}
#owner-app .panel-chart-bar.is-selected .panel-chart-value{opacity:1}
#owner-app .panel-chart-day,#owner-app .panel-chart-value{font-size:11px}
.panel-chart-avg{stroke:var(--ink-soft);stroke-width:1;stroke-dasharray:4 5;opacity:.55}
.panel-chart-avg-key{display:inline-block;width:18px;margin-right:6px;vertical-align:middle;border-top:1.5px dashed var(--ink-soft);opacity:.7}
.panel-chart-svg.is-animating .panel-chart-bar rect{transform-box:fill-box;transform-origin:50% 100%;animation:uxBar .75s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--i,0) * 40ms)}
.panel-chart-svg.is-animating .panel-chart-avg{stroke-dashoffset:0;animation:uxFade .6s .6s both}
@keyframes uxBar{from{transform:scaleY(0)}to{transform:scaleY(1)}}

/* ── Facturación: venta ── */
.pos-grid.is-entering .pos-tile{animation:uxTileIn .5s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--i,0) * 26ms)}
@keyframes uxTileIn{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}
#cart-app .pos-tile{transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
#cart-app .pos-tile:hover{transform:translateY(-3px);box-shadow:0 12px 24px -14px color-mix(in srgb,var(--brown-deep) 55%,transparent);border-color:var(--line-strong)}
#cart-app .pos-tile:active{transform:scale(.97);box-shadow:none}
#cart-app .pos-tile.is-out:hover{transform:none;box-shadow:none}
#cart-app .pos-tile-img{height:76px;transition:transform .35s ease}
#cart-app .pos-tile:hover .pos-tile-img{transform:scale(1.04)}
#cart-app .pos-tile:not(.is-out)::after{transition:transform .2s ease,background .2s ease}
#cart-app .pos-tile:not(.is-out):hover::after{transform:rotate(90deg) scale(1.08)}
.pos-tile.is-added{border-color:var(--yellow);box-shadow:0 0 0 3px color-mix(in srgb,var(--yellow) 30%,transparent)}
.pos-tile.is-added .pos-tile-count{animation:uxPop .45s cubic-bezier(.34,1.6,.64,1)}
.cart-line.is-new{animation:uxLineIn .6s cubic-bezier(.16,1,.3,1)}
@keyframes uxLineIn{0%{background:color-mix(in srgb,var(--yellow) 30%,transparent);transform:translateX(-6px)}100%{background:transparent;transform:none}}
.cart-line{border-radius:10px;padding-inline:6px;margin-inline:-6px}
#pos-total{display:inline-block;font-family:"Sora","Manrope",sans-serif;font-size:1.45rem;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.is-bump{animation:uxBump .42s cubic-bezier(.34,1.6,.64,1)}
@keyframes uxBump{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}
.pos-cobrar{width:100%;min-height:52px;font-size:1.05rem;border-radius:14px;margin-top:6px;font-variant-numeric:tabular-nums}
.pos-cobrar.has-total{box-shadow:0 10px 22px -12px color-mix(in srgb,var(--yellow) 90%,transparent)}
.pos-empty{padding:18px 4px 10px}
.ux-fly{
  position:fixed;z-index:9999;width:16px;height:16px;border-radius:50%;pointer-events:none;
  background:var(--yellow);box-shadow:0 0 0 4px color-mix(in srgb,var(--yellow) 30%,transparent),0 6px 14px rgba(0,0,0,.25);
}
#pos-mobile-cart-summary{display:inline-block}
.mobile-cart-bar{border-radius:16px;background:var(--brown-deep);box-shadow:0 12px 28px -10px rgba(0,0,0,.45)}
.mobile-cart-bar-cta{background:var(--yellow);color:var(--lime-ink);opacity:1;padding:6px 12px;border-radius:999px;font-weight:800}

@media (prefers-reduced-motion:reduce){
  .ux-status i,.view.is-entering,#owner-app .panel-hero::after,.panel-hero-spark .spark-line,.panel-hero-spark .spark-area,
  .panel-hero-spark .spark-dot,.panel-chart-svg.is-animating .panel-chart-bar rect,.panel-chart-svg.is-animating .panel-chart-avg,
  .pos-grid.is-entering .pos-tile,.pos-tile.is-added .pos-tile-count,.cart-line.is-new,.is-bump{animation:none}
  .panel-hero-spark .spark-line{stroke-dashoffset:0}
  .panel-hero-spark .spark-area{opacity:1}
  #owner-app .panel-hero::after{display:none}
  .nav-glider,.nav-item .nav-icon,#cart-app .pos-tile,#cart-app .pos-tile-img,#owner-app .panel-mini,#owner-app .ux-stat{transition:none}
  #cart-app .pos-tile:hover,#owner-app .panel-mini:hover,#owner-app .ux-stat:hover{transform:none}
}

/* Asistente de primer uso: «Cargar un respaldo» en vez de configurar de cero. */
.setup-restore{margin-top:18px;padding-top:16px;border-top:1px dashed var(--line);text-align:center}
.setup-restore .muted{margin:0 0 10px}
.setup-restore label.btn{cursor:pointer}
.setup-restore label.is-busy{pointer-events:none;opacity:.7}

/* ═══ Administrativo en el celular (v3.2): barra de pestañas + hoja «Más» ═══
   Reemplaza el panel lateral con grupos plegados (ver ownerNav.js). En
   escritorio no cambia nada: todo esto vive dentro del media query. */
.owner-tabbar,.owner-more{display:none}
@media (max-width:820px){
  #owner-app .sidebar{align-items:center;min-height:58px;padding:8px 16px}
  #owner-app .sidebar-brand{padding:0;align-items:center;flex-wrap:nowrap;gap:8px}
  #owner-app .sidebar-brand .brand-name{font-size:1.15rem;line-height:1}
  #owner-app .sidebar-brand span:not(.brand-name){margin:0;font-size:.68rem;padding:3px 9px}
  #owner-app .sidebar-toggle,#owner-app .sidebar-backdrop,
  #owner-app .sidebar-nav,#owner-app .sidebar-footer{display:none !important}
  #owner-app .app-content{padding-bottom:calc(84px + env(safe-area-inset-bottom))}
  .owner-tabbar{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:30;gap:4px;
    background:var(--brown-deep);box-shadow:0 -2px 14px rgba(0,0,0,.2);
    padding:6px 6px calc(6px + env(safe-area-inset-bottom));
  }
  .owner-tab{
    flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    padding:8px 2px;border:0;border-radius:12px;background:none;color:var(--cream);cursor:pointer;
    font:inherit;font-size:.74rem;font-weight:700;line-height:1.15;-webkit-tap-highlight-color:transparent;
    transition:background .25s ease,color .25s ease,transform .12s ease;
  }
  .owner-tab span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .owner-tab .nav-icon{width:21px;height:21px;opacity:.9}
  .owner-tab:active{transform:scale(.94)}
  .owner-tab.is-active{background:var(--yellow);color:var(--lime-ink)}

  .owner-more{display:block;position:fixed;inset:0;z-index:60}
  .owner-more[hidden]{display:none}
  .owner-more-backdrop{position:absolute;inset:0;background:rgba(10,12,18,.5);opacity:0;transition:opacity .25s ease}
  .owner-more.is-open .owner-more-backdrop{opacity:1}
  .owner-more-panel{
    position:absolute;left:0;right:0;bottom:0;max-height:86vh;display:flex;flex-direction:column;
    background:var(--bg);border-radius:22px 22px 0 0;box-shadow:0 -10px 40px rgba(0,0,0,.25);
    transform:translateY(100%);transition:transform .32s cubic-bezier(.16,1,.3,1);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .owner-more.is-open .owner-more-panel{transform:none}
  .owner-more-handle{width:42px;height:5px;border-radius:3px;background:var(--line-strong);margin:10px auto 2px}
  .owner-more-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 18px 10px}
  .owner-more-kicker{margin:0;font-size:.7rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
  .owner-more-title{margin:2px 0 0;font-size:1.3rem;font-weight:800;letter-spacing:-.02em}
  .owner-more-close{width:38px;height:38px;border-radius:50%;border:1px solid var(--line);background:var(--surface);color:var(--ink);font-size:1rem;cursor:pointer}
  .owner-more-body{overflow-y:auto;overscroll-behavior:contain;padding:4px 14px 14px;-webkit-overflow-scrolling:touch}
  .owner-more-group + .owner-more-group{margin-top:14px}
  .owner-more-label{margin:0 4px 8px;font-size:.72rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
  .owner-more-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
  .owner-more-item{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;min-height:82px;padding:10px 6px;
    border:1px solid var(--line);border-radius:16px;background:var(--surface);color:var(--ink);cursor:pointer;
    font:inherit;font-size:.8rem;font-weight:700;line-height:1.2;text-align:center;-webkit-tap-highlight-color:transparent;
    transition:transform .12s ease,border-color .2s ease;
  }
  .owner-more-item .nav-icon{width:22px;height:22px;opacity:1;color:var(--ink)}
  .owner-more-item:active{transform:scale(.95)}
  .owner-more-item.is-active{border-color:var(--yellow);background:color-mix(in srgb,var(--yellow) 18%,var(--surface))}
  .owner-more-foot{display:flex;align-items:center;gap:8px;padding:12px 18px 14px;border-top:1px solid var(--line)}
  .owner-more-foot .btn{margin:0;display:inline-flex;align-items:center;justify-content:center;height:38px;line-height:1}
  .owner-more-arche{
    margin-left:auto;width:64px;aspect-ratio:1600/243;background:var(--ink-soft);opacity:.7;
    -webkit-mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
    mask:url(../img/brand/arche-wordmark-hd.png) center/contain no-repeat;
  }
  html.owner-more-lock,html.owner-more-lock body{overflow:hidden}
}
@media (prefers-reduced-motion:reduce){
  .owner-tab,.owner-more-backdrop,.owner-more-panel,.owner-more-item{transition:none}
}

/* Botón sol/luna de la barra superior del administrativo (theme.js). Muestra
   el modo AL QUE se cambia: luna en modo claro, sol en modo oscuro. */
.ux-theme{
  position:relative;flex:none;width:36px;height:36px;border-radius:50%;display:grid;place-items:center;
  border:1px solid var(--line);background:var(--surface);color:var(--ink);cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.ux-theme:hover{border-color:var(--line-strong);background:var(--surface-2)}
.ux-theme:focus-visible{outline:2px solid var(--yellow);outline-offset:2px}
.ux-theme svg{position:absolute;width:19px;height:19px;transition:opacity .3s ease,transform .45s cubic-bezier(.34,1.4,.64,1)}
.ux-theme .ux-theme-sun{opacity:0;transform:rotate(-90deg) scale(.5)}
.ux-theme.is-dark .ux-theme-sun{opacity:1;transform:none}
.ux-theme.is-dark .ux-theme-moon{opacity:0;transform:rotate(90deg) scale(.5)}
.ux-theme.is-spinning{animation:uxBump .42s cubic-bezier(.34,1.6,.64,1)}
/* El cambio de tema se ve como un fundido corto, no de golpe. */
html.theme-fading,html.theme-fading *{transition:background-color .35s ease,color .35s ease,border-color .35s ease !important}
@media (prefers-reduced-motion:reduce){.ux-theme svg{transition:none}.ux-theme.is-spinning{animation:none}html.theme-fading,html.theme-fading *{transition:none !important}}

/* ═══ Facturación v3.3 (fase 1 de ANALISIS-SISTEMA-COMPLETO.md) ═══
   Hoja de cobro: pago en botones, «¿con cuánto paga?» con billetes y vuelto,
   cliente plegado. En la computadora el recibo sigue a la derecha; en el
   celular se esconde y sube desde abajo (pos.js, openCobro). */
.cobro-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.cobro-head h2{margin:0}
.cobro-handle,.cobro-close{display:none}
.cobro-block{margin:14px 0 4px}
.cobro-label{margin:0 0 8px;font-size:.78rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-soft)}
.pay-buttons{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:8px}
.pay-btn{
  min-height:48px;padding:8px 10px;border-radius:14px;border:1.5px solid var(--line);background:var(--surface);
  color:var(--ink);font:inherit;font-weight:800;font-size:.95rem;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:border-color .15s ease,background .15s ease,transform .1s ease;
}
.pay-btn:active{transform:scale(.97)}
.pay-btn.is-active{border-color:var(--yellow);background:color-mix(in srgb,var(--yellow) 22%,var(--surface));box-shadow:0 0 0 2px color-mix(in srgb,var(--yellow) 35%,transparent)}
.cash-chips{display:flex;flex-wrap:wrap;gap:8px}
.cash-chip{
  flex:1 1 auto;min-width:64px;min-height:44px;padding:6px 12px;border-radius:999px;border:1.5px solid var(--line);
  background:var(--surface);color:var(--ink);font:inherit;font-weight:800;font-size:.92rem;cursor:pointer;font-variant-numeric:tabular-nums;
  -webkit-tap-highlight-color:transparent;transition:border-color .15s ease,background .15s ease;
}
.cash-chip.is-active{border-color:var(--ink);background:var(--ink);color:var(--bg)}
.cash-otro{width:100%;margin-top:8px;font-size:1.05rem}
.vuelto{
  display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-top:10px;padding:12px 16px;border-radius:14px;
  background:color-mix(in srgb,var(--sage) 14%,var(--surface));border:1px solid color-mix(in srgb,var(--sage) 40%,transparent);
}
.vuelto span{font-weight:800;color:var(--sage)}
.vuelto strong{display:inline-block;font-family:"Sora","Manrope",sans-serif;font-size:1.6rem;font-weight:800;color:var(--sage);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.vuelto.is-short{background:var(--danger-bg);border-color:color-mix(in srgb,var(--danger) 40%,transparent)}
.vuelto.is-short span,.vuelto.is-short strong{color:var(--danger-on-bg)}
.cobro-extras{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 6px}
.cobro-extras .chip{min-height:38px}
#pos-cliente-wrap{margin-top:6px;animation:uxViewIn .3s cubic-bezier(.16,1,.3,1)}
.recibo-vuelto{margin:-4px 0 10px;font-size:1rem;text-align:center;color:var(--ink-soft)}
.recibo-vuelto strong{color:var(--sage);font-size:1.25rem}
.cobro-backdrop{display:none}
.owner-tab{position:relative}
.owner-tab-badge{
  position:absolute;top:4px;left:calc(50% + 6px);min-width:18px;height:18px;padding:0 5px;border-radius:999px;
  background:var(--orange);color:#fff;font-style:normal;font-size:.68rem;font-weight:800;line-height:18px;text-align:center;
}
.owner-tab-badge.is-dot{min-width:9px;width:9px;height:9px;padding:0;top:7px}
.owner-more-item{position:relative}
.owner-more-item .owner-tab-badge{top:8px;left:auto;right:8px}

@media (max-width:820px){
  /* Barra de abajo nueva (ownerNav.js) en vez de la vieja; Ayuda/Salir pasan a «Más». */
  #cart-app .sidebar-nav,#cart-app .sidebar-footer{display:none !important}
  #cart-app .sidebar{min-height:52px;padding:8px 16px;align-items:center}
  #cart-app .sidebar-brand{padding:0;flex-wrap:nowrap;align-items:center;gap:8px}
  #cart-app .app-content{padding-bottom:calc(84px + env(safe-area-inset-bottom))}
  /* En la venta el título sobra (la pestaña ya lo dice): más productos a la vista. */
  #cart-app .view[data-view="pos-venta"] > h1{display:none}
  #cart-app .app-topbar{padding-top:10px}
  /* La barra del total pasa a ser «Cobrar». */
  .mobile-cart-bar{bottom:calc(76px + env(safe-area-inset-bottom))}
  .mobile-cart-bar-cta svg{transform:rotate(180deg)}
  /* Hoja de cobro. */
  #cart-app #pos-cobro{
    position:fixed;left:0;right:0;bottom:0;z-index:61;margin:0;max-height:90vh;overflow-y:auto;overscroll-behavior:contain;
    border-radius:22px 22px 0 0;border:0;box-shadow:0 -12px 40px rgba(0,0,0,.28);
    padding:4px 18px calc(18px + env(safe-area-inset-bottom));
    transform:translateY(105%);visibility:hidden;transition:transform .32s cubic-bezier(.16,1,.3,1),visibility 0s linear .32s;
  }
  #cart-app #pos-cobro.is-open{transform:none;visibility:visible;transition:transform .32s cubic-bezier(.16,1,.3,1),visibility 0s}
  .cobro-head{position:sticky;top:-4px;z-index:2;background:var(--surface);padding:22px 0 10px;margin:0 -2px}
  .cobro-handle{display:block;position:absolute;top:9px;left:50%;width:42px;height:5px;margin-left:-21px;border-radius:3px;background:var(--line-strong)}
  .pay-btn{font-size:.9rem;padding:8px 6px}
  .cobro-close{display:grid;place-items:center;width:38px;height:38px;border-radius:50%;border:1px solid var(--line);background:var(--surface);color:var(--ink);font-size:1rem;cursor:pointer}
  .cobro-backdrop{display:block;position:fixed;inset:0;z-index:60;background:rgba(10,12,18,.5);opacity:0;transition:opacity .25s ease}
  .cobro-backdrop[hidden]{display:none}
  .cobro-backdrop.is-open{opacity:1}
  html.cobro-lock,html.cobro-lock body{overflow:hidden}
  .pos-cobrar{position:sticky;bottom:0;z-index:1}
  #cart-app .view[data-view="pos-venta"]{padding-bottom:110px}
}
@media (prefers-reduced-motion:reduce){
  #cart-app #pos-cobro,.cobro-backdrop,.pay-btn,.cash-chip{transition:none}
  #pos-cliente-wrap{animation:none}
}
/* Recibo final: solo el texto del recibo respeta saltos de línea (antes todo el
   recuadro lo hacía y los espacios del HTML dejaban huecos en blanco), y en el
   celular no queda debajo de la barra de pestañas. */
.recibo-modal{white-space:normal}
.recibo-modal pre{white-space:pre-wrap}
@media (max-width:820px){.recibo-modal{max-height:calc(100vh - 120px - env(safe-area-inset-bottom));bottom:calc(84px + env(safe-area-inset-bottom))}}

/* ═══ Facturación v3.4 (fase 2 de ANALISIS-SISTEMA-COMPLETO.md) ═══ */
/* Opciones de un plato en botones (posMenu.js): grilla de 2 columnas, el
   grupo listo se marca con ✓ y la hoja baja sola al siguiente obligatorio. */
.opts-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;padding:4px 0 2px}
.opts-group .opts-option{
  position:relative;min-height:52px;border:1.5px solid var(--line);border-top:1.5px solid var(--line);border-radius:14px;
  padding:8px 12px;gap:6px;background:var(--surface);flex-direction:column;align-items:flex-start;justify-content:center;
  transition:border-color .15s ease,background .15s ease,transform .1s ease;-webkit-tap-highlight-color:transparent;
}
.opts-group .opts-option:first-of-type{border-top:1.5px solid var(--line)}
.opts-group .opts-option input{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px}
.opts-group .opts-option:active{transform:scale(.97)}
.opts-group .opts-option:has(input:checked){border-color:var(--yellow);background:color-mix(in srgb,var(--yellow) 20%,var(--surface));box-shadow:0 0 0 2px color-mix(in srgb,var(--yellow) 30%,transparent)}
.opts-group .opts-option:has(input:focus-visible){outline:2px solid var(--yellow);outline-offset:2px}
.opts-option-name{line-height:1.2}
.opts-option-price{font-size:.82rem}
.opts-group{scroll-margin-top:8px}
.opts-done{display:none;margin-left:6px;color:var(--sage);font-weight:800}
.opts-group.is-done .opts-done{display:inline}
.opts-group.is-done{border-color:color-mix(in srgb,var(--sage) 45%,var(--line))}
.opts-footer{background:var(--surface);margin:0 -22px -22px;padding:12px 22px 16px;border-top:1px solid var(--line);z-index:2}
.opts-footer #opts-add{white-space:nowrap;flex:1}
@media (max-width:820px){
  .modal-overlay.opts-modal{align-items:flex-end;padding:0}
  .opts-modal .modal-box{width:100%;max-width:none;max-height:92vh;border-radius:22px 22px 0 0;margin:0}
  .opts-modal .modal-box-body{padding-bottom:calc(22px + env(safe-area-inset-bottom))}
  .opts-footer{margin-bottom:calc(-22px - env(safe-area-inset-bottom));padding-bottom:calc(16px + env(safe-area-inset-bottom))}
}
/* Lista compacta cuando no hay fotos (posMenu.js, .is-list). */
.pos-grid.is-list{grid-template-columns:1fr;gap:6px}
.pos-grid.is-list .pos-tile{min-height:58px;flex-direction:row;align-items:center;justify-content:space-between;gap:12px;padding:10px 54px 10px 14px}
.pos-grid.is-list .pos-tile-name{flex:1}
.pos-grid.is-list .pos-tile-price{width:auto;flex:none}
.pos-grid.is-list .pos-tile:not(.is-out)::after{top:50%;bottom:auto;transform:translateY(-50%)}
.pos-grid.is-list .pos-tile:not(.is-out):hover::after{transform:translateY(-50%) rotate(90deg)}
.pos-grid.is-list .pos-tile-count{top:50%;right:48px;transform:translateY(-50%)}
.pos-grid.is-list .pos-tile-flag{position:absolute;left:14px;bottom:4px;font-size:.62rem}
@media (min-width:821px){.pos-grid.is-list{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Recibo por WhatsApp. */
.btn-wa{background:#25D366;border-color:#25D366;color:#062b14;font-weight:800;text-decoration:none;display:inline-flex;align-items:center;justify-content:center}
.btn-wa:hover{background:#1ebe5a;border-color:#1ebe5a;color:#062b14}
.recibo-modal-actions{flex-wrap:wrap}
/* Historial por días. */
.hist-range{margin:-4px 0 14px}
.hist-day-row td{background:var(--surface-2);padding:10px 12px;font-size:.92rem}
@media (max-width:820px){
  #tabla-pos-historial .hist-day-row{display:block;border:0;background:none;margin:14px 0 6px}
  #tabla-pos-historial .hist-day-row td{display:block;padding:0 4px;background:none;text-align:left;border:0 !important;box-shadow:none !important;position:static !important;font-size:1rem}
  #tabla-pos-historial .hist-day-row td::before{display:none}
}
@media (prefers-reduced-motion:reduce){.opts-group .opts-option{transition:none}}
.opts-option-price:empty{display:none}

/* Configuración → Licencia y plan (fase 3, licenciaConfig.js). */
.lic-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}
.lic-head h2{margin-bottom:8px}
.lic-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:10px}
.lic-grid > div{display:flex;flex-direction:column;gap:2px;padding:10px 12px;border:1px solid var(--line);border-radius:12px;background:var(--surface)}
.lic-k{font-size:.72rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-soft)}
.lic-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.04em}
.lic-renovar{margin-top:6px}
.lic-renovar summary{cursor:pointer;font-weight:700}
.lic-renovar[open]{display:flex;flex-direction:column;gap:10px;align-items:flex-start}
.lic-renovar textarea{width:100%;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.82rem}

/* ═══ Fase 4: pestañas de grupo (hubs.js) ═══
   Arriba de Existencias/Entradas/Compras…, Ganancias/Gastos/Tendencias, etc. */
.hub-tabs{
  display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;margin:0 0 16px;padding:4px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:999px;width:max-content;max-width:100%;
}
.hub-tabs::-webkit-scrollbar{display:none}
.hub-tab{
  flex:none;padding:8px 16px;border:0;border-radius:999px;background:none;color:var(--ink-soft);cursor:pointer;
  font:inherit;font-size:.9rem;font-weight:700;white-space:nowrap;transition:background .2s ease,color .2s ease;
}
.hub-tab:hover{color:var(--ink)}
.hub-tab.is-active{background:var(--surface);color:var(--ink);box-shadow:var(--shadow-sm),0 0 0 1px var(--line)}
.hub-tab:focus-visible{outline:2px solid var(--yellow);outline-offset:2px}
@media (max-width:820px){.hub-tabs{width:auto;margin:0 0 14px}}

/* ═══ Lista de arranque del Panel (fase 4, dashboard.js) ═══ */
.arranque{margin:0 0 18px;padding:18px 20px;border-radius:18px;border:1px solid color-mix(in srgb,var(--yellow) 45%,var(--line));
  background:linear-gradient(135deg,color-mix(in srgb,var(--yellow) 12%,var(--surface)),var(--surface) 60%)}
.arranque-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
.arranque-head h2{margin:2px 0 0}
.arranque-kicker{margin:0;font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.arranque-meta{display:flex;align-items:center;gap:10px;white-space:nowrap}
.arranque-bar{height:6px;border-radius:3px;background:var(--surface-2);margin:12px 0 6px;overflow:hidden}
.arranque-bar i{display:block;height:100%;background:var(--yellow);border-radius:3px;transition:width .6s cubic-bezier(.16,1,.3,1)}
.arranque-steps{list-style:none;margin:0;padding:0}
.arranque-steps li{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px dashed var(--line)}
.arranque-steps li:last-child{border-bottom:0}
.arranque-steps li > div{flex:1;min-width:0;display:flex;flex-direction:column}
.arranque-steps li span:not(.arranque-check){font-size:.86rem;color:var(--ink-soft)}
.arranque-check{flex:none;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;border:2px solid var(--line-strong);font-weight:800;font-size:.85rem}
.arranque-steps li.is-done .arranque-check{background:var(--sage);border-color:var(--sage);color:#fff}
.arranque-steps li.is-done strong{color:var(--ink-soft);text-decoration:line-through;text-decoration-color:var(--line-strong)}
/* Configuración → Módulos en paquetes (fase 4, modulos.js). */
.mod-pack{border:1px solid var(--line);border-radius:16px;padding:6px 14px 8px;margin-bottom:12px;background:var(--surface)}
.mod-pack-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 10px;padding:8px 0 6px;border-bottom:1px dashed var(--line);margin-bottom:4px}
.mod-pack-head strong{font-size:1rem}
.mod-pack-head .muted{flex:1;font-size:.84rem}
.mod-pack .mod-item{border:0;border-radius:0;padding:10px 0;background:none;border-bottom:1px solid var(--line)}
.mod-pack .mod-item:last-child{border-bottom:0}

/* ═══ Campana de avisos (fase 4, avisos.js) ═══ */
.avisos-wrap{position:relative;display:inline-flex}
.avisos-btn .ux-theme-sun,.avisos-btn .ux-theme-moon{display:none}
.avisos-count{
  position:absolute;top:-4px;right:-4px;min-width:18px;height:18px;padding:0 5px;border-radius:999px;
  background:var(--yellow);color:var(--lime-ink);font-style:normal;font-size:.68rem;font-weight:800;line-height:18px;text-align:center;
  box-shadow:0 0 0 2px var(--bg);
}
.avisos-btn.has-urgent .avisos-count{background:var(--danger);color:#fff}
.avisos-panel{
  position:absolute;top:calc(100% + 8px);right:0;z-index:50;width:min(340px,calc(100vw - 32px));max-height:70vh;overflow-y:auto;
  padding:10px;border-radius:16px;border:1px solid var(--line);background:var(--surface);box-shadow:0 18px 40px -16px rgba(0,0,0,.35);
  animation:uxViewIn .25s cubic-bezier(.16,1,.3,1);
}
.avisos-title{margin:2px 6px 8px;font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.aviso{display:flex;gap:10px;align-items:flex-start;width:100%;text-align:left;padding:10px;border:0;border-radius:12px;background:none;color:var(--ink);font:inherit;cursor:pointer}
.aviso:hover{background:var(--surface-2)}
.aviso-icon{flex:none;width:32px;height:32px;border-radius:10px;display:grid;place-items:center;background:var(--surface-2);font-size:1rem}
.aviso-urgente .aviso-icon{background:var(--danger-bg)}
.aviso strong{display:block;font-size:.92rem}
.aviso small{display:block;color:var(--ink-soft);font-size:.8rem;margin-top:2px}
@media (max-width:820px){.avisos-panel{position:fixed;top:120px;left:16px;right:16px;width:auto}}
.recibo-modal-actions .btn{white-space:nowrap}
/* Hoja de opciones: sin hueco debajo de la barra «Agregar» (estaba quedando el
   relleno inferior del cuerpo del modal por debajo de la barra fija). */
.opts-modal .modal-box-body{padding-bottom:0}
.opts-modal .opts-footer{margin-bottom:0;padding-bottom:calc(16px + env(safe-area-inset-bottom))}
.opts-group .opts-option-name{flex:none}

/* Caja (v3.9): píldora de estado en la barra superior y montos rápidos del fondo. */
.ux-caja{display:inline-flex;align-items:center;gap:7px;padding:5px 11px;border-radius:999px;border:1px solid color-mix(in srgb,var(--amber) 45%,var(--line));
  background:var(--amber-bg);color:var(--amber);font:inherit;font-size:.76rem;font-weight:800;cursor:pointer;white-space:nowrap}
.ux-caja i{width:7px;height:7px;border-radius:50%;background:var(--amber)}
.ux-caja.is-open{border-color:color-mix(in srgb,var(--sage) 40%,var(--line));background:color-mix(in srgb,var(--sage) 12%,var(--surface));color:var(--sage)}
.ux-caja.is-open i{background:var(--sage)}
.caja-fondo-chips{margin:8px 0 12px}
@media (max-width:820px){#cart-app .ux-clock{display:none}.ux-who-text .muted{white-space:nowrap}}

/* ═══ Búsqueda global (v3.10, buscar.js) ═══ */
.buscar-overlay{position:fixed;inset:0;z-index:1100;display:flex;align-items:flex-start;justify-content:center;padding:12vh 16px 16px;
  background:color-mix(in srgb,var(--brown-deep) 45%,transparent);opacity:0;transition:opacity .18s ease}
.buscar-overlay[hidden]{display:none}
.buscar-overlay.is-open{opacity:1}
.buscar-box{width:min(620px,100%);max-height:70vh;display:flex;flex-direction:column;border-radius:18px;background:var(--surface);
  border:1px solid var(--line);box-shadow:0 30px 60px -20px rgba(0,0,0,.45);overflow:hidden;transform:translateY(-8px);transition:transform .25s cubic-bezier(.16,1,.3,1)}
.buscar-overlay.is-open .buscar-box{transform:none}
.buscar-input{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--line)}
.buscar-input svg{width:20px;height:20px;color:var(--ink-soft);flex:none}
.buscar-input input{flex:1;border:0;outline:0;background:none;font:inherit;font-size:1.05rem;color:var(--ink);padding:4px 0;box-shadow:none}
.buscar-input input:focus{box-shadow:none}
.buscar-input kbd{font:700 .7rem/1 inherit;padding:4px 7px;border-radius:6px;border:1px solid var(--line);color:var(--ink-soft)}
.buscar-res{overflow-y:auto;padding:8px}
.buscar-g{margin:10px 8px 4px;font-size:.7rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.buscar-item{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;padding:10px 12px;border:0;border-radius:10px;
  background:none;color:var(--ink);font:inherit;font-weight:600;text-align:left;cursor:pointer}
.buscar-item small{color:var(--ink-soft);font-weight:600;white-space:nowrap}
.buscar-item.is-sel,.buscar-item:hover{background:color-mix(in srgb,var(--yellow) 20%,var(--surface))}
.buscar-vacio{margin:14px;color:var(--ink-soft)}
@media (max-width:820px){.buscar-overlay{padding-top:70px}.buscar-input kbd{display:none}}
@media (prefers-reduced-motion:reduce){.buscar-overlay,.buscar-box{transition:none}}
@media (max-width:820px){#owner-app .ux-clock{display:none}#owner-app .app-topbar-date{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}}

/* Rangos de fecha de un toque (v3.11, rangos.js). */
.rango-chips{margin:0 0 12px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
.rango-chips::-webkit-scrollbar{display:none}
.rango-chips .chip{flex:none}
.rango-form:not(:has(:not([hidden]):is(label,.f,.field,button,select))){display:none}

/* Explicaciones cortas en el celular (v3.12, intros.js). */
@media (max-width:820px){
  .intro:not(.is-open){display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;cursor:pointer;position:relative}
  .intro:not(.is-open)::after{content:'… más';position:absolute;right:0;bottom:0;padding-left:28px;font-weight:700;color:var(--ink);
    background:linear-gradient(90deg,transparent,var(--bg) 26px)}
  .intro.is-open{cursor:pointer}
}
/* Formularios «Crear…» plegados en el celular (v3.12, intros.js). */
@media (max-width:820px){
  .plegable:not(.is-open) > :not(h2:first-child){display:none !important}
  .plegable > h2:first-child{cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:0;color:var(--ink)}
  .plegable > h2:first-child::before{content:'+';order:2;flex:none;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;background:var(--yellow);color:var(--lime-ink);font-size:1.2rem;font-weight:800;transition:transform .25s ease}
  .plegable.is-open > h2:first-child{margin-bottom:12px}
  .plegable.is-open > h2:first-child::before{transform:rotate(45deg)}
}
.pin-mask{border:1px dashed var(--line-strong);background:none;border-radius:8px;padding:4px 10px;font:inherit;font-variant-numeric:tabular-nums;letter-spacing:.12em;color:var(--ink);cursor:pointer}
/* Botones al pie de una ventana: si no caben, bajan de línea (antes se cortaban). */
.modal-actions{flex-wrap:wrap}
.modal-actions .btn{white-space:nowrap}
.ux-status{position:relative}
.ux-pend{position:absolute;top:-7px;right:-7px;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--amber);color:#fff;font-size:.66rem;font-weight:800;line-height:18px;text-align:center;box-shadow:0 0 0 2px var(--bg)}
.ux-status.has-failed .ux-pend{background:var(--danger)}
@media (max-width:820px){
  #cart-app .sidebar{gap:10px}
  #cart-app .sidebar-brand{flex:0 1 auto;min-width:0;overflow:hidden}
  #cart-app .sidebar-brand .brand-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #cart-app .offline-banner{margin:0 0 0 auto;flex:0 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:6px 10px}
}

/* v3.15: cifras en el celular — las tarjetas .stat de Ganancias, Merma, Gastos y
   Caja ya no se apilan de a una a todo el ancho (~170 px cada una): van de a
   dos (o tres si caben), compactas y alineadas a la izquierda. */
@media (max-width:620px){
  .grid-3:has(> .stat){grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px}
  .grid-3 > .stat{padding:10px 12px;text-align:left}
  .grid-3 > .stat .label{font-size:.76rem}
  .grid-3 > .stat .value{font-size:1.15rem}
}
/* Bloqueo por inactividad con el teclado del login (v3.17). */
.lock-form{display:flex;flex-direction:column;align-items:center}
.lock-form .login-pinpad{max-width:252px}
.lock-form.is-shake{animation:lxShake .5s cubic-bezier(.36,.07,.19,.97)}
#lock-screen .login-box h1{margin-bottom:4px}
#lock-screen #lock-who{text-align:center;margin:0 0 16px;font-weight:700}
@media (max-width:820px){.dash-head .panel-shortcuts{display:none}}
#lock-screen .login-box > p.muted:last-child{text-align:center}
