/* ============================================================
   Retuiled — hoja de estilos
   Vidrio: negro violeta con resplandor ambiental y superficies
   translucidas, dirigido con el usuario el 06-08 (opcion "D" de
   la tanda de UI en clave Apple: Wallet / Fitness / visionOS).
   ============================================================ */

:root {
  color-scheme: dark;
  --bg: #0c0a14;
  /* --surface/-2/-3 se quedan OPACOS a proposito: los usan la cabecera
     sticky de tabla (th) y la columna congelada (td.col-anchor), que
     necesitan un fondo solido o el contenido se transparenta por debajo
     al hacer scroll (bug ya documentado antes de esta pasada). El vidrio
     va encima, en .card/.kpi/.table-card/.modal/.sidebar, con --glass-*. */
  --surface: #17131f;
  --surface-2: #1d1828;
  --surface-3: #251f34;
  --border: #2b2440;
  --border-soft: #221c34;
  --text: #f1eef9;
  --muted: #a29bc0;
  /* Verificado contra el fondo real de una tarjeta de vidrio (translucida
     sobre el resplandor, no sobre --surface plano): en el punto mas claro
     del resplandor sigue dando ~4,6:1, AA para texto pequeño. */
  --muted-2: #9891b8;
  --accent: #8f7bff;
  --accent-soft: rgba(143, 123, 255, 0.16);
  --accent-2: #b9aaff;
  /* Semaforo sin tocar: ya autiado el 08-02 (verde/rojo emparejados en
     brillo, --muted-2 corregido). Cambiar de sitio el vidrio no reabre esa
     auditoria. */
  --green: #26b981;
  --green-soft: rgba(47, 211, 148, 0.13);
  --red: #ff5d7a;
  --red-soft: rgba(255, 93, 122, 0.12);
  --yellow: #f2b94b;
  --yellow-soft: rgba(242, 185, 75, 0.13);
  --blue: #58a6ff;
  --blue-soft: rgba(88, 166, 255, 0.13);
  /* Radio de cristal: 4px era radio de instrumento (deliberado en su
     momento). El vidrio pide esquina mas generosa para leerse como panel
     flotante, no como chapa metalica. */
  --radius: 16px;
  --radius-sm: 10px;
  --sidebar-w: 236px;
  /* Las superficies ahora SON el material (vidrio esmerilado), no una
     tarjeta plana con sombra corta: el shadow vuelve a las tarjetas (antes
     solo lo llevaban las capas flotantes) porque un panel de cristal sin
     ninguna sombra no lee como si flotara sobre el resplandor. */
  --shadow: 0 10px 30px rgba(8, 5, 20, 0.5);
  /* Material de vidrio: fondo translucido + desenfoque + borde de luz de
     1px. Solo en contenedores que NO son ellos mismos el contenedor de
     scroll con celdas sticky (ver nota de --surface arriba). */
  --glass-bg: rgba(255, 255, 255, 0.055);
  --glass-border: rgba(255, 255, 255, 0.1);
  --glass-blur: saturate(160%) blur(20px);
  /* Fuente para todo dato numerico verificable (dinero, SKU, fechas, %):
     alineacion por digito y distincion clara de 1.240,00 vs 124,00. */
  --font-num: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
  font-size: 15px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

* { box-sizing: border-box; }

html { -webkit-tap-highlight-color: transparent; }
button, a, .nav-link, input, select, textarea {
  touch-action: manipulation;
}

/* Anillo de foco generico para todo lo interactivo. --accent-2 en vez de
   --accent porque --accent (#8f7bff) tiene poco margen de contraste para
   un indicador de foco; --accent-2 (#b9aaff) es mas claro. */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

/* Saltar a #view: oculto hasta que se enfoca con teclado (primer Tab de la pagina). */
.skip-link {
  position: absolute;
  top: -40px;
  left: 8px;
  z-index: 1000;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  text-decoration: none;
}
.skip-link:focus-visible {
  top: 8px;
}

html, body {
  margin: 0;
  padding: 0;
  /* Resplandor ambiental: dos focos violeta, fijos respecto al viewport
     (no al contenido) para que no se note el scroll moviendolos. Es lo que
     el vidrio de encima (sidebar, tarjetas, tabla) deja entrever. */
  background-color: var(--bg);
  background-image:
    radial-gradient(900px 480px at 12% -10%, rgba(148, 120, 255, 0.28), transparent 60%),
    radial-gradient(760px 460px at 104% 8%, rgba(90, 66, 210, 0.22), transparent 62%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; color: inherit; }
input, select, textarea { font: inherit; }

a { color: inherit; text-decoration: none; }

/* ---------- Layout ---------- */

.app { display: flex; min-height: 100vh; }

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--sidebar-w);
  background: rgba(23, 18, 36, 0.6);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-right: 1px solid var(--glass-border);
  display: flex;
  flex-direction: column;
  padding: 18px 12px 14px;
  z-index: 20;
}

.main {
  flex: 1;
  margin-left: var(--sidebar-w);
  min-width: 0;
}

.view {
  max-width: 1180px;
  margin: 0 auto;
  padding: 28px 32px 60px;
}

/* ---------- Marca / sidebar ---------- */

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 18px;
}

.brand-mark {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--accent) 0%, #6a4cf5 100%);
  color: #fff;
  font-weight: 800;
  font-size: 18px;
  display: grid;
  place-items: center;
  box-shadow: 0 4px 16px rgba(143, 123, 255, 0.4);
  flex: none;
}

.brand-name {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.2px;
  flex: 1;
}

/* ---------- Campana de avisos ---------- */

.bell-btn {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  flex: none;
}
.bell-btn:hover { background: var(--surface-2); color: var(--text); }
.bell-btn .nav-ico svg { width: 17px; height: 17px; }

.bell-badge {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 999px;
  background: var(--red);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  display: grid;
  place-items: center;
  line-height: 1;
}

/* Bloque "Qué hacer hoy" del Dashboard. Reaprovecha .alert-row del panel de
   avisos, asi que un mismo aviso se ve igual en los dos sitios. */
.todo-hoy { margin-bottom: 14px; }
.todo-hoy-lista { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; }
.todo-hoy .alert-row { border-radius: 10px; }
.todo-hoy-ok { border-color: var(--border-soft); }

.alerts-panel {
  position: absolute;
  top: 58px;
  left: 12px;
  width: 300px;
  max-height: 60vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(23, 18, 36, 0.72);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 50;
}
.alerts-panel-head {
  padding: 12px 14px;
  font-weight: 700;
  font-size: 13px;
  border-bottom: 1px solid var(--border-soft);
}
.alerts-panel-body { display: flex; flex-direction: column; }

.alert-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border-soft);
  color: var(--text);
}
.alert-row:last-child { border-bottom: none; }
/* Fila de aviso + su boton de "marcar leido", que no puede ir dentro del <a>. */
.alert-item { display: flex; align-items: stretch; border-bottom: 1px solid var(--border-soft); }
.alert-item:last-child { border-bottom: none; }
.alert-item .alert-row { flex: 1; border-bottom: none; }
.alert-dismiss { flex: none; align-self: center; margin-right: 8px; opacity: .5; }
.alert-dismiss:hover { opacity: 1; }
.alerts-head { display: flex; justify-content: flex-end; padding: 8px 12px 4px; }
.alert-row:hover { background: var(--surface-2); }
.alert-ico { flex: none; margin-top: 1px; }
.alert-ico svg { width: 15px; height: 15px; }
.alert-row.alert-danger .alert-ico { color: var(--red); }
.alert-row.alert-warn .alert-ico { color: var(--yellow); }
.alert-row.alert-info .alert-ico { color: var(--blue); }
.alert-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.alert-title { font-size: 13px; font-weight: 600; }
.alert-sub { font-size: 12px; color: var(--muted-2); }
.alert-empty { padding: 20px 14px; text-align: center; color: var(--muted-2); font-size: 13px; }

