/* ------------------------------------------------------------------ */
/* Design tokens                                                       */
/* ------------------------------------------------------------------ */
:root {
  --main: #084383;
  --main-dark: #062f5e;
  --secondary: #35a2db;
  --secondary-light: #e7f4fb;

  --bg: #f4f6f9;
  --surface: #ffffff;
  --border: #e2e7ee;
  --text: #16233a;
  --text-muted: #62728a;
  --text-faint: #93a1b5;

  --success: #1b8a5a;
  --success-bg: #e7f6ee;
  --success-border: #cdeadd;
  --danger: #c23a3a;
  --danger-bg: #fbeaea;
  --danger-border: #f0b7b7;
  --warn-bg: #fff6e0;
  --warn-text: #8a6a10;

  /* Color de acento para TEXTO/íconos sobre el fondo propio de la app
     (--bg/--surface) — en modo claro es igual a --main, pero en modo
     oscuro se vuelve más brillante para seguir siendo legible. --main y
     --main-dark en cambio NUNCA cambian entre temas: son el azul de marca
     usado como relleno sólido (sidebar, botones, avatares) con texto
     blanco encima, y ese combo se ve bien en ambos temas sin tocarlo. */
  --accent-text: #084383;

  --input-bg: #ffffff;
  --group-row-bg: #e4ecf8;
  --row-alt-bg: #f8fbfd;
  --row-hover-bg: #eef5fa;
  --row-border: #eef1f5;
  --subtle-bg: #eef1f5;
  --badge-purple-bg: #f1ecfa;
  --badge-purple-text: #6b3fb0;
  --pie-swatch-ring: rgba(11, 11, 11, .08);

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(16, 34, 64, 0.06), 0 4px 16px rgba(16, 34, 64, 0.05);

  --gap-sm: 8px;
  --gap-md: 12px;
  --gap-lg: 16px;
  --pad-card: 20px;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --barcode-ink: #000;

  /* Espacio reservado arriba de .main para la campana/chip de usuario
     (position:fixed) — reutilizado por los elementos "pegajosos" (sticky)
     para que no se solapen con esa barra al hacer scroll. */
  --content-top-offset: 70px;
}

/* ------------------------------------------------------------------ */
/* Modo oscuro — toggle manual (menú del chip de usuario), no sigue la
   preferencia del sistema. --main/--main-dark se dejan igual a propósito
   (ver comentario de --accent-text arriba). */
