/* Ventas Nubecol — shared layout, built on top of theme.css tokens */

* { box-sizing: border-box; }

/* Barras de scroll (regla general, 2026-10-12): finas, redondeadas, del color
   del tema y sin fondo, en TODO elemento con scroll -- la nativa salía blanca
   y ancha en modo oscuro (ej. lista de canales del modal de AdSense). Mismo
   estilo que ya tenían .dropdown-menu-left y .programada-tabla-scroll. El
   selector * no tiene especificidad: lo que oculta su barra a propósito
   (.quicknav, scrollbar-width:none) sigue igual. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background-color: var(--text-muted); }
*::-webkit-scrollbar-corner { background: transparent; }

html, body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  min-height: 100vh;
  transition: background-color .2s ease, color .2s ease;
}

.screen {
  max-width: 420px;
  margin: 0 auto;
  padding: 24px 20px calc(40px + env(safe-area-inset-bottom, 0px));
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* Vista de escritorio -- toda la app quedaba fija en 420px sin importar
   el tamaño de pantalla (mismo ancho en celular y en un monitor). Este
   breakpoint ensancha el contenedor recién a partir de 720px de
   viewport, así que en mobile no cambia nada; en escritorio da más
   lugar para que las pantallas que lo necesiten usen ese espacio (ej.
   fichas lado a lado, tablas anchas sin scroll horizontal). */
@media (min-width: 720px) {
  .screen {
    max-width: 760px;
    padding-left: 32px;
    padding-right: 32px;
  }
}

/* ---------- Top bar / theme toggle ---------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

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

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 18px;
  color: var(--text);
  text-decoration: none;
}

.brand-mark {
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.theme-toggle {
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 999px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  cursor: pointer;
  box-shadow: var(--shadow);
  flex-shrink: 0;
}

.menu-wrap {
  position: relative;
}

.dropdown-menu {
  position: absolute;
  top: 48px;
  right: 0;
  min-width: 190px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow);
  padding: 8px;
  display: none;
  flex-direction: column;
  gap: 2px;
  z-index: 20;
}

.dropdown-menu.open {
  display: flex;
}

/* El menú de "cambiar de comercio" cuelga de un trigger pegado al borde
   IZQUIERDO de la pantalla (el logo/marca) -- con right:0 (pensado para
   el menú de perfil, que cuelga del borde derecho) se iba fuera de
   pantalla hacia la izquierda. */
.dropdown-menu-left {
  left: 0;
  right: auto;
  max-width: calc(100vw - 32px);
  /* La lista de "Cambiar de comercio" crece con la cantidad de
     comercios del usuario -- sin esto, con muchos comercios la lista
     se corta contra el borde de la pantalla y los últimos quedan
     inalcanzables. */
  max-height: 60vh;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.dropdown-menu-left::-webkit-scrollbar { width: 8px; }
.dropdown-menu-left::-webkit-scrollbar-track { background: transparent; }
.dropdown-menu-left::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }

.dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 14px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
}

.dropdown-item:hover,
.dropdown-item:active {
  background: var(--surface-muted);
}

.dropdown-item-danger {
  color: var(--accent);
}

.dropdown-info {
  min-width: 240px;
  max-width: 280px;
  padding: 14px;
  gap: 6px;
}

.dropdown-info-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
}

.dropdown-info-text {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
}

.dropdown-icon {
  width: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* ---------- Cards ---------- */

.card {
  background: var(--surface);
  border-radius: 28px;
  padding: 28px 24px;
  box-shadow: var(--shadow);
  border: 1px solid var(--border);
}

/* ---------- Forms: pill inputs & buttons ---------- */

.field {
  margin-bottom: 14px;
}

.field label {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin: 0 6px 6px;
}

/* En modo oscuro, --text-muted (compartida con textos secundarios como
 * subtítulos/fechas) se ve demasiado opaca para el nombre de un campo
 * -- acá se busca más contraste sin tocar la variable global. */
:root[data-theme="dark"] .field label {
  color: var(--text);
}

/* Título de subsección (ej. "Audio", "Carátula", "Tipo de lanzamiento"
 * en Lanzamientos Digitales) -- versión "eyebrow" de .field label:
 * mayúsculas + letter-spacing en vez de tamaño, para que siga siendo
 * el elemento más fuerte de la sección sin competir en tamaño con el
 * contenido real (ej. el nombre de una pista de audio). */
.subseccion-titulo {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 6px 10px;
}
:root[data-theme="dark"] .subseccion-titulo {
  color: var(--text);
}

/* Reproductor de audio de Lanzamientos Digitales -- los controles
 * nativos del navegador rondan ~54px de alto por defecto, mucho para
 * una lista de varias pistas; achicado y con radio para que combine
 * con el resto de las píldoras/tarjetas de la app. */
.lanzamiento-audio-player {
  display: block;
  width: 100%;
  height: 32px;
  border-radius: 8px;
}

/* Separador entre subsecciones del wizard/ficha de Lanzamientos
 * Digitales (Tipo, Nombre, Carátula, Audio, etc.) -- antes repetido
 * como inline style en cada una; también más compacto que el primer
 * intento (18px/14px) para que el formulario completo ocupe menos
 * alto sin perder el corte visual entre secciones. */
.subseccion-separador {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.phone-row {
  display: flex;
  gap: 8px;
}

.phone-row .code-select {
  flex: 0 0 96px;
  width: auto;
  padding-left: 14px;
  padding-right: 8px;
}

.phone-row .pill-input:not(.code-select) {
  flex: 1;
  min-width: 0;
}

.pill-input {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  border-radius: 999px;
  padding: 14px 20px;
  font-size: 15px;
  outline: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.pill-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 25%, transparent);
}

.otp-code-input {
  text-align: center;
  letter-spacing: 8px;
  font-size: 20px;
  font-weight: 600;
}

/* input[type=date] es sensible a que le agranden el padding — sus
 * sub-campos (día/mes/año) internos se desbordan si se le quita espacio
 * de más. Solo se le da un pequeño margen al ícono, sin tocar el padding
 * del input. */
.pill-input[type="date"]::-webkit-calendar-picker-indicator {
  margin-left: 6px;
  cursor: pointer;
}

/* Los <select> pill usan una flecha propia (en vez de la nativa, que
 * queda pegada al borde redondeado de forma inconsistente entre
 * navegadores). */
select.pill-input {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 46px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%236B7086' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 18px center;
  background-size: 16px;
}

/* La flecha del select es una imagen de fondo (no puede leer variables
 * CSS), así que en modo oscuro se reemplaza por una versión clara. */
:root[data-theme="dark"] select.pill-input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23A9AEC4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

.input-with-action {
  position: relative;
}

.input-with-action .pill-input {
  padding-right: 52px;
}

/* Lista de sugerencias del buscador de Artista(s)/Compositores/
 * Músicos (Lanzamientos Digitales) -- overlay flotante para no
 * empujar el layout de la fila (el input de Nombre comparte fila con
 * un <select> de Rol/Instrumento). El .field que lo contiene necesita
 * position:relative inline. */
.lanzamiento-nombre-sugerencias {
  position: absolute;
  z-index: 20;
  left: 0;
  right: 0;
  top: 100%;
  margin-top: 4px;
  /* surface-muted, no surface -- dentro de una .card (mismo color que
     surface) el desplegable quedaba casi invisible, sin contraste real
     contra el fondo (pedido explícito 2026-09-28). */
  background: var(--surface-muted);
  /* Borde con el mismo acento amarillo del buscador de arriba -- un
     borde neutro (var(--border)) se perdía casi igual que antes contra
     el fondo oscuro (pedido explícito 2026-09-28: "necesita algo más
     en el borde"). */
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 10px;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 8px 20px rgba(0, 0, 0, .35);
}

.lanzamiento-nombre-sugerencias-item {
  padding: 8px 10px;
  font-size: 13px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}

.lanzamiento-nombre-sugerencias-item:last-child {
  border-bottom: none;
}

.lanzamiento-nombre-sugerencias-item:hover {
  background: var(--border);
}

/* Select con buscador (regla general 2026-10-16, todo <select> con más de
 * 5 opciones, ver app.js). Panel FIJO pegado al <body> -- así ninguna
 * tarjeta/tabla/modal con overflow lo recorta. Mismo aspecto que las
 * sugerencias de arriba (fondo surface-muted + borde de acento). z-index
 * por encima de los modales (200). */
.select-buscador-panel {
  position: fixed;
  z-index: 300;
  background: var(--surface-muted);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 12px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, .35);
  padding: 8px;
  max-width: calc(100vw - 16px);
}

