@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600;700&display=swap');

/* ============================================================
   TOKENS — modo claro (por defecto) y modo oscuro ([data-theme="dark"])
   Paleta: tinta cálida + bronce envejecido. Nada de azul-violeta
   genérico de plantilla — la idea es que se sienta hecho a medida.
   ============================================================ */
:root {
  --bg: #f4f1ea;
  --bg-elevated: #fffdf9;
  --panel: #fffdf9;
  --panel-2: #ece6d8;
  --ink: #1c1912;
  --ink-soft: #746b58;
  --line: #e4dcc9;

  --brand-a: #a9812f;   /* bronce */
  --brand-b: #7c5e22;   /* bronce oscuro, para la sombra del degradé */
  --brand-grad: linear-gradient(160deg, var(--brand-a), var(--brand-b));
  --brand-solid: #8f6a26;
  --brand-soft: #f1e6c9;
  --brand-glow: rgba(169, 129, 47, 0.22);

  --ok: #3d6b4a;
  --ok-bg: #e7f0e5;
  --warn: #9c6b1f;
  --warn-bg: #f5ecd8;
  --danger: #96403a;
  --danger-bg: #f3e2df;
  --muted: #746b58;
  --muted-bg: #ece6d8;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow-card: 0 1px 2px rgba(28, 25, 18, 0.04), 0 10px 28px -14px rgba(28, 25, 18, 0.16);
  --shadow-glow: 0 10px 26px -10px var(--brand-glow);

  --sidebar-w: 252px;

  font-family: "Inter", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

[data-theme="dark"] {
  --bg: #0f0e0b;
  --bg-elevated: #17150f;
  --panel: #1a1812;
  --panel-2: #221f17;
  --ink: #f3efe4;
  --ink-soft: #a49a83;
  --line: #2c281e;

  --brand-a: #d9ab55;
  --brand-b: #a9812f;
  --brand-grad: linear-gradient(160deg, var(--brand-a), var(--brand-b));
  --brand-solid: #dcb26a;
  --brand-soft: rgba(217, 171, 85, 0.14);
  --brand-glow: rgba(217, 171, 85, 0.32);

  --ok: #7bb989;
  --ok-bg: rgba(123, 185, 137, 0.12);
  --warn: #dcaa55;
  --warn-bg: rgba(220, 170, 85, 0.12);
  --danger: #d98a83;
  --danger-bg: rgba(217, 138, 131, 0.12);
  --muted: #a49a83;
  --muted-bg: rgba(164, 154, 131, 0.12);

  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.35), 0 12px 30px -14px rgba(0, 0, 0, 0.6);
  --shadow-glow: 0 0 0 1px rgba(217, 171, 85, 0.14), 0 10px 26px -8px var(--brand-glow);
}

* { box-sizing: border-box; }

html { color-scheme: light; }
html[data-theme="dark"] { color-scheme: dark; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  transition: background-color 0.2s ease, color 0.2s ease;
}

h1, h2, h3, .brand-text .company, .login-card h1 {
  font-family: "Space Grotesk", "Inter", sans-serif;
  letter-spacing: -0.01em;
}

/* Ícono propio (SVG inline), reemplaza los emojis en toda la interfaz */
.icon { display: inline-block; vertical-align: -3px; flex-shrink: 0; }

/* Números: saldo, montos, fechas, stats -> monoespaciada (identidad del panel) */
.num, .mono, td.mono, .stat .num, .precio, .badge {
  font-family: "JetBrains Mono", "Inter", monospace;
  font-feature-settings: "tnum";
}

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--brand-b);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ============================================================
   SHELL: sidebar + topbar + main
   ============================================================ */
.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--panel);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  z-index: 50;
  transition: transform 0.25s ease;
}

.sidebar-top {
  padding: 22px 18px 16px 18px;
  position: relative;
}
.sidebar-top::after {
  content: "";
  position: absolute; left: 18px; right: 18px; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--line) 0%, var(--brand-a) 50%, var(--line) 100%);
  opacity: 0.55;
}

.sidebar-nav {
  padding: 18px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  position: relative;
}

/* Indicador deslizante: una sola pieza que se desliza y cambia de alto
   detrás del tab activo (posicionada por sidebar-fx.js), en vez de
   simplemente aparecer/desaparecer en cada uno. Es lo que le da esa
   sensación de "panel de mando" en lugar de una lista de botones. */
.tab-indicator {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 0;
  border-radius: var(--radius-sm);
  background: linear-gradient(120deg, var(--brand-soft), transparent 75%);
  box-shadow: inset 0 0 0 1px var(--brand-a);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.38s cubic-bezier(.22,.85,.32,1), height 0.28s cubic-bezier(.22,.85,.32,1), opacity 0.2s ease;
  z-index: 0;
  will-change: transform;
}
[data-theme="dark"] .tab-indicator { background: linear-gradient(120deg, rgba(217, 171, 85, 0.12), transparent 75%); }

.sidebar-nav .tab {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--ink-soft);
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.005em;
  position: relative;
  z-index: 1;
  overflow: hidden;
  transition: color 0.18s ease, transform 0.08s ease, letter-spacing 0.22s ease;
  opacity: 0;
  animation: nav-item-in 0.5s cubic-bezier(.2,.7,.3,1) both;
}
.sidebar-nav .tab:nth-child(1) { animation-delay: .04s; }
.sidebar-nav .tab:nth-child(2) { animation-delay: .08s; }
.sidebar-nav .tab:nth-child(3) { animation-delay: .12s; }
.sidebar-nav .tab:nth-child(4) { animation-delay: .16s; }
.sidebar-nav .tab:nth-child(5) { animation-delay: .20s; }
.sidebar-nav .tab:nth-child(6) { animation-delay: .24s; }
.sidebar-nav .tab:nth-child(7) { animation-delay: .28s; }
.sidebar-nav .tab:nth-child(8) { animation-delay: .32s; }
.sidebar-nav .tab:nth-child(9) { animation-delay: .36s; }
.sidebar-nav .tab:nth-child(10) { animation-delay: .40s; }
.sidebar-nav .tab:nth-child(11) { animation-delay: .44s; }
.sidebar-nav .tab:nth-child(12) { animation-delay: .48s; }

.sidebar-nav .tab.active { letter-spacing: 0.015em; }

/* Ondas de tinta al tocar un tab (ripple), inyectadas por sidebar-fx.js */
.tab-ripple {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, var(--brand-a) 0%, transparent 70%);
  opacity: 0.28;
  transform: scale(0);
  pointer-events: none;
  animation: tab-ripple-out 0.55s ease-out forwards;
}
@keyframes tab-ripple-out {
  to { transform: scale(1); opacity: 0; }
}

/* Pequeño "pop" del ícono cuando su tab pasa a estar activo */
.sidebar-nav .tab .ico.ico-pop { animation: ico-pop 0.42s cubic-bezier(.34,1.56,.64,1); }
@keyframes ico-pop {
  0% { transform: scale(1) rotate(0deg); }
  45% { transform: scale(1.22) rotate(-8deg); }
  100% { transform: scale(1) rotate(0deg); }
}
/* Trazo tipo "tinta" que crece desde arriba al pasar el mouse o al
   activarse — un solo gesto de movimiento, no un fondo que aparece de
   golpe. */
.sidebar-nav .tab::before {
  content: "";
  position: absolute; left: 0; top: 4px; bottom: 4px; width: 2.5px;
  border-radius: 2px;
  background: var(--brand-grad);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.22s cubic-bezier(.3,.8,.4,1);
}
.sidebar-nav .tab:hover::before { transform: scaleY(0.55); }
.sidebar-nav .tab.active::before { transform: scaleY(1); }
.sidebar-nav .tab:active { transform: scale(0.98); }

/* El ícono activo lleva un "sello" circular bronce detrás — más
   parecido a un timbre de cuenta/valor que a una fila de menú
   genérica, coherente con que esto es una plataforma de créditos. */
.sidebar-nav .tab .ico {
  width: 30px; height: 30px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 100px;
  color: var(--ink-soft);
  transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}
.sidebar-nav .tab .ico .icon { vertical-align: 0; }
.sidebar-nav .tab:hover .ico { background: var(--panel-2); color: var(--ink); transform: translateY(-1px); }
.sidebar-nav .tab:hover { color: var(--ink); }
.sidebar-nav .tab.active {
  color: var(--ink);
  font-weight: 600;
}
.sidebar-nav .tab.active .ico {
  background: var(--brand-grad);
  color: #fffdf6;
  box-shadow: var(--shadow-glow);
}