/* ------------------------------------------------------------------ */
:root[data-theme="dark"] {
  --secondary-light: rgba(53, 162, 219, .16);

  --bg: #0e1520;
  --surface: #172130;
  --border: #2a3648;
  --text: #e6ecf6;
  --text-muted: #8b9ab2;
  --text-faint: #64708a;

  --success: #3ecf8e;
  --success-bg: #113325;
  --success-border: #1f5c3f;
  --danger: #f0716f;
  --danger-bg: #3a1717;
  --danger-border: #6b2b2b;
  --warn-bg: #3a2f10;
  --warn-text: #e8b84b;

  --accent-text: #5aa9e6;

  --input-bg: #101a28;
  --group-row-bg: rgba(90, 169, 230, .14);
  --row-alt-bg: #141d2b;
  --row-hover-bg: #1c283a;
  --row-border: #232e40;
  --subtle-bg: #202b3d;
  --badge-purple-bg: #2a2140;
  --badge-purple-text: #c3adf5;
  --pie-swatch-ring: rgba(255, 255, 255, .15);
}
:root[data-theme="dark"] .btn-danger:hover { background: #4a1f1f; }
:root[data-theme="dark"] .date-day.disabled,
:root[data-theme="dark"] .date-day:disabled { color: #46536b; }
:root[data-theme="dark"] input[type=text], :root[data-theme="dark"] input[type=number],
:root[data-theme="dark"] input[type=search], :root[data-theme="dark"] input[type=email],
:root[data-theme="dark"] input[type=password], :root[data-theme="dark"] select,
:root[data-theme="dark"] textarea { color-scheme: dark; }
:root[data-theme="dark"] * { scrollbar-color: var(--border) var(--bg); }
:root[data-theme="dark"] ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
:root[data-theme="dark"] ::-webkit-scrollbar-track { background: transparent; }

/* Las etiquetas de código de barras se imprimen siempre en papel blanco,
   sin importar el tema activo en pantalla al momento de imprimir. */
@media print {
  :root, :root[data-theme="dark"] {
    --bg: #f4f6f9; --surface: #ffffff; --border: #e2e7ee;
    --text: #16233a; --text-muted: #62728a; --text-faint: #93a1b5;
  }
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  transition: background-color .15s ease, color .15s ease;
  /* Fuente tabular para todo número en la app (monto, cantidad, fecha) —
     se hereda a toda la página, así que cada tabla de dinero alinea sus
     columnas sin tener que tocar cada `fmtPrice(...)` uno por uno (son
     decenas de sitios, varios de ellos usan `.textContent` directo, que
     se rompería si `fmtPrice` empezara a devolver HTML con una clase). */
  font-variant-numeric: tabular-nums;
}
.card, .stat-tile, .modal-card, input, select, textarea, .sidebar, table {
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
h1, h2, h3, h4 { margin: 0; }
p { margin: 0; }

/* ------------------------------------------------------------------ */
/* Shell layout                                                        */
/* ------------------------------------------------------------------ */
.app-shell { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
  width: 232px;
  flex-shrink: 0;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
  color: #eaf2fb;
  display: flex;
  flex-direction: column;
  padding: 20px 14px;
  padding-top: calc(20px + env(safe-area-inset-top));
  padding-bottom: calc(20px + env(safe-area-inset-bottom));
  padding-left: calc(14px + env(safe-area-inset-left));
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  transition: transform .22s ease;
}

.brand { padding: 6px 8px 22px; cursor: pointer; }
.brand-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 8px;
}
.brand-logo img { display: block; width: 100%; max-width: 170px; height: auto; }
.brand-sub { font-size: 11.5px; color: #a9c7e6; letter-spacing: .04em; text-transform: uppercase; text-align: center; margin-top: 10px; }

.nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.nav-item {
  display: flex; align-items: center; gap: 11px;
  background: none; border: none; text-align: left;
  color: #cfe1f4;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14.5px;
  font-weight: 600;
  transition: background .12s ease, color .12s ease;
}
.nav-icon { width: 18px; height: 18px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; opacity: .9; }
.nav-icon svg { width: 18px; height: 18px; }
.nav-item:hover { background: rgba(255,255,255,.08); color: #fff; }

.nav-group-toggle {
  display: flex; align-items: center; gap: 6px;
  width: 100%; background: none; border: none; text-align: left;
  color: #82a4c6; padding: 16px 12px 6px;
  cursor: pointer; font-size: 10.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: .07em;
  transition: color .12s ease;
}
.nav-group-toggle:first-child { padding-top: 2px; }
.nav-group-toggle:hover { color: #cfe1f4; }
.nav-group-label { flex: 1; }
.nav-group-chevron { width: 12px; height: 12px; flex-shrink: 0; transition: transform .18s ease; opacity: .7; }
.nav-group-toggle.collapsed .nav-group-chevron { transform: rotate(-90deg); }
.nav-group { display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.nav-group.collapsed { display: none; }
.nav-item.active { background: var(--secondary); color: #06263f; font-weight: 700; }

.sidebar-footer { font-size: 10.5px; color: #82a4c6; padding: 10px 8px 0; line-height: 1.4; }
.sidebar-credit {
  background: none; border: none; padding: 0; margin: 0; width: 100%; text-align: left;
  font: inherit; color: inherit; cursor: pointer;
}
.sidebar-credit:hover { color: #cfe1f4; text-decoration: underline; }

/* Easter egg — clic en "Desarrollado por Ari Ramos" — ver openDevEasterEgg()
   en app.js. Puramente decorativo, se cierra solo a los 3 segundos.
   dev-easter-egg.webp es una animación real de 12 cuadros (no dibujada a
   mano), por eso solo hace falta el pop-in de la tarjeta acá. */
.dev-egg-overlay { background: rgba(15, 26, 45, .7); cursor: pointer; }
.dev-egg-card {
  width: 320px; height: 320px; max-width: 82vw; max-height: 82vw;
  border-radius: var(--radius); overflow: hidden;
  animation: eggPopIn .25s ease;
}
.dev-egg-card img { width: 100%; height: 100%; display: block; object-fit: cover; }
@keyframes eggPopIn { from { transform: scale(.85); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* ------------------------------------------------------------------ */
/* Pantallas de autenticación (login / configuración inicial)          */
/* ------------------------------------------------------------------ */
#auth-screen:empty { display: none; }
.auth-wrap {
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
}
.auth-card {
  width: 100%; max-width: 400px;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: 0 24px 64px rgba(8, 16, 32, .35); padding: 28px 26px;
}
.auth-logo { display: flex; justify-content: center; margin-bottom: 18px; }
.auth-logo img { width: 100%; max-width: 190px; height: auto; }
.auth-error { color: var(--danger); font-size: 13px; min-height: 1em; margin-top: 6px; }
.auth-card a { color: var(--secondary); font-weight: 600; }

/* Overlay de acento azul (misma familia visual que el sidebar), usado en
   los modales de contraseña — la tarjeta adentro se queda blanca normal */
.modal-overlay.modal-overlay-navy { background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%); }

.main { flex: 1; min-width: 0; padding: var(--content-top-offset) 34px 60px; margin-left: 232px; transition: margin-left .22s ease; }
.view { max-width: 1180px; margin: 0 auto; min-height: calc(100dvh - 100px); }

/* Colapsar el menú izquierdo también en PC (no solo en mobile) — mismo
   botón/animación hamburguesa -> X que ya existía solo para mobile. */
@media (min-width: 861px) {
  body.sidebar-collapsed .sidebar { transform: translateX(-100%); }
  body.sidebar-collapsed .main { margin-left: 0; }
}

.mobile-menu-toggle {
  display: flex;
  position: fixed;
  top: calc(14px + env(safe-area-inset-top));
  left: calc(14px + env(safe-area-inset-left));
  z-index: 220;
  width: 40px; height: 40px; align-items: center; justify-content: center;
  background: var(--main); color: #fff; border: none; border-radius: var(--radius-sm);
  box-shadow: var(--shadow); cursor: pointer;
}
.mobile-menu-toggle svg { width: 20px; height: 20px; }
.menu-line { transition: transform .22s ease, opacity .15s ease; transform-box: fill-box; transform-origin: center; }
.mobile-menu-toggle.open .menu-line-top { transform: translateY(6px) rotate(45deg); }
.mobile-menu-toggle.open .menu-line-mid { opacity: 0; }
.mobile-menu-toggle.open .menu-line-bottom { transform: translateY(-6px) rotate(-45deg); }
.sidebar-backdrop {
  display: none;
  position: fixed; inset: 0; z-index: 190;
  background: rgba(10, 20, 38, .5);
}
.sidebar-backdrop.visible { display: block; }

/* Campana de notificaciones + chip de usuario, arriba a la derecha en todo momento */
.topbar-actions {
  position: fixed;
  top: calc(14px + env(safe-area-inset-top));
  right: calc(14px + env(safe-area-inset-right));
  z-index: 220;
  display: flex; align-items: center; gap: 8px;
}
.user-chip { position: relative; }
.user-chip-btn {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 12px 5px 5px; cursor: pointer; box-shadow: var(--shadow);
}
.user-chip-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
  color: #fff; font-size: 12px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.avatar-img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }
.avatar-table-thumb {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
  color: #fff; font-size: 12px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.avatar-lg {
  width: 96px; height: 96px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
  color: #fff; font-size: 32px; font-weight: 800;
  display: flex; align-items: center; justify-content: center; margin: 0 auto 10px;
}
.avatar-xl {
  width: 128px; height: 128px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
  background: linear-gradient(180deg, var(--main) 0%, var(--main-dark) 100%);
  color: #fff; font-size: 42px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
/* Foto de un documento (ej. permiso firmado) — a diferencia de avatar-xl,
   NO es circular: recortar un documento en círculo le corta información. */
.photo-doc-preview {
  width: 100%; max-width: 480px; aspect-ratio: 4 / 3; border-radius: var(--radius-sm);
  flex-shrink: 0; overflow: hidden; background: var(--subtle-bg);
  border: 1px solid var(--border); color: var(--text-faint); font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
.perm-photo-thumb {
  width: 130px; height: 96px; object-fit: cover; border-radius: var(--radius-sm);
  border: 1px solid var(--border); cursor: pointer; display: block;
}
.perm-photo-missing {
  width: 130px; height: 96px; border-radius: var(--radius-sm); border: 1px dashed var(--border);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-faint); font-size: 11px; cursor: pointer; text-align: center;
}
.user-chip-text { display: flex; flex-direction: column; align-items: flex-start; max-width: 150px; line-height: 1.25; }
.user-chip-name { font-size: 13px; font-weight: 700; color: var(--text); text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.user-chip-username { font-size: 10.5px; font-weight: 500; color: var(--text-faint); text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.user-chip-chevron { width: 15px; height: 15px; color: var(--text-muted); transition: transform .15s ease; flex-shrink: 0; }
.user-chip.open .user-chip-chevron { transform: rotate(180deg); }
.user-chip-backdrop {
  display: none;
  position: fixed; inset: 0; z-index: 215;
  background: rgba(10, 20, 38, .35);
}
.user-chip-backdrop.visible { display: block; }
.user-chip-menu {
  display: none; position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 16px 40px rgba(8, 16, 32, .22); min-width: 210px; padding: 8px; z-index: 221;
}
.user-chip.open .user-chip-menu { display: block; }
.user-chip-menu-header { padding: 8px 10px 10px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.user-chip-menu-name { font-size: 13.5px; font-weight: 700; color: var(--text); }
.user-chip-menu-role { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }
.user-chip-menu button {
  display: block; width: 100%; text-align: left; background: none; border: none;
  padding: 9px 10px; border-radius: var(--radius-sm); font-size: 13.5px; color: var(--text); cursor: pointer;
}
.user-chip-menu button:hover { background: var(--bg); }
.user-chip-menu-theme-btn { display: flex !important; align-items: center; justify-content: space-between; gap: 10px; }
.theme-switch {
  position: relative; width: 34px; height: 20px; border-radius: 999px; flex-shrink: 0;
  background: var(--border); transition: background .15s ease;
}
.theme-switch-knob {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.3); transition: transform .15s ease;
}
.theme-switch.on { background: var(--main); }
.theme-switch.on .theme-switch-knob { transform: translateX(14px); }

.global-search { position: relative; }
.global-search-btn {
  position: relative; width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
  display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-muted);
}
.global-search-btn:hover { color: var(--text); }
.global-search-btn svg { width: 18px; height: 18px; }
.global-search-panel {
  display: none; position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 16px 40px rgba(8, 16, 32, .22); width: 360px; max-width: 88vw; z-index: 221; overflow: hidden;
}
.global-search.open .global-search-panel { display: block; }
#global-search-input {
  width: 100%; border: none; border-bottom: 1px solid var(--border); border-radius: 0;
  padding: 12px 14px; font-size: 13.5px; background: var(--surface); color: var(--text);
}
#global-search-input:focus { outline: none; }
.global-search-results { max-height: 400px; overflow-y: auto; }
.global-search-hint { padding: 16px 14px; font-size: 12.5px; color: var(--text-faint); text-align: center; }
.global-search-group-title {
  padding: 9px 14px 5px; font-size: 10.5px; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; color: var(--accent-text);
}
.global-search-item {
  display: block; width: 100%; text-align: left; padding: 9px 14px; cursor: pointer;
  background: none; border: none; font-size: 13px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.global-search-item:hover { background: var(--bg); }

.notif-bell { position: relative; }
.notif-bell-btn {
  position: relative; width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
  display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-muted);
}
.notif-bell-btn:hover { color: var(--text); }
.notif-bell-btn svg { width: 19px; height: 19px; }
@keyframes bell-ring {
  0%, 100% { transform: rotate(0deg); }
  15% { transform: rotate(16deg); }
  30% { transform: rotate(-13deg); }
  45% { transform: rotate(10deg); }
  60% { transform: rotate(-6deg); }
  75% { transform: rotate(3deg); }
}
.notif-bell-btn svg.ringing { animation: bell-ring .6s ease; transform-origin: 50% 15%; }
.notif-badge {
  position: absolute; top: -3px; right: -3px; min-width: 17px; height: 17px; padding: 0 4px;
  background: var(--danger); color: #fff; font-size: 10px; font-weight: 800; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; border: 2px solid var(--bg);
}
.notif-panel {
  display: none; position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 16px 40px rgba(8, 16, 32, .22); width: 300px; max-width: 85vw; z-index: 221; overflow: hidden;
}
.notif-bell.open .notif-panel { display: block; }
.notif-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 13px; font-weight: 700;
}
.notif-panel-header button {
  background: none; border: none; color: var(--accent-text); font-size: 11.5px; font-weight: 700; cursor: pointer; padding: 0;
}
.notif-list { max-height: 320px; overflow-y: auto; }
.notif-item {
  display: flex; align-items: flex-start; gap: 8px; padding: 11px 14px; cursor: pointer;
  border-bottom: 1px solid var(--border); font-size: 12.5px; color: var(--text);
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--bg); }
.notif-item-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--secondary); margin-top: 5px; flex-shrink: 0; }
.notif-item-text { flex: 1; line-height: 1.4; }
.notif-item-time { display: block; color: var(--text-faint); font-size: 10.5px; margin-top: 2px; }
.notif-item-read { color: var(--text-muted); }
.notif-item-read .notif-item-dot { background: var(--border); }
.notif-empty { padding: 24px 14px; text-align: center; color: var(--text-faint); font-size: 12.5px; }

@media (max-width: 860px) {
  .mobile-menu-toggle { display: flex; }
  .user-chip-text { display: none; }
  .user-chip-btn { padding: 5px; }
  .sidebar {
    transform: translateX(-100%);
    transition: transform .22s ease;
    z-index: 200;
    width: 240px;
  }
  .sidebar.open { transform: translateX(0); }
  .main {
    --content-top-offset: calc(66px + env(safe-area-inset-top));
    margin-left: 0;
    padding: var(--content-top-offset) calc(16px + env(safe-area-inset-right)) calc(40px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  }
  .page-title { font-size: 24px; }
  .card { padding: 14px; }
}

/* El buscador global y las notificaciones se posicionan con `right: 0`
   relativo a su propio botón (no al borde de la pantalla) — en celular el
   ícono de búsqueda queda lejos del borde derecho (a la izquierda de
   notificaciones + usuario), así que ese panel de 360px se salía por
   completo del lado izquierdo de la pantalla (hasta 90px invisibles/fuera
   de alcance). En vez de depender de esa posición relativa al ícono, se
   ancla directo a los bordes del viewport. */
@media (max-width: 520px) {
  .global-search-panel, .notif-panel {
    position: fixed;
    top: calc(62px + env(safe-area-inset-top));
    left: calc(12px + env(safe-area-inset-left));
    right: calc(12px + env(safe-area-inset-right));
    width: auto;
    max-width: none;
  }
}

/* ------------------------------------------------------------------ */
/* Header / page structure                                             */
/* ------------------------------------------------------------------ */
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--gap-lg); margin-bottom: 22px; flex-wrap: wrap; }
.page-title { font-size: 30px; font-weight: 700; letter-spacing: -.01em; }
.page-desc { color: var(--text-muted); font-size: 13.5px; margin-top: 4px; max-width: 560px; }

.grid { display: grid; gap: var(--gap-lg); }
.grid > * { min-width: 0; }
.grid > .card + .card { margin-top: 0; }
.grid-5 { grid-template-columns: repeat(5, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 900px) {
  .grid-5 { grid-template-columns: repeat(3,1fr); }
  .grid-4 { grid-template-columns: repeat(2,1fr); }
  .grid-3 { grid-template-columns: repeat(2,1fr); }
  .grid-2 { grid-template-columns: 1fr; }
}
@media (max-width: 700px) { .grid-2 { grid-template-columns: 1fr; } }
@media (max-width: 560px) { .grid-3 { grid-template-columns: 1fr; } .grid-5 { grid-template-columns: repeat(2,1fr); } }

.stack { display: flex; flex-direction: column; gap: var(--gap-lg); }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--pad-card);
}
.card + .card { margin-top: var(--gap-lg); }
.card-title { font-size: 16px; font-weight: 700; margin-bottom: 2px; }
.card-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.card-desc { font-size: 12.5px; color: var(--text-muted); margin-bottom: var(--gap-md); }

/* Stat tiles */
.stat-tile { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px 18px; }

.set-card { cursor: pointer; transition: box-shadow .15s ease, transform .15s ease; }
.set-card:hover { box-shadow: 0 6px 20px rgba(16, 34, 64, .13); transform: translateY(-2px); }
/* overflow-wrap: un monto largo (ej. "L 51,052,368.90") es una sola
   palabra sin espacios — sin esto no puede partirse en dos líneas y en
   celular (tarjetas de ~164px en un grid de 4) se sale del recuadro,
   agrandando el ancho de toda la página en vez de quedarse contenido. */
.stat-num { font-size: 26px; font-weight: 800; color: var(--accent-text); letter-spacing: -.02em; overflow-wrap: break-word; }
.stat-tile-compact .stat-num { font-size: 18px; }
.stat-label { font-size: 12px; color: var(--text-muted); margin-top: 2px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }

/* ------------------------------------------------------------------ */
/* Forms                                                                */
/* ------------------------------------------------------------------ */
.field { margin-bottom: var(--gap-md); }
.field label { display: block; font-size: 12.5px; font-weight: 700; color: var(--text); margin-bottom: 5px; }
.field .hint, .hint { font-size: 11.5px; color: var(--text-faint); margin-top: 4px; margin-bottom: 4px; }
.req { color: var(--danger); margin-left: 2px; }
input[type=text], input[type=number], input[type=search], input[type=email], input[type=password], select, textarea {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--input-bg);
  color: var(--text);
  outline: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--secondary);
  box-shadow: 0 0 0 3px var(--secondary-light);
}

/* Text input backed by a <datalist> — looks like a select (dropdown arrow)
   but still supports typing to filter/autocomplete. */
input.combo-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2362728a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 14px;
  padding-right: 32px;
  cursor: pointer;
}
.row { display: flex; gap: var(--gap-md); flex-wrap: wrap; }
.row > * { flex: 1; min-width: 160px; }

.scan-input {
  font-family: var(--mono);
  letter-spacing: .04em;
  font-size: 14px;
  border-width: 2px !important;
}
.scan-input.armed { border-color: var(--secondary) !important; box-shadow: 0 0 0 3px var(--secondary-light); }

.suggest-list { margin-top: 6px; border-radius: var(--radius-sm); overflow-y: auto; max-height: 220px; }
.suggest-list:empty { margin-top: 0; }
.suggest-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 12px; font-size: 13px; cursor: pointer;
  border: 1px solid var(--border); border-top: none;
}
.suggest-item:first-child { border-top: 1px solid var(--border); border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm); }
.suggest-item:last-child { border-bottom-left-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
.suggest-item:hover { background: var(--secondary-light); }
.suggest-item .code { color: var(--text-faint); font-size: 11.5px; flex-shrink: 0; }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 9px 15px;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  transition: filter .12s ease, background .12s ease;
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--main); color: #fff; }
.btn-primary:hover { filter: brightness(1.1); }
.btn-secondary { background: var(--secondary); color: #062f5e; }
.btn-secondary:hover { filter: brightness(1.05); }
.btn-ghost { background: transparent; color: var(--accent-text); border-color: var(--border); }
.btn-ghost:hover { background: var(--secondary-light); }
.btn-danger { background: var(--danger-bg); color: var(--danger); }
.btn-danger:hover { background: #f6d9d9; }
.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }
.btn-row { display: flex; gap: var(--gap-sm); flex-wrap: wrap; margin-top: 6px; }

/* Botones de solo ícono (editar/eliminar/imprimir) — filas de tabla y
   tarjetas donde el espacio es limitado. Mismo color por variante
   (btn-ghost/btn-danger) que ya tenían las versiones con texto. */
.btn-icon { padding: 0; width: 30px; height: 30px; gap: 0; flex-shrink: 0; }
.btn-icon svg { width: 15px; height: 15px; }

/* Tables */
table { width: 100%; border-collapse: collapse; font-size: 13px; color: var(--text); }
thead th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); font-weight: 700; padding: 8px 10px; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