.select-buscador-input {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 999px;
  padding: 9px 14px;
  font-size: 14px;
  outline: none;
  margin-bottom: 6px;
}

.select-buscador-input:focus {
  border-color: var(--primary);
}

.select-buscador-lista {
  max-height: 260px;
  overflow-y: auto;
}

.select-buscador-item {
  padding: 9px 12px;
  font-size: 14px;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.select-buscador-item:hover,
.select-buscador-activo {
  background: var(--border);
}

.select-buscador-seleccionado {
  color: var(--accent);
  font-weight: 600;
}

.select-buscador-deshabilitado {
  opacity: .45;
  cursor: default;
}

.select-buscador-grupo {
  padding: 8px 12px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.select-buscador-vacio {
  padding: 10px 12px;
  font-size: 13px;
  color: var(--text-muted);
}

.lanzamiento-nombre-sugerencias-hint {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.icon-btn {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  cursor: pointer;
}

/* Buscador: dos botones dentro del mismo input (borrar + escanear). */
.input-buscador .pill-input {
  padding-right: 92px;
}

.icon-btn-clear {
  right: 6px;
  width: 28px;
  height: 28px;
  background: var(--surface-muted);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

/* Fila del botón principal de registrar venta + acceso directo a escanear,
 * para poder registrar el siguiente producto sin volver a subir a la
 * barra de búsqueda — la app está pensada para vender lo más rápido
 * posible. */
.registrar-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
}

.registrar-row .btn {
  flex: 1;
}

.icon-btn-static {
  position: static;
  transform: none;
  width: 52px;
  height: 52px;
  flex-shrink: 0;
}

.btn {
  display: block;
  width: 100%;
  border: none;
  border-radius: 999px;
  padding: 15px 20px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
}

.btn-primary {
  background: var(--primary);
  color: var(--primary-contrast);
}

.btn-accent {
  background: var(--accent);
  color: var(--primary-contrast);
}

.btn-primary:disabled,
.btn-accent:disabled {
  opacity: .45;
  cursor: not-allowed;
}

.btn-spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  margin-right: 8px;
  vertical-align: -3px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}

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

/* Botón "Actualizar" con ícono (ej. home del admin, código TikTok) --
   gira el SVG mientras espera respuesta, misma animación que
   .btn-spinner de arriba, sin reemplazar el ícono por otro elemento. */
.btn-icon.tiktok-actualizar-girando svg {
  animation: btn-spin 0.6s linear infinite;
}

.link-muted {
  display: block;
  text-align: center;
  color: var(--text-muted);
  font-size: 14px;
  text-decoration: none;
  margin-top: 14px;
}

.link-primary {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}

/* ---------- Login page mascot / hero ---------- */

.hero {
  text-align: center;
  margin: 8px 0 28px;
}

.hero-mark {
  width: 96px;
  height: 96px;
  margin: 0 auto 14px;
  border-radius: 28px;
  background: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 44px;
}

.hero h1 {
  font-size: 20px;
  margin: 0 0 4px;
}

.hero p {
  color: var(--text-muted);
  font-size: 14px;
  margin: 0;
}

/* ---------- Sales page ---------- */

.qty-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 20px;
}

.chip {
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  border-radius: 999px;
  min-width: 42px;
  height: 42px;
  padding: 0 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: inherit;
  font-weight: 600;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.chip.selected {
  background: var(--surface-muted);
  color: var(--primary);
  border-color: var(--primary);
  border-width: 2px;
}

/* Carritos "enviados" (a delivery) se ven distintos de los "abiertos" en
   la lista de chips solo por el color del texto — el borde queda igual
   que un chip normal; el segundo renglón con el nombre del delivery ya
   es en sí mismo un indicador visual de que fue enviado. */
.chip-enviado {
  color: var(--primary);
}

/* Carrito actualmente abierto en pantalla: borde con el color secundario
   (mismo criterio que .btn-secondary) + check al inicio del chip. */
.chip-carrito.selected {
  border-color: var(--accent);
  border-width: 2px;
}

.chip-carrito-check {
  display: inline-flex;
  margin-right: 4px;
  color: var(--accent);
}

.divider {
  border-top: 1px solid var(--border);
  margin: 16px 0;
}

.product-card {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 14px 16px;
  margin-bottom: 18px;
}

.product-thumb {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  background: var(--bg-blush);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  flex-shrink: 0;
  overflow: hidden;
}

.list-item-thumb {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--bg-blush);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  color: var(--text-muted);
}

.list-item-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  cursor: pointer;
}