.sidebar-bottom {
  padding: 16px 16px 18px 16px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.account-rail { display: flex; align-items: center; gap: 10px; padding: 2px 2px 4px; }
.account-avatar {
  width: 34px; height: 34px; border-radius: 100px; flex-shrink: 0;
  background: var(--brand-grad);
  color: #fffdf6;
  display: flex; align-items: center; justify-content: center;
  font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 13.5px;
  box-shadow: var(--shadow-glow);
}
.account-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.account-name { font-size: 13.5px; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.account-role { font-size: 11.5px; color: var(--ink-soft); }

.account-actions { display: flex; flex-direction: column; gap: 6px; }

.sidebar-scrim {
  display: none;
}

.main-area {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 26px;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--line);
  gap: 12px;
  position: sticky;
  top: 0;
  z-index: 30;
}

.topbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.topbar-right { display: flex; align-items: center; gap: 8px; }

.hamburger {
  display: none;
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: var(--radius-sm);
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
  font-size: 16px;
  flex-shrink: 0;
}

.topbar .who {
  color: var(--ink-soft);
  font-size: 13.5px;
}

.theme-toggle {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 100px;
  padding: 7px 13px;
  font-size: 13px;
  cursor: pointer;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.theme-toggle:hover { border-color: var(--brand-a); }

/* ============================================================
   BOTONES
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 9px 15px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  transition: border-color 0.15s ease, transform 0.1s ease, background-color 0.15s ease;
}
.btn:hover { border-color: var(--brand-a); }
.btn:active { transform: scale(0.98); }

.btn-primary {
  background: var(--brand-grad);
  border-color: transparent;
  color: #fff5e4;
  font-weight: 600;
  box-shadow: var(--shadow-glow);
}
.btn-primary:hover { box-shadow: 0 12px 30px -10px var(--brand-glow); transform: translateY(-1px); }

.btn-danger { color: var(--danger); border-color: var(--danger); background: transparent; }
.btn-danger:hover { background: var(--danger-bg); }
.btn-small { padding: 6px 11px; font-size: 12.5px; }

/* ============================================================
   LAYOUT DE CONTENIDO
   ============================================================ */
.container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 26px;
  width: 100%;
}

/* Tabs viejos ya no se muestran arriba (ahora viven en el sidebar);
   se ocultan si algún panel los sigue trayendo por compatibilidad. */
.tabs { display: none; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  margin-bottom: 18px;
  box-shadow: var(--shadow-card);
}

.card h2 {
  margin: 0 0 14px 0;
  font-size: 15.5px;
  color: var(--ink);
  font-weight: 600;
}

/* ============================================================
   STATS
   ============================================================ */
.grid-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 17px 18px;
  box-shadow: var(--shadow-card);
  position: relative;
  overflow: hidden;
}
.stat::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--brand-grad);
}
.stat .num { font-size: 24px; font-weight: 700; color: var(--ink); letter-spacing: -0.02em; }
.stat .label { font-size: 12.5px; color: var(--ink-soft); margin-top: 4px; font-family: "Inter", sans-serif; }

/* ============================================================
   TABLA
   ============================================================ */
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th {
  text-align: left;
  color: var(--ink-soft);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 9px 10px;
  border-bottom: 1px solid var(--line);
}
td { padding: 11px 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--panel-2); }

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 100px;
  font-size: 11.5px;
  font-weight: 600;
}
.badge-ok { color: var(--ok); background: var(--ok-bg); }
.badge-warn { color: var(--warn); background: var(--warn-bg); }
.badge-danger { color: var(--danger); background: var(--danger-bg); }
.badge-muted { color: var(--muted); background: var(--muted-bg); }
.badge-level { color: var(--brand-solid); background: var(--brand-soft); }

/* ============================================================
   FORMULARIOS
   ============================================================ */
.form-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 10px; }
.field { display: flex; flex-direction: column; gap: 5px; min-width: 160px; flex: 1; }
.field label { font-size: 12px; color: var(--ink-soft); font-weight: 500; }
.field input, .field select, .field textarea {
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
  background: var(--bg-elevated);
  color: var(--ink);
  font-family: inherit;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--brand-a);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.empty { color: var(--ink-soft); font-size: 13.5px; padding: 22px 0; text-align: center; }

/* ============================================================
   LOGIN
   ============================================================ */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(70% 55% at 15% 10%, var(--brand-soft), transparent),
    radial-gradient(60% 50% at 90% 90%, var(--brand-soft), transparent),
    var(--bg);
  padding: 20px;
  /* Rojo fijo (no depende del tema claro/oscuro) tomado de la paleta
     del póster de fondo — se usa para que los detalles dorados del
     login (borde, línea superior, esquinas) sigan el mismo ritmo de
     color que la imagen de atrás, en vez de quedar solo "dorado
     genérico" sobre un fondo que trae mucho rojo oscuro. */
  --cine-red: #9c2b26;
  --cine-red-2: #d6453b;

  /* Paleta del login en modo claro: SIN dorado — grafito casi negro en
     vez de bronce. Esto reemplaza acá (--brand-a/-b/-grad/-solid/-soft/
     -glow) lo que el resto del sistema todavía toma de los tokens
     globales de :root; como está scopeado a .login-wrap, no afecta
     admin/revendedor. Es un adelanto de la paleta sin dorado que vas a
     llevar a todo el sistema más adelante. */
  --brand-a: #2c2c30;
  --brand-b: #17171a;
  --brand-grad: linear-gradient(160deg, var(--brand-a), var(--brand-b));
  --brand-solid: #232326;
  --brand-soft: rgba(30, 30, 34, 0.07);
  --brand-glow: rgba(20, 20, 22, 0.22);
}
/* Modo oscuro del login: acá SÍ seguimos con dorado+rojo (va atado a
   los pósters del fondo) — se re-declaran los mismos valores que ya
   tenía el tema oscuro global, pero fijos acá para que no dependan de
   lo que termine siendo el dorado del resto del sistema. */
[data-theme="dark"] .login-wrap {
  --brand-a: #d9ab55;
  --brand-b: #a9812f;
  --brand-grad: linear-gradient(160deg, var(--brand-a), var(--brand-b));
  --brand-solid: #dcb26a;
  --brand-soft: rgba(217, 171, 85, 0.14);
  --brand-glow: rgba(217, 171, 85, 0.32);
}
.login-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0;
  width: 400px;
  max-width: 100%;
  box-shadow: var(--shadow-card);
  position: relative;
  overflow: hidden;
}
.login-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand-b), var(--brand-a) 35%, var(--cine-red-2) 68%, var(--cine-red) 100%);
  z-index: 2;
}
.login-card h1 { font-size: 20px; margin: 0 0 4px 0; color: var(--ink); font-weight: 700; }
.login-card p { color: var(--ink-soft); font-size: 13px; margin: 0 0 22px 0; }
.login-card .field { margin-bottom: 13px; }
.login-card .btn-primary { width: 100%; margin-top: 6px; }
.error-msg { color: var(--danger); font-size: 13px; margin-top: 10px; min-height: 16px; }

.login-form-panel {
  position: relative;
  width: 100%;
  padding: 40px 34px 34px;
}

.section-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-soft);
  margin: 26px 0 10px 0;
  font-weight: 600;
}

/* ============================================================
   MARCA DE LA EMPRESA
   ============================================================ */
.brand-wrap { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand-logo {
  height: 34px; width: 34px; border-radius: 8px; object-fit: cover;
  flex-shrink: 0; background: var(--brand-soft);
}
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-text .company {
  font-weight: 700; color: var(--ink); font-size: 14.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.brand-text .panel-name { font-size: 11px; color: var(--ink-soft); white-space: nowrap; }
.login-card .brand-wrap { justify-content: center; margin-bottom: 16px; }
.login-card .brand-logo { height: 48px; width: 48px; border-radius: 11px; }

/* ============================================================
   BOTONES DE ACCIÓN (whatsapp / llamada / pdf)
   ============================================================ */
.action-icons { display: flex; gap: 6px; flex-wrap: wrap; }
.icon-btn {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid var(--line); background: var(--bg-elevated);
  padding: 6px 10px; border-radius: var(--radius-sm);
  font-size: 12px; cursor: pointer; text-decoration: none;
  color: var(--ink); white-space: nowrap;
}
.icon-btn:hover { border-color: var(--brand-a); }
.icon-btn .icon, .btn-small .icon { width: 14px; height: 14px; vertical-align: -2.5px; }
.icon-btn.whatsapp { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, var(--line)); }
.icon-btn.call { color: var(--brand-b); border-color: color-mix(in srgb, var(--brand-b) 35%, var(--line)); }
.icon-btn.pdf { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, var(--line)); }
.icon-btn.disabled { opacity: 0.4; pointer-events: none; }
.btn.disabled { opacity: 0.45; pointer-events: none; }

/* ============================================================
   SOPORTE FLOTANTE
   ============================================================ */
.support-fab {
  position: fixed; bottom: 20px; right: 20px;
  background: var(--brand-grad); color: #fff;
  border-radius: 100px; padding: 13px 19px; font-size: 13px; font-weight: 600;
  text-decoration: none; box-shadow: var(--shadow-glow);
  display: flex; align-items: center; gap: 6px; z-index: 40;
}

/* ============================================================
   FILTROS DE PERÍODO + TOOLBAR
   ============================================================ */
.filter-bar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.filter-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  border: 1px solid var(--line); background: var(--bg-elevated);
  padding: 7px 13px; border-radius: 100px; font-size: 12.5px;
  cursor: pointer; color: var(--ink-soft);
}
.chip.active { background: var(--brand-soft); border-color: var(--brand-a); color: var(--brand-solid); font-weight: 600; }
.btn.active { background: var(--brand-soft); border-color: var(--brand-a); color: var(--brand-solid); font-weight: 600; }