/* Sortable column headers (Panel) */
.sort-arrows { display: inline-flex; flex-direction: column; gap: 1px; vertical-align: middle; margin-left: 3px; }
.sort-arrow {
  background: none; border: none; cursor: pointer; padding: 0; margin: 0;
  color: var(--text-faint); font-size: 8px; line-height: 8px;
}
.sort-arrow:hover { color: var(--secondary); }
.sort-arrow.active { color: var(--accent-text); }
.sortable-label { cursor: pointer; }
.sortable-label:hover { color: var(--accent-text); text-decoration: underline; }

/* Dual-thumb price range slider: two range inputs stacked on one visual track */
.dual-slider { position: relative; height: 22px; margin-top: 8px; }
.dual-slider-track {
  position: absolute; top: 50%; left: 0; right: 0; height: 4px;
  transform: translateY(-50%);
  background: var(--border); border-radius: 999px;
}
.dual-slider-fill {
  position: absolute; top: 50%; height: 4px;
  transform: translateY(-50%);
  background: var(--accent-text); border-radius: 999px;
}
.dual-range {
  position: absolute; top: 0; left: 0; width: 100%; height: 22px; margin: 0;
  appearance: none; -webkit-appearance: none; background: transparent; pointer-events: none;
}
.dual-range::-webkit-slider-runnable-track { background: transparent; height: 4px; }
.dual-range::-moz-range-track { background: transparent; height: 4px; border: none; }
.dual-range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none; pointer-events: auto;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent-text); border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--border), var(--shadow);
  cursor: pointer; margin-top: -6px;
}
.dual-range::-moz-range-thumb {
  pointer-events: auto; width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent-text); border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--border), var(--shadow);
  cursor: pointer;
}
.price-range-ticks {
  display: flex; justify-content: space-between; margin-top: 8px;
  font-size: 11px; color: var(--text-faint);
}

/* Supplier chips */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--secondary-light); color: var(--accent-text);
  padding: 5px 8px 5px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
}
.chip button {
  background: none; border: none; color: var(--accent-text); cursor: pointer;
  font-weight: 800; font-size: 14px; padding: 0 2px; line-height: 1; opacity: .6;
}
.chip button:hover { opacity: 1; }
tbody td { padding: 10px; border-bottom: 1px solid var(--row-border); vertical-align: middle; white-space: nowrap; }
tbody td.wrap { white-space: normal; max-width: 240px; }
tbody tr:nth-child(even) { background: var(--row-alt-bg); }
tbody tr:hover { background: var(--row-hover-bg); }
tbody tr.clickable-row, tbody td.clickable-row { cursor: pointer; }
.client-group-row { background: var(--bg); }
.group-expand-arrow { display: inline-block; width: 12px; color: var(--text-faint); }
.table-wrap { overflow-x: auto; }
.table-scroll-mirror { overflow-x: auto; overflow-y: hidden; height: 16px; margin-bottom: 6px; }
.table-scroll-mirror-inner { height: 1px; }
.table-wrap-v-scroll { max-height: 480px; overflow-y: auto; }
.table-wrap-v-scroll thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }
/* Productos (pestaña Productos y Panel) tienen muchas más filas que el
   resto de las tablas — les damos más alto antes de necesitar scroll. */
.table-wrap-v-scroll-tall { max-height: 1100px; }
/* Columnas redimensionables (como Excel) — ver makeTableResizable() en
   app.js. table-layout:fixed es necesario para que los anchos manuales se
   respeten; sin él el navegador vuelve a acomodar según el contenido. */
.resizable-table { table-layout: fixed; }
.resizable-table th, .resizable-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.resizable-table th { position: relative; }
.col-resize-handle {
  position: absolute; top: 0; right: -4px; width: 8px; height: 100%; cursor: col-resize; z-index: 2;
}
.col-resize-handle::after {
  content: ""; position: absolute; top: 15%; bottom: 15%; left: 50%; width: 2px;
  transform: translateX(-50%); background: var(--border); border-radius: 1px;
}
.col-resize-handle:hover::after, .col-resizing .col-resize-handle::after { background: var(--main); width: 3px; }
.col-resize-handle:hover, .col-resizing .col-resize-handle { background: rgba(8, 67, 131, .12); }
body.col-resizing { cursor: col-resize; user-select: none; }
/* Productos/Panel tienen muchas columnas (incluyendo dos precios extra) —
   un poco menos de padding por celda ayuda a que quepan sin scroll
   horizontal en pantallas anchas, sin afectar el resto de las tablas. */
.table-wrap-v-scroll-tall table th, .table-wrap-v-scroll-tall table td { padding-left: 7px; padding-right: 7px; }
.mono { font-family: var(--mono); font-size: 12.5px; }

.badge {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--secondary-light); color: var(--accent-text);
  font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
}
.badge-muted { background: var(--subtle-bg); color: var(--text-muted); }
.badge-warn { background: var(--warn-bg); color: var(--warn-text); }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-purple { background: var(--badge-purple-bg); color: var(--badge-purple-text); }