.nav { display: flex; flex-direction: column; gap: 3px; flex: 1; }
.nav-spacer { flex: 1; }

.nav-link {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-weight: 500;
  font-size: 14px;
  transition: background 0.15s, color 0.15s;
}

.nav-link:hover { background: var(--surface-2); color: var(--text); }

.nav-link.active {
  background: var(--accent-soft);
  color: var(--accent-2);
}

.nav-ico { display: inline-flex; width: 19px; height: 19px; flex: none; }
.nav-ico svg { width: 19px; height: 19px; }

/* Menu de idioma: mismo lenguaje visual que el panel de avisos (.alerts-panel).
   Se ancla abajo porque el boton vive al pie de la barra lateral. */
.lang-menu {
  position: fixed;
  bottom: 96px;
  left: 12px;
  min-width: 150px;
  background: rgba(23, 18, 36, 0.72);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 60;
  overflow: hidden;
  padding: 4px;
}
.lang-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}
.lang-menu button:hover { background: var(--surface-2); }
.lang-menu button.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

.lang-switch {
  display: flex;
  gap: 4px;
  padding: 4px 12px 8px;
}

.lang-switch button {
  flex: 1;
  padding: 6px 0;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: transparent;
  color: var(--muted-2);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.lang-switch button.active {
  background: var(--accent, #8f7bff);
  border-color: var(--accent, #8f7bff);
  color: #fff;
}

.sidebar-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 12px 2px;
  color: var(--muted-2);
  font-size: 12px;
  border-top: 1px solid var(--border-soft);
}

.sidebar-foot .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--green);
  flex: none;
}

/* ---------- Cabecera de página ---------- */

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.page-head h1 { margin: 0 0 4px; font-size: 24px; font-weight: 700; }
.page-head p { margin: 0; color: var(--muted); font-size: 14px; }
/* flex-wrap es lo que evita que la fila de botones ensanche la pagina entera
   en movil: sin el, .page-actions medía 448px dentro de 313 disponibles y
   forzaba scroll horizontal en TODA la app, no solo en la cabecera. La
   cabecera (.page-head) ya envolvia; sus botones no. */
.page-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------- Botones ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* Fondo y color de texto AQUÍ, no solo en las variantes: un .btn sin
     variante caía al botón por defecto del navegador y salía como un
     rectángulo gris con el texto ilegible sobre el tema oscuro. Pasó en
     dos sitios reales (Registrar horas, y el toggle de una cuenta activa)
     y no lo vio nadie. Las variantes de abajo lo pisan igual que antes. */
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 9px 16px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: filter 0.15s, background 0.15s, border-color 0.15s;
  white-space: nowrap;
}

.btn svg { width: 16px; height: 16px; }

.btn.primary {
  background: linear-gradient(135deg, var(--accent) 0%, #6a4cf5 100%);
  color: #fff;
  box-shadow: 0 4px 16px rgba(143, 123, 255, 0.32);
}
.btn.primary:hover { filter: brightness(1.1); }

.btn.ghost {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}
.btn.ghost:hover { background: var(--surface-3); }

.btn.danger {
  background: var(--red-soft);
  color: var(--red);
  border-color: transparent;
}
.btn.danger:hover { background: rgba(255, 93, 122, 0.2); }

.btn.btn-sm { padding: 6px 12px; font-size: 12px; }

.status-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; display: inline-block; }
.status-dot.on { background: var(--green); }
.status-dot.off { background: var(--muted-2); }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
.icon-btn.danger:hover { background: var(--red-soft); color: var(--red); }
.icon-btn svg { width: 16px; height: 16px; }

/* ---------- Tarjetas ---------- */

.card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
}

.card-title {
  margin: 0 0 14px;
  font-size: 15px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 6px;
}
.card-title > span:first-child { white-space: nowrap; }

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 14px;
}

.kpi {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: var(--shadow);
}

.kpi-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
}

.kpi-ico {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  flex: none;
}
.kpi-ico svg { width: 16px; height: 16px; }
.kpi-ico.violet { background: var(--accent-soft); color: var(--accent-2); }
.kpi-ico.green { background: var(--green-soft); color: var(--green); }
.kpi-ico.yellow { background: var(--yellow-soft); color: var(--yellow); }
.kpi-ico.blue { background: var(--blue-soft); color: var(--blue); }
.kpi-ico.red { background: var(--red-soft); color: var(--red); }

.kpi-value { font-size: 24px; font-weight: 700; letter-spacing: -0.3px; }
.kpi-sub { color: var(--muted-2); font-size: 12px; }
.kpi-sub b { color: var(--green); font-weight: 600; }
.kpi-sub b.neg { color: var(--red); }

.dash-grid {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 14px;
}

/* Variantes de columnas. Antes iban como estilo EN LINEA desde views.js, y eso
   ganaba a las @media de mas abajo: en movil se quedaban 3 columnas metidas a
   la fuerza en 375px y la pagina entera se desplazaba en horizontal. Como
   clases, las @media vuelven a mandar y en movil caen a una sola columna. */
.kpi-grid-3 { grid-template-columns: repeat(3, 1fr); }
/* El Dashboard tiene 5 KPIs: con la rejilla de 4 el quinto ("Velocidad de
   capital") caia solo en su propia fila. Mismo caso que se arreglo el 25-07
   en Publicidad. En escritorio caben los 5; en 2 columnas el ultimo ocupa
   la fila entera para que lea como resumen, no como huerfano. */
.kpi-grid-5 { grid-template-columns: repeat(5, 1fr); }
/* Dashboard paso a 6 KPIs el 07-08 (margen por hora, P-11). Sin caso
   orfano que arreglar como el de arriba: 6 es par, cae limpio en las
   2 columnas de los @media de mas abajo. */
.kpi-grid-6 { grid-template-columns: repeat(6, 1fr); }
/* Inventario paso a 7 KPIs el 30-08 (sin fotos / sin tasar / listo para
   catalogo / antiguedad media): las tres cifras de dinero solas no decian que
   BLOQUEA publicar, que es lo que se mira al entrar. Misma convencion que
   arriba: N KPIs, N columnas. */
.kpi-grid-7 { grid-template-columns: repeat(7, 1fr); }
.dash-grid-2 { grid-template-columns: 1fr 1fr; }

/* ---------- Selector de periodo del Dashboard ---------- */

.range-selector {
  display: flex;
  gap: 6px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}

.range-btn {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  padding: 7px 14px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.range-btn:hover { background: var(--surface-3); color: var(--text); }
.range-btn.active {
  background: var(--accent-soft);
  color: var(--accent-2);
  border-color: transparent;
}

/* ---------- Comparativa vs periodo anterior ---------- */

.delta-badge { font-size: 11px; font-weight: 700; }
.delta-badge.delta-pos { color: var(--green); }
.delta-badge.delta-neg { color: var(--red); }
.delta-badge.delta-flat { color: var(--muted); }

/* ---------- Ficha de detalle de artículo ---------- */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 10px;
}
.back-link:hover { color: var(--text); }
.back-link svg { width: 14px; height: 14px; }

.detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

.detail-photo-main {
  width: 100%;
  max-height: 340px;
  object-fit: cover;
  border-radius: 12px;
  display: block;
  background: var(--surface-2);
}

.detail-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 18px;
}
.detail-fields > div { display: flex; flex-direction: column; gap: 5px; font-size: 13px; }