.product-info { flex: 1; min-width: 0; }
.product-info .name { font-weight: 600; font-size: 15px; }
.product-info .code { color: var(--text-muted); font-size: 12px; }
.product-info .price { color: var(--primary); font-weight: 700; font-size: 15px; margin-top: 2px; }

.section-label {
  font-size: 13px;
  color: var(--text-muted);
  margin: 0 6px 8px;
}

.spacer { flex: 1; }

/* ---------- CRUD: listas, badges, botones pequeños, checkbox ---------- */

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 4px 0 18px;
}

.page-header h1 {
  font-size: 19px;
  margin: 0;
}

.btn-fab {
  width: 42px;
  height: 42px;
  border-radius: 999px;
  border: none;
  background: var(--primary);
  color: var(--primary-contrast);
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none;
  flex-shrink: 0;
}

.list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 20px;
}

.list-empty {
  text-align: center;
  color: var(--text-muted);
  font-size: 14px;
  padding: 32px 16px;
}

/* ---------- Reportes de ventas: filtros y resumen ---------- */

.filter-row {
  display: flex;
  gap: 8px;
}

.filter-row .field {
  flex: 1;
  margin-bottom: 0;
  min-width: 0;
}

/* El input de fecha tiene un ancho mínimo propio del navegador: en celular
   "Hasta" se salía de la tarjeta (pedido 2026-10-11). Que se ajuste al
   ancho de su campo y, en pantallas angostas, con menos relleno y letra un
   poco más chica para que la fecha completa siga entrando. */
.filter-row .pill-input[type="date"] {
  min-width: 0;
  width: 100%;
}

@media (max-width: 420px) {
  .filter-row .pill-input[type="date"] {
    padding-left: 12px;
    padding-right: 8px;
    font-size: 14px;
  }
}

/* Versión compacta de .card para tarjetas de filtros (desde/hasta +
   selects/buscador + botón Filtrar) — mismo layout, menos alto: bajan el
   padding de la tarjeta, el alto de los inputs/label y el botón, que en
   la versión normal ocupan más de lo que hace falta para una tarjeta que
   el usuario suele mirar una sola vez antes de tocar "Filtrar". */
.card-filters {
  padding: 14px 18px;
  margin-bottom: 14px;
}

.card-filters .field {
  margin-bottom: 8px;
}

.card-filters .field label {
  font-size: 12px;
  margin: 0 4px 3px;
}

.card-filters .pill-input {
  padding: 10px 16px;
  font-size: 14px;
}

/* select.pill-input reserva 46px de padding-right para la flecha (regla
 * más abajo en este mismo archivo) — sin este override puntual, el
 * padding acortado de arriba se lo pisaría por especificidad y el texto
 * del select quedaría por debajo de la flecha. */
.card-filters select.pill-input {
  padding: 10px 46px 10px 16px;
}

/* Select de estado con botón "X" superpuesto (misma acción de borrado
 * rápido que el buscador) -- se corre la flecha del select más a la
 * izquierda para que no quede debajo del botón. */
.card-filters .input-with-action select.pill-input {
  padding-right: 78px;
  background-position: right 50px center;
}

.card-filters .btn {
  padding: 11px 20px;
  font-size: 14px;
  margin-top: 4px;
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 20px;
}

.summary-stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 14px;
}

.summary-stat .stat-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.summary-stat .stat-value {
  font-size: 17px;
  font-weight: 700;
}

/* Variante compacta — "Ventas del comercio"/"Mis ventas", donde el resumen
   es solo un dato de referencia rápida arriba de una lista/buscador que es
   lo que realmente importa en esa pantalla. */
.summary-grid-compact {
  gap: 8px;
  margin-bottom: 14px;
}

.summary-grid-compact .summary-stat {
  padding: 10px 12px;
  border-radius: 12px;
}

.summary-grid-compact .stat-label {
  font-size: 11px;
  margin-bottom: 2px;
}

.summary-grid-compact .stat-value {
  font-size: 15px;
}

.action-grid {
  display: grid;
  gap: 10px;
  margin-top: 16px;
}

.action-grid-3 {
  grid-template-columns: repeat(3, 1fr);
}

.action-grid-2 {
  grid-template-columns: repeat(2, 1fr);
}

.action-grid-4 {
  grid-template-columns: repeat(2, 1fr);
}

.action-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 18px 8px;
  text-decoration: none;
  color: var(--text);
  text-align: center;
}