.status-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  width: auto; border: none; cursor: pointer;
  font-size: 11px; font-weight: 700; padding: 3px 20px 3px 9px; border-radius: 999px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 6px center; background-size: 10px;
  flex-shrink: 0;
}
.status-select:hover { filter: brightness(.95); }
.status-select:focus { outline: 2px solid var(--secondary); outline-offset: 1px; }

.empty-state { text-align: center; padding: 40px 20px; color: var(--text-muted); }
.empty-state .big { font-size: 30px; margin-bottom: 8px; }
.empty-state-art { display: flex; justify-content: center; margin-bottom: 10px; color: var(--text-faint); }

.upcoming-dates-list { display: flex; flex-direction: column; gap: 2px; }
.upcoming-date-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 6px;
  border-bottom: 1px solid var(--border);
}
.upcoming-date-row:last-child { border-bottom: none; }
.upcoming-date-icon { font-size: 16px; flex-shrink: 0; }
.upcoming-date-name { font-weight: 700; color: var(--text); flex: 0 0 auto; }
.upcoming-date-detail { color: var(--text-muted); font-size: 12.5px; flex: 1 1 auto; }
.upcoming-date-when { font-weight: 700; font-size: 12.5px; color: var(--text-muted); flex-shrink: 0; }
.upcoming-date-today { color: var(--main); }

/* Toast — arriba a la derecha en login/registro (sin chip encima); arriba
   al centro, con texto centrado, para los mensajes generales dentro de la
   app; arriba a la derecha de nuevo para pantallas de cuenta (toast-stack-top,
   ej. "Crear usuario"), igual que login. Cada contenedor apila varios
   toasts a la vez (uno debajo del otro) si se disparan casi juntos. */
.toast-stack, .toast-stack-top {
  position: fixed;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-end;
  pointer-events: none;
}
.toast-stack {
  top: calc(24px + env(safe-area-inset-top));
  right: calc(20px + env(safe-area-inset-right));
}
.toast-stack-top {
  top: calc(64px + env(safe-area-inset-top));
  right: calc(20px + env(safe-area-inset-right));
}

body.app-mode .toast-stack {
  top: calc(64px + env(safe-area-inset-top));
  right: auto;
  left: 50%;
  align-items: center;
  transform: translateX(-50%);
}

.toast-item {
  background: var(--main); color: #fff; padding: 11px 16px; border-radius: var(--radius-sm);
  font-size: 13px; font-weight: 600; box-shadow: var(--shadow);
  max-width: min(360px, calc(100vw - 40px));
  opacity: 0; transform: translateY(-8px);
  transition: opacity .18s ease, transform .18s ease;
  pointer-events: auto;
}
.toast-item.show { opacity: 1; transform: translateY(0); }
.toast-item.error { background: var(--danger); }
/* Los de éxito ya no llevan verde — se quedan con el azul de marca por
   defecto de .toast-item (var(--main)), para que se sientan más nativos
   de la app en vez de un semáforo genérico rojo/verde. */

.toast-item-undo {
  display: flex; align-items: center; gap: 12px; position: relative;
  padding-bottom: 14px; overflow: hidden; max-width: min(400px, calc(100vw - 40px));
}
.toast-undo-text { flex: 1; }
.toast-undo-btn {
  background: none; border: 1px solid rgba(255,255,255,.4); color: #fff; border-radius: var(--radius-sm);
  padding: 4px 10px; font-size: 12px; font-weight: 700; cursor: pointer; flex-shrink: 0;
}
.toast-undo-btn:hover { background: rgba(255,255,255,.15); }
.toast-undo-bar {
  position: absolute; left: 0; bottom: 0; height: 3px; width: 100%;
  background: rgba(255,255,255,.5); transform-origin: left;
  animation: toast-undo-shrink 3s linear forwards;
}
@keyframes toast-undo-shrink { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* Scan list (serialization) */
.scan-list { border: 1px solid var(--border); border-radius: var(--radius-sm); max-height: 280px; overflow-y: auto; }
.scan-list-item {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px; border-bottom: 1px solid var(--row-border); font-size: 13px;
}
.scan-list-item:last-child { border-bottom: none; }
.scan-list-item .n { color: var(--text-faint); font-size: 11px; width: 22px; }

/* Barcode chip in tables/results */
.barcode-chip { display: inline-flex; align-items: center; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 4px; }
.barcode-chip svg { display: block; }

.product-result {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 16px 0 6px; text-align: center;
}
.product-result .model { font-size: 13px; font-weight: 600; color: var(--text); }

.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }

/* ------------------------------------------------------------------ */
/* Stock modal (entrada/salida, caja registradora)                     */
/* ------------------------------------------------------------------ */
.modal-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(15, 26, 45, .55);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.modal-card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: 0 24px 64px rgba(8, 16, 32, .35);
  width: 100%; max-width: 420px;
  max-height: 90vh; overflow-y: auto;
  padding: 22px;
}
.modal-card-wide { max-width: 560px; }
.modal-card-xwide { max-width: 760px; }
.modal-card-wo { max-width: 1400px; }

/* Título de sección dentro de un formulario largo (ej. Empleados) — debe
   distinguirse claramente tanto del título de la tarjeta como de las
   etiquetas de cada campo. */
.form-section-title {
  font-size: 15px; font-weight: 800; color: var(--accent-text);
  margin: 22px 0 12px; padding-bottom: 6px; border-bottom: 2px solid var(--secondary-light);
}
.form-section-title:first-of-type { margin-top: 2px; }

/* Popup de detalle de empleado */
.modal-title.emp-modal-name { font-size: 24px; font-weight: 800; color: var(--accent-text); }
.emp-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px 20px; }
/* Variante compacta — valores cortos (Sí/No, un estatus, un número de
   días) que deben caber en una sola fila aunque haya varios. */
.emp-detail-grid-tight { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }

/* Lista de servicios externos de una orden, cuando hay más de uno */
.es-order-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.es-order-item { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 8px 12px; background: var(--bg); }
.es-order-item-name { font-weight: 700; font-size: 13.5px; color: var(--text); margin-bottom: 3px; }
.es-order-item-contacts { font-size: 12px; color: var(--text-muted); }
.es-order-item-contact { margin-bottom: 5px; }
.es-order-item-contact:last-child { margin-bottom: 0; }
.es-order-item-contact-name { display: block; font-weight: 600; color: var(--text); }
.es-order-item-contact-meta { display: block; word-break: break-word; line-height: 1.4; }
.emp-detail-row { display: flex; flex-direction: column; gap: 2px; }
.emp-detail-label { font-size: 11px; color: var(--text-faint); }
.emp-detail-value { font-size: 14px; color: var(--text); font-weight: 600; }

/* Input con un prefijo visual fijo pegado a la izquierda (ej. "+504", "L") */
.input-prefix-group { display: flex; align-items: stretch; }
.input-prefix {
  display: flex; align-items: center; padding: 0 10px; background: var(--bg);
  border: 1px solid var(--border); border-right: none;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  font-size: 13px; color: var(--text-muted); font-weight: 700; white-space: nowrap;
}
.input-prefix-group input { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

/* Campo de contraseña con botón de "ojo" para mostrar/ocultar lo escrito */
.password-field-wrap { position: relative; }
.password-field-wrap input { width: 100%; padding-right: 40px; }
.password-toggle-btn {
  position: absolute; top: 0; right: 0; bottom: 0; width: 40px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; cursor: pointer; color: var(--text-faint);
}
.password-toggle-btn:hover { color: var(--text-muted); }
.password-toggle-btn svg { width: 18px; height: 18px; }
.password-toggle-btn .eye-off-icon { display: none; }
.password-toggle-btn.showing .eye-icon { display: none; }
.password-toggle-btn.showing .eye-off-icon { display: block; }

/* Botón de "escanear con la cámara" junto a un campo de texto — mismo
   patrón que .password-field-wrap/.password-toggle-btn de arriba. */
.scan-camera-wrap { position: relative; }
.scan-camera-wrap input { width: 100%; padding-right: 38px; }
.scan-camera-btn {
  position: absolute; top: 0; right: 0; bottom: 0; width: 36px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; cursor: pointer; color: var(--text-faint);
}
.scan-camera-btn:hover { color: var(--secondary); }
.scan-camera-btn svg { width: 18px; height: 18px; }
#camera-scan-region { min-height: 260px; border-radius: var(--radius-sm); overflow: hidden; background: #000; }
#camera-scan-region video { width: 100%; border-radius: var(--radius-sm); }
.confirm-overlay { z-index: 1100; }
.confirm-card { max-width: 380px; }
.confirm-message { color: var(--text-muted); font-size: 13.5px; line-height: 1.5; margin: 4px 0 18px; }
.modal-footer { display: flex; align-items: center; justify-content: flex-end; margin-top: 6px; }
.modal-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.modal-title { font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.modal-close {
  background: none; border: none; font-size: 22px; line-height: 1;
  color: var(--text-muted); cursor: pointer; padding: 2px 4px; flex-shrink: 0;
}
.modal-close:hover { color: var(--text); }
.copy-inline-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; margin-left: 6px; vertical-align: middle;
  background: none; border: none; border-radius: var(--radius-sm); cursor: pointer;
  color: var(--text-faint); padding: 0;
}
.copy-inline-btn:hover { color: var(--accent-text); background: var(--secondary-light); }
.copy-inline-btn svg { width: 14px; height: 14px; }
/* Variante chica — junto al código en tarjetas/filas (Kanban, Cuadrícula,
   Tabla), donde el botón de 22px del modal se ve desproporcionado. */
.copy-inline-btn-sm { width: 16px; height: 16px; margin-left: 4px; }
.copy-inline-btn-sm svg { width: 10px; height: 10px; }

/* Ícono de ayuda "?" junto al título de cada pestaña — ver helpIconHTML()/
   openHelpModal() en app.js. */
.help-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 21px; height: 21px; margin-left: 8px; vertical-align: middle;
  border-radius: 50%; border: 1.5px solid var(--border); background: var(--bg);
  color: var(--text-faint); font-size: 12.5px; font-weight: 800; line-height: 1;
  cursor: pointer; padding: 0;
}
.help-icon-btn:hover { background: var(--secondary); border-color: var(--secondary); color: #fff; }
.help-modal-card { max-width: 600px; }
.help-modal-body h4 { font-size: 14px; font-weight: 800; color: var(--accent-text); margin: 16px 0 6px; }
.help-modal-body h4:first-child { margin-top: 0; }
.help-modal-body p { font-size: 13.5px; color: var(--text-muted); line-height: 1.55; margin: 0 0 10px; }
.help-modal-body ul { margin: 0 0 10px; padding-left: 20px; display: flex; flex-direction: column; gap: 7px; }
.help-modal-body li { font-size: 13px; color: var(--text); line-height: 1.5; }
.help-tip {
  display: flex; gap: 9px; align-items: flex-start;
  background: var(--secondary-light); border-radius: var(--radius-sm);
  padding: 10px 12px; font-size: 12.5px; color: var(--text-muted); margin-top: 6px;
}
.help-tip svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--secondary); margin-top: 1px; }