/* Historial de WhatsApp en la ficha de cliente (CRM fase 1). Burbujas
   simples: entrante a la izquierda (fondo neutro), saliente a la derecha
   (fondo del acento), sin más adorno — es un log de lectura, no un chat
   con el que se interactúa desde aquí. */
.wa-history {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 360px;
  overflow-y: auto;
}
.wa-msg {
  max-width: 75%;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  font-size: 13px;
}
.wa-msg-in { align-self: flex-start; background: var(--surface-3); }
.wa-msg-out { align-self: flex-end; background: var(--accent-soft); }
.wa-msg-body { white-space: pre-wrap; word-break: break-word; }
.wa-msg-meta { margin-top: 4px; font-size: 11px; color: var(--muted); }
.detail-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* ---------- Rejilla de gráficas adicionales del Dashboard ---------- */

.charts-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 14px;
}

.chart-sm { width: 100%; height: 160px; display: block; }
.chart-donut { height: 130px; }

.stacked-bar {
  display: flex;
  width: 100%;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--surface-2);
}
.stacked-bar > div { height: 100%; }
.stacked-bar-empty { width: 100%; height: 100%; }

.donut-legend {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 12px;
  font-size: 12px;
}
.donut-legend-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  color: var(--muted);
}
.donut-legend-row .name {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  font-weight: 500;
}
.donut-legend-row .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.chart-legend {
  display: flex;
  gap: 16px;
  font-size: 12px;
  color: var(--muted);
}
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend i {
  width: 10px; height: 10px; border-radius: 3px; display: inline-block;
}

#salesChart { width: 100%; height: 260px; display: block; }

/* ---------- Listas del dashboard ---------- */

.mini-list { display: flex; flex-direction: column; }

.mini-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}
.mini-row:last-child { border-bottom: none; }

.mini-main { min-width: 0; }
.mini-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-sub { color: var(--muted-2); font-size: 12px; margin-top: 2px; }
.mini-val { font-weight: 700; white-space: nowrap; }
.mini-val.pos { color: var(--green); }
.mini-val.neg { color: var(--red); }

/* ---------- Paginación ---------- */

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--border, rgba(255,255,255,0.08));
}

/* ---------- Toolbar de listados ---------- */

.toolbar {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
  flex-wrap: wrap;
  align-items: center;
}

.search-box {
  position: relative;
  flex: 1;
  min-width: 200px;
  max-width: 340px;
}

.search-box svg {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--muted-2);
  pointer-events: none;
}

.search-box input[type="text"], .search-box input[type="search"] { padding-left: 36px; }

/* type="search" entro en la lista el 30-08: searchBox() lleva pintando
   <input type="search"> desde hace tiempo y esta regla no lo cubria, asi que
   los 10 buscadores de la app salian con el estilo por defecto del navegador
   — 175px de ancho, 2px de padding y la lupa encima del texto. */
input[type="text"], input[type="number"], input[type="date"],
input[type="email"], input[type="url"], input[type="password"], input[type="search"], select, textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 9px 12px;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

input:focus, select:focus, textarea:focus {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 3px rgba(185, 170, 255, 0.18);
}

input::placeholder, textarea::placeholder { color: var(--muted-2); }

select { cursor: pointer; appearance: none; -webkit-appearance: none;
  /* Gris grabado a mano en el SVG porque un data-URI no puede leer
     var(--muted): actualizado a juego con el --muted nuevo (antes
     %238b93a8, el --muted del tema oscuro previo). */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23a29bc0' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}

.toolbar select { width: auto; }

input[type="date"] { color-scheme: dark; }

textarea { resize: vertical; min-height: 70px; }

/* ---------- Tablas ---------- */

.table-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  /* Antes overflow:hidden, que ademas de recortar esquinas rompia el
     position:sticky de la cabecera (creaba su propio contenedor de scroll
     recortado). Con radio grande el corte de esquina de la tabla se nota
     mas que antes; asumido, es el mismo trade-off que ya existia. th y
     td.col-anchor (mas abajo) fijan su PROPIO fondo opaco con --surface/
     --surface-2, independiente de este fondo translucido: por eso pueden
     convivir cabecera/columna solidas con cuerpo de tabla en vidrio. */
  /* `overflow: visible` de verdad, y NO el par `overflow-x:auto` +
     `overflow-y:visible` que habia aqui: por la misma regla que rompia el
     sticky de `.table-scroll` (si un eje del overflow no es visible, el OTRO
     computa a `auto`), esta caja llevaba recortando desde siempre. Lo que
     recortaba es el menu de "Columnas"/"Vistas", que cuelga de la barra de
     arriba y cae DENTRO de la tarjeta: medido el 30-08 en Chrome con una
     tabla de 2 filas -- 256 px de menu fuera de la caja y la ultima opcion
     sin poder clicarse (`elementFromPoint` no devolvia nada ahi).
     El scroll horizontal de la tabla no se pierde con esto: lo hace
     `.table-scroll`, que es quien tiene el overflow de verdad, y con el la
     tabla de 920px sigue sin desbordar la tarjeta (comprobado a 800 y 900 px
     de ventana). */
  overflow: visible;
  box-shadow: var(--shadow);
}

/* La cabecera sticky NO funcionaba, y el motivo es una regla del propio CSS que
   parece un detalle y no lo es: si un eje del overflow no es visible, el OTRO
   deja de serlo tambien (`visible` computa a `auto`). O sea que este
   `overflow-y: visible` de aqui, escrito a proposito para no romper el sticky,
   estaba computando a `auto` desde el primer dia — comprobado en vivo el 30-08:
   `getComputedStyle(.table-scroll).overflowY` decia `auto`. Con eso, el `th`
   sticky se pegaba a ESTA caja en vez de a la ventana, y como la caja media
   exactamente lo que su contenido (6990px de alto, 6990 de scroll) nunca hacia
   scroll vertical: no habia de donde pegarse, y la cabecera se iba con la
   pagina. El comentario de `.table-card` de arriba dice que el `overflow-x:auto`
   protegia el sticky; no era verdad, por lo mismo.

   El arreglo es acotar la caja: en cuanto tiene un alto maximo, es ELLA la que
   scrollea y el sticky se agarra a su borde de arriba.

   El 140px del calc no es estetico, es la cuenta: al hacer scroll del todo la
   cabecera queda a `140 - (lo que haya debajo de la tabla)` de la ventana, asi
   que el margen tiene que superar el "debajo" mas grande de todas las vistas.
   Medido en las nueve: 61px en casi todas y 118 en Auditoria. Con 140 la
   cabecera cae a 79px del borde en las normales y a 22 en Auditoria, visible en
   todas. Bajarlo a 60 la sube del todo en Inventario pero la esconde (-1px) —
   probado. */
.table-scroll { overflow: auto; max-height: calc(100vh - 140px); }

table { width: 100%; min-width: 920px; border-collapse: collapse; font-size: 13px; }

/* max-width: sin el, una sola celda de texto libre revienta su columna y echa
   de la pantalla a todas las de detras. Pasaba de verdad: la talla de RT-0082
   son 190 caracteres ("34/32 en etiqueta / medidos W34 L31 (45 cm de cintura en
   plano…") y con nowrap estiraba la columna Talla a 1505px — de doce columnas
   se veian cinco. El tope reparte el problema en vez de propagarlo: esa celda
   se corta con puntos suspensivos y el resto de la tabla se ve. */
td { white-space: nowrap; max-width: 320px; overflow: hidden; text-overflow: ellipsis; }
td.cell-wrap, td:has(.cell-main), td:has(.cell-sub) { white-space: normal; }