/* ============================================================
   MODAL
   ============================================================ */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(10, 13, 20, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 100; padding: 16px; backdrop-filter: blur(2px);
}
.modal-box {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 24px; width: 440px;
  max-width: 100%; max-height: 90vh; overflow-y: auto;
  box-shadow: var(--shadow-card);
}
.modal-box h2 { margin-top: 0; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
.logo-preview {
  height: 62px; width: 62px; border-radius: 12px; object-fit: cover;
  background: var(--muted-bg); border: 1px solid var(--line);
}

/* ============================================================
   VITRINA DE PRODUCTOS (panel revendedor)
   ============================================================ */
.vitrina-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}
.producto-card {
  border: 1px solid var(--line);
  background: var(--bg-elevated);
  border-radius: var(--radius);
  padding: 14px;
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.producto-card:hover { border-color: var(--brand-a); transform: translateY(-2px); }
/* Resalta brevemente la tarjeta a la que llegaste desde el buscador global. */
.producto-card.resaltado-busqueda {
  animation: parpadeoResaltado 1.6s ease-out 2;
  border-color: var(--brand-a);
}
@keyframes parpadeoResaltado {
  0% { box-shadow: 0 0 0 3px var(--brand-a); }
  70% { box-shadow: 0 0 0 3px var(--brand-a); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.producto-card.selected {
  border-color: var(--brand-a);
  box-shadow: var(--shadow-glow);
  background: var(--brand-soft);
}
.producto-card .thumb {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius-sm); margin-bottom: 10px; background: var(--panel-2);
}
.producto-card .thumb-empty {
  width: 100%; aspect-ratio: 4 / 3; border-radius: var(--radius-sm);
  margin-bottom: 10px; background: var(--panel-2);
  display: flex; align-items: center; justify-content: center; font-size: 28px;
}
.producto-card .nombre { font-weight: 600; font-size: 14px; color: var(--ink); margin-bottom: 3px; }
.producto-card .desc { font-size: 12px; color: var(--ink-soft); margin-bottom: 8px; min-height: 14px; }
.producto-card .precio { font-size: 12.5px; color: var(--brand-solid); font-weight: 600; }

/* ============================================================
   TABLA CON SCROLL EN MOBILE
   ============================================================ */
.table-scroll { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll table { min-width: 560px; }

/* ============================================================
   MI CATÁLOGO (revendedor) — link para compartir + input de precio
   ============================================================ */
.tienda-link-box {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}
.tienda-link-box input {
  flex: 1;
  min-width: 220px;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13px;
  background: var(--bg-elevated);
  color: var(--ink-soft);
}
.input-precio {
  width: 110px;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  background: var(--bg-elevated);
  color: var(--ink);
}

/* ============================================================
   TIENDA PÚBLICA (tienda.html) — página sin login que comparte el
   revendedor con sus clientes finales
   ============================================================ */
.tienda-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-elevated);
  flex-wrap: wrap;
}
.tienda-vendedor {
  font-size: 12.5px;
  color: var(--ink-soft);
}
.tienda-vendedor strong { color: var(--ink); }
.tienda-container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 26px 20px 120px;
}
.tienda-container .vitrina-grid { margin-top: 6px; }

.tienda-cart-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--bg-elevated);
  border-top: 1px solid var(--line);
  box-shadow: 0 -8px 24px -14px rgba(20, 20, 20, 0.25);
  padding: 12px 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  z-index: 60;
  flex-wrap: wrap;
}
.tienda-cart-bar .tcb-info { font-size: 13.5px; }
.tienda-cart-bar .tcb-info strong { font-size: 15px; }

.tienda-cart-modal .modal-box { width: 460px; }
.tienda-cart-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.tienda-cart-item:last-child { border-bottom: none; }
.tienda-cart-item .qty-controls { display: flex; align-items: center; gap: 8px; }
.tienda-cart-item .qty-controls button {
  width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--line);
  background: var(--bg-elevated); cursor: pointer; color: var(--ink);
}

@media (max-width: 900px) {
  .hamburger { display: inline-flex; }
  .sidebar {
    position: fixed;
    left: 0; top: 0;
    height: 100vh;
    transform: translateX(-100%);
    box-shadow: 0 0 0 rgba(0,0,0,0);
  }
  body.sidebar-open .sidebar {
    transform: translateX(0);
    box-shadow: 20px 0 40px -20px rgba(0,0,0,0.35);
  }
  body.sidebar-open .sidebar-scrim {
    display: block;
    position: fixed; inset: 0;
    background: rgba(10, 13, 20, 0.45);
    z-index: 45;
  }
}

@media (max-width: 640px) {
  .container { padding: 15px; }
  .topbar { padding: 11px 14px; flex-wrap: wrap; gap: 8px; }
  .topbar .who { display: block; margin-right: 0; font-size: 12px; }
  .card { padding: 15px; }
  .grid-stats { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .stat { padding: 13px; }
  .stat .num { font-size: 19px; }
  .field { min-width: 100%; }
  .login-card-tilt { width: 100%; }
  .login-card { width: 100%; }
  .login-form-panel { padding: 24px; }
  .support-fab span.fab-label { display: none; }
  .modal-box { padding: 17px; }
  .vitrina-grid { grid-template-columns: repeat(2, 1fr); }
  .producto-card { padding: 10px; }
  .pc-precio-dinero { font-size: 14px; }
  .pc-badge-creditos { font-size: 9.5px; padding: 2px 7px; top: 8px; right: 8px; }
}

/* ============================================================
   TOASTS (notificaciones no modales)
   ============================================================ */
.toast-container {
  position: fixed; top: 16px; right: 16px; z-index: 200;
  display: flex; flex-direction: column; gap: 8px;
  max-width: min(360px, calc(100vw - 32px));
}
.toast {
  background: var(--panel); border: 1px solid var(--line);
  border-left: 4px solid var(--brand-a); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card); padding: 12px 14px;
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 13.5px; color: var(--ink);
  opacity: 0; transform: translateX(16px); transition: opacity 0.2s ease, transform 0.2s ease;
}
.toast.show { opacity: 1; transform: translateX(0); }
.toast-exito { border-left-color: var(--ok); }
.toast-error { border-left-color: var(--danger); }
.toast-info { border-left-color: var(--brand-a); }
.toast-msg { flex: 1; line-height: 1.4; }
.toast-close {
  background: none; border: none; color: var(--ink-soft); cursor: pointer;
  font-size: 16px; line-height: 1; padding: 0 2px;
}
.toast-close:hover { color: var(--ink); }

/* ============================================================
   PAGINACIÓN ("cargar más")
   ============================================================ */
.paginador { display: flex; justify-content: center; margin-top: 14px; }
.paginador .btn:disabled { opacity: 0.5; cursor: default; }

/* ============================================================
   COMBOS
   ============================================================ */
.badge-combo {
  color: var(--brand-solid); background: var(--brand-soft);
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.03em;
  padding: 2px 7px; border-radius: 100px; margin-left: 6px; vertical-align: middle;
}
.combo-items-chip {
  display: inline-block; font-size: 11.5px; color: var(--ink-soft);
  background: var(--muted-bg); border-radius: 100px; padding: 2px 9px; margin: 2px 3px 0 0;
}

/* ============================================================
   CUENTAS MAESTRAS / PERFILES
   ============================================================ */
.perfiles-barra {
  width: 100%; height: 6px; border-radius: 100px; background: var(--muted-bg);
  overflow: hidden; margin-top: 4px;
}
.perfiles-barra > div { height: 100%; background: var(--brand-grad); }
.credencial-copiable {
  font-family: "JetBrains Mono", monospace; font-size: 12.5px;
  background: var(--muted-bg); padding: 2px 7px; border-radius: 6px;
  cursor: pointer; user-select: all;
}

/* ============================================================
   SEGMENTADO (selector de preset de credenciales, etc.)
   ============================================================ */
.segmented {
  display: inline-flex; gap: 3px; padding: 3px; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: 100px;
  background: var(--bg-elevated);
}
.segmented button {
  border: none; background: transparent; padding: 6px 13px;
  border-radius: 100px; font-size: 12.5px; cursor: pointer;
  color: var(--ink-soft); font-family: inherit;
}
.segmented button.active { background: var(--brand-soft); color: var(--brand-solid); font-weight: 600; }

/* ============================================================
   CAMPOS DE CREDENCIALES LIBRES (cuenta maestra: email/pass, xtream, m3u...)
   ============================================================ */
.campos-credenciales { display: flex; flex-direction: column; gap: 8px; }
.campo-credencial-row { display: flex; gap: 8px; align-items: center; }
.campo-credencial-row input.campo-label { flex: 0 0 150px; }
.campo-credencial-row input.campo-valor { flex: 1; }
.campo-credencial-row input {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: 13.5px; background: var(--bg-elevated); color: var(--ink); font-family: inherit;
}
.campo-credencial-row .campo-quitar {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--bg-elevated); cursor: pointer;
  color: var(--danger); display: flex; align-items: center; justify-content: center;
}
.campo-credencial-row .campo-quitar:hover { border-color: var(--danger); }

/* Listado de credenciales de una cuenta madre (vista revendedor/admin) */
.credenciales-lista { display: flex; flex-direction: column; gap: 10px; }
.credenciales-lista .cred-item label { font-size: 12px; color: var(--ink-soft); }

/* ============================================================
   CLIENTE CONSOLIDADO (panel revendedor: cliente + sus servicios)
   ============================================================ */
.cliente-bloque {
  border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 12px; overflow: hidden;
}
.cliente-bloque-header {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;
  padding: 14px 16px; background: var(--panel-2);
}
.cliente-bloque-nombre { font-weight: 600; font-size: 14.5px; }
.cliente-bloque-email { font-size: 12.5px; color: var(--ink-soft); }
.cliente-bloque-servicios { padding: 4px 16px 12px 16px; }
.cliente-bloque-vacio { padding: 12px 16px; font-size: 13px; color: var(--ink-soft); }

/* ============================================================
   VITRINA: precio en dinero + badge de créditos + ribbon de oferta
   ============================================================ */
.producto-card { position: relative; overflow: hidden; }