.stock-current { text-align: center; background: var(--bg); border-radius: var(--radius-sm); padding: 16px; margin-bottom: 18px; }
.stock-current-num { font-size: 34px; font-weight: 800; color: var(--accent-text); letter-spacing: -.02em; }
.stock-current-label { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }

.stock-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.stock-action label { display: block; font-size: 12px; font-weight: 700; margin-bottom: 5px; }
.stock-action .row { gap: 6px; flex-wrap: nowrap; }
.stock-action .row input { flex: 1 1 auto; min-width: 0; padding: 9px 8px; }
.stock-action .row button { flex: 0 0 auto; }
.stock-action-in label { color: var(--success); }
.stock-action-out label { color: var(--danger); }

.no-spinner::-webkit-inner-spin-button,
.no-spinner::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.no-spinner { -moz-appearance: textfield; }

/* ------------------------------------------------------------------ */
/* Órdenes de Trabajo                                                  */
/* ------------------------------------------------------------------ */

.wo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.wo-card { cursor: pointer; display: flex; flex-direction: column; min-height: 176px; min-width: 0; }
.wo-card-overdue {
  border-color: var(--danger-border); background: var(--danger-bg); border-left: 4px solid var(--danger);
  box-shadow: 0 1px 2px rgba(194,58,58,.1), 0 5px 16px rgba(194,58,58,.12);
}
.wo-card-overdue .wo-code { color: var(--danger); font-weight: 800; }
.wo-overdue-text { color: var(--danger); font-weight: 800; }
/* "Orden sin movimiento" — ver isWorkOrderStale()/woStaleBadgeHTML() en
   app.js. Ámbar (no rojo) a propósito: no es un error como "atrasada",
   solo una señal de que nadie la ha tocado en varios días. */
.wo-stale-badge {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 4px;
  font-size: 11px; font-weight: 700; color: var(--warn-text);
  background: var(--warn-bg); border-radius: 999px; padding: 2px 8px;
}