/* Tablas dentro de un modal (p. ej. la revisión de la tasación): el
   min-width de 920px de las tablas de datos las desborda en el ancho de un
   modal y esconde la columna de valores tras un scroll horizontal. Aquí
   deben ajustarse al ancho disponible y poder partir línea. */
.modal table { min-width: 0; }
.modal td { white-space: normal; max-width: none; }

th {
  text-align: left;
  padding: 8px 12px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  background: var(--surface-2);
  white-space: nowrap;
  /* inset en vez de border-bottom: el borde de una celda sticky no se pinta
     al hacer scroll con border-bottom normal (el fondo de la fila siguiente
     lo tapa). Con box-shadow inset se queda encima siempre. */
  box-shadow: inset 0 -1px 0 var(--border);
  position: sticky;
  top: 0;
  z-index: 2;
}

th.sortable { user-select: none; padding: 0; }
th.sortable:hover { color: var(--text); }
/* El boton lleva el padding que antes tenia el th, para que el area clicable
   siga siendo la celda entera. Todo lo demas se hereda: asi th.num sigue
   alineado a la derecha y con la fuente de numeros, sin duplicar reglas. */
th.sortable > button {
  width: 100%;
  padding: 8px 12px;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  white-space: nowrap;
  cursor: pointer;
}

td {
  /* Antes 12px 16px: ~14 filas por pantalla en un portatil. Con 8px 12px caben
     ~20, un 43% mas de contexto en cada mirada, que es la diferencia real entre
     un ERP que se lee de un vistazo y uno que obliga a hacer scroll. */
  padding: 8px 12px;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background 0.12s; }
/* Zebra fuera: al 1.8% era invisible (no separaba nada) pero si ensuciaba el
   hover, porque una fila par en hover apenas se distinguia de una impar en
   hover. Ahora solo hay hover, mas marcado, + franja de acento en la columna
   ancla: un marcador de posicion mucho mas fuerte que un fondo, y que funciona
   igual con cualquier densidad. */
tbody tr:hover { background: rgba(255, 255, 255, 0.055); }

/* Franja de acento en la fila activa: marcador de posicion mas fuerte que un
   fondo, y que se lee igual con cualquier densidad. Sustituye al zebra. */
tbody tr:hover td:first-child { box-shadow: inset 2px 0 0 var(--accent); }

/* Columna ancla congelada. Con min-width:920px, al mirar "Beneficio estimado"
   ya no se veia de que articulo se hablaba. La clase .col-anchor la pone
   js/table-enhance.js sobre la celda Y su cabecera (el <th> no se puede
   seleccionar en CSS: no contiene .cell-main, y sin congelarlo aparecia la
   columna equivocada encima del nombre congelado). El background es obligatorio
   o el resto de la fila se transparenta por debajo al hacer scroll. */
td.col-anchor, th.col-anchor {
  position: sticky;
  left: 0;
  z-index: 1;
  box-shadow: 1px 0 0 var(--border);
}
td.col-anchor { background: var(--surface); }
th.col-anchor { z-index: 3; background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--border), 1px 0 0 var(--border); }
tbody tr:hover td.col-anchor {
  background: var(--surface-2);
  box-shadow: inset 2px 0 0 var(--accent), 1px 0 0 var(--border);
}

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-num); }
td.actions { text-align: right; white-space: nowrap; }

/* ---------- Columnas a medida: ancho y visibilidad (js/table-enhance.js) ----------
   Preferencia por tabla y por navegador, en localStorage. Mientras no se toca
   nada no hay ninguna regla activa aqui y la tabla se reparte por contenido
   como siempre. */

table.cols-sized { table-layout: fixed; }
/* Con el ancho fijado hay que decidir que pasa con lo que no cabe: elipsis en
   las celdas de una linea. Las que ya envolvian (.cell-main/.cell-sub, con
   white-space:normal) siguen partiendo linea, que es lo que quieres al
   estrechar la columna del producto. */
table.cols-sized td { overflow: hidden; text-overflow: ellipsis; }

th.col-hidden, td.col-hidden { display: none; }

/* El tirador va DENTRO de su <th>, pegado al borde derecho, y no a caballo
   sobre el borde: las cabeceras son sticky con el mismo z-index, asi que la
   de la columna siguiente pinta encima (va despues en el DOM) y se comia la
   mitad derecha del area agarrable — medido en vivo el 30-08, un tiron justo
   en el borde no hacia nada. Por dentro si manda el z-index de aqui, que es
   lo que hace falta para ganarle al boton de ordenar: ocupan el mismo sitio y
   sin esto tirar de la columna la ordenaba. El <th> ya es position:sticky,
   asi que sirve de referencia sin tocarlo. */
.col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 10px;
  height: 100%;
  z-index: 4;
  cursor: col-resize;
  touch-action: none;
}
.col-resizer::after {
  content: "";
  position: absolute;
  top: 25%;
  bottom: 25%;
  right: 0;
  width: 1px;
  background: var(--border);
}
.col-resizer:hover::after { top: 0; bottom: 0; width: 2px; background: var(--accent); }
/* Mientras se arrastra manda el cursor de toda la pagina, y no se selecciona
   media tabla de texto por el camino. */
body.col-resizing { cursor: col-resize; user-select: none; }

/* Reordenar columnas arrastrando la cabecera. Va DESPUES de th.col-anchor a
   proposito: misma especificidad, gana el ultimo, y la marca de destino tiene
   que verse tambien sobre la columna congelada. Se conserva el inset de abajo
   porque es el borde de la cabecera sticky, no decoracion. */
th.col-dragging { opacity: 0.4; }
th.col-drop-before { box-shadow: inset 0 -1px 0 var(--border), inset 3px 0 0 var(--accent); }
th.col-drop-after { box-shadow: inset 0 -1px 0 var(--border), inset -3px 0 0 var(--accent); }
body.col-reordering { cursor: grabbing; user-select: none; }

/* El fondo opaco, el z-index y el translateZ NO son decoracion: tapan un fallo
   de composicion de Chrome que aparecio al acotar .table-scroll. La celda
   sticky de la columna ancla se pinta FUERA del recorte de la caja y asoma en
   la franja que hay entre el borde de la tarjeta y el borde de la caja — que es
   justo esta barra. Se veia como un renglon fantasma del articulo de debajo,
   encima de la cabecera, y solo en algunas posiciones del scroll.
   Descartado por medicion, no por intuicion: no es el backdrop-filter de la
   tarjeta (quitarlo no lo arregla), ni el sticky de la celda (ponerla static
   tampoco), ni `contain: paint` ni `isolation: isolate` sobre la caja. Lo unico
   que lo tapa es una capa propia por encima: fondo opaco + z-index + una
   promocion a capa (translateZ). El hit-test confirma que ahi no hay ningun
   elemento: son pixeles sueltos del compositor. */
.cols-bar {
  position: relative;
  z-index: 6;
  transform: translateZ(0);
  background: var(--surface-2);
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 8px 10px 0;
}

/* Cada boton de la barra en su hueco: el menu se cuelga del hueco y cae debajo
   de SU boton. Colgado de la barra, los dos menus se abrian en el mismo sitio. */
.cols-bar__slot { position: relative; }

.cols-menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 20;
  min-width: 210px;
  padding: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
.cols-menu label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}
.cols-menu label:hover { background: var(--surface); }
.cols-menu input[type="checkbox"] { width: auto; margin: 0; }
.cols-menu__reset { width: 100%; margin-top: 6px; }

