/* ==========================================================================
   ORBIT WEB · design-all.css   —  CAPA DE DISEÑO COMPLETA EN UN SOLO FICHERO
   ==========================================================================
   Los 16 ficheros de css/ concatenados en el orden correcto (tokens y base
   primero). Es lo mismo, en un archivo: se copia UNO y se enlaza UNO.

   INTEGRACIÓN — dos pasos, sin nada más:
     1. copiar este fichero a  css/design-all.css  del portal
     2. en index.html, DESPUÉS de orbit.css, orbit-web.css, citas.css,
        reservar.css, venta.css y afinado.css, y antes de los <script>:

           <link rel="stylesheet" href="css/design-all.css">

   Nada de clases nuevas en <body>. Nada de JS. orbit.css no se toca.
   Marcha atrás: quitar ese único <link>.

   Para MANTENER el diseño usa los 16 ficheros sueltos de css/ (están
   comentados uno por uno con el valor original de producción y el porqué de
   cada cambio). Este fichero es solo para desplegar.

   Generado desde: design-tokens.css, design-base.css, design-hoy.css, design-agenda.css, design-calendario.css, design-sesiones.css, design-reservar.css, design-venta.css, design-tarjeta.css, design-perfiles.css, design-login.css, design-caja.css, design-productos.css, design-impresiones.css, design-clima.css, design-ticket.css
   ========================================================================== */


/* ══════════════════════════════════════════════════════════════════════════
   design-tokens.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   ORBIT WEB · design-tokens.css     [capa 1 de 3]
   Cargar DESPUÉS de orbit.css / orbit-web.css / citas.css / reservar.css /
   venta.css / afinado.css, y ANTES de design-base.css.

   PROCEDENCIA — leído, no supuesto:
   · La paleta NO se redeclara. orbit.css:root ya define --blue-500 #3B82F6,
     --blue-600 #2563EB, --blue-700 #1D4ED8, --purple-500 #8B5CF6,
     --purple-600 #7C3AED, --emerald-500/600, --red-500, --amber-500,
     --cyan-500, --pink-500, --gray-100..900, --bg-alpha, --border-color,
     --text-color. Aquí solo se ALIASAN para poder usarlas con color-mix.
   · Lo único nuevo son las escalas que el portal no tenía tokenizadas:
     espaciado, radios, elevación, tipografía, movimiento y objetivo táctil.
   · Prefijo propio --jzd-* / .jzd-*. NO se usa ow-* : orbit-web.css, citas.css
     y afinado.css ya tienen 129 clases con ese prefijo y pisarlas rompería
     componentes en producción.
   ========================================================================== */

:root{
  /* ---- Alias de la paleta REAL de orbit.css (no son colores nuevos) ---- */
  --jzd-blue:var(--blue-500);
  --jzd-blue-hi:var(--blue-600);
  --jzd-violet:var(--purple-500);
  --jzd-violet-hi:var(--purple-600);
  --jzd-green:var(--emerald-500);
  --jzd-green-hi:var(--emerald-600);
  --jzd-red:var(--red-500);
  --jzd-amber:var(--amber-500);
  --jzd-cyan:var(--cyan-500);
  --jzd-pink:var(--pink-500);
  --jzd-ink:var(--gray-900);
  --jzd-ink-2:var(--gray-700);
  --jzd-ink-3:var(--gray-500);   /* secundario — sube del 400 por contraste, ver NOTAS §2 */
  --jzd-ink-4:var(--gray-400);

  /* Naranjas literales de citas.css (no están en :root de orbit.css) */
  --jzd-hoy:#FF6803;             /* día de hoy en el calendario */
  --jzd-soli:#F97316;            /* solicitud del sitio web */
  --jzd-soli-hi:#EA580C;

  /* ---- Vidrio: los MISMOS valores que ya usan .cita-card / .an-kpi ---- */
  --jzd-glass:rgba(255,255,255,.40);
  --jzd-glass-hi:rgba(255,255,255,.55);
  --jzd-glass-brd:rgba(255,255,255,.10);
  --jzd-edge:inset 0 1px 0 rgba(255,255,255,.25);   /* el filo de luz de Orbit */

  /* ---- Espaciado (base 4) — NUEVO: el portal usaba 2,4,6,7,8,9,10,12,14 ---- */
  --jzd-s1:4px;  --jzd-s2:6px;  --jzd-s3:8px;  --jzd-s4:10px; --jzd-s5:12px;
  --jzd-s6:14px; --jzd-s7:16px; --jzd-s8:20px; --jzd-s9:24px; --jzd-s10:32px;

  /* ---- Radios — NUEVO. Los reales en uso: 6,8,10,12,14,16,20,22,24 ---- */
  --jzd-r-xs:8px;  --jzd-r-sm:10px; --jzd-r-md:12px; --jzd-r-lg:14px;
  --jzd-r-xl:16px; --jzd-r-2xl:20px; --jzd-r-3xl:24px; --jzd-r-pill:999px;

  /* ---- Elevación — NUEVO: escala explícita en lugar de sombras ad-hoc ---- */
  --jzd-e1:0 2px 8px rgba(0,0,0,.04);
  --jzd-e2:0 4px 16px rgba(0,0,0,.08);
  --jzd-e3:0 8px 24px rgba(0,0,0,.10);
  --jzd-e4:0 16px 44px rgba(0,0,0,.16);
  --jzd-e-blue:0 4px 18px rgba(59,130,246,.40);      /* = .btn-primary de orbit.css */
  --jzd-e-blue-hi:0 6px 20px rgba(59,130,246,.50);   /* = .btn-primary:hover */
  --jzd-e-green:0 4px 12px rgba(16,185,129,.30);
  --jzd-e-amber:0 4px 14px rgba(245,158,11,.24);
  --jzd-e-violet:0 4px 14px rgba(139,92,246,.35);

  /* ---- Tipografía — NUEVO. La pila la fija afinado.css; aquí solo tamaños ---- */
  --jzd-fs-1:8px;  --jzd-fs-2:9px;  --jzd-fs-3:10px; --jzd-fs-4:11px;
  --jzd-fs-5:12px; --jzd-fs-6:13px; --jzd-fs-7:15px; --jzd-fs-8:17px;
  --jzd-fs-9:21px; --jzd-fs-10:26px; --jzd-fs-11:34px;
  --jzd-track-wide:.06em;
  --jzd-track-eyebrow:.1em;

  /* ---- Movimiento. .2s es la transición estándar de Orbit ---- */
  --jzd-ease:cubic-bezier(.16,1,.3,1);    /* la de owSubir / confirmAppear */
  --jzd-t-fast:150ms; --jzd-t:200ms; --jzd-t-slow:250ms;

  /* ---- Táctil — NUEVO. Mínimo AA de 44px ---- */
  --jzd-tap:44px;
  --jzd-tap-lg:54px;
}

/* --------------------------------------------------------------------------
   MODO OSCURO — body.dark-mode (la clase que ya usa js/ui.js)
   Solo se reajusta lo que no llega a AA sobre el fondo #070D1F–#0D1B3F de
   orbit-web.css. La paleta de orbit.css no cambia de valor en dark, así que
   estos 8 alias son la única corrección de contraste de toda la entrega.
   -------------------------------------------------------------------------- */
body.dark-mode{
  --jzd-blue:#60A5FA;     /* #3B82F6 sobre #0A1633 no llega a 4.5:1 */
  --jzd-blue-hi:#3B82F6;
  --jzd-violet:#A78BFA;
  --jzd-green:#34D399;
  --jzd-red:#F87171;
  --jzd-amber:#FBBF24;
  --jzd-hoy:#FF8A3D;
  --jzd-soli:#FB923C;

  --jzd-ink:rgba(255,255,255,.92);
  --jzd-ink-2:rgba(255,255,255,.80);
  --jzd-ink-3:rgba(255,255,255,.60);
  --jzd-ink-4:rgba(255,255,255,.40);

  --jzd-glass:rgba(255,255,255,.05);
  --jzd-glass-hi:rgba(255,255,255,.10);
  --jzd-glass-brd:rgba(255,255,255,.06);
  --jzd-edge:inset 0 1px 0 rgba(255,255,255,.04);

  --jzd-e1:0 2px 8px rgba(0,0,0,.30);
  --jzd-e2:0 4px 16px rgba(0,0,0,.40);
  --jzd-e3:0 8px 26px rgba(0,0,0,.50);
  --jzd-e4:0 18px 48px rgba(0,0,0,.60);
}

/* afinado.css ya declara el bloque prefers-reduced-motion global
   (*{animation-duration:.01ms!important…}). No se repite aquí. */


/* ══════════════════════════════════════════════════════════════════════════
   design-base.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   ORBIT WEB · design-base.css     [capa 2 de 3]
   Refinamientos transversales sobre las primitivas REALES de Orbit, más los
   pocos componentes que el portal no tenía.

   LO QUE ESTA CAPA NO HACE (ya existe y funciona — no se duplica):
   · scrollbars, :focus-visible, ::selection, prefers-reduced-motion,
     pila tipográfica con respaldo local  → afinado.css §2–§5
   · anillo degradado de avatar                → afinado.css .ow-avatar-anillo
   · chips de etapa / tarjeta / atasco         → afinado.css .chip-etapa/.chip-tarjeta/.chip-atasco
   · estados vacío y de error                  → afinado.css .ow-vacio* / .ow-error*
   · ticket 80mm e impresión                   → venta.css #ticketVenta + @page
   Cero !important en toda la entrega.
   ========================================================================== */

/* ==========================================================================
   1 · REFINAMIENTOS de primitivas existentes
   ========================================================================== */

/* --- .cita-card: el hover sube 1px y la sombra salta de golpe. Se suaviza y
       se le da una escala de elevación coherente. Valores originales:
       hover → background .55 / translateY(-1px) / 0 4px 16px rgba(0,0,0,.08) --- */
.cita-card{ transition:background var(--jzd-t) linear, transform var(--jzd-t) var(--jzd-ease), box-shadow var(--jzd-t) var(--jzd-ease); }
.cita-card:hover{ box-shadow:var(--jzd-e2), var(--jzd-edge); }

/* --- .cita-meta: era var(--gray-400) = #9CA3AF. Sobre el vidrio claro
       (rgba(255,255,255,.4) sobre #E3EAF8) mide 3.1:1 — por debajo de AA.
       Sube a --gray-500 #6B7280 → 4.8:1. Mismo tono, un paso más oscuro. --- */
.cita-meta{ color:var(--jzd-ink-3); font-size:var(--jzd-fs-4); gap:var(--jzd-s3); row-gap:var(--jzd-s1); }
.cita-client{ font-size:var(--jzd-fs-6); letter-spacing:-.01em; }

/* --- .cita-date-badge: 44×44 con el día en 16px. La hora del portal es
       "9:00" + "AM", que a 16px se corta. Se ensancha y se tabula. --- */