.wo-header-actions { align-items: center; gap: 10px; }
.btn-row-divider { width: 1px; height: 22px; background: var(--border); flex-shrink: 0; }
.view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; }
.view-toggle-btn {
  background: var(--surface); border: none; padding: 9px 16px; font-size: 13px; font-weight: 600;
  cursor: pointer; color: var(--text-muted);
}
.view-toggle-btn + .view-toggle-btn { border-left: 1px solid var(--border); }
.view-toggle-btn.active { background: var(--main); color: #fff; }

.view-wide { max-width: none; }
/* Dentro de una .view-wide, la mayoría del contenido (título, tabs,
   formularios, tarjeta de filtro) debe seguir viéndose angosto y
   centrado como antes — solo la tabla/grid donde realmente aparecen los
   productos debe usar el ancho completo. */
.narrow-block { max-width: 1180px; margin-left: auto; margin-right: auto; }

/* Vista de Calendario (Órdenes de Trabajo) */
.wo-cal-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.wo-cal-month-label { font-size: 16px; font-weight: 800; color: var(--text); text-transform: capitalize; min-width: 150px; text-align: center; }
.wo-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.wo-cal-dow-row { margin-bottom: 4px; }
.wo-cal-dow { text-align: center; font-size: 11px; font-weight: 700; color: var(--text-faint); text-transform: uppercase; padding: 4px 0; }
.wo-cal-cell {
  min-height: 104px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 6px; display: flex; flex-direction: column; gap: 4px; background: var(--surface);
}
.wo-cal-cell-other { background: var(--bg); border-style: dashed; opacity: .5; }
.wo-cal-cell-today { border-color: var(--accent-text); border-width: 2px; }
.wo-cal-daynum { font-size: 12px; font-weight: 700; color: var(--text-muted); }
.wo-cal-cell-today .wo-cal-daynum { color: var(--accent-text); }
.wo-cal-chips { display: flex; flex-direction: column; gap: 3px; overflow: hidden; }
.wo-cal-chip {
  font-size: 11px; font-weight: 600; padding: 2px 6px; border-radius: 4px; cursor: pointer;
  background: var(--subtle-bg);
  background: color-mix(in srgb, var(--chip-accent, var(--text-faint)) 16%, var(--surface));
  color: var(--chip-accent, var(--text-muted)); border-left: 3px solid var(--chip-accent, var(--text-faint));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wo-cal-chip:hover { filter: brightness(1.12); }
.wo-cal-chip-overdue { box-shadow: 0 0 0 1px var(--danger) inset; }
.wo-cal-more { font-size: 10.5px; font-weight: 700; color: var(--text-faint); cursor: pointer; padding: 1px 6px; }
.wo-cal-more:hover { color: var(--accent-text); text-decoration: underline; }

.wo-cal-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.wo-cal-legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.wo-cal-legend-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.wo-cal-legend-overdue-swatch { background: transparent; box-shadow: 0 0 0 2px var(--danger) inset; }

.wo-cal-day-list { display: flex; flex-direction: column; gap: 2px; max-height: 360px; overflow-y: auto; }
.wo-cal-day-item { display: flex; align-items: center; gap: 10px; padding: 9px 6px; border-bottom: 1px solid var(--row-border); cursor: pointer; border-radius: var(--radius-sm); }
.wo-cal-day-item:hover { background: var(--bg); }
.wo-cal-day-item:last-child { border-bottom: none; }
.wo-cal-chip-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.wo-cal-day-item-client { font-weight: 700; font-size: 13px; color: var(--text); }
.wo-cal-day-item-meta { font-size: 11.5px; color: var(--text-muted); }

@media (max-width: 860px) {
  .wo-cal-cell { min-height: 66px; padding: 4px; }
  .wo-cal-daynum { font-size: 11px; }
  .wo-cal-chip { font-size: 9.5px; padding: 1px 4px; }
  .wo-cal-month-label { min-width: 0; font-size: 14px; }
  .wo-cal-grid { gap: 3px; }
}

/* Pantalla de bienvenida (Home) al iniciar la app */
.home-welcome {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; height: 100%; min-height: calc(100dvh - 200px); gap: 6px;
}
.home-welcome-logo { width: 100%; max-width: 220px; height: auto; margin-bottom: 18px; }
.home-welcome-title { font-size: 24px; font-weight: 700; color: var(--text); }
.home-welcome-sub { font-size: 14px; color: var(--text-muted); }
.home-birthdays-card { width: 100%; max-width: 640px; margin-top: 14px; text-align: left; }

@media (max-width: 560px) {
  .upcoming-date-row { flex-wrap: wrap; row-gap: 2px; }
  .upcoming-date-detail { flex: 1 1 100%; order: 3; }
}

/* Menu de filtros de Ordenes de Trabajo: se queda fijo al hacer scroll,
   en las 4 vistas (Kanban, Lista, Tabla, Calendario). El offset coincide con
   el espacio reservado arriba de .main para no taparse con la campana/chip
   de usuario. */
#wo-filters-card { position: sticky; top: var(--content-top-offset); z-index: 15; margin-bottom: 14px; }
#wo-table-view-scroll { max-height: 960px; }
/* Sin esto, filtrar a pocos (o cero) resultados en Tabla/Calendario podía
   encoger tanto la página que el navegador recorta el scroll automático a
   la nueva altura máxima — un salto brusco hacia arriba que hacía sentir
   que el menú "fijo" de arriba en realidad se movía con la página. */
#wo-results { min-height: 100vh; }
/* Mismo criterio en Productos: la barra de búsqueda se queda fija arriba en
   ambas vistas (Tabla y Grid). */
#products-filter-card { position: sticky; top: var(--content-top-offset); z-index: 15; margin-bottom: 14px; }
#products-grid-wrap { min-height: 60vh; }

/* Vista Grid de Productos — una sección colapsable por categoría; la foto
   se ve directo en la tarjeta (sin clic), a diferencia del modal de foto de
   Empleados/Usuarios que si exige un clic. */
.product-grid-sections { display: flex; flex-direction: column; gap: 4px; }
.product-grid-section + .product-grid-section { border-top: 1px solid var(--border); padding-top: 10px; margin-top: 6px; }
.product-grid-section-head {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 4px; color: var(--text);
}
.product-grid-section-toggle {
  display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
  background: none; border: none; cursor: pointer; text-align: left; color: inherit; padding: 0;
}
.product-grid-section-chevron { transition: transform .15s ease; font-size: 11px; color: var(--text-faint); }
.product-grid-section-chevron.collapsed { transform: rotate(-90deg); }
.product-grid-section-title { font-weight: 700; font-size: 14px; }
.product-grid-section-count {
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 1px 8px; font-size: 11.5px; color: var(--text-muted); margin-left: 2px;
}
.product-grid-section-body:not([hidden]) {
  display: grid; gap: 14px; padding: 10px 4px 4px;
  /* Máximo 8 tarjetas por fila: el mínimo de cada columna es lo que
     necesitarían 8 columnas iguales, así auto-fill nunca mete una 9na,
     pero sigue bajando a menos columnas (más anchas) en pantallas
     angostas — nunca menos de 130px de ancho por tarjeta. */
  grid-template-columns: repeat(auto-fill, minmax(max(130px, calc((100% - 7 * 14px) / 8)), 1fr));
}
.product-grid-card {
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
  cursor: pointer; background: var(--surface); transition: box-shadow .15s ease, border-color .15s ease;
}
.product-grid-card:hover { box-shadow: var(--shadow); border-color: var(--main); }
.product-grid-photo {
  width: 100%; aspect-ratio: 1 / 1; background: var(--bg); display: flex; align-items: center;
  justify-content: center; overflow: hidden;
}
.product-grid-photo img { width: 100%; height: 100%; object-fit: cover; }
.product-grid-photo-placeholder { font-size: 26px; color: var(--text-faint); }
.product-grid-body { padding: 8px 10px 10px; }
.product-grid-name { font-weight: 700; font-size: 13px; line-height: 1.3; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.product-grid-code { font-size: 11px; color: var(--text-faint); margin-bottom: 4px; }
.product-grid-meta { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-muted); margin-bottom: 2px; }
.product-grid-location { font-size: 11.5px; color: var(--text-faint); }

/* Barra de filtros de Órdenes — una sola fila compacta en las 4 vistas.
   Cliente/Grupo/Usuario/Estatus/Mes viven en un popover aparte (no en la
   fila) para que la altura de la barra nunca dependa de cuántos campos
   aplican a cada vista — así las 4 vistas miden exactamente lo mismo y la
   fila nunca necesita más de una línea salvo en pantallas muy angostas. */
.wo-filters-card { padding: 10px 14px; }
.wo-filters-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.wo-filters-search { flex: 1 1 110px; max-width: 480px; }
.wo-filters-search input { width: 100%; height: 33px; }
.wo-filters-popover-wrap { position: relative; flex-shrink: 0; }
.wo-filters-toggle-btn { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.wo-filter-count-badge:not([hidden]) {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 999px;
  background: var(--main); color: #fff; font-size: 10.5px; font-weight: 700; line-height: 1;
}
.wo-filters-popover:not([hidden]) {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 14px; width: 260px;
  display: flex; flex-direction: column; gap: 10px;
}
.wo-filters-overdue { flex-shrink: 0; white-space: nowrap; height: 38px; }
.wo-filters-actions { flex-shrink: 0; flex-wrap: nowrap; }
@media (max-width: 480px) {
  /* Misma especificidad que ".wo-filters-popover:not([hidden])" de arriba
     (una clase + un pseudo-selector) — si no, esa regla base gana sin
     importar el orden ni el media query, y este ajuste nunca se aplica.
     `position: fixed` + posición relativa al viewport (no al botón que lo
     abre) porque el botón "Filtros" no siempre queda cerca del borde
     derecho — anclarlo con `right: 0` a SU PROPIO contenedor lo mandaba
     fuera de la pantalla por la izquierda (mismo tipo de bug que el buscador
     global y las notificaciones, ver esas reglas más arriba). */
  .wo-filters-popover:not([hidden]) {
    /* `top` se fija por JS al abrirlo (ver wo-filters-toggle-btn en app.js)
       porque acá sí depende de dónde esté el botón en la pantalla en ese
       momento — pero izquierda/derecha quedan fijas al viewport siempre. */
    position: fixed; left: calc(12px + env(safe-area-inset-left));
    right: calc(12px + env(safe-area-inset-right)); width: auto; max-width: none;
  }
}

.kanban-scroll-mirror { overflow-x: auto; overflow-y: hidden; height: 16px; margin-bottom: 6px; }
.kanban-scroll-mirror-inner { height: 1px; }
/* Los títulos de columna viven en una fila APARTE (.kanban-header-row),
   hermana de .kanban-board en vez de estar dentro de cada .kanban-col — así
   se puede volver esta fila sticky RESPECTO A LA PÁGINA (igual que
   #wo-filters-card) sin pelear con .kanban-board, que necesita su propio
   overflow-x:auto para el scroll horizontal entre columnas y por lo tanto
   (aunque solo se declare overflow-x) siempre termina siendo el contenedor
   de referencia para cualquier `position: sticky` de SUS descendientes — si
   el título estuviera adentro, quedaría pegado al scroll del board en vez
   del de la página. El `top` de esta fila se fija por JS
   (positionKanbanHeaderRow) al alto real de #wo-filters-card, que puede
   cambiar (una o dos líneas según el ancho de pantalla), y su scroll
   horizontal se sincroniza con .kanban-board por JS. */
.kanban-header-row { position: sticky; z-index: 16; overflow: hidden; background: var(--bg); margin-bottom: 10px; }
.kanban-header-row-inner { display: flex; gap: 18px; width: max-content; }
.kanban-board { display: flex; gap: 18px; overflow-x: auto; padding: 2px 2px 16px; align-items: flex-start; }
/* La altura (no max-height) se fija por JS (resizeKanbanColumns) al espacio
   real que queda debajo de .kanban-header-row — TODAS las columnas quedan a
   esa misma altura exacta sin importar cuántas órdenes tenga cada una (un
   max-height dejaría a las columnas con pocas órdenes más cortas que las
   demás). Cada columna scrollea sus propias tarjetas por dentro
   (.kanban-col-body) en vez de crecer sin límite; así no hay que scrollear
   media pantalla para ver "Diseño" solo porque "Cotización" tiene 28
   órdenes, y el resaltado de "drag-over" (ver abajo) cubre el mismo área en
   cualquier columna, tenga 2 órdenes o 28. */
.kanban-col { flex: 0 0 310px; background: var(--bg); border-radius: var(--radius); display: flex; flex-direction: column; }
.kanban-col-head {
  flex: 0 0 310px; display: flex; align-items: center; justify-content: space-between; padding: 14px 14px 10px;
  background: var(--bg); border-radius: var(--radius); border-top: 4px solid var(--accent, var(--text-faint));
}
.kanban-col-title { font-size: 14.5px; font-weight: 800; letter-spacing: -.01em; color: var(--accent, var(--text)); }
.kanban-col-count {
  font-size: 11px; color: var(--text-muted); font-weight: 700; background: var(--surface);
  border-radius: 999px; padding: 2px 8px; flex-shrink: 0;
}
.kanban-col-body {
  padding: 10px 12px 12px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 10px;
  min-height: 90px; transition: background .12s ease; border-radius: var(--radius-sm);
}
.kanban-col-body.drag-over {
  background: var(--secondary-light);
  outline: 2px dashed var(--secondary);
  outline-offset: -4px;
}
.kanban-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 13px 14px; cursor: grab; box-shadow: var(--shadow);
}
.kanban-card.wo-card-overdue {
  border-color: var(--danger-border); background: var(--danger-bg); border-left: 4px solid var(--danger);
  box-shadow: 0 1px 2px rgba(194,58,58,.1), 0 5px 16px rgba(194,58,58,.12);
}
.kanban-card.wo-card-overdue .kanban-card-code { color: var(--danger); font-weight: 800; }
.kanban-card:active { cursor: grabbing; }
.kanban-card.dragging { opacity: .4; }
.kanban-card-code { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); font-weight: 700; margin-bottom: 4px; }
/* Ícono de "grupo de OT" — mismo botón redondo en Kanban, Cuadrícula, Tabla
   y el modal de detalle de una orden; abre el visor del grupo (ver
   openWorkOrderGroupModal). Ícono de capas apiladas en vez de un efecto de
   sombra "apilada" sobre la tarjeta misma — ese efecto choca con el
   box-shadow que .kanban-card ya usa para overdue/drag, y un ícono claro es
   más confiable entre vistas que un truco de CSS por tarjeta. */
.wo-group-badge {
  display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
  width: 18px; height: 18px; margin-left: 6px; padding: 0; border-radius: 50%; flex-shrink: 0;
  background: var(--secondary-light); color: var(--secondary); border: none; cursor: pointer;
}
.wo-group-badge:hover { background: var(--secondary); color: #fff; }
.wo-group-badge svg { width: 11px; height: 11px; }
.wo-group-selection-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 12px; background: var(--secondary-light);
  border-radius: var(--radius-sm); font-size: 13px; font-weight: 600;
}
/* "Stack" de tarjetas — cuando 2+ órdenes del mismo grupo caen en la misma
   columna del Kanban o en la Cuadrícula, se colapsan (ver collapseWoGroups
   en app.js) en una sola tarjeta con este efecto de cartas apiladas y un
   contador arriba a la derecha que reemplaza el ícono normal de grupo. Clic
   en cualquier parte de la tarjeta abre el grupo completo.
   El asomo es un pedacito angosto del BORDE inferior de cada tarjeta "de
   atrás" (alto fijo de unos 6px, no toda la tarjeta duplicada) — mucho más
   liviano y prolijo que un fantasma de la tarjeta completa, y cada capa
   siguiente se angosta un poco más para dar sensación de perspectiva/
   abanico. Sale solo hacia abajo, nunca a los lados, y con tan pocos px le
   sobra espacio dentro del gap normal entre tarjetas — el tamaño de la
   tarjeta y la separación entre fichas quedan intactos. */
.wo-stack-card { position: relative; z-index: 0; cursor: pointer; }
.wo-stack-card::before, .wo-stack-card::after {
  content: ""; position: absolute; bottom: -5px; height: 6px;
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--bg);
}
.wo-stack-card::before { left: 8px; right: 8px; z-index: -1; }
.wo-stack-card::after { left: 15px; right: 15px; bottom: -9px; opacity: .7; z-index: -2; }
.wo-stack-count {
  position: absolute; top: -8px; right: -8px; z-index: 2;
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
  min-width: 24px; height: 22px; padding: 0 7px; border-radius: 11px;
  background: var(--secondary); color: #fff; font-size: 11px; font-weight: 800;
  border: 2px solid var(--surface); box-shadow: 0 1px 3px rgba(0,0,0,.18); cursor: pointer;
}
.wo-stack-count:hover { filter: brightness(1.12); }