/* Vistas guardadas: nombre a la izquierda (aplica) y papelera a la derecha. */
.cols-menu__view { display: flex; align-items: center; gap: 2px; }
.cols-menu__apply {
  flex: 1;
  min-width: 0;
  text-align: left;
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 6px 8px;
  border-radius: 6px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cols-menu__apply:hover { background: var(--surface); }
.cols-menu__empty { margin: 4px 8px 8px; color: var(--muted-2); font-size: 12px; }
/* La estrella de "predeterminada": apagada es un contorno del color del texto
   secundario, encendida se llena y coge el amarillo del semaforo. */
.cols-menu__star { font-size: 15px; line-height: 1; color: var(--muted-2); }
.cols-menu__star:hover { color: var(--text); }
.cols-menu__star.activa { color: var(--yellow); }

/* Todo dato numerico verificable comparte fuente y alineacion por digito,
   no solo las celdas de tabla explicitamente marcadas .num. */
.kpi-value, .mini-val, .delta-badge, .goal-text, .tax-result b,
.stats-inline b, .quality-count, .score-help__table td:first-child {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
}

.cell-main {
  font-weight: 600;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-width: 180px;
  max-width: 340px;
}
a.cell-main { cursor: pointer; }
a.cell-main:hover { text-decoration: underline; }
.cell-sub { color: var(--muted-2); font-size: 12px; margin-top: 2px; }

/* Rentabilidad: el color NO puede ser el unico canal. Con deuteranopia (~8% de
   los hombres) verde y rojo son el mismo tono y esta columna no comunicaba nada.
   Se marca con un triangulo, NO con +/-: el render es inconsistente (views.js
   1641 y 2181 ya anteponen "+" a mano, 1642/1723/1725 no, y fmtMoney() ya trae
   el "-" en los negativos), asi que un ::before con signo daria "++12,00" en un
   sitio y "--12,00" en otro. El triangulo no colisiona con ninguno de los dos. */
.profit-pos { color: var(--green); font-weight: 700; }
.profit-neg { color: var(--red); font-weight: 700; }
.profit-pos::before { content: "\25B2\00A0"; font-size: 9px; vertical-align: 1px; }
.profit-neg::before { content: "\25BC\00A0"; font-size: 9px; vertical-align: 1px; }

/* ---------- Antigüedad de stock ---------- */

.aging-warm { color: var(--yellow); font-weight: 600; }
.aging-hot { color: var(--red); font-weight: 700; }

/* ---------- Badges ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge.stock { background: var(--green-soft); color: var(--green); }
.badge.listed { background: var(--yellow-soft); color: var(--yellow); }
.badge.sold { background: var(--accent-soft); color: var(--accent-2); }
.badge.plain { background: var(--surface-3); color: var(--muted); }
.badge.plain::before { display: none; }

/* Aviso de artículo vendido en Shopify pendiente de retirar de otras
   plataformas (Vinted, Wallapop...). Reutiliza el tono --red, igual
   que .aging-hot, porque es una acción urgente. */
.badge.pending-delist-badge { background: var(--red-soft); color: var(--red); }

/* Etapas del pedido en Ventas (confirmado -> preparado -> enviado ->
   recibido -> cerrado), un degradado de "recién confirmado" (azul) a
   "cerrado" (verde), pasando por los pasos intermedios en ámbar/violeta. */
.badge.fulfillment-confirmado { background: var(--blue-soft); color: var(--blue); }
.badge.fulfillment-preparado { background: var(--yellow-soft); color: var(--yellow); }
.badge.fulfillment-enviado { background: var(--accent-soft); color: var(--accent-2); }
.badge.fulfillment-recibido { background: var(--yellow-soft); color: var(--yellow); }
.badge.fulfillment-cerrado { background: var(--green-soft); color: var(--green); }
.badge.fulfillment-devuelto { background: var(--red-soft); color: var(--red); }

.pending-delist-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--red);
  border-radius: var(--radius);
  padding: 16px 20px;
  margin: 0 0 20px 0;
}
.pending-delist-icon { color: var(--red); flex-shrink: 0; margin-top: 2px; }
.pending-delist-icon svg { width: 20px; height: 20px; }
.pending-delist-body { flex: 1; }
.pending-delist-title { color: var(--text); font-weight: 600; margin-bottom: 8px; }
.pending-delist-platforms { display: flex; gap: 8px; flex-wrap: wrap; }
.delist-platform-link {
  font-size: 13px;
  padding: 3px 10px;
  border-radius: var(--radius-sm);
  background: var(--red-soft);
  color: var(--red);
  text-decoration: none;
  border: 1px solid transparent;
}
.delist-platform-link:hover { border-color: var(--red); }



/* ---------- Chip de plataforma (color + monograma) ---------- */

.platform-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.platform-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  flex: none;
}

/* ---------- SKU interno (para etiquetar el almacén físico) ---------- */

.internal-sku-badge {
  display: inline-block;
  font-family: ui-monospace, "SF Mono", "Roboto Mono", Consolas, monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--accent-2);
  background: var(--accent-soft);
  border-radius: 6px;
  padding: 3px 7px;
  white-space: nowrap;
}

/* ---------- Objetivo mensual (Dashboard) ---------- */

.goal-row { display: flex; align-items: center; gap: 16px; }
.goal-bar-track {
  flex: 1;
  height: 10px;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
}
.goal-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--green));
  transition: width 0.3s ease;
}
.goal-bar-fill.neg { background: var(--red); }
.goal-text { font-size: 13px; font-weight: 600; white-space: nowrap; }
.goal-text .muted { color: var(--muted-2); font-weight: 500; }

/* ---------- Chip de filtro (toggle) ---------- */

.toggle-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 8px 14px;
  white-space: nowrap;
}
.toggle-chip input { width: auto; margin: 0; }
.toggle-chip.active {
  color: var(--text);
  border-color: var(--yellow);
  background: var(--yellow-soft);
}

/* ---------- Vista de Impuestos ---------- */

.tax-disclaimer {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--yellow-soft);
  border: 1px solid rgba(242, 185, 75, 0.35);
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
}
.tax-disclaimer svg { width: 20px; height: 20px; color: var(--yellow); flex: none; margin-top: 1px; }

.year-label { font-weight: 700; font-size: 14px; padding: 0 6px; align-self: center; }

.tax-rows { display: flex; flex-direction: column; gap: 10px; }
.tax-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 13px;
  color: var(--muted);
}
.tax-row b { color: var(--text); font-weight: 700; }

.tax-result {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
}
.tax-result b { font-size: 18px; }
.tax-result.due { background: var(--red-soft); color: var(--red); }
.tax-result.ok { background: var(--green-soft); color: var(--green); }

/* ---------- Badge de estado clicable (Inventario) ---------- */

.badge-trigger {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  display: inline-flex;
  border-radius: 999px;
}
.badge-trigger:hover .badge { filter: brightness(1.18); }
.badge-trigger:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

.status-choice { display: flex; gap: 16px; margin-bottom: 14px; flex-wrap: wrap; }
.status-choice-opt { display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
.status-choice-opt input { width: auto; }

/* ---------- Miniaturas y galería de fotos ---------- */

.thumb {
  border-radius: 8px;
  object-fit: cover;
  display: block;
  cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
}

.thumb-empty { display: grid; place-items: center; color: var(--muted-2); }
.thumb-empty svg { width: 16px; height: 16px; }

.photo-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }

.photo-thumb-wrap { position: relative; width: 64px; height: 64px; }

.photo-thumb {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  display: block;
}

.photo-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 22px;
  height: 22px;
  background: var(--surface-3);
  border: 1px solid var(--border);
}
.photo-remove svg { width: 12px; height: 12px; }

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 10px;
}
.gallery-img { width: 100%; border-radius: 10px; display: block; }