.action-card-icon {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* Menú de inicio de root agrupado por secciones (2026-10-16): una sola
   tarjeta compacta, 4 accesos por fila, íconos chicos -- pedido explícito de
   no desperdiciar espacio vertical. Clases propias para no tocar las
   grillas .action-grid de otras pantallas. */
.menu-root { padding: 14px 14px 16px; }
.menu-root-saludo { margin: 0 2px 4px; font-size: 14px; }
.menu-root-titulo {
  margin: 6px 4px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.menu-root-secciones {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-width: 0;
  margin-top: 8px;
}
/* Cada sección en su propio recuadro (pedido 2026-10-16: "que queden
   encerrados en sus propias secciones"). */
.menu-root-seccion {
  min-width: 0;
  max-width: 100%;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface-muted);
  padding: 2px 6px 6px;
}
.menu-root-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.menu-root-item {
  position: relative;
  flex: 0 0 80px;
  width: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 0;
  padding: 7px 4px 6px;
  border-radius: 10px;
  color: var(--text);
  text-decoration: none;
  text-align: center;
}
.menu-root-item:hover { background: var(--border); }
.menu-root-icono {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.menu-root-label {
  max-width: 100%;
  font-size: 11.5px;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

/* RM Fotos / RM Video en la grilla de inicio -- misma sigla que ya usa
   la tira de íconos del header, ver .quicknav-icon-texto. */
.action-card-icon-texto {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -.02em;
}

/* Scroll (vertical + horizontal) de las tablas "Programadas" -- mismo
   criterio de scrollbar fina que .contenido-listado-scroll (esa vive
   inline dentro de admin/contenido.php, así que no le sirve a root),
   pero acá con barra horizontal visible y con estilo (pedido explícito
   2026-09-28: "dale estilo a este scroll horizontal"), no la del
   navegador por defecto. */
.programada-tabla-scroll {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.programada-tabla-scroll::-webkit-scrollbar { width: 6px; height: 6px; }
.programada-tabla-scroll::-webkit-scrollbar-track { background: transparent; }
.programada-tabla-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
.programada-tabla-scroll::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

.action-card-label {
  font-size: 13px;
  font-weight: 600;
}

/* Tira de accesos rápidos (mismos íconos del home) debajo del header --
   scroll horizontal si no entran todos, sin barra visible (mismo
   criterio que .dropdown-menu-left, que sí la deja ver por ser más
   larga verticalmente). */
.quicknav {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  overflow-x: auto;
  padding: 12px 4px 14px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  scrollbar-width: none;
  scroll-behavior: smooth;
}

/* Aviso de que hay más íconos (pedido 2026-10-12): el envoltorio recibe
   .quicknav-mas-der / .quicknav-mas-izq desde app.js solo cuando hay
   íconos fuera de la vista -- la tira se desvanece en ese borde y aparece
   una flechita que la desliza. Al llegar al final desaparecen solas. */
.quicknav-wrap {
  position: relative;
  margin: -4px -4px 10px;
}
.quicknav-wrap.quicknav-mas-der .quicknav {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent calc(100% - 8px));
  mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent calc(100% - 8px));
}
.quicknav-wrap.quicknav-mas-izq .quicknav {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 56px), transparent calc(100% - 8px));
  mask-image: linear-gradient(to left, #000 calc(100% - 56px), transparent calc(100% - 8px));
}
.quicknav-wrap.quicknav-mas-der.quicknav-mas-izq .quicknav {
  -webkit-mask-image: linear-gradient(to right, transparent 8px, #000 56px, #000 calc(100% - 56px), transparent calc(100% - 8px));
  mask-image: linear-gradient(to right, transparent 8px, #000 56px, #000 calc(100% - 56px), transparent calc(100% - 8px));
}
.quicknav-flecha {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}
.quicknav-flecha-izq { left: 0; }
.quicknav-flecha-der { right: 0; }
.quicknav-wrap.quicknav-mas-der .quicknav-flecha-der,
.quicknav-wrap.quicknav-mas-izq .quicknav-flecha-izq { display: inline-flex; }

.quicknav::-webkit-scrollbar { display: none; }

/* Separador entre secciones del menú de root en la tira de íconos
   (2026-10-16, ver 'seccion' en $__quicknavItems de header.php). */
.quicknav-sep {
  flex: 0 0 1px;
  align-self: center;
  height: 22px;
  background: var(--border);
}

.quicknav-item {
  display: flex;
  position: relative;
  flex-shrink: 0;
  text-decoration: none;
  color: var(--text);
}

/* Contador de notificaciones sin leer sobre el ícono de "Notificaciones"
   en la tira del header -- ver $__quicknavItems en header.php. */
.quicknav-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 999px;
  background: #E5484D;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
}

.quicknav-icon {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.quicknav-item.quicknav-activo .quicknav-icon {
  background: var(--primary);
  color: var(--primary-contrast);
}

/* RM Fotos / RM Video en la tira de íconos del header -- sigla en vez de
   ícono genérico (foto/videocámara), para no confundirlos entre sí de
   un vistazo. */
.quicknav-icon-texto {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: -.02em;
}

.list-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 16px 18px;
  box-shadow: var(--shadow);
}

.list-item-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.list-item-title {
  font-weight: 600;
  font-size: 15px;
}

/* Filas plegables (Mis ventas / Ventas del comercio): <details>/<summary>
 * nativos, sin JS — el resumen (cliente/producto + total) siempre visible,
 * el resto (vendedor, dirección, líneas de producto) solo al desplegar. */
.list-details summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.list-details summary::-webkit-details-marker,
.list-details summary::marker {
  display: none;
}

.list-details-chevron {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform .15s ease;
}

.list-details-csv {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  padding: 4px;
}

.list-details[open] .list-details-chevron {
  transform: rotate(180deg);
}

.list-details-body {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.list-item-sub {
  color: var(--text-muted);
  font-size: 12px;
  margin-top: 2px;
}

.list-item-meta {
  font-size: 13px;
  color: var(--text);
  margin-top: 8px;
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.badge-on {
  background: color-mix(in srgb, var(--primary) 20%, transparent);
  color: var(--primary);
}

.badge-off {
  background: color-mix(in srgb, var(--text-muted) 20%, transparent);
  color: var(--text-muted);
}

.badge-warn {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  color: var(--accent);
  margin-left: 6px;
}

/* Ámbar fijo (no var(--accent)/--primary) a propósito -- este tema
 * invierte esos dos tokens entre claro/oscuro (--accent es naranja en
 * claro pero verde en oscuro), así que un badge de estado "en
 * revisión" que dependiera de ellos cambiaría de color solo -- se
 * quiere el mismo ámbar en las dos vistas de Lanzamientos Digitales
 * (lista y ficha) sin importar el tema. */
.badge-revision {
  background: color-mix(in srgb, #F5A623 20%, transparent);
  color: #F5A623;
}

/* Mismo criterio que .badge-revision -- colores fijos, no ligados a
 * --primary/--accent, para que el resto del flujo de distribución
 * digital de Lanzamientos también se vea igual en claro y oscuro. */
.badge-pendiente {
  background: color-mix(in srgb, #4A90D9 20%, transparent);
  color: #4A90D9;
}

.badge-aprobado {
  background: color-mix(in srgb, #4CAF50 20%, transparent);
  color: #4CAF50;
}

.badge-rechazado {
  background: color-mix(in srgb, #E5484D 20%, transparent);
  color: #E5484D;
}

/* Selector de estado de root en lanzamiento_ver.php -- mismo pill-input
 * de siempre pero compacto, para que quepa junto al <h1> en el
 * page-header sin verse voluminoso. */
.lanzamiento-estado-select {
  width: auto;
  padding: 6px 34px 6px 12px;
  font-size: 12px;
  background-position: right 12px center;
  background-size: 12px;
}

.btn-icon-warn-on {
  background: var(--accent);
  color: var(--primary-contrast);
  border-color: var(--accent);
}

.actions-row {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  flex-wrap: wrap;
}

.btn-status {
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}

.btn-status-on {
  background: var(--primary);
  color: var(--primary-contrast);
}

.btn-status-off {
  background: color-mix(in srgb, var(--text-muted) 25%, transparent);
  color: var(--text-muted);
}

.btn-status-warn-on {
  background: var(--accent);
  color: var(--primary-contrast);
}

.btn-quitar-archivo {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: none;
  background: #E5484D;
  color: #fff;
  font-size: 16px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 2;
}

.btn-status-bloqueado {
  position: relative;
  background: color-mix(in srgb, var(--text-muted) 25%, transparent);
  color: var(--text-muted);
  opacity: .6;
}

.btn-status-bloqueado::after {
  content: '';
  position: absolute;
  left: 15%;
  top: 50%;
  width: 70%;
  height: 2px;
  background: var(--text-muted);
  transform: rotate(-45deg);
  border-radius: 2px;
}

.status-group {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.btn-sm {
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  border-radius: 999px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}

/* Acciones secundarias (guardar dirección/delivery, etc.) — borde de color
   en vez de relleno, mismo criterio que los chips seleccionados. */
.btn-secondary {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--surface-muted);
}

/* Botón chico relleno del color principal (mismo amarillo que .btn.btn-primary)
   -- .btn-sm por sí solo pone su propio background, hace falta esta combinación
   con más especificidad para que gane. */
.btn-sm.btn-primary {
  background: var(--primary);
  color: var(--primary-contrast);
  border-color: var(--primary);
}

.btn-icon {
  width: 36px;
  height: 36px;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  cursor: pointer;
  text-decoration: none;
  flex-shrink: 0;
  padding: 0;
}

.btn-icon:disabled {
  opacity: .4;
  cursor: not-allowed;
}

.btn-icon-danger {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}

.btn-icon-success {
  color: #4CAF50;
  border-color: color-mix(in srgb, #4CAF50 40%, var(--border));
}

.btn-add {
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}

.btn-sm-danger {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 6px 18px;
}

.checkbox-row label {
  font-size: 14px;
}

/* ---------- Checkbox estándar del sistema (toggle chico) ----------
 * Todo <input type="checkbox"> del sistema, presente y futuro, se ve
 * como un toggle chico -- sin tener que tocar el HTML de cada lugar
 * que ya usa un checkbox nativo. :where() le da especificidad CERO a
 * propósito: cualquier estilo más puntual que ya exista (ej. el
 * switch grande de los gates de root, ".switch input") sigue ganando
 * sin ningún cambio ni acá ni ahí. "order" + "margin-left:auto" lo
 * empujan al extremo derecho de su fila SOLO cuando el contenedor
 * inmediato es flex (que es el patrón que ya usan casi todas las
 * filas con checkbox de este sistema) -- fuera de un flex container
 * ambas propiedades no hacen nada, así que no rompe otros usos.
 * :not(.switch input) además excluye por completo al checkbox interno
 * del switch grande -- ese ya arma su propio toggle con .switch-track/
 * .switch-thumb (elementos hermanos, no pseudo-elementos), y sin
 * excluirlo acá el width/height explícitos de abajo podrían achicar
 * su área clickeable (queda oculto con opacity:0 ahí, pero el tamaño
 * de la caja sigue importando para dónde responde el click). */
:where(input[type="checkbox"]):not(.switch input) {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 34px;
  height: 20px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 30%, transparent);
  cursor: pointer;
  flex-shrink: 0;
  margin: 0;
  margin-left: auto;
  order: 1;
  vertical-align: middle;
  transition: background-color .15s ease;
}

:where(input[type="checkbox"]):not(.switch input)::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
  transition: transform .15s ease;
}

:where(input[type="checkbox"]):not(.switch input):checked {
  background: var(--primary);
}

:where(input[type="checkbox"]):not(.switch input):checked::before {
  transform: translateX(14px);
}

:where(input[type="checkbox"]):not(.switch input):focus-visible {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 25%, transparent);
}

:where(input[type="checkbox"]):not(.switch input):disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* Canal de YouTube que no cumple la regla de publicación (ver
   publicacionYoutubeAptitudActualizar() en publicacion.php) -- misma
   base que :disabled de arriba, más una raya diagonal roja sobre el
   switch para que se note a simple vista que está tachado, no solo
   apagado. */
:where(input[type="checkbox"]).publicacion-red-check-no-apto {
  position: relative;
}

:where(input[type="checkbox"]).publicacion-red-check-no-apto::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 1px;
  right: 1px;
  height: 2px;
  background: #E5484D;
  transform: translateY(-50%) rotate(-18deg);
  border-radius: 2px;
  pointer-events: none;
}

/* ---------- Switch deslizante (formularios: activo, modo tienda) ---------- */

.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 6px 18px;
}

.switch-row-label {
  font-size: 14px;
  color: var(--text);
}

.switch {
  position: relative;
  display: inline-block;
  width: 48px;
  height: 28px;
  flex-shrink: 0;
  cursor: pointer;
}

.switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.switch-track {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--text-muted) 30%, transparent);
  border-radius: 999px;
  transition: background-color .15s ease;
}

.switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  transition: transform .15s ease;
}

.switch input:checked + .switch-track {
  background: var(--primary);
}

.switch input:checked + .switch-track .switch-thumb {
  transform: translateX(20px);
}

.switch input:focus-visible + .switch-track {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 25%, transparent);
}