/* Fila "padre" desplegable de un grupo en vista Tabla/Panel de OT — ver
   woTableGroupRowHTML/otpTableGroupRowHTML en app.js. */
.wo-group-row { cursor: pointer; background: var(--secondary-light); font-weight: 700; }
.wo-group-row:hover { background: var(--secondary-light); filter: brightness(0.97); }
.wo-group-row-chevron {
  display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
  width: 18px; height: 18px; margin-right: 4px; padding: 0; border: none; background: none;
  color: var(--secondary); cursor: pointer; transition: transform .15s ease;
}
.wo-group-row-chevron svg { width: 14px; height: 14px; }
.wo-group-row-chevron.expanded { transform: rotate(90deg); }
.wo-table-child-row td:first-child { padding-left: 32px; }
.wo-table-child-row { background: var(--bg); }
.kanban-card-title { font-weight: 700; font-size: 13.5px; margin-bottom: 4px; }
.kanban-card-desc {
  font-size: 12.5px; color: var(--text-muted); margin-bottom: 8px; line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.kanban-card-due { font-size: 11.5px; color: var(--text-faint); margin-bottom: 8px; }
.kanban-card-due.overdue-text { color: var(--danger); font-weight: 800; }
.kanban-empty { text-align: center; color: var(--text-faint); font-size: 11.5px; padding: 20px 8px; }
.wo-card .assignee-list { margin-top: auto; padding-top: 8px; }
.wo-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.wo-code { font-family: var(--mono); font-size: 12px; color: var(--text-faint); font-weight: 700; }
.wo-desc { color: var(--text-muted); font-size: 13px; margin: 6px 0 10px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.wo-meta { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--text-faint); margin-bottom: 10px; }
.wo-meta strong { color: var(--text-muted); font-weight: 600; }

.assignee-list { display: flex; flex-wrap: wrap; gap: 6px; }
.wo-readonly {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 9px 11px; font-size: 13.5px; color: var(--text); white-space: pre-wrap;
}
.wo-modal-title { font-size: 21px; font-weight: 800; color: var(--accent-text); }
.textarea-autosize { resize: none; overflow: hidden; }

.product-photo-large {
  width: 100%; height: 260px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg); border: 1px solid var(--border); cursor: zoom-in;
  display: flex; align-items: center; justify-content: center;
}
.product-photo-large img { width: 100%; height: 100%; object-fit: contain; display: block; }
.product-photo-large.empty { cursor: default; color: var(--text-faint); font-size: 13px; }
.wo-photo-grid {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px;
  margin-bottom: 8px;
}
/* 8 columnas en un modal de 1320px dan miniaturas de sobra, pero en celular
   (modal angosto de ~290px de contenido) quedan de ~30px — ilegibles. */
@media (max-width: 520px) {
  .wo-photo-grid { grid-template-columns: repeat(4, 1fr); }
}
.wo-photo-thumb {
  position: relative; aspect-ratio: 1; border-radius: var(--radius-sm);
  overflow: hidden; cursor: zoom-in; background: var(--bg); border: 1px solid var(--border);
}
.wo-photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wo-photo-delete {
  position: absolute; top: 4px; right: 4px; width: 22px; height: 22px;
  border-radius: 50%; border: none; background: rgba(0, 0, 0, .6); color: #fff;
  font-size: 15px; line-height: 1; cursor: pointer;
}
.wo-photo-delete:hover { background: var(--danger); }
.wo-photo-thumb[draggable="true"] { cursor: grab; }
.wo-photo-thumb.dragging { opacity: .4; }
.wo-photo-thumb.drag-over { outline: 2px dashed var(--secondary); outline-offset: 2px; }

.wo-lightbox-overlay { z-index: 1000; }
.wo-lightbox-inner { position: relative; max-width: 90vw; max-height: 90vh; }
.wo-lightbox-img { max-width: 90vw; max-height: 90vh; display: block; border-radius: var(--radius-sm); }
.wo-lightbox-close {
  position: absolute; top: -14px; right: -14px; width: 32px; height: 32px;
  border-radius: 50%; background: #fff; color: #16233a; border: none;
  font-size: 20px; line-height: 1; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, .3);
}

.wo-items-table-wrap { margin-bottom: 8px; }
.wo-items-table { width: 100%; min-width: 1220px; border-collapse: collapse; }
.wo-items-table thead th {
  background: var(--main); color: #fff; font-size: 11.5px; font-weight: 700;
  text-align: left; padding: 8px 8px; white-space: nowrap;
}
.wo-items-table tbody td { padding: 5px 6px; border-bottom: 1px solid var(--border); font-size: 13px; vertical-align: middle; }
.wo-items-table tbody tr:last-child td { border-bottom: none; }
.wo-items-table input[type=text], .wo-items-table input[type=number] { padding: 6px 8px; font-size: 13px; }
.wo-items-table select.wo-item-input { padding: 6px 6px; font-size: 13px; }

.wo-totals-row-wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; margin-top: 10px; flex-wrap: wrap;
}
.wo-totals-side { flex: 1 1 300px; min-width: 0; }
.wo-totals-side .emp-detail-grid { margin: 0; }
.wo-status-cols { align-items: start; }
/* Un <select> normal nunca ensancha su columna del grid porque el texto de
   la opción elegida no cuenta para su ancho mínimo — pero un botón con texto
   normal (como el toggle del dropdown de Servicios externos) sí, aunque
   tenga overflow:hidden + text-overflow:ellipsis: en un grid, el ancho
   mínimo de una columna se calcula por el contenido de sus descendientes, y
   ese min-width:auto por defecto ignora el overflow de un hijo que no sea
   directamente el item del grid. Este min-width:0 en el item mismo (los dos
   <div> de esta fila) es lo que de verdad deja que la columna se achique y
   el ellipsis del botón funcione, en vez de estirar la fila entera cuando
   hay varios servicios externos seleccionados. */
.wo-status-cols > div { min-width: 0; }
.wo-totals-box {
  margin: 4px 0; width: 260px; max-width: 100%; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden;
}
.wo-totals-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 7px 14px; font-size: 13px; color: var(--text-muted); background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.wo-totals-row-total {
  background: var(--main); color: #fff; font-weight: 800; font-size: 15px;
  padding: 11px 14px; border-bottom: none;
}