/* ---------- Publicaciones (listados multi-plataforma) ---------- */

.listings-editor { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }

.listing-row {
  display: grid;
  grid-template-columns: 1fr 90px 1fr 140px auto;
  gap: 8px;
  align-items: center;
}

.shipping-checklist { display: flex; flex-direction: column; gap: 8px; }
.check-row { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; }
.check-row input { width: auto; margin: 0; }

.ship-progress {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--muted);
  border-radius: 999px;
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
.ship-progress svg { width: 12px; height: 12px; }
.ship-progress.done { color: var(--green); border-color: transparent; background: var(--green-soft); }

/* ---------- Calidad de datos (Ajustes) ---------- */

.quality-list { display: flex; flex-direction: column; }
.quality-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}
.quality-row:last-child { border-bottom: none; }
.quality-row.ok { color: var(--muted); }
.quality-row.warn { color: var(--text); }
.quality-count { font-weight: 700; }
.quality-row.ok .quality-count { color: var(--green); }
.quality-row.warn .quality-count { color: var(--yellow); }

/* ---------- Estado vacío ---------- */

.empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--muted);
}
.empty svg { width: 40px; height: 40px; color: var(--muted-2); margin-bottom: 10px; }
.empty h3 { margin: 0 0 6px; color: var(--text); font-size: 16px; }
.empty p { margin: 0 0 16px; font-size: 13px; }

/* ---------- Modales ---------- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(5, 6, 10, 0.72);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  display: grid;
  place-items: center;
  padding: 20px;
  z-index: 100;
  animation: fadeIn 0.15s ease;
}

.modal {
  /* Mas opaco que .card (0,72 vs el 0,055 del vidrio de tarjeta): un
     modal tapa texto denso y ya lleva el overlay oscuro detras, no
     necesita ver tanto a traves. */
  background: rgba(23, 18, 36, 0.82);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - 60px);
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: var(--shadow);
  animation: slideUp 0.18s ease;
}

.modal-wide { max-width: 640px; }

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 22px 0;
}
.modal-head h2 { margin: 0; font-size: 17px; }

.modal-body { padding: 18px 22px 22px; }

.draft-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--yellow-soft);
  border: 1px solid rgba(242, 185, 75, 0.35);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 12px;
  color: var(--text);
  margin-bottom: 16px;
}
.link-btn {
  background: none;
  border: none;
  color: var(--accent-2);
  font-weight: 700;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: underline;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

/* Rejilla de las cinco comprobaciones de autenticidad en el formulario del
   artículo: etiqueta + dos desplegables en una línea, nota corta debajo a
   todo el ancho (antes solo ocupaba la columna de la etiqueta, quedaba
   desalineada). En móvil se apila, que si no no cabe. */
.auth-grid { display: grid; gap: 8px; }
.auth-row { display: grid; grid-template-columns: 1fr 140px 1.4fr; gap: 8px; align-items: center; }
.auth-row__label { font-size: 13px; color: var(--muted); }
.auth-row > input { grid-column: 1 / -1; }

@media (max-width: 760px) {
  .auth-row { grid-template-columns: 1fr; gap: 4px; }
}

.field { display: flex; flex-direction: column; gap: 6px; }
.field.span2 { grid-column: 1 / -1; }
.field-label { font-size: 12px; font-weight: 600; color: var(--muted); }

/* ---------- Campos vacios: rojo sutil ----------
   Sirve para ver de un vistazo que falta por rellenar cuando se repasa un
   articulo a mano (p. ej. despues de darlo de alta desde el tasador, que no
   siempre trae color/material/condicion). SOLO PINTA: no bloquea el guardado
   ni cambia la validacion, porque hay campos que se dejan vacios a proposito.

   Sin JS a proposito:
   - :placeholder-shown se cumple exactamente cuando el campo esta vacio, y
     todos los campos de texto/numero del formulario llevan placeholder.
   - :has(option[value=""]:checked) coge los desplegables con la opcion vacia
     ("Sin categoria", "Sin asignar", "Sin especificar"...) seleccionada.
   - Los <input type="date"> nunca casan con :placeholder-shown (siempre
     tienen valor) y los desplegables sin opcion vacia (condicion, moneda,
     plataforma) tampoco se pintan nunca. Es lo que queremos.
   - Se apaga al enfocar el campo para no molestar mientras escribes.

   Si el navegador no soporta :has(), la regla del select se ignora sola y el
   resto sigue funcionando. */
.form-grid :is(input, textarea):not(:focus):placeholder-shown,
.form-grid select:not(:focus):has(option[value=""]:checked) {
  border-color: rgba(255, 93, 122, 0.42);
  background-color: var(--red-soft);
}

/* Excepcion: el tipo de cambio solo tiene sentido si la compra fue en libras.
   Con la moneda en EUR, vacio es lo CORRECTO, asi que no se marca (si no, la
   ficha de un articulo completo se quedaba con una casilla roja para siempre).
   ponytail: Chrome NO recalcula este :has() al cambiar la moneda con el
   formulario ya abierto (comprobado: el selector deja de casar pero el estilo
   se queda) — asi que si pasas de EUR a GBP sobre la marcha, el aviso rojo no
   aparece hasta reabrir el formulario. Se asume: el caso normal (compra en
   euros) queda bien, y quien elige GBP va a escribir el cambio a continuacion.
   Si algun dia molesta, la salida es marcar la clase desde app.js al cambiar
   la moneda, no mas CSS. */
.form-grid:has(select[name="purchaseCurrency"] option[value="EUR"]:checked)
  input[name="purchaseFxRate"]:placeholder-shown {
  border-color: var(--border);
  background-color: var(--surface-2);
}

.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

.confirm-text { color: var(--muted); font-size: 14px; line-height: 1.55; margin: 4px 0 0; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ---------- Toasts ---------- */

#toast-root {
  position: fixed;
  bottom: 22px;
  right: 22px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
}

.toast {
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 16px;
  font-size: 13px;
  font-weight: 500;
  box-shadow: var(--shadow);
  animation: slideUp 0.2s ease;
  display: flex;
  align-items: center;
  gap: 9px;
}
.toast.ok { border-left: 3px solid var(--green); }
.toast.err { border-left: 3px solid var(--red); }
.toast.warn { border-left: 3px solid var(--yellow); }

/* ---------- Ajustes ---------- */

.settings-stack { display: flex; flex-direction: column; gap: 14px; max-width: 640px; }

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}
.setting-row + .setting-row { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-soft); }
.setting-info h4 { margin: 0 0 3px; font-size: 14px; }
.setting-info p { margin: 0; color: var(--muted); font-size: 12px; max-width: 380px; line-height: 1.5; }
.setting-row select { width: 130px; }

.stats-inline { display: flex; gap: 22px; flex-wrap: wrap; }
.stats-inline div { font-size: 13px; color: var(--muted); }
.stats-inline b { display: block; color: var(--text); font-size: 18px; margin-bottom: 2px; }

/* mobile-nav es <nav>, display:block por defecto -- sin esto se veria
   siempre al pie de la pagina tambien en escritorio. Solo aparece (flex)
   dentro del @media de movil, mas abajo. */
.mobile-nav { display: none; }

/* ---------- Responsive ---------- */