.pc-badge-creditos {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  background: var(--panel-2); border: 1px solid var(--line);
  color: var(--ink-soft); font-size: 10.5px; font-weight: 600;
  padding: 3px 9px; border-radius: 100px; white-space: nowrap;
}

.pc-ribbon-oferta {
  position: absolute; top: 12px; left: -30px; z-index: 2;
  background: var(--danger); color: #fff; font-size: 10.5px; font-weight: 700;
  padding: 4px 34px; transform: rotate(-40deg); letter-spacing: .04em;
  box-shadow: 0 2px 6px rgba(0,0,0,.25);
}

.pc-ribbon-stock {
  position: absolute; top: 12px; left: -30px; z-index: 2;
  background: var(--ink-soft); color: var(--bg-elevated); font-size: 10.5px; font-weight: 700;
  padding: 4px 30px; transform: rotate(-40deg); letter-spacing: .04em;
  box-shadow: 0 2px 6px rgba(0,0,0,.25);
}

/* Tarjeta sin stock: se ve claramente "apagada" para no confundirla con
   una disponible — el revendedor no debería ni intentar venderla. */
.producto-card.sin-stock { opacity: .6; cursor: default; }
.producto-card.sin-stock:hover { transform: none; border-color: var(--line); }
.producto-card.sin-stock .thumb, .producto-card.sin-stock .thumb-empty { filter: grayscale(.6); }

/* Badge chico de "stock" que se usa al lado del servicio en el admin
   (catálogo y disponibilidad). */
.badge-stock-ok { background: var(--ok-bg); color: var(--ok); }
.badge-stock-agotado { background: var(--danger-bg); color: var(--danger); }


.pc-precio-dinero {
  font-size: 16px; font-weight: 700; color: var(--ink);
  display: flex; flex-direction: column; gap: 1px;
  overflow-wrap: break-word; word-break: break-word; min-width: 0;
}
.pc-precio-dinero .tachado {
  font-size: 11.5px; font-weight: 500; color: var(--ink-soft);
  text-decoration: line-through;
}
.pc-precio-dinero.en-oferta { color: var(--danger); }
.pc-dias { font-size: 12px; color: var(--ink-soft); margin-bottom: 2px; }

/* Fallback: si el admin no configuró el valor de 1 crédito todavía, la
   tarjeta igual necesita mostrar un precio principal legible. */
.pc-precio-fallback { font-size: 15px; font-weight: 700; color: var(--ink); }

/* ============================================================
   CARRITO DE COMPRA
   ============================================================ */
.carrito-item {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--line);
}
.carrito-item:last-child { border-bottom: none; }
.carrito-item .ci-nombre { font-weight: 600; font-size: 13.5px; }
.carrito-item .ci-detalle { font-size: 12px; color: var(--ink-soft); }
.carrito-item .ci-quitar {
  border: none; background: none; color: var(--danger); cursor: pointer;
  display: flex; align-items: center; gap: 4px; font-size: 12.5px;
}

/* ============================================================
   BANNER DE AVISO (saldo bajo, etc.)
   ============================================================ */
.banner-alerta {
  background: var(--warn-bg); color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--line));
  border-radius: var(--radius); padding: 12px 16px; margin-bottom: 16px; font-size: 13px;
}

.modal-wide { width: 560px; max-width: 92vw; }
.perfil-pin-row { display:flex; gap:8px; align-items:center; margin-bottom:8px; }
.perfil-pin-row .perfil-nombre { flex: 0 0 90px; font-size: 13px; color: var(--ink-soft); }
.perfil-pin-row input {
  flex: 1; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: 13.5px; background: var(--bg-elevated); color: var(--ink); font-family: inherit;
}
.perfil-pin-row .badge { flex-shrink: 0; }

/* ============================================================
   MODAL PERFILES DE LA CUENTA — administración independiente
   ============================================================ */
.perfil-admin-row {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px; margin-bottom: 10px;
}
.perfil-admin-row .pa-cabecera {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 8px;
}
.perfil-admin-row .pa-nombre { font-weight: 600; font-size: 13.5px; }
.perfil-admin-row .pa-asignado { font-size: 12.5px; color: var(--ink-soft); margin-bottom: 8px; }
.perfil-admin-row .pa-fila-pin { display: flex; gap: 8px; align-items: center; }
.perfil-admin-row .pa-fila-pin input {
  flex: 1; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: 13.5px; background: var(--bg-elevated); color: var(--ink); font-family: inherit;
}

/* ============================================================
   LOGIN — MODERNIZACIÓN (fondo animado, glass, floating labels,
   spinner de carga, shake de error, transición del toggle de tema)
   ============================================================ */

/* --- Fondo: blobs difuminados a la deriva, detrás de la card --- */
.login-wrap {
  position: relative;
  overflow: hidden;
  transition: opacity 0.32s ease, transform 0.32s ease;
  background: #0a0a0a; /* fallback mientras carga la imagen */
}
/* Transición de salida al loguear con éxito, antes de navegar al panel
   (ver login-fx.js / index.html: se agrega justo antes del redirect). */
.login-wrap.leaving { opacity: 0; transform: scale(0.99); }

/* --- Fondo: mosaico de posters (afiches) a pantalla completa, al
   estilo de una pantalla de inicio de un servicio de streaming, con un
   leve zoom-out inicial para que se sienta "vivo" sin distraer. El
   overlay de abajo es el que hace que el formulario siga siendo
   legible arriba de una imagen tan cargada. --- */
.login-bg {
  position: absolute; inset: 0; z-index: 0;
  background-image: url("../img/login-bg.jpg");
  background-size: cover;
  background-position: center;
  animation: login-bg-zoom 26s ease-in-out infinite alternate;
}
@keyframes login-bg-zoom {
  from { transform: scale(1); }
  to { transform: scale(1.06); }
}
.login-bg-overlay {
  position: absolute; inset: 0; z-index: 0;
  /* Siempre oscuro, independiente del tema claro/oscuro elegido: el
     fondo es una foto de pósters, no un color liso, así que aclararla
     en modo claro quedaba desprolijo. Ahora el toggle de tema solo
     afecta la card — el fondo se queda "de noche" siempre. */
  background:
    radial-gradient(120% 90% at 18% 20%, rgba(8, 8, 10, 0.66), transparent 55%),
    linear-gradient(180deg, rgba(6, 6, 8, 0.42) 0%, rgba(6, 6, 8, 0.58) 55%, rgba(6, 6, 8, 0.82) 100%);
}
@media (prefers-reduced-motion: reduce) {
  .login-bg { animation: none; }
}

/* --- Barrido de reflejo de vidrio: una franja de luz muy tenue que
   cruza la pantalla de tanto en tanto, DETRÁS de la card (por eso vive
   en su propio contenedor con z-index 0, entre el overlay y la card,
   que tiene z-index 1 — ver login-card-tilt más abajo). No es un loop
   continuo: login-fx.js la dispara a intervalos irregulares (varios
   segundos, nunca uno pegado al otro) y con ancho al azar — a veces
   una franja ancha, a veces una fina — así no se siente mecánico ni
   "de plantilla" para alguien que se queda un rato mirando el login.
   Sin color: solo blanco muy transparente, como el brillo real de un
   vidrio, no un efecto "de colores". --- */