.switch input:disabled + .switch-track {
  opacity: .5;
  cursor: not-allowed;
}

/* ---------- Mezclar audio: 3 capas (reemplaza al reproductor nativo --
 * el <audio> real queda oculto, el video es quien manda el play/pausa,
 * ver publicacion.php). Definición 2026-09-29, de más profunda a menos
 * profunda: (1) esta barra -- tiempo de la "referencia" (el VIDEO si
 * dura >= que la canción elegida, o la CANCIÓN completa si el video
 * dura menos -- típico en Historias, videos cortos con canciones de
 * varios minutos, para que la ventana tenga margen real donde
 * deslizarse), siempre el 100% del control; (2)
 * .mezclar-audio-barra-audio -- tiempo de la CANCIÓN elegida, nunca más
 * ancha que esta (capada al 100% cuando la referencia ES la canción);
 * (3) el slider verde -- la ventana asignada, con las ondas en
 * movimiento adentro. ---------- */
/* "Foto con música" (public/admin/publicacion.php): los controles de
   música (buscador, ventana, volúmenes) arrancan bloqueados hasta que se
   elige la foto -- ya vienen con una canción por defecto, pero no tiene
   sentido dejar tocarlos antes de tener algo que musicalizar. */
.mezclar-audio-bloqueado {
  opacity: .45;
  pointer-events: none;
}