@media (max-width: 1024px) {
  .kpi-grid, .kpi-grid-3, .kpi-grid-5, .kpi-grid-6, .kpi-grid-7 { grid-template-columns: repeat(2, 1fr); }
  /* Impares: el ultimo caeria solo en su fila. Mismo arreglo que el de 5. */
  .kpi-grid-5 > .kpi:last-child, .kpi-grid-7 > .kpi:last-child { grid-column: 1 / -1; }
  .dash-grid-2 { grid-template-columns: 1fr; }
  .dash-grid { grid-template-columns: 1fr; }
  .charts-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  /* La barra lateral plegada a 62px se comia el 17% del ancho de un iPhone
     de forma permanente y quedaba arriba a la izquierda, donde el pulgar no
     llega (auditoria de direccion de arte, seccion 39 de context/, 08-02).
     Se oculta entera y se sustituye por .mobile-nav, mas abajo. */
  .sidebar { display: none; }
  .main { margin-left: 0; }
  .view { padding: 20px 16px max(84px, calc(70px + env(safe-area-inset-bottom))); }
  /* Dos por fila, no una: el contenido de un KPI es cortisimo ("1", "280,06 €")
     y apilados de uno en uno se comian cuatro pantallas de scroll antes de
     llegar a la tabla, que es a lo que se entra. El icono se quita porque a
     media anchura compite con la cifra, que es el dato. */
  .kpi-grid, .kpi-grid-3, .kpi-grid-5, .kpi-grid-6, .kpi-grid-7 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .kpi { padding: 12px; }
  .kpi-ico { display: none; }
  .kpi-value { font-size: 18px; }
  .kpi-top { font-size: 12px; }
  .dash-grid-2 { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .listing-row { grid-template-columns: 1fr; }
  .charts-grid { grid-template-columns: 1fr; }
  .detail-grid { grid-template-columns: 1fr; }
  .detail-fields { grid-template-columns: 1fr; }
  /* En escritorio los titulos de tarjeta van en una sola linea a proposito
     (se arreglo asi una pasada de UI anterior), pero en movil ese nowrap
     empujaba la tarjeta mas alla de la pantalla y hacia que TODA la pagina
     se desplazara en horizontal. Aqui si deben poder partirse. */
  /* iOS hace zoom automatico al enfocar un campo con letra < 16px, y luego
     deja la pantalla descolocada. El formulario de alta tiene 22 campos: eran
     22 saltos por articulo. 16px lo evita, es el umbral exacto de Safari. */
  input, select, textarea { font-size: 16px; }

  /* Zonas tactiles: 30px es comodo con raton y pequeño con el dedo. Se suben
     los botones de icono y la campanita; el resto ya llegaba. */
  .icon-btn, .bell-btn { width: 40px; height: 40px; }
  /* La pastilla de estado del articulo se pulsa para cambiarlo y medía 22px de
     alto; el selector de idioma, 17px de ancho. Los dos son objetivos reales,
     no decoracion. */
  .badge-trigger { min-height: 34px; padding-top: 6px; padding-bottom: 6px; }
  /* La barra lateral se pliega a 62px en movil: dos botones de 40px uno al
     lado del otro NO caben y se salian sobre el contenido. Apilados si caben
     y siguen siendo comodos de pulsar. */
  /* Ya no hay dos botones que apilar: solo el que abre el menu. */
  .lang-switch button { min-height: 34px; }

  .card-title > span:first-child { white-space: normal; }

  /* Graficas que solo dicen algo con meses de historial: en movil se pliegan
     para no arrastrar por 18 bloques. Nada se pierde, se abren tocandolas. */
  details.grafica-larga > summary { cursor: pointer; }
  .alerts-panel { left: 8px; width: calc(100vw - 90px); max-width: 320px; }

  /* ---------- Barra de navegacion inferior (movil) ---------- */

  .mobile-nav {
    display: flex;
    position: fixed;
    inset: auto 0 0 0;
    background: rgba(23, 18, 36, 0.7);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border-top: 1px solid var(--glass-border);
    padding: 4px 2px max(4px, env(safe-area-inset-bottom));
    z-index: 30;
  }
  .mobile-nav > a, .mobile-nav > button {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 7px 2px;
    border-radius: var(--radius-sm);
    background: none;
    border: none;
    color: var(--muted);
    font-size: 10px;
    text-align: center;
    cursor: pointer;
  }
  .mobile-nav .nav-ico, .mobile-nav .nav-ico svg { width: 20px; height: 20px; }
  .mobile-nav .nav-label { display: block; white-space: nowrap; }
  .mobile-nav > a.active { color: var(--accent-2); }

  .mobile-more-sheet[hidden] { display: none; }
  .mobile-more-sheet {
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: calc(64px + max(4px, env(safe-area-inset-bottom)));
    background: rgba(29, 24, 40, 0.85);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 6px;
    max-height: 60vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    z-index: 31;
  }
  .mobile-more-sheet .nav-link { padding: 11px 12px; }

  /* ---------- Tablas -> tarjetas ----------
     Las tablas llevan min-width:920px, asi que en una pantalla de 375px eran
     scroll horizontal en TODAS las vistas. Encogerlas no es la salida (las
     columnas quedan ilegibles): por debajo de 760px cada fila pasa a tarjeta y
     cada valor lleva delante el nombre de su columna, que estampa
     js/table-enhance.js leyendo el propio <thead>. */
  .table-card { overflow: visible; border: none; background: none; }
  .table-scroll { overflow: visible; max-height: none; }
  table { min-width: 0; display: block; }
  thead { display: none; }
  tbody { display: block; }

  tbody tr {
    display: block;
    background: var(--surface);
    border: 1px solid var(--border-soft);
    border-radius: var(--radius);
    margin-bottom: 8px;
    padding: 2px 0;
  }
  tbody tr:hover { background: var(--surface); }

  tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: auto;
    padding: 6px 12px;
    border-bottom: none;
    white-space: normal;
    text-align: left;
    /* El `max-width: 320px` de `td` (puesto el 30-08 para que una talla de 190
       caracteres no reviente su columna) no tiene sentido cuando la fila YA no
       es una fila sino una tarjeta: aqui la celda ocupa el ancho de la tarjeta,
       y con el tope quedaba clavada en 320 px en cualquier movil -- 180 px de
       hueco muerto a la derecha en una pantalla de 500, y el valor partiendo
       linea sin necesidad (medido: "Producto" pasaba de 28 a 44 px de alto).
       El recorte con elipsis tampoco aplica: aqui el texto envuelve. */
    max-width: none;
    overflow: visible;
  }
  /* El congelado no aplica cuando ya no hay scroll horizontal. */
  td.col-anchor {
    position: static;
    box-shadow: none;
    background: none;
    border-bottom: 1px solid var(--border-soft);
    padding-bottom: 8px;
    margin-bottom: 2px;
  }
  tbody tr:hover td.col-anchor { background: none; box-shadow: none; }
  tbody tr:hover td:first-child { box-shadow: none; }

  td[data-label]::before {
    content: attr(data-label);
    flex: none;
    color: var(--muted-2);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    /* La etiqueta no debe empujar al valor fuera de la tarjeta cuando el valor
       es largo (un nombre de producto de dos lineas, p. ej.). */
    max-width: 42%;
  }
  /* La celda del nombre y la de acciones se leen solas: la etiqueta sobra y
     ademas rompe la jerarquia de la tarjeta. */
  td.col-anchor::before, td.actions::before { content: none; }
  td.col-anchor { display: block; }
  /* Y esto DETRAS de la linea de arriba, no en cualquier sitio: `td.col-hidden`
     (arriba del todo, con las columnas a medida) y `td.col-anchor` de aqui
     tienen la MISMA especificidad, asi que gana la ultima del fichero. Sin esta
     linea, ocultar la columna del nombre desde el menu "Columnas" funcionaba en
     la tabla y NO en las tarjetas de movil: la celda volvia a display:block y
     reaparecia. Solo le pasa a esa columna, que es la unica que el bloque movil
     vuelve a declarar. */
  td.col-hidden { display: none; }
  td.actions { justify-content: flex-end; }
  .cell-main { max-width: none; -webkit-line-clamp: 3; }
}