.login-glass-sweep {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.login-glass-sweep-band {
  position: absolute;
  top: -30%;
  height: 160%;
  width: var(--sweep-w, 90px);
  background: linear-gradient(100deg,
    transparent 0%,
    rgba(255, 255, 255, 0.05) 40%,
    rgba(255, 255, 255, 0.13) 50%,
    rgba(255, 255, 255, 0.05) 60%,
    transparent 100%);
  filter: blur(2px);
  transform: translateX(-140%) skewX(-14deg);
  animation: glass-sweep-move var(--sweep-dur, 2.4s) ease-in-out forwards;
}
@keyframes glass-sweep-move {
  from { transform: translateX(-140%) skewX(-14deg); }
  to   { transform: translateX(calc(100vw + 140%)) skewX(-14deg); }
}
@media (prefers-reduced-motion: reduce) {
  .login-glass-sweep { display: none; }
}

/* --- Firmas ambar: motas de bronce que suben a la deriva, como rescoldos
   de un metal al rojo — la pieza distintiva del login, en línea con la
   identidad "bronce envejecido" de la marca (ver tokens al inicio del
   archivo). Generadas por login-fx.js, cada una arranca en un punto y
   con un desfase (animation-delay negativo) distintos. --- */
.login-embers {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden; pointer-events: none;
}
.login-ember {
  position: absolute;
  bottom: -5%;
  width: var(--e-size, 4px);
  height: var(--e-size, 4px);
  border-radius: 50%;
  background: var(--brand-a);
  box-shadow: 0 0 6px 1px var(--brand-glow);
  opacity: 0;
  animation: ember-rise var(--e-dur, 9s) linear infinite;
  animation-delay: var(--e-delay, 0s);
}
@keyframes ember-rise {
  0%   { transform: translate(0, 0); opacity: 0; }
  8%   { opacity: 0.85; }
  92%  { opacity: 0.15; }
  100% { transform: translate(var(--e-drift, 24px), -112vh); opacity: 0; }
}

/* --- Resplandor: aro de luz que respira detrás del logo, como metal
   al calentarse. Sutil — es la única pieza "audaz" del login. --- */
.login-card .brand-wrap { position: relative; }
.login-card .brand-logo-glow {
  position: absolute;
  left: 50%; top: 18px;
  width: 74px; height: 74px;
  transform: translate(-50%, 0);
  border-radius: 50%;
  background: radial-gradient(circle, var(--brand-glow), transparent 70%);
  animation: ember-glow-breathe 3.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes ember-glow-breathe {
  0%, 100% { opacity: 0.5; transform: translate(-50%, 0) scale(0.94); }
  50%      { opacity: 1;   transform: translate(-50%, 0) scale(1.08); }
}

/* --- Tilt 3D: la card sigue sutilmente el mouse (login-fx.js calcula el
   ángulo; acá solo se define la perspectiva y el suavizado). Se
   desactiva solo en touch/mobile porque login-fx.js no la activa ahí. --- */
/* Mismo ancho que login-card tenía antes de envolverla (ver regla
   original más abajo): si no, al ser un div sin tamaño propio dentro
   del flex de .login-wrap, el "width: 100%" de login-card en mobile
   queda resolviendo contra un padre sin ancho definido. */
.login-card-tilt { perspective: 900px; z-index: 1; width: 400px; max-width: 100%; }
.login-card {
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  transform-style: preserve-3d;
}

/* --- Card: vidrio esmerilado + entrada animada. Usa las mismas
   variables de tema que el resto de la app (--panel, --ink, etc.), así
   que el toggle claro/oscuro SÍ cambia cómo se ve — solo le subimos
   blur y opacidad respecto al resto de la app porque acá atrás hay una
   foto (no un fondo liso) y necesita más "peso" para leerse bien. --- */
.login-card {
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(22px) saturate(1.3);
  -webkit-backdrop-filter: blur(22px) saturate(1.3);
  box-shadow: var(--shadow-card), 0 24px 60px -20px rgba(0, 0, 0, 0.45);
  animation: login-card-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.login-wrap .theme-toggle {
  background: color-mix(in srgb, var(--panel) 70%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
@keyframes login-card-in {
  from { opacity: 0; transform: translateY(18px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* Entrada escalonada: cada pieza del formulario aparece en cascada en
   vez de todas juntas de un tirón — es lo que hace que se sienta
   coreografiado y no un simple fade genérico. Esto solo cubre lo que
   se ve al cargar la página (logo + hero): lo que vive adentro del
   formulario ya no usa esta animación CSS — la coreografía GSAP de
   abrirFormularioLogin() (login-fx.js) la controla explícitamente al
   desplegarse, así que no compiten por la misma propiedad. */
.login-card .brand-wrap,
.login-card .login-hero-tagline,
.login-card #btn-abrir-login {
  animation: login-fade-in 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.login-card .brand-wrap { animation-delay: 0.10s; }
.login-card .login-hero-tagline { animation-delay: 0.18s; }
.login-card #btn-abrir-login { animation-delay: 0.26s; }

@keyframes login-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* --- Spotlight: resplandor que sigue al cursor dentro del panel del
   formulario (login-fx.js actualiza --sx/--sy en cada mousemove). Solo
   se activa con mouse real — el gate de hover/pointer:fine ya lo hace
   login-fx.js, así que en touch simplemente no pasa nada. --- */
.login-spotlight {
  position: absolute; inset: 0;
  pointer-events: none;
  background: radial-gradient(280px circle at var(--sx, 50%) var(--sy, 15%), var(--brand-glow), transparent 70%);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.login-form-panel:hover .login-spotlight { opacity: 1; }

/* --- Borde animado: un aro de gradiente cónico gira despacio alrededor
   de toda la card, como un detalle "vivo" sin ser invasivo. Mezcla el
   dorado de marca con el rojo oscuro de la paleta del póster de fondo
   (--cine-red), para que no se sienta "dorado genérico" pegado encima
   de una imagen que es mayormente rojos y negros. Se degrada de forma
   segura en navegadores sin @property: el borde queda estático en vez
   de girar, nada se rompe. --- */
.login-card-tilt { position: relative; }
.login-card-tilt::before {
  content: "";
  position: absolute; inset: -2px;
  border-radius: calc(var(--radius) + 2px);
  padding: 1.5px;
  background: conic-gradient(from var(--border-angle, 0deg), var(--brand-a), var(--cine-red) 26%, transparent 42%, var(--brand-b), var(--cine-red-2) 68%, transparent 84%, var(--brand-a));
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0.8;
  animation: border-spin 8s linear infinite;
  pointer-events: none;
  z-index: -1;
}
@property --border-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
@keyframes border-spin {
  to { --border-angle: 360deg; }
}

/* --- Silueta de fondo: un ícono grande, casi transparente, apoyado en
   una esquina de la card — el tipo de detalle que usan las apps de
   streaming "serias" para dar textura sin ensuciar el contenido. Va
   DETRÁS del formulario (por eso vive como primer hijo de .login-card
   en el HTML, no de .login-form-panel: así el orden del DOM alcanza
   para que quede debajo sin necesitar z-index explícito). --- */
.login-card-watermark {
  position: absolute;
  width: 230px; height: 230px;
  right: -46px; bottom: -34px;
  color: var(--brand-a);
  opacity: 0.07;
  transform: rotate(-14deg);
  pointer-events: none;
}
[data-theme="dark"] .login-card-watermark { opacity: 0.1; }

/* --- Hero de login: sin mensajes de texto tipo "publicidad" (esto lo
   ve por igual un admin, un súper revendedor o un revendedor) — en su
   lugar, una animación de monedas y un único botón "Iniciar sesión".
   Al tocarlo, GSAP (abrirFormularioLogin en login-fx.js) coreografía
   el cierre del hero y la apertura del formulario real (email,
   contraseña, olvidé mi contraseña, crear cuenta). Estas reglas solo
   dejan al formulario sin alto/oculto por default — la animación en sí
   la hace JS. Si GSAP no llegara a cargar, login-fx.js tiene un
   fallback que igual muestra el formulario (sin animar), así que la
   app nunca queda bloqueada por esto. --- */
.login-hero { overflow: hidden; }
.login-form-body {
  overflow: hidden;
  height: 0;
  opacity: 0;
}

.login-card .login-hero-tagline {
  color: var(--ink-soft);
  font-size: 13px;
  text-align: center;
  margin: 0 0 18px 0;
}

.login-hero-money {
  position: relative;
  height: 96px;
  margin: 2px 0 2px;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Las capas de movimiento del ícono (drift del contenedor) las sigue
   animando GSAP en login-fx.js — por eso acá no hay "animation:" en
   .login-hero-money. El glitch play→pausa sí es CSS puro (keyframes
   más abajo), disparado por login-fx.js con clases/atributos, para
   que funcione igual con o sin GSAP cargado. */
.login-hero-glitch-icon {
  --ghi-cyan: #22e6ff;
  --ghi-red: #ff2d55;
  position: relative;
  width: 46px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  color: var(--brand-solid);
}
/* Sin círculo, sin relleno: el ícono "flota" directo sobre la card. */
.ghi-icon {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  margin: auto;
  filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3));
  opacity: 0;
  transform: scale(1);
  transition: opacity 0.15s linear;
}
.ghi-play { margin-left: 3px; } /* mismo ajuste óptico que antes */
.login-hero-glitch-icon[data-state="play"] .ghi-play { opacity: 1; }
.login-hero-glitch-icon[data-state="pause"] .ghi-pause { opacity: 1; }

/* Líneas de barrido sutiles detrás del ícono: solo se notan durante
   el glitch (ver .is-glitching más abajo), como si el "cuadro" se
   perdiera un instante. */
.ghi-scanlines {
  position: absolute; inset: -6px;
  border-radius: 6px;
  background: repeating-linear-gradient(
    to bottom, rgba(255, 255, 255, 0.5) 0px, rgba(255, 255, 255, 0.5) 1px,
    transparent 1px, transparent 3px
  );
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: overlay;
}

/* ---- GLITCH: interferencia de señal al pasar de play a pausa ---- */
/* Mientras dura, cada ícono visible tiembla y se separa en dos capas
   de color (cian/rojo, como el corrimiento de canal de una señal
   analógica perdiendo sincronismo), con cortes de "clip-path" que
   simulan el cuadro rompiéndose por líneas. */
.login-hero-glitch-icon.is-glitching .ghi-play,
.login-hero-glitch-icon.is-glitching .ghi-pause {
  animation: ghi-glitch-shake 0.5s steps(2, end) both;
}
.login-hero-glitch-icon.is-glitching[data-state="play"] .ghi-play,
.login-hero-glitch-icon.is-glitching[data-state="pause"] .ghi-pause {
  opacity: 1;
}
.login-hero-glitch-icon.is-glitching .ghi-scanlines {
  opacity: 1;
  animation: ghi-scanlines-flicker 0.5s steps(1, end) both;
}
@keyframes ghi-glitch-shake {
  0%   { transform: translate(0, 0);      clip-path: inset(0 0 0 0);   filter: drop-shadow(0 0 0 transparent); }
  8%   { transform: translate(-3px, 1px); clip-path: inset(10% 0 55% 0); filter: drop-shadow(-2px 0 var(--ghi-cyan)) drop-shadow(2px 0 var(--ghi-red)); }
  16%  { transform: translate(3px, -1px); clip-path: inset(60% 0 5% 0);  filter: drop-shadow(3px 0 var(--ghi-red)) drop-shadow(-3px 0 var(--ghi-cyan)); }
  24%  { transform: translate(-2px, 2px); clip-path: inset(30% 0 30% 0); filter: drop-shadow(-2px 0 var(--ghi-cyan)) drop-shadow(2px 0 var(--ghi-red)); }
  32%  { transform: translate(0, 0);      clip-path: inset(0 0 0 0);   opacity: 0.15; filter: none; }
  40%  { transform: translate(4px, 1px);  clip-path: inset(5% 0 70% 0); filter: drop-shadow(3px 0 var(--ghi-red)) drop-shadow(-3px 0 var(--ghi-cyan)); opacity: 1; }
  48%  { transform: translate(-4px, -2px); clip-path: inset(45% 0 15% 0); filter: drop-shadow(-3px 0 var(--ghi-cyan)) drop-shadow(3px 0 var(--ghi-red)); }
  56%  { transform: translate(2px, 0);    clip-path: inset(20% 0 40% 0); filter: drop-shadow(2px 0 var(--ghi-red)) drop-shadow(-2px 0 var(--ghi-cyan)); }
  64%  { opacity: 0.2; transform: translate(0, 0); clip-path: inset(0 0 0 0); filter: none; }
  72%  { transform: translate(-2px, 1px); clip-path: inset(55% 0 10% 0); filter: drop-shadow(-2px 0 var(--ghi-cyan)) drop-shadow(2px 0 var(--ghi-red)); opacity: 1; }
  84%  { transform: translate(1px, -1px); clip-path: inset(15% 0 45% 0); filter: drop-shadow(1px 0 var(--ghi-red)) drop-shadow(-1px 0 var(--ghi-cyan)); }
  100% { transform: translate(0, 0);      clip-path: inset(0 0 0 0);   filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3)); }
}
@keyframes ghi-scanlines-flicker {
  0%, 100% { opacity: 0; }
  10%, 30%, 55%, 80% { opacity: 0.9; }
  20%, 45%, 65%, 90% { opacity: 0.2; }
}
@media (prefers-reduced-motion: reduce) {
  .login-hero-glitch-icon.is-glitching .ghi-play,
  .login-hero-glitch-icon.is-glitching .ghi-pause,
  .login-hero-glitch-icon.is-glitching .ghi-scanlines { animation: none; }
}

/* Shake cuando el login falla, con un pulso de sombra roja encima del
   shake horizontal para que el rechazo se sienta, no solo se lea. */
.login-card.shake { animation: login-shake 0.42s cubic-bezier(0.36, 0.07, 0.19, 0.97) both, login-glow-error 0.9s ease both; }
@keyframes login-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-5px); }
  40%, 60% { transform: translateX(5px); }
}
@keyframes login-glow-error {
  0% { box-shadow: var(--shadow-card); }
  25% { box-shadow: 0 0 0 3px var(--danger-bg), 0 0 32px -6px var(--danger); }
  100% { box-shadow: var(--shadow-card); }
}

/* Ícono de error: un pequeño "shake" propio + aparición con pop,
   separado del shake de la card para que el mensaje se note incluso
   si alguien no percibe el movimiento de la card. */
.error-msg { display: flex; align-items: center; gap: 6px; }
.error-msg:not(:empty) { animation: error-msg-in 0.3s cubic-bezier(.34,1.56,.64,1) both; }
@keyframes error-msg-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Destello de pantalla completa: un solo pulso de color al confirmar
   login (verde) o al rechazarlo (rojo) — refuerza el resultado sin
   ser intrusivo, un solo ciclo y desaparece. */
.result-flash {
  position: fixed; inset: 0; z-index: 60; pointer-events: none; opacity: 0;
}
.result-flash.flash-ok {
  background: radial-gradient(circle at 50% 38%, rgba(61, 107, 74, 0.32), transparent 62%);
  animation: result-flash-out 0.7s ease forwards;
}
.result-flash.flash-error {
  background: radial-gradient(circle at 50% 38%, rgba(150, 64, 58, 0.28), transparent 62%);
  animation: result-flash-out 0.55s ease forwards;
}
@keyframes result-flash-out {
  0% { opacity: 0; }
  30% { opacity: 1; }
  100% { opacity: 0; }
}

/* --- Floating labels (solo dentro de la card de login) --- */
.login-card .field-float { position: relative; margin-bottom: 20px; }
/* El "cuadro de datos" (email/contraseña) siempre oscuro con letras
   claras, en los dos temas — no light-bg-dark-text como el resto de
   los inputs de la app. Es la referencia tipo buscador de Hostinger:
   una píldora oscura y translúcida que funciona igual de bien arriba
   de una card clara que de una oscura. */
.login-card .field-float input {
  width: 100%;
  padding: 16px 13px 10px;
  border: none;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: rgba(18, 17, 16, 0.55);
  color: #f4f1ea;
  font-family: inherit;
  font-size: 14.5px;
  transition: border-color 0.18s ease, background-color 0.25s ease;
}
.login-card .field-float input::placeholder { color: rgba(244, 241, 234, 0.35); }
/* Línea que se ilumina y "crece" desde el centro al enfocar — reemplaza
   el box-shadow clásico por algo más minimalista y actual. */
.login-card .field-float::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  border-radius: 2px;
  /* Fijo (no var(--brand-grad)): el input de abajo es siempre oscuro en
     los dos temas, y en modo claro el acento de marca ahora es grafito
     — invisible sobre un fondo oscuro. El rojo del póster sí se lee
     en cualquiera de los dos casos. */
  background: var(--cine-red-2);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.3s cubic-bezier(.3,.8,.4,1);
  pointer-events: none;
}
.login-card .field-float label {
  position: absolute;
  left: 13px;
  top: 15px;
  font-size: 14.5px;
  color: rgba(244, 241, 234, 0.55);
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.16s ease, color 0.16s ease, top 0.16s ease;
}
.login-card .field-float input:focus,
.login-card .field-float input:not(:placeholder-shown) {
  outline: none;
  border-bottom-color: transparent;
  background: rgba(18, 17, 16, 0.72);
}
.login-card .field-float:focus-within::after { transform: scaleX(1); }
.login-card .field-float input:focus + label,
.login-card .field-float input:not(:placeholder-shown) + label {
  top: 6px;
  transform: scale(0.78);
  color: var(--cine-red-2);
}

/* --- Botón primario: brillo al pasar el mouse, feedback al clickear,
   estado de carga con spinner y estado de éxito (login-card únicamente,
   activado desde index.html justo antes de redirigir al panel). --- */
.btn-primary {
  position: relative;
  overflow: hidden;
  transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.3s ease;
}
.btn-primary::after {
  content: "";
  position: absolute; top: 0; bottom: 0; left: -60%;
  width: 40%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-18deg);
  transition: left 0.55s ease;
  pointer-events: none;
}
.btn-primary:hover::after { left: 130%; }
.btn-primary:hover { box-shadow: var(--shadow-glow); }
.btn-primary:active { transform: scale(0.97); }

.btn-primary .btn-spinner {
  display: none;
  width: 15px; height: 15px;
  border: 2px solid rgba(255, 245, 228, 0.4);
  border-top-color: #fff5e4;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
}
.btn-primary.loading .btn-label { opacity: 0; }
.btn-primary.loading .btn-spinner {
  display: block;
  position: absolute; left: 50%; top: 50%;
  margin: -9px 0 0 -9px;
}
.btn-primary.loading { pointer-events: none; }
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Estado de éxito: check que aparece con un pequeño "pop" al confirmar
   el login, antes de que login-wrap se desvanezca y navegue al panel. */
.btn-primary.success { pointer-events: none; }
.btn-primary.success .btn-spinner { display: none; }
.btn-primary .btn-check {
  display: none;
  position: absolute; left: 50%; top: 50%;
  margin: -8px 0 0 -8px;
}
.btn-primary.success .btn-check {
  display: inline-flex;
  animation: check-pop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.btn-primary.success .btn-label { opacity: 0; }
@keyframes check-pop {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: scale(1); }
}

/* Anillo que se expande desde el check y se desvanece: el "impacto"
   visual del éxito, además del check en sí. */
.btn-primary.success::before {
  content: "";
  position: absolute; left: 50%; top: 50%;
  width: 16px; height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  border: 2px solid rgba(255, 253, 246, 0.85);
  opacity: 0;
  animation: success-ring 0.6s cubic-bezier(.2,.7,.3,1) 0.08s both;
  pointer-events: none;
}
@keyframes success-ring {
  0% { opacity: 0.9; transform: scale(1); }
  100% { opacity: 0; transform: scale(3.2); }
}

/* --- Toggle de tema: giro completo (360°) al togglear ---
   OJO: antes esto era `transform: rotate(180deg)` fijo y la clase nunca se
   sacaba -> el botón quedaba girado boca abajo para siempre después del
   primer click. Con @keyframes + fill-mode por defecto ("none"), al
   terminar la animación el elemento vuelve solo a su estado normal
   (0deg), así que no hace falta ni tocar el JS para "destrancarlo". */
.theme-toggle { transition: border-color 0.15s ease; }
.theme-toggle.spin { animation: theme-spin 0.5s cubic-bezier(0.65, 0, 0.35, 1); }
@keyframes nav-item-in {
  from { opacity: 0; transform: translateX(-10px); }
  to { opacity: 1; transform: translateX(0); }
}

/* Transición entre módulos del panel: cada vez que JS pasa un
   .tab-panel de display:none a block, el navegador reinicia esta
   animación sola (no hace falta tocar la lógica de iniciarTabs()). */
.tab-panel {
  animation: panel-fade-in 0.34s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes panel-fade-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes theme-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ============================================================
   BUSCADOR GLOBAL (topbar) — admin y revendedor
   ============================================================ */
.buscador-global-wrap { position: relative; min-width: 0; }
.buscador-global-input {
  width: 220px; max-width: 40vw;
  padding: 8px 12px 8px 34px;
  border: 1px solid var(--line); border-radius: 100px;
  background: var(--panel); color: var(--ink); font-size: 13px;
}
.buscador-global-wrap .ico-lupa {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--ink-soft); pointer-events: none;
}
.buscador-global-dropdown {
  display: none; position: absolute; top: calc(100% + 6px); left: 0;
  width: 320px; max-width: 84vw; max-height: 400px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-card); z-index: 80;
}
.buscador-global-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-bottom: 1px solid var(--line); cursor: pointer;
}
.buscador-global-item:last-child { border-bottom: none; }
.buscador-global-item:hover { background: var(--panel-2); }
.buscador-global-tipo {
  flex-shrink: 0; font-size: 10px; font-weight: 700; text-transform: uppercase;
  color: var(--brand-solid); background: var(--brand-soft);
  padding: 3px 7px; border-radius: 100px; letter-spacing: .03em;
}
.buscador-global-textos { min-width: 0; flex: 1; }
.buscador-global-titulo { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buscador-global-sub { font-size: 11.5px; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buscador-global-vacio { padding: 16px 12px; font-size: 12.5px; color: var(--ink-soft); text-align: center; }

/* ============================================================
   NOTIFICACIONES INTERNAS (campanita)
   ============================================================ */
.noti-wrap { position: relative; }
.noti-btn {
  position: relative; border: 1px solid var(--line); background: var(--panel);
  border-radius: 100px; width: 36px; height: 36px; display: flex;
  align-items: center; justify-content: center; cursor: pointer; color: var(--ink);
}
.noti-badge {
  display: none; position: absolute; top: -4px; right: -4px;
  background: var(--danger); color: #fff; font-size: 10px; font-weight: 700;
  min-width: 17px; height: 17px; border-radius: 100px; align-items: center; justify-content: center;
  padding: 0 3px; border: 2px solid var(--bg-elevated);
}
.noti-dropdown {
  display: none; position: absolute; top: calc(100% + 8px); right: 0;
  width: 320px; max-width: 88vw; max-height: 420px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-card); z-index: 80;
}
.noti-dropdown-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 14px; border-bottom: 1px solid var(--line); font-weight: 600; font-size: 13.5px;
}
.noti-dropdown-header button { font-size: 11.5px; color: var(--brand-solid); background: none; border: none; cursor: pointer; }
.noti-item { display: flex; gap: 10px; padding: 11px 14px; border-bottom: 1px solid var(--line); cursor: pointer; }
.noti-item:last-child { border-bottom: none; }
.noti-item:hover { background: var(--panel-2); }
.noti-item.noti-sin-leer { background: var(--brand-soft); }
.noti-ico { flex-shrink: 0; color: var(--brand-solid); margin-top: 1px; }
.noti-texto { min-width: 0; }
.noti-titulo { font-size: 13px; font-weight: 600; }
.noti-detalle { font-size: 12px; color: var(--ink-soft); margin-top: 1px; }
.noti-fecha { font-size: 10.5px; color: var(--ink-soft); margin-top: 3px; }