.mezclar-audio-barra-video {
  height: 36px;
  flex: 1;
  min-width: 0;
  border-radius: 999px;
  /* Rayado diagonal -- esta capa siempre queda tapada por la capa 2
     (barra degradada) en la parte que sí cubre la canción, así que lo
     único que se termina viendo de este fondo es el tramo de la
     referencia que se va a quedar SIN música cuando la referencia ES el
     video (se completa con el audio original) -- el rayado lo marca
     como "bloqueado". Cuando la referencia ES la canción (video corto),
     la capa 2 cubre el 100% y este fondo directamente no se ve. */
  background: repeating-linear-gradient(
    45deg,
    var(--surface-muted),
    var(--surface-muted) 6px,
    var(--border) 6px,
    var(--border) 12px
  );
  border: 1px solid var(--border);
}

.mezclar-audio-barra-audio {
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(255, 214, 10, .14), rgba(255, 30, 200, .14));
}

/* Capa 3: el slider verde en sí -- fondo con volumen real (gradiente +
 * sombra interior/exterior) en vez del verde plano translúcido de
 * antes, para que se lea como un control "elevado", no como un
 * rectángulo pintado encima. */
.mezclar-audio-banda {
  position: absolute;
  top: 0;
  height: 100%;
  /* Tiene que entrar completo el contenido interno (7 barritas de onda +
     el chip de segundos) sin que "overflow:hidden" lo recorte -- 64px se
     quedaba corto para ventanas chicas (ej. 10s en una Historia), donde
     antes se veía la onda apretada/cortada contra el chip. */
  min-width: 130px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 10px;
  border-radius: 999px;
  pointer-events: none;
  overflow: hidden;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, white 10%), color-mix(in srgb, var(--accent) 78%, black 14%));
  border: 1px solid color-mix(in srgb, var(--accent) 55%, black 30%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .3), inset 0 1px 0 rgba(255, 255, 255, .3);
}

/* La etiqueta de segundos ya no es texto suelto sobre el verde -- es su
 * propia píldora oscura, mismo criterio que un badge/chip, para que se
 * lea nítida sin importar el tono exacto de --accent (naranja en claro,
 * verde en oscuro). */
.mezclar-audio-banda-texto {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
  color: #fff;
  white-space: nowrap;
  flex-shrink: 0;
  background: rgba(0, 0, 0, .32);
  padding: 3px 8px;
  border-radius: 999px;
  line-height: 1;
}

.mezclar-audio-ondas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 100%;
}

.mezclar-audio-ondas span {
  display: block;
  width: 4px;
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(180deg, #FFD60A, #FF2FD1);
  box-shadow: 0 0 6px rgba(255, 47, 209, .65);
  animation: mezclarAudioOnda 1s ease-in-out infinite;
  animation-play-state: paused;
}

.mezclar-audio-ondas.sonando span {
  animation-play-state: running;
}

.mezclar-audio-ondas span:nth-child(1) { animation-duration: .82s; animation-delay: 0s; }
.mezclar-audio-ondas span:nth-child(2) { animation-duration: 1.05s; animation-delay: .08s; }
.mezclar-audio-ondas span:nth-child(3) { animation-duration: .74s; animation-delay: .18s; }
.mezclar-audio-ondas span:nth-child(4) { animation-duration: 1.15s; animation-delay: .02s; }
.mezclar-audio-ondas span:nth-child(5) { animation-duration: .88s; animation-delay: .22s; }
.mezclar-audio-ondas span:nth-child(6) { animation-duration: 1s; animation-delay: .12s; }
.mezclar-audio-ondas span:nth-child(7) { animation-duration: .95s; animation-delay: .28s; }

@keyframes mezclarAudioOnda {
  0%, 100% { height: 6px; }
  50% { height: 26px; }
}

/* Con "Mezclar audio" tildado, el volumen del video se maneja con el
 * slider dedicado (no con el control nativo, que quedaría duplicando
 * el mismo ajuste) -- son pseudo-elementos de WebKit/Blink (Chrome,
 * Edge, Safari, y los navegadores del sistema en Android/iPhone, que
 * es donde se usa esto en la práctica); Firefox no tiene forma de
 * ocultar partes sueltas de sus controles nativos, así que ahí el
 * botón de volumen simplemente se queda visible -- no rompe nada,
 * solo no llega a ocultarse. */
video.sin-volumen-nativo::-webkit-media-controls-mute-button,
video.sin-volumen-nativo::-webkit-media-controls-volume-slider,
video.sin-volumen-nativo::-webkit-media-controls-volume-control-container {
  display: none !important;
}

/* Recorte de TIEMPO de Historias -- control de 2 manijas independientes
 * (a diferencia de la "banda" de Mezclar audio, que es un único bloque
 * que se arrastra entero). Vive junto al recorte de encuadre, en
 * #publicacionHistoriaRecorte -- ver publicacion.php. */
.historia-recorte-track {
  position: relative;
  height: 36px;
  margin-top: 8px;
  border-radius: 999px;
  /* Mismo rayado diagonal que .mezclar-audio-barra-video (la ventana de
     música) -- consistencia visual: acá marca el tramo del video que
     queda FUERA del recorte elegido. */
  background: repeating-linear-gradient(
    45deg,
    var(--surface-muted),
    var(--surface-muted) 6px,
    var(--border) 6px,
    var(--border) 12px
  );
  border: 1px solid var(--border);
  touch-action: none;
}

.historia-recorte-seleccion {
  position: absolute;
  top: 0;
  height: 100%;
  min-width: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 999px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, white 10%), color-mix(in srgb, var(--accent) 78%, black 14%));
  border: 1px solid color-mix(in srgb, var(--accent) 55%, black 30%);
  pointer-events: none;
}