/* ---------- Login ---------- */

.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: 20px;
}

.login-card {
  width: 100%;
  max-width: 340px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px 26px;
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 22px;
}

.login-brand .brand-mark {
  width: 34px; height: 34px; border-radius: 9px;
  background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 16px;
}

.login-brand span { font-weight: 700; font-size: 17px; }

.login-form .field { margin-bottom: 14px; }

.login-error {
  color: var(--red);
  font-size: 13px;
  margin: 0 0 12px;
  min-height: 16px;
}

.login-form .btn { width: 100%; justify-content: center; }

/* Ayuda desplegable de la escala 1-10 en el formulario de artículo. Va dentro
   del campo, debajo del input, para que la definición esté donde se decide la
   puntuación y no en un documento que nadie abre. */
.score-help { margin-top: 6px; }
.score-help > summary { cursor: pointer; font-size: 12px; color: var(--muted); }
.score-help__table { width: 100%; border-collapse: collapse; margin: 8px 0 6px; font-size: 12px; }
.score-help__table th, .score-help__table td { text-align: left; padding: 3px 6px 3px 0; vertical-align: top; }
.score-help__table thead th { color: var(--muted); font-weight: 600; border-bottom: 1px solid var(--border); }
.score-help__table td:first-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
.score-help__table td:last-child { white-space: nowrap; color: var(--muted); }

/* ---------- Ficha de artículo: bloques, barra de precio y comparables ---------- */

/* Los pares de la ficha van agrupados bajo una cabecera de bloque. La lista plana
   de 18 pares mezclaba "qué es la pieza" con "en qué estado está" y con el dinero,
   y no había forma de saltar al que se buscaba. */
.field-block { margin-top: 20px; }
.field-block:first-of-type { margin-top: 0; }
.field-block__title {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--muted-2);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  padding-bottom: 8px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-soft);
}

/* Misma regla que las tablas: todo dato numérico verificable en --font-num. */
.detail-num { font-family: var(--font-num); font-size: 13px; }

/* Barra de precio de la ficha: coste → suelo del canal → mercado, con la marca
   del precio publicado encima. El track NO lleva overflow:hidden porque esa
   marca sobresale por arriba; los redondeos van en los propios tramos. */
.ladder-track {
  position: relative;
  display: flex;
  height: 10px;
  border-radius: 5px;
  background: var(--surface-2);
  margin-top: 34px;
}
.ladder-seg { height: 10px; }
.ladder-seg:first-child { border-radius: 5px 0 0 5px; }
.ladder-seg:last-of-type { border-radius: 0 5px 5px 0; }
.ladder-cost { background: var(--muted-2); }
.ladder-fee { background: var(--yellow); }
.ladder-margin { background: var(--green); }
.ladder-mark {
  position: absolute;
  bottom: 100%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 11px;
  line-height: 1.25;
  white-space: nowrap;
  color: var(--text);
}
.ladder-mark b { font-family: var(--font-num); }
.ladder-mark > span { color: var(--muted); }
.ladder-mark::after { content: ""; width: 1px; height: 8px; background: var(--text); margin-top: 3px; }
.ladder-mark.is-low, .ladder-mark.is-low b { color: var(--red); }
.ladder-mark.is-low::after { background: var(--red); }
.ladder-keys {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin-top: 12px;
  font-size: 12px;
  color: var(--muted);
}
.ladder-key { display: inline-flex; align-items: center; gap: 6px; }
.ladder-key b { color: var(--text); }
.ladder-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; }

/* Puntuación del tasador: el número con su escala al lado. */
.score-meter { display: inline-flex; align-items: center; gap: 8px; }
.score-meter__track { width: 58px; height: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; flex: none; }
.score-meter__fill { display: block; height: 100%; border-radius: 3px; }

/* Historial de precio de un anuncio: mini-gráfica + la secuencia en texto. La
   gráfica sola no dice cuánto, el texto solo no dice la forma. */
.price-hist { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.sparkline { flex: none; }

/* Comparables de mercado: rejilla, no tabla (ver mercadosTablaHtml). */
.comps-list { display: flex; flex-direction: column; gap: 8px; font-size: 12px; }
.comps-row {
  display: grid;
  grid-template-columns: minmax(70px, auto) 1fr auto auto;
  gap: 10px;
  align-items: center;
}
.comps-src { color: var(--muted); white-space: nowrap; }
.comps-bar__track { position: relative; display: block; height: 8px; border-radius: 4px; background: var(--surface-2); }
/* Vendido y pedido NO se pintan igual: uno es lo que se paga y el otro lo que se
   pide, y dos barras del mismo color se leerían como la misma medida. */
.comps-bar__fill { display: block; height: 100%; border-radius: 4px; background: var(--blue); }
.comps-bar__fill.is-sold { background: var(--green); }
.comps-bar__ref { position: absolute; top: -3px; width: 2px; height: 14px; background: var(--accent-2); border-radius: 1px; }
.comps-val { white-space: nowrap; text-align: right; }
.comps-n { color: var(--muted); white-space: nowrap; }
.comps-legend { display: flex; align-items: center; gap: 6px; margin: 10px 0 4px; }
.comps-legend__ref { width: 2px; height: 11px; background: var(--accent-2); border-radius: 1px; display: inline-block; flex: none; }
.comps-models { margin: 0; padding-left: 18px; font-size: 12px; color: var(--muted); }
.comps-models li { margin-bottom: 5px; }
.comps-models strong { color: var(--text); }

/* En móvil no caben cuatro columnas: fuente y cifra arriba, la barra debajo a todo
   el ancho (que es donde se lee la comparación) y la muestra al pie. */
@media (max-width: 760px) {
  .comps-row { grid-template-columns: 1fr auto; row-gap: 5px; }
  .comps-bar__track { grid-column: 1 / -1; order: 3; }
  .comps-n { grid-column: 1 / -1; order: 4; text-align: left; }
}

/* La píldora del SKU (y la del serial) se estiraba a todo el ancho de la columna
   dentro de .detail-fields, que es un grid: sin esto parece un campo de entrada
   vacío en vez de una etiqueta. Acotado a la ficha — en las tablas la píldora ya
   se ajusta sola. */
.detail-fields .internal-sku-badge { justify-self: start; width: fit-content; }

/* ---------- Visor de fotos de la ficha ---------- */

/* Se hacen 7-8 tomas por pieza y desde la ficha solo se veía la primera. */
.is-zoomable { cursor: zoom-in; }
.lightbox-overlay { padding: 12px; }
.lightbox { display: flex; flex-direction: column; align-items: center; gap: 10px; max-width: 100%; }
/* `contain` y no `cover`: aquí el objetivo es ver la foto ENTERA (una costura en
   una esquina es justo lo que se viene a mirar), al revés que la foto principal
   de la tarjeta, que sí recorta para cuadrar. */
.lightbox-img {
  max-width: min(1100px, 92vw);
  max-height: 82vh;
  object-fit: contain;
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.lightbox-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
}

/* Cada modelo de la lista de comparables es un botón: clicarlo fija ese modelo
   para este artículo (ver mercadoFichaHtml). Se distingue del texto de al lado
   pero sin gritar — es una lista para leer, no una fila de botones. */
.comps-pin { font-family: var(--font-num); font-size: 11px; padding: 2px 8px; }
.comps-models li { margin-bottom: 8px; }