.cita-date-badge{ box-shadow:var(--jzd-e-blue), inset 0 1px 0 rgba(255,255,255,.26); }
.cita-date-day{ font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
.cita-date-month{ letter-spacing:.08em; }

/* --- .btn-primary: se mantiene el degradado y la sombra exactos. Solo se
       garantiza el objetivo táctil de 44px (era padding:12px → ~41px). --- */
.btn-primary{ min-height:var(--jzd-tap); }
.btn-primary:active{ transform:translateY(0) scale(.99); }

/* --- .finput: 9px 12px da ~36px de alto. Sube a 44px sin tocar el foco
       (el ring azul de orbit.css/afinado.css se queda tal cual). --- */
.finput{ min-height:var(--jzd-tap); padding:var(--jzd-s4) var(--jzd-s5); }
textarea.finput{ min-height:72px; padding:var(--jzd-s4) var(--jzd-s5); line-height:1.5; }
.citas-search{ min-height:var(--jzd-tap); }

/* --- .seg-btn: 36px de alto. Sube a 44 y el activo gana el degradado azul
       en vez del blanco translúcido, para que se lea de lejos. --- */
.seg-btn{ min-height:var(--jzd-tap); }
.seg-btn.active{ color:#fff; background:linear-gradient(135deg,var(--blue-500),var(--blue-600)); box-shadow:var(--jzd-e-blue); }
body.dark-mode .seg-btn.active{ color:#fff; }

/* --- .an-kpi-value: 20px es correcto en el panel de la extensión, pero el
       portal se ve de pie y de lejos. HOY lo sube a 26 (ver design-hoy.css). --- */
.an-kpi{ transition:transform var(--jzd-t) var(--jzd-ease), box-shadow var(--jzd-t) var(--jzd-ease); }
.an-kpi:hover{ box-shadow:var(--jzd-e3); }
.an-kpi-label{ letter-spacing:var(--jzd-track-wide); color:var(--jzd-ink-4); }

/* --- .t-badge / .cita-tag: 2px 8px es muy apretado para tocar y leer. --- */
.t-badge, .cita-tag{ padding:3px 9px; letter-spacing:.01em; }

/* --- .numpad-key: 48px ya es táctil; solo se tabula y se le da el radio de
       la escala para que no compita con el resto. --- */
.numpad-key{ font-variant-numeric:tabular-nums; }

/* --- .pill: 4px 10px → alto real ~24px. Es un control, sube a 32. --- */
.pill{ min-height:32px; display:inline-flex; align-items:center; }

/* --- .sec-label: la etiqueta de sección gana el tracking de eyebrow. --- */
.sec-label{ letter-spacing:var(--jzd-track-eyebrow); }

/* ==========================================================================
   2 · COMPONENTES NUEVOS (no existen en producción)
   ========================================================================== */

/* --- Punto de sede. citas.css colorea las pastillas del calendario por sede
       (.lavega azul / .bonao morado) pero no hay una etiqueta reutilizable
       para las listas de agenda, HOY y sesiones. --- */
.jzd-sede{
  display:inline-flex; align-items:center; gap:5px;
  font-size:var(--jzd-fs-4); font-weight:600; color:var(--jzd-ink-3);
  white-space:nowrap;
}
.jzd-sede::before{
  content:''; width:6px; height:6px; border-radius:50%; flex:none;
  background:linear-gradient(135deg,var(--blue-500),var(--blue-600));
}
.jzd-sede[data-sede*="Bonao"]::before{ background:linear-gradient(135deg,var(--purple-500),var(--purple-600)); }

/* --- Números tabulares a demanda. Varias cifras del portal (códigos, horas,
       contadores de columna) todavía bailan al actualizarse. --- */
.jzd-num{ font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1; }

/* --- Código de cliente. Se lee en voz alta por teléfono: tabular + tracking
       positivo para que JZ-2483 no se confunda con JZ-2463. --- */
.jzd-cod{
  font-variant-numeric:tabular-nums; letter-spacing:.06em;
  font-weight:800; color:var(--jzd-ink-2);
}

/* --- Entrada escalonada. orbit-web.css tiene owSubir para pantallas enteras;
       faltaba una cascada para listas.
       DELIBERADO: la entrada anima SOLO el desplazamiento, nunca la opacidad.
       El portal corre en pantallas de recepción que pasan horas en segundo
       plano; cuando el navegador congela el reloj de animación de una pestaña
       oculta, un fade desde opacity:0 deja el contenido invisible al volver.
       Animando solo transform, el peor caso es que la cascada no se vea —
       jamás que la agenda del día aparezca en blanco. --- */
@keyframes jzd-sube{ from{ transform:translateY(8px); } to{ transform:none; } }
.jzd-in{ animation:jzd-sube 360ms var(--jzd-ease) both; }
.jzd-stagger > *{ animation:jzd-sube 360ms var(--jzd-ease) both; }
.jzd-stagger > *:nth-child(1){ animation-delay:20ms }
.jzd-stagger > *:nth-child(2){ animation-delay:55ms }
.jzd-stagger > *:nth-child(3){ animation-delay:90ms }
.jzd-stagger > *:nth-child(4){ animation-delay:125ms }
.jzd-stagger > *:nth-child(5){ animation-delay:160ms }
.jzd-stagger > *:nth-child(6){ animation-delay:195ms }
.jzd-stagger > *:nth-child(7){ animation-delay:230ms }
.jzd-stagger > *:nth-child(n+8){ animation-delay:265ms }

/* --- Esqueleto de carga. venta.css y citas.css muestran texto "cargando…";
       un esqueleto evita el salto de layout al llegar los datos. --- */
.jzd-skel{
  border-radius:var(--jzd-r-sm);
  background:linear-gradient(90deg,var(--jzd-glass) 25%,rgba(0,0,0,.06) 50%,var(--jzd-glass) 75%);
  background-size:280% 100%; animation:jzd-brillo 1.4s linear infinite;
}
body.dark-mode .jzd-skel{ background:linear-gradient(90deg,var(--jzd-glass) 25%,rgba(255,255,255,.10) 50%,var(--jzd-glass) 75%); background-size:280% 100%; }
@keyframes jzd-brillo{ to{ background-position:-180% 0; } }

/* --- Utilidades de fila/columna. El portal resuelve esto con margin inline
       en varias vistas; con gap sobreviven los reordenamientos. --- */
.jzd-row{ display:flex; align-items:center; gap:var(--jzd-s3); }
.jzd-row--wrap{ flex-wrap:wrap; }
.jzd-between{ display:flex; align-items:center; justify-content:space-between; gap:var(--jzd-s3); }
.jzd-grow{ flex:1; min-width:0; }


/* ══════════════════════════════════════════════════════════════════════════
   design-hoy.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-hoy.css · La portada del día.
   Base real: afinado.css §"VISTA HOY" — .hoy-vista, .hoy-hero (sobre .an-hero
   de orbit.css), .hoy-cuerpo, .hoy-contadores > .an-kpi, .hoy-card,
   .hoy-card-fila, .hoy-hora-badge, .hoy-chips, .hoy-prime, .hoy-prime-linea.
   Los chips (.chip-etapa/.chip-tarjeta/.chip-atasco) ya existen: no se tocan.
   ========================================================================== */

/* ---------- Hero ----------
   .an-hero ya trae el degradado #3B82F6→#A78BFA y dos halos ::before/::after.
   Se le añade grano (le quita el look de plantilla), se sube el saludo de
   21px a 26 y se garantiza que el avatar no se solape en pantalla angosta. */
.hoy-hero{ padding:var(--jzd-s9) var(--jzd-s8) var(--jzd-s8); }
.hoy-hero .an-hero-title{ font-size:var(--jzd-fs-10); letter-spacing:-.02em; line-height:1.12; }
.hoy-hero .an-hero-subtitle{ font-size:var(--jzd-fs-5); color:rgba(255,255,255,.82); }
.hoy-hero .jzd-grano{
  position:absolute; inset:0; pointer-events:none; opacity:.12;
  background-image:radial-gradient(rgba(255,255,255,.9) .5px,transparent .5px);
  background-size:4px 4px;
}
.hoy-hero-avatar{ width:54px; height:54px; }
.hoy-hero-avatar .ow-avatar-ini{ font-size:var(--jzd-fs-8); }

/* ---------- Contadores ----------
   .hoy-contadores baja el .an-kpi a padding 12 y el valor a 18px. Para una
   pantalla que se lee de pie eso es pequeño: sube a 20/26 y cada KPI recibe
   un lavado de color propio para distinguirse sin romper "un solo acento". */
.hoy-contadores{ gap:var(--jzd-s5); }
.hoy-contadores .an-kpi{ padding:var(--jzd-s8); }
.hoy-contadores .an-kpi-value{ font-size:var(--jzd-fs-10); letter-spacing:-.02em; line-height:1; }
.hoy-contadores .an-kpi-icon{ width:38px; height:38px; font-size:var(--jzd-fs-8); margin-bottom:var(--jzd-s4); }
.hoy-contadores .an-kpi::after{
  content:''; position:absolute; inset:0; pointer-events:none; opacity:.55;
  background:radial-gradient(120% 130% at 0% 0%, color-mix(in srgb,var(--_t,var(--blue-500)) 15%,transparent), transparent 58%);
}
.hoy-contadores .an-kpi > *{ position:relative; z-index:1; }
.hoy-contadores .an-kpi[data-accent="blue"]{ --_t:var(--blue-500); }
.hoy-contadores .an-kpi[data-accent="purple"]{ --_t:var(--purple-500); }
.hoy-contadores .hoy-kpi-alerta{ --_t:var(--jzd-soli); }

/* pie de contexto — línea nueva, opcional */
.jzd-kpi-pie{ font-size:var(--jzd-fs-3); font-weight:600; color:var(--jzd-ink-3); margin-top:var(--jzd-s2); }

/* ---------- Línea de tiempo del día ----------
   Hoy las .hoy-card son cinco tarjetas idénticas apiladas. Un riel continuo
   entre las horas convierte la lista en una jornada. Se hace con un ::before
   en la propia .hoy-card: cero markup nuevo. */
.jzd-tl{ display:flex; flex-direction:column; gap:var(--jzd-s5); }
.jzd-tl .hoy-card{ position:relative; }
.jzd-tl .hoy-card::before{
  content:''; position:absolute; left:41px; top:calc(100% - 2px); height:var(--jzd-s5);
  width:2px; background:rgba(0,0,0,.08); z-index:0;
}
body.dark-mode .jzd-tl .hoy-card::before{ background:rgba(255,255,255,.10); }
.jzd-tl .hoy-card:last-child::before{ display:none; }

/* la pastilla de hora toma el color de la sede, como las del calendario */
.hoy-hora-badge{ width:58px; height:52px; border-radius:var(--jzd-r-lg); box-shadow:var(--jzd-e-blue), inset 0 1px 0 rgba(255,255,255,.26); }
.hoy-card[data-sede*="Bonao"] .hoy-hora-badge{
  background:linear-gradient(135deg,var(--purple-500),var(--purple-600));
  box-shadow:var(--jzd-e-violet), inset 0 1px 0 rgba(255,255,255,.26);
}
.hoy-hora-num{ font-size:var(--jzd-fs-8); }
.hoy-hora-ampm{ font-size:var(--jzd-fs-2); letter-spacing:.1em; }

/* el nombre del cliente es lo que se busca con la vista: 12px → 17px */
.hoy-card .cita-client{ font-size:var(--jzd-fs-8); font-weight:800; letter-spacing:-.015em; }

/* ---------- Brief de ambiente ----------
   .hoy-prime ya es la franja violeta con las líneas 🎵/🧸. Lo que le falta es
   ser un BLOQUE con cabecera: es la razón de existir de la vista HOY.
   Se le añade el título por ::before — cero markup nuevo. */
.hoy-prime{
  gap:var(--jzd-s2); padding:var(--jzd-s4) var(--jzd-s5);
  border-radius:var(--jzd-r-md);
  background:linear-gradient(120deg, rgba(139,92,246,.09), rgba(59,130,246,.06));
  border-color:rgba(139,92,246,.16);
  box-shadow:var(--jzd-edge);
}
.hoy-prime::before{
  content:'✨ AMBIENTE PARA SU LLEGADA';
  font-size:var(--jzd-fs-2); font-weight:800; letter-spacing:var(--jzd-track-eyebrow);
  color:var(--purple-600); margin-bottom:var(--jzd-s1);
}
body.dark-mode .hoy-prime{ background:linear-gradient(120deg, rgba(139,92,246,.12), rgba(59,130,246,.07)); }
body.dark-mode .hoy-prime::before{ color:var(--jzd-violet); }
.hoy-prime-linea{ font-size:var(--jzd-fs-5); color:var(--jzd-ink-2); }
.hoy-prime-linea strong,.hoy-prime-linea b{ color:var(--jzd-ink); font-weight:800; }

/* ---------- Responsive ---------- */
@media (max-width:860px){
  .hoy-contadores{ grid-template-columns:1fr 1fr; }
  .hoy-contadores > *:nth-child(3){ grid-column:span 2; }
  .hoy-hero .an-hero-title{ font-size:var(--jzd-fs-9); }
}
@media (max-width:560px){
  .hoy-contadores{ grid-template-columns:1fr; }
  .hoy-contadores > *:nth-child(3){ grid-column:auto; }
  .hoy-contadores .an-kpi{ display:flex; align-items:center; gap:var(--jzd-s6); padding:var(--jzd-s6); }
  .hoy-contadores .an-kpi-icon{ margin-bottom:0; }
  .jzd-tl .hoy-card::before{ left:37px; }
  .hoy-hora-badge{ width:50px; height:46px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-agenda.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-agenda.css · Los dos momentos emocionales del flujo.
   Base real: citas.css — .ow-agenda-controles, .ow-agenda-card (sobre
   .cita-card), .ow-agenda-fila, .ow-hora-badge, .ow-btn-etapa, .ow-etapa-fin,
   .ow-etapas + .ow-etapas-riel + .ow-etapas-linea + .ow-etapa/.ow-etapa-dot/
   .ow-etapa-label, .ow-persona/.ow-persona-titulo, .ow-bloque-solicitudes,
   .ow-solicitud-* , .ow-btn-confirmar / .ow-btn-rechazar, .ow-confirmada-*.
   TODO se refina en su sitio: ni un selector nuevo para lo que ya existe.
   ========================================================================== */

.ow-agenda-controles{ gap:var(--jzd-s4); padding:var(--jzd-s4) var(--jzd-s7) var(--jzd-s2); }

/* ---------- Tarjeta de cita ----------
   .ow-agenda-card hereda .cita-card. Se le añade un filo de estado a la
   izquierda: verde confirmada, naranja solicitud, rojo rechazada. Un dato
   de estado que hoy solo vive en el chip de la derecha. */
.ow-agenda-card{ padding:var(--jzd-s5) var(--jzd-s6); gap:var(--jzd-s4); overflow:hidden; }
.ow-agenda-card::before{
  content:''; position:absolute; left:0; top:12px; bottom:12px; width:3px;
  border-radius:0 3px 3px 0; background:transparent;
}
.ow-agenda-card{ position:relative; }
.ow-agenda-card[data-estado="confirmada"]::before{ background:linear-gradient(180deg,var(--emerald-500),var(--emerald-600)); }
.ow-agenda-card[data-estado="rechazada"]::before{ background:var(--red-500); }
.ow-agenda-fila{ gap:var(--jzd-s5); }

/* la pastilla de hora sigue a la sede, igual que en el calendario */
.ow-hora-badge{ width:58px; height:48px; border-radius:var(--jzd-r-lg); }
.ow-hora-badge .cita-date-day{ font-size:var(--jzd-fs-7); }
.ow-agenda-card[data-sede*="Bonao"] .ow-hora-badge{
  background:linear-gradient(135deg,var(--purple-500),var(--purple-600));
  box-shadow:var(--jzd-e-violet), inset 0 1px 0 rgba(255,255,255,.26);
}

/* .ow-btn-etapa: 11px con padding 6/12 → ~28px de alto. Es el botón que más
   se toca de la vista; sube a 40 sin cambiar su degradado azul→violeta. */
.ow-btn-etapa{ min-height:40px; padding:0 var(--jzd-s6); font-size:var(--jzd-fs-5); border-radius:var(--jzd-r-sm); }
.ow-etapa-fin{ font-size:var(--jzd-fs-4); }

/* ---------- Barra de 7 etapas ----------
   PROBLEMA REAL: .ow-etapa-label es font-size:8px y hay siete. En una tarjeta
   de 320px eso deja ~38px por etiqueta y todas se truncan con ellipsis; el
   nombre activo compite con los seis apagados.
   SOLUCIÓN SIN TOCAR EL MARKUP: los siete puntos y el riel se quedan (el mapa
   completo sigue visible); por debajo de 700px solo la etapa activa conserva
   su etiqueta, y crece. El JS que pinta .hecha/.activa no cambia. */
.ow-etapas{ margin:var(--jzd-s3) 0 var(--jzd-s1); padding:0 var(--jzd-s2); }
.ow-etapas-riel{ height:3px; top:4px; border-radius:3px; }
.ow-etapas-linea{ height:3px; top:4px; transition:width var(--jzd-t-slow) var(--jzd-ease); }
.ow-etapa-dot{ width:8px; height:8px; }
.ow-etapa.activa .ow-etapa-dot{ transform:scale(1.35); }
.ow-etapa-label{ font-size:var(--jzd-fs-2); margin-top:5px; color:var(--jzd-ink-4); }
.ow-etapa.hecha .ow-etapa-label{ color:var(--jzd-ink-3); }
.ow-etapa.activa .ow-etapa-label{ font-size:var(--jzd-fs-4); font-weight:800; color:var(--purple-600); }
body.dark-mode .ow-etapa.activa .ow-etapa-label{ color:var(--jzd-violet); }

@media (max-width:700px){
  .ow-etapa:not(.activa) .ow-etapa-label{
    /* la etiqueta se retira pero el punto se queda: el mapa de 7 no se pierde */
    position:absolute; width:1px; height:1px; overflow:hidden;
    clip-path:inset(50%); white-space:nowrap;
  }
  .ow-etapa.activa{ flex:2.4; }
  .ow-etapa.activa .ow-etapa-label{ overflow:visible; max-width:none; }
}

/* ---------- Personalización ---------- */
.ow-persona{ padding:var(--jzd-s4) var(--jzd-s5); border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-5); color:var(--jzd-ink-2); }
.ow-persona-titulo{ color:var(--purple-600); }
body.dark-mode .ow-persona-titulo{ color:var(--jzd-violet); }

/* ---------- Bloque de solicitudes ---------- */
.ow-bloque-solicitudes .smart-title{ letter-spacing:var(--jzd-track-eyebrow); }
/* contador junto al título — elemento nuevo */
.jzd-cuenta{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:22px; height:22px; padding:0 7px; border-radius:var(--jzd-r-pill);
  font-size:var(--jzd-fs-3); font-weight:800; font-variant-numeric:tabular-nums;
  color:#fff; background:var(--jzd-soli); box-shadow:0 3px 10px rgba(249,115,22,.4);
}

/* ---------- Tarjeta SOLICITUD NUEVA ----------
   El borde 2px dashed naranja y el fondo al 5% se quedan (era acertado).
   Se añade un barrido de luz muy lento: 5,5s de ciclo con el 68% en reposo.
   Dice "esto acaba de llegar" sin parpadear. */
.ow-solicitud-card{ position:relative; overflow:hidden; padding:var(--jzd-s6); border-radius:var(--jzd-r-xl); box-shadow:0 10px 28px -12px rgba(249,115,22,.28), var(--jzd-edge); }
.ow-solicitud-card::after{
  content:''; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:linear-gradient(105deg,transparent 38%,rgba(249,115,22,.13) 50%,transparent 62%);
  transform:translateX(-100%); animation:jzd-barrido 5.5s var(--jzd-ease) infinite;
}
@keyframes jzd-barrido{ 0%,68%{ transform:translateX(-100%) } 100%{ transform:translateX(100%) } }
.ow-solicitud-card > *{ position:relative; z-index:1; }
.ow-solicitud-header{ padding-bottom:var(--jzd-s4); }
.ow-solicitud-titulo{ font-size:var(--jzd-fs-4); }
.ow-solicitud-codigo{ font-size:var(--jzd-fs-3); padding:4px 10px; font-variant-numeric:tabular-nums; }
.ow-solicitud-cuerpo{ gap:var(--jzd-s5); }

/* Confirmar y Rechazar tenían el mismo peso visual. Confirmar es lo que pasa
   el 90% de las veces: se queda con el degradado y el tamaño; Rechazar baja. */
.ow-solicitud-acciones{ gap:var(--jzd-s4); margin-top:var(--jzd-s1); }
.ow-btn-confirmar{
  min-height:var(--jzd-tap-lg); font-size:var(--jzd-fs-6); border-radius:var(--jzd-r-md);
  background:linear-gradient(135deg,var(--emerald-500),var(--emerald-600));
  box-shadow:var(--jzd-e-green);
}
.ow-btn-confirmar:hover{ background:linear-gradient(135deg,#34D399,var(--emerald-500)); box-shadow:0 6px 18px rgba(16,185,129,.4); }
.ow-btn-rechazar{ min-height:var(--jzd-tap-lg); font-size:var(--jzd-fs-5); border-radius:var(--jzd-r-md); }

/* ---------- Microcelebración al confirmar ----------
   .ow-confirmada-card ya entra con confirmAppear. Se le añade un halo que se
   expande una vez: confirmar una sesión es el momento bueno del día. */
.ow-confirmada-card{ border-radius:var(--jzd-r-2xl); }
.ow-confirmada-card::after{
  content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  animation:jzd-halo 1.1s var(--jzd-ease) both;
}
.ow-confirmada-card{ position:relative; }
@keyframes jzd-halo{
  from{ box-shadow:0 0 0 0 rgba(16,185,129,.45); }
  to{ box-shadow:0 0 0 26px rgba(16,185,129,0); }
}
.ow-confirmada-titulo{ font-size:var(--jzd-fs-7); }
.ow-confirmada-texto{ color:var(--jzd-ink-3); }


/* ══════════════════════════════════════════════════════════════════════════
   design-calendario.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-calendario.css · Densidad elegante.
   Base real: citas.css — .ow-cal-nav, .ow-cal-mes, .ow-cal-flecha,
   .ow-cal-grid, .ow-cal-dow, .ow-cal-dia (+.fuera/.hoy/.abierto),
   .ow-cal-num, .ow-cal-pastilla (+.lavega/.bonao), .ow-cal-puntos,
   .ow-cal-punto, .ow-cal-mas, .ow-cal-dia-panel, .ow-cal-cita.
   ========================================================================== */

.ow-cal-nav{ padding:var(--jzd-s4) var(--jzd-s5); }
.ow-cal-mes{ font-size:var(--jzd-fs-7); text-transform:capitalize; }
.ow-cal-flecha{ min-width:var(--jzd-tap); min-height:38px; border-radius:var(--jzd-r-sm); }

/* ---------- Celdas ----------
   VALOR REAL LEÍDO: .ow-cal-dia = min-height:52px; padding:4px; radio 12px.
   CAMBIO: 52 → 84px y padding 4 → 7px. Justificación: con 52px de alto y
   pastillas de 8px, un día con 4 citas desborda y descuadra la fila entera
   (agosto 26 en los datos reales tiene 4). A 84px caben 3 pastillas legibles
   más el "+N más" sin recortes. En móvil vuelve a 56 y las pastillas se
   resumen en puntos (ver más abajo). */
.ow-cal-grid{ gap:var(--jzd-s2); }
.ow-cal-dow{ font-size:var(--jzd-fs-3); letter-spacing:var(--jzd-track-eyebrow); }
.ow-cal-dia{ min-height:84px; padding:7px 7px 8px; border-radius:var(--jzd-r-lg); gap:3px; }
.ow-cal-dia:hover{ box-shadow:var(--jzd-e2), inset 0 1px 0 rgba(255,255,255,.3); }
.ow-cal-num{ font-size:var(--jzd-fs-5); font-variant-numeric:tabular-nums; }

/* ---------- HOY ----------
   VALOR REAL LEÍDO: .ow-cal-dia.hoy = border-left:3px solid #FF6803.
   CAMBIO: se conserva el filo izquierdo (es la firma de Orbit) y se le suma
   un borde completo tenue + halo naranja. Justificación: en una rejilla de 7
   columnas con gap de 6px, un filo de 3px en el borde izquierdo se confunde
   con la separación entre celdas; a dos metros no se distingue. El naranja
   #FF6803 sigue siendo de uso exclusivo de "hoy" en esta vista. */
.ow-cal-dia.hoy{
  border-color:rgba(255,104,3,.45);
  box-shadow:0 0 0 1px rgba(255,104,3,.35), 0 8px 22px -10px rgba(255,104,3,.4), inset 0 1px 0 rgba(255,255,255,.3);
  background:color-mix(in srgb,var(--jzd-hoy) 6%,rgba(255,255,255,.4));
}
body.dark-mode .ow-cal-dia.hoy{ background:color-mix(in srgb,var(--jzd-hoy) 10%,rgba(255,255,255,.05)); }
.ow-cal-dia.abierto{ box-shadow:0 0 0 3px rgba(59,130,246,.18), var(--jzd-e2), inset 0 1px 0 rgba(255,255,255,.3); }

/* ---------- Pastillas ----------
   VALOR REAL LEÍDO: .ow-cal-pastilla = font-size:8px; padding:1px 5px.
   CAMBIO: 8 → 10px, padding 2px 6px, y se añade la SEDE al lado de la hora.
   Justificación: hoy las tres pastillas del 18 de agosto son visualmente
   idénticas (solo cambia el tono de fondo). Con la sede escrita, el estudio
   ve de un golpe que ese día hay trabajo en las dos sedes. */
.ow-cal-pastilla{
  font-size:var(--jzd-fs-3); padding:2px 6px; border-radius:6px;
  display:flex; align-items:center; gap:4px; font-variant-numeric:tabular-nums;
}
.ow-cal-pastilla b{ font-weight:800; }
.ow-cal-pastilla span{ font-weight:600; opacity:.8; overflow:hidden; text-overflow:ellipsis; }
/* solicitud sin confirmar: naranja punteado, se distingue de una confirmada */
.ow-cal-pastilla.tentative{
  background:rgba(249,115,22,.12); color:var(--jzd-soli-hi);
  border:1px dashed rgba(249,115,22,.35);
}
body.dark-mode .ow-cal-pastilla.tentative{ color:var(--jzd-soli); }
.ow-cal-punto{ width:6px; height:6px; }
.ow-cal-mas{ font-size:var(--jzd-fs-3); margin-top:auto; font-weight:700; }

/* ---------- Leyenda (bloque nuevo) ----------
   Las pastillas ya se coloreaban por sede pero nada lo explicaba: el color
   era el único mensaje, lo que incumple AA. */
.jzd-cal-leyenda{
  display:flex; align-items:center; flex-wrap:wrap; gap:var(--jzd-s7);
  padding:0 var(--jzd-s5) var(--jzd-s4);
  font-size:var(--jzd-fs-4); color:var(--jzd-ink-3);
}

.ow-cal-dia-panel{ gap:var(--jzd-s4); margin-top:var(--jzd-s3); }

/* ---------- Móvil ----------
   Por debajo de 560px la celda vuelve a 56px y las pastillas se reducen a
   puntos de color en fila. La densidad no se pierde: se resume. Sigues viendo
   cuántas citas hay y en qué sedes en una celda pequeña. */
@media (max-width:560px){
  .ow-cal-grid{ gap:4px; }
  .ow-cal-dia{ min-height:56px; padding:5px 4px; flex-direction:row; flex-wrap:wrap; align-content:flex-start; gap:3px; }
  .ow-cal-num{ width:100%; font-size:var(--jzd-fs-4); }
  .ow-cal-pastilla{ width:7px; height:7px; padding:0; border-radius:50%; overflow:hidden; color:transparent; border:none; }
  .ow-cal-pastilla.lavega{ background:linear-gradient(135deg,var(--blue-500),var(--blue-600)); }
  .ow-cal-pastilla.bonao{ background:linear-gradient(135deg,var(--purple-500),var(--purple-600)); }
  .ow-cal-pastilla.tentative{ background:var(--jzd-soli); }
  .ow-cal-mas{ font-size:var(--jzd-fs-2); margin:0; }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-sesiones.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-sesiones.css · Tablero de etapas, SIN drag.
   Base real: afinado.css §"VISTA SESIONES" — .ses-vista, .ses-cabecera,
   .ses-titulo, .sede-pill-group/.sede-pill, .ses-tablero, .ses-col
   [data-etapa], .ses-col-head/-nombre/-dot/-badge/-lista/-vacia, .ses-card,
   .ses-card-nombre/-meta, .ses-btn-avanzar, .ses-confirm* (modal de avance).
   Los siete valores de data-etapa ya existen y sus colores están definidos:
   agendada · sesion · seleccion · cliente_eligio · edicion · lista · entregada.
   ========================================================================== */

.ses-cabecera{ padding:var(--jzd-s6) var(--jzd-s7); }
.ses-titulo{ font-size:var(--jzd-fs-7); letter-spacing:var(--jzd-track-wide); }
.sede-pill{ min-height:34px; padding:0 var(--jzd-s5); font-size:var(--jzd-fs-4); }

/* ---------- Columnas ----------
   VALOR REAL LEÍDO: .ses-col = flex:0 0 240px; fondo rgba(0,0,0,.02).
   CAMBIO: 240 → 262px y padding interior 8 → 10px. Justificación: con 240px,
   la .ses-card-meta ("18/08 · 09:00 · Sesión Smash Cake · Jenzz La Vega") se
   parte en un sitio distinto en cada tarjeta y el carril se ve desordenado.
   Se añade además scroll-snap para que la columna quede alineada al soltar.
   NO se añade drag: los .ses-btn-avanzar siguen siendo el único camino. */
.ses-tablero{ gap:var(--jzd-s5); padding:var(--jzd-s5) var(--jzd-s7); scroll-snap-type:x proximity; }
.ses-col{ flex:0 0 262px; border-radius:var(--jzd-r-lg); scroll-snap-align:start; }
.ses-col-head{ padding:var(--jzd-s5); border-radius:var(--jzd-r-lg) var(--jzd-r-lg) 0 0; }
.ses-col-nombre{ font-size:var(--jzd-fs-5); letter-spacing:.02em; }
.ses-col-dot{ width:9px; height:9px; }
.ses-col-badge{ min-width:20px; height:20px; display:inline-flex; align-items:center; justify-content:center; font-size:var(--jzd-fs-3); font-variant-numeric:tabular-nums; }
.ses-col-lista{ padding:var(--jzd-s4); gap:var(--jzd-s4); }

/* una columna vacía deja de gritar: el badge pasa a gris */
.ses-col-badge[data-cero="true"]{ background:rgba(0,0,0,.07); color:var(--jzd-ink-4); }
body.dark-mode .ses-col-badge[data-cero="true"]{ background:rgba(255,255,255,.08); }

/* el vacío ocupa el carril completo con borde punteado, así el tablero se lee
   como siete carriles del mismo largo y no como columnas de altos aleatorios */
.ses-col-vacia{
  flex:1; display:grid; place-items:center; padding:var(--jzd-s9) var(--jzd-s4);
  font-size:var(--jzd-fs-4); border-radius:var(--jzd-r-md);
  border:1.5px dashed rgba(0,0,0,.07);
}
body.dark-mode .ses-col-vacia{ border-color:rgba(255,255,255,.07); }

/* ---------- Mini-tarjeta ---------- */
.ses-card{ padding:var(--jzd-s5) var(--jzd-s6); border-radius:var(--jzd-r-lg); gap:var(--jzd-s3); }
.ses-card:hover{ box-shadow:var(--jzd-e2), var(--jzd-edge); }
.ses-card-nombre{ font-size:var(--jzd-fs-6); font-weight:800; letter-spacing:-.01em; white-space:normal; }
.ses-card-meta{ font-size:var(--jzd-fs-4); color:var(--jzd-ink-3); gap:var(--jzd-s2) var(--jzd-s3); font-variant-numeric:tabular-nums; }
.ses-btn-avanzar{ min-height:36px; padding:0 var(--jzd-s6); font-size:var(--jzd-fs-4); border-radius:var(--jzd-r-md); }

/* recordatorio de la regla de negocio más fácil de olvidar y más cara de
   romper: las etapas nunca retroceden */
.jzd-ses-pie{
  display:flex; align-items:center; justify-content:space-between; gap:var(--jzd-s3);
}
.jzd-ses-nota{ font-size:var(--jzd-fs-2); font-weight:700; color:var(--jzd-ink-4); letter-spacing:.02em; }

@media (max-width:560px){ .ses-col{ flex:0 0 84vw; } }


/* ══════════════════════════════════════════════════════════════════════════
   design-reservar.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-reservar.css · Asistente por pasos y parrilla de horas.
   Base real: reservar.css — .rv-vista, .rv-pasos, .rv-paso-dot (+.activo/
   .hecho), .rv-paso-linea (+.hecha), .rv-nav, .rv-atras, .rv-serv-grid,
   .rv-resumen, .rv-res-fila/-lbl/-val, .rv-exito*, .rv-codigo*.
   Parrilla de horas: .time-slot (+.selected/.occupied) y .tgrid de orbit.css.
   Franjas mañana/tarde: .pay-btn / .pay-lbl / .pay-ico de orbit.css.
   ========================================================================== */

/* ---------- Pasos ----------
   VALOR REAL LEÍDO: .rv-paso-dot = 26×26, solo el número, sin etiqueta.
   CAMBIO: 26 → 32px y se añade una etiqueta debajo (elemento nuevo
   .jzd-paso-et). Justificación: seis círculos numerados no dicen en qué
   consiste cada paso; el empleado cuenta bolitas. En móvil las etiquetas se
   ocultan y quedan los círculos, como ahora. */
.rv-pasos{ padding:var(--jzd-s4) 0 var(--jzd-s2); align-items:flex-start; }
.rv-paso-dot{ width:32px; height:32px; font-size:var(--jzd-fs-5); }
.rv-paso-linea{ max-width:40px; margin-top:15px; }

.jzd-paso{ display:flex; flex-direction:column; align-items:center; gap:5px; flex:none; }
.jzd-paso-et{
  font-size:var(--jzd-fs-2); font-weight:800; letter-spacing:.08em;
  text-transform:uppercase; color:var(--jzd-ink-4); white-space:nowrap;
}
.jzd-paso:has(.rv-paso-dot.activo) .jzd-paso-et{ color:var(--jzd-blue); }
.jzd-paso:has(.rv-paso-dot.hecho) .jzd-paso-et{ color:var(--jzd-green-hi); }

/* ---------- Franjas mañana / tarde ---------- */
.jzd-franjas{ display:grid; grid-template-columns:1fr 1fr; gap:var(--jzd-s4); }
.jzd-franjas .pay-btn{ min-height:var(--jzd-tap-lg); border-radius:var(--jzd-r-md); }
.jzd-franjas .pay-btn.active{
  background:rgba(245,158,11,.10); border-color:rgba(245,158,11,.42);
  box-shadow:var(--jzd-e-amber);
}
.jzd-franjas .pay-btn.active .pay-lbl{ color:#D97706; }
body.dark-mode .jzd-franjas .pay-btn.active .pay-lbl{ color:var(--jzd-amber); }
.jzd-franjas .pay-lbl{ font-size:var(--jzd-fs-6); font-weight:800; }
.jzd-franjas .jzd-franja-h{ font-size:var(--jzd-fs-4); font-weight:600; color:var(--jzd-ink-4); font-variant-numeric:tabular-nums; }

/* ---------- Parrilla de horas ----------
   VALORES REALES LEÍDOS en orbit.css:
     .time-slot          padding:10px 4px; radio 12; 11px/700
     .time-slot.selected degradado #3B82F6→#6366F1; scale(1.04)
     .time-slot.occupied fondo slate 6%; color #94a3b8; line-through; opacity .6
   PROBLEMA REAL: solo existen tres estados y "ocupada" ya usa el tachado, así
   que una hora que YA PASÓ se ve exactamente igual que una ocupada. Son cosas
   distintas: una no se puede reservar nunca más, la otra está tomada.
   CAMBIO: "ocupada" pasa a rayado diagonal + la palabra "ocupada"; el tachado
   queda reservado para las horas pasadas (.jzd-pasada, clase nueva). Ninguno
   de los cuatro estados se comunica solo con color. */
.tgrid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(124px,1fr)); gap:var(--jzd-s4); }
.time-slot{
  min-height:var(--jzd-tap-lg); padding:0 var(--jzd-s4);
  font-size:var(--jzd-fs-6); border-radius:var(--jzd-r-md);
  display:flex; align-items:center; justify-content:center; gap:var(--jzd-s2);
  font-variant-numeric:tabular-nums;
}
.time-slot.selected{ transform:translateY(-2px) scale(1); box-shadow:var(--jzd-e-blue-hi), inset 0 1px 0 rgba(255,255,255,.28); }
.time-slot.selected::after{ content:'✓'; font-size:var(--jzd-fs-5); font-weight:800; }

.time-slot.occupied{
  text-decoration:none;                      /* el tachado pasa a .jzd-pasada */
  opacity:1; color:var(--jzd-ink-4);
  flex-direction:column; gap:0; line-height:1.15;
  background:repeating-linear-gradient(135deg,
    rgba(100,116,139,.10) 0 6px, rgba(100,116,139,.02) 6px 12px);
}
.time-slot.occupied::after{
  content:'ocupada'; font-size:var(--jzd-fs-1); font-weight:800;
  letter-spacing:.08em; text-transform:uppercase; opacity:.75;
}
body.dark-mode .time-slot.occupied{
  background:repeating-linear-gradient(135deg,
    rgba(255,255,255,.07) 0 6px, rgba(255,255,255,.02) 6px 12px);
}
.time-slot.jzd-pasada{
  cursor:not-allowed; opacity:.45; color:var(--jzd-ink-4);
  text-decoration:line-through; text-decoration-thickness:1.5px;
  box-shadow:none;
}
.time-slot.jzd-pasada:hover{ transform:none; background:rgba(255,255,255,.55); }

/* ayuda de lectura — evita "¿por qué no puedo tocar esa hora?" */
.jzd-horas-nota{ font-size:var(--jzd-fs-4); font-weight:600; color:var(--jzd-ink-4); }

/* ---------- Navegación entre pasos ----------
   .rv-nav ya pone .btn-primary a flex:1. Solo se garantiza el táctil. */
.rv-nav{ gap:var(--jzd-s4); }
.rv-atras,.rv-btn-fantasma{ min-height:var(--jzd-tap-lg); border-radius:var(--jzd-r-xl); }
.rv-nav .btn-primary{ min-height:var(--jzd-tap-lg); }
.rv-res-lbl,.rv-res-val{ font-size:var(--jzd-fs-5); }
.rv-res-val{ font-variant-numeric:tabular-nums; }

@media (max-width:560px){
  .tgrid{ grid-template-columns:repeat(2,1fr); }
  .jzd-paso-et{ display:none; }
  .rv-paso-linea{ margin-top:0; }
  .jzd-franjas{ grid-template-columns:1fr; }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-venta.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-venta.css · POS.
   Base real: venta.css — .pos-wrap/.pos-main/.pos-cart, .pos-grid, .pos-prod
   (+.pos-libre), .pos-prod-nombre/-precio, .pos-cart-lineas, .pos-linea*,
   .pos-qty*, .pos-total*, .pos-fab, .vh-* (hoja de cobro), .venta-exito*,
   .exito-folio, .btn-secundario, .prod-* (catálogo), .caja-* , .imp-*,
   .chip-met, .chip-est. Y de orbit.css: .numpad/.numpad-key, .pay-grid/
   .pay-btn, .change-box, .t-badge.

   NO SE TOCA el ticket: venta.css ya trae #ticketVenta con .tk-* , su
   @media print aislado y @page{size:80mm auto}. Está bien resuelto y
   duplicarlo solo podía romperlo. Por eso esta entrega no tiene ni un
   !important: la única razón por la que iba a necesitarlo era el ticket.
   ========================================================================== */

.pos-wrap{ gap:var(--jzd-s7); }
.pos-main{ gap:var(--jzd-s5); }
.pos-cart{ width:330px; gap:var(--jzd-s5); }

/* ---------- Categorías ----------
   Las categorías se filtran hoy con .pill de orbit.css, todas azules.
   CAMBIO: cada categoría recibe su tono fijo, y es el MISMO tono que la franja
   superior de sus productos. Eso es el "mapa visual de categorías" pedido:
   el ojo aprende el color una vez y ya no lee la etiqueta. */
.jzd-cats{ display:flex; flex-wrap:wrap; gap:var(--jzd-s3); }
.jzd-cats .pill{
  --_t:var(--blue-500);
  min-height:var(--jzd-tap); padding:0 var(--jzd-s6);
  font-size:var(--jzd-fs-5); font-weight:700;
  color:color-mix(in srgb,var(--_t) 78%,var(--gray-900) 22%);
  background:color-mix(in srgb,var(--_t) 9%,transparent);
  border-color:color-mix(in srgb,var(--_t) 18%,transparent);
}
body.dark-mode .jzd-cats .pill{ color:color-mix(in srgb,var(--_t) 72%,#fff 28%); }
.jzd-cats .pill.selected{
  color:#fff; border-color:transparent;
  background:linear-gradient(135deg,color-mix(in srgb,var(--_t) 86%,#fff 14%),var(--_t));
  box-shadow:0 4px 14px color-mix(in srgb,var(--_t) 38%,transparent);
}
.jzd-cats .pill[data-cat="Enmarcados"]{ --_t:var(--purple-500); }
.jzd-cats .pill[data-cat="Impresiones"]{ --_t:var(--cyan-500); }
.jzd-cats .pill[data-cat="Sesiones"]{ --_t:var(--pink-500); }
.jzd-cats .pill[data-cat="Extras"]{ --_t:var(--amber-500); }
.jzd-cats .pill[data-cat="Otros"]{ --_t:var(--gray-500); }

/* ---------- Tarjetas de producto ----------
   VALOR REAL LEÍDO: .pos-prod = minmax(128px,1fr); padding 13; radio 16;
   nombre 12px/700 con line-clamp 2; precio 15px/800.
   CAMBIO 1: franja superior de 3px con el color de su categoría.
   CAMBIO 2: 128 → 152px de mínimo y 13 → 14px de padding. Con 128px, un
   nombre de dos líneas ("Sesión Smash Cake") deja el precio pegado al borde.
   CAMBIO 3: estados "estimado" e "inactivo" en la tarjeta del POS. Hoy solo
   existen en el catálogo (.prod-fila.inactivo / .t-badge.estimado), que es una
   pantalla de administración que nadie abre durante una venta. */
.pos-grid{ grid-template-columns:repeat(auto-fill,minmax(152px,1fr)); gap:var(--jzd-s5); }
.pos-prod{
  --_t:var(--blue-500);
  position:relative; overflow:hidden; padding:var(--jzd-s6);
  min-height:124px; gap:var(--jzd-s4);
}
.pos-prod::before{ content:''; position:absolute; inset:0 0 auto; height:3px; background:var(--_t); opacity:.92; }
.pos-prod[data-cat="Enmarcados"]{ --_t:var(--purple-500); }
.pos-prod[data-cat="Impresiones"]{ --_t:var(--cyan-500); }
.pos-prod[data-cat="Sesiones"]{ --_t:var(--pink-500); }
.pos-prod[data-cat="Extras"]{ --_t:var(--amber-500); }
.pos-prod[data-cat="Otros"]{ --_t:var(--gray-500); }
.pos-prod:hover{ box-shadow:var(--jzd-e3), inset 0 1px 0 rgba(255,255,255,.35); }
.pos-prod-nombre{ font-size:var(--jzd-fs-6); }
.pos-prod-precio{ font-size:var(--jzd-fs-8); letter-spacing:-.01em; }

/* icono opcional en la tarjeta (el catálogo ya guarda un emoji por producto) */
.jzd-prod-ico{
  width:32px; height:32px; border-radius:var(--jzd-r-sm);
  display:grid; place-items:center; font-size:var(--jzd-fs-7);
  background:color-mix(in srgb,var(--_t) 13%,transparent);
  border:1px solid color-mix(in srgb,var(--_t) 20%,transparent);
}

.pos-prod[data-estimado="true"] .pos-prod-precio::after{
  content:'estimado'; display:block; margin-top:2px;
  font-size:var(--jzd-fs-2); font-weight:800; letter-spacing:.08em;
  text-transform:uppercase; color:#D97706;
}
body.dark-mode .pos-prod[data-estimado="true"] .pos-prod-precio::after{ color:var(--jzd-amber); }
.pos-prod.inactivo{ opacity:.66; }
.pos-prod.inactivo::after{
  content:'✎ ponle el precio real'; position:absolute; inset:auto 0 0;
  padding:4px var(--jzd-s6); text-align:left;
  font-size:var(--jzd-fs-2); font-weight:800; letter-spacing:.04em;
  color:#D97706; background:rgba(245,158,11,.14);
}
/* NOTA: no se bloquea la venta de un producto con precio estimado — eso
   cambiaría el flujo y es decisión de negocio (pregunta abierta #3). */

/* ---------- Carrito ----------
   VALOR REAL LEÍDO: .pos-linea-nombre = 11px, con ellipsis; los controles
   .pos-qty-btn son de 24×24.
   CAMBIO: el nombre sube a 12px y los ± a 32px (táctil), reorganizando la
   línea en rejilla 1fr/auto/auto/auto para que el nombre deje de cortarse a
   ~12 caracteres ("Sesión S…", "Enmarca…" en la captura actual). */
.pos-linea{ display:grid; grid-template-columns:1fr auto auto auto; gap:var(--jzd-s4); padding:var(--jzd-s4) var(--jzd-s5); border-radius:var(--jzd-r-md); }
.pos-linea-nombre{ font-size:var(--jzd-fs-5); }
.pos-linea-precio{ font-size:var(--jzd-fs-4); }
.pos-qty-btn{ width:32px; height:32px; font-size:var(--jzd-fs-7); border-radius:var(--jzd-r-sm); }
.pos-qty-num{ min-width:26px; font-size:var(--jzd-fs-6); }
.pos-linea-sub{ font-size:var(--jzd-fs-6); min-width:58px; }
.pos-linea-quitar{ width:30px; height:30px; border-radius:var(--jzd-r-xs); font-size:var(--jzd-fs-5); }

/* ---------- Total ----------
   Ya está en 34px, que es correcto: es la cifra que se le lee al cliente en
   voz alta. Solo se le da aire y tracking negativo. */
.pos-total{ padding:var(--jzd-s6) var(--jzd-s3) var(--jzd-s3); }
.pos-total-lbl{ letter-spacing:var(--jzd-track-eyebrow); }
.pos-total-num{ font-size:var(--jzd-fs-11); letter-spacing:-.03em; }

/* ---------- Cobro en efectivo ----------
   IMPORTANTE: el monto recibido YA se captura — venta.css trae .vh-monto,
   .vh-monto-pantalla, .vh-billetes/.vh-billete y el .numpad, y la devuelta se
   muestra en .venta-exito-cambio y en el .change-box de orbit.css. No hace
   falta funcionalidad nueva: solo se le da a la devuelta el tamaño que merece,
   porque es el número que evita un error de caja. */
.vh-monto-pantalla{ font-size:var(--jzd-fs-11); border-radius:var(--jzd-r-xl); min-height:72px; }
.vh-monto .numpad{ max-width:300px; }
.vh-monto .numpad-key{ height:var(--jzd-tap-lg); font-size:var(--jzd-fs-9); }
.vh-billete{ min-height:var(--jzd-tap); border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-6); }

.change-box{ padding:var(--jzd-s6) var(--jzd-s7); border-radius:var(--jzd-r-md); }
.change-box .change-lbl{ font-size:var(--jzd-fs-3); font-weight:800; letter-spacing:var(--jzd-track-eyebrow); text-transform:uppercase; color:var(--jzd-ink-4); }
.change-box .change-val{ font-size:var(--jzd-fs-10); font-weight:800; letter-spacing:-.02em; color:var(--emerald-600); font-variant-numeric:tabular-nums; }
body.dark-mode .change-box .change-val{ color:var(--jzd-green); }
.venta-exito-cambio{ font-size:var(--jzd-fs-7); padding:var(--jzd-s4) var(--jzd-s8); border-radius:var(--jzd-r-md); }

/* ---------- Éxito ----------
   .exito-folio ya es 46px con degradado azul→violeta y .venta-exito-check
   ya rebota con exitoPop. Ambos están bien. Lo único que falta es contarle al
   empleado qué pasó DESPUÉS del cobro. */
.venta-exito-lbl{ letter-spacing:var(--jzd-track-eyebrow); }
.jzd-exito-nota{
  font-size:var(--jzd-fs-5); font-weight:600; color:var(--jzd-ink-3);
  max-width:34ch; line-height:1.5; text-wrap:pretty;
}
.venta-exito-botones .btn-primary,.venta-exito-botones .btn-secundario{ min-height:var(--jzd-tap-lg); }

/* ---------- Ticket ----------
   Vive en design-ticket.css: es un deliverable aparte porque tiene que
   soportar dos anchos de papel (50 mm y 80 mm). Ver ese fichero. */

@media (max-width:1100px){ .pos-cart{ width:300px; } }
@media (max-width:860px){ .pos-wrap{ flex-direction:column; } }
@media (max-width:560px){ .pos-grid{ grid-template-columns:repeat(2,1fr); } }


/* ══════════════════════════════════════════════════════════════════════════
   design-tarjeta.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-tarjeta.css · La tarjeta del cliente (candado del flujo).
   Base real: reservar.css — .tj-vista, .tj-prev-marco, .tj-canvas,
   .tj-acciones, .tj-enviar (+:disabled). Formularios: .fgroup/.flabel/.finput
   de orbit.css.
   Sin tarjeta guardada no sale el correo de confirmación. Todo el refinamiento
   va a hacer visible en qué paso está el proceso y qué falta.
   ========================================================================== */

.tj-vista{ gap:var(--jzd-s7); }

/* ---------- El candado en 3 pasos (bloque nuevo) ----------
   Hoy el bloqueo se comunica con .tj-enviar:disabled{opacity:.45} más una
   línea de nota en gris pequeño. El empleado nuevo no la lee: toca el botón,
   no pasa nada, y pregunta. Esto convierte una prohibición silenciosa en un
   progreso visible. Misma regla de negocio, sin cambiar nada. */
.jzd-candado{ display:flex; flex-direction:column; gap:var(--jzd-s3); }
.jzd-candado__p{
  display:flex; align-items:center; gap:var(--jzd-s4);
  padding:var(--jzd-s4) var(--jzd-s5); border-radius:var(--jzd-r-md);
  background:var(--jzd-glass); border:1px solid var(--jzd-glass-brd);
  box-shadow:var(--jzd-edge);
  transition:border-color var(--jzd-t) linear, background var(--jzd-t) linear;
}
.jzd-candado__b{
  width:24px; height:24px; border-radius:50%; flex:none; display:grid; place-items:center;
  font-size:var(--jzd-fs-3); font-weight:800;
  color:var(--jzd-ink-4); background:rgba(0,0,0,.06);
}
body.dark-mode .jzd-candado__b{ background:rgba(255,255,255,.08); }
.jzd-candado__t{ font-size:var(--jzd-fs-5); font-weight:700; color:var(--jzd-ink-2); }

.jzd-candado__p[data-estado="hecho"]{ border-color:rgba(16,185,129,.30); background:rgba(16,185,129,.07); }
.jzd-candado__p[data-estado="hecho"] .jzd-candado__b{ color:#fff; background:linear-gradient(135deg,var(--emerald-500),var(--emerald-600)); }
.jzd-candado__p[data-estado="actual"]{ border-color:rgba(59,130,246,.40); background:rgba(59,130,246,.08); }
.jzd-candado__p[data-estado="actual"] .jzd-candado__b{ color:#fff; background:linear-gradient(135deg,var(--blue-500),var(--blue-600)); box-shadow:var(--jzd-e-blue); }
.jzd-candado__p[data-estado="actual"] .jzd-candado__t{ color:var(--jzd-ink); font-weight:800; }
.jzd-candado__p[data-estado="bloqueado"]{ opacity:.6; }

/* ---------- Previsualización ----------
   VALOR REAL LEÍDO: .tj-canvas = max-width 300px, radio 14, sombra
   0 10px 30px rgba(11,16,38,.35); .tj-prev-marco es el vidrio contenedor.
   CAMBIO: se fija el aspect-ratio 1080/1350 (así el marco no salta mientras
   el canvas se regenera) y se añade un reflejo diagonal, para que el preview
   se sienta un objeto y no un div con una imagen. */
.tj-prev-marco{ position:relative; border-radius:var(--jzd-r-xl); padding:var(--jzd-s6); }
.tj-canvas{ max-width:320px; aspect-ratio:1080/1350; border-radius:var(--jzd-r-xl); }
.tj-prev-marco::after{
  content:''; position:absolute; inset:var(--jzd-s6); pointer-events:none;
  border-radius:var(--jzd-r-xl);
  background:linear-gradient(160deg,rgba(255,255,255,.14),transparent 34%);
}

/* ---------- Selector de plantilla (bloque nuevo) ---------- */
.jzd-plantillas{ display:grid; grid-template-columns:1fr 1fr; gap:var(--jzd-s3); }
.jzd-plant{
  display:flex; align-items:center; gap:var(--jzd-s3);
  min-height:var(--jzd-tap); padding:0 var(--jzd-s4);
  border-radius:var(--jzd-r-md); cursor:pointer; font-family:inherit;
  font-size:var(--jzd-fs-5); font-weight:700; color:var(--jzd-ink-2);
  background:var(--jzd-glass); border:1px solid var(--jzd-glass-brd);
  box-shadow:var(--jzd-edge);
  transition:border-color var(--jzd-t-fast) linear, transform var(--jzd-t-fast) var(--jzd-ease);
}
.jzd-plant:hover{ transform:translateY(-1px); }
.jzd-plant__sw{ width:20px; height:20px; border-radius:6px; flex:none; box-shadow:inset 0 0 0 1px rgba(0,0,0,.14); }
.jzd-plant[aria-selected="true"]{ border-color:rgba(59,130,246,.45); box-shadow:0 0 0 3px rgba(59,130,246,.12), var(--jzd-edge); color:var(--jzd-ink); }

/* ---------- Acciones ----------
   El énfasis azul debe estar SIEMPRE en el paso actual del candado: mientras
   falte guardar, .btn-primary es "Guardar tarjeta"; cuando esté guardada, el
   JS mueve la clase a .tj-enviar. La nota de texto no cambia: es funcional. */
.tj-acciones{ gap:var(--jzd-s3); }
.tj-acciones > *{ min-height:var(--jzd-tap-lg); }
.jzd-tj-nota{
  font-size:var(--jzd-fs-4); font-weight:600; color:var(--jzd-ink-4);
  text-align:center; text-wrap:pretty;
}

@media (max-width:560px){ .jzd-plantillas{ grid-template-columns:1fr; } }


/* ══════════════════════════════════════════════════════════════════════════
   design-perfiles.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-perfiles.css · "¿Quién eres?" — el primer contacto de cada mañana.
   Base real: orbit-web.css — .ow-pantalla, .ow-fondo, .ow-perfiles-caja,
   .ow-wordmark(-sm/-xl) + .ow-punto, .ow-perfil-grid, .ow-perfil-tarjeta,
   .ow-anillo, .ow-avatar(+-84/-36/-22/-inicial), .ow-grad-0..5,
   .ow-perfil-nombre, .ow-perfil-rol. Títulos: .auth-title/.auth-subtitle.
   ========================================================================== */

/* dos anillos concéntricos apenas visibles detrás de las tarjetas: refuerzan
   el nombre "Orbit" sin dibujar un logo nuevo ni pedir una imagen */
.ow-pantalla.ow-fondo::before,
.ow-pantalla.ow-fondo::after{
  content:''; position:absolute; left:50%; top:44%; transform:translate(-50%,-50%);
  border-radius:50%; pointer-events:none; z-index:0;
}
.ow-pantalla.ow-fondo::before{ width:min(120vw,1200px); aspect-ratio:1; border:1px solid rgba(255,255,255,.05); }
.ow-pantalla.ow-fondo::after{ width:min(80vw,820px); aspect-ratio:1; border:1px solid rgba(139,92,246,.10); }
.ow-perfiles-caja{ position:relative; z-index:1; max-width:680px; }
.ow-perfiles-caja .auth-title{ font-size:var(--jzd-fs-10); letter-spacing:-.02em; }

/* ---------- Rejilla ----------
   VALOR REAL LEÍDO: .ow-perfil-grid = auto-fit minmax(128px,1fr); gap 14.
   Con 7 perfiles y ese mínimo, en escritorio salen 4+3 y la segunda fila deja
   un hueco a la derecha (se ve en la captura). Subir el mínimo a 150 reparte
   mejor y da sitio al anillo más grande. */
.ow-perfil-grid{ grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--jzd-s7); margin-top:var(--jzd-s9); }

/* ---------- Tarjeta ----------
   VALOR REAL LEÍDO: hover = background .14 / translateY(-3px) /
   0 12px 32px rgba(0,0,0,.3).
   CAMBIO: sube a -6px con escala 1.03, borde violeta y sombra más profunda;
   y las 7 entran en cascada de 60ms (480ms en total). Es el "nivel cine"
   pedido, y nadie espera por ello. */
.ow-perfil-tarjeta{
  --_d:0ms;
  padding:var(--jzd-s9) var(--jzd-s6) var(--jzd-s7);
  border-radius:var(--jzd-r-3xl); gap:var(--jzd-s5);
  transition:transform var(--jzd-t-slow) var(--jzd-ease),
             box-shadow var(--jzd-t-slow) var(--jzd-ease),
             border-color var(--jzd-t) linear, background var(--jzd-t) linear;
  animation:jzd-perfil-in 540ms var(--jzd-ease) both; animation-delay:var(--_d);
}
/* misma regla que jzd-sube: solo transform, nunca opacidad (ver design-base.css) */
@keyframes jzd-perfil-in{ from{ transform:translateY(16px) scale(.96); } to{ transform:none; } }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(1){ --_d:100ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(2){ --_d:160ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(3){ --_d:220ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(4){ --_d:280ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(5){ --_d:340ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(6){ --_d:400ms }
.ow-perfil-grid > .ow-perfil-tarjeta:nth-child(7){ --_d:460ms }

.ow-perfil-tarjeta:hover,
.ow-perfil-tarjeta:focus-visible{
  transform:translateY(-6px) scale(1.03);
  border-color:rgba(139,92,246,.42);
  box-shadow:0 30px 64px -20px rgba(0,0,0,.66), 0 0 0 1px rgba(139,92,246,.26), inset 0 1px 0 rgba(255,255,255,.18);
}
.ow-perfil-tarjeta:active{ transform:translateY(-2px) scale(1.005); }

/* el anillo gana luz y gira despacio al pasar por encima */
.ow-anillo{ position:relative; transition:transform var(--jzd-t-slow) var(--jzd-ease); }
.ow-perfil-tarjeta:hover .ow-anillo{ transform:scale(1.04); }
.ow-anillo::after{
  content:''; position:absolute; inset:-5px; border-radius:50%; pointer-events:none;
  background:conic-gradient(from 0deg,transparent 0deg,rgba(139,92,246,.75) 90deg,rgba(59,130,246,.75) 200deg,transparent 300deg);
  opacity:0; transition:opacity var(--jzd-t-slow) linear;
}
.ow-perfil-tarjeta:hover .ow-anillo::after{ opacity:.9; animation:jzd-girar 4.5s linear infinite; }
@keyframes jzd-girar{ to{ transform:rotate(360deg); } }

.ow-avatar-84{ width:96px; height:96px; font-size:var(--jzd-fs-11); }
.ow-perfil-nombre{ font-size:var(--jzd-fs-8); font-weight:800; }

/* ---------- Rol ----------
   VALOR REAL LEÍDO: .ow-perfil-rol es texto suelto en rgba(255,255,255,.5).
   CAMBIO: pasa a píldora con color por rol. Con 7 perfiles y tres roles
   distintos, saber de un vistazo quién es admin importa. */
.ow-perfil-rol{
  padding:4px 10px; border-radius:var(--jzd-r-pill);
  font-size:var(--jzd-fs-2); letter-spacing:.16em; text-indent:.16em;
  color:#93C5FD; background:rgba(59,130,246,.14); border:1px solid rgba(59,130,246,.22);
}
.ow-perfil-tarjeta[data-rol="ADMINISTRADOR"] .ow-perfil-rol{ color:#C4B5FD; background:rgba(139,92,246,.16); border-color:rgba(139,92,246,.26); }
.ow-perfil-tarjeta[data-rol="ACCESO LIMITADO"] .ow-perfil-rol{ color:#9CA3AF; background:rgba(156,163,175,.12); border-color:rgba(156,163,175,.2); }

@media (max-width:640px){
  .ow-perfil-grid{ grid-template-columns:repeat(2,1fr); gap:var(--jzd-s5); }
  .ow-perfil-tarjeta{ padding:var(--jzd-s7) var(--jzd-s4) var(--jzd-s6); }
  .ow-avatar-84{ width:76px; height:76px; font-size:var(--jzd-fs-10); }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-login.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-login.css · Splash y acceso.
   Base real: orbit-web.css — .ow-splash, .ow-splash-centro, .ow-splash-marca,
   .ow-splash-barra, .ow-wordmark-xl + .ow-punto (ya late con owLatir),
   .ow-fondo, .ow-auth-tarjeta, .ow-auth-paso, .ow-auth-marca, .ow-auth-form,
   .ow-auth-logo-mail, .ow-auth-enlaces, .ow-enlace, .ow-codigo,
   .ow-codigo-caja (+.ow-mal, que ya sacude con owTemblar).
   ========================================================================== */

/* el splash ya está muy bien resuelto: solo se le da aire a la firma */
.ow-splash-marca{ font-size:var(--jzd-fs-4); }
.ow-auth-tarjeta{ border-radius:var(--jzd-r-3xl); padding:var(--jzd-s10) var(--jzd-s9); }
.ow-auth-marca{ letter-spacing:.32em; }
.ow-auth-form{ gap:var(--jzd-s7); }
.ow-auth-form .finput{ min-height:var(--jzd-tap-lg); font-size:var(--jzd-fs-7); }

/* ---------- El código de 6 dígitos ----------
   VALOR REAL LEÍDO: .ow-codigo-caja = 44×52, 22px/800, radio 14, y usa
   !important tres veces para ganarle a .finput. Esta capa NO necesita
   !important: se sube la especificidad con .ow-codigo .ow-codigo-caja.
   CAMBIO: la casilla enfocada se eleva 2px, se tiñe de azul y gana halo; y una
   casilla ya escrita queda más luminosa que una vacía. Es el detalle que hace
   que un OTP se sienta premium en vez de burocrático: se ve exactamente dónde
   estás y cuánto llevas. */
.ow-codigo{ gap:var(--jzd-s3); }
.ow-codigo .ow-codigo-caja{
  width:48px; height:58px; font-variant-numeric:tabular-nums;
  transition:transform var(--jzd-t-fast) var(--jzd-ease),
             border-color var(--jzd-t-fast) linear,
             box-shadow var(--jzd-t-fast) linear,
             background var(--jzd-t-fast) linear;
}
.ow-codigo .ow-codigo-caja:focus{
  transform:translateY(-2px);
  border-color:rgba(59,130,246,.55);
  background:rgba(59,130,246,.10);
  box-shadow:0 0 0 3px rgba(59,130,246,.20), 0 8px 20px -8px rgba(59,130,246,.5);
}
/* data-lleno lo pone el JS al escribir — 1 línea, ver parches-html/login-perfiles.md */
.ow-codigo .ow-codigo-caja[data-lleno="true"]{
  background:rgba(255,255,255,.62);
  border-color:rgba(59,130,246,.28);
}
body.dark-mode .ow-codigo .ow-codigo-caja[data-lleno="true"]{ background:rgba(255,255,255,.10); }

/* mensaje de error en texto: el color no puede ser el único mensaje.
   .ow-mal ya pone el borde rojo y la sacudida. */
.jzd-auth-error{
  font-size:var(--jzd-fs-5); font-weight:600; color:#DC2626; text-align:center;
}
body.dark-mode .jzd-auth-error{ color:#FCA5A5; }

.ow-auth-enlaces{ gap:var(--jzd-s4); }
.ow-enlace{ min-height:38px; }

@media (max-width:420px){
  .ow-auth-tarjeta{ padding:var(--jzd-s9) var(--jzd-s7); }
  .ow-codigo{ gap:var(--jzd-s2); }
  .ow-codigo .ow-codigo-caja{ width:42px; height:52px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-caja.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-caja.css · Caja del día (ventas registradas).
   Base real: venta.css — .caja-kpi-grid, .caja-kpi-card, .caja-kpi-label,
   .caja-kpi-val, .caja-kpi-sub, .venta-fila (+.anulada), .venta-folio,
   .venta-hora, .venta-detalle, .venta-items, .venta-quien, .chip-met
   (+.efectivo/.transferencia/.tarjeta/.otro), .t-badge.anulada-chip,
   .anular-aviso, .venta-det-lineas/.venta-det-linea, .venta-head*.

   ⚠️ Sin captura de esta vista. Todo lo de abajo se afinó leyendo venta.css:
   son ajustes de escala y jerarquía sobre selectores verificados, no un
   rediseño de layout. Con una captura hago la segunda pasada.
   ========================================================================== */

.venta-head-titulo{ font-size:var(--jzd-fs-7); letter-spacing:-.01em; }

/* ---------- KPI de la caja ----------
   VALOR REAL LEÍDO: .caja-kpi-card padding 11px 12px; .caja-kpi-val 17px.
   Es la cifra que se cuadra al cerrar el día: 17px es poco. */
.caja-kpi-grid{ gap:var(--jzd-s4); }
.caja-kpi-card{ padding:var(--jzd-s6) var(--jzd-s5); border-radius:var(--jzd-r-lg); }
.caja-kpi-val{ font-size:var(--jzd-fs-9); letter-spacing:-.02em; line-height:1.1; }
.caja-kpi-label{ letter-spacing:var(--jzd-track-wide); }
.caja-kpi-sub{ font-size:var(--jzd-fs-3); color:var(--jzd-ink-4); }

/* ---------- Fila de venta ---------- */
.venta-fila{ padding:var(--jzd-s4) var(--jzd-s5); border-radius:var(--jzd-r-lg); gap:var(--jzd-s5); }
.venta-fila:hover{ box-shadow:var(--jzd-e2), var(--jzd-edge); }
.venta-folio{ font-size:var(--jzd-fs-6); letter-spacing:.04em; }
.venta-hora{ font-size:var(--jzd-fs-4); }
.venta-items{ font-size:var(--jzd-fs-4); color:var(--jzd-ink-3); }
.venta-quien{ font-size:var(--jzd-fs-3); }
.chip-met{ padding:3px 9px; font-size:var(--jzd-fs-3); }

/* ---------- Motivo de una anulación ----------
   El motivo es obligatorio y ya se captura, pero no se mostraba en la fila:
   había que abrir el detalle para saber por qué. Verlo evita que alguien
   vuelva a preguntar. .venta-fila.anulada ya tacha folio e importe. */
.jzd-motivo{
  width:100%; margin-top:var(--jzd-s2);
  font-size:var(--jzd-fs-4); font-weight:600; color:var(--jzd-ink-3);
  text-wrap:pretty;
}
.jzd-motivo b{ color:var(--red-500); font-weight:800; }
body.dark-mode .jzd-motivo b{ color:var(--jzd-red); }

/* ---------- Detalle ---------- */
.venta-det-linea{ padding:var(--jzd-s3) var(--jzd-s4); border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-5); }
.anular-aviso{ padding:var(--jzd-s5); border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-5); }


/* ══════════════════════════════════════════════════════════════════════════
   design-productos.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-productos.css · Administración del catálogo.
   Base real: venta.css — .prod-toolbar, .prod-fila (+.inactivo), .prod-info,
   .prod-nombre, .prod-precio, .prod-aviso, .prod-acciones, .prod-orden,
   .t-badge.estimado, .t-badge.inactivo-chip, .sembrar-* (vista previa del
   sembrado). Y de orbit.css: .act-btn/.act-view/.act-del, .atoggle.

   ⚠️ Sin captura de esta vista. Ajustes de escala sobre selectores verificados.
   ========================================================================== */

.prod-toolbar{ gap:var(--jzd-s4); }
.prod-toolbar .finput{ min-width:180px; }

/* ---------- Fila de producto ---------- */
.prod-fila{ padding:var(--jzd-s5) var(--jzd-s6); border-radius:var(--jzd-r-lg); gap:var(--jzd-s5); }
.prod-fila:hover{ box-shadow:var(--jzd-e2), var(--jzd-edge); }
.prod-nombre{ font-size:var(--jzd-fs-6); gap:var(--jzd-s3); }
.prod-precio{ font-size:var(--jzd-fs-7); letter-spacing:-.01em; }

/* ---------- El aviso de precio estimado ----------
   VALOR REAL LEÍDO: .prod-aviso es 10px en #D97706, y .prod-fila.inactivo baja
   a opacity .82 con fondo ámbar al 5%.
   Los 16 productos con precio estimado son una tarea pendiente, no un error:
   el aviso pasa a píldora para que se lea como algo que hay que hacer, y la
   fila gana un filo ámbar a la izquierda para poder barrer la lista de un
   vistazo y ver cuántos faltan. */
.prod-aviso{
  display:inline-flex; align-items:center; gap:5px;
  margin-top:var(--jzd-s2); padding:3px 9px;
  border-radius:var(--jzd-r-sm); font-size:var(--jzd-fs-3);
  background:rgba(245,158,11,.12); border:1px solid rgba(245,158,11,.24);
}
body.dark-mode .prod-aviso{ color:var(--jzd-amber); }
.prod-fila.inactivo{ position:relative; overflow:hidden; }
.prod-fila.inactivo::before{
  content:''; position:absolute; left:0; top:10px; bottom:10px; width:3px;
  border-radius:0 3px 3px 0; background:var(--amber-500);
}

/* ---------- Acciones ----------
   VALOR REAL LEÍDO: .act-btn es 26×26 y .prod-orden .act-btn baja a 20×14.
   14px de alto es imposible de acertar con el dedo en una tableta. */
.prod-acciones{ gap:var(--jzd-s2); }
.prod-acciones .act-btn{ width:36px; height:36px; border-radius:var(--jzd-r-sm); font-size:var(--jzd-fs-6); }
.prod-orden{ gap:2px; }
.prod-orden .act-btn{ width:32px; height:20px; font-size:var(--jzd-fs-2); }

/* ---------- Vista previa del sembrado ---------- */
.sembrar-preview{ gap:var(--jzd-s4); }
.sembrar-stat{ padding:var(--jzd-s5); border-radius:var(--jzd-r-md); }
.sembrar-stat .n{ font-size:var(--jzd-fs-9); }
.sembrar-stat .l{ letter-spacing:var(--jzd-track-wide); }


/* ══════════════════════════════════════════════════════════════════════════
   design-impresiones.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-impresiones.css · Cola de impresión a la Epson ET-8550.
   Base real: venta.css — .imp-nota, .imp-card, .imp-ico, .imp-info,
   .imp-titulo, .imp-meta, .imp-detalle-err, .imp-reintentar, y
   .chip-est (+.pendiente/.imprimiendo/.impresa/.fallida) con su .dot.

   ⚠️ Sin captura de esta vista. Ajustes de escala sobre selectores verificados.
   ========================================================================== */

.imp-nota{ padding:var(--jzd-s4) var(--jzd-s5); border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-4); }

/* ---------- Tarjeta de impresión ---------- */
.imp-card{ padding:var(--jzd-s5) var(--jzd-s6); border-radius:var(--jzd-r-lg); gap:var(--jzd-s5); }
.imp-card:hover{ box-shadow:var(--jzd-e2), var(--jzd-edge); }
.imp-ico{ width:40px; height:40px; border-radius:var(--jzd-r-md); font-size:var(--jzd-fs-8); }
.imp-titulo{ font-size:var(--jzd-fs-6); gap:var(--jzd-s3); }
.imp-meta{ font-size:var(--jzd-fs-4); color:var(--jzd-ink-3); gap:var(--jzd-s2) var(--jzd-s5); }
.imp-detalle-err{ font-size:var(--jzd-fs-4); padding:var(--jzd-s3) var(--jzd-s4); border-radius:var(--jzd-r-sm); }
.imp-reintentar{ min-height:var(--jzd-tap); padding:0 var(--jzd-s6); border-radius:var(--jzd-r-md); }

/* ---------- Estados ----------
   VALOR REAL LEÍDO: .chip-est es 9px con un .dot de 5px, y .imprimiendo ya
   anima el punto con oh-pulse. Los cuatro estados están bien resueltos y
   diferenciados por color + texto. Solo suben de tamaño: esta cola se mira
   desde el otro lado del mostrador para saber si la foto ya salió. */
.chip-est{ padding:4px 10px; font-size:var(--jzd-fs-3); letter-spacing:.04em; }
.chip-est .dot{ width:6px; height:6px; }

/* una impresión fallida es la única que pide acción: gana filo rojo */
.imp-card:has(.chip-est.fallida){ position:relative; overflow:hidden; }
.imp-card:has(.chip-est.fallida)::before{
  content:''; position:absolute; left:0; top:10px; bottom:10px; width:3px;
  border-radius:0 3px 3px 0; background:var(--red-500);
}


/* ══════════════════════════════════════════════════════════════════════════
   design-clima.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-clima.css · Control del aire acondicionado (Tuya).
   ⚠️ ES LA ÚNICA VISTA SIN CSS PROPIO EN PRODUCCIÓN. Verificado: no existe ni
   una clase con "clima", "aire", "temp", "tuya" o "therm" en los seis ficheros.
   Así que aquí sí se diseña de cero — pero SOLO ensamblando piezas que ya
   existen en orbit.css, para que no se sienta una vista de otro producto:

     .atoggle / .atoggle-thumb   → el interruptor de encendido (40×24, ya animado)
     .donut-wrap / .donut-svg /
     .donut-center / .donut-total /
     .donut-label                → el dial de temperatura
     .countdown-track /
     .countdown-fill /
     .countdown-text /
     .countdown-labels           → el cooldown de 10 minutos
     .kpi-card / .kpi-label /
     .kpi-val / .kpi-alert       → las lecturas
     .chart-card, .sec-label,
     .sede-pill-group/.sede-pill → contenedor y filtro de sede
     .shift-btn                  → los presets de temperatura
     .flex-notice                → el aviso de "esperando al equipo"

   Datos que pinta la vista: {temp:24, encendido:true, tempMin:22, tempMax:26}
   con cooldown de 10 min.
   ========================================================================== */

.jzd-clima{ display:flex; flex-direction:column; gap:var(--jzd-s7); }

/* ---------- Tarjeta de una sede ---------- */
.jzd-ac{
  display:grid; grid-template-columns:auto 1fr; gap:var(--jzd-s9);
  align-items:center; padding:var(--jzd-s8);
}
.jzd-ac__col{ display:flex; flex-direction:column; gap:var(--jzd-s5); min-width:0; }

/* ---------- Dial de temperatura ----------
   .donut-wrap es 100×100 en orbit.css. Aquí sube a 148 porque la temperatura es
   EL dato de la vista y se mira de lejos (el termostato está en recepción, la
   pantalla no). El anillo se llena entre tempMin y tempMax. */
.jzd-ac .donut-wrap{ width:148px; height:148px; margin:0; flex:none; }
.jzd-ac .donut-svg circle{ fill:none; stroke-linecap:round; }
.jzd-dial-track{ stroke:rgba(0,0,0,.08); stroke-width:10; }
body.dark-mode .jzd-dial-track{ stroke:rgba(255,255,255,.10); }
.jzd-dial-bar{
  stroke:var(--jzd-cyan); stroke-width:10;
  filter:drop-shadow(0 0 8px color-mix(in srgb,var(--jzd-cyan) 55%,transparent));
  transition:stroke-dashoffset .9s var(--jzd-ease), stroke .6s linear;
}
/* fuera del rango pedido: el dial avisa sin gritar */
.jzd-ac[data-fuera="true"] .jzd-dial-bar{ stroke:var(--jzd-amber); filter:drop-shadow(0 0 8px rgba(245,158,11,.5)); }
/* apagado: el dial se apaga de verdad */
.jzd-ac[data-encendido="false"] .jzd-dial-bar{ stroke:var(--jzd-ink-4); filter:none; }

.jzd-ac .donut-total{
  font-size:44px; letter-spacing:-.03em; line-height:1;
  font-variant-numeric:tabular-nums; font-weight:800;
}
.jzd-ac .donut-total sup{ font-size:20px; font-weight:700; vertical-align:super; opacity:.7; }
.jzd-ac .donut-label{ letter-spacing:var(--jzd-track-eyebrow); margin-top:2px; }
.jzd-ac[data-encendido="false"] .donut-total{ color:var(--jzd-ink-4); }

/* ---------- Cabecera de la tarjeta: sede + interruptor ---------- */
.jzd-ac__cab{ display:flex; align-items:center; justify-content:space-between; gap:var(--jzd-s5); }
.jzd-ac__sede{ font-size:var(--jzd-fs-8); font-weight:800; letter-spacing:-.01em; color:var(--jzd-ink); }
.jzd-ac__estado{
  display:inline-flex; align-items:center; gap:var(--jzd-s2);
  font-size:var(--jzd-fs-4); font-weight:700; color:var(--jzd-ink-3);
}
.jzd-ac__estado::before{
  content:''; width:7px; height:7px; border-radius:50%; flex:none;
  background:var(--jzd-ink-4);
}
.jzd-ac[data-encendido="true"] .jzd-ac__estado{ color:var(--jzd-green-hi); }
.jzd-ac[data-encendido="true"] .jzd-ac__estado::before{
  background:var(--emerald-500);
  box-shadow:0 0 0 0 rgba(16,185,129,.5);
  animation:jzd-ac-latir 3s var(--jzd-ease) infinite;
}
@keyframes jzd-ac-latir{ 0%,100%{ box-shadow:0 0 0 0 rgba(16,185,129,.45) } 60%{ box-shadow:0 0 0 6px rgba(16,185,129,0) } }
body.dark-mode .jzd-ac[data-encendido="true"] .jzd-ac__estado{ color:var(--jzd-green); }

/* el interruptor de orbit.css es 40×24; a 56×32 se toca sin apuntar */
.jzd-ac .atoggle{ width:56px; height:32px; border-radius:16px; }
.jzd-ac .atoggle-thumb{ width:26px; height:26px; top:3px; left:3px; }
.jzd-ac .atoggle.on .atoggle-thumb{ transform:translateX(24px); }

/* ---------- Rango pedido ---------- */
.jzd-ac__rango{ display:grid; grid-template-columns:1fr 1fr; gap:var(--jzd-s4); }
.jzd-ac__rango .kpi-card{ padding:var(--jzd-s5) var(--jzd-s6); gap:2px; }
.jzd-ac__rango .kpi-val{ font-size:var(--jzd-fs-9); font-variant-numeric:tabular-nums; }
.jzd-ac__rango .kpi-label{ letter-spacing:var(--jzd-track-wide); }

/* ---------- Presets ---------- */
.jzd-ac__presets{ display:flex; gap:var(--jzd-s3); flex-wrap:wrap; }
.jzd-ac__presets .shift-btn{
  flex:1 1 96px; min-height:var(--jzd-tap-lg); border-radius:var(--jzd-r-md);
  font-variant-numeric:tabular-nums;
}
.jzd-ac__presets .shift-btn b{ font-size:var(--jzd-fs-7); font-weight:800; }
.jzd-ac__presets .shift-range{ font-size:var(--jzd-fs-2); }

/* ---------- Cooldown de 10 minutos ----------
   La regla dura: tras un cambio, el control se bloquea 10 min. Hoy eso no
   tiene representación visual, así que un empleado que toca y no ve reacción
   vuelve a tocar. Se reutiliza el .countdown-* de orbit.css tal cual, con el
   tono ámbar en vez del verde: no es un logro, es una espera. */
.jzd-ac__espera{ display:flex; flex-direction:column; gap:var(--jzd-s2); }
.jzd-ac__espera .countdown-track{
  margin:var(--jzd-s3) 0 var(--jzd-s2); height:8px; border-radius:4px;
  background:rgba(245,158,11,.10); border-color:rgba(245,158,11,.14);
}
.jzd-ac__espera .countdown-fill{
  background:linear-gradient(90deg,#D97706,var(--amber-500));
  box-shadow:0 0 8px rgba(245,158,11,.35);
}
.jzd-ac__espera .countdown-text{ color:#D97706; font-size:var(--jzd-fs-4); }
.jzd-ac__espera .countdown-text .ct-days{ color:#D97706; font-size:var(--jzd-fs-7); font-variant-numeric:tabular-nums; }
body.dark-mode .jzd-ac__espera .countdown-text,
body.dark-mode .jzd-ac__espera .countdown-text .ct-days{ color:var(--jzd-amber); }
.jzd-ac__espera .countdown-label-start,
.jzd-ac__espera .countdown-label-end{ background:rgba(245,158,11,.10); border-color:rgba(245,158,11,.18); }

/* mientras el cooldown corre, todo lo que manda al equipo se ve inerte */
.jzd-ac[data-espera="true"] .atoggle,
.jzd-ac[data-espera="true"] .shift-btn{ opacity:.45; pointer-events:none; }

/* ---------- Aviso de sincronía con el equipo ---------- */
.jzd-ac__aviso.flex-notice.visible{
  font-size:var(--jzd-fs-4); padding:var(--jzd-s3) var(--jzd-s5);
  border-radius:var(--jzd-r-md);
}

@media (max-width:760px){
  .jzd-ac{ grid-template-columns:1fr; gap:var(--jzd-s7); justify-items:center; }
  .jzd-ac__col{ width:100%; }
  .jzd-ac__cab{ justify-content:space-between; }
}
@media (max-width:480px){
  .jzd-ac__rango{ grid-template-columns:1fr; }
  .jzd-ac .donut-wrap{ width:124px; height:124px; }
  .jzd-ac .donut-total{ font-size:36px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   design-ticket.css
   ══════════════════════════════════════════════════════════════════════════ */
/* ==========================================================================
   design-ticket.css · Recibo térmico. DOS ANCHOS DE PAPEL.

   HALLAZGO QUE HAY QUE MIRAR ANTES DE INTEGRAR ESTO
   -------------------------------------------------
   venta.css imprime hoy a 80 mm:

       @page{ size:80mm auto; margin:0 }
       body.imprime-ticket #ticketVenta{ width:72mm; padding:2mm 3mm;
                                         font-family:"Courier New",monospace;
                                         font-size:10.5px; line-height:1.45 }

   Operaciones confirma que la impresora real del estudio es de 50 mm.
   Con el CSS actual el navegador maqueta un recibo de 72 mm y la impresora
   solo puede sacar ~48 mm utiles: la columna de importes de la derecha se
   esta cortando. No es un problema de diseno, es un desajuste de papel — y
   probablemente lleva tiempo pasando sin que nadie lo relacione con el CSS.

   ESTA CAPA LO ARREGLA SIN CERRAR PUERTAS
   ---------------------------------------
   Se declaran las dos anchuras como paginas con nombre (@page con nombre mas
   la propiedad "page"), y se elige con un atributo en <body>:

       <body class="imprime-ticket" data-ticket="50">   <- impresora actual
       <body class="imprime-ticket" data-ticket="80">   <- si mañana entra una de 80

   Por defecto, SIN atributo, es 50 mm: el hardware real de hoy. El de 80 mm
   queda listo para cuando haga falta, sin tocar nada mas.

   LO QUE NO SE TOCA de venta.css: el aislamiento de impresion
   (body.imprime-ticket > *:not(#ticketVenta){display:none}), el
   overflow:visible, la monoespaciada Courier (es lo que hace que la Epson
   alinee las columnas por caracter) y toda la estructura .tk-*.
   Esta capa solo cambia medidas y jerarquia. Cero !important.
   ========================================================================== */

/* ==========================================================================
   1 · PAGINAS CON NOMBRE
   Un @page con nombre no compite con el @page anonimo de venta.css: convive.
   La propiedad page en #ticketVenta es la que elige cual se usa.
   ========================================================================== */
@page ticket-50{ size:50mm auto; margin:0; }
@page ticket-80{ size:80mm auto; margin:0; }

@media print{

  /* --- por defecto y con data-ticket="50": el papel de hoy --- */
  body.imprime-ticket #ticketVenta,
  body.imprime-ticket[data-ticket="50"] #ticketVenta{
    page:ticket-50;
    width:46mm;              /* 50mm de papel menos ~2mm no imprimible por lado */
    padding:1.5mm 2mm;
    font-size:9px;
    line-height:1.5;
    letter-spacing:-.01em;   /* Courier a 9px cuadra mejor un pelo mas junta */
  }

  /* --- con data-ticket="80": papel ancho, listo para el futuro --- */
  body.imprime-ticket[data-ticket="80"] #ticketVenta{
    page:ticket-80;
    width:72mm;
    padding:2mm 3mm;
    font-size:10.5px;
    line-height:1.45;
    letter-spacing:normal;
  }

  /* ========================================================================
     2 · JERARQUIA DEL RECIBO
     El problema del ticket actual no es el tamano, es que esta PLANO:
     .tk-logo 14px, .tk-folio 15px y .tk-total 13px pesan casi lo mismo, asi
     que el ojo no tiene por donde entrar. Un recibo se lee en dos golpes:
     "de quien es" y "cuanto fue". Esos dos son los que suben.
     ======================================================================== */

  /* -- 50 mm (por defecto) -- */
  body.imprime-ticket #ticketVenta .tk-logo,
  body.imprime-ticket[data-ticket="50"] #ticketVenta .tk-logo{
    font-size:13px; letter-spacing:.12em; line-height:1.2;
  }
  body.imprime-ticket #ticketVenta .tk-sub,
  body.imprime-ticket[data-ticket="50"] #ticketVenta .tk-sub{
    font-size:7.5px; letter-spacing:.08em;
  }
  body.imprime-ticket #ticketVenta .tk-folio,
  body.imprime-ticket[data-ticket="50"] #ticketVenta .tk-folio{
    font-size:11px; letter-spacing:.08em; margin:3px 0;
  }
  body.imprime-ticket #ticketVenta .tk-total,
  body.imprime-ticket[data-ticket="50"] #ticketVenta .tk-total{
    font-size:12px; margin-top:3px;
  }
  body.imprime-ticket #ticketVenta .tk-chico,
  body.imprime-ticket[data-ticket="50"] #ticketVenta .tk-chico{
    font-size:7.5px; line-height:1.5;
  }

  /* -- 80 mm -- */
  body.imprime-ticket[data-ticket="80"] #ticketVenta .tk-logo{ font-size:17px; letter-spacing:.14em; }
  body.imprime-ticket[data-ticket="80"] #ticketVenta .tk-sub{ font-size:9px; letter-spacing:.10em; }
  body.imprime-ticket[data-ticket="80"] #ticketVenta .tk-folio{ font-size:14px; letter-spacing:.10em; margin:4px 0; }
  body.imprime-ticket[data-ticket="80"] #ticketVenta .tk-total{ font-size:15px; margin-top:4px; }
  body.imprime-ticket[data-ticket="80"] #ticketVenta .tk-chico{ font-size:9px; line-height:1.55; }

  /* ========================================================================
     3 · AJUSTES COMUNES A LOS DOS ANCHOS
     ======================================================================== */

  /* el separador punteado necesita aire o el recibo se ve amontonado */
  body.imprime-ticket #ticketVenta .tk-sep{ margin:5px 0; }

  /* En 50 mm caben ~32 caracteres por linea. El nombre del articulo TIENE que
     ceder ante el importe: si no, el importe salta de linea y el recibo deja
     de cuadrar. .tk-n ya es flex:1 con ellipsis; se le fija min-width:0 para
     que el ellipsis funcione de verdad dentro del flex. */
  body.imprime-ticket #ticketVenta .tk-fila{ gap:4px; }
  body.imprime-ticket #ticketVenta .tk-fila .tk-n{ min-width:0; }

  /* el pie no queda pegado a la ultima linea de importes */
  body.imprime-ticket #ticketVenta .tk-centro.tk-chico{ margin-top:5px; }

  /* nada de viudas: que el total no se vaya solo a un segundo trozo de papel */
  body.imprime-ticket #ticketVenta .tk-total,
  body.imprime-ticket #ticketVenta .tk-folio{ break-inside:avoid; }
}

/* ==========================================================================
   4 · PREVISUALIZACION EN PANTALLA (opcional, aditiva)
   venta.css tiene #ticketVenta{display:none} fuera de imprimir, asi que el
   recibo solo se ve al imprimir: no hay forma de revisarlo sin gastar papel.
   Envolviendolo en .jzd-ticket-prev se muestra en pantalla al ancho real.
   Si nadie usa la clase, no cambia nada.
   ========================================================================== */
.jzd-ticket-prev{ display:flex; flex-direction:column; align-items:center; gap:var(--jzd-s4); }
.jzd-ticket-prev .jzd-ticket-papel{
  display:block; width:189px;                 /* 50 mm a 96 dpi */
  padding:8px 9px; background:#fff; color:#000;
  font-family:"Courier New",ui-monospace,monospace;
  font-size:9px; line-height:1.5; letter-spacing:-.01em;
  box-shadow:var(--jzd-e3);
}
.jzd-ticket-prev[data-ticket="80"] .jzd-ticket-papel{
  width:272px;                                /* 72 mm a 96 dpi */
  padding:10px 12px; font-size:10.5px; line-height:1.45; letter-spacing:normal;
}
.jzd-ticket-prev .tk-centro{ text-align:center; }
.jzd-ticket-prev .tk-logo{ font-size:13px; font-weight:800; letter-spacing:.12em; line-height:1.2; }
.jzd-ticket-prev .tk-sub{ font-size:7.5px; letter-spacing:.08em; }
.jzd-ticket-prev .tk-sep{ border:none; border-top:1px dashed #000; margin:5px 0; }
.jzd-ticket-prev .tk-fila{ display:flex; justify-content:space-between; gap:4px; }
.jzd-ticket-prev .tk-fila .tk-n{ flex:1; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
.jzd-ticket-prev .tk-folio{ font-size:11px; font-weight:800; letter-spacing:.08em; text-align:center; margin:3px 0; }
.jzd-ticket-prev .tk-total{ display:flex; justify-content:space-between; font-size:12px; font-weight:800; margin-top:3px; }
.jzd-ticket-prev .tk-chico{ font-size:7.5px; line-height:1.5; }
.jzd-ticket-prev[data-ticket="80"] .tk-logo{ font-size:17px; letter-spacing:.14em; }
.jzd-ticket-prev[data-ticket="80"] .tk-sub{ font-size:9px; letter-spacing:.10em; }
.jzd-ticket-prev[data-ticket="80"] .tk-folio{ font-size:14px; letter-spacing:.10em; margin:4px 0; }
.jzd-ticket-prev[data-ticket="80"] .tk-total{ font-size:15px; margin-top:4px; }
.jzd-ticket-prev[data-ticket="80"] .tk-chico{ font-size:9px; line-height:1.55; }

/* etiqueta del ancho, para saber que se esta viendo */
.jzd-ticket-tag{
  font-size:var(--jzd-fs-3); font-weight:800; letter-spacing:var(--jzd-track-eyebrow);
  text-transform:uppercase; color:var(--jzd-ink-4); font-variant-numeric:tabular-nums;
}