/* Relleno que avanza de izquierda a derecha mientras el preview
 * reproduce el tramo recortado (inicio -> fin) -- da la sensación de
 * "transcurrir" del video dentro de la propia píldora, se reinicia solo
 * cada vez que el loop vuelve al inicio (ver publicacionHistoriaRecorteTiempoActualizarProgreso). */
.historia-recorte-seleccion-progreso {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 0%;
  background: rgba(255, 255, 255, .3);
  transition: width .2s linear;
}

/* Ícono + segundos del recorte, mismo criterio visual que
 * .mezclar-audio-banda-texto (píldora oscura encima del verde, legible
 * sin importar el tono exacto de --accent). */
.historia-recorte-seleccion-texto {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
  color: #fff;
  white-space: nowrap;
  background: rgba(0, 0, 0, .32);
  padding: 3px 8px;
  border-radius: 999px;
  line-height: 1;
}

.historia-recorte-handle {
  position: absolute;
  top: 50%;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: #fff;
  border: 3px solid var(--accent);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .35);
  transform: translate(-50%, -50%);
  cursor: grab;
  touch-action: none;
}

.historia-recorte-handle:active {
  cursor: grabbing;
}

.historia-recorte-handle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Ventana horaria de republicación (0-24hs) de Contenido -- mismo
 * criterio de 2 manijas que .historia-recorte-*, pero graduada por hora
 * (24 divisiones) en vez de continua, y sin el relleno de "progreso" de
 * reproducción (acá no hay nada reproduciéndose). Ver
 * app/views/partials/contenido_ventana_horaria.php. */
.contenido-ventana-track {
  position: relative;
  height: 34px;
  margin-top: 8px;
  border-radius: 999px;
  background: repeating-linear-gradient(
    90deg,
    var(--surface-muted),
    var(--surface-muted) calc(100% / 24 - 1px),
    var(--border) calc(100% / 24 - 1px),
    var(--border) calc(100% / 24)
  );
  border: 1px solid var(--border);
  touch-action: none;
}

.contenido-ventana-seleccion {
  position: absolute;
  top: 0;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, white 10%), color-mix(in srgb, var(--accent) 78%, black 14%));
  border: 1px solid color-mix(in srgb, var(--accent) 55%, black 30%);
  pointer-events: none;
}

.contenido-ventana-handle {
  position: absolute;
  top: 50%;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: #fff;
  border: 3px solid var(--accent);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .35);
  transform: translate(-50%, -50%);
  cursor: grab;
  touch-action: none;
}

.contenido-ventana-handle:active {
  cursor: grabbing;
}

.contenido-ventana-handle:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.logo-picker {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.logo-picker-preview {
  width: 80px;
  height: 80px;
  border-radius: 20px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  overflow: hidden;
}

.logo-picker-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.logo-picker-badge {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--surface);
}

.form-error {
  color: var(--accent);
  font-size: 14px;
  margin-top: 0;
}

.form-success {
  color: var(--primary);
  font-size: 14px;
  margin-top: 0;
}

/* ---------- Búsqueda de productos: chips recientes y escáner ---------- */

.chips-scroll {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 14px;
  -webkit-overflow-scrolling: touch;
}

.chips-scroll .chip {
  white-space: nowrap;
  flex-shrink: 0;
}

/* Variante compacta — Recientes y Carritos abiertos en Modo Tienda, para
   que quepan todos los controles nuevos sin empujar el registrar/agregar
   fuera de la primera pantalla. */
.chips-sm.chips-scroll {
  gap: 6px;
  padding-bottom: 10px;
}

.chips-sm .chip {
  height: 28px;
  min-width: unset;
  padding: 0 10px;
  font-size: 12px;
}

/* Chips de "Carritos abiertos": a diferencia del resto de los chips (una
   sola línea, pill completa), estos llevan un segundo renglón opcional con
   el delivery asignado — por eso pasan a layout en columna con esquinas
   menos redondeadas en vez del pill de altura fija. */
.chip-carrito.chip {
  height: auto;
  min-height: 28px;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  border-radius: 14px;
  padding: 5px 12px;
  gap: 2px;
  text-align: left;
}

.chip-carrito-line1 {
  white-space: nowrap;
}

.chip-carrito-line2 {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}

.chip-carrito-line2 svg {
  flex-shrink: 0;
}

.scanner-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.82);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}

.scanner-box {
  background: var(--surface);
  border-radius: 20px;
  padding: 16px;
  width: 100%;
  max-width: 380px;
}

#scannerReader {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  margin-bottom: 12px;
  /* Sin una altura propia, un <video> con height:100% dentro de un
     contenedor de alto automático colapsa/se descuadra (visto en
     iPhone) — con aspect-ratio fijo el video siempre tiene un marco
     estable para llenar, sin importar la resolución real de la cámara. */
  aspect-ratio: 3 / 4;
  background: #000;
}

.scanner-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Marco de esquinas verdes sobre el video — le confirma al usuario que
   el escáner está activo y mirando, no solo un video mudo. */
.scan-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 82%;
  height: 42%;
  pointer-events: none;
}

.scan-corner {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 3px solid #4CAF50;
}

.scan-corner-tl { top: 0; left: 0; border-right: none; border-bottom: none; border-top-left-radius: 8px; }
.scan-corner-tr { top: 0; right: 0; border-left: none; border-bottom: none; border-top-right-radius: 8px; }
.scan-corner-bl { bottom: 0; left: 0; border-right: none; border-top: none; border-bottom-left-radius: 8px; }
.scan-corner-br { bottom: 0; right: 0; border-left: none; border-top: none; border-bottom-right-radius: 8px; }

/* ---------- Visor de imagen (lightbox), ver app.js ---------- */

.image-viewer-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.9);
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 20px;
}

.image-viewer-overlay.open {
  display: flex;
}

.image-viewer-box {
  position: relative;
  max-width: 100%;
  max-height: 100%;
}

.image-viewer-box img {
  display: block;
  max-width: 90vw;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 12px;
}

.image-viewer-close {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow);
}

/* Modal de ayuda contextual por pantalla (botón "?" en el topbar, ver
   header.php $helpTitulo/$helpContenido) -- mismo patrón que
   .image-viewer-overlay de arriba, pero con contenido de texto largo
   en vez de una imagen (por eso tiene scroll propio en el body). */
.help-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 20px;
}

.help-modal-overlay.open {
  display: flex;
}