.assignee-table-wrap { margin-bottom: 8px; }
.assignee-table-wrap table { width: 100%; }
.assignee-table-wrap td { padding: 7px 8px; border-bottom: 1px solid var(--border); }
.assignee-table-wrap tr:last-child td { border-bottom: none; }
.assignee-table-av { width: 30px; }
.assignee-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 3px 10px 3px 3px; font-size: 12px; font-weight: 600; color: var(--text);
}
.assignee-chip .av {
  width: 20px; height: 20px; border-radius: 50%; background: var(--main);
  color: #fff; font-size: 9.5px; font-weight: 800; display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.assignee-chip button {
  background: none; border: none; color: var(--text-faint); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 0 0 0 2px;
}
.assignee-chip button:hover { color: var(--danger); }
.assignee-chip-inactive { opacity: .55; }
.assignee-chip-inactive em, span.assignee-chip-inactive em { font-style: normal; color: var(--danger); font-weight: 700; }
.assignee-picker { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.assignee-option {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer; user-select: none;
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px 5px 5px; font-size: 12.5px; font-weight: 600;
  transition: border-color .12s ease, background .12s ease;
}
.assignee-option input { margin: 0; }
.assignee-option.checked { border-color: var(--secondary); background: var(--secondary-light); }
.assignee-option .av {
  width: 20px; height: 20px; border-radius: 50%; background: var(--main);
  color: #fff; font-size: 9.5px; font-weight: 800; display: flex; align-items: center; justify-content: center;
}

.inline-toggle-link {
  background: none; border: none; padding: 0; margin-top: 4px;
  color: var(--accent-text); font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.inline-toggle-link:hover { text-decoration: underline; }
.inline-client-box {
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
  padding: 12px; margin-top: 8px; background: var(--bg);
}
.inline-client-box .field { margin-bottom: 10px; }
.inline-client-box .field:last-child { margin-bottom: 0; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 640px) { .field-row { grid-template-columns: 1fr; } }
.field-row-wide { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.file-input-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.filter-checkbox {
  display: flex; align-items: center; gap: 8px; height: 38px;
  font-size: 13px; color: var(--text); cursor: pointer; white-space: nowrap;
}
.filter-checkbox input { width: 16px; height: 16px; cursor: pointer; margin: 0; }
.checkbox-list { display: flex; flex-wrap: wrap; gap: 4px 18px; border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 12px; }

/* Dropdown genérico de selección múltiple: cerrado se ve y se comporta como
   un <select> normal (mismo borde, flechita, texto truncado), y al hacer
   clic despliega un panel con checkboxes en vez de abrir el <select> nativo
   del navegador (que no soporta multi-selección con checkboxes). */
.ms-dropdown { position: relative; }
.ms-dropdown-toggle {
  width: 100%; padding: 9px 32px 9px 11px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--input-bg); color: var(--text); font-size: 13.5px; text-align: left; cursor: pointer;
  font-family: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2362728a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 14px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.ms-dropdown-toggle.placeholder { color: var(--text-faint); }
.ms-dropdown-toggle:focus { outline: none; border-color: var(--secondary); box-shadow: 0 0 0 3px var(--secondary-light); }
.ms-dropdown-panel:not([hidden]) {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 6px; max-height: 220px; overflow-y: auto;
}
.ms-dropdown-item {
  display: flex; align-items: center; gap: 8px; padding: 8px; border-radius: var(--radius-sm);
  font-size: 13px; cursor: pointer;
}
.ms-dropdown-item:hover { background: var(--bg); }
.ms-dropdown-item input { width: 16px; height: 16px; cursor: pointer; margin: 0; flex-shrink: 0; }
.checkbox-list .filter-checkbox { height: auto; }

/* Selector de fecha estilo calendario */
.date-field { position: relative; }
.date-input-btn {
  width: 100%; text-align: left; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 9px 11px; font-size: 13.5px; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 8px; color: var(--text);
}
.date-input-btn:hover { border-color: var(--secondary); }
.date-input-btn .placeholder { color: var(--text-faint); }
.date-input-btn span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.date-input-btn .cal-icon { color: var(--text-faint); flex-shrink: 0; }
.date-popover-backdrop {
  position: fixed; inset: 0; z-index: 1005;
  background: rgba(10, 20, 38, .35);
  display: flex; align-items: center; justify-content: center;
}
.date-popover {
  position: relative; z-index: 1006;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 24px 56px rgba(8, 16, 32, .32); padding: 14px; width: 280px;
}
.date-popover-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.date-popover-head .label { font-weight: 700; font-size: 13px; text-transform: capitalize; display: flex; align-items: center; gap: 4px; }
.date-year-select {
  width: auto; padding: 2px 18px 2px 6px; font-size: 13px; font-weight: 700; border-radius: 4px;
  background-position: right 2px center; background-size: 12px; cursor: pointer;
}
.date-nav-btn {
  background: none; border: none; cursor: pointer; color: var(--text-muted);
  width: 26px; height: 26px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center;
}
.date-nav-btn:hover { background: var(--bg); color: var(--text); }
.date-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.date-dow { text-align: center; font-size: 10px; font-weight: 700; color: var(--text-faint); padding: 4px 0; }
.date-day {
  text-align: center; font-size: 12.5px; padding: 6px 0; border-radius: var(--radius-sm);
  cursor: pointer; background: none; border: none; color: var(--text);
}
.date-day:hover { background: var(--secondary-light); }
.date-day.other-month { color: var(--text-faint); }
.date-day.disabled, .date-day:disabled { color: #ccd4e0; cursor: not-allowed; }
.date-day.disabled:hover, .date-day:disabled:hover { background: none; }
.date-day.today { font-weight: 800; color: var(--accent-text); }
.date-day.selected { background: var(--main); color: #fff; font-weight: 700; }
.date-popover-foot { display: flex; justify-content: space-between; margin-top: 8px; }
.date-popover-foot button {
  background: none; border: none; color: var(--secondary); font-size: 12px; font-weight: 700; cursor: pointer; padding: 4px;
}
.month-popover { width: 210px; }
.month-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.month-cell {
  padding: 9px 4px; border-radius: var(--radius-sm); cursor: pointer; background: none; border: none;
  font-size: 12.5px; color: var(--text); text-transform: capitalize;
}
.month-cell:hover { background: var(--secondary-light); }
.month-cell.selected { background: var(--main); color: #fff; font-weight: 700; }
#wo-month-filter-wrap .inline-toggle-link { margin-top: 6px; }

/* ------------------------------------------------------------------ */
/* Barra de selección masiva (Productos)                               */
/* ------------------------------------------------------------------ */
.bulk-bar {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 10px; background: var(--secondary-light); border: 1px solid var(--secondary);
  border-radius: var(--radius-sm); padding: 10px 14px; margin-bottom: 14px;
  font-size: 13.5px; font-weight: 600; color: var(--accent-text);
}

/* ------------------------------------------------------------------ */
/* Pagination (Panel table)                                            */
/* ------------------------------------------------------------------ */
.pagination {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: 10px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
}
.pagination-top {
  margin-top: 0; padding-top: 0; border-top: none;
  margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--border);
}
.pagination-size { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-muted); }
.pagination-size select { width: auto; padding: 5px 8px; }
.pagination-nav { display: flex; align-items: center; gap: 10px; }
.pagination-info { font-size: 12.5px; color: var(--text-muted); font-weight: 600; }

/* ------------------------------------------------------------------ */
/* Pie charts (Panel)                                                   */
/* ------------------------------------------------------------------ */
.pie-wrap { display: flex; align-items: flex-start; gap: 20px; flex-wrap: nowrap; min-height: 230px; overflow: hidden; }
.pie-svg-wrap { flex: 0 0 auto; width: 190px; }
.pie-svg { width: 100%; height: auto; display: block; overflow: visible; }
.pie-slice { transition: filter .12s ease, transform .12s ease; transform-box: fill-box; }
.pie-slice.pie-slice-active { filter: brightness(1.14); }
.pie-slice-hit { cursor: pointer; }
.pie-center-value { font-weight: 800; fill: var(--accent-text); font-family: var(--font); }
.pie-center-label { font-size: 7.5px; font-weight: 700; fill: var(--text-muted); text-transform: uppercase; letter-spacing: .02em; font-family: var(--font); }
.pie-legend { flex: 1 1 170px; min-width: 150px; max-height: 230px; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; padding-right: 4px; }
.pie-legend-item { display: flex; align-items: center; gap: 9px; font-size: 12.5px; padding: 6px 7px; border-radius: 6px; }
.pie-legend-item:hover { background: var(--bg); }
.pie-swatch { width: 11px; height: 11px; border-radius: 3px; flex-shrink: 0; box-shadow: 0 0 0 1px var(--pie-swatch-ring); }
.pie-legend-label { flex: 1; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pie-legend-value { flex: 0 0 auto; min-width: 64px; text-align: right; color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 700px) {
  .pie-wrap { min-height: 0; flex-wrap: wrap; }
  .pie-legend { max-height: 260px; }
}

/* Comparación año contra año (tabla con mini-barras) */
.yoy-bar-row { position: relative; display: flex; align-items: center; min-width: 130px; height: 20px; }
.yoy-bar { position: absolute; left: 0; top: 0; height: 100%; border-radius: 3px; opacity: .28; z-index: 0; }
.yoy-bar-0 { background: var(--accent-text); }
.yoy-bar-1 { background: var(--success); }
.yoy-bar-2 { background: var(--warn-text); }
.yoy-bar-3 { background: var(--danger); }
.yoy-bar-4 { background: var(--badge-purple-text); }
.yoy-bar-row span { position: relative; z-index: 1; padding-left: 6px; font-variant-numeric: tabular-nums; }
.yoy-legend-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 4px; opacity: .7; }
.yoy-up { color: var(--success); font-weight: 700; }
.yoy-down { color: var(--danger); font-weight: 700; }
.yoy-year-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.yoy-year-chip {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer; user-select: none;
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px; font-size: 12.5px; font-weight: 600;
  transition: border-color .12s ease, background .12s ease;
}
.yoy-year-chip input { margin: 0; }
.yoy-year-chip.checked { border-color: var(--secondary); background: var(--secondary-light); }

.bar-chart-scroll { overflow-x: auto; padding-bottom: 4px; }
.bar-rect { transition: opacity .12s ease; }
.bar-rect:hover { opacity: .8; }
.bar-x-label { font-size: 10px; fill: var(--text-muted); }
.bar-value-label { font-size: 10px; fill: var(--text); font-weight: 600; opacity: 0; transition: opacity .12s ease; pointer-events: none; }
.bar-group:hover .bar-value-label { opacity: 1; }
.line-point { transition: r .12s ease; }
.line-point-group:hover .line-point { r: 5.5; }
.line-point-group:hover .bar-value-label { opacity: 1; }

/* ------------------------------------------------------------------ */
/* Print stage — fuera de pantalla (no display:none) para que el layout
   de las etiquetas se calcule siempre, incluso sin estar imprimiendo.
   Así el JS puede medir el texto (para achicar la categoría si no cabe
   en una línea) antes de llamar a window.print(). Al imprimir, @media
   print solo lo reposiciona a la página visible.                      */
/* ------------------------------------------------------------------ */
.print-stage {
  position: absolute;
  left: -9999px;
  top: 0;
  width: 7.8in; /* igual al área imprimible real: 8.5in de hoja menos 0.35in de margen en cada lado */
}

/* Etiquetas de producto: hoja carta normal (8.5in x 11in), 12 etiquetas por
   página en una cuadrícula de 3 columnas x 4 filas — se llenan fila por
   fila (toda la fila 1 de izquierda a derecha, luego la 2, etc.), sin
   importar si se imprimen menos o más de 12 en total.

   Importante: esta @page NO lleva nombre (ni "page:" en .label-page) a
   propósito — asignarle un nombre fuerza un salto de página en el navegador
   apenas cambia de una página sin nombre a una con nombre, lo que dejaba
   una primera hoja en blanco antes de las etiquetas. */
@page {
  size: 8.5in 11in;
  margin: 0.35in;
}

.label-sheet { display: block; }
.label-page {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(4, 1fr);
  grid-auto-flow: row;
  width: 7.8in;
  height: 10.3in;
}
.label {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.label-body {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding: 0.12in 0.16in 0.08in;
  gap: 14px;
  min-height: 0;
}
.label .label-title {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  max-width: 100%;
  word-break: break-word;
}
.label svg { max-width: 2.3in; width: 100%; height: auto; }
.label-footer {
  flex-shrink: 0;
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--main);
  color: #fff;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
  color-adjust: exact;
  font-weight: 700;
  font-size: 16px;
  padding: 0 10px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
}

@media print {
  .app-shell { display: none !important; }
  .toast-stack, .toast-stack-top { display: none !important; }
  .print-stage {
    position: static;
    left: auto;
    width: 100%;
  }
  .label-page {
    page-break-after: always;
    break-after: page;
  }
  .label-page:last-child { page-break-after: auto; break-after: auto; }
}

/* Confeti discreto al cerrar una Orden de Trabajo — ver celebrateOrderClosed()
   en app.js. Piezas fijas (no afectan el layout), se autodestruyen solas. */
.confetti-piece {
  position: fixed; width: 8px; height: 12px; z-index: 1400; pointer-events: none;
  opacity: .95; animation: confetti-fall 1s ease-in forwards;
}
@keyframes confetti-fall {
  to { transform: translateY(130px) rotate(var(--rot)); opacity: 0; }
}