/* ============================================================
   FONDO CON LOGO DEL PROVEEDOR (difuminado) + TARJETAS GLASS ADAPTATIVAS
   ------------------------------------------------------------
   El contenedor (la sección de vitrina) recibe .con-fondo-logo +
   data-fondo="oscuro|claro|multicolor" desde logoBg.js. La capa del
   logo va DETRÁS de todo (z-index -1), difuminada y en baja opacidad
   para que nunca compita con las tarjetas. Las tarjetas de producto
   dentro de ese contenedor cambian de estilo según data-fondo, para
   garantizar lectura óptima sea cual sea el logo cargado.
   ============================================================ */
.con-fondo-logo { position: relative; isolation: isolate; }
.fondo-logo-capa {
  position: absolute; inset: -40px; z-index: -1;
  background-repeat: no-repeat; background-position: center;
  background-size: min(70%, 480px); filter: blur(38px) saturate(85%);
  opacity: 0.16; pointer-events: none;
}
[data-theme="dark"] .fondo-logo-capa { opacity: 0.22; }

/* Fondo oscuro → tarjeta clara (glass claro), texto oscuro fijo */
[data-fondo="oscuro"] .producto-card {
  background: rgba(250, 247, 240, 0.85);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-color: rgba(255, 255, 255, 0.35);
  color: #1c1912;
}
[data-fondo="oscuro"] .producto-card .nombre { color: #1c1912; }
[data-fondo="oscuro"] .producto-card .desc, [data-fondo="oscuro"] .producto-card .pc-dias { color: #5c5544; }
[data-fondo="oscuro"] .producto-card .pc-precio-dinero { color: #1c1912; }

/* Fondo claro → tarjeta oscura (glass oscuro), texto claro fijo */
[data-fondo="claro"] .producto-card {
  background: rgba(24, 21, 15, 0.78);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-color: rgba(255, 255, 255, 0.12);
  color: #f3efe4;
}
[data-fondo="claro"] .producto-card .nombre { color: #f3efe4; }
[data-fondo="claro"] .producto-card .desc, [data-fondo="claro"] .producto-card .pc-dias { color: #b7ae99; }
[data-fondo="claro"] .producto-card .pc-precio-dinero { color: #f0d9a0; }

/* Fondo multicolor → la tarjeta se "independiza": opacidad alta, casi
   sólida, en el color propio de la marca (no del logo), conservando el
   borde/realce cristalizado pero sin dejar que el fondo la pise. */
[data-fondo="multicolor"] .producto-card {
  background: var(--panel);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid var(--brand-a);
  box-shadow: var(--shadow-glow);
}

/* ============================================================
   CARRUSEL "MÁS VENDIDOS" (tienda pública)
   ============================================================ */
.carrusel-destacados-wrap { position: relative; margin-bottom: 22px; }
.carrusel-destacados {
  display: flex; gap: 14px; overflow-x: auto; scroll-behavior: smooth;
  padding: 4px 2px 10px; scrollbar-width: thin;
}
.carrusel-destacados .producto-card { flex: 0 0 auto; width: 216px; transform: scale(1.02); }
.carrusel-destacados .producto-card .thumb,
.carrusel-destacados .producto-card .thumb-empty { aspect-ratio: 4/3; }
.seccion-titulo {
  display: flex; align-items: center; gap: 8px; margin: 22px 0 10px;
  font-family: "Space Grotesk", sans-serif; font-size: 15.5px; font-weight: 600;
}
.seccion-titulo .badge-destacado {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: var(--brand-soft); color: var(--brand-solid); padding: 3px 9px; border-radius: 100px;
}

/* ============================================================
   CARRITO MEJORADO (revendedor y tienda pública)
   ============================================================ */
.qty-editable { display: flex; align-items: center; gap: 6px; }
.qty-editable button {
  width: 22px; height: 22px; border-radius: 6px; border: 1px solid var(--line);
  background: var(--panel); cursor: pointer; font-size: 13px; line-height: 1;
}
.qty-editable input {
  width: 34px; text-align: center; border: 1px solid var(--line); border-radius: 6px;
  padding: 3px 2px; font-size: 12.5px; background: var(--bg-elevated); color: var(--ink);
}
.carrito-nota-input {
  width: 100%; margin-top: 6px; padding: 6px 8px; font-size: 12px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--bg-elevated); color: var(--ink);
}
.toast-deshacer {
  display: flex; align-items: center; gap: 10px;
}
.toast-deshacer button {
  background: none; border: none; color: var(--brand-solid); font-weight: 700;
  font-size: 12.5px; cursor: pointer; text-decoration: underline;
}
.combo-sugerido-banner {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  background: var(--brand-soft); border: 1px solid var(--brand-a); border-radius: var(--radius-sm);
  padding: 9px 12px; margin-bottom: 10px; font-size: 12.5px;
}
.combo-sugerido-banner button { flex-shrink: 0; }

/* ============================================================
   MOROSOS (panel revendedor: clientes)
   ============================================================ */
.badge-moroso { background: var(--danger-bg); color: var(--danger); }

/* ============================================================
   CARGA MASIVA (cuentas maestras)
   ============================================================ */
#cm-masivo-lineas { width: 100%; font-family: "JetBrains Mono", monospace; font-size: 12.5px; }

/* ============================================================
   MASCOTA DE LA VITRINA (tienda.html)
   ============================================================ */
.tienda-mascota {
  position: fixed;
  z-index: 500;
  width: 58px;
  height: 58px;
  transition: left 0.2s ease, top 0.2s ease; /* red de seguridad si GSAP no cargó */
}
.tienda-mascota.tienda-mascota-quieta { left: auto !important; right: 18px; bottom: 18px; top: auto !important; }

.tienda-mascota-avatar {
  width: 58px; height: 58px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  background: var(--brand-grad);
  box-shadow: var(--shadow-glow), 0 8px 20px -6px rgba(0,0,0,0.35);
  display: flex; align-items: center; justify-content: center;
  animation: mascota-idle 2.4s ease-in-out infinite;
}
@keyframes mascota-idle {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-5px) scale(1.03); }
}

.tienda-mascota-cara { position: relative; width: 30px; height: 20px; }
.tienda-mascota-cara .ojo {
  position: absolute; top: 0; width: 6px; height: 6px; border-radius: 50%;
  background: #fffdf6;
}
.tienda-mascota-cara .ojo-izq { left: 4px; }
.tienda-mascota-cara .ojo-der { right: 4px; }
.tienda-mascota-cara .boca {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 16px; height: 8px;
  border: 2.5px solid #fffdf6;
  border-top: none;
  border-radius: 0 0 16px 16px;
}

.tienda-mascota-cerrar {
  position: absolute; top: -6px; right: -6px;
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-soft);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  z-index: 2;
}

.tienda-mascota-globo {
  position: absolute;
  bottom: 68px;
  right: 0;
  width: max-content;
  max-width: 220px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
  padding: 10px 12px;
  font-size: 12.5px;
  color: var(--ink);
  opacity: 0;
  transform: translateY(6px) scale(0.96);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.tienda-mascota-globo.is-visible { opacity: 1; transform: translateY(0) scale(1); }
.tienda-mascota-globo::after {
  content: "";
  position: absolute; bottom: -6px; right: 22px;
  width: 12px; height: 12px;
  background: var(--panel);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  transform: rotate(45deg);
}

/* ============================================================
   NOTIFICACIONES — sonido + alerta grande
   ============================================================ */
.noti-sonido-btn {
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border: none; background: none;
  color: var(--ink-soft);
  cursor: pointer;
  border-radius: 5px;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.noti-sonido-btn:hover { background: var(--bg-elevated); color: var(--ink); }
.noti-sonido-btn.noti-sonido-muteado { color: var(--danger); }

/* Banner grande, centrado arriba, para una notificación recién llegada
   con la ventana abierta. Se apila de a una (nunca varias juntas, para
   no ser invasivo) y se cierra sola a los pocos segundos, o al
   tocarla/cerrarla. */
.noti-alerta {
  position: fixed;
  top: 18px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10050;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: min(420px, calc(100vw - 32px));
  background: var(--panel);
  border: 1px solid var(--brand-a);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card), 0 20px 45px -15px rgba(0,0,0,0.4), 0 0 0 1px var(--brand-soft);
  padding: 16px 18px;
  cursor: pointer;
}
.noti-alerta-ico {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--brand-grad);
  color: #fffdf6;
  display: flex; align-items: center; justify-content: center;
}
.noti-alerta-texto { flex: 1; min-width: 0; }
.noti-alerta-titulo { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.noti-alerta-detalle { font-size: 13px; color: var(--ink-soft); margin-top: 3px; }
.noti-alerta-cerrar {
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: none;
  background: none;
  color: var(--ink-soft);
  font-size: 11px;
  cursor: pointer;
}
.noti-alerta-cerrar:hover { background: var(--bg-elevated); }

/* ============================================================
   SALUD DEL NEGOCIO — dos columnas, a favor / para atender
   ============================================================ */
.salud-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 640px) {
  .salud-grid { grid-template-columns: 1fr; }
}
.salud-col-titulo {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.03em;
  margin-bottom: 10px;
}
.salud-col-titulo-ok { color: var(--ok); }
.salud-col-titulo-alerta { color: var(--warn); }
.salud-item {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.salud-item:last-child { border-bottom: none; }
.salud-punto { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.salud-punto-ok { background: var(--ok); }
.salud-punto-alerta { background: var(--warn); }
.salud-label { flex: 1; color: var(--ink-soft); }
.salud-valor { font-weight: 700; color: var(--ink); }
.salud-valor-alerta { color: var(--danger); }

/* ============================================================
   PALETA DE COMANDOS (Cmd+K / Ctrl+K)
   ============================================================ */
.cmdk-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
  background: rgba(10, 9, 6, 0.55);
  backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.cmdk-overlay.is-open { opacity: 1; pointer-events: auto; }

.cmdk-box {
  width: 560px;
  max-width: 92vw;
  max-height: 60vh;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card), 0 30px 60px -20px rgba(0,0,0,0.5);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: translateY(-8px) scale(0.98);
  transition: transform 0.18s cubic-bezier(.22,.85,.32,1);
}
.cmdk-overlay.is-open .cmdk-box { transform: translateY(0) scale(1); }

.cmdk-inputwrap {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-soft);
  flex-shrink: 0;
}
.cmdk-input {
  flex: 1;
  border: none;
  background: transparent;
  outline: none;
  font-size: 15px;
  color: var(--ink);
  font-family: inherit;
}
.cmdk-hint {
  font-size: 11px;
  font-family: "JetBrains Mono", monospace;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 2px 6px;
}

.cmdk-list { overflow-y: auto; padding: 6px; }
.cmdk-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--ink-soft);
}
.cmdk-item.activo { background: var(--brand-soft); color: var(--ink); }
.cmdk-tipo {
  flex-shrink: 0;
  font-size: 10.5px;
  font-family: "JetBrains Mono", monospace;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--brand-solid);
  border: 1px solid var(--brand-a);
  border-radius: 4px;
  padding: 2px 6px;
}
.cmdk-textos { flex: 1; min-width: 0; }
.cmdk-titulo { font-size: 13.5px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmdk-sub { font-size: 11.5px; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmdk-vacio { padding: 24px 12px; text-align: center; color: var(--ink-soft); font-size: 13px; }

/* ============================================================
   LOADER DE ARRANQUE (admin / reseller / tienda)
   ------------------------------------------------------------
   Tapa la pantalla mientras se resuelve el login y arrancan los
   primeros datos, para no mostrar el sidebar/tablas vacías un
   instante. Una gema facetada (el mismo lenguaje visual del ícono de
   la PWA) girando en su lugar, con una barra de progreso fina abajo —
   nada de spinner genérico. La coreografía de salida la maneja GSAP
   en app-loader.js; estas reglas son el estado visual y un fallback
   en CSS puro si GSAP no llegó a cargar.
   ============================================================ */
.app-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  background: var(--bg);
  transition: opacity 0.5s ease;
}
.app-loader.is-hidden { opacity: 0; pointer-events: none; }

.app-loader-gem-wrap {
  width: 68px;
  height: 68px;
  perspective: 420px;
}
.app-loader-gem {
  width: 100%;
  height: 100%;
  display: block;
  transform-style: preserve-3d;
  animation: loader-gem-spin 2.2s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
  filter: drop-shadow(0 6px 18px rgba(169, 129, 47, 0.35));
}
.app-loader-gem .face-top { fill: var(--brand-a); }
.app-loader-gem .face-left { fill: var(--brand-b); }
.app-loader-gem .face-right { fill: color-mix(in srgb, var(--brand-a) 55%, var(--brand-b)); }

@keyframes loader-gem-spin {
  0%   { transform: rotateY(0deg) rotateX(8deg); }
  50%  { transform: rotateY(180deg) rotateX(8deg); }
  100% { transform: rotateY(360deg) rotateX(8deg); }
}

.app-loader-bar {
  width: 132px;
  height: 3px;
  border-radius: 2px;
  background: var(--line);
  overflow: hidden;
}
.app-loader-bar-fill {
  height: 100%;
  width: 0%;
  border-radius: 2px;
  background: var(--brand-grad);
}
/* ============================================================
   BANNER DE INSTALACIÓN PWA — glassmorphism + glow animado
   ============================================================ */
.pwa-install-banner {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 140%);
  width: min(420px, calc(100vw - 24px));
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 14px 14px 12px;
  border-radius: 18px;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--panel) 78%, transparent);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.06) inset,
    0 20px 45px -18px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(217, 171, 85, 0.08);
  z-index: 9999;
  opacity: 0;
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.55s ease;
  overflow: hidden;
}