.help-modal-box {
  background: var(--surface);
  border-radius: 20px;
  box-shadow: var(--shadow);
  max-width: 480px;
  width: 100%;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.help-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 20px 12px;
  border-bottom: 1px solid var(--border);
}

.help-modal-header h2 {
  margin: 0;
  font-size: 16px;
}

.help-modal-body {
  padding: 16px 20px 20px;
  overflow-y: auto;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
}

.help-modal-body p {
  margin: 0 0 12px;
}

.help-modal-body p:last-child {
  margin-bottom: 0;
}

.help-modal-body ul,
.help-modal-body ol {
  margin: 0 0 12px;
  padding-left: 20px;
}

.help-modal-body strong {
  color: var(--accent);
}

/* Modal de detalle de fila (data-fila-detalle, ver app.js) -- reusa
   .help-modal-* de arriba, esto es solo el listado de campo/valor que
   arma adentro. */
.fila-detalle-campo {
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}

.fila-detalle-campo:last-child {
  border-bottom: none;
}

.fila-detalle-etiqueta {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
  margin-bottom: 2px;
}

.fila-detalle-valor {
  font-size: 14px;
  color: var(--text);
  word-break: break-word;
  /* Respeta los saltos de línea del valor (2026-10-17): listas como los
     descuentos de un pago van un ítem por renglón. Sin saltos, igual que antes. */
  white-space: pre-line;
}

tr[data-fila-detalle] {
  cursor: pointer;
}

/* Fila "prendida": la última que se tocó para ver su detalle, para
   ubicar en qué puesto de la lista se iba (queda así aunque se cierre
   el modal). Mismo tratamiento visual que .contenido-seleccionado. */
tr[data-fila-detalle].fila-detalle-activa {
  background: rgba(245, 197, 24, 0.14);
  box-shadow: inset 3px 0 0 #F5C518;
}

/* Contenedor de scroll horizontal para tablas anchas que no entran en
   .screen{max-width:420px} (ej. la tabla de 10 columnas de Rights
   Manager) — la tabla se desplaza sola en vez de desbordar la página. */
.tabla-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.reporte-tabla-admin {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
  font-size: 13px;
}

.reporte-tabla-admin th,
.reporte-tabla-admin td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.reporte-tabla-admin th {
  color: var(--text-muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
}

.reporte-tabla-admin input.pill-input {
  min-width: 90px;
  padding: 6px 10px;
}

/* Flecha que gira al desplegar un bloque plegable -- genérico, para
   cualquier pantalla con un acordeón simple (ver uiToggleDesplegable()
   en app.js). El toggle (lo clickeable) lleva .toggle-abierto cuando
   el panel está visible; la flecha adentro lleva .toggle-chevron. */
.toggle-chevron {
  display: inline-flex;
  transition: transform 0.2s ease;
}

.toggle-abierto .toggle-chevron {
  transform: rotate(180deg);
}

/* Tablas con filas desplegables en árbol (2026-10-10, pedido: "todo se ve
   igual, muy plano"). Cada nivel se distingue por fondo, sangría y una
   barra de color a la izquierda; la fila abierta queda resaltada. Uso:
   <table class="tabla-arbol"> y en cada fila .arbol-padre (clickeable),
   .arbol-n1 / .arbol-n2 (niveles hijos). La flecha va ANTES del texto en
   un .arbol-caret (o .arbol-caret vacío para alinear filas sin hijos). */
.tabla-arbol tr.arbol-padre { cursor: pointer; }
.tabla-arbol tr.arbol-padre:hover > td { background: color-mix(in srgb, var(--accent) 6%, transparent); }
.tabla-arbol tr.arbol-padre.toggle-abierto > td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.tabla-arbol tr.arbol-padre.toggle-abierto > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.tabla-arbol tr.arbol-n1 > td {
  background: var(--surface-muted);
  font-size: 12.5px;
  border-bottom-color: color-mix(in srgb, var(--border) 60%, transparent);
}
.tabla-arbol tr.arbol-n1 > td:first-child {
  padding-left: 20px;
  box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent) 55%, transparent);
}
.tabla-arbol tr.arbol-n1.arbol-padre.toggle-abierto > td { background: color-mix(in srgb, var(--accent) 9%, var(--surface-muted)); }
.tabla-arbol tr.arbol-n2 > td {
  background: color-mix(in srgb, var(--surface-muted) 55%, transparent);
  color: var(--text-muted);
  font-size: 12px;
  border-bottom-color: color-mix(in srgb, var(--border) 40%, transparent);
}
.tabla-arbol tr.arbol-n2 > td:first-child {
  padding-left: 42px;
  box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent) 25%, transparent);
}
.arbol-caret {
  display: inline-flex;
  width: 16px;
  margin-right: 4px;
  vertical-align: -2px;
  color: var(--text-muted);
}

/* Marca del comercio en el encabezado (2026-10-11): logo a la izquierda y
   un bloque de texto con el nombre (una línea, "…" si es largo, completo
   en el title) y debajo la etiqueta de categoría COMERCIO / SOCIO /
   COMMUNITY MANAGER + el punto de venta. */
.brand-tenant { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand-texto { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; min-width: 0; }
.brand-nombre-fila { display: flex; align-items: center; gap: 4px; min-width: 0; max-width: 100%; }
.brand-nombre {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
}
/* El nombre se corta con "…" según el espacio REAL que queda al lado de
   los botones de la derecha (bug 2026-10-11: un ancho fijo lo montaba
   sobre el botón de tema). La fila superior reparte: la izquierda se
   achica, los botones nunca. */
.topbar { gap: 10px; }
.topbar-left { flex: 1 1 auto; }
.topbar-actions { flex-shrink: 0; }
.topbar-left .menu-wrap, .topbar-left .brand, .brand-tenant, .brand-texto, .brand-nombre-fila, .brand-nombre { min-width: 0; max-width: 100%; }
.brand-nombre-fila svg, .brand-tenant .brand-mark { flex-shrink: 0; }
.topbar-left .brand { overflow: hidden; }
.brand-categoria-fila { display: flex; align-items: center; gap: 6px; }
.brand-categoria {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .06em;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--border) 45%, transparent);
  white-space: nowrap;
}
.brand-punto-venta { font-size: 11px; font-weight: 400; color: var(--text-muted); line-height: 1; }