.pwa-install-banner.pwa-install-visible {
  transform: translate(-50%, 0);
  opacity: 1;
}

.pwa-install-glow {
  position: absolute;
  inset: -40% -20%;
  background: conic-gradient(from 0deg, transparent, var(--brand-glow), transparent 30%);
  animation: pwa-spin 6s linear infinite;
  opacity: 0.55;
  pointer-events: none;
}

@keyframes pwa-spin {
  to { transform: rotate(360deg); }
}

.pwa-install-icon {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  padding: 2px;
  background: var(--brand-grad);
  box-shadow: var(--shadow-glow);
  animation: pwa-pulse 2.6s ease-in-out infinite;
}

.pwa-install-icon img {
  width: 100%;
  height: 100%;
  border-radius: 11px;
  display: block;
  background: var(--bg-elevated);
  object-fit: cover;
}

@keyframes pwa-pulse {
  0%, 100% { box-shadow: var(--shadow-glow); }
  50% { box-shadow: 0 0 0 6px rgba(217, 171, 85, 0.10), var(--shadow-glow); }
}

.pwa-install-copy {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pwa-install-copy strong {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: 14px;
  color: var(--ink);
  letter-spacing: -0.01em;
}

.pwa-install-copy span {
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pwa-install-actions {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.pwa-install-btn {
  border: none;
  border-radius: var(--radius-sm);
  padding: 9px 14px;
  font-size: 12.5px;
  font-weight: 700;
  color: #1c1912;
  background: var(--brand-grad);
  box-shadow: var(--shadow-glow);
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  white-space: nowrap;
}

.pwa-install-btn:hover {
  transform: translateY(-1px) scale(1.02);
  box-shadow: 0 12px 30px -10px var(--brand-glow);
}

.pwa-install-btn:active {
  transform: translateY(0) scale(0.98);
}

.pwa-install-close {
  border: none;
  background: transparent;
  color: var(--ink-soft);
  font-size: 20px;
  line-height: 1;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s ease, color 0.15s ease;
}

.pwa-install-close:hover {
  background: var(--panel-2);
  color: var(--ink);
}

@media (max-width: 480px) {
  .pwa-install-banner {
    bottom: 12px;
    padding: 12px;
    gap: 10px;
  }
  .pwa-install-copy span { display: none; }
}

